summaryrefslogtreecommitdiff
path: root/src/ec/system76
diff options
context:
space:
mode:
Diffstat (limited to 'src/ec/system76')
-rw-r--r--src/ec/system76/ec/Makefile.inc6
-rw-r--r--src/ec/system76/ec/system76_ec.c61
2 files changed, 67 insertions, 0 deletions
diff --git a/src/ec/system76/ec/Makefile.inc b/src/ec/system76/ec/Makefile.inc
new file mode 100644
index 0000000000..382daa6581
--- /dev/null
+++ b/src/ec/system76/ec/Makefile.inc
@@ -0,0 +1,6 @@
+ifeq ($(CONFIG_EC_SYSTEM76_EC),y)
+
+all-y += system76_ec.c
+smm-$(CONFIG_DEBUG_SMI) += system76_ec.c
+
+endif
diff --git a/src/ec/system76/ec/system76_ec.c b/src/ec/system76/ec/system76_ec.c
new file mode 100644
index 0000000000..ddcb602d4c
--- /dev/null
+++ b/src/ec/system76/ec/system76_ec.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <arch/io.h>
+#include <console/system76_ec.h>
+#include <timer.h>
+
+// This is the command region for System76 EC firmware. It must be
+// enabled for LPC in the mainboard.
+#define SYSTEM76_EC_BASE 0x0E00
+#define SYSTEM76_EC_SIZE 256
+
+#define REG_CMD 0
+#define REG_RESULT 1
+
+// When command register is 0, command is complete
+#define CMD_FINISHED 0
+
+// Print command. Registers are unique for each command
+#define CMD_PRINT 4
+#define CMD_PRINT_REG_FLAGS 2
+#define CMD_PRINT_REG_LEN 3
+#define CMD_PRINT_REG_DATA 4
+
+static inline uint8_t system76_ec_read(uint8_t addr)
+{
+ return inb(SYSTEM76_EC_BASE + (uint16_t)addr);
+}
+
+static inline void system76_ec_write(uint8_t addr, uint8_t data)
+{
+ outb(data, SYSTEM76_EC_BASE + (uint16_t)addr);
+}
+
+void system76_ec_init(void)
+{
+ // Clear entire command region
+ for (int i = 0; i < SYSTEM76_EC_SIZE; i++)
+ system76_ec_write((uint8_t)i, 0);
+}
+
+void system76_ec_flush(void)
+{
+ system76_ec_write(REG_CMD, CMD_PRINT);
+
+ // Wait for command completion, for up to 10 milliseconds, with a
+ // test period of 1 microsecond
+ wait_us(10000, system76_ec_read(REG_CMD) == CMD_FINISHED);
+
+ system76_ec_write(CMD_PRINT_REG_LEN, 0);
+}
+
+void system76_ec_print(uint8_t byte)
+{
+ uint8_t len = system76_ec_read(CMD_PRINT_REG_LEN);
+ system76_ec_write(CMD_PRINT_REG_DATA + len, byte);
+ system76_ec_write(CMD_PRINT_REG_LEN, len + 1);
+
+ // If we hit the end of the buffer, or were given a newline, flush
+ if (byte == '\n' || len >= (SYSTEM76_EC_SIZE - CMD_PRINT_REG_DATA))
+ system76_ec_flush();
+}