summaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorTomasz Figa <t.figa@samsung.com>2015-01-23 14:47:41 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-02-02 10:11:26 -0800
commitb94ba0328d3b36ff95f5074c0e9b44f90dc56bb5 (patch)
tree644790b8e5dcf1705dfb6dc6e80d352fbed9d338 /drivers/tty
parent8b6ff84c2d445a476be5f5493b9deac00271eedd (diff)
serial: samsung: Add support for early console
This patch adds support for early console initialized from device tree and kernel command line to all variants of Samsung serial driver. Signed-off-by: Tomasz Figa <t.figa@samsung.com> [mszyprow: added support for command line based initialization, fixed comments, added documentation] Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com> Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com> Tested-by: Alim Akhtar <alim.akhtar@samsung.com> Tested-by: Chanwoo Choi <cw00.choi@samsung.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/Kconfig1
-rw-r--r--drivers/tty/serial/samsung.c103
2 files changed, 104 insertions, 0 deletions
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 35677f75a1d..c63317e87c3 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -241,6 +241,7 @@ config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
+ select SERIAL_EARLYCON
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 024e5ecee98..a6bef8dcdc3 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -2403,6 +2403,109 @@ static struct platform_driver samsung_serial_driver = {
module_platform_driver(samsung_serial_driver);
+/*
+ * Early console.
+ */
+
+struct samsung_early_console_data {
+ u32 txfull_mask;
+};
+
+static void samsung_early_busyuart(struct uart_port *port)
+{
+ while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
+ ;
+}
+
+static void samsung_early_busyuart_fifo(struct uart_port *port)
+{
+ struct samsung_early_console_data *data = port->private_data;
+
+ while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
+ ;
+}
+
+static void samsung_early_putc(struct uart_port *port, int c)
+{
+ if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+ samsung_early_busyuart_fifo(port);
+ else
+ samsung_early_busyuart(port);
+
+ writeb(c, port->membase + S3C2410_UTXH);
+}
+
+static void samsung_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, samsung_early_putc);
+}
+
+static int __init samsung_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = samsung_early_write;
+ return 0;
+}
+
+/* S3C2410 */
+static struct samsung_early_console_data s3c2410_early_console_data = {
+ .txfull_mask = S3C2410_UFSTAT_TXFULL,
+};
+
+static int __init s3c2410_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s3c2410_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
+ s3c2410_early_console_setup);
+EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
+
+/* S3C2412, S3C2440, S3C64xx */
+static struct samsung_early_console_data s3c2440_early_console_data = {
+ .txfull_mask = S3C2440_UFSTAT_TXFULL,
+};
+
+static int __init s3c2440_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s3c2440_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
+ s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
+ s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
+ s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
+
+/* S5PV210, EXYNOS */
+static struct samsung_early_console_data s5pv210_early_console_data = {
+ .txfull_mask = S5PV210_UFSTAT_TXFULL,
+};
+
+static int __init s5pv210_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s5pv210_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
+ s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
+ s5pv210_early_console_setup);
+EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
+EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
+
MODULE_ALIAS("platform:samsung-uart");
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");