57bf058
From 9db79f3a51c97e0cfcde1b25299e8db9ee3d64ab Mon Sep 17 00:00:00 2001
57bf058
From: Eric Anholt <eric@anholt.net>
57bf058
Date: Wed, 14 Sep 2016 19:21:29 +0100
57bf058
Subject: [PATCH 1/4] drm/vc4: Fall back to using an EDID probe in the absence
57bf058
 of a GPIO.
57bf058
57bf058
On Pi0/1/2, we use an external GPIO line for hotplug detection, since
57bf058
the HDMI_HOTPLUG register isn't connected to anything.  However, with
57bf058
the Pi3 the HPD GPIO line has moved off to a GPIO expander that will
57bf058
be tricky to get to (the firmware is constantly polling the expander
57bf058
using i2c0, so we'll need to coordinate with it).
57bf058
57bf058
As a stop-gap, if we don't have a GPIO line, use an EDID probe to
57bf058
detect connection.  Fixes HDMI display on the pi3.
57bf058
57bf058
Signed-off-by: Eric Anholt <eric@anholt.net>
57bf058
---
57bf058
 drivers/gpu/drm/vc4/vc4_hdmi.c | 3 +++
57bf058
 1 file changed, 3 insertions(+)
57bf058
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
index 4452f36..5adc0c7 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
@@ -174,6 +174,9 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
57bf058
 			return connector_status_disconnected;
57bf058
 	}
57bf058
 
57bf058
+	if (drm_probe_ddc(vc4->hdmi->ddc))
57bf058
+		return connector_status_connected;
57bf058
+
57bf058
 	if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
57bf058
 		return connector_status_connected;
57bf058
 	else
57bf058
-- 
57bf058
2.9.3
57bf058
57bf058
From 7b4c39f34fbbdfe0cd0e626686ee01ab96601598 Mon Sep 17 00:00:00 2001
57bf058
From: Eric Anholt <eric@anholt.net>
57bf058
Date: Fri, 16 Sep 2016 10:59:45 +0100
57bf058
Subject: [PATCH 2/4] drm/vc4: Enable limited range RGB output on HDMI with CEA
57bf058
 modes.
57bf058
57bf058
Fixes broken grayscale ramps on many HDMI monitors, where large areas
57bf058
at the ends of the ramp would all appear as black or white.
57bf058
57bf058
Signed-off-by: Eric Anholt <eric@anholt.net>
57bf058
---
57bf058
 drivers/gpu/drm/vc4/vc4_hdmi.c | 31 +++++++++++++++++++++++++++++--
57bf058
 drivers/gpu/drm/vc4/vc4_regs.h |  9 ++++++++-
57bf058
 2 files changed, 37 insertions(+), 3 deletions(-)
57bf058
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
index 5adc0c7..5df4e74 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
@@ -276,6 +276,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 				      struct drm_display_mode *unadjusted_mode,
57bf058
 				      struct drm_display_mode *mode)
57bf058
 {
57bf058
+	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
57bf058
 	struct drm_device *dev = encoder->dev;
57bf058
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
57bf058
 	bool debug_dump_regs = false;
57bf058
@@ -291,6 +292,7 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 	u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
57bf058
 		     VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
57bf058
 				   VC4_HDMI_VERTB_VBP));
57bf058
+	u32 csc_ctl;
57bf058
 
57bf058
 	if (debug_dump_regs) {
57bf058
 		DRM_INFO("HDMI regs before:\n");
57bf058
@@ -329,9 +331,34 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 		 (vsync_pos ? 0 : VC4_HD_VID_CTL_VSYNC_LOW) |
57bf058
 		 (hsync_pos ? 0 : VC4_HD_VID_CTL_HSYNC_LOW));
57bf058
 
57bf058
+	csc_ctl = VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
57bf058
+				VC4_HD_CSC_CTL_ORDER);
57bf058
+
57bf058
+	if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
57bf058
+		/* CEA VICs other than #1 requre limited range RGB
57bf058
+		 * output.  Apply a colorspace conversion to squash
57bf058
+		 * 0-255 down to 16-235.  The matrix here is:
57bf058
+		 *
57bf058
+		 * [ 0      0      0.8594 16]
57bf058
+		 * [ 0      0.8594 0      16]
57bf058
+		 * [ 0.8594 0      0      16]
57bf058
+		 * [ 0      0      0       1]
57bf058
+		 */
57bf058
+		csc_ctl |= VC4_HD_CSC_CTL_ENABLE;
57bf058
+		csc_ctl |= VC4_HD_CSC_CTL_RGB2YCC;
57bf058
+		csc_ctl |= VC4_SET_FIELD(VC4_HD_CSC_CTL_MODE_CUSTOM,
57bf058
+					 VC4_HD_CSC_CTL_MODE);
57bf058
+
57bf058
+		HD_WRITE(VC4_HD_CSC_12_11, (0x000 << 16) | 0x000);
57bf058
+		HD_WRITE(VC4_HD_CSC_14_13, (0x100 << 16) | 0x6e0);
57bf058
+		HD_WRITE(VC4_HD_CSC_22_21, (0x6e0 << 16) | 0x000);
57bf058
+		HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
57bf058
+		HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
57bf058
+		HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
57bf058
+	}
57bf058
+
57bf058
 	/* The RGB order applies even when CSC is disabled. */
57bf058
-	HD_WRITE(VC4_HD_CSC_CTL, VC4_SET_FIELD(VC4_HD_CSC_CTL_ORDER_BGR,
57bf058
-					       VC4_HD_CSC_CTL_ORDER));
57bf058
+	HD_WRITE(VC4_HD_CSC_CTL, csc_ctl);
57bf058
 
57bf058
 	HDMI_WRITE(VC4_HDMI_FIFO_CTL, VC4_HDMI_FIFO_CTL_MASTER_SLAVE_N);
57bf058
 
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
index 160942a..9ecd6ff 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
@@ -528,10 +528,17 @@
57bf058
 # define VC4_HD_CSC_CTL_MODE_SHIFT		2
57bf058
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_SD_YPRPB	0
57bf058
 # define VC4_HD_CSC_CTL_MODE_RGB_TO_HD_YPRPB	1
57bf058
-# define VC4_HD_CSC_CTL_MODE_CUSTOM		2
57bf058
+# define VC4_HD_CSC_CTL_MODE_CUSTOM		3
57bf058
 # define VC4_HD_CSC_CTL_RGB2YCC			BIT(1)
57bf058
 # define VC4_HD_CSC_CTL_ENABLE			BIT(0)
57bf058
 
57bf058
+#define VC4_HD_CSC_12_11			0x044
57bf058
+#define VC4_HD_CSC_14_13			0x048
57bf058
+#define VC4_HD_CSC_22_21			0x04c
57bf058
+#define VC4_HD_CSC_24_23			0x050
57bf058
+#define VC4_HD_CSC_32_31			0x054
57bf058
+#define VC4_HD_CSC_34_33			0x058
57bf058
+
57bf058
 #define VC4_HD_FRAME_COUNT			0x068
57bf058
 
57bf058
 /* HVS display list information. */
57bf058
-- 
57bf058
2.9.3
57bf058
57bf058
From 107d3188b3723840deddaa5efeffcaf167e462f2 Mon Sep 17 00:00:00 2001
57bf058
From: Eric Anholt <eric@anholt.net>
57bf058
Date: Wed, 28 Sep 2016 08:42:42 -0700
57bf058
Subject: [PATCH 3/4] drm/vc4: Fix races when the CS reads from render targets.
57bf058
57bf058
With the introduction of bin/render pipelining, the previous job may
57bf058
not be completed when we start binning the next one.  If the previous
57bf058
job wrote our VBO, IB, or CS textures, then the binning stage might
57bf058
get stale or uninitialized results.
57bf058
57bf058
Fixes the major rendering failure in glmark2 -b terrain.
57bf058
57bf058
Signed-off-by: Eric Anholt <eric@anholt.net>
57bf058
Fixes: ca26d28bbaa3 ("drm/vc4: improve throughput by pipelining binning and rendering jobs")
57bf058
Cc: stable@vger.kernel.org
57bf058
---
57bf058
 drivers/gpu/drm/vc4/vc4_drv.h       | 19 ++++++++++++++++++-
57bf058
 drivers/gpu/drm/vc4/vc4_gem.c       | 13 +++++++++++++
57bf058
 drivers/gpu/drm/vc4/vc4_render_cl.c | 21 +++++++++++++++++----
57bf058
 drivers/gpu/drm/vc4/vc4_validate.c  | 17 ++++++++++++++---
57bf058
 4 files changed, 62 insertions(+), 8 deletions(-)
57bf058
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_drv.h b/drivers/gpu/drm/vc4/vc4_drv.h
57bf058
index 428e249..f696b75 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_drv.h
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_drv.h
57bf058
@@ -122,9 +122,16 @@ to_vc4_dev(struct drm_device *dev)
57bf058
 struct vc4_bo {
57bf058
 	struct drm_gem_cma_object base;
57bf058
 
57bf058
-	/* seqno of the last job to render to this BO. */
57bf058
+	/* seqno of the last job to render using this BO. */
57bf058
 	uint64_t seqno;
57bf058
 
57bf058
+	/* seqno of the last job to use the RCL to write to this BO.
57bf058
+	 *
57bf058
+	 * Note that this doesn't include binner overflow memory
57bf058
+	 * writes.
57bf058
+	 */
57bf058
+	uint64_t write_seqno;
57bf058
+
57bf058
 	/* List entry for the BO's position in either
57bf058
 	 * vc4_exec_info->unref_list or vc4_dev->bo_cache.time_list
57bf058
 	 */
57bf058
@@ -216,6 +223,9 @@ struct vc4_exec_info {
57bf058
 	/* Sequence number for this bin/render job. */
57bf058
 	uint64_t seqno;
57bf058
 
57bf058
+	/* Latest write_seqno of any BO that binning depends on. */
57bf058
+	uint64_t bin_dep_seqno;
57bf058
+
57bf058
 	/* Last current addresses the hardware was processing when the
57bf058
 	 * hangcheck timer checked on us.
57bf058
 	 */
57bf058
@@ -230,6 +240,13 @@ struct vc4_exec_info {
57bf058
 	struct drm_gem_cma_object **bo;
57bf058
 	uint32_t bo_count;
57bf058
 
57bf058
+	/* List of BOs that are being written by the RCL.  Other than
57bf058
+	 * the binner temporary storage, this is all the BOs written
57bf058
+	 * by the job.
57bf058
+	 */
57bf058
+	struct drm_gem_cma_object *rcl_write_bo[4];
57bf058
+	uint32_t rcl_write_bo_count;
57bf058
+
57bf058
 	/* Pointers for our position in vc4->job_list */
57bf058
 	struct list_head head;
57bf058
 
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c
57bf058
index b262c5c..ae1609e 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_gem.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_gem.c
57bf058
@@ -471,6 +471,11 @@ vc4_update_bo_seqnos(struct vc4_exec_info *exec, uint64_t seqno)
57bf058
 	list_for_each_entry(bo, &exec->unref_list, unref_head) {
57bf058
 		bo->seqno = seqno;
57bf058
 	}
57bf058
+
57bf058
+	for (i = 0; i < exec->rcl_write_bo_count; i++) {
57bf058
+		bo = to_vc4_bo(&exec->rcl_write_bo[i]->base);
57bf058
+		bo->write_seqno = seqno;
57bf058
+	}
57bf058
 }
57bf058
 
57bf058
 /* Queues a struct vc4_exec_info for execution.  If no job is
57bf058
@@ -673,6 +678,14 @@ vc4_get_bcl(struct drm_device *dev, struct vc4_exec_info *exec)
57bf058
 		goto fail;
57bf058
 
57bf058
 	ret = vc4_validate_shader_recs(dev, exec);
57bf058
+	if (ret)
57bf058
+		goto fail;
57bf058
+
57bf058
+	/* Block waiting on any previous rendering into the CS's VBO,
57bf058
+	 * IB, or textures, so that pixels are actually written by the
57bf058
+	 * time we try to read them.
57bf058
+	 */
57bf058
+	ret = vc4_wait_for_seqno(dev, exec->bin_dep_seqno, ~0ull, true);
57bf058
 
57bf058
 fail:
57bf058
 	drm_free_large(temp);
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_render_cl.c b/drivers/gpu/drm/vc4/vc4_render_cl.c
57bf058
index 0f12418..08886a3 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_render_cl.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_render_cl.c
57bf058
@@ -45,6 +45,8 @@ struct vc4_rcl_setup {
57bf058
 
57bf058
 	struct drm_gem_cma_object *rcl;
57bf058
 	u32 next_offset;
57bf058
+
57bf058
+	u32 next_write_bo_index;
57bf058
 };
57bf058
 
57bf058
 static inline void rcl_u8(struct vc4_rcl_setup *setup, u8 val)
57bf058
@@ -407,6 +409,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
57bf058
 	if (!*obj)
57bf058
 		return -EINVAL;
57bf058
 
57bf058
+	exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
57bf058
+
57bf058
 	if (surf->offset & 0xf) {
57bf058
 		DRM_ERROR("MSAA write must be 16b aligned.\n");
57bf058
 		return -EINVAL;
57bf058
@@ -417,7 +421,8 @@ static int vc4_rcl_msaa_surface_setup(struct vc4_exec_info *exec,
57bf058
 
57bf058
 static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
57bf058
 				 struct drm_gem_cma_object **obj,
57bf058
-				 struct drm_vc4_submit_rcl_surface *surf)
57bf058
+				 struct drm_vc4_submit_rcl_surface *surf,
57bf058
+				 bool is_write)
57bf058
 {
57bf058
 	uint8_t tiling = VC4_GET_FIELD(surf->bits,
57bf058
 				       VC4_LOADSTORE_TILE_BUFFER_TILING);
57bf058
@@ -440,6 +445,9 @@ static int vc4_rcl_surface_setup(struct vc4_exec_info *exec,
57bf058
 	if (!*obj)
57bf058
 		return -EINVAL;
57bf058
 
57bf058
+	if (is_write)
57bf058
+		exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
57bf058
+
57bf058
 	if (surf->flags & VC4_SUBMIT_RCL_SURFACE_READ_IS_FULL_RES) {
57bf058
 		if (surf == &exec->args->zs_write) {
57bf058
 			DRM_ERROR("general zs write may not be a full-res.\n");
57bf058
@@ -542,6 +550,8 @@ vc4_rcl_render_config_surface_setup(struct vc4_exec_info *exec,
57bf058
 	if (!*obj)
57bf058
 		return -EINVAL;
57bf058
 
57bf058
+	exec->rcl_write_bo[exec->rcl_write_bo_count++] = *obj;
57bf058
+
57bf058
 	if (tiling > VC4_TILING_FORMAT_LT) {
57bf058
 		DRM_ERROR("Bad tiling format\n");
57bf058
 		return -EINVAL;
57bf058
@@ -599,15 +609,18 @@ int vc4_get_rcl(struct drm_device *dev, struct vc4_exec_info *exec)
57bf058
 	if (ret)
57bf058
 		return ret;
57bf058
 
57bf058
-	ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read);
57bf058
+	ret = vc4_rcl_surface_setup(exec, &setup.color_read, &args->color_read,
57bf058
+				    false);
57bf058
 	if (ret)
57bf058
 		return ret;
57bf058
 
57bf058
-	ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read);
57bf058
+	ret = vc4_rcl_surface_setup(exec, &setup.zs_read, &args->zs_read,
57bf058
+				    false);
57bf058
 	if (ret)
57bf058
 		return ret;
57bf058
 
57bf058
-	ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write);
57bf058
+	ret = vc4_rcl_surface_setup(exec, &setup.zs_write, &args->zs_write,
57bf058
+				    true);
57bf058
 	if (ret)
57bf058
 		return ret;
57bf058
 
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_validate.c b/drivers/gpu/drm/vc4/vc4_validate.c
57bf058
index 9ce1d0a..26503e3 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_validate.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_validate.c
57bf058
@@ -267,6 +267,9 @@ validate_indexed_prim_list(VALIDATE_ARGS)
57bf058
 	if (!ib)
57bf058
 		return -EINVAL;
57bf058
 
57bf058
+	exec->bin_dep_seqno = max(exec->bin_dep_seqno,
57bf058
+				  to_vc4_bo(&ib->base)->write_seqno);
57bf058
+
57bf058
 	if (offset > ib->base.size ||
57bf058
 	    (ib->base.size - offset) / index_size < length) {
57bf058
 		DRM_ERROR("IB access overflow (%d + %d*%d > %zd)\n",
57bf058
@@ -555,8 +558,7 @@ static bool
57bf058
 reloc_tex(struct vc4_exec_info *exec,
57bf058
 	  void *uniform_data_u,
57bf058
 	  struct vc4_texture_sample_info *sample,
57bf058
-	  uint32_t texture_handle_index)
57bf058
-
57bf058
+	  uint32_t texture_handle_index, bool is_cs)
57bf058
 {
57bf058
 	struct drm_gem_cma_object *tex;
57bf058
 	uint32_t p0 = *(uint32_t *)(uniform_data_u + sample->p_offset[0]);
57bf058
@@ -714,6 +716,11 @@ reloc_tex(struct vc4_exec_info *exec,
57bf058
 
57bf058
 	*validated_p0 = tex->paddr + p0;
57bf058
 
57bf058
+	if (is_cs) {
57bf058
+		exec->bin_dep_seqno = max(exec->bin_dep_seqno,
57bf058
+					  to_vc4_bo(&tex->base)->write_seqno);
57bf058
+	}
57bf058
+
57bf058
 	return true;
57bf058
  fail:
57bf058
 	DRM_INFO("Texture p0 at %d: 0x%08x\n", sample->p_offset[0], p0);
57bf058
@@ -835,7 +842,8 @@ validate_gl_shader_rec(struct drm_device *dev,
57bf058
 			if (!reloc_tex(exec,
57bf058
 				       uniform_data_u,
57bf058
 				       &validated_shader->texture_samples[tex],
57bf058
-				       texture_handles_u[tex])) {
57bf058
+				       texture_handles_u[tex],
57bf058
+				       i == 2)) {
57bf058
 				return -EINVAL;
57bf058
 			}
57bf058
 		}
57bf058
@@ -867,6 +875,9 @@ validate_gl_shader_rec(struct drm_device *dev,
57bf058
 		uint32_t stride = *(uint8_t *)(pkt_u + o + 5);
57bf058
 		uint32_t max_index;
57bf058
 
57bf058
+		exec->bin_dep_seqno = max(exec->bin_dep_seqno,
57bf058
+					  to_vc4_bo(&vbo->base)->write_seqno);
57bf058
+
57bf058
 		if (state->addr & 0x8)
57bf058
 			stride |= (*(uint32_t *)(pkt_u + 100 + i * 4)) & ~0xff;
57bf058
 
57bf058
-- 
57bf058
2.9.3
57bf058
57bf058
From f379f5432e4b74e3d1d894ce2fefbe1b8a3c24fd Mon Sep 17 00:00:00 2001
57bf058
From: Eric Anholt <eric@anholt.net>
57bf058
Date: Wed, 28 Sep 2016 19:20:44 -0700
57bf058
Subject: [PATCH 4/4] drm/vc4: Increase timeout for HDMI_SCHEDULER_CONTROL
57bf058
 changes.
57bf058
57bf058
Fixes occasional debug spew at boot when connected directly through
57bf058
HDMI, and probably confusing the HDMI state machine when we go trying
57bf058
to poke registers for the enable sequence too soon.
57bf058
57bf058
Signed-off-by: Eric Anholt <eric@anholt.net>
57bf058
---
57bf058
 drivers/gpu/drm/vc4/vc4_hdmi.c | 4 ++--
57bf058
 1 file changed, 2 insertions(+), 2 deletions(-)
57bf058
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
index 5df4e74..9a6883d 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
@@ -399,7 +399,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
57bf058
 			   VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
57bf058
 
57bf058
 		ret = wait_for(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
57bf058
-			       VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1);
57bf058
+			       VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE, 1000);
57bf058
 		WARN_ONCE(ret, "Timeout waiting for "
57bf058
 			  "VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
57bf058
 	} else {
57bf058
@@ -411,7 +411,7 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
57bf058
 			   ~VC4_HDMI_SCHEDULER_CONTROL_MODE_HDMI);
57bf058
 
57bf058
 		ret = wait_for(!(HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) &
57bf058
-				 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1);
57bf058
+				 VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE), 1000);
57bf058
 		WARN_ONCE(ret, "Timeout waiting for "
57bf058
 			  "!VC4_HDMI_SCHEDULER_CONTROL_HDMI_ACTIVE\n");
57bf058
 	}
57bf058
-- 
57bf058
2.9.3
57bf058
57bf058
From bd712d14886c37eb804036b2ac3036df79d33476 Mon Sep 17 00:00:00 2001
57bf058
From: Eric Anholt <eric@anholt.net>
57bf058
Date: Thu, 29 Sep 2016 15:34:43 -0700
57bf058
Subject: [PATCH] drm/vc4: Set up the AVI and SPD infoframes.
57bf058
57bf058
Fixes a purple bar on the left side of the screen with my Dell
57bf058
2408WFP.  It will also be required for supporting the double-clocked
57bf058
video modes.
57bf058
57bf058
Signed-off-by: Eric Anholt <eric@anholt.net>
57bf058
---
57bf058
 drivers/gpu/drm/vc4/vc4_hdmi.c | 136 +++++++++++++++++++++++++++++++++++++++--
57bf058
 drivers/gpu/drm/vc4/vc4_regs.h |   5 ++
57bf058
 2 files changed, 136 insertions(+), 5 deletions(-)
57bf058
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
index 9a6883d..f722334 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
57bf058
@@ -62,6 +62,8 @@ struct vc4_hdmi {
57bf058
 struct vc4_hdmi_encoder {
57bf058
 	struct vc4_encoder base;
57bf058
 	bool hdmi_monitor;
57bf058
+	bool limited_rgb_range;
57bf058
+	bool rgb_range_selectable;
57bf058
 };
57bf058
 
57bf058
 static inline struct vc4_hdmi_encoder *
57bf058
@@ -205,6 +207,12 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
57bf058
 		return -ENODEV;
57bf058
 
57bf058
 	vc4_encoder->hdmi_monitor = drm_detect_hdmi_monitor(edid);
57bf058
+
57bf058
+	if (edid && edid->input & DRM_EDID_INPUT_DIGITAL) {
57bf058
+		vc4_encoder->rgb_range_selectable =
57bf058
+			drm_rgb_quant_range_selectable(edid);
57bf058
+	}
57bf058
+
57bf058
 	drm_mode_connector_update_edid_property(connector, edid);
57bf058
 	ret = drm_add_edid_modes(connector, edid);
57bf058
 
57bf058
@@ -272,6 +280,117 @@ static const struct drm_encoder_funcs vc4_hdmi_encoder_funcs = {
57bf058
 	.destroy = vc4_hdmi_encoder_destroy,
57bf058
 };
57bf058
 
57bf058
+static int vc4_hdmi_stop_packet(struct drm_encoder *encoder,
57bf058
+				enum hdmi_infoframe_type type)
57bf058
+{
57bf058
+	struct drm_device *dev = encoder->dev;
57bf058
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
57bf058
+	u32 packet_id = type - 0x80;
57bf058
+
57bf058
+	HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
57bf058
+		   HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) & ~BIT(packet_id));
57bf058
+
57bf058
+	return wait_for(!(HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
57bf058
+			  BIT(packet_id)), 100);
57bf058
+}
57bf058
+
57bf058
+static void vc4_hdmi_write_infoframe(struct drm_encoder *encoder,
57bf058
+				     union hdmi_infoframe *frame)
57bf058
+{
57bf058
+	struct drm_device *dev = encoder->dev;
57bf058
+	struct vc4_dev *vc4 = to_vc4_dev(dev);
57bf058
+	u32 packet_id = frame->any.type - 0x80;
57bf058
+	u32 packet_reg = VC4_HDMI_GCP_0 + VC4_HDMI_PACKET_STRIDE * packet_id;
57bf058
+	uint8_t buffer[VC4_HDMI_PACKET_STRIDE];
57bf058
+	ssize_t len, i;
57bf058
+	int ret;
57bf058
+
57bf058
+	WARN_ONCE(!(HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) &
57bf058
+		    VC4_HDMI_RAM_PACKET_ENABLE),
57bf058
+		  "Packet RAM has to be on to store the packet.");
57bf058
+
57bf058
+	len = hdmi_infoframe_pack(frame, buffer, sizeof(buffer));
57bf058
+	if (len < 0)
57bf058
+		return;
57bf058
+
57bf058
+	ret = vc4_hdmi_stop_packet(encoder, frame->any.type);
57bf058
+	if (ret) {
57bf058
+		DRM_ERROR("Failed to wait for infoframe to go idle: %d\n", ret);
57bf058
+		return;
57bf058
+	}
57bf058
+
57bf058
+	for (i = 0; i < len; i += 7) {
57bf058
+		HDMI_WRITE(packet_reg,
57bf058
+			   buffer[i + 0] << 0 |
57bf058
+			   buffer[i + 1] << 8 |
57bf058
+			   buffer[i + 2] << 16);
57bf058
+		packet_reg += 4;
57bf058
+
57bf058
+		HDMI_WRITE(packet_reg,
57bf058
+			   buffer[i + 3] << 0 |
57bf058
+			   buffer[i + 4] << 8 |
57bf058
+			   buffer[i + 5] << 16 |
57bf058
+			   buffer[i + 6] << 24);
57bf058
+		packet_reg += 4;
57bf058
+	}
57bf058
+
57bf058
+	HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
57bf058
+		   HDMI_READ(VC4_HDMI_RAM_PACKET_CONFIG) | BIT(packet_id));
57bf058
+	ret = wait_for((HDMI_READ(VC4_HDMI_RAM_PACKET_STATUS) &
57bf058
+			BIT(packet_id)), 100);
57bf058
+	if (ret)
57bf058
+		DRM_ERROR("Failed to wait for infoframe to start: %d\n", ret);
57bf058
+}
57bf058
+
57bf058
+static void vc4_hdmi_set_avi_infoframe(struct drm_encoder *encoder)
57bf058
+{
57bf058
+	struct vc4_hdmi_encoder *vc4_encoder = to_vc4_hdmi_encoder(encoder);
57bf058
+	struct drm_crtc *crtc = encoder->crtc;
57bf058
+	const struct drm_display_mode *mode = &crtc->state->adjusted_mode;
57bf058
+	union hdmi_infoframe frame;
57bf058
+	int ret;
57bf058
+
57bf058
+	ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
57bf058
+	if (ret < 0) {
57bf058
+		DRM_ERROR("couldn't fill AVI infoframe\n");
57bf058
+		return;
57bf058
+	}
57bf058
+
57bf058
+	if (vc4_encoder->rgb_range_selectable) {
57bf058
+		if (vc4_encoder->limited_rgb_range) {
57bf058
+			frame.avi.quantization_range =
57bf058
+				HDMI_QUANTIZATION_RANGE_LIMITED;
57bf058
+		} else {
57bf058
+			frame.avi.quantization_range =
57bf058
+				HDMI_QUANTIZATION_RANGE_FULL;
57bf058
+		}
57bf058
+	}
57bf058
+
57bf058
+	vc4_hdmi_write_infoframe(encoder, &frame);
57bf058
+}
57bf058
+
57bf058
+static void vc4_hdmi_set_spd_infoframe(struct drm_encoder *encoder)
57bf058
+{
57bf058
+	union hdmi_infoframe frame;
57bf058
+	int ret;
57bf058
+
57bf058
+	ret = hdmi_spd_infoframe_init(&frame.spd, "Broadcom", "Videocore");
57bf058
+	if (ret < 0) {
57bf058
+		DRM_ERROR("couldn't fill SPD infoframe\n");
57bf058
+		return;
57bf058
+	}
57bf058
+
57bf058
+	frame.spd.sdi = HDMI_SPD_SDI_PC;
57bf058
+
57bf058
+	vc4_hdmi_write_infoframe(encoder, &frame);
57bf058
+}
57bf058
+
57bf058
+static void vc4_hdmi_set_infoframes(struct drm_encoder *encoder)
57bf058
+{
57bf058
+	vc4_hdmi_set_avi_infoframe(encoder);
57bf058
+	vc4_hdmi_set_spd_infoframe(encoder);
57bf058
+}
57bf058
+
57bf058
 static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 				      struct drm_display_mode *unadjusted_mode,
57bf058
 				      struct drm_display_mode *mode)
