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