diff mbox

[2/5] drm/vc4: Fix handling of interlaced video modes.

Message ID 1468954741-30993-3-git-send-email-mario.kleiner.de@gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Mario Kleiner July 19, 2016, 6:58 p.m. UTC
We must not apply CRTC_INTERLACE_HALVE_V to interlaced modes during
mode enumeration, as drm_helper_probe_single_connector_modes
does, so wrap it and reset the effect of CRTC_INTERLACE_HALVE_V
on affected interlaced modes.

Also mode_fixup interlaced modes passed in from user space.

This fixes the vblank timestamping constants and entries in
the mode->crtc_xxx fields needed for precise vblank timestamping.

Signed-off-by: Mario Kleiner <mario.kleiner.de@gmail.com>
Cc: Eric Anholt <eric@anholt.net>
---
 drivers/gpu/drm/vc4/vc4_crtc.c | 18 ++++++++++++++++++
 drivers/gpu/drm/vc4/vc4_hdmi.c | 29 +++++++++++++++++++++++++++--
 2 files changed, 45 insertions(+), 2 deletions(-)
diff mbox

Patch

diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c
index 8fc2b73..a479d3d 100644
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
@@ -532,6 +532,23 @@  static void vc4_crtc_enable(struct drm_crtc *crtc)
 		   CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
 }
 
+static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
+				const struct drm_display_mode *mode,
+				struct drm_display_mode *adjusted_mode)
+{
+	/*
+	 * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
+	 * coming from user space. We don't want this, as it screws up
+	 * vblank timestamping, so fix it up.
+	 */
+	drm_mode_set_crtcinfo(adjusted_mode, 0);
+
+	DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
+	drm_mode_debug_printmodeline(adjusted_mode);
+
+	return true;
+}
+
 static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
 				 struct drm_crtc_state *state)
 {
@@ -819,6 +836,7 @@  static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
 	.mode_set_nofb = vc4_crtc_mode_set_nofb,
 	.disable = vc4_crtc_disable,
 	.enable = vc4_crtc_enable,
+	.mode_fixup = vc4_crtc_mode_fixup,
 	.atomic_check = vc4_crtc_atomic_check,
 	.atomic_flush = vc4_crtc_atomic_flush,
 };
diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c
index 4452f36..68ad106 100644
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
@@ -208,10 +208,35 @@  static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
 	return ret;
 }
 
+/*
+ * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
+ * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
+ * screws up vblank timestamping for interlaced modes, so fix it up.
+ */
+static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
+					  uint32_t maxX, uint32_t maxY)
+{
+	struct drm_display_mode *mode;
+	int count;
+
+	count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
+	if (count == 0)
+		return 0;
+
+	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
+		      connector->base.id, connector->name);
+	list_for_each_entry(mode, &connector->modes, head) {
+		drm_mode_set_crtcinfo(mode, 0);
+		drm_mode_debug_printmodeline(mode);
+	}
+
+	return count;
+}
+
 static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
 	.dpms = drm_atomic_helper_connector_dpms,
 	.detect = vc4_hdmi_connector_detect,
-	.fill_modes = drm_helper_probe_single_connector_modes,
+	.fill_modes = vc4_hdmi_connector_probe_modes,
 	.destroy = vc4_hdmi_connector_destroy,
 	.reset = drm_atomic_helper_connector_reset,
 	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
@@ -246,7 +271,7 @@  static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
 	connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
 			     DRM_CONNECTOR_POLL_DISCONNECT);
 
-	connector->interlace_allowed = 0;
+	connector->interlace_allowed = 1;
 	connector->doublescan_allowed = 0;
 
 	drm_mode_connector_attach_encoder(connector, encoder);