e5ebdc4ea4141ec7d05db9eeb300d40beaecdf64
[openwrt/staging/pepe2k.git] / target / linux / at91 / patches-6.1 / 106-clk-at91-clk-sam9x60-pll-add-notifier-for-div-part-o.patch
1 From e76d2af5009f52aa02d3db7ae32d150ad66398f9 Mon Sep 17 00:00:00 2001
2 From: Claudiu Beznea <claudiu.beznea@microchip.com>
3 Date: Mon, 11 Oct 2021 14:27:15 +0300
4 Subject: [PATCH 243/247] clk: at91: clk-sam9x60-pll: add notifier for div part
5 of PLL
6
7 SAM9X60's PLL which is also part of SAMA7G5 is composed of 2 parts:
8 one fractional part and one divider. On SAMA7G5 the CPU PLL could be
9 changed at run-time to implement DVFS. The hardware clock tree on
10 SAMA7G5 for CPU PLL is as follows:
11
12 +---- div1 ----------------> cpuck
13 |
14 FRAC PLL ---> DIV PLL -+-> prescaler ---> div0 ---> mck0
15
16 The div1 block is not implemented in Linux; on prescaler block it has
17 been discovered a bug on some scenarios and will be removed from Linux
18 in next commits. Thus, the final clock tree that will be used in Linux
19 will be as follows:
20
21 +-----------> cpuck
22 |
23 FRAC PLL ---> DIV PLL -+-> div0 ---> mck0
24
25 It has been proposed in [1] to not introduce a new CPUFreq driver but
26 to overload the proper clock drivers with proper operation such that
27 cpufreq-dt to be used. To accomplish this DIV PLL and div0 implement
28 clock notifiers which applies safe dividers before FRAC PLL is changed.
29 The current commit treats only the DIV PLL by adding a notifier that
30 sets a safe divider on PRE_RATE_CHANGE events. The safe divider is
31 provided by initialization clock code (sama7g5.c). The div0 is treated
32 in next commits (to keep the changes as clean as possible).
33
34 [1] https://lore.kernel.org/lkml/20210105104426.4tmgc2l3vyicwedd@vireshk-i7/
35
36 Signed-off-by: Claudiu Beznea <claudiu.beznea@microchip.com>
37 Link: https://lore.kernel.org/r/20211011112719.3951784-12-claudiu.beznea@microchip.com
38 Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
39 Signed-off-by: Stephen Boyd <sboyd@kernel.org>
40 ---
41 drivers/clk/at91/clk-sam9x60-pll.c | 102 ++++++++++++++++++++++-------
42 drivers/clk/at91/pmc.h | 3 +-
43 drivers/clk/at91/sam9x60.c | 6 +-
44 drivers/clk/at91/sama7g5.c | 13 +++-
45 4 files changed, 95 insertions(+), 29 deletions(-)
46
47 --- a/drivers/clk/at91/clk-sam9x60-pll.c
48 +++ b/drivers/clk/at91/clk-sam9x60-pll.c
49 @@ -5,6 +5,7 @@
50 */
51
52 #include <linux/bitfield.h>
53 +#include <linux/clk.h>
54 #include <linux/clk-provider.h>
55 #include <linux/clkdev.h>
56 #include <linux/clk/at91_pmc.h>
57 @@ -47,12 +48,15 @@ struct sam9x60_div {
58 struct sam9x60_pll_core core;
59 struct at91_clk_pms pms;
60 u8 div;
61 + u8 safe_div;
62 };
63
64 #define to_sam9x60_pll_core(hw) container_of(hw, struct sam9x60_pll_core, hw)
65 #define to_sam9x60_frac(core) container_of(core, struct sam9x60_frac, core)
66 #define to_sam9x60_div(core) container_of(core, struct sam9x60_div, core)
67
68 +static struct sam9x60_div *notifier_div;
69 +
70 static inline bool sam9x60_pll_ready(struct regmap *regmap, int id)
71 {
72 unsigned int status;
73 @@ -329,6 +333,26 @@ static const struct clk_ops sam9x60_frac
74 .restore_context = sam9x60_frac_pll_restore_context,
75 };
76
77 +/* This function should be called with spinlock acquired. */
78 +static void sam9x60_div_pll_set_div(struct sam9x60_pll_core *core, u32 div,
79 + bool enable)
80 +{
81 + struct regmap *regmap = core->regmap;
82 + u32 ena_msk = enable ? core->layout->endiv_mask : 0;
83 + u32 ena_val = enable ? (1 << core->layout->endiv_shift) : 0;
84 +
85 + regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
86 + core->layout->div_mask | ena_msk,
87 + (div << core->layout->div_shift) | ena_val);
88 +
89 + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
90 + AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
91 + AT91_PMC_PLL_UPDT_UPDATE | core->id);
92 +
93 + while (!sam9x60_pll_ready(regmap, core->id))
94 + cpu_relax();
95 +}
96 +
97 static int sam9x60_div_pll_set(struct sam9x60_pll_core *core)
98 {
99 struct sam9x60_div *div = to_sam9x60_div(core);
100 @@ -346,17 +370,7 @@ static int sam9x60_div_pll_set(struct sa
101 if (!!(val & core->layout->endiv_mask) && cdiv == div->div)
102 goto unlock;
103
104 - regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
105 - core->layout->div_mask | core->layout->endiv_mask,
106 - (div->div << core->layout->div_shift) |
107 - (1 << core->layout->endiv_shift));
108 -
109 - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
110 - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
111 - AT91_PMC_PLL_UPDT_UPDATE | core->id);
112 -
113 - while (!sam9x60_pll_ready(regmap, core->id))
114 - cpu_relax();
115 + sam9x60_div_pll_set_div(core, div->div, 1);
116
117 unlock:
118 spin_unlock_irqrestore(core->lock, flags);
119 @@ -502,16 +516,7 @@ static int sam9x60_div_pll_set_rate_chg(
120 if (cdiv == div->div)
121 goto unlock;
122
123 - regmap_update_bits(regmap, AT91_PMC_PLL_CTRL0,
124 - core->layout->div_mask,
125 - (div->div << core->layout->div_shift));
126 -
127 - regmap_update_bits(regmap, AT91_PMC_PLL_UPDT,
128 - AT91_PMC_PLL_UPDT_UPDATE | AT91_PMC_PLL_UPDT_ID_MSK,
129 - AT91_PMC_PLL_UPDT_UPDATE | core->id);
130 -
131 - while (!sam9x60_pll_ready(regmap, core->id))
132 - cpu_relax();
133 + sam9x60_div_pll_set_div(core, div->div, 0);
134
135 unlock:
136 spin_unlock_irqrestore(core->lock, irqflags);
137 @@ -538,6 +543,48 @@ static void sam9x60_div_pll_restore_cont
138 sam9x60_div_pll_set(core);
139 }
140
141 +static int sam9x60_div_pll_notifier_fn(struct notifier_block *notifier,
142 + unsigned long code, void *data)
143 +{
144 + struct sam9x60_div *div = notifier_div;
145 + struct sam9x60_pll_core core = div->core;
146 + struct regmap *regmap = core.regmap;
147 + unsigned long irqflags;
148 + u32 val, cdiv;
149 + int ret = NOTIFY_DONE;
150 +
151 + if (code != PRE_RATE_CHANGE)
152 + return ret;
153 +
154 + /*
155 + * We switch to safe divider to avoid overclocking of other domains
156 + * feed by us while the frac PLL (our parent) is changed.
157 + */
158 + div->div = div->safe_div;
159 +
160 + spin_lock_irqsave(core.lock, irqflags);
161 + regmap_update_bits(regmap, AT91_PMC_PLL_UPDT, AT91_PMC_PLL_UPDT_ID_MSK,
162 + core.id);
163 + regmap_read(regmap, AT91_PMC_PLL_CTRL0, &val);
164 + cdiv = (val & core.layout->div_mask) >> core.layout->div_shift;
165 +
166 + /* Stop if nothing changed. */
167 + if (cdiv == div->safe_div)
168 + goto unlock;
169 +
170 + sam9x60_div_pll_set_div(&core, div->div, 0);
171 + ret = NOTIFY_OK;
172 +
173 +unlock:
174 + spin_unlock_irqrestore(core.lock, irqflags);
175 +
176 + return ret;
177 +}
178 +
179 +static struct notifier_block sam9x60_div_pll_notifier = {
180 + .notifier_call = sam9x60_div_pll_notifier_fn,
181 +};
182 +
183 static const struct clk_ops sam9x60_div_pll_ops = {
184 .prepare = sam9x60_div_pll_prepare,
185 .unprepare = sam9x60_div_pll_unprepare,
186 @@ -647,7 +694,8 @@ struct clk_hw * __init
187 sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
188 const char *name, const char *parent_name, u8 id,
189 const struct clk_pll_characteristics *characteristics,
190 - const struct clk_pll_layout *layout, u32 flags)
191 + const struct clk_pll_layout *layout, u32 flags,
192 + u32 safe_div)
193 {
194 struct sam9x60_div *div;
195 struct clk_hw *hw;
196 @@ -656,9 +704,13 @@ sam9x60_clk_register_div_pll(struct regm
197 unsigned int val;
198 int ret;
199
200 - if (id > PLL_MAX_ID || !lock)
201 + /* We only support one changeable PLL. */
202 + if (id > PLL_MAX_ID || !lock || (safe_div && notifier_div))
203 return ERR_PTR(-EINVAL);
204
205 + if (safe_div >= PLL_DIV_MAX)
206 + safe_div = PLL_DIV_MAX - 1;
207 +
208 div = kzalloc(sizeof(*div), GFP_KERNEL);
209 if (!div)
210 return ERR_PTR(-ENOMEM);
211 @@ -678,6 +730,7 @@ sam9x60_clk_register_div_pll(struct regm
212 div->core.layout = layout;
213 div->core.regmap = regmap;
214 div->core.lock = lock;
215 + div->safe_div = safe_div;
216
217 spin_lock_irqsave(div->core.lock, irqflags);
218
219 @@ -693,6 +746,9 @@ sam9x60_clk_register_div_pll(struct regm
220 if (ret) {
221 kfree(div);
222 hw = ERR_PTR(ret);
223 + } else if (div->safe_div) {
224 + notifier_div = div;
225 + clk_notifier_register(hw->clk, &sam9x60_div_pll_notifier);
226 }
227
228 return hw;
229 --- a/drivers/clk/at91/pmc.h
230 +++ b/drivers/clk/at91/pmc.h
231 @@ -214,7 +214,8 @@ struct clk_hw * __init
232 sam9x60_clk_register_div_pll(struct regmap *regmap, spinlock_t *lock,
233 const char *name, const char *parent_name, u8 id,
234 const struct clk_pll_characteristics *characteristics,
235 - const struct clk_pll_layout *layout, u32 flags);
236 + const struct clk_pll_layout *layout, u32 flags,
237 + u32 safe_div);
238
239 struct clk_hw * __init
240 sam9x60_clk_register_frac_pll(struct regmap *regmap, spinlock_t *lock,
241 --- a/drivers/clk/at91/sam9x60.c
242 +++ b/drivers/clk/at91/sam9x60.c
243 @@ -242,7 +242,7 @@ static void __init sam9x60_pmc_setup(str
244 * This feeds CPU. It should not
245 * be disabled.
246 */
247 - CLK_IS_CRITICAL | CLK_SET_RATE_GATE);
248 + CLK_IS_CRITICAL | CLK_SET_RATE_GATE, 0);
249 if (IS_ERR(hw))
250 goto err_free;
251
252 @@ -260,7 +260,7 @@ static void __init sam9x60_pmc_setup(str
253 &pll_div_layout,
254 CLK_SET_RATE_GATE |
255 CLK_SET_PARENT_GATE |
256 - CLK_SET_RATE_PARENT);
257 + CLK_SET_RATE_PARENT, 0);
258 if (IS_ERR(hw))
259 goto err_free;
260
261 @@ -279,7 +279,7 @@ static void __init sam9x60_pmc_setup(str
262 hw = at91_clk_register_master_div(regmap, "masterck_div",
263 "masterck_pres", &sam9x60_master_layout,
264 &mck_characteristics, &mck_lock,
265 - CLK_SET_RATE_GATE);
266 + CLK_SET_RATE_GATE, 0);
267 if (IS_ERR(hw))
268 goto err_free;
269
270 --- a/drivers/clk/at91/sama7g5.c
271 +++ b/drivers/clk/at91/sama7g5.c
272 @@ -127,6 +127,8 @@ static const struct clk_pll_characterist
273 * @t: clock type
274 * @f: clock flags
275 * @eid: export index in sama7g5->chws[] array
276 + * @safe_div: intermediate divider need to be set on PRE_RATE_CHANGE
277 + * notification
278 */
279 static const struct {
280 const char *n;
281 @@ -136,6 +138,7 @@ static const struct {
282 unsigned long f;
283 u8 t;
284 u8 eid;
285 + u8 safe_div;
286 } sama7g5_plls[][PLL_ID_MAX] = {
287 [PLL_ID_CPU] = {
288 { .n = "cpupll_fracck",
289 @@ -156,7 +159,12 @@ static const struct {
290 .t = PLL_TYPE_DIV,
291 /* This feeds CPU. It should not be disabled. */
292 .f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
293 - .eid = PMC_CPUPLL, },
294 + .eid = PMC_CPUPLL,
295 + /*
296 + * Safe div=15 should be safe even for switching b/w 1GHz and
297 + * 90MHz (frac pll might go up to 1.2GHz).
298 + */
299 + .safe_div = 15, },
300 },
301
302 [PLL_ID_SYS] = {
303 @@ -966,7 +974,8 @@ static void __init sama7g5_pmc_setup(str
304 sama7g5_plls[i][j].p, i,
305 sama7g5_plls[i][j].c,
306 sama7g5_plls[i][j].l,
307 - sama7g5_plls[i][j].f);
308 + sama7g5_plls[i][j].f,
309 + sama7g5_plls[i][j].safe_div);
310 break;
311
312 default: