Re: [PATCH AUTOSEL 5.10 16/18] drm/nouveau/kms/nv50: workaround EFI GOP window channel format differences
From: Lyude Paul
Date: Tue Aug 24 2021 - 13:09:58 EST
Ben, do we even have Ampere support in 5.10?
On Mon, 2021-08-23 at 20:54 -0400, Sasha Levin wrote:
> From: Ben Skeggs <bskeggs@xxxxxxxxxx>
>
> [ Upstream commit e78b1b545c6cfe9f87fc577128e00026fff230ba ]
>
> Should fix some initial modeset failures on (at least) Ampere boards.
>
> Signed-off-by: Ben Skeggs <bskeggs@xxxxxxxxxx>
> Reviewed-by: Lyude Paul <lyude@xxxxxxxxxx>
> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>
> ---
> drivers/gpu/drm/nouveau/dispnv50/disp.c | 27 +++++++++++++++++++++++++
> drivers/gpu/drm/nouveau/dispnv50/head.c | 13 ++++++++----
> drivers/gpu/drm/nouveau/dispnv50/head.h | 1 +
> 3 files changed, 37 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> index 5b8cabb099eb..c2d34c91e840 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
> @@ -2202,6 +2202,33 @@ nv50_disp_atomic_commit_tail(struct drm_atomic_state
> *state)
> interlock[NV50_DISP_INTERLOCK_CORE] = 0;
> }
>
> + /* Finish updating head(s)...
> + *
> + * NVD is rather picky about both where window assignments can
> change,
> + * *and* about certain core and window channel states matching.
> + *
> + * The EFI GOP driver on newer GPUs configures window channels with
> a
> + * different output format to what we do, and the core channel
> update
> + * in the assign_windows case above would result in a state
> mismatch.
> + *
> + * Delay some of the head update until after that point to
> workaround
> + * the issue. This only affects the initial modeset.
> + *
> + * TODO: handle this better when adding flexible window mapping
> + */
> + for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state,
> new_crtc_state, i) {
> + struct nv50_head_atom *asyh =
> nv50_head_atom(new_crtc_state);
> + struct nv50_head *head = nv50_head(crtc);
> +
> + NV_ATOMIC(drm, "%s: set %04x (clr %04x)\n", crtc->name,
> + asyh->set.mask, asyh->clr.mask);
> +
> + if (asyh->set.mask) {
> + nv50_head_flush_set_wndw(head, asyh);
> + interlock[NV50_DISP_INTERLOCK_CORE] = 1;
> + }
> + }
> +
> /* Update plane(s). */
> for_each_new_plane_in_state(state, plane, new_plane_state, i) {
> struct nv50_wndw_atom *asyw =
> nv50_wndw_atom(new_plane_state);
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.c
> b/drivers/gpu/drm/nouveau/dispnv50/head.c
> index 841edfaf5b9d..61826cac3061 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/head.c
> +++ b/drivers/gpu/drm/nouveau/dispnv50/head.c
> @@ -49,11 +49,8 @@ nv50_head_flush_clr(struct nv50_head *head,
> }
>
> void
> -nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
> +nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom
> *asyh)
> {
> - if (asyh->set.view ) head->func->view (head, asyh);
> - if (asyh->set.mode ) head->func->mode (head, asyh);
> - if (asyh->set.core ) head->func->core_set(head, asyh);
> if (asyh->set.olut ) {
> asyh->olut.offset = nv50_lut_load(&head->olut,
> asyh->olut.buffer,
> @@ -61,6 +58,14 @@ nv50_head_flush_set(struct nv50_head *head, struct
> nv50_head_atom *asyh)
> asyh->olut.load);
> head->func->olut_set(head, asyh);
> }
> +}
> +
> +void
> +nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh)
> +{
> + if (asyh->set.view ) head->func->view (head, asyh);
> + if (asyh->set.mode ) head->func->mode (head, asyh);
> + if (asyh->set.core ) head->func->core_set(head, asyh);
> if (asyh->set.curs ) head->func->curs_set(head, asyh);
> if (asyh->set.base ) head->func->base (head, asyh);
> if (asyh->set.ovly ) head->func->ovly (head, asyh);
> diff --git a/drivers/gpu/drm/nouveau/dispnv50/head.h
> b/drivers/gpu/drm/nouveau/dispnv50/head.h
> index dae841dc05fd..0bac6be9ba34 100644
> --- a/drivers/gpu/drm/nouveau/dispnv50/head.h
> +++ b/drivers/gpu/drm/nouveau/dispnv50/head.h
> @@ -21,6 +21,7 @@ struct nv50_head {
>
> struct nv50_head *nv50_head_create(struct drm_device *, int index);
> void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom
> *asyh);
> +void nv50_head_flush_set_wndw(struct nv50_head *head, struct nv50_head_atom
> *asyh);
> void nv50_head_flush_clr(struct nv50_head *head,
> struct nv50_head_atom *asyh, bool flush);
>
--
Cheers,
Lyude Paul (she/her)
Software Engineer at Red Hat