Prechádzať zdrojové kódy

Add dGPU hot-plug/power-setting support

qzed 6 rokov pred
rodič
commit
2009a8d721

+ 1 - 1
patches/4.19/0001-surface-acpi.patch

@@ -1,7 +1,7 @@
 From e9f55e5da497d27e0908cbffd3ecd0e8f1369ddb Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:43:58 +0200
-Subject: [PATCH 01/11] surface-acpi
+Subject: [PATCH 01/12] surface-acpi
 
 ---
  drivers/acpi/acpica/dsopcode.c      |    2 +-

+ 1 - 1
patches/4.19/0002-suspend.patch

@@ -1,7 +1,7 @@
 From e851005607738247775e43e9ac4336edd4c09516 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:45:42 +0200
-Subject: [PATCH 02/11] suspend
+Subject: [PATCH 02/12] suspend
 
 ---
  drivers/nvme/host/nvme.h |  5 +++++

+ 1 - 1
patches/4.19/0003-buttons.patch

@@ -1,7 +1,7 @@
 From ba453a89148ea2289e71741225273a02ae2db768 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:49:56 +0200
-Subject: [PATCH 03/11] buttons
+Subject: [PATCH 03/12] buttons
 
 ---
  drivers/input/misc/soc_button_array.c     | 145 ++++++++++++++++++++--

+ 1 - 1
patches/4.19/0004-cameras.patch

@@ -1,7 +1,7 @@
 From 4f79924d2848c13e9a0830c0c575421768f8d58a Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:50:29 +0200
-Subject: [PATCH 04/11] cameras
+Subject: [PATCH 04/12] cameras
 
 ---
  drivers/media/usb/uvc/uvc_driver.c |   40 +

+ 1 - 1
patches/4.19/0005-ipts.patch

@@ -1,7 +1,7 @@
 From aa2ce90ff8ee8ad90a5e84004b748e709167bd0f Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:50:47 +0200
-Subject: [PATCH 05/11] ipts
+Subject: [PATCH 05/12] ipts
 
 ---
  drivers/gpu/drm/i915/Makefile               |    3 +

+ 1 - 1
patches/4.19/0006-hid.patch

@@ -1,7 +1,7 @@
 From 3895e7b026d525d70fdc0f4a6dd59b08c9f44022 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:51:26 +0200
-Subject: [PATCH 06/11] hid
+Subject: [PATCH 06/12] hid
 
 ---
  drivers/hid/hid-ids.h        | 21 +++++++++----

+ 1 - 1
patches/4.19/0007-sdcard-reader.patch

@@ -1,7 +1,7 @@
 From 4cbc99c208e1938349aec603aee10b202a54f54a Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:51:55 +0200
-Subject: [PATCH 07/11] sdcard-reader
+Subject: [PATCH 07/12] sdcard-reader
 
 ---
  drivers/usb/core/hub.c | 3 ++-

+ 1 - 1
patches/4.19/0008-wifi.patch

@@ -1,7 +1,7 @@
 From 52cb41ede0999511587b9a2523771238c12f8033 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:52:12 +0200
-Subject: [PATCH 08/11] wifi
+Subject: [PATCH 08/12] wifi
 
 ---
  drivers/net/wireless/marvell/mwifiex/11n_aggr.c |  3 +--

+ 1 - 1
patches/4.19/0009-surface3-power.patch

@@ -1,7 +1,7 @@
 From 09ddddeb396321184eb2591c20e681d48623c34d Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:52:29 +0200
-Subject: [PATCH 09/11] surface3-power
+Subject: [PATCH 09/12] surface3-power
 
 ---
  drivers/platform/x86/Kconfig          |   7 +

+ 1 - 1
patches/4.19/0010-mwlwifi.patch

@@ -1,7 +1,7 @@
 From d27de602a55f146e79c125287e6dbc3aa70ded38 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:52:52 +0200
-Subject: [PATCH 10/11] mwlwifi
+Subject: [PATCH 10/12] mwlwifi
 
 ---
  drivers/net/wireless/marvell/Kconfig          |    1 +

+ 1 - 1
patches/4.19/0011-surface-lte.patch

@@ -1,7 +1,7 @@
 From 4b31faa2ddaffa6e6963c54ff6574178de94918e Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Tue, 2 Jul 2019 23:53:15 +0200
-Subject: [PATCH 11/11] surface-lte
+Subject: [PATCH 11/12] surface-lte
 
 ---
  drivers/usb/serial/qcserial.c | 1 +

