drivers/clk/qcom/gdsc.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++-- drivers/clk/qcom/gdsc.h | 19 +++ 2 files changed, 351 insertions(+), 12 deletions(-)
The MSM8x60 family (MSM8260 / MSM8660 / APQ8060) uses a pre-modern
"footswitch" power-domain block (GFS) for its multimedia GDSCs that
predates the modern qcom GDSC programming model. The legacy block has
a single-register layout (ENABLE / CLAMP / RETENTION at fixed bits in
the GDSCR) instead of the modern split GDSCR / CFG_GDSCR pair, no
power-status bit (state has to be inferred from ENABLE + CLAMP), and a
fixed-delay handoff sequence with no completion register to poll.
Patch 1 adds a LEGACY_FOOTSWITCH flag plus the supporting helpers
(legacy enable / disable sequencing, gdsc_check_status fallback,
legacy clamp helpers). Patch 2 adds an RPM_ALWAYS_ON flag wiring the
PWRSTS_ON ALWAYS_ON paths to GENPD_FLAG_RPM_ALWAYS_ON; this is needed
because some MSM8x60 GDSCs are managed by RPM firmware and the kernel
must keep its genpd vote alive across runtime PM transitions.
v2 folds 2 High Sashiko findings on the v1 patchset, both vote-balance
bugs in gdsc_init() (see below). Both folds verified on HW; no
regulator-imbalance WARNs in dmesg post-fix.
Signed-off-by: Herman van Hazendonk <github.com@herrie.org>
---
Changes in v2:
Both Sashiko findings folded:
- [High] gdsc_init() PWRSTS_ON + LEGACY_FOOTSWITCH + initial_on
triple condition: the PWRSTS_ON block calls gdsc_enable() above,
which on the legacy path takes a regulator_enable() vote
unconditionally. The downstream "sync" block at line ~737 then
voted *again* because initial_on=true, while gdsc_disable() only
unwinds the vote once -> permanent +1 ref-count imbalance per
probe. Skip the sync vote when
(pwrsts == PWRSTS_ON && LEGACY_FOOTSWITCH).
Folded into patch 1 (LEGACY_FOOTSWITCH support).
- [High] gdsc_init() ALWAYS_ON / RPM_ALWAYS_ON block: the
unconditional gdsc_enable() call ignored its return value and
unconditionally set on=true. If gdsc_enable() failed (e.g. an
internal regulator_enable failure) the subsequent
pm_genpd_init() error path would call regulator_disable() for a
vote that was never actually taken -> regulator ref-count
underflow and vote leak. Propagate the gdsc_enable() return
immediately. Folded into patch 2 (RPM_ALWAYS_ON flag).
Test results (v2, HP TouchPad APQ8060, kernel 7.1.0-rc1):
- Boot clean. All MSM8x60 GDSCs probe and reach their expected
initial state: vfe / ved / rot / mdp / gfx3d on (bootloader
handoff); ijpeg / vpe / gfx2d0 / gfx2d1 off-0 (kernel-managed).
- Camera stream stress (20x rapid pix640 + pix1280 + 60s
unbind/rebind race on mt9m113 -> exercises vfe domain off/on
cycles + ved bringup): zero regulator-imbalance WARNs, zero
"Unbalanced disable" messages from regulator/core.c, zero
clk-refcount underflow WARNs.
- 120s concurrent multi-subsystem load (camera stream loop + dd
to eMMC + /dev/urandom + filesystem walk): all GDSCs stay in
expected state, no genpd warnings, USB stayed up, MDP stayed
active. Driver still bound at the end.
- dmesg post-load: 0 WARN, 0 BUG, 0 Oops from gdsc /
regulator / clk frameworks. The only routine "CSIPHY1:
usleep 10-15ms for GDSC stabilize" info lines (camss
pre-existing chatter, not gdsc-related) are visible.
- Kernel build clean (ARCH=arm, CONFIG_QCOM_GDSC=y,
CONFIG_QCOM_CLK_RPM=y, CONFIG_MSM_MMCC_8660=y).
- Link to v1: https://lore.kernel.org/r/20260602050840.435933-1-github.com@herrie.org
---
Herman van Hazendonk (2):
clk: qcom: gdsc: add LEGACY_FOOTSWITCH support for MSM8x60
clk: qcom: gdsc: add RPM_ALWAYS_ON flag
drivers/clk/qcom/gdsc.c | 344 ++++++++++++++++++++++++++++++++++++++++++++++--
drivers/clk/qcom/gdsc.h | 19 +++
2 files changed, 351 insertions(+), 12 deletions(-)
---
base-commit: 944125b4c454b58d2fe6e35f1087a932b2050dff
change-id: 20260606-submit-clk-gdsc-msm8x60-legacy-1e8d4b336eeb
Best regards,
--
Herman van Hazendonk <github.com@herrie.org>
© 2016 - 2026 Red Hat, Inc.