diff options
Diffstat (limited to 'drm/nouveau/nv50_display.c')
-rw-r--r-- | drm/nouveau/nv50_display.c | 147 |
1 files changed, 97 insertions, 50 deletions
diff --git a/drm/nouveau/nv50_display.c b/drm/nouveau/nv50_display.c index 018f33601..d24304275 100644 --- a/drm/nouveau/nv50_display.c +++ b/drm/nouveau/nv50_display.c @@ -112,6 +112,14 @@ struct nv50_head_atom { } core; struct { + bool visible; + u32 handle; + u64 offset:40; + u8 layout:1; + u8 format:1; + } curs; + + struct { u8 depth; u8 cpp; u16 x; @@ -123,6 +131,7 @@ struct nv50_head_atom { union { struct { bool core:1; + bool curs:1; }; u8 mask; } clr; @@ -130,6 +139,7 @@ struct nv50_head_atom { union { struct { bool core:1; + bool curs:1; bool view:1; bool mode:1; }; @@ -776,6 +786,62 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb, * Head *****************************************************************************/ static void +nv50_head_curs_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, 0x0880 + head->base.index * 0x400, 1); + evo_data(push, 0x05000000); + } else + if (core->base.user.oclass < GF110_DISP_CORE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 1); + evo_data(push, 0x05000000); + evo_mthd(push, 0x089c + head->base.index * 0x400, 1); + evo_data(push, 0x00000000); + } else { + evo_mthd(push, 0x0480 + head->base.index * 0x300, 1); + evo_data(push, 0x05000000); + evo_mthd(push, 0x048c + head->base.index * 0x300, 1); + evo_data(push, 0x00000000); + } + evo_kick(push, core); + } +} + +static void +nv50_head_curs_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, 5))) { + if (core->base.user.oclass < G82_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + } else + if (core->base.user.oclass < GF110_DISP_BASE_CHANNEL_DMA) { + evo_mthd(push, 0x0880 + head->base.index * 0x400, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + evo_mthd(push, 0x089c + head->base.index * 0x400, 1); + evo_data(push, asyh->curs.handle); + } else { + evo_mthd(push, 0x0480 + head->base.index * 0x300, 2); + evo_data(push, 0x80000000 | (asyh->curs.layout << 26) | + (asyh->curs.format << 24)); + evo_data(push, asyh->curs.offset >> 8); + evo_mthd(push, 0x048c + head->base.index * 0x300, 1); + evo_data(push, asyh->curs.handle); + } + evo_kick(push, core); + } +} + +static void nv50_head_core_clr(struct nv50_head *head) { struct nv50_dmac *core = &nv50_disp(head->base.base.dev)->mast.base; @@ -941,6 +1007,8 @@ nv50_head_flush_clr(struct nv50_head *head, struct nv50_head_atom *asyh, bool y) nv50_head_lut_clr(head); if (asyh->clr.core && (!asyh->set.core || y)) nv50_head_core_clr(head); + if (asyh->clr.curs && (!asyh->set.curs || y)) + nv50_head_curs_clr(head); } static void @@ -949,6 +1017,7 @@ 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); + if (asyh->set.curs ) nv50_head_curs_set(head, asyh); } static void @@ -1017,7 +1086,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->core.w = asyh->base.w; asyh->core.h = asyh->base.h; } else - if ((asyh->core.visible = true)) { + if ((asyh->core.visible = asyh->curs.visible)) { /*XXX: We need to either find some way of having the * primary base layer appear black, while still * being able to display the other layers, or we @@ -1039,6 +1108,7 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) asyh->lut.offset = head->base.lut.nvbo->bo.offset; } else { asyh->core.visible = false; + asyh->curs.visible = false; } if (!drm_atomic_crtc_needs_modeset(&asyh->state)) { @@ -1049,9 +1119,19 @@ nv50_head_atomic_check(struct drm_crtc *crtc, struct drm_crtc_state *state) if (armh->core.visible) { asyh->clr.core = true; } + + if (asyh->curs.visible) { + if (memcmp(&armh->curs, &asyh->curs, sizeof(asyh->curs))) + asyh->set.curs = true; + } else + if (armh->curs.visible) { + asyh->clr.curs = true; + } } else { asyh->clr.core = armh->core.visible; + asyh->clr.curs = armh->curs.visible; asyh->set.core = asyh->core.visible; + asyh->set.curs = asyh->curs.visible; } memcpy(armh, asyh, sizeof(*asyh)); @@ -1304,55 +1384,27 @@ static void nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1); - evo_data(push, mast->base.vram.handle); - } else { - evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2); - evo_data(push, 0x85000000); - evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8); - evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); - evo_data(push, mast->base.vram.handle); - } - evo_kick(push, mast); - } - nv_crtc->cursor.visible = true; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + + asyh->curs.visible = true; + asyh->curs.handle = mast->base.vram.handle; + asyh->curs.offset = nv_crtc->cursor.nvbo->bo.offset; + asyh->curs.layout = 1; + asyh->curs.format = 1; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_set(head, asyh); } static void nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc) { - struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); - u32 *push = evo_wait(mast, 16); - if (push) { - if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x05000000); - } else - if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) { - evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x05000000); - evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1); - evo_data(push, 0x00000000); - } else { - evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x05000000); - evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); - evo_data(push, 0x00000000); - } - evo_kick(push, mast); - } - nv_crtc->cursor.visible = false; + struct nv50_head *head = nv50_head(&nv_crtc->base); + struct nv50_head_atom *asyh = &head->asy; + + asyh->curs.visible = false; + nv50_head_atomic_check(&head->base.base, &asyh->state); + nv50_head_flush_clr(head, asyh, false); } static void @@ -1383,7 +1435,6 @@ nv50_crtc_dpms(struct drm_crtc *crtc, int mode) static void nv50_crtc_prepare(struct drm_crtc *crtc) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; @@ -1392,14 +1443,11 @@ nv50_crtc_prepare(struct drm_crtc *crtc) asyh->state.active = false; nv50_head_atomic_check(&head->base.base, &asyh->state); nv50_head_flush_clr(head, asyh, false); - - nv50_crtc_cursor_show_hide(nv_crtc, false, false); } static void nv50_crtc_commit(struct drm_crtc *crtc) { - struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); struct nv50_head *head = nv50_head(crtc); struct nv50_head_atom *asyh = &head->asy; @@ -1407,7 +1455,6 @@ nv50_crtc_commit(struct drm_crtc *crtc) 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); } |