+ 359 - 0
patches/4.19/0012-surfacebook2-dgpu.patch

@@ -0,0 +1,359 @@
+From c7eb71b21227f0ee6b46a13c9b4f9df49dd23979 Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Tue, 2 Jul 2019 23:58:22 +0200
+Subject: [PATCH 12/12] surfacebook2-dgpu
+
+---
+ drivers/platform/x86/Kconfig                 |   9 +
+ drivers/platform/x86/Makefile                |   1 +
+ drivers/platform/x86/surfacebook2_dgpu_hps.c | 306 +++++++++++++++++++
+ 3 files changed, 316 insertions(+)
+ create mode 100644 drivers/platform/x86/surfacebook2_dgpu_hps.c
+
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index d6695d8fc795..16f40109337c 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -436,6 +436,15 @@ config SURFACE3_WMI
+ 	  To compile this driver as a module, choose M here: the module will
+ 	  be called surface3-wmi.
+ 
++config SURFACE_BOOK2_DGPU_HPS
++	tristate "Surface Book 2 dGPU Hot-Plug System Driver"
++	depends on ACPI
++	---help---
++	  This is an experimetnal driver to control the power-state of the
++	  Surface Book 2 dGPU.
++
++	  If you have a Surface Book 2, say Y or M here.
++
+ config THINKPAD_ACPI
+ 	tristate "ThinkPad ACPI Laptop Extras"
+ 	depends on ACPI
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index dd045ccf3a90..6d24ede71496 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -45,6 +45,7 @@ obj-$(CONFIG_ACPI_WMI)		+= wmi.o
+ obj-$(CONFIG_MSI_WMI)		+= msi-wmi.o
+ obj-$(CONFIG_PEAQ_WMI)		+= peaq-wmi.o
+ obj-$(CONFIG_SURFACE3_WMI)	+= surface3-wmi.o
++obj-$(CONFIG_SURFACE_BOOK2_DGPU_HPS)	+= surfacebook2_dgpu_hps.o
+ obj-$(CONFIG_TOPSTAR_LAPTOP)	+= topstar-laptop.o
+ obj-$(CONFIG_WMI_BMOF)		+= wmi-bmof.o
+ obj-$(CONFIG_INTEL_WMI_THUNDERBOLT)	+= intel-wmi-thunderbolt.o
+diff --git a/drivers/platform/x86/surfacebook2_dgpu_hps.c b/drivers/platform/x86/surfacebook2_dgpu_hps.c
+new file mode 100644
+index 000000000000..7639fb0029d8
+--- /dev/null
++++ b/drivers/platform/x86/surfacebook2_dgpu_hps.c
+@@ -0,0 +1,306 @@
++#include <linux/acpi.h>
++#include <linux/gpio.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/sysfs.h>
++
++#include <linux/uaccess.h>
++
++
++#define SB2_SHPS_DSM_REVISION	1
++#define SB2_SHPS_DSM_GPU_STATE	0x05
++
++static const guid_t SB2_SHPS_DSM_UUID =
++	GUID_INIT(0x5515a847, 0xed55, 0x4b27, 0x83, 0x52, 0xcd,
++	          0x32, 0x0e, 0x10, 0x36, 0x0a);
++
++#define SB2_PARAM_PERM		(S_IRUGO | S_IWUSR)
++
++
++static const struct acpi_gpio_params gpio_base_presence_int = { 0, 0, false };
++static const struct acpi_gpio_params gpio_base_presence     = { 1, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_power_int    = { 2, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_power        = { 3, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_presence_int = { 4, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_presence     = { 5, 0, false };
++
++static const struct acpi_gpio_mapping sb2_mshw0153_acpi_gpios[] = {
++	{ "base_presence-int-gpio", &gpio_base_presence_int, 1 },
++	{ "base_presence-gpio",     &gpio_base_presence,     1 },
++	{ "dgpu_power-int-gpio",    &gpio_dgpu_power_int,    1 },
++	{ "dgpu_power-gpio",        &gpio_dgpu_power,        1 },
++	{ "dgpu_presence-int-gpio", &gpio_dgpu_presence_int, 1 },
++	{ "dgpu_presence-gpio",     &gpio_dgpu_presence,     1 },
++	{ },
++};
++
++
++enum sb2_dgpu_power {
++	SB2_DGPU_POWER_OFF      = 0,
++	SB2_DGPU_POWER_ON       = 1,
++
++	__SB2_DGPU_POWER__START = 0,
++	__SB2_DGPU_POWER__END   = 1,
++};
++
++enum sb2_param_dgpu_power {
++	SB2_PARAM_DGPU_POWER_OFF      = SB2_DGPU_POWER_OFF,
++	SB2_PARAM_DGPU_POWER_ON       = SB2_DGPU_POWER_ON,
++	SB2_PARAM_DGPU_POWER_AS_IS    = 2,
++
++	__SB2_PARAM_DGPU_POWER__START = 0,
++	__SB2_PARAM_DGPU_POWER__END   = 2,
++};
++
++static const char* sb2_dgpu_power_str(enum sb2_dgpu_power power) {
++	if (power == SB2_DGPU_POWER_OFF) {
++		return "off";
++	} else if (power == SB2_DGPU_POWER_ON) {
++		return "on";
++	} else {
++		return "<invalid>";
++	}
++}
++
++
++struct sb2_shps_driver_data {
++	struct mutex dgpu_power_lock;
++	enum sb2_dgpu_power dgpu_power;
++};
++
++
++static int __sb2_shps_dgpu_set_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
++	union acpi_object *result;
++	union acpi_object param;
++
++	param.type = ACPI_TYPE_INTEGER;
++	param.integer.value = power == SB2_DGPU_POWER_ON;
++
++	result = acpi_evaluate_dsm_typed(handle, &SB2_SHPS_DSM_UUID, SB2_SHPS_DSM_REVISION,
++	                                 SB2_SHPS_DSM_GPU_STATE, &param, ACPI_TYPE_BUFFER);
++
++	if (IS_ERR_OR_NULL(result)) {
++		return result ? PTR_ERR(result) : -EFAULT;
++	}
++
++	if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
++		return -EIO;
++	}
++
++	drvdata->dgpu_power = power;
++
++	printk(KERN_INFO "sb2_shps: dGPU power state set to \'%s\'\n", sb2_dgpu_power_str(power));
++
++	ACPI_FREE(result);
++	return 0;
++}
++
++static int sb2_shps_dgpu_set_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	int status = 0;
++
++	if (power < __SB2_DGPU_POWER__START || power > __SB2_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	mutex_lock(&drvdata->dgpu_power_lock);
++	if (power != drvdata->dgpu_power) {
++		status = __sb2_shps_dgpu_set_power(pdev, power);
++	}
++	mutex_unlock(&drvdata->dgpu_power_lock);
++
++	return status;
++}
++
++static int sb2_shps_dgpu_force_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	int status;
++
++	if (power < __SB2_DGPU_POWER__START || power > __SB2_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	mutex_lock(&drvdata->dgpu_power_lock);
++	status = __sb2_shps_dgpu_set_power(pdev, power);
++	mutex_unlock(&drvdata->dgpu_power_lock);
++
++	return status;
++}
++
++
++static int param_dgpu_power_set(const char *val, const struct kernel_param *kp)
++{
++	int power = SB2_PARAM_DGPU_POWER_OFF;
++	int status;
++
++	status = kstrtoint(val, 0, &power);
++	if (status) {
++		return status;
++	}
++
++	if (power < __SB2_PARAM_DGPU_POWER__START || power > __SB2_PARAM_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	return param_set_int(val, kp);
++}
++
++static const struct kernel_param_ops param_dgpu_power_ops = {
++	.set = param_dgpu_power_set,
++	.get = param_get_int,
++};
++
++static int param_dgpu_power_init = SB2_PARAM_DGPU_POWER_OFF;
++static int param_dgpu_power_exit = SB2_PARAM_DGPU_POWER_OFF;
++
++module_param_cb(dgpu_power_init, &param_dgpu_power_ops, &param_dgpu_power_init, SB2_PARAM_PERM);
++module_param_cb(dgpu_power_exit, &param_dgpu_power_ops, &param_dgpu_power_exit, SB2_PARAM_PERM);
++
++MODULE_PARM_DESC(dgpu_power_init, "dGPU power state to be set on init (0: off / 1: on / 2: as-is)");
++MODULE_PARM_DESC(dgpu_power_exit, "dGPU power state to be set on exit (0: off / 1: on / 2: as-is)");
++
++
++static ssize_t dgpu_power_show(struct device *dev, struct device_attribute *attr, char *data)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++
++	return sprintf(data, "%s\n", sb2_dgpu_power_str(drvdata->dgpu_power));
++}
++
++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr,
++                                const char *data, size_t count)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	bool power = false;
++	int status;
++
++	status = kstrtobool(data, &power);
++	if (status) {
++		return status;
++	}
++
++	if (power) {
++		status = sb2_shps_dgpu_set_power(pdev, SB2_DGPU_POWER_ON);
++	} else {
++		status = sb2_shps_dgpu_set_power(pdev, SB2_DGPU_POWER_OFF);
++	}
++
++	return status < 0 ? status : count;
++}
++
++const static DEVICE_ATTR_RW(dgpu_power);
++
++
++#ifdef CONFIG_PM
++
++static int sb2_shps_resume(struct device *dev)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++
++	return sb2_shps_dgpu_force_power(pdev, drvdata->dgpu_power);
++}
++
++static SIMPLE_DEV_PM_OPS(sb2_shps_pm_ops, NULL, sb2_shps_resume);
++
++#endif
++
++
++static int sb2_shps_probe(struct platform_device *pdev)
++{
++	struct sb2_shps_driver_data *drvdata;
++	struct acpi_device *shps_dev = ACPI_COMPANION(&pdev->dev);
++	int status = 0;
++
++	if (gpiod_count(&pdev->dev, NULL) < 0) {
++		return -ENODEV;
++	}
++
++	status = acpi_dev_add_driver_gpios(shps_dev, sb2_mshw0153_acpi_gpios);
++	if (status) {
++		return status;
++	}
++
++	drvdata = kzalloc(sizeof(struct sb2_shps_driver_data), GFP_KERNEL);
++	if (!drvdata) {
++		status = -ENOMEM;
++		goto err_alloc_drvdata;
++	}
++
++	mutex_init(&drvdata->dgpu_power_lock);
++	drvdata->dgpu_power = SB2_DGPU_POWER_OFF;
++	platform_set_drvdata(pdev, drvdata);
++
++	if (param_dgpu_power_init != SB2_PARAM_DGPU_POWER_AS_IS) {
++		status = sb2_shps_dgpu_force_power(pdev, param_dgpu_power_init);
++		if (status) {
++			goto err_set_power;
++		}
++	}
++
++	status = sysfs_create_file(&pdev->dev.kobj, &dev_attr_dgpu_power.attr);
++	if (status) {
++		goto err_sysfs;
++	}
++
++	return 0;
++
++err_sysfs:
++	sb2_shps_dgpu_force_power(pdev, SB2_DGPU_POWER_OFF);
++err_set_power:
++	platform_set_drvdata(pdev, NULL);
++	kfree(drvdata);
++err_alloc_drvdata:
++	acpi_dev_remove_driver_gpios(shps_dev);
++	return status;
++}
++
++static int sb2_shps_remove(struct platform_device *pdev)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	struct acpi_device *shps_dev = ACPI_COMPANION(&pdev->dev);
++
++	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_dgpu_power.attr);
++
++	if (param_dgpu_power_exit != SB2_PARAM_DGPU_POWER_AS_IS) {
++		sb2_shps_dgpu_set_power(pdev, param_dgpu_power_exit);
++	}
++	acpi_dev_remove_driver_gpios(shps_dev);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(drvdata);
++
++	return 0;
++}
++
++
++static const struct acpi_device_id sb2_shps_acpi_match[] = {
++	{ "MSHW0153", 0 },
++	{ },
++};
++MODULE_DEVICE_TABLE(acpi, sb2_shps_acpi_match);
++
++static struct platform_driver sb2_shps_driver = {
++	.probe = sb2_shps_probe,
++	.remove = sb2_shps_remove,
++	.driver = {
++		.name = "sb2_shps",
++		.acpi_match_table = ACPI_PTR(sb2_shps_acpi_match),
++#ifdef CONFIG_PM
++		.pm = &sb2_shps_pm_ops,
++#endif
++	},
++};
++module_platform_driver(sb2_shps_driver);
++
++MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
++MODULE_DESCRIPTION("Surface Book 2 Hot-Plug System Driver");
++MODULE_LICENSE("GPL v2");
+-- 
+2.22.0
+

