2023-06-30 05:42:18

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 0/8] platform/x86: asus-wmi:

This patch series adds or exposes more features that are available in the ROG
laptop series.

- expose dGPU and CPU tunables for ROG
- These are things like GPU boost, CPU Pl1 and PL2, package power limits
- support setting mini-LED mode
- Some newer laptops have a screen that can toggle between regular style
backlight and using mini-LED backlight
- add WMI method to show if egpu connected
- This WMI method can be monitored/queried to see if it is possible to begin
the change-over to eGPU
- support middle fan custom curves
- Some newer laptops have a center/middle fan which blows across the CPU and GPU
- add support for showing middle fan RPM
- add support for showing charger mode (AC, USB-C, both plugged)
- add additional checks to GPU switching code
- These try to prevent a sceanrio such as the user disabling the dGPU while it
is driving the internal panel via MUX, resulting in no output at all.
There are no checks in the ACPI code for this, but on some newer models ASUS
did finally add a switch in the BIOS menu. It is best to try and prevent this
at the kernel level rather than userland level.

All patches pass ./scripts/checkpatch.pl

Changelog:
- v2-0008-platform-x86-asus-wmi-expose-dGPU-and-CPU-tunable.patch
- Rename the WMI defs to match what ASUS supplied as names
- Remove EDC and TDC exposure (unsafe)
- Slight change to formatting
- Add better notes to documentation


Luke D. Jones (8):
platform/x86: asus-wmi: add support for showing charger mode
platform/x86: asus-wmi: add support for showing middle fan RPM
platform/x86: asus-wmi: support middle fan custom curves
platform/x86: asus-wmi: add WMI method to show if egpu connected
platform/x86: asus-wmi: don't allow eGPU switching if eGPU not
connected
platform/x86: asus-wmi: add safety checks to gpu switching
platform/x86: asus-wmi: support setting mini-LED mode
platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG

.../ABI/testing/sysfs-platform-asus-wmi | 86 +++
drivers/platform/x86/asus-wmi.c | 605 +++++++++++++++++-
include/linux/platform_data/x86/asus-wmi.h | 19 +-
3 files changed, 707 insertions(+), 3 deletions(-)

--
2.41.0



2023-06-30 05:42:45

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 2/8] platform/x86: asus-wmi: add support for showing middle fan RPM

Some newer ASUS ROG laptops now have a middle/center fan in addition
to the CPU and GPU fans. This new fan typically blows across the
heatpipes and VRMs betweent eh CPU and GPU.

This commit exposes that fan to PWM control plus showing RPM.

Signed-off-by: Luke D. Jones <[email protected]>
---
drivers/platform/x86/asus-wmi.c | 91 ++++++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 1 +
2 files changed, 92 insertions(+)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index f23375d5fb82..375d25ae0aca 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -72,6 +72,7 @@ module_param(fnlock_default, bool, 0444);

#define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)

+#define ASUS_MID_FAN_DESC "mid_fan"
#define ASUS_GPU_FAN_DESC "gpu_fan"
#define ASUS_FAN_DESC "cpu_fan"
#define ASUS_FAN_MFUN 0x13
@@ -229,8 +230,10 @@ struct asus_wmi {

enum fan_type fan_type;
enum fan_type gpu_fan_type;
+ enum fan_type mid_fan_type;
int fan_pwm_mode;
int gpu_fan_pwm_mode;
+ int mid_fan_pwm_mode;
int agfn_pwm;

bool fan_boost_mode_available;
@@ -2129,6 +2132,31 @@ static ssize_t fan2_label_show(struct device *dev,
return sysfs_emit(buf, "%s\n", ASUS_GPU_FAN_DESC);
}

+/* Middle/Center fan on modern ROG laptops */
+static ssize_t fan3_input_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ int value;
+ int ret;
+
+ ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_MID_FAN_CTRL, &value);
+ if (ret < 0)
+ return ret;
+
+ value &= 0xffff;
+
+ return sysfs_emit(buf, "%d\n", value * 100);
+}
+
+static ssize_t fan3_label_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sysfs_emit(buf, "%s\n", ASUS_MID_FAN_DESC);
+}
+
static ssize_t pwm2_enable_show(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -2175,6 +2203,52 @@ static ssize_t pwm2_enable_store(struct device *dev,
return count;
}

+static ssize_t pwm3_enable_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ return sysfs_emit(buf, "%d\n", asus->mid_fan_pwm_mode);
+}
+
+static ssize_t pwm3_enable_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ int state;
+ int value;
+ int ret;
+ u32 retval;
+
+ ret = kstrtouint(buf, 10, &state);
+ if (ret)
+ return ret;
+
+ switch (state) { /* standard documented hwmon values */
+ case ASUS_FAN_CTRL_FULLSPEED:
+ value = 1;
+ break;
+ case ASUS_FAN_CTRL_AUTO:
+ value = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_MID_FAN_CTRL,
+ value, &retval);
+ if (ret)
+ return ret;
+
+ if (retval != 1)
+ return -EIO;
+
+ asus->mid_fan_pwm_mode = state;
+ return count;
+}
+
/* Fan1 */
static DEVICE_ATTR_RW(pwm1);
static DEVICE_ATTR_RW(pwm1_enable);
@@ -2184,6 +2258,10 @@ static DEVICE_ATTR_RO(fan1_label);
static DEVICE_ATTR_RW(pwm2_enable);
static DEVICE_ATTR_RO(fan2_input);
static DEVICE_ATTR_RO(fan2_label);
+/* Fan3 - Middle/center fan */
+static DEVICE_ATTR_RW(pwm3_enable);
+static DEVICE_ATTR_RO(fan3_input);
+static DEVICE_ATTR_RO(fan3_label);

/* Temperature */
static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
@@ -2192,10 +2270,13 @@ static struct attribute *hwmon_attributes[] = {
&dev_attr_pwm1.attr,
&dev_attr_pwm1_enable.attr,
&dev_attr_pwm2_enable.attr,
+ &dev_attr_pwm3_enable.attr,
&dev_attr_fan1_input.attr,
&dev_attr_fan1_label.attr,
&dev_attr_fan2_input.attr,
&dev_attr_fan2_label.attr,
+ &dev_attr_fan3_input.attr,
+ &dev_attr_fan3_label.attr,

&dev_attr_temp1_input.attr,
NULL
@@ -2221,6 +2302,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
|| attr == &dev_attr_pwm2_enable.attr) {
if (asus->gpu_fan_type == FAN_TYPE_NONE)
return 0;
+ } else if (attr == &dev_attr_fan3_input.attr
+ || attr == &dev_attr_fan3_label.attr
+ || attr == &dev_attr_pwm3_enable.attr) {
+ if (asus->mid_fan_type == FAN_TYPE_NONE)
+ return 0;
} else if (attr == &dev_attr_temp1_input.attr) {
int err = asus_wmi_get_devstate(asus,
ASUS_WMI_DEVID_THERMAL_CTRL,
@@ -2264,6 +2350,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
static int asus_wmi_fan_init(struct asus_wmi *asus)
{
asus->gpu_fan_type = FAN_TYPE_NONE;
+ asus->mid_fan_type = FAN_TYPE_NONE;
asus->fan_type = FAN_TYPE_NONE;
asus->agfn_pwm = -1;

@@ -2278,6 +2365,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL))
asus->gpu_fan_type = FAN_TYPE_SPEC83;

+ /* Some models also have a center/middle fan */
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MID_FAN_CTRL))
+ asus->mid_fan_type = FAN_TYPE_SPEC83;
+
if (asus->fan_type == FAN_TYPE_NONE)
return -ENODEV;

diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index f90cafe26af1..2c03bda7703f 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -80,6 +80,7 @@
#define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */
#define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013
#define ASUS_WMI_DEVID_GPU_FAN_CTRL 0x00110014
+#define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031
#define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024
#define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025

--
2.41.0


2023-06-30 05:50:44

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 3/8] platform/x86: asus-wmi: support middle fan custom curves

Adds support for fan curves defined for the middle fan which
is available on some ASUS ROG laptops.

Signed-off-by: Luke D. Jones <[email protected]>
---
drivers/platform/x86/asus-wmi.c | 77 +++++++++++++++++++++-
include/linux/platform_data/x86/asus-wmi.h | 1 +
2 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 375d25ae0aca..fb27218e51cf 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -113,6 +113,7 @@ module_param(fnlock_default, bool, 0444);
#define FAN_CURVE_BUF_LEN 32
#define FAN_CURVE_DEV_CPU 0x00
#define FAN_CURVE_DEV_GPU 0x01
+#define FAN_CURVE_DEV_MID 0x02
/* Mask to determine if setting temperature or percentage */
#define FAN_CURVE_PWM_MASK 0x04

