Commit b58e87f04ec53f9debbe934fe9009e5f7d45f21a

Authored by Fancy Fang
1 parent 9ed0a21714

MLK-21150-4 drm/bridge: sec-dsim: a general way to compute PLL PMS

A fixed PLL PMS setting for attached panel is obviously not
enough for any other mipi panel which needs a different PLL
output clock frequency, and besides, for the CEA-861 standard
display modes, the 'pll_pms' table also can not cover all the
modes requirements. So a general way is created to solve this
problem which can provide an optimum solution to output a PLL
bit clock to match the request frequency in a maximum degree
and also satisfy the input clock and intermediate clocks limit
according to the PLL specification.

Signed-off-by: Fancy Fang <chen.fang@nxp.com>
(cherry picked from commit a73fdd5e48fe0df47685cfc197fe66edc1e28405)

Showing 4 changed files with 212 additions and 63 deletions Side-by-side Diff

drivers/gpu/drm/bridge/sec-dsim.c
... ... @@ -18,6 +18,8 @@
18 18 #include <linux/clk.h>
19 19 #include <linux/completion.h>
20 20 #include <linux/delay.h>
  21 +#include <linux/gcd.h>
  22 +#include <linux/log2.h>
21 23 #include <linux/module.h>
22 24 #include <linux/of_graph.h>
23 25 #include <drm/bridge/sec_mipi_dsim.h>
... ... @@ -273,15 +275,6 @@
273 275 #define conn_to_sec_mipi_dsim(conn) \
274 276 container_of(conn, struct sec_mipi_dsim, connector)
275 277  
276   -/* DSIM PLL configuration from spec:
277   - *
278   - * Fout(DDR) = (M * Fin) / (P * 2^S), so Fout / Fin = M / (P * 2^S)
279   - * Fin_pll = Fin / P (6 ~ 12 MHz)
280   - * S: [2:0], M: [12:3], P: [18:13], so
281   - * TODO: 'S' is in [0 ~ 3], 'M' is in, 'P' is in [1 ~ 33]
282   - *
283   - */
284   -
285 278 /* used for CEA standard modes */
286 279 struct dsim_hblank_par {
287 280 char *name; /* drm display mode name */
... ... @@ -297,6 +290,7 @@
297 290 uint32_t p;
298 291 uint32_t m;
299 292 uint32_t s;
  293 + uint32_t k;
300 294 };
301 295  
302 296 struct sec_mipi_dsim {
... ... @@ -388,19 +382,6 @@
388 382 { DSIM_HBLANK_PARAM("640x480" , 60, 18, 66, 138, 2), },
389 383 };
390 384  
391   -static const struct dsim_pll_pms pll_pms[] = {
392   - { DSIM_PLL_PMS(891000, 1, 66, 1), },
393   - { DSIM_PLL_PMS(890112, 1, 66, 1), },
394   - { DSIM_PLL_PMS(594000, 3, 66, 0), },
395   - { DSIM_PLL_PMS(593408, 3, 66, 0), },
396   - { DSIM_PLL_PMS(445500, 1, 66, 2), },
397   - { DSIM_PLL_PMS(445056, 1, 66, 2), },
398   - { DSIM_PLL_PMS(324000, 3, 72, 1), },
399   - { DSIM_PLL_PMS(324324, 3, 72, 1), },
400   - { DSIM_PLL_PMS(162000, 3, 72, 2), },
401   - { DSIM_PLL_PMS(162162, 3, 72, 2), },
402   -};
403   -
404 385 static const struct dsim_hblank_par *sec_mipi_dsim_get_hblank_par(const char *name,
405 386 int vrefresh,
406 387 int lanes)
407 388  
... ... @@ -446,13 +427,16 @@
446 427 int ret;
447 428 uint32_t rate;
448 429 struct device *dev = dsim->dev;
  430 + const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
  431 + const struct sec_mipi_dsim_pll *dpll = pdata->dphy_pll;
  432 + const struct sec_mipi_dsim_range *fin_range = &dpll->fin;
