linux/drivers/clk/analogbits/wrpll-cln28hpc.c
<<
>>
Prefs
   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 */
  79static 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 */
 123static 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 */
 144static 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
 166wcd_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 */
 183static 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 */
 221int 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 */
 330unsigned 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 */
 361unsigned int wrpll_calc_max_lock_us(const struct wrpll_cfg *c)
 362{
 363        return MAX_LOCK_US;
 364}
 365