@@ -253,7 +254,8 @@ struct asus_wmi {

bool cpu_fan_curve_available;
bool gpu_fan_curve_available;
- struct fan_curve_data custom_fan_curves[2];
+ bool mid_fan_curve_available;
+ struct fan_curve_data custom_fan_curves[3];

struct platform_profile_handler platform_profile_handler;
bool platform_profile_support;
@@ -2080,6 +2082,8 @@ static ssize_t pwm1_enable_store(struct device *dev,
asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false;
if (asus->gpu_fan_curve_available)
asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false;
+ if (asus->mid_fan_curve_available)
+ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false;

return count;
}
@@ -2531,6 +2535,9 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE)
fan_idx = FAN_CURVE_DEV_GPU;

+ if (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE)
+ fan_idx = FAN_CURVE_DEV_MID;
+
curves = &asus->custom_fan_curves[fan_idx];
err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf,
FAN_CURVE_BUF_LEN);
@@ -2819,6 +2826,42 @@ static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve,
static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve,
FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7);

+/* MID */
+static SENSOR_DEVICE_ATTR_RW(pwm3_enable, fan_curve_enable, FAN_CURVE_DEV_GPU);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 0);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 1);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 2);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 3);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 4);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 5);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 6);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve,
+ FAN_CURVE_DEV_GPU, 7);
+
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6);
+static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve,
+ FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7);
+
static struct attribute *asus_fan_curve_attr[] = {
/* CPU */
&sensor_dev_attr_pwm1_enable.dev_attr.attr,
@@ -2856,6 +2899,24 @@ static struct attribute *asus_fan_curve_attr[] = {
&sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr,
&sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr,
+ /* MID */
+ &sensor_dev_attr_pwm3_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr,
+ &sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr,
NULL
};

@@ -2875,6 +2936,9 @@ static umode_t asus_fan_curve_is_visible(struct kobject *kobj,
if (asus->gpu_fan_curve_available && attr->name[3] == '2')
return 0644;

+ if (asus->mid_fan_curve_available && attr->name[3] == '3')
+ return 0644;
+
return 0;
}

@@ -2904,7 +2968,14 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
if (err)
return err;

- if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available)
+ err = fan_curve_check_present(asus, &asus->mid_fan_curve_available,
+ ASUS_WMI_DEVID_MID_FAN_CURVE);
+ if (err)
+ return err;
+
+ if (!asus->cpu_fan_curve_available
+ && !asus->gpu_fan_curve_available
+ && !asus->mid_fan_curve_available)
return 0;

hwmon = devm_hwmon_device_register_with_groups(
@@ -2973,6 +3044,8 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false;
if (asus->gpu_fan_curve_available)
asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false;
+ if (asus->mid_fan_curve_available)
+ asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false;

return 0;
}
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 2c03bda7703f..329efc086993 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -83,6 +83,7 @@
#define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031
#define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024
#define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
+#define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032

/* Power */
#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
--
2.41.0


2023-06-30 06:00:44

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 4/8] platform/x86: asus-wmi: add WMI method to show if egpu connected

Exposes the WMI method which tells if the eGPU is properly connected
on the devices that support it.

Signed-off-by: Luke D. Jones <[email protected]>
---
.../ABI/testing/sysfs-platform-asus-wmi | 11 +++++++++-
drivers/platform/x86/asus-wmi.c | 21 +++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 4 +++-
3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index eb29e3023c7b..878daf7c2036 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -107,4 +107,13 @@ Description:
Get the current charging mode being used:
* 1 - Barrel connected charger,
* 2 - USB-C charging
- * 3 - Both connected, barrel used for charging
\ No newline at end of file
+ * 3 - Both connected, barrel used for charging
+
+What: /sys/devices/platform/<platform>/egpu_connected
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Show if the egpu (XG Mobile) is correctly connected:
+ * 0 - False,
+ * 1 - True
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index fb27218e51cf..0c8a4a46b121 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -243,6 +243,7 @@ struct asus_wmi {

bool charge_mode_available;
bool egpu_enable_available;
+ bool egpu_connect_available;
bool dgpu_disable_available;
bool gpu_mux_mode_available;

@@ -709,6 +710,22 @@ static ssize_t egpu_enable_store(struct device *dev,
}
static DEVICE_ATTR_RW(egpu_enable);

+/* Is eGPU connected? *********************************************************/
+static ssize_t egpu_connected_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ int result;
+
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
+ if (result < 0)
+ return result;
+
+ return sysfs_emit(buf, "%d\n", result);
+}
+
+static DEVICE_ATTR_RO(egpu_connected);
+
/* gpu mux switch *************************************************************/
static ssize_t gpu_mux_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -3645,6 +3662,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_touchpad.attr,
&dev_attr_charge_mode.attr,
&dev_attr_egpu_enable.attr,
+ &dev_attr_egpu_connected.attr,
&dev_attr_dgpu_disable.attr,
&dev_attr_gpu_mux_mode.attr,
&dev_attr_lid_resume.attr,
@@ -3677,6 +3695,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
ok = asus->charge_mode_available;
else if (attr == &dev_attr_egpu_enable.attr)
ok = asus->egpu_enable_available;
+ else if (attr == &dev_attr_egpu_connected.attr)
+ ok = asus->egpu_connect_available;
else if (attr == &dev_attr_dgpu_disable.attr)
ok = asus->dgpu_disable_available;
else if (attr == &dev_attr_gpu_mux_mode.attr)
@@ -3943,6 +3963,7 @@ static int asus_wmi_add(struct platform_device *pdev)

asus->charge_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CHARGE_MODE);
asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
+ asus->egpu_connect_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 329efc086993..2034648f8cdf 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -100,7 +100,9 @@
/* Charging mode - 1=Barrel, 2=USB */
#define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C

-/* dgpu on/off */
+/* epu is connected? 1 == true */
+#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018
+/* egpu on/off */
#define ASUS_WMI_DEVID_EGPU 0x00090019

/* dgpu on/off */
--
2.41.0


2023-06-30 06:01:41

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 7/8] platform/x86: asus-wmi: support setting mini-LED mode

Support changing the mini-LED mode on some of the newer ASUS laptops.

Signed-off-by: Luke D. Jones <[email protected]>
---
.../ABI/testing/sysfs-platform-asus-wmi | 9 ++++
drivers/platform/x86/asus-wmi.c | 53 +++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 1 +
3 files changed, 63 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 878daf7c2036..5624bdef49cb 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -117,3 +117,12 @@ Description:
Show if the egpu (XG Mobile) is correctly connected:
* 0 - False,
* 1 - True
+
+What: /sys/devices/platform/<platform>/mini_led_mode
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Change the mini-LED mode:
+ * 0 - Single-zone,
+ * 1 - Multi-zone
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 602426a7fb41..1fc9e8afc2f3 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -265,6 +265,7 @@ struct asus_wmi {
bool battery_rsoc_available;

bool panel_overdrive_available;
+ bool mini_led_mode_available;

struct hotplug_slot hotplug_slot;
struct mutex hotplug_lock;
@@ -1820,6 +1821,54 @@ static ssize_t panel_od_store(struct device *dev,
}
static DEVICE_ATTR_RW(panel_od);

+/* Mini-LED mode **************************************************************/
+static ssize_t mini_led_mode_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+ int result;
+
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
+ if (result < 0)
+ return result;
+
+ return sysfs_emit(buf, "%d\n", result);
+}
+
+static ssize_t mini_led_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 mode;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &mode);
+ if (result)
+ return result;
+
+ if (mode > 1)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MINI_LED_MODE, mode, &result);
+
+ if (err) {
+ pr_warn("Failed to set mini-LED: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mini_led_mode");
+
+ return count;
+}
+static DEVICE_ATTR_RW(mini_led_mode);
+
/* Quirks *********************************************************************/

static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
@@ -3727,6 +3776,7 @@ static struct attribute *platform_attributes[] = {
&dev_attr_fan_boost_mode.attr,
&dev_attr_throttle_thermal_policy.attr,
&dev_attr_panel_od.attr,
+ &dev_attr_mini_led_mode.attr,
NULL
};

@@ -3764,6 +3814,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
ok = asus->throttle_thermal_policy_available;
else if (attr == &dev_attr_panel_od.attr)
ok = asus->panel_overdrive_available;
+ else if (attr == &dev_attr_mini_led_mode.attr)
+ ok = asus->mini_led_mode_available;

if (devid != -1)
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
@@ -4026,6 +4078,7 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
+ asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);

