aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-sunxi
diff options
context:
space:
mode:
authorChen-Yu Tsai <wens@csie.org>2015-03-17 23:24:01 -0400
committerMaxime Ripard <maxime.ripard@free-electrons.com>2015-04-27 02:16:33 -0400
commit7917d14129a5a7241289f06d2c5299c5d03ed529 (patch)
tree841b0e251dbd0af449f2e4ddb70d4c46898f0894 /arch/arm/mach-sunxi
parentb787f68c36d49bb1d9236f403813641efa74a031 (diff)
ARM: sun8i: Add SMP support for the Allwinner A23
The A23 is a dual Cortex-A7. Add the logic to use the IPs used to control the CPU configuration and the CPU power so that we can bring up secondary CPUs at boot. Signed-off-by: Chen-Yu Tsai <wens@csie.org> Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Diffstat (limited to 'arch/arm/mach-sunxi')
-rw-r--r--arch/arm/mach-sunxi/platsmp.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c
index 587b0468efcc..e8483ec79d67 100644
--- a/arch/arm/mach-sunxi/platsmp.c
+++ b/arch/arm/mach-sunxi/platsmp.c
@@ -121,3 +121,72 @@ static struct smp_operations sun6i_smp_ops __initdata = {
121 .smp_boot_secondary = sun6i_smp_boot_secondary, 121 .smp_boot_secondary = sun6i_smp_boot_secondary,
122}; 122};
123CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops); 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 if (!prcm_membase) {
137 pr_err("Couldn't map A23 PRCM registers\n");
138 return;
139 }
140
141 node = of_find_compatible_node(NULL, NULL,
142 "allwinner,sun8i-a23-cpuconfig");
143 if (!node) {
144 pr_err("Missing A23 CPU config node in the device tree\n");
145 return;
146 }
147
148 cpucfg_membase = of_iomap(node, 0);
149 if (!cpucfg_membase)
150 pr_err("Couldn't map A23 CPU config registers\n");
151
152}
153
154static int sun8i_smp_boot_secondary(unsigned int cpu,
155 struct task_struct *idle)
156{
157 u32 reg;
158
159 if (!(prcm_membase && cpucfg_membase))
160 return -EFAULT;
161
162 spin_lock(&cpu_lock);
163
164 /* Set CPU boot address */
165 writel(virt_to_phys(secondary_startup),
166 cpucfg_membase + CPUCFG_PRIVATE0_REG);
167
168 /* Assert the CPU core in reset */
169 writel(0, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
170
171 /* Assert the L1 cache in reset */
172 reg = readl(cpucfg_membase + CPUCFG_GEN_CTRL_REG);
173 writel(reg & ~BIT(cpu), cpucfg_membase + CPUCFG_GEN_CTRL_REG);
174
175 /* Clear CPU power-off gating */
176 reg = readl(prcm_membase + PRCM_CPU_PWROFF_REG);
177 writel(reg & ~BIT(cpu), prcm_membase + PRCM_CPU_PWROFF_REG);
178 mdelay(1);
179
180 /* Deassert the CPU core reset */
181 writel(3, cpucfg_membase + CPUCFG_CPU_RST_CTRL_REG(cpu));
182
183 spin_unlock(&cpu_lock);
184
185 return 0;
186}
187
188struct smp_operations sun8i_smp_ops __initdata = {
189 .smp_prepare_cpus = sun8i_smp_prepare_cpus,
190 .smp_boot_secondary = sun8i_smp_boot_secondary,
191};
192CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops);