xref: /openbmc/linux/arch/arm/mach-sunxi/platsmp.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
1*5923ddaaSJason Wang // SPDX-License-Identifier: GPL-2.0
273346794SMaxime Ripard /*
373346794SMaxime Ripard  * SMP support for Allwinner SoCs
473346794SMaxime Ripard  *
573346794SMaxime Ripard  * Copyright (C) 2013 Maxime Ripard
673346794SMaxime Ripard  *
773346794SMaxime Ripard  * Maxime Ripard <maxime.ripard@free-electrons.com>
873346794SMaxime Ripard  *
973346794SMaxime Ripard  * Based on code
1073346794SMaxime Ripard  *  Copyright (C) 2012-2013 Allwinner Ltd.
1173346794SMaxime Ripard  *
1273346794SMaxime Ripard  */
1373346794SMaxime Ripard 
1473346794SMaxime Ripard #include <linux/delay.h>
1573346794SMaxime Ripard #include <linux/init.h>
1673346794SMaxime Ripard #include <linux/io.h>
1773346794SMaxime Ripard #include <linux/memory.h>
1873346794SMaxime Ripard #include <linux/of.h>
1973346794SMaxime Ripard #include <linux/of_address.h>
2073346794SMaxime Ripard #include <linux/smp.h>
2173346794SMaxime Ripard 
2273346794SMaxime Ripard #define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu)	((cpu) * 0x40 + 0x64)
2373346794SMaxime Ripard #define CPUCFG_CPU_RST_CTRL_REG(cpu)		(((cpu) + 1) * 0x40)
2473346794SMaxime Ripard #define CPUCFG_CPU_CTRL_REG(cpu)		(((cpu) + 1) * 0x40 + 0x04)
2573346794SMaxime Ripard #define CPUCFG_CPU_STATUS_REG(cpu)		(((cpu) + 1) * 0x40 + 0x08)
2673346794SMaxime Ripard #define CPUCFG_GEN_CTRL_REG			0x184
2773346794SMaxime Ripard #define CPUCFG_PRIVATE0_REG			0x1a4
2873346794SMaxime Ripard #define CPUCFG_PRIVATE1_REG			0x1a8
2973346794SMaxime Ripard #define CPUCFG_DBG_CTL0_REG			0x1e0
3073346794SMaxime Ripard #define CPUCFG_DBG_CTL1_REG			0x1e4
3173346794SMaxime Ripard 
3273346794SMaxime Ripard #define PRCM_CPU_PWROFF_REG			0x100
3373346794SMaxime Ripard #define PRCM_CPU_PWR_CLAMP_REG(cpu)		(((cpu) * 4) + 0x140)
3473346794SMaxime Ripard 
3573346794SMaxime Ripard static void __iomem *cpucfg_membase;
3673346794SMaxime Ripard static void __iomem *prcm_membase;
3773346794SMaxime Ripard 
3873346794SMaxime Ripard static DEFINE_SPINLOCK(cpu_lock);
3973346794SMaxime Ripard 
sun6i_smp_prepare_cpus(unsigned int max_cpus)4073346794SMaxime Ripard static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
4173346794SMaxime Ripard {
4273346794SMaxime Ripard 	struct device_node *node;
4373346794SMaxime Ripard 
4473346794SMaxime Ripard 	node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
4573346794SMaxime Ripard 	if (!node) {
4673346794SMaxime Ripard 		pr_err("Missing A31 PRCM node in the device tree\n");
4773346794SMaxime Ripard 		return;
4873346794SMaxime Ripard 	}
4973346794SMaxime Ripard 
5073346794SMaxime Ripard 	prcm_membase = of_iomap(node, 0);
512b062a0aSWen Yang 	of_node_put(node);
5273346794SMaxime Ripard 	if (!prcm_membase) {
5373346794SMaxime Ripard 		pr_err("Couldn't map A31 PRCM registers\n");
5473346794SMaxime Ripard 		return;
5573346794SMaxime Ripard 	}
5673346794SMaxime Ripard 
5773346794SMaxime Ripard 	node = of_find_compatible_node(NULL, NULL,
5873346794SMaxime Ripard 				       "allwinner,sun6i-a31-cpuconfig");
5973346794SMaxime Ripard 	if (!node) {
6073346794SMaxime Ripard 		pr_err("Missing A31 CPU config node in the device tree\n");
6173346794SMaxime Ripard 		return;
6273346794SMaxime Ripard 	}
6373346794SMaxime Ripard 
6473346794SMaxime Ripard 	cpucfg_membase = of_iomap(node, 0);
652b062a0aSWen Yang 	of_node_put(node);
6673346794SMaxime Ripard 	if (!cpucfg_membase)
6773346794SMaxime Ripard 		pr_err("Couldn't map A31 CPU config registers\n");
6873346794SMaxime Ripard 
6973346794SMaxime Ripard }
7073346794SMaxime Ripard 
sun6i_smp_boot_secondary(unsigned int cpu,struct task_struct * idle)7173346794SMaxime Ripard static int sun6i_smp_boot_secondary(unsigned int cpu,
7273346794SMaxime Ripard 				    struct task_struct *idle)
7373346794SMaxime Ripard {
7473346794SMaxime Ripard 	u32 reg;
7573346794SMaxime Ripard 	int i;
7673346794SMaxime Ripard 
7773346794SMaxime Ripard 	if (!(prcm_membase && cpucfg_membase))
7873346794SMaxime Ripard 		return -EFAULT;
7973346794SMaxime Ripard 
8073346794SMaxime Ripard 	spin_lock(&cpu_lock);
8173346794SMaxime Ripard 
8273346794SMaxime Ripard 	/* Set CPU boot address */
8364fc2a94SFlorian Fainelli 	writel(__pa_symbol(secondary_startup),
8473346794SMaxime Ripard 	       cpucfg_membase + CPUCFG_PRIVATE0_REG);
8573346794SMaxime Ripard 
8673346794SMaxime Ripard 	/* Assert the CPU core in reset */
8773346794SMaxime Ripard 	writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
8873346794SMaxime Ripard 
8973346794SMaxime Ripard 	/* Assert the L1 cache in reset */
9073346794SMaxime Ripard 	reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
9173346794SMaxime Ripard 	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
9273346794SMaxime Ripard 
9373346794SMaxime Ripard 	/* Disable external debug access */
9473346794SMaxime Ripard 	reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
9573346794SMaxime Ripard 	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
9673346794SMaxime Ripard 
9773346794SMaxime Ripard 	/* Power up the CPU */
9873346794SMaxime Ripard 	for (i = 0; i <= 8; i++)
9973346794SMaxime Ripard 		writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
10073346794SMaxime Ripard 	mdelay(10);
10173346794SMaxime Ripard 
10273346794SMaxime Ripard 	/* Clear CPU power-off gating */
10373346794SMaxime Ripard 	reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
10473346794SMaxime Ripard 	writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
10573346794SMaxime Ripard 	mdelay(1);
10673346794SMaxime Ripard 
10773346794SMaxime Ripard 	/* Deassert the CPU core reset */
10873346794SMaxime Ripard 	writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
10973346794SMaxime Ripard 
11073346794SMaxime Ripard 	/* Enable back the external debug accesses */
11173346794SMaxime Ripard 	reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
11273346794SMaxime Ripard 	writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
11373346794SMaxime Ripard 
11473346794SMaxime Ripard 	spin_unlock(&cpu_lock);
11573346794SMaxime Ripard 
11673346794SMaxime Ripard 	return 0;
11773346794SMaxime Ripard }
11873346794SMaxime Ripard 
11975305275SMasahiro Yamada static const struct smp_operations sun6i_smp_ops __initconst = {
12073346794SMaxime Ripard 	.smp_prepare_cpus	= sun6i_smp_prepare_cpus,
12173346794SMaxime Ripard 	.smp_boot_secondary	= sun6i_smp_boot_secondary,
12273346794SMaxime Ripard };
123b0f2faa5SHans de Goede CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
1247917d141SChen-Yu Tsai 
sun8i_smp_prepare_cpus(unsigned int max_cpus)1257917d141SChen-Yu Tsai static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
1267917d141SChen-Yu Tsai {
1277917d141SChen-Yu Tsai 	struct device_node *node;
1287917d141SChen-Yu Tsai 
1297917d141SChen-Yu Tsai 	node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
1307917d141SChen-Yu Tsai 	if (!node) {
1317917d141SChen-Yu Tsai 		pr_err("Missing A23 PRCM node in the device tree\n");
1327917d141SChen-Yu Tsai 		return;
1337917d141SChen-Yu Tsai 	}
1347917d141SChen-Yu Tsai 
1357917d141SChen-Yu Tsai 	prcm_membase = of_iomap(node, 0);
136995c770bSWen Yang 	of_node_put(node);
1377917d141SChen-Yu Tsai 	if (!prcm_membase) {
1387917d141SChen-Yu Tsai 		pr_err("Couldn't map A23 PRCM registers\n");
1397917d141SChen-Yu Tsai 		return;
1407917d141SChen-Yu Tsai 	}
1417917d141SChen-Yu Tsai 
1427917d141SChen-Yu Tsai 	node = of_find_compatible_node(NULL, NULL,
1437917d141SChen-Yu Tsai 				       "allwinner,sun8i-a23-cpuconfig");
1447917d141SChen-Yu Tsai 	if (!node) {
1457917d141SChen-Yu Tsai 		pr_err("Missing A23 CPU config node in the device tree\n");
1467917d141SChen-Yu Tsai 		return;
1477917d141SChen-Yu Tsai 	}
1487917d141SChen-Yu Tsai 
1497917d141SChen-Yu Tsai 	cpucfg_membase = of_iomap(node, 0);
150995c770bSWen Yang 	of_node_put(node);
1517917d141SChen-Yu Tsai 	if (!cpucfg_membase)
1527917d141SChen-Yu Tsai 		pr_err("Couldn't map A23 CPU config registers\n");
1537917d141SChen-Yu Tsai 
1547917d141SChen-Yu Tsai }
1557917d141SChen-Yu Tsai 
sun8i_smp_boot_secondary(unsigned int cpu,struct task_struct * idle)1567917d141SChen-Yu Tsai static int sun8i_smp_boot_secondary(unsigned int cpu,
1577917d141SChen-Yu Tsai 				    struct task_struct *idle)
1587917d141SChen-Yu Tsai {
1597917d141SChen-Yu Tsai 	u32 reg;
1607917d141SChen-Yu Tsai 
1617917d141SChen-Yu Tsai 	if (!(prcm_membase && cpucfg_membase))
1627917d141SChen-Yu Tsai 		return -EFAULT;
1637917d141SChen-Yu Tsai 
1647917d141SChen-Yu Tsai 	spin_lock(&cpu_lock);
1657917d141SChen-Yu Tsai 
1667917d141SChen-Yu Tsai 	/* Set CPU boot address */
16764fc2a94SFlorian Fainelli 	writel(__pa_symbol(secondary_startup),
1687917d141SChen-Yu Tsai 	       cpucfg_membase + CPUCFG_PRIVATE0_REG);
1697917d141SChen-Yu Tsai 
1707917d141SChen-Yu Tsai 	/* Assert the CPU core in reset */
1717917d141SChen-Yu Tsai 	writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
1727917d141SChen-Yu Tsai 
1737917d141SChen-Yu Tsai 	/* Assert the L1 cache in reset */
1747917d141SChen-Yu Tsai 	reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
1757917d141SChen-Yu Tsai 	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
1767917d141SChen-Yu Tsai 
1777917d141SChen-Yu Tsai 	/* Clear CPU power-off gating */
1787917d141SChen-Yu Tsai 	reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
1797917d141SChen-Yu Tsai 	writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
1807917d141SChen-Yu Tsai 	mdelay(1);
1817917d141SChen-Yu Tsai 
1827917d141SChen-Yu Tsai 	/* Deassert the CPU core reset */
1837917d141SChen-Yu Tsai 	writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
1847917d141SChen-Yu Tsai 
1857917d141SChen-Yu Tsai 	spin_unlock(&cpu_lock);
1867917d141SChen-Yu Tsai 
1877917d141SChen-Yu Tsai 	return 0;
1887917d141SChen-Yu Tsai }
1897917d141SChen-Yu Tsai 
19075305275SMasahiro Yamada static const struct smp_operations sun8i_smp_ops __initconst = {
1917917d141SChen-Yu Tsai 	.smp_prepare_cpus	= sun8i_smp_prepare_cpus,
1927917d141SChen-Yu Tsai 	.smp_boot_secondary	= sun8i_smp_boot_secondary,
1937917d141SChen-Yu Tsai };
1947917d141SChen-Yu Tsai CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);
195