|
|
@@ -163,14 +163,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
|
|
int vblank_lines;
|
|
|
int ret = 0;
|
|
|
|
|
|
- /*
|
|
|
- * XXX Doesn't work well in interlaced mode yet, partially due
|
|
|
- * to problems in vc4 kms or drm core interlaced mode handling,
|
|
|
- * so disable for now in interlaced mode.
|
|
|
- */
|
|
|
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
- return ret;
|
|
|
-
|
|
|
/* preempt_disable_rt() should go right here in PREEMPT_RT patchset. */
|
|
|
|
|
|
/* Get optional system timestamp before query. */
|
|
|
@@ -191,10 +183,15 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
|
|
|
|
|
/* Vertical position of hvs composed scanline. */
|
|
|
*vpos = VC4_GET_FIELD(val, SCALER_DISPSTATX_LINE);
|
|
|
+ *hpos = 0;
|
|
|
|
|
|
- /* No hpos info available. */
|
|
|
- if (hpos)
|
|
|
- *hpos = 0;
|
|
|
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
|
|
|
+ *vpos /= 2;
|
|
|
+
|
|
|
+ /* Use hpos to correct for field offset in interlaced mode. */
|
|
|
+ if (VC4_GET_FIELD(val, SCALER_DISPSTATX_FRAME_COUNT) % 2)
|
|
|
+ *hpos += mode->crtc_htotal / 2;
|
|
|
+ }
|
|
|
|
|
|
/* This is the offset we need for translating hvs -> pv scanout pos. */
|
|
|
fifo_lines = vc4_crtc->cob_size / mode->crtc_hdisplay;
|
|
|
@@ -217,8 +214,6 @@ int vc4_crtc_get_scanoutpos(struct drm_device *dev, unsigned int crtc_id,
|
|
|
* position of the PV.
|
|
|
*/
|
|
|
*vpos -= fifo_lines + 1;
|
|
|
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
|
|
|
- *vpos /= 2;
|
|
|
|
|
|
ret |= DRM_SCANOUTPOS_ACCURATE;
|
|
|
return ret;
|
|
|
@@ -480,6 +475,9 @@ static void vc4_crtc_disable(struct drm_crtc *crtc)
|
|
|
int ret;
|
|
|
require_hvs_enabled(dev);
|
|
|
|
|
|
+ /* Disable vblank irq handling before crtc is disabled. */
|
|
|
+ drm_crtc_vblank_off(crtc);
|
|
|
+
|
|
|
CRTC_WRITE(PV_V_CONTROL,
|
|
|
CRTC_READ(PV_V_CONTROL) & ~PV_VCONTROL_VIDEN);
|
|
|
ret = wait_for(!(CRTC_READ(PV_V_CONTROL) & PV_VCONTROL_VIDEN), 1);
|
|
|
@@ -530,6 +528,33 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
|
|
|
/* Turn on the pixel valve, which will emit the vstart signal. */
|
|
|
CRTC_WRITE(PV_V_CONTROL,
|
|
|
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
|
|
|
+
|
|
|
+ /* Enable vblank irq handling after crtc is started. */
|
|
|
+ drm_crtc_vblank_on(crtc);
|
|
|
+}
|
|
|
+
|
|
|
+static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
|
|
|
+ const struct drm_display_mode *mode,
|
|
|
+ struct drm_display_mode *adjusted_mode)
|
|
|
+{
|
|
|
+ /* Do not allow doublescan modes from user space */
|
|
|
+ if (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN) {
|
|
|
+ DRM_DEBUG_KMS("[CRTC:%d] Doublescan mode rejected.\n",
|
|
|
+ crtc->base.id);
|
|
|
+ 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;
|
|
|
}
|
|
|
|
|
|
static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
|
|
|
@@ -819,6 +844,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,
|
|
|
};
|