err = fan_boost_mode_check_present(asus);
if (err)
diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index 2034648f8cdf..ea80361ac6c7 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -66,6 +66,7 @@
#define ASUS_WMI_DEVID_CAMERA 0x00060013
#define ASUS_WMI_DEVID_LID_FLIP 0x00060062
#define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077
+#define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E

/* Storage */
#define ASUS_WMI_DEVID_CARDREADER 0x00080013
--
2.41.0


2023-06-30 06:02:24

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 5/8] platform/x86: asus-wmi: don't allow eGPU switching if eGPU not connected

Check the ASUS_WMI_DEVID_EGPU_CONNECTED method for eGPU connection
before allowing the ASUS_WMI_DEVID_EGPU method to run.

Signed-off-by: Luke D. Jones <[email protected]>
---
drivers/platform/x86/asus-wmi.c | 9 +++++++++
1 file changed, 9 insertions(+)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 0c8a4a46b121..821addb284d7 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -693,6 +693,15 @@ static ssize_t egpu_enable_store(struct device *dev,
if (enable > 1)
return -EINVAL;

+ err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
+ if (err < 0)
+ return err;
+ if (err < 1) {
+ err = -ENODEV;
+ pr_warn("Failed to set egpu disable: %d\n", err);
+ return err;
+ }
+
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
if (err) {
pr_warn("Failed to set egpu disable: %d\n", err);
--
2.41.0


2023-06-30 06:03:09

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG

Expose various CPU and dGPU tunables that are available on many ASUS
ROG laptops. The tunables shown in sysfs will vary depending on the CPU
and dGPU vendor.

All of these variables are write only and there is no easy way to find
what the defaults are. In general they seem to default to the max value
the vendor sets for the CPU and dGPU package - this is not the same as
the min/max writable value. Values written to these variables that are
beyond the capabilities of the CPU are ignored by the laptop.

Signed-off-by: Luke D. Jones <[email protected]>
---
.../ABI/testing/sysfs-platform-asus-wmi | 58 ++++
drivers/platform/x86/asus-wmi.c | 285 ++++++++++++++++++
include/linux/platform_data/x86/asus-wmi.h | 9 +
3 files changed, 352 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
index 5624bdef49cb..caaccd28fabf 100644
--- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
+++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
@@ -126,3 +126,61 @@ Description:
Change the mini-LED mode:
* 0 - Single-zone,
* 1 - Multi-zone
+
+What: /sys/devices/platform/<platform>/ppt_pl1_spl
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
+ Shown on Intel+Nvidia or AMD+Nvidia based systems.
+ * min=5, max=250
+
+What: /sys/devices/platform/<platform>/ppt_pl2_sppt
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
+ on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems.
+ * min=5, max=250
+
+What: /sys/devices/platform/<platform>/ppt_fppt
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only.
+ * min=5, max=250
+
+What: /sys/devices/platform/<platform>/ppt_apu_sppt
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the APU SPPT limit. Shown on full AMD systems only.
+ * min=5, max=130
+
+What: /sys/devices/platform/<platform>/ppt_platform_sppt
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the platform SPPT limit. Shown on full AMD systems only.
+ * min=5, max=130
+
+What: /sys/devices/platform/<platform>/nv_dynamic_boost
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the dynamic boost limit of the Nvidia dGPU:
+ * min=5, max=25
+
+What: /sys/devices/platform/<platform>/nv_temp_target
+Date: Jun 2023
+KernelVersion: 6.5
+Contact: "Luke Jones" <[email protected]>
+Description:
+ Set the target temperature limit of the Nvidia dGPU:
+ * min=75, max=87
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 1fc9e8afc2f3..d9a353081f91 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -117,6 +117,16 @@ module_param(fnlock_default, bool, 0444);
/* Mask to determine if setting temperature or percentage */
#define FAN_CURVE_PWM_MASK 0x04

+/* Limits for tunables available on ASUS ROG laptops */
+#define PPT_TOTAL_MIN 5
+#define PPT_TOTAL_MAX 250
+#define PPT_CPU_MIN 5
+#define PPT_CPU_MAX 130
+#define NVIDIA_BOOST_MIN 5
+#define NVIDIA_BOOST_MAX 25
+#define NVIDIA_TEMP_MIN 75
+#define NVIDIA_TEMP_MAX 87
+
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };

static int throttle_thermal_policy_write(struct asus_wmi *);
@@ -247,6 +257,15 @@ struct asus_wmi {
bool dgpu_disable_available;
bool gpu_mux_mode_available;

+ /* Tunables provided by ASUS for gaming laptops */
+ bool ppt_pl2_sppt_available;
+ bool ppt_pl1_spl_available;
+ bool ppt_apu_sppt_available;
+ bool ppt_plat_sppt_available;
+ bool ppt_fppt_available;
+ bool nv_dyn_boost_available;
+ bool nv_temp_tgt_available;
+
bool kbd_rgb_mode_available;
bool kbd_rgb_state_available;

@@ -946,6 +965,244 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
NULL,
};

+/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
+static ssize_t ppt_pl2_sppt_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result);
+ if (err) {
+ pr_warn("Failed to set ppt_pl2_sppt: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt");
+
+ return count;
+}
+static DEVICE_ATTR_WO(ppt_pl2_sppt);
+
+/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/
+static ssize_t ppt_pl1_spl_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result);
+ if (err) {
+ pr_warn("Failed to set ppt_pl1_spl: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl");
+
+ return count;
+}
+static DEVICE_ATTR_WO(ppt_pl1_spl);
+
+/* Tunable: PPT APU FPPT ******************************************************/
+static ssize_t ppt_fppt_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result);
+ if (err) {
+ pr_warn("Failed to set ppt_fppt: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt");
+
+ return count;
+}
+static DEVICE_ATTR_WO(ppt_fppt);
+
+/* Tunable: PPT APU SPPT *****************************************************/
+static ssize_t ppt_apu_sppt_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result);
+ if (err) {
+ pr_warn("Failed to set ppt_apu_sppt: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt");
+
+ return count;
+}
+static DEVICE_ATTR_WO(ppt_apu_sppt);
+
+/* Tunable: PPT platform SPPT ************************************************/
+static ssize_t ppt_platform_sppt_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result);
+ if (err) {
+ pr_warn("Failed to set ppt_platform_sppt: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt");
+
+ return count;
+}
+static DEVICE_ATTR_WO(ppt_platform_sppt);
+
+/* Tunable: NVIDIA dynamic boost *********************************************/
+static ssize_t nv_dynamic_boost_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result);
+ if (err) {
+ pr_warn("Failed to set nv_dynamic_boost: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost");
+
+ return count;
+}
+static DEVICE_ATTR_WO(nv_dynamic_boost);
+
+/* Tunable: NVIDIA temperature target ****************************************/
+static ssize_t nv_temp_target_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int result, err;
+ u32 value;
+
+ struct asus_wmi *asus = dev_get_drvdata(dev);
+
+ result = kstrtou32(buf, 10, &value);
+ if (result)
+ return result;
+
+ if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX)
+ return -EINVAL;
+
+ err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result);
+ if (err) {
+ pr_warn("Failed to set nv_temp_target: %d\n", err);
+ return err;
+ }
+
+ if (result > 1) {
+ pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result);
+ return -EIO;
+ }
+
+ sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target");
+
+ return count;
+}
+static DEVICE_ATTR_WO(nv_temp_target);
+
/* Battery ********************************************************************/

/* The battery maximum charging percentage */
@@ -3775,6 +4032,13 @@ static struct attribute *platform_attributes[] = {
&dev_attr_als_enable.attr,
&dev_attr_fan_boost_mode.attr,
&dev_attr_throttle_thermal_policy.attr,
+ &dev_attr_ppt_pl2_sppt.attr,
+ &dev_attr_ppt_pl1_spl.attr,
+ &dev_attr_ppt_fppt.attr,
+ &dev_attr_ppt_apu_sppt.attr,
+ &dev_attr_ppt_platform_sppt.attr,
+ &dev_attr_nv_dynamic_boost.attr,
+ &dev_attr_nv_temp_target.attr,
&dev_attr_panel_od.attr,
&dev_attr_mini_led_mode.attr,
NULL
@@ -3812,6 +4076,20 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
ok = asus->fan_boost_mode_available;
else if (attr == &dev_attr_throttle_thermal_policy.attr)
ok = asus->throttle_thermal_policy_available;
+ else if (attr == &dev_attr_ppt_pl2_sppt.attr)
+ ok = asus->ppt_pl2_sppt_available;
+ else if (attr == &dev_attr_ppt_pl1_spl.attr)
+ ok = asus->ppt_pl1_spl_available;
+ else if (attr == &dev_attr_ppt_fppt.attr)
+ ok = asus->ppt_fppt_available;
+ else if (attr == &dev_attr_ppt_apu_sppt.attr)
+ ok = asus->ppt_apu_sppt_available;
+ else if (attr == &dev_attr_ppt_platform_sppt.attr)
+ ok = asus->ppt_plat_sppt_available;
+ else if (attr == &dev_attr_nv_dynamic_boost.attr)
+ ok = asus->nv_dyn_boost_available;
+ else if (attr == &dev_attr_nv_temp_target.attr)
+ ok = asus->nv_temp_tgt_available;
else if (attr == &dev_attr_panel_od.attr)
ok = asus->panel_overdrive_available;
else if (attr == &dev_attr_mini_led_mode.attr)
@@ -4077,6 +4355,13 @@ static int asus_wmi_add(struct platform_device *pdev)
asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
+ asus->ppt_pl2_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL2_SPPT);
+ asus->ppt_pl1_spl_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL1_SPL);
+ asus->ppt_fppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_FPPT);
+ asus->ppt_apu_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_APU_SPPT);
+ asus->ppt_plat_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PLAT_SPPT);
+ asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST);
+ asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);

diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
index ea80361ac6c7..16e99a1c37fc 100644
--- a/include/linux/platform_data/x86/asus-wmi.h
+++ b/include/linux/platform_data/x86/asus-wmi.h
@@ -86,6 +86,15 @@
#define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
#define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032

+/* Tunables for AUS ROG laptops */
+#define ASUS_WMI_DEVID_PPT_PL2_SPPT 0x001200A0
+#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3
+#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0
+#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1
+#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1
+#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0
+#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2
+
/* Power */
#define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012

--
2.41.0


2023-06-30 06:08:20

by Luke D. Jones

[permalink] [raw]
Subject: [PATCH v2 6/8] platform/x86: asus-wmi: add safety checks to gpu switching

Add safety checking to dgpu_disable, egpu_enable, gpu_mux_mode.

These checks prevent users from doing such things as:
- disabling the dGPU while is muxed to drive the internal screen
- enabling the eGPU which also disables the dGPU, while muxed to
the internal screen
- switching the MUX to dGPU while the dGPU is disabled

Signed-off-by: Luke D. Jones <[email protected]>
---
drivers/platform/x86/asus-wmi.c | 50 ++++++++++++++++++++++++++++++++-
1 file changed, 49 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 821addb284d7..602426a7fb41 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -645,6 +645,18 @@ static ssize_t dgpu_disable_store(struct device *dev,
if (disable > 1)
return -EINVAL;

+ if (asus->gpu_mux_mode_available) {
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
+ if (result < 0)
+ /* An error here may signal greater failure of GPU handling */
+ return result;
+ if (!result && disable) {
+ err = -ENODEV;
+ pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
+ return err;
+ }
+ }
+
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
if (err) {
pr_warn("Failed to set dgpu disable: %d\n", err);
@@ -693,7 +705,7 @@ static ssize_t egpu_enable_store(struct device *dev,
if (enable > 1)
return -EINVAL;

- err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
if (err < 0)
return err;
if (err < 1) {
@@ -702,6 +714,18 @@ static ssize_t egpu_enable_store(struct device *dev,
return err;
}

+ if (asus->gpu_mux_mode_available) {
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
+ if (result < 0)
+ /* An error here may signal greater failure of GPU handling */
+ return result;
+ if (!result && enable) {
+ err = -ENODEV;
+ pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
+ return err;
+ }
+ }
+
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
if (err) {
pr_warn("Failed to set egpu disable: %d\n", err);
@@ -764,6 +788,30 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
if (optimus > 1)
return -EINVAL;

+ if (asus->dgpu_disable_available) {
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU);
+ if (result < 0)
+ /* An error here may signal greater failure of GPU handling */
+ return result;
+ if (result && !optimus) {
+ err = -ENODEV;
+ pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err);
+ return err;
+ }
+ }
+
+ if (asus->egpu_enable_available) {
+ result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU);
+ if (result < 0)
+ /* An error here may signal greater failure of GPU handling */
+ return result;
+ if (result && !optimus) {
+ err = -ENODEV;
+ pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err);
+ return err;
+ }
+ }
+
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result);
if (err) {
dev_err(dev, "Failed to set GPU MUX mode: %d\n", err);
--
2.41.0


2023-07-04 11:51:38

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 2/8] platform/x86: asus-wmi: add support for showing middle fan RPM

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Some newer ASUS ROG laptops now have a middle/center fan in addition
> to the CPU and GPU fans. This new fan typically blows across the
> heatpipes and VRMs betweent eh CPU and GPU.
>
> This commit exposes that fan to PWM control plus showing RPM.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans



> ---
> drivers/platform/x86/asus-wmi.c | 91 ++++++++++++++++++++++
> include/linux/platform_data/x86/asus-wmi.h | 1 +
> 2 files changed, 92 insertions(+)
>
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index f23375d5fb82..375d25ae0aca 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -72,6 +72,7 @@ module_param(fnlock_default, bool, 0444);
>
> #define ASUS_WMI_FNLOCK_BIOS_DISABLED BIT(0)
>
> +#define ASUS_MID_FAN_DESC "mid_fan"
> #define ASUS_GPU_FAN_DESC "gpu_fan"
> #define ASUS_FAN_DESC "cpu_fan"
> #define ASUS_FAN_MFUN 0x13
> @@ -229,8 +230,10 @@ struct asus_wmi {
>
> enum fan_type fan_type;
> enum fan_type gpu_fan_type;
> + enum fan_type mid_fan_type;
> int fan_pwm_mode;
> int gpu_fan_pwm_mode;
> + int mid_fan_pwm_mode;
> int agfn_pwm;
>
> bool fan_boost_mode_available;
> @@ -2129,6 +2132,31 @@ static ssize_t fan2_label_show(struct device *dev,
> return sysfs_emit(buf, "%s\n", ASUS_GPU_FAN_DESC);
> }
>
> +/* Middle/Center fan on modern ROG laptops */
> +static ssize_t fan3_input_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> + int value;
> + int ret;
> +
> + ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_MID_FAN_CTRL, &value);
> + if (ret < 0)
> + return ret;
> +
> + value &= 0xffff;
> +
> + return sysfs_emit(buf, "%d\n", value * 100);
> +}
> +
> +static ssize_t fan3_label_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + return sysfs_emit(buf, "%s\n", ASUS_MID_FAN_DESC);
> +}
> +
> static ssize_t pwm2_enable_show(struct device *dev,
> struct device_attribute *attr,
> char *buf)
> @@ -2175,6 +2203,52 @@ static ssize_t pwm2_enable_store(struct device *dev,
> return count;
> }
>
> +static ssize_t pwm3_enable_show(struct device *dev,
> + struct device_attribute *attr,
> + char *buf)
> +{
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + return sysfs_emit(buf, "%d\n", asus->mid_fan_pwm_mode);
> +}
> +
> +static ssize_t pwm3_enable_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> + int state;
> + int value;
> + int ret;
> + u32 retval;
> +
> + ret = kstrtouint(buf, 10, &state);
> + if (ret)
> + return ret;
> +
> + switch (state) { /* standard documented hwmon values */
> + case ASUS_FAN_CTRL_FULLSPEED:
> + value = 1;
> + break;
> + case ASUS_FAN_CTRL_AUTO:
> + value = 0;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_MID_FAN_CTRL,
> + value, &retval);
> + if (ret)
> + return ret;
> +
> + if (retval != 1)
> + return -EIO;
> +
> + asus->mid_fan_pwm_mode = state;
> + return count;
> +}
> +
> /* Fan1 */
> static DEVICE_ATTR_RW(pwm1);
> static DEVICE_ATTR_RW(pwm1_enable);
> @@ -2184,6 +2258,10 @@ static DEVICE_ATTR_RO(fan1_label);
> static DEVICE_ATTR_RW(pwm2_enable);
> static DEVICE_ATTR_RO(fan2_input);
> static DEVICE_ATTR_RO(fan2_label);
> +/* Fan3 - Middle/center fan */
> +static DEVICE_ATTR_RW(pwm3_enable);
> +static DEVICE_ATTR_RO(fan3_input);
> +static DEVICE_ATTR_RO(fan3_label);
>
> /* Temperature */
> static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
> @@ -2192,10 +2270,13 @@ static struct attribute *hwmon_attributes[] = {
> &dev_attr_pwm1.attr,
> &dev_attr_pwm1_enable.attr,
> &dev_attr_pwm2_enable.attr,
> + &dev_attr_pwm3_enable.attr,
> &dev_attr_fan1_input.attr,
> &dev_attr_fan1_label.attr,
> &dev_attr_fan2_input.attr,
> &dev_attr_fan2_label.attr,
> + &dev_attr_fan3_input.attr,
> + &dev_attr_fan3_label.attr,
>
> &dev_attr_temp1_input.attr,
> NULL
> @@ -2221,6 +2302,11 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
> || attr == &dev_attr_pwm2_enable.attr) {
> if (asus->gpu_fan_type == FAN_TYPE_NONE)
> return 0;
> + } else if (attr == &dev_attr_fan3_input.attr
> + || attr == &dev_attr_fan3_label.attr
> + || attr == &dev_attr_pwm3_enable.attr) {
> + if (asus->mid_fan_type == FAN_TYPE_NONE)
> + return 0;
> } else if (attr == &dev_attr_temp1_input.attr) {
> int err = asus_wmi_get_devstate(asus,
> ASUS_WMI_DEVID_THERMAL_CTRL,
> @@ -2264,6 +2350,7 @@ static int asus_wmi_hwmon_init(struct asus_wmi *asus)
> static int asus_wmi_fan_init(struct asus_wmi *asus)
> {
> asus->gpu_fan_type = FAN_TYPE_NONE;
> + asus->mid_fan_type = FAN_TYPE_NONE;
> asus->fan_type = FAN_TYPE_NONE;
> asus->agfn_pwm = -1;
>
> @@ -2278,6 +2365,10 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
> if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_FAN_CTRL))
> asus->gpu_fan_type = FAN_TYPE_SPEC83;
>
> + /* Some models also have a center/middle fan */
> + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MID_FAN_CTRL))
> + asus->mid_fan_type = FAN_TYPE_SPEC83;
> +
> if (asus->fan_type == FAN_TYPE_NONE)
> return -ENODEV;
>
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index f90cafe26af1..2c03bda7703f 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -80,6 +80,7 @@
> #define ASUS_WMI_DEVID_FAN_CTRL 0x00110012 /* deprecated */
> #define ASUS_WMI_DEVID_CPU_FAN_CTRL 0x00110013
> #define ASUS_WMI_DEVID_GPU_FAN_CTRL 0x00110014
> +#define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031
> #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024
> #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
>


