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:
Linus Torvalds
2024-03-14 10:44:09 -07:00
58 changed files with 1843 additions and 708 deletions
@@ -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
+4 -3
View File
@@ -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
+4 -1
View File
@@ -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.
+53 -1
View File
@@ -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();
}
+1 -12
View File
@@ -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;
+1
View File
@@ -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,
};
/*
+7 -7
View File
@@ -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,
+1 -6
View File
@@ -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
+16 -1
View File
@@ -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) {
+1 -1
View File
@@ -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.
File diff suppressed because it is too large Load Diff
+132 -4
View File
@@ -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, &params);
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);
+13 -2
View File
@@ -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,
&current_power_limits_fops);
if (dev->pmf_if_version == PMF_IF_V1)
debugfs_create_file("current_power_limits", 0644, dev->dbgfs_dir, dev,
&current_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);
+91 -2
View File
@@ -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);
+144 -1
View File
@@ -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);
+14 -9
View File
@@ -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);
+16 -68
View File
@@ -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