diff options
author | Chen-Yu Tsai <wens@csie.org> | 2015-03-17 23:24:01 -0400 |
---|---|---|
committer | Maxime Ripard <maxime.ripard@free-electrons.com> | 2015-04-27 02:16:33 -0400 |
commit | 7917d14129a5a7241289f06d2c5299c5d03ed529 (patch) | |
tree | 841b0e251dbd0af449f2e4ddb70d4c46898f0894 /arch/arm/mach-sunxi | |
parent | b787f68c36d49bb1d9236f403813641efa74a031 (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.c | 69 |
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 | }; |
123 | CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops); | 123 | CPU_METHOD_OF_DECLARE(sun6i_a31_smp, "allwinner,sun6i-a31", &sun6i_smp_ops); |
124 | |||
125 | static 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 | |||
154 | static 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 | |||
188 | struct smp_operations sun8i_smp_ops __initdata = { | ||
189 | .smp_prepare_cpus = sun8i_smp_prepare_cpus, | ||
190 | .smp_boot_secondary = sun8i_smp_boot_secondary, | ||
191 | }; | ||
192 | CPU_METHOD_OF_DECLARE(sun8i_a23_smp, "allwinner,sun8i-a23", &sun8i_smp_ops); | ||