57bf058
@@ -336,8 +455,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 
57bf058
 	if (vc4_encoder->hdmi_monitor && drm_match_cea_mode(mode) > 1) {
57bf058
 		/* CEA VICs other than #1 requre limited range RGB
57bf058
-		 * output.  Apply a colorspace conversion to squash
57bf058
-		 * 0-255 down to 16-235.  The matrix here is:
57bf058
+		 * output unless overridden by an AVI infoframe.
57bf058
+		 * Apply a colorspace conversion to squash 0-255 down
57bf058
+		 * to 16-235.  The matrix here is:
57bf058
 		 *
57bf058
 		 * [ 0      0      0.8594 16]
57bf058
 		 * [ 0      0.8594 0      16]
57bf058
@@ -355,6 +475,9 @@ static void vc4_hdmi_encoder_mode_set(struct drm_encoder *encoder,
57bf058
 		HD_WRITE(VC4_HD_CSC_24_23, (0x100 << 16) | 0x000);
57bf058
 		HD_WRITE(VC4_HD_CSC_32_31, (0x000 << 16) | 0x6e0);
57bf058
 		HD_WRITE(VC4_HD_CSC_34_33, (0x100 << 16) | 0x000);
57bf058
+		vc4_encoder->limited_rgb_range = true;
57bf058
+	} else {
57bf058
+		vc4_encoder->limited_rgb_range = false;
57bf058
 	}
57bf058
 
57bf058
 	/* The RGB order applies even when CSC is disabled. */
57bf058
@@ -373,6 +496,8 @@ static void vc4_hdmi_encoder_disable(struct drm_encoder *encoder)
57bf058
 	struct drm_device *dev = encoder->dev;
57bf058
 	struct vc4_dev *vc4 = to_vc4_dev(dev);
57bf058
 
57bf058
+	HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG, 0);
57bf058
+
57bf058
 	HDMI_WRITE(VC4_HDMI_TX_PHY_RESET_CTL, 0xf << 16);
