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