From: Ben Skeggs Date: Tue, 14 Aug 2012 04:11:49 +0000 (+1000) Subject: drm/nv50/disp: initial implementation of the various channel object classes X-Git-Url: https://git.karo-electronics.de/?a=commitdiff_plain;h=370c00f939c5dddd527ab5cfa8740ba7683ac630;p=linux-beck.git drm/nv50/disp: initial implementation of the various channel object classes Signed-off-by: Ben Skeggs --- diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c index 8d3b6a21d62a..531175da6bb3 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c @@ -22,26 +22,198 @@ * Authors: Ben Skeggs */ +#include +#include +#include +#include + #include #include #include +#include +#include #include "nv50.h" /******************************************************************************* - * EVO channel common helpers + * EVO channel base class ******************************************************************************/ -static u32 +int +nv50_disp_chan_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int chid, + int length, void **pobject) +{ + struct nv50_disp_base *base = (void *)parent; + struct nv50_disp_chan *chan; + int ret; + + if (base->chan & (1 << chid)) + return -EBUSY; + base->chan |= (1 << chid); + + ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL, + (1ULL << NVDEV_ENGINE_DMAOBJ), + length, pobject); + chan = *pobject; + if (ret) + return ret; + + chan->chid = chid; + return 0; +} + +void +nv50_disp_chan_destroy(struct nv50_disp_chan *chan) +{ + struct nv50_disp_base *base = (void *)nv_object(chan)->parent; + base->chan &= ~(1 << chan->chid); + nouveau_namedb_destroy(&chan->base); +} + +u32 nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr) { - return 0xdeadcafe; + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_chan *chan = (void *)object; + return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr); } -static void +void nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data) { + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_chan *chan = (void *)object; + nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data); +} + +/******************************************************************************* + * EVO DMA channel base class + ******************************************************************************/ + +static int +nv50_disp_dmac_object_attach(struct nouveau_object *parent, + struct nouveau_object *object, u32 name) +{ + struct nv50_disp_base *base = (void *)parent->parent; + struct nv50_disp_chan *chan = (void *)parent; + u32 addr = nv_gpuobj(object)->node->offset; + u32 chid = chan->chid; + u32 data = (chid << 28) | (addr << 10) | chid; + return nouveau_ramht_insert(base->ramht, chid, name, data); +} + +static void +nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie) +{ + struct nv50_disp_base *base = (void *)parent->parent; + nouveau_ramht_remove(base->ramht, cookie); +} + +int +nv50_disp_dmac_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, u32 pushbuf, int chid, + int length, void **pobject) +{ + struct nv50_disp_dmac *dmac; + int ret; + + ret = nv50_disp_chan_create_(parent, engine, oclass, chid, + length, pobject); + dmac = *pobject; + if (ret) + return ret; + + dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf); + if (!dmac->pushdma) + return -ENOENT; + + switch (nv_mclass(dmac->pushdma)) { + case 0x0002: + case 0x003d: + if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff) + return -EINVAL; + + switch (dmac->pushdma->target) { + case NV_MEM_TARGET_VRAM: + dmac->push = 0x00000000 | dmac->pushdma->start >> 8; + break; + default: + return -EINVAL; + } + break; + default: + return -EINVAL; + } + + return 0; +} + +void +nv50_disp_dmac_dtor(struct nouveau_object *object) +{ + struct nv50_disp_dmac *dmac = (void *)object; + nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma); + nv50_disp_chan_destroy(&dmac->base); +} + +static int +nv50_disp_dmac_init(struct nouveau_object *object) +{ + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + int chid = dmac->base.chid; + int ret; + + ret = nv50_disp_chan_init(&dmac->base); + if (ret) + return ret; + + /* enable error reporting */ + nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00010001 << chid); + + /* initialise channel for dma command submission */ + nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push); + nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000); + nv_wr32(priv, 0x61020c + (chid * 0x0010), chid); + nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010); + nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000); + nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013); + + /* wait for it to go inactive */ + if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) { + nv_error(dmac, "init timeout, 0x%08x\n", + nv_rd32(priv, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + return 0; +} + +static int +nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend) +{ + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_dmac *dmac = (void *)object; + int chid = dmac->base.chid; + + /* deactivate channel */ + nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000); + nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000); + if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) { + nv_error(dmac, "fini timeout, 0x%08x\n", + nv_rd32(priv, 0x610200 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + /* disable error reporting */ + nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid); + + return nv50_disp_chan_fini(&dmac->base, suspend); } /******************************************************************************* @@ -54,48 +226,86 @@ nv50_disp_mast_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_disp_chan *chan; + struct nv50_display_mast_class *args = data; + struct nv50_disp_dmac *mast; int ret; - ret = nouveau_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); + if (size < sizeof(*args)) + return -EINVAL; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, + 0, sizeof(*mast), (void **)&mast); + *pobject = nv_object(mast); if (ret) return ret; + nv_parent(mast)->object_attach = nv50_disp_dmac_object_attach; + nv_parent(mast)->object_detach = nv50_disp_dmac_object_detach; return 0; } -static void -nv50_disp_mast_dtor(struct nouveau_object *object) -{ - struct nv50_disp_chan *chan = (void *)object; - nouveau_object_destroy(&chan->base); -} - static int nv50_disp_mast_init(struct nouveau_object *object) { - struct nv50_disp_chan *chan = (void *)object; + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; int ret; - ret = nouveau_object_init(&chan->base); + ret = nv50_disp_chan_init(&mast->base); if (ret) return ret; + /* enable error reporting */ + nv_mask(priv, 0x610028, 0x00010001, 0x00010001); + + /* attempt to unstick channel from some unknown state */ + if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000) + nv_mask(priv, 0x610200, 0x00800000, 0x00800000); + if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000) + nv_mask(priv, 0x610200, 0x00600000, 0x00600000); + + /* initialise channel for dma command submission */ + nv_wr32(priv, 0x610204, mast->push); + nv_wr32(priv, 0x610208, 0x00010000); + nv_wr32(priv, 0x61020c, 0x00000000); + nv_mask(priv, 0x610200, 0x00000010, 0x00000010); + nv_wr32(priv, 0x640000, 0x00000000); + nv_wr32(priv, 0x610200, 0x01000013); + + /* wait for it to go inactive */ + if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) { + nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200)); + return -EBUSY; + } + return 0; } static int nv50_disp_mast_fini(struct nouveau_object *object, bool suspend) { - struct nv50_disp_chan *chan = (void *)object; - return nouveau_object_fini(&chan->base, suspend); + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_dmac *mast = (void *)object; + + /* deactivate channel */ + nv_mask(priv, 0x610200, 0x00000010, 0x00000000); + nv_mask(priv, 0x610200, 0x00000003, 0x00000000); + if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) { + nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200)); + if (suspend) + return -EBUSY; + } + + /* disable error reporting */ + nv_mask(priv, 0x610028, 0x00010001, 0x00000000); + + return nv50_disp_chan_fini(&mast->base, suspend); } struct nouveau_ofuncs nv50_disp_mast_ofuncs = { .ctor = nv50_disp_mast_ctor, - .dtor = nv50_disp_mast_dtor, + .dtor = nv50_disp_dmac_dtor, .init = nv50_disp_mast_init, .fini = nv50_disp_mast_fini, .rd32 = nv50_disp_chan_rd32, @@ -103,56 +313,76 @@ nv50_disp_mast_ofuncs = { }; /******************************************************************************* - * EVO DMA channel objects (sync, overlay) + * EVO sync channel objects ******************************************************************************/ static int -nv50_disp_dmac_ctor(struct nouveau_object *parent, +nv50_disp_sync_ctor(struct nouveau_object *parent, struct nouveau_object *engine, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { - struct nv50_disp_chan *chan; + struct nv50_display_sync_class *args = data; + struct nv50_disp_dmac *dmac; int ret; - ret = nouveau_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); + if (size < sizeof(*data) || args->head > 1) + return -EINVAL; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, + 1 + args->head, sizeof(*dmac), + (void **)&dmac); + *pobject = nv_object(dmac); if (ret) return ret; + nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach; + nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach; return 0; } -static void -nv50_disp_dmac_dtor(struct nouveau_object *object) -{ - struct nv50_disp_chan *chan = (void *)object; - nouveau_object_destroy(&chan->base); -} +struct nouveau_ofuncs +nv50_disp_sync_ofuncs = { + .ctor = nv50_disp_sync_ctor, + .dtor = nv50_disp_dmac_dtor, + .init = nv50_disp_dmac_init, + .fini = nv50_disp_dmac_fini, + .rd32 = nv50_disp_chan_rd32, + .wr32 = nv50_disp_chan_wr32, +}; + +/******************************************************************************* + * EVO overlay channel objects + ******************************************************************************/ static int -nv50_disp_dmac_init(struct nouveau_object *object) +nv50_disp_ovly_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv50_disp_chan *chan = (void *)object; + struct nv50_display_ovly_class *args = data; + struct nv50_disp_dmac *dmac; int ret; - ret = nouveau_object_init(&chan->base); + if (size < sizeof(*data) || args->head > 1) + return -EINVAL; + + ret = nv50_disp_dmac_create_(parent, engine, oclass, args->pushbuf, + 3 + args->head, sizeof(*dmac), + (void **)&dmac); + *pobject = nv_object(dmac); if (ret) return ret; + nv_parent(dmac)->object_attach = nv50_disp_dmac_object_attach; + nv_parent(dmac)->object_detach = nv50_disp_dmac_object_detach; return 0; } -static int -nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend) -{ - struct nv50_disp_chan *chan = (void *)object; - return nouveau_object_fini(&chan->base, suspend); -} - struct nouveau_ofuncs -nv50_disp_dmac_ofuncs = { - .ctor = nv50_disp_dmac_ctor, +nv50_disp_ovly_ofuncs = { + .ctor = nv50_disp_ovly_ctor, .dtor = nv50_disp_dmac_dtor, .init = nv50_disp_dmac_init, .fini = nv50_disp_dmac_fini, @@ -161,56 +391,138 @@ nv50_disp_dmac_ofuncs = { }; /******************************************************************************* - * EVO PIO channel objects (cursor, immediate overlay controls) + * EVO PIO channel base class ******************************************************************************/ static int -nv50_disp_pioc_ctor(struct nouveau_object *parent, - struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) +nv50_disp_pioc_create_(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, int chid, + int length, void **pobject) { - struct nv50_disp_chan *chan; + return nv50_disp_chan_create_(parent, engine, oclass, chid, + length, pobject); +} + +static void +nv50_disp_pioc_dtor(struct nouveau_object *object) +{ + struct nv50_disp_pioc *pioc = (void *)object; + nv50_disp_chan_destroy(&pioc->base); +} + +static int +nv50_disp_pioc_init(struct nouveau_object *object) +{ + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + int chid = pioc->base.chid; int ret; - ret = nouveau_object_create(parent, engine, oclass, 0, &chan); - *pobject = nv_object(chan); + ret = nv50_disp_chan_init(&pioc->base); if (ret) return ret; + nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000); + if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) { + nv_error(pioc, "timeout0: 0x%08x\n", + nv_rd32(priv, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + + nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001); + if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) { + nv_error(pioc, "timeout1: 0x%08x\n", + nv_rd32(priv, 0x610200 + (chid * 0x10))); + return -EBUSY; + } + return 0; } -static void -nv50_disp_pioc_dtor(struct nouveau_object *object) +static int +nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend) { - struct nv50_disp_chan *chan = (void *)object; - nouveau_object_destroy(&chan->base); + struct nv50_disp_priv *priv = (void *)object->engine; + struct nv50_disp_pioc *pioc = (void *)object; + int chid = pioc->base.chid; + + nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000); + if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) { + nv_error(pioc, "timeout: 0x%08x\n", + nv_rd32(priv, 0x610200 + (chid * 0x10))); + if (suspend) + return -EBUSY; + } + + return nv50_disp_chan_fini(&pioc->base, suspend); } +/******************************************************************************* + * EVO immediate overlay channel objects + ******************************************************************************/ + static int -nv50_disp_pioc_init(struct nouveau_object *object) +nv50_disp_oimm_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv50_disp_chan *chan = (void *)object; + struct nv50_display_oimm_class *args = data; + struct nv50_disp_pioc *pioc; int ret; - ret = nouveau_object_init(&chan->base); + if (size < sizeof(*args) || args->head > 1) + return -EINVAL; + + ret = nv50_disp_pioc_create_(parent, engine, oclass, 5 + args->head, + sizeof(*pioc), (void **)&pioc); + *pobject = nv_object(pioc); if (ret) return ret; return 0; } +struct nouveau_ofuncs +nv50_disp_oimm_ofuncs = { + .ctor = nv50_disp_oimm_ctor, + .dtor = nv50_disp_pioc_dtor, + .init = nv50_disp_pioc_init, + .fini = nv50_disp_pioc_fini, + .rd32 = nv50_disp_chan_rd32, + .wr32 = nv50_disp_chan_wr32, +}; + +/******************************************************************************* + * EVO cursor channel objects + ******************************************************************************/ + static int -nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend) +nv50_disp_curs_ctor(struct nouveau_object *parent, + struct nouveau_object *engine, + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { - struct nv50_disp_chan *chan = (void *)object; - return nouveau_object_fini(&chan->base, suspend); + struct nv50_display_curs_class *args = data; + struct nv50_disp_pioc *pioc; + int ret; + + if (size < sizeof(*args) || args->head > 1) + return -EINVAL; + + ret = nv50_disp_pioc_create_(parent, engine, oclass, 7 + args->head, + sizeof(*pioc), (void **)&pioc); + *pobject = nv_object(pioc); + if (ret) + return ret; + + return 0; } struct nouveau_ofuncs -nv50_disp_pioc_ofuncs = { - .ctor = nv50_disp_pioc_ctor, +nv50_disp_curs_ofuncs = { + .ctor = nv50_disp_curs_ctor, .dtor = nv50_disp_pioc_dtor, .init = nv50_disp_pioc_init, .fini = nv50_disp_pioc_fini, @@ -238,13 +550,14 @@ nv50_disp_base_ctor(struct nouveau_object *parent, if (ret) return ret; - return 0; + return nouveau_ramht_new(parent, parent, 0x1000, 0, &base->ramht); } static void nv50_disp_base_dtor(struct nouveau_object *object) { struct nv50_disp_base *base = (void *)object; + nouveau_ramht_ref(NULL, &base->ramht); nouveau_parent_destroy(&base->base); } @@ -308,11 +621,11 @@ nv50_disp_base_init(struct nouveau_object *object) } /* point at display engine memory area (hash table, objects) */ - nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9); + nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9); /* enable supervisor interrupts, disable everything else */ - nv_wr32(priv, 0x610024, 0x00000370); - nv_wr32(priv, 0x610020, 0x00000000); + nv_wr32(priv, 0x61002c, 0x00000370); + nv_wr32(priv, 0x610028, 0x00000000); return 0; } @@ -326,10 +639,6 @@ nv50_disp_base_fini(struct nouveau_object *object, bool suspend) nv_wr32(priv, 0x610024, 0x00000000); nv_wr32(priv, 0x610020, 0x00000000); - /* return control of display to vbios */ - nv_mask(priv, 0x6194e8, 0x00000001, 0x00000001); - nv_wait(priv, 0x6194e8, 0x00000002, 0x00000002); - return nouveau_parent_fini(&base->base, suspend); } @@ -343,16 +652,17 @@ nv50_disp_base_ofuncs = { static struct nouveau_oclass nv50_disp_base_oclass[] = { - { 0x5070, &nv50_disp_base_ofuncs }, + { NV50_DISP_CLASS, &nv50_disp_base_ofuncs }, + {} }; static struct nouveau_oclass nv50_disp_sclass[] = { - { 0x507d, &nv50_disp_mast_ofuncs }, /* master */ - { 0x507c, &nv50_disp_dmac_ofuncs }, /* sync */ - { 0x507e, &nv50_disp_dmac_ofuncs }, /* overlay */ - { 0x507b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */ - { 0x507a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */ + { NV50_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, + { NV50_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, + { NV50_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, + { NV50_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, + { NV50_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, {} }; @@ -367,16 +677,27 @@ nv50_disp_data_ctor(struct nouveau_object *parent, struct nouveau_oclass *oclass, void *data, u32 size, struct nouveau_object **pobject) { + struct nv50_disp_priv *priv = (void *)engine; struct nouveau_engctx *ectx; - int ret; + int ret = -EBUSY; - ret = nouveau_engctx_create(parent, engine, oclass, NULL, 0x10000, - 0x10000, NVOBJ_FLAG_ZERO_ALLOC, &ectx); - *pobject = nv_object(ectx); - if (ret) - return ret; + /* no context needed for channel objects... */ + if (nv_mclass(parent) != NV_DEVICE_CLASS) { + atomic_inc(&parent->refcount); + *pobject = parent; + return 0; + } - return 0; + /* allocate display hardware to client */ + mutex_lock(&nv_subdev(priv)->mutex); + if (list_empty(&nv_engine(priv)->contexts)) { + ret = nouveau_engctx_create(parent, engine, oclass, NULL, + 0x10000, 0x10000, + NVOBJ_FLAG_HEAP, &ectx); + *pobject = nv_object(ectx); + } + mutex_unlock(&nv_subdev(priv)->mutex); + return ret; } struct nouveau_oclass @@ -455,8 +776,8 @@ nv50_disp_intr(struct nouveau_subdev *subdev) static int nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine, - struct nouveau_oclass *oclass, void *data, u32 size, - struct nouveau_object **pobject) + struct nouveau_oclass *oclass, void *data, u32 size, + struct nouveau_object **pobject) { struct nv50_disp_priv *priv; int ret; diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h index 06753f623f2e..6128bc4b4cb1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h @@ -2,6 +2,10 @@ #define __NV50_DISP_H__ #include +#include +#include + +#include #include struct nv50_disp_priv { @@ -20,15 +24,45 @@ struct nv50_disp_priv { struct nv50_disp_base { struct nouveau_parent base; + struct nouveau_ramht *ramht; + u32 chan; }; struct nv50_disp_chan { - struct nouveau_object base; + struct nouveau_namedb base; + int chid; +}; + +int nv50_disp_chan_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, int, int, void **); +void nv50_disp_chan_destroy(struct nv50_disp_chan *); +u32 nv50_disp_chan_rd32(struct nouveau_object *, u64); +void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32); + +#define nv50_disp_chan_init(a) \ + nouveau_namedb_init(&(a)->base) +#define nv50_disp_chan_fini(a,b) \ + nouveau_namedb_fini(&(a)->base, (b)) + +int nv50_disp_dmac_create_(struct nouveau_object *, struct nouveau_object *, + struct nouveau_oclass *, u32, int, int, void **); +void nv50_disp_dmac_dtor(struct nouveau_object *); + +struct nv50_disp_dmac { + struct nv50_disp_chan base; + struct nouveau_dmaobj *pushdma; + u32 push; +}; + +struct nv50_disp_pioc { + struct nv50_disp_chan base; }; extern struct nouveau_ofuncs nv50_disp_mast_ofuncs; -extern struct nouveau_ofuncs nv50_disp_dmac_ofuncs; -extern struct nouveau_ofuncs nv50_disp_pioc_ofuncs; +extern struct nouveau_ofuncs nv50_disp_sync_ofuncs; +extern struct nouveau_ofuncs nv50_disp_ovly_ofuncs; +extern struct nouveau_ofuncs nv50_disp_oimm_ofuncs; +extern struct nouveau_ofuncs nv50_disp_curs_ofuncs; extern struct nouveau_ofuncs nv50_disp_base_ofuncs; extern struct nouveau_oclass nv50_disp_cclass; void nv50_disp_intr(struct nouveau_subdev *); diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c index b262b167062c..3132301341d1 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c @@ -25,21 +25,24 @@ #include #include +#include + #include "nv50.h" static struct nouveau_oclass nv84_disp_sclass[] = { - { 0x827d, &nv50_disp_mast_ofuncs }, /* master */ - { 0x827c, &nv50_disp_dmac_ofuncs }, /* sync */ - { 0x827e, &nv50_disp_dmac_ofuncs }, /* overlay */ - { 0x827b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */ - { 0x827a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */ + { NV84_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, + { NV84_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, + { NV84_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, + { NV84_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, + { NV84_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, {} }; static struct nouveau_oclass nv84_disp_base_oclass[] = { - { 0x8270, &nv50_disp_base_ofuncs }, + { NV84_DISP_CLASS, &nv50_disp_base_ofuncs }, + {} }; static int diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c index 9d75f060bf0e..851abb73bc94 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c @@ -25,21 +25,24 @@ #include #include +#include + #include "nv50.h" static struct nouveau_oclass nv94_disp_sclass[] = { - { 0x887d, &nv50_disp_mast_ofuncs }, /* master */ - { 0x887c, &nv50_disp_dmac_ofuncs }, /* sync */ - { 0x887e, &nv50_disp_dmac_ofuncs }, /* overlay */ - { 0x887b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */ - { 0x887a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */ + { NV94_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, + { NV94_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, + { NV94_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, + { NV94_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, + { NV94_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, {} }; static struct nouveau_oclass nv94_disp_base_oclass[] = { - { 0x8870, &nv50_disp_base_ofuncs }, + { NV94_DISP_CLASS, &nv50_disp_base_ofuncs }, + {} }; static int diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c index 4fd0e39f59e9..f96ab6c55947 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c @@ -25,21 +25,24 @@ #include #include +#include + #include "nv50.h" static struct nouveau_oclass nva0_disp_sclass[] = { - { 0x837d, &nv50_disp_mast_ofuncs }, /* master */ - { 0x837c, &nv50_disp_dmac_ofuncs }, /* sync */ - { 0x837e, &nv50_disp_dmac_ofuncs }, /* overlay */ - { 0x837b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */ - { 0x837a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */ + { NVA0_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, + { NVA0_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, + { NVA0_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, + { NVA0_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, + { NVA0_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, {} }; static struct nouveau_oclass nva0_disp_base_oclass[] = { - { 0x8370, &nv50_disp_base_ofuncs }, + { NVA0_DISP_CLASS, &nv50_disp_base_ofuncs }, + {} }; static int diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c index e8da5e069605..08945cb3ea8e 100644 --- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c +++ b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c @@ -25,21 +25,24 @@ #include #include +#include + #include "nv50.h" static struct nouveau_oclass nva3_disp_sclass[] = { - { 0x857d, &nv50_disp_mast_ofuncs }, /* master */ - { 0x857c, &nv50_disp_dmac_ofuncs }, /* sync */ - { 0x857e, &nv50_disp_dmac_ofuncs }, /* overlay */ - { 0x857b, &nv50_disp_pioc_ofuncs }, /* overlay (pio) */ - { 0x857a, &nv50_disp_pioc_ofuncs }, /* cursor (pio) */ + { NVA3_DISP_MAST_CLASS, &nv50_disp_mast_ofuncs }, + { NVA3_DISP_SYNC_CLASS, &nv50_disp_sync_ofuncs }, + { NVA3_DISP_OVLY_CLASS, &nv50_disp_ovly_ofuncs }, + { NVA3_DISP_OIMM_CLASS, &nv50_disp_oimm_ofuncs }, + { NVA3_DISP_CURS_CLASS, &nv50_disp_curs_ofuncs }, {} }; static struct nouveau_oclass nva3_disp_base_oclass[] = { - { 0x8570, &nv50_disp_base_ofuncs }, + { NVA3_DISP_CLASS, &nv50_disp_base_ofuncs }, + {} }; static int diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c index bda7afcf8d3c..750183f7c057 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c @@ -48,6 +48,21 @@ nv50_dmaobj_bind(struct nouveau_dmaeng *dmaeng, case NV84_CHANNEL_DMA_CLASS: case NV50_CHANNEL_IND_CLASS: case NV84_CHANNEL_IND_CLASS: + case NV50_DISP_MAST_CLASS: + case NV84_DISP_MAST_CLASS: + case NV94_DISP_MAST_CLASS: + case NVA0_DISP_MAST_CLASS: + case NVA3_DISP_MAST_CLASS: + case NV50_DISP_SYNC_CLASS: + case NV84_DISP_SYNC_CLASS: + case NV94_DISP_SYNC_CLASS: + case NVA0_DISP_SYNC_CLASS: + case NVA3_DISP_SYNC_CLASS: + case NV50_DISP_OVLY_CLASS: + case NV84_DISP_OVLY_CLASS: + case NV94_DISP_OVLY_CLASS: + case NVA0_DISP_OVLY_CLASS: + case NVA3_DISP_OVLY_CLASS: break; default: return -EINVAL; diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c index b261a8ffe494..cd3970d03b80 100644 --- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c +++ b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c @@ -45,6 +45,10 @@ nvc0_dmaobj_bind(struct nouveau_dmaeng *dmaeng, if (!nv_iclass(parent, NV_ENGCTX_CLASS)) { switch (nv_mclass(parent->parent)) { + case NVA3_DISP_MAST_CLASS: + case NVA3_DISP_SYNC_CLASS: + case NVA3_DISP_OVLY_CLASS: + break; default: return -EINVAL; } diff --git a/drivers/gpu/drm/nouveau/core/include/core/class.h b/drivers/gpu/drm/nouveau/core/include/core/class.h index b8520334935e..e9634b4ed8c6 100644 --- a/drivers/gpu/drm/nouveau/core/include/core/class.h +++ b/drivers/gpu/drm/nouveau/core/include/core/class.h @@ -153,4 +153,107 @@ struct nve0_channel_ind_class { u32 engine; }; +/* 5070: NV50_DISP + * 8270: NV84_DISP + * 8370: NVA0_DISP + * 8870: NV94_DISP + * 8570: NVA3_DISP + */ + +#define NV50_DISP_CLASS 0x00005070 +#define NV84_DISP_CLASS 0x00008270 +#define NVA0_DISP_CLASS 0x00008370 +#define NV94_DISP_CLASS 0x00008870 +#define NVA3_DISP_CLASS 0x00008570 + +struct nv50_display_class { +}; + +/* 507a: NV50_DISP_CURS + * 827a: NV84_DISP_CURS + * 837a: NVA0_DISP_CURS + * 887a: NV94_DISP_CURS + * 857a: NVA3_DISP_CURS + */ + +#define NV50_DISP_CURS_CLASS 0x0000507a +#define NV84_DISP_CURS_CLASS 0x0000827a +#define NVA0_DISP_CURS_CLASS 0x0000837a +#define NV94_DISP_CURS_CLASS 0x0000887a +#define NVA3_DISP_CURS_CLASS 0x0000857a + +struct nv50_display_curs_class { + u32 head; +}; + +/* 507b: NV50_DISP_OIMM + * 827b: NV84_DISP_OIMM + * 837b: NVA0_DISP_OIMM + * 887b: NV94_DISP_OIMM + * 857b: NVA3_DISP_OIMM + */ + +#define NV50_DISP_OIMM_CLASS 0x0000507b +#define NV84_DISP_OIMM_CLASS 0x0000827b +#define NVA0_DISP_OIMM_CLASS 0x0000837b +#define NV94_DISP_OIMM_CLASS 0x0000887b +#define NVA3_DISP_OIMM_CLASS 0x0000857b + +struct nv50_display_oimm_class { + u32 head; +}; + +/* 507c: NV50_DISP_SYNC + * 827c: NV84_DISP_SYNC + * 837c: NVA0_DISP_SYNC + * 887c: NV94_DISP_SYNC + * 857c: NVA3_DISP_SYNC + */ + +#define NV50_DISP_SYNC_CLASS 0x0000507c +#define NV84_DISP_SYNC_CLASS 0x0000827c +#define NVA0_DISP_SYNC_CLASS 0x0000837c +#define NV94_DISP_SYNC_CLASS 0x0000887c +#define NVA3_DISP_SYNC_CLASS 0x0000857c + +struct nv50_display_sync_class { + u32 pushbuf; + u32 head; +}; + +/* 507d: NV50_DISP_MAST + * 827d: NV84_DISP_MAST + * 837d: NVA0_DISP_MAST + * 887d: NV94_DISP_MAST + * 857d: NVA3_DISP_MAST + */ + +#define NV50_DISP_MAST_CLASS 0x0000507d +#define NV84_DISP_MAST_CLASS 0x0000827d +#define NVA0_DISP_MAST_CLASS 0x0000837d +#define NV94_DISP_MAST_CLASS 0x0000887d +#define NVA3_DISP_MAST_CLASS 0x0000857d + +struct nv50_display_mast_class { + u32 pushbuf; +}; + +/* 507e: NV50_DISP_OVLY + * 827e: NV84_DISP_OVLY + * 837e: NVA0_DISP_OVLY + * 887e: NV94_DISP_OVLY + * 857e: NVA3_DISP_OVLY + */ + +#define NV50_DISP_OVLY_CLASS 0x0000507e +#define NV84_DISP_OVLY_CLASS 0x0000827e +#define NVA0_DISP_OVLY_CLASS 0x0000837e +#define NV94_DISP_OVLY_CLASS 0x0000887e +#define NVA3_DISP_OVLY_CLASS 0x0000857e + +struct nv50_display_ovly_class { + u32 pushbuf; + u32 head; +}; + #endif