• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * JZ4760 SoC CGU driver
4  * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
5  */
6 
7 #include <linux/bitops.h>
8 #include <linux/clk-provider.h>
9 #include <linux/delay.h>
10 #include <linux/io.h>
11 #include <linux/of.h>
12 
13 #include <linux/clk.h>
14 
15 #include <dt-bindings/clock/ingenic,jz4760-cgu.h>
16 
17 #include "cgu.h"
18 #include "pm.h"
19 
20 #define MHZ (1000 * 1000)
21 
22 /*
23  * CPM registers offset address definition
24  */
25 #define CGU_REG_CPCCR		0x00
26 #define CGU_REG_LCR		0x04
27 #define CGU_REG_CPPCR0		0x10
28 #define CGU_REG_CLKGR0		0x20
29 #define CGU_REG_OPCR		0x24
30 #define CGU_REG_CLKGR1		0x28
31 #define CGU_REG_CPPCR1		0x30
32 #define CGU_REG_USBPCR		0x3c
33 #define CGU_REG_USBCDR		0x50
34 #define CGU_REG_I2SCDR		0x60
35 #define CGU_REG_LPCDR		0x64
36 #define CGU_REG_MSCCDR		0x68
37 #define CGU_REG_UHCCDR		0x6c
38 #define CGU_REG_SSICDR		0x74
39 #define CGU_REG_CIMCDR		0x7c
40 #define CGU_REG_GPSCDR		0x80
41 #define CGU_REG_PCMCDR		0x84
42 #define CGU_REG_GPUCDR		0x88
43 
44 static const s8 pll_od_encoding[8] = {
45 	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
46 };
47 
48 static const u8 jz4760_cgu_cpccr_div_table[] = {
49 	1, 2, 3, 4, 6, 8,
50 };
51 
52 static const u8 jz4760_cgu_pll_half_div_table[] = {
53 	2, 1,
54 };
55 
56 static void
jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info * pll_info,unsigned long rate,unsigned long parent_rate,unsigned int * pm,unsigned int * pn,unsigned int * pod)57 jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
58 		       unsigned long rate, unsigned long parent_rate,
59 		       unsigned int *pm, unsigned int *pn, unsigned int *pod)
60 {
61 	unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 1;
62 
63 	/* The frequency after the N divider must be between 1 and 50 MHz. */
64 	n = parent_rate / (1 * MHZ);
65 
66 	/* The N divider must be >= 2. */
67 	n = clamp_val(n, 2, 1 << pll_info->n_bits);
68 
69 	rate /= MHZ;
70 	parent_rate /= MHZ;
71 
72 	for (m = m_max; m >= m_max && n >= 2; n--) {
73 		m = rate * n / parent_rate;
74 		od = m & 1;
75 		m <<= od;
76 	}
77 
78 	*pm = m;
79 	*pn = n + 1;
80 	*pod = 1 << od;
81 }
82 
83 static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
84 
85 	/* External clocks */
86 
87 	[JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
88 	[JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
89 
90 	/* PLLs */
91 
92 	[JZ4760_CLK_PLL0] = {
93 		"pll0", CGU_CLK_PLL,
94 		.parents = { JZ4760_CLK_EXT },
95 		.pll = {
96 			.reg = CGU_REG_CPPCR0,
97 			.rate_multiplier = 1,
98 			.m_shift = 23,
99 			.m_bits = 8,
100 			.m_offset = 0,
101 			.n_shift = 18,
102 			.n_bits = 4,
103 			.n_offset = 0,
104 			.od_shift = 16,
105 			.od_bits = 2,
106 			.od_max = 8,
107 			.od_encoding = pll_od_encoding,
108 			.bypass_reg = CGU_REG_CPPCR0,
109 			.bypass_bit = 9,
110 			.enable_bit = 8,
111 			.stable_bit = 10,
112 			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
113 		},
114 	},
115 
116 	[JZ4760_CLK_PLL1] = {
117 		/* TODO: PLL1 can depend on PLL0 */
118 		"pll1", CGU_CLK_PLL,
119 		.parents = { JZ4760_CLK_EXT },
120 		.pll = {
121 			.reg = CGU_REG_CPPCR1,
122 			.rate_multiplier = 1,
123 			.m_shift = 23,
124 			.m_bits = 8,
125 			.m_offset = 0,
126 			.n_shift = 18,
127 			.n_bits = 4,
128 			.n_offset = 0,
129 			.od_shift = 16,
130 			.od_bits = 2,
131 			.od_max = 8,
132 			.od_encoding = pll_od_encoding,
133 			.bypass_bit = -1,
134 			.enable_bit = 7,
135 			.stable_bit = 6,
136 			.calc_m_n_od = jz4760_cgu_calc_m_n_od,
137 		},
138 	},
139 
140 	/* Main clocks */
141 
142 	[JZ4760_CLK_CCLK] = {
143 		"cclk", CGU_CLK_DIV,
144 		/*
145 		 * Disabling the CPU clock or any parent clocks will hang the
146 		 * system; mark it critical.
147 		 */
148 		.flags = CLK_IS_CRITICAL,
149 		.parents = { JZ4760_CLK_PLL0, },
150 		.div = {
151 			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
152 			jz4760_cgu_cpccr_div_table,
153 		},
154 	},
155 	[JZ4760_CLK_HCLK] = {
156 		"hclk", CGU_CLK_DIV,
157 		.parents = { JZ4760_CLK_PLL0, },
158 		.div = {
159 			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
160 			jz4760_cgu_cpccr_div_table,
161 		},
162 	},
163 	[JZ4760_CLK_SCLK] = {
164 		"sclk", CGU_CLK_DIV,
165 		.parents = { JZ4760_CLK_PLL0, },
166 		.div = {
167 			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
168 			jz4760_cgu_cpccr_div_table,
169 		},
170 	},
171 	[JZ4760_CLK_H2CLK] = {
172 		"h2clk", CGU_CLK_DIV,
173 		.parents = { JZ4760_CLK_PLL0, },
174 		.div = {
175 			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
176 			jz4760_cgu_cpccr_div_table,
177 		},
178 	},
179 	[JZ4760_CLK_MCLK] = {
180 		"mclk", CGU_CLK_DIV,
181 		/*
182 		 * Disabling MCLK or its parents will render DRAM
183 		 * inaccessible; mark it critical.
184 		 */
185 		.flags = CLK_IS_CRITICAL,
186 		.parents = { JZ4760_CLK_PLL0, },
187 		.div = {
188 			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
189 			jz4760_cgu_cpccr_div_table,
190 		},
191 	},
192 	[JZ4760_CLK_PCLK] = {
193 		"pclk", CGU_CLK_DIV,
194 		.parents = { JZ4760_CLK_PLL0, },
195 		.div = {
196 			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
197 			jz4760_cgu_cpccr_div_table,
198 		},
199 	},
200 
201 	/* Divided clocks */
202 
203 	[JZ4760_CLK_PLL0_HALF] = {
204 		"pll0_half", CGU_CLK_DIV,
205 		.parents = { JZ4760_CLK_PLL0 },
206 		.div = {
207 			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
208 			jz4760_cgu_pll_half_div_table,
209 		},
210 	},
211 
212 	/* Those divided clocks can connect to PLL0 or PLL1 */
213 
214 	[JZ4760_CLK_UHC] = {
215 		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
216 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
217 		.mux = { CGU_REG_UHCCDR, 31, 1 },
218 		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
219 		.gate = { CGU_REG_CLKGR0, 24 },
220 	},
221 	[JZ4760_CLK_GPU] = {
222 		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
223 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
224 		.mux = { CGU_REG_GPUCDR, 31, 1 },
225 		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
226 		.gate = { CGU_REG_CLKGR1, 9 },
227 	},
228 	[JZ4760_CLK_LPCLK_DIV] = {
229 		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
230 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
231 		.mux = { CGU_REG_LPCDR, 29, 1 },
232 		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
233 	},
234 	[JZ4760_CLK_TVE] = {
235 		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
236 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
237 		.mux = { CGU_REG_LPCDR, 31, 1 },
238 		.gate = { CGU_REG_CLKGR0, 27 },
239 	},
240 	[JZ4760_CLK_LPCLK] = {
241 		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
242 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
243 		.mux = { CGU_REG_LPCDR, 30, 1 },
244 		.gate = { CGU_REG_CLKGR0, 28 },
245 	},
246 	[JZ4760_CLK_GPS] = {
247 		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
248 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
249 		.mux = { CGU_REG_GPSCDR, 31, 1 },
250 		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
251 		.gate = { CGU_REG_CLKGR0, 22 },
252 	},
253 
254 	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
255 
256 	[JZ4760_CLK_PCM] = {
257 		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
258 		.parents = { JZ4760_CLK_EXT, -1,
259 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
260 		.mux = { CGU_REG_PCMCDR, 30, 2 },
261 		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
262 		.gate = { CGU_REG_CLKGR1, 8 },
263 	},
264 	[JZ4760_CLK_I2S] = {
265 		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
266 		.parents = { JZ4760_CLK_EXT, -1,
267 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
268 		.mux = { CGU_REG_I2SCDR, 30, 2 },
269 		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
270 	},
271 	[JZ4760_CLK_OTG] = {
272 		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
273 		.parents = { JZ4760_CLK_EXT, -1,
274 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
275 		.mux = { CGU_REG_USBCDR, 30, 2 },
276 		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
277 		.gate = { CGU_REG_CLKGR0, 2 },
278 	},
279 
280 	/* Those divided clocks can connect to EXT or PLL0 */
281 	[JZ4760_CLK_MMC_MUX] = {
282 		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
283 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
284 		.mux = { CGU_REG_MSCCDR, 31, 1 },
285 		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
286 	},
287 	[JZ4760_CLK_SSI_MUX] = {
288 		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
289 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
290 		.mux = { CGU_REG_SSICDR, 31, 1 },
291 		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
292 	},
293 
294 	/* These divided clock can connect to PLL0 only */
295 	[JZ4760_CLK_CIM] = {
296 		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
297 		.parents = { JZ4760_CLK_PLL0_HALF },
298 		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
299 		.gate = { CGU_REG_CLKGR0, 26 },
300 	},
301 
302 	/* Gate-only clocks */
303 
304 	[JZ4760_CLK_SSI0] = {
305 		"ssi0", CGU_CLK_GATE,
306 		.parents = { JZ4760_CLK_SSI_MUX, },
307 		.gate = { CGU_REG_CLKGR0, 4 },
308 	},
309 	[JZ4760_CLK_SSI1] = {
310 		"ssi1", CGU_CLK_GATE,
311 		.parents = { JZ4760_CLK_SSI_MUX, },
312 		.gate = { CGU_REG_CLKGR0, 19 },
313 	},
314 	[JZ4760_CLK_SSI2] = {
315 		"ssi2", CGU_CLK_GATE,
316 		.parents = { JZ4760_CLK_SSI_MUX, },
317 		.gate = { CGU_REG_CLKGR0, 20 },
318 	},
319 	[JZ4760_CLK_DMA] = {
320 		"dma", CGU_CLK_GATE,
321 		.parents = { JZ4760_CLK_H2CLK, },
322 		.gate = { CGU_REG_CLKGR0, 21 },
323 	},
324 	[JZ4760_CLK_MDMA] = {
325 		"mdma", CGU_CLK_GATE,
326 		.parents = { JZ4760_CLK_HCLK, },
327 		.gate = { CGU_REG_CLKGR0, 25 },
328 	},
329 	[JZ4760_CLK_BDMA] = {
330 		"bdma", CGU_CLK_GATE,
331 		.parents = { JZ4760_CLK_HCLK, },
332 		.gate = { CGU_REG_CLKGR1, 0 },
333 	},
334 	[JZ4760_CLK_I2C0] = {
335 		"i2c0", CGU_CLK_GATE,
336 		.parents = { JZ4760_CLK_EXT, },
337 		.gate = { CGU_REG_CLKGR0, 5 },
338 	},
339 	[JZ4760_CLK_I2C1] = {
340 		"i2c1", CGU_CLK_GATE,
341 		.parents = { JZ4760_CLK_EXT, },
342 		.gate = { CGU_REG_CLKGR0, 6 },
343 	},
344 	[JZ4760_CLK_UART0] = {
345 		"uart0", CGU_CLK_GATE,
346 		.parents = { JZ4760_CLK_EXT, },
347 		.gate = { CGU_REG_CLKGR0, 15 },
348 	},
349 	[JZ4760_CLK_UART1] = {
350 		"uart1", CGU_CLK_GATE,
351 		.parents = { JZ4760_CLK_EXT, },
352 		.gate = { CGU_REG_CLKGR0, 16 },
353 	},
354 	[JZ4760_CLK_UART2] = {
355 		"uart2", CGU_CLK_GATE,
356 		.parents = { JZ4760_CLK_EXT, },
357 		.gate = { CGU_REG_CLKGR0, 17 },
358 	},
359 	[JZ4760_CLK_UART3] = {
360 		"uart3", CGU_CLK_GATE,
361 		.parents = { JZ4760_CLK_EXT, },
362 		.gate = { CGU_REG_CLKGR0, 18 },
363 	},
364 	[JZ4760_CLK_IPU] = {
365 		"ipu", CGU_CLK_GATE,
366 		.parents = { JZ4760_CLK_HCLK, },
367 		.gate = { CGU_REG_CLKGR0, 29 },
368 	},
369 	[JZ4760_CLK_ADC] = {
370 		"adc", CGU_CLK_GATE,
371 		.parents = { JZ4760_CLK_EXT, },
372 		.gate = { CGU_REG_CLKGR0, 14 },
373 	},
374 	[JZ4760_CLK_AIC] = {
375 		"aic", CGU_CLK_GATE,
376 		.parents = { JZ4760_CLK_EXT, },
377 		.gate = { CGU_REG_CLKGR0, 8 },
378 	},
379 	[JZ4760_CLK_VPU] = {
380 		"vpu", CGU_CLK_GATE,
381 		.parents = { JZ4760_CLK_HCLK, },
382 		.gate = { CGU_REG_LCR, 30, false, 150 },
383 	},
384 	[JZ4760_CLK_MMC0] = {
385 		"mmc0", CGU_CLK_GATE,
386 		.parents = { JZ4760_CLK_MMC_MUX, },
387 		.gate = { CGU_REG_CLKGR0, 3 },
388 	},
389 	[JZ4760_CLK_MMC1] = {
390 		"mmc1", CGU_CLK_GATE,
391 		.parents = { JZ4760_CLK_MMC_MUX, },
392 		.gate = { CGU_REG_CLKGR0, 11 },
393 	},
394 	[JZ4760_CLK_MMC2] = {
395 		"mmc2", CGU_CLK_GATE,
396 		.parents = { JZ4760_CLK_MMC_MUX, },
397 		.gate = { CGU_REG_CLKGR0, 12 },
398 	},
399 	[JZ4760_CLK_UHC_PHY] = {
400 		"uhc_phy", CGU_CLK_GATE,
401 		.parents = { JZ4760_CLK_UHC, },
402 		.gate = { CGU_REG_OPCR, 5 },
403 	},
404 	[JZ4760_CLK_OTG_PHY] = {
405 		"usb_phy", CGU_CLK_GATE,
406 		.parents = { JZ4760_CLK_OTG },
407 		.gate = { CGU_REG_OPCR, 7, true, 50 },
408 	},
409 
410 	/* Custom clocks */
411 	[JZ4760_CLK_EXT512] = {
412 		"ext/512", CGU_CLK_FIXDIV,
413 		.parents = { JZ4760_CLK_EXT },
414 		.fixdiv = { 512 },
415 	},
416 	[JZ4760_CLK_RTC] = {
417 		"rtc", CGU_CLK_MUX,
418 		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
419 		.mux = { CGU_REG_OPCR, 2, 1},
420 	},
421 };
422 
jz4760_cgu_init(struct device_node * np)423 static void __init jz4760_cgu_init(struct device_node *np)
424 {
425 	struct ingenic_cgu *cgu;
426 	int retval;
427 
428 	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
429 			      ARRAY_SIZE(jz4760_cgu_clocks), np);
430 	if (!cgu) {
431 		pr_err("%s: failed to initialise CGU\n", __func__);
432 		return;
433 	}
434 
435 	retval = ingenic_cgu_register_clocks(cgu);
436 	if (retval)
437 		pr_err("%s: failed to register CGU Clocks\n", __func__);
438 
439 	ingenic_cgu_register_syscore_ops(cgu);
440 }
441 
442 /* We only probe via devicetree, no need for a platform driver */
443 CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
444 
445 /* JZ4760B has some small differences, but we don't implement them. */
446 CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
447