diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index 8203a3873797..018f33601e1e 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -91,6 +91,11 @@ struct nv50_head_atom { } v; } mode; + struct { + u32 handle; + u64 offset:40; + } lut; + struct { bool visible; u32 handle; @@ -770,7 +775,6 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, /****************************************************************************** * Head *****************************************************************************/ - static void nv50_head_core_clr(struct nv50_head *head) { @@ -835,6 +839,61 @@ nv50_head_core_set(struct nv50_head *head, struct nv50_head_atom *asyh) } } +static void +nv50_head_lut_clr(struct nv50_head *head) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 4))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1); + evo_data(push, 0x40000000); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 1); + evo_data(push, 0x40000000); + evo_mthd(push, 0x085c + (head->base.index * 0x400), 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0440 + (head->base.index * 0x300), 1); + evo_data(push, 0x03000000); + evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); + evo_data(push, 0x00000000); + } + evo_kick(push, core); + } +} + +static void +nv50_head_lut_set(struct nv50_head *head, struct nv50_head_atom *asyh) +{ + struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; + u32 *push; + if ((push = evo_wait(core, 7))) { + if (core->base.user.oclass < G82_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); + evo_data(push, 0xc0000000); + evo_data(push, asyh->lut.offset >> 8); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0840 + (head->base.index * 0x400), 2); + evo_data(push, 0xc0000000); + evo_data(push, asyh->lut.offset >> 8); + evo_mthd(push, 0x085c + (head->base.index * 0x400), 1); + evo_data(push, asyh->lut.handle); + } else { + evo_mthd(push, 0x0440 + (head->base.index * 0x300), 4); + evo_data(push, 0x83000000); + evo_data(push, asyh->lut.offset >> 8); + evo_data(push, 0x00000000); + evo_data(push, 0x00000000); + evo_mthd(push, 0x045c + (head->base.index * 0x300), 1); + evo_data(push, asyh->lut.handle); + } + evo_kick(push, core); + } +} + static void nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) { @@ -878,6 +937,8 @@ nv50_head_mode(struct nv50_head *head, struct nv50_head_atom *asyh) static void nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) { + if (asyh->clr.core && (!asyh->set.core || y)) + nv50_head_lut_clr(head); if (asyh->clr.core && (!asyh->set.core || y)) nv50_head_core_clr(head); } @@ -886,6 +947,7 @@ static void nv50_head_flush_set(struct nv50_head *head, struct nv50_head_atom *asyh) { if (asyh->set.mode ) nv50_head_mode (head, asyh); + if (asyh->set.core ) nv50_head_lut_set (head, asyh); if (asyh->set.core ) nv50_head_core_set(head, asyh); } @@ -973,6 +1035,8 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->core.layout = 1; asyh->core.block = 0; asyh->core.pitch = ALIGN(asyh->core.w, 64) * 4; + asyh->lut.handle = disp->mast.base.vram.handle; + asyh->lut.offset = head->base.lut.nvbo->bo.offset; } else { asyh->core.visible = false; } @@ -1320,10 +1384,8 @@ static void nv50_crtc_prepare(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_mast *mast = nv50_mast(crtc->dev); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; - u32 *push; nv50_display_flip_stop(crtc); @@ -1331,27 +1393,6 @@ nv50_crtc_prepare(struct drm_crtc *crtc) nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_clr(head, asyh, false); - push = evo_wait(mast, 6); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x40000000); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x40000000); - evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x03000000); - evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); - } - - evo_kick(push, mast); - } - nv50_crtc_cursor_show_hide(nv_crtc, false, false); } @@ -1359,34 +1400,12 @@ static void nv50_crtc_commit(struct drm_crtc *crtc) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); - struct nv50_mast *mast = nv50_mast(crtc->dev); - u32 *push; + struct nv50_head *head = nv50_head(crtc); + struct nv50_head_atom *asyh = &head->asy; - push = evo_wait(mast, 32); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0xc0000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0840 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0xc0000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - evo_mthd(push, 0x085c + (nv_crtc->index * 0x400), 1); - evo_data(push, mast->base.vram.handle); - } else { - evo_mthd(push, 0x0440 + (nv_crtc->index * 0x300), 4); - evo_data(push, 0x83000000); - evo_data(push, nv_crtc->lut.nvbo->bo.offset >> 8); - evo_data(push, 0x00000000); - evo_data(push, 0x00000000); - evo_mthd(push, 0x045c + (nv_crtc->index * 0x300), 1); - evo_data(push, mast->base.vram.handle); - } - - evo_kick(push, mast); - } + asyh->state.active = true; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_set(head, asyh); nv50_crtc_cursor_show_hide(nv_crtc, true, true); nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1);