1*0fdebc5eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21ee89e22SGregory CLEMENT /*
31ee89e22SGregory CLEMENT * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
41ee89e22SGregory CLEMENT * based SOCs (Armada 375/38x).
51ee89e22SGregory CLEMENT *
61ee89e22SGregory CLEMENT * Copyright (C) 2014 Marvell
71ee89e22SGregory CLEMENT *
81ee89e22SGregory CLEMENT * Gregory CLEMENT <gregory.clement@free-electrons.com>
91ee89e22SGregory CLEMENT * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
101ee89e22SGregory CLEMENT */
111ee89e22SGregory CLEMENT
121ee89e22SGregory CLEMENT #include <linux/init.h>
131ee89e22SGregory CLEMENT #include <linux/io.h>
141ee89e22SGregory CLEMENT #include <linux/of.h>
151ee89e22SGregory CLEMENT #include <linux/smp.h>
1687384cc0SGregory CLEMENT #include <linux/mbus.h>
171ee89e22SGregory CLEMENT #include <asm/smp_scu.h>
181ee89e22SGregory CLEMENT #include <asm/smp_plat.h>
191ee89e22SGregory CLEMENT #include "common.h"
201ee89e22SGregory CLEMENT #include "pmsu.h"
211ee89e22SGregory CLEMENT
221ee89e22SGregory CLEMENT extern void mvebu_cortex_a9_secondary_startup(void);
231ee89e22SGregory CLEMENT
mvebu_cortex_a9_boot_secondary(unsigned int cpu,struct task_struct * idle)24ff6138adSPaul Gortmaker static int mvebu_cortex_a9_boot_secondary(unsigned int cpu,
251ee89e22SGregory CLEMENT struct task_struct *idle)
261ee89e22SGregory CLEMENT {
271ee89e22SGregory CLEMENT int ret, hw_cpu;
281ee89e22SGregory CLEMENT
291ee89e22SGregory CLEMENT pr_info("Booting CPU %d\n", cpu);
301ee89e22SGregory CLEMENT
311ee89e22SGregory CLEMENT /*
321ee89e22SGregory CLEMENT * Write the address of secondary startup into the system-wide
331ee89e22SGregory CLEMENT * flags register. The boot monitor waits until it receives a
341ee89e22SGregory CLEMENT * soft interrupt, and then the secondary CPU branches to this
351ee89e22SGregory CLEMENT * address.
361ee89e22SGregory CLEMENT */
371ee89e22SGregory CLEMENT hw_cpu = cpu_logical_map(cpu);
38305969fbSGregory CLEMENT if (of_machine_is_compatible("marvell,armada375"))
391ee89e22SGregory CLEMENT mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
40305969fbSGregory CLEMENT else
41305969fbSGregory CLEMENT mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
421ee89e22SGregory CLEMENT smp_wmb();
43626d6864SGregory CLEMENT
44626d6864SGregory CLEMENT /*
45626d6864SGregory CLEMENT * Doing this before deasserting the CPUs is needed to wake up CPUs
46626d6864SGregory CLEMENT * in the offline state after using CPU hotplug.
47626d6864SGregory CLEMENT */
48626d6864SGregory CLEMENT arch_send_wakeup_ipi_mask(cpumask_of(cpu));
49626d6864SGregory CLEMENT
501ee89e22SGregory CLEMENT ret = mvebu_cpu_reset_deassert(hw_cpu);
511ee89e22SGregory CLEMENT if (ret) {
521ee89e22SGregory CLEMENT pr_err("Could not start the secondary CPU: %d\n", ret);
531ee89e22SGregory CLEMENT return ret;
541ee89e22SGregory CLEMENT }
551ee89e22SGregory CLEMENT
561ee89e22SGregory CLEMENT return 0;
571ee89e22SGregory CLEMENT }
58626d6864SGregory CLEMENT /*
59626d6864SGregory CLEMENT * When a CPU is brought back online, either through CPU hotplug, or
60626d6864SGregory CLEMENT * because of the boot of a kexec'ed kernel, the PMSU configuration
61626d6864SGregory CLEMENT * for this CPU might be in the deep idle state, preventing this CPU
62626d6864SGregory CLEMENT * from receiving interrupts. Here, we therefore take out the current
63626d6864SGregory CLEMENT * CPU from this state, which was entered by armada_38x_cpu_die()
64626d6864SGregory CLEMENT * below.
65626d6864SGregory CLEMENT */
armada_38x_secondary_init(unsigned int cpu)66626d6864SGregory CLEMENT static void armada_38x_secondary_init(unsigned int cpu)
67626d6864SGregory CLEMENT {
68626d6864SGregory CLEMENT mvebu_v7_pmsu_idle_exit();
69626d6864SGregory CLEMENT }
70626d6864SGregory CLEMENT
71626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
armada_38x_cpu_die(unsigned int cpu)72626d6864SGregory CLEMENT static void armada_38x_cpu_die(unsigned int cpu)
73626d6864SGregory CLEMENT {
74626d6864SGregory CLEMENT /*
75626d6864SGregory CLEMENT * CPU hotplug is implemented by putting offline CPUs into the
76626d6864SGregory CLEMENT * deep idle sleep state.
77626d6864SGregory CLEMENT */
78626d6864SGregory CLEMENT armada_38x_do_cpu_suspend(true);
79626d6864SGregory CLEMENT }
80626d6864SGregory CLEMENT
81626d6864SGregory CLEMENT /*
82626d6864SGregory CLEMENT * We need a dummy function, so that platform_can_cpu_hotplug() knows
83626d6864SGregory CLEMENT * we support CPU hotplug. However, the function does not need to do
84626d6864SGregory CLEMENT * anything, because CPUs going offline can enter the deep idle state
85626d6864SGregory CLEMENT * by themselves, without any help from a still alive CPU.
86626d6864SGregory CLEMENT */
armada_38x_cpu_kill(unsigned int cpu)87626d6864SGregory CLEMENT static int armada_38x_cpu_kill(unsigned int cpu)
88626d6864SGregory CLEMENT {
89626d6864SGregory CLEMENT return 1;
90626d6864SGregory CLEMENT }
91626d6864SGregory CLEMENT #endif
921ee89e22SGregory CLEMENT
9375305275SMasahiro Yamada static const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = {
941ee89e22SGregory CLEMENT .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
951ee89e22SGregory CLEMENT };
961ee89e22SGregory CLEMENT
9775305275SMasahiro Yamada static const struct smp_operations armada_38x_smp_ops __initconst = {
98626d6864SGregory CLEMENT .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
99626d6864SGregory CLEMENT .smp_secondary_init = armada_38x_secondary_init,
100626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
101626d6864SGregory CLEMENT .cpu_die = armada_38x_cpu_die,
102626d6864SGregory CLEMENT .cpu_kill = armada_38x_cpu_kill,
103626d6864SGregory CLEMENT #endif
104626d6864SGregory CLEMENT };
105626d6864SGregory CLEMENT
1061ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
1071ee89e22SGregory CLEMENT &mvebu_cortex_a9_smp_ops);
1081ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
109626d6864SGregory CLEMENT &armada_38x_smp_ops);
110242ede0bSThomas Petazzoni CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp",
111242ede0bSThomas Petazzoni &armada_38x_smp_ops);
112