diff options
-rw-r--r-- | Documentation/devicetree/bindings/arm/cpus.txt | 1 | ||||
-rw-r--r-- | Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt | 16 | ||||
-rw-r--r-- | arch/arm/mach-mvebu/platsmp.c | 75 |
3 files changed, 92 insertions, 0 deletions
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt index a1bcfeed5f24..3c2fd72d0bf9 100644 --- a/Documentation/devicetree/bindings/arm/cpus.txt +++ b/Documentation/devicetree/bindings/arm/cpus.txt | |||
@@ -202,6 +202,7 @@ nodes to be present and contain the properties described below. | |||
202 | "marvell,armada-380-smp" | 202 | "marvell,armada-380-smp" |
203 | "marvell,armada-390-smp" | 203 | "marvell,armada-390-smp" |
204 | "marvell,armada-xp-smp" | 204 | "marvell,armada-xp-smp" |
205 | "marvell,98dx3236-smp" | ||
205 | "mediatek,mt6589-smp" | 206 | "mediatek,mt6589-smp" |
206 | "mediatek,mt81xx-tz-smp" | 207 | "mediatek,mt81xx-tz-smp" |
207 | "qcom,gcc-msm8660" | 208 | "qcom,gcc-msm8660" |
diff --git a/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt new file mode 100644 index 000000000000..26eb9d3aa630 --- /dev/null +++ b/Documentation/devicetree/bindings/arm/marvell/98dx3236-resume-ctrl.txt | |||
@@ -0,0 +1,16 @@ | |||
1 | Resume Control | ||
2 | -------------- | ||
3 | Available on Marvell SOCs: 98DX3336 and 98DX4251 | ||
4 | |||
5 | Required properties: | ||
6 | |||
7 | - compatible: must be "marvell,98dx3336-resume-ctrl" | ||
8 | |||
9 | - reg: Should contain resume control registers location and length | ||
10 | |||
11 | Example: | ||
12 | |||
13 | resume@20980 { | ||
14 | compatible = "marvell,98dx3336-resume-ctrl"; | ||
15 | reg = <0x20980 0x10>; | ||
16 | }; | ||
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c index 46c742d3bd41..e62273aacb43 100644 --- a/arch/arm/mach-mvebu/platsmp.c +++ b/arch/arm/mach-mvebu/platsmp.c | |||
@@ -184,3 +184,78 @@ const struct smp_operations armada_xp_smp_ops __initconst = { | |||
184 | 184 | ||
185 | CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp", | 185 | CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp", |
186 | &armada_xp_smp_ops); | 186 | &armada_xp_smp_ops); |
187 | |||
188 | #define MV98DX3236_CPU_RESUME_CTRL_REG 0x08 | ||
189 | #define MV98DX3236_CPU_RESUME_ADDR_REG 0x04 | ||
190 | |||
191 | static const struct of_device_id of_mv98dx3236_resume_table[] = { | ||
192 | { | ||
193 | .compatible = "marvell,98dx3336-resume-ctrl", | ||
194 | }, | ||
195 | { /* end of list */ }, | ||
196 | }; | ||
197 | |||
198 | static int mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr) | ||
199 | { | ||
200 | struct device_node *np; | ||
201 | void __iomem *base; | ||
202 | WARN_ON(hw_cpu != 1); | ||
203 | |||
204 | np = of_find_matching_node(NULL, of_mv98dx3236_resume_table); | ||
205 | if (!np) | ||
206 | return -ENODEV; | ||
207 | |||
208 | base = of_io_request_and_map(np, 0, of_node_full_name(np)); | ||
209 | of_node_put(np); | ||
210 | if (IS_ERR(base)) | ||
211 | return PTR_ERR(base); | ||
212 | |||
213 | writel(0, base + MV98DX3236_CPU_RESUME_CTRL_REG); | ||
214 | writel(virt_to_phys(boot_addr), base + MV98DX3236_CPU_RESUME_ADDR_REG); | ||
215 | |||
216 | iounmap(base); | ||
217 | |||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static int mv98dx3236_boot_secondary(unsigned int cpu, struct task_struct *idle) | ||
222 | { | ||
223 | int ret, hw_cpu; | ||
224 | |||
225 | hw_cpu = cpu_logical_map(cpu); | ||
226 | set_secondary_cpu_clock(hw_cpu); | ||
227 | mv98dx3236_resume_set_cpu_boot_addr(hw_cpu, | ||
228 | armada_xp_secondary_startup); | ||
229 | |||
230 | /* | ||
231 | * This is needed to wake up CPUs in the offline state after | ||
232 | * using CPU hotplug. | ||
233 | */ | ||
234 | arch_send_wakeup_ipi_mask(cpumask_of(cpu)); | ||
235 | |||
236 | /* | ||
237 | * This is needed to take secondary CPUs out of reset on the | ||
238 | * initial boot. | ||
239 | */ | ||
240 | ret = mvebu_cpu_reset_deassert(hw_cpu); | ||
241 | if (ret) { | ||
242 | pr_warn("unable to boot CPU: %d\n", ret); | ||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static const struct smp_operations mv98dx3236_smp_ops __initconst = { | ||
250 | .smp_init_cpus = armada_xp_smp_init_cpus, | ||
251 | .smp_prepare_cpus = armada_xp_smp_prepare_cpus, | ||
252 | .smp_boot_secondary = mv98dx3236_boot_secondary, | ||
253 | .smp_secondary_init = armada_xp_secondary_init, | ||
254 | #ifdef CONFIG_HOTPLUG_CPU | ||
255 | .cpu_die = armada_xp_cpu_die, | ||
256 | .cpu_kill = armada_xp_cpu_kill, | ||
257 | #endif | ||
258 | }; | ||
259 | |||
260 | CPU_METHOD_OF_DECLARE(mv98dx3236_smp, "marvell,98dx3236-smp", | ||
261 | &mv98dx3236_smp_ops); | ||