summaryrefslogtreecommitdiffstats
path: root/arch/arm/kernel
diff options
context:
space:
mode:
authorArnd Bergmann <arnd@arndb.de>2017-10-30 11:23:13 +0100
committerArnd Bergmann <arnd@arndb.de>2017-10-30 11:23:13 +0100
commit682e3efa4d23c0587eba784ede6ce6fcff5acee5 (patch)
tree7e59ea9663d6d4c8cd9042cd3ef6b15b370e5bb5 /arch/arm/kernel
parentMerge tag 'imx-soc-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/sha... (diff)
parentARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8b (diff)
downloadlinux-682e3efa4d23c0587eba784ede6ce6fcff5acee5.tar.xz
linux-682e3efa4d23c0587eba784ede6ce6fcff5acee5.zip
Merge tag 'amlogic-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic into next/soc
Pull "Amlogic SoC updates for v4.15" from Kevin Hilman: - add SMP support to Meson8/8b * tag 'amlogic-soc' of git://git.kernel.org/pub/scm/linux/kernel/git/khilman/linux-amlogic: ARM: meson: enable MESON_IRQ_GPIO in Kconfig for meson8b ARM: meson: Add SMP bringup code for Meson8 and Meson8b ARM: smp_scu: allow the platform code to read the SCU CPU status ARM: smp_scu: add a helper for powering on a specific CPU dt-bindings: Amlogic: Add Meson8 and Meson8b SMP related documentation
Diffstat (limited to 'arch/arm/kernel')
-rw-r--r--arch/arm/kernel/smp_scu.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
index 72f9241ad5db..c6b33074c393 100644
--- a/arch/arm/kernel/smp_scu.c
+++ b/arch/arm/kernel/smp_scu.c
@@ -21,6 +21,7 @@
#define SCU_STANDBY_ENABLE (1 << 5)
#define SCU_CONFIG 0x04
#define SCU_CPU_STATUS 0x08
+#define SCU_CPU_STATUS_MASK GENMASK(1, 0)
#define SCU_INVALIDATE 0x0c
#define SCU_FPGA_REVISION 0x10
@@ -72,6 +73,24 @@ void scu_enable(void __iomem *scu_base)
}
#endif
+static int scu_set_power_mode_internal(void __iomem *scu_base,
+ unsigned int logical_cpu,
+ unsigned int mode)
+{
+ unsigned int val;
+ int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(logical_cpu), 0);
+
+ if (mode > 3 || mode == 1 || cpu > 3)
+ return -EINVAL;
+
+ val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu);
+ val &= ~SCU_CPU_STATUS_MASK;
+ val |= mode;
+ writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);
+
+ return 0;
+}
+
/*
* Set the executing CPUs power mode as defined. This will be in
* preparation for it executing a WFI instruction.
@@ -82,15 +101,27 @@ void scu_enable(void __iomem *scu_base)
*/
int scu_power_mode(void __iomem *scu_base, unsigned int mode)
{
+ return scu_set_power_mode_internal(scu_base, smp_processor_id(), mode);
+}
+
+/*
+ * Set the given (logical) CPU's power mode to SCU_PM_NORMAL.
+ */
+int scu_cpu_power_enable(void __iomem *scu_base, unsigned int cpu)
+{
+ return scu_set_power_mode_internal(scu_base, cpu, SCU_PM_NORMAL);
+}
+
+int scu_get_cpu_power_mode(void __iomem *scu_base, unsigned int logical_cpu)
+{
unsigned int val;
- int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(smp_processor_id()), 0);
+ int cpu = MPIDR_AFFINITY_LEVEL(cpu_logical_map(logical_cpu), 0);
- if (mode > 3 || mode == 1 || cpu > 3)
+ if (cpu > 3)
return -EINVAL;
- val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu) & ~0x03;
- val |= mode;
- writeb_relaxed(val, scu_base + SCU_CPU_STATUS + cpu);
+ val = readb_relaxed(scu_base + SCU_CPU_STATUS + cpu);
+ val &= SCU_CPU_STATUS_MASK;
- return 0;
+ return val;
}