123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211 |
- 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)
|