18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9 38c2ecf20Sopenharmony_ci * based SOCs (Armada 375/38x). 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2014 Marvell 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Gregory CLEMENT <gregory.clement@free-electrons.com> 88c2ecf20Sopenharmony_ci * Thomas Petazzoni <thomas.petazzoni@free-electrons.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 118c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 128c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 138c2ecf20Sopenharmony_ci */ 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#include <linux/init.h> 168c2ecf20Sopenharmony_ci#include <linux/io.h> 178c2ecf20Sopenharmony_ci#include <linux/of.h> 188c2ecf20Sopenharmony_ci#include <linux/smp.h> 198c2ecf20Sopenharmony_ci#include <linux/mbus.h> 208c2ecf20Sopenharmony_ci#include <asm/smp_scu.h> 218c2ecf20Sopenharmony_ci#include <asm/smp_plat.h> 228c2ecf20Sopenharmony_ci#include "common.h" 238c2ecf20Sopenharmony_ci#include "pmsu.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciextern void mvebu_cortex_a9_secondary_startup(void); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic int mvebu_cortex_a9_boot_secondary(unsigned int cpu, 288c2ecf20Sopenharmony_ci struct task_struct *idle) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci int ret, hw_cpu; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci pr_info("Booting CPU %d\n", cpu); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci /* 358c2ecf20Sopenharmony_ci * Write the address of secondary startup into the system-wide 368c2ecf20Sopenharmony_ci * flags register. The boot monitor waits until it receives a 378c2ecf20Sopenharmony_ci * soft interrupt, and then the secondary CPU branches to this 388c2ecf20Sopenharmony_ci * address. 398c2ecf20Sopenharmony_ci */ 408c2ecf20Sopenharmony_ci hw_cpu = cpu_logical_map(cpu); 418c2ecf20Sopenharmony_ci if (of_machine_is_compatible("marvell,armada375")) 428c2ecf20Sopenharmony_ci mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup); 438c2ecf20Sopenharmony_ci else 448c2ecf20Sopenharmony_ci mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup); 458c2ecf20Sopenharmony_ci smp_wmb(); 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_ci /* 488c2ecf20Sopenharmony_ci * Doing this before deasserting the CPUs is needed to wake up CPUs 498c2ecf20Sopenharmony_ci * in the offline state after using CPU hotplug. 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci arch_send_wakeup_ipi_mask(cpumask_of(cpu)); 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci ret = mvebu_cpu_reset_deassert(hw_cpu); 548c2ecf20Sopenharmony_ci if (ret) { 558c2ecf20Sopenharmony_ci pr_err("Could not start the secondary CPU: %d\n", ret); 568c2ecf20Sopenharmony_ci return ret; 578c2ecf20Sopenharmony_ci } 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci/* 628c2ecf20Sopenharmony_ci * When a CPU is brought back online, either through CPU hotplug, or 638c2ecf20Sopenharmony_ci * because of the boot of a kexec'ed kernel, the PMSU configuration 648c2ecf20Sopenharmony_ci * for this CPU might be in the deep idle state, preventing this CPU 658c2ecf20Sopenharmony_ci * from receiving interrupts. Here, we therefore take out the current 668c2ecf20Sopenharmony_ci * CPU from this state, which was entered by armada_38x_cpu_die() 678c2ecf20Sopenharmony_ci * below. 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistatic void armada_38x_secondary_init(unsigned int cpu) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci mvebu_v7_pmsu_idle_exit(); 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 758c2ecf20Sopenharmony_cistatic void armada_38x_cpu_die(unsigned int cpu) 768c2ecf20Sopenharmony_ci{ 778c2ecf20Sopenharmony_ci /* 788c2ecf20Sopenharmony_ci * CPU hotplug is implemented by putting offline CPUs into the 798c2ecf20Sopenharmony_ci * deep idle sleep state. 808c2ecf20Sopenharmony_ci */ 818c2ecf20Sopenharmony_ci armada_38x_do_cpu_suspend(true); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * We need a dummy function, so that platform_can_cpu_hotplug() knows 868c2ecf20Sopenharmony_ci * we support CPU hotplug. However, the function does not need to do 878c2ecf20Sopenharmony_ci * anything, because CPUs going offline can enter the deep idle state 888c2ecf20Sopenharmony_ci * by themselves, without any help from a still alive CPU. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_cistatic int armada_38x_cpu_kill(unsigned int cpu) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci return 1; 938c2ecf20Sopenharmony_ci} 948c2ecf20Sopenharmony_ci#endif 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_cistatic const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = { 978c2ecf20Sopenharmony_ci .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic const struct smp_operations armada_38x_smp_ops __initconst = { 1018c2ecf20Sopenharmony_ci .smp_boot_secondary = mvebu_cortex_a9_boot_secondary, 1028c2ecf20Sopenharmony_ci .smp_secondary_init = armada_38x_secondary_init, 1038c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU 1048c2ecf20Sopenharmony_ci .cpu_die = armada_38x_cpu_die, 1058c2ecf20Sopenharmony_ci .cpu_kill = armada_38x_cpu_kill, 1068c2ecf20Sopenharmony_ci#endif 1078c2ecf20Sopenharmony_ci}; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp", 1108c2ecf20Sopenharmony_ci &mvebu_cortex_a9_smp_ops); 1118c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp", 1128c2ecf20Sopenharmony_ci &armada_38x_smp_ops); 1138c2ecf20Sopenharmony_ciCPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp", 1148c2ecf20Sopenharmony_ci &armada_38x_smp_ops); 115