From b39c54c59e4e9afaac37d0370b776660ba86cbae Mon Sep 17 00:00:00 2001 From: Marco Scardovi Date: Wed, 5 Aug 2026 20:28:06 +0200 Subject: platform/x86: asus-wmi: Add ASUS_WMI_DEVID_DGPU_POWER_STATE define MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add WMI device ID 0x00120097 (ASUS_WMI_DEVID_DGPU_POWER_STATE) to the asus-wmi platform header. This device ID is used on ASUS ROG laptops to query the discrete GPU (dGPU) power state level. Suggested-by: Denis Benato Signed-off-by: Marco Scardovi Link: https://patch.msgid.link/20260805183131.3075-2-scardracs@disroot.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- include/linux/platform_data/x86/asus-wmi.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index b5ed8c83ace1..289be6ac7335 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -140,8 +140,9 @@ #define ASUS_WMI_DEVID_APU_MEM 0x000600C1 -#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 +#define ASUS_WMI_DEVID_DGPU_POWER_STATE 0x00120097 #define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 +#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 /* gpu mux switch, 0 = dGPU, 1 = Optimus */ #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 -- cgit v1.2.3 From 5383cf280ef4f00b15f1d9e2a2886d0d02c0118b Mon Sep 17 00:00:00 2001 From: Thorsten Blum Date: Mon, 7 Sep 2026 10:43:20 +0200 Subject: lib/string_choices: Add str_supported_unsupported() helper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add str_supported_unsupported() to return "supported" or "unsupported" depending on the boolean argument. Also add the inverse str_unsupported_supported(). Suggested-by: Ilpo Järvinen Signed-off-by: Thorsten Blum Reviewed-by: Andy Shevchenko Link: https://patch.msgid.link/20260907084319.351688-5-blum@kernel.org Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- include/linux/string_choices.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'include/linux') diff --git a/include/linux/string_choices.h b/include/linux/string_choices.h index ee84087d4b26..a2eba454004f 100644 --- a/include/linux/string_choices.h +++ b/include/linux/string_choices.h @@ -65,6 +65,12 @@ static inline const char *str_read_write(bool v) } #define str_write_read(v) str_read_write(!(v)) +static inline const char *str_supported_unsupported(bool v) +{ + return v ? "supported" : "unsupported"; +} +#define str_unsupported_supported(v) str_supported_unsupported(!(v)) + static inline const char *str_true_false(bool v) { return v ? "true" : "false"; -- cgit v1.2.3 From d95982b2ea3453998466efe1e7e06fee7392e800 Mon Sep 17 00:00:00 2001 From: Patryk Dańków Date: Tue, 15 Sep 2026 17:41:28 +0000 Subject: platform/x86: asus-wmi: Add mute LED support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for WMI device 0x0004001c and register it as the platform::mute LED using the audio-mute trigger. The device ID is present in the PM3406CKA DSDT and is also used by GHelper for controlling the same LED. Tested on ASUS ExpertBook PM3406CKA. Signed-off-by: Patryk Dańków Reviewed-by: Denis Benato Link: https://patch.msgid.link/20260915174110.67871-2-patryk.dankow@protonmail.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-wmi.c | 26 +++++++++++++++++++++++++- include/linux/platform_data/x86/asus-wmi.h | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c index 15500e1f87bf..966b64b3962c 100644 --- a/drivers/platform/x86/asus-wmi.c +++ b/drivers/platform/x86/asus-wmi.c @@ -262,6 +262,7 @@ struct asus_wmi { struct led_classdev lightbar_led; int lightbar_led_wk; struct led_classdev micmute_led; + struct led_classdev mute_led; struct led_classdev camera_led; struct workqueue_struct *led_workqueue; struct work_struct tpd_led_work; @@ -2054,6 +2055,16 @@ static int micmute_led_set(struct led_classdev *led_cdev, return err < 0 ? err : 0; } +static int mute_led_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int state = brightness != LED_OFF; + int err; + + err = asus_wmi_set_devstate(ASUS_WMI_DEVID_MUTE_LED, state, NULL); + return err < 0 ? err : 0; +} + static enum led_brightness camera_led_get(struct led_classdev *led_cdev) { struct asus_wmi *asus; @@ -2084,6 +2095,7 @@ static void asus_wmi_led_exit(struct asus_wmi *asus) led_classdev_unregister(&asus->wlan_led); led_classdev_unregister(&asus->lightbar_led); led_classdev_unregister(&asus->micmute_led); + led_classdev_unregister(&asus->mute_led); led_classdev_unregister(&asus->camera_led); if (asus->led_workqueue) @@ -2188,7 +2200,19 @@ static int asus_wmi_led_init(struct asus_wmi *asus) asus->micmute_led.default_trigger = "audio-micmute"; rv = led_classdev_register(&asus->platform_device->dev, - &asus->micmute_led); + &asus->micmute_led); + if (rv) + goto error; + } + + if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MUTE_LED)) { + asus->mute_led.name = "platform::mute"; + asus->mute_led.max_brightness = 1; + asus->mute_led.brightness_set_blocking = mute_led_set; + asus->mute_led.default_trigger = "audio-mute"; + + rv = led_classdev_register(&asus->platform_device->dev, + &asus->mute_led); if (rv) goto error; } diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index 289be6ac7335..be4d2873ffc9 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -54,6 +54,7 @@ #define ASUS_WMI_DEVID_LED5 0x00020015 #define ASUS_WMI_DEVID_LED6 0x00020016 #define ASUS_WMI_DEVID_MICMUTE_LED 0x00040017 +#define ASUS_WMI_DEVID_MUTE_LED 0x0004001C /* Disable Camera LED */ #define ASUS_WMI_DEVID_CAMERA_LED_NEG 0x00060078 /* 0 = on (unused) */ -- cgit v1.2.3 From 7fdfccf87676a17ab7a24b67595c701dd8d913a5 Mon Sep 17 00:00:00 2001 From: "Michael J. Ruhl" Date: Wed, 23 Sep 2026 11:11:19 -0700 Subject: platform/x86/intel/pmt: Add register access callbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some HW does not have direct MMIO access to PMT control and data features. Augment the current callback infrastructure (data access) to allow a registered driver to customize read/write access to the control paths for PMT usage. Signed-off-by: Michael J. Ruhl Link: https://patch.msgid.link/20260923181115.2514193-26-michael.j.ruhl@intel.com Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/intel/pmt/crashlog.c | 46 +++++++++++++++++++++++++++++-- include/linux/intel_vsec.h | 14 +++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c index 200373cbb020..d7018b495217 100644 --- a/drivers/platform/x86/intel/pmt/crashlog.c +++ b/drivers/platform/x86/intel/pmt/crashlog.c @@ -11,10 +11,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -124,12 +126,36 @@ struct pmt_crashlog_priv { * I/O */ +static int pmt_crashlog_read_reg(struct intel_pmt_entry *entry, u32 *reg, u32 offset) +{ + int ret; + + *reg = 0; + + if (entry->cb && entry->cb->read_reg) { + ret = entry->cb->read_reg(entry->dev, entry->header.guid, reg, offset); + if (ret) { + dev_err_ratelimited(entry->dev, "failed to read reg: %d\n", ret); + return ret; + } + } else { + *reg = readl(entry->disc_table + offset); + } + + return 0; +} + /* Read, modify, write the control register, setting or clearing @bit based on @set */ static int pmt_crashlog_rmw(struct crashlog_entry *crashlog, u32 bit, bool set) { const struct crashlog_control *control = &crashlog->info->control; struct intel_pmt_entry *entry = &crashlog->entry; - u32 reg = readl(entry->disc_table + control->offset); + u32 reg; + int ret; + + ret = pmt_crashlog_read_reg(entry, ®, control->offset); + if (ret) + return ret; reg &= ~control->trigger_mask; @@ -138,7 +164,15 @@ static int pmt_crashlog_rmw(struct crashlog_entry *crashlog, u32 bit, bool set) else reg &= ~bit; - writel(reg, entry->disc_table + control->offset); + if (entry->cb && entry->cb->write_reg) { + ret = entry->cb->write_reg(entry->dev, entry->header.guid, reg, control->offset); + if (ret) { + dev_err_ratelimited(entry->dev, "failed to write reg: %d\n", ret); + return ret; + } + } else { + writel(reg, entry->disc_table + control->offset); + } return 0; } @@ -147,7 +181,13 @@ static int pmt_crashlog_rmw(struct crashlog_entry *crashlog, u32 bit, bool set) static int pmt_crashlog_rc(struct crashlog_entry *crashlog, u32 bit, bool *state) { const struct crashlog_status *status = &crashlog->info->status; - u32 reg = readl(crashlog->entry.disc_table + status->offset); + struct intel_pmt_entry *entry = &crashlog->entry; + u32 reg; + int ret; + + ret = pmt_crashlog_read_reg(entry, ®, status->offset); + if (ret) + return ret; *state = !!(reg & bit); diff --git a/include/linux/intel_vsec.h b/include/linux/intel_vsec.h index 843cda8f8644..917d9397a993 100644 --- a/include/linux/intel_vsec.h +++ b/include/linux/intel_vsec.h @@ -90,13 +90,25 @@ enum intel_vsec_quirks { * @read_telem: when specified, called by client driver to access PMT * data (instead of direct copy). * * dev: device reference for the callback's use - * * guid: ID of data to acccss + * * guid: ID of data to access * * data: buffer for the data to be copied * * off: offset into the requested buffer * * count: size of buffer + * @read_reg: when specified called by client driver to read PMT state + * * dev: device reference for the callback's use + * * guid: ID of data to access + * * reg_data: register data + * * offset: offset of register to read + * @write_reg: when specified called by client driver to write PMT state + * * dev: device reference for the callback's use + * * guid: ID of data to access + * * reg_data: register data + * * offset: offset of register to write */ struct pmt_callbacks { int (*read_telem)(struct device *dev, u32 guid, u64 *data, loff_t off, u32 count); + int (*read_reg)(struct device *dev, u32 guid, u32 *reg_data, u32 offset); + int (*write_reg)(struct device *dev, u32 guid, u32 reg_data, u32 offset); }; struct vsec_feature_dependency { -- cgit v1.2.3 From 10eb812c822620c7a11ac2840076e1cb2330cf37 Mon Sep 17 00:00:00 2001 From: Denis Benato Date: Fri, 25 Sep 2026 14:42:27 +0000 Subject: platform/x86: asus-armoury: add dGPU disable fallback DEVID for ProArt H7606 series MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Newer ASUS ProArt laptops (e.g. H7606 series) implement dGPU power control on WMI DEVID 0x00090120 instead of the usual 0x00090020. The default DEVID returns 0xFFFFFFE2 on these models, so the dgpu_disable firmware attribute is never created and the dGPU cannot be re-enabled from Linux at all. Add a fallback probe for device ID 0x00090120 following the same approach as the gpu_mux_dev_id probe. Details for 0x00090120 (confirmed on H7606W using direct WMNB calls and inspecting the DSDT DEVS handler): - Reading DSTS returns 0x00010001 when the dGPU is off (CUMA=1), or 0x00010000 when it's on. - Writing DEVS: 0 enables the dGPU (calls PG00._ON() + Notifies PEGP, Device Check), and 1 disables or ejects it. This behavior matches the dgpu_disable attribute (1 = disabled). Signed-off-by: Denis Benato Link: https://patch.msgid.link/20260925144229.3693-4-denis.benato@linux.dev Reviewed-by: Ilpo Järvinen Signed-off-by: Ilpo Järvinen --- drivers/platform/x86/asus-armoury.c | 2 ++ include/linux/platform_data/x86/asus-wmi.h | 3 +++ 2 files changed, 5 insertions(+) (limited to 'include/linux') diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c index 7812e93734b8..7c54f616d701 100644 --- a/drivers/platform/x86/asus-armoury.c +++ b/drivers/platform/x86/asus-armoury.c @@ -950,6 +950,8 @@ static int asus_fw_attr_add(void) asus_armoury.dgpu_disable_dev_id = 0; if (armoury_has_devstate(ASUS_WMI_DEVID_DGPU)) asus_armoury.dgpu_disable_dev_id = ASUS_WMI_DEVID_DGPU; + else if (armoury_has_devstate(ASUS_WMI_DEVID_GPU_MODE)) + asus_armoury.dgpu_disable_dev_id = ASUS_WMI_DEVID_GPU_MODE; for (i = 0; i < ARRAY_SIZE(armoury_attr_groups); i++) { err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h index be4d2873ffc9..4ea1ccc1d0ee 100644 --- a/include/linux/platform_data/x86/asus-wmi.h +++ b/include/linux/platform_data/x86/asus-wmi.h @@ -139,6 +139,9 @@ /* dgpu on/off */ #define ASUS_WMI_DEVID_DGPU 0x00090020 +/* dgpu on/off - alternative to ASUS_WMI_DEVID_DGPU */ +#define ASUS_WMI_DEVID_GPU_MODE 0x00090120 + #define ASUS_WMI_DEVID_APU_MEM 0x000600C1 #define ASUS_WMI_DEVID_DGPU_POWER_STATE 0x00120097 -- cgit v1.2.3