Commit 906eff7f authored by Laurent Pinchart's avatar Laurent Pinchart

drm: rcar-du: Implement support for interlaced modes

Accept interlaced modes on the VGA and HDMI connectors and configure the
hardware accordingly.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
parent 3dbf11e4
...@@ -155,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) ...@@ -155,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
mode->hsync_start - 1); mode->hsync_start - 1);
rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 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, VDSR, mode->crtc_vtotal -
rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end + mode->crtc_vsync_end - 2);
mode->vdisplay - 2); rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end + mode->crtc_vsync_end +
mode->vsync_start - 1); mode->crtc_vdisplay - 2);
rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1); 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, DESR, mode->htotal - mode->hsync_start);
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay); rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
...@@ -256,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc) ...@@ -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) static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{ {
struct drm_crtc *crtc = &rcrtc->crtc; struct drm_crtc *crtc = &rcrtc->crtc;
bool interlaced;
unsigned int i; unsigned int i;
if (rcrtc->started) if (rcrtc->started)
...@@ -291,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) ...@@ -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 * sync mode (with the HSYNC and VSYNC signals configured as outputs and
* actively driven). * 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); rcar_du_group_start_stop(rcrtc->group, true);
...@@ -528,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg) ...@@ -528,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
status = rcar_du_crtc_read(rcrtc, DSSR); status = rcar_du_crtc_read(rcrtc, DSSR);
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK); 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); drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
rcar_du_crtc_finish_page_flip(rcrtc); rcar_du_crtc_finish_page_flip(rcrtc);
ret = IRQ_HANDLED; ret = IRQ_HANDLED;
......
...@@ -95,6 +95,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu, ...@@ -95,6 +95,7 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
connector = &rcon->connector; connector = &rcon->connector;
connector->display_info.width_mm = 0; connector->display_info.width_mm = 0;
connector->display_info.height_mm = 0; connector->display_info.height_mm = 0;
connector->interlace_allowed = true;
connector->polled = DRM_CONNECTOR_POLL_HPD; connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
......
...@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane) ...@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
{ {
struct rcar_du_group *rgrp = plane->group; struct rcar_du_group *rgrp = plane->group;
unsigned int index = plane->hwindex; unsigned int index = plane->hwindex;
bool interlaced;
u32 mwr; 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) if (plane->format->planes == 2)
mwr = plane->pitch; mwr = plane->pitch;
else else
mwr = plane->pitch * 8 / plane->format->bpp; mwr = plane->pitch * 8 / plane->format->bpp;
if (interlaced && plane->format->bpp == 32)
mwr *= 2;
rcar_du_plane_write(rgrp, index, PnMWR, mwr); rcar_du_plane_write(rgrp, index, PnMWR, mwr);
/* The Y position is expressed in raster line units and must be doubled /* 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) ...@@ -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 * doubling the Y position is found in the R8A7779 datasheet, but the
* rule seems to apply there as well. * 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 * 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, PnSPXR, plane->src_x);
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y * 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]); rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
if (plane->format->planes == 2) { if (plane->format->planes == 2) {
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#define DSYSR_SCM_INT_NONE (0 << 4) #define DSYSR_SCM_INT_NONE (0 << 4)
#define DSYSR_SCM_INT_SYNC (2 << 4) #define DSYSR_SCM_INT_SYNC (2 << 4)
#define DSYSR_SCM_INT_VIDEO (3 << 4) #define DSYSR_SCM_INT_VIDEO (3 << 4)
#define DSYSR_SCM_MASK (3 << 4)
#define DSMR 0x00004 #define DSMR 0x00004
#define DSMR_VSPM (1 << 28) #define DSMR_VSPM (1 << 28)
......
...@@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu, ...@@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
connector = &rcon->connector; connector = &rcon->connector;
connector->display_info.width_mm = 0; connector->display_info.width_mm = 0;
connector->display_info.height_mm = 0; connector->display_info.height_mm = 0;
connector->interlace_allowed = true;
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs, ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_VGA); DRM_MODE_CONNECTOR_VGA);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment