Patchwork [U-Boot,02/18] Blackfin: uart: add multiple serial support

login
register
mail settings
Submitter Mike Frysinger
Date June 28, 2011, 7:36 p.m.
Message ID <1309289787-7846-3-git-send-email-vapier@gentoo.org>
Download mbox | patch
Permalink /patch/102462/
State Accepted
Commit 635f330fc7883a4cc703bc5ea2b90fc7d7f69e10
Delegated to: Mike Frysinger
Headers show

Comments

Mike Frysinger - June 28, 2011, 7:36 p.m.
This brings CONFIG_SERIAL_MULTI support to the Blackfin on-chip UARTs.
Ends up adding only ~512bytes per additional UART.

Signed-off-by: Mike Frysinger <vapier@gentoo.org>
---
 arch/blackfin/cpu/initcode.c |   12 ++-
 arch/blackfin/cpu/serial.c   |  205 +++++++++++++++++++++++++++++++++---------
 arch/blackfin/cpu/serial.h   |   44 +++++++---
 arch/blackfin/lib/board.c    |    4 +
 common/serial.c              |    3 +
 include/serial.h             |    9 ++
 6 files changed, 222 insertions(+), 55 deletions(-)

Patch

diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c
index 750add0..61dc5ab 100644
--- a/arch/blackfin/cpu/initcode.c
+++ b/arch/blackfin/cpu/initcode.c
@@ -24,6 +24,8 @@ 
 __attribute__((always_inline))
 static inline void serial_init(void)
 {
+	uint32_t uart_base = UART_DLL;
+
 #ifdef __ADSPBF54x__
 # ifdef BFIN_BOOT_UART_USE_RTS
 #  define BFIN_UART_USE_RTS 1
@@ -65,13 +67,13 @@  static inline void serial_init(void)
 
 	if (BFIN_DEBUG_EARLY_SERIAL) {
 		int ucen = bfin_read16(&pUART->gctl) & UCEN;
-		serial_early_init();
+		serial_early_init(uart_base);
 
 		/* If the UART is off, that means we need to program
 		 * the baud rate ourselves initially.
 		 */
 		if (ucen != UCEN)
-			serial_early_set_baud(CONFIG_BAUDRATE);
+			serial_early_set_baud(uart_base, CONFIG_BAUDRATE);
 	}
 }
 
