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