2023-07-04 11:57:11

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 3/8] platform/x86: asus-wmi: support middle fan custom curves

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Adds support for fan curves defined for the middle fan which
> is available on some ASUS ROG laptops.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans

p.s.

I've ran out of time to spend on reviews today, to be
continued later (for the rest of the series) ...







> ---
> drivers/platform/x86/asus-wmi.c | 77 +++++++++++++++++++++-
> include/linux/platform_data/x86/asus-wmi.h | 1 +
> 2 files changed, 76 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 375d25ae0aca..fb27218e51cf 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -113,6 +113,7 @@ module_param(fnlock_default, bool, 0444);
> #define FAN_CURVE_BUF_LEN 32
> #define FAN_CURVE_DEV_CPU 0x00
> #define FAN_CURVE_DEV_GPU 0x01
> +#define FAN_CURVE_DEV_MID 0x02
> /* Mask to determine if setting temperature or percentage */
> #define FAN_CURVE_PWM_MASK 0x04
>
> @@ -253,7 +254,8 @@ struct asus_wmi {
>
> bool cpu_fan_curve_available;
> bool gpu_fan_curve_available;
> - struct fan_curve_data custom_fan_curves[2];
> + bool mid_fan_curve_available;
> + struct fan_curve_data custom_fan_curves[3];
>
> struct platform_profile_handler platform_profile_handler;
> bool platform_profile_support;
> @@ -2080,6 +2082,8 @@ static ssize_t pwm1_enable_store(struct device *dev,
> asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false;
> if (asus->gpu_fan_curve_available)
> asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false;
> + if (asus->mid_fan_curve_available)
> + asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false;
>
> return count;
> }
> @@ -2531,6 +2535,9 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
> if (fan_dev == ASUS_WMI_DEVID_GPU_FAN_CURVE)
> fan_idx = FAN_CURVE_DEV_GPU;
>
> + if (fan_dev == ASUS_WMI_DEVID_MID_FAN_CURVE)
> + fan_idx = FAN_CURVE_DEV_MID;
> +
> curves = &asus->custom_fan_curves[fan_idx];
> err = asus_wmi_evaluate_method_buf(asus->dsts_id, fan_dev, mode, buf,
> FAN_CURVE_BUF_LEN);
> @@ -2819,6 +2826,42 @@ static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point7_pwm, fan_curve,
> static SENSOR_DEVICE_ATTR_2_RW(pwm2_auto_point8_pwm, fan_curve,
> FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7);
>
> +/* MID */
> +static SENSOR_DEVICE_ATTR_RW(pwm3_enable, fan_curve_enable, FAN_CURVE_DEV_GPU);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 0);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 1);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 2);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 3);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 4);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 5);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 6);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_temp, fan_curve,
> + FAN_CURVE_DEV_GPU, 7);
> +
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point1_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 0);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point2_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 1);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point3_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 2);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point4_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 3);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point5_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 4);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point6_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 5);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point7_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 6);
> +static SENSOR_DEVICE_ATTR_2_RW(pwm3_auto_point8_pwm, fan_curve,
> + FAN_CURVE_DEV_GPU | FAN_CURVE_PWM_MASK, 7);
> +
> static struct attribute *asus_fan_curve_attr[] = {
> /* CPU */
> &sensor_dev_attr_pwm1_enable.dev_attr.attr,
> @@ -2856,6 +2899,24 @@ static struct attribute *asus_fan_curve_attr[] = {
> &sensor_dev_attr_pwm2_auto_point6_pwm.dev_attr.attr,
> &sensor_dev_attr_pwm2_auto_point7_pwm.dev_attr.attr,
> &sensor_dev_attr_pwm2_auto_point8_pwm.dev_attr.attr,
> + /* MID */
> + &sensor_dev_attr_pwm3_enable.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point1_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point2_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point3_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point4_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point5_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point6_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point7_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point8_temp.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point1_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point2_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point3_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point4_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point5_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point6_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point7_pwm.dev_attr.attr,
> + &sensor_dev_attr_pwm3_auto_point8_pwm.dev_attr.attr,
> NULL
> };
>
> @@ -2875,6 +2936,9 @@ static umode_t asus_fan_curve_is_visible(struct kobject *kobj,
> if (asus->gpu_fan_curve_available && attr->name[3] == '2')
> return 0644;
>
> + if (asus->mid_fan_curve_available && attr->name[3] == '3')
> + return 0644;
> +
> return 0;
> }
>
> @@ -2904,7 +2968,14 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
> if (err)
> return err;
>
> - if (!asus->cpu_fan_curve_available && !asus->gpu_fan_curve_available)
> + err = fan_curve_check_present(asus, &asus->mid_fan_curve_available,
> + ASUS_WMI_DEVID_MID_FAN_CURVE);
> + if (err)
> + return err;
> +
> + if (!asus->cpu_fan_curve_available
> + && !asus->gpu_fan_curve_available
> + && !asus->mid_fan_curve_available)
> return 0;
>
> hwmon = devm_hwmon_device_register_with_groups(
> @@ -2973,6 +3044,8 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
> asus->custom_fan_curves[FAN_CURVE_DEV_CPU].enabled = false;
> if (asus->gpu_fan_curve_available)
> asus->custom_fan_curves[FAN_CURVE_DEV_GPU].enabled = false;
> + if (asus->mid_fan_curve_available)
> + asus->custom_fan_curves[FAN_CURVE_DEV_MID].enabled = false;
>
> return 0;
> }
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 2c03bda7703f..329efc086993 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -83,6 +83,7 @@
> #define ASUS_WMI_DEVID_MID_FAN_CTRL 0x00110031
> #define ASUS_WMI_DEVID_CPU_FAN_CURVE 0x00110024
> #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
> +#define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032
>
> /* Power */
> #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012


2023-07-11 10:14:55

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG

Hi Luke,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.5-rc1 next-20230711]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Luke-D-Jones/platform-x86-asus-wmi-add-support-for-showing-charger-mode/20230630-133937
base: linus/master
patch link: https://lore.kernel.org/r/20230630053552.976579-9-luke%40ljones.dev
patch subject: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG
reproduce: (https://download.01.org/0day-ci/archive/20230711/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All warnings (new ones prefixed by >>):

>> Documentation/ABI/testing/sysfs-platform-asus-wmi:131: WARNING: Unexpected indentation.

vim +131 Documentation/ABI/testing/sysfs-platform-asus-wmi

> 131 Date: Jun 2023
132 KernelVersion: 6.5
133 Contact: "Luke Jones" <[email protected]>
134 Description:
135 Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
136 Shown on Intel+Nvidia or AMD+Nvidia based systems.
137 * min=5, max=250
138

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-07-12 14:54:00

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 4/8] platform/x86: asus-wmi: add WMI method to show if egpu connected

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Exposes the WMI method which tells if the eGPU is properly connected
> on the devices that support it.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans


> ---
> .../ABI/testing/sysfs-platform-asus-wmi | 11 +++++++++-
> drivers/platform/x86/asus-wmi.c | 21 +++++++++++++++++++
> include/linux/platform_data/x86/asus-wmi.h | 4 +++-
> 3 files changed, 34 insertions(+), 2 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index eb29e3023c7b..878daf7c2036 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -107,4 +107,13 @@ Description:
> Get the current charging mode being used:
> * 1 - Barrel connected charger,
> * 2 - USB-C charging
> - * 3 - Both connected, barrel used for charging
> \ No newline at end of file
> + * 3 - Both connected, barrel used for charging
> +
> +What: /sys/devices/platform/<platform>/egpu_connected
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Show if the egpu (XG Mobile) is correctly connected:
> + * 0 - False,
> + * 1 - True
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index fb27218e51cf..0c8a4a46b121 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -243,6 +243,7 @@ struct asus_wmi {
>
> bool charge_mode_available;
> bool egpu_enable_available;
> + bool egpu_connect_available;
> bool dgpu_disable_available;
> bool gpu_mux_mode_available;
>
> @@ -709,6 +710,22 @@ static ssize_t egpu_enable_store(struct device *dev,
> }
> static DEVICE_ATTR_RW(egpu_enable);
>
> +/* Is eGPU connected? *********************************************************/
> +static ssize_t egpu_connected_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> + int result;
> +
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
> + if (result < 0)
> + return result;
> +
> + return sysfs_emit(buf, "%d\n", result);
> +}
> +
> +static DEVICE_ATTR_RO(egpu_connected);
> +
> /* gpu mux switch *************************************************************/
> static ssize_t gpu_mux_mode_show(struct device *dev,
> struct device_attribute *attr, char *buf)
> @@ -3645,6 +3662,7 @@ static struct attribute *platform_attributes[] = {
> &dev_attr_touchpad.attr,
> &dev_attr_charge_mode.attr,
> &dev_attr_egpu_enable.attr,
> + &dev_attr_egpu_connected.attr,
> &dev_attr_dgpu_disable.attr,
> &dev_attr_gpu_mux_mode.attr,
> &dev_attr_lid_resume.attr,
> @@ -3677,6 +3695,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> ok = asus->charge_mode_available;
> else if (attr == &dev_attr_egpu_enable.attr)
> ok = asus->egpu_enable_available;
> + else if (attr == &dev_attr_egpu_connected.attr)
> + ok = asus->egpu_connect_available;
> else if (attr == &dev_attr_dgpu_disable.attr)
> ok = asus->dgpu_disable_available;
> else if (attr == &dev_attr_gpu_mux_mode.attr)
> @@ -3943,6 +3963,7 @@ static int asus_wmi_add(struct platform_device *pdev)
>
> asus->charge_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CHARGE_MODE);
> asus->egpu_enable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU);
> + asus->egpu_connect_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
> asus->dgpu_disable_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_DGPU);
> asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
> asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 329efc086993..2034648f8cdf 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -100,7 +100,9 @@
> /* Charging mode - 1=Barrel, 2=USB */
> #define ASUS_WMI_DEVID_CHARGE_MODE 0x0012006C
>
> -/* dgpu on/off */
> +/* epu is connected? 1 == true */
> +#define ASUS_WMI_DEVID_EGPU_CONNECTED 0x00090018
> +/* egpu on/off */
> #define ASUS_WMI_DEVID_EGPU 0x00090019
>
> /* dgpu on/off */


