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

Peter Griffin peter.griffin at linaro.org
Fri Mar 6 06:15:34 PST 2026


Hi Alexey,

Thanks for your patch.

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

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



More information about the linux-arm-kernel mailing list