@@ -79,6 +81,8 @@  __attribute__((always_inline))
 static inline void serial_deinit(void)
 {
 #ifdef __ADSPBF54x__
+	uint32_t uart_base = UART_DLL;
+
 	if (BFIN_UART_USE_RTS && CONFIG_BFIN_BOOT_MODE == BFIN_BOOT_UART) {
 		/* clear forced RTS rather than relying on auto RTS */
 		bfin_write16(&pUART->mcr, bfin_read16(&pUART->mcr) & ~FCPOL);
@@ -89,6 +93,8 @@  static inline void serial_deinit(void)
 __attribute__((always_inline))
 static inline void serial_putc(char c)
 {
+	uint32_t uart_base = UART_DLL;
+
 	if (!BFIN_DEBUG_EARLY_SERIAL)
 		return;
 
@@ -519,7 +525,7 @@  update_serial_clocks(ADI_BOOT_DATA *bs, uint sdivB, uint divB, uint vcoB)
 		unsigned int quotient;
 		for (quotient = 0; dividend > 0; ++quotient)
 			dividend -= divisor;
-		serial_early_put_div(quotient - ANOMALY_05000230);
+		serial_early_put_div(UART_DLL, quotient - ANOMALY_05000230);
 		serial_putc('c');
 	}
 
diff --git a/arch/blackfin/cpu/serial.c b/arch/blackfin/cpu/serial.c
index b15c945..0252220 100644
--- a/arch/blackfin/cpu/serial.c
+++ b/arch/blackfin/cpu/serial.c
@@ -39,6 +39,8 @@ 
 
 #include <common.h>
 #include <watchdog.h>
+#include <serial.h>
+#include <linux/compiler.h>
 #include <asm/blackfin.h>
 #include <asm/mach-common/bits/uart.h>
 
@@ -59,14 +61,14 @@  static size_t cache_count;
  * tally of all the status bits.
  */
 static uint16_t uart_lsr_save;
-static uint16_t uart_lsr_read(void)
+static uint16_t uart_lsr_read(uint32_t uart_base)
 {
 	uint16_t lsr = bfin_read16(&pUART->lsr);
 	uart_lsr_save |= (lsr & (OE|PE|FE|BI));
 	return lsr | uart_lsr_save;
 }
 /* Just do the clear for everyone since it can't hurt. */
-static void uart_lsr_clear(void)
+static void uart_lsr_clear(uint32_t uart_base)
 {
 	uart_lsr_save = 0;
 	bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1);
@@ -76,46 +78,17 @@  static void uart_lsr_clear(void)
  * bits get set/cleared, we don't really care since we don't read them
  * anyways (and thus anomaly 05000099 is irrelevant).
  */
-static uint16_t uart_lsr_read(void)
+static inline uint16_t uart_lsr_read(uint32_t uart_base)
 {
 	return bfin_read16(&pUART->lsr);
 }
-static void uart_lsr_clear(void)
+static void uart_lsr_clear(uint32_t uart_base)
 {
 	bfin_write16(&pUART->lsr, bfin_read16(&pUART->lsr) | -1);
 }
 #endif
 
-/* Symbol for our assembly to call. */
-void serial_set_baud(uint32_t baud)
-{
-	serial_early_set_baud(baud);
-}
-
-/* Symbol for common u-boot code to call.
- * Setup the baudrate (brg: baudrate generator).
- */
-void serial_setbrg(void)
-{
-	serial_set_baud(gd->baudrate);
-}
-
-/* Symbol for our assembly to call. */
-void serial_initialize(void)
-{
-	serial_early_init();
-}
-
-/* Symbol for common u-boot code to call. */
-int serial_init(void)
-{
-	serial_initialize();
-	serial_setbrg();
-	uart_lsr_clear();
-	return 0;
-}
-
-void serial_putc(const char c)
+static void uart_putc(uint32_t uart_base, const char c)
 {
 	/* send a \r for compatibility */
 	if (c == '\n')
@@ -124,7 +97,7 @@  void serial_putc(const char c)
 	WATCHDOG_RESET();
 
 	/* wait for the hardware fifo to clear up */
-	while (!(uart_lsr_read() & THRE))
+	while (!(uart_lsr_read(uart_base) & THRE))
 		continue;
 
 	/* queue the character for transmission */
@@ -134,18 +107,18 @@  void serial_putc(const char c)
 	WATCHDOG_RESET();
 }
 
-int serial_tstc(void)
+static int uart_tstc(uint32_t uart_base)
 {
 	WATCHDOG_RESET();
-	return (uart_lsr_read() & DR) ? 1 : 0;
+	return (uart_lsr_read(uart_base) & DR) ? 1 : 0;
 }
 
-int serial_getc(void)
+static int uart_getc(uint32_t uart_base)
 {
 	uint16_t uart_rbr_val;
 
 	/* wait for data ! */
-	while (!serial_tstc())
+	while (!uart_tstc(uart_base))
 		continue;
 
 	/* grab the new byte */
@@ -153,7 +126,7 @@  int serial_getc(void)
 
 #ifdef CONFIG_DEBUG_SERIAL
 	/* grab & clear the LSR */
-	uint16_t uart_lsr_val = uart_lsr_read();
+	uint16_t uart_lsr_val = uart_lsr_read(uart_base);
 
 	cached_lsr[cache_count] = uart_lsr_val;
 	cached_rbr[cache_count] = uart_rbr_val;
@@ -175,11 +148,159 @@  int serial_getc(void)
 		return -1;
 	}
 #endif
-	uart_lsr_clear();
+	uart_lsr_clear(uart_base);
 
 	return uart_rbr_val;
 }
 
+#ifdef CONFIG_SYS_BFIN_UART
+
+static void uart_puts(uint32_t uart_base, const char *s)
+{
+	while (*s)
+		uart_putc(uart_base, *s++);
+}
+
+#define DECL_BFIN_UART(n) \
+static int uart##n##_init(void) \
+{ \
+	const unsigned short pins[] = { _P_UART(n, RX), _P_UART(n, TX), 0, }; \
+	peripheral_request_list(pins, "bfin-uart"); \
+	uart_init(MMR_UART(n)); \
+	serial_early_set_baud(MMR_UART(n), gd->baudrate); \
+	uart_lsr_clear(MMR_UART(n)); \
+	return 0; \
+} \
+\
+static int uart##n##_uninit(void) \
+{ \
+	return serial_early_uninit(MMR_UART(n)); \
+} \
+\
+static void uart##n##_setbrg(void) \
+{ \
+	serial_early_set_baud(MMR_UART(n), gd->baudrate); \
+} \
+\
+static int uart##n##_getc(void) \
+{ \
+	return uart_getc(MMR_UART(n)); \
+} \
+\
+static int uart##n##_tstc(void) \
+{ \
+	return uart_tstc(MMR_UART(n)); \
+} \
+\
+static void uart##n##_putc(const char c) \
+{ \
+	uart_putc(MMR_UART(n), c); \
+} \
+\
+static void uart##n##_puts(const char *s) \
+{ \
+	uart_puts(MMR_UART(n), s); \
+} \
+\
+struct serial_device bfin_serial##n##_device = { \
+	.name   = "bfin_uart"#n, \
+	.init   = uart##n##_init, \
+	.uninit = uart##n##_uninit, \
+	.setbrg = uart##n##_setbrg, \
+	.getc   = uart##n##_getc, \
+	.tstc   = uart##n##_tstc, \
+	.putc   = uart##n##_putc, \
+	.puts   = uart##n##_puts, \
+};
+
+#ifdef UART0_DLL
+DECL_BFIN_UART(0)
+#endif
+#ifdef UART1_DLL
+DECL_BFIN_UART(1)
+#endif
+#ifdef UART2_DLL
+DECL_BFIN_UART(2)
+#endif
+#ifdef UART3_DLL
+DECL_BFIN_UART(3)
+#endif
+
+__weak struct serial_device *default_serial_console(void)
+{
+#if CONFIG_UART_CONSOLE == 0
+	return &bfin_serial0_device;
+#elif CONFIG_UART_CONSOLE == 1
+	return &bfin_serial1_device;
+#elif CONFIG_UART_CONSOLE == 2
+	return &bfin_serial2_device;
+#elif CONFIG_UART_CONSOLE == 3
+	return &bfin_serial3_device;
+#endif
+}
+
+void serial_register_bfin_uart(void)
+{
+#ifdef UART0_DLL
+	serial_register(&bfin_serial0_device);
+#endif
+#ifdef UART1_DLL
+	serial_register(&bfin_serial1_device);
+#endif
+#ifdef UART2_DLL
+	serial_register(&bfin_serial2_device);
+#endif
+#ifdef UART3_DLL
+	serial_register(&bfin_serial3_device);
+#endif
+}
+
+#else
+
+/* Symbol for our assembly to call. */
+void serial_set_baud(uint32_t baud)
+{
+	serial_early_set_baud(UART_DLL, baud);
+}
+
+/* Symbol for common u-boot code to call.
+ * Setup the baudrate (brg: baudrate generator).
+ */
+void serial_setbrg(void)
+{
+	serial_set_baud(gd->baudrate);
+}
+
+/* Symbol for our assembly to call. */
+void serial_initialize(void)
+{
+	serial_early_init(UART_DLL);
+}
+
+/* Symbol for common u-boot code to call. */
+int serial_init(void)
+{
+	serial_initialize();
+	serial_setbrg();
+	uart_lsr_clear(UART_DLL);
+	return 0;
+}
+
+int serial_tstc(void)
+{
+	return uart_tstc(UART_DLL);
+}
+
+int serial_getc(void)
+{
+	return uart_getc(UART_DLL);
+}
+
+void serial_putc(const char c)
+{
+	uart_putc(UART_DLL, c);
+}
+
 void serial_puts(const char *s)
 {
 	while (*s)
@@ -187,3 +308,5 @@  void serial_puts(const char *s)
 }
 
 #endif
