From e2298350de58d5c956131003606bfa4995f26933 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Tue, 19 Jul 2016 20:58:57 +0200 Subject: [PATCH 1/6] drm/vc4: Disallow interlaced modes on DPI. We already don't expose such modes to userspace, but make sure userspace can't sneak some interlaced mode in. Signed-off-by: Mario Kleiner Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_dpi.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_dpi.c b/drivers/gpu/drm/vc4/vc4_dpi.c index 275fedbdbd9e..1e1f6b8184d0 100644 --- a/drivers/gpu/drm/vc4/vc4_dpi.c +++ b/drivers/gpu/drm/vc4/vc4_dpi.c @@ -340,9 +340,20 @@ static void vc4_dpi_encoder_enable(struct drm_encoder *encoder) } } +static bool vc4_dpi_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) + return false; + + return true; +} + static const struct drm_encoder_helper_funcs vc4_dpi_encoder_helper_funcs = { .disable = vc4_dpi_encoder_disable, .enable = vc4_dpi_encoder_enable, + .mode_fixup = vc4_dpi_encoder_mode_fixup, }; static const struct of_device_id vc4_dpi_dt_match[] = { From acc1be1d351e8d5c0c8d14dad904ae0e39fc3653 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Tue, 19 Jul 2016 20:58:58 +0200 Subject: [PATCH 2/6] drm/vc4: Fix handling of interlaced video modes. We must not apply CRTC_INTERLACE_HALVE_V to interlaced modes during mode enumeration, as drm_helper_probe_single_connector_modes does, so wrap it and reset the effect of CRTC_INTERLACE_HALVE_V on affected interlaced modes. Also mode_fixup interlaced modes passed in from user space. This fixes the vblank timestamping constants and entries in the mode->crtc_xxx fields needed for precise vblank timestamping. Signed-off-by: Mario Kleiner Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_crtc.c | 18 ++++++++++++++++++ drivers/gpu/drm/vc4/vc4_hdmi.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 8fc2b731b59a..a479d3d840c5 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -532,6 +532,23 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); } +static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + /* + * 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, struct drm_crtc_state *state) { @@ -819,6 +836,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, }; diff --git a/drivers/gpu/drm/vc4/vc4_hdmi.c b/drivers/gpu/drm/vc4/vc4_hdmi.c index 4452f3631cac..68ad10634b29 100644 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c @@ -208,10 +208,35 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) return ret; } +/* + * 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 = drm_helper_probe_single_connector_modes, + .fill_modes = vc4_hdmi_connector_probe_modes, .destroy = vc4_hdmi_connector_destroy, .reset = drm_atomic_helper_connector_reset, .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, @@ -246,7 +271,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev, connector->polled = (DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT); - connector->interlace_allowed = 0; + connector->interlace_allowed = 1; connector->doublescan_allowed = 0; drm_mode_connector_attach_encoder(connector, encoder); From 3645146706f716be7ef2b88ebcc26f7f1fc4e4aa Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Tue, 19 Jul 2016 20:58:59 +0200 Subject: [PATCH 3/6] drm/vc4: Reject doublescan modes. We can't handle doublescan modes at the moment, so if userspace tries to set one, reject the mode set. Signed-off-by: Mario Kleiner Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_crtc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index a479d3d840c5..2bfa2470e66b 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -536,6 +536,13 @@ 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 From e538092cb15cf2978cb661af3382d71601bed539 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Tue, 19 Jul 2016 20:59:00 +0200 Subject: [PATCH 4/6] drm/vc4: Enable precise vblank timestamping for interlaced modes. On top of the interlaced video mode fix and with some additional adjustments, this now works well. It has almost the same accuracy as on regular progressive scan modes. Signed-off-by: Mario Kleiner Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_crtc.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 2bfa2470e66b..7ffdad543ed2 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -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; From e941f05d3c1155b5cee65e146324219c6a72be27 Mon Sep 17 00:00:00 2001 From: Mario Kleiner Date: Tue, 19 Jul 2016 20:59:01 +0200 Subject: [PATCH 5/6] drm/vc4: Enable/Disable vblanks properly in crtc en/disable. Add missing drm_crtc_vblank_on/off() calls so vblank irq handling/updating/timestamping never runs with a crtc shut down or during its shutdown/startup, as that causes large jumps in vblank count and trouble for compositors. Signed-off-by: Mario Kleiner Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_crtc.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/drm/vc4/vc4_crtc.c b/drivers/gpu/drm/vc4/vc4_crtc.c index 7ffdad543ed2..2682f07d8f1e 100644 --- a/drivers/gpu/drm/vc4/vc4_crtc.c +++ b/drivers/gpu/drm/vc4/vc4_crtc.c @@ -475,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); @@ -525,6 +528,9 @@ 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, From 67f13690f447841fb3d2f952a6e49b2b28ae379b Mon Sep 17 00:00:00 2001 From: Eric Anholt Date: Tue, 2 Aug 2016 17:17:52 -0700 Subject: [PATCH 6/6] drm/vc4: Don't force new binner overflow allocation per draw. This came from the initial bringup code, which always idled the GPU and always reset the overflow. That massively increases the size of the working set when you're doing lots of small draws, though, as is common on X desktops or piglit. Signed-off-by: Eric Anholt --- drivers/gpu/drm/vc4/vc4_gem.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/gpu/drm/vc4/vc4_gem.c b/drivers/gpu/drm/vc4/vc4_gem.c index 6155e8aca1c6..27c52ec35193 100644 --- a/drivers/gpu/drm/vc4/vc4_gem.c +++ b/drivers/gpu/drm/vc4/vc4_gem.c @@ -419,10 +419,6 @@ vc4_submit_next_bin_job(struct drm_device *dev) vc4_flush_caches(dev); - /* Disable the binner's pre-loaded overflow memory address */ - V3D_WRITE(V3D_BPOA, 0); - V3D_WRITE(V3D_BPOS, 0); - /* Either put the job in the binner if it uses the binner, or * immediately move it to the to-be-rendered queue. */