diff --git a/src/soc/nvidia/tegra124/Kconfig b/src/soc/nvidia/tegra124/Kconfig index 4091e32d45..c2a40e9658 100644 --- a/src/soc/nvidia/tegra124/Kconfig +++ b/src/soc/nvidia/tegra124/Kconfig @@ -2,6 +2,10 @@ config SOC_NVIDIA_TEGRA124 depends on ARCH_ARMV7 bool default n + select HAVE_UART_MEMORY_MAPPED + select HAVE_UART_SPECIAL + select BOOTBLOCK_CONSOLE + select EARLY_CONSOLE select ARM_BOOTBLOCK_CUSTOM if SOC_NVIDIA_TEGRA124 @@ -52,4 +56,47 @@ config STACK_SIZE hex default 0x800 +choice CONSOLE_SERIAL_TEGRA124_UART_CHOICES + prompt "Serial Console UART" + default CONSOLE_SERIAL_UARTA + depends on CONSOLE_SERIAL_UART + +config CONSOLE_SERIAL_UARTA + bool "UARTA" + help + Serial console on UART A. + +config CONSOLE_SERIAL_UARTB + bool "UARTB" + help + Serial console on UART B. + +config CONSOLE_SERIAL_UARTC + bool "UARTC" + help + Serial console on UART C. + +config CONSOLE_SERIAL_UARTD + bool "UARTD" + help + Serial console on UART D. + +config CONSOLE_SERIAL_UARTE + bool "UARTE" + help + Serial console on UART E. + +endchoice + +config CONSOLE_SERIAL_UART_ADDRESS + hex + depends on CONSOLE_SERIAL_UART + default 0x70006000 if CONSOLE_SERIAL_UARTA + default 0x70006040 if CONSOLE_SERIAL_UARTB + default 0x70006200 if CONSOLE_SERIAL_UARTC + default 0x70006300 if CONSOLE_SERIAL_UARTD + default 0x70006400 if CONSOLE_SERIAL_UARTE + help + Map the UART names to the respective MMIO addres. + endif diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc index 16293c9fc3..19aabf6b64 100644 --- a/src/soc/nvidia/tegra124/Makefile.inc +++ b/src/soc/nvidia/tegra124/Makefile.inc @@ -6,14 +6,17 @@ bootblock-S-ccopts += -marm -march=armv4t bootblock-y += bootblock.c bootblock-y += bootblock_asm.S bootblock-y += cbfs.c +bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart.c romstage-y += cbfs.c romstage-y += monotonic_timer.c romstage-y += timer.c +romstage-$(CONFIG_EARLY_CONSOLE) += uart.c ramstage-y += cbfs.c ramstage-y += monotonic_timer.c ramstage-y += timer.c +ramstage-$(CONFIG_CONSOLE_SERIAL_UART) += uart.c # We want to grab the bootblock right before it goes into the image and wrap # it inside a BCT, but ideally we would do that without making special, one diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c index cd3d5d5541..cd7ea34147 100644 --- a/src/soc/nvidia/tegra124/bootblock.c +++ b/src/soc/nvidia/tegra124/bootblock.c @@ -19,22 +19,8 @@ #include #include -#include #include #include -#include - -#define UART_TEST 0 - -static uint8_t readr(int reg) -{ - return read8((void *)(0x70000000 + 0x6000 + 4 * reg)); -} - -static void writer(int reg, uint8_t val) -{ - write8(val, (void *)(0x70000000 + 0x6000 + 4 * reg)); -} static void hacky_hardcoded_uart_setup_function(void) { @@ -83,42 +69,16 @@ static void hacky_hardcoded_uart_setup_function(void) clrbits_le32((void *)(0x60006000 + 4 + 0), 1 << 6); } -static void test_func(void) -{ - const unsigned divisor = 221; - - while (!(readr(5) & 0x40)); - - writer(1, 0); - writer(3, 0x80 | 0x3); - writer(0, 0); - writer(1, 0); - writer(3, 0x3); - writer(2, 0x01 | 0x2 | 0x4); - writer(3, 0x80 | 0x3); - writer(0, divisor & 0xff); - writer(1, (divisor >> 8) & 0xff); - writer(3, 0x3); - - for (;;) { - writer(0, '!'); - } -} - void main(void) { void *entry; hacky_hardcoded_uart_setup_function(); - if (UART_TEST) - test_func(); - if (CONFIG_BOOTBLOCK_CONSOLE) console_init(); entry = cbfs_load_stage(CBFS_DEFAULT_MEDIA, "fallback/romstage"); - if (entry) stage_exit(entry); hlt(); } diff --git a/src/soc/nvidia/tegra124/uart.c b/src/soc/nvidia/tegra124/uart.c new file mode 100644 index 0000000000..b513d36a76 --- /dev/null +++ b/src/soc/nvidia/tegra124/uart.c @@ -0,0 +1,135 @@ +/* + * This file is part of the coreboot project. + * + * Copyright (C) 2009 Samsung Electronics + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include /* for __console definition */ +#include +#include + +struct tegra124_uart { + union { + uint32_t thr; // Transmit holding register. + uint32_t rbr; // Receive buffer register. + uint32_t dll; // Divisor latch lsb. + }; + union { + uint32_t ier; // Interrupt enable register. + uint32_t dlm; // Divisor latch msb. + }; + union { + uint32_t iir; // Interrupt identification register. + uint32_t fcr; // FIFO control register. + }; + uint32_t lcr; // Line control register. + uint32_t mcr; // Modem control register. + uint32_t lsr; // Line status register. + uint32_t msr; // Modem status register. +} __attribute__ ((packed)); + +static struct tegra124_uart * const uart_ptr = + (void *)CONFIG_CONSOLE_SERIAL_UART_ADDRESS; + +static void tegra124_uart_tx_flush(void); +static int tegra124_uart_tst_byte(void); + +static void tegra124_uart_init(void) +{ + // Use a hardcoded divisor for now. + const unsigned divisor = 221; + const uint8_t line_config = UART8250_LCR_WLS_8; // 8n1 + + tegra124_uart_tx_flush(); + + // Disable interrupts. + write8(0, &uart_ptr->ier); + // Set line configuration, access divisor latches. + write8(UART8250_LCR_DLAB | line_config, &uart_ptr->lcr); + // Set the divisor. + write8(divisor & 0xff, &uart_ptr->dll); + write8((divisor >> 8) & 0xff, &uart_ptr->dlm); + // Hide the divisor latches. + write8(line_config, &uart_ptr->lcr); + // Enable FIFOs, and clear receive and transmit. + write8(UART8250_FCR_FIFO_EN | + UART8250_FCR_CLEAR_RCVR | + UART8250_FCR_CLEAR_XMIT, &uart_ptr->fcr); +} + +static void tegra124_uart_tx_byte(unsigned char data) +{ + while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE)); + write8(data, &uart_ptr->thr); +} + +static void tegra124_uart_tx_flush(void) +{ + while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT)); +} + +static unsigned char tegra124_uart_rx_byte(void) +{ + if (!tegra124_uart_tst_byte()) + return 0; + return read8(&uart_ptr->rbr); +} + +static int tegra124_uart_tst_byte(void) +{ + return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR; +} + +#if !defined(__PRE_RAM__) + +static const struct console_driver tegra124_uart_console __console = { + .init = tegra124_uart_init, + .tx_byte = tegra124_uart_tx_byte, + .tx_flush = tegra124_uart_tx_flush, + .rx_byte = tegra124_uart_rx_byte, + .tst_byte = tegra124_uart_tst_byte, +}; + +uint32_t uartmem_getbaseaddr(void) +{ + return (uintptr_t)uart_ptr; +} + +#else + +void uart_init(void) +{ + tegra124_uart_init(); +} + +void uart_tx_byte(unsigned char data) +{ + tegra124_uart_tx_byte(data); +} + +void uart_tx_flush(void) +{ + tegra124_uart_tx_flush(); +} + +unsigned char uart_rx_byte(void) +{ + return tegra124_uart_rx_byte(); +} + +#endif