public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
@ 2025-11-17 13:23 Werner Sembach
  2025-11-17 13:23 ` [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices Werner Sembach
                   ` (6 more replies)
  0 siblings, 7 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:23 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

With the Uniwill driver from Armin now accepted I want to push the first
big addon to it that I worked on in parallel.

First this adds all current Tuxedo devices to use at least the input part
of the new driver.

Second it adds a new feature for cTGP control on Uniwill devices with
NVIDIA GPUs and enables that on the TUXEDO devices.

I have not yet enabled the other features in this driver for TUXEDO devices
as they either don't apply (Uniwill did a line with Intel that behaves a
little different to the rest of their ECs and that line is what the features
Armin added are based on) or are, as of now, untested.

There are plenty more features currently implemented in the out of tree
tuxedo-drivers dkms package that I plan to port over one by one, but as
always: No ETA given.

Werner Sembach (6):
  platform/x86/uniwill: Add TUXEDO devices
  platform/x86/uniwill: Handle more WMI events required for TUXEDO
    devices
  platform/x86/uniwill: Implement cTGP setting
  platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  platform/x86/uniwill: Run callbacks of uniwill_dmi_table
  platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7
    MK1

 drivers/platform/x86/uniwill/uniwill-acpi.c | 546 ++++++++++++++++++--
 drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
 2 files changed, 502 insertions(+), 46 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 43+ messages in thread

* [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
@ 2025-11-17 13:23 ` Werner Sembach
  2025-11-18 11:03   ` Armin Wolf
  2025-11-17 13:23 ` [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for " Werner Sembach
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:23 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

Add all TUXEDO devices that can make use of this driver.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 308 ++++++++++++++++++++
 1 file changed, 308 insertions(+)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 014960d16211b..29bb3709bfcc8 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -1478,6 +1478,20 @@ static struct platform_driver uniwill_driver = {
 };
 
 static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
+	{
+		.ident = "XMG FUSION 15",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
+		},
+	},
+	{
+		.ident = "XMG FUSION 15",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
+		},
+	},
 	{
 		.ident = "Intel NUC x15",
 		.matches = {
@@ -1503,6 +1517,300 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 					UNIWILL_FEATURE_BATTERY |
 					UNIWILL_FEATURE_HWMON),
 	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
+		},
+	},
+	{
+		.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 17 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 17 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15 Gen1 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15 Gen1 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 17 Gen1 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 17 Gen1 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
+		},
+	},
+	{
+		.ident = "TUXEDO Trinity 15 Intel Gen1",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
+		},
+	},
+	{
+		.ident = "TUXEDO Trinity 17 Intel Gen1",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
+		},
+	},
+	{
+		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
+		},
+	},
+	{
+		.ident = "TUXEDO Pulse 14 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
+		},
+	},
+	{
+		.ident = "TUXEDO Pulse 15 Gen1 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
+		},
+	},
+	{
+		.ident = "TUXEDO Pulse 15 Gen2 AMD",
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
+			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
+		},
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
  2025-11-17 13:23 ` [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices Werner Sembach
@ 2025-11-17 13:23 ` Werner Sembach
  2025-11-18 11:08   ` Armin Wolf
  2025-11-17 13:24 ` [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting Werner Sembach
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:23 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

Handle some more WMI events that are triggered on TUXEDO devices.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
 drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
 2 files changed, 20 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 29bb3709bfcc8..0cb86a701b2e1 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
 
 	/* Reported in manual mode when toggling the airplane mode status */
 	{ KE_KEY,       UNIWILL_OSD_RFKILL,                     { KEY_RFKILL }},
+	{ KE_IGNORE,    UNIWILL_OSD_RADIOON,                    { KEY_UNKNOWN }},
+	{ KE_IGNORE,    UNIWILL_OSD_RADIOOFF,                   { KEY_UNKNOWN }},
 
 	/* Reported when user wants to cycle the platform profile */
-	{ KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_UNKNOWN }},
+	{ KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_F14 }},
 
 	/* Reported when the user wants to adjust the brightness of the keyboard */
 	{ KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN,               { KEY_KBDILLUMDOWN }},
@@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
 	/* Reported when the user wants to toggle the microphone mute status */
 	{ KE_KEY,       UNIWILL_OSD_MIC_MUTE,                   { KEY_MICMUTE }},
 
+	/* Reported when the user wants to toggle the mute status */
+	{ KE_IGNORE,    UNIWILL_OSD_MUTE,                       { KEY_MUTE }},
+
 	/* Reported when the user locks/unlocks the Fn key */
 	{ KE_IGNORE,    UNIWILL_OSD_FN_LOCK,                    { KEY_FN_ESC }},
 
 	/* Reported when the user wants to toggle the brightness of the keyboard */
 	{ KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE,             { KEY_KBDILLUMTOGGLE }},
+	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0,              { KEY_KBDILLUMTOGGLE }},
+	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1,              { KEY_KBDILLUMTOGGLE }},
+	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2,              { KEY_KBDILLUMTOGGLE }},
+	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3,              { KEY_KBDILLUMTOGGLE }},
+	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4,              { KEY_KBDILLUMTOGGLE }},
 
 	/* FIXME: find out the exact meaning of those events */
 	{ KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H,       { KEY_UNKNOWN }},
@@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
 	/* Reported when the user wants to toggle the benchmark mode status */
 	{ KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE,      { KEY_UNKNOWN }},
 
+	/* Reported when the user wants to toggle the webcam */
+	{ KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE,              { KEY_UNKNOWN }},
+
 	{ KE_END }
 };
 
@@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
 		}
 		mutex_unlock(&data->battery_lock);
 
+		return NOTIFY_OK;
+	case UNIWILL_OSD_DC_ADAPTER_CHANGED:
+		// noop for the time being
+
 		return NOTIFY_OK;
 	default:
 		mutex_lock(&data->input_lock);
diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
index 2bf69f2d80381..48783b2e9ffb9 100644
--- a/drivers/platform/x86/uniwill/uniwill-wmi.h
+++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
@@ -113,6 +113,8 @@
 
 #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE	0xC0
 
+#define UNIWILL_OSD_WEBCAM_TOGGLE		0xCF
+
 #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED	0xF0
 
 struct device;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
  2025-11-17 13:23 ` [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices Werner Sembach
  2025-11-17 13:23 ` [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for " Werner Sembach
@ 2025-11-17 13:24 ` Werner Sembach
  2025-11-18 11:12   ` Armin Wolf
  2025-11-17 13:24 ` [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe Werner Sembach
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:24 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

Uniwill offers user setable cTGP for their EC on devices using NVIDIA 3000
Series and newer GPUs. This patch implements this setting as a sysfs
attribute.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 110 +++++++++++++++++++-
 1 file changed, 107 insertions(+), 3 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 0cb86a701b2e1..de3417d9d1ac0 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -122,11 +122,11 @@
 #define CTGP_DB_DB_ENABLE		BIT(1)
 #define CTGP_DB_CTGP_ENABLE		BIT(2)
 
-#define EC_ADDR_CTGP_OFFSET		0x0744
+#define EC_ADDR_CTGP_DB_CTGP_OFFSET	0x0744
 
-#define EC_ADDR_TPP_OFFSET		0x0745
+#define EC_ADDR_CTGP_DB_TPP_OFFSET	0x0745
 
-#define EC_ADDR_MAX_TGP			0x0746
+#define EC_ADDR_CTGP_DB_DB_OFFSET	0x0746
 
 #define EC_ADDR_LIGHTBAR_AC_CTRL	0x0748
 #define LIGHTBAR_APP_EXISTS		BIT(0)
@@ -317,6 +317,7 @@
 #define UNIWILL_FEATURE_LIGHTBAR		BIT(3)
 #define UNIWILL_FEATURE_BATTERY			BIT(4)
 #define UNIWILL_FEATURE_HWMON			BIT(5)
+#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(6)
 
 struct uniwill_data {
 	struct device *dev;
@@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
 	case EC_ADDR_LIGHTBAR_BAT_RED:
 	case EC_ADDR_LIGHTBAR_BAT_GREEN:
 	case EC_ADDR_LIGHTBAR_BAT_BLUE:
+	case EC_ADDR_CTGP_DB_CTRL:
+	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
+	case EC_ADDR_CTGP_DB_TPP_OFFSET:
+	case EC_ADDR_CTGP_DB_DB_OFFSET:
 		return true;
 	default:
 		return false;
@@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
 	case EC_ADDR_LIGHTBAR_BAT_RED:
 	case EC_ADDR_LIGHTBAR_BAT_GREEN:
 	case EC_ADDR_LIGHTBAR_BAT_BLUE:
+	case EC_ADDR_CTGP_DB_CTRL:
+	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
+	case EC_ADDR_CTGP_DB_TPP_OFFSET:
+	case EC_ADDR_CTGP_DB_DB_OFFSET:
 		return true;
 	default:
 		return false;
@@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attri
 
 static DEVICE_ATTR_RW(breathing_in_suspend);
 
+static ssize_t ctgp_offset_store(struct device *dev, struct device_attribute *attr,
+				 const char *buf, size_t count)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	unsigned int value;
+	int ret;
+
+	ret = kstrtouint(buf, 0, &value);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, value);
+	if (ret < 0)
+		return ret;
+
+	return count;
+}
+
+static ssize_t ctgp_offset_show(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, &value);
+	if (ret < 0)
+		return ret;
+
+	return sysfs_emit(buf, "%u\n", value);
+}
+
+DEVICE_ATTR_RW(ctgp_offset);
+
+static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
+{
+	int ret;
+
+	if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
+		return 0;
+
+	ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
+				 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE,
+				 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
+	if (ret < 0)
+		return ret;
+
+	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static struct attribute *uniwill_attrs[] = {
 	/* Keyboard-related */
 	&dev_attr_fn_lock_toggle_enable.attr,
@@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
 	/* Lightbar-related */
 	&dev_attr_rainbow_animation.attr,
 	&dev_attr_breathing_in_suspend.attr,
+	/* Power-management-related */
+	&dev_attr_ctgp_offset.attr,
 	NULL
 };
 
@@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
 			return attr->mode;
 	}
 
+	if (attr == &dev_attr_ctgp_offset.attr) {
+		if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
+			return attr->mode;
+	}
+
 	return 0;
 }
 
@@ -1371,6 +1449,10 @@ static int uniwill_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
+	ret = uniwill_nvidia_ctgp_init(data);
+	if (ret < 0)
+		return ret;
+
 	return uniwill_input_init(data);
 }
 
@@ -1547,6 +1629,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
@@ -1554,6 +1637,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
@@ -1561,6 +1645,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
@@ -1575,6 +1660,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
@@ -1582,6 +1668,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
@@ -1694,6 +1781,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
@@ -1701,6 +1789,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
@@ -1708,6 +1797,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
@@ -1715,6 +1805,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
@@ -1722,6 +1813,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
@@ -1729,6 +1821,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
@@ -1736,6 +1829,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
@@ -1743,6 +1837,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
@@ -1750,6 +1845,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
@@ -1757,6 +1853,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
@@ -1764,6 +1861,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
@@ -1771,6 +1869,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
@@ -1778,6 +1877,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
@@ -1785,6 +1885,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
@@ -1792,6 +1893,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
@@ -1799,6 +1901,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
@@ -1806,6 +1909,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
 		},
+		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO Pulse 14 Gen1 AMD",
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
                   ` (2 preceding siblings ...)
  2025-11-17 13:24 ` [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting Werner Sembach
@ 2025-11-17 13:24 ` Werner Sembach
  2025-11-18 11:16   ` Armin Wolf
  2025-11-17 13:24 ` [PATCH 5/6] platform/x86/uniwill: Run callbacks of uniwill_dmi_table Werner Sembach
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:24 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

Move uniwill_dmi_table up and remove __intconst to make it also accessible
in the probe function.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 344 ++++++++++----------
 1 file changed, 172 insertions(+), 172 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index de3417d9d1ac0..9412783698685 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -1405,178 +1405,7 @@ static int uniwill_ec_init(struct uniwill_data *data)
 	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
 }
 
-static int uniwill_probe(struct platform_device *pdev)
-{
-	struct uniwill_data *data;
-	struct regmap *regmap;
-	acpi_handle handle;
-	int ret;
-
-	handle = ACPI_HANDLE(&pdev->dev);
-	if (!handle)
-		return -ENODEV;
-
-	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	data->dev = &pdev->dev;
-	data->handle = handle;
-	platform_set_drvdata(pdev, data);
-
-	regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
-	if (IS_ERR(regmap))
-		return PTR_ERR(regmap);
-
-	data->regmap = regmap;
-	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_ec_init(data);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_battery_init(data);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_led_init(data);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_hwmon_init(data);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_nvidia_ctgp_init(data);
-	if (ret < 0)
-		return ret;
-
-	return uniwill_input_init(data);
-}
-
-static void uniwill_shutdown(struct platform_device *pdev)
-{
-	struct uniwill_data *data = platform_get_drvdata(pdev);
-
-	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
-}
-
-static int uniwill_suspend_keyboard(struct uniwill_data *data)
-{
-	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
-		return 0;
-
-	/*
-	 * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
-	 * ourselves.
-	 */
-	return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
-}
-
-static int uniwill_suspend_battery(struct uniwill_data *data)
-{
-	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
-		return 0;
-
-	/*
-	 * Save the current charge limit in order to restore it during resume.
-	 * We cannot use the regmap code for that since this register needs to
-	 * be declared as volatile due to CHARGE_CTRL_REACHED.
-	 */
-	return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
-}
-
-static int uniwill_suspend(struct device *dev)
-{
-	struct uniwill_data *data = dev_get_drvdata(dev);
-	int ret;
-
-	ret = uniwill_suspend_keyboard(data);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_suspend_battery(data);
-	if (ret < 0)
-		return ret;
-
-	regcache_cache_only(data->regmap, true);
-	regcache_mark_dirty(data->regmap);
-
-	return 0;
-}
-
-static int uniwill_resume_keyboard(struct uniwill_data *data)
-{
-	unsigned int value;
-	int ret;
-
-	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
-		return 0;
-
-	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
-	if (ret < 0)
-		return ret;
-
-	if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
-		return 0;
-
-	return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
-				 TRIGGER_SUPER_KEY_LOCK);
-}
-
-static int uniwill_resume_battery(struct uniwill_data *data)
-{
-	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
-		return 0;
-
-	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
-				  data->last_charge_ctrl);
-}
-
-static int uniwill_resume(struct device *dev)
-{
-	struct uniwill_data *data = dev_get_drvdata(dev);
-	int ret;
-
-	regcache_cache_only(data->regmap, false);
-
-	ret = regcache_sync(data->regmap);
-	if (ret < 0)
-		return ret;
-
-	ret = uniwill_resume_keyboard(data);
-	if (ret < 0)
-		return ret;
-
-	return uniwill_resume_battery(data);
-}
-
-static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
-
-/*
- * We only use the DMI table for auoloading because the ACPI device itself
- * does not guarantee that the underlying EC implementation is supported.
- */
-static const struct acpi_device_id uniwill_id_table[] = {
-	{ "INOU0000" },
-	{ },
-};
-
-static struct platform_driver uniwill_driver = {
-	.driver = {
-		.name = DRIVER_NAME,
-		.dev_groups = uniwill_groups,
-		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
-		.acpi_match_table = uniwill_id_table,
-		.pm = pm_sleep_ptr(&uniwill_pm_ops),
-	},
-	.probe = uniwill_probe,
-	.shutdown = uniwill_shutdown,
-};
-
-static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
+static const struct dmi_system_id uniwill_dmi_table[] = {
 	{
 		.ident = "XMG FUSION 15",
 		.matches = {
@@ -1936,6 +1765,177 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
 
+static int uniwill_probe(struct platform_device *pdev)
+{
+	struct uniwill_data *data;
+	struct regmap *regmap;
+	acpi_handle handle;
+	int ret;
+
+	handle = ACPI_HANDLE(&pdev->dev);
+	if (!handle)
+		return -ENODEV;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->dev = &pdev->dev;
+	data->handle = handle;
+	platform_set_drvdata(pdev, data);
+
+	regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
+	if (IS_ERR(regmap))
+		return PTR_ERR(regmap);
+
+	data->regmap = regmap;
+	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_ec_init(data);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_battery_init(data);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_led_init(data);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_hwmon_init(data);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_nvidia_ctgp_init(data);
+	if (ret < 0)
+		return ret;
+
+	return uniwill_input_init(data);
+}
+
+static void uniwill_shutdown(struct platform_device *pdev)
+{
+	struct uniwill_data *data = platform_get_drvdata(pdev);
+
+	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
+}
+
+static int uniwill_suspend_keyboard(struct uniwill_data *data)
+{
+	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+		return 0;
+
+	/*
+	 * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
+	 * ourselves.
+	 */
+	return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
+}
+
+static int uniwill_suspend_battery(struct uniwill_data *data)
+{
+	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+		return 0;
+
+	/*
+	 * Save the current charge limit in order to restore it during resume.
+	 * We cannot use the regmap code for that since this register needs to
+	 * be declared as volatile due to CHARGE_CTRL_REACHED.
+	 */
+	return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
+}
+
+static int uniwill_suspend(struct device *dev)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	ret = uniwill_suspend_keyboard(data);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_suspend_battery(data);
+	if (ret < 0)
+		return ret;
+
+	regcache_cache_only(data->regmap, true);
+	regcache_mark_dirty(data->regmap);
+
+	return 0;
+}
+
+static int uniwill_resume_keyboard(struct uniwill_data *data)
+{
+	unsigned int value;
+	int ret;
+
+	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+		return 0;
+
+	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
+	if (ret < 0)
+		return ret;
+
+	if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
+		return 0;
+
+	return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
+				 TRIGGER_SUPER_KEY_LOCK);
+}
+
+static int uniwill_resume_battery(struct uniwill_data *data)
+{
+	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+		return 0;
+
+	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
+				  data->last_charge_ctrl);
+}
+
+static int uniwill_resume(struct device *dev)
+{
+	struct uniwill_data *data = dev_get_drvdata(dev);
+	int ret;
+
+	regcache_cache_only(data->regmap, false);
+
+	ret = regcache_sync(data->regmap);
+	if (ret < 0)
+		return ret;
+
+	ret = uniwill_resume_keyboard(data);
+	if (ret < 0)
+		return ret;
+
+	return uniwill_resume_battery(data);
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
+
+/*
+ * We only use the DMI table for auoloading because the ACPI device itself
+ * does not guarantee that the underlying EC implementation is supported.
+ */
+static const struct acpi_device_id uniwill_id_table[] = {
+	{ "INOU0000" },
+	{ },
+};
+
+static struct platform_driver uniwill_driver = {
+	.driver = {
+		.name = DRIVER_NAME,
+		.dev_groups = uniwill_groups,
+		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
+		.acpi_match_table = uniwill_id_table,
+		.pm = pm_sleep_ptr(&uniwill_pm_ops),
+	},
+	.probe = uniwill_probe,
+	.shutdown = uniwill_shutdown,
+};
+
 static int __init uniwill_init(void)
 {
 	const struct dmi_system_id *id;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 5/6] platform/x86/uniwill: Run callbacks of uniwill_dmi_table
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
                   ` (3 preceding siblings ...)
  2025-11-17 13:24 ` [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe Werner Sembach
@ 2025-11-17 13:24 ` Werner Sembach
  2025-11-17 13:24 ` [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1 Werner Sembach
  2025-11-18 11:31 ` [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Armin Wolf
  6 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:24 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

The dmi_system_id uniwill_dmi_table[] has a callback field.

This patch calls these callbacks with EC read/write access. It also moves
the supported_features assignment further back into the code.

This enables the callbacks to dynamically determine supported_features
flags based on EC readouts.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 29 ++++++++++++---------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 9412783698685..15a94c256f728 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -335,6 +335,7 @@ struct uniwill_data {
 	struct mutex input_lock;	/* Protects input sequence during notify */
 	struct input_dev *input_device;
 	struct notifier_block nb;
+	struct dmi_system_id id;
 };
 
 struct uniwill_battery_entry {
@@ -1767,6 +1768,7 @@ MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
 
 static int uniwill_probe(struct platform_device *pdev)
 {
+	const struct dmi_system_id *id;
 	struct uniwill_data *data;
 	struct regmap *regmap;
 	acpi_handle handle;
@@ -1788,6 +1790,19 @@ static int uniwill_probe(struct platform_device *pdev)
 	if (IS_ERR(regmap))
 		return PTR_ERR(regmap);
 
+	if (force) {
+		/* Assume that the device supports all features */
+		supported_features = UINT_MAX;
+		pr_warn("Loading on a potentially unsupported device\n");
+	} else {
+		/* Match is guaranteed, otherwise init would have aborted */
+		id = dmi_first_match(uniwill_dmi_table);
+		memcpy(&data->id, id, sizeof(data->id));
+		if (data->id.callback)
+			data->id.callback(&data->id);
+		supported_features = (uintptr_t)data->id.driver_data;
+	}
+
 	data->regmap = regmap;
 	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
 	if (ret < 0)
@@ -1938,20 +1953,10 @@ static struct platform_driver uniwill_driver = {
 
 static int __init uniwill_init(void)
 {
-	const struct dmi_system_id *id;
 	int ret;
 
-	id = dmi_first_match(uniwill_dmi_table);
-	if (!id) {
-		if (!force)
-			return -ENODEV;
-
-		/* Assume that the device supports all features */
-		supported_features = UINT_MAX;
-		pr_warn("Loading on a potentially unsupported device\n");
-	} else {
-		supported_features = (uintptr_t)id->driver_data;
-	}
+	if (!dmi_first_match(uniwill_dmi_table) && !force)
+		return -ENODEV;
 
 	ret = platform_driver_register(&uniwill_driver);
 	if (ret < 0)
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
                   ` (4 preceding siblings ...)
  2025-11-17 13:24 ` [PATCH 5/6] platform/x86/uniwill: Run callbacks of uniwill_dmi_table Werner Sembach
@ 2025-11-17 13:24 ` Werner Sembach
  2025-11-18 10:43   ` Ilpo Järvinen
  2025-11-18 11:31 ` [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Armin Wolf
  6 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-17 13:24 UTC (permalink / raw)
  To: W_Armin, hansg, ilpo.jarvinen
  Cc: platform-driver-x86, linux-kernel, Werner Sembach

The TUXEDO InfinityBook 14 Gen7 shares a boardname between the variant with
and without an NVIDIA GPU.

Dynamically read which variant is present from EC to determine cTGP
support.

Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 22 ++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 15a94c256f728..f6b24d2c28b89 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -88,6 +88,9 @@
 
 #define EC_ADDR_GPU_TEMP		0x044F
 
+#define EC_ADDR_SYSTEM_ID		0x0456
+#define HAS_GPU				BIT(7)
+
 #define EC_ADDR_MAIN_FAN_RPM_1		0x0464
 
 #define EC_ADDR_MAIN_FAN_RPM_2		0x0465
@@ -1406,6 +1409,23 @@ static int uniwill_ec_init(struct uniwill_data *data)
 	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
 }
 
+static int quirk_ibp_gen7_ctgp_supported(const struct dmi_system_id *d)
+{
+	struct uniwill_data *data = container_of(d, struct uniwill_data, id);
+	unsigned int value;
+	int ret;
+
+	ret = regmap_read(data->regmap, EC_ADDR_SYSTEM_ID, &value);
+	if (ret < 0)
+		return ret;
+	if (value & HAS_GPU) {
+		data->id.driver_data =
+			(void *)((unsigned long)data->id.driver_data |
+				 UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL);
+	}
+	return 0;
+}
+
 static const struct dmi_system_id uniwill_dmi_table[] = {
 	{
 		.ident = "XMG FUSION 15",
@@ -1462,12 +1482,12 @@ static const struct dmi_system_id uniwill_dmi_table[] = {
 		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
+		.callback = quirk_ibp_gen7_ctgp_supported,
 		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
 		.matches = {
 			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
 			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
 		},
-		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
 	},
 	{
 		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1
  2025-11-17 13:24 ` [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1 Werner Sembach
@ 2025-11-18 10:43   ` Ilpo Järvinen
  2025-11-18 13:05     ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Ilpo Järvinen @ 2025-11-18 10:43 UTC (permalink / raw)
  To: Werner Sembach; +Cc: W_Armin, Hans de Goede, platform-driver-x86, LKML

On Mon, 17 Nov 2025, Werner Sembach wrote:

> The TUXEDO InfinityBook 14 Gen7 shares a boardname between the variant with
> and without an NVIDIA GPU.
> 
> Dynamically read which variant is present from EC to determine cTGP
> support.
> 
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>  drivers/platform/x86/uniwill/uniwill-acpi.c | 22 ++++++++++++++++++++-
>  1 file changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 15a94c256f728..f6b24d2c28b89 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -88,6 +88,9 @@
>  
>  #define EC_ADDR_GPU_TEMP		0x044F
>  
> +#define EC_ADDR_SYSTEM_ID		0x0456
> +#define HAS_GPU				BIT(7)
> +
>  #define EC_ADDR_MAIN_FAN_RPM_1		0x0464
>  
>  #define EC_ADDR_MAIN_FAN_RPM_2		0x0465
> @@ -1406,6 +1409,23 @@ static int uniwill_ec_init(struct uniwill_data *data)
>  	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
>  }
>  
> +static int quirk_ibp_gen7_ctgp_supported(const struct dmi_system_id *d)
> +{
> +	struct uniwill_data *data = container_of(d, struct uniwill_data, id);
> +	unsigned int value;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap, EC_ADDR_SYSTEM_ID, &value);
> +	if (ret < 0)
> +		return ret;
> +	if (value & HAS_GPU) {
> +		data->id.driver_data =
> +			(void *)((unsigned long)data->id.driver_data |
> +				 UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL);

Hi,

Mutating .driver_data like this is a no go. Please store information that 
isn't bound to the match properly, not with hacks like this.

There seems to be already struct uniwill_data where you can add things 
properly. If you want to use .driver_data as mutatable feature flags, you 
need to make a copy of it into a properly named variable (e.g. 
data->features). Then you can do
	data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
here.

> +	}
> +	return 0;
> +}
> +
>  static const struct dmi_system_id uniwill_dmi_table[] = {
>  	{
>  		.ident = "XMG FUSION 15",
> @@ -1462,12 +1482,12 @@ static const struct dmi_system_id uniwill_dmi_table[] = {
>  		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>  	},
>  	{
> +		.callback = quirk_ibp_gen7_ctgp_supported,
>  		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>  		.matches = {
>  			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>  			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>  		},
> -		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),

Please always order your series so you don't need to correct things you've 
just added.

-- 
 i.


^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices
  2025-11-17 13:23 ` [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices Werner Sembach
@ 2025-11-18 11:03   ` Armin Wolf
  0 siblings, 0 replies; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 11:03 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 17.11.25 um 14:23 schrieb Werner Sembach:

> Add all TUXEDO devices that can make use of this driver.

I think it would make sense to place this patch behind the patch for the additional
WMI events. Other than that:

Reviewed-by: Armin Wolf <W_Armin@gmx.de>

> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 308 ++++++++++++++++++++
>   1 file changed, 308 insertions(+)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 014960d16211b..29bb3709bfcc8 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -1478,6 +1478,20 @@ static struct platform_driver uniwill_driver = {
>   };
>   
>   static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
> +	{
> +		.ident = "XMG FUSION 15",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71A"),
> +		},
> +	},
> +	{
> +		.ident = "XMG FUSION 15",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "SchenkerTechnologiesGmbH"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "LAPQC71B"),
> +		},
> +	},
>   	{
>   		.ident = "Intel NUC x15",
>   		.matches = {
> @@ -1503,6 +1517,300 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   					UNIWILL_FEATURE_BATTERY |
>   					UNIWILL_FEATURE_HWMON),
>   	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTxX1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14 Gen6 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PRX1_PH6PRX1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxHRXx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 Intel/Commodore Omnia-Book 15 Gen9",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GXxMRXx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxHP4NAx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 14/15 Gen10 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxKK4NAx_XxSP4NAx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO InfinityBook Pro 15 Gen10 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "XxAR4NAx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A1650TI"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501A2060"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 17 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A1650TI"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 17 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701A2060"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15 Gen1 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I1650TI"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15 Gen1 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1501I2060"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 17 Gen1 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I1650TI"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 17 Gen1 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "POLARIS1701I2060"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Trinity 15 Intel Gen1",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1501I"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Trinity 17 Intel Gen1",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "TRINITY1701I"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15/17 Gen2 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Pulse 14 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1401"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Pulse 15 Gen1 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PULSE1501"),
> +		},
> +	},
> +	{
> +		.ident = "TUXEDO Pulse 15 Gen2 AMD",
> +		.matches = {
> +			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
> +			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PF5LUXG"),
> +		},
> +	},
>   	{ }
>   };
>   MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-17 13:23 ` [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for " Werner Sembach
@ 2025-11-18 11:08   ` Armin Wolf
  2025-11-18 12:45     ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 11:08 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 17.11.25 um 14:23 schrieb Werner Sembach:

> Handle some more WMI events that are triggered on TUXEDO devices.
>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>   2 files changed, 20 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 29bb3709bfcc8..0cb86a701b2e1 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>   
>   	/* Reported in manual mode when toggling the airplane mode status */
>   	{ KE_KEY,       UNIWILL_OSD_RFKILL,                     { KEY_RFKILL }},
> +	{ KE_IGNORE,    UNIWILL_OSD_RADIOON,                    { KEY_UNKNOWN }},
> +	{ KE_IGNORE,    UNIWILL_OSD_RADIOOFF,                   { KEY_UNKNOWN }},
>   
>   	/* Reported when user wants to cycle the platform profile */
> -	{ KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_UNKNOWN }},
> +	{ KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_F14 }},

I am currently working a patch adding platform profile support, so this event would
be handled inside the kernel on models with platform profile support.

>   
>   	/* Reported when the user wants to adjust the brightness of the keyboard */
>   	{ KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN,               { KEY_KBDILLUMDOWN }},
> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>   	/* Reported when the user wants to toggle the microphone mute status */
>   	{ KE_KEY,       UNIWILL_OSD_MIC_MUTE,                   { KEY_MICMUTE }},
>   
> +	/* Reported when the user wants to toggle the mute status */
> +	{ KE_IGNORE,    UNIWILL_OSD_MUTE,                       { KEY_MUTE }},

Why is this event being ignored?

> +
>   	/* Reported when the user locks/unlocks the Fn key */
>   	{ KE_IGNORE,    UNIWILL_OSD_FN_LOCK,                    { KEY_FN_ESC }},
>   
>   	/* Reported when the user wants to toggle the brightness of the keyboard */
>   	{ KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE,             { KEY_KBDILLUMTOGGLE }},
> +	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0,              { KEY_KBDILLUMTOGGLE }},
> +	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1,              { KEY_KBDILLUMTOGGLE }},
> +	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2,              { KEY_KBDILLUMTOGGLE }},
> +	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3,              { KEY_KBDILLUMTOGGLE }},
> +	{ KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4,              { KEY_KBDILLUMTOGGLE }},
>   
>   	/* FIXME: find out the exact meaning of those events */
>   	{ KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H,       { KEY_UNKNOWN }},
> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>   	/* Reported when the user wants to toggle the benchmark mode status */
>   	{ KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE,      { KEY_UNKNOWN }},
>   
> +	/* Reported when the user wants to toggle the webcam */
> +	{ KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE,              { KEY_UNKNOWN }},

Same as above.

> +
>   	{ KE_END }
>   };
>   
> @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct notifier_block *nb, unsigned long action
>   		}
>   		mutex_unlock(&data->battery_lock);
>   
> +		return NOTIFY_OK;
> +	case UNIWILL_OSD_DC_ADAPTER_CHANGED:
> +		// noop for the time being

Wrong comment style, please use /* */.

Thanks,
Armin Wolf

> +
>   		return NOTIFY_OK;
>   	default:
>   		mutex_lock(&data->input_lock);
> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h b/drivers/platform/x86/uniwill/uniwill-wmi.h
> index 2bf69f2d80381..48783b2e9ffb9 100644
> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
> @@ -113,6 +113,8 @@
>   
>   #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE	0xC0
>   
> +#define UNIWILL_OSD_WEBCAM_TOGGLE		0xCF
> +
>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED	0xF0
>   
>   struct device;

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-17 13:24 ` [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting Werner Sembach
@ 2025-11-18 11:12   ` Armin Wolf
  2025-11-18 12:58     ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 11:12 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 17.11.25 um 14:24 schrieb Werner Sembach:

> Uniwill offers user setable cTGP for their EC on devices using NVIDIA 3000
> Series and newer GPUs. This patch implements this setting as a sysfs
> attribute.
>
> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 +++++++++++++++++++-
>   1 file changed, 107 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index 0cb86a701b2e1..de3417d9d1ac0 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -122,11 +122,11 @@
>   #define CTGP_DB_DB_ENABLE		BIT(1)
>   #define CTGP_DB_CTGP_ENABLE		BIT(2)
>   
> -#define EC_ADDR_CTGP_OFFSET		0x0744
> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET	0x0744
>   
> -#define EC_ADDR_TPP_OFFSET		0x0745
> +#define EC_ADDR_CTGP_DB_TPP_OFFSET	0x0745
>   
> -#define EC_ADDR_MAX_TGP			0x0746
> +#define EC_ADDR_CTGP_DB_DB_OFFSET	0x0746
>   
>   #define EC_ADDR_LIGHTBAR_AC_CTRL	0x0748
>   #define LIGHTBAR_APP_EXISTS		BIT(0)
> @@ -317,6 +317,7 @@
>   #define UNIWILL_FEATURE_LIGHTBAR		BIT(3)
>   #define UNIWILL_FEATURE_BATTERY			BIT(4)
>   #define UNIWILL_FEATURE_HWMON			BIT(5)
> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL	BIT(6)
>   
>   struct uniwill_data {
>   	struct device *dev;
> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device *dev, unsigned int reg)
>   	case EC_ADDR_LIGHTBAR_BAT_RED:
>   	case EC_ADDR_LIGHTBAR_BAT_GREEN:
>   	case EC_ADDR_LIGHTBAR_BAT_BLUE:
> +	case EC_ADDR_CTGP_DB_CTRL:
> +	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
> +	case EC_ADDR_CTGP_DB_TPP_OFFSET:
> +	case EC_ADDR_CTGP_DB_DB_OFFSET:
>   		return true;
>   	default:
>   		return false;
> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device *dev, unsigned int reg)
>   	case EC_ADDR_LIGHTBAR_BAT_RED:
>   	case EC_ADDR_LIGHTBAR_BAT_GREEN:
>   	case EC_ADDR_LIGHTBAR_BAT_BLUE:
> +	case EC_ADDR_CTGP_DB_CTRL:
> +	case EC_ADDR_CTGP_DB_CTGP_OFFSET:
> +	case EC_ADDR_CTGP_DB_TPP_OFFSET:
> +	case EC_ADDR_CTGP_DB_DB_OFFSET:
>   		return true;
>   	default:
>   		return false;
> @@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct device *dev, struct device_attri
>   
>   static DEVICE_ATTR_RW(breathing_in_suspend);
>   
> +static ssize_t ctgp_offset_store(struct device *dev, struct device_attribute *attr,
> +				 const char *buf, size_t count)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	unsigned int value;
> +	int ret;
> +
> +	ret = kstrtouint(buf, 0, &value);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, value);
> +	if (ret < 0)
> +		return ret;
> +
> +	return count;
> +}
> +
> +static ssize_t ctgp_offset_show(struct device *dev, struct device_attribute *attr,
> +				char *buf)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	unsigned int value;
> +	int ret;
> +
> +	ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, &value);
> +	if (ret < 0)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%u\n", value);
> +}
> +
> +DEVICE_ATTR_RW(ctgp_offset);
> +
> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
> +{
> +	int ret;
> +
> +	if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
> +		return 0;
> +
> +	ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
> +				 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE,
> +				 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | CTGP_DB_CTGP_ENABLE);

I think we should initialize the power limits before enabling them, otherwise
the relevant registers might still contain invalid data.

> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
> +	if (ret < 0)
> +		return ret;

Are those values the maximum values supported by the platform? If yes then
we should enforce them for sysfs writes.

Also, why is only cTGP accessible from user space?

Thanks,
Armin Wolf

> +
> +	return 0;
> +}
> +
>   static struct attribute *uniwill_attrs[] = {
>   	/* Keyboard-related */
>   	&dev_attr_fn_lock_toggle_enable.attr,
> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>   	/* Lightbar-related */
>   	&dev_attr_rainbow_animation.attr,
>   	&dev_attr_breathing_in_suspend.attr,
> +	/* Power-management-related */
> +	&dev_attr_ctgp_offset.attr,
>   	NULL
>   };
>   
> @@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
>   			return attr->mode;
>   	}
>   
> +	if (attr == &dev_attr_ctgp_offset.attr) {
> +		if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
> +			return attr->mode;
> +	}
> +
>   	return 0;
>   }
>   
> @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct platform_device *pdev)
>   	if (ret < 0)
>   		return ret;
>   
> +	ret = uniwill_nvidia_ctgp_init(data);
> +	if (ret < 0)
> +		return ret;
> +
>   	return uniwill_input_init(data);
>   }
>   
> @@ -1547,6 +1629,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore Omnia-Book Pro Gen 7",
> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore Omnia-Book Pro Gen 8",
> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15/17 Gen2 Intel",
> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 15 Gen4 Intel",
> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Polaris 15/17 Gen5 AMD",
> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen5 AMD",
> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 15 Gen6",
> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 AMD",
> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Stellaris 16 Gen7 Intel",
> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>   		},
> +		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>   	},
>   	{
>   		.ident = "TUXEDO Pulse 14 Gen1 AMD",

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  2025-11-17 13:24 ` [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe Werner Sembach
@ 2025-11-18 11:16   ` Armin Wolf
  2025-11-18 13:01     ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 11:16 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 17.11.25 um 14:24 schrieb Werner Sembach:

> Move uniwill_dmi_table up and remove __intconst to make it also accessible
> in the probe function.

NAK, i expect the DMI table to become very large in the future, so not marking it
as __initconst will waste a sizeable amount of memory.

Luckily i am also currently working on extending the DMI table to contain additional
configuration data like power limits and callbacks for device-specific initialization.

I can share the patch with you if you want. It would allow us to discard the DMI table
after module initialization while still allowing for device-specific initialization
callbacks.

Thanks,
Armin Wolf

> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
> ---
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 344 ++++++++++----------
>   1 file changed, 172 insertions(+), 172 deletions(-)
>
> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
> index de3417d9d1ac0..9412783698685 100644
> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
> @@ -1405,178 +1405,7 @@ static int uniwill_ec_init(struct uniwill_data *data)
>   	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
>   }
>   
> -static int uniwill_probe(struct platform_device *pdev)
> -{
> -	struct uniwill_data *data;
> -	struct regmap *regmap;
> -	acpi_handle handle;
> -	int ret;
> -
> -	handle = ACPI_HANDLE(&pdev->dev);
> -	if (!handle)
> -		return -ENODEV;
> -
> -	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> -	if (!data)
> -		return -ENOMEM;
> -
> -	data->dev = &pdev->dev;
> -	data->handle = handle;
> -	platform_set_drvdata(pdev, data);
> -
> -	regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
> -	if (IS_ERR(regmap))
> -		return PTR_ERR(regmap);
> -
> -	data->regmap = regmap;
> -	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_ec_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_battery_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_led_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_hwmon_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_nvidia_ctgp_init(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	return uniwill_input_init(data);
> -}
> -
> -static void uniwill_shutdown(struct platform_device *pdev)
> -{
> -	struct uniwill_data *data = platform_get_drvdata(pdev);
> -
> -	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
> -}
> -
> -static int uniwill_suspend_keyboard(struct uniwill_data *data)
> -{
> -	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
> -		return 0;
> -
> -	/*
> -	 * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
> -	 * ourselves.
> -	 */
> -	return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
> -}
> -
> -static int uniwill_suspend_battery(struct uniwill_data *data)
> -{
> -	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
> -		return 0;
> -
> -	/*
> -	 * Save the current charge limit in order to restore it during resume.
> -	 * We cannot use the regmap code for that since this register needs to
> -	 * be declared as volatile due to CHARGE_CTRL_REACHED.
> -	 */
> -	return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
> -}
> -
> -static int uniwill_suspend(struct device *dev)
> -{
> -	struct uniwill_data *data = dev_get_drvdata(dev);
> -	int ret;
> -
> -	ret = uniwill_suspend_keyboard(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_suspend_battery(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	regcache_cache_only(data->regmap, true);
> -	regcache_mark_dirty(data->regmap);
> -
> -	return 0;
> -}
> -
> -static int uniwill_resume_keyboard(struct uniwill_data *data)
> -{
> -	unsigned int value;
> -	int ret;
> -
> -	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
> -		return 0;
> -
> -	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
> -	if (ret < 0)
> -		return ret;
> -
> -	if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
> -		return 0;
> -
> -	return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
> -				 TRIGGER_SUPER_KEY_LOCK);
> -}
> -
> -static int uniwill_resume_battery(struct uniwill_data *data)
> -{
> -	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
> -		return 0;
> -
> -	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
> -				  data->last_charge_ctrl);
> -}
> -
> -static int uniwill_resume(struct device *dev)
> -{
> -	struct uniwill_data *data = dev_get_drvdata(dev);
> -	int ret;
> -
> -	regcache_cache_only(data->regmap, false);
> -
> -	ret = regcache_sync(data->regmap);
> -	if (ret < 0)
> -		return ret;
> -
> -	ret = uniwill_resume_keyboard(data);
> -	if (ret < 0)
> -		return ret;
> -
> -	return uniwill_resume_battery(data);
> -}
> -
> -static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
> -
> -/*
> - * We only use the DMI table for auoloading because the ACPI device itself
> - * does not guarantee that the underlying EC implementation is supported.
> - */
> -static const struct acpi_device_id uniwill_id_table[] = {
> -	{ "INOU0000" },
> -	{ },
> -};
> -
> -static struct platform_driver uniwill_driver = {
> -	.driver = {
> -		.name = DRIVER_NAME,
> -		.dev_groups = uniwill_groups,
> -		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> -		.acpi_match_table = uniwill_id_table,
> -		.pm = pm_sleep_ptr(&uniwill_pm_ops),
> -	},
> -	.probe = uniwill_probe,
> -	.shutdown = uniwill_shutdown,
> -};
> -
> -static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
> +static const struct dmi_system_id uniwill_dmi_table[] = {
>   	{
>   		.ident = "XMG FUSION 15",
>   		.matches = {
> @@ -1936,6 +1765,177 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>   };
>   MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
>   
> +static int uniwill_probe(struct platform_device *pdev)
> +{
> +	struct uniwill_data *data;
> +	struct regmap *regmap;
> +	acpi_handle handle;
> +	int ret;
> +
> +	handle = ACPI_HANDLE(&pdev->dev);
> +	if (!handle)
> +		return -ENODEV;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->dev = &pdev->dev;
> +	data->handle = handle;
> +	platform_set_drvdata(pdev, data);
> +
> +	regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, &uniwill_ec_config);
> +	if (IS_ERR(regmap))
> +		return PTR_ERR(regmap);
> +
> +	data->regmap = regmap;
> +	ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_ec_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_battery_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_led_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_hwmon_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_nvidia_ctgp_init(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	return uniwill_input_init(data);
> +}
> +
> +static void uniwill_shutdown(struct platform_device *pdev)
> +{
> +	struct uniwill_data *data = platform_get_drvdata(pdev);
> +
> +	regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
> +}
> +
> +static int uniwill_suspend_keyboard(struct uniwill_data *data)
> +{
> +	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
> +		return 0;
> +
> +	/*
> +	 * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to restore it
> +	 * ourselves.
> +	 */
> +	return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &data->last_switch_status);
> +}
> +
> +static int uniwill_suspend_battery(struct uniwill_data *data)
> +{
> +	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
> +		return 0;
> +
> +	/*
> +	 * Save the current charge limit in order to restore it during resume.
> +	 * We cannot use the regmap code for that since this register needs to
> +	 * be declared as volatile due to CHARGE_CTRL_REACHED.
> +	 */
> +	return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, &data->last_charge_ctrl);
> +}
> +
> +static int uniwill_suspend(struct device *dev)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	int ret;
> +
> +	ret = uniwill_suspend_keyboard(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_suspend_battery(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	regcache_cache_only(data->regmap, true);
> +	regcache_mark_dirty(data->regmap);
> +
> +	return 0;
> +}
> +
> +static int uniwill_resume_keyboard(struct uniwill_data *data)
> +{
> +	unsigned int value;
> +	int ret;
> +
> +	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
> +		return 0;
> +
> +	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
> +	if (ret < 0)
> +		return ret;
> +
> +	if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & SUPER_KEY_LOCK_STATUS))
> +		return 0;
> +
> +	return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, TRIGGER_SUPER_KEY_LOCK,
> +				 TRIGGER_SUPER_KEY_LOCK);
> +}
> +
> +static int uniwill_resume_battery(struct uniwill_data *data)
> +{
> +	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
> +		return 0;
> +
> +	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
> +				  data->last_charge_ctrl);
> +}
> +
> +static int uniwill_resume(struct device *dev)
> +{
> +	struct uniwill_data *data = dev_get_drvdata(dev);
> +	int ret;
> +
> +	regcache_cache_only(data->regmap, false);
> +
> +	ret = regcache_sync(data->regmap);
> +	if (ret < 0)
> +		return ret;
> +
> +	ret = uniwill_resume_keyboard(data);
> +	if (ret < 0)
> +		return ret;
> +
> +	return uniwill_resume_battery(data);
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, uniwill_resume);
> +
> +/*
> + * We only use the DMI table for auoloading because the ACPI device itself
> + * does not guarantee that the underlying EC implementation is supported.
> + */
> +static const struct acpi_device_id uniwill_id_table[] = {
> +	{ "INOU0000" },
> +	{ },
> +};
> +
> +static struct platform_driver uniwill_driver = {
> +	.driver = {
> +		.name = DRIVER_NAME,
> +		.dev_groups = uniwill_groups,
> +		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
> +		.acpi_match_table = uniwill_id_table,
> +		.pm = pm_sleep_ptr(&uniwill_pm_ops),
> +	},
> +	.probe = uniwill_probe,
> +	.shutdown = uniwill_shutdown,
> +};
> +
>   static int __init uniwill_init(void)
>   {
>   	const struct dmi_system_id *id;

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
                   ` (5 preceding siblings ...)
  2025-11-17 13:24 ` [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1 Werner Sembach
@ 2025-11-18 11:31 ` Armin Wolf
  2025-11-18 13:17   ` Werner Sembach
  2025-11-18 13:42   ` Werner Sembach
  6 siblings, 2 replies; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 11:31 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 17.11.25 um 14:23 schrieb Werner Sembach:

> With the Uniwill driver from Armin now accepted I want to push the first
> big addon to it that I worked on in parallel.
>
> First this adds all current Tuxedo devices to use at least the input part
> of the new driver.
>
> Second it adds a new feature for cTGP control on Uniwill devices with
> NVIDIA GPUs and enables that on the TUXEDO devices.
>
> I have not yet enabled the other features in this driver for TUXEDO devices
> as they either don't apply (Uniwill did a line with Intel that behaves a
> little different to the rest of their ECs and that line is what the features
> Armin added are based on) or are, as of now, untested.
>
> There are plenty more features currently implemented in the out of tree
> tuxedo-drivers dkms package that I plan to port over one by one, but as
> always: No ETA given.

Very nice, i think that especially the cTGP control feature will be very popular with users.
I am also currently working to add fan table (aka "universal fan control"), PL1/PL2 power limit
and platform profile support to the driver, so you might be able to reuse some of that
functionality for your devices.

I think that we can merge the first two patches in the near future, but the remaining ones
dealing with the DMI table and cTGP support need some more work. What kind of control does
your software (Tuxedo control center) need over the cTGP values? I am asking because Intel
devices have fixed cTGP values for each platform profile. If your software does something
similar, then maybe we can integrate this into the platform profile mechanism.

Thanks,
Armin Wolf

>
> Werner Sembach (6):
>    platform/x86/uniwill: Add TUXEDO devices
>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>      devices
>    platform/x86/uniwill: Implement cTGP setting
>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7
>      MK1
>
>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 ++++++++++++++++++--
>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>   2 files changed, 502 insertions(+), 46 deletions(-)
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 11:08   ` Armin Wolf
@ 2025-11-18 12:45     ` Werner Sembach
  2025-11-18 13:12       ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 12:45 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 12:08 schrieb Armin Wolf:
> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>
>> Handle some more WMI events that are triggered on TUXEDO devices.
>>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>         /* Reported in manual mode when toggling the airplane mode status */
>>       { KE_KEY,       UNIWILL_OSD_RFKILL,                     { KEY_RFKILL }},
>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON,                    { KEY_UNKNOWN }},
>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF,                   { KEY_UNKNOWN }},
>>         /* Reported when user wants to cycle the platform profile */
>> -    { KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_UNKNOWN }},
>> +    { KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { KEY_F14 }},
>
> I am currently working a patch adding platform profile support, so this event 
> would
> be handled inside the kernel on models with platform profile support.

For tuxedo devices we have profiles managed in userspace that do additional 
things. So we need a way to handle this in userspace.

The 2 things I can spontaneously think of would be a sysfs toggle or 2 different 
UNIWILL_FEATURE_* defines.

>
>>         /* Reported when the user wants to adjust the brightness of the 
>> keyboard */
>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN,               { 
>> KEY_KBDILLUMDOWN }},
>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>>       /* Reported when the user wants to toggle the microphone mute status */
>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE,                   { KEY_MICMUTE }},
>>   +    /* Reported when the user wants to toggle the mute status */
>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE,                       { KEY_MUTE }},
>
> Why is this event being ignored?
Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key event, so 
not ignoring it here would result in a double trigger.
>
>> +
>>       /* Reported when the user locks/unlocks the Fn key */
>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK,                    { KEY_FN_ESC }},
>>         /* Reported when the user wants to toggle the brightness of the 
>> keyboard */
>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE,             { 
>> KEY_KBDILLUMTOGGLE }},
>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0,              { 
>> KEY_KBDILLUMTOGGLE }},
>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1,              { 
>> KEY_KBDILLUMTOGGLE }},
>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2,              { 
>> KEY_KBDILLUMTOGGLE }},
>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3,              { 
>> KEY_KBDILLUMTOGGLE }},
>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4,              { 
>> KEY_KBDILLUMTOGGLE }},
>>         /* FIXME: find out the exact meaning of those events */
>>       { KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H,       { KEY_UNKNOWN }},
>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>       /* Reported when the user wants to toggle the benchmark mode status */
>>       { KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE,      { KEY_UNKNOWN }},
>>   +    /* Reported when the user wants to toggle the webcam */
>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE,              { KEY_UNKNOWN }},
>
> Same as above.

Same as above ;)

At least iirc, would have to double check

>
>> +
>>       { KE_END }
>>   };
>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>> notifier_block *nb, unsigned long action
>>           }
>>           mutex_unlock(&data->battery_lock);
>>   +        return NOTIFY_OK;
>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>> +        // noop for the time being
>
> Wrong comment style, please use /* */.
ack
>
> Thanks,
> Armin Wolf
>
>> +
>>           return NOTIFY_OK;
>>       default:
>>           mutex_lock(&data->input_lock);
>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>> index 2bf69f2d80381..48783b2e9ffb9 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>> @@ -113,6 +113,8 @@
>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>> +
>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>     struct device;

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-18 11:12   ` Armin Wolf
@ 2025-11-18 12:58     ` Werner Sembach
  2025-11-18 13:29       ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 12:58 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 12:12 schrieb Armin Wolf:
> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>
>> Uniwill offers user setable cTGP for their EC on devices using NVIDIA 3000
>> Series and newer GPUs. This patch implements this setting as a sysfs
>> attribute.
>>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 +++++++++++++++++++-
>>   1 file changed, 107 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index 0cb86a701b2e1..de3417d9d1ac0 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -122,11 +122,11 @@
>>   #define CTGP_DB_DB_ENABLE        BIT(1)
>>   #define CTGP_DB_CTGP_ENABLE        BIT(2)
>>   -#define EC_ADDR_CTGP_OFFSET        0x0744
>> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET    0x0744
>>   -#define EC_ADDR_TPP_OFFSET        0x0745
>> +#define EC_ADDR_CTGP_DB_TPP_OFFSET    0x0745
>>   -#define EC_ADDR_MAX_TGP            0x0746
>> +#define EC_ADDR_CTGP_DB_DB_OFFSET    0x0746
>>     #define EC_ADDR_LIGHTBAR_AC_CTRL    0x0748
>>   #define LIGHTBAR_APP_EXISTS        BIT(0)
>> @@ -317,6 +317,7 @@
>>   #define UNIWILL_FEATURE_LIGHTBAR        BIT(3)
>>   #define UNIWILL_FEATURE_BATTERY            BIT(4)
>>   #define UNIWILL_FEATURE_HWMON            BIT(5)
>> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(6)
>>     struct uniwill_data {
>>       struct device *dev;
>> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device *dev, 
>> unsigned int reg)
>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>> +    case EC_ADDR_CTGP_DB_CTRL:
>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>           return true;
>>       default:
>>           return false;
>> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device *dev, 
>> unsigned int reg)
>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>> +    case EC_ADDR_CTGP_DB_CTRL:
>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>           return true;
>>       default:
>>           return false;
>> @@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct device 
>> *dev, struct device_attri
>>     static DEVICE_ATTR_RW(breathing_in_suspend);
>>   +static ssize_t ctgp_offset_store(struct device *dev, struct 
>> device_attribute *attr,
>> +                 const char *buf, size_t count)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    unsigned int value;
>> +    int ret;
>> +
>> +    ret = kstrtouint(buf, 0, &value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return count;
>> +}
>> +
>> +static ssize_t ctgp_offset_show(struct device *dev, struct device_attribute 
>> *attr,
>> +                char *buf)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    unsigned int value;
>> +    int ret;
>> +
>> +    ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, &value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return sysfs_emit(buf, "%u\n", value);
>> +}
>> +
>> +DEVICE_ATTR_RW(ctgp_offset);
>> +
>> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>> +{
>> +    int ret;
>> +
>> +    if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
>> +        return 0;
>> +
>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>> CTGP_DB_CTGP_ENABLE,
>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>> CTGP_DB_CTGP_ENABLE);
>
> I think we should initialize the power limits before enabling them, otherwise
> the relevant registers might still contain invalid data.
from boot they are all just 0, but ofc i can shuffle things around
>
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
>> +    if (ret < 0)
>> +        return ret;
>
> Are those values the maximum values supported by the platform? If yes then
> we should enforce them for sysfs writes.
>
> Also, why is only cTGP accessible from user space?

Because that is the only one that should be settable by the user according to 
NVIDIA, the rest should be set by the ODM.

EC_ADDR_CTGP_DB_TPP_OFFSET max value is just max u8 and would be another way to 
cap cpu + gpu power but there are already other ways to do that (e.g. the power 
profiles) so i don't see a value in capping them here in any way.

EC_ADDR_CTGP_DB_DB_OFFSET max value 25 is just the maximum value for dynamic 
boost defined by NVIDIA, bigger values are just being ignored (behave the same 
as having set 25): again the same story: devices that don't support 25 W dynamic 
boost are already capped elsewhere so i don't see value in capping it here.

EC_ADDR_CTGP_DB_CTGP_OFFSET is the only one intented to be set by the user, 
problem: the max value is different from device to device, and i only know how 
to probe it using nvidia smi from userspace. Good news: nothing bad happens when 
you set a higher value (same as for dynamic boost)

