[PATCH RFC 7/8] soc: samsung: exynos-pmu: add Exynos850 CPU hotplug support
From: Alexey Klimov <alexey.klimov@linaro.org>
Date: 2026-02-26 15:47:19
Also in:
linux-devicetree, linux-samsung-soc, lkml
Subsystem:
arm/samsung s3c, s5p and exynos arm architectures, the rest · Maintainers:
Krzysztof Kozlowski, Peter Griffin, Linus Torvalds
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@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