2023-07-12 14:58:31

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 6/8] platform/x86: asus-wmi: add safety checks to gpu switching

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Add safety checking to dgpu_disable, egpu_enable, gpu_mux_mode.
>
> These checks prevent users from doing such things as:
> - disabling the dGPU while is muxed to drive the internal screen
> - enabling the eGPU which also disables the dGPU, while muxed to
> the internal screen
> - switching the MUX to dGPU while the dGPU is disabled
>
> Signed-off-by: Luke D. Jones <[email protected]>
> ---
> drivers/platform/x86/asus-wmi.c | 50 ++++++++++++++++++++++++++++++++-
> 1 file changed, 49 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 821addb284d7..602426a7fb41 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -645,6 +645,18 @@ static ssize_t dgpu_disable_store(struct device *dev,
> if (disable > 1)
> return -EINVAL;
>
> + if (asus->gpu_mux_mode_available) {
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
> + if (result < 0)
> + /* An error here may signal greater failure of GPU handling */
> + return result;
> + if (!result && disable) {
> + err = -ENODEV;
> + pr_warn("Can not disable dGPU when the MUX is in dGPU mode: %d\n", err);
> + return err;
> + }
> + }
> +
> err = asus_wmi_set_devstate(ASUS_WMI_DEVID_DGPU, disable, &result);
> if (err) {
> pr_warn("Failed to set dgpu disable: %d\n", err);
> @@ -693,7 +705,7 @@ static ssize_t egpu_enable_store(struct device *dev,
> if (enable > 1)
> return -EINVAL;
>
> - err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
> if (err < 0)
> return err;
> if (err < 1) {

This seems like a stray and undesired change. I'll drop this err -> result change
when merging this.

Otherwise looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans





> @@ -702,6 +714,18 @@ static ssize_t egpu_enable_store(struct device *dev,
> return err;
> }
>
> + if (asus->gpu_mux_mode_available) {
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPU_MUX);
> + if (result < 0)
> + /* An error here may signal greater failure of GPU handling */
> + return result;
> + if (!result && enable) {
> + err = -ENODEV;
> + pr_warn("Can not enable eGPU when the MUX is in dGPU mode: %d\n", err);
> + return err;
> + }
> + }
> +
> err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
> if (err) {
> pr_warn("Failed to set egpu disable: %d\n", err);
> @@ -764,6 +788,30 @@ static ssize_t gpu_mux_mode_store(struct device *dev,
> if (optimus > 1)
> return -EINVAL;
>
> + if (asus->dgpu_disable_available) {
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_DGPU);
> + if (result < 0)
> + /* An error here may signal greater failure of GPU handling */
> + return result;
> + if (result && !optimus) {
> + err = -ENODEV;
> + pr_warn("Can not switch MUX to dGPU mode when dGPU is disabled: %d\n", err);
> + return err;
> + }
> + }
> +
> + if (asus->egpu_enable_available) {
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU);
> + if (result < 0)
> + /* An error here may signal greater failure of GPU handling */
> + return result;
> + if (result && !optimus) {
> + err = -ENODEV;
> + pr_warn("Can not switch MUX to dGPU mode when eGPU is enabled: %d\n", err);
> + return err;
> + }
> + }
> +
> err = asus_wmi_set_devstate(ASUS_WMI_DEVID_GPU_MUX, optimus, &result);
> if (err) {
> dev_err(dev, "Failed to set GPU MUX mode: %d\n", err);


2023-07-12 14:58:47

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 7/8] platform/x86: asus-wmi: support setting mini-LED mode

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Support changing the mini-LED mode on some of the newer ASUS laptops.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans


> ---
> .../ABI/testing/sysfs-platform-asus-wmi | 9 ++++
> drivers/platform/x86/asus-wmi.c | 53 +++++++++++++++++++
> include/linux/platform_data/x86/asus-wmi.h | 1 +
> 3 files changed, 63 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 878daf7c2036..5624bdef49cb 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -117,3 +117,12 @@ Description:
> Show if the egpu (XG Mobile) is correctly connected:
> * 0 - False,
> * 1 - True
> +
> +What: /sys/devices/platform/<platform>/mini_led_mode
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Change the mini-LED mode:
> + * 0 - Single-zone,
> + * 1 - Multi-zone
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 602426a7fb41..1fc9e8afc2f3 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -265,6 +265,7 @@ struct asus_wmi {
> bool battery_rsoc_available;
>
> bool panel_overdrive_available;
> + bool mini_led_mode_available;
>
> struct hotplug_slot hotplug_slot;
> struct mutex hotplug_lock;
> @@ -1820,6 +1821,54 @@ static ssize_t panel_od_store(struct device *dev,
> }
> static DEVICE_ATTR_RW(panel_od);
>
> +/* Mini-LED mode **************************************************************/
> +static ssize_t mini_led_mode_show(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> + int result;
> +
> + result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
> + if (result < 0)
> + return result;
> +
> + return sysfs_emit(buf, "%d\n", result);
> +}
> +
> +static ssize_t mini_led_mode_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 mode;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &mode);
> + if (result)
> + return result;
> +
> + if (mode > 1)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MINI_LED_MODE, mode, &result);
> +
> + if (err) {
> + pr_warn("Failed to set mini-LED: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set mini-LED mode (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "mini_led_mode");
> +
> + return count;
> +}
> +static DEVICE_ATTR_RW(mini_led_mode);
> +
> /* Quirks *********************************************************************/
>
> static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
> @@ -3727,6 +3776,7 @@ static struct attribute *platform_attributes[] = {
> &dev_attr_fan_boost_mode.attr,
> &dev_attr_throttle_thermal_policy.attr,
> &dev_attr_panel_od.attr,
> + &dev_attr_mini_led_mode.attr,
> NULL
> };
>
> @@ -3764,6 +3814,8 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> ok = asus->throttle_thermal_policy_available;
> else if (attr == &dev_attr_panel_od.attr)
> ok = asus->panel_overdrive_available;
> + else if (attr == &dev_attr_mini_led_mode.attr)
> + ok = asus->mini_led_mode_available;
>
> if (devid != -1)
> ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
> @@ -4026,6 +4078,7 @@ static int asus_wmi_add(struct platform_device *pdev)
> asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
> asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
> asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
> + asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
>
> err = fan_boost_mode_check_present(asus);
> if (err)
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index 2034648f8cdf..ea80361ac6c7 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -66,6 +66,7 @@
> #define ASUS_WMI_DEVID_CAMERA 0x00060013
> #define ASUS_WMI_DEVID_LID_FLIP 0x00060062
> #define ASUS_WMI_DEVID_LID_FLIP_ROG 0x00060077
> +#define ASUS_WMI_DEVID_MINI_LED_MODE 0x0005001E
>
> /* Storage */
> #define ASUS_WMI_DEVID_CARDREADER 0x00080013


2023-07-12 15:15:46

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 5/8] platform/x86: asus-wmi: don't allow eGPU switching if eGPU not connected

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Check the ASUS_WMI_DEVID_EGPU_CONNECTED method for eGPU connection
> before allowing the ASUS_WMI_DEVID_EGPU method to run.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

Regards,

Hans

> ---
> drivers/platform/x86/asus-wmi.c | 9 +++++++++
> 1 file changed, 9 insertions(+)
>
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 0c8a4a46b121..821addb284d7 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -693,6 +693,15 @@ static ssize_t egpu_enable_store(struct device *dev,
> if (enable > 1)
> return -EINVAL;
>
> + err = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_EGPU_CONNECTED);
> + if (err < 0)
> + return err;
> + if (err < 1) {
> + err = -ENODEV;
> + pr_warn("Failed to set egpu disable: %d\n", err);
> + return err;
> + }
> +
> err = asus_wmi_set_devstate(ASUS_WMI_DEVID_EGPU, enable, &result);
> if (err) {
> pr_warn("Failed to set egpu disable: %d\n", err);


2023-07-12 15:22:50

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 8/8] platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> Expose various CPU and dGPU tunables that are available on many ASUS
> ROG laptops. The tunables shown in sysfs will vary depending on the CPU
> and dGPU vendor.
>
> All of these variables are write only and there is no easy way to find
> what the defaults are. In general they seem to default to the max value
> the vendor sets for the CPU and dGPU package - this is not the same as
> the min/max writable value. Values written to these variables that are
> beyond the capabilities of the CPU are ignored by the laptop.
>
> Signed-off-by: Luke D. Jones <[email protected]>

Thanks, patch looks good to me:

Reviewed-by: Hans de Goede <[email protected]>

(I'll fix the make htmldocs warning lkp spotted while merging this).

Regards,

Hans

> ---
> .../ABI/testing/sysfs-platform-asus-wmi | 58 ++++
> drivers/platform/x86/asus-wmi.c | 285 ++++++++++++++++++
> include/linux/platform_data/x86/asus-wmi.h | 9 +
> 3 files changed, 352 insertions(+)
>
> diff --git a/Documentation/ABI/testing/sysfs-platform-asus-wmi b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> index 5624bdef49cb..caaccd28fabf 100644
> --- a/Documentation/ABI/testing/sysfs-platform-asus-wmi
> +++ b/Documentation/ABI/testing/sysfs-platform-asus-wmi
> @@ -126,3 +126,61 @@ Description:
> Change the mini-LED mode:
> * 0 - Single-zone,
> * 1 - Multi-zone
> +
> +What: /sys/devices/platform/<platform>/ppt_pl1_spl
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the Package Power Target total of CPU: PL1 on Intel, SPL on AMD.
> + Shown on Intel+Nvidia or AMD+Nvidia based systems.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_pl2_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the Slow Package Power Tracking Limit of CPU: PL2 on Intel, SPPT,
> + on AMD. Shown on Intel+Nvidia or AMD+Nvidia based systems.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_fppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the Fast Package Power Tracking Limit of CPU. AMD+Nvidia only.
> + * min=5, max=250
> +
> +What: /sys/devices/platform/<platform>/ppt_apu_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the APU SPPT limit. Shown on full AMD systems only.
> + * min=5, max=130
> +
> +What: /sys/devices/platform/<platform>/ppt_platform_sppt
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the platform SPPT limit. Shown on full AMD systems only.
> + * min=5, max=130
> +
> +What: /sys/devices/platform/<platform>/nv_dynamic_boost
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the dynamic boost limit of the Nvidia dGPU:
> + * min=5, max=25
> +
> +What: /sys/devices/platform/<platform>/nv_temp_target
> +Date: Jun 2023
> +KernelVersion: 6.5
> +Contact: "Luke Jones" <[email protected]>
> +Description:
> + Set the target temperature limit of the Nvidia dGPU:
> + * min=75, max=87
> diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
> index 1fc9e8afc2f3..d9a353081f91 100644
> --- a/drivers/platform/x86/asus-wmi.c
> +++ b/drivers/platform/x86/asus-wmi.c
> @@ -117,6 +117,16 @@ module_param(fnlock_default, bool, 0444);
> /* Mask to determine if setting temperature or percentage */
> #define FAN_CURVE_PWM_MASK 0x04
>
> +/* Limits for tunables available on ASUS ROG laptops */
> +#define PPT_TOTAL_MIN 5
> +#define PPT_TOTAL_MAX 250
> +#define PPT_CPU_MIN 5
> +#define PPT_CPU_MAX 130
> +#define NVIDIA_BOOST_MIN 5
> +#define NVIDIA_BOOST_MAX 25
> +#define NVIDIA_TEMP_MIN 75
> +#define NVIDIA_TEMP_MAX 87
> +
> static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };
>
> static int throttle_thermal_policy_write(struct asus_wmi *);
> @@ -247,6 +257,15 @@ struct asus_wmi {
> bool dgpu_disable_available;
> bool gpu_mux_mode_available;
>
> + /* Tunables provided by ASUS for gaming laptops */
> + bool ppt_pl2_sppt_available;
> + bool ppt_pl1_spl_available;
> + bool ppt_apu_sppt_available;
> + bool ppt_plat_sppt_available;
> + bool ppt_fppt_available;
> + bool nv_dyn_boost_available;
> + bool nv_temp_tgt_available;
> +
> bool kbd_rgb_mode_available;
> bool kbd_rgb_state_available;
>
> @@ -946,6 +965,244 @@ static const struct attribute_group *kbd_rgb_mode_groups[] = {
> NULL,
> };
>
> +/* Tunable: PPT: Intel=PL1, AMD=SPPT *****************************************/
> +static ssize_t ppt_pl2_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL2_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_pl2_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_pl2_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl2_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_pl2_sppt);
> +
> +/* Tunable: PPT, Intel=PL1, AMD=SPL ******************************************/
> +static ssize_t ppt_pl1_spl_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PL1_SPL, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_pl1_spl: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_pl1_spl (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_pl1_spl");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_pl1_spl);
> +
> +/* Tunable: PPT APU FPPT ******************************************************/
> +static ssize_t ppt_fppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_TOTAL_MIN || value > PPT_TOTAL_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_FPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_fppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_fppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_fpu_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_fppt);
> +
> +/* Tunable: PPT APU SPPT *****************************************************/
> +static ssize_t ppt_apu_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_APU_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_apu_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_apu_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_apu_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_apu_sppt);
> +
> +/* Tunable: PPT platform SPPT ************************************************/
> +static ssize_t ppt_platform_sppt_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < PPT_CPU_MIN || value > PPT_CPU_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_PPT_PLAT_SPPT, value, &result);
> + if (err) {
> + pr_warn("Failed to set ppt_platform_sppt: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set ppt_platform_sppt (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "ppt_platform_sppt");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(ppt_platform_sppt);
> +
> +/* Tunable: NVIDIA dynamic boost *********************************************/
> +static ssize_t nv_dynamic_boost_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < NVIDIA_BOOST_MIN || value > NVIDIA_BOOST_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_DYN_BOOST, value, &result);
> + if (err) {
> + pr_warn("Failed to set nv_dynamic_boost: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set nv_dynamic_boost (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_dynamic_boost");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(nv_dynamic_boost);
> +
> +/* Tunable: NVIDIA temperature target ****************************************/
> +static ssize_t nv_temp_target_store(struct device *dev,
> + struct device_attribute *attr,
> + const char *buf, size_t count)
> +{
> + int result, err;
> + u32 value;
> +
> + struct asus_wmi *asus = dev_get_drvdata(dev);
> +
> + result = kstrtou32(buf, 10, &value);
> + if (result)
> + return result;
> +
> + if (value < NVIDIA_TEMP_MIN || value > NVIDIA_TEMP_MAX)
> + return -EINVAL;
> +
> + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_NV_THERM_TARGET, value, &result);
> + if (err) {
> + pr_warn("Failed to set nv_temp_target: %d\n", err);
> + return err;
> + }
> +
> + if (result > 1) {
> + pr_warn("Failed to set nv_temp_target (result): 0x%x\n", result);
> + return -EIO;
> + }
> +
> + sysfs_notify(&asus->platform_device->dev.kobj, NULL, "nv_temp_target");
> +
> + return count;
> +}
> +static DEVICE_ATTR_WO(nv_temp_target);
> +
> /* Battery ********************************************************************/
>
> /* The battery maximum charging percentage */
> @@ -3775,6 +4032,13 @@ static struct attribute *platform_attributes[] = {
> &dev_attr_als_enable.attr,
> &dev_attr_fan_boost_mode.attr,
> &dev_attr_throttle_thermal_policy.attr,
> + &dev_attr_ppt_pl2_sppt.attr,
> + &dev_attr_ppt_pl1_spl.attr,
> + &dev_attr_ppt_fppt.attr,
> + &dev_attr_ppt_apu_sppt.attr,
> + &dev_attr_ppt_platform_sppt.attr,
> + &dev_attr_nv_dynamic_boost.attr,
> + &dev_attr_nv_temp_target.attr,
> &dev_attr_panel_od.attr,
> &dev_attr_mini_led_mode.attr,
> NULL
> @@ -3812,6 +4076,20 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
> ok = asus->fan_boost_mode_available;
> else if (attr == &dev_attr_throttle_thermal_policy.attr)
> ok = asus->throttle_thermal_policy_available;
> + else if (attr == &dev_attr_ppt_pl2_sppt.attr)
> + ok = asus->ppt_pl2_sppt_available;
> + else if (attr == &dev_attr_ppt_pl1_spl.attr)
> + ok = asus->ppt_pl1_spl_available;
> + else if (attr == &dev_attr_ppt_fppt.attr)
> + ok = asus->ppt_fppt_available;
> + else if (attr == &dev_attr_ppt_apu_sppt.attr)
> + ok = asus->ppt_apu_sppt_available;
> + else if (attr == &dev_attr_ppt_platform_sppt.attr)
> + ok = asus->ppt_plat_sppt_available;
> + else if (attr == &dev_attr_nv_dynamic_boost.attr)
> + ok = asus->nv_dyn_boost_available;
> + else if (attr == &dev_attr_nv_temp_target.attr)
> + ok = asus->nv_temp_tgt_available;
> else if (attr == &dev_attr_panel_od.attr)
> ok = asus->panel_overdrive_available;
> else if (attr == &dev_attr_mini_led_mode.attr)
> @@ -4077,6 +4355,13 @@ static int asus_wmi_add(struct platform_device *pdev)
> asus->gpu_mux_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_GPU_MUX);
> asus->kbd_rgb_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE);
> asus->kbd_rgb_state_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_STATE);
> + asus->ppt_pl2_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL2_SPPT);
> + asus->ppt_pl1_spl_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PL1_SPL);
> + asus->ppt_fppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_FPPT);
> + asus->ppt_apu_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_APU_SPPT);
> + asus->ppt_plat_sppt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PPT_PLAT_SPPT);
> + asus->nv_dyn_boost_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_DYN_BOOST);
> + asus->nv_temp_tgt_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_NV_THERM_TARGET);
> asus->panel_overdrive_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_PANEL_OD);
> asus->mini_led_mode_available = asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MINI_LED_MODE);
>
> diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h
> index ea80361ac6c7..16e99a1c37fc 100644
> --- a/include/linux/platform_data/x86/asus-wmi.h
> +++ b/include/linux/platform_data/x86/asus-wmi.h
> @@ -86,6 +86,15 @@
> #define ASUS_WMI_DEVID_GPU_FAN_CURVE 0x00110025
> #define ASUS_WMI_DEVID_MID_FAN_CURVE 0x00110032
>
> +/* Tunables for AUS ROG laptops */
> +#define ASUS_WMI_DEVID_PPT_PL2_SPPT 0x001200A0
> +#define ASUS_WMI_DEVID_PPT_PL1_SPL 0x001200A3
> +#define ASUS_WMI_DEVID_PPT_APU_SPPT 0x001200B0
> +#define ASUS_WMI_DEVID_PPT_PLAT_SPPT 0x001200B1
> +#define ASUS_WMI_DEVID_PPT_FPPT 0x001200C1
> +#define ASUS_WMI_DEVID_NV_DYN_BOOST 0x001200C0
> +#define ASUS_WMI_DEVID_NV_THERM_TARGET 0x001200C2
> +
> /* Power */
> #define ASUS_WMI_DEVID_PROCESSOR_STATE 0x00120012
>