>
> Thanks,
> Armin Wolf
>
>> +
>> +    return 0;
>> +}
>> +
>>   static struct attribute *uniwill_attrs[] = {
>>       /* Keyboard-related */
>>       &dev_attr_fn_lock_toggle_enable.attr,
>> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>>       /* Lightbar-related */
>>       &dev_attr_rainbow_animation.attr,
>>       &dev_attr_breathing_in_suspend.attr,
>> +    /* Power-management-related */
>> +    &dev_attr_ctgp_offset.attr,
>>       NULL
>>   };
>>   @@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct kobject 
>> *kobj, struct attribute *a
>>               return attr->mode;
>>       }
>>   +    if (attr == &dev_attr_ctgp_offset.attr) {
>> +        if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
>> +            return attr->mode;
>> +    }
>> +
>>       return 0;
>>   }
>>   @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct platform_device *pdev)
>>       if (ret < 0)
>>           return ret;
>>   +    ret = uniwill_nvidia_ctgp_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>>       return uniwill_input_init(data);
>>   }
>>   @@ -1547,6 +1629,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore 
>> Omnia-Book Pro Gen 7",
>> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore 
>> Omnia-Book Pro Gen 8",
>> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
>> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION Slim 
>> 15 Gen6",
>> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
>> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>           },
>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>       },
>>       {
>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  2025-11-18 11:16   ` Armin Wolf
@ 2025-11-18 13:01     ` Werner Sembach
  2025-11-18 13:35       ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:01 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 12:16 schrieb Armin Wolf:
> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>
>> Move uniwill_dmi_table up and remove __intconst to make it also accessible
>> in the probe function.
>
> NAK, i expect the DMI table to become very large in the future, so not marking it
> as __initconst will waste a sizeable amount of memory.
>
> Luckily i am also currently working on extending the DMI table to contain 
> additional
> configuration data like power limits and callbacks for device-specific 
> initialization.
>
> I can share the patch with you if you want. It would allow us to discard the 
> DMI table
> after module initialization while still allowing for device-specific 
> initialization
> callbacks.
this callback needs a way to probe for presence of a Nvidia card e.g. by reading 
the ec
>
> Thanks,
> Armin Wolf
>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 344 ++++++++++----------
>>   1 file changed, 172 insertions(+), 172 deletions(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index de3417d9d1ac0..9412783698685 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -1405,178 +1405,7 @@ static int uniwill_ec_init(struct uniwill_data *data)
>>       return devm_add_action_or_reset(data->dev, 
>> uniwill_disable_manual_control, data);
>>   }
>>   -static int uniwill_probe(struct platform_device *pdev)
>> -{
>> -    struct uniwill_data *data;
>> -    struct regmap *regmap;
>> -    acpi_handle handle;
>> -    int ret;
>> -
>> -    handle = ACPI_HANDLE(&pdev->dev);
>> -    if (!handle)
>> -        return -ENODEV;
>> -
>> -    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> -    if (!data)
>> -        return -ENOMEM;
>> -
>> -    data->dev = &pdev->dev;
>> -    data->handle = handle;
>> -    platform_set_drvdata(pdev, data);
>> -
>> -    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>> &uniwill_ec_config);
>> -    if (IS_ERR(regmap))
>> -        return PTR_ERR(regmap);
>> -
>> -    data->regmap = regmap;
>> -    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_ec_init(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_battery_init(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_led_init(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_hwmon_init(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_nvidia_ctgp_init(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    return uniwill_input_init(data);
>> -}
>> -
>> -static void uniwill_shutdown(struct platform_device *pdev)
>> -{
>> -    struct uniwill_data *data = platform_get_drvdata(pdev);
>> -
>> -    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
>> -}
>> -
>> -static int uniwill_suspend_keyboard(struct uniwill_data *data)
>> -{
>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>> -        return 0;
>> -
>> -    /*
>> -     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to 
>> restore it
>> -     * ourselves.
>> -     */
>> -    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>> &data->last_switch_status);
>> -}
>> -
>> -static int uniwill_suspend_battery(struct uniwill_data *data)
>> -{
>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>> -        return 0;
>> -
>> -    /*
>> -     * Save the current charge limit in order to restore it during resume.
>> -     * We cannot use the regmap code for that since this register needs to
>> -     * be declared as volatile due to CHARGE_CTRL_REACHED.
>> -     */
>> -    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>> &data->last_charge_ctrl);
>> -}
>> -
>> -static int uniwill_suspend(struct device *dev)
>> -{
>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>> -    int ret;
>> -
>> -    ret = uniwill_suspend_keyboard(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_suspend_battery(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    regcache_cache_only(data->regmap, true);
>> -    regcache_mark_dirty(data->regmap);
>> -
>> -    return 0;
>> -}
>> -
>> -static int uniwill_resume_keyboard(struct uniwill_data *data)
>> -{
>> -    unsigned int value;
>> -    int ret;
>> -
>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>> -        return 0;
>> -
>> -    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & 
>> SUPER_KEY_LOCK_STATUS))
>> -        return 0;
>> -
>> -    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>> TRIGGER_SUPER_KEY_LOCK,
>> -                 TRIGGER_SUPER_KEY_LOCK);
>> -}
>> -
>> -static int uniwill_resume_battery(struct uniwill_data *data)
>> -{
>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>> -        return 0;
>> -
>> -    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>> CHARGE_CTRL_MASK,
>> -                  data->last_charge_ctrl);
>> -}
>> -
>> -static int uniwill_resume(struct device *dev)
>> -{
>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>> -    int ret;
>> -
>> -    regcache_cache_only(data->regmap, false);
>> -
>> -    ret = regcache_sync(data->regmap);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    ret = uniwill_resume_keyboard(data);
>> -    if (ret < 0)
>> -        return ret;
>> -
>> -    return uniwill_resume_battery(data);
>> -}
>> -
>> -static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>> uniwill_resume);
>> -
>> -/*
>> - * We only use the DMI table for auoloading because the ACPI device itself
>> - * does not guarantee that the underlying EC implementation is supported.
>> - */
>> -static const struct acpi_device_id uniwill_id_table[] = {
>> -    { "INOU0000" },
>> -    { },
>> -};
>> -
>> -static struct platform_driver uniwill_driver = {
>> -    .driver = {
>> -        .name = DRIVER_NAME,
>> -        .dev_groups = uniwill_groups,
>> -        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>> -        .acpi_match_table = uniwill_id_table,
>> -        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>> -    },
>> -    .probe = uniwill_probe,
>> -    .shutdown = uniwill_shutdown,
>> -};
>> -
>> -static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>> +static const struct dmi_system_id uniwill_dmi_table[] = {
>>       {
>>           .ident = "XMG FUSION 15",
>>           .matches = {
>> @@ -1936,6 +1765,177 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>> __initconst = {
>>   };
>>   MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
>>   +static int uniwill_probe(struct platform_device *pdev)
>> +{
>> +    struct uniwill_data *data;
>> +    struct regmap *regmap;
>> +    acpi_handle handle;
>> +    int ret;
>> +
>> +    handle = ACPI_HANDLE(&pdev->dev);
>> +    if (!handle)
>> +        return -ENODEV;
>> +
>> +    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>> +    if (!data)
>> +        return -ENOMEM;
>> +
>> +    data->dev = &pdev->dev;
>> +    data->handle = handle;
>> +    platform_set_drvdata(pdev, data);
>> +
>> +    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>> &uniwill_ec_config);
>> +    if (IS_ERR(regmap))
>> +        return PTR_ERR(regmap);
>> +
>> +    data->regmap = regmap;
>> +    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_ec_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_battery_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_led_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_hwmon_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_nvidia_ctgp_init(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return uniwill_input_init(data);
>> +}
>> +
>> +static void uniwill_shutdown(struct platform_device *pdev)
>> +{
>> +    struct uniwill_data *data = platform_get_drvdata(pdev);
>> +
>> +    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
>> +}
>> +
>> +static int uniwill_suspend_keyboard(struct uniwill_data *data)
>> +{
>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>> +        return 0;
>> +
>> +    /*
>> +     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to 
>> restore it
>> +     * ourselves.
>> +     */
>> +    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>> &data->last_switch_status);
>> +}
>> +
>> +static int uniwill_suspend_battery(struct uniwill_data *data)
>> +{
>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>> +        return 0;
>> +
>> +    /*
>> +     * Save the current charge limit in order to restore it during resume.
>> +     * We cannot use the regmap code for that since this register needs to
>> +     * be declared as volatile due to CHARGE_CTRL_REACHED.
>> +     */
>> +    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>> &data->last_charge_ctrl);
>> +}
>> +
>> +static int uniwill_suspend(struct device *dev)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    int ret;
>> +
>> +    ret = uniwill_suspend_keyboard(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_suspend_battery(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    regcache_cache_only(data->regmap, true);
>> +    regcache_mark_dirty(data->regmap);
>> +
>> +    return 0;
>> +}
>> +
>> +static int uniwill_resume_keyboard(struct uniwill_data *data)
>> +{
>> +    unsigned int value;
>> +    int ret;
>> +
>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>> +        return 0;
>> +
>> +    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & 
>> SUPER_KEY_LOCK_STATUS))
>> +        return 0;
>> +
>> +    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>> TRIGGER_SUPER_KEY_LOCK,
>> +                 TRIGGER_SUPER_KEY_LOCK);
>> +}
>> +
>> +static int uniwill_resume_battery(struct uniwill_data *data)
>> +{
>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>> +        return 0;
>> +
>> +    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>> CHARGE_CTRL_MASK,
>> +                  data->last_charge_ctrl);
>> +}
>> +
>> +static int uniwill_resume(struct device *dev)
>> +{
>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>> +    int ret;
>> +
>> +    regcache_cache_only(data->regmap, false);
>> +
>> +    ret = regcache_sync(data->regmap);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    ret = uniwill_resume_keyboard(data);
>> +    if (ret < 0)
>> +        return ret;
>> +
>> +    return uniwill_resume_battery(data);
>> +}
>> +
>> +static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>> uniwill_resume);
>> +
>> +/*
>> + * We only use the DMI table for auoloading because the ACPI device itself
>> + * does not guarantee that the underlying EC implementation is supported.
>> + */
>> +static const struct acpi_device_id uniwill_id_table[] = {
>> +    { "INOU0000" },
>> +    { },
>> +};
>> +
>> +static struct platform_driver uniwill_driver = {
>> +    .driver = {
>> +        .name = DRIVER_NAME,
>> +        .dev_groups = uniwill_groups,
>> +        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>> +        .acpi_match_table = uniwill_id_table,
>> +        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>> +    },
>> +    .probe = uniwill_probe,
>> +    .shutdown = uniwill_shutdown,
>> +};
>> +
>>   static int __init uniwill_init(void)
>>   {
>>       const struct dmi_system_id *id;

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1
  2025-11-18 10:43   ` Ilpo Järvinen
@ 2025-11-18 13:05     ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:05 UTC (permalink / raw)
  To: Ilpo Järvinen; +Cc: W_Armin, Hans de Goede, platform-driver-x86, LKML


Am 18.11.25 um 11:43 schrieb Ilpo Järvinen:
> On Mon, 17 Nov 2025, Werner Sembach wrote:
>
>> The TUXEDO InfinityBook 14 Gen7 shares a boardname between the variant with
>> and without an NVIDIA GPU.
>>
>> Dynamically read which variant is present from EC to determine cTGP
>> support.
>>
>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>> ---
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 22 ++++++++++++++++++++-
>>   1 file changed, 21 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> index 15a94c256f728..f6b24d2c28b89 100644
>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>> @@ -88,6 +88,9 @@
>>   
>>   #define EC_ADDR_GPU_TEMP		0x044F
>>   
>> +#define EC_ADDR_SYSTEM_ID		0x0456
>> +#define HAS_GPU				BIT(7)
>> +
>>   #define EC_ADDR_MAIN_FAN_RPM_1		0x0464
>>   
>>   #define EC_ADDR_MAIN_FAN_RPM_2		0x0465
>> @@ -1406,6 +1409,23 @@ static int uniwill_ec_init(struct uniwill_data *data)
>>   	return devm_add_action_or_reset(data->dev, uniwill_disable_manual_control, data);
>>   }
>>   
>> +static int quirk_ibp_gen7_ctgp_supported(const struct dmi_system_id *d)
>> +{
>> +	struct uniwill_data *data = container_of(d, struct uniwill_data, id);
>> +	unsigned int value;
>> +	int ret;
>> +
>> +	ret = regmap_read(data->regmap, EC_ADDR_SYSTEM_ID, &value);
>> +	if (ret < 0)
>> +		return ret;
>> +	if (value & HAS_GPU) {
>> +		data->id.driver_data =
>> +			(void *)((unsigned long)data->id.driver_data |
>> +				 UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL);
> Hi,
>
> Mutating .driver_data like this is a no go. Please store information that
> isn't bound to the match properly, not with hacks like this.
>
> There seems to be already struct uniwill_data where you can add things
> properly. If you want to use .driver_data as mutatable feature flags, you
> need to make a copy of it into a properly named variable (e.g.
> data->features). Then you can do
> 	data->features |= UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL;
> here.
ok
>
>> +	}
>> +	return 0;
>> +}
>> +
>>   static const struct dmi_system_id uniwill_dmi_table[] = {
>>   	{
>>   		.ident = "XMG FUSION 15",
>> @@ -1462,12 +1482,12 @@ static const struct dmi_system_id uniwill_dmi_table[] = {
>>   		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>   	},
>>   	{
>> +		.callback = quirk_ibp_gen7_ctgp_supported,
>>   		.ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>>   		.matches = {
>>   			DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>   			DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>   		},
>> -		.driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
> Please always order your series so you don't need to correct things you've
> just added.
ack

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 12:45     ` Werner Sembach
@ 2025-11-18 13:12       ` Armin Wolf
  2025-11-18 13:29         ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:12 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 13:45 schrieb Werner Sembach:

>
> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>
>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>
>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>> ---
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>>         /* Reported in manual mode when toggling the airplane mode 
>>> status */
>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON,                    { 
>>> KEY_UNKNOWN }},
>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF,                   { 
>>> KEY_UNKNOWN }},
>>>         /* Reported when user wants to cycle the platform profile */
>>> -    { KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { 
>>> KEY_UNKNOWN }},
>>> +    { KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE,    { 
>>> KEY_F14 }},
>>
>> I am currently working a patch adding platform profile support, so 
>> this event would
>> be handled inside the kernel on models with platform profile support.
>
> For tuxedo devices we have profiles managed in userspace that do 
> additional things. So we need a way to handle this in userspace.
>
Do these things have something to do with the uniwill EC? If so then we should implement those inside the driver
itself. The control center can then poll the platform profile sysfs file to get notified when platform_profile_cycle()
is executed to perform additional actions.

> The 2 things I can spontaneously think of would be a sysfs toggle or 2 
> different UNIWILL_FEATURE_* defines.
>
TPH i would love to have an ordinary keycode allocated for that if the above does not work for you. There already
exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE should be possible.

>>
>>>         /* Reported when the user wants to adjust the brightness of 
>>> the keyboard */
>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] 
>>> = {
>>>       /* Reported when the user wants to toggle the microphone mute 
>>> status */
>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>   +    /* Reported when the user wants to toggle the mute status */
>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE,                       { 
>>> KEY_MUTE }},
>>
>> Why is this event being ignored?
> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key 
> event, so not ignoring it here would result in a double trigger.

I understand.

>>
>>> +
>>>       /* Reported when the user locks/unlocks the Fn key */
>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>         /* Reported when the user wants to toggle the brightness of 
>>> the keyboard */
>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>> KEY_KBDILLUMTOGGLE }},
>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0,              { 
>>> KEY_KBDILLUMTOGGLE }},
>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1,              { 
>>> KEY_KBDILLUMTOGGLE }},
>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2,              { 
>>> KEY_KBDILLUMTOGGLE }},
>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3,              { 
>>> KEY_KBDILLUMTOGGLE }},
>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4,              { 
>>> KEY_KBDILLUMTOGGLE }},
>>>         /* FIXME: find out the exact meaning of those events */
>>>       { KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>> KEY_UNKNOWN }},
>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>       /* Reported when the user wants to toggle the benchmark mode 
>>> status */
>>>       { KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>> KEY_UNKNOWN }},
>>>   +    /* Reported when the user wants to toggle the webcam */
>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE,              { 
>>> KEY_UNKNOWN }},
>>
>> Same as above.
>
> Same as above ;)
>
> At least iirc, would have to double check
>
Ok.

Thanks,
Armin Wolf

>>
>>> +
>>>       { KE_END }
>>>   };
>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>> notifier_block *nb, unsigned long action
>>>           }
>>>           mutex_unlock(&data->battery_lock);
>>>   +        return NOTIFY_OK;
>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>> +        // noop for the time being
>>
>> Wrong comment style, please use /* */.
> ack
>>
>> Thanks,
>> Armin Wolf
>>
>>> +
>>>           return NOTIFY_OK;
>>>       default:
>>>           mutex_lock(&data->input_lock);
>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>> @@ -113,6 +113,8 @@
>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>> +
>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>     struct device;
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-18 11:31 ` [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Armin Wolf
@ 2025-11-18 13:17   ` Werner Sembach
  2025-11-18 13:42     ` Armin Wolf
  2025-11-18 13:42   ` Werner Sembach
  1 sibling, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:17 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 12:31 schrieb Armin Wolf:
> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>
>> With the Uniwill driver from Armin now accepted I want to push the first
>> big addon to it that I worked on in parallel.
>>
>> First this adds all current Tuxedo devices to use at least the input part
>> of the new driver.
>>
>> Second it adds a new feature for cTGP control on Uniwill devices with
>> NVIDIA GPUs and enables that on the TUXEDO devices.
>>
>> I have not yet enabled the other features in this driver for TUXEDO devices
>> as they either don't apply (Uniwill did a line with Intel that behaves a
>> little different to the rest of their ECs and that line is what the features
>> Armin added are based on) or are, as of now, untested.
>>
>> There are plenty more features currently implemented in the out of tree
>> tuxedo-drivers dkms package that I plan to port over one by one, but as
>> always: No ETA given.
>
> Very nice, i think that especially the cTGP control feature will be very 
> popular with users.
> I am also currently working to add fan table (aka "universal fan control"), 
> PL1/PL2 power limit
> and platform profile support to the driver, so you might be able to reuse some 
> of that
> functionality for your devices.
>
> I think that we can merge the first two patches in the near future, but the 
> remaining ones
> dealing with the DMI table and cTGP support need some more work. What kind of 
> control does
> your software (Tuxedo control center) need over the cTGP values? I am asking 
> because Intel
> devices have fixed cTGP values for each platform profile. If your software 
> does something
> similar, then maybe we can integrate this into the platform profile mechanism.

On some newer Uniwill devices all the platform profile register does is changing 
a led, the actual TDP, cTGP, Fan Curves, etc. are set in other registers. We 
currently expose this flexibility to userspace and need to keep it that way.

>
> Thanks,
> Armin Wolf
>
>>
>> Werner Sembach (6):
>>    platform/x86/uniwill: Add TUXEDO devices
>>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>>      devices
>>    platform/x86/uniwill: Implement cTGP setting
>>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7
>>      MK1
>>
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 ++++++++++++++++++--
>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>>   2 files changed, 502 insertions(+), 46 deletions(-)
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-18 12:58     ` Werner Sembach
@ 2025-11-18 13:29       ` Armin Wolf
  2025-11-19 15:34         ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:29 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 13:58 schrieb Werner Sembach:

>
> Am 18.11.25 um 12:12 schrieb Armin Wolf:
>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>
>>> Uniwill offers user setable cTGP for their EC on devices using 
>>> NVIDIA 3000
>>> Series and newer GPUs. This patch implements this setting as a sysfs
>>> attribute.
>>>
>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>> ---
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 
>>> +++++++++++++++++++-
>>>   1 file changed, 107 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> index 0cb86a701b2e1..de3417d9d1ac0 100644
>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> @@ -122,11 +122,11 @@
>>>   #define CTGP_DB_DB_ENABLE        BIT(1)
>>>   #define CTGP_DB_CTGP_ENABLE        BIT(2)
>>>   -#define EC_ADDR_CTGP_OFFSET        0x0744
>>> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET    0x0744
>>>   -#define EC_ADDR_TPP_OFFSET        0x0745
>>> +#define EC_ADDR_CTGP_DB_TPP_OFFSET    0x0745
>>>   -#define EC_ADDR_MAX_TGP            0x0746
>>> +#define EC_ADDR_CTGP_DB_DB_OFFSET    0x0746
>>>     #define EC_ADDR_LIGHTBAR_AC_CTRL    0x0748
>>>   #define LIGHTBAR_APP_EXISTS        BIT(0)
>>> @@ -317,6 +317,7 @@
>>>   #define UNIWILL_FEATURE_LIGHTBAR        BIT(3)
>>>   #define UNIWILL_FEATURE_BATTERY            BIT(4)
>>>   #define UNIWILL_FEATURE_HWMON            BIT(5)
>>> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(6)
>>>     struct uniwill_data {
>>>       struct device *dev;
>>> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device 
>>> *dev, unsigned int reg)
>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>           return true;
>>>       default:
>>>           return false;
>>> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device 
>>> *dev, unsigned int reg)
>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>           return true;
>>>       default:
>>>           return false;
>>> @@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct 
>>> device *dev, struct device_attri
>>>     static DEVICE_ATTR_RW(breathing_in_suspend);
>>>   +static ssize_t ctgp_offset_store(struct device *dev, struct 
>>> device_attribute *attr,
>>> +                 const char *buf, size_t count)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    unsigned int value;
>>> +    int ret;
>>> +
>>> +    ret = kstrtouint(buf, 0, &value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 
>>> value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    return count;
>>> +}
>>> +
>>> +static ssize_t ctgp_offset_show(struct device *dev, struct 
>>> device_attribute *attr,
>>> +                char *buf)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    unsigned int value;
>>> +    int ret;
>>> +
>>> +    ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 
>>> &value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    return sysfs_emit(buf, "%u\n", value);
>>> +}
>>> +
>>> +DEVICE_ATTR_RW(ctgp_offset);
>>> +
>>> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>>> +{
>>> +    int ret;
>>> +
>>> +    if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
>>> +        return 0;
>>> +
>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>> CTGP_DB_CTGP_ENABLE,
>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>> CTGP_DB_CTGP_ENABLE);
>>
>> I think we should initialize the power limits before enabling them, 
>> otherwise
>> the relevant registers might still contain invalid data.
> from boot they are all just 0, but ofc i can shuffle things around

Please do, i prefer to play it safe here as we are dealing with power limits.

>>
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
>>> +    if (ret < 0)
>>> +        return ret;
>>
>> Are those values the maximum values supported by the platform? If yes 
>> then
>> we should enforce them for sysfs writes.
>>
>> Also, why is only cTGP accessible from user space?
>
> Because that is the only one that should be settable by the user 
> according to NVIDIA, the rest should be set by the ODM.
>
> EC_ADDR_CTGP_DB_TPP_OFFSET max value is just max u8 and would be 
> another way to cap cpu + gpu power but there are already other ways to 
> do that (e.g. the power profiles) so i don't see a value in capping 
> them here in any way.
>
> EC_ADDR_CTGP_DB_DB_OFFSET max value 25 is just the maximum value for 
> dynamic boost defined by NVIDIA, bigger values are just being ignored 
> (behave the same as having set 25): again the same story: devices that 
> don't support 25 W dynamic boost are already capped elsewhere so i 
> don't see value in capping it here.
>
> EC_ADDR_CTGP_DB_CTGP_OFFSET is the only one intented to be set by the 
> user, problem: the max value is different from device to device, and i 
> only know how to probe it using nvidia smi from userspace. Good news: 
> nothing bad happens when you set a higher value (same as for dynamic 
> boost)
>
I see, do you know the max. value for cTGP for the devices you added in patch 1? The intel notebooks use a similar
setup, but they limit the max. value of cTGP depending on the GPU module.

I think that extending uniwill_data to contain a upper limit for cTGP would be nice for usability. We can use a default
value (U8_MAX) for devices where the upper limit is unknown. For devices where the limit is known, userspace application
can use the limit for showing it in the UI. Additionally i am planning to integrate cTGP into the platform profile, as it
is done on Intel machines. For this i will add the ability to define cTGP values for each platform profile, with the
max value being used for the upcoming max-power platform profile (also called "benchmark mode" on intel platforms).

To put it short please add an additional sysfs attribute (maybe called ctgp_offset_max?) add just return U8_MAX for now.
We can then add the individual limits for each device later if desired.

Thanks,
Armin Wolf

>>
>> Thanks,
>> Armin Wolf
>>
>>> +
>>> +    return 0;
>>> +}
>>> +
>>>   static struct attribute *uniwill_attrs[] = {
>>>       /* Keyboard-related */
>>>       &dev_attr_fn_lock_toggle_enable.attr,
>>> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>>>       /* Lightbar-related */
>>>       &dev_attr_rainbow_animation.attr,
>>>       &dev_attr_breathing_in_suspend.attr,
>>> +    /* Power-management-related */
>>> +    &dev_attr_ctgp_offset.attr,
>>>       NULL
>>>   };
>>>   @@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct 
>>> kobject *kobj, struct attribute *a
>>>               return attr->mode;
>>>       }
>>>   +    if (attr == &dev_attr_ctgp_offset.attr) {
>>> +        if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
>>> +            return attr->mode;
>>> +    }
>>> +
>>>       return 0;
>>>   }
>>>   @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct 
>>> platform_device *pdev)
>>>       if (ret < 0)
>>>           return ret;
>>>   +    ret = uniwill_nvidia_ctgp_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>>       return uniwill_input_init(data);
>>>   }
>>>   @@ -1547,6 +1629,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>>> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore 
>>> Omnia-Book Pro Gen 7",
>>> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, 
>>> "PH6AG01_PH6AQ71_PH6AQI1"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 
>>> Intel/Commodore Omnia-Book Pro Gen 8",
>>> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>>> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>>> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>>> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>>> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>>> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>>> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>>> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>>> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>>> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore 
>>> ORION Gen 5",
>>> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>>> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore 
>>> ORION Slim 15 Gen6",
>>> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 
>>> 16 Gen6",
>>> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 
>>> 16 Gen6",
>>> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 
>>> 17 Gen6",
>>> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>>> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>>           },
>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>       },
>>>       {
>>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 13:12       ` Armin Wolf
@ 2025-11-18 13:29         ` Werner Sembach
  2025-11-18 13:48           ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:29 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 14:12 schrieb Armin Wolf:
> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>
>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>
>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>> ---
>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>>>         /* Reported in manual mode when toggling the airplane mode status */
>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>         /* Reported when user wants to cycle the platform profile */
>>>> -    { KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>> +    { KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>
>>> I am currently working a patch adding platform profile support, so this 
>>> event would
>>> be handled inside the kernel on models with platform profile support.
>>
>> For tuxedo devices we have profiles managed in userspace that do additional 
>> things. So we need a way to handle this in userspace.
>>
> Do these things have something to do with the uniwill EC? If so then we should 
> implement those inside the driver
> itself. The control center can then poll the platform profile sysfs file to 
> get notified when platform_profile_cycle()
> is executed to perform additional actions.
Not exclusively, e.g. one thing is display brightness.
>
>> The 2 things I can spontaneously think of would be a sysfs toggle or 2 
>> different UNIWILL_FEATURE_* defines.
>>
> TPH i would love to have an ordinary keycode allocated for that if the above 
> does not work for you. There already
> exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE should 
> be possible.

New keycodes won't work on X11, I don't know the reason, but X11 only supports a 
max of 248 keycodes

That's why for example touchpad toggle is bound to F21 e.g. here 
https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
.

>
>>>
>>>>         /* Reported when the user wants to adjust the brightness of the 
>>>> keyboard */
>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>>>>       /* Reported when the user wants to toggle the microphone mute status */
>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>
>>> Why is this event being ignored?
>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key event, 
>> so not ignoring it here would result in a double trigger.
>
> I understand.
>
>>>
>>>> +
>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>         /* Reported when the user wants to toggle the brightness of the 
>>>> keyboard */
>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>         /* FIXME: find out the exact meaning of those events */
>>>>       { KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>>       /* Reported when the user wants to toggle the benchmark mode status */
>>>>       { KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>
>>> Same as above.
>>
>> Same as above ;)
>>
>> At least iirc, would have to double check
>>
> Ok.
>
> Thanks,
> Armin Wolf
>
>>>
>>>> +
>>>>       { KE_END }
>>>>   };
>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>> notifier_block *nb, unsigned long action
>>>>           }
>>>>           mutex_unlock(&data->battery_lock);
>>>>   +        return NOTIFY_OK;
>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>> +        // noop for the time being
>>>
>>> Wrong comment style, please use /* */.
>> ack
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>> +
>>>>           return NOTIFY_OK;
>>>>       default:
>>>>           mutex_lock(&data->input_lock);
>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>> @@ -113,6 +113,8 @@
>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>> +
>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>>     struct device;
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  2025-11-18 13:01     ` Werner Sembach
@ 2025-11-18 13:35       ` Armin Wolf
  2025-11-18 13:40         ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:35 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 14:01 schrieb Werner Sembach:

>
> Am 18.11.25 um 12:16 schrieb Armin Wolf:
>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>
>>> Move uniwill_dmi_table up and remove __intconst to make it also 
>>> accessible
>>> in the probe function.
>>
>> NAK, i expect the DMI table to become very large in the future, so 
>> not marking it
>> as __initconst will waste a sizeable amount of memory.
>>
>> Luckily i am also currently working on extending the DMI table to 
>> contain additional
>> configuration data like power limits and callbacks for 
>> device-specific initialization.
>>
>> I can share the patch with you if you want. It would allow us to 
>> discard the DMI table
>> after module initialization while still allowing for device-specific 
>> initialization
>> callbacks.
> this callback needs a way to probe for presence of a Nvidia card e.g. 
> by reading the ec

The patch i am talking about allows DMI table entries to provide a "device descriptor" that
basically is a struct consisting of vendor-specific data and a callback that is executed by
the platform driver when probing the EC. This would allow you to read the special register.
Said device descriptor will replace the supported_features variable.

I will send you the patch tomorrow.

Thanks,
Armin Wolf

>> Thanks,
>> Armin Wolf
>>
>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>> ---
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 344 
>>> ++++++++++----------
>>>   1 file changed, 172 insertions(+), 172 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> index de3417d9d1ac0..9412783698685 100644
>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>> @@ -1405,178 +1405,7 @@ static int uniwill_ec_init(struct 
>>> uniwill_data *data)
>>>       return devm_add_action_or_reset(data->dev, 
>>> uniwill_disable_manual_control, data);
>>>   }
>>>   -static int uniwill_probe(struct platform_device *pdev)
>>> -{
>>> -    struct uniwill_data *data;
>>> -    struct regmap *regmap;
>>> -    acpi_handle handle;
>>> -    int ret;
>>> -
>>> -    handle = ACPI_HANDLE(&pdev->dev);
>>> -    if (!handle)
>>> -        return -ENODEV;
>>> -
>>> -    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>>> -    if (!data)
>>> -        return -ENOMEM;
>>> -
>>> -    data->dev = &pdev->dev;
>>> -    data->handle = handle;
>>> -    platform_set_drvdata(pdev, data);
>>> -
>>> -    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>>> &uniwill_ec_config);
>>> -    if (IS_ERR(regmap))
>>> -        return PTR_ERR(regmap);
>>> -
>>> -    data->regmap = regmap;
>>> -    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_ec_init(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_battery_init(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_led_init(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_hwmon_init(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_nvidia_ctgp_init(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    return uniwill_input_init(data);
>>> -}
>>> -
>>> -static void uniwill_shutdown(struct platform_device *pdev)
>>> -{
>>> -    struct uniwill_data *data = platform_get_drvdata(pdev);
>>> -
>>> -    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, 
>>> ENABLE_MANUAL_CTRL);
>>> -}
>>> -
>>> -static int uniwill_suspend_keyboard(struct uniwill_data *data)
>>> -{
>>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>> -        return 0;
>>> -
>>> -    /*
>>> -     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have 
>>> to restore it
>>> -     * ourselves.
>>> -     */
>>> -    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>>> &data->last_switch_status);
>>> -}
>>> -
>>> -static int uniwill_suspend_battery(struct uniwill_data *data)
>>> -{
>>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>> -        return 0;
>>> -
>>> -    /*
>>> -     * Save the current charge limit in order to restore it during 
>>> resume.
>>> -     * We cannot use the regmap code for that since this register 
>>> needs to
>>> -     * be declared as volatile due to CHARGE_CTRL_REACHED.
>>> -     */
>>> -    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>> &data->last_charge_ctrl);
>>> -}
>>> -
>>> -static int uniwill_suspend(struct device *dev)
>>> -{
>>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>>> -    int ret;
>>> -
>>> -    ret = uniwill_suspend_keyboard(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_suspend_battery(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    regcache_cache_only(data->regmap, true);
>>> -    regcache_mark_dirty(data->regmap);
>>> -
>>> -    return 0;
>>> -}
>>> -
>>> -static int uniwill_resume_keyboard(struct uniwill_data *data)
>>> -{
>>> -    unsigned int value;
>>> -    int ret;
>>> -
>>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>> -        return 0;
>>> -
>>> -    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == 
>>> (value & SUPER_KEY_LOCK_STATUS))
>>> -        return 0;
>>> -
>>> -    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>>> TRIGGER_SUPER_KEY_LOCK,
>>> -                 TRIGGER_SUPER_KEY_LOCK);
>>> -}
>>> -
>>> -static int uniwill_resume_battery(struct uniwill_data *data)
>>> -{
>>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>> -        return 0;
>>> -
>>> -    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>> CHARGE_CTRL_MASK,
>>> -                  data->last_charge_ctrl);
>>> -}
>>> -
>>> -static int uniwill_resume(struct device *dev)
>>> -{
>>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>>> -    int ret;
>>> -
>>> -    regcache_cache_only(data->regmap, false);
>>> -
>>> -    ret = regcache_sync(data->regmap);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    ret = uniwill_resume_keyboard(data);
>>> -    if (ret < 0)
>>> -        return ret;
>>> -
>>> -    return uniwill_resume_battery(data);
>>> -}
>>> -
>>> -static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>>> uniwill_resume);
>>> -
>>> -/*
>>> - * We only use the DMI table for auoloading because the ACPI device 
>>> itself
>>> - * does not guarantee that the underlying EC implementation is 
>>> supported.
>>> - */
>>> -static const struct acpi_device_id uniwill_id_table[] = {
>>> -    { "INOU0000" },
>>> -    { },
>>> -};
>>> -
>>> -static struct platform_driver uniwill_driver = {
>>> -    .driver = {
>>> -        .name = DRIVER_NAME,
>>> -        .dev_groups = uniwill_groups,
>>> -        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>> -        .acpi_match_table = uniwill_id_table,
>>> -        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>>> -    },
>>> -    .probe = uniwill_probe,
>>> -    .shutdown = uniwill_shutdown,
>>> -};
>>> -
>>> -static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>>> +static const struct dmi_system_id uniwill_dmi_table[] = {
>>>       {
>>>           .ident = "XMG FUSION 15",
>>>           .matches = {
>>> @@ -1936,6 +1765,177 @@ static const struct dmi_system_id 
>>> uniwill_dmi_table[] __initconst = {
>>>   };
>>>   MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
>>>   +static int uniwill_probe(struct platform_device *pdev)
>>> +{
>>> +    struct uniwill_data *data;
>>> +    struct regmap *regmap;
>>> +    acpi_handle handle;
>>> +    int ret;
>>> +
>>> +    handle = ACPI_HANDLE(&pdev->dev);
>>> +    if (!handle)
>>> +        return -ENODEV;
>>> +
>>> +    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>>> +    if (!data)
>>> +        return -ENOMEM;
>>> +
>>> +    data->dev = &pdev->dev;
>>> +    data->handle = handle;
>>> +    platform_set_drvdata(pdev, data);
>>> +
>>> +    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>>> &uniwill_ec_config);
>>> +    if (IS_ERR(regmap))
>>> +        return PTR_ERR(regmap);
>>> +
>>> +    data->regmap = regmap;
>>> +    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_ec_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_battery_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_led_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_hwmon_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_nvidia_ctgp_init(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    return uniwill_input_init(data);
>>> +}
>>> +
>>> +static void uniwill_shutdown(struct platform_device *pdev)
>>> +{
>>> +    struct uniwill_data *data = platform_get_drvdata(pdev);
>>> +
>>> +    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, 
>>> ENABLE_MANUAL_CTRL);
>>> +}
>>> +
>>> +static int uniwill_suspend_keyboard(struct uniwill_data *data)
>>> +{
>>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>> +        return 0;
>>> +
>>> +    /*
>>> +     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have 
>>> to restore it
>>> +     * ourselves.
>>> +     */
>>> +    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>>> &data->last_switch_status);
>>> +}
>>> +
>>> +static int uniwill_suspend_battery(struct uniwill_data *data)
>>> +{
>>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>> +        return 0;
>>> +
>>> +    /*
>>> +     * Save the current charge limit in order to restore it during 
>>> resume.
>>> +     * We cannot use the regmap code for that since this register 
>>> needs to
>>> +     * be declared as volatile due to CHARGE_CTRL_REACHED.
>>> +     */
>>> +    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>> &data->last_charge_ctrl);
>>> +}
>>> +
>>> +static int uniwill_suspend(struct device *dev)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    int ret;
>>> +
>>> +    ret = uniwill_suspend_keyboard(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_suspend_battery(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    regcache_cache_only(data->regmap, true);
>>> +    regcache_mark_dirty(data->regmap);
>>> +
>>> +    return 0;
>>> +}
>>> +
>>> +static int uniwill_resume_keyboard(struct uniwill_data *data)
>>> +{
>>> +    unsigned int value;
>>> +    int ret;
>>> +
>>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>> +        return 0;
>>> +
>>> +    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == 
>>> (value & SUPER_KEY_LOCK_STATUS))
>>> +        return 0;
>>> +
>>> +    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>>> TRIGGER_SUPER_KEY_LOCK,
>>> +                 TRIGGER_SUPER_KEY_LOCK);
>>> +}
>>> +
>>> +static int uniwill_resume_battery(struct uniwill_data *data)
>>> +{
>>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>> +        return 0;
>>> +
>>> +    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>> CHARGE_CTRL_MASK,
>>> +                  data->last_charge_ctrl);
>>> +}
>>> +
>>> +static int uniwill_resume(struct device *dev)
>>> +{
>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>> +    int ret;
>>> +
>>> +    regcache_cache_only(data->regmap, false);
>>> +
>>> +    ret = regcache_sync(data->regmap);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    ret = uniwill_resume_keyboard(data);
>>> +    if (ret < 0)
>>> +        return ret;
>>> +
>>> +    return uniwill_resume_battery(data);
>>> +}
>>> +
>>> +static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>>> uniwill_resume);
>>> +
>>> +/*
>>> + * We only use the DMI table for auoloading because the ACPI device 
>>> itself
>>> + * does not guarantee that the underlying EC implementation is 
>>> supported.
>>> + */
>>> +static const struct acpi_device_id uniwill_id_table[] = {
>>> +    { "INOU0000" },
>>> +    { },
>>> +};
>>> +
>>> +static struct platform_driver uniwill_driver = {
>>> +    .driver = {
>>> +        .name = DRIVER_NAME,
>>> +        .dev_groups = uniwill_groups,
>>> +        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>> +        .acpi_match_table = uniwill_id_table,
>>> +        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>>> +    },
>>> +    .probe = uniwill_probe,
>>> +    .shutdown = uniwill_shutdown,
>>> +};
>>> +
>>>   static int __init uniwill_init(void)
>>>   {
>>>       const struct dmi_system_id *id;
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
  2025-11-18 13:35       ` Armin Wolf
@ 2025-11-18 13:40         ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:40 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 14:35 schrieb Armin Wolf:
> Am 18.11.25 um 14:01 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 12:16 schrieb Armin Wolf:
>>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>>
>>>> Move uniwill_dmi_table up and remove __intconst to make it also accessible
>>>> in the probe function.
>>>
>>> NAK, i expect the DMI table to become very large in the future, so not 
>>> marking it
>>> as __initconst will waste a sizeable amount of memory.
>>>
>>> Luckily i am also currently working on extending the DMI table to contain 
>>> additional
>>> configuration data like power limits and callbacks for device-specific 
>>> initialization.
>>>
>>> I can share the patch with you if you want. It would allow us to discard the 
>>> DMI table
>>> after module initialization while still allowing for device-specific 
>>> initialization
>>> callbacks.
>> this callback needs a way to probe for presence of a Nvidia card e.g. by 
>> reading the ec
>
> The patch i am talking about allows DMI table entries to provide a "device 
> descriptor" that
> basically is a struct consisting of vendor-specific data and a callback that 
> is executed by
> the platform driver when probing the EC. This would allow you to read the 
> special register.
> Said device descriptor will replace the supported_features variable.
Sounds like it would work for my usecase
>
> I will send you the patch tomorrow.
Thx
>
> Thanks,
> Armin Wolf
>
>>> Thanks,
>>> Armin Wolf
>>>
>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>> ---
>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 344 ++++++++++----------
>>>>   1 file changed, 172 insertions(+), 172 deletions(-)
>>>>
>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> index de3417d9d1ac0..9412783698685 100644
>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> @@ -1405,178 +1405,7 @@ static int uniwill_ec_init(struct uniwill_data *data)
>>>>       return devm_add_action_or_reset(data->dev, 
>>>> uniwill_disable_manual_control, data);
>>>>   }
>>>>   -static int uniwill_probe(struct platform_device *pdev)
>>>> -{
>>>> -    struct uniwill_data *data;
>>>> -    struct regmap *regmap;
>>>> -    acpi_handle handle;
>>>> -    int ret;
>>>> -
>>>> -    handle = ACPI_HANDLE(&pdev->dev);
>>>> -    if (!handle)
>>>> -        return -ENODEV;
>>>> -
>>>> -    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>>>> -    if (!data)
>>>> -        return -ENOMEM;
>>>> -
>>>> -    data->dev = &pdev->dev;
>>>> -    data->handle = handle;
>>>> -    platform_set_drvdata(pdev, data);
>>>> -
>>>> -    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>>>> &uniwill_ec_config);
>>>> -    if (IS_ERR(regmap))
>>>> -        return PTR_ERR(regmap);
>>>> -
>>>> -    data->regmap = regmap;
>>>> -    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_ec_init(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_battery_init(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_led_init(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_hwmon_init(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_nvidia_ctgp_init(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    return uniwill_input_init(data);
>>>> -}
>>>> -
>>>> -static void uniwill_shutdown(struct platform_device *pdev)
>>>> -{
>>>> -    struct uniwill_data *data = platform_get_drvdata(pdev);
>>>> -
>>>> -    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
>>>> -}
>>>> -
>>>> -static int uniwill_suspend_keyboard(struct uniwill_data *data)
>>>> -{
>>>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>>> -        return 0;
>>>> -
>>>> -    /*
>>>> -     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to 
>>>> restore it
>>>> -     * ourselves.
>>>> -     */
>>>> -    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>>>> &data->last_switch_status);
>>>> -}
>>>> -
>>>> -static int uniwill_suspend_battery(struct uniwill_data *data)
>>>> -{
>>>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>>> -        return 0;
>>>> -
>>>> -    /*
>>>> -     * Save the current charge limit in order to restore it during resume.
>>>> -     * We cannot use the regmap code for that since this register needs to
>>>> -     * be declared as volatile due to CHARGE_CTRL_REACHED.
>>>> -     */
>>>> -    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>>> &data->last_charge_ctrl);
>>>> -}
>>>> -
>>>> -static int uniwill_suspend(struct device *dev)
>>>> -{
>>>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> -    int ret;
>>>> -
>>>> -    ret = uniwill_suspend_keyboard(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_suspend_battery(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    regcache_cache_only(data->regmap, true);
>>>> -    regcache_mark_dirty(data->regmap);
>>>> -
>>>> -    return 0;
>>>> -}
>>>> -
>>>> -static int uniwill_resume_keyboard(struct uniwill_data *data)
>>>> -{
>>>> -    unsigned int value;
>>>> -    int ret;
>>>> -
>>>> -    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>>> -        return 0;
>>>> -
>>>> -    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & 
>>>> SUPER_KEY_LOCK_STATUS))
>>>> -        return 0;
>>>> -
>>>> -    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>>>> TRIGGER_SUPER_KEY_LOCK,
>>>> -                 TRIGGER_SUPER_KEY_LOCK);
>>>> -}
>>>> -
>>>> -static int uniwill_resume_battery(struct uniwill_data *data)
>>>> -{
>>>> -    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>>> -        return 0;
>>>> -
>>>> -    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>>> CHARGE_CTRL_MASK,
>>>> -                  data->last_charge_ctrl);
>>>> -}
>>>> -
>>>> -static int uniwill_resume(struct device *dev)
>>>> -{
>>>> -    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> -    int ret;
>>>> -
>>>> -    regcache_cache_only(data->regmap, false);
>>>> -
>>>> -    ret = regcache_sync(data->regmap);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    ret = uniwill_resume_keyboard(data);
>>>> -    if (ret < 0)
>>>> -        return ret;
>>>> -
>>>> -    return uniwill_resume_battery(data);
>>>> -}
>>>> -
>>>> -static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>>>> uniwill_resume);
>>>> -
>>>> -/*
>>>> - * We only use the DMI table for auoloading because the ACPI device itself
>>>> - * does not guarantee that the underlying EC implementation is supported.
>>>> - */
>>>> -static const struct acpi_device_id uniwill_id_table[] = {
>>>> -    { "INOU0000" },
>>>> -    { },
>>>> -};
>>>> -
>>>> -static struct platform_driver uniwill_driver = {
>>>> -    .driver = {
>>>> -        .name = DRIVER_NAME,
>>>> -        .dev_groups = uniwill_groups,
>>>> -        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>>> -        .acpi_match_table = uniwill_id_table,
>>>> -        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>>>> -    },
>>>> -    .probe = uniwill_probe,
>>>> -    .shutdown = uniwill_shutdown,
>>>> -};
>>>> -
>>>> -static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
>>>> +static const struct dmi_system_id uniwill_dmi_table[] = {
>>>>       {
>>>>           .ident = "XMG FUSION 15",
>>>>           .matches = {
>>>> @@ -1936,6 +1765,177 @@ static const struct dmi_system_id 
>>>> uniwill_dmi_table[] __initconst = {
>>>>   };
>>>>   MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
>>>>   +static int uniwill_probe(struct platform_device *pdev)
>>>> +{
>>>> +    struct uniwill_data *data;
>>>> +    struct regmap *regmap;
>>>> +    acpi_handle handle;
>>>> +    int ret;
>>>> +
>>>> +    handle = ACPI_HANDLE(&pdev->dev);
>>>> +    if (!handle)
>>>> +        return -ENODEV;
>>>> +
>>>> +    data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
>>>> +    if (!data)
>>>> +        return -ENOMEM;
>>>> +
>>>> +    data->dev = &pdev->dev;
>>>> +    data->handle = handle;
>>>> +    platform_set_drvdata(pdev, data);
>>>> +
>>>> +    regmap = devm_regmap_init(&pdev->dev, &uniwill_ec_bus, data, 
>>>> &uniwill_ec_config);
>>>> +    if (IS_ERR(regmap))
>>>> +        return PTR_ERR(regmap);
>>>> +
>>>> +    data->regmap = regmap;
>>>> +    ret = devm_mutex_init(&pdev->dev, &data->super_key_lock);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_ec_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_battery_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_led_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_hwmon_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_nvidia_ctgp_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    return uniwill_input_init(data);
>>>> +}
>>>> +
>>>> +static void uniwill_shutdown(struct platform_device *pdev)
>>>> +{
>>>> +    struct uniwill_data *data = platform_get_drvdata(pdev);
>>>> +
>>>> +    regmap_clear_bits(data->regmap, EC_ADDR_AP_OEM, ENABLE_MANUAL_CTRL);
>>>> +}
>>>> +
>>>> +static int uniwill_suspend_keyboard(struct uniwill_data *data)
>>>> +{
>>>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>>> +        return 0;
>>>> +
>>>> +    /*
>>>> +     * The EC_ADDR_SWITCH_STATUS is marked as volatile, so we have to 
>>>> restore it
>>>> +     * ourselves.
>>>> +     */
>>>> +    return regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, 
>>>> &data->last_switch_status);
>>>> +}
>>>> +
>>>> +static int uniwill_suspend_battery(struct uniwill_data *data)
>>>> +{
>>>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>>> +        return 0;
>>>> +
>>>> +    /*
>>>> +     * Save the current charge limit in order to restore it during resume.
>>>> +     * We cannot use the regmap code for that since this register needs to
>>>> +     * be declared as volatile due to CHARGE_CTRL_REACHED.
>>>> +     */
>>>> +    return regmap_read(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>>> &data->last_charge_ctrl);
>>>> +}
>>>> +
>>>> +static int uniwill_suspend(struct device *dev)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    int ret;
>>>> +
>>>> +    ret = uniwill_suspend_keyboard(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_suspend_battery(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    regcache_cache_only(data->regmap, true);
>>>> +    regcache_mark_dirty(data->regmap);
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>> +static int uniwill_resume_keyboard(struct uniwill_data *data)
>>>> +{
>>>> +    unsigned int value;
>>>> +    int ret;
>>>> +
>>>> +    if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
>>>> +        return 0;
>>>> +
>>>> +    ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    if ((data->last_switch_status & SUPER_KEY_LOCK_STATUS) == (value & 
>>>> SUPER_KEY_LOCK_STATUS))
>>>> +        return 0;
>>>> +
>>>> +    return regmap_write_bits(data->regmap, EC_ADDR_TRIGGER, 
>>>> TRIGGER_SUPER_KEY_LOCK,
>>>> +                 TRIGGER_SUPER_KEY_LOCK);
>>>> +}
>>>> +
>>>> +static int uniwill_resume_battery(struct uniwill_data *data)
>>>> +{
>>>> +    if (!(supported_features & UNIWILL_FEATURE_BATTERY))
>>>> +        return 0;
>>>> +
>>>> +    return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, 
>>>> CHARGE_CTRL_MASK,
>>>> +                  data->last_charge_ctrl);
>>>> +}
>>>> +
>>>> +static int uniwill_resume(struct device *dev)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    int ret;
>>>> +
>>>> +    regcache_cache_only(data->regmap, false);
>>>> +
>>>> +    ret = regcache_sync(data->regmap);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = uniwill_resume_keyboard(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    return uniwill_resume_battery(data);
>>>> +}
>>>> +
>>>> +static DEFINE_SIMPLE_DEV_PM_OPS(uniwill_pm_ops, uniwill_suspend, 
>>>> uniwill_resume);
>>>> +
>>>> +/*
>>>> + * We only use the DMI table for auoloading because the ACPI device itself
>>>> + * does not guarantee that the underlying EC implementation is supported.
>>>> + */
>>>> +static const struct acpi_device_id uniwill_id_table[] = {
>>>> +    { "INOU0000" },
>>>> +    { },
>>>> +};
>>>> +
>>>> +static struct platform_driver uniwill_driver = {
>>>> +    .driver = {
>>>> +        .name = DRIVER_NAME,
>>>> +        .dev_groups = uniwill_groups,
>>>> +        .probe_type = PROBE_PREFER_ASYNCHRONOUS,
>>>> +        .acpi_match_table = uniwill_id_table,
>>>> +        .pm = pm_sleep_ptr(&uniwill_pm_ops),
>>>> +    },
>>>> +    .probe = uniwill_probe,
>>>> +    .shutdown = uniwill_shutdown,
>>>> +};
>>>> +
>>>>   static int __init uniwill_init(void)
>>>>   {
>>>>       const struct dmi_system_id *id;
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-18 11:31 ` [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Armin Wolf
  2025-11-18 13:17   ` Werner Sembach
@ 2025-11-18 13:42   ` Werner Sembach
  2025-11-18 13:43     ` Armin Wolf
  1 sibling, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 13:42 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 12:31 schrieb Armin Wolf:
> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>
>> With the Uniwill driver from Armin now accepted I want to push the first
>> big addon to it that I worked on in parallel.
>>
>> First this adds all current Tuxedo devices to use at least the input part
>> of the new driver.
>>
>> Second it adds a new feature for cTGP control on Uniwill devices with
>> NVIDIA GPUs and enables that on the TUXEDO devices.
>>
>> I have not yet enabled the other features in this driver for TUXEDO devices
>> as they either don't apply (Uniwill did a line with Intel that behaves a
>> little different to the rest of their ECs and that line is what the features
>> Armin added are based on) or are, as of now, untested.
>>
>> There are plenty more features currently implemented in the out of tree
>> tuxedo-drivers dkms package that I plan to port over one by one, but as
>> always: No ETA given.
>
> Very nice, i think that especially the cTGP control feature will be very 
> popular with users.
> I am also currently working to add fan table (aka "universal fan control"), 
> PL1/PL2 power limit
> and platform profile support to the driver, so you might be able to reuse some 
> of that
> functionality for your devices.
>
> I think that we can merge the first two patches in the near future, but the 
> remaining ones
> dealing with the DMI table and cTGP support need some more work.
After reading through everything i will resend the first 2 patches reordered as 
v2 and work on the cTGP stuff as a separate patchset
> What kind of control does
> your software (Tuxedo control center) need over the cTGP values? I am asking 
> because Intel
> devices have fixed cTGP values for each platform profile. If your software 
> does something
> similar, then maybe we can integrate this into the platform profile mechanism.
>
> Thanks,
> Armin Wolf
>
>>
>> Werner Sembach (6):
>>    platform/x86/uniwill: Add TUXEDO devices
>>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>>      devices
>>    platform/x86/uniwill: Implement cTGP setting
>>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7
>>      MK1
>>
>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 ++++++++++++++++++--
>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>>   2 files changed, 502 insertions(+), 46 deletions(-)
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-18 13:17   ` Werner Sembach
@ 2025-11-18 13:42     ` Armin Wolf
  2025-11-18 14:24       ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:42 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 14:17 schrieb Werner Sembach:

>
> Am 18.11.25 um 12:31 schrieb Armin Wolf:
>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>
>>> With the Uniwill driver from Armin now accepted I want to push the 
>>> first
>>> big addon to it that I worked on in parallel.
>>>
>>> First this adds all current Tuxedo devices to use at least the input 
>>> part
>>> of the new driver.
>>>
>>> Second it adds a new feature for cTGP control on Uniwill devices with
>>> NVIDIA GPUs and enables that on the TUXEDO devices.
>>>
>>> I have not yet enabled the other features in this driver for TUXEDO 
>>> devices
>>> as they either don't apply (Uniwill did a line with Intel that 
>>> behaves a
>>> little different to the rest of their ECs and that line is what the 
>>> features
>>> Armin added are based on) or are, as of now, untested.
>>>
>>> There are plenty more features currently implemented in the out of tree
>>> tuxedo-drivers dkms package that I plan to port over one by one, but as
>>> always: No ETA given.
>>
>> Very nice, i think that especially the cTGP control feature will be 
>> very popular with users.
>> I am also currently working to add fan table (aka "universal fan 
>> control"), PL1/PL2 power limit
>> and platform profile support to the driver, so you might be able to 
>> reuse some of that
>> functionality for your devices.
>>
>> I think that we can merge the first two patches in the near future, 
>> but the remaining ones
>> dealing with the DMI table and cTGP support need some more work. What 
>> kind of control does
>> your software (Tuxedo control center) need over the cTGP values? I am 
>> asking because Intel
>> devices have fixed cTGP values for each platform profile. If your 
>> software does something
>> similar, then maybe we can integrate this into the platform profile 
>> mechanism.
>
> On some newer Uniwill devices all the platform profile register does 
> is changing a led, the actual TDP, cTGP, Fan Curves, etc. are set in 
> other registers. We currently expose this flexibility to userspace and 
> need to keep it that way.
>
The power mode LED i assume? The same thing happens on Intel devices, Fan curves and power limits are independent
settings. Perhaps the "custom" platform profile would be suitable here? When selecting the custom platform
profile, your userspace application can modify the fan curves and power limits as desired.

Thanks,
Armin Wolf

>>
>> Thanks,
>> Armin Wolf
>>
>>>
>>> Werner Sembach (6):
>>>    platform/x86/uniwill: Add TUXEDO devices
>>>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>>>      devices
>>>    platform/x86/uniwill: Implement cTGP setting
>>>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>>>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>>>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP 
>>> Gen7
>>>      MK1
>>>
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 
>>> ++++++++++++++++++--
>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>>>   2 files changed, 502 insertions(+), 46 deletions(-)
>>>
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-18 13:42   ` Werner Sembach
@ 2025-11-18 13:43     ` Armin Wolf
  0 siblings, 0 replies; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:43 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 14:42 schrieb Werner Sembach:

>
> Am 18.11.25 um 12:31 schrieb Armin Wolf:
>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>
>>> With the Uniwill driver from Armin now accepted I want to push the 
>>> first
>>> big addon to it that I worked on in parallel.
>>>
>>> First this adds all current Tuxedo devices to use at least the input 
>>> part
>>> of the new driver.
>>>
>>> Second it adds a new feature for cTGP control on Uniwill devices with
>>> NVIDIA GPUs and enables that on the TUXEDO devices.
>>>
>>> I have not yet enabled the other features in this driver for TUXEDO 
>>> devices
>>> as they either don't apply (Uniwill did a line with Intel that 
>>> behaves a
>>> little different to the rest of their ECs and that line is what the 
>>> features
>>> Armin added are based on) or are, as of now, untested.
>>>
>>> There are plenty more features currently implemented in the out of tree
>>> tuxedo-drivers dkms package that I plan to port over one by one, but as
>>> always: No ETA given.
>>
>> Very nice, i think that especially the cTGP control feature will be 
>> very popular with users.
>> I am also currently working to add fan table (aka "universal fan 
>> control"), PL1/PL2 power limit
>> and platform profile support to the driver, so you might be able to 
>> reuse some of that
>> functionality for your devices.
>>
>> I think that we can merge the first two patches in the near future, 
>> but the remaining ones
>> dealing with the DMI table and cTGP support need some more work.
> After reading through everything i will resend the first 2 patches 
> reordered as v2 and work on the cTGP stuff as a separate patchset

Fine with me.

Thanks,
Armin Wolf

>> What kind of control does
>> your software (Tuxedo control center) need over the cTGP values? I am 
>> asking because Intel
>> devices have fixed cTGP values for each platform profile. If your 
>> software does something
>> similar, then maybe we can integrate this into the platform profile 
>> mechanism.
>>
>> Thanks,
>> Armin Wolf
>>
>>>
>>> Werner Sembach (6):
>>>    platform/x86/uniwill: Add TUXEDO devices
>>>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>>>      devices
>>>    platform/x86/uniwill: Implement cTGP setting
>>>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>>>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>>>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP 
>>> Gen7
>>>      MK1
>>>
>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 
>>> ++++++++++++++++++--
>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>>>   2 files changed, 502 insertions(+), 46 deletions(-)
>>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 13:29         ` Werner Sembach
@ 2025-11-18 13:48           ` Armin Wolf
  2025-11-18 14:27             ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 13:48 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 14:29 schrieb Werner Sembach:

>
> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>
>>>
>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>
>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>
>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>> ---
>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 
>>>>> ++++++++++++++++++-
>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>> uniwill_keymap[] = {
>>>>>         /* Reported in manual mode when toggling the airplane mode 
>>>>> status */
>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>> -    { KE_IGNORE,    UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>> KEY_UNKNOWN }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>> KEY_F14 }},
>>>>
>>>> I am currently working a patch adding platform profile support, so 
>>>> this event would
>>>> be handled inside the kernel on models with platform profile support.
>>>
>>> For tuxedo devices we have profiles managed in userspace that do 
>>> additional things. So we need a way to handle this in userspace.
>>>
>> Do these things have something to do with the uniwill EC? If so then 
>> we should implement those inside the driver
>> itself. The control center can then poll the platform profile sysfs 
>> file to get notified when platform_profile_cycle()
>> is executed to perform additional actions.
> Not exclusively, e.g. one thing is display brightness.

And you cannot poll the sysfs interface?

>>
>>> The 2 things I can spontaneously think of would be a sysfs toggle or 
>>> 2 different UNIWILL_FEATURE_* defines.
>>>
>> TPH i would love to have an ordinary keycode allocated for that if 
>> the above does not work for you. There already
>> exists KEY_PERFORMANCE, so adding something like 
>> KEY_PERFORMANCE_CYCLE should be possible.
>
> New keycodes won't work on X11, I don't know the reason, but X11 only 
> supports a max of 248 keycodes
>
> That's why for example touchpad toggle is bound to F21 e.g. here 
> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
> .
>
Oh no. In this case using F14 is fine.


Thanks,
Armin Wolf

>>
>>>>
>>>>>         /* Reported when the user wants to adjust the brightness 
>>>>> of the keyboard */
>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN 
>>>>> }},
>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>> uniwill_keymap[] = {
>>>>>       /* Reported when the user wants to toggle the microphone 
>>>>> mute status */
>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>
>>>> Why is this event being ignored?
>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute 
>>> key event, so not ignoring it here would result in a double trigger.
>>
>> I understand.
>>
>>>>
>>>>> +
>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>         /* Reported when the user wants to toggle the brightness 
>>>>> of the keyboard */
>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { 
>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>       { KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>> KEY_UNKNOWN }},
>>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] 
>>>>> = {
>>>>>       /* Reported when the user wants to toggle the benchmark mode 
>>>>> status */
>>>>>       { KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>> KEY_UNKNOWN }},
>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>
>>>> Same as above.
>>>
>>> Same as above ;)
>>>
>>> At least iirc, would have to double check
>>>
>> Ok.
>>
>> Thanks,
>> Armin Wolf
>>
>>>>
>>>>> +
>>>>>       { KE_END }
>>>>>   };
>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>> notifier_block *nb, unsigned long action
>>>>>           }
>>>>>           mutex_unlock(&data->battery_lock);
>>>>>   +        return NOTIFY_OK;
>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>> +        // noop for the time being
>>>>
>>>> Wrong comment style, please use /* */.
>>> ack
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>> +
>>>>>           return NOTIFY_OK;
>>>>>       default:
>>>>>           mutex_lock(&data->input_lock);
>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>> @@ -113,6 +113,8 @@
>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>> +
>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>>>     struct device;
>>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices
  2025-11-18 13:42     ` Armin Wolf
@ 2025-11-18 14:24       ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 14:24 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 14:42 schrieb Armin Wolf:
> Am 18.11.25 um 14:17 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 12:31 schrieb Armin Wolf:
>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>
>>>> With the Uniwill driver from Armin now accepted I want to push the first
>>>> big addon to it that I worked on in parallel.
>>>>
>>>> First this adds all current Tuxedo devices to use at least the input part
>>>> of the new driver.
>>>>
>>>> Second it adds a new feature for cTGP control on Uniwill devices with
>>>> NVIDIA GPUs and enables that on the TUXEDO devices.
>>>>
>>>> I have not yet enabled the other features in this driver for TUXEDO devices
>>>> as they either don't apply (Uniwill did a line with Intel that behaves a
>>>> little different to the rest of their ECs and that line is what the features
>>>> Armin added are based on) or are, as of now, untested.
>>>>
>>>> There are plenty more features currently implemented in the out of tree
>>>> tuxedo-drivers dkms package that I plan to port over one by one, but as
>>>> always: No ETA given.
>>>
>>> Very nice, i think that especially the cTGP control feature will be very 
>>> popular with users.
>>> I am also currently working to add fan table (aka "universal fan control"), 
>>> PL1/PL2 power limit
>>> and platform profile support to the driver, so you might be able to reuse 
>>> some of that
>>> functionality for your devices.
>>>
>>> I think that we can merge the first two patches in the near future, but the 
>>> remaining ones
>>> dealing with the DMI table and cTGP support need some more work. What kind 
>>> of control does
>>> your software (Tuxedo control center) need over the cTGP values? I am asking 
>>> because Intel
>>> devices have fixed cTGP values for each platform profile. If your software 
>>> does something
>>> similar, then maybe we can integrate this into the platform profile mechanism.
>>
>> On some newer Uniwill devices all the platform profile register does is 
>> changing a led, the actual TDP, cTGP, Fan Curves, etc. are set in other 
>> registers. We currently expose this flexibility to userspace and need to keep 
>> it that way.
>>
> The power mode LED i assume? The same thing happens on Intel devices, Fan 
> curves and power limits are independent
> settings. Perhaps the "custom" platform profile would be suitable here? When 
> selecting the custom platform
> profile, your userspace application can modify the fan curves and power limits 
> as desired.

Ah ok,

There are however uniwill devices where the register does more.

But when there is a custom profile i think TCC could fit into that.

>
> Thanks,
> Armin Wolf
>
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>
>>>> Werner Sembach (6):
>>>>    platform/x86/uniwill: Add TUXEDO devices
>>>>    platform/x86/uniwill: Handle more WMI events required for TUXEDO
>>>>      devices
>>>>    platform/x86/uniwill: Implement cTGP setting
>>>>    platform/x86/uniwill: Make uniwill_dmi_table accessible in probe
>>>>    platform/x86/uniwill: Run callbacks of uniwill_dmi_table
>>>>    platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7
>>>>      MK1
>>>>
>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 546 ++++++++++++++++++--
>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |   2 +
>>>>   2 files changed, 502 insertions(+), 46 deletions(-)
>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 13:48           ` Armin Wolf
@ 2025-11-18 14:27             ` Werner Sembach
  2025-11-18 14:41               ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 14:27 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 14:48 schrieb Armin Wolf:
> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>
>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>
>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>> ---
>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>         /* Reported in manual mode when toggling the airplane mode status */
>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>
>>>>> I am currently working a patch adding platform profile support, so this 
>>>>> event would
>>>>> be handled inside the kernel on models with platform profile support.
>>>>
>>>> For tuxedo devices we have profiles managed in userspace that do additional 
>>>> things. So we need a way to handle this in userspace.
>>>>
>>> Do these things have something to do with the uniwill EC? If so then we 
>>> should implement those inside the driver
>>> itself. The control center can then poll the platform profile sysfs file to 
>>> get notified when platform_profile_cycle()
>>> is executed to perform additional actions.
>> Not exclusively, e.g. one thing is display brightness.
>
> And you cannot poll the sysfs interface?
I can't follow you atm?
>
>>>
>>>> The 2 things I can spontaneously think of would be a sysfs toggle or 2 
>>>> different UNIWILL_FEATURE_* defines.
>>>>
>>> TPH i would love to have an ordinary keycode allocated for that if the above 
>>> does not work for you. There already
>>> exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE 
>>> should be possible.
>>
>> New keycodes won't work on X11, I don't know the reason, but X11 only 
>> supports a max of 248 keycodes
>>
>> That's why for example touchpad toggle is bound to F21 e.g. here 
>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>> .
>>
> Oh no. In this case using F14 is fine.
>
>
> Thanks,
> Armin Wolf
>
>>>
>>>>>
>>>>>>         /* Reported when the user wants to adjust the brightness of the 
>>>>>> keyboard */
>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>       /* Reported when the user wants to toggle the microphone mute 
>>>>>> status */
>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>
>>>>> Why is this event being ignored?
>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key 
>>>> event, so not ignoring it here would result in a double trigger.
>>>
>>> I understand.
>>>
>>>>>
>>>>>> +
>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>         /* Reported when the user wants to toggle the brightness of the 
>>>>>> keyboard */
>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>       { KE_IGNORE,    UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>       /* Reported when the user wants to toggle the benchmark mode status */
>>>>>>       { KE_IGNORE,    UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>
>>>>> Same as above.
>>>>
>>>> Same as above ;)
>>>>
>>>> At least iirc, would have to double check
>>>>
>>> Ok.
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>>
>>>>>> +
>>>>>>       { KE_END }
>>>>>>   };
>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>> notifier_block *nb, unsigned long action
>>>>>>           }
>>>>>>           mutex_unlock(&data->battery_lock);
>>>>>>   +        return NOTIFY_OK;
>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>> +        // noop for the time being
>>>>>
>>>>> Wrong comment style, please use /* */.
>>>> ack
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>> +
>>>>>>           return NOTIFY_OK;
>>>>>>       default:
>>>>>>           mutex_lock(&data->input_lock);
>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>> @@ -113,6 +113,8 @@
>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>>> +
>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>>>>     struct device;
>>>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 14:27             ` Werner Sembach
@ 2025-11-18 14:41               ` Armin Wolf
  2025-11-18 15:05                 ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-18 14:41 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 18.11.25 um 15:27 schrieb Werner Sembach:

>
> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>
>>>
>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>
>>>>>
>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>
>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>
>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>> ---
>>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 
>>>>>>> ++++++++++++++++++-
>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>>>> uniwill_keymap[] = {
>>>>>>>         /* Reported in manual mode when toggling the airplane 
>>>>>>> mode status */
>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>         /* Reported when user wants to cycle the platform 
>>>>>>> profile */
>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>> KEY_UNKNOWN }},
>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>
>>>>>> I am currently working a patch adding platform profile support, 
>>>>>> so this event would
>>>>>> be handled inside the kernel on models with platform profile 
>>>>>> support.
>>>>>
>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>> additional things. So we need a way to handle this in userspace.
>>>>>
>>>> Do these things have something to do with the uniwill EC? If so 
>>>> then we should implement those inside the driver
>>>> itself. The control center can then poll the platform profile sysfs 
>>>> file to get notified when platform_profile_cycle()
>>>> is executed to perform additional actions.
>>> Not exclusively, e.g. one thing is display brightness.
>>
>> And you cannot poll the sysfs interface?
> I can't follow you atm?

I meant to ask whether or not your application could poll the platform profile sysfs interface for changes instead of
listing for the F14 key.

Thanks,
Armin Wolf

>>
>>>>
>>>>> The 2 things I can spontaneously think of would be a sysfs toggle 
>>>>> or 2 different UNIWILL_FEATURE_* defines.
>>>>>
>>>> TPH i would love to have an ordinary keycode allocated for that if 
>>>> the above does not work for you. There already
>>>> exists KEY_PERFORMANCE, so adding something like 
>>>> KEY_PERFORMANCE_CYCLE should be possible.
>>>
>>> New keycodes won't work on X11, I don't know the reason, but X11 
>>> only supports a max of 248 keycodes
>>>
>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>> .
>>>
>> Oh no. In this case using F14 is fine.
>>
>>
>> Thanks,
>> Armin Wolf
>>
>>>>
>>>>>>
>>>>>>>         /* Reported when the user wants to adjust the brightness 
>>>>>>> of the keyboard */
>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { 
>>>>>>> KEY_KBDILLUMDOWN }},
>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>> uniwill_keymap[] = {
>>>>>>>       /* Reported when the user wants to toggle the microphone 
>>>>>>> mute status */
>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>
>>>>>> Why is this event being ignored?
>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute 
>>>>> key event, so not ignoring it here would result in a double trigger.
>>>>
>>>> I understand.
>>>>
>>>>>>
>>>>>>> +
>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>         /* Reported when the user wants to toggle the brightness 
>>>>>>> of the keyboard */
>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { 
>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>>>> KEY_UNKNOWN }},
>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry 
>>>>>>> uniwill_keymap[] = {
>>>>>>>       /* Reported when the user wants to toggle the benchmark 
>>>>>>> mode status */
>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>>>> KEY_UNKNOWN }},
>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>
>>>>>> Same as above.
>>>>>
>>>>> Same as above ;)
>>>>>
>>>>> At least iirc, would have to double check
>>>>>
>>>> Ok.
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>>>
>>>>>>> +
>>>>>>>       { KE_END }
>>>>>>>   };
>>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>>> notifier_block *nb, unsigned long action
>>>>>>>           }
>>>>>>>           mutex_unlock(&data->battery_lock);
>>>>>>>   +        return NOTIFY_OK;
>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>> +        // noop for the time being
>>>>>>
>>>>>> Wrong comment style, please use /* */.
>>>>> ack
>>>>>>
>>>>>> Thanks,
>>>>>> Armin Wolf
>>>>>>
>>>>>>> +
>>>>>>>           return NOTIFY_OK;
>>>>>>>       default:
>>>>>>>           mutex_lock(&data->input_lock);
>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE    0xC0
>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>>>> +
>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>>>>>     struct device;
>>>>>
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 14:41               ` Armin Wolf
@ 2025-11-18 15:05                 ` Werner Sembach
  2025-11-20  0:53                   ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-18 15:05 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 15:41 schrieb Armin Wolf:
> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>
>>>>>>
>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>
>>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>>
>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>> ---
>>>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>
>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>         /* Reported in manual mode when toggling the airplane mode 
>>>>>>>> status */
>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>>
>>>>>>> I am currently working a patch adding platform profile support, so this 
>>>>>>> event would
>>>>>>> be handled inside the kernel on models with platform profile support.
>>>>>>
>>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>>> additional things. So we need a way to handle this in userspace.
>>>>>>
>>>>> Do these things have something to do with the uniwill EC? If so then we 
>>>>> should implement those inside the driver
>>>>> itself. The control center can then poll the platform profile sysfs file 
>>>>> to get notified when platform_profile_cycle()
>>>>> is executed to perform additional actions.
>>>> Not exclusively, e.g. one thing is display brightness.
>>>
>>> And you cannot poll the sysfs interface?
>> I can't follow you atm?
>
> I meant to ask whether or not your application could poll the platform profile 
> sysfs interface for changes instead of
> listing for the F14 key.
But the platform profiles are a fixed number? TCC currently allows an arbitrary 
amount of profiles being created.
>
> Thanks,
> Armin Wolf
>
>>>
>>>>>
>>>>>> The 2 things I can spontaneously think of would be a sysfs toggle or 2 
>>>>>> different UNIWILL_FEATURE_* defines.
>>>>>>
>>>>> TPH i would love to have an ordinary keycode allocated for that if the 
>>>>> above does not work for you. There already
>>>>> exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE 
>>>>> should be possible.
>>>>
>>>> New keycodes won't work on X11, I don't know the reason, but X11 only 
>>>> supports a max of 248 keycodes
>>>>
>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>> .
>>>>
>>> Oh no. In this case using F14 is fine.
>>>
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>>
>>>>>>>
>>>>>>>>         /* Reported when the user wants to adjust the brightness of the 
>>>>>>>> keyboard */
>>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>       /* Reported when the user wants to toggle the microphone mute 
>>>>>>>> status */
>>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>
>>>>>>> Why is this event being ignored?
>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key 
>>>>>> event, so not ignoring it here would result in a double trigger.
>>>>>
>>>>> I understand.
>>>>>
>>>>>>>
>>>>>>>> +
>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>         /* Reported when the user wants to toggle the brightness of the 
>>>>>>>> keyboard */
>>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>       /* Reported when the user wants to toggle the benchmark mode 
>>>>>>>> status */
>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>
>>>>>>> Same as above.
>>>>>>
>>>>>> Same as above ;)
>>>>>>
>>>>>> At least iirc, would have to double check
>>>>>>
>>>>> Ok.
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>>>
>>>>>>>> +
>>>>>>>>       { KE_END }
>>>>>>>>   };
>>>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>>>> notifier_block *nb, unsigned long action
>>>>>>>>           }
>>>>>>>>           mutex_unlock(&data->battery_lock);
>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>> +        // noop for the time being
>>>>>>>
>>>>>>> Wrong comment style, please use /* */.
>>>>>> ack
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Armin Wolf
>>>>>>>
>>>>>>>> +
>>>>>>>>           return NOTIFY_OK;
>>>>>>>>       default:
>>>>>>>>           mutex_lock(&data->input_lock);
>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>>>>> +
>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED    0xF0
>>>>>>>>     struct device;
>>>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-18 13:29       ` Armin Wolf
@ 2025-11-19 15:34         ` Werner Sembach
  2025-11-20  1:16           ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-19 15:34 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 18.11.25 um 14:29 schrieb Armin Wolf:
> Am 18.11.25 um 13:58 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 12:12 schrieb Armin Wolf:
>>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>>
>>>> Uniwill offers user setable cTGP for their EC on devices using NVIDIA 3000
>>>> Series and newer GPUs. This patch implements this setting as a sysfs
>>>> attribute.
>>>>
>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>> ---
>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 +++++++++++++++++++-
>>>>   1 file changed, 107 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> index 0cb86a701b2e1..de3417d9d1ac0 100644
>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>> @@ -122,11 +122,11 @@
>>>>   #define CTGP_DB_DB_ENABLE        BIT(1)
>>>>   #define CTGP_DB_CTGP_ENABLE        BIT(2)
>>>>   -#define EC_ADDR_CTGP_OFFSET        0x0744
>>>> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET    0x0744
>>>>   -#define EC_ADDR_TPP_OFFSET        0x0745
>>>> +#define EC_ADDR_CTGP_DB_TPP_OFFSET    0x0745
>>>>   -#define EC_ADDR_MAX_TGP            0x0746
>>>> +#define EC_ADDR_CTGP_DB_DB_OFFSET    0x0746
>>>>     #define EC_ADDR_LIGHTBAR_AC_CTRL    0x0748
>>>>   #define LIGHTBAR_APP_EXISTS        BIT(0)
>>>> @@ -317,6 +317,7 @@
>>>>   #define UNIWILL_FEATURE_LIGHTBAR        BIT(3)
>>>>   #define UNIWILL_FEATURE_BATTERY            BIT(4)
>>>>   #define UNIWILL_FEATURE_HWMON            BIT(5)
>>>> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(6)
>>>>     struct uniwill_data {
>>>>       struct device *dev;
>>>> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device *dev, 
>>>> unsigned int reg)
>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>           return true;
>>>>       default:
>>>>           return false;
>>>> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device *dev, 
>>>> unsigned int reg)
>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>           return true;
>>>>       default:
>>>>           return false;
>>>> @@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct device 
>>>> *dev, struct device_attri
>>>>     static DEVICE_ATTR_RW(breathing_in_suspend);
>>>>   +static ssize_t ctgp_offset_store(struct device *dev, struct 
>>>> device_attribute *attr,
>>>> +                 const char *buf, size_t count)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    unsigned int value;
>>>> +    int ret;
>>>> +
>>>> +    ret = kstrtouint(buf, 0, &value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    return count;
>>>> +}
>>>> +
>>>> +static ssize_t ctgp_offset_show(struct device *dev, struct 
>>>> device_attribute *attr,
>>>> +                char *buf)
>>>> +{
>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>> +    unsigned int value;
>>>> +    int ret;
>>>> +
>>>> +    ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, &value);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    return sysfs_emit(buf, "%u\n", value);
>>>> +}
>>>> +
>>>> +DEVICE_ATTR_RW(ctgp_offset);
>>>> +
>>>> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>>>> +{
>>>> +    int ret;
>>>> +
>>>> +    if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
>>>> +        return 0;
>>>> +
>>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>> CTGP_DB_CTGP_ENABLE,
>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>> CTGP_DB_CTGP_ENABLE);
>>>
>>> I think we should initialize the power limits before enabling them, otherwise
>>> the relevant registers might still contain invalid data.
>> from boot they are all just 0, but ofc i can shuffle things around
>
> Please do, i prefer to play it safe here as we are dealing with power limits.
>
>>>
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>
>>> Are those values the maximum values supported by the platform? If yes then
>>> we should enforce them for sysfs writes.
>>>
>>> Also, why is only cTGP accessible from user space?
>>
>> Because that is the only one that should be settable by the user according to 
>> NVIDIA, the rest should be set by the ODM.
>>
>> EC_ADDR_CTGP_DB_TPP_OFFSET max value is just max u8 and would be another way 
>> to cap cpu + gpu power but there are already other ways to do that (e.g. the 
>> power profiles) so i don't see a value in capping them here in any way.
>>
>> EC_ADDR_CTGP_DB_DB_OFFSET max value 25 is just the maximum value for dynamic 
>> boost defined by NVIDIA, bigger values are just being ignored (behave the 
>> same as having set 25): again the same story: devices that don't support 25 W 
>> dynamic boost are already capped elsewhere so i don't see value in capping it 
>> here.
>>
>> EC_ADDR_CTGP_DB_CTGP_OFFSET is the only one intented to be set by the user, 
>> problem: the max value is different from device to device, and i only know 
>> how to probe it using nvidia smi from userspace. Good news: nothing bad 
>> happens when you set a higher value (same as for dynamic boost)
>>
> I see, do you know the max. value for cTGP for the devices you added in patch 
> 1? The intel notebooks use a similar
> setup, but they limit the max. value of cTGP depending on the GPU module.
>
> I think that extending uniwill_data to contain a upper limit for cTGP would be 
> nice for usability. We can use a default
> value (U8_MAX) for devices where the upper limit is unknown. For devices where 
> the limit is known, userspace application
> can use the limit for showing it in the UI. Additionally i am planning to 
> integrate cTGP into the platform profile, as it
> is done on Intel machines. For this i will add the ability to define cTGP 
> values for each platform profile, with the
> max value being used for the upcoming max-power platform profile (also called 
> "benchmark mode" on intel platforms).

cTGP is a little bit complicated

cTGP can be set between a Base TGP and a Max TGP (what you see here in the 
driver is actually only the offset from the base TGP).

The Dynamic Boost setting here give the max width of the dynamic boost windows, 
however this is still affected by the max TGP.

Say cTGP is 100W Max TGP is 115W and Dynamic Boost setting is 25W -> The Dynamic 
Boost window is actually just 15W because it can't go over Max TGP.

Now setting the cTGP to 80W, the Dynamic Boost window becomes 25W and the GPU 
will never clock above 105W.

What does this mean? Setting cTGP between 80W and 90W actually changes the 
overall power consumption, while setting it between 90W and 115W does not, it 
just reduces the drivers automatic power allocation window in favor of the gpu. 
-> At a certain point more cTGP does not bring more performance, it actually can 
hurt performance for CPU heavy tasks.

In addition: Most Uniwill devies don't even have a window between Base TGP and 
Max TGP that is bigger then the allowed Dynamic Boost window. -> There is no 
power saving in setting cTGP on most Uniwill devices and the "more performance" 
window of cTGP has a witdh of 0.

And all Uniwill devices that i have seen have the GPU locked at a Watt level 
below the Base TGP level on Battery. -> There is no battery saving in setting 
cTGP on all Uniwill devices

>
> To put it short please add an additional sysfs attribute (maybe called 
> ctgp_offset_max?) add just return U8_MAX for now.
> We can then add the individual limits for each device later if desired.
I don't think a placeholder sysfs attribute that is not used by anything is 
sensefull. I would wait with including it until it is actually used.
>
> Thanks,
> Armin Wolf
On a different note, leaving the one device out that needs the qurik callback, 
the patch should allready be usefull and ready?
>
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>> +
>>>> +    return 0;
>>>> +}
>>>> +
>>>>   static struct attribute *uniwill_attrs[] = {
>>>>       /* Keyboard-related */
>>>>       &dev_attr_fn_lock_toggle_enable.attr,
>>>> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>>>>       /* Lightbar-related */
>>>>       &dev_attr_rainbow_animation.attr,
>>>>       &dev_attr_breathing_in_suspend.attr,
>>>> +    /* Power-management-related */
>>>> +    &dev_attr_ctgp_offset.attr,
>>>>       NULL
>>>>   };
>>>>   @@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct 
>>>> kobject *kobj, struct attribute *a
>>>>               return attr->mode;
>>>>       }
>>>>   +    if (attr == &dev_attr_ctgp_offset.attr) {
>>>> +        if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
>>>> +            return attr->mode;
>>>> +    }
>>>> +
>>>>       return 0;
>>>>   }
>>>>   @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct platform_device 
>>>> *pdev)
>>>>       if (ret < 0)
>>>>           return ret;
>>>>   +    ret = uniwill_nvidia_ctgp_init(data);
>>>> +    if (ret < 0)
>>>> +        return ret;
>>>> +
>>>>       return uniwill_input_init(data);
>>>>   }
>>>>   @@ -1547,6 +1629,7 @@ static const struct dmi_system_id 
>>>> uniwill_dmi_table[] __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>>>> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore 
>>>> Omnia-Book Pro Gen 7",
>>>> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore 
>>>> Omnia-Book Pro Gen 8",
>>>> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>>>> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>>>> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>>>> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>>>> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>>>> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>>>> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>>>> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>>>> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>>>> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 5",
>>>> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>>>> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION 
>>>> Slim 15 Gen6",
>>>> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>>>> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>>>> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
>>>> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>>>> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id uniwill_dmi_table[] 
>>>> __initconst = {
>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>>>           },
>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>       },
>>>>       {
>>>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-18 15:05                 ` Werner Sembach
@ 2025-11-20  0:53                   ` Armin Wolf
  2025-11-20 10:42                     ` Werner Sembach
  2025-11-24 18:40                     ` Werner Sembach
  0 siblings, 2 replies; 43+ messages in thread
From: Armin Wolf @ 2025-11-20  0:53 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

[-- Attachment #1: Type: text/plain, Size: 8434 bytes --]

Am 18.11.25 um 16:05 schrieb Werner Sembach:

>
> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>
>>>
>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>
>>>>>
>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>
>>>>>>>
>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>
>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>>>
>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>> ---
>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 
>>>>>>>>> ++++++++++++++++++-
>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  |  2 ++
>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>
>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>         /* Reported in manual mode when toggling the airplane 
>>>>>>>>> mode status */
>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>         /* Reported when user wants to cycle the platform 
>>>>>>>>> profile */
>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>>>
>>>>>>>> I am currently working a patch adding platform profile support, 
>>>>>>>> so this event would
>>>>>>>> be handled inside the kernel on models with platform profile 
>>>>>>>> support.
>>>>>>>
>>>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>>>> additional things. So we need a way to handle this in userspace.
>>>>>>>
>>>>>> Do these things have something to do with the uniwill EC? If so 
>>>>>> then we should implement those inside the driver
>>>>>> itself. The control center can then poll the platform profile 
>>>>>> sysfs file to get notified when platform_profile_cycle()
>>>>>> is executed to perform additional actions.
>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>
>>>> And you cannot poll the sysfs interface?
>>> I can't follow you atm?
>>
>> I meant to ask whether or not your application could poll the 
>> platform profile sysfs interface for changes instead of
>> listing for the F14 key.
> But the platform profiles are a fixed number? TCC currently allows an 
> arbitrary amount of profiles being created.

With "poll the platform profile sysfs interface" i meant that you could use poll() (https://linux.die.net/man/2/poll)
or epoll() on the sysfs file containing the current platform profile.

Anyway, i attached the patch with the device descriptor infrastructure. The callback called during probe cannot modify
the feature bitmap anymore, but i suggest that you simply set the limit for cTGP to zero. The code responsible for
initializing cTGP support can then check if the cTGP limit is zero and return early.

Thanks,
Armin Wolf

>>
>> Thanks,
>> Armin Wolf
>>
>>>>
>>>>>>
>>>>>>> The 2 things I can spontaneously think of would be a sysfs 
>>>>>>> toggle or 2 different UNIWILL_FEATURE_* defines.
>>>>>>>
>>>>>> TPH i would love to have an ordinary keycode allocated for that 
>>>>>> if the above does not work for you. There already
>>>>>> exists KEY_PERFORMANCE, so adding something like 
>>>>>> KEY_PERFORMANCE_CYCLE should be possible.
>>>>>
>>>>> New keycodes won't work on X11, I don't know the reason, but X11 
>>>>> only supports a max of 248 keycodes
>>>>>
>>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>> .
>>>>>
>>>> Oh no. In this case using F14 is fine.
>>>>
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>>>
>>>>>>>>
>>>>>>>>>         /* Reported when the user wants to adjust the 
>>>>>>>>> brightness of the keyboard */
>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { 
>>>>>>>>> KEY_KBDILLUMDOWN }},
>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>       /* Reported when the user wants to toggle the microphone 
>>>>>>>>> mute status */
>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>   +    /* Reported when the user wants to toggle the mute 
>>>>>>>>> status */
>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>
>>>>>>>> Why is this event being ignored?
>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the 
>>>>>>> mute key event, so not ignoring it here would result in a double 
>>>>>>> trigger.
>>>>>>
>>>>>> I understand.
>>>>>>
>>>>>>>>
>>>>>>>>> +
>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>         /* Reported when the user wants to toggle the 
>>>>>>>>> brightness of the keyboard */
>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { 
>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry 
>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>       /* Reported when the user wants to toggle the benchmark 
>>>>>>>>> mode status */
>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>
>>>>>>>> Same as above.
>>>>>>>
>>>>>>> Same as above ;)
>>>>>>>
>>>>>>> At least iirc, would have to double check
>>>>>>>
>>>>>> Ok.
>>>>>>
>>>>>> Thanks,
>>>>>> Armin Wolf
>>>>>>
>>>>>>>>
>>>>>>>>> +
>>>>>>>>>       { KE_END }
>>>>>>>>>   };
>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int 
>>>>>>>>> uniwill_notifier_call(struct notifier_block *nb, unsigned long 
>>>>>>>>> action
>>>>>>>>>           }
>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>> +        // noop for the time being
>>>>>>>>
>>>>>>>> Wrong comment style, please use /* */.
>>>>>>> ack
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Armin Wolf
>>>>>>>>
>>>>>>>>> +
>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>       default:
>>>>>>>>>           mutex_lock(&data->input_lock);
>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>>>>>> +
>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>     struct device;
>>>>>>>
>>>
>

[-- Attachment #2: 0001-platform-x86-uniwill-laptop-Introduce-device-descrip.patch --]
[-- Type: text/x-patch, Size: 8503 bytes --]

From 9c6385d2f2eb4d03faa922c39ab1deb01072e53a Mon Sep 17 00:00:00 2001
From: Armin Wolf <W_Armin@gmx.de>
Date: Mon, 17 Nov 2025 06:42:14 +0100
Subject: [PATCH] platform/x86: uniwill-laptop: Introduce device descriptor
 system

Future additions to the driver will depend on device-specific
initialization steps. Extend the DMI-based feature detection system
to include device descriptors. Each descriptor contains a bitmap of
supported features and a set of callback for performing
device-specific initialization.

Signed-off-by: Armin Wolf <W_Armin@gmx.de>
---
 drivers/platform/x86/uniwill/uniwill-acpi.c | 98 +++++++++++++++------
 1 file changed, 72 insertions(+), 26 deletions(-)

diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c b/drivers/platform/x86/uniwill/uniwill-acpi.c
index 014960d16211..8c5f8c2a1c5e 100644
--- a/drivers/platform/x86/uniwill/uniwill-acpi.c
+++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
@@ -341,12 +341,21 @@ struct uniwill_battery_entry {
 	struct power_supply *battery;
 };
 
+struct uniwill_device_descriptor {
+	unsigned int features;
+	/* Executed during driver probing */
+	int (*probe)(struct uniwill_data *data);
+};
+
 static bool force;
 module_param_unsafe(force, bool, 0);
 MODULE_PARM_DESC(force, "Force loading without checking for supported devices\n");
 
-/* Feature bitmask since the associated registers are not reliable */
-static unsigned int supported_features;
+/*
+ * Contains device specific data like the feature bitmap since
+ * the associated registers are not always reliable.
+ */
+static struct uniwill_device_descriptor device_descriptor __ro_after_init;
 
 static const char * const uniwill_temp_labels[] = {
 	"CPU",
@@ -398,6 +407,11 @@ static const struct key_entry uniwill_keymap[] = {
 	{ KE_END }
 };
 
+static inline bool uniwill_device_supports(unsigned long feature_mask)
+{
+	return device_descriptor.features & feature_mask;
+}
+
 static int uniwill_ec_reg_write(void *context, unsigned int reg, unsigned int val)
 {
 	union acpi_object params[2] = {
@@ -787,23 +801,23 @@ static struct attribute *uniwill_attrs[] = {
 static umode_t uniwill_attr_is_visible(struct kobject *kobj, struct attribute *attr, int n)
 {
 	if (attr == &dev_attr_fn_lock_toggle_enable.attr) {
-		if (supported_features & UNIWILL_FEATURE_FN_LOCK_TOGGLE)
+		if (uniwill_device_supports(UNIWILL_FEATURE_FN_LOCK_TOGGLE))
 			return attr->mode;
 	}
 
 	if (attr == &dev_attr_super_key_toggle_enable.attr) {
-		if (supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE)
+		if (uniwill_device_supports(UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
 			return attr->mode;
 	}
 
 	if (attr == &dev_attr_touchpad_toggle_enable.attr) {
-		if (supported_features & UNIWILL_FEATURE_TOUCHPAD_TOGGLE)
+		if (uniwill_device_supports(UNIWILL_FEATURE_TOUCHPAD_TOGGLE))
 			return attr->mode;
 	}
 
 	if (attr == &dev_attr_rainbow_animation.attr ||
 	    attr == &dev_attr_breathing_in_suspend.attr) {
-		if (supported_features & UNIWILL_FEATURE_LIGHTBAR)
+		if (uniwill_device_supports(UNIWILL_FEATURE_LIGHTBAR))
 			return attr->mode;
 	}
 
@@ -931,7 +945,7 @@ static int uniwill_hwmon_init(struct uniwill_data *data)
 {
 	struct device *hdev;
 
-	if (!(supported_features & UNIWILL_FEATURE_HWMON))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_HWMON))
 		return 0;
 
 	hdev = devm_hwmon_device_register_with_info(data->dev, "uniwill", data,
@@ -1006,7 +1020,7 @@ static int uniwill_led_init(struct uniwill_data *data)
 	unsigned int value;
 	int ret;
 
-	if (!(supported_features & UNIWILL_FEATURE_LIGHTBAR))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_LIGHTBAR))
 		return 0;
 
 	ret = devm_mutex_init(data->dev, &data->led_lock);
@@ -1219,7 +1233,7 @@ static int uniwill_battery_init(struct uniwill_data *data)
 {
 	int ret;
 
-	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_BATTERY))
 		return 0;
 
 	ret = devm_mutex_init(data->dev, &data->battery_lock);
@@ -1342,6 +1356,17 @@ static int uniwill_probe(struct platform_device *pdev)
 	if (ret < 0)
 		return ret;
 
+	/*
+	 * Some devices might need to perform some device-specific initialization steps
+	 * before the supported features are initialized. Because of this we have to call
+	 * this callback just after the EC itself was initialized.
+	 */
+	if (device_descriptor.probe) {
+		ret = device_descriptor.probe(data);
+		if (ret < 0)
+			return ret;
+	}
+
 	ret = uniwill_battery_init(data);
 	if (ret < 0)
 		return ret;
@@ -1366,7 +1391,7 @@ static void uniwill_shutdown(struct platform_device *pdev)
 
 static int uniwill_suspend_keyboard(struct uniwill_data *data)
 {
-	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
 		return 0;
 
 	/*
@@ -1378,7 +1403,7 @@ static int uniwill_suspend_keyboard(struct uniwill_data *data)
 
 static int uniwill_suspend_battery(struct uniwill_data *data)
 {
-	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_BATTERY))
 		return 0;
 
 	/*
@@ -1413,7 +1438,7 @@ static int uniwill_resume_keyboard(struct uniwill_data *data)
 	unsigned int value;
 	int ret;
 
-	if (!(supported_features & UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_SUPER_KEY_TOGGLE))
 		return 0;
 
 	ret = regmap_read(data->regmap, EC_ADDR_SWITCH_STATUS, &value);
@@ -1429,7 +1454,7 @@ static int uniwill_resume_keyboard(struct uniwill_data *data)
 
 static int uniwill_resume_battery(struct uniwill_data *data)
 {
-	if (!(supported_features & UNIWILL_FEATURE_BATTERY))
+	if (!uniwill_device_supports(UNIWILL_FEATURE_BATTERY))
 		return 0;
 
 	return regmap_update_bits(data->regmap, EC_ADDR_CHARGE_CTRL, CHARGE_CTRL_MASK,
@@ -1477,6 +1502,23 @@ static struct platform_driver uniwill_driver = {
 	.shutdown = uniwill_shutdown,
 };
 
+struct uniwill_device_descriptor lapac71h_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
+		    UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
+		    UNIWILL_FEATURE_BATTERY |
+		    UNIWILL_FEATURE_HWMON
+};
+
+struct uniwill_device_descriptor lapkc71f_descriptor __initdata = {
+	.features = UNIWILL_FEATURE_FN_LOCK_TOGGLE |
+		    UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
+		    UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
+		    UNIWILL_FEATURE_LIGHTBAR |
+		    UNIWILL_FEATURE_BATTERY |
+		    UNIWILL_FEATURE_HWMON
+};
+
 static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 	{
 		.ident = "Intel NUC x15",
@@ -1484,11 +1526,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPAC71H"),
 		},
-		.driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
-					UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
-					UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
-					UNIWILL_FEATURE_BATTERY |
-					UNIWILL_FEATURE_HWMON),
+		.driver_data = &lapac71h_descriptor,
 	},
 	{
 		.ident = "Intel NUC x15",
@@ -1496,12 +1534,7 @@ static const struct dmi_system_id uniwill_dmi_table[] __initconst = {
 			DMI_EXACT_MATCH(DMI_SYS_VENDOR, "Intel(R) Client Systems"),
 			DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "LAPKC71F"),
 		},
-		.driver_data = (void *)(UNIWILL_FEATURE_FN_LOCK_TOGGLE |
-					UNIWILL_FEATURE_SUPER_KEY_TOGGLE |
-					UNIWILL_FEATURE_TOUCHPAD_TOGGLE |
-					UNIWILL_FEATURE_LIGHTBAR |
-					UNIWILL_FEATURE_BATTERY |
-					UNIWILL_FEATURE_HWMON),
+		.driver_data = &lapkc71f_descriptor,
 	},
 	{ }
 };
@@ -1509,6 +1542,7 @@ MODULE_DEVICE_TABLE(dmi, uniwill_dmi_table);
 
 static int __init uniwill_init(void)
 {
+	const struct uniwill_device_descriptor *descriptor;
 	const struct dmi_system_id *id;
 	int ret;
 
@@ -1518,10 +1552,22 @@ static int __init uniwill_init(void)
 			return -ENODEV;
 
 		/* Assume that the device supports all features */
-		supported_features = UINT_MAX;
+		device_descriptor.features = UINT_MAX;
 		pr_warn("Loading on a potentially unsupported device\n");
 	} else {
-		supported_features = (uintptr_t)id->driver_data;
+		/*
+		 * Some devices might support additional features depending on
+		 * the BIOS version/date, so we call this callback to let them
+		 * modify their device descriptor accordingly.
+		 */
+		if (id->callback) {
+			ret = id->callback(id);
+			if (ret < 0)
+				return ret;
+		}
+
+		descriptor = id->driver_data;
+		device_descriptor = *descriptor;
 	}
 
 	ret = platform_driver_register(&uniwill_driver);
-- 
2.39.5


^ permalink raw reply related	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-19 15:34         ` Werner Sembach
@ 2025-11-20  1:16           ` Armin Wolf
  2025-11-20 10:47             ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-20  1:16 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 19.11.25 um 16:34 schrieb Werner Sembach:

>
> Am 18.11.25 um 14:29 schrieb Armin Wolf:
>> Am 18.11.25 um 13:58 schrieb Werner Sembach:
>>
>>>
>>> Am 18.11.25 um 12:12 schrieb Armin Wolf:
>>>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>>>
>>>>> Uniwill offers user setable cTGP for their EC on devices using 
>>>>> NVIDIA 3000
>>>>> Series and newer GPUs. This patch implements this setting as a sysfs
>>>>> attribute.
>>>>>
>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>> ---
>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 
>>>>> +++++++++++++++++++-
>>>>>   1 file changed, 107 insertions(+), 3 deletions(-)
>>>>>
>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> index 0cb86a701b2e1..de3417d9d1ac0 100644
>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>> @@ -122,11 +122,11 @@
>>>>>   #define CTGP_DB_DB_ENABLE        BIT(1)
>>>>>   #define CTGP_DB_CTGP_ENABLE        BIT(2)
>>>>>   -#define EC_ADDR_CTGP_OFFSET        0x0744
>>>>> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET    0x0744
>>>>>   -#define EC_ADDR_TPP_OFFSET        0x0745
>>>>> +#define EC_ADDR_CTGP_DB_TPP_OFFSET    0x0745
>>>>>   -#define EC_ADDR_MAX_TGP            0x0746
>>>>> +#define EC_ADDR_CTGP_DB_DB_OFFSET    0x0746
>>>>>     #define EC_ADDR_LIGHTBAR_AC_CTRL    0x0748
>>>>>   #define LIGHTBAR_APP_EXISTS        BIT(0)
>>>>> @@ -317,6 +317,7 @@
>>>>>   #define UNIWILL_FEATURE_LIGHTBAR        BIT(3)
>>>>>   #define UNIWILL_FEATURE_BATTERY            BIT(4)
>>>>>   #define UNIWILL_FEATURE_HWMON            BIT(5)
>>>>> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(6)
>>>>>     struct uniwill_data {
>>>>>       struct device *dev;
>>>>> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct 
>>>>> device *dev, unsigned int reg)
>>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>>           return true;
>>>>>       default:
>>>>>           return false;
>>>>> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct 
>>>>> device *dev, unsigned int reg)
>>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>>           return true;
>>>>>       default:
>>>>>           return false;
>>>>> @@ -786,6 +795,68 @@ static ssize_t 
>>>>> breathing_in_suspend_show(struct device *dev, struct device_attri
>>>>>     static DEVICE_ATTR_RW(breathing_in_suspend);
>>>>>   +static ssize_t ctgp_offset_store(struct device *dev, struct 
>>>>> device_attribute *attr,
>>>>> +                 const char *buf, size_t count)
>>>>> +{
>>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>>> +    unsigned int value;
>>>>> +    int ret;
>>>>> +
>>>>> +    ret = kstrtouint(buf, 0, &value);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 
>>>>> value);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    return count;
>>>>> +}
>>>>> +
>>>>> +static ssize_t ctgp_offset_show(struct device *dev, struct 
>>>>> device_attribute *attr,
>>>>> +                char *buf)
>>>>> +{
>>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>>> +    unsigned int value;
>>>>> +    int ret;
>>>>> +
>>>>> +    ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 
>>>>> &value);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    return sysfs_emit(buf, "%u\n", value);
>>>>> +}
>>>>> +
>>>>> +DEVICE_ATTR_RW(ctgp_offset);
>>>>> +
>>>>> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>>>>> +{
>>>>> +    int ret;
>>>>> +
>>>>> +    if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
>>>>> +        return 0;
>>>>> +
>>>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
>>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>>> CTGP_DB_CTGP_ENABLE,
>>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>>> CTGP_DB_CTGP_ENABLE);
>>>>
>>>> I think we should initialize the power limits before enabling them, 
>>>> otherwise
>>>> the relevant registers might still contain invalid data.
>>> from boot they are all just 0, but ofc i can shuffle things around
>>
>> Please do, i prefer to play it safe here as we are dealing with power 
>> limits.
>>
>>>>
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 
>>>>> 0);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 
>>>>> 255);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>
>>>> Are those values the maximum values supported by the platform? If 
>>>> yes then
>>>> we should enforce them for sysfs writes.
>>>>
>>>> Also, why is only cTGP accessible from user space?
>>>
>>> Because that is the only one that should be settable by the user 
>>> according to NVIDIA, the rest should be set by the ODM.
>>>
>>> EC_ADDR_CTGP_DB_TPP_OFFSET max value is just max u8 and would be 
>>> another way to cap cpu + gpu power but there are already other ways 
>>> to do that (e.g. the power profiles) so i don't see a value in 
>>> capping them here in any way.
>>>
>>> EC_ADDR_CTGP_DB_DB_OFFSET max value 25 is just the maximum value for 
>>> dynamic boost defined by NVIDIA, bigger values are just being 
>>> ignored (behave the same as having set 25): again the same story: 
>>> devices that don't support 25 W dynamic boost are already capped 
>>> elsewhere so i don't see value in capping it here.
>>>
>>> EC_ADDR_CTGP_DB_CTGP_OFFSET is the only one intented to be set by 
>>> the user, problem: the max value is different from device to device, 
>>> and i only know how to probe it using nvidia smi from userspace. 
>>> Good news: nothing bad happens when you set a higher value (same as 
>>> for dynamic boost)
>>>
>> I see, do you know the max. value for cTGP for the devices you added 
>> in patch 1? The intel notebooks use a similar
>> setup, but they limit the max. value of cTGP depending on the GPU 
>> module.
>>
>> I think that extending uniwill_data to contain a upper limit for cTGP 
>> would be nice for usability. We can use a default
>> value (U8_MAX) for devices where the upper limit is unknown. For 
>> devices where the limit is known, userspace application
>> can use the limit for showing it in the UI. Additionally i am 
>> planning to integrate cTGP into the platform profile, as it
>> is done on Intel machines. For this i will add the ability to define 
>> cTGP values for each platform profile, with the
>> max value being used for the upcoming max-power platform profile 
>> (also called "benchmark mode" on intel platforms).
>
> cTGP is a little bit complicated
>
> cTGP can be set between a Base TGP and a Max TGP (what you see here in 
> the driver is actually only the offset from the base TGP).
>
> The Dynamic Boost setting here give the max width of the dynamic boost 
> windows, however this is still affected by the max TGP.
>
> Say cTGP is 100W Max TGP is 115W and Dynamic Boost setting is 25W -> 
> The Dynamic Boost window is actually just 15W because it can't go over 
> Max TGP.
>
> Now setting the cTGP to 80W, the Dynamic Boost window becomes 25W and 
> the GPU will never clock above 105W.
>
> What does this mean? Setting cTGP between 80W and 90W actually changes 
> the overall power consumption, while setting it between 90W and 115W 
> does not, it just reduces the drivers automatic power allocation 
> window in favor of the gpu. -> At a certain point more cTGP does not 
> bring more performance, it actually can hurt performance for CPU heavy 
> tasks.
>
> In addition: Most Uniwill devies don't even have a window between Base 
> TGP and Max TGP that is bigger then the allowed Dynamic Boost window. 
> -> There is no power saving in setting cTGP on most Uniwill devices 
> and the "more performance" window of cTGP has a witdh of 0.
>
> And all Uniwill devices that i have seen have the GPU locked at a Watt 
> level below the Base TGP level on Battery. -> There is no battery 
> saving in setting cTGP on all Uniwill devices
>
Thank you for explaining the meaning of cTGP and dynamic boost for me. I would still like to mirror the behavior of the OEM software
regarding the integration of cTGP into the platform profile, however it is totally fine if not all devices enable this.

>>
>> To put it short please add an additional sysfs attribute (maybe 
>> called ctgp_offset_max?) add just return U8_MAX for now.
>> We can then add the individual limits for each device later if desired.
> I don't think a placeholder sysfs attribute that is not used by 
> anything is sensefull. I would wait with including it until it is 
> actually used.

Alright, fine. I will add this additional sysfs attribute when i upstream the cTGP handling for Intel notebooks.

>>
>> Thanks,
>> Armin Wolf
> On a different note, leaving the one device out that needs the qurik 
> callback, the patch should allready be usefull and ready?

Not really, you still need to rework the DMI table. I already sent you the patch with the device descriptor infrastructure, i am sure
that you can build the cTGP support atop of that.

Thanks,
Armin Wolf

>>
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>> +
>>>>> +    return 0;
>>>>> +}
>>>>> +
>>>>>   static struct attribute *uniwill_attrs[] = {
>>>>>       /* Keyboard-related */
>>>>>       &dev_attr_fn_lock_toggle_enable.attr,
>>>>> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>>>>>       /* Lightbar-related */
>>>>>       &dev_attr_rainbow_animation.attr,
>>>>>       &dev_attr_breathing_in_suspend.attr,
>>>>> +    /* Power-management-related */
>>>>> +    &dev_attr_ctgp_offset.attr,
>>>>>       NULL
>>>>>   };
>>>>>   @@ -820,6 +893,11 @@ static umode_t 
>>>>> uniwill_attr_is_visible(struct kobject *kobj, struct attribute *a
>>>>>               return attr->mode;
>>>>>       }
>>>>>   +    if (attr == &dev_attr_ctgp_offset.attr) {
>>>>> +        if (supported_features & 
>>>>> UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
>>>>> +            return attr->mode;
>>>>> +    }
>>>>> +
>>>>>       return 0;
>>>>>   }
>>>>>   @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct 
>>>>> platform_device *pdev)
>>>>>       if (ret < 0)
>>>>>           return ret;
>>>>>   +    ret = uniwill_nvidia_ctgp_init(data);
>>>>> +    if (ret < 0)
>>>>> +        return ret;
>>>>> +
>>>>>       return uniwill_input_init(data);
>>>>>   }
>>>>>   @@ -1547,6 +1629,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>>>>> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen7 
>>>>> Intel/Commodore Omnia-Book Pro Gen 7",
>>>>> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, 
>>>>> "PH6AG01_PH6AQ71_PH6AQI1"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 
>>>>> Intel/Commodore Omnia-Book Pro Gen 8",
>>>>> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>>>>> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>>>>> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>>>>> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>>>>> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>>>>> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>>>>> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>>>>> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>>>>> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>>>>> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore 
>>>>> ORION Gen 5",
>>>>> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>>>>> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore 
>>>>> ORION Slim 15 Gen6",
>>>>> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 
>>>>> 16 Gen6",
>>>>> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 
>>>>> 16 Gen6",
>>>>> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 
>>>>> 17 Gen6",
>>>>> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>>>>> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>>> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>>> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id 
>>>>> uniwill_dmi_table[] __initconst = {
>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>>>>           },
>>>>> +        .driver_data = (void 
>>>>> *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>       },
>>>>>       {
>>>>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",
>>>
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-20  0:53                   ` Armin Wolf
@ 2025-11-20 10:42                     ` Werner Sembach
  2025-11-20 13:40                       ` Armin Wolf
  2025-11-24 18:40                     ` Werner Sembach
  1 sibling, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-20 10:42 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 20.11.25 um 01:53 schrieb Armin Wolf:
> Am 18.11.25 um 16:05 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>>
>>>>>>
>>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>>
>>>>>>>>
>>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>>
>>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>>>>
>>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>>> ---
>>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h  | 2 ++
>>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>>
>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>>>         /* Reported in manual mode when toggling the airplane mode 
>>>>>>>>>> status */
>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>>>>
>>>>>>>>> I am currently working a patch adding platform profile support, so 
>>>>>>>>> this event would
>>>>>>>>> be handled inside the kernel on models with platform profile support.
>>>>>>>>
>>>>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>>>>> additional things. So we need a way to handle this in userspace.
>>>>>>>>
>>>>>>> Do these things have something to do with the uniwill EC? If so then we 
>>>>>>> should implement those inside the driver
>>>>>>> itself. The control center can then poll the platform profile sysfs file 
>>>>>>> to get notified when platform_profile_cycle()
>>>>>>> is executed to perform additional actions.
>>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>>
>>>>> And you cannot poll the sysfs interface?
>>>> I can't follow you atm?
>>>
>>> I meant to ask whether or not your application could poll the platform 
>>> profile sysfs interface for changes instead of
>>> listing for the F14 key.
>> But the platform profiles are a fixed number? TCC currently allows an 
>> arbitrary amount of profiles being created.
>
> With "poll the platform profile sysfs interface" i meant that you could use 
> poll() (https://linux.die.net/man/2/poll)
> or epoll() on the sysfs file containing the current platform profile.
Sorry i think i still don't completely get what you mean with platform profile. 
I assume you have a poc on github? If not can you give me a short overview?
>
> Anyway, i attached the patch with the device descriptor infrastructure. The 
> callback called during probe cannot modify
> the feature bitmap anymore, but i suggest that you simply set the limit for 
> cTGP to zero. The code responsible for
> initializing cTGP support can then check if the cTGP limit is zero and return 
> early.

I wonder if we should directly put that into a formal quirk list. Opinions?

Best regards,

Werner

>
> Thanks,
> Armin Wolf
>
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>>
>>>>>>>
>>>>>>>> The 2 things I can spontaneously think of would be a sysfs toggle or 2 
>>>>>>>> different UNIWILL_FEATURE_* defines.
>>>>>>>>
>>>>>>> TPH i would love to have an ordinary keycode allocated for that if the 
>>>>>>> above does not work for you. There already
>>>>>>> exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE 
>>>>>>> should be possible.
>>>>>>
>>>>>> New keycodes won't work on X11, I don't know the reason, but X11 only 
>>>>>> supports a max of 248 keycodes
>>>>>>
>>>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>>> .
>>>>>>
>>>>> Oh no. In this case using F14 is fine.
>>>>>
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>>>         /* Reported when the user wants to adjust the brightness of 
>>>>>>>>>> the keyboard */
>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>>>       /* Reported when the user wants to toggle the microphone mute 
>>>>>>>>>> status */
>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>>
>>>>>>>>> Why is this event being ignored?
>>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute key 
>>>>>>>> event, so not ignoring it here would result in a double trigger.
>>>>>>>
>>>>>>> I understand.
>>>>>>>
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>>         /* Reported when the user wants to toggle the brightness of 
>>>>>>>>>> the keyboard */
>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>> +    { KE_KEY,       UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
>>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>>>       /* Reported when the user wants to toggle the benchmark mode 
>>>>>>>>>> status */
>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>
>>>>>>>>> Same as above.
>>>>>>>>
>>>>>>>> Same as above ;)
>>>>>>>>
>>>>>>>> At least iirc, would have to double check
>>>>>>>>
>>>>>>> Ok.
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Armin Wolf
>>>>>>>
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>>       { KE_END }
>>>>>>>>>>   };
>>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>>>>>> notifier_block *nb, unsigned long action
>>>>>>>>>>           }
>>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>>> +        // noop for the time being
>>>>>>>>>
>>>>>>>>> Wrong comment style, please use /* */.
>>>>>>>> ack
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Armin Wolf
>>>>>>>>>
>>>>>>>>>> +
>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>       default:
>>>>>>>>>>           mutex_lock(&data->input_lock);
>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE        0xCF
>>>>>>>>>> +
>>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>>     struct device;
>>>>>>>>
>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting
  2025-11-20  1:16           ` Armin Wolf