+ 1 - 1
patches/5.1/0001-surface-acpi.patch

@@ -1,7 +1,7 @@
 From d4d2fa3647f86b84ed6d38c8180cb020eb88627d Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:22:49 +0200
-Subject: [PATCH 01/11] surface-acpi
+Subject: [PATCH 01/12] surface-acpi
 
 ---
  drivers/acpi/acpica/dsopcode.c      |    2 +-

+ 1 - 1
patches/5.1/0002-suspend.patch

@@ -1,7 +1,7 @@
 From c2ae9c80d630190f67b102303f794277cd916d9f Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:24:31 +0200
-Subject: [PATCH 02/11] suspend
+Subject: [PATCH 02/12] suspend
 
 ---
  drivers/nvme/host/nvme.h |  5 +++++

+ 1 - 1
patches/5.1/0003-buttons.patch

@@ -1,7 +1,7 @@
 From 8b583fd83792f28f23461186b0c44d9c1554204e Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:25:27 +0200
-Subject: [PATCH 03/11] buttons
+Subject: [PATCH 03/12] buttons
 
 ---
  drivers/input/misc/soc_button_array.c     | 145 ++++++++++++++++++++--

+ 1 - 1
patches/5.1/0004-cameras.patch

@@ -1,7 +1,7 @@
 From ee99ccaced33d4db9d807b5452507c2b4257f595 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:27:27 +0200
