summaryrefslogtreecommitdiff
path: root/arch/arm/mach-mvebu
diff options
context:
space:
mode:
authorChris Packham <chris.packham@alliedtelesis.co.nz>2017-01-30 12:20:32 +1300
committerGregory CLEMENT <gregory.clement@free-electrons.com>2017-01-30 14:40:56 +0100
commitdb88977894aba193deee70b335c3db58b7ac6393 (patch)
tree835ade911a91200bf1e8cf6d2a3d5e6fedb620d1 /arch/arm/mach-mvebu
parentf2591b993ec95fd8d67c68187f07f30c9d79b38c (diff)
arm: mvebu: support for SMP on 98DX3336 SoC
Compared to the armada-xp the 98DX3336 uses different registers to set the boot address for the secondary CPU so a new enable-method is needed. This will only work if the machine definition doesn't define an overall smp_ops because there is not currently a way of overriding this from the device tree if it is set in the machine definition. Signed-off-by: Chris Packham <chris.packham@alliedtelesis.co.nz> Acked-by: Rob Herring <robh@kernel.org> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
Diffstat (limited to 'arch/arm/mach-mvebu')
-rw-r--r--arch/arm/mach-mvebu/platsmp.c75
1 files changed, 75 insertions, 0 deletions
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 = {
CPU_METHOD_OF_DECLARE(armada_xp_smp, "marvell,armada-xp-smp",
&armada_xp_smp_ops);
+
+#define MV98DX3236_CPU_RESUME_CTRL_REG 0x08
+#define MV98DX3236_CPU_RESUME_ADDR_REG 0x04
+
+static const struct of_device_id of_mv98dx3236_resume_table[] = {
+ {
+ .compatible = "marvell,98dx3336-resume-ctrl",
+ },
+ { /* end of list */ },
+};
+
+static int mv98dx3236_resume_set_cpu_boot_addr(int hw_cpu, void *boot_addr)
+{
+ struct device_node *np;
+ void __iomem *base;
+ WARN_ON(hw_cpu != 1);
+
+ np = of_find_matching_node(NULL, of_mv98dx3236_resume_table);
+ if (!np)
+ return -ENODEV;
+
+ base = of_io_request_and_map(np, 0, of_node_full_name(np));
+ of_node_put(np);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ writel(0, base + MV98DX3236_CPU_RESUME_CTRL_REG);
+ writel(virt_to_phys(boot_addr), base + MV98DX3236_CPU_RESUME_ADDR_REG);
+
+ iounmap(base);
+
+ return 0;
+}
+
+static int mv98dx3236_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ int ret, hw_cpu;
+
+ hw_cpu = cpu_logical_map(cpu);
+ set_secondary_cpu_clock(hw_cpu);
+ mv98dx3236_resume_set_cpu_boot_addr(hw_cpu,
+ armada_xp_secondary_startup);
+
+ /*
+ * This is needed to wake up CPUs in the offline state after
+ * using CPU hotplug.
+ */
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ /*
+ * This is needed to take secondary CPUs out of reset on the
+ * initial boot.
+ */
+ ret = mvebu_cpu_reset_deassert(hw_cpu);
+ if (ret) {
+ pr_warn("unable to boot CPU: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct smp_operations mv98dx3236_smp_ops __initconst = {
+ .smp_init_cpus = armada_xp_smp_init_cpus,
+ .smp_prepare_cpus = armada_xp_smp_prepare_cpus,
+ .smp_boot_secondary = mv98dx3236_boot_secondary,
+ .smp_secondary_init = armada_xp_secondary_init,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = armada_xp_cpu_die,
+ .cpu_kill = armada_xp_cpu_kill,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(mv98dx3236_smp, "marvell,98dx3236-smp",
+ &mv98dx3236_smp_ops);