X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=drivers%2Fserial%2Fserial_pl01x.c;h=d4c5137092f48648ce3e75aecd8bf2cb9ef04186;hb=5675b509165b67465a20e5cf71e07f40b449ef0c;hp=d0497ec418063bd5085cc3104bd1f153f94dc540;hpb=20c9226cb8cab08a111ee73db04e62d943ee0c97;p=u-boot diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c index d0497ec418..d4c5137092 100644 --- a/drivers/serial/serial_pl01x.c +++ b/drivers/serial/serial_pl01x.c @@ -25,49 +25,45 @@ * MA 02111-1307 USA */ -/* Simple U-Boot driver for the PrimeCell PL011 UARTs on the IntegratorCP */ -/* Should be fairly simple to make it work with the PL010 as well */ +/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ #include #include - -#if defined(CFG_PL010_SERIAL) || defined(CFG_PL011_SERIAL) - +#include #include "serial_pl01x.h" -#define IO_WRITE(addr, val) (*(volatile unsigned int *)(addr) = (val)) -#define IO_READ(addr) (*(volatile unsigned int *)(addr)) - /* * Integrator AP has two UARTs, we use the first one, at 38400-8-N-1 * Integrator CP has two UARTs, use the first one, at 38400-8-N-1 * Versatile PB has four UARTs. */ #define CONSOLE_PORT CONFIG_CONS_INDEX -#define baudRate CONFIG_BAUDRATE static volatile unsigned char *const port[] = CONFIG_PL01x_PORTS; #define NUM_PORTS (sizeof(port)/sizeof(port[0])) static void pl01x_putc (int portnum, char c); static int pl01x_getc (int portnum); static int pl01x_tstc (int portnum); +unsigned int baudrate = CONFIG_BAUDRATE; +DECLARE_GLOBAL_DATA_PTR; -#ifdef CFG_PL010_SERIAL +static struct pl01x_regs *pl01x_get_regs(int portnum) +{ + return (struct pl01x_regs *) port[portnum]; +} + +#ifdef CONFIG_PL010_SERIAL int serial_init (void) { + struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); unsigned int divisor; - /* - ** First, disable everything. - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL010_CR, 0x0); + /* First, disable everything */ + writel(0, ®s->pl010_cr); - /* - ** Set baud rate - ** - */ - switch (baudRate) { + /* Set baud rate */ + switch (baudrate) { case 9600: divisor = UART_PL010_BAUD_9600; break; @@ -92,72 +88,86 @@ int serial_init (void) divisor = UART_PL010_BAUD_38400; } - IO_WRITE (port[CONSOLE_PORT] + UART_PL010_LCRM, - ((divisor & 0xf00) >> 8)); - IO_WRITE (port[CONSOLE_PORT] + UART_PL010_LCRL, (divisor & 0xff)); + writel((divisor & 0xf00) >> 8, ®s->pl010_lcrm); + writel(divisor & 0xff, ®s->pl010_lcrl); - /* - ** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL010_LCRH, - (UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN)); + /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ + writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN, ®s->pl010_lcrh); - /* - ** Finally, enable the UART - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL010_CR, (UART_PL010_CR_UARTEN)); + /* Finally, enable the UART */ + writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); return 0; } -#endif /* CFG_PL010_SERIAL */ +#endif /* CONFIG_PL010_SERIAL */ -#ifdef CFG_PL011_SERIAL +#ifdef CONFIG_PL011_SERIAL int serial_init (void) { + struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); unsigned int temp; unsigned int divider; unsigned int remainder; unsigned int fraction; + unsigned int lcr; - /* - ** First, disable everything. - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR, 0x0); +#ifdef CONFIG_PL011_SERIAL_FLUSH_ON_INIT + /* Empty RX fifo if necessary */ + if (readl(®s->pl011_cr) & UART_PL011_CR_UARTEN) { + while (!(readl(®s->fr) & UART_PL01x_FR_RXFE)) + readl(®s->dr); + } +#endif + + /* First, disable everything */ + writel(0, ®s->pl011_cr); /* - ** Set baud rate - ** - ** IBRD = UART_CLK / (16 * BAUD_RATE) - ** FBRD = ROUND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE)) + * Set baud rate + * + * IBRD = UART_CLK / (16 * BAUD_RATE) + * FBRD = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE)) */ - temp = 16 * baudRate; + temp = 16 * baudrate; divider = CONFIG_PL011_CLOCK / temp; remainder = CONFIG_PL011_CLOCK % temp; - temp = (8 * remainder) / baudRate; + temp = (8 * remainder) / baudrate; fraction = (temp >> 1) + (temp & 1); - IO_WRITE (port[CONSOLE_PORT] + UART_PL011_IBRD, divider); - IO_WRITE (port[CONSOLE_PORT] + UART_PL011_FBRD, fraction); + writel(divider, ®s->pl011_ibrd); + writel(fraction, ®s->pl011_fbrd); - /* - ** Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled. - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL011_LCRH, - (UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN)); + /* Set the UART to be 8 bits, 1 stop bit, no parity, fifo enabled */ + lcr = UART_PL011_LCRH_WLEN_8 | UART_PL011_LCRH_FEN; + writel(lcr, ®s->pl011_lcrh); - /* - ** Finally, enable the UART - */ - IO_WRITE (port[CONSOLE_PORT] + UART_PL011_CR, - (UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | - UART_PL011_CR_RXE)); +#ifdef CONFIG_PL011_SERIAL_RLCR + { + int i; + + /* + * Program receive line control register after waiting + * 10 bus cycles. Delay be writing to readonly register + * 10 times + */ + for (i = 0; i < 10; i++) + writel(lcr, ®s->fr); + + writel(lcr, ®s->pl011_rlcr); + /* lcrh needs to be set again for change to be effective */ + writel(lcr, ®s->pl011_lcrh); + } +#endif + /* Finally, enable the UART */ + writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | UART_PL011_CR_RXE, + ®s->pl011_cr); return 0; } -#endif /* CFG_PL011_SERIAL */ +#endif /* CONFIG_PL011_SERIAL */ void serial_putc (const char c) { @@ -186,32 +196,47 @@ int serial_tstc (void) void serial_setbrg (void) { + struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); + + baudrate = gd->baudrate; + /* + * Flush FIFO and wait for non-busy before changing baudrate to avoid + * crap in console + */ + while (!(readl(®s->fr) & UART_PL01x_FR_TXFE)) + WATCHDOG_RESET(); + while (readl(®s->fr) & UART_PL01x_FR_BUSY) + WATCHDOG_RESET(); + serial_init(); } static void pl01x_putc (int portnum, char c) { + struct pl01x_regs *regs = pl01x_get_regs(portnum); + /* Wait until there is space in the FIFO */ - while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_TXFF) + while (readl(®s->fr) & UART_PL01x_FR_TXFF) WATCHDOG_RESET(); /* Send the character */ - IO_WRITE (port[portnum] + UART_PL01x_DR, c); + writel(c, ®s->dr); } static int pl01x_getc (int portnum) { + struct pl01x_regs *regs = pl01x_get_regs(portnum); unsigned int data; /* Wait until there is data in the FIFO */ - while (IO_READ (port[portnum] + UART_PL01x_FR) & UART_PL01x_FR_RXFE) + while (readl(®s->fr) & UART_PL01x_FR_RXFE) WATCHDOG_RESET(); - data = IO_READ (port[portnum] + UART_PL01x_DR); + data = readl(®s->dr); /* Check for an error flag */ if (data & 0xFFFFFF00) { /* Clear the error */ - IO_WRITE (port[portnum] + UART_PL01x_ECR, 0xFFFFFFFF); + writel(0xFFFFFFFF, ®s->ecr); return -1; } @@ -220,9 +245,8 @@ static int pl01x_getc (int portnum) static int pl01x_tstc (int portnum) { + struct pl01x_regs *regs = pl01x_get_regs(portnum); + WATCHDOG_RESET(); - return !(IO_READ (port[portnum] + UART_PL01x_FR) & - UART_PL01x_FR_RXFE); + return !(readl(®s->fr) & UART_PL01x_FR_RXFE); } - -#endif