212 lines
7.8 KiB
Diff
212 lines
7.8 KiB
Diff
|
From 6e6624aeedaa97f1b81636e0be4a7478ccb22d69 Mon Sep 17 00:00:00 2001
|
||
|
From: Eric Anholt <eric@anholt.net>
|
||
|
Date: Wed, 28 Sep 2016 17:30:25 -0700
|
||
|
Subject: [PATCH] drm/vc4: Fix support for interlaced modes on HDMI.
|
||
|
|
||
|
We really do need to be using the halved V fields. I had been
|
||
|
confused by the code I was using as a reference because it stored
|
||
|
halved vsync fields but not halved vdisplay, so it looked like I only
|
||
|
needed to divide vdisplay by 2.
|
||
|
|
||
|
This reverts part of Mario's timestamping fixes that prevented
|
||
|
CRTC_HALVE_V from applying, and instead adjusts the timestamping code
|
||
|
to not use the crtc field in that case.
|
||
|
|
||
|
Fixes locking of 1920x1080x60i on my Dell 2408WFP. There are black
|
||
|
bars on the top and bottom, but I suspect that might be an
|
||
|
under/overscan flags problem as opposed to video timings.
|
||
|
|
||
|
Signed-off-by: Eric Anholt <eric@anholt.net>
|
||
|
---
|
||
|
drivers/gpu/drm/vc4/vc4_crtc.c | 54 +++++++++++++++++++++++-------------------
|
||
|
drivers/gpu/drm/vc4/vc4_hdmi.c | 45 ++++++++++-------------------------
|
||
|
drivers/gpu/drm/vc4/vc4_regs.h | 3 +++
|
||
|
3 files changed, 44 insertions(+), 58 deletions(-)
|
||
|
|
||
|
--- a/drivers/gpu/drm/vc4/vc4_crtc.c
|
||
|
+++ b/drivers/gpu/drm/vc4/vc4_crtc.c
|
||
|
@@ -220,7 +220,7 @@ int vc4_crtc_get_scanoutpos(struct drm_d
|
||
|
* and need to make things up in a approximative but consistent way.
|
||
|
*/
|
||
|
ret |= DRM_SCANOUTPOS_IN_VBLANK;
|
||
|
- vblank_lines = mode->crtc_vtotal - mode->crtc_vdisplay;
|
||
|
+ vblank_lines = mode->vtotal - mode->vdisplay;
|
||
|
|
||
|
if (flags & DRM_CALLED_FROM_VBLIRQ) {
|
||
|
/*
|
||
|
@@ -368,7 +368,6 @@ static void vc4_crtc_mode_set_nofb(struc
|
||
|
struct drm_crtc_state *state = crtc->state;
|
||
|
struct drm_display_mode *mode = &state->adjusted_mode;
|
||
|
bool interlace = mode->flags & DRM_MODE_FLAG_INTERLACE;
|
||
|
- u32 vactive = (mode->vdisplay >> (interlace ? 1 : 0));
|
||
|
bool is_dsi = (vc4_encoder->type == VC4_ENCODER_TYPE_DSI0 ||
|
||
|
vc4_encoder->type == VC4_ENCODER_TYPE_DSI1);
|
||
|
u32 format = is_dsi ? PV_CONTROL_FORMAT_DSIV_24 : PV_CONTROL_FORMAT_24;
|
||
|
@@ -395,34 +394,49 @@ static void vc4_crtc_mode_set_nofb(struc
|
||
|
VC4_SET_FIELD(mode->hdisplay, PV_HORZB_HACTIVE));
|
||
|
|
||
|
CRTC_WRITE(PV_VERTA,
|
||
|
- VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
|
||
|
PV_VERTA_VBP) |
|
||
|
- VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
|
||
|
PV_VERTA_VSYNC));
|
||
|
CRTC_WRITE(PV_VERTB,
|
||
|
- VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
|
||
|
PV_VERTB_VFP) |
|
||
|
- VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
|
||
|
+ VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
|
||
|
|
||
|
if (interlace) {
|
||
|
CRTC_WRITE(PV_VERTA_EVEN,
|
||
|
- VC4_SET_FIELD(mode->vtotal - mode->vsync_end - 1,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vtotal -
|
||
|
+ mode->crtc_vsync_end - 1,
|
||
|
PV_VERTA_VBP) |
|
||
|
- VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vsync_end -
|
||
|
+ mode->crtc_vsync_start,
|
||
|
PV_VERTA_VSYNC));
|
||
|
CRTC_WRITE(PV_VERTB_EVEN,
|
||
|
- VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vsync_start -
|
||
|
+ mode->crtc_vdisplay,
|
||
|
PV_VERTB_VFP) |
|
||
|
- VC4_SET_FIELD(vactive, PV_VERTB_VACTIVE));
|
||
|
+ VC4_SET_FIELD(mode->crtc_vdisplay, PV_VERTB_VACTIVE));
|
||
|
+
|
||
|
+ /* We set up first field even mode for HDMI. VEC's
|
||
|
+ * NTSC mode would want first field odd instead, once
|
||
|
+ * we support it (to do so, set ODD_FIRST and put the
|
||
|
+ * delay in VSYNCD_EVEN instead).
|
||
|
+ */
|
||
|
+ CRTC_WRITE(PV_V_CONTROL,
|
||
|
+ PV_VCONTROL_CONTINUOUS |
|
||
|
+ (is_dsi ? PV_VCONTROL_DSI : 0) |
|
||
|
+ PV_VCONTROL_INTERLACE |
|
||
|
+ VC4_SET_FIELD(mode->htotal / 2,
|
||
|
+ PV_VCONTROL_ODD_DELAY));
|
||
|
+ CRTC_WRITE(PV_VSYNCD_EVEN, 0);
|
||
|
+ } else {
|
||
|
+ CRTC_WRITE(PV_V_CONTROL,
|
||
|
+ PV_VCONTROL_CONTINUOUS |
|
||
|
+ (is_dsi ? PV_VCONTROL_DSI : 0));
|
||
|
}
|
||
|
|
||
|
CRTC_WRITE(PV_HACT_ACT, mode->hdisplay);
|
||
|
|
||
|
- CRTC_WRITE(PV_V_CONTROL,
|
||
|
- PV_VCONTROL_CONTINUOUS |
|
||
|
- (is_dsi ? PV_VCONTROL_DSI : 0) |
|
||
|
- (interlace ? PV_VCONTROL_INTERLACE : 0));
|
||
|
-
|
||
|
CRTC_WRITE(PV_CONTROL,
|
||
|
VC4_SET_FIELD(format, PV_CONTROL_FORMAT) |
|
||
|
VC4_SET_FIELD(vc4_get_fifo_full_level(format),
|
||
|
@@ -550,16 +564,6 @@ static bool vc4_crtc_mode_fixup(struct d
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
- /*
|
||
|
- * 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;
|
||
|
}
|
||
|
|
||
|
--- a/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||
|
+++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
|
||
|
@@ -219,35 +219,10 @@ vc4_hdmi_connector_best_encoder(struct d
|
||
|
return hdmi_connector->encoder;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * 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 = vc4_hdmi_connector_probe_modes,
|
||
|
+ .fill_modes = drm_helper_probe_single_connector_modes,
|
||
|
.destroy = vc4_hdmi_connector_destroy,
|
||
|
.reset = drm_atomic_helper_connector_reset,
|
||
|
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
|
||
|
@@ -316,16 +291,20 @@ static void vc4_hdmi_encoder_mode_set(st
|
||
|
bool debug_dump_regs = false;
|
||
|
bool hsync_pos = mode->flags & DRM_MODE_FLAG_PHSYNC;
|
||
|
bool vsync_pos = mode->flags & DRM_MODE_FLAG_PVSYNC;
|
||
|
- u32 vactive = (mode->vdisplay >>
|
||
|
- ((mode->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0));
|
||
|
- u32 verta = (VC4_SET_FIELD(mode->vsync_end - mode->vsync_start,
|
||
|
+ bool interlaced = mode->flags & DRM_MODE_FLAG_INTERLACE;
|
||
|
+ u32 verta = (VC4_SET_FIELD(mode->crtc_vsync_end - mode->crtc_vsync_start,
|
||
|
VC4_HDMI_VERTA_VSP) |
|
||
|
- VC4_SET_FIELD(mode->vsync_start - mode->vdisplay,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vsync_start - mode->crtc_vdisplay,
|
||
|
VC4_HDMI_VERTA_VFP) |
|
||
|
- VC4_SET_FIELD(vactive, VC4_HDMI_VERTA_VAL));
|
||
|
+ VC4_SET_FIELD(mode->crtc_vdisplay, VC4_HDMI_VERTA_VAL));
|
||
|
u32 vertb = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
|
||
|
- VC4_SET_FIELD(mode->vtotal - mode->vsync_end,
|
||
|
+ VC4_SET_FIELD(mode->crtc_vtotal - mode->crtc_vsync_end,
|
||
|
VC4_HDMI_VERTB_VBP));
|
||
|
+ u32 vertb_even = (VC4_SET_FIELD(0, VC4_HDMI_VERTB_VSPO) |
|
||
|
+ VC4_SET_FIELD(mode->crtc_vtotal -
|
||
|
+ mode->crtc_vsync_end -
|
||
|
+ interlaced,
|
||
|
+ VC4_HDMI_VERTB_VBP));
|
||
|
u32 csc_ctl;
|
||
|
|
||
|
if (debug_dump_regs) {
|
||
|
@@ -358,7 +337,7 @@ static void vc4_hdmi_encoder_mode_set(st
|
||
|
HDMI_WRITE(VC4_HDMI_VERTA0, verta);
|
||
|
HDMI_WRITE(VC4_HDMI_VERTA1, verta);
|
||
|
|
||
|
- HDMI_WRITE(VC4_HDMI_VERTB0, vertb);
|
||
|
+ HDMI_WRITE(VC4_HDMI_VERTB0, vertb_even);
|
||
|
HDMI_WRITE(VC4_HDMI_VERTB1, vertb);
|
||
|
|
||
|
HD_WRITE(VC4_HD_VID_CTL,
|
||
|
--- a/drivers/gpu/drm/vc4/vc4_regs.h
|
||
|
+++ b/drivers/gpu/drm/vc4/vc4_regs.h
|
||
|
@@ -183,6 +183,9 @@
|
||
|
# define PV_CONTROL_EN BIT(0)
|
||
|
|
||
|
#define PV_V_CONTROL 0x04
|
||
|
+# define PV_VCONTROL_ODD_DELAY_MASK VC4_MASK(22, 6)
|
||
|
+# define PV_VCONTROL_ODD_DELAY_SHIFT 6
|
||
|
+# define PV_VCONTROL_ODD_FIRST BIT(5)
|
||
|
# define PV_VCONTROL_INTERLACE BIT(4)
|
||
|
# define PV_VCONTROL_DSI BIT(3)
|
||
|
# define PV_VCONTROL_COMMAND BIT(2)
|