449 433  
450 434 ret = of_property_read_u32(dev->of_node, "pref-rate", &rate);
451 435 if (ret < 0) {
452 436 dev_dbg(dev, "no valid rate assigned for pref clock\n");
453 437 dsim->pref_clk = PHY_REF_CLK;
454 438 } else {
455   - if (unlikely(rate < 6000 || rate > 300000)) {
  439 + if (unlikely(rate < fin_range->min || rate > fin_range->max)) {
456 440 dev_warn(dev, "pref-rate get is invalid: %uKHz\n",
457 441 rate);
458 442 dsim->pref_clk = PHY_REF_CLK;
... ... @@ -493,21 +477,6 @@
493 477 return 0;
494 478 }
495 479  
496   -static const struct dsim_pll_pms *sec_mipi_dsim_get_pms(uint32_t bit_clk)
497   -{
498   - int i;
499   - const struct dsim_pll_pms *pms;
500   -
501   - for (i = 0; i < ARRAY_SIZE(pll_pms); i++) {
502   - pms = &pll_pms[i];
503   -
504   - if (bit_clk == pms->bit_clk)
505   - return pms;
506   - }
507   -
508   - return NULL;
509   -}
510   -
511 480 static void sec_mipi_dsim_irq_init(struct sec_mipi_dsim *dsim);
512 481  
513 482 /* For now, dsim only support one device attached */
... ... @@ -936,7 +905,7 @@
936 905 bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
937 906  
938 907 /* calculate hfp & hbp word counts */
939   - if (dsim->panel || !dsim->hpar) {
  908 + if (!dsim->hpar) {
940 909 wc = DIV_ROUND_UP(vmode->hfront_porch * (bpp >> 3),
941 910 dsim->lanes);
942 911 hfp_wc = wc > MIPI_HFP_PKT_OVERHEAD ?
... ... @@ -956,7 +925,7 @@
956 925 dsim_write(dsim, mhporch, DSIM_MHPORCH);
957 926  
958 927 /* calculate hsa word counts */
959   - if (dsim->panel || !dsim->hpar) {
  928 + if (!dsim->hpar) {
960 929 wc = DIV_ROUND_UP(vmode->hsync_len * (bpp >> 3),
961 930 dsim->lanes);
962 931 hsa_wc = wc > MIPI_HSA_PKT_OVERHEAD ?
963 932  
964 933  
... ... @@ -1170,15 +1139,131 @@
1170 1139 dsim_write(dsim, mdresol, DSIM_MDRESOL);
1171 1140 }
1172 1141  
  1142 +struct dsim_pll_pms *sec_mipi_dsim_calc_pmsk(struct sec_mipi_dsim *dsim)
  1143 +{
  1144 + uint32_t p, m, s;
  1145 + uint32_t best_p, best_m, best_s;
  1146 + uint32_t fin, fout;
  1147 + uint32_t s_pow_2, raw_s;
  1148 + uint64_t mfin, pfvco, pfout, psfout;
  1149 + uint32_t delta, best_delta = ~0U;
  1150 + struct dsim_pll_pms *pll_pms;
  1151 + struct device *dev = dsim->dev;
  1152 + const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
  1153 + struct sec_mipi_dsim_pll dpll = *pdata->dphy_pll;
  1154 + struct sec_mipi_dsim_range *prange = &dpll.p;
  1155 + struct sec_mipi_dsim_range *mrange = &dpll.m;
  1156 + struct sec_mipi_dsim_range *srange = &dpll.s;
  1157 + struct sec_mipi_dsim_range *krange = &dpll.k;
  1158 + struct sec_mipi_dsim_range *fvco_range = &dpll.fvco;
  1159 + struct sec_mipi_dsim_range *fpref_range = &dpll.fpref;
  1160 + struct sec_mipi_dsim_range pr_new = *prange;
  1161 + struct sec_mipi_dsim_range sr_new = *srange;
  1162 +
  1163 + pll_pms = devm_kzalloc(dev, sizeof(*pll_pms), GFP_KERNEL);
  1164 + if (!pll_pms) {
  1165 + dev_err(dev, "Unable to allocate 'pll_pms'\n");
  1166 + return ERR_PTR(-ENOMEM);
  1167 + }
  1168 +
  1169 + fout = dsim->bit_clk;
  1170 + fin = dsim->pref_clk;
  1171 +
  1172 + /* TODO: ignore 'k' for PMS calculation,
  1173 + * only use 'p', 'm' and 's' to generate
  1174 + * the requested PLL output clock.
  1175 + */
  1176 + krange->min = 0;
  1177 + krange->max = 0;
  1178 +
  1179 + /* narrow 'p' range via 'Fpref' limitation:
  1180 + * Fpref : [2MHz ~ 30MHz] (Fpref = Fin / p)
  1181 + */
  1182 + prange->min = max(prange->min, DIV_ROUND_UP(fin, fpref_range->max));
  1183 + prange->max = min(prange->max, fin / fpref_range->min);
  1184 +
  1185 + /* narrow 'm' range via 'Fvco' limitation:
  1186 + * Fvco: [1050MHz ~ 2100MHz] (Fvco = ((m + k / 65536) * Fin) / p)
  1187 + * So, m = Fvco * p / Fin and Fvco > Fin;
  1188 + */
  1189 + pfvco = fvco_range->min * prange->min;
  1190 + mrange->min = max_t(uint32_t, mrange->min,
  1191 + DIV_ROUND_UP_ULL(pfvco, fin));
  1192 + pfvco = fvco_range->max * prange->max;
  1193 + mrange->max = min_t(uint32_t, mrange->max,
  1194 + DIV_ROUND_UP_ULL(pfvco, fin));
  1195 +
  1196 + dev_dbg(dev, "p: min = %u, max = %u, "
  1197 + "m: min = %u, max = %u, "
  1198 + "s: min = %u, max = %u\n",
  1199 + prange->min, prange->max, mrange->min,
  1200 + mrange->max, srange->min, srange->max);
  1201 +
  1202 + /* first determine 'm', then can determine 'p', last determine 's' */
  1203 + for (m = mrange->min; m <= mrange->max; m++) {
  1204 + /* p = m * Fin / Fvco */
  1205 + mfin = m * fin;
  1206 + pr_new.min = max_t(uint32_t, prange->min,
  1207 + DIV_ROUND_UP_ULL(mfin, fvco_range->max));
  1208 + pr_new.max = min_t(uint32_t, prange->max,
  1209 + (mfin / fvco_range->min));
  1210 +
  1211 + if (pr_new.max < pr_new.min || pr_new.min < prange->min)
  1212 + continue;
  1213 +
  1214 + for (p = pr_new.min; p <= pr_new.max; p++) {
  1215 + /* s = order_pow_of_two((m * Fin) / (p * Fout)) */
  1216 + pfout = p * fout;
  1217 + raw_s = DIV_ROUND_CLOSEST_ULL(mfin, pfout);
  1218 +
  1219 + s_pow_2 = rounddown_pow_of_two(raw_s);
  1220 + sr_new.min = max_t(uint32_t, srange->min,
  1221 + order_base_2(s_pow_2));
  1222 +
  1223 + s_pow_2 = roundup_pow_of_two(DIV_ROUND_CLOSEST_ULL(mfin, pfout));
  1224 + sr_new.max = min_t(uint32_t, srange->max,
  1225 + order_base_2(s_pow_2));
  1226 +
  1227 + if (sr_new.max < sr_new.min || sr_new.min < srange->min)
  1228 + continue;
  1229 +
  1230 + for (s = sr_new.min; s <= sr_new.max; s++) {
  1231 + /* fout = m * Fin / (p * 2^s) */
  1232 + psfout = pfout * (1 << s);
  1233 + delta = abs(psfout - mfin);
  1234 + if (delta < best_delta) {
  1235 + best_p = p;
  1236 + best_m = m;
  1237 + best_s = s;
  1238 + best_delta = delta;
  1239 + }
  1240 + }
  1241 + }
  1242 + }
  1243 +
  1244 + if (best_delta == ~0U)
  1245 + return ERR_PTR(-EINVAL);
  1246 +
  1247 + pll_pms->p = best_p;
  1248 + pll_pms->m = best_m;
  1249 + pll_pms->s = best_s;
  1250 +
  1251 + dev_dbg(dev, "fout = %u, fin = %u, m = %u, "
  1252 + "p = %u, s = %u, best_delta = %u\n",
  1253 + fout, fin, pll_pms->m, pll_pms->p, pll_pms->s, best_delta);
  1254 +
  1255 + return pll_pms;
  1256 +}
  1257 +
1173 1258 int sec_mipi_dsim_check_pll_out(void *driver_private,
1174 1259 const struct drm_display_mode *mode)
1175 1260 {
1176 1261 int bpp;
1177   - uint32_t pix_clk, bit_clk, ref_clk;
  1262 + uint32_t pix_clk, bit_clk;
1178 1263 struct sec_mipi_dsim *dsim = driver_private;
1179 1264 const struct sec_mipi_dsim_plat_data *pdata = dsim->pdata;
1180 1265 const struct dsim_hblank_par *hpar;
1181   - const struct dsim_pll_pms *pms;
  1266 + const struct dsim_pll_pms *pmsk;
1182 1267  
1183 1268 bpp = mipi_dsi_pixel_format_to_bpp(dsim->format);
1184 1269 if (bpp < 0)
1185 1270  
1186 1271  
1187 1272  
1188 1273  
... ... @@ -1195,32 +1280,27 @@
1195 1280  
1196 1281 dsim->pix_clk = pix_clk;
1197 1282 dsim->bit_clk = bit_clk;
1198   -
1199   - dsim->pms = 0x4210;
1200 1283 dsim->hpar = NULL;
1201   - if (dsim->panel)
1202   - return 0;
1203 1284  
  1285 + pmsk = sec_mipi_dsim_calc_pmsk(dsim);
  1286 + if (IS_ERR(pmsk)) {
  1287 + dev_err(dsim->dev,
  1288 + "failed to get pmsk for: fin = %u, fout = %u\n",
  1289 + dsim->pref_clk, dsim->bit_clk);
  1290 + return -EINVAL;
  1291 + }
  1292 +
  1293 + dsim->pms = PLLCTRL_SET_P(pmsk->p) |
  1294 + PLLCTRL_SET_M(pmsk->m) |
  1295 + PLLCTRL_SET_S(pmsk->s);
  1296 +
1204 1297 if (dsim->mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
1205 1298 hpar = sec_mipi_dsim_get_hblank_par(mode->name,
1206 1299 mode->vrefresh,
1207 1300 dsim->lanes);
1208   - if (!hpar)
1209   - return -EINVAL;
1210 1301 dsim->hpar = hpar;
1211   -
1212   - pms = sec_mipi_dsim_get_pms(dsim->bit_clk);
1213   - if (WARN_ON(!pms))
1214   - return -EINVAL;
1215   -
1216   - ref_clk = PHY_REF_CLK;
1217   - /* TODO: add PMS calculate and check
1218   - * Only support '1080p@60Hz' for now,
1219   - * add other modes support later
1220   - */
1221   - dsim->pms = PLLCTRL_SET_P(pms->p) |
1222   - PLLCTRL_SET_M(pms->m) |
1223   - PLLCTRL_SET_S(pms->s);
  1302 + if (!hpar)
  1303 + dev_dbg(dsim->dev, "no pre-exist hpar can be used\n");
1224 1304 }
1225 1305  
1226 1306 return 0;
drivers/gpu/drm/imx/sec_mipi_dsim-imx.c
1 1 /*
2 2 * Samsung MIPI DSI Host Controller on IMX
3 3 *
4   - * Copyright 2018 NXP
  4 + * Copyright 2018-2019 NXP
5 5 *
6 6 * This program is free software; you can redistribute it and/or modify
7 7 * it under the terms of the GNU General Public License as published by
... ... @@ -32,6 +32,7 @@
32 32  
33 33 #include "imx-drm.h"
34 34 #include "sec_mipi_dphy_ln14lpp.h"
  35 +#include "sec_mipi_pll_1432x.h"
35 36  
36 37 #define DRIVER_NAME "imx_sec_dsim_drv"
37 38  
... ... @@ -197,6 +198,7 @@
197 198 .version = 0x1060200,
198 199 .max_data_lanes = 4,
199 200 .max_data_rate = 1500000000ULL,
  201 + .dphy_pll = &pll_1432x,
200 202 .dphy_timing = dphy_timing_ln14lpp_v1p2,
201 203 .num_dphy_timing = ARRAY_SIZE(dphy_timing_ln14lpp_v1p2),
202 204 .dphy_timing_cmp = dphy_timing_default_cmp,
drivers/gpu/drm/imx/sec_mipi_pll_1432x.h
  1 +/*
  2 + * Samsung MIPI DSIM PLL_1432X
  3 + *
  4 + * Copyright 2019 NXP
  5 + *
  6 + * This program is free software; you can redistribute it and/or modify
  7 + * it under the terms of the GNU General Public License as published by
  8 + * the Free Software Foundation; either version 2 of the License, or
  9 + * (at your option) any later version.
  10 + *
  11 + * This program is distributed in the hope that it will be useful,
  12 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + * GNU General Public License for more details.
  15 + */
  16 +
  17 +#ifndef __SEC_DSIM_PLL_1432X_H__
  18 +#define __SEC_DSIM_PLL_1432X_H__
  19 +
  20 +#include <drm/bridge/sec_mipi_dsim.h>
  21 +/*
  22 + * DSIM PLL_1432X setting guide from spec:
  23 + *
  24 + * Fout(bitclk) = ((m + k / 65536) * Fin) / (p * 2^s), and
  25 + * p = P[5:0], m = M[9:0], s = S[2:0], k = K[15:0];
  26 + *
  27 + * Fpref = Fin / p
  28 + * Fin: [6MHz ~ 300MHz], Fpref: [2MHz ~ 30MHz]
  29 + *
  30 + * Fvco = ((m + k / 65536) * Fin) / p
  31 + * Fvco: [1050MHz ~ 2100MHz]
  32 + *
  33 + * 1 <= P[5:0] <= 63, 64 <= M[9:0] <= 1023,
  34 + * 0 <= S[2:0] <= 5, -32768 <= K[15:0] <= 32767
  35 + *
  36 + */
  37 +
  38 +const struct sec_mipi_dsim_pll pll_1432x = {
  39 + .p = { .min = 1, .max = 63, },
  40 + .m = { .min = 64, .max = 1023, },
  41 + .s = { .min = 0, .max = 5, },
  42 + .k = { .min = 0, .max = 32768, }, /* abs(k) */
  43 + .fin = { .min = 6000, .max = 300000, }, /* in KHz */
  44 + .fpref = { .min = 2000, .max = 30000, }, /* in KHz */
  45 + .fvco = { .min = 1050000, .max = 2100000, }, /* in KHz */
  46 +};
  47 +
  48 +#endif
include/drm/bridge/sec_mipi_dsim.h
1 1 /*
2   - * Copyright 2018 NXP
  2 + * Copyright 2018-2019 NXP
3 3 *
4 4 * This program is free software; you can redistribute it and/or modify
5 5 * it under the terms of the GNU General Public License as published by
... ... @@ -19,6 +19,7 @@
19 19 #include <linux/bsearch.h>
20 20  
21 21 struct sec_mipi_dsim_dphy_timing;
  22 +struct sec_mipi_dsim_pll;
22 23  
23 24 struct sec_mipi_dsim_plat_data {
24 25 uint32_t version;
25 26  
... ... @@ -26,9 +27,26 @@
26 27 uint64_t max_data_rate;
27 28 const struct sec_mipi_dsim_dphy_timing *dphy_timing;
28 29 uint32_t num_dphy_timing;
  30 + const struct sec_mipi_dsim_pll *dphy_pll;
29 31 int (*dphy_timing_cmp)(const void *key, const void *elt);
30 32 enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
31 33 struct drm_display_mode *mode);
  34 +};
  35 +
  36 +/* DPHY PLL structure */
  37 +struct sec_mipi_dsim_range {
  38 + uint32_t min;
  39 + uint32_t max;
  40 +};
  41 +
  42 +struct sec_mipi_dsim_pll {
  43 + struct sec_mipi_dsim_range p;
  44 + struct sec_mipi_dsim_range m;
  45 + struct sec_mipi_dsim_range s;
  46 + struct sec_mipi_dsim_range k;
  47 + struct sec_mipi_dsim_range fin;
  48 + struct sec_mipi_dsim_range fpref;
  49 + struct sec_mipi_dsim_range fvco;
32 50 };
33 51  
34 52 /* DPHY timings structure */