1 // SPDX-License-Identifier: GPL-2.0
4 * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
7 #include <linux/clk-provider.h>
8 #include <linux/delay.h>
12 #include <dt-bindings/clock/x1830-cgu.h>
17 /* CGU register offsets */
18 #define CGU_REG_CPCCR 0x00
19 #define CGU_REG_CPPCR 0x0c
20 #define CGU_REG_APLL 0x10
21 #define CGU_REG_MPLL 0x14
22 #define CGU_REG_CLKGR0 0x20
23 #define CGU_REG_OPCR 0x24
24 #define CGU_REG_CLKGR1 0x28
25 #define CGU_REG_DDRCDR 0x2c
26 #define CGU_REG_USBPCR 0x3c
27 #define CGU_REG_USBRDT 0x40
28 #define CGU_REG_USBVBFIL 0x44
29 #define CGU_REG_USBPCR1 0x48
30 #define CGU_REG_MACCDR 0x54
31 #define CGU_REG_EPLL 0x58
32 #define CGU_REG_I2SCDR 0x60
33 #define CGU_REG_LPCDR 0x64
34 #define CGU_REG_MSC0CDR 0x68
35 #define CGU_REG_I2SCDR1 0x70
36 #define CGU_REG_SSICDR 0x74
37 #define CGU_REG_CIMCDR 0x7c
38 #define CGU_REG_MSC1CDR 0xa4
39 #define CGU_REG_CMP_INTR 0xb0
40 #define CGU_REG_CMP_INTRE 0xb4
41 #define CGU_REG_DRCG 0xd0
42 #define CGU_REG_CPCSR 0xd4
43 #define CGU_REG_VPLL 0xe0
44 #define CGU_REG_MACPHYC 0xe8
46 /* bits within the OPCR register */
47 #define OPCR_GATE_USBPHYCLK BIT(23)
48 #define OPCR_SPENDN0 BIT(7)
49 #define OPCR_SPENDN1 BIT(6)
51 /* bits within the USBPCR register */
52 #define USBPCR_SIDDQ BIT(21)
53 #define USBPCR_OTG_DISABLE BIT(20)
55 static struct ingenic_cgu
*cgu
;
57 static int x1830_usb_phy_enable(struct clk_hw
*hw
)
59 void __iomem
*reg_opcr
= cgu
->base
+ CGU_REG_OPCR
;
60 void __iomem
*reg_usbpcr
= cgu
->base
+ CGU_REG_USBPCR
;
62 writel((readl(reg_opcr
) | OPCR_SPENDN0
) & ~OPCR_GATE_USBPHYCLK
, reg_opcr
);
63 writel(readl(reg_usbpcr
) & ~USBPCR_OTG_DISABLE
& ~USBPCR_SIDDQ
, reg_usbpcr
);
67 static void x1830_usb_phy_disable(struct clk_hw
*hw
)
69 void __iomem
*reg_opcr
= cgu
->base
+ CGU_REG_OPCR
;
70 void __iomem
*reg_usbpcr
= cgu
->base
+ CGU_REG_USBPCR
;
72 writel((readl(reg_opcr
) & ~OPCR_SPENDN0
) | OPCR_GATE_USBPHYCLK
, reg_opcr
);
73 writel(readl(reg_usbpcr
) | USBPCR_OTG_DISABLE
| USBPCR_SIDDQ
, reg_usbpcr
);
76 static int x1830_usb_phy_is_enabled(struct clk_hw
*hw
)
78 void __iomem
*reg_opcr
= cgu
->base
+ CGU_REG_OPCR
;
79 void __iomem
*reg_usbpcr
= cgu
->base
+ CGU_REG_USBPCR
;
81 return (readl(reg_opcr
) & OPCR_SPENDN0
) &&
82 !(readl(reg_usbpcr
) & USBPCR_SIDDQ
) &&
83 !(readl(reg_usbpcr
) & USBPCR_OTG_DISABLE
);
86 static const struct clk_ops x1830_otg_phy_ops
= {
87 .enable
= x1830_usb_phy_enable
,
88 .disable
= x1830_usb_phy_disable
,
89 .is_enabled
= x1830_usb_phy_is_enabled
,
92 static const s8 pll_od_encoding
[64] = {
93 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
94 -1, -1, -1, -1, -1, -1, -1, 0x4,
95 -1, -1, -1, -1, -1, -1, -1, -1,
96 -1, -1, -1, -1, -1, -1, -1, 0x5,
97 -1, -1, -1, -1, -1, -1, -1, -1,
98 -1, -1, -1, -1, -1, -1, -1, -1,
99 -1, -1, -1, -1, -1, -1, -1, -1,
100 -1, -1, -1, -1, -1, -1, -1, 0x6,
103 static const struct ingenic_cgu_clk_info x1830_cgu_clocks
[] = {
105 /* External clocks */
107 [X1830_CLK_EXCLK
] = { "ext", CGU_CLK_EXT
},
108 [X1830_CLK_RTCLK
] = { "rtc", CGU_CLK_EXT
},
114 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
117 .rate_multiplier
= 2,
127 .od_encoding
= pll_od_encoding
,
128 .bypass_reg
= CGU_REG_CPPCR
,
137 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
140 .rate_multiplier
= 2,
150 .od_encoding
= pll_od_encoding
,
151 .bypass_reg
= CGU_REG_CPPCR
,
160 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
163 .rate_multiplier
= 2,
173 .od_encoding
= pll_od_encoding
,
174 .bypass_reg
= CGU_REG_CPPCR
,
183 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
186 .rate_multiplier
= 2,
196 .od_encoding
= pll_od_encoding
,
197 .bypass_reg
= CGU_REG_CPPCR
,
204 /* Custom (SoC-specific) OTG PHY */
206 [X1830_CLK_OTGPHY
] = {
207 "otg_phy", CGU_CLK_CUSTOM
,
208 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
209 .custom
= { &x1830_otg_phy_ops
},
212 /* Muxes & dividers */
214 [X1830_CLK_SCLKA
] = {
215 "sclk_a", CGU_CLK_MUX
,
216 .parents
= { -1, X1830_CLK_EXCLK
, X1830_CLK_APLL
, -1 },
217 .mux
= { CGU_REG_CPCCR
, 30, 2 },
220 [X1830_CLK_CPUMUX
] = {
221 "cpu_mux", CGU_CLK_MUX
,
222 .parents
= { -1, X1830_CLK_SCLKA
, X1830_CLK_MPLL
, -1 },
223 .mux
= { CGU_REG_CPCCR
, 28, 2 },
227 "cpu", CGU_CLK_DIV
| CGU_CLK_GATE
,
228 .parents
= { X1830_CLK_CPUMUX
, -1, -1, -1 },
229 .div
= { CGU_REG_CPCCR
, 0, 1, 4, 22, -1, -1 },
230 .gate
= { CGU_REG_CLKGR1
, 15 },
233 [X1830_CLK_L2CACHE
] = {
234 "l2cache", CGU_CLK_DIV
,
235 .parents
= { X1830_CLK_CPUMUX
, -1, -1, -1 },
236 .div
= { CGU_REG_CPCCR
, 4, 1, 4, 22, -1, -1 },
240 "ahb0", CGU_CLK_MUX
| CGU_CLK_DIV
,
241 .parents
= { -1, X1830_CLK_SCLKA
, X1830_CLK_MPLL
, -1 },
242 .mux
= { CGU_REG_CPCCR
, 26, 2 },
243 .div
= { CGU_REG_CPCCR
, 8, 1, 4, 21, -1, -1 },
246 [X1830_CLK_AHB2PMUX
] = {
247 "ahb2_apb_mux", CGU_CLK_MUX
,
248 .parents
= { -1, X1830_CLK_SCLKA
, X1830_CLK_MPLL
, -1 },
249 .mux
= { CGU_REG_CPCCR
, 24, 2 },
254 .parents
= { X1830_CLK_AHB2PMUX
, -1, -1, -1 },
255 .div
= { CGU_REG_CPCCR
, 12, 1, 4, 20, -1, -1 },
259 "pclk", CGU_CLK_DIV
| CGU_CLK_GATE
,
260 .parents
= { X1830_CLK_AHB2PMUX
, -1, -1, -1 },
261 .div
= { CGU_REG_CPCCR
, 16, 1, 4, 20, -1, -1 },
262 .gate
= { CGU_REG_CLKGR1
, 14 },
266 "ddr", CGU_CLK_MUX
| CGU_CLK_DIV
| CGU_CLK_GATE
,
267 .parents
= { -1, X1830_CLK_SCLKA
, X1830_CLK_MPLL
, -1 },
268 .mux
= { CGU_REG_DDRCDR
, 30, 2 },
269 .div
= { CGU_REG_DDRCDR
, 0, 1, 4, 29, 28, 27 },
270 .gate
= { CGU_REG_CLKGR0
, 31 },
274 "mac", CGU_CLK_MUX
| CGU_CLK_DIV
| CGU_CLK_GATE
,
275 .parents
= { X1830_CLK_SCLKA
, X1830_CLK_MPLL
,
276 X1830_CLK_VPLL
, X1830_CLK_EPLL
},
277 .mux
= { CGU_REG_MACCDR
, 30, 2 },
278 .div
= { CGU_REG_MACCDR
, 0, 1, 8, 29, 28, 27 },
279 .gate
= { CGU_REG_CLKGR1
, 4 },
283 "lcd", CGU_CLK_MUX
| CGU_CLK_DIV
| CGU_CLK_GATE
,
284 .parents
= { X1830_CLK_SCLKA
, X1830_CLK_MPLL
,
285 X1830_CLK_VPLL
, X1830_CLK_EPLL
},
286 .mux
= { CGU_REG_LPCDR
, 30, 2 },
287 .div
= { CGU_REG_LPCDR
, 0, 1, 8, 28, 27, 26 },
288 .gate
= { CGU_REG_CLKGR1
, 9 },
291 [X1830_CLK_MSCMUX
] = {
292 "msc_mux", CGU_CLK_MUX
,
293 .parents
= { X1830_CLK_SCLKA
, X1830_CLK_MPLL
,
294 X1830_CLK_VPLL
, X1830_CLK_EPLL
},
295 .mux
= { CGU_REG_MSC0CDR
, 30, 2 },
299 "msc0", CGU_CLK_DIV
| CGU_CLK_GATE
,
300 .parents
= { X1830_CLK_MSCMUX
, -1, -1, -1 },
301 .div
= { CGU_REG_MSC0CDR
, 0, 2, 8, 29, 28, 27 },
302 .gate
= { CGU_REG_CLKGR0
, 4 },
306 "msc1", CGU_CLK_DIV
| CGU_CLK_GATE
,
307 .parents
= { X1830_CLK_MSCMUX
, -1, -1, -1 },
308 .div
= { CGU_REG_MSC1CDR
, 0, 2, 8, 29, 28, 27 },
309 .gate
= { CGU_REG_CLKGR0
, 5 },
312 [X1830_CLK_SSIPLL
] = {
313 "ssi_pll", CGU_CLK_MUX
| CGU_CLK_DIV
,
314 .parents
= { X1830_CLK_SCLKA
, X1830_CLK_MPLL
,
315 X1830_CLK_VPLL
, X1830_CLK_EPLL
},
316 .mux
= { CGU_REG_SSICDR
, 30, 2 },
317 .div
= { CGU_REG_SSICDR
, 0, 1, 8, 28, 27, 26 },
320 [X1830_CLK_SSIPLL_DIV2
] = {
321 "ssi_pll_div2", CGU_CLK_FIXDIV
,
322 .parents
= { X1830_CLK_SSIPLL
},
326 [X1830_CLK_SSIMUX
] = {
327 "ssi_mux", CGU_CLK_MUX
,
328 .parents
= { X1830_CLK_EXCLK
, X1830_CLK_SSIPLL_DIV2
, -1, -1 },
329 .mux
= { CGU_REG_SSICDR
, 29, 1 },
332 [X1830_CLK_EXCLK_DIV512
] = {
333 "exclk_div512", CGU_CLK_FIXDIV
,
334 .parents
= { X1830_CLK_EXCLK
},
339 "rtc_ercs", CGU_CLK_MUX
| CGU_CLK_GATE
,
340 .parents
= { X1830_CLK_EXCLK_DIV512
, X1830_CLK_RTCLK
},
341 .mux
= { CGU_REG_OPCR
, 2, 1},
342 .gate
= { CGU_REG_CLKGR0
, 29 },
345 /* Gate-only clocks */
349 .parents
= { X1830_CLK_AHB2
, -1, -1, -1 },
350 .gate
= { CGU_REG_CLKGR0
, 0 },
353 [X1830_CLK_EFUSE
] = {
354 "efuse", CGU_CLK_GATE
,
355 .parents
= { X1830_CLK_AHB2
, -1, -1, -1 },
356 .gate
= { CGU_REG_CLKGR0
, 1 },
361 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
362 .gate
= { CGU_REG_CLKGR0
, 3 },
366 "ssi0", CGU_CLK_GATE
,
367 .parents
= { X1830_CLK_SSIMUX
, -1, -1, -1 },
368 .gate
= { CGU_REG_CLKGR0
, 6 },
372 "smb0", CGU_CLK_GATE
,
373 .parents
= { X1830_CLK_PCLK
, -1, -1, -1 },
374 .gate
= { CGU_REG_CLKGR0
, 7 },
378 "smb1", CGU_CLK_GATE
,
379 .parents
= { X1830_CLK_PCLK
, -1, -1, -1 },
380 .gate
= { CGU_REG_CLKGR0
, 8 },
384 "smb2", CGU_CLK_GATE
,
385 .parents
= { X1830_CLK_PCLK
, -1, -1, -1 },
386 .gate
= { CGU_REG_CLKGR0
, 9 },
389 [X1830_CLK_UART0
] = {
390 "uart0", CGU_CLK_GATE
,
391 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
392 .gate
= { CGU_REG_CLKGR0
, 14 },
395 [X1830_CLK_UART1
] = {
396 "uart1", CGU_CLK_GATE
,
397 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
398 .gate
= { CGU_REG_CLKGR0
, 15 },
402 "ssi1", CGU_CLK_GATE
,
403 .parents
= { X1830_CLK_SSIMUX
, -1, -1, -1 },
404 .gate
= { CGU_REG_CLKGR0
, 19 },
409 .parents
= { X1830_CLK_SSIPLL
, -1, -1, -1 },
410 .gate
= { CGU_REG_CLKGR0
, 20 },
414 "pdma", CGU_CLK_GATE
,
415 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
416 .gate
= { CGU_REG_CLKGR0
, 21 },
421 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
422 .gate
= { CGU_REG_CLKGR0
, 30 },
425 [X1830_CLK_DTRNG
] = {
426 "dtrng", CGU_CLK_GATE
,
427 .parents
= { X1830_CLK_PCLK
, -1, -1, -1 },
428 .gate
= { CGU_REG_CLKGR1
, 1 },
433 .parents
= { X1830_CLK_EXCLK
, -1, -1, -1 },
434 .gate
= { CGU_REG_CLKGR1
, 11 },
438 static void __init
x1830_cgu_init(struct device_node
*np
)
442 cgu
= ingenic_cgu_new(x1830_cgu_clocks
,
443 ARRAY_SIZE(x1830_cgu_clocks
), np
);
445 pr_err("%s: failed to initialise CGU\n", __func__
);
449 retval
= ingenic_cgu_register_clocks(cgu
);
451 pr_err("%s: failed to register CGU Clocks\n", __func__
);
455 ingenic_cgu_register_syscore_ops(cgu
);
458 * CGU has some children devices, this is useful for probing children devices
459 * in the case where the device node is compatible with "simple-mfd".
461 CLK_OF_DECLARE_DRIVER(x1830_cgu
, "ingenic,x1830-cgu", x1830_cgu_init
);