18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * OMAP2/3/4 DPLL clock functions
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2005-2008 Texas Instruments, Inc.
68c2ecf20Sopenharmony_ci * Copyright (C) 2004-2010 Nokia Corporation
78c2ecf20Sopenharmony_ci *
88c2ecf20Sopenharmony_ci * Contacts:
98c2ecf20Sopenharmony_ci * Richard Woodruff <r-woodruff2@ti.com>
108c2ecf20Sopenharmony_ci * Paul Walmsley
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci#undef DEBUG
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/errno.h>
168c2ecf20Sopenharmony_ci#include <linux/clk.h>
178c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
188c2ecf20Sopenharmony_ci#include <linux/io.h>
198c2ecf20Sopenharmony_ci#include <linux/clk/ti.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include <asm/div64.h>
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#include "clock.h"
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci/* DPLL rate rounding: minimum DPLL multiplier, divider values */
268c2ecf20Sopenharmony_ci#define DPLL_MIN_MULTIPLIER		2
278c2ecf20Sopenharmony_ci#define DPLL_MIN_DIVIDER		1
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/* Possible error results from _dpll_test_mult */
308c2ecf20Sopenharmony_ci#define DPLL_MULT_UNDERFLOW		-1
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci/*
338c2ecf20Sopenharmony_ci * Scale factor to mitigate roundoff errors in DPLL rate rounding.
348c2ecf20Sopenharmony_ci * The higher the scale factor, the greater the risk of arithmetic overflow,
358c2ecf20Sopenharmony_ci * but the closer the rounded rate to the target rate.  DPLL_SCALE_FACTOR
368c2ecf20Sopenharmony_ci * must be a power of DPLL_SCALE_BASE.
378c2ecf20Sopenharmony_ci */
388c2ecf20Sopenharmony_ci#define DPLL_SCALE_FACTOR		64
398c2ecf20Sopenharmony_ci#define DPLL_SCALE_BASE			2
408c2ecf20Sopenharmony_ci#define DPLL_ROUNDING_VAL		((DPLL_SCALE_BASE / 2) * \
418c2ecf20Sopenharmony_ci					 (DPLL_SCALE_FACTOR / DPLL_SCALE_BASE))
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci/*
448c2ecf20Sopenharmony_ci * DPLL valid Fint frequency range for OMAP36xx and OMAP4xxx.
458c2ecf20Sopenharmony_ci * From device data manual section 4.3 "DPLL and DLL Specifications".
468c2ecf20Sopenharmony_ci */
478c2ecf20Sopenharmony_ci#define OMAP3PLUS_DPLL_FINT_JTYPE_MIN	500000
488c2ecf20Sopenharmony_ci#define OMAP3PLUS_DPLL_FINT_JTYPE_MAX	2500000
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* _dpll_test_fint() return codes */
518c2ecf20Sopenharmony_ci#define DPLL_FINT_UNDERFLOW		-1
528c2ecf20Sopenharmony_ci#define DPLL_FINT_INVALID		-2
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/* Private functions */
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci/*
578c2ecf20Sopenharmony_ci * _dpll_test_fint - test whether an Fint value is valid for the DPLL
588c2ecf20Sopenharmony_ci * @clk: DPLL struct clk to test
598c2ecf20Sopenharmony_ci * @n: divider value (N) to test
608c2ecf20Sopenharmony_ci *
618c2ecf20Sopenharmony_ci * Tests whether a particular divider @n will result in a valid DPLL
628c2ecf20Sopenharmony_ci * internal clock frequency Fint. See the 34xx TRM 4.7.6.2 "DPLL Jitter
638c2ecf20Sopenharmony_ci * Correction".  Returns 0 if OK, -1 if the enclosing loop can terminate
648c2ecf20Sopenharmony_ci * (assuming that it is counting N upwards), or -2 if the enclosing loop
658c2ecf20Sopenharmony_ci * should skip to the next iteration (again assuming N is increasing).
668c2ecf20Sopenharmony_ci */
678c2ecf20Sopenharmony_cistatic int _dpll_test_fint(struct clk_hw_omap *clk, unsigned int n)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	struct dpll_data *dd;
708c2ecf20Sopenharmony_ci	long fint, fint_min, fint_max;
718c2ecf20Sopenharmony_ci	int ret = 0;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	dd = clk->dpll_data;
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	/* DPLL divider must result in a valid jitter correction val */
768c2ecf20Sopenharmony_ci	fint = clk_hw_get_rate(clk_hw_get_parent(&clk->hw)) / n;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	if (dd->flags & DPLL_J_TYPE) {
798c2ecf20Sopenharmony_ci		fint_min = OMAP3PLUS_DPLL_FINT_JTYPE_MIN;
808c2ecf20Sopenharmony_ci		fint_max = OMAP3PLUS_DPLL_FINT_JTYPE_MAX;
818c2ecf20Sopenharmony_ci	} else {
828c2ecf20Sopenharmony_ci		fint_min = ti_clk_get_features()->fint_min;
838c2ecf20Sopenharmony_ci		fint_max = ti_clk_get_features()->fint_max;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (!fint_min || !fint_max) {
878c2ecf20Sopenharmony_ci		WARN(1, "No fint limits available!\n");
888c2ecf20Sopenharmony_ci		return DPLL_FINT_INVALID;
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if (fint < ti_clk_get_features()->fint_min) {
928c2ecf20Sopenharmony_ci		pr_debug("rejecting n=%d due to Fint failure, lowering max_divider\n",
938c2ecf20Sopenharmony_ci			 n);
948c2ecf20Sopenharmony_ci		dd->max_divider = n;
958c2ecf20Sopenharmony_ci		ret = DPLL_FINT_UNDERFLOW;
968c2ecf20Sopenharmony_ci	} else if (fint > ti_clk_get_features()->fint_max) {
978c2ecf20Sopenharmony_ci		pr_debug("rejecting n=%d due to Fint failure, boosting min_divider\n",
988c2ecf20Sopenharmony_ci			 n);
998c2ecf20Sopenharmony_ci		dd->min_divider = n;
1008c2ecf20Sopenharmony_ci		ret = DPLL_FINT_INVALID;
1018c2ecf20Sopenharmony_ci	} else if (fint > ti_clk_get_features()->fint_band1_max &&
1028c2ecf20Sopenharmony_ci		   fint < ti_clk_get_features()->fint_band2_min) {
1038c2ecf20Sopenharmony_ci		pr_debug("rejecting n=%d due to Fint failure\n", n);
1048c2ecf20Sopenharmony_ci		ret = DPLL_FINT_INVALID;
1058c2ecf20Sopenharmony_ci	}
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	return ret;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_cistatic unsigned long _dpll_compute_new_rate(unsigned long parent_rate,
1118c2ecf20Sopenharmony_ci					    unsigned int m, unsigned int n)
1128c2ecf20Sopenharmony_ci{
1138c2ecf20Sopenharmony_ci	unsigned long long num;
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	num = (unsigned long long)parent_rate * m;
1168c2ecf20Sopenharmony_ci	do_div(num, n);
1178c2ecf20Sopenharmony_ci	return num;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci/*
1218c2ecf20Sopenharmony_ci * _dpll_test_mult - test a DPLL multiplier value
1228c2ecf20Sopenharmony_ci * @m: pointer to the DPLL m (multiplier) value under test
1238c2ecf20Sopenharmony_ci * @n: current DPLL n (divider) value under test
1248c2ecf20Sopenharmony_ci * @new_rate: pointer to storage for the resulting rounded rate
1258c2ecf20Sopenharmony_ci * @target_rate: the desired DPLL rate
1268c2ecf20Sopenharmony_ci * @parent_rate: the DPLL's parent clock rate
1278c2ecf20Sopenharmony_ci *
1288c2ecf20Sopenharmony_ci * This code tests a DPLL multiplier value, ensuring that the
1298c2ecf20Sopenharmony_ci * resulting rate will not be higher than the target_rate, and that
1308c2ecf20Sopenharmony_ci * the multiplier value itself is valid for the DPLL.  Initially, the
1318c2ecf20Sopenharmony_ci * integer pointed to by the m argument should be prescaled by
1328c2ecf20Sopenharmony_ci * multiplying by DPLL_SCALE_FACTOR.  The code will replace this with
1338c2ecf20Sopenharmony_ci * a non-scaled m upon return.  This non-scaled m will result in a
1348c2ecf20Sopenharmony_ci * new_rate as close as possible to target_rate (but not greater than
1358c2ecf20Sopenharmony_ci * target_rate) given the current (parent_rate, n, prescaled m)
1368c2ecf20Sopenharmony_ci * triple. Returns DPLL_MULT_UNDERFLOW in the event that the
1378c2ecf20Sopenharmony_ci * non-scaled m attempted to underflow, which can allow the calling
1388c2ecf20Sopenharmony_ci * function to bail out early; or 0 upon success.
1398c2ecf20Sopenharmony_ci */
1408c2ecf20Sopenharmony_cistatic int _dpll_test_mult(int *m, int n, unsigned long *new_rate,
1418c2ecf20Sopenharmony_ci			   unsigned long target_rate,
1428c2ecf20Sopenharmony_ci			   unsigned long parent_rate)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	int r = 0, carry = 0;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	/* Unscale m and round if necessary */
1478c2ecf20Sopenharmony_ci	if (*m % DPLL_SCALE_FACTOR >= DPLL_ROUNDING_VAL)
1488c2ecf20Sopenharmony_ci		carry = 1;
1498c2ecf20Sopenharmony_ci	*m = (*m / DPLL_SCALE_FACTOR) + carry;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/*
1528c2ecf20Sopenharmony_ci	 * The new rate must be <= the target rate to avoid programming
1538c2ecf20Sopenharmony_ci	 * a rate that is impossible for the hardware to handle
1548c2ecf20Sopenharmony_ci	 */
1558c2ecf20Sopenharmony_ci	*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
1568c2ecf20Sopenharmony_ci	if (*new_rate > target_rate) {
1578c2ecf20Sopenharmony_ci		(*m)--;
1588c2ecf20Sopenharmony_ci		*new_rate = 0;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	/* Guard against m underflow */
1628c2ecf20Sopenharmony_ci	if (*m < DPLL_MIN_MULTIPLIER) {
1638c2ecf20Sopenharmony_ci		*m = DPLL_MIN_MULTIPLIER;
1648c2ecf20Sopenharmony_ci		*new_rate = 0;
1658c2ecf20Sopenharmony_ci		r = DPLL_MULT_UNDERFLOW;
1668c2ecf20Sopenharmony_ci	}
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci	if (*new_rate == 0)
1698c2ecf20Sopenharmony_ci		*new_rate = _dpll_compute_new_rate(parent_rate, *m, n);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	return r;
1728c2ecf20Sopenharmony_ci}
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/**
1758c2ecf20Sopenharmony_ci * _omap2_dpll_is_in_bypass - check if DPLL is in bypass mode or not
1768c2ecf20Sopenharmony_ci * @v: bitfield value of the DPLL enable
1778c2ecf20Sopenharmony_ci *
1788c2ecf20Sopenharmony_ci * Checks given DPLL enable bitfield to see whether the DPLL is in bypass
1798c2ecf20Sopenharmony_ci * mode or not. Returns 1 if the DPLL is in bypass, 0 otherwise.
1808c2ecf20Sopenharmony_ci */
1818c2ecf20Sopenharmony_cistatic int _omap2_dpll_is_in_bypass(u32 v)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	u8 mask, val;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	mask = ti_clk_get_features()->dpll_bypass_vals;
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_ci	/*
1888c2ecf20Sopenharmony_ci	 * Each set bit in the mask corresponds to a bypass value equal
1898c2ecf20Sopenharmony_ci	 * to the bitshift. Go through each set-bit in the mask and
1908c2ecf20Sopenharmony_ci	 * compare against the given register value.
1918c2ecf20Sopenharmony_ci	 */
1928c2ecf20Sopenharmony_ci	while (mask) {
1938c2ecf20Sopenharmony_ci		val = __ffs(mask);
1948c2ecf20Sopenharmony_ci		mask ^= (1 << val);
1958c2ecf20Sopenharmony_ci		if (v == val)
1968c2ecf20Sopenharmony_ci			return 1;
1978c2ecf20Sopenharmony_ci	}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	return 0;
2008c2ecf20Sopenharmony_ci}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci/* Public functions */
2038c2ecf20Sopenharmony_ciu8 omap2_init_dpll_parent(struct clk_hw *hw)
2048c2ecf20Sopenharmony_ci{
2058c2ecf20Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
2068c2ecf20Sopenharmony_ci	u32 v;
2078c2ecf20Sopenharmony_ci	struct dpll_data *dd;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	dd = clk->dpll_data;
2108c2ecf20Sopenharmony_ci	if (!dd)
2118c2ecf20Sopenharmony_ci		return -EINVAL;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
2148c2ecf20Sopenharmony_ci	v &= dd->enable_mask;
2158c2ecf20Sopenharmony_ci	v >>= __ffs(dd->enable_mask);
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	/* Reparent the struct clk in case the dpll is in bypass */
2188c2ecf20Sopenharmony_ci	if (_omap2_dpll_is_in_bypass(v))
2198c2ecf20Sopenharmony_ci		return 1;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return 0;
2228c2ecf20Sopenharmony_ci}
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci/**
2258c2ecf20Sopenharmony_ci * omap2_get_dpll_rate - returns the current DPLL CLKOUT rate
2268c2ecf20Sopenharmony_ci * @clk: struct clk * of a DPLL
2278c2ecf20Sopenharmony_ci *
2288c2ecf20Sopenharmony_ci * DPLLs can be locked or bypassed - basically, enabled or disabled.
2298c2ecf20Sopenharmony_ci * When locked, the DPLL output depends on the M and N values.  When
2308c2ecf20Sopenharmony_ci * bypassed, on OMAP2xxx, the output rate is either the 32KiHz clock
2318c2ecf20Sopenharmony_ci * or sys_clk.  Bypass rates on OMAP3 depend on the DPLL: DPLLs 1 and
2328c2ecf20Sopenharmony_ci * 2 are bypassed with dpll1_fclk and dpll2_fclk respectively
2338c2ecf20Sopenharmony_ci * (generated by DPLL3), while DPLL 3, 4, and 5 bypass rates are sys_clk.
2348c2ecf20Sopenharmony_ci * Returns the current DPLL CLKOUT rate (*not* CLKOUTX2) if the DPLL is
2358c2ecf20Sopenharmony_ci * locked, or the appropriate bypass rate if the DPLL is bypassed, or 0
2368c2ecf20Sopenharmony_ci * if the clock @clk is not a DPLL.
2378c2ecf20Sopenharmony_ci */
2388c2ecf20Sopenharmony_ciunsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	u64 dpll_clk;
2418c2ecf20Sopenharmony_ci	u32 dpll_mult, dpll_div, v;
2428c2ecf20Sopenharmony_ci	struct dpll_data *dd;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	dd = clk->dpll_data;
2458c2ecf20Sopenharmony_ci	if (!dd)
2468c2ecf20Sopenharmony_ci		return 0;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	/* Return bypass rate if DPLL is bypassed */
2498c2ecf20Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
2508c2ecf20Sopenharmony_ci	v &= dd->enable_mask;
2518c2ecf20Sopenharmony_ci	v >>= __ffs(dd->enable_mask);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	if (_omap2_dpll_is_in_bypass(v))
2548c2ecf20Sopenharmony_ci		return clk_hw_get_rate(dd->clk_bypass);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	v = ti_clk_ll_ops->clk_readl(&dd->mult_div1_reg);
2578c2ecf20Sopenharmony_ci	dpll_mult = v & dd->mult_mask;
2588c2ecf20Sopenharmony_ci	dpll_mult >>= __ffs(dd->mult_mask);
2598c2ecf20Sopenharmony_ci	dpll_div = v & dd->div1_mask;
2608c2ecf20Sopenharmony_ci	dpll_div >>= __ffs(dd->div1_mask);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	dpll_clk = (u64)clk_hw_get_rate(dd->clk_ref) * dpll_mult;
2638c2ecf20Sopenharmony_ci	do_div(dpll_clk, dpll_div + 1);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	return dpll_clk;
2668c2ecf20Sopenharmony_ci}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/* DPLL rate rounding code */
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/**
2718c2ecf20Sopenharmony_ci * omap2_dpll_round_rate - round a target rate for an OMAP DPLL
2728c2ecf20Sopenharmony_ci * @clk: struct clk * for a DPLL
2738c2ecf20Sopenharmony_ci * @target_rate: desired DPLL clock rate
2748c2ecf20Sopenharmony_ci *
2758c2ecf20Sopenharmony_ci * Given a DPLL and a desired target rate, round the target rate to a
2768c2ecf20Sopenharmony_ci * possible, programmable rate for this DPLL.  Attempts to select the
2778c2ecf20Sopenharmony_ci * minimum possible n.  Stores the computed (m, n) in the DPLL's
2788c2ecf20Sopenharmony_ci * dpll_data structure so set_rate() will not need to call this
2798c2ecf20Sopenharmony_ci * (expensive) function again.  Returns ~0 if the target rate cannot
2808c2ecf20Sopenharmony_ci * be rounded, or the rounded rate upon success.
2818c2ecf20Sopenharmony_ci */
2828c2ecf20Sopenharmony_cilong omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
2838c2ecf20Sopenharmony_ci			   unsigned long *parent_rate)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	struct clk_hw_omap *clk = to_clk_hw_omap(hw);
2868c2ecf20Sopenharmony_ci	int m, n, r, scaled_max_m;
2878c2ecf20Sopenharmony_ci	int min_delta_m = INT_MAX, min_delta_n = INT_MAX;
2888c2ecf20Sopenharmony_ci	unsigned long scaled_rt_rp;
2898c2ecf20Sopenharmony_ci	unsigned long new_rate = 0;
2908c2ecf20Sopenharmony_ci	struct dpll_data *dd;
2918c2ecf20Sopenharmony_ci	unsigned long ref_rate;
2928c2ecf20Sopenharmony_ci	long delta;
2938c2ecf20Sopenharmony_ci	long prev_min_delta = LONG_MAX;
2948c2ecf20Sopenharmony_ci	const char *clk_name;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	if (!clk || !clk->dpll_data)
2978c2ecf20Sopenharmony_ci		return ~0;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	dd = clk->dpll_data;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	if (dd->max_rate && target_rate > dd->max_rate)
3028c2ecf20Sopenharmony_ci		target_rate = dd->max_rate;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	ref_rate = clk_hw_get_rate(dd->clk_ref);
3058c2ecf20Sopenharmony_ci	clk_name = clk_hw_get_name(hw);
3068c2ecf20Sopenharmony_ci	pr_debug("clock: %s: starting DPLL round_rate, target rate %lu\n",
3078c2ecf20Sopenharmony_ci		 clk_name, target_rate);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	scaled_rt_rp = target_rate / (ref_rate / DPLL_SCALE_FACTOR);
3108c2ecf20Sopenharmony_ci	scaled_max_m = dd->max_multiplier * DPLL_SCALE_FACTOR;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	dd->last_rounded_rate = 0;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	for (n = dd->min_divider; n <= dd->max_divider; n++) {
3158c2ecf20Sopenharmony_ci		/* Is the (input clk, divider) pair valid for the DPLL? */
3168c2ecf20Sopenharmony_ci		r = _dpll_test_fint(clk, n);
3178c2ecf20Sopenharmony_ci		if (r == DPLL_FINT_UNDERFLOW)
3188c2ecf20Sopenharmony_ci			break;
3198c2ecf20Sopenharmony_ci		else if (r == DPLL_FINT_INVALID)
3208c2ecf20Sopenharmony_ci			continue;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci		/* Compute the scaled DPLL multiplier, based on the divider */
3238c2ecf20Sopenharmony_ci		m = scaled_rt_rp * n;
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci		/*
3268c2ecf20Sopenharmony_ci		 * Since we're counting n up, a m overflow means we
3278c2ecf20Sopenharmony_ci		 * can bail out completely (since as n increases in
3288c2ecf20Sopenharmony_ci		 * the next iteration, there's no way that m can
3298c2ecf20Sopenharmony_ci		 * increase beyond the current m)
3308c2ecf20Sopenharmony_ci		 */
3318c2ecf20Sopenharmony_ci		if (m > scaled_max_m)
3328c2ecf20Sopenharmony_ci			break;
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_ci		r = _dpll_test_mult(&m, n, &new_rate, target_rate,
3358c2ecf20Sopenharmony_ci				    ref_rate);
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci		/* m can't be set low enough for this n - try with a larger n */
3388c2ecf20Sopenharmony_ci		if (r == DPLL_MULT_UNDERFLOW)
3398c2ecf20Sopenharmony_ci			continue;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci		/* skip rates above our target rate */
3428c2ecf20Sopenharmony_ci		delta = target_rate - new_rate;
3438c2ecf20Sopenharmony_ci		if (delta < 0)
3448c2ecf20Sopenharmony_ci			continue;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		if (delta < prev_min_delta) {
3478c2ecf20Sopenharmony_ci			prev_min_delta = delta;
3488c2ecf20Sopenharmony_ci			min_delta_m = m;
3498c2ecf20Sopenharmony_ci			min_delta_n = n;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci		pr_debug("clock: %s: m = %d: n = %d: new_rate = %lu\n",
3538c2ecf20Sopenharmony_ci			 clk_name, m, n, new_rate);
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci		if (delta == 0)
3568c2ecf20Sopenharmony_ci			break;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	if (prev_min_delta == LONG_MAX) {
3608c2ecf20Sopenharmony_ci		pr_debug("clock: %s: cannot round to rate %lu\n",
3618c2ecf20Sopenharmony_ci			 clk_name, target_rate);
3628c2ecf20Sopenharmony_ci		return ~0;
3638c2ecf20Sopenharmony_ci	}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_ci	dd->last_rounded_m = min_delta_m;
3668c2ecf20Sopenharmony_ci	dd->last_rounded_n = min_delta_n;
3678c2ecf20Sopenharmony_ci	dd->last_rounded_rate = target_rate - prev_min_delta;
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	return dd->last_rounded_rate;
3708c2ecf20Sopenharmony_ci}
371