root/drivers/clk/analogbits/wrpll-cln28hpc.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. __wrpll_calc_filter_range
  2. __wrpll_calc_fbdiv
  3. __wrpll_calc_divq
  4. __wrpll_update_parent_rate
  5. wrpll_configure_for_rate
  6. wrpll_calc_output_rate
  7. wrpll_calc_max_lock_us

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

/* [<][>][^][v][top][bottom][index][help] */