Re: [PATCH v3 6/6] asus-wmi: Support the hardware GPU MUX on some laptops

From: Luke Jones
Date: Tue Aug 09 2022 - 03:20:12 EST


Hi all,

This patch still needs some work. I've been analysing the various dumps I've collected over the past 2 years.

Some laptops return a `0xFFFFFFFE` in response to query of this method, and do not have a corresponding set method. To work around it I was using `if (result == 0xFFFFFFFE) return 0;`, but, I'm unsure if `0xFFFFFFFE` is actually a valid response in the first place. Is it?

Additionally to this, I should have been reading the devstate in the related _show(), not returning the stored value. And this should be done for the egpu_enable and dgpu_disable attributes also.

Lastly, some laptops have a valid return for the getter, but no setter method.. I'm not sure what to do about this.

Are there any issues with me adding more patches to this series? In particular I think I need to add patches for the above mentioned things, and I should add the "asus-wmi: Modify behaviour of Fn+F5 fan key" patches too, I'm beginning to get merge conflicts in testing, and all the work I'm doing is becoming unwieldy.

Kind regards,
Luke.


On Tue, Aug 9 2022 at 14:50:54 +1200, Luke D. Jones <luke@xxxxxxxxxx> wrote:
Support the hardware GPU MUX switch available on some models. This
switch can toggle the MUX between:

- 0, Dedicated mode
- 1, Optimus mode

Optimus mode is the regular iGPU + dGPU available, while dedicated
mode switches the system to have only the dGPU available.

Signed-off-by: Luke D. Jones <luke@xxxxxxxxxx>
---
.../ABI/testing/sysfs-platform-asus-wmi | 9 ++
drivers/platform/x86/asus-wmi.c | 91 +++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 3 +
3 files changed, 103 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 541dbfbbbb26..d483bc3cb2e6 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -67,6 +67,15 @@ Description:
* 0 - Disable,
* 1 - Enable,

+What: /sys/devices/platform/<platform>/gpu_mux_mode
+Date: Aug 2022
+KernelVersion: 6.0
+Contact: "Luke Jones" <luke@xxxxxxxxxx>
+Description:
+ Switch the GPU used by the hardware MUX:
+ * 0 - Dedicated GPU,
+ * 1 - Optimus mode,
+
What: /sys/devices/platform/<platform>/panel_od
Date: Aug 2022
KernelVersion: 5.17
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 78f1f3af1b12..c5fa21370481 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -246,6 +246,9 @@ struct asus_wmi {
bool dgpu_disable_available;
bool dgpu_disable;

+ bool gpu_mux_mode_available;
+ bool gpu_mux_mode;
+
bool keyboard_rgb_state_available;
bool keyboard_rgb_mode_available;
struct keyboard_rgb_led keyboard_rgb_led;
@@ -750,6 +753,86 @@ static ssize_t egpu_enable_store(struct device *dev,

static DEVICE_ATTR_RW(egpu_enable);

+/* gpu mux switch *************************************************************/
+static int gpu_mux_mode_check_present(struct asus_wmi *asus)
+{
+ u32 result;
+ int err;
+
+ asus->gpu_mux_mode_available = false;
+
+ err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_GPU_MUX, &result);
+ if (err) {
+ if (err == -ENODEV)
+ return 0;
+ return err;
+ }
+
+ if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
+ asus->gpu_mux_mode_available = true;
+ asus->gpu_mux_mode = result & ASUS_WMI_DSTS_STATUS_BIT;
+ }
+
+ return 0;
+}
+
+static int gpu_mux_mode_write(struct asus_wmi *asus)
+{
+ u32 retval;
+ u8 value;
+ int err;
+
+ /* Don't rely on type conversion */
+ value = asus->gpu_mux_mode ? 1 : 0;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, value, &retval);
+ if (err) {
+ pr_warn("Failed to set dGPU-only mode: %d\n", err);
+ return err;
+ }
+
+ if (retval > 1) {
+ pr_warn("Failed to set dGPU-only mode (retval): 0x%x\n", retval);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "gpu_mux_mode");
+
+ return 0;
+}
+
+static ssize_t gpu_mux_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ u8 mode = asus->gpu_mux_mode;
+
+ return sysfs_emit(buf, "%d\n", mode);
+}
+
+static ssize_t gpu_mux_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ bool optimus;
+ int result;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtobool(buf, &optimus);
+ if (result)
+ return result;
+
+ asus->gpu_mux_mode = optimus;
+
+ result = gpu_mux_mode_write(asus);
+ if (result)
+ return result;
+
+ return count;
+}
+static DEVICE_ATTR_RW(gpu_mux_mode);
+
/* TUF Laptop Keyboard RGB Modes **********************************************/
static int keyboard_rgb_check_present(struct asus_wmi *asus)
{
@@ -3496,6 +3579,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_touchpad.attr,
&dev_attr_egpu_enable.attr,
&dev_attr_dgpu_disable.attr,
+ &dev_attr_gpu_mux_mode.attr,
&dev_attr_keyboard_rgb_save.attr,
&dev_attr_keyboard_rgb_mode.attr,
&dev_attr_keyboard_rgb_speed.attr,
@@ -3531,6 +3615,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
ok = asus->egpu_enable_available;
else if (attr == &dev_attr_dgpu_disable.attr)
ok = asus->dgpu_disable_available;
+ else if (attr == &dev_attr_gpu_mux_mode.attr)
+ ok = asus->gpu_mux_mode_available;
else if (attr == &dev_attr_keyboard_rgb_save.attr)
ok = asus->keyboard_rgb_mode_available;
else if (attr == &dev_attr_keyboard_rgb_mode.attr)
@@ -3810,6 +3896,10 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err)
goto fail_dgpu_disable;

+ err = gpu_mux_mode_check_present(asus);
+ if (err)
+ goto fail_gpu_mux_mode;
+
err = keyboard_rgb_check_present(asus);
if (err)
goto fail_keyboard_rgb_mode;
@@ -3932,6 +4022,7 @@ static int asus_wmi_add(struct platform_device *pdev)
fail_fan_boost_mode:
fail_egpu_enable:
fail_dgpu_disable:
+fail_gpu_mux_mode:
fail_keyboard_rgb_mode:
fail_keyboard_rgb_state:
fail_platform:
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index b5c966798ef8..3faeb98f6ea9 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -98,6 +98,9 @@
/* dgpu on/off */
#define ASUS_WMI_DEVID_DGPU 0x00090020

+/* gpu mux switch, 0 = dGPU, 1 = Optimus */
+#define ASUS_WMI_DEVID_GPU_MUX 0x00090016
+
/* TUF laptop RGB control */
#define ASUS_WMI_DEVID_TUF_RGB_MODE 0x00100056
/* TUF laptop RGB state control */
--
2.37.1