summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
authorTom Rini <trini@ti.com>2014-10-22 13:51:45 -0400
committerTom Rini <trini@ti.com>2014-10-22 13:51:45 -0400
commit68e80fdda1336068f40915388bbdacfd2b75233a (patch)
treedeb28e65fdd601e47bf5564f67da3035a840e284 /drivers/serial
parent35d4fed320d577a4446531d7b9350ce40065c4b0 (diff)
parent8a9cd5ad6f89ab721a352cbb9264bea5ede68789 (diff)
Merge git://git.denx.de/u-boot-dm
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Makefile5
-rw-r--r--drivers/serial/serial-uclass.c32
-rw-r--r--drivers/serial/serial_mxc.c170
-rw-r--r--drivers/serial/serial_pl01x.c373
-rw-r--r--drivers/serial/serial_pl01x_internal.h (renamed from drivers/serial/serial_pl01x.h)0
-rw-r--r--drivers/serial/serial_s5p.c255
6 files changed, 472 insertions, 363 deletions
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index b4f299bb0e..17c56ea66e 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -7,8 +7,11 @@
ifdef CONFIG_DM_SERIAL
obj-y += serial-uclass.o
+obj-$(CONFIG_PL01X_SERIAL) += serial_pl01x.o
else
obj-y += serial.o
+obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
+obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
obj-$(CONFIG_SYS_NS16550_SERIAL) += serial_ns16550.o
endif
@@ -25,8 +28,6 @@ obj-$(CONFIG_IMX_SERIAL) += serial_imx.o
obj-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
obj-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
obj-$(CONFIG_MXC_UART) += serial_mxc.o
-obj-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
-obj-$(CONFIG_PL011_SERIAL) += serial_pl01x.o
obj-$(CONFIG_PXA_SERIAL) += serial_pxa.o
obj-$(CONFIG_SA1100_SERIAL) += serial_sa1100.o
obj-$(CONFIG_S3C24X0_SERIAL) += serial_s3c24x0.o
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 6dde4eaf47..1a75950d19 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -71,7 +71,7 @@ void serial_initialize(void)
serial_find_console_or_panic();
}
-void serial_putc(char ch)
+static void serial_putc_dev(struct udevice *dev, char ch)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
int err;
@@ -83,6 +83,11 @@ void serial_putc(char ch)
serial_putc('\r');
}
+void serial_putc(char ch)
+{
+ serial_putc_dev(cur_dev, ch);
+}
+
void serial_setbrg(void)
{
struct dm_serial_ops *ops = serial_get_ops(cur_dev);
@@ -107,28 +112,32 @@ int serial_tstc(void)
return 1;
}
-int serial_getc(void)
+static int serial_getc_dev(struct udevice *dev)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+ struct dm_serial_ops *ops = serial_get_ops(dev);
int err;
do {
- err = ops->getc(cur_dev);
+ err = ops->getc(dev);
} while (err == -EAGAIN);
return err >= 0 ? err : 0;
}
+int serial_getc(void)
+{
+ return serial_getc_dev(cur_dev);
+}
+
void serial_stdio_init(void)
{
}
-void serial_stub_putc(struct stdio_dev *sdev, const char ch)
+static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
{
struct udevice *dev = sdev->priv;
- struct dm_serial_ops *ops = serial_get_ops(dev);
- ops->putc(dev, ch);
+ serial_putc_dev(dev, ch);
}
void serial_stub_puts(struct stdio_dev *sdev, const char *str)
@@ -140,15 +149,8 @@ void serial_stub_puts(struct stdio_dev *sdev, const char *str)
int serial_stub_getc(struct stdio_dev *sdev)
{
struct udevice *dev = sdev->priv;
- struct dm_serial_ops *ops = serial_get_ops(dev);
-
- int err;
- do {
- err = ops->getc(dev);
- } while (err == -EAGAIN);
-
- return err >= 0 ? err : 0;
+ return serial_getc_dev(dev);
}
int serial_stub_tstc(struct stdio_dev *sdev)
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index 313d560afc..9ce24f9f93 100644
--- a/drivers/serial/serial_mxc.c
+++ b/drivers/serial/serial_mxc.c
@@ -5,37 +5,15 @@
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <serial_mxc.h>
#include <watchdog.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
#include <serial.h>
#include <linux/compiler.h>
-#define __REG(x) (*((volatile u32 *)(x)))
-
-#ifndef CONFIG_MXC_UART_BASE
-#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
-#endif
-
-#define UART_PHYS CONFIG_MXC_UART_BASE
-
-/* Register definitions */
-#define URXD 0x0 /* Receiver Register */
-#define UTXD 0x40 /* Transmitter Register */
-#define UCR1 0x80 /* Control Register 1 */
-#define UCR2 0x84 /* Control Register 2 */
-#define UCR3 0x88 /* Control Register 3 */
-#define UCR4 0x8c /* Control Register 4 */
-#define UFCR 0x90 /* FIFO Control Register */
-#define USR1 0x94 /* Status Register 1 */
-#define USR2 0x98 /* Status Register 2 */
-#define UESC 0x9c /* Escape Character Register */
-#define UTIM 0xa0 /* Escape Timer Register */
-#define UBIR 0xa4 /* BRM Incremental Register */
-#define UBMR 0xa8 /* BRM Modulator Register */
-#define UBRC 0xac /* Baud Rate Count Register */
-#define UTS 0xb4 /* UART Test Register (mx31) */
-
/* UART Control Register Bit Fields.*/
#define URXD_CHARRDY (1<<15)
#define URXD_ERR (1<<14)
@@ -128,6 +106,33 @@
#define UTS_RXFULL (1<<3) /* RxFIFO full */
#define UTS_SOFTRST (1<<0) /* Software reset */
+#ifndef CONFIG_DM_SERIAL
+
+#ifndef CONFIG_MXC_UART_BASE
+#error "define CONFIG_MXC_UART_BASE to use the MXC UART driver"
+#endif
+
+#define UART_PHYS CONFIG_MXC_UART_BASE
+
+#define __REG(x) (*((volatile u32 *)(x)))
+
+/* Register definitions */
+#define URXD 0x0 /* Receiver Register */
+#define UTXD 0x40 /* Transmitter Register */
+#define UCR1 0x80 /* Control Register 1 */
+#define UCR2 0x84 /* Control Register 2 */
+#define UCR3 0x88 /* Control Register 3 */
+#define UCR4 0x8c /* Control Register 4 */
+#define UFCR 0x90 /* FIFO Control Register */
+#define USR1 0x94 /* Status Register 1 */
+#define USR2 0x98 /* Status Register 2 */
+#define UESC 0x9c /* Escape Character Register */
+#define UTIM 0xa0 /* Escape Timer Register */
+#define UBIR 0xa4 /* BRM Incremental Register */
+#define UBMR 0xa8 /* BRM Modulator Register */
+#define UBRC 0xac /* Baud Rate Count Register */
+#define UTS 0xb4 /* UART Test Register (mx31) */
+
DECLARE_GLOBAL_DATA_PTR;
static void mxc_serial_setbrg(void)
@@ -222,3 +227,118 @@ __weak struct serial_device *default_serial_console(void)
{
return &mxc_serial_drv;
}
+#endif
+
+#ifdef CONFIG_DM_SERIAL
+
+struct mxc_uart {
+ u32 rxd;
+ u32 spare0[15];
+
+ u32 txd;
+ u32 spare1[15];
+
+ u32 cr1;
+ u32 cr2;
+ u32 cr3;
+ u32 cr4;
+
+ u32 fcr;
+ u32 sr1;
+ u32 sr2;
+ u32 esc;
+
+ u32 tim;
+ u32 bir;
+ u32 bmr;
+ u32 brc;
+
+ u32 onems;
+ u32 ts;
+};
+
+int mxc_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct mxc_serial_platdata *plat = dev->platdata;
+ struct mxc_uart *const uart = plat->reg;
+ u32 clk = imx_get_uartclk();
+
+ writel(4 << 7, &uart->fcr); /* divide input clock by 2 */
+ writel(0xf, &uart->bir);
+ writel(clk / (2 * baudrate), &uart->bmr);
+
+ writel(UCR2_WS | UCR2_IRTS | UCR2_RXEN | UCR2_TXEN | UCR2_SRST,
+ &uart->cr2);
+ writel(UCR1_UARTEN, &uart->cr1);
+
+ return 0;
+}
+
+static int mxc_serial_probe(struct udevice *dev)
+{
+ struct mxc_serial_platdata *plat = dev->platdata;
+ struct mxc_uart *const uart = plat->reg;
+
+ writel(0, &uart->cr1);
+ writel(0, &uart->cr2);
+ while (!(readl(&uart->cr2) & UCR2_SRST));
+ writel(0x704 | UCR3_ADNIMP, &uart->cr3);
+ writel(0x8000, &uart->cr4);
+ writel(0x2b, &uart->esc);
+ writel(0, &uart->tim);
+ writel(0, &uart->ts);
+
+ return 0;
+}
+
+static int mxc_serial_getc(struct udevice *dev)
+{
+ struct mxc_serial_platdata *plat = dev->platdata;
+ struct mxc_uart *const uart = plat->reg;
+
+ if (readl(&uart->ts) & UTS_RXEMPTY)
+ return -EAGAIN;
+
+ return readl(&uart->rxd) & URXD_RX_DATA;
+}
+
+static int mxc_serial_putc(struct udevice *dev, const char ch)
+{
+ struct mxc_serial_platdata *plat = dev->platdata;
+ struct mxc_uart *const uart = plat->reg;
+
+ if (!(readl(&uart->ts) & UTS_TXEMPTY))
+ return -EAGAIN;
+
+ writel(ch, &uart->txd);
+
+ return 0;
+}
+
+static int mxc_serial_pending(struct udevice *dev, bool input)
+{
+ struct mxc_serial_platdata *plat = dev->platdata;
+ struct mxc_uart *const uart = plat->reg;
+ uint32_t sr2 = readl(&uart->sr2);
+
+ if (input)
+ return sr2 & USR2_RDR ? 1 : 0;
+ else
+ return sr2 & USR2_TXDC ? 0 : 1;
+}
+
+static const struct dm_serial_ops mxc_serial_ops = {
+ .putc = mxc_serial_putc,
+ .pending = mxc_serial_pending,
+ .getc = mxc_serial_getc,
+ .setbrg = mxc_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_mxc) = {
+ .name = "serial_mxc",
+ .id = UCLASS_SERIAL,
+ .probe = mxc_serial_probe,
+ .ops = &mxc_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+#endif
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index dfb610e1a9..e6313ad3d3 100644
--- a/drivers/serial/serial_pl01x.c
+++ b/drivers/serial/serial_pl01x.c
@@ -12,125 +12,90 @@
/* Simple U-Boot driver for the PrimeCell PL010/PL011 UARTs */
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <watchdog.h>
#include <asm/io.h>
#include <serial.h>
+#include <serial_pl01x.h>
#include <linux/compiler.h>
-#include "serial_pl01x.h"
+#include "serial_pl01x_internal.h"
+
+#ifndef CONFIG_DM_SERIAL
-/*
- * 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;
+static enum pl01x_type pl01x_type __attribute__ ((section(".data")));
+static struct pl01x_regs *base_regs __attribute__ ((section(".data")));
#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;
+#endif
-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)
+static int pl01x_putc(struct pl01x_regs *regs, char c)
{
- struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
- unsigned int divisor;
-
- /* First, disable everything */
- writel(0, &regs->pl010_cr);
+ /* Wait until there is space in the FIFO */
+ if (readl(&regs->fr) & UART_PL01x_FR_TXFF)
+ return -EAGAIN;
- /* Set baud rate */
- switch (baudrate) {
- case 9600:
- divisor = UART_PL010_BAUD_9600;
- break;
+ /* Send the character */
+ writel(c, &regs->dr);
- case 19200:
- divisor = UART_PL010_BAUD_9600;
- break;
+ return 0;
+}
- case 38400:
- divisor = UART_PL010_BAUD_38400;
- break;
+static int pl01x_getc(struct pl01x_regs *regs)
+{
+ unsigned int data;
- case 57600:
- divisor = UART_PL010_BAUD_57600;
- break;
+ /* Wait until there is data in the FIFO */
+ if (readl(&regs->fr) & UART_PL01x_FR_RXFE)
+ return -EAGAIN;
- case 115200:
- divisor = UART_PL010_BAUD_115200;
- break;
+ data = readl(&regs->dr);
- default:
- divisor = UART_PL010_BAUD_38400;
+ /* Check for an error flag */
+ if (data & 0xFFFFFF00) {
+ /* Clear the error */
+ writel(0xFFFFFFFF, &regs->ecr);
+ return -1;
}
- writel((divisor & 0xf00) >> 8, &regs->pl010_lcrm);
- writel(divisor & 0xff, &regs->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, &regs->pl010_lcrh);
-
- /* Finally, enable the UART */
- writel(UART_PL010_CR_UARTEN, &regs->pl010_cr);
-
- return 0;
+ return (int) data;
}
-#endif /* CONFIG_PL010_SERIAL */
-
-#ifdef CONFIG_PL011_SERIAL
+static int pl01x_tstc(struct pl01x_regs *regs)
+{
+ WATCHDOG_RESET();
+ return !(readl(&regs->fr) & UART_PL01x_FR_RXFE);
+}
-static int pl01x_serial_init(void)
+static int pl01x_generic_serial_init(struct pl01x_regs *regs,
+ enum pl01x_type type)
{
- 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(&regs->pl011_cr) & UART_PL011_CR_UARTEN) {
- while (!(readl(&regs->fr) & UART_PL01x_FR_RXFE))
- readl(&regs->dr);
+ if (type == TYPE_PL011) {
+ /* Empty RX fifo if necessary */
+ if (readl(&regs->pl011_cr) & UART_PL011_CR_UARTEN) {
+ while (!(readl(&regs->fr) & UART_PL01x_FR_RXFE))
+ readl(&regs->dr);
+ }
}
#endif
/* First, disable everything */
- writel(0, &regs->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, &regs->pl011_ibrd);
- writel(fraction, &regs->pl011_fbrd);
+ writel(0, &regs->pl010_cr);
/* 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, &regs->pl011_lcrh);
+ switch (type) {
+ case TYPE_PL010:
+ break;
+ case TYPE_PL011: {
#ifdef CONFIG_PL011_SERIAL_RLCR
- {
int i;
/*
@@ -144,90 +109,151 @@ static int pl01x_serial_init(void)
writel(lcr, &regs->pl011_rlcr);
/* lcrh needs to be set again for change to be effective */
writel(lcr, &regs->pl011_lcrh);
- }
#endif
- /* Finally, enable the UART */
- writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE | UART_PL011_CR_RXE |
- UART_PL011_CR_RTS, &regs->pl011_cr);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
return 0;
}
-#endif /* CONFIG_PL011_SERIAL */
-
-static void pl01x_serial_putc(const char c)
+static int pl01x_generic_setbrg(struct pl01x_regs *regs, enum pl01x_type type,
+ int clock, int baudrate)
{
- if (c == '\n')
- pl01x_putc (CONSOLE_PORT, '\r');
+ switch (type) {
+ case TYPE_PL010: {
+ unsigned int divisor;
+
+ 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, &regs->pl010_lcrm);
+ writel(divisor & 0xff, &regs->pl010_lcrl);
+
+ /* Finally, enable the UART */
+ writel(UART_PL010_CR_UARTEN, &regs->pl010_cr);
+ break;
+ }
+ case TYPE_PL011: {
+ unsigned int temp;
+ unsigned int divider;
+ unsigned int remainder;
+ unsigned int fraction;
- pl01x_putc (CONSOLE_PORT, c);
-}
+ /*
+ * 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 = clock / temp;
+ remainder = clock % temp;
+ temp = (8 * remainder) / baudrate;
+ fraction = (temp >> 1) + (temp & 1);
+
+ writel(divider, &regs->pl011_ibrd);
+ writel(fraction, &regs->pl011_fbrd);
+
+ /* Finally, enable the UART */
+ writel(UART_PL011_CR_UARTEN | UART_PL011_CR_TXE |
+ UART_PL011_CR_RXE | UART_PL011_CR_RTS, &regs->pl011_cr);
+ break;
+ }
+ default:
+ return -EINVAL;
+ }
-static int pl01x_serial_getc(void)
-{
- return pl01x_getc (CONSOLE_PORT);
+ return 0;
}
-static int pl01x_serial_tstc(void)
+#ifndef CONFIG_DM_SERIAL
+static void pl01x_serial_init_baud(int baudrate)
{
- return pl01x_tstc (CONSOLE_PORT);
+ int clock = 0;
+
+#if defined(CONFIG_PL010_SERIAL)
+ pl01x_type = TYPE_PL010;
+#elif defined(CONFIG_PL011_SERIAL)
+ pl01x_type = TYPE_PL011;
+ clock = CONFIG_PL011_CLOCK;
+#endif
+ base_regs = (struct pl01x_regs *)port[CONFIG_CONS_INDEX];
+
+ pl01x_generic_serial_init(base_regs, pl01x_type);
+ pl01x_generic_setbrg(base_regs, TYPE_PL010, clock, baudrate);
}
-static void pl01x_serial_setbrg(void)
+/*
+ * 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.
+ */
+int pl01x_serial_init(void)
{
- struct pl01x_regs *regs = pl01x_get_regs(CONSOLE_PORT);
+ pl01x_serial_init_baud(CONFIG_BAUDRATE);
- baudrate = gd->baudrate;
- /*
- * Flush FIFO and wait for non-busy before changing baudrate to avoid
- * crap in console
- */
- while (!(readl(&regs->fr) & UART_PL01x_FR_TXFE))
- WATCHDOG_RESET();
- while (readl(&regs->fr) & UART_PL01x_FR_BUSY)
- WATCHDOG_RESET();
- serial_init();
+ return 0;
}
-static void pl01x_putc (int portnum, char c)
+static void pl01x_serial_putc(const char c)
{
- struct pl01x_regs *regs = pl01x_get_regs(portnum);
-
- /* Wait until there is space in the FIFO */
- while (readl(&regs->fr) & UART_PL01x_FR_TXFF)
- WATCHDOG_RESET();
+ if (c == '\n')
+ while (pl01x_putc(base_regs, '\r') == -EAGAIN);
- /* Send the character */
- writel(c, &regs->dr);
+ while (pl01x_putc(base_regs, c) == -EAGAIN);
}
-static int pl01x_getc (int portnum)
+static int pl01x_serial_getc(void)
{
- struct pl01x_regs *regs = pl01x_get_regs(portnum);
- unsigned int data;
+ while (1) {
+ int ch = pl01x_getc(base_regs);
- /* Wait until there is data in the FIFO */
- while (readl(&regs->fr) & UART_PL01x_FR_RXFE)
- WATCHDOG_RESET();
-
- data = readl(&regs->dr);
+ if (ch == -EAGAIN) {
+ WATCHDOG_RESET();
+ continue;
+ }
- /* Check for an error flag */
- if (data & 0xFFFFFF00) {
- /* Clear the error */
- writel(0xFFFFFFFF, &regs->ecr);
- return -1;
+ return ch;
}
-
- return (int) data;
}
-static int pl01x_tstc (int portnum)
+static int pl01x_serial_tstc(void)
{
- struct pl01x_regs *regs = pl01x_get_regs(portnum);
+ return pl01x_tstc(base_regs);
+}
- WATCHDOG_RESET();
- return !(readl(&regs->fr) & UART_PL01x_FR_RXFE);
+static void pl01x_serial_setbrg(void)
+{
+ /*
+ * Flush FIFO and wait for non-busy before changing baudrate to avoid
+ * crap in console
+ */
+ while (!(readl(&base_regs->fr) & UART_PL01x_FR_TXFE))
+ WATCHDOG_RESET();
+ while (readl(&base_regs->fr) & UART_PL01x_FR_BUSY)
+ WATCHDOG_RESET();
+ pl01x_serial_init_baud(gd->baudrate);
}
static struct serial_device pl01x_serial_drv = {
@@ -250,3 +276,74 @@ __weak struct serial_device *default_serial_console(void)
{
return &pl01x_serial_drv;
}
+
+#endif /* nCONFIG_DM_SERIAL */
+
+#ifdef CONFIG_DM_SERIAL
+
+struct pl01x_priv {
+ struct pl01x_regs *regs;
+ enum pl01x_type type;
+};
+
+static int pl01x_serial_setbrg(struct udevice *dev, int baudrate)
+{
+ struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+ struct pl01x_priv *priv = dev_get_priv(dev);
+
+ pl01x_generic_setbrg(priv->regs, priv->type, plat->clock, baudrate);
+
+ return 0;
+}
+
+static int pl01x_serial_probe(struct udevice *dev)
+{
+ struct pl01x_serial_platdata *plat = dev_get_platdata(dev);
+ struct pl01x_priv *priv = dev_get_priv(dev);
+
+ priv->regs = (struct pl01x_regs *)plat->base;
+ priv->type = plat->type;
+ return pl01x_generic_serial_init(priv->regs, priv->type);
+}
+
+static int pl01x_serial_getc(struct udevice *dev)
+{
+ struct pl01x_priv *priv = dev_get_priv(dev);
+
+ return pl01x_getc(priv->regs);
+}
+
+static int pl01x_serial_putc(struct udevice *dev, const char ch)
+{
+ struct pl01x_priv *priv = dev_get_priv(dev);
+
+ return pl01x_putc(priv->regs, ch);
+}
+
+static int pl01x_serial_pending(struct udevice *dev, bool input)
+{
+ struct pl01x_priv *priv = dev_get_priv(dev);
+ unsigned int fr = readl(&priv->regs->fr);
+
+ if (input)
+ return pl01x_tstc(priv->regs);
+ else
+ return fr & UART_PL01x_FR_TXFF ? 0 : 1;
+}
+
+static const struct dm_serial_ops pl01x_serial_ops = {
+ .putc = pl01x_serial_putc,
+ .pending = pl01x_serial_pending,
+ .getc = pl01x_serial_getc,
+ .setbrg = pl01x_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_pl01x) = {
+ .name = "serial_pl01x",
+ .id = UCLASS_SERIAL,
+ .probe = pl01x_serial_probe,
+ .ops = &pl01x_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
+
+#endif
diff --git a/drivers/serial/serial_pl01x.h b/drivers/serial/serial_pl01x_internal.h
index 288a4f19f5..288a4f19f5 100644
--- a/drivers/serial/serial_pl01x.h
+++ b/drivers/serial/serial_pl01x_internal.h
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 98c62b4c14..8469afdaae 100644
--- a/drivers/serial/serial_s5p.c
+++ b/drivers/serial/serial_s5p.c
@@ -9,6 +9,8 @@
*/
#include <common.h>
+#include <dm.h>
+#include <errno.h>
#include <fdtdec.h>
#include <linux/compiler.h>
#include <asm/io.h>
@@ -18,26 +20,18 @@
DECLARE_GLOBAL_DATA_PTR;
-#define RX_FIFO_COUNT_MASK 0xff
-#define RX_FIFO_FULL_MASK (1 << 8)
-#define TX_FIFO_FULL_MASK (1 << 24)
+#define RX_FIFO_COUNT_SHIFT 0
+#define RX_FIFO_COUNT_MASK (0xff << RX_FIFO_COUNT_SHIFT)
+#define RX_FIFO_FULL (1 << 8)
+#define TX_FIFO_COUNT_SHIFT 16
+#define TX_FIFO_COUNT_MASK (0xff << TX_FIFO_COUNT_SHIFT)
+#define TX_FIFO_FULL (1 << 24)
/* Information about a serial port */
-struct fdt_serial {
- u32 base_addr; /* address of registers in physical memory */
+struct s5p_serial_platdata {
+ struct s5p_uart *reg; /* address of registers in physical memory */
u8 port_id; /* uart port number */
- u8 enabled; /* 1 if enabled, 0 if disabled */
-} config __attribute__ ((section(".data")));
-
-static inline struct s5p_uart *s5p_get_base_uart(int dev_index)
-{
-#ifdef CONFIG_OF_CONTROL
- return (struct s5p_uart *)(config.base_addr);
-#else
- u32 offset = dev_index * sizeof(struct s5p_uart);
- return (struct s5p_uart *)(samsung_get_base_uart() + offset);
-#endif
-}
+};
/*
* The coefficient, used to calculate the baudrate on S5P UARTs is
@@ -65,23 +59,13 @@ static const int udivslot[] = {
0xffdf,
};
-static void serial_setbrg_dev(const int dev_index)
+int s5p_serial_setbrg(struct udevice *dev, int baudrate)
{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
- u32 uclk = get_uart_clk(dev_index);
- u32 baudrate = gd->baudrate;
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
+ u32 uclk = get_uart_clk(plat->port_id);
u32 val;
-#if defined(CONFIG_SILENT_CONSOLE) && \
- defined(CONFIG_OF_CONTROL) && \
- !defined(CONFIG_SPL_BUILD)
- if (fdtdec_get_config_int(gd->fdt_blob, "silent_console", 0))
- gd->flags |= GD_FLG_SILENT;
-#endif
-
- if (!config.enabled)
- return;
-
val = uclk / baudrate;
writel(val / 16 - 1, &uart->ubrdiv);
@@ -90,15 +74,14 @@ static void serial_setbrg_dev(const int dev_index)
writew(udivslot[val % 16], &uart->rest.slot);
else
writeb(val % 16, &uart->rest.value);
+
+ return 0;
}
-/*
- * Initialise the serial port with the given baudrate. The settings
- * are always 8 data bits, no parity, 1 stop bit, no start bits.
- */
-static int serial_init_dev(const int dev_index)
+static int s5p_serial_probe(struct udevice *dev)
{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
/* enable FIFOs, auto clear Rx FIFO */
writel(0x3, &uart->ufcon);
@@ -108,14 +91,11 @@ static int serial_init_dev(const int dev_index)
/* No interrupts, no DMA, pure polling */
writel(0x245, &uart->ucon);
- serial_setbrg_dev(dev_index);
-
return 0;
}
-static int serial_err_check(const int dev_index, int op)
+static int serial_err_check(const struct s5p_uart *const uart, int op)
{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
unsigned int mask;
/*
@@ -133,169 +113,78 @@ static int serial_err_check(const int dev_index, int op)
return readl(&uart->uerstat) & mask;
}
-/*
- * Read a single byte from the serial port. Returns 1 on success, 0
- * otherwise. When the function is succesfull, the character read is
- * written into its argument c.
- */
-static int serial_getc_dev(const int dev_index)
+static int s5p_serial_getc(struct udevice *dev)
{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
- if (!config.enabled)
- return 0;
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
- /* wait for character to arrive */
- while (!(readl(&uart->ufstat) & (RX_FIFO_COUNT_MASK |
- RX_FIFO_FULL_MASK))) {
- if (serial_err_check(dev_index, 0))
- return 0;
- }
+ if (!(readl(&uart->ufstat) & RX_FIFO_COUNT_MASK))
+ return -EAGAIN;
+ serial_err_check(uart, 0);
return (int)(readb(&uart->urxh) & 0xff);
}
-/*
- * Output a single byte to the serial port.
- */
-static void serial_putc_dev(const char c, const int dev_index)
+static int s5p_serial_putc(struct udevice *dev, const char ch)
{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
-
- if (!config.enabled)
- return;
-
- /* wait for room in the tx FIFO */
- while ((readl(&uart->ufstat) & TX_FIFO_FULL_MASK)) {
- if (serial_err_check(dev_index, 1))
- return;
- }
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
- writeb(c, &uart->utxh);
+ if (readl(&uart->ufstat) & TX_FIFO_FULL)
+ return -EAGAIN;
- /* If \n, also do \r */
- if (c == '\n')
- serial_putc('\r');
-}
-
-/*
- * Test whether a character is in the RX buffer
- */
-static int serial_tstc_dev(const int dev_index)
-{
- struct s5p_uart *const uart = s5p_get_base_uart(dev_index);
+ writeb(ch, &uart->utxh);
+ serial_err_check(uart, 1);
- if (!config.enabled)
- return 0;
-
- return (int)(readl(&uart->utrstat) & 0x1);
+ return 0;
}
-static void serial_puts_dev(const char *s, const int dev_index)
+static int s5p_serial_pending(struct udevice *dev, bool input)
{
- while (*s)
- serial_putc_dev(*s++, dev_index);
-}
+ struct s5p_serial_platdata *plat = dev->platdata;
+ struct s5p_uart *const uart = plat->reg;
+ uint32_t ufstat = readl(&uart->ufstat);
-/* Multi serial device functions */
-#define DECLARE_S5P_SERIAL_FUNCTIONS(port) \
-static int s5p_serial##port##_init(void) { return serial_init_dev(port); } \
-static void s5p_serial##port##_setbrg(void) { serial_setbrg_dev(port); } \
-static int s5p_serial##port##_getc(void) { return serial_getc_dev(port); } \
-static int s5p_serial##port##_tstc(void) { return serial_tstc_dev(port); } \
-static void s5p_serial##port##_putc(const char c) { serial_putc_dev(c, port); } \
-static void s5p_serial##port##_puts(const char *s) { serial_puts_dev(s, port); }
-
-#define INIT_S5P_SERIAL_STRUCTURE(port, __name) { \
- .name = __name, \
- .start = s5p_serial##port##_init, \
- .stop = NULL, \
- .setbrg = s5p_serial##port##_setbrg, \
- .getc = s5p_serial##port##_getc, \
- .tstc = s5p_serial##port##_tstc, \
- .putc = s5p_serial##port##_putc, \
- .puts = s5p_serial##port##_puts, \
+ if (input)
+ return (ufstat & RX_FIFO_COUNT_MASK) >> RX_FIFO_COUNT_SHIFT;
+ else
+ return (ufstat & TX_FIFO_COUNT_MASK) >> TX_FIFO_COUNT_SHIFT;
}
-DECLARE_S5P_SERIAL_FUNCTIONS(0);
-struct serial_device s5p_serial0_device =
- INIT_S5P_SERIAL_STRUCTURE(0, "s5pser0");
-DECLARE_S5P_SERIAL_FUNCTIONS(1);
-struct serial_device s5p_serial1_device =
- INIT_S5P_SERIAL_STRUCTURE(1, "s5pser1");
-DECLARE_S5P_SERIAL_FUNCTIONS(2);
-struct serial_device s5p_serial2_device =
- INIT_S5P_SERIAL_STRUCTURE(2, "s5pser2");
-DECLARE_S5P_SERIAL_FUNCTIONS(3);
-struct serial_device s5p_serial3_device =
- INIT_S5P_SERIAL_STRUCTURE(3, "s5pser3");
-
-#ifdef CONFIG_OF_CONTROL
-int fdtdec_decode_console(int *index, struct fdt_serial *uart)
+static int s5p_serial_ofdata_to_platdata(struct udevice *dev)
{
- const void *blob = gd->fdt_blob;
- int node;
+ struct s5p_serial_platdata *plat = dev->platdata;
+ fdt_addr_t addr;
- node = fdt_path_offset(blob, "console");
- if (node < 0)
- return node;
+ addr = fdtdec_get_addr(gd->fdt_blob, dev->of_offset, "reg");
+ if (addr == FDT_ADDR_T_NONE)
+ return -EINVAL;
- uart->base_addr = fdtdec_get_addr(blob, node, "reg");
- if (uart->base_addr == FDT_ADDR_T_NONE)
- return -FDT_ERR_NOTFOUND;
-
- uart->port_id = fdtdec_get_int(blob, node, "id", -1);
- uart->enabled = fdtdec_get_is_enabled(blob, node);
+ plat->reg = (struct s5p_uart *)addr;
+ plat->port_id = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "id", -1);
return 0;
}
-#endif
-__weak struct serial_device *default_serial_console(void)
-{
-#ifdef CONFIG_OF_CONTROL
- int index = 0;
-
- if ((!config.base_addr) && (fdtdec_decode_console(&index, &config))) {
- debug("Cannot decode default console node\n");
- return NULL;
- }
-
- switch (config.port_id) {
- case 0:
- return &s5p_serial0_device;
- case 1:
- return &s5p_serial1_device;
- case 2:
- return &s5p_serial2_device;
- case 3:
- return &s5p_serial3_device;
- default:
- debug("Unknown config.port_id: %d", config.port_id);
- break;
- }
-
- return NULL;
-#else
- config.enabled = 1;
-#if defined(CONFIG_SERIAL0)
- return &s5p_serial0_device;
-#elif defined(CONFIG_SERIAL1)
- return &s5p_serial1_device;
-#elif defined(CONFIG_SERIAL2)
- return &s5p_serial2_device;
-#elif defined(CONFIG_SERIAL3)
- return &s5p_serial3_device;
-#else
-#error "CONFIG_SERIAL? missing."
-#endif
-#endif
-}
+static const struct dm_serial_ops s5p_serial_ops = {
+ .putc = s5p_serial_putc,
+ .pending = s5p_serial_pending,
+ .getc = s5p_serial_getc,
+ .setbrg = s5p_serial_setbrg,
+};
-void s5p_serial_initialize(void)
-{
- serial_register(&s5p_serial0_device);
- serial_register(&s5p_serial1_device);
- serial_register(&s5p_serial2_device);
- serial_register(&s5p_serial3_device);
-}
+static const struct udevice_id s5p_serial_ids[] = {
+ { .compatible = "samsung,exynos4210-uart" },
+ { }
+};
+
+U_BOOT_DRIVER(serial_s5p) = {
+ .name = "serial_s5p",
+ .id = UCLASS_SERIAL,
+ .of_match = s5p_serial_ids,
+ .ofdata_to_platdata = s5p_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct s5p_serial_platdata),
+ .probe = s5p_serial_probe,
+ .ops = &s5p_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};