Blob Blame History Raw
From 9648da5a71c25e17d14feb0d7dc9ee73319e8a24 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/dp: determine link bandwidth requirements from head state
Git-commit: 9648da5a71c25e17d14feb0d7dc9ee73319e8a24
Patch-mainline: v4.13-rc1
References: bsc#1095094

Training/Untraining will be hooked up to the routing logic, which
doesn't allow us to pass in a data rate.

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

---
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c        |   14 ++++++++-
 drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h      |    6 ++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c |   13 +++++++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c  |    1 
 drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h       |    2 +
 drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c  |   27 +++++++++++++++++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c    |    1 
 7 files changed, 62 insertions(+), 2 deletions(-)

--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -23,6 +23,7 @@
  */
 #include "dp.h"
 #include "conn.h"
+#include "head.h"
 #include "ior.h"
 
 #include <subdev/bios.h>
@@ -419,19 +420,28 @@ nvkm_dp_train(struct nvkm_dp *dp, u32 da
 }
 
 int
-nvkm_output_dp_train(struct nvkm_outp *outp, u32 datakbps)
+nvkm_output_dp_train(struct nvkm_outp *outp, u32 unused)
 {
 	struct nvkm_dp *dp = nvkm_dp(outp);
 	struct nvkm_ior *ior = dp->outp.ior;
+	struct nvkm_head *head;
 	bool retrain = true;
-	u32 linkKBps;
+	u32 datakbps = 0;
 	u32 dataKBps;
+	u32 linkKBps;
 	u8  stat[3];
 	int ret, i;
 
 	mutex_lock(&dp->mutex);
 
 	/* Check that link configuration meets current requirements. */
+	list_for_each_entry(head, &outp->disp->head, head) {
+		if (ior->asy.head & (1 << head->id)) {
+			u32 khz = (head->asy.hz >> ior->asy.rgdiv) / 1000;
+			datakbps += khz * head->asy.or.depth;
+		}
+	}
+
 	linkKBps = ior->dp.bw * 27000 * ior->dp.nr;
 	dataKBps = DIV_ROUND_UP(datakbps, 8);
 	OUTP_DBG(&dp->outp, "data %d KB/s link %d KB/s mst %d->%d",
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/head.h
@@ -18,6 +18,12 @@ struct nvkm_head {
 		u16 vsynce;
 		u16 vblanke;
 		u16 vblanks;
+		u32 hz;
+
+		/* Prior to GF119, these are set by the OR. */
+		struct {
+			u8 depth;
+		} or;
 	} arm, asy;
 };
 
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headgf119.c
@@ -58,6 +58,19 @@ gf119_head_state(struct nvkm_head *head,
 	data = nvkm_rd32(device, 0x640420 + hoff);
 	state->vblanks = (data & 0xffff0000) >> 16;
 	state->hblanks = (data & 0x0000ffff);
+	state->hz = nvkm_rd32(device, 0x640450 + hoff);
+
+	data = nvkm_rd32(device, 0x640404 + hoff);
+	switch ((data & 0x000003c0) >> 6) {
+	case 6: state->or.depth = 30; break;
+	case 5: state->or.depth = 24; break;
+	case 2: state->or.depth = 18; break;
+	case 0: state->or.depth = 18; break; /*XXX: "default" */
+	default:
+		state->or.depth = 18;
+		WARN_ON(1);
+		break;
+	}
 }
 
 static const struct nvkm_head_func
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/headnv50.c
@@ -66,6 +66,7 @@ nv50_head_state(struct nvkm_head *head,
 	data = nvkm_rd32(device, 0x610b00 + hoff);
 	state->vsynce = (data & 0xffff0000) >> 16;
 	state->hsynce = (data & 0x0000ffff);
+	state->hz = (nvkm_rd32(device, 0x610ad0 + hoff) & 0x003fffff) * 1000;
 }
 
 static const struct nvkm_head_func
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -89,6 +89,8 @@ nv50_ior_base(struct nvkm_ior *ior)
 void nv50_dac_power(struct nvkm_ior *, bool, bool, bool, bool, bool);
 int nv50_dac_sense(struct nvkm_ior *, u32);
 
+void nv50_pior_depth(struct nvkm_ior *, struct nvkm_ior_state *, u32 ctrl);
+
 static inline u32
 nv50_sor_link(struct nvkm_ior *ior)
 {
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -22,6 +22,7 @@
  * Authors: Ben Skeggs
  */
 #include "ior.h"
+#include "head.h"
 
 #include <subdev/i2c.h>
 #include <subdev/timer.h>
@@ -60,6 +61,31 @@ nv50_pior_power(struct nvkm_ior *pior, b
 	nv50_pior_power_wait(device, poff);
 }
 
+void
+nv50_pior_depth(struct nvkm_ior *ior, struct nvkm_ior_state *state, u32 ctrl)
+{
+	/* GF119 moves this information to per-head methods, which is
+	 * a lot more convenient, and where our shared code expect it.
+	 */
+	if (state->head && state == &ior->asy) {
+		struct nvkm_head *head =
+			nvkm_head_find(ior->disp, __ffs(state->head));
+		if (!WARN_ON(!head)) {
+			struct nvkm_head_state *state = &head->asy;
+			switch ((ctrl & 0x000f0000) >> 16) {
+			case 6: state->or.depth = 30; break;
+			case 5: state->or.depth = 24; break;
+			case 2: state->or.depth = 18; break;
+			case 0: state->or.depth = 18; break; /*XXX*/
+			default:
+				state->or.depth = 18;
+				WARN_ON(1);
+				break;
+			}
+		}
+	}
+}
+
 static void
 nv50_pior_state(struct nvkm_ior *pior, struct nvkm_ior_state *state)
 {
@@ -77,6 +103,7 @@ nv50_pior_state(struct nvkm_ior *pior, s
 	}
 
 	state->head = ctrl & 0x00000003;
+	nv50_pior_depth(pior, state, ctrl);
 }
 
 static const struct nvkm_ior_func
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -238,6 +238,7 @@ g94_sor_state(struct nvkm_ior *sor, stru
 	}
 
 	state->head = ctrl & 0x00000003;
+	nv50_pior_depth(sor, state, ctrl);
 }
 
 static const struct nvkm_ior_func