aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform/x86/thinkpad_acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 12:14:39 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2022-03-25 12:14:39 -0700
commit1464677662943738741500a6f16b85d36bbde2be (patch)
tree316d8a47d4cc6d2f579cbed80e2f977a0aed64ed /drivers/platform/x86/thinkpad_acpi.c
parentMerge tag 'kbuild-gnu11-v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/masahiroy/linux-kbuild (diff)
parentplatform/x86: think-lmi: Certificate authentication support (diff)
downloadlinux-dev-1464677662943738741500a6f16b85d36bbde2be.tar.xz
linux-dev-1464677662943738741500a6f16b85d36bbde2be.zip
Merge tag 'platform-drivers-x86-v5.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86
Pull x86 platform driver updates from Hans de Goede: "New drivers: - AMD Host System Management Port (HSMP) - Intel Software Defined Silicon Removed drivers (functionality folded into other drivers): - intel_cht_int33fe_microb - surface3_button amd-pmc: - s2idle bug-fixes - Support for AMD Spill to DRAM STB feature hp-wmi: - Fix SW_TABLET_MODE detection method (and other fixes) - Support omen thermal profile policy v1 serial-multi-instantiate: - Add SPI device support - Add support for CS35L41 amplifiers used in new laptops think-lmi: - syfs-class-firmware-attributes Certificate authentication support thinkpad_acpi: - Fixes + quirks - Add platform_profile support on AMD based ThinkPads x86-android-tablets: - Improve Asus ME176C / TF103C support - Support Nextbook Ares 8, Lenovo Tab 2 830 and 1050 tablets Lots of various other small fixes and hardware-id additions" * tag 'platform-drivers-x86-v5.18-1' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86: (60 commits) platform/x86: think-lmi: Certificate authentication support Documentation: syfs-class-firmware-attributes: Lenovo Certificate support platform/x86: amd-pmc: Only report STB errors when STB enabled platform/x86: amd-pmc: Drop CPU QoS workaround platform/x86: amd-pmc: Output error codes in messages platform/x86: amd-pmc: Move to later in the suspend process ACPI / x86: Add support for LPS0 callback handler platform/x86: thinkpad_acpi: consistently check fan_get_status return. platform/x86: hp-wmi: support omen thermal profile policy v1 platform/x86: hp-wmi: Changing bios_args.data to be dynamically allocated platform/x86: hp-wmi: Fix 0x05 error code reported by several WMI calls platform/x86: hp-wmi: Fix SW_TABLET_MODE detection method platform/x86: hp-wmi: Fix hp_wmi_read_int() reporting error (0x05) platform/x86: amd-pmc: Validate entry into the deepest state on resume platform/x86: thinkpad_acpi: Don't use test_bit on an integer platform/x86: thinkpad_acpi: Fix compiler warning about uninitialized err variable platform/x86: thinkpad_acpi: clean up dytc profile convert platform/x86: x86-android-tablets: Depend on EFI and SPI platform/x86: amd-pmc: uninitialized variable in amd_pmc_s2d_init() platform/x86: intel-uncore-freq: fix uncore_freq_common_init() error codes ...
Diffstat (limited to 'drivers/platform/x86/thinkpad_acpi.c')
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c221
1 files changed, 144 insertions, 77 deletions
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index 7d0947b827e2..c568fae56db2 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -728,11 +728,10 @@ static void __init drv_acpi_handle_init(const char *name,
static acpi_status __init tpacpi_acpi_handle_locate_callback(acpi_handle handle,
u32 level, void *context, void **return_value)
{
- struct acpi_device *dev;
if (!strcmp(context, "video")) {
- if (acpi_bus_get_device(handle, &dev))
- return AE_OK;
- if (strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev)))
+ struct acpi_device *dev = acpi_fetch_acpi_dev(handle);
+
+ if (!dev || strcmp(ACPI_VIDEO_HID, acpi_device_hid(dev)))
return AE_OK;
}
@@ -786,7 +785,6 @@ static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data)
static int __init setup_acpi_notify(struct ibm_struct *ibm)
{
acpi_status status;
- int rc;
BUG_ON(!ibm->acpi);
@@ -796,9 +794,9 @@ static int __init setup_acpi_notify(struct ibm_struct *ibm)
vdbg_printk(TPACPI_DBG_INIT,
"setting up ACPI notify for %s\n", ibm->name);
- rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device);
- if (rc < 0) {
- pr_err("acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc);
+ ibm->acpi->device = acpi_fetch_acpi_dev(*ibm->acpi->handle);
+ if (!ibm->acpi->device) {
+ pr_err("acpi_fetch_acpi_dev(%s) failed\n", ibm->name);
return -ENODEV;
}
@@ -6723,7 +6721,8 @@ static int __init tpacpi_query_bcl_levels(acpi_handle handle)
struct acpi_device *device, *child;
int rc;
- if (acpi_bus_get_device(handle, &device))
+ device = acpi_fetch_acpi_dev(handle);
+ if (!device)
return 0;
rc = 0;
@@ -8286,7 +8285,7 @@ static int fan_set_enable(void)
case TPACPI_FAN_WR_ACPI_FANS:
case TPACPI_FAN_WR_TPEC:
rc = fan_get_status(&s);
- if (rc < 0)
+ if (rc)
break;
/* Don't go out of emergency fan mode */
@@ -8305,7 +8304,7 @@ static int fan_set_enable(void)
case TPACPI_FAN_WR_ACPI_SFAN:
rc = fan_get_status(&s);
- if (rc < 0)
+ if (rc)
break;
s &= 0x07;
@@ -8699,10 +8698,7 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_Q_LNV3('N', '2', 'N', TPACPI_FAN_2CTL), /* P53 / P73 */
TPACPI_Q_LNV3('N', '2', 'E', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (1st gen) */
TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */
- TPACPI_Q_LNV3('N', '2', 'V', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (3nd gen) */
- TPACPI_Q_LNV3('N', '4', '0', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (4nd gen) */
TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */
- TPACPI_Q_LNV3('N', '3', '2', TPACPI_FAN_2CTL), /* X1 Carbon (9th gen) */
TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL), /* T15g (2nd gen) */
TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
};
@@ -8746,6 +8742,9 @@ static int __init fan_init(struct ibm_init_struct *iibm)
* ThinkPad ECs supports the fan control register */
if (likely(acpi_ec_read(fan_status_offset,
&fan_control_initial_status))) {
+ int res;
+ unsigned int speed;
+
fan_status_access_mode = TPACPI_FAN_RD_TPEC;
if (quirks & TPACPI_FAN_Q1)
fan_quirk1_setup();
@@ -8758,6 +8757,15 @@ static int __init fan_init(struct ibm_init_struct *iibm)
tp_features.second_fan_ctl = 1;
pr_info("secondary fan control enabled\n");
}
+ /* Try and probe the 2nd fan */
+ res = fan2_get_speed(&speed);
+ if (res >= 0) {
+ /* It responded - so let's assume it's there */
+ tp_features.second_fan = 1;
+ tp_features.second_fan_ctl = 1;
+ pr_info("secondary fan control detected & enabled\n");
+ }
+
} else {
pr_err("ThinkPad ACPI EC access misbehaving, fan status and control unavailable\n");
return -ENODEV;
@@ -8835,7 +8843,7 @@ static void fan_suspend(void)
/* Store fan status in cache */
fan_control_resume_level = 0;
rc = fan_get_status_safe(&fan_control_resume_level);
- if (rc < 0)
+ if (rc)
pr_notice("failed to read fan level for later restore during resume: %d\n",
rc);
@@ -8856,7 +8864,7 @@ static void fan_resume(void)
if (!fan_control_allowed ||
!fan_control_resume_level ||
- (fan_get_status_safe(&current_level) < 0))
+ fan_get_status_safe(&current_level))
return;
switch (fan_control_access_mode) {
@@ -8910,7 +8918,7 @@ static int fan_read(struct seq_file *m)
case TPACPI_FAN_RD_ACPI_GFAN:
/* 570, 600e/x, 770e, 770x */
rc = fan_get_status_safe(&status);
- if (rc < 0)
+ if (rc)
return rc;
seq_printf(m, "status:\t\t%s\n"
@@ -8921,7 +8929,7 @@ static int fan_read(struct seq_file *m)
case TPACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */
rc = fan_get_status_safe(&status);
- if (rc < 0)
+ if (rc)
return rc;
seq_printf(m, "status:\t\t%s\n",
@@ -10122,6 +10130,7 @@ static struct ibm_struct proxsensor_driver_data = {
#define DYTC_CMD_FUNC_CAP 3 /* To get DYTC capabilities */
#define DYTC_FC_MMC 27 /* MMC Mode supported */
+#define DYTC_FC_PSC 29 /* PSC Mode supported */
#define DYTC_GET_FUNCTION_BIT 8 /* Bits 8-11 - function setting */
#define DYTC_GET_MODE_BIT 12 /* Bits 12-15 - mode setting */
@@ -10132,12 +10141,17 @@ static struct ibm_struct proxsensor_driver_data = {
#define DYTC_FUNCTION_STD 0 /* Function = 0, standard mode */
#define DYTC_FUNCTION_CQL 1 /* Function = 1, lap mode */
-#define DYTC_FUNCTION_MMC 11 /* Function = 11, desk mode */
+#define DYTC_FUNCTION_MMC 11 /* Function = 11, MMC mode */
+#define DYTC_FUNCTION_PSC 13 /* Function = 13, PSC mode */
+
+#define DYTC_MODE_MMC_PERFORM 2 /* High power mode aka performance */
+#define DYTC_MODE_MMC_LOWPOWER 3 /* Low power mode */
+#define DYTC_MODE_MMC_BALANCE 0xF /* Default mode aka balanced */
+#define DYTC_MODE_MMC_DEFAULT 0 /* Default mode from MMC_GET, aka balanced */
-#define DYTC_MODE_PERFORM 2 /* High power mode aka performance */
-#define DYTC_MODE_LOWPOWER 3 /* Low power mode */
-#define DYTC_MODE_BALANCE 0xF /* Default mode aka balanced */
-#define DYTC_MODE_MMC_BALANCE 0 /* Default mode from MMC_GET, aka balanced */
+#define DYTC_MODE_PSC_LOWPOWER 3 /* Low power mode */
+#define DYTC_MODE_PSC_BALANCE 5 /* Default mode aka balanced */
+#define DYTC_MODE_PSC_PERFORM 7 /* High power mode aka performance */
#define DYTC_ERR_MASK 0xF /* Bits 0-3 in cmd result are the error result */
#define DYTC_ERR_SUCCESS 1 /* CMD completed successful */
@@ -10147,10 +10161,16 @@ static struct ibm_struct proxsensor_driver_data = {
(mode) << DYTC_SET_MODE_BIT | \
(on) << DYTC_SET_VALID_BIT)
-#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 0)
+#define DYTC_DISABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 0)
+#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_MMC_BALANCE, 1)
-#define DYTC_ENABLE_CQL DYTC_SET_COMMAND(DYTC_FUNCTION_CQL, DYTC_MODE_BALANCE, 1)
+enum dytc_profile_funcmode {
+ DYTC_FUNCMODE_NONE = 0,
+ DYTC_FUNCMODE_MMC,
+ DYTC_FUNCMODE_PSC,
+};
+static enum dytc_profile_funcmode dytc_profile_available;
static enum platform_profile_option dytc_current_profile;
static atomic_t dytc_ignore_event = ATOMIC_INIT(0);
static DEFINE_MUTEX(dytc_mutex);
@@ -10158,19 +10178,37 @@ static bool dytc_mmc_get_available;
static int convert_dytc_to_profile(int dytcmode, enum platform_profile_option *profile)
{
- switch (dytcmode) {
- case DYTC_MODE_LOWPOWER:
- *profile = PLATFORM_PROFILE_LOW_POWER;
- break;
- case DYTC_MODE_BALANCE:
- case DYTC_MODE_MMC_BALANCE:
- *profile = PLATFORM_PROFILE_BALANCED;
- break;
- case DYTC_MODE_PERFORM:
- *profile = PLATFORM_PROFILE_PERFORMANCE;
- break;
- default: /* Unknown mode */
- return -EINVAL;
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+ switch (dytcmode) {
+ case DYTC_MODE_MMC_LOWPOWER:
+ *profile = PLATFORM_PROFILE_LOW_POWER;
+ break;
+ case DYTC_MODE_MMC_DEFAULT:
+ case DYTC_MODE_MMC_BALANCE:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case DYTC_MODE_MMC_PERFORM:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ default: /* Unknown mode */
+ return -EINVAL;
+ }
+ return 0;
+ }
+ if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+ switch (dytcmode) {
+ case DYTC_MODE_PSC_LOWPOWER:
+ *profile = PLATFORM_PROFILE_LOW_POWER;
+ break;
+ case DYTC_MODE_PSC_BALANCE:
+ *profile = PLATFORM_PROFILE_BALANCED;
+ break;
+ case DYTC_MODE_PSC_PERFORM:
+ *profile = PLATFORM_PROFILE_PERFORMANCE;
+ break;
+ default: /* Unknown mode */
+ return -EINVAL;
+ }
}
return 0;
}
@@ -10179,13 +10217,22 @@ static int convert_profile_to_dytc(enum platform_profile_option profile, int *pe
{
switch (profile) {
case PLATFORM_PROFILE_LOW_POWER:
- *perfmode = DYTC_MODE_LOWPOWER;
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+ *perfmode = DYTC_MODE_MMC_LOWPOWER;
+ else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+ *perfmode = DYTC_MODE_PSC_LOWPOWER;
break;
case PLATFORM_PROFILE_BALANCED:
- *perfmode = DYTC_MODE_BALANCE;
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+ *perfmode = DYTC_MODE_MMC_BALANCE;
+ else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+ *perfmode = DYTC_MODE_PSC_BALANCE;
break;
case PLATFORM_PROFILE_PERFORMANCE:
- *perfmode = DYTC_MODE_PERFORM;
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC)
+ *perfmode = DYTC_MODE_MMC_PERFORM;
+ else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+ *perfmode = DYTC_MODE_PSC_PERFORM;
break;
default: /* Unknown profile */
return -EOPNOTSUPP;
@@ -10251,6 +10298,7 @@ static int dytc_cql_command(int command, int *output)
static int dytc_profile_set(struct platform_profile_handler *pprof,
enum platform_profile_option profile)
{
+ int perfmode;
int output;
int err;
@@ -10258,25 +10306,31 @@ static int dytc_profile_set(struct platform_profile_handler *pprof,
if (err)
return err;
- if (profile == PLATFORM_PROFILE_BALANCED) {
- /*
- * To get back to balanced mode we need to issue a reset command.
- * Note we still need to disable CQL mode before hand and re-enable
- * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
- * stuck at 0 for aprox. 30 minutes.
- */
- err = dytc_cql_command(DYTC_CMD_RESET, &output);
- if (err)
- goto unlock;
- } else {
- int perfmode;
-
- err = convert_profile_to_dytc(profile, &perfmode);
- if (err)
- goto unlock;
+ err = convert_profile_to_dytc(profile, &perfmode);
+ if (err)
+ goto unlock;
- /* Determine if we are in CQL mode. This alters the commands we do */
- err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1), &output);
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+ if (profile == PLATFORM_PROFILE_BALANCED) {
+ /*
+ * To get back to balanced mode we need to issue a reset command.
+ * Note we still need to disable CQL mode before hand and re-enable
+ * it afterwards, otherwise dytc_lapmode gets reset to 0 and stays
+ * stuck at 0 for aprox. 30 minutes.
+ */
+ err = dytc_cql_command(DYTC_CMD_RESET, &output);
+ if (err)
+ goto unlock;
+ } else {
+ /* Determine if we are in CQL mode. This alters the commands we do */
+ err = dytc_cql_command(DYTC_SET_COMMAND(DYTC_FUNCTION_MMC, perfmode, 1),
+ &output);
+ if (err)
+ goto unlock;
+ }
+ }
+ if (dytc_profile_available == DYTC_FUNCMODE_PSC) {
+ err = dytc_command(DYTC_SET_COMMAND(DYTC_FUNCTION_PSC, perfmode, 1), &output);
if (err)
goto unlock;
}
@@ -10290,14 +10344,18 @@ unlock:
static void dytc_profile_refresh(void)
{
enum platform_profile_option profile;
- int output, err;
+ int output, err = 0;
int perfmode;
mutex_lock(&dytc_mutex);
- if (dytc_mmc_get_available)
- err = dytc_command(DYTC_CMD_MMC_GET, &output);
- else
- err = dytc_cql_command(DYTC_CMD_GET, &output);
+ if (dytc_profile_available == DYTC_FUNCMODE_MMC) {
+ if (dytc_mmc_get_available)
+ err = dytc_command(DYTC_CMD_MMC_GET, &output);
+ else
+ err = dytc_cql_command(DYTC_CMD_GET, &output);
+ } else if (dytc_profile_available == DYTC_FUNCMODE_PSC)
+ err = dytc_command(DYTC_CMD_GET, &output);
+
mutex_unlock(&dytc_mutex);
if (err)
return;
@@ -10324,6 +10382,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
set_bit(PLATFORM_PROFILE_BALANCED, dytc_profile.choices);
set_bit(PLATFORM_PROFILE_PERFORMANCE, dytc_profile.choices);
+ dytc_profile_available = DYTC_FUNCMODE_NONE;
err = dytc_command(DYTC_CMD_QUERY, &output);
if (err)
return err;
@@ -10335,27 +10394,34 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
if (dytc_version < 5)
return -ENODEV;
- /* Check what capabilities are supported. Currently MMC is needed */
+ /* Check what capabilities are supported */
err = dytc_command(DYTC_CMD_FUNC_CAP, &output);
if (err)
return err;
- if (!(output & BIT(DYTC_FC_MMC))) {
- dbg_printk(TPACPI_DBG_INIT, " DYTC MMC mode not supported\n");
+
+ if (output & BIT(DYTC_FC_MMC)) { /* MMC MODE */
+ dytc_profile_available = DYTC_FUNCMODE_MMC;
+
+ /*
+ * Check if MMC_GET functionality available
+ * Version > 6 and return success from MMC_GET command
+ */
+ dytc_mmc_get_available = false;
+ if (dytc_version >= 6) {
+ err = dytc_command(DYTC_CMD_MMC_GET, &output);
+ if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
+ dytc_mmc_get_available = true;
+ }
+ } else if (output & BIT(DYTC_FC_PSC)) { /* PSC MODE */
+ dytc_profile_available = DYTC_FUNCMODE_PSC;
+ } else {
+ dbg_printk(TPACPI_DBG_INIT, "No DYTC support available\n");
return -ENODEV;
}
dbg_printk(TPACPI_DBG_INIT,
"DYTC version %d: thermal mode available\n", dytc_version);
- /*
- * Check if MMC_GET functionality available
- * Version > 6 and return success from MMC_GET command
- */
- dytc_mmc_get_available = false;
- if (dytc_version >= 6) {
- err = dytc_command(DYTC_CMD_MMC_GET, &output);
- if (!err && ((output & DYTC_ERR_MASK) == DYTC_ERR_SUCCESS))
- dytc_mmc_get_available = true;
- }
+
/* Create platform_profile structure and register */
err = platform_profile_register(&dytc_profile);
/*
@@ -10373,6 +10439,7 @@ static int tpacpi_dytc_profile_init(struct ibm_init_struct *iibm)
static void dytc_profile_exit(void)
{
+ dytc_profile_available = DYTC_FUNCMODE_NONE;
platform_profile_remove();
}