drm: rcar-du: Add interlaced mode support 25/31925/1
authorKoji Matsuoka <koji.matsuoka.xm@renesas.com>
Mon, 24 Mar 2014 04:15:13 +0000 (13:15 +0900)
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>
Fri, 12 Dec 2014 09:13:10 +0000 (18:13 +0900)
Change-Id: Ibbebf7ce4e740af149de25e448c98ca8ca7ed53b
Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com>
Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
drivers/gpu/drm/rcar-du/rcar_du_drv.h
drivers/gpu/drm/rcar-du/rcar_du_group.c
drivers/gpu/drm/rcar-du/rcar_du_group.h
drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/rcar-du/rcar_du_plane.h
drivers/gpu/drm/rcar-du/rcar_du_regs.h

index 8b0545c..79d6ddb 100644 (file)
@@ -116,12 +116,25 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
                                        mode->hsync_start - 1);
        rcar_du_crtc_write(rcrtc, HCR,  mode->htotal - 1);
 
-       rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
-       rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
-                                       mode->vdisplay - 2);
-       rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
-                                       mode->vsync_start - 1);
-       rcar_du_crtc_write(rcrtc, VCR,  mode->vtotal - 1);
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               rcar_du_crtc_write(rcrtc, VDSR, (mode->vtotal / 2)
+                                                - (mode->vsync_end / 2) - 2);
+               rcar_du_crtc_write(rcrtc, VDER, (mode->vtotal / 2)
+                                                - (mode->vsync_end / 2)
+                                                + (mode->vdisplay / 2) - 2);
+               rcar_du_crtc_write(rcrtc, VSPR, (mode->vtotal / 2)
+                                                - (mode->vsync_end / 2)
+                                                + (mode->vsync_start / 2) - 1);
+               rcar_du_crtc_write(rcrtc, VCR,  (mode->vtotal / 2) - 1);
+       } else {
+               rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal
+                                                - mode->vsync_end - 2);
+               rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end
+                                                + mode->vdisplay - 2);
+               rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end
+                                                + mode->vsync_start - 1);
+               rcar_du_crtc_write(rcrtc, VCR,  mode->vtotal - 1);
+       }
 
        rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
        rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
@@ -244,6 +257,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
                if (plane->crtc != crtc || !plane->enabled)
                        continue;
 
+               if (rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE)
+                       plane->interlace_flag = true;
+               else
+                       plane->interlace_flag = false;
                rcar_du_plane_setup(plane);
        }
 
@@ -253,6 +270,19 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
         */
        rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
 
+       if (rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE) {
+               if (rcrtc->index == 1)
+                       rcar_du_crtc_clr_set(rcrtc, DSYSR,
+                               DSYSR_SCM_INT_VIDEO, DSYSR_SCM_INT_VIDEO);
+               else
+                       rcrtc->group->interlace_grp = true;
+       } else {
+               if (rcrtc->index == 1)
+                       rcar_du_crtc_clr_set(rcrtc, DSYSR,
+                               DSYSR_SCM_INT_VIDEO, 0);
+               else
+                       rcrtc->group->interlace_grp = false;
+       }
        rcar_du_group_start_stop(rcrtc->group, true);
 
        rcrtc->started = true;
@@ -275,6 +305,14 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc)
         */
        rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_SWITCH);
 
+       if (rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE) {
+               if (rcrtc->index == 1)
+                       rcar_du_crtc_clr_set(rcrtc,
+                               DSYSR, DSYSR_SCM_INT_VIDEO, 0);
+               else
+                       rcrtc->group->interlace_grp = false;
+       }
+
        rcar_du_group_start_stop(rcrtc->group, false);
 
        rcrtc->started = false;
@@ -485,7 +523,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
        status = rcar_du_crtc_read(rcrtc, DSSR);
        rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
 
