summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoji Matsuoka <koji.matsuoka.xm@renesas.com>2014-03-24 13:15:13 +0900
committerDamian Hobson-Garcia <dhobsong@igel.co.jp>2014-12-12 18:13:10 +0900
commit535e6b92647b7eff5e08e5f91bf24d259bef6c73 (patch)
tree4d0a51ea750d2094798dfd3b2d62c534cd6a7cb6
parent25c3f231bc880acad1146be13aa5e672a9ffbf81 (diff)
downloadrenesas_kernel-535e6b92647b7eff5e08e5f91bf24d259bef6c73.tar.gz
renesas_kernel-535e6b92647b7eff5e08e5f91bf24d259bef6c73.tar.bz2
renesas_kernel-535e6b92647b7eff5e08e5f91bf24d259bef6c73.zip
drm: rcar-du: Add interlaced mode support
Change-Id: Ibbebf7ce4e740af149de25e448c98ca8ca7ed53b Signed-off-by: Koji Matsuoka <koji.matsuoka.xm@renesas.com> Signed-off-by: Damian Hobson-Garcia <dhobsong@igel.co.jp>
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c52
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c11
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.h1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c17
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_regs.h1
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 8b0545c35b0..79d6ddba035 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 0a724669f02..fdd645b2eac 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 4e7614b145d..2d3495bf681 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 0c38cdcda4c..d8d0a8c953c 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 4d7d4dd46d2..1678a3139f5 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 72a7cb47bd9..0f422f95910 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 3021288b1a8..89e4e136bb7 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 73f7347f740..3ef4579ae56 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)