@ 2025-11-20 10:47             ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-20 10:47 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 20.11.25 um 02:16 schrieb Armin Wolf:
> Am 19.11.25 um 16:34 schrieb Werner Sembach:
>
>>
>> Am 18.11.25 um 14:29 schrieb Armin Wolf:
>>> Am 18.11.25 um 13:58 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 18.11.25 um 12:12 schrieb Armin Wolf:
>>>>> Am 17.11.25 um 14:24 schrieb Werner Sembach:
>>>>>
>>>>>> Uniwill offers user setable cTGP for their EC on devices using NVIDIA 3000
>>>>>> Series and newer GPUs. This patch implements this setting as a sysfs
>>>>>> attribute.
>>>>>>
>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>> ---
>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 110 +++++++++++++++++++-
>>>>>>   1 file changed, 107 insertions(+), 3 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> index 0cb86a701b2e1..de3417d9d1ac0 100644
>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>> @@ -122,11 +122,11 @@
>>>>>>   #define CTGP_DB_DB_ENABLE        BIT(1)
>>>>>>   #define CTGP_DB_CTGP_ENABLE        BIT(2)
>>>>>>   -#define EC_ADDR_CTGP_OFFSET        0x0744
>>>>>> +#define EC_ADDR_CTGP_DB_CTGP_OFFSET    0x0744
>>>>>>   -#define EC_ADDR_TPP_OFFSET        0x0745
>>>>>> +#define EC_ADDR_CTGP_DB_TPP_OFFSET    0x0745
>>>>>>   -#define EC_ADDR_MAX_TGP            0x0746
>>>>>> +#define EC_ADDR_CTGP_DB_DB_OFFSET    0x0746
>>>>>>     #define EC_ADDR_LIGHTBAR_AC_CTRL    0x0748
>>>>>>   #define LIGHTBAR_APP_EXISTS        BIT(0)
>>>>>> @@ -317,6 +317,7 @@
>>>>>>   #define UNIWILL_FEATURE_LIGHTBAR        BIT(3)
>>>>>>   #define UNIWILL_FEATURE_BATTERY            BIT(4)
>>>>>>   #define UNIWILL_FEATURE_HWMON            BIT(5)
>>>>>> +#define UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL    BIT(6)
>>>>>>     struct uniwill_data {
>>>>>>       struct device *dev;
>>>>>> @@ -498,6 +499,10 @@ static bool uniwill_writeable_reg(struct device 
>>>>>> *dev, unsigned int reg)
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>>>           return true;
>>>>>>       default:
>>>>>>           return false;
>>>>>> @@ -531,6 +536,10 @@ static bool uniwill_readable_reg(struct device *dev, 
>>>>>> unsigned int reg)
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_RED:
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_GREEN:
>>>>>>       case EC_ADDR_LIGHTBAR_BAT_BLUE:
>>>>>> +    case EC_ADDR_CTGP_DB_CTRL:
>>>>>> +    case EC_ADDR_CTGP_DB_CTGP_OFFSET:
>>>>>> +    case EC_ADDR_CTGP_DB_TPP_OFFSET:
>>>>>> +    case EC_ADDR_CTGP_DB_DB_OFFSET:
>>>>>>           return true;
>>>>>>       default:
>>>>>>           return false;
>>>>>> @@ -786,6 +795,68 @@ static ssize_t breathing_in_suspend_show(struct 
>>>>>> device *dev, struct device_attri
>>>>>>     static DEVICE_ATTR_RW(breathing_in_suspend);
>>>>>>   +static ssize_t ctgp_offset_store(struct device *dev, struct 
>>>>>> device_attribute *attr,
>>>>>> +                 const char *buf, size_t count)
>>>>>> +{
>>>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>>>> +    unsigned int value;
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    ret = kstrtouint(buf, 0, &value);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, value);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    return count;
>>>>>> +}
>>>>>> +
>>>>>> +static ssize_t ctgp_offset_show(struct device *dev, struct 
>>>>>> device_attribute *attr,
>>>>>> +                char *buf)
>>>>>> +{
>>>>>> +    struct uniwill_data *data = dev_get_drvdata(dev);
>>>>>> +    unsigned int value;
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    ret = regmap_read(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, &value);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    return sysfs_emit(buf, "%u\n", value);
>>>>>> +}
>>>>>> +
>>>>>> +DEVICE_ATTR_RW(ctgp_offset);
>>>>>> +
>>>>>> +static int uniwill_nvidia_ctgp_init(struct uniwill_data *data)
>>>>>> +{
>>>>>> +    int ret;
>>>>>> +
>>>>>> +    if (!(supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL))
>>>>>> +        return 0;
>>>>>> +
>>>>>> +    ret = regmap_update_bits(data->regmap, EC_ADDR_CTGP_DB_CTRL,
>>>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>>>> CTGP_DB_CTGP_ENABLE,
>>>>>> +                 CTGP_DB_GENERAL_ENABLE | CTGP_DB_DB_ENABLE | 
>>>>>> CTGP_DB_CTGP_ENABLE);
>>>>>
>>>>> I think we should initialize the power limits before enabling them, otherwise
>>>>> the relevant registers might still contain invalid data.
>>>> from boot they are all just 0, but ofc i can shuffle things around
>>>
>>> Please do, i prefer to play it safe here as we are dealing with power limits.
>>>
>>>>>
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_CTGP_OFFSET, 0);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_TPP_OFFSET, 255);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>> +    ret = regmap_write(data->regmap, EC_ADDR_CTGP_DB_DB_OFFSET, 25);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>
>>>>> Are those values the maximum values supported by the platform? If yes then
>>>>> we should enforce them for sysfs writes.
>>>>>
>>>>> Also, why is only cTGP accessible from user space?
>>>>
>>>> Because that is the only one that should be settable by the user according 
>>>> to NVIDIA, the rest should be set by the ODM.
>>>>
>>>> EC_ADDR_CTGP_DB_TPP_OFFSET max value is just max u8 and would be another 
>>>> way to cap cpu + gpu power but there are already other ways to do that 
>>>> (e.g. the power profiles) so i don't see a value in capping them here in 
>>>> any way.
>>>>
>>>> EC_ADDR_CTGP_DB_DB_OFFSET max value 25 is just the maximum value for 
>>>> dynamic boost defined by NVIDIA, bigger values are just being ignored 
>>>> (behave the same as having set 25): again the same story: devices that 
>>>> don't support 25 W dynamic boost are already capped elsewhere so i don't 
>>>> see value in capping it here.
>>>>
>>>> EC_ADDR_CTGP_DB_CTGP_OFFSET is the only one intented to be set by the user, 
>>>> problem: the max value is different from device to device, and i only know 
>>>> how to probe it using nvidia smi from userspace. Good news: nothing bad 
>>>> happens when you set a higher value (same as for dynamic boost)
>>>>
>>> I see, do you know the max. value for cTGP for the devices you added in 
>>> patch 1? The intel notebooks use a similar
>>> setup, but they limit the max. value of cTGP depending on the GPU module.
>>>
>>> I think that extending uniwill_data to contain a upper limit for cTGP would 
>>> be nice for usability. We can use a default
>>> value (U8_MAX) for devices where the upper limit is unknown. For devices 
>>> where the limit is known, userspace application
>>> can use the limit for showing it in the UI. Additionally i am planning to 
>>> integrate cTGP into the platform profile, as it
>>> is done on Intel machines. For this i will add the ability to define cTGP 
>>> values for each platform profile, with the
>>> max value being used for the upcoming max-power platform profile (also 
>>> called "benchmark mode" on intel platforms).
>>
>> cTGP is a little bit complicated
>>
>> cTGP can be set between a Base TGP and a Max TGP (what you see here in the 
>> driver is actually only the offset from the base TGP).
>>
>> The Dynamic Boost setting here give the max width of the dynamic boost 
>> windows, however this is still affected by the max TGP.
>>
>> Say cTGP is 100W Max TGP is 115W and Dynamic Boost setting is 25W -> The 
>> Dynamic Boost window is actually just 15W because it can't go over Max TGP.
>>
>> Now setting the cTGP to 80W, the Dynamic Boost window becomes 25W and the GPU 
>> will never clock above 105W.
>>
>> What does this mean? Setting cTGP between 80W and 90W actually changes the 
>> overall power consumption, while setting it between 90W and 115W does not, it 
>> just reduces the drivers automatic power allocation window in favor of the 
>> gpu. -> At a certain point more cTGP does not bring more performance, it 
>> actually can hurt performance for CPU heavy tasks.
>>
>> In addition: Most Uniwill devies don't even have a window between Base TGP 
>> and Max TGP that is bigger then the allowed Dynamic Boost window. -> There is 
>> no power saving in setting cTGP on most Uniwill devices and the "more 
>> performance" window of cTGP has a witdh of 0.
>>
>> And all Uniwill devices that i have seen have the GPU locked at a Watt level 
>> below the Base TGP level on Battery. -> There is no battery saving in setting 
>> cTGP on all Uniwill devices
>>
> Thank you for explaining the meaning of cTGP and dynamic boost for me. I would 
> still like to mirror the behavior of the OEM software
> regarding the integration of cTGP into the platform profile, however it is 
> totally fine if not all devices enable this.