2023-07-12 15:34:04

by Hans de Goede

[permalink] [raw]
Subject: Re: [PATCH v2 0/8] platform/x86: asus-wmi:

Hi,

On 6/30/23 07:35, Luke D. Jones wrote:
> This patch series adds or exposes more features that are available in the ROG
> laptop series.
>
> - expose dGPU and CPU tunables for ROG
> - These are things like GPU boost, CPU Pl1 and PL2, package power limits
> - support setting mini-LED mode
> - Some newer laptops have a screen that can toggle between regular style
> backlight and using mini-LED backlight
> - add WMI method to show if egpu connected
> - This WMI method can be monitored/queried to see if it is possible to begin
> the change-over to eGPU
> - support middle fan custom curves
> - Some newer laptops have a center/middle fan which blows across the CPU and GPU
> - add support for showing middle fan RPM
> - add support for showing charger mode (AC, USB-C, both plugged)
> - add additional checks to GPU switching code
> - These try to prevent a sceanrio such as the user disabling the dGPU while it
> is driving the internal panel via MUX, resulting in no output at all.
> There are no checks in the ACPI code for this, but on some newer models ASUS
> did finally add a switch in the BIOS menu. It is best to try and prevent this
> at the kernel level rather than userland level.
>
> All patches pass ./scripts/checkpatch.pl

Thank you for your patch-series, I've applied the series to my
review-hans branch:
https://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86.git/log/?h=review-hans

Note it will show up in my review-hans branch once I've pushed my
local branch there, which might take a while.

Once I've run some tests on this branch the patches there will be
added to the platform-drivers-x86/for-next branch and eventually
will be included in the pdx86 pull-request to Linus for the next
merge-window.

Regards,

Hans



>
> Changelog:
> - v2-0008-platform-x86-asus-wmi-expose-dGPU-and-CPU-tunable.patch
> - Rename the WMI defs to match what ASUS supplied as names
> - Remove EDC and TDC exposure (unsafe)
> - Slight change to formatting
> - Add better notes to documentation
>
>
> Luke D. Jones (8):
> platform/x86: asus-wmi: add support for showing charger mode
> platform/x86: asus-wmi: add support for showing middle fan RPM
> platform/x86: asus-wmi: support middle fan custom curves
> platform/x86: asus-wmi: add WMI method to show if egpu connected
> platform/x86: asus-wmi: don't allow eGPU switching if eGPU not
> connected
> platform/x86: asus-wmi: add safety checks to gpu switching
> platform/x86: asus-wmi: support setting mini-LED mode
> platform/x86: asus-wmi: expose dGPU and CPU tunables for ROG
>
> .../ABI/testing/sysfs-platform-asus-wmi | 86 +++
> drivers/platform/x86/asus-wmi.c | 605 +++++++++++++++++-
> include/linux/platform_data/x86/asus-wmi.h | 19 +-
> 3 files changed, 707 insertions(+), 3 deletions(-)
>