|
@@ -60,6 +60,7 @@ struct apple_gmux_data {
|
|
|
/* switcheroo data */
|
|
|
acpi_handle dhandle;
|
|
|
int gpe;
|
|
|
+ bool external_switchable;
|
|
|
enum vga_switcheroo_client_id switch_state_display;
|
|
|
enum vga_switcheroo_client_id switch_state_ddc;
|
|
|
enum vga_switcheroo_client_id switch_state_external;
|
|
@@ -358,6 +359,19 @@ static const struct backlight_ops gmux_bl_ops = {
|
|
|
* ports while the discrete GPU is asleep, but currently we do not make use
|
|
|
* of this feature.
|
|
|
*
|
|
|
+ * Our switching policy for the external port is that on those generations
|
|
|
+ * which are able to switch it fully, the port is switched together with the
|
|
|
+ * panel when IGD / DIS commands are issued to vga_switcheroo. It is thus
|
|
|
+ * possible to drive e.g. a beamer on battery power with the integrated GPU.
|
|
|
+ * The user may manually switch to the discrete GPU if more performance is
|
|
|
+ * needed.
|
|
|
+ *
|
|
|
+ * On all newer generations, the external port can only be driven by the
|
|
|
+ * discrete GPU. If a display is plugged in while the panel is switched to
|
|
|
+ * the integrated GPU, *both* GPUs will be in use for maximum performance.
|
|
|
+ * To decrease power consumption, the user may manually switch to the
|
|
|
+ * discrete GPU, thereby suspending the integrated GPU.
|
|
|
+ *
|
|
|
* gmux' initial switch state on bootup is user configurable via the EFI
|
|
|
* variable ``gpu-power-prefs-fa4ce28d-b62f-4c99-9cc3-6815686e30f9`` (5th byte,
|
|
|
* 1 = IGD, 0 = DIS). Based on this setting, the EFI firmware tells gmux to
|
|
@@ -414,7 +428,8 @@ static int gmux_switchto(enum vga_switcheroo_client_id id)
|
|
|
{
|
|
|
apple_gmux_data->switch_state_ddc = id;
|
|
|
apple_gmux_data->switch_state_display = id;
|
|
|
- apple_gmux_data->switch_state_external = id;
|
|
|
+ if (apple_gmux_data->external_switchable)
|
|
|
+ apple_gmux_data->switch_state_external = id;
|
|
|
|
|
|
gmux_write_switch_state(apple_gmux_data);
|
|
|
|
|
@@ -601,6 +616,11 @@ static struct pci_dev *gmux_get_io_pdev(void)
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
+static int is_thunderbolt(struct device *dev, void *data)
|
|
|
+{
|
|
|
+ return to_pci_dev(dev)->is_thunderbolt;
|
|
|
+}
|
|
|
+
|
|
|
static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|
|
{
|
|
|
struct apple_gmux_data *gmux_data;
|
|
@@ -755,6 +775,15 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
|
|
|
gmux_data->gpe = -1;
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * If Thunderbolt is present, the external DP port is not fully
|
|
|
+ * switchable. Force its AUX channel to the discrete GPU.
|
|
|
+ */
|
|
|
+ gmux_data->external_switchable =
|
|
|
+ !bus_for_each_dev(&pci_bus_type, NULL, NULL, is_thunderbolt);
|
|
|
+ if (!gmux_data->external_switchable)
|
|
|
+ gmux_write8(gmux_data, GMUX_PORT_SWITCH_EXTERNAL, 3);
|
|
|
+
|
|
|
apple_gmux_data = gmux_data;
|
|
|
init_completion(&gmux_data->powerchange_done);
|
|
|
gmux_enable_interrupts(gmux_data);
|