Sasha Levin
2021-Aug-24 00:54 UTC
[Nouveau] [PATCH AUTOSEL 5.10 16/18] drm/nouveau/kms/nv50: workaround EFI GOP window channel format differences
From: Ben Skeggs <bskeggs at redhat.com>
[ Upstream commit e78b1b545c6cfe9f87fc577128e00026fff230ba ]
Should fix some initial modeset failures on (at least) Ampere boards.
Signed-off-by: Ben Skeggs <bskeggs at redhat.com>
Reviewed-by: Lyude Paul <lyude at redhat.com>
Signed-off-by: Sasha Levin <sashal at kernel.org>
---
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);
--
2.30.2
Lyude Paul
2021-Aug-24 17:07 UTC
[Nouveau] [PATCH AUTOSEL 5.10 16/18] drm/nouveau/kms/nv50: workaround EFI GOP window channel format differences
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 at redhat.com> > > [ Upstream commit e78b1b545c6cfe9f87fc577128e00026fff230ba ] > > Should fix some initial modeset failures on (at least) Ampere boards. > > Signed-off-by: Ben Skeggs <bskeggs at redhat.com> > Reviewed-by: Lyude Paul <lyude at redhat.com> > Signed-off-by: Sasha Levin <sashal at kernel.org> > --- > ?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