[PATCH RFC 7/8] soc: samsung: exynos-pmu: add Exynos850 CPU hotplug support
Alexey Klimov
alexey.klimov at linaro.org
Thu Feb 26 07:47:13 PST 2026
Some Exynos-based SoCs require specific set of writes/updates to PMU
and PMU intr gen blocks in order to put a CPU or a group of CPUs into
a different sleep states or prepare these entities for a CPU_OFF.
The same is valid for a reverse procedures like wake-ups or CPU(s)
online. Without these writes/updates the CPU(s) wake-up or online
fails.
Add support for Exynos850-based SoCs for PMU and PMU intr gen write/update
sequences.
While at this, also add description of Exynos850 PMU registers.
Signed-off-by: Alexey Klimov <alexey.klimov at linaro.org>
---
drivers/soc/samsung/exynos-pmu.c | 86 +++++++++++++++++++++++++++--
include/linux/soc/samsung/exynos-regs-pmu.h | 5 ++
2 files changed, 87 insertions(+), 4 deletions(-)
diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-pmu.c
index 0967fa56708a..7b9b8e22d91b 100644
--- a/drivers/soc/samsung/exynos-pmu.c
+++ b/drivers/soc/samsung/exynos-pmu.c
@@ -118,6 +118,10 @@ static const struct regmap_config regmap_pmu_intr = {
.use_raw_spinlock = true,
};
+const struct exynos_pmu_data exynos850_pmu_data = {
+ .pmu_cpuhp = true,
+};
+
/*
* PMU platform driver and devicetree bindings.
*/
@@ -151,6 +155,7 @@ static const struct of_device_id exynos_pmu_of_device_ids[] = {
.compatible = "samsung,exynos7-pmu",
}, {
.compatible = "samsung,exynos850-pmu",
+ .data = &exynos850_pmu_data,
},
{ /*sentinel*/ },
};
@@ -229,6 +234,65 @@ EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle);
#define CPU_INFORM_CLEAR 0
#define CPU_INFORM_C2 1
+static int __exynos850_cpu_pmu_online(unsigned int cpu)
+ __must_hold(&pmu_context->cpupm_lock)
+{
+ u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
+ u32 cluster_cpu = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+ unsigned int cpuhint = smp_processor_id();
+ u32 reg, mask;
+
+ /* clear cpu inform hint */
+ regmap_write(pmu_context->pmureg, EXYNOS850_CPU_INFORM(cpuhint),
+ CPU_INFORM_CLEAR);
+
+ mask = BIT(cpu);
+
+ regmap_update_bits(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_ENABLE,
+ mask, (0 << cpu));
+
+ regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_UPEND, ®);
+
+ regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_CLEAR,
+ reg & mask);
+
+ regmap_update_bits(pmu_context->pmureg,
+ EXYNOS850_CLUSTER_CPU_INT_EN(this_cluster, cluster_cpu),
+ 1 << 3, 0 << 3);
+ return 0;
+}
+
+static int __exynos850_cpu_pmu_offline(unsigned int cpu)
+ __must_hold(&pmu_context->cpupm_lock)
+{
+ u32 this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 2);
+ u32 cluster_cpu = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+ unsigned int cpuhint = smp_processor_id();
+ u32 reg, mask;
+
+ /* set cpu inform hint */
+ regmap_write(pmu_context->pmureg, EXYNOS850_CPU_INFORM(cpuhint),
+ CPU_INFORM_C2);
+
+ mask = BIT(cpu);
+ regmap_update_bits(pmu_context->pmuintrgen, EXYNOS_GRP2_INTR_BID_ENABLE,
+ mask, BIT(cpu));
+
+ regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_UPEND, ®);
+ regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_CLEAR,
+ reg & mask);
+
+ mask = (BIT(cpu + 8));
+ regmap_read(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_UPEND, ®);
+ regmap_write(pmu_context->pmuintrgen, EXYNOS_GRP1_INTR_BID_CLEAR,
+ reg & mask);
+
+ regmap_update_bits(pmu_context->pmureg,
+ EXYNOS850_CLUSTER_CPU_INT_EN(this_cluster, cluster_cpu),
+ 1 << 3, 1 << 3);
+ return 0;
+}
+
/*
* __gs101_cpu_pmu_ prefix functions are common code shared by CPU PM notifiers
* (CPUIdle) and CPU hotplug callbacks. Functions should be called with IRQs
@@ -416,8 +480,12 @@ static int setup_cpuhp_and_cpuidle(struct device *dev)
void __iomem *virt_addr;
int ret, cpu;
- intr_gen_node = of_parse_phandle(dev->of_node,
- "google,pmu-intr-gen-syscon", 0);
+ intr_gen_node = of_parse_phandle(dev->of_node, "samsung,pmu-intr-gen-syscon", 0);
+
+ /* Fall back to the google pmu intr gen property for older DTBs */
+ if (!intr_gen_node)
+ intr_gen_node = of_parse_phandle(dev->of_node, "google,pmu-intr-gen-syscon", 0);
+
if (!intr_gen_node) {
/*
* To maintain support for older DTs that didn't specify syscon
@@ -427,9 +495,19 @@ static int setup_cpuhp_and_cpuidle(struct device *dev)
return 0;
}
- pmu_context->cpu_pmu_online = __gs101_cpu_pmu_online;
- pmu_context->cpu_pmu_offline = __gs101_cpu_pmu_offline;
+ if (of_machine_is_compatible("google,gs101")) {
+ pmu_context->cpu_pmu_online = __gs101_cpu_pmu_online;
+ pmu_context->cpu_pmu_offline = __gs101_cpu_pmu_offline;
+ }
+
+ if (of_machine_is_compatible("samsung,exynos850")) {
+ pmu_context->cpu_pmu_online = __exynos850_cpu_pmu_online;
+ pmu_context->cpu_pmu_offline = __exynos850_cpu_pmu_offline;
+ } else {
+ dev_err(dev, "pmu-intr-gen is present but machine is not supported\n");
+ return -ENODEV;
+ }
/*
* To avoid lockdep issues (CPU PM notifiers use raw spinlocks) create
* a mmio regmap for pmu-intr-gen that uses raw spinlocks instead of
diff --git a/include/linux/soc/samsung/exynos-regs-pmu.h b/include/linux/soc/samsung/exynos-regs-pmu.h
index 9c4d3da41dbf..93c4d724c8ea 100644
--- a/include/linux/soc/samsung/exynos-regs-pmu.h
+++ b/include/linux/soc/samsung/exynos-regs-pmu.h
@@ -1015,6 +1015,11 @@
#define EXYNOS_GRP2_INTR_BID_UPEND (0x0208)
#define EXYNOS_GRP2_INTR_BID_CLEAR (0x020c)
+/* Exynos850 PMU Alive */
+#define EXYNOS850_CPU_INFORM(cpu) (0x0860 + ((cpu) & 7) * 4)
+#define EXYNOS850_CLUSTER_CPU_OFFSET(cl, cpu) (0x1000 + ((cl * 0x400) + ((cpu) * 0x80)))
+#define EXYNOS850_CLUSTER_CPU_INT_EN(cl, cpu) (EXYNOS850_CLUSTER_CPU_OFFSET(cl, cpu) + 0x44)
+
/* exynosautov920 */
#define EXYNOSAUTOV920_PHY_CTRL_USB20 (0x0710)
#define EXYNOSAUTOV920_PHY_CTRL_USB31 (0x0714)
--
2.51.0
More information about the linux-arm-kernel
mailing list