diff options
author | Mario Kleiner <mario.kleiner.de@gmail.com> | 2016-07-19 14:58:58 -0400 |
---|---|---|
committer | Eric Anholt <eric@anholt.net> | 2016-08-19 22:05:49 -0400 |
commit | acc1be1d351e8d5c0c8d14dad904ae0e39fc3653 (patch) | |
tree | a68e8e73fdd44eb82588b9e562f25f57d30ddd6e | |
parent | e2298350de58d5c956131003606bfa4995f26933 (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.c | 18 | ||||
-rw-r--r-- | 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) | |||
532 | CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); | 532 | CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); |
533 | } | 533 | } |
534 | 534 | ||
535 | static 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 | |||
535 | static int vc4_crtc_atomic_check(struct drm_crtc *crtc, | 552 | static 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 | */ | ||
216 | static 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 | |||
211 | static const struct drm_connector_funcs vc4_hdmi_connector_funcs = { | 236 | static 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); |