From patchwork Wed Jul 29 19:23:14 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Lukas Wunner X-Patchwork-Id: 7000691 Return-Path: X-Original-To: patchwork-dri-devel@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 64D28C05AC for ; Wed, 12 Aug 2015 11:39:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 0A4B7206CE for ; Wed, 12 Aug 2015 11:39:58 +0000 (UTC) Received: from gabe.freedesktop.org (gabe.freedesktop.org [131.252.210.177]) by mail.kernel.org (Postfix) with ESMTP id DFF5C20678 for ; Wed, 12 Aug 2015 11:39:56 +0000 (UTC) Received: from gabe.freedesktop.org (localhost [127.0.0.1]) by gabe.freedesktop.org (Postfix) with ESMTP id 06EF06EB27; Wed, 12 Aug 2015 04:39:53 -0700 (PDT) X-Original-To: dri-devel@lists.freedesktop.org Delivered-To: dri-devel@lists.freedesktop.org Received: from mailout2.hostsharing.net (mailout2.hostsharing.net [83.223.90.233]) by gabe.freedesktop.org (Postfix) with ESMTPS id EEDBD6EB2A for ; Wed, 12 Aug 2015 04:39:51 -0700 (PDT) Received: from h08.hostsharing.net (h08.hostsharing.net [83.223.95.28]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mailout2.hostsharing.net (Postfix) with ESMTPS id 896281016DAE7; Wed, 12 Aug 2015 13:33:03 +0200 (CEST) Received: from localhost (6-38-90-81.adsl.cmo.de [81.90.38.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by h08.hostsharing.net (Postfix) with ESMTPSA id 3DF6160423EA; Wed, 12 Aug 2015 13:33:00 +0200 (CEST) X-Mailbox-Line: From 9eed8ede6f15a254ad578e783b050e1c585d5a15 Mon Sep 17 00:00:00 2001 Message-Id: <9eed8ede6f15a254ad578e783b050e1c585d5a15.1439288957.git.lukas@wunner.de> In-Reply-To: <3313fb587249b00537dbcde127223151652427ec.1439288957.git.lukas@wunner.de> References: <29bed586baf62f6be77b7ab0ba1b8f5cb3be3aad.1439288957.git.lukas@wunner.de> <164b43588e80baaddb7a4d1081785c4d03a89c4b.1439288957.git.lukas@wunner.de> <27944adb13aa1ab246ee4a1ebb833e397324d073.1439288957.git.lukas@wunner.de> <2ac3eca0759cedd1009221cbef908605f8d29e1e.1439288957.git.lukas@wunner.de> <832f1cfceab9d9403b541b51733b87110fd8e019.1439288957.git.lukas@wunner.de> <88b49891e95ced43bfb57cc8472bb69985827153.1439288957.git.lukas@wunner.de> <2032c8103fc62d709f10be04a54b4df5c6302ad2.1439288957.git.lukas@wunner.de> <5aa64781469028545deb0f0360f56dad5dbe0057.1439288957.git.lukas@wunner.de> <53015af5b9a91332d3d74ef54fff587395447ecf.1439288957.git.lukas@wunner.de> <3313fb587249b00537dbcde127223151652427ec.1439288957.git.lukas@wunner.de> From: Lukas Wunner Date: Wed, 29 Jul 2015 21:23:14 +0200 Subject: [PATCH v2 18/22 EXPERIMENTAL] vga_switcheroo: Allow using active client as proxy when reading DDC/AUX To: dri-devel@lists.freedesktop.org Cc: Andreas Heider , Paul Hordiienko , William Brown , Bruno Bierbaumer , Matthew Garrett , Dave Airlie X-BeenThere: dri-devel@lists.freedesktop.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Direct Rendering Infrastructure - Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: dri-devel-bounces@lists.freedesktop.org Sender: "dri-devel" X-Spam-Status: No, score=-0.8 required=5.0 tests=BAYES_00, DATE_IN_PAST_96_XX, RCVD_IN_DNSWL_MED,RP_MATCHES_RCVD,UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. Allow storing pointers to each client's struct i2c_adapter (for DDC) and struct drm_dp_aux. Allow retrieving the active client's structures but constrain access to vga_switcheroo clients to prevent non-clients from using proxying. Drivers store AUX first, then DDC because they access the DPCD before the EDID. Retrieving AUX is only allowed if DDC is also stored, thereby avoiding race condition where AUX is already stored but not DDC and the inactive client uses AUX then fails on retrieving the EDID via DDC. Upon storing DDC, generate hotplug event so that already registered inactive clients reprobe once the active client has registered its DDC/AUX structures. Based (loosely) on patches by Matthew Garrett who let the active client stash the EDID and the first 8 bytes of the DPCD (receiver capabilities) in vga_switcheroo where the inactive client would subsequently pick it up. It turns out that the drivers are unhappy with just 8 bytes of DPCD, they need access to the full DPCD to set up their outputs. Switching in software gives us more options (even write access to the DPCD if need be): http://www.codon.org.uk/~mjg59/tmp/retina_patches/0016-vga_switcheroo-Allow-stashing-of-panel-data.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 [MBP 6,2 2010 intel ILK + nvidia GT216 pre-retina] Tested-by: William Brown [MBP 8,2 2011 intel SNB + amd turks pre-retina] Tested-by: Lukas Wunner [MBP 9,1 2012 intel IVB + nvidia GK107 pre-retina] Tested-by: Bruno Bierbaumer [MBP 11,3 2013 intel HSW + nvidia GK107 retina -- work in progress] Signed-off-by: Lukas Wunner --- drivers/gpu/vga/vga_switcheroo.c | 62 ++++++++++++++++++++++++++++++++++++++++ include/linux/vga_switcheroo.h | 11 +++++++ 2 files changed, 73 insertions(+) diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c index 94b0b6f..0c52eb4 100644 --- a/drivers/gpu/vga/vga_switcheroo.c +++ b/drivers/gpu/vga/vga_switcheroo.c @@ -19,6 +19,7 @@ */ #include +#include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include #include #include @@ -37,6 +39,8 @@ struct vga_switcheroo_client { struct pci_dev *pdev; struct fb_info *fb_info; + struct i2c_adapter *ddc; + struct drm_dp_aux *aux; struct work_struct reprobe_work; int pwr_state; const struct vga_switcheroo_client_ops *ops; @@ -355,6 +359,64 @@ out: } EXPORT_SYMBOL(vga_switcheroo_unlock_ddc); +void vga_switcheroo_set_ddc(struct pci_dev *pdev, struct i2c_adapter *ddc) +{ + struct vga_switcheroo_client *client; + + mutex_lock(&vgasr_mutex); + client = find_client_from_pci(&vgasr_priv.clients, pdev); + if (client) + client->ddc = ddc; + mutex_unlock(&vgasr_mutex); + + /* DDC is stored after AUX on eDP, so we have both now */ + if (client->active) + vga_switcheroo_reprobe_inactive_clients(); +} +EXPORT_SYMBOL(vga_switcheroo_set_ddc); + +struct i2c_adapter *vga_switcheroo_get_ddc(struct pci_dev *pdev) +{ + struct vga_switcheroo_client *active = NULL; + + mutex_lock(&vgasr_mutex); + if (find_client_from_pci(&vgasr_priv.clients, pdev)) + active = find_active_client(&vgasr_priv.clients); + mutex_unlock(&vgasr_mutex); + if (!active) + return NULL; + + return active->ddc; +} +EXPORT_SYMBOL(vga_switcheroo_get_ddc); + +void vga_switcheroo_set_aux(struct pci_dev *pdev, struct drm_dp_aux *aux) +{ + struct vga_switcheroo_client *client; + + mutex_lock(&vgasr_mutex); + client = find_client_from_pci(&vgasr_priv.clients, pdev); + if (client) + client->aux = aux; + mutex_unlock(&vgasr_mutex); +} +EXPORT_SYMBOL(vga_switcheroo_set_aux); + +struct drm_dp_aux *vga_switcheroo_get_aux(struct pci_dev *pdev) +{ + struct vga_switcheroo_client *active = NULL; + + mutex_lock(&vgasr_mutex); + if (find_client_from_pci(&vgasr_priv.clients, pdev)) + active = find_active_client(&vgasr_priv.clients); + mutex_unlock(&vgasr_mutex); + if (!active || !active->ddc) + return NULL; + + return active->aux; +} +EXPORT_SYMBOL(vga_switcheroo_get_aux); + static int vga_switcheroo_show(struct seq_file *m, void *v) { struct vga_switcheroo_client *client; diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h index b935d83..1d4c07e 100644 --- a/include/linux/vga_switcheroo.h +++ b/include/linux/vga_switcheroo.h @@ -10,7 +10,10 @@ #ifndef _LINUX_VGA_SWITCHEROO_H_ #define _LINUX_VGA_SWITCHEROO_H_ +#include + #include +#include struct pci_dev; @@ -56,6 +59,10 @@ void vga_switcheroo_client_fb_set(struct pci_dev *dev, int vga_switcheroo_lock_ddc(struct pci_dev *pdev); int vga_switcheroo_unlock_ddc(struct pci_dev *pdev); +void vga_switcheroo_set_ddc(struct pci_dev *pdev, struct i2c_adapter *ddc); +struct i2c_adapter *vga_switcheroo_get_ddc(struct pci_dev *pdev); +void vga_switcheroo_set_aux(struct pci_dev *pdev, struct drm_dp_aux *aux); +struct drm_dp_aux *vga_switcheroo_get_aux(struct pci_dev *pdev); int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler); void vga_switcheroo_unregister_handler(void); @@ -77,6 +84,10 @@ static inline int vga_switcheroo_register_client(struct pci_dev *dev, static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {} static inline int vga_switcheroo_lock_ddc(struct pci_dev *pdev) { return -ENODEV; } static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return -ENODEV; } +static inline void vga_switcheroo_set_ddc(struct pci_dev *pdev, struct i2c_adapter *ddc) {} +static inline struct i2c_adapter *vga_switcheroo_get_ddc(struct pci_dev *pdev) { return NULL; } +static inline void vga_switcheroo_set_aux(struct pci_dev *pdev, struct drm_dp_aux *aux) {} +static inline struct drm_dp_aux *vga_switcheroo_get_aux(struct pci_dev *pdev) { return NULL; } static inline int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler) { return 0; } static inline int vga_switcheroo_register_audio_client(struct pci_dev *pdev, const struct vga_switcheroo_client_ops *ops,