From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-ot1-f47.google.com (mail-ot1-f47.google.com [209.85.210.47]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3B1C619CCF5 for ; Mon, 13 Oct 2025 19:13:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.47 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760382784; cv=none; b=cg1F46M39Gi5ScINyQn1tKHItaaQJx+ro5NBrjSDe5pkU2VUUqlyCOeBBaVAOgBI/Pb5qwlikyQkeAejfCKEepntGW7CrOZ5mlAI82624ACxTgaog3zO65fayvkvq046UCr2EjEjcLq5QkEWFF2WPAUQ+OUj/FHNBXw659ce8E8= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1760382784; c=relaxed/simple; bh=eT/WInPZZdkBcllihWWXxa6Q1ZlSZIYL2/gZCJVsOIo=; h=Message-ID:Date:MIME-Version:Subject:To:Cc:References:From: In-Reply-To:Content-Type; b=JJHFp1lq7AdE4BuTnLyVkPCJIsEyT+qkxAU9s9N0cl4jEMBUMf678UsfrkeBPVsNeBPGFeksuPdz9H8Qgce9iMMdlbxIHCqMil2GgJ3mIEseF0UNCxovH+RDHF7vBAA5XTFvk3IMzI3gJ5KOAFPUJxv5wwSVN6Kebdxd9hRvQMA= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=BZMN2sE1; arc=none smtp.client-ip=209.85.210.47 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="BZMN2sE1" Received: by mail-ot1-f47.google.com with SMTP id 46e09a7af769-7bd8909c682so3045806a34.3 for ; Mon, 13 Oct 2025 12:13:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1760382779; x=1760987579; darn=vger.kernel.org; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :from:to:cc:subject:date:message-id:reply-to; bh=78jY7yI9EEPM0HaRkplFkOHEcPOXrpB7WK7QZGIoaAk=; b=BZMN2sE1hMCe68aW3ErUl8dlfFq2g6hxAq6EHSzrJ5bDuJBWtnggeWYQM0tariSXLt rAy0MmTpSmR5nlFJSSTxc2rgONy3oapV4zredeNeAFtcXq2t9lPGpGYpZMhIFq5cAPIe NbtWGhuvuqW3wLWHiR1WQ5pJVYMwV9ru19usTaFmncCyLVOHLU8kemEyxXlo4ZcEltXw WMyshL6z183ikQFsAUihksrCUn1IqqiwdemkmiNN1s/lkqRwB11zRVHoWL/4aHfTniR4 CUHzycKxlYcgnas5aW0wz0iahp+9LwSMX49VwcFB4e5EL/vKdiRH/f358o5sJdCVqSm3 wO3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1760382779; x=1760987579; h=content-transfer-encoding:in-reply-to:from:content-language :references:cc:to:subject:user-agent:mime-version:date:message-id :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=78jY7yI9EEPM0HaRkplFkOHEcPOXrpB7WK7QZGIoaAk=; b=Nsr+NAv64ZWS75n6/X30NfGOVdv9q9AsrJR08ZzygrSV9YJZFPQCMMsDkVDLhyInHy s8CNN/vBCiPTDnjW7EnsuKRxpsZzmdL94XxqlA0rCWNCpUoly540Rlfmuk2Lb1Gy3NLT i0JhVGUBRah1GX/C2HoDE/WCC8NQy6DGaRRjuWnYeknATaK7/ZjINm1aG1fudwe3nZGy 6ks3FZmeAtuvgoy4RXHMLpuF3Q/f8+GL2Huq/yNXpeVUeu/caWtdcw1kIsC+yA/jww+W Uc7eHfGBrf7VyW4nyXjUtgu2z7/97OkOUgMOSzqujQYQY4qj6VDmmRpeNISCS3oAlq79 wGTw== X-Forwarded-Encrypted: i=1; AJvYcCUkgANpyBFcyp8rT0JCPUVth76tdsj/tY9k3UbnEjSa7ZF+Xkntp2mVw1j1LvDcO3Y3l7KkhYKzWrjHHVE=@vger.kernel.org X-Gm-Message-State: AOJu0YzCzZ9d1W9HZ+AGhn0tC5dbkap+soA9bsGzF5P7hrUBN072+4k9 60MuWB+FxhTLNTVL3y6uHRY/O8tJuM3IoMiPHvlrmHFjKeqODQxzP9qZ X-Gm-Gg: ASbGncujAnNHEAm6GTpqWvudKFdjAri4RLnOnazJM2bgL+/Q+rI7ZEhc+NjSk3qkAUG GuzpNq2+V9JbazIwPoVclLfYOOGRnb1KhsmypKC8M+kV+dwKFM2Skoi2rhq+qVNBNqar7iL2DSu 4cuHKrVNvkrG7phQoTSe2SbzvBVleF+cN9wcnNLK0ko35MQVOlvNpXPjBkehMhsBVmP5UspB947 U7cVR1Dy2vS0pjET3bYHT2cN7hrxssRJpdjarh669j8eKYHgut+hwW7QZrkicmPfcAOQQbxy/ii XcEKTRjJyiMe69uZeb54/xQOVEvkQebQzISPqBMAbXeF5ZOyQ3OFROqGTPmXCGXCZFKspaMqmsv 5Un/JHDiGNNePqAPNRvTXODfJDaKUh6pk+BtD8pzO5wwSE8kApzP22RqcboZ5XU3XvfGEMAx5Td DN8A== X-Google-Smtp-Source: AGHT+IGYdP1uz+s2azwXxj8Co3YmOmM0qVKwuPv9tcbZ572Psosrg1JURWPIP362PE6kBXlU4erpHw== X-Received: by 2002:a05:6830:71a5:b0:756:92af:deb8 with SMTP id 46e09a7af769-7c0df6bc4efmr12841219a34.21.1760382778784; Mon, 13 Oct 2025 12:12:58 -0700 (PDT) Received: from [192.168.10.123] (ip174-72-42-244.ph.ph.cox.net. [174.72.42.244]) by smtp.gmail.com with ESMTPSA id 46e09a7af769-7c0f911aacesm3750986a34.27.2025.10.13.12.12.57 (version=TLS1_3 cipher=TLS_AES_128_GCM_SHA256 bits=128/128); Mon, 13 Oct 2025 12:12:58 -0700 (PDT) Message-ID: Date: Mon, 13 Oct 2025 12:12:57 -0700 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH v13 8/8] platform/x86: asus-armoury: add ppt_* and nv_* tuning knobs To: Denis Benato , linux-kernel@vger.kernel.org Cc: platform-driver-x86@vger.kernel.org, Hans de Goede , =?UTF-8?Q?Ilpo_J=C3=A4rvinen?= , "Limonciello, Mario" , "Luke D . Jones" , Alok Tiwari , Derek John Clark , Mateusz Schyboll References: <20251013180534.1222432-1-benato.denis96@gmail.com> <20251013180534.1222432-9-benato.denis96@gmail.com> Content-Language: en-US From: Porfet Lillian In-Reply-To: <20251013180534.1222432-9-benato.denis96@gmail.com> Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 10/13/25 11:05 AM, Denis Benato wrote: > From: "Luke D. Jones" > > Adds the ppt_* and nv_* tuning knobs that are available via WMI methods > and adds proper min/max levels plus defaults. > > The min/max are defined by ASUS and typically gained by looking at what > they allow in the ASUS Armoury Crate application - ASUS does not share > the values outside of this. It could also be possible to gain the AMD > values by use of ryzenadj and testing for the minimum stable value. > > The general rule of thumb for adding to the match table is that if the > model range has a single CPU used throughout, then the DMI match can > omit the last letter of the model number as this is the GPU model. > > If a min or max value is not provided it is assumed that the particular > setting is not supported. for example ppt_pl2_sppt_min/max is not set. > If a _def is not set then the default is assumed to be > _max > > It is assumed that at least AC settings are available so that the > firmware attributes will be created - if no DC table is available > and power is on DC, then reading the attributes is -ENODEV. > > Signed-off-by: Denis Benato > Signed-off-by: Luke D. Jones > Reviewed-by: Mario Limonciello > Tested-by: Mateusz Schyboll Tested-by: Porfet Lillian > --- > drivers/platform/x86/asus-armoury.c | 296 ++++- > drivers/platform/x86/asus-armoury.h | 1210 ++++++++++++++++++++ > include/linux/platform_data/x86/asus-wmi.h | 3 + > 3 files changed, 1503 insertions(+), 6 deletions(-) > > diff --git a/drivers/platform/x86/asus-armoury.c b/drivers/platform/x86/asus-armoury.c > index e27f964aebf8..918aea6fba1e 100644 > --- a/drivers/platform/x86/asus-armoury.c > +++ b/drivers/platform/x86/asus-armoury.c > @@ -27,6 +27,7 @@ > #include > #include > #include > +#include > #include > > #include "asus-armoury.h" > @@ -45,6 +46,17 @@ > #define ASUS_MINI_LED_2024_STRONG 0x01 > #define ASUS_MINI_LED_2024_OFF 0x02 > > +/* Power tunable attribute name defines */ > +#define ATTR_PPT_PL1_SPL "ppt_pl1_spl" > +#define ATTR_PPT_PL2_SPPT "ppt_pl2_sppt" > +#define ATTR_PPT_PL3_FPPT "ppt_pl3_fppt" > +#define ATTR_PPT_APU_SPPT "ppt_apu_sppt" > +#define ATTR_PPT_PLATFORM_SPPT "ppt_platform_sppt" > +#define ATTR_NV_DYNAMIC_BOOST "nv_dynamic_boost" > +#define ATTR_NV_TEMP_TARGET "nv_temp_target" > +#define ATTR_NV_BASE_TGP "nv_base_tgp" > +#define ATTR_NV_TGP "nv_tgp" > + > #define ASUS_POWER_CORE_MASK GENMASK(15, 8) > #define ASUS_PERF_CORE_MASK GENMASK(7, 0) > > @@ -73,11 +85,26 @@ struct cpu_cores { > u32 max_power_cores; > }; > > +struct rog_tunables { > + const struct power_limits *power_limits; > + u32 ppt_pl1_spl; // cpu > + u32 ppt_pl2_sppt; // cpu > + u32 ppt_pl3_fppt; // cpu > + u32 ppt_apu_sppt; // plat > + u32 ppt_platform_sppt; // plat > + > + u32 nv_dynamic_boost; > + u32 nv_temp_target; > + u32 nv_tgp; > +}; > + > static struct asus_armoury_priv { > struct device *fw_attr_dev; > struct kset *fw_attr_kset; > > struct cpu_cores *cpu_cores; > + /* Index 0 for DC, 1 for AC */ > + struct rog_tunables *rog_tunables[2]; > u32 mini_led_dev_id; > u32 gpu_mux_dev_id; > /* > @@ -719,7 +746,34 @@ static ssize_t cores_efficiency_current_value_store(struct kobject *kobj, > ATTR_GROUP_CORES_RW(cores_efficiency, "cores_efficiency", > "Set the max available efficiency cores"); > > +/* Define helper to access the current power mode tunable values */ > +static inline struct rog_tunables *get_current_tunables(void) > +{ > + return asus_armoury > + .rog_tunables[power_supply_is_system_supplied() ? 1 : 0]; > +} > + > /* Simple attribute creation */ > +ATTR_GROUP_ROG_TUNABLE(ppt_pl1_spl, ATTR_PPT_PL1_SPL, ASUS_WMI_DEVID_PPT_PL1_SPL, > + "Set the CPU slow package limit"); > +ATTR_GROUP_ROG_TUNABLE(ppt_pl2_sppt, ATTR_PPT_PL2_SPPT, ASUS_WMI_DEVID_PPT_PL2_SPPT, > + "Set the CPU fast package limit"); > +ATTR_GROUP_ROG_TUNABLE(ppt_pl3_fppt, ATTR_PPT_PL3_FPPT, ASUS_WMI_DEVID_PPT_FPPT, > + "Set the CPU fastest package limit"); > +ATTR_GROUP_ROG_TUNABLE(ppt_apu_sppt, ATTR_PPT_APU_SPPT, ASUS_WMI_DEVID_PPT_APU_SPPT, > + "Set the APU package limit"); > +ATTR_GROUP_ROG_TUNABLE(ppt_platform_sppt, ATTR_PPT_PLATFORM_SPPT, ASUS_WMI_DEVID_PPT_PLAT_SPPT, > + "Set the platform package limit"); > +ATTR_GROUP_ROG_TUNABLE(nv_dynamic_boost, ATTR_NV_DYNAMIC_BOOST, ASUS_WMI_DEVID_NV_DYN_BOOST, > + "Set the Nvidia dynamic boost limit"); > +ATTR_GROUP_ROG_TUNABLE(nv_temp_target, ATTR_NV_TEMP_TARGET, ASUS_WMI_DEVID_NV_THERM_TARGET, > + "Set the Nvidia max thermal limit"); > +ATTR_GROUP_ROG_TUNABLE(nv_tgp, "nv_tgp", ASUS_WMI_DEVID_DGPU_SET_TGP, > + "Set the additional TGP on top of the base TGP"); > +ATTR_GROUP_INT_VALUE_ONLY_RO(nv_base_tgp, ATTR_NV_BASE_TGP, ASUS_WMI_DEVID_DGPU_BASE_TGP, > + "Read the base TGP value"); > + > + > ATTR_GROUP_ENUM_INT_RO(charge_mode, "charge_mode", ASUS_WMI_DEVID_CHARGE_MODE, "0;1;2", > "Show the current mode of charging"); > > @@ -746,6 +800,16 @@ static const struct asus_attr_group armoury_attr_groups[] = { > { &cores_efficiency_attr_group, ASUS_WMI_DEVID_CORES_MAX }, > { &cores_performance_attr_group, ASUS_WMI_DEVID_CORES_MAX }, > > + { &ppt_pl1_spl_attr_group, ASUS_WMI_DEVID_PPT_PL1_SPL }, > + { &ppt_pl2_sppt_attr_group, ASUS_WMI_DEVID_PPT_PL2_SPPT }, > + { &ppt_pl3_fppt_attr_group, ASUS_WMI_DEVID_PPT_FPPT }, > + { &ppt_apu_sppt_attr_group, ASUS_WMI_DEVID_PPT_APU_SPPT }, > + { &ppt_platform_sppt_attr_group, ASUS_WMI_DEVID_PPT_PLAT_SPPT }, > + { &nv_dynamic_boost_attr_group, ASUS_WMI_DEVID_NV_DYN_BOOST }, > + { &nv_temp_target_attr_group, ASUS_WMI_DEVID_NV_THERM_TARGET }, > + { &nv_base_tgp_attr_group, ASUS_WMI_DEVID_DGPU_BASE_TGP }, > + { &nv_tgp_attr_group, ASUS_WMI_DEVID_DGPU_SET_TGP }, > + > { &charge_mode_attr_group, ASUS_WMI_DEVID_CHARGE_MODE }, > { &boot_sound_attr_group, ASUS_WMI_DEVID_BOOT_SOUND }, > { &mcu_powersave_attr_group, ASUS_WMI_DEVID_MCU_POWERSAVE }, > @@ -754,8 +818,75 @@ static const struct asus_attr_group armoury_attr_groups[] = { > { &screen_auto_brightness_attr_group, ASUS_WMI_DEVID_SCREEN_AUTO_BRIGHTNESS }, > }; > > +/** > + * is_power_tunable_attr - Determines if an attribute is a power-related tunable > + * @name: The name of the attribute to check > + * > + * This function checks if the given attribute name is related to power tuning. > + * > + * Return: true if the attribute is a power-related tunable, false otherwise > + */ > +static bool is_power_tunable_attr(const char *name) > +{ > + static const char * const power_tunable_attrs[] = { > + ATTR_PPT_PL1_SPL, ATTR_PPT_PL2_SPPT, > + ATTR_PPT_PL3_FPPT, ATTR_PPT_APU_SPPT, > + ATTR_PPT_PLATFORM_SPPT, ATTR_NV_DYNAMIC_BOOST, > + ATTR_NV_TEMP_TARGET, ATTR_NV_BASE_TGP, > + ATTR_NV_TGP > + }; > + > + for (unsigned int i = 0; i < ARRAY_SIZE(power_tunable_attrs); i++) { > + if (!strcmp(name, power_tunable_attrs[i])) > + return true; > + } > + > + return false; > +} > + > +/** > + * has_valid_limit - Checks if a power-related attribute has a valid limit value > + * @name: The name of the attribute to check > + * @limits: Pointer to the power_limits structure containing limit values > + * > + * This function checks if a power-related attribute has a valid limit value. > + * It returns false if limits is NULL or if the corresponding limit value is zero. > + * > + * Return: true if the attribute has a valid limit value, false otherwise > + */ > +static bool has_valid_limit(const char *name, const struct power_limits *limits) > +{ > + u32 limit_value = 0; > + > + if (!limits) > + return false; > + > + if (!strcmp(name, ATTR_PPT_PL1_SPL)) > + limit_value = limits->ppt_pl1_spl_max; > + else if (!strcmp(name, ATTR_PPT_PL2_SPPT)) > + limit_value = limits->ppt_pl2_sppt_max; > + else if (!strcmp(name, ATTR_PPT_PL3_FPPT)) > + limit_value = limits->ppt_pl3_fppt_max; > + else if (!strcmp(name, ATTR_PPT_APU_SPPT)) > + limit_value = limits->ppt_apu_sppt_max; > + else if (!strcmp(name, ATTR_PPT_PLATFORM_SPPT)) > + limit_value = limits->ppt_platform_sppt_max; > + else if (!strcmp(name, ATTR_NV_DYNAMIC_BOOST)) > + limit_value = limits->nv_dynamic_boost_max; > + else if (!strcmp(name, ATTR_NV_TEMP_TARGET)) > + limit_value = limits->nv_temp_target_max; > + else if (!strcmp(name, ATTR_NV_BASE_TGP) || > + !strcmp(name, ATTR_NV_TGP)) > + limit_value = limits->nv_tgp_max; > + > + return limit_value > 0; > +} > + > static int asus_fw_attr_add(void) > { > + const struct power_limits *limits; > + bool should_create; > + const char *name; > int err, i; > > asus_armoury.fw_attr_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), > @@ -812,12 +943,30 @@ static int asus_fw_attr_add(void) > if (!asus_wmi_is_present(armoury_attr_groups[i].wmi_devid)) > continue; > > - err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, > - armoury_attr_groups[i].attr_group); > - if (err) { > - pr_err("Failed to create sysfs-group for %s\n", > - armoury_attr_groups[i].attr_group->name); > - goto err_remove_groups; > + /* Always create by default, unless PPT is not present */ > + should_create = true; > + name = armoury_attr_groups[i].attr_group->name; > + > + /* Check if this is a power-related tunable requiring limits */ > + if (asus_armoury.rog_tunables[1] && asus_armoury.rog_tunables[1]->power_limits && > + is_power_tunable_attr(name)) { > + limits = asus_armoury.rog_tunables[1]->power_limits; > + /* Check only AC, if DC is not present then AC won't be either */ > + should_create = has_valid_limit(name, limits); > + if (!should_create) { > + pr_debug("Missing max value on %s for tunable: %s\n", > + dmi_get_system_info(DMI_BOARD_NAME), name); > + } > + } > + > + if (should_create) { > + err = sysfs_create_group(&asus_armoury.fw_attr_kset->kobj, > + armoury_attr_groups[i].attr_group); > + if (err) { > + pr_err("Failed to create sysfs-group for %s\n", > + armoury_attr_groups[i].attr_group->name); > + goto err_remove_groups; > + } > } > } > > @@ -846,6 +995,135 @@ static int asus_fw_attr_add(void) > > /* Init / exit ****************************************************************/ > > +/* Set up the min/max and defaults for ROG tunables */ > +static void init_rog_tunables(void) > +{ > + const struct power_limits *ac_limits, *dc_limits; > + const struct power_data *power_data; > + const struct dmi_system_id *dmi_id; > + bool ac_initialized = false, dc_initialized = false; > + > + /* Match the system against the power_limits table */ > + dmi_id = dmi_first_match(power_limits); > + if (!dmi_id) { > + pr_warn("No matching power limits found for this system\n"); > + return; > + } > + > + /* Get the power data for this system */ > + power_data = dmi_id->driver_data; > + if (!power_data) { > + pr_info("No power data available for this system\n"); > + return; > + } > + > + /* Initialize AC power tunables */ > + ac_limits = power_data->ac_data; > + if (ac_limits) { > + asus_armoury.rog_tunables[1] = > + kzalloc(sizeof(*asus_armoury.rog_tunables[1]), GFP_KERNEL); > + if (!asus_armoury.rog_tunables[1]) > + goto err_nomem; > + > + asus_armoury.rog_tunables[1]->power_limits = ac_limits; > + > + /* Set initial AC values */ > + asus_armoury.rog_tunables[1]->ppt_pl1_spl = > + ac_limits->ppt_pl1_spl_def ? > + ac_limits->ppt_pl1_spl_def : > + ac_limits->ppt_pl1_spl_max; > + > + asus_armoury.rog_tunables[1]->ppt_pl2_sppt = > + ac_limits->ppt_pl2_sppt_def ? > + ac_limits->ppt_pl2_sppt_def : > + ac_limits->ppt_pl2_sppt_max; > + > + asus_armoury.rog_tunables[1]->ppt_pl3_fppt = > + ac_limits->ppt_pl3_fppt_def ? > + ac_limits->ppt_pl3_fppt_def : > + ac_limits->ppt_pl3_fppt_max; > + > + asus_armoury.rog_tunables[1]->ppt_apu_sppt = > + ac_limits->ppt_apu_sppt_def ? > + ac_limits->ppt_apu_sppt_def : > + ac_limits->ppt_apu_sppt_max; > + > + asus_armoury.rog_tunables[1]->ppt_platform_sppt = > + ac_limits->ppt_platform_sppt_def ? > + ac_limits->ppt_platform_sppt_def : > + ac_limits->ppt_platform_sppt_max; > + > + asus_armoury.rog_tunables[1]->nv_dynamic_boost = > + ac_limits->nv_dynamic_boost_max; > + asus_armoury.rog_tunables[1]->nv_temp_target = > + ac_limits->nv_temp_target_max; > + asus_armoury.rog_tunables[1]->nv_tgp = ac_limits->nv_tgp_max; > + > + ac_initialized = true; > + pr_debug("AC power limits initialized for %s\n", dmi_id->matches[0].substr); > + } > + > + /* Initialize DC power tunables */ > + dc_limits = power_data->dc_data; > + if (dc_limits) { > + asus_armoury.rog_tunables[0] = > + kzalloc(sizeof(*asus_armoury.rog_tunables[0]), GFP_KERNEL); > + if (!asus_armoury.rog_tunables[0]) { > + if (ac_initialized) > + kfree(asus_armoury.rog_tunables[1]); > + goto err_nomem; > + } > + > + asus_armoury.rog_tunables[0]->power_limits = dc_limits; > + > + /* Set initial DC values */ > + asus_armoury.rog_tunables[0]->ppt_pl1_spl = > + dc_limits->ppt_pl1_spl_def ? > + dc_limits->ppt_pl1_spl_def : > + dc_limits->ppt_pl1_spl_max; > + > + asus_armoury.rog_tunables[0]->ppt_pl2_sppt = > + dc_limits->ppt_pl2_sppt_def ? > + dc_limits->ppt_pl2_sppt_def : > + dc_limits->ppt_pl2_sppt_max; > + > + asus_armoury.rog_tunables[0]->ppt_pl3_fppt = > + dc_limits->ppt_pl3_fppt_def ? > + dc_limits->ppt_pl3_fppt_def : > + dc_limits->ppt_pl3_fppt_max; > + > + asus_armoury.rog_tunables[0]->ppt_apu_sppt = > + dc_limits->ppt_apu_sppt_def ? > + dc_limits->ppt_apu_sppt_def : > + dc_limits->ppt_apu_sppt_max; > + > + asus_armoury.rog_tunables[0]->ppt_platform_sppt = > + dc_limits->ppt_platform_sppt_def ? > + dc_limits->ppt_platform_sppt_def : > + dc_limits->ppt_platform_sppt_max; > + > + asus_armoury.rog_tunables[0]->nv_dynamic_boost = > + dc_limits->nv_dynamic_boost_max; > + asus_armoury.rog_tunables[0]->nv_temp_target = > + dc_limits->nv_temp_target_max; > + asus_armoury.rog_tunables[0]->nv_tgp = dc_limits->nv_tgp_max; > + > + dc_initialized = true; > + pr_debug("DC power limits initialized for %s\n", dmi_id->matches[0].substr); > + } > + > + if (!ac_initialized) > + pr_debug("No AC PPT limits defined\n"); > + > + if (!dc_initialized) > + pr_debug("No DC PPT limits defined\n"); > + > + return; > + > +err_nomem: > + pr_err("Failed to allocate memory for tunables\n"); > +} > + > static int __init asus_fw_init(void) > { > char *wmi_uid; > @@ -870,6 +1148,9 @@ static int __init asus_fw_init(void) > } > } > > + init_rog_tunables(); > + > + /* Must always be last step to ensure data is available */ > return asus_fw_attr_add(); > } > > @@ -878,6 +1159,9 @@ static void __exit asus_fw_exit(void) > sysfs_remove_file(&asus_armoury.fw_attr_kset->kobj, &pending_reboot.attr); > kset_unregister(asus_armoury.fw_attr_kset); > device_destroy(&firmware_attributes_class, MKDEV(0, 0)); > + > + kfree(asus_armoury.rog_tunables[0]); > + kfree(asus_armoury.rog_tunables[1]); > } > > module_init(asus_fw_init); > diff --git a/drivers/platform/x86/asus-armoury.h b/drivers/platform/x86/asus-armoury.h > index a6c4caefdef9..d99db5f5f6a0 100644 > --- a/drivers/platform/x86/asus-armoury.h > +++ b/drivers/platform/x86/asus-armoury.h > @@ -8,6 +8,7 @@ > #ifndef _ASUS_ARMOURY_H_ > #define _ASUS_ARMOURY_H_ > > +#include > #include > #include > > @@ -189,4 +190,1213 @@ > .name = _fsname, .attrs = _attrname##_attrs \ > } > > +#define ATTR_GROUP_INT_VALUE_ONLY_RO(_attrname, _fsname, _wmi, _dispname) \ > + WMI_SHOW_INT(_attrname##_current_value, "%d\n", _wmi); \ > + static struct kobj_attribute attr_##_attrname##_current_value = \ > + __ASUS_ATTR_RO(_attrname, current_value); \ > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ > + static struct kobj_attribute attr_##_attrname##_type = \ > + __ASUS_ATTR_RO_AS(type, int_type_show); \ > + static struct attribute *_attrname##_attrs[] = { \ > + &attr_##_attrname##_current_value.attr, \ > + &attr_##_attrname##_display_name.attr, \ > + &attr_##_attrname##_type.attr, NULL \ > + }; \ > + static const struct attribute_group _attrname##_attr_group = { \ > + .name = _fsname, .attrs = _attrname##_attrs \ > + } > + > +/* > + * ROG PPT attributes need a little different in setup as they > + * require rog_tunables members. > + */ > + > +#define __ROG_TUNABLE_SHOW(_prop, _attrname, _val) \ > + static ssize_t _attrname##_##_prop##_show( \ > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ > + { \ > + struct rog_tunables *tunables = get_current_tunables(); \ > + \ > + if (!tunables || !tunables->power_limits) \ > + return -ENODEV; \ > + \ > + return sysfs_emit(buf, "%d\n", tunables->power_limits->_val); \ > + } \ > + static struct kobj_attribute attr_##_attrname##_##_prop = \ > + __ASUS_ATTR_RO(_attrname, _prop) > + > +#define __ROG_TUNABLE_SHOW_DEFAULT(_attrname) \ > + static ssize_t _attrname##_default_value_show( \ > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ > + { \ > + struct rog_tunables *tunables = get_current_tunables(); \ > + \ > + if (!tunables || !tunables->power_limits) \ > + return -ENODEV; \ > + \ > + return sysfs_emit( \ > + buf, "%d\n", \ > + tunables->power_limits->_attrname##_def ? \ > + tunables->power_limits->_attrname##_def : \ > + tunables->power_limits->_attrname##_max); \ > + } \ > + static struct kobj_attribute attr_##_attrname##_default_value = \ > + __ASUS_ATTR_RO(_attrname, default_value) > + > +#define __ROG_TUNABLE_RW(_attr, _wmi) \ > + static ssize_t _attr##_current_value_store( \ > + struct kobject *kobj, struct kobj_attribute *attr, \ > + const char *buf, size_t count) \ > + { \ > + struct rog_tunables *tunables = get_current_tunables(); \ > + \ > + if (!tunables || !tunables->power_limits) \ > + return -ENODEV; \ > + \ > + return attr_uint_store(kobj, attr, buf, count, \ > + tunables->power_limits->_attr##_min, \ > + tunables->power_limits->_attr##_max, \ > + &tunables->_attr, _wmi); \ > + } \ > + static ssize_t _attr##_current_value_show( \ > + struct kobject *kobj, struct kobj_attribute *attr, char *buf) \ > + { \ > + struct rog_tunables *tunables = get_current_tunables(); \ > + \ > + if (!tunables) \ > + return -ENODEV; \ > + \ > + return sysfs_emit(buf, "%u\n", tunables->_attr); \ > + } \ > + static struct kobj_attribute attr_##_attr##_current_value = \ > + __ASUS_ATTR_RW(_attr, current_value) > + > +#define ATTR_GROUP_ROG_TUNABLE(_attrname, _fsname, _wmi, _dispname) \ > + __ROG_TUNABLE_RW(_attrname, _wmi); \ > + __ROG_TUNABLE_SHOW_DEFAULT(_attrname); \ > + __ROG_TUNABLE_SHOW(min_value, _attrname, _attrname##_min); \ > + __ROG_TUNABLE_SHOW(max_value, _attrname, _attrname##_max); \ > + __ATTR_SHOW_FMT(scalar_increment, _attrname, "%d\n", 1); \ > + __ATTR_SHOW_FMT(display_name, _attrname, "%s\n", _dispname); \ > + static struct kobj_attribute attr_##_attrname##_type = \ > + __ASUS_ATTR_RO_AS(type, int_type_show); \ > + static struct attribute *_attrname##_attrs[] = { \ > + &attr_##_attrname##_current_value.attr, \ > + &attr_##_attrname##_default_value.attr, \ > + &attr_##_attrname##_min_value.attr, \ > + &attr_##_attrname##_max_value.attr, \ > + &attr_##_attrname##_scalar_increment.attr, \ > + &attr_##_attrname##_display_name.attr, \ > + &attr_##_attrname##_type.attr, \ > + NULL \ > + }; \ > + static const struct attribute_group _attrname##_attr_group = { \ > + .name = _fsname, .attrs = _attrname##_attrs \ > + } > + > +/* Default is always the maximum value unless *_def is specified */ > +struct power_limits { > + u8 ppt_pl1_spl_min; > + u8 ppt_pl1_spl_def; > + u8 ppt_pl1_spl_max; > + u8 ppt_pl2_sppt_min; > + u8 ppt_pl2_sppt_def; > + u8 ppt_pl2_sppt_max; > + u8 ppt_pl3_fppt_min; > + u8 ppt_pl3_fppt_def; > + u8 ppt_pl3_fppt_max; > + u8 ppt_apu_sppt_min; > + u8 ppt_apu_sppt_def; > + u8 ppt_apu_sppt_max; > + u8 ppt_platform_sppt_min; > + u8 ppt_platform_sppt_def; > + u8 ppt_platform_sppt_max; > + /* Nvidia GPU specific, default is always max */ > + u8 nv_dynamic_boost_def; // unused. exists for macro > + u8 nv_dynamic_boost_min; > + u8 nv_dynamic_boost_max; > + u8 nv_temp_target_def; // unused. exists for macro > + u8 nv_temp_target_min; > + u8 nv_temp_target_max; > + u8 nv_tgp_def; // unused. exists for macro > + u8 nv_tgp_min; > + u8 nv_tgp_max; > +}; > + > +struct power_data { > + const struct power_limits *ac_data; > + const struct power_limits *dc_data; > + bool requires_fan_curve; > +}; > + > +/* > + * For each available attribute there must be a min and a max. > + * _def is not required and will be assumed to be default == max if missing. > + */ > +static const struct dmi_system_id power_limits[] = { > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA401W"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 75, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 30, > + .ppt_pl2_sppt_min = 31, > + .ppt_pl2_sppt_max = 44, > + .ppt_pl3_fppt_min = 45, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA507N"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 45, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA507R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80 > + }, > + .dc_data = NULL > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA507X"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 85, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 45, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA507Z"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 105, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 15, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 85, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 45, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 60, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA607P"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 30, > + .ppt_pl1_spl_def = 100, > + .ppt_pl1_spl_max = 135, > + .ppt_pl2_sppt_min = 30, > + .ppt_pl2_sppt_def = 115, > + .ppt_pl2_sppt_max = 135, > + .ppt_pl3_fppt_min = 30, > + .ppt_pl3_fppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 115, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_def = 45, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_def = 60, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 25, > + .ppt_pl3_fppt_max = 80, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA608WI"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 90, > + .ppt_pl1_spl_max = 90, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 90, > + .ppt_pl2_sppt_max = 90, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 90, > + .ppt_pl3_fppt_max = 90, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 115, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 45, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 65, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA617NS"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 15, > + .ppt_apu_sppt_max = 80, > + .ppt_platform_sppt_min = 30, > + .ppt_platform_sppt_max = 120 > + }, > + .dc_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 25, > + .ppt_apu_sppt_max = 35, > + .ppt_platform_sppt_min = 45, > + .ppt_platform_sppt_max = 100 > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA617NT"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 15, > + .ppt_apu_sppt_max = 80, > + .ppt_platform_sppt_min = 30, > + .ppt_platform_sppt_max = 115 > + }, > + .dc_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 15, > + .ppt_apu_sppt_max = 45, > + .ppt_platform_sppt_min = 30, > + .ppt_platform_sppt_max = 50 > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FA617XS"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 15, > + .ppt_apu_sppt_max = 80, > + .ppt_platform_sppt_min = 30, > + .ppt_platform_sppt_max = 120, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 25, > + .ppt_apu_sppt_max = 35, > + .ppt_platform_sppt_min = 45, > + .ppt_platform_sppt_max = 100, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FX507VI"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 135, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 45, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 60, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "FX507Z"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 90, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 15, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 45, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 60, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GA401Q"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_max = 80, > + }, > + .dc_data = NULL > + }, > + }, > + { > + .matches = { > + // This model is full AMD. No Nvidia dGPU. > + DMI_MATCH(DMI_BOARD_NAME, "GA402R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 15, > + .ppt_apu_sppt_max = 80, > + .ppt_platform_sppt_min = 30, > + .ppt_platform_sppt_max = 115, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_apu_sppt_min = 25, > + .ppt_apu_sppt_def = 30, > + .ppt_apu_sppt_max = 45, > + .ppt_platform_sppt_min = 40, > + .ppt_platform_sppt_max = 60, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GA402X"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 35, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_def = 65, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 35, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GA403U"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 65, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 35, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GA503R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 35, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 65, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 25, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 60, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65 > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GA605W"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 85, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 31, > + .ppt_pl2_sppt_max = 44, > + .ppt_pl3_fppt_min = 45, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GU603Z"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 60, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 135, > + /* Only allowed in AC mode */ > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 40, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 40, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GU604V"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 65, > + .ppt_pl1_spl_max = 120, > + .ppt_pl2_sppt_min = 65, > + .ppt_pl2_sppt_max = 150, > + /* Only allowed in AC mode */ > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 40, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 40, > + .ppt_pl2_sppt_max = 60, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GU605CW"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 45, > + .ppt_pl1_spl_max = 85, > + .ppt_pl2_sppt_min = 56, > + .ppt_pl2_sppt_max = 110, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 80, > + .nv_tgp_def = 90, > + .nv_tgp_max = 110, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 85, > + .ppt_pl2_sppt_min = 32, > + .ppt_pl2_sppt_max = 110, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GU605M"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 90, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 38, > + .ppt_pl2_sppt_max = 53, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GV301Q"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 45, > + .ppt_pl2_sppt_min = 65, > + .ppt_pl2_sppt_max = 80, > + }, > + .dc_data = NULL > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GV301R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 45, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 54, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 35, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GV601R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 35, > + .ppt_pl1_spl_max = 90, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 100, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 80, > + .ppt_pl3_fppt_max = 125, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 28, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 54, > + .ppt_pl2_sppt_max = 60, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 80, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GV601V"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_def = 100, > + .ppt_pl1_spl_max = 110, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 40, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 40, > + .ppt_pl2_sppt_max = 60, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "GX650P"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 110, > + .ppt_pl1_spl_max = 130, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 125, > + .ppt_pl2_sppt_max = 130, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 125, > + .ppt_pl3_fppt_max = 135, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_def = 25, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_def = 35, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_def = 42, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G513I"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + /* Yes this laptop is very limited */ > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_max = 80, > + }, > + .dc_data = NULL, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G513QM"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + /* Yes this laptop is very limited */ > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 100, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_max = 190, > + }, > + .dc_data = NULL, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G513R"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 35, > + .ppt_pl1_spl_max = 90, > + .ppt_pl2_sppt_min = 54, > + .ppt_pl2_sppt_max = 100, > + .ppt_pl3_fppt_min = 54, > + .ppt_pl3_fppt_max = 125, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 50, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 50, > + .ppt_pl3_fppt_min = 28, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G614J"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 140, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 175, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 55, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 70, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G634J"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 140, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 175, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 55, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 70, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G713PV"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 30, > + .ppt_pl1_spl_def = 120, > + .ppt_pl1_spl_max = 130, > + .ppt_pl2_sppt_min = 65, > + .ppt_pl2_sppt_def = 125, > + .ppt_pl2_sppt_max = 130, > + .ppt_pl3_fppt_min = 65, > + .ppt_pl3_fppt_def = 125, > + .ppt_pl3_fppt_max = 130, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 75, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G733C"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 170, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 175, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 35, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G733P"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 30, > + .ppt_pl1_spl_def = 100, > + .ppt_pl1_spl_max = 130, > + .ppt_pl2_sppt_min = 65, > + .ppt_pl2_sppt_def = 125, > + .ppt_pl2_sppt_max = 130, > + .ppt_pl3_fppt_min = 65, > + .ppt_pl3_fppt_def = 125, > + .ppt_pl3_fppt_max = 130, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 65, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 65, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 75, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G814J"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 140, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 140, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 55, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 70, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "G834J"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 28, > + .ppt_pl1_spl_max = 140, > + .ppt_pl2_sppt_min = 28, > + .ppt_pl2_sppt_max = 175, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 25, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 55, > + .ppt_pl2_sppt_min = 25, > + .ppt_pl2_sppt_max = 70, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + }, > + .requires_fan_curve = true, > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "H7606W"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 15, > + .ppt_pl1_spl_max = 80, > + .ppt_pl2_sppt_min = 35, > + .ppt_pl2_sppt_max = 80, > + .ppt_pl3_fppt_min = 35, > + .ppt_pl3_fppt_max = 80, > + .nv_dynamic_boost_min = 5, > + .nv_dynamic_boost_max = 20, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + .nv_tgp_min = 55, > + .nv_tgp_max = 85, > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 25, > + .ppt_pl1_spl_max = 35, > + .ppt_pl2_sppt_min = 31, > + .ppt_pl2_sppt_max = 44, > + .ppt_pl3_fppt_min = 45, > + .ppt_pl3_fppt_max = 65, > + .nv_temp_target_min = 75, > + .nv_temp_target_max = 87, > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "RC71"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 7, > + .ppt_pl1_spl_max = 30, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_max = 43, > + .ppt_pl3_fppt_min = 15, > + .ppt_pl3_fppt_max = 53 > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 7, > + .ppt_pl1_spl_def = 15, > + .ppt_pl1_spl_max = 25, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_def = 20, > + .ppt_pl2_sppt_max = 30, > + .ppt_pl3_fppt_min = 15, > + .ppt_pl3_fppt_def = 25, > + .ppt_pl3_fppt_max = 35 > + } > + }, > + }, > + { > + .matches = { > + DMI_MATCH(DMI_BOARD_NAME, "RC72"), > + }, > + .driver_data = &(struct power_data) { > + .ac_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 7, > + .ppt_pl1_spl_max = 30, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_max = 43, > + .ppt_pl3_fppt_min = 15, > + .ppt_pl3_fppt_max = 53 > + }, > + .dc_data = &(struct power_limits) { > + .ppt_pl1_spl_min = 7, > + .ppt_pl1_spl_def = 17, > + .ppt_pl1_spl_max = 25, > + .ppt_pl2_sppt_min = 15, > + .ppt_pl2_sppt_def = 24, > + .ppt_pl2_sppt_max = 30, > + .ppt_pl3_fppt_min = 15, > + .ppt_pl3_fppt_def = 30, > + .ppt_pl3_fppt_max = 35 > + } > + }, > + }, > + {} > +}; > + > #endif /* _ASUS_ARMOURY_H_ */ > diff --git a/include/linux/platform_data/x86/asus-wmi.h b/include/linux/platform_data/x86/asus-wmi.h > index 260796fee301..480596317c7a 100644 > --- a/include/linux/platform_data/x86/asus-wmi.h > +++ b/include/linux/platform_data/x86/asus-wmi.h > @@ -145,6 +145,9 @@ > > #define ASUS_WMI_DEVID_APU_MEM 0x000600C1 > > +#define ASUS_WMI_DEVID_DGPU_BASE_TGP 0x00120099 > +#define ASUS_WMI_DEVID_DGPU_SET_TGP 0x00120098 > + > /* gpu mux switch, 0 = dGPU, 1 = Optimus */ > #define ASUS_WMI_DEVID_GPU_MUX 0x00090016 > #define ASUS_WMI_DEVID_GPU_MUX_VIVO 0x00090026