Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * X1000 SoC CGU driver
4 * Copyright (c) 2019 周琰杰 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
5 */
6
7#include <linux/clk-provider.h>
8#include <linux/delay.h>
9#include <linux/io.h>
10#include <linux/of.h>
11
12#include <dt-bindings/clock/x1000-cgu.h>
13
14#include "cgu.h"
15#include "pm.h"
16
17/* CGU register offsets */
18#define CGU_REG_CPCCR 0x00
19#define CGU_REG_APLL 0x10
20#define CGU_REG_MPLL 0x14
21#define CGU_REG_CLKGR 0x20
22#define CGU_REG_OPCR 0x24
23#define CGU_REG_DDRCDR 0x2c
24#define CGU_REG_USBPCR 0x3c
25#define CGU_REG_USBPCR1 0x48
26#define CGU_REG_USBCDR 0x50
27#define CGU_REG_MACCDR 0x54
28#define CGU_REG_I2SCDR 0x60
29#define CGU_REG_LPCDR 0x64
30#define CGU_REG_MSC0CDR 0x68
31#define CGU_REG_I2SCDR1 0x70
32#define CGU_REG_SSICDR 0x74
33#define CGU_REG_CIMCDR 0x7c
34#define CGU_REG_PCMCDR 0x84
35#define CGU_REG_MSC1CDR 0xa4
36#define CGU_REG_CMP_INTR 0xb0
37#define CGU_REG_CMP_INTRE 0xb4
38#define CGU_REG_DRCG 0xd0
39#define CGU_REG_CPCSR 0xd4
40#define CGU_REG_PCMCDR1 0xe0
41#define CGU_REG_MACPHYC 0xe8
42
43/* bits within the OPCR register */
44#define OPCR_SPENDN0 BIT(7)
45#define OPCR_SPENDN1 BIT(6)
46
47/* bits within the USBPCR register */
48#define USBPCR_SIDDQ BIT(21)
49#define USBPCR_OTG_DISABLE BIT(20)
50
51static struct ingenic_cgu *cgu;
52
53static int x1000_usb_phy_enable(struct clk_hw *hw)
54{
55 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
56 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
57
58 writel(readl(reg_opcr) | OPCR_SPENDN0, reg_opcr);
59 writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
60 return 0;
61}
62
63static void x1000_usb_phy_disable(struct clk_hw *hw)
64{
65 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
66 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
67
68 writel(readl(reg_opcr) & ~OPCR_SPENDN0, reg_opcr);
69 writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
70}
71
72static int x1000_usb_phy_is_enabled(struct clk_hw *hw)
73{
74 void __iomem *reg_opcr = cgu->base + CGU_REG_OPCR;
75 void __iomem *reg_usbpcr = cgu->base + CGU_REG_USBPCR;
76
77 return (readl(reg_opcr) & OPCR_SPENDN0) &&
78 !(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
79 !(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
80}
81
82static const struct clk_ops x1000_otg_phy_ops = {
83 .enable = x1000_usb_phy_enable,
84 .disable = x1000_usb_phy_disable,
85 .is_enabled = x1000_usb_phy_is_enabled,
86};
87
88static const s8 pll_od_encoding[8] = {
89 0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
90};
91
92static const struct ingenic_cgu_clk_info x1000_cgu_clocks[] = {
93
94 /* External clocks */
95
96 [X1000_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
97 [X1000_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
98
99 /* PLLs */
100
101 [X1000_CLK_APLL] = {
102 "apll", CGU_CLK_PLL,
103 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
104 .pll = {
105 .reg = CGU_REG_APLL,
106 .rate_multiplier = 1,
107 .m_shift = 24,
108 .m_bits = 7,
109 .m_offset = 1,
110 .n_shift = 18,
111 .n_bits = 5,
112 .n_offset = 1,
113 .od_shift = 16,
114 .od_bits = 2,
115 .od_max = 8,
116 .od_encoding = pll_od_encoding,
117 .bypass_reg = CGU_REG_APLL,
118 .bypass_bit = 9,
119 .enable_bit = 8,
120 .stable_bit = 10,
121 },
122 },
123
124 [X1000_CLK_MPLL] = {
125 "mpll", CGU_CLK_PLL,
126 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
127 .pll = {
128 .reg = CGU_REG_MPLL,
129 .rate_multiplier = 1,
130 .m_shift = 24,
131 .m_bits = 7,
132 .m_offset = 1,
133 .n_shift = 18,
134 .n_bits = 5,
135 .n_offset = 1,
136 .od_shift = 16,
137 .od_bits = 2,
138 .od_max = 8,
139 .od_encoding = pll_od_encoding,
140 .bypass_reg = CGU_REG_MPLL,
141 .bypass_bit = 6,
142 .enable_bit = 7,
143 .stable_bit = 0,
144 },
145 },
146
147
148 /* Custom (SoC-specific) OTG PHY */
149
150 [X1000_CLK_OTGPHY] = {
151 "otg_phy", CGU_CLK_CUSTOM,
152 .parents = { -1, -1, X1000_CLK_EXCLK, -1 },
153 .custom = { &x1000_otg_phy_ops },
154 },
155
156 /* Muxes & dividers */
157
158 [X1000_CLK_SCLKA] = {
159 "sclk_a", CGU_CLK_MUX,
160 .parents = { -1, X1000_CLK_EXCLK, X1000_CLK_APLL, -1 },
161 .mux = { CGU_REG_CPCCR, 30, 2 },
162 },
163
164 [X1000_CLK_CPUMUX] = {
165 "cpu_mux", CGU_CLK_MUX,
166 .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
167 .mux = { CGU_REG_CPCCR, 28, 2 },
168 },
169
170 [X1000_CLK_CPU] = {
171 "cpu", CGU_CLK_DIV | CGU_CLK_GATE,
172 .parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
173 .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
174 .gate = { CGU_REG_CLKGR, 30 },
175 },
176
177 [X1000_CLK_L2CACHE] = {
178 "l2cache", CGU_CLK_DIV,
179 .parents = { X1000_CLK_CPUMUX, -1, -1, -1 },
180 .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
181 },
182
183 [X1000_CLK_AHB0] = {
184 "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
185 .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
186 .mux = { CGU_REG_CPCCR, 26, 2 },
187 .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
188 },
189
190 [X1000_CLK_AHB2PMUX] = {
191 "ahb2_apb_mux", CGU_CLK_MUX,
192 .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
193 .mux = { CGU_REG_CPCCR, 24, 2 },
194 },
195
196 [X1000_CLK_AHB2] = {
197 "ahb2", CGU_CLK_DIV,
198 .parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
199 .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
200 },
201
202 [X1000_CLK_PCLK] = {
203 "pclk", CGU_CLK_DIV | CGU_CLK_GATE,
204 .parents = { X1000_CLK_AHB2PMUX, -1, -1, -1 },
205 .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
206 .gate = { CGU_REG_CLKGR, 28 },
207 },
208
209 [X1000_CLK_DDR] = {
210 "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
211 .parents = { -1, X1000_CLK_SCLKA, X1000_CLK_MPLL, -1 },
212 .mux = { CGU_REG_DDRCDR, 30, 2 },
213 .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
214 .gate = { CGU_REG_CLKGR, 31 },
215 },
216
217 [X1000_CLK_MAC] = {
218 "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
219 .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
220 .mux = { CGU_REG_MACCDR, 31, 1 },
221 .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },
222 .gate = { CGU_REG_CLKGR, 25 },
223 },
224
225 [X1000_CLK_LCD] = {
226 "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
227 .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL },
228 .mux = { CGU_REG_LPCDR, 31, 1 },
229 .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },
230 .gate = { CGU_REG_CLKGR, 23 },
231 },
232
233 [X1000_CLK_MSCMUX] = {
234 "msc_mux", CGU_CLK_MUX,
235 .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL},
236 .mux = { CGU_REG_MSC0CDR, 31, 1 },
237 },
238
239 [X1000_CLK_MSC0] = {
240 "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
241 .parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
242 .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
243 .gate = { CGU_REG_CLKGR, 4 },
244 },
245
246 [X1000_CLK_MSC1] = {
247 "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
248 .parents = { X1000_CLK_MSCMUX, -1, -1, -1 },
249 .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
250 .gate = { CGU_REG_CLKGR, 5 },
251 },
252
253 [X1000_CLK_OTG] = {
254 "otg", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
255 .parents = { X1000_CLK_EXCLK, -1,
256 X1000_CLK_APLL, X1000_CLK_MPLL },
257 .mux = { CGU_REG_USBCDR, 30, 2 },
258 .div = { CGU_REG_USBCDR, 0, 1, 8, 29, 28, 27 },
259 .gate = { CGU_REG_CLKGR, 3 },
260 },
261
262 [X1000_CLK_SSIPLL] = {
263 "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
264 .parents = { X1000_CLK_SCLKA, X1000_CLK_MPLL, -1, -1 },
265 .mux = { CGU_REG_SSICDR, 31, 1 },
266 .div = { CGU_REG_SSICDR, 0, 1, 8, 29, 28, 27 },
267 },
268
269 [X1000_CLK_SSIPLL_DIV2] = {
270 "ssi_pll_div2", CGU_CLK_FIXDIV,
271 .parents = { X1000_CLK_SSIPLL },
272 .fixdiv = { 2 },
273 },
274
275 [X1000_CLK_SSIMUX] = {
276 "ssi_mux", CGU_CLK_MUX,
277 .parents = { X1000_CLK_EXCLK, X1000_CLK_SSIPLL_DIV2, -1, -1 },
278 .mux = { CGU_REG_SSICDR, 30, 1 },
279 },
280
281 /* Gate-only clocks */
282
283 [X1000_CLK_EMC] = {
284 "emc", CGU_CLK_GATE,
285 .parents = { X1000_CLK_AHB2, -1, -1, -1 },
286 .gate = { CGU_REG_CLKGR, 0 },
287 },
288
289 [X1000_CLK_EFUSE] = {
290 "efuse", CGU_CLK_GATE,
291 .parents = { X1000_CLK_AHB2, -1, -1, -1 },
292 .gate = { CGU_REG_CLKGR, 1 },
293 },
294
295 [X1000_CLK_SFC] = {
296 "sfc", CGU_CLK_GATE,
297 .parents = { X1000_CLK_SSIPLL, -1, -1, -1 },
298 .gate = { CGU_REG_CLKGR, 2 },
299 },
300
301 [X1000_CLK_I2C0] = {
302 "i2c0", CGU_CLK_GATE,
303 .parents = { X1000_CLK_PCLK, -1, -1, -1 },
304 .gate = { CGU_REG_CLKGR, 7 },
305 },
306
307 [X1000_CLK_I2C1] = {
308 "i2c1", CGU_CLK_GATE,
309 .parents = { X1000_CLK_PCLK, -1, -1, -1 },
310 .gate = { CGU_REG_CLKGR, 8 },
311 },
312
313 [X1000_CLK_I2C2] = {
314 "i2c2", CGU_CLK_GATE,
315 .parents = { X1000_CLK_PCLK, -1, -1, -1 },
316 .gate = { CGU_REG_CLKGR, 9 },
317 },
318
319 [X1000_CLK_UART0] = {
320 "uart0", CGU_CLK_GATE,
321 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
322 .gate = { CGU_REG_CLKGR, 14 },
323 },
324
325 [X1000_CLK_UART1] = {
326 "uart1", CGU_CLK_GATE,
327 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
328 .gate = { CGU_REG_CLKGR, 15 },
329 },
330
331 [X1000_CLK_UART2] = {
332 "uart2", CGU_CLK_GATE,
333 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
334 .gate = { CGU_REG_CLKGR, 16 },
335 },
336
337 [X1000_CLK_TCU] = {
338 "tcu", CGU_CLK_GATE,
339 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
340 .gate = { CGU_REG_CLKGR, 18 },
341 },
342
343 [X1000_CLK_SSI] = {
344 "ssi", CGU_CLK_GATE,
345 .parents = { X1000_CLK_SSIMUX, -1, -1, -1 },
346 .gate = { CGU_REG_CLKGR, 19 },
347 },
348
349 [X1000_CLK_OST] = {
350 "ost", CGU_CLK_GATE,
351 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
352 .gate = { CGU_REG_CLKGR, 20 },
353 },
354
355 [X1000_CLK_PDMA] = {
356 "pdma", CGU_CLK_GATE,
357 .parents = { X1000_CLK_EXCLK, -1, -1, -1 },
358 .gate = { CGU_REG_CLKGR, 21 },
359 },
360};
361
362static void __init x1000_cgu_init(struct device_node *np)
363{
364 int retval;
365
366 cgu = ingenic_cgu_new(x1000_cgu_clocks,
367 ARRAY_SIZE(x1000_cgu_clocks), np);
368 if (!cgu) {
369 pr_err("%s: failed to initialise CGU\n", __func__);
370 return;
371 }
372
373 retval = ingenic_cgu_register_clocks(cgu);
374 if (retval) {
375 pr_err("%s: failed to register CGU Clocks\n", __func__);
376 return;
377 }
378
379 ingenic_cgu_register_syscore_ops(cgu);
380}
381/*
382 * CGU has some children devices, this is useful for probing children devices
383 * in the case where the device node is compatible with "simple-mfd".
384 */
385CLK_OF_DECLARE_DRIVER(x1000_cgu, "ingenic,x1000-cgu", x1000_cgu_init);