The intel oem software is different from the one of the other uniwill devices iirc.

The one we ship for windows has the cTGP slider completly seperate from the 
profiles iirc.

I still lean towards implementing all of this just in userspace.

>
>>>
>>> To put it short please add an additional sysfs attribute (maybe called 
>>> ctgp_offset_max?) add just return U8_MAX for now.
>>> We can then add the individual limits for each device later if desired.
>> I don't think a placeholder sysfs attribute that is not used by anything is 
>> sensefull. I would wait with including it until it is actually used.
>
> Alright, fine. I will add this additional sysfs attribute when i upstream the 
> cTGP handling for Intel notebooks.
>
>>>
>>> Thanks,
>>> Armin Wolf
>> On a different note, leaving the one device out that needs the qurik 
>> callback, the patch should allready be usefull and ready?
>
> Not really, you still need to rework the DMI table. I already sent you the 
> patch with the device descriptor infrastructure, i am sure
> that you can build the cTGP support atop of that.

I will look into it, thanks.

Best regards,

Werner

>
> Thanks,
> Armin Wolf
>
>>>
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>> +
>>>>>> +    return 0;
>>>>>> +}
>>>>>> +
>>>>>>   static struct attribute *uniwill_attrs[] = {
>>>>>>       /* Keyboard-related */
>>>>>>       &dev_attr_fn_lock_toggle_enable.attr,
>>>>>> @@ -794,6 +865,8 @@ static struct attribute *uniwill_attrs[] = {
>>>>>>       /* Lightbar-related */
>>>>>>       &dev_attr_rainbow_animation.attr,
>>>>>>       &dev_attr_breathing_in_suspend.attr,
>>>>>> +    /* Power-management-related */
>>>>>> +    &dev_attr_ctgp_offset.attr,
>>>>>>       NULL
>>>>>>   };
>>>>>>   @@ -820,6 +893,11 @@ static umode_t uniwill_attr_is_visible(struct 
>>>>>> kobject *kobj, struct attribute *a
>>>>>>               return attr->mode;
>>>>>>       }
>>>>>>   +    if (attr == &dev_attr_ctgp_offset.attr) {
>>>>>> +        if (supported_features & UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL)
>>>>>> +            return attr->mode;
>>>>>> +    }
>>>>>> +
>>>>>>       return 0;
>>>>>>   }
>>>>>>   @@ -1371,6 +1449,10 @@ static int uniwill_probe(struct platform_device 
>>>>>> *pdev)
>>>>>>       if (ret < 0)
>>>>>>           return ret;
>>>>>>   +    ret = uniwill_nvidia_ctgp_init(data);
>>>>>> +    if (ret < 0)
>>>>>> +        return ret;
>>>>>> +
>>>>>>       return uniwill_input_init(data);
>>>>>>   }
>>>>>>   @@ -1547,6 +1629,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxTQx1"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen7 Intel",
>>>>>> @@ -1554,6 +1637,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PHxARX1_PHxAQF1"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen7 Intel/Commodore 
>>>>>> Omnia-Book Pro Gen 7",
>>>>>> @@ -1561,6 +1645,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6AG01_PH6AQ71_PH6AQI1"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO InfinityBook Pro 14/16 Gen8 Intel/Commodore 
>>>>>> Omnia-Book Pro Gen 8",
>>>>>> @@ -1575,6 +1660,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH4PG31"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO InfinityBook Pro 16 Gen8 Intel",
>>>>>> @@ -1582,6 +1668,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "PH6PG01_PH6PG71"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO InfinityBook Pro 14/15 Gen9 AMD",
>>>>>> @@ -1694,6 +1781,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxMGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Polaris 15/17 Gen2 Intel",
>>>>>> @@ -1701,6 +1789,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxNGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 AMD",
>>>>>> @@ -1708,6 +1797,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxZGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen3 Intel",
>>>>>> @@ -1715,6 +1805,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxTGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris/Polaris 15/17 Gen4 AMD",
>>>>>> @@ -1722,6 +1813,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxRGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 15 Gen4 Intel",
>>>>>> @@ -1729,6 +1821,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxAGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Polaris 15/17 Gen5 AMD",
>>>>>> @@ -1736,6 +1829,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxXGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen5 AMD",
>>>>>> @@ -1743,6 +1837,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6XGxX"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16/17 Gen5 Intel/Commodore ORION Gen 
>>>>>> 5",
>>>>>> @@ -1750,6 +1845,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxPXxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 AMD",
>>>>>> @@ -1757,6 +1853,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GMxHGxx"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris Slim 15 Gen6 Intel/Commodore ORION 
>>>>>> Slim 15 Gen6",
>>>>>> @@ -1764,6 +1861,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM5IXxA"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>>>>>> @@ -1771,6 +1869,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB1"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen6 Intel/Commodore ORION 16 Gen6",
>>>>>> @@ -1778,6 +1877,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM6IXxB_MB2"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 17 Gen6 Intel/Commodore ORION 17 Gen6",
>>>>>> @@ -1785,6 +1885,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "GM7IXxN"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 AMD",
>>>>>> @@ -1792,6 +1893,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6FR5xxY"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>>>> @@ -1799,6 +1901,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Stellaris 16 Gen7 Intel",
>>>>>> @@ -1806,6 +1909,7 @@ static const struct dmi_system_id 
>>>>>> uniwill_dmi_table[] __initconst = {
>>>>>>               DMI_MATCH(DMI_SYS_VENDOR, "TUXEDO"),
>>>>>>               DMI_EXACT_MATCH(DMI_BOARD_NAME, "X6AR5xxY_mLED"),
>>>>>>           },
>>>>>> +        .driver_data = (void *)(UNIWILL_FEATURE_NVIDIA_CTGP_CONTROL),
>>>>>>       },
>>>>>>       {
>>>>>>           .ident = "TUXEDO Pulse 14 Gen1 AMD",
>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-20 10:42                     ` Werner Sembach
@ 2025-11-20 13:40                       ` Armin Wolf
  2025-11-20 22:06                         ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-20 13:40 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 20.11.25 um 11:42 schrieb Werner Sembach:

>
> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>> Am 18.11.25 um 16:05 schrieb Werner Sembach:
>>
>>>
>>> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>>>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>>>
>>>>>
>>>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>>>
>>>>>>>
>>>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>>>
>>>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO 
>>>>>>>>>>> devices.
>>>>>>>>>>>
>>>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>>>> ---
>>>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-acpi.c | 19 
>>>>>>>>>>> ++++++++++++++++++-
>>>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h | 2 ++
>>>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>>>
>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>         /* Reported in manual mode when toggling the 
>>>>>>>>>>> airplane mode status */
>>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>>>         /* Reported when user wants to cycle the platform 
>>>>>>>>>>> profile */
>>>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>> KEY_F14 }},
>>>>>>>>>>
>>>>>>>>>> I am currently working a patch adding platform profile 
>>>>>>>>>> support, so this event would
>>>>>>>>>> be handled inside the kernel on models with platform profile 
>>>>>>>>>> support.
>>>>>>>>>
>>>>>>>>> For tuxedo devices we have profiles managed in userspace that 
>>>>>>>>> do additional things. So we need a way to handle this in 
>>>>>>>>> userspace.
>>>>>>>>>
>>>>>>>> Do these things have something to do with the uniwill EC? If so 
>>>>>>>> then we should implement those inside the driver
>>>>>>>> itself. The control center can then poll the platform profile 
>>>>>>>> sysfs file to get notified when platform_profile_cycle()
>>>>>>>> is executed to perform additional actions.
>>>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>>>
>>>>>> And you cannot poll the sysfs interface?
>>>>> I can't follow you atm?
>>>>
>>>> I meant to ask whether or not your application could poll the 
>>>> platform profile sysfs interface for changes instead of
>>>> listing for the F14 key.
>>> But the platform profiles are a fixed number? TCC currently allows 
>>> an arbitrary amount of profiles being created.
>>
>> With "poll the platform profile sysfs interface" i meant that you 
>> could use poll() (https://linux.die.net/man/2/poll)
>> or epoll() on the sysfs file containing the current platform profile.
> Sorry i think i still don't completely get what you mean with platform 
> profile. I assume you have a poc on github? If not can you give me a 
> short overview?

Example code, might not work:

from select import poll, POLLPRI

fd = open("|/sys/firmware/acpi/platform_profile", "r") p = poll() 
p.register(fd.fileno(), POLLPRI) # Wait till platform profile changes 
p.poll() print("Platform profile changed") This however comes with the 
drawback that you cannot prevent the platform profile from cycling. If 
you want to do that manually depending on the settings inside your 
custom profiles, then maybe we can keep the F14 hack for now. I will 
then add a module option when adding platform profile support to select 
between platform_profile_cycle() and the F14 keycode. Does this sound OK?|

>>
>> Anyway, i attached the patch with the device descriptor 
>> infrastructure. The callback called during probe cannot modify
>> the feature bitmap anymore, but i suggest that you simply set the 
>> limit for cTGP to zero. The code responsible for
>> initializing cTGP support can then check if the cTGP limit is zero 
>> and return early.
>
> I wonder if we should directly put that into a formal quirk list. 
> Opinions?
>
> Best regards,
>
> Werner
>
The problem is that the quirk list will become RO before the driver can access the EC, so we have to use uniwill_data
for storing this information.

Thanks,
Armin Wolf

>>
>> Thanks,
>> Armin Wolf
>>
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>>>
>>>>>>>>
>>>>>>>>> The 2 things I can spontaneously think of would be a sysfs 
>>>>>>>>> toggle or 2 different UNIWILL_FEATURE_* defines.
>>>>>>>>>
>>>>>>>> TPH i would love to have an ordinary keycode allocated for that 
>>>>>>>> if the above does not work for you. There already
>>>>>>>> exists KEY_PERFORMANCE, so adding something like 
>>>>>>>> KEY_PERFORMANCE_CYCLE should be possible.
>>>>>>>
>>>>>>> New keycodes won't work on X11, I don't know the reason, but X11 
>>>>>>> only supports a max of 248 keycodes
>>>>>>>
>>>>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>>>> .
>>>>>>>
>>>>>> Oh no. In this case using F14 is fine.
>>>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Armin Wolf
>>>>>>
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>>         /* Reported when the user wants to adjust the 
>>>>>>>>>>> brightness of the keyboard */
>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN 
>>>>>>>>>>> }},
>>>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>       /* Reported when the user wants to toggle the 
>>>>>>>>>>> microphone mute status */
>>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>>>   +    /* Reported when the user wants to toggle the mute 
>>>>>>>>>>> status */
>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>>>
>>>>>>>>>> Why is this event being ignored?
>>>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the 
>>>>>>>>> mute key event, so not ignoring it here would result in a 
>>>>>>>>> double trigger.
>>>>>>>>
>>>>>>>> I understand.
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> +
>>>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>>>         /* Reported when the user wants to toggle the 
>>>>>>>>>>> brightness of the keyboard */
>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { 
>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry 
>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>       /* Reported when the user wants to toggle the 
>>>>>>>>>>> benchmark mode status */
>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>>
>>>>>>>>>> Same as above.
>>>>>>>>>
>>>>>>>>> Same as above ;)
>>>>>>>>>
>>>>>>>>> At least iirc, would have to double check
>>>>>>>>>
>>>>>>>> Ok.
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Armin Wolf
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> +
>>>>>>>>>>>       { KE_END }
>>>>>>>>>>>   };
>>>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int 
>>>>>>>>>>> uniwill_notifier_call(struct notifier_block *nb, unsigned 
>>>>>>>>>>> long action
>>>>>>>>>>>           }
>>>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>>>> +        // noop for the time being
>>>>>>>>>>
>>>>>>>>>> Wrong comment style, please use /* */.
>>>>>>>>> ack
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Armin Wolf
>>>>>>>>>>
>>>>>>>>>>> +
>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>       default:
>>>>>>>>>>> mutex_lock(&data->input_lock);
>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
>>>>>>>>>>> +
>>>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>>>     struct device;
>>>>>>>>>
>>>>>
>>>
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-20 13:40                       ` Armin Wolf
@ 2025-11-20 22:06                         ` Werner Sembach
  2025-11-22 23:54                           ` Armin Wolf
  0 siblings, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-20 22:06 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 20.11.25 um 14:40 schrieb Armin Wolf:
> Am 20.11.25 um 11:42 schrieb Werner Sembach:
>
>>
>> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>>> Am 18.11.25 um 16:05 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>>>>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>>>>
>>>>>>
>>>>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>>>>
>>>>>>>>
>>>>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>>>>
>>>>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>>>>>>
>>>>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>>>>> ---
>>>>>>>>>>>> drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>>>>>>>>>   drivers/platform/x86/uniwill/uniwill-wmi.h | 2 ++
>>>>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>>>>
>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry uniwill_keymap[] 
>>>>>>>>>>>> = {
>>>>>>>>>>>>         /* Reported in manual mode when toggling the airplane mode 
>>>>>>>>>>>> status */
>>>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>>>>>>
>>>>>>>>>>> I am currently working a patch adding platform profile support, so 
>>>>>>>>>>> this event would
>>>>>>>>>>> be handled inside the kernel on models with platform profile support.
>>>>>>>>>>
>>>>>>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>>>>>>> additional things. So we need a way to handle this in userspace.
>>>>>>>>>>
>>>>>>>>> Do these things have something to do with the uniwill EC? If so then 
>>>>>>>>> we should implement those inside the driver
>>>>>>>>> itself. The control center can then poll the platform profile sysfs 
>>>>>>>>> file to get notified when platform_profile_cycle()
>>>>>>>>> is executed to perform additional actions.
>>>>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>>>>
>>>>>>> And you cannot poll the sysfs interface?
>>>>>> I can't follow you atm?
>>>>>
>>>>> I meant to ask whether or not your application could poll the platform 
>>>>> profile sysfs interface for changes instead of
>>>>> listing for the F14 key.
>>>> But the platform profiles are a fixed number? TCC currently allows an 
>>>> arbitrary amount of profiles being created.
>>>
>>> With "poll the platform profile sysfs interface" i meant that you could use 
>>> poll() (https://linux.die.net/man/2/poll)
>>> or epoll() on the sysfs file containing the current platform profile.
>> Sorry i think i still don't completely get what you mean with platform 
>> profile. I assume you have a poc on github? If not can you give me a short 
>> overview?
>
> Example code, might not work:
>
> from select import poll, POLLPRI
>
> fd = open("|/sys/firmware/acpi/platform_profile", "r") p = poll() 
> p.register(fd.fileno(), POLLPRI) # Wait till platform profile changes p.poll() 
> print("Platform profile changed") This however comes with the drawback that 
> you cannot prevent the platform profile from cycling. If you want to do that 
> manually depending on the settings inside your custom profiles, then maybe we 
> can keep the F14 hack for now. I will then add a module option when adding 
> platform profile support to select between platform_profile_cycle() and the 
> F14 keycode. Does this sound OK?|

a sorry i was imprecise, i wanted to know the kernelspace implementation.

But let me sum up what i think you mean:

Platform profiles are in driver predefined profiles like: Power Save, Balanced, 
Performance, and Custom.

When you press the button you want to cycle through the profiles (except custom 
I guess?).

Only in Custom things like cTGP can be directly controlled by userspace via 
sysfs (otherwise the sysfs value is ignored?)


Maybe an elegant solution would be that upon boot for example "Balanced" is 
selected and when being in one of the predefined profiles the button cycles 
them. But once Custom get selected via sysfs the button starts sending a button 
press as the driver now expects everything to be handled by userspace. Bonus 
points if userspace can read out what the predefined profiles actually set to, 
for example, use that as initialization for custom profiles.

>
>>>
>>> Anyway, i attached the patch with the device descriptor infrastructure. The 
>>> callback called during probe cannot modify
>>> the feature bitmap anymore, but i suggest that you simply set the limit for 
>>> cTGP to zero. The code responsible for
>>> initializing cTGP support can then check if the cTGP limit is zero and 
>>> return early.
>>
>> I wonder if we should directly put that into a formal quirk list. Opinions?
>>
>> Best regards,
>>
>> Werner
>>
> The problem is that the quirk list will become RO before the driver can access 
> the EC, so we have to use uniwill_data
> for storing this information.
>
> Thanks,
> Armin Wolf
>
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>>>
>>>>>>>>>
>>>>>>>>>> The 2 things I can spontaneously think of would be a sysfs toggle or 
>>>>>>>>>> 2 different UNIWILL_FEATURE_* defines.
>>>>>>>>>>
>>>>>>>>> TPH i would love to have an ordinary keycode allocated for that if the 
>>>>>>>>> above does not work for you. There already
>>>>>>>>> exists KEY_PERFORMANCE, so adding something like KEY_PERFORMANCE_CYCLE 
>>>>>>>>> should be possible.
>>>>>>>>
>>>>>>>> New keycodes won't work on X11, I don't know the reason, but X11 only 
>>>>>>>> supports a max of 248 keycodes
>>>>>>>>
>>>>>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>>>>> .
>>>>>>>>
>>>>>>> Oh no. In this case using F14 is fine.
>>>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Armin Wolf
>>>>>>>
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>>         /* Reported when the user wants to adjust the brightness of 
>>>>>>>>>>>> the keyboard */
>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>       /* Reported when the user wants to toggle the microphone mute 
>>>>>>>>>>>> status */
>>>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>>>>
>>>>>>>>>>> Why is this event being ignored?
>>>>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute 
>>>>>>>>>> key event, so not ignoring it here would result in a double trigger.
>>>>>>>>>
>>>>>>>>> I understand.
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> +
>>>>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>>>>         /* Reported when the user wants to toggle the brightness of 
>>>>>>>>>>>> the keyboard */
>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { KEY_UNKNOWN }},
>>>>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry uniwill_keymap[] = {
>>>>>>>>>>>>       /* Reported when the user wants to toggle the benchmark mode 
>>>>>>>>>>>> status */
>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { KEY_UNKNOWN 
>>>>>>>>>>>> }},
>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>>>
>>>>>>>>>>> Same as above.
>>>>>>>>>>
>>>>>>>>>> Same as above ;)
>>>>>>>>>>
>>>>>>>>>> At least iirc, would have to double check
>>>>>>>>>>
>>>>>>>>> Ok.
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Armin Wolf
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> +
>>>>>>>>>>>>       { KE_END }
>>>>>>>>>>>>   };
>>>>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>>>>>>>> notifier_block *nb, unsigned long action
>>>>>>>>>>>>           }
>>>>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>>>>> +        // noop for the time being
>>>>>>>>>>>
>>>>>>>>>>> Wrong comment style, please use /* */.
>>>>>>>>>> ack
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Armin Wolf
>>>>>>>>>>>
>>>>>>>>>>>> +
>>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>>       default:
>>>>>>>>>>>> mutex_lock(&data->input_lock);
>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
>>>>>>>>>>>> +
>>>>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>>>>     struct device;
>>>>>>>>>>
>>>>>>
>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-20 22:06                         ` Werner Sembach
@ 2025-11-22 23:54                           ` Armin Wolf
  2025-11-24 17:43                             ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-22 23:54 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 20.11.25 um 23:06 schrieb Werner Sembach:

>
> Am 20.11.25 um 14:40 schrieb Armin Wolf:
>> Am 20.11.25 um 11:42 schrieb Werner Sembach:
>>
>>>
>>> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>>>> Am 18.11.25 um 16:05 schrieb Werner Sembach:
>>>>
>>>>>
>>>>> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>>>>>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>>>>>
>>>>>>>
>>>>>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>>>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>>>>>
>>>>>>>>>
>>>>>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>>>>>
>>>>>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO 
>>>>>>>>>>>>> devices.
>>>>>>>>>>>>>
>>>>>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>>>>>> ---
>>>>>>>>>>>>> drivers/platform/x86/uniwill/uniwill-acpi.c | 19 
>>>>>>>>>>>>> ++++++++++++++++++-
>>>>>>>>>>>>> drivers/platform/x86/uniwill/uniwill-wmi.h | 2 ++
>>>>>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>>>>>
>>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>         /* Reported in manual mode when toggling the 
>>>>>>>>>>>>> airplane mode status */
>>>>>>>>>>>>>       { KE_KEY,       UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>>>>>         /* Reported when user wants to cycle the platform 
>>>>>>>>>>>>> profile */
>>>>>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>>>> KEY_F14 }},
>>>>>>>>>>>>
>>>>>>>>>>>> I am currently working a patch adding platform profile 
>>>>>>>>>>>> support, so this event would
>>>>>>>>>>>> be handled inside the kernel on models with platform 
>>>>>>>>>>>> profile support.
>>>>>>>>>>>
>>>>>>>>>>> For tuxedo devices we have profiles managed in userspace 
>>>>>>>>>>> that do additional things. So we need a way to handle this 
>>>>>>>>>>> in userspace.
>>>>>>>>>>>
>>>>>>>>>> Do these things have something to do with the uniwill EC? If 
>>>>>>>>>> so then we should implement those inside the driver
>>>>>>>>>> itself. The control center can then poll the platform profile 
>>>>>>>>>> sysfs file to get notified when platform_profile_cycle()
>>>>>>>>>> is executed to perform additional actions.
>>>>>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>>>>>
>>>>>>>> And you cannot poll the sysfs interface?
>>>>>>> I can't follow you atm?
>>>>>>
>>>>>> I meant to ask whether or not your application could poll the 
>>>>>> platform profile sysfs interface for changes instead of
>>>>>> listing for the F14 key.
>>>>> But the platform profiles are a fixed number? TCC currently allows 
>>>>> an arbitrary amount of profiles being created.
>>>>
>>>> With "poll the platform profile sysfs interface" i meant that you 
>>>> could use poll() (https://linux.die.net/man/2/poll)
>>>> or epoll() on the sysfs file containing the current platform profile.
>>> Sorry i think i still don't completely get what you mean with 
>>> platform profile. I assume you have a poc on github? If not can you 
>>> give me a short overview?
>>
>> Example code, might not work:
>>
>> from select import poll, POLLPRI
>>
>> fd = open("|/sys/firmware/acpi/platform_profile", "r") p = poll() 
>> p.register(fd.fileno(), POLLPRI) # Wait till platform profile changes 
>> p.poll() print("Platform profile changed") This however comes with 
>> the drawback that you cannot prevent the platform profile from 
>> cycling. If you want to do that manually depending on the settings 
>> inside your custom profiles, then maybe we can keep the F14 hack for 
>> now. I will then add a module option when adding platform profile 
>> support to select between platform_profile_cycle() and the F14 
>> keycode. Does this sound OK?|
>
> a sorry i was imprecise, i wanted to know the kernelspace implementation.
>
Take a look at https://github.com/Wer-Wolf/uniwill-laptop/tree/platform_profile for the prototype.

The function platform_profile_cycle() is defined inside drivers/acpi/platform_profile.

> But let me sum up what i think you mean:
>
> Platform profiles are in driver predefined profiles like: Power Save, 
> Balanced, Performance, and Custom.
>
> When you press the button you want to cycle through the profiles 
> (except custom I guess?).
>
> Only in Custom things like cTGP can be directly controlled by 
> userspace via sysfs (otherwise the sysfs value is ignored?)
>
Correct.

> Maybe an elegant solution would be that upon boot for example 
> "Balanced" is selected and when being in one of the predefined 
> profiles the button cycles them. But once Custom get selected via 
> sysfs the button starts sending a button press as the driver now 
> expects everything to be handled by userspace. Bonus points if 
> userspace can read out what the predefined profiles actually set to, 
> for example, use that as initialization for custom profiles.
>
Agreed, i will implement this behavior once my testers give me feedback.

Thanks,
Armin Wolf

>>
>>>>
>>>> Anyway, i attached the patch with the device descriptor 
>>>> infrastructure. The callback called during probe cannot modify
>>>> the feature bitmap anymore, but i suggest that you simply set the 
>>>> limit for cTGP to zero. The code responsible for
>>>> initializing cTGP support can then check if the cTGP limit is zero 
>>>> and return early.
>>>
>>> I wonder if we should directly put that into a formal quirk list. 
>>> Opinions?
>>>
>>> Best regards,
>>>
>>> Werner
>>>
>> The problem is that the quirk list will become RO before the driver 
>> can access the EC, so we have to use uniwill_data
>> for storing this information.
>>
>> Thanks,
>> Armin Wolf
>>
>>>>
>>>> Thanks,
>>>> Armin Wolf
>>>>
>>>>>>
>>>>>> Thanks,
>>>>>> Armin Wolf
>>>>>>
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>> The 2 things I can spontaneously think of would be a sysfs 
>>>>>>>>>>> toggle or 2 different UNIWILL_FEATURE_* defines.
>>>>>>>>>>>
>>>>>>>>>> TPH i would love to have an ordinary keycode allocated for 
>>>>>>>>>> that if the above does not work for you. There already
>>>>>>>>>> exists KEY_PERFORMANCE, so adding something like 
>>>>>>>>>> KEY_PERFORMANCE_CYCLE should be possible.
>>>>>>>>>
>>>>>>>>> New keycodes won't work on X11, I don't know the reason, but 
>>>>>>>>> X11 only supports a max of 248 keycodes
>>>>>>>>>
>>>>>>>>> That's why for example touchpad toggle is bound to F21 e.g. 
>>>>>>>>> here 
>>>>>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>>>>>> .
>>>>>>>>>
>>>>>>>> Oh no. In this case using F14 is fine.
>>>>>>>>
>>>>>>>>
>>>>>>>> Thanks,
>>>>>>>> Armin Wolf
>>>>>>>>
>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>>         /* Reported when the user wants to adjust the 
>>>>>>>>>>>>> brightness of the keyboard */
>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { 
>>>>>>>>>>>>> KEY_KBDILLUMDOWN }},
>>>>>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>       /* Reported when the user wants to toggle the 
>>>>>>>>>>>>> microphone mute status */
>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the mute 
>>>>>>>>>>>>> status */
>>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>>>>>
>>>>>>>>>>>> Why is this event being ignored?
>>>>>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to 
>>>>>>>>>>> the mute key event, so not ignoring it here would result in 
>>>>>>>>>>> a double trigger.
>>>>>>>>>>
>>>>>>>>>> I understand.
>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> +
>>>>>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>>>>>       { KE_IGNORE,    UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>>>>>         /* Reported when the user wants to toggle the 
>>>>>>>>>>>>> brightness of the keyboard */
>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { 
>>>>>>>>>>>>> KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>         /* FIXME: find out the exact meaning of those 
>>>>>>>>>>>>> events */
>>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry 
>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>       /* Reported when the user wants to toggle the 
>>>>>>>>>>>>> benchmark mode status */
>>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the 
>>>>>>>>>>>>> webcam */
>>>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN 
>>>>>>>>>>>>> }},
>>>>>>>>>>>>
>>>>>>>>>>>> Same as above.
>>>>>>>>>>>
>>>>>>>>>>> Same as above ;)
>>>>>>>>>>>
>>>>>>>>>>> At least iirc, would have to double check
>>>>>>>>>>>
>>>>>>>>>> Ok.
>>>>>>>>>>
>>>>>>>>>> Thanks,
>>>>>>>>>> Armin Wolf
>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>>> +
>>>>>>>>>>>>>       { KE_END }
>>>>>>>>>>>>>   };
>>>>>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int 
>>>>>>>>>>>>> uniwill_notifier_call(struct notifier_block *nb, unsigned 
>>>>>>>>>>>>> long action
>>>>>>>>>>>>>           }
>>>>>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>>>>>> +        // noop for the time being
>>>>>>>>>>>>
>>>>>>>>>>>> Wrong comment style, please use /* */.
>>>>>>>>>>> ack
>>>>>>>>>>>>
>>>>>>>>>>>> Thanks,
>>>>>>>>>>>> Armin Wolf
>>>>>>>>>>>>
>>>>>>>>>>>>> +
>>>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>>>       default:
>>>>>>>>>>>>> mutex_lock(&data->input_lock);
>>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
>>>>>>>>>>>>> +
>>>>>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>>>>>     struct device;
>>>>>>>>>>>
>>>>>>>
>>>>>
>>>
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-22 23:54                           ` Armin Wolf
@ 2025-11-24 17:43                             ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-24 17:43 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 23.11.25 um 00:54 schrieb Armin Wolf:
> Am 20.11.25 um 23:06 schrieb Werner Sembach:
>
>>
>> Am 20.11.25 um 14:40 schrieb Armin Wolf:
>>> Am 20.11.25 um 11:42 schrieb Werner Sembach:
>>>
>>>>
>>>> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>>>>> Am 18.11.25 um 16:05 schrieb Werner Sembach:
>>>>>
>>>>>>
>>>>>> Am 18.11.25 um 15:41 schrieb Armin Wolf:
>>>>>>> Am 18.11.25 um 15:27 schrieb Werner Sembach:
>>>>>>>
>>>>>>>>
>>>>>>>> Am 18.11.25 um 14:48 schrieb Armin Wolf:
>>>>>>>>> Am 18.11.25 um 14:29 schrieb Werner Sembach:
>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> Am 18.11.25 um 14:12 schrieb Armin Wolf:
>>>>>>>>>>> Am 18.11.25 um 13:45 schrieb Werner Sembach:
>>>>>>>>>>>
>>>>>>>>>>>>
>>>>>>>>>>>> Am 18.11.25 um 12:08 schrieb Armin Wolf:
>>>>>>>>>>>>> Am 17.11.25 um 14:23 schrieb Werner Sembach:
>>>>>>>>>>>>>
>>>>>>>>>>>>>> Handle some more WMI events that are triggered on TUXEDO devices.
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> Signed-off-by: Werner Sembach <wse@tuxedocomputers.com>
>>>>>>>>>>>>>> ---
>>>>>>>>>>>>>> drivers/platform/x86/uniwill/uniwill-acpi.c | 19 ++++++++++++++++++-
>>>>>>>>>>>>>> drivers/platform/x86/uniwill/uniwill-wmi.h | 2 ++
>>>>>>>>>>>>>>   2 files changed, 20 insertions(+), 1 deletion(-)
>>>>>>>>>>>>>>
>>>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-acpi.c 
>>>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>>> index 29bb3709bfcc8..0cb86a701b2e1 100644
>>>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-acpi.c
>>>>>>>>>>>>>> @@ -371,9 +371,11 @@ static const struct key_entry 
>>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>>         /* Reported in manual mode when toggling the airplane 
>>>>>>>>>>>>>> mode status */
>>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_RFKILL, { KEY_RFKILL }},
>>>>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_RADIOON, { KEY_UNKNOWN }},
>>>>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_RADIOOFF, { KEY_UNKNOWN }},
>>>>>>>>>>>>>>         /* Reported when user wants to cycle the platform profile */
>>>>>>>>>>>>>> -    { KE_IGNORE, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { 
>>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_PERFORMANCE_MODE_TOGGLE, { KEY_F14 }},
>>>>>>>>>>>>>
>>>>>>>>>>>>> I am currently working a patch adding platform profile support, so 
>>>>>>>>>>>>> this event would
>>>>>>>>>>>>> be handled inside the kernel on models with platform profile support.
>>>>>>>>>>>>
>>>>>>>>>>>> For tuxedo devices we have profiles managed in userspace that do 
>>>>>>>>>>>> additional things. So we need a way to handle this in userspace.
>>>>>>>>>>>>
>>>>>>>>>>> Do these things have something to do with the uniwill EC? If so then 
>>>>>>>>>>> we should implement those inside the driver
>>>>>>>>>>> itself. The control center can then poll the platform profile sysfs 
>>>>>>>>>>> file to get notified when platform_profile_cycle()
>>>>>>>>>>> is executed to perform additional actions.
>>>>>>>>>> Not exclusively, e.g. one thing is display brightness.
>>>>>>>>>
>>>>>>>>> And you cannot poll the sysfs interface?
>>>>>>>> I can't follow you atm?
>>>>>>>
>>>>>>> I meant to ask whether or not your application could poll the platform 
>>>>>>> profile sysfs interface for changes instead of
>>>>>>> listing for the F14 key.
>>>>>> But the platform profiles are a fixed number? TCC currently allows an 
>>>>>> arbitrary amount of profiles being created.
>>>>>
>>>>> With "poll the platform profile sysfs interface" i meant that you could 
>>>>> use poll() (https://linux.die.net/man/2/poll)
>>>>> or epoll() on the sysfs file containing the current platform profile.
>>>> Sorry i think i still don't completely get what you mean with platform 
>>>> profile. I assume you have a poc on github? If not can you give me a short 
>>>> overview?
>>>
>>> Example code, might not work:
>>>
>>> from select import poll, POLLPRI
>>>
>>> fd = open("|/sys/firmware/acpi/platform_profile", "r") p = poll() 
>>> p.register(fd.fileno(), POLLPRI) # Wait till platform profile changes 
>>> p.poll() print("Platform profile changed") This however comes with the 
>>> drawback that you cannot prevent the platform profile from cycling. If you 
>>> want to do that manually depending on the settings inside your custom 
>>> profiles, then maybe we can keep the F14 hack for now. I will then add a 
>>> module option when adding platform profile support to select between 
>>> platform_profile_cycle() and the F14 keycode. Does this sound OK?|
>>
>> a sorry i was imprecise, i wanted to know the kernelspace implementation.
>>
> Take a look at 
> https://github.com/Wer-Wolf/uniwill-laptop/tree/platform_profile for the 
> prototype.
thanks
>
> The function platform_profile_cycle() is defined inside 
> drivers/acpi/platform_profile.
>
>> But let me sum up what i think you mean:
>>
>> Platform profiles are in driver predefined profiles like: Power Save, 
>> Balanced, Performance, and Custom.
>>
>> When you press the button you want to cycle through the profiles (except 
>> custom I guess?).
>>
>> Only in Custom things like cTGP can be directly controlled by userspace via 
>> sysfs (otherwise the sysfs value is ignored?)
>>
> Correct.
>
>> Maybe an elegant solution would be that upon boot for example "Balanced" is 
>> selected and when being in one of the predefined profiles the button cycles 
>> them. But once Custom get selected via sysfs the button starts sending a 
>> button press as the driver now expects everything to be handled by userspace. 
>> Bonus points if userspace can read out what the predefined profiles actually 
>> set to, for example, use that as initialization for custom profiles.
>>
> Agreed, i will implement this behavior once my testers give me feedback.
thanks
>
> Thanks,
> Armin Wolf
>
>>>
>>>>>
>>>>> Anyway, i attached the patch with the device descriptor infrastructure. 
>>>>> The callback called during probe cannot modify
>>>>> the feature bitmap anymore, but i suggest that you simply set the limit 
>>>>> for cTGP to zero. The code responsible for
>>>>> initializing cTGP support can then check if the cTGP limit is zero and 
>>>>> return early.
>>>>
>>>> I wonder if we should directly put that into a formal quirk list. Opinions?
>>>>
>>>> Best regards,
>>>>
>>>> Werner
>>>>
>>> The problem is that the quirk list will become RO before the driver can 
>>> access the EC, so we have to use uniwill_data
>>> for storing this information.
>>>
>>> Thanks,
>>> Armin Wolf
>>>
>>>>>
>>>>> Thanks,
>>>>> Armin Wolf
>>>>>
>>>>>>>
>>>>>>> Thanks,
>>>>>>> Armin Wolf
>>>>>>>
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>> The 2 things I can spontaneously think of would be a sysfs toggle 
>>>>>>>>>>>> or 2 different UNIWILL_FEATURE_* defines.
>>>>>>>>>>>>
>>>>>>>>>>> TPH i would love to have an ordinary keycode allocated for that if 
>>>>>>>>>>> the above does not work for you. There already
>>>>>>>>>>> exists KEY_PERFORMANCE, so adding something like 
>>>>>>>>>>> KEY_PERFORMANCE_CYCLE should be possible.
>>>>>>>>>>
>>>>>>>>>> New keycodes won't work on X11, I don't know the reason, but X11 only 
>>>>>>>>>> supports a max of 248 keycodes
>>>>>>>>>>
>>>>>>>>>> That's why for example touchpad toggle is bound to F21 e.g. here 
>>>>>>>>>> https://elixir.bootlin.com/linux/v6.17.8/source/drivers/platform/x86/lg-laptop.c#L106 
>>>>>>>>>> .
>>>>>>>>>>
>>>>>>>>> Oh no. In this case using F14 is fine.
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> Thanks,
>>>>>>>>> Armin Wolf
>>>>>>>>>
>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>>         /* Reported when the user wants to adjust the brightness 
>>>>>>>>>>>>>> of the keyboard */
>>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMDOWN, { KEY_KBDILLUMDOWN }},
>>>>>>>>>>>>>> @@ -382,11 +384,19 @@ static const struct key_entry 
>>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>>       /* Reported when the user wants to toggle the microphone 
>>>>>>>>>>>>>> mute status */
>>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_MIC_MUTE, { KEY_MICMUTE }},
>>>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the mute status */
>>>>>>>>>>>>>> +    { KE_IGNORE,    UNIWILL_OSD_MUTE, { KEY_MUTE }},
>>>>>>>>>>>>>
>>>>>>>>>>>>> Why is this event being ignored?
>>>>>>>>>>>> Because the UNIWILL_OSD_MUTE event is sent in addition to the mute 
>>>>>>>>>>>> key event, so not ignoring it here would result in a double trigger.
>>>>>>>>>>>
>>>>>>>>>>> I understand.
>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>       /* Reported when the user locks/unlocks the Fn key */
>>>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_FN_LOCK, { KEY_FN_ESC }},
>>>>>>>>>>>>>>         /* Reported when the user wants to toggle the brightness 
>>>>>>>>>>>>>> of the keyboard */
>>>>>>>>>>>>>>       { KE_KEY, UNIWILL_OSD_KBDILLUMTOGGLE, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL0, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL1, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL2, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL3, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>> +    { KE_KEY, UNIWILL_OSD_KB_LED_LEVEL4, { KEY_KBDILLUMTOGGLE }},
>>>>>>>>>>>>>>         /* FIXME: find out the exact meaning of those events */
>>>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BAT_CHARGE_FULL_24_H, { 
>>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>>> @@ -395,6 +405,9 @@ static const struct key_entry 
>>>>>>>>>>>>>> uniwill_keymap[] = {
>>>>>>>>>>>>>>       /* Reported when the user wants to toggle the benchmark 
>>>>>>>>>>>>>> mode status */
>>>>>>>>>>>>>>       { KE_IGNORE, UNIWILL_OSD_BENCHMARK_MODE_TOGGLE, { 
>>>>>>>>>>>>>> KEY_UNKNOWN }},
>>>>>>>>>>>>>>   +    /* Reported when the user wants to toggle the webcam */
>>>>>>>>>>>>>> +    { KE_IGNORE, UNIWILL_OSD_WEBCAM_TOGGLE, { KEY_UNKNOWN }},
>>>>>>>>>>>>>
>>>>>>>>>>>>> Same as above.
>>>>>>>>>>>>
>>>>>>>>>>>> Same as above ;)
>>>>>>>>>>>>
>>>>>>>>>>>> At least iirc, would have to double check
>>>>>>>>>>>>
>>>>>>>>>>> Ok.
>>>>>>>>>>>
>>>>>>>>>>> Thanks,
>>>>>>>>>>> Armin Wolf
>>>>>>>>>>>
>>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>       { KE_END }
>>>>>>>>>>>>>>   };
>>>>>>>>>>>>>>   @@ -1247,6 +1260,10 @@ static int uniwill_notifier_call(struct 
>>>>>>>>>>>>>> notifier_block *nb, unsigned long action
>>>>>>>>>>>>>>           }
>>>>>>>>>>>>>> mutex_unlock(&data->battery_lock);
>>>>>>>>>>>>>>   +        return NOTIFY_OK;
>>>>>>>>>>>>>> +    case UNIWILL_OSD_DC_ADAPTER_CHANGED:
>>>>>>>>>>>>>> +        // noop for the time being
>>>>>>>>>>>>>
>>>>>>>>>>>>> Wrong comment style, please use /* */.
>>>>>>>>>>>> ack
>>>>>>>>>>>>>
>>>>>>>>>>>>> Thanks,
>>>>>>>>>>>>> Armin Wolf
>>>>>>>>>>>>>
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>           return NOTIFY_OK;
>>>>>>>>>>>>>>       default:
>>>>>>>>>>>>>> mutex_lock(&data->input_lock);
>>>>>>>>>>>>>> diff --git a/drivers/platform/x86/uniwill/uniwill-wmi.h 
>>>>>>>>>>>>>> b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>>> index 2bf69f2d80381..48783b2e9ffb9 100644
>>>>>>>>>>>>>> --- a/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>>> +++ b/drivers/platform/x86/uniwill/uniwill-wmi.h
>>>>>>>>>>>>>> @@ -113,6 +113,8 @@
>>>>>>>>>>>>>>     #define UNIWILL_OSD_BENCHMARK_MODE_TOGGLE 0xC0
>>>>>>>>>>>>>>   +#define UNIWILL_OSD_WEBCAM_TOGGLE 0xCF
>>>>>>>>>>>>>> +
>>>>>>>>>>>>>>   #define UNIWILL_OSD_KBD_BACKLIGHT_CHANGED 0xF0
>>>>>>>>>>>>>>     struct device;
>>>>>>>>>>>>
>>>>>>>>
>>>>>>
>>>>
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-20  0:53                   ` Armin Wolf
  2025-11-20 10:42                     ` Werner Sembach
@ 2025-11-24 18:40                     ` Werner Sembach
  2025-11-25  0:50                       ` Armin Wolf
  1 sibling, 1 reply; 43+ messages in thread
From: Werner Sembach @ 2025-11-24 18:40 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Hi

Am 20.11.25 um 01:53 schrieb Armin Wolf:
> [snip]
>
> Anyway, i attached the patch with the device descriptor infrastructure. The 
> callback called during probe cannot modify
> the feature bitmap anymore, but i suggest that you simply set the limit for 
> cTGP to zero. The code responsible for
> initializing cTGP support can then check if the cTGP limit is zero and return 
> early. 

Looked into it: whats the reason for the "__ro_after_init" in "static struct 
uniwill_device_descriptor device_descriptor __ro_after_init;"?

The thing Ilpo wrote sounded like just .driver_data itself should be read only, 
but as soon as it has an indirection, like here being copied over to a static 
variable, read/write is ok.

Also: Why not just copy the device_descriptor over to uniwill_data instead of a 
static variable?

And do I get that correctly: All you can do during the init callback is doing 
more sophisticated DMI matching?

Best regards,

Werner

> [snip]

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-24 18:40                     ` Werner Sembach
@ 2025-11-25  0:50                       ` Armin Wolf
  2025-11-25 14:05                         ` Werner Sembach
  0 siblings, 1 reply; 43+ messages in thread
From: Armin Wolf @ 2025-11-25  0:50 UTC (permalink / raw)
  To: Werner Sembach, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel

Am 24.11.25 um 19:40 schrieb Werner Sembach:

> Hi
>
> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>> [snip]
>>
>> Anyway, i attached the patch with the device descriptor 
>> infrastructure. The callback called during probe cannot modify
>> the feature bitmap anymore, but i suggest that you simply set the 
>> limit for cTGP to zero. The code responsible for
>> initializing cTGP support can then check if the cTGP limit is zero 
>> and return early. 
>
> Looked into it: whats the reason for the "__ro_after_init" in "static 
> struct uniwill_device_descriptor device_descriptor __ro_after_init;"?
>
__ro_after_init tells the kernel to mark the variables annotated with it as read-only after module initialization has finished.
I used it to ensure that the static device configuration data cannot be (accidentally) modified after module initialization.

> The thing Ilpo wrote sounded like just .driver_data itself should be 
> read only, but as soon as it has an indirection, like here being 
> copied over to a static variable, read/write is ok.

No, the device descriptor needs to be treated as read-only because, theoretically, multiple instances of the uniwill-laptop driver might probe.
If one of those instances modifies the descriptor, the other instances might run into trouble.

I suggest that in order to dynamically modify the supported_features bitmap, you simply copy said variable from the descriptor
into uniwill_data and then use the probe() callback to modify it.

>
> Also: Why not just copy the device_descriptor over to uniwill_data 
> instead of a static variable?

uniwill_data is not available during module initialization, so we have store it separately.

>
> And do I get that correctly: All you can do during the init callback 
> is doing more sophisticated DMI matching?
>
Inside the callback provided dmi_system_id, you indeed can only do more sophisticated DMI matching. You should
use the probe() callback inside the descriptor to perform device-specific initialization that requires access
to the EC and/or uniwill_data.

Thanks,
Armin Wolf

> Best regards,
>
> Werner
>
>> [snip]
>

^ permalink raw reply	[flat|nested] 43+ messages in thread

* Re: [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for TUXEDO devices
  2025-11-25  0:50                       ` Armin Wolf
@ 2025-11-25 14:05                         ` Werner Sembach
  0 siblings, 0 replies; 43+ messages in thread
From: Werner Sembach @ 2025-11-25 14:05 UTC (permalink / raw)
  To: Armin Wolf, hansg, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel


Am 25.11.25 um 01:50 schrieb Armin Wolf:
> Am 24.11.25 um 19:40 schrieb Werner Sembach:
>
>> Hi
>>
>> Am 20.11.25 um 01:53 schrieb Armin Wolf:
>>> [snip]
>>>
>>> Anyway, i attached the patch with the device descriptor infrastructure. The 
>>> callback called during probe cannot modify
>>> the feature bitmap anymore, but i suggest that you simply set the limit for 
>>> cTGP to zero. The code responsible for
>>> initializing cTGP support can then check if the cTGP limit is zero and 
>>> return early. 
>>
>> Looked into it: whats the reason for the "__ro_after_init" in "static struct 
>> uniwill_device_descriptor device_descriptor __ro_after_init;"?
>>
> __ro_after_init tells the kernel to mark the variables annotated with it as 
> read-only after module initialization has finished.
> I used it to ensure that the static device configuration data cannot be 
> (accidentally) modified after module initialization.
Hope it's ok that in my rfc the copy in driver data is no longer read only, but 
is outside of the probe only accessed via a getter method.
>
>> The thing Ilpo wrote sounded like just .driver_data itself should be read 
>> only, but as soon as it has an indirection, like here being copied over to a 
>> static variable, read/write is ok.
>
> No, the device descriptor needs to be treated as read-only because, 
> theoretically, multiple instances of the uniwill-laptop driver might probe.
> If one of those instances modifies the descriptor, the other instances might 
> run into trouble.
Every instance in my RFC has now it's own copy of the feature bitmap.
>
> I suggest that in order to dynamically modify the supported_features bitmap, 
> you simply copy said variable from the descriptor
> into uniwill_data and then use the probe() callback to modify it.
Yes, I did that.
>
>>
>> Also: Why not just copy the device_descriptor over to uniwill_data instead of 
>> a static variable?
>
> uniwill_data is not available during module initialization, so we have store 
> it separately.
sorry I'm stupid xD
>
>>
>> And do I get that correctly: All you can do during the init callback is doing 
>> more sophisticated DMI matching?
>>
> Inside the callback provided dmi_system_id, you indeed can only do more 
> sophisticated DMI matching. You should
> use the probe() callback inside the descriptor to perform device-specific 
> initialization that requires access
> to the EC and/or uniwill_data.

I sent a RFC based on your PoC patch, I would suggest moving the discussion 
thread there.

Thanks so far for your PoC/WIP patch

Best regards

Werner

>
> Thanks,
> Armin Wolf
>
>> Best regards,
>>
>> Werner
>>
>>> [snip]
>>

^ permalink raw reply	[flat|nested] 43+ messages in thread

end of thread, other threads:[~2025-11-25 14:05 UTC | newest]

Thread overview: 43+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-11-17 13:23 [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Werner Sembach
2025-11-17 13:23 ` [PATCH 1/6] platform/x86/uniwill: Add TUXEDO devices Werner Sembach
2025-11-18 11:03   ` Armin Wolf
2025-11-17 13:23 ` [PATCH 2/6] platform/x86/uniwill: Handle more WMI events required for " Werner Sembach
2025-11-18 11:08   ` Armin Wolf
2025-11-18 12:45     ` Werner Sembach
2025-11-18 13:12       ` Armin Wolf
2025-11-18 13:29         ` Werner Sembach
2025-11-18 13:48           ` Armin Wolf
2025-11-18 14:27             ` Werner Sembach
2025-11-18 14:41               ` Armin Wolf
2025-11-18 15:05                 ` Werner Sembach
2025-11-20  0:53                   ` Armin Wolf
2025-11-20 10:42                     ` Werner Sembach
2025-11-20 13:40                       ` Armin Wolf
2025-11-20 22:06                         ` Werner Sembach
2025-11-22 23:54                           ` Armin Wolf
2025-11-24 17:43                             ` Werner Sembach
2025-11-24 18:40                     ` Werner Sembach
2025-11-25  0:50                       ` Armin Wolf
2025-11-25 14:05                         ` Werner Sembach
2025-11-17 13:24 ` [PATCH 3/6] platform/x86/uniwill: Implement cTGP setting Werner Sembach
2025-11-18 11:12   ` Armin Wolf
2025-11-18 12:58     ` Werner Sembach
2025-11-18 13:29       ` Armin Wolf
2025-11-19 15:34         ` Werner Sembach
2025-11-20  1:16           ` Armin Wolf
2025-11-20 10:47             ` Werner Sembach
2025-11-17 13:24 ` [PATCH 4/6] platform/x86/uniwill: Make uniwill_dmi_table accessible in probe Werner Sembach
2025-11-18 11:16   ` Armin Wolf
2025-11-18 13:01     ` Werner Sembach
2025-11-18 13:35       ` Armin Wolf
2025-11-18 13:40         ` Werner Sembach
2025-11-17 13:24 ` [PATCH 5/6] platform/x86/uniwill: Run callbacks of uniwill_dmi_table Werner Sembach
2025-11-17 13:24 ` [PATCH 6/6] platform/x86/uniwill: Set cTGP support based on EC for TUXEDO IBP Gen7 MK1 Werner Sembach
2025-11-18 10:43   ` Ilpo Järvinen
2025-11-18 13:05     ` Werner Sembach
2025-11-18 11:31 ` [PATCH 0/6] Start of Upstream Support for TUXEDO NB02 devices Armin Wolf
2025-11-18 13:17   ` Werner Sembach
2025-11-18 13:42     ` Armin Wolf
2025-11-18 14:24       ` Werner Sembach
2025-11-18 13:42   ` Werner Sembach
2025-11-18 13:43     ` Armin Wolf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox