xref: /linux/arch/arm/mach-mvebu/platsmp-a9.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
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