Re: [PATCH RFC 7/8] soc: samsung: exynos-pmu: add Exynos850 CPU hotplug support

From: Peter Griffin

Date: Fri Mar 06 2026 - 09:24:22 EST


Hi Alexey,

Thanks for your patch.

On Thu, 26 Feb 2026 at 15:47, Alexey Klimov <alexey.klimov@xxxxxxxxxx> wrote:
>
> 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@xxxxxxxxxx>
> ---
> 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,
> +};
> +

You may want to consider having an e850-pmu.c file to contain the e850
specific data and hooks.

Andre recently moved some of the gs101-specific parts into gs101-pmu.c
(although not the actual gs101 online/offline hooks). Now that more
SoCs are being added it could be a good time for exynos-pmu to contain
only the generic code and the <soc>-pmu.c file having the
peculiarities/hooks for the specific SoC.

> /*
> * 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, &reg);
> +
> + 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, &reg);
> + 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, &reg);
> + 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;
>

There should be no compatibles inside probe (that rule applies to all
drivers & subsystems). Instead use the driver match data
(exynos_pmu_data).

regards,

Peter