From fc60a8b675bd9499c71716d21c238eed5092ddfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20F=C3=A4rber?= Date: Sun, 9 Jul 2017 22:29:42 +0200 Subject: tty: serial: owl: Implement console driver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement serial console driver to complement earlycon. Based on LeMaker linux-actions tree. Signed-off-by: Andreas Färber Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 4 +- drivers/tty/serial/owl-uart.c | 635 ++++++++++++++++++++++++++++++++++++++- include/uapi/linux/serial_core.h | 1 + 3 files changed, 636 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 1f096e2..b788fee 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1689,7 +1689,7 @@ config SERIAL_MVEBU_CONSOLE Otherwise, say 'N'. config SERIAL_OWL - bool "Actions Semi Owl serial port support" + tristate "Actions Semi Owl serial port support" depends on ARCH_ACTIONS || COMPILE_TEST select SERIAL_CORE help @@ -1705,7 +1705,7 @@ config SERIAL_OWL_CONSOLE default y help Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART - as the system console. Only earlycon is implemented currently. + as the system console. endmenu diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 1b80087..683b054 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -20,6 +20,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -28,22 +29,66 @@ #include #include #include +#include +#include + +#define OWL_UART_PORT_NUM 7 +#define OWL_UART_DEV_NAME "ttyOWL" #define OWL_UART_CTL 0x000 +#define OWL_UART_RXDAT 0x004 #define OWL_UART_TXDAT 0x008 #define OWL_UART_STAT 0x00c +#define OWL_UART_CTL_DWLS_MASK GENMASK(1, 0) +#define OWL_UART_CTL_DWLS_5BITS (0x0 << 0) +#define OWL_UART_CTL_DWLS_6BITS (0x1 << 0) +#define OWL_UART_CTL_DWLS_7BITS (0x2 << 0) +#define OWL_UART_CTL_DWLS_8BITS (0x3 << 0) +#define OWL_UART_CTL_STPS_2BITS BIT(2) +#define OWL_UART_CTL_PRS_MASK GENMASK(6, 4) +#define OWL_UART_CTL_PRS_NONE (0x0 << 4) +#define OWL_UART_CTL_PRS_ODD (0x4 << 4) +#define OWL_UART_CTL_PRS_MARK (0x5 << 4) +#define OWL_UART_CTL_PRS_EVEN (0x6 << 4) +#define OWL_UART_CTL_PRS_SPACE (0x7 << 4) +#define OWL_UART_CTL_AFE BIT(12) #define OWL_UART_CTL_TRFS_TX BIT(14) #define OWL_UART_CTL_EN BIT(15) +#define OWL_UART_CTL_RXDE BIT(16) +#define OWL_UART_CTL_TXDE BIT(17) #define OWL_UART_CTL_RXIE BIT(18) #define OWL_UART_CTL_TXIE BIT(19) +#define OWL_UART_CTL_LBEN BIT(20) #define OWL_UART_STAT_RIP BIT(0) #define OWL_UART_STAT_TIP BIT(1) +#define OWL_UART_STAT_RXER BIT(2) +#define OWL_UART_STAT_TFER BIT(3) +#define OWL_UART_STAT_RXST BIT(4) +#define OWL_UART_STAT_RFEM BIT(5) #define OWL_UART_STAT_TFFU BIT(6) -#define OWL_UART_STAT_TRFL_MASK (0x1f << 11) +#define OWL_UART_STAT_CTSS BIT(7) +#define OWL_UART_STAT_RTSS BIT(8) +#define OWL_UART_STAT_TFES BIT(10) +#define OWL_UART_STAT_TRFL_MASK GENMASK(16, 11) #define OWL_UART_STAT_UTBB BIT(17) +static struct uart_driver owl_uart_driver; + +struct owl_uart_info { + unsigned int tx_fifosize; +}; + +struct owl_uart_port { + struct uart_port port; + struct clk *clk; +}; + +#define to_owl_uart_port(prt) container_of(prt, struct owl_uart_port, prt) + +static struct owl_uart_port *owl_uart_ports[OWL_UART_PORT_NUM]; + static inline void owl_uart_write(struct uart_port *port, u32 val, unsigned int off) { writel(val, port->membase + off); @@ -54,6 +99,397 @@ static inline u32 owl_uart_read(struct uart_port *port, unsigned int off) return readl(port->membase + off); } +static void owl_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u32 ctl; + + ctl = owl_uart_read(port, OWL_UART_CTL); + + if (mctrl & TIOCM_LOOP) + ctl |= OWL_UART_CTL_LBEN; + else + ctl &= ~OWL_UART_CTL_LBEN; + + owl_uart_write(port, ctl, OWL_UART_CTL); +} + +static unsigned int owl_uart_get_mctrl(struct uart_port *port) +{ + unsigned int mctrl = TIOCM_CAR | TIOCM_DSR; + u32 stat, ctl; + + ctl = owl_uart_read(port, OWL_UART_CTL); + stat = owl_uart_read(port, OWL_UART_STAT); + if (stat & OWL_UART_STAT_RTSS) + mctrl |= TIOCM_RTS; + if ((stat & OWL_UART_STAT_CTSS) || !(ctl & OWL_UART_CTL_AFE)) + mctrl |= TIOCM_CTS; + return mctrl; +} + +static unsigned int owl_uart_tx_empty(struct uart_port *port) +{ + unsigned long flags; + u32 val; + unsigned int ret; + + spin_lock_irqsave(&port->lock, flags); + + val = owl_uart_read(port, OWL_UART_STAT); + ret = (val & OWL_UART_STAT_TFES) ? TIOCSER_TEMT : 0; + + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +static void owl_uart_stop_rx(struct uart_port *port) +{ + u32 val; + + val = owl_uart_read(port, OWL_UART_CTL); + val &= ~(OWL_UART_CTL_RXIE | OWL_UART_CTL_RXDE); + owl_uart_write(port, val, OWL_UART_CTL); + + val = owl_uart_read(port, OWL_UART_STAT); + val |= OWL_UART_STAT_RIP; + owl_uart_write(port, val, OWL_UART_STAT); +} + +static void owl_uart_stop_tx(struct uart_port *port) +{ + u32 val; + + val = owl_uart_read(port, OWL_UART_CTL); + val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_TXDE); + owl_uart_write(port, val, OWL_UART_CTL); + + val = owl_uart_read(port, OWL_UART_STAT); + val |= OWL_UART_STAT_TIP; + owl_uart_write(port, val, OWL_UART_STAT); +} + +static void owl_uart_start_tx(struct uart_port *port) +{ + u32 val; + + if (uart_tx_stopped(port)) { + owl_uart_stop_tx(port); + return; + } + + val = owl_uart_read(port, OWL_UART_STAT); + val |= OWL_UART_STAT_TIP; + owl_uart_write(port, val, OWL_UART_STAT); + + val = owl_uart_read(port, OWL_UART_CTL); + val |= OWL_UART_CTL_TXIE; + owl_uart_write(port, val, OWL_UART_CTL); +} + +static void owl_uart_send_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int ch; + + if (uart_tx_stopped(port)) + return; + + if (port->x_char) { + while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) + cpu_relax(); + owl_uart_write(port, port->x_char, OWL_UART_TXDAT); + port->icount.tx++; + port->x_char = 0; + } + + while (!(owl_uart_read(port, OWL_UART_STAT) & OWL_UART_STAT_TFFU)) { + if (uart_circ_empty(xmit)) + break; + + ch = xmit->buf[xmit->tail]; + owl_uart_write(port, ch, OWL_UART_TXDAT); + xmit->tail = (xmit->tail + 1) & (SERIAL_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + owl_uart_stop_tx(port); +} + +static void owl_uart_receive_chars(struct uart_port *port) +{ + u32 stat, val; + + val = owl_uart_read(port, OWL_UART_CTL); + val &= ~OWL_UART_CTL_TRFS_TX; + owl_uart_write(port, val, OWL_UART_CTL); + + stat = owl_uart_read(port, OWL_UART_STAT); + while (!(stat & OWL_UART_STAT_RFEM)) { + char flag = TTY_NORMAL; + + if (stat & OWL_UART_STAT_RXER) + port->icount.overrun++; + + if (stat & OWL_UART_STAT_RXST) { + /* We are not able to distinguish the error type. */ + port->icount.brk++; + port->icount.frame++; + + stat &= port->read_status_mask; + if (stat & OWL_UART_STAT_RXST) + flag = TTY_PARITY; + } else + port->icount.rx++; + + val = owl_uart_read(port, OWL_UART_RXDAT); + val &= 0xff; + + if ((stat & port->ignore_status_mask) == 0) + tty_insert_flip_char(&port->state->port, val, flag); + + stat = owl_uart_read(port, OWL_UART_STAT); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); +} + +static irqreturn_t owl_uart_irq(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned long flags; + u32 stat; + + spin_lock_irqsave(&port->lock, flags); + + stat = owl_uart_read(port, OWL_UART_STAT); + + if (stat & OWL_UART_STAT_RIP) + owl_uart_receive_chars(port); + + if (stat & OWL_UART_STAT_TIP) + owl_uart_send_chars(port); + + stat = owl_uart_read(port, OWL_UART_STAT); + stat |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP; + owl_uart_write(port, stat, OWL_UART_STAT); + + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; +} + +static void owl_uart_shutdown(struct uart_port *port) +{ + u32 val; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + val = owl_uart_read(port, OWL_UART_CTL); + val &= ~(OWL_UART_CTL_TXIE | OWL_UART_CTL_RXIE + | OWL_UART_CTL_TXDE | OWL_UART_CTL_RXDE | OWL_UART_CTL_EN); + owl_uart_write(port, val, OWL_UART_CTL); + + spin_unlock_irqrestore(&port->lock, flags); + + free_irq(port->irq, port); +} + +static int owl_uart_startup(struct uart_port *port) +{ + u32 val; + unsigned long flags; + int ret; + + ret = request_irq(port->irq, owl_uart_irq, IRQF_TRIGGER_HIGH, + "owl-uart", port); + if (ret) + return ret; + + spin_lock_irqsave(&port->lock, flags); + + val = owl_uart_read(port, OWL_UART_STAT); + val |= OWL_UART_STAT_RIP | OWL_UART_STAT_TIP + | OWL_UART_STAT_RXER | OWL_UART_STAT_TFER | OWL_UART_STAT_RXST; + owl_uart_write(port, val, OWL_UART_STAT); + + val = owl_uart_read(port, OWL_UART_CTL); + val |= OWL_UART_CTL_RXIE | OWL_UART_CTL_TXIE; + val |= OWL_UART_CTL_EN; + owl_uart_write(port, val, OWL_UART_CTL); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void owl_uart_change_baudrate(struct owl_uart_port *owl_port, + unsigned long baud) +{ + clk_set_rate(owl_port->clk, baud * 8); +} + +static void owl_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct owl_uart_port *owl_port = to_owl_uart_port(port); + unsigned int baud; + u32 ctl; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + ctl = owl_uart_read(port, OWL_UART_CTL); + + ctl &= ~OWL_UART_CTL_DWLS_MASK; + switch (termios->c_cflag & CSIZE) { + case CS5: + ctl |= OWL_UART_CTL_DWLS_5BITS; + break; + case CS6: + ctl |= OWL_UART_CTL_DWLS_6BITS; + break; + case CS7: + ctl |= OWL_UART_CTL_DWLS_7BITS; + break; + case CS8: + default: + ctl |= OWL_UART_CTL_DWLS_8BITS; + break; + } + + if (termios->c_cflag & CSTOPB) + ctl |= OWL_UART_CTL_STPS_2BITS; + else + ctl &= ~OWL_UART_CTL_STPS_2BITS; + + ctl &= ~OWL_UART_CTL_PRS_MASK; + if (termios->c_cflag & PARENB) { + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + ctl |= OWL_UART_CTL_PRS_MARK; + else + ctl |= OWL_UART_CTL_PRS_SPACE; + } else if (termios->c_cflag & PARODD) + ctl |= OWL_UART_CTL_PRS_ODD; + else + ctl |= OWL_UART_CTL_PRS_EVEN; + } else + ctl |= OWL_UART_CTL_PRS_NONE; + + if (termios->c_cflag & CRTSCTS) + ctl |= OWL_UART_CTL_AFE; + else + ctl &= ~OWL_UART_CTL_AFE; + + owl_uart_write(port, ctl, OWL_UART_CTL); + + baud = uart_get_baud_rate(port, termios, old, 9600, 3200000); + owl_uart_change_baudrate(owl_port, baud); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + port->read_status_mask |= OWL_UART_STAT_RXER; + if (termios->c_iflag & INPCK) + port->read_status_mask |= OWL_UART_STAT_RXST; + + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void owl_uart_release_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return; + + if (port->flags & UPF_IOREMAP) { + devm_release_mem_region(port->dev, port->mapbase, + resource_size(res)); + devm_iounmap(port->dev, port->membase); + port->membase = NULL; + } +} + +static int owl_uart_request_port(struct uart_port *port) +{ + struct platform_device *pdev = to_platform_device(port->dev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) + return -ENXIO; + + if (!devm_request_mem_region(port->dev, port->mapbase, + resource_size(res), dev_name(port->dev))) + return -EBUSY; + + if (port->flags & UPF_IOREMAP) { + port->membase = devm_ioremap_nocache(port->dev, port->mapbase, + resource_size(res)); + if (!port->membase) + return -EBUSY; + } + + return 0; +} + +static const char *owl_uart_type(struct uart_port *port) +{ + return (port->type == PORT_OWL) ? "owl-uart" : NULL; +} + +static int owl_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (port->type != PORT_OWL) + return -EINVAL; + + if (port->irq != ser->irq) + return -EINVAL; + + return 0; +} + +static void owl_uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_OWL; + owl_uart_request_port(port); + } +} + +static struct uart_ops owl_uart_ops = { + .set_mctrl = owl_uart_set_mctrl, + .get_mctrl = owl_uart_get_mctrl, + .tx_empty = owl_uart_tx_empty, + .start_tx = owl_uart_start_tx, + .stop_rx = owl_uart_stop_rx, + .stop_tx = owl_uart_stop_tx, + .startup = owl_uart_startup, + .shutdown = owl_uart_shutdown, + .set_termios = owl_uart_set_termios, + .type = owl_uart_type, + .config_port = owl_uart_config_port, + .request_port = owl_uart_request_port, + .release_port = owl_uart_release_port, + .verify_port = owl_uart_verify_port, +}; + #ifdef CONFIG_SERIAL_OWL_CONSOLE static void owl_console_putchar(struct uart_port *port, int ch) @@ -110,6 +546,57 @@ static void owl_uart_port_write(struct uart_port *port, const char *s, local_irq_restore(flags); } +static void owl_uart_console_write(struct console *co, const char *s, + u_int count) +{ + struct owl_uart_port *owl_port; + + owl_port = owl_uart_ports[co->index]; + if (!owl_port) + return; + + owl_uart_port_write(&owl_port->port, s, count); +} + +static int owl_uart_console_setup(struct console *co, char *options) +{ + struct owl_uart_port *owl_port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= OWL_UART_PORT_NUM) + return -EINVAL; + + owl_port = owl_uart_ports[co->index]; + if (!owl_port || !owl_port->port.membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&owl_port->port, co, baud, parity, bits, flow); +} + +static struct console owl_uart_console = { + .name = OWL_UART_DEV_NAME, + .write = owl_uart_console_write, + .device = uart_console_device, + .setup = owl_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &owl_uart_driver, +}; + +static int __init owl_uart_console_init(void) +{ + register_console(&owl_uart_console); + + return 0; +} +console_initcall(owl_uart_console_init); + static void owl_uart_early_console_write(struct console *co, const char *s, u_int count) @@ -132,4 +619,148 @@ owl_uart_early_console_setup(struct earlycon_device *device, const char *opt) OF_EARLYCON_DECLARE(owl, "actions,owl-uart", owl_uart_early_console_setup); -#endif /* CONFIG_SERIAL_OWL_CONSOLE */ +#define OWL_UART_CONSOLE (&owl_uart_console) +#else +#define OWL_UART_CONSOLE NULL +#endif + +static struct uart_driver owl_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "owl-uart", + .dev_name = OWL_UART_DEV_NAME, + .nr = OWL_UART_PORT_NUM, + .cons = OWL_UART_CONSOLE, +}; + +static const struct owl_uart_info owl_s500_info = { + .tx_fifosize = 16, +}; + +static const struct owl_uart_info owl_s900_info = { + .tx_fifosize = 32, +}; + +static const struct of_device_id owl_uart_dt_matches[] = { + { .compatible = "actions,s500-uart", .data = &owl_s500_info }, + { .compatible = "actions,s900-uart", .data = &owl_s900_info }, + { } +}; +MODULE_DEVICE_TABLE(of, owl_uart_dt_matches); + +static int owl_uart_probe(struct platform_device *pdev) +{ + const struct of_device_id *match; + const struct owl_uart_info *info = NULL; + struct resource *res_mem; + struct owl_uart_port *owl_port; + int ret, irq; + + if (pdev->dev.of_node) { + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + match = of_match_node(owl_uart_dt_matches, pdev->dev.of_node); + if (match) + info = match->data; + } + + if (pdev->id < 0 || pdev->id >= OWL_UART_PORT_NUM) { + dev_err(&pdev->dev, "id %d out of range\n", pdev->id); + return -EINVAL; + } + + res_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res_mem) { + dev_err(&pdev->dev, "could not get mem\n"); + return -ENODEV; + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(&pdev->dev, "could not get irq\n"); + return irq; + } + + if (owl_uart_ports[pdev->id]) { + dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); + return -EBUSY; + } + + owl_port = devm_kzalloc(&pdev->dev, sizeof(*owl_port), GFP_KERNEL); + if (!owl_port) + return -ENOMEM; + + owl_port->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(owl_port->clk)) { + dev_err(&pdev->dev, "could not get clk\n"); + return PTR_ERR(owl_port->clk); + } + + owl_port->port.dev = &pdev->dev; + owl_port->port.line = pdev->id; + owl_port->port.type = PORT_OWL; + owl_port->port.iotype = UPIO_MEM; + owl_port->port.mapbase = res_mem->start; + owl_port->port.irq = irq; + owl_port->port.uartclk = clk_get_rate(owl_port->clk); + if (owl_port->port.uartclk == 0) { + dev_err(&pdev->dev, "clock rate is zero\n"); + return -EINVAL; + } + owl_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_LOW_LATENCY; + owl_port->port.x_char = 0; + owl_port->port.fifosize = (info) ? info->tx_fifosize : 16; + owl_port->port.ops = &owl_uart_ops; + + owl_uart_ports[pdev->id] = owl_port; + platform_set_drvdata(pdev, owl_port); + + ret = uart_add_one_port(&owl_uart_driver, &owl_port->port); + if (ret) + owl_uart_ports[pdev->id] = NULL; + + return ret; +} + +static int owl_uart_remove(struct platform_device *pdev) +{ + struct owl_uart_port *owl_port = platform_get_drvdata(pdev); + + uart_remove_one_port(&owl_uart_driver, &owl_port->port); + owl_uart_ports[pdev->id] = NULL; + + return 0; +} + +static struct platform_driver owl_uart_platform_driver = { + .probe = owl_uart_probe, + .remove = owl_uart_remove, + .driver = { + .name = "owl-uart", + .of_match_table = owl_uart_dt_matches, + }, +}; + +static int __init owl_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&owl_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&owl_uart_platform_driver); + if (ret) + uart_unregister_driver(&owl_uart_driver); + + return ret; +} + +static void __init owl_uart_exit(void) +{ + platform_driver_unregister(&owl_uart_platform_driver); + uart_unregister_driver(&owl_uart_driver); +} + +module_init(owl_uart_init); +module_exit(owl_uart_exit); + +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index c34a2a3..38bea32 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -70,6 +70,7 @@ #define PORT_CLPS711X 33 #define PORT_SA1100 34 #define PORT_UART00 35 +#define PORT_OWL 36 #define PORT_21285 37 /* Sparc type numbers. */ -- cgit v1.1 From a5fa2660d787d8416f426cd622778a5d8851ac36 Mon Sep 17 00:00:00 2001 From: Marius Vlad Date: Sun, 16 Jul 2017 01:00:58 +0300 Subject: tty/serial/fsl_lpuart: Add CONSOLE_POLL support for lpuart32. This mirrors commit 2a41bc2a2b but for 32-bit register definitions. Fix a minor typo while at it. Signed-off-by: Marius Vlad CC: Nicolae Rosia CC: Stefan Golinschi CC: Greg Kroah-Hartman Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 58 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 343de8c..f9deb9a 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -117,7 +117,7 @@ #define UARTSFIFO_TXOF 0x02 #define UARTSFIFO_RXUF 0x01 -/* 32-bit register defination */ +/* 32-bit register definition */ #define UARTBAUD 0x00 #define UARTSTAT 0x04 #define UARTCTRL 0x08 @@ -521,6 +521,57 @@ static int lpuart_poll_get_char(struct uart_port *port) return readb(port->membase + UARTDR); } +static int lpuart32_poll_init(struct uart_port *port) +{ + unsigned long flags; + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + u32 temp; + + sport->port.fifosize = 0; + + spin_lock_irqsave(&sport->port.lock, flags); + + /* Disable Rx & Tx */ + writel(0, sport->port.membase + UARTCTRL); + + temp = readl(sport->port.membase + UARTFIFO); + + /* Enable Rx and Tx FIFO */ + writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE, + sport->port.membase + UARTFIFO); + + /* flush Tx and Rx FIFO */ + writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, + sport->port.membase + UARTFIFO); + + /* explicitly clear RDRF */ + if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) { + readl(sport->port.membase + UARTDATA); + writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO); + } + + /* Enable Rx and Tx */ + writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL); + spin_unlock_irqrestore(&sport->port.lock, flags); + + return 0; +} + +static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) +{ + while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE)) + barrier(); + + writel(c, port->membase + UARTDATA); +} + +static int lpuart32_poll_get_char(struct uart_port *port) +{ + if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF)) + return NO_POLL_CHAR; + + return readl(port->membase + UARTDATA); +} #endif static inline void lpuart_transmit_buffer(struct lpuart_port *sport) @@ -1776,6 +1827,11 @@ static const struct uart_ops lpuart32_pops = { .config_port = lpuart_config_port, .verify_port = lpuart_verify_port, .flush_buffer = lpuart_flush_buffer, +#if defined(CONFIG_CONSOLE_POLL) + .poll_init = lpuart32_poll_init, + .poll_get_char = lpuart32_poll_get_char, + .poll_put_char = lpuart32_poll_put_char, +#endif }; static struct lpuart_port *lpuart_ports[UART_NR]; -- cgit v1.1 From 3e5fcbacee5c2524499f203c31db46eefa744437 Mon Sep 17 00:00:00 2001 From: Bich HEMON Date: Thu, 13 Jul 2017 15:08:26 +0000 Subject: serial: stm32: fix copyright Fix missing copyright for STMicroelectronics Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 1 + drivers/tty/serial/stm32-usart.h | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 0338562..ebc49e4 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -1,5 +1,6 @@ /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics SA 2017 * Authors: Maxime Coquelin * Gerald Baeza * License terms: GNU General Public License (GPL), version 2 diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index cd97ceb..0532b2f 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -1,5 +1,6 @@ /* * Copyright (C) Maxime Coquelin 2015 + * Copyright (C) STMicroelectronics SA 2017 * Authors: Maxime Coquelin * Gerald Baeza * License terms: GNU General Public License (GPL), version 2 -- cgit v1.1 From e57079159619c21d7b33916ba5a4e74259a9fce7 Mon Sep 17 00:00:00 2001 From: Gerald Baeza Date: Thu, 13 Jul 2017 15:08:27 +0000 Subject: serial: stm32: fix multi-ports management Correct management of multi-ports. Each port has its own last residue value and its own alias. Signed-off-by: Gerald Baeza Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 12 +++++++----- drivers/tty/serial/stm32-usart.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index ebc49e4..a12d79c 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -111,14 +111,13 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) unsigned long c; u32 sr; char flag; - static int last_res = RX_BUF_L; if (port->irq_wake) pm_wakeup_event(tport->tty->dev, 0); - while (stm32_pending_rx(port, &sr, &last_res, threaded)) { + while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { sr |= USART_SR_DUMMY_RX; - c = stm32_get_char(port, &sr, &last_res); + c = stm32_get_char(port, &sr, &stm32_port->last_res); flag = TTY_NORMAL; port->icount.rx++; @@ -694,8 +693,10 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) return NULL; id = of_alias_get_id(np, "serial"); - if (id < 0) - id = 0; + if (id < 0) { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", id); + return NULL; + } if (WARN_ON(id >= STM32_MAX_PORTS)) return NULL; @@ -703,6 +704,7 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) stm32_ports[id].hw_flow_control = of_property_read_bool(np, "st,hw-flow-ctrl"); stm32_ports[id].port.line = id; + stm32_ports[id].last_res = RX_BUF_L; return &stm32_ports[id]; } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 0532b2f..65b4ffa 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -222,6 +222,7 @@ struct stm32_port { struct dma_chan *tx_ch; /* dma tx channel */ dma_addr_t tx_dma_buf; /* dma tx buffer bus address */ unsigned char *tx_buf; /* dma tx buffer cpu address */ + int last_res; bool tx_dma_busy; /* dma tx busy */ bool hw_flow_control; }; -- cgit v1.1 From cc7aefd4fa6c0e12301a923b629f49bfbaaac6b1 Mon Sep 17 00:00:00 2001 From: Gerald Baeza Date: Thu, 13 Jul 2017 15:08:27 +0000 Subject: serial: stm32: Increase maximum number of ports Increase max number of ports for stm32h7 which supports up to 8 uart and usart instances. Signed-off-by: Gerald Baeza Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 65b4ffa..6092789 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -206,7 +206,7 @@ struct stm32_usart_info stm32f7_info = { #define USART_ICR_CMCF BIT(17) /* F7 */ #define STM32_SERIAL_NAME "ttyS" -#define STM32_MAX_PORTS 6 +#define STM32_MAX_PORTS 8 #define RX_BUF_L 200 /* dma rx buffer length */ #define RX_BUF_P RX_BUF_L /* dma rx buffer period */ -- cgit v1.1 From 35abe98f15ed60d252f79da6e41b477527af8b2f Mon Sep 17 00:00:00 2001 From: Bich HEMON Date: Thu, 13 Jul 2017 15:08:28 +0000 Subject: serial: stm32: add RTS support Implement support of RTS in USART control register Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index a12d79c..2fca2d2 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -518,7 +518,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, port->status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS); if (cflag & CRTSCTS) { port->status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS; - cr3 |= USART_CR3_CTSE; + cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; } usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); -- cgit v1.1 From ada8004374afc35cc3b450dec35fb53531570e7b Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 13 Jul 2017 15:08:29 +0000 Subject: serial: stm32: fix error handling in probe Disable clock properly in case of error. Signed-off-by: Fabrice Gasnier Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 2fca2d2..688afc4 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -678,8 +678,10 @@ static int stm32_init_port(struct stm32_port *stm32port, return ret; stm32port->port.uartclk = clk_get_rate(stm32port->clk); - if (!stm32port->port.uartclk) + if (!stm32port->port.uartclk) { + clk_disable_unprepare(stm32port->clk); ret = -EINVAL; + } return ret; } @@ -865,7 +867,7 @@ static int stm32_serial_probe(struct platform_device *pdev) ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); if (ret) - return ret; + goto err_uninit; ret = stm32_of_dma_rx_probe(stm32port, pdev); if (ret) @@ -878,6 +880,11 @@ static int stm32_serial_probe(struct platform_device *pdev) platform_set_drvdata(pdev, &stm32port->port); return 0; + +err_uninit: + clk_disable_unprepare(stm32port->clk); + + return ret; } static int stm32_serial_remove(struct platform_device *pdev) -- cgit v1.1 From 20e4cfc9c11f3b44ae921f1b31e6fc614d878bb8 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 13 Jul 2017 15:08:29 +0000 Subject: dt-bindings: serial: add compatible for stm32h7 Introduce new compatibles for "st,stm32h7-usart" and "st,stm32h7-uart". This new compatible allow to use optional wake-up interrupt. Signed-off-by: Fabrice Gasnier Signed-off-by: Bich Hemon Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- .../devicetree/bindings/serial/st,stm32-usart.txt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt index 85ec5f2..3657f9f 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-usart.txt +++ b/Documentation/devicetree/bindings/serial/st,stm32-usart.txt @@ -1,12 +1,19 @@ * STMicroelectronics STM32 USART Required properties: -- compatible: Can be either "st,stm32-usart", "st,stm32-uart", -"st,stm32f7-usart" or "st,stm32f7-uart" depending on whether -the device supports synchronous mode and is compatible with -stm32(f4) or stm32f7. +- compatible: can be either: + - "st,stm32-usart", + - "st,stm32-uart", + - "st,stm32f7-usart", + - "st,stm32f7-uart", + - "st,stm32h7-usart" + - "st,stm32h7-uart". + depending on whether the device supports synchronous mode + and is compatible with stm32(f4), stm32f7 or stm32h7. - reg: The address and length of the peripheral registers space -- interrupts: The interrupt line of the USART instance +- interrupts: + - The interrupt line for the USART instance, + - An optional wake-up interrupt. - clocks: The input clock of the USART instance Optional properties: -- cgit v1.1 From 270e5a74fe4c78a857d65f1a129d3d77a36b8d58 Mon Sep 17 00:00:00 2001 From: Fabrice Gasnier Date: Thu, 13 Jul 2017 15:08:30 +0000 Subject: serial: stm32: add wakeup mechanism Add support for wake-up from low power modes. This extends stm32f7. Introduce new compatible for stm32h7 to manage wake-up capability. Signed-off-by: Fabrice Gasnier Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 90 +++++++++++++++++++++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 29 +++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 688afc4..9c43573 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -326,6 +327,10 @@ static irqreturn_t stm32_interrupt(int irq, void *ptr) sr = readl_relaxed(port->membase + ofs->isr); + if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) + writel_relaxed(USART_ICR_WUCF, + port->membase + ofs->icr); + if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) stm32_receive_chars(port, false); @@ -442,6 +447,7 @@ static int stm32_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; @@ -452,6 +458,15 @@ static int stm32_startup(struct uart_port *port) if (ret) return ret; + if (cfg->has_wakeup && stm32_port->wakeirq >= 0) { + ret = dev_pm_set_dedicated_wake_irq(port->dev, + stm32_port->wakeirq); + if (ret) { + free_irq(port->irq, port); + return ret; + } + } + val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; stm32_set_bits(port, ofs->cr1, val); @@ -469,6 +484,7 @@ static void stm32_shutdown(struct uart_port *port) val |= BIT(cfg->uart_enable_bit); stm32_clr_bits(port, ofs->cr1, val); + dev_pm_clear_wake_irq(port->dev); free_irq(port->irq, port); } @@ -659,6 +675,7 @@ static int stm32_init_port(struct stm32_port *stm32port, port->ops = &stm32_uart_ops; port->dev = &pdev->dev; port->irq = platform_get_irq(pdev, 0); + stm32port->wakeirq = platform_get_irq(pdev, 1); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->membase = devm_ioremap_resource(&pdev->dev, res); @@ -716,6 +733,8 @@ static const struct of_device_id stm32_match[] = { { .compatible = "st,stm32-uart", .data = &stm32f4_info}, { .compatible = "st,stm32f7-usart", .data = &stm32f7_info}, { .compatible = "st,stm32f7-uart", .data = &stm32f7_info}, + { .compatible = "st,stm32h7-usart", .data = &stm32h7_info}, + { .compatible = "st,stm32h7-uart", .data = &stm32h7_info}, {}, }; @@ -865,9 +884,15 @@ static int stm32_serial_probe(struct platform_device *pdev) if (ret) return ret; + if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) { + ret = device_init_wakeup(&pdev->dev, true); + if (ret) + goto err_uninit; + } + ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); if (ret) - goto err_uninit; + goto err_nowup; ret = stm32_of_dma_rx_probe(stm32port, pdev); if (ret) @@ -881,6 +906,10 @@ static int stm32_serial_probe(struct platform_device *pdev) return 0; +err_nowup: + if (stm32port->info->cfg.has_wakeup && stm32port->wakeirq >= 0) + device_init_wakeup(&pdev->dev, false); + err_uninit: clk_disable_unprepare(stm32port->clk); @@ -892,6 +921,7 @@ static int stm32_serial_remove(struct platform_device *pdev) struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); @@ -913,6 +943,9 @@ static int stm32_serial_remove(struct platform_device *pdev) TX_BUF_L, stm32_port->tx_buf, stm32_port->tx_dma_buf); + if (cfg->has_wakeup && stm32_port->wakeirq >= 0) + device_init_wakeup(&pdev->dev, false); + clk_disable_unprepare(stm32_port->clk); return uart_remove_one_port(&stm32_usart_driver, port); @@ -1018,11 +1051,66 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; +#ifdef CONFIG_PM_SLEEP +static void stm32_serial_enable_wakeup(struct uart_port *port, bool enable) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; + u32 val; + + if (!cfg->has_wakeup || stm32_port->wakeirq < 0) + return; + + if (enable) { + stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + stm32_set_bits(port, ofs->cr1, USART_CR1_UESM); + val = readl_relaxed(port->membase + ofs->cr3); + val &= ~USART_CR3_WUS_MASK; + /* Enable Wake up interrupt from low power on start bit */ + val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; + writel_relaxed(val, port->membase + ofs->cr3); + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + } else { + stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); + } +} + +static int stm32_serial_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + + uart_suspend_port(&stm32_usart_driver, port); + + if (device_may_wakeup(dev)) + stm32_serial_enable_wakeup(port, true); + else + stm32_serial_enable_wakeup(port, false); + + return 0; +} + +static int stm32_serial_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + stm32_serial_enable_wakeup(port, false); + + return uart_resume_port(&stm32_usart_driver, port); +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops stm32_serial_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) +}; + static struct platform_driver stm32_serial_driver = { .probe = stm32_serial_probe, .remove = stm32_serial_remove, .driver = { .name = DRIVER_NAME, + .pm = &stm32_serial_pm_ops, .of_match_table = of_match_ptr(stm32_match), }, }; diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 6092789..5984a66 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -25,6 +25,7 @@ struct stm32_usart_offsets { struct stm32_usart_config { u8 uart_enable_bit; /* USART_CR1_UE */ bool has_7bits_data; + bool has_wakeup; }; struct stm32_usart_info { @@ -75,6 +76,27 @@ struct stm32_usart_info stm32f7_info = { } }; +struct stm32_usart_info stm32h7_info = { + .ofs = { + .cr1 = 0x00, + .cr2 = 0x04, + .cr3 = 0x08, + .brr = 0x0c, + .gtpr = 0x10, + .rtor = 0x14, + .rqr = 0x18, + .isr = 0x1c, + .icr = 0x20, + .rdr = 0x24, + .tdr = 0x28, + }, + .cfg = { + .uart_enable_bit = 0, + .has_7bits_data = true, + .has_wakeup = true, + } +}; + /* USART_SR (F4) / USART_ISR (F7) */ #define USART_SR_PE BIT(0) #define USART_SR_FE BIT(1) @@ -94,6 +116,7 @@ struct stm32_usart_info stm32f7_info = { #define USART_SR_BUSY BIT(16) /* F7 */ #define USART_SR_CMF BIT(17) /* F7 */ #define USART_SR_SBKF BIT(18) /* F7 */ +#define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ #define USART_SR_ERR_MASK (USART_SR_LBD | USART_SR_ORE | \ USART_SR_FE | USART_SR_PE) @@ -114,6 +137,7 @@ struct stm32_usart_info stm32f7_info = { /* USART_CR1 */ #define USART_CR1_SBK BIT(0) #define USART_CR1_RWU BIT(1) /* F4 */ +#define USART_CR1_UESM BIT(1) /* H7 */ #define USART_CR1_RE BIT(2) #define USART_CR1_TE BIT(3) #define USART_CR1_IDLEIE BIT(4) @@ -176,6 +200,9 @@ struct stm32_usart_info stm32f7_info = { #define USART_CR3_DEM BIT(14) /* F7 */ #define USART_CR3_DEP BIT(15) /* F7 */ #define USART_CR3_SCARCNT_MASK GENMASK(19, 17) /* F7 */ +#define USART_CR3_WUS_MASK GENMASK(21, 20) /* H7 */ +#define USART_CR3_WUS_START_BIT BIT(21) /* H7 */ +#define USART_CR3_WUFIE BIT(22) /* H7 */ /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) @@ -204,6 +231,7 @@ struct stm32_usart_info stm32f7_info = { #define USART_ICR_RTOCF BIT(11) /* F7 */ #define USART_ICR_EOBCF BIT(12) /* F7 */ #define USART_ICR_CMCF BIT(17) /* F7 */ +#define USART_ICR_WUCF BIT(20) /* H7 */ #define STM32_SERIAL_NAME "ttyS" #define STM32_MAX_PORTS 8 @@ -225,6 +253,7 @@ struct stm32_port { int last_res; bool tx_dma_busy; /* dma tx busy */ bool hw_flow_control; + int wakeirq; }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; -- cgit v1.1 From 351a762aa8051960695a0f131731518e93b957fa Mon Sep 17 00:00:00 2001 From: Gerald Baeza Date: Thu, 13 Jul 2017 15:08:30 +0000 Subject: serial: stm32: add fifo support This patch adds fifo mode support for rx and tx. A fifo configuration is set in each port structure. Add has_fifo flag to usart configuration to use fifo only when possible. Signed-off-by: Gerald Baeza Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 7 +++++++ drivers/tty/serial/stm32-usart.h | 4 ++++ 2 files changed, 11 insertions(+) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 9c43573..72c0ec1 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -468,6 +468,8 @@ static int stm32_startup(struct uart_port *port) } val = USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + if (stm32_port->fifoen) + val |= USART_CR1_FIFOEN; stm32_set_bits(port, ofs->cr1, val); return 0; @@ -482,6 +484,8 @@ static void stm32_shutdown(struct uart_port *port) val = USART_CR1_TXEIE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; val |= BIT(cfg->uart_enable_bit); + if (stm32_port->fifoen) + val |= USART_CR1_FIFOEN; stm32_clr_bits(port, ofs->cr1, val); dev_pm_clear_wake_irq(port->dev); @@ -512,6 +516,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; cr1 |= BIT(cfg->uart_enable_bit); + if (stm32_port->fifoen) + cr1 |= USART_CR1_FIFOEN; cr2 = 0; cr3 = 0; @@ -676,6 +682,7 @@ static int stm32_init_port(struct stm32_port *stm32port, port->dev = &pdev->dev; port->irq = platform_get_irq(pdev, 0); stm32port->wakeirq = platform_get_irq(pdev, 1); + stm32port->fifoen = stm32port->info->cfg.has_fifo; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->membase = devm_ioremap_resource(&pdev->dev, res); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 5984a66..ffc0c52 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -26,6 +26,7 @@ struct stm32_usart_config { u8 uart_enable_bit; /* USART_CR1_UE */ bool has_7bits_data; bool has_wakeup; + bool has_fifo; }; struct stm32_usart_info { @@ -94,6 +95,7 @@ struct stm32_usart_info stm32h7_info = { .uart_enable_bit = 0, .has_7bits_data = true, .has_wakeup = true, + .has_fifo = true, } }; @@ -159,6 +161,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR1_EOBIE BIT(27) /* F7 */ #define USART_CR1_M1 BIT(28) /* F7 */ #define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) +#define USART_CR1_FIFOEN BIT(29) /* H7 */ /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ @@ -253,6 +256,7 @@ struct stm32_port { int last_res; bool tx_dma_busy; /* dma tx busy */ bool hw_flow_control; + bool fifoen; int wakeirq; }; -- cgit v1.1 From 7280f6d9b22f98716568124c280b389415e91497 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:03 +0530 Subject: tty: synclinkmp: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 44660 432 104 45196 b08c drivers/tty/synclinkmp.o File size After adding 'const': text data bss dec hex filename 44756 336 104 45196 b08c drivers/tty/synclinkmp.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/synclinkmp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/synclinkmp.c b/drivers/tty/synclinkmp.c index 9b4fb02..4fed9e7 100644 --- a/drivers/tty/synclinkmp.c +++ b/drivers/tty/synclinkmp.c @@ -479,7 +479,7 @@ static char *driver_version = "$Revision: 4.38 $"; static int synclinkmp_init_one(struct pci_dev *dev,const struct pci_device_id *ent); static void synclinkmp_remove_one(struct pci_dev *dev); -static struct pci_device_id synclinkmp_pci_tbl[] = { +static const struct pci_device_id synclinkmp_pci_tbl[] = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_SCA, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* terminate list */ }; -- cgit v1.1 From 763653d7d51ae2d100b0b5f364ff7e343cea0efe Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:02 +0530 Subject: tty: isicom: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 12176 1520 25864 39560 9a88 drivers/tty/isicom.o File size After adding 'const': text data bss dec hex filename 12528 1168 25864 39560 9a88 drivers/tty/isicom.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/isicom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c index b70187b..61ecdd6 100644 --- a/drivers/tty/isicom.c +++ b/drivers/tty/isicom.c @@ -150,7 +150,7 @@ static int isicom_probe(struct pci_dev *, const struct pci_device_id *); static void isicom_remove(struct pci_dev *); -static struct pci_device_id isicom_pci_tbl[] = { +static const struct pci_device_id isicom_pci_tbl[] = { { PCI_DEVICE(VENDOR_ID, 0x2028) }, { PCI_DEVICE(VENDOR_ID, 0x2051) }, { PCI_DEVICE(VENDOR_ID, 0x2052) }, -- cgit v1.1 From 3385ecf87f21d4dc0281ab781bdc57830cf681b6 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:01 +0530 Subject: tty: mxser: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 20253 1184 19904 41341 a17d drivers/tty/mxser.o File size After adding 'const': text data bss dec hex filename 21117 300 19904 41341 a17d drivers/tty/mxser.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mxser.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/mxser.c b/drivers/tty/mxser.c index 8bd6fb6..1c0c955 100644 --- a/drivers/tty/mxser.c +++ b/drivers/tty/mxser.c @@ -145,7 +145,7 @@ static const struct mxser_cardinfo mxser_cards[] = { /* driver_data correspond to the lines in the structure above see also ISA probe function before you change something */ -static struct pci_device_id mxser_pcibrds[] = { +static const struct pci_device_id mxser_pcibrds[] = { { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C168), .driver_data = 3 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_C104), .driver_data = 4 }, { PCI_VDEVICE(MOXA, PCI_DEVICE_ID_MOXA_CP132), .driver_data = 8 }, -- cgit v1.1 From ba38aac161f2d8b5d5d30e7169456b13dbb8caed Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:04 +0530 Subject: tty: synclink: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 51755 400 513 52668 cdbc drivers/tty/synclink.o File size After adding 'const': text data bss dec hex filename 51883 304 513 52700 cddc drivers/tty/synclink.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/synclink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/synclink.c b/drivers/tty/synclink.c index 3fafc5a..3be9811 100644 --- a/drivers/tty/synclink.c +++ b/drivers/tty/synclink.c @@ -884,7 +884,7 @@ static int synclink_init_one (struct pci_dev *dev, const struct pci_device_id *ent); static void synclink_remove_one (struct pci_dev *dev); -static struct pci_device_id synclink_pci_tbl[] = { +static const struct pci_device_id synclink_pci_tbl[] = { { PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, }, { PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, }, { 0, }, /* terminate list */ -- cgit v1.1 From 50bd842b32b4ef57fdf5381b428d1b5605f429ea Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:05 +0530 Subject: tty: moxa: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 14201 656 1760 16617 40e9 drivers/tty/moxa.o File size After adding 'const': text data bss dec hex filename 14329 528 1760 16617 40e9 drivers/tty/moxa.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/moxa.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/moxa.c b/drivers/tty/moxa.c index 3b251f4e..7f3d4cb 100644 --- a/drivers/tty/moxa.c +++ b/drivers/tty/moxa.c @@ -88,7 +88,7 @@ static char *moxa_brdname[] = }; #ifdef CONFIG_PCI -static struct pci_device_id moxa_pcibrds[] = { +static const struct pci_device_id moxa_pcibrds[] = { { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C218), .driver_data = MOXA_BOARD_C218_PCI }, { PCI_DEVICE(PCI_VENDOR_ID_MOXA, PCI_DEVICE_ID_MOXA_C320), -- cgit v1.1 From 3637c46032515fe975f652d315ccd2076026c522 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:07 +0530 Subject: tty: serial: exar: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 4030 1280 0 5310 14be tty/serial/8250/8250_exar.o File size After adding 'const': text data bss dec hex filename 4958 352 0 5310 14be tty/serial/8250/8250_exar.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_exar.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_exar.c b/drivers/tty/serial/8250/8250_exar.c index b5c98e5..6f031fc 100644 --- a/drivers/tty/serial/8250/8250_exar.c +++ b/drivers/tty/serial/8250/8250_exar.c @@ -601,7 +601,7 @@ static const struct exar8250_board pbn_exar_XR17V8358 = { (kernel_ulong_t)&bd \ } -static struct pci_device_id exar_pci_tbl[] = { +static const struct pci_device_id exar_pci_tbl[] = { CONNECT_DEVICE(XR17C152, UART_2_232, pbn_connect), CONNECT_DEVICE(XR17C154, UART_4_232, pbn_connect), CONNECT_DEVICE(XR17C158, UART_8_232, pbn_connect), -- cgit v1.1 From c40f716ad34170aec93da145210aacf10599ecb0 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:06 +0530 Subject: tty: serial: pci: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 12626 18128 0 30754 7822 tty/serial/8250/8250_pci.o File size After adding 'const': text data bss dec hex filename 23986 6768 0 30754 7822 tty/serial/8250/8250_pci.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 00e51a0..553823c 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -3723,7 +3723,7 @@ static int pciserial_resume_one(struct device *dev) static SIMPLE_DEV_PM_OPS(pciserial_pm_ops, pciserial_suspend_one, pciserial_resume_one); -static struct pci_device_id serial_pci_tbl[] = { +static const struct pci_device_id serial_pci_tbl[] = { /* Advantech use PCI_DEVICE_ID_ADVANTECH_PCI3620 (0x3620) as 'PCI_SUBVENDOR_ID' */ { PCI_VENDOR_ID_ADVANTECH, PCI_DEVICE_ID_ADVANTECH_PCI3620, PCI_DEVICE_ID_ADVANTECH_PCI3620, 0x0001, 0, 0, -- cgit v1.1 From 0846b762c42d9654290f19a3b2e6248d6aca2b0a Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:09 +0530 Subject: tty: synclink_gt: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 41180 480 185 41845 a375 drivers/tty/synclink_gt.o File size After adding 'const': text data bss dec hex filename 41340 320 185 41845 a375 drivers/tty/synclink_gt.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/synclink_gt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/synclink_gt.c b/drivers/tty/synclink_gt.c index 529c6e3..636b8ae 100644 --- a/drivers/tty/synclink_gt.c +++ b/drivers/tty/synclink_gt.c @@ -95,7 +95,7 @@ MODULE_LICENSE("GPL"); #define MGSL_MAGIC 0x5401 #define MAX_DEVICES 32 -static struct pci_device_id pci_table[] = { +static const struct pci_device_id pci_table[] = { {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,}, -- cgit v1.1 From 46d01710f621ee8efaa1fc12f54d49124bb477bd Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sun, 23 Jul 2017 15:31:08 +0530 Subject: tty: serial: jsm: constify pci_device_id. pci_device_id are not supposed to change at runtime. All functions working with pci_device_id provided by work with const pci_device_id. So mark the non-const structs as const. File size before: text data bss dec hex filename 2442 1088 8 3538 dd2 tty/serial/jsm/jsm_driver.o File size After adding 'const': text data bss dec hex filename 3082 448 8 3538 dd2 tty/serial/jsm/jsm_driver.o Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/jsm/jsm_driver.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/jsm/jsm_driver.c b/drivers/tty/serial/jsm/jsm_driver.c index a119f11..102d499 100644 --- a/drivers/tty/serial/jsm/jsm_driver.c +++ b/drivers/tty/serial/jsm/jsm_driver.c @@ -304,7 +304,7 @@ static void jsm_remove_one(struct pci_dev *pdev) kfree(brd); } -static struct pci_device_id jsm_pci_tbl[] = { +static const struct pci_device_id jsm_pci_tbl[] = { { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9), 0, 0, 0 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2DB9PRI), 0, 0, 1 }, { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 }, -- cgit v1.1 From a73ee8438c6da166589d975fc9c7c4e98ff5e330 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 18 Jul 2017 16:43:34 -0500 Subject: tty: Convert to using %pOF instead of full_name Now that we have a custom printf format specifier, convert users of full_name to use %pOF instead. This is preparation to remove storing of the full path string for each node. Signed-off-by: Rob Herring Acked-by: David S. Miller Cc: Jiri Slaby Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Michael Ellerman Cc: "David S. Miller" Cc: linuxppc-dev@lists.ozlabs.org Cc: linux-serial@vger.kernel.org Cc: sparclinux@vger.kernel.org Signed-off-by: Greg Kroah-Hartman --- drivers/tty/ehv_bytechan.c | 2 +- drivers/tty/hvc/hvc_opal.c | 16 ++++++++-------- drivers/tty/hvc/hvc_vio.c | 6 +++--- drivers/tty/serdev/core.c | 2 +- drivers/tty/serial/mpc52xx_uart.c | 12 ++++++------ drivers/tty/serial/pmac_zilog.c | 4 ++-- drivers/tty/serial/sunsu.c | 4 ++-- 7 files changed, 23 insertions(+), 23 deletions(-) diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c index 61fe8d6..a1c7125 100644 --- a/drivers/tty/ehv_bytechan.c +++ b/drivers/tty/ehv_bytechan.c @@ -122,7 +122,7 @@ static int find_console_handle(void) stdout_irq = irq_of_parse_and_map(np, 0); if (stdout_irq == NO_IRQ) { - pr_err("ehv-bc: no 'interrupts' property in %s node\n", np->full_name); + pr_err("ehv-bc: no 'interrupts' property in %pOF node\n", np); return 0; } diff --git a/drivers/tty/hvc/hvc_opal.c b/drivers/tty/hvc/hvc_opal.c index 5107993..16331a9 100644 --- a/drivers/tty/hvc/hvc_opal.c +++ b/drivers/tty/hvc/hvc_opal.c @@ -179,8 +179,8 @@ static int hvc_opal_probe(struct platform_device *dev) proto = HV_PROTOCOL_HVSI; ops = &hvc_opal_hvsi_ops; } else { - pr_err("hvc_opal: Unknown protocol for %s\n", - dev->dev.of_node->full_name); + pr_err("hvc_opal: Unknown protocol for %pOF\n", + dev->dev.of_node); return -ENXIO; } @@ -204,14 +204,14 @@ static int hvc_opal_probe(struct platform_device *dev) /* Instanciate now to establish a mapping index==vtermno */ hvc_instantiate(termno, termno, ops); } else { - pr_err("hvc_opal: Device %s has duplicate terminal number #%d\n", - dev->dev.of_node->full_name, termno); + pr_err("hvc_opal: Device %pOF has duplicate terminal number #%d\n", + dev->dev.of_node, termno); return -ENXIO; } - pr_info("hvc%d: %s protocol on %s%s\n", termno, + pr_info("hvc%d: %s protocol on %pOF%s\n", termno, proto == HV_PROTOCOL_RAW ? "raw" : "hvsi", - dev->dev.of_node->full_name, + dev->dev.of_node, boot ? " (boot console)" : ""); irq = irq_of_parse_and_map(dev->dev.of_node, 0); @@ -222,8 +222,8 @@ static int hvc_opal_probe(struct platform_device *dev) } if (!irq) { - pr_err("hvc_opal: Unable to map interrupt for device %s\n", - dev->dev.of_node->full_name); + pr_err("hvc_opal: Unable to map interrupt for device %pOF\n", + dev->dev.of_node); return irq; } diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index b05dc50..78b003b 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -312,12 +312,12 @@ static int hvc_vio_probe(struct vio_dev *vdev, proto = HV_PROTOCOL_HVSI; ops = &hvterm_hvsi_ops; } else { - pr_err("hvc_vio: Unknown protocol for %s\n", vdev->dev.of_node->full_name); + pr_err("hvc_vio: Unknown protocol for %pOF\n", vdev->dev.of_node); return -ENXIO; } - pr_devel("hvc_vio_probe() device %s, using %s protocol\n", - vdev->dev.of_node->full_name, + pr_devel("hvc_vio_probe() device %pOF, using %s protocol\n", + vdev->dev.of_node, proto == HV_PROTOCOL_RAW ? "raw" : "hvsi"); /* Is it our boot one ? */ diff --git a/drivers/tty/serdev/core.c b/drivers/tty/serdev/core.c index ae1aaa0..c68fb3a 100644 --- a/drivers/tty/serdev/core.c +++ b/drivers/tty/serdev/core.c @@ -363,7 +363,7 @@ static int of_serdev_register_devices(struct serdev_controller *ctrl) if (!of_get_property(node, "compatible", NULL)) continue; - dev_dbg(&ctrl->dev, "adding child %s\n", node->full_name); + dev_dbg(&ctrl->dev, "adding child %pOF\n", node); serdev = serdev_device_alloc(ctrl); if (!serdev) diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 3970d6a..4cacaad 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1634,8 +1634,8 @@ mpc52xx_console_setup(struct console *co, char *options) return -EINVAL; } - pr_debug("Console on ttyPSC%x is %s\n", - co->index, mpc52xx_uart_nodes[co->index]->full_name); + pr_debug("Console on ttyPSC%x is %pOF\n", + co->index, mpc52xx_uart_nodes[co->index]); /* Fetch register locations */ ret = of_address_to_resource(np, 0, &res); @@ -1755,8 +1755,8 @@ static int mpc52xx_uart_of_probe(struct platform_device *op) break; if (idx >= MPC52xx_PSC_MAXNUM) return -EINVAL; - pr_debug("Found %s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[idx]->full_name, idx); + pr_debug("Found %pOF assigned to ttyPSC%x\n", + mpc52xx_uart_nodes[idx], idx); /* set the uart clock to the input clock of the psc, the different * prescalers are taken into account in the set_baudrate() methods @@ -1881,8 +1881,8 @@ mpc52xx_uart_of_enumerate(void) for (i = 0; i < MPC52xx_PSC_MAXNUM; i++) { if (mpc52xx_uart_nodes[i]) - pr_debug("%s assigned to ttyPSC%x\n", - mpc52xx_uart_nodes[i]->full_name, i); + pr_debug("%pOF assigned to ttyPSC%x\n", + mpc52xx_uart_nodes[i], i); } } diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index 0da5294..6ccdd01 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1671,8 +1671,8 @@ static int __init pmz_probe(void) if (!node_a && !node_b) { of_node_put(node_a); of_node_put(node_b); - printk(KERN_ERR "pmac_zilog: missing node %c for escc %s\n", - (!node_a) ? 'a' : 'b', node_p->full_name); + printk(KERN_ERR "pmac_zilog: missing node %c for escc %pOF\n", + (!node_a) ? 'a' : 'b', node_p); continue; } diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 72df2e1..5380407 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1212,8 +1212,8 @@ static int sunsu_kbd_ms_init(struct uart_sunsu_port *up) if (up->port.type == PORT_UNKNOWN) return -ENODEV; - printk("%s: %s port at %llx, irq %u\n", - up->port.dev->of_node->full_name, + printk("%pOF: %s port at %llx, irq %u\n", + up->port.dev->of_node, (up->su_type == SU_PORT_KBD) ? "Keyboard" : "Mouse", (unsigned long long) up->port.mapbase, up->port.irq); -- cgit v1.1 From fa9ba3acb557e444fe4a736ab654f0d0a0fbccde Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Wed, 19 Jul 2017 11:32:37 +0300 Subject: serial: 8250: fix error handling in of_platform_serial_probe() clk_disable_unprepare(info->clk) is missed in of_platform_serial_probe(), while irq_dispose_mapping(port->irq) is missed in of_platform_serial_setup(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 0cf95fd..6c5a8ca 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -88,7 +88,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, ret = of_address_to_resource(np, 0, &resource); if (ret) { dev_warn(&ofdev->dev, "invalid address\n"); - goto out; + goto err_unprepare; } spin_lock_init(&port->lock); @@ -130,16 +130,16 @@ static int of_platform_serial_setup(struct platform_device *ofdev, dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", prop); ret = -EINVAL; - goto out; + goto err_dispose; } } info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) - goto out; + goto err_dispose; ret = reset_control_deassert(info->rst); if (ret) - goto out; + goto err_dispose; port->type = type; port->uartclk = clk; @@ -167,7 +167,9 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->handle_irq = fsl8250_handle_irq; return 0; -out: +err_dispose: + irq_dispose_mapping(port->irq); +err_unprepare: if (info->clk) clk_disable_unprepare(info->clk); return ret; @@ -201,7 +203,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) memset(&port8250, 0, sizeof(port8250)); ret = of_platform_serial_setup(ofdev, port_type, &port8250.port, info); if (ret) - goto out; + goto err_free; if (port8250.port.fifosize) port8250.capabilities = UART_CAP_FIFO; @@ -217,15 +219,18 @@ static int of_platform_serial_probe(struct platform_device *ofdev) ret = serial8250_register_8250_port(&port8250); if (ret < 0) - goto out; + goto err_dispose; info->type = port_type; info->line = ret; platform_set_drvdata(ofdev, info); return 0; -out: - kfree(info); +err_dispose: irq_dispose_mapping(port8250.port.irq); + if (info->clk) + clk_disable_unprepare(info->clk); +err_free: + kfree(info); return ret; } -- cgit v1.1 From b382f5d3c3962213492772b380c8fa3f752ffd98 Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:28 +0200 Subject: serial: 8250_dw: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: linux-serial@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 787b116..7e63899 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -529,7 +529,7 @@ static int dw8250_probe(struct platform_device *pdev) } } - data->rst = devm_reset_control_get_optional(dev, NULL); + data->rst = devm_reset_control_get_optional_exclusive(dev, NULL); if (IS_ERR(data->rst)) { err = PTR_ERR(data->rst); goto err_pclk; -- cgit v1.1 From f67276a0ee113adcfd542527b39e937bbdc64ceb Mon Sep 17 00:00:00 2001 From: Philipp Zabel Date: Wed, 19 Jul 2017 17:26:29 +0200 Subject: serial: tegra: explicitly request exclusive reset control Commit a53e35db70d1 ("reset: Ensure drivers are explicit when requesting reset lines") started to transition the reset control request API calls to explicitly state whether the driver needs exclusive or shared reset control behavior. Convert all drivers requesting exclusive resets to the explicit API call so the temporary transition helpers can be removed. No functional changes. Cc: Laxman Dewangan Cc: Greg Kroah-Hartman Cc: Jiri Slaby Cc: Thierry Reding Cc: Jonathan Hunter Cc: linux-serial@vger.kernel.org Cc: linux-tegra@vger.kernel.org Signed-off-by: Philipp Zabel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial-tegra.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index d92a150..cf9b736 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -1310,7 +1310,7 @@ static int tegra_uart_probe(struct platform_device *pdev) return PTR_ERR(tup->uart_clk); } - tup->rst = devm_reset_control_get(&pdev->dev, "serial"); + tup->rst = devm_reset_control_get_exclusive(&pdev->dev, "serial"); if (IS_ERR(tup->rst)) { dev_err(&pdev->dev, "Couldn't get the reset\n"); return PTR_ERR(tup->rst); -- cgit v1.1 From 64432a855148fd858e228a0faaebe7036a549706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2017 14:01:52 +0200 Subject: serial: imx: drop useless member from driver data MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wait queue was only initialized and then checked if it contains active jobs but a job is never added. The last real user was removed with commit 9d297239b8cb ("serial: imx-serial - update UART IMX driver to use cyclic DMA"). Further there is no need to release the lock for the check if the port should be woken up, (and IMHO there never was) so drop the unlock/lock pair in dma_tx_callback(), too. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 80934e7..3964ae5 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -226,7 +226,6 @@ struct imx_port { dma_cookie_t rx_cookie; unsigned int tx_bytes; unsigned int dma_tx_nents; - wait_queue_head_t dma_wait; unsigned int saved_reg[10]; bool context_saved; }; @@ -498,20 +497,12 @@ static void dma_tx_callback(void *data) sport->dma_is_txing = 0; - spin_unlock_irqrestore(&sport->port.lock, flags); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (waitqueue_active(&sport->dma_wait)) { - wake_up(&sport->dma_wait); - dev_dbg(sport->port.dev, "exit in %s.\n", __func__); - return; - } - - spin_lock_irqsave(&sport->port.lock, flags); if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) imx_dma_tx(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1208,8 +1199,6 @@ static void imx_enable_dma(struct imx_port *sport) { unsigned long temp; - init_waitqueue_head(&sport->dma_wait); - /* set UCR1 */ temp = readl(sport->port.membase + UCR1); temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; -- cgit v1.1 From 4350782570b919f254c1e083261a21c19fcaee90 Mon Sep 17 00:00:00 2001 From: Lanqing Liu Date: Tue, 18 Jul 2017 17:58:13 +0800 Subject: serial: sprd: clear timeout interrupt only rather than all interrupts On Spreadtrum's serial device, nearly all of interrupts would be cleared by hardware except timeout interrupt. This patch removed the operation of clearing all interrupt in irq handler, instead added an if statement to check if the timeout interrupt is supposed to be cleared. Wrongly clearing timeout interrupt would lead to uart data stay in rx fifo, that means the driver cannot read them out anymore. Signed-off-by: Lanqing Liu Signed-off-by: Chunyan Zhang Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 90996ad..f758fe6 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -63,6 +63,7 @@ /* interrupt clear register */ #define SPRD_ICLR 0x0014 +#define SPRD_ICLR_TIMEOUT BIT(13) /* line control register */ #define SPRD_LCR 0x0018 @@ -298,7 +299,8 @@ static irqreturn_t sprd_handle_irq(int irq, void *dev_id) return IRQ_NONE; } - serial_out(port, SPRD_ICLR, ~0); + if (ims & SPRD_IMSR_TIMEOUT) + serial_out(port, SPRD_ICLR, SPRD_ICLR_TIMEOUT); if (ims & (SPRD_IMSR_RX_FIFO_FULL | SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT)) -- cgit v1.1 From cbafe9d5c346735d6ac5d5c905fd9c215fbbb941 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 28 Jul 2017 21:54:03 +0300 Subject: drivers/serial: Do not leave sysfs group in case of error in aspeed_vuart_probe() There are several error handling paths in aspeed_vuart_probe(), where sysfs group is left unremoved. The patch fixes them. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_aspeed_vuart.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 822be49..33a8013 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -223,12 +223,13 @@ static int aspeed_vuart_probe(struct platform_device *pdev) if (IS_ERR(vuart->clk)) { dev_warn(&pdev->dev, "clk or clock-frequency not defined\n"); - return PTR_ERR(vuart->clk); + rc = PTR_ERR(vuart->clk); + goto err_sysfs_remove; } rc = clk_prepare_enable(vuart->clk); if (rc < 0) - return rc; + goto err_sysfs_remove; clk = clk_get_rate(vuart->clk); } @@ -286,6 +287,8 @@ static int aspeed_vuart_probe(struct platform_device *pdev) err_clk_disable: clk_disable_unprepare(vuart->clk); irq_dispose_mapping(port.port.irq); +err_sysfs_remove: + sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); return rc; } -- cgit v1.1 From ac1e6965597d26cc1d16559b01261cbe1279ed00 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 18 Jul 2017 14:02:54 +0800 Subject: serial: arc: Remove __init marking from early write The earlycon would be alive outside the init code in these cases: 1/ we have keep_bootcon in cmdline. 2/ we don't have a real console to switch to. So remove the __init marking to avoid invalid memory access. Signed-off-by: Jeffy Chen Reviewed-by: Douglas Anderson Tested-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 5ac06fc..77fe306 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -549,8 +549,8 @@ static struct console arc_console = { .data = &arc_uart_driver }; -static __init void arc_early_serial_write(struct console *con, const char *s, - unsigned int n) +static void arc_early_serial_write(struct console *con, const char *s, + unsigned int n) { struct earlycon_device *dev = con->data; -- cgit v1.1 From b38dd0e8edd0ccd28eaa67a76e7d10ec693ce3a3 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 18 Jul 2017 14:02:55 +0800 Subject: serial: omap: Remove __init marking from early write The earlycon would be alive outside the init code in these cases: 1/ we have keep_bootcon in cmdline. 2/ we don't have a real console to switch to. So remove the __init marking to avoid invalid memory access. Signed-off-by: Jeffy Chen Reviewed-by: Douglas Anderson Tested-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/omap-serial.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c index 1ea05ac..7754053 100644 --- a/drivers/tty/serial/omap-serial.c +++ b/drivers/tty/serial/omap-serial.c @@ -1235,21 +1235,20 @@ out: #ifdef CONFIG_SERIAL_OMAP_CONSOLE #ifdef CONFIG_SERIAL_EARLYCON -static unsigned int __init omap_serial_early_in(struct uart_port *port, - int offset) +static unsigned int omap_serial_early_in(struct uart_port *port, int offset) { offset <<= port->regshift; return readw(port->membase + offset); } -static void __init omap_serial_early_out(struct uart_port *port, int offset, - int value) +static void omap_serial_early_out(struct uart_port *port, int offset, + int value) { offset <<= port->regshift; writew(value, port->membase + offset); } -static void __init omap_serial_early_putc(struct uart_port *port, int c) +static void omap_serial_early_putc(struct uart_port *port, int c) { unsigned int status; @@ -1262,8 +1261,8 @@ static void __init omap_serial_early_putc(struct uart_port *port, int c) omap_serial_early_out(port, UART_TX, c); } -static void __init early_omap_serial_write(struct console *console, - const char *s, unsigned int count) +static void early_omap_serial_write(struct console *console, const char *s, + unsigned int count) { struct earlycon_device *device = console->data; struct uart_port *port = &device->port; -- cgit v1.1 From 99d2731678723b86a7fe17319214fdbe53e4fc0c Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 18 Jul 2017 14:02:56 +0800 Subject: serial: xuartps: Remove __init marking from early write The earlycon would be alive outside the init code in these cases: 1/ we have keep_bootcon in cmdline. 2/ we don't have a real console to switch to. So remove the __init marking to avoid invalid memory access. Signed-off-by: Jeffy Chen Reviewed-by: Douglas Anderson Tested-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index fde55dc..31a630a 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1163,7 +1163,7 @@ static void cdns_uart_console_putchar(struct uart_port *port, int ch) writel(ch, port->membase + CDNS_UART_FIFO); } -static void __init cdns_early_write(struct console *con, const char *s, +static void cdns_early_write(struct console *con, const char *s, unsigned n) { struct earlycon_device *dev = con->data; -- cgit v1.1 From 1b7eec2af68ef0af8a54397791cab437343bddc2 Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 18 Jul 2017 14:02:57 +0800 Subject: serial: 8250_ingenic: Remove __init marking from early write The earlycon would be alive outside the init code in these cases: 1/ we have keep_bootcon in cmdline. 2/ we don't have a real console to switch to. So remove the __init marking to avoid invalid memory access. Signed-off-by: Jeffy Chen Reviewed-by: Douglas Anderson Tested-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_ingenic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 4d9dc10..464389b 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -50,17 +50,17 @@ static const struct of_device_id of_match[]; static struct earlycon_device *early_device; -static uint8_t __init early_in(struct uart_port *port, int offset) +static uint8_t early_in(struct uart_port *port, int offset) { return readl(port->membase + (offset << 2)); } -static void __init early_out(struct uart_port *port, int offset, uint8_t value) +static void early_out(struct uart_port *port, int offset, uint8_t value) { writel(value, port->membase + (offset << 2)); } -static void __init ingenic_early_console_putc(struct uart_port *port, int c) +static void ingenic_early_console_putc(struct uart_port *port, int c) { uint8_t lsr; @@ -71,7 +71,7 @@ static void __init ingenic_early_console_putc(struct uart_port *port, int c) early_out(port, UART_TX, c); } -static void __init ingenic_early_console_write(struct console *console, +static void ingenic_early_console_write(struct console *console, const char *s, unsigned int count) { uart_console_write(&early_device->port, s, count, -- cgit v1.1 From bdc4704b2da9a30162d5990c1dad605828fcecdd Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Tue, 18 Jul 2017 14:02:58 +0800 Subject: serial: 8250_early: Remove __init marking from early write The earlycon would be alive outside the init code in these cases: 1/ we have keep_bootcon in cmdline. 2/ we don't have a real console to switch to. So remove the __init marking to avoid invalid memory access. Signed-off-by: Jeffy Chen Reviewed-by: Douglas Anderson Tested-by: Brian Norris Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_early.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index 82fc48e..af72ec3 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -37,7 +37,7 @@ #include #include -static unsigned int __init serial8250_early_in(struct uart_port *port, int offset) +static unsigned int serial8250_early_in(struct uart_port *port, int offset) { int reg_offset = offset; offset <<= port->regshift; @@ -60,7 +60,7 @@ static unsigned int __init serial8250_early_in(struct uart_port *port, int offse } } -static void __init serial8250_early_out(struct uart_port *port, int offset, int value) +static void serial8250_early_out(struct uart_port *port, int offset, int value) { int reg_offset = offset; offset <<= port->regshift; @@ -89,7 +89,7 @@ static void __init serial8250_early_out(struct uart_port *port, int offset, int #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) -static void __init serial_putc(struct uart_port *port, int c) +static void serial_putc(struct uart_port *port, int c) { unsigned int status; @@ -103,7 +103,7 @@ static void __init serial_putc(struct uart_port *port, int c) } } -static void __init early_serial8250_write(struct console *console, +static void early_serial8250_write(struct console *console, const char *s, unsigned int count) { struct earlycon_device *device = console->data; -- cgit v1.1 From a17e74c533c1be241177c83545e3ec0a39db8a68 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 25 Jul 2017 20:39:57 +0300 Subject: serial: core: enforce type for upf_t when copying upf_t is a bitwise defined type and any assignment from different, but compatible, types makes static analyzer unhappy. drivers/tty/serial/serial_core.c:793:29: warning: incorrect type in assignment (different base types) drivers/tty/serial/serial_core.c:793:29: expected int [signed] flags drivers/tty/serial/serial_core.c:793:29: got restricted upf_t [usertype] flags drivers/tty/serial/serial_core.c:867:19: warning: incorrect type in assignment (different base types) drivers/tty/serial/serial_core.c:867:19: expected restricted upf_t [usertype] new_flags drivers/tty/serial/serial_core.c:867:19: got int [signed] flags Enforce corresponding types when upf_t being assigned. Note, we need __force attribute due to the scope of variable. It's being used in user space with plain old type while kernel uses bitwise one. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index f534a40..73ce4e2 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -744,7 +744,7 @@ static int uart_get_info(struct tty_port *port, struct serial_struct *retinfo) if (HIGH_BITS_OFFSET) retinfo->port_high = (long) uport->iobase >> HIGH_BITS_OFFSET; retinfo->irq = uport->irq; - retinfo->flags = uport->flags; + retinfo->flags = (__force int)uport->flags; retinfo->xmit_fifo_size = uport->fifosize; retinfo->baud_base = uport->uartclk / 16; retinfo->close_delay = jiffies_to_msecs(port->close_delay) / 10; @@ -818,7 +818,7 @@ static int uart_set_info(struct tty_struct *tty, struct tty_port *port, new_info->type != uport->type); old_flags = uport->flags; - new_flags = new_info->flags; + new_flags = (__force upf_t)new_info->flags; old_custom_divisor = uport->custom_divisor; if (!capable(CAP_SYS_ADMIN)) { -- cgit v1.1 From c7ac15ce89242e3c25fcc49fa4d00028285fab05 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 25 Jul 2017 20:39:58 +0300 Subject: serial: core: move UPF_NO_TXEN_TEST to quirks and rename First 16 bits in the flags field are user-visible except UPF_NO_TXEN_TEST. To keep it clean we introduce internal quirks and move UPF_NO_TXEN_TEST to them. Rename the constant to UPQ_NO_TXEN_TEST to distinguish with port flags. Users are converted accordingly. The quirks field might be extended later to hold the additional ones. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_core.c | 16 ++++++++-------- drivers/tty/serial/8250/8250_pci.c | 2 +- drivers/tty/serial/8250/8250_port.c | 2 +- include/linux/serial_core.h | 9 +++++---- 4 files changed, 15 insertions(+), 14 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index b5def35..3db9d6e 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -497,6 +497,11 @@ static void univ8250_rsa_support(struct uart_ops *ops) #define univ8250_rsa_support(x) do { } while (0) #endif /* CONFIG_SERIAL_8250_RSA */ +static inline void serial8250_apply_quirks(struct uart_8250_port *up) +{ + up->port.quirks |= skip_txen_test ? UPQ_NO_TXEN_TEST : 0; +} + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -577,9 +582,7 @@ serial8250_register_ports(struct uart_driver *drv, struct device *dev) up->port.dev = dev; - if (skip_txen_test) - up->port.flags |= UPF_NO_TXEN_TEST; - + serial8250_apply_quirks(up); uart_add_one_port(drv, &up->port); } } @@ -1006,9 +1009,6 @@ int serial8250_register_8250_port(struct uart_8250_port *up) if (up->port.dev) uart->port.dev = up->port.dev; - if (skip_txen_test) - uart->port.flags |= UPF_NO_TXEN_TEST; - if (up->port.flags & UPF_FIXED_TYPE) uart->port.type = up->port.type; @@ -1047,6 +1047,7 @@ int serial8250_register_8250_port(struct uart_8250_port *up) serial8250_isa_config(0, &uart->port, &uart->capabilities); + serial8250_apply_quirks(uart); ret = uart_add_one_port(&serial8250_reg, &uart->port); if (ret == 0) ret = uart->port.line; @@ -1081,11 +1082,10 @@ void serial8250_unregister_port(int line) uart_remove_one_port(&serial8250_reg, &uart->port); if (serial8250_isa_devs) { uart->port.flags &= ~UPF_BOOT_AUTOCONF; - if (skip_txen_test) - uart->port.flags |= UPF_NO_TXEN_TEST; uart->port.type = PORT_UNKNOWN; uart->port.dev = &serial8250_isa_devs->dev; uart->capabilities = 0; + serial8250_apply_quirks(uart); uart_add_one_port(&serial8250_reg, &uart->port); } else { uart->port.dev = NULL; diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 553823c..e82d7d5 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1548,7 +1548,7 @@ static int skip_tx_en_setup(struct serial_private *priv, const struct pciserial_board *board, struct uart_8250_port *port, int idx) { - port->port.flags |= UPF_NO_TXEN_TEST; + port->port.quirks |= UPQ_NO_TXEN_TEST; dev_dbg(&priv->dev->dev, "serial8250: skipping TxEn test for device [%04x:%04x] subsystem [%04x:%04x]\n", priv->dev->vendor, priv->dev->device, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index a5fe0e6..25aae66 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2304,7 +2304,7 @@ int serial8250_do_startup(struct uart_port *port) * test if we receive TX irq. This way, we'll never enable * UART_BUG_TXEN. */ - if (up->port.flags & UPF_NO_TXEN_TEST) + if (up->port.quirks & UPQ_NO_TXEN_TEST) goto dont_test_tx_en; /* diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 1775500..8dc24c8 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -20,7 +20,7 @@ #ifndef LINUX_SERIAL_CORE_H #define LINUX_SERIAL_CORE_H - +#include #include #include #include @@ -144,7 +144,7 @@ struct uart_port { unsigned char x_char; /* xon/xoff char */ unsigned char regshift; /* reg offset shift */ unsigned char iotype; /* io access style */ - unsigned char unused1; + unsigned char quirks; /* internal quirks */ #define UPIO_PORT (SERIAL_IO_PORT) /* 8b I/O port access */ #define UPIO_HUB6 (SERIAL_IO_HUB6) /* Hub6 ISA card */ @@ -155,6 +155,9 @@ struct uart_port { #define UPIO_MEM32BE (SERIAL_IO_MEM32BE) /* 32b big endian */ #define UPIO_MEM16 (SERIAL_IO_MEM16) /* 16b little endian */ + /* quirks must be updated while holding port mutex */ +#define UPQ_NO_TXEN_TEST BIT(0) + unsigned int read_status_mask; /* driver specific */ unsigned int ignore_status_mask; /* driver specific */ struct uart_state *state; /* pointer to parent state */ @@ -175,7 +178,6 @@ struct uart_port { * [for bit definitions in the UPF_CHANGE_MASK] * * Bits [0..UPF_LAST_USER] are userspace defined/visible/changeable - * except bit 15 (UPF_NO_TXEN_TEST) which is masked off. * The remaining bits are serial-core specific and not modifiable by * userspace. */ @@ -192,7 +194,6 @@ struct uart_port { #define UPF_SPD_SHI ((__force upf_t) ASYNC_SPD_SHI /* 12 */ ) #define UPF_LOW_LATENCY ((__force upf_t) ASYNC_LOW_LATENCY /* 13 */ ) #define UPF_BUGGY_UART ((__force upf_t) ASYNC_BUGGY_UART /* 14 */ ) -#define UPF_NO_TXEN_TEST ((__force upf_t) (1 << 15)) #define UPF_MAGIC_MULTIPLIER ((__force upf_t) ASYNC_MAGIC_MULTIPLIER /* 16 */ ) #define UPF_NO_THRE_TEST ((__force upf_t) (1 << 19)) -- cgit v1.1 From 7d8905d064058f4b65057e0101588f362f288bc0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 24 Jul 2017 20:28:32 +0300 Subject: serial: 8250_pci: Enable device after we check black list If the board we are guessing has been listed in black list we don't need to enable it twice. The associated driver, if any, will take care about proper initialization. To achieve this we split out two helper functions, i.e. serial_pci_is_class_communication() and serial_pci_is_blacklisted() which will be called before pcim_enable_device(). We can do this since PCI specification requires class, device and vendor ID registers to be always present in the configuration space. As an example what happens before this patch applied (These are some debug prints, don't search for them in kernel sources): serial 0000:00:04.1: Mapped GSI28 to IRQ28 serial 0000:00:04.2: Mapped GSI29 to IRQ29 serial 0000:00:04.3: Mapped GSI54 to IRQ54 8250_mid 0000:00:04.1: Mapped GSI28 to IRQ28 8250_mid 0000:00:04.2: Mapped GSI29 to IRQ29 8250_mid 0000:00:04.3: Mapped GSI54 to IRQ54 After we will have just last three lines out of above. 8250_mid 0000:00:04.1: Mapped GSI28 to IRQ28 8250_mid 0000:00:04.2: Mapped GSI29 to IRQ29 8250_mid 0000:00:04.3: Mapped GSI54 to IRQ54 While here, correct a value of error code mentioned in the comment of serial_pci_guess_board(). Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_pci.c | 39 ++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index e82d7d5..0c101a7 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -3384,17 +3384,8 @@ static const struct pci_device_id blacklist[] = { { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, }; -/* - * Given a complete unknown PCI device, try to use some heuristics to - * guess what the configuration might be, based on the pitiful PCI - * serial specs. Returns 0 on success, 1 on failure. - */ -static int -serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) +static int serial_pci_is_class_communication(struct pci_dev *dev) { - const struct pci_device_id *bldev; - int num_iomem, num_port, first_port = -1, i; - /* * If it is not a communications device or the programming * interface is greater than 6, give up. @@ -3407,6 +3398,13 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) (dev->class & 0xff) > 6) return -ENODEV; + return 0; +} + +static int serial_pci_is_blacklisted(struct pci_dev *dev) +{ + const struct pci_device_id *bldev; + /* * Do not access blacklisted devices that are known not to * feature serial ports or are handled by other modules. @@ -3419,6 +3417,19 @@ serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) return -ENODEV; } + return 0; +} + +/* + * Given a complete unknown PCI device, try to use some heuristics to + * guess what the configuration might be, based on the pitiful PCI + * serial specs. Returns 0 on success, -ENODEV on failure. + */ +static int +serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) +{ + int num_iomem, num_port, first_port = -1, i; + num_iomem = num_port = 0; for (i = 0; i < PCI_NUM_BAR_RESOURCES; i++) { if (pci_resource_flags(dev, i) & IORESOURCE_IO) { @@ -3639,6 +3650,14 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) board = &pci_boards[ent->driver_data]; + rc = serial_pci_is_class_communication(dev); + if (rc) + return rc; + + rc = serial_pci_is_blacklisted(dev); + if (rc) + return rc; + rc = pcim_enable_device(dev); pci_save_state(dev); if (rc) -- cgit v1.1 From 68c338eaa0bf3e399a1b96ac35d909f0b475208f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2017 12:59:40 +0200 Subject: serial: fsl_lpuart: clear unsupported options in .rs485_config() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The struct serial_rs485 parameter is both input and output and is supposed to hold the actually used configuration on return. So clear unsupported settings. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 5b4721b..d24270f 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -1076,6 +1076,11 @@ static int lpuart_config_rs485(struct uart_port *port, ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); writeb(modem, sport->port.membase + UARTMODEM); + /* clear unsupported configurations */ + rs485->delay_rts_before_send = 0; + rs485->delay_rts_after_send = 0; + rs485->flags &= ~SER_RS485_RX_DURING_TX; + if (rs485->flags & SER_RS485_ENABLED) { /* Enable auto RS-485 RTS mode */ modem |= UARTMODEM_TXRTSE; -- cgit v1.1 From a449f12bfe2f56c7975816d870c0bc0ef4d03125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 18 Jul 2017 12:59:41 +0200 Subject: dt-bindings: serial/rs485: make rs485-rts-delay optional MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are a few device trees that specify one of the already optional properties without also having the up to now required property rs485-rts-delay. Additionally there is no technical reason to require rs485-rts-delay and that's also what most drivers implement. So give existing users and implementers a blessing and document rs485-rts-delay as optional. Signed-off-by: Uwe Kleine-König Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/rs485.txt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/devicetree/bindings/serial/rs485.txt b/Documentation/devicetree/bindings/serial/rs485.txt index 32b1fa1..b841593 100644 --- a/Documentation/devicetree/bindings/serial/rs485.txt +++ b/Documentation/devicetree/bindings/serial/rs485.txt @@ -5,14 +5,13 @@ the built-in half-duplex mode. The properties described hereafter shall be given to a half-duplex capable UART node. -Required properties: +Optional properties: - rs485-rts-delay: prop-encoded-array where: * a is the delay between rts signal and beginning of data sent in milliseconds. it corresponds to the delay before sending data. * b is the delay between end of data sent and rts signal in milliseconds it corresponds to the delay after sending data and actual release of the line. - -Optional properties: + If this property is not specified, <0 0> is assumed. - linux,rs485-enabled-at-boot-time: empty property telling to enable the rs485 feature at boot time. It can be disabled later with proper ioctl. - rs485-rx-during-tx: empty property that enables the receiving of data even -- cgit v1.1 From 979990c6284814617d8f2179d197f72ff62b5d85 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Jun 2017 23:10:41 +0200 Subject: tty: improve tty_insert_flip_char() fast path kernelci.org reports a crazy stack usage for the VT code when CONFIG_KASAN is enabled: drivers/tty/vt/keyboard.c: In function 'kbd_keycode': drivers/tty/vt/keyboard.c:1452:1: error: the frame size of 2240 bytes is larger than 2048 bytes [-Werror=frame-larger-than=] The problem is that tty_insert_flip_char() gets inlined many times into kbd_keycode(), and also into other functions, and each copy requires 128 bytes for stack redzone to check for a possible out-of-bounds access on the 'ch' and 'flags' arguments that are passed into tty_insert_flip_string_flags as a variable-length string. This introduces a new __tty_insert_flip_char() function for the slow path, which receives the two arguments by value. This completely avoids the problem and the stack usage goes back down to around 100 bytes. Without KASAN, this is also slightly better, as we don't have to spill the arguments to the stack but can simply pass 'ch' and 'flag' in registers, saving a few bytes in .text for each call site. This should be backported to linux-4.0 or later, which first introduced the stack sanitizer in the kernel. Cc: stable@vger.kernel.org Fixes: c420f167db8c ("kasan: enable stack instrumentation") Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 24 ++++++++++++++++++++++++ include/linux/tty_flip.h | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 4e7a4e9..2da05fa 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -362,6 +362,30 @@ int tty_insert_flip_string_flags(struct tty_port *port, EXPORT_SYMBOL(tty_insert_flip_string_flags); /** + * __tty_insert_flip_char - Add one character to the tty buffer + * @port: tty port + * @ch: character + * @flag: flag byte + * + * Queue a single byte to the tty buffering, with an optional flag. + * This is the slow path of tty_insert_flip_char. + */ +int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) +{ + struct tty_buffer *tb = port->buf.tail; + int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; + + if (!tty_buffer_request_room(port, 1)) + return 0; + + *flag_buf_ptr(tb, tb->used) = flag; + *char_buf_ptr(tb, tb->used++) = ch; + + return 1; +} +EXPORT_SYMBOL(__tty_insert_flip_char); + +/** * tty_schedule_flip - push characters to ldisc * @port: tty port to push from * diff --git a/include/linux/tty_flip.h b/include/linux/tty_flip.h index c28dd52..d43837f 100644 --- a/include/linux/tty_flip.h +++ b/include/linux/tty_flip.h @@ -12,6 +12,7 @@ extern int tty_prepare_flip_string(struct tty_port *port, unsigned char **chars, size_t size); extern void tty_flip_buffer_push(struct tty_port *port); void tty_schedule_flip(struct tty_port *port); +int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag); static inline int tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) @@ -26,7 +27,7 @@ static inline int tty_insert_flip_char(struct tty_port *port, *char_buf_ptr(tb, tb->used++) = ch; return 1; } - return tty_insert_flip_string_flags(port, &ch, &flag, 1); + return __tty_insert_flip_char(port, ch, flag); } static inline int tty_insert_flip_string(struct tty_port *port, -- cgit v1.1 From 065ea0a7afd64d6cf3464bdd1d8cd227527e2045 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Tue, 20 Jun 2017 23:10:42 +0200 Subject: tty: improve tty_insert_flip_char() slow path While working on improving the fast path of tty_insert_flip_char(), I noticed that by calling tty_buffer_request_room(), we needlessly move to the separate flag buffer mode for the tty, even when all characters use TTY_NORMAL as the flag. This changes the code to call __tty_buffer_request_room() with the correct flag, which will then allocate a regular buffer when it rounds out of space but no special flags have been used. I'm guessing that this is the behavior that Peter Hurley intended when he introduced the compacted flip buffers. Fixes: acc0f67f307f ("tty: Halve flip buffer GFP_ATOMIC memory consumption") Cc: Peter Hurley Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 2da05fa..6a85636 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -375,10 +375,11 @@ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) struct tty_buffer *tb = port->buf.tail; int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; - if (!tty_buffer_request_room(port, 1)) + if (!__tty_buffer_request_room(port, 1, flags)) return 0; - *flag_buf_ptr(tb, tb->used) = flag; + if (~tb->flags & TTYB_NORMAL) + *flag_buf_ptr(tb, tb->used) = flag; *char_buf_ptr(tb, tb->used++) = ch; return 1; -- cgit v1.1 From 8a5a90a2a477b86a3dc2eaa5a706db9bfdd647ca Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Wed, 2 Aug 2017 13:11:39 +0200 Subject: tty: fix __tty_insert_flip_char regression Sergey noticed a small but fatal mistake in __tty_insert_flip_char, leading to an oops in an interrupt handler when using any serial port. The problem is that I accidentally took the tty_buffer pointer before calling __tty_buffer_request_room(), which replaces the buffer. This moves the pointer lookup to the right place after allocating the new buffer space. Fixes: 979990c62848 ("tty: improve tty_insert_flip_char() fast path") Reported-by: Sergey Senozhatsky Tested-by: Sergey Senozhatsky Signed-off-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/tty_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c index 6a85636..f8eba1c5 100644 --- a/drivers/tty/tty_buffer.c +++ b/drivers/tty/tty_buffer.c @@ -372,12 +372,13 @@ EXPORT_SYMBOL(tty_insert_flip_string_flags); */ int __tty_insert_flip_char(struct tty_port *port, unsigned char ch, char flag) { - struct tty_buffer *tb = port->buf.tail; + struct tty_buffer *tb; int flags = (flag == TTY_NORMAL) ? TTYB_NORMAL : 0; if (!__tty_buffer_request_room(port, 1, flags)) return 0; + tb = port->buf.tail; if (~tb->flags & TTYB_NORMAL) *flag_buf_ptr(tb, tb->used) = flag; *char_buf_ptr(tb, tb->used++) = ch; -- cgit v1.1 From d054b3acb71862c297b923ca24120788c40261e3 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Fri, 11 Aug 2017 13:47:28 +0200 Subject: tty: amba-pl011: constify vendor_data structures These vendor_data structures are only stored in the vendor field of the uart_amba_port structure, as defined in the same file, and this field is declared as const. Thus the vendor_data structures can be const too. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 1888d16..ba4e795 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -128,7 +128,7 @@ static struct vendor_data vendor_arm = { .get_fifosize = get_fifosize_arm, }; -static struct vendor_data vendor_sbsa = { +static const struct vendor_data vendor_sbsa = { .reg_offset = pl011_std_offsets, .fr_busy = UART01x_FR_BUSY, .fr_dsr = UART01x_FR_DSR, @@ -143,7 +143,7 @@ static struct vendor_data vendor_sbsa = { }; #ifdef CONFIG_ACPI_SPCR_TABLE -static struct vendor_data vendor_qdt_qdf2400_e44 = { +static const struct vendor_data vendor_qdt_qdf2400_e44 = { .reg_offset = pl011_std_offsets, .fr_busy = UART011_FR_TXFE, .fr_dsr = UART01x_FR_DSR, -- cgit v1.1 From 5337e5490fa2e6056849228335f0fb168f3b35bc Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 23 Aug 2017 22:17:58 +0530 Subject: serial: pl010: constify amba_id amba_id are not supposed to change at runtime. All functions working with const amba_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl010.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/amba-pl010.c b/drivers/tty/serial/amba-pl010.c index 24180ad..9ec4b8d 100644 --- a/drivers/tty/serial/amba-pl010.c +++ b/drivers/tty/serial/amba-pl010.c @@ -814,7 +814,7 @@ static int pl010_resume(struct device *dev) static SIMPLE_DEV_PM_OPS(pl010_dev_pm_ops, pl010_suspend, pl010_resume); -static struct amba_id pl010_ids[] = { +static const struct amba_id pl010_ids[] = { { .id = 0x00041010, .mask = 0x000fffff, -- cgit v1.1 From a704ddc2504610ba4227d1ae036e962e530c8c0b Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Wed, 23 Aug 2017 22:18:21 +0530 Subject: serial: pl011: constify amba_id amba_id are not supposed to change at runtime. All functions working with const amba_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/amba-pl011.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ba4e795..111e6a9 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2787,7 +2787,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { }, }; -static struct amba_id pl011_ids[] = { +static const struct amba_id pl011_ids[] = { { .id = 0x00041011, .mask = 0x000fffff, -- cgit v1.1 From a61d9e6e30d48b67fe864ba4bb9babac7b178312 Mon Sep 17 00:00:00 2001 From: Gerald Baeza Date: Mon, 31 Jul 2017 09:31:52 +0000 Subject: serial: stm32: fix pio transmit timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 100µs was too short for low speed transmission (9600bps) Signed-off-by: Gerald Baeza Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 72c0ec1..b16e7e7 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -203,7 +203,7 @@ static void stm32_transmit_chars_pio(struct uart_port *port) ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, isr, (isr & USART_SR_TXE), - 10, 100); + 10, 100000); if (ret) dev_err(port->dev, "tx empty not set\n"); -- cgit v1.1 From e5a74707314fbb4ef685d6e218073064f47315e2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:41 +0200 Subject: serial: owl: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/owl-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/owl-uart.c b/drivers/tty/serial/owl-uart.c index 683b054..b9c85936 100644 --- a/drivers/tty/serial/owl-uart.c +++ b/drivers/tty/serial/owl-uart.c @@ -473,7 +473,7 @@ static void owl_uart_config_port(struct uart_port *port, int flags) } } -static struct uart_ops owl_uart_ops = { +static const struct uart_ops owl_uart_ops = { .set_mctrl = owl_uart_set_mctrl, .get_mctrl = owl_uart_get_mctrl, .tx_empty = owl_uart_tx_empty, -- cgit v1.1 From 921469f7fb972f7c6146a6a82693bd45b3beec21 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:40 +0200 Subject: serial: meson: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/meson_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 42e4a4c..07c0f98 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -424,7 +424,7 @@ static void meson_uart_config_port(struct uart_port *port, int flags) } } -static struct uart_ops meson_uart_ops = { +static const struct uart_ops meson_uart_ops = { .set_mctrl = meson_uart_set_mctrl, .get_mctrl = meson_uart_get_mctrl, .tx_empty = meson_uart_tx_empty, -- cgit v1.1 From ec085c5a51b768947ca481f90b66653e36b3c566 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Tue, 8 Aug 2017 17:42:46 -0500 Subject: tty: serial: sprd: fix error return code in sprd_probe() platform_get_irq() returns an error code, but the sprd_serial driver ignores it and always returns -ENODEV. This is not correct and, prevents -EPROBE_DEFER from being propagated properly. Also, notice that platform_get_irq() no longer returns 0 on error: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=e330b9a6bb35dc7097a4f02cb1ae7b6f96df92af Print and propagate the return value of platform_get_irq on failure. This issue was detected with the help of Coccinelle. Signed-off-by: Gustavo A. R. Silva Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sprd_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index f758fe6..e902494 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -731,8 +731,8 @@ static int sprd_probe(struct platform_device *pdev) irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(&pdev->dev, "not provide irq resource\n"); - return -ENODEV; + dev_err(&pdev->dev, "not provide irq resource: %d\n", irq); + return irq; } up->irq = irq; -- cgit v1.1 From 62f466ee0398d9c67e7a867090324794afff1525 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 7 Aug 2017 14:44:11 -0300 Subject: serial: pch_uart: Remove unneeded NULL check There is no need to do a NULL check for debugfs_remove(). Quoting Documentation/filesystems/debugfs.txt: "The dentry value can be NULL, in which case nothing will be removed." , so remove the unneeded NULL check. Signed-off-by: Fabio Estevam Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index d3796dc..3788198 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -1862,8 +1862,7 @@ static void pch_uart_exit_port(struct eg20t_port *priv) { #ifdef CONFIG_DEBUG_FS - if (priv->debugfs) - debugfs_remove(priv->debugfs); + debugfs_remove(priv->debugfs); #endif uart_remove_one_port(&pch_uart_driver, &priv->port); free_page((unsigned long)priv->rxbuf.buf); -- cgit v1.1 From 4d691f75924171787bce2853eb236f89b62ec736 Mon Sep 17 00:00:00 2001 From: Neeraj Upadhyay Date: Mon, 7 Aug 2017 11:51:25 +0530 Subject: tty: serial: msm: Move request_irq to the end of startup Move the request_irq() call to the end of the msm_startup(), so that we don't handle interrupts while msm_startup() is running. This avoids potential races while initialization is in progress. For example, consider below scenario where rx handler reads the intermediate value of dma->chan, set in msm_request_rx_dma(), and tries to do dma mapping, which results in data abort. uart_port_startup() msm_startup() request_irq() ... msm_request_rx_dma() ... dma->chan = dma_request_slave_channel_reason(dev, "rx"); msm_uart_irq() msm_handle_rx_dm() msm_start_rx_dma() dma->desc = dma_map_single() Signed-off-by: Neeraj Upadhyay Reviewd-by: Andy Gross Reviewed-by: Stephen Boyd Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/msm_serial.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 6788e75..1db79ee 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1175,11 +1175,6 @@ static int msm_startup(struct uart_port *port) snprintf(msm_port->name, sizeof(msm_port->name), "msm_serial%d", port->line); - ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH, - msm_port->name, port); - if (unlikely(ret)) - return ret; - msm_init_clock(port); if (likely(port->fifosize > 12)) @@ -1206,7 +1201,21 @@ static int msm_startup(struct uart_port *port) msm_request_rx_dma(msm_port, msm_port->uart.mapbase); } + ret = request_irq(port->irq, msm_uart_irq, IRQF_TRIGGER_HIGH, + msm_port->name, port); + if (unlikely(ret)) + goto err_irq; + return 0; + +err_irq: + if (msm_port->is_uartdm) + msm_release_dma(msm_port); + + clk_disable_unprepare(msm_port->pclk); + clk_disable_unprepare(msm_port->clk); + + return ret; } static void msm_shutdown(struct uart_port *port) -- cgit v1.1 From 3d6bcddf5490e86f2fb384329ce6bb8c36dc69a0 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 13 Aug 2017 17:47:39 +0300 Subject: serial: fsl_lpuart: Avoid using irq_wake flag There is no need to duplicate a flag which IRQ core takes care of. Replace custom flag by IRQ core API that retrieves its state. Cc: Bhuvanchandra DV Cc: Dong Aisheng Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index d24270f..849c1f9 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2264,6 +2264,7 @@ static int lpuart_suspend(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); unsigned long temp; + bool irq_wake; if (lpuart_is_32(sport)) { /* disable Rx/Tx and interrupts */ @@ -2279,6 +2280,9 @@ static int lpuart_suspend(struct device *dev) uart_suspend_port(&lpuart_reg, &sport->port); + /* uart_suspend_port() might set wakeup flag */ + irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); + if (sport->lpuart_dma_rx_use) { /* * EDMA driver during suspend will forcefully release any @@ -2287,7 +2291,7 @@ static int lpuart_suspend(struct device *dev) * cannot resume as as expected, hence gracefully release the * Rx DMA path before suspend and start Rx DMA path on resume. */ - if (sport->port.irq_wake) { + if (irq_wake) { del_timer_sync(&sport->lpuart_timer); lpuart_dma_rx_free(&sport->port); } @@ -2302,7 +2306,7 @@ static int lpuart_suspend(struct device *dev) dmaengine_terminate_all(sport->dma_tx_chan); } - if (sport->port.suspended && !sport->port.irq_wake) + if (sport->port.suspended && !irq_wake) clk_disable_unprepare(sport->clk); return 0; @@ -2311,9 +2315,10 @@ static int lpuart_suspend(struct device *dev) static int lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); + bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); unsigned long temp; - if (sport->port.suspended && !sport->port.irq_wake) + if (sport->port.suspended && !irq_wake) clk_prepare_enable(sport->clk); if (lpuart_is_32(sport)) { @@ -2330,7 +2335,7 @@ static int lpuart_resume(struct device *dev) } if (sport->lpuart_dma_rx_use) { - if (sport->port.irq_wake) { + if (irq_wake) { if (!lpuart_start_rx_dma(sport)) rx_dma_timer_init(sport); else -- cgit v1.1 From 7b8a0353f39d579a654d5920e656f2f91006b6c1 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 13 Aug 2017 17:47:40 +0300 Subject: serial: st-asc: Avoid using irq_wake flag There is no need to duplicate a flag which IRQ core takes care of. Replace custom flag by IRQ core API that retrieves its state. Cc: Patrice Chotard Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index 6b0ca65..b313a79 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -310,7 +310,7 @@ static void asc_receive_chars(struct uart_port *port) if (mode == ASC_CTL_MODE_8BIT || mode == ASC_CTL_MODE_8BIT_PAR) ignore_pe = true; - if (port->irq_wake) + if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) pm_wakeup_event(tport->tty->dev, 0); while ((status = asc_in(port, ASC_STA)) & ASC_STA_RBF) { -- cgit v1.1 From 29d60981db522ce301e06e18d9edf8b31b233b89 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 13 Aug 2017 17:47:41 +0300 Subject: serial: stm32-usart: Avoid using irq_wake flag There is no need to duplicate a flag which IRQ core takes care of. Replace custom flag by IRQ core API that retrieves its state. Cc: Maxime Coquelin Cc: Alexandre Torgue Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index b16e7e7..03a58326 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -113,7 +113,7 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) u32 sr; char flag; - if (port->irq_wake) + if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) pm_wakeup_event(tport->tty->dev, 0); while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { -- cgit v1.1 From aef3ad103a686f21b746977d4ed21cc1af36f589 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Sun, 13 Aug 2017 17:47:42 +0300 Subject: serial: core: remove unneeded irq_wake flag There is no need to duplicate a flag which IRQ core takes care of. Replace custom flag by IRQ core API that retrieves its state. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 9 +++------ include/linux/serial_core.h | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 73ce4e2..220e1d0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -36,7 +36,7 @@ #include #include -#include +#include #include /* @@ -2083,8 +2083,7 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport) tty_dev = device_find_child(uport->dev, &match, serial_match_port); if (tty_dev && device_may_wakeup(tty_dev)) { - if (!enable_irq_wake(uport->irq)) - uport->irq_wake = 1; + enable_irq_wake(uport->irq); put_device(tty_dev); mutex_unlock(&port->mutex); return 0; @@ -2147,10 +2146,8 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport) tty_dev = device_find_child(uport->dev, &match, serial_match_port); if (!uport->suspended && device_may_wakeup(tty_dev)) { - if (uport->irq_wake) { + if (irqd_is_wakeup_set(irq_get_irq_data((uport->irq)))) disable_irq_wake(uport->irq); - uport->irq_wake = 0; - } put_device(tty_dev); mutex_unlock(&port->mutex); return 0; diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 8dc24c8..5553e04 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -247,7 +247,6 @@ struct uart_port { struct device *dev; /* parent device */ unsigned char hub6; /* this should be in the 8250 driver */ unsigned char suspended; - unsigned char irq_wake; unsigned char unused[2]; const char *name; /* port name */ struct attribute_group *attr_group; /* port specific attributes */ -- cgit v1.1 From 63e8d4394a2d226803f47abd7287dbb6d21bf8e4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Aug 2017 16:58:20 +0300 Subject: serial: pch_uart: Make port type explicit It used to be a gap in port definitions after PORT_MAX_8250. Since the new drivers are coming the gap become shorter and shorter until the commit a2d6a987bfe4 ("serial: 8250: Add new port type for TI DA8xx/66AK2x") completely removed it. So, while type here is just a formality, make things a little bit more explicit for this driver and move port types to UAPI header. Note, it uses two types for now. Fixes: fddceb8b5399 ("tty: 8250: Add 64byte UART support for FSL platforms") Cc: Priyanka Jain Cc: Poonam Aggrwal Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pch_uart.c | 35 +++++++++++++++-------------------- include/uapi/linux/serial_core.h | 5 ++++- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index 3788198..ae8cfc8 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -46,11 +46,6 @@ enum { PCH_UART_HANDLED_LS_INT_SHIFT, }; -enum { - PCH_UART_8LINE, - PCH_UART_2LINE, -}; - #define PCH_UART_DRIVER_DEVICE "ttyPCH" /* Set the max number of UART port @@ -267,7 +262,7 @@ struct eg20t_port { /** * struct pch_uart_driver_data - private data structure for UART-DMA - * @port_type: The number of DMA channel + * @port_type: The type of UART port * @line_no: UART port line number (0, 1, 2...) */ struct pch_uart_driver_data { @@ -290,17 +285,17 @@ enum pch_uart_num_t { }; static struct pch_uart_driver_data drv_dat[] = { - [pch_et20t_uart0] = {PCH_UART_8LINE, 0}, - [pch_et20t_uart1] = {PCH_UART_2LINE, 1}, - [pch_et20t_uart2] = {PCH_UART_2LINE, 2}, - [pch_et20t_uart3] = {PCH_UART_2LINE, 3}, - [pch_ml7213_uart0] = {PCH_UART_8LINE, 0}, - [pch_ml7213_uart1] = {PCH_UART_2LINE, 1}, - [pch_ml7213_uart2] = {PCH_UART_2LINE, 2}, - [pch_ml7223_uart0] = {PCH_UART_8LINE, 0}, - [pch_ml7223_uart1] = {PCH_UART_2LINE, 1}, - [pch_ml7831_uart0] = {PCH_UART_8LINE, 0}, - [pch_ml7831_uart1] = {PCH_UART_2LINE, 1}, + [pch_et20t_uart0] = {PORT_PCH_8LINE, 0}, + [pch_et20t_uart1] = {PORT_PCH_2LINE, 1}, + [pch_et20t_uart2] = {PORT_PCH_2LINE, 2}, + [pch_et20t_uart3] = {PORT_PCH_2LINE, 3}, + [pch_ml7213_uart0] = {PORT_PCH_8LINE, 0}, + [pch_ml7213_uart1] = {PORT_PCH_2LINE, 1}, + [pch_ml7213_uart2] = {PORT_PCH_2LINE, 2}, + [pch_ml7223_uart0] = {PORT_PCH_8LINE, 0}, + [pch_ml7223_uart1] = {PORT_PCH_2LINE, 1}, + [pch_ml7831_uart0] = {PORT_PCH_8LINE, 0}, + [pch_ml7831_uart1] = {PORT_PCH_2LINE, 1}, }; #ifdef CONFIG_SERIAL_PCH_UART_CONSOLE @@ -1777,10 +1772,10 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, goto init_port_free_txbuf; switch (port_type) { - case PORT_UNKNOWN: + case PORT_PCH_8LINE: fifosize = 256; /* EG20T/ML7213: UART0 */ break; - case PORT_8250: + case PORT_PCH_2LINE: fifosize = 64; /* EG20T:UART1~3 ML7213: UART1~2*/ break; default: @@ -1804,7 +1799,7 @@ static struct eg20t_port *pch_uart_init_port(struct pci_dev *pdev, priv->fifo_size = fifosize; priv->uartclk = pch_uart_get_uartclk(); - priv->port_type = PORT_MAX_8250 + port_type + 1; + priv->port_type = port_type; priv->port.dev = &pdev->dev; priv->port.iobase = iobase; priv->port.membase = NULL; diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 38bea32..502aa23 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -57,7 +57,6 @@ #define PORT_RT2880 29 /* Ralink RT2880 internal UART */ #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */ #define PORT_DA830 31 /* TI DA8xx/66AK2x */ -#define PORT_MAX_8250 31 /* max port ID */ /* * ARM specific type numbers. These are not currently guaranteed @@ -77,6 +76,10 @@ #define PORT_SUNZILOG 38 #define PORT_SUNSAB 39 +/* Intel EG20 */ +#define PORT_PCH_8LINE 44 +#define PORT_PCH_2LINE 45 + /* DEC */ #define PORT_DZ 46 #define PORT_ZS 47 -- cgit v1.1 From 3f3dac7e4d815cb7f929c0ed98c3a45a86852e53 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Aug 2017 16:58:21 +0300 Subject: serial: Remove unused port type PORT_MFD is not in use since commit 1bd187de5364 ("x86, intel-mid: remove Intel MID specific serial support") Remove leftover. Fixes: 1bd187de5364 ("x86, intel-mid: remove Intel MID specific serial support") Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/serial_core.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 502aa23..00d3356 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -209,9 +209,6 @@ /* MAX310X */ #define PORT_MAX310X 94 -/* High Speed UART for Medfield */ -#define PORT_MFD 95 - /* TI OMAP-UART */ #define PORT_OMAP 96 -- cgit v1.1 From ee1c90cc2cea80638f559c552371ee6893ca9d9e Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 22 Aug 2017 16:58:22 +0300 Subject: serial: Fix port type numbering for TI DA8xx The UAPI has a global list of unique numbers for different port types. The commit a2d6a987bfe4 ("serial: 8250: Add new port type for TI DA8xx/66AK2x") introduced a new port type and brought the collision with two other port types. Reuse 95 for it instead. Fixes: a2d6a987bfe4 ("serial: 8250: Add new port type for TI DA8xx/66AK2x") Cc: David Lechner Cc: Sekhar Nori Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- include/uapi/linux/serial_core.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 00d3356..dc2d7cb 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -56,7 +56,6 @@ #define PORT_ALTR_16550_F128 28 /* Altera 16550 UART with 128 FIFOs */ #define PORT_RT2880 29 /* Ralink RT2880 internal UART */ #define PORT_16550A_FSL64 30 /* Freescale 16550 UART with 64 FIFOs */ -#define PORT_DA830 31 /* TI DA8xx/66AK2x */ /* * ARM specific type numbers. These are not currently guaranteed @@ -209,6 +208,9 @@ /* MAX310X */ #define PORT_MAX310X 94 +/* TI DA8xx/66AK2x */ +#define PORT_DA830 95 + /* TI OMAP-UART */ #define PORT_OMAP 96 -- cgit v1.1 From 43c61286839761a5275c889364fc2588a756f197 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 13 Aug 2017 22:11:24 +0300 Subject: serial: sh-sci: use of_property_read_bool() Use more compact of_property_read_bool() call for a boolean property instead of of_find_property() call in sci_parse_dt(). Signed-off-by: Sergei Shtylyov Reviewed-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index e08b16b..784dd42 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3073,8 +3073,7 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, p->type = SCI_OF_TYPE(match->data); p->regtype = SCI_OF_REGTYPE(match->data); - if (of_find_property(np, "uart-has-rtscts", NULL)) - sp->has_rtscts = true; + sp->has_rtscts = of_property_read_bool(np, "uart-has-rtscts"); return p; } -- cgit v1.1 From dde68266ba0da457954cf13c907494ab899ea714 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 17 Aug 2017 13:16:28 +0200 Subject: dt-bindings: serial: sh-sci: Add support for r8a77995 (H)SCIF Document support for the (H)SCIF serial ports in the Renesas R-Car D3 (r8a77995) SoC. No driver update is needed. Signed-off-by: Geert Uytterhoeven Acked-by: Simon Horman Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/renesas,sci-serial.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt index 8d27d1a..4fc9694 100644 --- a/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt +++ b/Documentation/devicetree/bindings/serial/renesas,sci-serial.txt @@ -41,6 +41,8 @@ Required properties: - "renesas,hscif-r8a7795" for R8A7795 (R-Car H3) HSCIF compatible UART. - "renesas,scif-r8a7796" for R8A7796 (R-Car M3-W) SCIF compatible UART. - "renesas,hscif-r8a7796" for R8A7796 (R-Car M3-W) HSCIF compatible UART. + - "renesas,scif-r8a77995" for R8A77995 (R-Car D3) SCIF compatible UART. + - "renesas,hscif-r8a77995" for R8A77995 (R-Car D3) HSCIF compatible UART. - "renesas,scifa-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFA compatible UART. - "renesas,scifb-sh73a0" for SH73A0 (SH-Mobile AG5) SCIFB compatible UART. - "renesas,rcar-gen1-scif" for R-Car Gen1 SCIF compatible UART, -- cgit v1.1 From d77dc47fce23daf57f60cb407698108229a33e8c Mon Sep 17 00:00:00 2001 From: Himanshu Jha Date: Sun, 27 Aug 2017 12:01:41 +0530 Subject: tty: serial: 8250_mtk: Use PTR_ERR_OR_ZERO Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Signed-off-by: Himanshu Jha Reviewed-by: Matthias Brugger Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_mtk.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index ce0cc47..fb45770 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -171,10 +171,7 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, } data->bus_clk = devm_clk_get(&pdev->dev, "bus"); - if (IS_ERR(data->bus_clk)) - return PTR_ERR(data->bus_clk); - - return 0; + return PTR_ERR_OR_ZERO(data->bus_clk); } static int mtk8250_probe(struct platform_device *pdev) -- cgit v1.1 From a6845e1e1b781933ed7f54919f5ea4a108d1b9f2 Mon Sep 17 00:00:00 2001 From: Rafael Gago Date: Mon, 31 Jul 2017 10:46:42 +0200 Subject: serial: core: Consider rs485 settings to drive RTS Previously the rs485 settings weren't considered when setting the RTS line, so e.g. closing and reopening a port made serial_core to drive the line as if rs485 was disabled. This patch fixes those issues. Signed-off-by: Rafael Gago Castano Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 34 +++++++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 9 deletions(-) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 220e1d0..3a14ccc 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -165,6 +165,27 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear) #define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0) #define uart_clear_mctrl(port, clear) uart_update_mctrl(port, 0, clear) +static void uart_port_dtr_rts(struct uart_port *uport, int raise) +{ + int rs485_on = uport->rs485_config && + (uport->rs485.flags & SER_RS485_ENABLED); + int RTS_after_send = !!(uport->rs485.flags & SER_RS485_RTS_AFTER_SEND); + + if (raise) { + if (rs485_on && !RTS_after_send) { + uart_set_mctrl(uport, TIOCM_DTR); + uart_clear_mctrl(uport, TIOCM_RTS); + } else { + uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + } + } else { + unsigned int clear = TIOCM_DTR; + + clear |= (!rs485_on || !RTS_after_send) ? TIOCM_RTS : 0; + uart_clear_mctrl(uport, clear); + } +} + /* * Startup the port. This will be called once per open. All calls * will be serialised by the per-port mutex. @@ -214,7 +235,7 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, * port is open and ready to respond. */ if (init_hw && C_BAUD(tty)) - uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR); + uart_port_dtr_rts(uport, 1); } /* @@ -272,7 +293,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) uport->cons->cflag = tty->termios.c_cflag; if (!tty || C_HUPCL(tty)) - uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); + uart_port_dtr_rts(uport, 0); uart_port_shutdown(port); } @@ -1658,7 +1679,7 @@ static int uart_carrier_raised(struct tty_port *port) return 0; } -static void uart_dtr_rts(struct tty_port *port, int onoff) +static void uart_dtr_rts(struct tty_port *port, int raise) { struct uart_state *state = container_of(port, struct uart_state, port); struct uart_port *uport; @@ -1666,12 +1687,7 @@ static void uart_dtr_rts(struct tty_port *port, int onoff) uport = uart_port_ref(state); if (!uport) return; - - if (onoff) - uart_set_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - else - uart_clear_mctrl(uport, TIOCM_DTR | TIOCM_RTS); - + uart_port_dtr_rts(uport, raise); uart_port_deref(uport); } -- cgit v1.1 From 6e0a5de2136b26bd0b3501f2f362abfffeb47d1e Mon Sep 17 00:00:00 2001 From: Rafael Gago Date: Mon, 31 Jul 2017 10:46:43 +0200 Subject: serial: 8250: Use hrtimers for rs485 delays Previously the timers where based on the classic timers, giving a too coarse resolution on systems with configs of less than 1000 HZ. This patch changes the rs485 timers to hrtimers. Signed-off-by: Rafael Gago Castano Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 63 +++++++++++++++++++++++-------------- include/linux/serial_8250.h | 7 +++-- 2 files changed, 44 insertions(+), 26 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 25aae66..6b745e4 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -37,7 +37,7 @@ #include #include #include -#include +#include #include #include @@ -553,8 +553,8 @@ static inline void serial8250_em485_rts_after_send(struct uart_8250_port *p) serial8250_out_MCR(p, mcr); } -static void serial8250_em485_handle_start_tx(unsigned long arg); -static void serial8250_em485_handle_stop_tx(unsigned long arg); +static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t); +static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t); void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p) { @@ -609,12 +609,14 @@ int serial8250_em485_init(struct uart_8250_port *p) if (!p->em485) return -ENOMEM; - setup_timer(&p->em485->stop_tx_timer, - serial8250_em485_handle_stop_tx, (unsigned long)p); - setup_timer(&p->em485->start_tx_timer, - serial8250_em485_handle_start_tx, (unsigned long)p); + hrtimer_init(&p->em485->stop_tx_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + hrtimer_init(&p->em485->start_tx_timer, CLOCK_MONOTONIC, + HRTIMER_MODE_REL); + p->em485->stop_tx_timer.function = &serial8250_em485_handle_stop_tx; + p->em485->start_tx_timer.function = &serial8250_em485_handle_start_tx; + p->em485->port = p; p->em485->active_timer = NULL; - serial8250_em485_rts_after_send(p); return 0; @@ -639,8 +641,8 @@ void serial8250_em485_destroy(struct uart_8250_port *p) if (!p->em485) return; - del_timer(&p->em485->start_tx_timer); - del_timer(&p->em485->stop_tx_timer); + hrtimer_cancel(&p->em485->start_tx_timer); + hrtimer_cancel(&p->em485->stop_tx_timer); kfree(p->em485); p->em485 = NULL; @@ -1435,12 +1437,13 @@ static void __do_stop_tx_rs485(struct uart_8250_port *p) serial_port_out(&p->port, UART_IER, p->ier); } } - -static void serial8250_em485_handle_stop_tx(unsigned long arg) +static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) { - struct uart_8250_port *p = (struct uart_8250_port *)arg; - struct uart_8250_em485 *em485 = p->em485; + struct uart_8250_em485 *em485; + struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); + p = em485->port; serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); @@ -1451,6 +1454,16 @@ static void serial8250_em485_handle_stop_tx(unsigned long arg) } spin_unlock_irqrestore(&p->port.lock, flags); serial8250_rpm_put(p); + return HRTIMER_NORESTART; +} + +static void start_hrtimer_ms(struct hrtimer *hrt, unsigned long msec) +{ + long sec = msec / 1000; + long nsec = (msec % 1000) * 1000000; + ktime_t t = ktime_set(sec, nsec); + + hrtimer_start(hrt, t, HRTIMER_MODE_REL); } static void __stop_tx_rs485(struct uart_8250_port *p) @@ -1463,8 +1476,8 @@ static void __stop_tx_rs485(struct uart_8250_port *p) */ if (p->port.rs485.delay_rts_after_send > 0) { em485->active_timer = &em485->stop_tx_timer; - mod_timer(&em485->stop_tx_timer, jiffies + - p->port.rs485.delay_rts_after_send * HZ / 1000); + start_hrtimer_ms(&em485->stop_tx_timer, + p->port.rs485.delay_rts_after_send); } else { __do_stop_tx_rs485(p); } @@ -1494,8 +1507,8 @@ static inline void __stop_tx(struct uart_8250_port *p) if ((lsr & BOTH_EMPTY) != BOTH_EMPTY) return; - del_timer(&em485->start_tx_timer); em485->active_timer = NULL; + hrtimer_cancel(&em485->start_tx_timer); __stop_tx_rs485(p); } @@ -1558,8 +1571,9 @@ static inline void start_tx_rs485(struct uart_port *port) if (!(up->port.rs485.flags & SER_RS485_RX_DURING_TX)) serial8250_stop_rx(&up->port); - del_timer(&em485->stop_tx_timer); em485->active_timer = NULL; + if (hrtimer_is_queued(&em485->stop_tx_timer)) + hrtimer_cancel(&em485->stop_tx_timer); mcr = serial8250_in_MCR(up); if (!!(up->port.rs485.flags & SER_RS485_RTS_ON_SEND) != @@ -1572,8 +1586,8 @@ static inline void start_tx_rs485(struct uart_port *port) if (up->port.rs485.delay_rts_before_send > 0) { em485->active_timer = &em485->start_tx_timer; - mod_timer(&em485->start_tx_timer, jiffies + - up->port.rs485.delay_rts_before_send * HZ / 1000); + start_hrtimer_ms(&em485->start_tx_timer, + up->port.rs485.delay_rts_before_send); return; } } @@ -1581,11 +1595,13 @@ static inline void start_tx_rs485(struct uart_port *port) __start_tx(port); } -static void serial8250_em485_handle_start_tx(unsigned long arg) +static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) { - struct uart_8250_port *p = (struct uart_8250_port *)arg; - struct uart_8250_em485 *em485 = p->em485; + struct uart_8250_em485 *em485; + struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, start_tx_timer); + p = em485->port; spin_lock_irqsave(&p->port.lock, flags); if (em485 && @@ -1594,6 +1610,7 @@ static void serial8250_em485_handle_start_tx(unsigned long arg) em485->active_timer = NULL; } spin_unlock_irqrestore(&p->port.lock, flags); + return HRTIMER_NORESTART; } static void serial8250_start_tx(struct uart_port *port) diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 61fbb44..a27ef5f 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -80,9 +80,10 @@ struct uart_8250_ops { }; struct uart_8250_em485 { - struct timer_list start_tx_timer; /* "rs485 start tx" timer */ - struct timer_list stop_tx_timer; /* "rs485 stop tx" timer */ - struct timer_list *active_timer; /* pointer to active timer */ + struct hrtimer start_tx_timer; /* "rs485 start tx" timer */ + struct hrtimer stop_tx_timer; /* "rs485 stop tx" timer */ + struct hrtimer *active_timer; /* pointer to active timer */ + struct uart_8250_port *port; /* for hrtimer callbacks */ }; /* -- cgit v1.1 From 5c98e9cd459bd80232a5b007c3b9a618d8a96ea6 Mon Sep 17 00:00:00 2001 From: Sergei Shtylyov Date: Sun, 20 Aug 2017 19:51:55 +0300 Subject: serial: 8250_of: use of_property_read_bool() Use slightly more compact of_property_read_bool() calls for the boolean properties instead of of_find_property() calls. Signed-off-by: Sergei Shtylyov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 6c5a8ca..8867b63 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -146,7 +146,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP | UPF_FIXED_PORT | UPF_FIXED_TYPE; - if (of_find_property(np, "no-loopback-test", NULL)) + if (of_property_read_bool(np, "no-loopback-test")) port->flags |= UPF_SKIP_TEST; port->dev = &ofdev->dev; @@ -192,7 +192,7 @@ static int of_platform_serial_probe(struct platform_device *ofdev) if (!match) return -EINVAL; - if (of_find_property(ofdev->dev.of_node, "used-by-rtas", NULL)) + if (of_property_read_bool(ofdev->dev.of_node, "used-by-rtas")) return -EBUSY; info = kzalloc(sizeof(*info), GFP_KERNEL); -- cgit v1.1 From a2d23edaef9e022df26e9d46a49c2ecfc960cc8b Mon Sep 17 00:00:00 2001 From: Franklin S Cooper Jr Date: Wed, 16 Aug 2017 15:55:36 -0500 Subject: serial: 8250_of: Add basic PM runtime support 66AK2G UART instances are not apart of the ALWAYS_ON power domain. Therefore, pm_runtime calls must be made to properly insure the appropriate power domains needed by UART are on. Keep legacy clk api calls since other users of this driver may not support PM runtime. Signed-off-by: Franklin S Cooper Jr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 8867b63..30eacbf 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -65,6 +66,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, int ret; memset(port, 0, sizeof *port); + + pm_runtime_enable(&ofdev->dev); + pm_runtime_get_sync(&ofdev->dev); + if (of_property_read_u32(np, "clock-frequency", &clk)) { /* Get clk rate through clk driver if present */ @@ -72,12 +77,13 @@ static int of_platform_serial_setup(struct platform_device *ofdev, if (IS_ERR(info->clk)) { dev_warn(&ofdev->dev, "clk or clock-frequency not defined\n"); - return PTR_ERR(info->clk); + ret = PTR_ERR(info->clk); + goto err_pmruntime; } ret = clk_prepare_enable(info->clk); if (ret < 0) - return ret; + goto err_pmruntime; clk = clk_get_rate(info->clk); } @@ -170,8 +176,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, err_dispose: irq_dispose_mapping(port->irq); err_unprepare: - if (info->clk) - clk_disable_unprepare(info->clk); + clk_disable_unprepare(info->clk); +err_pmruntime: + pm_runtime_put_sync(&ofdev->dev); + pm_runtime_disable(&ofdev->dev); return ret; } @@ -227,8 +235,9 @@ static int of_platform_serial_probe(struct platform_device *ofdev) return 0; err_dispose: irq_dispose_mapping(port8250.port.irq); - if (info->clk) - clk_disable_unprepare(info->clk); + pm_runtime_put_sync(&ofdev->dev); + pm_runtime_disable(&ofdev->dev); + clk_disable_unprepare(info->clk); err_free: kfree(info); return ret; @@ -244,8 +253,9 @@ static int of_platform_serial_remove(struct platform_device *ofdev) serial8250_unregister_port(info->line); reset_control_assert(info->rst); - if (info->clk) - clk_disable_unprepare(info->clk); + pm_runtime_put_sync(&ofdev->dev); + pm_runtime_disable(&ofdev->dev); + clk_disable_unprepare(info->clk); kfree(info); return 0; } @@ -259,9 +269,10 @@ static int of_serial_suspend(struct device *dev) serial8250_suspend_port(info->line); - if (info->clk && (!uart_console(port) || console_suspend_enabled)) + if (!uart_console(port) || console_suspend_enabled) { + pm_runtime_put_sync(dev); clk_disable_unprepare(info->clk); - + } return 0; } @@ -271,8 +282,10 @@ static int of_serial_resume(struct device *dev) struct uart_8250_port *port8250 = serial8250_get_port(info->line); struct uart_port *port = &port8250->port; - if (info->clk && (!uart_console(port) || console_suspend_enabled)) + if (!uart_console(port) || console_suspend_enabled) { + pm_runtime_get_sync(dev); clk_prepare_enable(info->clk); + } serial8250_resume_port(info->line); -- cgit v1.1 From 0d474f7fad3b20a51394f5eb19d08b49d4e9ebc8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sat, 19 Aug 2017 23:24:55 +0530 Subject: tty: 8250: constify parisc_device_id parisc_device_id are not supposed to change at runtime. All functions working with parisc_device_id provided by work with const parisc_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_gsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/8250/8250_gsc.c b/drivers/tty/serial/8250/8250_gsc.c index 63306de..0c078cc 100644 --- a/drivers/tty/serial/8250/8250_gsc.c +++ b/drivers/tty/serial/8250/8250_gsc.c @@ -80,7 +80,7 @@ static int __init serial_init_chip(struct parisc_device *dev) return 0; } -static struct parisc_device_id serial_tbl[] = { +static const struct parisc_device_id serial_tbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00075 }, { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008c }, { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0008d }, @@ -94,7 +94,7 @@ static struct parisc_device_id serial_tbl[] = { * which only knows about Lasi and then a second which will find all the * other serial ports. HPUX ignores this problem. */ -static struct parisc_device_id lasi_tbl[] = { +static const struct parisc_device_id lasi_tbl[] = { { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03B, 0x0008C }, /* C1xx/C1xxL */ { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03C, 0x0008C }, /* B132L */ { HPHW_FIO, HVERSION_REV_ANY_ID, 0x03D, 0x0008C }, /* B160L */ -- cgit v1.1 From 829374f544b3b9499300f48c741cbc085ce06c14 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Sat, 19 Aug 2017 23:24:56 +0530 Subject: tty: mux: constify parisc_device_id parisc_device_id are not supposed to change at runtime. All functions working with parisc_device_id provided by work with const parisc_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mux.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 8a4be4b..6afe83d 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -536,13 +536,13 @@ static int mux_remove(struct parisc_device *dev) * This table only contains the parisc_device_id of known builtin mux * devices. All other mux cards will be detected by the generic mux_tbl. */ -static struct parisc_device_id builtin_mux_tbl[] = { +static const struct parisc_device_id builtin_mux_tbl[] = { { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x15, 0x0000D }, /* All K-class */ { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, 0x44, 0x0000D }, /* E35, E45, and E55 */ { 0, } }; -static struct parisc_device_id mux_tbl[] = { +static const struct parisc_device_id mux_tbl[] = { { HPHW_A_DIRECT, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0000D }, { 0, } }; -- cgit v1.1 From 8162ae5c47977c3f13910b5c1718081d30e8a65a Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:44 +0200 Subject: serial: uuc_uart: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: Timur Tabi Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/ucc_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c index 481eb29..55b7027 100644 --- a/drivers/tty/serial/ucc_uart.c +++ b/drivers/tty/serial/ucc_uart.c @@ -1085,7 +1085,7 @@ static int qe_uart_verify_port(struct uart_port *port, * * Details on these functions can be found in Documentation/serial/driver */ -static struct uart_ops qe_uart_pops = { +static const struct uart_ops qe_uart_pops = { .tx_empty = qe_uart_tx_empty, .set_mctrl = qe_uart_set_mctrl, .get_mctrl = qe_uart_get_mctrl, -- cgit v1.1 From ccb47a339dabace57c71ab41e6d7cd5f9b8d6746 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:45 +0200 Subject: serial: 21285: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/21285.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/21285.c b/drivers/tty/serial/21285.c index 9b208bd..804632b 100644 --- a/drivers/tty/serial/21285.c +++ b/drivers/tty/serial/21285.c @@ -334,7 +334,7 @@ static int serial21285_verify_port(struct uart_port *port, struct serial_struct return ret; } -static struct uart_ops serial21285_ops = { +static const struct uart_ops serial21285_ops = { .tx_empty = serial21285_tx_empty, .get_mctrl = serial21285_get_mctrl, .set_mctrl = serial21285_set_mctrl, -- cgit v1.1 From 1a607d31b264b930b986bc24958b4a840167f346 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:42 +0200 Subject: serial: sunsab: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunsab.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sunsab.c b/drivers/tty/serial/sunsab.c index b5e3195..653a076 100644 --- a/drivers/tty/serial/sunsab.c +++ b/drivers/tty/serial/sunsab.c @@ -819,7 +819,7 @@ static int sunsab_verify_port(struct uart_port *port, struct serial_struct *ser) return -EINVAL; } -static struct uart_ops sunsab_pops = { +static const struct uart_ops sunsab_pops = { .tx_empty = sunsab_tx_empty, .set_mctrl = sunsab_set_mctrl, .get_mctrl = sunsab_get_mctrl, -- cgit v1.1 From 57495265e90c79d3395a5a2fff3149c91af7c6c2 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:46 +0200 Subject: serial: apbuart: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/apbuart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/apbuart.c b/drivers/tty/serial/apbuart.c index 75eb083..dd60ed9 100644 --- a/drivers/tty/serial/apbuart.c +++ b/drivers/tty/serial/apbuart.c @@ -325,7 +325,7 @@ static int apbuart_verify_port(struct uart_port *port, return ret; } -static struct uart_ops grlib_apbuart_ops = { +static const struct uart_ops grlib_apbuart_ops = { .tx_empty = apbuart_tx_empty, .set_mctrl = apbuart_set_mctrl, .get_mctrl = apbuart_get_mctrl, -- cgit v1.1 From 5848eeaec620e6df962b171081e725e6ea854f1f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:47 +0200 Subject: serial: cpm_uart: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/cpm_uart/cpm_uart_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/cpm_uart/cpm_uart_core.c b/drivers/tty/serial/cpm_uart/cpm_uart_core.c index f6bcc19..9ac142c 100644 --- a/drivers/tty/serial/cpm_uart/cpm_uart_core.c +++ b/drivers/tty/serial/cpm_uart/cpm_uart_core.c @@ -1123,7 +1123,7 @@ static void cpm_put_poll_char(struct uart_port *port, } #endif /* CONFIG_CONSOLE_POLL */ -static struct uart_ops cpm_uart_pops = { +static const struct uart_ops cpm_uart_pops = { .tx_empty = cpm_uart_tx_empty, .set_mctrl = cpm_uart_set_mctrl, .get_mctrl = cpm_uart_get_mctrl, -- cgit v1.1 From cdb939456f81878cda1f31ba0ef1a3b1d7be07e8 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:48 +0200 Subject: serial: m32r_sio: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/m32r_sio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/m32r_sio.c b/drivers/tty/serial/m32r_sio.c index 218b711..5b3bd95 100644 --- a/drivers/tty/serial/m32r_sio.c +++ b/drivers/tty/serial/m32r_sio.c @@ -854,7 +854,7 @@ m32r_sio_verify_port(struct uart_port *port, struct serial_struct *ser) return 0; } -static struct uart_ops m32r_sio_pops = { +static const struct uart_ops m32r_sio_pops = { .tx_empty = m32r_sio_tx_empty, .set_mctrl = m32r_sio_set_mctrl, .get_mctrl = m32r_sio_get_mctrl, -- cgit v1.1 From 6f137a751cd968b5ddd27a5d99eefa83f73d3390 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:49 +0200 Subject: serial: mpc52xx: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mpc52xx_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/mpc52xx_uart.c b/drivers/tty/serial/mpc52xx_uart.c index 4cacaad..791c4c7 100644 --- a/drivers/tty/serial/mpc52xx_uart.c +++ b/drivers/tty/serial/mpc52xx_uart.c @@ -1347,7 +1347,7 @@ mpc52xx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) } -static struct uart_ops mpc52xx_uart_ops = { +static const struct uart_ops mpc52xx_uart_ops = { .tx_empty = mpc52xx_uart_tx_empty, .set_mctrl = mpc52xx_uart_set_mctrl, .get_mctrl = mpc52xx_uart_get_mctrl, -- cgit v1.1 From 0bfdbe0737b6bf6e4553e36279cf6fd80295a859 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:43 +0200 Subject: serial: sunsu: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Acked-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sunsu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 5380407..95d34d7 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -958,7 +958,7 @@ sunsu_type(struct uart_port *port) return uart_config[type].name; } -static struct uart_ops sunsu_pops = { +static const struct uart_ops sunsu_pops = { .tx_empty = sunsu_tx_empty, .set_mctrl = sunsu_set_mctrl, .get_mctrl = sunsu_get_mctrl, -- cgit v1.1 From 454d23797a61c2c7424fb737ec417db7dd22bc60 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Aug 2017 08:21:50 +0200 Subject: serial: mux: constify uart_ops structures These uart_ops structures are only stored in the ops field of a uart_port structure and this fields is const, so the uart_ops structures can also be const. Done with the help of Coccinelle. Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mux.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/mux.c b/drivers/tty/serial/mux.c index 6afe83d..5ee5b9f 100644 --- a/drivers/tty/serial/mux.c +++ b/drivers/tty/serial/mux.c @@ -427,7 +427,7 @@ static struct console mux_console = { #define MUX_CONSOLE NULL #endif -static struct uart_ops mux_pops = { +static const struct uart_ops mux_pops = { .tx_empty = mux_tx_empty, .set_mctrl = mux_set_mctrl, .get_mctrl = mux_get_mctrl, -- cgit v1.1 From 447ef990ad9e909443ec16edb837c6e37664f5ba Mon Sep 17 00:00:00 2001 From: Jeffy Chen Date: Sat, 19 Aug 2017 09:43:17 +0800 Subject: serial: earlycon: Only try fdt when specify 'earlycon' exactly When moving earlycon early_param handling to serial, the devicetree earlycons enable condition changed slightly. We used to only do that for 'console'/'earlycon', but now would also for 'console='/'earlycon='. Fix it by using the same condition like before. Fixes: d503187b6cc4 (of/serial: move earlycon early_param handling to serial) Signed-off-by: Jeffy Chen Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index c365154..335933e 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -220,7 +220,7 @@ static int __init param_setup_earlycon(char *buf) if (IS_ENABLED(CONFIG_ACPI_SPCR_TABLE)) { earlycon_init_is_deferred = true; return 0; - } else { + } else if (!buf) { return early_init_dt_scan_chosen_stdout(); } } -- cgit v1.1 From 785704d29197732b8a77ee440d0c138ca9544580 Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 21 Aug 2017 01:17:55 +0800 Subject: dt-bindings: serial: 8250: Add MediaTek BTIF controller bindings Document the devicetree bindings in 8250.txt for MediaTek BTIF controller which could be found on MT7622 and MT7623 SoC. Signed-off-by: Sean Wang Acked-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index 419ff6c..dad3b2e 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -14,6 +14,8 @@ Required properties: tegra132, or tegra210. - "nxp,lpc3220-uart" - "ralink,rt2880-uart" + - For MediaTek BTIF, must contain '"mediatek,-btif", + "mediatek,mtk-btif"' where is mt7622, mt7623. - "altr,16550-FIFO32" - "altr,16550-FIFO64" - "altr,16550-FIFO128" -- cgit v1.1 From 1c16ae65e2502da05310b2ec56b3a1fd3efe6f4d Mon Sep 17 00:00:00 2001 From: Sean Wang Date: Mon, 21 Aug 2017 01:17:56 +0800 Subject: serial: 8250: of: Add new port type for MediaTek BTIF controller on MT7622/23 SoC MediaTek BTIF controller is the serial interface similar to UART but it works only as the digital device which is mainly used to communicate with the connectivity module called CONNSYS inside the SoC which could be mostly found on those MediaTek SoCs with Bluetooth feature such as MT7622 and MT7623 SoCs. And the controller is made as being compatible with the 8250 register layout with extra registers such as DMA enablement so it tends to be integrated with reusing 8250 OF driver. However, DMA mode is not being supported yet in the current driver. Signed-off-by: Sean Wang Suggested-by: Andy Shevchenko Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_of.c | 2 ++ drivers/tty/serial/8250/8250_port.c | 8 ++++++++ include/uapi/linux/serial_core.h | 3 +++ 3 files changed, 13 insertions(+) diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 30eacbf..1222c00 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -313,6 +313,8 @@ static const struct of_device_id of_platform_serial_table[] = { .data = (void *)PORT_ALTR_16550_F64, }, { .compatible = "altr,16550-FIFO128", .data = (void *)PORT_ALTR_16550_F128, }, + { .compatible = "mediatek,mtk-btif", + .data = (void *)PORT_MTK_BTIF, }, { .compatible = "mrvl,mmp-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 6b745e4..4726aa2 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -289,6 +289,14 @@ static const struct serial8250_config uart_config[] = { .rxtrig_bytes = {1, 4, 8, 14}, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, + [PORT_MTK_BTIF] = { + .name = "MediaTek BTIF", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + .flags = UART_CAP_FIFO, + }, }; /* Uart divisor latch read */ diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index dc2d7cb..50d71c4 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -274,4 +274,7 @@ /* MPS2 UART */ #define PORT_MPS2UART 116 +/* MediaTek BTIF */ +#define PORT_MTK_BTIF 117 + #endif /* _UAPILINUX_SERIAL_CORE_H */ -- cgit v1.1 From 39be40ce066da4d5d59bf53f72b914018bc84029 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2017 22:48:41 +0900 Subject: serial: 8250_uniphier: fix serial port index in private data serial8250_register_8250_port() may allocate a different port index than requested. The driver needs to remember the returned value of serial8250_register_8250_port() for later use. Otherwise, the .remove hook may unregister a different port. Fixes: 1a8d2903cb6a ("serial: 8250_uniphier: add UniPhier serial driver") Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 746680e..633ac37 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -169,7 +169,7 @@ static int uniphier_of_serial_setup(struct device *dev, struct uart_port *port, dev_err(dev, "failed to get alias id\n"); return ret; } - port->line = priv->line = ret; + port->line = ret; /* Get clk rate through clk driver */ priv->clk = devm_clk_get(dev, NULL); @@ -249,8 +249,8 @@ static int uniphier_uart_probe(struct platform_device *pdev) up.dl_read = uniphier_serial_dl_read; up.dl_write = uniphier_serial_dl_write; - ret = serial8250_register_8250_port(&up); - if (ret < 0) { + priv->line = serial8250_register_8250_port(&up); + if (priv->line < 0) { dev_err(dev, "failed to register 8250 port\n"); clk_disable_unprepare(priv->clk); return ret; -- cgit v1.1 From d3a9184773c5cde483e249096ae7c7f98f310e20 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2017 22:48:42 +0900 Subject: serial: 8250_uniphier: use CHAR register for canary to detect power-off The 8250 core uses the SCR as a canary to discover if the console has been powered-off. This hardware does not have SCR at offset 7, but an unused register CHAR at a different offset. As long as the character interrupt is disabled, the register access has no impact, so it is useful as an alternative scratch register. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 633ac37..97a45b79 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -29,12 +29,13 @@ * - MMIO32 (regshift = 2) * - FCR is not at 2, but 3 * - LCR and MCR are not at 3 and 4, they share 4 + * - No SCR (Instead, CHAR can be used as a scratch register) * - Divisor latch at 9, no divisor latch access bit */ #define UNIPHIER_UART_REGSHIFT 2 -/* bit[15:8] = CHAR (not used), bit[7:0] = FCR */ +/* bit[15:8] = CHAR, bit[7:0] = FCR */ #define UNIPHIER_UART_CHAR_FCR (3 << (UNIPHIER_UART_REGSHIFT)) /* bit[15:8] = LCR, bit[7:0] = MCR */ #define UNIPHIER_UART_LCR_MCR (4 << (UNIPHIER_UART_REGSHIFT)) @@ -72,13 +73,18 @@ OF_EARLYCON_DECLARE(uniphier, "socionext,uniphier-uart", /* * The register map is slightly different from that of 8250. - * IO callbacks must be overridden for correct access to FCR, LCR, and MCR. + * IO callbacks must be overridden for correct access to FCR, LCR, MCR and SCR. */ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) { unsigned int valshift = 0; switch (offset) { + case UART_SCR: + /* No SCR for this hardware. Use CHAR as a scratch register */ + valshift = 8; + offset = UNIPHIER_UART_CHAR_FCR; + break; case UART_LCR: valshift = 8; /* fall through */ @@ -91,8 +97,8 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) } /* - * The return value must be masked with 0xff because LCR and MCR reside - * in the same register that must be accessed by 32-bit write/read. + * The return value must be masked with 0xff because some registers + * share the same offset that must be accessed by 32-bit write/read. * 8 or 16 bit access to this hardware result in unexpected behavior. */ return (readl(p->membase + offset) >> valshift) & 0xff; @@ -101,9 +107,13 @@ static unsigned int uniphier_serial_in(struct uart_port *p, int offset) static void uniphier_serial_out(struct uart_port *p, int offset, int value) { unsigned int valshift = 0; - bool normal = true; + bool normal = false; switch (offset) { + case UART_SCR: + /* No SCR for this hardware. Use CHAR as a scratch register */ + valshift = 8; + /* fall through */ case UART_FCR: offset = UNIPHIER_UART_CHAR_FCR; break; @@ -114,10 +124,10 @@ static void uniphier_serial_out(struct uart_port *p, int offset, int value) /* fall through */ case UART_MCR: offset = UNIPHIER_UART_LCR_MCR; - normal = false; break; default: offset <<= UNIPHIER_UART_REGSHIFT; + normal = true; break; } -- cgit v1.1 From 3d16ddc13c5e56726d05b4eceb766b06483e3686 Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Tue, 8 Aug 2017 22:48:43 +0900 Subject: serial: 8250_uniphier: add suspend/resume support Add suspend/resume support for UniPhier serial driver. Signed-off-by: Masahiro Yamada Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_uniphier.c | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/tty/serial/8250/8250_uniphier.c b/drivers/tty/serial/8250/8250_uniphier.c index 97a45b79..8a10b10 100644 --- a/drivers/tty/serial/8250/8250_uniphier.c +++ b/drivers/tty/serial/8250/8250_uniphier.c @@ -281,6 +281,40 @@ static int uniphier_uart_remove(struct platform_device *pdev) return 0; } +static int __maybe_unused uniphier_uart_suspend(struct device *dev) +{ + struct uniphier8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + + serial8250_suspend_port(priv->line); + + if (!uart_console(&up->port) || console_suspend_enabled) + clk_disable_unprepare(priv->clk); + + return 0; +} + +static int __maybe_unused uniphier_uart_resume(struct device *dev) +{ + struct uniphier8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); + int ret; + + if (!uart_console(&up->port) || console_suspend_enabled) { + ret = clk_prepare_enable(priv->clk); + if (ret) + return ret; + } + + serial8250_resume_port(priv->line); + + return 0; +} + +static const struct dev_pm_ops uniphier_uart_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(uniphier_uart_suspend, uniphier_uart_resume) +}; + static const struct of_device_id uniphier_uart_match[] = { { .compatible = "socionext,uniphier-uart" }, { /* sentinel */ } @@ -293,6 +327,7 @@ static struct platform_driver uniphier_uart_platform_driver = { .driver = { .name = "uniphier-uart", .of_match_table = uniphier_uart_match, + .pm = &uniphier_uart_pm_ops, }, }; module_platform_driver(uniphier_uart_platform_driver); -- cgit v1.1 From 81b289cc14ba349cc4707cf664aa1c72d7dff1d7 Mon Sep 17 00:00:00 2001 From: "Maxim Yu. Osipov" Date: Mon, 14 Aug 2017 16:27:49 +0200 Subject: tty: serial: imx: disable irq after suspend If any key on console is pressed when board is suspended, board hangs. Driver's interrupt handler must be guaranteed not to run while resume/suspend_noirq() are being executed. See include/linux/pm.h for details. Tested on i.MX6 based board. The idea of this fix is based on commit in official i.MX kernel tree: http://git.freescale.com/git/cgit.cgi/imx/linux-2.6-imx.git commit 81e8e7d91d81 ("tty: serial: imx: disable irq after suspend") Disable rx irq after suspend to avoid interrupt coming in early resume. Signed-off-by: Fugang Duan Signed-off-by: Maxim Yu. Osipov Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 3964ae5..d879a9b 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2321,6 +2321,7 @@ static int imx_serial_port_suspend(struct device *dev) serial_imx_enable_wakeup(sport, true); uart_suspend_port(&imx_reg, &sport->port); + disable_irq(sport->port.irq); /* Needed to enable clock in suspend_noirq */ return clk_prepare(sport->clk_ipg); @@ -2335,6 +2336,7 @@ static int imx_serial_port_resume(struct device *dev) serial_imx_enable_wakeup(sport, false); uart_resume_port(&imx_reg, &sport->port); + enable_irq(sport->port.irq); clk_unprepare(sport->clk_ipg); -- cgit v1.1 From 5aabd3b0077e0577f60a1ca6b8bdad62f23353d8 Mon Sep 17 00:00:00 2001 From: Ian Jamison Date: Mon, 28 Aug 2017 09:02:29 +0100 Subject: serial: imx: Avoid post-PIO cleanup if TX DMA is started MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The imx_transmit_buffer function should return if TX DMA has already been started and not just skip over the buffer PIO write loop. (Which did fix the initial problem, but could have unintentional side-effects) Tested on an i.MX6Q board with half-duplex RS-485 and with RS-232. Cc: Clemens Gruber Cc: Uwe-Kleine König Cc: Greg Kroah-Hartman Cc: Fabio Estevam Fixes: 514ab34dbad6 ("serial: imx: Prevent TX buffer PIO write when a DMA has been started") Signed-off-by: Ian Jamison Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d879a9b..dfeff39 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -457,7 +457,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport) } } - while (!uart_circ_empty(xmit) && !sport->dma_is_txing && + if (sport->dma_is_txing) + return; + + while (!uart_circ_empty(xmit) && !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ -- cgit v1.1 From 2ce8008711e4837c11e99a94df55406085d0d098 Mon Sep 17 00:00:00 2001 From: Johannes Thumshirn Date: Wed, 2 Aug 2017 09:58:52 +0200 Subject: mcb: introduce mcb_get_resource() Introduce mcb_get_resource() as a common accessor to a mcb device's memory or IRQ resources. Signed-off-by: Johannes Thumshirn Signed-off-by: Greg Kroah-Hartman --- drivers/mcb/mcb-core.c | 20 +++++++++++++++++++- include/linux/mcb.h | 2 ++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/drivers/mcb/mcb-core.c b/drivers/mcb/mcb-core.c index 921a5d2..bb5c569 100644 --- a/drivers/mcb/mcb-core.c +++ b/drivers/mcb/mcb-core.c @@ -418,6 +418,22 @@ void mcb_bus_add_devices(const struct mcb_bus *bus) EXPORT_SYMBOL_GPL(mcb_bus_add_devices); /** + * mcb_get_resource() - get a resource for a mcb device + * @dev: the mcb device + * @type: the type of resource + */ +struct resource *mcb_get_resource(struct mcb_device *dev, unsigned int type) +{ + if (type == IORESOURCE_MEM) + return &dev->mem; + else if (type == IORESOURCE_IRQ) + return &dev->irq; + else + return NULL; +} +EXPORT_SYMBOL_GPL(mcb_get_resource); + +/** * mcb_request_mem() - Request memory * @dev: The @mcb_device the memory is for * @name: The name for the memory reference. @@ -460,7 +476,9 @@ EXPORT_SYMBOL_GPL(mcb_release_mem); static int __mcb_get_irq(struct mcb_device *dev) { - struct resource *irq = &dev->irq; + struct resource *irq; + + irq = mcb_get_resource(dev, IORESOURCE_IRQ); return irq->start; } diff --git a/include/linux/mcb.h b/include/linux/mcb.h index 4097ac9..b1a0ad9 100644 --- a/include/linux/mcb.h +++ b/include/linux/mcb.h @@ -136,5 +136,7 @@ extern struct resource *mcb_request_mem(struct mcb_device *dev, const char *name); extern void mcb_release_mem(struct resource *mem); extern int mcb_get_irq(struct mcb_device *dev); +extern struct resource *mcb_get_resource(struct mcb_device *dev, + unsigned int type); #endif /* _LINUX_MCB_H */ -- cgit v1.1 From 562e6ef81f9b3dadeb7d05a6055e502d43caa830 Mon Sep 17 00:00:00 2001 From: Michael Moese Date: Wed, 2 Aug 2017 09:58:53 +0200 Subject: Introduce 8250_men_mcb This patch introduces the 8250_men_mcb driver for the MEN 16Z125 IP-Core. This is a 16550-type UART with a 60 byte FIFO. Due to strange old hardware, every board using this IP core requires different values for uartclk. A reasonable default is included in addition to the support of three boards. Additional values for other boards will be added later. This v2 has some whitespace fixes, I screwed this up yesterday. Signed-off-by: Michael Moese Reviewed-by: Johannes Thumshirn Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_men_mcb.c | 118 +++++++++++++++++++++++++++++++++ drivers/tty/serial/8250/Kconfig | 11 +++ drivers/tty/serial/8250/Makefile | 1 + 3 files changed, 130 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_men_mcb.c diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c new file mode 100644 index 0000000..3089778 --- /dev/null +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -0,0 +1,118 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +struct serial_8250_men_mcb_data { + struct uart_8250_port uart; + int line; +}; + +/* + * The Z125 16550-compatible UART has no fixed base clock assigned + * So, depending on the board we're on, we need to adjust the + * parameter in order to really set the correct baudrate, and + * do so if possible without user interaction + */ +static u32 men_z125_lookup_uartclk(struct mcb_device *mdev) +{ + /* use default value if board is not available below */ + u32 clkval = 1041666; + + dev_info(&mdev->dev, "%s on board %s\n", + dev_name(&mdev->dev), + mdev->bus->name); + if (strncmp(mdev->bus->name, "F075", 4) == 0) + clkval = 1041666; + else if (strncmp(mdev->bus->name, "F216", 4) == 0) + clkval = 1843200; + else if (strncmp(mdev->bus->name, "G215", 4) == 0) + clkval = 1843200; + else + dev_info(&mdev->dev, + "board not detected, using default uartclk\n"); + + clkval = clkval << 4; + + return clkval; +} + +static int serial_8250_men_mcb_probe(struct mcb_device *mdev, + const struct mcb_device_id *id) +{ + struct serial_8250_men_mcb_data *data; + struct resource *mem; + + data = devm_kzalloc(&mdev->dev, + sizeof(struct serial_8250_men_mcb_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; + + mcb_set_drvdata(mdev, data); + data->uart.port.dev = mdev->dma_dev; + spin_lock_init(&data->uart.port.lock); + + data->uart.port.type = PORT_16550; + data->uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; + data->uart.port.iotype = UPIO_MEM; + data->uart.port.uartclk = men_z125_lookup_uartclk(mdev); + data->uart.port.regshift = 0; + data->uart.port.fifosize = 60; + + mem = mcb_get_resource(mdev, IORESOURCE_MEM); + if (mem == NULL) + return -ENXIO; + + data->uart.port.irq = mcb_get_irq(mdev); + + data->uart.port.membase = devm_ioremap_resource(&mdev->dev, mem); + if (IS_ERR(data->uart.port.membase)) + return PTR_ERR_OR_ZERO(data->uart.port.membase); + + data->uart.port.mapbase = (unsigned long) mem->start; + data->uart.port.iobase = data->uart.port.mapbase; + + /* ok, register the port */ + data->line = serial8250_register_8250_port(&data->uart); + if (data->line < 0) + return data->line; + + dev_info(&mdev->dev, "found 16Z125 UART: ttyS%d\n", data->line); + + return 0; +} + +static void serial_8250_men_mcb_remove(struct mcb_device *mdev) +{ + struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev); + + if (data) + serial8250_unregister_port(data->line); +} + +static const struct mcb_device_id serial_8250_men_mcb_ids[] = { + { .device = 0x7d }, + { } +}; +MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids); + +static struct mcb_driver mcb_driver = { + .driver = { + .name = "8250_men_mcb", + .owner = THIS_MODULE, + }, + .probe = serial_8250_men_mcb_probe, + .remove = serial_8250_men_mcb_remove, + .id_table = serial_8250_men_mcb_ids, +}; +module_mcb_driver(mcb_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MEN 16z125 8250 UART driver"); +MODULE_AUTHOR("Michael Moese Date: Fri, 25 Aug 2017 23:44:11 +0530 Subject: tty: mips_ejtag_fdc: constify mips_cdmm_device_id mips_cdmm_device_id are not supposed to change at runtime. mips_cdmm_driver is working with const 'id_table'. So mark the non-const mips_cdmm_device_id structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/mips_ejtag_fdc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/mips_ejtag_fdc.c b/drivers/tty/mips_ejtag_fdc.c index 234123b..a2dab3f 100644 --- a/drivers/tty/mips_ejtag_fdc.c +++ b/drivers/tty/mips_ejtag_fdc.c @@ -1110,7 +1110,7 @@ out: return ret; } -static struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = { +static const struct mips_cdmm_device_id mips_ejtag_fdc_tty_ids[] = { { .type = 0xfd }, { } }; -- cgit v1.1 From 7298bd1d7b07b55fe3fe9c84906f2eb065913701 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 17 Aug 2017 19:04:22 +0530 Subject: tty: hvc_vio: constify vio_device_id vio_device_id are not supposed to change at runtime. All functions working with vio_device_id provided by work with const vio_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvc_vio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index 78b003b..653f9927 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c @@ -53,7 +53,7 @@ static const char hvc_driver_name[] = "hvc_console"; -static struct vio_device_id hvc_driver_table[] = { +static const struct vio_device_id hvc_driver_table[] = { {"serial", "hvterm1"}, #ifndef HVC_OLD_HVSI {"serial", "hvterm-protocol"}, -- cgit v1.1 From a846c3e5f338206c84e292a57abde0b06f1777c8 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Thu, 17 Aug 2017 19:04:23 +0530 Subject: tty: hvcs: constify vio_device_id vio_device_id are not supposed to change at runtime. All functions working with vio_device_id provided by work with const vio_device_id. So mark the non-const structs as const. Signed-off-by: Arvind Yadav Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 79cc5be..7320190 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -675,7 +675,7 @@ static int khvcsd(void *unused) return 0; } -static struct vio_device_id hvcs_driver_table[] = { +static const struct vio_device_id hvcs_driver_table[] = { {"serial-server", "hvterm2"}, { "", "" } }; -- cgit v1.1 From 199e717f252be0e31c97b9c7861dd6e2abfaa936 Mon Sep 17 00:00:00 2001 From: Lars Poeschel Date: Tue, 15 Aug 2017 13:58:27 +0200 Subject: tty: n_gsm: Add compat_ioctl To use this driver with 32 bit userspace applications on 64 bit kernels a compat_ioctl is needed. Signed-off-by: Lars Poeschel Signed-off-by: Greg Kroah-Hartman --- drivers/tty/n_gsm.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c index 2afe5fc..0a3c966 100644 --- a/drivers/tty/n_gsm.c +++ b/drivers/tty/n_gsm.c @@ -2607,6 +2607,14 @@ static int gsmld_ioctl(struct tty_struct *tty, struct file *file, } } +#ifdef CONFIG_COMPAT +static long gsmld_compat_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return gsmld_ioctl(tty, file, cmd, arg); +} +#endif + /* * Network interface * @@ -2818,6 +2826,9 @@ static struct tty_ldisc_ops tty_ldisc_packet = { .flush_buffer = gsmld_flush_buffer, .read = gsmld_read, .write = gsmld_write, +#ifdef CONFIG_COMPAT + .compat_ioctl = gsmld_compat_ioctl, +#endif .ioctl = gsmld_ioctl, .poll = gsmld_poll, .receive_buf = gsmld_receive_buf, -- cgit v1.1 From d01c3289e7d68162e32bc08c2b65dd1a216a7ef8 Mon Sep 17 00:00:00 2001 From: Masatake YAMATO Date: Tue, 18 Jul 2017 06:27:59 +0900 Subject: pty: show associative slave of ptmx in fdinfo This patch adds "tty-index" field to /proc/PID/fdinfo/N if N specifies /dev/ptmx. The field shows the index of associative slave pts. Though a minor number is given for each pts instance, ptmx is not. It means there is no way in user-space to know the association between file descriptors for pts/n and ptmx. (n = 0, 1, ...) This is different from pipe. About pipe such association can be solved by inode of pipefs. Providing the way to know the association between pts/n and ptmx helps users understand the status of running system. lsof can utilize this field. Signed-off-by: Masatake YAMATO Signed-off-by: Greg Kroah-Hartman --- drivers/tty/pty.c | 8 +++++++- drivers/tty/tty_io.c | 9 +++++++++ include/linux/tty_driver.h | 2 ++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 284749f..bb672ac 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -741,6 +741,11 @@ static void pty_unix98_remove(struct tty_driver *driver, struct tty_struct *tty) } } +static void pty_show_fdinfo(struct tty_struct *tty, struct seq_file *m) +{ + seq_printf(m, "tty-index:\t%d\n", tty->index); +} + static const struct tty_operations ptm_unix98_ops = { .lookup = ptm_unix98_lookup, .install = pty_unix98_install, @@ -755,7 +760,8 @@ static const struct tty_operations ptm_unix98_ops = { .ioctl = pty_unix98_ioctl, .compat_ioctl = pty_unix98_compat_ioctl, .resize = pty_resize, - .cleanup = pty_cleanup + .cleanup = pty_cleanup, + .show_fdinfo = pty_show_fdinfo, }; static const struct tty_operations pty_unix98_ops = { diff --git a/drivers/tty/tty_io.c b/drivers/tty/tty_io.c index 974b13d..c3c8fd0 100644 --- a/drivers/tty/tty_io.c +++ b/drivers/tty/tty_io.c @@ -462,6 +462,14 @@ static int hung_up_tty_fasync(int fd, struct file *file, int on) return -ENOTTY; } +static void tty_show_fdinfo(struct seq_file *m, struct file *file) +{ + struct tty_struct *tty = file_tty(file); + + if (tty && tty->ops && tty->ops->show_fdinfo) + tty->ops->show_fdinfo(tty, m); +} + static const struct file_operations tty_fops = { .llseek = no_llseek, .read = tty_read, @@ -472,6 +480,7 @@ static const struct file_operations tty_fops = { .open = tty_open, .release = tty_release, .fasync = tty_fasync, + .show_fdinfo = tty_show_fdinfo, }; static const struct file_operations console_fops = { diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index 00b2213..fcdc0f5 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -243,6 +243,7 @@ #include #include #include +#include struct tty_struct; struct tty_driver; @@ -285,6 +286,7 @@ struct tty_operations { int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); int (*get_icount)(struct tty_struct *tty, struct serial_icounter_struct *icount); + void (*show_fdinfo)(struct tty_struct *tty, struct seq_file *m); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_get_char)(struct tty_driver *driver, int line); -- cgit v1.1 From 6ec6e80d11783c00bb96794688d0d51d0481c8d3 Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Tue, 29 Aug 2017 00:00:31 +0530 Subject: tty: hvcs: make ktermios const Make this const as it is not modified anywhere. Signed-off-by: Bhumika Goyal Reviewed-by: Tyrel Datwyler Signed-off-by: Greg Kroah-Hartman --- drivers/tty/hvc/hvcs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index 7320190..63c29fe 100644 --- a/drivers/tty/hvc/hvcs.c +++ b/drivers/tty/hvc/hvcs.c @@ -189,7 +189,7 @@ MODULE_VERSION(HVCS_DRIVER_VERSION); * that will cause echoing or we'll go into recursive loop echoing chars back * and forth with the console drivers. */ -static struct ktermios hvcs_tty_termios = { +static const struct ktermios hvcs_tty_termios = { .c_iflag = IGNBRK | IGNPAR, .c_oflag = OPOST, .c_cflag = B38400 | CS8 | CREAD | HUPCL, -- cgit v1.1 From 31cb9a8575ca04f47ea113434d4782b695638b62 Mon Sep 17 00:00:00 2001 From: Eugeniy Paltsev Date: Mon, 21 Aug 2017 19:22:13 +0300 Subject: earlycon: initialise baud field of earlycon device structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now baud field of earlycon structure device is't initialised at all in of_setup_earlycon (in oppositе to register_earlycon). So when I use stdout-path to point earlycon device (like stdout-path = &serial or stdout-path = "serial:115200n8") baud field of earlycon device structure remains uninitialised and earlycon initialization is not performed correctly as of_setup_earlycon is used. When pass all arguments via bootargs (like bootargs = "earlycon=uart8250,mmio32,0xf0005000,115200n8") initialization is performed correctly as register_earlycon is used. So initialise baud field of earlycon device structure by value of "current-speed" property from device tree or from options (if they exist) when we use of_setup_earlycon Signed-off-by: Eugeniy Paltsev Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/earlycon.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 335933e..98928f0 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -282,7 +282,12 @@ int __init of_setup_earlycon(const struct earlycon_id *match, } } + val = of_get_flat_dt_prop(node, "current-speed", NULL); + if (val) + early_console_dev.baud = be32_to_cpu(*val); + if (options) { + early_console_dev.baud = simple_strtoul(options, NULL, 0); strlcpy(early_console_dev.options, options, sizeof(early_console_dev.options)); } -- cgit v1.1 From ae28d7402a7e7cf3dd0da1f2eb6a52b337873e08 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 30 Aug 2017 17:12:13 +0300 Subject: serial: 8250_port: Remove useless NULL checks After switching to HR timers for RS485 the NULL checks for the object inside timer functions become useless. Remove them to avoid confusion to static analyzers. Fixes 6e0a5de2136b ("serial: 8250: Use hrtimers for rs485 delays") Cc: Colin Ian King Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 4726aa2..f0cc04f 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1450,13 +1450,13 @@ static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t) struct uart_8250_em485 *em485; struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, stop_tx_timer); p = em485->port; serial8250_rpm_get(p); spin_lock_irqsave(&p->port.lock, flags); - if (em485 && - em485->active_timer == &em485->stop_tx_timer) { + if (em485->active_timer == &em485->stop_tx_timer) { __do_stop_tx_rs485(p); em485->active_timer = NULL; } @@ -1608,12 +1608,12 @@ static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t) struct uart_8250_em485 *em485; struct uart_8250_port *p; unsigned long flags; + em485 = container_of(t, struct uart_8250_em485, start_tx_timer); p = em485->port; spin_lock_irqsave(&p->port.lock, flags); - if (em485 && - em485->active_timer == &em485->start_tx_timer) { + if (em485->active_timer == &em485->start_tx_timer) { __start_tx(&p->port); em485->active_timer = NULL; } -- cgit v1.1 From 2296eee704e70dac7fef8ac13f2716e4896dd13e Mon Sep 17 00:00:00 2001 From: Aleksandar Markovic Date: Tue, 29 Aug 2017 15:53:18 +0200 Subject: tty: goldfish: Refactor constants to better reflect their nature Classify constants GOLDFISH_TTY_xxx into two groups: command ids and register offsets. Apply different naming for register offsets (add 'REG_' after 'GOLDFISH_TTY_' in constant names). Change implementation to use preprocessor's '#define' statements instead of 'enum' declaration (as this is more common way of implementation in such cases). This makes the driver code easier to follow and hopefully prevents future bugs. Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 52 ++++++++++++++++++++++++-------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 996bd47..011eb53 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -23,20 +23,18 @@ #include #include -enum { - GOLDFISH_TTY_PUT_CHAR = 0x00, - GOLDFISH_TTY_BYTES_READY = 0x04, - GOLDFISH_TTY_CMD = 0x08, - - GOLDFISH_TTY_DATA_PTR = 0x10, - GOLDFISH_TTY_DATA_LEN = 0x14, - GOLDFISH_TTY_DATA_PTR_HIGH = 0x18, - - GOLDFISH_TTY_CMD_INT_DISABLE = 0, - GOLDFISH_TTY_CMD_INT_ENABLE = 1, - GOLDFISH_TTY_CMD_WRITE_BUFFER = 2, - GOLDFISH_TTY_CMD_READ_BUFFER = 3, -}; +/* Goldfish tty register's offsets */ +#define GOLDFISH_TTY_REG_BYTES_READY 0x04 +#define GOLDFISH_TTY_REG_CMD 0x08 +#define GOLDFISH_TTY_REG_DATA_PTR 0x10 +#define GOLDFISH_TTY_REG_DATA_LEN 0x14 +#define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18 + +/* Goldfish tty commands */ +#define GOLDFISH_TTY_CMD_INT_DISABLE 0 +#define GOLDFISH_TTY_CMD_INT_ENABLE 1 +#define GOLDFISH_TTY_CMD_WRITE_BUFFER 2 +#define GOLDFISH_TTY_CMD_READ_BUFFER 3 struct goldfish_tty { struct tty_port port; @@ -59,10 +57,10 @@ static void goldfish_tty_do_write(int line, const char *buf, unsigned count) struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, - base + GOLDFISH_TTY_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_DATA_LEN); - writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_CMD); + gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); + writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); + writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_REG_CMD); spin_unlock_irqrestore(&qtty->lock, irq_flags); } @@ -74,16 +72,16 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) unsigned char *buf; u32 count; - count = readl(base + GOLDFISH_TTY_BYTES_READY); + count = readl(base + GOLDFISH_TTY_REG_BYTES_READY); if (count == 0) return IRQ_NONE; count = tty_prepare_flip_string(&qtty->port, &buf, count); spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_DATA_PTR, - base + GOLDFISH_TTY_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_DATA_LEN); - writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_CMD); + gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); + writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); + writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); spin_unlock_irqrestore(&qtty->lock, irq_flags); tty_schedule_flip(&qtty->port); return IRQ_HANDLED; @@ -93,7 +91,7 @@ static int goldfish_tty_activate(struct tty_port *port, struct tty_struct *tty) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_ENABLE, qtty->base + GOLDFISH_TTY_REG_CMD); return 0; } @@ -101,7 +99,7 @@ static void goldfish_tty_shutdown(struct tty_port *port) { struct goldfish_tty *qtty = container_of(port, struct goldfish_tty, port); - writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_DISABLE, qtty->base + GOLDFISH_TTY_REG_CMD); } static int goldfish_tty_open(struct tty_struct *tty, struct file *filp) @@ -136,7 +134,7 @@ static int goldfish_tty_chars_in_buffer(struct tty_struct *tty) { struct goldfish_tty *qtty = &goldfish_ttys[tty->index]; void __iomem *base = qtty->base; - return readl(base + GOLDFISH_TTY_BYTES_READY); + return readl(base + GOLDFISH_TTY_REG_BYTES_READY); } static void goldfish_tty_console_write(struct console *co, const char *b, @@ -272,7 +270,7 @@ static int goldfish_tty_probe(struct platform_device *pdev) qtty->base = base; qtty->irq = irq; - writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_CMD); + writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, "goldfish_tty", qtty); -- cgit v1.1 From 7157d2be23da9f8860c69e2b79184a4e02701dad Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Tue, 29 Aug 2017 15:53:19 +0200 Subject: tty: goldfish: Use streaming DMA for r/w operations on Ranchu platforms Implement tty r/w operations using streaming DMA. Goldfish tty for Ranchu platforms has been modified to use streaming DMA mappings for read/write operations. This change eliminates the need for snooping through the TLB in QEMU using cpu_get_phys_page_debug() which does not guarantee that it will return the valid va -> pa mapping. The streaming DMA mapping is implemented using dma_map_single() per transfer, while dma_unmap_single() is used for unmapping right after the DMA transfer. Using DMA API is the proper way for handling r/w transfers and makes this driver more portable, thus effectively eliminating the need for virt_to_page() and page_to_phys() conversions. This change does not affect the old style Goldfish tty behaviour which is still used by the Goldfish emulator. Version register has been added and probed to see which platform is running this driver. Reading from the new register GOLDFISH_TTY_REG_VERSION using the Goldfish emulator will return 0 and driver will work with virtual addresses. Whereas if run on Ranchu it returns 1, and thus DMA is used. (Goldfish and Ranchu are code names for the first and the second generation of virtual boards used by Android emulator.) Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman --- drivers/tty/goldfish.c | 166 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 139 insertions(+), 27 deletions(-) diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 011eb53..757e17f 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -22,6 +22,8 @@ #include #include #include +#include +#include /* Goldfish tty register's offsets */ #define GOLDFISH_TTY_REG_BYTES_READY 0x04 @@ -29,6 +31,7 @@ #define GOLDFISH_TTY_REG_DATA_PTR 0x10 #define GOLDFISH_TTY_REG_DATA_LEN 0x14 #define GOLDFISH_TTY_REG_DATA_PTR_HIGH 0x18 +#define GOLDFISH_TTY_REG_VERSION 0x20 /* Goldfish tty commands */ #define GOLDFISH_TTY_CMD_INT_DISABLE 0 @@ -43,6 +46,8 @@ struct goldfish_tty { u32 irq; int opencount; struct console console; + u32 version; + struct device *dev; }; static DEFINE_MUTEX(goldfish_tty_lock); @@ -51,24 +56,95 @@ static u32 goldfish_tty_line_count = 8; static u32 goldfish_tty_current_line_count; static struct goldfish_tty *goldfish_ttys; -static void goldfish_tty_do_write(int line, const char *buf, unsigned count) +static void do_rw_io(struct goldfish_tty *qtty, + unsigned long address, + unsigned int count, + int is_write) { unsigned long irq_flags; - struct goldfish_tty *qtty = &goldfish_ttys[line]; void __iomem *base = qtty->base; + spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, + gf_write_ptr((void *)address, base + GOLDFISH_TTY_REG_DATA_PTR, base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); - writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, base + GOLDFISH_TTY_REG_CMD); + + if (is_write) + writel(GOLDFISH_TTY_CMD_WRITE_BUFFER, + base + GOLDFISH_TTY_REG_CMD); + else + writel(GOLDFISH_TTY_CMD_READ_BUFFER, + base + GOLDFISH_TTY_REG_CMD); + spin_unlock_irqrestore(&qtty->lock, irq_flags); } +static void goldfish_tty_rw(struct goldfish_tty *qtty, + unsigned long addr, + unsigned int count, + int is_write) +{ + dma_addr_t dma_handle; + enum dma_data_direction dma_dir; + + dma_dir = (is_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE); + if (qtty->version > 0) { + /* + * Goldfish TTY for Ranchu platform uses + * physical addresses and DMA for read/write operations + */ + unsigned long addr_end = addr + count; + + while (addr < addr_end) { + unsigned long pg_end = (addr & PAGE_MASK) + PAGE_SIZE; + unsigned long next = + pg_end < addr_end ? pg_end : addr_end; + unsigned long avail = next - addr; + + /* + * Map the buffer's virtual address to the DMA address + * so the buffer can be accessed by the device. + */ + dma_handle = dma_map_single(qtty->dev, (void *)addr, + avail, dma_dir); + + if (dma_mapping_error(qtty->dev, dma_handle)) { + dev_err(qtty->dev, "tty: DMA mapping error.\n"); + return; + } + do_rw_io(qtty, dma_handle, avail, is_write); + + /* + * Unmap the previously mapped region after + * the completion of the read/write operation. + */ + dma_unmap_single(qtty->dev, dma_handle, avail, dma_dir); + + addr += avail; + } + } else { + /* + * Old style Goldfish TTY used on the Goldfish platform + * uses virtual addresses. + */ + do_rw_io(qtty, addr, count, is_write); + } +} + +static void goldfish_tty_do_write(int line, const char *buf, + unsigned int count) +{ + struct goldfish_tty *qtty = &goldfish_ttys[line]; + unsigned long address = (unsigned long)(void *)buf; + + goldfish_tty_rw(qtty, address, count, 1); +} + static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) { struct goldfish_tty *qtty = dev_id; void __iomem *base = qtty->base; - unsigned long irq_flags; + unsigned long address; unsigned char *buf; u32 count; @@ -77,12 +153,10 @@ static irqreturn_t goldfish_tty_interrupt(int irq, void *dev_id) return IRQ_NONE; count = tty_prepare_flip_string(&qtty->port, &buf, count); - spin_lock_irqsave(&qtty->lock, irq_flags); - gf_write_ptr(buf, base + GOLDFISH_TTY_REG_DATA_PTR, - base + GOLDFISH_TTY_REG_DATA_PTR_HIGH); - writel(count, base + GOLDFISH_TTY_REG_DATA_LEN); - writel(GOLDFISH_TTY_CMD_READ_BUFFER, base + GOLDFISH_TTY_REG_CMD); - spin_unlock_irqrestore(&qtty->lock, irq_flags); + + address = (unsigned long)(void *)buf; + goldfish_tty_rw(qtty, address, count, 0); + tty_schedule_flip(&qtty->port); return IRQ_HANDLED; } @@ -225,7 +299,7 @@ static void goldfish_tty_delete_driver(void) static int goldfish_tty_probe(struct platform_device *pdev) { struct goldfish_tty *qtty; - int ret = -EINVAL; + int ret = -ENODEV; struct resource *r; struct device *ttydev; void __iomem *base; @@ -233,16 +307,22 @@ static int goldfish_tty_probe(struct platform_device *pdev) unsigned int line; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (r == NULL) - return -EINVAL; + if (!r) { + pr_err("goldfish_tty: No MEM resource available!\n"); + return -ENOMEM; + } base = ioremap(r->start, 0x1000); - if (base == NULL) - pr_err("goldfish_tty: unable to remap base\n"); + if (!base) { + pr_err("goldfish_tty: Unable to ioremap base!\n"); + return -ENOMEM; + } r = platform_get_resource(pdev, IORESOURCE_IRQ, 0); - if (r == NULL) + if (!r) { + pr_err("goldfish_tty: No IRQ resource available!\n"); goto err_unmap; + } irq = r->start; @@ -253,13 +333,17 @@ static int goldfish_tty_probe(struct platform_device *pdev) else line = pdev->id; - if (line >= goldfish_tty_line_count) - goto err_create_driver_failed; + if (line >= goldfish_tty_line_count) { + pr_err("goldfish_tty: Reached maximum tty number of %d.\n", + goldfish_tty_current_line_count); + ret = -ENOMEM; + goto err_unlock; + } if (goldfish_tty_current_line_count == 0) { ret = goldfish_tty_create_driver(); if (ret) - goto err_create_driver_failed; + goto err_unlock; } goldfish_tty_current_line_count++; @@ -269,17 +353,45 @@ static int goldfish_tty_probe(struct platform_device *pdev) qtty->port.ops = &goldfish_port_ops; qtty->base = base; qtty->irq = irq; + qtty->dev = &pdev->dev; + + /* + * Goldfish TTY device used by the Goldfish emulator + * should identify itself with 0, forcing the driver + * to use virtual addresses. Goldfish TTY device + * on Ranchu emulator (qemu2) returns 1 here and + * driver will use physical addresses. + */ + qtty->version = readl(base + GOLDFISH_TTY_REG_VERSION); + + /* + * Goldfish TTY device on Ranchu emulator (qemu2) + * will use DMA for read/write IO operations. + */ + if (qtty->version > 0) { + /* + * Initialize dma_mask to 32-bits. + */ + if (!pdev->dev.dma_mask) + pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask; + ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32)); + if (ret) { + dev_err(&pdev->dev, "No suitable DMA available.\n"); + goto err_dec_line_count; + } + } writel(GOLDFISH_TTY_CMD_INT_DISABLE, base + GOLDFISH_TTY_REG_CMD); ret = request_irq(irq, goldfish_tty_interrupt, IRQF_SHARED, - "goldfish_tty", qtty); - if (ret) - goto err_request_irq_failed; - + "goldfish_tty", qtty); + if (ret) { + pr_err("goldfish_tty: No IRQ available!\n"); + goto err_dec_line_count; + } ttydev = tty_port_register_device(&qtty->port, goldfish_tty_driver, - line, &pdev->dev); + line, &pdev->dev); if (IS_ERR(ttydev)) { ret = PTR_ERR(ttydev); goto err_tty_register_device_failed; @@ -299,11 +411,11 @@ static int goldfish_tty_probe(struct platform_device *pdev) err_tty_register_device_failed: free_irq(irq, qtty); -err_request_irq_failed: +err_dec_line_count: goldfish_tty_current_line_count--; if (goldfish_tty_current_line_count == 0) goldfish_tty_delete_driver(); -err_create_driver_failed: +err_unlock: mutex_unlock(&goldfish_tty_lock); err_unmap: iounmap(base); -- cgit v1.1 From 3840ed9548f778717aaab5eab744da798c3ea055 Mon Sep 17 00:00:00 2001 From: Miodrag Dinic Date: Tue, 29 Aug 2017 15:53:20 +0200 Subject: tty: goldfish: Implement support for kernel 'earlycon' parameter Add early console functionality to the Goldfish tty driver. When 'earlycon' kernel command line parameter is used with no options, the early console is determined by the 'stdout-path' property in device tree's 'chosen' node. This is illustrated in the following device tree source example: Device tree example: chosen { stdout-path = "/goldfish_tty@1f004000"; }; goldfish_tty@1f004000 { interrupts = <0xc>; reg = <0x1f004000 0x0 0x1000>; compatible = "google,goldfish-tty"; }; Signed-off-by: Miodrag Dinic Signed-off-by: Goran Ferenc Signed-off-by: Aleksandar Markovic Signed-off-by: Greg Kroah-Hartman --- drivers/tty/Kconfig | 3 +++ drivers/tty/goldfish.c | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/drivers/tty/Kconfig b/drivers/tty/Kconfig index 9510305..873e0ba 100644 --- a/drivers/tty/Kconfig +++ b/drivers/tty/Kconfig @@ -392,6 +392,9 @@ config PPC_EARLY_DEBUG_EHV_BC_HANDLE config GOLDFISH_TTY tristate "Goldfish TTY Driver" depends on GOLDFISH + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON help Console and system TTY driver for the Goldfish virtual platform. diff --git a/drivers/tty/goldfish.c b/drivers/tty/goldfish.c index 757e17f..381e981 100644 --- a/drivers/tty/goldfish.c +++ b/drivers/tty/goldfish.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2007 Google, Inc. * Copyright (C) 2012 Intel, Inc. + * Copyright (C) 2017 Imagination Technologies Ltd. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -24,6 +25,7 @@ #include #include #include +#include /* Goldfish tty register's offsets */ #define GOLDFISH_TTY_REG_BYTES_READY 0x04 @@ -440,6 +442,30 @@ static int goldfish_tty_remove(struct platform_device *pdev) return 0; } +static void gf_early_console_putchar(struct uart_port *port, int ch) +{ + __raw_writel(ch, port->membase); +} + +static void gf_early_write(struct console *con, const char *s, unsigned int n) +{ + struct earlycon_device *dev = con->data; + + uart_console_write(&dev->port, s, n, gf_early_console_putchar); +} + +static int __init gf_earlycon_setup(struct earlycon_device *device, + const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = gf_early_write; + return 0; +} + +OF_EARLYCON_DECLARE(early_gf_tty, "google,goldfish-tty", gf_earlycon_setup); + static const struct of_device_id goldfish_tty_of_match[] = { { .compatible = "google,goldfish-tty", }, {}, -- cgit v1.1