^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) }