Nicholas Chin has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/84344?usp=email )
Change subject: soc/xilinx/zynq7000: Add UART driver ......................................................................
soc/xilinx/zynq7000: Add UART driver
Add a driver for the 2 UART controllers on the Zynq 7000. Assumes MIO pin mappings are already set up in mainboard specific code. Currently the clock control registers are not modified from their default values so the reference clock is hard coded to an unusual value.
Change-Id: I2b845af3f057847d7c5c56615396f946df39b921 Signed-off-by: Nicholas Chin nic.c3.14@gmail.com --- M src/soc/xilinx/zynq7000/Kconfig M src/soc/xilinx/zynq7000/Makefile.mk A src/soc/xilinx/zynq7000/uart.c A src/soc/xilinx/zynq7000/uart.h 4 files changed, 145 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/44/84344/1
diff --git a/src/soc/xilinx/zynq7000/Kconfig b/src/soc/xilinx/zynq7000/Kconfig index 3254435..b82acea 100644 --- a/src/soc/xilinx/zynq7000/Kconfig +++ b/src/soc/xilinx/zynq7000/Kconfig @@ -7,6 +7,8 @@ select ARCH_VERSTAGE_ARMV7 select ARCH_ROMSTAGE_ARMV7 select ARCH_RAMSTAGE_ARMV7 + select HAVE_UART_SPECIAL + select UART_OVERRIDE_REFCLK
if SOC_XILINX_ZYNQ7000
diff --git a/src/soc/xilinx/zynq7000/Makefile.mk b/src/soc/xilinx/zynq7000/Makefile.mk index b6b4e1c..2287332 100644 --- a/src/soc/xilinx/zynq7000/Makefile.mk +++ b/src/soc/xilinx/zynq7000/Makefile.mk @@ -5,6 +5,10 @@ romstage-y += timer.c ramstage-y += timer.c
+bootblock-y += uart.c +romstage-y += uart.c +ramstage-y += uart.c + romstage-y += cbmem.c ramstage-y += soc.c
diff --git a/src/soc/xilinx/zynq7000/uart.c b/src/soc/xilinx/zynq7000/uart.c new file mode 100644 index 0000000..6737528 --- /dev/null +++ b/src/soc/xilinx/zynq7000/uart.c @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include <boot/coreboot_tables.h> +#include <console/uart.h> +#include <device/mmio.h> +#include <soc/xilinx/zynq7000/uart.h> +#include <types.h> + +static void zynq_uart_init(struct zynq7000_uart *uart, uint16_t div) +{ + /* 8n1, normal mode, uart_ref_clk source 8 */ + write32(&uart->mode, 0x20); + + /* Disable uart */ + write32(&uart->control, ((read32(&uart->control) & ~(0xf << 2)) | (0xa << 2))); + + /* Write CD baudgen divider */ + write16(&uart->baudgen, div); + + /* Write BDIV 8 */ + write8(&uart->baud_div, uart_input_clock_divider() - 1); + + /* Reset uart */ + write32(&uart->control, read32(&uart->control) | 0x3); + + /* Enable uart */ + write32(&uart->control, ((read32(&uart->control) & ~(0xf << 2)) | (0xa << 2))); + + /* 3. Disable Rx trigger level */ + write32(&uart->rxwm, 0); + /* 4. Enable the Controller */ + write32(&uart->control, 0x117); + /* 5. Disable rx timeout mechanism */ + write32(&uart->rxtout, 0); + + /* Disable interrupts */ + write32(&uart->idr, 0x1fff); +} + +static void zynq_uart_tx_byte(struct zynq7000_uart *uart, unsigned char data) +{ + /* Wait for fifo not full */ + while (read32(&uart->sr) & (1 << 4)) + ; + + write8(&uart->fifo, data); +} + +static unsigned char zynq_uart_rx_byte(struct zynq7000_uart *uart) +{ + /* Wait for fifo not empty */ + while (read32(&uart->sr) & (1 << 1)) + ; + + return read8(&uart->fifo); +} + +uintptr_t uart_platform_base(unsigned int idx) +{ + const unsigned int bases[] = {0xe0000000, 0xe0001000}; + + if (idx < ARRAY_SIZE(bases)) + return bases[idx]; + return 0; +} + +unsigned int uart_platform_refclk(void) +{ + /* This is the default UART refclk, based on the default reset + * values of all related clock configuration registers. + * TODO: Properly set the system clocks to more reasonable values */ + return 13756614; +} + + +void uart_tx_byte(unsigned int idx, unsigned char data) +{ + struct zynq7000_uart *uart = uart_platform_baseptr(idx); + zynq_uart_tx_byte(uart, data); +} + +void uart_tx_flush(unsigned int idx) +{ +} + +unsigned char uart_rx_byte(unsigned int idx) +{ + struct zynq7000_uart *uart = uart_platform_baseptr(idx); + return zynq_uart_rx_byte(uart); +} + +void uart_init(unsigned int idx) +{ + struct zynq7000_uart *uart = uart_platform_baseptr(idx); + uint16_t div = (uint16_t)uart_baudrate_divisor( + get_uart_baudrate(), uart_platform_refclk(), uart_input_clock_divider()); + zynq_uart_init(uart, div); +} + +enum cb_err fill_lb_serial(struct lb_serial *serial) +{ + serial->type = LB_SERIAL_TYPE_MEMORY_MAPPED; + serial->baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE); + serial->baud = get_uart_baudrate(); + serial->regwidth = 2; + serial->input_hertz = uart_platform_refclk(); + + return CB_SUCCESS; +} diff --git a/src/soc/xilinx/zynq7000/uart.h b/src/soc/xilinx/zynq7000/uart.h new file mode 100644 index 0000000..bb647f3 --- /dev/null +++ b/src/soc/xilinx/zynq7000/uart.h @@ -0,0 +1,30 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#ifndef ZYNQ7000_UART_H +#define ZYNQ7000_UART_H + +#include <stdint.h> + +#define ZYNQ7000_UART0_BASE 0xe0000000 +#define ZYNQ7000_UART1_BASE 0xe0001000 + +struct zynq7000_uart { + uint32_t control; + uint32_t mode; + uint32_t ier; + uint32_t idr; + uint32_t imr; + uint32_t isr; + uint32_t baudgen; + uint32_t rxtout; + uint32_t rxwm; + uint32_t modemcr; + uint32_t modemsr; + uint32_t sr; + uint32_t fifo; + uint32_t baud_div; + uint32_t flow_delay; + uint32_t tx_fifo_trig; +} __packed; + +#endif /* ZYNQ7000_UART_H */