From 535e6b92647b7eff5e08e5f91bf24d259bef6c73 Mon Sep 17 00:00:00 2001 From: Koji Matsuoka Date: Mon, 24 Mar 2014 13:15:13 +0900 Subject: [PATCH] drm: rcar-du: Add interlaced mode support Change-Id: Ibbebf7ce4e740af149de25e448c98ca8ca7ed53b Signed-off-by: Koji Matsuoka Signed-off-by: Damian Hobson-Garcia --- drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 52 ++++++++++++++++++++++++++----- drivers/gpu/drm/rcar-du/rcar_du_drv.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_group.c | 11 +++++-- drivers/gpu/drm/rcar-du/rcar_du_group.h | 1 + drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c | 1 + drivers/gpu/drm/rcar-du/rcar_du_plane.c | 17 ++++++++-- drivers/gpu/drm/rcar-du/rcar_du_plane.h | 2 ++ drivers/gpu/drm/rcar-du/rcar_du_regs.h | 1 + 8 files changed, 74 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 8b0545c..79d6ddb 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -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; diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h index 0a72466..fdd645b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h @@ -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 */ diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c index 4e7614b..2d3495b 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c @@ -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) diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.h b/drivers/gpu/drm/rcar-du/rcar_du_group.h index 0c38cdc..d8d0a8c 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_group.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_group.h @@ -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); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c index 4d7d4dd..1678a31 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c @@ -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); diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c index 72a7cb4..0f422f9 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c @@ -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, diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.h b/drivers/gpu/drm/rcar-du/rcar_du_plane.h index 3021288..89e4e13 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_plane.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.h @@ -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 { diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h index 73f7347..3ef4579 100644 --- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h +++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h @@ -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) -- 2.7.4