cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-nomadik.c (13426B)


      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 */
     60static DEFINE_SPINLOCK(src_lock);
     61/* Base address of the SRC */
     62static void __iomem *src_base;
     63
     64static 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
     79static struct notifier_block nomadik_clk_reboot_notifier = {
     80	.notifier_call = nomadik_clk_reboot_handler,
     81};
     82
     83static const struct of_device_id nomadik_src_match[] __initconst = {
     84	{ .compatible = "stericsson,nomadik-src" },
     85	{ /* sentinel */ }
     86};
     87
     88static 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 */
    142struct 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 */
    154struct 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
    164static 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
    184static 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
    203static 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
    218static 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
    249static 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
    256static struct clk_hw * __init
    257pll_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
    300static 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
    313static 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
    325static 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
    334static unsigned long
    335src_clk_recalc_rate(struct clk_hw *hw,
    336		    unsigned long parent_rate)
    337{
    338	return parent_rate;
    339}
    340
    341static 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
    348static struct clk_hw * __init
    349src_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
    388static u32 src_pcksr0_boot;
    389static u32 src_pcksr1_boot;
    390
    391static 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
    458static 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
    482DEFINE_SHOW_ATTRIBUTE(nomadik_src_clk_debugfs);
    483
    484static 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}
    495device_initcall(nomadik_src_clk_init_debugfs);
    496
    497#endif
    498
    499static 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}
    519CLK_OF_DECLARE(nomadik_pll_clk,
    520	"st,nomadik-pll-clock", of_nomadik_pll_setup);
    521
    522static 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}
    543CLK_OF_DECLARE(nomadik_hclk_clk,
    544	"st,nomadik-hclk-clock", of_nomadik_hclk_setup);
    545
    546static 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}
    566CLK_OF_DECLARE(nomadik_src_clk,
    567	"st,nomadik-src-clock", of_nomadik_src_clk_setup);