Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Symmetric Multi Processing (SMP) support for Marvell EBU Cortex-A9
0004  * based SOCs (Armada 375/38x).
0005  *
0006  * Copyright (C) 2014 Marvell
0007  *
0008  * Gregory CLEMENT <gregory.clement@free-electrons.com>
0009  * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
0010  */
0011 
0012 #include <linux/init.h>
0013 #include <linux/io.h>
0014 #include <linux/of.h>
0015 #include <linux/smp.h>
0016 #include <linux/mbus.h>
0017 #include <asm/smp_scu.h>
0018 #include <asm/smp_plat.h>
0019 #include "common.h"
0020 #include "pmsu.h"
0021 
0022 extern void mvebu_cortex_a9_secondary_startup(void);
0023 
0024 static int mvebu_cortex_a9_boot_secondary(unsigned int cpu,
0025                             struct task_struct *idle)
0026 {
0027     int ret, hw_cpu;
0028 
0029     pr_info("Booting CPU %d\n", cpu);
0030 
0031     /*
0032      * Write the address of secondary startup into the system-wide
0033      * flags register. The boot monitor waits until it receives a
0034      * soft interrupt, and then the secondary CPU branches to this
0035      * address.
0036      */
0037     hw_cpu = cpu_logical_map(cpu);
0038     if (of_machine_is_compatible("marvell,armada375"))
0039         mvebu_system_controller_set_cpu_boot_addr(mvebu_cortex_a9_secondary_startup);
0040     else
0041         mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
0042     smp_wmb();
0043 
0044     /*
0045      * Doing this before deasserting the CPUs is needed to wake up CPUs
0046      * in the offline state after using CPU hotplug.
0047      */
0048     arch_send_wakeup_ipi_mask(cpumask_of(cpu));
0049 
0050     ret = mvebu_cpu_reset_deassert(hw_cpu);
0051     if (ret) {
0052         pr_err("Could not start the secondary CPU: %d\n", ret);
0053         return ret;
0054     }
0055 
0056     return 0;
0057 }
0058 /*
0059  * When a CPU is brought back online, either through CPU hotplug, or
0060  * because of the boot of a kexec'ed kernel, the PMSU configuration
0061  * for this CPU might be in the deep idle state, preventing this CPU
0062  * from receiving interrupts. Here, we therefore take out the current
0063  * CPU from this state, which was entered by armada_38x_cpu_die()
0064  * below.
0065  */
0066 static void armada_38x_secondary_init(unsigned int cpu)
0067 {
0068     mvebu_v7_pmsu_idle_exit();
0069 }
0070 
0071 #ifdef CONFIG_HOTPLUG_CPU
0072 static void armada_38x_cpu_die(unsigned int cpu)
0073 {
0074     /*
0075      * CPU hotplug is implemented by putting offline CPUs into the
0076      * deep idle sleep state.
0077      */
0078     armada_38x_do_cpu_suspend(true);
0079 }
0080 
0081 /*
0082  * We need a dummy function, so that platform_can_cpu_hotplug() knows
0083  * we support CPU hotplug. However, the function does not need to do
0084  * anything, because CPUs going offline can enter the deep idle state
0085  * by themselves, without any help from a still alive CPU.
0086  */
0087 static int armada_38x_cpu_kill(unsigned int cpu)
0088 {
0089     return 1;
0090 }
0091 #endif
0092 
0093 static const struct smp_operations mvebu_cortex_a9_smp_ops __initconst = {
0094     .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
0095 };
0096 
0097 static const struct smp_operations armada_38x_smp_ops __initconst = {
0098     .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
0099     .smp_secondary_init     = armada_38x_secondary_init,
0100 #ifdef CONFIG_HOTPLUG_CPU
0101     .cpu_die        = armada_38x_cpu_die,
0102     .cpu_kill               = armada_38x_cpu_kill,
0103 #endif
0104 };
0105 
0106 CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
0107               &mvebu_cortex_a9_smp_ops);
0108 CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
0109               &armada_38x_smp_ops);
0110 CPU_METHOD_OF_DECLARE(mvebu_armada_390_smp, "marvell,armada-390-smp",
0111               &armada_38x_smp_ops);