From e0e6bccd4423f44188a45c2c3841c0b2c6825854 Mon Sep 17 00:00:00 2001 From: Nicholas Chin Date: Sat, 27 Nov 2021 22:06:00 -0700 Subject: [PATCH] ec/dell: Add support for the SMSC MEC5035 This is required to prevent the EC from shutting down the system after about 15 seconds after being turned on. If the EC doesn't receive a command meaning "CPU OK" it assumes that the processor has failed and flashes a diagnostic code on the keyboard LEDs to indicate this. This also enables the keyboard and trackpad/trackpoint interfaces. Parts of this code were derived from yet-to-be merged code in CB:44975 (ec: Add support for MEC5055 for Dell laptops) written by Iru Cai. Tested on a Dell Latitude E6400 Signed-off-by: Nicholas Chin Change-Id: Ia420cd51e9a64be5eee4af2c0d113618575522b0 Reviewed-on: https://review.coreboot.org/c/coreboot/+/59703 Reviewed-by: Angel Pons Reviewed-by: Paul Menzel Tested-by: build bot (Jenkins) --- src/ec/dell/mec5035/Kconfig | 4 + src/ec/dell/mec5035/Makefile.inc | 9 +++ src/ec/dell/mec5035/mec5035.c | 122 +++++++++++++++++++++++++++++++ src/ec/dell/mec5035/mec5035.h | 23 ++++++ 4 files changed, 158 insertions(+) create mode 100644 src/ec/dell/mec5035/Kconfig create mode 100644 src/ec/dell/mec5035/Makefile.inc create mode 100644 src/ec/dell/mec5035/mec5035.c create mode 100644 src/ec/dell/mec5035/mec5035.h diff --git a/src/ec/dell/mec5035/Kconfig b/src/ec/dell/mec5035/Kconfig new file mode 100644 index 0000000000..220714371d --- /dev/null +++ b/src/ec/dell/mec5035/Kconfig @@ -0,0 +1,4 @@ +## SPDX-License-Identifier: GPL-2.0-only + +config EC_DELL_MEC5035 + bool diff --git a/src/ec/dell/mec5035/Makefile.inc b/src/ec/dell/mec5035/Makefile.inc new file mode 100644 index 0000000000..4ebdd811f9 --- /dev/null +++ b/src/ec/dell/mec5035/Makefile.inc @@ -0,0 +1,9 @@ +## SPDX-License-Identifier: GPL-2.0-only + +ifeq ($(CONFIG_EC_DELL_MEC5035),y) + +bootblock-y += mec5035.c +romstage-y += mec5035.c +ramstage-y += mec5035.c + +endif diff --git a/src/ec/dell/mec5035/mec5035.c b/src/ec/dell/mec5035/mec5035.c new file mode 100644 index 0000000000..8da11e5b1c --- /dev/null +++ b/src/ec/dell/mec5035/mec5035.c @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include +#include +#include +#include +#include +#include +#include "mec5035.h" + +static const u16 MAILBOX_INDEX = 0x910; +static const u16 MAILBOX_DATA = MAILBOX_INDEX + 1; + +static inline u8 __get_mailbox_register(u8 index) +{ + outb(index + 0x10, MAILBOX_INDEX); + return inb(MAILBOX_DATA); +} + +static inline void __set_mailbox_register(u8 index, u8 data) +{ + outb(index + 0x10, MAILBOX_INDEX); + outb(data, MAILBOX_DATA); +} + +static void wait_ec(void) +{ + u8 busy; + do { + outb(0, MAILBOX_INDEX); + busy = inb(MAILBOX_DATA); + } while (busy); +} + + +static enum cb_err read_mailbox_regs(u8 *data, u8 start, u8 count) +{ + if (start + count >= NUM_REGISTERS) { + printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__); + return CB_ERR_ARG; + } + + while (count--) { + *data = __get_mailbox_register(start); + data++; + start++; + } + + return CB_SUCCESS; +} + +static enum cb_err write_mailbox_regs(const u8 *data, u8 start, u8 count) +{ + if (start + count >= NUM_REGISTERS) { + printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__); + return CB_ERR_ARG; + } + + while (count--) { + __set_mailbox_register(start, *data); + data++; + start++; + } + + return CB_SUCCESS; +} + +static void ec_command(u8 cmd) +{ + outb(0, MAILBOX_INDEX); + outb(cmd, MAILBOX_DATA); + wait_ec(); +} + +u8 mec5035_mouse_touchpad(u8 setting) +{ + u8 buf[15] = {0}; + write_mailbox_regs(&setting, 2, 1); + ec_command(CMD_MOUSE_TP); + /* The vendor firmware reads 15 bytes starting at index 1, presumably + to get some sort of return code. Though I don't know for sure if + this is the case. Assume the first byte is the return code. */ + read_mailbox_regs(buf, 1, 15); + return buf[0]; +} + +void mec5035_early_init(void) +{ + /* If this isn't sent the EC shuts down the system after about 15 + seconds, flashing a pattern on the keyboard LEDs corresponding + to "processor failure" according to Dell service manuals. */ + ec_command(CMD_CPU_OK); +} + +static void mec5035_init(struct device *dev) +{ + /* Unconditionally use this argument for now as this setting + is probably the most sensible default out of the 3 choices. */ + mec5035_mouse_touchpad(TP_PS2_MOUSE); + + pc_keyboard_init(NO_AUX_DEVICE); +} + +static struct device_operations ops = { + .init = mec5035_init, + .read_resources = noop_read_resources, + .set_resources = noop_set_resources +}; + +static struct pnp_info pnp_dev_info[] = { + { NULL, 0, 0, 0, } +}; + +static void mec5035_enable(struct device *dev) +{ + pnp_enable_devices(dev, &ops, ARRAY_SIZE(pnp_dev_info), pnp_dev_info); +} + +struct chip_operations ec_dell_mec5035_ops = { + CHIP_NAME("MEC5035 EC") + .enable_dev = mec5035_enable, +}; diff --git a/src/ec/dell/mec5035/mec5035.h b/src/ec/dell/mec5035/mec5035.h new file mode 100644 index 0000000000..e7a05b64d4 --- /dev/null +++ b/src/ec/dell/mec5035/mec5035.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef _EC_DELL_MEC5035_H_ +#define _EC_DELL_MEC5035_H_ + +#include + +#define NUM_REGISTERS 32 + +/* Touchpad (TP) and mouse related. The EC seems to + default to 0 which results in the TP not working. */ +#define CMD_MOUSE_TP 0x1a +#define SERIAL_MOUSE 0 /* Disable TP, force use of a serial mouse */ +#define PS2_MOUSE 1 /* Disable TP when using a PS/2 mouse */ +#define TP_PS2_MOUSE 2 /* Leave TP enabled when using a PS/2 mouse */ + +#define CMD_CPU_OK 0xc2 + +u8 mec5035_mouse_touchpad(u8 setting); +void mec5035_cpu_ok(void); +void mec5035_early_init(void); + +#endif /* _EC_DELL_MEC5035_H_ */