diff options
Diffstat (limited to 'drivers/tty/serial/meson_uart.c')
-rw-r--r-- | drivers/tty/serial/meson_uart.c | 72 |
1 files changed, 67 insertions, 5 deletions
diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index fbc5bc022a39..d2c08b760f83 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -5,15 +5,12 @@ * Copyright (C) 2014 Carlo Caione <carlo@caione.org> */ -#if defined(CONFIG_SERIAL_MESON_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/clk.h> #include <linux/console.h> #include <linux/delay.h> #include <linux/init.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/of.h> @@ -76,6 +73,8 @@ #define AML_UART_PORT_OFFSET 6 #define AML_UART_DEV_NAME "ttyAML" +#define AML_UART_POLL_USEC 5 +#define AML_UART_TIMEOUT_USEC 10000 static struct uart_driver meson_uart_driver; @@ -411,7 +410,7 @@ static int meson_uart_request_port(struct uart_port *port) return -EBUSY; } - port->membase = devm_ioremap_nocache(port->dev, port->mapbase, + port->membase = devm_ioremap(port->dev, port->mapbase, port->mapsize); if (!port->membase) return -ENOMEM; @@ -427,6 +426,64 @@ static void meson_uart_config_port(struct uart_port *port, int flags) } } +#ifdef CONFIG_CONSOLE_POLL +/* + * Console polling routines for writing and reading from the uart while + * in an interrupt or debug context (i.e. kgdb). + */ + +static int meson_uart_poll_get_char(struct uart_port *port) +{ + u32 c; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + if (readl(port->membase + AML_UART_STATUS) & AML_UART_RX_EMPTY) + c = NO_POLL_CHAR; + else + c = readl(port->membase + AML_UART_RFIFO); + + spin_unlock_irqrestore(&port->lock, flags); + + return c; +} + +static void meson_uart_poll_put_char(struct uart_port *port, unsigned char c) +{ + unsigned long flags; + u32 reg; + int ret; + + spin_lock_irqsave(&port->lock, flags); + + /* Wait until FIFO is empty or timeout */ + ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg, + reg & AML_UART_TX_EMPTY, + AML_UART_POLL_USEC, + AML_UART_TIMEOUT_USEC); + if (ret == -ETIMEDOUT) { + dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n"); + goto out; + } + + /* Write the character */ + writel(c, port->membase + AML_UART_WFIFO); + + /* Wait until FIFO is empty or timeout */ + ret = readl_poll_timeout_atomic(port->membase + AML_UART_STATUS, reg, + reg & AML_UART_TX_EMPTY, + AML_UART_POLL_USEC, + AML_UART_TIMEOUT_USEC); + if (ret == -ETIMEDOUT) + dev_err(port->dev, "Timeout waiting for UART TX EMPTY\n"); + +out: + spin_unlock_irqrestore(&port->lock, flags); +} + +#endif /* CONFIG_CONSOLE_POLL */ + static const struct uart_ops meson_uart_ops = { .set_mctrl = meson_uart_set_mctrl, .get_mctrl = meson_uart_get_mctrl, @@ -442,6 +499,10 @@ static const struct uart_ops meson_uart_ops = { .request_port = meson_uart_request_port, .release_port = meson_uart_release_port, .verify_port = meson_uart_verify_port, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = meson_uart_poll_get_char, + .poll_put_char = meson_uart_poll_put_char, +#endif }; #ifdef CONFIG_SERIAL_MESON_CONSOLE @@ -703,6 +764,7 @@ static int meson_uart_probe(struct platform_device *pdev) port->mapsize = resource_size(res_mem); port->irq = res_irq->start; port->flags = UPF_BOOT_AUTOCONF | UPF_LOW_LATENCY; + port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_MESON_CONSOLE); port->dev = &pdev->dev; port->line = pdev->id; port->type = PORT_MESON; |