mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-28 13:34:38 +08:00
Merge branch 'drm/next/rcar-du' of git://linuxtv.org/pinchartl/fbdev into drm-next
rcar-du fixes * 'drm/next/rcar-du' of git://linuxtv.org/pinchartl/fbdev: drm: rcar-du: Split planes pre-association 4/4 between CRTCs drm: rcar-du: Store the number of CRTCs per group in the group structure drm: rcar-du: Consider plane to CRTC associations in the plane allocator drm: rcar-du: Keep plane to CRTC associations when disabling a plane drm: rcar-du: Add plane allocation debugging drm: rcar-du: Rename to_rcar_du_plane_state to to_rcar_plane_state drm: rcar-du: Embed rcar_du_planes structure into rcar_du_group drm: rcar-du: Move properties from rcar_du_planes to rcar_du_device drm: rcar-du: Document the rcar_du_plane_state structure drm: rcar-du: Document the rcar_du_crtc structure
This commit is contained in:
commit
f025705e73
@ -195,26 +195,27 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
|
|||||||
|
|
||||||
static unsigned int plane_zpos(struct rcar_du_plane *plane)
|
static unsigned int plane_zpos(struct rcar_du_plane *plane)
|
||||||
{
|
{
|
||||||
return to_rcar_du_plane_state(plane->plane.state)->zpos;
|
return to_rcar_plane_state(plane->plane.state)->zpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct rcar_du_format_info *
|
static const struct rcar_du_format_info *
|
||||||
plane_format(struct rcar_du_plane *plane)
|
plane_format(struct rcar_du_plane *plane)
|
||||||
{
|
{
|
||||||
return to_rcar_du_plane_state(plane->plane.state)->format;
|
return to_rcar_plane_state(plane->plane.state)->format;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
|
static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
|
||||||
{
|
{
|
||||||
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 dptsr_planes;
|
||||||
|
unsigned int hwplanes = 0;
|
||||||
unsigned int prio = 0;
|
unsigned int prio = 0;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
u32 dptsr = 0;
|
|
||||||
u32 dspr = 0;
|
u32 dspr = 0;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
|
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
|
||||||
struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
|
struct rcar_du_plane *plane = &rcrtc->group->planes[i];
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
|
|
||||||
if (plane->plane.state->crtc != &rcrtc->crtc)
|
if (plane->plane.state->crtc != &rcrtc->crtc)
|
||||||
@ -234,41 +235,45 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
|
|||||||
for (i = 0; i < num_planes; ++i) {
|
for (i = 0; i < num_planes; ++i) {
|
||||||
struct rcar_du_plane *plane = planes[i];
|
struct rcar_du_plane *plane = planes[i];
|
||||||
struct drm_plane_state *state = plane->plane.state;
|
struct drm_plane_state *state = plane->plane.state;
|
||||||
unsigned int index = to_rcar_du_plane_state(state)->hwindex;
|
unsigned int index = to_rcar_plane_state(state)->hwindex;
|
||||||
|
|
||||||
prio -= 4;
|
prio -= 4;
|
||||||
dspr |= (index + 1) << prio;
|
dspr |= (index + 1) << prio;
|
||||||
dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
|
hwplanes |= 1 << index;
|
||||||
|
|
||||||
if (plane_format(plane)->planes == 2) {
|
if (plane_format(plane)->planes == 2) {
|
||||||
index = (index + 1) % 8;
|
index = (index + 1) % 8;
|
||||||
|
|
||||||
prio -= 4;
|
prio -= 4;
|
||||||
dspr |= (index + 1) << prio;
|
dspr |= (index + 1) << prio;
|
||||||
dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index);
|
hwplanes |= 1 << index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Select display timing and dot clock generator 2 for planes associated
|
/* Update the planes to display timing and dot clock generator
|
||||||
* with superposition controller 2.
|
* associations.
|
||||||
|
*
|
||||||
|
* Updating the DPTSR register requires restarting the CRTC group,
|
||||||
|
* resulting in visible flicker. To mitigate the issue only update the
|
||||||
|
* association if needed by enabled planes. Planes being disabled will
|
||||||
|
* keep their current association.
|
||||||
*/
|
*/
|
||||||
if (rcrtc->index % 2) {
|
mutex_lock(&rcrtc->group->lock);
|
||||||
/* The DPTSR register is updated when the display controller is
|
|
||||||
* stopped. We thus need to restart the DU. Once again, sorry
|
dptsr_planes = rcrtc->index % 2 ? rcrtc->group->dptsr_planes | hwplanes
|
||||||
* for the flicker. One way to mitigate the issue would be to
|
: rcrtc->group->dptsr_planes & ~hwplanes;
|
||||||
* pre-associate planes with CRTCs (either with a fixed 4/4
|
|
||||||
* split, or through a module parameter). Flicker would then
|
if (dptsr_planes != rcrtc->group->dptsr_planes) {
|
||||||
* occur only if we need to break the pre-association.
|
rcar_du_group_write(rcrtc->group, DPTSR,
|
||||||
*/
|
(dptsr_planes << 16) | dptsr_planes);
|
||||||
mutex_lock(&rcrtc->group->lock);
|
rcrtc->group->dptsr_planes = dptsr_planes;
|
||||||
if (rcar_du_group_read(rcrtc->group, 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);
|
|
||||||
}
|
|
||||||
mutex_unlock(&rcrtc->group->lock);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&rcrtc->group->lock);
|
||||||
|
|
||||||
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
|
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR,
|
||||||
dspr);
|
dspr);
|
||||||
}
|
}
|
||||||
@ -427,8 +432,8 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc)
|
|||||||
rcar_du_crtc_start(rcrtc);
|
rcar_du_crtc_start(rcrtc);
|
||||||
|
|
||||||
/* Commit the planes state. */
|
/* Commit the planes state. */
|
||||||
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) {
|
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
|
||||||
struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i];
|
struct rcar_du_plane *plane = &rcrtc->group->planes[i];
|
||||||
|
|
||||||
if (plane->plane.state->crtc != &rcrtc->crtc)
|
if (plane->plane.state->crtc != &rcrtc->crtc)
|
||||||
continue;
|
continue;
|
||||||
@ -592,7 +597,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
|
|||||||
rcrtc->enabled = false;
|
rcrtc->enabled = false;
|
||||||
|
|
||||||
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc,
|
ret = drm_crtc_init_with_planes(rcdu->ddev, crtc,
|
||||||
&rgrp->planes.planes[index % 2].plane,
|
&rgrp->planes[index % 2].plane,
|
||||||
NULL, &crtc_funcs);
|
NULL, &crtc_funcs);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -22,6 +22,20 @@
|
|||||||
|
|
||||||
struct rcar_du_group;
|
struct rcar_du_group;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct rcar_du_crtc - the CRTC, representing a DU superposition processor
|
||||||
|
* @crtc: base DRM CRTC
|
||||||
|
* @clock: the CRTC functional clock
|
||||||
|
* @extclock: external pixel dot clock (optional)
|
||||||
|
* @mmio_offset: offset of the CRTC registers in the DU MMIO block
|
||||||
|
* @index: CRTC software and hardware index
|
||||||
|
* @started: whether the CRTC has been started and is running
|
||||||
|
* @event: event to post when the pending page flip completes
|
||||||
|
* @flip_wait: wait queue used to signal page flip completion
|
||||||
|
* @outputs: bitmask of the outputs (enum rcar_du_output) driven by this CRTC
|
||||||
|
* @enabled: whether the CRTC is enabled, used to control system resume
|
||||||
|
* @group: CRTC group this CRTC belongs to
|
||||||
|
*/
|
||||||
struct rcar_du_crtc {
|
struct rcar_du_crtc {
|
||||||
struct drm_crtc crtc;
|
struct drm_crtc crtc;
|
||||||
|
|
||||||
|
@ -83,6 +83,12 @@ struct rcar_du_device {
|
|||||||
|
|
||||||
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
|
struct rcar_du_group groups[RCAR_DU_MAX_GROUPS];
|
||||||
|
|
||||||
|
struct {
|
||||||
|
struct drm_property *alpha;
|
||||||
|
struct drm_property *colorkey;
|
||||||
|
struct drm_property *zpos;
|
||||||
|
} props;
|
||||||
|
|
||||||
unsigned int dpad0_source;
|
unsigned int dpad0_source;
|
||||||
struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
|
struct rcar_du_lvdsenc *lvds[RCAR_DU_MAX_LVDS];
|
||||||
|
|
||||||
|
@ -85,6 +85,12 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
|
|||||||
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
|
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
|
||||||
*/
|
*/
|
||||||
rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
|
rcar_du_group_write(rgrp, DORCR, DORCR_PG1D_DS1 | DORCR_DPRS);
|
||||||
|
|
||||||
|
/* Apply planes to CRTCs association. */
|
||||||
|
mutex_lock(&rgrp->lock);
|
||||||
|
rcar_du_group_write(rgrp, DPTSR, (rgrp->dptsr_planes << 16) |
|
||||||
|
rgrp->dptsr_planes);
|
||||||
|
mutex_unlock(&rgrp->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -25,9 +25,11 @@ struct rcar_du_device;
|
|||||||
* @dev: the DU device
|
* @dev: the DU device
|
||||||
* @mmio_offset: registers offset in the device memory map
|
* @mmio_offset: registers offset in the device memory map
|
||||||
* @index: group index
|
* @index: group index
|
||||||
|
* @num_crtcs: number of CRTCs in this group (1 or 2)
|
||||||
* @use_count: number of users of the group (rcar_du_group_(get|put))
|
* @use_count: number of users of the group (rcar_du_group_(get|put))
|
||||||
* @used_crtcs: number of CRTCs currently in use
|
* @used_crtcs: number of CRTCs currently in use
|
||||||
* @lock: protects the DPTSR register
|
* @lock: protects the dptsr_planes field and the DPTSR register
|
||||||
|
* @dptsr_planes: bitmask of planes driven by dot-clock and timing generator 1
|
||||||
* @planes: planes handled by the group
|
* @planes: planes handled by the group
|
||||||
*/
|
*/
|
||||||
struct rcar_du_group {
|
struct rcar_du_group {
|
||||||
@ -35,12 +37,14 @@ struct rcar_du_group {
|
|||||||
unsigned int mmio_offset;
|
unsigned int mmio_offset;
|
||||||
unsigned int index;
|
unsigned int index;
|
||||||
|
|
||||||
|
unsigned int num_crtcs;
|
||||||
unsigned int use_count;
|
unsigned int use_count;
|
||||||
unsigned int used_crtcs;
|
unsigned int used_crtcs;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
unsigned int dptsr_planes;
|
||||||
|
|
||||||
struct rcar_du_planes planes;
|
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
|
||||||
};
|
};
|
||||||
|
|
||||||
u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg);
|
u32 rcar_du_group_read(struct rcar_du_group *rgrp, u32 reg);
|
||||||
|
@ -221,7 +221,7 @@ static bool rcar_du_plane_needs_realloc(struct rcar_du_plane *plane,
|
|||||||
{
|
{
|
||||||
const struct rcar_du_format_info *cur_format;
|
const struct rcar_du_format_info *cur_format;
|
||||||
|
|
||||||
cur_format = to_rcar_du_plane_state(plane->plane.state)->format;
|
cur_format = to_rcar_plane_state(plane->plane.state)->format;
|
||||||
|
|
||||||
/* Lowering the number of planes doesn't strictly require reallocation
|
/* Lowering the number of planes doesn't strictly require reallocation
|
||||||
* as the extra hardware plane will be freed when committing, but doing
|
* as the extra hardware plane will be freed when committing, but doing
|
||||||
@ -284,14 +284,19 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
plane = to_rcar_plane(state->planes[i]);
|
plane = to_rcar_plane(state->planes[i]);
|
||||||
plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
plane_state = to_rcar_plane_state(state->plane_states[i]);
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: checking plane (%u,%u)\n", __func__,
|
||||||
|
plane->group->index, plane - plane->group->planes);
|
||||||
|
|
||||||
/* If the plane is being disabled we don't need to go through
|
/* If the plane is being disabled we don't need to go through
|
||||||
* the full reallocation procedure. Just mark the hardware
|
* the full reallocation procedure. Just mark the hardware
|
||||||
* plane(s) as freed.
|
* plane(s) as freed.
|
||||||
*/
|
*/
|
||||||
if (!plane_state->format) {
|
if (!plane_state->format) {
|
||||||
index = plane - plane->group->planes.planes;
|
dev_dbg(rcdu->dev, "%s: plane is being disabled\n",
|
||||||
|
__func__);
|
||||||
|
index = plane - plane->group->planes;
|
||||||
group_freed_planes[plane->group->index] |= 1 << index;
|
group_freed_planes[plane->group->index] |= 1 << index;
|
||||||
plane_state->hwindex = -1;
|
plane_state->hwindex = -1;
|
||||||
continue;
|
continue;
|
||||||
@ -301,10 +306,12 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||||||
* mark the hardware plane(s) as free.
|
* mark the hardware plane(s) as free.
|
||||||
*/
|
*/
|
||||||
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
|
if (rcar_du_plane_needs_realloc(plane, plane_state)) {
|
||||||
|
dev_dbg(rcdu->dev, "%s: plane needs reallocation\n",
|
||||||
|
__func__);
|
||||||
groups |= 1 << plane->group->index;
|
groups |= 1 << plane->group->index;
|
||||||
needs_realloc = true;
|
needs_realloc = true;
|
||||||
|
|
||||||
index = plane - plane->group->planes.planes;
|
index = plane - plane->group->planes;
|
||||||
group_freed_planes[plane->group->index] |= 1 << index;
|
group_freed_planes[plane->group->index] |= 1 << index;
|
||||||
plane_state->hwindex = -1;
|
plane_state->hwindex = -1;
|
||||||
}
|
}
|
||||||
@ -326,8 +333,11 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||||||
struct rcar_du_group *group = &rcdu->groups[index];
|
struct rcar_du_group *group = &rcdu->groups[index];
|
||||||
unsigned int used_planes = 0;
|
unsigned int used_planes = 0;
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: finding free planes for group %u\n",
|
||||||
|
__func__, index);
|
||||||
|
|
||||||
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
|
for (i = 0; i < RCAR_DU_NUM_KMS_PLANES; ++i) {
|
||||||
struct rcar_du_plane *plane = &group->planes.planes[i];
|
struct rcar_du_plane *plane = &group->planes[i];
|
||||||
struct rcar_du_plane_state *plane_state;
|
struct rcar_du_plane_state *plane_state;
|
||||||
struct drm_plane_state *s;
|
struct drm_plane_state *s;
|
||||||
|
|
||||||
@ -342,28 +352,49 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||||||
* above. Use the local freed planes list to check for
|
* above. Use the local freed planes list to check for
|
||||||
* that condition instead.
|
* that condition instead.
|
||||||
*/
|
*/
|
||||||
if (group_freed_planes[index] & (1 << i))
|
if (group_freed_planes[index] & (1 << i)) {
|
||||||
|
dev_dbg(rcdu->dev,
|
||||||
|
"%s: plane (%u,%u) has been freed, skipping\n",
|
||||||
|
__func__, plane->group->index,
|
||||||
|
plane - plane->group->planes);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
plane_state = to_rcar_du_plane_state(plane->plane.state);
|
plane_state = to_rcar_plane_state(plane->plane.state);
|
||||||
used_planes |= rcar_du_plane_hwmask(plane_state);
|
used_planes |= rcar_du_plane_hwmask(plane_state);
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev,
|
||||||
|
"%s: plane (%u,%u) uses %u hwplanes (index %d)\n",
|
||||||
|
__func__, plane->group->index,
|
||||||
|
plane - plane->group->planes,
|
||||||
|
plane_state->format ?
|
||||||
|
plane_state->format->planes : 0,
|
||||||
|
plane_state->hwindex);
|
||||||
}
|
}
|
||||||
|
|
||||||
group_free_planes[index] = 0xff & ~used_planes;
|
group_free_planes[index] = 0xff & ~used_planes;
|
||||||
groups &= ~(1 << index);
|
groups &= ~(1 << index);
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
|
||||||
|
__func__, index, group_free_planes[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reallocate hardware planes for each plane that needs it. */
|
/* Reallocate hardware planes for each plane that needs it. */
|
||||||
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
for (i = 0; i < dev->mode_config.num_total_plane; ++i) {
|
||||||
struct rcar_du_plane_state *plane_state;
|
struct rcar_du_plane_state *plane_state;
|
||||||
struct rcar_du_plane *plane;
|
struct rcar_du_plane *plane;
|
||||||
|
unsigned int crtc_planes;
|
||||||
|
unsigned int free;
|
||||||
int idx;
|
int idx;
|
||||||
|
|
||||||
if (!state->planes[i])
|
if (!state->planes[i])
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
plane = to_rcar_plane(state->planes[i]);
|
plane = to_rcar_plane(state->planes[i]);
|
||||||
plane_state = to_rcar_du_plane_state(state->plane_states[i]);
|
plane_state = to_rcar_plane_state(state->plane_states[i]);
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: allocating plane (%u,%u)\n", __func__,
|
||||||
|
plane->group->index, plane - plane->group->planes);
|
||||||
|
|
||||||
/* Skip planes that are being disabled or don't need to be
|
/* Skip planes that are being disabled or don't need to be
|
||||||
* reallocated.
|
* reallocated.
|
||||||
@ -372,18 +403,38 @@ static int rcar_du_atomic_check(struct drm_device *dev,
|
|||||||
!rcar_du_plane_needs_realloc(plane, plane_state))
|
!rcar_du_plane_needs_realloc(plane, plane_state))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
/* Try to allocate the plane from the free planes currently
|
||||||
|
* associated with the target CRTC to avoid restarting the CRTC
|
||||||
|
* group and thus minimize flicker. If it fails fall back to
|
||||||
|
* allocating from all free planes.
|
||||||
|
*/
|
||||||
|
crtc_planes = to_rcar_crtc(plane_state->state.crtc)->index % 2
|
||||||
|
? plane->group->dptsr_planes
|
||||||
|
: ~plane->group->dptsr_planes;
|
||||||
|
free = group_free_planes[plane->group->index];
|
||||||
|
|
||||||
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
||||||
group_free_planes[plane->group->index]);
|
free & crtc_planes);
|
||||||
|
if (idx < 0)
|
||||||
|
idx = rcar_du_plane_hwalloc(plane_state->format->planes,
|
||||||
|
free);
|
||||||
if (idx < 0) {
|
if (idx < 0) {
|
||||||
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
|
dev_dbg(rcdu->dev, "%s: no available hardware plane\n",
|
||||||
__func__);
|
__func__);
|
||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: allocated %u hwplanes (index %u)\n",
|
||||||
|
__func__, plane_state->format->planes, idx);
|
||||||
|
|
||||||
plane_state->hwindex = idx;
|
plane_state->hwindex = idx;
|
||||||
|
|
||||||
group_free_planes[plane->group->index] &=
|
group_free_planes[plane->group->index] &=
|
||||||
~rcar_du_plane_hwmask(plane_state);
|
~rcar_du_plane_hwmask(plane_state);
|
||||||
|
|
||||||
|
dev_dbg(rcdu->dev, "%s: group %u free planes mask 0x%02x\n",
|
||||||
|
__func__, plane->group->index,
|
||||||
|
group_free_planes[plane->group->index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -648,6 +699,31 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
|
|||||||
return num_encoders;
|
return num_encoders;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rcar_du_properties_init(struct rcar_du_device *rcdu)
|
||||||
|
{
|
||||||
|
rcdu->props.alpha =
|
||||||
|
drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
|
||||||
|
if (rcdu->props.alpha == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
/* The color key is expressed as an RGB888 triplet stored in a 32-bit
|
||||||
|
* integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
|
||||||
|
* or enable source color keying (1).
|
||||||
|
*/
|
||||||
|
rcdu->props.colorkey =
|
||||||
|
drm_property_create_range(rcdu->ddev, 0, "colorkey",
|
||||||
|
0, 0x01ffffff);
|
||||||
|
if (rcdu->props.colorkey == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
rcdu->props.zpos =
|
||||||
|
drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
|
||||||
|
if (rcdu->props.zpos == NULL)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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[] = {
|
static const unsigned int mmio_offsets[] = {
|
||||||
@ -672,6 +748,10 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|||||||
|
|
||||||
rcdu->num_crtcs = rcdu->info->num_crtcs;
|
rcdu->num_crtcs = rcdu->info->num_crtcs;
|
||||||
|
|
||||||
|
ret = rcar_du_properties_init(rcdu);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/* Initialize the groups. */
|
/* Initialize the groups. */
|
||||||
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
|
num_groups = DIV_ROUND_UP(rcdu->num_crtcs, 2);
|
||||||
|
|
||||||
@ -683,6 +763,13 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
|
|||||||
rgrp->dev = rcdu;
|
rgrp->dev = rcdu;
|
||||||
rgrp->mmio_offset = mmio_offsets[i];
|
rgrp->mmio_offset = mmio_offsets[i];
|
||||||
rgrp->index = i;
|
rgrp->index = i;
|
||||||
|
rgrp->num_crtcs = min(rcdu->num_crtcs - 2 * i, 2U);
|
||||||
|
|
||||||
|
/* If we have more than one CRTCs in this group pre-associate
|
||||||
|
* planes 0-3 with CRTC 0 and planes 4-7 with CRTC 1 to minimize
|
||||||
|
* flicker occurring when the association is changed.
|
||||||
|
*/
|
||||||
|
rgrp->dptsr_planes = rgrp->num_crtcs > 1 ? 0xf0 : 0;
|
||||||
|
|
||||||
ret = rcar_du_planes_init(rgrp);
|
ret = rcar_du_planes_init(rgrp);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
@ -45,7 +45,7 @@ static void rcar_du_plane_write(struct rcar_du_group *rgrp,
|
|||||||
static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane)
|
static void rcar_du_plane_setup_fb(struct rcar_du_plane *plane)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *state =
|
struct rcar_du_plane_state *state =
|
||||||
to_rcar_du_plane_state(plane->plane.state);
|
to_rcar_plane_state(plane->plane.state);
|
||||||
struct drm_framebuffer *fb = plane->plane.state->fb;
|
struct drm_framebuffer *fb = plane->plane.state->fb;
|
||||||
struct rcar_du_group *rgrp = plane->group;
|
struct rcar_du_group *rgrp = plane->group;
|
||||||
unsigned int src_x = state->state.src_x >> 16;
|
unsigned int src_x = state->state.src_x >> 16;
|
||||||
@ -109,7 +109,7 @@ static void rcar_du_plane_setup_mode(struct rcar_du_plane *plane,
|
|||||||
unsigned int index)
|
unsigned int index)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *state =
|
struct rcar_du_plane_state *state =
|
||||||
to_rcar_du_plane_state(plane->plane.state);
|
to_rcar_plane_state(plane->plane.state);
|
||||||
struct rcar_du_group *rgrp = plane->group;
|
struct rcar_du_group *rgrp = plane->group;
|
||||||
u32 colorkey;
|
u32 colorkey;
|
||||||
u32 pnmr;
|
u32 pnmr;
|
||||||
@ -172,7 +172,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
|
|||||||
unsigned int index)
|
unsigned int index)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *state =
|
struct rcar_du_plane_state *state =
|
||||||
to_rcar_du_plane_state(plane->plane.state);
|
to_rcar_plane_state(plane->plane.state);
|
||||||
struct rcar_du_group *rgrp = plane->group;
|
struct rcar_du_group *rgrp = plane->group;
|
||||||
u32 ddcr2 = PnDDCR2_CODE;
|
u32 ddcr2 = PnDDCR2_CODE;
|
||||||
u32 ddcr4;
|
u32 ddcr4;
|
||||||
@ -222,7 +222,7 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
|
|||||||
void rcar_du_plane_setup(struct rcar_du_plane *plane)
|
void rcar_du_plane_setup(struct rcar_du_plane *plane)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *state =
|
struct rcar_du_plane_state *state =
|
||||||
to_rcar_du_plane_state(plane->plane.state);
|
to_rcar_plane_state(plane->plane.state);
|
||||||
|
|
||||||
__rcar_du_plane_setup(plane, state->hwindex);
|
__rcar_du_plane_setup(plane, state->hwindex);
|
||||||
if (state->format->planes == 2)
|
if (state->format->planes == 2)
|
||||||
@ -234,7 +234,7 @@ void rcar_du_plane_setup(struct rcar_du_plane *plane)
|
|||||||
static int rcar_du_plane_atomic_check(struct drm_plane *plane,
|
static int rcar_du_plane_atomic_check(struct drm_plane *plane,
|
||||||
struct drm_plane_state *state)
|
struct drm_plane_state *state)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
|
struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
|
||||||
struct rcar_du_plane *rplane = to_rcar_plane(plane);
|
struct rcar_du_plane *rplane = to_rcar_plane(plane);
|
||||||
struct rcar_du_device *rcdu = rplane->group->dev;
|
struct rcar_du_device *rcdu = rplane->group->dev;
|
||||||
|
|
||||||
@ -302,7 +302,7 @@ rcar_du_plane_atomic_duplicate_state(struct drm_plane *plane)
|
|||||||
struct rcar_du_plane_state *state;
|
struct rcar_du_plane_state *state;
|
||||||
struct rcar_du_plane_state *copy;
|
struct rcar_du_plane_state *copy;
|
||||||
|
|
||||||
state = to_rcar_du_plane_state(plane->state);
|
state = to_rcar_plane_state(plane->state);
|
||||||
copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
|
copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
|
||||||
if (copy == NULL)
|
if (copy == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
@ -319,7 +319,7 @@ static void rcar_du_plane_atomic_destroy_state(struct drm_plane *plane,
|
|||||||
if (state->fb)
|
if (state->fb)
|
||||||
drm_framebuffer_unreference(state->fb);
|
drm_framebuffer_unreference(state->fb);
|
||||||
|
|
||||||
kfree(to_rcar_du_plane_state(state));
|
kfree(to_rcar_plane_state(state));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
|
static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
|
||||||
@ -327,15 +327,14 @@ static int rcar_du_plane_atomic_set_property(struct drm_plane *plane,
|
|||||||
struct drm_property *property,
|
struct drm_property *property,
|
||||||
uint64_t val)
|
uint64_t val)
|
||||||
{
|
{
|
||||||
struct rcar_du_plane_state *rstate = to_rcar_du_plane_state(state);
|
struct rcar_du_plane_state *rstate = to_rcar_plane_state(state);
|
||||||
struct rcar_du_plane *rplane = to_rcar_plane(plane);
|
struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
|
||||||
struct rcar_du_group *rgrp = rplane->group;
|
|
||||||
|
|
||||||
if (property == rgrp->planes.alpha)
|
if (property == rcdu->props.alpha)
|
||||||
rstate->alpha = val;
|
rstate->alpha = val;
|
||||||
else if (property == rgrp->planes.colorkey)
|
else if (property == rcdu->props.colorkey)
|
||||||
rstate->colorkey = val;
|
rstate->colorkey = val;
|
||||||
else if (property == rgrp->planes.zpos)
|
else if (property == rcdu->props.zpos)
|
||||||
rstate->zpos = val;
|
rstate->zpos = val;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -349,14 +348,13 @@ static int rcar_du_plane_atomic_get_property(struct drm_plane *plane,
|
|||||||
{
|
{
|
||||||
const struct rcar_du_plane_state *rstate =
|
const struct rcar_du_plane_state *rstate =
|
||||||
container_of(state, const struct rcar_du_plane_state, state);
|
container_of(state, const struct rcar_du_plane_state, state);
|
||||||
struct rcar_du_plane *rplane = to_rcar_plane(plane);
|
struct rcar_du_device *rcdu = to_rcar_plane(plane)->group->dev;
|
||||||
struct rcar_du_group *rgrp = rplane->group;
|
|
||||||
|
|
||||||
if (property == rgrp->planes.alpha)
|
if (property == rcdu->props.alpha)
|
||||||
*val = rstate->alpha;
|
*val = rstate->alpha;
|
||||||
else if (property == rgrp->planes.colorkey)
|
else if (property == rcdu->props.colorkey)
|
||||||
*val = rstate->colorkey;
|
*val = rstate->colorkey;
|
||||||
else if (property == rgrp->planes.zpos)
|
else if (property == rcdu->props.zpos)
|
||||||
*val = rstate->zpos;
|
*val = rstate->zpos;
|
||||||
else
|
else
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -391,47 +389,24 @@ static const uint32_t formats[] = {
|
|||||||
|
|
||||||
int rcar_du_planes_init(struct rcar_du_group *rgrp)
|
int rcar_du_planes_init(struct rcar_du_group *rgrp)
|
||||||
{
|
{
|
||||||
struct rcar_du_planes *planes = &rgrp->planes;
|
|
||||||
struct rcar_du_device *rcdu = rgrp->dev;
|
struct rcar_du_device *rcdu = rgrp->dev;
|
||||||
unsigned int num_planes;
|
unsigned int num_planes;
|
||||||
unsigned int num_crtcs;
|
|
||||||
unsigned int crtcs;
|
unsigned int crtcs;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
planes->alpha =
|
/* Create one primary plane per CRTC in this group and seven overlay
|
||||||
drm_property_create_range(rcdu->ddev, 0, "alpha", 0, 255);
|
|
||||||
if (planes->alpha == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* The color key is expressed as an RGB888 triplet stored in a 32-bit
|
|
||||||
* integer in XRGB8888 format. Bit 24 is used as a flag to disable (0)
|
|
||||||
* or enable source color keying (1).
|
|
||||||
*/
|
|
||||||
planes->colorkey =
|
|
||||||
drm_property_create_range(rcdu->ddev, 0, "colorkey",
|
|
||||||
0, 0x01ffffff);
|
|
||||||
if (planes->colorkey == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
planes->zpos =
|
|
||||||
drm_property_create_range(rcdu->ddev, 0, "zpos", 1, 7);
|
|
||||||
if (planes->zpos == NULL)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
/* Create one primary plane per in this group CRTC and seven overlay
|
|
||||||
* planes.
|
* planes.
|
||||||
*/
|
*/
|
||||||
num_crtcs = min(rcdu->num_crtcs - 2 * rgrp->index, 2U);
|
num_planes = rgrp->num_crtcs + 7;
|
||||||
num_planes = num_crtcs + 7;
|
|
||||||
|
|
||||||
crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
|
crtcs = ((1 << rcdu->num_crtcs) - 1) & (3 << (2 * rgrp->index));
|
||||||
|
|
||||||
for (i = 0; i < num_planes; ++i) {
|
for (i = 0; i < num_planes; ++i) {
|
||||||
enum drm_plane_type type = i < num_crtcs
|
enum drm_plane_type type = i < rgrp->num_crtcs
|
||||||
? DRM_PLANE_TYPE_PRIMARY
|
? DRM_PLANE_TYPE_PRIMARY
|
||||||
: DRM_PLANE_TYPE_OVERLAY;
|
: DRM_PLANE_TYPE_OVERLAY;
|
||||||
struct rcar_du_plane *plane = &planes->planes[i];
|
struct rcar_du_plane *plane = &rgrp->planes[i];
|
||||||
|
|
||||||
plane->group = rgrp;
|
plane->group = rgrp;
|
||||||
|
|
||||||
@ -448,12 +423,12 @@ int rcar_du_planes_init(struct rcar_du_group *rgrp)
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
drm_object_attach_property(&plane->plane.base,
|
drm_object_attach_property(&plane->plane.base,
|
||||||
planes->alpha, 255);
|
rcdu->props.alpha, 255);
|
||||||
drm_object_attach_property(&plane->plane.base,
|
drm_object_attach_property(&plane->plane.base,
|
||||||
planes->colorkey,
|
rcdu->props.colorkey,
|
||||||
RCAR_DU_COLORKEY_NONE);
|
RCAR_DU_COLORKEY_NONE);
|
||||||
drm_object_attach_property(&plane->plane.base,
|
drm_object_attach_property(&plane->plane.base,
|
||||||
planes->zpos, 1);
|
rcdu->props.zpos, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -38,19 +38,20 @@ static inline struct rcar_du_plane *to_rcar_plane(struct drm_plane *plane)
|
|||||||
return container_of(plane, struct rcar_du_plane, plane);
|
return container_of(plane, struct rcar_du_plane, plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rcar_du_planes {
|
/**
|
||||||
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
|
* struct rcar_du_plane_state - Driver-specific plane state
|
||||||
|
* @state: base DRM plane state
|
||||||
struct drm_property *alpha;
|
* @format: information about the pixel format used by the plane
|
||||||
struct drm_property *colorkey;
|
* @hwindex: 0-based hardware plane index, -1 means unused
|
||||||
struct drm_property *zpos;
|
* @alpha: value of the plane alpha property
|
||||||
};
|
* @colorkey: value of the plane colorkey property
|
||||||
|
* @zpos: value of the plane zpos property
|
||||||
|
*/
|
||||||
struct rcar_du_plane_state {
|
struct rcar_du_plane_state {
|
||||||
struct drm_plane_state state;
|
struct drm_plane_state state;
|
||||||
|
|
||||||
const struct rcar_du_format_info *format;
|
const struct rcar_du_format_info *format;
|
||||||
int hwindex; /* 0-based, -1 means unused */
|
int hwindex;
|
||||||
|
|
||||||
unsigned int alpha;
|
unsigned int alpha;
|
||||||
unsigned int colorkey;
|
unsigned int colorkey;
|
||||||
@ -58,7 +59,7 @@ struct rcar_du_plane_state {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static inline struct rcar_du_plane_state *
|
static inline struct rcar_du_plane_state *
|
||||||
to_rcar_du_plane_state(struct drm_plane_state *state)
|
to_rcar_plane_state(struct drm_plane_state *state)
|
||||||
{
|
{
|
||||||
return container_of(state, struct rcar_du_plane_state, state);
|
return container_of(state, struct rcar_du_plane_state, state);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user