drm/rcar-du: Add support for multiple groups

The R8A7790 DU has 3 CRTCs, split in two groups. Support them.

Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
This commit is contained in:
Laurent Pinchart 2013-06-17 00:29:25 +02:00
parent 9e2d2de9e8
commit a5f0ef593c
8 changed files with 63 additions and 30 deletions

View File

@ -91,7 +91,6 @@ static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc) static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{ {
const struct drm_display_mode *mode = &rcrtc->crtc.mode; const struct drm_display_mode *mode = &rcrtc->crtc.mode;
struct rcar_du_device *rcdu = rcrtc->group->dev;
unsigned long clk; unsigned long clk;
u32 value; u32 value;
u32 div; u32 div;
@ -101,9 +100,9 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000); div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
div = clamp(div, 1U, 64U) - 1; div = clamp(div, 1U, 64U) - 1;
rcar_du_write(rcdu, rcrtc->index ? ESCR2 : ESCR, rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
ESCR_DCLKSEL_CLKS | div); ESCR_DCLKSEL_CLKS | div);
rcar_du_write(rcdu, rcrtc->index ? OTAR2 : OTAR, 0); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
/* Signal polarities */ /* Signal polarities */
value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL) value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
@ -143,7 +142,6 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc, unsigned int output)
void rcar_du_crtc_update_planes(struct drm_crtc *crtc) void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
{ {
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
struct rcar_du_device *rcdu = rcrtc->group->dev;
struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES];
unsigned int num_planes = 0; unsigned int num_planes = 0;
unsigned int prio = 0; unsigned int prio = 0;
@ -189,8 +187,8 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
/* Select display timing and dot clock generator 2 for planes associated /* Select display timing and dot clock generator 2 for planes associated
* with superposition controller 2. * with superposition controller 2.
*/ */
if (rcrtc->index) { if (rcrtc->index % 2) {
u32 value = rcar_du_read(rcdu, DPTSR); u32 value = rcar_du_group_read(rcrtc->group, DPTSR);
/* The DPTSR register is updated when the display controller is /* The DPTSR register is updated when the display controller is
* stopped. We thus need to restart the DU. Once again, sorry * stopped. We thus need to restart the DU. Once again, sorry
@ -200,13 +198,14 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
* occur only if we need to break the pre-association. * occur only if we need to break the pre-association.
*/ */
if (value != dptsr) { if (value != dptsr) {
rcar_du_write(rcdu, DPTSR, dptsr); rcar_du_group_write(rcrtc->group, DPTSR, dptsr);
if (rcrtc->group->used_crtcs) if (rcrtc->group->used_crtcs)
rcar_du_group_restart(rcrtc->group); rcar_du_group_restart(rcrtc->group);
} }
} }
rcar_du_write(rcdu, rcrtc->index ? DS2PR : DS1PR, dspr); rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
dspr);
} }
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc) static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
@ -528,6 +527,10 @@ static const struct drm_crtc_funcs crtc_funcs = {
int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
{ {
static const unsigned int mmio_offsets[] = {
DU0_REG_OFFSET, DU1_REG_OFFSET, DU2_REG_OFFSET
};
struct rcar_du_device *rcdu = rgrp->dev; struct rcar_du_device *rcdu = rgrp->dev;
struct platform_device *pdev = to_platform_device(rcdu->dev); struct platform_device *pdev = to_platform_device(rcdu->dev);
struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index]; struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
@ -553,10 +556,10 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
} }
rcrtc->group = rgrp; rcrtc->group = rgrp;
rcrtc->mmio_offset = index ? DISP2_REG_OFFSET : 0; rcrtc->mmio_offset = mmio_offsets[index];
rcrtc->index = index; rcrtc->index = index;
rcrtc->dpms = DRM_MODE_DPMS_OFF; rcrtc->dpms = DRM_MODE_DPMS_OFF;
rcrtc->plane = &rgrp->planes.planes[index]; rcrtc->plane = &rgrp->planes.planes[index % 2];
rcrtc->plane->crtc = crtc; rcrtc->plane->crtc = crtc;

View File

@ -218,10 +218,12 @@ static int rcar_du_remove(struct platform_device *pdev)
static const struct rcar_du_device_info rcar_du_r8a7779_info = { static const struct rcar_du_device_info rcar_du_r8a7779_info = {
.features = 0, .features = 0,
.num_crtcs = 2,
}; };
static const struct rcar_du_device_info rcar_du_r8a7790_info = { static const struct rcar_du_device_info rcar_du_r8a7790_info = {
.features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B, .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B,
.num_crtcs = 3,
}; };
static const struct platform_device_id rcar_du_id_table[] = { static const struct platform_device_id rcar_du_id_table[] = {

View File

@ -31,9 +31,11 @@ struct rcar_du_device;
/* /*
* struct rcar_du_device_info - DU model-specific information * struct rcar_du_device_info - DU model-specific information
* @features: device features (RCAR_DU_FEATURE_*) * @features: device features (RCAR_DU_FEATURE_*)
* @num_crtcs: total number of CRTCs
*/ */
struct rcar_du_device_info { struct rcar_du_device_info {
unsigned int features; unsigned int features;
unsigned int num_crtcs;
}; };
struct rcar_du_device { struct rcar_du_device {
@ -45,10 +47,10 @@ struct rcar_du_device {
struct drm_device *ddev; struct drm_device *ddev;
struct rcar_du_crtc crtcs[2]; struct rcar_du_crtc crtcs[3];
unsigned int num_crtcs; unsigned int num_crtcs;
struct rcar_du_group group; struct rcar_du_group groups[2];
}; };
static inline bool rcar_du_has(struct rcar_du_device *rcdu, static inline bool rcar_du_has(struct rcar_du_device *rcdu,

View File

@ -33,12 +33,12 @@
#include "rcar_du_group.h" #include "rcar_du_group.h"
#include "rcar_du_regs.h" #include "rcar_du_regs.h"
static u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg) u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg)
{ {
return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg); return rcar_du_read(rgrp->dev, rgrp->mmio_offset + reg);
} }
static void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data) void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data)
{ {
rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data); rcar_du_write(rgrp->dev, rgrp->mmio_offset + reg, data);
} }

View File

@ -38,6 +38,9 @@ struct rcar_du_group {
struct rcar_du_planes planes; struct rcar_du_planes planes;
}; };
u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg);
void rcar_du_group_write(struct rcar_du_group *rgrp, u32 reg, u32 data);
int rcar_du_group_get(struct rcar_du_group *rgrp); int rcar_du_group_get(struct rcar_du_group *rgrp);
void rcar_du_group_put(struct rcar_du_group *rgrp); void rcar_du_group_put(struct rcar_du_group *rgrp);
void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start); void rcar_du_group_start_stop(struct rcar_du_group *rgrp, bool start);

View File

