0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/device.h>
0013 #include <linux/gcd.h>
0014 #include <linux/lcm.h>
0015 #include <linux/module.h>
0016
0017 #include "ccs-pll.h"
0018
0019
0020 static inline u32 clk_div_even(u32 a)
0021 {
0022 return max_t(u32, 1, a & ~1);
0023 }
0024
0025
0026 static inline u32 clk_div_even_up(u32 a)
0027 {
0028 if (a == 1)
0029 return 1;
0030 return (a + 1) & ~1;
0031 }
0032
0033 static inline u32 is_one_or_even(u32 a)
0034 {
0035 if (a == 1)
0036 return 1;
0037 if (a & 1)
0038 return 0;
0039
0040 return 1;
0041 }
0042
0043 static inline u32 one_or_more(u32 a)
0044 {
0045 return a ?: 1;
0046 }
0047
0048 static int bounds_check(struct device *dev, u32 val,
0049 u32 min, u32 max, const char *prefix,
0050 char *str)
0051 {
0052 if (val >= min && val <= max)
0053 return 0;
0054
0055 dev_dbg(dev, "%s_%s out of bounds: %d (%d--%d)\n", prefix,
0056 str, val, min, max);
0057
0058 return -EINVAL;
0059 }
0060
0061 #define PLL_OP 1
0062 #define PLL_VT 2
0063
0064 static const char *pll_string(unsigned int which)
0065 {
0066 switch (which) {
0067 case PLL_OP:
0068 return "op";
0069 case PLL_VT:
0070 return "vt";
0071 }
0072
0073 return NULL;
0074 }
0075
0076 #define PLL_FL(f) CCS_PLL_FLAG_##f
0077
0078 static void print_pll(struct device *dev, struct ccs_pll *pll)
0079 {
0080 const struct {
0081 struct ccs_pll_branch_fr *fr;
0082 struct ccs_pll_branch_bk *bk;
0083 unsigned int which;
0084 } branches[] = {
0085 { &pll->vt_fr, &pll->vt_bk, PLL_VT },
0086 { &pll->op_fr, &pll->op_bk, PLL_OP }
0087 }, *br;
0088 unsigned int i;
0089
0090 dev_dbg(dev, "ext_clk_freq_hz\t\t%u\n", pll->ext_clk_freq_hz);
0091
0092 for (i = 0, br = branches; i < ARRAY_SIZE(branches); i++, br++) {
0093 const char *s = pll_string(br->which);
0094
0095 if (pll->flags & CCS_PLL_FLAG_DUAL_PLL ||
0096 br->which == PLL_VT) {
0097 dev_dbg(dev, "%s_pre_pll_clk_div\t\t%u\n", s,
0098 br->fr->pre_pll_clk_div);
0099 dev_dbg(dev, "%s_pll_multiplier\t\t%u\n", s,
0100 br->fr->pll_multiplier);
0101
0102 dev_dbg(dev, "%s_pll_ip_clk_freq_hz\t%u\n", s,
0103 br->fr->pll_ip_clk_freq_hz);
0104 dev_dbg(dev, "%s_pll_op_clk_freq_hz\t%u\n", s,
0105 br->fr->pll_op_clk_freq_hz);
0106 }
0107
0108 if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) ||
0109 br->which == PLL_VT) {
0110 dev_dbg(dev, "%s_sys_clk_div\t\t%u\n", s,
0111 br->bk->sys_clk_div);
0112 dev_dbg(dev, "%s_pix_clk_div\t\t%u\n", s,
0113 br->bk->pix_clk_div);
0114
0115 dev_dbg(dev, "%s_sys_clk_freq_hz\t%u\n", s,
0116 br->bk->sys_clk_freq_hz);
0117 dev_dbg(dev, "%s_pix_clk_freq_hz\t%u\n", s,
0118 br->bk->pix_clk_freq_hz);
0119 }
0120 }
0121
0122 dev_dbg(dev, "pixel rate in pixel array:\t%u\n",
0123 pll->pixel_rate_pixel_array);
0124 dev_dbg(dev, "pixel rate on CSI-2 bus:\t%u\n",
0125 pll->pixel_rate_csi);
0126
0127 dev_dbg(dev, "flags%s%s%s%s%s%s%s%s%s\n",
0128 pll->flags & PLL_FL(LANE_SPEED_MODEL) ? " lane-speed" : "",
0129 pll->flags & PLL_FL(LINK_DECOUPLED) ? " link-decoupled" : "",
0130 pll->flags & PLL_FL(EXT_IP_PLL_DIVIDER) ?
0131 " ext-ip-pll-divider" : "",
0132 pll->flags & PLL_FL(FLEXIBLE_OP_PIX_CLK_DIV) ?
0133 " flexible-op-pix-div" : "",
0134 pll->flags & PLL_FL(FIFO_DERATING) ? " fifo-derating" : "",
0135 pll->flags & PLL_FL(FIFO_OVERRATING) ? " fifo-overrating" : "",
0136 pll->flags & PLL_FL(DUAL_PLL) ? " dual-pll" : "",
0137 pll->flags & PLL_FL(OP_SYS_DDR) ? " op-sys-ddr" : "",
0138 pll->flags & PLL_FL(OP_PIX_DDR) ? " op-pix-ddr" : "");
0139 }
0140
0141 static u32 op_sys_ddr(u32 flags)
0142 {
0143 return flags & CCS_PLL_FLAG_OP_SYS_DDR ? 1 : 0;
0144 }
0145
0146 static u32 op_pix_ddr(u32 flags)
0147 {
0148 return flags & CCS_PLL_FLAG_OP_PIX_DDR ? 1 : 0;
0149 }
0150
0151 static int check_fr_bounds(struct device *dev,
0152 const struct ccs_pll_limits *lim,
0153 struct ccs_pll *pll, unsigned int which)
0154 {
0155 const struct ccs_pll_branch_limits_fr *lim_fr;
0156 struct ccs_pll_branch_fr *pll_fr;
0157 const char *s = pll_string(which);
0158 int rval;
0159
0160 if (which == PLL_OP) {
0161 lim_fr = &lim->op_fr;
0162 pll_fr = &pll->op_fr;
0163 } else {
0164 lim_fr = &lim->vt_fr;
0165 pll_fr = &pll->vt_fr;
0166 }
0167
0168 rval = bounds_check(dev, pll_fr->pre_pll_clk_div,
0169 lim_fr->min_pre_pll_clk_div,
0170 lim_fr->max_pre_pll_clk_div, s, "pre_pll_clk_div");
0171
0172 if (!rval)
0173 rval = bounds_check(dev, pll_fr->pll_ip_clk_freq_hz,
0174 lim_fr->min_pll_ip_clk_freq_hz,
0175 lim_fr->max_pll_ip_clk_freq_hz,
0176 s, "pll_ip_clk_freq_hz");
0177 if (!rval)
0178 rval = bounds_check(dev, pll_fr->pll_multiplier,
0179 lim_fr->min_pll_multiplier,
0180 lim_fr->max_pll_multiplier,
0181 s, "pll_multiplier");
0182 if (!rval)
0183 rval = bounds_check(dev, pll_fr->pll_op_clk_freq_hz,
0184 lim_fr->min_pll_op_clk_freq_hz,
0185 lim_fr->max_pll_op_clk_freq_hz,
0186 s, "pll_op_clk_freq_hz");
0187
0188 return rval;
0189 }
0190
0191 static int check_bk_bounds(struct device *dev,
0192 const struct ccs_pll_limits *lim,
0193 struct ccs_pll *pll, unsigned int which)
0194 {
0195 const struct ccs_pll_branch_limits_bk *lim_bk;
0196 struct ccs_pll_branch_bk *pll_bk;
0197 const char *s = pll_string(which);
0198 int rval;
0199
0200 if (which == PLL_OP) {
0201 if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
0202 return 0;
0203
0204 lim_bk = &lim->op_bk;
0205 pll_bk = &pll->op_bk;
0206 } else {
0207 lim_bk = &lim->vt_bk;
0208 pll_bk = &pll->vt_bk;
0209 }
0210
0211 rval = bounds_check(dev, pll_bk->sys_clk_div,
0212 lim_bk->min_sys_clk_div,
0213 lim_bk->max_sys_clk_div, s, "op_sys_clk_div");
0214 if (!rval)
0215 rval = bounds_check(dev, pll_bk->sys_clk_freq_hz,
0216 lim_bk->min_sys_clk_freq_hz,
0217 lim_bk->max_sys_clk_freq_hz,
0218 s, "sys_clk_freq_hz");
0219 if (!rval)
0220 rval = bounds_check(dev, pll_bk->sys_clk_div,
0221 lim_bk->min_sys_clk_div,
0222 lim_bk->max_sys_clk_div,
0223 s, "sys_clk_div");
0224 if (!rval)
0225 rval = bounds_check(dev, pll_bk->pix_clk_freq_hz,
0226 lim_bk->min_pix_clk_freq_hz,
0227 lim_bk->max_pix_clk_freq_hz,
0228 s, "pix_clk_freq_hz");
0229
0230 return rval;
0231 }
0232
0233 static int check_ext_bounds(struct device *dev, struct ccs_pll *pll)
0234 {
0235 if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING) &&
0236 pll->pixel_rate_pixel_array > pll->pixel_rate_csi) {
0237 dev_dbg(dev, "device does not support derating\n");
0238 return -EINVAL;
0239 }
0240
0241 if (!(pll->flags & CCS_PLL_FLAG_FIFO_OVERRATING) &&
0242 pll->pixel_rate_pixel_array < pll->pixel_rate_csi) {
0243 dev_dbg(dev, "device does not support overrating\n");
0244 return -EINVAL;
0245 }
0246
0247 return 0;
0248 }
0249
0250 static void
0251 ccs_pll_find_vt_sys_div(struct device *dev, const struct ccs_pll_limits *lim,
0252 struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr,
0253 u16 min_vt_div, u16 max_vt_div,
0254 u16 *min_sys_div, u16 *max_sys_div)
0255 {
0256
0257
0258
0259
0260 *min_sys_div = lim->vt_bk.min_sys_clk_div;
0261 dev_dbg(dev, "min_sys_div: %u\n", *min_sys_div);
0262 *min_sys_div = max_t(u16, *min_sys_div,
0263 DIV_ROUND_UP(min_vt_div,
0264 lim->vt_bk.max_pix_clk_div));
0265 dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", *min_sys_div);
0266 *min_sys_div = max_t(u16, *min_sys_div,
0267 pll_fr->pll_op_clk_freq_hz
0268 / lim->vt_bk.max_sys_clk_freq_hz);
0269 dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", *min_sys_div);
0270 *min_sys_div = clk_div_even_up(*min_sys_div);
0271 dev_dbg(dev, "min_sys_div: one or even: %u\n", *min_sys_div);
0272
0273 *max_sys_div = lim->vt_bk.max_sys_clk_div;
0274 dev_dbg(dev, "max_sys_div: %u\n", *max_sys_div);
0275 *max_sys_div = min_t(u16, *max_sys_div,
0276 DIV_ROUND_UP(max_vt_div,
0277 lim->vt_bk.min_pix_clk_div));
0278 dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", *max_sys_div);
0279 *max_sys_div = min_t(u16, *max_sys_div,
0280 DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz,
0281 lim->vt_bk.min_pix_clk_freq_hz));
0282 dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", *max_sys_div);
0283 }
0284
0285 #define CPHY_CONST 7
0286 #define DPHY_CONST 16
0287 #define PHY_CONST_DIV 16
0288
0289 static inline int
0290 __ccs_pll_calculate_vt_tree(struct device *dev,
0291 const struct ccs_pll_limits *lim,
0292 struct ccs_pll *pll, u32 mul, u32 div)
0293 {
0294 const struct ccs_pll_branch_limits_fr *lim_fr = &lim->vt_fr;
0295 const struct ccs_pll_branch_limits_bk *lim_bk = &lim->vt_bk;
0296 struct ccs_pll_branch_fr *pll_fr = &pll->vt_fr;
0297 struct ccs_pll_branch_bk *pll_bk = &pll->vt_bk;
0298 u32 more_mul;
0299 u16 best_pix_div = SHRT_MAX >> 1, best_div;
0300 u16 vt_div, min_sys_div, max_sys_div, sys_div;
0301
0302 pll_fr->pll_ip_clk_freq_hz =
0303 pll->ext_clk_freq_hz / pll_fr->pre_pll_clk_div;
0304
0305 dev_dbg(dev, "vt_pll_ip_clk_freq_hz %u\n", pll_fr->pll_ip_clk_freq_hz);
0306
0307 more_mul = one_or_more(DIV_ROUND_UP(lim_fr->min_pll_op_clk_freq_hz,
0308 pll_fr->pll_ip_clk_freq_hz * mul));
0309
0310 dev_dbg(dev, "more_mul: %u\n", more_mul);
0311 more_mul *= DIV_ROUND_UP(lim_fr->min_pll_multiplier, mul * more_mul);
0312 dev_dbg(dev, "more_mul2: %u\n", more_mul);
0313
0314 pll_fr->pll_multiplier = mul * more_mul;
0315
0316 if (pll_fr->pll_multiplier * pll_fr->pll_ip_clk_freq_hz >
0317 lim_fr->max_pll_op_clk_freq_hz)
0318 return -EINVAL;
0319
0320 pll_fr->pll_op_clk_freq_hz =
0321 pll_fr->pll_ip_clk_freq_hz * pll_fr->pll_multiplier;
0322
0323 vt_div = div * more_mul;
0324
0325 ccs_pll_find_vt_sys_div(dev, lim, pll, pll_fr, vt_div, vt_div,
0326 &min_sys_div, &max_sys_div);
0327
0328 max_sys_div = (vt_div & 1) ? 1 : max_sys_div;
0329
0330 dev_dbg(dev, "vt min/max_sys_div: %u,%u\n", min_sys_div, max_sys_div);
0331
0332 for (sys_div = min_sys_div; sys_div <= max_sys_div;
0333 sys_div += 2 - (sys_div & 1)) {
0334 u16 pix_div;
0335
0336 if (vt_div % sys_div)
0337 continue;
0338
0339 pix_div = vt_div / sys_div;
0340
0341 if (pix_div < lim_bk->min_pix_clk_div ||
0342 pix_div > lim_bk->max_pix_clk_div) {
0343 dev_dbg(dev,
0344 "pix_div %u too small or too big (%u--%u)\n",
0345 pix_div,
0346 lim_bk->min_pix_clk_div,
0347 lim_bk->max_pix_clk_div);
0348 continue;
0349 }
0350
0351 dev_dbg(dev, "sys/pix/best_pix: %u,%u,%u\n", sys_div, pix_div,
0352 best_pix_div);
0353
0354 if (pix_div * sys_div <= best_pix_div) {
0355 best_pix_div = pix_div;
0356 best_div = pix_div * sys_div;
0357 }
0358 }
0359 if (best_pix_div == SHRT_MAX >> 1)
0360 return -EINVAL;
0361
0362 pll_bk->sys_clk_div = best_div / best_pix_div;
0363 pll_bk->pix_clk_div = best_pix_div;
0364
0365 pll_bk->sys_clk_freq_hz =
0366 pll_fr->pll_op_clk_freq_hz / pll_bk->sys_clk_div;
0367 pll_bk->pix_clk_freq_hz =
0368 pll_bk->sys_clk_freq_hz / pll_bk->pix_clk_div;
0369
0370 pll->pixel_rate_pixel_array =
0371 pll_bk->pix_clk_freq_hz * pll->vt_lanes;
0372
0373 return 0;
0374 }
0375
0376 static int ccs_pll_calculate_vt_tree(struct device *dev,
0377 const struct ccs_pll_limits *lim,
0378 struct ccs_pll *pll)
0379 {
0380 const struct ccs_pll_branch_limits_fr *lim_fr = &lim->vt_fr;
0381 struct ccs_pll_branch_fr *pll_fr = &pll->vt_fr;
0382 u16 min_pre_pll_clk_div = lim_fr->min_pre_pll_clk_div;
0383 u16 max_pre_pll_clk_div = lim_fr->max_pre_pll_clk_div;
0384 u32 pre_mul, pre_div;
0385
0386 pre_div = gcd(pll->pixel_rate_csi,
0387 pll->ext_clk_freq_hz * pll->vt_lanes);
0388 pre_mul = pll->pixel_rate_csi / pre_div;
0389 pre_div = pll->ext_clk_freq_hz * pll->vt_lanes / pre_div;
0390
0391
0392 max_pre_pll_clk_div =
0393 min_t(u16, max_pre_pll_clk_div,
0394 DIV_ROUND_UP(pll->ext_clk_freq_hz,
0395 lim_fr->min_pll_ip_clk_freq_hz));
0396
0397 min_pre_pll_clk_div = max_t(u16, min_pre_pll_clk_div,
0398 pll->ext_clk_freq_hz /
0399 lim_fr->max_pll_ip_clk_freq_hz);
0400
0401 dev_dbg(dev, "vt min/max_pre_pll_clk_div: %u,%u\n",
0402 min_pre_pll_clk_div, max_pre_pll_clk_div);
0403
0404 for (pll_fr->pre_pll_clk_div = min_pre_pll_clk_div;
0405 pll_fr->pre_pll_clk_div <= max_pre_pll_clk_div;
0406 pll_fr->pre_pll_clk_div +=
0407 (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 :
0408 2 - (pll_fr->pre_pll_clk_div & 1)) {
0409 u32 mul, div;
0410 int rval;
0411
0412 div = gcd(pre_mul * pll_fr->pre_pll_clk_div, pre_div);
0413 mul = pre_mul * pll_fr->pre_pll_clk_div / div;
0414 div = pre_div / div;
0415
0416 dev_dbg(dev, "vt pre-div/mul/div: %u,%u,%u\n",
0417 pll_fr->pre_pll_clk_div, mul, div);
0418
0419 rval = __ccs_pll_calculate_vt_tree(dev, lim, pll,
0420 mul, div);
0421 if (rval)
0422 continue;
0423
0424 rval = check_fr_bounds(dev, lim, pll, PLL_VT);
0425 if (rval)
0426 continue;
0427
0428 rval = check_bk_bounds(dev, lim, pll, PLL_VT);
0429 if (rval)
0430 continue;
0431
0432 return 0;
0433 }
0434
0435 return -EINVAL;
0436 }
0437
0438 static void
0439 ccs_pll_calculate_vt(struct device *dev, const struct ccs_pll_limits *lim,
0440 const struct ccs_pll_branch_limits_bk *op_lim_bk,
0441 struct ccs_pll *pll, struct ccs_pll_branch_fr *pll_fr,
0442 struct ccs_pll_branch_bk *op_pll_bk, bool cphy,
0443 u32 phy_const)
0444 {
0445 u16 sys_div;
0446 u16 best_pix_div = SHRT_MAX >> 1;
0447 u16 vt_op_binning_div;
0448 u16 min_vt_div, max_vt_div, vt_div;
0449 u16 min_sys_div, max_sys_div;
0450
0451 if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
0452 goto out_calc_pixel_rate;
0453
0454
0455
0456
0457
0458 if (!(pll->flags & CCS_PLL_FLAG_FIFO_DERATING)) {
0459 min_vt_div =
0460 op_pll_bk->sys_clk_div * op_pll_bk->pix_clk_div
0461 * pll->vt_lanes * phy_const / pll->op_lanes
0462 / (PHY_CONST_DIV << op_pix_ddr(pll->flags));
0463 } else {
0464
0465
0466
0467
0468
0469
0470
0471 if (lim->min_line_length_pck_bin > lim->min_line_length_pck
0472 / pll->binning_horizontal)
0473 vt_op_binning_div = pll->binning_horizontal;
0474 else
0475 vt_op_binning_div = 1;
0476 dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489 dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
0490 min_vt_div =
0491 DIV_ROUND_UP(pll->bits_per_pixel
0492 * op_pll_bk->sys_clk_div * pll->scale_n
0493 * pll->vt_lanes * phy_const,
0494 (pll->flags &
0495 CCS_PLL_FLAG_LANE_SPEED_MODEL ?
0496 pll->csi2.lanes : 1)
0497 * vt_op_binning_div * pll->scale_m
0498 * PHY_CONST_DIV << op_pix_ddr(pll->flags));
0499 }
0500
0501
0502 dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
0503 min_vt_div = max_t(u16, min_vt_div,
0504 DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz,
0505 lim->vt_bk.max_pix_clk_freq_hz));
0506 dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
0507 min_vt_div);
0508 min_vt_div = max_t(u16, min_vt_div, lim->vt_bk.min_pix_clk_div
0509 * lim->vt_bk.min_sys_clk_div);
0510 dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
0511
0512 max_vt_div = lim->vt_bk.max_sys_clk_div * lim->vt_bk.max_pix_clk_div;
0513 dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
0514 max_vt_div = min_t(u16, max_vt_div,
0515 DIV_ROUND_UP(pll_fr->pll_op_clk_freq_hz,
0516 lim->vt_bk.min_pix_clk_freq_hz));
0517 dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
0518 max_vt_div);
0519
0520 ccs_pll_find_vt_sys_div(dev, lim, pll, pll_fr, min_vt_div,
0521 max_vt_div, &min_sys_div, &max_sys_div);
0522
0523
0524
0525
0526
0527
0528 for (vt_div = min_vt_div; vt_div <= max_vt_div; vt_div++) {
0529 u16 __max_sys_div = vt_div & 1 ? 1 : max_sys_div;
0530
0531 for (sys_div = min_sys_div; sys_div <= __max_sys_div;
0532 sys_div += 2 - (sys_div & 1)) {
0533 u16 pix_div;
0534 u16 rounded_div;
0535
0536 pix_div = DIV_ROUND_UP(vt_div, sys_div);
0537
0538 if (pix_div < lim->vt_bk.min_pix_clk_div
0539 || pix_div > lim->vt_bk.max_pix_clk_div) {
0540 dev_dbg(dev,
0541 "pix_div %u too small or too big (%u--%u)\n",
0542 pix_div,
0543 lim->vt_bk.min_pix_clk_div,
0544 lim->vt_bk.max_pix_clk_div);
0545 continue;
0546 }
0547
0548 rounded_div = roundup(vt_div, best_pix_div);
0549
0550
0551 if (pix_div * sys_div <= rounded_div)
0552 best_pix_div = pix_div;
0553
0554
0555 if (vt_div == rounded_div)
0556 break;
0557 }
0558 if (best_pix_div < SHRT_MAX >> 1)
0559 break;
0560 }
0561
0562 pll->vt_bk.sys_clk_div = DIV_ROUND_UP(vt_div, best_pix_div);
0563 pll->vt_bk.pix_clk_div = best_pix_div;
0564
0565 pll->vt_bk.sys_clk_freq_hz =
0566 pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div;
0567 pll->vt_bk.pix_clk_freq_hz =
0568 pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div;
0569
0570 out_calc_pixel_rate:
0571 pll->pixel_rate_pixel_array =
0572 pll->vt_bk.pix_clk_freq_hz * pll->vt_lanes;
0573 }
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584
0585
0586 static int
0587 ccs_pll_calculate_op(struct device *dev, const struct ccs_pll_limits *lim,
0588 const struct ccs_pll_branch_limits_fr *op_lim_fr,
0589 const struct ccs_pll_branch_limits_bk *op_lim_bk,
0590 struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr,
0591 struct ccs_pll_branch_bk *op_pll_bk, u32 mul,
0592 u32 div, u32 op_sys_clk_freq_hz_sdr, u32 l,
0593 bool cphy, u32 phy_const)
0594 {
0595
0596
0597
0598
0599
0600
0601 u32 more_mul_min, more_mul_max;
0602 u32 more_mul_factor;
0603 u32 i;
0604
0605
0606
0607
0608
0609 dev_dbg(dev, "op_pre_pll_clk_div %u\n", op_pll_fr->pre_pll_clk_div);
0610
0611
0612 more_mul_max = op_lim_fr->max_pll_multiplier / mul;
0613 dev_dbg(dev, "more_mul_max: max_op_pll_multiplier check: %u\n",
0614 more_mul_max);
0615
0616 more_mul_max =
0617 min_t(u32,
0618 more_mul_max,
0619 op_lim_fr->max_pll_op_clk_freq_hz
0620 / (pll->ext_clk_freq_hz /
0621 op_pll_fr->pre_pll_clk_div * mul));
0622 dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n",
0623 more_mul_max);
0624
0625 more_mul_max = min(more_mul_max,
0626 op_lim_bk->max_sys_clk_div * op_pll_fr->pre_pll_clk_div
0627 / div);
0628 dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
0629 more_mul_max);
0630
0631 more_mul_max = min(more_mul_max, op_lim_fr->max_pll_multiplier / mul);
0632 dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
0633 more_mul_max);
0634
0635
0636 more_mul_min = DIV_ROUND_UP(op_lim_fr->min_pll_op_clk_freq_hz,
0637 pll->ext_clk_freq_hz /
0638 op_pll_fr->pre_pll_clk_div * mul);
0639 dev_dbg(dev, "more_mul_min: min_op_pll_op_clk_freq_hz check: %u\n",
0640 more_mul_min);
0641
0642 more_mul_min = max(more_mul_min,
0643 DIV_ROUND_UP(op_lim_fr->min_pll_multiplier, mul));
0644 dev_dbg(dev, "more_mul_min: min_op_pll_multiplier check: %u\n",
0645 more_mul_min);
0646
0647 if (more_mul_min > more_mul_max) {
0648 dev_dbg(dev,
0649 "unable to compute more_mul_min and more_mul_max\n");
0650 return -EINVAL;
0651 }
0652
0653 more_mul_factor = lcm(div, op_pll_fr->pre_pll_clk_div) / div;
0654 dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
0655 more_mul_factor = lcm(more_mul_factor, op_lim_bk->min_sys_clk_div);
0656 dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
0657 more_mul_factor);
0658 i = roundup(more_mul_min, more_mul_factor);
0659 if (!is_one_or_even(i))
0660 i <<= 1;
0661
0662 dev_dbg(dev, "final more_mul: %u\n", i);
0663 if (i > more_mul_max) {
0664 dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
0665 return -EINVAL;
0666 }
0667
0668 op_pll_fr->pll_multiplier = mul * i;
0669 op_pll_bk->sys_clk_div = div * i / op_pll_fr->pre_pll_clk_div;
0670 dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll_bk->sys_clk_div);
0671
0672 op_pll_fr->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
0673 / op_pll_fr->pre_pll_clk_div;
0674
0675 op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz
0676 * op_pll_fr->pll_multiplier;
0677
0678 if (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)
0679 op_pll_bk->pix_clk_div =
0680 (pll->bits_per_pixel
0681 * pll->op_lanes * (phy_const << op_sys_ddr(pll->flags))
0682 / PHY_CONST_DIV / pll->csi2.lanes / l)
0683 >> op_pix_ddr(pll->flags);
0684 else
0685 op_pll_bk->pix_clk_div =
0686 (pll->bits_per_pixel
0687 * (phy_const << op_sys_ddr(pll->flags))
0688 / PHY_CONST_DIV / l) >> op_pix_ddr(pll->flags);
0689
0690 op_pll_bk->pix_clk_freq_hz =
0691 (op_sys_clk_freq_hz_sdr >> op_pix_ddr(pll->flags))
0692 / op_pll_bk->pix_clk_div;
0693 op_pll_bk->sys_clk_freq_hz =
0694 op_sys_clk_freq_hz_sdr >> op_sys_ddr(pll->flags);
0695
0696 dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div);
0697
0698 return 0;
0699 }
0700
0701 int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
0702 struct ccs_pll *pll)
0703 {
0704 const struct ccs_pll_branch_limits_fr *op_lim_fr;
0705 const struct ccs_pll_branch_limits_bk *op_lim_bk;
0706 struct ccs_pll_branch_fr *op_pll_fr;
0707 struct ccs_pll_branch_bk *op_pll_bk;
0708 bool cphy = pll->bus_type == CCS_PLL_BUS_TYPE_CSI2_CPHY;
0709 u32 phy_const = cphy ? CPHY_CONST : DPHY_CONST;
0710 u32 op_sys_clk_freq_hz_sdr;
0711 u16 min_op_pre_pll_clk_div;
0712 u16 max_op_pre_pll_clk_div;
0713 u32 mul, div;
0714 u32 l = (!pll->op_bits_per_lane ||
0715 pll->op_bits_per_lane >= pll->bits_per_pixel) ? 1 : 2;
0716 u32 i;
0717 int rval = -EINVAL;
0718
0719 if (!(pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL)) {
0720 pll->op_lanes = 1;
0721 pll->vt_lanes = 1;
0722 }
0723
0724 if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) {
0725 op_lim_fr = &lim->op_fr;
0726 op_lim_bk = &lim->op_bk;
0727 op_pll_fr = &pll->op_fr;
0728 op_pll_bk = &pll->op_bk;
0729 } else if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
0730
0731
0732
0733
0734
0735 op_lim_fr = &lim->vt_fr;
0736 op_lim_bk = &lim->vt_bk;
0737 op_pll_fr = &pll->vt_fr;
0738 op_pll_bk = &pll->vt_bk;
0739 } else {
0740 op_lim_fr = &lim->vt_fr;
0741 op_lim_bk = &lim->op_bk;
0742 op_pll_fr = &pll->vt_fr;
0743 op_pll_bk = &pll->op_bk;
0744 }
0745
0746 if (!pll->op_lanes || !pll->vt_lanes || !pll->bits_per_pixel ||
0747 !pll->ext_clk_freq_hz || !pll->link_freq || !pll->scale_m ||
0748 !op_lim_fr->min_pll_ip_clk_freq_hz ||
0749 !op_lim_fr->max_pll_ip_clk_freq_hz ||
0750 !op_lim_fr->min_pll_op_clk_freq_hz ||
0751 !op_lim_fr->max_pll_op_clk_freq_hz ||
0752 !op_lim_bk->max_sys_clk_div || !op_lim_fr->max_pll_multiplier)
0753 return -EINVAL;
0754
0755
0756
0757
0758
0759 if (!(pll->flags & CCS_PLL_FLAG_FLEXIBLE_OP_PIX_CLK_DIV) &&
0760 (pll->bits_per_pixel * pll->op_lanes) %
0761 (pll->csi2.lanes * l << op_pix_ddr(pll->flags))) {
0762 dev_dbg(dev, "op_pix_clk_div not an integer (bpp %u, op lanes %u, lanes %u, l %u)\n",
0763 pll->bits_per_pixel, pll->op_lanes, pll->csi2.lanes, l);
0764 return -EINVAL;
0765 }
0766
0767 dev_dbg(dev, "vt_lanes: %u\n", pll->vt_lanes);
0768 dev_dbg(dev, "op_lanes: %u\n", pll->op_lanes);
0769
0770 dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
0771 pll->binning_vertical);
0772
0773 switch (pll->bus_type) {
0774 case CCS_PLL_BUS_TYPE_CSI2_DPHY:
0775 case CCS_PLL_BUS_TYPE_CSI2_CPHY:
0776 op_sys_clk_freq_hz_sdr = pll->link_freq * 2
0777 * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
0778 1 : pll->csi2.lanes);
0779 break;
0780 default:
0781 return -EINVAL;
0782 }
0783
0784 pll->pixel_rate_csi =
0785 div_u64((uint64_t)op_sys_clk_freq_hz_sdr
0786 * (pll->flags & CCS_PLL_FLAG_LANE_SPEED_MODEL ?
0787 pll->csi2.lanes : 1) * PHY_CONST_DIV,
0788 phy_const * pll->bits_per_pixel * l);
0789
0790
0791 dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n",
0792 op_lim_fr->min_pre_pll_clk_div, op_lim_fr->max_pre_pll_clk_div);
0793 max_op_pre_pll_clk_div =
0794 min_t(u16, op_lim_fr->max_pre_pll_clk_div,
0795 clk_div_even(pll->ext_clk_freq_hz /
0796 op_lim_fr->min_pll_ip_clk_freq_hz));
0797 min_op_pre_pll_clk_div =
0798 max_t(u16, op_lim_fr->min_pre_pll_clk_div,
0799 clk_div_even_up(
0800 DIV_ROUND_UP(pll->ext_clk_freq_hz,
0801 op_lim_fr->max_pll_ip_clk_freq_hz)));
0802 dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n",
0803 min_op_pre_pll_clk_div, max_op_pre_pll_clk_div);
0804
0805 i = gcd(op_sys_clk_freq_hz_sdr,
0806 pll->ext_clk_freq_hz << op_pix_ddr(pll->flags));
0807 mul = op_sys_clk_freq_hz_sdr / i;
0808 div = (pll->ext_clk_freq_hz << op_pix_ddr(pll->flags)) / i;
0809 dev_dbg(dev, "mul %u / div %u\n", mul, div);
0810
0811 min_op_pre_pll_clk_div =
0812 max_t(u16, min_op_pre_pll_clk_div,
0813 clk_div_even_up(
0814 mul /
0815 one_or_more(
0816 DIV_ROUND_UP(op_lim_fr->max_pll_op_clk_freq_hz,
0817 pll->ext_clk_freq_hz))));
0818 dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n",
0819 min_op_pre_pll_clk_div, max_op_pre_pll_clk_div);
0820
0821 for (op_pll_fr->pre_pll_clk_div = min_op_pre_pll_clk_div;
0822 op_pll_fr->pre_pll_clk_div <= max_op_pre_pll_clk_div;
0823 op_pll_fr->pre_pll_clk_div +=
0824 (pll->flags & CCS_PLL_FLAG_EXT_IP_PLL_DIVIDER) ? 1 :
0825 2 - (op_pll_fr->pre_pll_clk_div & 1)) {
0826 rval = ccs_pll_calculate_op(dev, lim, op_lim_fr, op_lim_bk, pll,
0827 op_pll_fr, op_pll_bk, mul, div,
0828 op_sys_clk_freq_hz_sdr, l, cphy,
0829 phy_const);
0830 if (rval)
0831 continue;
0832
0833 rval = check_fr_bounds(dev, lim, pll,
0834 pll->flags & CCS_PLL_FLAG_DUAL_PLL ?
0835 PLL_OP : PLL_VT);
0836 if (rval)
0837 continue;
0838
0839 rval = check_bk_bounds(dev, lim, pll, PLL_OP);
0840 if (rval)
0841 continue;
0842
0843 if (pll->flags & CCS_PLL_FLAG_DUAL_PLL)
0844 break;
0845
0846 ccs_pll_calculate_vt(dev, lim, op_lim_bk, pll, op_pll_fr,
0847 op_pll_bk, cphy, phy_const);
0848
0849 rval = check_bk_bounds(dev, lim, pll, PLL_VT);
0850 if (rval)
0851 continue;
0852 rval = check_ext_bounds(dev, pll);
0853 if (rval)
0854 continue;
0855
0856 break;
0857 }
0858
0859 if (rval) {
0860 dev_dbg(dev, "unable to compute pre_pll divisor\n");
0861
0862 return rval;
0863 }
0864
0865 if (pll->flags & CCS_PLL_FLAG_DUAL_PLL) {
0866 rval = ccs_pll_calculate_vt_tree(dev, lim, pll);
0867
0868 if (rval)
0869 return rval;
0870 }
0871
0872 print_pll(dev, pll);
0873
0874 return 0;
0875 }
0876 EXPORT_SYMBOL_GPL(ccs_pll_calculate);
0877
0878 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
0879 MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator");
0880 MODULE_LICENSE("GPL");