Commit acc1be1d authored by Mario Kleiner's avatar Mario Kleiner Committed by Eric Anholt

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: default avatarMario Kleiner <mario.kleiner.de@gmail.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
parent e2298350
...@@ -532,6 +532,23 @@ static void vc4_crtc_enable(struct drm_crtc *crtc) ...@@ -532,6 +532,23 @@ static void vc4_crtc_enable(struct drm_crtc *crtc)
CRTC_READ(PV_V_CONTROL) | PV_VCONTROL_VIDEN); 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, static int vc4_crtc_atomic_check(struct drm_crtc *crtc,
struct drm_crtc_state *state) struct drm_crtc_state *state)
{ {
...@@ -819,6 +836,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = { ...@@ -819,6 +836,7 @@ static const struct drm_crtc_helper_funcs vc4_crtc_helper_funcs = {
.mode_set_nofb = vc4_crtc_mode_set_nofb, .mode_set_nofb = vc4_crtc_mode_set_nofb,
.disable = vc4_crtc_disable, .disable = vc4_crtc_disable,
.enable = vc4_crtc_enable, .enable = vc4_crtc_enable,
.mode_fixup = vc4_crtc_mode_fixup,
.atomic_check = vc4_crtc_atomic_check, .atomic_check = vc4_crtc_atomic_check,
.atomic_flush = vc4_crtc_atomic_flush, .atomic_flush = vc4_crtc_atomic_flush,
}; };
......
...@@ -208,10 +208,35 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector) ...@@ -208,10 +208,35 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
return ret; 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 = { static const struct drm_connector_funcs vc4_hdmi_connector_funcs = {
.dpms = drm_atomic_helper_connector_dpms, .dpms = drm_atomic_helper_connector_dpms,
.detect = vc4_hdmi_connector_detect, .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, .destroy = vc4_hdmi_connector_destroy,
.reset = drm_atomic_helper_connector_reset, .reset = drm_atomic_helper_connector_reset,
.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state, .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,7 +271,7 @@ static struct drm_connector *vc4_hdmi_connector_init(struct drm_device *dev,
connector->polled = (DRM_CONNECTOR_POLL_CONNECT | connector->polled = (DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT); DRM_CONNECTOR_POLL_DISCONNECT);
connector->interlace_allowed = 0; connector->interlace_allowed = 1;
connector->doublescan_allowed = 0; connector->doublescan_allowed = 0;
drm_mode_connector_attach_encoder(connector, encoder); drm_mode_connector_attach_encoder(connector, encoder);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment