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>
This commit is contained in:
Mike Frysinger 2011-04-29 23:23:28 -04:00
parent 34a6d0b84a
commit 635f330fc7
6 changed files with 222 additions and 55 deletions

View File

@ -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');
}

View File

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

View File

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

View File

@ -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");

View File

@ -172,6 +172,9 @@ void serial_initialize (void)
#if defined(CONFIG_SYS_PSC6)
serial_register(&serial6_device);
#endif
#endif
#if defined(CONFIG_SYS_BFIN_UART)
serial_register_bfin_uart();
#endif
serial_assign (default_serial_console ()->name);
}

View File

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