diff options
author | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-11 10:41:07 +0300 |
---|---|---|
committer | José Pekkarinen <jose.pekkarinen@nokia.com> | 2016-04-13 08:17:18 +0300 |
commit | e09b41010ba33a20a87472ee821fa407a5b8da36 (patch) | |
tree | d10dc367189862e7ca5c592f033dc3726e1df4e3 /kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | |
parent | f93b97fd65072de626c074dbe099a1fff05ce060 (diff) |
These changes are the raw update to linux-4.4.6-rt14. Kernel sources
are taken from kernel.org, and rt patch from the rt wiki download page.
During the rebasing, the following patch collided:
Force tick interrupt and get rid of softirq magic(I70131fb85).
Collisions have been removed because its logic was found on the
source already.
Change-Id: I7f57a4081d9deaa0d9ccfc41a6c8daccdee3b769
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c')
-rw-r--r-- | kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c | 80 |
1 files changed, 50 insertions, 30 deletions
diff --git a/kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c index 7d0b8ef9b..48cb19949 100644 --- a/kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c +++ b/kernel/drivers/gpu/drm/rcar-du/rcar_du_crtc.c @@ -195,26 +195,27 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc, 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 * 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) { struct rcar_du_plane *planes[RCAR_DU_NUM_HW_PLANES]; unsigned int num_planes = 0; + unsigned int dptsr_planes; + unsigned int hwplanes = 0; unsigned int prio = 0; unsigned int i; - u32 dptsr = 0; u32 dspr = 0; - for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) { - struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i]; + for (i = 0; i < rcrtc->group->num_planes; ++i) { + struct rcar_du_plane *plane = &rcrtc->group->planes[i]; unsigned int j; 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) { struct rcar_du_plane *plane = planes[i]; 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; dspr |= (index + 1) << prio; - dptsr |= DPTSR_PnDK(index) | DPTSR_PnTS(index); + hwplanes |= 1 << index; if (plane_format(plane)->planes == 2) { index = (index + 1) % 8; prio -= 4; 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 - * with superposition controller 2. + /* Update the planes to display timing and dot clock generator + * 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) { - /* The DPTSR register is updated when the display controller is - * stopped. We thus need to restart the DU. Once again, sorry - * for the flicker. One way to mitigate the issue would be to - * pre-associate planes with CRTCs (either with a fixed 4/4 - * split, or through a module parameter). Flicker would then - * occur only if we need to break the pre-association. - */ - mutex_lock(&rcrtc->group->lock); - if (rcar_du_group_read(rcrtc->group, DPTSR) != dptsr) { - rcar_du_group_write(rcrtc->group, DPTSR, dptsr); - if (rcrtc->group->used_crtcs) - rcar_du_group_restart(rcrtc->group); - } - mutex_unlock(&rcrtc->group->lock); + mutex_lock(&rcrtc->group->lock); + + dptsr_planes = rcrtc->index % 2 ? rcrtc->group->dptsr_planes | hwplanes + : rcrtc->group->dptsr_planes & ~hwplanes; + + if (dptsr_planes != rcrtc->group->dptsr_planes) { + rcar_du_group_write(rcrtc->group, DPTSR, + (dptsr_planes << 16) | dptsr_planes); + rcrtc->group->dptsr_planes = dptsr_planes; + + if (rcrtc->group->used_crtcs) + rcar_du_group_restart(rcrtc->group); } + mutex_unlock(&rcrtc->group->lock); + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, dspr); } @@ -393,6 +398,19 @@ static void rcar_du_crtc_stop(struct rcar_du_crtc *rcrtc) if (!rcrtc->started) return; + /* Disable all planes and wait for the change to take effect. This is + * required as the DSnPR registers are updated on vblank, and no vblank + * will occur once the CRTC is stopped. Disabling planes when starting + * the CRTC thus wouldn't be enough as it would start scanning out + * immediately from old frame buffers until the next vblank. + * + * This increases the CRTC stop delay, especially when multiple CRTCs + * are stopped in one operation as we now wait for one vblank per CRTC. + * Whether this can be improved needs to be researched. + */ + rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? DS2PR : DS1PR, 0); + drm_crtc_wait_one_vblank(crtc); + /* Disable vertical blanking interrupt reporting. We first need to wait * for page flip completion before stopping the CRTC as userspace * expects page flips to eventually complete. @@ -427,8 +445,8 @@ void rcar_du_crtc_resume(struct rcar_du_crtc *rcrtc) rcar_du_crtc_start(rcrtc); /* Commit the planes state. */ - for (i = 0; i < ARRAY_SIZE(rcrtc->group->planes.planes); ++i) { - struct rcar_du_plane *plane = &rcrtc->group->planes.planes[i]; + for (i = 0; i < rcrtc->group->num_planes; ++i) { + struct rcar_du_plane *plane = &rcrtc->group->planes[i]; if (plane->plane.state->crtc != &rcrtc->crtc) continue; @@ -478,7 +496,8 @@ static bool rcar_du_crtc_mode_fixup(struct drm_crtc *crtc, return true; } -static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct drm_pending_vblank_event *event = crtc->state->event; struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); @@ -494,7 +513,8 @@ static void rcar_du_crtc_atomic_begin(struct drm_crtc *crtc) } } -static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc) +static void rcar_du_crtc_atomic_flush(struct drm_crtc *crtc, + struct drm_crtc_state *old_crtc_state) { struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc); @@ -592,7 +612,7 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index) rcrtc->enabled = false; ret = drm_crtc_init_with_planes(rcdu->ddev, crtc, - &rgrp->planes.planes[index % 2].plane, + &rgrp->planes[index % 2].plane, NULL, &crtc_funcs); if (ret < 0) return ret; |