• 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/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 		.parents = { JZ4760_CLK_PLL0, },
145 		.div = {
146 			CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
147 			jz4760_cgu_cpccr_div_table,
148 		},
149 	},
150 	[JZ4760_CLK_HCLK] = {
151 		"hclk", CGU_CLK_DIV,
152 		.parents = { JZ4760_CLK_PLL0, },
153 		.div = {
154 			CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
155 			jz4760_cgu_cpccr_div_table,
156 		},
157 	},
158 	[JZ4760_CLK_SCLK] = {
159 		"sclk", CGU_CLK_DIV,
160 		.parents = { JZ4760_CLK_PLL0, },
161 		.div = {
162 			CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
163 			jz4760_cgu_cpccr_div_table,
164 		},
165 	},
166 	[JZ4760_CLK_H2CLK] = {
167 		"h2clk", CGU_CLK_DIV,
168 		.parents = { JZ4760_CLK_PLL0, },
169 		.div = {
170 			CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
171 			jz4760_cgu_cpccr_div_table,
172 		},
173 	},
174 	[JZ4760_CLK_MCLK] = {
175 		"mclk", CGU_CLK_DIV,
176 		.parents = { JZ4760_CLK_PLL0, },
177 		.div = {
178 			CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
179 			jz4760_cgu_cpccr_div_table,
180 		},
181 	},
182 	[JZ4760_CLK_PCLK] = {
183 		"pclk", CGU_CLK_DIV,
184 		.parents = { JZ4760_CLK_PLL0, },
185 		.div = {
186 			CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
187 			jz4760_cgu_cpccr_div_table,
188 		},
189 	},
190 
191 	/* Divided clocks */
192 
193 	[JZ4760_CLK_PLL0_HALF] = {
194 		"pll0_half", CGU_CLK_DIV,
195 		.parents = { JZ4760_CLK_PLL0 },
196 		.div = {
197 			CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
198 			jz4760_cgu_pll_half_div_table,
199 		},
200 	},
201 
202 	/* Those divided clocks can connect to PLL0 or PLL1 */
203 
204 	[JZ4760_CLK_UHC] = {
205 		"uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
206 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
207 		.mux = { CGU_REG_UHCCDR, 31, 1 },
208 		.div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
209 		.gate = { CGU_REG_CLKGR0, 24 },
210 	},
211 	[JZ4760_CLK_GPU] = {
212 		"gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
213 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
214 		.mux = { CGU_REG_GPUCDR, 31, 1 },
215 		.div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
216 		.gate = { CGU_REG_CLKGR1, 9 },
217 	},
218 	[JZ4760_CLK_LPCLK_DIV] = {
219 		"lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
220 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
221 		.mux = { CGU_REG_LPCDR, 29, 1 },
222 		.div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
223 	},
224 	[JZ4760_CLK_TVE] = {
225 		"tve", CGU_CLK_GATE | CGU_CLK_MUX,
226 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
227 		.mux = { CGU_REG_LPCDR, 31, 1 },
228 		.gate = { CGU_REG_CLKGR0, 27 },
229 	},
230 	[JZ4760_CLK_LPCLK] = {
231 		"lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
232 		.parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
233 		.mux = { CGU_REG_LPCDR, 30, 1 },
234 		.gate = { CGU_REG_CLKGR0, 28 },
235 	},
236 	[JZ4760_CLK_GPS] = {
237 		"gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
238 		.parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
239 		.mux = { CGU_REG_GPSCDR, 31, 1 },
240 		.div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
241 		.gate = { CGU_REG_CLKGR0, 22 },
242 	},
243 
244 	/* Those divided clocks can connect to EXT, PLL0 or PLL1 */
245 
246 	[JZ4760_CLK_PCM] = {
247 		"pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
248 		.parents = { JZ4760_CLK_EXT, -1,
249 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
250 		.mux = { CGU_REG_PCMCDR, 30, 2 },
251 		.div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
252 		.gate = { CGU_REG_CLKGR1, 8 },
253 	},
254 	[JZ4760_CLK_I2S] = {
255 		"i2s", CGU_CLK_DIV | CGU_CLK_MUX,
256 		.parents = { JZ4760_CLK_EXT, -1,
257 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
258 		.mux = { CGU_REG_I2SCDR, 30, 2 },
259 		.div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
260 	},
261 	[JZ4760_CLK_OTG] = {
262 		"usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
263 		.parents = { JZ4760_CLK_EXT, -1,
264 			JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
265 		.mux = { CGU_REG_USBCDR, 30, 2 },
266 		.div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
267 		.gate = { CGU_REG_CLKGR0, 2 },
268 	},
269 
270 	/* Those divided clocks can connect to EXT or PLL0 */
271 	[JZ4760_CLK_MMC_MUX] = {
272 		"mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
273 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
274 		.mux = { CGU_REG_MSCCDR, 31, 1 },
275 		.div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
276 	},
277 	[JZ4760_CLK_SSI_MUX] = {
278 		"ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
279 		.parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
280 		.mux = { CGU_REG_SSICDR, 31, 1 },
281 		.div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
282 	},
283 
284 	/* These divided clock can connect to PLL0 only */
285 	[JZ4760_CLK_CIM] = {
286 		"cim", CGU_CLK_DIV | CGU_CLK_GATE,
287 		.parents = { JZ4760_CLK_PLL0_HALF },
288 		.div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
289 		.gate = { CGU_REG_CLKGR0, 26 },
290 	},
291 
292 	/* Gate-only clocks */
293 
294 	[JZ4760_CLK_SSI0] = {
295 		"ssi0", CGU_CLK_GATE,
296 		.parents = { JZ4760_CLK_SSI_MUX, },
297 		.gate = { CGU_REG_CLKGR0, 4 },
298 	},
299 	[JZ4760_CLK_SSI1] = {
300 		"ssi1", CGU_CLK_GATE,
301 		.parents = { JZ4760_CLK_SSI_MUX, },
302 		.gate = { CGU_REG_CLKGR0, 19 },
303 	},
304 	[JZ4760_CLK_SSI2] = {
305 		"ssi2", CGU_CLK_GATE,
306 		.parents = { JZ4760_CLK_SSI_MUX, },
307 		.gate = { CGU_REG_CLKGR0, 20 },
308 	},
309 	[JZ4760_CLK_DMA] = {
310 		"dma", CGU_CLK_GATE,
311 		.parents = { JZ4760_CLK_H2CLK, },
312 		.gate = { CGU_REG_CLKGR0, 21 },
313 	},
314 	[JZ4760_CLK_I2C0] = {
315 		"i2c0", CGU_CLK_GATE,
316 		.parents = { JZ4760_CLK_EXT, },
317 		.gate = { CGU_REG_CLKGR0, 5 },
318 	},
319 	[JZ4760_CLK_I2C1] = {
320 		"i2c1", CGU_CLK_GATE,
321 		.parents = { JZ4760_CLK_EXT, },
322 		.gate = { CGU_REG_CLKGR0, 6 },
323 	},
324 	[JZ4760_CLK_UART0] = {
325 		"uart0", CGU_CLK_GATE,
326 		.parents = { JZ4760_CLK_EXT, },
327 		.gate = { CGU_REG_CLKGR0, 15 },
328 	},
329 	[JZ4760_CLK_UART1] = {
330 		"uart1", CGU_CLK_GATE,
331 		.parents = { JZ4760_CLK_EXT, },
332 		.gate = { CGU_REG_CLKGR0, 16 },
333 	},
334 	[JZ4760_CLK_UART2] = {
335 		"uart2", CGU_CLK_GATE,
336 		.parents = { JZ4760_CLK_EXT, },
337 		.gate = { CGU_REG_CLKGR0, 17 },
338 	},
339 	[JZ4760_CLK_UART3] = {
340 		"uart3", CGU_CLK_GATE,
341 		.parents = { JZ4760_CLK_EXT, },
342 		.gate = { CGU_REG_CLKGR0, 18 },
343 	},
344 	[JZ4760_CLK_IPU] = {
345 		"ipu", CGU_CLK_GATE,
346 		.parents = { JZ4760_CLK_HCLK, },
347 		.gate = { CGU_REG_CLKGR0, 29 },
348 	},
349 	[JZ4760_CLK_ADC] = {
350 		"adc", CGU_CLK_GATE,
351 		.parents = { JZ4760_CLK_EXT, },
352 		.gate = { CGU_REG_CLKGR0, 14 },
353 	},
354 	[JZ4760_CLK_AIC] = {
355 		"aic", CGU_CLK_GATE,
356 		.parents = { JZ4760_CLK_EXT, },
357 		.gate = { CGU_REG_CLKGR0, 8 },
358 	},
359 	[JZ4760_CLK_VPU] = {
360 		"vpu", CGU_CLK_GATE,
361 		.parents = { JZ4760_CLK_HCLK, },
362 		.gate = { CGU_REG_LCR, 30, false, 150 },
363 	},
364 	[JZ4760_CLK_MMC0] = {
365 		"mmc0", CGU_CLK_GATE,
366 		.parents = { JZ4760_CLK_MMC_MUX, },
367 		.gate = { CGU_REG_CLKGR0, 3 },
368 	},
369 	[JZ4760_CLK_MMC1] = {
370 		"mmc1", CGU_CLK_GATE,
371 		.parents = { JZ4760_CLK_MMC_MUX, },
372 		.gate = { CGU_REG_CLKGR0, 11 },
373 	},
374 	[JZ4760_CLK_MMC2] = {
375 		"mmc2", CGU_CLK_GATE,
376 		.parents = { JZ4760_CLK_MMC_MUX, },
377 		.gate = { CGU_REG_CLKGR0, 12 },
378 	},
379 	[JZ4760_CLK_UHC_PHY] = {
380 		"uhc_phy", CGU_CLK_GATE,
381 		.parents = { JZ4760_CLK_UHC, },
382 		.gate = { CGU_REG_OPCR, 5 },
383 	},
384 	[JZ4760_CLK_OTG_PHY] = {
385 		"usb_phy", CGU_CLK_GATE,
386 		.parents = { JZ4760_CLK_OTG },
387 		.gate = { CGU_REG_OPCR, 7, true, 50 },
388 	},
389 
390 	/* Custom clocks */
391 	[JZ4760_CLK_EXT512] = {
392 		"ext/512", CGU_CLK_FIXDIV,
393 		.parents = { JZ4760_CLK_EXT },
394 		.fixdiv = { 512 },
395 	},
396 	[JZ4760_CLK_RTC] = {
397 		"rtc", CGU_CLK_MUX,
398 		.parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
399 		.mux = { CGU_REG_OPCR, 2, 1},
400 	},
401 };
402 
jz4760_cgu_init(struct device_node * np)403 static void __init jz4760_cgu_init(struct device_node *np)
404 {
405 	struct ingenic_cgu *cgu;
406 	int retval;
407 
408 	cgu = ingenic_cgu_new(jz4760_cgu_clocks,
409 			      ARRAY_SIZE(jz4760_cgu_clocks), np);
410 	if (!cgu) {
411 		pr_err("%s: failed to initialise CGU\n", __func__);
412 		return;
413 	}
414 
415 	retval = ingenic_cgu_register_clocks(cgu);
416 	if (retval)
417 		pr_err("%s: failed to register CGU Clocks\n", __func__);
418 
419 	ingenic_cgu_register_syscore_ops(cgu);
420 }
421 
422 /* We only probe via devicetree, no need for a platform driver */
423 CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
424 
425 /* JZ4760B has some small differences, but we don't implement them. */
426 CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
427