tegra124: Implement and enable serial console support for tegra124.

The driver is very similar to the 8250 driver, except it isn't in two parts,
and it also spaces its registers 4 bytes apart instead of having them directly
adjacent to each other.

Also, eliminate the UART test function in the bootblock. It's no longer needed
since the actual console output serves the same purpose.

Right now the clock divisor is fixed for now, and we'll want to actually
figure out what value to use at some point.

BUG=None
TEST=Built for link, pit, nyan and lumpy. Booted into the bootblock on nyan
and saw serial output on the console.
BRANCH=None

Change-Id: Idd659222901eb76b0ed8cbb986deb5124096f2f6
Signed-off-by: Gabe Black <gabeblack@google.com>
Reviewed-on: https://chromium-review.googlesource.com/171337
Reviewed-by: Gabe Black <gabeblack@chromium.org>
Commit-Queue: Gabe Black <gabeblack@chromium.org>
Tested-by: Gabe Black <gabeblack@chromium.org>
This commit is contained in:
Gabe Black 2013-09-30 21:28:30 -07:00 committed by chrome-internal-fetch
commit 86f5e2875b
4 changed files with 185 additions and 40 deletions

View file

@ -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

View file

@ -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

View file

@ -19,22 +19,8 @@
#include <arch/hlt.h>
#include <arch/io.h>
#include <arch/stages.h>
#include <cbfs.h>
#include <console/console.h>
#include <stdint.h>
#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();
}

View file

@ -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 <uart.h>
#include <arch/io.h>
#include <console/console.h> /* for __console definition */
#include <stdint.h>
#include <uart8250.h>
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