drm/exynos: hdmi: support for interlaced mode
authorAkshay Saraswat <Akshay.s@samsung.com>
Wed, 10 Oct 2012 09:47:10 +0000 (18:47 +0900)
committerGerrit <chrome-bot@google.com>
Tue, 23 Oct 2012 08:42:24 +0000 (01:42 -0700)
This patch adds interlaced mode support for exynos 5 HDMI IP
as per the spec requirement and differing quirk register
values between progressive and interlaced in exynos drm
hdmi driver.

BUG=chrome-os-partner:12642
TEST=Tested with two differnet monitors and
        Agilent Technologies N5998A HDMI
        protocol analyzer and generator
        for 1080i modes at 60Hz and 50Hz
        frequencies.

Change-Id: I61743b91d4553089c72c376cfc94b4bb96f1edf6
Signed-off-by: Shirish S <s.shirish@samsung.com>
Signed-off-by: Akshay Saraswat <Akshay.s@samsung.com>
Reviewed-on: https://gerrit.chromium.org/gerrit/33427
Tested-by: Akshay Saraswat <akshay.s@samsung.com>
Reviewed-by: Sean Paul <seanpaul@chromium.org>
Commit-Ready: Akshay Saraswat <akshay.s@samsung.com>

drivers/gpu/drm/exynos/exynos_hdmi.c
drivers/gpu/drm/exynos/exynos_mixer.c

index 6edf8b1..fc1f7fe 100644 (file)
@@ -959,13 +959,6 @@ static int hdmi_v14_check_timing(struct fb_videomode *mode)
        int ret;
        enum exynos_mixer_mode_type mode_type;
 
-       /*
-        * No support for interlaced since there's no clear way to convert the
-        * timing values in drm_display_mode to exynos register values.
-        */
-       if (mode->vmode == FB_VMODE_INTERLACED)
-               return -EINVAL;
-
        /* Make sure the mixer can generate this mode */
        mode_type = exynos_mixer_get_mode_type(mode->xres, mode->yres);
        if (mode_type == EXYNOS_MIXER_MODE_INVALID)
@@ -1747,7 +1740,6 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
 
        hdata->mode_conf.pixel_clock = m->clock * 1000;
        hdmi_set_reg(core->h_blank, 2, m->htotal - m->hdisplay);
-       hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
        hdmi_set_reg(core->v_line, 2, m->vtotal);
        hdmi_set_reg(core->h_line, 2, m->htotal);
        hdmi_set_reg(core->hsync_pol, 1,
@@ -1755,35 +1747,67 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
        hdmi_set_reg(core->vsync_pol, 1,
                        (m->flags & DRM_MODE_FLAG_NVSYNC) ? 1 : 0);
        hdmi_set_reg(core->int_pro_mode, 1,
-                       (m->flags >> DRM_MODE_FLAG_INTERLACE) & 0x01);
-       /* Quirk requirement for exynos 5 HDMI IP design,
+                       (m->flags & DRM_MODE_FLAG_INTERLACE) ? 1 : 0);
+
+       /*
+        * Quirk requirement for exynos 5 HDMI IP design,
         * 2 pixels less than the actual calculation for hsync_start
         * and end.
         */
+
+       /* Following values & calculations differ for different type of modes */
+       if (m->flags & DRM_MODE_FLAG_INTERLACE) {
+               /* Interlaced Mode */
+               hdmi_set_reg(core->v_sync_line_bef_2, 2,
+                       (m->vsync_end - m->vdisplay) / 2);
+               hdmi_set_reg(core->v_sync_line_bef_1, 2,
+                       (m->vsync_start - m->vdisplay) / 2);
+               hdmi_set_reg(core->v2_blank, 2, m->vtotal / 2);
+               hdmi_set_reg(core->v1_blank, 2, (m->vtotal - m->vdisplay) / 2);
+               hdmi_set_reg(core->v_blank_f0, 2,
+                       (m->vtotal + ((m->vsync_end - m->vsync_start) * 4) + 5) / 2);
+               hdmi_set_reg(core->v_blank_f1, 2, m->vtotal);
+               hdmi_set_reg(core->v_sync_line_aft_2, 2, (m->vtotal / 2) + 7);
+               hdmi_set_reg(core->v_sync_line_aft_1, 2, (m->vtotal / 2) + 2);
+               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2,
+                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
+               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2,
+                       (m->htotal / 2) + (m->hsync_start - m->hdisplay));
+               hdmi_set_reg(tg->vact_st, 2, (m->vtotal - m->vdisplay) / 2);
+               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay / 2);
+               hdmi_set_reg(tg->vact_st2, 2, 0x249);/* Reset value + 1*/
+               hdmi_set_reg(tg->vact_st3, 2, 0x0);
+               hdmi_set_reg(tg->vact_st4, 2, 0x0);
+       } else {
+               /* Progressive Mode */
+               hdmi_set_reg(core->v_sync_line_bef_2, 2,
+                       m->vsync_end - m->vdisplay);
+               hdmi_set_reg(core->v_sync_line_bef_1, 2,
+                       m->vsync_start - m->vdisplay);
+               hdmi_set_reg(core->v2_blank, 2, m->vtotal);
+               hdmi_set_reg(core->v1_blank, 2, m->vtotal - m->vdisplay);
+               hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
+               hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
+               hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
+               hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
+               hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
+               hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
+               hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
+               hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
+               hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
+               hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
+               hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
+       }
+
+       /* Following values & calculations are same irrespective of mode type */
        hdmi_set_reg(core->h_sync_start, 2, m->hsync_start - m->hdisplay - 2);
        hdmi_set_reg(core->h_sync_end, 2, m->hsync_end - m->hdisplay - 2);
