1 // SPDX-License-Identifier: (GPL-2.0-only OR MIT)
2 /*
3 * Amlogic S4 PLL Clock Controller Driver
4 *
5 * Copyright (c) 2022-2023 Amlogic, inc. All rights reserved
6 * Author: Yu Tu <yu.tu@amlogic.com>
7 */
8
9 #include <linux/clk-provider.h>
10 #include <linux/of_device.h>
11 #include <linux/platform_device.h>
12
13 #include "clk-mpll.h"
14 #include "clk-pll.h"
15 #include "clk-regmap.h"
16 #include "s4-pll.h"
17 #include "meson-clkc-utils.h"
18 #include <dt-bindings/clock/amlogic,s4-pll-clkc.h>
19
20 /*
21 * These clock are a fixed value (fixed_pll is 2GHz) that is initialized by ROMcode.
22 * The chip was changed fixed pll for security reasons. Fixed PLL registers are not writable
23 * in the kernel phase. Write of fixed PLL-related register will cause the system to crash.
24 * Meanwhile, these clock won't ever change at runtime.
25 * For the above reasons, we can only use ro_ops for fixed PLL related clocks.
26 */
27 static struct clk_regmap s4_fixed_pll_dco = {
28 .data = &(struct meson_clk_pll_data){
29 .en = {
30 .reg_off = ANACTRL_FIXPLL_CTRL0,
31 .shift = 28,
32 .width = 1,
33 },
34 .m = {
35 .reg_off = ANACTRL_FIXPLL_CTRL0,
36 .shift = 0,
37 .width = 8,
38 },
39 .frac = {
40 .reg_off = ANACTRL_FIXPLL_CTRL1,
41 .shift = 0,
42 .width = 17,
43 },
44 .n = {
45 .reg_off = ANACTRL_FIXPLL_CTRL0,
46 .shift = 10,
47 .width = 5,
48 },
49 .l = {
50 .reg_off = ANACTRL_FIXPLL_CTRL0,
51 .shift = 31,
52 .width = 1,
53 },
54 .rst = {
55 .reg_off = ANACTRL_FIXPLL_CTRL0,
56 .shift = 29,
57 .width = 1,
58 },
59 },
60 .hw.init = &(struct clk_init_data){
61 .name = "fixed_pll_dco",
62 .ops = &meson_clk_pll_ro_ops,
63 .parent_data = (const struct clk_parent_data []) {
64 { .fw_name = "xtal", }
65 },
66 .num_parents = 1,
67 },
68 };
69
70 static struct clk_regmap s4_fixed_pll = {
71 .data = &(struct clk_regmap_div_data){
72 .offset = ANACTRL_FIXPLL_CTRL0,
73 .shift = 16,
74 .width = 2,
75 .flags = CLK_DIVIDER_POWER_OF_TWO,
76 },
77 .hw.init = &(struct clk_init_data){
78 .name = "fixed_pll",
79 .ops = &clk_regmap_divider_ro_ops,
80 .parent_hws = (const struct clk_hw *[]) {
81 &s4_fixed_pll_dco.hw
82 },
83 .num_parents = 1,
84 /*
85 * This clock won't ever change at runtime so
86 * CLK_SET_RATE_PARENT is not required
87 */
88 },
89 };
90
91 static struct clk_fixed_factor s4_fclk_div2_div = {
92 .mult = 1,
93 .div = 2,
94 .hw.init = &(struct clk_init_data){
95 .name = "fclk_div2_div",
96 .ops = &clk_fixed_factor_ops,
97 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
98 .num_parents = 1,
99 },
100 };
101
102 static struct clk_regmap s4_fclk_div2 = {
103 .data = &(struct clk_regmap_gate_data){
104 .offset = ANACTRL_FIXPLL_CTRL1,
105 .bit_idx = 24,
106 },
107 .hw.init = &(struct clk_init_data){
108 .name = "fclk_div2",
109 .ops = &clk_regmap_gate_ro_ops,
110 .parent_hws = (const struct clk_hw *[]) {
111 &s4_fclk_div2_div.hw
112 },
113 .num_parents = 1,
114 },
115 };
116
117 static struct clk_fixed_factor s4_fclk_div3_div = {
118 .mult = 1,
119 .div = 3,
120 .hw.init = &(struct clk_init_data){
121 .name = "fclk_div3_div",
122 .ops = &clk_fixed_factor_ops,
123 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
124 .num_parents = 1,
125 },
126 };
127
128 static struct clk_regmap s4_fclk_div3 = {
129 .data = &(struct clk_regmap_gate_data){
130 .offset = ANACTRL_FIXPLL_CTRL1,
131 .bit_idx = 20,
132 },
133 .hw.init = &(struct clk_init_data){
134 .name = "fclk_div3",
135 .ops = &clk_regmap_gate_ro_ops,
136 .parent_hws = (const struct clk_hw *[]) {
137 &s4_fclk_div3_div.hw
138 },
139 .num_parents = 1,
140 },
141 };
142
143 static struct clk_fixed_factor s4_fclk_div4_div = {
144 .mult = 1,
145 .div = 4,
146 .hw.init = &(struct clk_init_data){
147 .name = "fclk_div4_div",
148 .ops = &clk_fixed_factor_ops,
149 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
150 .num_parents = 1,
151 },
152 };
153
154 static struct clk_regmap s4_fclk_div4 = {
155 .data = &(struct clk_regmap_gate_data){
156 .offset = ANACTRL_FIXPLL_CTRL1,
157 .bit_idx = 21,
158 },
159 .hw.init = &(struct clk_init_data){
160 .name = "fclk_div4",
161 .ops = &clk_regmap_gate_ro_ops,
162 .parent_hws = (const struct clk_hw *[]) {
163 &s4_fclk_div4_div.hw
164 },
165 .num_parents = 1,
166 },
167 };
168
169 static struct clk_fixed_factor s4_fclk_div5_div = {
170 .mult = 1,
171 .div = 5,
172 .hw.init = &(struct clk_init_data){
173 .name = "fclk_div5_div",
174 .ops = &clk_fixed_factor_ops,
175 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
176 .num_parents = 1,
177 },
178 };
179
180 static struct clk_regmap s4_fclk_div5 = {
181 .data = &(struct clk_regmap_gate_data){
182 .offset = ANACTRL_FIXPLL_CTRL1,
183 .bit_idx = 22,
184 },
185 .hw.init = &(struct clk_init_data){
186 .name = "fclk_div5",
187 .ops = &clk_regmap_gate_ro_ops,
188 .parent_hws = (const struct clk_hw *[]) {
189 &s4_fclk_div5_div.hw
190 },
191 .num_parents = 1,
192 },
193 };
194
195 static struct clk_fixed_factor s4_fclk_div7_div = {
196 .mult = 1,
197 .div = 7,
198 .hw.init = &(struct clk_init_data){
199 .name = "fclk_div7_div",
200 .ops = &clk_fixed_factor_ops,
201 .parent_hws = (const struct clk_hw *[]) { &s4_fixed_pll.hw },
202 .num_parents = 1,
203 },
204 };
205
206 static struct clk_regmap s4_fclk_div7 = {
207 .data = &(struct clk_regmap_gate_data){
208 .offset = ANACTRL_FIXPLL_CTRL1,
209 .bit_idx = 23,
210 },
211 .hw.init = &(struct clk_init_data){
212 .name = "fclk_div7",
213 .ops = &clk_regmap_gate_ro_ops,
214 .parent_hws = (const struct clk_hw *[]) {
215 &s4_fclk_div7_div.hw
216 },
217 .num_parents = 1,
218 },
219 };
220
221 static struct clk_fixed_factor s4_fclk_div2p5_div = {
222 .mult = 2,
223 .div = 5,
224 .hw.init = &(struct clk_init_data){
225 .name = "fclk_div2p5_div",
226 .ops = &clk_fixed_factor_ops,
227 .parent_hws = (const struct clk_hw *[]) {
228 &s4_fixed_pll.hw
229 },
230 .num_parents = 1,
231 },
232 };
233
234 static struct clk_regmap s4_fclk_div2p5 = {
235 .data = &(struct clk_regmap_gate_data){
236 .offset = ANACTRL_FIXPLL_CTRL1,
237 .bit_idx = 25,
238 },
239 .hw.init = &(struct clk_init_data){
240 .name = "fclk_div2p5",
241 .ops = &clk_regmap_gate_ro_ops,
242 .parent_hws = (const struct clk_hw *[]) {
243 &s4_fclk_div2p5_div.hw
244 },
245 .num_parents = 1,
246 },
247 };
248
249 static const struct pll_mult_range s4_gp0_pll_mult_range = {
250 .min = 125,
251 .max = 250,
252 };
253
254 /*
255 * Internal gp0 pll emulation configuration parameters
256 */
257 static const struct reg_sequence s4_gp0_init_regs[] = {
258 { .reg = ANACTRL_GP0PLL_CTRL1, .def = 0x00000000 },
259 { .reg = ANACTRL_GP0PLL_CTRL2, .def = 0x00000000 },
260 { .reg = ANACTRL_GP0PLL_CTRL3, .def = 0x48681c00 },
261 { .reg = ANACTRL_GP0PLL_CTRL4, .def = 0x88770290 },
262 { .reg = ANACTRL_GP0PLL_CTRL5, .def = 0x39272000 },
263 { .reg = ANACTRL_GP0PLL_CTRL6, .def = 0x56540000 }
264 };
265
266 static struct clk_regmap s4_gp0_pll_dco = {
267 .data = &(struct meson_clk_pll_data){
268 .en = {
269 .reg_off = ANACTRL_GP0PLL_CTRL0,
270 .shift = 28,
271 .width = 1,
272 },
273 .m = {
274 .reg_off = ANACTRL_GP0PLL_CTRL0,
275 .shift = 0,
276 .width = 8,
277 },
278 .n = {
279 .reg_off = ANACTRL_GP0PLL_CTRL0,
280 .shift = 10,
281 .width = 5,
282 },
283 .l = {
284 .reg_off = ANACTRL_GP0PLL_CTRL0,
285 .shift = 31,
286 .width = 1,
287 },
288 .rst = {
289 .reg_off = ANACTRL_GP0PLL_CTRL0,
290 .shift = 29,
291 .width = 1,
292 },
293 .range = &s4_gp0_pll_mult_range,
294 .init_regs = s4_gp0_init_regs,
295 .init_count = ARRAY_SIZE(s4_gp0_init_regs),
296 },
297 .hw.init = &(struct clk_init_data){
298 .name = "gp0_pll_dco",
299 .ops = &meson_clk_pll_ops,
300 .parent_data = (const struct clk_parent_data []) {
301 { .fw_name = "xtal", }
302 },
303 .num_parents = 1,
304 },
305 };
306
307 static struct clk_regmap s4_gp0_pll = {
308 .data = &(struct clk_regmap_div_data){
309 .offset = ANACTRL_GP0PLL_CTRL0,
310 .shift = 16,
311 .width = 3,
312 .flags = (CLK_DIVIDER_POWER_OF_TWO |
313 CLK_DIVIDER_ROUND_CLOSEST),
314 },
315 .hw.init = &(struct clk_init_data){
316 .name = "gp0_pll",
317 .ops = &clk_regmap_divider_ops,
318 .parent_hws = (const struct clk_hw *[]) {
319 &s4_gp0_pll_dco.hw
320 },
321 .num_parents = 1,
322 .flags = CLK_SET_RATE_PARENT,
323 },
324 };
325
326 /*
327 * Internal hifi pll emulation configuration parameters
328 */
329 static const struct reg_sequence s4_hifi_init_regs[] = {
330 { .reg = ANACTRL_HIFIPLL_CTRL2, .def = 0x00000000 },
331 { .reg = ANACTRL_HIFIPLL_CTRL3, .def = 0x6a285c00 },
332 { .reg = ANACTRL_HIFIPLL_CTRL4, .def = 0x65771290 },
333 { .reg = ANACTRL_HIFIPLL_CTRL5, .def = 0x39272000 },
334 { .reg = ANACTRL_HIFIPLL_CTRL6, .def = 0x56540000 }
335 };
336
337 static struct clk_regmap s4_hifi_pll_dco = {
338 .data = &(struct meson_clk_pll_data){
339 .en = {
340 .reg_off = ANACTRL_HIFIPLL_CTRL0,
341 .shift = 28,
342 .width = 1,
343 },
344 .m = {
345 .reg_off = ANACTRL_HIFIPLL_CTRL0,
346 .shift = 0,
347 .width = 8,
348 },
349 .n = {
350 .reg_off = ANACTRL_HIFIPLL_CTRL0,
351 .shift = 10,
352 .width = 5,
353 },
354 .frac = {
355 .reg_off = ANACTRL_HIFIPLL_CTRL1,
356 .shift = 0,
357 .width = 17,
358 },
359 .l = {
360 .reg_off = ANACTRL_HIFIPLL_CTRL0,
361 .shift = 31,
362 .width = 1,
363 },
364 .rst = {
365 .reg_off = ANACTRL_HIFIPLL_CTRL0,
366 .shift = 29,
367 .width = 1,
368 },
369 .range = &s4_gp0_pll_mult_range,
370 .init_regs = s4_hifi_init_regs,
371 .init_count = ARRAY_SIZE(s4_hifi_init_regs),
372 .frac_max = 100000,
373 .flags = CLK_MESON_PLL_ROUND_CLOSEST,
374 },
375 .hw.init = &(struct clk_init_data){
376 .name = "hifi_pll_dco",
377 .ops = &meson_clk_pll_ops,
378 .parent_data = (const struct clk_parent_data []) {
379 { .fw_name = "xtal", }
380 },
381 .num_parents = 1,
382 },
383 };
384
385 static struct clk_regmap s4_hifi_pll = {
386 .data = &(struct clk_regmap_div_data){
387 .offset = ANACTRL_HIFIPLL_CTRL0,
388 .shift = 16,
389 .width = 2,
390 .flags = (CLK_DIVIDER_POWER_OF_TWO |
391 CLK_DIVIDER_ROUND_CLOSEST),
392 },
393 .hw.init = &(struct clk_init_data){
394 .name = "hifi_pll",
395 .ops = &clk_regmap_divider_ops,
396 .parent_hws = (const struct clk_hw *[]) {
397 &s4_hifi_pll_dco.hw
398 },
399 .num_parents = 1,
400 .flags = CLK_SET_RATE_PARENT,
401 },
402 };
403
404 static struct clk_regmap s4_hdmi_pll_dco = {
405 .data = &(struct meson_clk_pll_data){
406 .en = {
407 .reg_off = ANACTRL_HDMIPLL_CTRL0,
408 .shift = 28,
409 .width = 1,
410 },
411 .m = {
412 .reg_off = ANACTRL_HDMIPLL_CTRL0,
413 .shift = 0,
414 .width = 8,
415 },
416 .n = {
417 .reg_off = ANACTRL_HDMIPLL_CTRL0,
418 .shift = 10,
419 .width = 5,
420 },
421 .l = {
422 .reg_off = ANACTRL_HDMIPLL_CTRL0,
423 .shift = 31,
424 .width = 1,
425 },
426 .rst = {
427 .reg_off = ANACTRL_HDMIPLL_CTRL0,
428 .shift = 29,
429 .width = 1,
430 },
431 .range = &s4_gp0_pll_mult_range,
432 },
433 .hw.init = &(struct clk_init_data){
434 .name = "hdmi_pll_dco",
435 .ops = &meson_clk_pll_ops,
436 .parent_data = (const struct clk_parent_data []) {
437 { .fw_name = "xtal", }
438 },
439 .num_parents = 1,
440 },
441 };
442
443 static struct clk_regmap s4_hdmi_pll_od = {
444 .data = &(struct clk_regmap_div_data){
445 .offset = ANACTRL_HDMIPLL_CTRL0,
446 .shift = 16,
447 .width = 4,
448 .flags = CLK_DIVIDER_POWER_OF_TWO,
449 },
450 .hw.init = &(struct clk_init_data){
451 .name = "hdmi_pll_od",
452 .ops = &clk_regmap_divider_ops,
453 .parent_hws = (const struct clk_hw *[]) {
454 &s4_hdmi_pll_dco.hw
455 },
456 .num_parents = 1,
457 .flags = CLK_SET_RATE_PARENT,
458 },
459 };
460
461 static struct clk_regmap s4_hdmi_pll = {
462 .data = &(struct clk_regmap_div_data){
463 .offset = ANACTRL_HDMIPLL_CTRL0,
464 .shift = 20,
465 .width = 2,
466 .flags = CLK_DIVIDER_POWER_OF_TWO,
467 },
468 .hw.init = &(struct clk_init_data){
469 .name = "hdmi_pll",
470 .ops = &clk_regmap_divider_ops,
471 .parent_hws = (const struct clk_hw *[]) {
472 &s4_hdmi_pll_od.hw
473 },
474 .num_parents = 1,
475 .flags = CLK_SET_RATE_PARENT,
476 },
477 };
478
479 static struct clk_fixed_factor s4_mpll_50m_div = {
480 .mult = 1,
481 .div = 80,
482 .hw.init = &(struct clk_init_data){
483 .name = "mpll_50m_div",
484 .ops = &clk_fixed_factor_ops,
485 .parent_hws = (const struct clk_hw *[]) {
486 &s4_fixed_pll_dco.hw
487 },
488 .num_parents = 1,
489 },
490 };
491
492 static struct clk_regmap s4_mpll_50m = {
493 .data = &(struct clk_regmap_mux_data){
494 .offset = ANACTRL_FIXPLL_CTRL3,
495 .mask = 0x1,
496 .shift = 5,
497 },
498 .hw.init = &(struct clk_init_data){
499 .name = "mpll_50m",
500 .ops = &clk_regmap_mux_ro_ops,
501 .parent_data = (const struct clk_parent_data []) {
502 { .fw_name = "xtal", },
503 { .hw = &s4_mpll_50m_div.hw },
504 },
505 .num_parents = 2,
506 },
507 };
508
509 static struct clk_fixed_factor s4_mpll_prediv = {
510 .mult = 1,
511 .div = 2,
512 .hw.init = &(struct clk_init_data){
513 .name = "mpll_prediv",
514 .ops = &clk_fixed_factor_ops,
515 .parent_hws = (const struct clk_hw *[]) {
516 &s4_fixed_pll_dco.hw
517 },
518 .num_parents = 1,
519 },
520 };
521
522 static const struct reg_sequence s4_mpll0_init_regs[] = {
523 { .reg = ANACTRL_MPLL_CTRL2, .def = 0x40000033 }
524 };
525
526 static struct clk_regmap s4_mpll0_div = {
527 .data = &(struct meson_clk_mpll_data){
528 .sdm = {
529 .reg_off = ANACTRL_MPLL_CTRL1,
530 .shift = 0,
531 .width = 14,
532 },
533 .sdm_en = {
534 .reg_off = ANACTRL_MPLL_CTRL1,
535 .shift = 30,
536 .width = 1,
537 },
538 .n2 = {
539 .reg_off = ANACTRL_MPLL_CTRL1,
540 .shift = 20,
541 .width = 9,
542 },
543 .ssen = {
544 .reg_off = ANACTRL_MPLL_CTRL1,
545 .shift = 29,
546 .width = 1,
547 },
548 .init_regs = s4_mpll0_init_regs,
549 .init_count = ARRAY_SIZE(s4_mpll0_init_regs),
550 },
551 .hw.init = &(struct clk_init_data){
552 .name = "mpll0_div",
553 .ops = &meson_clk_mpll_ops,
554 .parent_hws = (const struct clk_hw *[]) {
555 &s4_mpll_prediv.hw
556 },
557 .num_parents = 1,
558 },
559 };
560
561 static struct clk_regmap s4_mpll0 = {
562 .data = &(struct clk_regmap_gate_data){
563 .offset = ANACTRL_MPLL_CTRL1,
564 .bit_idx = 31,
565 },
566 .hw.init = &(struct clk_init_data){
567 .name = "mpll0",
568 .ops = &clk_regmap_gate_ops,
569 .parent_hws = (const struct clk_hw *[]) { &s4_mpll0_div.hw },
570 .num_parents = 1,
571 .flags = CLK_SET_RATE_PARENT,
572 },
573 };
574
575 static const struct reg_sequence s4_mpll1_init_regs[] = {
576 { .reg = ANACTRL_MPLL_CTRL4, .def = 0x40000033 }
577 };
578
579 static struct clk_regmap s4_mpll1_div = {
580 .data = &(struct meson_clk_mpll_data){
581 .sdm = {
582 .reg_off = ANACTRL_MPLL_CTRL3,
583 .shift = 0,
584 .width = 14,
585 },
586 .sdm_en = {
587 .reg_off = ANACTRL_MPLL_CTRL3,
588 .shift = 30,
589 .width = 1,
590 },
591 .n2 = {
592 .reg_off = ANACTRL_MPLL_CTRL3,
593 .shift = 20,
594 .width = 9,
595 },
596 .ssen = {
597 .reg_off = ANACTRL_MPLL_CTRL3,
598 .shift = 29,
599 .width = 1,
600 },
601 .init_regs = s4_mpll1_init_regs,
602 .init_count = ARRAY_SIZE(s4_mpll1_init_regs),
603 },
604 .hw.init = &(struct clk_init_data){
605 .name = "mpll1_div",
606 .ops = &meson_clk_mpll_ops,
607 .parent_hws = (const struct clk_hw *[]) {
608 &s4_mpll_prediv.hw
609 },
610 .num_parents = 1,
611 },
612 };
613
614 static struct clk_regmap s4_mpll1 = {
615 .data = &(struct clk_regmap_gate_data){
616 .offset = ANACTRL_MPLL_CTRL3,
617 .bit_idx = 31,
618 },
619 .hw.init = &(struct clk_init_data){
620 .name = "mpll1",
621 .ops = &clk_regmap_gate_ops,
622 .parent_hws = (const struct clk_hw *[]) { &s4_mpll1_div.hw },
623 .num_parents = 1,
624 .flags = CLK_SET_RATE_PARENT,
625 },
626 };
627
628 static const struct reg_sequence s4_mpll2_init_regs[] = {
629 { .reg = ANACTRL_MPLL_CTRL6, .def = 0x40000033 }
630 };
631
632 static struct clk_regmap s4_mpll2_div = {
633 .data = &(struct meson_clk_mpll_data){
634 .sdm = {
635 .reg_off = ANACTRL_MPLL_CTRL5,
636 .shift = 0,
637 .width = 14,
638 },
639 .sdm_en = {
640 .reg_off = ANACTRL_MPLL_CTRL5,
641 .shift = 30,
642 .width = 1,
643 },
644 .n2 = {
645 .reg_off = ANACTRL_MPLL_CTRL5,
646 .shift = 20,
647 .width = 9,
648 },
649 .ssen = {
650 .reg_off = ANACTRL_MPLL_CTRL5,
651 .shift = 29,
652 .width = 1,
653 },
654 .init_regs = s4_mpll2_init_regs,
655 .init_count = ARRAY_SIZE(s4_mpll2_init_regs),
656 },
657 .hw.init = &(struct clk_init_data){
658 .name = "mpll2_div",
659 .ops = &meson_clk_mpll_ops,
660 .parent_hws = (const struct clk_hw *[]) {
661 &s4_mpll_prediv.hw
662 },
663 .num_parents = 1,
664 },
665 };
666
667 static struct clk_regmap s4_mpll2 = {
668 .data = &(struct clk_regmap_gate_data){
669 .offset = ANACTRL_MPLL_CTRL5,
670 .bit_idx = 31,
671 },
672 .hw.init = &(struct clk_init_data){
673 .name = "mpll2",
674 .ops = &clk_regmap_gate_ops,
675 .parent_hws = (const struct clk_hw *[]) { &s4_mpll2_div.hw },
676 .num_parents = 1,
677 .flags = CLK_SET_RATE_PARENT,
678 },
679 };
680
681 static const struct reg_sequence s4_mpll3_init_regs[] = {
682 { .reg = ANACTRL_MPLL_CTRL8, .def = 0x40000033 }
683 };
684
685 static struct clk_regmap s4_mpll3_div = {
686 .data = &(struct meson_clk_mpll_data){
687 .sdm = {
688 .reg_off = ANACTRL_MPLL_CTRL7,
689 .shift = 0,
690 .width = 14,
691 },
692 .sdm_en = {
693 .reg_off = ANACTRL_MPLL_CTRL7,
694 .shift = 30,
695 .width = 1,
696 },
697 .n2 = {
698 .reg_off = ANACTRL_MPLL_CTRL7,
699 .shift = 20,
700 .width = 9,
701 },
702 .ssen = {
703 .reg_off = ANACTRL_MPLL_CTRL7,
704 .shift = 29,
705 .width = 1,
706 },
707 .init_regs = s4_mpll3_init_regs,
708 .init_count = ARRAY_SIZE(s4_mpll3_init_regs),
709 },
710 .hw.init = &(struct clk_init_data){
711 .name = "mpll3_div",
712 .ops = &meson_clk_mpll_ops,
713 .parent_hws = (const struct clk_hw *[]) {
714 &s4_mpll_prediv.hw
715 },
716 .num_parents = 1,
717 },
718 };
719
720 static struct clk_regmap s4_mpll3 = {
721 .data = &(struct clk_regmap_gate_data){
722 .offset = ANACTRL_MPLL_CTRL7,
723 .bit_idx = 31,
724 },
725 .hw.init = &(struct clk_init_data){
726 .name = "mpll3",
727 .ops = &clk_regmap_gate_ops,
728 .parent_hws = (const struct clk_hw *[]) { &s4_mpll3_div.hw },
729 .num_parents = 1,
730 .flags = CLK_SET_RATE_PARENT,
731 },
732 };
733
734 /* Array of all clocks provided by this provider */
735 static struct clk_hw *s4_pll_hw_clks[] = {
736 [CLKID_FIXED_PLL_DCO] = &s4_fixed_pll_dco.hw,
737 [CLKID_FIXED_PLL] = &s4_fixed_pll.hw,
738 [CLKID_FCLK_DIV2_DIV] = &s4_fclk_div2_div.hw,
739 [CLKID_FCLK_DIV2] = &s4_fclk_div2.hw,
740 [CLKID_FCLK_DIV3_DIV] = &s4_fclk_div3_div.hw,
741 [CLKID_FCLK_DIV3] = &s4_fclk_div3.hw,
742 [CLKID_FCLK_DIV4_DIV] = &s4_fclk_div4_div.hw,
743 [CLKID_FCLK_DIV4] = &s4_fclk_div4.hw,
744 [CLKID_FCLK_DIV5_DIV] = &s4_fclk_div5_div.hw,
745 [CLKID_FCLK_DIV5] = &s4_fclk_div5.hw,
746 [CLKID_FCLK_DIV7_DIV] = &s4_fclk_div7_div.hw,
747 [CLKID_FCLK_DIV7] = &s4_fclk_div7.hw,
748 [CLKID_FCLK_DIV2P5_DIV] = &s4_fclk_div2p5_div.hw,
749 [CLKID_FCLK_DIV2P5] = &s4_fclk_div2p5.hw,
750 [CLKID_GP0_PLL_DCO] = &s4_gp0_pll_dco.hw,
751 [CLKID_GP0_PLL] = &s4_gp0_pll.hw,
752 [CLKID_HIFI_PLL_DCO] = &s4_hifi_pll_dco.hw,
753 [CLKID_HIFI_PLL] = &s4_hifi_pll.hw,
754 [CLKID_HDMI_PLL_DCO] = &s4_hdmi_pll_dco.hw,
755 [CLKID_HDMI_PLL_OD] = &s4_hdmi_pll_od.hw,
756 [CLKID_HDMI_PLL] = &s4_hdmi_pll.hw,
757 [CLKID_MPLL_50M_DIV] = &s4_mpll_50m_div.hw,
758 [CLKID_MPLL_50M] = &s4_mpll_50m.hw,
759 [CLKID_MPLL_PREDIV] = &s4_mpll_prediv.hw,
760 [CLKID_MPLL0_DIV] = &s4_mpll0_div.hw,
761 [CLKID_MPLL0] = &s4_mpll0.hw,
762 [CLKID_MPLL1_DIV] = &s4_mpll1_div.hw,
763 [CLKID_MPLL1] = &s4_mpll1.hw,
764 [CLKID_MPLL2_DIV] = &s4_mpll2_div.hw,
765 [CLKID_MPLL2] = &s4_mpll2.hw,
766 [CLKID_MPLL3_DIV] = &s4_mpll3_div.hw,
767 [CLKID_MPLL3] = &s4_mpll3.hw,
768 };
769
770 static struct clk_regmap *const s4_pll_clk_regmaps[] = {
771 &s4_fixed_pll_dco,
772 &s4_fixed_pll,
773 &s4_fclk_div2,
774 &s4_fclk_div3,
775 &s4_fclk_div4,
776 &s4_fclk_div5,
777 &s4_fclk_div7,
778 &s4_fclk_div2p5,
779 &s4_gp0_pll_dco,
780 &s4_gp0_pll,
781 &s4_hifi_pll_dco,
782 &s4_hifi_pll,
783 &s4_hdmi_pll_dco,
784 &s4_hdmi_pll_od,
785 &s4_hdmi_pll,
786 &s4_mpll_50m,
787 &s4_mpll0_div,
788 &s4_mpll0,
789 &s4_mpll1_div,
790 &s4_mpll1,
791 &s4_mpll2_div,
792 &s4_mpll2,
793 &s4_mpll3_div,
794 &s4_mpll3,
795 };
796
797 static const struct reg_sequence s4_init_regs[] = {
798 { .reg = ANACTRL_MPLL_CTRL0, .def = 0x00000543 },
799 };
800
801 static const struct regmap_config clkc_regmap_config = {
802 .reg_bits = 32,
803 .val_bits = 32,
804 .reg_stride = 4,
805 .max_register = ANACTRL_HDMIPLL_CTRL0,
806 };
807
808 static struct meson_clk_hw_data s4_pll_clks = {
809 .hws = s4_pll_hw_clks,
810 .num = ARRAY_SIZE(s4_pll_hw_clks),
811 };
812
meson_s4_pll_probe(struct platform_device * pdev)813 static int meson_s4_pll_probe(struct platform_device *pdev)
814 {
815 struct device *dev = &pdev->dev;
816 struct regmap *regmap;
817 void __iomem *base;
818 int ret, i;
819
820 base = devm_platform_ioremap_resource(pdev, 0);
821 if (IS_ERR(base))
822 return dev_err_probe(dev, PTR_ERR(base),
823 "can't ioremap resource\n");
824
825 regmap = devm_regmap_init_mmio(dev, base, &clkc_regmap_config);
826 if (IS_ERR(regmap))
827 return dev_err_probe(dev, PTR_ERR(regmap),
828 "can't init regmap mmio region\n");
829
830 ret = regmap_multi_reg_write(regmap, s4_init_regs, ARRAY_SIZE(s4_init_regs));
831 if (ret)
832 return dev_err_probe(dev, ret,
833 "Failed to init registers\n");
834
835 /* Populate regmap for the regmap backed clocks */
836 for (i = 0; i < ARRAY_SIZE(s4_pll_clk_regmaps); i++)
837 s4_pll_clk_regmaps[i]->map = regmap;
838
839 /* Register clocks */
840 for (i = 0; i < s4_pll_clks.num; i++) {
841 /* array might be sparse */
842 if (!s4_pll_clks.hws[i])
843 continue;
844
845 ret = devm_clk_hw_register(dev, s4_pll_clks.hws[i]);
846 if (ret)
847 return dev_err_probe(dev, ret,
848 "clock[%d] registration failed\n", i);
849 }
850
851 return devm_of_clk_add_hw_provider(dev, meson_clk_hw_get,
852 &s4_pll_clks);
853 }
854
855 static const struct of_device_id clkc_match_table[] = {
856 {
857 .compatible = "amlogic,s4-pll-clkc",
858 },
859 {}
860 };
861 MODULE_DEVICE_TABLE(of, clkc_match_table);
862
863 static struct platform_driver s4_driver = {
864 .probe = meson_s4_pll_probe,
865 .driver = {
866 .name = "s4-pll-clkc",
867 .of_match_table = clkc_match_table,
868 },
869 };
870 module_platform_driver(s4_driver);
871
872 MODULE_DESCRIPTION("Amlogic S4 PLL Clock Controller driver");
873 MODULE_AUTHOR("Yu Tu <yu.tu@amlogic.com>");
874 MODULE_LICENSE("GPL");
875 MODULE_IMPORT_NS("CLK_MESON");
876