summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-09-19 09:16:04 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2024-09-19 09:16:04 +0200
commit84bbfe6b6435658132df2880258d34babe46d3e0 (patch)
tree3066cce5c7ab4daa2268230204f1124f4ce3faeb /drivers/platform
parent2a17bb8c204f2b6461524a1b52ace2dbe097eaf7 (diff)
parent837acb691c844d0525f4ac86f2a2ce55a9706908 (diff)
downloadlwn-84bbfe6b6435658132df2880258d34babe46d3e0.tar.gz
lwn-84bbfe6b6435658132df2880258d34babe46d3e0.zip
Merge tag 'platform-drivers-x86-v6.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform drivers updates from Hans de Goede: - asus-wmi: Add support for vivobook fan profiles - dell-laptop: Add knobs to change battery charge settings - lg-laptop: Add operation region support - intel-uncore-freq: Add support for efficiency latency control - intel/ifs: Add SBAF test support - intel/pmc: Ignore all LTRs during suspend - platform/surface: Support for arm64 based Surface devices - wmi: Pass event data directly to legacy notify handlers - x86/platform/geode: switch GPIO buttons and LEDs to software properties - bunch of small cleanups, fixes, hw-id additions, etc. * tag 'platform-drivers-x86-v6.12-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (65 commits) MAINTAINERS: adjust file entry in INTEL MID PLATFORM platform/x86: x86-android-tablets: Adjust Xiaomi Pad 2 bottom bezel touch buttons LED platform/mellanox: mlxbf-pmc: fix lockdep warning platform/x86/amd: pmf: Add quirk for TUF Gaming A14 platform/x86: touchscreen_dmi: add nanote-next quirk platform/x86: asus-wmi: don't fail if platform_profile already registered platform/x86: asus-wmi: add debug print in more key places platform/x86: intel_scu_wdt: Move intel_scu_wdt.h to x86 subfolder platform/x86: intel_scu_ipc: Move intel_scu_ipc.h out of arch/x86/include/asm MAINTAINERS: Add Intel MID section platform/x86: panasonic-laptop: Add support for programmable buttons platform/olpc: Remove redundant null pointer checks in olpc_ec_setup_debugfs() platform/x86: intel/pmc: Ignore all LTRs during suspend platform/x86: wmi: Call both legacy and WMI driver notify handlers platform/x86: wmi: Merge get_event_data() with wmi_get_notify_data() platform/x86: wmi: Remove wmi_get_event_data() platform/x86: wmi: Pass event data directly to legacy notify handlers platform/x86: thinkpad_acpi: Fix uninitialized symbol 's' warning platform/x86: x86-android-tablets: Fix spelling in the comments platform/x86: ideapad-laptop: Make the scope_guard() clear of its scope ...
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/mellanox/mlxbf-pmc.c5
-rw-r--r--drivers/platform/olpc/olpc-ec.c3
-rw-r--r--drivers/platform/surface/aggregator/bus.c2
-rw-r--r--drivers/platform/surface/aggregator/controller.c67
-rw-r--r--drivers/platform/surface/aggregator/core.c82
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c45
-rw-r--r--drivers/platform/x86/Kconfig3
-rw-r--r--drivers/platform/x86/acer-wmi.c19
-rw-r--r--drivers/platform/x86/amd/pmf/acpi.c31
-rw-r--r--drivers/platform/x86/amd/pmf/core.c20
-rw-r--r--drivers/platform/x86/amd/pmf/pmf-quirks.c8
-rw-r--r--drivers/platform/x86/amd/pmf/pmf.h73
-rw-r--r--drivers/platform/x86/amd/pmf/spc.c51
-rw-r--r--drivers/platform/x86/amd/pmf/tee-if.c40
-rw-r--r--drivers/platform/x86/asus-laptop.c3
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c4
-rw-r--r--drivers/platform/x86/asus-wmi.c224
-rw-r--r--drivers/platform/x86/dell/Kconfig1
-rw-r--r--drivers/platform/x86/dell/dell-laptop.c417
-rw-r--r--drivers/platform/x86/dell/dell-smbios.h7
-rw-r--r--drivers/platform/x86/dell/dell-wmi-aio.c13
-rw-r--r--drivers/platform/x86/eeepc-laptop.c3
-rw-r--r--drivers/platform/x86/eeepc-wmi.c4
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c9
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c16
-rw-r--r--drivers/platform/x86/huawei-wmi.c14
-rw-r--r--drivers/platform/x86/ideapad-laptop.c191
-rw-r--r--drivers/platform/x86/ideapad-laptop.h139
-rw-r--r--drivers/platform/x86/intel/hid.c7
-rw-r--r--drivers/platform/x86/intel/ifs/core.c33
-rw-r--r--drivers/platform/x86/intel/ifs/ifs.h92
-rw-r--r--drivers/platform/x86/intel/ifs/load.c40
-rw-r--r--drivers/platform/x86/intel/ifs/runtest.c233
-rw-r--r--drivers/platform/x86/intel/int3472/Makefile9
-rw-r--r--drivers/platform/x86/intel/int3472/common.c7
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c9
-rw-r--r--drivers/platform/x86/intel/oaktrail.c3
-rw-r--r--drivers/platform/x86/intel/pmc/core.c83
-rw-r--r--drivers/platform/x86/intel/pmc/core.h12
-rw-r--r--drivers/platform/x86/intel/pmc/core_ssram.c6
-rw-r--r--drivers/platform/x86/intel/pmt/class.c28
-rw-r--r--drivers/platform/x86/intel/pmt/class.h10
-rw-r--r--drivers/platform/x86/intel/pmt/crashlog.c2
-rw-r--r--drivers/platform/x86/intel/pmt/telemetry.c12
-rw-r--r--drivers/platform/x86/intel/sdsi.c3
-rw-r--r--drivers/platform/x86/intel/speed_select_if/isst_if_common.c42
-rw-r--r--drivers/platform/x86/intel/tpmi.c3
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c42
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h17
-rw-r--r--drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c165
-rw-r--r--drivers/platform/x86/intel/vsec.c8
-rw-r--r--drivers/platform/x86/intel/vsec.h108
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c2
-rw-r--r--drivers/platform/x86/intel_scu_ipcutil.c2
-rw-r--r--drivers/platform/x86/intel_scu_pcidrv.c2
-rw-r--r--drivers/platform/x86/intel_scu_pltdrv.c2
-rw-r--r--drivers/platform/x86/intel_scu_wdt.c3
-rw-r--r--drivers/platform/x86/lenovo-ymc.c2
-rw-r--r--drivers/platform/x86/lg-laptop.c149
-rw-r--r--drivers/platform/x86/msi-wmi.c20
-rw-r--r--drivers/platform/x86/panasonic-laptop.c16
-rw-r--r--drivers/platform/x86/samsung-laptop.c5
-rw-r--r--drivers/platform/x86/serial-multi-instantiate.c32
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c145
-rw-r--r--drivers/platform/x86/toshiba-wmi.c15
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c26
-rw-r--r--drivers/platform/x86/wmi.c143
-rw-r--r--drivers/platform/x86/x86-android-tablets/Kconfig2
-rw-r--r--drivers/platform/x86/x86-android-tablets/asus.c8
-rw-r--r--drivers/platform/x86/x86-android-tablets/core.c20
-rw-r--r--drivers/platform/x86/x86-android-tablets/dmi.c16
-rw-r--r--drivers/platform/x86/x86-android-tablets/lenovo.c22
-rw-r--r--drivers/platform/x86/x86-android-tablets/other.c40
-rw-r--r--drivers/platform/x86/x86-android-tablets/shared-psy-info.c4
-rw-r--r--drivers/platform/x86/x86-android-tablets/x86-android-tablets.h2
75 files changed, 2229 insertions, 917 deletions
diff --git a/drivers/platform/mellanox/mlxbf-pmc.c b/drivers/platform/mellanox/mlxbf-pmc.c
index 4ed9c7fd2b62..9d18dfca6a67 100644
--- a/drivers/platform/mellanox/mlxbf-pmc.c
+++ b/drivers/platform/mellanox/mlxbf-pmc.c
@@ -1774,6 +1774,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
/* "event_list" sysfs to list events supported by the block */
attr = &pmc->block[blk_num].attr_event_list;
+ sysfs_attr_init(&attr->dev_attr.attr);
attr->dev_attr.attr.mode = 0444;
attr->dev_attr.show = mlxbf_pmc_event_list_show;
attr->nr = blk_num;
@@ -1787,6 +1788,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
if (strstr(pmc->block_name[blk_num], "l3cache") ||
((pmc->block[blk_num].type == MLXBF_PMC_TYPE_CRSPACE))) {
attr = &pmc->block[blk_num].attr_enable;
+ sysfs_attr_init(&attr->dev_attr.attr);
attr->dev_attr.attr.mode = 0644;
attr->dev_attr.show = mlxbf_pmc_enable_show;
attr->dev_attr.store = mlxbf_pmc_enable_store;
@@ -1814,6 +1816,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
/* "eventX" and "counterX" sysfs to program and read counter values */
for (j = 0; j < pmc->block[blk_num].counters; ++j) {
attr = &pmc->block[blk_num].attr_counter[j];
+ sysfs_attr_init(&attr->dev_attr.attr);
attr->dev_attr.attr.mode = 0644;
attr->dev_attr.show = mlxbf_pmc_counter_show;
attr->dev_attr.store = mlxbf_pmc_counter_store;
@@ -1826,6 +1829,7 @@ static int mlxbf_pmc_init_perftype_counter(struct device *dev, unsigned int blk_
attr = NULL;
attr = &pmc->block[blk_num].attr_event[j];
+ sysfs_attr_init(&attr->dev_attr.attr);
attr->dev_attr.attr.mode = 0644;
attr->dev_attr.show = mlxbf_pmc_event_show;
attr->dev_attr.store = mlxbf_pmc_event_store;
@@ -1861,6 +1865,7 @@ static int mlxbf_pmc_init_perftype_reg(struct device *dev, unsigned int blk_num)
while (count > 0) {
--count;
attr = &pmc->block[blk_num].attr_event[count];
+ sysfs_attr_init(&attr->dev_attr.attr);
attr->dev_attr.attr.mode = 0644;
attr->dev_attr.show = mlxbf_pmc_counter_show;
attr->dev_attr.store = mlxbf_pmc_counter_store;
diff --git a/drivers/platform/olpc/olpc-ec.c b/drivers/platform/olpc/olpc-ec.c
index 921520475ff6..48e9861bb571 100644
--- a/drivers/platform/olpc/olpc-ec.c
+++ b/drivers/platform/olpc/olpc-ec.c
@@ -332,9 +332,6 @@ static struct dentry *olpc_ec_setup_debugfs(void)
struct dentry *dbgfs_dir;
dbgfs_dir = debugfs_create_dir("olpc-ec", NULL);
- if (IS_ERR_OR_NULL(dbgfs_dir))
- return NULL;
-
debugfs_create_file("cmd", 0600, dbgfs_dir, NULL, &ec_dbgfs_ops);
return dbgfs_dir;
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index af8d573aae93..d68d231e716e 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -6,6 +6,7 @@
*/
#include <linux/device.h>
+#include <linux/of.h>
#include <linux/property.h>
#include <linux/slab.h>
@@ -441,6 +442,7 @@ static int ssam_add_client_device(struct device *parent, struct ssam_controller
sdev->dev.parent = parent;
sdev->dev.fwnode = fwnode_handle_get(node);
+ sdev->dev.of_node = to_of_node(node);
status = ssam_device_add(sdev);
if (status)
diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
index 7e89f547999b..a265e667538c 100644
--- a/drivers/platform/surface/aggregator/controller.c
+++ b/drivers/platform/surface/aggregator/controller.c
@@ -1104,13 +1104,6 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
u64 funcs;
int status;
- /* Set defaults. */
- caps->ssh_power_profile = U32_MAX;
- caps->screen_on_sleep_idle_timeout = U32_MAX;
- caps->screen_off_sleep_idle_timeout = U32_MAX;
- caps->d3_closes_handle = false;
- caps->ssh_buffer_size = U32_MAX;
-
/* Pre-load supported DSM functions. */
status = ssam_dsm_get_functions(handle, &funcs);
if (status)
@@ -1150,6 +1143,52 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
}
/**
+ * ssam_controller_caps_load_from_of() - Load controller capabilities from OF/DT.
+ * @dev: A pointer to the controller device
+ * @caps: Where to store the capabilities in.
+ *
+ * Return: Returns zero on success, a negative error code on failure.
+ */
+static int ssam_controller_caps_load_from_of(struct device *dev, struct ssam_controller_caps *caps)
+{
+ /*
+ * Every device starting with Surface Pro X through Laptop 7 uses these
+ * identical values, which makes them good defaults.
+ */
+ caps->d3_closes_handle = true;
+ caps->screen_on_sleep_idle_timeout = 5000;
+ caps->screen_off_sleep_idle_timeout = 30;
+ caps->ssh_buffer_size = 48;
+ /* TODO: figure out power profile */
+
+ return 0;
+}
+
+/**
+ * ssam_controller_caps_load() - Load controller capabilities
+ * @dev: A pointer to the controller device
+ * @caps: Where to store the capabilities in.
+ *
+ * Return: Returns zero on success, a negative error code on failure.
+ */
+static int ssam_controller_caps_load(struct device *dev, struct ssam_controller_caps *caps)
+{
+ acpi_handle handle = ACPI_HANDLE(dev);
+
+ /* Set defaults. */
+ caps->ssh_power_profile = U32_MAX;
+ caps->screen_on_sleep_idle_timeout = U32_MAX;
+ caps->screen_off_sleep_idle_timeout = U32_MAX;
+ caps->d3_closes_handle = false;
+ caps->ssh_buffer_size = U32_MAX;
+
+ if (handle)
+ return ssam_controller_caps_load_from_acpi(handle, caps);
+ else
+ return ssam_controller_caps_load_from_of(dev, caps);
+}
+
+/**
* ssam_controller_init() - Initialize SSAM controller.
* @ctrl: The controller to initialize.
* @serdev: The serial device representing the underlying data transport.
@@ -1165,13 +1204,12 @@ int ssam_controller_caps_load_from_acpi(acpi_handle handle,
int ssam_controller_init(struct ssam_controller *ctrl,
struct serdev_device *serdev)
{
- acpi_handle handle = ACPI_HANDLE(&serdev->dev);
int status;
init_rwsem(&ctrl->lock);
kref_init(&ctrl->kref);
- status = ssam_controller_caps_load_from_acpi(handle, &ctrl->caps);
+ status = ssam_controller_caps_load(&serdev->dev, &ctrl->caps);
if (status)
return status;
@@ -2716,11 +2754,12 @@ int ssam_irq_setup(struct ssam_controller *ctrl)
const int irqf = IRQF_ONESHOT | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN;
gpiod = gpiod_get(dev, "ssam_wakeup-int", GPIOD_ASIS);
- if (IS_ERR(gpiod))
- return PTR_ERR(gpiod);
-
- irq = gpiod_to_irq(gpiod);
- gpiod_put(gpiod);
+ if (IS_ERR(gpiod)) {
+ irq = fwnode_irq_get(dev_fwnode(dev), 0);
+ } else {
+ irq = gpiod_to_irq(gpiod);
+ gpiod_put(gpiod);
+ }
if (irq < 0)
return irq;
diff --git a/drivers/platform/surface/aggregator/core.c b/drivers/platform/surface/aggregator/core.c
index 797d0645bd77..c58e1fdd1a5f 100644
--- a/drivers/platform/surface/aggregator/core.c
+++ b/drivers/platform/surface/aggregator/core.c
@@ -17,9 +17,12 @@
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
#include <linux/pm.h>
#include <linux/serdev.h>
#include <linux/sysfs.h>
+#include <linux/units.h>
#include <linux/surface_aggregator/controller.h>
#include <linux/surface_aggregator/device.h>
@@ -299,7 +302,7 @@ static const struct attribute_group ssam_sam_group = {
};
-/* -- ACPI based device setup. ---------------------------------------------- */
+/* -- Serial device setup. -------------------------------------------------- */
static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
void *ctx)
@@ -352,13 +355,28 @@ static acpi_status ssam_serdev_setup_via_acpi_crs(struct acpi_resource *rsc,
return AE_CTRL_TERMINATE;
}
-static acpi_status ssam_serdev_setup_via_acpi(acpi_handle handle,
- struct serdev_device *serdev)
+static int ssam_serdev_setup_via_acpi(struct serdev_device *serdev, acpi_handle handle)
{
- return acpi_walk_resources(handle, METHOD_NAME__CRS,
- ssam_serdev_setup_via_acpi_crs, serdev);
+ acpi_status status;
+
+ status = acpi_walk_resources(handle, METHOD_NAME__CRS,
+ ssam_serdev_setup_via_acpi_crs, serdev);
+
+ return status ? -ENXIO : 0;
}
+static int ssam_serdev_setup(struct acpi_device *ssh, struct serdev_device *serdev)
+{
+ if (ssh)
+ return ssam_serdev_setup_via_acpi(serdev, ssh->handle);
+
+ /* TODO: these values may differ per board/implementation */
+ serdev_device_set_baudrate(serdev, 4 * HZ_PER_MHZ);
+ serdev_device_set_flow_control(serdev, true);
+ serdev_device_set_parity(serdev, SERDEV_PARITY_NONE);
+
+ return 0;
+}
/* -- Power management. ----------------------------------------------------- */
@@ -621,16 +639,17 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
struct device *dev = &serdev->dev;
struct acpi_device *ssh = ACPI_COMPANION(dev);
struct ssam_controller *ctrl;
- acpi_status astatus;
int status;
- status = gpiod_count(dev, NULL);
- if (status < 0)
- return dev_err_probe(dev, status, "no GPIO found\n");
+ if (ssh) {
+ status = gpiod_count(dev, NULL);
+ if (status < 0)
+ return dev_err_probe(dev, status, "no GPIO found\n");
- status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
- if (status)
- return status;
+ status = devm_acpi_dev_add_driver_gpios(dev, ssam_acpi_gpios);
+ if (status)
+ return status;
+ }
/* Allocate controller. */
ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
@@ -655,9 +674,9 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
goto err_devopen;
}
- astatus = ssam_serdev_setup_via_acpi(ssh->handle, serdev);
- if (ACPI_FAILURE(astatus)) {
- status = dev_err_probe(dev, -ENXIO, "failed to setup serdev\n");
+ status = ssam_serdev_setup(ssh, serdev);
+ if (status) {
+ status = dev_err_probe(dev, status, "failed to setup serdev\n");
goto err_devinit;
}
@@ -717,7 +736,23 @@ static int ssam_serial_hub_probe(struct serdev_device *serdev)
* For now let's thus default power/wakeup to false.
*/
device_set_wakeup_capable(dev, true);
- acpi_dev_clear_dependencies(ssh);
+
+ /*
+ * When using DT, we have to register the platform hub driver manually,
+ * as it can't be matched based on top-level board compatible (like it
+ * does the ACPI case).
+ */
+ if (!ssh) {
+ struct platform_device *ph_pdev =
+ platform_device_register_simple("surface_aggregator_platform_hub",
+ 0, NULL, 0);
+ if (IS_ERR(ph_pdev))
+ return dev_err_probe(dev, PTR_ERR(ph_pdev),
+ "Failed to register the platform hub driver\n");
+ }
+
+ if (ssh)
+ acpi_dev_clear_dependencies(ssh);
return 0;
@@ -782,18 +817,27 @@ static void ssam_serial_hub_remove(struct serdev_device *serdev)
device_set_wakeup_capable(&serdev->dev, false);
}
-static const struct acpi_device_id ssam_serial_hub_match[] = {
+static const struct acpi_device_id ssam_serial_hub_acpi_match[] = {
{ "MSHW0084", 0 },
{ },
};
-MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_match);
+MODULE_DEVICE_TABLE(acpi, ssam_serial_hub_acpi_match);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ssam_serial_hub_of_match[] = {
+ { .compatible = "microsoft,surface-sam", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ssam_serial_hub_of_match);
+#endif
static struct serdev_device_driver ssam_serial_hub = {
.probe = ssam_serial_hub_probe,
.remove = ssam_serial_hub_remove,
.driver = {
.name = "surface_serial_hub",
- .acpi_match_table = ssam_serial_hub_match,
+ .acpi_match_table = ACPI_PTR(ssam_serial_hub_acpi_match),
+ .of_match_table = of_match_ptr(ssam_serial_hub_of_match),
.pm = &ssam_serial_hub_pm_ops,
.shutdown = ssam_serial_hub_shutdown,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index a23dff35f8ca..25c8aa2131d6 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -12,6 +12,7 @@
#include <linux/acpi.h>
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/types.h>
@@ -291,6 +292,18 @@ static const struct software_node *ssam_node_group_sl6[] = {
NULL,
};
+/* Devices for Surface Laptop 7. */
+static const struct software_node *ssam_node_group_sl7[] = {
+ &ssam_node_root,
+ &ssam_node_bat_ac,
+ &ssam_node_bat_main,
+ &ssam_node_tmp_perf_profile_with_fan,
+ &ssam_node_fan_speed,
+ &ssam_node_hid_sam_keyboard,
+ /* TODO: evaluate thermal sensors devices when we get a driver for that */
+ NULL,
+};
+
/* Devices for Surface Laptop Studio 1. */
static const struct software_node *ssam_node_group_sls1[] = {
&ssam_node_root,
@@ -380,7 +393,7 @@ static const struct software_node *ssam_node_group_sp9[] = {
/* -- SSAM platform/meta-hub driver. ---------------------------------------- */
-static const struct acpi_device_id ssam_platform_hub_match[] = {
+static const struct acpi_device_id ssam_platform_hub_acpi_match[] = {
/* Surface Pro 4, 5, and 6 (OMBR < 0x10) */
{ "MSHW0081", (unsigned long)ssam_node_group_gen5 },
@@ -446,18 +459,39 @@ static const struct acpi_device_id ssam_platform_hub_match[] = {
{ },
};
-MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_match);
+MODULE_DEVICE_TABLE(acpi, ssam_platform_hub_acpi_match);
+
+static const struct of_device_id ssam_platform_hub_of_match[] __maybe_unused = {
+ /* Surface Laptop 7 */
+ { .compatible = "microsoft,romulus13", (void *)ssam_node_group_sl7 },
+ { .compatible = "microsoft,romulus15", (void *)ssam_node_group_sl7 },
+ { },
+};
static int ssam_platform_hub_probe(struct platform_device *pdev)
{
const struct software_node **nodes;
+ const struct of_device_id *match;
+ struct device_node *fdt_root;
struct ssam_controller *ctrl;
struct fwnode_handle *root;
int status;
nodes = (const struct software_node **)acpi_device_get_match_data(&pdev->dev);
- if (!nodes)
- return -ENODEV;
+ if (!nodes) {
+ fdt_root = of_find_node_by_path("/");
+ if (!fdt_root)
+ return -ENODEV;
+
+ match = of_match_node(ssam_platform_hub_of_match, fdt_root);
+ of_node_put(fdt_root);
+ if (!match)
+ return -ENODEV;
+
+ nodes = (const struct software_node **)match->data;
+ if (!nodes)
+ return -ENODEV;
+ }
/*
* As we're adding the SSAM client devices as children under this device
@@ -506,12 +540,13 @@ static struct platform_driver ssam_platform_hub_driver = {
.remove_new = ssam_platform_hub_remove,
.driver = {
.name = "surface_aggregator_platform_hub",
- .acpi_match_table = ssam_platform_hub_match,
+ .acpi_match_table = ssam_platform_hub_acpi_match,
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
},
};
module_platform_driver(ssam_platform_hub_driver);
+MODULE_ALIAS("platform:surface_aggregator_platform_hub");
MODULE_AUTHOR("Maximilian Luz <luzmaximilian@gmail.com>");
MODULE_DESCRIPTION("Device-registry for Surface System Aggregator Module");
MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ddfccc226751..3875abba5a79 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1000,7 +1000,8 @@ config TOPSTAR_LAPTOP
config SERIAL_MULTI_INSTANTIATE
tristate "Serial bus multi instantiate pseudo device driver"
- depends on I2C && SPI && ACPI
+ depends on ACPI
+ depends on (I2C && !SPI) || (!I2C && SPI) || (I2C && SPI)
help
Some ACPI-based systems list multiple devices in a single ACPI
firmware-node. This driver will instantiate separate clients
diff --git a/drivers/platform/x86/acer-wmi.c b/drivers/platform/x86/acer-wmi.c
index 38c932df6446..7169b84ccdb6 100644
--- a/drivers/platform/x86/acer-wmi.c
+++ b/drivers/platform/x86/acer-wmi.c
@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/dmi.h>
-#include <linux/fb.h>
#include <linux/backlight.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
@@ -1685,7 +1684,7 @@ static int acer_backlight_init(struct device *dev)
acer_backlight_device = bd;
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
bd->props.brightness = read_brightness(bd);
backlight_update_status(bd);
return 0;
@@ -2224,39 +2223,25 @@ static void acer_rfkill_exit(void)
}
}
-static void acer_wmi_notify(u32 value, void *context)
+static void acer_wmi_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
struct event_return_value return_value;
- acpi_status status;
u16 device_state;
const struct key_entry *key;
u32 scancode;
- status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_warn("bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
-
if (!obj)
return;
if (obj->type != ACPI_TYPE_BUFFER) {
pr_warn("Unknown response received %d\n", obj->type);
- kfree(obj);
return;
}
if (obj->buffer.length != 8) {
pr_warn("Unknown buffer length %d\n", obj->buffer.length);
- kfree(obj);
return;
}
return_value = *((struct event_return_value *)obj->buffer.pointer);
- kfree(obj);
switch (return_value.function) {
case WMID_HOTKEY_EVENT:
diff --git a/drivers/platform/x86/amd/pmf/acpi.c b/drivers/platform/x86/amd/pmf/acpi.c
index 1157ec148880..d5b496433d69 100644
--- a/drivers/platform/x86/amd/pmf/acpi.c
+++ b/drivers/platform/x86/amd/pmf/acpi.c
@@ -282,6 +282,29 @@ int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx)
return 0;
}
+static int apmf_notify_smart_pc_update(struct amd_pmf_dev *pdev, u32 val, u32 preq, u32 index)
+{
+ struct amd_pmf_notify_smart_pc_update args;
+ struct acpi_buffer params;
+ union acpi_object *info;
+
+ args.size = sizeof(args);
+ args.pending_req = preq;
+ args.custom_bios[index] = val;
+
+ params.length = sizeof(args);
+ params.pointer = &args;
+
+ info = apmf_if_call(pdev, APMF_FUNC_NOTIFY_SMART_PC_UPDATES, &params);
+ if (!info)
+ return -EIO;
+
+ kfree(info);
+ dev_dbg(pdev->dev, "Notify smart pc update, val: %u\n", val);
+
+ return 0;
+}
+
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));
@@ -447,6 +470,14 @@ int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev)
return 0;
}
+int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq, u32 idx)
+{
+ if (!is_apmf_func_supported(dev, APMF_FUNC_NOTIFY_SMART_PC_UPDATES))
+ return -EINVAL;
+
+ return apmf_notify_smart_pc_update(dev, val, preq, idx);
+}
+
void apmf_acpi_deinit(struct amd_pmf_dev *pmf_dev)
{
acpi_handle ahandle = ACPI_HANDLE(pmf_dev->dev);
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index 8f1f719befa3..d6af0ca036f1 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -37,12 +37,6 @@
#define AMD_PMF_RESULT_CMD_UNKNOWN 0xFE
#define AMD_PMF_RESULT_FAILED 0xFF
-/* List of supported CPU ids */
-#define AMD_CPU_ID_RMB 0x14b5
-#define AMD_CPU_ID_PS 0x14e8
-#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
-#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
-
#define PMF_MSG_DELAY_MIN_US 50
#define RESPONSE_REGISTER_LOOP_MAX 20000
@@ -261,7 +255,19 @@ int amd_pmf_set_dram_addr(struct amd_pmf_dev *dev, bool alloc_buffer)
/* Get Metrics Table Address */
if (alloc_buffer) {
- dev->buf = kzalloc(sizeof(dev->m_table), GFP_KERNEL);
+ switch (dev->cpu_id) {
+ case AMD_CPU_ID_PS:
+ case AMD_CPU_ID_RMB:
+ dev->mtable_size = sizeof(dev->m_table);
+ break;
+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
+ dev->mtable_size = sizeof(dev->m_table_v2);
+ break;
+ default:
+ dev_err(dev->dev, "Invalid CPU id: 0x%x", dev->cpu_id);
+ }
+
+ dev->buf = kzalloc(dev->mtable_size, GFP_KERNEL);
if (!dev->buf)
return -ENOMEM;
}
diff --git a/drivers/platform/x86/amd/pmf/pmf-quirks.c b/drivers/platform/x86/amd/pmf/pmf-quirks.c
index 48870ca52b41..7cde5733b9ca 100644
--- a/drivers/platform/x86/amd/pmf/pmf-quirks.c
+++ b/drivers/platform/x86/amd/pmf/pmf-quirks.c
@@ -37,6 +37,14 @@ static const struct dmi_system_id fwbug_list[] = {
},
.driver_data = &quirk_no_sps_bug,
},
+ {
+ .ident = "ASUS TUF Gaming A14",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "FA401W"),
+ },
+ .driver_data = &quirk_no_sps_bug,
+ },
{}
};
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 753d5662c080..8ce8816da9c1 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -19,6 +19,12 @@
#define POLICY_SIGN_COOKIE 0x31535024
#define POLICY_COOKIE_OFFSET 0x10
+/* List of supported CPU ids */
+#define AMD_CPU_ID_RMB 0x14b5
+#define AMD_CPU_ID_PS 0x14e8
+#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
+#define PCI_DEVICE_ID_AMD_1AH_M60H_ROOT 0x1122
+
struct cookie_header {
u32 sign;
u32 length;
@@ -35,6 +41,7 @@ struct cookie_header {
#define APMF_FUNC_STATIC_SLIDER_GRANULAR 9
#define APMF_FUNC_DYN_SLIDER_AC 11
#define APMF_FUNC_DYN_SLIDER_DC 12
+#define APMF_FUNC_NOTIFY_SMART_PC_UPDATES 14
#define APMF_FUNC_SBIOS_HEARTBEAT_V2 16
/* Message Definitions */
@@ -82,7 +89,17 @@ struct cookie_header {
#define PMF_POLICY_STT_SKINTEMP_APU 7
#define PMF_POLICY_STT_SKINTEMP_HS2 8
#define PMF_POLICY_SYSTEM_STATE 9
+#define PMF_POLICY_BIOS_OUTPUT_1 10
+#define PMF_POLICY_BIOS_OUTPUT_2 11
#define PMF_POLICY_P3T 38
+#define PMF_POLICY_BIOS_OUTPUT_3 57
+#define PMF_POLICY_BIOS_OUTPUT_4 58
+#define PMF_POLICY_BIOS_OUTPUT_5 59
+#define PMF_POLICY_BIOS_OUTPUT_6 60
+#define PMF_POLICY_BIOS_OUTPUT_7 61
+#define PMF_POLICY_BIOS_OUTPUT_8 62
+#define PMF_POLICY_BIOS_OUTPUT_9 63
+#define PMF_POLICY_BIOS_OUTPUT_10 64
/* TA macros */
#define PMF_TA_IF_VERSION_MAJOR 1
@@ -181,6 +198,53 @@ struct apmf_fan_idx {
u32 fan_ctl_idx;
} __packed;
+struct smu_pmf_metrics_v2 {
+ u16 core_frequency[16]; /* MHz */
+ u16 core_power[16]; /* mW */
+ u16 core_temp[16]; /* centi-C */
+ u16 gfx_temp; /* centi-C */
+ u16 soc_temp; /* centi-C */
+ u16 stapm_opn_limit; /* mW */
+ u16 stapm_cur_limit; /* mW */
+ u16 infra_cpu_maxfreq; /* MHz */
+ u16 infra_gfx_maxfreq; /* MHz */
+ u16 skin_temp; /* centi-C */
+ u16 gfxclk_freq; /* MHz */
+ u16 fclk_freq; /* MHz */
+ u16 gfx_activity; /* GFX busy % [0-100] */
+ u16 socclk_freq; /* MHz */
+ u16 vclk_freq; /* MHz */
+ u16 vcn_activity; /* VCN busy % [0-100] */
+ u16 vpeclk_freq; /* MHz */
+ u16 ipuclk_freq; /* MHz */
+ u16 ipu_busy[8]; /* NPU busy % [0-100] */
+ u16 dram_reads; /* MB/sec */
+ u16 dram_writes; /* MB/sec */
+ u16 core_c0residency[16]; /* C0 residency % [0-100] */
+ u16 ipu_power; /* mW */
+ u32 apu_power; /* mW */
+ u32 gfx_power; /* mW */
+ u32 dgpu_power; /* mW */
+ u32 socket_power; /* mW */
+ u32 all_core_power; /* mW */
+ u32 filter_alpha_value; /* time constant [us] */
+ u32 metrics_counter;
+ u16 memclk_freq; /* MHz */
+ u16 mpipuclk_freq; /* MHz */
+ u16 ipu_reads; /* MB/sec */
+ u16 ipu_writes; /* MB/sec */
+ u32 throttle_residency_prochot;
+ u32 throttle_residency_spl;
+ u32 throttle_residency_fppt;
+ u32 throttle_residency_sppt;
+ u32 throttle_residency_thm_core;
+ u32 throttle_residency_thm_gfx;
+ u32 throttle_residency_thm_soc;
+ u16 psys;
+ u16 spare1;
+ u32 spare[6];
+} __packed;
+
struct smu_pmf_metrics {
u16 gfxclk_freq; /* in MHz */
u16 socclk_freq; /* in MHz */
@@ -278,6 +342,7 @@ struct amd_pmf_dev {
int hb_interval; /* SBIOS heartbeat interval */
struct delayed_work heart_beat;
struct smu_pmf_metrics m_table;
+ struct smu_pmf_metrics_v2 m_table_v2;
struct delayed_work work_buffer;
ktime_t start_time;
int socket_power_history[AVG_SAMPLE_SIZE];
@@ -302,6 +367,7 @@ struct amd_pmf_dev {
bool smart_pc_enabled;
u16 pmf_if_version;
struct input_dev *pmf_idev;
+ size_t mtable_size;
};
struct apmf_sps_prop_granular_v2 {
@@ -344,6 +410,12 @@ struct os_power_slider {
u8 slider_event;
} __packed;
+struct amd_pmf_notify_smart_pc_update {
+ u16 size;
+ u32 pending_req;
+ u32 custom_bios[10];
+} __packed;
+
struct fan_table_control {
bool manual;
unsigned long fan_id;
@@ -717,6 +789,7 @@ extern const struct attribute_group cnqf_feature_attribute_group;
int amd_pmf_init_smart_pc(struct amd_pmf_dev *dev);
void amd_pmf_deinit_smart_pc(struct amd_pmf_dev *dev);
int apmf_check_smart_pc(struct amd_pmf_dev *pmf_dev);
+int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq, u32 idx);
/* Smart PC - TA interfaces */
void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index 3c153fb1425e..b5183969f9bf 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -53,30 +53,49 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *
void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in) {}
#endif
-static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
+static void amd_pmf_get_c0_residency(u16 *core_res, size_t size, struct ta_pmf_enact_table *in)
{
u16 max, avg = 0;
int i;
- memset(dev->buf, 0, sizeof(dev->m_table));
- amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
- memcpy(&dev->m_table, dev->buf, sizeof(dev->m_table));
-
- in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
- in->ev_info.skin_temperature = dev->m_table.skin_temp;
-
/* Get the avg and max C0 residency of all the cores */
- max = dev->m_table.avg_core_c0residency[0];
- for (i = 0; i < ARRAY_SIZE(dev->m_table.avg_core_c0residency); i++) {
- avg += dev->m_table.avg_core_c0residency[i];
- if (dev->m_table.avg_core_c0residency[i] > max)
- max = dev->m_table.avg_core_c0residency[i];
+ max = *core_res;
+ for (i = 0; i < size; i++) {
+ avg += core_res[i];
+ if (core_res[i] > max)
+ max = core_res[i];
}
-
- avg = DIV_ROUND_CLOSEST(avg, ARRAY_SIZE(dev->m_table.avg_core_c0residency));
+ avg = DIV_ROUND_CLOSEST(avg, size);
in->ev_info.avg_c0residency = avg;
in->ev_info.max_c0residency = max;
- in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity;
+}
+
+static void amd_pmf_get_smu_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
+{
+ /* Get the updated metrics table data */
+ memset(dev->buf, 0, dev->mtable_size);
+ amd_pmf_send_cmd(dev, SET_TRANSFER_TABLE, 0, 7, NULL);
+
+ switch (dev->cpu_id) {
+ case AMD_CPU_ID_PS:
+ memcpy(&dev->m_table, dev->buf, dev->mtable_size);
+ in->ev_info.socket_power = dev->m_table.apu_power + dev->m_table.dgpu_power;
+ in->ev_info.skin_temperature = dev->m_table.skin_temp;
+ in->ev_info.gfx_busy = dev->m_table.avg_gfx_activity;
+ amd_pmf_get_c0_residency(dev->m_table.avg_core_c0residency,
+ ARRAY_SIZE(dev->m_table.avg_core_c0residency), in);
+ break;
+ case PCI_DEVICE_ID_AMD_1AH_M20H_ROOT:
+ memcpy(&dev->m_table_v2, dev->buf, dev->mtable_size);
+ in->ev_info.socket_power = dev->m_table_v2.apu_power + dev->m_table_v2.dgpu_power;
+ in->ev_info.skin_temperature = dev->m_table_v2.skin_temp;
+ in->ev_info.gfx_busy = dev->m_table_v2.gfx_activity;
+ amd_pmf_get_c0_residency(dev->m_table_v2.core_c0residency,
+ ARRAY_SIZE(dev->m_table_v2.core_c0residency), in);
+ break;
+ default:
+ dev_err(dev->dev, "Unsupported CPU id: 0x%x", dev->cpu_id);
+ }
}
static const char * const pmf_battery_supply_name[] = {
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
index e246367aacee..19c27b6e4666 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -160,6 +160,46 @@ static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_
dev_dbg(dev->dev, "update SYSTEM_STATE: %s\n",
amd_pmf_uevent_as_str(val));
break;
+
+ case PMF_POLICY_BIOS_OUTPUT_1:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(0), 0);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_2:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(1), 1);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_3:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(2), 2);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_4:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(3), 3);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_5:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(4), 4);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_6:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(5), 5);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_7:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(6), 6);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_8:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(7), 7);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_9:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(8), 8);
+ break;
+
+ case PMF_POLICY_BIOS_OUTPUT_10:
+ amd_pmf_smartpc_apply_bios_output(dev, val, BIT(9), 9);
+ break;
}
}
}
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index ccb33d034e2a..9d7e6b712abf 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -28,7 +28,6 @@
#include <linux/err.h>
#include <linux/proc_fs.h>
#include <linux/backlight.h>
-#include <linux/fb.h>
#include <linux/leds.h>
#include <linux/platform_device.h>
#include <linux/uaccess.h>
@@ -818,7 +817,7 @@ static int asus_backlight_init(struct asus_laptop *asus)
asus->backlight_device = bd;
bd->props.brightness = asus_read_brightness(bd);
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
backlight_update_status(bd);
return 0;
}
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index ed3633c5955d..ef04d396f61c 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -7,12 +7,12 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/backlight.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
-#include <linux/fb.h>
#include <linux/dmi.h>
#include <linux/i8042.h>
@@ -538,7 +538,7 @@ static void asus_nb_wmi_quirks(struct asus_wmi_driver *driver)
dmi_check_system(asus_quirks);
driver->quirks = quirks;
- driver->panel_power = FB_BLANK_UNBLANK;
+ driver->panel_power = BACKLIGHT_POWER_ON;
/* overwrite the wapf setting if the wapf paramater is specified */
if (wapf != -1)
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 321a658e4554..7a48220b4f5a 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -18,7 +18,6 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/dmi.h>
-#include <linux/fb.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/init.h>
@@ -97,6 +96,12 @@ module_param(fnlock_default, bool, 0444);
#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST 1
#define ASUS_THROTTLE_THERMAL_POLICY_SILENT 2
+#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO 0
+#define ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO 1
+#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO 2
+
+#define PLATFORM_PROFILE_MAX 2
+
#define USB_INTEL_XUSB2PR 0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI 0x9c31
@@ -300,8 +305,8 @@ struct asus_wmi {
u32 kbd_rgb_dev;
bool kbd_rgb_state_available;
- bool throttle_thermal_policy_available;
u8 throttle_thermal_policy_mode;
+ u32 throttle_thermal_policy_dev;
bool cpu_fan_curve_available;
bool gpu_fan_curve_available;
@@ -349,20 +354,29 @@ static int asus_wmi_evaluate_method3(u32 method_id,
status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
&input, &output);
- if (ACPI_FAILURE(status))
+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x\n",
+ __func__, method_id, arg0, arg1, arg2);
+ if (ACPI_FAILURE(status)) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, -EIO);
return -EIO;
+ }
obj = (union acpi_object *)output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
tmp = (u32) obj->integer.value;
+ pr_debug("Result: 0x%08x\n", tmp);
if (retval)
*retval = tmp;
kfree(obj);
- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, -ENODEV);
return -ENODEV;
+ }
return 0;
}
@@ -392,20 +406,29 @@ static int asus_wmi_evaluate_method5(u32 method_id,
status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
&input, &output);
- if (ACPI_FAILURE(status))
+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",
+ __func__, method_id, arg0, arg1, arg2, arg3, arg4);
+ if (ACPI_FAILURE(status)) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, -EIO);
return -EIO;
+ }
obj = (union acpi_object *)output.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
tmp = (u32) obj->integer.value;
+ pr_debug("Result: %x\n", tmp);
if (retval)
*retval = tmp;
kfree(obj);
- if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
+ if (tmp == ASUS_WMI_UNSUPPORTED_METHOD) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, -ENODEV);
return -ENODEV;
+ }
return 0;
}
@@ -431,8 +454,13 @@ static int asus_wmi_evaluate_method_buf(u32 method_id,
status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
&input, &output);
- if (ACPI_FAILURE(status))
+ pr_debug("%s called (0x%08x) with args: 0x%08x, 0x%08x\n",
+ __func__, method_id, arg0, arg1);
+ if (ACPI_FAILURE(status)) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, -EIO);
return -EIO;
+ }
obj = (union acpi_object *)output.pointer;
@@ -468,8 +496,11 @@ static int asus_wmi_evaluate_method_buf(u32 method_id,
kfree(obj);
- if (err)
+ if (err) {
+ pr_debug("%s, (0x%08x), arg 0x%08x failed: %d\n",
+ __func__, method_id, arg0, err);
return err;
+ }
return 0;
}
@@ -557,6 +588,7 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
{
u32 retval;
int status = asus_wmi_get_devstate(asus, dev_id, &retval);
+ pr_debug("%s called (0x%08x), retval: 0x%08x\n", __func__, dev_id, retval);
return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
}
@@ -1722,7 +1754,8 @@ static int asus_wmi_led_init(struct asus_wmi *asus)
goto error;
}
- if (!kbd_led_read(asus, &led_val, NULL)) {
+ if (!kbd_led_read(asus, &led_val, NULL) && !dmi_check_system(asus_use_hid_led_dmi_ids)) {
+ pr_info("using asus-wmi for asus::kbd_backlight\n");
asus->kbd_led_wk = led_val;
asus->kbd_led.name = "asus::kbd_backlight";
asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
@@ -3186,7 +3219,7 @@ static int fan_curve_get_factory_default(struct asus_wmi *asus, u32 fan_dev)
int err, fan_idx;
u8 mode = 0;
- if (asus->throttle_thermal_policy_available)
+ if (asus->throttle_thermal_policy_dev)
mode = asus->throttle_thermal_policy_mode;
/* DEVID_<C/G>PU_FAN_CURVE is switched for OVERBOOST vs SILENT */
if (mode == 2)
@@ -3393,7 +3426,7 @@ static ssize_t fan_curve_enable_store(struct device *dev,
* For machines with throttle this is the only way to reset fans
* to default mode of operation (does not erase curve data).
*/
- if (asus->throttle_thermal_policy_available) {
+ if (asus->throttle_thermal_policy_dev) {
err = throttle_thermal_policy_write(asus);
if (err)
return err;
@@ -3610,8 +3643,8 @@ static const struct attribute_group asus_fan_curve_attr_group = {
__ATTRIBUTE_GROUPS(asus_fan_curve_attr);
/*
- * Must be initialised after throttle_thermal_policy_check_present() as
- * we check the status of throttle_thermal_policy_available during init.
+ * Must be initialised after throttle_thermal_policy_dev is set as
+ * we check the status of throttle_thermal_policy_dev during init.
*/
static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
{
@@ -3621,18 +3654,27 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
err = fan_curve_check_present(asus, &asus->cpu_fan_curve_available,
ASUS_WMI_DEVID_CPU_FAN_CURVE);
- if (err)
+ if (err) {
+ pr_debug("%s, checked 0x%08x, failed: %d\n",
+ __func__, ASUS_WMI_DEVID_CPU_FAN_CURVE, err);
return err;
+ }
err = fan_curve_check_present(asus, &asus->gpu_fan_curve_available,
ASUS_WMI_DEVID_GPU_FAN_CURVE);
- if (err)
+ if (err) {
+ pr_debug("%s, checked 0x%08x, failed: %d\n",
+ __func__, ASUS_WMI_DEVID_GPU_FAN_CURVE, err);
return err;
+ }
err = fan_curve_check_present(asus, &asus->mid_fan_curve_available,
ASUS_WMI_DEVID_MID_FAN_CURVE);
- if (err)
+ if (err) {
+ pr_debug("%s, checked 0x%08x, failed: %d\n",
+ __func__, ASUS_WMI_DEVID_MID_FAN_CURVE, err);
return err;
+ }
if (!asus->cpu_fan_curve_available
&& !asus->gpu_fan_curve_available
@@ -3652,38 +3694,13 @@ static int asus_wmi_custom_fan_curve_init(struct asus_wmi *asus)
}
/* Throttle thermal policy ****************************************************/
-
-static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
-{
- u32 result;
- int err;
-
- asus->throttle_thermal_policy_available = false;
-
- err = asus_wmi_get_devstate(asus,
- ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
- &result);
- if (err) {
- if (err == -ENODEV)
- return 0;
- return err;
- }
-
- if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
- asus->throttle_thermal_policy_available = true;
-
- return 0;
-}
-
static int throttle_thermal_policy_write(struct asus_wmi *asus)
{
- int err;
- u8 value;
+ u8 value = asus->throttle_thermal_policy_mode;
u32 retval;
+ int err;
- value = asus->throttle_thermal_policy_mode;
-
- err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
+ err = asus_wmi_set_devstate(asus->throttle_thermal_policy_dev,
value, &retval);
sysfs_notify(&asus->platform_device->dev.kobj, NULL,
@@ -3713,7 +3730,7 @@ static int throttle_thermal_policy_write(struct asus_wmi *asus)
static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
{
- if (!asus->throttle_thermal_policy_available)
+ if (!asus->throttle_thermal_policy_dev)
return 0;
asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
@@ -3725,7 +3742,7 @@ static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
u8 new_mode = asus->throttle_thermal_policy_mode + 1;
int err;
- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ if (new_mode > PLATFORM_PROFILE_MAX)
new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
asus->throttle_thermal_policy_mode = new_mode;
@@ -3764,7 +3781,7 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
if (result < 0)
return result;
- if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
+ if (new_mode > PLATFORM_PROFILE_MAX)
return -EINVAL;
asus->throttle_thermal_policy_mode = new_mode;
@@ -3781,10 +3798,52 @@ static ssize_t throttle_thermal_policy_store(struct device *dev,
return count;
}
-// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
+/*
+ * Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
+ */
static DEVICE_ATTR_RW(throttle_thermal_policy);
/* Platform profile ***********************************************************/
+static int asus_wmi_platform_profile_to_vivo(struct asus_wmi *asus, int mode)
+{
+ bool vivo;
+
+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+
+ if (vivo) {
+ switch (mode) {
+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO;
+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST:
+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO;
+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT:
+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO;
+ }
+ }
+
+ return mode;
+}
+
+static int asus_wmi_platform_profile_mode_from_vivo(struct asus_wmi *asus, int mode)
+{
+ bool vivo;
+
+ vivo = asus->throttle_thermal_policy_dev == ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+
+ if (vivo) {
+ switch (mode) {
+ case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT_VIVO:
+ return ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
+ case ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST_VIVO:
+ return ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST;
+ case ASUS_THROTTLE_THERMAL_POLICY_SILENT_VIVO:
+ return ASUS_THROTTLE_THERMAL_POLICY_SILENT;
+ }
+ }
+
+ return mode;
+}
+
static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
@@ -3792,10 +3851,9 @@ static int asus_wmi_platform_profile_get(struct platform_profile_handler *pprof,
int tp;
asus = container_of(pprof, struct asus_wmi, platform_profile_handler);
-
tp = asus->throttle_thermal_policy_mode;
- switch (tp) {
+ switch (asus_wmi_platform_profile_mode_from_vivo(asus, tp)) {
case ASUS_THROTTLE_THERMAL_POLICY_DEFAULT:
*profile = PLATFORM_PROFILE_BALANCED;
break;
@@ -3834,7 +3892,7 @@ static int asus_wmi_platform_profile_set(struct platform_profile_handler *pprof,
return -EOPNOTSUPP;
}
- asus->throttle_thermal_policy_mode = tp;
+ asus->throttle_thermal_policy_mode = asus_wmi_platform_profile_to_vivo(asus, tp);
return throttle_thermal_policy_write(asus);
}
@@ -3847,7 +3905,7 @@ static int platform_profile_setup(struct asus_wmi *asus)
* Not an error if a component platform_profile relies on is unavailable
* so early return, skipping the setup of platform_profile.
*/
- if (!asus->throttle_thermal_policy_available)
+ if (!asus->throttle_thermal_policy_dev)
return 0;
dev_info(dev, "Using throttle_thermal_policy for platform_profile support\n");
@@ -3862,8 +3920,13 @@ static int platform_profile_setup(struct asus_wmi *asus)
asus->platform_profile_handler.choices);
err = platform_profile_register(&asus->platform_profile_handler);
- if (err)
+ if (err == -EEXIST) {
+ pr_warn("%s, a platform_profile handler is already registered\n", __func__);
+ return 0;
+ } else if (err) {
+ pr_err("%s, failed at platform_profile_register: %d\n", __func__, err);
return err;
+ }
asus->platform_profile_support = true;
return 0;
@@ -3884,7 +3947,7 @@ static int read_backlight_power(struct asus_wmi *asus)
if (ret < 0)
return ret;
- return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+ return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
}
static int read_brightness_max(struct asus_wmi *asus)
@@ -3943,7 +4006,7 @@ static int update_bl_status(struct backlight_device *bd)
power = read_backlight_power(asus);
if (power != -ENODEV && bd->props.power != power) {
- ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
+ ctrl_param = !!(bd->props.power == BACKLIGHT_POWER_ON);
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
ctrl_param, NULL);
if (asus->driver->quirks->store_backlight_power)
@@ -4002,7 +4065,7 @@ static int asus_wmi_backlight_init(struct asus_wmi *asus)
power = read_backlight_power(asus);
if (power == -ENODEV)
- power = FB_BLANK_UNBLANK;
+ power = BACKLIGHT_POWER_ON;
else if (power < 0)
return power;
@@ -4060,7 +4123,7 @@ static int read_screenpad_backlight_power(struct asus_wmi *asus)
if (ret < 0)
return ret;
/* 1 == powered */
- return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+ return ret ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
}
static int read_screenpad_brightness(struct backlight_device *bd)
@@ -4073,7 +4136,7 @@ static int read_screenpad_brightness(struct backlight_device *bd)
if (err < 0)
return err;
/* The device brightness can only be read if powered, so return stored */
- if (err == FB_BLANK_POWERDOWN)
+ if (err == BACKLIGHT_POWER_OFF)
return asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &retval);
@@ -4094,7 +4157,7 @@ static int update_screenpad_bl_status(struct backlight_device *bd)
return power;
if (bd->props.power != power) {
- if (power != FB_BLANK_UNBLANK) {
+ if (power != BACKLIGHT_POWER_ON) {
/* Only brightness > 0 can power it back on */
ctrl_param = asus->driver->screenpad_brightness - ASUS_SCREENPAD_BRIGHT_MIN;
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT,
@@ -4102,7 +4165,7 @@ static int update_screenpad_bl_status(struct backlight_device *bd)
} else {
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_POWER, 0, NULL);
}
- } else if (power == FB_BLANK_UNBLANK) {
+ } else if (power == BACKLIGHT_POWER_ON) {
/* Only set brightness if powered on or we get invalid/unsync state */
ctrl_param = bd->props.brightness + ASUS_SCREENPAD_BRIGHT_MIN;
err = asus_wmi_set_devstate(ASUS_WMI_DEVID_SCREENPAD_LIGHT, ctrl_param, NULL);
@@ -4132,7 +4195,7 @@ static int asus_screenpad_init(struct asus_wmi *asus)
if (power < 0)
return power;
- if (power != FB_BLANK_POWERDOWN) {
+ if (power != BACKLIGHT_POWER_OFF) {
err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_SCREENPAD_LIGHT, &brightness);
if (err < 0)
return err;
@@ -4189,28 +4252,15 @@ static void asus_wmi_fnlock_update(struct asus_wmi *asus)
/* WMI events *****************************************************************/
-static int asus_wmi_get_event_code(u32 value)
+static int asus_wmi_get_event_code(union acpi_object *obj)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
int code;
- status = wmi_get_event_data(value, &response);
- if (ACPI_FAILURE(status)) {
- pr_warn("Failed to get WMI notify code: %s\n",
- acpi_format_exception(status));
- return -EIO;
- }
-
- obj = (union acpi_object *)response.pointer;
-
if (obj && obj->type == ACPI_TYPE_INTEGER)
code = (int)(obj->integer.value & WMI_EVENT_MASK);
else
code = -EIO;
- kfree(obj);
return code;
}
@@ -4262,7 +4312,7 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
if (code == NOTIFY_KBD_FBM || code == NOTIFY_KBD_TTP) {
if (asus->fan_boost_mode_available)
fan_boost_mode_switch_next(asus);
- if (asus->throttle_thermal_policy_available)
+ if (asus->throttle_thermal_policy_dev)
throttle_thermal_policy_switch_next(asus);
return;
@@ -4276,10 +4326,10 @@ static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
pr_info("Unknown key code 0x%x\n", code);
}
-static void asus_wmi_notify(u32 value, void *context)
+static void asus_wmi_notify(union acpi_object *obj, void *context)
{
struct asus_wmi *asus = context;
- int code = asus_wmi_get_event_code(value);
+ int code = asus_wmi_get_event_code(obj);
if (code < 0) {
pr_warn("Failed to get notify code: %d\n", code);
@@ -4434,7 +4484,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
else if (attr == &dev_attr_fan_boost_mode.attr)
ok = asus->fan_boost_mode_available;
else if (attr == &dev_attr_throttle_thermal_policy.attr)
- ok = asus->throttle_thermal_policy_available;
+ ok = asus->throttle_thermal_policy_dev != 0;
else if (attr == &dev_attr_ppt_pl2_sppt.attr)
devid = ASUS_WMI_DEVID_PPT_PL2_SPPT;
else if (attr == &dev_attr_ppt_pl1_spl.attr)
@@ -4460,8 +4510,10 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
else if (attr == &dev_attr_available_mini_led_mode.attr)
ok = asus->mini_led_dev_id != 0;
- if (devid != -1)
+ if (devid != -1) {
ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
+ pr_debug("%s called 0x%08x, ok: %x\n", __func__, devid, ok);
+ }
return ok ? attr->mode : 0;
}
@@ -4726,16 +4778,15 @@ static int asus_wmi_add(struct platform_device *pdev)
else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_TUF_RGB_MODE2))
asus->kbd_rgb_dev = ASUS_WMI_DEVID_TUF_RGB_MODE2;
+ if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY))
+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY;
+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO))
+ asus->throttle_thermal_policy_dev = ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY_VIVO;
+
err = fan_boost_mode_check_present(asus);
if (err)
goto fail_fan_boost_mode;
- err = throttle_thermal_policy_check_present(asus);
- if (err)
- goto fail_throttle_thermal_policy;
- else
- throttle_thermal_policy_set_default(asus);
-
err = platform_profile_setup(asus);
if (err)
goto fail_platform_profile_setup;
@@ -4830,7 +4881,6 @@ fail_hwmon:
fail_input:
asus_wmi_sysfs_exit(asus->platform_device);
fail_sysfs:
-fail_throttle_thermal_policy:
fail_custom_fan_curve:
fail_platform_profile_setup:
if (asus->platform_profile_support)
diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
index 309236cecd5a..68a49788a396 100644
--- a/drivers/platform/x86/dell/Kconfig
+++ b/drivers/platform/x86/dell/Kconfig
@@ -49,6 +49,7 @@ config DELL_LAPTOP
default m
depends on DMI
depends on BACKLIGHT_CLASS_DEVICE
+ depends on ACPI_BATTERY
depends on ACPI_VIDEO || ACPI_VIDEO = n
depends on RFKILL || RFKILL = n
depends on DELL_WMI || DELL_WMI = n
diff --git a/drivers/platform/x86/dell/dell-laptop.c b/drivers/platform/x86/dell/dell-laptop.c
index 6552dfe491c6..a3cd0505f282 100644
--- a/drivers/platform/x86/dell/dell-laptop.c
+++ b/drivers/platform/x86/dell/dell-laptop.c
@@ -22,11 +22,13 @@
#include <linux/io.h>
#include <linux/rfkill.h>
#include <linux/power_supply.h>
+#include <linux/sysfs.h>
#include <linux/acpi.h>
#include <linux/mm.h>
#include <linux/i8042.h>
#include <linux/debugfs.h>
#include <linux/seq_file.h>
+#include <acpi/battery.h>
#include <acpi/video.h>
#include "dell-rbtn.h"
#include "dell-smbios.h"
@@ -99,6 +101,20 @@ static bool force_rfkill;
static bool micmute_led_registered;
static bool mute_led_registered;
+struct battery_mode_info {
+ int token;
+ const char *label;
+};
+
+static const struct battery_mode_info battery_modes[] = {
+ { BAT_PRI_AC_MODE_TOKEN, "Trickle" },
+ { BAT_EXPRESS_MODE_TOKEN, "Fast" },
+ { BAT_STANDARD_MODE_TOKEN, "Standard" },
+ { BAT_ADAPTIVE_MODE_TOKEN, "Adaptive" },
+ { BAT_CUSTOM_MODE_TOKEN, "Custom" },
+};
+static u32 battery_supported_modes;
+
module_param(force_rfkill, bool, 0444);
MODULE_PARM_DESC(force_rfkill, "enable rfkill on non whitelisted models");
@@ -353,6 +369,32 @@ static const struct dmi_system_id dell_quirks[] __initconst = {
{ }
};
+/* -1 is a sentinel value, telling us to use token->value */
+#define USE_TVAL ((u32) -1)
+static int dell_send_request_for_tokenid(struct calling_interface_buffer *buffer,
+ u16 class, u16 select, u16 tokenid,
+ u32 val)
+{
+ struct calling_interface_token *token;
+
+ token = dell_smbios_find_token(tokenid);
+ if (!token)
+ return -ENODEV;
+
+ if (val == USE_TVAL)
+ val = token->value;
+
+ dell_fill_request(buffer, token->location, val, 0, 0);
+ return dell_send_request(buffer, class, select);
+}
+
+static inline int dell_set_std_token_value(struct calling_interface_buffer *buffer,
+ u16 tokenid, u32 value)
+{
+ return dell_send_request_for_tokenid(buffer, CLASS_TOKEN_WRITE,
+ SELECT_TOKEN_STD, tokenid, value);
+}
+
/*
* Derived from information in smbios-wireless-ctl:
*
@@ -895,43 +937,24 @@ static void dell_cleanup_rfkill(void)
static int dell_send_intensity(struct backlight_device *bd)
{
struct calling_interface_buffer buffer;
- struct calling_interface_token *token;
- int ret;
-
- token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
- if (!token)
- return -ENODEV;
-
- dell_fill_request(&buffer,
- token->location, bd->props.brightness, 0, 0);
- if (power_supply_is_system_supplied() > 0)
- ret = dell_send_request(&buffer,
- CLASS_TOKEN_WRITE, SELECT_TOKEN_AC);
- else
- ret = dell_send_request(&buffer,
- CLASS_TOKEN_WRITE, SELECT_TOKEN_BAT);
+ u16 select;
- return ret;
+ select = power_supply_is_system_supplied() > 0 ?
+ SELECT_TOKEN_AC : SELECT_TOKEN_BAT;
+ return dell_send_request_for_tokenid(&buffer, CLASS_TOKEN_WRITE,
+ select, BRIGHTNESS_TOKEN, bd->props.brightness);
}
static int dell_get_intensity(struct backlight_device *bd)
{
struct calling_interface_buffer buffer;
- struct calling_interface_token *token;
int ret;
+ u16 select;
- token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
- if (!token)
- return -ENODEV;
-
- dell_fill_request(&buffer, token->location, 0, 0, 0);
- if (power_supply_is_system_supplied() > 0)
- ret = dell_send_request(&buffer,
- CLASS_TOKEN_READ, SELECT_TOKEN_AC);
- else
- ret = dell_send_request(&buffer,
- CLASS_TOKEN_READ, SELECT_TOKEN_BAT);
-
+ select = power_supply_is_system_supplied() > 0 ?
+ SELECT_TOKEN_AC : SELECT_TOKEN_BAT;
+ ret = dell_send_request_for_tokenid(&buffer, CLASS_TOKEN_READ,
+ select, BRIGHTNESS_TOKEN, 0);
if (ret == 0)
ret = buffer.output[1];
@@ -1355,20 +1378,11 @@ static int kbd_set_state_safe(struct kbd_state *state, struct kbd_state *old)
static int kbd_set_token_bit(u8 bit)
{
struct calling_interface_buffer buffer;
- struct calling_interface_token *token;
- int ret;
if (bit >= ARRAY_SIZE(kbd_tokens))
return -EINVAL;
- token = dell_smbios_find_token(kbd_tokens[bit]);
- if (!token)
- return -EINVAL;
-
- dell_fill_request(&buffer, token->location, token->value, 0, 0);
- ret = dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
-
- return ret;
+ return dell_set_std_token_value(&buffer, kbd_tokens[bit], USE_TVAL);
}
static int kbd_get_token_bit(u8 bit)
@@ -1387,11 +1401,10 @@ static int kbd_get_token_bit(u8 bit)
dell_fill_request(&buffer, token->location, 0, 0, 0);
ret = dell_send_request(&buffer, CLASS_TOKEN_READ, SELECT_TOKEN_STD);
- val = buffer.output[1];
-
if (ret)
return ret;
+ val = buffer.output[1];
return (val == token->value);
}
@@ -1497,7 +1510,7 @@ static inline int kbd_init_info(void)
}
-static inline void kbd_init_tokens(void)
+static inline void __init kbd_init_tokens(void)
{
int i;
@@ -1506,7 +1519,7 @@ static inline void kbd_init_tokens(void)
kbd_token_bits |= BIT(i);
}
-static void kbd_init(void)
+static void __init kbd_init(void)
{
int ret;
@@ -2131,21 +2144,11 @@ static int micmute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct calling_interface_buffer buffer;
- struct calling_interface_token *token;
- int state = brightness != LED_OFF;
+ u32 tokenid;
- if (state == 0)
- token = dell_smbios_find_token(GLOBAL_MIC_MUTE_DISABLE);
- else
- token = dell_smbios_find_token(GLOBAL_MIC_MUTE_ENABLE);
-
- if (!token)
- return -ENODEV;
-
- dell_fill_request(&buffer, token->location, token->value, 0, 0);
- dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
-
- return 0;
+ tokenid = brightness == LED_OFF ?
+ GLOBAL_MIC_MUTE_DISABLE : GLOBAL_MIC_MUTE_ENABLE;
+ return dell_set_std_token_value(&buffer, tokenid, USE_TVAL);
}
static struct led_classdev micmute_led_cdev = {
@@ -2159,33 +2162,288 @@ static int mute_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct calling_interface_buffer buffer;
+ u32 tokenid;
+
+ tokenid = brightness == LED_OFF ?
+ GLOBAL_MUTE_DISABLE : GLOBAL_MUTE_ENABLE;
+ return dell_set_std_token_value(&buffer, tokenid, USE_TVAL);
+}
+
+static struct led_classdev mute_led_cdev = {
+ .name = "platform::mute",
+ .max_brightness = 1,
+ .brightness_set_blocking = mute_led_set,
+ .default_trigger = "audio-mute",
+};
+
+static int dell_battery_set_mode(const u16 tokenid)
+{
+ struct calling_interface_buffer buffer;
+
+ return dell_set_std_token_value(&buffer, tokenid, USE_TVAL);
+}
+
+static int dell_battery_read(const u16 tokenid)
+{
+ struct calling_interface_buffer buffer;
+ int err;
+
+ err = dell_send_request_for_tokenid(&buffer, CLASS_TOKEN_READ,
+ SELECT_TOKEN_STD, tokenid, 0);
+ if (err)
+ return err;
+
+ if (buffer.output[1] > INT_MAX)
+ return -EIO;
+
+ return buffer.output[1];
+}
+
+static bool dell_battery_mode_is_active(const u16 tokenid)
+{
struct calling_interface_token *token;
- int state = brightness != LED_OFF;
+ int ret;
- if (state == 0)
- token = dell_smbios_find_token(GLOBAL_MUTE_DISABLE);
- else
- token = dell_smbios_find_token(GLOBAL_MUTE_ENABLE);
+ ret = dell_battery_read(tokenid);
+ if (ret < 0)
+ return false;
- if (!token)
+ token = dell_smbios_find_token(tokenid);
+ /* token's already verified by dell_battery_read() */
+
+ return token->value == (u16) ret;
+}
+
+/*
+ * The rules: the minimum start charging value is 50%. The maximum
+ * start charging value is 95%. The minimum end charging value is
+ * 55%. The maximum end charging value is 100%. And finally, there
+ * has to be at least a 5% difference between start & end values.
+ */
+#define CHARGE_START_MIN 50
+#define CHARGE_START_MAX 95
+#define CHARGE_END_MIN 55
+#define CHARGE_END_MAX 100
+#define CHARGE_MIN_DIFF 5
+
+static int dell_battery_set_custom_charge_start(int start)
+{
+ struct calling_interface_buffer buffer;
+ int end;
+
+ start = clamp(start, CHARGE_START_MIN, CHARGE_START_MAX);
+ end = dell_battery_read(BAT_CUSTOM_CHARGE_END);
+ if (end < 0)
+ return end;
+ if ((end - start) < CHARGE_MIN_DIFF)
+ start = end - CHARGE_MIN_DIFF;
+
+ return dell_set_std_token_value(&buffer, BAT_CUSTOM_CHARGE_START,
+ start);
+}
+
+static int dell_battery_set_custom_charge_end(int end)
+{
+ struct calling_interface_buffer buffer;
+ int start;
+
+ end = clamp(end, CHARGE_END_MIN, CHARGE_END_MAX);
+ start = dell_battery_read(BAT_CUSTOM_CHARGE_START);
+ if (start < 0)
+ return start;
+ if ((end - start) < CHARGE_MIN_DIFF)
+ end = start + CHARGE_MIN_DIFF;
+
+ return dell_set_std_token_value(&buffer, BAT_CUSTOM_CHARGE_END, end);
+}
+
+static ssize_t charge_types_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ ssize_t count = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(battery_modes); i++) {
+ bool active;
+
+ if (!(battery_supported_modes & BIT(i)))
+ continue;
+
+ active = dell_battery_mode_is_active(battery_modes[i].token);
+ count += sysfs_emit_at(buf, count, active ? "[%s] " : "%s ",
+ battery_modes[i].label);
+ }
+
+ /* convert the last space to a newline */
+ if (count > 0)
+ count--;
+ count += sysfs_emit_at(buf, count, "\n");
+
+ return count;
+}
+
+static ssize_t charge_types_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ bool matched = false;
+ int err, i;
+
+ for (i = 0; i < ARRAY_SIZE(battery_modes); i++) {
+ if (!(battery_supported_modes & BIT(i)))
+ continue;
+
+ if (sysfs_streq(battery_modes[i].label, buf)) {
+ matched = true;
+ break;
+ }
+ }
+ if (!matched)
+ return -EINVAL;
+
+ err = dell_battery_set_mode(battery_modes[i].token);
+ if (err)
+ return err;
+
+ return size;
+}
+
+static ssize_t charge_control_start_threshold_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int start;
+
+ start = dell_battery_read(BAT_CUSTOM_CHARGE_START);
+ if (start < 0)
+ return start;
+
+ if (start > CHARGE_START_MAX)
+ return -EIO;
+
+ return sysfs_emit(buf, "%d\n", start);
+}
+
+static ssize_t charge_control_start_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret, start;
+
+ ret = kstrtoint(buf, 10, &start);
+ if (ret)
+ return ret;
+ if (start < 0 || start > 100)
+ return -EINVAL;
+
+ ret = dell_battery_set_custom_charge_start(start);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t charge_control_end_threshold_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int end;
+
+ end = dell_battery_read(BAT_CUSTOM_CHARGE_END);
+ if (end < 0)
+ return end;
+
+ if (end > CHARGE_END_MAX)
+ return -EIO;
+
+ return sysfs_emit(buf, "%d\n", end);
+}
+
+static ssize_t charge_control_end_threshold_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
+{
+ int ret, end;
+
+ ret = kstrtouint(buf, 10, &end);
+ if (ret)
+ return ret;
+ if (end < 0 || end > 100)
+ return -EINVAL;
+
+ ret = dell_battery_set_custom_charge_end(end);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static DEVICE_ATTR_RW(charge_control_start_threshold);
+static DEVICE_ATTR_RW(charge_control_end_threshold);
+static DEVICE_ATTR_RW(charge_types);
+
+static struct attribute *dell_battery_attrs[] = {
+ &dev_attr_charge_control_start_threshold.attr,
+ &dev_attr_charge_control_end_threshold.attr,
+ &dev_attr_charge_types.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(dell_battery);
+
+static int dell_battery_add(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ /* this currently only supports the primary battery */
+ if (strcmp(battery->desc->name, "BAT0") != 0)
return -ENODEV;
- dell_fill_request(&buffer, token->location, token->value, 0, 0);
- dell_send_request(&buffer, CLASS_TOKEN_WRITE, SELECT_TOKEN_STD);
+ return device_add_groups(&battery->dev, dell_battery_groups);
+}
+static int dell_battery_remove(struct power_supply *battery,
+ struct acpi_battery_hook *hook)
+{
+ device_remove_groups(&battery->dev, dell_battery_groups);
return 0;
}
-static struct led_classdev mute_led_cdev = {
- .name = "platform::mute",
- .max_brightness = 1,
- .brightness_set_blocking = mute_led_set,
- .default_trigger = "audio-mute",
+static struct acpi_battery_hook dell_battery_hook = {
+ .add_battery = dell_battery_add,
+ .remove_battery = dell_battery_remove,
+ .name = "Dell Primary Battery Extension",
};
+static u32 __init battery_get_supported_modes(void)
+{
+ u32 modes = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(battery_modes); i++) {
+ if (dell_smbios_find_token(battery_modes[i].token))
+ modes |= BIT(i);
+ }
+
+ return modes;
+}
+
+static void __init dell_battery_init(struct device *dev)
+{
+ battery_supported_modes = battery_get_supported_modes();
+
+ if (battery_supported_modes != 0)
+ battery_hook_register(&dell_battery_hook);
+}
+
+static void dell_battery_exit(void)
+{
+ if (battery_supported_modes != 0)
+ battery_hook_unregister(&dell_battery_hook);
+}
+
static int __init dell_init(void)
{
- struct calling_interface_token *token;
+ struct calling_interface_buffer buffer;
int max_intensity = 0;
int ret;
@@ -2219,6 +2477,7 @@ static int __init dell_init(void)
touchpad_led_init(&platform_device->dev);
kbd_led_init(&platform_device->dev);
+ dell_battery_init(&platform_device->dev);
dell_laptop_dir = debugfs_create_dir("dell_laptop", NULL);
debugfs_create_file("rfkill", 0444, dell_laptop_dir, NULL,
@@ -2246,16 +2505,10 @@ static int __init dell_init(void)
if (acpi_video_get_backlight_type() != acpi_backlight_vendor)
return 0;
- token = dell_smbios_find_token(BRIGHTNESS_TOKEN);
- if (token) {
- struct calling_interface_buffer buffer;
-
- dell_fill_request(&buffer, token->location, 0, 0, 0);
- ret = dell_send_request(&buffer,
- CLASS_TOKEN_READ, SELECT_TOKEN_AC);
- if (ret == 0)
- max_intensity = buffer.output[3];
- }
+ ret = dell_send_request_for_tokenid(&buffer, CLASS_TOKEN_READ,
+ SELECT_TOKEN_AC, BRIGHTNESS_TOKEN, 0);
+ if (ret == 0)
+ max_intensity = buffer.output[3];
if (max_intensity) {
struct backlight_properties props;
@@ -2293,6 +2546,7 @@ fail_backlight:
if (mute_led_registered)
led_classdev_unregister(&mute_led_cdev);
fail_led:
+ dell_battery_exit();
dell_cleanup_rfkill();
fail_rfkill:
platform_device_del(platform_device);
@@ -2311,6 +2565,7 @@ static void __exit dell_exit(void)
if (quirks && quirks->touchpad_led)
touchpad_led_exit();
kbd_led_exit();
+ dell_battery_exit();
backlight_device_unregister(dell_backlight_device);
if (micmute_led_registered)
led_classdev_unregister(&micmute_led_cdev);
diff --git a/drivers/platform/x86/dell/dell-smbios.h b/drivers/platform/x86/dell/dell-smbios.h
index ea0cc38642a2..77baa15eb523 100644
--- a/drivers/platform/x86/dell/dell-smbios.h
+++ b/drivers/platform/x86/dell/dell-smbios.h
@@ -33,6 +33,13 @@
#define KBD_LED_AUTO_50_TOKEN 0x02EB
#define KBD_LED_AUTO_75_TOKEN 0x02EC
#define KBD_LED_AUTO_100_TOKEN 0x02F6
+#define BAT_PRI_AC_MODE_TOKEN 0x0341
+#define BAT_ADAPTIVE_MODE_TOKEN 0x0342
+#define BAT_CUSTOM_MODE_TOKEN 0x0343
+#define BAT_STANDARD_MODE_TOKEN 0x0346
+#define BAT_EXPRESS_MODE_TOKEN 0x0347
+#define BAT_CUSTOM_CHARGE_START 0x0349
+#define BAT_CUSTOM_CHARGE_END 0x034A
#define GLOBAL_MIC_MUTE_ENABLE 0x0364
#define GLOBAL_MIC_MUTE_DISABLE 0x0365
#define GLOBAL_MUTE_ENABLE 0x058C
diff --git a/drivers/platform/x86/dell/dell-wmi-aio.c b/drivers/platform/x86/dell/dell-wmi-aio.c
index c7b7f1e403fb..54096495719b 100644
--- a/drivers/platform/x86/dell/dell-wmi-aio.c
+++ b/drivers/platform/x86/dell/dell-wmi-aio.c
@@ -70,20 +70,10 @@ static bool dell_wmi_aio_event_check(u8 *buffer, int length)
return false;
}
-static void dell_wmi_aio_notify(u32 value, void *context)
+static void dell_wmi_aio_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
struct dell_wmi_event *event;
- acpi_status status;
- status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_info("bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
if (obj) {
unsigned int scancode = 0;
@@ -114,7 +104,6 @@ static void dell_wmi_aio_notify(u32 value, void *context)
break;
}
}
- kfree(obj);
}
static int __init dell_wmi_aio_input_setup(void)
diff --git a/drivers/platform/x86/eeepc-laptop.c b/drivers/platform/x86/eeepc-laptop.c
index 447364bed249..03319a80e114 100644
--- a/drivers/platform/x86/eeepc-laptop.c
+++ b/drivers/platform/x86/eeepc-laptop.c
@@ -15,7 +15,6 @@
#include <linux/types.h>
#include <linux/platform_device.h>
#include <linux/backlight.h>
-#include <linux/fb.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
#include <linux/slab.h>
@@ -1137,7 +1136,7 @@ static int eeepc_backlight_init(struct eeepc_laptop *eeepc)
}
eeepc->backlight_device = bd;
bd->props.brightness = read_brightness(bd);
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
backlight_update_status(bd);
return 0;
}
diff --git a/drivers/platform/x86/eeepc-wmi.c b/drivers/platform/x86/eeepc-wmi.c
index 32d9f0ba6be3..37edb9ae67b8 100644
--- a/drivers/platform/x86/eeepc-wmi.c
+++ b/drivers/platform/x86/eeepc-wmi.c
@@ -13,13 +13,13 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/backlight.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/dmi.h>
-#include <linux/fb.h>
#include <linux/acpi.h>
#include "asus-wmi.h"
@@ -192,7 +192,7 @@ static void eeepc_wmi_quirks(struct asus_wmi_driver *driver)
driver->quirks = quirks;
driver->quirks->wapf = -1;
- driver->panel_power = FB_BLANK_UNBLANK;
+ driver->panel_power = BACKLIGHT_POWER_ON;
}
static struct asus_wmi_driver asus_wmi_driver = {
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 968fc91bd5e4..ae992ac1ab4a 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -43,7 +43,6 @@
#include <linux/bitops.h>
#include <linux/dmi.h>
#include <linux/backlight.h>
-#include <linux/fb.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
#include <linux/kfifo.h>
@@ -356,7 +355,7 @@ static int bl_get_brightness(struct backlight_device *b)
{
struct acpi_device *device = bl_get_data(b);
- return b->props.power == FB_BLANK_POWERDOWN ? 0 : get_lcd_level(device);
+ return b->props.power == BACKLIGHT_POWER_OFF ? 0 : get_lcd_level(device);
}
static int bl_update_status(struct backlight_device *b)
@@ -364,7 +363,7 @@ static int bl_update_status(struct backlight_device *b)
struct acpi_device *device = bl_get_data(b);
if (fext) {
- if (b->props.power == FB_BLANK_POWERDOWN)
+ if (b->props.power == BACKLIGHT_POWER_OFF)
call_fext_func(fext, FUNC_BACKLIGHT, 0x1,
BACKLIGHT_PARAM_POWER, BACKLIGHT_OFF);
else
@@ -933,9 +932,9 @@ static int acpi_fujitsu_laptop_add(struct acpi_device *device)
acpi_video_get_backlight_type() == acpi_backlight_vendor) {
if (call_fext_func(fext, FUNC_BACKLIGHT, 0x2,
BACKLIGHT_PARAM_POWER, 0x0) == BACKLIGHT_OFF)
- fujitsu_bl->bl_device->props.power = FB_BLANK_POWERDOWN;
+ fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_OFF;
else
- fujitsu_bl->bl_device->props.power = FB_BLANK_UNBLANK;
+ fujitsu_bl->bl_device->props.power = BACKLIGHT_POWER_ON;
}
ret = acpi_fujitsu_laptop_input_setup(device);
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 876e0a97cee1..8c05e0dd2a21 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -834,28 +834,16 @@ static struct attribute *hp_wmi_attrs[] = {
};
ATTRIBUTE_GROUPS(hp_wmi);
-static void hp_wmi_notify(u32 value, void *context)
+static void hp_wmi_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
u32 event_id, event_data;
- union acpi_object *obj;
- acpi_status status;
u32 *location;
int key_code;
- status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_info("bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
-
if (!obj)
return;
if (obj->type != ACPI_TYPE_BUFFER) {
pr_info("Unknown response received %d\n", obj->type);
- kfree(obj);
return;
}
@@ -872,10 +860,8 @@ static void hp_wmi_notify(u32 value, void *context)
event_data = *(location + 2);
} else {
pr_info("Unknown buffer length %d\n", obj->buffer.length);
- kfree(obj);
return;
}
- kfree(obj);
switch (event_id) {
case HPWMI_DOCK_EVENT:
diff --git a/drivers/platform/x86/huawei-wmi.c b/drivers/platform/x86/huawei-wmi.c
index 09d476dd832e..d81fd5df4a00 100644
--- a/drivers/platform/x86/huawei-wmi.c
+++ b/drivers/platform/x86/huawei-wmi.c
@@ -734,26 +734,14 @@ static void huawei_wmi_process_key(struct input_dev *idev, int code)
sparse_keymap_report_entry(idev, key, 1, true);
}
-static void huawei_wmi_input_notify(u32 value, void *context)
+static void huawei_wmi_input_notify(union acpi_object *obj, void *context)
{
struct input_dev *idev = (struct input_dev *)context;
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
- status = wmi_get_event_data(value, &response);
- if (ACPI_FAILURE(status)) {
- dev_err(&idev->dev, "Unable to get event data\n");
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER)
huawei_wmi_process_key(idev, obj->integer.value);
else
dev_err(&idev->dev, "Bad response type\n");
-
- kfree(response.pointer);
}
static int huawei_wmi_input_setup(struct device *dev, const char *guid)
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 98ec30fce9fd..c64dfc56651d 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -17,11 +17,11 @@
#include <linux/debugfs.h>
#include <linux/device.h>
#include <linux/dmi.h>
-#include <linux/fb.h>
#include <linux/i8042.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
@@ -87,6 +87,34 @@ enum {
SALS_FNLOCK_OFF = 0xf,
};
+enum {
+ VPCCMD_R_VPC1 = 0x10,
+ VPCCMD_R_BL_MAX,
+ VPCCMD_R_BL,
+ VPCCMD_W_BL,
+ VPCCMD_R_WIFI,
+ VPCCMD_W_WIFI,
+ VPCCMD_R_BT,
+ VPCCMD_W_BT,
+ VPCCMD_R_BL_POWER,
+ VPCCMD_R_NOVO,
+ VPCCMD_R_VPC2,
+ VPCCMD_R_TOUCHPAD,
+ VPCCMD_W_TOUCHPAD,
+ VPCCMD_R_CAMERA,
+ VPCCMD_W_CAMERA,
+ VPCCMD_R_3G,
+ VPCCMD_W_3G,
+ VPCCMD_R_ODD, /* 0x21 */
+ VPCCMD_W_FAN,
+ VPCCMD_R_RF,
+ VPCCMD_W_RF,
+ VPCCMD_W_YMC = 0x2A,
+ VPCCMD_R_FAN = 0x2B,
+ VPCCMD_R_SPECIAL_BUTTONS = 0x31,
+ VPCCMD_W_BL_POWER = 0x33,
+};
+
/*
* These correspond to the number of supported states - 1
* Future keyboard types may need a new system, if there's a collision
@@ -237,6 +265,7 @@ static void ideapad_shared_exit(struct ideapad_private *priv)
/*
* ACPI Helpers
*/
+#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
{
@@ -252,6 +281,29 @@ static int eval_int(acpi_handle handle, const char *name, unsigned long *res)
return 0;
}
+static int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg,
+ unsigned long *res)
+{
+ struct acpi_object_list params;
+ unsigned long long result;
+ union acpi_object in_obj;
+ acpi_status status;
+
+ params.count = 1;
+ params.pointer = &in_obj;
+ in_obj.type = ACPI_TYPE_INTEGER;
+ in_obj.integer.value = arg;
+
+ status = acpi_evaluate_integer(handle, (char *)name, &params, &result);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (res)
+ *res = result;
+
+ return 0;
+}
+
static int exec_simple_method(acpi_handle handle, const char *name, unsigned long arg)
{
acpi_status status = acpi_execute_simple_method(handle, (char *)name, arg);
@@ -294,6 +346,89 @@ static int eval_dytc(acpi_handle handle, unsigned long cmd, unsigned long *res)
return eval_int_with_arg(handle, "DYTC", cmd, res);
}
+static int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
+{
+ return eval_int_with_arg(handle, "VPCR", cmd, res);
+}
+
+static int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
+{
+ struct acpi_object_list params;
+ union acpi_object in_obj[2];
+ acpi_status status;
+
+ params.count = 2;
+ params.pointer = in_obj;
+ in_obj[0].type = ACPI_TYPE_INTEGER;
+ in_obj[0].integer.value = cmd;
+ in_obj[1].type = ACPI_TYPE_INTEGER;
+ in_obj[1].integer.value = data;
+
+ status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ return 0;
+}
+
+static int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
+{
+ unsigned long end_jiffies, val;
+ int err;
+
+ err = eval_vpcw(handle, 1, cmd);
+ if (err)
+ return err;
+
+ end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
+
+ while (time_before(jiffies, end_jiffies)) {
+ schedule();
+
+ err = eval_vpcr(handle, 1, &val);
+ if (err)
+ return err;
+
+ if (val == 0)
+ return eval_vpcr(handle, 0, data);
+ }
+
+ acpi_handle_err(handle, "timeout in %s\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
+static int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
+{
+ unsigned long end_jiffies, val;
+ int err;
+
+ err = eval_vpcw(handle, 0, data);
+ if (err)
+ return err;
+
+ err = eval_vpcw(handle, 1, cmd);
+ if (err)
+ return err;
+
+ end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
+
+ while (time_before(jiffies, end_jiffies)) {
+ schedule();
+
+ err = eval_vpcr(handle, 1, &val);
+ if (err)
+ return err;
+
+ if (val == 0)
+ return 0;
+ }
+
+ acpi_handle_err(handle, "timeout in %s\n", __func__);
+
+ return -ETIMEDOUT;
+}
+
/*
* debugfs
*/
@@ -419,13 +554,14 @@ static ssize_t camera_power_show(struct device *dev,
char *buf)
{
struct ideapad_private *priv = dev_get_drvdata(dev);
- unsigned long result;
+ unsigned long result = 0;
int err;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = read_ec_data(priv->adev->handle, VPCCMD_R_CAMERA, &result);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
return sysfs_emit(buf, "%d\n", !!result);
}
@@ -442,10 +578,11 @@ static ssize_t camera_power_store(struct device *dev,
if (err)
return err;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_CAMERA, state);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
return count;
}
@@ -493,13 +630,14 @@ static ssize_t fan_mode_show(struct device *dev,
char *buf)
{
struct ideapad_private *priv = dev_get_drvdata(dev);
- unsigned long result;
+ unsigned long result = 0;
int err;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = read_ec_data(priv->adev->handle, VPCCMD_R_FAN, &result);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
return sysfs_emit(buf, "%lu\n", result);
}
@@ -519,10 +657,11 @@ static ssize_t fan_mode_store(struct device *dev,
if (state > 4 || state == 3)
return -EINVAL;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_FAN, state);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
return count;
}
@@ -602,13 +741,14 @@ static ssize_t touchpad_show(struct device *dev,
char *buf)
{
struct ideapad_private *priv = dev_get_drvdata(dev);
- unsigned long result;
+ unsigned long result = 0;
int err;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = read_ec_data(priv->adev->handle, VPCCMD_R_TOUCHPAD, &result);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
priv->r_touchpad_val = result;
@@ -627,10 +767,11 @@ static ssize_t touchpad_store(struct device *dev,
if (err)
return err;
- scoped_guard(mutex, &priv->vpc_mutex)
+ scoped_guard(mutex, &priv->vpc_mutex) {
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_TOUCHPAD, state);
- if (err)
- return err;
+ if (err)
+ return err;
+ }
priv->r_touchpad_val = state;
@@ -1282,7 +1423,7 @@ static int ideapad_backlight_update_status(struct backlight_device *blightdev)
return err;
err = write_ec_cmd(priv->adev->handle, VPCCMD_W_BL_POWER,
- blightdev->props.power != FB_BLANK_POWERDOWN);
+ blightdev->props.power != BACKLIGHT_POWER_OFF);
if (err)
return err;
@@ -1332,7 +1473,7 @@ static int ideapad_backlight_init(struct ideapad_private *priv)
priv->blightdev = blightdev;
blightdev->props.brightness = now;
- blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+ blightdev->props.power = power ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
backlight_update_status(blightdev);
@@ -1358,7 +1499,7 @@ static void ideapad_backlight_notify_power(struct ideapad_private *priv)
if (read_ec_data(priv->adev->handle, VPCCMD_R_BL_POWER, &power))
return;
- blightdev->props.power = power ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
+ blightdev->props.power = power ? BACKLIGHT_POWER_ON : BACKLIGHT_POWER_OFF;
}
static void ideapad_backlight_notify_brightness(struct ideapad_private *priv)
diff --git a/drivers/platform/x86/ideapad-laptop.h b/drivers/platform/x86/ideapad-laptop.h
index 948cc61800a9..1e52f2aa0aac 100644
--- a/drivers/platform/x86/ideapad-laptop.h
+++ b/drivers/platform/x86/ideapad-laptop.h
@@ -9,9 +9,6 @@
#ifndef _IDEAPAD_LAPTOP_H_
#define _IDEAPAD_LAPTOP_H_
-#include <linux/acpi.h>
-#include <linux/jiffies.h>
-#include <linux/errno.h>
#include <linux/notifier.h>
enum ideapad_laptop_notifier_actions {
@@ -22,140 +19,4 @@ int ideapad_laptop_register_notifier(struct notifier_block *nb);
int ideapad_laptop_unregister_notifier(struct notifier_block *nb);
void ideapad_laptop_call_notifier(unsigned long action, void *data);
-enum {
- VPCCMD_R_VPC1 = 0x10,
- VPCCMD_R_BL_MAX,
- VPCCMD_R_BL,
- VPCCMD_W_BL,
- VPCCMD_R_WIFI,
- VPCCMD_W_WIFI,
- VPCCMD_R_BT,
- VPCCMD_W_BT,
- VPCCMD_R_BL_POWER,
- VPCCMD_R_NOVO,
- VPCCMD_R_VPC2,
- VPCCMD_R_TOUCHPAD,
- VPCCMD_W_TOUCHPAD,
- VPCCMD_R_CAMERA,
- VPCCMD_W_CAMERA,
- VPCCMD_R_3G,
- VPCCMD_W_3G,
- VPCCMD_R_ODD, /* 0x21 */
- VPCCMD_W_FAN,
- VPCCMD_R_RF,
- VPCCMD_W_RF,
- VPCCMD_W_YMC = 0x2A,
- VPCCMD_R_FAN = 0x2B,
- VPCCMD_R_SPECIAL_BUTTONS = 0x31,
- VPCCMD_W_BL_POWER = 0x33,
-};
-
-static inline int eval_int_with_arg(acpi_handle handle, const char *name, unsigned long arg, unsigned long *res)
-{
- struct acpi_object_list params;
- unsigned long long result;
- union acpi_object in_obj;
- acpi_status status;
-
- params.count = 1;
- params.pointer = &in_obj;
- in_obj.type = ACPI_TYPE_INTEGER;
- in_obj.integer.value = arg;
-
- status = acpi_evaluate_integer(handle, (char *)name, &params, &result);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- if (res)
- *res = result;
-
- return 0;
-}
-
-static inline int eval_vpcr(acpi_handle handle, unsigned long cmd, unsigned long *res)
-{
- return eval_int_with_arg(handle, "VPCR", cmd, res);
-}
-
-static inline int eval_vpcw(acpi_handle handle, unsigned long cmd, unsigned long data)
-{
- struct acpi_object_list params;
- union acpi_object in_obj[2];
- acpi_status status;
-
- params.count = 2;
- params.pointer = in_obj;
- in_obj[0].type = ACPI_TYPE_INTEGER;
- in_obj[0].integer.value = cmd;
- in_obj[1].type = ACPI_TYPE_INTEGER;
- in_obj[1].integer.value = data;
-
- status = acpi_evaluate_object(handle, "VPCW", &params, NULL);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- return 0;
-}
-
-#define IDEAPAD_EC_TIMEOUT 200 /* in ms */
-
-static inline int read_ec_data(acpi_handle handle, unsigned long cmd, unsigned long *data)
-{
- unsigned long end_jiffies, val;
- int err;
-
- err = eval_vpcw(handle, 1, cmd);
- if (err)
- return err;
-
- end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
-
- while (time_before(jiffies, end_jiffies)) {
- schedule();
-
- err = eval_vpcr(handle, 1, &val);
- if (err)
- return err;
-
- if (val == 0)
- return eval_vpcr(handle, 0, data);
- }
-
- acpi_handle_err(handle, "timeout in %s\n", __func__);
-
- return -ETIMEDOUT;
-}
-
-static inline int write_ec_cmd(acpi_handle handle, unsigned long cmd, unsigned long data)
-{
- unsigned long end_jiffies, val;
- int err;
-
- err = eval_vpcw(handle, 0, data);
- if (err)
- return err;
-
- err = eval_vpcw(handle, 1, cmd);
- if (err)
- return err;
-
- end_jiffies = jiffies + msecs_to_jiffies(IDEAPAD_EC_TIMEOUT) + 1;
-
- while (time_before(jiffies, end_jiffies)) {
- schedule();
-
- err = eval_vpcr(handle, 1, &val);
- if (err)
- return err;
-
- if (val == 0)
- return 0;
- }
-
- acpi_handle_err(handle, "timeout in %s\n", __func__);
-
- return -ETIMEDOUT;
-}
-
-#undef IDEAPAD_EC_TIMEOUT
#endif /* !_IDEAPAD_LAPTOP_H_ */
diff --git a/drivers/platform/x86/intel/hid.c b/drivers/platform/x86/intel/hid.c
index 10cd65497cc1..445e7a59beb4 100644
--- a/drivers/platform/x86/intel/hid.c
+++ b/drivers/platform/x86/intel/hid.c
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/string_choices.h>
#include <linux/suspend.h>
#include "../dual_accel_detect.h"
@@ -331,10 +332,8 @@ static int intel_hid_set_enable(struct device *device, bool enable)
acpi_handle handle = ACPI_HANDLE(device);
/* Enable|disable features - power button is always enabled */
- if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN,
- enable)) {
- dev_warn(device, "failed to %sable hotkeys\n",
- enable ? "en" : "dis");
+ if (!intel_hid_execute_method(handle, INTEL_HID_DSM_HDSM_FN, enable)) {
+ dev_warn(device, "failed to %s hotkeys\n", str_enable_disable(enable));
return -EIO;
}
diff --git a/drivers/platform/x86/intel/ifs/core.c b/drivers/platform/x86/intel/ifs/core.c
index 33412a584836..bc252b883210 100644
--- a/drivers/platform/x86/intel/ifs/core.c
+++ b/drivers/platform/x86/intel/ifs/core.c
@@ -32,6 +32,7 @@ bool *ifs_pkg_auth;
static const struct ifs_test_caps scan_test = {
.integrity_cap_bit = MSR_INTEGRITY_CAPS_PERIODIC_BIST_BIT,
.test_num = IFS_TYPE_SAF,
+ .image_suffix = "scan",
};
static const struct ifs_test_caps array_test = {
@@ -39,9 +40,32 @@ static const struct ifs_test_caps array_test = {
.test_num = IFS_TYPE_ARRAY_BIST,
};
+static const struct ifs_test_msrs scan_msrs = {
+ .copy_hashes = MSR_COPY_SCAN_HASHES,
+ .copy_hashes_status = MSR_SCAN_HASHES_STATUS,
+ .copy_chunks = MSR_AUTHENTICATE_AND_COPY_CHUNK,
+ .copy_chunks_status = MSR_CHUNKS_AUTHENTICATION_STATUS,
+ .test_ctrl = MSR_SAF_CTRL,
+};
+
+static const struct ifs_test_msrs sbaf_msrs = {
+ .copy_hashes = MSR_COPY_SBAF_HASHES,
+ .copy_hashes_status = MSR_SBAF_HASHES_STATUS,
+ .copy_chunks = MSR_AUTHENTICATE_AND_COPY_SBAF_CHUNK,
+ .copy_chunks_status = MSR_SBAF_CHUNKS_AUTHENTICATION_STATUS,
+ .test_ctrl = MSR_SBAF_CTRL,
+};
+
+static const struct ifs_test_caps sbaf_test = {
+ .integrity_cap_bit = MSR_INTEGRITY_CAPS_SBAF_BIT,
+ .test_num = IFS_TYPE_SBAF,
+ .image_suffix = "sbft",
+};
+
static struct ifs_device ifs_devices[] = {
[IFS_TYPE_SAF] = {
.test_caps = &scan_test,
+ .test_msrs = &scan_msrs,
.misc = {
.name = "intel_ifs_0",
.minor = MISC_DYNAMIC_MINOR,
@@ -56,6 +80,15 @@ static struct ifs_device ifs_devices[] = {
.groups = plat_ifs_array_groups,
},
},
+ [IFS_TYPE_SBAF] = {
+ .test_caps = &sbaf_test,
+ .test_msrs = &sbaf_msrs,
+ .misc = {
+ .name = "intel_ifs_2",
+ .minor = MISC_DYNAMIC_MINOR,
+ .groups = plat_ifs_groups,
+ },
+ },
};
#define IFS_NUMTESTS ARRAY_SIZE(ifs_devices)
diff --git a/drivers/platform/x86/intel/ifs/ifs.h b/drivers/platform/x86/intel/ifs/ifs.h
index 56b9f3e3cf76..5c3c0dfa1bf8 100644
--- a/drivers/platform/x86/intel/ifs/ifs.h
+++ b/drivers/platform/x86/intel/ifs/ifs.h
@@ -126,11 +126,40 @@
* The driver does not make use of this, it only tests one core at a time.
*
* .. [#f1] https://github.com/intel/TBD
+ *
+ *
+ * Structural Based Functional Test at Field (SBAF):
+ * -------------------------------------------------
+ *
+ * SBAF is a new type of testing that provides comprehensive core test
+ * coverage complementing Scan at Field (SAF) testing. SBAF mimics the
+ * manufacturing screening environment and leverages the same test suite.
+ * It makes use of Design For Test (DFT) observation sites and features
+ * to maximize coverage in minimum time.
+ *
+ * Similar to the SAF test, SBAF isolates the core under test from the
+ * rest of the system during execution. Upon completion, the core
+ * seamlessly resets to its pre-test state and resumes normal operation.
+ * Any machine checks or hangs encountered during the test are confined to
+ * the isolated core, preventing disruption to the overall system.
+ *
+ * Like the SAF test, the SBAF test is also divided into multiple batches,
+ * and each batch test can take hundreds of milliseconds (100-200 ms) to
+ * complete. If such a lengthy interruption is undesirable, it is
+ * recommended to relocate the time-sensitive applications to other cores.
*/
#include <linux/device.h>
#include <linux/miscdevice.h>
#define MSR_ARRAY_BIST 0x00000105
+
+#define MSR_COPY_SBAF_HASHES 0x000002b8
+#define MSR_SBAF_HASHES_STATUS 0x000002b9
+#define MSR_AUTHENTICATE_AND_COPY_SBAF_CHUNK 0x000002ba
+#define MSR_SBAF_CHUNKS_AUTHENTICATION_STATUS 0x000002bb
+#define MSR_ACTIVATE_SBAF 0x000002bc
+#define MSR_SBAF_STATUS 0x000002bd
+
#define MSR_COPY_SCAN_HASHES 0x000002c2
#define MSR_SCAN_HASHES_STATUS 0x000002c3
#define MSR_AUTHENTICATE_AND_COPY_CHUNK 0x000002c4
@@ -140,6 +169,7 @@
#define MSR_ARRAY_TRIGGER 0x000002d6
#define MSR_ARRAY_STATUS 0x000002d7
#define MSR_SAF_CTRL 0x000004f0
+#define MSR_SBAF_CTRL 0x000004f8
#define SCAN_NOT_TESTED 0
#define SCAN_TEST_PASS 1
@@ -147,6 +177,7 @@
#define IFS_TYPE_SAF 0
#define IFS_TYPE_ARRAY_BIST 1
+#define IFS_TYPE_SBAF 2
#define ARRAY_GEN0 0
#define ARRAY_GEN1 1
@@ -196,7 +227,8 @@ union ifs_chunks_auth_status_gen2 {
u16 valid_chunks;
u16 total_chunks;
u32 error_code :8;
- u32 rsvd2 :24;
+ u32 rsvd2 :8;
+ u32 max_bundle :16;
};
};
@@ -253,6 +285,34 @@ union ifs_array {
};
};
+/* MSR_ACTIVATE_SBAF bit fields */
+union ifs_sbaf {
+ u64 data;
+ struct {
+ u32 bundle_idx :9;
+ u32 rsvd1 :5;
+ u32 pgm_idx :2;
+ u32 rsvd2 :16;
+ u32 delay :31;
+ u32 sigmce :1;
+ };
+};
+
+/* MSR_SBAF_STATUS bit fields */
+union ifs_sbaf_status {
+ u64 data;
+ struct {
+ u32 bundle_idx :9;
+ u32 rsvd1 :5;
+ u32 pgm_idx :2;
+ u32 rsvd2 :16;
+ u32 error_code :8;
+ u32 rsvd3 :21;
+ u32 test_fail :1;
+ u32 sbaf_status :2;
+ };
+};
+
/*
* Driver populated error-codes
* 0xFD: Test timed out before completing all the chunks.
@@ -261,9 +321,28 @@ union ifs_array {
#define IFS_SW_TIMEOUT 0xFD
#define IFS_SW_PARTIAL_COMPLETION 0xFE
+#define IFS_SUFFIX_SZ 5
+
struct ifs_test_caps {
int integrity_cap_bit;
int test_num;
+ char image_suffix[IFS_SUFFIX_SZ];
+};
+
+/**
+ * struct ifs_test_msrs - MSRs used in IFS tests
+ * @copy_hashes: Copy test hash data
+ * @copy_hashes_status: Status of copied test hash data
+ * @copy_chunks: Copy chunks of the test data
+ * @copy_chunks_status: Status of the copied test data chunks
+ * @test_ctrl: Control the test attributes
+ */
+struct ifs_test_msrs {
+ u32 copy_hashes;
+ u32 copy_hashes_status;
+ u32 copy_chunks;
+ u32 copy_chunks_status;
+ u32 test_ctrl;
};
/**
@@ -278,6 +357,7 @@ struct ifs_test_caps {
* @generation: IFS test generation enumerated by hardware
* @chunk_size: size of a test chunk
* @array_gen: test generation of array test
+ * @max_bundle: maximum bundle index
*/
struct ifs_data {
int loaded_version;
@@ -290,6 +370,7 @@ struct ifs_data {
u32 generation;
u32 chunk_size;
u32 array_gen;
+ u32 max_bundle;
};
struct ifs_work {
@@ -299,6 +380,7 @@ struct ifs_work {
struct ifs_device {
const struct ifs_test_caps *test_caps;
+ const struct ifs_test_msrs *test_msrs;
struct ifs_data rw_data;
struct miscdevice misc;
};
@@ -319,6 +401,14 @@ static inline const struct ifs_test_caps *ifs_get_test_caps(struct device *dev)
return d->test_caps;
}
+static inline const struct ifs_test_msrs *ifs_get_test_msrs(struct device *dev)
+{
+ struct miscdevice *m = dev_get_drvdata(dev);
+ struct ifs_device *d = container_of(m, struct ifs_device, misc);
+
+ return d->test_msrs;
+}
+
extern bool *ifs_pkg_auth;
int ifs_load_firmware(struct device *dev);
int do_core_test(int cpu, struct device *dev);
diff --git a/drivers/platform/x86/intel/ifs/load.c b/drivers/platform/x86/intel/ifs/load.c
index 39f19cb51749..de54bd1a5970 100644
--- a/drivers/platform/x86/intel/ifs/load.c
+++ b/drivers/platform/x86/intel/ifs/load.c
@@ -118,15 +118,17 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
union ifs_scan_hashes_status hashes_status;
union ifs_chunks_auth_status chunk_status;
struct device *dev = local_work->dev;
+ const struct ifs_test_msrs *msrs;
int i, num_chunks, chunk_size;
struct ifs_data *ifsd;
u64 linear_addr, base;
u32 err_code;
ifsd = ifs_get_data(dev);
+ msrs = ifs_get_test_msrs(dev);
/* run scan hash copy */
- wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
- rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
+ wrmsrl(msrs->copy_hashes, ifs_hash_ptr);
+ rdmsrl(msrs->copy_hashes_status, hashes_status.data);
/* enumerate the scan image information */
num_chunks = hashes_status.num_chunks;
@@ -147,8 +149,8 @@ static void copy_hashes_authenticate_chunks(struct work_struct *work)
linear_addr = base + i * chunk_size;
linear_addr |= i;
- wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, linear_addr);
- rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
+ wrmsrl(msrs->copy_chunks, linear_addr);
+ rdmsrl(msrs->copy_chunks_status, chunk_status.data);
ifsd->valid_chunks = chunk_status.valid_chunks;
err_code = chunk_status.error_code;
@@ -180,6 +182,7 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
union ifs_scan_hashes_status_gen2 hashes_status;
union ifs_chunks_auth_status_gen2 chunk_status;
u32 err_code, valid_chunks, total_chunks;
+ const struct ifs_test_msrs *msrs;
int i, num_chunks, chunk_size;
union meta_data *ifs_meta;
int starting_chunk_nr;
@@ -189,10 +192,11 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
int retry_count;
ifsd = ifs_get_data(dev);
+ msrs = ifs_get_test_msrs(dev);
if (need_copy_scan_hashes(ifsd)) {
- wrmsrl(MSR_COPY_SCAN_HASHES, ifs_hash_ptr);
- rdmsrl(MSR_SCAN_HASHES_STATUS, hashes_status.data);
+ wrmsrl(msrs->copy_hashes, ifs_hash_ptr);
+ rdmsrl(msrs->copy_hashes_status, hashes_status.data);
/* enumerate the scan image information */
chunk_size = hashes_status.chunk_size * SZ_1K;
@@ -212,8 +216,8 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
}
if (ifsd->generation >= IFS_GEN_STRIDE_AWARE) {
- wrmsrl(MSR_SAF_CTRL, INVALIDATE_STRIDE);
- rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
+ wrmsrl(msrs->test_ctrl, INVALIDATE_STRIDE);
+ rdmsrl(msrs->copy_chunks_status, chunk_status.data);
if (chunk_status.valid_chunks != 0) {
dev_err(dev, "Couldn't invalidate installed stride - %d\n",
chunk_status.valid_chunks);
@@ -234,9 +238,9 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
chunk_table[1] = linear_addr;
do {
local_irq_disable();
- wrmsrl(MSR_AUTHENTICATE_AND_COPY_CHUNK, (u64)chunk_table);
+ wrmsrl(msrs->copy_chunks, (u64)chunk_table);
local_irq_enable();
- rdmsrl(MSR_CHUNKS_AUTHENTICATION_STATUS, chunk_status.data);
+ rdmsrl(msrs->copy_chunks_status, chunk_status.data);
err_code = chunk_status.error_code;
} while (err_code == AUTH_INTERRUPTED_ERROR && --retry_count);
@@ -257,20 +261,22 @@ static int copy_hashes_authenticate_chunks_gen2(struct device *dev)
return -EIO;
}
ifsd->valid_chunks = valid_chunks;
+ ifsd->max_bundle = chunk_status.max_bundle;
return 0;
}
static int validate_ifs_metadata(struct device *dev)
{
+ const struct ifs_test_caps *test = ifs_get_test_caps(dev);
struct ifs_data *ifsd = ifs_get_data(dev);
union meta_data *ifs_meta;
char test_file[64];
int ret = -EINVAL;
- snprintf(test_file, sizeof(test_file), "%02x-%02x-%02x-%02x.scan",
+ snprintf(test_file, sizeof(test_file), "%02x-%02x-%02x-%02x.%s",
boot_cpu_data.x86, boot_cpu_data.x86_model,
- boot_cpu_data.x86_stepping, ifsd->cur_batch);
+ boot_cpu_data.x86_stepping, ifsd->cur_batch, test->image_suffix);
ifs_meta = (union meta_data *)find_meta_data(ifs_header_ptr, META_TYPE_IFS);
if (!ifs_meta) {
@@ -300,6 +306,12 @@ static int validate_ifs_metadata(struct device *dev)
return ret;
}
+ if (ifs_meta->test_type != test->test_num) {
+ dev_warn(dev, "Metadata test_type %d mismatches with device type\n",
+ ifs_meta->test_type);
+ return ret;
+ }
+
return 0;
}
@@ -387,9 +399,9 @@ int ifs_load_firmware(struct device *dev)
char scan_path[64];
int ret;
- snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.scan",
+ snprintf(scan_path, sizeof(scan_path), "intel/ifs_%d/%02x-%02x-%02x-%02x.%s",
test->test_num, boot_cpu_data.x86, boot_cpu_data.x86_model,
- boot_cpu_data.x86_stepping, ifsd->cur_batch);
+ boot_cpu_data.x86_stepping, ifsd->cur_batch, test->image_suffix);
ret = request_firmware_direct(&fw, scan_path, dev);
if (ret) {
diff --git a/drivers/platform/x86/intel/ifs/runtest.c b/drivers/platform/x86/intel/ifs/runtest.c
index be3d51ed0e47..f978dd05d4d8 100644
--- a/drivers/platform/x86/intel/ifs/runtest.c
+++ b/drivers/platform/x86/intel/ifs/runtest.c
@@ -29,6 +29,13 @@ struct run_params {
union ifs_status status;
};
+struct sbaf_run_params {
+ struct ifs_data *ifsd;
+ int *retry_cnt;
+ union ifs_sbaf *activate;
+ union ifs_sbaf_status status;
+};
+
/*
* Number of TSC cycles that a logical CPU will wait for the other
* logical CPU on the core in the WRMSR(ACTIVATE_SCAN).
@@ -146,6 +153,7 @@ static bool can_restart(union ifs_status status)
#define SPINUNIT 100 /* 100 nsec */
static atomic_t array_cpus_in;
static atomic_t scan_cpus_in;
+static atomic_t sbaf_cpus_in;
/*
* Simplified cpu sibling rendezvous loop based on microcode loader __wait_for_cpus()
@@ -387,6 +395,225 @@ static void ifs_array_test_gen1(int cpu, struct device *dev)
ifsd->status = SCAN_TEST_PASS;
}
+#define SBAF_STATUS_PASS 0
+#define SBAF_STATUS_SIGN_FAIL 1
+#define SBAF_STATUS_INTR 2
+#define SBAF_STATUS_TEST_FAIL 3
+
+enum sbaf_status_err_code {
+ IFS_SBAF_NO_ERROR = 0,
+ IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN = 1,
+ IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS = 2,
+ IFS_SBAF_UNASSIGNED_ERROR_CODE3 = 3,
+ IFS_SBAF_INVALID_BUNDLE_INDEX = 4,
+ IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS = 5,
+ IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY = 6,
+ IFS_SBAF_UNASSIGNED_ERROR_CODE7 = 7,
+ IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT = 8,
+ IFS_SBAF_INTERRUPTED_DURING_EXECUTION = 9,
+ IFS_SBAF_INVALID_PROGRAM_INDEX = 0xA,
+ IFS_SBAF_CORRUPTED_CHUNK = 0xB,
+ IFS_SBAF_DID_NOT_START = 0xC,
+};
+
+static const char * const sbaf_test_status[] = {
+ [IFS_SBAF_NO_ERROR] = "SBAF no error",
+ [IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN] = "Other thread could not join.",
+ [IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS] = "Interrupt occurred prior to SBAF coordination.",
+ [IFS_SBAF_UNASSIGNED_ERROR_CODE3] = "Unassigned error code 0x3",
+ [IFS_SBAF_INVALID_BUNDLE_INDEX] = "Non-valid sbaf bundles. Reload test image",
+ [IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS] = "Mismatch in arguments between threads T0/T1.",
+ [IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY] = "Core not capable of performing SBAF currently",
+ [IFS_SBAF_UNASSIGNED_ERROR_CODE7] = "Unassigned error code 0x7",
+ [IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT] = "Exceeded number of Logical Processors (LP) allowed to run Scan-At-Field concurrently",
+ [IFS_SBAF_INTERRUPTED_DURING_EXECUTION] = "Interrupt occurred prior to SBAF start",
+ [IFS_SBAF_INVALID_PROGRAM_INDEX] = "SBAF program index not valid",
+ [IFS_SBAF_CORRUPTED_CHUNK] = "SBAF operation aborted due to corrupted chunk",
+ [IFS_SBAF_DID_NOT_START] = "SBAF operation did not start",
+};
+
+static void sbaf_message_not_tested(struct device *dev, int cpu, u64 status_data)
+{
+ union ifs_sbaf_status status = (union ifs_sbaf_status)status_data;
+
+ if (status.error_code < ARRAY_SIZE(sbaf_test_status)) {
+ dev_info(dev, "CPU(s) %*pbl: SBAF operation did not start. %s\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)),
+ sbaf_test_status[status.error_code]);
+ } else if (status.error_code == IFS_SW_TIMEOUT) {
+ dev_info(dev, "CPU(s) %*pbl: software timeout during scan\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)));
+ } else if (status.error_code == IFS_SW_PARTIAL_COMPLETION) {
+ dev_info(dev, "CPU(s) %*pbl: %s\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)),
+ "Not all SBAF bundles executed. Maximum forward progress retries exceeded");
+ } else {
+ dev_info(dev, "CPU(s) %*pbl: SBAF unknown status %llx\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)), status.data);
+ }
+}
+
+static void sbaf_message_fail(struct device *dev, int cpu, union ifs_sbaf_status status)
+{
+ /* Failed signature check is set when SBAF signature did not match the expected value */
+ if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL) {
+ dev_err(dev, "CPU(s) %*pbl: Failed signature check\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)));
+ }
+
+ /* Failed to reach end of test */
+ if (status.sbaf_status == SBAF_STATUS_TEST_FAIL) {
+ dev_err(dev, "CPU(s) %*pbl: Failed to complete test\n",
+ cpumask_pr_args(cpu_smt_mask(cpu)));
+ }
+}
+
+static bool sbaf_bundle_completed(union ifs_sbaf_status status)
+{
+ return !(status.sbaf_status || status.error_code);
+}
+
+static bool sbaf_can_restart(union ifs_sbaf_status status)
+{
+ enum sbaf_status_err_code err_code = status.error_code;
+
+ /* Signature for chunk is bad, or scan test failed */
+ if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL ||
+ status.sbaf_status == SBAF_STATUS_TEST_FAIL)
+ return false;
+
+ switch (err_code) {
+ case IFS_SBAF_NO_ERROR:
+ case IFS_SBAF_OTHER_THREAD_COULD_NOT_JOIN:
+ case IFS_SBAF_INTERRUPTED_BEFORE_RENDEZVOUS:
+ case IFS_SBAF_EXCEED_NUMBER_OF_THREADS_CONCURRENT:
+ case IFS_SBAF_INTERRUPTED_DURING_EXECUTION:
+ return true;
+ case IFS_SBAF_UNASSIGNED_ERROR_CODE3:
+ case IFS_SBAF_INVALID_BUNDLE_INDEX:
+ case IFS_SBAF_MISMATCH_ARGS_BETWEEN_THREADS:
+ case IFS_SBAF_CORE_NOT_CAPABLE_CURRENTLY:
+ case IFS_SBAF_UNASSIGNED_ERROR_CODE7:
+ case IFS_SBAF_INVALID_PROGRAM_INDEX:
+ case IFS_SBAF_CORRUPTED_CHUNK:
+ case IFS_SBAF_DID_NOT_START:
+ break;
+ }
+ return false;
+}
+
+/*
+ * Execute the SBAF test. Called "simultaneously" on all threads of a core
+ * at high priority using the stop_cpus mechanism.
+ */
+static int dosbaf(void *data)
+{
+ struct sbaf_run_params *run_params = data;
+ int cpu = smp_processor_id();
+ union ifs_sbaf_status status;
+ struct ifs_data *ifsd;
+ int first;
+
+ ifsd = run_params->ifsd;
+
+ /* Only the first logical CPU on a core reports result */
+ first = cpumask_first(cpu_smt_mask(cpu));
+ wait_for_sibling_cpu(&sbaf_cpus_in, NSEC_PER_SEC);
+
+ /*
+ * This WRMSR will wait for other HT threads to also write
+ * to this MSR (at most for activate.delay cycles). Then it
+ * starts scan of each requested bundle. The core test happens
+ * during the "execution" of the WRMSR.
+ */
+ wrmsrl(MSR_ACTIVATE_SBAF, run_params->activate->data);
+ rdmsrl(MSR_SBAF_STATUS, status.data);
+ trace_ifs_sbaf(ifsd->cur_batch, *run_params->activate, status);
+
+ /* Pass back the result of the test */
+ if (cpu == first)
+ run_params->status = status;
+
+ return 0;
+}
+
+static void ifs_sbaf_test_core(int cpu, struct device *dev)
+{
+ struct sbaf_run_params run_params;
+ union ifs_sbaf_status status = {};
+ union ifs_sbaf activate;
+ unsigned long timeout;
+ struct ifs_data *ifsd;
+ int stop_bundle;
+ int retries;
+
+ ifsd = ifs_get_data(dev);
+
+ activate.data = 0;
+ activate.delay = IFS_THREAD_WAIT;
+
+ timeout = jiffies + 2 * HZ;
+ retries = MAX_IFS_RETRIES;
+ activate.bundle_idx = 0;
+ stop_bundle = ifsd->max_bundle;
+
+ while (activate.bundle_idx <= stop_bundle) {
+ if (time_after(jiffies, timeout)) {
+ status.error_code = IFS_SW_TIMEOUT;
+ break;
+ }
+
+ atomic_set(&sbaf_cpus_in, 0);
+
+ run_params.ifsd = ifsd;
+ run_params.activate = &activate;
+ run_params.retry_cnt = &retries;
+ stop_core_cpuslocked(cpu, dosbaf, &run_params);
+
+ status = run_params.status;
+
+ if (sbaf_bundle_completed(status)) {
+ activate.bundle_idx = status.bundle_idx + 1;
+ activate.pgm_idx = 0;
+ retries = MAX_IFS_RETRIES;
+ continue;
+ }
+
+ /* Some cases can be retried, give up for others */
+ if (!sbaf_can_restart(status))
+ break;
+
+ if (status.pgm_idx == activate.pgm_idx) {
+ /* If no progress retry */
+ if (--retries == 0) {
+ if (status.error_code == IFS_NO_ERROR)
+ status.error_code = IFS_SW_PARTIAL_COMPLETION;
+ break;
+ }
+ } else {
+ /* if some progress, more pgms remaining in bundle, reset retries */
+ retries = MAX_IFS_RETRIES;
+ activate.bundle_idx = status.bundle_idx;
+ activate.pgm_idx = status.pgm_idx;
+ }
+ }
+
+ /* Update status for this core */
+ ifsd->scan_details = status.data;
+
+ if (status.sbaf_status == SBAF_STATUS_SIGN_FAIL ||
+ status.sbaf_status == SBAF_STATUS_TEST_FAIL) {
+ ifsd->status = SCAN_TEST_FAIL;
+ sbaf_message_fail(dev, cpu, status);
+ } else if (status.error_code || status.sbaf_status == SBAF_STATUS_INTR ||
+ (activate.bundle_idx < stop_bundle)) {
+ ifsd->status = SCAN_NOT_TESTED;
+ sbaf_message_not_tested(dev, cpu, status.data);
+ } else {
+ ifsd->status = SCAN_TEST_PASS;
+ }
+}
+
/*
* Initiate per core test. It wakes up work queue threads on the target cpu and
* its sibling cpu. Once all sibling threads wake up, the scan test gets executed and
@@ -420,6 +647,12 @@ int do_core_test(int cpu, struct device *dev)
else
ifs_array_test_gen1(cpu, dev);
break;
+ case IFS_TYPE_SBAF:
+ if (!ifsd->loaded)
+ ret = -EPERM;
+ else
+ ifs_sbaf_test_core(cpu, dev);
+ break;
default:
ret = -EINVAL;
}
diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile
index 9f16cb514397..a8aba07bf1dc 100644
--- a/drivers/platform/x86/intel/int3472/Makefile
+++ b/drivers/platform/x86/intel/int3472/Makefile
@@ -1,4 +1,7 @@
obj-$(CONFIG_INTEL_SKL_INT3472) += intel_skl_int3472_discrete.o \
- intel_skl_int3472_tps68470.o
-intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o common.o
-intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o common.o
+ intel_skl_int3472_tps68470.o \
+ intel_skl_int3472_common.o
+intel_skl_int3472_discrete-y := discrete.o clk_and_regulator.o led.o
+intel_skl_int3472_tps68470-y := tps68470.o tps68470_board_data.o
+
+intel_skl_int3472_common-y += common.o
diff --git a/drivers/platform/x86/intel/int3472/common.c b/drivers/platform/x86/intel/int3472/common.c
index 9db2bb0bbba4..b3a2578e06c1 100644
--- a/drivers/platform/x86/intel/int3472/common.c
+++ b/drivers/platform/x86/intel/int3472/common.c
@@ -29,6 +29,7 @@ union acpi_object *skl_int3472_get_acpi_buffer(struct acpi_device *adev, char *i
return obj;
}
+EXPORT_SYMBOL_GPL(skl_int3472_get_acpi_buffer);
int skl_int3472_fill_cldb(struct acpi_device *adev, struct int3472_cldb *cldb)
{
@@ -52,6 +53,7 @@ out_free_obj:
kfree(obj);
return ret;
}
+EXPORT_SYMBOL_GPL(skl_int3472_fill_cldb);
/* sensor_adev_ret may be NULL, name_ret must not be NULL */
int skl_int3472_get_sensor_adev_and_name(struct device *dev,
@@ -80,3 +82,8 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
return ret;
}
+EXPORT_SYMBOL_GPL(skl_int3472_get_sensor_adev_and_name);
+
+MODULE_DESCRIPTION("Intel SkyLake INT3472 ACPI Device Driver library");
+MODULE_AUTHOR("Daniel Scally <djrscally@gmail.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 07b302e09340..3de463c3d13b 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -11,6 +11,7 @@
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/platform_device.h>
+#include <linux/string_choices.h>
#include <linux/uuid.h>
#include "common.h"
@@ -69,11 +70,7 @@ static int skl_int3472_fill_gpiod_lookup(struct gpiod_lookup *table_entry,
if (!adev)
return -ENODEV;
- table_entry->key = acpi_dev_name(adev);
- table_entry->chip_hwnum = agpio->pin_table[0];
- table_entry->con_id = func;
- table_entry->idx = 0;
- table_entry->flags = polarity;
+ *table_entry = GPIO_LOOKUP(acpi_dev_name(adev), agpio->pin_table[0], func, polarity);
return 0;
}
@@ -234,7 +231,7 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
dev_dbg(int3472->dev, "%s %s pin %d active-%s\n", func,
agpio->resource_source.string_ptr, agpio->pin_table[0],
- (polarity == GPIO_ACTIVE_HIGH) ? "high" : "low");
+ str_high_low(polarity == GPIO_ACTIVE_HIGH));
switch (type) {
case INT3472_GPIO_TYPE_RESET:
diff --git a/drivers/platform/x86/intel/oaktrail.c b/drivers/platform/x86/intel/oaktrail.c
index 217630f40c3f..265cef327b4f 100644
--- a/drivers/platform/x86/intel/oaktrail.c
+++ b/drivers/platform/x86/intel/oaktrail.c
@@ -28,7 +28,6 @@
#include <linux/backlight.h>
#include <linux/dmi.h>
#include <linux/err.h>
-#include <linux/fb.h>
#include <linux/i2c.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -250,7 +249,7 @@ static int oaktrail_backlight_init(void)
oaktrail_bl_device = bd;
bd->props.brightness = get_backlight_brightness(bd);
- bd->props.power = FB_BLANK_UNBLANK;
+ bd->props.power = BACKLIGHT_POWER_ON;
backlight_update_status(bd);
return 0;
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index e2b4c74ce7f6..ecb47f8b4f83 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -715,6 +715,49 @@ static int pmc_core_s0ix_blocker_show(struct seq_file *s, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(pmc_core_s0ix_blocker);
+static void pmc_core_ltr_ignore_all(struct pmc_dev *pmcdev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
+ struct pmc *pmc;
+ u32 ltr_ign;
+
+ pmc = pmcdev->pmcs[i];
+ if (!pmc)
+ continue;
+
+ guard(mutex)(&pmcdev->lock);
+ pmc->ltr_ign = pmc_core_reg_read(pmc, pmc->map->ltr_ignore_offset);
+
+ /* ltr_ignore_max is the max index value for LTR ignore register */
+ ltr_ign = pmc->ltr_ign | GENMASK(pmc->map->ltr_ignore_max, 0);
+ pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, ltr_ign);
+ }
+
+ /*
+ * Ignoring ME during suspend is blocking platforms with ADL PCH to get to
+ * deeper S0ix substate.
+ */
+ pmc_core_send_ltr_ignore(pmcdev, 6, 0);
+}
+
+static void pmc_core_ltr_restore_all(struct pmc_dev *pmcdev)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(pmcdev->pmcs); i++) {
+ struct pmc *pmc;
+
+ pmc = pmcdev->pmcs[i];
+ if (!pmc)
+ continue;
+
+ guard(mutex)(&pmcdev->lock);
+ pmc_core_reg_write(pmc, pmc->map->ltr_ignore_offset, pmc->ltr_ign);
+ }
+}
+
static inline u64 adjust_lpm_residency(struct pmc *pmc, u32 offset,
const int lpm_adj_x2)
{
@@ -729,12 +772,11 @@ static int pmc_core_substate_res_show(struct seq_file *s, void *unused)
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
const int lpm_adj_x2 = pmc->map->lpm_res_counter_step_x2;
u32 offset = pmc->map->lpm_residency_offset;
- unsigned int i;
int mode;
seq_printf(s, "%-10s %-15s\n", "Substate", "Residency");
- pmc_for_each_mode(i, mode, pmcdev) {
+ pmc_for_each_mode(mode, pmcdev) {
seq_printf(s, "%-10s %-15llu\n", pmc_lpm_modes[mode],
adjust_lpm_residency(pmc, offset + (4 * mode), lpm_adj_x2));
}
@@ -788,20 +830,21 @@ DEFINE_SHOW_ATTRIBUTE(pmc_core_substate_l_sts_regs);
static void pmc_core_substate_req_header_show(struct seq_file *s, int pmc_index)
{
struct pmc_dev *pmcdev = s->private;
- unsigned int i;
int mode;
seq_printf(s, "%30s |", "Element");
- pmc_for_each_mode(i, mode, pmcdev)
+ pmc_for_each_mode(mode, pmcdev)
seq_printf(s, " %9s |", pmc_lpm_modes[mode]);
- seq_printf(s, " %9s |\n", "Status");
+ seq_printf(s, " %9s |", "Status");
+ seq_printf(s, " %11s |\n", "Live Status");
}
static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
u32 sts_offset;
+ u32 sts_offset_live;
u32 *lpm_req_regs;
unsigned int mp, pmc_index;
int num_maps;
@@ -816,6 +859,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
maps = pmc->map->lpm_sts;
num_maps = pmc->map->lpm_num_maps;
sts_offset = pmc->map->lpm_status_offset;
+ sts_offset_live = pmc->map->lpm_live_status_offset;
lpm_req_regs = pmc->lpm_req_regs;
/*
@@ -833,20 +877,24 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
for (mp = 0; mp < num_maps; mp++) {
u32 req_mask = 0;
u32 lpm_status;
+ u32 lpm_status_live;
const struct pmc_bit_map *map;
- int mode, idx, i, len = 32;
+ int mode, i, len = 32;
/*
* Capture the requirements and create a mask so that we only
* show an element if it's required for at least one of the
* enabled low power modes
*/
- pmc_for_each_mode(idx, mode, pmcdev)
+ pmc_for_each_mode(mode, pmcdev)
req_mask |= lpm_req_regs[mp + (mode * num_maps)];
/* Get the last latched status for this map */
lpm_status = pmc_core_reg_read(pmc, sts_offset + (mp * 4));
+ /* Get the runtime status for this map */
+ lpm_status_live = pmc_core_reg_read(pmc, sts_offset_live + (mp * 4));
+
/* Loop over elements in this map */
map = maps[mp];
for (i = 0; map[i].name && i < len; i++) {
@@ -864,7 +912,7 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
seq_printf(s, "pmc%d: %26s |", pmc_index, map[i].name);
/* Loop over the enabled states and display if required */
- pmc_for_each_mode(idx, mode, pmcdev) {
+ pmc_for_each_mode(mode, pmcdev) {
bool required = lpm_req_regs[mp + (mode * num_maps)] &
bit_mask;
seq_printf(s, " %9s |", required ? "Required" : " ");
@@ -873,6 +921,9 @@ static int pmc_core_substate_req_regs_show(struct seq_file *s, void *unused)
/* In Status column, show the last captured state of this agent */
seq_printf(s, " %9s |", lpm_status & bit_mask ? "Yes" : " ");
+ /* In Live status column, show the live state of this agent */
+ seq_printf(s, " %11s |", lpm_status_live & bit_mask ? "Yes" : " ");
+
seq_puts(s, "\n");
}
}
@@ -926,7 +977,6 @@ static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
{
struct pmc_dev *pmcdev = s->private;
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
- unsigned int idx;
bool c10;
u32 reg;
int mode;
@@ -940,7 +990,7 @@ static int pmc_core_lpm_latch_mode_show(struct seq_file *s, void *unused)
c10 = true;
}
- pmc_for_each_mode(idx, mode, pmcdev) {
+ pmc_for_each_mode(mode, pmcdev) {
if ((BIT(mode) & reg) && !c10)
seq_printf(s, " [%s]", pmc_lpm_modes[mode]);
else
@@ -961,7 +1011,6 @@ static ssize_t pmc_core_lpm_latch_mode_write(struct file *file,
struct pmc *pmc = pmcdev->pmcs[PMC_IDX_MAIN];
bool clear = false, c10 = false;
unsigned char buf[8];
- unsigned int idx;
int m, mode;
u32 reg;
@@ -980,7 +1029,7 @@ static ssize_t pmc_core_lpm_latch_mode_write(struct file *file,
mode = sysfs_match_string(pmc_lpm_modes, buf);
/* Check string matches enabled mode */
- pmc_for_each_mode(idx, m, pmcdev)
+ pmc_for_each_mode(m, pmcdev)
if (mode == m)
break;
@@ -1524,6 +1573,10 @@ static bool warn_on_s0ix_failures;
module_param(warn_on_s0ix_failures, bool, 0644);
MODULE_PARM_DESC(warn_on_s0ix_failures, "Check and warn for S0ix failures");
+static bool ltr_ignore_all_suspend = true;
+module_param(ltr_ignore_all_suspend, bool, 0644);
+MODULE_PARM_DESC(ltr_ignore_all_suspend, "Ignore all LTRs during suspend");
+
static __maybe_unused int pmc_core_suspend(struct device *dev)
{
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
@@ -1533,6 +1586,9 @@ static __maybe_unused int pmc_core_suspend(struct device *dev)
if (pmcdev->suspend)
pmcdev->suspend(pmcdev);
+ if (ltr_ignore_all_suspend)
+ pmc_core_ltr_ignore_all(pmcdev);
+
/* Check if the syspend will actually use S0ix */
if (pm_suspend_via_firmware())
return 0;
@@ -1639,6 +1695,9 @@ static __maybe_unused int pmc_core_resume(struct device *dev)
{
struct pmc_dev *pmcdev = dev_get_drvdata(dev);
+ if (ltr_ignore_all_suspend)
+ pmc_core_ltr_restore_all(pmcdev);
+
if (pmcdev->resume)
return pmcdev->resume(pmcdev);
diff --git a/drivers/platform/x86/intel/pmc/core.h b/drivers/platform/x86/intel/pmc/core.h
index 4d37ef7113d7..75fd593a7b0f 100644
--- a/drivers/platform/x86/intel/pmc/core.h
+++ b/drivers/platform/x86/intel/pmc/core.h
@@ -378,6 +378,7 @@ struct pmc_info {
* @map: pointer to pmc_reg_map struct that contains platform
* specific attributes
* @lpm_req_regs: List of substate requirements
+ * @ltr_ign: Holds LTR ignore data while suspended
*
* pmc contains info about one power management controller device.
*/
@@ -386,6 +387,7 @@ struct pmc {
void __iomem *regbase;
const struct pmc_reg_map *map;
u32 *lpm_req_regs;
+ u32 ltr_ign;
};
/**
@@ -612,10 +614,12 @@ int lnl_core_init(struct pmc_dev *pmcdev);
void cnl_suspend(struct pmc_dev *pmcdev);
int cnl_resume(struct pmc_dev *pmcdev);
-#define pmc_for_each_mode(i, mode, pmcdev) \
- for (i = 0, mode = pmcdev->lpm_en_modes[i]; \
- i < pmcdev->num_lpm_modes; \
- i++, mode = pmcdev->lpm_en_modes[i])
+#define pmc_for_each_mode(mode, pmcdev) \
+ for (unsigned int __i = 0, __cond; \
+ __cond = __i < (pmcdev)->num_lpm_modes, \
+ __cond && ((mode) = (pmcdev)->lpm_en_modes[__i]), \
+ __cond; \
+ __i++)
#define DEFINE_PMC_CORE_ATTR_WRITE(__name) \
static int __name ## _open(struct inode *inode, struct file *file) \
diff --git a/drivers/platform/x86/intel/pmc/core_ssram.c b/drivers/platform/x86/intel/pmc/core_ssram.c
index 1bde86c54eb9..c259c96b7dfd 100644
--- a/drivers/platform/x86/intel/pmc/core_ssram.c
+++ b/drivers/platform/x86/intel/pmc/core_ssram.c
@@ -9,11 +9,11 @@
*/
#include <linux/cleanup.h>
+#include <linux/intel_vsec.h>
#include <linux/pci.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include "core.h"
-#include "../vsec.h"
#include "../pmt/telemetry.h"
#define SSRAM_HDR_SIZE 0x100
@@ -45,7 +45,7 @@ static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc)
struct telem_endpoint *ep;
const u8 *lpm_indices;
int num_maps, mode_offset = 0;
- int ret, mode, i;
+ int ret, mode;
int lpm_size;
u32 guid;
@@ -116,7 +116,7 @@ static int pmc_core_get_lpm_req(struct pmc_dev *pmcdev, struct pmc *pmc)
*
*/
mode_offset = LPM_HEADER_OFFSET + LPM_MODE_OFFSET;
- pmc_for_each_mode(i, mode, pmcdev) {
+ pmc_for_each_mode(mode, pmcdev) {
u32 *req_offset = pmc->lpm_req_regs + (mode * num_maps);
int m;
diff --git a/drivers/platform/x86/intel/pmt/class.c b/drivers/platform/x86/intel/pmt/class.c
index 4b53940a64e2..c04bb7f97a4d 100644
--- a/drivers/platform/x86/intel/pmt/class.c
+++ b/drivers/platform/x86/intel/pmt/class.c
@@ -9,12 +9,12 @@
*/
#include <linux/kernel.h>
+#include <linux/intel_vsec.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/module.h>
#include <linux/mm.h>
#include <linux/pci.h>
-#include "../vsec.h"
#include "class.h"
#define PMT_XA_START 1
@@ -58,6 +58,22 @@ pmt_memcpy64_fromio(void *to, const u64 __iomem *from, size_t count)
return count;
}
+int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf,
+ void __iomem *addr, u32 count)
+{
+ if (cb && cb->read_telem)
+ return cb->read_telem(pdev, guid, buf, count);
+
+ if (guid == GUID_SPR_PUNIT)
+ /* PUNIT on SPR only supports aligned 64-bit read */
+ return pmt_memcpy64_fromio(buf, addr, count);
+
+ memcpy_fromio(buf, addr, count);
+
+ return count;
+}
+EXPORT_SYMBOL_NS_GPL(pmt_telem_read_mmio, INTEL_PMT);
+
/*
* sysfs
*/
@@ -79,11 +95,8 @@ intel_pmt_read(struct file *filp, struct kobject *kobj,
if (count > entry->size - off)
count = entry->size - off;
- if (entry->guid == GUID_SPR_PUNIT)
- /* PUNIT on SPR only supports aligned 64-bit read */
- count = pmt_memcpy64_fromio(buf, entry->base + off, count);
- else
- memcpy_fromio(buf, entry->base + off, count);
+ count = pmt_telem_read_mmio(entry->ep->pcidev, entry->cb, entry->header.guid, buf,
+ entry->base + off, count);
return count;
}
@@ -239,6 +252,7 @@ static int intel_pmt_populate_entry(struct intel_pmt_entry *entry,
entry->guid = header->guid;
entry->size = header->size;
+ entry->cb = ivdev->priv_data;
return 0;
}
@@ -300,7 +314,7 @@ static int intel_pmt_dev_register(struct intel_pmt_entry *entry,
goto fail_ioremap;
if (ns->pmt_add_endpoint) {
- ret = ns->pmt_add_endpoint(entry, ivdev->pcidev);
+ ret = ns->pmt_add_endpoint(ivdev, entry);
if (ret)
goto fail_add_endpoint;
}
diff --git a/drivers/platform/x86/intel/pmt/class.h b/drivers/platform/x86/intel/pmt/class.h
index d23c63b73ab7..a267ac964423 100644
--- a/drivers/platform/x86/intel/pmt/class.h
+++ b/drivers/platform/x86/intel/pmt/class.h
@@ -2,13 +2,13 @@
#ifndef _INTEL_PMT_CLASS_H
#define _INTEL_PMT_CLASS_H
+#include <linux/intel_vsec.h>
#include <linux/xarray.h>
#include <linux/types.h>
#include <linux/bits.h>
#include <linux/err.h>
#include <linux/io.h>
-#include "../vsec.h"
#include "telemetry.h"
/* PMT access types */
@@ -24,6 +24,7 @@ struct pci_dev;
struct telem_endpoint {
struct pci_dev *pcidev;
struct telem_header header;
+ struct pmt_callbacks *cb;
void __iomem *base;
bool present;
struct kref kref;
@@ -43,6 +44,7 @@ struct intel_pmt_entry {
struct kobject *kobj;
void __iomem *disc_table;
void __iomem *base;
+ struct pmt_callbacks *cb;
unsigned long base_addr;
size_t size;
u32 guid;
@@ -55,10 +57,12 @@ struct intel_pmt_namespace {
const struct attribute_group *attr_grp;
int (*pmt_header_decode)(struct intel_pmt_entry *entry,
struct device *dev);
- int (*pmt_add_endpoint)(struct intel_pmt_entry *entry,
- struct pci_dev *pdev);
+ int (*pmt_add_endpoint)(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry);
};
+int pmt_telem_read_mmio(struct pci_dev *pdev, struct pmt_callbacks *cb, u32 guid, void *buf,
+ void __iomem *addr, u32 count);
bool intel_pmt_is_early_client_hw(struct device *dev);
int intel_pmt_dev_create(struct intel_pmt_entry *entry,
struct intel_pmt_namespace *ns,
diff --git a/drivers/platform/x86/intel/pmt/crashlog.c b/drivers/platform/x86/intel/pmt/crashlog.c
index 4014c02cafdb..9079d5dffc03 100644
--- a/drivers/platform/x86/intel/pmt/crashlog.c
+++ b/drivers/platform/x86/intel/pmt/crashlog.c
@@ -9,6 +9,7 @@
*/
#include <linux/auxiliary_bus.h>
+#include <linux/intel_vsec.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -16,7 +17,6 @@
#include <linux/uaccess.h>
#include <linux/overflow.h>
-#include "../vsec.h"
#include "class.h"
/* Crashlog discovery header types */
diff --git a/drivers/platform/x86/intel/pmt/telemetry.c b/drivers/platform/x86/intel/pmt/telemetry.c
index 09258564dfc4..c9feac859e57 100644
--- a/drivers/platform/x86/intel/pmt/telemetry.c
+++ b/drivers/platform/x86/intel/pmt/telemetry.c
@@ -9,6 +9,7 @@
*/
#include <linux/auxiliary_bus.h>
+#include <linux/intel_vsec.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
@@ -16,7 +17,6 @@
#include <linux/uaccess.h>
#include <linux/overflow.h>
-#include "../vsec.h"
#include "class.h"
#define TELEM_SIZE_OFFSET 0x0
@@ -93,8 +93,8 @@ static int pmt_telem_header_decode(struct intel_pmt_entry *entry,
return 0;
}
-static int pmt_telem_add_endpoint(struct intel_pmt_entry *entry,
- struct pci_dev *pdev)
+static int pmt_telem_add_endpoint(struct intel_vsec_device *ivdev,
+ struct intel_pmt_entry *entry)
{
struct telem_endpoint *ep;
@@ -104,13 +104,14 @@ static int pmt_telem_add_endpoint(struct intel_pmt_entry *entry,
return -ENOMEM;
ep = entry->ep;
- ep->pcidev = pdev;
+ ep->pcidev = ivdev->pcidev;
ep->header.access_type = entry->header.access_type;
ep->header.guid = entry->header.guid;
ep->header.base_offset = entry->header.base_offset;
ep->header.size = entry->header.size;
ep->base = entry->base;
ep->present = true;
+ ep->cb = ivdev->priv_data;
kref_init(&ep->kref);
@@ -218,7 +219,8 @@ int pmt_telem_read(struct telem_endpoint *ep, u32 id, u64 *data, u32 count)
if (offset + NUM_BYTES_QWORD(count) > size)
return -EINVAL;
- memcpy_fromio(data, ep->base + offset, NUM_BYTES_QWORD(count));
+ pmt_telem_read_mmio(ep->pcidev, ep->cb, ep->header.guid, data, ep->base + offset,
+ NUM_BYTES_QWORD(count));
return ep->present ? 0 : -EPIPE;
}
diff --git a/drivers/platform/x86/intel/sdsi.c b/drivers/platform/x86/intel/sdsi.c
index 277e4f4b20ac..9d137621f0e6 100644
--- a/drivers/platform/x86/intel/sdsi.c
+++ b/drivers/platform/x86/intel/sdsi.c
@@ -12,6 +12,7 @@
#include <linux/bits.h>
#include <linux/bitfield.h>
#include <linux/device.h>
+#include <linux/intel_vsec.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -22,8 +23,6 @@
#include <linux/types.h>
#include <linux/uaccess.h>
-#include "vsec.h"
-
#define ACCESS_TYPE_BARID 2
#define ACCESS_TYPE_LOCAL 3
diff --git a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
index 10e21563fa46..9ad35fefea47 100644
--- a/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
+++ b/drivers/platform/x86/intel/speed_select_if/isst_if_common.c
@@ -651,10 +651,6 @@ static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
/* Lock to prevent module registration when already opened by user space */
static DEFINE_MUTEX(punit_misc_dev_open_lock);
-/* Lock to allow one shared misc device for all ISST interfaces */
-static DEFINE_MUTEX(punit_misc_dev_reg_lock);
-static int misc_usage_count;
-static int misc_device_ret;
static int misc_device_open;
static int isst_if_open(struct inode *inode, struct file *file)
@@ -720,39 +716,23 @@ static struct miscdevice isst_if_char_driver = {
static int isst_misc_reg(void)
{
- mutex_lock(&punit_misc_dev_reg_lock);
- if (misc_device_ret)
- goto unlock_exit;
-
- if (!misc_usage_count) {
- misc_device_ret = isst_if_cpu_info_init();
- if (misc_device_ret)
- goto unlock_exit;
-
- misc_device_ret = misc_register(&isst_if_char_driver);
- if (misc_device_ret) {
- isst_if_cpu_info_exit();
- goto unlock_exit;
- }
- }
- misc_usage_count++;
+ int ret;
-unlock_exit:
- mutex_unlock(&punit_misc_dev_reg_lock);
+ ret = isst_if_cpu_info_init();
+ if (ret)
+ return ret;
- return misc_device_ret;
+ ret = misc_register(&isst_if_char_driver);
+ if (ret)
+ isst_if_cpu_info_exit();
+
+ return ret;
}
static void isst_misc_unreg(void)
{
- mutex_lock(&punit_misc_dev_reg_lock);
- if (misc_usage_count)
- misc_usage_count--;
- if (!misc_usage_count && !misc_device_ret) {
- misc_deregister(&isst_if_char_driver);
- isst_if_cpu_info_exit();
- }
- mutex_unlock(&punit_misc_dev_reg_lock);
+ misc_deregister(&isst_if_char_driver);
+ isst_if_cpu_info_exit();
}
/**
diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c
index 83e8b1fe53b3..486ddc9b3592 100644
--- a/drivers/platform/x86/intel/tpmi.c
+++ b/drivers/platform/x86/intel/tpmi.c
@@ -51,6 +51,7 @@
#include <linux/debugfs.h>
#include <linux/delay.h>
#include <linux/intel_tpmi.h>
+#include <linux/intel_vsec.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/module.h>
@@ -59,8 +60,6 @@
#include <linux/sizes.h>
#include <linux/string_helpers.h>
-#include "vsec.h"
-
/**
* struct intel_tpmi_pfs_entry - TPMI PM Feature Structure (PFS) entry
* @tpmi_id: TPMI feature identifier (what the feature is and its data format).
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
index 4e880585cbe4..e22b683a7a43 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.c
@@ -60,11 +60,16 @@ static ssize_t show_attr(struct uncore_data *data, char *buf, enum uncore_index
static ssize_t store_attr(struct uncore_data *data, const char *buf, ssize_t count,
enum uncore_index index)
{
- unsigned int input;
+ unsigned int input = 0;
int ret;
- if (kstrtouint(buf, 10, &input))
- return -EINVAL;
+ if (index == UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE) {
+ if (kstrtobool(buf, (bool *)&input))
+ return -EINVAL;
+ } else {
+ if (kstrtouint(buf, 10, &input))
+ return -EINVAL;
+ }
mutex_lock(&uncore_lock);
ret = uncore_write(data, input, index);
@@ -103,6 +108,18 @@ show_uncore_attr(max_freq_khz, UNCORE_INDEX_MAX_FREQ);
show_uncore_attr(current_freq_khz, UNCORE_INDEX_CURRENT_FREQ);
+store_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
+store_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
+store_uncore_attr(elc_high_threshold_enable,
+ UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
+store_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
+
+show_uncore_attr(elc_low_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
+show_uncore_attr(elc_high_threshold_percent, UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD);
+show_uncore_attr(elc_high_threshold_enable,
+ UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE);
+show_uncore_attr(elc_floor_freq_khz, UNCORE_INDEX_EFF_LAT_CTRL_FREQ);
+
#define show_uncore_data(member_name) \
static ssize_t show_##member_name(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf)\
@@ -146,7 +163,8 @@ show_uncore_data(initial_max_freq_khz);
static int create_attr_group(struct uncore_data *data, char *name)
{
- int ret, freq, index = 0;
+ int ret, index = 0;
+ unsigned int val;
init_attribute_rw(max_freq_khz);
init_attribute_rw(min_freq_khz);
@@ -168,10 +186,24 @@ static int create_attr_group(struct uncore_data *data, char *name)
data->uncore_attrs[index++] = &data->initial_min_freq_khz_kobj_attr.attr;
data->uncore_attrs[index++] = &data->initial_max_freq_khz_kobj_attr.attr;
- ret = uncore_read(data, &freq, UNCORE_INDEX_CURRENT_FREQ);
+ ret = uncore_read(data, &val, UNCORE_INDEX_CURRENT_FREQ);
if (!ret)
data->uncore_attrs[index++] = &data->current_freq_khz_kobj_attr.attr;
+ ret = uncore_read(data, &val, UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD);
+ if (!ret) {
+ init_attribute_rw(elc_low_threshold_percent);
+ init_attribute_rw(elc_high_threshold_percent);
+ init_attribute_rw(elc_high_threshold_enable);
+ init_attribute_rw(elc_floor_freq_khz);
+
+ data->uncore_attrs[index++] = &data->elc_low_threshold_percent_kobj_attr.attr;
+ data->uncore_attrs[index++] = &data->elc_high_threshold_percent_kobj_attr.attr;
+ data->uncore_attrs[index++] =
+ &data->elc_high_threshold_enable_kobj_attr.attr;
+ data->uncore_attrs[index++] = &data->elc_floor_freq_khz_kobj_attr.attr;
+ }
+
data->uncore_attrs[index] = NULL;
data->uncore_attr_group.name = name;
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
index 4c245b945e4e..26c854cd5d97 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-common.h
@@ -34,6 +34,13 @@
* @domain_id_kobj_attr: Storage for kobject attribute domain_id
* @fabric_cluster_id_kobj_attr: Storage for kobject attribute fabric_cluster_id
* @package_id_kobj_attr: Storage for kobject attribute package_id
+ * @elc_low_threshold_percent_kobj_attr:
+ Storage for kobject attribute elc_low_threshold_percent
+ * @elc_high_threshold_percent_kobj_attr:
+ Storage for kobject attribute elc_high_threshold_percent
+ * @elc_high_threshold_enable_kobj_attr:
+ Storage for kobject attribute elc_high_threshold_enable
+ * @elc_floor_freq_khz_kobj_attr: Storage for kobject attribute elc_floor_freq_khz
* @uncore_attrs: Attribute storage for group creation
*
* This structure is used to encapsulate all data related to uncore sysfs
@@ -61,7 +68,11 @@ struct uncore_data {
struct kobj_attribute domain_id_kobj_attr;
struct kobj_attribute fabric_cluster_id_kobj_attr;
struct kobj_attribute package_id_kobj_attr;
- struct attribute *uncore_attrs[9];
+ struct kobj_attribute elc_low_threshold_percent_kobj_attr;
+ struct kobj_attribute elc_high_threshold_percent_kobj_attr;
+ struct kobj_attribute elc_high_threshold_enable_kobj_attr;
+ struct kobj_attribute elc_floor_freq_khz_kobj_attr;
+ struct attribute *uncore_attrs[13];
};
#define UNCORE_DOMAIN_ID_INVALID -1
@@ -70,6 +81,10 @@ enum uncore_index {
UNCORE_INDEX_MIN_FREQ,
UNCORE_INDEX_MAX_FREQ,
UNCORE_INDEX_CURRENT_FREQ,
+ UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD,
+ UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD,
+ UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE,
+ UNCORE_INDEX_EFF_LAT_CTRL_FREQ,
};
int uncore_freq_common_init(int (*read)(struct uncore_data *data, unsigned int *value,
diff --git a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
index 9fa3037c03d1..0591053813a2 100644
--- a/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
+++ b/drivers/platform/x86/intel/uncore-frequency/uncore-frequency-tpmi.c
@@ -30,6 +30,7 @@
#define UNCORE_MAJOR_VERSION 0
#define UNCORE_MINOR_VERSION 2
+#define UNCORE_ELC_SUPPORTED_VERSION 2
#define UNCORE_HEADER_INDEX 0
#define UNCORE_FABRIC_CLUSTER_OFFSET 8
@@ -46,6 +47,7 @@ struct tpmi_uncore_struct;
/* Information for each cluster */
struct tpmi_uncore_cluster_info {
bool root_domain;
+ bool elc_supported;
u8 __iomem *cluster_base;
struct uncore_data uncore_data;
struct tpmi_uncore_struct *uncore_root;
@@ -75,6 +77,10 @@ struct tpmi_uncore_struct {
/* Bit definitions for CONTROL register */
#define UNCORE_MAX_RATIO_MASK GENMASK_ULL(14, 8)
#define UNCORE_MIN_RATIO_MASK GENMASK_ULL(21, 15)
+#define UNCORE_EFF_LAT_CTRL_RATIO_MASK GENMASK_ULL(28, 22)
+#define UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK GENMASK_ULL(38, 32)
+#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE BIT(39)
+#define UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK GENMASK_ULL(46, 40)
/* Helper function to read MMIO offset for max/min control frequency */
static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info,
@@ -89,6 +95,48 @@ static void read_control_freq(struct tpmi_uncore_cluster_info *cluster_info,
*value = FIELD_GET(UNCORE_MIN_RATIO_MASK, control) * UNCORE_FREQ_KHZ_MULTIPLIER;
}
+/* Helper function to read efficiency latency control values over MMIO */
+static int read_eff_lat_ctrl(struct uncore_data *data, unsigned int *val, enum uncore_index index)
+{
+ struct tpmi_uncore_cluster_info *cluster_info;
+ u64 ctrl;
+
+ cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);
+ if (cluster_info->root_domain)
+ return -ENODATA;
+
+ if (!cluster_info->elc_supported)
+ return -EOPNOTSUPP;
+
+ ctrl = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
+
+ switch (index) {
+ case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
+ *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, ctrl);
+ *val *= 100;
+ *val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK));
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
+ *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, ctrl);
+ *val *= 100;
+ *val = DIV_ROUND_UP(*val, FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK));
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
+ *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, ctrl);
+ break;
+ case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
+ *val = FIELD_GET(UNCORE_EFF_LAT_CTRL_RATIO_MASK, ctrl) * UNCORE_FREQ_KHZ_MULTIPLIER;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
#define UNCORE_MAX_RATIO FIELD_MAX(UNCORE_MAX_RATIO_MASK)
/* Helper for sysfs read for max/min frequencies. Called under mutex locks */
@@ -137,6 +185,82 @@ static int uncore_read_control_freq(struct uncore_data *data, unsigned int *valu
return 0;
}
+/* Helper function for writing efficiency latency control values over MMIO */
+static int write_eff_lat_ctrl(struct uncore_data *data, unsigned int val, enum uncore_index index)
+{
+ struct tpmi_uncore_cluster_info *cluster_info;
+ u64 control;
+
+ cluster_info = container_of(data, struct tpmi_uncore_cluster_info, uncore_data);
+
+ if (cluster_info->root_domain)
+ return -ENODATA;
+
+ if (!cluster_info->elc_supported)
+ return -EOPNOTSUPP;
+
+ switch (index) {
+ case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
+ if (val > 100)
+ return -EINVAL;
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
+ if (val > 100)
+ return -EINVAL;
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
+ if (val > 1)
+ return -EINVAL;
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
+ val /= UNCORE_FREQ_KHZ_MULTIPLIER;
+ if (val > FIELD_MAX(UNCORE_EFF_LAT_CTRL_RATIO_MASK))
+ return -EINVAL;
+ break;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ control = readq(cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
+
+ switch (index) {
+ case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
+ val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK);
+ val /= 100;
+ control &= ~UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK;
+ control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_LOW_THRESHOLD_MASK, val);
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
+ val *= FIELD_MAX(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK);
+ val /= 100;
+ control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK;
+ control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_MASK, val);
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
+ control &= ~UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE;
+ control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE, val);
+ break;
+
+ case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
+ control &= ~UNCORE_EFF_LAT_CTRL_RATIO_MASK;
+ control |= FIELD_PREP(UNCORE_EFF_LAT_CTRL_RATIO_MASK, val);
+ break;
+
+ default:
+ break;
+ }
+
+ writeq(control, cluster_info->cluster_base + UNCORE_CONTROL_INDEX);
+
+ return 0;
+}
+
/* Helper function to write MMIO offset for max/min control frequency */
static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, unsigned int input,
unsigned int index)
@@ -156,7 +280,7 @@ static void write_control_freq(struct tpmi_uncore_cluster_info *cluster_info, un
writeq(control, (cluster_info->cluster_base + UNCORE_CONTROL_INDEX));
}
-/* Callback for sysfs write for max/min frequencies. Called under mutex locks */
+/* Helper for sysfs write for max/min frequencies. Called under mutex locks */
static int uncore_write_control_freq(struct uncore_data *data, unsigned int input,
enum uncore_index index)
{
@@ -234,6 +358,33 @@ static int uncore_read(struct uncore_data *data, unsigned int *value, enum uncor
case UNCORE_INDEX_CURRENT_FREQ:
return uncore_read_freq(data, value);
+ case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
+ case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
+ return read_eff_lat_ctrl(data, value, index);
+
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+/* Callback for sysfs write for TPMI uncore data. Called under mutex locks. */
+static int uncore_write(struct uncore_data *data, unsigned int value, enum uncore_index index)
+{
+ switch (index) {
+ case UNCORE_INDEX_EFF_LAT_CTRL_LOW_THRESHOLD:
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD:
+ case UNCORE_INDEX_EFF_LAT_CTRL_HIGH_THRESHOLD_ENABLE:
+ case UNCORE_INDEX_EFF_LAT_CTRL_FREQ:
+ return write_eff_lat_ctrl(data, value, index);
+
+ case UNCORE_INDEX_MIN_FREQ:
+ case UNCORE_INDEX_MAX_FREQ:
+ return uncore_write_control_freq(data, value, index);
+
default:
break;
}
@@ -291,7 +442,7 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
return -EINVAL;
/* Register callbacks to uncore core */
- ret = uncore_freq_common_init(uncore_read, uncore_write_control_freq);
+ ret = uncore_freq_common_init(uncore_read, uncore_write);
if (ret)
return ret;
@@ -409,6 +560,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
cluster_info->uncore_root = tpmi_uncore;
+ if (TPMI_MINOR_VERSION(pd_info->ufs_header_ver) >= UNCORE_ELC_SUPPORTED_VERSION)
+ cluster_info->elc_supported = true;
+
ret = uncore_freq_add_entry(&cluster_info->uncore_data, 0);
if (ret) {
cluster_info->cluster_base = NULL;
@@ -427,6 +581,9 @@ static int uncore_probe(struct auxiliary_device *auxdev, const struct auxiliary_
auxiliary_set_drvdata(auxdev, tpmi_uncore);
+ if (topology_max_dies_per_package() > 1)
+ return 0;
+
tpmi_uncore->root_cluster.root_domain = true;
tpmi_uncore->root_cluster.uncore_root = tpmi_uncore;
@@ -450,7 +607,9 @@ static void uncore_remove(struct auxiliary_device *auxdev)
{
struct tpmi_uncore_struct *tpmi_uncore = auxiliary_get_drvdata(auxdev);
- uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);
+ if (tpmi_uncore->root_cluster.root_domain)
+ uncore_freq_remove_die_entry(&tpmi_uncore->root_cluster.uncore_data);
+
remove_cluster_entries(tpmi_uncore);
uncore_freq_common_exit();
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index 0fdfaf3a4f5c..7b5cc9993974 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -17,14 +17,13 @@
#include <linux/bits.h>
#include <linux/cleanup.h>
#include <linux/delay.h>
-#include <linux/kernel.h>
#include <linux/idr.h>
+#include <linux/intel_vsec.h>
+#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/types.h>
-#include "vsec.h"
-
#define PMT_XA_START 0
#define PMT_XA_MAX INT_MAX
#define PMT_XA_LIMIT XA_LIMIT(PMT_XA_START, PMT_XA_MAX)
@@ -213,6 +212,7 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
intel_vsec_dev->num_resources = header->num_entries;
intel_vsec_dev->quirks = info->quirks;
intel_vsec_dev->base_addr = info->base_addr;
+ intel_vsec_dev->priv_data = info->priv_data;
if (header->id == VSEC_ID_SDSI)
intel_vsec_dev->ida = &intel_vsec_sdsi_ida;
@@ -341,7 +341,7 @@ static bool intel_vsec_walk_vsec(struct pci_dev *pdev,
void intel_vsec_register(struct pci_dev *pdev,
struct intel_vsec_platform_info *info)
{
- if (!pdev || !info)
+ if (!pdev || !info || !info->headers)
return;
intel_vsec_walk_header(pdev, info);
diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h
deleted file mode 100644
index e23e76129691..000000000000
--- a/drivers/platform/x86/intel/vsec.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _VSEC_H
-#define _VSEC_H
-
-#include <linux/auxiliary_bus.h>
-#include <linux/bits.h>
-
-#define VSEC_CAP_TELEMETRY BIT(0)
-#define VSEC_CAP_WATCHER BIT(1)
-#define VSEC_CAP_CRASHLOG BIT(2)
-#define VSEC_CAP_SDSI BIT(3)
-#define VSEC_CAP_TPMI BIT(4)
-
-/* Intel DVSEC offsets */
-#define INTEL_DVSEC_ENTRIES 0xA
-#define INTEL_DVSEC_SIZE 0xB
-#define INTEL_DVSEC_TABLE 0xC
-#define INTEL_DVSEC_TABLE_BAR(x) ((x) & GENMASK(2, 0))
-#define INTEL_DVSEC_TABLE_OFFSET(x) ((x) & GENMASK(31, 3))
-#define TABLE_OFFSET_SHIFT 3
-
-struct pci_dev;
-struct resource;
-
-enum intel_vsec_id {
- VSEC_ID_TELEMETRY = 2,
- VSEC_ID_WATCHER = 3,
- VSEC_ID_CRASHLOG = 4,
- VSEC_ID_SDSI = 65,
- VSEC_ID_TPMI = 66,
-};
-
-/**
- * struct intel_vsec_header - Common fields of Intel VSEC and DVSEC registers.
- * @rev: Revision ID of the VSEC/DVSEC register space
- * @length: Length of the VSEC/DVSEC register space
- * @id: ID of the feature
- * @num_entries: Number of instances of the feature
- * @entry_size: Size of the discovery table for each feature
- * @tbir: BAR containing the discovery tables
- * @offset: BAR offset of start of the first discovery table
- */
-struct intel_vsec_header {
- u8 rev;
- u16 length;
- u16 id;
- u8 num_entries;
- u8 entry_size;
- u8 tbir;
- u32 offset;
-};
-
-enum intel_vsec_quirks {
- /* Watcher feature not supported */
- VSEC_QUIRK_NO_WATCHER = BIT(0),
-
- /* Crashlog feature not supported */
- VSEC_QUIRK_NO_CRASHLOG = BIT(1),
-
- /* Use shift instead of mask to read discovery table offset */
- VSEC_QUIRK_TABLE_SHIFT = BIT(2),
-
- /* DVSEC not present (provided in driver data) */
- VSEC_QUIRK_NO_DVSEC = BIT(3),
-
- /* Platforms requiring quirk in the auxiliary driver */
- VSEC_QUIRK_EARLY_HW = BIT(4),
-};
-
-/* Platform specific data */
-struct intel_vsec_platform_info {
- struct device *parent;
- struct intel_vsec_header **headers;
- unsigned long caps;
- unsigned long quirks;
- u64 base_addr;
-};
-
-struct intel_vsec_device {
- struct auxiliary_device auxdev;
- struct pci_dev *pcidev;
- struct resource *resource;
- struct ida *ida;
- int num_resources;
- int id; /* xa */
- void *priv_data;
- size_t priv_data_size;
- unsigned long quirks;
- u64 base_addr;
-};
-
-int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
- struct intel_vsec_device *intel_vsec_dev,
- const char *name);
-
-static inline struct intel_vsec_device *dev_to_ivdev(struct device *dev)
-{
- return container_of(dev, struct intel_vsec_device, auxdev.dev);
-}
-
-static inline struct intel_vsec_device *auxdev_to_ivdev(struct auxiliary_device *auxdev)
-{
- return container_of(auxdev, struct intel_vsec_device, auxdev);
-}
-
-void intel_vsec_register(struct pci_dev *pdev,
- struct intel_vsec_platform_info *info);
-#endif
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index a68df4133403..5b16d29c93d7 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -23,7 +23,7 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <asm/intel_scu_ipc.h>
+#include <linux/platform_data/x86/intel_scu_ipc.h>
/* IPC defines the following message types */
#define IPCMSG_PCNTRL 0xff /* Power controller unit read/write */
diff --git a/drivers/platform/x86/intel_scu_ipcutil.c b/drivers/platform/x86/intel_scu_ipcutil.c
index 7d87cbd4b9c6..69b36ce41fa2 100644
--- a/drivers/platform/x86/intel_scu_ipcutil.c
+++ b/drivers/platform/x86/intel_scu_ipcutil.c
@@ -18,7 +18,7 @@
#include <linux/types.h>
#include <linux/uaccess.h>
-#include <asm/intel_scu_ipc.h>
+#include <linux/platform_data/x86/intel_scu_ipc.h>
static int major;
diff --git a/drivers/platform/x86/intel_scu_pcidrv.c b/drivers/platform/x86/intel_scu_pcidrv.c
index dbf0310448da..d7f72d6deb44 100644
--- a/drivers/platform/x86/intel_scu_pcidrv.c
+++ b/drivers/platform/x86/intel_scu_pcidrv.c
@@ -11,7 +11,7 @@
#include <linux/init.h>
#include <linux/pci.h>
-#include <asm/intel_scu_ipc.h>
+#include <linux/platform_data/x86/intel_scu_ipc.h>
static int intel_scu_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
diff --git a/drivers/platform/x86/intel_scu_pltdrv.c b/drivers/platform/x86/intel_scu_pltdrv.c
index 56ec6ae4c824..0892362acd7b 100644
--- a/drivers/platform/x86/intel_scu_pltdrv.c
+++ b/drivers/platform/x86/intel_scu_pltdrv.c
@@ -15,7 +15,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
-#include <asm/intel_scu_ipc.h>
+#include <linux/platform_data/x86/intel_scu_ipc.h>
static int intel_scu_platform_probe(struct platform_device *pdev)
{
diff --git a/drivers/platform/x86/intel_scu_wdt.c b/drivers/platform/x86/intel_scu_wdt.c
index d0b6637861d3..746d47d33406 100644
--- a/drivers/platform/x86/intel_scu_wdt.c
+++ b/drivers/platform/x86/intel_scu_wdt.c
@@ -9,13 +9,14 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/platform_device.h>
-#include <linux/platform_data/intel-mid_wdt.h>
#include <asm/cpu_device_id.h>
#include <asm/intel-family.h>
#include <asm/io_apic.h>
#include <asm/hw_irq.h>
+#include <linux/platform_data/x86/intel-mid_wdt.h>
+
#define TANGIER_EXT_TIMER0_MSI 12
static struct platform_device wdt_dev = {
diff --git a/drivers/platform/x86/lenovo-ymc.c b/drivers/platform/x86/lenovo-ymc.c
index e0bbd6a14a89..bd9f95404c7c 100644
--- a/drivers/platform/x86/lenovo-ymc.c
+++ b/drivers/platform/x86/lenovo-ymc.c
@@ -43,6 +43,8 @@ struct lenovo_ymc_private {
};
static const struct key_entry lenovo_ymc_keymap[] = {
+ /* Ignore the uninitialized state */
+ { KE_IGNORE, 0x00 },
/* Laptop */
{ KE_SW, 0x01, { .sw = { SW_TABLET_MODE, 0 } } },
/* Tablet */
diff --git a/drivers/platform/x86/lg-laptop.c b/drivers/platform/x86/lg-laptop.c
index 9c7857842caf..4b57102c7f62 100644
--- a/drivers/platform/x86/lg-laptop.c
+++ b/drivers/platform/x86/lg-laptop.c
@@ -8,6 +8,9 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/device.h>
+#include <linux/dev_printk.h>
#include <linux/dmi.h>
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
@@ -31,6 +34,26 @@ MODULE_AUTHOR("Matan Ziv-Av");
MODULE_DESCRIPTION("LG WMI Hotkey Driver");
MODULE_LICENSE("GPL");
+static bool fw_debug;
+module_param(fw_debug, bool, 0);
+MODULE_PARM_DESC(fw_debug, "Enable printing of firmware debug messages");
+
+#define LG_ADDRESS_SPACE_ID 0x8F
+
+#define LG_ADDRESS_SPACE_DEBUG_FLAG_ADR 0x00
+#define LG_ADDRESS_SPACE_FAN_MODE_ADR 0x03
+
+#define LG_ADDRESS_SPACE_DTTM_FLAG_ADR 0x20
+#define LG_ADDRESS_SPACE_CPU_TEMP_ADR 0x21
+#define LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR 0x22
+#define LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR 0x23
+#define LG_ADDRESS_SPACE_MB_TEMP_ADR 0x24
+#define LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR 0x25
+#define LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR 0x26
+
+#define LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR 0x3E8
+#define LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR 0x5E8
+
#define WMI_EVENT_GUID0 "E4FB94F9-7F2B-4173-AD1A-CD1D95086248"
#define WMI_EVENT_GUID1 "023B133E-49D1-4E10-B313-698220140DC2"
#define WMI_EVENT_GUID2 "37BE1AC0-C3F2-4B1F-BFBE-8FDEAF2814D6"
@@ -182,21 +205,11 @@ static union acpi_object *lg_wmbb(struct device *dev, u32 method_id, u32 arg1, u
return (union acpi_object *)buffer.pointer;
}
-static void wmi_notify(u32 value, void *context)
+static void wmi_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
long data = (long)context;
pr_debug("event guid %li\n", data);
- status = wmi_get_event_data(value, &response);
- if (ACPI_FAILURE(status)) {
- pr_err("Bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
if (!obj)
return;
@@ -218,7 +231,6 @@ static void wmi_notify(u32 value, void *context)
pr_debug("Type: %i Eventcode: 0x%llx\n", obj->type,
obj->integer.value);
- kfree(response.pointer);
}
static void wmi_input_setup(void)
@@ -646,6 +658,107 @@ static struct platform_driver pf_driver = {
}
};
+static acpi_status lg_laptop_address_space_write(struct device *dev, acpi_physical_address address,
+ size_t size, u64 value)
+{
+ u8 byte;
+
+ /* Ignore any debug messages */
+ if (address >= LG_ADDRESS_SPACE_DEBUG_MSG_START_ADR &&
+ address <= LG_ADDRESS_SPACE_DEBUG_MSG_END_ADR)
+ return AE_OK;
+
+ if (size != sizeof(byte))
+ return AE_BAD_PARAMETER;
+
+ byte = value & 0xFF;
+
+ switch (address) {
+ case LG_ADDRESS_SPACE_FAN_MODE_ADR:
+ /*
+ * The fan mode field is not affected by the DTTM flag, so we
+ * have to manually check fw_debug.
+ */
+ if (fw_debug)
+ dev_dbg(dev, "Fan mode set to mode %u\n", byte);
+
+ return AE_OK;
+ case LG_ADDRESS_SPACE_CPU_TEMP_ADR:
+ dev_dbg(dev, "CPU temperature is %u °C\n", byte);
+ return AE_OK;
+ case LG_ADDRESS_SPACE_CPU_TRIP_LOW_ADR:
+ dev_dbg(dev, "CPU lower trip point set to %u °C\n", byte);
+ return AE_OK;
+ case LG_ADDRESS_SPACE_CPU_TRIP_HIGH_ADR:
+ dev_dbg(dev, "CPU higher trip point set to %u °C\n", byte);
+ return AE_OK;
+ case LG_ADDRESS_SPACE_MB_TEMP_ADR:
+ dev_dbg(dev, "Motherboard temperature is %u °C\n", byte);
+ return AE_OK;
+ case LG_ADDRESS_SPACE_MB_TRIP_LOW_ADR:
+ dev_dbg(dev, "Motherboard lower trip point set to %u °C\n", byte);
+ return AE_OK;
+ case LG_ADDRESS_SPACE_MB_TRIP_HIGH_ADR:
+ dev_dbg(dev, "Motherboard higher trip point set to %u °C\n", byte);
+ return AE_OK;
+ default:
+ dev_notice_ratelimited(dev, "Ignoring write to unknown opregion address %llu\n",
+ address);
+ return AE_OK;
+ }
+}
+
+static acpi_status lg_laptop_address_space_read(struct device *dev, acpi_physical_address address,
+ size_t size, u64 *value)
+{
+ if (size != 1)
+ return AE_BAD_PARAMETER;
+
+ switch (address) {
+ case LG_ADDRESS_SPACE_DEBUG_FLAG_ADR:
+ /* Debug messages are already printed using the standard ACPI Debug object */
+ *value = 0x00;
+ return AE_OK;
+ case LG_ADDRESS_SPACE_DTTM_FLAG_ADR:
+ *value = fw_debug;
+ return AE_OK;
+ default:
+ dev_notice_ratelimited(dev, "Attempt to read unknown opregion address %llu\n",
+ address);
+ return AE_BAD_PARAMETER;
+ }
+}
+
+static acpi_status lg_laptop_address_space_handler(u32 function, acpi_physical_address address,
+ u32 bits, u64 *value, void *handler_context,
+ void *region_context)
+{
+ struct device *dev = handler_context;
+ size_t size;
+
+ if (bits % BITS_PER_BYTE)
+ return AE_BAD_PARAMETER;
+
+ size = bits / BITS_PER_BYTE;
+
+ switch (function) {
+ case ACPI_READ:
+ return lg_laptop_address_space_read(dev, address, size, value);
+ case ACPI_WRITE:
+ return lg_laptop_address_space_write(dev, address, size, *value);
+ default:
+ return AE_BAD_PARAMETER;
+ }
+}
+
+static void lg_laptop_remove_address_space_handler(void *data)
+{
+ struct acpi_device *device = data;
+
+ acpi_remove_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
+ &lg_laptop_address_space_handler);
+}
+
static int acpi_add(struct acpi_device *device)
{
struct platform_device_info pdev_info = {
@@ -653,6 +766,7 @@ static int acpi_add(struct acpi_device *device)
.name = PLATFORM_NAME,
.id = PLATFORM_DEVID_NONE,
};
+ acpi_status status;
int ret;
const char *product;
int year = 2017;
@@ -660,6 +774,17 @@ static int acpi_add(struct acpi_device *device)
if (pf_device)
return 0;
+ status = acpi_install_address_space_handler(device->handle, LG_ADDRESS_SPACE_ID,
+ &lg_laptop_address_space_handler,
+ NULL, &device->dev);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ ret = devm_add_action_or_reset(&device->dev, lg_laptop_remove_address_space_handler,
+ device);
+ if (ret < 0)
+ return ret;
+
ret = platform_driver_register(&pf_driver);
if (ret)
return ret;
diff --git a/drivers/platform/x86/msi-wmi.c b/drivers/platform/x86/msi-wmi.c
index fd318cdfe313..4a7ac85c4db4 100644
--- a/drivers/platform/x86/msi-wmi.c
+++ b/drivers/platform/x86/msi-wmi.c
@@ -170,20 +170,9 @@ static const struct backlight_ops msi_backlight_ops = {
.update_status = bl_set_status,
};
-static void msi_wmi_notify(u32 value, void *context)
+static void msi_wmi_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
struct key_entry *key;
- union acpi_object *obj;
- acpi_status status;
-
- status = wmi_get_event_data(value, &response);
- if (status != AE_OK) {
- pr_info("bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
if (obj && obj->type == ACPI_TYPE_INTEGER) {
int eventcode = obj->integer.value;
@@ -192,7 +181,7 @@ static void msi_wmi_notify(u32 value, void *context)
eventcode);
if (!key) {
pr_info("Unknown key pressed - %x\n", eventcode);
- goto msi_wmi_notify_exit;
+ return;
}
if (event_wmi->quirk_last_pressed) {
@@ -204,7 +193,7 @@ static void msi_wmi_notify(u32 value, void *context)
pr_debug("Suppressed key event 0x%X - "
"Last press was %lld us ago\n",
key->code, ktime_to_us(diff));
- goto msi_wmi_notify_exit;
+ return;
}
last_pressed = cur;
}
@@ -221,9 +210,6 @@ static void msi_wmi_notify(u32 value, void *context)
}
} else
pr_info("Unknown event received\n");
-
-msi_wmi_notify_exit:
- kfree(response.pointer);
}
static int __init msi_wmi_backlight_setup(void)
diff --git a/drivers/platform/x86/panasonic-laptop.c b/drivers/platform/x86/panasonic-laptop.c
index ebd81846e2d5..2bf94d0ab324 100644
--- a/drivers/platform/x86/panasonic-laptop.c
+++ b/drivers/platform/x86/panasonic-laptop.c
@@ -121,6 +121,7 @@
#include <linux/acpi.h>
#include <linux/backlight.h>
+#include <linux/bits.h>
#include <linux/ctype.h>
#include <linux/i8042.h>
#include <linux/init.h>
@@ -224,6 +225,17 @@ static const struct key_entry panasonic_keymap[] = {
{ KE_KEY, 8, { KEY_PROG1 } }, /* Change CPU boost */
{ KE_KEY, 9, { KEY_BATTERY } },
{ KE_KEY, 10, { KEY_SUSPEND } },
+ { KE_KEY, 21, { KEY_MACRO1 } },
+ { KE_KEY, 22, { KEY_MACRO2 } },
+ { KE_KEY, 24, { KEY_MACRO3 } },
+ { KE_KEY, 25, { KEY_MACRO4 } },
+ { KE_KEY, 34, { KEY_MACRO5 } },
+ { KE_KEY, 35, { KEY_MACRO6 } },
+ { KE_KEY, 36, { KEY_MACRO7 } },
+ { KE_KEY, 37, { KEY_MACRO8 } },
+ { KE_KEY, 41, { KEY_MACRO9 } },
+ { KE_KEY, 42, { KEY_MACRO10 } },
+ { KE_KEY, 43, { KEY_MACRO11 } },
{ KE_END, 0 }
};
@@ -830,8 +842,8 @@ static void acpi_pcc_generate_keyinput(struct pcc_acpi *pcc)
return;
}
- key = result & 0xf;
- updown = result & 0x80; /* 0x80 == key down; 0x00 = key up */
+ key = result & GENMASK(6, 0);
+ updown = result & BIT(7); /* 0x80 == key down; 0x00 = key up */
/* hack: some firmware sends no key down for sleep / hibernate */
if (key == 7 || key == 10) {
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index 3d2f8e758369..0d3e3ca20b1b 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -14,7 +14,6 @@
#include <linux/pci.h>
#include <linux/backlight.h>
#include <linux/leds.h>
-#include <linux/fb.h>
#include <linux/dmi.h>
#include <linux/platform_device.h>
#include <linux/rfkill.h>
@@ -554,7 +553,7 @@ static int update_status(struct backlight_device *bd)
set_brightness(samsung, bd->props.brightness);
- if (bd->props.power == FB_BLANK_UNBLANK)
+ if (bd->props.power == BACKLIGHT_POWER_ON)
sabi_set_commandb(samsung, commands->set_backlight, 1);
else
sabi_set_commandb(samsung, commands->set_backlight, 0);
@@ -1189,7 +1188,7 @@ static int __init samsung_backlight_init(struct samsung_laptop *samsung)
samsung->backlight_device = bd;
samsung->backlight_device->props.brightness = read_brightness(samsung);
- samsung->backlight_device->props.power = FB_BLANK_UNBLANK;
+ samsung->backlight_device->props.power = BACKLIGHT_POWER_ON;
backlight_update_status(samsung->backlight_device);
return 0;
diff --git a/drivers/platform/x86/serial-multi-instantiate.c b/drivers/platform/x86/serial-multi-instantiate.c
index 3be016cfe601..7c04cc9e5891 100644
--- a/drivers/platform/x86/serial-multi-instantiate.c
+++ b/drivers/platform/x86/serial-multi-instantiate.c
@@ -83,11 +83,15 @@ static int smi_get_irq(struct platform_device *pdev, struct acpi_device *adev,
static void smi_devs_unregister(struct smi *smi)
{
+#if IS_REACHABLE(CONFIG_I2C)
while (smi->i2c_num--)
i2c_unregister_device(smi->i2c_devs[smi->i2c_num]);
+#endif
- while (smi->spi_num--)
- spi_unregister_device(smi->spi_devs[smi->spi_num]);
+ if (IS_REACHABLE(CONFIG_SPI)) {
+ while (smi->spi_num--)
+ spi_unregister_device(smi->spi_devs[smi->spi_num]);
+ }
}
/**
@@ -258,9 +262,15 @@ static int smi_probe(struct platform_device *pdev)
switch (node->bus_type) {
case SMI_I2C:
- return smi_i2c_probe(pdev, smi, node->instances);
+ if (IS_REACHABLE(CONFIG_I2C))
+ return smi_i2c_probe(pdev, smi, node->instances);
+
+ return -ENODEV;
case SMI_SPI:
- return smi_spi_probe(pdev, smi, node->instances);
+ if (IS_REACHABLE(CONFIG_SPI))
+ return smi_spi_probe(pdev, smi, node->instances);
+
+ return -ENODEV;
case SMI_AUTO_DETECT:
/*
* For backwards-compatibility with the existing nodes I2C
@@ -270,10 +280,16 @@ static int smi_probe(struct platform_device *pdev)
* SpiSerialBus nodes that were previously ignored, and this
* preserves that behavior.
*/
- ret = smi_i2c_probe(pdev, smi, node->instances);
- if (ret != -ENOENT)
- return ret;
- return smi_spi_probe(pdev, smi, node->instances);
+ if (IS_REACHABLE(CONFIG_I2C)) {
+ ret = smi_i2c_probe(pdev, smi, node->instances);
+ if (ret != -ENOENT)
+ return ret;
+ }
+
+ if (IS_REACHABLE(CONFIG_SPI))
+ return smi_spi_probe(pdev, smi, node->instances);
+
+ return -ENODEV;
default:
return -EINVAL;
}
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index f269ca1ff771..4c1b0553f872 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -7749,6 +7749,28 @@ static struct ibm_struct volume_driver_data = {
* EC 0x2f (HFSP) might be available *for reading*, but do not use
* it for writing.
*
+ * TPACPI_FAN_RD_ACPI_FANG:
+ * ACPI FANG method: returns fan control register
+ *
+ * Takes one parameter which is 0x8100 plus the offset to EC memory
+ * address 0xf500 and returns the byte at this address.
+ *
+ * 0xf500:
+ * When the value is less than 9 automatic mode is enabled
+ * 0xf502:
+ * Contains the current fan speed from 0-100%
+ * 0xf506:
+ * Bit 7 has to be set in order to enable manual control by
+ * writing a value >= 9 to 0xf500
+ *
+ * TPACPI_FAN_WR_ACPI_FANW:
+ * ACPI FANW method: sets fan control registers
+ *
+ * Takes 0x8100 plus the offset to EC memory address 0xf500 and the
+ * value to be written there as parameters.
+ *
+ * see TPACPI_FAN_RD_ACPI_FANG
+ *
* TPACPI_FAN_WR_TPEC:
* ThinkPad EC register 0x2f (HFSP): fan control loop mode
* Supported on almost all ThinkPads
@@ -7882,6 +7904,7 @@ enum { /* Fan control constants */
enum fan_status_access_mode {
TPACPI_FAN_NONE = 0, /* No fan status or control */
TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
+ TPACPI_FAN_RD_ACPI_FANG, /* Use ACPI FANG */
TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
TPACPI_FAN_RD_TPEC_NS, /* Use non-standard ACPI EC regs (eg: L13 Yoga gen2 etc.) */
};
@@ -7889,6 +7912,7 @@ enum fan_status_access_mode {
enum fan_control_access_mode {
TPACPI_FAN_WR_NONE = 0, /* No fan control */
TPACPI_FAN_WR_ACPI_SFAN, /* Use ACPI SFAN */
+ TPACPI_FAN_WR_ACPI_FANW, /* Use ACPI FANW */
TPACPI_FAN_WR_TPEC, /* Use ACPI EC reg 0x2f */
TPACPI_FAN_WR_ACPI_FANS, /* Use ACPI FANS and EC reg 0x2f */
};
@@ -7922,9 +7946,13 @@ TPACPI_HANDLE(fans, ec, "FANS"); /* X31, X40, X41 */
TPACPI_HANDLE(gfan, ec, "GFAN", /* 570 */
"\\FSPD", /* 600e/x, 770e, 770x */
); /* all others */
+TPACPI_HANDLE(fang, ec, "FANG", /* E531 */
+ ); /* all others */
TPACPI_HANDLE(sfan, ec, "SFAN", /* 570 */
"JFNS", /* 770x-JL */
); /* all others */
+TPACPI_HANDLE(fanw, ec, "FANW", /* E531 */
+ ); /* all others */
/*
* Unitialized HFSP quirk: ACPI DSDT and EC fail to initialize the
@@ -8031,6 +8059,23 @@ static int fan_get_status(u8 *status)
break;
}
+ case TPACPI_FAN_RD_ACPI_FANG: {
+ /* E531 */
+ int mode, speed;
+
+ if (unlikely(!acpi_evalf(fang_handle, &mode, NULL, "dd", 0x8100)))
+ return -EIO;
+ if (unlikely(!acpi_evalf(fang_handle, &speed, NULL, "dd", 0x8102)))
+ return -EIO;
+
+ if (likely(status)) {
+ *status = speed * 7 / 100;
+ if (mode < 9)
+ *status |= TP_EC_FAN_AUTO;
+ }
+
+ break;
+ }
case TPACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
if (unlikely(!acpi_ec_read(fan_status_offset, &s)))
@@ -8145,6 +8190,17 @@ static int fan2_get_speed(unsigned int *speed)
if (speed)
*speed = lo ? FAN_RPM_CAL_CONST / lo : 0;
break;
+ case TPACPI_FAN_RD_ACPI_FANG: {
+ /* E531 */
+ int speed_tmp;
+
+ if (unlikely(!acpi_evalf(fang_handle, &speed_tmp, NULL, "dd", 0x8102)))
+ return -EIO;
+
+ if (likely(speed))
+ *speed = speed_tmp * 65535 / 100;
+ break;
+ }
default:
return -ENXIO;
@@ -8204,6 +8260,32 @@ static int fan_set_level(int level)
tp_features.fan_ctrl_status_undef = 0;
break;
+ case TPACPI_FAN_WR_ACPI_FANW:
+ if (!(level & TP_EC_FAN_AUTO) && (level < 0 || level > 7))
+ return -EINVAL;
+ if (level & TP_EC_FAN_FULLSPEED)
+ return -EINVAL;
+
+ if (level & TP_EC_FAN_AUTO) {
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8106, 0x05)) {
+ return -EIO;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8100, 0x00)) {
+ return -EIO;
+ }
+ } else {
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8106, 0x45)) {
+ return -EIO;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8100, 0xff)) {
+ return -EIO;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8102, level * 100 / 7)) {
+ return -EIO;
+ }
+ }
+ break;
+
default:
return -ENXIO;
}
@@ -8236,7 +8318,7 @@ static int fan_set_level_safe(int level)
static int fan_set_enable(void)
{
- u8 s;
+ u8 s = 0;
int rc;
if (!fan_control_allowed)
@@ -8282,6 +8364,19 @@ static int fan_set_enable(void)
rc = 0;
break;
+ case TPACPI_FAN_WR_ACPI_FANW:
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8106, 0x05)) {
+ rc = -EIO;
+ break;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8100, 0x00)) {
+ rc = -EIO;
+ break;
+ }
+
+ rc = 0;
+ break;
+
default:
rc = -ENXIO;
}
@@ -8324,6 +8419,22 @@ static int fan_set_disable(void)
fan_control_desired_level = 0;
break;
+ case TPACPI_FAN_WR_ACPI_FANW:
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8106, 0x45)) {
+ rc = -EIO;
+ break;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8100, 0xff)) {
+ rc = -EIO;
+ break;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8102, 0x00)) {
+ rc = -EIO;
+ break;
+ }
+ rc = 0;
+ break;
+
default:
rc = -ENXIO;
}
@@ -8357,6 +8468,23 @@ static int fan_set_speed(int speed)
rc = -EINVAL;
break;
+ case TPACPI_FAN_WR_ACPI_FANW:
+ if (speed >= 0 && speed <= 65535) {
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8106, 0x45)) {
+ rc = -EIO;
+ break;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd", 0x8100, 0xff)) {
+ rc = -EIO;
+ break;
+ }
+ if (!acpi_evalf(fanw_handle, NULL, NULL, "vdd",
+ 0x8102, speed * 100 / 65535))
+ rc = -EIO;
+ } else
+ rc = -EINVAL;
+ break;
+
default:
rc = -ENXIO;
}
@@ -8699,6 +8827,10 @@ static int __init fan_init(struct ibm_init_struct *iibm)
TPACPI_ACPIHANDLE_INIT(gfan);
TPACPI_ACPIHANDLE_INIT(sfan);
}
+ if (tpacpi_is_lenovo()) {
+ TPACPI_ACPIHANDLE_INIT(fang);
+ TPACPI_ACPIHANDLE_INIT(fanw);
+ }
quirks = tpacpi_check_quirks(fan_quirk_table,
ARRAY_SIZE(fan_quirk_table));
@@ -8718,6 +8850,9 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */
fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
+ } else if (fang_handle) {
+ /* E531 */
+ fan_status_access_mode = TPACPI_FAN_RD_ACPI_FANG;
} else {
/* all other ThinkPads: note that even old-style
* ThinkPad ECs supports the fan control register */
@@ -8764,6 +8899,11 @@ static int __init fan_init(struct ibm_init_struct *iibm)
fan_control_access_mode = TPACPI_FAN_WR_ACPI_SFAN;
fan_control_commands |=
TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_ENABLE;
+ } else if (fanw_handle) {
+ /* E531 */
+ fan_control_access_mode = TPACPI_FAN_WR_ACPI_FANW;
+ fan_control_commands |=
+ TPACPI_FAN_CMD_LEVEL | TPACPI_FAN_CMD_SPEED | TPACPI_FAN_CMD_ENABLE;
} else {
if (!gfan_handle) {
/* gfan without sfan means no fan control */
@@ -8915,6 +9055,7 @@ static int fan_read(struct seq_file *m)
case TPACPI_FAN_RD_TPEC_NS:
case TPACPI_FAN_RD_TPEC:
+ case TPACPI_FAN_RD_ACPI_FANG:
/* all except 570, 600e/x, 770e, 770x */
rc = fan_get_status_safe(&status);
if (rc)
@@ -8935,7 +9076,7 @@ static int fan_read(struct seq_file *m)
* No other levels settings available
*/
seq_printf(m, "level:\t\t%s\n", status & FAN_NS_CTRL ? "unknown" : "auto");
- } else {
+ } else if (fan_status_access_mode == TPACPI_FAN_RD_TPEC) {
if (status & TP_EC_FAN_FULLSPEED)
/* Disengaged mode takes precedence */
seq_printf(m, "level:\t\tdisengaged\n");
diff --git a/drivers/platform/x86/toshiba-wmi.c b/drivers/platform/x86/toshiba-wmi.c
index 77c35529ab6f..12c46455e8dc 100644
--- a/drivers/platform/x86/toshiba-wmi.c
+++ b/drivers/platform/x86/toshiba-wmi.c
@@ -32,26 +32,13 @@ static const struct key_entry toshiba_wmi_keymap[] __initconst = {
{ KE_END, 0 }
};
-static void toshiba_wmi_notify(u32 value, void *context)
+static void toshiba_wmi_notify(union acpi_object *obj, void *context)
{
- struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
-
- status = wmi_get_event_data(value, &response);
- if (ACPI_FAILURE(status)) {
- pr_err("Bad event status 0x%x\n", status);
- return;
- }
-
- obj = (union acpi_object *)response.pointer;
if (!obj)
return;
/* TODO: Add proper checks once we have data */
pr_debug("Unknown event received, obj type %x\n", obj->type);
-
- kfree(response.pointer);
}
static const struct dmi_system_id toshiba_wmi_dmi_table[] __initconst = {
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index f74af0a689f2..0a39f68c641d 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -840,6 +840,21 @@ static const struct ts_dmi_data rwc_nanote_p8_data = {
.properties = rwc_nanote_p8_props,
};
+static const struct property_entry rwc_nanote_next_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 5),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 5),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1785),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1145),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-rwc-nanote-next.fw"),
+ { }
+};
+
+static const struct ts_dmi_data rwc_nanote_next_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = rwc_nanote_next_props,
+};
+
static const struct property_entry schneider_sct101ctm_props[] = {
PROPERTY_ENTRY_U32("touchscreen-size-x", 1715),
PROPERTY_ENTRY_U32("touchscreen-size-y", 1140),
@@ -1590,6 +1605,17 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* RWC NANOTE NEXT */
+ .driver_data = (void *)&rwc_nanote_next_data,
+ .matches = {
+ DMI_MATCH(DMI_PRODUCT_NAME, "To be filled by O.E.M."),
+ DMI_MATCH(DMI_BOARD_NAME, "To be filled by O.E.M."),
+ DMI_MATCH(DMI_BOARD_VENDOR, "To be filled by O.E.M."),
+ /* Above matches are too generic, add bios-version match */
+ DMI_MATCH(DMI_BIOS_VERSION, "S8A70R100-V005"),
+ },
+ },
+ {
/* Schneider SCT101CTM */
.driver_data = (void *)&schneider_sct101ctm_data,
.matches = {
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 1d0b2d6040d1..3cbe180c3fc0 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -166,22 +166,6 @@ static inline acpi_object_type get_param_acpi_type(const struct wmi_block *wbloc
return ACPI_TYPE_BUFFER;
}
-static acpi_status get_event_data(const struct wmi_block *wblock, struct acpi_buffer *out)
-{
- union acpi_object param = {
- .integer = {
- .type = ACPI_TYPE_INTEGER,
- .value = wblock->gblock.notify_id,
- }
- };
- struct acpi_object_list input = {
- .count = 1,
- .pointer = &param,
- };
-
- return acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, out);
-}
-
static int wmidev_match_guid(struct device *dev, const void *data)
{
struct wmi_block *wblock = dev_to_wblock(dev);
@@ -199,23 +183,6 @@ static int wmidev_match_guid(struct device *dev, const void *data)
return 0;
}
-static int wmidev_match_notify_id(struct device *dev, const void *data)
-{
- struct wmi_block *wblock = dev_to_wblock(dev);
- const u32 *notify_id = data;
-
- /* Legacy GUID-based functions are restricted to only see
- * a single WMI device for each GUID.
- */
- if (test_bit(WMI_GUID_DUPLICATED, &wblock->flags))
- return 0;
-
- if (wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *notify_id)
- return 1;
-
- return 0;
-}
-
static const struct bus_type wmi_bus_type;
static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
@@ -235,17 +202,6 @@ static struct wmi_device *wmi_find_device_by_guid(const char *guid_string)
return dev_to_wdev(dev);
}
-static struct wmi_device *wmi_find_event_by_notify_id(const u32 notify_id)
-{
- struct device *dev;
-
- dev = bus_find_device(&wmi_bus_type, NULL, &notify_id, wmidev_match_notify_id);
- if (!dev)
- return ERR_PTR(-ENODEV);
-
- return to_wmi_device(dev);
-}
-
static void wmi_device_put(struct wmi_device *wdev)
{
put_device(&wdev->dev);
@@ -650,35 +606,6 @@ acpi_status wmi_remove_notify_handler(const char *guid)
EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
/**
- * wmi_get_event_data - Get WMI data associated with an event (deprecated)
- *
- * @event: Event to find
- * @out: Buffer to hold event data
- *
- * Get extra data associated with an WMI event, the caller needs to free @out.
- *
- * Return: acpi_status signaling success or error.
- */
-acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
-{
- struct wmi_block *wblock;
- struct wmi_device *wdev;
- acpi_status status;
-
- wdev = wmi_find_event_by_notify_id(event);
- if (IS_ERR(wdev))
- return AE_NOT_FOUND;
-
- wblock = container_of(wdev, struct wmi_block, dev);
- status = get_event_data(wblock, out);
-
- wmi_device_put(wdev);
-
- return status;
-}
-EXPORT_SYMBOL_GPL(wmi_get_event_data);
-
-/**
* wmi_has_guid - Check if a GUID is available
* @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
*
@@ -1186,14 +1113,19 @@ static int parse_wdg(struct device *wmi_bus_dev, struct platform_device *pdev)
static int wmi_get_notify_data(struct wmi_block *wblock, union acpi_object **obj)
{
struct acpi_buffer data = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object param = {
+ .integer = {
+ .type = ACPI_TYPE_INTEGER,
+ .value = wblock->gblock.notify_id,
+ }
+ };
+ struct acpi_object_list input = {
+ .count = 1,
+ .pointer = &param,
+ };
acpi_status status;
- if (test_bit(WMI_NO_EVENT_DATA, &wblock->flags)) {
- *obj = NULL;
- return 0;
- }
-
- status = get_event_data(wblock, &data);
+ status = acpi_evaluate_object(wblock->acpi_device->handle, "_WED", &input, &data);
if (ACPI_FAILURE(status)) {
dev_warn(&wblock->dev.dev, "Failed to get event data\n");
return -EIO;
@@ -1220,47 +1152,40 @@ static void wmi_notify_driver(struct wmi_block *wblock, union acpi_object *obj)
static int wmi_notify_device(struct device *dev, void *data)
{
struct wmi_block *wblock = dev_to_wblock(dev);
- union acpi_object *obj;
+ union acpi_object *obj = NULL;
u32 *event = data;
int ret;
if (!(wblock->gblock.flags & ACPI_WMI_EVENT && wblock->gblock.notify_id == *event))
return 0;
- down_read(&wblock->notify_lock);
- /* The WMI driver notify handler conflicts with the legacy WMI handler.
- * Because of this the WMI driver notify handler takes precedence.
+ /* The ACPI WMI specification says that _WED should be
+ * evaluated every time an notification is received, even
+ * if no consumers are present.
+ *
+ * Some firmware implementations actually depend on this
+ * by using a queue for events which will fill up if the
+ * WMI driver core stops evaluating _WED due to missing
+ * WMI event consumers.
*/
- if (wblock->dev.dev.driver && wblock->driver_ready) {
+ if (!test_bit(WMI_NO_EVENT_DATA, &wblock->flags)) {
ret = wmi_get_notify_data(wblock, &obj);
- if (ret >= 0) {
- wmi_notify_driver(wblock, obj);
- kfree(obj);
- }
- } else {
- if (wblock->handler) {
- wblock->handler(*event, wblock->handler_data);
- } else {
- /* The ACPI WMI specification says that _WED should be
- * evaluated every time an notification is received, even
- * if no consumers are present.
- *
- * Some firmware implementations actually depend on this
- * by using a queue for events which will fill up if the
- * WMI driver core stops evaluating _WED due to missing
- * WMI event consumers.
- *
- * Because of this we need this seemingly useless call to
- * wmi_get_notify_data() which in turn evaluates _WED.
- */
- ret = wmi_get_notify_data(wblock, &obj);
- if (ret >= 0)
- kfree(obj);
- }
-
+ if (ret < 0)
+ return -EIO;
}
+
+ down_read(&wblock->notify_lock);
+
+ if (wblock->dev.dev.driver && wblock->driver_ready)
+ wmi_notify_driver(wblock, obj);
+
+ if (wblock->handler)
+ wblock->handler(obj, wblock->handler_data);
+
up_read(&wblock->notify_lock);
+ kfree(obj);
+
acpi_bus_generate_netlink_event("wmi", acpi_dev_name(wblock->acpi_device), *event, 0);
return -EBUSY;
diff --git a/drivers/platform/x86/x86-android-tablets/Kconfig b/drivers/platform/x86/x86-android-tablets/Kconfig
index b591419de80c..88d9e8f2ff24 100644
--- a/drivers/platform/x86/x86-android-tablets/Kconfig
+++ b/drivers/platform/x86/x86-android-tablets/Kconfig
@@ -20,4 +20,4 @@ config X86_ANDROID_TABLETS
are missing from the DSDT.
If you have a x86 Android tablet say Y or M here, for a generic x86
- distro config say M here.
+ distro configuration say M here.
diff --git a/drivers/platform/x86/x86-android-tablets/asus.c b/drivers/platform/x86/x86-android-tablets/asus.c
index 227afbb51078..07fbeab2319a 100644
--- a/drivers/platform/x86/x86-android-tablets/asus.c
+++ b/drivers/platform/x86/x86-android-tablets/asus.c
@@ -37,7 +37,7 @@ static const struct x86_gpio_button asus_me176c_tf103c_lid __initconst = {
.pin = 12,
};
-/* Asus ME176C tablets have an Android factory img with everything hardcoded */
+/* Asus ME176C tablets have an Android factory image with everything hardcoded */
static const char * const asus_me176c_accel_mount_matrix[] = {
"-1", "0", "0",
"0", "1", "0",
@@ -112,7 +112,7 @@ static const struct x86_i2c_client_info asus_me176c_i2c_clients[] __initconst =
},
.adapter_path = "\\_SB_.I2C5",
}, {
- /* kxtj21009 accel */
+ /* kxtj21009 accelerometer */
.board_info = {
.type = "kxtj21009",
.addr = 0x0f,
@@ -181,7 +181,7 @@ const struct x86_dev_info asus_me176c_info __initconst = {
.modules = bq24190_modules,
};
-/* Asus TF103C tablets have an Android factory img with everything hardcoded */
+/* Asus TF103C tablets have an Android factory image with everything hardcoded */
static const char * const asus_tf103c_accel_mount_matrix[] = {
"0", "-1", "0",
"-1", "0", "0",
@@ -280,7 +280,7 @@ static const struct x86_i2c_client_info asus_tf103c_i2c_clients[] __initconst =
},
.adapter_path = "\\_SB_.I2C5",
}, {
- /* kxtj21009 accel */
+ /* kxtj21009 accelerometer */
.board_info = {
.type = "kxtj21009",
.addr = 0x0f,
diff --git a/drivers/platform/x86/x86-android-tablets/core.c b/drivers/platform/x86/x86-android-tablets/core.c
index 919ef4471229..1427a9a39008 100644
--- a/drivers/platform/x86/x86-android-tablets/core.c
+++ b/drivers/platform/x86/x86-android-tablets/core.c
@@ -26,19 +26,19 @@
static struct platform_device *x86_android_tablet_device;
/*
- * This helper allows getting a gpio_desc *before* the actual device consuming
- * the GPIO has been instantiated. This function _must_ only be used to handle
- * this special case such as e.g. :
+ * This helper allows getting a GPIO descriptor *before* the actual device
+ * consuming it has been instantiated. This function MUST only be used to
+ * handle this special case such as, e.g.:
*
* 1. Getting an IRQ from a GPIO for i2c_board_info.irq which is passed to
* i2c_client_new() to instantiate i2c_client-s; or
- * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio_keys
+ * 2. Calling desc_to_gpio() to get an old style GPIO number for gpio-keys
* platform_data which still uses old style GPIO numbers.
*
- * Since the consuming device has not been instatiated yet a dynamic lookup
- * is generated using the special x86_android_tablet dev for dev_id.
+ * Since the consuming device has not been instantiated yet a dynamic lookup
+ * is generated using the special x86_android_tablet device for dev_id.
*
- * For normal GPIO lookups a standard static gpiod_lookup_table _must_ be used.
+ * For normal GPIO lookups a standard static struct gpiod_lookup_table MUST be used.
*/
int x86_android_tablet_get_gpiod(const char *chip, int pin, const char *con_id,
bool active_low, enum gpiod_flags dflags,
@@ -87,7 +87,7 @@ int x86_acpi_irq_helper_get(const struct x86_acpi_irq_data *data)
/*
* The DSDT may already reference the GSI in a device skipped by
* acpi_quirk_skip_i2c_client_enumeration(). Unregister the GSI
- * to avoid EBUSY errors in this case.
+ * to avoid -EBUSY errors in this case.
*/
acpi_unregister_gsi(data->index);
irq = acpi_register_gsi(NULL, data->index, data->trigger, data->polarity);
@@ -379,7 +379,7 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev)
}
}
- /* + 1 to make space for (optional) gpio_keys_button pdev */
+ /* + 1 to make space for the (optional) gpio_keys_button platform device */
pdevs = kcalloc(dev_info->pdev_count + 1, sizeof(*pdevs), GFP_KERNEL);
if (!pdevs) {
x86_android_tablet_remove(pdev);
@@ -432,7 +432,7 @@ static __init int x86_android_tablet_probe(struct platform_device *pdev)
buttons[i] = dev_info->gpio_button[i].button;
buttons[i].gpio = desc_to_gpio(gpiod);
- /* Release gpiod so that gpio-keys can request it */
+ /* Release GPIO descriptor so that gpio-keys can request it */
devm_gpiod_put(&x86_android_tablet_device->dev, gpiod);
}
diff --git a/drivers/platform/x86/x86-android-tablets/dmi.c b/drivers/platform/x86/x86-android-tablets/dmi.c
index 387dd092c4dd..17f6da96aa01 100644
--- a/drivers/platform/x86/x86-android-tablets/dmi.c
+++ b/drivers/platform/x86/x86-android-tablets/dmi.c
@@ -99,17 +99,17 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
{
/* Lenovo Yoga Book X91F / X91L */
.matches = {
- /* Non exact match to match F + L versions */
+ /* Inexact match to match F + L versions */
DMI_MATCH(DMI_PRODUCT_NAME, "Lenovo YB1-X91"),
},
.driver_data = (void *)&lenovo_yogabook_x91_info,
},
{
/*
- * Lenovo Yoga Tablet 2 Pro 1380F/L (13") This has more or less
- * the same BIOS as the 830F/L or 1050F/L (8" and 10") below,
- * but unlike the 8" / 10" models which share the same mainboard
- * this model has a different mainboard.
+ * Lenovo Yoga Tablet 2 Pro 1380F/L (13")
+ * This has more or less the same BIOS as the 830F/L or 1050F/L
+ * (8" and 10") below, but unlike the 8"/10" models which share
+ * the same mainboard this model has a different mainboard.
* This match for the 13" model MUST come before the 8" + 10"
* match since that one will also match the 13" model!
*/
@@ -124,8 +124,8 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
},
{
/*
- * Lenovo Yoga Tablet 2 830F/L or 1050F/L (The 8" and 10"
- * Lenovo Yoga Tablet 2 use the same mainboard)
+ * Lenovo Yoga Tablet 2 830F/L or 1050F/L
+ * The 8" and 10" Lenovo Yoga Tablet 2 use the same mainboard.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Intel Corp."),
@@ -163,7 +163,7 @@ const struct dmi_system_id x86_android_tablet_ids[] __initconst = {
.driver_data = (void *)&nextbook_ares8_info,
},
{
- /* Nextbook Ares 8A (CHT version)*/
+ /* Nextbook Ares 8A (CHT version) */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
DMI_MATCH(DMI_PRODUCT_NAME, "CherryTrail"),
diff --git a/drivers/platform/x86/x86-android-tablets/lenovo.c b/drivers/platform/x86/x86-android-tablets/lenovo.c
index 74f39b658d2c..ae087f1471c1 100644
--- a/drivers/platform/x86/x86-android-tablets/lenovo.c
+++ b/drivers/platform/x86/x86-android-tablets/lenovo.c
@@ -59,7 +59,7 @@ static struct lp855x_platform_data lenovo_lp8557_reg_only_pdata = {
.initial_brightness = 128,
};
-/* Lenovo Yoga Book X90F / X90L's Android factory img has everything hardcoded */
+/* Lenovo Yoga Book X90F / X90L's Android factory image has everything hardcoded */
static const struct property_entry lenovo_yb1_x90_wacom_props[] = {
PROPERTY_ENTRY_U32("hid-descr-addr", 0x0001),
@@ -262,7 +262,7 @@ const struct x86_dev_info lenovo_yogabook_x90_info __initconst = {
.init = lenovo_yb1_x90_init,
};
-/* Lenovo Yoga Book X91F/L Windows tablet needs manual instantiation of the fg client */
+/* Lenovo Yoga Book X91F/L Windows tablet needs manual instantiation of the fuel-gauge client */
static const struct x86_i2c_client_info lenovo_yogabook_x91_i2c_clients[] __initconst = {
{
/* BQ27542 fuel-gauge */
@@ -281,7 +281,7 @@ const struct x86_dev_info lenovo_yogabook_x91_info __initconst = {
.i2c_client_count = ARRAY_SIZE(lenovo_yogabook_x91_i2c_clients),
};
-/* Lenovo Yoga Tablet 2 1050F/L's Android factory img has everything hardcoded */
+/* Lenovo Yoga Tablet 2 1050F/L's Android factory image has everything hardcoded */
static const struct property_entry lenovo_yoga_tab2_830_1050_bq24190_props[] = {
PROPERTY_ENTRY_STRING_ARRAY_LEN("supplied-from", tusb1211_chg_det_psy, 1),
PROPERTY_ENTRY_REF("monitored-battery", &generic_lipo_hv_4v35_battery_node),
@@ -521,9 +521,9 @@ err_put_device:
}
/*
- * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off
+ * These tablet's DSDT does not set acpi_gbl_reduced_hardware, so acpi_power_off()
* gets used as pm_power_off handler. This causes "poweroff" on these tablets
- * to hang hard. Requiring pressing the powerbutton for 30 seconds *twice*
+ * to hang hard. Requiring pressing the power button for 30 seconds *twice*
* followed by a normal 3 second press to recover. Avoid this by doing an EFI
* poweroff instead.
*/
@@ -546,7 +546,7 @@ static int __init lenovo_yoga_tab2_830_1050_init(struct device *dev)
if (ret)
return ret;
- /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+ /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off() */
lenovo_yoga_tab2_830_1050_sys_off_handler =
register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
lenovo_yoga_tab2_830_1050_power_off, NULL);
@@ -742,7 +742,7 @@ static int __init lenovo_yoga_tab2_1380_init(struct device *dev)
if (ret)
return ret;
- /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off */
+ /* SYS_OFF_PRIO_FIRMWARE + 1 so that it runs before acpi_power_off() */
lenovo_yoga_tab2_830_1050_sys_off_handler =
register_sys_off_handler(SYS_OFF_MODE_POWER_OFF, SYS_OFF_PRIO_FIRMWARE + 1,
lenovo_yoga_tab2_830_1050_power_off, NULL);
@@ -799,7 +799,7 @@ static const struct software_node fg_bq25890_1_supply_node = {
.properties = fg_bq25890_1_supply_props,
};
-/* bq25892 charger settings for the flat lipo battery behind the screen */
+/* bq25892 charger settings for the flat LiPo battery behind the screen */
static const struct property_entry lenovo_yt3_bq25892_0_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", lenovo_yt3_bq25892_0_suppliers),
PROPERTY_ENTRY_U32("linux,iinlim-percentage", 40),
@@ -833,7 +833,7 @@ static const struct software_node lenovo_yt3_hideep_ts_node = {
static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
{
- /* bq27500 fuel-gauge for the flat lipo battery behind the screen */
+ /* bq27500 fuel-gauge for the flat LiPo battery behind the screen */
.board_info = {
.type = "bq27500",
.addr = 0x55,
@@ -842,7 +842,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
},
.adapter_path = "\\_SB_.PCI0.I2C1",
}, {
- /* bq25892 charger for the flat lipo battery behind the screen */
+ /* bq25892 charger for the flat LiPo battery behind the screen */
.board_info = {
.type = "bq25892",
.addr = 0x6b,
@@ -859,7 +859,7 @@ static const struct x86_i2c_client_info lenovo_yt3_i2c_clients[] __initconst = {
.con_id = "bq25892_0_irq",
},
}, {
- /* bq27500 fuel-gauge for the round li-ion cells in the hinge */
+ /* bq27500 fuel-gauge for the round Li-ion cells in the hinge */
.board_info = {
.type = "bq27500",
.addr = 0x55,
diff --git a/drivers/platform/x86/x86-android-tablets/other.c b/drivers/platform/x86/x86-android-tablets/other.c
index eb0e55c69dfe..7db8aa58b907 100644
--- a/drivers/platform/x86/x86-android-tablets/other.c
+++ b/drivers/platform/x86/x86-android-tablets/other.c
@@ -20,7 +20,7 @@
#include "shared-psy-info.h"
#include "x86-android-tablets.h"
-/* Acer Iconia One 7 B1-750 has an Android factory img with everything hardcoded */
+/* Acer Iconia One 7 B1-750 has an Android factory image with everything hardcoded */
static const char * const acer_b1_750_mount_matrix[] = {
"-1", "0", "0",
"0", "1", "0",
@@ -98,7 +98,7 @@ const struct x86_dev_info acer_b1_750_info __initconst = {
* Advantech MICA-071
* This is a standard Windows tablet, but it has an extra "quick launch" button
* which is not described in the ACPI tables in anyway.
- * Use the x86-android-tablets infra to create a gpio-button device for this.
+ * Use the x86-android-tablets infra to create a gpio-keys device for this.
*/
static const struct x86_gpio_button advantech_mica_071_button __initconst = {
.button = {
@@ -209,7 +209,7 @@ const struct x86_dev_info chuwi_hi8_info __initconst = {
* This comes in both Windows and Android versions and even on Android
* the DSDT is mostly sane. This tablet has 2 extra general purpose buttons
* in the button row with the power + volume-buttons labeled P and F.
- * Use the x86-android-tablets infra to create a gpio-button device for these.
+ * Use the x86-android-tablets infra to create a gpio-keys device for these.
*/
static const struct x86_gpio_button cyberbook_t116_buttons[] __initconst = {
{
@@ -276,7 +276,7 @@ const struct x86_dev_info czc_p10t __initconst = {
.init = czc_p10t_init,
};
-/* Medion Lifetab S10346 tablets have an Android factory img with everything hardcoded */
+/* Medion Lifetab S10346 tablets have an Android factory image with everything hardcoded */
static const char * const medion_lifetab_s10346_accel_mount_matrix[] = {
"0", "1", "0",
"1", "0", "0",
@@ -305,7 +305,7 @@ static const struct software_node medion_lifetab_s10346_touchscreen_node = {
static const struct x86_i2c_client_info medion_lifetab_s10346_i2c_clients[] __initconst = {
{
- /* kxtj21009 accel */
+ /* kxtj21009 accelerometer */
.board_info = {
.type = "kxtj21009",
.addr = 0x0f,
@@ -359,7 +359,7 @@ const struct x86_dev_info medion_lifetab_s10346_info __initconst = {
.gpiod_lookup_tables = medion_lifetab_s10346_gpios,
};
-/* Nextbook Ares 8 (BYT) tablets have an Android factory img with everything hardcoded */
+/* Nextbook Ares 8 (BYT) tablets have an Android factory image with everything hardcoded */
static const char * const nextbook_ares8_accel_mount_matrix[] = {
"0", "-1", "0",
"-1", "0", "0",
@@ -387,7 +387,7 @@ static const struct software_node nextbook_ares8_touchscreen_node = {
static const struct x86_i2c_client_info nextbook_ares8_i2c_clients[] __initconst = {
{
- /* Freescale MMA8653FC accel */
+ /* Freescale MMA8653FC accelerometer */
.board_info = {
.type = "mma8653",
.addr = 0x1d,
@@ -428,7 +428,7 @@ const struct x86_dev_info nextbook_ares8_info __initconst = {
.gpiod_lookup_tables = nextbook_ares8_gpios,
};
-/* Nextbook Ares 8A (CHT) tablets have an Android factory img with everything hardcoded */
+/* Nextbook Ares 8A (CHT) tablets have an Android factory image with everything hardcoded */
static const char * const nextbook_ares8a_accel_mount_matrix[] = {
"1", "0", "0",
"0", "-1", "0",
@@ -446,7 +446,7 @@ static const struct software_node nextbook_ares8a_accel_node = {
static const struct x86_i2c_client_info nextbook_ares8a_i2c_clients[] __initconst = {
{
- /* Freescale MMA8653FC accel */
+ /* Freescale MMA8653FC accelerometer */
.board_info = {
.type = "mma8653",
.addr = 0x1d,
@@ -497,7 +497,7 @@ const struct x86_dev_info nextbook_ares8a_info __initconst = {
* Peaq C1010
* This is a standard Windows tablet, but it has a special Dolby button.
* This button has a WMI interface, but that is broken. Instead of trying to
- * use the broken WMI interface, instantiate a gpio_keys device for this.
+ * use the broken WMI interface, instantiate a gpio-keys device for this.
*/
static const struct x86_gpio_button peaq_c1010_button __initconst = {
.button = {
@@ -521,7 +521,7 @@ const struct x86_dev_info peaq_c1010_info __initconst = {
* Whitelabel (sold as various brands) TM800A550L tablets.
* These tablet's DSDT contains a whole bunch of bogus ACPI I2C devices
* (removed through acpi_quirk_skip_i2c_client_enumeration()) and
- * the touchscreen fwnode has the wrong GPIOs.
+ * the touchscreen firmware node has the wrong GPIOs.
*/
static const char * const whitelabel_tm800a550l_accel_mount_matrix[] = {
"-1", "0", "0",
@@ -566,7 +566,7 @@ static const struct x86_i2c_client_info whitelabel_tm800a550l_i2c_clients[] __in
.polarity = ACPI_ACTIVE_HIGH,
},
}, {
- /* kxcj91008 accel */
+ /* kxcj91008 accelerometer */
.board_info = {
.type = "kxcj91008",
.addr = 0x0f,
@@ -598,12 +598,12 @@ const struct x86_dev_info whitelabel_tm800a550l_info __initconst = {
};
/*
- * The fwnode for ktd2026 on Xaomi pad2. It composed of a RGB LED node
+ * The firmware node for ktd2026 on Xaomi pad2. It composed of a RGB LED node
* with three subnodes for each color (B/G/R). The RGB LED node is named
* "multi-led" to align with the name in the device tree.
*/
-/* main fwnode for ktd2026 */
+/* Main firmware node for ktd2026 */
static const struct software_node ktd2026_node = {
.name = "ktd2026",
};
@@ -665,12 +665,12 @@ static const struct software_node *ktd2026_node_group[] = {
};
/*
- * For the LEDs which backlight the menu / home / back capacitive buttons on
+ * For the LEDs which backlight the Menu / Home / Back capacitive buttons on
* the bottom bezel. These are attached to a TPS61158 LED controller which
* is controlled by the "pwm_soc_lpss_2" PWM output.
*/
#define XIAOMI_MIPAD2_LED_PERIOD_NS 19200
-#define XIAOMI_MIPAD2_LED_DEFAULT_DUTY 6000 /* From Android kernel */
+#define XIAOMI_MIPAD2_LED_MAX_DUTY_NS 6000 /* From Android kernel */
static struct pwm_device *xiaomi_mipad2_led_pwm;
@@ -679,7 +679,7 @@ static int xiaomi_mipad2_brightness_set(struct led_classdev *led_cdev,
{
struct pwm_state state = {
.period = XIAOMI_MIPAD2_LED_PERIOD_NS,
- .duty_cycle = val,
+ .duty_cycle = XIAOMI_MIPAD2_LED_MAX_DUTY_NS * val / LED_FULL,
/* Always set PWM enabled to avoid the pin floating */
.enabled = true,
};
@@ -701,11 +701,11 @@ static int __init xiaomi_mipad2_init(struct device *dev)
return -ENOMEM;
led_cdev->name = "mipad2:white:touch-buttons-backlight";
- led_cdev->max_brightness = XIAOMI_MIPAD2_LED_PERIOD_NS;
- /* "input-events" trigger uses blink_brightness */
- led_cdev->blink_brightness = XIAOMI_MIPAD2_LED_DEFAULT_DUTY;
+ led_cdev->max_brightness = LED_FULL;
led_cdev->default_trigger = "input-events";
led_cdev->brightness_set_blocking = xiaomi_mipad2_brightness_set;
+ /* Turn LED off during suspend */
+ led_cdev->flags = LED_CORE_SUSPENDRESUME;
ret = devm_led_classdev_register(dev, led_cdev);
if (ret)
diff --git a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c
index d2d0aa51bc3f..a46fa15acfb1 100644
--- a/drivers/platform/x86/x86-android-tablets/shared-psy-info.c
+++ b/drivers/platform/x86/x86-android-tablets/shared-psy-info.c
@@ -39,7 +39,7 @@ const struct software_node fg_bq25890_supply_node = {
.properties = fg_bq25890_supply_props,
};
-/* LiPo HighVoltage (max 4.35V) settings used by most devs with a HV bat. */
+/* LiPo HighVoltage (max 4.35V) settings used by most devs with a HV battery */
static const struct property_entry generic_lipo_hv_4v35_battery_props[] = {
PROPERTY_ENTRY_STRING("compatible", "simple-battery"),
PROPERTY_ENTRY_STRING("device-chemistry", "lithium-ion"),
@@ -80,7 +80,7 @@ const char * const bq24190_modules[] __initconst = {
NULL
};
-/* Generic pdevs array and gpio-lookups for micro USB ID pin handling */
+/* Generic platform device array and GPIO lookup table for micro USB ID pin handling */
const struct platform_device_info int3496_pdevs[] __initconst = {
{
/* For micro USB ID pin handling */
diff --git a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
index 86402b9b46a3..5517e438c7b6 100644
--- a/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
+++ b/drivers/platform/x86/x86-android-tablets/x86-android-tablets.h
@@ -61,7 +61,7 @@ struct x86_serdev_info {
const char *ctrl_uid;
const char *ctrl_devname;
/*
- * ATM the serdev core only supports of or ACPI matching; and sofar all
+ * ATM the serdev core only supports of or ACPI matching; and so far all
* Android x86 tablets DSDTs have usable serdev nodes, but sometimes
* under the wrong controller. So we just tie the existing serdev ACPI
* node to the right controller.