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