All of lore.kernel.org
 help / color / mirror / Atom feed
From: Lukas Wunner <lukas@wunner.de>
To: dri-devel@lists.freedesktop.org
Cc: Andreas Heider <andreas@meetr.de>,
	Paul Hordiienko <pvt.gord@gmail.com>,
	William Brown <william@blackhats.net.au>,
	Bruno Bierbaumer <bruno@bierbaumer.net>,
	Matthew Garrett <mjg59@coreos.com>,
	Dave Airlie <airlied@redhat.com>
Subject: [PATCH v2 21/22 EXPERIMENTAL] drm/nouveau/i2c: Use vga_switcheroo active client as proxy when reading DDC/AUX
Date: Thu, 30 Jul 2015 13:31:20 +0200	[thread overview]
Message-ID: <3f6ade80a735137c732b328e65d6e38d728cdaf6.1439288957.git.lukas@wunner.de> (raw)
In-Reply-To: <e92963887342af48adb1dc962b793daf4ec823cb.1439288957.git.lukas@wunner.de>

The retina MacBook Pro uses an eDP panel and a gmux controller to switch
the panel between its two GPUs. Unfortunately it seems that it cannot
switch the AUX channel separately from the main link.

But we can emulate switching of DDC/AUX in software by using the active
client as a proxy to talk to the panel.

Proxying of the AUX channel is facilitated by way of Thierry Reding's
awesome struct drm_dp_aux abstraction (cf. c197db75ff5c, "drm/dp: Add
AUX channel infrastructure"). However, as regards usage of struct
drm_dp_aux, nouveau is the odd man out: A struct drm_dp_aux is defined
as part of struct nouveau_connector but never used. Instead, the AUX
channel is accessed directly with nv_rdaux() and nv_wraux(), even in
the DRM part of the driver.

To enable proxying in nouveau, inject a pointer to the struct drm_dp_aux
from the DRM part of the driver into the struct nvkm_i2c_port. Modify
nv_rdaux() to try drm_dp_dpcd_read() first. If that fails, fall back to
accessing the AUX channel directly. Enclose in #if IS_ENABLED(CONFIG_DRM
_KMS_HELPER) to keep the NVKM part of the driver portable and free of
DRM symbols.

Obviously this is a bit of a kludge but it seems there's no elegant way
short of factoring all the AUX communication in dport.c / outpdp.c out
and into the DRM part of the driver (plus the AUX initialization in
VBIOS).

When the driver first initializes the output with nvkm_output_dp_init(),
the pointer to the struct drm_dp_aux is not yet injected into the struct
nvkm_i2c_port. Thus, if the panel is not switched to the Nvidia GPU,
the dpcd attribute of struct nvkm_output_dp can't be filled and the link
doesn't get trained. Make up for this by checking the link training
status in nouveau_dp_detect() and calling nvkm_output_dp_detect()
if the link hasn't been trained yet.

Modify link training itself so that it does not fail when writing to
DPCD if the value to be written is identical with what's already
configured in DPCD. (Proxying is currently read only for safety
reasons.)

Bugzilla: https://bugzilla.kernel.org/show_bug.cgi?id=88861
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=61115
Tested-by: Paul Hordiienko <pvt.gord@gmail.com>
    [MBP  6,2 2010  intel ILK + nvidia GT216  pre-retina]
Tested-by: William Brown <william@blackhats.net.au>
    [MBP  8,2 2011  intel SNB + amd turks     pre-retina]
Tested-by: Lukas Wunner <lukas@wunner.de>
    [MBP  9,1 2012  intel IVB + nvidia GK107  pre-retina]
Tested-by: Bruno Bierbaumer <bruno@bierbaumer.net>
    [MBP 11,3 2013  intel HSW + nvidia GK107  retina -- work in progress]

Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h |  1 +
 drivers/gpu/drm/nouveau/nouveau_connector.c       |  4 ++--
 drivers/gpu/drm/nouveau/nouveau_dp.c              | 20 +++++++++++++++++++
 drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c  |  6 +++++-
 drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c |  2 +-
 drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h |  1 +
 drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c     | 24 +++++++++++++++++++++++
 7 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
