1 // SPDX-License-Identifier: GPL-2.0
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
10 #include <linux/clk.h>
11 #include <linux/clk-provider.h>
12 #include <linux/mfd/syscon.h>
13 #include <linux/slab.h>
15 #include <dt-bindings/clock/at91.h>
19 #define SAMA7G5_INIT_TABLE(_table, _count) \
22 for (_i = 0; _i < (_count); _i++) \
26 #define SAMA7G5_FILL_TABLE(_to, _from, _count) \
29 for (_i = 0; _i < (_count); _i++) { \
30 (_to)[_i] = (_from)[_i]; \
34 static DEFINE_SPINLOCK(pmc_pll_lock);
35 static DEFINE_SPINLOCK(pmc_mck0_lock);
36 static DEFINE_SPINLOCK(pmc_mckX_lock);
39 * PLL clocks identifiers
40 * @PLL_ID_CPU: CPU PLL identifier
41 * @PLL_ID_SYS: System PLL identifier
42 * @PLL_ID_DDR: DDR PLL identifier
43 * @PLL_ID_IMG: Image subsystem PLL identifier
44 * @PLL_ID_BAUD: Baud PLL identifier
45 * @PLL_ID_AUDIO: Audio PLL identifier
46 * @PLL_ID_ETH: Ethernet PLL identifier
60 * PLL component identifier
61 * @PLL_COMPID_FRAC: Fractional PLL component identifier
62 * @PLL_COMPID_DIV0: 1st PLL divider component identifier
63 * @PLL_COMPID_DIV1: 2nd PLL divider component identifier
65 enum pll_component_id {
72 * PLL type identifiers
73 * @PLL_TYPE_FRAC: fractional PLL identifier
74 * @PLL_TYPE_DIV: divider PLL identifier
81 /* Layout for fractional PLLs. */
82 static const struct clk_pll_layout pll_layout_frac = {
83 .mul_mask = GENMASK(31, 24),
84 .frac_mask = GENMASK(21, 0),
89 /* Layout for DIVPMC dividers. */
90 static const struct clk_pll_layout pll_layout_divpmc = {
91 .div_mask = GENMASK(7, 0),
92 .endiv_mask = BIT(29),
97 /* Layout for DIVIO dividers. */
98 static const struct clk_pll_layout pll_layout_divio = {
99 .div_mask = GENMASK(19, 12),
100 .endiv_mask = BIT(30),
106 * CPU PLL output range.
107 * Notice: The upper limit has been setup to 1000000002 due to hardware
108 * block which cannot output exactly 1GHz.
110 static const struct clk_range cpu_pll_outputs[] = {
111 { .min = 2343750, .max = 1000000002 },
114 /* PLL output range. */
115 static const struct clk_range pll_outputs[] = {
116 { .min = 2343750, .max = 1200000000 },
119 /* CPU PLL characteristics. */
120 static const struct clk_pll_characteristics cpu_pll_characteristics = {
121 .input = { .min = 12000000, .max = 50000000 },
122 .num_output = ARRAY_SIZE(cpu_pll_outputs),
123 .output = cpu_pll_outputs,
126 /* PLL characteristics. */
127 static const struct clk_pll_characteristics pll_characteristics = {
128 .input = { .min = 12000000, .max = 50000000 },
129 .num_output = ARRAY_SIZE(pll_outputs),
130 .output = pll_outputs,
134 * SAMA7G5 PLL possible parents
135 * @SAMA7G5_PLL_PARENT_MAINCK: MAINCK is PLL a parent
136 * @SAMA7G5_PLL_PARENT_MAIN_XTAL: MAIN XTAL is a PLL parent
137 * @SAMA7G5_PLL_PARENT_FRACCK: Frac PLL is a PLL parent (for PLL dividers)
139 enum sama7g5_pll_parent {
140 SAMA7G5_PLL_PARENT_MAINCK,
141 SAMA7G5_PLL_PARENT_MAIN_XTAL,
142 SAMA7G5_PLL_PARENT_FRACCK,
146 * PLL clocks description
149 * @c: clock characteristics
150 * @hw: pointer to clk_hw
154 * @eid: export index in sama7g5->chws[] array
155 * @safe_div: intermediate divider need to be set on PRE_RATE_CHANGE
158 static struct sama7g5_pll {
160 const struct clk_pll_layout *l;
161 const struct clk_pll_characteristics *c;
164 enum sama7g5_pll_parent p;
168 } sama7g5_plls[][PLL_ID_MAX] = {
170 [PLL_COMPID_FRAC] = {
171 .n = "cpupll_fracck",
172 .p = SAMA7G5_PLL_PARENT_MAINCK,
173 .l = &pll_layout_frac,
174 .c = &cpu_pll_characteristics,
177 * This feeds cpupll_divpmcck which feeds CPU. It should
180 .f = CLK_IS_CRITICAL,
183 [PLL_COMPID_DIV0] = {
184 .n = "cpupll_divpmcck",
185 .p = SAMA7G5_PLL_PARENT_FRACCK,
186 .l = &pll_layout_divpmc,
187 .c = &cpu_pll_characteristics,
189 /* This feeds CPU. It should not be disabled. */
190 .f = CLK_IS_CRITICAL | CLK_SET_RATE_PARENT,
193 * Safe div=15 should be safe even for switching b/w 1GHz and
194 * 90MHz (frac pll might go up to 1.2GHz).
201 [PLL_COMPID_FRAC] = {
202 .n = "syspll_fracck",
203 .p = SAMA7G5_PLL_PARENT_MAINCK,
204 .l = &pll_layout_frac,
205 .c = &pll_characteristics,
208 * This feeds syspll_divpmcck which may feed critical parts
209 * of the systems like timers. Therefore it should not be
212 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
215 [PLL_COMPID_DIV0] = {
216 .n = "syspll_divpmcck",
217 .p = SAMA7G5_PLL_PARENT_FRACCK,
218 .l = &pll_layout_divpmc,
219 .c = &pll_characteristics,
222 * This may feed critical parts of the systems like timers.
223 * Therefore it should not be disabled.
225 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
231 [PLL_COMPID_FRAC] = {
232 .n = "ddrpll_fracck",
233 .p = SAMA7G5_PLL_PARENT_MAINCK,
234 .l = &pll_layout_frac,
235 .c = &pll_characteristics,
238 * This feeds ddrpll_divpmcck which feeds DDR. It should not
241 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
244 [PLL_COMPID_DIV0] = {
245 .n = "ddrpll_divpmcck",
246 .p = SAMA7G5_PLL_PARENT_FRACCK,
247 .l = &pll_layout_divpmc,
248 .c = &pll_characteristics,
250 /* This feeds DDR. It should not be disabled. */
251 .f = CLK_IS_CRITICAL | CLK_SET_RATE_GATE,
256 [PLL_COMPID_FRAC] = {
257 .n = "imgpll_fracck",
258 .p = SAMA7G5_PLL_PARENT_MAINCK,
259 .l = &pll_layout_frac,
260 .c = &pll_characteristics,
262 .f = CLK_SET_RATE_GATE,
265 [PLL_COMPID_DIV0] = {
266 .n = "imgpll_divpmcck",
267 .p = SAMA7G5_PLL_PARENT_FRACCK,
268 .l = &pll_layout_divpmc,
269 .c = &pll_characteristics,
271 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
277 [PLL_COMPID_FRAC] = {
278 .n = "baudpll_fracck",
279 .p = SAMA7G5_PLL_PARENT_MAINCK,
280 .l = &pll_layout_frac,
281 .c = &pll_characteristics,
283 .f = CLK_SET_RATE_GATE, },
285 [PLL_COMPID_DIV0] = {
286 .n = "baudpll_divpmcck",
287 .p = SAMA7G5_PLL_PARENT_FRACCK,
288 .l = &pll_layout_divpmc,
289 .c = &pll_characteristics,
291 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
297 [PLL_COMPID_FRAC] = {
298 .n = "audiopll_fracck",
299 .p = SAMA7G5_PLL_PARENT_MAIN_XTAL,
300 .l = &pll_layout_frac,
301 .c = &pll_characteristics,
303 .f = CLK_SET_RATE_GATE,
306 [PLL_COMPID_DIV0] = {
307 .n = "audiopll_divpmcck",
308 .p = SAMA7G5_PLL_PARENT_FRACCK,
309 .l = &pll_layout_divpmc,
310 .c = &pll_characteristics,
312 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
314 .eid = PMC_AUDIOPMCPLL,
317 [PLL_COMPID_DIV1] = {
318 .n = "audiopll_diviock",
319 .p = SAMA7G5_PLL_PARENT_FRACCK,
320 .l = &pll_layout_divio,
321 .c = &pll_characteristics,
323 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
325 .eid = PMC_AUDIOIOPLL,
330 [PLL_COMPID_FRAC] = {
331 .n = "ethpll_fracck",
332 .p = SAMA7G5_PLL_PARENT_MAIN_XTAL,
333 .l = &pll_layout_frac,
334 .c = &pll_characteristics,
336 .f = CLK_SET_RATE_GATE,
339 [PLL_COMPID_DIV0] = {
340 .n = "ethpll_divpmcck",
341 .p = SAMA7G5_PLL_PARENT_FRACCK,
342 .l = &pll_layout_divpmc,
343 .c = &pll_characteristics,
345 .f = CLK_SET_RATE_GATE | CLK_SET_PARENT_GATE |
351 /* Used to create an array entry identifying a PLL by its components. */
352 #define PLL_IDS_TO_ARR_ENTRY(_id, _comp) { PLL_ID_##_id, PLL_COMPID_##_comp}
355 * Master clock (MCK[1..4]) description
357 * @ep: extra parents names array (entry formed by PLL components
358 * identifiers (see enum pll_component_id))
359 * @hw: pointer to clk_hw
360 * @ep_chg_id: index in parents array that specifies the changeable
362 * @ep_count: extra parents count
363 * @ep_mux_table: mux table for extra parents
365 * @eid: export index in sama7g5->chws[] array
366 * @c: true if clock is critical and cannot be disabled
382 { .n = "mck0", }, /* Dummy entry for MCK0 to store hw in probe. */
385 .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), },
386 .ep_mux_table = { 5, },
388 .ep_chg_id = INT_MIN,
394 .ep = { PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), },
395 .ep_mux_table = { 6, },
397 .ep_chg_id = INT_MIN,
402 .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(DDR, DIV0),
403 PLL_IDS_TO_ARR_ENTRY(IMG, DIV0), },
404 .ep_mux_table = { 5, 6, 7, },
410 .ep = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), },
411 .ep_mux_table = { 5, },
413 .ep_chg_id = INT_MIN,
418 * System clock description
422 static const struct {
425 } sama7g5_systemck[] = {
426 { .n = "pck0", .id = 8, },
427 { .n = "pck1", .id = 9, },
428 { .n = "pck2", .id = 10, },
429 { .n = "pck3", .id = 11, },
430 { .n = "pck4", .id = 12, },
431 { .n = "pck5", .id = 13, },
432 { .n = "pck6", .id = 14, },
433 { .n = "pck7", .id = 15, },
436 /* Mux table for programmable clocks. */
437 static u32 sama7g5_prog_mux_table[] = { 0, 1, 2, 5, 6, 7, 8, 9, 10, };
440 * Peripheral clock parent hw identifier (used to index in sama7g5_mckx[])
441 * @PCK_PARENT_HW_MCK0: pck parent hw identifier is MCK0
442 * @PCK_PARENT_HW_MCK1: pck parent hw identifier is MCK1
443 * @PCK_PARENT_HW_MCK2: pck parent hw identifier is MCK2
444 * @PCK_PARENT_HW_MCK3: pck parent hw identifier is MCK3
445 * @PCK_PARENT_HW_MCK4: pck parent hw identifier is MCK4
446 * @PCK_PARENT_HW_MAX: max identifier
448 enum sama7g5_pck_parent_hw_id {
458 * Peripheral clock description
460 * @p: clock parent hw id
461 * @r: clock range values
463 * @chgp: index in parent array of the changeable parent
467 enum sama7g5_pck_parent_hw_id p;
471 } sama7g5_periphck[] = {
472 { .n = "pioA_clk", .p = PCK_PARENT_HW_MCK0, .id = 11, },
473 { .n = "securam_clk", .p = PCK_PARENT_HW_MCK0, .id = 18, },
474 { .n = "sfr_clk", .p = PCK_PARENT_HW_MCK1, .id = 19, },
475 { .n = "hsmc_clk", .p = PCK_PARENT_HW_MCK1, .id = 21, },
476 { .n = "xdmac0_clk", .p = PCK_PARENT_HW_MCK1, .id = 22, },
477 { .n = "xdmac1_clk", .p = PCK_PARENT_HW_MCK1, .id = 23, },
478 { .n = "xdmac2_clk", .p = PCK_PARENT_HW_MCK1, .id = 24, },
479 { .n = "acc_clk", .p = PCK_PARENT_HW_MCK1, .id = 25, },
480 { .n = "aes_clk", .p = PCK_PARENT_HW_MCK1, .id = 27, },
481 { .n = "tzaesbasc_clk", .p = PCK_PARENT_HW_MCK1, .id = 28, },
482 { .n = "asrc_clk", .p = PCK_PARENT_HW_MCK1, .id = 30, .r = { .max = 200000000, }, },
483 { .n = "cpkcc_clk", .p = PCK_PARENT_HW_MCK0, .id = 32, },
484 { .n = "csi_clk", .p = PCK_PARENT_HW_MCK3, .id = 33, .r = { .max = 266000000, }, .chgp = 1, },
485 { .n = "csi2dc_clk", .p = PCK_PARENT_HW_MCK3, .id = 34, .r = { .max = 266000000, }, .chgp = 1, },
486 { .n = "eic_clk", .p = PCK_PARENT_HW_MCK1, .id = 37, },
487 { .n = "flex0_clk", .p = PCK_PARENT_HW_MCK1, .id = 38, },
488 { .n = "flex1_clk", .p = PCK_PARENT_HW_MCK1, .id = 39, },
489 { .n = "flex2_clk", .p = PCK_PARENT_HW_MCK1, .id = 40, },
490 { .n = "flex3_clk", .p = PCK_PARENT_HW_MCK1, .id = 41, },
491 { .n = "flex4_clk", .p = PCK_PARENT_HW_MCK1, .id = 42, },
492 { .n = "flex5_clk", .p = PCK_PARENT_HW_MCK1, .id = 43, },
493 { .n = "flex6_clk", .p = PCK_PARENT_HW_MCK1, .id = 44, },
494 { .n = "flex7_clk", .p = PCK_PARENT_HW_MCK1, .id = 45, },
495 { .n = "flex8_clk", .p = PCK_PARENT_HW_MCK1, .id = 46, },
496 { .n = "flex9_clk", .p = PCK_PARENT_HW_MCK1, .id = 47, },
497 { .n = "flex10_clk", .p = PCK_PARENT_HW_MCK1, .id = 48, },
498 { .n = "flex11_clk", .p = PCK_PARENT_HW_MCK1, .id = 49, },
499 { .n = "gmac0_clk", .p = PCK_PARENT_HW_MCK1, .id = 51, },
500 { .n = "gmac1_clk", .p = PCK_PARENT_HW_MCK1, .id = 52, },
501 { .n = "icm_clk", .p = PCK_PARENT_HW_MCK1, .id = 55, },
502 { .n = "isc_clk", .p = PCK_PARENT_HW_MCK3, .id = 56, .r = { .max = 266000000, }, .chgp = 1, },
503 { .n = "i2smcc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 57, .r = { .max = 200000000, }, },
504 { .n = "i2smcc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 58, .r = { .max = 200000000, }, },
505 { .n = "matrix_clk", .p = PCK_PARENT_HW_MCK1, .id = 60, },
506 { .n = "mcan0_clk", .p = PCK_PARENT_HW_MCK1, .id = 61, .r = { .max = 200000000, }, },
507 { .n = "mcan1_clk", .p = PCK_PARENT_HW_MCK1, .id = 62, .r = { .max = 200000000, }, },
508 { .n = "mcan2_clk", .p = PCK_PARENT_HW_MCK1, .id = 63, .r = { .max = 200000000, }, },
509 { .n = "mcan3_clk", .p = PCK_PARENT_HW_MCK1, .id = 64, .r = { .max = 200000000, }, },
510 { .n = "mcan4_clk", .p = PCK_PARENT_HW_MCK1, .id = 65, .r = { .max = 200000000, }, },
511 { .n = "mcan5_clk", .p = PCK_PARENT_HW_MCK1, .id = 66, .r = { .max = 200000000, }, },
512 { .n = "pdmc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 68, .r = { .max = 200000000, }, },
513 { .n = "pdmc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 69, .r = { .max = 200000000, }, },
514 { .n = "pit64b0_clk", .p = PCK_PARENT_HW_MCK1, .id = 70, },
515 { .n = "pit64b1_clk", .p = PCK_PARENT_HW_MCK1, .id = 71, },
516 { .n = "pit64b2_clk", .p = PCK_PARENT_HW_MCK1, .id = 72, },
517 { .n = "pit64b3_clk", .p = PCK_PARENT_HW_MCK1, .id = 73, },
518 { .n = "pit64b4_clk", .p = PCK_PARENT_HW_MCK1, .id = 74, },
519 { .n = "pit64b5_clk", .p = PCK_PARENT_HW_MCK1, .id = 75, },
520 { .n = "pwm_clk", .p = PCK_PARENT_HW_MCK1, .id = 77, },
521 { .n = "qspi0_clk", .p = PCK_PARENT_HW_MCK1, .id = 78, },
522 { .n = "qspi1_clk", .p = PCK_PARENT_HW_MCK1, .id = 79, },
523 { .n = "sdmmc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 80, },
524 { .n = "sdmmc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 81, },
525 { .n = "sdmmc2_clk", .p = PCK_PARENT_HW_MCK1, .id = 82, },
526 { .n = "sha_clk", .p = PCK_PARENT_HW_MCK1, .id = 83, },
527 { .n = "spdifrx_clk", .p = PCK_PARENT_HW_MCK1, .id = 84, .r = { .max = 200000000, }, },
528 { .n = "spdiftx_clk", .p = PCK_PARENT_HW_MCK1, .id = 85, .r = { .max = 200000000, }, },
529 { .n = "ssc0_clk", .p = PCK_PARENT_HW_MCK1, .id = 86, .r = { .max = 200000000, }, },
530 { .n = "ssc1_clk", .p = PCK_PARENT_HW_MCK1, .id = 87, .r = { .max = 200000000, }, },
531 { .n = "tcb0_ch0_clk", .p = PCK_PARENT_HW_MCK1, .id = 88, .r = { .max = 200000000, }, },
532 { .n = "tcb0_ch1_clk", .p = PCK_PARENT_HW_MCK1, .id = 89, .r = { .max = 200000000, }, },
533 { .n = "tcb0_ch2_clk", .p = PCK_PARENT_HW_MCK1, .id = 90, .r = { .max = 200000000, }, },
534 { .n = "tcb1_ch0_clk", .p = PCK_PARENT_HW_MCK1, .id = 91, .r = { .max = 200000000, }, },
535 { .n = "tcb1_ch1_clk", .p = PCK_PARENT_HW_MCK1, .id = 92, .r = { .max = 200000000, }, },
536 { .n = "tcb1_ch2_clk", .p = PCK_PARENT_HW_MCK1, .id = 93, .r = { .max = 200000000, }, },
537 { .n = "tcpca_clk", .p = PCK_PARENT_HW_MCK1, .id = 94, },
538 { .n = "tcpcb_clk", .p = PCK_PARENT_HW_MCK1, .id = 95, },
539 { .n = "tdes_clk", .p = PCK_PARENT_HW_MCK1, .id = 96, },
540 { .n = "trng_clk", .p = PCK_PARENT_HW_MCK1, .id = 97, },
541 { .n = "udphsa_clk", .p = PCK_PARENT_HW_MCK1, .id = 104, },
542 { .n = "udphsb_clk", .p = PCK_PARENT_HW_MCK1, .id = 105, },
543 { .n = "uhphs_clk", .p = PCK_PARENT_HW_MCK1, .id = 106, },
547 * Generic clock description
549 * @pp: PLL parents (entry formed by PLL components identifiers
550 * (see enum pll_component_id))
551 * @pp_mux_table: PLL parents mux table
552 * @r: clock output range
553 * @pp_chg_id: id in parent array of changeable PLL parent
554 * @pp_count: PLL parents count
557 static const struct {
563 const char pp_mux_table[8];
571 .r = { .max = 100000000, },
572 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
573 PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
574 .pp_mux_table = { 5, 7, 9, },
576 .pp_chg_id = INT_MIN, },
580 .r = { .max = 200000000 },
581 .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
582 .pp_mux_table = { 9, },
588 .r = { .max = 27000000 },
589 .pp = { PLL_IDS_TO_ARR_ENTRY(DDR, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0), },
590 .pp_mux_table = { 6, 7, },
592 .pp_chg_id = INT_MIN, },
596 .r = { .max = 200000000 },
597 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
598 .pp_mux_table = { 5, 8, },
600 .pp_chg_id = INT_MIN, },
604 .r = { .max = 200000000 },
605 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
606 .pp_mux_table = { 5, 8, },
608 .pp_chg_id = INT_MIN, },
612 .r = { .max = 200000000 },
613 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
614 .pp_mux_table = { 5, 8, },
616 .pp_chg_id = INT_MIN, },
620 .r = { .max = 200000000 },
621 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
622 .pp_mux_table = { 5, 8, },
624 .pp_chg_id = INT_MIN, },
628 .r = { .max = 200000000 },
629 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
630 .pp_mux_table = { 5, 8, },
632 .pp_chg_id = INT_MIN, },
636 .r = { .max = 200000000 },
637 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
638 .pp_mux_table = { 5, 8, },
640 .pp_chg_id = INT_MIN, },
644 .r = { .max = 200000000 },
645 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
646 .pp_mux_table = { 5, 8, },
648 .pp_chg_id = INT_MIN, },
652 .r = { .max = 200000000 },
653 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
654 .pp_mux_table = { 5, 8, },
656 .pp_chg_id = INT_MIN, },
660 .r = { .max = 200000000 },
661 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
662 .pp_mux_table = { 5, 8, },
664 .pp_chg_id = INT_MIN, },
668 .r = { .max = 200000000 },
669 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
670 .pp_mux_table = { 5, 8, },
672 .pp_chg_id = INT_MIN, },
674 { .n = "flex10_gclk",
676 .r = { .max = 200000000 },
677 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
678 .pp_mux_table = { 5, 8, },
680 .pp_chg_id = INT_MIN, },
682 { .n = "flex11_gclk",
684 .r = { .max = 200000000 },
685 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
686 .pp_mux_table = { 5, 8, },
688 .pp_chg_id = INT_MIN, },
692 .r = { .max = 125000000 },
693 .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
694 .pp_mux_table = { 10, },
700 .r = { .max = 50000000 },
701 .pp = { PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
702 .pp_mux_table = { 10, },
704 .pp_chg_id = INT_MIN, },
706 { .n = "gmac0_tsu_gclk",
708 .r = { .max = 300000000 },
709 .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
710 .pp_mux_table = { 9, 10, },
712 .pp_chg_id = INT_MIN, },
714 { .n = "gmac1_tsu_gclk",
716 .r = { .max = 300000000 },
717 .pp = { PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
718 .pp_mux_table = { 9, 10, },
720 .pp_chg_id = INT_MIN, },
722 { .n = "i2smcc0_gclk",
724 .r = { .max = 100000000 },
725 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
726 .pp_mux_table = { 5, 9, },
730 { .n = "i2smcc1_gclk",
732 .r = { .max = 100000000 },
733 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
734 .pp_mux_table = { 5, 9, },
740 .r = { .max = 200000000 },
741 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
742 .pp_mux_table = { 5, 8, },
744 .pp_chg_id = INT_MIN, },
748 .r = { .max = 200000000 },
749 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
750 .pp_mux_table = { 5, 8, },
752 .pp_chg_id = INT_MIN, },
756 .r = { .max = 200000000 },
757 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
758 .pp_mux_table = { 5, 8, },
760 .pp_chg_id = INT_MIN, },
764 .r = { .max = 200000000 },
765 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
766 .pp_mux_table = { 5, 8, },
768 .pp_chg_id = INT_MIN, },
772 .r = { .max = 200000000 },
773 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
774 .pp_mux_table = { 5, 8, },
776 .pp_chg_id = INT_MIN, },
780 .r = { .max = 200000000 },
781 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
782 .pp_mux_table = { 5, 8, },
784 .pp_chg_id = INT_MIN, },
788 .r = { .max = 50000000 },
789 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
790 .pp_mux_table = { 5, 9, },
792 .pp_chg_id = INT_MIN, },
796 .r = { .max = 50000000, },
797 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
798 .pp_mux_table = { 5, 9, },
800 .pp_chg_id = INT_MIN, },
802 { .n = "pit64b0_gclk",
804 .r = { .max = 200000000 },
805 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
806 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
807 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
808 .pp_mux_table = { 5, 7, 8, 9, 10, },
810 .pp_chg_id = INT_MIN, },
812 { .n = "pit64b1_gclk",
814 .r = { .max = 200000000 },
815 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
816 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
817 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
818 .pp_mux_table = { 5, 7, 8, 9, 10, },
820 .pp_chg_id = INT_MIN, },
822 { .n = "pit64b2_gclk",
824 .r = { .max = 200000000 },
825 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
826 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
827 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
828 .pp_mux_table = { 5, 7, 8, 9, 10, },
830 .pp_chg_id = INT_MIN, },
832 { .n = "pit64b3_gclk",
834 .r = { .max = 200000000 },
835 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
836 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
837 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
838 .pp_mux_table = { 5, 7, 8, 9, 10, },
840 .pp_chg_id = INT_MIN, },
842 { .n = "pit64b4_gclk",
844 .r = { .max = 200000000 },
845 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
846 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
847 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
848 .pp_mux_table = { 5, 7, 8, 9, 10, },
850 .pp_chg_id = INT_MIN, },
852 { .n = "pit64b5_gclk",
854 .r = { .max = 200000000 },
855 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
856 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
857 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
858 .pp_mux_table = { 5, 7, 8, 9, 10, },
860 .pp_chg_id = INT_MIN, },
864 .r = { .max = 200000000 },
865 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
866 .pp_mux_table = { 5, 8, },
868 .pp_chg_id = INT_MIN, },
872 .r = { .max = 200000000 },
873 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
874 .pp_mux_table = { 5, 8, },
876 .pp_chg_id = INT_MIN, },
878 { .n = "sdmmc0_gclk",
880 .r = { .max = 208000000 },
881 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
882 .pp_mux_table = { 5, 8, },
886 { .n = "sdmmc1_gclk",
888 .r = { .max = 208000000 },
889 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
890 .pp_mux_table = { 5, 8, },
894 { .n = "sdmmc2_gclk",
896 .r = { .max = 208000000 },
897 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), },
898 .pp_mux_table = { 5, 8, },
902 { .n = "spdifrx_gclk",
904 .r = { .max = 150000000 },
905 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
906 .pp_mux_table = { 5, 9, },
910 { .n = "spdiftx_gclk",
912 .r = { .max = 25000000 },
913 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0), },
914 .pp_mux_table = { 5, 9, },
918 { .n = "tcb0_ch0_gclk",
920 .r = { .max = 200000000 },
921 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
922 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
923 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
924 .pp_mux_table = { 5, 7, 8, 9, 10, },
926 .pp_chg_id = INT_MIN, },
928 { .n = "tcb1_ch0_gclk",
930 .r = { .max = 200000000 },
931 .pp = { PLL_IDS_TO_ARR_ENTRY(SYS, DIV0), PLL_IDS_TO_ARR_ENTRY(IMG, DIV0),
932 PLL_IDS_TO_ARR_ENTRY(BAUD, DIV0), PLL_IDS_TO_ARR_ENTRY(AUDIO, DIV0),
933 PLL_IDS_TO_ARR_ENTRY(ETH, DIV0), },
934 .pp_mux_table = { 5, 7, 8, 9, 10, },
936 .pp_chg_id = INT_MIN, },
940 .r = { .max = 32768, },
941 .pp_chg_id = INT_MIN, },
945 .r = { .max = 32768, },
946 .pp_chg_id = INT_MIN, },
949 /* MCK0 characteristics. */
950 static const struct clk_master_characteristics mck0_characteristics = {
951 .output = { .min = 32768, .max = 200000000 },
952 .divisors = { 1, 2, 4, 3, 5 },
957 static const struct clk_master_layout mck0_layout = {
963 /* Programmable clock layout. */
964 static const struct clk_programmable_layout programmable_layout = {
972 /* Peripheral clock layout. */
973 static const struct clk_pcr_layout sama7g5_pcr_layout = {
976 .gckcss_mask = GENMASK(12, 8),
977 .pid_mask = GENMASK(6, 0),
980 static void __init sama7g5_pmc_setup(struct device_node *np)
982 const char *main_xtal_name = "main_xtal";
983 struct pmc_data *sama7g5_pmc;
984 void **alloc_mem = NULL;
985 int alloc_mem_size = 0;
986 struct regmap *regmap;
987 struct clk_hw *hw, *main_rc_hw, *main_osc_hw, *main_xtal_hw;
988 struct clk_hw *td_slck_hw, *md_slck_hw;
989 static struct clk_parent_data parent_data;
990 struct clk_hw *parent_hws[10];
994 td_slck_hw = __clk_get_hw(of_clk_get_by_name(np, "td_slck"));
995 md_slck_hw = __clk_get_hw(of_clk_get_by_name(np, "md_slck"));
996 main_xtal_hw = __clk_get_hw(of_clk_get_by_name(np, main_xtal_name));
998 if (!td_slck_hw || !md_slck_hw || !main_xtal_hw)
1001 regmap = device_node_to_regmap(np);
1005 sama7g5_pmc = pmc_data_allocate(PMC_MCK1 + 1,
1006 nck(sama7g5_systemck),
1007 nck(sama7g5_periphck),
1008 nck(sama7g5_gck), 8);
1012 alloc_mem = kmalloc(sizeof(void *) *
1013 (ARRAY_SIZE(sama7g5_mckx) + ARRAY_SIZE(sama7g5_gck)),
1018 main_rc_hw = at91_clk_register_main_rc_osc(regmap, "main_rc_osc", 12000000,
1020 if (IS_ERR(main_rc_hw))
1023 bypass = of_property_read_bool(np, "atmel,osc-bypass");
1025 parent_data.name = main_xtal_name;
1026 parent_data.fw_name = main_xtal_name;
1027 main_osc_hw = at91_clk_register_main_osc(regmap, "main_osc", NULL,
1028 &parent_data, bypass);
1029 if (IS_ERR(main_osc_hw))
1032 parent_hws[0] = main_rc_hw;
1033 parent_hws[1] = main_osc_hw;
1034 hw = at91_clk_register_sam9x5_main(regmap, "mainck", NULL, parent_hws, 2);
1038 sama7g5_pmc->chws[PMC_MAIN] = hw;
1040 for (i = 0; i < PLL_ID_MAX; i++) {
1041 for (j = 0; j < 3; j++) {
1042 struct clk_hw *parent_hw;
1044 if (!sama7g5_plls[i][j].n)
1047 switch (sama7g5_plls[i][j].t) {
1049 switch (sama7g5_plls[i][j].p) {
1050 case SAMA7G5_PLL_PARENT_MAINCK:
1051 parent_hw = sama7g5_pmc->chws[PMC_MAIN];
1053 case SAMA7G5_PLL_PARENT_MAIN_XTAL:
1054 parent_hw = main_xtal_hw;
1057 /* Should not happen. */
1062 hw = sam9x60_clk_register_frac_pll(regmap,
1063 &pmc_pll_lock, sama7g5_plls[i][j].n,
1065 sama7g5_plls[i][j].c,
1066 sama7g5_plls[i][j].l,
1067 sama7g5_plls[i][j].f);
1071 hw = sam9x60_clk_register_div_pll(regmap,
1072 &pmc_pll_lock, sama7g5_plls[i][j].n,
1073 NULL, sama7g5_plls[i][0].hw, i,
1074 sama7g5_plls[i][j].c,
1075 sama7g5_plls[i][j].l,
1076 sama7g5_plls[i][j].f,
1077 sama7g5_plls[i][j].safe_div);
1087 sama7g5_plls[i][j].hw = hw;
1088 if (sama7g5_plls[i][j].eid)
1089 sama7g5_pmc->chws[sama7g5_plls[i][j].eid] = hw;
1093 hw = at91_clk_register_master_div(regmap, "mck0", NULL,
1094 sama7g5_plls[PLL_ID_CPU][1].hw,
1095 &mck0_layout, &mck0_characteristics,
1096 &pmc_mck0_lock, CLK_GET_RATE_NOCACHE, 5);
1100 sama7g5_mckx[PCK_PARENT_HW_MCK0].hw = sama7g5_pmc->chws[PMC_MCK] = hw;
1102 parent_hws[0] = md_slck_hw;
1103 parent_hws[1] = td_slck_hw;
1104 parent_hws[2] = sama7g5_pmc->chws[PMC_MAIN];
1105 for (i = PCK_PARENT_HW_MCK1; i < ARRAY_SIZE(sama7g5_mckx); i++) {
1106 u8 num_parents = 3 + sama7g5_mckx[i].ep_count;
1107 struct clk_hw *tmp_parent_hws[8];
1110 mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
1115 SAMA7G5_INIT_TABLE(mux_table, 3);
1116 SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_mckx[i].ep_mux_table,
1117 sama7g5_mckx[i].ep_count);
1118 for (j = 0; j < sama7g5_mckx[i].ep_count; j++) {
1119 u8 pll_id = sama7g5_mckx[i].ep[j].pll_id;
1120 u8 pll_compid = sama7g5_mckx[i].ep[j].pll_compid;
1122 tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw;
1124 SAMA7G5_FILL_TABLE(&parent_hws[3], tmp_parent_hws,
1125 sama7g5_mckx[i].ep_count);
1127 hw = at91_clk_sama7g5_register_master(regmap, sama7g5_mckx[i].n,
1128 num_parents, NULL, parent_hws, mux_table,
1129 &pmc_mckX_lock, sama7g5_mckx[i].id,
1131 sama7g5_mckx[i].ep_chg_id);
1135 alloc_mem[alloc_mem_size++] = mux_table;
1137 sama7g5_mckx[i].hw = hw;
1138 if (sama7g5_mckx[i].eid)
1139 sama7g5_pmc->chws[sama7g5_mckx[i].eid] = hw;
1142 hw = at91_clk_sama7g5_register_utmi(regmap, "utmick", NULL, main_xtal_hw);
1146 sama7g5_pmc->chws[PMC_UTMI] = hw;
1148 parent_hws[0] = md_slck_hw;
1149 parent_hws[1] = td_slck_hw;
1150 parent_hws[2] = sama7g5_pmc->chws[PMC_MAIN];
1151 parent_hws[3] = sama7g5_plls[PLL_ID_SYS][PLL_COMPID_DIV0].hw;
1152 parent_hws[4] = sama7g5_plls[PLL_ID_DDR][PLL_COMPID_DIV0].hw;
1153 parent_hws[5] = sama7g5_plls[PLL_ID_IMG][PLL_COMPID_DIV0].hw;
1154 parent_hws[6] = sama7g5_plls[PLL_ID_BAUD][PLL_COMPID_DIV0].hw;
1155 parent_hws[7] = sama7g5_plls[PLL_ID_AUDIO][PLL_COMPID_DIV0].hw;
1156 parent_hws[8] = sama7g5_plls[PLL_ID_ETH][PLL_COMPID_DIV0].hw;
1157 for (i = 0; i < 8; i++) {
1160 snprintf(name, sizeof(name), "prog%d", i);
1162 hw = at91_clk_register_programmable(regmap, name, NULL, parent_hws,
1164 &programmable_layout,
1165 sama7g5_prog_mux_table);
1169 sama7g5_pmc->pchws[i] = hw;
1172 for (i = 0; i < ARRAY_SIZE(sama7g5_systemck); i++) {
1173 hw = at91_clk_register_system(regmap, sama7g5_systemck[i].n,
1174 NULL, sama7g5_pmc->pchws[i],
1175 sama7g5_systemck[i].id, 0);
1179 sama7g5_pmc->shws[sama7g5_systemck[i].id] = hw;
1182 for (i = 0; i < ARRAY_SIZE(sama7g5_periphck); i++) {
1183 hw = at91_clk_register_sam9x5_peripheral(regmap, &pmc_pcr_lock,
1184 &sama7g5_pcr_layout,
1185 sama7g5_periphck[i].n,
1187 sama7g5_mckx[sama7g5_periphck[i].p].hw,
1188 sama7g5_periphck[i].id,
1189 &sama7g5_periphck[i].r,
1190 sama7g5_periphck[i].chgp ? 0 :
1195 sama7g5_pmc->phws[sama7g5_periphck[i].id] = hw;
1198 parent_hws[0] = md_slck_hw;
1199 parent_hws[1] = td_slck_hw;
1200 parent_hws[2] = sama7g5_pmc->chws[PMC_MAIN];
1201 for (i = 0; i < ARRAY_SIZE(sama7g5_gck); i++) {
1202 u8 num_parents = 3 + sama7g5_gck[i].pp_count;
1203 struct clk_hw *tmp_parent_hws[8];
1206 mux_table = kmalloc_array(num_parents, sizeof(*mux_table),
1211 SAMA7G5_INIT_TABLE(mux_table, 3);
1212 SAMA7G5_FILL_TABLE(&mux_table[3], sama7g5_gck[i].pp_mux_table,
1213 sama7g5_gck[i].pp_count);
1214 for (j = 0; j < sama7g5_gck[i].pp_count; j++) {
1215 u8 pll_id = sama7g5_gck[i].pp[j].pll_id;
1216 u8 pll_compid = sama7g5_gck[i].pp[j].pll_compid;
1218 tmp_parent_hws[j] = sama7g5_plls[pll_id][pll_compid].hw;
1220 SAMA7G5_FILL_TABLE(&parent_hws[3], tmp_parent_hws,
1221 sama7g5_gck[i].pp_count);
1223 hw = at91_clk_register_generated(regmap, &pmc_pcr_lock,
1224 &sama7g5_pcr_layout,
1225 sama7g5_gck[i].n, NULL,
1226 parent_hws, mux_table,
1230 sama7g5_gck[i].pp_chg_id);
1234 sama7g5_pmc->ghws[sama7g5_gck[i].id] = hw;
1235 alloc_mem[alloc_mem_size++] = mux_table;
1238 of_clk_add_hw_provider(np, of_clk_hw_pmc_get, sama7g5_pmc);
1244 for (i = 0; i < alloc_mem_size; i++)
1245 kfree(alloc_mem[i]);
1252 /* Some clks are used for a clocksource */
1253 CLK_OF_DECLARE(sama7g5_pmc, "microchip,sama7g5-pmc", sama7g5_pmc_setup);