diff options
Diffstat (limited to 'drivers/tty/serial')
46 files changed, 2699 insertions, 670 deletions
diff --git a/drivers/tty/serial/8250/8250_aspeed_vuart.c b/drivers/tty/serial/8250/8250_aspeed_vuart.c index 435bec40dee6..0438d9a905ce 100644 --- a/drivers/tty/serial/8250/8250_aspeed_vuart.c +++ b/drivers/tty/serial/8250/8250_aspeed_vuart.c @@ -5,6 +5,10 @@ * Copyright (C) 2016 Jeremy Kerr <jk@ozlabs.org>, IBM Corp. * Copyright (C) 2006 Arnd Bergmann <arnd@arndb.de>, IBM Corp. */ +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/device.h> #include <linux/module.h> #include <linux/of_address.h> @@ -293,7 +297,7 @@ static int aspeed_vuart_handle_irq(struct uart_port *port) if (lsr & UART_LSR_THRE) serial8250_tx_chars(up); - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq(port, flags); return 1; } diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 94f3e1c64490..e441221e04b9 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -942,6 +942,21 @@ static struct uart_8250_port *serial8250_find_match_or_unused(struct uart_port * return NULL; } +static void serial_8250_overrun_backoff_work(struct work_struct *work) +{ + struct uart_8250_port *up = + container_of(to_delayed_work(work), struct uart_8250_port, + overrun_backoff); + struct uart_port *port = &up->port; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + up->ier |= UART_IER_RLSI | UART_IER_RDI; + up->port.read_status_mask |= UART_LSR_DR; + serial_out(up, UART_IER, up->ier); + spin_unlock_irqrestore(&port->lock, flags); +} + /** * serial8250_register_8250_port - register a serial port * @up: serial port template @@ -1055,7 +1070,18 @@ int serial8250_register_8250_port(struct uart_8250_port *up) ret = 0; } + + /* Initialise interrupt backoff work if required */ + if (up->overrun_backoff_time_ms > 0) { + uart->overrun_backoff_time_ms = + up->overrun_backoff_time_ms; + INIT_DELAYED_WORK(&uart->overrun_backoff, + serial_8250_overrun_backoff_work); + } else { + uart->overrun_backoff_time_ms = 0; + } } + mutex_unlock(&serial_mutex); return ret; diff --git a/drivers/tty/serial/8250/8250_fsl.c b/drivers/tty/serial/8250/8250_fsl.c index 6640a4c7ddd1..aa0e216d5ead 100644 --- a/drivers/tty/serial/8250/8250_fsl.c +++ b/drivers/tty/serial/8250/8250_fsl.c @@ -1,4 +1,8 @@ // SPDX-License-Identifier: GPL-2.0 +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + #include <linux/serial_reg.h> #include <linux/serial_8250.h> @@ -45,8 +49,29 @@ int fsl8250_handle_irq(struct uart_port *port) lsr = orig_lsr = up->port.serial_in(&up->port, UART_LSR); - if (lsr & (UART_LSR_DR | UART_LSR_BI)) + /* Process incoming characters first */ + if ((lsr & (UART_LSR_DR | UART_LSR_BI)) && + (up->ier & (UART_IER_RLSI | UART_IER_RDI))) { lsr = serial8250_rx_chars(up, lsr); + } + + /* Stop processing interrupts on input overrun */ + if ((orig_lsr & UART_LSR_OE) && (up->overrun_backoff_time_ms > 0)) { + unsigned long delay; + + up->ier = port->serial_in(port, UART_IER); + if (up->ier & (UART_IER_RLSI | UART_IER_RDI)) { + port->ops->stop_rx(port); + } else { + /* Keep restarting the timer until + * the input overrun subsides. + */ + cancel_delayed_work(&up->overrun_backoff); + } + + delay = msecs_to_jiffies(up->overrun_backoff_time_ms); + schedule_delayed_work(&up->overrun_backoff, delay); + } serial8250_modem_status(up); @@ -54,7 +79,7 @@ int fsl8250_handle_irq(struct uart_port *port) serial8250_tx_chars(up); up->lsr_saved_flags = orig_lsr; - spin_unlock_irqrestore(&up->port.lock, flags); + uart_unlock_and_check_sysrq(&up->port, flags); return 1; } EXPORT_SYMBOL_GPL(fsl8250_handle_irq); diff --git a/drivers/tty/serial/8250/8250_ingenic.c b/drivers/tty/serial/8250/8250_ingenic.c index 15a8c8dfa92b..424c07c5f629 100644 --- a/drivers/tty/serial/8250/8250_ingenic.c +++ b/drivers/tty/serial/8250/8250_ingenic.c @@ -129,22 +129,21 @@ static int __init ingenic_early_console_setup(struct earlycon_device *dev, return 0; } -EARLYCON_DECLARE(jz4740_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4740_uart, "ingenic,jz4740-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4770_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4770_uart, "ingenic,jz4770-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4775_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4775_uart, "ingenic,jz4775-uart", ingenic_early_console_setup); -EARLYCON_DECLARE(jz4780_uart, ingenic_early_console_setup); OF_EARLYCON_DECLARE(jz4780_uart, "ingenic,jz4780-uart", ingenic_early_console_setup); +OF_EARLYCON_DECLARE(x1000_uart, "ingenic,x1000-uart", + ingenic_early_console_setup); + static void ingenic_uart_serial_out(struct uart_port *p, int offset, int value) { int ier; @@ -328,12 +327,18 @@ static const struct ingenic_uart_config jz4780_uart_config = { .fifosize = 64, }; +static const struct ingenic_uart_config x1000_uart_config = { + .tx_loadsz = 32, + .fifosize = 64, +}; + static const struct of_device_id of_match[] = { { .compatible = "ingenic,jz4740-uart", .data = &jz4740_uart_config }, { .compatible = "ingenic,jz4760-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4770-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4775-uart", .data = &jz4760_uart_config }, { .compatible = "ingenic,jz4780-uart", .data = &jz4780_uart_config }, + { .compatible = "ingenic,x1000-uart", .data = &x1000_uart_config }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, of_match); diff --git a/drivers/tty/serial/8250/8250_lpss.c b/drivers/tty/serial/8250/8250_lpss.c index 98dbc796353f..53ca9ba6ab4b 100644 --- a/drivers/tty/serial/8250/8250_lpss.c +++ b/drivers/tty/serial/8250/8250_lpss.c @@ -153,7 +153,6 @@ static int byt_serial_setup(struct lpss8250 *lpss, struct uart_port *port) #ifdef CONFIG_SERIAL_8250_DMA static const struct dw_dma_platform_data qrk_serial_dma_pdata = { .nr_channels = 2, - .is_private = true, .chan_allocation_order = CHAN_ALLOCATION_ASCENDING, .chan_priority = CHAN_PRIORITY_ASCENDING, .block_size = 4095, diff --git a/drivers/tty/serial/8250/8250_mtk.c b/drivers/tty/serial/8250/8250_mtk.c index c3f933d10295..c1fdbc0b6840 100644 --- a/drivers/tty/serial/8250/8250_mtk.c +++ b/drivers/tty/serial/8250/8250_mtk.c @@ -14,6 +14,10 @@ #include <linux/pm_runtime.h> #include <linux/serial_8250.h> #include <linux/serial_reg.h> +#include <linux/console.h> +#include <linux/dma-mapping.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #include "8250.h" @@ -22,12 +26,172 @@ #define UART_MTK_SAMPLE_POINT 0x0b /* Sample point register */ #define MTK_UART_RATE_FIX 0x0d /* UART Rate Fix Register */ +#define MTK_UART_DMA_EN 0x13 /* DMA Enable register */ +#define MTK_UART_DMA_EN_TX 0x2 +#define MTK_UART_DMA_EN_RX 0x5 + +#define MTK_UART_TX_SIZE UART_XMIT_SIZE +#define MTK_UART_RX_SIZE 0x8000 +#define MTK_UART_TX_TRIGGER 1 +#define MTK_UART_RX_TRIGGER MTK_UART_RX_SIZE + +#ifdef CONFIG_SERIAL_8250_DMA +enum dma_rx_status { + DMA_RX_START = 0, + DMA_RX_RUNNING = 1, + DMA_RX_SHUTDOWN = 2, +}; +#endif + struct mtk8250_data { int line; + unsigned int rx_pos; struct clk *uart_clk; struct clk *bus_clk; + struct uart_8250_dma *dma; +#ifdef CONFIG_SERIAL_8250_DMA + enum dma_rx_status rx_status; +#endif }; +#ifdef CONFIG_SERIAL_8250_DMA +static void mtk8250_rx_dma(struct uart_8250_port *up); + +static void mtk8250_dma_rx_complete(void *param) +{ + struct uart_8250_port *up = param; + struct uart_8250_dma *dma = up->dma; + struct mtk8250_data *data = up->port.private_data; + struct tty_port *tty_port = &up->port.state->port; + struct dma_tx_state state; + unsigned char *ptr; + int copied; + + dma_sync_single_for_cpu(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + + if (data->rx_status == DMA_RX_SHUTDOWN) + return; + + if ((data->rx_pos + state.residue) <= dma->rx_size) { + ptr = (unsigned char *)(data->rx_pos + dma->rx_buf); + copied = tty_insert_flip_string(tty_port, ptr, state.residue); + } else { + ptr = (unsigned char *)(data->rx_pos + dma->rx_buf); + copied = tty_insert_flip_string(tty_port, ptr, + dma->rx_size - data->rx_pos); + ptr = (unsigned char *)(dma->rx_buf); + copied += tty_insert_flip_string(tty_port, ptr, + data->rx_pos + state.residue - dma->rx_size); + } + up->port.icount.rx += copied; + + tty_flip_buffer_push(tty_port); + + mtk8250_rx_dma(up); +} + +static void mtk8250_rx_dma(struct uart_8250_port *up) +{ + struct uart_8250_dma *dma = up->dma; + struct mtk8250_data *data = up->port.private_data; + struct dma_async_tx_descriptor *desc; + struct dma_tx_state state; + + desc = dmaengine_prep_slave_single(dma->rxchan, dma->rx_addr, + dma->rx_size, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT | DMA_CTRL_ACK); + if (!desc) { + pr_err("failed to prepare rx slave single\n"); + return; + } + + desc->callback = mtk8250_dma_rx_complete; + desc->callback_param = up; + + dma->rx_cookie = dmaengine_submit(desc); + + dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state); + data->rx_pos = state.residue; + + dma_sync_single_for_device(dma->rxchan->device->dev, dma->rx_addr, + dma->rx_size, DMA_FROM_DEVICE); + + dma_async_issue_pending(dma->rxchan); +} + +static void mtk8250_dma_enable(struct uart_8250_port *up) +{ + struct uart_8250_dma *dma = up->dma; + struct mtk8250_data *data = up->port.private_data; + int lcr = serial_in(up, UART_LCR); + + if (data->rx_status != DMA_RX_START) + return; + + dma->rxconf.direction = DMA_DEV_TO_MEM; + dma->rxconf.src_addr_width = dma->rx_size / 1024; + dma->rxconf.src_addr = dma->rx_addr; + + dma->txconf.direction = DMA_MEM_TO_DEV; + dma->txconf.dst_addr_width = MTK_UART_TX_SIZE / 1024; + dma->txconf.dst_addr = dma->tx_addr; + + serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT); + serial_out(up, MTK_UART_DMA_EN, + MTK_UART_DMA_EN_RX | MTK_UART_DMA_EN_TX); + + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + serial_out(up, UART_EFR, UART_EFR_ECB); + serial_out(up, UART_LCR, lcr); + + if (dmaengine_slave_config(dma->rxchan, &dma->rxconf) != 0) + pr_err("failed to configure rx dma channel\n"); + if (dmaengine_slave_config(dma->txchan, &dma->txconf) != 0) + pr_err("failed to configure tx dma channel\n"); + + data->rx_status = DMA_RX_RUNNING; + data->rx_pos = 0; + mtk8250_rx_dma(up); +} +#endif + +static int mtk8250_startup(struct uart_port *port) +{ +#ifdef CONFIG_SERIAL_8250_DMA + struct uart_8250_port *up = up_to_u8250p(port); + struct mtk8250_data *data = port->private_data; + + /* disable DMA for console */ + if (uart_console(port)) + up->dma = NULL; + + if (up->dma) { + data->rx_status = DMA_RX_START; + uart_circ_clear(&port->state->xmit); + } +#endif + memset(&port->icount, 0, sizeof(port->icount)); + + return serial8250_do_startup(port); +} + +static void mtk8250_shutdown(struct uart_port *port) +{ +#ifdef CONFIG_SERIAL_8250_DMA + struct uart_8250_port *up = up_to_u8250p(port); + struct mtk8250_data *data = port->private_data; + + if (up->dma) + data->rx_status = DMA_RX_SHUTDOWN; +#endif + + return serial8250_do_shutdown(port); +} + static void mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) @@ -36,6 +200,17 @@ mtk8250_set_termios(struct uart_port *port, struct ktermios *termios, unsigned long flags; unsigned int baud, quot; +#ifdef CONFIG_SERIAL_8250_DMA + if (up->dma) { + if (uart_console(port)) { + devm_kfree(up->port.dev, up->dma); + up->dma = NULL; + } else { + mtk8250_dma_enable(up); + } + } +#endif + serial8250_do_set_termios(port, termios, old); /* @@ -143,9 +318,20 @@ mtk8250_do_pm(struct uart_port *port, unsigned int state, unsigned int old) pm_runtime_put_sync_suspend(port->dev); } +#ifdef CONFIG_SERIAL_8250_DMA +static bool mtk8250_dma_filter(struct dma_chan *chan, void *param) +{ + return false; +} +#endif + static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, struct mtk8250_data *data) { +#ifdef CONFIG_SERIAL_8250_DMA + int dmacnt; +#endif + data->uart_clk = devm_clk_get(&pdev->dev, "baud"); if (IS_ERR(data->uart_clk)) { /* @@ -162,7 +348,26 @@ static int mtk8250_probe_of(struct platform_device *pdev, struct uart_port *p, } data->bus_clk = devm_clk_get(&pdev->dev, "bus"); - return PTR_ERR_OR_ZERO(data->bus_clk); + if (IS_ERR(data->bus_clk)) + return PTR_ERR(data->bus_clk); + + data->dma = NULL; +#ifdef CONFIG_SERIAL_8250_DMA + dmacnt = of_property_count_strings(pdev->dev.of_node, "dma-names"); + if (dmacnt == 2) { + data->dma = devm_kzalloc(&pdev->dev, sizeof(*data->dma), + GFP_KERNEL); + if (!data->dma) + return -ENOMEM; + + data->dma->fn = mtk8250_dma_filter; + data->dma->rx_size = MTK_UART_RX_SIZE; + data->dma->rxconf.src_maxburst = MTK_UART_RX_TRIGGER; + data->dma->txconf.dst_maxburst = MTK_UART_TX_TRIGGER; + } +#endif + + return 0; } static int mtk8250_probe(struct platform_device *pdev) @@ -204,8 +409,14 @@ static int mtk8250_probe(struct platform_device *pdev) uart.port.iotype = UPIO_MEM32; uart.port.regshift = 2; uart.port.private_data = data; + uart.port.shutdown = mtk8250_shutdown; + uart.port.startup = mtk8250_startup; uart.port.set_termios = mtk8250_set_termios; uart.port.uartclk = clk_get_rate(data->uart_clk); +#ifdef CONFIG_SERIAL_8250_DMA + if (data->dma) + uart.dma = data->dma; +#endif /* Disable Rate Fix function */ writel(0x0, uart.port.membase + diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 877fd7f8a8ed..0277479c87e9 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -130,6 +130,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev, port->flags |= UPF_IOREMAP; } + /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */ + if (of_device_is_compatible(np, "mrvl,mmp-uart")) + port->regshift = 2; + /* Check for registers offset within the devices address range */ if (of_property_read_u32(np, "reg-shift", &prop) == 0) port->regshift = prop; @@ -240,6 +244,11 @@ static int of_platform_serial_probe(struct platform_device *ofdev) if (of_property_read_bool(ofdev->dev.of_node, "auto-flow-control")) port8250.capabilities |= UART_CAP_AFE; + if (of_property_read_u32(ofdev->dev.of_node, + "overrun-throttle-ms", + &port8250.overrun_backoff_time_ms) != 0) + port8250.overrun_backoff_time_ms = 0; + ret = serial8250_register_8250_port(&port8250); if (ret < 0) goto err_dispose; @@ -322,6 +331,7 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "nvidia,tegra20-uart", .data = (void *)PORT_TEGRA, }, { .compatible = "nxp,lpc3220-uart", .data = (void *)PORT_LPC3220, }, { .compatible = "ralink,rt2880-uart", .data = (void *)PORT_RT2880, }, + { .compatible = "intel,xscale-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "altr,16550-FIFO32", .data = (void *)PORT_ALTR_16550_F32, }, { .compatible = "altr,16550-FIFO64", diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index a019286f8bb6..0a8316632d75 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -8,6 +8,11 @@ * */ +#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include <linux/clk.h> #include <linux/device.h> #include <linux/io.h> #include <linux/module.h> @@ -1085,7 +1090,7 @@ static int omap_8250_dma_handle_irq(struct uart_port *port) } } - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq(port, flags); serial8250_rpm_put(up); return 1; } @@ -1130,10 +1135,12 @@ static int omap8250_probe(struct platform_device *pdev) { struct resource *regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct resource *irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + struct device_node *np = pdev->dev.of_node; struct omap8250_priv *priv; struct uart_8250_port up; int ret; void __iomem *membase; + const struct of_device_id *id; if (!regs || !irq) { dev_err(&pdev->dev, "missing registers or irq\n"); @@ -1190,27 +1197,31 @@ static int omap8250_probe(struct platform_device *pdev) up.port.unthrottle = omap_8250_unthrottle; up.port.rs485_config = omap_8250_rs485_config; - if (pdev->dev.of_node) { - const struct of_device_id *id; - - ret = of_alias_get_id(pdev->dev.of_node, "serial"); - - of_property_read_u32(pdev->dev.of_node, "clock-frequency", - &up.port.uartclk); - priv->wakeirq = irq_of_parse_and_map(pdev->dev.of_node, 1); - - id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); - if (id && id->data) - priv->habit |= *(u8 *)id->data; - } else { - ret = pdev->id; - } + ret = of_alias_get_id(np, "serial"); if (ret < 0) { - dev_err(&pdev->dev, "failed to get alias/pdev id\n"); + dev_err(&pdev->dev, "failed to get alias\n"); return ret; } up.port.line = ret; + if (of_property_read_u32(np, "clock-frequency", &up.port.uartclk)) { + struct clk *clk; + + clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(clk)) { + if (PTR_ERR(clk) == -EPROBE_DEFER) + return -EPROBE_DEFER; + } else { + up.port.uartclk = clk_get_rate(clk); + } + } + + priv->wakeirq = irq_of_parse_and_map(np, 1); + + id = of_match_device(of_match_ptr(omap8250_dt_ids), &pdev->dev); + if (id && id->data) + priv->habit |= *(u8 *)id->data; + if (!up.port.uartclk) { up.port.uartclk = DEFAULT_CLK_SPEED; dev_warn(&pdev->dev, @@ -1238,25 +1249,23 @@ static int omap8250_probe(struct platform_device *pdev) omap_serial_fill_features_erratas(&up, priv); up.port.handle_irq = omap8250_no_handle_irq; #ifdef CONFIG_SERIAL_8250_DMA - if (pdev->dev.of_node) { - /* - * Oh DMA support. If there are no DMA properties in the DT then - * we will fall back to a generic DMA channel which does not - * really work here. To ensure that we do not get a generic DMA - * channel assigned, we have the the_no_dma_filter_fn() here. - * To avoid "failed to request DMA" messages we check for DMA - * properties in DT. - */ - ret = of_property_count_strings(pdev->dev.of_node, "dma-names"); - if (ret == 2) { - up.dma = &priv->omap8250_dma; - priv->omap8250_dma.fn = the_no_dma_filter_fn; - priv->omap8250_dma.tx_dma = omap_8250_tx_dma; - priv->omap8250_dma.rx_dma = omap_8250_rx_dma; - priv->omap8250_dma.rx_size = RX_TRIGGER; - priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; - priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; - } + /* + * Oh DMA support. If there are no DMA properties in the DT then + * we will fall back to a generic DMA channel which does not + * really work here. To ensure that we do not get a generic DMA + * channel assigned, we have the the_no_dma_filter_fn() here. + * To avoid "failed to request DMA" messages we check for DMA + * properties in DT. + */ + ret = of_property_count_strings(np, "dma-names"); + if (ret == 2) { + up.dma = &priv->omap8250_dma; + priv->omap8250_dma.fn = the_no_dma_filter_fn; + priv->omap8250_dma.tx_dma = omap_8250_tx_dma; + priv->omap8250_dma.rx_dma = omap_8250_rx_dma; + priv->omap8250_dma.rx_size = RX_TRIGGER; + priv->omap8250_dma.rxconf.src_maxburst = RX_TRIGGER; + priv->omap8250_dma.txconf.dst_maxburst = TX_TRIGGER; } #endif ret = serial8250_register_8250_port(&up); diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index f80a300b5d68..df41397de478 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -2027,6 +2027,111 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = { .setup = pci_default_setup, .exit = pci_plx9050_exit, }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4S, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_COM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, + { + .vendor = PCI_VENDOR_ID_ACCESIO, + .device = PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .setup = pci_pericom_setup, + }, /* * SBS Technologies, Inc., PMC-OCTALPRO 232 */ @@ -3375,6 +3480,9 @@ static const struct pci_device_id blacklist[] = { /* Exar devices */ { PCI_VDEVICE(EXAR, PCI_ANY_ID), }, { PCI_VDEVICE(COMMTECH, PCI_ANY_ID), }, + + /* End of the black list */ + { } }; static int serial_pci_is_class_communication(struct pci_dev *dev) @@ -3392,25 +3500,6 @@ static int serial_pci_is_class_communication(struct pci_dev *dev) 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. - */ - for (bldev = blacklist; - bldev < blacklist + ARRAY_SIZE(blacklist); - bldev++) { - if (dev->vendor == bldev->vendor && - dev->device == bldev->device) - 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 @@ -3420,6 +3509,11 @@ static int serial_pci_guess_board(struct pci_dev *dev, struct pciserial_board *board) { int num_iomem, num_port, first_port = -1, i; + int rc; + + rc = serial_pci_is_class_communication(dev); + if (rc) + return rc; /* * Should we try to make guesses for multiport serial devices later? @@ -3629,6 +3723,7 @@ pciserial_init_one(struct pci_dev *dev, const struct pci_device_id *ent) struct pci_serial_quirk *quirk; struct serial_private *priv; const struct pciserial_board *board; + const struct pci_device_id *exclude; struct pciserial_board tmp; int rc; @@ -3647,13 +3742,9 @@ 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; + exclude = pci_match_id(blacklist, dev); + if (exclude) + return -ENODEV; rc = pcim_enable_device(dev); pci_save_state(dev); @@ -4574,10 +4665,10 @@ static const struct pci_device_id serial_pci_tbl[] = { */ { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4586,10 +4677,10 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_2DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4DB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4598,10 +4689,10 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_2SMDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_COM_2SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SMDB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4610,13 +4701,13 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7951 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM485_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM422_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4625,16 +4716,16 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4S, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_MPCIE_ICM232_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM232_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7954 }, @@ -4643,13 +4734,13 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_2SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7954 }, + pbn_pericom_PI7C9X7952 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM485_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM422_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, @@ -4658,19 +4749,19 @@ static const struct pci_device_id serial_pci_tbl[] = { pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM232_8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_4SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_COM_8SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, pbn_pericom_PI7C9X7958 }, { PCI_VENDOR_ID_ACCESIO, PCI_DEVICE_ID_ACCESIO_PCIE_ICM_4SM, PCI_ANY_ID, PCI_ANY_ID, 0, 0, - pbn_pericom_PI7C9X7958 }, + pbn_pericom_PI7C9X7954 }, /* * Topic TP560 Data/Fax/Voice 56k modem (reported by Evan Clarke) */ diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 3f779d25ec0c..d2f3310abe54 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1736,7 +1736,7 @@ void serial8250_read_char(struct uart_8250_port *up, unsigned char lsr) else if (lsr & UART_LSR_FE) flag = TTY_FRAME; } - if (uart_handle_sysrq_char(port, ch)) + if (uart_prepare_sysrq_char(port, ch)) return; uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); @@ -1878,7 +1878,7 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) if ((!up->dma || up->dma->tx_err) && (status & UART_LSR_THRE)) serial8250_tx_chars(up); - spin_unlock_irqrestore(&port->lock, flags); + uart_unlock_and_check_sysrq(port, flags); return 1; } EXPORT_SYMBOL_GPL(serial8250_handle_irq); @@ -3239,9 +3239,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s, serial8250_rpm_get(up); - if (port->sysrq) - locked = 0; - else if (oops_in_progress) + if (oops_in_progress) locked = spin_trylock_irqsave(&port->lock, flags); else spin_lock_irqsave(&port->lock, flags); diff --git a/drivers/tty/serial/8250/8250_pxa.c b/drivers/tty/serial/8250/8250_pxa.c index b9bcbe20a2be..c47188860e32 100644 --- a/drivers/tty/serial/8250/8250_pxa.c +++ b/drivers/tty/serial/8250/8250_pxa.c @@ -113,6 +113,10 @@ static int serial_pxa_probe(struct platform_device *pdev) if (ret) return ret; + ret = of_alias_get_id(pdev->dev.of_node, "serial"); + if (ret >= 0) + uart.port.line = ret; + uart.port.type = PORT_XSCALE; uart.port.iotype = UPIO_MEM32; uart.port.mapbase = mmres->start; diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 32886c304641..72966bc0ac76 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -85,6 +85,18 @@ config SERIAL_EARLYCON_ARM_SEMIHOST with "earlycon=smh" on the kernel command line. The console is enabled when early_param is processed. +config SERIAL_EARLYCON_RISCV_SBI + bool "Early console using RISC-V SBI" + depends on RISCV + select SERIAL_CORE + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Support for early debug console using RISC-V SBI. This enables + the console before standard serial driver is probed. This is enabled + with "earlycon=sbi" on the kernel command line. The console is + enabled when early_param is processed. + config SERIAL_SB1250_DUART tristate "BCM1xxx on-chip DUART serial support" depends on SIBYTE_SB1xxx_SOC=y @@ -323,6 +335,28 @@ config SERIAL_TEGRA are enabled). This driver uses the APB DMA to achieve higher baudrate and better performance. +config SERIAL_TEGRA_TCU + tristate "NVIDIA Tegra Combined UART" + depends on ARCH_TEGRA && TEGRA_HSP_MBOX + select SERIAL_CORE + help + Support for the mailbox-based TCU (Tegra Combined UART) serial port. + TCU is a virtual serial port that allows multiplexing multiple data + streams into a single hardware serial port. + +config SERIAL_TEGRA_TCU_CONSOLE + bool "Support for console on a Tegra TCU serial port" + depends on SERIAL_TEGRA_TCU=y + select SERIAL_CORE_CONSOLE + default y + ---help--- + If you say Y here, it will be possible to use a the Tegra TCU as the + system console (the system console is the device which receives all + kernel messages and warnings and which allows logins in single user + mode). + + If unsure, say Y. + config SERIAL_MAX3100 tristate "MAX3100 support" depends on SPI @@ -1529,6 +1563,25 @@ config SERIAL_OWL_CONSOLE Say 'Y' here if you wish to use Actions Semiconductor S500/S900 UART as the system console. +config SERIAL_RDA + bool "RDA Micro serial port support" + depends on ARCH_RDA || COMPILE_TEST + select SERIAL_CORE + help + This driver is for RDA8810PL SoC's UART. + Say 'Y' here if you wish to use the on-board serial port. + Otherwise, say 'N'. + +config SERIAL_RDA_CONSOLE + bool "Console on RDA Micro serial port" + depends on SERIAL_RDA=y + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + default y + help + Say 'Y' here if you wish to use the RDA8810PL UART as the system + console. Only earlycon is implemented currently. + endmenu config SERIAL_MCTRL_GPIO diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index daac675612df..40b702aaa85e 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_SERIAL_CORE) += serial_core.o obj-$(CONFIG_SERIAL_EARLYCON) += earlycon.o obj-$(CONFIG_SERIAL_EARLYCON_ARM_SEMIHOST) += earlycon-arm-semihost.o +obj-$(CONFIG_SERIAL_EARLYCON_RISCV_SBI) += earlycon-riscv-sbi.o # These Sparc drivers have to appear before others such as 8250 # which share ttySx minor node space. Otherwise console device @@ -76,6 +77,7 @@ obj-$(CONFIG_SERIAL_LANTIQ) += lantiq.o obj-$(CONFIG_SERIAL_XILINX_PS_UART) += xilinx_uartps.o obj-$(CONFIG_SERIAL_SIRFSOC) += sirfsoc_uart.o obj-$(CONFIG_SERIAL_TEGRA) += serial-tegra.o +obj-$(CONFIG_SERIAL_TEGRA_TCU) += tegra-tcu.o obj-$(CONFIG_SERIAL_AR933X) += ar933x_uart.o obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o obj-$(CONFIG_SERIAL_ARC) += arc_uart.o @@ -89,6 +91,7 @@ obj-$(CONFIG_SERIAL_MVEBU_UART) += mvebu-uart.o obj-$(CONFIG_SERIAL_PIC32) += pic32_uart.o obj-$(CONFIG_SERIAL_MPS2_UART) += mps2-uart.o obj-$(CONFIG_SERIAL_OWL) += owl-uart.o +obj-$(CONFIG_SERIAL_RDA) += rda-uart.o # GPIOLIB helpers for modem control lines obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c index ebd33c0232e6..89ade213a1a9 100644 --- a/drivers/tty/serial/amba-pl011.c +++ b/drivers/tty/serial/amba-pl011.c @@ -2780,6 +2780,7 @@ static struct platform_driver arm_sbsa_uart_platform_driver = { .name = "sbsa-uart", .of_match_table = of_match_ptr(sbsa_uart_of_match), .acpi_match_table = ACPI_PTR(sbsa_uart_acpi_match), + .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), }, }; @@ -2808,6 +2809,7 @@ static struct amba_driver pl011_driver = { .drv = { .name = "uart-pl011", .pm = &pl011_dev_pm_ops, + .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_AMBA_PL011), }, .id_table = pl011_ids, .probe = pl011_probe, diff --git a/drivers/tty/serial/ar933x_uart.c b/drivers/tty/serial/ar933x_uart.c index db5df3d54818..3bdd56a1021b 100644 --- a/drivers/tty/serial/ar933x_uart.c +++ b/drivers/tty/serial/ar933x_uart.c @@ -49,11 +49,6 @@ struct ar933x_uart_port { struct clk *clk; }; -static inline bool ar933x_uart_console_enabled(void) -{ - return IS_ENABLED(CONFIG_SERIAL_AR933X_CONSOLE); -} - static inline unsigned int ar933x_uart_read(struct ar933x_uart_port *up, int offset) { @@ -508,6 +503,7 @@ static const struct uart_ops ar933x_uart_ops = { .verify_port = ar933x_uart_verify_port, }; +#ifdef CONFIG_SERIAL_AR933X_CONSOLE static struct ar933x_uart_port * ar933x_console_ports[CONFIG_SERIAL_AR933X_NR_UARTS]; @@ -604,14 +600,7 @@ static struct console ar933x_uart_console = { .index = -1, .data = &ar933x_uart_driver, }; - -static void ar933x_uart_add_console_port(struct ar933x_uart_port *up) -{ - if (!ar933x_uart_console_enabled()) - return; - - ar933x_console_ports[up->port.line] = up; -} +#endif /* CONFIG_SERIAL_AR933X_CONSOLE */ static struct uart_driver ar933x_uart_driver = { .owner = THIS_MODULE, @@ -700,7 +689,9 @@ static int ar933x_uart_probe(struct platform_device *pdev) baud = ar933x_uart_get_baud(port->uartclk, 0, AR933X_UART_MAX_STEP); up->max_baud = min_t(unsigned int, baud, AR933X_UART_MAX_BAUD); - ar933x_uart_add_console_port(up); +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + ar933x_console_ports[up->port.line] = up; +#endif ret = uart_add_one_port(&ar933x_uart_driver, &up->port); if (ret) @@ -749,8 +740,9 @@ static int __init ar933x_uart_init(void) { int ret; - if (ar933x_uart_console_enabled()) - ar933x_uart_driver.cons = &ar933x_uart_console; +#ifdef CONFIG_SERIAL_AR933X_CONSOLE + ar933x_uart_driver.cons = &ar933x_uart_console; +#endif ret = uart_register_driver(&ar933x_uart_driver); if (ret) diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c index 05147fe24343..0b4f36905321 100644 --- a/drivers/tty/serial/atmel_serial.c +++ b/drivers/tty/serial/atmel_serial.c @@ -166,6 +166,8 @@ struct atmel_uart_port { unsigned int pending_status; spinlock_t lock_suspended; + bool hd_start_rx; /* can start RX during half-duplex operation */ + /* ISO7816 */ unsigned int fidi_min; unsigned int fidi_max; @@ -231,6 +233,13 @@ static inline void atmel_uart_write_char(struct uart_port *port, u8 value) __raw_writeb(value, port->membase + ATMEL_US_THR); } +static inline int atmel_uart_is_half_duplex(struct uart_port *port) +{ + return ((port->rs485.flags & SER_RS485_ENABLED) && + !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || + (port->iso7816.flags & SER_ISO7816_ENABLED); +} + #ifdef CONFIG_SERIAL_ATMEL_PDC static bool atmel_use_pdc_rx(struct uart_port *port) { @@ -608,10 +617,9 @@ static void atmel_stop_tx(struct uart_port *port) /* Disable interrupts */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) + if (atmel_uart_is_half_duplex(port)) atmel_start_rx(port); + } /* @@ -628,9 +636,7 @@ static void atmel_start_tx(struct uart_port *port) return; if (atmel_use_pdc_tx(port) || atmel_use_dma_tx(port)) - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) + if (atmel_uart_is_half_duplex(port)) atmel_stop_rx(port); if (atmel_use_pdc_tx(port)) @@ -928,11 +934,14 @@ static void atmel_complete_tx_dma(void *arg) */ if (!uart_circ_empty(xmit)) atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); - else if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) { - /* DMA done, stop TX, start RX for RS485 */ - atmel_start_rx(port); + else if (atmel_uart_is_half_duplex(port)) { + /* + * DMA done, re-enable TXEMPTY and signal that we can stop + * TX and start RX for RS485 + */ + atmel_port->hd_start_rx = true; + atmel_uart_writel(port, ATMEL_US_IER, + atmel_port->tx_done_mask); } spin_unlock_irqrestore(&port->lock, flags); @@ -1288,6 +1297,10 @@ static int atmel_prepare_rx_dma(struct uart_port *port) sg_dma_len(&atmel_port->sg_rx)/2, DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT); + if (!desc) { + dev_err(port->dev, "Preparing DMA cyclic failed\n"); + goto chan_err; + } desc->callback = atmel_complete_rx_dma; desc->callback_param = port; atmel_port->desc_rx = desc; @@ -1376,9 +1389,20 @@ atmel_handle_transmit(struct uart_port *port, unsigned int pending) struct atmel_uart_port *atmel_port = to_atmel_uart_port(port); if (pending & atmel_port->tx_done_mask) { - /* Either PDC or interrupt transmission */ atmel_uart_writel(port, ATMEL_US_IDR, atmel_port->tx_done_mask); + + /* Start RX if flag was set and FIFO is empty */ + if (atmel_port->hd_start_rx) { + if (!(atmel_uart_readl(port, ATMEL_US_CSR) + & ATMEL_US_TXEMPTY)) + dev_warn(port->dev, "Should start RX, but TX fifo is not empty\n"); + + atmel_port->hd_start_rx = false; + atmel_start_rx(port); + return; + } + atmel_tasklet_schedule(atmel_port, &atmel_port->tasklet_tx); } } @@ -1508,9 +1532,7 @@ static void atmel_tx_pdc(struct uart_port *port) atmel_uart_writel(port, ATMEL_US_IER, atmel_port->tx_done_mask); } else { - if (((port->rs485.flags & SER_RS485_ENABLED) && - !(port->rs485.flags & SER_RS485_RX_DURING_TX)) || - port->iso7816.flags & SER_ISO7816_ENABLED) { + if (atmel_uart_is_half_duplex(port)) { /* DMA done, stop TX, start RX for RS485 */ atmel_start_rx(port); } diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 98f193a83392..061590795680 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c @@ -442,14 +442,10 @@ static struct console clps711x_console = { static int uart_clps711x_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; - int ret, index = np ? of_alias_get_id(np, "serial") : pdev->id; struct clps711x_port *s; struct resource *res; struct clk *uart_clk; - int irq; - - if (index < 0 || index >= UART_CLPS711X_NR) - return -EINVAL; + int irq, ret; s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL); if (!s) @@ -473,20 +469,11 @@ static int uart_clps711x_probe(struct platform_device *pdev) if (s->rx_irq < 0) return s->rx_irq; - if (!np) { - char syscon_name[9]; - - sprintf(syscon_name, "syscon.%i", index + 1); - s->syscon = syscon_regmap_lookup_by_pdevname(syscon_name); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } else { - s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); - if (IS_ERR(s->syscon)) - return PTR_ERR(s->syscon); - } + s->syscon = syscon_regmap_lookup_by_phandle(np, "syscon"); + if (IS_ERR(s->syscon)) + return PTR_ERR(s->syscon); - s->port.line = index; + s->port.line = of_alias_get_id(np, "serial"); s->port.dev = &pdev->dev; s->port.iotype = UPIO_MEM32; s->port.mapbase = res->start; diff --git a/drivers/tty/serial/earlycon-riscv-sbi.c b/drivers/tty/serial/earlycon-riscv-sbi.c new file mode 100644 index 000000000000..ce81523c3113 --- /dev/null +++ b/drivers/tty/serial/earlycon-riscv-sbi.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * RISC-V SBI based earlycon + * + * Copyright (C) 2018 Anup Patel <anup@brainfault.org> + */ +#include <linux/kernel.h> +#include <linux/console.h> +#include <linux/init.h> +#include <linux/serial_core.h> +#include <asm/sbi.h> + +static void sbi_putc(struct uart_port *port, int c) +{ + sbi_console_putchar(c); +} + +static void sbi_console_write(struct console *con, + const char *s, unsigned n) +{ + struct earlycon_device *dev = con->data; + uart_console_write(&dev->port, s, n, sbi_putc); +} + +static int __init early_sbi_setup(struct earlycon_device *device, + const char *opt) +{ + device->con->write = sbi_console_write; + return 0; +} +EARLYCON_DECLARE(sbi, early_sbi_setup); diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 00c220e4f43c..ea1c85e3b432 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -426,6 +426,17 @@ static void lpuart_dma_tx_complete(void *arg) spin_unlock_irqrestore(&sport->port.lock, flags); } +static dma_addr_t lpuart_dma_datareg_addr(struct lpuart_port *sport) +{ + switch (sport->port.iotype) { + case UPIO_MEM32: + return sport->port.mapbase + UARTDATA; + case UPIO_MEM32BE: + return sport->port.mapbase + UARTDATA + sizeof(u32) - 1; + } + return sport->port.mapbase + UARTDR; +} + static int lpuart_dma_tx_request(struct uart_port *port) { struct lpuart_port *sport = container_of(port, @@ -433,7 +444,7 @@ static int lpuart_dma_tx_request(struct uart_port *port) struct dma_slave_config dma_tx_sconfig = {}; int ret; - dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR; + dma_tx_sconfig.dst_addr = lpuart_dma_datareg_addr(sport); dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_tx_sconfig.dst_maxburst = 1; dma_tx_sconfig.direction = DMA_MEM_TO_DEV; @@ -636,13 +647,19 @@ static void lpuart_start_tx(struct uart_port *port) static void lpuart32_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + struct circ_buf *xmit = &sport->port.state->xmit; unsigned long temp; - temp = lpuart32_read(port, UARTCTRL); - lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL); + if (sport->lpuart_dma_tx_use) { + if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + lpuart_dma_tx(sport); + } else { + temp = lpuart32_read(port, UARTCTRL); + lpuart32_write(port, temp | UARTCTRL_TIE, UARTCTRL); - if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE) - lpuart32_transmit_buffer(sport); + if (lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE) + lpuart32_transmit_buffer(sport); + } } /* return TIOCSER_TEMT when transmitter is not busy */ @@ -664,8 +681,18 @@ static unsigned int lpuart_tx_empty(struct uart_port *port) static unsigned int lpuart32_tx_empty(struct uart_port *port) { - return (lpuart32_read(port, UARTSTAT) & UARTSTAT_TC) ? - TIOCSER_TEMT : 0; + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + unsigned long stat = lpuart32_read(port, UARTSTAT); + unsigned long sfifo = lpuart32_read(port, UARTFIFO); + + if (sport->dma_tx_in_progress) + return 0; + + if (stat & UARTSTAT_TC && sfifo & UARTFIFO_TXEMPT) + return TIOCSER_TEMT; + + return 0; } static bool lpuart_is_32(struct lpuart_port *sport) @@ -862,11 +889,10 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) rxcount = lpuart32_read(&sport->port, UARTWATER); rxcount = rxcount >> UARTWATER_RXCNT_OFF; - if (sts & UARTSTAT_RDRF || rxcount > 0) + if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) lpuart32_rxint(irq, dev_id); - if ((sts & UARTSTAT_TDRE) && - !(lpuart32_read(&sport->port, UARTBAUD) & UARTBAUD_TDMAE)) + if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) lpuart_txint(irq, dev_id); lpuart32_write(&sport->port, sts, UARTSTAT); @@ -881,18 +907,31 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) struct circ_buf *ring = &sport->rx_ring; unsigned long flags; int count = 0; - unsigned char sr; - sr = readb(sport->port.membase + UARTSR1); + if (lpuart_is_32(sport)) { + unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); - if (sr & (UARTSR1_PE | UARTSR1_FE)) { - /* Read DR to clear the error flags */ - readb(sport->port.membase + UARTDR); + if (sr & (UARTSTAT_PE | UARTSTAT_FE)) { + /* Read DR to clear the error flags */ + lpuart32_read(&sport->port, UARTDATA); - if (sr & UARTSR1_PE) - sport->port.icount.parity++; - else if (sr & UARTSR1_FE) - sport->port.icount.frame++; + if (sr & UARTSTAT_PE) + sport->port.icount.parity++; + else if (sr & UARTSTAT_FE) + sport->port.icount.frame++; + } + } else { + unsigned char sr = readb(sport->port.membase + UARTSR1); + + if (sr & (UARTSR1_PE | UARTSR1_FE)) { + /* Read DR to clear the error flags */ + readb(sport->port.membase + UARTDR); + + if (sr & UARTSR1_PE) + sport->port.icount.parity++; + else if (sr & UARTSR1_FE) + sport->port.icount.frame++; + } } async_tx_ack(sport->dma_rx_desc); @@ -1015,7 +1054,7 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) return -EINVAL; } - dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR; + dma_rx_sconfig.src_addr = lpuart_dma_datareg_addr(sport); dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; dma_rx_sconfig.src_maxburst = 1; dma_rx_sconfig.direction = DMA_DEV_TO_MEM; @@ -1043,8 +1082,14 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); dma_async_issue_pending(sport->dma_rx_chan); - writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, - sport->port.membase + UARTCR5); + if (lpuart_is_32(sport)) { + unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); + + lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, + sport->port.membase + UARTCR5); + } return 0; } @@ -1334,6 +1379,8 @@ static int lpuart32_startup(struct uart_port *port) sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK) - 1); + sport->port.fifosize = sport->txfifo_size; + sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) & UARTFIFO_FIFOSIZE_MASK) - 1); @@ -1342,8 +1389,41 @@ static int lpuart32_startup(struct uart_port *port) lpuart32_setup_watermark(sport); temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | UARTCTRL_TE); - temp |= UARTCTRL_ILIE; + temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; + lpuart32_write(&sport->port, temp, UARTCTRL); + + if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { + /* set Rx DMA timeout */ + sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); + if (!sport->dma_rx_timeout) + sport->dma_rx_timeout = 1; + + sport->lpuart_dma_rx_use = true; + rx_dma_timer_init(sport); + } else { + sport->lpuart_dma_rx_use = false; + } + + if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp | UARTBAUD_TDMAE, UARTBAUD); + } else { + sport->lpuart_dma_tx_use = false; + } + + if (sport->lpuart_dma_rx_use) { + /* RXWATER must be 0 */ + temp = lpuart32_read(&sport->port, UARTWATER); + temp &= ~(UARTWATER_WATER_MASK << UARTWATER_RXWATER_OFF); + lpuart32_write(&sport->port, temp, UARTWATER); + } + temp = lpuart32_read(&sport->port, UARTCTRL); + if (!sport->lpuart_dma_rx_use) + temp |= UARTCTRL_RIE; + if (!sport->lpuart_dma_tx_use) + temp |= UARTCTRL_TIE; lpuart32_write(&sport->port, temp, UARTCTRL); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1384,6 +1464,8 @@ static void lpuart_shutdown(struct uart_port *port) static void lpuart32_shutdown(struct uart_port *port) { + struct lpuart_port *sport = + container_of(port, struct lpuart_port, port); unsigned long temp; unsigned long flags; @@ -1396,6 +1478,21 @@ static void lpuart32_shutdown(struct uart_port *port) lpuart32_write(port, temp, UARTCTRL); spin_unlock_irqrestore(&port->lock, flags); + + if (sport->lpuart_dma_rx_use) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } + + if (sport->lpuart_dma_tx_use) { + if (wait_event_interruptible(sport->dma_wait, + !sport->dma_tx_in_progress)) { + sport->dma_tx_in_progress = false; + dmaengine_terminate_all(sport->dma_tx_chan); + } + + lpuart32_stop_tx(port); + } } static void @@ -1479,6 +1576,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, else cr1 &= ~UARTCR1_PT; } + } else { + cr1 &= ~UARTCR1_PE; } /* ask the core to calculate the divisor */ @@ -1619,7 +1718,10 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) tmp &= ~UARTBAUD_SBR_MASK; tmp |= sbr & UARTBAUD_SBR_MASK; - tmp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE); + if (!sport->lpuart_dma_rx_use) + tmp &= ~UARTBAUD_RDMAE; + if (!sport->lpuart_dma_tx_use) + tmp &= ~UARTBAUD_TDMAE; lpuart32_write(&sport->port, tmp, UARTBAUD); } @@ -1682,7 +1784,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, ctrl &= ~UARTCTRL_PE; ctrl |= UARTCTRL_M; } else { - ctrl |= UARTCR1_PE; + ctrl |= UARTCTRL_PE; if ((termios->c_cflag & CSIZE) == CS8) ctrl |= UARTCTRL_M; if (termios->c_cflag & PARODD) @@ -1690,10 +1792,24 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, else ctrl &= ~UARTCTRL_PT; } + } else { + ctrl &= ~UARTCTRL_PE; } /* ask the core to calculate the divisor */ - baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 16); + baud = uart_get_baud_rate(port, termios, old, 50, port->uartclk / 4); + + /* + * Need to update the Ring buffer length according to the selected + * baud rate and restart Rx DMA path. + * + * Since timer function acqures sport->port.lock, need to stop before + * acquring same lock because otherwise del_timer_sync() can deadlock. + */ + if (old && sport->lpuart_dma_rx_use) { + del_timer_sync(&sport->lpuart_timer); + lpuart_dma_rx_free(&sport->port); + } spin_lock_irqsave(&sport->port.lock, flags); @@ -1733,6 +1849,13 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, lpuart32_write(&sport->port, ctrl, UARTCTRL); /* restore control register */ + if (old && sport->lpuart_dma_rx_use) { + if (!lpuart_start_rx_dma(sport)) + rx_dma_timer_init(sport); + else + sport->lpuart_dma_rx_use = false; + } + spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -2302,8 +2425,14 @@ static int lpuart_suspend(struct device *dev) } /* Disable Rx DMA to use UART port as wakeup source */ - writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_RDMAS, - sport->port.membase + UARTCR5); + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, temp & ~UARTBAUD_RDMAE, + UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) & + ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); + } } if (sport->lpuart_dma_tx_use) { @@ -2329,8 +2458,7 @@ static int lpuart_resume(struct device *dev) if (lpuart_is_32(sport)) { lpuart32_setup_watermark(sport); temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= (UARTCTRL_RIE | UARTCTRL_TIE | UARTCTRL_RE | - UARTCTRL_TE | UARTCTRL_ILIE); + temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; lpuart32_write(&sport->port, temp, UARTCTRL); } else { lpuart_setup_watermark(sport); @@ -2349,14 +2477,36 @@ static int lpuart_resume(struct device *dev) } if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + if (lpuart_is_32(sport)) { + temp = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, + temp | UARTBAUD_TDMAE, UARTBAUD); + } else { writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS, sport->port.membase + UARTCR5); + } } else { sport->lpuart_dma_tx_use = false; } + if (lpuart_is_32(sport)) { + if (sport->lpuart_dma_rx_use) { + /* RXWATER must be 0 */ + temp = lpuart32_read(&sport->port, UARTWATER); + temp &= ~(UARTWATER_WATER_MASK << + UARTWATER_RXWATER_OFF); + lpuart32_write(&sport->port, temp, UARTWATER); + } + temp = lpuart32_read(&sport->port, UARTCTRL); + if (!sport->lpuart_dma_rx_use) + temp |= UARTCTRL_RIE; + if (!sport->lpuart_dma_tx_use) + temp |= UARTCTRL_TIE; + lpuart32_write(&sport->port, temp, UARTCTRL); + } + uart_resume_port(&lpuart_reg, &sport->port); return 0; diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index d4e051b578f6..dff75dc94731 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2064,7 +2064,7 @@ imx_uart_console_setup(struct console *co, char *options) retval = clk_prepare(sport->clk_per); if (retval) - clk_disable_unprepare(sport->clk_ipg); + clk_unprepare(sport->clk_ipg); error_console: return retval; diff --git a/drivers/tty/serial/kgdboc.c b/drivers/tty/serial/kgdboc.c index 6fb312e7af71..bfe5e9e034ec 100644 --- a/drivers/tty/serial/kgdboc.c +++ b/drivers/tty/serial/kgdboc.c @@ -148,8 +148,10 @@ static int configure_kgdboc(void) char *cptr = config; struct console *cons; - if (!strlen(config) || isspace(config[0])) + if (!strlen(config) || isspace(config[0])) { + err = 0; goto noconfig; + } kgdboc_io_ops.is_console = 0; kgdb_tty_driver = NULL; diff --git a/drivers/tty/serial/lantiq.c b/drivers/tty/serial/lantiq.c index 044128277248..9de9f0f239a1 100644 --- a/drivers/tty/serial/lantiq.c +++ b/drivers/tty/serial/lantiq.c @@ -8,24 +8,23 @@ * Copyright (C) 2010 Thomas Langer, <thomas.langer@lantiq.com> */ -#include <linux/slab.h> -#include <linux/ioport.h> -#include <linux/init.h> +#include <linux/clk.h> #include <linux/console.h> -#include <linux/sysrq.h> #include <linux/device.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/serial_core.h> -#include <linux/serial.h> -#include <linux/of_platform.h> +#include <linux/gpio.h> +#include <linux/init.h> +#include <linux/io.h> +#include <linux/ioport.h> +#include <linux/lantiq.h> #include <linux/of_address.h> #include <linux/of_irq.h> -#include <linux/io.h> -#include <linux/clk.h> -#include <linux/gpio.h> - -#include <lantiq_soc.h> +#include <linux/of_platform.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/sysrq.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> #define PORT_LTQ_ASC 111 #define MAXPORTS 2 @@ -105,7 +104,7 @@ static DEFINE_SPINLOCK(ltq_asc_lock); struct ltq_uart_port { struct uart_port port; /* clock used to derive divider */ - struct clk *fpiclk; + struct clk *freqclk; /* clock gating of the ASC core */ struct clk *clk; unsigned int tx_irq; @@ -113,6 +112,13 @@ struct ltq_uart_port { unsigned int err_irq; }; +static inline void asc_update_bits(u32 clear, u32 set, void __iomem *reg) +{ + u32 tmp = __raw_readl(reg); + + __raw_writel((tmp & ~clear) | set, reg); +} + static inline struct ltq_uart_port *to_ltq_uart_port(struct uart_port *port) { @@ -138,7 +144,7 @@ lqasc_start_tx(struct uart_port *port) static void lqasc_stop_rx(struct uart_port *port) { - ltq_w32(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); + __raw_writel(ASCWHBSTATE_CLRREN, port->membase + LTQ_ASC_WHBSTATE); } static int @@ -147,11 +153,12 @@ lqasc_rx_chars(struct uart_port *port) struct tty_port *tport = &port->state->port; unsigned int ch = 0, rsr = 0, fifocnt; - fifocnt = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_RXFFLMASK; + fifocnt = __raw_readl(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_RXFFLMASK; while (fifocnt--) { u8 flag = TTY_NORMAL; - ch = ltq_r8(port->membase + LTQ_ASC_RBUF); - rsr = (ltq_r32(port->membase + LTQ_ASC_STATE) + ch = readb(port->membase + LTQ_ASC_RBUF); + rsr = (__raw_readl(port->membase + LTQ_ASC_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX; tty_flip_buffer_push(tport); port->icount.rx++; @@ -163,16 +170,16 @@ lqasc_rx_chars(struct uart_port *port) if (rsr & ASCSTATE_ANY) { if (rsr & ASCSTATE_PE) { port->icount.parity++; - ltq_w32_mask(0, ASCWHBSTATE_CLRPE, + asc_update_bits(0, ASCWHBSTATE_CLRPE, port->membase + LTQ_ASC_WHBSTATE); } else if (rsr & ASCSTATE_FE) { port->icount.frame++; - ltq_w32_mask(0, ASCWHBSTATE_CLRFE, + asc_update_bits(0, ASCWHBSTATE_CLRFE, port->membase + LTQ_ASC_WHBSTATE); } if (rsr & ASCSTATE_ROE) { port->icount.overrun++; - ltq_w32_mask(0, ASCWHBSTATE_CLRROE, + asc_update_bits(0, ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); } @@ -211,10 +218,10 @@ lqasc_tx_chars(struct uart_port *port) return; } - while (((ltq_r32(port->membase + LTQ_ASC_FSTAT) & + while (((__raw_readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF) != 0) { if (port->x_char) { - ltq_w8(port->x_char, port->membase + LTQ_ASC_TBUF); + writeb(port->x_char, port->membase + LTQ_ASC_TBUF); port->icount.tx++; port->x_char = 0; continue; @@ -223,7 +230,7 @@ lqasc_tx_chars(struct uart_port *port) if (uart_circ_empty(xmit)) break; - ltq_w8(port->state->xmit.buf[port->state->xmit.tail], + writeb(port->state->xmit.buf[port->state->xmit.tail], port->membase + LTQ_ASC_TBUF); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; @@ -239,7 +246,7 @@ lqasc_tx_int(int irq, void *_port) unsigned long flags; struct uart_port *port = (struct uart_port *)_port; spin_lock_irqsave(<q_asc_lock, flags); - ltq_w32(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); + __raw_writel(ASC_IRNCR_TIR, port->membase + LTQ_ASC_IRNCR); spin_unlock_irqrestore(<q_asc_lock, flags); lqasc_start_tx(port); return IRQ_HANDLED; @@ -252,7 +259,7 @@ lqasc_err_int(int irq, void *_port) struct uart_port *port = (struct uart_port *)_port; spin_lock_irqsave(<q_asc_lock, flags); /* clear any pending interrupts */ - ltq_w32_mask(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | + asc_update_bits(0, ASCWHBSTATE_CLRPE | ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, port->membase + LTQ_ASC_WHBSTATE); spin_unlock_irqrestore(<q_asc_lock, flags); return IRQ_HANDLED; @@ -264,7 +271,7 @@ lqasc_rx_int(int irq, void *_port) unsigned long flags; struct uart_port *port = (struct uart_port *)_port; spin_lock_irqsave(<q_asc_lock, flags); - ltq_w32(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); + __raw_writel(ASC_IRNCR_RIR, port->membase + LTQ_ASC_IRNCR); lqasc_rx_chars(port); spin_unlock_irqrestore(<q_asc_lock, flags); return IRQ_HANDLED; @@ -274,7 +281,8 @@ static unsigned int lqasc_tx_empty(struct uart_port *port) { int status; - status = ltq_r32(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFFLMASK; + status = __raw_readl(port->membase + LTQ_ASC_FSTAT) & + ASCFSTAT_TXFFLMASK; return status ? 0 : TIOCSER_TEMT; } @@ -301,18 +309,18 @@ lqasc_startup(struct uart_port *port) int retval; if (!IS_ERR(ltq_port->clk)) - clk_enable(ltq_port->clk); - port->uartclk = clk_get_rate(ltq_port->fpiclk); + clk_prepare_enable(ltq_port->clk); + port->uartclk = clk_get_rate(ltq_port->freqclk); - ltq_w32_mask(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), + asc_update_bits(ASCCLC_DISS | ASCCLC_RMCMASK, (1 << ASCCLC_RMCOFFSET), port->membase + LTQ_ASC_CLC); - ltq_w32(0, port->membase + LTQ_ASC_PISEL); - ltq_w32( + __raw_writel(0, port->membase + LTQ_ASC_PISEL); + __raw_writel( ((TXFIFO_FL << ASCTXFCON_TXFITLOFF) & ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, port->membase + LTQ_ASC_TXFCON); - ltq_w32( + __raw_writel( ((RXFIFO_FL << ASCRXFCON_RXFITLOFF) & ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, port->membase + LTQ_ASC_RXFCON); @@ -320,7 +328,7 @@ lqasc_startup(struct uart_port *port) * setting enable bits */ wmb(); - ltq_w32_mask(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | + asc_update_bits(0, ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, port->membase + LTQ_ASC_CON); retval = request_irq(ltq_port->tx_irq, lqasc_tx_int, @@ -344,7 +352,7 @@ lqasc_startup(struct uart_port *port) goto err2; } - ltq_w32(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, + __raw_writel(ASC_IRNREN_RX | ASC_IRNREN_ERR | ASC_IRNREN_TX, port->membase + LTQ_ASC_IRNREN); return 0; @@ -363,13 +371,13 @@ lqasc_shutdown(struct uart_port *port) free_irq(ltq_port->rx_irq, port); free_irq(ltq_port->err_irq, port); - ltq_w32(0, port->membase + LTQ_ASC_CON); - ltq_w32_mask(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, + __raw_writel(0, port->membase + LTQ_ASC_CON); + asc_update_bits(ASCRXFCON_RXFEN, ASCRXFCON_RXFFLU, port->membase + LTQ_ASC_RXFCON); - ltq_w32_mask(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, + asc_update_bits(ASCTXFCON_TXFEN, ASCTXFCON_TXFFLU, port->membase + LTQ_ASC_TXFCON); if (!IS_ERR(ltq_port->clk)) - clk_disable(ltq_port->clk); + clk_disable_unprepare(ltq_port->clk); } static void @@ -438,7 +446,7 @@ lqasc_set_termios(struct uart_port *port, spin_lock_irqsave(<q_asc_lock, flags); /* set up CON */ - ltq_w32_mask(0, con, port->membase + LTQ_ASC_CON); + asc_update_bits(0, con, port->membase + LTQ_ASC_CON); /* Set baud rate - take a divider of 2 into account */ baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); @@ -446,22 +454,22 @@ lqasc_set_termios(struct uart_port *port, divisor = divisor / 2 - 1; /* disable the baudrate generator */ - ltq_w32_mask(ASCCON_R, 0, port->membase + LTQ_ASC_CON); + asc_update_bits(ASCCON_R, 0, port->membase + LTQ_ASC_CON); /* make sure the fractional divider is off */ - ltq_w32_mask(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); + asc_update_bits(ASCCON_FDE, 0, port->membase + LTQ_ASC_CON); /* set up to use divisor of 2 */ - ltq_w32_mask(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); + asc_update_bits(ASCCON_BRS, 0, port->membase + LTQ_ASC_CON); /* now we can write the new baudrate into the register */ - ltq_w32(divisor, port->membase + LTQ_ASC_BG); + __raw_writel(divisor, port->membase + LTQ_ASC_BG); /* turn the baudrate generator back on */ - ltq_w32_mask(0, ASCCON_R, port->membase + LTQ_ASC_CON); + asc_update_bits(0, ASCCON_R, port->membase + LTQ_ASC_CON); /* enable rx */ - ltq_w32(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); + __raw_writel(ASCWHBSTATE_SETREN, port->membase + LTQ_ASC_WHBSTATE); spin_unlock_irqrestore(<q_asc_lock, flags); @@ -572,10 +580,10 @@ lqasc_console_putchar(struct uart_port *port, int ch) return; do { - fifofree = (ltq_r32(port->membase + LTQ_ASC_FSTAT) + fifofree = (__raw_readl(port->membase + LTQ_ASC_FSTAT) & ASCFSTAT_TXFREEMASK) >> ASCFSTAT_TXFREEOFF; } while (fifofree == 0); - ltq_w8(ch, port->membase + LTQ_ASC_TBUF); + writeb(ch, port->membase + LTQ_ASC_TBUF); } static void lqasc_serial_port_write(struct uart_port *port, const char *s, @@ -623,9 +631,9 @@ lqasc_console_setup(struct console *co, char *options) port = <q_port->port; if (!IS_ERR(ltq_port->clk)) - clk_enable(ltq_port->clk); + clk_prepare_enable(ltq_port->clk); - port->uartclk = clk_get_rate(ltq_port->fpiclk); + port->uartclk = clk_get_rate(ltq_port->freqclk); if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -688,7 +696,7 @@ lqasc_probe(struct platform_device *pdev) struct ltq_uart_port *ltq_port; struct uart_port *port; struct resource *mmres, irqres[3]; - int line = 0; + int line; int ret; mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); @@ -699,9 +707,20 @@ lqasc_probe(struct platform_device *pdev) return -ENODEV; } - /* check if this is the console port */ - if (mmres->start != CPHYSADDR(LTQ_EARLY_ASC)) - line = 1; + /* get serial id */ + line = of_alias_get_id(node, "serial"); + if (line < 0) { + if (IS_ENABLED(CONFIG_LANTIQ)) { + if (mmres->start == CPHYSADDR(LTQ_EARLY_ASC)) + line = 0; + else + line = 1; + } else { + dev_err(&pdev->dev, "failed to get alias id, errno %d\n", + line); + return line; + } + } if (lqasc_port[line]) { dev_err(&pdev->dev, "port %d already allocated\n", line); @@ -726,14 +745,22 @@ lqasc_probe(struct platform_device *pdev) port->irq = irqres[0].start; port->mapbase = mmres->start; - ltq_port->fpiclk = clk_get_fpi(); - if (IS_ERR(ltq_port->fpiclk)) { + if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK)) + ltq_port->freqclk = clk_get_fpi(); + else + ltq_port->freqclk = devm_clk_get(&pdev->dev, "freq"); + + + if (IS_ERR(ltq_port->freqclk)) { pr_err("failed to get fpi clk\n"); return -ENOENT; } /* not all asc ports have clock gates, lets ignore the return code */ - ltq_port->clk = clk_get(&pdev->dev, NULL); + if (IS_ENABLED(CONFIG_LANTIQ) && !IS_ENABLED(CONFIG_COMMON_CLK)) + ltq_port->clk = clk_get(&pdev->dev, NULL); + else + ltq_port->clk = devm_clk_get(&pdev->dev, "asc"); ltq_port->tx_irq = irqres[0].start; ltq_port->rx_irq = irqres[1].start; @@ -759,7 +786,7 @@ static struct platform_driver lqasc_driver = { }, }; -int __init +static int __init init_lqasc(void) { int ret; diff --git a/drivers/tty/serial/lpc32xx_hs.c b/drivers/tty/serial/lpc32xx_hs.c index d1d73261575b..f4e27d0ad947 100644 --- a/drivers/tty/serial/lpc32xx_hs.c +++ b/drivers/tty/serial/lpc32xx_hs.c @@ -151,6 +151,8 @@ static void lpc32xx_hsuart_console_write(struct console *co, const char *s, local_irq_restore(flags); } +static void lpc32xx_loopback_set(resource_size_t mapbase, int state); + static int __init lpc32xx_hsuart_console_setup(struct console *co, char *options) { @@ -170,6 +172,8 @@ static int __init lpc32xx_hsuart_console_setup(struct console *co, if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); + lpc32xx_loopback_set(port->mapbase, 0); /* get out of loopback mode */ + return uart_set_options(port, co, baud, parity, bits, flow); } diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 3db48fcd6068..450ba6d7996c 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -248,6 +248,7 @@ struct max310x_devtype { char name[9]; int nr; + u8 mode1; int (*detect)(struct device *); void (*power)(struct uart_port *, int); }; @@ -410,6 +411,7 @@ static void max14830_power(struct uart_port *port, int on) static const struct max310x_devtype max3107_devtype = { .name = "MAX3107", .nr = 1, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT | MAX310X_MODE1_IRQSEL_BIT, .detect = max3107_detect, .power = max310x_power, }; @@ -417,6 +419,7 @@ static const struct max310x_devtype max3107_devtype = { static const struct max310x_devtype max3108_devtype = { .name = "MAX3108", .nr = 1, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3108_detect, .power = max310x_power, }; @@ -424,6 +427,7 @@ static const struct max310x_devtype max3108_devtype = { static const struct max310x_devtype max3109_devtype = { .name = "MAX3109", .nr = 2, + .mode1 = MAX310X_MODE1_AUTOSLEEP_BIT, .detect = max3109_detect, .power = max310x_power, }; @@ -431,6 +435,7 @@ static const struct max310x_devtype max3109_devtype = { static const struct max310x_devtype max14830_devtype = { .name = "MAX14830", .nr = 4, + .mode1 = MAX310X_MODE1_IRQSEL_BIT, .detect = max14830_detect, .power = max14830_power, }; @@ -833,12 +838,9 @@ static void max310x_wq_proc(struct work_struct *ws) static unsigned int max310x_tx_empty(struct uart_port *port) { - unsigned int lvl, sts; + u8 lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); - lvl = max310x_port_read(port, MAX310X_TXFIFOLVL_REG); - sts = max310x_port_read(port, MAX310X_IRQSTS_REG); - - return ((sts & MAX310X_IRQ_TXEMPTY_BIT) && !lvl) ? TIOCSER_TEMT : 0; + return lvl ? 0 : TIOCSER_TEMT; } static unsigned int max310x_get_mctrl(struct uart_port *port) @@ -1200,8 +1202,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct max310x_one) * devtype->nr, GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; @@ -1261,9 +1262,8 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, MAX310X_BRGDIVLSB_REG + offs, &ret); } while (ret != 0x01); - regmap_update_bits(s->regmap, MAX310X_MODE1_REG + offs, - MAX310X_MODE1_AUTOSLEEP_BIT, - MAX310X_MODE1_AUTOSLEEP_BIT); + regmap_write(s->regmap, MAX310X_MODE1_REG + offs, + devtype->mode1); } uartclk = max310x_set_ref_clk(dev, s, freq, xtal); @@ -1297,10 +1297,6 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, max310x_port_write(&s->p[i].port, MAX310X_IRQEN_REG, 0); /* Clear IRQ status register */ max310x_port_read(&s->p[i].port, MAX310X_IRQSTS_REG); - /* Enable IRQ pin */ - max310x_port_update(&s->p[i].port, MAX310X_MODE1_REG, - MAX310X_MODE1_IRQSEL_BIT, - MAX310X_MODE1_IRQSEL_BIT); /* Initialize queue for start TX */ INIT_WORK(&s->p[i].tx_work, max310x_wq_proc); /* Initialize queue for changing LOOPBACK mode */ @@ -1419,6 +1415,8 @@ static int max310x_spi_probe(struct spi_device *spi) if (spi->dev.of_node) { const struct of_device_id *of_id = of_match_device(max310x_dt_ids, &spi->dev); + if (!of_id) + return -ENODEV; devtype = (struct max310x_devtype *)of_id->data; } else { @@ -1470,10 +1468,10 @@ static int __init max310x_uart_init(void) return ret; #ifdef CONFIG_SPI_MASTER - spi_register_driver(&max310x_spi_driver); + ret = spi_register_driver(&max310x_spi_driver); #endif - return 0; + return ret; } module_init(max310x_uart_init); diff --git a/drivers/tty/serial/meson_uart.c b/drivers/tty/serial/meson_uart.c index 8a842591b37c..fbc5bc022a39 100644 --- a/drivers/tty/serial/meson_uart.c +++ b/drivers/tty/serial/meson_uart.c @@ -72,7 +72,8 @@ #define AML_UART_BAUD_USE BIT(23) #define AML_UART_BAUD_XTAL BIT(24) -#define AML_UART_PORT_NUM 6 +#define AML_UART_PORT_NUM 12 +#define AML_UART_PORT_OFFSET 6 #define AML_UART_DEV_NAME "ttyAML" @@ -654,10 +655,20 @@ static int meson_uart_probe(struct platform_device *pdev) struct resource *res_mem, *res_irq; struct uart_port *port; int ret = 0; + int id = -1; if (pdev->dev.of_node) pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (pdev->id < 0) { + for (id = AML_UART_PORT_OFFSET; id < AML_UART_PORT_NUM; id++) { + if (!meson_ports[id]) { + pdev->id = id; + break; + } + } + } + if (pdev->id < 0 || pdev->id >= AML_UART_PORT_NUM) return -EINVAL; diff --git a/drivers/tty/serial/mps2-uart.c b/drivers/tty/serial/mps2-uart.c index 9f8f63719126..587b42f754cb 100644 --- a/drivers/tty/serial/mps2-uart.c +++ b/drivers/tty/serial/mps2-uart.c @@ -22,6 +22,7 @@ #include <linux/serial_core.h> #include <linux/tty_flip.h> #include <linux/types.h> +#include <linux/idr.h> #define SERIAL_NAME "ttyMPS" #define DRIVER_NAME "mps2-uart" @@ -65,11 +66,14 @@ #define MPS2_MAX_PORTS 3 +#define UART_PORT_COMBINED_IRQ BIT(0) + struct mps2_uart_port { struct uart_port port; struct clk *clk; unsigned int tx_irq; unsigned int rx_irq; + unsigned int flags; }; static inline struct mps2_uart_port *to_mps2_port(struct uart_port *port) @@ -264,6 +268,20 @@ static irqreturn_t mps2_uart_oerrirq(int irq, void *data) return handled; } +static irqreturn_t mps2_uart_combinedirq(int irq, void *data) +{ + if (mps2_uart_rxirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + if (mps2_uart_txirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + if (mps2_uart_oerrirq(irq, data) == IRQ_HANDLED) + return IRQ_HANDLED; + + return IRQ_NONE; +} + static int mps2_uart_startup(struct uart_port *port) { struct mps2_uart_port *mps_port = to_mps2_port(port); @@ -274,26 +292,37 @@ static int mps2_uart_startup(struct uart_port *port) mps2_uart_write8(port, control, UARTn_CTRL); - ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, - MAKE_NAME(-rx), mps_port); - if (ret) { - dev_err(port->dev, "failed to register rxirq (%d)\n", ret); - return ret; - } + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { + ret = request_irq(port->irq, mps2_uart_combinedirq, 0, + MAKE_NAME(-combined), mps_port); - ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, - MAKE_NAME(-tx), mps_port); - if (ret) { - dev_err(port->dev, "failed to register txirq (%d)\n", ret); - goto err_free_rxirq; - } + if (ret) { + dev_err(port->dev, "failed to register combinedirq (%d)\n", ret); + return ret; + } + } else { + ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, + MAKE_NAME(-overrun), mps_port); + + if (ret) { + dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); + return ret; + } + + ret = request_irq(mps_port->rx_irq, mps2_uart_rxirq, 0, + MAKE_NAME(-rx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register rxirq (%d)\n", ret); + goto err_free_oerrirq; + } - ret = request_irq(port->irq, mps2_uart_oerrirq, IRQF_SHARED, - MAKE_NAME(-overrun), mps_port); + ret = request_irq(mps_port->tx_irq, mps2_uart_txirq, 0, + MAKE_NAME(-tx), mps_port); + if (ret) { + dev_err(port->dev, "failed to register txirq (%d)\n", ret); + goto err_free_rxirq; + } - if (ret) { - dev_err(port->dev, "failed to register oerrirq (%d)\n", ret); - goto err_free_txirq; } control |= UARTn_CTRL_RX_GRP | UARTn_CTRL_TX_GRP; @@ -302,10 +331,10 @@ static int mps2_uart_startup(struct uart_port *port) return 0; -err_free_txirq: - free_irq(mps_port->tx_irq, mps_port); err_free_rxirq: free_irq(mps_port->rx_irq, mps_port); +err_free_oerrirq: + free_irq(port->irq, mps_port); return ret; } @@ -319,8 +348,11 @@ static void mps2_uart_shutdown(struct uart_port *port) mps2_uart_write8(port, control, UARTn_CTRL); - free_irq(mps_port->rx_irq, mps_port); - free_irq(mps_port->tx_irq, mps_port); + if (!(mps_port->flags & UART_PORT_COMBINED_IRQ)) { + free_irq(mps_port->rx_irq, mps_port); + free_irq(mps_port->tx_irq, mps_port); + } + free_irq(port->irq, mps_port); } @@ -397,7 +429,7 @@ static const struct uart_ops mps2_uart_pops = { .verify_port = mps2_uart_verify_port, }; -static struct mps2_uart_port mps2_uart_ports[MPS2_MAX_PORTS]; +static DEFINE_IDR(ports_idr); #ifdef CONFIG_SERIAL_MPS2_UART_CONSOLE static void mps2_uart_console_putchar(struct uart_port *port, int ch) @@ -410,7 +442,8 @@ static void mps2_uart_console_putchar(struct uart_port *port, int ch) static void mps2_uart_console_write(struct console *co, const char *s, unsigned int cnt) { - struct uart_port *port = &mps2_uart_ports[co->index].port; + struct mps2_uart_port *mps_port = idr_find(&ports_idr, co->index); + struct uart_port *port = &mps_port->port; uart_console_write(port, s, cnt, mps2_uart_console_putchar); } @@ -426,7 +459,10 @@ static int mps2_uart_console_setup(struct console *co, char *options) if (co->index < 0 || co->index >= MPS2_MAX_PORTS) return -ENODEV; - mps_port = &mps2_uart_ports[co->index]; + mps_port = idr_find(&ports_idr, co->index); + + if (!mps_port) + return -ENODEV; if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); @@ -487,27 +523,36 @@ static struct uart_driver mps2_uart_driver = { .cons = MPS2_SERIAL_CONSOLE, }; -static struct mps2_uart_port *mps2_of_get_port(struct platform_device *pdev) +static int mps2_of_get_port(struct platform_device *pdev, + struct mps2_uart_port *mps_port) { struct device_node *np = pdev->dev.of_node; int id; if (!np) - return NULL; + return -ENODEV; id = of_alias_get_id(np, "serial"); + if (id < 0) - id = 0; + id = idr_alloc_cyclic(&ports_idr, (void *)mps_port, 0, MPS2_MAX_PORTS, GFP_KERNEL); + else + id = idr_alloc(&ports_idr, (void *)mps_port, id, MPS2_MAX_PORTS, GFP_KERNEL); - if (WARN_ON(id >= MPS2_MAX_PORTS)) - return NULL; + if (id < 0) + return id; + + /* Only combined irq is presesnt */ + if (platform_irq_count(pdev) == 1) + mps_port->flags |= UART_PORT_COMBINED_IRQ; + + mps_port->port.line = id; - mps2_uart_ports[id].port.line = id; - return &mps2_uart_ports[id]; + return 0; } -static int mps2_init_port(struct mps2_uart_port *mps_port, - struct platform_device *pdev) +static int mps2_init_port(struct platform_device *pdev, + struct mps2_uart_port *mps_port) { struct resource *res; int ret; @@ -519,11 +564,6 @@ static int mps2_init_port(struct mps2_uart_port *mps_port, mps_port->port.mapbase = res->start; mps_port->port.mapsize = resource_size(res); - - mps_port->rx_irq = platform_get_irq(pdev, 0); - mps_port->tx_irq = platform_get_irq(pdev, 1); - mps_port->port.irq = platform_get_irq(pdev, 2); - mps_port->port.iotype = UPIO_MEM; mps_port->port.flags = UPF_BOOT_AUTOCONF; mps_port->port.fifosize = 1; @@ -542,6 +582,15 @@ static int mps2_init_port(struct mps2_uart_port *mps_port, clk_disable_unprepare(mps_port->clk); + + if (mps_port->flags & UART_PORT_COMBINED_IRQ) { + mps_port->port.irq = platform_get_irq(pdev, 0); + } else { + mps_port->rx_irq = platform_get_irq(pdev, 0); + mps_port->tx_irq = platform_get_irq(pdev, 1); + mps_port->port.irq = platform_get_irq(pdev, 2); + } + return ret; } @@ -550,11 +599,16 @@ static int mps2_serial_probe(struct platform_device *pdev) struct mps2_uart_port *mps_port; int ret; - mps_port = mps2_of_get_port(pdev); - if (!mps_port) - return -ENODEV; + mps_port = devm_kzalloc(&pdev->dev, sizeof(struct mps2_uart_port), GFP_KERNEL); + + if (!mps_port) + return -ENOMEM; + + ret = mps2_of_get_port(pdev, mps_port); + if (ret) + return ret; - ret = mps2_init_port(mps_port, pdev); + ret = mps2_init_port(pdev, mps_port); if (ret) return ret; diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c index 736b74fd6623..109096033bb1 100644 --- a/drivers/tty/serial/msm_serial.c +++ b/drivers/tty/serial/msm_serial.c @@ -1634,7 +1634,7 @@ static void msm_console_write(struct console *co, const char *s, __msm_console_write(port, s, count, msm_port->is_uartdm); } -static int __init msm_console_setup(struct console *co, char *options) +static int msm_console_setup(struct console *co, char *options) { struct uart_port *port; int baud = 115200; diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index 170e446a2f62..7e7b1559fa36 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -72,6 +72,8 @@ #define BRDV_BAUD_MASK 0x3FF #define UART_OSAMP 0x14 +#define OSAMP_DEFAULT_DIVISOR 16 +#define OSAMP_DIVISORS_MASK 0x3F3F3F3F #define MVEBU_NR_UARTS 2 @@ -444,25 +446,34 @@ static void mvebu_uart_shutdown(struct uart_port *port) static int mvebu_uart_baud_rate_set(struct uart_port *port, unsigned int baud) { struct mvebu_uart *mvuart = to_mvuart(port); - unsigned int baud_rate_div; - u32 brdv; + unsigned int d_divisor, m_divisor; + u32 brdv, osamp; if (IS_ERR(mvuart->clk)) return -PTR_ERR(mvuart->clk); /* - * The UART clock is divided by the value of the divisor to generate - * UCLK_OUT clock, which is 16 times faster than the baudrate. - * This prescaler can achieve all standard baudrates until 230400. - * Higher baudrates could be achieved for the extended UART by using the - * programmable oversampling stack (also called fractional divisor). + * The baudrate is derived from the UART clock thanks to two divisors: + * > D ("baud generator"): can divide the clock from 2 to 2^10 - 1. + * > M ("fractional divisor"): allows a better accuracy for + * baudrates higher than 230400. + * + * As the derivation of M is rather complicated, the code sticks to its + * default value (x16) when all the prescalers are zeroed, and only + * makes use of D to configure the desired baudrate. */ - baud_rate_div = DIV_ROUND_UP(port->uartclk, baud * 16); + m_divisor = OSAMP_DEFAULT_DIVISOR; + d_divisor = DIV_ROUND_UP(port->uartclk, baud * m_divisor); + brdv = readl(port->membase + UART_BRDV); brdv &= ~BRDV_BAUD_MASK; - brdv |= baud_rate_div; + brdv |= d_divisor; writel(brdv, port->membase + UART_BRDV); + osamp = readl(port->membase + UART_OSAMP); + osamp &= ~OSAMP_DIVISORS_MASK; + writel(osamp, port->membase + UART_OSAMP); + return 0; } @@ -799,6 +810,9 @@ static int mvebu_uart_probe(struct platform_device *pdev) return -EINVAL; } + if (!match) + return -ENODEV; + /* Assume that all UART ports have a DT alias or none has */ id = of_alias_get_id(pdev->dev.of_node, "serial"); if (!pdev->dev.of_node || id < 0) diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 27235a526cce..4c188f4079b3 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1686,6 +1686,10 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.mapbase = r->start; s->port.membase = ioremap(r->start, resource_size(r)); + if (!s->port.membase) { + ret = -ENOMEM; + goto out_disable_clks; + } s->port.ops = &mxs_auart_ops; s->port.iotype = UPIO_MEM; s->port.fifosize = MXS_AUART_FIFO_SIZE; diff --git a/drivers/tty/serial/pch_uart.c b/drivers/tty/serial/pch_uart.c index cb85002a10d8..6157213a8359 100644 --- a/drivers/tty/serial/pch_uart.c +++ b/drivers/tty/serial/pch_uart.c @@ -192,8 +192,6 @@ enum { #define PCH_UART_HAL_LOOP (PCH_UART_MCR_LOOP) #define PCH_UART_HAL_AFE (PCH_UART_MCR_AFE) -#define PCI_VENDOR_ID_ROHM 0x10DB - #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define DEFAULT_UARTCLK 1843200 /* 1.8432 MHz */ @@ -933,7 +931,6 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) struct scatterlist *sg; int nent; int fifo_size; - int tx_empty; struct dma_async_tx_descriptor *desc; int num; int i; @@ -958,11 +955,9 @@ static unsigned int dma_handle_tx(struct eg20t_port *priv) } fifo_size = max(priv->fifo_size, 1); - tx_empty = 1; if (pop_tx_x(priv, xmit->buf)) { pch_uart_hal_write(priv, xmit->buf, 1); port->icount.tx++; - tx_empty = 0; fifo_size--; } diff --git a/drivers/tty/serial/pic32_uart.c b/drivers/tty/serial/pic32_uart.c index fd80d999308d..0bdf1687983f 100644 --- a/drivers/tty/serial/pic32_uart.c +++ b/drivers/tty/serial/pic32_uart.c @@ -919,6 +919,7 @@ static struct platform_driver pic32_uart_platform_driver = { .driver = { .name = PIC32_DEV_NAME, .of_match_table = of_match_ptr(pic32_serial_dt_ids), + .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_PIC32), }, }; diff --git a/drivers/tty/serial/pmac_zilog.c b/drivers/tty/serial/pmac_zilog.c index a9d40988e1c8..bcb5bf70534e 100644 --- a/drivers/tty/serial/pmac_zilog.c +++ b/drivers/tty/serial/pmac_zilog.c @@ -1648,9 +1648,9 @@ static int __init pmz_probe(void) */ node_a = node_b = NULL; for (np = NULL; (np = of_get_next_child(node_p, np)) != NULL;) { - if (strncmp(np->name, "ch-a", 4) == 0) + if (of_node_name_prefix(np, "ch-a")) node_a = of_node_get(np); - else if (strncmp(np->name, "ch-b", 4) == 0) + else if (of_node_name_prefix(np, "ch-b")) node_b = of_node_get(np); } if (!node_a && !node_b) { diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index d3b5261ee80a..35e5f9c5d5be 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1,6 +1,10 @@ // SPDX-License-Identifier: GPL-2.0 // Copyright (c) 2017-2018, The Linux foundation. All rights reserved. +#if defined(CONFIG_SERIAL_QCOM_GENI_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +# define SUPPORT_SYSRQ +#endif + #include <linux/clk.h> #include <linux/console.h> #include <linux/io.h> @@ -85,13 +89,13 @@ #define DEF_FIFO_DEPTH_WORDS 16 #define DEF_TX_WM 2 #define DEF_FIFO_WIDTH_BITS 32 -#define UART_CONSOLE_RX_WM 2 +#define UART_RX_WM 2 #define MAX_LOOPBACK_CFG 3 #ifdef CONFIG_CONSOLE_POLL -#define RX_BYTES_PW 1 +#define CONSOLE_RX_BYTES_PW 1 #else -#define RX_BYTES_PW 4 +#define CONSOLE_RX_BYTES_PW 4 #endif struct qcom_geni_serial_port { @@ -101,10 +105,6 @@ struct qcom_geni_serial_port { u32 tx_fifo_depth; u32 tx_fifo_width; u32 rx_fifo_depth; - u32 tx_wm; - u32 rx_wm; - u32 rx_rfr; - enum geni_se_xfer_mode xfer_mode; bool setup; int (*handle_rx)(struct uart_port *uport, u32 bytes, bool drop); unsigned int baud; @@ -113,6 +113,8 @@ struct qcom_geni_serial_port { u32 *rx_fifo; u32 loopback; bool brk; + + unsigned int tx_remaining; }; static const struct uart_ops qcom_geni_console_pops; @@ -162,8 +164,7 @@ static struct qcom_geni_serial_port qcom_geni_uart_ports[GENI_UART_PORTS] = { static ssize_t loopback_show(struct device *dev, struct device_attribute *attr, char *buf) { - struct platform_device *pdev = to_platform_device(dev); - struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct qcom_geni_serial_port *port = dev_get_drvdata(dev); return snprintf(buf, sizeof(u32), "%d\n", port->loopback); } @@ -172,8 +173,7 @@ static ssize_t loopback_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t size) { - struct platform_device *pdev = to_platform_device(dev); - struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct qcom_geni_serial_port *port = dev_get_drvdata(dev); u32 loopback; if (kstrtoint(buf, 0, &loopback) || loopback > MAX_LOOPBACK_CFG) { @@ -221,10 +221,10 @@ static unsigned int qcom_geni_serial_get_mctrl(struct uart_port *uport) unsigned int mctrl = TIOCM_DSR | TIOCM_CAR; u32 geni_ios; - if (uart_console(uport) || !uart_cts_enabled(uport)) { + if (uart_console(uport)) { mctrl |= TIOCM_CTS; } else { - geni_ios = readl_relaxed(uport->membase + SE_GENI_IOS); + geni_ios = readl(uport->membase + SE_GENI_IOS); if (!(geni_ios & IO2_DATA_IN)) mctrl |= TIOCM_CTS; } @@ -237,12 +237,12 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport, { u32 uart_manual_rfr = 0; - if (uart_console(uport) || !uart_cts_enabled(uport)) + if (uart_console(uport)) return; if (!(mctrl & TIOCM_RTS)) uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; - writel_relaxed(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); + writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); } static const char *qcom_geni_serial_get_type(struct uart_port *uport) @@ -271,9 +271,6 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, unsigned int fifo_bits; unsigned long timeout_us = 20000; - /* Ensure polling is not re-ordered before the prior writes/reads */ - mb(); - if (uport->private_data) { port = to_dev_port(uport, uport); baud = port->baud; @@ -293,7 +290,7 @@ static bool qcom_geni_serial_poll_bit(struct uart_port *uport, */ timeout_us = DIV_ROUND_UP(timeout_us, 10) * 10; while (timeout_us) { - reg = readl_relaxed(uport->membase + offset); + reg = readl(uport->membase + offset); if ((bool)(reg & field) == set) return true; udelay(10); @@ -306,7 +303,7 @@ static void qcom_geni_serial_setup_tx(struct uart_port *uport, u32 xmit_size) { u32 m_cmd; - writel_relaxed(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); + writel(xmit_size, uport->membase + SE_UART_TX_TRANS_LEN); m_cmd = UART_START_TX << M_OPCODE_SHFT; writel(m_cmd, uport->membase + SE_GENI_M_CMD0); } @@ -319,13 +316,13 @@ static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) done = qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_DONE_EN, true); if (!done) { - writel_relaxed(M_GENI_CMD_ABORT, uport->membase + + writel(M_GENI_CMD_ABORT, uport->membase + SE_GENI_M_CMD_CTRL_REG); irq_clear |= M_CMD_ABORT_EN; qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); } - writel_relaxed(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(irq_clear, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_abort_rx(struct uart_port *uport) @@ -335,8 +332,8 @@ static void qcom_geni_serial_abort_rx(struct uart_port *uport) writel(S_GENI_CMD_ABORT, uport->membase + SE_GENI_S_CMD_CTRL_REG); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_ABORT, false); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); - writel_relaxed(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + writel(FORCE_DEFAULT, uport->membase + GENI_FORCE_DEFAULT_REG); } #ifdef CONFIG_CONSOLE_POLL @@ -345,19 +342,13 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) u32 rx_fifo; u32 status; - status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_M_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_M_IRQ_CLEAR); - status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - writel_relaxed(status, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + writel(status, uport->membase + SE_GENI_S_IRQ_CLEAR); - /* - * Ensure the writes to clear interrupts is not re-ordered after - * reading the data. - */ - mb(); - - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); if (!(status & RX_FIFO_WC_MSK)) return NO_POLL_CHAR; @@ -368,15 +359,12 @@ static int qcom_geni_serial_get_char(struct uart_port *uport) static void qcom_geni_serial_poll_put_char(struct uart_port *uport, unsigned char c) { - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - - writel_relaxed(port->tx_wm, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, 1); WARN_ON(!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_TX_FIFO_WATERMARK_EN, true)); - writel_relaxed(c, uport->membase + SE_GENI_TX_FIFOn); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(c, uport->membase + SE_GENI_TX_FIFOn); + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); qcom_geni_serial_poll_tx_done(uport); } #endif @@ -384,7 +372,7 @@ static void qcom_geni_serial_poll_put_char(struct uart_port *uport, #ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE static void qcom_geni_serial_wr_char(struct uart_port *uport, int ch) { - writel_relaxed(ch, uport->membase + SE_GENI_TX_FIFOn); + writel(ch, uport->membase + SE_GENI_TX_FIFOn); } static void @@ -403,7 +391,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, bytes_to_send++; } - writel_relaxed(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); qcom_geni_serial_setup_tx(uport, bytes_to_send); for (i = 0; i < count; ) { size_t chars_to_write = 0; @@ -421,7 +409,7 @@ __qcom_geni_serial_console_write(struct uart_port *uport, const char *s, chars_to_write = min_t(size_t, count - i, avail / 2); uart_console_write(uport, s + i, chars_to_write, qcom_geni_serial_wr_char); - writel_relaxed(M_TX_FIFO_WATERMARK_EN, uport->membase + + writel(M_TX_FIFO_WATERMARK_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); i += chars_to_write; } @@ -435,6 +423,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, struct qcom_geni_serial_port *port; bool locked = true; unsigned long flags; + u32 geni_status; + u32 irq_en; WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); @@ -448,6 +438,8 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, else spin_lock_irqsave(&uport->lock, flags); + geni_status = readl(uport->membase + SE_GENI_STATUS); + /* Cancel the current write to log the fault */ if (!locked) { geni_se_cancel_m_cmd(&port->se); @@ -456,14 +448,29 @@ static void qcom_geni_serial_console_write(struct console *co, const char *s, geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + } else if ((geni_status & M_GENI_CMD_ACTIVE) && !port->tx_remaining) { + /* + * It seems we can't interrupt existing transfers if all data + * has been sent, in which case we need to look for done first. + */ + qcom_geni_serial_poll_tx_done(uport); + + if (uart_circ_chars_pending(&uport->state->xmit)) { + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(irq_en | M_TX_FIFO_WATERMARK_EN, + uport->membase + SE_GENI_M_IRQ_EN); + } } __qcom_geni_serial_console_write(uport, s, count); + + if (port->tx_remaining) + qcom_geni_serial_setup_tx(uport, port->tx_remaining); + if (locked) spin_unlock_irqrestore(&uport->lock, flags); } @@ -495,7 +502,8 @@ static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) continue; } - sysrq = uart_handle_sysrq_char(uport, buf[c]); + sysrq = uart_prepare_sysrq_char(uport, buf[c]); + if (!sysrq) tty_insert_flip_char(tport, buf[c], TTY_NORMAL); } @@ -541,29 +549,20 @@ static int handle_rx_uart(struct uart_port *uport, u32 bytes, bool drop) static void qcom_geni_serial_start_tx(struct uart_port *uport) { u32 irq_en; - struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 status; - if (port->xfer_mode == GENI_SE_FIFO) { - /* - * readl ensures reading & writing of IRQ_EN register - * is not re-ordered before checking the status of the - * Serial Engine. - */ - status = readl(uport->membase + SE_GENI_STATUS); - if (status & M_GENI_CMD_ACTIVE) - return; + status = readl(uport->membase + SE_GENI_STATUS); + if (status & M_GENI_CMD_ACTIVE) + return; - if (!qcom_geni_serial_tx_empty(uport)) - return; + if (!qcom_geni_serial_tx_empty(uport)) + return; - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN; - writel_relaxed(port->tx_wm, uport->membase + - SE_GENI_TX_WATERMARK_REG); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + writel(DEF_TX_WM, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_tx(struct uart_port *uport) @@ -572,35 +571,24 @@ static void qcom_geni_serial_stop_tx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~M_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en &= ~M_TX_FIFO_WATERMARK_EN; - writel_relaxed(0, uport->membase + - SE_GENI_TX_WATERMARK_REG); - } - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en &= ~(M_CMD_DONE_EN | M_TX_FIFO_WATERMARK_EN); + writel(0, uport->membase + SE_GENI_TX_WATERMARK_REG); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop tx is called multiple times. */ if (!(status & M_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Primary Sequencer. - */ - mb(); - geni_se_cancel_m_cmd(&port->se); if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_CANCEL_EN, true)) { geni_se_abort_m_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, M_CMD_ABORT_EN, true); - writel_relaxed(M_CMD_ABORT_EN, uport->membase + - SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_ABORT_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } - writel_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); } static void qcom_geni_serial_start_rx(struct uart_port *uport) @@ -609,27 +597,19 @@ static void qcom_geni_serial_start_rx(struct uart_port *uport) u32 status; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_stop_rx(uport); - /* - * Ensure setup command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_setup_s_cmd(&port->se, UART_START_READ, 0); - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); - irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en |= S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en |= M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN; + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); } static void qcom_geni_serial_stop_rx(struct uart_port *uport) @@ -639,32 +619,24 @@ static void qcom_geni_serial_stop_rx(struct uart_port *uport) struct qcom_geni_serial_port *port = to_dev_port(uport, uport); u32 irq_clear = S_CMD_DONE_EN; - if (port->xfer_mode == GENI_SE_FIFO) { - irq_en = readl_relaxed(uport->membase + SE_GENI_S_IRQ_EN); - irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_S_IRQ_EN); + irq_en = readl(uport->membase + SE_GENI_S_IRQ_EN); + irq_en &= ~(S_RX_FIFO_WATERMARK_EN | S_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_S_IRQ_EN); - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + irq_en &= ~(M_RX_FIFO_WATERMARK_EN | M_RX_FIFO_LAST_EN); + writel(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); + status = readl(uport->membase + SE_GENI_STATUS); /* Possible stop rx is called multiple times. */ if (!(status & S_GENI_CMD_ACTIVE)) return; - /* - * Ensure cancel command write is not re-ordered before checking - * the status of the Secondary Sequencer. - */ - mb(); - geni_se_cancel_s_cmd(&port->se); qcom_geni_serial_poll_bit(uport, SE_GENI_S_CMD_CTRL_REG, S_GENI_CMD_CANCEL, false); - status = readl_relaxed(uport->membase + SE_GENI_STATUS); - writel_relaxed(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); + status = readl(uport->membase + SE_GENI_STATUS); + writel(irq_clear, uport->membase + SE_GENI_S_IRQ_CLEAR); if (status & S_GENI_CMD_ACTIVE) qcom_geni_serial_abort_rx(uport); } @@ -678,7 +650,7 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) u32 total_bytes; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - status = readl_relaxed(uport->membase + SE_GENI_RX_FIFO_STATUS); + status = readl(uport->membase + SE_GENI_RX_FIFO_STATUS); word_cnt = status & RX_FIFO_WC_MSK; last_word_partial = status & RX_LAST; last_word_byte_cnt = (status & RX_LAST_BYTE_VALID_MSK) >> @@ -694,40 +666,51 @@ static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) port->handle_rx(uport, total_bytes, drop); } -static void qcom_geni_serial_handle_tx(struct uart_port *uport) +static void qcom_geni_serial_handle_tx(struct uart_port *uport, bool done, + bool active) { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); struct circ_buf *xmit = &uport->state->xmit; size_t avail; size_t remaining; + size_t pending; int i; u32 status; + u32 irq_en; unsigned int chunk; int tail; - u32 irq_en; - chunk = uart_circ_chars_pending(xmit); - status = readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); - /* Both FIFO and framework buffer are drained */ - if (!chunk && !status) { + status = readl(uport->membase + SE_GENI_TX_FIFO_STATUS); + + /* Complete the current tx command before taking newly added data */ + if (active) + pending = port->tx_remaining; + else + pending = uart_circ_chars_pending(xmit); + + /* All data has been transmitted and acknowledged as received */ + if (!pending && !status && done) { qcom_geni_serial_stop_tx(uport); goto out_write_wakeup; } - if (!uart_console(uport)) { - irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - irq_en &= ~(M_TX_FIFO_WATERMARK_EN); - writel_relaxed(0, uport->membase + SE_GENI_TX_WATERMARK_REG); - writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); - } + avail = port->tx_fifo_depth - (status & TX_FIFO_WC); + avail *= port->tx_bytes_pw; - avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw; tail = xmit->tail; - chunk = min3((size_t)chunk, (size_t)(UART_XMIT_SIZE - tail), avail); + chunk = min(avail, pending); if (!chunk) goto out_write_wakeup; - qcom_geni_serial_setup_tx(uport, chunk); + if (!port->tx_remaining) { + qcom_geni_serial_setup_tx(uport, pending); + port->tx_remaining = pending; + + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + if (!(irq_en & M_TX_FIFO_WATERMARK_EN)) + writel(irq_en | M_TX_FIFO_WATERMARK_EN, + uport->membase + SE_GENI_M_IRQ_EN); + } remaining = chunk; for (i = 0; i < chunk; ) { @@ -737,32 +720,50 @@ static void qcom_geni_serial_handle_tx(struct uart_port *uport) memset(buf, 0, ARRAY_SIZE(buf)); tx_bytes = min_t(size_t, remaining, port->tx_bytes_pw); - for (c = 0; c < tx_bytes ; c++) - buf[c] = xmit->buf[tail + c]; + + for (c = 0; c < tx_bytes ; c++) { + buf[c] = xmit->buf[tail++]; + tail &= UART_XMIT_SIZE - 1; + } iowrite32_rep(uport->membase + SE_GENI_TX_FIFOn, buf, 1); i += tx_bytes; - tail += tx_bytes; uport->icount.tx += tx_bytes; remaining -= tx_bytes; + port->tx_remaining -= tx_bytes; } - xmit->tail = tail & (UART_XMIT_SIZE - 1); - if (uart_console(uport)) - qcom_geni_serial_poll_tx_done(uport); + xmit->tail = tail; + + /* + * The tx fifo watermark is level triggered and latched. Though we had + * cleared it in qcom_geni_serial_isr it will have already reasserted + * so we must clear it again here after our writes. + */ + writel(M_TX_FIFO_WATERMARK_EN, + uport->membase + SE_GENI_M_IRQ_CLEAR); + out_write_wakeup: + if (!port->tx_remaining) { + irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + if (irq_en & M_TX_FIFO_WATERMARK_EN) + writel(irq_en & ~M_TX_FIFO_WATERMARK_EN, + uport->membase + SE_GENI_M_IRQ_EN); + } + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(uport); } static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) { - unsigned int m_irq_status; - unsigned int s_irq_status; + u32 m_irq_en; + u32 m_irq_status; + u32 s_irq_status; + u32 geni_status; struct uart_port *uport = dev; unsigned long flags; - unsigned int m_irq_en; bool drop_rx = false; struct tty_port *tport = &uport->state->port; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); @@ -771,11 +772,12 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) return IRQ_NONE; spin_lock_irqsave(&uport->lock, flags); - m_irq_status = readl_relaxed(uport->membase + SE_GENI_M_IRQ_STATUS); - s_irq_status = readl_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); - m_irq_en = readl_relaxed(uport->membase + SE_GENI_M_IRQ_EN); - writel_relaxed(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); - writel_relaxed(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); + m_irq_status = readl(uport->membase + SE_GENI_M_IRQ_STATUS); + s_irq_status = readl(uport->membase + SE_GENI_S_IRQ_STATUS); + geni_status = readl(uport->membase + SE_GENI_STATUS); + m_irq_en = readl(uport->membase + SE_GENI_M_IRQ_EN); + writel(m_irq_status, uport->membase + SE_GENI_M_IRQ_CLEAR); + writel(s_irq_status, uport->membase + SE_GENI_S_IRQ_CLEAR); if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) goto out_unlock; @@ -785,9 +787,9 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) tty_insert_flip_char(tport, 0, TTY_OVERRUN); } - if (m_irq_status & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN) && - m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) - qcom_geni_serial_handle_tx(uport); + if (m_irq_status & m_irq_en & (M_TX_FIFO_WATERMARK_EN | M_CMD_DONE_EN)) + qcom_geni_serial_handle_tx(uport, m_irq_status & M_CMD_DONE_EN, + geni_status & M_GENI_CMD_ACTIVE); if (s_irq_status & S_GP_IRQ_0_EN || s_irq_status & S_GP_IRQ_1_EN) { if (s_irq_status & S_GP_IRQ_0_EN) @@ -804,7 +806,8 @@ static irqreturn_t qcom_geni_serial_isr(int isr, void *dev) qcom_geni_serial_handle_rx(uport, drop_rx); out_unlock: - spin_unlock_irqrestore(&uport->lock, flags); + uart_unlock_and_check_sysrq(uport, flags); + return IRQ_HANDLED; } @@ -820,17 +823,6 @@ static void get_tx_fifo_size(struct qcom_geni_serial_port *port) (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; } -static void set_rfr_wm(struct qcom_geni_serial_port *port) -{ - /* - * Set RFR (Flow off) to FIFO_DEPTH - 2. - * RX WM level at 10% RX_FIFO_DEPTH. - * TX WM level at 10% TX_FIFO_DEPTH. - */ - port->rx_rfr = port->rx_fifo_depth - 2; - port->rx_wm = UART_CONSOLE_RX_WM; - port->tx_wm = DEF_TX_WM; -} static void qcom_geni_serial_shutdown(struct uart_port *uport) { @@ -850,14 +842,16 @@ static void qcom_geni_serial_shutdown(struct uart_port *uport) static int qcom_geni_serial_port_setup(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport, uport); - unsigned int rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; + u32 rxstale = DEFAULT_BITS_PER_CHAR * STALE_TIMEOUT; u32 proto; - if (uart_console(uport)) + if (uart_console(uport)) { port->tx_bytes_pw = 1; - else + port->rx_bytes_pw = CONSOLE_RX_BYTES_PW; + } else { port->tx_bytes_pw = 4; - port->rx_bytes_pw = RX_BYTES_PW; + port->rx_bytes_pw = 4; + } proto = geni_se_read_proto(&port->se); if (proto != GENI_SE_UART) { @@ -869,21 +863,19 @@ static int qcom_geni_serial_port_setup(struct uart_port *uport) get_tx_fifo_size(port); - set_rfr_wm(port); - writel_relaxed(rxstale, uport->membase + SE_UART_RX_STALE_CNT); + writel(rxstale, uport->membase + SE_UART_RX_STALE_CNT); /* * Make an unconditional cancel on the main sequencer to reset * it else we could end up in data loss scenarios. */ - port->xfer_mode = GENI_SE_FIFO; if (uart_console(uport)) qcom_geni_serial_poll_tx_done(uport); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->tx_bytes_pw, false, true, false); geni_se_config_packing(&port->se, BITS_PER_BYTE, port->rx_bytes_pw, false, false, true); - geni_se_init(&port->se, port->rx_wm, port->rx_rfr); - geni_se_select_mode(&port->se, port->xfer_mode); + geni_se_init(&port->se, UART_RX_WM, port->rx_fifo_depth - 2); + geni_se_select_mode(&port->se, GENI_SE_FIFO); if (!uart_console(uport)) { port->rx_fifo = devm_kcalloc(uport->dev, port->rx_fifo_depth, sizeof(u32), GFP_KERNEL); @@ -949,14 +941,14 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, struct ktermios *termios, struct ktermios *old) { unsigned int baud; - unsigned int bits_per_char; - unsigned int tx_trans_cfg; - unsigned int tx_parity_cfg; - unsigned int rx_trans_cfg; - unsigned int rx_parity_cfg; - unsigned int stop_bit_len; + u32 bits_per_char; + u32 tx_trans_cfg; + u32 tx_parity_cfg; + u32 rx_trans_cfg; + u32 rx_parity_cfg; + u32 stop_bit_len; unsigned int clk_div; - unsigned long ser_clk_cfg; + u32 ser_clk_cfg; struct qcom_geni_serial_port *port = to_dev_port(uport, uport); unsigned long clk_rate; @@ -974,10 +966,10 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, ser_clk_cfg |= clk_div << CLK_DIV_SHFT; /* parity */ - tx_trans_cfg = readl_relaxed(uport->membase + SE_UART_TX_TRANS_CFG); - tx_parity_cfg = readl_relaxed(uport->membase + SE_UART_TX_PARITY_CFG); - rx_trans_cfg = readl_relaxed(uport->membase + SE_UART_RX_TRANS_CFG); - rx_parity_cfg = readl_relaxed(uport->membase + SE_UART_RX_PARITY_CFG); + tx_trans_cfg = readl(uport->membase + SE_UART_TX_TRANS_CFG); + tx_parity_cfg = readl(uport->membase + SE_UART_TX_PARITY_CFG); + rx_trans_cfg = readl(uport->membase + SE_UART_RX_TRANS_CFG); + rx_parity_cfg = readl(uport->membase + SE_UART_RX_PARITY_CFG); if (termios->c_cflag & PARENB) { tx_trans_cfg |= UART_TX_PAR_EN; rx_trans_cfg |= UART_RX_PAR_EN; @@ -1033,17 +1025,17 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport, uart_update_timeout(uport, termios->c_cflag, baud); if (!uart_console(uport)) - writel_relaxed(port->loopback, + writel(port->loopback, uport->membase + SE_UART_LOOPBACK_CFG); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); - writel_relaxed(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(ser_clk_cfg, uport->membase + GENI_SER_M_CLK_CFG); + writel(ser_clk_cfg, uport->membase + GENI_SER_S_CLK_CFG); out_restart_rx: qcom_geni_serial_start_rx(uport); } @@ -1058,7 +1050,7 @@ static int __init qcom_geni_console_setup(struct console *co, char *options) { struct uart_port *uport; struct qcom_geni_serial_port *port; - int baud; + int baud = 9600; int bits = 8; int parity = 'n'; int flow = 'n'; @@ -1134,13 +1126,13 @@ static int __init qcom_geni_serial_earlycon_setup(struct earlycon_device *dev, geni_se_init(&se, DEF_FIFO_DEPTH_WORDS / 2, DEF_FIFO_DEPTH_WORDS - 2); geni_se_select_mode(&se, GENI_SE_FIFO); - writel_relaxed(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); - writel_relaxed(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); - writel_relaxed(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); - writel_relaxed(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); - writel_relaxed(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); - writel_relaxed(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); - writel_relaxed(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); + writel(tx_trans_cfg, uport->membase + SE_UART_TX_TRANS_CFG); + writel(tx_parity_cfg, uport->membase + SE_UART_TX_PARITY_CFG); + writel(rx_trans_cfg, uport->membase + SE_UART_RX_TRANS_CFG); + writel(rx_parity_cfg, uport->membase + SE_UART_RX_PARITY_CFG); + writel(bits_per_char, uport->membase + SE_UART_TX_WORD_LEN); + writel(bits_per_char, uport->membase + SE_UART_RX_WORD_LEN); + writel(stop_bit_len, uport->membase + SE_UART_TX_STOP_BIT_LEN); dev->con->write = qcom_geni_serial_earlycon_write; dev->con->setup = NULL; @@ -1322,49 +1314,25 @@ static int qcom_geni_serial_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev) +static int __maybe_unused qcom_geni_serial_sys_suspend(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; - if (uart_console(uport)) { - uart_suspend_port(uport->private_data, uport); - } else { - struct uart_state *state = uport->state; - /* - * If the port is open, deny system suspend. - */ - if (state->pm_state == UART_PM_STATE_ON) - return -EBUSY; - } - - return 0; + return uart_suspend_port(uport->private_data, uport); } -static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev) +static int __maybe_unused qcom_geni_serial_sys_resume(struct device *dev) { struct qcom_geni_serial_port *port = dev_get_drvdata(dev); struct uart_port *uport = &port->uport; - if (uart_console(uport) && - console_suspend_enabled && uport->suspended) { - uart_resume_port(uport->private_data, uport); - /* - * uart_suspend_port() invokes port shutdown which in turn - * frees the irq. uart_resume_port invokes port startup which - * performs request_irq. The request_irq auto-enables the IRQ. - * In addition, resume_noirq implicitly enables the IRQ and - * leads to an unbalanced IRQ enable warning. Disable the IRQ - * before returning so that the warning is suppressed. - */ - disable_irq(uport->irq); - } - return 0; + return uart_resume_port(uport->private_data, uport); } static const struct dev_pm_ops qcom_geni_serial_pm_ops = { - SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend_noirq, - qcom_geni_serial_sys_resume_noirq) + SET_SYSTEM_SLEEP_PM_OPS(qcom_geni_serial_sys_suspend, + qcom_geni_serial_sys_resume) }; static const struct of_device_id qcom_geni_serial_match_table[] = { diff --git a/drivers/tty/serial/rda-uart.c b/drivers/tty/serial/rda-uart.c new file mode 100644 index 000000000000..284623eefaeb --- /dev/null +++ b/drivers/tty/serial/rda-uart.c @@ -0,0 +1,831 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * RDA8810PL serial device driver + * + * Copyright RDA Microelectronics Company Limited + * Copyright (c) 2017 Andreas Färber + * Copyright (c) 2018 Manivannan Sadhasivam + */ + +#include <linux/clk.h> +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#define RDA_UART_PORT_NUM 3 +#define RDA_UART_DEV_NAME "ttyRDA" + +#define RDA_UART_CTRL 0x00 +#define RDA_UART_STATUS 0x04 +#define RDA_UART_RXTX_BUFFER 0x08 +#define RDA_UART_IRQ_MASK 0x0c +#define RDA_UART_IRQ_CAUSE 0x10 +#define RDA_UART_IRQ_TRIGGERS 0x14 +#define RDA_UART_CMD_SET 0x18 +#define RDA_UART_CMD_CLR 0x1c + +/* UART_CTRL Bits */ +#define RDA_UART_ENABLE BIT(0) +#define RDA_UART_DBITS_8 BIT(1) +#define RDA_UART_TX_SBITS_2 BIT(2) +#define RDA_UART_PARITY_EN BIT(3) +#define RDA_UART_PARITY(x) (((x) & 0x3) << 4) +#define RDA_UART_PARITY_ODD RDA_UART_PARITY(0) +#define RDA_UART_PARITY_EVEN RDA_UART_PARITY(1) +#define RDA_UART_PARITY_SPACE RDA_UART_PARITY(2) +#define RDA_UART_PARITY_MARK RDA_UART_PARITY(3) +#define RDA_UART_DIV_MODE BIT(20) +#define RDA_UART_IRDA_EN BIT(21) +#define RDA_UART_DMA_EN BIT(22) +#define RDA_UART_FLOW_CNT_EN BIT(23) +#define RDA_UART_LOOP_BACK_EN BIT(24) +#define RDA_UART_RX_LOCK_ERR BIT(25) +#define RDA_UART_RX_BREAK_LEN(x) (((x) & 0xf) << 28) + +/* UART_STATUS Bits */ +#define RDA_UART_RX_FIFO(x) (((x) & 0x7f) << 0) +#define RDA_UART_RX_FIFO_MASK (0x7f << 0) +#define RDA_UART_TX_FIFO(x) (((x) & 0x1f) << 8) +#define RDA_UART_TX_FIFO_MASK (0x1f << 8) +#define RDA_UART_TX_ACTIVE BIT(14) +#define RDA_UART_RX_ACTIVE BIT(15) +#define RDA_UART_RX_OVERFLOW_ERR BIT(16) +#define RDA_UART_TX_OVERFLOW_ERR BIT(17) +#define RDA_UART_RX_PARITY_ERR BIT(18) +#define RDA_UART_RX_FRAMING_ERR BIT(19) +#define RDA_UART_RX_BREAK_INT BIT(20) +#define RDA_UART_DCTS BIT(24) +#define RDA_UART_CTS BIT(25) +#define RDA_UART_DTR BIT(28) +#define RDA_UART_CLK_ENABLED BIT(31) + +/* UART_RXTX_BUFFER Bits */ +#define RDA_UART_RX_DATA(x) (((x) & 0xff) << 0) +#define RDA_UART_TX_DATA(x) (((x) & 0xff) << 0) + +/* UART_IRQ_MASK Bits */ +#define RDA_UART_TX_MODEM_STATUS BIT(0) +#define RDA_UART_RX_DATA_AVAILABLE BIT(1) +#define RDA_UART_TX_DATA_NEEDED BIT(2) +#define RDA_UART_RX_TIMEOUT BIT(3) +#define RDA_UART_RX_LINE_ERR BIT(4) +#define RDA_UART_TX_DMA_DONE BIT(5) +#define RDA_UART_RX_DMA_DONE BIT(6) +#define RDA_UART_RX_DMA_TIMEOUT BIT(7) +#define RDA_UART_DTR_RISE BIT(8) +#define RDA_UART_DTR_FALL BIT(9) + +/* UART_IRQ_CAUSE Bits */ +#define RDA_UART_TX_MODEM_STATUS_U BIT(16) +#define RDA_UART_RX_DATA_AVAILABLE_U BIT(17) +#define RDA_UART_TX_DATA_NEEDED_U BIT(18) +#define RDA_UART_RX_TIMEOUT_U BIT(19) +#define RDA_UART_RX_LINE_ERR_U BIT(20) +#define RDA_UART_TX_DMA_DONE_U BIT(21) +#define RDA_UART_RX_DMA_DONE_U BIT(22) +#define RDA_UART_RX_DMA_TIMEOUT_U BIT(23) +#define RDA_UART_DTR_RISE_U BIT(24) +#define RDA_UART_DTR_FALL_U BIT(25) + +/* UART_TRIGGERS Bits */ +#define RDA_UART_RX_TRIGGER(x) (((x) & 0x1f) << 0) +#define RDA_UART_TX_TRIGGER(x) (((x) & 0xf) << 8) +#define RDA_UART_AFC_LEVEL(x) (((x) & 0x1f) << 16) + +/* UART_CMD_SET Bits */ +#define RDA_UART_RI BIT(0) +#define RDA_UART_DCD BIT(1) +#define RDA_UART_DSR BIT(2) +#define RDA_UART_TX_BREAK_CONTROL BIT(3) +#define RDA_UART_TX_FINISH_N_WAIT BIT(4) +#define RDA_UART_RTS BIT(5) +#define RDA_UART_RX_FIFO_RESET BIT(6) +#define RDA_UART_TX_FIFO_RESET BIT(7) + +#define RDA_UART_TX_FIFO_SIZE 16 + +static struct uart_driver rda_uart_driver; + +struct rda_uart_port { + struct uart_port port; + struct clk *clk; +}; + +#define to_rda_uart_port(port) container_of(port, struct rda_uart_port, port) + +static struct rda_uart_port *rda_uart_ports[RDA_UART_PORT_NUM]; + +static inline void rda_uart_write(struct uart_port *port, u32 val, + unsigned int off) +{ + writel(val, port->membase + off); +} + +static inline u32 rda_uart_read(struct uart_port *port, unsigned int off) +{ + return readl(port->membase + off); +} + +static unsigned int rda_uart_tx_empty(struct uart_port *port) +{ + unsigned long flags; + unsigned int ret; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + + val = rda_uart_read(port, RDA_UART_STATUS); + ret = (val & RDA_UART_TX_FIFO_MASK) ? TIOCSER_TEMT : 0; + + spin_unlock_irqrestore(&port->lock, flags); + + return ret; +} + +static unsigned int rda_uart_get_mctrl(struct uart_port *port) +{ + unsigned int mctrl = 0; + u32 cmd_set, status; + + cmd_set = rda_uart_read(port, RDA_UART_CMD_SET); + status = rda_uart_read(port, RDA_UART_STATUS); + if (cmd_set & RDA_UART_RTS) + mctrl |= TIOCM_RTS; + if (!(status & RDA_UART_CTS)) + mctrl |= TIOCM_CTS; + + return mctrl; +} + +static void rda_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u32 val; + + if (mctrl & TIOCM_RTS) { + val = rda_uart_read(port, RDA_UART_CMD_SET); + rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_SET); + } else { + /* Clear RTS to stop to receive. */ + val = rda_uart_read(port, RDA_UART_CMD_CLR); + rda_uart_write(port, (val | RDA_UART_RTS), RDA_UART_CMD_CLR); + } + + val = rda_uart_read(port, RDA_UART_CTRL); + + if (mctrl & TIOCM_LOOP) + val |= RDA_UART_LOOP_BACK_EN; + else + val &= ~RDA_UART_LOOP_BACK_EN; + + rda_uart_write(port, val, RDA_UART_CTRL); +} + +static void rda_uart_stop_tx(struct uart_port *port) +{ + u32 val; + + val = rda_uart_read(port, RDA_UART_IRQ_MASK); + val &= ~RDA_UART_TX_DATA_NEEDED; + rda_uart_write(port, val, RDA_UART_IRQ_MASK); + + val = rda_uart_read(port, RDA_UART_CMD_SET); + val |= RDA_UART_TX_FIFO_RESET; + rda_uart_write(port, val, RDA_UART_CMD_SET); +} + +static void rda_uart_stop_rx(struct uart_port *port) +{ + u32 val; + + val = rda_uart_read(port, RDA_UART_IRQ_MASK); + val &= ~(RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT); + rda_uart_write(port, val, RDA_UART_IRQ_MASK); + + /* Read Rx buffer before reset to avoid Rx timeout interrupt */ + val = rda_uart_read(port, RDA_UART_RXTX_BUFFER); + + val = rda_uart_read(port, RDA_UART_CMD_SET); + val |= RDA_UART_RX_FIFO_RESET; + rda_uart_write(port, val, RDA_UART_CMD_SET); +} + +static void rda_uart_start_tx(struct uart_port *port) +{ + u32 val; + + if (uart_tx_stopped(port)) { + rda_uart_stop_tx(port); + return; + } + + val = rda_uart_read(port, RDA_UART_IRQ_MASK); + val |= RDA_UART_TX_DATA_NEEDED; + rda_uart_write(port, val, RDA_UART_IRQ_MASK); +} + +static void rda_uart_change_baudrate(struct rda_uart_port *rda_port, + unsigned long baud) +{ + clk_set_rate(rda_port->clk, baud * 8); +} + +static void rda_uart_set_termios(struct uart_port *port, + struct ktermios *termios, + struct ktermios *old) +{ + struct rda_uart_port *rda_port = to_rda_uart_port(port); + unsigned long flags; + unsigned int ctrl, cmd_set, cmd_clr, triggers; + unsigned int baud; + u32 irq_mask; + + spin_lock_irqsave(&port->lock, flags); + + baud = uart_get_baud_rate(port, termios, old, 9600, port->uartclk / 4); + rda_uart_change_baudrate(rda_port, baud); + + ctrl = rda_uart_read(port, RDA_UART_CTRL); + cmd_set = rda_uart_read(port, RDA_UART_CMD_SET); + cmd_clr = rda_uart_read(port, RDA_UART_CMD_CLR); + + switch (termios->c_cflag & CSIZE) { + case CS5: + case CS6: + dev_warn(port->dev, "bit size not supported, using 7 bits\n"); + /* Fall through */ + case CS7: + ctrl &= ~RDA_UART_DBITS_8; + break; + default: + ctrl |= RDA_UART_DBITS_8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + ctrl |= RDA_UART_TX_SBITS_2; + else + ctrl &= ~RDA_UART_TX_SBITS_2; + + /* parity check */ + if (termios->c_cflag & PARENB) { + ctrl |= RDA_UART_PARITY_EN; + + /* Mark or Space parity */ + if (termios->c_cflag & CMSPAR) { + if (termios->c_cflag & PARODD) + ctrl |= RDA_UART_PARITY_MARK; + else + ctrl |= RDA_UART_PARITY_SPACE; + } else if (termios->c_cflag & PARODD) { + ctrl |= RDA_UART_PARITY_ODD; + } else { + ctrl |= RDA_UART_PARITY_EVEN; + } + } else { + ctrl &= ~RDA_UART_PARITY_EN; + } + + /* Hardware handshake (RTS/CTS) */ + if (termios->c_cflag & CRTSCTS) { + ctrl |= RDA_UART_FLOW_CNT_EN; + cmd_set |= RDA_UART_RTS; + } else { + ctrl &= ~RDA_UART_FLOW_CNT_EN; + cmd_clr |= RDA_UART_RTS; + } + + ctrl |= RDA_UART_ENABLE; + ctrl &= ~RDA_UART_DMA_EN; + + triggers = (RDA_UART_AFC_LEVEL(20) | RDA_UART_RX_TRIGGER(16)); + irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); + + rda_uart_write(port, triggers, RDA_UART_IRQ_TRIGGERS); + rda_uart_write(port, ctrl, RDA_UART_CTRL); + rda_uart_write(port, cmd_set, RDA_UART_CMD_SET); + rda_uart_write(port, cmd_clr, RDA_UART_CMD_CLR); + + rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK); + + /* Don't rewrite B0 */ + if (tty_termios_baud_rate(termios)) + tty_termios_encode_baud_rate(termios, baud, baud); + + /* update the per-port timeout */ + uart_update_timeout(port, termios->c_cflag, baud); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static void rda_uart_send_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->state->xmit; + unsigned int ch; + u32 val; + + if (uart_tx_stopped(port)) + return; + + if (port->x_char) { + while (!(rda_uart_read(port, RDA_UART_STATUS) & + RDA_UART_TX_FIFO_MASK)) + cpu_relax(); + + rda_uart_write(port, port->x_char, RDA_UART_RXTX_BUFFER); + port->icount.tx++; + port->x_char = 0; + } + + while (rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK) { + if (uart_circ_empty(xmit)) + break; + + ch = xmit->buf[xmit->tail]; + rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER); + 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)) { + /* Re-enable Tx FIFO interrupt */ + val = rda_uart_read(port, RDA_UART_IRQ_MASK); + val |= RDA_UART_TX_DATA_NEEDED; + rda_uart_write(port, val, RDA_UART_IRQ_MASK); + } +} + +static void rda_uart_receive_chars(struct uart_port *port) +{ + u32 status, val; + + status = rda_uart_read(port, RDA_UART_STATUS); + while ((status & RDA_UART_RX_FIFO_MASK)) { + char flag = TTY_NORMAL; + + if (status & RDA_UART_RX_PARITY_ERR) { + port->icount.parity++; + flag = TTY_PARITY; + } + + if (status & RDA_UART_RX_FRAMING_ERR) { + port->icount.frame++; + flag = TTY_FRAME; + } + + if (status & RDA_UART_RX_OVERFLOW_ERR) { + port->icount.overrun++; + flag = TTY_OVERRUN; + } + + val = rda_uart_read(port, RDA_UART_RXTX_BUFFER); + val &= 0xff; + + port->icount.rx++; + tty_insert_flip_char(&port->state->port, val, flag); + + status = rda_uart_read(port, RDA_UART_STATUS); + } + + spin_unlock(&port->lock); + tty_flip_buffer_push(&port->state->port); + spin_lock(&port->lock); +} + +static irqreturn_t rda_interrupt(int irq, void *dev_id) +{ + struct uart_port *port = dev_id; + unsigned long flags; + u32 val, irq_mask; + + spin_lock_irqsave(&port->lock, flags); + + /* Clear IRQ cause */ + val = rda_uart_read(port, RDA_UART_IRQ_CAUSE); + rda_uart_write(port, val, RDA_UART_IRQ_CAUSE); + + if (val & (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT)) + rda_uart_receive_chars(port); + + if (val & (RDA_UART_TX_DATA_NEEDED)) { + irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); + irq_mask &= ~RDA_UART_TX_DATA_NEEDED; + rda_uart_write(port, irq_mask, RDA_UART_IRQ_MASK); + + rda_uart_send_chars(port); + } + + spin_unlock_irqrestore(&port->lock, flags); + + return IRQ_HANDLED; +} + +static int rda_uart_startup(struct uart_port *port) +{ + unsigned long flags; + int ret; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); + spin_unlock_irqrestore(&port->lock, flags); + + ret = request_irq(port->irq, rda_interrupt, IRQF_NO_SUSPEND, + "rda-uart", port); + if (ret) + return ret; + + spin_lock_irqsave(&port->lock, flags); + + val = rda_uart_read(port, RDA_UART_CTRL); + val |= RDA_UART_ENABLE; + rda_uart_write(port, val, RDA_UART_CTRL); + + /* enable rx interrupt */ + val = rda_uart_read(port, RDA_UART_IRQ_MASK); + val |= (RDA_UART_RX_DATA_AVAILABLE | RDA_UART_RX_TIMEOUT); + rda_uart_write(port, val, RDA_UART_IRQ_MASK); + + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static void rda_uart_shutdown(struct uart_port *port) +{ + unsigned long flags; + u32 val; + + spin_lock_irqsave(&port->lock, flags); + + rda_uart_stop_tx(port); + rda_uart_stop_rx(port); + + val = rda_uart_read(port, RDA_UART_CTRL); + val &= ~RDA_UART_ENABLE; + rda_uart_write(port, val, RDA_UART_CTRL); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *rda_uart_type(struct uart_port *port) +{ + return (port->type == PORT_RDA) ? "rda-uart" : NULL; +} + +static int rda_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 void rda_uart_config_port(struct uart_port *port, int flags) +{ + unsigned long irq_flags; + + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_RDA; + rda_uart_request_port(port); + } + + spin_lock_irqsave(&port->lock, irq_flags); + + /* Clear mask, so no surprise interrupts. */ + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); + + /* Clear status register */ + rda_uart_write(port, 0, RDA_UART_STATUS); + + spin_unlock_irqrestore(&port->lock, irq_flags); +} + +static void rda_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 rda_uart_verify_port(struct uart_port *port, + struct serial_struct *ser) +{ + if (port->type != PORT_RDA) + return -EINVAL; + + if (port->irq != ser->irq) + return -EINVAL; + + return 0; +} + +static const struct uart_ops rda_uart_ops = { + .tx_empty = rda_uart_tx_empty, + .get_mctrl = rda_uart_get_mctrl, + .set_mctrl = rda_uart_set_mctrl, + .start_tx = rda_uart_start_tx, + .stop_tx = rda_uart_stop_tx, + .stop_rx = rda_uart_stop_rx, + .startup = rda_uart_startup, + .shutdown = rda_uart_shutdown, + .set_termios = rda_uart_set_termios, + .type = rda_uart_type, + .request_port = rda_uart_request_port, + .release_port = rda_uart_release_port, + .config_port = rda_uart_config_port, + .verify_port = rda_uart_verify_port, +}; + +#ifdef CONFIG_SERIAL_RDA_CONSOLE + +static void rda_console_putchar(struct uart_port *port, int ch) +{ + if (!port->membase) + return; + + while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK)) + cpu_relax(); + + rda_uart_write(port, ch, RDA_UART_RXTX_BUFFER); +} + +static void rda_uart_port_write(struct uart_port *port, const char *s, + u_int count) +{ + u32 old_irq_mask; + unsigned long flags; + int locked; + + local_irq_save(flags); + + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else { + spin_lock(&port->lock); + locked = 1; + } + + old_irq_mask = rda_uart_read(port, RDA_UART_IRQ_MASK); + rda_uart_write(port, 0, RDA_UART_IRQ_MASK); + + uart_console_write(port, s, count, rda_console_putchar); + + /* wait until all contents have been sent out */ + while (!(rda_uart_read(port, RDA_UART_STATUS) & RDA_UART_TX_FIFO_MASK)) + cpu_relax(); + + rda_uart_write(port, old_irq_mask, RDA_UART_IRQ_MASK); + + if (locked) + spin_unlock(&port->lock); + + local_irq_restore(flags); +} + +static void rda_uart_console_write(struct console *co, const char *s, + u_int count) +{ + struct rda_uart_port *rda_port; + + rda_port = rda_uart_ports[co->index]; + if (!rda_port) + return; + + rda_uart_port_write(&rda_port->port, s, count); +} + +static int rda_uart_console_setup(struct console *co, char *options) +{ + struct rda_uart_port *rda_port; + int baud = 921600; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index < 0 || co->index >= RDA_UART_PORT_NUM) + return -EINVAL; + + rda_port = rda_uart_ports[co->index]; + if (!rda_port || !rda_port->port.membase) + return -ENODEV; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(&rda_port->port, co, baud, parity, bits, flow); +} + +static struct console rda_uart_console = { + .name = RDA_UART_DEV_NAME, + .write = rda_uart_console_write, + .device = uart_console_device, + .setup = rda_uart_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &rda_uart_driver, +}; + +static int __init rda_uart_console_init(void) +{ + register_console(&rda_uart_console); + + return 0; +} +console_initcall(rda_uart_console_init); + +static void rda_uart_early_console_write(struct console *co, + const char *s, + u_int count) +{ + struct earlycon_device *dev = co->data; + + rda_uart_port_write(&dev->port, s, count); +} + +static int __init +rda_uart_early_console_setup(struct earlycon_device *device, const char *opt) +{ + if (!device->port.membase) + return -ENODEV; + + device->con->write = rda_uart_early_console_write; + + return 0; +} + +OF_EARLYCON_DECLARE(rda, "rda,8810pl-uart", + rda_uart_early_console_setup); + +#define RDA_UART_CONSOLE (&rda_uart_console) +#else +#define RDA_UART_CONSOLE NULL +#endif /* CONFIG_SERIAL_RDA_CONSOLE */ + +static struct uart_driver rda_uart_driver = { + .owner = THIS_MODULE, + .driver_name = "rda-uart", + .dev_name = RDA_UART_DEV_NAME, + .nr = RDA_UART_PORT_NUM, + .cons = RDA_UART_CONSOLE, +}; + +static const struct of_device_id rda_uart_dt_matches[] = { + { .compatible = "rda,8810pl-uart" }, + { } +}; +MODULE_DEVICE_TABLE(of, rda_uart_dt_matches); + +static int rda_uart_probe(struct platform_device *pdev) +{ + struct resource *res_mem; + struct rda_uart_port *rda_port; + int ret, irq; + + if (pdev->dev.of_node) + pdev->id = of_alias_get_id(pdev->dev.of_node, "serial"); + + if (pdev->id < 0 || pdev->id >= RDA_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 (rda_uart_ports[pdev->id]) { + dev_err(&pdev->dev, "port %d already allocated\n", pdev->id); + return -EBUSY; + } + + rda_port = devm_kzalloc(&pdev->dev, sizeof(*rda_port), GFP_KERNEL); + if (!rda_port) + return -ENOMEM; + + rda_port->clk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(rda_port->clk)) { + dev_err(&pdev->dev, "could not get clk\n"); + return PTR_ERR(rda_port->clk); + } + + rda_port->port.dev = &pdev->dev; + rda_port->port.regshift = 0; + rda_port->port.line = pdev->id; + rda_port->port.type = PORT_RDA; + rda_port->port.iotype = UPIO_MEM; + rda_port->port.mapbase = res_mem->start; + rda_port->port.irq = irq; + rda_port->port.uartclk = clk_get_rate(rda_port->clk); + if (rda_port->port.uartclk == 0) { + dev_err(&pdev->dev, "clock rate is zero\n"); + return -EINVAL; + } + rda_port->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP | + UPF_LOW_LATENCY; + rda_port->port.x_char = 0; + rda_port->port.fifosize = RDA_UART_TX_FIFO_SIZE; + rda_port->port.ops = &rda_uart_ops; + + rda_uart_ports[pdev->id] = rda_port; + platform_set_drvdata(pdev, rda_port); + + ret = uart_add_one_port(&rda_uart_driver, &rda_port->port); + if (ret) + rda_uart_ports[pdev->id] = NULL; + + return ret; +} + +static int rda_uart_remove(struct platform_device *pdev) +{ + struct rda_uart_port *rda_port = platform_get_drvdata(pdev); + + uart_remove_one_port(&rda_uart_driver, &rda_port->port); + rda_uart_ports[pdev->id] = NULL; + + return 0; +} + +static struct platform_driver rda_uart_platform_driver = { + .probe = rda_uart_probe, + .remove = rda_uart_remove, + .driver = { + .name = "rda-uart", + .of_match_table = rda_uart_dt_matches, + }, +}; + +static int __init rda_uart_init(void) +{ + int ret; + + ret = uart_register_driver(&rda_uart_driver); + if (ret) + return ret; + + ret = platform_driver_register(&rda_uart_platform_driver); + if (ret) + uart_unregister_driver(&rda_uart_driver); + + return ret; +} + +static void __init rda_uart_exit(void) +{ + platform_driver_unregister(&rda_uart_platform_driver); + uart_unregister_driver(&rda_uart_driver); +} + +module_init(rda_uart_init); +module_exit(rda_uart_exit); + +MODULE_AUTHOR("Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>"); +MODULE_DESCRIPTION("RDA8810PL serial device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index da1bd4bba8a9..83fd51607741 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1287,7 +1287,7 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, * Ask the core to calculate the divisor for us. */ - baud = uart_get_baud_rate(port, termios, old, 0, 115200*8); + baud = uart_get_baud_rate(port, termios, old, 0, 3000000); quot = s3c24xx_serial_getclk(ourport, baud, &clk, &clk_sel); if (baud == 38400 && (port->flags & UPF_SPD_MASK) == UPF_SPD_CUST) quot = port->custom_divisor; @@ -1365,11 +1365,14 @@ static void s3c24xx_serial_set_termios(struct uart_port *port, wr_regl(port, S3C2410_ULCON, ulcon); wr_regl(port, S3C2410_UBRDIV, quot); + port->status &= ~UPSTAT_AUTOCTS; + umcon = rd_regl(port, S3C2410_UMCON); if (termios->c_cflag & CRTSCTS) { umcon |= S3C2410_UMCOM_AFC; /* Disable RTS when RX FIFO contains 63 bytes */ umcon &= ~S3C2412_UMCON_AFC_8; + port->status = UPSTAT_AUTOCTS; } else { umcon &= ~S3C2410_UMCOM_AFC; } @@ -1691,6 +1694,42 @@ s3c24xx_serial_cpufreq_deregister(struct s3c24xx_uart_port *port) } #endif +static int s3c24xx_serial_enable_baudclk(struct s3c24xx_uart_port *ourport) +{ + struct device *dev = ourport->port.dev; + struct s3c24xx_uart_info *info = ourport->info; + char clk_name[MAX_CLK_NAME_LENGTH]; + unsigned int clk_sel; + struct clk *clk; + int clk_num; + int ret; + + clk_sel = ourport->cfg->clk_sel ? : info->def_clk_sel; + for (clk_num = 0; clk_num < info->num_clks; clk_num++) { + if (!(clk_sel & (1 << clk_num))) + continue; + + sprintf(clk_name, "clk_uart_baud%d", clk_num); + clk = clk_get(dev, clk_name); + if (IS_ERR(clk)) + continue; + + ret = clk_prepare_enable(clk); + if (ret) { + clk_put(clk); + continue; + } + + ourport->baudclk = clk; + ourport->baudclk_rate = clk_get_rate(clk); + s3c24xx_serial_setsource(&ourport->port, clk_num); + + return 0; + } + + return -EINVAL; +} + /* s3c24xx_serial_init_port * * initialise a single serial port from the platform device given @@ -1785,6 +1824,10 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport, goto err; } + ret = s3c24xx_serial_enable_baudclk(ourport); + if (ret) + pr_warn("uart: failed to enable baudclk\n"); + /* Keep all interrupts masked and cleared */ if (s3c24xx_serial_has_interrupt_mask(port)) { wr_regl(port, S3C64XX_UINTM, 0xf); @@ -1898,6 +1941,8 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) * and keeps the clock enabled in this case. */ clk_disable_unprepare(ourport->clk); + if (!IS_ERR(ourport->baudclk)) + clk_disable_unprepare(ourport->baudclk); ret = s3c24xx_serial_cpufreq_register(ourport); if (ret < 0) diff --git a/drivers/tty/serial/sc16is7xx.c b/drivers/tty/serial/sc16is7xx.c index 268098681856..a31db15cd7c0 100644 --- a/drivers/tty/serial/sc16is7xx.c +++ b/drivers/tty/serial/sc16is7xx.c @@ -1187,9 +1187,7 @@ static int sc16is7xx_probe(struct device *dev, return PTR_ERR(regmap); /* Alloc port structure */ - s = devm_kzalloc(dev, sizeof(*s) + - sizeof(struct sc16is7xx_one) * devtype->nr_uart, - GFP_KERNEL); + s = devm_kzalloc(dev, struct_size(s, p, devtype->nr_uart), GFP_KERNEL); if (!s) { dev_err(dev, "Error allocating port structure\n"); return -ENOMEM; @@ -1509,7 +1507,7 @@ static int __init sc16is7xx_init(void) ret = i2c_add_driver(&sc16is7xx_i2c_uart_driver); if (ret < 0) { pr_err("failed to init sc16is7xx i2c --> %d\n", ret); - return ret; + goto err_i2c; } #endif @@ -1517,10 +1515,20 @@ static int __init sc16is7xx_init(void) ret = spi_register_driver(&sc16is7xx_spi_uart_driver); if (ret < 0) { pr_err("failed to init sc16is7xx spi --> %d\n", ret); - return ret; + goto err_spi; } #endif return ret; + +#ifdef CONFIG_SERIAL_SC16IS7XX_SPI +err_spi: +#endif +#ifdef CONFIG_SERIAL_SC16IS7XX_I2C + i2c_del_driver(&sc16is7xx_i2c_uart_driver); +err_i2c: +#endif + uart_unregister_driver(&sc16is7xx_uart); + return ret; } module_init(sc16is7xx_init); diff --git a/drivers/tty/serial/sccnxp.c b/drivers/tty/serial/sccnxp.c index 339befdd2f4d..68a24a14f6b7 100644 --- a/drivers/tty/serial/sccnxp.c +++ b/drivers/tty/serial/sccnxp.c @@ -12,6 +12,7 @@ #endif #include <linux/clk.h> +#include <linux/delay.h> #include <linux/err.h> #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -47,7 +48,6 @@ # define MR2_STOP1 (7 << 0) # define MR2_STOP2 (0xf << 0) #define SCCNXP_SR_REG (0x01) -#define SCCNXP_CSR_REG SCCNXP_SR_REG # define SR_RXRDY (1 << 0) # define SR_FULL (1 << 1) # define SR_TXRDY (1 << 2) @@ -56,6 +56,8 @@ # define SR_PE (1 << 5) # define SR_FE (1 << 6) # define SR_BRK (1 << 7) +#define SCCNXP_CSR_REG (SCCNXP_SR_REG) +# define CSR_TIMER_MODE (0x0d) #define SCCNXP_CR_REG (0x02) # define CR_RX_ENABLE (1 << 0) # define CR_RX_DISABLE (1 << 1) @@ -82,9 +84,12 @@ # define IMR_RXRDY (1 << 1) # define ISR_TXRDY(x) (1 << ((x * 4) + 0)) # define ISR_RXRDY(x) (1 << ((x * 4) + 1)) +#define SCCNXP_CTPU_REG (0x06) +#define SCCNXP_CTPL_REG (0x07) #define SCCNXP_IPR_REG (0x0d) #define SCCNXP_OPCR_REG SCCNXP_IPR_REG #define SCCNXP_SOP_REG (0x0e) +#define SCCNXP_START_COUNTER_REG SCCNXP_SOP_REG #define SCCNXP_ROP_REG (0x0f) /* Route helpers */ @@ -103,6 +108,8 @@ struct sccnxp_chip { unsigned long freq_max; unsigned int flags; unsigned int fifosize; + /* Time between read/write cycles */ + unsigned int trwd; }; struct sccnxp_port { @@ -137,6 +144,7 @@ static const struct sccnxp_chip sc2681 = { .freq_max = 4000000, .flags = SCCNXP_HAVE_IO, .fifosize = 3, + .trwd = 200, }; static const struct sccnxp_chip sc2691 = { @@ -147,6 +155,7 @@ static const struct sccnxp_chip sc2691 = { .freq_max = 4000000, .flags = 0, .fifosize = 3, + .trwd = 150, }; static const struct sccnxp_chip sc2692 = { @@ -157,6 +166,7 @@ static const struct sccnxp_chip sc2692 = { .freq_max = 4000000, .flags = SCCNXP_HAVE_IO, .fifosize = 3, + .trwd = 30, }; static const struct sccnxp_chip sc2891 = { @@ -167,6 +177,7 @@ static const struct sccnxp_chip sc2891 = { .freq_max = 8000000, .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, .fifosize = 16, + .trwd = 27, }; static const struct sccnxp_chip sc2892 = { @@ -177,6 +188,7 @@ static const struct sccnxp_chip sc2892 = { .freq_max = 8000000, .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, .fifosize = 16, + .trwd = 17, }; static const struct sccnxp_chip sc28202 = { @@ -187,6 +199,7 @@ static const struct sccnxp_chip sc28202 = { .freq_max = 50000000, .flags = SCCNXP_HAVE_IO | SCCNXP_HAVE_MR0, .fifosize = 256, + .trwd = 10, }; static const struct sccnxp_chip sc68681 = { @@ -197,6 +210,7 @@ static const struct sccnxp_chip sc68681 = { .freq_max = 4000000, .flags = SCCNXP_HAVE_IO, .fifosize = 3, + .trwd = 200, }; static const struct sccnxp_chip sc68692 = { @@ -207,24 +221,36 @@ static const struct sccnxp_chip sc68692 = { .freq_max = 4000000, .flags = SCCNXP_HAVE_IO, .fifosize = 3, + .trwd = 200, }; -static inline u8 sccnxp_read(struct uart_port *port, u8 reg) +static u8 sccnxp_read(struct uart_port *port, u8 reg) { - return readb(port->membase + (reg << port->regshift)); + struct sccnxp_port *s = dev_get_drvdata(port->dev); + u8 ret; + + ret = readb(port->membase + (reg << port->regshift)); + + ndelay(s->chip->trwd); + + return ret; } -static inline void sccnxp_write(struct uart_port *port, u8 reg, u8 v) +static void sccnxp_write(struct uart_port *port, u8 reg, u8 v) { + struct sccnxp_port *s = dev_get_drvdata(port->dev); + writeb(v, port->membase + (reg << port->regshift)); + + ndelay(s->chip->trwd); } -static inline u8 sccnxp_port_read(struct uart_port *port, u8 reg) +static u8 sccnxp_port_read(struct uart_port *port, u8 reg) { return sccnxp_read(port, (port->line << 3) + reg); } -static inline void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) +static void sccnxp_port_write(struct uart_port *port, u8 reg, u8 v) { sccnxp_write(port, (port->line << 3) + reg, v); } @@ -233,7 +259,7 @@ static int sccnxp_update_best_err(int a, int b, int *besterr) { int err = abs(a - b); - if ((*besterr < 0) || (*besterr > err)) { + if (*besterr > err) { *besterr = err; return 0; } @@ -281,10 +307,22 @@ static const struct { static int sccnxp_set_baud(struct uart_port *port, int baud) { struct sccnxp_port *s = dev_get_drvdata(port->dev); - int div_std, tmp_baud, bestbaud = baud, besterr = -1; + int div_std, tmp_baud, bestbaud = INT_MAX, besterr = INT_MAX; struct sccnxp_chip *chip = s->chip; u8 i, acr = 0, csr = 0, mr0 = 0; + /* Find divisor to load to the timer preset registers */ + div_std = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * baud); + if ((div_std >= 2) && (div_std <= 0xffff)) { + bestbaud = DIV_ROUND_CLOSEST(port->uartclk, 2 * 16 * div_std); + sccnxp_update_best_err(baud, bestbaud, &besterr); + csr = CSR_TIMER_MODE; + sccnxp_port_write(port, SCCNXP_CTPU_REG, div_std >> 8); + sccnxp_port_write(port, SCCNXP_CTPL_REG, div_std); + /* Issue start timer/counter command */ + sccnxp_port_read(port, SCCNXP_START_COUNTER_REG); + } + /* Find best baud from table */ for (i = 0; baud_std[i].baud && besterr; i++) { if (baud_std[i].mr0 && !(chip->flags & SCCNXP_HAVE_MR0)) diff --git a/drivers/tty/serial/serial-tegra.c b/drivers/tty/serial/serial-tegra.c index af2a29cfbbe9..d5269aaaf9b2 100644 --- a/drivers/tty/serial/serial-tegra.c +++ b/drivers/tty/serial/serial-tegra.c @@ -746,7 +746,7 @@ static void tegra_uart_stop_rx(struct uart_port *u) if (!tup->rx_in_progress) return; - tegra_uart_wait_sym_time(tup, 1); /* wait a character interval */ + tegra_uart_wait_sym_time(tup, 1); /* wait one character interval */ ier = tup->ier_shadow; ier &= ~(UART_IER_RDI | UART_IER_RLSI | UART_IER_RTOIE | @@ -887,7 +887,7 @@ static int tegra_uart_hw_init(struct tegra_uart_port *tup) * * EORD is different interrupt than RX_TIMEOUT - RX_TIMEOUT occurs when * the DATA is sitting in the FIFO and couldn't be transferred to the - * DMA as the DMA size alignment(4 bytes) is not met. EORD will be + * DMA as the DMA size alignment (4 bytes) is not met. EORD will be * triggered when there is a pause of the incomming data stream for 4 * characters long. * @@ -1079,7 +1079,7 @@ static void tegra_uart_set_termios(struct uart_port *u, if (tup->rts_active) set_rts(tup, false); - /* Clear all interrupts as configuration is going to be change */ + /* Clear all interrupts as configuration is going to be changed */ tegra_uart_write(tup, tup->ier_shadow | UART_IER_RDI, UART_IER); tegra_uart_read(tup, UART_IER); tegra_uart_write(tup, 0, UART_IER); @@ -1165,10 +1165,10 @@ static void tegra_uart_set_termios(struct uart_port *u, /* update the port timeout based on new settings */ uart_update_timeout(u, termios->c_cflag, baud); - /* Make sure all write has completed */ + /* Make sure all writes have completed */ tegra_uart_read(tup, UART_IER); - /* Reenable interrupt */ + /* Re-enable interrupt */ tegra_uart_write(tup, tup->ier_shadow, UART_IER); tegra_uart_read(tup, UART_IER); diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index c439a5a1e6c0..351843f847c0 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -130,6 +130,9 @@ static void uart_start(struct tty_struct *tty) struct uart_port *port; unsigned long flags; + if (!state) + return; + port = uart_port_lock(state, flags); __uart_start(tty); uart_port_unlock(port, flags); @@ -205,10 +208,15 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state, if (!state->xmit.buf) { state->xmit.buf = (unsigned char *) page; uart_circ_clear(&state->xmit); + uart_port_unlock(uport, flags); } else { + uart_port_unlock(uport, flags); + /* + * Do not free() the page under the port lock, see + * uart_shutdown(). + */ free_page(page); } - uart_port_unlock(uport, flags); retval = uport->ops->startup(uport); if (retval == 0) { @@ -268,6 +276,7 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) struct uart_port *uport = uart_port_check(state); struct tty_port *port = &state->port; unsigned long flags = 0; + char *xmit_buf = NULL; /* * Set the TTY IO error marker @@ -298,14 +307,18 @@ static void uart_shutdown(struct tty_struct *tty, struct uart_state *state) tty_port_set_suspended(port, 0); /* - * Free the transmit buffer page. + * Do not free() the transmit buffer page under the port lock since + * this can create various circular locking scenarios. For instance, + * console driver may need to allocate/free a debug object, which + * can endup in printk() recursion. */ uart_port_lock(state, flags); - if (state->xmit.buf) { - free_page((unsigned long)state->xmit.buf); - state->xmit.buf = NULL; - } + xmit_buf = state->xmit.buf; + state->xmit.buf = NULL; uart_port_unlock(uport, flags); + + if (xmit_buf) + free_page((unsigned long)xmit_buf); } /** @@ -540,10 +553,12 @@ static int uart_put_char(struct tty_struct *tty, unsigned char c) int ret = 0; circ = &state->xmit; - if (!circ->buf) + port = uart_port_lock(state, flags); + if (!circ->buf) { + uart_port_unlock(port, flags); return 0; + } - port = uart_port_lock(state, flags); if (port && uart_circ_chars_free(circ) != 0) { circ->buf[circ->head] = c; circ->head = (circ->head + 1) & (UART_XMIT_SIZE - 1); @@ -576,11 +591,13 @@ static int uart_write(struct tty_struct *tty, return -EL3HLT; } + port = uart_port_lock(state, flags); circ = &state->xmit; - if (!circ->buf) + if (!circ->buf) { + uart_port_unlock(port, flags); return 0; + } - port = uart_port_lock(state, flags); while (port) { c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); if (count < c) @@ -713,6 +730,9 @@ static void uart_unthrottle(struct tty_struct *tty) upstat_t mask = UPSTAT_SYNC_FIFO; struct uart_port *port; + if (!state) + return; + port = uart_port_ref(state); if (!port) return; @@ -2824,7 +2844,7 @@ int uart_add_one_port(struct uart_driver *drv, struct uart_port *uport) */ tty_dev = tty_port_register_device_attr_serdev(port, drv->tty_driver, uport->line, uport->dev, port, uport->tty_groups); - if (likely(!IS_ERR(tty_dev))) { + if (!IS_ERR(tty_dev)) { device_set_wakeup_capable(tty_dev, 1); } else { dev_err(uport->dev, "Cannot register tty device on line %d\n", diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index cc56cb3b3eca..3cd139752d3f 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -838,19 +838,9 @@ static void sci_transmit_chars(struct uart_port *port) if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); - if (uart_circ_empty(xmit)) { + if (uart_circ_empty(xmit)) sci_stop_tx(port); - } else { - ctrl = serial_port_in(port, SCSCR); - - if (port->type != PORT_SCI) { - serial_port_in(port, SCxSR); /* Dummy read */ - sci_clear_SCxSR(port, SCxSR_TDxE_CLEAR(port)); - } - ctrl |= SCSCR_TIE; - serial_port_out(port, SCSCR, ctrl); - } } /* On SH3, SCIF may read end-of-break as a space->mark char */ @@ -1243,12 +1233,22 @@ static int sci_dma_rx_find_active(struct sci_port *s) return -1; } -static void sci_rx_dma_release(struct sci_port *s) +static void sci_dma_rx_chan_invalidate(struct sci_port *s) +{ + unsigned int i; + + s->chan_rx = NULL; + for (i = 0; i < ARRAY_SIZE(s->cookie_rx); i++) + s->cookie_rx[i] = -EINVAL; + s->active_rx = 0; +} + +static void sci_dma_rx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_rx_saved; - s->chan_rx_saved = s->chan_rx = NULL; - s->cookie_rx[0] = s->cookie_rx[1] = -EINVAL; + s->chan_rx_saved = NULL; + sci_dma_rx_chan_invalidate(s); dmaengine_terminate_sync(chan); dma_free_coherent(chan->device->dev, s->buf_len_rx * 2, s->rx_buf[0], sg_dma_address(&s->sg_rx[0])); @@ -1264,6 +1264,20 @@ static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec) hrtimer_start(hrt, t, HRTIMER_MODE_REL); } +static void sci_dma_rx_reenable_irq(struct sci_port *s) +{ + struct uart_port *port = &s->port; + u16 scr; + + /* Direct new serial port interrupts back to CPU */ + scr = serial_port_in(port, SCSCR); + if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { + scr &= ~SCSCR_RDRQE; + enable_irq(s->irqs[SCIx_RXI_IRQ]); + } + serial_port_out(port, SCSCR, scr | SCSCR_RIE); +} + static void sci_dma_rx_complete(void *arg) { struct sci_port *s = arg; @@ -1313,12 +1327,13 @@ fail: dev_warn(port->dev, "Failed submitting Rx DMA descriptor\n"); /* Switch to PIO */ spin_lock_irqsave(&port->lock, flags); - s->chan_rx = NULL; - sci_start_rx(port); + dmaengine_terminate_async(chan); + sci_dma_rx_chan_invalidate(s); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); } -static void sci_tx_dma_release(struct sci_port *s) +static void sci_dma_tx_release(struct sci_port *s) { struct dma_chan *chan = s->chan_tx_saved; @@ -1331,7 +1346,7 @@ static void sci_tx_dma_release(struct sci_port *s) dma_release_channel(chan); } -static void sci_submit_rx(struct sci_port *s) +static int sci_dma_rx_submit(struct sci_port *s, bool port_lock_held) { struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; @@ -1359,22 +1374,22 @@ static void sci_submit_rx(struct sci_port *s) s->active_rx = s->cookie_rx[0]; dma_async_issue_pending(chan); - return; + return 0; fail: + /* Switch to PIO */ + if (!port_lock_held) + spin_lock_irqsave(&port->lock, flags); if (i) dmaengine_terminate_async(chan); - for (i = 0; i < 2; i++) - s->cookie_rx[i] = -EINVAL; - s->active_rx = -EINVAL; - /* Switch to PIO */ - spin_lock_irqsave(&port->lock, flags); - s->chan_rx = NULL; + sci_dma_rx_chan_invalidate(s); sci_start_rx(port); - spin_unlock_irqrestore(&port->lock, flags); + if (!port_lock_held) + spin_unlock_irqrestore(&port->lock, flags); + return -EAGAIN; } -static void work_fn_tx(struct work_struct *work) +static void sci_dma_tx_work_fn(struct work_struct *work) { struct sci_port *s = container_of(work, struct sci_port, work_tx); struct dma_async_tx_descriptor *desc; @@ -1433,7 +1448,7 @@ switch_to_pio: return; } -static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) +static enum hrtimer_restart sci_dma_rx_timer_fn(struct hrtimer *t) { struct sci_port *s = container_of(t, struct sci_port, rx_timer); struct dma_chan *chan = s->chan_rx; @@ -1443,7 +1458,6 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) unsigned long flags; unsigned int read; int active, count; - u16 scr; dev_dbg(port->dev, "DMA Rx timed out\n"); @@ -1491,15 +1505,9 @@ static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) } if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s); + sci_dma_rx_submit(s, true); - /* Direct new serial port interrupts back to CPU */ - scr = serial_port_in(port, SCSCR); - if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) { - scr &= ~SCSCR_RDRQE; - enable_irq(s->irqs[SCIx_RXI_IRQ]); - } - serial_port_out(port, SCSCR, scr | SCSCR_RIE); + sci_dma_rx_reenable_irq(s); spin_unlock_irqrestore(&port->lock, flags); @@ -1577,7 +1585,7 @@ static void sci_request_dma(struct uart_port *port) __func__, UART_XMIT_SIZE, port->state->xmit.buf, &s->tx_dma_addr); - INIT_WORK(&s->work_tx, work_fn_tx); + INIT_WORK(&s->work_tx, sci_dma_tx_work_fn); s->chan_tx_saved = s->chan_tx = chan; } } @@ -1612,12 +1620,12 @@ static void sci_request_dma(struct uart_port *port) } hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); - s->rx_timer.function = rx_timer_fn; + s->rx_timer.function = sci_dma_rx_timer_fn; s->chan_rx_saved = s->chan_rx = chan; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) - sci_submit_rx(s); + sci_dma_rx_submit(s, false); } } @@ -1626,9 +1634,9 @@ static void sci_free_dma(struct uart_port *port) struct sci_port *s = to_sci_port(port); if (s->chan_tx_saved) - sci_tx_dma_release(s); + sci_dma_tx_release(s); if (s->chan_rx_saved) - sci_rx_dma_release(s); + sci_dma_rx_release(s); } static void sci_flush_buffer(struct uart_port *port) @@ -1666,8 +1674,10 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) disable_irq_nosync(irq); scr |= SCSCR_RDRQE; } else { + if (sci_dma_rx_submit(s, false) < 0) + goto handle_pio; + scr &= ~SCSCR_RIE; - sci_submit_rx(s); } serial_port_out(port, SCSCR, scr); /* Clear current interrupt */ @@ -1679,6 +1689,8 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) return IRQ_HANDLED; } + +handle_pio: #endif if (s->rx_trigger > 1 && s->rx_fifo_timeout > 0) { @@ -1693,7 +1705,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) * of whether the I_IXOFF is set, otherwise, how is the interrupt * to be disabled? */ - sci_receive_chars(ptr); + sci_receive_chars(port); return IRQ_HANDLED; } @@ -1749,7 +1761,7 @@ static irqreturn_t sci_er_interrupt(int irq, void *ptr) } else { sci_handle_fifo_overrun(port); if (!s->chan_rx) - sci_receive_chars(ptr); + sci_receive_chars(port); } sci_clear_SCxSR(port, SCxSR_ERROR_CLEAR(port)); @@ -1914,7 +1926,7 @@ out_nomem: static void sci_free_irq(struct sci_port *port) { - int i; + int i, j; /* * Intentionally in reverse order so we iterate over the muxed @@ -1930,6 +1942,13 @@ static void sci_free_irq(struct sci_port *port) if (unlikely(irq < 0)) continue; + /* Check if already freed (irq was muxed) */ + for (j = 0; j < i; j++) + if (port->irqs[j] == irq) + j = i + 1; + if (j > i) + continue; + free_irq(port->irqs[i], port); kfree(port->irqstr[i]); @@ -2493,14 +2512,16 @@ done: * center of the last stop bit in sampling clocks. */ int last_stop = bits * 2 - 1; - int deviation = min_err * srr * last_stop / 2 / baud; + int deviation = DIV_ROUND_CLOSEST(min_err * last_stop * + (int)(srr + 1), + 2 * (int)baud); if (abs(deviation) >= 2) { /* At least two sampling clocks off at the * last stop bit; we can increase the error * margin by shifting the sampling point. */ - int shift = min(-8, max(7, deviation / 2)); + int shift = clamp(deviation / 2, -8, 7); hssrr |= (shift << HSCIF_SRHP_SHIFT) & HSCIF_SRHP_MASK; diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c index 4287ca305b6b..1891a45ac05d 100644 --- a/drivers/tty/serial/sprd_serial.c +++ b/drivers/tty/serial/sprd_serial.c @@ -371,7 +371,7 @@ static void sprd_set_termios(struct uart_port *port, /* ask the core to calculate the divisor for us */ baud = uart_get_baud_rate(port, termios, old, 0, SPRD_BAUD_IO_LIMIT); - quot = (unsigned int)((port->uartclk + baud / 2) / baud); + quot = port->uartclk / baud; /* set data length */ switch (termios->c_cflag & CSIZE) { diff --git a/drivers/tty/serial/suncore.c b/drivers/tty/serial/suncore.c index 990376576970..2491551c293e 100644 --- a/drivers/tty/serial/suncore.c +++ b/drivers/tty/serial/suncore.c @@ -89,14 +89,14 @@ void sunserial_console_termios(struct console *con, struct device_node *uart_dp) int baud, bits, stop, cflag; char parity; - if (!strcmp(uart_dp->name, "rsc") || - !strcmp(uart_dp->name, "rsc-console") || - !strcmp(uart_dp->name, "rsc-control")) { + if (of_node_name_eq(uart_dp, "rsc") || + of_node_name_eq(uart_dp, "rsc-console") || + of_node_name_eq(uart_dp, "rsc-control")) { mode = of_get_property(uart_dp, "ssp-console-modes", NULL); if (!mode) mode = "115200,8,n,1,-"; - } else if (!strcmp(uart_dp->name, "lom-console")) { + } else if (of_node_name_eq(uart_dp, "lom-console")) { mode = "9600,8,n,1,-"; } else { struct device_node *dp; diff --git a/drivers/tty/serial/sunsu.c b/drivers/tty/serial/sunsu.c index 3e77475668c0..4db6aaa330b2 100644 --- a/drivers/tty/serial/sunsu.c +++ b/drivers/tty/serial/sunsu.c @@ -1503,8 +1503,8 @@ static int su_probe(struct platform_device *op) up->port.ops = &sunsu_pops; ignore_line = false; - if (!strcmp(dp->name, "rsc-console") || - !strcmp(dp->name, "lom-console")) + if (of_node_name_eq(dp, "rsc-console") || + of_node_name_eq(dp, "lom-console")) ignore_line = true; sunserial_console_match(SUNSU_CONSOLE(), dp, diff --git a/drivers/tty/serial/tegra-tcu.c b/drivers/tty/serial/tegra-tcu.c new file mode 100644 index 000000000000..aaf8748a6147 --- /dev/null +++ b/drivers/tty/serial/tegra-tcu.c @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved. + */ + +#include <linux/console.h> +#include <linux/mailbox_client.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/serial.h> +#include <linux/serial_core.h> +#include <linux/slab.h> +#include <linux/tty.h> +#include <linux/tty_flip.h> + +#define TCU_MBOX_BYTE(i, x) ((x) << (i * 8)) +#define TCU_MBOX_BYTE_V(x, i) (((x) >> (i * 8)) & 0xff) +#define TCU_MBOX_NUM_BYTES(x) ((x) << 24) +#define TCU_MBOX_NUM_BYTES_V(x) (((x) >> 24) & 0x3) + +struct tegra_tcu { + struct uart_driver driver; +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + struct console console; +#endif + struct uart_port port; + + struct mbox_client tx_client, rx_client; + struct mbox_chan *tx, *rx; +}; + +static unsigned int tegra_tcu_uart_tx_empty(struct uart_port *port) +{ + return TIOCSER_TEMT; +} + +static void tegra_tcu_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ +} + +static unsigned int tegra_tcu_uart_get_mctrl(struct uart_port *port) +{ + return 0; +} + +static void tegra_tcu_uart_stop_tx(struct uart_port *port) +{ +} + +static void tegra_tcu_write_one(struct tegra_tcu *tcu, u32 value, + unsigned int count) +{ + void *msg; + + value |= TCU_MBOX_NUM_BYTES(count); + msg = (void *)(unsigned long)value; + mbox_send_message(tcu->tx, msg); + mbox_flush(tcu->tx, 1000); +} + +static void tegra_tcu_write(struct tegra_tcu *tcu, const char *s, + unsigned int count) +{ + unsigned int written = 0, i = 0; + bool insert_nl = false; + u32 value = 0; + + while (i < count) { + if (insert_nl) { + value |= TCU_MBOX_BYTE(written++, '\n'); + insert_nl = false; + i++; + } else if (s[i] == '\n') { + value |= TCU_MBOX_BYTE(written++, '\r'); + insert_nl = true; + } else { + value |= TCU_MBOX_BYTE(written++, s[i++]); + } + + if (written == 3) { + tegra_tcu_write_one(tcu, value, 3); + value = written = 0; + } + } + + if (written) + tegra_tcu_write_one(tcu, value, written); +} + +static void tegra_tcu_uart_start_tx(struct uart_port *port) +{ + struct tegra_tcu *tcu = port->private_data; + struct circ_buf *xmit = &port->state->xmit; + unsigned long count; + + for (;;) { + count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE); + if (!count) + break; + + tegra_tcu_write(tcu, &xmit->buf[xmit->tail], count); + xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); + } + + uart_write_wakeup(port); +} + +static void tegra_tcu_uart_stop_rx(struct uart_port *port) +{ +} + +static void tegra_tcu_uart_break_ctl(struct uart_port *port, int ctl) +{ +} + +static int tegra_tcu_uart_startup(struct uart_port *port) +{ + return 0; +} + +static void tegra_tcu_uart_shutdown(struct uart_port *port) +{ +} + +static void tegra_tcu_uart_set_termios(struct uart_port *port, + struct ktermios *new, + struct ktermios *old) +{ +} + +static const struct uart_ops tegra_tcu_uart_ops = { + .tx_empty = tegra_tcu_uart_tx_empty, + .set_mctrl = tegra_tcu_uart_set_mctrl, + .get_mctrl = tegra_tcu_uart_get_mctrl, + .stop_tx = tegra_tcu_uart_stop_tx, + .start_tx = tegra_tcu_uart_start_tx, + .stop_rx = tegra_tcu_uart_stop_rx, + .break_ctl = tegra_tcu_uart_break_ctl, + .startup = tegra_tcu_uart_startup, + .shutdown = tegra_tcu_uart_shutdown, + .set_termios = tegra_tcu_uart_set_termios, +}; + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) +static void tegra_tcu_console_write(struct console *cons, const char *s, + unsigned int count) +{ + struct tegra_tcu *tcu = container_of(cons, struct tegra_tcu, console); + + tegra_tcu_write(tcu, s, count); +} + +static int tegra_tcu_console_setup(struct console *cons, char *options) +{ + return 0; +} +#endif + +static void tegra_tcu_receive(struct mbox_client *cl, void *msg) +{ + struct tegra_tcu *tcu = container_of(cl, struct tegra_tcu, rx_client); + struct tty_port *port = &tcu->port.state->port; + u32 value = (u32)(unsigned long)msg; + unsigned int num_bytes, i; + + num_bytes = TCU_MBOX_NUM_BYTES_V(value); + + for (i = 0; i < num_bytes; i++) + tty_insert_flip_char(port, TCU_MBOX_BYTE_V(value, i), + TTY_NORMAL); + + tty_flip_buffer_push(port); +} + +static int tegra_tcu_probe(struct platform_device *pdev) +{ + struct uart_port *port; + struct tegra_tcu *tcu; + int err; + + tcu = devm_kzalloc(&pdev->dev, sizeof(*tcu), GFP_KERNEL); + if (!tcu) + return -ENOMEM; + + tcu->tx_client.dev = &pdev->dev; + tcu->rx_client.dev = &pdev->dev; + tcu->rx_client.rx_callback = tegra_tcu_receive; + + tcu->tx = mbox_request_channel_byname(&tcu->tx_client, "tx"); + if (IS_ERR(tcu->tx)) { + err = PTR_ERR(tcu->tx); + dev_err(&pdev->dev, "failed to get tx mailbox: %d\n", err); + return err; + } + + tcu->rx = mbox_request_channel_byname(&tcu->rx_client, "rx"); + if (IS_ERR(tcu->rx)) { + err = PTR_ERR(tcu->rx); + dev_err(&pdev->dev, "failed to get rx mailbox: %d\n", err); + goto free_tx; + } + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + /* setup the console */ + strcpy(tcu->console.name, "ttyTCU"); + tcu->console.device = uart_console_device; + tcu->console.flags = CON_PRINTBUFFER | CON_ANYTIME; + tcu->console.index = -1; + tcu->console.write = tegra_tcu_console_write; + tcu->console.setup = tegra_tcu_console_setup; + tcu->console.data = &tcu->driver; +#endif + + /* setup the driver */ + tcu->driver.owner = THIS_MODULE; + tcu->driver.driver_name = "tegra-tcu"; + tcu->driver.dev_name = "ttyTCU"; +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + tcu->driver.cons = &tcu->console; +#endif + tcu->driver.nr = 1; + + err = uart_register_driver(&tcu->driver); + if (err) { + dev_err(&pdev->dev, "failed to register UART driver: %d\n", + err); + goto free_rx; + } + + /* setup the port */ + port = &tcu->port; + spin_lock_init(&port->lock); + port->dev = &pdev->dev; + port->type = PORT_TEGRA_TCU; + port->ops = &tegra_tcu_uart_ops; + port->fifosize = 1; + port->iotype = UPIO_MEM; + port->flags = UPF_BOOT_AUTOCONF; + port->private_data = tcu; + + err = uart_add_one_port(&tcu->driver, port); + if (err) { + dev_err(&pdev->dev, "failed to add UART port: %d\n", err); + goto unregister_uart; + } + + platform_set_drvdata(pdev, tcu); +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + register_console(&tcu->console); +#endif + + return 0; + +unregister_uart: + uart_unregister_driver(&tcu->driver); +free_rx: + mbox_free_channel(tcu->rx); +free_tx: + mbox_free_channel(tcu->tx); + + return err; +} + +static int tegra_tcu_remove(struct platform_device *pdev) +{ + struct tegra_tcu *tcu = platform_get_drvdata(pdev); + +#if IS_ENABLED(CONFIG_SERIAL_TEGRA_TCU_CONSOLE) + unregister_console(&tcu->console); +#endif + uart_remove_one_port(&tcu->driver, &tcu->port); + uart_unregister_driver(&tcu->driver); + mbox_free_channel(tcu->rx); + mbox_free_channel(tcu->tx); + + return 0; +} + +static const struct of_device_id tegra_tcu_match[] = { + { .compatible = "nvidia,tegra194-tcu" }, + { } +}; + +static struct platform_driver tegra_tcu_driver = { + .driver = { + .name = "tegra-tcu", + .of_match_table = tegra_tcu_match, + }, + .probe = tegra_tcu_probe, + .remove = tegra_tcu_remove, +}; +module_platform_driver(tegra_tcu_driver); + +MODULE_AUTHOR("Mikko Perttunen <mperttunen@nvidia.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("NVIDIA Tegra Combined UART driver"); diff --git a/drivers/tty/serial/uartlite.c b/drivers/tty/serial/uartlite.c index f0344adc86db..b8b912b5a8b9 100644 --- a/drivers/tty/serial/uartlite.c +++ b/drivers/tty/serial/uartlite.c @@ -22,6 +22,7 @@ #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/clk.h> +#include <linux/pm_runtime.h> #define ULITE_NAME "ttyUL" #define ULITE_MAJOR 204 @@ -54,6 +55,7 @@ #define ULITE_CONTROL_RST_TX 0x01 #define ULITE_CONTROL_RST_RX 0x02 #define ULITE_CONTROL_IE 0x10 +#define UART_AUTOSUSPEND_TIMEOUT 3000 /* Static pointer to console port */ #ifdef CONFIG_SERIAL_UARTLITE_CONSOLE @@ -63,6 +65,7 @@ static struct uart_port *console_port; struct uartlite_data { const struct uartlite_reg_ops *reg_ops; struct clk *clk; + struct uart_driver *ulite_uart_driver; }; struct uartlite_reg_ops { @@ -390,12 +393,12 @@ static int ulite_verify_port(struct uart_port *port, struct serial_struct *ser) static void ulite_pm(struct uart_port *port, unsigned int state, unsigned int oldstate) { - struct uartlite_data *pdata = port->private_data; - - if (!state) - clk_enable(pdata->clk); - else - clk_disable(pdata->clk); + if (!state) { + pm_runtime_get_sync(port->dev); + } else { + pm_runtime_mark_last_busy(port->dev); + pm_runtime_put_autosuspend(port->dev); + } } #ifdef CONFIG_CONSOLE_POLL @@ -694,7 +697,9 @@ static int ulite_release(struct device *dev) int rc = 0; if (port) { - rc = uart_remove_one_port(&ulite_uart_driver, port); + struct uartlite_data *pdata = port->private_data; + + rc = uart_remove_one_port(pdata->ulite_uart_driver, port); dev_set_drvdata(dev, NULL); port->mapbase = 0; } @@ -712,8 +717,11 @@ static int __maybe_unused ulite_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); - if (port) - uart_suspend_port(&ulite_uart_driver, port); + if (port) { + struct uartlite_data *pdata = port->private_data; + + uart_suspend_port(pdata->ulite_uart_driver, port); + } return 0; } @@ -728,17 +736,41 @@ static int __maybe_unused ulite_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); - if (port) - uart_resume_port(&ulite_uart_driver, port); + if (port) { + struct uartlite_data *pdata = port->private_data; + + uart_resume_port(pdata->ulite_uart_driver, port); + } return 0; } +static int __maybe_unused ulite_runtime_suspend(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + + clk_disable(pdata->clk); + return 0; +}; + +static int __maybe_unused ulite_runtime_resume(struct device *dev) +{ + struct uart_port *port = dev_get_drvdata(dev); + struct uartlite_data *pdata = port->private_data; + + clk_enable(pdata->clk); + return 0; +} /* --------------------------------------------------------------------- * Platform bus binding */ -static SIMPLE_DEV_PM_OPS(ulite_pm_ops, ulite_suspend, ulite_resume); +static const struct dev_pm_ops ulite_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(ulite_suspend, ulite_resume) + SET_RUNTIME_PM_OPS(ulite_runtime_suspend, + ulite_runtime_resume, NULL) +}; #if defined(CONFIG_OF) /* Match table for of_platform binding */ @@ -763,6 +795,22 @@ static int ulite_probe(struct platform_device *pdev) if (prop) id = be32_to_cpup(prop); #endif + if (id < 0) { + /* Look for a serialN alias */ + id = of_alias_get_id(pdev->dev.of_node, "serial"); + if (id < 0) + id = 0; + } + + if (!ulite_uart_driver.state) { + dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); + ret = uart_register_driver(&ulite_uart_driver); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to register driver\n"); + return ret; + } + } + pdata = devm_kzalloc(&pdev->dev, sizeof(struct uartlite_data), GFP_KERNEL); if (!pdata) @@ -788,24 +836,22 @@ static int ulite_probe(struct platform_device *pdev) pdata->clk = NULL; } + pdata->ulite_uart_driver = &ulite_uart_driver; ret = clk_prepare_enable(pdata->clk); if (ret) { dev_err(&pdev->dev, "Failed to prepare clock\n"); return ret; } - if (!ulite_uart_driver.state) { - dev_dbg(&pdev->dev, "uartlite: calling uart_register_driver()\n"); - ret = uart_register_driver(&ulite_uart_driver); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to register driver\n"); - return ret; - } - } + pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); + pm_runtime_set_active(&pdev->dev); + pm_runtime_enable(&pdev->dev); ret = ulite_assign(&pdev->dev, id, res->start, irq, pdata); - clk_disable(pdata->clk); + pm_runtime_mark_last_busy(&pdev->dev); + pm_runtime_put_autosuspend(&pdev->dev); return ret; } @@ -814,9 +860,14 @@ static int ulite_remove(struct platform_device *pdev) { struct uart_port *port = dev_get_drvdata(&pdev->dev); struct uartlite_data *pdata = port->private_data; + int rc; - clk_disable_unprepare(pdata->clk); - return ulite_release(&pdev->dev); + clk_unprepare(pdata->clk); + rc = ulite_release(&pdev->dev); + pm_runtime_disable(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_dont_use_autosuspend(&pdev->dev); + return rc; } /* work with hotplug and coldplug */ diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index 57c66d2c3471..74089f5e5b53 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -123,7 +123,7 @@ MODULE_PARM_DESC(rx_timeout, "Rx timeout, 1-255"); #define CDNS_UART_IXR_RXTRIG 0x00000001 /* RX FIFO trigger interrupt */ #define CDNS_UART_IXR_RXFULL 0x00000004 /* RX FIFO full interrupt. */ #define CDNS_UART_IXR_RXEMPTY 0x00000002 /* RX FIFO empty interrupt. */ -#define CDNS_UART_IXR_MASK 0x00001FFF /* Valid bit mask */ +#define CDNS_UART_IXR_RXMASK 0x000021e7 /* Valid RX bit mask */ /* * Do not enable parity error interrupt for the following @@ -364,7 +364,13 @@ static irqreturn_t cdns_uart_isr(int irq, void *dev_id) cdns_uart_handle_tx(dev_id); isrstatus &= ~CDNS_UART_IXR_TXEMPTY; } - if (isrstatus & CDNS_UART_IXR_MASK) + + /* + * Skip RX processing if RX is disabled as RXEMPTY will never be set + * as read bytes will not be removed from the FIFO. + */ + if (isrstatus & CDNS_UART_IXR_RXMASK && + !(readl(port->membase + CDNS_UART_CR) & CDNS_UART_CR_RX_DIS)) cdns_uart_handle_rx(dev_id, isrstatus); spin_unlock(&port->lock); @@ -1255,7 +1261,7 @@ static int cdns_uart_suspend(struct device *device) may_wake = device_may_wakeup(device); - if (console_suspend_enabled && may_wake) { + if (console_suspend_enabled && uart_console(port) && may_wake) { unsigned long flags = 0; spin_lock_irqsave(&port->lock, flags); @@ -1293,7 +1299,7 @@ static int cdns_uart_resume(struct device *device) may_wake = device_may_wakeup(device); - if (console_suspend_enabled && !may_wake) { + if (console_suspend_enabled && uart_console(port) && !may_wake) { clk_enable(cdns_uart->pclk); clk_enable(cdns_uart->uartclk); @@ -1508,8 +1514,10 @@ static int cdns_uart_probe(struct platform_device *pdev) #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE cdns_uart_console = devm_kzalloc(&pdev->dev, sizeof(*cdns_uart_console), GFP_KERNEL); - if (!cdns_uart_console) - return -ENOMEM; + if (!cdns_uart_console) { + rc = -ENOMEM; + goto err_out_id; + } strncpy(cdns_uart_console->name, CDNS_UART_TTY_NAME, sizeof(cdns_uart_console->name)); @@ -1545,27 +1553,33 @@ static int cdns_uart_probe(struct platform_device *pdev) } cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "pclk"); + if (PTR_ERR(cdns_uart_data->pclk) == -EPROBE_DEFER) { + rc = PTR_ERR(cdns_uart_data->pclk); + goto err_out_unregister_driver; + } + if (IS_ERR(cdns_uart_data->pclk)) { cdns_uart_data->pclk = devm_clk_get(&pdev->dev, "aper_clk"); - if (!IS_ERR(cdns_uart_data->pclk)) - dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); + if (IS_ERR(cdns_uart_data->pclk)) { + rc = PTR_ERR(cdns_uart_data->pclk); + goto err_out_unregister_driver; + } + dev_err(&pdev->dev, "clock name 'aper_clk' is deprecated.\n"); } - if (IS_ERR(cdns_uart_data->pclk)) { - dev_err(&pdev->dev, "pclk clock not found.\n"); - rc = PTR_ERR(cdns_uart_data->pclk); + + cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); + if (PTR_ERR(cdns_uart_data->uartclk) == -EPROBE_DEFER) { + rc = PTR_ERR(cdns_uart_data->uartclk); goto err_out_unregister_driver; } - cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "uart_clk"); if (IS_ERR(cdns_uart_data->uartclk)) { cdns_uart_data->uartclk = devm_clk_get(&pdev->dev, "ref_clk"); - if (!IS_ERR(cdns_uart_data->uartclk)) - dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); - } - if (IS_ERR(cdns_uart_data->uartclk)) { - dev_err(&pdev->dev, "uart_clk clock not found.\n"); - rc = PTR_ERR(cdns_uart_data->uartclk); - goto err_out_unregister_driver; + if (IS_ERR(cdns_uart_data->uartclk)) { + rc = PTR_ERR(cdns_uart_data->uartclk); + goto err_out_unregister_driver; + } + dev_err(&pdev->dev, "clock name 'ref_clk' is deprecated.\n"); } rc = clk_prepare_enable(cdns_uart_data->pclk); @@ -1624,6 +1638,7 @@ static int cdns_uart_probe(struct platform_device *pdev) pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT); pm_runtime_set_active(&pdev->dev); pm_runtime_enable(&pdev->dev); + device_init_wakeup(port->dev, true); #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE /* @@ -1702,6 +1717,7 @@ static int cdns_uart_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); pm_runtime_set_suspended(&pdev->dev); pm_runtime_dont_use_autosuspend(&pdev->dev); + device_init_wakeup(&pdev->dev, false); #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE if (console_port == port) @@ -1719,6 +1735,7 @@ static struct platform_driver cdns_uart_platform_driver = { .name = CDNS_UART_NAME, .of_match_table = cdns_uart_of_match, .pm = &cdns_uart_dev_pm_ops, + .suppress_bind_attrs = IS_BUILTIN(CONFIG_SERIAL_XILINX_PS_UART), }, }; |