nvif_object_fini(&chan->user);
}
-/******************************************************************************
- * PIO EVO channel
- *****************************************************************************/
-
-struct nv50_pioc {
- struct nv50_chan base;
-};
-
-static void
-nv50_pioc_destroy(struct nv50_pioc *pioc)
-{
- nv50_chan_destroy(&pioc->base);
-}
-
-static int
-nv50_pioc_create(struct nvif_device *device, struct nvif_object *disp,
- const s32 *oclass, u8 head, void *data, u32 size,
- struct nv50_pioc *pioc)
-{
- return nv50_chan_create(device, disp, oclass, head, data, size,
- &pioc->base);
-}
-
-/******************************************************************************
- * Overlay Immediate
- *****************************************************************************/
-
-struct nv50_oimm {
- struct nv50_pioc base;
-};
-
-static int
-nv50_oimm_create(struct nvif_device *device, struct nvif_object *disp,
- int head, struct nv50_oimm *oimm)
-{
- struct nv50_disp_cursor_v0 args = {
- .head = head,
- };
- static const s32 oclass[] = {
- GK104_DISP_OVERLAY,
- GF110_DISP_OVERLAY,
- GT214_DISP_OVERLAY,
- G82_DISP_OVERLAY,
- NV50_DISP_OVERLAY,
- 0
- };
-
- return nv50_pioc_create(device, disp, oclass, head, &args, sizeof(args),
- &oimm->base);
-}
-
/******************************************************************************
* DMA EVO channel
*****************************************************************************/
syncbuf, &base->base);
}
-/******************************************************************************
- * Overlay
- *****************************************************************************/
-
-struct nv50_ovly {
- struct nv50_dmac base;
-};
-
-static int
-nv50_ovly_create(struct nvif_device *device, struct nvif_object *disp,
- int head, u64 syncbuf, struct nv50_ovly *ovly)
-{
- struct nv50_disp_overlay_channel_dma_v0 args = {
- .head = head,
- };
- static const s32 oclass[] = {
- GK104_DISP_OVERLAY_CONTROL_DMA,
- GF110_DISP_OVERLAY_CONTROL_DMA,
- GT214_DISP_OVERLAY_CHANNEL_DMA,
- GT200_DISP_OVERLAY_CHANNEL_DMA,
- G82_DISP_OVERLAY_CHANNEL_DMA,
- NV50_DISP_OVERLAY_CHANNEL_DMA,
- 0
- };
-
- return nv50_dmac_create(device, disp, oclass, head, &args, sizeof(args),
- syncbuf, &ovly->base);
-}
-
struct nv50_head {
struct nouveau_crtc base;
struct {
struct nouveau_bo *nvbo[2];
int next;
} lut;
- struct nv50_ovly ovly;
- struct nv50_oimm oimm;
};
#define nv50_head(c) ((struct nv50_head *)nouveau_crtc(c))
struct nv50_wndw {
const struct nv50_wndw_func *func;
+ const struct nv50_wimm_func *immd;
struct nv50_dmac *dmac;
+ int id;
struct {
struct nvif_object *parent;
struct drm_plane plane;
+ struct nv50_dmac wndw;
+ struct nv50_dmac wimm;
+
struct nvif_notify notify;
u16 ntfy;
u16 sema;
u32 (*update)(struct nv50_wndw *, u32 interlock);
};
+struct nv50_wimm_func {
+};
+
static void
nv50_wndw_ctxdma_del(struct nv50_wndw_ctxdma *ctxdma)
{
{
struct nv50_wndw *wndw = nv50_wndw(plane);
struct nv50_wndw_ctxdma *ctxdma, *ctxtmp;
- void *data;
+ void *data = wndw;
list_for_each_entry_safe(ctxdma, ctxtmp, &wndw->ctxdma.list, head) {
nv50_wndw_ctxdma_del(ctxdma);
}
nvif_notify_fini(&wndw->notify);
- data = wndw->func->dtor(wndw);
+ if (wndw->func->dtor)
+ data = wndw->func->dtor(wndw);
+ nv50_dmac_destroy(&wndw->wimm);
+ nv50_dmac_destroy(&wndw->wndw);
drm_plane_cleanup(&wndw->plane);
kfree(data);
}
return 0;
}
+static int
+nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
+ enum drm_plane_type type, const char *name, int index,
+ const u32 *format, struct nv50_wndw **pwndw)
+{
+ struct nv50_wndw *wndw;
+ int nformat;
+ int ret;
+
+ if (!(wndw = *pwndw = kzalloc(sizeof(*wndw), GFP_KERNEL)))
+ return -ENOMEM;
+ wndw->id = index;
+
+ for (nformat = 0; format[nformat]; nformat++);
+
+ ret = nv50_wndw_ctor(func, dev, type, name, index,
+ &wndw->wndw, format, nformat, wndw);
+ if (ret) {
+ kfree(*pwndw);
+ *pwndw = NULL;
+ }
+
+ return ret;
+}
+
+/******************************************************************************
+ * Overlay
+ *****************************************************************************/
+
+static const struct nv50_wimm_func
+oimm507b = {
+};
+
+static int
+oimm507b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
+ s32 oclass, struct nv50_wndw *wndw)
+{
+ struct nv50_disp_overlay_v0 args = {
+ .head = wndw->id,
+ };
+ struct nv50_disp *disp = nv50_disp(drm->dev);
+ int ret;
+
+ ret = nvif_object_init(&disp->disp->object, 0, oclass, &args,
+ sizeof(args), &wndw->wimm.base.user);
+ if (ret) {
+ NV_ERROR(drm, "oimm%04x allocation failed: %d\n", oclass, ret);
+ return ret;
+ }
+
+ nvif_object_map(&wndw->wimm.base.user, NULL, 0);
+ wndw->immd = func;
+ return 0;
+}
+
+static int
+oimm507b_init(struct nouveau_drm *drm, s32 oclass, struct nv50_wndw *wndw)
+{
+ return oimm507b_init_(&oimm507b, drm, oclass, wndw);
+}
+
+static int
+nv50_oimm_init(struct nouveau_drm *drm, struct nv50_wndw *wndw)
+{
+ static const struct {
+ s32 oclass;
+ int version;
+ int (*init)(struct nouveau_drm *, s32, struct nv50_wndw *);
+ } oimms[] = {
+ { GK104_DISP_OVERLAY, 0, oimm507b_init },
+ { GF110_DISP_OVERLAY, 0, oimm507b_init },
+ { GT214_DISP_OVERLAY, 0, oimm507b_init },
+ { G82_DISP_OVERLAY, 0, oimm507b_init },
+ { NV50_DISP_OVERLAY, 0, oimm507b_init },
+ {}
+ };
+ struct nv50_disp *disp = nv50_disp(drm->dev);
+ int cid;
+
+ cid = nvif_mclass(&disp->disp->object, oimms);
+ if (cid < 0) {
+ NV_ERROR(drm, "No supported overlay immediate class\n");
+ return cid;
+ }
+
+ return oimms[cid].init(drm, oimms[cid].oclass, wndw);
+}
+
+static const struct nv50_wndw_func
+ovly507e = {
+};
+
+static const u32
+ovly507e_format[] = {
+ 0
+};
+
+static int
+ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
+ struct nouveau_drm *drm, int head, s32 oclass,
+ struct nv50_wndw **pwndw)
+{
+ struct nv50_disp_overlay_channel_dma_v0 args = {
+ .head = head,
+ };
+ struct nv50_disp *disp = nv50_disp(drm->dev);
+ struct nv50_wndw *wndw;
+ int ret;
+
+ ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_OVERLAY,
+ "ovly", head, format, &wndw);
+ if (*pwndw = wndw, ret)
+ return ret;
+
+ ret = nv50_dmac_create(&drm->client.device, &disp->disp->object,
+ &oclass, 0, &args, sizeof(args),
+ disp->sync->bo.offset, &wndw->wndw);
+ if (ret) {
+ NV_ERROR(drm, "ovly%04x allocation failed: %d\n", oclass, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+ovly507e_new(struct nouveau_drm *drm, int head, s32 oclass,
+ struct nv50_wndw **pwndw)
+{
+ return ovly507e_new_(&ovly507e, ovly507e_format, drm, head, oclass, pwndw);
+}
+
+static int
+nv50_ovly_new(struct nouveau_drm *drm, int head, struct nv50_wndw **pwndw)
+{
+ static const struct {
+ s32 oclass;
+ int version;
+ int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
+ } ovlys[] = {
+ { GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly507e_new },
+ { GF110_DISP_OVERLAY_CONTROL_DMA, 0, ovly507e_new },
+ { GT214_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
+ { GT200_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
+ { G82_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
+ { NV50_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
+ {}
+ };
+ struct nv50_disp *disp = nv50_disp(drm->dev);
+ int cid, ret;
+
+ cid = nvif_mclass(&disp->disp->object, ovlys);
+ if (cid < 0) {
+ NV_ERROR(drm, "No supported overlay class\n");
+ return cid;
+ }
+
+ ret = ovlys[cid].new(drm, head, ovlys[cid].oclass, pwndw);
+ if (ret)
+ return ret;
+
+ return nv50_oimm_init(drm, *pwndw);
+}
+
/******************************************************************************
* Cursor plane
*****************************************************************************/
struct nv50_head *head = nv50_head(crtc);
int i;
- nv50_dmac_destroy(&head->ovly.base);
- nv50_pioc_destroy(&head->oimm.base);
-
for (i = 0; i < ARRAY_SIZE(head->lut.nvbo); i++)
nouveau_bo_unmap_unpin_unref(&head->lut.nvbo[i]);
nv50_head_create(struct drm_device *dev, int index)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nvif_device *device = &drm->client.device;
- struct nv50_disp *disp = nv50_disp(dev);
struct nv50_head *head;
struct nv50_base *base;
struct nv50_curs *curs;
+ struct nv50_wndw *wndw;
struct drm_crtc *crtc;
int ret, i;
}
/* allocate overlay resources */
- ret = nv50_oimm_create(device, &disp->disp->object, index, &head->oimm);
- if (ret)
- goto out;
-
- ret = nv50_ovly_create(device, &disp->disp->object, index,
- disp->sync->bo.offset, &head->ovly);
- if (ret)
- goto out;
-
+ ret = nv50_ovly_new(drm, head->base.index, &wndw);
out:
if (ret)
nv50_head_destroy(crtc);