diff options
| author | Mike Frysinger <vapier@gentoo.org> | 2011-04-29 23:23:28 -0400 | 
|---|---|---|
| committer | Mike Frysinger <vapier@gentoo.org> | 2011-07-12 02:17:45 -0400 | 
| commit | 635f330fc7883a4cc703bc5ea2b90fc7d7f69e10 (patch) | |
| tree | 2895084758f361d1874be7d233fda4683381219d | |
| parent | 34a6d0b84a25a141123f589b0cfef2bf88afe220 (diff) | |
| download | olio-uboot-2014.01-635f330fc7883a4cc703bc5ea2b90fc7d7f69e10.tar.xz olio-uboot-2014.01-635f330fc7883a4cc703bc5ea2b90fc7d7f69e10.zip | |
Blackfin: uart: add multiple serial support
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>
| -rw-r--r-- | arch/blackfin/cpu/initcode.c | 12 | ||||
| -rw-r--r-- | arch/blackfin/cpu/serial.c | 205 | ||||
| -rw-r--r-- | arch/blackfin/cpu/serial.h | 44 | ||||
| -rw-r--r-- | arch/blackfin/lib/board.c | 4 | ||||
| -rw-r--r-- | common/serial.c | 3 | ||||
| -rw-r--r-- | include/serial.h | 9 | 
6 files changed, 222 insertions, 55 deletions
| diff --git a/arch/blackfin/cpu/initcode.c b/arch/blackfin/cpu/initcode.c index 750add06b..61dc5ab0e 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 b15c945cb..02522209d 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 7999a1933..aa5c21756 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 362b8c47e..e00050ccb 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 8ebf9a5d2..7a69fc1a5 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 f21d96171..4aa1cdc31 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); |