blob: b7d64bdbb3d4b3e9a07bc0c43928252050251f99 [file] [log] [blame]
Claudiu Bezneabaf5b522020-10-07 18:17:08 +03001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
4 *
5 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
6 *
7 * Based on sam9x60.c on Linux.
8 */
9
Claudiu Bezneabaf5b522020-10-07 18:17:08 +030010#include <clk-uclass.h>
11#include <dm.h>
12#include <dt-bindings/clk/at91.h>
13#include <linux/clk-provider.h>
14
15#include "pmc.h"
16
17/**
18 * Clock identifiers to be used in conjunction with macros like
19 * AT91_TO_CLK_ID()
20 *
21 * @ID_MD_SLCK: TD slow clock identifier
22 * @ID_TD_SLCK: MD slow clock identifier
23 * @ID_MAIN_XTAL: Main Xtal clock identifier
24 * @ID_MAIN_RC: Main RC clock identifier
25 * @ID_MAIN_RC_OSC: Main RC Oscillator clock identifier
26 * @ID_MAIN_OSC: Main Oscillator clock identifier
27 * @ID_MAINCK: MAINCK clock identifier
28 * @ID_PLL_U_FRAC: UPLL fractional clock identifier
29 * @ID_PLL_U_DIV: UPLL divider clock identifier
30 * @ID_PLL_A_FRAC: APLL fractional clock identifier
31 * @ID_PLL_A_DIV: APLL divider clock identifier
32
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +030033 * @ID_MCK_DIV: MCK DIV clock identifier
Claudiu Bezneabaf5b522020-10-07 18:17:08 +030034
35 * @ID_UTMI: UTMI clock identifier
36
37 * @ID_PROG0: Programmable 0 clock identifier
38 * @ID_PROG1: Programmable 1 clock identifier
39
40 * @ID_PCK0: PCK0 system clock identifier
41 * @ID_PCK1: PCK1 system clock identifier
42 * @ID_DDR: DDR system clock identifier
43 * @ID_QSPI: QSPI system clock identifier
44 *
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +030045 * @ID_MCK_PRES: MCK PRES clock identifier
46 *
Claudiu Bezneabaf5b522020-10-07 18:17:08 +030047 * Note: if changing the values of this enums please sync them with
48 * device tree
49 */
50enum pmc_clk_ids {
51 ID_MD_SLCK = 0,
52 ID_TD_SLCK = 1,
53 ID_MAIN_XTAL = 2,
54 ID_MAIN_RC = 3,
55 ID_MAIN_RC_OSC = 4,
56 ID_MAIN_OSC = 5,
57 ID_MAINCK = 6,
58
59 ID_PLL_U_FRAC = 7,
60 ID_PLL_U_DIV = 8,
61 ID_PLL_A_FRAC = 9,
62 ID_PLL_A_DIV = 10,
63
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +030064 ID_MCK_DIV = 11,
Claudiu Bezneabaf5b522020-10-07 18:17:08 +030065
66 ID_UTMI = 12,
67
68 ID_PROG0 = 13,
69 ID_PROG1 = 14,
70
71 ID_PCK0 = 15,
72 ID_PCK1 = 16,
73
74 ID_DDR = 17,
75 ID_QSPI = 18,
76
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +030077 ID_MCK_PRES = 19,
Sergiu Moga790b9702023-03-08 16:39:51 +020078 ID_USBCK = 20,
79 ID_UHPCK = 21,
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +030080
Claudiu Bezneabaf5b522020-10-07 18:17:08 +030081 ID_MAX,
82};
83
84/**
85 * PLL type identifiers
86 * @PLL_TYPE_FRAC: fractional PLL identifier
87 * @PLL_TYPE_DIV: divider PLL identifier
88 */
89enum pll_type {
90 PLL_TYPE_FRAC,
91 PLL_TYPE_DIV,
92};
93
94/* Clock names used as parents for multiple clocks. */
95static const char *clk_names[] = {
96 [ID_MAIN_RC_OSC] = "main_rc_osc",
97 [ID_MAIN_OSC] = "main_osc",
98 [ID_MAINCK] = "mainck",
99 [ID_PLL_U_DIV] = "upll_divpmcck",
100 [ID_PLL_A_DIV] = "plla_divpmcck",
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300101 [ID_MCK_PRES] = "mck_pres",
102 [ID_MCK_DIV] = "mck_div",
Sergiu Moga790b9702023-03-08 16:39:51 +0200103 [ID_USBCK] = "usbck",
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300104};
105
106/* Fractional PLL output range. */
107static const struct clk_range plla_outputs[] = {
108 { .min = 2343750, .max = 1200000000 },
109};
110
111static const struct clk_range upll_outputs[] = {
112 { .min = 300000000, .max = 500000000 },
113};
114
115/* PLL characteristics. */
116static const struct clk_pll_characteristics apll_characteristics = {
117 .input = { .min = 12000000, .max = 48000000 },
118 .num_output = ARRAY_SIZE(plla_outputs),
119 .output = plla_outputs,
120};
121
122static const struct clk_pll_characteristics upll_characteristics = {
123 .input = { .min = 12000000, .max = 48000000 },
124 .num_output = ARRAY_SIZE(upll_outputs),
125 .output = upll_outputs,
126 .upll = true,
127};
128
129/* Layout for fractional PLLs. */
130static const struct clk_pll_layout pll_layout_frac = {
131 .mul_mask = GENMASK(31, 24),
132 .frac_mask = GENMASK(21, 0),
133 .mul_shift = 24,
134 .frac_shift = 0,
135};
136
137/* Layout for DIV PLLs. */
138static const struct clk_pll_layout pll_layout_div = {
139 .div_mask = GENMASK(7, 0),
140 .endiv_mask = BIT(29),
141 .div_shift = 0,
142 .endiv_shift = 29,
143};
144
145/* MCK characteristics. */
146static const struct clk_master_characteristics mck_characteristics = {
147 .output = { .min = 140000000, .max = 200000000 },
148 .divisors = { 1, 2, 4, 3 },
149 .have_div3_pres = 1,
150};
151
152/* MCK layout. */
153static const struct clk_master_layout mck_layout = {
154 .mask = 0x373,
155 .pres_shift = 4,
156 .offset = 0x28,
157};
158
159/* Programmable clock layout. */
160static const struct clk_programmable_layout programmable_layout = {
161 .pres_mask = 0xff,
162 .pres_shift = 8,
163 .css_mask = 0x1f,
164 .have_slck_mck = 0,
165 .is_pres_direct = 1,
166};
167
168/* Peripheral clock layout. */
169static const struct clk_pcr_layout pcr_layout = {
170 .offset = 0x88,
171 .cmd = BIT(31),
172 .gckcss_mask = GENMASK(12, 8),
173 .pid_mask = GENMASK(6, 0),
174};
175
Sergiu Moga790b9702023-03-08 16:39:51 +0200176/* USB clock layout */
177static const struct clk_usbck_layout usbck_layout = {
178 .offset = 0x38,
179 .usbs_mask = GENMASK(1, 0),
180 .usbdiv_mask = GENMASK(11, 8),
181};
182
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300183/**
184 * PLL clocks description
185 * @n: clock name
186 * @p: clock parent
187 * @l: clock layout
188 * @t: clock type
189 * @f: true if clock is fixed and not changeable by driver
190 * @id: clock id corresponding to PLL driver
191 * @cid: clock id corresponding to clock subsystem
192 */
193static const struct {
194 const char *n;
195 const char *p;
196 const struct clk_pll_layout *l;
197 const struct clk_pll_characteristics *c;
198 u8 t;
199 u8 f;
200 u8 id;
201 u8 cid;
202} sam9x60_plls[] = {
203 {
204 .n = "plla_fracck",
205 .p = "mainck",
206 .l = &pll_layout_frac,
207 .c = &apll_characteristics,
208 .t = PLL_TYPE_FRAC,
209 .f = 1,
210 .id = 0,
211 .cid = ID_PLL_A_FRAC,
212 },
213
214 {
215 .n = "plla_divpmcck",
216 .p = "plla_fracck",
217 .l = &pll_layout_div,
218 .c = &apll_characteristics,
219 .t = PLL_TYPE_DIV,
220 .f = 1,
221 .id = 0,
222 .cid = ID_PLL_A_DIV,
223 },
224
225 {
226 .n = "upll_fracck",
227 .p = "main_osc",
228 .l = &pll_layout_frac,
229 .c = &upll_characteristics,
230 .t = PLL_TYPE_FRAC,
231 .f = 1,
232 .id = 1,
233 .cid = ID_PLL_U_FRAC,
234 },
235
236 {
237 .n = "upll_divpmcck",
238 .p = "upll_fracck",
239 .l = &pll_layout_div,
240 .c = &upll_characteristics,
241 .t = PLL_TYPE_DIV,
242 .f = 1,
243 .id = 1,
244 .cid = ID_PLL_U_DIV,
245 },
246};
247
248/**
249 * Programmable clock description
250 * @n: clock name
251 * @cid: clock id corresponding to clock subsystem
252 */
253static const struct {
254 const char *n;
255 u8 cid;
256} sam9x60_prog[] = {
257 { .n = "prog0", .cid = ID_PROG0, },
258 { .n = "prog1", .cid = ID_PROG1, },
259};
260
261/* Mux table for programmable clocks. */
262static u32 sam9x60_prog_mux_table[] = { 0, 1, 2, 3, 4, 5, };
263
264/**
265 * System clock description
266 * @n: clock name
267 * @p: parent clock name
268 * @id: clock id corresponding to system clock driver
269 * @cid: clock id corresponding to clock subsystem
270 */
271static const struct {
272 const char *n;
273 const char *p;
274 u8 id;
275 u8 cid;
276} sam9x60_systemck[] = {
Mihai Saind469b1a2022-07-19 16:51:59 +0300277 { .n = "ddrck", .p = "mck_div", .id = 2, .cid = ID_DDR, },
Sergiu Moga790b9702023-03-08 16:39:51 +0200278 { .n = "uhpck", .p = "usbck", .id = 6, .cid = ID_UHPCK },
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300279 { .n = "pck0", .p = "prog0", .id = 8, .cid = ID_PCK0, },
280 { .n = "pck1", .p = "prog1", .id = 9, .cid = ID_PCK1, },
Mihai Saind469b1a2022-07-19 16:51:59 +0300281 { .n = "qspick", .p = "mck_div", .id = 19, .cid = ID_QSPI, },
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300282};
283
284/**
285 * Peripheral clock description
286 * @n: clock name
287 * @id: clock id
288 */
289static const struct {
290 const char *n;
291 u8 id;
292} sam9x60_periphck[] = {
293 { .n = "pioA_clk", .id = 2, },
294 { .n = "pioB_clk", .id = 3, },
295 { .n = "pioC_clk", .id = 4, },
296 { .n = "flex0_clk", .id = 5, },
297 { .n = "flex1_clk", .id = 6, },
298 { .n = "flex2_clk", .id = 7, },
299 { .n = "flex3_clk", .id = 8, },
300 { .n = "flex6_clk", .id = 9, },
301 { .n = "flex7_clk", .id = 10, },
302 { .n = "flex8_clk", .id = 11, },
303 { .n = "sdmmc0_clk", .id = 12, },
304 { .n = "flex4_clk", .id = 13, },
305 { .n = "flex5_clk", .id = 14, },
306 { .n = "flex9_clk", .id = 15, },
307 { .n = "flex10_clk", .id = 16, },
308 { .n = "tcb0_clk", .id = 17, },
309 { .n = "pwm_clk", .id = 18, },
310 { .n = "adc_clk", .id = 19, },
311 { .n = "dma0_clk", .id = 20, },
312 { .n = "matrix_clk", .id = 21, },
313 { .n = "uhphs_clk", .id = 22, },
314 { .n = "udphs_clk", .id = 23, },
315 { .n = "macb0_clk", .id = 24, },
316 { .n = "lcd_clk", .id = 25, },
317 { .n = "sdmmc1_clk", .id = 26, },
318 { .n = "macb1_clk", .id = 27, },
319 { .n = "ssc_clk", .id = 28, },
320 { .n = "can0_clk", .id = 29, },
321 { .n = "can1_clk", .id = 30, },
322 { .n = "flex11_clk", .id = 32, },
323 { .n = "flex12_clk", .id = 33, },
324 { .n = "i2s_clk", .id = 34, },
325 { .n = "qspi_clk", .id = 35, },
326 { .n = "gfx2d_clk", .id = 36, },
327 { .n = "pit64b_clk", .id = 37, },
328 { .n = "trng_clk", .id = 38, },
329 { .n = "aes_clk", .id = 39, },
330 { .n = "tdes_clk", .id = 40, },
331 { .n = "sha_clk", .id = 41, },
332 { .n = "classd_clk", .id = 42, },
333 { .n = "isi_clk", .id = 43, },
334 { .n = "pioD_clk", .id = 44, },
335 { .n = "tcb1_clk", .id = 45, },
336 { .n = "dbgu_clk", .id = 47, },
337 { .n = "mpddr_clk", .id = 49, },
338};
339
340/**
341 * Generic clock description
342 * @n: clock name
343 * @ep: extra parents parents names
344 * @ep_mux_table: extra parents mux table
345 * @ep_clk_mux_table: extra parents clock mux table (for CCF)
346 * @r: clock output range
347 * @ep_count: extra parents count
348 * @id: clock id
349 */
350static const struct {
351 const char *n;
352 struct clk_range r;
353 u8 id;
354} sam9x60_gck[] = {
355 { .n = "flex0_gclk", .id = 5, },
356 { .n = "flex1_gclk", .id = 6, },
357 { .n = "flex2_gclk", .id = 7, },
358 { .n = "flex3_gclk", .id = 8, },
359 { .n = "flex6_gclk", .id = 9, },
360 { .n = "flex7_gclk", .id = 10, },
361 { .n = "flex8_gclk", .id = 11, },
362 { .n = "sdmmc0_gclk", .id = 12, .r = { .min = 0, .max = 105000000 }, },
363 { .n = "flex4_gclk", .id = 13, },
364 { .n = "flex5_gclk", .id = 14, },
365 { .n = "flex9_gclk", .id = 15, },
366 { .n = "flex10_gclk", .id = 16, },
367 { .n = "tcb0_gclk", .id = 17, },
368 { .n = "adc_gclk", .id = 19, },
369 { .n = "lcd_gclk", .id = 25, .r = { .min = 0, .max = 140000000 }, },
370 { .n = "sdmmc1_gclk", .id = 26, .r = { .min = 0, .max = 105000000 }, },
371 { .n = "flex11_gclk", .id = 32, },
372 { .n = "flex12_gclk", .id = 33, },
373 { .n = "i2s_gclk", .id = 34, .r = { .min = 0, .max = 105000000 }, },
374 { .n = "pit64b_gclk", .id = 37, },
375 { .n = "classd_gclk", .id = 42, .r = { .min = 0, .max = 100000000 }, },
376 { .n = "tcb1_gclk", .id = 45, },
377 { .n = "dbgu_gclk", .id = 47, },
378};
379
Sergiu Moga11bb0ed2023-03-08 16:39:53 +0200380/**
381 * Clock setup description
382 * @cid: clock id corresponding to clock subsystem
383 * @pid: parent clock id corresponding to clock subsystem
384 * @rate: clock rate
385 * @prate: parent rate
386 */
387static const struct pmc_clk_setup sam9x60_clk_setup[] = {
388 {
389 .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_FRAC),
390 .rate = 960000000,
391 },
392
393 {
394 .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV),
395 .rate = 480000000,
396 },
397
398 {
399 .cid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK),
400 .pid = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV),
401 .rate = 48000000,
402 },
403};
404
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300405#define prepare_mux_table(_allocs, _index, _dst, _src, _num, _label) \
406 do { \
407 int _i; \
408 (_dst) = kzalloc(sizeof(*(_dst)) * (_num), GFP_KERNEL); \
409 if (!(_dst)) { \
410 ret = -ENOMEM; \
411 goto _label; \
412 } \
413 (_allocs)[(_index)++] = (_dst); \
414 for (_i = 0; _i < (_num); _i++) \
415 (_dst)[_i] = (_src)[_i]; \
416 } while (0)
417
418static int sam9x60_clk_probe(struct udevice *dev)
419{
420 void __iomem *base = (void *)devfdt_get_addr_ptr(dev);
421 unsigned int *clkmuxallocs[64], *muxallocs[64];
422 const char *p[10];
423 unsigned int cm[10], m[10], *tmpclkmux, *tmpmux;
424 struct clk clk, *c;
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300425 int ret, muxallocindex = 0, clkmuxallocindex = 0, i;
426 static const struct clk_range r = { 0, 0 };
427
428 if (!base)
429 return -EINVAL;
430
Francois Berder14f9b112023-09-24 11:58:54 +0200431 memset(muxallocs, 0, sizeof(muxallocs));
432 memset(clkmuxallocs, 0, sizeof(clkmuxallocs));
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300433
434 ret = clk_get_by_index(dev, 0, &clk);
435 if (ret)
436 return ret;
437
438 ret = clk_get_by_id(clk.id, &c);
439 if (ret)
440 return ret;
441
442 clk_names[ID_TD_SLCK] = kmemdup(clk_hw_get_name(c),
443 strlen(clk_hw_get_name(c)) + 1,
444 GFP_KERNEL);
445 if (!clk_names[ID_TD_SLCK])
446 return -ENOMEM;
447
448 ret = clk_get_by_index(dev, 1, &clk);
449 if (ret)
450 return ret;
451
452 ret = clk_get_by_id(clk.id, &c);
453 if (ret)
454 return ret;
455
456 clk_names[ID_MD_SLCK] = kmemdup(clk_hw_get_name(c),
457 strlen(clk_hw_get_name(c)) + 1,
458 GFP_KERNEL);
459 if (!clk_names[ID_MD_SLCK])
460 return -ENOMEM;
461
462 ret = clk_get_by_index(dev, 2, &clk);
463 if (ret)
464 return ret;
465
466 clk_names[ID_MAIN_XTAL] = kmemdup(clk_hw_get_name(&clk),
467 strlen(clk_hw_get_name(&clk)) + 1,
468 GFP_KERNEL);
469 if (!clk_names[ID_MAIN_XTAL])
470 return -ENOMEM;
471
472 ret = clk_get_by_index(dev, 3, &clk);
473 if (ret)
474 goto fail;
475
476 clk_names[ID_MAIN_RC] = kmemdup(clk_hw_get_name(&clk),
477 strlen(clk_hw_get_name(&clk)) + 1,
478 GFP_KERNEL);
479 if (ret)
480 goto fail;
481
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300482 /* Register main rc oscillator. */
483 c = at91_clk_main_rc(base, clk_names[ID_MAIN_RC_OSC],
484 clk_names[ID_MAIN_RC]);
485 if (IS_ERR(c)) {
486 ret = PTR_ERR(c);
487 goto fail;
488 }
489 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC), c);
490
491 /* Register main oscillator. */
492 c = at91_clk_main_osc(base, clk_names[ID_MAIN_OSC],
Claudiu Beznea84503cd2020-12-02 13:39:33 +0200493 clk_names[ID_MAIN_XTAL], false);
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300494 if (IS_ERR(c)) {
495 ret = PTR_ERR(c);
496 goto fail;
497 }
498 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC), c);
499
500 /* Register mainck. */
501 p[0] = clk_names[ID_MAIN_RC_OSC];
502 p[1] = clk_names[ID_MAIN_OSC];
503 cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_RC_OSC);
504 cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_OSC);
505 prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 2,
506 fail);
507 c = at91_clk_sam9x5_main(base, clk_names[ID_MAINCK], p,
508 2, tmpclkmux, PMC_TYPE_CORE);
509 if (IS_ERR(c)) {
510 ret = PTR_ERR(c);
511 goto fail;
512 }
513 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK), c);
514
515 /* Register PLL fracs clocks. */
516 for (i = 0; i < ARRAY_SIZE(sam9x60_plls); i++) {
517 if (sam9x60_plls[i].t != PLL_TYPE_FRAC)
518 continue;
519
520 c = sam9x60_clk_register_frac_pll(base, sam9x60_plls[i].n,
521 sam9x60_plls[i].p,
522 sam9x60_plls[i].id,
523 sam9x60_plls[i].c,
524 sam9x60_plls[i].l,
525 sam9x60_plls[i].f);
526 if (IS_ERR(c)) {
527 ret = PTR_ERR(c);
528 goto fail;
529 }
530 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x60_plls[i].cid), c);
531 }
532
533 /* Register PLL div clocks. */
534 for (i = 0; i < ARRAY_SIZE(sam9x60_plls); i++) {
535 if (sam9x60_plls[i].t != PLL_TYPE_DIV)
536 continue;
537
538 c = sam9x60_clk_register_div_pll(base, sam9x60_plls[i].n,
539 sam9x60_plls[i].p,
540 sam9x60_plls[i].id,
541 sam9x60_plls[i].c,
542 sam9x60_plls[i].l,
543 sam9x60_plls[i].f);
544 if (IS_ERR(c)) {
545 ret = PTR_ERR(c);
546 goto fail;
547 }
548 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x60_plls[i].cid), c);
549 }
550
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300551 /* Register MCK pres clock. */
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300552 p[0] = clk_names[ID_MD_SLCK];
553 p[1] = clk_names[ID_MAINCK];
554 p[2] = clk_names[ID_PLL_A_DIV];
555 p[3] = clk_names[ID_PLL_U_DIV];
556 cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
557 cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
558 cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
559 cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
560 prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm, 4,
561 fail);
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300562 c = at91_clk_register_master_pres(base, clk_names[ID_MCK_PRES], p, 4,
563 &mck_layout, &mck_characteristics,
564 tmpclkmux);
565 if (IS_ERR(c)) {
566 ret = PTR_ERR(c);
567 goto fail;
568 }
569 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_PRES), c);
570
571 /* Register MCK div clock. */
572 c = at91_clk_register_master_div(base, clk_names[ID_MCK_DIV],
573 clk_names[ID_MCK_PRES],
574 &mck_layout, &mck_characteristics);
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300575 if (IS_ERR(c)) {
576 ret = PTR_ERR(c);
577 goto fail;
578 }
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300579 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV), c);
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300580
Sergiu Moga790b9702023-03-08 16:39:51 +0200581 /* Register usbck. */
582 p[0] = clk_names[ID_PLL_A_DIV];
583 p[1] = clk_names[ID_PLL_U_DIV];
584 p[2] = clk_names[ID_MAIN_XTAL];
585 m[0] = 0;
586 m[1] = 1;
587 m[2] = 2;
588 cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
589 cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
590 cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAIN_XTAL);
591 prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
592 3, fail);
593 prepare_mux_table(muxallocs, muxallocindex, tmpmux, m, 3, fail);
594 c = sam9x60_clk_register_usb(base, clk_names[ID_USBCK], p, 3,
595 &usbck_layout, tmpclkmux, tmpmux,
596 ID_USBCK);
597 if (IS_ERR(c)) {
598 ret = PTR_ERR(c);
599 goto fail;
600 }
601 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_USBCK), c);
602
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300603 /* Register programmable clocks. */
604 p[0] = clk_names[ID_MD_SLCK];
605 p[1] = clk_names[ID_TD_SLCK];
606 p[2] = clk_names[ID_MAINCK];
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300607 p[3] = clk_names[ID_MCK_DIV];
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300608 p[4] = clk_names[ID_PLL_A_DIV];
609 p[5] = clk_names[ID_PLL_U_DIV];
610 cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
611 cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
612 cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300613 cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV);
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300614 cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
615 cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
616 for (i = 0; i < ARRAY_SIZE(sam9x60_prog); i++) {
617 prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
618 6, fail);
619
620 c = at91_clk_register_programmable(base, sam9x60_prog[i].n, p,
621 10, i, &programmable_layout,
622 tmpclkmux,
623 sam9x60_prog_mux_table);
624 if (IS_ERR(c)) {
625 ret = PTR_ERR(c);
626 goto fail;
627 }
628 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_CORE, sam9x60_prog[i].cid), c);
629 }
630
631 /* System clocks. */
632 for (i = 0; i < ARRAY_SIZE(sam9x60_systemck); i++) {
633 c = at91_clk_register_system(base, sam9x60_systemck[i].n,
634 sam9x60_systemck[i].p,
635 sam9x60_systemck[i].id);
636 if (IS_ERR(c)) {
637 ret = PTR_ERR(c);
638 goto fail;
639 }
640 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_SYSTEM, sam9x60_systemck[i].cid),
641 c);
642 }
643
644 /* Peripheral clocks. */
645 for (i = 0; i < ARRAY_SIZE(sam9x60_periphck); i++) {
646 c = at91_clk_register_sam9x5_peripheral(base, &pcr_layout,
647 sam9x60_periphck[i].n,
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300648 clk_names[ID_MCK_DIV],
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300649 sam9x60_periphck[i].id,
650 &r);
651 if (IS_ERR(c)) {
652 ret = PTR_ERR(c);
653 goto fail;
654 }
655 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_PERIPHERAL,
656 sam9x60_periphck[i].id), c);
657 }
658
659 /* Generic clocks. */
660 p[0] = clk_names[ID_MD_SLCK];
661 p[1] = clk_names[ID_TD_SLCK];
662 p[2] = clk_names[ID_MAINCK];
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300663 p[3] = clk_names[ID_MCK_DIV];
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300664 p[4] = clk_names[ID_PLL_A_DIV];
665 p[5] = clk_names[ID_PLL_U_DIV];
666 m[0] = 0;
667 m[1] = 1;
668 m[2] = 2;
669 m[3] = 3;
670 m[4] = 4;
671 m[5] = 5;
672 cm[0] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MD_SLCK);
673 cm[1] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_TD_SLCK);
674 cm[2] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MAINCK);
Claudiu Beznea8b5bbad2021-07-16 08:43:48 +0300675 cm[3] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_MCK_DIV);
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300676 cm[4] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_A_DIV);
677 cm[5] = AT91_TO_CLK_ID(PMC_TYPE_CORE, ID_PLL_U_DIV);
678 for (i = 0; i < ARRAY_SIZE(sam9x60_gck); i++) {
679 prepare_mux_table(clkmuxallocs, clkmuxallocindex, tmpclkmux, cm,
680 6, fail);
681 prepare_mux_table(muxallocs, muxallocindex, tmpmux, m,
682 6, fail);
683
684 c = at91_clk_register_generic(base, &pcr_layout,
685 sam9x60_gck[i].n, p, tmpclkmux,
686 tmpmux, 6, sam9x60_gck[i].id,
687 &sam9x60_gck[i].r);
688 if (IS_ERR(c)) {
689 ret = PTR_ERR(c);
690 goto fail;
691 }
692 clk_dm(AT91_TO_CLK_ID(PMC_TYPE_GCK, sam9x60_gck[i].id), c);
693 }
694
Sergiu Moga11bb0ed2023-03-08 16:39:53 +0200695 /* Setup clocks. */
696 ret = at91_clk_setup(sam9x60_clk_setup, ARRAY_SIZE(sam9x60_clk_setup));
697 if (ret)
698 goto fail;
699
Claudiu Bezneabaf5b522020-10-07 18:17:08 +0300700 return 0;
701
702fail:
703 for (i = 0; i < ARRAY_SIZE(muxallocs); i++)
704 kfree(muxallocs[i]);
705
706 for (i = 0; i < ARRAY_SIZE(clkmuxallocs); i++)
707 kfree(clkmuxallocs[i]);
708
709 return ret;
710}
711
712static const struct udevice_id sam9x60_clk_ids[] = {
713 { .compatible = "microchip,sam9x60-pmc" },
714 { /* Sentinel. */ },
715};
716
717U_BOOT_DRIVER(at91_sam9x60_pmc) = {
718 .name = "at91-sam9x60-pmc",
719 .id = UCLASS_CLK,
720 .of_match = sam9x60_clk_ids,
721 .ops = &at91_clk_ops,
722 .probe = sam9x60_clk_probe,
723 .flags = DM_FLAG_PRE_RELOC,
724};