Blob Blame History Raw
From 327c5581d303183e9e56b50238034f419dcca3ce Mon Sep 17 00:00:00 2001
From: Ben Skeggs <bskeggs@redhat.com>
Date: Fri, 19 May 2017 23:59:35 +1000
Subject: [PATCH] drm/nouveau/disp/nv50-: implement a common supervisor 1.0
Git-commit: 327c5581d303183e9e56b50238034f419dcca3ce
Patch-mainline: v4.13-rc1
References: bsc#1095094

This makes use of all the additional routing and state added in previous
commits, making it possible to deal with GM20x macro link routing, while
also sharing code between the NV50 and GF119 implementations.

Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 .../gpu/drm/nouveau/nvkm/engine/disp/gf119.c  |  9 +--
 .../gpu/drm/nouveau/nvkm/engine/disp/nv50.c   | 71 +++++++++++++++++--
 .../gpu/drm/nouveau/nvkm/engine/disp/nv50.h   |  2 +
 3 files changed, 70 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
index 7a8dff7b8c95..e8bfb6ee89ae 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf119.c
@@ -176,12 +176,6 @@ exec_clkcmp(struct nv50_disp *disp, int head, int id, u32 pclk, u32 *conf)
 	return outp;
 }
 
-static void
-gf119_disp_intr_unk1_0(struct nv50_disp *disp, int head)
-{
-	exec_script(disp, head, 1);
-}
-
 static void
 gf119_disp_intr_unk2_0(struct nv50_disp *disp, int head)
 {
@@ -363,8 +357,7 @@ gf119_disp_super(struct work_struct *work)
 		list_for_each_entry(head, &disp->base.head, head) {
 			if (!(mask[head->id] & 0x00001000))
 				continue;
-			nvkm_debug(subdev, "supervisor 1.0 - head %d\n", head->id);
-			gf119_disp_intr_unk1_0(disp, head->id);
+			nv50_disp_super_1_0(disp, head);
 		}
 	} else
 	if (disp->super & 0x00000002) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
index c018dbdb121d..96d281568765 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -114,6 +114,60 @@ nv50_disp_new_(const struct nv50_disp_func *func, struct nvkm_device *device,
 	return nvkm_event_init(func->uevent, 1, 1 + (heads * 4), &disp->uevent);
 }
 
+static u32
+nv50_disp_super_iedt(struct nvkm_head *head, struct nvkm_outp *outp,
+		     u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+		     struct nvbios_outp *iedt)
+{
+	struct nvkm_bios *bios = head->disp->engine.subdev.device->bios;
+	const u8  l = ffs(outp->info.link);
+	const u16 t = outp->info.hasht;
+	const u16 m = (0x0100 << head->id) | (l << 6) | outp->info.or;
+	u32 data = nvbios_outp_match(bios, t, m, ver, hdr, cnt, len, iedt);
+	if (!data)
+		OUTP_DBG(outp, "missing IEDT for %04x:%04x", t, m);
+	return data;
+}
+
+static void
+nv50_disp_super_ied_off(struct nvkm_head *head, struct nvkm_ior *ior, int id)
+{
+	struct nvkm_outp *outp = ior->arm.outp;
+	struct nvbios_outp iedt;
+	u8  ver, hdr, cnt, len;
+	u32 data;
+
+	if (!outp) {
+		IOR_DBG(ior, "nothing attached");
+		return;
+	}
+
+	data = nv50_disp_super_iedt(head, outp, &ver, &hdr, &cnt, &len, &iedt);
+	if (!data)
+		return;
+
+	nvbios_init(&head->disp->engine.subdev, iedt.script[id],
+		init.outp = &outp->info;
+		init.or   = ior->id;
+		init.link = ior->arm.link;
+		init.head = head->id;
+	);
+}
+
+static struct nvkm_ior *
+nv50_disp_super_ior_arm(struct nvkm_head *head)
+{
+	struct nvkm_ior *ior;
+	list_for_each_entry(ior, &head->disp->ior, head) {
+		if (ior->arm.head & (1 << head->id)) {
+			HEAD_DBG(head, "on %s", ior->name);
+			return ior;
+		}
+	}
+	HEAD_DBG(head, "nothing attached");
+	return NULL;
+}
+
 static struct nvkm_output *
 exec_lookup(struct nv50_disp *disp, int head, int or, u32 ctrl,
 	    u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
@@ -582,10 +636,19 @@ nv50_disp_intr_unk20_0(struct nv50_disp *disp, int head)
 	}
 }
 
-static void
-nv50_disp_intr_unk10_0(struct nv50_disp *disp, int head)
+void
+nv50_disp_super_1_0(struct nv50_disp *disp, struct nvkm_head *head)
 {
-	exec_script(disp, head, 1);
+	struct nvkm_ior *ior;
+
+	/* Determine which OR, if any, we're detaching from the head. */
+	HEAD_DBG(head, "supervisor 1.0");
+	ior = nv50_disp_super_ior_arm(head);
+	if (!ior)
+		return;
+
+	/* Execute OffInt1 IED script. */
+	nv50_disp_super_ied_off(head, ior, 1);
 }
 
 void
@@ -625,7 +688,7 @@ nv50_disp_super(struct work_struct *work)
 				continue;
 			if (!(super & (0x00000080 << head->id)))
 				continue;
-			nv50_disp_intr_unk10_0(disp, head->id);
+			nv50_disp_super_1_0(disp, head);
 		}
 	} else
 	if (disp->super & 0x00000020) {
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
index 65d445687038..921ed0fa87f3 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -3,6 +3,7 @@
 #define nv50_disp(p) container_of((p), struct nv50_disp, base)
 #include "priv.h"
 #include "dp.h"
+struct nvkm_head;
 
 struct nv50_disp {
 	const struct nv50_disp_func *func;
@@ -26,6 +27,7 @@ struct nv50_disp {
 };
 
 void nv50_disp_super_1(struct nv50_disp *);
+void nv50_disp_super_1_0(struct nv50_disp *, struct nvkm_head *);
 
 int nv50_disp_new_(const struct nv50_disp_func *, struct nvkm_device *,
 		   int index, int heads, struct nvkm_disp **);
-- 
2.17.0