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