57bf058
 	HD_WRITE(VC4_HD_VID_CTL,
57bf058
 		 HD_READ(VC4_HD_VID_CTL) & ~VC4_HD_VID_CTL_ENABLE);
57bf058
@@ -425,9 +550,10 @@ static void vc4_hdmi_encoder_enable(struct drm_encoder *encoder)
57bf058
 			   HDMI_READ(VC4_HDMI_SCHEDULER_CONTROL) |
57bf058
 			   VC4_HDMI_SCHEDULER_CONTROL_VERT_ALWAYS_KEEPOUT);
57bf058
 
57bf058
-		/* XXX: Set HDMI_RAM_PACKET_CONFIG (1 << 16) and set
57bf058
-		 * up the infoframe.
57bf058
-		 */
57bf058
+		HDMI_WRITE(VC4_HDMI_RAM_PACKET_CONFIG,
57bf058
+			   VC4_HDMI_RAM_PACKET_ENABLE);
57bf058
+
57bf058
+		vc4_hdmi_set_infoframes(encoder);
57bf058
 
57bf058
 		drift = HDMI_READ(VC4_HDMI_FIFO_CTL);
57bf058
 		drift &= VC4_HDMI_FIFO_VALID_WRITE_MASK;
57bf058
diff --git a/drivers/gpu/drm/vc4/vc4_regs.h b/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
index 9ecd6ff..a4b5370 100644
57bf058
--- a/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
57bf058
@@ -438,6 +438,8 @@
57bf058
 #define VC4_HDMI_RAM_PACKET_CONFIG		0x0a0
57bf058
 # define VC4_HDMI_RAM_PACKET_ENABLE		BIT(16)
57bf058
 
57bf058
+#define VC4_HDMI_RAM_PACKET_STATUS		0x0a4
57bf058
+
57bf058
 #define VC4_HDMI_HORZA				0x0c4
57bf058
 # define VC4_HDMI_HORZA_VPOS			BIT(14)
57bf058
 # define VC4_HDMI_HORZA_HPOS			BIT(13)
57bf058
@@ -499,6 +501,9 @@
57bf058
 
57bf058
 #define VC4_HDMI_TX_PHY_RESET_CTL		0x2c0
57bf058
 
57bf058
+#define VC4_HDMI_GCP_0				0x400
57bf058
+#define VC4_HDMI_PACKET_STRIDE			0x24
57bf058
+
57bf058
 #define VC4_HD_M_CTL				0x00c
57bf058
 # define VC4_HD_M_REGISTER_FILE_STANDBY		(3 << 6)
57bf058
 # define VC4_HD_M_RAM_STANDBY			(3 << 4)
57bf058
-- 
57bf058
2.9.3
57bf058