Blob Blame History Raw
From 17aa20345d6894409875516e8f134c3bf14d5527 Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Wed, 1 Jun 2022 20:46:29 +1000
Subject: drm/nouveau/disp: add common channel class handling
Git-commit: 889fcbe949bdd8470931a90b91f273ca18c510c1
Patch-mainline: v6.0-rc1
References: jsc#PED-1166 jsc#PED-1168 jsc#PED-1170 jsc#PED-1218 jsc#PED-1220 jsc#PED-1222 jsc#PED-1223 jsc#PED-1225 jsc#PED-2849

Replaces a bunch of unnecessarily duplicated boilerplate in per-chipset
code with a simpler, common, implementation.

Channel "awaken" notify code is completely gone for now.  KMS has never
made use of it so far, and event notify handling is about to be changed
in general anyway.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Reviewed-by: Lyude Paul <lyude@redhat.com>
Signed-off-by: Dave Airlie <airlied@redhat.com>
Acked-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 drivers/gpu/drm/nouveau/dispnv50/base507c.c   |  17 +-
 drivers/gpu/drm/nouveau/dispnv50/core507d.c   |   4 +-
 drivers/gpu/drm/nouveau/dispnv50/curs507a.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv50/disp.c       |   4 +-
 drivers/gpu/drm/nouveau/dispnv50/oimm507b.c   |   6 +-
 drivers/gpu/drm/nouveau/dispnv50/ovly507e.c   |  17 +-
 drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c   |   7 +-
 drivers/gpu/drm/nouveau/dispnv50/wndw.c       |   9 -
 drivers/gpu/drm/nouveau/dispnv50/wndw.h       |   3 -
 drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c   |   7 +-
 drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c   |   1 -
 drivers/gpu/drm/nouveau/include/nvif/cl507a.h |  12 -
 drivers/gpu/drm/nouveau/include/nvif/cl507b.h |  12 -
 drivers/gpu/drm/nouveau/include/nvif/cl507c.h |  13 -
 drivers/gpu/drm/nouveau/include/nvif/cl507d.h |  12 -
 drivers/gpu/drm/nouveau/include/nvif/cl507e.h |  13 -
 drivers/gpu/drm/nouveau/include/nvif/class.h  | 107 +++----
 drivers/gpu/drm/nouveau/include/nvif/clc37b.h |  11 -
 drivers/gpu/drm/nouveau/include/nvif/clc37e.h |  13 -
 drivers/gpu/drm/nouveau/include/nvif/if0014.h |  13 +
 .../drm/nouveau/include/nvkm/engine/disp.h    |   1 +
 .../gpu/drm/nouveau/nvkm/engine/disp/chan.c   |  82 +++++-
 .../gpu/drm/nouveau/nvkm/engine/disp/chan.h   | 127 +++------
 .../gpu/drm/nouveau/nvkm/engine/disp/g84.c    |  52 ++--
 .../gpu/drm/nouveau/nvkm/engine/disp/g94.c    |  24 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/ga102.c  |   8 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c  |  81 +++---
 .../gpu/drm/nouveau/nvkm/engine/disp/gk104.c  |  38 +--
 .../gpu/drm/nouveau/nvkm/engine/disp/gk110.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gm107.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gm200.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gp100.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gp102.c  |  80 +++---
 .../gpu/drm/nouveau/nvkm/engine/disp/gt200.c  |  24 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gt215.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/gv100.c  | 139 +++------
 .../gpu/drm/nouveau/nvkm/engine/disp/mcp77.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/mcp89.c  |  10 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c   | 269 +++---------------
 .../gpu/drm/nouveau/nvkm/engine/disp/priv.h   |   8 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/tu102.c  |   8 +-
 .../gpu/drm/nouveau/nvkm/engine/disp/udisp.c  |  13 +-
 42 files changed, 470 insertions(+), 841 deletions(-)
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/cl507a.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/cl507b.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/cl507c.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/cl507d.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/cl507e.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/clc37b.h
 delete mode 100644 drivers/gpu/drm/nouveau/include/nvif/clc37e.h
 create mode 100644 drivers/gpu/drm/nouveau/include/nvif/if0014.h

diff --git a/drivers/gpu/drm/nouveau/dispnv50/base507c.c b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
index 788db043a342..cad5a646983a 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/base507c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
@@ -21,8 +21,7 @@
  */
 #include "base.h"
 
-#include <nvif/cl507c.h>
-#include <nvif/event.h>
+#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 #include <nvif/timer.h>
 
@@ -306,8 +305,8 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
 	      struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
 	      struct nv50_wndw **pwndw)
 {
-	struct nv50_disp_base_channel_dma_v0 args = {
-		.head = head,
+	struct nvif_disp_chan_v0 args = {
+		.id = head,
 	};
 	struct nouveau_display *disp = nouveau_display(drm->dev);
 	struct nv50_disp *disp50 = nv50_disp(drm->dev);
@@ -328,16 +327,6 @@ base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
 		return ret;
 	}
 
-	ret = nvif_notify_ctor(&wndw->wndw.base.user, "kmsBaseNtfy",
-			       wndw->notify.func, false,
-			       NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT,
-			       &(struct nvif_notify_uevent_req) {},
-			       sizeof(struct nvif_notify_uevent_req),
-			       sizeof(struct nvif_notify_uevent_rep),
-			       &wndw->notify);
-	if (ret)
-		return ret;
-
 	wndw->ntfy = NV50_DISP_BASE_NTFY(wndw->id);
 	wndw->sema = NV50_DISP_BASE_SEM0(wndw->id);
 	wndw->data = 0x00000000;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/core507d.c b/drivers/gpu/drm/nouveau/dispnv50/core507d.c
index 1a1d806e0b01..e5bb5ca950c8 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c
@@ -22,7 +22,7 @@
 #include "core.h"
 #include "head.h"
 
-#include <nvif/cl507d.h>
+#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 #include <nvif/timer.h>
 
@@ -157,7 +157,7 @@ int
 core507d_new_(const struct nv50_core_func *func, struct nouveau_drm *drm,
 	      s32 oclass, struct nv50_core **pcore)
 {
-	struct nv50_disp_core_channel_dma_v0 args = {};
+	struct nvif_disp_chan_v0 args = {};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	struct nv50_core *core;
 	int ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
index 00e19fd959ea..cd2c79e4b7af 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
@@ -23,7 +23,7 @@
 #include "core.h"
 #include "head.h"
 
-#include <nvif/cl507a.h>
+#include <nvif/if0014.h>
 #include <nvif/timer.h>
 
 #include <nvhw/class/cl507a.h>
@@ -150,8 +150,8 @@ curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
 	      int head, s32 oclass, u32 interlock_data,
 	      struct nv50_wndw **pwndw)
 {
-	struct nv50_disp_cursor_v0 args = {
-		.head = head,
+	struct nvif_disp_chan_v0 args = {
+		.id = head,
 	};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	struct nv50_wndw *wndw;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/disp.c b/drivers/gpu/drm/nouveau/dispnv50/disp.c
index ade2988e85f3..f4d0bc362c89 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -48,8 +48,8 @@
 #include <nvif/class.h>
 #include <nvif/cl0002.h>
 #include <nvif/cl5070.h>
-#include <nvif/cl507d.h>
 #include <nvif/event.h>
+#include <nvif/if0014.h>
 #include <nvif/timer.h>
 
 #include <nvhw/class/cl507c.h>
@@ -231,7 +231,7 @@ nv50_dmac_create(struct nvif_device *device, struct nvif_object *disp,
 		 struct nv50_dmac *dmac)
 {
 	struct nouveau_cli *cli = (void *)device->object.client;
-	struct nv50_disp_core_channel_dma_v0 *args = data;
+	struct nvif_disp_chan_v0 *args = data;
 	u8 type = NVIF_MEM_COHERENT;
 	int ret;
 
diff --git a/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c b/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
index a6c3a9b95bdb..752318cf3cf1 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
@@ -21,14 +21,14 @@
  */
 #include "oimm.h"
 
-#include <nvif/cl507b.h>
+#include <nvif/if0014.h>
 
 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 nvif_disp_chan_v0 args = {
+		.id = wndw->id,
 	};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	int ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
index afd6c7271de1..d4af69e903ad 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
@@ -26,8 +26,7 @@
 #include <drm/drm_fourcc.h>
 #include <drm/drm_plane_helper.h>
 
-#include <nvif/cl507e.h>
-#include <nvif/event.h>
+#include <nvif/if0014.h>
 #include <nvif/push507c.h>
 
 #include <nvhw/class/cl507e.h>
@@ -147,8 +146,8 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
 	      struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
 	      struct nv50_wndw **pwndw)
 {
-	struct nv50_disp_overlay_channel_dma_v0 args = {
-		.head = head,
+	struct nvif_disp_chan_v0 args = {
+		.id = head,
 	};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	struct nv50_wndw *wndw;
@@ -169,16 +168,6 @@ ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
 		return ret;
 	}
 
-	ret = nvif_notify_ctor(&wndw->wndw.base.user, "kmsOvlyNtfy",
-			       wndw->notify.func, false,
-			       NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT,
-			       &(struct nvif_notify_uevent_req) {},
-			       sizeof(struct nvif_notify_uevent_req),
-			       sizeof(struct nvif_notify_uevent_rep),
-			       &wndw->notify);
-	if (ret)
-		return ret;
-
 	wndw->ntfy = NV50_DISP_OVLY_NTFY(wndw->id);
 	wndw->sema = NV50_DISP_OVLY_SEM0(wndw->id);
 	wndw->data = 0x00000000;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c b/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
index b390029c69ec..ee76b091d4ef 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wimmc37b.c
@@ -23,7 +23,7 @@
 #include "atom.h"
 #include "wndw.h"
 
-#include <nvif/clc37b.h>
+#include <nvif/if0014.h>
 #include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc37b.h>
@@ -68,9 +68,8 @@ static int
 wimmc37b_init_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
 	       s32 oclass, struct nv50_wndw *wndw)
 {
-	struct nvc37b_window_imm_channel_dma_v0 args = {
-		.pushbuf = 0xb0007b00 | wndw->id,
-		.index = wndw->id,
+	struct nvif_disp_chan_v0 args = {
+		.id = wndw->id,
 	};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	int ret;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.c b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
index b21f49f0eae5..7a2cceaee6e9 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -644,7 +644,6 @@ nv50_wndw_destroy(struct drm_plane *plane)
 		nv50_wndw_ctxdma_del(ctxdma);
 	}
 
-	nvif_notify_dtor(&wndw->notify);
 	nv50_dmac_destroy(&wndw->wimm);
 	nv50_dmac_destroy(&wndw->wndw);
 
@@ -688,12 +687,6 @@ nv50_wndw = {
 	.format_mod_supported = nv50_plane_format_mod_supported,
 };
 
-static int
-nv50_wndw_notify(struct nvif_notify *notify)
-{
-	return NVIF_NOTIFY_KEEP;
-}
-
 static const u64 nv50_cursor_format_modifiers[] = {
 	DRM_FORMAT_MOD_LINEAR,
 	DRM_FORMAT_MOD_INVALID,
@@ -747,8 +740,6 @@ nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
 			return ret;
 	}
 
-	wndw->notify.func = nv50_wndw_notify;
-
 	if (wndw->func->blend_set) {
 		ret = drm_plane_create_zpos_property(&wndw->plane,
 				nv50_wndw_zpos_default(&wndw->plane), 0, 254);
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndw.h b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
index 96542ce666fc..591c852f326b 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -5,8 +5,6 @@
 #include "atom.h"
 #include "lut.h"
 
-#include <nvif/notify.h>
-
 struct nv50_wndw_ctxdma {
 	struct list_head head;
 	struct nvif_object object;
@@ -30,7 +28,6 @@ struct nv50_wndw {
 	struct nv50_dmac wndw;
 	struct nv50_dmac wimm;
 
-	struct nvif_notify notify;
 	u16 ntfy;
 	u16 sema;
 	u32 data;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
index 183d2c0e65b6..082a66d59506 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc37e.c
@@ -26,7 +26,7 @@
 #include <drm/drm_plane_helper.h>
 #include <nouveau_bo.h>
 
-#include <nvif/clc37e.h>
+#include <nvif/if0014.h>
 #include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc37e.h>
@@ -351,9 +351,8 @@ wndwc37e_new_(const struct nv50_wndw_func *func, struct nouveau_drm *drm,
 	      enum drm_plane_type type, int index, s32 oclass, u32 heads,
 	      struct nv50_wndw **pwndw)
 {
-	struct nvc37e_window_channel_dma_v0 args = {
-		.pushbuf = 0xb0007e00 | index,
-		.index = index,
+	struct nvif_disp_chan_v0 args = {
+		.id = index,
 	};
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	struct nv50_wndw *wndw;
diff --git a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
index 37f6da8b3f2a..31167c398708 100644
--- a/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndwc57e.c
@@ -26,7 +26,6 @@
 #include <drm/drm_plane_helper.h>
 #include <nouveau_bo.h>
 
-#include <nvif/clc37e.h>
 #include <nvif/pushc37b.h>
 
 #include <nvhw/class/clc57e.h>
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507a.h b/drivers/gpu/drm/nouveau/include/nvif/cl507a.h
deleted file mode 100644
index 3b2a9809b8ce..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl507a.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL507A_H__
-#define __NVIF_CL507A_H__
-
-struct nv50_disp_cursor_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_CURSOR_V0_NTFY_UEVENT                                    0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507b.h b/drivers/gpu/drm/nouveau/include/nvif/cl507b.h
deleted file mode 100644
index 0f3d05581ea5..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl507b.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL507B_H__
-#define __NVIF_CL507B_H__
-
-struct nv50_disp_overlay_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-};
-
-#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT                                   0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507c.h b/drivers/gpu/drm/nouveau/include/nvif/cl507c.h
deleted file mode 100644
index 7da8813f4f5c..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl507c.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL507C_H__
-#define __NVIF_CL507C_H__
-
-struct nv50_disp_base_channel_dma_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-	__u64 pushbuf;
-};
-
-#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507d.h b/drivers/gpu/drm/nouveau/include/nvif/cl507d.h
deleted file mode 100644
index 4a56e42d8bc9..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl507d.h
+++ /dev/null
@@ -1,12 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL507D_H__
-#define __NVIF_CL507D_H__
-
-struct nv50_disp_core_channel_dma_v0 {
-	__u8  version;
-	__u8  pad01[7];
-	__u64 pushbuf;
-};
-
-#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT                          0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/cl507e.h b/drivers/gpu/drm/nouveau/include/nvif/cl507e.h
deleted file mode 100644
index 633936cb6313..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/cl507e.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CL507E_H__
-#define __NVIF_CL507E_H__
-
-struct nv50_disp_overlay_channel_dma_v0 {
-	__u8  version;
-	__u8  head;
-	__u8  pad02[6];
-	__u64 pushbuf;
-};
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT                       0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
index 2483a3787b00..1c185433b39e 100644
--- a/drivers/gpu/drm/nouveau/include/nvif/class.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -33,6 +33,7 @@
 #define NVIF_CLASS_VMM_GP100                         /* ifc00d.h */  0x8000c00d
 
 #define NVIF_CLASS_DISP                              /* if0010.h */  0x80000010
+#define NVIF_CLASS_DISP_CHAN                         /* if0014.h */  0x80000014
 
 /* the below match nvidia-assigned (either in hw, or sw) class numbers */
 #define NV_NULL_CLASS                                                0x00000030
@@ -98,59 +99,59 @@
 
 #define NV74_VP2                                                     0x00007476
 
-#define NV50_DISP_CURSOR                              /* cl507a.h */ 0x0000507a
-#define G82_DISP_CURSOR                               /* cl507a.h */ 0x0000827a
-#define GT214_DISP_CURSOR                             /* cl507a.h */ 0x0000857a
-#define GF110_DISP_CURSOR                             /* cl507a.h */ 0x0000907a
-#define GK104_DISP_CURSOR                             /* cl507a.h */ 0x0000917a
-#define GV100_DISP_CURSOR                             /* cl507a.h */ 0x0000c37a
-#define TU102_DISP_CURSOR                             /* cl507a.h */ 0x0000c57a
-#define GA102_DISP_CURSOR                             /* cl507a.h */ 0x0000c67a
-
-#define NV50_DISP_OVERLAY                             /* cl507b.h */ 0x0000507b
-#define G82_DISP_OVERLAY                              /* cl507b.h */ 0x0000827b
-#define GT214_DISP_OVERLAY                            /* cl507b.h */ 0x0000857b
-#define GF110_DISP_OVERLAY                            /* cl507b.h */ 0x0000907b
-#define GK104_DISP_OVERLAY                            /* cl507b.h */ 0x0000917b
-
-#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA             /* clc37b.h */ 0x0000c37b
-#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA             /* clc37b.h */ 0x0000c57b
-#define GA102_DISP_WINDOW_IMM_CHANNEL_DMA             /* clc37b.h */ 0x0000c67b
-
-#define NV50_DISP_BASE_CHANNEL_DMA                    /* cl507c.h */ 0x0000507c
-#define G82_DISP_BASE_CHANNEL_DMA                     /* cl507c.h */ 0x0000827c
-#define GT200_DISP_BASE_CHANNEL_DMA                   /* cl507c.h */ 0x0000837c
-#define GT214_DISP_BASE_CHANNEL_DMA                   /* cl507c.h */ 0x0000857c
-#define GF110_DISP_BASE_CHANNEL_DMA                   /* cl507c.h */ 0x0000907c
-#define GK104_DISP_BASE_CHANNEL_DMA                   /* cl507c.h */ 0x0000917c
-#define GK110_DISP_BASE_CHANNEL_DMA                   /* cl507c.h */ 0x0000927c
-
-#define NV50_DISP_CORE_CHANNEL_DMA                    /* cl507d.h */ 0x0000507d
-#define G82_DISP_CORE_CHANNEL_DMA                     /* cl507d.h */ 0x0000827d
-#define GT200_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000837d
-#define GT214_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000857d
-#define GT206_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000887d
-#define GF110_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000907d
-#define GK104_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000917d
-#define GK110_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000927d
-#define GM107_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000947d
-#define GM200_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000957d
-#define GP100_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000977d
-#define GP102_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000987d
-#define GV100_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000c37d
-#define TU102_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000c57d
-#define GA102_DISP_CORE_CHANNEL_DMA                   /* cl507d.h */ 0x0000c67d
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA                 /* cl507e.h */ 0x0000507e
-#define G82_DISP_OVERLAY_CHANNEL_DMA                  /* cl507e.h */ 0x0000827e
-#define GT200_DISP_OVERLAY_CHANNEL_DMA                /* cl507e.h */ 0x0000837e
-#define GT214_DISP_OVERLAY_CHANNEL_DMA                /* cl507e.h */ 0x0000857e
-#define GF110_DISP_OVERLAY_CONTROL_DMA                /* cl507e.h */ 0x0000907e
-#define GK104_DISP_OVERLAY_CONTROL_DMA                /* cl507e.h */ 0x0000917e
-
-#define GV100_DISP_WINDOW_CHANNEL_DMA                 /* clc37e.h */ 0x0000c37e
-#define TU102_DISP_WINDOW_CHANNEL_DMA                 /* clc37e.h */ 0x0000c57e
-#define GA102_DISP_WINDOW_CHANNEL_DMA                 /* clc37e.h */ 0x0000c67e
+#define NV50_DISP_CURSOR                              /* if0014.h */ 0x0000507a
+#define G82_DISP_CURSOR                               /* if0014.h */ 0x0000827a
+#define GT214_DISP_CURSOR                             /* if0014.h */ 0x0000857a
+#define GF110_DISP_CURSOR                             /* if0014.h */ 0x0000907a
+#define GK104_DISP_CURSOR                             /* if0014.h */ 0x0000917a
+#define GV100_DISP_CURSOR                             /* if0014.h */ 0x0000c37a
+#define TU102_DISP_CURSOR                             /* if0014.h */ 0x0000c57a
+#define GA102_DISP_CURSOR                             /* if0014.h */ 0x0000c67a
+
+#define NV50_DISP_OVERLAY                             /* if0014.h */ 0x0000507b
+#define G82_DISP_OVERLAY                              /* if0014.h */ 0x0000827b
+#define GT214_DISP_OVERLAY                            /* if0014.h */ 0x0000857b
+#define GF110_DISP_OVERLAY                            /* if0014.h */ 0x0000907b
+#define GK104_DISP_OVERLAY                            /* if0014.h */ 0x0000917b
+
+#define GV100_DISP_WINDOW_IMM_CHANNEL_DMA             /* if0014.h */ 0x0000c37b
+#define TU102_DISP_WINDOW_IMM_CHANNEL_DMA             /* if0014.h */ 0x0000c57b
+#define GA102_DISP_WINDOW_IMM_CHANNEL_DMA             /* if0014.h */ 0x0000c67b
+
+#define NV50_DISP_BASE_CHANNEL_DMA                    /* if0014.h */ 0x0000507c
+#define G82_DISP_BASE_CHANNEL_DMA                     /* if0014.h */ 0x0000827c
+#define GT200_DISP_BASE_CHANNEL_DMA                   /* if0014.h */ 0x0000837c
+#define GT214_DISP_BASE_CHANNEL_DMA                   /* if0014.h */ 0x0000857c
+#define GF110_DISP_BASE_CHANNEL_DMA                   /* if0014.h */ 0x0000907c
+#define GK104_DISP_BASE_CHANNEL_DMA                   /* if0014.h */ 0x0000917c
+#define GK110_DISP_BASE_CHANNEL_DMA                   /* if0014.h */ 0x0000927c
+
+#define NV50_DISP_CORE_CHANNEL_DMA                    /* if0014.h */ 0x0000507d
+#define G82_DISP_CORE_CHANNEL_DMA                     /* if0014.h */ 0x0000827d
+#define GT200_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000837d
+#define GT214_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000857d
+#define GT206_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000887d
+#define GF110_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000907d
+#define GK104_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000917d
+#define GK110_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000927d
+#define GM107_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000947d
+#define GM200_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000957d
+#define GP100_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000977d
+#define GP102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000987d
+#define GV100_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c37d
+#define TU102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c57d
+#define GA102_DISP_CORE_CHANNEL_DMA                   /* if0014.h */ 0x0000c67d
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA                 /* if0014.h */ 0x0000507e
+#define G82_DISP_OVERLAY_CHANNEL_DMA                  /* if0014.h */ 0x0000827e
+#define GT200_DISP_OVERLAY_CHANNEL_DMA                /* if0014.h */ 0x0000837e
+#define GT214_DISP_OVERLAY_CHANNEL_DMA                /* if0014.h */ 0x0000857e
+#define GF110_DISP_OVERLAY_CONTROL_DMA                /* if0014.h */ 0x0000907e
+#define GK104_DISP_OVERLAY_CONTROL_DMA                /* if0014.h */ 0x0000917e
+
+#define GV100_DISP_WINDOW_CHANNEL_DMA                 /* if0014.h */ 0x0000c37e
+#define TU102_DISP_WINDOW_CHANNEL_DMA                 /* if0014.h */ 0x0000c57e
+#define GA102_DISP_WINDOW_CHANNEL_DMA                 /* if0014.h */ 0x0000c67e
 
 #define NV50_TESLA                                                   0x00005097
 #define G82_TESLA                                                    0x00008297
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clc37b.h b/drivers/gpu/drm/nouveau/include/nvif/clc37b.h
deleted file mode 100644
index 970a5ac4cb95..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/clc37b.h
+++ /dev/null
@@ -1,11 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CLC37B_H__
-#define __NVIF_CLC37B_H__
-
-struct nvc37b_window_imm_channel_dma_v0 {
-	__u8  version;
-	__u8  index;
-	__u8  pad02[6];
-	__u64 pushbuf;
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/clc37e.h b/drivers/gpu/drm/nouveau/include/nvif/clc37e.h
deleted file mode 100644
index 7ea23695e7e1..000000000000
--- a/drivers/gpu/drm/nouveau/include/nvif/clc37e.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: MIT */
-#ifndef __NVIF_CLC37E_H__
-#define __NVIF_CLC37E_H__
-
-struct nvc37e_window_channel_dma_v0 {
-	__u8  version;
-	__u8  index;
-	__u8  pad02[6];
-	__u64 pushbuf;
-};
-
-#define NVC37E_WINDOW_CHANNEL_DMA_V0_NTFY_UEVENT                           0x00
-#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/if0014.h b/drivers/gpu/drm/nouveau/include/nvif/if0014.h
new file mode 100644
index 000000000000..be0362805106
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/if0014.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: MIT */
+#ifndef __NVIF_IF0014_H__
+#define __NVIF_IF0014_H__
+
+union nvif_disp_chan_args {
+	struct nvif_disp_chan_v0 {
+		__u8  version;
+		__u8  id;
+		__u8  pad02[6];
+		__u64 pushbuf;
+	} v0;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
index 593a2395ce9c..64bda44a13e5 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -24,6 +24,7 @@ struct nvkm_disp {
 		u32 pending;
 	} super;
 
+#define NVKM_DISP_EVENT_CHAN_AWAKEN BIT(0)
 	struct nvkm_event uevent;
 
 	struct {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
index fac9fc41847c..d5e18daed79f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.c
@@ -24,7 +24,7 @@
 #include <core/oproxy.h>
 #include <core/ramht.h>
 
-#include <nvif/cl507d.h>
+#include <nvif/if0014.h>
 
 static int
 nvkm_disp_chan_rd32(struct nvkm_object *object, u64 addr, u32 *data)
@@ -55,7 +55,7 @@ nvkm_disp_chan_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **pe
 	struct nvkm_disp *disp = chan->disp;
 
 	switch (type) {
-	case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
+	case 0:
 		*pevent = &disp->uevent;
 		return 0;
 	default:
@@ -174,8 +174,10 @@ nvkm_disp_chan_dtor(struct nvkm_object *object)
 	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
 	struct nvkm_disp *disp = chan->disp;
 
-	if (chan->chid.user >= 0)
+	spin_lock(&disp->client.lock);
+	if (disp->chan[chan->chid.user] == chan)
 		disp->chan[chan->chid.user] = NULL;
+	spin_unlock(&disp->client.lock);
 
 	nvkm_memory_unref(&chan->memory);
 	return chan;
@@ -193,31 +195,81 @@ nvkm_disp_chan = {
 	.sclass = nvkm_disp_chan_child_get,
 };
 
-int
-nvkm_disp_chan_new_(const struct nvkm_disp_chan_func *func,
-		    const struct nvkm_disp_chan_mthd *mthd,
-		    struct nvkm_disp *disp, int ctrl, int user, int head,
-		    const struct nvkm_oclass *oclass,
-		    struct nvkm_object **pobject)
+static int
+nvkm_disp_chan_new_(struct nvkm_disp *disp, int nr, const struct nvkm_oclass *oclass,
+		    void *argv, u32 argc, struct nvkm_object **pobject)
 {
+	const struct nvkm_disp_chan_user *user = NULL;
 	struct nvkm_disp_chan *chan;
+	union nvif_disp_chan_args *args = argv;
+	int ret, i;
+
+	for (i = 0; disp->func->user[i].ctor; i++) {
+		if (disp->func->user[i].base.oclass == oclass->base.oclass) {
+			user = disp->func->user[i].chan;
+			break;
+		}
+	}
+
+	if (WARN_ON(!user))
+		return -EINVAL;
+
+	if (argc != sizeof(args->v0) || args->v0.version != 0)
+		return -ENOSYS;
+	if (args->v0.id >= nr || !args->v0.pushbuf != !user->func->push)
+		return -EINVAL;
 
 	if (!(chan = kzalloc(sizeof(*chan), GFP_KERNEL)))
 		return -ENOMEM;
 	*pobject = &chan->object;
 
 	nvkm_object_ctor(&nvkm_disp_chan, oclass, &chan->object);
-	chan->func = func;
-	chan->mthd = mthd;
+	chan->func = user->func;
+	chan->mthd = user->mthd;
 	chan->disp = disp;
-	chan->chid.ctrl = ctrl;
-	chan->chid.user = user;
-	chan->head = head;
+	chan->chid.ctrl = user->ctrl + args->v0.id;
+	chan->chid.user = user->user + args->v0.id;
+	chan->head = args->v0.id;
+
+	if (chan->func->push) {
+		ret = chan->func->push(chan, args->v0.pushbuf);
+		if (ret)
+			return ret;
+	}
 
+	spin_lock(&disp->client.lock);
 	if (disp->chan[chan->chid.user]) {
-		chan->chid.user = -1;
+		spin_unlock(&disp->client.lock);
 		return -EBUSY;
 	}
 	disp->chan[chan->chid.user] = chan;
+	spin_unlock(&disp->client.lock);
 	return 0;
 }
+
+int
+nvkm_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+		   struct nvkm_object **pobject)
+{
+	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+	return nvkm_disp_chan_new_(disp, disp->wndw.nr, oclass, argv, argc, pobject);
+}
+
+int
+nvkm_disp_chan_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+		   struct nvkm_object **pobject)
+{
+	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+	return nvkm_disp_chan_new_(disp, disp->head.nr, oclass, argv, argc, pobject);
+}
+
+int
+nvkm_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
+		   struct nvkm_object **pobject)
+{
+	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
+
+	return nvkm_disp_chan_new_(disp, 1, oclass, argv, argc, pobject);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
index b7394b6a0fb8..398336ffb685 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/chan.h
@@ -24,7 +24,12 @@ struct nvkm_disp_chan {
 	u32 suspend_put;
 };
 
+int nvkm_disp_core_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
+int nvkm_disp_chan_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
+int nvkm_disp_wndw_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
+
 struct nvkm_disp_chan_func {
+	int (*push)(struct nvkm_disp_chan *, u64 object);
 	int (*init)(struct nvkm_disp_chan *);
 	void (*fini)(struct nvkm_disp_chan *);
 	void (*intr)(struct nvkm_disp_chan *, bool en);
@@ -32,19 +37,11 @@ struct nvkm_disp_chan_func {
 	int (*bind)(struct nvkm_disp_chan *, struct nvkm_object *, u32 handle);
 };
 
-int nvkm_disp_chan_new_(const struct nvkm_disp_chan_func *,
-			const struct nvkm_disp_chan_mthd *,
-			struct nvkm_disp *, int ctrl, int user, int head,
-			const struct nvkm_oclass *, struct nvkm_object **);
-int nv50_disp_dmac_new_(const struct nvkm_disp_chan_func *,
-			const struct nvkm_disp_chan_mthd *,
-			struct nvkm_disp *, int chid, int head, u64 push,
-			const struct nvkm_oclass *, struct nvkm_object **);
-
 void nv50_disp_chan_intr(struct nvkm_disp_chan *, bool);
 u64 nv50_disp_chan_user(struct nvkm_disp_chan *, u64 *);
 extern const struct nvkm_disp_chan_func nv50_disp_pioc_func;
 extern const struct nvkm_disp_chan_func nv50_disp_dmac_func;
+int nv50_disp_dmac_push(struct nvkm_disp_chan *, u64);
 int nv50_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
 extern const struct nvkm_disp_chan_func nv50_disp_core_func;
 
@@ -63,89 +60,35 @@ int gv100_disp_dmac_init(struct nvkm_disp_chan *);
 void gv100_disp_dmac_fini(struct nvkm_disp_chan *);
 int gv100_disp_dmac_bind(struct nvkm_disp_chan *, struct nvkm_object *, u32);
 
-int nv50_disp_curs_new_(const struct nvkm_disp_chan_func *,
-			struct nvkm_disp *, int ctrl, int user,
-			const struct nvkm_oclass *, void *argv, u32 argc,
-			struct nvkm_object **);
-int nv50_disp_oimm_new_(const struct nvkm_disp_chan_func *,
-			struct nvkm_disp *, int ctrl, int user,
-			const struct nvkm_oclass *, void *argv, u32 argc,
-			struct nvkm_object **);
-int nv50_disp_base_new_(const struct nvkm_disp_chan_func *,
-			const struct nvkm_disp_chan_mthd *,
-			struct nvkm_disp *, int chid,
-			const struct nvkm_oclass *, void *argv, u32 argc,
-			struct nvkm_object **);
-int nv50_disp_core_new_(const struct nvkm_disp_chan_func *,
-			const struct nvkm_disp_chan_mthd *,
-			struct nvkm_disp *, int chid,
-			const struct nvkm_oclass *oclass, void *argv, u32 argc,
-			struct nvkm_object **);
-int nv50_disp_ovly_new_(const struct nvkm_disp_chan_func *,
-			const struct nvkm_disp_chan_mthd *,
-			struct nvkm_disp *, int chid,
-			const struct nvkm_oclass *, void *argv, u32 argc,
-			struct nvkm_object **);
-
-int nv50_disp_curs_new(const struct nvkm_oclass *, void *, u32,
-		       struct nvkm_disp *, struct nvkm_object **);
-int nv50_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
-		       struct nvkm_disp *, struct nvkm_object **);
-int nv50_disp_base_new(const struct nvkm_oclass *, void *, u32,
-		       struct nvkm_disp *, struct nvkm_object **);
-int nv50_disp_core_new(const struct nvkm_oclass *, void *, u32,
-		       struct nvkm_disp *, struct nvkm_object **);
-int nv50_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-		       struct nvkm_disp *, struct nvkm_object **);
-
-int g84_disp_base_new(const struct nvkm_oclass *, void *, u32,
-		      struct nvkm_disp *, struct nvkm_object **);
-int g84_disp_core_new(const struct nvkm_oclass *, void *, u32,
-		      struct nvkm_disp *, struct nvkm_object **);
-int g84_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-		      struct nvkm_disp *, struct nvkm_object **);
-
-int g94_disp_core_new(const struct nvkm_oclass *, void *, u32,
-		      struct nvkm_disp *, struct nvkm_object **);
-
-int gt200_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-
-int gf119_disp_curs_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gf119_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gf119_disp_base_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gf119_disp_core_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gf119_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-
-int gk104_disp_core_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gk104_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-
-int gp102_disp_curs_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gp102_disp_oimm_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gp102_disp_base_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gp102_disp_core_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gp102_disp_ovly_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-
-int gv100_disp_curs_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gv100_disp_wimm_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gv100_disp_core_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
-int gv100_disp_wndw_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
+struct nvkm_disp_chan_user {
+	const struct nvkm_disp_chan_func *func;
+	int ctrl;
+	int user;
+	const struct nvkm_disp_chan_mthd *mthd;
+};
+
+extern const struct nvkm_disp_chan_user nv50_disp_oimm;
+extern const struct nvkm_disp_chan_user nv50_disp_curs;
+
+extern const struct nvkm_disp_chan_user g84_disp_core;
+extern const struct nvkm_disp_chan_user g84_disp_base;
+extern const struct nvkm_disp_chan_user g84_disp_ovly;
+
+extern const struct nvkm_disp_chan_user g94_disp_core;
+
+extern const struct nvkm_disp_chan_user gt200_disp_ovly;
+
+extern const struct nvkm_disp_chan_user gf119_disp_base;
+extern const struct nvkm_disp_chan_user gf119_disp_oimm;
+extern const struct nvkm_disp_chan_user gf119_disp_curs;
+
+extern const struct nvkm_disp_chan_user gk104_disp_core;
+extern const struct nvkm_disp_chan_user gk104_disp_ovly;
+
+extern const struct nvkm_disp_chan_user gv100_disp_core;
+extern const struct nvkm_disp_chan_user gv100_disp_curs;
+extern const struct nvkm_disp_chan_user gv100_disp_wndw;
+extern const struct nvkm_disp_chan_user gv100_disp_wimm;
 
 struct nvkm_disp_mthd_list {
 	u32 mthd;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
index 43dc73abad61..4966a51af3d7 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -151,13 +151,13 @@ g84_disp_ovly_mthd = {
 	}
 };
 
-int
-g84_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		  struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&nv50_disp_dmac_func, &g84_disp_ovly_mthd,
-				   disp, 3, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+g84_disp_ovly = {
+	.func = &nv50_disp_dmac_func,
+	.ctrl = 3,
+	.user = 3,
+	.mthd = &g84_disp_ovly_mthd,
+};
 
 static const struct nvkm_disp_mthd_list
 g84_disp_base_mthd_base = {
@@ -201,13 +201,13 @@ g84_disp_base_mthd = {
 	}
 };
 
-int
-g84_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		  struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_base_new_(&nv50_disp_dmac_func, &g84_disp_base_mthd,
-				   disp, 1, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+g84_disp_base = {
+	.func = &nv50_disp_dmac_func,
+	.ctrl = 1,
+	.user = 1,
+	.mthd = &g84_disp_base_mthd,
+};
 
 const struct nvkm_disp_mthd_list
 g84_disp_core_mthd_dac = {
@@ -288,13 +288,13 @@ g84_disp_core_mthd = {
 	}
 };
 
-int
-g84_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		  struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&nv50_disp_core_func, &g84_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+g84_disp_core = {
+	.func = &nv50_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &g84_disp_core_mthd,
+};
 
 static const struct nvkm_disp_func
 g84_disp = {
@@ -310,11 +310,11 @@ g84_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,G82_DISP },
 	.user = {
-		{{0,0,G82_DISP_CURSOR             }, nv50_disp_curs_new },
-		{{0,0,G82_DISP_OVERLAY            }, nv50_disp_oimm_new },
-		{{0,0,G82_DISP_BASE_CHANNEL_DMA   },  g84_disp_base_new },
-		{{0,0,G82_DISP_CORE_CHANNEL_DMA   },  g84_disp_core_new },
-		{{0,0,G82_DISP_OVERLAY_CHANNEL_DMA},  g84_disp_ovly_new },
+		{{0,0,G82_DISP_CURSOR             }, nvkm_disp_chan_new, &nv50_disp_curs },
+		{{0,0,G82_DISP_OVERLAY            }, nvkm_disp_chan_new, &nv50_disp_oimm },
+		{{0,0,G82_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, & g84_disp_base },
+		{{0,0,G82_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, & g84_disp_core },
+		{{0,0,G82_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, & g84_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
index d808f6e8887c..a4853c4e5ee3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -338,13 +338,13 @@ g94_disp_core_mthd = {
 	}
 };
 
-int
-g94_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		  struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&nv50_disp_core_func, &g94_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+g94_disp_core = {
+	.func = &nv50_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &g94_disp_core_mthd,
+};
 
 static const struct nvkm_disp_func
 g94_disp = {
@@ -360,11 +360,11 @@ g94_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,GT206_DISP },
 	.user = {
-		{{0,0,  G82_DISP_CURSOR             },  nv50_disp_curs_new },
-		{{0,0,  G82_DISP_OVERLAY            },  nv50_disp_oimm_new },
-		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   },   g84_disp_base_new },
-		{{0,0,GT206_DISP_CORE_CHANNEL_DMA   },   g94_disp_core_new },
-		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, gt200_disp_ovly_new },
+		{{0,0,  G82_DISP_CURSOR             }, nvkm_disp_chan_new, & nv50_disp_curs },
+		{{0,0,  G82_DISP_OVERLAY            }, nvkm_disp_chan_new, & nv50_disp_oimm },
+		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &  g84_disp_base },
+		{{0,0,GT206_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &  g94_disp_core },
+		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &gt200_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
index a9e2403da66c..7489d0d7fce0 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ga102.c
@@ -137,10 +137,10 @@ ga102_disp = {
 	.root = {  0, 0,GA102_DISP },
 	.user = {
 		{{-1,-1,GV100_DISP_CAPS                  }, gv100_disp_caps_new },
-		{{ 0, 0,GA102_DISP_CURSOR                }, gv100_disp_curs_new },
-		{{ 0, 0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
-		{{ 0, 0,GA102_DISP_CORE_CHANNEL_DMA      }, gv100_disp_core_new },
-		{{ 0, 0,GA102_DISP_WINDOW_CHANNEL_DMA    }, gv100_disp_wndw_new },
+		{{ 0, 0,GA102_DISP_CURSOR                }, nvkm_disp_chan_new, &gv100_disp_curs },
+		{{ 0, 0,GA102_DISP_WINDOW_IMM_CHANNEL_DMA}, nvkm_disp_wndw_new, &gv100_disp_wimm },
+		{{ 0, 0,GA102_DISP_CORE_CHANNEL_DMA      }, nvkm_disp_core_new, &gv100_disp_core },
+		{{ 0, 0,GA102_DISP_WINDOW_CHANNEL_DMA    }, nvkm_disp_wndw_new, &gv100_disp_wndw },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 7e099e4f3c22..3af527d2328c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -474,7 +474,6 @@ gf119_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
 
 const struct nvkm_event_func
 gf119_disp_chan_uevent = {
-	.ctor = nv50_disp_chan_uevent_ctor,
 	.init = gf119_disp_chan_uevent_init,
 	.fini = gf119_disp_chan_uevent_fini,
 };
@@ -603,6 +602,7 @@ gf119_disp_dmac_init(struct nvkm_disp_chan *chan)
 
 const struct nvkm_disp_chan_func
 gf119_disp_dmac_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gf119_disp_dmac_init,
 	.fini = gf119_disp_dmac_fini,
 	.intr = gf119_disp_chan_intr,
@@ -610,21 +610,19 @@ gf119_disp_dmac_func = {
 	.bind = gf119_disp_dmac_bind,
 };
 
-int
-gf119_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 13,
-				   oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gf119_disp_curs = {
+	.func = &gf119_disp_pioc_func,
+	.ctrl = 13,
+	.user = 13,
+};
 
-int
-gf119_disp_oimm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_oimm_new_(&gf119_disp_pioc_func, disp, 9, 9,
-				   oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gf119_disp_oimm = {
+	.func = &gf119_disp_pioc_func,
+	.ctrl = 9,
+	.user = 9,
+};
 
 static const struct nvkm_disp_mthd_list
 gf119_disp_ovly_mthd_base = {
@@ -689,13 +687,13 @@ gf119_disp_ovly_mthd = {
 	}
 };
 
-int
-gf119_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&gf119_disp_dmac_func, &gf119_disp_ovly_mthd,
-				   disp, 5, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gf119_disp_ovly = {
+	.func = &gf119_disp_dmac_func,
+	.ctrl = 5,
+	.user = 5,
+	.mthd = &gf119_disp_ovly_mthd,
+};
 
 static const struct nvkm_disp_mthd_list
 gf119_disp_base_mthd_base = {
@@ -773,13 +771,13 @@ gf119_disp_base_mthd = {
 	}
 };
 
-int
-gf119_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_base_new_(&gf119_disp_dmac_func, &gf119_disp_base_mthd,
-				   disp, 1, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gf119_disp_base = {
+	.func = &gf119_disp_dmac_func,
+	.ctrl = 1,
+	.user = 1,
+	.mthd = &gf119_disp_base_mthd,
+};
 
 const struct nvkm_disp_mthd_list
 gf119_disp_core_mthd_base = {
@@ -971,6 +969,7 @@ gf119_disp_core_init(struct nvkm_disp_chan *chan)
 
 const struct nvkm_disp_chan_func
 gf119_disp_core_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gf119_disp_core_init,
 	.fini = gf119_disp_core_fini,
 	.intr = gf119_disp_chan_intr,
@@ -978,13 +977,13 @@ gf119_disp_core_func = {
 	.bind = gf119_disp_dmac_bind,
 };
 
-int
-gf119_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&gf119_disp_core_func, &gf119_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gf119_disp_core = {
+	.func = &gf119_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &gf119_disp_core_mthd,
+};
 
 void
 gf119_disp_super(struct work_struct *work)
@@ -1220,11 +1219,11 @@ gf119_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gf119_sor_new },
 	.root = { 0,0,GF110_DISP },
 	.user = {
-		{{0,0,GF110_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GF110_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GF110_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GF110_DISP_CORE_CHANNEL_DMA   }, gf119_disp_core_new },
-		{{0,0,GF110_DISP_OVERLAY_CONTROL_DMA}, gf119_disp_ovly_new },
+		{{0,0,GF110_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GF110_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GF110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GF110_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gf119_disp_core },
+		{{0,0,GF110_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gf119_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
index f8b58ee3a764..7248e9ec835e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -170,13 +170,13 @@ gk104_disp_ovly_mthd = {
 	}
 };
 
-int
-gk104_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&gf119_disp_dmac_func, &gk104_disp_ovly_mthd,
-				   disp, 5, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gk104_disp_ovly = {
+	.func = &gf119_disp_dmac_func,
+	.ctrl = 5,
+	.user = 5,
+	.mthd = &gk104_disp_ovly_mthd,
+};
 
 static const struct nvkm_disp_mthd_list
 gk104_disp_core_mthd_head = {
@@ -272,13 +272,13 @@ gk104_disp_core_mthd = {
 	}
 };
 
-int
-gk104_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&gf119_disp_core_func, &gk104_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gk104_disp_core = {
+	.func = &gf119_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &gk104_disp_core_mthd,
+};
 
 static const struct nvkm_disp_func
 gk104_disp = {
@@ -294,11 +294,11 @@ gk104_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gk104_sor_new },
 	.root = { 0,0,GK104_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GK104_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GK104_DISP_CORE_CHANNEL_DMA   }, gk104_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gk104_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GK104_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GK104_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gk104_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
index 018a92d6a694..1704aa381ee9 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
@@ -42,11 +42,11 @@ gk110_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gk104_sor_new },
 	.root = { 0,0,GK110_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GK110_DISP_CORE_CHANNEL_DMA   }, gk104_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gk104_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GK110_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gk104_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
index e96df705e79b..9e9ef49bd8ac 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -97,11 +97,11 @@ gm107_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gm107_sor_new },
 	.root = { 0,0,GM107_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GM107_DISP_CORE_CHANNEL_DMA   }, gk104_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gk104_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GM107_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gk104_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
index 5a08c79dbb85..4ecc8f98af6e 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm200.c
@@ -165,11 +165,11 @@ gm200_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gm200_sor_new },
 	.root = { 0,0,GM200_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GM200_DISP_CORE_CHANNEL_DMA   }, gk104_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gk104_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GM200_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gk104_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
index a7cda46cfdb6..7172a9dfd89b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp100.c
@@ -70,11 +70,11 @@ gp100_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gp100_sor_new },
 	.root = { 0,0,GP100_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gf119_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gf119_disp_oimm_new },
-		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, gf119_disp_base_new },
-		{{0,0,GP100_DISP_CORE_CHANNEL_DMA   }, gk104_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gk104_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gf119_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gf119_disp_oimm },
+		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gf119_disp_base },
+		{{0,0,GP100_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gk104_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gk104_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
index 5cafd7ce5382..07e9aeec5e08 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gp102.c
@@ -61,6 +61,7 @@ gp102_disp_dmac_init(struct nvkm_disp_chan *chan)
 
 const struct nvkm_disp_chan_func
 gp102_disp_dmac_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gp102_disp_dmac_init,
 	.fini = gf119_disp_dmac_fini,
 	.intr = gf119_disp_chan_intr,
@@ -68,37 +69,35 @@ gp102_disp_dmac_func = {
 	.bind = gf119_disp_dmac_bind,
 };
 
-int
-gp102_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_curs_new_(&gf119_disp_pioc_func, disp, 13, 17,
-				   oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gp102_disp_curs = {
+	.func = &gf119_disp_pioc_func,
+	.ctrl = 13,
+	.user = 17,
+};
 
-int
-gp102_disp_oimm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_oimm_new_(&gf119_disp_pioc_func, disp, 9, 13,
-				   oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gp102_disp_oimm = {
+	.func = &gf119_disp_pioc_func,
+	.ctrl = 9,
+	.user = 13,
+};
 
-int
-gp102_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&gp102_disp_dmac_func, &gk104_disp_ovly_mthd,
-				   disp, 5, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gp102_disp_ovly = {
+	.func = &gp102_disp_dmac_func,
+	.ctrl = 5,
+	.user = 5,
+	.mthd = &gk104_disp_ovly_mthd,
+};
 
-int
-gp102_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_base_new_(&gp102_disp_dmac_func, &gf119_disp_base_mthd,
-				   disp, 1, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gp102_disp_base = {
+	.func = &gp102_disp_dmac_func,
+	.ctrl = 1,
+	.user = 1,
+	.mthd = &gf119_disp_base_mthd,
+};
 
 static int
 gp102_disp_core_init(struct nvkm_disp_chan *chan)
@@ -129,6 +128,7 @@ gp102_disp_core_init(struct nvkm_disp_chan *chan)
 
 static const struct nvkm_disp_chan_func
 gp102_disp_core_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gp102_disp_core_init,
 	.fini = gf119_disp_core_fini,
 	.intr = gf119_disp_chan_intr,
@@ -136,13 +136,13 @@ gp102_disp_core_func = {
 	.bind = gf119_disp_dmac_bind,
 };
 
-int
-gp102_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&gp102_disp_core_func, &gk104_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+gp102_disp_core = {
+	.func = &gp102_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &gk104_disp_core_mthd,
+};
 
 static void
 gp102_disp_intr_error(struct nvkm_disp *disp, int chid)
@@ -183,11 +183,11 @@ gp102_disp = {
 	.sor = { .cnt = gf119_sor_cnt, .new = gp100_sor_new },
 	.root = { 0,0,GP102_DISP },
 	.user = {
-		{{0,0,GK104_DISP_CURSOR             }, gp102_disp_curs_new },
-		{{0,0,GK104_DISP_OVERLAY            }, gp102_disp_oimm_new },
-		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, gp102_disp_base_new },
-		{{0,0,GP102_DISP_CORE_CHANNEL_DMA   }, gp102_disp_core_new },
-		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, gp102_disp_ovly_new },
+		{{0,0,GK104_DISP_CURSOR             }, nvkm_disp_chan_new, &gp102_disp_curs },
+		{{0,0,GK104_DISP_OVERLAY            }, nvkm_disp_chan_new, &gp102_disp_oimm },
+		{{0,0,GK110_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &gp102_disp_base },
+		{{0,0,GP102_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &gp102_disp_core },
+		{{0,0,GK104_DISP_OVERLAY_CONTROL_DMA}, nvkm_disp_chan_new, &gp102_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
index 31b5fd32e03a..6f69c4e3ade2 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
@@ -70,13 +70,13 @@ gt200_disp_ovly_mthd = {
 	}
 };
 
-int
-gt200_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&nv50_disp_dmac_func, &gt200_disp_ovly_mthd,
-				   disp, 3, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gt200_disp_ovly = {
+	.func = &nv50_disp_dmac_func,
+	.ctrl = 3,
+	.user = 3,
+	.mthd = &gt200_disp_ovly_mthd,
+};
 
 static const struct nvkm_disp_func
 gt200_disp = {
@@ -92,11 +92,11 @@ gt200_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,GT200_DISP },
 	.user = {
-		{{0,0,  G82_DISP_CURSOR             },  nv50_disp_curs_new },
-		{{0,0,  G82_DISP_OVERLAY            },  nv50_disp_oimm_new },
-		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   },   g84_disp_base_new },
-		{{0,0,GT200_DISP_CORE_CHANNEL_DMA   },   g84_disp_core_new },
-		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, gt200_disp_ovly_new },
+		{{0,0,  G82_DISP_CURSOR             }, nvkm_disp_chan_new, & nv50_disp_curs },
+		{{0,0,  G82_DISP_OVERLAY            }, nvkm_disp_chan_new, & nv50_disp_oimm },
+		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &  g84_disp_base },
+		{{0,0,GT200_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &  g84_disp_core },
+		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &gt200_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
index 0b97b44e52e6..70c49e7af9cf 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -191,11 +191,11 @@ gt215_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,GT214_DISP },
 	.user = {
-		{{0,0,GT214_DISP_CURSOR             },  nv50_disp_curs_new },
-		{{0,0,GT214_DISP_OVERLAY            },  nv50_disp_oimm_new },
-		{{0,0,GT214_DISP_BASE_CHANNEL_DMA   },   g84_disp_base_new },
-		{{0,0,GT214_DISP_CORE_CHANNEL_DMA   },   g94_disp_core_new },
-		{{0,0,GT214_DISP_OVERLAY_CHANNEL_DMA},   g84_disp_ovly_new },
+		{{0,0,GT214_DISP_CURSOR             }, nvkm_disp_chan_new, & nv50_disp_curs },
+		{{0,0,GT214_DISP_OVERLAY            }, nvkm_disp_chan_new, & nv50_disp_oimm },
+		{{0,0,GT214_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &  g84_disp_base },
+		{{0,0,GT214_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &  g94_disp_core },
+		{{0,0,GT214_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &  g84_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
index 1708e0e3332e..9106743a6368 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gv100.c
@@ -32,8 +32,6 @@
 #include <subdev/timer.h>
 
 #include <nvif/class.h>
-#include <nvif/clc37b.h>
-#include <nvif/clc37e.h>
 #include <nvif/unpack.h>
 
 static void
@@ -309,7 +307,6 @@ gv100_head_cnt(struct nvkm_disp *disp, unsigned long *pmask)
 
 const struct nvkm_event_func
 gv100_disp_chan_uevent = {
-	.ctor = nv50_disp_chan_uevent_ctor,
 };
 
 u64
@@ -382,50 +379,20 @@ gv100_disp_wimm_intr(struct nvkm_disp_chan *chan, bool en)
 }
 
 static const struct nvkm_disp_chan_func
-gv100_disp_wimm = {
+gv100_disp_wimm_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gv100_disp_dmac_init,
 	.fini = gv100_disp_dmac_fini,
 	.intr = gv100_disp_wimm_intr,
 	.user = gv100_disp_chan_user,
 };
 
-static int
-gv100_disp_wimm_new_(const struct nvkm_disp_chan_func *func,
-		     const struct nvkm_disp_chan_mthd *mthd,
-		     struct nvkm_disp *disp, int chid,
-		     const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		     struct nvkm_object **pobject)
-{
-	union {
-		struct nvc37b_window_imm_channel_dma_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int wndw, ret = -ENOSYS;
-	u64 push;
-
-	nvif_ioctl(parent, "create window imm channel dma size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create window imm channel dma vers %d "
-				   "pushbuf %016llx index %d\n",
-			   args->v0.version, args->v0.pushbuf, args->v0.index);
-		if (!(disp->wndw.mask & BIT(args->v0.index)))
-			return -EINVAL;
-		push = args->v0.pushbuf;
-		wndw = args->v0.index;
-	} else
-		return ret;
-
-	return nv50_disp_dmac_new_(func, mthd, disp, chid + wndw,
-				   wndw, push, oclass, pobject);
-}
-
-int
-gv100_disp_wimm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return gv100_disp_wimm_new_(&gv100_disp_wimm, NULL, disp, 33,
-				    oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gv100_disp_wimm = {
+	.func = &gv100_disp_wimm_func,
+	.ctrl = 33,
+	.user = 33,
+};
 
 static const struct nvkm_disp_mthd_list
 gv100_disp_wndw_mthd_base = {
@@ -538,7 +505,8 @@ gv100_disp_wndw_intr(struct nvkm_disp_chan *chan, bool en)
 }
 
 static const struct nvkm_disp_chan_func
-gv100_disp_wndw = {
+gv100_disp_wndw_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gv100_disp_dmac_init,
 	.fini = gv100_disp_dmac_fini,
 	.intr = gv100_disp_wndw_intr,
@@ -546,43 +514,13 @@ gv100_disp_wndw = {
 	.bind = gv100_disp_dmac_bind,
 };
 
-static int
-gv100_disp_wndw_new_(const struct nvkm_disp_chan_func *func,
-		     const struct nvkm_disp_chan_mthd *mthd,
-		     struct nvkm_disp *disp, int chid,
-		     const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		     struct nvkm_object **pobject)
-{
-	union {
-		struct nvc37e_window_channel_dma_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int wndw, ret = -ENOSYS;
-	u64 push;
-
-	nvif_ioctl(parent, "create window channel dma size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create window channel dma vers %d "
-				   "pushbuf %016llx index %d\n",
-			   args->v0.version, args->v0.pushbuf, args->v0.index);
-		if (!(disp->wndw.mask & BIT(args->v0.index)))
-			return -EINVAL;
-		push = args->v0.pushbuf;
-		wndw = args->v0.index;
-	} else
-		return ret;
-
-	return nv50_disp_dmac_new_(func, mthd, disp, chid + wndw,
-				   wndw, push, oclass, pobject);
-}
-
-int
-gv100_disp_wndw_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return gv100_disp_wndw_new_(&gv100_disp_wndw, &gv100_disp_wndw_mthd,
-				    disp, 1, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gv100_disp_wndw = {
+	.func = &gv100_disp_wndw_func,
+	.ctrl = 1,
+	.user = 1,
+	.mthd = &gv100_disp_wndw_mthd,
+};
 
 int
 gv100_disp_wndw_cnt(struct nvkm_disp *disp, unsigned long *pmask)
@@ -635,20 +573,19 @@ gv100_disp_curs_init(struct nvkm_disp_chan *chan)
 }
 
 static const struct nvkm_disp_chan_func
-gv100_disp_curs = {
+gv100_disp_curs_func = {
 	.init = gv100_disp_curs_init,
 	.fini = gv100_disp_curs_fini,
 	.intr = gv100_disp_curs_intr,
 	.user = gv100_disp_chan_user,
 };
 
-int
-gv100_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_curs_new_(&gv100_disp_curs, disp, 73, 73,
-				   oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gv100_disp_curs = {
+	.func = &gv100_disp_curs_func,
+	.ctrl = 73,
+	.user = 73,
+};
 
 const struct nvkm_disp_mthd_list
 gv100_disp_core_mthd_base = {
@@ -817,7 +754,8 @@ gv100_disp_core_init(struct nvkm_disp_chan *chan)
 }
 
 static const struct nvkm_disp_chan_func
-gv100_disp_core = {
+gv100_disp_core_func = {
+	.push = nv50_disp_dmac_push,
 	.init = gv100_disp_core_init,
 	.fini = gv100_disp_core_fini,
 	.intr = gv100_disp_core_intr,
@@ -825,13 +763,13 @@ gv100_disp_core = {
 	.bind = gv100_disp_dmac_bind,
 };
 
-int
-gv100_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&gv100_disp_core, &gv100_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+const struct nvkm_disp_chan_user
+gv100_disp_core = {
+	.func = &gv100_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &gv100_disp_core_mthd,
+};
 
 #define gv100_disp_caps(p) container_of((p), struct gv100_disp_caps, object)
 
@@ -859,8 +797,9 @@ gv100_disp_caps = {
 
 int
 gv100_disp_caps_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_disp *disp, struct nvkm_object **pobject)
+		    struct nvkm_object **pobject)
 {
+	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
 	struct gv100_disp_caps *caps;
 
 	if (!(caps = kzalloc(sizeof(*caps), GFP_KERNEL)))
@@ -1276,10 +1215,10 @@ gv100_disp = {
 	.root = {  0, 0,GV100_DISP },
 	.user = {
 		{{-1,-1,GV100_DISP_CAPS                  }, gv100_disp_caps_new },
-		{{ 0, 0,GV100_DISP_CURSOR                }, gv100_disp_curs_new },
-		{{ 0, 0,GV100_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
-		{{ 0, 0,GV100_DISP_CORE_CHANNEL_DMA      }, gv100_disp_core_new },
-		{{ 0, 0,GV100_DISP_WINDOW_CHANNEL_DMA    }, gv100_disp_wndw_new },
+		{{ 0, 0,GV100_DISP_CURSOR                },  nvkm_disp_chan_new, &gv100_disp_curs },
+		{{ 0, 0,GV100_DISP_WINDOW_IMM_CHANNEL_DMA},  nvkm_disp_wndw_new, &gv100_disp_wimm },
+		{{ 0, 0,GV100_DISP_CORE_CHANNEL_DMA      },  nvkm_disp_core_new, &gv100_disp_core },
+		{{ 0, 0,GV100_DISP_WINDOW_CHANNEL_DMA    },  nvkm_disp_wndw_new, &gv100_disp_wndw },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
index 915a0edc0c84..916b1d477b0b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp77.c
@@ -57,11 +57,11 @@ mcp77_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,GT206_DISP },
 	.user = {
-		{{0,0,  G82_DISP_CURSOR             },  nv50_disp_curs_new },
-		{{0,0,  G82_DISP_OVERLAY            },  nv50_disp_oimm_new },
-		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   },   g84_disp_base_new },
-		{{0,0,GT206_DISP_CORE_CHANNEL_DMA   },   g94_disp_core_new },
-		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, gt200_disp_ovly_new },
+		{{0,0,  G82_DISP_CURSOR             }, nvkm_disp_chan_new, & nv50_disp_curs },
+		{{0,0,  G82_DISP_OVERLAY            }, nvkm_disp_chan_new, & nv50_disp_oimm },
+		{{0,0,GT200_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &  g84_disp_base },
+		{{0,0,GT206_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &  g94_disp_core },
+		{{0,0,GT200_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &gt200_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
index 0e921a87f10d..a5a0b9439374 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/mcp89.c
@@ -71,11 +71,11 @@ mcp89_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0,0,GT214_DISP },
 	.user = {
-		{{0,0,GT214_DISP_CURSOR             },  nv50_disp_curs_new },
-		{{0,0,GT214_DISP_OVERLAY            },  nv50_disp_oimm_new },
-		{{0,0,GT214_DISP_BASE_CHANNEL_DMA   },   g84_disp_base_new },
-		{{0,0,GT214_DISP_CORE_CHANNEL_DMA   },   g94_disp_core_new },
-		{{0,0,GT214_DISP_OVERLAY_CHANNEL_DMA},   g84_disp_ovly_new },
+		{{0,0,GT214_DISP_CURSOR             }, nvkm_disp_chan_new, &nv50_disp_curs },
+		{{0,0,GT214_DISP_OVERLAY            }, nvkm_disp_chan_new, &nv50_disp_oimm },
+		{{0,0,GT214_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, & g84_disp_base },
+		{{0,0,GT214_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, & g94_disp_core },
+		{{0,0,GT214_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, & g84_disp_ovly },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index 25853cbc55f0..237f5aa06850 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -39,12 +39,6 @@
 #include <subdev/timer.h>
 
 #include <nvif/class.h>
-#include <nvif/cl507a.h>
-#include <nvif/cl507b.h>
-#include <nvif/cl507c.h>
-#include <nvif/cl507d.h>
-#include <nvif/cl507e.h>
-#include <nvif/event.h>
 #include <nvif/unpack.h>
 
 static void
@@ -509,35 +503,11 @@ nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
 void
 nv50_disp_chan_uevent_send(struct nvkm_disp *disp, int chid)
 {
-	struct nvif_notify_uevent_rep {
-	} rep;
-
-	nvkm_event_send(&disp->uevent, 1, chid, &rep, sizeof(rep));
-}
-
-int
-nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
-			   struct nvkm_notify *notify)
-{
-	struct nvkm_disp_chan *chan = nvkm_disp_chan(object);
-	union {
-		struct nvif_notify_uevent_req none;
-	} *args = data;
-	int ret = -ENOSYS;
-
-	if (!(ret = nvif_unvers(ret, &data, &size, args->none))) {
-		notify->size  = sizeof(struct nvif_notify_uevent_rep);
-		notify->types = 1;
-		notify->index = chan->chid.user;
-		return 0;
-	}
-
-	return ret;
+	nvkm_event_send(&disp->uevent, NVKM_DISP_EVENT_CHAN_AWAKEN, chid, NULL, 0);
 }
 
 const struct nvkm_event_func
 nv50_disp_chan_uevent = {
-	.ctor = nv50_disp_chan_uevent_ctor,
 	.init = nv50_disp_chan_uevent_init,
 	.fini = nv50_disp_chan_uevent_fini,
 };
@@ -677,23 +647,9 @@ nv50_disp_dmac_init(struct nvkm_disp_chan *chan)
 }
 
 int
-nv50_disp_dmac_new_(const struct nvkm_disp_chan_func *func,
-		    const struct nvkm_disp_chan_mthd *mthd,
-		    struct nvkm_disp *disp, int chid, int head, u64 push,
-		    const struct nvkm_oclass *oclass,
-		    struct nvkm_object **pobject)
+nv50_disp_dmac_push(struct nvkm_disp_chan *chan, u64 object)
 {
-	struct nvkm_client *client = oclass->client;
-	struct nvkm_disp_chan *chan;
-	int ret;
-
-	ret = nvkm_disp_chan_new_(func, mthd, disp, chid, chid, head, oclass,
-				  pobject);
-	chan = nvkm_disp_chan(*pobject);
-	if (ret)
-		return ret;
-
-	chan->memory = nvkm_umem_search(client, push);
+	chan->memory = nvkm_umem_search(chan->object.client, object);
 	if (IS_ERR(chan->memory))
 		return PTR_ERR(chan->memory);
 
@@ -714,6 +670,7 @@ nv50_disp_dmac_new_(const struct nvkm_disp_chan_func *func,
 
 const struct nvkm_disp_chan_func
 nv50_disp_dmac_func = {
+	.push = nv50_disp_dmac_push,
 	.init = nv50_disp_dmac_init,
 	.fini = nv50_disp_dmac_fini,
 	.intr = nv50_disp_chan_intr,
@@ -721,103 +678,19 @@ nv50_disp_dmac_func = {
 	.bind = nv50_disp_dmac_bind,
 };
 
-int
-nv50_disp_curs_new_(const struct nvkm_disp_chan_func *func,
-		    struct nvkm_disp *disp, int ctrl, int user,
-		    const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_object **pobject)
-{
-	union {
-		struct nv50_disp_cursor_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int head, ret = -ENOSYS;
-
-	nvif_ioctl(parent, "create disp cursor size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create disp cursor vers %d head %d\n",
-			   args->v0.version, args->v0.head);
-		if (!nvkm_head_find(disp, args->v0.head))
-			return -EINVAL;
-		head = args->v0.head;
-	} else
-		return ret;
-
-	return nvkm_disp_chan_new_(func, NULL, disp, ctrl + head, user + head,
-				   head, oclass, pobject);
-}
-
-int
-nv50_disp_curs_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		   struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_curs_new_(&nv50_disp_pioc_func, disp, 7, 7,
-				   oclass, argv, argc, pobject);
-}
-
-int
-nv50_disp_oimm_new_(const struct nvkm_disp_chan_func *func,
-		    struct nvkm_disp *disp, int ctrl, int user,
-		    const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_object **pobject)
-{
-	union {
-		struct nv50_disp_overlay_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int head, ret = -ENOSYS;
-
-	nvif_ioctl(parent, "create disp overlay size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create disp overlay vers %d head %d\n",
-			   args->v0.version, args->v0.head);
-		if (!nvkm_head_find(disp, args->v0.head))
-			return -EINVAL;
-		head = args->v0.head;
-	} else
-		return ret;
-
-	return nvkm_disp_chan_new_(func, NULL, disp, ctrl + head, user + head,
-				   head, oclass, pobject);
-}
-
-int
-nv50_disp_oimm_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		   struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_oimm_new_(&nv50_disp_pioc_func, disp, 5, 5,
-				   oclass, argv, argc, pobject);
-}
-
-int
-nv50_disp_ovly_new_(const struct nvkm_disp_chan_func *func,
-		    const struct nvkm_disp_chan_mthd *mthd,
-		    struct nvkm_disp *disp, int chid,
-		    const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_object **pobject)
-{
-	union {
-		struct nv50_disp_overlay_channel_dma_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int head, ret = -ENOSYS;
-	u64 push;
-
-	nvif_ioctl(parent, "create disp overlay channel dma size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create disp overlay channel dma vers %d "
-				   "pushbuf %016llx head %d\n",
-			   args->v0.version, args->v0.pushbuf, args->v0.head);
-		if (!nvkm_head_find(disp, args->v0.head))
-			return -EINVAL;
-		push = args->v0.pushbuf;
-		head = args->v0.head;
-	} else
-		return ret;
+const struct nvkm_disp_chan_user
+nv50_disp_curs = {
+	.func = &nv50_disp_pioc_func,
+	.ctrl = 7,
+	.user = 7,
+};
 
-	return nv50_disp_dmac_new_(func, mthd, disp, chid + head,
-				   head, push, oclass, pobject);
-}
+const struct nvkm_disp_chan_user
+nv50_disp_oimm = {
+	.func = &nv50_disp_pioc_func,
+	.ctrl = 5,
+	.user = 5,
+};
 
 static const struct nvkm_disp_mthd_list
 nv50_disp_ovly_mthd_base = {
@@ -858,43 +731,13 @@ nv50_disp_ovly_mthd = {
 	}
 };
 
-int
-nv50_disp_ovly_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		   struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_ovly_new_(&nv50_disp_dmac_func, &nv50_disp_ovly_mthd,
-				   disp, 3, oclass, argv, argc, pobject);
-}
-
-int
-nv50_disp_base_new_(const struct nvkm_disp_chan_func *func,
-		    const struct nvkm_disp_chan_mthd *mthd,
-		    struct nvkm_disp *disp, int chid,
-		    const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_object **pobject)
-{
-	union {
-		struct nv50_disp_base_channel_dma_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	int head, ret = -ENOSYS;
-	u64 push;
-
-	nvif_ioctl(parent, "create disp base channel dma size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create disp base channel dma vers %d "
-				   "pushbuf %016llx head %d\n",
-			   args->v0.version, args->v0.pushbuf, args->v0.head);
-		if (!nvkm_head_find(disp, args->v0.head))
-			return -EINVAL;
-		push = args->v0.pushbuf;
-		head = args->v0.head;
-	} else
-		return ret;
-
-	return nv50_disp_dmac_new_(func, mthd, disp, chid + head,
-				   head, push, oclass, pobject);
-}
+static const struct nvkm_disp_chan_user
+nv50_disp_ovly = {
+	.func = &nv50_disp_dmac_func,
+	.ctrl = 3,
+	.user = 3,
+	.mthd = &nv50_disp_ovly_mthd,
+};
 
 static const struct nvkm_disp_mthd_list
 nv50_disp_base_mthd_base = {
@@ -947,40 +790,13 @@ nv50_disp_base_mthd = {
 	}
 };
 
-int
-nv50_disp_base_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		   struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_base_new_(&nv50_disp_dmac_func, &nv50_disp_base_mthd,
-				   disp, 1, oclass, argv, argc, pobject);
-}
-
-int
-nv50_disp_core_new_(const struct nvkm_disp_chan_func *func,
-		    const struct nvkm_disp_chan_mthd *mthd,
-		    struct nvkm_disp *disp, int chid,
-		    const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		    struct nvkm_object **pobject)
-{
-	union {
-		struct nv50_disp_core_channel_dma_v0 v0;
-	} *args = argv;
-	struct nvkm_object *parent = oclass->parent;
-	u64 push;
-	int ret = -ENOSYS;
-
-	nvif_ioctl(parent, "create disp core channel dma size %d\n", argc);
-	if (!(ret = nvif_unpack(ret, &argv, &argc, args->v0, 0, 0, false))) {
-		nvif_ioctl(parent, "create disp core channel dma vers %d "
-				   "pushbuf %016llx\n",
-			   args->v0.version, args->v0.pushbuf);
-		push = args->v0.pushbuf;
-	} else
-		return ret;
-
-	return nv50_disp_dmac_new_(func, mthd, disp, chid, 0,
-				   push, oclass, pobject);
-}
+static const struct nvkm_disp_chan_user
+nv50_disp_base = {
+	.func = &nv50_disp_dmac_func,
+	.ctrl = 1,
+	.user = 1,
+	.mthd = &nv50_disp_base_mthd,
+};
 
 const struct nvkm_disp_mthd_list
 nv50_disp_core_mthd_base = {
@@ -1144,6 +960,7 @@ nv50_disp_core_init(struct nvkm_disp_chan *chan)
 
 const struct nvkm_disp_chan_func
 nv50_disp_core_func = {
+	.push = nv50_disp_dmac_push,
 	.init = nv50_disp_core_init,
 	.fini = nv50_disp_core_fini,
 	.intr = nv50_disp_chan_intr,
@@ -1151,13 +968,13 @@ nv50_disp_core_func = {
 	.bind = nv50_disp_dmac_bind,
 };
 
-int
-nv50_disp_core_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		   struct nvkm_disp *disp, struct nvkm_object **pobject)
-{
-	return nv50_disp_core_new_(&nv50_disp_core_func, &nv50_disp_core_mthd,
-				   disp, 0, oclass, argv, argc, pobject);
-}
+static const struct nvkm_disp_chan_user
+nv50_disp_core = {
+	.func = &nv50_disp_core_func,
+	.ctrl = 0,
+	.user = 0,
+	.mthd = &nv50_disp_core_mthd,
+};
 
 static u32
 nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp,
@@ -1805,11 +1622,11 @@ nv50_disp = {
 	.pior = { .cnt = nv50_pior_cnt, .new = nv50_pior_new },
 	.root = { 0, 0, NV50_DISP },
 	.user = {
-		{{0,0,NV50_DISP_CURSOR             }, nv50_disp_curs_new },
-		{{0,0,NV50_DISP_OVERLAY            }, nv50_disp_oimm_new },
-		{{0,0,NV50_DISP_BASE_CHANNEL_DMA   }, nv50_disp_base_new },
-		{{0,0,NV50_DISP_CORE_CHANNEL_DMA   }, nv50_disp_core_new },
-		{{0,0,NV50_DISP_OVERLAY_CHANNEL_DMA}, nv50_disp_ovly_new },
+		{{0,0,NV50_DISP_CURSOR             }, nvkm_disp_chan_new, &nv50_disp_curs },
+		{{0,0,NV50_DISP_OVERLAY            }, nvkm_disp_chan_new, &nv50_disp_oimm },
+		{{0,0,NV50_DISP_BASE_CHANNEL_DMA   }, nvkm_disp_chan_new, &nv50_disp_base },
+		{{0,0,NV50_DISP_CORE_CHANNEL_DMA   }, nvkm_disp_core_new, &nv50_disp_core },
+		{{0,0,NV50_DISP_OVERLAY_CHANNEL_DMA}, nvkm_disp_chan_new, &nv50_disp_ovly },
 		{}
 	}
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
index a73b453c6302..5bd0e0e84c3f 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -36,8 +36,9 @@ struct nvkm_disp_func {
 
 	struct nvkm_disp_user {
 		struct nvkm_sclass base;
-		int (*ctor)(const struct nvkm_oclass *, void *argv, u32 argc, struct nvkm_disp *,
+		int (*ctor)(const struct nvkm_oclass *, void *argv, u32 argc,
 			    struct nvkm_object **);
+		const struct nvkm_disp_chan_user *chan;
 	} user[];
 };
 
@@ -68,8 +69,7 @@ void gv100_disp_fini(struct nvkm_disp *);
 void gv100_disp_intr(struct nvkm_disp *);
 void gv100_disp_super(struct work_struct *);
 int gv100_disp_wndw_cnt(struct nvkm_disp *, unsigned long *);
-int gv100_disp_caps_new(const struct nvkm_oclass *, void *, u32,
-			struct nvkm_disp *, struct nvkm_object **);
+int gv100_disp_caps_new(const struct nvkm_oclass *, void *, u32, struct nvkm_object **);
 
 int tu102_disp_init(struct nvkm_disp *);
 
@@ -78,8 +78,6 @@ void nv50_disp_dptmds_war_3(struct nvkm_disp *, struct dcb_output *);
 void nv50_disp_update_sppll1(struct nvkm_disp *);
 
 extern const struct nvkm_event_func nv50_disp_chan_uevent;
-int  nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32,
-				struct nvkm_notify *);
 void nv50_disp_chan_uevent_send(struct nvkm_disp *, int);
 
 extern const struct nvkm_event_func gf119_disp_chan_uevent;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
index c85bde64fb76..e4ad1a6f6c88 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/tu102.c
@@ -223,10 +223,10 @@ tu102_disp = {
 	.root = {  0, 0,TU102_DISP },
 	.user = {
 		{{-1,-1,GV100_DISP_CAPS                  }, gv100_disp_caps_new },
-		{{ 0, 0,TU102_DISP_CURSOR                }, gv100_disp_curs_new },
-		{{ 0, 0,TU102_DISP_WINDOW_IMM_CHANNEL_DMA}, gv100_disp_wimm_new },
-		{{ 0, 0,TU102_DISP_CORE_CHANNEL_DMA      }, gv100_disp_core_new },
-		{{ 0, 0,TU102_DISP_WINDOW_CHANNEL_DMA    }, gv100_disp_wndw_new },
+		{{ 0, 0,TU102_DISP_CURSOR                },  nvkm_disp_chan_new, &gv100_disp_curs },
+		{{ 0, 0,TU102_DISP_WINDOW_IMM_CHANNEL_DMA},  nvkm_disp_wndw_new, &gv100_disp_wimm },
+		{{ 0, 0,TU102_DISP_CORE_CHANNEL_DMA      },  nvkm_disp_core_new, &gv100_disp_core },
+		{{ 0, 0,TU102_DISP_WINDOW_CHANNEL_DMA    },  nvkm_disp_wndw_new, &gv100_disp_wndw },
 		{}
 	},
 };
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
index ec17254890d1..f756208d4a14 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/udisp.c
@@ -23,16 +23,6 @@
 
 #include <nvif/if0010.h>
 
-static int
-nvkm_udisp_sclass_new(const struct nvkm_oclass *oclass, void *argv, u32 argc,
-		      struct nvkm_object **pobject)
-{
-	struct nvkm_disp *disp = nvkm_udisp(oclass->parent);
-	const struct nvkm_disp_user *user = oclass->priv;
-
-	return user->ctor(oclass, argv, argc, disp, pobject);
-}
-
 static int
 nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *sclass)
 {
@@ -40,8 +30,7 @@ nvkm_udisp_sclass(struct nvkm_object *object, int index, struct nvkm_oclass *scl
 
 	if (disp->func->user[index].ctor) {
 		sclass->base = disp->func->user[index].base;
-		sclass->priv = disp->func->user + index;
-		sclass->ctor = nvkm_udisp_sclass_new;
+		sclass->ctor = disp->func->user[index].ctor;
 		return 0;
 	}
 
-- 
2.38.1