blob: 09daae97676de7a682c88eb32f5292d586353ed8 [file] [log] [blame]
Claudiu Beznea5d408872020-09-07 17:46:41 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Main clock support for AT91 architectures.
4 *
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6 *
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
8 *
9 * Based on drivers/clk/at91/clk-main.c from Linux.
10 */
11
12#include <asm/processor.h>
Claudiu Beznea5d408872020-09-07 17:46:41 +030013#include <clk-uclass.h>
14#include <dm.h>
15#include <linux/clk-provider.h>
16#include <linux/clk/at91_pmc.h>
17#include <linux/delay.h>
18#include <linux/io.h>
Igor Prusovc3421ea2023-11-09 20:10:04 +030019#include <linux/time.h>
Claudiu Beznea5d408872020-09-07 17:46:41 +030020#include "pmc.h"
21
22#define UBOOT_DM_CLK_AT91_MAIN_RC "at91-main-rc-clk"
23#define UBOOT_DM_CLK_AT91_MAIN_OSC "at91-main-osc-clk"
24#define UBOOT_DM_CLK_AT91_RM9200_MAIN "at91-rm9200-main-clk"
25#define UBOOT_DM_CLK_AT91_SAM9X5_MAIN "at91-sam9x5-main-clk"
26
27#define MOR_KEY_MASK GENMASK(23, 16)
Claudiu Beznea5d408872020-09-07 17:46:41 +030028#define SLOW_CLOCK_FREQ 32768
29
30#define clk_main_parent_select(s) (((s) & \
31 (AT91_PMC_MOSCEN | \
32 AT91_PMC_OSCBYPASS)) ? 1 : 0)
33
34struct clk_main_rc {
35 void __iomem *reg;
36 struct clk clk;
37};
38
39#define to_clk_main_rc(_clk) container_of(_clk, struct clk_main_rc, clk)
40
41struct clk_main_osc {
42 void __iomem *reg;
43 struct clk clk;
44};
45
46#define to_clk_main_osc(_clk) container_of(_clk, struct clk_main_osc, clk)
47
48struct clk_main {
49 void __iomem *reg;
50 const unsigned int *clk_mux_table;
51 const char * const *parent_names;
52 unsigned int num_parents;
53 int type;
54 struct clk clk;
55};
56
57#define to_clk_main(_clk) container_of(_clk, struct clk_main, clk)
58
59static int main_rc_enable(struct clk *clk)
60{
61 struct clk_main_rc *main_rc = to_clk_main_rc(clk);
62 void __iomem *reg = main_rc->reg;
63 unsigned int val;
64
65 pmc_read(reg, AT91_CKGR_MOR, &val);
66
67 if (!(val & AT91_PMC_MOSCRCEN)) {
68 pmc_update_bits(reg, AT91_CKGR_MOR,
69 MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
70 AT91_PMC_KEY | AT91_PMC_MOSCRCEN);
71 }
72
73 pmc_read(reg, AT91_PMC_SR, &val);
74 while (!(val & AT91_PMC_MOSCRCS)) {
75 pmc_read(reg, AT91_PMC_SR, &val);
76 debug("waiting for main rc...\n");
77 cpu_relax();
78 }
79
80 return 0;
81}
82
83static int main_rc_disable(struct clk *clk)
84{
85 struct clk_main_rc *main_rc = to_clk_main_rc(clk);
86 struct reg *reg = main_rc->reg;
87 unsigned int val;
88
89 pmc_read(reg, AT91_CKGR_MOR, &val);
90
91 if (!(val & AT91_PMC_MOSCRCEN))
92 return 0;
93
94 pmc_update_bits(reg, AT91_CKGR_MOR, MOR_KEY_MASK | AT91_PMC_MOSCRCEN,
95 AT91_PMC_KEY);
96
97 return 0;
98}
99
100static const struct clk_ops main_rc_clk_ops = {
101 .enable = main_rc_enable,
102 .disable = main_rc_disable,
103 .get_rate = clk_generic_get_rate,
104};
105
106struct clk *at91_clk_main_rc(void __iomem *reg, const char *name,
107 const char *parent_name)
108{
109 struct clk_main_rc *main_rc;
110 struct clk *clk;
111 int ret;
112
113 if (!reg || !name || !parent_name)
114 return ERR_PTR(-EINVAL);
115
116 main_rc = kzalloc(sizeof(*main_rc), GFP_KERNEL);
117 if (!main_rc)
118 return ERR_PTR(-ENOMEM);
119
120 main_rc->reg = reg;
121 clk = &main_rc->clk;
122
123 ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_RC, name,
124 parent_name);
125 if (ret) {
126 kfree(main_rc);
127 clk = ERR_PTR(ret);
128 }
129
130 return clk;
131}
132
133U_BOOT_DRIVER(at91_main_rc_clk) = {
134 .name = UBOOT_DM_CLK_AT91_MAIN_RC,
135 .id = UCLASS_CLK,
136 .ops = &main_rc_clk_ops,
137 .flags = DM_FLAG_PRE_RELOC,
138};
139
140static int clk_main_osc_enable(struct clk *clk)
141{
142 struct clk_main_osc *main = to_clk_main_osc(clk);
143 void __iomem *reg = main->reg;
144 unsigned int val;
145
146 pmc_read(reg, AT91_CKGR_MOR, &val);
147 val &= ~MOR_KEY_MASK;
148
149 if (val & AT91_PMC_OSCBYPASS)
150 return 0;
151
152 if (!(val & AT91_PMC_MOSCEN)) {
153 val |= AT91_PMC_MOSCEN | AT91_PMC_KEY;
154 pmc_write(reg, AT91_CKGR_MOR, val);
155 }
156
157 pmc_read(reg, AT91_PMC_SR, &val);
158 while (!(val & AT91_PMC_MOSCS)) {
159 pmc_read(reg, AT91_PMC_SR, &val);
160 debug("waiting for main osc..\n");
161 cpu_relax();
162 }
163
164 return 0;
165}
166
167static int clk_main_osc_disable(struct clk *clk)
168{
169 struct clk_main_osc *main = to_clk_main_osc(clk);
170 void __iomem *reg = main->reg;
171 unsigned int val;
172
173 pmc_read(reg, AT91_CKGR_MOR, &val);
174 if (val & AT91_PMC_OSCBYPASS)
175 return 0;
176
177 if (!(val & AT91_PMC_MOSCEN))
178 return 0;
179
180 val &= ~(AT91_PMC_KEY | AT91_PMC_MOSCEN);
181 pmc_write(reg, AT91_CKGR_MOR, val | AT91_PMC_KEY);
182
183 return 0;
184}
185
186static const struct clk_ops main_osc_clk_ops = {
187 .enable = clk_main_osc_enable,
188 .disable = clk_main_osc_disable,
189 .get_rate = clk_generic_get_rate,
190};
191
192struct clk *at91_clk_main_osc(void __iomem *reg, const char *name,
193 const char *parent_name, bool bypass)
194{
195 struct clk_main_osc *main;
196 struct clk *clk;
197 int ret;
198
199 if (!reg || !name || !parent_name)
200 return ERR_PTR(-EINVAL);
201
202 main = kzalloc(sizeof(*main), GFP_KERNEL);
203 if (!main)
204 return ERR_PTR(-ENOMEM);
205
206 main->reg = reg;
207 clk = &main->clk;
208
209 if (bypass) {
210 pmc_update_bits(reg, AT91_CKGR_MOR,
211 MOR_KEY_MASK | AT91_PMC_OSCBYPASS,
212 AT91_PMC_KEY | AT91_PMC_OSCBYPASS);
213 }
214
215 ret = clk_register(clk, UBOOT_DM_CLK_AT91_MAIN_OSC, name, parent_name);
216 if (ret) {
217 kfree(main);
218 clk = ERR_PTR(ret);
219 }
220
221 return clk;
222}
223
224U_BOOT_DRIVER(at91_main_osc_clk) = {
225 .name = UBOOT_DM_CLK_AT91_MAIN_OSC,
226 .id = UCLASS_CLK,
227 .ops = &main_osc_clk_ops,
228 .flags = DM_FLAG_PRE_RELOC,
229};
230
231static int clk_main_probe_frequency(void __iomem *reg)
232{
233 unsigned int cycles = 16;
234 unsigned int cycle = DIV_ROUND_UP(USEC_PER_SEC, SLOW_CLOCK_FREQ);
235 unsigned int mcfr;
236
237 while (cycles--) {
238 pmc_read(reg, AT91_CKGR_MCFR, &mcfr);
239 if (mcfr & AT91_PMC_MAINRDY)
240 return 0;
241 udelay(cycle);
242 }
243
244 return -ETIMEDOUT;
245}
246
247static int clk_rm9200_main_enable(struct clk *clk)
248{
249 struct clk_main *main = to_clk_main(clk);
250
251 return clk_main_probe_frequency(main->reg);
252}
253
254static const struct clk_ops rm9200_main_clk_ops = {
255 .enable = clk_rm9200_main_enable,
256};
257
258struct clk *at91_clk_rm9200_main(void __iomem *reg, const char *name,
259 const char *parent_name)
260{
261 struct clk_main *main;
262 struct clk *clk;
263 int ret;
264
265 if (!reg || !name || !parent_name)
266 return ERR_PTR(-EINVAL);
267
268 main = kzalloc(sizeof(*main), GFP_KERNEL);
269 if (!main)
270 return ERR_PTR(-ENOMEM);
271
272 main->reg = reg;
273 clk = &main->clk;
274
275 ret = clk_register(clk, UBOOT_DM_CLK_AT91_RM9200_MAIN, name,
276 parent_name);
277 if (ret) {
278 kfree(main);
279 clk = ERR_PTR(ret);
280 }
281
282 return clk;
283}
284
285U_BOOT_DRIVER(at91_rm9200_main_clk) = {
286 .name = UBOOT_DM_CLK_AT91_RM9200_MAIN,
287 .id = UCLASS_CLK,
288 .ops = &rm9200_main_clk_ops,
289 .flags = DM_FLAG_PRE_RELOC,
290};
291
292static inline bool clk_sam9x5_main_ready(void __iomem *reg)
293{
294 unsigned int val;
295
296 pmc_read(reg, AT91_PMC_SR, &val);
297
298 return !!(val & AT91_PMC_MOSCSELS);
299}
300
301static int clk_sam9x5_main_enable(struct clk *clk)
302{
303 struct clk_main *main = to_clk_main(clk);
304 void __iomem *reg = main->reg;
305
306 while (!clk_sam9x5_main_ready(reg)) {
307 debug("waiting for main...");
308 cpu_relax();
309 }
310
311 return clk_main_probe_frequency(reg);
312}
313
314static int clk_sam9x5_main_set_parent(struct clk *clk, struct clk *parent)
315{
316 struct clk_main *main = to_clk_main(clk);
317 void __iomem *reg = main->reg;
318 unsigned int tmp, index;
319
320 index = at91_clk_mux_val_to_index(main->clk_mux_table,
321 main->num_parents, AT91_CLK_ID_TO_DID(parent->id));
322 if (index < 0)
323 return index;
324
325 pmc_read(reg, AT91_CKGR_MOR, &tmp);
326 tmp &= ~MOR_KEY_MASK;
327 tmp |= AT91_PMC_KEY;
328
329 if (index && !(tmp & AT91_PMC_MOSCSEL))
330 pmc_write(reg, AT91_CKGR_MOR, tmp | AT91_PMC_MOSCSEL);
331 else if (!index && (tmp & AT91_PMC_MOSCSEL))
332 pmc_write(reg, AT91_CKGR_MOR, tmp & ~AT91_PMC_MOSCSEL);
333
334 while (!clk_sam9x5_main_ready(reg))
335 cpu_relax();
336
337 return 0;
338}
339
340static const struct clk_ops sam9x5_main_clk_ops = {
341 .enable = clk_sam9x5_main_enable,
342 .set_parent = clk_sam9x5_main_set_parent,
343 .get_rate = clk_generic_get_rate,
344};
345
346struct clk *at91_clk_sam9x5_main(void __iomem *reg, const char *name,
347 const char * const *parent_names,
348 int num_parents, const u32 *clk_mux_table,
349 int type)
350{
351 struct clk *clk = ERR_PTR(-ENOMEM);
352 struct clk_main *main = NULL;
353 unsigned int val;
354 int ret;
355
356 if (!reg || !name || !parent_names || !num_parents || !clk_mux_table)
357 return ERR_PTR(-EINVAL);
358
359 main = kzalloc(sizeof(*main), GFP_KERNEL);
360 if (!main)
361 return ERR_PTR(-ENOMEM);
362
363 main->reg = reg;
364 main->parent_names = parent_names;
365 main->num_parents = num_parents;
366 main->clk_mux_table = clk_mux_table;
367 main->type = type;
368 clk = &main->clk;
369 clk->flags = CLK_GET_RATE_NOCACHE;
370 pmc_read(reg, AT91_CKGR_MOR, &val);
371 ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAM9X5_MAIN, name,
372 main->parent_names[clk_main_parent_select(val)]);
373 if (ret) {
374 kfree(main);
375 clk = ERR_PTR(ret);
376 }
377
378 return clk;
379}
380
381U_BOOT_DRIVER(at91_sam9x5_main_clk) = {
382 .name = UBOOT_DM_CLK_AT91_SAM9X5_MAIN,
383 .id = UCLASS_CLK,
384 .ops = &sam9x5_main_clk_ops,
385 .flags = DM_FLAG_PRE_RELOC,
386};