mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'platform-drivers-x86-v6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Ilpo Järvinen: - New acer-wmi HW support - Support for new revision of amd/pmf heartbeat notify - Correctly handle asus-wmi HW without LEDs - fujitsu-laptop battery charge control support - Support for new hp-wmi thermal profiles - Support ideapad-laptop refresh rate key - Put intel/pmc AI accelerator (GNA) into D3 if it has no driver to allow entry into low-power modes, and temporarily removed Lunar Lake SSRAM support due to breaking FW changes causing probe fail (further breaking FW changes are still pending) - Report pmc/punit_atom devices that prevent reacing low power levels - Surface Fan speed function support - Support for more sperial keys and complete the list of models with non-standard fan registers in thinkpad_acpi - New DMI touchscreen HW support - Continued modernization efforts of wmi - Removal of obsoleted ledtrig-audio call and the related dependency - Debug & metrics interface improvements - Miscellaneous cleanups / fixes / improvements * tag 'platform-drivers-x86-v6.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (87 commits) platform/x86/intel/pmc: Improve PKGC residency counters debug platform/x86: asus-wmi: Consider device is absent when the read is ~0 Documentation/x86/amd/hsmp: Updating urls platform/mellanox: mlxreg-hotplug: Remove redundant NULL-check platform/x86/amd/pmf: Update sps power thermals according to the platform-profiles platform/x86/amd/pmf: Add support to get sps default APTS index values platform/x86/amd/pmf: Add support to get APTS index numbers for static slider platform/x86/amd/pmf: Add support to notify sbios heart beat event platform/x86/amd/pmf: Add support to get sbios requests in PMF driver platform/x86/amd/pmf: Disable debugfs support for querying power thermals platform/x86/amd/pmf: Differentiate PMF ACPI versions x86/platform/atom: Check state of Punit managed devices on s2idle platform/x86: pmc_atom: Check state of PMC clocks on s2idle platform/x86: pmc_atom: Check state of PMC managed devices on s2idle platform/x86: pmc_atom: Annotate d3_sts register bit defines clk: x86: Move clk-pmc-atom register defines to include/linux/platform_data/x86/pmc_atom.h platform/x86: make fw_attr_class constant platform/x86/intel/tpmi: Change vsec offset to u64 platform/x86: intel_scu_pcidrv: Remove unused intel-mid.h platform/x86: intel_scu_wdt: Remove unused intel-mid.h ...
This commit is contained in:
@@ -444,7 +444,9 @@ event code Key Notes
|
||||
|
||||
0x1008 0x07 FN+F8 IBM: toggle screen expand
|
||||
Lenovo: configure UltraNav,
|
||||
or toggle screen expand
|
||||
or toggle screen expand.
|
||||
On newer platforms (2024+)
|
||||
replaced by 0x131f (see below)
|
||||
|
||||
0x1009 0x08 FN+F9 -
|
||||
|
||||
@@ -504,6 +506,9 @@ event code Key Notes
|
||||
|
||||
0x1019 0x18 unknown
|
||||
|
||||
0x131f ... FN+F8 Platform Mode change.
|
||||
Implemented in driver.
|
||||
|
||||
... ... ...
|
||||
|
||||
0x1020 0x1F unknown
|
||||
|
||||
@@ -13,7 +13,8 @@ set of mailbox registers.
|
||||
|
||||
More details on the interface can be found in chapter
|
||||
"7 Host System Management Port (HSMP)" of the family/model PPR
|
||||
Eg: https://www.amd.com/system/files/TechDocs/55898_B1_pub_0.50.zip
|
||||
Eg: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/55898_B1_pub_0_50.zip
|
||||
|
||||
|
||||
HSMP interface is supported on EPYC server CPU models only.
|
||||
|
||||
@@ -97,8 +98,8 @@ what happened. The transaction returns 0 on success.
|
||||
|
||||
More details on the interface and message definitions can be found in chapter
|
||||
"7 Host System Management Port (HSMP)" of the respective family/model PPR
|
||||
eg: https://www.amd.com/system/files/TechDocs/55898_B1_pub_0.50.zip
|
||||
eg: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/programmer-references/55898_B1_pub_0_50.zip
|
||||
|
||||
User space C-APIs are made available by linking against the esmi library,
|
||||
which is provided by the E-SMS project https://developer.amd.com/e-sms/.
|
||||
which is provided by the E-SMS project https://www.amd.com/en/developer/e-sms.html.
|
||||
See: https://github.com/amd/esmi_ib_library
|
||||
|
||||
@@ -93,4 +93,7 @@ _WED ACPI method
|
||||
----------------
|
||||
|
||||
Used to retrieve additional WMI event data, its single parameter is a integer
|
||||
holding the notification ID of the event.
|
||||
holding the notification ID of the event. This method should be evaluated every
|
||||
time an ACPI notification is received, since some ACPI implementations use a
|
||||
queue to store WMI event data items. This queue will overflow after a couple
|
||||
of WMI events are received without retrieving the associated WMI event data.
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
* Copyright (c) 2015, Intel Corporation.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "punit_atom: " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/device.h>
|
||||
@@ -117,6 +120,51 @@ static void punit_dbgfs_unregister(void)
|
||||
debugfs_remove_recursive(punit_dbg_file);
|
||||
}
|
||||
|
||||
#if defined(CONFIG_ACPI) && defined(CONFIG_SUSPEND)
|
||||
static const struct punit_device *punit_dev;
|
||||
|
||||
static void punit_s2idle_check(void)
|
||||
{
|
||||
const struct punit_device *punit_devp;
|
||||
u32 punit_pwr_status, dstate;
|
||||
int status;
|
||||
|
||||
for (punit_devp = punit_dev; punit_devp->name; punit_devp++) {
|
||||
/* Skip MIO, it is on till the very last moment */
|
||||
if (punit_devp->reg == MIO_SS_PM)
|
||||
continue;
|
||||
|
||||
status = iosf_mbi_read(BT_MBI_UNIT_PMC, MBI_REG_READ,
|
||||
punit_devp->reg, &punit_pwr_status);
|
||||
if (status) {
|
||||
pr_err("%s read failed\n", punit_devp->name);
|
||||
} else {
|
||||
dstate = (punit_pwr_status >> punit_devp->sss_pos) & 3;
|
||||
if (!dstate)
|
||||
pr_err("%s is in D0 prior to s2idle\n", punit_devp->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static struct acpi_s2idle_dev_ops punit_s2idle_ops = {
|
||||
.check = punit_s2idle_check,
|
||||
};
|
||||
|
||||
static void punit_s2idle_check_register(struct punit_device *punit_device)
|
||||
{
|
||||
punit_dev = punit_device;
|
||||
acpi_register_lps0_dev(&punit_s2idle_ops);
|
||||
}
|
||||
|
||||
static void punit_s2idle_check_unregister(void)
|
||||
{
|
||||
acpi_unregister_lps0_dev(&punit_s2idle_ops);
|
||||
}
|
||||
#else
|
||||
static void punit_s2idle_check_register(struct punit_device *punit_device) {}
|
||||
static void punit_s2idle_check_unregister(void) {}
|
||||
#endif
|
||||
|
||||
#define X86_MATCH(model, data) \
|
||||
X86_MATCH_VENDOR_FAM_MODEL_FEATURE(INTEL, 6, INTEL_FAM6_##model, \
|
||||
X86_FEATURE_MWAIT, data)
|
||||
@@ -131,19 +179,23 @@ MODULE_DEVICE_TABLE(x86cpu, intel_punit_cpu_ids);
|
||||
|
||||
static int __init punit_atom_debug_init(void)
|
||||
{
|
||||
struct punit_device *punit_device;
|
||||
const struct x86_cpu_id *id;
|
||||
|
||||
id = x86_match_cpu(intel_punit_cpu_ids);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
|
||||
punit_dbgfs_register((struct punit_device *)id->driver_data);
|
||||
punit_device = (struct punit_device *)id->driver_data;
|
||||
punit_dbgfs_register(punit_device);
|
||||
punit_s2idle_check_register(punit_device);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit punit_atom_debug_exit(void)
|
||||
{
|
||||
punit_s2idle_check_unregister();
|
||||
punit_dbgfs_unregister();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,23 +11,12 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_data/x86/clk-pmc-atom.h>
|
||||
#include <linux/platform_data/x86/pmc_atom.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#define PLT_CLK_NAME_BASE "pmc_plt_clk"
|
||||
|
||||
#define PMC_CLK_CTL_OFFSET 0x60
|
||||
#define PMC_CLK_CTL_SIZE 4
|
||||
#define PMC_CLK_NUM 6
|
||||
#define PMC_CLK_CTL_GATED_ON_D3 0x0
|
||||
#define PMC_CLK_CTL_FORCE_ON 0x1
|
||||
#define PMC_CLK_CTL_FORCE_OFF 0x2
|
||||
#define PMC_CLK_CTL_RESERVED 0x3
|
||||
#define PMC_MASK_CLK_CTL GENMASK(1, 0)
|
||||
#define PMC_MASK_CLK_FREQ BIT(2)
|
||||
#define PMC_CLK_FREQ_XTAL (0 << 2) /* 25 MHz */
|
||||
#define PMC_CLK_FREQ_PLL (1 << 2) /* 19.2 MHz */
|
||||
|
||||
struct clk_plt_fixed {
|
||||
struct clk_hw *clk;
|
||||
struct clk_lookup *lookup;
|
||||
|
||||
@@ -1600,6 +1600,7 @@ static struct wmi_driver dell_smm_wmi_driver = {
|
||||
},
|
||||
.id_table = dell_smm_wmi_id_table,
|
||||
.probe = dell_smm_wmi_probe,
|
||||
.no_singleton = true,
|
||||
};
|
||||
|
||||
/*
|
||||
|
||||
@@ -463,7 +463,7 @@ static ssize_t large_icm_show(struct device *dev,
|
||||
if (res.a0)
|
||||
return -EPERM;
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "0x%lx", res.a1);
|
||||
return sysfs_emit(buf, "0x%lx", res.a1);
|
||||
}
|
||||
|
||||
static ssize_t large_icm_store(struct device *dev,
|
||||
@@ -581,7 +581,7 @@ static ssize_t opn_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)opn_data);
|
||||
return sysfs_emit(buf, "%s", (char *)opn_data);
|
||||
}
|
||||
|
||||
static ssize_t opn_store(struct device *dev,
|
||||
@@ -632,7 +632,7 @@ static ssize_t sku_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)sku_data);
|
||||
return sysfs_emit(buf, "%s", (char *)sku_data);
|
||||
}
|
||||
|
||||
static ssize_t sku_store(struct device *dev,
|
||||
@@ -683,7 +683,7 @@ static ssize_t modl_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)modl_data);
|
||||
return sysfs_emit(buf, "%s", (char *)modl_data);
|
||||
}
|
||||
|
||||
static ssize_t modl_store(struct device *dev,
|
||||
@@ -734,7 +734,7 @@ static ssize_t sn_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)sn_data);
|
||||
return sysfs_emit(buf, "%s", (char *)sn_data);
|
||||
}
|
||||
|
||||
static ssize_t sn_store(struct device *dev,
|
||||
@@ -785,7 +785,7 @@ static ssize_t uuid_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)uuid_data);
|
||||
return sysfs_emit(buf, "%s", (char *)uuid_data);
|
||||
}
|
||||
|
||||
static ssize_t uuid_store(struct device *dev,
|
||||
@@ -836,7 +836,7 @@ static ssize_t rev_show(struct device *dev,
|
||||
}
|
||||
mutex_unlock(&mfg_ops_lock);
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%s", (char *)rev_data);
|
||||
return sysfs_emit(buf, "%s", (char *)rev_data);
|
||||
}
|
||||
|
||||
static ssize_t rev_store(struct device *dev,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -348,20 +348,6 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
|
||||
u32 regval, bit;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Validate if item related to received signal type is valid.
|
||||
* It should never happen, excepted the situation when some
|
||||
* piece of hardware is broken. In such situation just produce
|
||||
* error message and return. Caller must continue to handle the
|
||||
* signals from other devices if any.
|
||||
*/
|
||||
if (unlikely(!item)) {
|
||||
dev_err(priv->dev, "False signal: at offset:mask 0x%02x:0x%02x.\n",
|
||||
item->reg, item->mask);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Mask event. */
|
||||
ret = regmap_write(priv->regmap, item->reg + MLXREG_HOTPLUG_MASK_OFF,
|
||||
0);
|
||||
|
||||
@@ -74,6 +74,12 @@ static const struct software_node ssam_node_tmp_pprof = {
|
||||
.parent = &ssam_node_root,
|
||||
};
|
||||
|
||||
/* Fan speed function. */
|
||||
static const struct software_node ssam_node_fan_speed = {
|
||||
.name = "ssam:01:05:01:01:01",
|
||||
.parent = &ssam_node_root,
|
||||
};
|
||||
|
||||
/* Tablet-mode switch via KIP subsystem. */
|
||||
static const struct software_node ssam_node_kip_tablet_switch = {
|
||||
.name = "ssam:01:0e:01:00:01",
|
||||
@@ -305,6 +311,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
|
||||
&ssam_node_bat_ac,
|
||||
&ssam_node_bat_main,
|
||||
&ssam_node_tmp_pprof,
|
||||
&ssam_node_fan_speed,
|
||||
&ssam_node_pos_tablet_switch,
|
||||
&ssam_node_hid_kip_keyboard,
|
||||
&ssam_node_hid_kip_penstash,
|
||||
|
||||
@@ -56,8 +56,6 @@ config HUAWEI_WMI
|
||||
depends on INPUT
|
||||
select INPUT_SPARSEKMAP
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
select NEW_LEDS
|
||||
help
|
||||
This driver provides support for Huawei WMI hotkeys, battery charge
|
||||
@@ -269,8 +267,6 @@ config ASUS_WMI
|
||||
select INPUT_SPARSEKMAP
|
||||
select LEDS_CLASS
|
||||
select NEW_LEDS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
select ACPI_PLATFORM_PROFILE
|
||||
help
|
||||
Say Y here if you have a WMI aware Asus laptop (like Eee PCs or new
|
||||
@@ -374,6 +370,7 @@ config FUJITSU_LAPTOP
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
depends on BACKLIGHT_CLASS_DEVICE
|
||||
depends on ACPI_BATTERY
|
||||
depends on ACPI_VIDEO || ACPI_VIDEO = n
|
||||
select INPUT_SPARSEKMAP
|
||||
select NEW_LEDS
|
||||
@@ -507,8 +504,6 @@ config THINKPAD_ACPI
|
||||
select NVRAM
|
||||
select NEW_LEDS
|
||||
select LEDS_CLASS
|
||||
select LEDS_TRIGGERS
|
||||
select LEDS_TRIGGER_AUDIO
|
||||
help
|
||||
This is a driver for the IBM and Lenovo ThinkPad laptops. It adds
|
||||
support for Fn-Fx key combinations, Bluetooth control, video
|
||||
|
||||
@@ -276,6 +276,7 @@ static bool has_type_aa;
|
||||
static u16 commun_func_bitmap;
|
||||
static u8 commun_fn_key_number;
|
||||
static bool cycle_gaming_thermal_profile = true;
|
||||
static bool predator_v4;
|
||||
|
||||
module_param(mailled, int, 0444);
|
||||
module_param(brightness, int, 0444);
|
||||
@@ -284,6 +285,7 @@ module_param(force_series, int, 0444);
|
||||
module_param(force_caps, int, 0444);
|
||||
module_param(ec_raw_mode, bool, 0444);
|
||||
module_param(cycle_gaming_thermal_profile, bool, 0644);
|
||||
module_param(predator_v4, bool, 0444);
|
||||
MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
|
||||
MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
|
||||
MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
|
||||
@@ -292,6 +294,8 @@ MODULE_PARM_DESC(force_caps, "Force the capability bitmask to this value");
|
||||
MODULE_PARM_DESC(ec_raw_mode, "Enable EC raw mode");
|
||||
MODULE_PARM_DESC(cycle_gaming_thermal_profile,
|
||||
"Set thermal mode key in cycle mode. Disabling it sets the mode key in turbo toggle mode");
|
||||
MODULE_PARM_DESC(predator_v4,
|
||||
"Enable features for predator laptops that use predator sense v4");
|
||||
|
||||
struct acer_data {
|
||||
int mailled;
|
||||
@@ -584,6 +588,15 @@ static const struct dmi_system_id acer_quirks[] __initconst = {
|
||||
},
|
||||
.driver_data = &quirk_acer_predator_v4,
|
||||
},
|
||||
{
|
||||
.callback = dmi_matched,
|
||||
.ident = "Acer Predator PH16-71",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Predator PH16-71"),
|
||||
},
|
||||
.driver_data = &quirk_acer_predator_v4,
|
||||
},
|
||||
{
|
||||
.callback = set_force_caps,
|
||||
.ident = "Acer Aspire Switch 10E SW3-016",
|
||||
@@ -725,7 +738,9 @@ enum acer_predator_v4_thermal_profile_wmi {
|
||||
/* Find which quirks are needed for a particular vendor/ model pair */
|
||||
static void __init find_quirks(void)
|
||||
{
|
||||
if (!force_series) {
|
||||
if (predator_v4) {
|
||||
quirks = &quirk_acer_predator_v4;
|
||||
} else if (!force_series) {
|
||||
dmi_check_system(acer_quirks);
|
||||
dmi_check_system(non_acer_quirks);
|
||||
} else if (force_series == 2490) {
|
||||
|
||||
@@ -8,7 +8,7 @@ source "drivers/platform/x86/amd/pmc/Kconfig"
|
||||
|
||||
config AMD_HSMP
|
||||
tristate "AMD HSMP Driver"
|
||||
depends on AMD_NB && X86_64
|
||||
depends on AMD_NB && X86_64 && ACPI
|
||||
help
|
||||
The driver provides a way for user space tools to monitor and manage
|
||||
system management functionality on EPYC server CPUs from AMD.
|
||||
|
||||
+464
-120
File diff suppressed because it is too large
Load Diff
@@ -90,12 +90,96 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static union acpi_object *apts_if_call(struct amd_pmf_dev *pdev, u32 state_index)
|
||||
{
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
acpi_handle ahandle = ACPI_HANDLE(pdev->dev);
|
||||
struct acpi_object_list apts_if_arg_list;
|
||||
union acpi_object apts_if_args[3];
|
||||
acpi_status status;
|
||||
|
||||
apts_if_arg_list.count = 3;
|
||||
apts_if_arg_list.pointer = &apts_if_args[0];
|
||||
|
||||
apts_if_args[0].type = ACPI_TYPE_INTEGER;
|
||||
apts_if_args[0].integer.value = 1;
|
||||
apts_if_args[1].type = ACPI_TYPE_INTEGER;
|
||||
apts_if_args[1].integer.value = state_index;
|
||||
apts_if_args[2].type = ACPI_TYPE_INTEGER;
|
||||
apts_if_args[2].integer.value = 0;
|
||||
|
||||
status = acpi_evaluate_object(ahandle, "APTS", &apts_if_arg_list, &buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
dev_err(pdev->dev, "APTS state_idx:%u call failed\n", state_index);
|
||||
kfree(buffer.pointer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return buffer.pointer;
|
||||
}
|
||||
|
||||
static int apts_if_call_store_buffer(struct amd_pmf_dev *pdev,
|
||||
u32 index, void *data, size_t out_sz)
|
||||
{
|
||||
union acpi_object *info;
|
||||
size_t size;
|
||||
int err = 0;
|
||||
|
||||
info = apts_if_call(pdev, index);
|
||||
if (!info)
|
||||
return -EIO;
|
||||
|
||||
if (info->type != ACPI_TYPE_BUFFER) {
|
||||
dev_err(pdev->dev, "object is not a buffer\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
size = *(u16 *)info->buffer.pointer;
|
||||
if (info->buffer.length < size) {
|
||||
dev_err(pdev->dev, "buffer smaller than header size %u < %zu\n",
|
||||
info->buffer.length, size);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (size < out_sz) {
|
||||
dev_err(pdev->dev, "buffer too small %zu\n", size);
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(data, info->buffer.pointer, out_sz);
|
||||
out:
|
||||
kfree(info);
|
||||
return err;
|
||||
}
|
||||
|
||||
int is_apmf_func_supported(struct amd_pmf_dev *pdev, unsigned long index)
|
||||
{
|
||||
/* If bit-n is set, that indicates function n+1 is supported */
|
||||
return !!(pdev->supported_func & BIT(index - 1));
|
||||
}
|
||||
|
||||
int apts_get_static_slider_granular_v2(struct amd_pmf_dev *pdev,
|
||||
struct amd_pmf_apts_granular_output *data, u32 apts_idx)
|
||||
{
|
||||
if (!is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
|
||||
return -EINVAL;
|
||||
|
||||
return apts_if_call_store_buffer(pdev, apts_idx, data, sizeof(*data));
|
||||
}
|
||||
|
||||
int apmf_get_static_slider_granular_v2(struct amd_pmf_dev *pdev,
|
||||
struct apmf_static_slider_granular_output_v2 *data)
|
||||
{
|
||||
if (!is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
|
||||
return -EINVAL;
|
||||
|
||||
return apmf_if_call_store_buffer(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR,
|
||||
data, sizeof(*data));
|
||||
}
|
||||
|
||||
int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
|
||||
struct apmf_static_slider_granular_output *data)
|
||||
{
|
||||
@@ -140,6 +224,43 @@ static void apmf_sbios_heartbeat_notify(struct work_struct *work)
|
||||
kfree(info);
|
||||
}
|
||||
|
||||
int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag)
|
||||
{
|
||||
struct sbios_hb_event_v2 args = { };
|
||||
struct acpi_buffer params;
|
||||
union acpi_object *info;
|
||||
|
||||
args.size = sizeof(args);
|
||||
|
||||
switch (flag) {
|
||||
case ON_LOAD:
|
||||
args.load = 1;
|
||||
break;
|
||||
case ON_UNLOAD:
|
||||
args.unload = 1;
|
||||
break;
|
||||
case ON_SUSPEND:
|
||||
args.suspend = 1;
|
||||
break;
|
||||
case ON_RESUME:
|
||||
args.resume = 1;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev->dev, "Failed to send v2 heartbeat event, flag:0x%x\n", flag);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
params.length = sizeof(args);
|
||||
params.pointer = &args;
|
||||
|
||||
info = apmf_if_call(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2, ¶ms);
|
||||
if (!info)
|
||||
return -EIO;
|
||||
|
||||
kfree(info);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx)
|
||||
{
|
||||
union acpi_object *info;
|
||||
@@ -166,6 +287,11 @@ int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data
|
||||
return apmf_if_call_store_buffer(pdev, APMF_FUNC_AUTO_MODE, data, sizeof(*data));
|
||||
}
|
||||
|
||||
int apmf_get_sbios_requests_v2(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v2 *req)
|
||||
{
|
||||
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS, req, sizeof(*req));
|
||||
}
|
||||
|
||||
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req)
|
||||
{
|
||||
return apmf_if_call_store_buffer(pdev, APMF_FUNC_SBIOS_REQUESTS,
|
||||
@@ -218,8 +344,10 @@ static int apmf_if_verify_interface(struct amd_pmf_dev *pdev)
|
||||
return err;
|
||||
|
||||
pdev->supported_func = output.supported_functions;
|
||||
dev_dbg(pdev->dev, "supported functions:0x%x notifications:0x%x\n",
|
||||
output.supported_functions, output.notification_mask);
|
||||
dev_dbg(pdev->dev, "supported functions:0x%x notifications:0x%x version:%u\n",
|
||||
output.supported_functions, output.notification_mask, output.version);
|
||||
|
||||
pdev->pmf_if_version = output.version;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -320,7 +448,7 @@ void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
|
||||
{
|
||||
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
|
||||
|
||||
if (pmf_dev->hb_interval)
|
||||
if (pmf_dev->hb_interval && pmf_dev->pmf_if_version == PMF_IF_V1)
|
||||
cancel_delayed_work_sync(&pmf_dev->heart_beat);
|
||||
|
||||
if (is_apmf_func_supported(pmf_dev, APMF_FUNC_AUTO_MODE) &&
|
||||
@@ -344,7 +472,7 @@ int apmf_acpi_init(struct amd_pmf_dev *pmf_dev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (pmf_dev->hb_interval) {
|
||||
if (pmf_dev->hb_interval && pmf_dev->pmf_if_version == PMF_IF_V1) {
|
||||
/* send heartbeats only if the interval is not zero */
|
||||
INIT_DELAYED_WORK(&pmf_dev->heart_beat, apmf_sbios_heartbeat_notify);
|
||||
schedule_delayed_work(&pmf_dev->heart_beat, 0);
|
||||
|
||||
@@ -113,8 +113,9 @@ static void amd_pmf_dbgfs_unregister(struct amd_pmf_dev *dev)
|
||||
static void amd_pmf_dbgfs_register(struct amd_pmf_dev *dev)
|
||||
{
|
||||
dev->dbgfs_dir = debugfs_create_dir("amd_pmf", NULL);
|
||||
debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev,
|
||||
¤t_power_limits_fops);
|
||||
if (dev->pmf_if_version == PMF_IF_V1)
|
||||
debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev,
|
||||
¤t_power_limits_fops);
|
||||
}
|
||||
|
||||
int amd_pmf_get_power_source(void)
|
||||
@@ -299,6 +300,9 @@ static int amd_pmf_suspend_handler(struct device *dev)
|
||||
if (pdev->smart_pc_enabled)
|
||||
cancel_delayed_work_sync(&pdev->pb_work);
|
||||
|
||||
if (is_apmf_func_supported(pdev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
|
||||
amd_pmf_notify_sbios_heartbeat_event_v2(pdev, ON_SUSPEND);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -313,6 +317,9 @@ static int amd_pmf_resume_handler(struct device *dev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (is_apmf_func_supported(pdev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
|
||||
amd_pmf_notify_sbios_heartbeat_event_v2(pdev, ON_RESUME);
|
||||
|
||||
if (pdev->smart_pc_enabled)
|
||||
schedule_delayed_work(&pdev->pb_work, msecs_to_jiffies(2000));
|
||||
|
||||
@@ -443,6 +450,8 @@ static int amd_pmf_probe(struct platform_device *pdev)
|
||||
amd_pmf_dbgfs_register(dev);
|
||||
amd_pmf_init_features(dev);
|
||||
apmf_install_handler(dev);
|
||||
if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
|
||||
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_LOAD);
|
||||
|
||||
dev_info(dev->dev, "registered PMF device successfully\n");
|
||||
|
||||
@@ -454,6 +463,8 @@ static void amd_pmf_remove(struct platform_device *pdev)
|
||||
struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
|
||||
|
||||
amd_pmf_deinit_features(dev);
|
||||
if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
|
||||
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
|
||||
apmf_acpi_deinit(dev);
|
||||
amd_pmf_dbgfs_unregister(dev);
|
||||
mutex_destroy(&dev->lock);
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
#define POLICY_BUF_MAX_SZ 0x4b000
|
||||
#define POLICY_SIGN_COOKIE 0x31535024
|
||||
#define POLICY_COOKIE_OFFSET 0x10
|
||||
#define POLICY_COOKIE_LEN 0x14
|
||||
|
||||
struct cookie_header {
|
||||
u32 sign;
|
||||
u32 length;
|
||||
} __packed;
|
||||
|
||||
/* APMF Functions */
|
||||
#define APMF_FUNC_VERIFY_INTERFACE 0
|
||||
@@ -30,6 +34,7 @@
|
||||
#define APMF_FUNC_STATIC_SLIDER_GRANULAR 9
|
||||
#define APMF_FUNC_DYN_SLIDER_AC 11
|
||||
#define APMF_FUNC_DYN_SLIDER_DC 12
|
||||
#define APMF_FUNC_SBIOS_HEARTBEAT_V2 16
|
||||
|
||||
/* Message Definitions */
|
||||
#define SET_SPL 0x03 /* SPL: Sustained Power Limit */
|
||||
@@ -50,6 +55,8 @@
|
||||
#define GET_STT_LIMIT_APU 0x20
|
||||
#define GET_STT_LIMIT_HS2 0x21
|
||||
#define SET_P3T 0x23 /* P3T: Peak Package Power Limit */
|
||||
#define SET_PMF_PPT 0x25
|
||||
#define SET_PMF_PPT_APU_ONLY 0x26
|
||||
|
||||
/* OS slider update notification */
|
||||
#define DC_BEST_PERF 0
|
||||
@@ -83,6 +90,47 @@
|
||||
#define TA_OUTPUT_RESERVED_MEM 906
|
||||
#define MAX_OPERATION_PARAMS 4
|
||||
|
||||
#define PMF_IF_V1 1
|
||||
#define PMF_IF_V2 2
|
||||
|
||||
#define APTS_MAX_STATES 16
|
||||
|
||||
/* APTS PMF BIOS Interface */
|
||||
struct amd_pmf_apts_output {
|
||||
u16 table_version;
|
||||
u32 fan_table_idx;
|
||||
u32 pmf_ppt;
|
||||
u32 ppt_pmf_apu_only;
|
||||
u32 stt_min_limit;
|
||||
u8 stt_skin_temp_limit_apu;
|
||||
u8 stt_skin_temp_limit_hs2;
|
||||
} __packed;
|
||||
|
||||
struct amd_pmf_apts_granular_output {
|
||||
u16 size;
|
||||
struct amd_pmf_apts_output val;
|
||||
} __packed;
|
||||
|
||||
struct amd_pmf_apts_granular {
|
||||
u16 size;
|
||||
struct amd_pmf_apts_output val[APTS_MAX_STATES];
|
||||
};
|
||||
|
||||
struct sbios_hb_event_v2 {
|
||||
u16 size;
|
||||
u8 load;
|
||||
u8 unload;
|
||||
u8 suspend;
|
||||
u8 resume;
|
||||
} __packed;
|
||||
|
||||
enum sbios_hb_v2 {
|
||||
ON_LOAD,
|
||||
ON_UNLOAD,
|
||||
ON_SUSPEND,
|
||||
ON_RESUME,
|
||||
};
|
||||
|
||||
/* AMD PMF BIOS interfaces */
|
||||
struct apmf_verify_interface {
|
||||
u16 size;
|
||||
@@ -114,6 +162,18 @@ struct apmf_sbios_req {
|
||||
u8 skin_temp_hs2;
|
||||
} __packed;
|
||||
|
||||
struct apmf_sbios_req_v2 {
|
||||
u16 size;
|
||||
u32 pending_req;
|
||||
u8 rsd;
|
||||
u32 ppt_pmf;
|
||||
u32 ppt_pmf_apu_only;
|
||||
u32 stt_min_limit;
|
||||
u8 skin_temp_apu;
|
||||
u8 skin_temp_hs2;
|
||||
u32 custom_policy[10];
|
||||
} __packed;
|
||||
|
||||
struct apmf_fan_idx {
|
||||
u16 size;
|
||||
u8 fan_ctl_mode;
|
||||
@@ -194,6 +254,14 @@ enum power_modes {
|
||||
POWER_MODE_MAX,
|
||||
};
|
||||
|
||||
enum power_modes_v2 {
|
||||
POWER_MODE_BEST_PERFORMANCE,
|
||||
POWER_MODE_BALANCED,
|
||||
POWER_MODE_BEST_POWER_EFFICIENCY,
|
||||
POWER_MODE_ENERGY_SAVE,
|
||||
POWER_MODE_V2_MAX,
|
||||
};
|
||||
|
||||
struct amd_pmf_dev {
|
||||
void __iomem *regbase;
|
||||
void __iomem *smu_virt_addr;
|
||||
@@ -229,10 +297,15 @@ struct amd_pmf_dev {
|
||||
struct delayed_work pb_work;
|
||||
struct pmf_action_table *prev_data;
|
||||
u64 policy_addr;
|
||||
void *policy_base;
|
||||
void __iomem *policy_base;
|
||||
bool smart_pc_enabled;
|
||||
u16 pmf_if_version;
|
||||
};
|
||||
|
||||
struct apmf_sps_prop_granular_v2 {
|
||||
u8 power_states[POWER_SOURCE_MAX][POWER_MODE_V2_MAX];
|
||||
} __packed;
|
||||
|
||||
struct apmf_sps_prop_granular {
|
||||
u32 fppt;
|
||||
u32 sppt;
|
||||
@@ -254,6 +327,16 @@ struct amd_pmf_static_slider_granular {
|
||||
struct apmf_sps_prop_granular prop[POWER_SOURCE_MAX][POWER_MODE_MAX];
|
||||
};
|
||||
|
||||
struct apmf_static_slider_granular_output_v2 {
|
||||
u16 size;
|
||||
struct apmf_sps_prop_granular_v2 sps_idx;
|
||||
} __packed;
|
||||
|
||||
struct amd_pmf_static_slider_granular_v2 {
|
||||
u16 size;
|
||||
struct apmf_sps_prop_granular_v2 sps_idx;
|
||||
};
|
||||
|
||||
struct os_power_slider {
|
||||
u16 size;
|
||||
u8 slider_event;
|
||||
@@ -585,6 +668,7 @@ int amd_pmf_get_power_source(void);
|
||||
int apmf_install_handler(struct amd_pmf_dev *pmf_dev);
|
||||
int apmf_os_power_slider_update(struct amd_pmf_dev *dev, u8 flag);
|
||||
int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer);
|
||||
int amd_pmf_notify_sbios_heartbeat_event_v2(struct amd_pmf_dev *dev, u8 flag);
|
||||
|
||||
/* SPS Layer */
|
||||
int amd_pmf_get_pprof_modes(struct amd_pmf_dev *pmf);
|
||||
@@ -602,6 +686,10 @@ const char *amd_pmf_source_as_str(unsigned int state);
|
||||
|
||||
int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
|
||||
int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf);
|
||||
int apmf_get_static_slider_granular_v2(struct amd_pmf_dev *dev,
|
||||
struct apmf_static_slider_granular_output_v2 *data);
|
||||
int apts_get_static_slider_granular_v2(struct amd_pmf_dev *pdev,
|
||||
struct amd_pmf_apts_granular_output *data, u32 apts_idx);
|
||||
|
||||
/* Auto Mode Layer */
|
||||
int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
|
||||
@@ -609,6 +697,7 @@ void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev);
|
||||
void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev);
|
||||
void amd_pmf_trans_automode(struct amd_pmf_dev *dev, int socket_power, ktime_t time_elapsed_ms);
|
||||
int apmf_get_sbios_requests(struct amd_pmf_dev *pdev, struct apmf_sbios_req *req);
|
||||
int apmf_get_sbios_requests_v2(struct amd_pmf_dev *pdev, struct apmf_sbios_req_v2 *req);
|
||||
|
||||
void amd_pmf_update_2_cql(struct amd_pmf_dev *dev, bool is_cql_event);
|
||||
int amd_pmf_reset_amt(struct amd_pmf_dev *dev);
|
||||
|
||||
@@ -10,9 +10,27 @@
|
||||
|
||||
#include "pmf.h"
|
||||
|
||||
static struct amd_pmf_static_slider_granular_v2 config_store_v2;
|
||||
static struct amd_pmf_static_slider_granular config_store;
|
||||
static struct amd_pmf_apts_granular apts_config_store;
|
||||
|
||||
#ifdef CONFIG_AMD_PMF_DEBUG
|
||||
static const char *slider_v2_as_str(unsigned int state)
|
||||
{
|
||||
switch (state) {
|
||||
case POWER_MODE_BEST_PERFORMANCE:
|
||||
return "Best Performance";
|
||||
case POWER_MODE_BALANCED:
|
||||
return "Balanced";
|
||||
case POWER_MODE_BEST_POWER_EFFICIENCY:
|
||||
return "Best Power Efficiency";
|
||||
case POWER_MODE_ENERGY_SAVE:
|
||||
return "Energy Save";
|
||||
default:
|
||||
return "Unknown Power Mode";
|
||||
}
|
||||
}
|
||||
|
||||
static const char *slider_as_str(unsigned int state)
|
||||
{
|
||||
switch (state) {
|
||||
@@ -63,10 +81,88 @@ static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *dat
|
||||
|
||||
pr_debug("Static Slider Data - END\n");
|
||||
}
|
||||
|
||||
static void amd_pmf_dump_sps_defaults_v2(struct amd_pmf_static_slider_granular_v2 *data)
|
||||
{
|
||||
unsigned int i, j;
|
||||
|
||||
pr_debug("Static Slider APTS state index data - BEGIN");
|
||||
pr_debug("size: %u\n", data->size);
|
||||
|
||||
for (i = 0; i < POWER_SOURCE_MAX; i++)
|
||||
for (j = 0; j < POWER_MODE_V2_MAX; j++)
|
||||
pr_debug("%s %s: %u\n", amd_pmf_source_as_str(i), slider_v2_as_str(j),
|
||||
data->sps_idx.power_states[i][j]);
|
||||
|
||||
pr_debug("Static Slider APTS state index data - END\n");
|
||||
}
|
||||
|
||||
static void amd_pmf_dump_apts_sps_defaults(struct amd_pmf_apts_granular *info)
|
||||
{
|
||||
int i;
|
||||
|
||||
pr_debug("Static Slider APTS index default values data - BEGIN");
|
||||
|
||||
for (i = 0; i < APTS_MAX_STATES; i++) {
|
||||
pr_debug("Table Version[%d] = %u\n", i, info->val[i].table_version);
|
||||
pr_debug("Fan Index[%d] = %u\n", i, info->val[i].fan_table_idx);
|
||||
pr_debug("PPT[%d] = %u\n", i, info->val[i].pmf_ppt);
|
||||
pr_debug("PPT APU[%d] = %u\n", i, info->val[i].ppt_pmf_apu_only);
|
||||
pr_debug("STT Min[%d] = %u\n", i, info->val[i].stt_min_limit);
|
||||
pr_debug("STT APU[%d] = %u\n", i, info->val[i].stt_skin_temp_limit_apu);
|
||||
pr_debug("STT HS2[%d] = %u\n", i, info->val[i].stt_skin_temp_limit_hs2);
|
||||
}
|
||||
|
||||
pr_debug("Static Slider APTS index default values data - END");
|
||||
}
|
||||
#else
|
||||
static void amd_pmf_dump_sps_defaults(struct amd_pmf_static_slider_granular *data) {}
|
||||
static void amd_pmf_dump_sps_defaults_v2(struct amd_pmf_static_slider_granular_v2 *data) {}
|
||||
static void amd_pmf_dump_apts_sps_defaults(struct amd_pmf_apts_granular *info) {}
|
||||
#endif
|
||||
|
||||
static void amd_pmf_load_apts_defaults_sps_v2(struct amd_pmf_dev *pdev)
|
||||
{
|
||||
struct amd_pmf_apts_granular_output output;
|
||||
struct amd_pmf_apts_output *ps;
|
||||
int i;
|
||||
|
||||
memset(&apts_config_store, 0, sizeof(apts_config_store));
|
||||
|
||||
ps = apts_config_store.val;
|
||||
|
||||
for (i = 0; i < APTS_MAX_STATES; i++) {
|
||||
apts_get_static_slider_granular_v2(pdev, &output, i);
|
||||
ps[i].table_version = output.val.table_version;
|
||||
ps[i].fan_table_idx = output.val.fan_table_idx;
|
||||
ps[i].pmf_ppt = output.val.pmf_ppt;
|
||||
ps[i].ppt_pmf_apu_only = output.val.ppt_pmf_apu_only;
|
||||
ps[i].stt_min_limit = output.val.stt_min_limit;
|
||||
ps[i].stt_skin_temp_limit_apu = output.val.stt_skin_temp_limit_apu;
|
||||
ps[i].stt_skin_temp_limit_hs2 = output.val.stt_skin_temp_limit_hs2;
|
||||
}
|
||||
|
||||
amd_pmf_dump_apts_sps_defaults(&apts_config_store);
|
||||
}
|
||||
|
||||
static void amd_pmf_load_defaults_sps_v2(struct amd_pmf_dev *dev)
|
||||
{
|
||||
struct apmf_static_slider_granular_output_v2 output;
|
||||
unsigned int i, j;
|
||||
|
||||
memset(&config_store_v2, 0, sizeof(config_store_v2));
|
||||
apmf_get_static_slider_granular_v2(dev, &output);
|
||||
|
||||
config_store_v2.size = output.size;
|
||||
|
||||
for (i = 0; i < POWER_SOURCE_MAX; i++)
|
||||
for (j = 0; j < POWER_MODE_V2_MAX; j++)
|
||||
config_store_v2.sps_idx.power_states[i][j] =
|
||||
output.sps_idx.power_states[i][j];
|
||||
|
||||
amd_pmf_dump_sps_defaults_v2(&config_store_v2);
|
||||
}
|
||||
|
||||
static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
|
||||
{
|
||||
struct apmf_static_slider_granular_output output;
|
||||
@@ -94,6 +190,19 @@ static void amd_pmf_load_defaults_sps(struct amd_pmf_dev *dev)
|
||||
amd_pmf_dump_sps_defaults(&config_store);
|
||||
}
|
||||
|
||||
static void amd_pmf_update_slider_v2(struct amd_pmf_dev *dev, int idx)
|
||||
{
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT, false, apts_config_store.val[idx].pmf_ppt, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_PMF_PPT_APU_ONLY, false,
|
||||
apts_config_store.val[idx].ppt_pmf_apu_only, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_MIN_LIMIT, false,
|
||||
apts_config_store.val[idx].stt_min_limit, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_APU, false,
|
||||
apts_config_store.val[idx].stt_skin_temp_limit_apu, NULL);
|
||||
amd_pmf_send_cmd(dev, SET_STT_LIMIT_HS2, false,
|
||||
apts_config_store.val[idx].stt_skin_temp_limit_hs2, NULL);
|
||||
}
|
||||
|
||||
void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
|
||||
struct amd_pmf_static_slider_granular *table)
|
||||
{
|
||||
@@ -126,6 +235,32 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
|
||||
}
|
||||
}
|
||||
|
||||
static int amd_pmf_update_sps_power_limits_v2(struct amd_pmf_dev *pdev, int pwr_mode)
|
||||
{
|
||||
int src, index;
|
||||
|
||||
src = amd_pmf_get_power_source();
|
||||
|
||||
switch (pwr_mode) {
|
||||
case POWER_MODE_PERFORMANCE:
|
||||
index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_PERFORMANCE];
|
||||
amd_pmf_update_slider_v2(pdev, index);
|
||||
break;
|
||||
case POWER_MODE_BALANCED_POWER:
|
||||
index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BALANCED];
|
||||
amd_pmf_update_slider_v2(pdev, index);
|
||||
break;
|
||||
case POWER_MODE_POWER_SAVER:
|
||||
index = config_store_v2.sps_idx.power_states[src][POWER_MODE_BEST_POWER_EFFICIENCY];
|
||||
amd_pmf_update_slider_v2(pdev, index);
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf)
|
||||
{
|
||||
int mode;
|
||||
@@ -134,6 +269,9 @@ int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf)
|
||||
if (mode < 0)
|
||||
return mode;
|
||||
|
||||
if (pmf->pmf_if_version == PMF_IF_V2)
|
||||
return amd_pmf_update_sps_power_limits_v2(pmf, mode);
|
||||
|
||||
amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
|
||||
|
||||
return 0;
|
||||
@@ -256,7 +394,12 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev)
|
||||
dev->current_profile = PLATFORM_PROFILE_BALANCED;
|
||||
|
||||
if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
|
||||
amd_pmf_load_defaults_sps(dev);
|
||||
if (dev->pmf_if_version == PMF_IF_V2) {
|
||||
amd_pmf_load_defaults_sps_v2(dev);
|
||||
amd_pmf_load_apts_defaults_sps_v2(dev);
|
||||
} else {
|
||||
amd_pmf_load_defaults_sps(dev);
|
||||
}
|
||||
|
||||
/* update SPS balanced power mode thermals */
|
||||
amd_pmf_set_sps_power_limits(dev);
|
||||
|
||||
@@ -246,19 +246,24 @@ static void amd_pmf_invoke_cmd(struct work_struct *work)
|
||||
|
||||
static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
|
||||
{
|
||||
u32 cookie, length;
|
||||
struct cookie_header *header;
|
||||
int res;
|
||||
|
||||
cookie = readl(dev->policy_buf + POLICY_COOKIE_OFFSET);
|
||||
length = readl(dev->policy_buf + POLICY_COOKIE_LEN);
|
||||
if (dev->policy_sz < POLICY_COOKIE_OFFSET + sizeof(*header))
|
||||
return -EINVAL;
|
||||
|
||||
if (cookie != POLICY_SIGN_COOKIE || !length) {
|
||||
header = (struct cookie_header *)(dev->policy_buf + POLICY_COOKIE_OFFSET);
|
||||
|
||||
if (header->sign != POLICY_SIGN_COOKIE || !header->length) {
|
||||
dev_dbg(dev->dev, "cookie doesn't match\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (dev->policy_sz < header->length + 512)
|
||||
return -EINVAL;
|
||||
|
||||
/* Update the actual length */
|
||||
dev->policy_sz = length + 512;
|
||||
dev->policy_sz = header->length + 512;
|
||||
res = amd_pmf_invoke_cmd_init(dev);
|
||||
if (res == TA_PMF_TYPE_SUCCESS) {
|
||||
/* Now its safe to announce that smart pc is enabled */
|
||||
@@ -271,7 +276,7 @@ static int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev)
|
||||
} else {
|
||||
dev_err(dev->dev, "ta invoke cmd init failed err: %x\n", res);
|
||||
dev->smart_pc_enabled = false;
|
||||
return res;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -311,8 +316,8 @@ static ssize_t amd_pmf_get_pb_data(struct file *filp, const char __user *buf,
|
||||
|
||||
amd_pmf_hex_dump_pb(dev);
|
||||
ret = amd_pmf_start_policy_engine(dev);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return length;
|
||||
}
|
||||
@@ -453,7 +458,7 @@ int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev)
|
||||
goto error;
|
||||
}
|
||||
|
||||
memcpy(dev->policy_buf, dev->policy_base, dev->policy_sz);
|
||||
memcpy_fromio(dev->policy_buf, dev->policy_base, dev->policy_sz);
|
||||
|
||||
amd_pmf_hex_dump_pb(dev);
|
||||
|
||||
|
||||
@@ -101,13 +101,6 @@ module_param(fnlock_default, bool, 0444);
|
||||
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
|
||||
|
||||
#define ASUS_ACPI_UID_ASUSWMI "ASUSWMI"
|
||||
#define ASUS_ACPI_UID_ATK "ATK"
|
||||
|
||||
#define WMI_EVENT_QUEUE_SIZE 0x10
|
||||
#define WMI_EVENT_QUEUE_END 0x1
|
||||
#define WMI_EVENT_MASK 0xFFFF
|
||||
/* The WMI hotkey event value is always the same. */
|
||||
#define WMI_EVENT_VALUE_ATK 0xFF
|
||||
|
||||
#define WMI_EVENT_MASK 0xFFFF
|
||||
|
||||
@@ -219,7 +212,6 @@ struct asus_wmi {
|
||||
int dsts_id;
|
||||
int spec;
|
||||
int sfun;
|
||||
bool wmi_event_queue;
|
||||
|
||||
struct input_dev *inputdev;
|
||||
struct backlight_device *backlight_device;
|
||||
@@ -489,7 +481,17 @@ static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args)
|
||||
|
||||
static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
|
||||
{
|
||||
return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
|
||||
int err;
|
||||
|
||||
err = asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (*retval == ~0)
|
||||
return -ENODEV;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
|
||||
@@ -1620,7 +1622,6 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
|
||||
if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_MICMUTE_LED)) {
|
||||
asus->micmute_led.name = "platform::micmute";
|
||||
asus->micmute_led.max_brightness = 1;
|
||||
asus->micmute_led.brightness = ledtrig_audio_get(LED_AUDIO_MICMUTE);
|
||||
asus->micmute_led.brightness_set_blocking = micmute_led_set;
|
||||
asus->micmute_led.default_trigger = "audio-micmute";
|
||||
|
||||
@@ -4020,50 +4021,14 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
|
||||
static void asus_wmi_notify(u32 value, void *context)
|
||||
{
|
||||
struct asus_wmi *asus = context;
|
||||
int code;
|
||||
int i;
|
||||
int code = asus_wmi_get_event_code(value);
|
||||
|
||||
for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
|
||||
code = asus_wmi_get_event_code(value);
|
||||
if (code < 0) {
|
||||
pr_warn("Failed to get notify code: %d\n", code);
|
||||
return;
|
||||
}
|
||||
|
||||
if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
|
||||
return;
|
||||
|
||||
asus_wmi_handle_event_code(code, asus);
|
||||
|
||||
/*
|
||||
* Double check that queue is present:
|
||||
* ATK (with queue) uses 0xff, ASUSWMI (without) 0xd2.
|
||||
*/
|
||||
if (!asus->wmi_event_queue || value != WMI_EVENT_VALUE_ATK)
|
||||
return;
|
||||
if (code < 0) {
|
||||
pr_warn("Failed to get notify code: %d\n", code);
|
||||
return;
|
||||
}
|
||||
|
||||
pr_warn("Failed to process event queue, last code: 0x%x\n", code);
|
||||
}
|
||||
|
||||
static int asus_wmi_notify_queue_flush(struct asus_wmi *asus)
|
||||
{
|
||||
int code;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
|
||||
code = asus_wmi_get_event_code(WMI_EVENT_VALUE_ATK);
|
||||
if (code < 0) {
|
||||
pr_warn("Failed to get event during flush: %d\n", code);
|
||||
return code;
|
||||
}
|
||||
|
||||
if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
|
||||
return 0;
|
||||
}
|
||||
|
||||
pr_warn("Failed to flush event queue\n");
|
||||
return -EIO;
|
||||
asus_wmi_handle_event_code(code, asus);
|
||||
}
|
||||
|
||||
/* Sysfs **********************************************************************/
|
||||
@@ -4303,23 +4268,6 @@ static int asus_wmi_platform_init(struct asus_wmi *asus)
|
||||
asus->dsts_id = ASUS_WMI_METHODID_DSTS;
|
||||
}
|
||||
|
||||
/*
|
||||
* Some devices can have multiple event codes stored in a queue before
|
||||
* the module load if it was unloaded intermittently after calling
|
||||
* the INIT method (enables event handling). The WMI notify handler is
|
||||
* expected to retrieve all event codes until a retrieved code equals
|
||||
* queue end marker (One or Ones). Old codes are flushed from the queue
|
||||
* upon module load. Not enabling this when it should be has minimal
|
||||
* visible impact so fall back if anything goes wrong.
|
||||
*/
|
||||
wmi_uid = wmi_get_acpi_device_uid(asus->driver->event_guid);
|
||||
if (wmi_uid && !strcmp(wmi_uid, ASUS_ACPI_UID_ATK)) {
|
||||
dev_info(dev, "Detected ATK, enable event queue\n");
|
||||
|
||||
if (!asus_wmi_notify_queue_flush(asus))
|
||||
asus->wmi_event_queue = true;
|
||||
}
|
||||
|
||||
/* CWAP allow to define the behavior of the Fn+F2 key,
|
||||
* this method doesn't seems to be present on Eee PCs */
|
||||
if (asus->driver->quirks->wapf >= 0)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user