platsmp-a9.c (3395B)
1/* 2 * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 3 * based SOCs (Armada 375/38x). 4 * 5 * Copyright (C) 2014 Marvell 6 * 7 * Gregory CLEMENT <gregory.clement@free-electrons.com> 8 * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 9 * 10 * This file is licensed under the terms of the GNU General Public 11 * License version 2. This program is licensed "as is" without any 12 * warranty of any kind, whether express or implied. 13 */ 14 15#include <linux/init.h> 16#include <linux/io.h> 17#include <linux/of.h> 18#include <linux/smp.h> 19#include <linux/mbus.h> 20#include <asm/smp_scu.h> 21#include <asm/smp_plat.h> 22#include "common.h" 23#include "pmsu.h" 24 25extern void mvebu_cortex_a9_secondary_startup(void); 26 27static int mvebu_cortex_a9_boot_secondary(unsigned int cpu, 28 struct task_struct *idle) 29{ 30 int ret, hw_cpu; 31 32 pr_info("Booting CPU %d\n", cpu); 33 34 /* 35 * Write the address of secondary startup into the system-wide 36 * flags register. The boot monitor waits until it receives a 37 * soft interrupt, and then the secondary CPU branches to this 38 * address. 39 */ 40 hw_cpu = cpu_logical_map(cpu); 41 if (of_machine_is_compatible("marvell,armada375")) 42 mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); 43 else 44 mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); 45 smp_wmb(); 46 47 /* 48 * Doing this before deasserting the CPUs is needed to wake up CPUs 49 * in the offline state after using CPU hotplug. 50 */ 51 arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 52 53 ret = mvebu_cpu_reset_deassert(hw_cpu); 54 if (ret) { 55 pr_err("Could not start the secondary CPU: %d\n", ret); 56 return ret; 57 } 58 59 return 0; 60} 61/* 62 * When a CPU is brought back online, either through CPU hotplug, or 63 * because of the boot of a kexec'ed kernel, the PMSU configuration 64 * for this CPU might be in the deep idle state, preventing this CPU 65 * from receiving interrupts. Here, we therefore take out the current 66 * CPU from this state, which was entered by armada_38x_cpu_die() 67 * below. 68 */ 69static void armada_38x_secondary_init(unsigned int cpu) 70{ 71 mvebu_v7_pmsu_idle_exit(); 72} 73 74#ifdef CONFIG_HOTPLUG_CPU 75static void armada_38x_cpu_die(unsigned int cpu) 76{ 77 /* 78 * CPU hotplug is implemented by putting offline CPUs into the 79 * deep idle sleep state. 80 */ 81 armada_38x_do_cpu_suspend(true); 82} 83 84/* 85 * We need a dummy function, so that platform_can_cpu_hotplug() knows 86 * we support CPU hotplug. However, the function does not need to do 87 * anything, because CPUs going offline can enter the deep idle state 88 * by themselves, without any help from a still alive CPU. 89 */ 90static int armada_38x_cpu_kill(unsigned int cpu) 91{ 92 return 1; 93} 94#endif 95 96static const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = { 97 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 98}; 99 100static const struct smp_operations armada_38x_smp_ops __initconst = { 101 .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 102 .smp_secondary_init = armada_38x_secondary_init, 103#ifdef CONFIG_HOTPLUG_CPU 104 .cpu_die = armada_38x_cpu_die, 105 .cpu_kill = armada_38x_cpu_kill, 106#endif 107}; 108 109CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 110 &mvebu_cortex_a9_smp_ops); 111CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 112 &armada_38x_smp_ops); 113CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp", 114 &armada_38x_smp_ops);