* [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation
@ 2026-11-03 10:45 Abel Vesa
2026-11-05 15:53 ` sashiko-bot
2026-11-05 20:18 ` Akhil P Oommen
0 siblings, 2 replies; 3+ messages in thread
From: Abel Vesa @ 2026-11-03 10:45 UTC (permalink / raw)
To: Rob Clark, Sean Paul, Konrad Dybcio, Akhil P Oommen,
Dmitry Baryshkov, Abhinav Kumar, Jessica Zhang, Marijn Suijten,
David Airlie, Simona Vetter
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Abel Vesa
The GMU puts the RSC to sleep when the GPU is suspended, and remembers
that it has to request the RSC to wake up again on the next resume. A
hibernation image is restored after a power cycle though, and the RSC
then starts from scratch, in a state where it does not answer that
request:
adreno_gmu 3d6c000.gmu: [drm:a6xx_gmu_resume [msm]] *ERROR* Unable to power on the GPU RSC
adreno_gmu 3d6c000.gmu: [drm:a6xx_gmu_set_oob [msm]] *ERROR* Timeout waiting for GMU OOB set GPU_SET: 0x0
msm_dpu ae01000.display-controller: [drm:hangcheck_handler [msm]] *ERROR* 44070041: hangcheck detected gpu lockup rb 0!
The first job submitted after the resume hangs, and the compositor is
left with nothing to show.
The GMU secure init has the same problem: it is done once, but the
registers it has the secure world program are reset by the power cycle
as well, so the restored kernel only gets them set up if the kernel
that loaded the image happened to initialize the GPU.
Forget about both when restoring, so that the resume starts the GMU
like after probe.
Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
---
Sent as an RFC, as this only resets the GMU state the driver keeps
track of. That is enough on the Glymur CRD (A8xx), where the AOP
configures the RSC and PDC. On A6xx and A7xx, a6xx_gmu_rpmh_init()
programs the RSCC sequence, and on older parts the PDC, only at probe,
so after a restore they are only set up if the kernel that loaded the
image probed the GPU.
The zap shader has a similar problem: it is loaded once per boot (the
static "loaded" in a6xx_zap_shader_init()), while the secure world and
the zap memory region start out empty after the power cycle.
Would a full GMU re-initialization on restore be preferred over
resetting the status bits?
Tested on the Glymur CRD over 9 hibernation and restore cycles, with
msm in the initramfs of the kernel that loads the image. The GPU renders
after each restore, with no RSC, OOB or hangcheck errors.
Prepared with help from an LLM-based assistant.
---
drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 10 ++++++++++
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 8 ++++++++
drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 1 +
drivers/gpu/drm/msm/adreno/adreno_device.c | 22 +++++++++++++++++++++-
drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 ++
5 files changed, 42 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
index 662f09bec9d5..1e6e47b635f0 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
@@ -1319,6 +1319,16 @@ static int a6xx_gmu_gxpd_put(struct a6xx_gmu *gmu)
return 0;
}
+/*
+ * After a power cycle the RSC does not expect a wakeup request and the GMU
+ * secure init is gone, so start the GMU like after probe.
+ */
+void a6xx_gmu_power_cycled(struct a6xx_gpu *a6xx_gpu)
+{
+ clear_bit(GMU_STATUS_PDC_SLEEP, &a6xx_gpu->gmu.status);
+ clear_bit(GMU_STATUS_SECURE_INIT, &a6xx_gpu->gmu.status);
+}
+
int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
{
struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 92e8c8abb86d..962b497868da 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -2796,6 +2796,11 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return gpu;
}
+static void a6xx_gpu_power_cycled(struct adreno_gpu *adreno_gpu)
+{
+ a6xx_gmu_power_cycled(to_a6xx_gpu(adreno_gpu));
+}
+
const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.base = {
.get_param = adreno_get_param,
@@ -2831,6 +2836,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
.bus_halt = a6xx_bus_clear_pending_transactions,
.mmu_fault_handler = a6xx_fault_handler,
.gx_is_on = a6xx_gmu_gx_is_on,
+ .power_cycled = a6xx_gpu_power_cycled,
};
const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
@@ -2903,6 +2909,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
.mmu_fault_handler = a6xx_fault_handler,
.gx_is_on = a7xx_gmu_gx_is_on,
.aqe_is_enabled = a6xx_aqe_is_enabled,
+ .power_cycled = a6xx_gpu_power_cycled,
};
const struct adreno_gpu_funcs a8xx_gpu_funcs = {
@@ -2935,4 +2942,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
.mmu_fault_handler = a8xx_fault_handler,
.gx_is_on = a8xx_gmu_gx_is_on,
.aqe_is_enabled = a6xx_aqe_is_enabled,
+ .power_cycled = a6xx_gpu_power_cycled,
};
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
index 79912a33e17c..37266d64427c 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
@@ -286,6 +286,7 @@ static inline void a6xx_cx_misc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 va
((_ring)->id * sizeof(uint32_t)))
int a6xx_gmu_resume(struct a6xx_gpu *gpu);
+void a6xx_gmu_power_cycled(struct a6xx_gpu *gpu);
int a6xx_gmu_stop(struct a6xx_gpu *gpu);
int a6xx_gmu_wait_for_idle(struct a6xx_gmu *gmu);
diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
index 7108d4aa59b5..b91b32e61fab 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_device.c
+++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
@@ -402,8 +402,28 @@ static int adreno_system_resume(struct device *dev)
return pm_runtime_force_resume(dev);
}
+static int adreno_system_restore(struct device *dev)
+{
+ struct msm_gpu *gpu = dev_to_gpu(dev);
+ struct adreno_gpu *adreno_gpu;
+
+ if (!gpu)
+ return 0;
+
+ adreno_gpu = to_adreno_gpu(gpu);
+ if (adreno_gpu->funcs->power_cycled)
+ adreno_gpu->funcs->power_cycled(adreno_gpu);
+
+ return adreno_system_resume(dev);
+}
+
static const struct dev_pm_ops adreno_pm_ops = {
- SYSTEM_SLEEP_PM_OPS(adreno_system_suspend, adreno_system_resume)
+ .suspend = pm_sleep_ptr(adreno_system_suspend),
+ .resume = pm_sleep_ptr(adreno_system_resume),
+ .freeze = pm_sleep_ptr(adreno_system_suspend),
+ .thaw = pm_sleep_ptr(adreno_system_resume),
+ .poweroff = pm_sleep_ptr(adreno_system_suspend),
+ .restore = pm_sleep_ptr(adreno_system_restore),
RUNTIME_PM_OPS(adreno_runtime_suspend, adreno_runtime_resume, NULL)
};
diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
index 4b2156825bdf..7ad8cbcfede4 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
@@ -81,6 +81,8 @@ struct adreno_gpu_funcs {
int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
bool (*gx_is_on)(struct adreno_gpu *adreno_gpu);
bool (*aqe_is_enabled)(struct adreno_gpu *adreno_gpu);
+ /* Called on restore from hibernation, after the hardware lost its state */
+ void (*power_cycled)(struct adreno_gpu *adreno_gpu);
};
struct adreno_reglist {
---
base-commit: 2637bdec0535a2044cd830eba9a79363651d9043
change-id: 20261023-b4-drm-msm-a6xx-rsc-restore-hibernation-912730e2de2d
Best regards,
--
Abel
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation
2026-11-03 10:45 [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation Abel Vesa
@ 2026-11-05 15:53 ` sashiko-bot
2026-11-05 20:18 ` Akhil P Oommen
1 sibling, 0 replies; 3+ messages in thread
From: sashiko-bot @ 2026-11-05 15:53 UTC (permalink / raw)
To: Abel Vesa; +Cc: dri-devel
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] drm/msm/a6xx: missing RSCC/PDC and ACD reinit in a6xx_gmu_power_cycled()
- [High] drm/msm/a6xx: stale static loaded flag in a6xx_zap_shader_init() on restore
- [High] drm/msm/a6xx: unconditional PDC_SLEEP clear in a6xx_gmu_power_cycled()
--
commit 491412dbdff3368cc8067f8c98101632e337bedb
Author: Abel Vesa <abel.vesa@oss.qualcomm.com>
drm/msm/a6xx: Reset the GMU state when restoring from hibernation
This commit adds a power_cycled callback invoked from adreno_system_restore()
to clear GMU_STATUS_PDC_SLEEP and GMU_STATUS_SECURE_INIT when restoring from
hibernation so that the GMU restarts as it does after probe.
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 662f09bec9d52..1e6e47b635f08 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1319,6 +1319,16 @@ static int a6xx_gmu_gxpd_put(struct a6xx_gmu *gmu)
> return 0;
> }
>
> +/*
> + * After a power cycle the RSC does not expect a wakeup request and the GMU
> + * secure init is gone, so start the GMU like after probe.
> + */
> +void a6xx_gmu_power_cycled(struct a6xx_gpu *a6xx_gpu)
> +{
> + clear_bit(GMU_STATUS_PDC_SLEEP, &a6xx_gpu->gmu.status);
[Severity: High]
Is it always safe to unconditionally clear GMU_STATUS_PDC_SLEEP and assume a
cold boot on every restore transition?
If the boot kernel that loads the hibernation image opens the DRM device
(for example via an initramfs splash screen calling
msm_open() -> adreno_load_gpu() -> a6xx_gmu_resume()), it boots the GMU,
sets REG_A7XX_CX_MISC_TCM_RET_CNTL = 1 or REG_A6XX_GMU_GENERAL_7 = 1, and
then suspends the GPU during runtime suspend or
dpm_suspend_start(PMSG_QUIESCE) -> adreno_system_suspend() ->
a6xx_gmu_stop() -> a6xx_rpmh_stop(), which puts the hardware GPU RSC into
sleep mode. The same RSC sleep state also remains in effect when
adreno_system_restore() runs without a power cycle, such as during
HIBERNATION_TEST_RESUME or when hibernation_platform_enter() aborts after
dpm_suspend_start(PMSG_HIBERNATE) and rolls back via PMSG_RESTORE.
When a6xx_gmu_power_cycled() clears GMU_STATUS_PDC_SLEEP in those cases,
a6xx_rpmh_start() will return early without waking the sleeping RSC:
drivers/gpu/drm/msm/adreno/a6xx_gmu.c:a6xx_rpmh_start() {
if (!test_and_clear_bit(GMU_STATUS_PDC_SLEEP, &gmu->status))
return 0;
}
Additionally, if the loader kernel booted the GMU prior to quiesce,
a6xx_gmu_resume() in the restored kernel will still read 1 from
REG_A7XX_CX_MISC_TCM_RET_CNTL or REG_A6XX_GMU_GENERAL_7 and select
GMU_WARM_BOOT, skipping a6xx_gmu_fw_load() in a6xx_gmu_fw_start():
drivers/gpu/drm/msm/adreno/a6xx_gmu.c:a6xx_gmu_resume() {
if (adreno_is_a7xx(adreno_gpu) || adreno_is_a8xx(adreno_gpu)) {
status = a6xx_cx_misc_read(a6xx_gpu, REG_A7XX_CX_MISC_TCM_RET_CNTL) == 1 ?
GMU_WARM_BOOT : GMU_COLD_BOOT;
} else if (gmu->legacy) {
status = gmu_read(gmu, REG_A6XX_GMU_GENERAL_7) == 1 ?
GMU_WARM_BOOT : GMU_COLD_BOOT;
...
}
Should this check the hardware RSC status (or re-initialize the hardware
state) and ensure a cold boot so that GMU firmware is reloaded and the RSC
state matches?
> + clear_bit(GMU_STATUS_SECURE_INIT, &a6xx_gpu->gmu.status);
> +}
[Severity: High]
Does a6xx_gmu_power_cycled() also need to re-run the RSCC/PDC and ACD probe-
time initialization when restoring from hibernation?
The callback is wired into a6xx_gpu_funcs, a7xx_gpu_funcs, and
a8xx_gpu_funcs. When the kernel that loads the hibernation image has not
probed the msm driver, the hibernation power cycle resets RSCC, PDC, and AOSS
state to power-on defaults. During initial probe, a6xx_gmu_init() runs both
a6xx_gmu_acd_probe() and a6xx_gmu_rpmh_init():
drivers/gpu/drm/msm/adreno/a6xx_gmu.c:a6xx_gmu_init() {
ret = a6xx_gmu_acd_probe(gmu);
if (ret)
goto detach_gxpd;
/* Set up the HFI queues */
a6xx_hfi_init(gmu);
/* Initialize RPMh */
a6xx_gmu_rpmh_init(gmu);
}
On A6xx and A7xx (unlike A8xx where AOP configures RSCC and PDC),
a6xx_gmu_rpmh_init() programs the RSCC-PDC handshake registers, loads the
RSCC sequencer microcode, loads PDC sequencer microcode and TCS commands on
older targets, and enables the GPU PDC via REG_A6XX_PDC_GPU_ENABLE_PDC.
Similarly, a6xx_gmu_acd_probe() sends the QMP notification to AOSS:
drivers/gpu/drm/msm/adreno/a6xx_gmu.c:a6xx_gmu_acd_probe() {
ret = qmp_send(gmu->qmp, "{class: gpu, res: acd, val: %d}", !!cmd->enable_by_level);
}
Without re-running a6xx_gmu_rpmh_init() and re-notifying AOSS of the ACD
state before a6xx_gmu_resume() -> a6xx_hfi_start() -> a6xx_hfi_enable_acd()
enables HFI_FEATURE_ACD on the GMU, won't resume after hibernation leave
RSCC/PDC unprogrammed on A6xx/A7xx and leave AOSS with ACD disabled while
the GMU enables ACD?
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 92e8c8abb86da..962b497868daf 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -2796,6 +2796,11 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
> return gpu;
> }
>
> +static void a6xx_gpu_power_cycled(struct adreno_gpu *adreno_gpu)
> +{
> + a6xx_gmu_power_cycled(to_a6xx_gpu(adreno_gpu));
> +}
[Severity: High]
What happens to the zap shader state in a6xx_zap_shader_init() after
a6xx_gpu_power_cycled() runs on hibernation restore?
Before hibernation, hw_init() in a6xx_gpu.c and a8xx_gpu.c calls
a6xx_zap_shader_init(), which loads the zap shader via
adreno_zap_shader_load(gpu, GPU_PAS_ID) and sets its static loaded flag to
true:
drivers/gpu/drm/msm/adreno/a6xx_gpu.c:a6xx_zap_shader_init() {
static bool loaded;
int ret;
if (loaded)
return 0;
ret = adreno_zap_shader_load(gpu, GPU_PAS_ID);
loaded = !ret;
return ret;
}
Across a hibernation power cycle, the no-map zap-shader memory region and
secure world PAS state are wiped (even if the loader kernel has msm in its
initramfs, unless the loader kernel also opened the DRM device to trigger
adreno_load_gpu() -> hw_init()). Because loaded remains true in the restored
kernel image, the next hw_init() sees a6xx_zap_shader_init() return 0
without reloading the zap shader and immediately emits CP_SET_SECURE_MODE:
drivers/gpu/drm/msm/adreno/a6xx_gpu.c:hw_init() {
ret = a6xx_zap_shader_init(gpu);
if (!ret) {
OUT_PKT7(gpu->rb[0], CP_SET_SECURE_MODE, 1);
OUT_RING(gpu->rb[0], 0x00000000);
a6xx_flush(gpu, gpu->rb[0]);
if (!a6xx_idle(gpu, gpu->rb[0]))
return -EINVAL;
...
}
Won't CP_SET_SECURE_MODE fail or hang on A6xx, A7xx, and A8xx targets that
use a zap shader unless the zap shader is also reloaded (or shut down and
re-initialized via qcom_scm_pas_shutdown() / adreno_zap_shader_load()) across
hibernation?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261103-b4-drm-msm-a6xx-rsc-restore-hibernation-v1-1-3250fd8eefb6@oss.qualcomm.com?part=1
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation
2026-11-03 10:45 [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation Abel Vesa
2026-11-05 15:53 ` sashiko-bot
@ 2026-11-05 20:18 ` Akhil P Oommen
1 sibling, 0 replies; 3+ messages in thread
From: Akhil P Oommen @ 2026-11-05 20:18 UTC (permalink / raw)
To: Abel Vesa
Cc: linux-arm-msm, dri-devel, freedreno, linux-kernel, Rob Clark,
Sean Paul, Konrad Dybcio, Dmitry Baryshkov, Abhinav Kumar,
Jessica Zhang, Marijn Suijten, David Airlie, Simona Vetter
On 11/3/2026 4:15 PM, Abel Vesa wrote:
> The GMU puts the RSC to sleep when the GPU is suspended, and remembers
> that it has to request the RSC to wake up again on the next resume. A
> hibernation image is restored after a power cycle though, and the RSC
> then starts from scratch, in a state where it does not answer that
> request:
>
> adreno_gmu 3d6c000.gmu: [drm:a6xx_gmu_resume [msm]] *ERROR* Unable to power on the GPU RSC
> adreno_gmu 3d6c000.gmu: [drm:a6xx_gmu_set_oob [msm]] *ERROR* Timeout waiting for GMU OOB set GPU_SET: 0x0
> msm_dpu ae01000.display-controller: [drm:hangcheck_handler [msm]] *ERROR* 44070041: hangcheck detected gpu lockup rb 0!
>
> The first job submitted after the resume hangs, and the compositor is
> left with nothing to show.
>
> The GMU secure init has the same problem: it is done once, but the
> registers it has the secure world program are reset by the power cycle
> as well, so the restored kernel only gets them set up if the kernel
> that loaded the image happened to initialize the GPU.
>
> Forget about both when restoring, so that the resume starts the GMU
> like after probe.
>
> Signed-off-by: Abel Vesa <abel.vesa@oss.qualcomm.com>
> ---
> Sent as an RFC, as this only resets the GMU state the driver keeps
> track of. That is enough on the Glymur CRD (A8xx), where the AOP
> configures the RSC and PDC. On A6xx and A7xx, a6xx_gmu_rpmh_init()
> programs the RSCC sequence, and on older parts the PDC, only at probe,
> so after a restore they are only set up if the kernel that loaded the
> image probed the GPU.
>
> The zap shader has a similar problem: it is loaded once per boot (the
> static "loaded" in a6xx_zap_shader_init()), while the secure world and
> the zap memory region start out empty after the power cycle.
>
> Would a full GMU re-initialization on restore be preferred over
> resetting the status bits?
>
> Tested on the Glymur CRD over 9 hibernation and restore cycles, with
> msm in the initramfs of the kernel that loads the image. The GPU renders
> after each restore, with no RSC, OOB or hangcheck errors.
>
> Prepared with help from an LLM-based assistant.
> ---
> drivers/gpu/drm/msm/adreno/a6xx_gmu.c | 10 ++++++++++
> drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 8 ++++++++
> drivers/gpu/drm/msm/adreno/a6xx_gpu.h | 1 +
> drivers/gpu/drm/msm/adreno/adreno_device.c | 22 +++++++++++++++++++++-
> drivers/gpu/drm/msm/adreno/adreno_gpu.h | 2 ++
> 5 files changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> index 662f09bec9d5..1e6e47b635f0 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c
> @@ -1319,6 +1319,16 @@ static int a6xx_gmu_gxpd_put(struct a6xx_gmu *gmu)
> return 0;
> }
>
> +/*
> + * After a power cycle the RSC does not expect a wakeup request and the GMU
> + * secure init is gone, so start the GMU like after probe.
> + */
> +void a6xx_gmu_power_cycled(struct a6xx_gpu *a6xx_gpu)
> +{
Need a check to skip this on gmu_wrapper.
> + clear_bit(GMU_STATUS_PDC_SLEEP, &a6xx_gpu->gmu.status);
> + clear_bit(GMU_STATUS_SECURE_INIT, &a6xx_gpu->gmu.status);
> +}
> +
> int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu)
> {
> struct adreno_gpu *adreno_gpu = &a6xx_gpu->base;
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> index 92e8c8abb86d..962b497868da 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
> @@ -2796,6 +2796,11 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
> return gpu;
> }
>
> +static void a6xx_gpu_power_cycled(struct adreno_gpu *adreno_gpu)
> +{
This wrapper is unnecessary.
> + a6xx_gmu_power_cycled(to_a6xx_gpu(adreno_gpu));
> +}
> +
> const struct adreno_gpu_funcs a6xx_gpu_funcs = {
> .base = {
> .get_param = adreno_get_param,
> @@ -2831,6 +2836,7 @@ const struct adreno_gpu_funcs a6xx_gpu_funcs = {
> .bus_halt = a6xx_bus_clear_pending_transactions,
> .mmu_fault_handler = a6xx_fault_handler,
> .gx_is_on = a6xx_gmu_gx_is_on,
> + .power_cycled = a6xx_gpu_power_cycled,
> };
>
> const struct adreno_gpu_funcs a6xx_gmuwrapper_funcs = {
> @@ -2903,6 +2909,7 @@ const struct adreno_gpu_funcs a7xx_gpu_funcs = {
> .mmu_fault_handler = a6xx_fault_handler,
> .gx_is_on = a7xx_gmu_gx_is_on,
> .aqe_is_enabled = a6xx_aqe_is_enabled,
> + .power_cycled = a6xx_gpu_power_cycled,
> };
>
> const struct adreno_gpu_funcs a8xx_gpu_funcs = {
> @@ -2935,4 +2942,5 @@ const struct adreno_gpu_funcs a8xx_gpu_funcs = {
> .mmu_fault_handler = a8xx_fault_handler,
> .gx_is_on = a8xx_gmu_gx_is_on,
> .aqe_is_enabled = a6xx_aqe_is_enabled,
> + .power_cycled = a6xx_gpu_power_cycled,
> };
> diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> index 79912a33e17c..37266d64427c 100644
> --- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.h
> @@ -286,6 +286,7 @@ static inline void a6xx_cx_misc_write(struct a6xx_gpu *a6xx_gpu, u32 reg, u32 va
> ((_ring)->id * sizeof(uint32_t)))
>
> int a6xx_gmu_resume(struct a6xx_gpu *gpu);
> +void a6xx_gmu_power_cycled(struct a6xx_gpu *gpu);
> int a6xx_gmu_stop(struct a6xx_gpu *gpu);
>
> int a6xx_gmu_wait_for_idle(struct a6xx_gmu *gmu);
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_device.c b/drivers/gpu/drm/msm/adreno/adreno_device.c
> index 7108d4aa59b5..b91b32e61fab 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_device.c
> +++ b/drivers/gpu/drm/msm/adreno/adreno_device.c
> @@ -402,8 +402,28 @@ static int adreno_system_resume(struct device *dev)
> return pm_runtime_force_resume(dev);
> }
>
> +static int adreno_system_restore(struct device *dev)
> +{
> + struct msm_gpu *gpu = dev_to_gpu(dev);
> + struct adreno_gpu *adreno_gpu;
> +
> + if (!gpu)
> + return 0;
> +
> + adreno_gpu = to_adreno_gpu(gpu);
> + if (adreno_gpu->funcs->power_cycled)
> + adreno_gpu->funcs->power_cycled(adreno_gpu);
> +
Can we please reset the zap loaded state here even though Glymur doesn't
require it at the moment?
Also, please ensure all registers are reloaded on the smmu driver side.
for eg: PRR configuration.
-Akhil.
> + return adreno_system_resume(dev);
> +}
> +
> static const struct dev_pm_ops adreno_pm_ops = {
> - SYSTEM_SLEEP_PM_OPS(adreno_system_suspend, adreno_system_resume)
> + .suspend = pm_sleep_ptr(adreno_system_suspend),
> + .resume = pm_sleep_ptr(adreno_system_resume),
> + .freeze = pm_sleep_ptr(adreno_system_suspend),
> + .thaw = pm_sleep_ptr(adreno_system_resume),
> + .poweroff = pm_sleep_ptr(adreno_system_suspend),
> + .restore = pm_sleep_ptr(adreno_system_restore),
> RUNTIME_PM_OPS(adreno_runtime_suspend, adreno_runtime_resume, NULL)
> };
>
> diff --git a/drivers/gpu/drm/msm/adreno/adreno_gpu.h b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> index 4b2156825bdf..7ad8cbcfede4 100644
> --- a/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> +++ b/drivers/gpu/drm/msm/adreno/adreno_gpu.h
> @@ -81,6 +81,8 @@ struct adreno_gpu_funcs {
> int (*mmu_fault_handler)(void *arg, unsigned long iova, int flags, void *data);
> bool (*gx_is_on)(struct adreno_gpu *adreno_gpu);
> bool (*aqe_is_enabled)(struct adreno_gpu *adreno_gpu);
> + /* Called on restore from hibernation, after the hardware lost its state */
> + void (*power_cycled)(struct adreno_gpu *adreno_gpu);
> };
>
> struct adreno_reglist {
>
> ---
> base-commit: 2637bdec0535a2044cd830eba9a79363651d9043
> change-id: 20261023-b4-drm-msm-a6xx-rsc-restore-hibernation-912730e2de2d
>
> Best regards,
> --
>
> Abel
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-05 20:19 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-03 10:45 [PATCH RFC] drm/msm/a6xx: Reset the GMU state when restoring from hibernation Abel Vesa
2026-11-05 15:53 ` sashiko-bot
2026-11-05 20:18 ` Akhil P Oommen
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.