diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c | 184 |
1 files changed, 128 insertions, 56 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c index 2999996497ff..c9cbfbd2a1ae 100644 --- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c +++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/channv50.c @@ -24,6 +24,10 @@ #include "channv50.h" #include "rootnv50.h" +#include <core/client.h> +#include <core/ramht.h> +#include <engine/dma.h> + #include <nvif/class.h> #include <nvif/event.h> #include <nvif/unpack.h> @@ -58,39 +62,38 @@ nv50_disp_mthd_list(struct nv50_disp *disp, int debug, u32 base, int c, } void -nv50_disp_mthd_chan(struct nv50_disp *disp, int debug, int head, - const struct nv50_disp_mthd_chan *chan) +nv50_disp_chan_mthd(struct nv50_disp_chan *chan, int debug) { - struct nvkm_object *object = nv_object(disp); - const struct nv50_disp_impl *impl = (void *)object->oclass; - const struct nv50_disp_mthd_list *list; + struct nv50_disp *disp = chan->root->disp; struct nvkm_subdev *subdev = &disp->base.engine.subdev; + const struct nv50_disp_chan_mthd *mthd = chan->mthd; + const struct nv50_disp_mthd_list *list; int i, j; - if (debug > nv_subdev(disp)->debug) + if (debug > subdev->debug) return; - for (i = 0; (list = chan->data[i].mthd) != NULL; i++) { - u32 base = head * chan->addr; - for (j = 0; j < chan->data[i].nr; j++, base += list->addr) { - const char *cname = chan->name; + for (i = 0; (list = mthd->data[i].mthd) != NULL; i++) { + u32 base = chan->head * mthd->addr; + for (j = 0; j < mthd->data[i].nr; j++, base += list->addr) { + const char *cname = mthd->name; const char *sname = ""; char cname_[16], sname_[16]; - if (chan->addr) { + if (mthd->addr) { snprintf(cname_, sizeof(cname_), "%s %d", - chan->name, head); + mthd->name, chan->chid); cname = cname_; } - if (chan->data[i].nr > 1) { + if (mthd->data[i].nr > 1) { snprintf(sname_, sizeof(sname_), " - %s %d", - chan->data[i].name, j); + mthd->data[i].name, j); sname = sname_; } nvkm_printk_(subdev, debug, info, "%s%s:\n", cname, sname); - nv50_disp_mthd_list(disp, debug, base, impl->mthd.prev, + nv50_disp_mthd_list(disp, debug, base, mthd->prev, list, j); } } @@ -127,7 +130,7 @@ int nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, struct nvkm_notify *notify) { - struct nv50_disp_dmac *dmac = (void *)object; + struct nv50_disp_chan *chan = nv50_disp_chan(object); union { struct nvif_notify_uevent_req none; } *args = data; @@ -136,7 +139,7 @@ nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size, if (nvif_unvers(args->none)) { notify->size = sizeof(struct nvif_notify_uevent_rep); notify->types = 1; - notify->index = dmac->base.chid; + notify->index = chan->chid; return 0; } @@ -151,10 +154,31 @@ nv50_disp_chan_uevent = { }; int +nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *data = nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); + return 0; +} + +int +nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); + return 0; +} + +int nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pevent) { - struct nv50_disp *disp = (void *)object->engine; + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; switch (type) { case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT: *pevent = &disp->uevent; @@ -168,62 +192,110 @@ nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type, int nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size) { - struct nv50_disp_chan *chan = (void *)object; - *addr = nv_device_resource_start(nv_device(object), 0) + + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + struct nvkm_device *device = disp->base.engine.subdev.device; + *addr = nv_device_resource_start(device, 0) + 0x640000 + (chan->chid * 0x1000); *size = 0x001000; return 0; } -u32 -nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr) +static int +nv50_disp_chan_child_new(const struct nvkm_oclass *oclass, + void *data, u32 size, struct nvkm_object **pobject) { - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - return nvkm_rd32(device, 0x640000 + (chan->chid * 0x1000) + addr); + struct nv50_disp_chan *chan = nv50_disp_chan(oclass->parent); + return chan->func->child_new(chan, oclass, data, size, pobject); } -void -nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data) +static int +nv50_disp_chan_child_get(struct nvkm_object *object, int index, + struct nvkm_oclass *oclass) { - struct nv50_disp_chan *chan = (void *)object; - struct nvkm_device *device = object->engine->subdev.device; - nvkm_wr32(device, 0x640000 + (chan->chid * 0x1000) + addr, data); + struct nv50_disp_chan *chan = nv50_disp_chan(object); + if (chan->func->child_get) { + int ret = chan->func->child_get(chan, index, oclass); + if (ret == 0) + oclass->ctor = nv50_disp_chan_child_new; + return ret; + } + return -EINVAL; } -void -nv50_disp_chan_destroy(struct nv50_disp_chan *chan) +static int +nv50_disp_chan_fini(struct nvkm_object *object, bool suspend) { - struct nv50_disp_root *root = (void *)nv_object(chan)->parent; - root->chan &= ~(1 << chan->chid); - nvkm_namedb_destroy(&chan->base); + struct nv50_disp_chan *chan = nv50_disp_chan(object); + chan->func->fini(chan); + return 0; } -int -nv50_disp_chan_create_(struct nvkm_object *parent, - struct nvkm_object *engine, - struct nvkm_oclass *oclass, int head, - int length, void **pobject) +static int +nv50_disp_chan_init(struct nvkm_object *object) { - const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs; - struct nv50_disp_root *root = (void *)parent; - struct nv50_disp_chan *chan; - int chid = impl->chid + head; - int ret; + struct nv50_disp_chan *chan = nv50_disp_chan(object); + return chan->func->init(chan); +} - if (root->chan & (1 << chid)) - return -EBUSY; - root->chan |= (1 << chid); +static void * +nv50_disp_chan_dtor(struct nvkm_object *object) +{ + struct nv50_disp_chan *chan = nv50_disp_chan(object); + struct nv50_disp *disp = chan->root->disp; + if (chan->chid >= 0) + disp->chan[chan->chid] = NULL; + return chan->func->dtor ? chan->func->dtor(chan) : chan; +} - ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL, - (1ULL << NVDEV_ENGINE_DMAOBJ), - length, pobject); - chan = *pobject; - if (ret) - return ret; +static const struct nvkm_object_func +nv50_disp_chan = { + .dtor = nv50_disp_chan_dtor, + .init = nv50_disp_chan_init, + .fini = nv50_disp_chan_fini, + .rd32 = nv50_disp_chan_rd32, + .wr32 = nv50_disp_chan_wr32, + .ntfy = nv50_disp_chan_ntfy, + .map = nv50_disp_chan_map, + .sclass = nv50_disp_chan_child_get, +}; + +int +nv50_disp_chan_ctor(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nv50_disp_chan *chan) +{ + struct nv50_disp *disp = root->disp; + + nvkm_object_ctor(&nv50_disp_chan, oclass, &chan->object); + chan->func = func; + chan->mthd = mthd; + chan->root = root; chan->chid = chid; + chan->head = head; - nv_parent(chan)->object_attach = impl->attach; - nv_parent(chan)->object_detach = impl->detach; + if (disp->chan[chan->chid]) { + chan->chid = -1; + return -EBUSY; + } + disp->chan[chan->chid] = chan; return 0; } + +int +nv50_disp_chan_new_(const struct nv50_disp_chan_func *func, + const struct nv50_disp_chan_mthd *mthd, + struct nv50_disp_root *root, int chid, int head, + const struct nvkm_oclass *oclass, + struct nvkm_object **pobject) +{ + struct nv50_disp_chan *chan; + + if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL))) + return -ENOMEM; + *pobject = &chan->object; + + return nv50_disp_chan_ctor(func, mthd, root, chid, head, oclass, chan); +} |