drm: rcar-du: Implement support for interlaced modes
authorLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tue, 9 Dec 2014 17:11:18 +0000 (19:11 +0200)
committerLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
Tue, 23 Dec 2014 10:01:52 +0000 (12:01 +0200)
Accept interlaced modes on the VGA and HDMI connectors and configure the
hardware accordingly.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
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_regs.h
drivers/gpu/drm/rcar-du/rcar_du_vgacon.c

index 86766cc..25c7a99 100644 (file)
@@ -155,12 +155,15 @@ 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);
+       rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end - 2);
+       rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end +
+                                       mode->crtc_vdisplay - 2);
+       rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal -
+                                       mode->crtc_vsync_end +
+                                       mode->crtc_vsync_start - 1);
+       rcar_du_crtc_write(rcrtc, VCR,  mode->crtc_vtotal - 1);
 
        rcar_du_crtc_write(rcrtc, DESR,  mode->htotal - mode->hsync_start);
        rcar_du_crtc_write(rcrtc, DEWR,  mode->hdisplay);
@@ -256,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
 static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
 {
        struct drm_crtc *crtc = &rcrtc->crtc;
+       bool interlaced;
        unsigned int i;
 
        if (rcrtc->started)
@@ -291,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
         * sync mode (with the HSYNC and VSYNC signals configured as outputs and
         * actively driven).
         */
-       rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
+       interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+       rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
+                            (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
+                            DSYSR_TVM_MASTER);
 
        rcar_du_group_start_stop(rcrtc->group, true);
 
@@ -528,7 +535,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 322b720..ca94b02 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;
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
        ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
index fb3ea4f..50f2f2b 100644 (file)
@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
 {
        struct rcar_du_group *rgrp = plane->group;
        unsigned int index = plane->hwindex;
+       bool interlaced;
        u32 mwr;
 
-       /* Memory pitch (expressed in pixels) */
+       interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
+       /* Memory pitch (expressed in pixels). Must be doubled for interlaced
+        * operation with 32bpp formats.
+        */
        if (plane->format->planes == 2)
                mwr = plane->pitch;
        else
                mwr = plane->pitch * 8 / plane->format->bpp;
 
+       if (interlaced && plane->format->bpp == 32)
+               mwr *= 2;
+
        rcar_du_plane_write(rgrp, index, PnMWR, mwr);
 
        /* The Y position is expressed in raster line units and must be doubled
@@ -119,12 +127,16 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
         * doubling the Y position is found in the R8A7779 datasheet, but the
         * rule seems to apply there as well.
         *
+        * Despite not being documented, doubling seem not to be needed when
+        * operating in interlaced mode.
+        *
         * Similarly, for the second plane, NV12 and NV21 formats seem to
-        * require a halved Y position value.
+        * require a halved Y position value, in both progressive and interlaced
+        * modes.
         */
        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));
+                           (!interlaced && plane->format->bpp == 32 ? 2 : 1));
        rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
 
        if (plane->format->planes == 2) {
index c3639d1..70fcbc4 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)
index 752747a..9d48799 100644 (file)
@@ -64,6 +64,7 @@ int rcar_du_vga_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_VGA);