diff options
-rw-r--r-- | arch/arm/mach-rockchip/headsmp.S | 5 | ||||
-rw-r--r-- | arch/arm/mach-rockchip/platsmp.c | 120 |
2 files changed, 100 insertions, 25 deletions
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S index 73206e360e31..46c22dedf632 100644 --- a/arch/arm/mach-rockchip/headsmp.S +++ b/arch/arm/mach-rockchip/headsmp.S | |||
@@ -16,7 +16,10 @@ | |||
16 | #include <linux/init.h> | 16 | #include <linux/init.h> |
17 | 17 | ||
18 | ENTRY(rockchip_secondary_startup) | 18 | ENTRY(rockchip_secondary_startup) |
19 | bl v7_invalidate_l1 | 19 | mrc p15, 0, r0, c0, c0, 0 @ read main ID register |
20 | ldr r1, =0x00000c09 @ Cortex-A9 primary part number | ||
21 | teq r0, r1 | ||
22 | beq v7_invalidate_l1 | ||
20 | b secondary_startup | 23 | b secondary_startup |
21 | ENDPROC(rockchip_secondary_startup) | 24 | ENDPROC(rockchip_secondary_startup) |
22 | 25 | ||
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c index 57b53b32e103..f26fcdca2445 100644 --- a/arch/arm/mach-rockchip/platsmp.c +++ b/arch/arm/mach-rockchip/platsmp.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/regmap.h> | 22 | #include <linux/regmap.h> |
23 | #include <linux/mfd/syscon.h> | 23 | #include <linux/mfd/syscon.h> |
24 | 24 | ||
25 | #include <linux/reset.h> | ||
26 | #include <linux/cpu.h> | ||
25 | #include <asm/cacheflush.h> | 27 | #include <asm/cacheflush.h> |
26 | #include <asm/cp15.h> | 28 | #include <asm/cp15.h> |
27 | #include <asm/smp_scu.h> | 29 | #include <asm/smp_scu.h> |
@@ -53,11 +55,47 @@ static int pmu_power_domain_is_on(int pd) | |||
53 | return !(val & BIT(pd)); | 55 | return !(val & BIT(pd)); |
54 | } | 56 | } |
55 | 57 | ||
58 | struct reset_control *rockchip_get_core_reset(int cpu) | ||
59 | { | ||
60 | struct device *dev = get_cpu_device(cpu); | ||
61 | struct device_node *np; | ||
62 | |||
63 | /* The cpu device is only available after the initial core bringup */ | ||
64 | if (dev) | ||
65 | np = dev->of_node; | ||
66 | else | ||
67 | np = of_get_cpu_node(cpu, 0); | ||
68 | |||
69 | return of_reset_control_get(np, NULL); | ||
70 | } | ||
71 | |||
56 | static int pmu_set_power_domain(int pd, bool on) | 72 | static int pmu_set_power_domain(int pd, bool on) |
57 | { | 73 | { |
58 | u32 val = (on) ? 0 : BIT(pd); | 74 | u32 val = (on) ? 0 : BIT(pd); |
59 | int ret; | 75 | int ret; |
60 | 76 | ||
77 | /* | ||
78 | * We need to soft reset the cpu when we turn off the cpu power domain, | ||
79 | * or else the active processors might be stalled when the individual | ||
80 | * processor is powered down. | ||
81 | */ | ||
82 | if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { | ||
83 | struct reset_control *rstc = rockchip_get_core_reset(pd); | ||
84 | |||
85 | if (IS_ERR(rstc)) { | ||
86 | pr_err("%s: could not get reset control for core %d\n", | ||
87 | __func__, pd); | ||
88 | return PTR_ERR(rstc); | ||
89 | } | ||
90 | |||
91 | if (on) | ||
92 | reset_control_deassert(rstc); | ||
93 | else | ||
94 | reset_control_assert(rstc); | ||
95 | |||
96 | reset_control_put(rstc); | ||
97 | } | ||
98 | |||
61 | ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); | 99 | ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val); |
62 | if (ret < 0) { | 100 | if (ret < 0) { |
63 | pr_err("%s: could not update power domain\n", __func__); | 101 | pr_err("%s: could not update power domain\n", __func__); |
@@ -84,6 +122,8 @@ static int pmu_set_power_domain(int pd, bool on) | |||
84 | static int __cpuinit rockchip_boot_secondary(unsigned int cpu, | 122 | static int __cpuinit rockchip_boot_secondary(unsigned int cpu, |
85 | struct task_struct *idle) | 123 | struct task_struct *idle) |
86 | { | 124 | { |
125 | int ret; | ||
126 | |||
87 | if (!sram_base_addr || !pmu) { | 127 | if (!sram_base_addr || !pmu) { |
88 | pr_err("%s: sram or pmu missing for cpu boot\n", __func__); | 128 | pr_err("%s: sram or pmu missing for cpu boot\n", __func__); |
89 | return -ENXIO; | 129 | return -ENXIO; |
@@ -96,7 +136,26 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu, | |||
96 | } | 136 | } |
97 | 137 | ||
98 | /* start the core */ | 138 | /* start the core */ |
99 | return pmu_set_power_domain(0 + cpu, true); | 139 | ret = pmu_set_power_domain(0 + cpu, true); |
140 | if (ret < 0) | ||
141 | return ret; | ||
142 | |||
143 | if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) { | ||
144 | /* We communicate with the bootrom to active the cpus other | ||
145 | * than cpu0, after a blob of initialize code, they will | ||
146 | * stay at wfe state, once they are actived, they will check | ||
147 | * the mailbox: | ||
148 | * sram_base_addr + 4: 0xdeadbeaf | ||
149 | * sram_base_addr + 8: start address for pc | ||
150 | * */ | ||
151 | udelay(10); | ||
152 | writel(virt_to_phys(rockchip_secondary_startup), | ||
153 | sram_base_addr + 8); | ||
154 | writel(0xDEADBEAF, sram_base_addr + 4); | ||
155 | dsb_sev(); | ||
156 | } | ||
157 | |||
158 | return 0; | ||
100 | } | 159 | } |
101 | 160 | ||
102 | /** | 161 | /** |
@@ -129,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node) | |||
129 | return -EINVAL; | 188 | return -EINVAL; |
130 | } | 189 | } |
131 | 190 | ||
132 | sram_base_addr = of_iomap(node, 0); | ||
133 | |||
134 | /* set the boot function for the sram code */ | 191 | /* set the boot function for the sram code */ |
135 | rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup); | 192 | rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup); |
136 | 193 | ||
@@ -204,40 +261,55 @@ static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus) | |||
204 | struct device_node *node; | 261 | struct device_node *node; |
205 | unsigned int i; | 262 | unsigned int i; |
206 | 263 | ||
207 | node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); | ||
208 | if (!node) { | ||
209 | pr_err("%s: missing scu\n", __func__); | ||
210 | return; | ||
211 | } | ||
212 | |||
213 | scu_base_addr = of_iomap(node, 0); | ||
214 | if (!scu_base_addr) { | ||
215 | pr_err("%s: could not map scu registers\n", __func__); | ||
216 | return; | ||
217 | } | ||
218 | |||
219 | node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); | 264 | node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram"); |
220 | if (!node) { | 265 | if (!node) { |
221 | pr_err("%s: could not find sram dt node\n", __func__); | 266 | pr_err("%s: could not find sram dt node\n", __func__); |
222 | return; | 267 | return; |
223 | } | 268 | } |
224 | 269 | ||
225 | if (rockchip_smp_prepare_sram(node)) | 270 | sram_base_addr = of_iomap(node, 0); |
271 | if (!sram_base_addr) { | ||
272 | pr_err("%s: could not map sram registers\n", __func__); | ||
226 | return; | 273 | return; |
274 | } | ||
227 | 275 | ||
228 | if (rockchip_smp_prepare_pmu()) | 276 | if (rockchip_smp_prepare_pmu()) |
229 | return; | 277 | return; |
230 | 278 | ||
231 | /* enable the SCU power domain */ | 279 | if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { |
232 | pmu_set_power_domain(PMU_PWRDN_SCU, true); | 280 | if (rockchip_smp_prepare_sram(node)) |
281 | return; | ||
233 | 282 | ||
234 | /* | 283 | /* enable the SCU power domain */ |
235 | * While the number of cpus is gathered from dt, also get the number | 284 | pmu_set_power_domain(PMU_PWRDN_SCU, true); |
236 | * of cores from the scu to verify this value when booting the cores. | 285 | |
237 | */ | 286 | node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); |
238 | ncores = scu_get_core_count(scu_base_addr); | 287 | if (!node) { |
288 | pr_err("%s: missing scu\n", __func__); | ||
289 | return; | ||
290 | } | ||
239 | 291 | ||
240 | scu_enable(scu_base_addr); | 292 | scu_base_addr = of_iomap(node, 0); |
293 | if (!scu_base_addr) { | ||
294 | pr_err("%s: could not map scu registers\n", __func__); | ||
295 | return; | ||
296 | } | ||
297 | |||
298 | /* | ||
299 | * While the number of cpus is gathered from dt, also get the | ||
300 | * number of cores from the scu to verify this value when | ||
301 | * booting the cores. | ||
302 | */ | ||
303 | ncores = scu_get_core_count(scu_base_addr); | ||
304 | pr_err("%s: ncores %d\n", __func__, ncores); | ||
305 | |||
306 | scu_enable(scu_base_addr); | ||
307 | } else { | ||
308 | unsigned int l2ctlr; | ||
309 | |||
310 | asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr)); | ||
311 | ncores = ((l2ctlr >> 24) & 0x3) + 1; | ||
312 | } | ||
241 | 313 | ||
242 | /* Make sure that all cores except the first are really off */ | 314 | /* Make sure that all cores except the first are really off */ |
243 | for (i = 1; i < ncores; i++) | 315 | for (i = 1; i < ncores; i++) |