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 <nic.c3.14@gmail.com>
Change-Id: Ia420cd51e9a64be5eee4af2c0d113618575522b0
Reviewed-on: https://review.coreboot.org/c/coreboot/+/59703
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Paul Menzel <paulepanter@mailbox.org>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Nicholas Chin 2021-11-27 22:06:00 -07:00 committed by Felix Held
parent 6bd733b7d4
commit e0e6bccd44
4 changed files with 158 additions and 0 deletions

View File

@ -0,0 +1,4 @@
## SPDX-License-Identifier: GPL-2.0-only
config EC_DELL_MEC5035
bool

View File

@ -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

View File

@ -0,0 +1,122 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/io.h>
#include <console/console.h>
#include <device/device.h>
#include <device/pnp.h>
#include <pc80/keyboard.h>
#include <stdint.h>
#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,
};

View File

@ -0,0 +1,23 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef _EC_DELL_MEC5035_H_
#define _EC_DELL_MEC5035_H_
#include <stdint.h>
#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_ */