Blob Blame History Raw
From: Ben Skeggs <bskeggs@redhat.com>
Date: Tue, 8 May 2018 20:39:47 +1000
Subject: drm/nouveau/kms/nv50-: initial overlay support
Git-commit: 2ce7f38629891eeaf3e5d406add102a3fa6f6632
Patch-mainline: v4.18-rc1
References: FATE#326289 FATE#326079 FATE#326049 FATE#322398 FATE#326166

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/nouveau/dispnv50/Kbuild     |    1 
 drivers/gpu/drm/nouveau/dispnv50/atom.h     |   11 ++
 drivers/gpu/drm/nouveau/dispnv50/base.h     |    2 
 drivers/gpu/drm/nouveau/dispnv50/curs.h     |    1 
 drivers/gpu/drm/nouveau/dispnv50/disp.h     |    3 
 drivers/gpu/drm/nouveau/dispnv50/head507d.c |    3 
 drivers/gpu/drm/nouveau/dispnv50/head907d.c |    2 
 drivers/gpu/drm/nouveau/dispnv50/oimm507b.c |    6 -
 drivers/gpu/drm/nouveau/dispnv50/ovly.c     |    2 
 drivers/gpu/drm/nouveau/dispnv50/ovly.h     |   14 ++
 drivers/gpu/drm/nouveau/dispnv50/ovly507e.c |  144 ++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/ovly827e.c |   66 ++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/ovly907e.c |   38 +++++++
 drivers/gpu/drm/nouveau/dispnv50/ovly917e.c |   45 ++++++++
 drivers/gpu/drm/nouveau/dispnv50/wndw.c     |   35 ++++++
 drivers/gpu/drm/nouveau/dispnv50/wndw.h     |    6 +
 16 files changed, 364 insertions(+), 15 deletions(-)

--- a/drivers/gpu/drm/nouveau/dispnv50/Kbuild
+++ b/drivers/gpu/drm/nouveau/dispnv50/Kbuild
@@ -40,3 +40,4 @@ nouveau-y += dispnv50/ovly.o
 nouveau-y += dispnv50/ovly507e.o
 nouveau-y += dispnv50/ovly827e.o
 nouveau-y += dispnv50/ovly907e.o
+nouveau-y += dispnv50/ovly917e.o
--- a/drivers/gpu/drm/nouveau/dispnv50/atom.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/atom.h
@@ -173,6 +173,7 @@ struct nv50_wndw_atom {
 		u8  mode:2;
 		u8  interval:4;
 
+		u8  colorspace:2;
 		u8  format;
 		u8  kind:7;
 		u8  layout:1;
@@ -187,6 +188,15 @@ struct nv50_wndw_atom {
 	} image;
 
 	struct {
+		u16 sx;
+		u16 sy;
+		u16 sw;
+		u16 sh;
+		u16 dw;
+		u16 dh;
+	} scale;
+
+	struct {
 		u16 x;
 		u16 y;
 	} point;
@@ -197,6 +207,7 @@ struct nv50_wndw_atom {
 			bool sema:1;
 			bool xlut:1;
 			bool image:1;
+			bool scale:1;
 			bool point:1;
 		};
 		u8 mask;
--- a/drivers/gpu/drm/nouveau/dispnv50/base.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/base.h
@@ -13,10 +13,8 @@ void base507c_release(struct nv50_wndw *
 		      struct nv50_head_atom *);
 void base507c_sema_set(struct nv50_wndw *, struct nv50_wndw_atom *);
 void base507c_sema_clr(struct nv50_wndw *);
-void base507c_ntfy_reset(struct nouveau_bo *, u32);
 void base507c_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
 void base507c_ntfy_clr(struct nv50_wndw *);
-int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
 void base507c_xlut_set(struct nv50_wndw *, struct nv50_wndw_atom *);
 void base507c_xlut_clr(struct nv50_wndw *);
 void base507c_image_clr(struct nv50_wndw *);
--- a/drivers/gpu/drm/nouveau/dispnv50/curs.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs.h
@@ -6,7 +6,6 @@ int curs507a_new(struct nouveau_drm *, i
 int curs507a_new_(const struct nv50_wimm_func *, struct nouveau_drm *,
 		  int head, s32 oclass, u32 interlock_data,
 		  struct nv50_wndw **);
-extern const struct nv50_wimm_func curs507a;
 
 int curs907a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h
@@ -16,6 +16,9 @@ struct nv50_disp {
 #define NV50_DISP_BASE_SEM0(c)                    NV50_DISP_WNDW_SEM0(0 + (c))
 #define NV50_DISP_BASE_SEM1(c)                    NV50_DISP_WNDW_SEM1(0 + (c))
 #define NV50_DISP_BASE_NTFY(c)                    NV50_DISP_WNDW_NTFY(0 + (c))
+#define NV50_DISP_OVLY_SEM0(c)                    NV50_DISP_WNDW_SEM0(4 + (c))
+#define NV50_DISP_OVLY_SEM1(c)                    NV50_DISP_WNDW_SEM1(4 + (c))
+#define NV50_DISP_OVLY_NTFY(c)                    NV50_DISP_WNDW_NTFY(4 + (c))
 	struct nouveau_bo *sync;
 
 	struct mutex mutex;
--- a/drivers/gpu/drm/nouveau/dispnv50/head507d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head507d.c
@@ -58,7 +58,6 @@ head507d_ovly(struct nv50_head *head, st
 
 	if (asyh->ovly.cpp) {
 		switch (asyh->ovly.cpp) {
-		case 8: bounds |= 0x00000500; break;
 		case 4: bounds |= 0x00000300; break;
 		case 2: bounds |= 0x00000100; break;
 		default:
@@ -66,6 +65,8 @@ head507d_ovly(struct nv50_head *head, st
 			break;
 		}
 		bounds |= 0x00000001;
+	} else {
+		bounds |= 0x00000100;
 	}
 
 	if ((push = evo_wait(core, 2))) {
--- a/drivers/gpu/drm/nouveau/dispnv50/head907d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/head907d.c
@@ -82,6 +82,8 @@ head907d_ovly(struct nv50_head *head, st
 			break;
 		}
 		bounds |= 0x00000001;
+	} else {
+		bounds |= 0x00000100;
 	}
 
 	if ((push = evo_wait(core, 2))) {
--- a/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/oimm507b.c
@@ -23,10 +23,6 @@
 
 #include <nvif/cl507b.h>
 
-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)
@@ -52,5 +48,5 @@ oimm507b_init_(const struct nv50_wimm_fu
 int
 oimm507b_init(struct nouveau_drm *drm, s32 oclass, struct nv50_wndw *wndw)
 {
-	return oimm507b_init_(&oimm507b, drm, oclass, wndw);
+	return oimm507b_init_(&curs507a, drm, oclass, wndw);
 }
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly.c
@@ -32,7 +32,7 @@ nv50_ovly_new(struct nouveau_drm *drm, i
 		int version;
 		int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 	} ovlys[] = {
-		{ GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly907e_new },
+		{ GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly917e_new },
 		{ GF110_DISP_OVERLAY_CONTROL_DMA, 0, ovly907e_new },
 		{ GT214_DISP_OVERLAY_CHANNEL_DMA, 0, ovly827e_new },
 		{ GT200_DISP_OVERLAY_CHANNEL_DMA, 0, ovly827e_new },
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly.h
@@ -6,11 +6,25 @@ int ovly507e_new(struct nouveau_drm *, i
 int ovly507e_new_(const struct nv50_wndw_func *, const u32 *format,
 		  struct nouveau_drm *, int head, s32 oclass,
 		  u32 interlock_data, struct nv50_wndw **);
+int ovly507e_acquire(struct nv50_wndw *, struct nv50_wndw_atom *,
+		     struct nv50_head_atom *);
+void ovly507e_release(struct nv50_wndw *, struct nv50_wndw_atom *,
+		      struct nv50_head_atom *);
+void ovly507e_ntfy_set(struct nv50_wndw *, struct nv50_wndw_atom *);
+void ovly507e_ntfy_clr(struct nv50_wndw *);
+void ovly507e_image_clr(struct nv50_wndw *);
+void ovly507e_scale_set(struct nv50_wndw *, struct nv50_wndw_atom *);
+void ovly507e_update(struct nv50_wndw *, u32 *);
 
 extern const u32 ovly827e_format[];
+void ovly827e_ntfy_reset(struct nouveau_bo *, u32);
+int ovly827e_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
+
+extern const struct nv50_wndw_func ovly907e;
 
 int ovly827e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 int ovly907e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
+int ovly917e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 
 int nv50_ovly_new(struct nouveau_drm *, int head, struct nv50_wndw **);
 #endif
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly507e.c
@@ -20,17 +20,149 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 #include "ovly.h"
+#include "atom.h"
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
 
 #include <nvif/cl507e.h>
+#include <nvif/event.h>
+
+void
+ovly507e_update(struct nv50_wndw *wndw, u32 *interlock)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 2))) {
+		evo_mthd(push, 0x0080, 1);
+		evo_data(push, interlock[NV50_DISP_INTERLOCK_CORE]);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+void
+ovly507e_scale_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 4))) {
+		evo_mthd(push, 0x00e0, 3);
+		evo_data(push, asyw->scale.sy << 16 | asyw->scale.sx);
+		evo_data(push, asyw->scale.sh << 16 | asyw->scale.sw);
+		evo_data(push, asyw->scale.dw);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+void
+ovly507e_image_clr(struct nv50_wndw *wndw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 4))) {
+		evo_mthd(push, 0x0084, 1);
+		evo_data(push, 0x00000000);
+		evo_mthd(push, 0x00c0, 1);
+		evo_data(push, 0x00000000);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+static void
+ovly507e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 12))) {
+		evo_mthd(push, 0x0084, 1);
+		evo_data(push, asyw->image.interval << 4);
+		evo_mthd(push, 0x00c0, 1);
+		evo_data(push, asyw->image.handle[0]);
+		evo_mthd(push, 0x0100, 1);
+		evo_data(push, 0x00000002);
+		evo_mthd(push, 0x0800, 1);
+		evo_data(push, asyw->image.offset[0] >> 8);
+		evo_mthd(push, 0x0808, 3);
+		evo_data(push, asyw->image.h << 16 | asyw->image.w);
+		evo_data(push, asyw->image.layout << 20 |
+			       (asyw->image.pitch[0] >> 8) << 8 |
+			       asyw->image.blocks[0] << 8 |
+			       asyw->image.blockh);
+		evo_data(push, asyw->image.kind << 16 |
+			       asyw->image.format << 8 |
+			       asyw->image.colorspace);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+void
+ovly507e_ntfy_clr(struct nv50_wndw *wndw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 2))) {
+		evo_mthd(push, 0x00a4, 1);
+		evo_data(push, 0x00000000);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+void
+ovly507e_ntfy_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 3))) {
+		evo_mthd(push, 0x00a0, 2);
+		evo_data(push, asyw->ntfy.awaken << 30 | asyw->ntfy.offset);
+		evo_data(push, asyw->ntfy.handle);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+void
+ovly507e_release(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
+		 struct nv50_head_atom *asyh)
+{
+	asyh->ovly.cpp = 0;
+}
+
+int
+ovly507e_acquire(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw,
+		 struct nv50_head_atom *asyh)
+{
+	const struct drm_framebuffer *fb = asyw->state.fb;
+	int ret;
+
+	ret = drm_atomic_helper_check_plane_state(&asyw->state, &asyh->state,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  DRM_PLANE_HELPER_NO_SCALING,
+						  true, true);
+	if (ret)
+		return ret;
+
+	asyh->ovly.cpp = fb->format->cpp[0];
+	return 0;
+}
 
 #include "nouveau_bo.h"
 
 static const struct nv50_wndw_func
 ovly507e = {
+	.acquire = ovly507e_acquire,
+	.release = ovly507e_release,
+	.ntfy_set = ovly507e_ntfy_set,
+	.ntfy_clr = ovly507e_ntfy_clr,
+	.ntfy_reset = base507c_ntfy_reset,
+	.ntfy_wait_begun = base507c_ntfy_wait_begun,
+	.image_set = ovly507e_image_set,
+	.image_clr = ovly507e_image_clr,
+	.scale_set = ovly507e_scale_set,
+	.update = ovly507e_update,
 };
 
 static const u32
 ovly507e_format[] = {
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ARGB1555,
 	0
 };
 
@@ -61,6 +193,18 @@ ovly507e_new_(const struct nv50_wndw_fun
 		return ret;
 	}
 
+	ret = nvif_notify_init(&wndw->wndw.base.user, 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;
 	return 0;
 }
 
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
@@ -20,17 +20,81 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 #include "ovly.h"
+#include "atom.h"
 
 #include <nouveau_bo.h>
 
-#include <nvif/cl507e.h>
+static void
+ovly827e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 12))) {
+		evo_mthd(push, 0x0084, 1);
+		evo_data(push, asyw->image.interval << 4);
+		evo_mthd(push, 0x00c0, 1);
+		evo_data(push, asyw->image.handle[0]);
+		evo_mthd(push, 0x0100, 1);
+		evo_data(push, 0x00000002);
+		evo_mthd(push, 0x0800, 1);
+		evo_data(push, asyw->image.offset[0] >> 8);
+		evo_mthd(push, 0x0808, 3);
+		evo_data(push, asyw->image.h << 16 | asyw->image.w);
+		evo_data(push, asyw->image.layout << 20 |
+			       (asyw->image.pitch[0] >> 8) << 8 |
+			       asyw->image.blocks[0] << 8 |
+			       asyw->image.blockh);
+		evo_data(push, asyw->image.format << 8 |
+			       asyw->image.colorspace);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+int
+ovly827e_ntfy_wait_begun(struct nouveau_bo *bo, u32 offset,
+			 struct nvif_device *device)
+{
+	s64 time = nvif_msec(device, 2000ULL,
+		u32 data = nouveau_bo_rd32(bo, offset / 4 + 3);
+		if ((data & 0xffff0000) == 0xffff0000)
+			break;
+		usleep_range(1, 2);
+	);
+	return time < 0 ? time : 0;
+}
+
+void
+ovly827e_ntfy_reset(struct nouveau_bo *bo, u32 offset)
+{
+	nouveau_bo_wr32(bo, offset / 4 + 0, 0x00000000);
+	nouveau_bo_wr32(bo, offset / 4 + 1, 0x00000000);
+	nouveau_bo_wr32(bo, offset / 4 + 2, 0x00000000);
+	nouveau_bo_wr32(bo, offset / 4 + 3, 0x80000000);
+}
 
 static const struct nv50_wndw_func
 ovly827e = {
+	.acquire = ovly507e_acquire,
+	.release = ovly507e_release,
+	.ntfy_set = ovly507e_ntfy_set,
+	.ntfy_clr = ovly507e_ntfy_clr,
+	.ntfy_reset = ovly827e_ntfy_reset,
+	.ntfy_wait_begun = ovly827e_ntfy_wait_begun,
+	.image_set = ovly827e_image_set,
+	.image_clr = ovly507e_image_clr,
+	.scale_set = ovly507e_scale_set,
+	.update = ovly507e_update,
 };
 
 const u32
 ovly827e_format[] = {
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_ABGR2101010,
 	0
 };
 
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
@@ -20,9 +20,45 @@
  * OTHER DEALINGS IN THE SOFTWARE.
  */
 #include "ovly.h"
+#include "atom.h"
 
-static const struct nv50_wndw_func
+static void
+ovly907e_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
+{
+	u32 *push;
+	if ((push = evo_wait(&wndw->wndw, 12))) {
+		evo_mthd(push, 0x0084, 1);
+		evo_data(push, asyw->image.interval << 4);
+		evo_mthd(push, 0x00c0, 1);
+		evo_data(push, asyw->image.handle[0]);
+		evo_mthd(push, 0x0100, 1);
+		evo_data(push, 0x00000002);
+		evo_mthd(push, 0x0400, 1);
+		evo_data(push, asyw->image.offset[0] >> 8);
+		evo_mthd(push, 0x0408, 3);
+		evo_data(push, asyw->image.h << 16 | asyw->image.w);
+		evo_data(push, asyw->image.layout << 24 |
+			       (asyw->image.pitch[0] >> 8) << 8 |
+			       asyw->image.blocks[0] << 8 |
+			       asyw->image.blockh);
+		evo_data(push, asyw->image.format << 8 |
+			       asyw->image.colorspace);
+		evo_kick(push, &wndw->wndw);
+	}
+}
+
+const struct nv50_wndw_func
 ovly907e = {
+	.acquire = ovly507e_acquire,
+	.release = ovly507e_release,
+	.ntfy_set = ovly507e_ntfy_set,
+	.ntfy_clr = ovly507e_ntfy_clr,
+	.ntfy_reset = ovly827e_ntfy_reset,
+	.ntfy_wait_begun = ovly827e_ntfy_wait_begun,
+	.image_set = ovly907e_image_set,
+	.image_clr = ovly507e_image_clr,
+	.scale_set = ovly507e_scale_set,
+	.update = ovly507e_update,
 };
 
 int
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly917e.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "ovly.h"
+
+static const u32
+ovly917e_format[] = {
+	DRM_FORMAT_YUYV,
+	DRM_FORMAT_UYVY,
+	DRM_FORMAT_XRGB8888,
+	DRM_FORMAT_ARGB8888,
+	DRM_FORMAT_XRGB1555,
+	DRM_FORMAT_ARGB1555,
+	DRM_FORMAT_XBGR2101010,
+	DRM_FORMAT_ABGR2101010,
+	DRM_FORMAT_XRGB2101010,
+	DRM_FORMAT_ARGB2101010,
+	0
+};
+
+int
+ovly917e_new(struct nouveau_drm *drm, int head, s32 oclass,
+	     struct nv50_wndw **pwndw)
+{
+	return ovly507e_new_(&ovly907e, ovly917e_format, drm, head, oclass,
+			     0x00000004 << (head * 4), pwndw);
+}
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -146,6 +146,7 @@ nv50_wndw_flush_set(struct nv50_wndw *wn
 		wndw->func->xlut_set(wndw, asyw);
 	}
 
+	if (asyw->set.scale) wndw->func->scale_set(wndw, asyw);
 	if (asyw->set.point) {
 		wndw->immd->point(wndw, asyw);
 		wndw->immd->update(wndw, interlock);
@@ -181,6 +182,20 @@ nv50_wndw_atomic_check_release(struct nv
 }
 
 static int
+nv50_wndw_atomic_check_acquire_yuv(struct nv50_wndw_atom *asyw)
+{
+	switch (asyw->state.fb->format->format) {
+	case DRM_FORMAT_YUYV: asyw->image.format = 0x28; break;
+	case DRM_FORMAT_UYVY: asyw->image.format = 0x29; break;
+	default:
+		WARN_ON(1);
+		return -EINVAL;
+	}
+	asyw->image.colorspace = 1;
+	return 0;
+}
+
+static int
 nv50_wndw_atomic_check_acquire_rgb(struct nv50_wndw_atom *asyw)
 {
 	switch (asyw->state.fb->format->format) {
@@ -197,9 +212,9 @@ nv50_wndw_atomic_check_acquire_rgb(struc
 	case DRM_FORMAT_XRGB2101010:
 	case DRM_FORMAT_ARGB2101010: asyw->image.format = 0xdf; break;
 	default:
-		WARN_ON(1);
 		return -EINVAL;
 	}
+	asyw->image.colorspace = 0;
 	return 0;
 }
 
@@ -221,8 +236,11 @@ nv50_wndw_atomic_check_acquire(struct nv
 		asyw->image.kind = fb->nvbo->kind;
 
 		ret = nv50_wndw_atomic_check_acquire_rgb(asyw);
-		if (ret)
-			return ret;
+		if (ret) {
+			ret = nv50_wndw_atomic_check_acquire_yuv(asyw);
+			if (ret)
+				return ret;
+		}
 
 		if (asyw->image.kind) {
 			asyw->image.layout = 0;
@@ -247,6 +265,17 @@ nv50_wndw_atomic_check_acquire(struct nv
 		asyw->set.image = wndw->func->image_set != NULL;
 	}
 
+	if (wndw->func->scale_set) {
+		asyw->scale.sx = asyw->state.src_x >> 16;
+		asyw->scale.sy = asyw->state.src_y >> 16;
+		asyw->scale.sw = asyw->state.src_w >> 16;
+		asyw->scale.sh = asyw->state.src_h >> 16;
+		asyw->scale.dw = asyw->state.crtc_w;
+		asyw->scale.dh = asyw->state.crtc_h;
+		if (memcmp(&armw->scale, &asyw->scale, sizeof(asyw->scale)))
+			asyw->set.scale = true;
+	}
+
 	if (wndw->immd) {
 		asyw->point.x = asyw->state.crtc_x;
 		asyw->point.y = asyw->state.crtc_y;
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -70,15 +70,21 @@ struct nv50_wndw_func {
 	void (*xlut_clr)(struct nv50_wndw *);
 	void (*image_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
 	void (*image_clr)(struct nv50_wndw *);
+	void (*scale_set)(struct nv50_wndw *, struct nv50_wndw_atom *);
 
 	void (*update)(struct nv50_wndw *, u32 *interlock);
 };
 
 extern const struct drm_plane_funcs nv50_wndw;
 
+void base507c_ntfy_reset(struct nouveau_bo *, u32);
+int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
+
 struct nv50_wimm_func {
 	void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
 
 	void (*update)(struct nv50_wndw *, u32 *interlock);
 };
+
+extern const struct nv50_wimm_func curs507a;
 #endif