^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) * Actions Semi Leopard
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * This file is based on arm realview smp platform.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Copyright 2012 Actions Semi Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Author: Actions Semi, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * Copyright (c) 2017 Andreas Färber
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/delay.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/smp.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/soc/actions/owl-sps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <asm/cacheflush.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) #include <asm/smp_scu.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #define OWL_CPU1_ADDR 0x50
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #define OWL_CPU1_FLAG 0x5c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #define OWL_CPUx_FLAG_BOOT 0x55aa
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #define OWL_SPS_PG_CTL_PWR_CPU2 BIT(5)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #define OWL_SPS_PG_CTL_PWR_CPU3 BIT(6)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #define OWL_SPS_PG_CTL_ACK_CPU2 BIT(21)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #define OWL_SPS_PG_CTL_ACK_CPU3 BIT(22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) static void __iomem *scu_base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) static void __iomem *sps_base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) static void __iomem *timer_base_addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) static int ncores;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) static int s500_wakeup_secondary(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (cpu > 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) /* The generic PM domain driver is not available this early. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) switch (cpu) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) case 2:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ret = owl_sps_set_pg(sps_base_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) OWL_SPS_PG_CTL_PWR_CPU2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) OWL_SPS_PG_CTL_ACK_CPU2, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) case 3:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) ret = owl_sps_set_pg(sps_base_addr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) OWL_SPS_PG_CTL_PWR_CPU3,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) OWL_SPS_PG_CTL_ACK_CPU3, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) /* wait for CPUx to run to WFE instruction */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) udelay(200);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) writel(__pa_symbol(secondary_startup),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) writel(OWL_CPUx_FLAG_BOOT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) dsb_sev();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) mb();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) static int s500_smp_boot_secondary(unsigned int cpu, struct task_struct *idle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) ret = s500_wakeup_secondary(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) udelay(10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) smp_send_reschedule(cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) writel(0, timer_base_addr + OWL_CPU1_ADDR + (cpu - 1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) writel(0, timer_base_addr + OWL_CPU1_FLAG + (cpu - 1) * 4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static void __init s500_smp_prepare_cpus(unsigned int max_cpus)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) struct device_node *node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) node = of_find_compatible_node(NULL, NULL, "actions,s500-timer");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) pr_err("%s: missing timer\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) timer_base_addr = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) if (!timer_base_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) pr_err("%s: could not map timer registers\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) node = of_find_compatible_node(NULL, NULL, "actions,s500-sps");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) pr_err("%s: missing sps\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) return;
^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) sps_base_addr = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (!sps_base_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) pr_err("%s: could not map sps registers\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) if (!node) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) pr_err("%s: missing scu\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) scu_base_addr = of_iomap(node, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) if (!scu_base_addr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) pr_err("%s: could not map scu registers\n", __func__);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) * While the number of cpus is gathered from dt, also get the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) * number of cores from the scu to verify this value when
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) * booting the cores.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) ncores = scu_get_core_count(scu_base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pr_debug("%s: ncores %d\n", __func__, ncores);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) scu_enable(scu_base_addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) static const struct smp_operations s500_smp_ops __initconst = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) .smp_prepare_cpus = s500_smp_prepare_cpus,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) .smp_boot_secondary = s500_smp_boot_secondary,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) CPU_METHOD_OF_DECLARE(s500_smp, "actions,s500-smp", &s500_smp_ops);