-Subject: [PATCH 04/11] cameras
+Subject: [PATCH 04/12] cameras
 
 ---
  drivers/media/usb/uvc/uvc_driver.c |   40 +

+ 1 - 1
patches/5.1/0005-ipts.patch

@@ -1,7 +1,7 @@
 From fa6be7e31d29959edc738986507fed1e1a877e2e Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:28:10 +0200
-Subject: [PATCH 05/11] ipts
+Subject: [PATCH 05/12] ipts
 
 ---
  drivers/gpu/drm/i915/Makefile               |    3 +

+ 1 - 1
patches/5.1/0006-hid.patch

@@ -1,7 +1,7 @@
 From d784fa6928c75c033a240d6db839c3aacd9edd33 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:28:41 +0200
-Subject: [PATCH 06/11] hid
+Subject: [PATCH 06/12] hid
 
 ---
  drivers/hid/hid-ids.h        | 21 +++++++++----

+ 1 - 1
patches/5.1/0007-sdcard-reader.patch

@@ -1,7 +1,7 @@
 From 1b434e8d2943d1c6a3fb9eb7936f8ecc5c1551e3 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:29:19 +0200
-Subject: [PATCH 07/11] sdcard-reader
+Subject: [PATCH 07/12] sdcard-reader
 
 ---
  drivers/usb/core/hub.c | 3 ++-

