From nobody Mon Oct 6 19:11:50 2025 Received: from mail-wm1-f41.google.com (mail-wm1-f41.google.com [209.85.128.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8F5DE2FC3D6 for ; Thu, 17 Jul 2025 16:22:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.128.41 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752769381; cv=none; b=cGhLwpMF7x2YMet3YWpvOwre5/+8txdWTzJQkuLxG5xSIVI/b1GneeJMO/RqyDSDjpaL8Zryu2SUGnrvFqqlQAW5bkPSAAnTIUXXPCcSQ+kOMjk1Aom1FDZF5/L7qHze+K+PuX6xl7mFICzdrbfZrTxF+YKu8eb3w8u4WwY3XhQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752769381; c=relaxed/simple; bh=D/alBt/IO0rXB4lbViRL+PF3NluC/vCh5+UjJNMc89c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:To:Cc; b=LB0omV5wOcA4NUsombbQp6bcKN/I/wY6HetWaoRVooyi9nepYsBnYuqQhk4QXkVEalVkTc3l5xlYNVdoObV0H+JxPsSMLxF0THf2mKmkFaII9cdBIlXrnQPuQ+jr7fCxkdvkWaDsSGK1sbp4GTwzOMwLE7oc02iYilgCOGaL3f0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org; spf=pass smtp.mailfrom=linaro.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b=GWy/28m3; arc=none smtp.client-ip=209.85.128.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linaro.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="GWy/28m3" Received: by mail-wm1-f41.google.com with SMTP id 5b1f17b1804b1-4538bc52a8dso9305615e9.2 for ; Thu, 17 Jul 2025 09:22:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1752769377; x=1753374177; darn=vger.kernel.org; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:from:to:cc:subject:date:message-id:reply-to; bh=10QORs6KuK3KoVhoNTRYpOhsvpEP9POMNGa7ng7GyN4=; b=GWy/28m3zqQNF+Zdb13Of+SqIapJy/EaOqyJaHNrTZazGcXZsD9C8GEWYZoefiWENW W4GdxyjiOH36A+dKVj2EnpmtfRK0UPDW916c6/stldnZ6eUlxoJgfyb2tM7R4PouD9k1 Wgo09y/RESUJzitzv1oc9rZuxJCd/vluXqOteEw4KUUeHQzmlKSO6N07QPXgC9HjVZc6 d53QeoWTlmj2bzr52fe5LQWYXnFH1Y2TTiVcfDK7SQPzfcBqS5E9zzHbPPtwzlfXiQaC 8kQsbPOZEba92zQxQq5w51K83OWqV9YXV3X9DBZU6+v7hWb9bF0YTjQ5hInVi2QJ1+18 OuiQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752769377; x=1753374177; h=cc:to:message-id:content-transfer-encoding:mime-version:subject :date:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=10QORs6KuK3KoVhoNTRYpOhsvpEP9POMNGa7ng7GyN4=; b=nPF2IV0w4/WX+2juVsyYBzVucOHe057dunar46a+Eub7cxshrVUcJD3YwG74lkzsdl ipQ8nWdY8C7OkqdHXIoNNM3ppd8D5m63kHRVQZwFtXplnjeOtC2k6A+Zngo9hf5UgUtf Gf73X0srVD0olGReTj3EIuVzAUskJpxQXuTfzqZ0iGu3+9SW7ku45iBi2QEhR/FIAbwO nPbD0HEK3Xisc20JrutUMsXTkBLg8BZqGkkAMsXQ5EY1gLsAN5hcQbOPDLqEO84WKyDA YhXIS4RxraLoF/8NN/tBQzlNgh3sF6zYP3YjTiaMmQxK81ULA+JMkHYZoDnomjIXEnYk PKnw== X-Forwarded-Encrypted: i=1; AJvYcCUHq0w501T1NDVevMMAfdHygNHwY9fzMjKTmCb1Y5cCxTvXSCBMeA0TgSXvN2pnRPgpMYXr+KE6+NLq+ug=@vger.kernel.org X-Gm-Message-State: AOJu0YzsvnEjVEAqni6xXbMWSNgIbS2i4n8tEXFcZU/KyT19UukFNWb0 VfEaeacTkwTZMO+xWRGhSmnvngmAUTpv3sxVXOZiRrg3ieTpl2PjwE5JWPgo7M2TwNo= X-Gm-Gg: ASbGnctmYH+x5jntAkJnVVnE0Sh+u/JlRl0oimlF6x6XJmqvuOUyU58xtTqHEpu1N5A 4wq/lKPk2qqTUoJ925AAyaSL1b1b3lgxP3T54Ctp3Sa9WwgFT0xyT30TZB4I//NMhV9S7SepxID eNlQptgXjfB2p/5UNydGC33xLhKdRFJRtE8pIIZiDu0y8aUc/Fpx3Nu0mMb9XamzNF/y8hRmmbr PEFAQCic7Ccfwq9IFyiQSvoLXt4anEgJ7cXp051pAsOzfl52WR4tD26eOUmdIfc6rpvMTEgpuUD PAp4zkywWJv1cUdBJJIRipIN8p+8dTGgki5ipTof3sSpUOXOD4bYg2DTkWvAgCKi7dogAn0NTBo LUkot4nOjUjeO+EX0xdJ3TIsSeHBz9XGtbOk675SG1xzzaWb+j8muXw== X-Google-Smtp-Source: AGHT+IE++zTw7j6btUVkqUEYspAqPSCyXgCDgYCI8SNJwqI7G1Fq6QlWWZg6HM2OXb9NaKUehGX6vg== X-Received: by 2002:a05:600c:620e:b0:456:43c:dcdc with SMTP id 5b1f17b1804b1-4562e2aa7bbmr68434475e9.33.1752769376585; Thu, 17 Jul 2025 09:22:56 -0700 (PDT) Received: from gpeter-l.roam.corp.google.com ([209.198.129.187]) by smtp.gmail.com with ESMTPSA id 5b1f17b1804b1-4562e80731bsm55078025e9.15.2025.07.17.09.22.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 17 Jul 2025 09:22:55 -0700 (PDT) From: Peter Griffin Date: Thu, 17 Jul 2025 17:22:36 +0100 Subject: [PATCH v7] soc: samsung: exynos-pmu: Enable CPU Idle for gs101 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250717-gs101-cpuidle-v7-1-33d51770114b@linaro.org> X-B4-Tracking: v=1; b=H4sIAEsjeWgC/33PwW7DIAwG4FepOI/JGANJT3uPaQcGJkWqkgq2a FOVdx/ppV2i7fhb+n7bV1G5ZK7ieLiKwnOueRpbcE8HEU5+HFjm2LJAQAMGSQ5VgZLh8pnjmWX wKfQ2xo76KJq5FE7569b3+tbyKdePqXzf6me1Tv9qmpUE6dk7511H6O3LOY++TM9TGcRaNeOdW 6W2HBun5DulOBBQ3HH9wNFtuZZtPwKQwZjYwo7TnTvot5waN5ZRxYjUW73j5l9uGn/XFDUqwM7 uj7cPfP+7XbeD5mBMCpj6X3xZlh9IyFDN5gEAAA== X-Change-ID: 20250524-gs101-cpuidle-cafc96dd849d To: =?utf-8?q?Andr=C3=A9_Draszik?= , Tudor Ambarus , Alim Akhtar , Krzysztof Kozlowski Cc: William Mcvicker , Krzysztof Kozlowski , linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org, kernel-team@android.com, sudeep.holla@arm.com, Peter Griffin X-Mailer: b4 0.14.2 X-Developer-Signature: v=1; a=openpgp-sha256; l=15370; i=peter.griffin@linaro.org; h=from:subject:message-id; bh=D/alBt/IO0rXB4lbViRL+PF3NluC/vCh5+UjJNMc89c=; b=owEBbQKS/ZANAwAKAc7ouNYCNHK6AcsmYgBoeSNevp2Fd+5CIDHpUymfxKHigKhGd6hKVqRGL esvln6QdI+JAjMEAAEKAB0WIQQO/I5vVXh1DVa1SfzO6LjWAjRyugUCaHkjXgAKCRDO6LjWAjRy umJ/D/9x3WOsdHblLVE+GAdOaT8T6h4/DDFr9n4GBhg9X+DjjpbjV9pLs0Okd5UuBdDNOsq7kVb 2qE5aEsib8QktmC9aflhmui7Cp+wZ/uTqRI7fwzgJwfHsE1dyc3x8bb7kNyDKMxv/c8SieeFMRY kelw8Kq97IwdyQ+kzVuEcnxJVmMvizPtUEoV83MrGz3yUKEKmoHj1FhiWk/7kZizBzEnoEtV7oD MXxr65iqfejyhD67uuO45q28gAgWmpjTI7KZtDroEWB34ivJoHCBcGPUzbYcHHWaCdxv1x9KgxC h8GFkMguEC9BYFqnuwPB1B3wfo7CbeAIM6zz1ZMjWnqzSFhr+d1pX+rN99K6aEe3ozvjP8Hw21U IcOP9rsOA200I0D70GKBqiXnrQoDU0tbhfD1p4z0n1YfMTHu4x6TWqI3APi6Dq+Pnci201+j1RA 7SIr9kOwSY7s8zMOQQmQ3pUuUZNB5XbYCSa2mbRsVveCFnlImQZ6H0Hl5BdHLMN7emwkZwN2zHF CAVkcP564gLeN1PZX7rdqnQf6XzrJxOTgTTdksbFOsG8WU6IWjULHaS9zvvWI4pLTFmso3v0Cs+ DlhtbYIxCoOYTJJKcViirTwWCmZZw583MCJ4UHjf2ji/XkX5ypKty3/6s+uTV8/vSaHAed7c41w l5uqDmK+3UIFGVQ== X-Developer-Key: i=peter.griffin@linaro.org; a=openpgp; fpr=0EFC8E6F5578750D56B549FCCEE8B8D6023472BA Register cpu pm notifiers for gs101 which call the gs101_cpu_pmu_online/offline callbacks which in turn program the ACPM C2 hint. This hint is required to actually enter the C2 idle state in addition to the PSCI calls due to limitations in the el3mon/ACPM firmware. A couple of corner cases are handled, namely when the system is rebooting or suspending we ignore the request. Additionally the request is ignored if the CPU is in CPU hot plug. Some common code is refactored so that it can be called from both the CPU hot plug callbacks and CPU PM notifier taking into account that CPU PM notifiers are called with IRQs disabled whereas CPU hotplug callbacks are not. Additionally due to CPU PM notifiers using raw_spinlock the locking is updated to use raw_spinlock variants, this includes updating the pmu_regs regmap to use .use_raw_spinlock =3D true and additionally creating and registering a custom pmu-intr-gen regmap instead of using the regmap provided by syscon. Note: this patch has a runtime dependency on adding 'local-timer-stop' dt property to the CPU nodes. This informs the time framework to switch to a broadcast timer as the local timer will be shutdown. Without that DT property specified the system hangs in early boot with this patch applied. Signed-off-by: Peter Griffin --- Hi folks, This patch adds support for CPU Idle on gs101. In particular it achieves this by registerring a cpu pm notifier and programming a ACPM hint. This is required in addition to the PSCI calls to enter the c2 idle state due to limitations in the el3mon/ACPM firmware. Note: the `local-timer-stop` DT patch mentioned above is already queued. We can measure the impact of these changes upstream using the fuel gauge series from Thomas Antoine [2]. With the ACPM hint now programmed /sys/class/power_supply/max77759-fg/current_avg is a postive number around 150000 microamps meaning we are charging the battery (assuming it isn't already full). Prior to programming the hint this would report a negative number around -150000 microamps meaning the battery was discharing. This has also been tested with kernel/configs/debug.config options enabled, monitoring the cpuidle sysfs files, and a script to hotplug CPUs in a loop to test the interactions between cpu idle and hotplug parts. Thanks, Peter [1] https://lore.kernel.org/lkml/20250421-b4-gs101_max77759_fg-v3-0-50cd8ca= f9017@uclouvain.be/ --- Changes in v7: - Remove atomics and protect suspend/reboot flags with the existing raw spi= nlock (Krzysztof) - Use a bitmap for in_cpuhp (Krzysztof) - Align the naming of various flags (sys_inreboot, sys_insuspend, in_cpuhp)= (Peter) - Link to v6: https://lore.kernel.org/r/20250711-gs101-cpuidle-v6-1-503ec55= fc2f9@linaro.org Changes in v6: - Add more verbose comment on why the hint values are required for gs101 CPU hotplug & CPU Idle states in addition to standard PSCI calls (Sudeep)=20 - Link to v5: https://lore.kernel.org/r/20250709-gs101-cpuidle-v5-1-b34d321= 0286d@linaro.org Changes in v5: - Rename hotplug_ing flag to in_hotplug to aid readability - Use NOIRQ_SYSTEM_SLEEP_PM_OPS wrapper for dev_pm_ops (Krzysztof) - Link to v4: https://lore.kernel.org/r/20250709-gs101-cpuidle-v4-1-56e21dd= 24963@linaro.org Changes in v4: - Avoid lockdep [ BUG: Invalid wait context ] on boot (Andr=C3=A9) - Updated callbacks to use raw_spinlock variants - Ensure pmu_regs regmap uses a raw_spinlock - Create pmu-intr-gen regmap that uses a raw_spinlock - Use pm_sleep_ptr to avoid #ifdef (Andr=C3=A9) - Refactor CPU hotplug and cpuidle parts into dedicated function - Remove unnecessary break; statement (Andr=C3=A9) - Link to v3: https://lore.kernel.org/r/20250627-gs101-cpuidle-v3-1-0200452= dfe60@linaro.org Changes in v3: - Add more verbose comment regarding spinlock (Krzysztof) - Remove per-cpu hotplug_ing bool to avoid highly discouraged remote writes (Krzysztof) - Add extra comments for similarly named functions (Krzysztof) - Initialize lock before for_each_online_cpu() in probe() (Peter) - Use spin_lock_irqsave in cpu hot plug callbacks (Peter/Krzysztof) - Rebase on next-20250627 - Link to v2: https://lore.kernel.org/r/20250611-gs101-cpuidle-v2-0-4fa811e= c404d@linaro.org Changes in v2: - rebase onto next-20250610 - Add #ifdef CONFIG_PM_SLEEP to avoid Fix warning: unused variable 'cpupm_pm_ops' [-Wunused-const-variable] (0-= day) - Link to v1: https://lore.kernel.org/r/20250524-gs101-cpuidle-v1-0-aea77a7= 842a6@linaro.org --- drivers/soc/samsung/exynos-pmu.c | 276 +++++++++++++++++++++++++++++++++++= ---- 1 file changed, 254 insertions(+), 22 deletions(-) diff --git a/drivers/soc/samsung/exynos-pmu.c b/drivers/soc/samsung/exynos-= pmu.c index a77288f49d249f890060c595556708334383c910..22c50ca2aa79bf1945255ee6cc7= 443d7309b2573 100644 --- a/drivers/soc/samsung/exynos-pmu.c +++ b/drivers/soc/samsung/exynos-pmu.c @@ -7,7 +7,9 @@ =20 #include #include +#include #include +#include #include #include #include @@ -15,6 +17,7 @@ #include #include #include +#include #include =20 #include @@ -35,6 +38,15 @@ struct exynos_pmu_context { const struct exynos_pmu_data *pmu_data; struct regmap *pmureg; struct regmap *pmuintrgen; + /* + * Serialization lock for CPU hot plug and cpuidle ACPM hint + * programming. Also protects in_cpuhp, sys_insuspend & sys_inreboot + * flags. + */ + raw_spinlock_t cpupm_lock; + unsigned long *in_cpuhp; + bool sys_insuspend; + bool sys_inreboot; }; =20 void __iomem *pmu_base_addr; @@ -221,6 +233,15 @@ static const struct regmap_config regmap_smccfg =3D { .reg_read =3D tensor_sec_reg_read, .reg_write =3D tensor_sec_reg_write, .reg_update_bits =3D tensor_sec_update_bits, + .use_raw_spinlock =3D true, +}; + +static const struct regmap_config regmap_pmu_intr =3D { + .name =3D "pmu_intr_gen", + .reg_bits =3D 32, + .reg_stride =3D 4, + .val_bits =3D 32, + .use_raw_spinlock =3D true, }; =20 static const struct exynos_pmu_data gs101_pmu_data =3D { @@ -330,13 +351,19 @@ struct regmap *exynos_get_pmu_regmap_by_phandle(struc= t device_node *np, EXPORT_SYMBOL_GPL(exynos_get_pmu_regmap_by_phandle); =20 /* - * CPU_INFORM register hint values which are used by - * EL3 firmware (el3mon). + * CPU_INFORM register "hint" values are required to be programmed in addi= tion to + * the standard PSCI calls to have functional CPU hotplug and CPU idle sta= tes. + * This is required to workaround limitations in the el3mon/ACPM firmware. */ #define CPU_INFORM_CLEAR 0 #define CPU_INFORM_C2 1 =20 -static int gs101_cpuhp_pmu_online(unsigned int cpu) +/* + * __gs101_cpu_pmu_ prefix functions are common code shared by CPU PM noti= fiers + * (CPUIdle) and CPU hotplug callbacks. Functions should be called with IR= Qs + * disabled and cpupm_lock held. + */ +static int __gs101_cpu_pmu_online(unsigned int cpu) { unsigned int cpuhint =3D smp_processor_id(); u32 reg, mask; @@ -358,10 +385,48 @@ static int gs101_cpuhp_pmu_online(unsigned int cpu) return 0; } =20 -static int gs101_cpuhp_pmu_offline(unsigned int cpu) +/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */ +static int gs101_cpu_pmu_online(void) +{ + int cpu; + + raw_spin_lock(&pmu_context->cpupm_lock); + + if (pmu_context->sys_inreboot) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_OK; + } + + cpu =3D smp_processor_id(); + __gs101_cpu_pmu_online(cpu); + raw_spin_unlock(&pmu_context->cpupm_lock); + + return NOTIFY_OK; +} + +/* Called from CPU hot plug callback with IRQs enabled */ +static int gs101_cpuhp_pmu_online(unsigned int cpu) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + + __gs101_cpu_pmu_online(cpu); + /* + * Mark this CPU as having finished the hotplug. + * This means this CPU can now enter C2 idle state. + */ + clear_bit(cpu, pmu_context->in_cpuhp); + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + + return 0; +} + +/* Common function shared by both CPU hot plug and CPUIdle */ +static int __gs101_cpu_pmu_offline(unsigned int cpu) { - u32 reg, mask; unsigned int cpuhint =3D smp_processor_id(); + u32 reg, mask; =20 /* set cpu inform hint */ regmap_write(pmu_context->pmureg, GS101_CPU_INFORM(cpuhint), @@ -379,6 +444,165 @@ static int gs101_cpuhp_pmu_offline(unsigned int cpu) regmap_read(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_UPEND, ®); regmap_write(pmu_context->pmuintrgen, GS101_GRP1_INTR_BID_CLEAR, reg & mask); + + return 0; +} + +/* Called from CPU PM notifier (CPUIdle code path) with IRQs disabled */ +static int gs101_cpu_pmu_offline(void) +{ + int cpu; + + raw_spin_lock(&pmu_context->cpupm_lock); + cpu =3D smp_processor_id(); + + if (test_bit(cpu, pmu_context->in_cpuhp)) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_BAD; + } + + /* Ignore CPU_PM_ENTER event in reboot or suspend sequence. */ + if (pmu_context->sys_insuspend || pmu_context->sys_inreboot) { + raw_spin_unlock(&pmu_context->cpupm_lock); + return NOTIFY_OK; + } + + __gs101_cpu_pmu_offline(cpu); + raw_spin_unlock(&pmu_context->cpupm_lock); + + return NOTIFY_OK; +} + +/* Called from CPU hot plug callback with IRQs enabled */ +static int gs101_cpuhp_pmu_offline(unsigned int cpu) +{ + unsigned long flags; + + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + /* + * Mark this CPU as entering hotplug. So as not to confuse + * ACPM the CPU entering hotplug should not enter C2 idle state. + */ + set_bit(cpu, pmu_context->in_cpuhp); + __gs101_cpu_pmu_offline(cpu); + + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + + return 0; +} + +static int gs101_cpu_pm_notify_callback(struct notifier_block *self, + unsigned long action, void *v) +{ + switch (action) { + case CPU_PM_ENTER: + return gs101_cpu_pmu_offline(); + + case CPU_PM_EXIT: + return gs101_cpu_pmu_online(); + } + + return NOTIFY_OK; +} + +static struct notifier_block gs101_cpu_pm_notifier =3D { + .notifier_call =3D gs101_cpu_pm_notify_callback, + /* + * We want to be called first, as the ACPM hint and handshake is what + * puts the CPU into C2. + */ + .priority =3D INT_MAX +}; + +static int exynos_cpupm_reboot_notifier(struct notifier_block *nb, + unsigned long event, void *v) +{ + unsigned long flags; + + switch (event) { + case SYS_POWER_OFF: + case SYS_RESTART: + raw_spin_lock_irqsave(&pmu_context->cpupm_lock, flags); + pmu_context->sys_inreboot =3D true; + raw_spin_unlock_irqrestore(&pmu_context->cpupm_lock, flags); + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block exynos_cpupm_reboot_nb =3D { + .priority =3D INT_MAX, + .notifier_call =3D exynos_cpupm_reboot_notifier, +}; + +static int setup_cpuhp_and_cpuidle(struct device *dev) +{ + struct device_node *intr_gen_node; + struct resource intrgen_res; + void __iomem *virt_addr; + int ret, cpu; + + intr_gen_node =3D 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 + * phandle just issue a warning rather than fail to probe. + */ + dev_warn(dev, "pmu-intr-gen syscon unavailable\n"); + return 0; + } + + /* + * To avoid lockdep issues (CPU PM notifiers use raw spinlocks) create + * a mmio regmap for pmu-intr-gen that uses raw spinlocks instead of + * syscon provided regmap. + */ + ret =3D of_address_to_resource(intr_gen_node, 0, &intrgen_res); + of_node_put(intr_gen_node); + + virt_addr =3D devm_ioremap(dev, intrgen_res.start, + resource_size(&intrgen_res)); + if (!virt_addr) + return -ENOMEM; + + pmu_context->pmuintrgen =3D devm_regmap_init_mmio(dev, virt_addr, + ®map_pmu_intr); + if (IS_ERR(pmu_context->pmuintrgen)) { + dev_err(dev, "failed to initialize pmu-intr-gen regmap\n"); + return PTR_ERR(pmu_context->pmuintrgen); + } + + /* register custom mmio regmap with syscon */ + ret =3D of_syscon_register_regmap(intr_gen_node, + pmu_context->pmuintrgen); + if (ret) + return ret; + + pmu_context->in_cpuhp =3D devm_bitmap_zalloc(dev, num_possible_cpus(), + GFP_KERNEL); + if (!pmu_context->in_cpuhp) + return -ENOMEM; + + raw_spin_lock_init(&pmu_context->cpupm_lock); + pmu_context->sys_inreboot =3D false; + pmu_context->sys_insuspend =3D false; + + /* set PMU to power on */ + for_each_online_cpu(cpu) + gs101_cpuhp_pmu_online(cpu); + + /* register CPU hotplug callbacks */ + cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, "soc/exynos-pmu:prepare", + gs101_cpuhp_pmu_online, NULL); + + cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "soc/exynos-pmu:online", + NULL, gs101_cpuhp_pmu_offline); + + /* register CPU PM notifiers for cpuidle */ + cpu_pm_register_notifier(&gs101_cpu_pm_notifier); + register_reboot_notifier(&exynos_cpupm_reboot_nb); return 0; } =20 @@ -435,23 +659,9 @@ static int exynos_pmu_probe(struct platform_device *pd= ev) pmu_context->dev =3D dev; =20 if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_cpuhp) { - pmu_context->pmuintrgen =3D syscon_regmap_lookup_by_phandle(dev->of_node, - "google,pmu-intr-gen-syscon"); - if (IS_ERR(pmu_context->pmuintrgen)) { - /* - * To maintain support for older DTs that didn't specify syscon phandle - * just issue a warning rather than fail to probe. - */ - dev_warn(&pdev->dev, "pmu-intr-gen syscon unavailable\n"); - } else { - cpuhp_setup_state(CPUHP_BP_PREPARE_DYN, - "soc/exynos-pmu:prepare", - gs101_cpuhp_pmu_online, NULL); - - cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, - "soc/exynos-pmu:online", - NULL, gs101_cpuhp_pmu_offline); - } + ret =3D setup_cpuhp_and_cpuidle(dev); + if (ret) + return ret; } =20 if (pmu_context->pmu_data && pmu_context->pmu_data->pmu_init) @@ -471,10 +681,32 @@ static int exynos_pmu_probe(struct platform_device *p= dev) return 0; } =20 +static int exynos_cpupm_suspend_noirq(struct device *dev) +{ + raw_spin_lock(&pmu_context->cpupm_lock); + pmu_context->sys_insuspend =3D true; + raw_spin_unlock(&pmu_context->cpupm_lock); + return 0; +} + +static int exynos_cpupm_resume_noirq(struct device *dev) +{ + raw_spin_lock(&pmu_context->cpupm_lock); + pmu_context->sys_insuspend =3D false; + raw_spin_unlock(&pmu_context->cpupm_lock); + return 0; +} + +static const struct dev_pm_ops cpupm_pm_ops =3D { + NOIRQ_SYSTEM_SLEEP_PM_OPS(exynos_cpupm_suspend_noirq, + exynos_cpupm_resume_noirq) +}; + static struct platform_driver exynos_pmu_driver =3D { .driver =3D { .name =3D "exynos-pmu", .of_match_table =3D exynos_pmu_of_device_ids, + .pm =3D pm_sleep_ptr(&cpupm_pm_ops), }, .probe =3D exynos_pmu_probe, }; --- base-commit: 024e09e444bd2b06aee9d1f3fe7b313c7a2df1bb change-id: 20250524-gs101-cpuidle-cafc96dd849d Best regards, --=20 Peter Griffin