diff --git a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c index 1b44b9e21ad86..b7166a883b018 100644 --- a/drivers/gpu/drm/msm/adreno/a6xx_gmu.c +++ b/drivers/gpu/drm/msm/adreno/a6xx_gmu.c @@ -1250,6 +1250,56 @@ static int a6xx_gmu_secure_init(struct a6xx_gpu *a6xx_gpu) return 0; } +static int a6xx_gmu_gxpd_get(struct a6xx_gmu *gmu) +{ + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + + if (IS_ERR_OR_NULL(gmu->gxpd)) + return 0; + + /* + * On A8xx HW, GX GDSC is moved to a new clk controller block under GX + * power domain. The clock driver for this new block keeps the GX rail + * voted when gxpd is voted. So, use the gxpd only during gpu recovery. + */ + if (adreno_gpu->info->family >= ADRENO_8XX_GEN1) + return 0; + + /* + * On A6x/A7x, "enable" the GX power domain which won't actually do + * anything but it will make sure that the refcounting is correct in + * case we need to bring down the GX after a GMU failure + */ + return pm_runtime_get_sync(gmu->gxpd); +} + +static int a6xx_gmu_gxpd_put(struct a6xx_gmu *gmu) +{ + struct a6xx_gpu *a6xx_gpu = container_of(gmu, struct a6xx_gpu, gmu); + struct adreno_gpu *adreno_gpu = &a6xx_gpu->base; + + if (IS_ERR_OR_NULL(gmu->gxpd)) + return 0; + + if (adreno_gpu->info->family < ADRENO_8XX_GEN1) + return pm_runtime_put_sync(gmu->gxpd); + + /* + * On A8x, GX GDSC collapse should be triggered only when it is stuck ON + */ + if (adreno_gpu->funcs->gx_is_on(adreno_gpu)) { + pm_runtime_get_sync(gmu->gxpd); + /* + * Hint to gfxclkctl driver to do a hw collapse during the next + * RPM PUT. This is a special behavior in the gfxclkctl driver + */ + dev_pm_genpd_synced_poweroff(gmu->gxpd); + pm_runtime_put_sync(gmu->gxpd); + } + + return 0; +} int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) { @@ -1266,13 +1316,7 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) /* Turn on the resources */ pm_runtime_get_sync(gmu->dev); - /* - * "enable" the GX power domain which won't actually do anything but it - * will make sure that the refcounting is correct in case we need to - * bring down the GX after a GMU failure - */ - if (!IS_ERR_OR_NULL(gmu->gxpd)) - pm_runtime_get_sync(gmu->gxpd); + a6xx_gmu_gxpd_get(gmu); /* Use a known rate to bring up the GMU */ clk_set_rate(gmu->core_clk, 200000000); @@ -1339,7 +1383,8 @@ int a6xx_gmu_resume(struct a6xx_gpu *a6xx_gpu) disable_clk: clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); rpm_put: - pm_runtime_put(gmu->gxpd); + a6xx_gmu_gxpd_put(gmu); + pm_runtime_put(gmu->dev); return ret; @@ -1455,8 +1500,7 @@ int a6xx_gmu_stop(struct a6xx_gpu *a6xx_gpu) * domain. Usually the GMU does this but only if the shutdown sequence * was successful */ - if (!IS_ERR_OR_NULL(gmu->gxpd)) - pm_runtime_put_sync(gmu->gxpd); + a6xx_gmu_gxpd_put(gmu); clk_bulk_disable_unprepare(gmu->nr_clocks, gmu->clocks); diff --git a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c index ccfccc45133fd..9b99ec5ceeb58 100644 --- a/drivers/gpu/drm/msm/adreno/a8xx_gpu.c +++ b/drivers/gpu/drm/msm/adreno/a8xx_gpu.c @@ -886,17 +886,22 @@ void a8xx_recover(struct msm_gpu *gpu) adreno_dump_info(gpu); - if (hang_debug) - a8xx_dump(gpu); - /* * To handle recovery specific sequences during the rpm suspend we are * about to trigger */ a6xx_gpu->hung = true; - /* Halt SQE first */ - gpu_write(gpu, REG_A8XX_CP_SQE_CNTL, 3); + 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_A8XX_CP_SQE_CNTL, 3); + + if (hang_debug) + a8xx_dump(gpu); + } pm_runtime_dont_use_autosuspend(&gpu->pdev->dev);