GNU Linux-libre 4.19.268-gnu1
[releases.git] / drivers / clk / meson / clk-pll.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (c) 2015 Endless Mobile, Inc.
4  * Author: Carlo Caione <carlo@endlessm.com>
5  *
6  * Copyright (c) 2018 Baylibre, SAS.
7  * Author: Jerome Brunet <jbrunet@baylibre.com>
8  */
9
10 /*
11  * In the most basic form, a Meson PLL is composed as follows:
12  *
13  *                     PLL
14  *      +------------------------------+
15  *      |                              |
16  * in -----[ /N ]---[ *M ]---[ >>OD ]----->> out
17  *      |         ^        ^           |
18  *      +------------------------------+
19  *                |        |
20  *               FREF     VCO
21  *
22  * out = in * (m + frac / frac_max) / (n << sum(ods))
23  */
24
25 #include <linux/clk-provider.h>
26 #include <linux/delay.h>
27 #include <linux/err.h>
28 #include <linux/io.h>
29 #include <linux/math64.h>
30 #include <linux/module.h>
31 #include <linux/of_address.h>
32 #include <linux/slab.h>
33 #include <linux/string.h>
34
35 #include "clkc.h"
36
37 static inline struct meson_clk_pll_data *
38 meson_clk_pll_data(struct clk_regmap *clk)
39 {
40         return (struct meson_clk_pll_data *)clk->data;
41 }
42
43 static unsigned long __pll_params_to_rate(unsigned long parent_rate,
44                                           const struct pll_rate_table *pllt,
45                                           u16 frac,
46                                           struct meson_clk_pll_data *pll)
47 {
48         u64 rate = (u64)parent_rate * pllt->m;
49         unsigned int od = pllt->od + pllt->od2 + pllt->od3;
50
51         if (frac && MESON_PARM_APPLICABLE(&pll->frac)) {
52                 u64 frac_rate = (u64)parent_rate * frac;
53
54                 rate += DIV_ROUND_UP_ULL(frac_rate,
55                                          (1 << pll->frac.width));
56         }
57
58         return DIV_ROUND_UP_ULL(rate, pllt->n << od);
59 }
60
61 static unsigned long meson_clk_pll_recalc_rate(struct clk_hw *hw,
62                                                 unsigned long parent_rate)
63 {
64         struct clk_regmap *clk = to_clk_regmap(hw);
65         struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
66         struct pll_rate_table pllt;
67         u16 frac;
68
69         pllt.n = meson_parm_read(clk->map, &pll->n);
70         pllt.m = meson_parm_read(clk->map, &pll->m);
71         pllt.od = meson_parm_read(clk->map, &pll->od);
72
73         pllt.od2 = MESON_PARM_APPLICABLE(&pll->od2) ?
74                 meson_parm_read(clk->map, &pll->od2) :
75                 0;
76
77         pllt.od3 = MESON_PARM_APPLICABLE(&pll->od3) ?
78                 meson_parm_read(clk->map, &pll->od3) :
79                 0;
80
81         frac = MESON_PARM_APPLICABLE(&pll->frac) ?
82                 meson_parm_read(clk->map, &pll->frac) :
83                 0;
84
85         return __pll_params_to_rate(parent_rate, &pllt, frac, pll);
86 }
87
88 static u16 __pll_params_with_frac(unsigned long rate,
89                                   unsigned long parent_rate,
90                                   const struct pll_rate_table *pllt,
91                                   struct meson_clk_pll_data *pll)
92 {
93         u16 frac_max = (1 << pll->frac.width);
94         u64 val = (u64)rate * pllt->n;
95
96         val <<= pllt->od + pllt->od2 + pllt->od3;
97
98         if (pll->flags & CLK_MESON_PLL_ROUND_CLOSEST)
99                 val = DIV_ROUND_CLOSEST_ULL(val * frac_max, parent_rate);
100         else
101                 val = div_u64(val * frac_max, parent_rate);
102
103         val -= pllt->m * frac_max;
104
105         return min((u16)val, (u16)(frac_max - 1));
106 }
107
108 static const struct pll_rate_table *
109 meson_clk_get_pll_settings(unsigned long rate,
110                            struct meson_clk_pll_data *pll)
111 {
112         const struct pll_rate_table *table = pll->table;
113         unsigned int i = 0;
114
115         if (!table)
116                 return NULL;
117
118         /* Find the first table element exceeding rate */
119         while (table[i].rate && table[i].rate <= rate)
120                 i++;
121
122         if (i != 0) {
123                 if (MESON_PARM_APPLICABLE(&pll->frac) ||
124                     !(pll->flags & CLK_MESON_PLL_ROUND_CLOSEST) ||
125                     (abs(rate - table[i - 1].rate) <
126                      abs(rate - table[i].rate)))
127                         i--;
128         }
129
130         return (struct pll_rate_table *)&table[i];
131 }
132
133 static long meson_clk_pll_round_rate(struct clk_hw *hw, unsigned long rate,
134                                      unsigned long *parent_rate)
135 {
136         struct clk_regmap *clk = to_clk_regmap(hw);
137         struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
138         const struct pll_rate_table *pllt =
139                 meson_clk_get_pll_settings(rate, pll);
140         u16 frac;
141
142         if (!pllt)
143                 return meson_clk_pll_recalc_rate(hw, *parent_rate);
144
145         if (!MESON_PARM_APPLICABLE(&pll->frac)
146             || rate == pllt->rate)
147                 return pllt->rate;
148
149         /*
150          * The rate provided by the setting is not an exact match, let's
151          * try to improve the result using the fractional parameter
152          */
153         frac = __pll_params_with_frac(rate, *parent_rate, pllt, pll);
154
155         return __pll_params_to_rate(*parent_rate, pllt, frac, pll);
156 }
157
158 static int meson_clk_pll_wait_lock(struct clk_hw *hw)
159 {
160         struct clk_regmap *clk = to_clk_regmap(hw);
161         struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
162         int delay = 24000000;
163
164         do {
165                 /* Is the clock locked now ? */
166                 if (meson_parm_read(clk->map, &pll->l))
167                         return 0;
168
169                 delay--;
170         } while (delay > 0);
171
172         return -ETIMEDOUT;
173 }
174
175 static void meson_clk_pll_init(struct clk_hw *hw)
176 {
177         struct clk_regmap *clk = to_clk_regmap(hw);
178         struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
179
180         if (pll->init_count) {
181                 meson_parm_write(clk->map, &pll->rst, 1);
182                 regmap_multi_reg_write(clk->map, pll->init_regs,
183                                        pll->init_count);
184                 meson_parm_write(clk->map, &pll->rst, 0);
185         }
186 }
187
188 static int meson_clk_pll_set_rate(struct clk_hw *hw, unsigned long rate,
189                                   unsigned long parent_rate)
190 {
191         struct clk_regmap *clk = to_clk_regmap(hw);
192         struct meson_clk_pll_data *pll = meson_clk_pll_data(clk);
193         const struct pll_rate_table *pllt;
194         unsigned long old_rate;
195         u16 frac = 0;
196
197         if (parent_rate == 0 || rate == 0)
198                 return -EINVAL;
199
200         old_rate = clk_hw_get_rate(hw);
201
202         pllt = meson_clk_get_pll_settings(rate, pll);
203         if (!pllt)
204                 return -EINVAL;
205
206         /* Put the pll in reset to write the params */
207         meson_parm_write(clk->map, &pll->rst, 1);
208
209         meson_parm_write(clk->map, &pll->n, pllt->n);
210         meson_parm_write(clk->map, &pll->m, pllt->m);
211         meson_parm_write(clk->map, &pll->od, pllt->od);
212
213         if (MESON_PARM_APPLICABLE(&pll->od2))
214                 meson_parm_write(clk->map, &pll->od2, pllt->od2);
215
216         if (MESON_PARM_APPLICABLE(&pll->od3))
217                 meson_parm_write(clk->map, &pll->od3, pllt->od3);
218
219         if (MESON_PARM_APPLICABLE(&pll->frac)) {
220                 frac = __pll_params_with_frac(rate, parent_rate, pllt, pll);
221                 meson_parm_write(clk->map, &pll->frac, frac);
222         }
223
224         /* make sure the reset is cleared at this point */
225         meson_parm_write(clk->map, &pll->rst, 0);
226
227         if (meson_clk_pll_wait_lock(hw)) {
228                 pr_warn("%s: pll did not lock, trying to restore old rate %lu\n",
229                         __func__, old_rate);
230                 /*
231                  * FIXME: Do we really need/want this HACK ?
232                  * It looks unsafe. what happens if the clock gets into a
233                  * broken state and we can't lock back on the old_rate ? Looks
234                  * like an infinite recursion is possible
235                  */
236                 meson_clk_pll_set_rate(hw, old_rate, parent_rate);
237         }
238
239         return 0;
240 }
241
242 const struct clk_ops meson_clk_pll_ops = {
243         .init           = meson_clk_pll_init,
244         .recalc_rate    = meson_clk_pll_recalc_rate,
245         .round_rate     = meson_clk_pll_round_rate,
246         .set_rate       = meson_clk_pll_set_rate,
247 };
248
249 const struct clk_ops meson_clk_pll_ro_ops = {
250         .recalc_rate    = meson_clk_pll_recalc_rate,
251 };