summaryrefslogtreecommitdiff
path: root/drivers/serial
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/serial')
-rw-r--r--drivers/serial/Kconfig12
-rw-r--r--drivers/serial/Makefile7
-rw-r--r--drivers/serial/ns16550.c17
-rw-r--r--drivers/serial/serial-uclass.c107
-rw-r--r--drivers/serial/serial.c10
-rw-r--r--drivers/serial/serial_coreboot.c38
-rw-r--r--drivers/serial/serial_mxc.c170
-rw-r--r--drivers/serial/serial_ns16550.c21
-rw-r--r--drivers/serial/serial_omap.c47
-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_s3c24x0.c10
-rw-r--r--drivers/serial/serial_s5p.c255
-rw-r--r--drivers/serial/serial_sh.c4
-rw-r--r--drivers/serial/serial_uniphier.c199
15 files changed, 715 insertions, 555 deletions
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index e69de29..a0b6e02 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -0,0 +1,12 @@
+config DM_SERIAL
+ bool "Enable Driver Model for serial drivers"
+ depends on DM
+ help
+ If you want to use driver model for serial drivers, say Y.
+ To use legacy serial drivers, say N.
+
+config UNIPHIER_SERIAL
+ bool "UniPhier on-chip UART support"
+ depends on ARCH_UNIPHIER && DM_SERIAL
+ help
+ Support for the on-chip UARTs on the Panasonic UniPhier platform.
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index b4f299b..2c19ebc 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
@@ -40,6 +41,8 @@ obj-$(CONFIG_MXS_AUART) += mxs_auart.o
obj-$(CONFIG_ARC_SERIAL) += serial_arc.o
obj-$(CONFIG_TEGRA_SERIAL) += serial_tegra.o
obj-$(CONFIG_UNIPHIER_SERIAL) += serial_uniphier.o
+obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
+obj-$(CONFIG_COREBOOT_SERIAL) += serial_coreboot.o
ifndef CONFIG_SPL_BUILD
obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/ns16550.c b/drivers/serial/ns16550.c
index 63a9ef6..8f05191 100644
--- a/drivers/serial/ns16550.c
+++ b/drivers/serial/ns16550.c
@@ -61,13 +61,13 @@ static void ns16550_writeb(NS16550_t port, int offset, int value)
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = plat->base + offset;
+ addr = map_sysmem(plat->base, 0) + offset;
/*
* As far as we know it doesn't make sense to support selection of
* these options at run-time, so use the existing CONFIG options.
*/
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
- outb(value, addr);
+ outb(value, (ulong)addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
out_le32(addr, value);
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
@@ -85,9 +85,9 @@ static int ns16550_readb(NS16550_t port, int offset)
unsigned char *addr;
offset *= 1 << plat->reg_shift;
- addr = plat->base + offset;
+ addr = map_sysmem(plat->base, 0) + offset;
#ifdef CONFIG_SYS_NS16550_PORT_MAPPED
- return inb(addr);
+ return inb((ulong)addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && !defined(CONFIG_SYS_BIG_ENDIAN)
return in_le32(addr);
#elif defined(CONFIG_SYS_NS16550_MEM32) && defined(CONFIG_SYS_BIG_ENDIAN)
@@ -253,7 +253,7 @@ static int ns16550_serial_getc(struct udevice *dev)
{
struct NS16550 *const com_port = dev_get_priv(dev);
- if (!serial_in(&com_port->lsr) & UART_LSR_DR)
+ if (!(serial_in(&com_port->lsr) & UART_LSR_DR))
return -EAGAIN;
return serial_in(&com_port->rbr);
@@ -276,14 +276,15 @@ int ns16550_serial_probe(struct udevice *dev)
{
struct NS16550 *const com_port = dev_get_priv(dev);
+ com_port->plat = dev_get_platdata(dev);
NS16550_init(com_port, -1);
return 0;
}
+#ifdef CONFIG_OF_CONTROL
int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
{
- struct NS16550 *const com_port = dev_get_priv(dev);
struct ns16550_platdata *plat = dev->platdata;
fdt_addr_t addr;
@@ -291,13 +292,13 @@ int ns16550_serial_ofdata_to_platdata(struct udevice *dev)
if (addr == FDT_ADDR_T_NONE)
return -EINVAL;
- plat->base = (unsigned char *)addr;
+ plat->base = addr;
plat->reg_shift = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
"reg-shift", 1);
- com_port->plat = plat;
return 0;
}
+#endif
const struct dm_serial_ops ns16550_serial_ops = {
.putc = ns16550_serial_putc,
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index 6dde4ea..71f1a5c 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -11,9 +11,12 @@
#include <os.h>
#include <serial.h>
#include <stdio_dev.h>
+#include <watchdog.h>
#include <dm/lists.h>
#include <dm/device-internal.h>
+#include <ns16550.h>
+
DECLARE_GLOBAL_DATA_PTR;
/* The currently-selected console serial device */
@@ -47,13 +50,22 @@ static void serial_find_console_or_panic(void)
}
#endif
/*
+ * Try to use CONFIG_CONS_INDEX if available (it is numbered from 1!).
+ *
* Failing that, get the device with sequence number 0, or in extremis
* just the first serial device we can find. But we insist on having
* a console (even if it is silent).
*/
- if (uclass_get_device_by_seq(UCLASS_SERIAL, 0, &cur_dev) &&
+#ifdef CONFIG_CONS_INDEX
+#define INDEX (CONFIG_CONS_INDEX - 1)
+#else
+#define INDEX 0
+#endif
+ if (uclass_get_device_by_seq(UCLASS_SERIAL, INDEX, &cur_dev) &&
+ uclass_get_device(UCLASS_SERIAL, INDEX, &cur_dev) &&
(uclass_first_device(UCLASS_SERIAL, &cur_dev) || !cur_dev))
panic("No serial driver found");
+#undef INDEX
}
/* Called prior to relocation */
@@ -71,95 +83,98 @@ void serial_initialize(void)
serial_find_console_or_panic();
}
-void serial_putc(char ch)
+static void _serial_putc(struct udevice *dev, char ch)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+ struct dm_serial_ops *ops = serial_get_ops(dev);
int err;
do {
- err = ops->putc(cur_dev, ch);
+ err = ops->putc(dev, ch);
} while (err == -EAGAIN);
if (ch == '\n')
- serial_putc('\r');
+ _serial_putc(dev, '\r');
}
-void serial_setbrg(void)
+static void _serial_puts(struct udevice *dev, const char *str)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
-
- if (ops->setbrg)
- ops->setbrg(cur_dev, gd->baudrate);
+ while (*str)
+ _serial_putc(dev, *str++);
}
-void serial_puts(const char *str)
+static int _serial_getc(struct udevice *dev)
{
- while (*str)
- serial_putc(*str++);
+ struct dm_serial_ops *ops = serial_get_ops(dev);
+ int err;
+
+ do {
+ err = ops->getc(dev);
+ if (err == -EAGAIN)
+ WATCHDOG_RESET();
+ } while (err == -EAGAIN);
+
+ return err >= 0 ? err : 0;
}
-int serial_tstc(void)
+static int _serial_tstc(struct udevice *dev)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+ struct dm_serial_ops *ops = serial_get_ops(dev);
if (ops->pending)
- return ops->pending(cur_dev, true);
+ return ops->pending(dev, true);
return 1;
}
+void serial_putc(char ch)
+{
+ _serial_putc(cur_dev, ch);
+}
+
+void serial_puts(const char *str)
+{
+ _serial_puts(cur_dev, str);
+}
+
int serial_getc(void)
{
- struct dm_serial_ops *ops = serial_get_ops(cur_dev);
- int err;
+ return _serial_getc(cur_dev);
+}
- do {
- err = ops->getc(cur_dev);
- } while (err == -EAGAIN);
+int serial_tstc(void)
+{
+ return _serial_tstc(cur_dev);
+}
- return err >= 0 ? err : 0;
+void serial_setbrg(void)
+{
+ struct dm_serial_ops *ops = serial_get_ops(cur_dev);
+
+ if (ops->setbrg)
+ ops->setbrg(cur_dev, gd->baudrate);
}
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(sdev->priv, ch);
}
void serial_stub_puts(struct stdio_dev *sdev, const char *str)
{
- while (*str)
- serial_stub_putc(sdev, *str++);
+ _serial_puts(sdev->priv, 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(sdev->priv);
}
int serial_stub_tstc(struct stdio_dev *sdev)
{
- struct udevice *dev = sdev->priv;
- struct dm_serial_ops *ops = serial_get_ops(dev);
-
- if (ops->pending)
- return ops->pending(dev, true);
-
- return 1;
+ return _serial_tstc(sdev->priv);
}
static int serial_post_probe(struct udevice *dev)
diff --git a/drivers/serial/serial.c b/drivers/serial/serial.c
index 82fbbd9..18e41b2 100644
--- a/drivers/serial/serial.c
+++ b/drivers/serial/serial.c
@@ -157,7 +157,6 @@ serial_initfunc(sh_serial_initialize);
serial_initfunc(arm_dcc_initialize);
serial_initfunc(mxs_auart_initialize);
serial_initfunc(arc_serial_initialize);
-serial_initfunc(uniphier_serial_initialize);
/**
* serial_register() - Register serial driver with serial driver core
@@ -251,33 +250,32 @@ void serial_initialize(void)
arm_dcc_initialize();
mxs_auart_initialize();
arc_serial_initialize();
- uniphier_serial_initialize();
serial_assign(default_serial_console()->name);
}
-int serial_stub_start(struct stdio_dev *sdev)
+static int serial_stub_start(struct stdio_dev *sdev)
{
struct serial_device *dev = sdev->priv;
return dev->start();
}
-int serial_stub_stop(struct stdio_dev *sdev)
+static int serial_stub_stop(struct stdio_dev *sdev)
{
struct serial_device *dev = sdev->priv;
return dev->stop();
}
-void serial_stub_putc(struct stdio_dev *sdev, const char ch)
+static void serial_stub_putc(struct stdio_dev *sdev, const char ch)
{
struct serial_device *dev = sdev->priv;
dev->putc(ch);
}
-void serial_stub_puts(struct stdio_dev *sdev, const char *str)
+static void serial_stub_puts(struct stdio_dev *sdev, const char *str)
{
struct serial_device *dev = sdev->priv;
diff --git a/drivers/serial/serial_coreboot.c b/drivers/serial/serial_coreboot.c
new file mode 100644
index 0000000..5c6a76c
--- /dev/null
+++ b/drivers/serial/serial_coreboot.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ns16550.h>
+#include <serial.h>
+
+static const struct udevice_id coreboot_serial_ids[] = {
+ { .compatible = "coreboot-uart" },
+ { }
+};
+
+static int coreboot_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ns16550_platdata *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = ns16550_serial_ofdata_to_platdata(dev);
+ if (ret)
+ return ret;
+ plat->clock = 1843200;
+
+ return 0;
+}
+U_BOOT_DRIVER(serial_ns16550) = {
+ .name = "serial_coreboot",
+ .id = UCLASS_SERIAL,
+ .of_match = coreboot_serial_ids,
+ .ofdata_to_platdata = coreboot_serial_ofdata_to_platdata,
+ .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .probe = ns16550_serial_probe,
+ .ops = &ns16550_serial_ops,
+};
diff --git a/drivers/serial/serial_mxc.c b/drivers/serial/serial_mxc.c
index 313d560..d6cf1d8 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 <watchdog.h>
#include <asm/arch/imx-regs.h>
#include <asm/arch/clock.h>
+#include <dm/platform_data/serial_mxc.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_ns16550.c b/drivers/serial/serial_ns16550.c
index 632da4c..799ef6a 100644
--- a/drivers/serial/serial_ns16550.c
+++ b/drivers/serial/serial_ns16550.c
@@ -119,8 +119,7 @@ static NS16550_t serial_ports[6] = {
.puts = eserial##port##_puts, \
}
-void
-_serial_putc(const char c,const int port)
+static void _serial_putc(const char c, const int port)
{
if (c == '\n')
NS16550_putc(PORT, '\r');
@@ -128,35 +127,29 @@ _serial_putc(const char c,const int port)
NS16550_putc(PORT, c);
}
-void
-_serial_putc_raw(const char c,const int port)
+static void _serial_putc_raw(const char c, const int port)
{
NS16550_putc(PORT, c);
}
-void
-_serial_puts (const char *s,const int port)
+static void _serial_puts(const char *s, const int port)
{
while (*s) {
- _serial_putc (*s++,port);
+ _serial_putc(*s++, port);
}
}
-
-int
-_serial_getc(const int port)
+static int _serial_getc(const int port)
{
return NS16550_getc(PORT);
}
-int
-_serial_tstc(const int port)
+static int _serial_tstc(const int port)
{
return NS16550_tstc(PORT);
}
-void
-_serial_setbrg (const int port)
+static void _serial_setbrg(const int port)
{
int clock_divisor;
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
new file mode 100644
index 0000000..265fe00
--- /dev/null
+++ b/drivers/serial/serial_omap.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <ns16550.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_OF_CONTROL
+static const struct udevice_id omap_serial_ids[] = {
+ { .compatible = "ti,omap3-uart" },
+ { }
+};
+
+static int omap_serial_ofdata_to_platdata(struct udevice *dev)
+{
+ struct ns16550_platdata *plat = dev_get_platdata(dev);
+ int ret;
+
+ ret = ns16550_serial_ofdata_to_platdata(dev);
+ if (ret)
+ return ret;
+ plat->clock = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+ "clock-frequency", -1);
+ plat->reg_shift = 2;
+
+ return 0;
+}
+#endif
+
+U_BOOT_DRIVER(serial_omap_ns16550) = {
+ .name = "serial_omap",
+ .id = UCLASS_SERIAL,
+ .of_match = of_match_ptr(omap_serial_ids),
+ .ofdata_to_platdata = of_match_ptr(omap_serial_ofdata_to_platdata),
+ .platdata_auto_alloc_size = sizeof(struct ns16550_platdata),
+ .priv_auto_alloc_size = sizeof(struct NS16550),
+ .probe = ns16550_serial_probe,
+ .ops = &ns16550_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/serial/serial_pl01x.c b/drivers/serial/serial_pl01x.c
index dfb610e..38dda91 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 <dm/platform_data/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 288a4f1..288a4f1 100644
--- a/drivers/serial/serial_pl01x.h
+++ b/drivers/serial/serial_pl01x_internal.h
diff --git a/drivers/serial/serial_s3c24x0.c b/drivers/serial/serial_s3c24x0.c
index c07f4c9..7afc504 100644
--- a/drivers/serial/serial_s3c24x0.c
+++ b/drivers/serial/serial_s3c24x0.c
@@ -69,7 +69,7 @@ DECLARE_GLOBAL_DATA_PTR;
static int hwflow;
#endif
-void _serial_setbrg(const int dev_index)
+static void _serial_setbrg(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
unsigned int reg = 0;
@@ -131,7 +131,7 @@ static int serial_init_dev(const int dev_index)
* otherwise. When the function is succesfull, the character read is
* written into its argument c.
*/
-int _serial_getc(const int dev_index)
+static int _serial_getc(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
@@ -181,7 +181,7 @@ void enable_putc(void)
/*
* Output a single byte to the serial port.
*/
-void _serial_putc(const char c, const int dev_index)
+static void _serial_putc(const char c, const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
#ifdef CONFIG_MODEM_SUPPORT
@@ -212,7 +212,7 @@ static inline void serial_putc_dev(unsigned int dev_index, const char c)
/*
* Test whether a character is in the RX buffer
*/
-int _serial_tstc(const int dev_index)
+static int _serial_tstc(const int dev_index)
{
struct s3c24x0_uart *uart = s3c24x0_get_base_uart(dev_index);
@@ -224,7 +224,7 @@ static inline int serial_tstc_dev(unsigned int dev_index)
return _serial_tstc(dev_index);
}
-void _serial_puts(const char *s, const int dev_index)
+static void _serial_puts(const char *s, const int dev_index)
{
while (*s) {
_serial_putc(*s++, dev_index);
diff --git a/drivers/serial/serial_s5p.c b/drivers/serial/serial_s5p.c
index 98c62b4..8469afd 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,
+};
diff --git a/drivers/serial/serial_sh.c b/drivers/serial/serial_sh.c
index 144a925..7c1f271 100644
--- a/drivers/serial/serial_sh.c
+++ b/drivers/serial/serial_sh.c
@@ -122,7 +122,7 @@ static void handle_error(void)
sci_out(&sh_sci, SCLSR, 0x00);
}
-void serial_raw_putc(const char c)
+static void serial_raw_putc(const char c)
{
while (1) {
/* Tx fifo is empty */
@@ -152,7 +152,7 @@ static int sh_serial_tstc(void)
}
-int serial_getc_check(void)
+static int serial_getc_check(void)
{
unsigned short status;
diff --git a/drivers/serial/serial_uniphier.c b/drivers/serial/serial_uniphier.c
index f8c9d92..9114b3e 100644
--- a/drivers/serial/serial_uniphier.c
+++ b/drivers/serial/serial_uniphier.c
@@ -2,14 +2,14 @@
* Copyright (C) 2012-2014 Panasonic Corporation
* Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
*
- * Based on serial_ns16550.c
- * (C) Copyright 2000
- * Rob Taylor, Flying Pig Systems. robt@flyingpig.com.
- *
* SPDX-License-Identifier: GPL-2.0+
*/
#include <common.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <dm/device.h>
+#include <dm/platform_data/serial-uniphier.h>
#include <serial.h>
#define UART_REG(x) \
@@ -48,157 +48,104 @@ struct uniphier_serial {
#define UART_LSR_DR 0x01 /* Data ready */
#define UART_LSR_THRE 0x20 /* Xmit holding register empty */
-DECLARE_GLOBAL_DATA_PTR;
+struct uniphier_serial_private_data {
+ struct uniphier_serial __iomem *membase;
+};
+
+#define uniphier_serial_port(dev) \
+ ((struct uniphier_serial_private_data *)dev_get_priv(dev))->membase
-static void uniphier_serial_init(struct uniphier_serial *port)
+int uniphier_serial_setbrg(struct udevice *dev, int baudrate)
{
+ struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
const unsigned int mode_x_div = 16;
unsigned int divisor;
writeb(UART_LCR_WLS_8, &port->lcr);
- divisor = DIV_ROUND_CLOSEST(CONFIG_SYS_UNIPHIER_UART_CLK,
- mode_x_div * gd->baudrate);
+ divisor = DIV_ROUND_CLOSEST(plat->uartclk, mode_x_div * baudrate);
writew(divisor, &port->dlr);
-}
-static void uniphier_serial_setbrg(struct uniphier_serial *port)
-{
- uniphier_serial_init(port);
+ return 0;
}
-static int uniphier_serial_tstc(struct uniphier_serial *port)
+static int uniphier_serial_getc(struct udevice *dev)
{
- return (readb(&port->lsr) & UART_LSR_DR) != 0;
-}
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
-static int uniphier_serial_getc(struct uniphier_serial *port)
-{
- while (!uniphier_serial_tstc(port))
- ;
+ if (!(readb(&port->lsr) & UART_LSR_DR))
+ return -EAGAIN;
return readb(&port->rbr);
}
-static void uniphier_serial_putc(struct uniphier_serial *port, const char c)
+static int uniphier_serial_putc(struct udevice *dev, const char c)
{
- if (c == '\n')
- uniphier_serial_putc(port, '\r');
+ struct uniphier_serial __iomem *port = uniphier_serial_port(dev);
- while (!(readb(&port->lsr) & UART_LSR_THRE))
- ;
+ if (!(readb(&port->lsr) & UART_LSR_THRE))
+ return -EAGAIN;
writeb(c, &port->thr);
+
+ return 0;
}
-static struct uniphier_serial *serial_ports[4] = {
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE0
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE0,
-#else
- NULL,
-#endif
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE1
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE1,
-#else
- NULL,
-#endif
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE2
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE2,
-#else
- NULL,
-#endif
-#ifdef CONFIG_SYS_UNIPHIER_SERIAL_BASE3
- (struct uniphier_serial *)CONFIG_SYS_UNIPHIER_SERIAL_BASE3,
-#else
- NULL,
-#endif
-};
+int uniphier_serial_probe(struct udevice *dev)
+{
+ struct uniphier_serial_private_data *priv = dev_get_priv(dev);
+ struct uniphier_serial_platform_data *plat = dev_get_platdata(dev);
-/* Multi serial device functions */
-#define DECLARE_ESERIAL_FUNCTIONS(port) \
- static int eserial##port##_init(void) \
- { \
- uniphier_serial_init(serial_ports[port]); \
- return 0 ; \
- } \
- static void eserial##port##_setbrg(void) \
- { \
- uniphier_serial_setbrg(serial_ports[port]); \
- } \
- static int eserial##port##_getc(void) \
- { \
- return uniphier_serial_getc(serial_ports[port]); \
- } \
- static int eserial##port##_tstc(void) \
- { \
- return uniphier_serial_tstc(serial_ports[port]); \
- } \
- static void eserial##port##_putc(const char c) \
- { \
- uniphier_serial_putc(serial_ports[port], c); \
- }
-
-/* Serial device descriptor */
-#define INIT_ESERIAL_STRUCTURE(port, __name) { \
- .name = __name, \
- .start = eserial##port##_init, \
- .stop = NULL, \
- .setbrg = eserial##port##_setbrg, \
- .getc = eserial##port##_getc, \
- .tstc = eserial##port##_tstc, \
- .putc = eserial##port##_putc, \
- .puts = default_serial_puts, \
-}
+ priv->membase = map_sysmem(plat->base, sizeof(struct uniphier_serial));
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
-DECLARE_ESERIAL_FUNCTIONS(0);
-struct serial_device uniphier_serial0_device =
- INIT_ESERIAL_STRUCTURE(0, "ttyS0");
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
-DECLARE_ESERIAL_FUNCTIONS(1);
-struct serial_device uniphier_serial1_device =
- INIT_ESERIAL_STRUCTURE(1, "ttyS1");
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
-DECLARE_ESERIAL_FUNCTIONS(2);
-struct serial_device uniphier_serial2_device =
- INIT_ESERIAL_STRUCTURE(2, "ttyS2");
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
-DECLARE_ESERIAL_FUNCTIONS(3);
-struct serial_device uniphier_serial3_device =
- INIT_ESERIAL_STRUCTURE(3, "ttyS3");
-#endif
+ if (!priv->membase)
+ return -ENOMEM;
-__weak struct serial_device *default_serial_console(void)
+ return 0;
+}
+
+int uniphier_serial_remove(struct udevice *dev)
{
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
- return &uniphier_serial0_device;
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
- return &uniphier_serial1_device;
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
- return &uniphier_serial2_device;
-#elif defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
- return &uniphier_serial3_device;
-#else
-#error "No uniphier serial ports configured."
-#endif
+ unmap_sysmem(uniphier_serial_port(dev));
+
+ return 0;
}
-void uniphier_serial_initialize(void)
+#ifdef CONFIG_OF_CONTROL
+static const struct udevice_id uniphier_uart_of_match = {
+ { .compatible = "panasonic,uniphier-uart"},
+ {},
+};
+
+static int uniphier_serial_ofdata_to_platdata(struct udevice *dev)
{
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE0)
- serial_register(&uniphier_serial0_device);
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE1)
- serial_register(&uniphier_serial1_device);
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE2)
- serial_register(&uniphier_serial2_device);
-#endif
-#if defined(CONFIG_SYS_UNIPHIER_SERIAL_BASE3)
- serial_register(&uniphier_serial3_device);
-#endif
+ /*
+ * TODO: Masahiro Yamada (yamada.m@jp.panasonic.com)
+ *
+ * Implement conversion code from DTB to platform data
+ * when supporting CONFIG_OF_CONTROL on UniPhir platform.
+ */
}
+#endif
+
+static const struct dm_serial_ops uniphier_serial_ops = {
+ .setbrg = uniphier_serial_setbrg,
+ .getc = uniphier_serial_getc,
+ .putc = uniphier_serial_putc,
+};
+
+U_BOOT_DRIVER(uniphier_serial) = {
+ .name = DRIVER_NAME,
+ .id = UCLASS_SERIAL,
+ .of_match = of_match_ptr(uniphier_uart_of_match),
+ .ofdata_to_platdata = of_match_ptr(uniphier_serial_ofdata_to_platdata),
+ .probe = uniphier_serial_probe,
+ .remove = uniphier_serial_remove,
+ .priv_auto_alloc_size = sizeof(struct uniphier_serial_private_data),
+ .platdata_auto_alloc_size =
+ sizeof(struct uniphier_serial_platform_data),
+ .ops = &uniphier_serial_ops,
+ .flags = DM_FLAG_PRE_RELOC,
+};