1*1ee89e22SGregory CLEMENT /* 2*1ee89e22SGregory CLEMENT * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 3*1ee89e22SGregory CLEMENT * based SOCs (Armada 375/38x). 4*1ee89e22SGregory CLEMENT * 5*1ee89e22SGregory CLEMENT * Copyright (C) 2014 Marvell 6*1ee89e22SGregory CLEMENT * 7*1ee89e22SGregory CLEMENT * Gregory CLEMENT <gregory.clement@free-electrons.com> 8*1ee89e22SGregory CLEMENT * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 9*1ee89e22SGregory CLEMENT * 10*1ee89e22SGregory CLEMENT * This file is licensed under the terms of the GNU General Public 11*1ee89e22SGregory CLEMENT * License version 2. This program is licensed "as is" without any 12*1ee89e22SGregory CLEMENT * warranty of any kind, whether express or implied. 13*1ee89e22SGregory CLEMENT */ 14*1ee89e22SGregory CLEMENT 15*1ee89e22SGregory CLEMENT #include <linux/init.h> 16*1ee89e22SGregory CLEMENT #include <linux/io.h> 17*1ee89e22SGregory CLEMENT #include <linux/of.h> 18*1ee89e22SGregory CLEMENT #include <linux/smp.h> 19*1ee89e22SGregory CLEMENT #include <asm/smp_scu.h> 20*1ee89e22SGregory CLEMENT #include <asm/smp_plat.h> 21*1ee89e22SGregory CLEMENT #include "common.h" 22*1ee89e22SGregory CLEMENT #include "pmsu.h" 23*1ee89e22SGregory CLEMENT 24*1ee89e22SGregory CLEMENT extern void mvebu_cortex_a9_secondary_startup(void); 25*1ee89e22SGregory CLEMENT 26*1ee89e22SGregory CLEMENT static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu, 27*1ee89e22SGregory CLEMENT struct task_struct *idle) 28*1ee89e22SGregory CLEMENT { 29*1ee89e22SGregory CLEMENT int ret, hw_cpu; 30*1ee89e22SGregory CLEMENT 31*1ee89e22SGregory CLEMENT pr_info("Booting CPU %d\n", cpu); 32*1ee89e22SGregory CLEMENT 33*1ee89e22SGregory CLEMENT /* 34*1ee89e22SGregory CLEMENT * Write the address of secondary startup into the system-wide 35*1ee89e22SGregory CLEMENT * flags register. The boot monitor waits until it receives a 36*1ee89e22SGregory CLEMENT * soft interrupt, and then the secondary CPU branches to this 37*1ee89e22SGregory CLEMENT * address. 38*1ee89e22SGregory CLEMENT */ 39*1ee89e22SGregory CLEMENT hw_cpu = cpu_logical_map(cpu); 40*1ee89e22SGregory CLEMENT 41*1ee89e22SGregory CLEMENT if (of_machine_is_compatible("marvell,armada375")) 42*1ee89e22SGregory CLEMENT mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); 43*1ee89e22SGregory CLEMENT else 44*1ee89e22SGregory CLEMENT mvebu_pmsu_set_cpu_boot_addr(hw_cpu, 45*1ee89e22SGregory CLEMENT mvebu_cortex_a9_secondary_startup); 46*1ee89e22SGregory CLEMENT 47*1ee89e22SGregory CLEMENT smp_wmb(); 48*1ee89e22SGregory CLEMENT ret = mvebu_cpu_reset_deassert(hw_cpu); 49*1ee89e22SGregory CLEMENT if (ret) { 50*1ee89e22SGregory CLEMENT pr_err("Could not start the secondary CPU: %d\n", ret); 51*1ee89e22SGregory CLEMENT return ret; 52*1ee89e22SGregory CLEMENT } 53*1ee89e22SGregory CLEMENT arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 54*1ee89e22SGregory CLEMENT 55*1ee89e22SGregory CLEMENT return 0; 56*1ee89e22SGregory CLEMENT } 57*1ee89e22SGregory CLEMENT 58*1ee89e22SGregory CLEMENT static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = { 59*1ee89e22SGregory CLEMENT .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 60*1ee89e22SGregory CLEMENT #ifdef CONFIG_HOTPLUG_CPU 61*1ee89e22SGregory CLEMENT .cpu_die = armada_xp_cpu_die, 62*1ee89e22SGregory CLEMENT #endif 63*1ee89e22SGregory CLEMENT }; 64*1ee89e22SGregory CLEMENT 65*1ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 66*1ee89e22SGregory CLEMENT &mvebu_cortex_a9_smp_ops); 67*1ee89e22SGregory CLEMENT CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 68*1ee89e22SGregory CLEMENT &mvebu_cortex_a9_smp_ops); 69