2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2025-01-11 07:04:04 +08:00

drm/nouveau/kms/nv50: workaround EFI GOP window channel format differences

Should fix some initial modeset failures on (at least) Ampere boards.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
This commit is contained in:
Ben Skeggs 2021-08-10 19:29:57 +10:00
parent 6eaa1f3c59
commit e78b1b545c
3 changed files with 37 additions and 4 deletions

View File

@ -2237,6 +2237,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);

View File

@ -50,11 +50,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,
@ -62,6 +59,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);

View File

@ -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);