diff options
Diffstat (limited to 'target/linux/brcm2708/patches-4.4/0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch')
-rw-r--r-- | target/linux/brcm2708/patches-4.4/0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/target/linux/brcm2708/patches-4.4/0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch b/target/linux/brcm2708/patches-4.4/0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch new file mode 100644 index 0000000..db17743 --- /dev/null +++ b/target/linux/brcm2708/patches-4.4/0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch @@ -0,0 +1,211 @@ +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) |