^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (C) 2015 Carlo Caione <carlo@endlessm.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2017 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <linux/init.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/regmap.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/reset.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/mfd/syscon.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <asm/cacheflush.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <asm/cp15.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/smp_scu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include <asm/smp_plat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #define MESON_SMP_SRAM_CPU_CTRL_REG (0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(c) (0x04 + ((c - 1) << 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #define MESON_CPU_AO_RTI_PWR_A9_CNTL0 (0x00)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define MESON_CPU_AO_RTI_PWR_A9_CNTL1 (0x04)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #define MESON_CPU_AO_RTI_PWR_A9_MEM_PD0 (0x14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define MESON_CPU_PWR_A9_CNTL0_M(c) (0x03 << ((c * 2) + 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define MESON_CPU_PWR_A9_CNTL1_M(c) (0x03 << ((c + 1) << 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define MESON_CPU_PWR_A9_MEM_PD0_M(c) (0x0f << (32 - (c * 4)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #define MESON_CPU_PWR_A9_CNTL1_ST(c) (0x01 << (c + 16))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static void __iomem *sram_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static void __iomem *scu_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static struct regmap *pmu;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static struct reset_control *meson_smp_get_core_reset(int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct device_node *np = of_get_cpu_node(cpu, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) return of_reset_control_get_exclusive(np, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) static void meson_smp_set_cpu_ctrl(int cpu, bool on_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) u32 val = readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) if (on_off)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) val |= BIT(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) val &= ~BIT(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /* keep bit 0 always enabled */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) val |= BIT(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) writel(val, sram_base + MESON_SMP_SRAM_CPU_CTRL_REG);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) static void __init meson_smp_prepare_cpus(const char *scu_compatible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) const char *pmu_compatible,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) const char *sram_compatible)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) static struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) /* SMP SRAM */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) node = of_find_compatible_node(NULL, NULL, sram_compatible);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) pr_err("Missing SRAM node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) sram_base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (!sram_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) pr_err("Couldn't map SRAM registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) /* PMU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) pmu = syscon_regmap_lookup_by_compatible(pmu_compatible);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (IS_ERR(pmu)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) pr_err("Couldn't map PMU registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) /* SCU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) node = of_find_compatible_node(NULL, NULL, scu_compatible);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) pr_err("Missing SCU node\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) scu_base = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) if (!scu_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) pr_err("Couldn't map SCU registers\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) scu_enable(scu_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static void __init meson8b_smp_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) meson_smp_prepare_cpus("arm,cortex-a5-scu", "amlogic,meson8b-pmu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) "amlogic,meson8b-smp-sram");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static void __init meson8_smp_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) meson_smp_prepare_cpus("arm,cortex-a9-scu", "amlogic,meson8-pmu",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) "amlogic,meson8-smp-sram");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) static void meson_smp_begin_secondary_boot(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * Set the entry point before powering on the CPU through the SCU. This
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * is needed if the CPU is in "warm" state (= after rebooting the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * system without power-cycling, or when taking the CPU offline and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) * then taking it online again.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) writel(__pa_symbol(secondary_startup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * SCU Power on CPU (needs to be done before starting the CPU,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) * otherwise the secondary CPU will not start).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) scu_cpu_power_enable(scu_base, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static int meson_smp_finalize_secondary_boot(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) timeout = jiffies + (10 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) while (readl(sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!time_before(jiffies, timeout)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pr_err("Timeout while waiting for CPU%d status\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) writel(__pa_symbol(secondary_startup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) sram_base + MESON_SMP_SRAM_CPU_CTRL_ADDR_REG(cpu));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) meson_smp_set_cpu_ctrl(cpu, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) static int meson8_smp_boot_secondary(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) struct reset_control *rstc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) rstc = meson_smp_get_core_reset(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) if (IS_ERR(rstc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) return PTR_ERR(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) meson_smp_begin_secondary_boot(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) /* Reset enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) ret = reset_control_assert(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) pr_err("Failed to assert CPU%d reset\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) /* CPU power ON */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) pr_err("Couldn't wake up CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) /* Isolation disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) pr_err("Error when disabling isolation of CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) /* Reset disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) ret = reset_control_deassert(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) pr_err("Failed to de-assert CPU%d reset\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) ret = meson_smp_finalize_secondary_boot(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) reset_control_put(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) static int meson8b_smp_boot_secondary(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) struct reset_control *rstc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) u32 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) rstc = meson_smp_get_core_reset(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (IS_ERR(rstc)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) pr_err("Couldn't get the reset controller for CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return PTR_ERR(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) meson_smp_begin_secondary_boot(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) /* CPU power UP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) MESON_CPU_PWR_A9_CNTL0_M(cpu), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) pr_err("Couldn't power up CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) udelay(5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) /* Reset enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) ret = reset_control_assert(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) pr_err("Failed to assert CPU%d reset\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) /* Memory power UP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) pr_err("Couldn't power up the memory for CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) /* Wake up CPU */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) MESON_CPU_PWR_A9_CNTL1_M(cpu), 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) pr_err("Couldn't wake up CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) ret = regmap_read_poll_timeout(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1, val,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) val & MESON_CPU_PWR_A9_CNTL1_ST(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 10, 10000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) pr_err("Timeout while polling PMU for CPU%d status\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) /* Isolation disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) pr_err("Error when disabling isolation of CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) /* Reset disable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) ret = reset_control_deassert(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) pr_err("Failed to de-assert CPU%d reset\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) ret = meson_smp_finalize_secondary_boot(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) reset_control_put(rstc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) static void meson8_smp_cpu_die(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) meson_smp_set_cpu_ctrl(cpu, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) v7_exit_coherency_flush(louis);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) scu_power_mode(scu_base, SCU_PM_POWEROFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) dsb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) wfi();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) /* we should never get here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) WARN_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) static int meson8_smp_cpu_kill(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) int ret, power_mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) unsigned long timeout;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) timeout = jiffies + (50 * HZ);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) power_mode = scu_get_cpu_power_mode(scu_base, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (power_mode == SCU_PM_POWEROFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) usleep_range(10000, 15000);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) } while (time_before(jiffies, timeout));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) if (power_mode != SCU_PM_POWEROFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) pr_err("Error while waiting for SCU power-off on CPU%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) msleep(30);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) /* Isolation enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 0x3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) pr_err("Error when enabling isolation for CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* CPU power OFF */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) pr_err("Couldn't change sleep status of CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) static int meson8b_smp_cpu_kill(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) int ret, power_mode, count = 5000;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) power_mode = scu_get_cpu_power_mode(scu_base, cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) if (power_mode == SCU_PM_POWEROFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) } while (++count);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (power_mode != SCU_PM_POWEROFF) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) pr_err("Error while waiting for SCU power-off on CPU%d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return -ETIMEDOUT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) /* CPU power DOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) MESON_CPU_PWR_A9_CNTL0_M(cpu), 0x3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) pr_err("Couldn't power down CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) /* Isolation enable */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL0, BIT(cpu),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) 0x3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) pr_err("Error when enabling isolation for CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) /* Sleep status */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_CNTL1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) MESON_CPU_PWR_A9_CNTL1_M(cpu), 0x3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) pr_err("Couldn't change sleep status of CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) /* Memory power DOWN */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) ret = regmap_update_bits(pmu, MESON_CPU_AO_RTI_PWR_A9_MEM_PD0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) MESON_CPU_PWR_A9_MEM_PD0_M(cpu), 0xf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) if (ret < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) pr_err("Couldn't power down the memory of CPU%d\n", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) static struct smp_operations meson8_smp_ops __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) .smp_prepare_cpus = meson8_smp_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) .smp_boot_secondary = meson8_smp_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) .cpu_die = meson8_smp_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) .cpu_kill = meson8_smp_cpu_kill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) static struct smp_operations meson8b_smp_ops __initdata = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) .smp_prepare_cpus = meson8b_smp_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) .smp_boot_secondary = meson8b_smp_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) #ifdef CONFIG_HOTPLUG_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) .cpu_die = meson8_smp_cpu_die,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) .cpu_kill = meson8b_smp_cpu_kill,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) #endif
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) CPU_METHOD_OF_DECLARE(meson8_smp, "amlogic,meson8-smp", &meson8_smp_ops);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) CPU_METHOD_OF_DECLARE(meson8b_smp, "amlogic,meson8b-smp", &meson8b_smp_ops);