From e80b9f4eea2649f67edc05d4f2e7ddc250f91453 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 21 Jul 2015 11:08:25 +0100 Subject: [PATCH] drm: bridge/dw_hdmi: add support for interlaced video modes Add support for interlaced video modes to the dw_hdmi bridge. This mainly involves halving the vertical parameters to be programmed into the bridge registers, and setting the interlace_allowed connector flag. This brings working 1080i support. However, 480i and 576i fail to work due to the lack of proper pixel repetition support, which is not trivial to add due to the tabular PLL parameterisation. Hence, we filter out these modes in our mode_valid() method. Tested-by: Philipp Zabel Reviewed-by: Fabio Estevam Signed-off-by: Russell King --- drivers/gpu/drm/bridge/dw_hdmi.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c index 0083d4e7e7e2..dc1a382a9666 100644 --- a/drivers/gpu/drm/bridge/dw_hdmi.c +++ b/drivers/gpu/drm/bridge/dw_hdmi.c @@ -1063,6 +1063,7 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, u8 inv_val; struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode; int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len; + unsigned int vdisplay; vmode->mpixelclock = mode->clock * 1000; @@ -1102,13 +1103,29 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF); + vdisplay = mode->vdisplay; + vblank = mode->vtotal - mode->vdisplay; + v_de_vs = mode->vsync_start - mode->vdisplay; + vsync_len = mode->vsync_end - mode->vsync_start; + + /* + * When we're setting an interlaced mode, we need + * to adjust the vertical timing to suit. + */ + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + vdisplay /= 2; + vblank /= 2; + v_de_vs /= 2; + vsync_len /= 2; + } + /* Set up horizontal active pixel width */ hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1); hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0); /* Set up vertical active lines */ - hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1); - hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0); + hdmi_writeb(hdmi, vdisplay >> 8, HDMI_FC_INVACTV1); + hdmi_writeb(hdmi, vdisplay, HDMI_FC_INVACTV0); /* Set up horizontal blanking pixel region width */ hblank = mode->htotal - mode->hdisplay; @@ -1116,7 +1133,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0); /* Set up vertical blanking pixel region width */ - vblank = mode->vtotal - mode->vdisplay; hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK); /* Set up HSYNC active edge delay width (in pixel clks) */ @@ -1125,7 +1141,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0); /* Set up VSYNC active edge delay (in lines) */ - v_de_vs = mode->vsync_start - mode->vdisplay; hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY); /* Set up HSYNC active pulse width (in pixel clks) */ @@ -1134,7 +1149,6 @@ static void hdmi_av_composer(struct dw_hdmi *hdmi, hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0); /* Set up VSYNC active edge delay (in lines) */ - vsync_len = mode->vsync_end - mode->vsync_start; hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH); } @@ -1608,6 +1622,8 @@ int dw_hdmi_bind(struct device *dev, struct device *master, if (!hdmi) return -ENOMEM; + hdmi->connector.interlace_allowed = 1; + hdmi->plat_data = plat_data; hdmi->dev = dev; hdmi->dev_type = plat_data->dev_type; -- 2.20.1