-       if (status & DSSR_VBK) {
+       if (status & DSSR_FRM) {
                drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
                rcar_du_crtc_finish_page_flip(rcrtc);
                ret = IRQ_HANDLED;
index 0a72466..fdd645b 100644 (file)
@@ -28,6 +28,7 @@ struct rcar_du_lvdsenc;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0)        /* Per-CRTC IRQ and clock */
 #define RCAR_DU_FEATURE_DEFR8          (1 << 1)        /* Has DEFR8 register */
+#define RCAR_DU_FEATURE_INTERLACE      (1 << 4)
 
 #define RCAR_DU_QUIRK_ALIGN_128B       (1 << 0)        /* Align pitches to 128 bytes */
 #define RCAR_DU_QUIRK_LVDS_LANES       (1 << 1)        /* LVDS lanes 1 and 3 inverted */
index 4e7614b..2d3495b 100644 (file)
@@ -111,9 +111,16 @@ void rcar_du_group_put(struct rcar_du_group *rgrp)
 
 static void __rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
 {
+       u32 dsysr_scm;
+
+       if (rgrp->interlace_grp)
+               dsysr_scm = DSYSR_SCM_INT_VIDEO;
+       else
+               dsysr_scm = DSYSR_SCM_INT_NONE;
+
        rcar_du_group_write(rgrp, DSYSR,
-               (rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN)) |
-               (start ? DSYSR_DEN : DSYSR_DRES));
+            (rcar_du_group_read(rgrp, DSYSR) & ~(DSYSR_DRES | DSYSR_DEN |
+             DSYSR_SCM_MASK)) | dsysr_scm | (start ? DSYSR_DEN : DSYSR_DRES));
 }
 
 void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start)
index 0c38cdc..d8d0a8c 100644 (file)
@@ -36,6 +36,7 @@ struct rcar_du_group {
        unsigned int used_crtcs;
 
        struct rcar_du_planes planes;
+       bool interlace_grp;
 };
 
 u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg);
index 4d7d4dd..1678a31 100644 (file)
@@ -95,6 +95,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
        connector = &rcon->connector;
        connector->display_info.width_mm = 0;
        connector->display_info.height_mm = 0;
+       connector->interlace_allowed = true;
 
        ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
                                 DRM_MODE_CONNECTOR_HDMIA);
index 72a7cb4..0f422f9 100644 (file)
@@ -112,7 +112,10 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
        else
                mwr = plane->pitch * 8 / plane->format->bpp;
 
-       rcar_du_plane_write(rgrp, index, PnMWR, mwr);
+       if ((plane->interlace_flag) && (plane->format->bpp == 32))
+               rcar_du_plane_write(rgrp, index, PnMWR, mwr * 2);
+       else
+               rcar_du_plane_write(rgrp, index, PnMWR, mwr);
 
        /* The Y position is expressed in raster line units and must be doubled
         * for 32bpp formats, according to the R8A7790 datasheet. No mention of
@@ -123,8 +126,10 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
         * require a halved Y position value.
         */
        rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
-       rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
-                           (plane->format->bpp == 32 ? 2 : 1));
+       if ((!plane->interlace_flag) && (plane->format->bpp == 32))
+               rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * 2);
+       else
+               rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y);
        rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
 
        if (plane->format->planes == 2) {
@@ -320,6 +325,11 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
        rplane->height = crtc_h;
 
        rcar_du_plane_compute_base(rplane, fb);
+
+       if (crtc->mode.flags & DRM_MODE_FLAG_INTERLACE)
+               rplane->interlace_flag = true;
+       else
+               rplane->interlace_flag = false;
        rcar_du_plane_setup(rplane);
 
        mutex_lock(&rplane->group->planes.lock);
@@ -496,6 +506,7 @@ int rcar_du_planes_register(struct rcar_du_group *rgrp)
 
                plane->hwplane = &planes->planes[i + 2];
                plane->hwplane->zpos = 1;
+               plane->hwplane->interlace_flag = false;
 
                ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs,
                                     &rcar_du_plane_funcs, formats,
index 3021288..89e4e13 100644 (file)
@@ -55,6 +55,8 @@ struct rcar_du_plane {
        unsigned int src_y;
        unsigned int dst_x;
        unsigned int dst_y;
+
+       bool interlace_flag;
 };
 
 struct rcar_du_planes {
index 73f7347..3ef4579 100644 (file)
@@ -34,6 +34,7 @@
 #define DSYSR_SCM_INT_NONE     (0 << 4)
 #define DSYSR_SCM_INT_SYNC     (2 << 4)
 #define DSYSR_SCM_INT_VIDEO    (3 << 4)
+#define DSYSR_SCM_MASK         (3 << 4)
 
 #define DSMR                   0x00004
 #define DSMR_VSPM              (1 << 28)