summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/Kconfig12
-rw-r--r--drivers/platform/chrome/Makefile4
-rw-r--r--drivers/platform/chrome/cros_ec.c15
-rw-r--r--drivers/platform/chrome/cros_ec_debugfs.c25
-rw-r--r--drivers/platform/chrome/cros_ec_lightbar.c14
-rw-r--r--drivers/platform/chrome/cros_ec_lpc.c12
-rw-r--r--drivers/platform/chrome/cros_ec_proto_test.c13
-rw-r--r--drivers/platform/chrome/cros_ec_sysfs.c40
-rw-r--r--drivers/platform/chrome/cros_ec_typec.c123
-rw-r--r--drivers/platform/chrome/cros_ec_typec.h85
-rw-r--r--drivers/platform/chrome/cros_ec_uart.c362
-rw-r--r--drivers/platform/chrome/cros_typec_switch.c16
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.c148
-rw-r--r--drivers/platform/chrome/cros_typec_vdm.h13
-rw-r--r--drivers/platform/chrome/wilco_ec/sysfs.c3
-rw-r--r--drivers/platform/mellanox/mlxreg-hotplug.c28
-rw-r--r--drivers/platform/surface/aggregator/bus.c10
-rw-r--r--drivers/platform/surface/aggregator/controller.c48
-rw-r--r--drivers/platform/surface/aggregator/ssh_msgb.h4
-rw-r--r--drivers/platform/surface/aggregator/ssh_request_layer.c15
-rw-r--r--drivers/platform/surface/aggregator/trace.h73
-rw-r--r--drivers/platform/surface/surface_acpi_notify.c2
-rw-r--r--drivers/platform/surface/surface_aggregator_cdev.c6
-rw-r--r--drivers/platform/surface/surface_aggregator_hub.c8
-rw-r--r--drivers/platform/surface/surface_aggregator_registry.c2
-rw-r--r--drivers/platform/surface/surface_aggregator_tabletsw.c12
-rw-r--r--drivers/platform/surface/surface_dtx.c20
-rw-r--r--drivers/platform/surface/surface_hotplug.c13
-rw-r--r--drivers/platform/surface/surface_platform_profile.c2
-rw-r--r--drivers/platform/x86/Kconfig1
-rw-r--r--drivers/platform/x86/acerhdf.c79
-rw-r--r--drivers/platform/x86/amd/Kconfig1
-rw-r--r--drivers/platform/x86/amd/pmc.c100
-rw-r--r--drivers/platform/x86/amd/pmf/Kconfig1
-rw-r--r--drivers/platform/x86/amd/pmf/auto-mode.c9
-rw-r--r--drivers/platform/x86/amd/pmf/cnqf.c14
-rw-r--r--drivers/platform/x86/amd/pmf/core.c32
-rw-r--r--drivers/platform/x86/amd/pmf/pmf.h3
-rw-r--r--drivers/platform/x86/amd/pmf/sps.c28
-rw-r--r--drivers/platform/x86/apple-gmux.c93
-rw-r--r--drivers/platform/x86/asus-nb-wmi.c15
-rw-r--r--drivers/platform/x86/asus-tf103c-dock.c4
-rw-r--r--drivers/platform/x86/asus-wmi.c24
-rw-r--r--drivers/platform/x86/asus-wmi.h1
-rw-r--r--drivers/platform/x86/dell/Kconfig8
-rw-r--r--drivers/platform/x86/dell/dell-smo8800.c5
-rw-r--r--drivers/platform/x86/dell/dell-wmi-base.c3
-rw-r--r--drivers/platform/x86/dell/dell-wmi-ddv.c528
-rw-r--r--drivers/platform/x86/dell/dell-wmi-privacy.c41
-rw-r--r--drivers/platform/x86/dell/dell-wmi-sysman/sysman.c2
-rw-r--r--drivers/platform/x86/gigabyte-wmi.c1
-rw-r--r--drivers/platform/x86/hp/hp-wmi.c8
-rw-r--r--drivers/platform/x86/ideapad-laptop.c6
-rw-r--r--drivers/platform/x86/intel/Kconfig13
-rw-r--r--drivers/platform/x86/intel/Makefile4
-rw-r--r--drivers/platform/x86/intel/int1092/intel_sar.c15
-rw-r--r--drivers/platform/x86/intel/int3472/Kconfig1
-rw-r--r--drivers/platform/x86/intel/int3472/Makefile2
-rw-r--r--drivers/platform/x86/intel/int3472/clk_and_regulator.c37
-rw-r--r--drivers/platform/x86/intel/int3472/common.h18
-rw-r--r--drivers/platform/x86/intel/int3472/discrete.c104
-rw-r--r--drivers/platform/x86/intel/int3472/led.c75
-rw-r--r--drivers/platform/x86/intel/oaktrail.c6
-rw-r--r--drivers/platform/x86/intel/pmc/core.c1
-rw-r--r--drivers/platform/x86/intel/pmc/tgl.c6
-rw-r--r--drivers/platform/x86/intel/punit_ipc.c6
-rw-r--r--drivers/platform/x86/intel/tpmi.c415
-rw-r--r--drivers/platform/x86/intel/vsec.c39
-rw-r--r--drivers/platform/x86/intel/vsec.h6
-rw-r--r--drivers/platform/x86/mlx-platform.c1246
-rw-r--r--drivers/platform/x86/nvidia-wmi-ec-backlight.c6
-rw-r--r--drivers/platform/x86/simatic-ipc.c3
-rw-r--r--drivers/platform/x86/sony-laptop.c21
-rw-r--r--drivers/platform/x86/think-lmi.c8
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c34
-rw-r--r--drivers/platform/x86/touchscreen_dmi.c34
-rw-r--r--drivers/platform/x86/uv_sysfs.c6
-rw-r--r--drivers/platform/x86/wmi.c15
-rw-r--r--drivers/platform/x86/x86-android-tablets.c2
79 files changed, 3580 insertions, 678 deletions
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index c1ca247987d2..7d82a0946e1c 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -119,6 +119,16 @@ config CROS_EC_SPI
response time cannot be guaranteed, we support ignoring
'pre-amble' bytes before the response actually starts.
+config CROS_EC_UART
+ tristate "ChromeOS Embedded Controller (UART)"
+ depends on CROS_EC && ACPI && SERIAL_DEV_BUS
+ help
+ If you say Y here, you get support for talking to the ChromeOS EC
+ through a UART, using a byte-level protocol.
+
+ To compile this driver as a module, choose M here: the
+ module will be called cros_ec_uart.
+
config CROS_EC_LPC
tristate "ChromeOS Embedded Controller (LPC)"
depends on CROS_EC && ACPI && (X86 || COMPILE_TEST)
@@ -226,7 +236,7 @@ config CROS_EC_TYPEC
information from the Chrome OS EC.
To compile this driver as a module, choose M here: the module will be
- called cros_ec_typec.
+ called cros-ec-typec.
config CROS_HPS_I2C
tristate "ChromeOS HPS device"
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index f6068d077a40..9e26e45c4a37 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -15,8 +15,10 @@ obj-$(CONFIG_CROS_EC_ISHTP) += cros_ec_ishtp.o
obj-$(CONFIG_CROS_TYPEC_SWITCH) += cros_typec_switch.o
obj-$(CONFIG_CROS_EC_RPMSG) += cros_ec_rpmsg.o
obj-$(CONFIG_CROS_EC_SPI) += cros_ec_spi.o
+obj-$(CONFIG_CROS_EC_UART) += cros_ec_uart.o
cros_ec_lpcs-objs := cros_ec_lpc.o cros_ec_lpc_mec.o
-obj-$(CONFIG_CROS_EC_TYPEC) += cros_ec_typec.o
+cros-ec-typec-objs := cros_ec_typec.o cros_typec_vdm.o
+obj-$(CONFIG_CROS_EC_TYPEC) += cros-ec-typec.o
obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpcs.o
obj-$(CONFIG_CROS_EC_PROTO) += cros_ec_proto.o cros_ec_trace.o
obj-$(CONFIG_CROS_KBD_LED_BACKLIGHT) += cros_kbd_led_backlight.o
diff --git a/drivers/platform/chrome/cros_ec.c b/drivers/platform/chrome/cros_ec.c
index ec733f683f34..b895c8130bba 100644
--- a/drivers/platform/chrome/cros_ec.c
+++ b/drivers/platform/chrome/cros_ec.c
@@ -182,6 +182,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
int err = 0;
BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->event_notifier);
+ BLOCKING_INIT_NOTIFIER_HEAD(&ec_dev->panic_notifier);
ec_dev->max_request = sizeof(struct ec_params_hello);
ec_dev->max_response = sizeof(struct ec_response_get_protocol_info);
@@ -198,12 +199,14 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (!ec_dev->dout)
return -ENOMEM;
+ lockdep_register_key(&ec_dev->lockdep_key);
mutex_init(&ec_dev->lock);
+ lockdep_set_class(&ec_dev->lock, &ec_dev->lockdep_key);
err = cros_ec_query_all(ec_dev);
if (err) {
dev_err(dev, "Cannot identify the EC: error %d\n", err);
- return err;
+ goto destroy_mutex;
}
if (ec_dev->irq > 0) {
@@ -215,7 +218,7 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (err) {
dev_err(dev, "Failed to request IRQ %d: %d\n",
ec_dev->irq, err);
- return err;
+ goto destroy_mutex;
}
}
@@ -226,7 +229,8 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
if (IS_ERR(ec_dev->ec)) {
dev_err(ec_dev->dev,
"Failed to create CrOS EC platform device\n");
- return PTR_ERR(ec_dev->ec);
+ err = PTR_ERR(ec_dev->ec);
+ goto destroy_mutex;
}
if (ec_dev->max_passthru) {
@@ -292,6 +296,9 @@ int cros_ec_register(struct cros_ec_device *ec_dev)
exit:
platform_device_unregister(ec_dev->ec);
platform_device_unregister(ec_dev->pd);
+destroy_mutex:
+ mutex_destroy(&ec_dev->lock);
+ lockdep_unregister_key(&ec_dev->lockdep_key);
return err;
}
EXPORT_SYMBOL(cros_ec_register);
@@ -309,6 +316,8 @@ void cros_ec_unregister(struct cros_ec_device *ec_dev)
if (ec_dev->pd)
platform_device_unregister(ec_dev->pd);
platform_device_unregister(ec_dev->ec);
+ mutex_destroy(&ec_dev->lock);
+ lockdep_unregister_key(&ec_dev->lockdep_key);
}
EXPORT_SYMBOL(cros_ec_unregister);
diff --git a/drivers/platform/chrome/cros_ec_debugfs.c b/drivers/platform/chrome/cros_ec_debugfs.c
index 21d973fc6be2..a98c529d8c69 100644
--- a/drivers/platform/chrome/cros_ec_debugfs.c
+++ b/drivers/platform/chrome/cros_ec_debugfs.c
@@ -38,6 +38,8 @@ static DECLARE_WAIT_QUEUE_HEAD(cros_ec_debugfs_log_wq);
* @log_mutex: mutex to protect circular buffer
* @log_poll_work: recurring task to poll EC for new console log data
* @panicinfo_blob: panicinfo debugfs blob
+ * @notifier_panic: notifier_block to let kernel to flush buffered log
+ * when EC panic
*/
struct cros_ec_debugfs {
struct cros_ec_dev *ec;
@@ -49,6 +51,7 @@ struct cros_ec_debugfs {
struct delayed_work log_poll_work;
/* EC panicinfo */
struct debugfs_blob_wrapper panicinfo_blob;
+ struct notifier_block notifier_panic;
};
/*
@@ -437,6 +440,22 @@ free:
return ret;
}
+static int cros_ec_debugfs_panic_event(struct notifier_block *nb,
+ unsigned long queued_during_suspend, void *_notify)
+{
+ struct cros_ec_debugfs *debug_info =
+ container_of(nb, struct cros_ec_debugfs, notifier_panic);
+
+ if (debug_info->log_buffer.buf) {
+ /* Force log poll work to run immediately */
+ mod_delayed_work(debug_info->log_poll_work.wq, &debug_info->log_poll_work, 0);
+ /* Block until log poll work finishes */
+ flush_delayed_work(&debug_info->log_poll_work);
+ }
+
+ return NOTIFY_DONE;
+}
+
static int cros_ec_debugfs_probe(struct platform_device *pd)
{
struct cros_ec_dev *ec = dev_get_drvdata(pd->dev.parent);
@@ -473,6 +492,12 @@ static int cros_ec_debugfs_probe(struct platform_device *pd)
debugfs_create_u16("suspend_timeout_ms", 0664, debug_info->dir,
&ec->ec_dev->suspend_timeout_ms);
+ debug_info->notifier_panic.notifier_call = cros_ec_debugfs_panic_event;
+ ret = blocking_notifier_chain_register(&ec->ec_dev->panic_notifier,
+ &debug_info->notifier_panic);
+ if (ret)
+ goto remove_debugfs;
+
ec->debug_info = debug_info;
dev_set_drvdata(&pd->dev, ec);
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c
index 1674105decfb..376425bbd8ff 100644
--- a/drivers/platform/chrome/cros_ec_lightbar.c
+++ b/drivers/platform/chrome/cros_ec_lightbar.c
@@ -34,7 +34,7 @@ static ssize_t interval_msec_show(struct device *dev,
{
unsigned long msec = lb_interval_jiffies * 1000 / HZ;
- return scnprintf(buf, PAGE_SIZE, "%lu\n", msec);
+ return sysfs_emit(buf, "%lu\n", msec);
}
static ssize_t interval_msec_store(struct device *dev,
@@ -169,7 +169,7 @@ static ssize_t version_show(struct device *dev,
if (!get_lightbar_version(ec, &version, &flags))
return -EIO;
- return scnprintf(buf, PAGE_SIZE, "%d %d\n", version, flags);
+ return sysfs_emit(buf, "%d %d\n", version, flags);
}
static ssize_t brightness_store(struct device *dev,
@@ -302,17 +302,15 @@ static ssize_t sequence_show(struct device *dev,
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- ret = scnprintf(buf, PAGE_SIZE, "XFER / EC ERROR %d / %d\n",
- ret, msg->result);
+ ret = sysfs_emit(buf, "XFER / EC ERROR %d / %d\n", ret, msg->result);
goto exit;
}
resp = (struct ec_response_lightbar *)msg->data;
if (resp->get_seq.num >= ARRAY_SIZE(seqname))
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num);
+ ret = sysfs_emit(buf, "%d\n", resp->get_seq.num);
else
- ret = scnprintf(buf, PAGE_SIZE, "%s\n",
- seqname[resp->get_seq.num]);
+ ret = sysfs_emit(buf, "%s\n", seqname[resp->get_seq.num]);
exit:
kfree(msg);
@@ -483,7 +481,7 @@ static ssize_t userspace_control_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%d\n", userspace_control);
+ return sysfs_emit(buf, "%d\n", userspace_control);
}
static ssize_t userspace_control_store(struct device *dev,
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c
index 7fc8f82280ac..68bba0fcafab 100644
--- a/drivers/platform/chrome/cros_ec_lpc.c
+++ b/drivers/platform/chrome/cros_ec_lpc.c
@@ -21,6 +21,7 @@
#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_device.h>
#include <linux/printk.h>
+#include <linux/reboot.h>
#include <linux/suspend.h>
#include "cros_ec.h"
@@ -320,6 +321,15 @@ static void cros_ec_lpc_acpi_notify(acpi_handle device, u32 value, void *data)
ec_dev->last_event_time = cros_ec_get_time_ns();
+ if (value == ACPI_NOTIFY_CROS_EC_PANIC) {
+ dev_emerg(ec_dev->dev, "CrOS EC Panic Reported. Shutdown is imminent!");
+ blocking_notifier_call_chain(&ec_dev->panic_notifier, 0, ec_dev);
+ /* Begin orderly shutdown. Force shutdown after 1 second. */
+ hw_protection_shutdown("CrOS EC Panic", 1000);
+ /* Do not query for other events after a panic is reported */
+ return;
+ }
+
if (ec_dev->mkbp_event_supported)
do {
ret = cros_ec_get_next_event(ec_dev, NULL,
@@ -340,7 +350,7 @@ static int cros_ec_lpc_probe(struct platform_device *pdev)
struct acpi_device *adev;
acpi_status status;
struct cros_ec_device *ec_dev;
- u8 buf[2];
+ u8 buf[2] = {};
int irq, ret;
/*
diff --git a/drivers/platform/chrome/cros_ec_proto_test.c b/drivers/platform/chrome/cros_ec_proto_test.c
index c6a83df91ae1..5b9748e0463b 100644
--- a/drivers/platform/chrome/cros_ec_proto_test.c
+++ b/drivers/platform/chrome/cros_ec_proto_test.c
@@ -5,7 +5,8 @@
#include <kunit/test.h>
-#include <asm-generic/unaligned.h>
+#include <asm/unaligned.h>
+
#include <linux/platform_data/cros_ec_commands.h>
#include <linux/platform_data/cros_ec_proto.h>
@@ -2370,7 +2371,7 @@ static void cros_ec_proto_test_get_host_event_normal(struct kunit *test)
static void cros_ec_proto_test_check_features_cached(struct kunit *test)
{
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec.features.flags[0] = EC_FEATURE_MASK_0(EC_FEATURE_FINGERPRINT);
ec.features.flags[1] = EC_FEATURE_MASK_0(EC_FEATURE_SCP);
@@ -2395,7 +2396,7 @@ static void cros_ec_proto_test_check_features_not_cached(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2448,7 +2449,7 @@ static void cros_ec_proto_test_get_sensor_count_normal(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2493,7 +2494,7 @@ static void cros_ec_proto_test_get_sensor_count_xfer_error(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
ec_dev->max_request = 0xff;
ec_dev->max_response = 0xee;
@@ -2533,7 +2534,7 @@ static void cros_ec_proto_test_get_sensor_count_legacy(struct kunit *test)
struct cros_ec_device *ec_dev = &priv->ec_dev;
struct ec_xfer_mock *mock;
int ret, i;
- struct cros_ec_dev ec;
+ static struct cros_ec_dev ec;
struct {
u8 readmem_data;
int expected_result;
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c
index f07eabcf9494..09e3bf5e8ec6 100644
--- a/drivers/platform/chrome/cros_ec_sysfs.c
+++ b/drivers/platform/chrome/cros_ec_sysfs.c
@@ -27,10 +27,9 @@ static ssize_t reboot_show(struct device *dev,
{
int count = 0;
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off");
- count += scnprintf(buf + count, PAGE_SIZE - count,
- " [at-shutdown]\n");
+ count += sysfs_emit_at(buf, count,
+ "ro|rw|cancel|cold|disable-jump|hibernate|cold-ap-off");
+ count += sysfs_emit_at(buf, count, " [at-shutdown]\n");
return count;
}
@@ -138,12 +137,9 @@ static ssize_t version_show(struct device *dev,
/* Strings should be null-terminated, but let's be sure. */
r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0';
r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "RO version: %s\n", r_ver->version_string_ro);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "RW version: %s\n", r_ver->version_string_rw);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Firmware copy: %s\n",
+ count += sysfs_emit_at(buf, count, "RO version: %s\n", r_ver->version_string_ro);
+ count += sysfs_emit_at(buf, count, "RW version: %s\n", r_ver->version_string_rw);
+ count += sysfs_emit_at(buf, count, "Firmware copy: %s\n",
(r_ver->current_image < ARRAY_SIZE(image_names) ?
image_names[r_ver->current_image] : "?"));
@@ -152,13 +148,12 @@ static ssize_t version_show(struct device *dev,
msg->insize = EC_HOST_PARAM_SIZE;
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Build info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
msg->data[EC_HOST_PARAM_SIZE - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Build info: %s\n", msg->data);
+ count += sysfs_emit_at(buf, count, "Build info: %s\n", msg->data);
}
/* Get chip info. */
@@ -166,7 +161,7 @@ static ssize_t version_show(struct device *dev,
msg->insize = sizeof(*r_chip);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Chip info: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
@@ -175,12 +170,9 @@ static ssize_t version_show(struct device *dev,
r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0';
r_chip->name[sizeof(r_chip->name) - 1] = '\0';
r_chip->revision[sizeof(r_chip->revision) - 1] = '\0';
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip vendor: %s\n", r_chip->vendor);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip name: %s\n", r_chip->name);
- count += scnprintf(buf + count, PAGE_SIZE - count,
- "Chip revision: %s\n", r_chip->revision);
+ count += sysfs_emit_at(buf, count, "Chip vendor: %s\n", r_chip->vendor);
+ count += sysfs_emit_at(buf, count, "Chip name: %s\n", r_chip->name);
+ count += sysfs_emit_at(buf, count, "Chip revision: %s\n", r_chip->revision);
}
/* Get board version */
@@ -188,13 +180,13 @@ static ssize_t version_show(struct device *dev,
msg->insize = sizeof(*r_board);
ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
if (ret < 0) {
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Board version: XFER / EC ERROR %d / %d\n",
ret, msg->result);
} else {
r_board = (struct ec_response_board_version *)msg->data;
- count += scnprintf(buf + count, PAGE_SIZE - count,
+ count += sysfs_emit_at(buf, count,
"Board version: %d\n",
r_board->board_version);
}
@@ -227,7 +219,7 @@ static ssize_t flashinfo_show(struct device *dev,
resp = (struct ec_response_flash_info *)msg->data;
- ret = scnprintf(buf, PAGE_SIZE,
+ ret = sysfs_emit(buf,
"FlashSize %d\nWriteSize %d\n"
"EraseSize %d\nProtectSize %d\n",
resp->flash_size, resp->write_block_size,
@@ -264,7 +256,7 @@ static ssize_t kb_wake_angle_show(struct device *dev,
goto exit;
resp = (struct ec_response_motion_sense *)msg->data;
- ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->kb_wake_angle.ret);
+ ret = sysfs_emit(buf, "%d\n", resp->kb_wake_angle.ret);
exit:
kfree(msg);
return ret;
diff --git a/drivers/platform/chrome/cros_ec_typec.c b/drivers/platform/chrome/cros_ec_typec.c
index 001b0de95a46..a673c3342470 100644
--- a/drivers/platform/chrome/cros_ec_typec.c
+++ b/drivers/platform/chrome/cros_ec_typec.c
@@ -7,92 +7,22 @@
*/
#include <linux/acpi.h>
-#include <linux/list.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_data/cros_ec_commands.h>
-#include <linux/platform_data/cros_ec_proto.h>
#include <linux/platform_data/cros_usbpd_notify.h>
#include <linux/platform_device.h>
-#include <linux/usb/pd.h>
#include <linux/usb/pd_vdo.h>
-#include <linux/usb/typec.h>
-#include <linux/usb/typec_altmode.h>
#include <linux/usb/typec_dp.h>
-#include <linux/usb/typec_mux.h>
-#include <linux/usb/typec_retimer.h>
#include <linux/usb/typec_tbt.h>
-#include <linux/usb/role.h>
+
+#include "cros_ec_typec.h"
+#include "cros_typec_vdm.h"
#define DRV_NAME "cros-ec-typec"
#define DP_PORT_VDO (DP_CONF_SET_PIN_ASSIGN(BIT(DP_PIN_ASSIGN_C) | BIT(DP_PIN_ASSIGN_D)) | \
- DP_CAP_DFP_D)
-
-/* Supported alt modes. */
-enum {
- CROS_EC_ALTMODE_DP = 0,
- CROS_EC_ALTMODE_TBT,
- CROS_EC_ALTMODE_MAX,
-};
-
-/* Container for altmode pointer nodes. */
-struct cros_typec_altmode_node {
- struct typec_altmode *amode;
- struct list_head list;
-};
-
-/* Per port data. */
-struct cros_typec_port {
- struct typec_port *port;
- /* Initial capabilities for the port. */
- struct typec_capability caps;
- struct typec_partner *partner;
- struct typec_cable *cable;
- /* SOP' plug. */
- struct typec_plug *plug;
- /* Port partner PD identity info. */
- struct usb_pd_identity p_identity;
- /* Port cable PD identity info. */
- struct usb_pd_identity c_identity;
- struct typec_switch *ori_sw;
- struct typec_mux *mux;
- struct typec_retimer *retimer;
- struct usb_role_switch *role_sw;
-
- /* Variables keeping track of switch state. */
- struct typec_mux_state state;
- uint8_t mux_flags;
- uint8_t role;
-
- struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
-
- /* Flag indicating that PD partner discovery data parsing is completed. */
- bool sop_disc_done;
- bool sop_prime_disc_done;
- struct ec_response_typec_discovery *disc_data;
- struct list_head partner_mode_list;
- struct list_head plug_mode_list;
-
- /* PDO-related structs */
- struct usb_power_delivery *partner_pd;
- struct usb_power_delivery_capabilities *partner_src_caps;
- struct usb_power_delivery_capabilities *partner_sink_caps;
-};
-
-/* Platform-specific data for the Chrome OS EC Type C controller. */
-struct cros_typec_data {
- struct device *dev;
- struct cros_ec_device *ec;
- int num_ports;
- unsigned int pd_ctrl_ver;
- /* Array of ports, indexed by port number. */
- struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
- struct notifier_block nb;
- struct work_struct port_work;
- bool typec_cmd_supported;
- bool needs_mux_ack;
-};
+ DP_CAP_DFP_D | DP_CAP_RECEPTACLE)
static int cros_typec_parse_port_props(struct typec_capability *cap,
struct fwnode_handle *fwnode,
@@ -145,27 +75,33 @@ static int cros_typec_get_switch_handles(struct cros_typec_port *port,
struct fwnode_handle *fwnode,
struct device *dev)
{
+ int ret = 0;
+
port->mux = fwnode_typec_mux_get(fwnode, NULL);
if (IS_ERR(port->mux)) {
- dev_dbg(dev, "Mux handle not found.\n");
+ ret = PTR_ERR(port->mux);
+ dev_dbg(dev, "Mux handle not found: %d.\n", ret);
goto mux_err;
}
port->retimer = fwnode_typec_retimer_get(fwnode);
if (IS_ERR(port->retimer)) {
- dev_dbg(dev, "Retimer handle not found.\n");
+ ret = PTR_ERR(port->retimer);
+ dev_dbg(dev, "Retimer handle not found: %d.\n", ret);
goto retimer_sw_err;
}
port->ori_sw = fwnode_typec_switch_get(fwnode);
if (IS_ERR(port->ori_sw)) {
- dev_dbg(dev, "Orientation switch handle not found.\n");
+ ret = PTR_ERR(port->ori_sw);
+ dev_dbg(dev, "Orientation switch handle not found: %d\n", ret);
goto ori_sw_err;
}
port->role_sw = fwnode_usb_role_switch_get(fwnode);
if (IS_ERR(port->role_sw)) {
- dev_dbg(dev, "USB role switch handle not found.\n");
+ ret = PTR_ERR(port->role_sw);
+ dev_dbg(dev, "USB role switch handle not found: %d\n", ret);
goto role_sw_err;
}
@@ -181,7 +117,7 @@ retimer_sw_err:
typec_mux_put(port->mux);
port->mux = NULL;
mux_err:
- return -ENODEV;
+ return ret;
}
static int cros_typec_add_partner(struct cros_typec_data *typec, int port_num,
@@ -342,6 +278,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_DP] = amode;
+ typec_altmode_set_drvdata(amode, port);
+ amode->ops = &port_amode_ops;
/*
* Register TBT compatibility alt mode. The EC will not enter the mode
@@ -355,6 +293,8 @@ static int cros_typec_register_port_altmodes(struct cros_typec_data *typec,
if (IS_ERR(amode))
return PTR_ERR(amode);
port->port_altmode[CROS_EC_ALTMODE_TBT] = amode;
+ typec_altmode_set_drvdata(amode, port);
+ amode->ops = &port_amode_ops;
port->state.alt = NULL;
port->state.mode = TYPEC_STATE_USB;
@@ -408,6 +348,8 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
goto unregister_ports;
}
+ cros_port->port_num = port_num;
+ cros_port->typec_data = typec;
typec->ports[port_num] = cros_port;
cap = &cros_port->caps;
@@ -423,9 +365,11 @@ static int cros_typec_init_ports(struct cros_typec_data *typec)
}
ret = cros_typec_get_switch_handles(cros_port, fwnode, dev);
- if (ret)
- dev_dbg(dev, "No switch control for port %d\n",
- port_num);
+ if (ret) {
+ dev_dbg(dev, "No switch control for port %d, err: %d\n", port_num, ret);
+ if (ret == -EPROBE_DEFER)
+ goto unregister_ports;
+ }
ret = cros_typec_register_port_altmodes(typec, port_num);
if (ret) {
@@ -1064,6 +1008,21 @@ static void cros_typec_handle_status(struct cros_typec_data *typec, int port_num
"Failed SOP Disc event clear, port: %d\n", port_num);
}
}
+
+ if (resp.events & PD_STATUS_EVENT_VDM_REQ_REPLY) {
+ cros_typec_handle_vdm_response(typec, port_num);
+ ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_REQ_REPLY);
+ if (ret < 0)
+ dev_warn(typec->dev, "Failed VDM Reply event clear, port: %d\n", port_num);
+ }
+
+ if (resp.events & PD_STATUS_EVENT_VDM_ATTENTION) {
+ cros_typec_handle_vdm_attention(typec, port_num);
+ ret = cros_typec_send_clear_event(typec, port_num, PD_STATUS_EVENT_VDM_ATTENTION);
+ if (ret < 0)
+ dev_warn(typec->dev, "Failed VDM attention event clear, port: %d\n",
+ port_num);
+ }
}
static int cros_typec_port_update(struct cros_typec_data *typec, int port_num)
diff --git a/drivers/platform/chrome/cros_ec_typec.h b/drivers/platform/chrome/cros_ec_typec.h
new file mode 100644
index 000000000000..deda180a646f
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_typec.h
@@ -0,0 +1,85 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __CROS_EC_TYPEC__
+#define __CROS_EC_TYPEC__
+
+#include <linux/list.h>
+#include <linux/notifier.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/usb/pd.h>
+#include <linux/usb/role.h>
+#include <linux/usb/typec.h>
+#include <linux/usb/typec_altmode.h>
+#include <linux/usb/typec_mux.h>
+#include <linux/usb/typec_retimer.h>
+#include <linux/workqueue.h>
+
+/* Supported alt modes. */
+enum {
+ CROS_EC_ALTMODE_DP = 0,
+ CROS_EC_ALTMODE_TBT,
+ CROS_EC_ALTMODE_MAX,
+};
+
+/* Container for altmode pointer nodes. */
+struct cros_typec_altmode_node {
+ struct typec_altmode *amode;
+ struct list_head list;
+};
+
+/* Platform-specific data for the Chrome OS EC Type C controller. */
+struct cros_typec_data {
+ struct device *dev;
+ struct cros_ec_device *ec;
+ int num_ports;
+ unsigned int pd_ctrl_ver;
+ /* Array of ports, indexed by port number. */
+ struct cros_typec_port *ports[EC_USB_PD_MAX_PORTS];
+ struct notifier_block nb;
+ struct work_struct port_work;
+ bool typec_cmd_supported;
+ bool needs_mux_ack;
+};
+
+/* Per port data. */
+struct cros_typec_port {
+ struct typec_port *port;
+ int port_num;
+ /* Initial capabilities for the port. */
+ struct typec_capability caps;
+ struct typec_partner *partner;
+ struct typec_cable *cable;
+ /* SOP' plug. */
+ struct typec_plug *plug;
+ /* Port partner PD identity info. */
+ struct usb_pd_identity p_identity;
+ /* Port cable PD identity info. */
+ struct usb_pd_identity c_identity;
+ struct typec_switch *ori_sw;
+ struct typec_mux *mux;
+ struct typec_retimer *retimer;
+ struct usb_role_switch *role_sw;
+
+ /* Variables keeping track of switch state. */
+ struct typec_mux_state state;
+ uint8_t mux_flags;
+ uint8_t role;
+
+ struct typec_altmode *port_altmode[CROS_EC_ALTMODE_MAX];
+
+ /* Flag indicating that PD partner discovery data parsing is completed. */
+ bool sop_disc_done;
+ bool sop_prime_disc_done;
+ struct ec_response_typec_discovery *disc_data;
+ struct list_head partner_mode_list;
+ struct list_head plug_mode_list;
+
+ /* PDO-related structs */
+ struct usb_power_delivery *partner_pd;
+ struct usb_power_delivery_capabilities *partner_src_caps;
+ struct usb_power_delivery_capabilities *partner_sink_caps;
+
+ struct cros_typec_data *typec_data;
+};
+
+#endif /* __CROS_EC_TYPEC__ */
diff --git a/drivers/platform/chrome/cros_ec_uart.c b/drivers/platform/chrome/cros_ec_uart.c
new file mode 100644
index 000000000000..788246559bbb
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_uart.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * UART interface for ChromeOS Embedded Controller
+ *
+ * Copyright 2020-2022 Google LLC.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/cros_ec_proto.h>
+#include <linux/serdev.h>
+#include <linux/slab.h>
+#include <uapi/linux/sched/types.h>
+
+#include "cros_ec.h"
+
+/*
+ * EC sends contiguous bytes of response packet on UART AP RX.
+ * TTY driver in AP accumulates incoming bytes and calls the registered callback
+ * function. Byte count can range from 1 to MAX bytes supported by EC.
+ * This driver should wait for long time for all callbacks to be processed.
+ * Considering the worst case scenario, wait for 500 msec. This timeout should
+ * account for max latency and some additional guard time.
+ * Best case: Entire packet is received in ~200 ms, wait queue will be released
+ * and packet will be processed.
+ * Worst case: TTY driver sends bytes in multiple callbacks. In this case this
+ * driver will wait for ~1 sec beyond which it will timeout.
+ * This timeout value should not exceed ~500 msec because in case if
+ * EC_CMD_REBOOT_EC sent, high level driver should be able to intercept EC
+ * in RO.
+ */
+#define EC_MSG_DEADLINE_MS 500
+
+/**
+ * struct response_info - Encapsulate EC response related
+ * information for passing between function
+ * cros_ec_uart_pkt_xfer() and cros_ec_uart_rx_bytes()
+ * callback.
+ * @data: Copy the data received from EC here.
+ * @max_size: Max size allocated for the @data buffer. If the
+ * received data exceeds this value, we log an error.
+ * @size: Actual size of data received from EC. This is also
+ * used to accumulate byte count with response is received
+ * in dma chunks.
+ * @exp_len: Expected bytes of response from EC including header.
+ * @status: Re-init to 0 before sending a cmd. Updated to 1 when
+ * a response is successfully received, or an error number
+ * on failure.
+ * @wait_queue: Wait queue EC response where the cros_ec sends request
+ * to EC and waits
+ */
+struct response_info {
+ void *data;
+ size_t max_size;
+ size_t size;
+ size_t exp_len;
+ int status;
+ wait_queue_head_t wait_queue;
+};
+
+/**
+ * struct cros_ec_uart - information about a uart-connected EC
+ *
+ * @serdev: serdev uart device we are connected to.
+ * @baudrate: UART baudrate of attached EC device.
+ * @flowcontrol: UART flowcontrol of attached device.
+ * @irq: Linux IRQ number of associated serial device.
+ * @response: Response info passing between cros_ec_uart_pkt_xfer()
+ * and cros_ec_uart_rx_bytes()
+ */
+struct cros_ec_uart {
+ struct serdev_device *serdev;
+ u32 baudrate;
+ u8 flowcontrol;
+ u32 irq;
+ struct response_info response;
+};
+
+static int cros_ec_uart_rx_bytes(struct serdev_device *serdev,
+ const u8 *data,
+ size_t count)
+{
+ struct ec_host_response *host_response;
+ struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);
+ struct cros_ec_uart *ec_uart = ec_dev->priv;
+ struct response_info *resp = &ec_uart->response;
+
+ /* Check if bytes were sent out of band */
+ if (!resp->data) {
+ /* Discard all bytes */
+ dev_warn(ec_dev->dev, "Bytes received out of band, dropping them.\n");
+ return count;
+ }
+
+ /*
+ * Check if incoming bytes + resp->size is greater than allocated
+ * buffer in din by cros_ec. This will ensure that if EC sends more
+ * bytes than max_size, waiting process will be notified with an error.
+ */
+ if (resp->size + count > resp->max_size) {
+ resp->status = -EMSGSIZE;
+ wake_up(&resp->wait_queue);
+ return count;
+ }
+
+ memcpy(resp->data + resp->size, data, count);
+
+ resp->size += count;
+
+ /* Read data_len if we received response header and if exp_len was not read before. */
+ if (resp->size >= sizeof(*host_response) && resp->exp_len == 0) {
+ host_response = (struct ec_host_response *)resp->data;
+ resp->exp_len = host_response->data_len + sizeof(*host_response);
+ }
+
+ /* If driver received response header and payload from EC, wake up the wait queue. */
+ if (resp->size >= sizeof(*host_response) && resp->size == resp->exp_len) {
+ resp->status = 1;
+ wake_up(&resp->wait_queue);
+ }
+
+ return count;
+}
+
+static int cros_ec_uart_pkt_xfer(struct cros_ec_device *ec_dev,
+ struct cros_ec_command *ec_msg)
+{
+ struct cros_ec_uart *ec_uart = ec_dev->priv;
+ struct serdev_device *serdev = ec_uart->serdev;
+ struct response_info *resp = &ec_uart->response;
+ struct ec_host_response *host_response;
+ unsigned int len;
+ int ret, i;
+ u8 sum;
+
+ len = cros_ec_prepare_tx(ec_dev, ec_msg);
+ dev_dbg(ec_dev->dev, "Prepared len=%d\n", len);
+
+ /* Setup for incoming response */
+ resp->data = ec_dev->din;
+ resp->max_size = ec_dev->din_size;
+ resp->size = 0;
+ resp->exp_len = 0;
+ resp->status = 0;
+
+ ret = serdev_device_write_buf(serdev, ec_dev->dout, len);
+ if (ret < 0 || ret < len) {
+ dev_err(ec_dev->dev, "Unable to write data\n");
+ if (ret >= 0)
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = wait_event_timeout(resp->wait_queue, resp->status,
+ msecs_to_jiffies(EC_MSG_DEADLINE_MS));
+ if (ret == 0) {
+ dev_warn(ec_dev->dev, "Timed out waiting for response.\n");
+ ret = -ETIMEDOUT;
+ goto exit;
+ }
+
+ if (resp->status < 0) {
+ ret = resp->status;
+ dev_warn(ec_dev->dev, "Error response received: %d\n", ret);
+ goto exit;
+ }
+
+ host_response = (struct ec_host_response *)ec_dev->din;
+ ec_msg->result = host_response->result;
+
+ if (host_response->data_len > ec_msg->insize) {
+ dev_err(ec_dev->dev, "Resp too long (%d bytes, expected %d)\n",
+ host_response->data_len, ec_msg->insize);
+ ret = -ENOSPC;
+ goto exit;
+ }
+
+ /* Validate checksum */
+ sum = 0;
+ for (i = 0; i < sizeof(*host_response) + host_response->data_len; i++)
+ sum += ec_dev->din[i];
+
+ if (sum) {
+ dev_err(ec_dev->dev, "Bad packet checksum calculated %x\n", sum);
+ ret = -EBADMSG;
+ goto exit;
+ }
+
+ memcpy(ec_msg->data, ec_dev->din + sizeof(*host_response), host_response->data_len);
+
+ ret = host_response->data_len;
+
+exit:
+ /* Invalidate response buffer to guard against out of band rx data */
+ resp->data = NULL;
+
+ if (ec_msg->command == EC_CMD_REBOOT_EC)
+ msleep(EC_REBOOT_DELAY_MS);
+
+ return ret;
+}
+
+static int cros_ec_uart_resource(struct acpi_resource *ares, void *data)
+{
+ struct cros_ec_uart *ec_uart = data;
+ struct acpi_resource_uart_serialbus *sb = &ares->data.uart_serial_bus;
+
+ if (ares->type == ACPI_RESOURCE_TYPE_SERIAL_BUS &&
+ sb->type == ACPI_RESOURCE_SERIAL_TYPE_UART) {
+ ec_uart->baudrate = sb->default_baud_rate;
+ dev_dbg(&ec_uart->serdev->dev, "Baudrate %d\n", ec_uart->baudrate);
+
+ ec_uart->flowcontrol = sb->flow_control;
+ dev_dbg(&ec_uart->serdev->dev, "Flow control %d\n", ec_uart->flowcontrol);
+ }
+
+ return 0;
+}
+
+static int cros_ec_uart_acpi_probe(struct cros_ec_uart *ec_uart)
+{
+ int ret;
+ LIST_HEAD(resources);
+ struct acpi_device *adev = ACPI_COMPANION(&ec_uart->serdev->dev);
+
+ ret = acpi_dev_get_resources(adev, &resources, cros_ec_uart_resource, ec_uart);
+ if (ret < 0)
+ return ret;
+
+ acpi_dev_free_resource_list(&resources);
+
+ /* Retrieve GpioInt and translate it to Linux IRQ number */
+ ret = acpi_dev_gpio_irq_get(adev, 0);
+ if (ret < 0)
+ return ret;
+
+ ec_uart->irq = ret;
+ dev_dbg(&ec_uart->serdev->dev, "IRQ number %d\n", ec_uart->irq);
+
+ return 0;
+}
+
+static const struct serdev_device_ops cros_ec_uart_client_ops = {
+ .receive_buf = cros_ec_uart_rx_bytes,
+};
+
+static int cros_ec_uart_probe(struct serdev_device *serdev)
+{
+ struct device *dev = &serdev->dev;
+ struct cros_ec_device *ec_dev;
+ struct cros_ec_uart *ec_uart;
+ int ret;
+
+ ec_uart = devm_kzalloc(dev, sizeof(*ec_uart), GFP_KERNEL);
+ if (!ec_uart)
+ return -ENOMEM;
+
+ ec_dev = devm_kzalloc(dev, sizeof(*ec_dev), GFP_KERNEL);
+ if (!ec_dev)
+ return -ENOMEM;
+
+ ret = devm_serdev_device_open(dev, serdev);
+ if (ret) {
+ dev_err(dev, "Unable to open UART device");
+ return ret;
+ }
+
+ serdev_device_set_drvdata(serdev, ec_dev);
+ init_waitqueue_head(&ec_uart->response.wait_queue);
+
+ ec_uart->serdev = serdev;
+
+ ret = cros_ec_uart_acpi_probe(ec_uart);
+ if (ret < 0) {
+ dev_err(dev, "Failed to get ACPI info (%d)", ret);
+ return ret;
+ }
+
+ ret = serdev_device_set_baudrate(serdev, ec_uart->baudrate);
+ if (ret < 0) {
+ dev_err(dev, "Failed to set up host baud rate (%d)", ret);
+ return ret;
+ }
+
+ serdev_device_set_flow_control(serdev, ec_uart->flowcontrol);
+
+ /* Initialize ec_dev for cros_ec */
+ ec_dev->phys_name = dev_name(dev);
+ ec_dev->dev = dev;
+ ec_dev->priv = ec_uart;
+ ec_dev->irq = ec_uart->irq;
+ ec_dev->cmd_xfer = NULL;
+ ec_dev->pkt_xfer = cros_ec_uart_pkt_xfer;
+ ec_dev->din_size = sizeof(struct ec_host_response) +
+ sizeof(struct ec_response_get_protocol_info);
+ ec_dev->dout_size = sizeof(struct ec_host_request);
+
+ serdev_device_set_client_ops(serdev, &cros_ec_uart_client_ops);
+
+ return cros_ec_register(ec_dev);
+}
+
+static void cros_ec_uart_remove(struct serdev_device *serdev)
+{
+ struct cros_ec_device *ec_dev = serdev_device_get_drvdata(serdev);
+
+ cros_ec_unregister(ec_dev);
+};
+
+static int __maybe_unused cros_ec_uart_suspend(struct device *dev)
+{
+ struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
+
+ return cros_ec_suspend(ec_dev);
+}
+
+static int __maybe_unused cros_ec_uart_resume(struct device *dev)
+{
+ struct cros_ec_device *ec_dev = dev_get_drvdata(dev);
+
+ return cros_ec_resume(ec_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(cros_ec_uart_pm_ops, cros_ec_uart_suspend,
+ cros_ec_uart_resume);
+
+static const struct of_device_id cros_ec_uart_of_match[] = {
+ { .compatible = "google,cros-ec-uart" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, cros_ec_uart_of_match);
+
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cros_ec_uart_acpi_id[] = {
+ { "GOOG0019", 0 },
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, cros_ec_uart_acpi_id);
+#endif
+
+static struct serdev_device_driver cros_ec_uart_driver = {
+ .driver = {
+ .name = "cros-ec-uart",
+ .acpi_match_table = ACPI_PTR(cros_ec_uart_acpi_id),
+ .of_match_table = cros_ec_uart_of_match,
+ .pm = &cros_ec_uart_pm_ops,
+ },
+ .probe = cros_ec_uart_probe,
+ .remove = cros_ec_uart_remove,
+};
+
+module_serdev_device_driver(cros_ec_uart_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("UART interface for ChromeOS Embedded Controller");
+MODULE_AUTHOR("Bhanu Prakash Maiya <bhanumaiya@chromium.org>");
diff --git a/drivers/platform/chrome/cros_typec_switch.c b/drivers/platform/chrome/cros_typec_switch.c
index a26219e97c93..9ed1605f4071 100644
--- a/drivers/platform/chrome/cros_typec_switch.c
+++ b/drivers/platform/chrome/cros_typec_switch.c
@@ -246,15 +246,17 @@ static int cros_typec_register_switches(struct cros_typec_switch_data *sdata)
port->port_num = index;
sdata->ports[index] = port;
- ret = cros_typec_register_retimer(port, fwnode);
- if (ret) {
- dev_err(dev, "Retimer switch register failed\n");
- goto err_switch;
+ if (fwnode_property_present(fwnode, "retimer-switch")) {
+ ret = cros_typec_register_retimer(port, fwnode);
+ if (ret) {
+ dev_err(dev, "Retimer switch register failed\n");
+ goto err_switch;
+ }
+
+ dev_dbg(dev, "Retimer switch registered for index %llu\n", index);
}
- dev_dbg(dev, "Retimer switch registered for index %llu\n", index);
-
- if (!device_property_present(fwnode->dev, "mode-switch"))
+ if (!fwnode_property_present(fwnode, "mode-switch"))
continue;
ret = cros_typec_register_mode_switch(port, fwnode);
diff --git a/drivers/platform/chrome/cros_typec_vdm.c b/drivers/platform/chrome/cros_typec_vdm.c
new file mode 100644
index 000000000000..20515ee0a20e
--- /dev/null
+++ b/drivers/platform/chrome/cros_typec_vdm.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * USB Power Delivery Vendor Defined Message (VDM) support code.
+ *
+ * Copyright 2023 Google LLC
+ * Author: Prashant Malani <pmalani@chromium.org>
+ */
+
+#include <linux/module.h>
+#include <linux/platform_data/cros_ec_commands.h>
+#include <linux/usb/pd_vdo.h>
+
+#include "cros_ec_typec.h"
+#include "cros_typec_vdm.h"
+
+/*
+ * Retrieves pending VDM attention messages from the EC and forwards them to the altmode driver
+ * based on SVID.
+ */
+void cros_typec_handle_vdm_attention(struct cros_typec_data *typec, int port_num)
+{
+ struct ec_response_typec_vdm_response resp;
+ struct ec_params_typec_vdm_response req = {
+ .port = port_num,
+ };
+ struct typec_altmode *amode;
+ u16 svid;
+ u32 hdr;
+ int ret;
+
+ do {
+ ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_VDM_RESPONSE, &req,
+ sizeof(req), &resp, sizeof(resp));
+ if (ret < 0) {
+ dev_warn(typec->dev, "Failed VDM response fetch, port: %d\n", port_num);
+ return;
+ }
+
+ hdr = resp.vdm_response[0];
+ svid = PD_VDO_VID(hdr);
+ dev_dbg(typec->dev, "Received VDM Attention header: %x, port: %d\n", hdr, port_num);
+
+ amode = typec_match_altmode(typec->ports[port_num]->port_altmode,
+ CROS_EC_ALTMODE_MAX, svid, PD_VDO_OPOS(hdr));
+ if (!amode) {
+ dev_err(typec->dev,
+ "Received VDM for unregistered altmode (SVID:%x), port: %d\n",
+ svid, port_num);
+ return;
+ }
+
+ typec_altmode_attention(amode, resp.vdm_attention[1]);
+ } while (resp.vdm_attention_left);
+}
+
+/*
+ * Retrieves a VDM response from the EC and forwards it to the altmode driver based on SVID.
+ */
+void cros_typec_handle_vdm_response(struct cros_typec_data *typec, int port_num)
+{
+ struct ec_response_typec_vdm_response resp;
+ struct ec_params_typec_vdm_response req = {
+ .port = port_num,
+ };
+ struct typec_altmode *amode;
+ u16 svid;
+ u32 hdr;
+ int ret;
+
+ ret = cros_ec_cmd(typec->ec, 0, EC_CMD_TYPEC_VDM_RESPONSE, &req,
+ sizeof(req), &resp, sizeof(resp));
+ if (ret < 0) {
+ dev_warn(typec->dev, "Failed VDM response fetch, port: %d\n", port_num);
+ return;
+ }
+
+ hdr = resp.vdm_response[0];
+ svid = PD_VDO_VID(hdr);
+ dev_dbg(typec->dev, "Received VDM header: %x, port: %d\n", hdr, port_num);
+
+ amode = typec_match_altmode(typec->ports[port_num]->port_altmode, CROS_EC_ALTMODE_MAX,
+ svid, PD_VDO_OPOS(hdr));
+ if (!amode) {
+ dev_err(typec->dev, "Received VDM for unregistered altmode (SVID:%x), port: %d\n",
+ svid, port_num);
+ return;
+ }
+
+ ret = typec_altmode_vdm(amode, hdr, &resp.vdm_response[1], resp.vdm_data_objects);
+ if (ret)
+ dev_err(typec->dev, "Failed to forward VDM to altmode (SVID:%x), port: %d\n",
+ svid, port_num);
+}
+
+static int cros_typec_port_amode_enter(struct typec_altmode *amode, u32 *vdo)
+{
+ struct cros_typec_port *port = typec_altmode_get_drvdata(amode);
+ struct ec_params_typec_control req = {
+ .port = port->port_num,
+ .command = TYPEC_CONTROL_COMMAND_SEND_VDM_REQ,
+ };
+ struct typec_vdm_req vdm_req = {};
+ u32 hdr;
+
+ hdr = VDO(amode->svid, 1, SVDM_VER_2_0, CMD_ENTER_MODE);
+ hdr |= VDO_OPOS(amode->mode);
+
+ vdm_req.vdm_data[0] = hdr;
+ vdm_req.vdm_data_objects = 1;
+ vdm_req.partner_type = TYPEC_PARTNER_SOP;
+ req.vdm_req_params = vdm_req;
+
+ dev_dbg(port->typec_data->dev, "Sending EnterMode VDM, hdr: %x, port: %d\n",
+ hdr, port->port_num);
+
+ return cros_ec_cmd(port->typec_data->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
+ sizeof(req), NULL, 0);
+}
+
+static int cros_typec_port_amode_vdm(struct typec_altmode *amode, const u32 hdr,
+ const u32 *vdo, int cnt)
+{
+ struct cros_typec_port *port = typec_altmode_get_drvdata(amode);
+ struct ec_params_typec_control req = {
+ .port = port->port_num,
+ .command = TYPEC_CONTROL_COMMAND_SEND_VDM_REQ,
+ };
+ struct typec_vdm_req vdm_req = {};
+ int i;
+
+ vdm_req.vdm_data[0] = hdr;
+ vdm_req.vdm_data_objects = cnt;
+ for (i = 1; i < cnt; i++)
+ vdm_req.vdm_data[i] = vdo[i-1];
+ vdm_req.partner_type = TYPEC_PARTNER_SOP;
+ req.vdm_req_params = vdm_req;
+
+ dev_dbg(port->typec_data->dev, "Sending VDM, hdr: %x, num_objects: %d, port: %d\n",
+ hdr, cnt, port->port_num);
+
+ return cros_ec_cmd(port->typec_data->ec, 0, EC_CMD_TYPEC_CONTROL, &req,
+ sizeof(req), NULL, 0);
+}
+
+struct typec_altmode_ops port_amode_ops = {
+ .enter = cros_typec_port_amode_enter,
+ .vdm = cros_typec_port_amode_vdm,
+};
diff --git a/drivers/platform/chrome/cros_typec_vdm.h b/drivers/platform/chrome/cros_typec_vdm.h
new file mode 100644
index 000000000000..95a6a75d32b6
--- /dev/null
+++ b/drivers/platform/chrome/cros_typec_vdm.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __CROS_TYPEC_VDM__
+#define __CROS_TYPEC_VDM__
+
+#include <linux/usb/typec_altmode.h>
+
+extern struct typec_altmode_ops port_amode_ops;
+
+void cros_typec_handle_vdm_attention(struct cros_typec_data *typec, int port_num);
+void cros_typec_handle_vdm_response(struct cros_typec_data *typec, int port_num);
+
+#endif /* __CROS_TYPEC_VDM__ */
diff --git a/drivers/platform/chrome/wilco_ec/sysfs.c b/drivers/platform/chrome/wilco_ec/sysfs.c
index 79a5e8fa680f..893c59dde32a 100644
--- a/drivers/platform/chrome/wilco_ec/sysfs.c
+++ b/drivers/platform/chrome/wilco_ec/sysfs.c
@@ -119,8 +119,7 @@ static ssize_t get_info(struct device *dev, char *buf, enum get_ec_info_op op)
if (ret < 0)
return ret;
- return scnprintf(buf, PAGE_SIZE, "%.*s\n", (int)sizeof(resp.value),
- (char *)&resp.value);
+ return sysfs_emit(buf, "%.*s\n", (int)sizeof(resp.value), (char *)&resp.value);
}
static ssize_t version_show(struct device *dev, struct device_attribute *attr,
diff --git a/drivers/platform/mellanox/mlxreg-hotplug.c b/drivers/platform/mellanox/mlxreg-hotplug.c
index 117bc3f395fd..b7dcc64cd238 100644
--- a/drivers/platform/mellanox/mlxreg-hotplug.c
+++ b/drivers/platform/mellanox/mlxreg-hotplug.c
@@ -239,6 +239,17 @@ static ssize_t mlxreg_hotplug_attr_show(struct device *dev,
#define PRIV_ATTR(i) priv->mlxreg_hotplug_attr[i]
#define PRIV_DEV_ATTR(i) priv->mlxreg_hotplug_dev_attr[i]
+static int mlxreg_hotplug_item_label_index_get(u32 mask, u32 bit)
+{
+ int i, j;
+
+ for (i = 0, j = -1; i <= bit; i++) {
+ if (mask & BIT(i))
+ j++;
+ }
+ return j;
+}
+
static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
{
struct mlxreg_core_hotplug_platform_data *pdata;
@@ -246,7 +257,7 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
struct mlxreg_core_data *data;
unsigned long mask;
u32 regval;
- int num_attrs = 0, id = 0, i, j, k, ret;
+ int num_attrs = 0, id = 0, i, j, k, count, ret;
pdata = dev_get_platdata(&priv->pdev->dev);
item = pdata->items;
@@ -272,7 +283,8 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
/* Go over all unmasked units within item. */
mask = item->mask;
k = 0;
- for_each_set_bit(j, &mask, item->count) {
+ count = item->ind ? item->ind : item->count;
+ for_each_set_bit(j, &mask, count) {
if (data->capability) {
/*
* Read capability register and skip non
@@ -282,16 +294,17 @@ static int mlxreg_hotplug_attr_init(struct mlxreg_hotplug_priv_data *priv)
data->capability, &regval);
if (ret)
return ret;
+
if (!(regval & data->bit)) {
data++;
continue;
}
}
+
PRIV_ATTR(id) = &PRIV_DEV_ATTR(id).dev_attr.attr;
PRIV_ATTR(id)->name = devm_kasprintf(&priv->pdev->dev,
GFP_KERNEL,
data->label);
-
if (!PRIV_ATTR(id)->name) {
dev_err(priv->dev, "Memory allocation failed for attr %d.\n",
id);
@@ -365,9 +378,14 @@ mlxreg_hotplug_work_helper(struct mlxreg_hotplug_priv_data *priv,
regval &= item->mask;
asserted = item->cache ^ regval;
item->cache = regval;
-
for_each_set_bit(bit, &asserted, 8) {
- data = item->data + bit;
+ int pos;
+
+ pos = mlxreg_hotplug_item_label_index_get(item->mask, bit);
+ if (pos < 0)
+ goto out;
+
+ data = item->data + pos;
if (regval & BIT(bit)) {
if (item->inversed)
mlxreg_hotplug_device_destroy(priv, data, item->kind);
diff --git a/drivers/platform/surface/aggregator/bus.c b/drivers/platform/surface/aggregator/bus.c
index de539938896e..aaad41294200 100644
--- a/drivers/platform/surface/aggregator/bus.c
+++ b/drivers/platform/surface/aggregator/bus.c
@@ -35,9 +35,9 @@ static struct attribute *ssam_device_attrs[] = {
};
ATTRIBUTE_GROUPS(ssam_device);
-static int ssam_device_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int ssam_device_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct ssam_device *sdev = to_ssam_device(dev);
+ const struct ssam_device *sdev = to_ssam_device(dev);
return add_uevent_var(env, "MODALIAS=ssam:d%02Xc%02Xt%02Xi%02Xf%02X",
sdev->uid.domain, sdev->uid.category,
@@ -136,9 +136,9 @@ int ssam_device_add(struct ssam_device *sdev)
* is always valid and can be used for requests as long as the client
* device we add here is registered as child under it. This essentially
* guarantees that the client driver can always expect the preconditions
- * for functions like ssam_request_sync (controller has to be started
- * and is not suspended) to hold and thus does not have to check for
- * them.
+ * for functions like ssam_request_do_sync() (controller has to be
+ * started and is not suspended) to hold and thus does not have to check
+ * for them.
*
* Note that for this to work, the controller has to be a parent device.
* If it is not a direct parent, care has to be taken that the device is
diff --git a/drivers/platform/surface/aggregator/controller.c b/drivers/platform/surface/aggregator/controller.c
index 43e765199137..535581c0471c 100644
--- a/drivers/platform/surface/aggregator/controller.c
+++ b/drivers/platform/surface/aggregator/controller.c
@@ -994,7 +994,7 @@ static void ssam_handle_event(struct ssh_rtl *rtl,
item->rqid = get_unaligned_le16(&cmd->rqid);
item->event.target_category = cmd->tc;
- item->event.target_id = cmd->tid_in;
+ item->event.target_id = cmd->sid;
item->event.command_id = cmd->cid;
item->event.instance_id = cmd->iid;
memcpy(&item->event.data[0], data->ptr, data->len);
@@ -1674,7 +1674,7 @@ int ssam_request_sync_submit(struct ssam_controller *ctrl,
EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
/**
- * ssam_request_sync() - Execute a synchronous request.
+ * ssam_request_do_sync() - Execute a synchronous request.
* @ctrl: The controller via which the request will be submitted.
* @spec: The request specification and payload.
* @rsp: The response buffer.
@@ -1686,9 +1686,9 @@ EXPORT_SYMBOL_GPL(ssam_request_sync_submit);
*
* Return: Returns the status of the request or any failure during setup.
*/
-int ssam_request_sync(struct ssam_controller *ctrl,
- const struct ssam_request *spec,
- struct ssam_response *rsp)
+int ssam_request_do_sync(struct ssam_controller *ctrl,
+ const struct ssam_request *spec,
+ struct ssam_response *rsp)
{
struct ssam_request_sync *rqst;
struct ssam_span buf;
@@ -1700,8 +1700,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
return status;
status = ssam_request_sync_init(rqst, spec->flags);
- if (status)
+ if (status) {
+ ssam_request_sync_free(rqst);
return status;
+ }
ssam_request_sync_set_resp(rqst, rsp);
@@ -1720,10 +1722,10 @@ int ssam_request_sync(struct ssam_controller *ctrl,
ssam_request_sync_free(rqst);
return status;
}
-EXPORT_SYMBOL_GPL(ssam_request_sync);
+EXPORT_SYMBOL_GPL(ssam_request_do_sync);
/**
- * ssam_request_sync_with_buffer() - Execute a synchronous request with the
+ * ssam_request_do_sync_with_buffer() - Execute a synchronous request with the
* provided buffer as back-end for the message buffer.
* @ctrl: The controller via which the request will be submitted.
* @spec: The request specification and payload.
@@ -1736,17 +1738,17 @@ EXPORT_SYMBOL_GPL(ssam_request_sync);
* SSH_COMMAND_MESSAGE_LENGTH() macro can be used to compute the required
* message buffer size.
*
- * This function does essentially the same as ssam_request_sync(), but instead
- * of dynamically allocating the request and message data buffer, it uses the
- * provided message data buffer and stores the (small) request struct on the
- * heap.
+ * This function does essentially the same as ssam_request_do_sync(), but
+ * instead of dynamically allocating the request and message data buffer, it
+ * uses the provided message data buffer and stores the (small) request struct
+ * on the heap.
*
* Return: Returns the status of the request or any failure during setup.
*/
-int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
- const struct ssam_request *spec,
- struct ssam_response *rsp,
- struct ssam_span *buf)
+int ssam_request_do_sync_with_buffer(struct ssam_controller *ctrl,
+ const struct ssam_request *spec,
+ struct ssam_response *rsp,
+ struct ssam_span *buf)
{
struct ssam_request_sync rqst;
ssize_t len;
@@ -1770,42 +1772,42 @@ int ssam_request_sync_with_buffer(struct ssam_controller *ctrl,
return status;
}
-EXPORT_SYMBOL_GPL(ssam_request_sync_with_buffer);
+EXPORT_SYMBOL_GPL(ssam_request_do_sync_with_buffer);
/* -- Internal SAM requests. ------------------------------------------------ */
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_get_firmware_version, __le32, {
.target_category = SSAM_SSH_TC_SAM,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x13,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_off, u8, {
.target_category = SSAM_SSH_TC_SAM,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x15,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_display_on, u8, {
.target_category = SSAM_SSH_TC_SAM,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x16,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_exit, u8, {
.target_category = SSAM_SSH_TC_SAM,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x33,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_ssh_notif_d0_entry, u8, {
.target_category = SSAM_SSH_TC_SAM,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x34,
.instance_id = 0x00,
});
@@ -1862,7 +1864,7 @@ static int __ssam_ssh_event_request(struct ssam_controller *ctrl,
result.length = 0;
result.pointer = &buf;
- status = ssam_retry(ssam_request_sync_onstack, ctrl, &rqst, &result,
+ status = ssam_retry(ssam_request_do_sync_onstack, ctrl, &rqst, &result,
sizeof(params));
return status < 0 ? status : buf;
diff --git a/drivers/platform/surface/aggregator/ssh_msgb.h b/drivers/platform/surface/aggregator/ssh_msgb.h
index f3ecad92eefd..438873e06098 100644
--- a/drivers/platform/surface/aggregator/ssh_msgb.h
+++ b/drivers/platform/surface/aggregator/ssh_msgb.h
@@ -189,8 +189,8 @@ static inline void msgb_push_cmd(struct msgbuf *msgb, u8 seq, u16 rqid,
__msgb_push_u8(msgb, SSH_PLD_TYPE_CMD); /* Payload type. */
__msgb_push_u8(msgb, rqst->target_category); /* Target category. */
- __msgb_push_u8(msgb, rqst->target_id); /* Target ID (out). */
- __msgb_push_u8(msgb, 0x00); /* Target ID (in). */
+ __msgb_push_u8(msgb, rqst->target_id); /* Target ID. */
+ __msgb_push_u8(msgb, SSAM_SSH_TID_HOST); /* Source ID. */
__msgb_push_u8(msgb, rqst->instance_id); /* Instance ID. */
__msgb_push_u16(msgb, rqid); /* Request ID. */
__msgb_push_u8(msgb, rqst->command_id); /* Command ID. */
diff --git a/drivers/platform/surface/aggregator/ssh_request_layer.c b/drivers/platform/surface/aggregator/ssh_request_layer.c
index f5565570f16c..90634dcacabf 100644
--- a/drivers/platform/surface/aggregator/ssh_request_layer.c
+++ b/drivers/platform/surface/aggregator/ssh_request_layer.c
@@ -916,6 +916,21 @@ static void ssh_rtl_rx_command(struct ssh_ptl *p, const struct ssam_span *data)
if (sshp_parse_command(dev, data, &command, &command_data))
return;
+ /*
+ * Check if the message was intended for us. If not, drop it.
+ *
+ * Note: We will need to change this to handle debug messages. On newer
+ * generation devices, these seem to be sent to SSAM_SSH_TID_DEBUG. We
+ * as host can still receive them as they can be forwarded via an
+ * override option on SAM, but doing so does not change the target ID
+ * to SSAM_SSH_TID_HOST.
+ */
+ if (command->tid != SSAM_SSH_TID_HOST) {
+ rtl_warn(rtl, "rtl: dropping message not intended for us (tid = %#04x)\n",
+ command->tid);
+ return;
+ }
+
if (ssh_rqid_is_event(get_unaligned_le16(&command->rqid)))
ssh_rtl_rx_event(rtl, command, &command_data);
else
diff --git a/drivers/platform/surface/aggregator/trace.h b/drivers/platform/surface/aggregator/trace.h
index 2a2c17771d01..55cc61bba1da 100644
--- a/drivers/platform/surface/aggregator/trace.h
+++ b/drivers/platform/surface/aggregator/trace.h
@@ -96,6 +96,7 @@ TRACE_DEFINE_ENUM(SSAM_SSH_TC_POS);
#define SSAM_SEQ_NOT_APPLICABLE ((u16)-1)
#define SSAM_RQID_NOT_APPLICABLE ((u32)-1)
#define SSAM_SSH_TC_NOT_APPLICABLE 0
+#define SSAM_SSH_TID_NOT_APPLICABLE ((u8)-1)
#ifndef _SURFACE_AGGREGATOR_TRACE_HELPERS
#define _SURFACE_AGGREGATOR_TRACE_HELPERS
@@ -151,11 +152,43 @@ static inline u32 ssam_trace_get_request_id(const struct ssh_packet *p)
}
/**
+ * ssam_trace_get_request_tid() - Read the packet's request target ID.
+ * @p: The packet.
+ *
+ * Return: Returns the packet's request target ID (TID) field if the packet
+ * represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
+ * if not (e.g. flush request, control packet).
+ */
+static inline u32 ssam_trace_get_request_tid(const struct ssh_packet *p)
+{
+ if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
+ return SSAM_SSH_TID_NOT_APPLICABLE;
+
+ return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(tid)]);
+}
+
+/**
+ * ssam_trace_get_request_sid() - Read the packet's request source ID.
+ * @p: The packet.
+ *
+ * Return: Returns the packet's request source ID (SID) field if the packet
+ * represents a request with command data, or %SSAM_SSH_TID_NOT_APPLICABLE
+ * if not (e.g. flush request, control packet).
+ */
+static inline u32 ssam_trace_get_request_sid(const struct ssh_packet *p)
+{
+ if (!p->data.ptr || p->data.len < SSH_COMMAND_MESSAGE_LENGTH(0))
+ return SSAM_SSH_TID_NOT_APPLICABLE;
+
+ return get_unaligned_le16(&p->data.ptr[SSH_MSGOFFSET_COMMAND(sid)]);
+}
+
+/**
* ssam_trace_get_request_tc() - Read the packet's request target category.
* @p: The packet.
*
* Return: Returns the packet's request target category (TC) field if the
- * packet represents a request with command data, or %SSAM_TC_NOT_APPLICABLE
+ * packet represents a request with command data, or %SSAM_SSH_TC_NOT_APPLICABLE
* if not (e.g. flush request, control packet).
*/
static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
@@ -232,8 +265,18 @@ static inline u32 ssam_trace_get_request_tc(const struct ssh_packet *p)
{ SSAM_RQID_NOT_APPLICABLE, "N/A" } \
)
-#define ssam_show_ssh_tc(rqid) \
- __print_symbolic(rqid, \
+#define ssam_show_ssh_tid(tid) \
+ __print_symbolic(tid, \
+ { SSAM_SSH_TID_NOT_APPLICABLE, "N/A" }, \
+ { SSAM_SSH_TID_HOST, "Host" }, \
+ { SSAM_SSH_TID_SAM, "SAM" }, \
+ { SSAM_SSH_TID_KIP, "KIP" }, \
+ { SSAM_SSH_TID_DEBUG, "Debug" }, \
+ { SSAM_SSH_TID_SURFLINK, "SurfLink" } \
+ )
+
+#define ssam_show_ssh_tc(tc) \
+ __print_symbolic(tc, \
{ SSAM_SSH_TC_NOT_APPLICABLE, "N/A" }, \
{ SSAM_SSH_TC_SAM, "SAM" }, \
{ SSAM_SSH_TC_BAT, "BAT" }, \
@@ -313,6 +356,8 @@ DECLARE_EVENT_CLASS(ssam_command_class,
TP_STRUCT__entry(
__field(u16, rqid)
__field(u16, len)
+ __field(u8, tid)
+ __field(u8, sid)
__field(u8, tc)
__field(u8, cid)
__field(u8, iid)
@@ -320,14 +365,18 @@ DECLARE_EVENT_CLASS(ssam_command_class,
TP_fast_assign(
__entry->rqid = get_unaligned_le16(&cmd->rqid);
+ __entry->tid = cmd->tid;
+ __entry->sid = cmd->sid;
__entry->tc = cmd->tc;
__entry->cid = cmd->cid;
__entry->iid = cmd->iid;
__entry->len = len;
),
- TP_printk("rqid=%#06x, tc=%s, cid=%#04x, iid=%#04x, len=%u",
+ TP_printk("rqid=%#06x, tid=%s, sid=%s, tc=%s, cid=%#04x, iid=%#04x, len=%u",
__entry->rqid,
+ ssam_show_ssh_tid(__entry->tid),
+ ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
__entry->cid,
__entry->iid,
@@ -430,6 +479,8 @@ DECLARE_EVENT_CLASS(ssam_request_class,
__field(u8, tc)
__field(u16, cid)
__field(u16, iid)
+ __field(u8, tid)
+ __field(u8, sid)
),
TP_fast_assign(
@@ -439,16 +490,20 @@ DECLARE_EVENT_CLASS(ssam_request_class,
__entry->state = READ_ONCE(request->state);
__entry->rqid = ssam_trace_get_request_id(p);
ssam_trace_ptr_uid(p, __entry->uid);
+ __entry->tid = ssam_trace_get_request_tid(p);
+ __entry->sid = ssam_trace_get_request_sid(p);
__entry->tc = ssam_trace_get_request_tc(p);
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
),
- TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s",
+ TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s",
__entry->uid,
ssam_show_request_id(__entry->rqid),
ssam_show_request_type(__entry->state),
ssam_show_request_state(__entry->state),
+ ssam_show_ssh_tid(__entry->tid),
+ ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
ssam_show_generic_u8_field(__entry->cid),
ssam_show_generic_u8_field(__entry->iid)
@@ -474,6 +529,8 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
__field(u8, tc)
__field(u16, cid)
__field(u16, iid)
+ __field(u8, tid)
+ __field(u8, sid)
),
TP_fast_assign(
@@ -484,16 +541,20 @@ DECLARE_EVENT_CLASS(ssam_request_status_class,
__entry->rqid = ssam_trace_get_request_id(p);
__entry->status = status;
ssam_trace_ptr_uid(p, __entry->uid);
+ __entry->tid = ssam_trace_get_request_tid(p);
+ __entry->sid = ssam_trace_get_request_sid(p);
__entry->tc = ssam_trace_get_request_tc(p);
__entry->cid = ssam_trace_get_command_field_u8(p, cid);
__entry->iid = ssam_trace_get_command_field_u8(p, iid);
),
- TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tc=%s, cid=%s, iid=%s, status=%d",
+ TP_printk("uid=%s, rqid=%s, ty=%s, sta=%s, tid=%s, sid=%s, tc=%s, cid=%s, iid=%s, status=%d",
__entry->uid,
ssam_show_request_id(__entry->rqid),
ssam_show_request_type(__entry->state),
ssam_show_request_state(__entry->state),
+ ssam_show_ssh_tid(__entry->tid),
+ ssam_show_ssh_tid(__entry->sid),
ssam_show_ssh_tc(__entry->tc),
ssam_show_generic_u8_field(__entry->cid),
ssam_show_generic_u8_field(__entry->iid),
diff --git a/drivers/platform/surface/surface_acpi_notify.c b/drivers/platform/surface/surface_acpi_notify.c
index 50500e562963..897cdd9c3aae 100644
--- a/drivers/platform/surface/surface_acpi_notify.c
+++ b/drivers/platform/surface/surface_acpi_notify.c
@@ -590,7 +590,7 @@ static acpi_status san_rqst(struct san_data *d, struct gsb_buffer *buffer)
return san_rqst_fixup_suspended(d, &rqst, buffer);
}
- status = __ssam_retry(ssam_request_sync_onstack, SAN_REQUEST_NUM_TRIES,
+ status = __ssam_retry(ssam_request_do_sync_onstack, SAN_REQUEST_NUM_TRIES,
d->ctrl, &rqst, &rsp, SAN_GSB_MAX_RQSX_PAYLOAD);
if (!status) {
diff --git a/drivers/platform/surface/surface_aggregator_cdev.c b/drivers/platform/surface/surface_aggregator_cdev.c
index 492c82e69182..07f0ed658369 100644
--- a/drivers/platform/surface/surface_aggregator_cdev.c
+++ b/drivers/platform/surface/surface_aggregator_cdev.c
@@ -302,8 +302,8 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
* theoretical maximum (SSH_COMMAND_MAX_PAYLOAD_SIZE) of the
* underlying protocol (note that nothing remotely this size
* should ever be allocated in any normal case). This size is
- * validated later in ssam_request_sync(), for allocation the
- * bound imposed by u16 should be enough.
+ * validated later in ssam_request_do_sync(), for allocation
+ * the bound imposed by u16 should be enough.
*/
spec.payload = kzalloc(spec.length, GFP_KERNEL);
if (!spec.payload) {
@@ -342,7 +342,7 @@ static long ssam_cdev_request(struct ssam_cdev_client *client, struct ssam_cdev_
}
/* Perform request. */
- status = ssam_request_sync(client->cdev->ctrl, &spec, &rsp);
+ status = ssam_request_do_sync(client->cdev->ctrl, &spec, &rsp);
if (status)
goto out;
diff --git a/drivers/platform/surface/surface_aggregator_hub.c b/drivers/platform/surface/surface_aggregator_hub.c
index 43061514be38..8b8b80228c14 100644
--- a/drivers/platform/surface/surface_aggregator_hub.c
+++ b/drivers/platform/surface/surface_aggregator_hub.c
@@ -214,7 +214,7 @@ static void ssam_hub_remove(struct ssam_device *sdev)
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_query_opmode, u8, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0d,
.instance_id = 0x00,
});
@@ -292,7 +292,7 @@ static const struct ssam_hub_desc base_hub = {
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_query_state, u8, {
.target_category = SSAM_SSH_TC_KIP,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x2c,
.instance_id = 0x00,
});
@@ -348,8 +348,8 @@ static const struct ssam_hub_desc kip_hub = {
/* -- Driver registration. -------------------------------------------------- */
static const struct ssam_device_id ssam_hub_match[] = {
- { SSAM_VDEV(HUB, 0x01, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
- { SSAM_VDEV(HUB, 0x02, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
+ { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_KIP, 0x00), (unsigned long)&kip_hub },
+ { SSAM_VDEV(HUB, SAM, SSAM_SSH_TC_BAS, 0x00), (unsigned long)&base_hub },
{ }
};
MODULE_DEVICE_TABLE(ssam, ssam_hub_match);
diff --git a/drivers/platform/surface/surface_aggregator_registry.c b/drivers/platform/surface/surface_aggregator_registry.c
index 023f126121d7..296f72d52e6a 100644
--- a/drivers/platform/surface/surface_aggregator_registry.c
+++ b/drivers/platform/surface/surface_aggregator_registry.c
@@ -46,7 +46,7 @@ static const struct software_node ssam_node_hub_kip = {
/* Base device hub (devices attached to Surface Book 3 base). */
static const struct software_node ssam_node_hub_base = {
- .name = "ssam:00:00:02:11:00",
+ .name = "ssam:00:00:01:11:00",
.parent = &ssam_node_root,
};
diff --git a/drivers/platform/surface/surface_aggregator_tabletsw.c b/drivers/platform/surface/surface_aggregator_tabletsw.c
index 27d95a6a7851..9fed800c7cc0 100644
--- a/drivers/platform/surface/surface_aggregator_tabletsw.c
+++ b/drivers/platform/surface/surface_aggregator_tabletsw.c
@@ -247,7 +247,7 @@ static bool ssam_kip_cover_state_is_tablet_mode(struct ssam_tablet_sw *sw, u32 s
SSAM_DEFINE_SYNC_REQUEST_R(__ssam_kip_get_cover_state, u8, {
.target_category = SSAM_SSH_TC_KIP,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x1d,
.instance_id = 0x00,
});
@@ -371,7 +371,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
int status;
rqst.target_category = SSAM_SSH_TC_POS;
- rqst.target_id = 0x01;
+ rqst.target_id = SSAM_SSH_TID_SAM;
rqst.command_id = 0x01;
rqst.instance_id = 0x00;
rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
@@ -382,7 +382,7 @@ static int ssam_pos_get_sources_list(struct ssam_tablet_sw *sw, struct ssam_sour
rsp.length = 0;
rsp.pointer = (u8 *)sources;
- status = ssam_retry(ssam_request_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
+ status = ssam_retry(ssam_request_do_sync_onstack, sw->sdev->ctrl, &rqst, &rsp, 0);
if (status)
return status;
@@ -430,7 +430,7 @@ static int ssam_pos_get_source(struct ssam_tablet_sw *sw, u32 *source_id)
SSAM_DEFINE_SYNC_REQUEST_WR(__ssam_pos_get_posture_for_source, __le32, __le32, {
.target_category = SSAM_SSH_TC_POS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x02,
.instance_id = 0x00,
});
@@ -510,8 +510,8 @@ static const struct ssam_tablet_sw_desc ssam_pos_sw_desc = {
/* -- Driver registration. -------------------------------------------------- */
static const struct ssam_device_id ssam_tablet_sw_match[] = {
- { SSAM_SDEV(KIP, 0x01, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
- { SSAM_SDEV(POS, 0x01, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
+ { SSAM_SDEV(KIP, SAM, 0x00, 0x01), (unsigned long)&ssam_kip_sw_desc },
+ { SSAM_SDEV(POS, SAM, 0x00, 0x01), (unsigned long)&ssam_pos_sw_desc },
{ },
};
MODULE_DEVICE_TABLE(ssam, ssam_tablet_sw_match);
diff --git a/drivers/platform/surface/surface_dtx.c b/drivers/platform/surface/surface_dtx.c
index ed36944467f9..30cbde278c59 100644
--- a/drivers/platform/surface/surface_dtx.c
+++ b/drivers/platform/surface/surface_dtx.c
@@ -71,63 +71,63 @@ static_assert(sizeof(struct ssam_bas_base_info) == 2);
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_lock, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x06,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_unlock, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x07,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_request, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x08,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_confirm, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x09,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_heartbeat, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0a,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_N(ssam_bas_latch_cancel, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0b,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_base, struct ssam_bas_base_info, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0c,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_device_mode, u8, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x0d,
.instance_id = 0x00,
});
SSAM_DEFINE_SYNC_REQUEST_R(ssam_bas_get_latch_status, u8, {
.target_category = SSAM_SSH_TC_BAS,
- .target_id = 0x01,
+ .target_id = SSAM_SSH_TID_SAM,
.command_id = 0x11,
.instance_id = 0x00,
});
@@ -1214,7 +1214,7 @@ static void surface_dtx_ssam_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id surface_dtx_ssam_match[] = {
- { SSAM_SDEV(BAS, 0x01, 0x00, 0x00) },
+ { SSAM_SDEV(BAS, SAM, 0x00, 0x00) },
{ },
};
MODULE_DEVICE_TABLE(ssam, surface_dtx_ssam_match);
diff --git a/drivers/platform/surface/surface_hotplug.c b/drivers/platform/surface/surface_hotplug.c
index f004a2495201..7b6d887dccdb 100644
--- a/drivers/platform/surface/surface_hotplug.c
+++ b/drivers/platform/surface/surface_hotplug.c
@@ -101,18 +101,12 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
param.type = ACPI_TYPE_INTEGER;
param.integer.value = value;
- result = acpi_evaluate_dsm(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
- shps_dsm_fn_for_irq(type), &param);
-
+ result = acpi_evaluate_dsm_typed(handle, &shps_dsm_guid, SHPS_DSM_REVISION,
+ shps_dsm_fn_for_irq(type), &param, ACPI_TYPE_BUFFER);
if (!result) {
dev_err(&pdev->dev, "IRQ notification via DSM failed (irq=%d, gpio=%d)\n",
type, value);
- } else if (result->type != ACPI_TYPE_BUFFER) {
- dev_err(&pdev->dev,
- "IRQ notification via DSM failed: unexpected result type (irq=%d, gpio=%d)\n",
- type, value);
-
} else if (result->buffer.length != 1 || result->buffer.pointer[0] != 0) {
dev_err(&pdev->dev,
"IRQ notification via DSM failed: unexpected result value (irq=%d, gpio=%d)\n",
@@ -121,8 +115,7 @@ static void shps_dsm_notify_irq(struct platform_device *pdev, enum shps_irq_type
mutex_unlock(&sdev->lock[type]);
- if (result)
- ACPI_FREE(result);
+ ACPI_FREE(result);
}
static irqreturn_t shps_handle_irq(int irq, void *data)
diff --git a/drivers/platform/surface/surface_platform_profile.c b/drivers/platform/surface/surface_platform_profile.c
index fbf2e11fd6ce..f433a13c3689 100644
--- a/drivers/platform/surface/surface_platform_profile.c
+++ b/drivers/platform/surface/surface_platform_profile.c
@@ -169,7 +169,7 @@ static void surface_platform_profile_remove(struct ssam_device *sdev)
}
static const struct ssam_device_id ssam_platform_profile_match[] = {
- { SSAM_SDEV(TMP, 0x01, 0x00, 0x01) },
+ { SSAM_SDEV(TMP, SAM, 0x00, 0x01) },
{ },
};
MODULE_DEVICE_TABLE(ssam, ssam_platform_profile_match);
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 5692385e2d26..ec7c2b4e1721 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -214,7 +214,6 @@ config APPLE_GMUX
depends on PNP
depends on BACKLIGHT_CLASS_DEVICE
depends on BACKLIGHT_APPLE=n || BACKLIGHT_APPLE
- depends on ACPI_VIDEO=n || ACPI_VIDEO
help
This driver provides support for the gmux device found on many
Apple laptops, which controls the display mux for the hybrid
diff --git a/drivers/platform/x86/acerhdf.c b/drivers/platform/x86/acerhdf.c
index d2c0fc38c201..a48638ad2a8a 100644
--- a/drivers/platform/x86/acerhdf.c
+++ b/drivers/platform/x86/acerhdf.c
@@ -46,6 +46,8 @@
* measured by the on-die thermal monitor are within 0 <= Tj <= 90. So,
* assume 89°C is critical temperature.
*/
+#define ACERHDF_DEFAULT_TEMP_FANON 60000
+#define ACERHDF_DEFAULT_TEMP_FANOFF 53000
#define ACERHDF_TEMP_CRIT 89000
#define ACERHDF_FAN_OFF 0
#define ACERHDF_FAN_AUTO 1
@@ -70,8 +72,8 @@ static int kernelmode;
#endif
static unsigned int interval = 10;
-static unsigned int fanon = 60000;
-static unsigned int fanoff = 53000;
+static unsigned int fanon = ACERHDF_DEFAULT_TEMP_FANON;
+static unsigned int fanoff = ACERHDF_DEFAULT_TEMP_FANOFF;
static unsigned int verbose;
static unsigned int list_supported;
static unsigned int fanstate = ACERHDF_FAN_AUTO;
@@ -137,6 +139,15 @@ struct ctrl_settings {
int mcmd_enable;
};
+static struct thermal_trip trips[] = {
+ [0] = { .temperature = ACERHDF_DEFAULT_TEMP_FANON,
+ .hysteresis = ACERHDF_DEFAULT_TEMP_FANON - ACERHDF_DEFAULT_TEMP_FANOFF,
+ .type = THERMAL_TRIP_ACTIVE },
+
+ [1] = { .temperature = ACERHDF_TEMP_CRIT,
+ .type = THERMAL_TRIP_CRITICAL }
+};
+
static struct ctrl_settings ctrl_cfg __read_mostly;
/* Register addresses and values for different BIOS versions */
@@ -326,6 +337,15 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
fanon = ACERHDF_MAX_FANON;
}
+ if (fanon < fanoff) {
+ pr_err("fanoff temperature (%d) is above fanon temperature (%d), clamping to %d\n",
+ fanoff, fanon, fanon);
+ fanoff = fanon;
+ };
+
+ trips[0].temperature = fanon;
+ trips[0].hysteresis = fanon - fanoff;
+
if (kernelmode && prev_interval != interval) {
if (interval > ACERHDF_MAX_INTERVAL) {
pr_err("interval too high, set to %d\n",
@@ -424,43 +444,6 @@ static int acerhdf_change_mode(struct thermal_zone_device *thermal,
return 0;
}
-static int acerhdf_get_trip_type(struct thermal_zone_device *thermal, int trip,
- enum thermal_trip_type *type)
-{
- if (trip == 0)
- *type = THERMAL_TRIP_ACTIVE;
- else if (trip == 1)
- *type = THERMAL_TRIP_CRITICAL;
- else
- return -EINVAL;
-
- return 0;
-}
-
-static int acerhdf_get_trip_hyst(struct thermal_zone_device *thermal, int trip,
- int *temp)
-{
- if (trip != 0)
- return -EINVAL;
-
- *temp = fanon - fanoff;
-
- return 0;
-}
-
-static int acerhdf_get_trip_temp(struct thermal_zone_device *thermal, int trip,
- int *temp)
-{
- if (trip == 0)
- *temp = fanon;
- else if (trip == 1)
- *temp = ACERHDF_TEMP_CRIT;
- else
- return -EINVAL;
-
- return 0;
-}
-
static int acerhdf_get_crit_temp(struct thermal_zone_device *thermal,
int *temperature)
{
@@ -474,13 +457,9 @@ static struct thermal_zone_device_ops acerhdf_dev_ops = {
.unbind = acerhdf_unbind,
.get_temp = acerhdf_get_ec_temp,
.change_mode = acerhdf_change_mode,
- .get_trip_type = acerhdf_get_trip_type,
- .get_trip_hyst = acerhdf_get_trip_hyst,
- .get_trip_temp = acerhdf_get_trip_temp,
.get_crit_temp = acerhdf_get_crit_temp,
};
-
/*
* cooling device callback functions
* get maximal fan cooling state
@@ -565,11 +544,6 @@ static int acerhdf_probe(struct platform_device *device)
return 0;
}
-static int acerhdf_remove(struct platform_device *device)
-{
- return 0;
-}
-
static const struct dev_pm_ops acerhdf_pm_ops = {
.suspend = acerhdf_suspend,
.freeze = acerhdf_suspend,
@@ -581,7 +555,6 @@ static struct platform_driver acerhdf_driver = {
.pm = &acerhdf_pm_ops,
},
.probe = acerhdf_probe,
- .remove = acerhdf_remove,
};
/* check hardware */
@@ -710,10 +683,10 @@ static int __init acerhdf_register_thermal(void)
if (IS_ERR(cl_dev))
return -EINVAL;
- thz_dev = thermal_zone_device_register("acerhdf", 2, 0, NULL,
- &acerhdf_dev_ops,
- &acerhdf_zone_params, 0,
- (kernelmode) ? interval*1000 : 0);
+ thz_dev = thermal_zone_device_register_with_trips("acerhdf", trips, ARRAY_SIZE(trips),
+ 0, NULL, &acerhdf_dev_ops,
+ &acerhdf_zone_params, 0,
+ (kernelmode) ? interval*1000 : 0);
if (IS_ERR(thz_dev))
return -EINVAL;
diff --git a/drivers/platform/x86/amd/Kconfig b/drivers/platform/x86/amd/Kconfig
index a825af8126c8..2ce8cb2170df 100644
--- a/drivers/platform/x86/amd/Kconfig
+++ b/drivers/platform/x86/amd/Kconfig
@@ -8,6 +8,7 @@ source "drivers/platform/x86/amd/pmf/Kconfig"
config AMD_PMC
tristate "AMD SoC PMC driver"
depends on ACPI && PCI && RTC_CLASS
+ select SERIO
help
The driver provides support for AMD Power Management Controller
primarily responsible for S2Idle transactions that are driven from
diff --git a/drivers/platform/x86/amd/pmc.c b/drivers/platform/x86/amd/pmc.c
index 439d282aafd1..ab05b9ee6655 100644
--- a/drivers/platform/x86/amd/pmc.c
+++ b/drivers/platform/x86/amd/pmc.c
@@ -22,6 +22,7 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/serio.h>
#include <linux/suspend.h>
#include <linux/seq_file.h>
#include <linux/uaccess.h>
@@ -42,6 +43,7 @@
#define AMD_PMC_STB_S2IDLE_PREPARE 0xC6000001
#define AMD_PMC_STB_S2IDLE_RESTORE 0xC6000002
#define AMD_PMC_STB_S2IDLE_CHECK 0xC6000003
+#define AMD_PMC_STB_DUMMY_PC 0xC6000007
/* STB S2D(Spill to DRAM) has different message port offset */
#define STB_SPILL_TO_DRAM 0xBE
@@ -103,6 +105,7 @@
#define DELAY_MIN_US 2000
#define DELAY_MAX_US 3000
#define FIFO_SIZE 4096
+
enum amd_pmc_def {
MSG_TEST = 0x01,
MSG_OS_HINT_PCO,
@@ -113,6 +116,7 @@ enum s2d_arg {
S2D_TELEMETRY_SIZE = 0x01,
S2D_PHYS_ADDR_LOW,
S2D_PHYS_ADDR_HIGH,
+ S2D_NUM_SAMPLES,
};
struct amd_pmc_bit_map {
@@ -160,6 +164,10 @@ static bool enable_stb;
module_param(enable_stb, bool, 0644);
MODULE_PARM_DESC(enable_stb, "Enable the STB debug mechanism");
+static bool disable_workarounds;
+module_param(disable_workarounds, bool, 0644);
+MODULE_PARM_DESC(disable_workarounds, "Disable workarounds for platform bugs");
+
static struct amd_pmc_dev pmc;
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret);
static int amd_pmc_read_stb(struct amd_pmc_dev *dev, u32 *buf);
@@ -241,13 +249,40 @@ static const struct file_operations amd_pmc_stb_debugfs_fops = {
static int amd_pmc_stb_debugfs_open_v2(struct inode *inode, struct file *filp)
{
struct amd_pmc_dev *dev = filp->f_inode->i_private;
- u32 *buf;
+ u32 *buf, fsize, num_samples, stb_rdptr_offset = 0;
+ int ret;
+
+ /* Write dummy postcode while reading the STB buffer */
+ ret = amd_pmc_write_stb(dev, AMD_PMC_STB_DUMMY_PC);
+ if (ret)
+ dev_err(dev->dev, "error writing to STB: %d\n", ret);
buf = kzalloc(S2D_TELEMETRY_BYTES_MAX, GFP_KERNEL);
if (!buf)
return -ENOMEM;
- memcpy_fromio(buf, dev->stb_virt_addr, S2D_TELEMETRY_BYTES_MAX);
+ /* Spill to DRAM num_samples uses separate SMU message port */
+ dev->msg_port = 1;
+
+ /* Get the num_samples to calculate the last push location */
+ ret = amd_pmc_send_cmd(dev, S2D_NUM_SAMPLES, &num_samples, STB_SPILL_TO_DRAM, 1);
+ /* Clear msg_port for other SMU operation */
+ dev->msg_port = 0;
+ if (ret) {
+ dev_err(dev->dev, "error: S2D_NUM_SAMPLES not supported : %d\n", ret);
+ return ret;
+ }
+
+ /* Start capturing data from the last push location */
+ if (num_samples > S2D_TELEMETRY_BYTES_MAX) {
+ fsize = S2D_TELEMETRY_BYTES_MAX;
+ stb_rdptr_offset = num_samples - fsize;
+ } else {
+ fsize = num_samples;
+ stb_rdptr_offset = 0;
+ }
+
+ memcpy_fromio(buf, dev->stb_virt_addr + stb_rdptr_offset, fsize);
filp->private_data = buf;
return 0;
@@ -555,13 +590,13 @@ static void amd_pmc_dump_registers(struct amd_pmc_dev *dev)
}
value = amd_pmc_reg_read(dev, response);
- dev_dbg(dev->dev, "AMD_PMC_REGISTER_RESPONSE:%x\n", value);
+ dev_dbg(dev->dev, "AMD_%s_REGISTER_RESPONSE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
value = amd_pmc_reg_read(dev, argument);
- dev_dbg(dev->dev, "AMD_PMC_REGISTER_ARGUMENT:%x\n", value);
+ dev_dbg(dev->dev, "AMD_%s_REGISTER_ARGUMENT:%x\n", dev->msg_port ? "S2D" : "PMC", value);
value = amd_pmc_reg_read(dev, message);
- dev_dbg(dev->dev, "AMD_PMC_REGISTER_MESSAGE:%x\n", value);
+ dev_dbg(dev->dev, "AMD_%s_REGISTER_MESSAGE:%x\n", dev->msg_port ? "S2D" : "PMC", value);
}
static int amd_pmc_send_cmd(struct amd_pmc_dev *dev, u32 arg, u32 *data, u8 msg, bool ret)
@@ -653,6 +688,33 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
return -EINVAL;
}
+static int amd_pmc_czn_wa_irq1(struct amd_pmc_dev *pdev)
+{
+ struct device *d;
+ int rc;
+
+ if (!pdev->major) {
+ rc = amd_pmc_get_smu_version(pdev);
+ if (rc)
+ return rc;
+ }
+
+ if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65))
+ return 0;
+
+ d = bus_find_device_by_name(&serio_bus, NULL, "serio0");
+ if (!d)
+ return 0;
+ if (device_may_wakeup(d)) {
+ dev_info_once(d, "Disabling IRQ1 wakeup source to avoid platform firmware bug\n");
+ disable_irq_wake(1);
+ device_set_wakeup_enable(d, false);
+ }
+ put_device(d);
+
+ return 0;
+}
+
static int amd_pmc_verify_czn_rtc(struct amd_pmc_dev *pdev, u32 *arg)
{
struct rtc_device *rtc_device;
@@ -715,8 +777,8 @@ static void amd_pmc_s2idle_prepare(void)
/* Reset and Start SMU logging - to monitor the s0i3 stats */
amd_pmc_setup_smu_logging(pdev);
- /* Activate CZN specific RTC functionality */
- if (pdev->cpu_id == AMD_CPU_ID_CZN) {
+ /* Activate CZN specific platform bug workarounds */
+ if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) {
rc = amd_pmc_verify_czn_rtc(pdev, &arg);
if (rc) {
dev_err(pdev->dev, "failed to set RTC: %d\n", rc);
@@ -782,6 +844,25 @@ static struct acpi_s2idle_dev_ops amd_pmc_s2idle_dev_ops = {
.check = amd_pmc_s2idle_check,
.restore = amd_pmc_s2idle_restore,
};
+
+static int __maybe_unused amd_pmc_suspend_handler(struct device *dev)
+{
+ struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
+
+ if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) {
+ int rc = amd_pmc_czn_wa_irq1(pdev);
+
+ if (rc) {
+ dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc);
+ return rc;
+ }
+ }
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(amd_pmc_pm, amd_pmc_suspend_handler, NULL);
+
#endif
static const struct pci_device_id pmc_pci_ids[] = {
@@ -932,7 +1013,7 @@ static int amd_pmc_probe(struct platform_device *pdev)
if (enable_stb && (dev->cpu_id == AMD_CPU_ID_YC || dev->cpu_id == AMD_CPU_ID_CB)) {
err = amd_pmc_s2d_init(dev);
if (err)
- return err;
+ goto err_pci_dev_put;
}
platform_set_drvdata(pdev, dev);
@@ -980,6 +1061,9 @@ static struct platform_driver amd_pmc_driver = {
.name = "amd_pmc",
.acpi_match_table = amd_pmc_acpi_ids,
.dev_groups = pmc_groups,
+#ifdef CONFIG_SUSPEND
+ .pm = &amd_pmc_pm,
+#endif
},
.probe = amd_pmc_probe,
.remove = amd_pmc_remove,
diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
index c375498c4071..6d89528c3177 100644
--- a/drivers/platform/x86/amd/pmf/Kconfig
+++ b/drivers/platform/x86/amd/pmf/Kconfig
@@ -6,6 +6,7 @@
config AMD_PMF
tristate "AMD Platform Management Framework"
depends on ACPI && PCI
+ depends on POWER_SUPPLY
select ACPI_PLATFORM_PROFILE
help
This driver provides support for the AMD Platform Management Framework.
diff --git a/drivers/platform/x86/amd/pmf/auto-mode.c b/drivers/platform/x86/amd/pmf/auto-mode.c
index 644af42e07cf..96a8e1832c05 100644
--- a/drivers/platform/x86/amd/pmf/auto-mode.c
+++ b/drivers/platform/x86/amd/pmf/auto-mode.c
@@ -275,13 +275,8 @@ int amd_pmf_reset_amt(struct amd_pmf_dev *dev)
*/
if (is_apmf_func_supported(dev, APMF_FUNC_STATIC_SLIDER_GRANULAR)) {
- int mode = amd_pmf_get_pprof_modes(dev);
-
- if (mode < 0)
- return mode;
-
dev_dbg(dev->dev, "resetting AMT thermals\n");
- amd_pmf_update_slider(dev, SLIDER_OP_SET, mode, NULL);
+ amd_pmf_set_sps_power_limits(dev);
}
return 0;
}
@@ -299,7 +294,5 @@ void amd_pmf_deinit_auto_mode(struct amd_pmf_dev *dev)
void amd_pmf_init_auto_mode(struct amd_pmf_dev *dev)
{
amd_pmf_load_defaults_auto_mode(dev);
- /* update the thermal limits for Automode */
- amd_pmf_set_automode(dev, config_store.current_mode, NULL);
amd_pmf_init_metrics_table(dev);
}
diff --git a/drivers/platform/x86/amd/pmf/cnqf.c b/drivers/platform/x86/amd/pmf/cnqf.c
index 3f9731a2ac28..4beb22a19466 100644
--- a/drivers/platform/x86/amd/pmf/cnqf.c
+++ b/drivers/platform/x86/amd/pmf/cnqf.c
@@ -103,7 +103,7 @@ int amd_pmf_trans_cnqf(struct amd_pmf_dev *dev, int socket_power, ktime_t time_l
src = amd_pmf_cnqf_get_power_source(dev);
- if (dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+ if (is_pprof_balanced(dev)) {
amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
} else {
/*
@@ -307,13 +307,9 @@ static ssize_t cnqf_enable_store(struct device *dev,
const char *buf, size_t count)
{
struct amd_pmf_dev *pdev = dev_get_drvdata(dev);
- int mode, result, src;
+ int result, src;
bool input;
- mode = amd_pmf_get_pprof_modes(pdev);
- if (mode < 0)
- return mode;
-
result = kstrtobool(buf, &input);
if (result)
return result;
@@ -321,11 +317,11 @@ static ssize_t cnqf_enable_store(struct device *dev,
src = amd_pmf_cnqf_get_power_source(pdev);
pdev->cnqf_enabled = input;
- if (pdev->cnqf_enabled && pdev->current_profile == PLATFORM_PROFILE_BALANCED) {
+ if (pdev->cnqf_enabled && is_pprof_balanced(pdev)) {
amd_pmf_set_cnqf(pdev, src, config_store.current_mode, NULL);
} else {
if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
- amd_pmf_update_slider(pdev, SLIDER_OP_SET, mode, NULL);
+ amd_pmf_set_sps_power_limits(pdev);
}
dev_dbg(pdev->dev, "Received CnQF %s\n", input ? "on" : "off");
@@ -386,7 +382,7 @@ int amd_pmf_init_cnqf(struct amd_pmf_dev *dev)
dev->cnqf_enabled = amd_pmf_check_flags(dev);
/* update the thermal for CnQF */
- if (dev->cnqf_enabled && dev->current_profile == PLATFORM_PROFILE_BALANCED) {
+ if (dev->cnqf_enabled && is_pprof_balanced(dev)) {
src = amd_pmf_cnqf_get_power_source(dev);
amd_pmf_set_cnqf(dev, src, config_store.current_mode, NULL);
}
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index a5f5a4bcff6d..da23639071d7 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -58,6 +58,25 @@ static bool force_load;
module_param(force_load, bool, 0444);
MODULE_PARM_DESC(force_load, "Force load this driver on supported older platforms (experimental)");
+static int amd_pmf_pwr_src_notify_call(struct notifier_block *nb, unsigned long event, void *data)
+{
+ struct amd_pmf_dev *pmf = container_of(nb, struct amd_pmf_dev, pwr_src_notifier);
+
+ if (event != PSY_EVENT_PROP_CHANGED)
+ return NOTIFY_OK;
+
+ if (is_apmf_func_supported(pmf, APMF_FUNC_AUTO_MODE) ||
+ is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_DC) ||
+ is_apmf_func_supported(pmf, APMF_FUNC_DYN_SLIDER_AC)) {
+ if ((pmf->amt_enabled || pmf->cnqf_enabled) && is_pprof_balanced(pmf))
+ return NOTIFY_DONE;
+ }
+
+ amd_pmf_set_sps_power_limits(pmf);
+
+ return NOTIFY_OK;
+}
+
static int current_power_limits_show(struct seq_file *seq, void *unused)
{
struct amd_pmf_dev *dev = seq->private;
@@ -366,14 +385,18 @@ static int amd_pmf_probe(struct platform_device *pdev)
if (!dev->regbase)
return -ENOMEM;
+ mutex_init(&dev->lock);
+ mutex_init(&dev->update_mutex);
+
apmf_acpi_init(dev);
platform_set_drvdata(pdev, dev);
amd_pmf_init_features(dev);
apmf_install_handler(dev);
amd_pmf_dbgfs_register(dev);
- mutex_init(&dev->lock);
- mutex_init(&dev->update_mutex);
+ dev->pwr_src_notifier.notifier_call = amd_pmf_pwr_src_notify_call;
+ power_supply_reg_notifier(&dev->pwr_src_notifier);
+
dev_info(dev->dev, "registered PMF device successfully\n");
return 0;
@@ -383,11 +406,12 @@ static int amd_pmf_remove(struct platform_device *pdev)
{
struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
- mutex_destroy(&dev->lock);
- mutex_destroy(&dev->update_mutex);
+ power_supply_unreg_notifier(&dev->pwr_src_notifier);
amd_pmf_deinit_features(dev);
apmf_acpi_deinit(dev);
amd_pmf_dbgfs_unregister(dev);
+ mutex_destroy(&dev->lock);
+ mutex_destroy(&dev->update_mutex);
kfree(dev->buf);
return 0;
}
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 84bbe2c6ea61..06c30cdc0573 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -169,6 +169,7 @@ struct amd_pmf_dev {
struct mutex update_mutex; /* protects race between ACPI handler and metrics thread */
bool cnqf_enabled;
bool cnqf_supported;
+ struct notifier_block pwr_src_notifier;
};
struct apmf_sps_prop_granular {
@@ -391,9 +392,11 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev);
void amd_pmf_deinit_sps(struct amd_pmf_dev *dev);
int apmf_get_static_slider_granular(struct amd_pmf_dev *pdev,
struct apmf_static_slider_granular_output *output);
+bool is_pprof_balanced(struct amd_pmf_dev *pmf);
int apmf_update_fan_idx(struct amd_pmf_dev *pdev, bool manual, u32 idx);
+int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf);
/* Auto Mode Layer */
int apmf_get_auto_mode_def(struct amd_pmf_dev *pdev, struct apmf_auto_mode *data);
diff --git a/drivers/platform/x86/amd/pmf/sps.c b/drivers/platform/x86/amd/pmf/sps.c
index dba7e36962dc..bed762d47a14 100644
--- a/drivers/platform/x86/amd/pmf/sps.c
+++ b/drivers/platform/x86/amd/pmf/sps.c
@@ -70,6 +70,24 @@ void amd_pmf_update_slider(struct amd_pmf_dev *dev, bool op, int idx,
}
}
+int amd_pmf_set_sps_power_limits(struct amd_pmf_dev *pmf)
+{
+ int mode;
+
+ mode = amd_pmf_get_pprof_modes(pmf);
+ if (mode < 0)
+ return mode;
+
+ amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
+
+ return 0;
+}
+
+bool is_pprof_balanced(struct amd_pmf_dev *pmf)
+{
+ return (pmf->current_profile == PLATFORM_PROFILE_BALANCED) ? true : false;
+}
+
static int amd_pmf_profile_get(struct platform_profile_handler *pprof,
enum platform_profile_option *profile)
{
@@ -105,15 +123,10 @@ static int amd_pmf_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
struct amd_pmf_dev *pmf = container_of(pprof, struct amd_pmf_dev, pprof);
- int mode;
pmf->current_profile = profile;
- mode = amd_pmf_get_pprof_modes(pmf);
- if (mode < 0)
- return mode;
- amd_pmf_update_slider(pmf, SLIDER_OP_SET, mode, NULL);
- return 0;
+ return amd_pmf_set_sps_power_limits(pmf);
}
int amd_pmf_init_sps(struct amd_pmf_dev *dev)
@@ -123,6 +136,9 @@ int amd_pmf_init_sps(struct amd_pmf_dev *dev)
dev->current_profile = PLATFORM_PROFILE_BALANCED;
amd_pmf_load_defaults_sps(dev);
+ /* update SPS balanced power mode thermals */
+ amd_pmf_set_sps_power_limits(dev);
+
dev->pprof.profile_get = amd_pmf_profile_get;
dev->pprof.profile_set = amd_pmf_profile_set;
diff --git a/drivers/platform/x86/apple-gmux.c b/drivers/platform/x86/apple-gmux.c
index ca33df7ea550..9333f82cfa8a 100644
--- a/drivers/platform/x86/apple-gmux.c
+++ b/drivers/platform/x86/apple-gmux.c
@@ -64,29 +64,6 @@ struct apple_gmux_data {
static struct apple_gmux_data *apple_gmux_data;
-/*
- * gmux port offsets. Many of these are not yet used, but may be in the
- * future, and it's useful to have them documented here anyhow.
- */
-#define GMUX_PORT_VERSION_MAJOR 0x04
-#define GMUX_PORT_VERSION_MINOR 0x05
-#define GMUX_PORT_VERSION_RELEASE 0x06
-#define GMUX_PORT_SWITCH_DISPLAY 0x10
-#define GMUX_PORT_SWITCH_GET_DISPLAY 0x11
-#define GMUX_PORT_INTERRUPT_ENABLE 0x14
-#define GMUX_PORT_INTERRUPT_STATUS 0x16
-#define GMUX_PORT_SWITCH_DDC 0x28
-#define GMUX_PORT_SWITCH_EXTERNAL 0x40
-#define GMUX_PORT_SWITCH_GET_EXTERNAL 0x41
-#define GMUX_PORT_DISCRETE_POWER 0x50
-#define GMUX_PORT_MAX_BRIGHTNESS 0x70
-#define GMUX_PORT_BRIGHTNESS 0x74
-#define GMUX_PORT_VALUE 0xc2
-#define GMUX_PORT_READ 0xd0
-#define GMUX_PORT_WRITE 0xd4
-
-#define GMUX_MIN_IO_LEN (GMUX_PORT_BRIGHTNESS + 4)
-
#define GMUX_INTERRUPT_ENABLE 0xff
#define GMUX_INTERRUPT_DISABLE 0x00
@@ -249,23 +226,6 @@ static void gmux_write32(struct apple_gmux_data *gmux_data, int port,
gmux_pio_write32(gmux_data, port, val);
}
-static bool gmux_is_indexed(struct apple_gmux_data *gmux_data)
-{
- u16 val;
-
- outb(0xaa, gmux_data->iostart + 0xcc);
- outb(0x55, gmux_data->iostart + 0xcd);
- outb(0x00, gmux_data->iostart + 0xce);
-
- val = inb(gmux_data->iostart + 0xcc) |
- (inb(gmux_data->iostart + 0xcd) << 8);
-
- if (val == 0x55aa)
- return true;
-
- return false;
-}
-
/**
* DOC: Backlight control
*
@@ -605,60 +565,43 @@ static int gmux_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
int ret = -ENXIO;
acpi_status status;
unsigned long long gpe;
+ bool indexed = false;
+ u32 version;
if (apple_gmux_data)
return -EBUSY;
+ if (!apple_gmux_detect(pnp, &indexed)) {
+ pr_info("gmux device not present\n");
+ return -ENODEV;
+ }
+
gmux_data = kzalloc(sizeof(*gmux_data), GFP_KERNEL);
if (!gmux_data)
return -ENOMEM;
pnp_set_drvdata(pnp, gmux_data);
res = pnp_get_resource(pnp, IORESOURCE_IO, 0);
- if (!res) {
- pr_err("Failed to find gmux I/O resource\n");
- goto err_free;
- }
-
gmux_data->iostart = res->start;
gmux_data->iolen = resource_size(res);
- if (gmux_data->iolen < GMUX_MIN_IO_LEN) {
- pr_err("gmux I/O region too small (%lu < %u)\n",
- gmux_data->iolen, GMUX_MIN_IO_LEN);
- goto err_free;
- }
-
if (!request_region(gmux_data->iostart, gmux_data->iolen,
"Apple gmux")) {
pr_err("gmux I/O already in use\n");
goto err_free;
}
- /*
- * Invalid version information may indicate either that the gmux
- * device isn't present or that it's a new one that uses indexed
- * io
- */
-
- ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
- ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
- ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
- if (ver_major == 0xff && ver_minor == 0xff && ver_release == 0xff) {
- if (gmux_is_indexed(gmux_data)) {
- u32 version;
- mutex_init(&gmux_data->index_lock);
- gmux_data->indexed = true;
- version = gmux_read32(gmux_data,
- GMUX_PORT_VERSION_MAJOR);
- ver_major = (version >> 24) & 0xff;
- ver_minor = (version >> 16) & 0xff;
- ver_release = (version >> 8) & 0xff;
- } else {
- pr_info("gmux device not present\n");
- ret = -ENODEV;
- goto err_release;
- }
+ if (indexed) {
+ mutex_init(&gmux_data->index_lock);
+ gmux_data->indexed = true;
+ version = gmux_read32(gmux_data, GMUX_PORT_VERSION_MAJOR);
+ ver_major = (version >> 24) & 0xff;
+ ver_minor = (version >> 16) & 0xff;
+ ver_release = (version >> 8) & 0xff;
+ } else {
+ ver_major = gmux_read8(gmux_data, GMUX_PORT_VERSION_MAJOR);
+ ver_minor = gmux_read8(gmux_data, GMUX_PORT_VERSION_MINOR);
+ ver_release = gmux_read8(gmux_data, GMUX_PORT_VERSION_RELEASE);
}
pr_info("Found gmux version %d.%d.%d [%s]\n", ver_major, ver_minor,
ver_release, (gmux_data->indexed ? "indexed" : "classic"));
diff --git a/drivers/platform/x86/asus-nb-wmi.c b/drivers/platform/x86/asus-nb-wmi.c
index c685a705b73d..cb15acdf14a3 100644
--- a/drivers/platform/x86/asus-nb-wmi.c
+++ b/drivers/platform/x86/asus-nb-wmi.c
@@ -121,6 +121,10 @@ static struct quirk_entry quirk_asus_tablet_mode = {
.tablet_switch_mode = asus_wmi_lid_flip_rog_devid,
};
+static struct quirk_entry quirk_asus_ignore_fan = {
+ .wmi_ignore_fan = true,
+};
+
static int dmi_matched(const struct dmi_system_id *dmi)
{
pr_info("Identified laptop model '%s'\n", dmi->ident);
@@ -473,6 +477,15 @@ static const struct dmi_system_id asus_quirks[] = {
},
.driver_data = &quirk_asus_tablet_mode,
},
+ {
+ .callback = dmi_matched,
+ .ident = "ASUS VivoBook E410MA",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "E410MA"),
+ },
+ .driver_data = &quirk_asus_ignore_fan,
+ },
{},
};
@@ -511,6 +524,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x30, { KEY_VOLUMEUP } },
{ KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
{ KE_KEY, 0x32, { KEY_MUTE } },
+ { KE_KEY, 0x33, { KEY_SCREENLOCK } },
{ KE_KEY, 0x35, { KEY_SCREENLOCK } },
{ KE_KEY, 0x38, { KEY_PROG3 } }, /* Armoury Crate */
{ KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
@@ -544,6 +558,7 @@ static const struct key_entry asus_nb_wmi_keymap[] = {
{ KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
{ KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
{ KE_KEY, 0x82, { KEY_CAMERA } },
+ { KE_KEY, 0x85, { KEY_CAMERA } },
{ KE_KEY, 0x86, { KEY_PROG1 } }, /* MyASUS Key */
{ KE_KEY, 0x88, { KEY_RFKILL } }, /* Radio Toggle Key */
{ KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
diff --git a/drivers/platform/x86/asus-tf103c-dock.c b/drivers/platform/x86/asus-tf103c-dock.c
index 62310e06282b..aeb1138464df 100644
--- a/drivers/platform/x86/asus-tf103c-dock.c
+++ b/drivers/platform/x86/asus-tf103c-dock.c
@@ -250,7 +250,7 @@ static int tf103c_dock_hid_raw_request(struct hid_device *hid, u8 reportnum,
return 0;
}
-static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
+static const struct hid_ll_driver tf103c_dock_hid_ll_driver = {
.parse = tf103c_dock_hid_parse,
.start = tf103c_dock_hid_start,
.stop = tf103c_dock_hid_stop,
@@ -259,7 +259,7 @@ static struct hid_ll_driver tf103c_dock_hid_ll_driver = {
.raw_request = tf103c_dock_hid_raw_request,
};
-static int tf103c_dock_toprow_codes[13][2] = {
+static const int tf103c_dock_toprow_codes[13][2] = {
/* Normal, AltGr pressed */
{ KEY_POWER, KEY_F1 },
{ KEY_RFKILL, KEY_F2 },
diff --git a/drivers/platform/x86/asus-wmi.c b/drivers/platform/x86/asus-wmi.c
index 6f81b2844dcb..1038dfdcdd32 100644
--- a/drivers/platform/x86/asus-wmi.c
+++ b/drivers/platform/x86/asus-wmi.c
@@ -225,6 +225,7 @@ struct asus_wmi {
int tablet_switch_event_code;
u32 tablet_switch_dev_id;
+ bool tablet_switch_inverted;
enum fan_type fan_type;
enum fan_type gpu_fan_type;
@@ -493,6 +494,13 @@ static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
}
/* Input **********************************************************************/
+static void asus_wmi_tablet_sw_report(struct asus_wmi *asus, bool value)
+{
+ input_report_switch(asus->inputdev, SW_TABLET_MODE,
+ asus->tablet_switch_inverted ? !value : value);
+ input_sync(asus->inputdev);
+}
+
static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event_code)
{
struct device *dev = &asus->platform_device->dev;
@@ -501,7 +509,7 @@ static void asus_wmi_tablet_sw_init(struct asus_wmi *asus, u32 dev_id, int event
result = asus_wmi_get_devstate_simple(asus, dev_id);
if (result >= 0) {
input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
- input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
+ asus_wmi_tablet_sw_report(asus, result);
asus->tablet_switch_dev_id = dev_id;
asus->tablet_switch_event_code = event_code;
} else if (result == -ENODEV) {
@@ -534,6 +542,7 @@ static int asus_wmi_input_init(struct asus_wmi *asus)
case asus_wmi_no_tablet_switch:
break;
case asus_wmi_kbd_dock_devid:
+ asus->tablet_switch_inverted = true;
asus_wmi_tablet_sw_init(asus, ASUS_WMI_DEVID_KBD_DOCK, NOTIFY_KBD_DOCK_CHANGE);
break;
case asus_wmi_lid_flip_devid:
@@ -573,10 +582,8 @@ static void asus_wmi_tablet_mode_get_state(struct asus_wmi *asus)
return;
result = asus_wmi_get_devstate_simple(asus, asus->tablet_switch_dev_id);
- if (result >= 0) {
- input_report_switch(asus->inputdev, SW_TABLET_MODE, result);
- input_sync(asus->inputdev);
- }
+ if (result >= 0)
+ asus_wmi_tablet_sw_report(asus, result);
}
/* dGPU ********************************************************************/
@@ -2243,7 +2250,9 @@ static int asus_wmi_fan_init(struct asus_wmi *asus)
asus->fan_type = FAN_TYPE_NONE;
asus->agfn_pwm = -1;
- if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
+ if (asus->driver->quirks->wmi_ignore_fan)
+ asus->fan_type = FAN_TYPE_NONE;
+ else if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
asus->fan_type = FAN_TYPE_SPEC83;
else if (asus_wmi_has_agfn_fan(asus))
asus->fan_type = FAN_TYPE_AGFN;
@@ -2436,6 +2445,9 @@ static int fan_curve_check_present(struct asus_wmi *asus, bool *available,
*available = false;
+ if (asus->fan_type == FAN_TYPE_NONE)
+ return 0;
+
err = fan_curve_get_factory_default(asus, fan_dev);
if (err) {
return 0;
diff --git a/drivers/platform/x86/asus-wmi.h b/drivers/platform/x86/asus-wmi.h
index 65316998b898..a478ebfd34df 100644
--- a/drivers/platform/x86/asus-wmi.h
+++ b/drivers/platform/x86/asus-wmi.h
@@ -38,6 +38,7 @@ struct quirk_entry {
bool store_backlight_power;
bool wmi_backlight_set_devstate;
bool wmi_force_als_set;
+ bool wmi_ignore_fan;
enum asus_wmi_tablet_switch_mode tablet_switch_mode;
int wapf;
/*
diff --git a/drivers/platform/x86/dell/Kconfig b/drivers/platform/x86/dell/Kconfig
index d319de8f2132..bdd78076b1d7 100644
--- a/drivers/platform/x86/dell/Kconfig
+++ b/drivers/platform/x86/dell/Kconfig
@@ -192,12 +192,12 @@ config DELL_WMI_DESCRIPTOR
config DELL_WMI_DDV
tristate "Dell WMI sensors Support"
default m
- depends on ACPI_BATTERY
depends on ACPI_WMI
+ depends on ACPI_BATTERY || HWMON
help
- This option adds support for WMI-based sensors like
- battery temperature sensors found on some Dell notebooks.
- It also supports reading of the battery ePPID.
+ This option adds support for WMI-based fan and thermal sensors
+ found on some Dell notebooks. It also supports various WMI-based battery
+ extras like reading of the battery temperature and ePPID.
To compile this drivers as a module, choose M here: the module will
be called dell-wmi-ddv.
diff --git a/drivers/platform/x86/dell/dell-smo8800.c b/drivers/platform/x86/dell/dell-smo8800.c
index 3385e852104c..8d6b7a83cf24 100644
--- a/drivers/platform/x86/dell/dell-smo8800.c
+++ b/drivers/platform/x86/dell/dell-smo8800.c
@@ -67,10 +67,7 @@ static ssize_t smo8800_misc_read(struct file *file, char __user *buf,
retval = 1;
- if (data < 255)
- byte_data = data;
- else
- byte_data = 255;
+ byte_data = min_t(u32, data, 255);
if (put_user(byte_data, buf))
retval = -EFAULT;
diff --git a/drivers/platform/x86/dell/dell-wmi-base.c b/drivers/platform/x86/dell/dell-wmi-base.c
index 0a259a27459f..502783a7adb1 100644
--- a/drivers/platform/x86/dell/dell-wmi-base.c
+++ b/drivers/platform/x86/dell/dell-wmi-base.c
@@ -261,6 +261,9 @@ static const struct key_entry dell_wmi_keymap_type_0010[] = {
{ KE_KEY, 0x57, { KEY_BRIGHTNESSDOWN } },
{ KE_KEY, 0x58, { KEY_BRIGHTNESSUP } },
+ /*Speaker Mute*/
+ { KE_KEY, 0x109, { KEY_MUTE} },
+
/* Mic mute */
{ KE_KEY, 0x150, { KEY_MICMUTE } },
diff --git a/drivers/platform/x86/dell/dell-wmi-ddv.c b/drivers/platform/x86/dell/dell-wmi-ddv.c
index 2bb449845d14..d547c9d09725 100644
--- a/drivers/platform/x86/dell/dell-wmi-ddv.c
+++ b/drivers/platform/x86/dell/dell-wmi-ddv.c
@@ -10,28 +10,43 @@
#include <linux/acpi.h>
#include <linux/debugfs.h>
#include <linux/device.h>
+#include <linux/device/driver.h>
#include <linux/dev_printk.h>
+#include <linux/errno.h>
+#include <linux/kconfig.h>
#include <linux/kernel.h>
+#include <linux/hwmon.h>
#include <linux/kstrtox.h>
#include <linux/math.h>
+#include <linux/math64.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/limits.h>
+#include <linux/pm.h>
#include <linux/power_supply.h>
#include <linux/printk.h>
#include <linux/seq_file.h>
#include <linux/sysfs.h>
+#include <linux/types.h>
#include <linux/wmi.h>
#include <acpi/battery.h>
+#include <asm/unaligned.h>
+
#define DRIVER_NAME "dell-wmi-ddv"
-#define DELL_DDV_SUPPORTED_INTERFACE 2
+#define DELL_DDV_SUPPORTED_VERSION_MIN 2
+#define DELL_DDV_SUPPORTED_VERSION_MAX 3
#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"
#define DELL_EPPID_LENGTH 20
#define DELL_EPPID_EXT_LENGTH 23
+static bool force;
+module_param_unsafe(force, bool, 0);
+MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions");
+
enum dell_ddv_method {
DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,
DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,
@@ -49,6 +64,7 @@ enum dell_ddv_method {
DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,
DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,
DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,
+ DELL_DDV_BATTERY_RAW_ANALYTICS_A_BLOCK = 0x11, /* version 3 */
DELL_DDV_INTERFACE_VERSION = 0x12,
@@ -56,13 +72,63 @@ enum dell_ddv_method {
DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,
};
+struct fan_sensor_entry {
+ u8 type;
+ __le16 rpm;
+} __packed;
+
+struct thermal_sensor_entry {
+ u8 type;
+ s8 now;
+ s8 min;
+ s8 max;
+ u8 unknown;
+} __packed;
+
+struct combined_channel_info {
+ struct hwmon_channel_info info;
+ u32 config[];
+};
+
+struct combined_chip_info {
+ struct hwmon_chip_info chip;
+ const struct hwmon_channel_info *info[];
+};
+
+struct dell_wmi_ddv_sensors {
+ struct mutex lock; /* protect caching */
+ unsigned long timestamp;
+ union acpi_object *obj;
+ u64 entries;
+};
+
struct dell_wmi_ddv_data {
struct acpi_battery_hook hook;
struct device_attribute temp_attr;
struct device_attribute eppid_attr;
+ struct dell_wmi_ddv_sensors fans;
+ struct dell_wmi_ddv_sensors temps;
struct wmi_device *wdev;
};
+static const char * const fan_labels[] = {
+ "CPU Fan",
+ "Chassis Motherboard Fan",
+ "Video Fan",
+ "Power Supply Fan",
+ "Chipset Fan",
+ "Memory Fan",
+ "PCI Fan",
+ "HDD Fan",
+};
+
+static const char * const fan_dock_labels[] = {
+ "Docking Chassis/Motherboard Fan",
+ "Docking Video Fan",
+ "Docking Power Supply Fan",
+ "Docking Chipset Fan",
+};
+
static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,
union acpi_object **result, acpi_object_type type)
{
@@ -84,7 +150,7 @@ static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method
if (obj->type != type) {
kfree(obj);
- return -EIO;
+ return -ENOMSG;
}
*result = obj;
@@ -123,21 +189,27 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth
if (ret < 0)
return ret;
- if (obj->package.count != 2)
- goto err_free;
+ if (obj->package.count != 2 ||
+ obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
+ obj->package.elements[1].type != ACPI_TYPE_BUFFER) {
+ ret = -ENOMSG;
- if (obj->package.elements[0].type != ACPI_TYPE_INTEGER)
goto err_free;
+ }
buffer_size = obj->package.elements[0].integer.value;
- if (obj->package.elements[1].type != ACPI_TYPE_BUFFER)
+ if (!buffer_size) {
+ ret = -ENODATA;
+
goto err_free;
+ }
if (buffer_size > obj->package.elements[1].buffer.length) {
dev_warn(&wdev->dev,
FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",
buffer_size, obj->package.elements[1].buffer.length);
+ ret = -EMSGSIZE;
goto err_free;
}
@@ -149,7 +221,7 @@ static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_meth
err_free:
kfree(obj);
- return -EIO;
+ return ret;
}
static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,
@@ -158,6 +230,410 @@ static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_meth
return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);
}
+/*
+ * Needs to be called with lock held, except during initialization.
+ */
+static int dell_wmi_ddv_update_sensors(struct wmi_device *wdev, enum dell_ddv_method method,
+ struct dell_wmi_ddv_sensors *sensors, size_t entry_size)
+{
+ u64 buffer_size, rem, entries;
+ union acpi_object *obj;
+ u8 *buffer;
+ int ret;
+
+ if (sensors->obj) {
+ if (time_before(jiffies, sensors->timestamp + HZ))
+ return 0;
+
+ kfree(sensors->obj);
+ sensors->obj = NULL;
+ }
+
+ ret = dell_wmi_ddv_query_buffer(wdev, method, 0, &obj);
+ if (ret < 0)
+ return ret;
+
+ /* buffer format sanity check */
+ buffer_size = obj->package.elements[0].integer.value;
+ buffer = obj->package.elements[1].buffer.pointer;
+ entries = div64_u64_rem(buffer_size, entry_size, &rem);
+ if (rem != 1 || buffer[buffer_size - 1] != 0xff) {
+ ret = -ENOMSG;
+ goto err_free;
+ }
+
+ if (!entries) {
+ ret = -ENODATA;
+ goto err_free;
+ }
+
+ sensors->obj = obj;
+ sensors->entries = entries;
+ sensors->timestamp = jiffies;
+
+ return 0;
+
+err_free:
+ kfree(obj);
+
+ return ret;
+}
+
+static umode_t dell_wmi_ddv_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
+ int channel)
+{
+ return 0444;
+}
+
+static int dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
+ long *val)
+{
+ struct fan_sensor_entry *entry;
+ int ret;
+
+ ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
+ &data->fans, sizeof(*entry));
+ if (ret < 0)
+ return ret;
+
+ if (channel >= data->fans.entries)
+ return -ENXIO;
+
+ entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
+ switch (attr) {
+ case hwmon_fan_input:
+ *val = get_unaligned_le16(&entry[channel].rpm);
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
+ long *val)
+{
+ struct thermal_sensor_entry *entry;
+ int ret;
+
+ ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
+ &data->temps, sizeof(*entry));
+ if (ret < 0)
+ return ret;
+
+ if (channel >= data->temps.entries)
+ return -ENXIO;
+
+ entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
+ switch (attr) {
+ case hwmon_temp_input:
+ *val = entry[channel].now * 1000;
+ return 0;
+ case hwmon_temp_min:
+ *val = entry[channel].min * 1000;
+ return 0;
+ case hwmon_temp_max:
+ *val = entry[channel].max * 1000;
+ return 0;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dell_wmi_ddv_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, long *val)
+{
+ struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ mutex_lock(&data->fans.lock);
+ ret = dell_wmi_ddv_fan_read_channel(data, attr, channel, val);
+ mutex_unlock(&data->fans.lock);
+ return ret;
+ case hwmon_temp:
+ mutex_lock(&data->temps.lock);
+ ret = dell_wmi_ddv_temp_read_channel(data, attr, channel, val);
+ mutex_unlock(&data->temps.lock);
+ return ret;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static int dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data *data, int channel,
+ const char **str)
+{
+ struct fan_sensor_entry *entry;
+ int ret;
+ u8 type;
+
+ ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
+ &data->fans, sizeof(*entry));
+ if (ret < 0)
+ return ret;
+
+ if (channel >= data->fans.entries)
+ return -ENXIO;
+
+ entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
+ type = entry[channel].type;
+ switch (type) {
+ case 0x00 ... 0x07:
+ *str = fan_labels[type];
+ break;
+ case 0x11 ... 0x14:
+ *str = fan_dock_labels[type - 0x11];
+ break;
+ default:
+ *str = "Unknown Fan";
+ break;
+ }
+
+ return 0;
+}
+
+static int dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data *data, int channel,
+ const char **str)
+{
+ struct thermal_sensor_entry *entry;
+ int ret;
+
+ ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
+ &data->temps, sizeof(*entry));
+ if (ret < 0)
+ return ret;
+
+ if (channel >= data->temps.entries)
+ return -ENXIO;
+
+ entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
+ switch (entry[channel].type) {
+ case 0x00:
+ *str = "CPU";
+ break;
+ case 0x11:
+ *str = "Video";
+ break;
+ case 0x22:
+ *str = "Memory"; /* sometimes called DIMM */
+ break;
+ case 0x33:
+ *str = "Other";
+ break;
+ case 0x44:
+ *str = "Ambient"; /* sometimes called SKIN */
+ break;
+ case 0x52:
+ *str = "SODIMM";
+ break;
+ case 0x55:
+ *str = "HDD";
+ break;
+ case 0x62:
+ *str = "SODIMM 2";
+ break;
+ case 0x73:
+ *str = "NB";
+ break;
+ case 0x83:
+ *str = "Charger";
+ break;
+ case 0xbb:
+ *str = "Memory 3";
+ break;
+ default:
+ *str = "Unknown";
+ break;
+ }
+
+ return 0;
+}
+
+static int dell_wmi_ddv_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
+ int channel, const char **str)
+{
+ struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ switch (type) {
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_label:
+ mutex_lock(&data->fans.lock);
+ ret = dell_wmi_ddv_fan_read_string(data, channel, str);
+ mutex_unlock(&data->fans.lock);
+ return ret;
+ default:
+ break;
+ }
+ break;
+ case hwmon_temp:
+ switch (attr) {
+ case hwmon_temp_label:
+ mutex_lock(&data->temps.lock);
+ ret = dell_wmi_ddv_temp_read_string(data, channel, str);
+ mutex_unlock(&data->temps.lock);
+ return ret;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -EOPNOTSUPP;
+}
+
+static const struct hwmon_ops dell_wmi_ddv_ops = {
+ .is_visible = dell_wmi_ddv_is_visible,
+ .read = dell_wmi_ddv_read,
+ .read_string = dell_wmi_ddv_read_string,
+};
+
+static struct hwmon_channel_info *dell_wmi_ddv_channel_create(struct device *dev, u64 count,
+ enum hwmon_sensor_types type,
+ u32 config)
+{
+ struct combined_channel_info *cinfo;
+ int i;
+
+ cinfo = devm_kzalloc(dev, struct_size(cinfo, config, count + 1), GFP_KERNEL);
+ if (!cinfo)
+ return ERR_PTR(-ENOMEM);
+
+ cinfo->info.type = type;
+ cinfo->info.config = cinfo->config;
+
+ for (i = 0; i < count; i++)
+ cinfo->config[i] = config;
+
+ return &cinfo->info;
+}
+
+static void dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors *sensors)
+{
+ mutex_lock(&sensors->lock);
+ kfree(sensors->obj);
+ sensors->obj = NULL;
+ mutex_unlock(&sensors->lock);
+}
+
+static void dell_wmi_ddv_hwmon_cache_destroy(void *data)
+{
+ struct dell_wmi_ddv_sensors *sensors = data;
+
+ mutex_destroy(&sensors->lock);
+ kfree(sensors->obj);
+}
+
+static struct hwmon_channel_info *dell_wmi_ddv_channel_init(struct wmi_device *wdev,
+ enum dell_ddv_method method,
+ struct dell_wmi_ddv_sensors *sensors,
+ size_t entry_size,
+ enum hwmon_sensor_types type,
+ u32 config)
+{
+ struct hwmon_channel_info *info;
+ int ret;
+
+ ret = dell_wmi_ddv_update_sensors(wdev, method, sensors, entry_size);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ mutex_init(&sensors->lock);
+
+ ret = devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
+ if (ret < 0)
+ return ERR_PTR(ret);
+
+ info = dell_wmi_ddv_channel_create(&wdev->dev, sensors->entries, type, config);
+ if (IS_ERR(info))
+ devm_release_action(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
+
+ return info;
+}
+
+static int dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data *data)
+{
+ struct wmi_device *wdev = data->wdev;
+ struct combined_chip_info *cinfo;
+ struct hwmon_channel_info *info;
+ struct device *hdev;
+ int index = 0;
+ int ret;
+
+ if (!devres_open_group(&wdev->dev, dell_wmi_ddv_hwmon_add, GFP_KERNEL))
+ return -ENOMEM;
+
+ cinfo = devm_kzalloc(&wdev->dev, struct_size(cinfo, info, 4), GFP_KERNEL);
+ if (!cinfo) {
+ ret = -ENOMEM;
+
+ goto err_release;
+ }
+
+ cinfo->chip.ops = &dell_wmi_ddv_ops;
+ cinfo->chip.info = cinfo->info;
+
+ info = dell_wmi_ddv_channel_create(&wdev->dev, 1, hwmon_chip, HWMON_C_REGISTER_TZ);
+ if (IS_ERR(info)) {
+ ret = PTR_ERR(info);
+
+ goto err_release;
+ }
+
+ cinfo->info[index] = info;
+ index++;
+
+ info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_FAN_SENSOR_INFORMATION, &data->fans,
+ sizeof(struct fan_sensor_entry), hwmon_fan,
+ (HWMON_F_INPUT | HWMON_F_LABEL));
+ if (!IS_ERR(info)) {
+ cinfo->info[index] = info;
+ index++;
+ }
+
+ info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, &data->temps,
+ sizeof(struct thermal_sensor_entry), hwmon_temp,
+ (HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
+ HWMON_T_LABEL));
+ if (!IS_ERR(info)) {
+ cinfo->info[index] = info;
+ index++;
+ }
+
+ if (index < 2) {
+ ret = -ENODEV;
+
+ goto err_release;
+ }
+
+ hdev = devm_hwmon_device_register_with_info(&wdev->dev, "dell_ddv", data, &cinfo->chip,
+ NULL);
+ if (IS_ERR(hdev)) {
+ ret = PTR_ERR(hdev);
+
+ goto err_release;
+ }
+
+ devres_close_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
+
+ return 0;
+
+err_release:
+ devres_release_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
+
+ return ret;
+}
+
static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
{
const char *uid_str;
@@ -340,8 +816,13 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
return ret;
dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);
- if (version != DELL_DDV_SUPPORTED_INTERFACE)
- return -ENODEV;
+ if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) {
+ if (!force)
+ return -ENODEV;
+
+ dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u)\n",
+ version);
+ }
data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -352,9 +833,34 @@ static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
dell_wmi_ddv_debugfs_init(wdev);
- return dell_wmi_ddv_battery_add(data);
+ if (IS_REACHABLE(CONFIG_ACPI_BATTERY)) {
+ ret = dell_wmi_ddv_battery_add(data);
+ if (ret < 0 && ret != -ENODEV)
+ dev_warn(&wdev->dev, "Unable to register ACPI battery hook: %d\n", ret);
+ }
+
+ if (IS_REACHABLE(CONFIG_HWMON)) {
+ ret = dell_wmi_ddv_hwmon_add(data);
+ if (ret < 0 && ret != -ENODEV)
+ dev_warn(&wdev->dev, "Unable to register hwmon interface: %d\n", ret);
+ }
+
+ return 0;
}
+static int dell_wmi_ddv_resume(struct device *dev)
+{
+ struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
+
+ /* Force re-reading of all sensors */
+ dell_wmi_ddv_hwmon_cache_invalidate(&data->fans);
+ dell_wmi_ddv_hwmon_cache_invalidate(&data->temps);
+
+ return 0;
+}
+
+static DEFINE_SIMPLE_DEV_PM_OPS(dell_wmi_ddv_dev_pm_ops, NULL, dell_wmi_ddv_resume);
+
static const struct wmi_device_id dell_wmi_ddv_id_table[] = {
{ DELL_DDV_GUID, NULL },
{ }
@@ -364,6 +870,8 @@ MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);
static struct wmi_driver dell_wmi_ddv_driver = {
.driver = {
.name = DRIVER_NAME,
+ .probe_type = PROBE_PREFER_ASYNCHRONOUS,
+ .pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops),
},
.id_table = dell_wmi_ddv_id_table,
.probe = dell_wmi_ddv_probe,
diff --git a/drivers/platform/x86/dell/dell-wmi-privacy.c b/drivers/platform/x86/dell/dell-wmi-privacy.c
index c82b3d6867c5..c517bd45dd32 100644
--- a/drivers/platform/x86/dell/dell-wmi-privacy.c
+++ b/drivers/platform/x86/dell/dell-wmi-privacy.c
@@ -61,7 +61,7 @@ static const struct key_entry dell_wmi_keymap_type_0012[] = {
/* privacy mic mute */
{ KE_KEY, 0x0001, { KEY_MICMUTE } },
/* privacy camera mute */
- { KE_SW, 0x0002, { SW_CAMERA_LENS_COVER } },
+ { KE_VSW, 0x0002, { SW_CAMERA_LENS_COVER } },
{ KE_END, 0},
};
@@ -115,11 +115,15 @@ bool dell_privacy_process_event(int type, int code, int status)
switch (code) {
case DELL_PRIVACY_AUDIO_EVENT: /* Mic mute */
- case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
priv->last_status = status;
sparse_keymap_report_entry(priv->input_dev, key, 1, true);
ret = true;
break;
+ case DELL_PRIVACY_CAMERA_EVENT: /* Camera mute */
+ priv->last_status = status;
+ sparse_keymap_report_entry(priv->input_dev, key, !(status & CAMERA_STATUS), false);
+ ret = true;
+ break;
default:
dev_dbg(&priv->wdev->dev, "unknown event type 0x%04x 0x%04x\n", type, code);
}
@@ -292,7 +296,7 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
{
struct privacy_wmi_data *priv;
struct key_entry *keymap;
- int ret, i;
+ int ret, i, j;
ret = wmi_has_guid(DELL_PRIVACY_GUID);
if (!ret)
@@ -304,6 +308,11 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
dev_set_drvdata(&wdev->dev, priv);
priv->wdev = wdev;
+
+ ret = get_current_status(priv->wdev);
+ if (ret)
+ return ret;
+
/* create evdev passing interface */
priv->input_dev = devm_input_allocate_device(&wdev->dev);
if (!priv->input_dev)
@@ -318,9 +327,20 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
/* remap the keymap code with Dell privacy key type 0x12 as prefix
* KEY_MICMUTE scancode will be reported as 0x120001
*/
- for (i = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
- keymap[i] = dell_wmi_keymap_type_0012[i];
- keymap[i].code |= (0x0012 << 16);
+ for (i = 0, j = 0; i < ARRAY_SIZE(dell_wmi_keymap_type_0012); i++) {
+ /*
+ * Unlike keys where only presses matter, userspace may act
+ * on switches in both of their positions. Only register
+ * SW_CAMERA_LENS_COVER if it is actually there.
+ */
+ if (dell_wmi_keymap_type_0012[i].type == KE_VSW &&
+ dell_wmi_keymap_type_0012[i].sw.code == SW_CAMERA_LENS_COVER &&
+ !(priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA)))
+ continue;
+
+ keymap[j] = dell_wmi_keymap_type_0012[i];
+ keymap[j].code |= (0x0012 << 16);
+ j++;
}
ret = sparse_keymap_setup(priv->input_dev, keymap, NULL);
kfree(keymap);
@@ -331,11 +351,12 @@ static int dell_privacy_wmi_probe(struct wmi_device *wdev, const void *context)
priv->input_dev->name = "Dell Privacy Driver";
priv->input_dev->id.bustype = BUS_HOST;
- ret = input_register_device(priv->input_dev);
- if (ret)
- return ret;
+ /* Report initial camera-cover status */
+ if (priv->features_present & BIT(DELL_PRIVACY_TYPE_CAMERA))
+ input_report_switch(priv->input_dev, SW_CAMERA_LENS_COVER,
+ !(priv->last_status & CAMERA_STATUS));
- ret = get_current_status(priv->wdev);
+ ret = input_register_device(priv->input_dev);
if (ret)
return ret;
diff --git a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
index 0a6411a8a104..0285b47d99d1 100644
--- a/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
+++ b/drivers/platform/x86/dell/dell-wmi-sysman/sysman.c
@@ -255,7 +255,7 @@ static void attr_name_release(struct kobject *kobj)
kfree(kobj);
}
-static struct kobj_type attr_name_ktype = {
+static const struct kobj_type attr_name_ktype = {
.release = attr_name_release,
.sysfs_ops = &wmi_sysman_kobj_sysfs_ops,
};
diff --git a/drivers/platform/x86/gigabyte-wmi.c b/drivers/platform/x86/gigabyte-wmi.c
index 5e7e6659a849..322cfaeda17b 100644
--- a/drivers/platform/x86/gigabyte-wmi.c
+++ b/drivers/platform/x86/gigabyte-wmi.c
@@ -141,6 +141,7 @@ static u8 gigabyte_wmi_detect_sensor_usability(struct wmi_device *wdev)
static const struct dmi_system_id gigabyte_wmi_known_working_platforms[] = {
DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H-CF"),
+ DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M DS3H WIFI-CF"),
DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B450M S2H V2"),
DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE AX V2"),
DMI_EXACT_MATCH_GIGABYTE_BOARD_NAME("B550 AORUS ELITE"),
diff --git a/drivers/platform/x86/hp/hp-wmi.c b/drivers/platform/x86/hp/hp-wmi.c
index 0a99058be813..873f59c3e280 100644
--- a/drivers/platform/x86/hp/hp-wmi.c
+++ b/drivers/platform/x86/hp/hp-wmi.c
@@ -90,6 +90,7 @@ enum hp_wmi_event_ids {
HPWMI_PEAKSHIFT_PERIOD = 0x0F,
HPWMI_BATTERY_CHARGE_PERIOD = 0x10,
HPWMI_SANITIZATION_MODE = 0x17,
+ HPWMI_OMEN_KEY = 0x1D,
HPWMI_SMART_EXPERIENCE_APP = 0x21,
};
@@ -216,6 +217,10 @@ static const struct key_entry hp_wmi_keymap[] = {
{ KE_KEY, 0x213b, { KEY_INFO } },
{ KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
{ KE_KEY, 0x216a, { KEY_SETUP } },
+ { KE_IGNORE, 0x21a4, }, /* Win Lock On */
+ { KE_IGNORE, 0x121a4, }, /* Win Lock Off */
+ { KE_KEY, 0x21a5, { KEY_PROG2 } }, /* HP Omen Key */
+ { KE_KEY, 0x21a7, { KEY_FN_ESC } },
{ KE_KEY, 0x21a9, { KEY_TOUCHPAD_OFF } },
{ KE_KEY, 0x121a9, { KEY_TOUCHPAD_ON } },
{ KE_KEY, 0x231b, { KEY_HELP } },
@@ -548,7 +553,7 @@ static int __init hp_wmi_enable_hotkeys(void)
static int hp_wmi_set_block(void *data, bool blocked)
{
- enum hp_wmi_radio r = (enum hp_wmi_radio) data;
+ enum hp_wmi_radio r = (long)data;
int query = BIT(r + 8) | ((!blocked) << r);
int ret;
@@ -810,6 +815,7 @@ static void hp_wmi_notify(u32 value, void *context)
case HPWMI_SMART_ADAPTER:
break;
case HPWMI_BEZEL_BUTTON:
+ case HPWMI_OMEN_KEY:
key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
if (key_code < 0)
break;
diff --git a/drivers/platform/x86/ideapad-laptop.c b/drivers/platform/x86/ideapad-laptop.c
index 435d2d3d903b..0eb5bfdd823a 100644
--- a/drivers/platform/x86/ideapad-laptop.c
+++ b/drivers/platform/x86/ideapad-laptop.c
@@ -1621,6 +1621,12 @@ static const struct dmi_system_id set_fn_lock_led_list[] = {
DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion R7000P2020H"),
}
},
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "Lenovo Legion 5 15ARH05"),
+ }
+ },
{}
};
diff --git a/drivers/platform/x86/intel/Kconfig b/drivers/platform/x86/intel/Kconfig
index d5a33473e838..bbbd9e54e9ee 100644
--- a/drivers/platform/x86/intel/Kconfig
+++ b/drivers/platform/x86/intel/Kconfig
@@ -182,6 +182,19 @@ config INTEL_SMARTCONNECT
This driver checks to determine whether the device has Intel Smart
Connect enabled, and if so disables it.
+config INTEL_TPMI
+ tristate "Intel Topology Aware Register and PM Capsule Interface (TPMI)"
+ depends on INTEL_VSEC
+ depends on X86_64
+ help
+ The Intel Topology Aware Register and PM Capsule Interface (TPMI),
+ provides enumerable MMIO interface for power management features.
+ This driver creates devices, so that other PM feature driver can
+ be loaded for PM specific feature operation.
+
+ To compile this driver as a module, choose M here: the module will
+ be called intel_vsec_tpmi.
+
config INTEL_TURBO_MAX_3
bool "Intel Turbo Boost Max Technology 3.0 enumeration driver"
depends on X86_64 && SCHED_MC_PRIO
diff --git a/drivers/platform/x86/intel/Makefile b/drivers/platform/x86/intel/Makefile
index 717933dd0cfd..411df4040427 100644
--- a/drivers/platform/x86/intel/Makefile
+++ b/drivers/platform/x86/intel/Makefile
@@ -47,6 +47,10 @@ obj-$(CONFIG_INTEL_MRFLD_PWRBTN) += intel_mrfld_pwrbtn.o
intel_punit_ipc-y := punit_ipc.o
obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
+# TPMI drivers
+intel_vsec_tpmi-y := tpmi.o
+obj-$(CONFIG_INTEL_TPMI) += intel_vsec_tpmi.o
+
# Intel Uncore drivers
intel-rst-y := rst.o
obj-$(CONFIG_INTEL_RST) += intel-rst.o
diff --git a/drivers/platform/x86/intel/int1092/intel_sar.c b/drivers/platform/x86/intel/int1092/intel_sar.c
index e03943e6380a..352fc4596494 100644
--- a/drivers/platform/x86/intel/int1092/intel_sar.c
+++ b/drivers/platform/x86/intel/int1092/intel_sar.c
@@ -131,16 +131,15 @@ static acpi_status sar_get_device_mode(struct platform_device *device)
acpi_status status = AE_OK;
union acpi_object *out;
u32 rev = 0;
- int value;
- out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
- COMMAND_ID_DEV_MODE, NULL);
- if (get_int_value(out, &value)) {
+ out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
+ COMMAND_ID_DEV_MODE, NULL, ACPI_TYPE_INTEGER);
+ if (!out) {
dev_err(&device->dev, "DSM cmd:%d Failed to retrieve value\n", COMMAND_ID_DEV_MODE);
status = AE_ERROR;
goto dev_mode_error;
}
- context->sar_data.device_mode = value;
+ context->sar_data.device_mode = out->integer.value;
update_sar_data(context);
sysfs_notify(&device->dev.kobj, NULL, SYSFS_DATANAME);
@@ -221,11 +220,11 @@ static void sar_get_data(int reg, struct wwan_sar_context *context)
req.type = ACPI_TYPE_INTEGER;
req.integer.value = reg;
- out = acpi_evaluate_dsm(context->handle, &context->guid, rev,
- COMMAND_ID_CONFIG_TABLE, &req);
+ out = acpi_evaluate_dsm_typed(context->handle, &context->guid, rev,
+ COMMAND_ID_CONFIG_TABLE, &req, ACPI_TYPE_PACKAGE);
if (!out)
return;
- if (out->type == ACPI_TYPE_PACKAGE && out->package.count >= 3 &&
+ if (out->package.count >= 3 &&
out->package.elements[0].type == ACPI_TYPE_INTEGER &&
out->package.elements[1].type == ACPI_TYPE_INTEGER &&
out->package.elements[2].type == ACPI_TYPE_PACKAGE &&
diff --git a/drivers/platform/x86/intel/int3472/Kconfig b/drivers/platform/x86/intel/int3472/Kconfig
index 62e5d4cf9ee5..17ae997f93ea 100644
--- a/drivers/platform/x86/intel/int3472/Kconfig
+++ b/drivers/platform/x86/intel/int3472/Kconfig
@@ -4,6 +4,7 @@ config INTEL_SKL_INT3472
depends on COMMON_CLK
depends on I2C
depends on GPIOLIB
+ depends on LEDS_CLASS
depends on REGULATOR
select MFD_CORE
select REGMAP_I2C
diff --git a/drivers/platform/x86/intel/int3472/Makefile b/drivers/platform/x86/intel/int3472/Makefile
index cfec7784c5c9..9f16cb514397 100644
--- a/drivers/platform/x86/intel/int3472/Makefile
+++ b/drivers/platform/x86/intel/int3472/Makefile
@@ -1,4 +1,4 @@
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 common.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
diff --git a/drivers/platform/x86/intel/int3472/clk_and_regulator.c b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
index b2342b3d78c7..1086c3d83494 100644
--- a/drivers/platform/x86/intel/int3472/clk_and_regulator.c
+++ b/drivers/platform/x86/intel/int3472/clk_and_regulator.c
@@ -23,8 +23,6 @@ static int skl_int3472_clk_prepare(struct clk_hw *hw)
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
gpiod_set_value_cansleep(clk->ena_gpio, 1);
- gpiod_set_value_cansleep(clk->led_gpio, 1);
-
return 0;
}
@@ -33,7 +31,6 @@ static void skl_int3472_clk_unprepare(struct clk_hw *hw)
struct int3472_gpio_clock *clk = to_int3472_clk(hw);
gpiod_set_value_cansleep(clk->ena_gpio, 0);
- gpiod_set_value_cansleep(clk->led_gpio, 0);
}
static int skl_int3472_clk_enable(struct clk_hw *hw)
@@ -89,18 +86,37 @@ static const struct clk_ops skl_int3472_clock_ops = {
.recalc_rate = skl_int3472_clk_recalc_rate,
};
-int skl_int3472_register_clock(struct int3472_discrete_device *int3472)
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio, u32 polarity)
{
+ char *path = agpio->resource_source.string_ptr;
struct clk_init_data init = {
.ops = &skl_int3472_clock_ops,
.flags = CLK_GET_RATE_NOCACHE,
};
int ret;
+ if (int3472->clock.cl)
+ return -EBUSY;
+
+ int3472->clock.ena_gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
+ "int3472,clk-enable");
+ if (IS_ERR(int3472->clock.ena_gpio))
+ return dev_err_probe(int3472->dev, PTR_ERR(int3472->clock.ena_gpio),
+ "getting clk-enable GPIO\n");
+
+ if (polarity == GPIO_ACTIVE_LOW)
+ gpiod_toggle_active_low(int3472->clock.ena_gpio);
+
+ /* Ensure the pin is in output mode and non-active state */
+ gpiod_direction_output(int3472->clock.ena_gpio, 0);
+
init.name = kasprintf(GFP_KERNEL, "%s-clk",
acpi_dev_name(int3472->adev));
- if (!init.name)
- return -ENOMEM;
+ if (!init.name) {
+ ret = -ENOMEM;
+ goto out_put_gpio;
+ }
int3472->clock.frequency = skl_int3472_get_clk_frequency(int3472);
@@ -126,14 +142,20 @@ err_unregister_clk:
clk_unregister(int3472->clock.clk);
out_free_init_name:
kfree(init.name);
+out_put_gpio:
+ gpiod_put(int3472->clock.ena_gpio);
return ret;
}
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472)
{
+ if (!int3472->clock.cl)
+ return;
+
clkdev_drop(int3472->clock.cl);
clk_unregister(int3472->clock.clk);
+ gpiod_put(int3472->clock.ena_gpio);
}
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
@@ -181,6 +203,9 @@ int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
return PTR_ERR(int3472->regulator.gpio);
}
+ /* Ensure the pin is in output mode and non-active state */
+ gpiod_direction_output(int3472->regulator.gpio, 0);
+
cfg.dev = &int3472->adev->dev;
cfg.init_data = &init_data;
cfg.ena_gpiod = int3472->regulator.gpio;
diff --git a/drivers/platform/x86/intel/int3472/common.h b/drivers/platform/x86/intel/int3472/common.h
index 53270d19c73a..61688e450ce5 100644
--- a/drivers/platform/x86/intel/int3472/common.h
+++ b/drivers/platform/x86/intel/int3472/common.h
@@ -6,6 +6,7 @@
#include <linux/clk-provider.h>
#include <linux/gpio/machine.h>
+#include <linux/leds.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/types.h>
@@ -28,6 +29,8 @@
#define GPIO_REGULATOR_NAME_LENGTH 21
#define GPIO_REGULATOR_SUPPLY_NAME_LENGTH 9
+#define INT3472_LED_MAX_NAME_LEN 32
+
#define CIO2_SENSOR_SSDB_MCLKSPEED_OFFSET 86
#define INT3472_REGULATOR(_name, _supply, _ops) \
@@ -96,10 +99,16 @@ struct int3472_discrete_device {
struct clk_hw clk_hw;
struct clk_lookup *cl;
struct gpio_desc *ena_gpio;
- struct gpio_desc *led_gpio;
u32 frequency;
} clock;
+ struct int3472_pled {
+ struct led_classdev classdev;
+ struct led_lookup_data lookup;
+ char name[INT3472_LED_MAX_NAME_LEN];
+ struct gpio_desc *gpio;
+ } pled;
+
unsigned int ngpios; /* how many GPIOs have we seen */
unsigned int n_sensor_gpios; /* how many have we mapped to sensor */
struct gpiod_lookup_table gpios;
@@ -112,11 +121,16 @@ int skl_int3472_get_sensor_adev_and_name(struct device *dev,
struct acpi_device **sensor_adev_ret,
const char **name_ret);
-int skl_int3472_register_clock(struct int3472_discrete_device *int3472);
+int skl_int3472_register_clock(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio, u32 polarity);
void skl_int3472_unregister_clock(struct int3472_discrete_device *int3472);
int skl_int3472_register_regulator(struct int3472_discrete_device *int3472,
struct acpi_resource_gpio *agpio);
void skl_int3472_unregister_regulator(struct int3472_discrete_device *int3472);
+int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio, u32 polarity);
+void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472);
+
#endif
diff --git a/drivers/platform/x86/intel/int3472/discrete.c b/drivers/platform/x86/intel/int3472/discrete.c
index 974a132db651..f064da74f50a 100644
--- a/drivers/platform/x86/intel/int3472/discrete.c
+++ b/drivers/platform/x86/intel/int3472/discrete.c
@@ -2,8 +2,6 @@
/* Author: Dan Scally <djrscally@gmail.com> */
#include <linux/acpi.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
#include <linux/device.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/machine.h>
@@ -80,14 +78,6 @@ skl_int3472_get_sensor_module_config(struct int3472_discrete_device *int3472)
return ERR_PTR(-ENODEV);
}
- if (obj->string.type != ACPI_TYPE_STRING) {
- dev_err(int3472->dev,
- "Sensor _DSM returned a non-string value\n");
-
- ACPI_FREE(obj);
- return ERR_PTR(-EINVAL);
- }
-
for (i = 0; i < ARRAY_SIZE(int3472_sensor_configs); i++) {
if (!strcmp(int3472_sensor_configs[i].sensor_module_name,
obj->string.pointer))
@@ -154,34 +144,34 @@ static int skl_int3472_map_gpio_to_sensor(struct int3472_discrete_device *int347
return 0;
}
-static int skl_int3472_map_gpio_to_clk(struct int3472_discrete_device *int3472,
- struct acpi_resource_gpio *agpio, u8 type)
+static void int3472_get_func_and_polarity(u8 type, const char **func, u32 *polarity)
{
- char *path = agpio->resource_source.string_ptr;
- u16 pin = agpio->pin_table[0];
- struct gpio_desc *gpio;
-
switch (type) {
+ case INT3472_GPIO_TYPE_RESET:
+ *func = "reset";
+ *polarity = GPIO_ACTIVE_LOW;
+ break;
+ case INT3472_GPIO_TYPE_POWERDOWN:
+ *func = "powerdown";
+ *polarity = GPIO_ACTIVE_LOW;
+ break;
case INT3472_GPIO_TYPE_CLK_ENABLE:
- gpio = acpi_get_and_request_gpiod(path, pin, "int3472,clk-enable");
- if (IS_ERR(gpio))
- return (PTR_ERR(gpio));
-
- int3472->clock.ena_gpio = gpio;
+ *func = "clk-enable";
+ *polarity = GPIO_ACTIVE_HIGH;
break;
case INT3472_GPIO_TYPE_PRIVACY_LED:
- gpio = acpi_get_and_request_gpiod(path, pin, "int3472,privacy-led");
- if (IS_ERR(gpio))
- return (PTR_ERR(gpio));
-
- int3472->clock.led_gpio = gpio;
+ *func = "privacy-led";
+ *polarity = GPIO_ACTIVE_HIGH;
+ break;
+ case INT3472_GPIO_TYPE_POWER_ENABLE:
+ *func = "power-enable";
+ *polarity = GPIO_ACTIVE_HIGH;
break;
default:
- dev_err(int3472->dev, "Invalid GPIO type 0x%02x for clock\n", type);
+ *func = "unknown";
+ *polarity = GPIO_ACTIVE_HIGH;
break;
}
-
- return 0;
}
/**
@@ -222,9 +212,11 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
struct int3472_discrete_device *int3472 = data;
struct acpi_resource_gpio *agpio;
union acpi_object *obj;
+ u8 active_value, type;
const char *err_msg;
+ const char *func;
+ u32 polarity;
int ret;
- u8 type;
if (!acpi_gpio_get_io_resource(ares, &agpio))
return 1;
@@ -246,26 +238,35 @@ static int skl_int3472_handle_gpio_resources(struct acpi_resource *ares,
type = obj->integer.value & 0xff;
+ int3472_get_func_and_polarity(type, &func, &polarity);
+
+ /* If bits 31-24 of the _DSM entry are all 0 then the signal is inverted */
+ active_value = obj->integer.value >> 24;
+ if (!active_value)
+ polarity ^= GPIO_ACTIVE_LOW;
+
+ 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");
+
switch (type) {
case INT3472_GPIO_TYPE_RESET:
- ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "reset",
- GPIO_ACTIVE_LOW);
+ case INT3472_GPIO_TYPE_POWERDOWN:
+ ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, func, polarity);
if (ret)
- err_msg = "Failed to map reset pin to sensor\n";
+ err_msg = "Failed to map GPIO pin to sensor\n";
break;
- case INT3472_GPIO_TYPE_POWERDOWN:
- ret = skl_int3472_map_gpio_to_sensor(int3472, agpio, "powerdown",
- GPIO_ACTIVE_LOW);
+ case INT3472_GPIO_TYPE_CLK_ENABLE:
+ ret = skl_int3472_register_clock(int3472, agpio, polarity);
if (ret)
- err_msg = "Failed to map powerdown pin to sensor\n";
+ err_msg = "Failed to register clock\n";
break;
- case INT3472_GPIO_TYPE_CLK_ENABLE:
case INT3472_GPIO_TYPE_PRIVACY_LED:
- ret = skl_int3472_map_gpio_to_clk(int3472, agpio, type);
+ ret = skl_int3472_register_pled(int3472, agpio, polarity);
if (ret)
- err_msg = "Failed to map GPIO to clock\n";
+ err_msg = "Failed to register LED\n";
break;
case INT3472_GPIO_TYPE_POWER_ENABLE:
@@ -310,21 +311,6 @@ static int skl_int3472_parse_crs(struct int3472_discrete_device *int3472)
acpi_dev_free_resource_list(&resource_list);
- /*
- * If we find no clock enable GPIO pin then the privacy LED won't work.
- * We've never seen that situation, but it's possible. Warn the user so
- * it's clear what's happened.
- */
- if (int3472->clock.ena_gpio) {
- ret = skl_int3472_register_clock(int3472);
- if (ret)
- return ret;
- } else {
- if (int3472->clock.led_gpio)
- dev_warn(int3472->dev,
- "No clk GPIO. The privacy LED won't work\n");
- }
-
int3472->gpios.dev_id = int3472->sensor_name;
gpiod_add_lookup_table(&int3472->gpios);
@@ -337,12 +323,8 @@ static int skl_int3472_discrete_remove(struct platform_device *pdev)
gpiod_remove_lookup_table(&int3472->gpios);
- if (int3472->clock.cl)
- skl_int3472_unregister_clock(int3472);
-
- gpiod_put(int3472->clock.ena_gpio);
- gpiod_put(int3472->clock.led_gpio);
-
+ skl_int3472_unregister_clock(int3472);
+ skl_int3472_unregister_pled(int3472);
skl_int3472_unregister_regulator(int3472);
return 0;
diff --git a/drivers/platform/x86/intel/int3472/led.c b/drivers/platform/x86/intel/int3472/led.c
new file mode 100644
index 000000000000..bca1ce7d0d0c
--- /dev/null
+++ b/drivers/platform/x86/intel/int3472/led.c
@@ -0,0 +1,75 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Author: Hans de Goede <hdegoede@redhat.com> */
+
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/leds.h>
+#include "common.h"
+
+static int int3472_pled_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct int3472_discrete_device *int3472 =
+ container_of(led_cdev, struct int3472_discrete_device, pled.classdev);
+
+ gpiod_set_value_cansleep(int3472->pled.gpio, brightness);
+ return 0;
+}
+
+int skl_int3472_register_pled(struct int3472_discrete_device *int3472,
+ struct acpi_resource_gpio *agpio, u32 polarity)
+{
+ char *p, *path = agpio->resource_source.string_ptr;
+ int ret;
+
+ if (int3472->pled.classdev.dev)
+ return -EBUSY;
+
+ int3472->pled.gpio = acpi_get_and_request_gpiod(path, agpio->pin_table[0],
+ "int3472,privacy-led");
+ if (IS_ERR(int3472->pled.gpio))
+ return dev_err_probe(int3472->dev, PTR_ERR(int3472->pled.gpio),
+ "getting privacy LED GPIO\n");
+
+ if (polarity == GPIO_ACTIVE_LOW)
+ gpiod_toggle_active_low(int3472->pled.gpio);
+
+ /* Ensure the pin is in output mode and non-active state */
+ gpiod_direction_output(int3472->pled.gpio, 0);
+
+ /* Generate the name, replacing the ':' in the ACPI devname with '_' */
+ snprintf(int3472->pled.name, sizeof(int3472->pled.name),
+ "%s::privacy_led", acpi_dev_name(int3472->sensor));
+ p = strchr(int3472->pled.name, ':');
+ if (p)
+ *p = '_';
+
+ int3472->pled.classdev.name = int3472->pled.name;
+ int3472->pled.classdev.max_brightness = 1;
+ int3472->pled.classdev.brightness_set_blocking = int3472_pled_set;
+
+ ret = led_classdev_register(int3472->dev, &int3472->pled.classdev);
+ if (ret)
+ goto err_free_gpio;
+
+ int3472->pled.lookup.provider = int3472->pled.name;
+ int3472->pled.lookup.dev_id = int3472->sensor_name;
+ int3472->pled.lookup.con_id = "privacy-led";
+ led_add_lookup(&int3472->pled.lookup);
+
+ return 0;
+
+err_free_gpio:
+ gpiod_put(int3472->pled.gpio);
+ return ret;
+}
+
+void skl_int3472_unregister_pled(struct int3472_discrete_device *int3472)
+{
+ if (IS_ERR_OR_NULL(int3472->pled.classdev.dev))
+ return;
+
+ led_remove_lookup(&int3472->pled.lookup);
+ led_classdev_unregister(&int3472->pled.classdev);
+ gpiod_put(int3472->pled.gpio);
+}
diff --git a/drivers/platform/x86/intel/oaktrail.c b/drivers/platform/x86/intel/oaktrail.c
index 7c5c623630c1..fa720967e69b 100644
--- a/drivers/platform/x86/intel/oaktrail.c
+++ b/drivers/platform/x86/intel/oaktrail.c
@@ -266,17 +266,11 @@ static int oaktrail_probe(struct platform_device *pdev)
return 0;
}
-static int oaktrail_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static struct platform_driver oaktrail_driver = {
.driver = {
.name = DRIVER_NAME,
},
.probe = oaktrail_probe,
- .remove = oaktrail_remove,
};
static int dmi_check_cb(const struct dmi_system_id *id)
diff --git a/drivers/platform/x86/intel/pmc/core.c b/drivers/platform/x86/intel/pmc/core.c
index f1d802f6ec3f..3a15d32d7644 100644
--- a/drivers/platform/x86/intel/pmc/core.c
+++ b/drivers/platform/x86/intel/pmc/core.c
@@ -1029,6 +1029,7 @@ static const struct x86_cpu_id intel_pmc_core_ids[] = {
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, adl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_S, adl_core_init),
X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE, mtl_core_init),
+ X86_MATCH_INTEL_FAM6_MODEL(METEORLAKE_L, mtl_core_init),
{}
};
diff --git a/drivers/platform/x86/intel/pmc/tgl.c b/drivers/platform/x86/intel/pmc/tgl.c
index e3e50538465d..c245ada849d0 100644
--- a/drivers/platform/x86/intel/pmc/tgl.c
+++ b/drivers/platform/x86/intel/pmc/tgl.c
@@ -221,9 +221,9 @@ void pmc_core_get_tgl_lpm_reqs(struct platform_device *pdev)
guid_parse(ACPI_S0IX_DSM_UUID, &s0ix_dsm_guid);
- out_obj = acpi_evaluate_dsm(adev->handle, &s0ix_dsm_guid, 0,
- ACPI_GET_LOW_MODE_REGISTERS, NULL);
- if (out_obj && out_obj->type == ACPI_TYPE_BUFFER) {
+ out_obj = acpi_evaluate_dsm_typed(adev->handle, &s0ix_dsm_guid, 0,
+ ACPI_GET_LOW_MODE_REGISTERS, NULL, ACPI_TYPE_BUFFER);
+ if (out_obj) {
u32 size = out_obj->buffer.length;
if (size != lpm_size) {
diff --git a/drivers/platform/x86/intel/punit_ipc.c b/drivers/platform/x86/intel/punit_ipc.c
index 66bb39fd0ef9..cd0ba84cc8e4 100644
--- a/drivers/platform/x86/intel/punit_ipc.c
+++ b/drivers/platform/x86/intel/punit_ipc.c
@@ -302,11 +302,6 @@ static int intel_punit_ipc_probe(struct platform_device *pdev)
return 0;
}
-static int intel_punit_ipc_remove(struct platform_device *pdev)
-{
- return 0;
-}
-
static const struct acpi_device_id punit_ipc_acpi_ids[] = {
{ "INT34D4", 0 },
{ }
@@ -315,7 +310,6 @@ MODULE_DEVICE_TABLE(acpi, punit_ipc_acpi_ids);
static struct platform_driver intel_punit_ipc_driver = {
.probe = intel_punit_ipc_probe,
- .remove = intel_punit_ipc_remove,
.driver = {
.name = "intel_punit_ipc",
.acpi_match_table = punit_ipc_acpi_ids,
diff --git a/drivers/platform/x86/intel/tpmi.c b/drivers/platform/x86/intel/tpmi.c
new file mode 100644
index 000000000000..c60733261c89
--- /dev/null
+++ b/drivers/platform/x86/intel/tpmi.c
@@ -0,0 +1,415 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * intel-tpmi : Driver to enumerate TPMI features and create devices
+ *
+ * Copyright (c) 2023, Intel Corporation.
+ * All Rights Reserved.
+ *
+ * The TPMI (Topology Aware Register and PM Capsule Interface) provides a
+ * flexible, extendable and PCIe enumerable MMIO interface for PM features.
+ *
+ * For example Intel RAPL (Running Average Power Limit) provides a MMIO
+ * interface using TPMI. This has advantage over traditional MSR
+ * (Model Specific Register) interface, where a thread needs to be scheduled
+ * on the target CPU to read or write. Also the RAPL features vary between
+ * CPU models, and hence lot of model specific code. Here TPMI provides an
+ * architectural interface by providing hierarchical tables and fields,
+ * which will not need any model specific implementation.
+ *
+ * The TPMI interface uses a PCI VSEC structure to expose the location of
+ * MMIO region.
+ *
+ * This VSEC structure is present in the PCI configuration space of the
+ * Intel Out-of-Band (OOB) device, which is handled by the Intel VSEC
+ * driver. The Intel VSEC driver parses VSEC structures present in the PCI
+ * configuration space of the given device and creates an auxiliary device
+ * object for each of them. In particular, it creates an auxiliary device
+ * object representing TPMI that can be bound by an auxiliary driver.
+ *
+ * This TPMI driver will bind to the TPMI auxiliary device object created
+ * by the Intel VSEC driver.
+ *
+ * The TPMI specification defines a PFS (PM Feature Structure) table.
+ * This table is present in the TPMI MMIO region. The starting address
+ * of PFS is derived from the tBIR (Bar Indicator Register) and "Address"
+ * field from the VSEC header.
+ *
+ * Each TPMI PM feature has one entry in the PFS with a unique TPMI
+ * ID and its access details. The TPMI driver creates device nodes
+ * for the supported PM features.
+ *
+ * The names of the devices created by the TPMI driver start with the
+ * "intel_vsec.tpmi-" prefix which is followed by a specific name of the
+ * given PM feature (for example, "intel_vsec.tpmi-rapl.0").
+ *
+ * The device nodes are create by using interface "intel_vsec_add_aux()"
+ * provided by the Intel VSEC driver.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/intel_tpmi.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pci.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).
+ * @num_entries: Number of feature interface instances present in the PFS.
+ * This represents the maximum number of Power domains in the SoC.
+ * @entry_size: Interface instance entry size in 32-bit words.
+ * @cap_offset: Offset from the PM_Features base address to the base of the PM VSEC
+ * register bank in KB.
+ * @attribute: Feature attribute: 0=BIOS. 1=OS. 2-3=Reserved.
+ * @reserved: Bits for use in the future.
+ *
+ * Represents one TPMI feature entry data in the PFS retrieved as is
+ * from the hardware.
+ */
+struct intel_tpmi_pfs_entry {
+ u64 tpmi_id:8;
+ u64 num_entries:8;
+ u64 entry_size:16;
+ u64 cap_offset:16;
+ u64 attribute:2;
+ u64 reserved:14;
+} __packed;
+
+/**
+ * struct intel_tpmi_pm_feature - TPMI PM Feature information for a TPMI ID
+ * @pfs_header: PFS header retireved from the hardware.
+ * @vsec_offset: Starting MMIO address for this feature in bytes. Essentially
+ * this offset = "Address" from VSEC header + PFS Capability
+ * offset for this feature entry.
+ *
+ * Represents TPMI instance information for one TPMI ID.
+ */
+struct intel_tpmi_pm_feature {
+ struct intel_tpmi_pfs_entry pfs_header;
+ unsigned int vsec_offset;
+};
+
+/**
+ * struct intel_tpmi_info - TPMI information for all IDs in an instance
+ * @tpmi_features: Pointer to a list of TPMI feature instances
+ * @vsec_dev: Pointer to intel_vsec_device structure for this TPMI device
+ * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features
+ * @pfs_start: Start of PFS offset for the TPMI instances in this device
+ * @plat_info: Stores platform info which can be used by the client drivers
+ *
+ * Stores the information for all TPMI devices enumerated from a single PCI device.
+ */
+struct intel_tpmi_info {
+ struct intel_tpmi_pm_feature *tpmi_features;
+ struct intel_vsec_device *vsec_dev;
+ int feature_count;
+ u64 pfs_start;
+ struct intel_tpmi_plat_info plat_info;
+};
+
+/**
+ * struct tpmi_info_header - CPU package ID to PCI device mapping information
+ * @fn: PCI function number
+ * @dev: PCI device number
+ * @bus: PCI bus number
+ * @pkg: CPU Package id
+ * @reserved: Reserved for future use
+ * @lock: When set to 1 the register is locked and becomes read-only
+ * until next reset. Not for use by the OS driver.
+ *
+ * The structure to read hardware provided mapping information.
+ */
+struct tpmi_info_header {
+ u64 fn:3;
+ u64 dev:5;
+ u64 bus:8;
+ u64 pkg:8;
+ u64 reserved:39;
+ u64 lock:1;
+} __packed;
+
+/*
+ * List of supported TMPI IDs.
+ * Some TMPI IDs are not used by Linux, so the numbers are not consecutive.
+ */
+enum intel_tpmi_id {
+ TPMI_ID_RAPL = 0, /* Running Average Power Limit */
+ TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */
+ TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */
+ TPMI_ID_SST = 5, /* Speed Select Technology */
+ TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */
+};
+
+/* Used during auxbus device creation */
+static DEFINE_IDA(intel_vsec_tpmi_ida);
+
+struct intel_tpmi_plat_info *tpmi_get_platform_data(struct auxiliary_device *auxdev)
+{
+ struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
+
+ return vsec_dev->priv_data;
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_get_platform_data, INTEL_TPMI);
+
+int tpmi_get_resource_count(struct auxiliary_device *auxdev)
+{
+ struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
+
+ if (vsec_dev)
+ return vsec_dev->num_resources;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_count, INTEL_TPMI);
+
+struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index)
+{
+ struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
+
+ if (vsec_dev && index < vsec_dev->num_resources)
+ return &vsec_dev->resource[index];
+
+ return NULL;
+}
+EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI);
+
+static const char *intel_tpmi_name(enum intel_tpmi_id id)
+{
+ switch (id) {
+ case TPMI_ID_RAPL:
+ return "rapl";
+ case TPMI_ID_PEM:
+ return "pem";
+ case TPMI_ID_UNCORE:
+ return "uncore";
+ case TPMI_ID_SST:
+ return "sst";
+ default:
+ return NULL;
+ }
+}
+
+/* String Length for tpmi-"feature_name(upto 8 bytes)" */
+#define TPMI_FEATURE_NAME_LEN 14
+
+static int tpmi_create_device(struct intel_tpmi_info *tpmi_info,
+ struct intel_tpmi_pm_feature *pfs,
+ u64 pfs_start)
+{
+ struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev;
+ char feature_id_name[TPMI_FEATURE_NAME_LEN];
+ struct intel_vsec_device *feature_vsec_dev;
+ struct resource *res, *tmp;
+ const char *name;
+ int ret, i;
+
+ name = intel_tpmi_name(pfs->pfs_header.tpmi_id);
+ if (!name)
+ return -EOPNOTSUPP;
+
+ feature_vsec_dev = kzalloc(sizeof(*feature_vsec_dev), GFP_KERNEL);
+ if (!feature_vsec_dev)
+ return -ENOMEM;
+
+ res = kcalloc(pfs->pfs_header.num_entries, sizeof(*res), GFP_KERNEL);
+ if (!res) {
+ ret = -ENOMEM;
+ goto free_vsec;
+ }
+
+ snprintf(feature_id_name, sizeof(feature_id_name), "tpmi-%s", name);
+
+ for (i = 0, tmp = res; i < pfs->pfs_header.num_entries; i++, tmp++) {
+ u64 entry_size_bytes = pfs->pfs_header.entry_size * 4;
+
+ tmp->start = pfs->vsec_offset + entry_size_bytes * i;
+ tmp->end = tmp->start + entry_size_bytes - 1;
+ tmp->flags = IORESOURCE_MEM;
+ }
+
+ feature_vsec_dev->pcidev = vsec_dev->pcidev;
+ feature_vsec_dev->resource = res;
+ feature_vsec_dev->num_resources = pfs->pfs_header.num_entries;
+ feature_vsec_dev->priv_data = &tpmi_info->plat_info;
+ feature_vsec_dev->priv_data_size = sizeof(tpmi_info->plat_info);
+ feature_vsec_dev->ida = &intel_vsec_tpmi_ida;
+
+ /*
+ * intel_vsec_add_aux() is resource managed, no explicit
+ * delete is required on error or on module unload.
+ */
+ ret = intel_vsec_add_aux(vsec_dev->pcidev, &vsec_dev->auxdev.dev,
+ feature_vsec_dev, feature_id_name);
+ if (ret)
+ goto free_res;
+
+ return 0;
+
+free_res:
+ kfree(res);
+free_vsec:
+ kfree(feature_vsec_dev);
+
+ return ret;
+}
+
+static int tpmi_create_devices(struct intel_tpmi_info *tpmi_info)
+{
+ struct intel_vsec_device *vsec_dev = tpmi_info->vsec_dev;
+ int ret, i;
+
+ for (i = 0; i < vsec_dev->num_resources; i++) {
+ ret = tpmi_create_device(tpmi_info, &tpmi_info->tpmi_features[i],
+ tpmi_info->pfs_start);
+ /*
+ * Fail, if the supported features fails to create device,
+ * otherwise, continue. Even if one device failed to create,
+ * fail the loading of driver. Since intel_vsec_add_aux()
+ * is resource managed, no clean up is required for the
+ * successfully created devices.
+ */
+ if (ret && ret != -EOPNOTSUPP)
+ return ret;
+ }
+
+ return 0;
+}
+
+#define TPMI_INFO_BUS_INFO_OFFSET 0x08
+
+static int tpmi_process_info(struct intel_tpmi_info *tpmi_info,
+ struct intel_tpmi_pm_feature *pfs)
+{
+ struct tpmi_info_header header;
+ void __iomem *info_mem;
+
+ info_mem = ioremap(pfs->vsec_offset + TPMI_INFO_BUS_INFO_OFFSET,
+ pfs->pfs_header.entry_size * 4 - TPMI_INFO_BUS_INFO_OFFSET);
+ if (!info_mem)
+ return -ENOMEM;
+
+ memcpy_fromio(&header, info_mem, sizeof(header));
+
+ tpmi_info->plat_info.package_id = header.pkg;
+ tpmi_info->plat_info.bus_number = header.bus;
+ tpmi_info->plat_info.device_number = header.dev;
+ tpmi_info->plat_info.function_number = header.fn;
+
+ iounmap(info_mem);
+
+ return 0;
+}
+
+static int tpmi_fetch_pfs_header(struct intel_tpmi_pm_feature *pfs, u64 start, int size)
+{
+ void __iomem *pfs_mem;
+
+ pfs_mem = ioremap(start, size);
+ if (!pfs_mem)
+ return -ENOMEM;
+
+ memcpy_fromio(&pfs->pfs_header, pfs_mem, sizeof(pfs->pfs_header));
+
+ iounmap(pfs_mem);
+
+ return 0;
+}
+
+static int intel_vsec_tpmi_init(struct auxiliary_device *auxdev)
+{
+ struct intel_vsec_device *vsec_dev = auxdev_to_ivdev(auxdev);
+ struct pci_dev *pci_dev = vsec_dev->pcidev;
+ struct intel_tpmi_info *tpmi_info;
+ u64 pfs_start = 0;
+ int i;
+
+ tpmi_info = devm_kzalloc(&auxdev->dev, sizeof(*tpmi_info), GFP_KERNEL);
+ if (!tpmi_info)
+ return -ENOMEM;
+
+ tpmi_info->vsec_dev = vsec_dev;
+ tpmi_info->feature_count = vsec_dev->num_resources;
+ tpmi_info->plat_info.bus_number = pci_dev->bus->number;
+
+ tpmi_info->tpmi_features = devm_kcalloc(&auxdev->dev, vsec_dev->num_resources,
+ sizeof(*tpmi_info->tpmi_features),
+ GFP_KERNEL);
+ if (!tpmi_info->tpmi_features)
+ return -ENOMEM;
+
+ for (i = 0; i < vsec_dev->num_resources; i++) {
+ struct intel_tpmi_pm_feature *pfs;
+ struct resource *res;
+ u64 res_start;
+ int size, ret;
+
+ pfs = &tpmi_info->tpmi_features[i];
+
+ res = &vsec_dev->resource[i];
+ if (!res)
+ continue;
+
+ res_start = res->start;
+ size = resource_size(res);
+ if (size < 0)
+ continue;
+
+ ret = tpmi_fetch_pfs_header(pfs, res_start, size);
+ if (ret)
+ continue;
+
+ if (!pfs_start)
+ pfs_start = res_start;
+
+ pfs->pfs_header.cap_offset *= 1024;
+
+ pfs->vsec_offset = pfs_start + pfs->pfs_header.cap_offset;
+
+ /*
+ * Process TPMI_INFO to get PCI device to CPU package ID.
+ * Device nodes for TPMI features are not created in this
+ * for loop. So, the mapping information will be available
+ * when actual device nodes created outside this
+ * loop via tpmi_create_devices().
+ */
+ if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID)
+ tpmi_process_info(tpmi_info, pfs);
+ }
+
+ tpmi_info->pfs_start = pfs_start;
+
+ auxiliary_set_drvdata(auxdev, tpmi_info);
+
+ return tpmi_create_devices(tpmi_info);
+}
+
+static int tpmi_probe(struct auxiliary_device *auxdev,
+ const struct auxiliary_device_id *id)
+{
+ return intel_vsec_tpmi_init(auxdev);
+}
+
+/*
+ * Remove callback is not needed currently as there is no
+ * cleanup required. All memory allocs are device managed. All
+ * devices created by this modules are also device managed.
+ */
+
+static const struct auxiliary_device_id tpmi_id_table[] = {
+ { .name = "intel_vsec.tpmi" },
+ {}
+};
+MODULE_DEVICE_TABLE(auxiliary, tpmi_id_table);
+
+static struct auxiliary_driver tpmi_aux_driver = {
+ .id_table = tpmi_id_table,
+ .probe = tpmi_probe,
+};
+
+module_auxiliary_driver(tpmi_aux_driver);
+
+MODULE_IMPORT_NS(INTEL_VSEC);
+MODULE_DESCRIPTION("Intel TPMI enumeration module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/intel/vsec.c b/drivers/platform/x86/intel/vsec.c
index bb81b8b1f7e9..13decf36c6de 100644
--- a/drivers/platform/x86/intel/vsec.c
+++ b/drivers/platform/x86/intel/vsec.c
@@ -64,6 +64,7 @@ enum intel_vsec_id {
VSEC_ID_WATCHER = 3,
VSEC_ID_CRASHLOG = 4,
VSEC_ID_SDSI = 65,
+ VSEC_ID_TPMI = 66,
};
static enum intel_vsec_id intel_vsec_allow_list[] = {
@@ -71,6 +72,7 @@ static enum intel_vsec_id intel_vsec_allow_list[] = {
VSEC_ID_WATCHER,
VSEC_ID_CRASHLOG,
VSEC_ID_SDSI,
+ VSEC_ID_TPMI,
};
static const char *intel_vsec_name(enum intel_vsec_id id)
@@ -88,6 +90,9 @@ static const char *intel_vsec_name(enum intel_vsec_id id)
case VSEC_ID_SDSI:
return "sdsi";
+ case VSEC_ID_TPMI:
+ return "tpmi";
+
default:
return NULL;
}
@@ -124,35 +129,48 @@ static void intel_vsec_remove_aux(void *data)
auxiliary_device_uninit(data);
}
+static DEFINE_MUTEX(vsec_ida_lock);
+
static void intel_vsec_dev_release(struct device *dev)
{
struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(dev);
+ mutex_lock(&vsec_ida_lock);
ida_free(intel_vsec_dev->ida, intel_vsec_dev->auxdev.id);
+ mutex_unlock(&vsec_ida_lock);
+
kfree(intel_vsec_dev->resource);
kfree(intel_vsec_dev);
}
-static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *intel_vsec_dev,
- const char *name)
+int intel_vsec_add_aux(struct pci_dev *pdev, struct device *parent,
+ struct intel_vsec_device *intel_vsec_dev,
+ const char *name)
{
struct auxiliary_device *auxdev = &intel_vsec_dev->auxdev;
int ret, id;
+ mutex_lock(&vsec_ida_lock);
ret = ida_alloc(intel_vsec_dev->ida, GFP_KERNEL);
+ mutex_unlock(&vsec_ida_lock);
if (ret < 0) {
kfree(intel_vsec_dev);
return ret;
}
+ if (!parent)
+ parent = &pdev->dev;
+
auxdev->id = ret;
auxdev->name = name;
- auxdev->dev.parent = &pdev->dev;
+ auxdev->dev.parent = parent;
auxdev->dev.release = intel_vsec_dev_release;
ret = auxiliary_device_init(auxdev);
if (ret < 0) {
+ mutex_lock(&vsec_ida_lock);
ida_free(intel_vsec_dev->ida, auxdev->id);
+ mutex_unlock(&vsec_ida_lock);
kfree(intel_vsec_dev->resource);
kfree(intel_vsec_dev);
return ret;
@@ -164,7 +182,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
return ret;
}
- ret = devm_add_action_or_reset(&pdev->dev, intel_vsec_remove_aux,
+ ret = devm_add_action_or_reset(parent, intel_vsec_remove_aux,
auxdev);
if (ret < 0)
return ret;
@@ -177,6 +195,7 @@ static int intel_vsec_add_aux(struct pci_dev *pdev, struct intel_vsec_device *in
return 0;
}
+EXPORT_SYMBOL_NS_GPL(intel_vsec_add_aux, INTEL_VSEC);
static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *header,
struct intel_vsec_platform_info *info)
@@ -234,7 +253,8 @@ static int intel_vsec_add_dev(struct pci_dev *pdev, struct intel_vsec_header *he
else
intel_vsec_dev->ida = &intel_vsec_ida;
- return intel_vsec_add_aux(pdev, intel_vsec_dev, intel_vsec_name(header->id));
+ return intel_vsec_add_aux(pdev, NULL, intel_vsec_dev,
+ intel_vsec_name(header->id));
}
static bool intel_vsec_walk_header(struct pci_dev *pdev,
@@ -408,14 +428,23 @@ static const struct intel_vsec_platform_info dg1_info = {
.quirks = VSEC_QUIRK_NO_DVSEC | VSEC_QUIRK_EARLY_HW,
};
+/* MTL info */
+static const struct intel_vsec_platform_info mtl_info = {
+ .quirks = VSEC_QUIRK_NO_WATCHER | VSEC_QUIRK_NO_CRASHLOG,
+};
+
#define PCI_DEVICE_ID_INTEL_VSEC_ADL 0x467d
#define PCI_DEVICE_ID_INTEL_VSEC_DG1 0x490e
+#define PCI_DEVICE_ID_INTEL_VSEC_MTL_M 0x7d0d
+#define PCI_DEVICE_ID_INTEL_VSEC_MTL_S 0xad0d
#define PCI_DEVICE_ID_INTEL_VSEC_OOBMSM 0x09a7
#define PCI_DEVICE_ID_INTEL_VSEC_RPL 0xa77d
#define PCI_DEVICE_ID_INTEL_VSEC_TGL 0x9a0d
static const struct pci_device_id intel_vsec_pci_ids[] = {
{ PCI_DEVICE_DATA(INTEL, VSEC_ADL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_DG1, &dg1_info) },
+ { PCI_DEVICE_DATA(INTEL, VSEC_MTL_M, &mtl_info) },
+ { PCI_DEVICE_DATA(INTEL, VSEC_MTL_S, &mtl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_OOBMSM, &(struct intel_vsec_platform_info) {}) },
{ PCI_DEVICE_DATA(INTEL, VSEC_RPL, &tgl_info) },
{ PCI_DEVICE_DATA(INTEL, VSEC_TGL, &tgl_info) },
diff --git a/drivers/platform/x86/intel/vsec.h b/drivers/platform/x86/intel/vsec.h
index 3deeb05cf394..ae8fe92c5595 100644
--- a/drivers/platform/x86/intel/vsec.h
+++ b/drivers/platform/x86/intel/vsec.h
@@ -38,8 +38,14 @@ struct intel_vsec_device {
struct ida *ida;
struct intel_vsec_platform_info *info;
int num_resources;
+ void *priv_data;
+ size_t priv_data_size;
};
+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);
diff --git a/drivers/platform/x86/mlx-platform.c b/drivers/platform/x86/mlx-platform.c
index 2fac05a17a5c..7b6779cdb134 100644
--- a/drivers/platform/x86/mlx-platform.c
+++ b/drivers/platform/x86/mlx-platform.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/platform_data/i2c-mux-reg.h>
#include <linux/platform_data/mlxreg.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
#define MLX_PLAT_DEVICE_NAME "mlxplat"
@@ -61,12 +62,19 @@
#define MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET 0x37
#define MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET 0x3a
#define MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET 0x3b
+#define MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET 0x3c
+#define MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET 0x3d
+#define MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET 0x3e
+#define MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET 0x3f
#define MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET 0x40
#define MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET 0x41
#define MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET 0x42
#define MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET 0x43
#define MLXPLAT_CPLD_LPC_REG_AGGRCX_OFFSET 0x44
#define MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET 0x45
+#define MLXPLAT_CPLD_LPC_REG_BRD_OFFSET 0x47
+#define MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET 0x48
+#define MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET 0x49
#define MLXPLAT_CPLD_LPC_REG_GWP_OFFSET 0x4a
#define MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET 0x4b
#define MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET 0x4c
@@ -90,6 +98,15 @@
#define MLXPLAT_CPLD_LPC_REG_FAN_OFFSET 0x88
#define MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET 0x89
#define MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET 0x8a
+#define MLXPLAT_CPLD_LPC_REG_EROT_OFFSET 0x91
+#define MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET 0x92
+#define MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET 0x93
+#define MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET 0x94
+#define MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET 0x95
+#define MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET 0x96
+#define MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET 0x97
+#define MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET 0x98
+#define MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET 0x99
#define MLXPLAT_CPLD_LPC_REG_LC_VR_OFFSET 0x9a
#define MLXPLAT_CPLD_LPC_REG_LC_VR_EVENT_OFFSET 0x9b
#define MLXPLAT_CPLD_LPC_REG_LC_VR_MASK_OFFSET 0x9c
@@ -109,6 +126,8 @@
#define MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET 0xaa
#define MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET 0xab
#define MLXPLAT_CPLD_LPC_REG_LC_PWR_ON 0xb2
+#define MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET 0xc2
+#define MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT 0xc3
#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET 0xc7
#define MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET 0xc8
#define MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET 0xc9
@@ -119,6 +138,11 @@
#define MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET 0xd1
#define MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET 0xd2
#define MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET 0xd3
+#define MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET 0xd9
+#define MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET 0xdb
+#define MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET 0xda
+#define MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET 0xdc
+#define MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET 0xdd
#define MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET 0xde
#define MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET 0xdf
#define MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET 0xe0
@@ -152,23 +176,19 @@
#define MLXPLAT_CPLD_LPC_REG_CONFIG2_OFFSET 0xfc
#define MLXPLAT_CPLD_LPC_REG_CONFIG3_OFFSET 0xfd
#define MLXPLAT_CPLD_LPC_IO_RANGE 0x100
-#define MLXPLAT_CPLD_LPC_I2C_CH1_OFF 0xdb
-#define MLXPLAT_CPLD_LPC_I2C_CH2_OFF 0xda
-#define MLXPLAT_CPLD_LPC_I2C_CH3_OFF 0xdc
-#define MLXPLAT_CPLD_LPC_I2C_CH4_OFF 0xdd
#define MLXPLAT_CPLD_LPC_PIO_OFFSET 0x10000UL
#define MLXPLAT_CPLD_LPC_REG1 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
- MLXPLAT_CPLD_LPC_I2C_CH1_OFF) | \
+ MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
#define MLXPLAT_CPLD_LPC_REG2 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
- MLXPLAT_CPLD_LPC_I2C_CH2_OFF) | \
+ MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
#define MLXPLAT_CPLD_LPC_REG3 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
- MLXPLAT_CPLD_LPC_I2C_CH3_OFF) | \
+ MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
#define MLXPLAT_CPLD_LPC_REG4 ((MLXPLAT_CPLD_LPC_REG_BASE_ADRR + \
- MLXPLAT_CPLD_LPC_I2C_CH4_OFF) | \
+ MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET) | \
MLXPLAT_CPLD_LPC_PIO_OFFSET)
/* Masks for aggregation, psu, pwr and fan event in CPLD related registers. */
@@ -202,6 +222,7 @@
MLXPLAT_CPLD_AGGR_MASK_LC_SDWN)
#define MLXPLAT_CPLD_LOW_AGGR_MASK_LOW 0xc1
#define MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2 BIT(2)
+#define MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT BIT(4)
#define MLXPLAT_CPLD_LOW_AGGR_MASK_I2C BIT(6)
#define MLXPLAT_CPLD_PSU_MASK GENMASK(1, 0)
#define MLXPLAT_CPLD_PWR_MASK GENMASK(1, 0)
@@ -214,6 +235,17 @@
#define MLXPLAT_CPLD_LED_HI_NIBBLE_MASK GENMASK(3, 0)
#define MLXPLAT_CPLD_VOLTREG_UPD_MASK GENMASK(5, 4)
#define MLXPLAT_CPLD_GWP_MASK GENMASK(0, 0)
+#define MLXPLAT_CPLD_EROT_MASK GENMASK(1, 0)
+#define MLXPLAT_CPLD_PWR_BUTTON_MASK BIT(0)
+#define MLXPLAT_CPLD_LATCH_RST_MASK BIT(5)
+#define MLXPLAT_CPLD_THERMAL1_PDB_MASK BIT(3)
+#define MLXPLAT_CPLD_THERMAL2_PDB_MASK BIT(4)
+#define MLXPLAT_CPLD_INTRUSION_MASK BIT(6)
+#define MLXPLAT_CPLD_PWM_PG_MASK BIT(7)
+#define MLXPLAT_CPLD_L1_CHA_HEALTH_MASK (MLXPLAT_CPLD_THERMAL1_PDB_MASK | \
+ MLXPLAT_CPLD_THERMAL2_PDB_MASK | \
+ MLXPLAT_CPLD_INTRUSION_MASK |\
+ MLXPLAT_CPLD_PWM_PG_MASK)
#define MLXPLAT_CPLD_I2C_CAP_BIT 0x04
#define MLXPLAT_CPLD_I2C_CAP_MASK GENMASK(5, MLXPLAT_CPLD_I2C_CAP_BIT)
@@ -226,6 +258,8 @@
/* Masks for aggregation for modular systems */
#define MLXPLAT_CPLD_LPC_LC_MASK GENMASK(7, 0)
+#define MLXPLAT_CPLD_HALT_MASK BIT(3)
+
/* Default I2C parent bus number */
#define MLXPLAT_CPLD_PHYS_ADAPTER_DEF_NR 1
@@ -243,6 +277,8 @@
#define MLXPLAT_CPLD_CH2_ETH_MODULAR 3
#define MLXPLAT_CPLD_CH3_ETH_MODULAR 43
#define MLXPLAT_CPLD_CH4_ETH_MODULAR 51
+#define MLXPLAT_CPLD_CH2_RACK_SWITCH 18
+#define MLXPLAT_CPLD_CH2_NG800 34
/* Number of LPC attached MUX platform devices */
#define MLXPLAT_CPLD_LPC_MUX_DEVS 4
@@ -280,6 +316,12 @@
/* Minimum power required for turning on Ethernet modular system (WATT) */
#define MLXPLAT_CPLD_ETH_MODULAR_PWR_MIN 50
+/* Default value for PWM control register for rack switch system */
+#define MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT 0xf4
+
+#define MLXPLAT_I2C_MAIN_BUS_NOTIFIED 0x01
+#define MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED 0x02
+
/* mlxplat_priv - platform private data
* @pdev_i2c - i2c controller platform device
* @pdev_mux - array of mux platform devices
@@ -289,6 +331,9 @@
* @pdev_fan - FAN platform devices
* @pdev_wd - array of watchdog platform devices
* @regmap: device register map
+ * @hotplug_resources: system hotplug resources
+ * @hotplug_resources_size: size of system hotplug resources
+ * @hi2c_main_init_status: init status of I2C main bus
*/
struct mlxplat_priv {
struct platform_device *pdev_i2c;
@@ -299,8 +344,14 @@ struct mlxplat_priv {
struct platform_device *pdev_fan;
struct platform_device *pdev_wd[MLXPLAT_CPLD_WD_MAX_DEVS];
void *regmap;
+ struct resource *hotplug_resources;
+ unsigned int hotplug_resources_size;
+ u8 i2c_main_init_status;
};
+static struct platform_device *mlxplat_dev;
+static int mlxplat_i2c_main_complition_notify(void *handle, int id);
+
/* Regions for LPC I2C controller and LPC base register space */
static const struct resource mlxplat_lpc_resources[] = {
[0] = DEFINE_RES_NAMED(MLXPLAT_CPLD_LPC_I2C_BASE_ADRR,
@@ -312,6 +363,11 @@ static const struct resource mlxplat_lpc_resources[] = {
IORESOURCE_IO),
};
+/* Platform systems default i2c data */
+static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_default_data = {
+ .completion_notify = mlxplat_i2c_main_complition_notify,
+};
+
/* Platform i2c next generation systems data */
static struct mlxreg_core_data mlxplat_mlxcpld_i2c_ng_items_data[] = {
{
@@ -334,6 +390,7 @@ static struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_i2c_ng_data = {
.mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_I2C,
+ .completion_notify = mlxplat_i2c_main_complition_notify,
};
/* Platform default channels */
@@ -460,6 +517,67 @@ static struct i2c_mux_reg_platform_data mlxplat_modular_mux_data[] = {
},
};
+/* Platform channels for rack switch system family */
+static const int mlxplat_rack_switch_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+};
+
+/* Platform rack switch mux data */
+static struct i2c_mux_reg_platform_data mlxplat_rack_switch_mux_data[] = {
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH1,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ .values = mlxplat_rack_switch_channels,
+ .n_values = ARRAY_SIZE(mlxplat_rack_switch_channels),
+ },
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH2_RACK_SWITCH,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ .values = mlxplat_msn21xx_channels,
+ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels),
+ },
+
+};
+
+/* Platform channels for ng800 system family */
+static const int mlxplat_ng800_channels[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+};
+
+/* Platform ng800 mux data */
+static struct i2c_mux_reg_platform_data mlxplat_ng800_mux_data[] = {
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH1,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG1,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ .values = mlxplat_ng800_channels,
+ .n_values = ARRAY_SIZE(mlxplat_ng800_channels),
+ },
+ {
+ .parent = 1,
+ .base_nr = MLXPLAT_CPLD_CH2_NG800,
+ .write_only = 1,
+ .reg = (void __iomem *)MLXPLAT_CPLD_LPC_REG2,
+ .reg_size = 1,
+ .idle_in_use = 1,
+ .values = mlxplat_msn21xx_channels,
+ .n_values = ARRAY_SIZE(mlxplat_msn21xx_channels),
+ },
+
+};
+
/* Platform hotplug devices */
static struct i2c_board_info mlxplat_mlxcpld_pwr[] = {
{
@@ -479,6 +597,15 @@ static struct i2c_board_info mlxplat_mlxcpld_ext_pwr[] = {
},
};
+static struct i2c_board_info mlxplat_mlxcpld_pwr_ng800[] = {
+ {
+ I2C_BOARD_INFO("dps460", 0x59),
+ },
+ {
+ I2C_BOARD_INFO("dps460", 0x5a),
+ },
+};
+
static struct i2c_board_info mlxplat_mlxcpld_fan[] = {
{
I2C_BOARD_INFO("24c32", 0x50),
@@ -558,6 +685,23 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_wc_items_data[] = {
},
};
+static struct mlxreg_core_data mlxplat_mlxcpld_default_pwr_ng800_items_data[] = {
+ {
+ .label = "pwr1",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(0),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[0],
+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
+ },
+ {
+ .label = "pwr2",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = BIT(1),
+ .hpdev.brdinfo = &mlxplat_mlxcpld_pwr_ng800[1],
+ .hpdev.nr = MLXPLAT_CPLD_PSU_MSNXXXX_NR,
+ },
+};
+
static struct mlxreg_core_data mlxplat_mlxcpld_default_fan_items_data[] = {
{
.label = "fan1",
@@ -1181,6 +1325,47 @@ static struct mlxreg_core_item mlxplat_mlxcpld_ext_items[] = {
}
};
+static struct mlxreg_core_item mlxplat_mlxcpld_ng800_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_ng_psu_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = MLXPLAT_CPLD_PSU_EXT_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_psu_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_pwr_ng800_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_EXT_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_pwr_ng800_items_data),
+ .inversed = 0,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_ng_fan_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = MLXPLAT_CPLD_FAN_NG_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_asic_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
+ .mask = MLXPLAT_CPLD_ASIC_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_asic_items_data),
+ .inversed = 0,
+ .health = true,
+ },
+};
+
static
struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = {
.items = mlxplat_mlxcpld_ext_items,
@@ -1191,6 +1376,16 @@ struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ext_data = {
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2,
};
+static
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_ng800_data = {
+ .items = mlxplat_mlxcpld_ng800_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_ng800_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX,
+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_ASIC2,
+};
+
static struct mlxreg_core_data mlxplat_mlxcpld_modular_pwr_items_data[] = {
{
.label = "pwr1",
@@ -2042,7 +2237,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_global_wp_items_data[] = {
},
};
-static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = {
+static struct mlxreg_core_item mlxplat_mlxcpld_chassis_blade_items[] = {
{
.data = mlxplat_mlxcpld_global_wp_items_data,
.aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
@@ -2055,15 +2250,256 @@ static struct mlxreg_core_item mlxplat_mlxcpld_nvlink_blade_items[] = {
};
static
-struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_nvlink_blade_data = {
- .items = mlxplat_mlxcpld_nvlink_blade_items,
- .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_items),
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_chassis_blade_data = {
+ .items = mlxplat_mlxcpld_chassis_blade_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_items),
.cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
.mask = MLXPLAT_CPLD_AGGR_MASK_COMEX,
.cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
.mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
};
+/* Platform hotplug for switch systems family data */
+static struct mlxreg_core_data mlxplat_mlxcpld_erot_ap_items_data[] = {
+ {
+ .label = "erot1_ap",
+ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET,
+ .mask = BIT(0),
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+ {
+ .label = "erot2_ap",
+ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET,
+ .mask = BIT(1),
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_erot_error_items_data[] = {
+ {
+ .label = "erot1_error",
+ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET,
+ .mask = BIT(0),
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+ {
+ .label = "erot2_error",
+ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET,
+ .mask = BIT(1),
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+};
+
+static struct mlxreg_core_item mlxplat_mlxcpld_rack_switch_items[] = {
+ {
+ .data = mlxplat_mlxcpld_ext_psu_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PSU_OFFSET,
+ .mask = MLXPLAT_CPLD_PSU_EXT_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_psu_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_ext_pwr_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWR_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_EXT_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_PSU_I2C_CAP_OFFSET,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_ext_pwr_items_data),
+ .inversed = 0,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_default_ng_fan_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = MLXPLAT_CPLD_FAN_NG_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_erot_ap_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET,
+ .mask = MLXPLAT_CPLD_EROT_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_erot_error_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET,
+ .mask = MLXPLAT_CPLD_EROT_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+};
+
+static
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_rack_switch_data = {
+ .items = mlxplat_mlxcpld_rack_switch_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_rack_switch_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX,
+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW,
+};
+
+/* Callback performs graceful shutdown after notification about power button event */
+static int
+mlxplat_mlxcpld_l1_switch_pwr_events_handler(void *handle, enum mlxreg_hotplug_kind kind,
+ u8 action)
+{
+ dev_info(&mlxplat_dev->dev, "System shutdown due to short press of power button");
+ kernel_halt();
+ return 0;
+}
+
+static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_pwr_events_notifier = {
+ .user_handler = mlxplat_mlxcpld_l1_switch_pwr_events_handler,
+};
+
+/* Platform hotplug for l1 switch systems family data */
+static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_pwr_events_items_data[] = {
+ {
+ .label = "power_button",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK,
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_pwr_events_notifier,
+ },
+};
+
+/* Callback activates latch reset flow after notification about intrusion event */
+static int
+mlxplat_mlxcpld_l1_switch_intrusion_events_handler(void *handle, enum mlxreg_hotplug_kind kind,
+ u8 action)
+{
+ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+ u32 regval;
+ int err;
+
+ err = regmap_read(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, &regval);
+ if (err)
+ goto fail_regmap_read;
+
+ if (action) {
+ dev_info(&mlxplat_dev->dev, "Detected intrusion - system latch is opened");
+ err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+ regval | MLXPLAT_CPLD_LATCH_RST_MASK);
+ } else {
+ dev_info(&mlxplat_dev->dev, "System latch is properly closed");
+ err = regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+ regval & ~MLXPLAT_CPLD_LATCH_RST_MASK);
+ }
+
+ if (err)
+ goto fail_regmap_write;
+
+ return 0;
+
+fail_regmap_read:
+fail_regmap_write:
+ dev_err(&mlxplat_dev->dev, "Register access failed");
+ return err;
+}
+
+static struct mlxreg_core_hotplug_notifier mlxplat_mlxcpld_l1_switch_intrusion_events_notifier = {
+ .user_handler = mlxplat_mlxcpld_l1_switch_intrusion_events_handler,
+};
+
+static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_health_events_items_data[] = {
+ {
+ .label = "thermal1_pdb",
+ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
+ .mask = MLXPLAT_CPLD_THERMAL1_PDB_MASK,
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+ {
+ .label = "thermal2_pdb",
+ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
+ .mask = MLXPLAT_CPLD_THERMAL2_PDB_MASK,
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+ {
+ .label = "intrusion",
+ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
+ .mask = MLXPLAT_CPLD_INTRUSION_MASK,
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ .hpdev.notifier = &mlxplat_mlxcpld_l1_switch_intrusion_events_notifier,
+ },
+ {
+ .label = "pwm_pg",
+ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
+ .mask = MLXPLAT_CPLD_PWM_PG_MASK,
+ .hpdev.nr = MLXPLAT_CPLD_NR_NONE,
+ },
+};
+
+static struct mlxreg_core_item mlxplat_mlxcpld_l1_switch_events_items[] = {
+ {
+ .data = mlxplat_mlxcpld_default_ng_fan_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_FAN_OFFSET,
+ .mask = MLXPLAT_CPLD_FAN_NG_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_default_ng_fan_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_erot_ap_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_EROT_OFFSET,
+ .mask = MLXPLAT_CPLD_EROT_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_ap_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_erot_error_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET,
+ .mask = MLXPLAT_CPLD_EROT_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_erot_error_items_data),
+ .inversed = 1,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_l1_switch_pwr_events_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET,
+ .mask = MLXPLAT_CPLD_PWR_BUTTON_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_pwr_events_items_data),
+ .inversed = 0,
+ .health = false,
+ },
+ {
+ .data = mlxplat_mlxcpld_l1_switch_health_events_items_data,
+ .aggr_mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF,
+ .reg = MLXPLAT_CPLD_LPC_REG_BRD_OFFSET,
+ .mask = MLXPLAT_CPLD_L1_CHA_HEALTH_MASK,
+ .count = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_health_events_items_data),
+ .inversed = 0,
+ .health = false,
+ .ind = 8,
+ },
+};
+
+static
+struct mlxreg_core_hotplug_platform_data mlxplat_mlxcpld_l1_switch_data = {
+ .items = mlxplat_mlxcpld_l1_switch_events_items,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_events_items),
+ .cell = MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET,
+ .mask = MLXPLAT_CPLD_AGGR_MASK_NG_DEF | MLXPLAT_CPLD_AGGR_MASK_COMEX,
+ .cell_low = MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET,
+ .mask_low = MLXPLAT_CPLD_LOW_AGGR_MASK_LOW | MLXPLAT_CPLD_LOW_AGGR_MASK_PWR_BUT,
+};
+
/* Platform led default data */
static struct mlxreg_core_data mlxplat_mlxcpld_default_led_data[] = {
{
@@ -2593,6 +3029,114 @@ static struct mlxreg_core_platform_data mlxplat_modular_led_data = {
.counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_led_data),
};
+/* Platform led data for chassis system */
+static struct mlxreg_core_data mlxplat_mlxcpld_l1_switch_led_data[] = {
+ {
+ .label = "status:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ },
+ {
+ .label = "status:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED1_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK
+ },
+ {
+ .label = "fan1:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(0),
+ },
+ {
+ .label = "fan1:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(0),
+ },
+ {
+ .label = "fan2:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(1),
+ },
+ {
+ .label = "fan2:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED2_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(1),
+ },
+ {
+ .label = "fan3:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(2),
+ },
+ {
+ .label = "fan3:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(2),
+ },
+ {
+ .label = "fan4:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(3),
+ },
+ {
+ .label = "fan4:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED3_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(3),
+ },
+ {
+ .label = "fan5:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(4),
+ },
+ {
+ .label = "fan5:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(4),
+ },
+ {
+ .label = "fan6:green",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(5),
+ },
+ {
+ .label = "fan6:orange",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED4_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_HI_NIBBLE_MASK,
+ .capability = MLXPLAT_CPLD_LPC_REG_FAN_DRW_CAP_OFFSET,
+ .bit = BIT(5),
+ },
+ {
+ .label = "uid:blue",
+ .reg = MLXPLAT_CPLD_LPC_REG_LED5_OFFSET,
+ .mask = MLXPLAT_CPLD_LED_LO_NIBBLE_MASK,
+ },
+};
+
+static struct mlxreg_core_platform_data mlxplat_l1_switch_led_data = {
+ .data = mlxplat_mlxcpld_l1_switch_led_data,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_l1_switch_led_data),
+};
+
/* Platform register access default */
static struct mlxreg_core_data mlxplat_mlxcpld_default_regs_io_data[] = {
{
@@ -2948,6 +3492,51 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0200,
},
{
+ .label = "erot1_reset",
+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0644,
+ },
+ {
+ .label = "erot2_reset",
+ .reg = MLXPLAT_CPLD_LPC_REG_RESET_GP2_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(7),
+ .mode = 0644,
+ },
+ {
+ .label = "clk_brd_prog_en",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(1),
+ .mode = 0644,
+ .secured = 1,
+ },
+ {
+ .label = "erot1_recovery",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0644,
+ },
+ {
+ .label = "erot2_recovery",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(7),
+ .mode = 0644,
+ },
+ {
+ .label = "erot1_wp",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(4),
+ .mode = 0644,
+ .secured = 1,
+ },
+ {
+ .label = "erot2_wp",
+ .reg = MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0644,
+ .secured = 1,
+ },
+ {
.label = "reset_long_pb",
.reg = MLXPLAT_CPLD_LPC_REG_RESET_CAUSE_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
@@ -3014,7 +3603,7 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
- .label = "reset_voltmon_upgrade_fail",
+ .label = "reset_pwr_converter_fail",
.reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
.mode = 0444,
@@ -3050,6 +3639,12 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "reset_ac_ok_fail",
+ .reg = MLXPLAT_CPLD_LPC_REG_RST_CAUSE2_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(7),
+ .mode = 0444,
+ },
+ {
.label = "psu1_on",
.reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(0),
@@ -3074,12 +3669,48 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0200,
},
{
+ .label = "deep_pwr_cycle",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0200,
+ },
+ {
+ .label = "latch_reset",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP1_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0200,
+ },
+ {
.label = "jtag_enable",
.reg = MLXPLAT_CPLD_LPC_REG_GP2_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(4),
.mode = 0644,
},
{
+ .label = "dbg1",
+ .reg = MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET,
+ .bit = GENMASK(7, 0),
+ .mode = 0644,
+ },
+ {
+ .label = "dbg2",
+ .reg = MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET,
+ .bit = GENMASK(7, 0),
+ .mode = 0644,
+ },
+ {
+ .label = "dbg3",
+ .reg = MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET,
+ .bit = GENMASK(7, 0),
+ .mode = 0644,
+ },
+ {
+ .label = "dbg4",
+ .reg = MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET,
+ .bit = GENMASK(7, 0),
+ .mode = 0644,
+ },
+ {
.label = "asic_health",
.reg = MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET,
.mask = MLXPLAT_CPLD_ASIC_MASK,
@@ -3131,6 +3762,13 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0444,
},
{
+ .label = "pwr_converter_prog_en",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(0),
+ .mode = 0644,
+ .secured = 1,
+ },
+ {
.label = "vpd_wp",
.reg = MLXPLAT_CPLD_LPC_REG_GP0_OFFSET,
.mask = GENMASK(7, 0) & ~BIT(3),
@@ -3143,6 +3781,49 @@ static struct mlxreg_core_data mlxplat_mlxcpld_default_ng_regs_io_data[] = {
.mode = 0644,
},
{
+ .label = "erot1_ap_reset",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(0),
+ .mode = 0444,
+ },
+ {
+ .label = "erot2_ap_reset",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(1),
+ .mode = 0444,
+ },
+ {
+ .label = "clk_brd1_boot_fail",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(4),
+ .mode = 0444,
+ },
+ {
+ .label = "clk_brd2_boot_fail",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(5),
+ .mode = 0444,
+ },
+ {
+ .label = "clk_brd_fail",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(6),
+ .mode = 0444,
+ },
+ {
+ .label = "asic_pg_fail",
+ .reg = MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET,
+ .mask = GENMASK(7, 0) & ~BIT(7),
+ .mode = 0444,
+ },
+ {
+ .label = "spi_chnl_select",
+ .reg = MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT,
+ .mask = GENMASK(7, 0),
+ .bit = 1,
+ .mode = 0644,
+ },
+ {
.label = "config1",
.reg = MLXPLAT_CPLD_LPC_REG_CONFIG1_OFFSET,
.bit = GENMASK(7, 0),
@@ -3657,8 +4338,8 @@ static struct mlxreg_core_platform_data mlxplat_modular_regs_io_data = {
.counter = ARRAY_SIZE(mlxplat_mlxcpld_modular_regs_io_data),
};
-/* Platform register access for NVLink blade systems family data */
-static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = {
+/* Platform register access for chassis blade systems family data */
+static struct mlxreg_core_data mlxplat_mlxcpld_chassis_blade_regs_io_data[] = {
{
.label = "cpld1_version",
.reg = MLXPLAT_CPLD_LPC_REG_CPLD1_VER_OFFSET,
@@ -3855,9 +4536,9 @@ static struct mlxreg_core_data mlxplat_mlxcpld_nvlink_blade_regs_io_data[] = {
},
};
-static struct mlxreg_core_platform_data mlxplat_nvlink_blade_regs_io_data = {
- .data = mlxplat_mlxcpld_nvlink_blade_regs_io_data,
- .counter = ARRAY_SIZE(mlxplat_mlxcpld_nvlink_blade_regs_io_data),
+static struct mlxreg_core_platform_data mlxplat_chassis_blade_regs_io_data = {
+ .data = mlxplat_mlxcpld_chassis_blade_regs_io_data,
+ .counter = ARRAY_SIZE(mlxplat_mlxcpld_chassis_blade_regs_io_data),
};
/* Platform FAN default */
@@ -4242,11 +4923,18 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_SAFE_BIOS_OFFSET:
case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCX_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC2_EVENT_OFFSET:
@@ -4257,6 +4945,12 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_PWR_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_IN_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_IN_MASK_OFFSET:
@@ -4274,6 +4968,7 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON:
+ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT:
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
@@ -4284,6 +4979,11 @@ static bool mlxplat_mlxcpld_writeable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PWM1_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PWM2_OFFSET:
case MLXPLAT_CPLD_LPC_REG_PWM3_OFFSET:
@@ -4334,6 +5034,10 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
@@ -4343,6 +5047,9 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
@@ -4358,6 +5065,15 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET:
@@ -4382,6 +5098,8 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON:
+ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT:
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD_CLEAR_WP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD1_TMR_OFFSET:
@@ -4392,6 +5110,11 @@ static bool mlxplat_mlxcpld_readable_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET:
@@ -4468,6 +5191,10 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_SAFE_BIOS_WP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGR_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLO_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRCO_OFFSET:
@@ -4477,6 +5204,9 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_GWP_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_GWP_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_BRD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_HEALTH_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_ASIC_MASK_OFFSET:
@@ -4492,6 +5222,15 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_FAN_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_FAN_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROT_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_EROTE_MASK_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_EVENT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_PWRB_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLC_OFFSET:
case MLXPLAT_CPLD_LPC_REG_AGGRLC_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_IN_OFFSET:
@@ -4516,10 +5255,17 @@ static bool mlxplat_mlxcpld_volatile_reg(struct device *dev, unsigned int reg)
case MLXPLAT_CPLD_LPC_REG_LC_SD_EVENT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_SD_MASK_OFFSET:
case MLXPLAT_CPLD_LPC_REG_LC_PWR_ON:
+ case MLXPLAT_CPLD_LPC_REG_GP4_RO_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_SPI_CHNL_SELECT:
case MLXPLAT_CPLD_LPC_REG_WD2_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD2_TLEFT_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TMR_OFFSET:
case MLXPLAT_CPLD_LPC_REG_WD3_TLEFT_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_DBG_CTRL_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH1_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH2_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH3_OFFSET:
+ case MLXPLAT_CPLD_LPC_REG_I2C_CH4_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD1_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD2_MVER_OFFSET:
case MLXPLAT_CPLD_LPC_REG_CPLD3_MVER_OFFSET:
@@ -4583,6 +5329,13 @@ static const struct reg_default mlxplat_mlxcpld_regmap_ng400[] = {
{ MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 },
};
+static const struct reg_default mlxplat_mlxcpld_regmap_rack_switch[] = {
+ { MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, MLXPLAT_REGMAP_NVSWITCH_PWM_DEFAULT },
+ { MLXPLAT_CPLD_LPC_REG_WD1_ACT_OFFSET, 0x00 },
+ { MLXPLAT_CPLD_LPC_REG_WD2_ACT_OFFSET, 0x00 },
+ { MLXPLAT_CPLD_LPC_REG_WD3_ACT_OFFSET, 0x00 },
+};
+
static const struct reg_default mlxplat_mlxcpld_regmap_eth_modular[] = {
{ MLXPLAT_CPLD_LPC_REG_GP2_OFFSET, 0x61 },
{ MLXPLAT_CPLD_LPC_REG_PWM_CONTROL_OFFSET, 0x00 },
@@ -4676,6 +5429,20 @@ static const struct regmap_config mlxplat_mlxcpld_regmap_config_ng400 = {
.reg_write = mlxplat_mlxcpld_reg_write,
};
+static const struct regmap_config mlxplat_mlxcpld_regmap_config_rack_switch = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 255,
+ .cache_type = REGCACHE_FLAT,
+ .writeable_reg = mlxplat_mlxcpld_writeable_reg,
+ .readable_reg = mlxplat_mlxcpld_readable_reg,
+ .volatile_reg = mlxplat_mlxcpld_volatile_reg,
+ .reg_defaults = mlxplat_mlxcpld_regmap_rack_switch,
+ .num_reg_defaults = ARRAY_SIZE(mlxplat_mlxcpld_regmap_rack_switch),
+ .reg_read = mlxplat_mlxcpld_reg_read,
+ .reg_write = mlxplat_mlxcpld_reg_write,
+};
+
static const struct regmap_config mlxplat_mlxcpld_regmap_config_eth_modular = {
.reg_bits = 8,
.val_bits = 8,
@@ -4694,7 +5461,6 @@ static struct resource mlxplat_mlxcpld_resources[] = {
[0] = DEFINE_RES_IRQ_NAMED(MLXPLAT_CPLD_LPC_SYSIRQ, "mlxreg-hotplug"),
};
-static struct platform_device *mlxplat_dev;
static struct mlxreg_core_hotplug_platform_data *mlxplat_i2c;
static struct mlxreg_core_hotplug_platform_data *mlxplat_hotplug;
static struct mlxreg_core_platform_data *mlxplat_led;
@@ -4704,6 +5470,14 @@ static struct mlxreg_core_platform_data
*mlxplat_wd_data[MLXPLAT_CPLD_WD_MAX_DEVS];
static const struct regmap_config *mlxplat_regmap_config;
+/* Platform default poweroff function */
+static void mlxplat_poweroff(void)
+{
+ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+
+ regmap_write(priv->regmap, MLXPLAT_CPLD_LPC_REG_GP1_OFFSET, MLXPLAT_CPLD_HALT_MASK);
+}
+
static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
{
int i;
@@ -4722,6 +5496,7 @@ static int __init mlxplat_dmi_default_matched(const struct dmi_system_id *dmi)
mlxplat_led = &mlxplat_default_led_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
return 1;
}
@@ -4744,6 +5519,7 @@ static int __init mlxplat_dmi_default_wc_matched(const struct dmi_system_id *dmi
mlxplat_led = &mlxplat_default_led_wc_data;
mlxplat_regs_io = &mlxplat_default_regs_io_data;
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
return 1;
}
@@ -4791,6 +5567,7 @@ static int __init mlxplat_dmi_msn21xx_matched(const struct dmi_system_id *dmi)
mlxplat_led = &mlxplat_msn21xx_led_data;
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
return 1;
}
@@ -4813,6 +5590,7 @@ static int __init mlxplat_dmi_msn274x_matched(const struct dmi_system_id *dmi)
mlxplat_led = &mlxplat_default_led_data;
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
return 1;
}
@@ -4835,6 +5613,7 @@ static int __init mlxplat_dmi_msn201x_matched(const struct dmi_system_id *dmi)
mlxplat_led = &mlxplat_msn21xx_led_data;
mlxplat_regs_io = &mlxplat_msn21xx_regs_io_data;
mlxplat_wd_data[0] = &mlxplat_mlxcpld_wd_set_type1[0];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
return 1;
}
@@ -4884,6 +5663,7 @@ static int __init mlxplat_dmi_comex_matched(const struct dmi_system_id *dmi)
mlxplat_fan = &mlxplat_default_fan_data;
for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_default_data;
mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_comex;
return 1;
@@ -4935,14 +5715,14 @@ static int __init mlxplat_dmi_modular_matched(const struct dmi_system_id *dmi)
return 1;
}
-static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *dmi)
+static int __init mlxplat_dmi_chassis_blade_matched(const struct dmi_system_id *dmi)
{
int i;
mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
mlxplat_mux_num = ARRAY_SIZE(mlxplat_default_mux_data);
mlxplat_mux_data = mlxplat_default_mux_data;
- mlxplat_hotplug = &mlxplat_mlxcpld_nvlink_blade_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_chassis_blade_data;
mlxplat_hotplug->deferred_nr =
mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
for (i = 0; i < mlxplat_mux_num; i++) {
@@ -4950,13 +5730,77 @@ static int __init mlxplat_dmi_nvlink_blade_matched(const struct dmi_system_id *d
mlxplat_mux_data[i].n_values =
ARRAY_SIZE(mlxplat_msn21xx_channels);
}
- mlxplat_regs_io = &mlxplat_nvlink_blade_regs_io_data;
+ mlxplat_regs_io = &mlxplat_chassis_blade_regs_io_data;
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400;
+
+ return 1;
+}
+
+static int __init mlxplat_dmi_rack_switch_matched(const struct dmi_system_id *dmi)
+{
+ int i;
+
+ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
+ mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data);
+ mlxplat_mux_data = mlxplat_rack_switch_mux_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_rack_switch_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+ mlxplat_led = &mlxplat_default_ng_led_data;
+ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
+ mlxplat_fan = &mlxplat_default_fan_data;
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch;
+
+ return 1;
+}
+
+static int __init mlxplat_dmi_ng800_matched(const struct dmi_system_id *dmi)
+{
+ int i;
+
+ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
+ mlxplat_mux_num = ARRAY_SIZE(mlxplat_ng800_mux_data);
+ mlxplat_mux_data = mlxplat_ng800_mux_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_ng800_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+ mlxplat_led = &mlxplat_default_ng_led_data;
+ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
+ mlxplat_fan = &mlxplat_default_fan_data;
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_ng400;
return 1;
}
+static int __init mlxplat_dmi_l1_switch_matched(const struct dmi_system_id *dmi)
+{
+ int i;
+
+ mlxplat_max_adap_num = MLXPLAT_CPLD_MAX_PHYS_ADAPTER_NUM;
+ mlxplat_mux_num = ARRAY_SIZE(mlxplat_rack_switch_mux_data);
+ mlxplat_mux_data = mlxplat_rack_switch_mux_data;
+ mlxplat_hotplug = &mlxplat_mlxcpld_l1_switch_data;
+ mlxplat_hotplug->deferred_nr =
+ mlxplat_msn21xx_channels[MLXPLAT_CPLD_GRP_CHNL_NUM - 1];
+ mlxplat_led = &mlxplat_l1_switch_led_data;
+ mlxplat_regs_io = &mlxplat_default_ng_regs_io_data;
+ mlxplat_fan = &mlxplat_default_fan_data;
+ for (i = 0; i < ARRAY_SIZE(mlxplat_mlxcpld_wd_set_type2); i++)
+ mlxplat_wd_data[i] = &mlxplat_mlxcpld_wd_set_type2[i];
+ mlxplat_i2c = &mlxplat_mlxcpld_i2c_ng_data;
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config_rack_switch;
+ pm_power_off = mlxplat_poweroff;
+
+ return 1;
+}
+
static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
{
.callback = mlxplat_dmi_default_wc_matched,
@@ -5015,6 +5859,13 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
},
},
{
+ .callback = mlxplat_dmi_rack_switch_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"),
+ DMI_EXACT_MATCH(DMI_PRODUCT_SKU, "HI142"),
+ },
+ },
+ {
.callback = mlxplat_dmi_ng400_matched,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "VMOD0010"),
@@ -5027,12 +5878,24 @@ static const struct dmi_system_id mlxplat_dmi_table[] __initconst = {
},
},
{
- .callback = mlxplat_dmi_nvlink_blade_matched,
+ .callback = mlxplat_dmi_ng800_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0013"),
+ },
+ },
+ {
+ .callback = mlxplat_dmi_chassis_blade_matched,
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "VMOD0015"),
},
},
{
+ .callback = mlxplat_dmi_l1_switch_matched,
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "VMOD0017"),
+ },
+ },
+ {
.callback = mlxplat_dmi_msn274x_matched,
.matches = {
DMI_MATCH(DMI_BOARD_VENDOR, "Mellanox Technologies"),
@@ -5145,10 +6008,11 @@ static int mlxplat_mlxcpld_verify_bus_topology(int *nr)
shift = *nr - mlxplat_mux_data[i].parent;
mlxplat_mux_data[i].parent = *nr;
mlxplat_mux_data[i].base_nr += shift;
- if (shift > 0)
- mlxplat_hotplug->shift_nr = shift;
}
+ if (shift > 0)
+ mlxplat_hotplug->shift_nr = shift;
+
return 0;
}
@@ -5173,73 +6037,53 @@ static int mlxplat_mlxcpld_check_wd_capability(void *regmap)
return 0;
}
-static int __init mlxplat_init(void)
+static int mlxplat_lpc_cpld_device_init(struct resource **hotplug_resources,
+ unsigned int *hotplug_resources_size)
{
- struct mlxplat_priv *priv;
- int i, j, nr, err;
-
- if (!dmi_check_system(mlxplat_dmi_table))
- return -ENODEV;
+ int err;
mlxplat_dev = platform_device_register_simple(MLX_PLAT_DEVICE_NAME, PLATFORM_DEVID_NONE,
- mlxplat_lpc_resources,
- ARRAY_SIZE(mlxplat_lpc_resources));
-
+ mlxplat_lpc_resources,
+ ARRAY_SIZE(mlxplat_lpc_resources));
if (IS_ERR(mlxplat_dev))
return PTR_ERR(mlxplat_dev);
- priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
- GFP_KERNEL);
- if (!priv) {
- err = -ENOMEM;
- goto fail_alloc;
- }
- platform_set_drvdata(mlxplat_dev, priv);
-
mlxplat_mlxcpld_regmap_ctx.base = devm_ioport_map(&mlxplat_dev->dev,
- mlxplat_lpc_resources[1].start, 1);
+ mlxplat_lpc_resources[1].start, 1);
if (!mlxplat_mlxcpld_regmap_ctx.base) {
err = -ENOMEM;
- goto fail_alloc;
+ goto fail_devm_ioport_map;
}
- if (!mlxplat_regmap_config)
- mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config;
+ *hotplug_resources = mlxplat_mlxcpld_resources;
+ *hotplug_resources_size = ARRAY_SIZE(mlxplat_mlxcpld_resources);
- priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
- &mlxplat_mlxcpld_regmap_ctx,
- mlxplat_regmap_config);
- if (IS_ERR(priv->regmap)) {
- err = PTR_ERR(priv->regmap);
- goto fail_alloc;
- }
+ return 0;
- err = mlxplat_mlxcpld_verify_bus_topology(&nr);
- if (nr < 0)
- goto fail_alloc;
+fail_devm_ioport_map:
+ platform_device_unregister(mlxplat_dev);
+ return err;
+}
- nr = (nr == mlxplat_max_adap_num) ? -1 : nr;
- if (mlxplat_i2c)
- mlxplat_i2c->regmap = priv->regmap;
- priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld",
- nr, mlxplat_mlxcpld_resources,
- ARRAY_SIZE(mlxplat_mlxcpld_resources),
- mlxplat_i2c, sizeof(*mlxplat_i2c));
- if (IS_ERR(priv->pdev_i2c)) {
- err = PTR_ERR(priv->pdev_i2c);
- goto fail_alloc;
- }
+static void mlxplat_lpc_cpld_device_exit(void)
+{
+ platform_device_unregister(mlxplat_dev);
+}
- for (i = 0; i < mlxplat_mux_num; i++) {
- priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev,
- "i2c-mux-reg", i, NULL, 0,
- &mlxplat_mux_data[i],
- sizeof(mlxplat_mux_data[i]));
- if (IS_ERR(priv->pdev_mux[i])) {
- err = PTR_ERR(priv->pdev_mux[i]);
- goto fail_platform_mux_register;
- }
- }
+static int
+mlxplat_pre_init(struct resource **hotplug_resources, unsigned int *hotplug_resources_size)
+{
+ return mlxplat_lpc_cpld_device_init(hotplug_resources, hotplug_resources_size);
+}
+
+static void mlxplat_post_exit(void)
+{
+ mlxplat_lpc_cpld_device_exit();
+}
+
+static int mlxplat_post_init(struct mlxplat_priv *priv)
+{
+ int i = 0, err;
/* Add hotplug driver */
if (mlxplat_hotplug) {
@@ -5247,24 +6091,15 @@ static int __init mlxplat_init(void)
priv->pdev_hotplug =
platform_device_register_resndata(&mlxplat_dev->dev,
"mlxreg-hotplug", PLATFORM_DEVID_NONE,
- mlxplat_mlxcpld_resources,
- ARRAY_SIZE(mlxplat_mlxcpld_resources),
+ priv->hotplug_resources,
+ priv->hotplug_resources_size,
mlxplat_hotplug, sizeof(*mlxplat_hotplug));
if (IS_ERR(priv->pdev_hotplug)) {
err = PTR_ERR(priv->pdev_hotplug);
- goto fail_platform_mux_register;
+ goto fail_platform_hotplug_register;
}
}
- /* Set default registers. */
- for (j = 0; j < mlxplat_regmap_config->num_reg_defaults; j++) {
- err = regmap_write(priv->regmap,
- mlxplat_regmap_config->reg_defaults[j].reg,
- mlxplat_regmap_config->reg_defaults[j].def);
- if (err)
- goto fail_platform_mux_register;
- }
-
/* Add LED driver. */
if (mlxplat_led) {
mlxplat_led->regmap = priv->regmap;
@@ -5274,7 +6109,7 @@ static int __init mlxplat_init(void)
sizeof(*mlxplat_led));
if (IS_ERR(priv->pdev_led)) {
err = PTR_ERR(priv->pdev_led);
- goto fail_platform_hotplug_register;
+ goto fail_platform_leds_register;
}
}
@@ -5288,7 +6123,7 @@ static int __init mlxplat_init(void)
sizeof(*mlxplat_regs_io));
if (IS_ERR(priv->pdev_io_regs)) {
err = PTR_ERR(priv->pdev_io_regs);
- goto fail_platform_led_register;
+ goto fail_platform_io_register;
}
}
@@ -5301,7 +6136,7 @@ static int __init mlxplat_init(void)
sizeof(*mlxplat_fan));
if (IS_ERR(priv->pdev_fan)) {
err = PTR_ERR(priv->pdev_fan);
- goto fail_platform_io_regs_register;
+ goto fail_platform_fan_register;
}
}
@@ -5309,56 +6144,40 @@ static int __init mlxplat_init(void)
err = mlxplat_mlxcpld_check_wd_capability(priv->regmap);
if (err)
goto fail_platform_wd_register;
- for (j = 0; j < MLXPLAT_CPLD_WD_MAX_DEVS; j++) {
- if (mlxplat_wd_data[j]) {
- mlxplat_wd_data[j]->regmap = priv->regmap;
- priv->pdev_wd[j] =
- platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", j,
- NULL, 0, mlxplat_wd_data[j],
- sizeof(*mlxplat_wd_data[j]));
- if (IS_ERR(priv->pdev_wd[j])) {
- err = PTR_ERR(priv->pdev_wd[j]);
+ for (i = 0; i < MLXPLAT_CPLD_WD_MAX_DEVS; i++) {
+ if (mlxplat_wd_data[i]) {
+ mlxplat_wd_data[i]->regmap = priv->regmap;
+ priv->pdev_wd[i] =
+ platform_device_register_resndata(&mlxplat_dev->dev, "mlx-wdt", i,
+ NULL, 0, mlxplat_wd_data[i],
+ sizeof(*mlxplat_wd_data[i]));
+ if (IS_ERR(priv->pdev_wd[i])) {
+ err = PTR_ERR(priv->pdev_wd[i]);
goto fail_platform_wd_register;
}
}
}
- /* Sync registers with hardware. */
- regcache_mark_dirty(priv->regmap);
- err = regcache_sync(priv->regmap);
- if (err)
- goto fail_platform_wd_register;
-
return 0;
fail_platform_wd_register:
- while (--j >= 0)
- platform_device_unregister(priv->pdev_wd[j]);
- if (mlxplat_fan)
- platform_device_unregister(priv->pdev_fan);
-fail_platform_io_regs_register:
+ while (--i >= 0)
+ platform_device_unregister(priv->pdev_wd[i]);
+fail_platform_fan_register:
if (mlxplat_regs_io)
platform_device_unregister(priv->pdev_io_regs);
-fail_platform_led_register:
+fail_platform_io_register:
if (mlxplat_led)
platform_device_unregister(priv->pdev_led);
-fail_platform_hotplug_register:
+fail_platform_leds_register:
if (mlxplat_hotplug)
platform_device_unregister(priv->pdev_hotplug);
-fail_platform_mux_register:
- while (--i >= 0)
- platform_device_unregister(priv->pdev_mux[i]);
- platform_device_unregister(priv->pdev_i2c);
-fail_alloc:
- platform_device_unregister(mlxplat_dev);
-
+fail_platform_hotplug_register:
return err;
}
-module_init(mlxplat_init);
-static void __exit mlxplat_exit(void)
+static void mlxplat_pre_exit(struct mlxplat_priv *priv)
{
- struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
int i;
for (i = MLXPLAT_CPLD_WD_MAX_DEVS - 1; i >= 0 ; i--)
@@ -5371,12 +6190,185 @@ static void __exit mlxplat_exit(void)
platform_device_unregister(priv->pdev_led);
if (priv->pdev_hotplug)
platform_device_unregister(priv->pdev_hotplug);
+}
+
+static int
+mlxplat_i2c_mux_complition_notify(void *handle, struct i2c_adapter *parent,
+ struct i2c_adapter *adapters[])
+{
+ struct mlxplat_priv *priv = handle;
+
+ return mlxplat_post_init(priv);
+}
+
+static int mlxplat_i2c_mux_topolgy_init(struct mlxplat_priv *priv)
+{
+ int i, err;
+
+ if (!priv->pdev_i2c) {
+ priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_NOTIFIED;
+ return 0;
+ }
+
+ priv->i2c_main_init_status = MLXPLAT_I2C_MAIN_BUS_HANDLE_CREATED;
+ for (i = 0; i < mlxplat_mux_num; i++) {
+ priv->pdev_mux[i] = platform_device_register_resndata(&priv->pdev_i2c->dev,
+ "i2c-mux-reg", i, NULL, 0,
+ &mlxplat_mux_data[i],
+ sizeof(mlxplat_mux_data[i]));
+ if (IS_ERR(priv->pdev_mux[i])) {
+ err = PTR_ERR(priv->pdev_mux[i]);
+ goto fail_platform_mux_register;
+ }
+ }
- for (i = mlxplat_mux_num - 1; i >= 0 ; i--)
+ return mlxplat_i2c_mux_complition_notify(priv, NULL, NULL);
+
+fail_platform_mux_register:
+ while (--i >= 0)
platform_device_unregister(priv->pdev_mux[i]);
+ return err;
+}
- platform_device_unregister(priv->pdev_i2c);
- platform_device_unregister(mlxplat_dev);
+static void mlxplat_i2c_mux_topolgy_exit(struct mlxplat_priv *priv)
+{
+ int i;
+
+ for (i = mlxplat_mux_num - 1; i >= 0 ; i--) {
+ if (priv->pdev_mux[i])
+ platform_device_unregister(priv->pdev_mux[i]);
+ }
+
+ mlxplat_post_exit();
+}
+
+static int mlxplat_i2c_main_complition_notify(void *handle, int id)
+{
+ struct mlxplat_priv *priv = handle;
+
+ return mlxplat_i2c_mux_topolgy_init(priv);
+}
+
+static int mlxplat_i2c_main_init(struct mlxplat_priv *priv)
+{
+ int nr, err;
+
+ if (!mlxplat_i2c)
+ return 0;
+
+ err = mlxplat_mlxcpld_verify_bus_topology(&nr);
+ if (nr < 0)
+ goto fail_mlxplat_mlxcpld_verify_bus_topology;
+
+ nr = (nr == mlxplat_max_adap_num) ? -1 : nr;
+ mlxplat_i2c->regmap = priv->regmap;
+ mlxplat_i2c->handle = priv;
+
+ priv->pdev_i2c = platform_device_register_resndata(&mlxplat_dev->dev, "i2c_mlxcpld",
+ nr, priv->hotplug_resources,
+ priv->hotplug_resources_size,
+ mlxplat_i2c, sizeof(*mlxplat_i2c));
+ if (IS_ERR(priv->pdev_i2c)) {
+ err = PTR_ERR(priv->pdev_i2c);
+ goto fail_platform_i2c_register;
+ }
+
+ if (priv->i2c_main_init_status == MLXPLAT_I2C_MAIN_BUS_NOTIFIED) {
+ err = mlxplat_i2c_mux_topolgy_init(priv);
+ if (err)
+ goto fail_mlxplat_i2c_mux_topolgy_init;
+ }
+
+ return 0;
+
+fail_mlxplat_i2c_mux_topolgy_init:
+fail_platform_i2c_register:
+fail_mlxplat_mlxcpld_verify_bus_topology:
+ return err;
+}
+
+static void mlxplat_i2c_main_exit(struct mlxplat_priv *priv)
+{
+ mlxplat_i2c_mux_topolgy_exit(priv);
+ if (priv->pdev_i2c)
+ platform_device_unregister(priv->pdev_i2c);
+}
+
+static int __init mlxplat_init(void)
+{
+ unsigned int hotplug_resources_size;
+ struct resource *hotplug_resources;
+ struct mlxplat_priv *priv;
+ int i, err;
+
+ if (!dmi_check_system(mlxplat_dmi_table))
+ return -ENODEV;
+
+ err = mlxplat_pre_init(&hotplug_resources, &hotplug_resources_size);
+ if (err)
+ return err;
+
+ priv = devm_kzalloc(&mlxplat_dev->dev, sizeof(struct mlxplat_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ err = -ENOMEM;
+ goto fail_alloc;
+ }
+ platform_set_drvdata(mlxplat_dev, priv);
+ priv->hotplug_resources = hotplug_resources;
+ priv->hotplug_resources_size = hotplug_resources_size;
+
+ if (!mlxplat_regmap_config)
+ mlxplat_regmap_config = &mlxplat_mlxcpld_regmap_config;
+
+ priv->regmap = devm_regmap_init(&mlxplat_dev->dev, NULL,
+ &mlxplat_mlxcpld_regmap_ctx,
+ mlxplat_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ err = PTR_ERR(priv->regmap);
+ goto fail_alloc;
+ }
+
+ /* Set default registers. */
+ for (i = 0; i < mlxplat_regmap_config->num_reg_defaults; i++) {
+ err = regmap_write(priv->regmap,
+ mlxplat_regmap_config->reg_defaults[i].reg,
+ mlxplat_regmap_config->reg_defaults[i].def);
+ if (err)
+ goto fail_regmap_write;
+ }
+
+ err = mlxplat_i2c_main_init(priv);
+ if (err)
+ goto fail_mlxplat_i2c_main_init;
+
+ /* Sync registers with hardware. */
+ regcache_mark_dirty(priv->regmap);
+ err = regcache_sync(priv->regmap);
+ if (err)
+ goto fail_regcache_sync;
+
+ return 0;
+
+fail_regcache_sync:
+ mlxplat_pre_exit(priv);
+fail_mlxplat_i2c_main_init:
+fail_regmap_write:
+fail_alloc:
+ mlxplat_post_exit();
+
+ return err;
+}
+module_init(mlxplat_init);
+
+static void __exit mlxplat_exit(void)
+{
+ struct mlxplat_priv *priv = platform_get_drvdata(mlxplat_dev);
+
+ if (pm_power_off)
+ pm_power_off = NULL;
+ mlxplat_pre_exit(priv);
+ mlxplat_i2c_main_exit(priv);
}
module_exit(mlxplat_exit);
diff --git a/drivers/platform/x86/nvidia-wmi-ec-backlight.c b/drivers/platform/x86/nvidia-wmi-ec-backlight.c
index baccdf658538..1b572c90c76e 100644
--- a/drivers/platform/x86/nvidia-wmi-ec-backlight.c
+++ b/drivers/platform/x86/nvidia-wmi-ec-backlight.c
@@ -12,6 +12,10 @@
#include <linux/wmi.h>
#include <acpi/video.h>
+static bool force;
+module_param(force, bool, 0444);
+MODULE_PARM_DESC(force, "Force loading (disable acpi_backlight=xxx checks");
+
/**
* wmi_brightness_notify() - helper function for calling WMI-wrapped ACPI method
* @w: Pointer to the struct wmi_device identified by %WMI_BRIGHTNESS_GUID
@@ -91,7 +95,7 @@ static int nvidia_wmi_ec_backlight_probe(struct wmi_device *wdev, const void *ct
int ret;
/* drivers/acpi/video_detect.c also checks that SOURCE == EC */
- if (acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
+ if (!force && acpi_video_get_backlight_type() != acpi_backlight_nvidia_wmi_ec)
return -ENODEV;
/*
diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c
index ca76076fc706..b3622419cd1a 100644
--- a/drivers/platform/x86/simatic-ipc.c
+++ b/drivers/platform/x86/simatic-ipc.c
@@ -46,7 +46,8 @@ static struct {
{SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE},
{SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E},
{SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E},
- {SIMATIC_IPC_IPC427G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
+ {SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
+ {SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G},
};
static int register_platform_devices(u32 station_id)
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 7156ae2ad196..537d6a2d0781 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1887,14 +1887,21 @@ static int sony_nc_kbd_backlight_setup(struct platform_device *pd,
break;
}
- ret = sony_call_snc_handle(handle, probe_base, &result);
- if (ret)
- return ret;
+ /*
+ * Only probe if there is a separate probe_base, otherwise the probe call
+ * is equivalent to __sony_nc_kbd_backlight_mode_set(0), resulting in
+ * the keyboard backlight being turned off.
+ */
+ if (probe_base) {
+ ret = sony_call_snc_handle(handle, probe_base, &result);
+ if (ret)
+ return ret;
- if ((handle == 0x0137 && !(result & 0x02)) ||
- !(result & 0x01)) {
- dprintk("no backlight keyboard found\n");
- return 0;
+ if ((handle == 0x0137 && !(result & 0x02)) ||
+ !(result & 0x01)) {
+ dprintk("no backlight keyboard found\n");
+ return 0;
+ }
}
kbdbl_ctl = kzalloc(sizeof(*kbdbl_ctl), GFP_KERNEL);
diff --git a/drivers/platform/x86/think-lmi.c b/drivers/platform/x86/think-lmi.c
index a01a92769c1a..86b33b74519b 100644
--- a/drivers/platform/x86/think-lmi.c
+++ b/drivers/platform/x86/think-lmi.c
@@ -317,8 +317,8 @@ static int tlmi_get_pwd_settings(struct tlmi_pwdcfg *pwdcfg)
return -EIO;
}
- copy_size = obj->buffer.length < sizeof(struct tlmi_pwdcfg) ?
- obj->buffer.length : sizeof(struct tlmi_pwdcfg);
+ copy_size = min_t(size_t, obj->buffer.length, sizeof(struct tlmi_pwdcfg));
+
memcpy(pwdcfg, obj->buffer.pointer, copy_size);
kfree(obj);
@@ -1089,12 +1089,12 @@ static void tlmi_pwd_setting_release(struct kobject *kobj)
kfree(setting);
}
-static struct kobj_type tlmi_attr_setting_ktype = {
+static const struct kobj_type tlmi_attr_setting_ktype = {
.release = &tlmi_attr_setting_release,
.sysfs_ops = &tlmi_kobj_sysfs_ops,
};
-static struct kobj_type tlmi_pwd_setting_ktype = {
+static const struct kobj_type tlmi_pwd_setting_ktype = {
.release = &tlmi_pwd_setting_release,
.sysfs_ops = &tlmi_kobj_sysfs_ops,
};
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 1195293b22fd..32c10457399e 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -5563,7 +5563,7 @@ static int light_sysfs_set(struct led_classdev *led_cdev,
static enum led_brightness light_sysfs_get(struct led_classdev *led_cdev)
{
- return (light_get_status() == 1) ? LED_FULL : LED_OFF;
+ return (light_get_status() == 1) ? LED_ON : LED_OFF;
}
static struct tpacpi_led_classdev tpacpi_led_thinklight = {
@@ -10311,9 +10311,11 @@ static DEFINE_MUTEX(dytc_mutex);
static int dytc_capabilities;
static bool dytc_mmc_get_available;
-static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
+static int convert_dytc_to_profile(int funcmode, int dytcmode,
+ enum platform_profile_option *profile)
{
- if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
+ switch (funcmode) {
+ case DYTC_FUNCTION_MMC:
switch (dytcmode) {
case DYTC_MODE_MMC_LOWPOWER:
*profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10329,8 +10331,7 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
return -EINVAL;
}
return 0;
- }
- if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
+ case DYTC_FUNCTION_PSC:
switch (dytcmode) {
case DYTC_MODE_PSC_LOWPOWER:
*profile = PLATFORM_PROFILE_LOW_POWER;
@@ -10344,6 +10345,14 @@ static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *p
default: /* Unknown mode */
return -EINVAL;
}
+ return 0;
+ case DYTC_FUNCTION_AMT:
+ /* For now return balanced. It's the closest we have to 'auto' */
+ *profile = PLATFORM_PROFILE_BALANCED;
+ return 0;
+ default:
+ /* Unknown function */
+ return -EOPNOTSUPP;
}
return 0;
}
@@ -10487,11 +10496,11 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
if (err)
goto unlock;
}
- }
- if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
+ } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
if (err)
goto unlock;
+
/* system supports AMT, activate it when on balanced */
if (dytc_capabilities & BIT(DYTC_FC_AMT))
dytc_control_amt(profile == PLATFORM_PROFILE_BALANCED);
@@ -10507,7 +10516,7 @@ static void dytc_profile_refresh(void)
{
enum platform_profile_option profile;
int output, err = 0;
- int perfmode;
+ int perfmode, funcmode;
mutex_lock(&dytc_mutex);
if (dytc_capabilities & BIT(DYTC_FC_MMC)) {
@@ -10515,15 +10524,18 @@ static void dytc_profile_refresh(void)
err = dytc_command(DYTC_CMD_MMC_GET, &output);
else
err = dytc_cql_command(DYTC_CMD_GET, &output);
- } else if (dytc_capabilities & BIT(DYTC_FC_PSC))
+ funcmode = DYTC_FUNCTION_MMC;
+ } else if (dytc_capabilities & BIT(DYTC_FC_PSC)) {
err = dytc_command(DYTC_CMD_GET, &output);
-
+ /* Check if we are PSC mode, or have AMT enabled */
+ funcmode = (output >> DYTC_GET_FUNCTION_BIT) & 0xF;
+ }
mutex_unlock(&dytc_mutex);
if (err)
return;
perfmode = (output >> DYTC_GET_MODE_BIT) & 0xF;
- convert_dytc_to_profile(perfmode, &profile);
+ convert_dytc_to_profile(funcmode, perfmode, &profile);
if (profile != dytc_current_profile) {
dytc_current_profile = profile;
platform_profile_notify();
diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c
index baae3120efd0..13802a3c3591 100644
--- a/drivers/platform/x86/touchscreen_dmi.c
+++ b/drivers/platform/x86/touchscreen_dmi.c
@@ -264,6 +264,23 @@ static const struct ts_dmi_data connect_tablet9_data = {
.properties = connect_tablet9_props,
};
+static const struct property_entry csl_panther_tab_hd_props[] = {
+ PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
+ PROPERTY_ENTRY_U32("touchscreen-min-y", 20),
+ PROPERTY_ENTRY_U32("touchscreen-size-x", 1980),
+ PROPERTY_ENTRY_U32("touchscreen-size-y", 1526),
+ PROPERTY_ENTRY_BOOL("touchscreen-inverted-y"),
+ PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"),
+ PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-csl-panther-tab-hd.fw"),
+ PROPERTY_ENTRY_U32("silead,max-fingers", 10),
+ { }
+};
+
+static const struct ts_dmi_data csl_panther_tab_hd_data = {
+ .acpi_name = "MSSL1680:00",
+ .properties = csl_panther_tab_hd_props,
+};
+
static const struct property_entry cube_iwork8_air_props[] = {
PROPERTY_ENTRY_U32("touchscreen-min-x", 1),
PROPERTY_ENTRY_U32("touchscreen-min-y", 3),
@@ -1081,6 +1098,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* Chuwi Vi8 (CWI501) */
+ .driver_data = (void *)&chuwi_vi8_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Insyde"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "i86"),
+ DMI_MATCH(DMI_BIOS_VERSION, "CHUWI.W86JLBNR01"),
+ },
+ },
+ {
/* Chuwi Vi8 (CWI506) */
.driver_data = (void *)&chuwi_vi8_data,
.matches = {
@@ -1125,6 +1151,14 @@ const struct dmi_system_id touchscreen_dmi_table[] = {
},
},
{
+ /* CSL Panther Tab HD */
+ .driver_data = (void *)&csl_panther_tab_hd_data,
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "CSL Computer GmbH & Co. KG"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "CSL Panther Tab HD"),
+ },
+ },
+ {
/* CUBE iwork8 Air */
.driver_data = (void *)&cube_iwork8_air_data,
.matches = {
diff --git a/drivers/platform/x86/uv_sysfs.c b/drivers/platform/x86/uv_sysfs.c
index 73fc38ee7430..38d1b692d3c0 100644
--- a/drivers/platform/x86/uv_sysfs.c
+++ b/drivers/platform/x86/uv_sysfs.c
@@ -203,7 +203,7 @@ static const struct sysfs_ops hub_sysfs_ops = {
.show = hub_type_show,
};
-static struct kobj_type hub_attr_type = {
+static const struct kobj_type hub_attr_type = {
.release = hub_release,
.sysfs_ops = &hub_sysfs_ops,
.default_groups = uv_hub_groups,
@@ -356,7 +356,7 @@ static const struct sysfs_ops uv_port_sysfs_ops = {
.show = uv_port_type_show,
};
-static struct kobj_type uv_port_attr_type = {
+static const struct kobj_type uv_port_attr_type = {
.release = uv_port_release,
.sysfs_ops = &uv_port_sysfs_ops,
.default_groups = uv_port_groups,
@@ -528,7 +528,7 @@ static const struct sysfs_ops uv_pci_top_sysfs_ops = {
.show = pci_top_type_show,
};
-static struct kobj_type uv_pci_top_attr_type = {
+static const struct kobj_type uv_pci_top_attr_type = {
.release = uv_pci_top_release,
.sysfs_ops = &uv_pci_top_sysfs_ops,
};
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
index 5ffc00480aef..4fe7650dd014 100644
--- a/drivers/platform/x86/wmi.c
+++ b/drivers/platform/x86/wmi.c
@@ -693,15 +693,8 @@ char *wmi_get_acpi_device_uid(const char *guid_string)
}
EXPORT_SYMBOL_GPL(wmi_get_acpi_device_uid);
-static struct wmi_block *dev_to_wblock(struct device *dev)
-{
- return container_of(dev, struct wmi_block, dev.dev);
-}
-
-static struct wmi_device *dev_to_wdev(struct device *dev)
-{
- return container_of(dev, struct wmi_device, dev);
-}
+#define dev_to_wblock(__dev) container_of_const(__dev, struct wmi_block, dev.dev)
+#define dev_to_wdev(__dev) container_of_const(__dev, struct wmi_device, dev)
static inline struct wmi_driver *drv_to_wdrv(struct device_driver *drv)
{
@@ -804,9 +797,9 @@ static struct attribute *wmi_method_attrs[] = {
};
ATTRIBUTE_GROUPS(wmi_method);
-static int wmi_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
+static int wmi_dev_uevent(const struct device *dev, struct kobj_uevent_env *env)
{
- struct wmi_block *wblock = dev_to_wblock(dev);
+ const struct wmi_block *wblock = dev_to_wblock(dev);
if (add_uevent_var(env, "MODALIAS=wmi:%pUL", &wblock->gblock.guid))
return -ENOMEM;
diff --git a/drivers/platform/x86/x86-android-tablets.c b/drivers/platform/x86/x86-android-tablets.c
index 123a4618db55..111b007656fc 100644
--- a/drivers/platform/x86/x86-android-tablets.c
+++ b/drivers/platform/x86/x86-android-tablets.c
@@ -187,7 +187,7 @@ struct x86_dev_info {
/* Generic / shared charger / battery settings */
static const char * const tusb1211_chg_det_psy[] = { "tusb1211-charger-detect" };
static const char * const bq24190_psy[] = { "bq24190-charger" };
-static const char * const bq25890_psy[] = { "bq25890-charger" };
+static const char * const bq25890_psy[] = { "bq25890-charger-0" };
static const struct property_entry fg_bq24190_supply_props[] = {
PROPERTY_ENTRY_STRING_ARRAY("supplied-from", bq24190_psy),