Commit 382b91db authored by Luke D. Jones's avatar Luke D. Jones Committed by Hans de Goede

asus-wmi: Add egpu enable method

The X13 Flow laptops can utilise an external GPU. This requires
toggling an ACPI method which will first disable the internal
dGPU, and then enable the eGPU.
Signed-off-by: default avatarLuke D. Jones <luke@ljones.dev>
Link: https://lore.kernel.org/r/20210807023656.25020-4-luke@ljones.devReviewed-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
parent 98829e84
...@@ -210,6 +210,9 @@ struct asus_wmi { ...@@ -210,6 +210,9 @@ struct asus_wmi {
u8 fan_boost_mode_mask; u8 fan_boost_mode_mask;
u8 fan_boost_mode; u8 fan_boost_mode;
bool egpu_enable_available; // 0 = enable
bool egpu_enable;
bool dgpu_disable_available; bool dgpu_disable_available;
bool dgpu_disable; bool dgpu_disable;
...@@ -517,6 +520,94 @@ static ssize_t dgpu_disable_store(struct device *dev, ...@@ -517,6 +520,94 @@ static ssize_t dgpu_disable_store(struct device *dev,
static DEVICE_ATTR_RW(dgpu_disable); static DEVICE_ATTR_RW(dgpu_disable);
/* eGPU ********************************************************************/
static int egpu_enable_check_present(struct asus_wmi *asus)
{
u32 result;
int err;
asus->egpu_enable_available = false;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_EGPU, &result);
if (err) {
if (err == -ENODEV)
return 0;
return err;
}
if (result & ASUS_WMI_DSTS_PRESENCE_BIT) {
asus->egpu_enable_available = true;
asus->egpu_enable = result & ASUS_WMI_DSTS_STATUS_BIT;
}
return 0;
}
static int egpu_enable_write(struct asus_wmi *asus)
{
u32 retval;
u8 value;
int err;
/* Don't rely on type conversion */
value = asus->egpu_enable ? 1 : 0;
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, value, &retval);
if (err) {
pr_warn("Failed to set egpu disable: %d\n", err);
return err;
}
if (retval > 1 || retval < 0) {
pr_warn("Failed to set egpu disable (retval): 0x%x\n", retval);
return -EIO;
}
sysfs_notify(&asus->platform_device->dev.kobj, NULL, "egpu_enable");
return 0;
}
static ssize_t egpu_enable_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct asus_wmi *asus = dev_get_drvdata(dev);
bool mode = asus->egpu_enable;
return sysfs_emit(buf, "%d\n", mode);
}
/* The ACPI call to enable the eGPU also disables the internal dGPU */
static ssize_t egpu_enable_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
bool enable;
int result;
struct asus_wmi *asus = dev_get_drvdata(dev);
result = kstrtobool(buf, &enable);
if (result)
return result;
asus->egpu_enable = enable;
result = egpu_enable_write(asus);
if (result)
return result;
/* Ensure that the kernel status of dgpu is updated */
result = dgpu_disable_check_present(asus);
if (result)
return result;
return count;
}
static DEVICE_ATTR_RW(egpu_enable);
/* Battery ********************************************************************/ /* Battery ********************************************************************/
/* The battery maximum charging percentage */ /* The battery maximum charging percentage */
...@@ -2502,6 +2593,7 @@ static struct attribute *platform_attributes[] = { ...@@ -2502,6 +2593,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_camera.attr, &dev_attr_camera.attr,
&dev_attr_cardr.attr, &dev_attr_cardr.attr,
&dev_attr_touchpad.attr, &dev_attr_touchpad.attr,
&dev_attr_egpu_enable.attr,
&dev_attr_dgpu_disable.attr, &dev_attr_dgpu_disable.attr,
&dev_attr_lid_resume.attr, &dev_attr_lid_resume.attr,
&dev_attr_als_enable.attr, &dev_attr_als_enable.attr,
...@@ -2529,6 +2621,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj, ...@@ -2529,6 +2621,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
devid = ASUS_WMI_DEVID_LID_RESUME; devid = ASUS_WMI_DEVID_LID_RESUME;
else if (attr == &dev_attr_als_enable.attr) else if (attr == &dev_attr_als_enable.attr)
devid = ASUS_WMI_DEVID_ALS_ENABLE; devid = ASUS_WMI_DEVID_ALS_ENABLE;
else if (attr == &dev_attr_egpu_enable.attr)
ok = asus->egpu_enable_available;
else if (attr == &dev_attr_dgpu_disable.attr) else if (attr == &dev_attr_dgpu_disable.attr)
ok = asus->dgpu_disable_available; ok = asus->dgpu_disable_available;
else if (attr == &dev_attr_fan_boost_mode.attr) else if (attr == &dev_attr_fan_boost_mode.attr)
...@@ -2792,6 +2886,10 @@ static int asus_wmi_add(struct platform_device *pdev) ...@@ -2792,6 +2886,10 @@ static int asus_wmi_add(struct platform_device *pdev)
if (err) if (err)
goto fail_platform; goto fail_platform;
err = egpu_enable_check_present(asus);
if (err)
goto fail_egpu_enable;
err = dgpu_disable_check_present(asus); err = dgpu_disable_check_present(asus);
if (err) if (err)
goto fail_dgpu_disable; goto fail_dgpu_disable;
...@@ -2896,6 +2994,7 @@ static int asus_wmi_add(struct platform_device *pdev) ...@@ -2896,6 +2994,7 @@ static int asus_wmi_add(struct platform_device *pdev)
fail_sysfs: fail_sysfs:
fail_throttle_thermal_policy: fail_throttle_thermal_policy:
fail_fan_boost_mode: fail_fan_boost_mode:
fail_egpu_enable:
fail_dgpu_disable: fail_dgpu_disable:
fail_platform: fail_platform:
fail_panel_od: fail_panel_od:
......
...@@ -90,6 +90,9 @@ ...@@ -90,6 +90,9 @@
/* Keyboard dock */ /* Keyboard dock */
#define ASUS_WMI_DEVID_KBD_DOCK 0x00120063 #define ASUS_WMI_DEVID_KBD_DOCK 0x00120063
/* dgpu on/off */
#define ASUS_WMI_DEVID_EGPU 0x00090019
/* dgpu on/off */ /* dgpu on/off */
#define ASUS_WMI_DEVID_DGPU 0x00090020 #define ASUS_WMI_DEVID_DGPU 0x00090020
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment