diff options
Diffstat (limited to 'drivers/tty/serial')
-rw-r--r-- | drivers/tty/serial/8250/8250_aspeed_vuart.c | 125 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_dw.c | 35 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_early.c | 2 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_of.c | 63 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_omap.c | 27 | ||||
-rw-r--r-- | drivers/tty/serial/8250/8250_port.c | 6 | ||||
-rw-r--r-- | drivers/tty/serial/Kconfig | 8 | ||||
-rw-r--r-- | drivers/tty/serial/amba-pl011.c | 16 | ||||
-rw-r--r-- | drivers/tty/serial/atmel_serial.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/earlycon.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/imx.c | 43 | ||||
-rw-r--r-- | drivers/tty/serial/msm_serial.c | 23 | ||||
-rw-r--r-- | drivers/tty/serial/mvebu-uart.c | 64 | ||||
-rw-r--r-- | drivers/tty/serial/qcom_geni_serial.c | 177 | ||||
-rw-r--r-- | drivers/tty/serial/samsung.c | 40 | ||||
-rw-r--r-- | drivers/tty/serial/sc16is7xx.c | 5 | ||||
-rw-r--r-- | drivers/tty/serial/serial_core.c | 4 | ||||
-rw-r--r-- | drivers/tty/serial/sh-sci.c | 81 | ||||
-rw-r--r-- | drivers/tty/serial/sh-sci.h | 4 | ||||
-rw-r--r-- | drivers/tty/serial/st-asc.c | 6 | ||||
-rw-r--r-- | drivers/tty/serial/xilinx_uartps.c | 108 |
21 files changed, 617 insertions, 230 deletions
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 74a408d9db24..435bec40dee6 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -10,6 +10,8 @@ #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/of_platform.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include <linux/clk.h> #include "8250.h" @@ -28,9 +30,18 @@ struct aspeed_vuart { void __iomem *regs; struct clk *clk; int line; + struct timer_list unthrottle_timer; + struct uart_8250_port *port; }; /* + * If we fill the tty flip buffers, we throttle the data ready interrupt + * to prevent dropped characters. This timeout defines how long we wait + * to (conditionally, depending on buffer state) unthrottle. + */ +static const int unthrottle_timeout = HZ/10; + +/* * The VUART is basically two UART 'front ends' connected by their FIFO * (no actual serial line in between). One is on the BMC side (management * controller) and one is on the host CPU side. @@ -179,6 +190,114 @@ static void aspeed_vuart_shutdown(struct uart_port *uart_port) serial8250_do_shutdown(uart_port); } +static void __aspeed_vuart_set_throttle(struct uart_8250_port *up, + bool throttle) +{ + unsigned char irqs = UART_IER_RLSI | UART_IER_RDI; + + up->ier &= ~irqs; + if (!throttle) + up->ier |= irqs; + serial_out(up, UART_IER, up->ier); +} +static void aspeed_vuart_set_throttle(struct uart_port *port, bool throttle) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + __aspeed_vuart_set_throttle(up, throttle); + spin_unlock_irqrestore(&port->lock, flags); +} + +static void aspeed_vuart_throttle(struct uart_port *port) +{ + aspeed_vuart_set_throttle(port, true); +} + +static void aspeed_vuart_unthrottle(struct uart_port *port) +{ + aspeed_vuart_set_throttle(port, false); +} + +static void aspeed_vuart_unthrottle_exp(struct timer_list *timer) +{ + struct aspeed_vuart *vuart = from_timer(vuart, timer, unthrottle_timer); + struct uart_8250_port *up = vuart->port; + + if (!tty_buffer_space_avail(&up->port.state->port)) { + mod_timer(&vuart->unthrottle_timer, + jiffies + unthrottle_timeout); + return; + } + + aspeed_vuart_unthrottle(&up->port); +} + +/* + * Custom interrupt handler to manage finer-grained flow control. Although we + * have throttle/unthrottle callbacks, we've seen that the VUART device can + * deliver characters faster than the ldisc has a chance to check buffer space + * against the throttle threshold. This results in dropped characters before + * the throttle. + * + * We do this by checking for flip buffer space before RX. If we have no space, + * throttle now and schedule an unthrottle for later, once the ldisc has had + * a chance to drain the buffers. + */ +static int aspeed_vuart_handle_irq(struct uart_port *port) +{ + struct uart_8250_port *up = up_to_u8250p(port); + unsigned int iir, lsr; + unsigned long flags; + int space, count; + + iir = serial_port_in(port, UART_IIR); + + if (iir & UART_IIR_NO_INT) + return 0; + + spin_lock_irqsave(&port->lock, flags); + + lsr = serial_port_in(port, UART_LSR); + + if (lsr & (UART_LSR_DR | UART_LSR_BI)) { + space = tty_buffer_space_avail(&port->state->port); + + if (!space) { + /* throttle and schedule an unthrottle later */ + struct aspeed_vuart *vuart = port->private_data; + __aspeed_vuart_set_throttle(up, true); + + if (!timer_pending(&vuart->unthrottle_timer)) { + vuart->port = up; + mod_timer(&vuart->unthrottle_timer, + jiffies + unthrottle_timeout); + } + + } else { + count = min(space, 256); + + do { + serial8250_read_char(up, lsr); + lsr = serial_in(up, UART_LSR); + if (--count == 0) + break; + } while (lsr & (UART_LSR_DR | UART_LSR_BI)); + + tty_flip_buffer_push(&port->state->port); + } + } + + serial8250_modem_status(up); + if (lsr & UART_LSR_THRE) + serial8250_tx_chars(up); + + spin_unlock_irqrestore(&port->lock, flags); + + return 1; +} + static int aspeed_vuart_probe(struct platform_device *pdev) { struct uart_8250_port port; @@ -195,6 +314,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) return -ENOMEM; vuart->dev = &pdev->dev; + timer_setup(&vuart->unthrottle_timer, aspeed_vuart_unthrottle_exp, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); vuart->regs = devm_ioremap_resource(&pdev->dev, res); @@ -208,6 +328,9 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.mapsize = resource_size(res); port.port.startup = aspeed_vuart_startup; port.port.shutdown = aspeed_vuart_shutdown; + port.port.throttle = aspeed_vuart_throttle; + port.port.unthrottle = aspeed_vuart_unthrottle; + port.port.status = UPSTAT_SYNC_FIFO; port.port.dev = &pdev->dev; rc = sysfs_create_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); @@ -253,6 +376,7 @@ static int aspeed_vuart_probe(struct platform_device *pdev) port.port.irq = irq_of_parse_and_map(np, 0); port.port.irqflags = IRQF_SHARED; + port.port.handle_irq = aspeed_vuart_handle_irq; port.port.iotype = UPIO_MEM; port.port.type = PORT_16550A; port.port.uartclk = clk; @@ -292,6 +416,7 @@ static int aspeed_vuart_remove(struct platform_device *pdev) { struct aspeed_vuart *vuart = platform_get_drvdata(pdev); + del_timer_sync(&vuart->unthrottle_timer); aspeed_vuart_set_enabled(vuart, false); serial8250_unregister_port(vuart->line); sysfs_remove_group(&vuart->dev->kobj, &aspeed_vuart_attr_group); diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 6fcdb90f616a..aff04f1de3a5 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -121,25 +121,44 @@ static void dw8250_check_lcr(struct uart_port *p, int value) } /* Returns once the transmitter is empty or we run out of retries */ -static void dw8250_tx_wait_empty(struct uart_port *p, int tries) +static void dw8250_tx_wait_empty(struct uart_port *p) { + unsigned int tries = 20000; + unsigned int delay_threshold = tries - 1000; unsigned int lsr; while (tries--) { lsr = readb (p->membase + (UART_LSR << p->regshift)); if (lsr & UART_LSR_TEMT) break; - udelay (10); + + /* The device is first given a chance to empty without delay, + * to avoid slowdowns at high bitrates. If after 1000 tries + * the buffer has still not emptied, allow more time for low- + * speed links. */ + if (tries < delay_threshold) + udelay (1); } } -static void dw8250_serial_out(struct uart_port *p, int offset, int value) +static void dw8250_serial_out38x(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; /* Allow the TX to drain before we reconfigure */ if (offset == UART_LCR) - dw8250_tx_wait_empty(p, 1000); + dw8250_tx_wait_empty(p); + + writeb(value, p->membase + (offset << p->regshift)); + + if (offset == UART_LCR && !d->uart_16550_compatible) + dw8250_check_lcr(p, value); +} + + +static void dw8250_serial_out(struct uart_port *p, int offset, int value) +{ + struct dw8250_data *d = p->private_data; writeb(value, p->membase + (offset << p->regshift)); @@ -357,6 +376,9 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) p->serial_in = dw8250_serial_in32be; p->serial_out = dw8250_serial_out32be; } + if (of_device_is_compatible(np, "marvell,armada-38x-uart")) + p->serial_out = dw8250_serial_out38x; + } else if (acpi_dev_present("APMC0D08", NULL, -1)) { p->iotype = UPIO_MEM32; p->regshift = 2; @@ -554,6 +576,10 @@ static int dw8250_probe(struct platform_device *pdev) if (!data->skip_autocfg) dw8250_setup_port(p); +#ifdef CONFIG_PM + uart.capabilities |= UART_CAP_RPM; +#endif + /* If we have a valid fifosize, try hooking up DMA */ if (p->fifosize) { data->dma.rxconf.src_maxburst = p->fifosize / 4; @@ -666,6 +692,7 @@ static const struct dev_pm_ops dw8250_pm_ops = { static const struct of_device_id dw8250_of_match[] = { { .compatible = "snps,dw-apb-uart" }, { .compatible = "cavium,octeon-3860-uart" }, + { .compatible = "marvell,armada-38x-uart" }, { /* Sentinel */ } }; MODULE_DEVICE_TABLE(of, dw8250_of_match); diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c index ae6a256524d8..5cd8c36c8fcc 100644 --- a/drivers/tty/serial/8250/8250_early.c +++ b/drivers/tty/serial/8250/8250_early.c @@ -122,7 +122,7 @@ static void __init init_port(struct earlycon_device *device) serial8250_early_out(port, UART_FCR, 0); /* no fifo */ serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */ - if (port->uartclk && device->baud) { + if (port->uartclk) { divisor = DIV_ROUND_CLOSEST(port->uartclk, 16 * device->baud); c = serial8250_early_in(port, UART_LCR); serial8250_early_out(port, UART_LCR, c | UART_LCR_DLAB); diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 9835b1c1cbe1..bfb37f0be22f 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -92,13 +92,43 @@ static int of_platform_serial_setup(struct platform_device *ofdev, goto err_unprepare; } + port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | + UPF_FIXED_TYPE; spin_lock_init(&port->lock); - port->mapbase = resource.start; - port->mapsize = resource_size(&resource); - /* Check for shifted address mapping */ - if (of_property_read_u32(np, "reg-offset", &prop) == 0) - port->mapbase += prop; + if (resource_type(&resource) == IORESOURCE_IO) { + port->iotype = UPIO_PORT; + port->iobase = resource.start; + } else { + port->mapbase = resource.start; + port->mapsize = resource_size(&resource); + + /* Check for shifted address mapping */ + if (of_property_read_u32(np, "reg-offset", &prop) == 0) + port->mapbase += prop; + + port->iotype = UPIO_MEM; + if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { + switch (prop) { + case 1: + port->iotype = UPIO_MEM; + break; + case 2: + port->iotype = UPIO_MEM16; + break; + case 4: + port->iotype = of_device_is_big_endian(np) ? + UPIO_MEM32BE : UPIO_MEM32; + break; + default: + dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", + prop); + ret = -EINVAL; + goto err_dispose; + } + } + port->flags |= UPF_IOREMAP; + } /* Check for registers offset within the devices address range */ if (of_property_read_u32(np, "reg-shift", &prop) == 0) @@ -114,26 +144,6 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->line = ret; port->irq = irq_of_parse_and_map(np, 0); - port->iotype = UPIO_MEM; - if (of_property_read_u32(np, "reg-io-width", &prop) == 0) { - switch (prop) { - case 1: - port->iotype = UPIO_MEM; - break; - case 2: - port->iotype = UPIO_MEM16; - break; - case 4: - port->iotype = of_device_is_big_endian(np) ? - UPIO_MEM32BE : UPIO_MEM32; - break; - default: - dev_warn(&ofdev->dev, "unsupported reg-io-width (%d)\n", - prop); - ret = -EINVAL; - goto err_dispose; - } - } info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL); if (IS_ERR(info->rst)) { @@ -147,8 +157,7 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->type = type; port->uartclk = clk; - port->flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF | UPF_IOREMAP - | UPF_FIXED_PORT | UPF_FIXED_TYPE; + port->irqflags |= IRQF_SHARED; if (of_property_read_bool(np, "no-loopback-test")) port->flags |= UPF_SKIP_TEST; diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 624b501fd253..1b337fee07ed 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -1110,13 +1110,14 @@ static int omap8250_no_handle_irq(struct uart_port *port) return 0; } +static const u8 omap4_habit = UART_ERRATA_CLOCK_DISABLE; static const u8 am3352_habit = OMAP_DMA_TX_KICK | UART_ERRATA_CLOCK_DISABLE; static const u8 dra742_habit = UART_ERRATA_CLOCK_DISABLE; static const struct of_device_id omap8250_dt_ids[] = { { .compatible = "ti,omap2-uart" }, { .compatible = "ti,omap3-uart" }, - { .compatible = "ti,omap4-uart" }, + { .compatible = "ti,omap4-uart", .data = &omap4_habit, }, { .compatible = "ti,am3352-uart", .data = &am3352_habit, }, { .compatible = "ti,am4372-uart", .data = &am3352_habit, }, { .compatible = "ti,dra742-uart", .data = &dra742_habit, }, @@ -1310,8 +1311,17 @@ static void omap8250_complete(struct device *dev) static int omap8250_suspend(struct device *dev) { struct omap8250_priv *priv = dev_get_drvdata(dev); + struct uart_8250_port *up = serial8250_get_port(priv->line); serial8250_suspend_port(priv->line); + + pm_runtime_get_sync(dev); + if (!device_may_wakeup(dev)) + priv->wer = 0; + serial_out(up, UART_OMAP_WER, priv->wer); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + flush_work(&priv->qos_work); return 0; } @@ -1353,6 +1363,19 @@ static int omap8250_soft_reset(struct device *dev) int sysc; int syss; + /* + * At least on omap4, unused uarts may not idle after reset without + * a basic scr dma configuration even with no dma in use. The + * module clkctrl status bits will be 1 instead of 3 blocking idle + * for the whole clockdomain. The softreset below will clear scr, + * and we restore it on resume so this is safe to do on all SoCs + * needing omap8250_soft_reset() quirk. Do it in two writes as + * recommended in the comment for omap8250_update_scr(). + */ + serial_out(up, UART_OMAP_SCR, OMAP_UART_SCR_DMAMODE_1); + serial_out(up, UART_OMAP_SCR, + OMAP_UART_SCR_DMAMODE_1 | OMAP_UART_SCR_DMAMODE_CTL); + sysc = serial_in(up, UART_OMAP_SYSC); /* softreset the UART */ @@ -1403,6 +1426,8 @@ static int omap8250_runtime_suspend(struct device *dev) /* Restore to UART mode after reset (for wakeup) */ omap8250_update_mdr1(up, priv); + /* Restore wakeup enable register */ + serial_out(up, UART_OMAP_WER, priv->wer); } if (up->dma && up->dma->rxchan) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 95833cbc4338..cf541aab2bd0 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -243,6 +243,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 32, .tx_loadsz = 32, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 8, 16, 30}, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, [PORT_ALTR_16550_F64] = { @@ -250,6 +251,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 64, .tx_loadsz = 64, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 16, 32, 62}, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, [PORT_ALTR_16550_F128] = { @@ -257,6 +259,7 @@ static const struct serial8250_config uart_config[] = { .fifo_size = 128, .tx_loadsz = 128, .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10, + .rxtrig_bytes = {1, 32, 64, 126}, .flags = UART_CAP_FIFO | UART_CAP_AFE, }, /* @@ -1680,7 +1683,7 @@ static void serial8250_enable_ms(struct uart_port *port) serial8250_rpm_put(up); } -static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) +void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) { struct uart_port *port = &up->port; unsigned char ch; @@ -1740,6 +1743,7 @@ static void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); } +EXPORT_SYMBOL_GPL(serial8250_read_char); /* * serial8250_rx_chars: processes according to the passed in LSR diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 0f058df0b070..df8bd0c7b97d 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -115,7 +115,6 @@ config SERIAL_SB1250_DUART_CONSOLE config SERIAL_ATMEL bool "AT91 on-chip serial port support" - depends on HAS_DMA depends on ARCH_AT91 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB @@ -500,7 +499,6 @@ config SERIAL_SA1100_CONSOLE config SERIAL_IMX tristate "IMX serial port support" - depends on HAS_DMA depends on ARCH_MXC || COMPILE_TEST select SERIAL_CORE select RATIONAL @@ -676,6 +674,8 @@ config SERIAL_SH_SCI config SERIAL_SH_SCI_NR_UARTS int "Maximum number of SCI(F) serial ports" if EXPERT + range 1 64 if 64BIT + range 1 32 if !64BIT depends on SERIAL_SH_SCI default "3" if H8300 default "10" if SUPERH @@ -1262,7 +1262,6 @@ config SERIAL_PCH_UART_CONSOLE config SERIAL_MXS_AUART tristate "MXS AUART support" - depends on HAS_DMA depends on ARCH_MXS || MACH_ASM9260 || COMPILE_TEST select SERIAL_CORE select SERIAL_MCTRL_GPIO if GPIOLIB @@ -1295,7 +1294,7 @@ config SERIAL_XILINX_PS_UART_CONSOLE config SERIAL_AR933X tristate "AR933X serial port support" - depends on HAVE_CLK && SOC_AR933X + depends on HAVE_CLK && ATH79 select SERIAL_CORE help If you have an Atheros AR933X SOC based board and want to use the @@ -1473,7 +1472,6 @@ config SERIAL_SPRD_CONSOLE config SERIAL_STM32 tristate "STMicroelectronics STM32 serial port support" select SERIAL_CORE - depends on HAS_DMA depends on ARCH_STM32 || COMPILE_TEST help This driver is for the on-chip Serial Controller on diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index 4b40a5b449ee..ebd33c0232e6 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -1727,10 +1727,26 @@ static int pl011_allocate_irq(struct uart_amba_port *uap) */ static void pl011_enable_interrupts(struct uart_amba_port *uap) { + unsigned int i; + spin_lock_irq(&uap->port.lock); /* Clear out any spuriously appearing RX interrupts */ pl011_write(UART011_RTIS | UART011_RXIS, uap, REG_ICR); + + /* + * RXIS is asserted only when the RX FIFO transitions from below + * to above the trigger threshold. If the RX FIFO is already + * full to the threshold this can't happen and RXIS will now be + * stuck off. Drain the RX FIFO explicitly to fix this: + */ + for (i = 0; i < uap->fifosize * 2; ++i) { + if (pl011_read(uap, REG_FR) & UART01x_FR_RXFE) + break; + + pl011_read(uap, REG_DR); + } + uap->im = UART011_RTIM; if (!pl011_dma_rx_running(uap)) uap->im |= UART011_RXIM; diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index e287fe8f10fc..55b3eff148b1 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -1757,7 +1757,6 @@ static int atmel_startup(struct uart_port *port) { struct platform_device *pdev = to_platform_device(port->dev); struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); - struct tty_struct *tty = port->state->port.tty; int retval; /* @@ -1772,8 +1771,8 @@ static int atmel_startup(struct uart_port *port) * Allocate the IRQ */ retval = request_irq(port->irq, atmel_interrupt, - IRQF_SHARED | IRQF_COND_SUSPEND, - tty ? tty->name : "atmel_serial", port); + IRQF_SHARED | IRQF_COND_SUSPEND, + dev_name(&pdev->dev), port); if (retval) { dev_err(port->dev, "atmel_startup - Can't get irq\n"); return retval; diff --git a/drivers/tty/serial/earlycon.c b/drivers/tty/serial/earlycon.c index 22683393a0f2..c14873b67803 100644 --- a/drivers/tty/serial/earlycon.c +++ b/drivers/tty/serial/earlycon.c @@ -246,7 +246,6 @@ int __init of_setup_earlycon(const struct earlycon_id *match, return -ENXIO; } port->mapbase = addr; - port->uartclk = BASE_BAUD * 16; val = of_get_flat_dt_prop(node, "reg-offset", NULL); if (val) @@ -281,6 +280,10 @@ int __init of_setup_earlycon(const struct earlycon_id *match, if (val) early_console_dev.baud = be32_to_cpu(*val); + val = of_get_flat_dt_prop(node, "clock-frequency", NULL); + if (val) + port->uartclk = be32_to_cpu(*val); + if (options) { early_console_dev.baud = simple_strtoul(options, NULL, 0); strlcpy(early_console_dev.options, options, diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c2fc6bef7a6f..4e853570ea80 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1291,18 +1291,13 @@ static void imx_uart_enable_dma(struct imx_port *sport) static void imx_uart_disable_dma(struct imx_port *sport) { - u32 ucr1, ucr2; + u32 ucr1; /* clear UCR1 */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); imx_uart_writel(sport, ucr1, UCR1); - /* clear UCR2 */ - ucr2 = imx_uart_readl(sport, UCR2); - ucr2 &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); - imx_uart_writel(sport, ucr2, UCR2); - imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); sport->dma_is_enabled = 0; @@ -1427,13 +1422,21 @@ static void imx_uart_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - u32 ucr1, ucr2; + u32 ucr1, ucr2, ucr4; if (sport->dma_is_enabled) { - sport->dma_is_rxing = 0; - sport->dma_is_txing = 0; dmaengine_terminate_sync(sport->dma_chan_tx); + if (sport->dma_is_txing) { + dma_unmap_sg(sport->port.dev, &sport->tx_sgl[0], + sport->dma_tx_nents, DMA_TO_DEVICE); + sport->dma_is_txing = 0; + } dmaengine_terminate_sync(sport->dma_chan_rx); + if (sport->dma_is_rxing) { + dma_unmap_sg(sport->port.dev, &sport->rx_sgl, + 1, DMA_FROM_DEVICE); + sport->dma_is_rxing = 0; + } spin_lock_irqsave(&sport->port.lock, flags); imx_uart_stop_tx(port); @@ -1449,6 +1452,10 @@ static void imx_uart_shutdown(struct uart_port *port) ucr2 = imx_uart_readl(sport, UCR2); ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); imx_uart_writel(sport, ucr2, UCR2); + + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 &= ~UCR4_OREN; + imx_uart_writel(sport, ucr4, UCR4); spin_unlock_irqrestore(&sport->port.lock, flags); /* @@ -2425,8 +2432,7 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) static int imx_uart_suspend_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); imx_uart_save_context(sport); @@ -2437,8 +2443,7 @@ static int imx_uart_suspend_noirq(struct device *dev) static int imx_uart_resume_noirq(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); int ret; ret = clk_enable(sport->clk_ipg); @@ -2452,8 +2457,7 @@ static int imx_uart_resume_noirq(struct device *dev) static int imx_uart_suspend(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); int ret; uart_suspend_port(&imx_uart_uart_driver, &sport->port); @@ -2471,8 +2475,7 @@ static int imx_uart_suspend(struct device *dev) static int imx_uart_resume(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); /* disable wakeup from i.MX UART */ imx_uart_enable_wakeup(sport, false); @@ -2487,8 +2490,7 @@ static int imx_uart_resume(struct device *dev) static int imx_uart_freeze(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); uart_suspend_port(&imx_uart_uart_driver, &sport->port); @@ -2497,8 +2499,7 @@ static int imx_uart_freeze(struct device *dev) static int imx_uart_thaw(struct device *dev) { - struct platform_device *pdev = to_platform_device(dev); - struct imx_port *sport = platform_get_drvdata(pdev); + struct imx_port *sport = dev_get_drvdata(dev); uart_resume_port(&imx_uart_uart_driver, &sport->port); diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index ee96cf0d0057..736b74fd6623 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1812,11 +1812,34 @@ static const struct of_device_id msm_match_table[] = { }; MODULE_DEVICE_TABLE(of, msm_match_table); +static int __maybe_unused msm_serial_suspend(struct device *dev) +{ + struct msm_port *port = dev_get_drvdata(dev); + + uart_suspend_port(&msm_uart_driver, &port->uart); + + return 0; +} + +static int __maybe_unused msm_serial_resume(struct device *dev) +{ + struct msm_port *port = dev_get_drvdata(dev); + + uart_resume_port(&msm_uart_driver, &port->uart); + + return 0; +} + +static const struct dev_pm_ops msm_serial_dev_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(msm_serial_suspend, msm_serial_resume) +}; + static struct platform_driver msm_platform_driver = { .remove = msm_serial_remove, .probe = msm_serial_probe, .driver = { .name = "msm_serial", + .pm = &msm_serial_dev_pm_ops, .of_match_table = msm_match_table, }, }; diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index f503fab1e268..d04b5eeea3c6 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -71,6 +71,8 @@ #define UART_BRDV 0x10 #define BRDV_BAUD_MASK 0x3FF +#define UART_OSAMP 0x14 + #define MVEBU_NR_UARTS 2 #define MVEBU_UART_TYPE "mvebu-uart" @@ -108,6 +110,17 @@ struct mvebu_uart_driver_data { struct uart_flags flags; }; +/* Saved registers during suspend */ +struct mvebu_uart_pm_regs { + unsigned int rbr; + unsigned int tsh; + unsigned int ctrl; + unsigned int intr; + unsigned int stat; + unsigned int brdv; + unsigned int osamp; +}; + /* MVEBU UART driver structure */ struct mvebu_uart { struct uart_port *port; @@ -115,6 +128,9 @@ struct mvebu_uart { int irq[UART_IRQ_COUNT]; unsigned char __iomem *nb; struct mvebu_uart_driver_data *data; +#if defined(CONFIG_PM) + struct mvebu_uart_pm_regs pm_regs; +#endif /* CONFIG_PM */ }; static struct mvebu_uart *to_mvuart(struct uart_port *port) @@ -718,6 +734,51 @@ static struct uart_driver mvebu_uart_driver = { #endif }; +#if defined(CONFIG_PM) +static int mvebu_uart_suspend(struct device *dev) +{ + struct mvebu_uart *mvuart = dev_get_drvdata(dev); + struct uart_port *port = mvuart->port; + + uart_suspend_port(&mvebu_uart_driver, port); + + mvuart->pm_regs.rbr = readl(port->membase + UART_RBR(port)); + mvuart->pm_regs.tsh = readl(port->membase + UART_TSH(port)); + mvuart->pm_regs.ctrl = readl(port->membase + UART_CTRL(port)); + mvuart->pm_regs.intr = readl(port->membase + UART_INTR(port)); + mvuart->pm_regs.stat = readl(port->membase + UART_STAT); + mvuart->pm_regs.brdv = readl(port->membase + UART_BRDV); + mvuart->pm_regs.osamp = readl(port->membase + UART_OSAMP); + + device_set_wakeup_enable(dev, true); + + return 0; +} + +static int mvebu_uart_resume(struct device *dev) +{ + struct mvebu_uart *mvuart = dev_get_drvdata(dev); + struct uart_port *port = mvuart->port; + + writel(mvuart->pm_regs.rbr, port->membase + UART_RBR(port)); + writel(mvuart->pm_regs.tsh, port->membase + UART_TSH(port)); + writel(mvuart->pm_regs.ctrl, port->membase + UART_CTRL(port)); + writel(mvuart->pm_regs.intr, port->membase + UART_INTR(port)); + writel(mvuart->pm_regs.stat, port->membase + UART_STAT); + writel(mvuart->pm_regs.brdv, port->membase + UART_BRDV); + writel(mvuart->pm_regs.osamp, port->membase + UART_OSAMP); + + uart_resume_port(&mvebu_uart_driver, port); + + return 0; +} + +static const struct dev_pm_ops mvebu_uart_pm_ops = { + .suspend = mvebu_uart_suspend, + .resume = mvebu_uart_resume, +}; +#endif /* CONFIG_PM */ + static const struct of_device_id mvebu_uart_of_match[]; /* Counter to keep track of each UART port id when not using CONFIG_OF */ @@ -891,6 +952,9 @@ static struct platform_driver mvebu_uart_platform_driver = { .name = "mvebu-uart", .of_match_table = of_match_ptr(mvebu_uart_of_match), .suppress_bind_attrs = true, +#if defined(CONFIG_PM) + .pm = &mvebu_uart_pm_ops, +#endif /* CONFIG_PM */ |