Commit 1bddd45b authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'platform-drivers-x86-v6.7-5' of...

Merge tag 'platform-drivers-x86-v6.7-5' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86

Pull x86 platform drivers fixes from Ilpo Järvinen:

 - Fan reporting on some ThinkPads

 - Laptop 13 spurious keypresses while suspended

 - Intel PMC correction to avoid crash

* tag 'platform-drivers-x86-v6.7-5' of git://git.kernel.org/pub/scm/linux/kernel/git/pdx86/platform-drivers-x86:
  platform/x86/amd/pmc: Disable keyboard wakeup on AMD Framework 13
  platform/x86/amd/pmc: Move keyboard wakeup disablement detection to pmc-quirks
  platform/x86/amd/pmc: Only run IRQ1 firmware version check on Cezanne
  platform/x86/amd/pmc: Move platform defines to header
  platform/x86/intel/pmc: Fix hang in pmc_core_send_ltr_ignore()
  platform/x86: thinkpad_acpi: fix for incorrect fan reporting on some ThinkPad systems
parents 1a44b007 a55bdad5
...@@ -16,12 +16,17 @@ ...@@ -16,12 +16,17 @@
struct quirk_entry { struct quirk_entry {
u32 s2idle_bug_mmio; u32 s2idle_bug_mmio;
bool spurious_8042;
}; };
static struct quirk_entry quirk_s2idle_bug = { static struct quirk_entry quirk_s2idle_bug = {
.s2idle_bug_mmio = 0xfed80380, .s2idle_bug_mmio = 0xfed80380,
}; };
static struct quirk_entry quirk_spurious_8042 = {
.spurious_8042 = true,
};
static const struct dmi_system_id fwbug_list[] = { static const struct dmi_system_id fwbug_list[] = {
{ {
.ident = "L14 Gen2 AMD", .ident = "L14 Gen2 AMD",
...@@ -193,6 +198,16 @@ static const struct dmi_system_id fwbug_list[] = { ...@@ -193,6 +198,16 @@ static const struct dmi_system_id fwbug_list[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"), DMI_MATCH(DMI_PRODUCT_NAME, "HP Laptop 15s-eq2xxx"),
} }
}, },
/* https://community.frame.work/t/tracking-framework-amd-ryzen-7040-series-lid-wakeup-behavior-feedback/39128 */
{
.ident = "Framework Laptop 13 (Phoenix)",
.driver_data = &quirk_spurious_8042,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Framework"),
DMI_MATCH(DMI_PRODUCT_NAME, "Laptop 13 (AMD Ryzen 7040Series)"),
DMI_MATCH(DMI_BIOS_VERSION, "03.03"),
}
},
{} {}
}; };
...@@ -235,6 +250,9 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev) ...@@ -235,6 +250,9 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
{ {
const struct dmi_system_id *dmi_id; const struct dmi_system_id *dmi_id;
if (dev->cpu_id == AMD_CPU_ID_CZN)
dev->disable_8042_wakeup = true;
dmi_id = dmi_first_match(fwbug_list); dmi_id = dmi_first_match(fwbug_list);
if (!dmi_id) if (!dmi_id)
return; return;
...@@ -242,4 +260,6 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev) ...@@ -242,4 +260,6 @@ void amd_pmc_quirks_init(struct amd_pmc_dev *dev)
if (dev->quirks->s2idle_bug_mmio) if (dev->quirks->s2idle_bug_mmio)
pr_info("Using s2idle quirk to avoid %s platform firmware bug\n", pr_info("Using s2idle quirk to avoid %s platform firmware bug\n",
dmi_id->ident); dmi_id->ident);
if (dev->quirks->spurious_8042)
dev->disable_8042_wakeup = true;
} }
...@@ -91,16 +91,6 @@ ...@@ -91,16 +91,6 @@
#define SMU_MSG_LOG_RESET 0x07 #define SMU_MSG_LOG_RESET 0x07
#define SMU_MSG_LOG_DUMP_DATA 0x08 #define SMU_MSG_LOG_DUMP_DATA 0x08
#define SMU_MSG_GET_SUP_CONSTRAINTS 0x09 #define SMU_MSG_GET_SUP_CONSTRAINTS 0x09
/* List of supported CPU ids */
#define AMD_CPU_ID_RV 0x15D0
#define AMD_CPU_ID_RN 0x1630
#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
#define AMD_CPU_ID_YC 0x14B5
#define AMD_CPU_ID_CB 0x14D8
#define AMD_CPU_ID_PS 0x14E8
#define AMD_CPU_ID_SP 0x14A4
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
#define PMC_MSG_DELAY_MIN_US 50 #define PMC_MSG_DELAY_MIN_US 50
#define RESPONSE_REGISTER_LOOP_MAX 20000 #define RESPONSE_REGISTER_LOOP_MAX 20000
...@@ -766,19 +756,22 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev) ...@@ -766,19 +756,22 @@ static int amd_pmc_get_os_hint(struct amd_pmc_dev *dev)
return -EINVAL; return -EINVAL;
} }
static int amd_pmc_czn_wa_irq1(struct amd_pmc_dev *pdev) static int amd_pmc_wa_irq1(struct amd_pmc_dev *pdev)
{ {
struct device *d; struct device *d;
int rc; int rc;
if (!pdev->major) { /* cezanne platform firmware has a fix in 64.66.0 */
rc = amd_pmc_get_smu_version(pdev); if (pdev->cpu_id == AMD_CPU_ID_CZN) {
if (rc) if (!pdev->major) {
return rc; rc = amd_pmc_get_smu_version(pdev);
} if (rc)
return rc;
}
if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65)) if (pdev->major > 64 || (pdev->major == 64 && pdev->minor > 65))
return 0; return 0;
}
d = bus_find_device_by_name(&serio_bus, NULL, "serio0"); d = bus_find_device_by_name(&serio_bus, NULL, "serio0");
if (!d) if (!d)
...@@ -937,8 +930,8 @@ static int amd_pmc_suspend_handler(struct device *dev) ...@@ -937,8 +930,8 @@ static int amd_pmc_suspend_handler(struct device *dev)
{ {
struct amd_pmc_dev *pdev = dev_get_drvdata(dev); struct amd_pmc_dev *pdev = dev_get_drvdata(dev);
if (pdev->cpu_id == AMD_CPU_ID_CZN && !disable_workarounds) { if (pdev->disable_8042_wakeup && !disable_workarounds) {
int rc = amd_pmc_czn_wa_irq1(pdev); int rc = amd_pmc_wa_irq1(pdev);
if (rc) { if (rc) {
dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc); dev_err(pdev->dev, "failed to adjust keyboard wakeup: %d\n", rc);
......
...@@ -36,9 +36,21 @@ struct amd_pmc_dev { ...@@ -36,9 +36,21 @@ struct amd_pmc_dev {
struct mutex lock; /* generic mutex lock */ struct mutex lock; /* generic mutex lock */
struct dentry *dbgfs_dir; struct dentry *dbgfs_dir;
struct quirk_entry *quirks; struct quirk_entry *quirks;
bool disable_8042_wakeup;
}; };
void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev); void amd_pmc_process_restore_quirks(struct amd_pmc_dev *dev);
void amd_pmc_quirks_init(struct amd_pmc_dev *dev); void amd_pmc_quirks_init(struct amd_pmc_dev *dev);
/* List of supported CPU ids */
#define AMD_CPU_ID_RV 0x15D0
#define AMD_CPU_ID_RN 0x1630
#define AMD_CPU_ID_PCO AMD_CPU_ID_RV
#define AMD_CPU_ID_CZN AMD_CPU_ID_RN
#define AMD_CPU_ID_YC 0x14B5
#define AMD_CPU_ID_CB 0x14D8
#define AMD_CPU_ID_PS 0x14E8
#define AMD_CPU_ID_SP 0x14A4
#define PCI_DEVICE_ID_AMD_1AH_M20H_ROOT 0x1507
#endif /* PMC_H */ #endif /* PMC_H */
...@@ -472,7 +472,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value) ...@@ -472,7 +472,7 @@ int pmc_core_send_ltr_ignore(struct pmc_dev *pmcdev, u32 value)
* is based on the contiguous indexes from ltr_show output. * is based on the contiguous indexes from ltr_show output.
* pmc index and ltr index needs to be calculated from it. * pmc index and ltr index needs to be calculated from it.
*/ */
for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index > 0; pmc_index++) { for (pmc_index = 0; pmc_index < ARRAY_SIZE(pmcdev->pmcs) && ltr_index >= 0; pmc_index++) {
pmc = pmcdev->pmcs[pmc_index]; pmc = pmcdev->pmcs[pmc_index];
if (!pmc) if (!pmc)
......
...@@ -7948,8 +7948,19 @@ static struct ibm_struct volume_driver_data = { ...@@ -7948,8 +7948,19 @@ static struct ibm_struct volume_driver_data = {
* TPACPI_FAN_WR_TPEC is also available and should be used to * TPACPI_FAN_WR_TPEC is also available and should be used to
* command the fan. The X31/X40/X41 seems to have 8 fan levels, * command the fan. The X31/X40/X41 seems to have 8 fan levels,
* but the ACPI tables just mention level 7. * but the ACPI tables just mention level 7.
*
* TPACPI_FAN_RD_TPEC_NS:
* This mode is used for a few ThinkPads (L13 Yoga Gen2, X13 Yoga Gen2 etc.)
* that are using non-standard EC locations for reporting fan speeds.
* Currently these platforms only provide fan rpm reporting.
*
*/ */
#define FAN_RPM_CAL_CONST 491520 /* FAN RPM calculation offset for some non-standard ECFW */
#define FAN_NS_CTRL_STATUS BIT(2) /* Bit which determines control is enabled or not */
#define FAN_NS_CTRL BIT(4) /* Bit which determines control is by host or EC */
enum { /* Fan control constants */ enum { /* Fan control constants */
fan_status_offset = 0x2f, /* EC register 0x2f */ fan_status_offset = 0x2f, /* EC register 0x2f */
fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM) fan_rpm_offset = 0x84, /* EC register 0x84: LSB, 0x85 MSB (RPM)
...@@ -7957,6 +7968,11 @@ enum { /* Fan control constants */ ...@@ -7957,6 +7968,11 @@ enum { /* Fan control constants */
fan_select_offset = 0x31, /* EC register 0x31 (Firmware 7M) fan_select_offset = 0x31, /* EC register 0x31 (Firmware 7M)
bit 0 selects which fan is active */ bit 0 selects which fan is active */
fan_status_offset_ns = 0x93, /* Special status/control offset for non-standard EC Fan1 */
fan2_status_offset_ns = 0x96, /* Special status/control offset for non-standard EC Fan2 */
fan_rpm_status_ns = 0x95, /* Special offset for Fan1 RPM status for non-standard EC */
fan2_rpm_status_ns = 0x98, /* Special offset for Fan2 RPM status for non-standard EC */
TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */ TP_EC_FAN_FULLSPEED = 0x40, /* EC fan mode: full speed */
TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */ TP_EC_FAN_AUTO = 0x80, /* EC fan mode: auto fan control */
...@@ -7967,6 +7983,7 @@ enum fan_status_access_mode { ...@@ -7967,6 +7983,7 @@ enum fan_status_access_mode {
TPACPI_FAN_NONE = 0, /* No fan status or control */ TPACPI_FAN_NONE = 0, /* No fan status or control */
TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */ TPACPI_FAN_RD_ACPI_GFAN, /* Use ACPI GFAN */
TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */ TPACPI_FAN_RD_TPEC, /* Use ACPI EC regs 0x2f, 0x84-0x85 */
TPACPI_FAN_RD_TPEC_NS, /* Use non-standard ACPI EC regs (eg: L13 Yoga gen2 etc.) */
}; };
enum fan_control_access_mode { enum fan_control_access_mode {
...@@ -7994,6 +8011,8 @@ static u8 fan_control_desired_level; ...@@ -7994,6 +8011,8 @@ static u8 fan_control_desired_level;
static u8 fan_control_resume_level; static u8 fan_control_resume_level;
static int fan_watchdog_maxinterval; static int fan_watchdog_maxinterval;
static bool fan_with_ns_addr;
static struct mutex fan_mutex; static struct mutex fan_mutex;
static void fan_watchdog_fire(struct work_struct *ignored); static void fan_watchdog_fire(struct work_struct *ignored);
...@@ -8123,6 +8142,15 @@ static int fan_get_status(u8 *status) ...@@ -8123,6 +8142,15 @@ static int fan_get_status(u8 *status)
} }
break; break;
case TPACPI_FAN_RD_TPEC_NS:
/* Default mode is AUTO which means controlled by EC */
if (!acpi_ec_read(fan_status_offset_ns, &s))
return -EIO;
if (status)
*status = s;
break;
default: default:
return -ENXIO; return -ENXIO;
...@@ -8139,7 +8167,8 @@ static int fan_get_status_safe(u8 *status) ...@@ -8139,7 +8167,8 @@ static int fan_get_status_safe(u8 *status)
if (mutex_lock_killable(&fan_mutex)) if (mutex_lock_killable(&fan_mutex))
return -ERESTARTSYS; return -ERESTARTSYS;
rc = fan_get_status(&s); rc = fan_get_status(&s);
if (!rc) /* NS EC doesn't have register with level settings */
if (!rc && !fan_with_ns_addr)
fan_update_desired_level(s); fan_update_desired_level(s);
mutex_unlock(&fan_mutex); mutex_unlock(&fan_mutex);
...@@ -8166,7 +8195,13 @@ static int fan_get_speed(unsigned int *speed) ...@@ -8166,7 +8195,13 @@ static int fan_get_speed(unsigned int *speed)
if (likely(speed)) if (likely(speed))
*speed = (hi << 8) | lo; *speed = (hi << 8) | lo;
break;
case TPACPI_FAN_RD_TPEC_NS:
if (!acpi_ec_read(fan_rpm_status_ns, &lo))
return -EIO;
if (speed)
*speed = lo ? FAN_RPM_CAL_CONST / lo : 0;
break; break;
default: default:
...@@ -8178,7 +8213,7 @@ static int fan_get_speed(unsigned int *speed) ...@@ -8178,7 +8213,7 @@ static int fan_get_speed(unsigned int *speed)
static int fan2_get_speed(unsigned int *speed) static int fan2_get_speed(unsigned int *speed)
{ {
u8 hi, lo; u8 hi, lo, status;
bool rc; bool rc;
switch (fan_status_access_mode) { switch (fan_status_access_mode) {
...@@ -8194,7 +8229,21 @@ static int fan2_get_speed(unsigned int *speed) ...@@ -8194,7 +8229,21 @@ static int fan2_get_speed(unsigned int *speed)
if (likely(speed)) if (likely(speed))
*speed = (hi << 8) | lo; *speed = (hi << 8) | lo;
break;
case TPACPI_FAN_RD_TPEC_NS:
rc = !acpi_ec_read(fan2_status_offset_ns, &status);
if (rc)
return -EIO;
if (!(status & FAN_NS_CTRL_STATUS)) {
pr_info("secondary fan control not supported\n");
return -EIO;
}
rc = !acpi_ec_read(fan2_rpm_status_ns, &lo);
if (rc)
return -EIO;
if (speed)
*speed = lo ? FAN_RPM_CAL_CONST / lo : 0;
break; break;
default: default:
...@@ -8697,6 +8746,7 @@ static const struct attribute_group fan_driver_attr_group = { ...@@ -8697,6 +8746,7 @@ static const struct attribute_group fan_driver_attr_group = {
#define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */ #define TPACPI_FAN_2FAN 0x0002 /* EC 0x31 bit 0 selects fan2 */
#define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */ #define TPACPI_FAN_2CTL 0x0004 /* selects fan2 control */
#define TPACPI_FAN_NOFAN 0x0008 /* no fan available */ #define TPACPI_FAN_NOFAN 0x0008 /* no fan available */
#define TPACPI_FAN_NS 0x0010 /* For EC with non-Standard register addresses */
static const struct tpacpi_quirk fan_quirk_table[] __initconst = { static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1), TPACPI_QEC_IBM('1', 'Y', TPACPI_FAN_Q1),
...@@ -8715,6 +8765,8 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = { ...@@ -8715,6 +8765,8 @@ static const struct tpacpi_quirk fan_quirk_table[] __initconst = {
TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */ TPACPI_Q_LNV3('N', '2', 'O', TPACPI_FAN_2CTL), /* P1 / X1 Extreme (2nd gen) */
TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */ TPACPI_Q_LNV3('N', '3', '0', TPACPI_FAN_2CTL), /* P15 (1st gen) / P15v (1st gen) */
TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL), /* T15g (2nd gen) */ TPACPI_Q_LNV3('N', '3', '7', TPACPI_FAN_2CTL), /* T15g (2nd gen) */
TPACPI_Q_LNV3('R', '1', 'F', TPACPI_FAN_NS), /* L13 Yoga Gen 2 */
TPACPI_Q_LNV3('N', '2', 'U', TPACPI_FAN_NS), /* X13 Yoga Gen 2*/
TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */ TPACPI_Q_LNV3('N', '1', 'O', TPACPI_FAN_NOFAN), /* X1 Tablet (2nd gen) */
}; };
...@@ -8749,18 +8801,27 @@ static int __init fan_init(struct ibm_init_struct *iibm) ...@@ -8749,18 +8801,27 @@ static int __init fan_init(struct ibm_init_struct *iibm)
return -ENODEV; return -ENODEV;
} }
if (quirks & TPACPI_FAN_NS) {
pr_info("ECFW with non-standard fan reg control found\n");
fan_with_ns_addr = 1;
/* Fan ctrl support from host is undefined for now */
tp_features.fan_ctrl_status_undef = 1;
}
if (gfan_handle) { if (gfan_handle) {
/* 570, 600e/x, 770e, 770x */ /* 570, 600e/x, 770e, 770x */
fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN; fan_status_access_mode = TPACPI_FAN_RD_ACPI_GFAN;
} else { } else {
/* all other ThinkPads: note that even old-style /* all other ThinkPads: note that even old-style
* ThinkPad ECs supports the fan control register */ * ThinkPad ECs supports the fan control register */
if (likely(acpi_ec_read(fan_status_offset, if (fan_with_ns_addr ||
&fan_control_initial_status))) { likely(acpi_ec_read(fan_status_offset, &fan_control_initial_status))) {
int res; int res;
unsigned int speed; unsigned int speed;
fan_status_access_mode = TPACPI_FAN_RD_TPEC; fan_status_access_mode = fan_with_ns_addr ?
TPACPI_FAN_RD_TPEC_NS : TPACPI_FAN_RD_TPEC;
if (quirks & TPACPI_FAN_Q1) if (quirks & TPACPI_FAN_Q1)
fan_quirk1_setup(); fan_quirk1_setup();
/* Try and probe the 2nd fan */ /* Try and probe the 2nd fan */
...@@ -8769,7 +8830,8 @@ static int __init fan_init(struct ibm_init_struct *iibm) ...@@ -8769,7 +8830,8 @@ static int __init fan_init(struct ibm_init_struct *iibm)
if (res >= 0 && speed != FAN_NOT_PRESENT) { if (res >= 0 && speed != FAN_NOT_PRESENT) {
/* It responded - so let's assume it's there */ /* It responded - so let's assume it's there */
tp_features.second_fan = 1; tp_features.second_fan = 1;
tp_features.second_fan_ctl = 1; /* fan control not currently available for ns ECFW */
tp_features.second_fan_ctl = !fan_with_ns_addr;
pr_info("secondary fan control detected & enabled\n"); pr_info("secondary fan control detected & enabled\n");
} else { } else {
/* Fan not auto-detected */ /* Fan not auto-detected */
...@@ -8944,6 +9006,7 @@ static int fan_read(struct seq_file *m) ...@@ -8944,6 +9006,7 @@ static int fan_read(struct seq_file *m)
str_enabled_disabled(status), status); str_enabled_disabled(status), status);
break; break;
case TPACPI_FAN_RD_TPEC_NS:
case TPACPI_FAN_RD_TPEC: case TPACPI_FAN_RD_TPEC:
/* all except 570, 600e/x, 770e, 770x */ /* all except 570, 600e/x, 770e, 770x */
rc = fan_get_status_safe(&status); rc = fan_get_status_safe(&status);
...@@ -8958,13 +9021,22 @@ static int fan_read(struct seq_file *m) ...@@ -8958,13 +9021,22 @@ static int fan_read(struct seq_file *m)
seq_printf(m, "speed:\t\t%d\n", speed); seq_printf(m, "speed:\t\t%d\n", speed);
if (status & TP_EC_FAN_FULLSPEED) if (fan_status_access_mode == TPACPI_FAN_RD_TPEC_NS) {
/* Disengaged mode takes precedence */ /*
seq_printf(m, "level:\t\tdisengaged\n"); * No full speed bit in NS EC
else if (status & TP_EC_FAN_AUTO) * EC Auto mode is set by default.
seq_printf(m, "level:\t\tauto\n"); * No other levels settings available
else */
seq_printf(m, "level:\t\t%d\n", status); seq_printf(m, "level:\t\t%s\n", status & FAN_NS_CTRL ? "unknown" : "auto");
} else {
if (status & TP_EC_FAN_FULLSPEED)
/* Disengaged mode takes precedence */
seq_printf(m, "level:\t\tdisengaged\n");
else if (status & TP_EC_FAN_AUTO)
seq_printf(m, "level:\t\tauto\n");
else
seq_printf(m, "level:\t\t%d\n", status);
}
break; break;
case TPACPI_FAN_NONE: case TPACPI_FAN_NONE:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment