xref: /openbmc/linux/arch/arm/mach-mvebu/platsmp-a9.c (revision ff6138ad196d7591d07d4c465c03e90dd86d61db)
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 
27*ff6138adSPaul Gortmaker static int 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();
46626d6864SGregory CLEMENT 
47626d6864SGregory CLEMENT 	/*
48626d6864SGregory CLEMENT 	 * Doing this before deasserting the CPUs is needed to wake up CPUs
49626d6864SGregory CLEMENT 	 * in the offline state after using CPU hotplug.
50626d6864SGregory CLEMENT 	 */
51626d6864SGregory CLEMENT 	arch_send_wakeup_ipi_mask(cpumask_of(cpu));
52626d6864SGregory 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 }
61626d6864SGregory CLEMENT /*
62626d6864SGregory CLEMENT  * When a CPU is brought back online, either through CPU hotplug, or
63626d6864SGregory CLEMENT  * because of the boot of a kexec'ed kernel, the PMSU configuration
64626d6864SGregory CLEMENT  * for this CPU might be in the deep idle state, preventing this CPU
65626d6864SGregory CLEMENT  * from receiving interrupts. Here, we therefore take out the current
66626d6864SGregory CLEMENT  * CPU from this state, which was entered by armada_38x_cpu_die()
67626d6864SGregory CLEMENT  * below.
68626d6864SGregory CLEMENT  */
69626d6864SGregory CLEMENT static void armada_38x_secondary_init(unsigned int cpu)
70626d6864SGregory CLEMENT {
71626d6864SGregory CLEMENT 	mvebu_v7_pmsu_idle_exit();
72626d6864SGregory CLEMENT }
73626d6864SGregory CLEMENT 
74626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
75626d6864SGregory CLEMENT static void armada_38x_cpu_die(unsigned int cpu)
76626d6864SGregory CLEMENT {
77626d6864SGregory CLEMENT 	/*
78626d6864SGregory CLEMENT 	 * CPU hotplug is implemented by putting offline CPUs into the
79626d6864SGregory CLEMENT 	 * deep idle sleep state.
80626d6864SGregory CLEMENT 	 */
81626d6864SGregory CLEMENT 	armada_38x_do_cpu_suspend(true);
82626d6864SGregory CLEMENT }
83626d6864SGregory CLEMENT 
84626d6864SGregory CLEMENT /*
85626d6864SGregory CLEMENT  * We need a dummy function, so that platform_can_cpu_hotplug() knows
86626d6864SGregory CLEMENT  * we support CPU hotplug. However, the function does not need to do
87626d6864SGregory CLEMENT  * anything, because CPUs going offline can enter the deep idle state
88626d6864SGregory CLEMENT  * by themselves, without any help from a still alive CPU.
89626d6864SGregory CLEMENT  */
90626d6864SGregory CLEMENT static int armada_38x_cpu_kill(unsigned int cpu)
91626d6864SGregory CLEMENT {
92626d6864SGregory CLEMENT 	return 1;
93626d6864SGregory CLEMENT }
94626d6864SGregory 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 
100626d6864SGregory CLEMENT static struct smp_operations armada_38x_smp_ops __initdata = {
101626d6864SGregory CLEMENT 	.smp_boot_secondary	= mvebu_cortex_a9_boot_secondary,
102626d6864SGregory CLEMENT 	.smp_secondary_init     = armada_38x_secondary_init,
103626d6864SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU
104626d6864SGregory CLEMENT 	.cpu_die		= armada_38x_cpu_die,
105626d6864SGregory CLEMENT 	.cpu_kill               = armada_38x_cpu_kill,
106626d6864SGregory CLEMENT #endif
107626d6864SGregory CLEMENT };
108626d6864SGregory 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",
112626d6864SGregory CLEMENT 		      &armada_38x_smp_ops);
113242ede0bSThomas Petazzoni CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp",
114242ede0bSThomas Petazzoni 		      &armada_38x_smp_ops);
115