[coreboot-gerrit] Patch set updated for coreboot: ecd887b tegra124: add custom uart

Isaac Christensen (isaac.christensen@se-eng.com) gerrit at coreboot.org
Thu Aug 28 01:51:10 CEST 2014


Isaac Christensen (isaac.christensen at se-eng.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/6764

-gerrit

commit ecd887b73c0a96cb3eac0d14a779a805508351a8
Author: Gabe Black <gabeblack at google.com>
Date:   Sun Sep 29 07:06:08 2013 -0700

    tegra124: add custom uart
    
    tegra124: Add a test function which spams exclamation points on the UART.
    
    This function spews characters on the console and, until we have a working
    console, is an easy way to see whether the system boots to a particular point.
    For some reason waiting for transmitter to be empty hangs, but transmitting
    characters still works.
    
    Old-Change-Id: I1622c8a58849f4b8bdcaa67500b81042d7346df4
    Signed-off-by: Gabe Black <gabeblack at google.com>
    Reviewed-on: https://chromium-review.googlesource.com/171030
    Reviewed-by: Ronald Minnich <rminnich at chromium.org>
    Commit-Queue: Gabe Black <gabeblack at chromium.org>
    Tested-by: Gabe Black <gabeblack at chromium.org>
    (cherry picked from commit e0059181958cfe8afec2f3a7ea732e81f5d55e5d)
    
    tegra124: Re-enable waiting for the transmitter to empty in the test function.
    
    The compiler was emitting code compatible with armv7-a, but the bootblock was
    running on a core which uses armv4t. By coincidence, it was emitting an
    instruction which is unavailable on armv4t when checking the value of the
    UART's LSR register. Now that the bootblock is compiled with more appropriate
    flags, this code can be re-introduced.
    
    Old-Change-Id: I7ecada4138b0889b963d1a8b19a4bab8e0bb1add
    Signed-off-by: Gabe Black <gabeblack at google.com>
    Reviewed-on: https://chromium-review.googlesource.com/170997
    Reviewed-by: Gabe Black <gabeblack at chromium.org>
    Tested-by: Gabe Black <gabeblack at chromium.org>
    Commit-Queue: Gabe Black <gabeblack at chromium.org>
    (cherry picked from commit 2a0adceb5029c8ee633d17c82dbb11e48d30349d)
    
    tegra124: Seperate out the non-UART specific hardcoded init in the bootblock.
    
    The hardcoded init in the test function in the bootblock is actually useful
    generally because it doesn't belong in the UART driver itself but is necessary
    for the UART to work. Until we have real implementations for the pinmux, etc.,
    we can use that code to get the UART and console going.
    
    Old-Change-Id: I2efe0b571d8b022eb2a2e5569620558540b28373
    Signed-off-by: Gabe Black <gabeblack at google.com>
    Reviewed-on: https://chromium-review.googlesource.com/171334
    Reviewed-by: Ronald Minnich <rminnich at chromium.org>
    Tested-by: Gabe Black <gabeblack at chromium.org>
    Commit-Queue: Gabe Black <gabeblack at chromium.org>
    (cherry picked from commit ae7d4d890be1936cc86dc15adeb33f3b46a51ae5)
    
    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.
    
    Old-Change-Id: Idd659222901eb76b0ed8cbb986deb5124096f2f6
    Signed-off-by: Gabe Black <gabeblack at google.com>
    Reviewed-on: https://chromium-review.googlesource.com/171337
    Reviewed-by: Gabe Black <gabeblack at chromium.org>
    Commit-Queue: Gabe Black <gabeblack at chromium.org>
    Tested-by: Gabe Black <gabeblack at chromium.org>
    (cherry picked from commit 86f5e2875b18901b349283cfbcd4f8cc88b7a019)
    
    Squashed 4 commits related to uart support for tegra124. Modified the
    new uart.c to look like the uart.c for exynos5420.
    
    Change-Id: I490cba014a43d58c30c48ca9ddcae2b00095b7a6
    Signed-off-by: Isaac Christensen <isaac.christensen at se-eng.com>
---
 src/soc/nvidia/tegra124/Kconfig      |   2 +
 src/soc/nvidia/tegra124/Makefile.inc |   3 +
 src/soc/nvidia/tegra124/bootblock.c  |  52 ++++++++++++-
 src/soc/nvidia/tegra124/uart.c       | 137 +++++++++++++++++++++++++++++++++++
 4 files changed, 192 insertions(+), 2 deletions(-)

diff --git a/src/soc/nvidia/tegra124/Kconfig b/src/soc/nvidia/tegra124/Kconfig
index 7f03ad7..4f33f56 100644
--- a/src/soc/nvidia/tegra124/Kconfig
+++ b/src/soc/nvidia/tegra124/Kconfig
@@ -2,6 +2,8 @@ config SOC_NVIDIA_TEGRA124
 	select ARCH_BOOTBLOCK_ARMV7
 	select ARCH_ROMSTAGE_ARMV7
 	select ARCH_RAMSTAGE_ARMV7
+	select HAVE_UART_SPECIAL
+	select BOOTBLOCK_CONSOLE
 	select ARM_BOOTBLOCK_CUSTOM
 	bool
 	default n
diff --git a/src/soc/nvidia/tegra124/Makefile.inc b/src/soc/nvidia/tegra124/Makefile.inc
index c7d56ab..34d24da 100644
--- a/src/soc/nvidia/tegra124/Makefile.inc
+++ b/src/soc/nvidia/tegra124/Makefile.inc
@@ -14,14 +14,17 @@ bootblock-y += ../tegra/i2c.c
 bootblock-y += ../tegra/pingroup.c
 bootblock-y += ../tegra/pinmux.c
 bootblock-y += timer.c
+bootblock-$(CONFIG_BOOTBLOCK_CONSOLE) += uart.c
 
 romstage-y += cbfs.c
 romstage-y += monotonic_timer.c
 romstage-y += timer.c
+romstage-y += uart.c
 
 ramstage-y += cbfs.c
 ramstage-y += monotonic_timer.c
 ramstage-y += timer.c
+ramstage-y += uart.c
 
 CPPFLAGS_common += -Isrc/soc/nvidia/tegra124/include/
 
diff --git a/src/soc/nvidia/tegra124/bootblock.c b/src/soc/nvidia/tegra124/bootblock.c
index 97180a0..cd7ea34 100644
--- a/src/soc/nvidia/tegra124/bootblock.c
+++ b/src/soc/nvidia/tegra124/bootblock.c
@@ -18,19 +18,67 @@
  */
 
 #include <arch/hlt.h>
-#include <arch/stages.h>
+#include <arch/io.h>
 #include <cbfs.h>
 #include <console/console.h>
 
+static void hacky_hardcoded_uart_setup_function(void)
+{
+	int i;
+
+	/*
+	 * On poweron, AVP clock source (also called system clock) is set to
+	 * PLLP_out0 with frequency set at 1MHz. Before initializing PLLP, we
+	 * need to move the system clock's source to CLK_M temporarily. And
+	 * then switch it to PLLP_out4 (204MHz) at a later time.
+	 */
+	write32((0 << 12) | (0 << 8) | (0 << 4) | (0 << 0) | (2 << 28),
+		(void *)(0x60006000 + 0x28));
+
+	// wait a little bit (nominally 2-3 us)
+	for (i = 0; i < 0x10000; i++)
+		__asm__ __volatile__("");
+
+	// Set function.
+	setbits_le32((void *)(0x70000000 + 0x3000 + 0x2e0), 3 << 0);
+	setbits_le32((void *)(0x70000000 + 0x3000 + 0x2e4), 3 << 0);
+
+	// Output.
+	clrbits_le32((void *)(0x70000000 + 0x3000 + 0x2e0), 1 << 5);
+	// Input.
+	setbits_le32((void *)(0x70000000 + 0x3000 + 0x2e4), 1 << 5);
+
+	// Disable tristate.
+	clrbits_le32((void *)(0x70000000 + 0x3000 + 0x2e0), 1 << 4);
+	clrbits_le32((void *)(0x70000000 + 0x3000 + 0x2e4), 1 << 4);
+
+	// Assert UART reset and enable clock.
+	setbits_le32((void *)(0x60006000 + 4 + 0), 1 << 6);
+
+	// Enable the clock.
+	setbits_le32((void *)(0x60006000 + 4 * 4 + 0), 1 << 6);
+
+	// Set the clock source.
+	clrbits_le32((void *)(0x60006000 + 0x100 + 4 * 0x1e), 3 << 30);
+
+	// wait a little bit (nominally 2us?)
+	for (i = 0; i < 0x10000; i++)
+		__asm__ __volatile__("");
+
+	// De-assert reset to UART.
+	clrbits_le32((void *)(0x60006000 + 4 + 0), 1 << 6);
+}
+
 void main(void)
 {
 	void *entry;
 
+	hacky_hardcoded_uart_setup_function();
+
 	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 0000000..d28cbb7
--- /dev/null
+++ b/src/soc/nvidia/tegra124/uart.c
@@ -0,0 +1,137 @@
+/*
+ * 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 <console/uart.h>
+#include <arch/io.h>
+#include <boot/coreboot_tables.h>
+#include <console/console.h>	/* for __console definition */
+#include <drivers/uart/uart8250reg.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 void tegra124_uart_tx_flush(struct tegra124_uart *uart_ptr);
+static int tegra124_uart_tst_byte(struct tegra124_uart *uart_ptr);
+
+static void tegra124_uart_init(struct tegra124_uart *uart_ptr)
+{
+	// Use a hardcoded divisor for now.
+	const unsigned divisor = 221;
+	const uint8_t line_config = UART8250_LCR_WLS_8; // 8n1
+
+	tegra124_uart_tx_flush(uart_ptr);
+
+	// 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 unsigned char tegra124_uart_rx_byte(struct tegra124_uart *uart_ptr)
+{
+	if (!tegra124_uart_tst_byte(uart_ptr))
+		return 0;
+	return read8(&uart_ptr->rbr);
+}
+
+static void tegra124_uart_tx_byte(struct tegra124_uart *uart_ptr, unsigned char data)
+{
+	while (!(read8(&uart_ptr->lsr) & UART8250_LSR_THRE));
+	write8(data, &uart_ptr->thr);
+}
+
+static void tegra124_uart_tx_flush(struct tegra124_uart *uart_ptr)
+{
+	while (!(read8(&uart_ptr->lsr) & UART8250_LSR_TEMT));
+}
+
+static int tegra124_uart_tst_byte(struct tegra124_uart *uart_ptr)
+{
+	return (read8(&uart_ptr->lsr) & UART8250_LSR_DR) == UART8250_LSR_DR;
+}
+
+unsigned int uart_platform_base(int idx)
+{
+	//TODO:return the correct address based on which UART has been selected
+	return CONFIG_CONSOLE_SERIAL_UART_ADDRESS;
+}
+
+void uart_init(int idx)
+{
+	struct tegra124_uart *uart_ptr = uart_platform_baseptr(idx);
+	tegra124_uart_init(uart_ptr);
+}
+
+unsigned char uart_rx_byte(int idx)
+{
+	struct tegra124_uart *uart_ptr = uart_platform_baseptr(idx);
+	return tegra124_uart_rx_byte(uart_ptr);
+}
+
+void uart_tx_byte(int idx, unsigned char data)
+{
+	struct tegra124_uart *uart_ptr = uart_platform_baseptr(idx);
+	tegra124_uart_tx_byte(uart_ptr, data);
+}
+
+void uart_tx_flush(int idx)
+{
+	struct tegra124_uart *uart_ptr = uart_platform_baseptr(idx);
+	tegra124_uart_tx_flush(uart_ptr);
+}
+
+#ifndef __PRE_RAM__
+void uart_fill_lb(void *data)
+{
+	struct lb_serial serial;
+	serial.type = LB_SERIAL_TYPE_MEMORY_MAPPED;
+	serial.baseaddr = uart_platform_base(CONFIG_UART_FOR_CONSOLE);
+	serial.baud = default_baudrate();
+	lb_add_serial(&serial, data);
+
+	lb_add_console(LB_TAG_CONSOLE_SERIAL8250MEM, data);
+}
+#endif



More information about the coreboot-gerrit mailing list