+
+#endif
diff --git a/arch/blackfin/cpu/serial.h b/arch/blackfin/cpu/serial.h
index 7999a19..aa5c217 100644
--- a/arch/blackfin/cpu/serial.h
+++ b/arch/blackfin/cpu/serial.h
@@ -82,17 +82,19 @@  struct bfin_mmr_serial {
 
 #define __PASTE_UART(num, pfx, sfx) pfx##num##_##sfx
 #define _PASTE_UART(num, pfx, sfx) __PASTE_UART(num, pfx, sfx)
-#define MMR_UART(mmr) _PASTE_UART(CONFIG_UART_CONSOLE, UART, DLL)
-#define P_UART(pin) _PASTE_UART(CONFIG_UART_CONSOLE, P_UART, pin)
+#define MMR_UART(n) _PASTE_UART(n, UART, DLL)
+#define _P_UART(n, pin) _PASTE_UART(n, P_UART, pin)
+#define P_UART(pin) _P_UART(CONFIG_UART_CONSOLE, pin)
 
 #ifndef UART_DLL
-# define UART_DLL MMR_UART(DLL)
+# define UART_DLL MMR_UART(CONFIG_UART_CONSOLE)
 #else
+# define UART0_DLL UART_DLL
 # if CONFIG_UART_CONSOLE != 0
 #  error CONFIG_UART_CONSOLE must be 0 on parts with only one UART
 # endif
 #endif
-#define pUART ((volatile struct bfin_mmr_serial *)UART_DLL)
+#define pUART ((volatile struct bfin_mmr_serial *)uart_base)
 
 #if BFIN_UART_HW_VER == 2
 # define ACCESS_LATCH()
@@ -168,11 +170,8 @@  static inline void serial_do_portmux(void)
 }
 
 __attribute__((always_inline))