+ 1 - 1
patches/5.1/0008-wifi.patch

@@ -1,7 +1,7 @@
 From 8f2bb111745b57988030776899049153dadf2e3d Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:30:18 +0200
-Subject: [PATCH 08/11] wifi
+Subject: [PATCH 08/12] wifi
 
 ---
  drivers/net/wireless/marvell/mwifiex/11n_aggr.c |  3 +--

+ 1 - 1
patches/5.1/0009-surface3-power.patch

@@ -1,7 +1,7 @@
 From facb57708454c1424e5dffe2be999356fc88984a Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:30:44 +0200
-Subject: [PATCH 09/11] surface3-power
+Subject: [PATCH 09/12] surface3-power
 
 ---
  drivers/platform/x86/Kconfig          |   7 +

+ 1 - 1
patches/5.1/0010-mwlwifi.patch

@@ -1,7 +1,7 @@
 From 74d3a35c573f41861590ee786400067220c300b6 Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:31:18 +0200
-Subject: [PATCH 10/11] mwlwifi
+Subject: [PATCH 10/12] mwlwifi
 
 ---
  drivers/net/wireless/marvell/Kconfig          |    1 +

+ 1 - 1
patches/5.1/0011-surface-lte.patch

@@ -1,7 +1,7 @@
 From ba5ab6c097f826ef6ec92379383f8b9963b8f48c Mon Sep 17 00:00:00 2001
 From: Maximilian Luz <luzmaximilian@gmail.com>
 Date: Wed, 3 Jul 2019 00:32:00 +0200
-Subject: [PATCH 11/11] surface-lte
+Subject: [PATCH 11/12] surface-lte
 
 ---
  drivers/usb/serial/qcserial.c | 1 +

+ 359 - 0
patches/5.1/0012-surfacebook2-dgpu.patch

