[PATCH RFC 083/111] staging: etnaviv: add support to shutdown and restore the front end

Lucas Stach l.stach at pengutronix.de
Thu Apr 2 08:30:25 PDT 2015


From: Russell King <rmk+kernel at arm.linux.org.uk>

Add support to append an END command to the GPU command stream so we
cleanly shutdown the GPU on driver removal and suspend.  This properly
quiesces the GPU, allowing it to come back up on SoCs such as iMX6.

Signed-off-by: Russell King <rmk+kernel at arm.linux.org.uk>
---
 drivers/staging/etnaviv/etnaviv_buffer.c | 11 +++++++++++
 drivers/staging/etnaviv/etnaviv_drv.h    |  1 +
 drivers/staging/etnaviv/etnaviv_gpu.c    | 29 +++++++++++++++++++++++++++++
 3 files changed, 41 insertions(+)

diff --git a/drivers/staging/etnaviv/etnaviv_buffer.c b/drivers/staging/etnaviv/etnaviv_buffer.c
index 0ce1e4baafa4..17bf6f9abed0 100644
--- a/drivers/staging/etnaviv/etnaviv_buffer.c
+++ b/drivers/staging/etnaviv/etnaviv_buffer.c
@@ -157,6 +157,17 @@ u32 etnaviv_buffer_init(struct etnaviv_gpu *gpu)
 	return buffer->offset;
 }
 
+void etnaviv_buffer_end(struct etnaviv_gpu *gpu)
+{
+	struct etnaviv_gem_object *buffer = to_etnaviv_bo(gpu->buffer);
+
+	/* Replace the last WAIT with an END */
+	buffer->offset -= 4;
+
+	CMD_END(buffer);
+	mb();
+}
+
 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	struct etnaviv_gem_submit *submit)
 {
diff --git a/drivers/staging/etnaviv/etnaviv_drv.h b/drivers/staging/etnaviv/etnaviv_drv.h
index 18b929f9d268..4c848afab876 100644
--- a/drivers/staging/etnaviv/etnaviv_drv.h
+++ b/drivers/staging/etnaviv/etnaviv_drv.h
@@ -111,6 +111,7 @@ struct drm_gem_object *etnaviv_gem_new(struct drm_device *dev,
 int etnaviv_gem_new_userptr(struct drm_device *dev, struct drm_file *file,
 	uintptr_t ptr, uint32_t size, uint32_t flags, uint32_t *handle);
 u32 etnaviv_buffer_init(struct etnaviv_gpu *gpu);
+void etnaviv_buffer_end(struct etnaviv_gpu *gpu);
 void etnaviv_buffer_queue(struct etnaviv_gpu *gpu, unsigned int event,
 	struct etnaviv_gem_submit *submit);
 bool etnaviv_cmd_validate_one(struct etnaviv_gpu *gpu,
diff --git a/drivers/staging/etnaviv/etnaviv_gpu.c b/drivers/staging/etnaviv/etnaviv_gpu.c
index df3210424d09..a22c5ab558a7 100644
--- a/drivers/staging/etnaviv/etnaviv_gpu.c
+++ b/drivers/staging/etnaviv/etnaviv_gpu.c
@@ -942,6 +942,35 @@ static int etnaviv_gpu_suspend(struct etnaviv_gpu *gpu)
 {
 	int ret;
 
+	if (gpu->buffer) {
+		unsigned long timeout;
+
+		/* Replace the last WAIT with END */
+		etnaviv_buffer_end(gpu);
+
+		/*
+		 * We know that only the FE is busy here, this should
+		 * happen quickly (as the WAIT is only 200 cycles).  If
+		 * we fail, just warn and continue.
+		 */
+		timeout = jiffies + msecs_to_jiffies(100);
+		do {
+			u32 idle = gpu_read(gpu, VIVS_HI_IDLE_STATE);
+
+			if ((idle & gpu->idle_mask) == gpu->idle_mask)
+				break;
+
+			if (time_is_before_jiffies(timeout)) {
+				dev_warn(gpu->dev,
+					 "timed out waiting for idle: idle=0x%x\n",
+					 idle);
+				break;
+			}
+
+			udelay(5);
+		} while (1);
+	}
+
 	ret = disable_axi(gpu);
 	if (ret)
 		return ret;
-- 
2.1.4



More information about the dri-devel mailing list