File Index
Files and directories
Sign in
FILE

clk-nomadik.c

File preview with syntax highlighting.

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