mturney mturney has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/35960 )
Change subject: trogdor: libpayload uart/serial driver support ......................................................................
trogdor: libpayload uart/serial driver support
Change-Id: I5be3904298cd88c60dbc6d8d662beeede2abe442 Signed-off-by: T Michael Turney mturney@codeaurora.org --- M payloads/libpayload/Kconfig A payloads/libpayload/configs/config.trogdor M payloads/libpayload/drivers/Makefile.inc A payloads/libpayload/drivers/serial/sc7180.c 4 files changed, 292 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/60/35960/1
diff --git a/payloads/libpayload/Kconfig b/payloads/libpayload/Kconfig index 97b970b..aa044bd 100644 --- a/payloads/libpayload/Kconfig +++ b/payloads/libpayload/Kconfig @@ -263,6 +263,16 @@ depends on SERIAL_CONSOLE default n
+config SC7180_SERIAL_CONSOLE + bool "SC7180 SOC compatible serial port driver" + depends on SERIAL_CONSOLE + default n + +config CONSOLE_UART_ADDR + hex "Default I/O base for the serial port" + depends on SC7180_SERIAL_CONSOLE + default 0x00A88000 + config PL011_SERIAL_CONSOLE bool "PL011 compatible serial port driver" depends on 8250_SERIAL_CONSOLE diff --git a/payloads/libpayload/configs/config.trogdor b/payloads/libpayload/configs/config.trogdor new file mode 100644 index 0000000..0625ff5 --- /dev/null +++ b/payloads/libpayload/configs/config.trogdor @@ -0,0 +1,5 @@ +CONFIG_LP_CHROMEOS=y +CONFIG_LP_ARCH_ARM64=y +CONFIG_LP_TIMER_ARM64_ARCH=y +CONFIG_LP_SERIAL_CONSOLE=y +CONFIG_LP_SC7180_SERIAL_CONSOLE=y diff --git a/payloads/libpayload/drivers/Makefile.inc b/payloads/libpayload/drivers/Makefile.inc index b4e7594..701434d 100644 --- a/payloads/libpayload/drivers/Makefile.inc +++ b/payloads/libpayload/drivers/Makefile.inc @@ -38,6 +38,7 @@ libc-$(CONFIG_LP_IPQ806X_SERIAL_CONSOLE) += serial/ipq806x.c serial/serial.c libc-$(CONFIG_LP_IPQ40XX_SERIAL_CONSOLE) += serial/ipq40xx.c serial/serial.c libc-$(CONFIG_LP_QCS405_SERIAL_CONSOLE) += serial/qcs405.c serial/serial.c +libc-$(CONFIG_LP_SC7180_SERIAL_CONSOLE) += serial/sc7180.c serial/serial.c libc-$(CONFIG_LP_PC_KEYBOARD) += i8042/keyboard.c libc-$(CONFIG_LP_PC_MOUSE) += i8042/mouse.c libc-$(CONFIG_LP_PC_I8042) += i8042/i8042.c diff --git a/payloads/libpayload/drivers/serial/sc7180.c b/payloads/libpayload/drivers/serial/sc7180.c new file mode 100644 index 0000000..d104cd6 --- /dev/null +++ b/payloads/libpayload/drivers/serial/sc7180.c @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2010-2012, 2014, 2016, 2019, The Linux Foundation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <libpayload.h> + +/* For simplicity sake let's rely on coreboot initalizing the UART. */ +#include <sys/types.h> +#include <config.h> + +#define true 1 +#define false 0 +typedef uint8_t bool; + +#define REG_IN(base, offset) (*(volatile unsigned int *)(base + offset)) + +#define REG_OUT(base, offset, value) \ + (*(volatile unsigned int *)(base + offset) = value) + +/* BASE ADDRESS OF DIFFERENT REGISTER SPACES IN HW */ + +#define GENI4_CFG 0x0 +#define GENI4_IMAGE_REGS 0x100 +#define GENI4_DATA 0x600 +#define QUPV3_SE_DMA 0xC00 +#define GENI4_IMAGE 0x1000 +#define QUPV3_SEC 0x2000 + +/* COMMON STATUS/CONFIGURATION REGISTERS AND MASKS */ + +#define SE_HW_PARAM_0_REG (QUPV3_SE_DMA + 0x00000224) +#define SE_HW_PARAM_0_TX_FIFO_DEPTH_MASK 0x3f0000 +#define SE_HW_PARAM_0_TX_FIFO_DEPTH_SHIFT 0x10 + +#define SE_HW_PARAM_1_REG (QUPV3_SE_DMA + 0x00000228) +#define SE_HW_PARAM_1_RX_FIFO_DEPTH_MASK 0x3f0000 +#define SE_HW_PARAM_1_RX_FIFO_DEPTH_SHIFT 0x10 + +#define GENI_FW_REVISION_RO_REG (GENI4_CFG + 0x00000068) +#define GENI_FW_REVISION_RO_PROTOCOL_MASK 0x0000FF00 +#define GENI_FW_REVISION_RO_PROTOCOL_SHIFT 0x00000008 + +#define GENI_SER_M_CLK_CFG_REG (GENI4_CFG + 0x00000048) +#define GENI_SER_S_CLK_CFG_REG (GENI4_CFG + 0x0000004c) + +#define GENI_STATUS_REG (GENI4_CFG + 0x00000040) +#define GENI_STATUS_M_GENI_CMD_ACTIVE_MASK 0x1 +#define GENI_STATUS_S_GENI_CMD_ACTIVE_MASK 0x1000 + +#define GENI_TX_WATERMARK_REG (GENI4_DATA + 0x0000020c) +#define GENI_RX_WATERMARK_REG (GENI4_DATA + 0x00000210) +#define GENI_RX_RFR_WATERMARK_REG (GENI4_DATA + 0x00000214) + +#define UART_TX_WORD_LEN_REG (GENI4_IMAGE_REGS + 0x00000168) +#define UART_RX_WORD_LEN_REG (GENI4_IMAGE_REGS + 0x0000018c) + +#define UART_TX_PARITY_CFG_REG (GENI4_IMAGE_REGS + 0x000001a4) +#define UART_TX_TRANS_CFG_REG (GENI4_IMAGE_REGS + 0x0000015c) +#define UART_RX_PARITY_CFG_REG (GENI4_IMAGE_REGS + 0x000001a8) +#define UART_RX_TRANS_CFG_REG (GENI4_IMAGE_REGS + 0x00000180) + +#define UART_TX_STOP_BIT_LEN_REG (GENI4_IMAGE_REGS + 0x0000016c) + +#define UART_RX_STALE_CNT_REG (GENI4_IMAGE_REGS + 0x00000194) + +#define GENI_TX_PACKING_CFG0_REG (GENI4_IMAGE_REGS + 0x00000160) +#define GENI_TX_PACKING_CFG1_REG (GENI4_IMAGE_REGS + 0x00000164) +#define GENI_RX_PACKING_CFG0_REG (GENI4_IMAGE_REGS + 0x00000184) +#define GENI_RX_PACKING_CFG1_REG (GENI4_IMAGE_REGS + 0x00000188) + +#define UART_TX_TRANS_LEN_REG (GENI4_IMAGE_REGS + 0x00000170) + +/* FIFO, STATUS REGISTERS AND MASKS */ + +#define GENI_TX_FIFOn_REG (GENI4_DATA + 0x00000100) +#define GENI_RX_FIFOn_REG (GENI4_DATA + 0x00000180) + +#define GENI_TX_FIFO_STATUS_REG (GENI4_DATA + 0x00000200) +#define GENI_TX_FIFO_STATUS_TX_FIFO_WC_MASK 0xfffffff + +#define GENI_RX_FIFO_STATUS_REG (GENI4_DATA + 0x00000204) +#define GENI_RX_FIFO_STATUS_RX_LAST_VALID_BYTES_MASK 0x70000000 +#define GENI_RX_FIFO_STATUS_RX_LAST_VALID_BYTES_SHIFT 0x1c +#define GENI_RX_FIFO_STATUS_RX_FIFO_WC_MASK 0x1ffffff +#define GENI_RX_FIFO_STATUS_RX_FIFO_WC_SHIFT 0x0 + +/* MASTER/TX ENGINE REGISTERS */ + +#define GENI_M_CMD0_REG (GENI4_DATA + 0x00000000) + +/* SECONDARY/RX ENGINE REGISTERS */ + +#define GENI_S_CMD0_REG (GENI4_DATA + 0x00000030) + +#define TX_WATERMARK_MARGIN 4 /* Represented in words */ +#define RX_WATERMARK_MARGIN 8 /* Represented in words */ +#define RX_RFR_WATERMARK_MARGIN 4 /* Represented in words */ + +#define PROTOCOL_UART 0x2 + +static struct console_input_driver consin = { + .next = 0, + .input_type = 0, +}; + +static struct console_output_driver consout = { + .next = 0, +}; + +static bool uart_initialized = false; + +static bool uart_qupv3_init(void); +static unsigned char uart_qupv3_rx_byte(void); +static void uart_qupv3_tx_byte(unsigned char data); + +uintptr_t uart_platform_base(int idx); + +static bool uart_qupv3_init(void) +{ + uintptr_t base = uart_platform_base(0); + unsigned int reg_value; + + reg_value = REG_IN(base, GENI_FW_REVISION_RO_REG); + reg_value &= GENI_FW_REVISION_RO_PROTOCOL_MASK; + reg_value >>= GENI_FW_REVISION_RO_PROTOCOL_SHIFT; + + if (reg_value != PROTOCOL_UART) + return false; + + /* + * If the RX (secondary) sequencer is already active, it means the core + * has been already initialized in the previous stage. Skip + * configuration + */ + if (REG_IN(base, GENI_STATUS_REG) & + GENI_STATUS_S_GENI_CMD_ACTIVE_MASK) { + uart_initialized = true; + return true; + } + + REG_OUT(base, GENI_TX_WATERMARK_REG, TX_WATERMARK_MARGIN); + + /* To get RX FIFO size */ + reg_value = REG_IN(base, SE_HW_PARAM_1_REG); + reg_value &= SE_HW_PARAM_1_RX_FIFO_DEPTH_MASK; + reg_value >>= SE_HW_PARAM_1_RX_FIFO_DEPTH_SHIFT; + + REG_OUT(base, GENI_RX_WATERMARK_REG, reg_value - RX_WATERMARK_MARGIN); + + REG_OUT(base, GENI_RX_RFR_WATERMARK_REG, + reg_value - RX_RFR_WATERMARK_MARGIN); + + REG_OUT(base, UART_TX_WORD_LEN_REG, 0x8); + REG_OUT(base, UART_RX_WORD_LEN_REG, 0x8); + + REG_OUT(base, UART_TX_PARITY_CFG_REG, 0x0); + REG_OUT(base, UART_TX_TRANS_CFG_REG, 0x2); + REG_OUT(base, UART_RX_PARITY_CFG_REG, 0x0); + REG_OUT(base, UART_RX_TRANS_CFG_REG, 0x0); + + REG_OUT(base, UART_TX_STOP_BIT_LEN_REG, 0x0); + + REG_OUT(base, UART_RX_STALE_CNT_REG, 0x16 * 10); + + REG_OUT(base, GENI_TX_PACKING_CFG0_REG, 0x4380E); + REG_OUT(base, GENI_TX_PACKING_CFG1_REG, 0xC3E0E); + REG_OUT(base, GENI_RX_PACKING_CFG0_REG, 0xF); + REG_OUT(base, GENI_RX_PACKING_CFG1_REG, 0x0); + + REG_OUT(base, GENI_S_CMD0_REG, 0x8000000); + + uart_initialized = true; + return true; +} + +unsigned char uart_qupv3_rx_byte(void) +{ + uintptr_t base = uart_platform_base(0); + unsigned char data; + + if (uart_initialized) { + if (REG_IN(base, GENI_RX_FIFO_STATUS_REG) & + GENI_RX_FIFO_STATUS_RX_FIFO_WC_MASK) { + data = (unsigned char)REG_IN(base, GENI_RX_FIFOn_REG) & + 0xFF; + return data; + } + } + return 0x0; +} + +void uart_qupv3_tx_byte(unsigned char data) +{ + uintptr_t base = uart_platform_base(0); + + if (uart_initialized == false) { + if (!uart_qupv3_init()) + return; + } + + while (REG_IN(base, GENI_STATUS_REG) & + GENI_STATUS_M_GENI_CMD_ACTIVE_MASK) + ; + + REG_OUT(base, UART_TX_TRANS_LEN_REG, 1); + REG_OUT(base, GENI_M_CMD0_REG, 0x08000000); + REG_OUT(base, GENI_TX_FIFOn_REG, (unsigned int)data); +} + +uintptr_t uart_platform_base(int idx) +{ + return CONFIG_LP_CONSOLE_UART_ADDR; +} + +void serial_putchar(unsigned int data) +{ + if (data == 0xa) + uart_qupv3_tx_byte(0xd); + uart_qupv3_tx_byte(data); +} + +int serial_havechar(void) +{ + uintptr_t base = uart_platform_base(0); + + if (uart_initialized) { + if (REG_IN(base, GENI_RX_FIFO_STATUS_REG) & + GENI_RX_FIFO_STATUS_RX_FIFO_WC_MASK) { + return 1; + } + } + return 0; +} + +int serial_getchar(void) +{ + return uart_qupv3_rx_byte(); +} + +void serial_console_init(void) +{ + uart_qupv3_init(); + + consout.putchar = &serial_putchar; + console_add_output_driver(&consout); + + consin.havekey = &serial_havechar; + consin.getchar = &serial_getchar; + console_add_input_driver(&consin); +}