![]() |
|
|||
0001 // SPDX-License-Identifier: GPL-2.0 0002 /* 0003 * Copyright (C) 2018-2019 SiFive, Inc. 0004 * Wesley Terpstra 0005 * Paul Walmsley 0006 * 0007 * This library supports configuration parsing and reprogramming of 0008 * the CLN28HPC variant of the Analog Bits Wide Range PLL. The 0009 * intention is for this library to be reusable for any device that 0010 * integrates this PLL; thus the register structure and programming 0011 * details are expected to be provided by a separate IP block driver. 0012 * 0013 * The bulk of this code is primarily useful for clock configurations 0014 * that must operate at arbitrary rates, as opposed to clock configurations 0015 * that are restricted by software or manufacturer guidance to a small, 0016 * pre-determined set of performance points. 0017 * 0018 * References: 0019 * - Analog Bits "Wide Range PLL Datasheet", version 2015.10.01 0020 * - SiFive FU540-C000 Manual v1p0, Chapter 7 "Clocking and Reset" 0021 * https://static.dev.sifive.com/FU540-C000-v1.0.pdf 0022 */ 0023 0024 #include <linux/bug.h> 0025 #include <linux/err.h> 0026 #include <linux/limits.h> 0027 #include <linux/log2.h> 0028 #include <linux/math64.h> 0029 #include <linux/math.h> 0030 #include <linux/minmax.h> 0031 0032 #include <linux/clk/analogbits-wrpll-cln28hpc.h> 0033 0034 /* MIN_INPUT_FREQ: minimum input clock frequency, in Hz (Fref_min) */ 0035 #define MIN_INPUT_FREQ 7000000 0036 0037 /* MAX_INPUT_FREQ: maximum input clock frequency, in Hz (Fref_max) */ 0038 #define MAX_INPUT_FREQ 600000000 0039 0040 /* MIN_POST_DIVIDE_REF_FREQ: minimum post-divider reference frequency, in Hz */ 0041 #define MIN_POST_DIVR_FREQ 7000000 0042 0043 /* MAX_POST_DIVIDE_REF_FREQ: maximum post-divider reference frequency, in Hz */ 0044 #define MAX_POST_DIVR_FREQ 200000000 0045 0046 /* MIN_VCO_FREQ: minimum VCO frequency, in Hz (Fvco_min) */ 0047 #define MIN_VCO_FREQ 2400000000UL 0048 0049 /* MAX_VCO_FREQ: maximum VCO frequency, in Hz (Fvco_max) */ 0050 #define MAX_VCO_FREQ 4800000000ULL 0051 0052 /* MAX_DIVQ_DIVISOR: maximum output divisor. Selected by DIVQ = 6 */ 0053 #define MAX_DIVQ_DIVISOR 64 0054 0055 /* MAX_DIVR_DIVISOR: maximum reference divisor. Selected by DIVR = 63 */ 0056 #define MAX_DIVR_DIVISOR 64 0057 0058 /* MAX_LOCK_US: maximum PLL lock time, in microseconds (tLOCK_max) */ 0059 #define MAX_LOCK_US 70 0060 0061 /* 0062 * ROUND_SHIFT: number of bits to shift to avoid precision loss in the rounding 0063 * algorithm 0064 */ 0065 #define ROUND_SHIFT 20 0066 0067 /* 0068 * Private functions 0069 */ 0070 0071 /** 0072 * __wrpll_calc_filter_range() - determine PLL loop filter bandwidth 0073 * @post_divr_freq: input clock rate after the R divider 0074 * 0075 * Select the value to be presented to the PLL RANGE input signals, based 0076 * on the input clock frequency after the post-R-divider @post_divr_freq. 0077 * This code follows the recommendations in the PLL datasheet for filter 0078 * range selection. 0079 * 0080 * Return: The RANGE value to be presented to the PLL configuration inputs, 0081 * or a negative return code upon error. 0082 */ 0083 static int __wrpll_calc_filter_range(unsigned long post_divr_freq) 0084 { 0085 if (post_divr_freq < MIN_POST_DIVR_FREQ || 0086 post_divr_freq > MAX_POST_DIVR_FREQ) { 0087 WARN(1, "%s: post-divider reference freq out of range: %lu", 0088 __func__, post_divr_freq); 0089 return -ERANGE; 0090 } 0091 0092 switch (post_divr_freq) { 0093 case 0 ... 10999999: 0094 return 1; 0095 case 11000000 ... 17999999: 0096 return 2; 0097 case 18000000 ... 29999999: 0098 return 3; 0099 case 30000000 ... 49999999: 0100 return 4; 0101 case 50000000 ... 79999999: 0102 return 5; 0103 case 80000000 ... 129999999: 0104 return 6; 0105 } 0106 0107 return 7; 0108 } 0109 0110 /** 0111 * __wrpll_calc_fbdiv() - return feedback fixed divide value 0112 * @c: ptr to a struct wrpll_cfg record to read from 0113 * 0114 * The internal feedback path includes a fixed by-two divider; the 0115 * external feedback path does not. Return the appropriate divider 0116 * value (2 or 1) depending on whether internal or external feedback 0117 * is enabled. This code doesn't test for invalid configurations 0118 * (e.g. both or neither of WRPLL_FLAGS_*_FEEDBACK are set); it relies 0119 * on the caller to do so. 0120 * 0121 * Context: Any context. Caller must protect the memory pointed to by 0122 * @c from simultaneous modification. 0123 * 0124 * Return: 2 if internal feedback is enabled or 1 if external feedback 0125 * is enabled. 0126 */ 0127 static u8 __wrpll_calc_fbdiv(const struct wrpll_cfg *c) 0128 { 0129 return (c->flags & WRPLL_FLAGS_INT_FEEDBACK_MASK) ? 2 : 1; 0130 } 0131 0132 /** 0133 * __wrpll_calc_divq() - determine DIVQ based on target PLL output clock rate 0134 * @target_rate: target PLL output clock rate 0135 * @vco_rate: pointer to a u64 to store the computed VCO rate into 0136 * 0137 * Determine a reasonable value for the PLL Q post-divider, based on the 0138 * target output rate @target_rate for the PLL. Along with returning the 0139 * computed Q divider value as the return value, this function stores the 0140 * desired target VCO rate into the variable pointed to by @vco_rate. 0141 * 0142 * Context: Any context. Caller must protect the memory pointed to by 0143 * @vco_rate from simultaneous access or modification. 0144 * 0145 * Return: a positive integer DIVQ value to be programmed into the hardware 0146 * upon success, or 0 upon error (since 0 is an invalid DIVQ value) 0147 */ 0148 static u8 __wrpll_calc_divq(u32 target_rate, u64 *vco_rate) 0149 { 0150 u64 s; 0151 u8 divq = 0; 0152 0153 if (!vco_rate) { 0154 WARN_ON(1); 0155 goto wcd_out; 0156 } 0157 0158 s = div_u64(MAX_VCO_FREQ, target_rate); 0159 if (s <= 1) { 0160 divq = 1; 0161 *vco_rate = MAX_VCO_FREQ; 0162 } else if (s > MAX_DIVQ_DIVISOR) { 0163 divq = ilog2(MAX_DIVQ_DIVISOR); 0164 *vco_rate = MIN_VCO_FREQ; 0165 } else { 0166 divq = ilog2(s); 0167 *vco_rate = (u64)target_rate << divq; 0168 } 0169 0170 wcd_out: 0171 return divq; 0172 } 0173 0174 /** 0175 * __wrpll_update_parent_rate() - update PLL data when parent rate changes 0176 * @c: ptr to a struct wrpll_cfg record to write PLL data to 0177 * @parent_rate: PLL input refclk rate (pre-R-divider) 0178 * 0179 * Pre-compute some data used by the PLL configuration algorithm when 0180 * the PLL's reference clock rate changes. The intention is to avoid 0181 * computation when the parent rate remains constant - expected to be 0182 * the common case. 0183 * 0184 * Returns: 0 upon success or -ERANGE if the reference clock rate is 0185 * out of range. 0186 */ 0187 static int __wrpll_update_parent_rate(struct wrpll_cfg *c, 0188 unsigned long parent_rate) 0189 { 0190 u8 max_r_for_parent; 0191 0192 if (parent_rate > MAX_INPUT_FREQ || parent_rate < MIN_POST_DIVR_FREQ) 0193 return -ERANGE; 0194 0195 c->parent_rate = parent_rate; 0196 max_r_for_parent = div_u64(parent_rate, MIN_POST_DIVR_FREQ); 0197 c->max_r = min_t(u8, MAX_DIVR_DIVISOR, max_r_for_parent); 0198 0199 c->init_r = DIV_ROUND_UP_ULL(parent_rate, MAX_POST_DIVR_FREQ); 0200 0201 return 0; 0202 } 0203 0204 /** 0205 * wrpll_configure_for_rate() - compute PLL configuration for a target rate 0206 * @c: ptr to a struct wrpll_cfg record to write into 0207 * @target_rate: target PLL output clock rate (post-Q-divider) 0208 * @parent_rate: PLL input refclk rate (pre-R-divider) 0209 * 0210 * Compute the appropriate PLL signal configuration values and store 0211 * in PLL context @c. PLL reprogramming is not glitchless, so the 0212 * caller should switch any downstream logic to a different clock 0213 * source or clock-gate it before presenting these values to the PLL 0214 * configuration signals. 0215 * 0216 * The caller must pass this function a pre-initialized struct 0217 * wrpll_cfg record: either initialized to zero (with the 0218 * exception of the .name and .flags fields) or read from the PLL. 0219 * 0220 * Context: Any context. Caller must protect the memory pointed to by @c 0221 * from simultaneous access or modification. 0222 * 0223 * Return: 0 upon success; anything else upon failure. 0224 */ 0225 int wrpll_configure_for_rate(struct wrpll_cfg *c, u32 target_rate, 0226 unsigned long parent_rate) 0227 { 0228 unsigned long ratio; 0229 u64 target_vco_rate, delta, best_delta, f_pre_div, vco, vco_pre; 0230 u32 best_f, f, post_divr_freq; 0231 u8 fbdiv, divq, best_r, r; 0232 int range; 0233 0234 if (c->flags == 0) { 0235 WARN(1, "%s called with uninitialized PLL config", __func__); 0236 return -EINVAL; 0237 } 0238 0239 /* Initialize rounding data if it hasn't been initialized already */ 0240 if (parent_rate != c->parent_rate) { 0241 if (__wrpll_update_parent_rate(c, parent_rate)) { 0242 pr_err("%s: PLL input rate is out of range\n", 0243 __func__); 0244 return -ERANGE; 0245 } 0246 } 0247 0248 c->flags &= ~WRPLL_FLAGS_RESET_MASK; 0249 0250 /* Put the PLL into bypass if the user requests the parent clock rate */ 0251 if (target_rate == parent_rate) { 0252 c->flags |= WRPLL_FLAGS_BYPASS_MASK; 0253 return 0; 0254 } 0255 0256 c->flags &= ~WRPLL_FLAGS_BYPASS_MASK; 0257 0258 /* Calculate the Q shift and target VCO rate */ 0259 divq = __wrpll_calc_divq(target_rate, &target_vco_rate); 0260 if (!divq) 0261 return -1; 0262 c->divq = divq; 0263 0264 /* Precalculate the pre-Q divider target ratio */ 0265 ratio = div64_u64((target_vco_rate << ROUND_SHIFT), parent_rate); 0266 0267 fbdiv = __wrpll_calc_fbdiv(c); 0268 best_r = 0; 0269 best_f = 0; 0270 best_delta = MAX_VCO_FREQ; 0271 0272 /* 0273 * Consider all values for R which land within 0274 * [MIN_POST_DIVR_FREQ, MAX_POST_DIVR_FREQ]; prefer smaller R 0275 */ 0276 for (r = c->init_r; r <= c->max_r; ++r) { 0277 f_pre_div = ratio * r; 0278 f = (f_pre_div + (1 << ROUND_SHIFT)) >> ROUND_SHIFT; 0279 f >>= (fbdiv - 1); 0280 0281 post_divr_freq = div_u64(parent_rate, r); 0282 vco_pre = fbdiv * post_divr_freq; 0283 vco = vco_pre * f; 0284 0285 /* Ensure rounding didn't take us out of range */ 0286 if (vco > target_vco_rate) { 0287 --f; 0288 vco = vco_pre * f; 0289 } else if (vco < MIN_VCO_FREQ) { 0290 ++f; 0291 vco = vco_pre * f; 0292 } 0293 0294 delta = abs(target_rate - vco); 0295 if (delta < best_delta) { 0296 best_delta = delta; 0297 best_r = r; 0298 best_f = f; 0299 } 0300 } 0301 0302 c->divr = best_r - 1; 0303 c->divf = best_f - 1; 0304 0305 post_divr_freq = div_u64(parent_rate, best_r); 0306 0307 /* Pick the best PLL jitter filter */ 0308 range = __wrpll_calc_filter_range(post_divr_freq); 0309 if (range < 0) 0310 return range; 0311 c->range = range; 0312 0313 return 0; 0314 } 0315 0316 /** 0317 * wrpll_calc_output_rate() - calculate the PLL's target output rate 0318 * @c: ptr to a struct wrpll_cfg record to read from 0319 * @parent_rate: PLL refclk rate 0320 * 0321 * Given a pointer to the PLL's current input configuration @c and the 0322 * PLL's input reference clock rate @parent_rate (before the R 0323 * pre-divider), calculate the PLL's output clock rate (after the Q 0324 * post-divider). 0325 * 0326 * Context: Any context. Caller must protect the memory pointed to by @c 0327 * from simultaneous modification. 0328 * 0329 * Return: the PLL's output clock rate, in Hz. The return value from 0330 * this function is intended to be convenient to pass directly 0331 * to the Linux clock framework; thus there is no explicit 0332 * error return value. 0333 */ 0334 unsigned long wrpll_calc_output_rate(const struct wrpll_cfg *c, 0335 unsigned long parent_rate) 0336 { 0337 u8 fbdiv; 0338 u64 n; 0339 0340 if (c->flags & WRPLL_FLAGS_EXT_FEEDBACK_MASK) { 0341 WARN(1, "external feedback mode not yet supported"); 0342 return ULONG_MAX; 0343 } 0344 0345 fbdiv = __wrpll_calc_fbdiv(c); 0346 n = parent_rate * fbdiv * (c->divf + 1); 0347 n = div_u64(n, c->divr + 1); 0348 n >>= c->divq; 0349 0350 return n; 0351 } 0352 0353 /** 0354 * wrpll_calc_max_lock_us() - return the time for the PLL to lock 0355 * @c: ptr to a struct wrpll_cfg record to read from 0356 * 0357 * Return the minimum amount of time (in microseconds) that the caller 0358 * must wait after reprogramming the PLL to ensure that it is locked 0359 * to the input frequency and stable. This is likely to depend on the DIVR 0360 * value; this is under discussion with the manufacturer. 0361 * 0362 * Return: the minimum amount of time the caller must wait for the PLL 0363 * to lock (in microseconds) 0364 */ 0365 unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c) 0366 { 0367 return MAX_LOCK_US; 0368 }
[ Source navigation ] | [ Diff markup ] | [ Identifier search ] | [ general search ] |
This page was automatically generated by the 2.1.0 LXR engine. The LXR team |
![]() ![]() |