@@ -0,0 +1,359 @@
+From 42b801e957cc7aa47e7d6a869970c149d959b539 Mon Sep 17 00:00:00 2001
+From: Maximilian Luz <luzmaximilian@gmail.com>
+Date: Wed, 3 Jul 2019 00:35:24 +0200
+Subject: [PATCH 12/12] surfacebook2-dgpu
+
+---
+ drivers/platform/x86/Kconfig                 |   9 +
+ drivers/platform/x86/Makefile                |   1 +
+ drivers/platform/x86/surfacebook2_dgpu_hps.c | 306 +++++++++++++++++++
+ 3 files changed, 316 insertions(+)
+ create mode 100644 drivers/platform/x86/surfacebook2_dgpu_hps.c
+
+diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
+index 21ffc03cd372..200d4d55da98 100644
+--- a/drivers/platform/x86/Kconfig
++++ b/drivers/platform/x86/Kconfig
+@@ -483,6 +483,15 @@ config SURFACE3_WMI
+ 	  To compile this driver as a module, choose M here: the module will
+ 	  be called surface3-wmi.
+ 
++config SURFACE_BOOK2_DGPU_HPS
++	tristate "Surface Book 2 dGPU Hot-Plug System Driver"
++	depends on ACPI
++	---help---
++	  This is an experimetnal driver to control the power-state of the
++	  Surface Book 2 dGPU.
++
++	  If you have a Surface Book 2, say Y or M here.
++
+ config THINKPAD_ACPI
+ 	tristate "ThinkPad ACPI Laptop Extras"
+ 	depends on ACPI
+diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
+index 278ce32df99f..0faf98020b84 100644
+--- a/drivers/platform/x86/Makefile
++++ b/drivers/platform/x86/Makefile
+@@ -49,6 +49,7 @@ obj-$(CONFIG_ACPI_WMI)		+= wmi.o
+ obj-$(CONFIG_MSI_WMI)		+= msi-wmi.o
+ obj-$(CONFIG_PEAQ_WMI)		+= peaq-wmi.o
+ obj-$(CONFIG_SURFACE3_WMI)	+= surface3-wmi.o
++obj-$(CONFIG_SURFACE_BOOK2_DGPU_HPS)	+= surfacebook2_dgpu_hps.o
+ obj-$(CONFIG_TOPSTAR_LAPTOP)	+= topstar-laptop.o
+ obj-$(CONFIG_WMI_BMOF)		+= wmi-bmof.o
+ obj-$(CONFIG_INTEL_WMI_THUNDERBOLT)	+= intel-wmi-thunderbolt.o
+diff --git a/drivers/platform/x86/surfacebook2_dgpu_hps.c b/drivers/platform/x86/surfacebook2_dgpu_hps.c
+new file mode 100644
+index 000000000000..7639fb0029d8
+--- /dev/null
++++ b/drivers/platform/x86/surfacebook2_dgpu_hps.c
+@@ -0,0 +1,306 @@
++#include <linux/acpi.h>
++#include <linux/gpio.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/platform_device.h>
++#include <linux/sysfs.h>
++
++#include <linux/uaccess.h>
++
++
++#define SB2_SHPS_DSM_REVISION	1
++#define SB2_SHPS_DSM_GPU_STATE	0x05
++
++static const guid_t SB2_SHPS_DSM_UUID =
++	GUID_INIT(0x5515a847, 0xed55, 0x4b27, 0x83, 0x52, 0xcd,
++	          0x32, 0x0e, 0x10, 0x36, 0x0a);
++
++#define SB2_PARAM_PERM		(S_IRUGO | S_IWUSR)
++
++
++static const struct acpi_gpio_params gpio_base_presence_int = { 0, 0, false };
++static const struct acpi_gpio_params gpio_base_presence     = { 1, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_power_int    = { 2, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_power        = { 3, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_presence_int = { 4, 0, false };
++static const struct acpi_gpio_params gpio_dgpu_presence     = { 5, 0, false };
++
++static const struct acpi_gpio_mapping sb2_mshw0153_acpi_gpios[] = {
++	{ "base_presence-int-gpio", &gpio_base_presence_int, 1 },
++	{ "base_presence-gpio",     &gpio_base_presence,     1 },
++	{ "dgpu_power-int-gpio",    &gpio_dgpu_power_int,    1 },
++	{ "dgpu_power-gpio",        &gpio_dgpu_power,        1 },
++	{ "dgpu_presence-int-gpio", &gpio_dgpu_presence_int, 1 },
++	{ "dgpu_presence-gpio",     &gpio_dgpu_presence,     1 },
++	{ },
++};
++
++
++enum sb2_dgpu_power {
++	SB2_DGPU_POWER_OFF      = 0,
++	SB2_DGPU_POWER_ON       = 1,
++
++	__SB2_DGPU_POWER__START = 0,
++	__SB2_DGPU_POWER__END   = 1,
++};
++
++enum sb2_param_dgpu_power {
++	SB2_PARAM_DGPU_POWER_OFF      = SB2_DGPU_POWER_OFF,
++	SB2_PARAM_DGPU_POWER_ON       = SB2_DGPU_POWER_ON,
++	SB2_PARAM_DGPU_POWER_AS_IS    = 2,
++
++	__SB2_PARAM_DGPU_POWER__START = 0,
++	__SB2_PARAM_DGPU_POWER__END   = 2,
++};
++
++static const char* sb2_dgpu_power_str(enum sb2_dgpu_power power) {
++	if (power == SB2_DGPU_POWER_OFF) {
++		return "off";
++	} else if (power == SB2_DGPU_POWER_ON) {
++		return "on";
++	} else {
++		return "<invalid>";
++	}
++}
++
++
++struct sb2_shps_driver_data {
++	struct mutex dgpu_power_lock;
++	enum sb2_dgpu_power dgpu_power;
++};
++
++
++static int __sb2_shps_dgpu_set_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	acpi_handle handle = ACPI_HANDLE(&pdev->dev);
++	union acpi_object *result;
++	union acpi_object param;
++
++	param.type = ACPI_TYPE_INTEGER;
++	param.integer.value = power == SB2_DGPU_POWER_ON;
++
++	result = acpi_evaluate_dsm_typed(handle, &SB2_SHPS_DSM_UUID, SB2_SHPS_DSM_REVISION,
++	                                 SB2_SHPS_DSM_GPU_STATE, &param, ACPI_TYPE_BUFFER);
++
++	if (IS_ERR_OR_NULL(result)) {
++		return result ? PTR_ERR(result) : -EFAULT;
++	}
++
++	if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
++		return -EIO;
++	}
++
++	drvdata->dgpu_power = power;
++
++	printk(KERN_INFO "sb2_shps: dGPU power state set to \'%s\'\n", sb2_dgpu_power_str(power));
++
++	ACPI_FREE(result);
++	return 0;
++}
++
++static int sb2_shps_dgpu_set_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	int status = 0;
++
++	if (power < __SB2_DGPU_POWER__START || power > __SB2_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	mutex_lock(&drvdata->dgpu_power_lock);
++	if (power != drvdata->dgpu_power) {
++		status = __sb2_shps_dgpu_set_power(pdev, power);
++	}
++	mutex_unlock(&drvdata->dgpu_power_lock);
++
++	return status;
++}
++
++static int sb2_shps_dgpu_force_power(struct platform_device *pdev, enum sb2_dgpu_power power)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	int status;
++
++	if (power < __SB2_DGPU_POWER__START || power > __SB2_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	mutex_lock(&drvdata->dgpu_power_lock);
++	status = __sb2_shps_dgpu_set_power(pdev, power);
++	mutex_unlock(&drvdata->dgpu_power_lock);
++
++	return status;
++}
++
++
++static int param_dgpu_power_set(const char *val, const struct kernel_param *kp)
++{
++	int power = SB2_PARAM_DGPU_POWER_OFF;
++	int status;
++
++	status = kstrtoint(val, 0, &power);
++	if (status) {
++		return status;
++	}
++
++	if (power < __SB2_PARAM_DGPU_POWER__START || power > __SB2_PARAM_DGPU_POWER__END) {
++		return -EINVAL;
++	}
++
++	return param_set_int(val, kp);
++}
++
++static const struct kernel_param_ops param_dgpu_power_ops = {
++	.set = param_dgpu_power_set,
++	.get = param_get_int,
++};
++
++static int param_dgpu_power_init = SB2_PARAM_DGPU_POWER_OFF;
++static int param_dgpu_power_exit = SB2_PARAM_DGPU_POWER_OFF;
++
++module_param_cb(dgpu_power_init, &param_dgpu_power_ops, &param_dgpu_power_init, SB2_PARAM_PERM);
++module_param_cb(dgpu_power_exit, &param_dgpu_power_ops, &param_dgpu_power_exit, SB2_PARAM_PERM);
++
++MODULE_PARM_DESC(dgpu_power_init, "dGPU power state to be set on init (0: off / 1: on / 2: as-is)");
++MODULE_PARM_DESC(dgpu_power_exit, "dGPU power state to be set on exit (0: off / 1: on / 2: as-is)");
++
++
++static ssize_t dgpu_power_show(struct device *dev, struct device_attribute *attr, char *data)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++
++	return sprintf(data, "%s\n", sb2_dgpu_power_str(drvdata->dgpu_power));
++}
++
++static ssize_t dgpu_power_store(struct device *dev, struct device_attribute *attr,
++                                const char *data, size_t count)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	bool power = false;
++	int status;
++
++	status = kstrtobool(data, &power);
++	if (status) {
++		return status;
++	}
++
++	if (power) {
++		status = sb2_shps_dgpu_set_power(pdev, SB2_DGPU_POWER_ON);
++	} else {
++		status = sb2_shps_dgpu_set_power(pdev, SB2_DGPU_POWER_OFF);
++	}
++
++	return status < 0 ? status : count;
++}
++
++const static DEVICE_ATTR_RW(dgpu_power);
++
++
++#ifdef CONFIG_PM
++
++static int sb2_shps_resume(struct device *dev)
++{
++	struct platform_device *pdev = container_of(dev, struct platform_device, dev);
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++
++	return sb2_shps_dgpu_force_power(pdev, drvdata->dgpu_power);
++}
++
++static SIMPLE_DEV_PM_OPS(sb2_shps_pm_ops, NULL, sb2_shps_resume);
++
++#endif
++
++
++static int sb2_shps_probe(struct platform_device *pdev)
++{
++	struct sb2_shps_driver_data *drvdata;
++	struct acpi_device *shps_dev = ACPI_COMPANION(&pdev->dev);
++	int status = 0;
++
++	if (gpiod_count(&pdev->dev, NULL) < 0) {
++		return -ENODEV;
++	}
++
++	status = acpi_dev_add_driver_gpios(shps_dev, sb2_mshw0153_acpi_gpios);
++	if (status) {
++		return status;
++	}
++
++	drvdata = kzalloc(sizeof(struct sb2_shps_driver_data), GFP_KERNEL);
++	if (!drvdata) {
++		status = -ENOMEM;
++		goto err_alloc_drvdata;
++	}
++
++	mutex_init(&drvdata->dgpu_power_lock);
++	drvdata->dgpu_power = SB2_DGPU_POWER_OFF;
++	platform_set_drvdata(pdev, drvdata);
++
++	if (param_dgpu_power_init != SB2_PARAM_DGPU_POWER_AS_IS) {
++		status = sb2_shps_dgpu_force_power(pdev, param_dgpu_power_init);
++		if (status) {
++			goto err_set_power;
++		}
++	}
++
++	status = sysfs_create_file(&pdev->dev.kobj, &dev_attr_dgpu_power.attr);
++	if (status) {
++		goto err_sysfs;
++	}
++
++	return 0;
++
++err_sysfs:
++	sb2_shps_dgpu_force_power(pdev, SB2_DGPU_POWER_OFF);
++err_set_power:
++	platform_set_drvdata(pdev, NULL);
++	kfree(drvdata);
++err_alloc_drvdata:
++	acpi_dev_remove_driver_gpios(shps_dev);
++	return status;
++}
++
++static int sb2_shps_remove(struct platform_device *pdev)
++{
++	struct sb2_shps_driver_data *drvdata = platform_get_drvdata(pdev);
++	struct acpi_device *shps_dev = ACPI_COMPANION(&pdev->dev);
++
++	sysfs_remove_file(&pdev->dev.kobj, &dev_attr_dgpu_power.attr);
++
++	if (param_dgpu_power_exit != SB2_PARAM_DGPU_POWER_AS_IS) {
++		sb2_shps_dgpu_set_power(pdev, param_dgpu_power_exit);
++	}
++	acpi_dev_remove_driver_gpios(shps_dev);
++
++	platform_set_drvdata(pdev, NULL);
++	kfree(drvdata);
++
++	return 0;
++}
++
++
++static const struct acpi_device_id sb2_shps_acpi_match[] = {
++	{ "MSHW0153", 0 },
++	{ },
++};
++MODULE_DEVICE_TABLE(acpi, sb2_shps_acpi_match);
++
++static struct platform_driver sb2_shps_driver = {
++	.probe = sb2_shps_probe,
++	.remove = sb2_shps_remove,
++	.driver = {
++		.name = "sb2_shps",
++		.acpi_match_table = ACPI_PTR(sb2_shps_acpi_match),
++#ifdef CONFIG_PM
++		.pm = &sb2_shps_pm_ops,
++#endif
++	},
++};
++module_platform_driver(sb2_shps_driver);
++
++MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
++MODULE_DESCRIPTION("Surface Book 2 Hot-Plug System Driver");
++MODULE_LICENSE("GPL v2");
+-- 
+2.22.0
+