diff options
author | Andreas Färber <afaerber@suse.de> | 2017-02-28 01:08:37 +0100 |
---|---|---|
committer | Andreas Färber <afaerber@suse.de> | 2017-06-23 18:01:35 +0200 |
commit | b6a0e18ca690c2398661c42b942187621ab77e36 (patch) | |
tree | 0c75f135b019d73f588050f35880e56c3fd1631e /arch/arm/mach-actions | |
parent | 4c0f860779e9835f87233d89319096501778430c (diff) |
ARM: owl: smp: Implement SPS power-gating for CPU2 and CPU3
Bring up the two remaining CPUs by calling into PM domain code.
Signed-off-by: Andreas Färber <afaerber@suse.de>
Diffstat (limited to 'arch/arm/mach-actions')
-rw-r--r-- | arch/arm/mach-actions/Kconfig | 1 | ||||
-rw-r--r-- | arch/arm/mach-actions/platsmp.c | 36 |
2 files changed, 35 insertions, 2 deletions
diff --git a/arch/arm/mach-actions/Kconfig b/arch/arm/mach-actions/Kconfig index 717adc1630a1..ad9c5c89c683 100644 --- a/arch/arm/mach-actions/Kconfig +++ b/arch/arm/mach-actions/Kconfig @@ -10,6 +10,7 @@ menuconfig ARCH_ACTIONS select GENERIC_IRQ_CHIP select HAVE_ARM_SCU if SMP select HAVE_ARM_TWD if SMP + select OWL_PM_DOMAINS_HELPER select OWL_TIMER help This enables support for the Actions Semiconductor S500 SoC family. diff --git a/arch/arm/mach-actions/platsmp.c b/arch/arm/mach-actions/platsmp.c index 9d3601ebe535..b4806ce0e9bb 100644 --- a/arch/arm/mach-actions/platsmp.c +++ b/arch/arm/mach-actions/platsmp.c @@ -19,6 +19,7 @@ #include <linux/of.h> #include <linux/of_address.h> #include <linux/smp.h> +#include <linux/soc/actions/owl-sps.h> #include <asm/cacheflush.h> #include <asm/smp_plat.h> #include <asm/smp_scu.h> @@ -28,7 +29,13 @@ #define OWL_CPUx_FLAG_BOOT 0x55aa +#define OWL_SPS_PG_CTL_PWR_CPU2 BIT(5) +#define OWL_SPS_PG_CTL_PWR_CPU3 BIT(6) +#define OWL_SPS_PG_CTL_ACK_CPU2 BIT(21) +#define OWL_SPS_PG_CTL_ACK_CPU3 BIT(22) + static void __iomem *scu_base_addr; +static void __iomem *sps_base_addr; static void __iomem *timer_base_addr; static int ncores; @@ -58,14 +65,27 @@ void owl_secondary_startup(void); static int s500_wakeup_secondary(unsigned int cpu) { + int ret; + if (cpu > 3) return -EINVAL; + /* The generic PM domain driver is not available this early. */ switch (cpu) { case 2: + ret = owl_sps_set_pg(sps_base_addr, + OWL_SPS_PG_CTL_PWR_CPU2, + OWL_SPS_PG_CTL_ACK_CPU2, true); + if (ret) + return ret; + break; case 3: - /* CPU2/3 are power-gated */ - return -EINVAL; + ret = owl_sps_set_pg(sps_base_addr, + OWL_SPS_PG_CTL_PWR_CPU3, + OWL_SPS_PG_CTL_ACK_CPU3, true); + if (ret) + return ret; + break; } /* wait for CPUx to run to WFE instruction */ @@ -133,6 +153,18 @@ static void __init s500_smp_prepare_cpus(unsigned int max_cpus) return; } + node = of_find_compatible_node(NULL, NULL, "actions,s500-sps"); + if (!node) { + pr_err("%s: missing sps\n", __func__); + return; + } + + sps_base_addr = of_iomap(node, 0); + if (!sps_base_addr) { + pr_err("%s: could not map sps registers\n", __func__); + return; + } + if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) { node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu"); if (!node) { |