[PATCH v2 20/22 EXPERIMENTAL] drm: Use vga_switcheroo active client as proxy when reading DDC/AUX

Lukas Wunner lukas at wunner.de
Wed Aug 12 04:33:33 PDT 2015


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.

When reading the DPCD or EDID, store the struct drm_dp_aux and struct
i2c_adapter (for DDC) in vga_switcheroo. Retrieve the active client's
structures and use them in lieu of the client's own structures.

To avoid using proxying with external DP-connected displays, this is
constrained to eDP connectors and further constrained by vga_switcheroo
to its clients.

Based (loosely) on patches by Matthew Garrett <mjg59 at srcf.ucam.org>
who used stashing instead of proxying and changed each driver rather
than the generic helper functions:
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0025-i915-Use-vga_switcheroo-to-obtain-and-stash-EDID-DPC.patch
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0026-nouveau-Use-vga_switcheroo-to-obtain-and-stash-EDID-.patch

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 at gmail.com>
    [MBP  6,2 2010  intel ILK + nvidia GT216  pre-retina]
Tested-by: William Brown <william at blackhats.net.au>
    [MBP  8,2 2011  intel SNB + amd turks     pre-retina]
Tested-by: Lukas Wunner <lukas at wunner.de>
    [MBP  9,1 2012  intel IVB + nvidia GK107  pre-retina]
Tested-by: Bruno Bierbaumer <bruno at bierbaumer.net>
    [MBP 11,3 2013  intel HSW + nvidia GK107  retina -- work in progress]

Signed-off-by: Lukas Wunner <lukas at wunner.de>
---
 drivers/gpu/drm/drm_dp_helper.c | 14 ++++++++++++++
 drivers/gpu/drm/drm_edid.c      | 12 ++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 80a02a4..f34622f 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -27,6 +27,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/i2c.h>
+#include <linux/vga_switcheroo.h>
 #include <drm/drm_dp_helper.h>
 #include <drm/drmP.h>
 
@@ -239,6 +240,19 @@ static int drm_dp_dpcd_access(struct drm_dp_aux *aux, u8 request,
 ssize_t drm_dp_dpcd_read(struct drm_dp_aux *aux, unsigned int offset,
 			 void *buffer, size_t size)
 {
+	struct pci_dev *pdev = to_pci_dev(aux->dev);
+	struct drm_dp_aux *proxy_aux;
+
+	if (aux->connector &&
+	    aux->connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		vga_switcheroo_set_aux(pdev, aux);
+		proxy_aux = vga_switcheroo_get_aux(pdev);
+		if (proxy_aux && proxy_aux != aux) {
+			DRM_DEBUG_KMS("Using vga_switcheroo active client as proxy\n");
+			aux = proxy_aux;
+		}
+	}
+
 	return drm_dp_dpcd_access(aux, DP_AUX_NATIVE_READ, offset, buffer,
 				  size);
 }
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index cdb2fa1..b4b0e01 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -1379,6 +1379,18 @@ struct edid *drm_get_edid(struct drm_connector *connector,
 {
 	struct edid *edid;
 	struct pci_dev *pdev = connector->dev->pdev;
+	struct i2c_adapter *proxy_ddc;
+
+	if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS ||
+	    connector->connector_type == DRM_MODE_CONNECTOR_eDP) {
+		vga_switcheroo_set_ddc(pdev, adapter);
+		proxy_ddc = vga_switcheroo_get_ddc(pdev);
+		if (proxy_ddc && proxy_ddc != adapter) {
+			DRM_DEBUG_KMS("Using vga_switcheroo active client as proxy\n");
+			adapter = proxy_ddc;
+			pdev = to_pci_dev(proxy_ddc->dev.parent);
+		}
+	}
 
 	vga_switcheroo_lock_ddc(pdev);
 
-- 
1.8.5.2 (Apple Git-48)



More information about the dri-devel mailing list