diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nv50_display.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nv50_display.c | 159 |
1 files changed, 87 insertions, 72 deletions
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c index ae873d1a8d46..490b90866baf 100644 --- a/drivers/gpu/drm/nouveau/nv50_display.c +++ b/drivers/gpu/drm/nouveau/nv50_display.c @@ -26,6 +26,7 @@ #include <drm/drmP.h> #include <drm/drm_crtc_helper.h> +#include <drm/drm_plane_helper.h> #include <drm/drm_dp_helper.h> #include <nvif/class.h> @@ -65,15 +66,29 @@ static int nv50_chan_create(struct nvif_object *disp, const u32 *oclass, u8 head, void *data, u32 size, struct nv50_chan *chan) { + const u32 handle = (oclass[0] << 16) | head; + u32 sclass[8]; + int ret, i; + + ret = nvif_object_sclass(disp, sclass, ARRAY_SIZE(sclass)); + WARN_ON(ret > ARRAY_SIZE(sclass)); + if (ret < 0) + return ret; + while (oclass[0]) { - int ret = nvif_object_init(disp, NULL, (oclass[0] << 16) | head, - oclass[0], data, size, - &chan->user); - if (oclass++, ret == 0) { - nvif_object_map(&chan->user); - return ret; + for (i = 0; i < ARRAY_SIZE(sclass); i++) { + if (sclass[i] == oclass[0]) { + ret = nvif_object_init(disp, NULL, handle, + oclass[0], data, size, + &chan->user); + if (ret == 0) + nvif_object_map(&chan->user); + return ret; + } } + oclass++; } + return -ENOSYS; } @@ -110,6 +125,7 @@ nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head, struct nv50_curs { struct nv50_pioc base; + struct nouveau_bo *image; }; static int @@ -265,6 +281,7 @@ nv50_core_create(struct nvif_object *disp, u64 syncbuf, struct nv50_mast *core) .pushbuf = 0xb0007d00, }; static const u32 oclass[] = { + GM204_DISP_CORE_CHANNEL_DMA, GM107_DISP_CORE_CHANNEL_DMA, GK110_DISP_CORE_CHANNEL_DMA, GK104_DISP_CORE_CHANNEL_DMA, @@ -424,8 +441,21 @@ evo_kick(u32 *push, void *evoc) mutex_unlock(&dmac->lock); } +#if 1 #define evo_mthd(p,m,s) *((p)++) = (((s) << 18) | (m)) #define evo_data(p,d) *((p)++) = (d) +#else +#define evo_mthd(p,m,s) do { \ + const u32 _m = (m), _s = (s); \ + printk(KERN_ERR "%04x %d %s\n", _m, _s, __func__); \ + *((p)++) = ((_s << 18) | _m); \ +} while(0) +#define evo_data(p,d) do { \ + const u32 _d = (d); \ + printk(KERN_ERR "\t%08x\n", _d); \ + *((p)++) = _d; \ +} while(0) +#endif static bool evo_sync_wait(void *data) @@ -791,6 +821,22 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update) } static int +nv50_crtc_set_raster_vblank_dmi(struct nouveau_crtc *nv_crtc, u32 usec) +{ + struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); + u32 *push; + + push = evo_wait(mast, 8); + if (!push) + return -ENOMEM; + + evo_mthd(push, 0x0828 + (nv_crtc->index * 0x400), 1); + evo_data(push, usec); + evo_kick(push, mast); + return 0; +} + +static int nv50_crtc_set_color_vibrance(struct nouveau_crtc *nv_crtc, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); @@ -871,23 +917,24 @@ static void nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); + struct nv50_curs *curs = nv50_curs(&nv_crtc->base); 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); + evo_data(push, curs->image->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_data(push, curs->image->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_data(push, curs->image->bo.offset >> 8); evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1); evo_data(push, mast->base.vram.handle); } @@ -924,8 +971,9 @@ static void nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update) { struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev); + struct nv50_curs *curs = nv50_curs(&nv_crtc->base); - if (show) + if (show && curs->image) nv50_crtc_cursor_show(nv_crtc); else nv50_crtc_cursor_hide(nv_crtc); @@ -1025,7 +1073,7 @@ nv50_crtc_commit(struct drm_crtc *crtc) evo_kick(push, mast); } - nv50_crtc_cursor_show_hide(nv_crtc, nv_crtc->cursor.visible, true); + nv50_crtc_cursor_show_hide(nv_crtc, true, true); nv50_display_flip_next(crtc, crtc->primary->fb, NULL, 1); } @@ -1044,7 +1092,7 @@ nv50_crtc_swap_fbs(struct drm_crtc *crtc, struct drm_framebuffer *old_fb) struct nv50_head *head = nv50_head(crtc); int ret; - ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(nvfb->nvbo, TTM_PL_FLAG_VRAM, true); if (ret == 0) { if (head->image) nouveau_bo_unpin(head->image); @@ -1104,14 +1152,14 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, evo_mthd(push, 0x0804 + (nv_crtc->index * 0x400), 2); evo_data(push, 0x00800000 | mode->clock); evo_data(push, (ilace == 2) ? 2 : 0); - evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 8); + evo_mthd(push, 0x0810 + (nv_crtc->index * 0x400), 6); evo_data(push, 0x00000000); evo_data(push, (vactive << 16) | hactive); evo_data(push, ( vsynce << 16) | hsynce); evo_data(push, (vblanke << 16) | hblanke); evo_data(push, (vblanks << 16) | hblanks); evo_data(push, (vblan2e << 16) | vblan2s); - evo_data(push, vblankus); + evo_mthd(push, 0x082c + (nv_crtc->index * 0x400), 1); evo_data(push, 0x00000000); evo_mthd(push, 0x0900 + (nv_crtc->index * 0x400), 2); evo_data(push, 0x00000311); @@ -1141,6 +1189,11 @@ nv50_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *umode, nv_connector = nouveau_crtc_connector_get(nv_crtc); nv50_crtc_set_dither(nv_crtc, false); nv50_crtc_set_scale(nv_crtc, false); + + /* G94 only accepts this after setting scale */ + if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) + nv50_crtc_set_raster_vblank_dmi(nv_crtc, vblankus); + nv50_crtc_set_color_vibrance(nv_crtc, false); nv50_crtc_set_image(nv_crtc, crtc->primary->fb, x, y, false); return 0; @@ -1220,13 +1273,13 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, uint32_t handle, uint32_t width, uint32_t height) { struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc); + struct nv50_curs *curs = nv50_curs(crtc); struct drm_device *dev = crtc->dev; - struct drm_gem_object *gem; - struct nouveau_bo *nvbo; - bool visible = (handle != 0); - int i, ret = 0; + struct drm_gem_object *gem = NULL; + struct nouveau_bo *nvbo = NULL; + int ret = 0; - if (visible) { + if (handle) { if (width != 64 || height != 64) return -EINVAL; @@ -1235,23 +1288,17 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv, return -ENOENT; nvbo = nouveau_gem_object(gem); - ret = nouveau_bo_map(nvbo); - if (ret == 0) { - for (i = 0; i < 64 * 64; i++) { - u32 v = nouveau_bo_rd32(nvbo, i); - nouveau_bo_wr32(nv_crtc->cursor.nvbo, i, v); - } - nouveau_bo_unmap(nvbo); - } - - drm_gem_object_unreference_unlocked(gem); + ret = nouveau_bo_pin(nvbo, TTM_PL_FLAG_VRAM, true); } - if (visible != nv_crtc->cursor.visible) { - nv50_crtc_cursor_show_hide(nv_crtc, visible, true); - nv_crtc->cursor.visible = visible; + if (ret == 0) { + if (curs->image) + nouveau_bo_unpin(curs->image); + nouveau_bo_ref(nvbo, &curs->image); } + drm_gem_object_unreference_unlocked(gem); + nv50_crtc_cursor_show_hide(nv_crtc, true, true); return ret; } @@ -1306,10 +1353,10 @@ nv50_crtc_destroy(struct drm_crtc *crtc) nouveau_bo_unpin(head->image); nouveau_bo_ref(NULL, &head->image); - nouveau_bo_unmap(nv_crtc->cursor.nvbo); - if (nv_crtc->cursor.nvbo) - nouveau_bo_unpin(nv_crtc->cursor.nvbo); - nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo); + /*XXX: ditto */ + if (head->curs.image) + nouveau_bo_unpin(head->curs.image); + nouveau_bo_ref(NULL, &head->curs.image); nouveau_bo_unmap(nv_crtc->lut.nvbo); if (nv_crtc->lut.nvbo) @@ -1341,16 +1388,6 @@ static const struct drm_crtc_funcs nv50_crtc_func = { .page_flip = nouveau_crtc_page_flip, }; -static void -nv50_cursor_set_pos(struct nouveau_crtc *nv_crtc, int x, int y) -{ -} - -static void -nv50_cursor_set_offset(struct nouveau_crtc *nv_crtc, uint32_t offset) -{ -} - static int nv50_crtc_create(struct drm_device *dev, int index) { @@ -1369,8 +1406,6 @@ nv50_crtc_create(struct drm_device *dev, int index) head->base.set_color_vibrance = nv50_crtc_set_color_vibrance; head->base.color_vibrance = 50; head->base.vibrant_hue = 0; - head->base.cursor.set_offset = nv50_cursor_set_offset; - head->base.cursor.set_pos = nv50_cursor_set_pos; for (i = 0; i < 256; i++) { head->base.lut.r[i] = i << 8; head->base.lut.g[i] = i << 8; @@ -1385,7 +1420,7 @@ nv50_crtc_create(struct drm_device *dev, int index) ret = nouveau_bo_new(dev, 8192, 0x100, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &head->base.lut.nvbo); if (!ret) { - ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(head->base.lut.nvbo, TTM_PL_FLAG_VRAM, true); if (!ret) { ret = nouveau_bo_map(head->base.lut.nvbo); if (ret) @@ -1405,22 +1440,6 @@ nv50_crtc_create(struct drm_device *dev, int index) if (ret) goto out; - ret = nouveau_bo_new(dev, 64 * 64 * 4, 0x100, TTM_PL_FLAG_VRAM, - 0, 0x0000, NULL, NULL, &head->base.cursor.nvbo); - if (!ret) { - ret = nouveau_bo_pin(head->base.cursor.nvbo, TTM_PL_FLAG_VRAM); - if (!ret) { - ret = nouveau_bo_map(head->base.cursor.nvbo); - if (ret) - nouveau_bo_unpin(head->base.lut.nvbo); - } - if (ret) - nouveau_bo_ref(NULL, &head->base.cursor.nvbo); - } - - if (ret) - goto out; - /* allocate page flip / sync resources */ ret = nv50_base_create(disp->disp, index, disp->sync->bo.offset, &head->sync); @@ -1680,7 +1699,8 @@ nv50_audio_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode) drm_edid_to_eld(&nv_connector->base, nv_connector->edid); memcpy(args.data, nv_connector->base.eld, sizeof(args.data)); - nvif_mthd(disp->disp, 0, &args, sizeof(args.base) + args.data[2] * 4); + nvif_mthd(disp->disp, 0, &args, + sizeof(args.base) + drm_eld_size(args.data)); } static void @@ -2352,11 +2372,6 @@ nv50_fb_ctor(struct drm_framebuffer *fb) u8 kind = nouveau_bo_tile_layout(nvbo) >> 8; u8 tile = nvbo->tile_mode; - if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) { - NV_ERROR(drm, "framebuffer requires contiguous bo\n"); - return -EINVAL; - } - if (drm->device.info.chipset >= 0xc0) tile >>= 4; /* yep.. */ @@ -2470,7 +2485,7 @@ nv50_display_create(struct drm_device *dev) ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM, 0, 0x0000, NULL, NULL, &disp->sync); if (!ret) { - ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM); + ret = nouveau_bo_pin(disp->sync, TTM_PL_FLAG_VRAM, true); if (!ret) { ret = nouveau_bo_map(disp->sync); if (ret) |