diff options
author | Yang Zhang <yang.z.zhang@intel.com> | 2015-08-28 09:58:54 +0800 |
---|---|---|
committer | Yang Zhang <yang.z.zhang@intel.com> | 2015-09-01 12:44:00 +0800 |
commit | e44e3482bdb4d0ebde2d8b41830ac2cdb07948fb (patch) | |
tree | 66b09f592c55df2878107a468a91d21506104d3f /qemu/roms/u-boot/drivers/serial/serial_pl01x.c | |
parent | 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 (diff) |
Add qemu 2.4.0
Change-Id: Ic99cbad4b61f8b127b7dc74d04576c0bcbaaf4f5
Signed-off-by: Yang Zhang <yang.z.zhang@intel.com>
Diffstat (limited to 'qemu/roms/u-boot/drivers/serial/serial_pl01x.c')
-rw-r--r-- | qemu/roms/u-boot/drivers/serial/serial_pl01x.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/qemu/roms/u-boot/drivers/serial/serial_pl01x.c b/qemu/roms/u-boot/drivers/serial/serial_pl01x.c new file mode 100644 index 000000000..dfb610e1a --- /dev/null +++ b/qemu/roms/u-boot/drivers/serial/serial_pl01x.c @@ -0,0 +1,252 @@ +/* + * (C) Copyright 2000 + * Rob Taylor, Flying Pig Systems. robt@flyingpig.com. + * + * (C) Copyright 2004 + * ARM Ltd. + * Philippe Robin, <philippe.robin@arm.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */ + +#include <common.h> +#include <watchdog.h> +#include <asm/io.h> +#include <serial.h> +#include <linux/compiler.h> +#include "serial_pl01x.h" + +/* + * 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 +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; + +static struct pl01x_regs *pl01x_get_regs(int portnum) +{ + return (struct pl01x_regs *) port[portnum]; +} + +#ifdef CONFIG_PL010_SERIAL + +static int pl01x_serial_init(void) +{ + struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT); + unsigned int divisor; + + /* First, disable everything */ + writel(0, ®s->pl010_cr); + + /* Set baud rate */ + switch (baudrate) { + case 9600: + divisor = UART_PL010_BAUD_9600; + break; + + case 19200: + divisor = UART_PL010_BAUD_9600; + break; + + case 38400: + divisor = UART_PL010_BAUD_38400; + break; + + case 57600: + divisor = UART_PL010_BAUD_57600; + break; + + case 115200: + divisor = UART_PL010_BAUD_115200; + break; + + default: + divisor = UART_PL010_BAUD_38400; + } + + 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 */ + writel(UART_PL010_LCRH_WLEN_8 | UART_PL010_LCRH_FEN, ®s->pl010_lcrh); + + /* Finally, enable the UART */ + writel(UART_PL010_CR_UARTEN, ®s->pl010_cr); + + return 0; +} + +#endif /* CONFIG_PL010_SERIAL */ + +#ifdef CONFIG_PL011_SERIAL + +static int pl01x_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; + +#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 = RND((64 * MOD(UART_CLK,(16 * BAUD_RATE))) / (16 * BAUD_RATE)) + */ + temp = 16 * baudrate; + divider = CONFIG_PL011_CLOCK / temp; + remainder = CONFIG_PL011_CLOCK % temp; + temp = (8 * remainder) / baudrate; + fraction = (temp >> 1) + (temp & 1); + + writel(divider, ®s->pl011_ibrd); + writel(fraction, ®s->pl011_fbrd); + + /* 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); + +#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 | + UART_PL011_CR_RTS, ®s->pl011_cr); + + return 0; +} + +#endif /* CONFIG_PL011_SERIAL */ + +static void pl01x_serial_putc(const char c) +{ + if (c == '\n') + pl01x_putc (CONSOLE_PORT, '\r'); + + pl01x_putc (CONSOLE_PORT, c); +} + +static int pl01x_serial_getc(void) +{ + return pl01x_getc (CONSOLE_PORT); +} + +static int pl01x_serial_tstc(void) +{ + return pl01x_tstc (CONSOLE_PORT); +} + +static void pl01x_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 (readl(®s->fr) & UART_PL01x_FR_TXFF) + WATCHDOG_RESET(); + + /* Send the character */ + 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 (readl(®s->fr) & UART_PL01x_FR_RXFE) + WATCHDOG_RESET(); + + data = readl(®s->dr); + + /* Check for an error flag */ + if (data & 0xFFFFFF00) { + /* Clear the error */ + writel(0xFFFFFFFF, ®s->ecr); + return -1; + } + + return (int) data; +} + +static int pl01x_tstc (int portnum) +{ + struct pl01x_regs *regs = pl01x_get_regs(portnum); + + WATCHDOG_RESET(); + return !(readl(®s->fr) & UART_PL01x_FR_RXFE); +} + +static struct serial_device pl01x_serial_drv = { + .name = "pl01x_serial", + .start = pl01x_serial_init, + .stop = NULL, + .setbrg = pl01x_serial_setbrg, + .putc = pl01x_serial_putc, + .puts = default_serial_puts, + .getc = pl01x_serial_getc, + .tstc = pl01x_serial_tstc, +}; + +void pl01x_serial_initialize(void) +{ + serial_register(&pl01x_serial_drv); +} + +__weak struct serial_device *default_serial_console(void) +{ + return &pl01x_serial_drv; +} |