xref: /openbmc/linux/drivers/media/i2c/ccs-pll.c (revision 9e05bbac43ebfc2fd1ff95e072730ceed807d149)
1*9e05bbacSSakari Ailus // SPDX-License-Identifier: GPL-2.0-only
2*9e05bbacSSakari Ailus /*
3*9e05bbacSSakari Ailus  * drivers/media/i2c/ccs-pll.c
4*9e05bbacSSakari Ailus  *
5*9e05bbacSSakari Ailus  * Generic MIPI CCS/SMIA/SMIA++ PLL calculator
6*9e05bbacSSakari Ailus  *
7*9e05bbacSSakari Ailus  * Copyright (C) 2020 Intel Corporation
8*9e05bbacSSakari Ailus  * Copyright (C) 2011--2012 Nokia Corporation
9*9e05bbacSSakari Ailus  * Contact: Sakari Ailus <sakari.ailus@iki.fi>
10*9e05bbacSSakari Ailus  */
11*9e05bbacSSakari Ailus 
12*9e05bbacSSakari Ailus #include <linux/device.h>
13*9e05bbacSSakari Ailus #include <linux/gcd.h>
14*9e05bbacSSakari Ailus #include <linux/lcm.h>
15*9e05bbacSSakari Ailus #include <linux/module.h>
16*9e05bbacSSakari Ailus 
17*9e05bbacSSakari Ailus #include "ccs-pll.h"
18*9e05bbacSSakari Ailus 
19*9e05bbacSSakari Ailus /* Return an even number or one. */
20*9e05bbacSSakari Ailus static inline uint32_t clk_div_even(uint32_t a)
21*9e05bbacSSakari Ailus {
22*9e05bbacSSakari Ailus 	return max_t(uint32_t, 1, a & ~1);
23*9e05bbacSSakari Ailus }
24*9e05bbacSSakari Ailus 
25*9e05bbacSSakari Ailus /* Return an even number or one. */
26*9e05bbacSSakari Ailus static inline uint32_t clk_div_even_up(uint32_t a)
27*9e05bbacSSakari Ailus {
28*9e05bbacSSakari Ailus 	if (a == 1)
29*9e05bbacSSakari Ailus 		return 1;
30*9e05bbacSSakari Ailus 	return (a + 1) & ~1;
31*9e05bbacSSakari Ailus }
32*9e05bbacSSakari Ailus 
33*9e05bbacSSakari Ailus static inline uint32_t is_one_or_even(uint32_t a)
34*9e05bbacSSakari Ailus {
35*9e05bbacSSakari Ailus 	if (a == 1)
36*9e05bbacSSakari Ailus 		return 1;
37*9e05bbacSSakari Ailus 	if (a & 1)
38*9e05bbacSSakari Ailus 		return 0;
39*9e05bbacSSakari Ailus 
40*9e05bbacSSakari Ailus 	return 1;
41*9e05bbacSSakari Ailus }
42*9e05bbacSSakari Ailus 
43*9e05bbacSSakari Ailus static int bounds_check(struct device *dev, uint32_t val,
44*9e05bbacSSakari Ailus 			uint32_t min, uint32_t max, char *str)
45*9e05bbacSSakari Ailus {
46*9e05bbacSSakari Ailus 	if (val >= min && val <= max)
47*9e05bbacSSakari Ailus 		return 0;
48*9e05bbacSSakari Ailus 
49*9e05bbacSSakari Ailus 	dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
50*9e05bbacSSakari Ailus 
51*9e05bbacSSakari Ailus 	return -EINVAL;
52*9e05bbacSSakari Ailus }
53*9e05bbacSSakari Ailus 
54*9e05bbacSSakari Ailus static void print_pll(struct device *dev, struct ccs_pll *pll)
55*9e05bbacSSakari Ailus {
56*9e05bbacSSakari Ailus 	dev_dbg(dev, "pre_pll_clk_div\t%u\n",  pll->pre_pll_clk_div);
57*9e05bbacSSakari Ailus 	dev_dbg(dev, "pll_multiplier \t%u\n",  pll->pll_multiplier);
58*9e05bbacSSakari Ailus 	if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
59*9e05bbacSSakari Ailus 		dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div);
60*9e05bbacSSakari Ailus 		dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div);
61*9e05bbacSSakari Ailus 	}
62*9e05bbacSSakari Ailus 	dev_dbg(dev, "vt_sys_clk_div \t%u\n",  pll->vt.sys_clk_div);
63*9e05bbacSSakari Ailus 	dev_dbg(dev, "vt_pix_clk_div \t%u\n",  pll->vt.pix_clk_div);
64*9e05bbacSSakari Ailus 
65*9e05bbacSSakari Ailus 	dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz);
66*9e05bbacSSakari Ailus 	dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz);
67*9e05bbacSSakari Ailus 	dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz);
68*9e05bbacSSakari Ailus 	if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
69*9e05bbacSSakari Ailus 		dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n",
70*9e05bbacSSakari Ailus 			pll->op.sys_clk_freq_hz);
71*9e05bbacSSakari Ailus 		dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n",
72*9e05bbacSSakari Ailus 			pll->op.pix_clk_freq_hz);
73*9e05bbacSSakari Ailus 	}
74*9e05bbacSSakari Ailus 	dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz);
75*9e05bbacSSakari Ailus 	dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz);
76*9e05bbacSSakari Ailus }
77*9e05bbacSSakari Ailus 
78*9e05bbacSSakari Ailus static int check_all_bounds(struct device *dev,
79*9e05bbacSSakari Ailus 			    const struct ccs_pll_limits *limits,
80*9e05bbacSSakari Ailus 			    const struct ccs_pll_branch_limits *op_limits,
81*9e05bbacSSakari Ailus 			    struct ccs_pll *pll, struct ccs_pll_branch *op_pll)
82*9e05bbacSSakari Ailus {
83*9e05bbacSSakari Ailus 	int rval;
84*9e05bbacSSakari Ailus 
85*9e05bbacSSakari Ailus 	rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
86*9e05bbacSSakari Ailus 			    limits->min_pll_ip_freq_hz,
87*9e05bbacSSakari Ailus 			    limits->max_pll_ip_freq_hz,
88*9e05bbacSSakari Ailus 			    "pll_ip_clk_freq_hz");
89*9e05bbacSSakari Ailus 	if (!rval)
90*9e05bbacSSakari Ailus 		rval = bounds_check(
91*9e05bbacSSakari Ailus 			dev, pll->pll_multiplier,
92*9e05bbacSSakari Ailus 			limits->min_pll_multiplier, limits->max_pll_multiplier,
93*9e05bbacSSakari Ailus 			"pll_multiplier");
94*9e05bbacSSakari Ailus 	if (!rval)
95*9e05bbacSSakari Ailus 		rval = bounds_check(
96*9e05bbacSSakari Ailus 			dev, pll->pll_op_clk_freq_hz,
97*9e05bbacSSakari Ailus 			limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
98*9e05bbacSSakari Ailus 			"pll_op_clk_freq_hz");
99*9e05bbacSSakari Ailus 	if (!rval)
100*9e05bbacSSakari Ailus 		rval = bounds_check(
101*9e05bbacSSakari Ailus 			dev, op_pll->sys_clk_div,
102*9e05bbacSSakari Ailus 			op_limits->min_sys_clk_div, op_limits->max_sys_clk_div,
103*9e05bbacSSakari Ailus 			"op_sys_clk_div");
104*9e05bbacSSakari Ailus 	if (!rval)
105*9e05bbacSSakari Ailus 		rval = bounds_check(
106*9e05bbacSSakari Ailus 			dev, op_pll->sys_clk_freq_hz,
107*9e05bbacSSakari Ailus 			op_limits->min_sys_clk_freq_hz,
108*9e05bbacSSakari Ailus 			op_limits->max_sys_clk_freq_hz,
109*9e05bbacSSakari Ailus 			"op_sys_clk_freq_hz");
110*9e05bbacSSakari Ailus 	if (!rval)
111*9e05bbacSSakari Ailus 		rval = bounds_check(
112*9e05bbacSSakari Ailus 			dev, op_pll->pix_clk_freq_hz,
113*9e05bbacSSakari Ailus 			op_limits->min_pix_clk_freq_hz,
114*9e05bbacSSakari Ailus 			op_limits->max_pix_clk_freq_hz,
115*9e05bbacSSakari Ailus 			"op_pix_clk_freq_hz");
116*9e05bbacSSakari Ailus 
117*9e05bbacSSakari Ailus 	/*
118*9e05bbacSSakari Ailus 	 * If there are no OP clocks, the VT clocks are contained in
119*9e05bbacSSakari Ailus 	 * the OP clock struct.
120*9e05bbacSSakari Ailus 	 */
121*9e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
122*9e05bbacSSakari Ailus 		return rval;
123*9e05bbacSSakari Ailus 
124*9e05bbacSSakari Ailus 	if (!rval)
125*9e05bbacSSakari Ailus 		rval = bounds_check(
126*9e05bbacSSakari Ailus 			dev, pll->vt.sys_clk_freq_hz,
127*9e05bbacSSakari Ailus 			limits->vt.min_sys_clk_freq_hz,
128*9e05bbacSSakari Ailus 			limits->vt.max_sys_clk_freq_hz,
129*9e05bbacSSakari Ailus 			"vt_sys_clk_freq_hz");
130*9e05bbacSSakari Ailus 	if (!rval)
131*9e05bbacSSakari Ailus 		rval = bounds_check(
132*9e05bbacSSakari Ailus 			dev, pll->vt.pix_clk_freq_hz,
133*9e05bbacSSakari Ailus 			limits->vt.min_pix_clk_freq_hz,
134*9e05bbacSSakari Ailus 			limits->vt.max_pix_clk_freq_hz,
135*9e05bbacSSakari Ailus 			"vt_pix_clk_freq_hz");
136*9e05bbacSSakari Ailus 
137*9e05bbacSSakari Ailus 	return rval;
138*9e05bbacSSakari Ailus }
139*9e05bbacSSakari Ailus 
140*9e05bbacSSakari Ailus /*
141*9e05bbacSSakari Ailus  * Heuristically guess the PLL tree for a given common multiplier and
142*9e05bbacSSakari Ailus  * divisor. Begin with the operational timing and continue to video
143*9e05bbacSSakari Ailus  * timing once operational timing has been verified.
144*9e05bbacSSakari Ailus  *
145*9e05bbacSSakari Ailus  * @mul is the PLL multiplier and @div is the common divisor
146*9e05bbacSSakari Ailus  * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
147*9e05bbacSSakari Ailus  * multiplier will be a multiple of @mul.
148*9e05bbacSSakari Ailus  *
149*9e05bbacSSakari Ailus  * @return Zero on success, error code on error.
150*9e05bbacSSakari Ailus  */
151*9e05bbacSSakari Ailus static int
152*9e05bbacSSakari Ailus __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits,
153*9e05bbacSSakari Ailus 		    const struct ccs_pll_branch_limits *op_limits,
154*9e05bbacSSakari Ailus 		    struct ccs_pll *pll, struct ccs_pll_branch *op_pll,
155*9e05bbacSSakari Ailus 		    uint32_t mul, uint32_t div, uint32_t lane_op_clock_ratio)
156*9e05bbacSSakari Ailus {
157*9e05bbacSSakari Ailus 	uint32_t sys_div;
158*9e05bbacSSakari Ailus 	uint32_t best_pix_div = INT_MAX >> 1;
159*9e05bbacSSakari Ailus 	uint32_t vt_op_binning_div;
160*9e05bbacSSakari Ailus 	/*
161*9e05bbacSSakari Ailus 	 * Higher multipliers (and divisors) are often required than
162*9e05bbacSSakari Ailus 	 * necessitated by the external clock and the output clocks.
163*9e05bbacSSakari Ailus 	 * There are limits for all values in the clock tree. These
164*9e05bbacSSakari Ailus 	 * are the minimum and maximum multiplier for mul.
165*9e05bbacSSakari Ailus 	 */
166*9e05bbacSSakari Ailus 	uint32_t more_mul_min, more_mul_max;
167*9e05bbacSSakari Ailus 	uint32_t more_mul_factor;
168*9e05bbacSSakari Ailus 	uint32_t min_vt_div, max_vt_div, vt_div;
169*9e05bbacSSakari Ailus 	uint32_t min_sys_div, max_sys_div;
170*9e05bbacSSakari Ailus 	unsigned int i;
171*9e05bbacSSakari Ailus 
172*9e05bbacSSakari Ailus 	/*
173*9e05bbacSSakari Ailus 	 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
174*9e05bbacSSakari Ailus 	 * too high.
175*9e05bbacSSakari Ailus 	 */
176*9e05bbacSSakari Ailus 	dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div);
177*9e05bbacSSakari Ailus 
178*9e05bbacSSakari Ailus 	/* Don't go above max pll multiplier. */
179*9e05bbacSSakari Ailus 	more_mul_max = limits->max_pll_multiplier / mul;
180*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n",
181*9e05bbacSSakari Ailus 		more_mul_max);
182*9e05bbacSSakari Ailus 	/* Don't go above max pll op frequency. */
183*9e05bbacSSakari Ailus 	more_mul_max =
184*9e05bbacSSakari Ailus 		min_t(uint32_t,
185*9e05bbacSSakari Ailus 		      more_mul_max,
186*9e05bbacSSakari Ailus 		      limits->max_pll_op_freq_hz
187*9e05bbacSSakari Ailus 		      / (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
188*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n",
189*9e05bbacSSakari Ailus 		more_mul_max);
190*9e05bbacSSakari Ailus 	/* Don't go above the division capability of op sys clock divider. */
191*9e05bbacSSakari Ailus 	more_mul_max = min(more_mul_max,
192*9e05bbacSSakari Ailus 			   op_limits->max_sys_clk_div * pll->pre_pll_clk_div
193*9e05bbacSSakari Ailus 			   / div);
194*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
195*9e05bbacSSakari Ailus 		more_mul_max);
196*9e05bbacSSakari Ailus 	/* Ensure we won't go above min_pll_multiplier. */
197*9e05bbacSSakari Ailus 	more_mul_max = min(more_mul_max,
198*9e05bbacSSakari Ailus 			   DIV_ROUND_UP(limits->max_pll_multiplier, mul));
199*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
200*9e05bbacSSakari Ailus 		more_mul_max);
201*9e05bbacSSakari Ailus 
202*9e05bbacSSakari Ailus 	/* Ensure we won't go below min_pll_op_freq_hz. */
203*9e05bbacSSakari Ailus 	more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
204*9e05bbacSSakari Ailus 				    pll->ext_clk_freq_hz / pll->pre_pll_clk_div
205*9e05bbacSSakari Ailus 				    * mul);
206*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n",
207*9e05bbacSSakari Ailus 		more_mul_min);
208*9e05bbacSSakari Ailus 	/* Ensure we won't go below min_pll_multiplier. */
209*9e05bbacSSakari Ailus 	more_mul_min = max(more_mul_min,
210*9e05bbacSSakari Ailus 			   DIV_ROUND_UP(limits->min_pll_multiplier, mul));
211*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n",
212*9e05bbacSSakari Ailus 		more_mul_min);
213*9e05bbacSSakari Ailus 
214*9e05bbacSSakari Ailus 	if (more_mul_min > more_mul_max) {
215*9e05bbacSSakari Ailus 		dev_dbg(dev,
216*9e05bbacSSakari Ailus 			"unable to compute more_mul_min and more_mul_max\n");
217*9e05bbacSSakari Ailus 		return -EINVAL;
218*9e05bbacSSakari Ailus 	}
219*9e05bbacSSakari Ailus 
220*9e05bbacSSakari Ailus 	more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
221*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
222*9e05bbacSSakari Ailus 	more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div);
223*9e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
224*9e05bbacSSakari Ailus 		more_mul_factor);
225*9e05bbacSSakari Ailus 	i = roundup(more_mul_min, more_mul_factor);
226*9e05bbacSSakari Ailus 	if (!is_one_or_even(i))
227*9e05bbacSSakari Ailus 		i <<= 1;
228*9e05bbacSSakari Ailus 
229*9e05bbacSSakari Ailus 	dev_dbg(dev, "final more_mul: %u\n", i);
230*9e05bbacSSakari Ailus 	if (i > more_mul_max) {
231*9e05bbacSSakari Ailus 		dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
232*9e05bbacSSakari Ailus 		return -EINVAL;
233*9e05bbacSSakari Ailus 	}
234*9e05bbacSSakari Ailus 
235*9e05bbacSSakari Ailus 	pll->pll_multiplier = mul * i;
236*9e05bbacSSakari Ailus 	op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div;
237*9e05bbacSSakari Ailus 	dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div);
238*9e05bbacSSakari Ailus 
239*9e05bbacSSakari Ailus 	pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
240*9e05bbacSSakari Ailus 		/ pll->pre_pll_clk_div;
241*9e05bbacSSakari Ailus 
242*9e05bbacSSakari Ailus 	pll->pll_op_clk_freq_hz = pll->pll_ip_clk_freq_hz
243*9e05bbacSSakari Ailus 		* pll->pll_multiplier;
244*9e05bbacSSakari Ailus 
245*9e05bbacSSakari Ailus 	/* Derive pll_op_clk_freq_hz. */
246*9e05bbacSSakari Ailus 	op_pll->sys_clk_freq_hz =
247*9e05bbacSSakari Ailus 		pll->pll_op_clk_freq_hz / op_pll->sys_clk_div;
248*9e05bbacSSakari Ailus 
249*9e05bbacSSakari Ailus 	op_pll->pix_clk_div = pll->bits_per_pixel;
250*9e05bbacSSakari Ailus 	dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div);
251*9e05bbacSSakari Ailus 
252*9e05bbacSSakari Ailus 	op_pll->pix_clk_freq_hz =
253*9e05bbacSSakari Ailus 		op_pll->sys_clk_freq_hz / op_pll->pix_clk_div;
254*9e05bbacSSakari Ailus 
255*9e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
256*9e05bbacSSakari Ailus 		/* No OP clocks --- VT clocks are used instead. */
257*9e05bbacSSakari Ailus 		goto out_skip_vt_calc;
258*9e05bbacSSakari Ailus 	}
259*9e05bbacSSakari Ailus 
260*9e05bbacSSakari Ailus 	/*
261*9e05bbacSSakari Ailus 	 * Some sensors perform analogue binning and some do this
262*9e05bbacSSakari Ailus 	 * digitally. The ones doing this digitally can be roughly be
263*9e05bbacSSakari Ailus 	 * found out using this formula. The ones doing this digitally
264*9e05bbacSSakari Ailus 	 * should run at higher clock rate, so smaller divisor is used
265*9e05bbacSSakari Ailus 	 * on video timing side.
266*9e05bbacSSakari Ailus 	 */
267*9e05bbacSSakari Ailus 	if (limits->min_line_length_pck_bin > limits->min_line_length_pck
268*9e05bbacSSakari Ailus 	    / pll->binning_horizontal)
269*9e05bbacSSakari Ailus 		vt_op_binning_div = pll->binning_horizontal;
270*9e05bbacSSakari Ailus 	else
271*9e05bbacSSakari Ailus 		vt_op_binning_div = 1;
272*9e05bbacSSakari Ailus 	dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
273*9e05bbacSSakari Ailus 
274*9e05bbacSSakari Ailus 	/*
275*9e05bbacSSakari Ailus 	 * Profile 2 supports vt_pix_clk_div E [4, 10]
276*9e05bbacSSakari Ailus 	 *
277*9e05bbacSSakari Ailus 	 * Horizontal binning can be used as a base for difference in
278*9e05bbacSSakari Ailus 	 * divisors. One must make sure that horizontal blanking is
279*9e05bbacSSakari Ailus 	 * enough to accommodate the CSI-2 sync codes.
280*9e05bbacSSakari Ailus 	 *
281*9e05bbacSSakari Ailus 	 * Take scaling factor into account as well.
282*9e05bbacSSakari Ailus 	 *
283*9e05bbacSSakari Ailus 	 * Find absolute limits for the factor of vt divider.
284*9e05bbacSSakari Ailus 	 */
285*9e05bbacSSakari Ailus 	dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
286*9e05bbacSSakari Ailus 	min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div
287*9e05bbacSSakari Ailus 				  * pll->scale_n,
288*9e05bbacSSakari Ailus 				  lane_op_clock_ratio * vt_op_binning_div
289*9e05bbacSSakari Ailus 				  * pll->scale_m);
290*9e05bbacSSakari Ailus 
291*9e05bbacSSakari Ailus 	/* Find smallest and biggest allowed vt divisor. */
292*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
293*9e05bbacSSakari Ailus 	min_vt_div = max(min_vt_div,
294*9e05bbacSSakari Ailus 			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
295*9e05bbacSSakari Ailus 				      limits->vt.max_pix_clk_freq_hz));
296*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
297*9e05bbacSSakari Ailus 		min_vt_div);
298*9e05bbacSSakari Ailus 	min_vt_div = max_t(uint32_t, min_vt_div,
299*9e05bbacSSakari Ailus 			   limits->vt.min_pix_clk_div
300*9e05bbacSSakari Ailus 			   * limits->vt.min_sys_clk_div);
301*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
302*9e05bbacSSakari Ailus 
303*9e05bbacSSakari Ailus 	max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div;
304*9e05bbacSSakari Ailus 	dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
305*9e05bbacSSakari Ailus 	max_vt_div = min(max_vt_div,
306*9e05bbacSSakari Ailus 			 DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
307*9e05bbacSSakari Ailus 				      limits->vt.min_pix_clk_freq_hz));
308*9e05bbacSSakari Ailus 	dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
309*9e05bbacSSakari Ailus 		max_vt_div);
310*9e05bbacSSakari Ailus 
311*9e05bbacSSakari Ailus 	/*
312*9e05bbacSSakari Ailus 	 * Find limitsits for sys_clk_div. Not all values are possible
313*9e05bbacSSakari Ailus 	 * with all values of pix_clk_div.
314*9e05bbacSSakari Ailus 	 */
315*9e05bbacSSakari Ailus 	min_sys_div = limits->vt.min_sys_clk_div;
316*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: %u\n", min_sys_div);
317*9e05bbacSSakari Ailus 	min_sys_div = max(min_sys_div,
318*9e05bbacSSakari Ailus 			  DIV_ROUND_UP(min_vt_div,
319*9e05bbacSSakari Ailus 				       limits->vt.max_pix_clk_div));
320*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div);
321*9e05bbacSSakari Ailus 	min_sys_div = max(min_sys_div,
322*9e05bbacSSakari Ailus 			  pll->pll_op_clk_freq_hz
323*9e05bbacSSakari Ailus 			  / limits->vt.max_sys_clk_freq_hz);
324*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div);
325*9e05bbacSSakari Ailus 	min_sys_div = clk_div_even_up(min_sys_div);
326*9e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div);
327*9e05bbacSSakari Ailus 
328*9e05bbacSSakari Ailus 	max_sys_div = limits->vt.max_sys_clk_div;
329*9e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: %u\n", max_sys_div);
330*9e05bbacSSakari Ailus 	max_sys_div = min(max_sys_div,
331*9e05bbacSSakari Ailus 			  DIV_ROUND_UP(max_vt_div,
332*9e05bbacSSakari Ailus 				       limits->vt.min_pix_clk_div));
333*9e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div);
334*9e05bbacSSakari Ailus 	max_sys_div = min(max_sys_div,
335*9e05bbacSSakari Ailus 			  DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
336*9e05bbacSSakari Ailus 				       limits->vt.min_pix_clk_freq_hz));
337*9e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div);
338*9e05bbacSSakari Ailus 
339*9e05bbacSSakari Ailus 	/*
340*9e05bbacSSakari Ailus 	 * Find pix_div such that a legal pix_div * sys_div results
341*9e05bbacSSakari Ailus 	 * into a value which is not smaller than div, the desired
342*9e05bbacSSakari Ailus 	 * divisor.
343*9e05bbacSSakari Ailus 	 */
344*9e05bbacSSakari Ailus 	for (vt_div = min_vt_div; vt_div <= max_vt_div;
345*9e05bbacSSakari Ailus 	     vt_div += 2 - (vt_div & 1)) {
346*9e05bbacSSakari Ailus 		for (sys_div = min_sys_div;
347*9e05bbacSSakari Ailus 		     sys_div <= max_sys_div;
348*9e05bbacSSakari Ailus 		     sys_div += 2 - (sys_div & 1)) {
349*9e05bbacSSakari Ailus 			uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div);
350*9e05bbacSSakari Ailus 
351*9e05bbacSSakari Ailus 			if (pix_div < limits->vt.min_pix_clk_div
352*9e05bbacSSakari Ailus 			    || pix_div > limits->vt.max_pix_clk_div) {
353*9e05bbacSSakari Ailus 				dev_dbg(dev,
354*9e05bbacSSakari Ailus 					"pix_div %u too small or too big (%u--%u)\n",
355*9e05bbacSSakari Ailus 					pix_div,
356*9e05bbacSSakari Ailus 					limits->vt.min_pix_clk_div,
357*9e05bbacSSakari Ailus 					limits->vt.max_pix_clk_div);
358*9e05bbacSSakari Ailus 				continue;
359*9e05bbacSSakari Ailus 			}
360*9e05bbacSSakari Ailus 
361*9e05bbacSSakari Ailus 			/* Check if this one is better. */
362*9e05bbacSSakari Ailus 			if (pix_div * sys_div
363*9e05bbacSSakari Ailus 			    <= roundup(min_vt_div, best_pix_div))
364*9e05bbacSSakari Ailus 				best_pix_div = pix_div;
365*9e05bbacSSakari Ailus 		}
366*9e05bbacSSakari Ailus 		if (best_pix_div < INT_MAX >> 1)
367*9e05bbacSSakari Ailus 			break;
368*9e05bbacSSakari Ailus 	}
369*9e05bbacSSakari Ailus 
370*9e05bbacSSakari Ailus 	pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
371*9e05bbacSSakari Ailus 	pll->vt.pix_clk_div = best_pix_div;
372*9e05bbacSSakari Ailus 
373*9e05bbacSSakari Ailus 	pll->vt.sys_clk_freq_hz =
374*9e05bbacSSakari Ailus 		pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div;
375*9e05bbacSSakari Ailus 	pll->vt.pix_clk_freq_hz =
376*9e05bbacSSakari Ailus 		pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div;
377*9e05bbacSSakari Ailus 
378*9e05bbacSSakari Ailus out_skip_vt_calc:
379*9e05bbacSSakari Ailus 	pll->pixel_rate_csi =
380*9e05bbacSSakari Ailus 		op_pll->pix_clk_freq_hz * lane_op_clock_ratio;
381*9e05bbacSSakari Ailus 	pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz;
382*9e05bbacSSakari Ailus 
383*9e05bbacSSakari Ailus 	return check_all_bounds(dev, limits, op_limits, pll, op_pll);
384*9e05bbacSSakari Ailus }
385*9e05bbacSSakari Ailus 
386*9e05bbacSSakari Ailus int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *limits,
387*9e05bbacSSakari Ailus 		      struct ccs_pll *pll)
388*9e05bbacSSakari Ailus {
389*9e05bbacSSakari Ailus 	const struct ccs_pll_branch_limits *op_limits = &limits->op;
390*9e05bbacSSakari Ailus 	struct ccs_pll_branch *op_pll = &pll->op;
391*9e05bbacSSakari Ailus 	uint16_t min_pre_pll_clk_div;
392*9e05bbacSSakari Ailus 	uint16_t max_pre_pll_clk_div;
393*9e05bbacSSakari Ailus 	uint32_t lane_op_clock_ratio;
394*9e05bbacSSakari Ailus 	uint32_t mul, div;
395*9e05bbacSSakari Ailus 	unsigned int i;
396*9e05bbacSSakari Ailus 	int rval = -EINVAL;
397*9e05bbacSSakari Ailus 
398*9e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
399*9e05bbacSSakari Ailus 		/*
400*9e05bbacSSakari Ailus 		 * If there's no OP PLL at all, use the VT values
401*9e05bbacSSakari Ailus 		 * instead. The OP values are ignored for the rest of
402*9e05bbacSSakari Ailus 		 * the PLL calculation.
403*9e05bbacSSakari Ailus 		 */
404*9e05bbacSSakari Ailus 		op_limits = &limits->vt;
405*9e05bbacSSakari Ailus 		op_pll = &pll->vt;
406*9e05bbacSSakari Ailus 	}
407*9e05bbacSSakari Ailus 
408*9e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
409*9e05bbacSSakari Ailus 		lane_op_clock_ratio = pll->csi2.lanes;
410*9e05bbacSSakari Ailus 	else
411*9e05bbacSSakari Ailus 		lane_op_clock_ratio = 1;
412*9e05bbacSSakari Ailus 	dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio);
413*9e05bbacSSakari Ailus 
414*9e05bbacSSakari Ailus 	dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
415*9e05bbacSSakari Ailus 		pll->binning_vertical);
416*9e05bbacSSakari Ailus 
417*9e05bbacSSakari Ailus 	switch (pll->bus_type) {
418*9e05bbacSSakari Ailus 	case CCS_PLL_BUS_TYPE_CSI2:
419*9e05bbacSSakari Ailus 		/* CSI transfers 2 bits per clock per lane; thus times 2 */
420*9e05bbacSSakari Ailus 		pll->pll_op_clk_freq_hz = pll->link_freq * 2
421*9e05bbacSSakari Ailus 			* (pll->csi2.lanes / lane_op_clock_ratio);
422*9e05bbacSSakari Ailus 		break;
423*9e05bbacSSakari Ailus 	case CCS_PLL_BUS_TYPE_PARALLEL:
424*9e05bbacSSakari Ailus 		pll->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel
425*9e05bbacSSakari Ailus 			/ DIV_ROUND_UP(pll->bits_per_pixel,
426*9e05bbacSSakari Ailus 				       pll->parallel.bus_width);
427*9e05bbacSSakari Ailus 		break;
428*9e05bbacSSakari Ailus 	default:
429*9e05bbacSSakari Ailus 		return -EINVAL;
430*9e05bbacSSakari Ailus 	}
431*9e05bbacSSakari Ailus 
432*9e05bbacSSakari Ailus 	/* Figure out limits for pre-pll divider based on extclk */
433*9e05bbacSSakari Ailus 	dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n",
434*9e05bbacSSakari Ailus 		limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
435*9e05bbacSSakari Ailus 	max_pre_pll_clk_div =
436*9e05bbacSSakari Ailus 		min_t(uint16_t, limits->max_pre_pll_clk_div,
437*9e05bbacSSakari Ailus 		      clk_div_even(pll->ext_clk_freq_hz /
438*9e05bbacSSakari Ailus 				   limits->min_pll_ip_freq_hz));
439*9e05bbacSSakari Ailus 	min_pre_pll_clk_div =
440*9e05bbacSSakari Ailus 		max_t(uint16_t, limits->min_pre_pll_clk_div,
441*9e05bbacSSakari Ailus 		      clk_div_even_up(
442*9e05bbacSSakari Ailus 			      DIV_ROUND_UP(pll->ext_clk_freq_hz,
443*9e05bbacSSakari Ailus 					   limits->max_pll_ip_freq_hz)));
444*9e05bbacSSakari Ailus 	dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n",
445*9e05bbacSSakari Ailus 		min_pre_pll_clk_div, max_pre_pll_clk_div);
446*9e05bbacSSakari Ailus 
447*9e05bbacSSakari Ailus 	i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
448*9e05bbacSSakari Ailus 	mul = div_u64(pll->pll_op_clk_freq_hz, i);
449*9e05bbacSSakari Ailus 	div = pll->ext_clk_freq_hz / i;
450*9e05bbacSSakari Ailus 	dev_dbg(dev, "mul %u / div %u\n", mul, div);
451*9e05bbacSSakari Ailus 
452*9e05bbacSSakari Ailus 	min_pre_pll_clk_div =
453*9e05bbacSSakari Ailus 		max_t(uint16_t, min_pre_pll_clk_div,
454*9e05bbacSSakari Ailus 		      clk_div_even_up(
455*9e05bbacSSakari Ailus 			      DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
456*9e05bbacSSakari Ailus 					   limits->max_pll_op_freq_hz)));
457*9e05bbacSSakari Ailus 	dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n",
458*9e05bbacSSakari Ailus 		min_pre_pll_clk_div, max_pre_pll_clk_div);
459*9e05bbacSSakari Ailus 
460*9e05bbacSSakari Ailus 	for (pll->pre_pll_clk_div = min_pre_pll_clk_div;
461*9e05bbacSSakari Ailus 	     pll->pre_pll_clk_div <= max_pre_pll_clk_div;
462*9e05bbacSSakari Ailus 	     pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
463*9e05bbacSSakari Ailus 		rval = __ccs_pll_calculate(dev, limits, op_limits, pll, op_pll,
464*9e05bbacSSakari Ailus 					   mul, div, lane_op_clock_ratio);
465*9e05bbacSSakari Ailus 		if (rval)
466*9e05bbacSSakari Ailus 			continue;
467*9e05bbacSSakari Ailus 
468*9e05bbacSSakari Ailus 		print_pll(dev, pll);
469*9e05bbacSSakari Ailus 		return 0;
470*9e05bbacSSakari Ailus 	}
471*9e05bbacSSakari Ailus 
472*9e05bbacSSakari Ailus 	dev_dbg(dev, "unable to compute pre_pll divisor\n");
473*9e05bbacSSakari Ailus 
474*9e05bbacSSakari Ailus 	return rval;
475*9e05bbacSSakari Ailus }
476*9e05bbacSSakari Ailus EXPORT_SYMBOL_GPL(ccs_pll_calculate);
477*9e05bbacSSakari Ailus 
478*9e05bbacSSakari Ailus MODULE_AUTHOR("Sakari Ailus <sakari.ailus@iki.fi>");
479*9e05bbacSSakari Ailus MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator");
480*9e05bbacSSakari Ailus MODULE_LICENSE("GPL");
481