[PATCH v2 4/4] drm/msm/a6xx: keep the timestamp offset before a750
From: Dmitry Baryshkov
Date: Sat Oct 31 2026 - 12:13:37 EST
Before a750 the always-on counter does not survive a power collapse
either: on the GMU-less parts it is in the GPU power domain, and on a650
the GMU counter behind MSM_PARAM_TIMESTAMP restarts with every runtime
suspend, reading 65229 and 68216 ticks two seconds apart. From a750 on
the counter is loaded from one in the CX domain that keeps running, and
userspace already relies on that.
Save and restore the counter around power collapse and recovery on the
earlier parts, as on a5xx.
Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@xxxxxxxxxxxxxxxx>
---
drivers/gpu/drm/msm/adreno/a6xx_gpu.c | 21 ++++++++++++++++++++-
1 file changed, 20 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
index 92e8c8abb86d..7cbeeccca000 100644
--- a/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a6xx_gpu.c
@@ -1575,6 +1575,8 @@ static void a6xx_recover(struct msm_gpu *gpu)
adreno_dump_info(gpu);
+ adreno_timestamp_save(gpu);
+
if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) {
/* Sometimes crashstate capture is skipped, so SQE should be halted here again */
gpu_write(gpu, REG_A6XX_CP_SQE_CNTL, 3);
@@ -1638,6 +1640,9 @@ static void a6xx_recover(struct msm_gpu *gpu)
gpu->active_submits = active_submits;
mutex_unlock(&gpu->active_lock);
+ /* the GPU may not have suspended, so resume did not restore */
+ adreno_timestamp_restore(gpu);
+
msm_gpu_hw_init(gpu);
a6xx_gpu->hung = false;
}
@@ -2151,6 +2156,8 @@ static int a6xx_gmu_pm_resume(struct msm_gpu *gpu)
if (ret)
return ret;
+ adreno_timestamp_restore(gpu);
+
msm_devfreq_resume(gpu);
if (adreno_is_a8xx(adreno_gpu))
@@ -2212,6 +2219,8 @@ static int a6xx_pm_resume(struct msm_gpu *gpu)
msm_devfreq_resume(gpu);
a6xx_llc_activate(a6xx_gpu);
+ adreno_timestamp_restore(gpu);
+
return 0;
/* If anything goes south, tear the GPU down piece by piece.. */
@@ -2234,6 +2243,8 @@ static int a6xx_gmu_pm_suspend(struct msm_gpu *gpu)
trace_msm_gpu_suspend(0);
+ adreno_timestamp_save(gpu);
+
a6xx_llc_deactivate(a6xx_gpu);
msm_devfreq_suspend(gpu);
@@ -2241,8 +2252,10 @@ static int a6xx_gmu_pm_suspend(struct msm_gpu *gpu)
mutex_lock(&a6xx_gpu->gmu.lock);
ret = a6xx_gmu_stop(a6xx_gpu);
mutex_unlock(&a6xx_gpu->gmu.lock);
- if (ret)
+ if (ret) {
+ adreno_timestamp_restore(gpu);
return ret;
+ }
if (a6xx_gpu->shadow_bo)
for (i = 0; i < gpu->nr_rings; i++)
@@ -2262,6 +2275,8 @@ static int a6xx_pm_suspend(struct msm_gpu *gpu)
trace_msm_gpu_suspend(0);
+ adreno_timestamp_save(gpu);
+
a6xx_llc_deactivate(a6xx_gpu);
msm_devfreq_suspend(gpu);
@@ -2757,6 +2772,10 @@ static struct msm_gpu *a6xx_gpu_init(struct drm_device *dev)
return ERR_PTR(ret);
}
+ /* From a750 on, the always-on counter survives a power collapse */
+ if (!adreno_is_a750_family(adreno_gpu) && !adreno_is_a8xx(adreno_gpu))
+ adreno_timestamp_init(gpu);
+
/* Set the speedbin value that is passed to userspace */
if (a6xx_read_speedbin(&pdev->dev, a6xx_gpu, info, &speedbin) || !speedbin)
speedbin = 0xffff;
--
2.47.3