index a2e3373..9fa95fb 100644
--- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -37,6 +37,7 @@ struct nvkm_i2c_port {
 	struct list_head head;
 	u8  index;
 	int aux;
+	void *drm_dp_aux;
 
 	const struct nvkm_i2c_func *func;
 };
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index 1e5224f..159df7f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -144,8 +144,8 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
 		nv_encoder = nouveau_encoder(encoder);
 
 		if (nv_encoder->dcb->type == DCB_OUTPUT_DP) {
-			int ret = nouveau_dp_detect(nv_encoder);
-			if (ret == 0)
+			nv_encoder->i2c->drm_dp_aux = &nv_connector->aux;
+			if (nouveau_dp_detect(nv_encoder) == 0)
 				break;
 		} else
 		if (nv_encoder->i2c) {
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c3ef30b..317d6b1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -30,6 +30,25 @@
 #include "nouveau_encoder.h"
 #include "nouveau_crtc.h"
 
+#include <engine/disp.h>
+#include <engine/disp/outpdp.h>
+
+static void
+nouveau_dp_check_link_training(struct nouveau_encoder *nv_encoder)
+{
+	struct nvkm_disp *disp = nvkm_disp(nv_encoder->i2c);
+	struct nvkm_output *outp;
+	struct nvkm_output_dp *outpdp;
+
+	list_for_each_entry(outp, &disp->outp, head)
+		if (outp->info.index == nv_encoder->dcb->index)
+			break;
+
+	outpdp = (struct nvkm_output_dp *)outp;
+	if (!atomic_read(&outpdp->lt.done))
+		nvkm_output_dp_detect(outpdp);
+}
+
 static void
 nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch,
 		     u8 *dpcd)
@@ -85,5 +104,6 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
 		     nv_encoder->dp.link_nr, nv_encoder->dp.link_bw);
 
 	nouveau_dp_probe_oui(dev, auxch, dpcd);
+	nouveau_dp_check_link_training(nv_encoder);
 	return 0;
 }
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
index 6834766..5257e4c 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -61,7 +61,7 @@ dp_set_link_config(struct dp_state *dp)
 		.execute = 1,
 	};
 	u32 lnkcmp;
-	u8 sink[2];
+	u8 sink[2], sink_rd[2];
 	int ret;
 
 	DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
@@ -98,6 +98,10 @@ dp_set_link_config(struct dp_state *dp)
 	if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
 		sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
 
+	if (nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink_rd, 2) == 0 &&
+	    memcmp(sink, sink_rd, 2) == 0)
+		return 0;
+
 	return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
 }
 
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
index 0bde0fa..b95373b 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
@@ -122,7 +122,7 @@ nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
 	}
 }
 
-static void
+void
 nvkm_output_dp_detect(struct nvkm_output_dp *outp)
 {
 	struct nvkm_i2c_port *port = outp->base.edid;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
index 70c77ae..0bd4dcb 100644
--- a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
@@ -58,4 +58,5 @@ struct nvkm_output_dp_impl {
 };
 
 int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
+void nvkm_output_dp_detect(struct nvkm_output_dp *);
 #endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
index 1c18860..16ec3cc 100644
--- a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -23,10 +23,34 @@
  */
 #include "priv.h"
 
+#if IS_ENABLED(CONFIG_DRM_KMS_HELPER)
+#include <drm/drm_dp_helper.h>
+#endif
+
+static int
+drm_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+#if IS_ENABLED(CONFIG_DRM_KMS_HELPER)
+	if (port->drm_dp_aux) {
+		nv_debug(port, "Try reading DPCD with KMS helper: addr=0x%x size=%d\n",
+			 addr, size);
+		return !(drm_dp_dpcd_read(port->drm_dp_aux, addr, data, size)
+			 == size);
+	}
+#endif
+	return -ENODEV;
+}
+
 int
 nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
 {
 	struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+	if (drm_rdaux(port, addr, data, size) == 0)
+		return 0;
+
+	nv_debug(port, "Try reading DPCD directly:        addr=0x%x size=%d\n",
+		 addr, size);
 	if (port->func->aux) {
 		int ret = i2c->acquire(port, 0);
 		if (ret == 0) {
-- 
1.8.5.2 (Apple Git-48)

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel

  reply	other threads:[~2015-08-12 11:39 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-08-11 10:29 [PATCH v2 00/22] Enable gpu switching on the MacBook Pro Lukas Wunner
2012-09-07 15:22 ` [PATCH v2 01/22] vga_switcheroo: Add support for switching only the DDC Lukas Wunner
2012-09-07 15:22   ` [PATCH v2 02/22] vga_switcheroo: Add helper function to get the active client Lukas Wunner
2012-09-07 15:22     ` [PATCH v2 03/22] apple-gmux: Add switch_ddc support Lukas Wunner
2012-09-07 15:22       ` [PATCH v2 04/22] drm/edid: Switch DDC when reading the EDID Lukas Wunner
2012-12-22  2:52         ` [PATCH v2 05/22] vga_switcheroo: Lock/unlock DDC lines Lukas Wunner
2015-03-27 11:29           ` [PATCH v2 06/22] vga_switcheroo: Lock/unlock DDC lines harder Lukas Wunner
2015-04-21  8:39             ` [PATCH v2 07/22] Revert "vga_switcheroo: Add helper function to get the active client" Lukas Wunner
2015-08-02  9:06               ` [PATCH v2 08/22] Revert "vga_switcheroo: add reprobe hook for fbcon to recheck connected outputs." Lukas Wunner
2015-05-09 15:20                 ` [PATCH v2 09/22] drm/nouveau: Lock/unlock DDC lines on probe Lukas Wunner
2014-03-05 22:34                   ` [PATCH v2 10/22] apple-gmux: Assign apple_gmux_data before registering Lukas Wunner
2015-04-20 10:08                     ` [PATCH v2 11/22] vga_switcheroo: Generate hotplug event on handler and proxy registration Lukas Wunner
2015-07-15 11:57                       ` [PATCH v2 12/22] drm/i915: Preserve SSC earlier Lukas Wunner
2015-04-19 15:01                         ` [PATCH v2 13/22] drm/i915: Reprobe eDP and LVDS connectors on hotplug event Lukas Wunner
2015-06-30  9:06                           ` [PATCH v2 14/22 RESEND] drm/i915: Fix failure paths around initial fbdev allocation Lukas Wunner
2015-07-04  9:50                             ` [PATCH v2 15/22 RESEND] drm/i915: On fb alloc failure, unref gem object where it gets refed Lukas Wunner
2015-05-25 13:15                               ` [PATCH v2 16/22] drm: Create new fb and replace default 1024x768 fb on hotplug event Lukas Wunner
     [not found]                                 ` <afe73d5a7382f85c9bdbfc46197a52c4278c99c7.1439288957.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2015-07-23 10:59                                   ` [PATCH v2 17/22] drm/nouveau/timer: Fall back to kernel timer if GPU timer read failed Lukas Wunner
2015-07-29 19:23                                     ` [PATCH v2 18/22 EXPERIMENTAL] vga_switcheroo: Allow using active client as proxy when reading DDC/AUX Lukas Wunner
2015-05-13 19:50                                       ` [PATCH v2 19/22 EXPERIMENTAL] drm: Amend struct drm_dp_aux with connector attribute Lukas Wunner
2015-05-06 12:06                                         ` [PATCH v2 20/22 EXPERIMENTAL] drm: Use vga_switcheroo active client as proxy when reading DDC/AUX Lukas Wunner
2015-07-30 11:31                                           ` Lukas Wunner [this message]
2015-06-07  9:20                                             ` [PATCH v2 22/22 EXPERIMENTAL] drm/nouveau: Use vga_switcheroo active client as proxy when probing DDC on LVDS Lukas Wunner
2015-08-31 20:23                         ` [PATCH v2 12/22] drm/i915: Preserve SSC earlier Jesse Barnes
2015-09-01  6:46                           ` Jani Nikula
2015-08-12 14:25               ` [PATCH v2 07/22] Revert "vga_switcheroo: Add helper function to get the active client" Daniel Vetter
2015-08-12 17:34                 ` Lukas Wunner
2015-08-12 21:10                   ` Daniel Vetter
2015-08-12 14:23             ` [PATCH v2 06/22] vga_switcheroo: Lock/unlock DDC lines harder Daniel Vetter
     [not found] ` <cover.1439288957.git.lukas-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2015-08-12 14:16   ` [Intel-gfx] [PATCH v2 00/22] Enable gpu switching on the MacBook Pro Daniel Vetter
2015-08-12 23:37     ` Lukas Wunner
     [not found]       ` <20150812233711.GA6002-JFq808J9C/izQB+pC5nmwQ@public.gmane.org>
2015-08-13  6:50         ` [Intel-gfx] " Daniel Vetter
2015-08-16 19:10           ` Lukas Wunner
2015-08-25  7:36 ` Lukas Wunner
2015-08-25  8:21   ` Daniel Vetter
2015-08-26 14:01     ` Lukas Wunner
2015-08-29 14:15 ` Lukas Wunner
2015-08-31 19:15   ` Jani Nikula
2015-09-01  6:48     ` Jani Nikula
2015-09-04 14:00     ` Lukas Wunner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=3f6ade80a735137c732b328e65d6e38d728cdaf6.1439288957.git.lukas@wunner.de \
    --to=lukas@wunner.de \
    --cc=airlied@redhat.com \
    --cc=andreas@meetr.de \
    --cc=bruno@bierbaumer.net \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=mjg59@coreos.com \
    --cc=pvt.gord@gmail.com \
    --cc=william@blackhats.net.au \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.