From: Jyri Sarha <jsarha@ti.com>
To: Tomi Valkeinen <tomi.valkeinen@ti.com>,
<dri-devel@lists.freedesktop.org>
Cc: praneeth@ti.com, peter.ujfalusi@ti.com,
laurent.pinchart@ideasonboard.com
Subject: Re: [PATCH v4] drm/tidss: dispc: Rewrite naive plane positioning code
Date: Mon, 24 Feb 2020 16:49:55 +0200 [thread overview]
Message-ID: <8a20b3b2-6a57-dcdb-028d-9b22e89a9d4f@ti.com> (raw)
In-Reply-To: <a615dc2a-f142-fa23-10f1-94d3c2d2fbdf@ti.com>
On 14/02/2020 13:20, Tomi Valkeinen wrote:
> On 13/02/2020 21:37, Jyri Sarha wrote:
>> The old implementation of placing planes on the CRTC while configuring
>> the planes was naive and relied on the order in which the planes were
>> configured, enabled, and disabled. The situation where a plane's zpos
>> was changed on the fly was completely broken. The usual symptoms of
>> this problem was scrambled display and a flood of sync lost errors,
>> when a plane was active in two layers at the same time, or a missing
>> plane, in case when a layer was accidentally disabled.
>>
>> The rewrite takes a more straight forward approach when HW is
>> concerned. The plane positioning registers are in the CRTC (or
>> actually OVR) register space and it is more natural to configure them
>> in a one go when configuring the CRTC. To do this we need make sure we
>> have all the planes on the updated CRTCs in the new atomic state. The
>> untouched planes on CRTCs that need plane position update are added to
>> the atomic state in tidss_atomic_check().
>
> The subject needs updating. This is a fix for a bug, and subject needs
> to reflect that.
>
Ok
>> Signed-off-by: Jyri Sarha <jsarha@ti.com>
>> ---
>> drivers/gpu/drm/tidss/tidss_crtc.c | 55 +++++++++++++++++++++++++++++
>> drivers/gpu/drm/tidss/tidss_crtc.h | 2 ++
>> drivers/gpu/drm/tidss/tidss_dispc.c | 55 +++++++++++------------------
>> drivers/gpu/drm/tidss/tidss_dispc.h | 5 +++
>> drivers/gpu/drm/tidss/tidss_kms.c | 49 ++++++++++++++++++++++++-
>> 5 files changed, 130 insertions(+), 36 deletions(-)
>>
>> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.c
>> b/drivers/gpu/drm/tidss/tidss_crtc.c
>> index 032c31ee2820..631ec61b086a 100644
>> --- a/drivers/gpu/drm/tidss/tidss_crtc.c
>> +++ b/drivers/gpu/drm/tidss/tidss_crtc.c
>> @@ -17,6 +17,7 @@
>> #include "tidss_dispc.h"
>> #include "tidss_drv.h"
>> #include "tidss_irq.h"
>> +#include "tidss_plane.h"
>> /* Page flip and frame done IRQs */
>> @@ -111,6 +112,54 @@ static int tidss_crtc_atomic_check(struct
>> drm_crtc *crtc,
>> return dispc_vp_bus_check(dispc, hw_videoport, state);
>> }
>> +/*
>> + * This needs all affected planes to be present in the atomic
>> + * state. The untouched planes are added to the state in
>> + * tidss_atomic_check().
>> + */
>> +static void tidss_crtc_position_planes(struct tidss_device *tidss,
>> + struct drm_crtc *crtc,
>> + struct drm_crtc_state *old_state,
>> + bool newmodeset)
>> +{
>> + struct drm_atomic_state *ostate = old_state->state;
>> + struct tidss_crtc *tcrtc = to_tidss_crtc(crtc);
>> + struct drm_crtc_state *cstate = crtc->state;
>> + int zpos;
>> +
>> + if (!newmodeset && !cstate->zpos_changed &&
>> + !to_tidss_crtc_state(cstate)->plane_pos_changed)
>> + return;
>> +
>> + for (zpos = 0; zpos < tidss->feat->num_planes; zpos++) {
>> + struct drm_plane_state *pstate;
>> + struct drm_plane *plane;
>> + bool zpos_taken = false;
>> + int i;
>> +
>> + for_each_new_plane_in_state(ostate, plane, pstate, i) {
>> + if (pstate->crtc != crtc || !pstate->visible)
>> + continue;
>> +
>> + if (pstate->normalized_zpos == zpos) {
>> + zpos_taken = true;
>> + break;
>> + }
>> + }
>> +
>> + if (zpos_taken) {
>> + struct tidss_plane *tplane = to_tidss_plane(plane);
>> +
>> + dispc_ovr_set_plane(tidss->dispc, tplane->hw_plane_id,
>> + tcrtc->hw_videoport,
>> + pstate->crtc_x, pstate->crtc_y,
>> + zpos);
>> + }
>> + dispc_ovr_enable_layer(tidss->dispc, tcrtc->hw_videoport, zpos,
>> + zpos_taken);
>> + }
>> +}
>
> Nitpicking, but... I think the "zpos" above is really "layer". Even the
> params, to which you pass "zpos", in the ovr functions are named "layer".
>
Well, it is both. But I'll change that.
> "zpos_taken" sounds like it's reserved and not available for us, or
> something like that. Maybe "layer_active" conveys better that we're just
> collecting which layers are active and which are not.
>
Ok, that sounds better.
>> +
>> static void tidss_crtc_atomic_flush(struct drm_crtc *crtc,
>> struct drm_crtc_state *old_crtc_state)
>> {
>> @@ -146,6 +195,9 @@ static void tidss_crtc_atomic_flush(struct
>> drm_crtc *crtc,
>> /* Write vp properties to HW if needed. */
>> dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state,
>> false);
>> + /* Update plane positions if needed. */
>> + tidss_crtc_position_planes(tidss, crtc, old_crtc_state, false);
>> +
>> WARN_ON(drm_crtc_vblank_get(crtc) != 0);
>> spin_lock_irqsave(&ddev->event_lock, flags);
>> @@ -183,6 +235,7 @@ static void tidss_crtc_atomic_enable(struct
>> drm_crtc *crtc,
>> return;
>> dispc_vp_setup(tidss->dispc, tcrtc->hw_videoport, crtc->state,
>> true);
>> + tidss_crtc_position_planes(tidss, crtc, old_state, true);
>> /* Turn vertical blanking interrupt reporting on. */
>> drm_crtc_vblank_on(crtc);
>> @@ -318,6 +371,8 @@ static struct drm_crtc_state
>> *tidss_crtc_duplicate_state(struct drm_crtc *crtc)
>> __drm_atomic_helper_crtc_duplicate_state(crtc, &state->base);
>> + state->plane_pos_changed = false;
>> +
>> state->bus_format = current_state->bus_format;
>> state->bus_flags = current_state->bus_flags;
>> diff --git a/drivers/gpu/drm/tidss/tidss_crtc.h
>> b/drivers/gpu/drm/tidss/tidss_crtc.h
>> index df9d90b1ad2d..09e773666228 100644
>> --- a/drivers/gpu/drm/tidss/tidss_crtc.h
>> +++ b/drivers/gpu/drm/tidss/tidss_crtc.h
>> @@ -32,6 +32,8 @@ struct tidss_crtc_state {
>> /* Must be first. */
>> struct drm_crtc_state base;
>> + bool plane_pos_changed;
>> +
>> u32 bus_format;
>> u32 bus_flags;
>> };
>> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.c
>> b/drivers/gpu/drm/tidss/tidss_dispc.c
>> index eeb160dc047b..e79dad246b1e 100644
>> --- a/drivers/gpu/drm/tidss/tidss_dispc.c
>> +++ b/drivers/gpu/drm/tidss/tidss_dispc.c
>> @@ -281,11 +281,6 @@ struct dss_vp_data {
>> u32 *gamma_table;
>> };
>> -struct dss_plane_data {
>> - u32 zorder;
>> - u32 hw_videoport;
>> -};
>> -
>> struct dispc_device {
>> struct tidss_device *tidss;
>> struct device *dev;
>> @@ -307,8 +302,6 @@ struct dispc_device {
>> struct dss_vp_data vp_data[TIDSS_MAX_PORTS];
>> - struct dss_plane_data plane_data[TIDSS_MAX_PLANES];
>> -
>> u32 *fourccs;
>> u32 num_fourccs;
>> @@ -1247,7 +1240,7 @@ int dispc_vp_set_clk_rate(struct dispc_device
>> *dispc, u32 hw_videoport,
>> /* OVR */
>> static void dispc_k2g_ovr_set_plane(struct dispc_device *dispc,
>> u32 hw_plane, u32 hw_videoport,
>> - u32 x, u32 y, u32 zpos)
>> + u32 x, u32 y, u32 layer)
>> {
>> /* On k2g there is only one plane and no need for ovr */
>> dispc_vid_write(dispc, hw_plane, DISPC_VID_K2G_POSITION,
>> @@ -1256,44 +1249,43 @@ static void dispc_k2g_ovr_set_plane(struct
>> dispc_device *dispc,
>> static void dispc_am65x_ovr_set_plane(struct dispc_device *dispc,
>> u32 hw_plane, u32 hw_videoport,
>> - u32 x, u32 y, u32 zpos)
>> + u32 x, u32 y, u32 layer)
>> {
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
>> hw_plane, 4, 1);
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
>> x, 17, 6);
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
>> y, 30, 19);
>> }
>> static void dispc_j721e_ovr_set_plane(struct dispc_device *dispc,
>> u32 hw_plane, u32 hw_videoport,
>> - u32 x, u32 y, u32 zpos)
>> + u32 x, u32 y, u32 layer)
>> {
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
>> hw_plane, 4, 1);
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer),
>> x, 13, 0);
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(zpos),
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES2(layer),
>> y, 29, 16);
>> }
>> -static void dispc_ovr_set_plane(struct dispc_device *dispc,
>> - u32 hw_plane, u32 hw_videoport,
>> - u32 x, u32 y, u32 zpos)
>> +void dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane,
>> + u32 hw_videoport, u32 x, u32 y, u32 layer)
>> {
>> switch (dispc->feat->subrev) {
>> case DISPC_K2G:
>> dispc_k2g_ovr_set_plane(dispc, hw_plane, hw_videoport,
>> - x, y, zpos);
>> + x, y, layer);
>> break;
>> case DISPC_AM65X:
>> dispc_am65x_ovr_set_plane(dispc, hw_plane, hw_videoport,
>> - x, y, zpos);
>> + x, y, layer);
>> break;
>> case DISPC_J721E:
>> dispc_j721e_ovr_set_plane(dispc, hw_plane, hw_videoport,
>> - x, y, zpos);
>> + x, y, layer);
>> break;
>> default:
>> WARN_ON(1);
>> @@ -1301,10 +1293,13 @@ static void dispc_ovr_set_plane(struct
>> dispc_device *dispc,
>> }
>> }
>> -static void dispc_ovr_enable_plane(struct dispc_device *dispc,
>> - u32 hw_videoport, u32 zpos, bool enable)
>> +void dispc_ovr_enable_layer(struct dispc_device *dispc,
>> + u32 hw_videoport, u32 layer, bool enable)
>> {
>> - OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(zpos),
>> + if (dispc->feat->subrev == DISPC_K2G)
>> + return;
>> +
>> + OVR_REG_FLD_MOD(dispc, hw_videoport, DISPC_OVR_ATTRIBUTES(layer),
>> !!enable, 0, 0);
>> }
>> @@ -2070,21 +2065,11 @@ int dispc_plane_setup(struct dispc_device
>> *dispc, u32 hw_plane,
>> VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, 0,
>> 28, 28);
>> - dispc_ovr_set_plane(dispc, hw_plane, hw_videoport,
>> - state->crtc_x, state->crtc_y,
>> - state->normalized_zpos);
>> -
>> - dispc->plane_data[hw_plane].zorder = state->normalized_zpos;
>> - dispc->plane_data[hw_plane].hw_videoport = hw_videoport;
>> -
>> return 0;
>> }
>> int dispc_plane_enable(struct dispc_device *dispc, u32 hw_plane,
>> bool enable)
>> {
>> - dispc_ovr_enable_plane(dispc,
>> dispc->plane_data[hw_plane].hw_videoport,
>> - dispc->plane_data[hw_plane].zorder, enable);
>> -
>> VID_REG_FLD_MOD(dispc, hw_plane, DISPC_VID_ATTRIBUTES, !!enable,
>> 0, 0);
>> return 0;
>> diff --git a/drivers/gpu/drm/tidss/tidss_dispc.h
>> b/drivers/gpu/drm/tidss/tidss_dispc.h
>> index e65e6a2bb821..a4a68249e44b 100644
>> --- a/drivers/gpu/drm/tidss/tidss_dispc.h
>> +++ b/drivers/gpu/drm/tidss/tidss_dispc.h
>> @@ -94,6 +94,11 @@ extern const struct dispc_features dispc_j721e_feats;
>> void dispc_set_irqenable(struct dispc_device *dispc, dispc_irq_t mask);
>> dispc_irq_t dispc_read_and_clear_irqstatus(struct dispc_device *dispc);
>> +void dispc_ovr_set_plane(struct dispc_device *dispc, u32 hw_plane,
>> + u32 hw_videoport, u32 x, u32 y, u32 layer);
>> +void dispc_ovr_enable_layer(struct dispc_device *dispc,
>> + u32 hw_videoport, u32 layer, bool enable);
>> +
>> void dispc_vp_prepare(struct dispc_device *dispc, u32 hw_videoport,
>> const struct drm_crtc_state *state);
>> void dispc_vp_enable(struct dispc_device *dispc, u32 hw_videoport,
>> diff --git a/drivers/gpu/drm/tidss/tidss_kms.c
>> b/drivers/gpu/drm/tidss/tidss_kms.c
>> index 5311e0f1c551..24b3f02b90c6 100644
>> --- a/drivers/gpu/drm/tidss/tidss_kms.c
>> +++ b/drivers/gpu/drm/tidss/tidss_kms.c
>> @@ -47,9 +47,56 @@ static const struct drm_mode_config_helper_funcs
>> mode_config_helper_funcs = {
>> .atomic_commit_tail = tidss_atomic_commit_tail,
>> };
>> +static int tidss_atomic_check(struct drm_device *ddev,
>> + struct drm_atomic_state *state)
>> +{
>> + struct drm_plane_state *opstate;
>> + struct drm_plane_state *npstate;
>> + struct drm_plane *plane;
>> + struct drm_crtc_state *cstate;
>> + struct drm_crtc *crtc;
>> + int ret, i;
>> +
>> + ret = drm_atomic_helper_check(ddev, state);
>> + if (ret)
>> + return ret;
>> +
>> + /*
>> + * If a plane on a CRTC changes add all active planes on that
>
> Only if the plane's position (x/y/z) changes.
>
Ok.
>> + * CRTC to the atomic state. This is needed for updating the
>> + * plane positions in tidss_crtc_position_planes() which is
>> + * called from crtc_atomic_enable() and crtc_atomic_flush().
>> + * The update is needed for x,y-position changes too, so
>> + * zpos_changed condition is not enough and we need add the
>> + * our own plane_pos_changed flag.
>
> Strictly speaking, we don't need to add all active planes if only
> plane's x/y pos changes. In that case it's enough to just update the OVR
> layer's x & y.
>
The we are back to plane-specific updates. The whole idea of this fix is
to keep things simple and just update all ovr layers if anything there
changes.
> And when a plane is enabled or disabled, we need to update OVR. Does the
> code handled that? Keeping plane's x/y/z pos the same, but enabling and
> disabling it. I think both zpos_changed and pos_changed could be false
> in that case.
>
zpos_changed flag handles that. If any plane on the crtc is
disabled/enabled/moved then the flag is set (in
drm_atomic_normalize_zpos()).
>> + */
>> + for_each_oldnew_plane_in_state(state, plane, opstate, npstate, i) {
>> + if (npstate->crtc && npstate->visible &&
>> + (!opstate->crtc ||
>> + opstate->crtc_x != npstate->crtc_x ||
>> + opstate->crtc_y != npstate->crtc_y)) {
>
> The above becomes a bit easier to read if you first:
>
> if (!npstate->crtc || !npstate->visible)
> continue;
>
Sure.
>> + cstate = drm_atomic_get_crtc_state(state,
>> + npstate->crtc);
>> + if (IS_ERR(cstate))
>> + return PTR_ERR(cstate);
>> + to_tidss_crtc_state(cstate)->plane_pos_changed = true;
>> + }
>> + }
>
> Add blank line here.
>
The two loops are part of the same procedure, but never mind I'll add a
newline.
>> + for_each_new_crtc_in_state(state, crtc, cstate, i) {
>> + if (to_tidss_crtc_state(cstate)->plane_pos_changed ||
>> + cstate->zpos_changed) {
>> + ret = drm_atomic_add_affected_planes(state, crtc);
>> + if (ret)
>> + return ret;
>> + }
>> + }
>
> Tomi
>
--
Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki.
Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel
prev parent reply other threads:[~2020-02-24 14:50 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-13 19:37 [PATCH v4] drm/tidss: dispc: Rewrite naive plane positioning code Jyri Sarha
2020-02-14 11:20 ` Tomi Valkeinen
2020-02-24 14:49 ` Jyri Sarha [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8a20b3b2-6a57-dcdb-028d-9b22e89a9d4f@ti.com \
--to=jsarha@ti.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=laurent.pinchart@ideasonboard.com \
--cc=peter.ujfalusi@ti.com \
--cc=praneeth@ti.com \
--cc=tomi.valkeinen@ti.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).