aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMario Kleiner <mario.kleiner.de@gmail.com>2016-07-19 14:58:58 -0400
committerEric Anholt <eric@anholt.net>2016-08-19 22:05:49 -0400
commitacc1be1d351e8d5c0c8d14dad904ae0e39fc3653 (patch)
treea68e8e73fdd44eb82588b9e562f25f57d30ddd6e
parente2298350de58d5c956131003606bfa4995f26933 (diff)
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 <mario.kleiner.de@gmail.com> Signed-off-by: Eric Anholt <eric@anholt.net>
-rw-r--r--drivers/gpu/drm/vc4/vc4_crtc.c18
-rw-r--r--drivers/gpu/drm/vc4/vc4_hdmi.c29
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)
532 CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); 532 CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN);
533} 533}
534 534
535static bool vc4_crtc_mode_fixup(struct drm_crtc *crtc,
536 const struct drm_display_mode *mode,
537 struct drm_display_mode *adjusted_mode)
538{
539 /*
540 * Interlaced video modes got CRTC_INTERLACE_HALVE_V applied when
541 * coming from user space. We don't want this, as it screws up
542 * vblank timestamping, so fix it up.
543 */
544 drm_mode_set_crtcinfo(adjusted_mode, 0);
545
546 DRM_DEBUG_KMS("[CRTC:%d] adjusted_mode :\n", crtc->base.id);
547 drm_mode_debug_printmodeline(adjusted_mode);
548
549 return true;
550}
551
535static int vc4_crtc_atomic_check(struct drm_crtc *crtc, 552static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
536 struct drm_crtc_state *state) 553 struct drm_crtc_state *state)
537{ 554{
@@ -819,6 +836,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
819 .mode_set_nofb = vc4_crtc_mode_set_nofb, 836 .mode_set_nofb = vc4_crtc_mode_set_nofb,
820 .disable = vc4_crtc_disable, 837 .disable = vc4_crtc_disable,
821 .enable = vc4_crtc_enable, 838 .enable = vc4_crtc_enable,
839 .mode_fixup = vc4_crtc_mode_fixup,
822 .atomic_check = vc4_crtc_atomic_check, 840 .atomic_check = vc4_crtc_atomic_check,
823 .atomic_flush = vc4_crtc_atomic_flush, 841 .atomic_flush = vc4_crtc_atomic_flush,
824}; 842};
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)
208 return ret; 208 return ret;
209} 209}
210 210
211/*
212 * drm_helper_probe_single_connector_modes() applies drm_mode_set_crtcinfo to
213 * all modes with flag CRTC_INTERLACE_HALVE_V. We don't want this, as it
214 * screws up vblank timestamping for interlaced modes, so fix it up.
215 */
216static int vc4_hdmi_connector_probe_modes(struct drm_connector *connector,
217 uint32_t maxX, uint32_t maxY)
218{
219 struct drm_display_mode *mode;
220 int count;
221
222 count = drm_helper_probe_single_connector_modes(connector, maxX, maxY);
223 if (count == 0)
224 return 0;
225
226 DRM_DEBUG_KMS("[CONNECTOR:%d:%s] probed adapted modes :\n",
227 connector->base.id, connector->name);
228 list_for_each_entry(mode, &connector->modes, head) {
229 drm_mode_set_crtcinfo(mode, 0);
230 drm_mode_debug_printmodeline(mode);
231 }
232
233 return count;
234}
235
211static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { 236static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
212 .dpms = drm_atomic_helper_connector_dpms, 237 .dpms = drm_atomic_helper_connector_dpms,
213 .detect = vc4_hdmi_connector_detect, 238 .detect = vc4_hdmi_connector_detect,
214 .fill_modes = drm_helper_probe_single_connector_modes, 239 .fill_modes = vc4_hdmi_connector_probe_modes,
215 .destroy = vc4_hdmi_connector_destroy, 240 .destroy = vc4_hdmi_connector_destroy,
216 .reset = drm_atomic_helper_connector_reset, 241 .reset = drm_atomic_helper_connector_reset,
217 .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, 242 .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,
246 connector->polled = (DRM_CONNECTOR_POLL_CONNECT | 271 connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
247 DRM_CONNECTOR_POLL_DISCONNECT); 272 DRM_CONNECTOR_POLL_DISCONNECT);
248 273
249 connector->interlace_allowed = 0; 274 connector->interlace_allowed = 1;
250 connector->doublescan_allowed = 0; 275 connector->doublescan_allowed = 0;
251 276
252 drm_mode_connector_attach_encoder(connector, encoder); 277 drm_mode_connector_attach_encoder(connector, encoder);