-       hdmi_set_reg(core->v_sync_line_bef_2, 2, m->vsync_end - m->vdisplay);
-       hdmi_set_reg(core->v_sync_line_bef_1, 2, m->vsync_start - m->vdisplay);
        hdmi_set_reg(core->vact_space_1, 2, 0xffff);
        hdmi_set_reg(core->vact_space_2, 2, 0xffff);
        hdmi_set_reg(core->vact_space_3, 2, 0xffff);
        hdmi_set_reg(core->vact_space_4, 2, 0xffff);
        hdmi_set_reg(core->vact_space_5, 2, 0xffff);
        hdmi_set_reg(core->vact_space_6, 2, 0xffff);
-
-       /*
-        * The following values can be different when using interlaced mode.
-        * Unfortunately the datasheet doesn't describe them. This is why we
-        * reject interlaced modes. Once this is fixed, we can remove that
-        * restriction.
-        */
-       hdmi_set_reg(core->v2_blank, 2, m->vtotal);
-       hdmi_set_reg(core->v_blank_f0, 2, 0xffff);
-       hdmi_set_reg(core->v_blank_f1, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_2, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_1, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_2, 2, 0xffff);
-       hdmi_set_reg(core->v_sync_line_aft_pxl_1, 2, 0xffff);
        hdmi_set_reg(core->v_blank_f2, 2, 0xffff);
        hdmi_set_reg(core->v_blank_f3, 2, 0xffff);
        hdmi_set_reg(core->v_blank_f4, 2, 0xffff);
@@ -1805,12 +1829,7 @@ static void hdmi_v14_mode_set(struct hdmi_context *hdata,
        hdmi_set_reg(tg->v_fsz, 2, m->vtotal);
        hdmi_set_reg(tg->vsync, 2, 0x1);
        hdmi_set_reg(tg->vsync2, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vact_st, 2, m->vtotal - m->vdisplay);
-       hdmi_set_reg(tg->vact_sz, 2, m->vdisplay);
        hdmi_set_reg(tg->field_chg, 2, 0x233); /* Reset value */
-       hdmi_set_reg(tg->vact_st2, 2, 0x248); /* Reset value */
-       hdmi_set_reg(tg->vact_st3, 2, 0x47b); /* Reset value */
-       hdmi_set_reg(tg->vact_st4, 2, 0x6ae); /* Reset value */
        hdmi_set_reg(tg->vsync_top_hdmi, 2, 0x1); /* Reset value */
        hdmi_set_reg(tg->vsync_bot_hdmi, 2, 0x233); /* Reset value */
        hdmi_set_reg(tg->field_top_hdmi, 2, 0x1); /* Reset value */
index ea3eb84..fc758f4 100644 (file)
@@ -849,7 +849,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
        /* handling VSYNC */
        if (val & MXR_INT_STATUS_VSYNC) {
                /* interlace scan need to check shadow register */
-               if (mctx->interlace) {
+               if (mctx->interlace && !res->is_soc_exynos5) {
                        base = mixer_reg_read(res, MXR_GRAPHIC_BASE(0));
                        shadow = mixer_reg_read(res, MXR_GRAPHIC_BASE_S(0));
                        if (base != shadow)