Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  * Copyright (C) 2018-2019 SiFive, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Wesley Terpstra
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  * Paul Walmsley
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * This library supports configuration parsing and reprogramming of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  * the CLN28HPC variant of the Analog Bits Wide Range PLL.  The
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * intention is for this library to be reusable for any device that
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * integrates this PLL; thus the register structure and programming
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * details are expected to be provided by a separate IP block driver.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * The bulk of this code is primarily useful for clock configurations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  * that must operate at arbitrary rates, as opposed to clock configurations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  * that are restricted by software or manufacturer guidance to a small,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  * pre-determined set of performance points.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * References:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *   https://static.dev.sifive.com/FU540-C000-v1.0.pdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24) #include <linux/bug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26) #include <linux/log2.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27) #include <linux/math64.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) #include <linux/clk/analogbits-wrpll-cln28hpc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) /* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) #define MIN_INPUT_FREQ			7000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) /* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) #define MAX_INPUT_FREQ			600000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) /* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) #define MIN_POST_DIVR_FREQ		7000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) /* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) #define MAX_POST_DIVR_FREQ		200000000
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) /* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) #define MIN_VCO_FREQ			2400000000UL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45) /* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) #define MAX_VCO_FREQ			4800000000ULL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) /* MAX_DIVQ_DIVISOR: maximum output divisor.  Selected by DIVQ = 6 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #define MAX_DIVQ_DIVISOR		64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) /* MAX_DIVR_DIVISOR: maximum reference divisor.  Selected by DIVR = 63 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #define MAX_DIVR_DIVISOR		64
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) /* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) #define MAX_LOCK_US			70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58)  * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59)  *              algorithm
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) #define ROUND_SHIFT			20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64)  * Private functions
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68)  * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69)  * @post_divr_freq: input clock rate after the R divider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71)  * Select the value to be presented to the PLL RANGE input signals, based
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72)  * on the input clock frequency after the post-R-divider @post_divr_freq.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73)  * This code follows the recommendations in the PLL datasheet for filter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74)  * range selection.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76)  * Return: The RANGE value to be presented to the PLL configuration inputs,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77)  *         or a negative return code upon error.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) static int __wrpll_calc_filter_range(unsigned long post_divr_freq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	if (post_divr_freq < MIN_POST_DIVR_FREQ ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) 	    post_divr_freq > MAX_POST_DIVR_FREQ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 		WARN(1, "%s: post-divider reference freq out of range: %lu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) 		     __func__, post_divr_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 		return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 	switch (post_divr_freq) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 	case 0 ... 10999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 		return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	case 11000000 ... 17999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 		return 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	case 18000000 ... 29999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 		return 3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	case 30000000 ... 49999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		return 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	case 50000000 ... 79999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 		return 5;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	case 80000000 ... 129999999:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		return 6;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	return 7;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)  * __wrpll_calc_fbdiv() - return feedback fixed divide value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108)  * @c: ptr to a struct wrpll_cfg record to read from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)  * The internal feedback path includes a fixed by-two divider; the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)  * external feedback path does not.  Return the appropriate divider
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)  * value (2 or 1) depending on whether internal or external feedback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)  * is enabled.  This code doesn't test for invalid configurations
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)  * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)  * on the caller to do so.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)  * Context: Any context.  Caller must protect the memory pointed to by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)  *          @c from simultaneous modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120)  * Return: 2 if internal feedback is enabled or 1 if external feedback
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)  *         is enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)  * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)  * @target_rate: target PLL output clock rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)  * @vco_rate: pointer to a u64 to store the computed VCO rate into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)  * Determine a reasonable value for the PLL Q post-divider, based on the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)  * target output rate @target_rate for the PLL.  Along with returning the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)  * computed Q divider value as the return value, this function stores the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)  * desired target VCO rate into the variable pointed to by @vco_rate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)  * Context: Any context.  Caller must protect the memory pointed to by
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)  *          @vco_rate from simultaneous access or modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)  * Return: a positive integer DIVQ value to be programmed into the hardware
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142)  *         upon success, or 0 upon error (since 0 is an invalid DIVQ value)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	u64 s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	u8 divq = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 	if (!vco_rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 		WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 		goto wcd_out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	s = div_u64(MAX_VCO_FREQ, target_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	if (s <= 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 		divq = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 		*vco_rate = MAX_VCO_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	} else if (s > MAX_DIVQ_DIVISOR) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 		divq = ilog2(MAX_DIVQ_DIVISOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 		*vco_rate = MIN_VCO_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	} else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 		divq = ilog2(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 		*vco_rate = (u64)target_rate << divq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) wcd_out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	return divq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)  * __wrpll_update_parent_rate() - update PLL data when parent rate changes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172)  * @c: ptr to a struct wrpll_cfg record to write PLL data to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)  * @parent_rate: PLL input refclk rate (pre-R-divider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175)  * Pre-compute some data used by the PLL configuration algorithm when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)  * the PLL's reference clock rate changes.  The intention is to avoid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)  * computation when the parent rate remains constant - expected to be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)  * the common case.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180)  * Returns: 0 upon success or -ERANGE if the reference clock rate is
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)  * out of range.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) static int __wrpll_update_parent_rate(struct wrpll_cfg *c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 				      unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	u8 max_r_for_parent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 	if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 		return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	c->parent_rate = parent_rate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 	max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 	c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)  * wrpll_configure() - compute PLL configuration for a target rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)  * @c: ptr to a struct wrpll_cfg record to write into
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)  * @target_rate: target PLL output clock rate (post-Q-divider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)  * @parent_rate: PLL input refclk rate (pre-R-divider)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)  * Compute the appropriate PLL signal configuration values and store
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207)  * in PLL context @c.  PLL reprogramming is not glitchless, so the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)  * caller should switch any downstream logic to a different clock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209)  * source or clock-gate it before presenting these values to the PLL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210)  * configuration signals.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)  * The caller must pass this function a pre-initialized struct
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213)  * wrpll_cfg record: either initialized to zero (with the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214)  * exception of the .name and .flags fields) or read from the PLL.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216)  * Context: Any context.  Caller must protect the memory pointed to by @c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217)  *          from simultaneous access or modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)  * Return: 0 upon success; anything else upon failure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 			     unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) 	unsigned long ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) 	u32 best_f, f, post_divr_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 	u8 fbdiv, divq, best_r, r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) 	int range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	if (c->flags == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) 		WARN(1, "%s called with uninitialized PLL config", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 		return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	/* Initialize rounding data if it hasn't been initialized already */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	if (parent_rate != c->parent_rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 		if (__wrpll_update_parent_rate(c, parent_rate)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 			pr_err("%s: PLL input rate is out of range\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 			       __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 			return -ERANGE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	c->flags &= ~WRPLL_FLAGS_RESET_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	/* Put the PLL into bypass if the user requests the parent clock rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 	if (target_rate == parent_rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 		c->flags |= WRPLL_FLAGS_BYPASS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 	c->flags &= ~WRPLL_FLAGS_BYPASS_MASK;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	/* Calculate the Q shift and target VCO rate */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 	divq = __wrpll_calc_divq(target_rate, &target_vco_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 	if (!divq)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	c->divq = divq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	/* Precalculate the pre-Q divider target ratio */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 	ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	fbdiv = __wrpll_calc_fbdiv(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	best_r = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 	best_f = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	best_delta = MAX_VCO_FREQ;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	/*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	 * Consider all values for R which land within
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 	 * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 	for (r = c->init_r; r <= c->max_r; ++r) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 		f_pre_div = ratio * r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 		f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		f >>= (fbdiv - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 		post_divr_freq = div_u64(parent_rate, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 		vco_pre = fbdiv * post_divr_freq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 		vco = vco_pre * f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		/* Ensure rounding didn't take us out of range */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 		if (vco > target_vco_rate) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 			--f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 			vco = vco_pre * f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		} else if (vco < MIN_VCO_FREQ) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 			++f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 			vco = vco_pre * f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		delta = abs(target_rate - vco);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 		if (delta < best_delta) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 			best_delta = delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 			best_r = r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 			best_f = f;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 	c->divr = best_r - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	c->divf = best_f - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 	post_divr_freq = div_u64(parent_rate, best_r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	/* Pick the best PLL jitter filter */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	range = __wrpll_calc_filter_range(post_divr_freq);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	if (range < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 		return range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	c->range = range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)  * wrpll_calc_output_rate() - calculate the PLL's target output rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314)  * @c: ptr to a struct wrpll_cfg record to read from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)  * @parent_rate: PLL refclk rate
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317)  * Given a pointer to the PLL's current input configuration @c and the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318)  * PLL's input reference clock rate @parent_rate (before the R
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)  * pre-divider), calculate the PLL's output clock rate (after the Q
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)  * post-divider).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)  * Context: Any context.  Caller must protect the memory pointed to by @c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323)  *          from simultaneous modification.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325)  * Return: the PLL's output clock rate, in Hz.  The return value from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)  *         this function is intended to be convenient to pass directly
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)  *         to the Linux clock framework; thus there is no explicit
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)  *         error return value.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 				     unsigned long parent_rate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	u8 fbdiv;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	u64 n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 		WARN(1, "external feedback mode not yet supported");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 		return ULONG_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 	fbdiv = __wrpll_calc_fbdiv(c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) 	n = parent_rate * fbdiv * (c->divf + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	n = div_u64(n, c->divr + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	n >>= c->divq;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	return n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350)  * wrpll_calc_max_lock_us() - return the time for the PLL to lock
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)  * @c: ptr to a struct wrpll_cfg record to read from
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)  * Return the minimum amount of time (in microseconds) that the caller
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354)  * must wait after reprogramming the PLL to ensure that it is locked
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)  * to the input frequency and stable.  This is likely to depend on the DIVR
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356)  * value; this is under discussion with the manufacturer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)  * Return: the minimum amount of time the caller must wait for the PLL
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359)  *         to lock (in microseconds)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	return MAX_LOCK_US;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }