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

Instead of windows returning their core channel interlock mask if they
know core has been modified, it's recorded unconditionally and used if
required when update methods are emitted.

This will be required to support Volta.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Acked-by: Petr Tesarik <ptesarik@suse.com>
---
 drivers/gpu/drm/nouveau/dispnv50/Kbuild     |    3 +
 drivers/gpu/drm/nouveau/dispnv50/base.h     |    4 +-
 drivers/gpu/drm/nouveau/dispnv50/base507c.c |   16 +++++-----
 drivers/gpu/drm/nouveau/dispnv50/base827c.c |    3 +
 drivers/gpu/drm/nouveau/dispnv50/base907c.c |   18 +----------
 drivers/gpu/drm/nouveau/dispnv50/core.h     |    5 +--
 drivers/gpu/drm/nouveau/dispnv50/core507d.c |    5 +--
 drivers/gpu/drm/nouveau/dispnv50/curs.c     |    4 +-
 drivers/gpu/drm/nouveau/dispnv50/curs.h     |    6 +++
 drivers/gpu/drm/nouveau/dispnv50/curs507a.c |   18 ++++++-----
 drivers/gpu/drm/nouveau/dispnv50/curs907a.c |   30 +++++++++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/disp.c     |   42 ++++++++++++---------------
 drivers/gpu/drm/nouveau/dispnv50/disp.h     |   11 +++++++
 drivers/gpu/drm/nouveau/dispnv50/ovly.c     |   10 +++---
 drivers/gpu/drm/nouveau/dispnv50/ovly.h     |    8 +++++
 drivers/gpu/drm/nouveau/dispnv50/ovly507e.c |   11 ++++---
 drivers/gpu/drm/nouveau/dispnv50/ovly827e.c |   43 ++++++++++++++++++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/ovly907e.c |   34 ++++++++++++++++++++++
 drivers/gpu/drm/nouveau/dispnv50/wndw.c     |   23 ++++++++++----
 drivers/gpu/drm/nouveau/dispnv50/wndw.h     |   16 +++++-----
 20 files changed, 224 insertions(+), 86 deletions(-)

--- a/drivers/gpu/drm/nouveau/dispnv50/Kbuild
+++ b/drivers/gpu/drm/nouveau/dispnv50/Kbuild
@@ -29,9 +29,12 @@ nouveau-y += dispnv50/base907c.o
 
 nouveau-y += dispnv50/curs.o
 nouveau-y += dispnv50/curs507a.o
+nouveau-y += dispnv50/curs907a.o
 
 nouveau-y += dispnv50/oimm.o
 nouveau-y += dispnv50/oimm507b.o
 
 nouveau-y += dispnv50/ovly.o
 nouveau-y += dispnv50/ovly507e.o
+nouveau-y += dispnv50/ovly827e.o
+nouveau-y += dispnv50/ovly907e.o
--- a/drivers/gpu/drm/nouveau/dispnv50/base.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/base.h
@@ -5,7 +5,7 @@
 int base507c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 int base507c_new_(const struct nv50_wndw_func *, const u32 *format,
 		  struct nouveau_drm *, int head, s32 oclass,
-		  struct nv50_wndw **);
+		  u32 interlock_data, struct nv50_wndw **);
 extern const u32 base507c_format[];
 int base507c_acquire(struct nv50_wndw *, struct nv50_wndw_atom *,
 		     struct nv50_head_atom *);
@@ -19,7 +19,7 @@ void base507c_ntfy_clr(struct nv50_wndw
 int base507c_ntfy_wait_begun(struct nouveau_bo *, u32, struct nvif_device *);
 void base507c_image_clr(struct nv50_wndw *);
 void base507c_lut(struct nv50_wndw *, struct nv50_wndw_atom *);
-u32 base507c_update(struct nv50_wndw *, u32);
+void base507c_update(struct nv50_wndw *, u32 *);
 
 int base827c_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 
--- a/drivers/gpu/drm/nouveau/dispnv50/base507c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base507c.c
@@ -28,17 +28,15 @@
 #include <drm/drm_plane_helper.h>
 #include "nouveau_bo.h"
 
-u32
-base507c_update(struct nv50_wndw *wndw, u32 interlock)
+void
+base507c_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);
+		evo_data(push, interlock[NV50_DISP_INTERLOCK_CORE]);
 		evo_kick(push, &wndw->wndw);
-		return interlock ? 2 << (wndw->id * 8) : 0;
 	}
-	return 0;
 }
 
 void
@@ -224,7 +222,7 @@ base507c = {
 
 int
 base507c_new_(const struct nv50_wndw_func *func, const u32 *format,
-	      struct nouveau_drm *drm, int head, s32 oclass,
+	      struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
 	      struct nv50_wndw **pwndw)
 {
 	struct nv50_disp_base_channel_dma_v0 args = {
@@ -235,7 +233,8 @@ base507c_new_(const struct nv50_wndw_fun
 	int ret;
 
 	ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_PRIMARY,
-			     "base", head, format, BIT(head), &wndw);
+			     "base", head, format, BIT(head),
+			     NV50_DISP_INTERLOCK_BASE, interlock_data, &wndw);
 	if (*pwndw = wndw, ret)
 		return ret;
 
@@ -266,5 +265,6 @@ int
 base507c_new(struct nouveau_drm *drm, int head, s32 oclass,
 	     struct nv50_wndw **pwndw)
 {
-	return base507c_new_(&base507c, base507c_format, drm, head, oclass, pwndw);
+	return base507c_new_(&base507c, base507c_format, drm, head, oclass,
+			     0x00000002 << (head * 8), pwndw);
 }
--- a/drivers/gpu/drm/nouveau/dispnv50/base827c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base827c.c
@@ -63,5 +63,6 @@ int
 base827c_new(struct nouveau_drm *drm, int head, s32 oclass,
 	     struct nv50_wndw **pwndw)
 {
-	return base507c_new_(&base827c, base507c_format, drm, head, oclass, pwndw);
+	return base507c_new_(&base827c, base507c_format, drm, head, oclass,
+			     0x00000002 << (head * 8), pwndw);
 }
--- a/drivers/gpu/drm/nouveau/dispnv50/base907c.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/base907c.c
@@ -21,19 +21,6 @@
  */
 #include "base.h"
 
-static u32
-base907c_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);
-		evo_kick(push, &wndw->wndw);
-		return interlock ? 2 << (wndw->id * 4) : 0;
-	}
-	return 0;
-}
-
 static void
 base907c_image_set(struct nv50_wndw *wndw, struct nv50_wndw_atom *asyw)
 {
@@ -69,12 +56,13 @@ base907c = {
 	.image_set = base907c_image_set,
 	.image_clr = base507c_image_clr,
 	.lut = base507c_lut,
-	.update = base907c_update,
+	.update = base507c_update,
 };
 
 int
 base907c_new(struct nouveau_drm *drm, int head, s32 oclass,
 	     struct nv50_wndw **pwndw)
 {
-	return base507c_new_(&base907c, base507c_format, drm, head, oclass, pwndw);
+	return base507c_new_(&base907c, base507c_format, drm, head, oclass,
+			     0x00000002 << (head * 4), pwndw);
 }
--- a/drivers/gpu/drm/nouveau/dispnv50/core.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/core.h
@@ -16,7 +16,7 @@ struct nv50_core_func {
 	void (*ntfy_init)(struct nouveau_bo *, u32 offset);
 	int (*ntfy_wait_done)(struct nouveau_bo *, u32 offset,
 			      struct nvif_device *);
-	void (*update)(struct nv50_core *, u32 interlock, bool ntfy);
+	void (*update)(struct nv50_core *, u32 *interlock, bool ntfy);
 
 	const struct nv50_head_func *head;
 	const struct nv50_outp_func {
@@ -31,7 +31,8 @@ int core507d_new_(const struct nv50_core
 void core507d_init(struct nv50_core *);
 void core507d_ntfy_init(struct nouveau_bo *, u32);
 int core507d_ntfy_wait_done(struct nouveau_bo *, u32, struct nvif_device *);
-void core507d_update(struct nv50_core *, u32, bool);
+void core507d_update(struct nv50_core *, u32 *, bool);
+
 extern const struct nv50_outp_func dac507d;
 extern const struct nv50_outp_func sor507d;
 extern const struct nv50_outp_func pior507d;
--- a/drivers/gpu/drm/nouveau/dispnv50/core507d.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/core507d.c
@@ -27,7 +27,7 @@
 #include "nouveau_bo.h"
 
 void
-core507d_update(struct nv50_core *core, u32 interlock, bool ntfy)
+core507d_update(struct nv50_core *core, u32 *interlock, bool ntfy)
 {
 	u32 *push;
 	if ((push = evo_wait(&core->chan, 5))) {
@@ -36,7 +36,8 @@ core507d_update(struct nv50_core *core,
 			evo_data(push, 0x80000000 | NV50_DISP_CORE_NTFY);
 		}
 		evo_mthd(push, 0x0080, 2);
-		evo_data(push, interlock);
+		evo_data(push, interlock[NV50_DISP_INTERLOCK_BASE] |
+			       interlock[NV50_DISP_INTERLOCK_OVLY]);
 		evo_data(push, 0x00000000);
 		evo_kick(push, &core->chan);
 	}
--- a/drivers/gpu/drm/nouveau/dispnv50/curs.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs.c
@@ -31,8 +31,8 @@ nv50_curs_new(struct nouveau_drm *drm, i
 		int version;
 		int (*new)(struct nouveau_drm *, int, s32, struct nv50_wndw **);
 	} curses[] = {
-		{ GK104_DISP_CURSOR, 0, curs507a_new },
-		{ GF110_DISP_CURSOR, 0, curs507a_new },
+		{ GK104_DISP_CURSOR, 0, curs907a_new },
+		{ GF110_DISP_CURSOR, 0, curs907a_new },
 		{ GT214_DISP_CURSOR, 0, curs507a_new },
 		{   G82_DISP_CURSOR, 0, curs507a_new },
 		{  NV50_DISP_CURSOR, 0, curs507a_new },
--- a/drivers/gpu/drm/nouveau/dispnv50/curs.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs.h
@@ -3,6 +3,12 @@
 #include "wndw.h"
 
 int curs507a_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
+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 **);
 
 int nv50_curs_new(struct nouveau_drm *, int head, struct nv50_wndw **);
 #endif
--- a/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs507a.c
@@ -27,11 +27,10 @@
 #include <drm/drm_atomic_helper.h>
 #include <drm/drm_plane_helper.h>
 
-static u32
-curs507a_update(struct nv50_wndw *wndw, u32 interlock)
+static void
+curs507a_update(struct nv50_wndw *wndw, u32 *interlock)
 {
 	nvif_wr32(&wndw->wimm.base.user, 0x0080, 0x00000000);
-	return 0;
 }
 
 static void
@@ -41,7 +40,7 @@ curs507a_point(struct nv50_wndw *wndw, s
 						 asyw->point.x);
 }
 
-static const struct nv50_wimm_func
+const struct nv50_wimm_func
 curs507a = {
 	.point = curs507a_point,
 	.update = curs507a_update,
@@ -114,9 +113,10 @@ curs507a_wndw = {
 	.prepare = curs507a_prepare,
 };
 
-static int
+int
 curs507a_new_(const struct nv50_wimm_func *func, struct nouveau_drm *drm,
-	      int head, s32 oclass, struct nv50_wndw **pwndw)
+	      int head, s32 oclass, u32 interlock_data,
+	      struct nv50_wndw **pwndw)
 {
 	struct nv50_disp_cursor_v0 args = {
 		.head = head,
@@ -126,7 +126,8 @@ curs507a_new_(const struct nv50_wimm_fun
 	int ret;
 
 	ret = nv50_wndw_new_(&curs507a_wndw, drm->dev, DRM_PLANE_TYPE_CURSOR,
-			     "curs", head, curs507a_format, BIT(head), &wndw);
+			     "curs", head, curs507a_format, BIT(head),
+			     NV50_DISP_INTERLOCK_CURS, interlock_data, &wndw);
 	if (*pwndw = wndw, ret)
 		return ret;
 
@@ -147,5 +148,6 @@ int
 curs507a_new(struct nouveau_drm *drm, int head, s32 oclass,
 	     struct nv50_wndw **pwndw)
 {
-	return curs507a_new_(&curs507a, drm, head, oclass, pwndw);
+	return curs507a_new_(&curs507a, drm, head, oclass,
+			     0x00000001 << (head * 8), pwndw);
 }
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/dispnv50/curs907a.c
@@ -0,0 +1,30 @@
+/*
+ * 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 "curs.h"
+
+int
+curs907a_new(struct nouveau_drm *drm, int head, s32 oclass,
+	     struct nv50_wndw **pwndw)
+{
+	return curs507a_new_(&curs507a, drm, head, oclass,
+			     0x00000001 << (head * 4), pwndw);
+}
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.c
@@ -1582,14 +1582,14 @@ nv50_pior_create(struct drm_connector *c
  *****************************************************************************/
 
 static void
-nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 interlock)
+nv50_disp_atomic_commit_core(struct nouveau_drm *drm, u32 *interlock)
 {
 	struct nv50_disp *disp = nv50_disp(drm->dev);
 	struct nv50_core *core = disp->core;
 	struct nv50_mstm *mstm;
 	struct drm_encoder *encoder;
 
-	NV_ATOMIC(drm, "commit core %08x\n", interlock);
+	NV_ATOMIC(drm, "commit core %08x\n", interlock[NV50_DISP_INTERLOCK_BASE]);
 
 	drm_for_each_encoder(encoder, drm->dev) {
 		if (encoder->encoder_type != DRM_MODE_ENCODER_DPMST) {
@@ -1626,8 +1626,7 @@ nv50_disp_atomic_commit_tail(struct drm_
 	struct nv50_disp *disp = nv50_disp(dev);
 	struct nv50_atom *atom = nv50_atom(state);
 	struct nv50_outp_atom *outp, *outt;
-	u32 interlock_core = 0;
-	u32 interlock_chan = 0;
+	u32 interlock[NV50_DISP_INTERLOCK__SIZE] = {};
 	int i;
 
 	NV_ATOMIC(drm, "commit %d %d\n", atom->lock_core, atom->flush_disable);
@@ -1650,7 +1649,7 @@ nv50_disp_atomic_commit_tail(struct drm_
 
 		if (asyh->clr.mask) {
 			nv50_head_flush_clr(head, asyh, atom->flush_disable);
-			interlock_core |= 1;
+			interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
 		}
 	}
 
@@ -1664,9 +1663,7 @@ nv50_disp_atomic_commit_tail(struct drm_
 		if (!asyw->clr.mask)
 			continue;
 
-		interlock_chan |= nv50_wndw_flush_clr(wndw, interlock_core,
-						      atom->flush_disable,
-						      asyw);
+		nv50_wndw_flush_clr(wndw, interlock, atom->flush_disable, asyw);
 	}
 
 	/* Disable output path(s). */
@@ -1682,21 +1679,19 @@ nv50_disp_atomic_commit_tail(struct drm_
 
 		if (outp->clr.mask) {
 			help->disable(encoder);
-			interlock_core |= 1;
+			interlock[NV50_DISP_INTERLOCK_CORE] |= 1;
 			if (outp->flush_disable) {
-				nv50_disp_atomic_commit_core(drm, interlock_chan);
-				interlock_core = 0;
-				interlock_chan = 0;
+				nv50_disp_atomic_commit_core(drm, interlock);
+				memset(interlock, 0x00, sizeof(interlock));
 			}
 		}
 	}
 
 	/* Flush disable. */
-	if (interlock_core) {
+	if (interlock[NV50_DISP_INTERLOCK_CORE]) {
 		if (atom->flush_disable) {
-			nv50_disp_atomic_commit_core(drm, interlock_chan);
-			interlock_core = 0;
-			interlock_chan = 0;
+			nv50_disp_atomic_commit_core(drm, interlock);
+			memset(interlock, 0x00, sizeof(interlock));
 		}
 	}
 
@@ -1713,7 +1708,7 @@ nv50_disp_atomic_commit_tail(struct drm_
 
 		if (outp->set.mask) {
 			help->enable(encoder);
-			interlock_core = 1;
+			interlock[NV50_DISP_INTERLOCK_CORE] = 1;
 		}
 
 		list_del(&outp->head);
@@ -1730,7 +1725,7 @@ nv50_disp_atomic_commit_tail(struct drm_
 
 		if (asyh->set.mask) {
 			nv50_head_flush_set(head, asyh);
-			interlock_core = 1;
+			interlock[NV50_DISP_INTERLOCK_CORE] = 1;
 		}
 
 		if (new_crtc_state->active) {
@@ -1752,15 +1747,16 @@ nv50_disp_atomic_commit_tail(struct drm_
 		    (!asyw->clr.mask || atom->flush_disable))
 			continue;
 
-		interlock_chan |= nv50_wndw_flush_set(wndw, interlock_core, asyw);
+		nv50_wndw_flush_set(wndw, interlock, asyw);
 	}
 
 	/* Flush update. */
-	if (interlock_core) {
-		if (interlock_chan || !atom->state.legacy_cursor_update)
-			nv50_disp_atomic_commit_core(drm, interlock_chan);
+	if (interlock[NV50_DISP_INTERLOCK_CORE]) {
+		if (interlock[NV50_DISP_INTERLOCK_BASE] ||
+		    !atom->state.legacy_cursor_update)
+			nv50_disp_atomic_commit_core(drm, interlock);
 		else
-			disp->core->func->update(disp->core, 0, false);
+			disp->core->func->update(disp->core, interlock, false);
 	}
 
 	if (atom->lock_core)
--- a/drivers/gpu/drm/nouveau/dispnv50/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/disp.h
@@ -27,6 +27,17 @@ nv50_disp(struct drm_device *dev)
 	return nouveau_display(dev)->priv;
 }
 
+struct nv50_disp_interlock {
+	enum nv50_disp_interlock_type {
+		NV50_DISP_INTERLOCK_CORE = 0,
+		NV50_DISP_INTERLOCK_CURS,
+		NV50_DISP_INTERLOCK_BASE,
+		NV50_DISP_INTERLOCK_OVLY,
+		NV50_DISP_INTERLOCK__SIZE
+	} type;
+	u32 data;
+};
+
 struct nv50_chan {
 	struct nvif_object user;
 	struct nvif_device *device;
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly.c
@@ -32,11 +32,11 @@ 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, ovly507e_new },
-		{ GF110_DISP_OVERLAY_CONTROL_DMA, 0, ovly507e_new },
-		{ GT214_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
-		{ GT200_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
-		{   G82_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
+		{ GK104_DISP_OVERLAY_CONTROL_DMA, 0, ovly907e_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 },
+		{   G82_DISP_OVERLAY_CHANNEL_DMA, 0, ovly827e_new },
 		{  NV50_DISP_OVERLAY_CHANNEL_DMA, 0, ovly507e_new },
 		{}
 	};
--- a/drivers/gpu/drm/nouveau/dispnv50/ovly.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly.h
@@ -3,6 +3,14 @@
 #include "wndw.h"
 
 int ovly507e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
+int ovly507e_new_(const struct nv50_wndw_func *, const u32 *format,
+		  struct nouveau_drm *, int head, s32 oclass,
+		  u32 interlock_data, struct nv50_wndw **);
+
+extern const u32 ovly827e_format[];
+
+int ovly827e_new(struct nouveau_drm *, int, s32, struct nv50_wndw **);
+int ovly907e_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
@@ -34,9 +34,9 @@ ovly507e_format[] = {
 	0
 };
 
-static int
+int
 ovly507e_new_(const struct nv50_wndw_func *func, const u32 *format,
-	      struct nouveau_drm *drm, int head, s32 oclass,
+	      struct nouveau_drm *drm, int head, s32 oclass, u32 interlock_data,
 	      struct nv50_wndw **pwndw)
 {
 	struct nv50_disp_overlay_channel_dma_v0 args = {
@@ -47,7 +47,9 @@ ovly507e_new_(const struct nv50_wndw_fun
 	int ret;
 
 	ret = nv50_wndw_new_(func, drm->dev, DRM_PLANE_TYPE_OVERLAY,
-			     "ovly", head, format, BIT(head), &wndw);
+			     "ovly", head, format, BIT(head),
+			     NV50_DISP_INTERLOCK_OVLY, interlock_data,
+			     &wndw);
 	if (*pwndw = wndw, ret)
 		return ret;
 
@@ -66,5 +68,6 @@ int
 ovly507e_new(struct nouveau_drm *drm, int head, s32 oclass,
 	     struct nv50_wndw **pwndw)
 {
-	return ovly507e_new_(&ovly507e, ovly507e_format, drm, head, oclass, pwndw);
+	return ovly507e_new_(&ovly507e, ovly507e_format, drm, head, oclass,
+			     0x00000004 << (head * 8), pwndw);
 }
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly827e.c
@@ -0,0 +1,43 @@
+/*
+ * 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"
+
+#include <nouveau_bo.h>
+
+#include <nvif/cl507e.h>
+
+static const struct nv50_wndw_func
+ovly827e = {
+};
+
+const u32
+ovly827e_format[] = {
+	0
+};
+
+int
+ovly827e_new(struct nouveau_drm *drm, int head, s32 oclass,
+	     struct nv50_wndw **pwndw)
+{
+	return ovly507e_new_(&ovly827e, ovly827e_format, drm, head, oclass,
+			     0x00000004 << (head * 8), pwndw);
+}
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/dispnv50/ovly907e.c
@@ -0,0 +1,34 @@
+/*
+ * 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 struct nv50_wndw_func
+ovly907e = {
+};
+
+int
+ovly907e_new(struct nouveau_drm *drm, int head, s32 oclass,
+	     struct nv50_wndw **pwndw)
+{
+	return ovly507e_new_(&ovly907e, ovly827e_format, drm, head, oclass,
+			     0x00000004 << (head * 4), pwndw);
+}
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.c
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.c
@@ -107,8 +107,8 @@ nv50_wndw_wait_armed(struct nv50_wndw *w
 	return 0;
 }
 
-u32
-nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 interlock, bool flush,
+void
+nv50_wndw_flush_clr(struct nv50_wndw *wndw, u32 *interlock, bool flush,
 		    struct nv50_wndw_atom *asyw)
 {
 	union nv50_wndw_atom_mask clr = {
@@ -118,11 +118,13 @@ nv50_wndw_flush_clr(struct nv50_wndw *wn
 	if (clr.ntfy ) wndw->func-> ntfy_clr(wndw);
 	if (clr.image) wndw->func->image_clr(wndw);
 
-	return flush ? wndw->func->update(wndw, interlock) : 0;
+	interlock[wndw->interlock.type] |= wndw->interlock.data;
+	if (flush)
+		wndw->func->update(wndw, interlock);
 }
 
-u32
-nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 interlock,
+void
+nv50_wndw_flush_set(struct nv50_wndw *wndw, u32 *interlock,
 		    struct nv50_wndw_atom *asyw)
 {
 	if (interlock) {
@@ -139,7 +141,9 @@ nv50_wndw_flush_set(struct nv50_wndw *wn
 		wndw->immd->update(wndw, interlock);
 	}
 
-	return wndw->func->update ? wndw->func->update(wndw, interlock) : 0;
+	interlock[wndw->interlock.type] |= wndw->interlock.data;
+	if (wndw->func->update)
+		wndw->func->update(wndw, interlock);
 }
 
 void
@@ -445,7 +449,9 @@ nv50_wndw_init(struct nv50_wndw *wndw)
 int
 nv50_wndw_new_(const struct nv50_wndw_func *func, struct drm_device *dev,
 	       enum drm_plane_type type, const char *name, int index,
-	       const u32 *format, u32 heads, struct nv50_wndw **pwndw)
+	       const u32 *format, u32 heads,
+	       enum nv50_disp_interlock_type interlock_type, u32 interlock_data,
+	       struct nv50_wndw **pwndw)
 {
 	struct nv50_wndw *wndw;
 	int nformat;
@@ -455,6 +461,9 @@ nv50_wndw_new_(const struct nv50_wndw_fu
 		return -ENOMEM;
 	wndw->func = func;
 	wndw->id = index;
+	wndw->interlock.type = interlock_type;
+	wndw->interlock.data = interlock_data;
+	wndw->ctxdma.parent = &wndw->wndw.base.user;
 
 	wndw->ctxdma.parent = &wndw->wndw.base.user;
 	INIT_LIST_HEAD(&wndw->ctxdma.list);
--- a/drivers/gpu/drm/nouveau/dispnv50/wndw.h
+++ b/drivers/gpu/drm/nouveau/dispnv50/wndw.h
@@ -15,6 +15,7 @@ struct nv50_wndw {
 	const struct nv50_wndw_func *func;
 	const struct nv50_wimm_func *immd;
 	int id;
+	struct nv50_disp_interlock interlock;
 
 	struct {
 		struct nvif_object *parent;
@@ -34,13 +35,14 @@ struct nv50_wndw {
 
 int nv50_wndw_new_(const struct nv50_wndw_func *, struct drm_device *,
 		   enum drm_plane_type, const char *name, int index,
-		   const u32 *format, u32 heads, struct nv50_wndw **);
+		   const u32 *format, enum nv50_disp_interlock_type,
+		   u32 interlock_data, u32 heads, struct nv50_wndw **);
 void nv50_wndw_init(struct nv50_wndw *);
 void nv50_wndw_fini(struct nv50_wndw *);
-u32 nv50_wndw_flush_set(struct nv50_wndw *, u32 interlock,
-			struct nv50_wndw_atom *);
-u32 nv50_wndw_flush_clr(struct nv50_wndw *, u32 interlock, bool flush,
-			struct nv50_wndw_atom *);
+void nv50_wndw_flush_set(struct nv50_wndw *, u32 *interlock,
+			 struct nv50_wndw_atom *);
+void nv50_wndw_flush_clr(struct nv50_wndw *, u32 *interlock, bool flush,
+			 struct nv50_wndw_atom *);
 void nv50_wndw_ntfy_enable(struct nv50_wndw *, struct nv50_wndw_atom *);
 int nv50_wndw_wait_armed(struct nv50_wndw *, struct nv50_wndw_atom *);
 
@@ -63,7 +65,7 @@ struct nv50_wndw_func {
 	void (*image_clr)(struct nv50_wndw *);
 	void (*lut)(struct nv50_wndw *, struct nv50_wndw_atom *);
 
-	u32 (*update)(struct nv50_wndw *, u32 interlock);
+	void (*update)(struct nv50_wndw *, u32 *interlock);
 };
 
 extern const struct drm_plane_funcs nv50_wndw;
@@ -71,6 +73,6 @@ extern const struct drm_plane_funcs nv50
 struct nv50_wimm_func {
 	void (*point)(struct nv50_wndw *, struct nv50_wndw_atom *);
 
-	u32 (*update)(struct nv50_wndw *, u32 interlock);
+	void (*update)(struct nv50_wndw *, u32 *interlock);
 };
 #endif