xref: /openbmc/linux/arch/arm/mach-mvebu/platsmp-a9.c (revision 626d686487bfd8136c4543bee7b6b2e52c33b3f8)
11ee89e22SGregory CLEMENT /*
21ee89e22SGregory CLEMENT  * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
31ee89e22SGregory CLEMENT  * based SOCs (Armada 375/38x).
41ee89e22SGregory CLEMENT  *
51ee89e22SGregory CLEMENT  * Copyright (C) 2014 Marvell
61ee89e22SGregory CLEMENT  *
71ee89e22SGregory CLEMENT  * Gregory CLEMENT <gregory.clement@free-electrons.com>
81ee89e22SGregory CLEMENT  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
91ee89e22SGregory CLEMENT  *
101ee89e22SGregory CLEMENT  * This file is licensed under the terms of the GNU General Public
111ee89e22SGregory CLEMENT  * License version 2.  This program is licensed "as is" without any
121ee89e22SGregory CLEMENT  * warranty of any kind, whether express or implied.
131ee89e22SGregory CLEMENT  */
141ee89e22SGregory CLEMENT 
151ee89e22SGregory CLEMENT #include <linux/init.h>
161ee89e22SGregory CLEMENT #include <linux/io.h>
171ee89e22SGregory CLEMENT #include <linux/of.h>
181ee89e22SGregory CLEMENT #include <linux/smp.h>
1987384cc0SGregory CLEMENT #include <linux/mbus.h>
201ee89e22SGregory CLEMENT #include <asm/smp_scu.h>
211ee89e22SGregory CLEMENT #include <asm/smp_plat.h>
221ee89e22SGregory CLEMENT #include "common.h"
231ee89e22SGregory CLEMENT #include "pmsu.h"
241ee89e22SGregory CLEMENT 
251ee89e22SGregory CLEMENT extern void mvebu_cortex_a9_secondary_startup(void);
261ee89e22SGregory CLEMENT 
271ee89e22SGregory CLEMENT static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
281ee89e22SGregory CLEMENT 						    struct task_struct *idle)
291ee89e22SGregory CLEMENT {
301ee89e22SGregory CLEMENT 	int ret, hw_cpu;
311ee89e22SGregory CLEMENT 
321ee89e22SGregory CLEMENT 	pr_info("Booting CPU %d\n", cpu);
331ee89e22SGregory CLEMENT 
341ee89e22SGregory CLEMENT 	/*
351ee89e22SGregory CLEMENT 	 * Write the address of secondary startup into the system-wide
361ee89e22SGregory CLEMENT 	 * flags register. The boot monitor waits until it receives a
371ee89e22SGregory CLEMENT 	 * soft interrupt, and then the secondary CPU branches to this
381ee89e22SGregory CLEMENT 	 * address.
391ee89e22SGregory CLEMENT 	 */
401ee89e22SGregory CLEMENT 	hw_cpu = cpu_logical_map(cpu);
41305969fbSGregory CLEMENT 	if (of_machine_is_compatible("marvell,armada375"))
421ee89e22SGregory CLEMENT 		mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
43305969fbSGregory CLEMENT 	else
44305969fbSGregory CLEMENT 		mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
451ee89e22SGregory CLEMENT 	smp_wmb();
46*626d6864SGregory CLEMENT 
47*626d6864SGregory CLEMENT 	/*
48*626d6864SGregory CLEMENT 	 * Doing this before deasserting the CPUs is needed to wake up CPUs
49*626d6864SGregory CLEMENT 	 * in the offline state after using CPU hotplug.
50*626d6864SGregory CLEMENT 	 */
51*626d6864SGregory CLEMENT 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
52*626d6864SGregory CLEMENT 
531ee89e22SGregory CLEMENT 	ret = mvebu_cpu_reset_deassert(hw_cpu);
541ee89e22SGregory CLEMENT 	if (ret) {
551ee89e22SGregory CLEMENT 		pr_err("Could not start the secondary CPU: %d\n", ret);
561ee89e22SGregory CLEMENT 		return ret;
571ee89e22SGregory CLEMENT 	}
581ee89e22SGregory CLEMENT 
591ee89e22SGregory CLEMENT 	return 0;
601ee89e22SGregory CLEMENT }
61*626d6864SGregory CLEMENT /*
62*626d6864SGregory CLEMENT  * When a CPU is brought back online, either through CPU hotplug, or
63*626d6864SGregory CLEMENT  * because of the boot of a kexec'ed kernel, the PMSU configuration
64*626d6864SGregory CLEMENT  * for this CPU might be in the deep idle state, preventing this CPU
65*626d6864SGregory CLEMENT  * from receiving interrupts. Here, we therefore take out the current
66*626d6864SGregory CLEMENT  * CPU from this state, which was entered by armada_38x_cpu_die()
67*626d6864SGregory CLEMENT  * below.
68*626d6864SGregory CLEMENT  */
69*626d6864SGregory CLEMENT static void armada_38x_secondary_init(unsigned int cpu)
70*626d6864SGregory CLEMENT {
71*626d6864SGregory CLEMENT 	mvebu_v7_pmsu_idle_exit();
72*626d6864SGregory CLEMENT }
73*626d6864SGregory CLEMENT 
74*626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
75*626d6864SGregory CLEMENT static void armada_38x_cpu_die(unsigned int cpu)
76*626d6864SGregory CLEMENT {
77*626d6864SGregory CLEMENT 	/*
78*626d6864SGregory CLEMENT 	 * CPU hotplug is implemented by putting offline CPUs into the
79*626d6864SGregory CLEMENT 	 * deep idle sleep state.
80*626d6864SGregory CLEMENT 	 */
81*626d6864SGregory CLEMENT 	armada_38x_do_cpu_suspend(true);
82*626d6864SGregory CLEMENT }
83*626d6864SGregory CLEMENT 
84*626d6864SGregory CLEMENT /*
85*626d6864SGregory CLEMENT  * We need a dummy function, so that platform_can_cpu_hotplug() knows
86*626d6864SGregory CLEMENT  * we support CPU hotplug. However, the function does not need to do
87*626d6864SGregory CLEMENT  * anything, because CPUs going offline can enter the deep idle state
88*626d6864SGregory CLEMENT  * by themselves, without any help from a still alive CPU.
89*626d6864SGregory CLEMENT  */
90*626d6864SGregory CLEMENT static int armada_38x_cpu_kill(unsigned int cpu)
91*626d6864SGregory CLEMENT {
92*626d6864SGregory CLEMENT 	return 1;
93*626d6864SGregory CLEMENT }
94*626d6864SGregory CLEMENT #endif
951ee89e22SGregory CLEMENT 
961ee89e22SGregory CLEMENT static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
971ee89e22SGregory CLEMENT 	.smp_boot_secondary	= mvebu_cortex_a9_boot_secondary,
981ee89e22SGregory CLEMENT };
991ee89e22SGregory CLEMENT 
100*626d6864SGregory CLEMENT static struct smp_operations armada_38x_smp_ops __initdata = {
101*626d6864SGregory CLEMENT 	.smp_boot_secondary	= mvebu_cortex_a9_boot_secondary,
102*626d6864SGregory CLEMENT 	.smp_secondary_init     = armada_38x_secondary_init,
103*626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
104*626d6864SGregory CLEMENT 	.cpu_die		= armada_38x_cpu_die,
105*626d6864SGregory CLEMENT 	.cpu_kill               = armada_38x_cpu_kill,
106*626d6864SGregory CLEMENT #endif
107*626d6864SGregory CLEMENT };
108*626d6864SGregory CLEMENT 
1091ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
1101ee89e22SGregory CLEMENT 		      &mvebu_cortex_a9_smp_ops);
1111ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
112*626d6864SGregory CLEMENT 		      &armada_38x_smp_ops);
113