• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 		return;
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 
137 /**
138  * struct clk_pll1 - Nomadik PLL1 clock
139  * @hw: corresponding clock hardware entry
140  * @id: PLL instance: 1 or 2
141  */
142 struct clk_pll {
143 	struct clk_hw hw;
144 	int id;
145 };
146 
147 /**
148  * struct clk_src - Nomadik src clock
149  * @hw: corresponding clock hardware entry
150  * @id: the clock ID
151  * @group1: true if the clock is in group1, else it is in group0
152  * @clkbit: bit 0...31 corresponding to the clock in each clock register
153  */
154 struct clk_src {
155 	struct clk_hw hw;
156 	int id;
157 	bool group1;
158 	u32 clkbit;
159 };
160 
161 #define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
162 #define to_src(_hw) container_of(_hw, struct clk_src, hw)
163 
pll_clk_enable(struct clk_hw * hw)164 static int pll_clk_enable(struct clk_hw *hw)
165 {
166 	struct clk_pll *pll = to_pll(hw);
167 	u32 val;
168 
169 	spin_lock(&src_lock);
170 	val = readl(src_base + SRC_PLLCR);
171 	if (pll->id == 1) {
172 		if (val & SRC_PLLCR_PLL1OVER) {
173 			val |= SRC_PLLCR_PLL1EN;
174 			writel(val, src_base + SRC_PLLCR);
175 		}
176 	} else if (pll->id == 2) {
177 		val |= SRC_PLLCR_PLL2EN;
178 		writel(val, src_base + SRC_PLLCR);
179 	}
180 	spin_unlock(&src_lock);
181 	return 0;
182 }
183 
pll_clk_disable(struct clk_hw * hw)184 static void pll_clk_disable(struct clk_hw *hw)
185 {
186 	struct clk_pll *pll = to_pll(hw);
187 	u32 val;
188 
189 	spin_lock(&src_lock);
190 	val = readl(src_base + SRC_PLLCR);
191 	if (pll->id == 1) {
192 		if (val & SRC_PLLCR_PLL1OVER) {
193 			val &= ~SRC_PLLCR_PLL1EN;
194 			writel(val, src_base + SRC_PLLCR);
195 		}
196 	} else if (pll->id == 2) {
197 		val &= ~SRC_PLLCR_PLL2EN;
198 		writel(val, src_base + SRC_PLLCR);
199 	}
200 	spin_unlock(&src_lock);
201 }
202 
pll_clk_is_enabled(struct clk_hw * hw)203 static int pll_clk_is_enabled(struct clk_hw *hw)
204 {
205 	struct clk_pll *pll = to_pll(hw);
206 	u32 val;
207 
208 	val = readl(src_base + SRC_PLLCR);
209 	if (pll->id == 1) {
210 		if (val & SRC_PLLCR_PLL1OVER)
211 			return !!(val & SRC_PLLCR_PLL1EN);
212 	} else if (pll->id == 2) {
213 		return !!(val & SRC_PLLCR_PLL2EN);
214 	}
215 	return 1;
216 }
217 
pll_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)218 static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
219 					  unsigned long parent_rate)
220 {
221 	struct clk_pll *pll = to_pll(hw);
222 	u32 val;
223 
224 	val = readl(src_base + SRC_PLLFR);
225 
226 	if (pll->id == 1) {
227 		u8 mul;
228 		u8 div;
229 
230 		mul = (val >> 8) & 0x3FU;
231 		mul += 2;
232 		div = val & 0x07U;
233 		return (parent_rate * mul) >> div;
234 	}
235 
236 	if (pll->id == 2) {
237 		u8 mul;
238 
239 		mul = (val >> 24) & 0x3FU;
240 		mul += 2;
241 		return (parent_rate * mul);
242 	}
243 
244 	/* Unknown PLL */
245 	return 0;
246 }
247 
248 
249 static const struct clk_ops pll_clk_ops = {
250 	.enable = pll_clk_enable,
251 	.disable = pll_clk_disable,
252 	.is_enabled = pll_clk_is_enabled,
253 	.recalc_rate = pll_clk_recalc_rate,
254 };
255 
256 static struct clk_hw * __init
pll_clk_register(struct device * dev,const char * name,const char * parent_name,u32 id)257 pll_clk_register(struct device *dev, const char *name,
258 		 const char *parent_name, u32 id)
259 {
260 	int ret;
261 	struct clk_pll *pll;
262 	struct clk_init_data init;
263 
264 	if (id != 1 && id != 2) {
265 		pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
266 		return ERR_PTR(-EINVAL);
267 	}
268 
269 	pll = kzalloc(sizeof(*pll), GFP_KERNEL);
270 	if (!pll)
271 		return ERR_PTR(-ENOMEM);
272 
273 	init.name = name;
274 	init.ops = &pll_clk_ops;
275 	init.parent_names = (parent_name ? &parent_name : NULL);
276 	init.num_parents = (parent_name ? 1 : 0);
277 	pll->hw.init = &init;
278 	pll->id = id;
279 
280 	pr_debug("register PLL1 clock \"%s\"\n", name);
281 
282 	ret = clk_hw_register(dev, &pll->hw);
283 	if (ret) {
284 		kfree(pll);
285 		return ERR_PTR(ret);
286 	}
287 
288 	return &pll->hw;
289 }
290 
291 /*
292  * The Nomadik SRC clocks are gated, but not in the sense that
293  * you read-modify-write a register. Instead there are separate
294  * clock enable and clock disable registers. Writing a '1' bit in
295  * the enable register for a certain clock ungates that clock without
296  * affecting the other clocks. The disable register works the opposite
297  * way.
298  */
299 
src_clk_enable(struct clk_hw * hw)300 static int src_clk_enable(struct clk_hw *hw)
301 {
302 	struct clk_src *sclk = to_src(hw);
303 	u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
304 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
305 
306 	writel(sclk->clkbit, src_base + enreg);
307 	/* spin until enabled */
308 	while (!(readl(src_base + sreg) & sclk->clkbit))
309 		cpu_relax();
310 	return 0;
311 }
312 
src_clk_disable(struct clk_hw * hw)313 static void src_clk_disable(struct clk_hw *hw)
314 {
315 	struct clk_src *sclk = to_src(hw);
316 	u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
317 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
318 
319 	writel(sclk->clkbit, src_base + disreg);
320 	/* spin until disabled */
321 	while (readl(src_base + sreg) & sclk->clkbit)
322 		cpu_relax();
323 }
324 
src_clk_is_enabled(struct clk_hw * hw)325 static int src_clk_is_enabled(struct clk_hw *hw)
326 {
327 	struct clk_src *sclk = to_src(hw);
328 	u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
329 	u32 val = readl(src_base + sreg);
330 
331 	return !!(val & sclk->clkbit);
332 }
333 
334 static unsigned long
src_clk_recalc_rate(struct clk_hw * hw,unsigned long parent_rate)335 src_clk_recalc_rate(struct clk_hw *hw,
336 		    unsigned long parent_rate)
337 {
338 	return parent_rate;
339 }
340 
341 static const struct clk_ops src_clk_ops = {
342 	.enable = src_clk_enable,
343 	.disable = src_clk_disable,
344 	.is_enabled = src_clk_is_enabled,
345 	.recalc_rate = src_clk_recalc_rate,
346 };
347 
348 static struct clk_hw * __init
src_clk_register(struct device * dev,const char * name,const char * parent_name,u8 id)349 src_clk_register(struct device *dev, const char *name,
350 		 const char *parent_name, u8 id)
351 {
352 	int ret;
353 	struct clk_src *sclk;
354 	struct clk_init_data init;
355 
356 	sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
357 	if (!sclk)
358 		return ERR_PTR(-ENOMEM);
359 
360 	init.name = name;
361 	init.ops = &src_clk_ops;
362 	/* Do not force-disable the static SDRAM controller */
363 	if (id == 2)
364 		init.flags = CLK_IGNORE_UNUSED;
365 	else
366 		init.flags = 0;
367 	init.parent_names = (parent_name ? &parent_name : NULL);
368 	init.num_parents = (parent_name ? 1 : 0);
369 	sclk->hw.init = &init;
370 	sclk->id = id;
371 	sclk->group1 = (id > 31);
372 	sclk->clkbit = BIT(id & 0x1f);
373 
374 	pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
375 		 name, id, sclk->group1, sclk->clkbit);
376 
377 	ret = clk_hw_register(dev, &sclk->hw);
378 	if (ret) {
379 		kfree(sclk);
380 		return ERR_PTR(ret);
381 	}
382 
383 	return &sclk->hw;
384 }
385 
386 #ifdef CONFIG_DEBUG_FS
387 
388 static u32 src_pcksr0_boot;
389 static u32 src_pcksr1_boot;
390 
391 static const char * const src_clk_names[] = {
392 	"HCLKDMA0  ",
393 	"HCLKSMC   ",
394 	"HCLKSDRAM ",
395 	"HCLKDMA1  ",
396 	"HCLKCLCD  ",
397 	"PCLKIRDA  ",
398 	"PCLKSSP   ",
399 	"PCLKUART0 ",
400 	"PCLKSDI   ",
401 	"PCLKI2C0  ",
402 	"PCLKI2C1  ",
403 	"PCLKUART1 ",
404 	"PCLMSP0   ",
405 	"HCLKUSB   ",
406 	"HCLKDIF   ",
407 	"HCLKSAA   ",
408 	"HCLKSVA   ",
409 	"PCLKHSI   ",
410 	"PCLKXTI   ",
411 	"PCLKUART2 ",
412 	"PCLKMSP1  ",
413 	"PCLKMSP2  ",
414 	"PCLKOWM   ",
415 	"HCLKHPI   ",
416 	"PCLKSKE   ",
417 	"PCLKHSEM  ",
418 	"HCLK3D    ",
419 	"HCLKHASH  ",
420 	"HCLKCRYP  ",
421 	"PCLKMSHC  ",
422 	"HCLKUSBM  ",
423 	"HCLKRNG   ",
424 	"RESERVED  ",
425 	"RESERVED  ",
426 	"RESERVED  ",
427 	"RESERVED  ",
428 	"CLDCLK    ",
429 	"IRDACLK   ",
430 	"SSPICLK   ",
431 	"UART0CLK  ",
432 	"SDICLK    ",
433 	"I2C0CLK   ",
434 	"I2C1CLK   ",
435 	"UART1CLK  ",
436 	"MSPCLK0   ",
437 	"USBCLK    ",
438 	"DIFCLK    ",
439 	"IPI2CCLK  ",
440 	"IPBMCCLK  ",
441 	"HSICLKRX  ",
442 	"HSICLKTX  ",
443 	"UART2CLK  ",
444 	"MSPCLK1   ",
445 	"MSPCLK2   ",
446 	"OWMCLK    ",
447 	"RESERVED  ",
448 	"SKECLK    ",
449 	"RESERVED  ",
450 	"3DCLK     ",
451 	"PCLKMSP3  ",
452 	"MSPCLK3   ",
453 	"MSHCCLK   ",
454 	"USBMCLK   ",
455 	"RNGCCLK   ",
456 };
457 
nomadik_src_clk_debugfs_show(struct seq_file * s,void * what)458 static int nomadik_src_clk_debugfs_show(struct seq_file *s, void *what)
459 {
460 	int i;
461 	u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
462 	u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
463 	u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
464 	u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
465 
466 	seq_puts(s, "Clock:      Boot:   Now:    Request: ASKED:\n");
467 	for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
468 		u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
469 		u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
470 		u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
471 		u32 mask = BIT(i & 0x1f);
472 
473 		seq_printf(s, "%s  %s     %s     %s\n",
474 			   src_clk_names[i],
475 			   (pcksrb & mask) ? "on " : "off",
476 			   (pcksr & mask) ? "on " : "off",
477 			   (pckreq & mask) ? "on " : "off");
478 	}
479 	return 0;
480 }
481 
482 DEFINE_SHOW_ATTRIBUTE(nomadik_src_clk_debugfs);
483 
nomadik_src_clk_init_debugfs(void)484 static int __init nomadik_src_clk_init_debugfs(void)
485 {
486 	/* Vital for multiplatform */
487 	if (!src_base)
488 		return -ENODEV;
489 	src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
490 	src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
491 	debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
492 			    NULL, NULL, &nomadik_src_clk_debugfs_fops);
493 	return 0;
494 }
495 device_initcall(nomadik_src_clk_init_debugfs);
496 
497 #endif
498 
of_nomadik_pll_setup(struct device_node * np)499 static void __init of_nomadik_pll_setup(struct device_node *np)
500 {
501 	struct clk_hw *hw;
502 	const char *clk_name = np->name;
503 	const char *parent_name;
504 	u32 pll_id;
505 
506 	if (!src_base)
507 		nomadik_src_init();
508 
509 	if (of_property_read_u32(np, "pll-id", &pll_id)) {
510 		pr_err("%s: PLL \"%s\" missing pll-id property\n",
511 			__func__, clk_name);
512 		return;
513 	}
514 	parent_name = of_clk_get_parent_name(np, 0);
515 	hw = pll_clk_register(NULL, clk_name, parent_name, pll_id);
516 	if (!IS_ERR(hw))
517 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
518 }
519 CLK_OF_DECLARE(nomadik_pll_clk,
520 	"st,nomadik-pll-clock", of_nomadik_pll_setup);
521 
of_nomadik_hclk_setup(struct device_node * np)522 static void __init of_nomadik_hclk_setup(struct device_node *np)
523 {
524 	struct clk_hw *hw;
525 	const char *clk_name = np->name;
526 	const char *parent_name;
527 
528 	if (!src_base)
529 		nomadik_src_init();
530 
531 	parent_name = of_clk_get_parent_name(np, 0);
532 	/*
533 	 * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
534 	 */
535 	hw = clk_hw_register_divider(NULL, clk_name, parent_name,
536 			   0, src_base + SRC_CR,
537 			   13, 2,
538 			   CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
539 			   &src_lock);
540 	if (!IS_ERR(hw))
541 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
542 }
543 CLK_OF_DECLARE(nomadik_hclk_clk,
544 	"st,nomadik-hclk-clock", of_nomadik_hclk_setup);
545 
of_nomadik_src_clk_setup(struct device_node * np)546 static void __init of_nomadik_src_clk_setup(struct device_node *np)
547 {
548 	struct clk_hw *hw;
549 	const char *clk_name = np->name;
550 	const char *parent_name;
551 	u32 clk_id;
552 
553 	if (!src_base)
554 		nomadik_src_init();
555 
556 	if (of_property_read_u32(np, "clock-id", &clk_id)) {
557 		pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
558 			__func__, clk_name);
559 		return;
560 	}
561 	parent_name = of_clk_get_parent_name(np, 0);
562 	hw = src_clk_register(NULL, clk_name, parent_name, clk_id);
563 	if (!IS_ERR(hw))
564 		of_clk_add_hw_provider(np, of_clk_hw_simple_get, hw);
565 }
566 CLK_OF_DECLARE(nomadik_src_clk,
567 	"st,nomadik-src-clock", of_nomadik_src_clk_setup);
568