drm: rcar-du: Keep plane to CRTC associations when disabling a plane
Changing the plane to CRTC associations requires restarting the CRTC group, creating visible flicker. Mitigate the issue by changing plane association only when a plane becomes enabled, not when it get disabled. Signed-off-by: Laurent Pinchart <laurent.pinchart+renesas@ideasonboard.com>
This commit is contained in:
parent
0805861195
commit
2a57e9b5af
|
@ -208,9 +208,10 @@ 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); ++i) {
|
for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes); ++i) {
|
||||||
|
@ -238,37 +239,44 @@ static void rcar_du_crtc_update_planes(struct rcar_du_crtc *rcrtc)
|
||||||
|
|
||||||
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.
|
||||||
|
*
|
||||||
|
* To mitigate the issue further we could pre-associate planes with
|
||||||
|
* CRTCs, either with a fixed 4/4 split, or through a module parameter.
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -27,7 +27,8 @@ struct rcar_du_device;
|
||||||
* @index: group index
|
* @index: group index
|
||||||
* @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 {
|
||||||
|
@ -39,6 +40,7 @@ struct rcar_du_group {
|
||||||
unsigned int used_crtcs;
|
unsigned int used_crtcs;
|
||||||
|
|
||||||
struct mutex lock;
|
struct mutex lock;
|
||||||
|
unsigned int dptsr_planes;
|
||||||
|
|
||||||
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
|
struct rcar_du_plane planes[RCAR_DU_NUM_KMS_PLANES];
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue