summaryrefslogtreecommitdiff
path: root/src/ec/dell/mec5055/mec5055.c
diff options
context:
space:
mode:
authorIru Cai <mytbk920423@gmail.com>2020-06-07 21:40:21 +0800
committerIru Cai <mytbk920423@gmail.com>2020-12-28 21:30:33 +0800
commit37c1822ba1a1d98c81270ab3b708ed57d1c6c88a (patch)
tree8182f8c2fa5cc7d6c284b46734f8bc7003843aab /src/ec/dell/mec5055/mec5055.c
parenta5746aaa4ee53277c817c7fd3293ba3a851d0fc5 (diff)
downloadcoreboot-37c1822ba1a1d98c81270ab3b708ed57d1c6c88a.tar.xz
ec: Add support for MEC5055 for Dell laptops
This EC support code is required to boot various Dell Latitude laptops, otherwise the laptop will shut down in a minute after being powered on. Tested on Dell Latitude E7240. Change-Id: Iee68ea52dcf0242315868a46b5e4768303e30dce Signed-off-by: Iru Cai <mytbk920423@gmail.com>
Diffstat (limited to 'src/ec/dell/mec5055/mec5055.c')
-rw-r--r--src/ec/dell/mec5055/mec5055.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/src/ec/dell/mec5055/mec5055.c b/src/ec/dell/mec5055/mec5055.c
new file mode 100644
index 0000000000..4e41229a13
--- /dev/null
+++ b/src/ec/dell/mec5055/mec5055.c
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/io.h>
+#include <console/console.h>
+#include "mec5055.h"
+
+static const u16 EC_CTRL = 0x910;
+static const u16 EC_DATA = 0x911;
+
+static void wait_ec(void)
+{
+ u8 v;
+ do {
+ outb(0, EC_CTRL);
+ v = inb(EC_DATA);
+ } while (v != 0);
+}
+
+static enum cb_err read_ec_regs(u8 start, u8 *sdata, u8 count)
+{
+ if (start >= 0x20 || start + count > 0x20) {
+ printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
+ return CB_ERR_ARG;
+ }
+
+ while (count--) {
+ outb(start + 0x10, EC_CTRL);
+ *sdata = inb(EC_DATA);
+ sdata++;
+ start++;
+ }
+
+ return CB_SUCCESS;
+}
+
+static enum cb_err write_ec_regs(u8 start, const u8 *sdata, u8 count)
+{
+ if (start >= 0x20 || start + count > 0x20) {
+ printk(BIOS_ERR, "%s: Invalid start or count argument.\n", __func__);
+ return CB_ERR_ARG;
+ }
+
+ while (count--) {
+ outb(start + 0x10, EC_CTRL);
+ outb(*sdata, EC_DATA);
+ sdata++;
+ start++;
+ }
+
+ return CB_SUCCESS;
+}
+
+/*
+ * Steps to communicate with the EC:
+ * 1. send command:
+ * - write arguments to EC[2:]
+ * - send 0 to CTRL then cmd to DATA
+ * 2. wait for EC
+ * 3. receive result: result may starts at EC[0] or EC[1]
+ */
+
+/* send command to EC and wait, command at cmd[0], args in cmd[2:] */
+static enum cb_err ec_send_command(const u8 *cmd, int argc)
+{
+ int result = CB_SUCCESS;
+
+ if (argc > 0) {
+ if (argc > 0x1e) {
+ printk(BIOS_ERR, "%s: argc too big.\n", __func__);
+ result = CB_ERR_ARG;
+ } else {
+ result = write_ec_regs(2, cmd + 2, argc);
+ }
+ }
+
+ outb(0, EC_CTRL);
+ outb(cmd[0], EC_DATA);
+ wait_ec();
+ return result;
+}
+
+/* receive result from EC[0:] */
+enum cb_err mec5055_ec_command_0(u8 *buf, u8 cmd, int argc)
+{
+ buf[0] = cmd;
+ enum cb_err res = ec_send_command(buf, argc);
+ if (res != CB_SUCCESS) {
+ printk(BIOS_ERR, "error: %s returns %d.\n", __func__, res);
+ return res;
+ }
+
+ return read_ec_regs(0, buf, 0x10);
+}
+
+/* receive result from EC[1:] */
+enum cb_err mec5055_ec_command_1(u8 cmd, const u8 *cmd_buf, int argc, u8 *res_buf, int res_size)
+{
+ if (argc >= 0x1e)
+ argc = 0x1e;
+
+ if (res_size >= 0x1f)
+ res_size = 0x1f;
+
+ enum cb_err res = write_ec_regs(2, cmd_buf, argc);
+ if (res != CB_SUCCESS) {
+ printk(BIOS_ERR, "error: %s returns %d.\n", __func__, res);
+ return res;
+ }
+
+ outb(0, EC_CTRL);
+ outb(cmd, EC_DATA);
+ wait_ec();
+
+ return read_ec_regs(1, res_buf, res_size);
+}