[PATCH 04/11] vga_switcheroo: Allow stashing of panel data

Matthew Garrett matthew.garrett at nebula.com
Sun Jun 1 09:38:36 PDT 2014


Not all MUXes allow us to connect the panel data channel to a GPU without
handing over the entire panel and triggering additional flickering during
boot. We only need to do this in order to probe for data that the first
GPU driver has already identified, so add some functions for stashing that
data in vga_switcheroo where it can be retrieved by the other driver later.

Signed-off-by: Matthew Garrett <matthew.garrett at nebula.com>
---
 drivers/gpu/vga/vga_switcheroo.c | 59 ++++++++++++++++++++++++++++++++++++++++
 include/linux/vga_switcheroo.h   | 12 ++++++++
 2 files changed, 71 insertions(+)

diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 6d95626..1a80b93 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -17,6 +17,8 @@
  - switch_check  - check if the device is in a position to switch now
  */
 
+#include <drm/drm_edid.h>
+
 #include <linux/module.h>
 #include <linux/seq_file.h>
 #include <linux/uaccess.h>
@@ -39,6 +41,7 @@ struct vga_switcheroo_client {
 	int id;
 	bool active;
 	bool driver_power_control;
+	bool use_panel;
 	struct list_head list;
 };
 
@@ -56,6 +59,9 @@ struct vgasr_priv {
 	int registered_clients;
 	struct list_head clients;
 
+	struct edid *edid;
+	u8 *dpcd;
+
 	struct vga_switcheroo_handler *handler;
 };
 
@@ -107,7 +113,9 @@ static void vga_switcheroo_enable(void)
 				VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
 			if (vgasr_priv.handler->switch_ddc)
 				vgasr_priv.handler->switch_ddc(client->id);
+			client->use_panel = true;
 			client->ops->reprobe_connectors(client->pdev);
+			client->use_panel = false;
 			if (vgasr_priv.handler->switch_ddc)
 				vgasr_priv.handler->switch_ddc(old_id);
 		}
@@ -412,6 +420,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
 	if (ret)
 		goto restore_ddc;
 
+	new_client->use_panel = true;
+	active->use_panel = false;
+
 	if (new_client->ops->reprobe)
 		new_client->ops->reprobe(new_client->pdev);
 
@@ -766,6 +777,54 @@ int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct
 }
 EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio);
 
+int vga_switcheroo_set_dpcd(u8 *dpcd)
+{
+	if (vgasr_priv.dpcd)
+		return -EEXIST;
+
+	vgasr_priv.dpcd = kmalloc(8, GFP_KERNEL);
+	memcpy(vgasr_priv.dpcd, dpcd, 8);
+	return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_set_dpcd);
+
+u8 *vga_switcheroo_get_dpcd(struct pci_dev *pdev)
+{
+	struct vga_switcheroo_client *client;
+	client = find_client_from_pci(&vgasr_priv.clients, pdev);
+
+	if (!client || !client->use_panel)
+		return NULL;
+
+	return vgasr_priv.dpcd;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_dpcd);
+
+int vga_switcheroo_set_edid(struct edid *edid)
+{
+	int size = EDID_LENGTH * (1 + edid->extensions);
+
+	if (vgasr_priv.edid)
+		return -EEXIST;
+
+	vgasr_priv.edid = kmalloc(size, GFP_KERNEL);
+	memcpy(vgasr_priv.edid, edid, size);
+	return 0;
+}
+EXPORT_SYMBOL(vga_switcheroo_set_edid);
+
+struct edid *vga_switcheroo_get_edid(struct pci_dev *pdev)
+{
+	struct vga_switcheroo_client *client;
+	client = find_client_from_pci(&vgasr_priv.clients, pdev);
+
+	if (!client || !client->use_panel)
+		return NULL;
+
+	return vgasr_priv.edid;
+}
+EXPORT_SYMBOL(vga_switcheroo_get_edid);
+
 static int __init vga_switcheroo_setup(char *str)
 {
 	if (!strcmp(str, "IGD"))
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index bae62fd..07b07fc 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -10,6 +10,7 @@
 #ifndef _LINUX_VGA_SWITCHEROO_H_
 #define _LINUX_VGA_SWITCHEROO_H_
 
+#include <drm/drm_edid.h>
 #include <linux/fb.h>
 
 struct pci_dev;
@@ -69,6 +70,12 @@ void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo
 
 int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
 int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain);
+
+int vga_switcheroo_set_dpcd(u8 *dpcd);
+u8 *vga_switcheroo_get_dpcd(struct pci_dev *pdev);
+int vga_switcheroo_set_edid(struct edid *edid);
+struct edid *vga_switcheroo_get_edid(struct pci_dev *pdev);
+
 #else
 
 static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
@@ -89,5 +96,10 @@ static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum
 static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
 static inline int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
 
+static inline int vga_switcheroo_set_dpcd(u8 *dpcd) { return 0 };
+static inline u8 *vga_switcheroo_get_dpcd(struct pci_dev *pdev) { return NULL };
+static inline int vga_switcheroo_set_edid(struct edid *edid) { return 0 };
+static inline struct edid *vga_switcheroo_get_edid(struct pci_dev *pdev) { return NULL };
+
 #endif
 #endif /* _LINUX_VGA_SWITCHEROO_H_ */
-- 
1.8.5.3



More information about the dri-devel mailing list