Lines Matching +full:high +full:- +full:vt

1 // SPDX-License-Identifier: GPL-2.0-only
3 * drivers/media/i2c/smiapp-pll.c
7 * Copyright (C) 2011--2012 Nokia Corporation
16 #include "smiapp-pll.h"
48 dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max); in bounds_check()
50 return -EINVAL; in bounds_check()
55 dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div); in print_pll()
56 dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier); in print_pll()
57 if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { in print_pll()
58 dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div); in print_pll()
59 dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div); in print_pll()
61 dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div); in print_pll()
62 dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div); in print_pll()
64 dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz); in print_pll()
65 dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz); in print_pll()
66 dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz); in print_pll()
67 if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) { in print_pll()
69 pll->op.sys_clk_freq_hz); in print_pll()
71 pll->op.pix_clk_freq_hz); in print_pll()
73 dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz); in print_pll()
74 dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz); in print_pll()
85 rval = bounds_check(dev, pll->pll_ip_clk_freq_hz, in check_all_bounds()
86 limits->min_pll_ip_freq_hz, in check_all_bounds()
87 limits->max_pll_ip_freq_hz, in check_all_bounds()
91 dev, pll->pll_multiplier, in check_all_bounds()
92 limits->min_pll_multiplier, limits->max_pll_multiplier, in check_all_bounds()
96 dev, pll->pll_op_clk_freq_hz, in check_all_bounds()
97 limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz, in check_all_bounds()
101 dev, op_pll->sys_clk_div, in check_all_bounds()
102 op_limits->min_sys_clk_div, op_limits->max_sys_clk_div, in check_all_bounds()
106 dev, op_pll->sys_clk_freq_hz, in check_all_bounds()
107 op_limits->min_sys_clk_freq_hz, in check_all_bounds()
108 op_limits->max_sys_clk_freq_hz, in check_all_bounds()
112 dev, op_pll->pix_clk_freq_hz, in check_all_bounds()
113 op_limits->min_pix_clk_freq_hz, in check_all_bounds()
114 op_limits->max_pix_clk_freq_hz, in check_all_bounds()
118 * If there are no OP clocks, the VT clocks are contained in in check_all_bounds()
121 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) in check_all_bounds()
126 dev, pll->vt.sys_clk_freq_hz, in check_all_bounds()
127 limits->vt.min_sys_clk_freq_hz, in check_all_bounds()
128 limits->vt.max_sys_clk_freq_hz, in check_all_bounds()
132 dev, pll->vt.pix_clk_freq_hz, in check_all_bounds()
133 limits->vt.min_pix_clk_freq_hz, in check_all_bounds()
134 limits->vt.max_pix_clk_freq_hz, in check_all_bounds()
174 * too high. in __smiapp_pll_calculate()
176 dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div); in __smiapp_pll_calculate()
179 more_mul_max = limits->max_pll_multiplier / mul; in __smiapp_pll_calculate()
186 limits->max_pll_op_freq_hz in __smiapp_pll_calculate()
187 / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul)); in __smiapp_pll_calculate()
192 op_limits->max_sys_clk_div * pll->pre_pll_clk_div in __smiapp_pll_calculate()
198 DIV_ROUND_UP(limits->max_pll_multiplier, mul)); in __smiapp_pll_calculate()
203 more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz, in __smiapp_pll_calculate()
204 pll->ext_clk_freq_hz / pll->pre_pll_clk_div in __smiapp_pll_calculate()
210 DIV_ROUND_UP(limits->min_pll_multiplier, mul)); in __smiapp_pll_calculate()
217 return -EINVAL; in __smiapp_pll_calculate()
220 more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div; in __smiapp_pll_calculate()
222 more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div); in __smiapp_pll_calculate()
232 return -EINVAL; in __smiapp_pll_calculate()
235 pll->pll_multiplier = mul * i; in __smiapp_pll_calculate()
236 op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div; in __smiapp_pll_calculate()
237 dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div); in __smiapp_pll_calculate()
239 pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz in __smiapp_pll_calculate()
240 / pll->pre_pll_clk_div; in __smiapp_pll_calculate()
242 pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz in __smiapp_pll_calculate()
243 * pll->pll_multiplier; in __smiapp_pll_calculate()
246 op_pll->sys_clk_freq_hz = in __smiapp_pll_calculate()
247 pll->pll_op_clk_freq_hz / op_pll->sys_clk_div; in __smiapp_pll_calculate()
249 op_pll->pix_clk_div = pll->bits_per_pixel; in __smiapp_pll_calculate()
250 dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div); in __smiapp_pll_calculate()
252 op_pll->pix_clk_freq_hz = in __smiapp_pll_calculate()
253 op_pll->sys_clk_freq_hz / op_pll->pix_clk_div; in __smiapp_pll_calculate()
255 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { in __smiapp_pll_calculate()
256 /* No OP clocks --- VT clocks are used instead. */ in __smiapp_pll_calculate()
267 if (limits->min_line_length_pck_bin > limits->min_line_length_pck in __smiapp_pll_calculate()
268 / pll->binning_horizontal) in __smiapp_pll_calculate()
269 vt_op_binning_div = pll->binning_horizontal; in __smiapp_pll_calculate()
279 * enough to accommodate the CSI-2 sync codes. in __smiapp_pll_calculate()
283 * Find absolute limits for the factor of vt divider. in __smiapp_pll_calculate()
285 dev_dbg(dev, "scale_m: %u\n", pll->scale_m); in __smiapp_pll_calculate()
286 min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div in __smiapp_pll_calculate()
287 * pll->scale_n, in __smiapp_pll_calculate()
289 * pll->scale_m); in __smiapp_pll_calculate()
291 /* Find smallest and biggest allowed vt divisor. */ in __smiapp_pll_calculate()
294 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
295 limits->vt.max_pix_clk_freq_hz)); in __smiapp_pll_calculate()
299 limits->vt.min_pix_clk_div in __smiapp_pll_calculate()
300 * limits->vt.min_sys_clk_div); in __smiapp_pll_calculate()
303 max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div; in __smiapp_pll_calculate()
306 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
307 limits->vt.min_pix_clk_freq_hz)); in __smiapp_pll_calculate()
315 min_sys_div = limits->vt.min_sys_clk_div; in __smiapp_pll_calculate()
319 limits->vt.max_pix_clk_div)); in __smiapp_pll_calculate()
322 pll->pll_op_clk_freq_hz in __smiapp_pll_calculate()
323 / limits->vt.max_sys_clk_freq_hz); in __smiapp_pll_calculate()
328 max_sys_div = limits->vt.max_sys_clk_div; in __smiapp_pll_calculate()
332 limits->vt.min_pix_clk_div)); in __smiapp_pll_calculate()
335 DIV_ROUND_UP(pll->pll_op_clk_freq_hz, in __smiapp_pll_calculate()
336 limits->vt.min_pix_clk_freq_hz)); in __smiapp_pll_calculate()
345 vt_div += 2 - (vt_div & 1)) { in __smiapp_pll_calculate()
348 sys_div += 2 - (sys_div & 1)) { in __smiapp_pll_calculate()
351 if (pix_div < limits->vt.min_pix_clk_div in __smiapp_pll_calculate()
352 || pix_div > limits->vt.max_pix_clk_div) { in __smiapp_pll_calculate()
354 "pix_div %u too small or too big (%u--%u)\n", in __smiapp_pll_calculate()
356 limits->vt.min_pix_clk_div, in __smiapp_pll_calculate()
357 limits->vt.max_pix_clk_div); in __smiapp_pll_calculate()
370 pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div); in __smiapp_pll_calculate()
371 pll->vt.pix_clk_div = best_pix_div; in __smiapp_pll_calculate()
373 pll->vt.sys_clk_freq_hz = in __smiapp_pll_calculate()
374 pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div; in __smiapp_pll_calculate()
375 pll->vt.pix_clk_freq_hz = in __smiapp_pll_calculate()
376 pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div; in __smiapp_pll_calculate()
379 pll->pixel_rate_csi = in __smiapp_pll_calculate()
380 op_pll->pix_clk_freq_hz * lane_op_clock_ratio; in __smiapp_pll_calculate()
381 pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz; in __smiapp_pll_calculate()
390 const struct smiapp_pll_branch_limits *op_limits = &limits->op; in smiapp_pll_calculate()
391 struct smiapp_pll_branch *op_pll = &pll->op; in smiapp_pll_calculate()
397 int rval = -EINVAL; in smiapp_pll_calculate()
399 if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) { in smiapp_pll_calculate()
401 * If there's no OP PLL at all, use the VT values in smiapp_pll_calculate()
405 op_limits = &limits->vt; in smiapp_pll_calculate()
406 op_pll = &pll->vt; in smiapp_pll_calculate()
409 if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE) in smiapp_pll_calculate()
410 lane_op_clock_ratio = pll->csi2.lanes; in smiapp_pll_calculate()
415 dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal, in smiapp_pll_calculate()
416 pll->binning_vertical); in smiapp_pll_calculate()
418 switch (pll->bus_type) { in smiapp_pll_calculate()
421 pll->pll_op_clk_freq_hz = pll->link_freq * 2 in smiapp_pll_calculate()
422 * (pll->csi2.lanes / lane_op_clock_ratio); in smiapp_pll_calculate()
425 pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel in smiapp_pll_calculate()
426 / DIV_ROUND_UP(pll->bits_per_pixel, in smiapp_pll_calculate()
427 pll->parallel.bus_width); in smiapp_pll_calculate()
430 return -EINVAL; in smiapp_pll_calculate()
433 /* Figure out limits for pre-pll divider based on extclk */ in smiapp_pll_calculate()
435 limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div); in smiapp_pll_calculate()
437 min_t(uint16_t, limits->max_pre_pll_clk_div, in smiapp_pll_calculate()
438 clk_div_even(pll->ext_clk_freq_hz / in smiapp_pll_calculate()
439 limits->min_pll_ip_freq_hz)); in smiapp_pll_calculate()
441 max_t(uint16_t, limits->min_pre_pll_clk_div, in smiapp_pll_calculate()
443 DIV_ROUND_UP(pll->ext_clk_freq_hz, in smiapp_pll_calculate()
444 limits->max_pll_ip_freq_hz))); in smiapp_pll_calculate()
445 dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n", in smiapp_pll_calculate()
448 i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz); in smiapp_pll_calculate()
449 mul = div_u64(pll->pll_op_clk_freq_hz, i); in smiapp_pll_calculate()
450 div = pll->ext_clk_freq_hz / i; in smiapp_pll_calculate()
456 DIV_ROUND_UP(mul * pll->ext_clk_freq_hz, in smiapp_pll_calculate()
457 limits->max_pll_op_freq_hz))); in smiapp_pll_calculate()
461 for (pll->pre_pll_clk_div = min_pre_pll_clk_div; in smiapp_pll_calculate()
462 pll->pre_pll_clk_div <= max_pre_pll_clk_div; in smiapp_pll_calculate()
463 pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) { in smiapp_pll_calculate()