xref: /openbmc/linux/drivers/media/i2c/ccs-pll.c (revision 415ddd9939783cb79790aba1833ea39fd335caed)
19e05bbacSSakari Ailus // SPDX-License-Identifier: GPL-2.0-only
29e05bbacSSakari Ailus /*
39e05bbacSSakari Ailus  * drivers/media/i2c/ccs-pll.c
49e05bbacSSakari Ailus  *
59e05bbacSSakari Ailus  * Generic MIPI CCS/SMIA/SMIA++ PLL calculator
69e05bbacSSakari Ailus  *
79e05bbacSSakari Ailus  * Copyright (C) 2020 Intel Corporation
89e05bbacSSakari Ailus  * Copyright (C) 2011--2012 Nokia Corporation
97389d01cSSakari Ailus  * Contact: Sakari Ailus <sakari.ailus@linux.intel.com>
109e05bbacSSakari Ailus  */
119e05bbacSSakari Ailus 
129e05bbacSSakari Ailus #include <linux/device.h>
139e05bbacSSakari Ailus #include <linux/gcd.h>
149e05bbacSSakari Ailus #include <linux/lcm.h>
159e05bbacSSakari Ailus #include <linux/module.h>
169e05bbacSSakari Ailus 
179e05bbacSSakari Ailus #include "ccs-pll.h"
189e05bbacSSakari Ailus 
199e05bbacSSakari Ailus /* Return an even number or one. */
209e05bbacSSakari Ailus static inline uint32_t clk_div_even(uint32_t a)
219e05bbacSSakari Ailus {
229e05bbacSSakari Ailus 	return max_t(uint32_t, 1, a & ~1);
239e05bbacSSakari Ailus }
249e05bbacSSakari Ailus 
259e05bbacSSakari Ailus /* Return an even number or one. */
269e05bbacSSakari Ailus static inline uint32_t clk_div_even_up(uint32_t a)
279e05bbacSSakari Ailus {
289e05bbacSSakari Ailus 	if (a == 1)
299e05bbacSSakari Ailus 		return 1;
309e05bbacSSakari Ailus 	return (a + 1) & ~1;
319e05bbacSSakari Ailus }
329e05bbacSSakari Ailus 
339e05bbacSSakari Ailus static inline uint32_t is_one_or_even(uint32_t a)
349e05bbacSSakari Ailus {
359e05bbacSSakari Ailus 	if (a == 1)
369e05bbacSSakari Ailus 		return 1;
379e05bbacSSakari Ailus 	if (a & 1)
389e05bbacSSakari Ailus 		return 0;
399e05bbacSSakari Ailus 
409e05bbacSSakari Ailus 	return 1;
419e05bbacSSakari Ailus }
429e05bbacSSakari Ailus 
439e05bbacSSakari Ailus static int bounds_check(struct device *dev, uint32_t val,
449e05bbacSSakari Ailus 			uint32_t min, uint32_t max, char *str)
459e05bbacSSakari Ailus {
469e05bbacSSakari Ailus 	if (val >= min && val <= max)
479e05bbacSSakari Ailus 		return 0;
489e05bbacSSakari Ailus 
499e05bbacSSakari Ailus 	dev_dbg(dev, "%s out of bounds: %d (%d--%d)\n", str, val, min, max);
509e05bbacSSakari Ailus 
519e05bbacSSakari Ailus 	return -EINVAL;
529e05bbacSSakari Ailus }
539e05bbacSSakari Ailus 
549e05bbacSSakari Ailus static void print_pll(struct device *dev, struct ccs_pll *pll)
559e05bbacSSakari Ailus {
56*415ddd99SSakari Ailus 	dev_dbg(dev, "pre_pll_clk_div\t%u\n",  pll->vt_fr.pre_pll_clk_div);
57*415ddd99SSakari Ailus 	dev_dbg(dev, "pll_multiplier \t%u\n",  pll->vt_fr.pll_multiplier);
589e05bbacSSakari Ailus 	if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
59*415ddd99SSakari Ailus 		dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op_bk.sys_clk_div);
60*415ddd99SSakari Ailus 		dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op_bk.pix_clk_div);
619e05bbacSSakari Ailus 	}
62*415ddd99SSakari Ailus 	dev_dbg(dev, "vt_sys_clk_div \t%u\n",  pll->vt_bk.sys_clk_div);
63*415ddd99SSakari Ailus 	dev_dbg(dev, "vt_pix_clk_div \t%u\n",  pll->vt_bk.pix_clk_div);
649e05bbacSSakari Ailus 
659e05bbacSSakari Ailus 	dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz);
66*415ddd99SSakari Ailus 	dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->vt_fr.pll_ip_clk_freq_hz);
67*415ddd99SSakari Ailus 	dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->vt_fr.pll_op_clk_freq_hz);
689e05bbacSSakari Ailus 	if (!(pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)) {
699e05bbacSSakari Ailus 		dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n",
70*415ddd99SSakari Ailus 			pll->op_bk.sys_clk_freq_hz);
719e05bbacSSakari Ailus 		dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n",
72*415ddd99SSakari Ailus 			pll->op_bk.pix_clk_freq_hz);
739e05bbacSSakari Ailus 	}
74*415ddd99SSakari Ailus 	dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt_bk.sys_clk_freq_hz);
75*415ddd99SSakari Ailus 	dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt_bk.pix_clk_freq_hz);
769e05bbacSSakari Ailus }
779e05bbacSSakari Ailus 
789e05bbacSSakari Ailus static int check_all_bounds(struct device *dev,
79*415ddd99SSakari Ailus 			    const struct ccs_pll_limits *lim,
80*415ddd99SSakari Ailus 			    const struct ccs_pll_branch_limits_fr *op_lim_fr,
81*415ddd99SSakari Ailus 			    const struct ccs_pll_branch_limits_bk *op_lim_bk,
82*415ddd99SSakari Ailus 			    struct ccs_pll *pll,
83*415ddd99SSakari Ailus 			    struct ccs_pll_branch_fr *op_pll_fr,
84*415ddd99SSakari Ailus 			    struct ccs_pll_branch_bk *op_pll_bk)
859e05bbacSSakari Ailus {
869e05bbacSSakari Ailus 	int rval;
879e05bbacSSakari Ailus 
88*415ddd99SSakari Ailus 	rval = bounds_check(dev, op_pll_fr->pll_ip_clk_freq_hz,
89*415ddd99SSakari Ailus 			    op_lim_fr->min_pll_ip_clk_freq_hz,
90*415ddd99SSakari Ailus 			    op_lim_fr->max_pll_ip_clk_freq_hz,
919e05bbacSSakari Ailus 			    "pll_ip_clk_freq_hz");
929e05bbacSSakari Ailus 	if (!rval)
939e05bbacSSakari Ailus 		rval = bounds_check(
94*415ddd99SSakari Ailus 			dev, op_pll_fr->pll_multiplier,
95*415ddd99SSakari Ailus 			op_lim_fr->min_pll_multiplier,
96*415ddd99SSakari Ailus 			op_lim_fr->max_pll_multiplier, "pll_multiplier");
979e05bbacSSakari Ailus 	if (!rval)
989e05bbacSSakari Ailus 		rval = bounds_check(
99*415ddd99SSakari Ailus 			dev, op_pll_fr->pll_op_clk_freq_hz,
100*415ddd99SSakari Ailus 			op_lim_fr->min_pll_op_clk_freq_hz,
101*415ddd99SSakari Ailus 			op_lim_fr->max_pll_op_clk_freq_hz, "pll_op_clk_freq_hz");
1029e05bbacSSakari Ailus 	if (!rval)
1039e05bbacSSakari Ailus 		rval = bounds_check(
104*415ddd99SSakari Ailus 			dev, op_pll_bk->sys_clk_div,
105*415ddd99SSakari Ailus 			op_lim_bk->min_sys_clk_div, op_lim_bk->max_sys_clk_div,
1069e05bbacSSakari Ailus 			"op_sys_clk_div");
1079e05bbacSSakari Ailus 	if (!rval)
1089e05bbacSSakari Ailus 		rval = bounds_check(
109*415ddd99SSakari Ailus 			dev, op_pll_bk->sys_clk_freq_hz,
110*415ddd99SSakari Ailus 			op_lim_bk->min_sys_clk_freq_hz,
111*415ddd99SSakari Ailus 			op_lim_bk->max_sys_clk_freq_hz,
1129e05bbacSSakari Ailus 			"op_sys_clk_freq_hz");
1139e05bbacSSakari Ailus 	if (!rval)
1149e05bbacSSakari Ailus 		rval = bounds_check(
115*415ddd99SSakari Ailus 			dev, op_pll_bk->pix_clk_freq_hz,
116*415ddd99SSakari Ailus 			op_lim_bk->min_pix_clk_freq_hz,
117*415ddd99SSakari Ailus 			op_lim_bk->max_pix_clk_freq_hz,
1189e05bbacSSakari Ailus 			"op_pix_clk_freq_hz");
1199e05bbacSSakari Ailus 
1209e05bbacSSakari Ailus 	/*
1219e05bbacSSakari Ailus 	 * If there are no OP clocks, the VT clocks are contained in
1229e05bbacSSakari Ailus 	 * the OP clock struct.
1239e05bbacSSakari Ailus 	 */
1249e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS)
1259e05bbacSSakari Ailus 		return rval;
1269e05bbacSSakari Ailus 
1279e05bbacSSakari Ailus 	if (!rval)
1289e05bbacSSakari Ailus 		rval = bounds_check(
129*415ddd99SSakari Ailus 			dev, pll->vt_bk.sys_clk_freq_hz,
130*415ddd99SSakari Ailus 			lim->vt_bk.min_sys_clk_freq_hz,
131*415ddd99SSakari Ailus 			lim->vt_bk.max_sys_clk_freq_hz,
1329e05bbacSSakari Ailus 			"vt_sys_clk_freq_hz");
1339e05bbacSSakari Ailus 	if (!rval)
1349e05bbacSSakari Ailus 		rval = bounds_check(
135*415ddd99SSakari Ailus 			dev, pll->vt_bk.pix_clk_freq_hz,
136*415ddd99SSakari Ailus 			lim->vt_bk.min_pix_clk_freq_hz,
137*415ddd99SSakari Ailus 			lim->vt_bk.max_pix_clk_freq_hz,
1389e05bbacSSakari Ailus 			"vt_pix_clk_freq_hz");
1399e05bbacSSakari Ailus 
1409e05bbacSSakari Ailus 	return rval;
1419e05bbacSSakari Ailus }
1429e05bbacSSakari Ailus 
1439e05bbacSSakari Ailus /*
1449e05bbacSSakari Ailus  * Heuristically guess the PLL tree for a given common multiplier and
1459e05bbacSSakari Ailus  * divisor. Begin with the operational timing and continue to video
1469e05bbacSSakari Ailus  * timing once operational timing has been verified.
1479e05bbacSSakari Ailus  *
1489e05bbacSSakari Ailus  * @mul is the PLL multiplier and @div is the common divisor
1499e05bbacSSakari Ailus  * (pre_pll_clk_div and op_sys_clk_div combined). The final PLL
1509e05bbacSSakari Ailus  * multiplier will be a multiple of @mul.
1519e05bbacSSakari Ailus  *
1529e05bbacSSakari Ailus  * @return Zero on success, error code on error.
1539e05bbacSSakari Ailus  */
1549e05bbacSSakari Ailus static int
155*415ddd99SSakari Ailus __ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
156*415ddd99SSakari Ailus 		    const struct ccs_pll_branch_limits_fr *op_lim_fr,
157*415ddd99SSakari Ailus 		    const struct ccs_pll_branch_limits_bk *op_lim_bk,
158*415ddd99SSakari Ailus 		    struct ccs_pll *pll, struct ccs_pll_branch_fr *op_pll_fr,
159*415ddd99SSakari Ailus 		    struct ccs_pll_branch_bk *op_pll_bk, uint32_t mul,
160*415ddd99SSakari Ailus 		    uint32_t div, uint32_t lane_op_clock_ratio)
1619e05bbacSSakari Ailus {
1629e05bbacSSakari Ailus 	uint32_t sys_div;
1639e05bbacSSakari Ailus 	uint32_t best_pix_div = INT_MAX >> 1;
1649e05bbacSSakari Ailus 	uint32_t vt_op_binning_div;
1659e05bbacSSakari Ailus 	/*
1669e05bbacSSakari Ailus 	 * Higher multipliers (and divisors) are often required than
1679e05bbacSSakari Ailus 	 * necessitated by the external clock and the output clocks.
1689e05bbacSSakari Ailus 	 * There are limits for all values in the clock tree. These
1699e05bbacSSakari Ailus 	 * are the minimum and maximum multiplier for mul.
1709e05bbacSSakari Ailus 	 */
1719e05bbacSSakari Ailus 	uint32_t more_mul_min, more_mul_max;
1729e05bbacSSakari Ailus 	uint32_t more_mul_factor;
1739e05bbacSSakari Ailus 	uint32_t min_vt_div, max_vt_div, vt_div;
1749e05bbacSSakari Ailus 	uint32_t min_sys_div, max_sys_div;
1759e05bbacSSakari Ailus 	unsigned int i;
1769e05bbacSSakari Ailus 
1779e05bbacSSakari Ailus 	/*
1789e05bbacSSakari Ailus 	 * Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
1799e05bbacSSakari Ailus 	 * too high.
1809e05bbacSSakari Ailus 	 */
181*415ddd99SSakari Ailus 	dev_dbg(dev, "op_pre_pll_clk_div %u\n", op_pll_fr->pre_pll_clk_div);
1829e05bbacSSakari Ailus 
1839e05bbacSSakari Ailus 	/* Don't go above max pll multiplier. */
184*415ddd99SSakari Ailus 	more_mul_max = op_lim_fr->max_pll_multiplier / mul;
185*415ddd99SSakari Ailus 	dev_dbg(dev, "more_mul_max: max_op_pll_multiplier check: %u\n",
1869e05bbacSSakari Ailus 		more_mul_max);
1879e05bbacSSakari Ailus 	/* Don't go above max pll op frequency. */
1889e05bbacSSakari Ailus 	more_mul_max =
1899e05bbacSSakari Ailus 		min_t(uint32_t,
1909e05bbacSSakari Ailus 		      more_mul_max,
191*415ddd99SSakari Ailus 		      op_lim_fr->max_pll_op_clk_freq_hz
192*415ddd99SSakari Ailus 		      / (pll->ext_clk_freq_hz / op_pll_fr->pre_pll_clk_div * mul));
193*415ddd99SSakari Ailus 	dev_dbg(dev, "more_mul_max: max_pll_op_clk_freq_hz check: %u\n",
1949e05bbacSSakari Ailus 		more_mul_max);
1959e05bbacSSakari Ailus 	/* Don't go above the division capability of op sys clock divider. */
1969e05bbacSSakari Ailus 	more_mul_max = min(more_mul_max,
197*415ddd99SSakari Ailus 			   op_lim_bk->max_sys_clk_div * op_pll_fr->pre_pll_clk_div
1989e05bbacSSakari Ailus 			   / div);
1999e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
2009e05bbacSSakari Ailus 		more_mul_max);
2019e05bbacSSakari Ailus 	/* Ensure we won't go above min_pll_multiplier. */
2029e05bbacSSakari Ailus 	more_mul_max = min(more_mul_max,
203*415ddd99SSakari Ailus 			   DIV_ROUND_UP(op_lim_fr->max_pll_multiplier, mul));
2049e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
2059e05bbacSSakari Ailus 		more_mul_max);
2069e05bbacSSakari Ailus 
207*415ddd99SSakari Ailus 	/* Ensure we won't go below min_pll_op_clk_freq_hz. */
208*415ddd99SSakari Ailus 	more_mul_min = DIV_ROUND_UP(op_lim_fr->min_pll_op_clk_freq_hz,
209*415ddd99SSakari Ailus 				    pll->ext_clk_freq_hz /
210*415ddd99SSakari Ailus 				    op_pll_fr->pre_pll_clk_div * mul);
211*415ddd99SSakari Ailus 	dev_dbg(dev, "more_mul_min: min_op_pll_op_clk_freq_hz check: %u\n",
2129e05bbacSSakari Ailus 		more_mul_min);
2139e05bbacSSakari Ailus 	/* Ensure we won't go below min_pll_multiplier. */
2149e05bbacSSakari Ailus 	more_mul_min = max(more_mul_min,
215*415ddd99SSakari Ailus 			   DIV_ROUND_UP(op_lim_fr->min_pll_multiplier, mul));
216*415ddd99SSakari Ailus 	dev_dbg(dev, "more_mul_min: min_op_pll_multiplier check: %u\n",
2179e05bbacSSakari Ailus 		more_mul_min);
2189e05bbacSSakari Ailus 
2199e05bbacSSakari Ailus 	if (more_mul_min > more_mul_max) {
2209e05bbacSSakari Ailus 		dev_dbg(dev,
2219e05bbacSSakari Ailus 			"unable to compute more_mul_min and more_mul_max\n");
2229e05bbacSSakari Ailus 		return -EINVAL;
2239e05bbacSSakari Ailus 	}
2249e05bbacSSakari Ailus 
225*415ddd99SSakari Ailus 	more_mul_factor = lcm(div, op_pll_fr->pre_pll_clk_div) / div;
2269e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
227*415ddd99SSakari Ailus 	more_mul_factor = lcm(more_mul_factor, op_lim_bk->min_sys_clk_div);
2289e05bbacSSakari Ailus 	dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
2299e05bbacSSakari Ailus 		more_mul_factor);
2309e05bbacSSakari Ailus 	i = roundup(more_mul_min, more_mul_factor);
2319e05bbacSSakari Ailus 	if (!is_one_or_even(i))
2329e05bbacSSakari Ailus 		i <<= 1;
2339e05bbacSSakari Ailus 
2349e05bbacSSakari Ailus 	dev_dbg(dev, "final more_mul: %u\n", i);
2359e05bbacSSakari Ailus 	if (i > more_mul_max) {
2369e05bbacSSakari Ailus 		dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
2379e05bbacSSakari Ailus 		return -EINVAL;
2389e05bbacSSakari Ailus 	}
2399e05bbacSSakari Ailus 
240*415ddd99SSakari Ailus 	op_pll_fr->pll_multiplier = mul * i;
241*415ddd99SSakari Ailus 	op_pll_bk->sys_clk_div = div * i / op_pll_fr->pre_pll_clk_div;
242*415ddd99SSakari Ailus 	dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll_bk->sys_clk_div);
2439e05bbacSSakari Ailus 
244*415ddd99SSakari Ailus 	op_pll_fr->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
245*415ddd99SSakari Ailus 		/ op_pll_fr->pre_pll_clk_div;
2469e05bbacSSakari Ailus 
247*415ddd99SSakari Ailus 	op_pll_fr->pll_op_clk_freq_hz = op_pll_fr->pll_ip_clk_freq_hz
248*415ddd99SSakari Ailus 		* op_pll_fr->pll_multiplier;
2499e05bbacSSakari Ailus 
2509e05bbacSSakari Ailus 	/* Derive pll_op_clk_freq_hz. */
251*415ddd99SSakari Ailus 	op_pll_bk->sys_clk_freq_hz =
252*415ddd99SSakari Ailus 		op_pll_fr->pll_op_clk_freq_hz / op_pll_bk->sys_clk_div;
2539e05bbacSSakari Ailus 
254*415ddd99SSakari Ailus 	op_pll_bk->pix_clk_div = pll->bits_per_pixel;
255*415ddd99SSakari Ailus 	dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll_bk->pix_clk_div);
2569e05bbacSSakari Ailus 
257*415ddd99SSakari Ailus 	op_pll_bk->pix_clk_freq_hz =
258*415ddd99SSakari Ailus 		op_pll_bk->sys_clk_freq_hz / op_pll_bk->pix_clk_div;
2599e05bbacSSakari Ailus 
2609e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
2619e05bbacSSakari Ailus 		/* No OP clocks --- VT clocks are used instead. */
2629e05bbacSSakari Ailus 		goto out_skip_vt_calc;
2639e05bbacSSakari Ailus 	}
2649e05bbacSSakari Ailus 
2659e05bbacSSakari Ailus 	/*
2669e05bbacSSakari Ailus 	 * Some sensors perform analogue binning and some do this
2679e05bbacSSakari Ailus 	 * digitally. The ones doing this digitally can be roughly be
2689e05bbacSSakari Ailus 	 * found out using this formula. The ones doing this digitally
2699e05bbacSSakari Ailus 	 * should run at higher clock rate, so smaller divisor is used
2709e05bbacSSakari Ailus 	 * on video timing side.
2719e05bbacSSakari Ailus 	 */
272*415ddd99SSakari Ailus 	if (lim->min_line_length_pck_bin > lim->min_line_length_pck
2739e05bbacSSakari Ailus 	    / pll->binning_horizontal)
2749e05bbacSSakari Ailus 		vt_op_binning_div = pll->binning_horizontal;
2759e05bbacSSakari Ailus 	else
2769e05bbacSSakari Ailus 		vt_op_binning_div = 1;
2779e05bbacSSakari Ailus 	dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
2789e05bbacSSakari Ailus 
2799e05bbacSSakari Ailus 	/*
2809e05bbacSSakari Ailus 	 * Profile 2 supports vt_pix_clk_div E [4, 10]
2819e05bbacSSakari Ailus 	 *
2829e05bbacSSakari Ailus 	 * Horizontal binning can be used as a base for difference in
2839e05bbacSSakari Ailus 	 * divisors. One must make sure that horizontal blanking is
2849e05bbacSSakari Ailus 	 * enough to accommodate the CSI-2 sync codes.
2859e05bbacSSakari Ailus 	 *
2869e05bbacSSakari Ailus 	 * Take scaling factor into account as well.
2879e05bbacSSakari Ailus 	 *
2889e05bbacSSakari Ailus 	 * Find absolute limits for the factor of vt divider.
2899e05bbacSSakari Ailus 	 */
2909e05bbacSSakari Ailus 	dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
291*415ddd99SSakari Ailus 	min_vt_div = DIV_ROUND_UP(op_pll_bk->pix_clk_div
292*415ddd99SSakari Ailus 				  * op_pll_bk->sys_clk_div * pll->scale_n,
2939e05bbacSSakari Ailus 				  lane_op_clock_ratio * vt_op_binning_div
2949e05bbacSSakari Ailus 				  * pll->scale_m);
2959e05bbacSSakari Ailus 
2969e05bbacSSakari Ailus 	/* Find smallest and biggest allowed vt divisor. */
2979e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
2989e05bbacSSakari Ailus 	min_vt_div = max(min_vt_div,
299*415ddd99SSakari Ailus 			 DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz,
300*415ddd99SSakari Ailus 				      lim->vt_bk.max_pix_clk_freq_hz));
3019e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
3029e05bbacSSakari Ailus 		min_vt_div);
3039e05bbacSSakari Ailus 	min_vt_div = max_t(uint32_t, min_vt_div,
304*415ddd99SSakari Ailus 			   lim->vt_bk.min_pix_clk_div
305*415ddd99SSakari Ailus 			   * lim->vt_bk.min_sys_clk_div);
3069e05bbacSSakari Ailus 	dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
3079e05bbacSSakari Ailus 
308*415ddd99SSakari Ailus 	max_vt_div = lim->vt_bk.max_sys_clk_div * lim->vt_bk.max_pix_clk_div;
3099e05bbacSSakari Ailus 	dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
3109e05bbacSSakari Ailus 	max_vt_div = min(max_vt_div,
311*415ddd99SSakari Ailus 			 DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz,
312*415ddd99SSakari Ailus 				      lim->vt_bk.min_pix_clk_freq_hz));
3139e05bbacSSakari Ailus 	dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
3149e05bbacSSakari Ailus 		max_vt_div);
3159e05bbacSSakari Ailus 
3169e05bbacSSakari Ailus 	/*
3179e05bbacSSakari Ailus 	 * Find limitsits for sys_clk_div. Not all values are possible
3189e05bbacSSakari Ailus 	 * with all values of pix_clk_div.
3199e05bbacSSakari Ailus 	 */
320*415ddd99SSakari Ailus 	min_sys_div = lim->vt_bk.min_sys_clk_div;
3219e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: %u\n", min_sys_div);
3229e05bbacSSakari Ailus 	min_sys_div = max(min_sys_div,
3239e05bbacSSakari Ailus 			  DIV_ROUND_UP(min_vt_div,
324*415ddd99SSakari Ailus 				       lim->vt_bk.max_pix_clk_div));
3259e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div);
3269e05bbacSSakari Ailus 	min_sys_div = max(min_sys_div,
327*415ddd99SSakari Ailus 			  op_pll_fr->pll_op_clk_freq_hz
328*415ddd99SSakari Ailus 			  / lim->vt_bk.max_sys_clk_freq_hz);
3299e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div);
3309e05bbacSSakari Ailus 	min_sys_div = clk_div_even_up(min_sys_div);
3319e05bbacSSakari Ailus 	dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div);
3329e05bbacSSakari Ailus 
333*415ddd99SSakari Ailus 	max_sys_div = lim->vt_bk.max_sys_clk_div;
3349e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: %u\n", max_sys_div);
3359e05bbacSSakari Ailus 	max_sys_div = min(max_sys_div,
3369e05bbacSSakari Ailus 			  DIV_ROUND_UP(max_vt_div,
337*415ddd99SSakari Ailus 				       lim->vt_bk.min_pix_clk_div));
3389e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div);
3399e05bbacSSakari Ailus 	max_sys_div = min(max_sys_div,
340*415ddd99SSakari Ailus 			  DIV_ROUND_UP(op_pll_fr->pll_op_clk_freq_hz,
341*415ddd99SSakari Ailus 				       lim->vt_bk.min_pix_clk_freq_hz));
3429e05bbacSSakari Ailus 	dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div);
3439e05bbacSSakari Ailus 
3449e05bbacSSakari Ailus 	/*
3459e05bbacSSakari Ailus 	 * Find pix_div such that a legal pix_div * sys_div results
3469e05bbacSSakari Ailus 	 * into a value which is not smaller than div, the desired
3479e05bbacSSakari Ailus 	 * divisor.
3489e05bbacSSakari Ailus 	 */
3499e05bbacSSakari Ailus 	for (vt_div = min_vt_div; vt_div <= max_vt_div;
3509e05bbacSSakari Ailus 	     vt_div += 2 - (vt_div & 1)) {
3519e05bbacSSakari Ailus 		for (sys_div = min_sys_div;
3529e05bbacSSakari Ailus 		     sys_div <= max_sys_div;
3539e05bbacSSakari Ailus 		     sys_div += 2 - (sys_div & 1)) {
3549e05bbacSSakari Ailus 			uint16_t pix_div = DIV_ROUND_UP(vt_div, sys_div);
3559e05bbacSSakari Ailus 
356*415ddd99SSakari Ailus 			if (pix_div < lim->vt_bk.min_pix_clk_div
357*415ddd99SSakari Ailus 			    || pix_div > lim->vt_bk.max_pix_clk_div) {
3589e05bbacSSakari Ailus 				dev_dbg(dev,
3599e05bbacSSakari Ailus 					"pix_div %u too small or too big (%u--%u)\n",
3609e05bbacSSakari Ailus 					pix_div,
361*415ddd99SSakari Ailus 					lim->vt_bk.min_pix_clk_div,
362*415ddd99SSakari Ailus 					lim->vt_bk.max_pix_clk_div);
3639e05bbacSSakari Ailus 				continue;
3649e05bbacSSakari Ailus 			}
3659e05bbacSSakari Ailus 
3669e05bbacSSakari Ailus 			/* Check if this one is better. */
3679e05bbacSSakari Ailus 			if (pix_div * sys_div
3689e05bbacSSakari Ailus 			    <= roundup(min_vt_div, best_pix_div))
3699e05bbacSSakari Ailus 				best_pix_div = pix_div;
3709e05bbacSSakari Ailus 		}
3719e05bbacSSakari Ailus 		if (best_pix_div < INT_MAX >> 1)
3729e05bbacSSakari Ailus 			break;
3739e05bbacSSakari Ailus 	}
3749e05bbacSSakari Ailus 
375*415ddd99SSakari Ailus 	pll->vt_bk.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
376*415ddd99SSakari Ailus 	pll->vt_bk.pix_clk_div = best_pix_div;
3779e05bbacSSakari Ailus 
378*415ddd99SSakari Ailus 	pll->vt_bk.sys_clk_freq_hz =
379*415ddd99SSakari Ailus 		op_pll_fr->pll_op_clk_freq_hz / pll->vt_bk.sys_clk_div;
380*415ddd99SSakari Ailus 	pll->vt_bk.pix_clk_freq_hz =
381*415ddd99SSakari Ailus 		pll->vt_bk.sys_clk_freq_hz / pll->vt_bk.pix_clk_div;
3829e05bbacSSakari Ailus 
3839e05bbacSSakari Ailus out_skip_vt_calc:
3849e05bbacSSakari Ailus 	pll->pixel_rate_csi =
385*415ddd99SSakari Ailus 		op_pll_bk->pix_clk_freq_hz * lane_op_clock_ratio;
386*415ddd99SSakari Ailus 	pll->pixel_rate_pixel_array = pll->vt_bk.pix_clk_freq_hz;
3879e05bbacSSakari Ailus 
388*415ddd99SSakari Ailus 	return check_all_bounds(dev, lim, op_lim_fr, op_lim_bk, pll, op_pll_fr,
389*415ddd99SSakari Ailus 				op_pll_bk);
3909e05bbacSSakari Ailus }
3919e05bbacSSakari Ailus 
392*415ddd99SSakari Ailus int ccs_pll_calculate(struct device *dev, const struct ccs_pll_limits *lim,
3939e05bbacSSakari Ailus 		      struct ccs_pll *pll)
3949e05bbacSSakari Ailus {
395*415ddd99SSakari Ailus 	const struct ccs_pll_branch_limits_fr *op_lim_fr = &lim->vt_fr;
396*415ddd99SSakari Ailus 	const struct ccs_pll_branch_limits_bk *op_lim_bk = &lim->op_bk;
397*415ddd99SSakari Ailus 	struct ccs_pll_branch_fr *op_pll_fr = &pll->vt_fr;
398*415ddd99SSakari Ailus 	struct ccs_pll_branch_bk *op_pll_bk = &pll->op_bk;
399*415ddd99SSakari Ailus 	uint16_t min_op_pre_pll_clk_div;
400*415ddd99SSakari Ailus 	uint16_t max_op_pre_pll_clk_div;
4019e05bbacSSakari Ailus 	uint32_t lane_op_clock_ratio;
4029e05bbacSSakari Ailus 	uint32_t mul, div;
4039e05bbacSSakari Ailus 	unsigned int i;
4049e05bbacSSakari Ailus 	int rval = -EINVAL;
4059e05bbacSSakari Ailus 
4069e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_NO_OP_CLOCKS) {
4079e05bbacSSakari Ailus 		/*
4089e05bbacSSakari Ailus 		 * If there's no OP PLL at all, use the VT values
4099e05bbacSSakari Ailus 		 * instead. The OP values are ignored for the rest of
4109e05bbacSSakari Ailus 		 * the PLL calculation.
4119e05bbacSSakari Ailus 		 */
412*415ddd99SSakari Ailus 		op_lim_fr = &lim->vt_fr;
413*415ddd99SSakari Ailus 		op_lim_bk = &lim->vt_bk;
414*415ddd99SSakari Ailus 		op_pll_bk = &pll->vt_bk;
4159e05bbacSSakari Ailus 	}
4169e05bbacSSakari Ailus 
4179e05bbacSSakari Ailus 	if (pll->flags & CCS_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
4189e05bbacSSakari Ailus 		lane_op_clock_ratio = pll->csi2.lanes;
4199e05bbacSSakari Ailus 	else
4209e05bbacSSakari Ailus 		lane_op_clock_ratio = 1;
4219e05bbacSSakari Ailus 	dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio);
4229e05bbacSSakari Ailus 
4239e05bbacSSakari Ailus 	dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
4249e05bbacSSakari Ailus 		pll->binning_vertical);
4259e05bbacSSakari Ailus 
4269e05bbacSSakari Ailus 	switch (pll->bus_type) {
4279e05bbacSSakari Ailus 	case CCS_PLL_BUS_TYPE_CSI2:
4289e05bbacSSakari Ailus 		/* CSI transfers 2 bits per clock per lane; thus times 2 */
429*415ddd99SSakari Ailus 		op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * 2
4309e05bbacSSakari Ailus 			* (pll->csi2.lanes / lane_op_clock_ratio);
4319e05bbacSSakari Ailus 		break;
4329e05bbacSSakari Ailus 	case CCS_PLL_BUS_TYPE_PARALLEL:
433*415ddd99SSakari Ailus 		op_pll_fr->pll_op_clk_freq_hz = pll->link_freq * pll->bits_per_pixel
4349e05bbacSSakari Ailus 			/ DIV_ROUND_UP(pll->bits_per_pixel,
4359e05bbacSSakari Ailus 				       pll->parallel.bus_width);
4369e05bbacSSakari Ailus 		break;
4379e05bbacSSakari Ailus 	default:
4389e05bbacSSakari Ailus 		return -EINVAL;
4399e05bbacSSakari Ailus 	}
4409e05bbacSSakari Ailus 
441*415ddd99SSakari Ailus 	/* Figure out limits for OP pre-pll divider based on extclk */
442*415ddd99SSakari Ailus 	dev_dbg(dev, "min / max op_pre_pll_clk_div: %u / %u\n",
443*415ddd99SSakari Ailus 		op_lim_fr->min_pre_pll_clk_div, op_lim_fr->max_pre_pll_clk_div);
444*415ddd99SSakari Ailus 	max_op_pre_pll_clk_div =
445*415ddd99SSakari Ailus 		min_t(uint16_t, op_lim_fr->max_pre_pll_clk_div,
4469e05bbacSSakari Ailus 		      clk_div_even(pll->ext_clk_freq_hz /
447*415ddd99SSakari Ailus 				   op_lim_fr->min_pll_ip_clk_freq_hz));
448*415ddd99SSakari Ailus 	min_op_pre_pll_clk_div =
449*415ddd99SSakari Ailus 		max_t(uint16_t, op_lim_fr->min_pre_pll_clk_div,
4509e05bbacSSakari Ailus 		      clk_div_even_up(
4519e05bbacSSakari Ailus 			      DIV_ROUND_UP(pll->ext_clk_freq_hz,
452*415ddd99SSakari Ailus 					   op_lim_fr->max_pll_ip_clk_freq_hz)));
453*415ddd99SSakari Ailus 	dev_dbg(dev, "pre-pll check: min / max op_pre_pll_clk_div: %u / %u\n",
454*415ddd99SSakari Ailus 		min_op_pre_pll_clk_div, max_op_pre_pll_clk_div);
4559e05bbacSSakari Ailus 
456*415ddd99SSakari Ailus 	i = gcd(op_pll_fr->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
457*415ddd99SSakari Ailus 	mul = op_pll_fr->pll_op_clk_freq_hz / i;
4589e05bbacSSakari Ailus 	div = pll->ext_clk_freq_hz / i;
4599e05bbacSSakari Ailus 	dev_dbg(dev, "mul %u / div %u\n", mul, div);
4609e05bbacSSakari Ailus 
461*415ddd99SSakari Ailus 	min_op_pre_pll_clk_div =
462*415ddd99SSakari Ailus 		max_t(uint16_t, min_op_pre_pll_clk_div,
4639e05bbacSSakari Ailus 		      clk_div_even_up(
4649e05bbacSSakari Ailus 			      DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
465*415ddd99SSakari Ailus 					   op_lim_fr->max_pll_op_clk_freq_hz)));
466*415ddd99SSakari Ailus 	dev_dbg(dev, "pll_op check: min / max op_pre_pll_clk_div: %u / %u\n",
467*415ddd99SSakari Ailus 		min_op_pre_pll_clk_div, max_op_pre_pll_clk_div);
4689e05bbacSSakari Ailus 
469*415ddd99SSakari Ailus 	for (op_pll_fr->pre_pll_clk_div = min_op_pre_pll_clk_div;
470*415ddd99SSakari Ailus 	     op_pll_fr->pre_pll_clk_div <= max_op_pre_pll_clk_div;
471*415ddd99SSakari Ailus 	     op_pll_fr->pre_pll_clk_div += 2 - (op_pll_fr->pre_pll_clk_div & 1)) {
472*415ddd99SSakari Ailus 		rval = __ccs_pll_calculate(dev, lim, op_lim_fr, op_lim_bk, pll,
473*415ddd99SSakari Ailus 					   op_pll_fr, op_pll_bk, mul, div,
474*415ddd99SSakari Ailus 					   lane_op_clock_ratio);
4759e05bbacSSakari Ailus 		if (rval)
4769e05bbacSSakari Ailus 			continue;
4779e05bbacSSakari Ailus 
4789e05bbacSSakari Ailus 		print_pll(dev, pll);
4799e05bbacSSakari Ailus 		return 0;
4809e05bbacSSakari Ailus 	}
4819e05bbacSSakari Ailus 
4829e05bbacSSakari Ailus 	dev_dbg(dev, "unable to compute pre_pll divisor\n");
4839e05bbacSSakari Ailus 
4849e05bbacSSakari Ailus 	return rval;
4859e05bbacSSakari Ailus }
4869e05bbacSSakari Ailus EXPORT_SYMBOL_GPL(ccs_pll_calculate);
4879e05bbacSSakari Ailus 
4887389d01cSSakari Ailus MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
4899e05bbacSSakari Ailus MODULE_DESCRIPTION("Generic MIPI CCS/SMIA/SMIA++ PLL calculator");
490b3c0115eSSakari Ailus MODULE_LICENSE("GPL v2");
491