* Improve Apple GMUX support on switcheroo
@ 2014-06-01 16:38 Matthew Garrett
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
` (10 more replies)
0 siblings, 11 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86
The Apple GMUX switcheroo code doesn't really work that well - there's no
straightforward way to ensure that drivers are loaded in the correct order,
and no mechanism to probe displays without performing a full switch. This
patchset adds infrastructural support to switcheroo and functionality to
GMUX in order to fix things up. This won't actually *work* in its current
form - it needs additional patches to the GPU drivers, which are currently
in a somewhat hacky state.
--
Matthew Garrett | matthew.garrett@nebula.com
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-03 13:26 ` Jani Nikula
2014-06-12 0:37 ` Dave Airlie
2014-06-01 16:38 ` [PATCH 02/11] vga_switcheroo: Add support for reprobing connectors Matthew Garrett
` (9 subsequent siblings)
10 siblings, 2 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Seth Forshee
From: Seth Forshee <seth.forshee@canonical.com>
During graphics driver initialization its useful to be able to mux only
the DDC to the inactive client in order to read the EDID. Add a
switch_ddc callback to allow capable handlers to provide this
functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
only the DDC.
Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
drivers/gpu/vga/vga_switcheroo.c | 38 +++++++++++++++++++++++++++++++++++++-
include/linux/vga_switcheroo.h | 4 ++++
2 files changed, 41 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index ec0ae2d..dd1d587 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -256,6 +256,28 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
}
EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
+{
+ int ret = 0;
+ int id;
+
+ mutex_lock(&vgasr_mutex);
+
+ if (!vgasr_priv.handler) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (vgasr_priv.handler->switch_ddc) {
+ id = vgasr_priv.handler->get_client_id(pdev);
+ ret = vgasr_priv.handler->switch_ddc(id);
+ }
+out:
+ mutex_unlock(&vgasr_mutex);
+ return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
+
static int vga_switcheroo_show(struct seq_file *m, void *v)
{
struct vga_switcheroo_client *client;
@@ -353,9 +375,15 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
console_unlock();
}
+ if (vgasr_priv.handler->switch_ddc) {
+ ret = vgasr_priv.handler->switch_ddc(new_client->id);
+ if (ret)
+ return ret;
+ }
+
ret = vgasr_priv.handler->switchto(new_client->id);
if (ret)
- return ret;
+ goto restore_ddc;
if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
@@ -367,6 +395,14 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
new_client->active = true;
return 0;
+
+restore_ddc:
+ if (vgasr_priv.handler->switch_ddc) {
+ int id = (new_client->id == VGA_SWITCHEROO_IGD) ?
+ VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+ vgasr_priv.handler->switch_ddc(id);
+ }
+ return ret;
}
static bool check_can_switch(void)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 502073a..37d6850 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
};
struct vga_switcheroo_handler {
+ int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
enum vga_switcheroo_state state);
@@ -54,6 +55,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
void vga_switcheroo_client_fb_set(struct pci_dev *dev,
struct fb_info *info);
+int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
+
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
void vga_switcheroo_unregister_handler(void);
@@ -71,6 +74,7 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
+static inline void vga_switcheroo_switch_ddc(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,
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
@ 2014-06-03 13:26 ` Jani Nikula
2014-06-12 0:37 ` Dave Airlie
1 sibling, 0 replies; 17+ messages in thread
From: Jani Nikula @ 2014-06-03 13:26 UTC (permalink / raw)
To: Matthew Garrett, airlied; +Cc: Seth Forshee, dri-devel, platform-driver-x86
On Sun, 01 Jun 2014, Matthew Garrett <matthew.garrett@nebula.com> wrote:
> From: Seth Forshee <seth.forshee@canonical.com>
>
> During graphics driver initialization its useful to be able to mux only
> the DDC to the inactive client in order to read the EDID. Add a
> switch_ddc callback to allow capable handlers to provide this
> functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
> only the DDC.
>
> Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
> ---
> drivers/gpu/vga/vga_switcheroo.c | 38 +++++++++++++++++++++++++++++++++++++-
> include/linux/vga_switcheroo.h | 4 ++++
> 2 files changed, 41 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
> index ec0ae2d..dd1d587 100644
> --- a/drivers/gpu/vga/vga_switcheroo.c
> +++ b/drivers/gpu/vga/vga_switcheroo.c
> @@ -256,6 +256,28 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
> }
> EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
>
> +int vga_switcheroo_switch_ddc(struct pci_dev *pdev)
> +{
> + int ret = 0;
> + int id;
> +
> + mutex_lock(&vgasr_mutex);
> +
> + if (!vgasr_priv.handler) {
> + ret = -ENODEV;
> + goto out;
> + }
> +
> + if (vgasr_priv.handler->switch_ddc) {
> + id = vgasr_priv.handler->get_client_id(pdev);
> + ret = vgasr_priv.handler->switch_ddc(id);
> + }
> +out:
> + mutex_unlock(&vgasr_mutex);
> + return ret;
> +}
> +EXPORT_SYMBOL(vga_switcheroo_switch_ddc);
> +
> static int vga_switcheroo_show(struct seq_file *m, void *v)
> {
> struct vga_switcheroo_client *client;
> @@ -353,9 +375,15 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
> console_unlock();
> }
>
> + if (vgasr_priv.handler->switch_ddc) {
> + ret = vgasr_priv.handler->switch_ddc(new_client->id);
> + if (ret)
> + return ret;
> + }
> +
> ret = vgasr_priv.handler->switchto(new_client->id);
> if (ret)
> - return ret;
> + goto restore_ddc;
>
> if (new_client->ops->reprobe)
> new_client->ops->reprobe(new_client->pdev);
> @@ -367,6 +395,14 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
>
> new_client->active = true;
> return 0;
> +
> +restore_ddc:
> + if (vgasr_priv.handler->switch_ddc) {
> + int id = (new_client->id == VGA_SWITCHEROO_IGD) ?
> + VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
> + vgasr_priv.handler->switch_ddc(id);
> + }
> + return ret;
> }
>
> static bool check_can_switch(void)
> diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
> index 502073a..37d6850 100644
> --- a/include/linux/vga_switcheroo.h
> +++ b/include/linux/vga_switcheroo.h
> @@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
> };
>
> struct vga_switcheroo_handler {
> + int (*switch_ddc)(enum vga_switcheroo_client_id id);
> int (*switchto)(enum vga_switcheroo_client_id id);
> int (*power_state)(enum vga_switcheroo_client_id id,
> enum vga_switcheroo_state state);
> @@ -54,6 +55,8 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
> void vga_switcheroo_client_fb_set(struct pci_dev *dev,
> struct fb_info *info);
>
> +int vga_switcheroo_switch_ddc(struct pci_dev *pdev);
> +
> int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
> void vga_switcheroo_unregister_handler(void);
>
> @@ -71,6 +74,7 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
> static inline int vga_switcheroo_register_client(struct pci_dev *dev,
> const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
> static inline void vga_switcheroo_client_fb_set(struct pci_dev *dev, struct fb_info *info) {}
> +static inline void vga_switcheroo_switch_ddc(struct pci_dev *pdev) { return NULL; }
Not really reviewing, but this three-way contradiction of return types
caught my eye.
BR,
Jani.
> 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,
> --
> 1.8.5.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Jani Nikula, Intel Open Source Technology Center
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
2014-06-03 13:26 ` Jani Nikula
@ 2014-06-12 0:37 ` Dave Airlie
1 sibling, 0 replies; 17+ messages in thread
From: Dave Airlie @ 2014-06-12 0:37 UTC (permalink / raw)
To: Matthew Garrett; +Cc: dri-devel, platform-driver-x86, Seth Forshee
On 2 June 2014 02:38, Matthew Garrett <matthew.garrett@nebula.com> wrote:
> From: Seth Forshee <seth.forshee@canonical.com>
>
> During graphics driver initialization its useful to be able to mux only
> the DDC to the inactive client in order to read the EDID. Add a
> switch_ddc callback to allow capable handlers to provide this
> functionality, and add vga_switcheroo_switch_ddc() to allow DRM to mux
> only the DDC.
>
I can't figure out why I didn't like this, but I rewrote this way back
to lock/unlock the ddc lines,
bits are contained in this WIP mess.
http://cgit.freedesktop.org/~airlied/linux/commit/?h=switchy-wip&id=aead3bb72d82bd63149082a2670cc2521f2290a4
I think I'd prefer something like that otherwise the interface got really ugly.
Dave.
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 02/11] vga_switcheroo: Add support for reprobing connectors
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 03/11] vga_switcheroo: Add command line option Matthew Garrett
` (8 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
If display MUXing is handled by an external driver, the handler may not
initialise until some time after the graphics drivers originally bound. If
the driver is unable to detect some drivers unless appropriately MUXed, this
will cause problems. This patch adds a callback to allow switcheroo to
retrigger the driver's output probing.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/gpu/vga/vga_switcheroo.c | 10 ++++++++++
include/linux/vga_switcheroo.h | 1 +
2 files changed, 11 insertions(+)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index dd1d587..c06ad5f 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -96,6 +96,16 @@ static void vga_switcheroo_enable(void)
return;
client->id = ret;
+
+ if (!client->active && client->ops->reprobe_connectors) {
+ int old_id = (client->id == VGA_SWITCHEROO_IGD) ?
+ VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
+ if (vgasr_priv.handler->switch_ddc)
+ vgasr_priv.handler->switch_ddc(client->id);
+ client->ops->reprobe_connectors(client->pdev);
+ if (vgasr_priv.handler->switch_ddc)
+ vgasr_priv.handler->switch_ddc(old_id);
+ }
}
vga_switcheroo_debugfs_init(&vgasr_priv);
vgasr_priv.active = true;
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 37d6850..bae62fd 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -40,6 +40,7 @@ struct vga_switcheroo_handler {
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
void (*reprobe)(struct pci_dev *dev);
+ void (*reprobe_connectors)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
};
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 03/11] vga_switcheroo: Add command line option
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
2014-06-01 16:38 ` [PATCH 02/11] vga_switcheroo: Add support for reprobing connectors Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 04/11] vga_switcheroo: Allow stashing of panel data Matthew Garrett
` (7 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
Add a command line option in order to allow the user to provide a perferred
GPU at boot time.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
Documentation/kernel-parameters.txt | 5 +++++
drivers/gpu/vga/vga_switcheroo.c | 29 +++++++++++++++++++++++++++++
2 files changed, 34 insertions(+)
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 30a8ad0d..6e6d505 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -3486,6 +3486,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
This is actually a boot loader parameter; the value is
passed to the kernel using a special protocol.
+ vga_switcheroo= [HW] Switches the enabled GPU at boot time.
+ Format: { IGD | DIS }
+ IGD -- enable the Integrated GPU
+ DIS -- enable the Discrete GPU
+
vmalloc=nn[KMG] [KNL,BOOT] Forces the vmalloc area to have an exact
size of <nn>. This can be used to increase the
minimum size (128MB on x86). It can also be used to
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index c06ad5f..6d95626 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -67,6 +67,11 @@ struct vgasr_priv {
static int vga_switcheroo_debugfs_init(struct vgasr_priv *priv);
static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
+static enum vga_switcheroo_client_id vga_switcheroo_default = -1;
+
+static int vga_switchto_stage1(struct vga_switcheroo_client *new_client);
+static int vga_switchto_stage2(struct vga_switcheroo_client *new_client);
+
/* only one switcheroo per system */
static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
@@ -107,6 +112,18 @@ static void vga_switcheroo_enable(void)
vgasr_priv.handler->switch_ddc(old_id);
}
}
+
+ list_for_each_entry(client, &vgasr_priv.clients, list) {
+ if (!client->active && client->id == vga_switcheroo_default) {
+ ret = vga_switchto_stage1(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: switching failed stage 1 %d\n", ret);
+
+ ret = vga_switchto_stage2(client);
+ if (ret)
+ printk(KERN_ERR "vga_switcheroo: switching failed stage 2 %d\n", ret);
+ }
+ }
vga_switcheroo_debugfs_init(&vgasr_priv);
vgasr_priv.active = true;
}
@@ -748,3 +765,15 @@ int vga_switcheroo_init_domain_pm_optimus_hdmi_audio(struct device *dev, struct
return -EINVAL;
}
EXPORT_SYMBOL(vga_switcheroo_init_domain_pm_optimus_hdmi_audio);
+
+static int __init vga_switcheroo_setup(char *str)
+{
+ if (!strcmp(str, "IGD"))
+ vga_switcheroo_default = VGA_SWITCHEROO_IGD;
+ else if (!strcmp(str, "DIS"))
+ vga_switcheroo_default = VGA_SWITCHEROO_DIS;
+
+ return 1;
+}
+
+__setup("vga_switcheroo=", vga_switcheroo_setup);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 04/11] vga_switcheroo: Allow stashing of panel data
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (2 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 03/11] vga_switcheroo: Add command line option Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-03 13:40 ` Jani Nikula
2014-06-01 16:38 ` [PATCH 05/11] vga_switcheroo: Allow handlers to indicate that they can handle PM Matthew Garrett
` (6 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
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@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
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 04/11] vga_switcheroo: Allow stashing of panel data
2014-06-01 16:38 ` [PATCH 04/11] vga_switcheroo: Allow stashing of panel data Matthew Garrett
@ 2014-06-03 13:40 ` Jani Nikula
0 siblings, 0 replies; 17+ messages in thread
From: Jani Nikula @ 2014-06-03 13:40 UTC (permalink / raw)
To: airlied; +Cc: Matthew Garrett, dri-devel, platform-driver-x86
On Sun, 01 Jun 2014, Matthew Garrett <matthew.garrett@nebula.com> wrote:
> 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@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)
Quite a few DPCD related things in drm_dp_helper.h expect
DP_RECEIVER_CAP_SIZE bytes of DPCD. Might be helpful to conform to that.
Can also be made const u8 *.
> +{
> + if (vgasr_priv.dpcd)
> + return -EEXIST;
> +
> + vgasr_priv.dpcd = kmalloc(8, GFP_KERNEL);
> + memcpy(vgasr_priv.dpcd, dpcd, 8);
kmemdup.
> + 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);
kmemdup.
BR,
Jani.
> + 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
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
--
Jani Nikula, Intel Open Source Technology Center
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 05/11] vga_switcheroo: Allow handlers to indicate that they can handle PM
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (3 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 04/11] vga_switcheroo: Allow stashing of panel data Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 06/11] vga_switcheroo: Add enable() call to clients and permit deferral of dynamic PM Matthew Garrett
` (5 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
Most switcheroo setups attach power management to one of the GPUs. This is
not always the case, so provide a mechanism for handlers to declare that
they can change the power state of GPUs and permit drivers to obtain this
information.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/gpu/vga/vga_switcheroo.c | 8 ++++++++
include/linux/vga_switcheroo.h | 5 +++++
2 files changed, 13 insertions(+)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 1a80b93..c5e97d4 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -825,6 +825,14 @@ struct edid *vga_switcheroo_get_edid(struct pci_dev *pdev)
}
EXPORT_SYMBOL(vga_switcheroo_get_edid);
+bool vga_switcheroo_handler_pm(void) {
+ if (!vgasr_priv.handler)
+ return false;
+
+ return vgasr_priv.handler->handler_pm;
+}
+EXPORT_SYMBOL(vga_switcheroo_handler_pm);
+
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 07b07fc..4bba934 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -36,6 +36,7 @@ struct vga_switcheroo_handler {
enum vga_switcheroo_state state);
int (*init)(void);
int (*get_client_id)(struct pci_dev *pdev);
+ bool handler_pm;
};
struct vga_switcheroo_client_ops {
@@ -76,6 +77,8 @@ 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);
+bool vga_switcheroo_handler_pm(void);
+
#else
static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
@@ -101,5 +104,7 @@ 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 };
+static inline bool vga_switcheroo_handler_pm(void) { return false; };
+
#endif
#endif /* _LINUX_VGA_SWITCHEROO_H_ */
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 06/11] vga_switcheroo: Add enable() call to clients and permit deferral of dynamic PM
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (4 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 05/11] vga_switcheroo: Allow handlers to indicate that they can handle PM Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 07/11] vga_switcheroo: Reprobe old device on switching Matthew Garrett
` (4 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
We may not know whether the platform supports dynamic PM of GPUs until the
switcheroo handler is registered. Add an enable() callback for clients and
another entry point to switcheroo in order to permit them to set dynamic PM
appropriately.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/gpu/vga/vga_switcheroo.c | 17 +++++++++++++++++
include/linux/vga_switcheroo.h | 3 +++
2 files changed, 20 insertions(+)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index c5e97d4..199a111 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -108,6 +108,9 @@ static void vga_switcheroo_enable(void)
client->id = ret;
+ if (client->ops->enable)
+ client->ops->enable(client->pdev);
+
if (!client->active && client->ops->reprobe_connectors) {
int old_id = (client->id == VGA_SWITCHEROO_IGD) ?
VGA_SWITCHEROO_DIS : VGA_SWITCHEROO_IGD;
@@ -670,6 +673,20 @@ static void vga_switcheroo_power_switch(struct pci_dev *pdev, enum vga_switchero
vgasr_priv.handler->power_state(client->id, state);
}
+void vga_switcheroo_set_dynamic_support(struct pci_dev *pdev, bool dynamic)
+{
+ struct vga_switcheroo_client *client;
+
+ client = find_client_from_pci(&vgasr_priv.clients, pdev);
+ if (!client)
+ return;
+
+ client->driver_power_control = dynamic;
+
+ return;
+}
+EXPORT_SYMBOL(vga_switcheroo_set_dynamic_support);
+
/* force a PCI device to a certain state - mainly to turn off audio clients */
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic)
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index 4bba934..5a483c6 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -44,6 +44,7 @@ struct vga_switcheroo_client_ops {
void (*reprobe)(struct pci_dev *dev);
void (*reprobe_connectors)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
+ void (*enable)(struct pci_dev *dev);
};
#if defined(CONFIG_VGA_SWITCHEROO)
@@ -67,6 +68,7 @@ int vga_switcheroo_process_delayed_switch(void);
int vga_switcheroo_get_client_state(struct pci_dev *dev);
+void vga_switcheroo_set_dynamic_support(struct pci_dev *pdev, bool dynamic);
void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic);
int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain);
@@ -94,6 +96,7 @@ static inline void vga_switcheroo_unregister_handler(void) {}
static inline int vga_switcheroo_process_delayed_switch(void) { return 0; }
static inline int vga_switcheroo_get_client_state(struct pci_dev *dev) { return VGA_SWITCHEROO_ON; }
+static inline void vga_switcheroo_set_dynamic_support(struct pci_dev *pdev, bool dynamic) {}
static inline void vga_switcheroo_set_dynamic_switch(struct pci_dev *pdev, enum vga_switcheroo_state dynamic) {}
static inline int vga_switcheroo_init_domain_pm_ops(struct device *dev, struct dev_pm_domain *domain) { return -EINVAL; }
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 07/11] vga_switcheroo: Reprobe old device on switching
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (5 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 06/11] vga_switcheroo: Add enable() call to clients and permit deferral of dynamic PM Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback Matthew Garrett
` (3 subsequent siblings)
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
We need to force the previously active device to reprobe its connectors
when we switch in order to allow it to give up connectors that are no
longer in use.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/gpu/vga/vga_switcheroo.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 199a111..d380158 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -429,6 +429,9 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
+ if (active->ops->reprobe)
+ active->ops->reprobe(active->pdev);
+
if (active->pwr_state == VGA_SWITCHEROO_ON)
vga_switchoff(active);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (6 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 07/11] vga_switcheroo: Reprobe old device on switching Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-02 14:35 ` Alex Deucher
2014-06-01 16:38 ` [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering Matthew Garrett
` (2 subsequent siblings)
10 siblings, 1 reply; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
We can switch DDC pins in a way that ought (with luck) to work for LVDS.
This isn't sufficient for eDP, which is addressed in later patches.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/platform/x86/apple-gmux.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index b9429fb..5594cbc 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -271,6 +271,16 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
};
+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+ if (id == VGA_SWITCHEROO_IGD)
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+ else
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+
+ return 0;
+}
+
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD) {
@@ -346,6 +356,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
static struct vga_switcheroo_handler gmux_handler = {
.switchto = gmux_switchto,
+ .switch_ddc = gmux_switch_ddc,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
};
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback
2014-06-01 16:38 ` [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback Matthew Garrett
@ 2014-06-02 14:35 ` Alex Deucher
0 siblings, 0 replies; 17+ messages in thread
From: Alex Deucher @ 2014-06-02 14:35 UTC (permalink / raw)
To: Matthew Garrett
Cc: Dave Airlie, Maling list - DRI developers, platform-driver-x86
On Sun, Jun 1, 2014 at 12:38 PM, Matthew Garrett
<matthew.garrett@nebula.com> wrote:
> We can switch DDC pins in a way that ought (with luck) to work for LVDS.
> This isn't sufficient for eDP, which is addressed in later patches.
>
> Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
FWIW, on AMD muxed PX systems, there are separate muxes for ddc/hpd
and data lines so it would be trivial to implement there as well.
Alex
> ---
> drivers/platform/x86/apple-gmux.c | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
> index b9429fb..5594cbc 100644
> --- a/drivers/platform/x86/apple-gmux.c
> +++ b/drivers/platform/x86/apple-gmux.c
> @@ -271,6 +271,16 @@ static const struct backlight_ops gmux_bl_ops = {
> .update_status = gmux_update_status,
> };
>
> +static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
> +{
> + if (id == VGA_SWITCHEROO_IGD)
> + gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
> + else
> + gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
> +
> + return 0;
> +}
> +
> static int gmux_switchto(enum vga_switcheroo_client_id id)
> {
> if (id == VGA_SWITCHEROO_IGD) {
> @@ -346,6 +356,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
>
> static struct vga_switcheroo_handler gmux_handler = {
> .switchto = gmux_switchto,
> + .switch_ddc = gmux_switch_ddc,
> .power_state = gmux_set_power_state,
> .get_client_id = gmux_get_client_id,
> };
> --
> 1.8.5.3
>
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (7 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 10/11] apple-gmux: Indicate that driver supports changing of GPU power states Matthew Garrett
2014-06-01 16:38 ` [PATCH 11/11] apple_gmux: Wait for switch completion Matthew Garrett
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
Registering the handler after both GPUs will trigger a DDC switch for
connector reprobing. This will oops if apple_gmux_data hasn't already been
assigned. Reorder the code to do that.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/platform/x86/apple-gmux.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 5594cbc..e9b6d77 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -563,18 +563,20 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
gmux_data->gpe = -1;
}
+ apple_gmux_data = gmux_data;
+ init_completion(&gmux_data->powerchange_done);
+ gmux_enable_interrupts(gmux_data);
+
if (vga_switcheroo_register_handler(&gmux_handler)) {
ret = -ENODEV;
goto err_register_handler;
}
- init_completion(&gmux_data->powerchange_done);
- apple_gmux_data = gmux_data;
- gmux_enable_interrupts(gmux_data);
-
return 0;
err_register_handler:
+ gmux_disable_interrupts(gmux_data);
+ apple_gmux_data = NULL;
if (gmux_data->gpe >= 0)
acpi_disable_gpe(NULL, gmux_data->gpe);
err_enable_gpe:
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 10/11] apple-gmux: Indicate that driver supports changing of GPU power states
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (8 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
2014-06-01 16:38 ` [PATCH 11/11] apple_gmux: Wait for switch completion Matthew Garrett
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
The Apple GMUX can cut power to the discrete GPU, so should declare this
to the vga_switcheroo core.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/platform/x86/apple-gmux.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index e9b6d77..17f906d 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -359,6 +359,7 @@ static struct vga_switcheroo_handler gmux_handler = {
.switch_ddc = gmux_switch_ddc,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
+ .handler_pm = true,
};
static inline void gmux_disable_interrupts(struct apple_gmux_data *gmux_data)
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 11/11] apple_gmux: Wait for switch completion
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
` (9 preceding siblings ...)
2014-06-01 16:38 ` [PATCH 10/11] apple-gmux: Indicate that driver supports changing of GPU power states Matthew Garrett
@ 2014-06-01 16:38 ` Matthew Garrett
10 siblings, 0 replies; 17+ messages in thread
From: Matthew Garrett @ 2014-06-01 16:38 UTC (permalink / raw)
To: airlied; +Cc: dri-devel, platform-driver-x86, Matthew Garrett
The GMUX doesn't appear to switch instantly, which can trigger problems in
panel detection and setup. Wait for an interrupt or 200msec, whichever comes
first.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
---
drivers/platform/x86/apple-gmux.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 17f906d..6826ede 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -38,6 +38,7 @@ struct apple_gmux_data {
int gpe;
enum vga_switcheroo_client_id resume_client_id;
enum vga_switcheroo_state power_state;
+ struct completion switch_done;
struct completion powerchange_done;
};
@@ -283,6 +284,8 @@ static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
+ reinit_completion(&apple_gmux_data->switch_done);
+
if (id == VGA_SWITCHEROO_IGD) {
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
@@ -293,6 +296,11 @@ static int gmux_switchto(enum vga_switcheroo_client_id id)
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
+ if (apple_gmux_data->gpe >= 0 &&
+ !wait_for_completion_interruptible_timeout(&apple_gmux_data->switch_done,
+ msecs_to_jiffies(200)))
+ pr_warn("Timeout waiting for gmux GPU switch to complete\n");
+
return 0;
}
@@ -401,6 +409,9 @@ static void gmux_notify_handler(acpi_handle device, u32 value, void *context)
gmux_clear_interrupts(gmux_data);
gmux_enable_interrupts(gmux_data);
+ if (status & GMUX_INTERRUPT_STATUS_DISPLAY)
+ complete(&gmux_data->switch_done);
+
if (status & GMUX_INTERRUPT_STATUS_POWER)
complete(&gmux_data->powerchange_done);
}
@@ -565,6 +576,7 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
}
apple_gmux_data = gmux_data;
+ init_completion(&gmux_data->switch_done);
init_completion(&gmux_data->powerchange_done);
gmux_enable_interrupts(gmux_data);
--
1.8.5.3
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 00/11] Enable gpu switching on the MacBook Pro
@ 2015-04-21 9:58 Lukas Wunner
2014-03-05 22:34 ` [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering Lukas Wunner
0 siblings, 1 reply; 17+ messages in thread
From: Lukas Wunner @ 2015-04-21 9:58 UTC (permalink / raw)
To: dri-devel; +Cc: Daniel Vetter, Seth Forshee, Matthew Garrett, Dave Airlie
The following patchset extends vga_switcheroo and related drivers
to enable gpu switching on the MacBook Pro.
On MBPs, the panel is not connected to one of the gpus, but to the
gmux chip (the "handler" in vga_switcheroo speak). Initially the gmux
is switched to the discrete gpu. The integrated i915 gpu is therefore
unable to detect the LVDS (or eDP) connector on bootup and switching
to the integrated gpu will lead to a black screen. The solution is
to temporarily switch the DDC lines to the integrated gpu when reading
the EDID, which the gmux is capable of. Lack of support for this in
vga_switcheroo is pretty much the only obstacle to get gpu switching
to work on MBPs.
Seth Forshee came up with a patchset in fall 2012 but only a portion
of it got merged. Matthew Garrett developed this further in 2014:
http://www.codon.org.uk/~mjg59/tmp/retina_patches/
http://lists.freedesktop.org/archives/dri-devel/2014-June/060947.html
Matthew Garrett's patches weren't merged either: Dave Airlie responded
that he had rewritten Seth Forshee's code in December 2012. Whereas
Seth Forshee had used a single function vga_switcheroo_switch_ddc()
with a mutex in drm_get_edid() to avoid race conditions, Dave Airlie
had moved the mutex to vga_switcheroo.c and used *two* functions
vga_switcheroo_lock_ddc() and vga_switcheroo_unlock_ddc():
http://lists.freedesktop.org/archives/dri-devel/2014-June/061629.html
http://cgit.freedesktop.org/~airlied/linux/log/?h=switchy-wip
Quoth Dave Airlie: "I can't figure out why I didn't like this, but I
rewrote this way back to lock/unlock the ddc lines, bits are contained
in this WIP mess. I think I'd prefer something like that otherwise the
interface got really ugly."
I basically took Dave Airlies WIP code of December 2012, added all the
missing pieces, applied one of Matthew Garrett's patches verbatim and
rewrote two others.
This works on a MacBookPro9,1 with Intel HD4000 (Ivy Bridge) and
Nvidia GT650M (NVE7 / GK107) plus a "classic" (non-indexed) gmux
connected to a 1680x1050 panel with dual channel LVDS (applied
on top of drm-next and using nouveau).
Dave Airlie's commit removes a portion of Seth Forshee's code and my
commit in turn removes some of Dave Airlie's code. Because this makes
reviewing difficult, I'm including below a diff which contains all
commits squashed into one. Reviewers may want to look at that diff
first instead of the individual commits.
One difficulty one needs to be aware of is that gmux may register
after the i915 driver, making it impossible to switch the DDC lines
upon i915 initialization. Seth Forshee solved this by deferring
initialization of the graphics driver:
http://cgit.freedesktop.org/~airlied/linux/commit/?h=switchy-wip&id=f7acbeae3e997750c3d23a56ad1501d4aeb0d896
Matthew Garrett came up with a simpler approach, he added a callback
reprobe_connectors() which gets invoked in vga_switcheroo_enable():
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0014-vga_switcheroo-Add-support-for-reprobing-connectors.patch
The latter approach is further refined in the following patchset by
invoking the callback as soon as gmux registers, which is earlier
than in Matthew Garrett's patch since vga_switcheroo_enable() waits
for registration of a second gpu. (It may never register if its
driver is blacklisted or not installed.)
The following issues currently remain:
- Sometimes there's flickering when switching, so the user experience is
not yet as smooth as on OS X. (On OS X there's never any flickering.)
- If gmux registers *before* the i915 driver, the latter will find the
LVDS connector plus a disconnected VGA connector. If gmux registers
*after* the i915 driver, the latter initially only finds the VGA
connector. Upon reprobe it will find the LVDS connector and *another*
(ghost) VGA connector. That's because I call intel_setup_outputs()
which probes for all sorts of connectors. Matthew Garrett duplicated
that function and reduced it to just the eDP probing portion (which
is not sufficient since pre-retina MBPs used LVDS):
http://www.codon.org.uk/~mjg59/tmp/retina_patches/0024-i915-Add-support-for-reprobing-for-a-panel.patch
It would be great if Intel developers could give advice on how to
best integrate reprobing with their driver or how detection of
ghost VGA connectors can be avoided.
- The Nvidia gpu sometimes gets stuck in powersaving mode and refuses
to wake up ("Refused to change power state, currently in D3").
It seems that a delay is necessary between putting the device in
D3hot and cutting the power. (On MBPs, power is cut by the gmux.)
I added a delay of 200 usec and this seems to work most of the time
but not always. My impression is that the required length of the
delay is somehow heat related: I stress tested the code by switching
back and forth in an endless loop, causing the fans to spin fast as
the constant powerup and powerdown seems to draw a lot of energy,
and after about 5 minutes of constant switching the Nvidia gpu gets
stuck in D3 even if the delay is increased to 2 seconds. Using D3cold
instead of D3hot didn't help either.
Kind regards,
Lukas
Dave Airlie (1):
vga_switcheroo: Lock/unlock DDC lines
Lukas Wunner (5):
vga_switcheroo: Lock/unlock DDC lines harder
Revert "vga_switcheroo: Add helper function to get the active client"
vga_switcheroo: Reprobe connectors if handler registers late
drm/i915: Reprobe connectors if vga_switcheroo handler registers late
drm/nouveau: Pause between setting gpu to D3hot and cutting the power
Matthew Garrett (1):
apple-gmux: Assign apple_gmux_data before registering
Seth Forshee (4):
vga_switcheroo: Add support for switching only the DDC
vga_switcheroo: Add helper function to get the active client
apple-gmux: Add switch_ddc support
drm/edid: Switch DDC when reading the EDID
drivers/gpu/drm/drm_edid.c | 10 +++-
drivers/gpu/drm/i915/i915_dma.c | 40 +++++++++++++
drivers/gpu/drm/i915/i915_drv.h | 1 +
drivers/gpu/drm/i915/intel_display.c | 2 +-
drivers/gpu/drm/i915/intel_dp.c | 6 +-
drivers/gpu/drm/nouveau/nouveau_drm.c | 2 +
drivers/gpu/vga/vga_switcheroo.c | 105 +++++++++++++++++++++++++++++++++-
drivers/platform/x86/apple-gmux.c | 35 ++++++++++--
include/linux/vga_switcheroo.h | 7 +++
9 files changed, 196 insertions(+), 12 deletions(-)
-- >8 --
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c
index 53bc7a6..8950722 100644
--- a/drivers/gpu/drm/drm_edid.c
+++ b/drivers/gpu/drm/drm_edid.c
@@ -32,6 +32,7 @@
#include <linux/hdmi.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/vga_switcheroo.h>
#include <drm/drmP.h>
#include <drm/drm_edid.h>
#include <drm/drm_displayid.h>
@@ -1326,12 +1327,19 @@ struct edid *drm_get_edid(struct drm_connector *connector,
{
struct edid *edid;
- if (!drm_probe_ddc(adapter))
+ vga_switcheroo_lock_ddc(connector->dev->pdev);
+
+ if (!drm_probe_ddc(adapter)) {
+ vga_switcheroo_unlock_ddc(connector->dev->pdev);
return NULL;
+ }
edid = drm_do_get_edid(connector, drm_do_probe_ddc_edid, adapter);
if (edid)
drm_get_displayid(connector, edid);
+
+ vga_switcheroo_unlock_ddc(connector->dev->pdev);
+
return edid;
}
EXPORT_SYMBOL(drm_get_edid);
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 68e0c85..86726b7 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -379,9 +379,49 @@ static bool i915_switcheroo_can_switch(struct pci_dev *pdev)
return dev->open_count == 0;
}
+static void i915_switcheroo_reprobe_connectors(struct pci_dev *pdev)
+{
+ struct drm_device *dev = pci_get_drvdata(pdev);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_encoder *encoder;
+
+ /*
+ * Check whether we've already found a panel.
+ * If so, we don't need to reprobe
+ */
+ for_each_intel_encoder(dev, encoder)
+ if (encoder->type == INTEL_OUTPUT_LVDS ||
+ encoder->type == INTEL_OUTPUT_EDP)
+ return;
+
+ /*
+ * intel_modeset_gem_init() sets lvds_use_ssc to 0,
+ * reset to 1 so that the SSC gets used on the panel
+ */
+ dev_priv->vbt.lvds_use_ssc =
+ !(i915.panel_use_ssc == 0 ||
+ dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
+ intel_setup_outputs(dev);
+
+ /* Destroy default 1024x768 fbdev and reinitialize */
+ intel_fbdev_fini(dev);
+ if (intel_fbdev_init(dev))
+ goto cleanup_gem;
+ async_schedule(intel_fbdev_initial_config, dev_priv);
+ return;
+
+cleanup_gem:
+ DRM_ERROR("failed to reinitialize fbdev\n");
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_cleanup_ringbuffer(dev);
+ i915_gem_context_fini(dev);
+ mutex_unlock(&dev->struct_mutex);
+}
+
static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
.set_gpu_state = i915_switcheroo_set_state,
.reprobe = NULL,
+ .reprobe_connectors = i915_switcheroo_reprobe_connectors,
.can_switch = i915_switcheroo_can_switch,
};
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e326ac9..7f58858 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -3120,6 +3120,7 @@ extern void intel_set_memory_cxsr(struct drm_i915_private *dev_priv,
extern void intel_detect_pch(struct drm_device *dev);
extern int intel_trans_dp_port_sel(struct drm_crtc *crtc);
extern int intel_enable_rc6(const struct drm_device *dev);
+extern void intel_setup_outputs(struct drm_device *dev);
extern bool i915_semaphore_is_enabled(struct drm_device *dev);
int i915_reg_read_ioctl(struct drm_device *dev, void *data,
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index d547d9c8..9481206 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -13027,7 +13027,7 @@ static bool intel_crt_present(struct drm_device *dev)
return true;
}
-static void intel_setup_outputs(struct drm_device *dev)
+void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index d023710..e9c40b1 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -30,6 +30,7 @@
#include <linux/export.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
+#include <linux/vga_switcheroo.h>
#include <drm/drmP.h>
#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
@@ -4079,6 +4080,7 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
{
uint8_t *dpcd = intel_dp->dpcd;
uint8_t type;
+ struct pci_dev *pdev = intel_dp->attached_connector->base.dev->pdev;
if (!intel_dp_get_dpcd(intel_dp))
return connector_status_disconnected;
@@ -4101,7 +4103,9 @@ intel_dp_detect_dpcd(struct intel_dp *intel_dp)
}
/* If no HPD, poke DDC gently */
- if (drm_probe_ddc(&intel_dp->aux.ddc))
+ if (vga_switcheroo_lock_ddc(pdev) >= 0 &&
+ drm_probe_ddc(&intel_dp->aux.ddc) &&
+ vga_switcheroo_unlock_ddc(pdev) >= 0)
return connector_status_connected;
/* Well we tried, say unknown for unreliable port types */
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 8904933..649024d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -23,6 +23,7 @@
*/
#include <linux/console.h>
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pm_runtime.h>
@@ -666,6 +667,7 @@ nouveau_pmops_suspend(struct device *dev)
pci_save_state(pdev);
pci_disable_device(pdev);
pci_set_power_state(pdev, PCI_D3hot);
+ udelay(200);
return 0;
}
diff --git a/drivers/gpu/vga/vga_switcheroo.c b/drivers/gpu/vga/vga_switcheroo.c
index 37ac7b5..3b13e9a 100644
--- a/drivers/gpu/vga/vga_switcheroo.c
+++ b/drivers/gpu/vga/vga_switcheroo.c
@@ -9,12 +9,13 @@
Switcher interface - methods require for ATPX and DCM
- switchto - this throws the output MUX switch
- - discrete_set_power - sets the power state for the discrete card
+ - switch_ddc - switch only DDC lines, return old DDC owner (or < 0 on failure)
+ - power_state - sets the power state for either GPU
GPU driver interface
- set_gpu_state - this should do the equiv of s/r for the card
- this should *not* set the discrete power state
- - switch_check - check if the device is in a position to switch now
+ - can_switch - check if the device is in a position to switch now
*/
#include <linux/module.h>
@@ -57,6 +58,9 @@ struct vgasr_priv {
struct list_head clients;
struct vga_switcheroo_handler *handler;
+
+ struct mutex ddc_lock;
+ enum vga_switcheroo_client_id old_ddc_owner;
};
#define ID_BIT_AUDIO 0x100
@@ -70,6 +74,7 @@ static void vga_switcheroo_debugfs_fini(struct vgasr_priv *priv);
/* only one switcheroo per system */
static struct vgasr_priv vgasr_priv = {
.clients = LIST_HEAD_INIT(vgasr_priv.clients),
+ .ddc_lock = __MUTEX_INITIALIZER(vgasr_priv.ddc_lock),
};
static bool vga_switcheroo_ready(void)
@@ -103,6 +108,8 @@ static void vga_switcheroo_enable(void)
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
{
+ struct vga_switcheroo_client *client;
+
mutex_lock(&vgasr_mutex);
if (vgasr_priv.handler) {
mutex_unlock(&vgasr_mutex);
@@ -110,6 +117,12 @@ int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler)
}
vgasr_priv.handler = handler;
+
+ /* clients which registered before the handler must reprobe */
+ list_for_each_entry(client, &vgasr_priv.clients, list)
+ if (!client->active && client->ops->reprobe_connectors)
+ client->ops->reprobe_connectors(client->pdev);
+
if (vga_switcheroo_ready()) {
printk(KERN_INFO "vga_switcheroo: enabled\n");
vga_switcheroo_enable();
@@ -256,6 +269,60 @@ void vga_switcheroo_client_fb_set(struct pci_dev *pdev,
}
EXPORT_SYMBOL(vga_switcheroo_client_fb_set);
+int vga_switcheroo_lock_ddc(struct pci_dev *pdev)
+{
+ int ret = 0;
+ int id;
+
+ if (!vgasr_priv.handler) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (vgasr_priv.handler->switch_ddc) {
+ mutex_lock(&vgasr_priv.ddc_lock);
+
+ id = vgasr_priv.handler->get_client_id(pdev);
+ ret = vgasr_priv.handler->switch_ddc(id);
+
+ if (ret < 0) {
+ mutex_unlock(&vgasr_priv.ddc_lock);
+ printk(KERN_ERR "vga_switcheroo: failed to switch DDC lines\n");
+ } else
+ vgasr_priv.old_ddc_owner = ret;
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_lock_ddc);
+
+int vga_switcheroo_unlock_ddc(struct pci_dev *pdev)
+{
+ int ret = 0;
+ int id;
+
+ if (!vgasr_priv.handler) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (vgasr_priv.handler->switch_ddc) {
+ id = vgasr_priv.handler->get_client_id(pdev);
+
+ if (vgasr_priv.old_ddc_owner != id)
+ ret = vgasr_priv.handler->switch_ddc(vgasr_priv.old_ddc_owner);
+ if (ret < 0)
+ printk(KERN_ERR "vga_switcheroo: failed to switch DDC lines\n");
+
+ mutex_unlock(&vgasr_priv.ddc_lock);
+ }
+
+out:
+ return ret;
+}
+EXPORT_SYMBOL(vga_switcheroo_unlock_ddc);
+
static int vga_switcheroo_show(struct seq_file *m, void *v)
{
struct vga_switcheroo_client *client;
@@ -353,9 +420,25 @@ static int vga_switchto_stage2(struct vga_switcheroo_client *new_client)
console_unlock();
}
+ if (vgasr_priv.handler->switch_ddc) {
+ mutex_lock(&vgasr_priv.ddc_lock);
+ ret = vgasr_priv.handler->switch_ddc(new_client->id);
+ mutex_unlock(&vgasr_priv.ddc_lock);
+ if (ret < 0) {
+ printk(KERN_ERR "vga_switcheroo: failed to switch DDC lines\n");
+ return ret;
+ }
+ }
+
ret = vgasr_priv.handler->switchto(new_client->id);
- if (ret)
+ if (ret) {
+ printk(KERN_ERR "vga_switcheroo: failed to switch to client %d\n", new_client->id);
+ /* restore DDC lines */
+ mutex_lock(&vgasr_priv.ddc_lock);
+ vgasr_priv.handler->switch_ddc(active->id);
+ mutex_unlock(&vgasr_priv.ddc_lock);
return ret;
+ }
if (new_client->ops->reprobe)
new_client->ops->reprobe(new_client->pdev);
@@ -468,6 +551,15 @@ vga_switcheroo_debugfs_write(struct file *filp, const char __user *ubuf,
vgasr_priv.delayed_switch_active = false;
if (just_mux) {
+ if (vgasr_priv.handler->switch_ddc) {
+ mutex_lock(&vgasr_priv.ddc_lock);
+ ret = vgasr_priv.handler->switch_ddc(client_id);
+ mutex_unlock(&vgasr_priv.ddc_lock);
+ if (ret < 0) {
+ printk(KERN_ERR "vga_switcheroo: failed to switch DDC lines\n");
+ goto out;
+ }
+ }
ret = vgasr_priv.handler->switchto(client_id);
goto out;
}
@@ -623,6 +715,13 @@ static int vga_switcheroo_runtime_suspend(struct device *dev)
ret = dev->bus->pm->runtime_suspend(dev);
if (ret)
return ret;
+ if (vgasr_priv.handler->switch_ddc) {
+ mutex_lock(&vgasr_priv.ddc_lock);
+ ret = vgasr_priv.handler->switch_ddc(VGA_SWITCHEROO_IGD);
+ mutex_unlock(&vgasr_priv.ddc_lock);
+ if (ret < 0)
+ printk(KERN_ERR "vga_switcheroo: failed to switch DDC lines\n");
+ }
if (vgasr_priv.handler->switchto)
vgasr_priv.handler->switchto(VGA_SWITCHEROO_IGD);
vga_switcheroo_power_switch(pdev, VGA_SWITCHEROO_OFF);
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index b9429fb..05bba92 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -271,14 +271,34 @@ static const struct backlight_ops gmux_bl_ops = {
.update_status = gmux_update_status,
};
+static int gmux_switch_ddc(enum vga_switcheroo_client_id id)
+{
+ enum vga_switcheroo_client_id old_ddc_owner;
+
+ if (gmux_read8(apple_gmux_data, GMUX_PORT_SWITCH_DDC) == 1)
+ old_ddc_owner = VGA_SWITCHEROO_IGD;
+ else
+ old_ddc_owner = VGA_SWITCHEROO_DIS;
+
+ pr_debug("Switching gmux DDC from %d to %d\n", old_ddc_owner, id);
+
+ if (id == old_ddc_owner)
+ return old_ddc_owner;
+
+ if (id == VGA_SWITCHEROO_IGD)
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
+ else
+ gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
+
+ return old_ddc_owner;
+}
+
static int gmux_switchto(enum vga_switcheroo_client_id id)
{
if (id == VGA_SWITCHEROO_IGD) {
- gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 1);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 2);
} else {
- gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DDC, 2);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_DISPLAY, 3);
gmux_write8(apple_gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
}
@@ -345,6 +365,7 @@ gmux_active_client(struct apple_gmux_data *gmux_data)
}
static struct vga_switcheroo_handler gmux_handler = {
+ .switch_ddc = gmux_switch_ddc,
.switchto = gmux_switchto,
.power_state = gmux_set_power_state,
.get_client_id = gmux_get_client_id,
@@ -552,18 +573,20 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
gmux_data->gpe = -1;
}
+ apple_gmux_data = gmux_data;
+ init_completion(&gmux_data->powerchange_done);
+ gmux_enable_interrupts(gmux_data);
+
if (vga_switcheroo_register_handler(&gmux_handler)) {
ret = -ENODEV;
goto err_register_handler;
}
- init_completion(&gmux_data->powerchange_done);
- apple_gmux_data = gmux_data;
- gmux_enable_interrupts(gmux_data);
-
return 0;
err_register_handler:
+ gmux_disable_interrupts(gmux_data);
+ apple_gmux_data = NULL;
if (gmux_data->gpe >= 0)
acpi_disable_gpe(NULL, gmux_data->gpe);
err_enable_gpe:
diff --git a/include/linux/vga_switcheroo.h b/include/linux/vga_switcheroo.h
index b483abd..c3ad8bf 100644
--- a/include/linux/vga_switcheroo.h
+++ b/include/linux/vga_switcheroo.h
@@ -29,6 +29,7 @@ enum vga_switcheroo_client_id {
};
struct vga_switcheroo_handler {
+ int (*switch_ddc)(enum vga_switcheroo_client_id id);
int (*switchto)(enum vga_switcheroo_client_id id);
int (*power_state)(enum vga_switcheroo_client_id id,
enum vga_switcheroo_state state);
@@ -39,6 +40,7 @@ struct vga_switcheroo_handler {
struct vga_switcheroo_client_ops {
void (*set_gpu_state)(struct pci_dev *dev, enum vga_switcheroo_state);
void (*reprobe)(struct pci_dev *dev);
+ void (*reprobe_connectors)(struct pci_dev *dev);
bool (*can_switch)(struct pci_dev *dev);
};
@@ -54,6 +56,9 @@ int vga_switcheroo_register_audio_client(struct pci_dev *pdev,
void vga_switcheroo_client_fb_set(struct pci_dev *dev,
struct fb_info *info);
+int vga_switcheroo_lock_ddc(struct pci_dev *pdev);
+int vga_switcheroo_unlock_ddc(struct pci_dev *pdev);
+
int vga_switcheroo_register_handler(struct vga_switcheroo_handler *handler);
void vga_switcheroo_unregister_handler(void);
@@ -72,6 +77,8 @@ static inline void vga_switcheroo_unregister_client(struct pci_dev *dev) {}
static inline int vga_switcheroo_register_client(struct pci_dev *dev,
const struct vga_switcheroo_client_ops *ops, bool driver_power_control) { return 0; }
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 0; }
+static inline int vga_switcheroo_unlock_ddc(struct pci_dev *pdev) { return 0; }
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,
--
1.8.5.2 (Apple Git-48)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering
2015-04-21 9:58 [PATCH 00/11] Enable gpu switching on the MacBook Pro Lukas Wunner
@ 2014-03-05 22:34 ` Lukas Wunner
0 siblings, 0 replies; 17+ messages in thread
From: Lukas Wunner @ 2014-03-05 22:34 UTC (permalink / raw)
To: dri-devel; +Cc: Daniel Vetter, Seth Forshee, Matthew Garrett, Dave Airlie
From: Matthew Garrett <matthew.garrett@nebula.com>
Registering the handler after both GPUs will trigger a DDC switch for
connector reprobing. This will oops if apple_gmux_data hasn't already been
assigned. Reorder the code to do that.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
drivers/platform/x86/apple-gmux.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index 9aafbde..05bba92 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -573,18 +573,20 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
gmux_data->gpe = -1;
}
+ apple_gmux_data = gmux_data;
+ init_completion(&gmux_data->powerchange_done);
+ gmux_enable_interrupts(gmux_data);
+
if (vga_switcheroo_register_handler(&gmux_handler)) {
ret = -ENODEV;
goto err_register_handler;
}
- init_completion(&gmux_data->powerchange_done);
- apple_gmux_data = gmux_data;
- gmux_enable_interrupts(gmux_data);
-
return 0;
err_register_handler:
+ gmux_disable_interrupts(gmux_data);
+ apple_gmux_data = NULL;
if (gmux_data->gpe >= 0)
acpi_disable_gpe(NULL, gmux_data->gpe);
err_enable_gpe:
--
1.8.5.2 (Apple Git-48)
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/dri-devel
^ permalink raw reply related [flat|nested] 17+ messages in thread
end of thread, other threads:[~2015-04-21 11:36 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-01 16:38 Improve Apple GMUX support on switcheroo Matthew Garrett
2014-06-01 16:38 ` [PATCH 01/11] vga_switcheroo: Add support for switching only the DDC Matthew Garrett
2014-06-03 13:26 ` Jani Nikula
2014-06-12 0:37 ` Dave Airlie
2014-06-01 16:38 ` [PATCH 02/11] vga_switcheroo: Add support for reprobing connectors Matthew Garrett
2014-06-01 16:38 ` [PATCH 03/11] vga_switcheroo: Add command line option Matthew Garrett
2014-06-01 16:38 ` [PATCH 04/11] vga_switcheroo: Allow stashing of panel data Matthew Garrett
2014-06-03 13:40 ` Jani Nikula
2014-06-01 16:38 ` [PATCH 05/11] vga_switcheroo: Allow handlers to indicate that they can handle PM Matthew Garrett
2014-06-01 16:38 ` [PATCH 06/11] vga_switcheroo: Add enable() call to clients and permit deferral of dynamic PM Matthew Garrett
2014-06-01 16:38 ` [PATCH 07/11] vga_switcheroo: Reprobe old device on switching Matthew Garrett
2014-06-01 16:38 ` [PATCH 08/11] apple-gmux: Add support for the switch_ddc callback Matthew Garrett
2014-06-02 14:35 ` Alex Deucher
2014-06-01 16:38 ` [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering Matthew Garrett
2014-06-01 16:38 ` [PATCH 10/11] apple-gmux: Indicate that driver supports changing of GPU power states Matthew Garrett
2014-06-01 16:38 ` [PATCH 11/11] apple_gmux: Wait for switch completion Matthew Garrett
2015-04-21 9:58 [PATCH 00/11] Enable gpu switching on the MacBook Pro Lukas Wunner
2014-03-05 22:34 ` [PATCH 09/11] apple-gmux: Assign apple_gmux_data before registering Lukas Wunner
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.