brcm2708: update linux 4.4 patches to latest version
[openwrt/staging/yousong.git] / target / linux / brcm2708 / patches-4.4 / 0520-drm-vc4-Fix-support-for-interlaced-modes-on-HDMI.patch
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 (file)
index 0000000..db17743
--- /dev/null
@@ -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)