@ -172,8 +172,13 @@ static const struct drm_mode_config_funcs rcar_du_mode_config_funcs = {
int rcar_du_modeset_init(struct rcar_du_device *rcdu) int rcar_du_modeset_init(struct rcar_du_device *rcdu)
{ {
static const unsigned int mmio_offsets[] = {
DU0_REG_OFFSET, DU2_REG_OFFSET
};
struct drm_device *dev = rcdu->ddev; struct drm_device *dev = rcdu->ddev;
struct drm_encoder *encoder; struct drm_encoder *encoder;
unsigned int num_groups;
unsigned int i; unsigned int i;
int ret; int ret;
@ -185,22 +190,33 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
rcdu->ddev->mode_config.max_height = 2047; rcdu->ddev->mode_config.max_height = 2047;
rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs; rcdu->ddev->mode_config.funcs = &rcar_du_mode_config_funcs;
rcdu->group.dev = rcdu; rcdu->num_crtcs = rcdu->info->num_crtcs;
rcdu->group.index = 0;
rcdu->group.used_crtcs = 0;
ret = rcar_du_planes_init(&rcdu->group); /* Initialize the groups. */
if (ret < 0) num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
return ret;
for (i = 0; i < ARRAY_SIZE(rcdu->crtcs); ++i) { for (i = 0; i < num_groups; ++i) {
ret = rcar_du_crtc_create(&rcdu->group, i); struct rcar_du_group *rgrp = &rcdu->groups[i];
rgrp->dev = rcdu;
rgrp->mmio_offset = mmio_offsets[i];
rgrp->index = i;
ret = rcar_du_planes_init(rgrp);
if (ret < 0) if (ret < 0)
return ret; return ret;
} }
rcdu->num_crtcs = i; /* Create the CRTCs. */
for (i = 0; i < rcdu->num_crtcs; ++i) {
struct rcar_du_group *rgrp = &rcdu->groups[i / 2];
ret = rcar_du_crtc_create(rgrp, i);
if (ret < 0)
return ret;
}
/* Initialize the encoders. */
for (i = 0; i < rcdu->pdata->num_encoders; ++i) { for (i = 0; i < rcdu->pdata->num_encoders; ++i) {
const struct rcar_du_encoder_data *pdata = const struct rcar_du_encoder_data *pdata =
&rcdu->pdata->encoders[i]; &rcdu->pdata->encoders[i];
@ -229,9 +245,12 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
encoder->possible_clones = 1 << 0; encoder->possible_clones = 1 << 0;
} }
ret = rcar_du_planes_register(&rcdu->group); /* Now that the CRTCs have been initialized register the planes. */
if (ret < 0) for (i = 0; i < num_groups; ++i) {
return ret; ret = rcar_du_planes_register(&rcdu->groups[i]);
if (ret < 0)
return ret;
}
drm_kms_helper_poll_init(rcdu->ddev); drm_kms_helper_poll_init(rcdu->ddev);

View File

@ -480,9 +480,12 @@ int rcar_du_planes_register(struct rcar_du_group *rgrp)
{ {
struct rcar_du_planes *planes = &rgrp->planes; struct rcar_du_planes *planes = &rgrp->planes;
struct rcar_du_device *rcdu = rgrp->dev; struct rcar_du_device *rcdu = rgrp->dev;
unsigned int crtcs;
unsigned int i; unsigned int i;
int ret; int ret;
crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) { for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
struct rcar_du_kms_plane *plane; struct rcar_du_kms_plane *plane;
@ -493,8 +496,7 @@ int rcar_du_planes_register(struct rcar_du_group *rgrp)
plane->hwplane = &planes->planes[i + 2]; plane->hwplane = &planes->planes[i + 2];
plane->hwplane->zpos = 1; plane->hwplane->zpos = 1;
ret = drm_plane_init(rcdu->ddev, &plane->plane, ret = drm_plane_init(rcdu->ddev, &plane->plane, crtcs,
(1 << rcdu->num_crtcs) - 1,
&rcar_du_plane_funcs, formats, &rcar_du_plane_funcs, formats,
ARRAY_SIZE(formats), false); ARRAY_SIZE(formats), false);
if (ret < 0) if (ret < 0)

View File

@ -13,7 +13,9 @@
#ifndef __RCAR_DU_REGS_H__ #ifndef __RCAR_DU_REGS_H__
#define __RCAR_DU_REGS_H__ #define __RCAR_DU_REGS_H__
#define DISP2_REG_OFFSET 0x30000 #define DU0_REG_OFFSET 0x00000
#define DU1_REG_OFFSET 0x30000
#define DU2_REG_OFFSET 0x40000
/* ----------------------------------------------------------------------------- /* -----------------------------------------------------------------------------
* Display Control Registers * Display Control Registers