xref: /linux/drivers/clk/clk-nomadik.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Nomadik clock implementation
4  * Copyright (C) 2013 ST-Ericsson AB
5  * Author: Linus Walleij <linus.walleij@linaro.org>
6  */
7 
8 #define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
9 
10 #include <linux/bitops.h>
11 #include <linux/slab.h>
12 #include <linux/err.h>
13 #include <linux/io.h>
14 #include <linux/clk-provider.h>
15 #include <linux/of.h>
16 #include <linux/of_address.h>
17 #include <linux/debugfs.h>
18 #include <linux/seq_file.h>
19 #include <linux/spinlock.h>
20 #include <linux/reboot.h>
21 
22 /*
23  * The Nomadik clock tree is described in the STN8815A12 DB V4.2
24  * reference manual for the chip, page 94 ff.
25  * Clock IDs are in the STn8815 Reference Manual table 3, page 27.
26  */
27 
28 #define SRC_CR			0x00U
29 #define SRC_CR_T0_ENSEL		BIT(15)
30 #define SRC_CR_T1_ENSEL		BIT(17)
31 #define SRC_CR_T2_ENSEL		BIT(19)
32 #define SRC_CR_T3_ENSEL		BIT(21)
33 #define SRC_CR_T4_ENSEL		BIT(23)
34 #define SRC_CR_T5_ENSEL		BIT(25)
35 #define SRC_CR_T6_ENSEL		BIT(27)
36 #define SRC_CR_T7_ENSEL		BIT(29)
37 #define SRC_XTALCR		0x0CU
38 #define SRC_XTALCR_XTALTIMEN	BIT(20)
39 #define SRC_XTALCR_SXTALDIS	BIT(19)
40 #define SRC_XTALCR_MXTALSTAT	BIT(2)
41 #define SRC_XTALCR_MXTALEN	BIT(1)
42 #define SRC_XTALCR_MXTALOVER	BIT(0)
43 #define SRC_PLLCR		0x10U
44 #define SRC_PLLCR_PLLTIMEN	BIT(29)
45 #define SRC_PLLCR_PLL2EN	BIT(28)
46 #define SRC_PLLCR_PLL1STAT	BIT(2)
47 #define SRC_PLLCR_PLL1EN	BIT(1)
48 #define SRC_PLLCR_PLL1OVER	BIT(0)
49 #define SRC_PLLFR		0x14U
50 #define SRC_PCKEN0		0x24U
51 #define SRC_PCKDIS0		0x28U
52 #define SRC_PCKENSR0		0x2CU
53 #define SRC_PCKSR0		0x30U
54 #define SRC_PCKEN1		0x34U
55 #define SRC_PCKDIS1		0x38U
56 #define SRC_PCKENSR1		0x3CU
57 #define SRC_PCKSR1		0x40U
58 
59 /* Lock protecting the SRC_CR register */
60 static DEFINE_SPINLOCK(src_lock);
61 /* Base address of the SRC */
62 static void __iomem *src_base;
63 
nomadik_clk_reboot_handler(struct notifier_block * this,unsigned long code,void * unused)64 static int nomadik_clk_reboot_handler(struct notifier_block *this,
65 				unsigned long code,
66 				void *unused)
67 {
68 	u32 val;
69 
70 	/* The main chrystal need to be enabled for reboot to work */
71 	val = readl(src_base + SRC_XTALCR);
72 	val &= ~SRC_XTALCR_MXTALOVER;
73 	val |= SRC_XTALCR_MXTALEN;
74 	pr_crit("force-enabling MXTALO\n");
75 	writel(val, src_base + SRC_XTALCR);
76 	return NOTIFY_OK;
77 }
78 
79 static struct notifier_block nomadik_clk_reboot_notifier = {
80 	.notifier_call = nomadik_clk_reboot_handler,
81 };
82 
83 static const struct of_device_id nomadik_src_match[] __initconst = {
84 	{ .compatible = "stericsson,nomadik-src" },
85 	{ /* sentinel */ }
86 };
87 
nomadik_src_init(void)88 static void __init nomadik_src_init(void)
89 {
90 	struct device_node *np;
91 	u32 val;
92 
93 	np = of_find_matching_node(NULL, nomadik_src_match);
94 	if (!np) {
95 		pr_crit("no matching node for SRC, aborting clock init\n");
96 		return;
97 	}
98 	src_base = of_iomap(np, 0);
99 	if (!src_base) {
100 		pr_err("%s: must have src parent node with REGS (%pOFn)\n",
101 		       __func__, np);
102 		goto out_put;
103 	}
104 
105 	/* Set all timers to use the 2.4 MHz TIMCLK */
106 	val = readl(src_base + SRC_CR);
107 	val |= SRC_CR_T0_ENSEL;
108 	val |= SRC_CR_T1_ENSEL;
109 	val |= SRC_CR_T2_ENSEL;
110 	val |= SRC_CR_T3_ENSEL;
111 	val |= SRC_CR_T4_ENSEL;
112 	val |= SRC_CR_T5_ENSEL;
113 	val |= SRC_CR_T6_ENSEL;
114 	val |= SRC_CR_T7_ENSEL;
115 	writel(val, src_base + SRC_CR);
116 
117 	val = readl(src_base + SRC_XTALCR);
118 	pr_info("SXTALO is %s\n",
119 		(val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
120 	pr_info("MXTAL is %s\n",
121 		(val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled");
122 	if (of_property_read_bool(np, "disable-sxtalo")) {
123 		/* The machine uses an external oscillator circuit */
124 		val |= SRC_XTALCR_SXTALDIS;
125 		pr_info("disabling SXTALO\n");
126 	}
127 	if (of_property_read_bool(np, "disable-mxtalo")) {
128 		/* Disable this too: also run by external oscillator */
129 		val |= SRC_XTALCR_MXTALOVER;
130 		val &= ~SRC_XTALCR_MXTALEN;
131 		pr_info("disabling MXTALO\n");
132 	}
133 	writel(val, src_base + SRC_XTALCR);
134 	register_reboot_notifier(&nomadik_clk_reboot_notifier);
135 
136 out_put:
137 	of_node_put(np);
138 }
139 
140 /**
141  * struct clk_pll - Nomadik PLL clock
142  * @hw: corresponding clock hardware entry
143  * @id: PLL instance: 1 or 2
144  */
145 struct clk_pll {
146 	struct clk_hw hw;
147 	int id;
148 };
149 
150 /**
151  * struct clk_src - Nomadik src clock
152  * @hw: corresponding clock hardware entry
153  * @id: the clock ID
154  * @group1: true if the clock is in group1, else it is in group0
155  * @clkbit: bit 0...31 corresponding to the clock in each clock register
156  */
157 struct clk_src {
158 	struct clk_hw hw;
159 	int id;
160 	bool group1;
161 	u32 clkbit;
162 };
163 
164 #define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
165 #define to_src(_hw) container_of(_hw, struct clk_src, hw)
166 
pll_clk_enable(struct clk_hw * hw)167 static int pll_clk_enable(struct clk_hw *hw)
168 {
169 	struct clk_pll *pll = to_pll(hw);
170 	u32 val;
171 
172 	spin_lock(&src_lock);
173 	val = readl(src_base + SRC_PLLCR);
174 	if (pll->id == 1) {
175 		if (val & SRC_PLLCR_PLL1OVER) {
176 			val |= SRC_PLLCR_PLL1EN;
177 			writel(val, src_base + SRC_PLLCR);
178 		}
179 	} else if (pll->id == 2) {
180 		val |= SRC_PLLCR_PLL2EN;
181 		writel(val, src_base + SRC_PLLCR);
182 	}
183 	spin_unlock(&src_lock);
184 	return 0;
185 }
186 
pll_clk_disable(struct clk_hw * hw)187 static void pll_clk_disable(struct clk_hw *hw)
188 {
189 	struct clk_pll *pll = to_pll(hw);
190 	u32 val;
191 
192 	spin_lock(&src_lock);
193 	val = readl(src_base + SRC_PLLCR);
194 	if (pll->id == 1) {
195 		if (val & SRC_PLLCR_PLL1OVER) {
196 			val &= ~SRC_PLLCR_PLL1EN;
197 			writel(val, src_base + SRC_PLLCR);
198 		}
199 	} else if (pll->id == 2) {
200 		val &= ~SRC_PLLCR_PLL2EN;
201 		writel(val, src_base + SRC_PLLCR);
202 	}
203 	spin_unlock(&src_lock);
204 }
205 
pll_clk_is_enabled(struct clk_hw * hw)206 static int pll_clk_is_enabled(struct clk_hw *hw)
207 {
208 	struct clk_pll *pll = to_pll(hw);
209 	u32 val;
210 
211 	val = readl(src_base + SRC_PLLCR);
212 	if (pll->id == 1) {
213 		if (val & SRC_PLLCR_PLL1OVER)
214 			return !!(val & SRC_PLLCR_PLL1EN);
215 	} else if (pll->id == 2) {
216 		return !!(val & SRC_PLLCR_PLL2EN);
217 	}
218 	return 1;
219 }
220 
pll_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)221 static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
222 					  unsigned long parent_rate)
223 {
224 	struct clk_pll *pll = to_pll(hw);
225 	u32 val;
226 
227 	val = readl(src_base + SRC_PLLFR);
228 
229 	if (pll->id == 1) {
230 		u8 mul;
231 		u8 div;
232 
233 		mul = (val >> 8) & 0x3FU;
234 		mul += 2;
235 		div = val & 0x07U;
236 		return (parent_rate * mul) >> div;
237 	}
238 
239 	if (pll->id == 2) {
240 		u8 mul;
241 
242 		mul = (val >> 24) & 0x3FU;
243 		mul += 2;
244 		return (parent_rate * mul);
245 	}
246 
247 	/* Unknown PLL */
248 	return 0;
249 }
250 
251 
252 static const struct clk_ops pll_clk_ops = {
253 	.enable = pll_clk_enable,
254 	.disable = pll_clk_disable,
255 	.is_enabled = pll_clk_is_enabled,
256 	.recalc_rate = pll_clk_recalc_rate,
257 };
258 
259 static struct clk_hw * __init
pll_clk_register(struct device * dev,const char * name,const char * parent_name,u32 id)260 pll_clk_register(struct device *dev, const char *name,
261 		 const char *parent_name, u32 id)
262 {
263 	int ret;
264 	struct clk_pll *pll;
265 	struct clk_init_data init;
266 
267 	if (id != 1 && id != 2) {
268 		pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
269 		return ERR_PTR(-EINVAL);
270 	}
271 
272 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
273 	if (!pll)
274 		return ERR_PTR(-ENOMEM);
275 
276 	init.name = name;
277 	init.ops = &pll_clk_ops;
278 	init.parent_names = (parent_name ? &parent_name : NULL);
279 	init.num_parents = (parent_name ? 1 : 0);
280 	pll->hw.init = &init;
281 	pll->id = id;
282 
283 	pr_debug("register PLL1 clock \"%s\"\n", name);
284 
285 	ret = clk_hw_register(dev, &pll->hw);
286 	if (ret) {
287 		kfree(pll);
288 		return ERR_PTR(ret);
289 	}
290 
291 	return &pll->hw;
292 }
293 
294 /*
295  * The Nomadik SRC clocks are gated, but not in the sense that
296  * you read-modify-write a register. Instead there are separate
297  * clock enable and clock disable registers. Writing a '1' bit in
298  * the enable register for a certain clock ungates that clock without
299  * affecting the other clocks. The disable register works the opposite
300  * way.
301  */
302 
src_clk_enable(struct clk_hw * hw)303 static int src_clk_enable(struct clk_hw *hw)
304 {
305 	struct clk_src *sclk = to_src(hw);
306 	u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
307 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
308 
309 	writel(sclk->clkbit, src_base + enreg);
310 	/* spin until enabled */
311 	while (!(readl(src_base + sreg) & sclk->clkbit))
312 		cpu_relax();
313 	return 0;
314 }
315 
src_clk_disable(struct clk_hw * hw)316 static void src_clk_disable(struct clk_hw *hw)
317 {
318 	struct clk_src *sclk = to_src(hw);
319 	u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
320 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
321 
322 	writel(sclk->clkbit, src_base + disreg);
323 	/* spin until disabled */
324 	while (readl(src_base + sreg) & sclk->clkbit)
325 		cpu_relax();
326 }
327 
src_clk_is_enabled(struct clk_hw * hw)328 static int src_clk_is_enabled(struct clk_hw *hw)
329 {
330 	struct clk_src *sclk = to_src(hw);
331 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
332 	u32 val = readl(src_base + sreg);
333 
334 	return !!(val & sclk->clkbit);
335 }
336 
337 static unsigned long
src_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)338 src_clk_recalc_rate(struct clk_hw *hw,
339 		    unsigned long parent_rate)
340 {
341 	return parent_rate;
342 }
343 
344 static const struct clk_ops src_clk_ops = {
345 	.enable = src_clk_enable,
346 	.disable = src_clk_disable,
347 	.is_enabled = src_clk_is_enabled,
348 	.recalc_rate = src_clk_recalc_rate,
349 };
350 
351 static struct clk_hw * __init
src_clk_register(struct device * dev,const char * name,const char * parent_name,u8 id)352 src_clk_register(struct device *dev, const char *name,
353 		 const char *parent_name, u8 id)
354 {
355 	int ret;
356 	struct clk_src *sclk;
357 	struct clk_init_data init;
358 
359 	sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
360 	if (!sclk)
361 		return ERR_PTR(-ENOMEM);
362 
363 	init.name = name;
364 	init.ops = &src_clk_ops;
365 	/* Do not force-disable the static SDRAM controller */
366 	if (id == 2)
367 		init.flags = CLK_IGNORE_UNUSED;
368 	else
369 		init.flags = 0;
370 	init.parent_names = (parent_name ? &parent_name : NULL);
371 	init.num_parents = (parent_name ? 1 : 0);
372 	sclk->hw.init = &init;
373 	sclk->id = id;
374 	sclk->group1 = (id > 31);
375 	sclk->clkbit = BIT(id & 0x1f);
376 
377 	pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
378 		 name, id, sclk->group1, sclk->clkbit);
379 
380 	ret = clk_hw_register(dev, &sclk->hw);
381 	if (ret) {
382 		kfree(sclk);
383 		return ERR_PTR(ret);
384 	}
385 
386 	return &sclk->hw;
387 }
388 
389 #ifdef CONFIG_DEBUG_FS
390 
391 static u32 src_pcksr0_boot;
392 static u32 src_pcksr1_boot;
393 
394 static const char * const src_clk_names[] = {
395 	"HCLKDMA0  ",
396 	"HCLKSMC   ",
397 	"HCLKSDRAM ",
398 	"HCLKDMA1  ",
399 	"HCLKCLCD  ",
400 	"PCLKIRDA  ",
401 	"PCLKSSP   ",
402 	"PCLKUART0 ",
403 	"PCLKSDI   ",
404 	"PCLKI2C0  ",
405 	"PCLKI2C1  ",
406 	"PCLKUART1 ",
407 	"PCLMSP0   ",
408 	"HCLKUSB   ",
409 	"HCLKDIF   ",
410 	"HCLKSAA   ",
411 	"HCLKSVA   ",
412 	"PCLKHSI   ",
413 	"PCLKXTI   ",
414 	"PCLKUART2 ",
415 	"PCLKMSP1  ",
416 	"PCLKMSP2  ",
417 	"PCLKOWM   ",
418 	"HCLKHPI   ",
419 	"PCLKSKE   ",
420 	"PCLKHSEM  ",
421 	"HCLK3D    ",
422 	"HCLKHASH  ",
423 	"HCLKCRYP  ",
424 	"PCLKMSHC  ",
425 	"HCLKUSBM  ",
426 	"HCLKRNG   ",
427 	"RESERVED  ",
428 	"RESERVED  ",
429 	"RESERVED  ",
430 	"RESERVED  ",
431 	"CLDCLK    ",
432 	"IRDACLK   ",
433 	"SSPICLK   ",
434 	"UART0CLK  ",
435 	"SDICLK    ",
436 	"I2C0CLK   ",
437 	"I2C1CLK   ",
438 	"UART1CLK  ",
439 	"MSPCLK0   ",
440 	"USBCLK    ",
441 	"DIFCLK    ",
442 	"IPI2CCLK  ",
443 	"IPBMCCLK  ",
444 	"HSICLKRX  ",
445 	"HSICLKTX  ",
446 	"UART2CLK  ",
447 	"MSPCLK1   ",
448 	"MSPCLK2   ",
449 	"OWMCLK    ",
450 	"RESERVED  ",
451 	"SKECLK    ",
452 	"RESERVED  ",
453 	"3DCLK     ",
454 	"PCLKMSP3  ",
455 	"MSPCLK3   ",
456 	"MSHCCLK   ",
457 	"USBMCLK   ",
458 	"RNGCCLK   ",
459 };
460 
nomadik_src_clk_debugfs_show(struct seq_file * s,void * what)461 static int nomadik_src_clk_debugfs_show(struct seq_file *s, void *what)
462 {
463 	int i;
464 	u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
465 	u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
466 	u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
467 	u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
468 
469 	seq_puts(s, "Clock:      Boot:   Now:    Request: ASKED:\n");
470 	for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
471 		u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
472 		u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
473 		u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
474 		u32 mask = BIT(i & 0x1f);
475 
476 		seq_printf(s, "%s  %s     %s     %s\n",
477 			   src_clk_names[i],
478 			   (pcksrb & mask) ? "on " : "off",
479 			   (pcksr & mask) ? "on " : "off",
480 			   (pckreq & mask) ? "on " : "off");
481 	}
482 	return 0;
483 }
484 
485 DEFINE_SHOW_ATTRIBUTE(nomadik_src_clk_debugfs);
486 
nomadik_src_clk_init_debugfs(void)487 static int __init nomadik_src_clk_init_debugfs(void)
488 {
489 	/* Vital for multiplatform */
490 	if (!src_base)
491 		return -ENODEV;
492 	src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
493 	src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
494 	debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
495 			    NULL, NULL, &nomadik_src_clk_debugfs_fops);
496 	return 0;
497 }
498 device_initcall(nomadik_src_clk_init_debugfs);
499 
500 #endif
501 
of_nomadik_pll_setup(struct device_node * np)502 static void __init of_nomadik_pll_setup(struct device_node *np)
503 {
504 	struct clk_hw *hw;
505 	const char *clk_name = np->name;
506 	const char *parent_name;
507 	u32 pll_id;
508 
509 	if (!src_base)
510 		nomadik_src_init();
511 
512 	if (of_property_read_u32(np, "pll-id", &pll_id)) {
513 		pr_err("%s: PLL \"%s\" missing pll-id property\n",
514 			__func__, clk_name);
515 		return;
516 	}
517 	parent_name = of_clk_get_parent_name(np, 0);
518 	hw = pll_clk_register(NULL, clk_name, parent_name, pll_id);
519 	if (!IS_ERR(hw))
520 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
521 }
522 CLK_OF_DECLARE(nomadik_pll_clk,
523 	"st,nomadik-pll-clock", of_nomadik_pll_setup);
524 
of_nomadik_hclk_setup(struct device_node * np)525 static void __init of_nomadik_hclk_setup(struct device_node *np)
526 {
527 	struct clk_hw *hw;
528 	const char *clk_name = np->name;
529 	const char *parent_name;
530 
531 	if (!src_base)
532 		nomadik_src_init();
533 
534 	parent_name = of_clk_get_parent_name(np, 0);
535 	/*
536 	 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
537 	 */
538 	hw = clk_hw_register_divider(NULL, clk_name, parent_name,
539 			   0, src_base + SRC_CR,
540 			   13, 2,
541 			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
542 			   &src_lock);
543 	if (!IS_ERR(hw))
544 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
545 }
546 CLK_OF_DECLARE(nomadik_hclk_clk,
547 	"st,nomadik-hclk-clock", of_nomadik_hclk_setup);
548 
of_nomadik_src_clk_setup(struct device_node * np)549 static void __init of_nomadik_src_clk_setup(struct device_node *np)
550 {
551 	struct clk_hw *hw;
552 	const char *clk_name = np->name;
553 	const char *parent_name;
554 	u32 clk_id;
555 
556 	if (!src_base)
557 		nomadik_src_init();
558 
559 	if (of_property_read_u32(np, "clock-id", &clk_id)) {
560 		pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
561 			__func__, clk_name);
562 		return;
563 	}
564 	parent_name = of_clk_get_parent_name(np, 0);
565 	hw = src_clk_register(NULL, clk_name, parent_name, clk_id);
566 	if (!IS_ERR(hw))
567 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
568 }
569 CLK_OF_DECLARE(nomadik_src_clk,
570 	"st,nomadik-src-clock", of_nomadik_src_clk_setup);
571