summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c22
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.h1
2 files changed, 21 insertions, 2 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index 8948ab07ff36..57aa177ac348 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -599,7 +599,7 @@ static void etnaviv_gpu_hw_init(struct etnaviv_gpu *gpu)
int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
{
- int ret, i;
+ int ret, i, try;
struct iommu_domain *iommu;
enum etnaviv_iommu_version version;
bool mmuv2;
@@ -642,7 +642,20 @@ int etnaviv_gpu_init(struct etnaviv_gpu *gpu)
gpu->memory_base = dma_mask - SZ_2G + 1;
}
- ret = etnaviv_hw_reset(gpu);
+ for (try = 0; try < 2; try++) {
+ ret = etnaviv_hw_reset(gpu);
+ if (ret == 0)
+ break;
+
+ dev_warn(gpu->dev, "GPU failed to reset, trying to power cycle\n");
+ gpu->force_rpm_idle = true;
+ pm_runtime_put_sync(gpu->dev);
+ msleep(100);
+ ret = pm_runtime_get_sync(gpu->dev);
+ gpu->force_rpm_idle = false;
+ if (ret)
+ break;
+ }
if (ret)
goto fail;
@@ -1798,6 +1811,11 @@ static int __maybe_unused etnaviv_gpu_rpm_suspend(struct device *dev)
{
struct etnaviv_gpu *gpu = dev_get_drvdata(dev);
+ if (gpu->force_rpm_idle) {
+ etnaviv_gpu_clk_disable(gpu);
+ return 0;
+ }
+
/* If we have outstanding fences, we're not idle */
if (gpu->completed_fence != gpu->active_fence)
return -EBUSY;
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
index 1332802aa831..f36c75ed3470 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.h
@@ -101,6 +101,7 @@ struct etnaviv_gpu {
struct mutex lock;
struct etnaviv_chip_identity identity;
struct etnaviv_file_private *lastctx;
+ bool force_rpm_idle;
bool switch_context;
/* 'ring'-buffer: */