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
44static const s8 pll_od_encoding[8] = {
45	0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
46};
47
48static const u8 jz4760_cgu_cpccr_div_table[] = {
49	1, 2, 3, 4, 6, 8,
50};
51
52static const u8 jz4760_cgu_pll_half_div_table[] = {
53	2, 1,
54};
55
56static void
57jz4760_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
83static 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
423static 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 */
443CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
444
445/* JZ4760B has some small differences, but we don't implement them. */
446CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
447