summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/console/Kconfig7
-rw-r--r--src/console/console.c4
-rw-r--r--src/ec/system76/ec/Makefile.inc6
-rw-r--r--src/ec/system76/ec/system76_ec.c61
-rw-r--r--src/include/console/system76_ec.h35
5 files changed, 113 insertions, 0 deletions
diff --git a/src/console/Kconfig b/src/console/Kconfig
index 7c6e9bc5e0..bad6c564fc 100644
--- a/src/console/Kconfig
+++ b/src/console/Kconfig
@@ -302,6 +302,13 @@ config SPI_CONSOLE
This is currently working only in ramstage due to how the spi
drivers are written.
+config CONSOLE_SYSTEM76_EC
+ bool "System76 EC console output"
+ default n
+ depends on EC_SYSTEM76_EC
+ help
+ Send coreboot debug output to a System76 embedded controller.
+
config CONSOLE_OVERRIDE_LOGLEVEL
bool
help
diff --git a/src/console/console.c b/src/console/console.c
index bc9d9183a0..2f544a80f2 100644
--- a/src/console/console.c
+++ b/src/console/console.c
@@ -9,6 +9,7 @@
#include <console/usb.h>
#include <console/spi.h>
#include <console/flash.h>
+#include <console/system76_ec.h>
void console_hw_init(void)
{
@@ -21,6 +22,7 @@ void console_hw_init(void)
__usbdebug_init();
__spiconsole_init();
__flashconsole_init();
+ __system76_ec_init();
}
void console_tx_byte(unsigned char byte)
@@ -42,6 +44,7 @@ void console_tx_byte(unsigned char byte)
__usb_tx_byte(byte);
__spiconsole_tx_byte(byte);
__flashconsole_tx_byte(byte);
+ __system76_ec_tx_byte(byte);
}
void console_tx_flush(void)
@@ -50,6 +53,7 @@ void console_tx_flush(void)
__ne2k_tx_flush();
__usb_tx_flush();
__flashconsole_tx_flush();
+ __system76_ec_tx_flush();
}
void console_write_line(uint8_t *buffer, size_t number_of_bytes)
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();
+}
diff --git a/src/include/console/system76_ec.h b/src/include/console/system76_ec.h
new file mode 100644
index 0000000000..616e46f4a2
--- /dev/null
+++ b/src/include/console/system76_ec.h
@@ -0,0 +1,35 @@
+#ifndef CONSOLE_SYSTEM76_EC_H
+#define CONSOLE_SYSTEM76_EC_H 1
+
+#include <stddef.h>
+#include <stdint.h>
+
+void system76_ec_init(void);
+void system76_ec_flush(void);
+void system76_ec_print(uint8_t byte);
+
+#define __CONSOLE_SYSTEM76_EC_ENABLE__ (CONFIG(CONSOLE_SYSTEM76_EC) && \
+ (ENV_BOOTBLOCK || ENV_ROMSTAGE || ENV_RAMSTAGE \
+ || ENV_SEPARATE_VERSTAGE || ENV_POSTCAR \
+ || (ENV_SMM && CONFIG(DEBUG_SMI))))
+
+#if __CONSOLE_SYSTEM76_EC_ENABLE__
+static inline void __system76_ec_init(void)
+{
+ system76_ec_init();
+}
+static inline void __system76_ec_tx_flush(void)
+{
+ system76_ec_flush();
+}
+static inline void __system76_ec_tx_byte(unsigned char byte)
+{
+ system76_ec_print(byte);
+}
+#else
+static inline void __system76_ec_init(void) {}
+static inline void __system76_ec_tx_flush(void) {}
+static inline void __system76_ec_tx_byte(unsigned char byte) {}
+#endif
+
+#endif