Blob Blame History Raw
From 01a976376b6e57838f223dd2d2639597efd92db4 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: identity-map display paths to output resources
Git-commit: 01a976376b6e57838f223dd2d2639597efd92db4
Patch-mainline: v4.13-rc1
References: bsc#1095094

This essentially replicates our current behaviour in a way that's
compatible with the new model that's emerging, so that we're able
to start porting the hw-specific functions to it.

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

---
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c   |    5 +
 drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h  |   10 +++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c |   74 ++++++++++++++++++++++--
 drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h |    8 +-
 4 files changed, 89 insertions(+), 8 deletions(-)

--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dp.c
@@ -562,7 +562,10 @@ nvkm_dp_ctor(struct nvkm_disp *disp, int
 	u32 data;
 	int ret;
 
-	nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
+	ret = nvkm_outp_ctor(&nvkm_dp_func, disp, index, dcbE, &dp->outp);
+	if (ret)
+		return ret;
+
 	dp->aux = aux;
 	if (!dp->aux) {
 		OUTP_ERR(&dp->outp, "no aux");
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/ior.h
@@ -14,6 +14,16 @@ struct nvkm_ior {
 	char name[8];
 
 	struct list_head head;
+
+	struct nvkm_ior_state {
+		enum nvkm_ior_proto {
+			CRT,
+			TMDS,
+			LVDS,
+			DP,
+			UNKNOWN
+		} proto:3;
+	} arm, asy;
 };
 
 struct nvkm_ior_func {
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -22,11 +22,41 @@
  * Authors: Ben Skeggs
  */
 #include "outp.h"
+#include "ior.h"
 
 #include <subdev/bios.h>
 #include <subdev/bios/dcb.h>
 #include <subdev/i2c.h>
 
+static enum nvkm_ior_proto
+nvkm_outp_xlat(struct nvkm_output *outp, enum nvkm_ior_type *type)
+{
+	switch (outp->info.location) {
+	case 0:
+		switch (outp->info.type) {
+		case DCB_OUTPUT_ANALOG: *type = DAC; return  CRT;
+		case DCB_OUTPUT_TMDS  : *type = SOR; return TMDS;
+		case DCB_OUTPUT_LVDS  : *type = SOR; return LVDS;
+		case DCB_OUTPUT_DP    : *type = SOR; return   DP;
+		default:
+			break;
+		}
+		break;
+	case 1:
+		switch (outp->info.type) {
+		case DCB_OUTPUT_TMDS: *type = PIOR; return TMDS;
+		case DCB_OUTPUT_DP  : *type = PIOR; return TMDS; /* not a bug */
+		default:
+			break;
+		}
+		break;
+	default:
+		break;
+	}
+	WARN_ON(1);
+	return UNKNOWN;
+}
+
 void
 nvkm_outp_fini(struct nvkm_outp *outp)
 {
@@ -34,9 +64,38 @@ nvkm_outp_fini(struct nvkm_outp *outp)
 		outp->func->fini(outp);
 }
 
+static void
+nvkm_outp_init_route(struct nvkm_output *outp)
+{
+	struct nvkm_disp *disp = outp->disp;
+	enum nvkm_ior_proto proto;
+	enum nvkm_ior_type type;
+	struct nvkm_ior *ior;
+	int id;
+
+	proto = nvkm_outp_xlat(outp, &type);
+	if (proto == UNKNOWN)
+		return;
+
+	/* Determine the specific OR, if any, this device is attached to. */
+	if (1) {
+		/* Prior to DCB 4.1, this is hardwired like so. */
+		id = ffs(outp->info.or) - 1;
+	}
+
+	ior = nvkm_ior_find(disp, type, id);
+	if (!ior) {
+		WARN_ON(1);
+		return;
+	}
+
+	outp->ior = ior;
+}
+
 void
 nvkm_outp_init(struct nvkm_outp *outp)
 {
+	nvkm_outp_init_route(outp);
 	if (outp->func->init)
 		outp->func->init(outp);
 }
@@ -53,11 +112,13 @@ nvkm_outp_del(struct nvkm_outp **poutp)
 	}
 }
 
-void
+int
 nvkm_outp_ctor(const struct nvkm_outp_func *func, struct nvkm_disp *disp,
 	       int index, struct dcb_output *dcbE, struct nvkm_outp *outp)
 {
 	struct nvkm_i2c *i2c = disp->engine.subdev.device->i2c;
+	enum nvkm_ior_proto proto;
+	enum nvkm_ior_type type;
 
 	outp->func = func;
 	outp->disp = disp;
@@ -72,6 +133,13 @@ nvkm_outp_ctor(const struct nvkm_outp_fu
 		 outp->info.type >= 2 ? outp->info.sorconf.link : 0,
 		 outp->info.connector, outp->info.i2c_index,
 		 outp->info.bus, outp->info.heads);
+
+	/* Cull output paths we can't map to an output resource. */
+	proto = nvkm_outp_xlat(outp, &type);
+	if (proto == UNKNOWN)
+		return -ENODEV;
+
+	return 0;
 }
 
 int
@@ -81,7 +149,5 @@ nvkm_outp_new_(const struct nvkm_outp_fu
 {
 	if (!(*poutp = kzalloc(sizeof(**poutp), GFP_KERNEL)))
 		return -ENOMEM;
-
-	nvkm_outp_ctor(func, disp, index, dcbE, *poutp);
-	return 0;
+	return nvkm_outp_ctor(func, disp, index, dcbE, *poutp);
 }
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -11,16 +11,18 @@ struct nvkm_outp {
 	int index;
 	struct dcb_output info;
 
-	// whatever (if anything) is pointed at by the dcb device entry
 	struct nvkm_i2c_bus *i2c;
 	int or;
 
 	struct list_head head;
 	struct nvkm_conn *conn;
+
+	/* Assembly state. */
+	struct nvkm_ior *ior;
 };
 
-void nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *,
-		    int index, struct dcb_output *, struct nvkm_outp *);
+int nvkm_outp_ctor(const struct nvkm_outp_func *, struct nvkm_disp *,
+		   int index, struct dcb_output *, struct nvkm_outp *);
 void nvkm_outp_del(struct nvkm_outp **);
 void nvkm_outp_init(struct nvkm_outp *);
 void nvkm_outp_fini(struct nvkm_outp *);