diff --git a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
index c17e9777beae..0259e60b8011 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
+++ b/drivers/gpu/drm/msm/adreno/a3xx_gpu.c
@@ -25,6 +25,8 @@
extern bool hang_debug;
+#define A3XX_VBIF_XIN_HALT_CTRL0_MASK GENMASK(5, 0)
+
static void a3xx_dump(struct msm_gpu *gpu);
static bool a3xx_idle(struct msm_gpu *gpu);
@@ -496,6 +498,38 @@ static u64 a3xx_gpu_busy(struct msm_gpu *gpu, unsigned long *out_sample_rate)
return busy_cycles;
}
+static int a3xx_vbif_halt(struct msm_gpu *gpu)
+{
+ u32 ack;
+ int ret;
+
+ gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0,
+ A3XX_VBIF_XIN_HALT_CTRL0_MASK);
+ ret = spin_until(((ack = gpu_read(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL1)) &
+ A3XX_VBIF_XIN_HALT_CTRL0_MASK) ==
+ A3XX_VBIF_XIN_HALT_CTRL0_MASK);
+ gpu_write(gpu, REG_A3XX_VBIF_XIN_HALT_CTRL0, 0);
+
+ if (ret)
+ return -EBUSY;
+
+ return 0;
+}
+
+static int a3xx_pm_suspend(struct msm_gpu *gpu)
+{
+ int ret;
+
+ if (!a3xx_idle(gpu))
+ return -EBUSY;
+
+ ret = a3xx_vbif_halt(gpu);
+ if (ret)
+ return ret;
+
+ return msm_gpu_pm_suspend(gpu);
+}
+
static u32 a3xx_get_rptr(struct msm_gpu *gpu, struct msm_ringbuffer *ring)
{
ring->memptrs->rptr = gpu_read(gpu, REG_AXXX_CP_RB_RPTR);
@@ -581,7 +615,7 @@ const struct adreno_gpu_funcs a3xx_gpu_funcs = {
.get_param = adreno_get_param,
.set_param = adreno_set_param,
.hw_init = a3xx_hw_init,
- .pm_suspend = msm_gpu_pm_suspend,
+ .pm_suspend = a3xx_pm_suspend,
.pm_resume = msm_gpu_pm_resume,
.recover = a3xx_recover,
.submit = a3xx_submit,
diff --git a/drivers/gpu/drm/msm/registers/adreno/a3xx.xml b/drivers/gpu/drm/msm/registers/adreno/a3xx.xml
index 09c9606fc3e1..21b00a17ef3e 100644
--- a/drivers/gpu/drm/msm/registers/adreno/a3xx.xml
+++ b/drivers/gpu/drm/msm/registers/adreno/a3xx.xml
@@ -1495,6 +1495,8 @@ xsi:schemaLocation="https://gitlab.freedesktop.org/freedreno/ rules-fd.xsd">
+
+