-static inline void serial_early_init(void)
+static inline int uart_init(uint32_t uart_base)
 {
-	/* handle portmux crap on different Blackfins */
-	serial_do_portmux();
-
 	/* always enable UART -- avoids anomalies 05000309 and 05000350 */
 	bfin_write16(&pUART->gctl, UCEN);
 
@@ -180,10 +179,30 @@  static inline void serial_early_init(void)
 	bfin_write16(&pUART->lcr, WLS_8);
 
 	SSYNC();
+
+	return 0;
 }
 
 __attribute__((always_inline))
-static inline void serial_early_put_div(uint16_t divisor)
+static inline int serial_early_init(uint32_t uart_base)
+{
+	/* handle portmux crap on different Blackfins */
+	serial_do_portmux();
+
+	return uart_init(uart_base);
+}
+
+__attribute__((always_inline))
+static inline int serial_early_uninit(uint32_t uart_base)
+{
+	/* disable the UART by clearing UCEN */
+	bfin_write16(&pUART->gctl, 0);
+
+	return 0;
+}
+
+__attribute__((always_inline))
+static inline void serial_early_put_div(uint32_t uart_base, uint16_t divisor)
 {
 	/* Set DLAB in LCR to Access DLL and DLH */
 	ACCESS_LATCH();
@@ -202,6 +221,8 @@  static inline void serial_early_put_div(uint16_t divisor)
 __attribute__((always_inline))
 static inline uint16_t serial_early_get_div(void)
 {
+	uint32_t uart_base = UART_DLL;
+
 	/* Set DLAB in LCR to Access DLL and DLH */
 	ACCESS_LATCH();
 	SSYNC();
@@ -223,13 +244,14 @@  static inline uint16_t serial_early_get_div(void)
 #endif
 
 __attribute__((always_inline))
-static inline void serial_early_set_baud(uint32_t baud)
+static inline void serial_early_set_baud(uint32_t uart_base, uint32_t baud)
 {
 	/* Translate from baud into divisor in terms of SCLK.  The
 	 * weird multiplication is to make sure we over sample just
 	 * a little rather than under sample the incoming signals.
 	 */
-	serial_early_put_div((get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230);
+	serial_early_put_div(uart_base,
+		(get_sclk() + (baud * 8)) / (baud * 16) - ANOMALY_05000230);
 }
 
 #ifndef BFIN_IN_INITCODE
diff --git a/arch/blackfin/lib/board.c b/arch/blackfin/lib/board.c
index 362b8c4..e00050c 100644
--- a/arch/blackfin/lib/board.c
+++ b/arch/blackfin/lib/board.c
@@ -12,6 +12,7 @@ 
 #include <common.h>
 #include <command.h>
 #include <stdio_dev.h>
+#include <serial.h>
 #include <environment.h>
 #include <malloc.h>
 #include <mmc.h>
@@ -265,6 +266,9 @@  void board_init_f(ulong bootflag)
 	init_baudrate();
 	serial_early_puts("Serial init\n");
 	serial_init();
+#ifdef CONFIG_SERIAL_MULTI
+	serial_initialize();
+#endif
 	serial_early_puts("Console init flash\n");
 	console_init_f();
 	serial_early_puts("End of early debugging\n");
diff --git a/common/serial.c b/common/serial.c
index 8ebf9a5..7a69fc1 100644
--- a/common/serial.c
+++ b/common/serial.c
@@ -173,6 +173,9 @@  void serial_initialize (void)
 	serial_register(&serial6_device);
 #endif
 #endif
+#if defined(CONFIG_SYS_BFIN_UART)
+	serial_register_bfin_uart();
+#endif
 	serial_assign (default_serial_console ()->name);
 }
 
diff --git a/include/serial.h b/include/serial.h
index f21d961..4aa1cdc 100644
--- a/include/serial.h
+++ b/include/serial.h
@@ -71,6 +71,15 @@  extern struct serial_device serial_ffuart_device;
 extern struct serial_device serial_btuart_device;
 extern struct serial_device serial_stuart_device;
 
+#if defined(CONFIG_SYS_BFIN_UART)
+extern void serial_register_bfin_uart(void);
+extern struct serial_device bfin_serial0_device;
+extern struct serial_device bfin_serial1_device;
+extern struct serial_device bfin_serial2_device;
+extern struct serial_device bfin_serial3_device;
+#endif
+
+extern void serial_register(struct serial_device *);
 extern void serial_initialize(void);
 extern void serial_stdio_init(void);
 extern int serial_assign(char * name);