File Index
Files and directories
Sign in
FILE

platsmp.c

File preview with syntax highlighting.

linux-6.19.14/arch/arm/mach-sunxi/platsmp.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * SMP support for Allwinner SoCs
  4 *
  5 * Copyright (C) 2013 Maxime Ripard
  6 *
  7 * Maxime Ripard <maxime.ripard@free-electrons.com>
  8 *
  9 * Based on code
 10 *  Copyright (C) 2012-2013 Allwinner Ltd.
 11 *
 12 */
 13
 14#include <linux/delay.h>
 15#include <linux/init.h>
 16#include <linux/io.h>
 17#include <linux/memory.h>
 18#include <linux/of.h>
 19#include <linux/of_address.h>
 20#include <linux/smp.h>
 21
 22#define CPUCFG_CPU_PWR_CLAMP_STATUS_REG(cpu)	((cpu) * 0x40 + 0x64)
 23#define CPUCFG_CPU_RST_CTRL_REG(cpu)		(((cpu) + 1) * 0x40)
 24#define CPUCFG_CPU_CTRL_REG(cpu)		(((cpu) + 1) * 0x40 + 0x04)
 25#define CPUCFG_CPU_STATUS_REG(cpu)		(((cpu) + 1) * 0x40 + 0x08)
 26#define CPUCFG_GEN_CTRL_REG			0x184
 27#define CPUCFG_PRIVATE0_REG			0x1a4
 28#define CPUCFG_PRIVATE1_REG			0x1a8
 29#define CPUCFG_DBG_CTL0_REG			0x1e0
 30#define CPUCFG_DBG_CTL1_REG			0x1e4
 31
 32#define PRCM_CPU_PWROFF_REG			0x100
 33#define PRCM_CPU_PWR_CLAMP_REG(cpu)		(((cpu) * 4) + 0x140)
 34
 35static void __iomem *cpucfg_membase;
 36static void __iomem *prcm_membase;
 37
 38static DEFINE_SPINLOCK(cpu_lock);
 39
 40static void __init sun6i_smp_prepare_cpus(unsigned int max_cpus)
 41{
 42	struct device_node *node;
 43
 44	node = of_find_compatible_node(NULL, NULL, "allwinner,sun6i-a31-prcm");
 45	if (!node) {
 46		pr_err("Missing A31 PRCM node in the device tree\n");
 47		return;
 48	}
 49
 50	prcm_membase = of_iomap(node, 0);
 51	of_node_put(node);
 52	if (!prcm_membase) {
 53		pr_err("Couldn't map A31 PRCM registers\n");
 54		return;
 55	}
 56
 57	node = of_find_compatible_node(NULL, NULL,
 58				       "allwinner,sun6i-a31-cpuconfig");
 59	if (!node) {
 60		pr_err("Missing A31 CPU config node in the device tree\n");
 61		return;
 62	}
 63
 64	cpucfg_membase = of_iomap(node, 0);
 65	of_node_put(node);
 66	if (!cpucfg_membase)
 67		pr_err("Couldn't map A31 CPU config registers\n");
 68
 69}
 70
 71static int sun6i_smp_boot_secondary(unsigned int cpu,
 72				    struct task_struct *idle)
 73{
 74	u32 reg;
 75	int i;
 76
 77	if (!(prcm_membase && cpucfg_membase))
 78		return -EFAULT;
 79
 80	spin_lock(&cpu_lock);
 81
 82	/* Set CPU boot address */
 83	writel(__pa_symbol(secondary_startup),
 84	       cpucfg_membase + CPUCFG_PRIVATE0_REG);
 85
 86	/* Assert the CPU core in reset */
 87	writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
 88
 89	/* Assert the L1 cache in reset */
 90	reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 91	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
 92
 93	/* Disable external debug access */
 94	reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 95	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
 96
 97	/* Power up the CPU */
 98	for (i = 0; i <= 8; i++)
 99		writel(0xff >> i, prcm_membase + PRCM_CPU_PWR_CLAMP_REG(cpu));
100	mdelay(10);
101
102	/* Clear CPU power-off gating */
103	reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
104	writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
105	mdelay(1);
106
107	/* Deassert the CPU core reset */
108	writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
109
110	/* Enable back the external debug accesses */
111	reg = readl(cpucfg_membase + CPUCFG_DBG_CTL1_REG);
112	writel(reg | BIT(cpu), cpucfg_membase + CPUCFG_DBG_CTL1_REG);
113
114	spin_unlock(&cpu_lock);
115
116	return 0;
117}
118
119static const struct smp_operations sun6i_smp_ops __initconst = {
120	.smp_prepare_cpus	= sun6i_smp_prepare_cpus,
121	.smp_boot_secondary	= sun6i_smp_boot_secondary,
122};
123CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops);
124
125static void __init sun8i_smp_prepare_cpus(unsigned int max_cpus)
126{
127	struct device_node *node;
128
129	node = of_find_compatible_node(NULL, NULL, "allwinner,sun8i-a23-prcm");
130	if (!node) {
131		pr_err("Missing A23 PRCM node in the device tree\n");
132		return;
133	}
134
135	prcm_membase = of_iomap(node, 0);
136	of_node_put(node);
137	if (!prcm_membase) {
138		pr_err("Couldn't map A23 PRCM registers\n");
139		return;
140	}
141
142	node = of_find_compatible_node(NULL, NULL,
143				       "allwinner,sun8i-a23-cpuconfig");
144	if (!node) {
145		pr_err("Missing A23 CPU config node in the device tree\n");
146		return;
147	}
148
149	cpucfg_membase = of_iomap(node, 0);
150	of_node_put(node);
151	if (!cpucfg_membase)
152		pr_err("Couldn't map A23 CPU config registers\n");
153
154}
155
156static int sun8i_smp_boot_secondary(unsigned int cpu,
157				    struct task_struct *idle)
158{
159	u32 reg;
160
161	if (!(prcm_membase && cpucfg_membase))
162		return -EFAULT;
163
164	spin_lock(&cpu_lock);
165
166	/* Set CPU boot address */
167	writel(__pa_symbol(secondary_startup),
168	       cpucfg_membase + CPUCFG_PRIVATE0_REG);
169
170	/* Assert the CPU core in reset */
171	writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
172
173	/* Assert the L1 cache in reset */
174	reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
175	writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
176
177	/* Clear CPU power-off gating */
178	reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
179	writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
180	mdelay(1);
181
182	/* Deassert the CPU core reset */
183	writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
184
185	spin_unlock(&cpu_lock);
186
187	return 0;
188}
189
190static const struct smp_operations sun8i_smp_ops __initconst = {
191	.smp_prepare_cpus	= sun8i_smp_prepare_cpus,
192	.smp_boot_secondary	= sun8i_smp_boot_secondary,
193};
194CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);
~/ Read-only file preview.