From 0e254963b6ba4d63ac911e79537fea38dd03dc50 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 25 Jan 2018 14:30:43 +0100 Subject: serial: altera: ensure port->regshift is honored consistently MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most register accesses in the altera driver honor port->regshift by using altera_uart_writel(). There are a few accesses however that were missed when the driver was converted to use port->regshift and some others were added later in commit 4d9d7d896d77 ("serial: altera_uart: add earlycon support"). Fixes: 2780ad42f5fe ("tty: serial: altera_uart: Use port->regshift to store bus shift") Signed-off-by: Uwe Kleine-König Acked-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_uart.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index b88b05f8e81e..ae30398fcf56 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -327,7 +327,7 @@ static int altera_uart_startup(struct uart_port *port) /* Enable RX interrupts now */ pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); @@ -343,7 +343,7 @@ static void altera_uart_shutdown(struct uart_port *port) /* Disable all interrupts now */ pp->imr = 0; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); @@ -432,7 +432,7 @@ static void altera_uart_console_putc(struct uart_port *port, int c) ALTERA_UART_STATUS_TRDY_MSK)) cpu_relax(); - writel(c, port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, c, ALTERA_UART_TXDATA_REG); } static void altera_uart_console_write(struct console *co, const char *s, @@ -502,13 +502,13 @@ static int __init altera_uart_earlycon_setup(struct earlycon_device *dev, return -ENODEV; /* Enable RX interrupts now */ - writel(ALTERA_UART_CONTROL_RRDY_MSK, - port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, ALTERA_UART_CONTROL_RRDY_MSK, + ALTERA_UART_CONTROL_REG); if (dev->baud) { unsigned int baudclk = port->uartclk / dev->baud; - writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); } dev->con->write = altera_uart_earlycon_write; -- cgit v1.2.3 From 2ea6ad8bc60f66a5d323ca7e93fddf2363c3ed80 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 25 Jan 2018 14:30:44 +0100 Subject: serial: altera: don't enable any irq if the device doesn't feature an irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the irq line of an altera UART device isn't used to report interrupts for this device the driver better ensures that this device doesn't pull this line to active state and so disturb the whatever might be connected to this line. Signed-off-by: Uwe Kleine-König Acked-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_uart.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index ae30398fcf56..427843761d32 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -109,6 +109,20 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port) return sigs; } +static void altera_uart_update_ctrl_reg(struct altera_uart *pp) +{ + unsigned short imr = pp->imr; + + /* + * If the device doesn't have an irq, ensure that the irq bits are + * masked out to keep the irq line inactive. + */ + if (!pp->port.irq) + imr &= ALTERA_UART_CONTROL_TRBK_MSK | ALTERA_UART_CONTROL_RTS_MSK; + + altera_uart_writel(&pp->port, imr, ALTERA_UART_CONTROL_REG); +} + static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) { struct altera_uart *pp = container_of(port, struct altera_uart, port); @@ -118,7 +132,7 @@ static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); } static void altera_uart_start_tx(struct uart_port *port) @@ -126,7 +140,7 @@ static void altera_uart_start_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); } static void altera_uart_stop_tx(struct uart_port *port) @@ -134,7 +148,7 @@ static void altera_uart_stop_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); } static void altera_uart_stop_rx(struct uart_port *port) @@ -142,7 +156,7 @@ static void altera_uart_stop_rx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); } static void altera_uart_break_ctl(struct uart_port *port, int break_state) @@ -155,7 +169,7 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); spin_unlock_irqrestore(&port->lock, flags); } @@ -262,7 +276,7 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (xmit->head == xmit->tail) { pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); } } @@ -327,7 +341,7 @@ static int altera_uart_startup(struct uart_port *port) /* Enable RX interrupts now */ pp->imr = ALTERA_UART_CONTROL_RRDY_MSK; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); spin_unlock_irqrestore(&port->lock, flags); @@ -343,7 +357,7 @@ static void altera_uart_shutdown(struct uart_port *port) /* Disable all interrupts now */ pp->imr = 0; - altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); + altera_uart_update_ctrl_reg(pp); spin_unlock_irqrestore(&port->lock, flags); -- cgit v1.2.3 From eefadcbca7f394fb9248384f2c759ebbe81e20c7 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Thu, 25 Jan 2018 14:30:45 +0100 Subject: serial: altera: set RRDY flag also without irq MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The UART can be operated without an irq. In this case a timer is setup that regularily calls altera_uart_interrupt(). The receiving part depends on pp->imr having the bit ALTERA_UART_STATUS_RRDY_MSK set, otherwise altera_uart_rx_chars() is never called. So ensure that the bit gets set (disguised as ALTERA_UART_CONTROL_RRDY_MSK) by not returning early from altera_uart_startup() if port->irq is 0. This doesn't affect the hardware as the ALTERA_UART_CONTROL_RRDY_MSK bit isn't actually written to the control register. Signed-off-by: Uwe Kleine-König Acked-by: Tobias Klauser Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/altera_uart.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c index 427843761d32..0e487ce091ac 100644 --- a/drivers/tty/serial/altera_uart.c +++ b/drivers/tty/serial/altera_uart.c @@ -321,20 +321,20 @@ static int altera_uart_startup(struct uart_port *port) { struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned long flags; - int ret; if (!port->irq) { timer_setup(&pp->tmr, altera_uart_timer, 0); mod_timer(&pp->tmr, jiffies + uart_poll_timeout(port)); - return 0; - } - - ret = request_irq(port->irq, altera_uart_interrupt, 0, - DRV_NAME, port); - if (ret) { - pr_err(DRV_NAME ": unable to attach Altera UART %d " - "interrupt vector=%d\n", port->line, port->irq); - return ret; + } else { + int ret; + + ret = request_irq(port->irq, altera_uart_interrupt, 0, + DRV_NAME, port); + if (ret) { + pr_err(DRV_NAME ": unable to attach Altera UART %d " + "interrupt vector=%d\n", port->line, port->irq); + return ret; + } } spin_lock_irqsave(&port->lock, flags); -- cgit v1.2.3 From 1a9ab351fb5d68f40936233c471c53567b82fea1 Mon Sep 17 00:00:00 2001 From: Jan Kundrát Date: Fri, 26 Jan 2018 20:02:00 +0100 Subject: gpio: serial: max310x: Use HW type for gpio_chip's label MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some debugging tools (/sys/kernel/debug/gpio, `lsgpio`) use the gpio_chip's label for displaying an additional context. Right now, the information duplicates stuff which is already available from the parent's device. This is how e.g. `lsgpio`'s output looks like: GPIO chip: gpiochip2, "spi1.2", 16 GPIO lines Comparing the output of other GPIO expanders that I have available: gpiochip4: GPIOs 464-479, parent: spi/spi1.1, mcp23s17, can sleep: gpiochip5: GPIOs 448-463, parent: i2c/0-0020, pca9555, can sleep: gpiochip2: GPIOs 496-511, parent: spi/spi1.2, spi1.2, can sleep: This patch ensures that the type of the real HW device is shown instead of duplicating the SPI path: gpiochip2: GPIOs 496-511, parent: spi/spi1.2, MAX14830, can sleep: Signed-off-by: Jan Kundrát Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/max310x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c index 39f635812077..efe55a1a0615 100644 --- a/drivers/tty/serial/max310x.c +++ b/drivers/tty/serial/max310x.c @@ -1318,7 +1318,7 @@ static int max310x_probe(struct device *dev, struct max310x_devtype *devtype, /* Setup GPIO cotroller */ s->gpio.owner = THIS_MODULE; s->gpio.parent = dev; - s->gpio.label = dev_name(dev); + s->gpio.label = devtype->name; s->gpio.direction_input = max310x_gpio_direction_input; s->gpio.get = max310x_gpio_get; s->gpio.direction_output= max310x_gpio_direction_output; -- cgit v1.2.3 From 2e9fe539108320820016f78ca7704a7342788380 Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Thu, 8 Feb 2018 18:25:41 +0530 Subject: serial: 8250: Don't service RX FIFO if interrupts are disabled Currently, data in RX FIFO is read based on UART_LSR register state even if RDI and RLSI interrupts are disabled in UART_IER register. This is because when IRQ handler is called due to TX FIFO empty event, RX FIFO is serviced based on UART_LSR register status instead of UART_IIR status. This defeats the purpose of disabling UART RX FIFO interrupts during throttling(see, omap_8250_throttle()) as IRQ handler continues to drain UART RX FIFO resulting in overflow of buffer at tty layer. Fix this by making sure that driver drains UART RX FIFO only when UART_IIR_RDI is set along with UART_LSR_BI or UART_LSR_DR bits. Signed-off-by: Vignesh R Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_port.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index 1328c7e70108..ffbb955d1c06 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -1854,7 +1854,8 @@ int serial8250_handle_irq(struct uart_port *port, unsigned int iir) status = serial_port_in(port, UART_LSR); - if (status & (UART_LSR_DR | UART_LSR_BI)) { + if (status & (UART_LSR_DR | UART_LSR_BI) && + iir & UART_IIR_RDI) { if (!up->dma || handle_rx_dma(up, iir)) status = serial8250_rx_chars(up, status); } -- cgit v1.2.3 From 08fb00c64f3401b4ecc18a7395cf302b8d8e12fd Mon Sep 17 00:00:00 2001 From: Vignesh R Date: Thu, 8 Feb 2018 18:25:42 +0530 Subject: serial: 8250: 8250_omap: Fix throttling when DMA is enabled omap_8250_throttle() is called when tty RX buffer is about to overflow and can no longer keep up with the rate at which UART is receiving data. So, the expectation of this callback, is that UART stops RX and asserts HW flow control to signal the sender to stop sending more data. omap_8250_throttle() disables RX FIFO interrupts thus FIFO is no longer serviced, leading to assertion of flow control once RX FIFO is full. But, this does not work when DMA is enabled as driver keeps queuing new RX DMA request in completion handler without brothering about throttling request made by the higher layer. This patch introduces a flag that can be used to determine whether or not to queue next RX DMA request based on throttling request. Without this patch, tty buffer overflows are reported at higher baudrates. Signed-off-by: Vignesh R Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_omap.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c index 57f6eba47f44..624b501fd253 100644 --- a/drivers/tty/serial/8250/8250_omap.c +++ b/drivers/tty/serial/8250/8250_omap.c @@ -114,6 +114,7 @@ struct omap8250_priv { struct uart_8250_dma omap8250_dma; spinlock_t rx_dma_lock; bool rx_dma_broken; + bool throttled; }; #ifdef CONFIG_SERIAL_8250_DMA @@ -692,6 +693,7 @@ static void omap_8250_shutdown(struct uart_port *port) static void omap_8250_throttle(struct uart_port *port) { + struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; @@ -700,6 +702,7 @@ static void omap_8250_throttle(struct uart_port *port) spin_lock_irqsave(&port->lock, flags); up->ier &= ~(UART_IER_RLSI | UART_IER_RDI); serial_out(up, UART_IER, up->ier); + priv->throttled = true; spin_unlock_irqrestore(&port->lock, flags); pm_runtime_mark_last_busy(port->dev); @@ -738,12 +741,16 @@ static int omap_8250_rs485_config(struct uart_port *port, static void omap_8250_unthrottle(struct uart_port *port) { + struct omap8250_priv *priv = port->private_data; struct uart_8250_port *up = up_to_u8250p(port); unsigned long flags; pm_runtime_get_sync(port->dev); spin_lock_irqsave(&port->lock, flags); + priv->throttled = false; + if (up->dma) + up->dma->rx_dma(up); up->ier |= UART_IER_RLSI | UART_IER_RDI; serial_out(up, UART_IER, up->ier); spin_unlock_irqrestore(&port->lock, flags); @@ -788,6 +795,7 @@ unlock: static void __dma_rx_complete(void *param) { struct uart_8250_port *p = param; + struct omap8250_priv *priv = p->port.private_data; struct uart_8250_dma *dma = p->dma; struct dma_tx_state state; unsigned long flags; @@ -805,7 +813,8 @@ static void __dma_rx_complete(void *param) return; } __dma_rx_do_complete(p); - omap_8250_rx_dma(p); + if (!priv->throttled) + omap_8250_rx_dma(p); spin_unlock_irqrestore(&p->port.lock, flags); } -- cgit v1.2.3 From b96408b47480f9947eee933fcce35ed4ae74cc9a Mon Sep 17 00:00:00 2001 From: Ulrich Hecht Date: Thu, 15 Feb 2018 13:02:41 +0100 Subject: serial: sh-sci: use hrtimer for receive timeout High latencies of classic timers cause performance issues for high- speed serial transmissions. This patch transforms rx_timer into an hrtimer to reduce the minimum latency. Signed-off-by: Ulrich Hecht Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 47 +++++++++++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 17 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index 7257c078e155..af1c3246cee1 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -143,8 +144,8 @@ struct sci_port { void *rx_buf[2]; size_t buf_len_rx; struct work_struct work_tx; - struct timer_list rx_timer; - unsigned int rx_timeout; + struct hrtimer rx_timer; + unsigned int rx_timeout; /* microseconds */ #endif unsigned int rx_frame; int rx_trigger; @@ -1229,6 +1230,15 @@ static void sci_rx_dma_release(struct sci_port *s, bool enable_pio) } } +static void start_hrtimer_us(struct hrtimer *hrt, unsigned long usec) +{ + long sec = usec / 1000000; + long nsec = (usec % 1000000) * 1000; + ktime_t t = ktime_set(sec, nsec); + + hrtimer_start(hrt, t, HRTIMER_MODE_REL); +} + static void sci_dma_rx_complete(void *arg) { struct sci_port *s = arg; @@ -1247,7 +1257,7 @@ static void sci_dma_rx_complete(void *arg) if (active >= 0) count = sci_dma_rx_push(s, s->rx_buf[active], s->buf_len_rx); - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + start_hrtimer_us(&s->rx_timer, s->rx_timeout); if (count) tty_flip_buffer_push(&port->state->port); @@ -1391,9 +1401,9 @@ static void work_fn_tx(struct work_struct *work) dma_async_issue_pending(chan); } -static void rx_timer_fn(struct timer_list *t) +static enum hrtimer_restart rx_timer_fn(struct hrtimer *t) { - struct sci_port *s = from_timer(s, t, rx_timer); + struct sci_port *s = container_of(t, struct sci_port, rx_timer); struct dma_chan *chan = s->chan_rx; struct uart_port *port = &s->port; struct dma_tx_state state; @@ -1410,7 +1420,7 @@ static void rx_timer_fn(struct timer_list *t) active = sci_dma_rx_find_active(s); if (active < 0) { spin_unlock_irqrestore(&port->lock, flags); - return; + return HRTIMER_NORESTART; } status = dmaengine_tx_status(s->chan_rx, s->active_rx, &state); @@ -1420,7 +1430,7 @@ static void rx_timer_fn(struct timer_list *t) s->active_rx, active); /* Let packet complete handler take care of the packet */ - return; + return HRTIMER_NORESTART; } dmaengine_pause(chan); @@ -1435,7 +1445,7 @@ static void rx_timer_fn(struct timer_list *t) if (status == DMA_COMPLETE) { spin_unlock_irqrestore(&port->lock, flags); dev_dbg(port->dev, "Transaction complete after DMA engine was stopped"); - return; + return HRTIMER_NORESTART; } /* Handle incomplete DMA receive */ @@ -1460,6 +1470,8 @@ static void rx_timer_fn(struct timer_list *t) serial_port_out(port, SCSCR, scr | SCSCR_RIE); spin_unlock_irqrestore(&port->lock, flags); + + return HRTIMER_NORESTART; } static struct dma_chan *sci_request_dma_chan(struct uart_port *port, @@ -1571,7 +1583,8 @@ static void sci_request_dma(struct uart_port *port) dma += s->buf_len_rx; } - timer_setup(&s->rx_timer, rx_timer_fn, 0); + hrtimer_init(&s->rx_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + s->rx_timer.function = rx_timer_fn; if (port->type == PORT_SCIFA || port->type == PORT_SCIFB) sci_submit_rx(s); @@ -1630,9 +1643,9 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) /* Clear current interrupt */ serial_port_out(port, SCxSR, ssr & ~(SCIF_DR | SCxSR_RDxF(port))); - dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u jiffies\n", + dev_dbg(port->dev, "Rx IRQ %lu: setup t-out in %u us\n", jiffies, s->rx_timeout); - mod_timer(&s->rx_timer, jiffies + s->rx_timeout); + start_hrtimer_us(&s->rx_timer, s->rx_timeout); return IRQ_HANDLED; } @@ -1643,7 +1656,7 @@ static irqreturn_t sci_rx_interrupt(int irq, void *ptr) scif_set_rtrg(port, s->rx_trigger); mod_timer(&s->rx_fifo_timer, jiffies + DIV_ROUND_UP( - s->rx_frame * s->rx_fifo_timeout, 1000)); + s->rx_frame * HZ * s->rx_fifo_timeout, 1000000)); } /* I think sci_receive_chars has to be called irrespective @@ -2079,7 +2092,7 @@ static void sci_shutdown(struct uart_port *port) if (s->chan_rx) { dev_dbg(port->dev, "%s(%d) deleting rx_timer\n", __func__, port->line); - del_timer_sync(&s->rx_timer); + hrtimer_cancel(&s->rx_timer); } #endif @@ -2480,11 +2493,11 @@ done: if (termios->c_cflag & PARENB) bits++; - s->rx_frame = (100 * bits * HZ) / (baud / 10); + s->rx_frame = (10000 * bits) / (baud / 100); #ifdef CONFIG_SERIAL_SH_SCI_DMA - s->rx_timeout = DIV_ROUND_UP(s->buf_len_rx * 2 * s->rx_frame, 1000); - if (s->rx_timeout < msecs_to_jiffies(20)) - s->rx_timeout = msecs_to_jiffies(20); + s->rx_timeout = s->buf_len_rx * 2 * s->rx_frame; + if (s->rx_timeout < 20) + s->rx_timeout = 20; #endif if ((termios->c_cflag & CREAD) != 0) -- cgit v1.2.3 From 914eaf935ec78d3a3ce03751b1e0f8395035d94a Mon Sep 17 00:00:00 2001 From: Joshua Scott Date: Fri, 9 Feb 2018 10:59:56 +1300 Subject: serial: 8250_dw: Allow TX FIFO to drain before writing to UART_LCR An issue has been observed on the Marvell Armada 38x serial port. Writes to UART_LCR can result in characters that are currently held in the TX FIFO being lost rather than sent, even if the userspace process has attempted to flush them. This is most visible when using the "resize" command (tested on Busybox), where we have observed the escape code for restoring cursor position becoming mangled. Signed-off-by: Joshua Scott Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index cd1b94a0f451..41618b780146 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -9,6 +9,7 @@ * LCR is written whilst busy. If it is, then a busy detect interrupt is * raised, the LCR needs to be rewritten and the uart status register read. */ +#include #include #include #include @@ -119,10 +120,27 @@ static void dw8250_check_lcr(struct uart_port *p, int value) */ } +/* Returns once the transmitter is empty or we run out of retries */ +static void dw8250_tx_wait_empty(struct uart_port *p, int tries) +{ + unsigned int lsr; + + while (tries--) { + lsr = readb (p->membase + (UART_LSR << p->regshift)); + if (lsr & UART_LSR_TEMT) + break; + udelay (10); + } +} + static void dw8250_serial_out(struct uart_port *p, int offset, int value) { struct dw8250_data *d = p->private_data; + /* Allow the TX to drain before we reconfigure */ + if (offset == UART_LCR) + dw8250_tx_wait_empty(p, 1000); + writeb(value, p->membase + (offset << p->regshift)); if (offset == UART_LCR && !d->uart_16550_compatible) -- cgit v1.2.3 From 45ca673e81df80f24a575e0a9a4e33c1f865ad08 Mon Sep 17 00:00:00 2001 From: Troy Kisky Date: Fri, 23 Feb 2018 18:27:50 -0800 Subject: tty: serial: imx: allow breaks to be received when using dma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows me to login after sending a break when service serial-getty@ttymxc0.service is running The "tty_insert_flip_char(port, 0, TTY_BREAK)" in clear_rx_errors fixes this by allowing the higher layers to see a break. Also, call uart_handle_break to handle possible "secure attention key." FYI: Martin said the ROM sdma firmware works with this patch, but external sdma firmware still does not send breaks on a i.mx6UL Signed-off-by: Troy Kisky Tested-by: Martin Hicks Reviewed-by: Fabio Estevam Acked-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 1d7ca382bc12..ace96283bdb8 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -927,7 +927,6 @@ static void dma_rx_callback(void *data) status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); if (status == DMA_ERROR) { - dev_err(sport->port.dev, "DMA transaction error.\n"); clear_rx_errors(sport); return; } @@ -1028,6 +1027,7 @@ static int start_rx_dma(struct imx_port *sport) static void clear_rx_errors(struct imx_port *sport) { + struct tty_port *port = &sport->port.state->port; unsigned int status_usr1, status_usr2; status_usr1 = readl(sport->port.membase + USR1); @@ -1036,12 +1036,19 @@ static void clear_rx_errors(struct imx_port *sport) if (status_usr2 & USR2_BRCD) { sport->port.icount.brk++; writel(USR2_BRCD, sport->port.membase + USR2); - } else if (status_usr1 & USR1_FRAMERR) { - sport->port.icount.frame++; - writel(USR1_FRAMERR, sport->port.membase + USR1); - } else if (status_usr1 & USR1_PARITYERR) { - sport->port.icount.parity++; - writel(USR1_PARITYERR, sport->port.membase + USR1); + uart_handle_break(&sport->port); + if (tty_insert_flip_char(port, 0, TTY_BREAK) == 0) + sport->port.icount.buf_overrun++; + tty_flip_buffer_push(port); + } else { + dev_err(sport->port.dev, "DMA transaction error.\n"); + if (status_usr1 & USR1_FRAMERR) { + sport->port.icount.frame++; + writel(USR1_FRAMERR, sport->port.membase + USR1); + } else if (status_usr1 & USR1_PARITYERR) { + sport->port.icount.parity++; + writel(USR1_PARITYERR, sport->port.membase + USR1); + } } if (status_usr2 & USR2_ORE) { -- cgit v1.2.3 From 0ef5a6e09b99c39439d09a957bd40dd3154b51ba Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 23 Feb 2018 14:14:51 +0000 Subject: serial: mvebu-uart: remove duplicated bit-wise or of STAT_FRM_ERR Bit pattern STAT_FRM_ERR is being bit-wise or'd twice; remove the redundant 2nd STAT_FRM_ERR Signed-off-by: Colin Ian King Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index a100e98259d7..a4176afb9404 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -65,7 +65,7 @@ #define STAT_FRM_ERR BIT(2) #define STAT_PAR_ERR BIT(1) #define STAT_OVR_ERR BIT(0) -#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR | STAT_FRM_ERR\ +#define STAT_BRK_ERR (STAT_BRK_DET | STAT_FRM_ERR \ | STAT_PAR_ERR | STAT_OVR_ERR) #define UART_BRDV 0x10 -- cgit v1.2.3 From 135ccb0129952966715074398f422c1517f2e7ad Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 18 Feb 2018 22:02:42 +0100 Subject: serial: imx: drop if that always evaluates to true MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The check sts & USR1_DTRD was just evaluated to true two lines above. So this change doesn't have any effect on the semantic of the driver. Fixes: 27e16501052e ("serial: imx: implement DSR irq handling for DTE mode") Signed-off-by: Uwe Kleine-König Reviewed-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index ace96283bdb8..6c926f702655 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -781,8 +781,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (sts & USR1_DTRD) { unsigned long flags; - if (sts & USR1_DTRD) - writel(USR1_DTRD, sport->port.membase + USR1); + writel(USR1_DTRD, sport->port.membase + USR1); spin_lock_irqsave(&sport->port.lock, flags); imx_mctrl_check(sport); -- cgit v1.2.3 From 0399fd6147143ed9260041c9b466b67e60e1939e Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 18 Feb 2018 22:02:43 +0100 Subject: serial: imx: rename variables to match the register names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now the variable holding the value of register USR1 is called usr1 instead of sts which is more straight forward. The same is also done for sts2 which is called usr2 now. Signed-off-by: Uwe Kleine-König Reviewed-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 6c926f702655..34185991f872 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -758,27 +758,26 @@ static void imx_mctrl_check(struct imx_port *sport) static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int sts; - unsigned int sts2; + unsigned int usr1, usr2; irqreturn_t ret = IRQ_NONE; - sts = readl(sport->port.membase + USR1); - sts2 = readl(sport->port.membase + USR2); + usr1 = readl(sport->port.membase + USR1); + usr2 = readl(sport->port.membase + USR2); - if (!sport->dma_is_enabled && (sts & (USR1_RRDY | USR1_AGTIM))) { + if (!sport->dma_is_enabled && (usr1 & (USR1_RRDY | USR1_AGTIM))) { imx_rxint(irq, dev_id); ret = IRQ_HANDLED; } - if ((sts & USR1_TRDY && + if ((usr1 & USR1_TRDY && readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || - (sts2 & USR2_TXDC && + (usr2 & USR2_TXDC && readl(sport->port.membase + UCR4) & UCR4_TCEN)) { imx_txint(irq, dev_id); ret = IRQ_HANDLED; } - if (sts & USR1_DTRD) { + if (usr1 & USR1_DTRD) { unsigned long flags; writel(USR1_DTRD, sport->port.membase + USR1); @@ -790,17 +789,17 @@ static irqreturn_t imx_int(int irq, void *dev_id) ret = IRQ_HANDLED; } - if (sts & USR1_RTSD) { + if (usr1 & USR1_RTSD) { imx_rtsint(irq, dev_id); ret = IRQ_HANDLED; } - if (sts & USR1_AWAKE) { + if (usr1 & USR1_AWAKE) { writel(USR1_AWAKE, sport->port.membase + USR1); ret = IRQ_HANDLED; } - if (sts2 & USR2_ORE) { + if (usr2 & USR2_ORE) { sport->port.icount.overrun++; writel(USR2_ORE, sport->port.membase + USR2); ret = IRQ_HANDLED; -- cgit v1.2.3 From 437768962f754d9501e5ba4d98b1f2a89dc62028 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 18 Feb 2018 22:02:44 +0100 Subject: serial: imx: Only handle irqs that are actually enabled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Handling an irq that isn't enabled can have some undesired side effects. Some of these are mentioned in the newly introduced code comment. Some of the irq sources already had their handling right, some don't. Handle them all in the same consistent way. The change for USR1_RRDY and USR1_AGTIM drops the check for dma_is_enabled. This is correct as UCR1_RRDYEN and UCR2_ATEN are always off if dma is enabled. Signed-off-by: Uwe Kleine-König Reviewed-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 34185991f872..f34200a4613f 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -758,21 +758,47 @@ static void imx_mctrl_check(struct imx_port *sport) static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int usr1, usr2; + unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; usr1 = readl(sport->port.membase + USR1); usr2 = readl(sport->port.membase + USR2); + ucr1 = readl(sport->port.membase + UCR1); + ucr2 = readl(sport->port.membase + UCR2); + ucr3 = readl(sport->port.membase + UCR3); + ucr4 = readl(sport->port.membase + UCR4); - if (!sport->dma_is_enabled && (usr1 & (USR1_RRDY | USR1_AGTIM))) { + /* + * Even if a condition is true that can trigger an irq only handle it if + * the respective irq source is enabled. This prevents some undesired + * actions, for example if a character that sits in the RX FIFO and that + * should be fetched via DMA is tried to be fetched using PIO. Or the + * receiver is currently off and so reading from URXD0 results in an + * exception. So just mask the (raw) status bits for disabled irqs. + */ + if ((ucr1 & UCR1_RRDYEN) == 0) + usr1 &= ~USR1_RRDY; + if ((ucr2 & UCR2_ATEN) == 0) + usr1 &= ~USR1_AGTIM; + if ((ucr1 & UCR1_TXMPTYEN) == 0) + usr1 &= ~USR1_TRDY; + if ((ucr4 & UCR4_TCEN) == 0) + usr2 &= ~USR2_TXDC; + if ((ucr3 & UCR3_DTRDEN) == 0) + usr1 &= ~USR1_DTRD; + if ((ucr1 & UCR1_RTSDEN) == 0) + usr1 &= ~USR1_RTSD; + if ((ucr3 & UCR3_AWAKEN) == 0) + usr1 &= ~USR1_AWAKE; + if ((ucr4 & UCR4_OREN) == 0) + usr2 &= ~USR2_ORE; + + if (usr1 & (USR1_RRDY | USR1_AGTIM)) { imx_rxint(irq, dev_id); ret = IRQ_HANDLED; } - if ((usr1 & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || - (usr2 & USR2_TXDC && - readl(sport->port.membase + UCR4) & UCR4_TCEN)) { + if ((usr1 & USR1_TRDY) || (usr2 & USR2_TXDC)) { imx_txint(irq, dev_id); ret = IRQ_HANDLED; } -- cgit v1.2.3 From 4238c00bb154be840c11540a81c5e99faa06a631 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 18 Feb 2018 22:02:45 +0100 Subject: serial: imx: simplify tracking of dma being initialized MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The .dma_is_inited member is only set to a value != 0 when the port's startup function calls imx_uart_dma_init(). On shutdown of the port imx_uart_dma_exit is called which sets the value back to 0. So .dma_is_inited is always 0 when imx_startup() is called (assuming .startup() and .shutdown() are correctly balanced) and the check for !sport->dma_is_inited can go away. This allows to replace .dma_is_inited by a variable local to imx_startup. Signed-off-by: Uwe Kleine-König Reviewed-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index f34200a4613f..c60ce00e701c 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -205,7 +205,6 @@ struct imx_port { struct mctrl_gpios *gpios; /* DMA fields */ - unsigned int dma_is_inited:1; unsigned int dma_is_enabled:1; unsigned int dma_is_rxing:1; unsigned int dma_is_txing:1; @@ -1114,8 +1113,6 @@ static void imx_uart_dma_exit(struct imx_port *sport) dma_release_channel(sport->dma_chan_tx); sport->dma_chan_tx = NULL; } - - sport->dma_is_inited = 0; } static int imx_uart_dma_init(struct imx_port *sport) @@ -1168,8 +1165,6 @@ static int imx_uart_dma_init(struct imx_port *sport) goto err; } - sport->dma_is_inited = 1; - return 0; err: imx_uart_dma_exit(sport); @@ -1217,6 +1212,7 @@ static int imx_startup(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; int retval, i; unsigned long flags, temp; + int dma_is_inited = 0; retval = clk_prepare_enable(sport->clk_per); if (retval) @@ -1241,8 +1237,8 @@ static int imx_startup(struct uart_port *port) writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); /* Can we enable the DMA support? */ - if (!uart_console(port) && !sport->dma_is_inited) - imx_uart_dma_init(sport); + if (!uart_console(port) && imx_uart_dma_init(sport) == 0) + dma_is_inited = 1; spin_lock_irqsave(&sport->port.lock, flags); /* Reset fifo's and state machines */ @@ -1261,7 +1257,7 @@ static int imx_startup(struct uart_port *port) writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1); writel(USR2_ORE, sport->port.membase + USR2); - if (sport->dma_is_inited && !sport->dma_is_enabled) + if (dma_is_inited && !sport->dma_is_enabled) imx_enable_dma(sport); temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN; -- cgit v1.2.3 From 42afa627c338e22bbde06c95bd7b46f960c91f79 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Sun, 18 Feb 2018 22:02:46 +0100 Subject: serial: imx: drop check for enabled dma in .startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit imx_shutdown() calls imx_disable_dma if .dma_is_enabled. So after imx_shudown() completes, .dma_is_enabled is zero. For this reason .dma_is_enabled is also zero when imx_startup() is called. So the check for this variable being zero can be dropped. Signed-off-by: Uwe Kleine-König Reviewed-by: Shawn Guo Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index c60ce00e701c..689a117943a0 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1257,7 +1257,7 @@ static int imx_startup(struct uart_port *port) writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1); writel(USR2_ORE, sport->port.membase + USR2); - if (dma_is_inited && !sport->dma_is_enabled) + if (dma_is_inited) imx_enable_dma(sport); temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN; -- cgit v1.2.3 From f9f5786987e81d166c60833edcb7d1836aa16944 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:29 +0100 Subject: serial: arc_uart: Fix out-of-bounds access through DT alias The arc_uart_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Note that the array size is defined by a Kconfig symbol (CONFIG_SERIAL_ARC_NR_PORTS), so this can even be triggered using a legitimate DTB. Fixes: ea28fd56fcde69af ("serial/arc-uart: switch to devicetree based probing") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/arc_uart.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/arc_uart.c b/drivers/tty/serial/arc_uart.c index 2599f9ecccfe..d904a3a345e7 100644 --- a/drivers/tty/serial/arc_uart.c +++ b/drivers/tty/serial/arc_uart.c @@ -593,6 +593,11 @@ static int arc_serial_probe(struct platform_device *pdev) if (dev_id < 0) dev_id = 0; + if (dev_id >= ARRAY_SIZE(arc_uart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", dev_id); + return -EINVAL; + } + uart = &arc_uart_ports[dev_id]; port = &uart->port; -- cgit v1.2.3 From ffab87fdecc655cc676f8be8dd1a2c5e22bd6d47 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:30 +0100 Subject: serial: fsl_lpuart: Fix out-of-bounds access through DT alias The lpuart_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: c9e2e946fb0ba5d2 ("tty: serial: add Freescale lpuart driver support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 8cf112f2efc3..51e47a63d61a 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -2145,6 +2145,10 @@ static int lpuart_probe(struct platform_device *pdev) dev_err(&pdev->dev, "failed to get alias id, errno %d\n", ret); return ret; } + if (ret >= ARRAY_SIZE(lpuart_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", ret); + return -EINVAL; + } sport->port.line = ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); sport->port.membase = devm_ioremap_resource(&pdev->dev, res); -- cgit v1.2.3 From 5673444821406dda5fc25e4b52aca419f8065a19 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:31 +0100 Subject: serial: imx: Fix out-of-bounds access through serial port index MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The imx_ports[] array is indexed using a value derived from the "serialN" alias in DT, or from platform data, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: ff05967a07225ab6 ("serial/imx: add of_alias_get_id() reference back") Signed-off-by: Geert Uytterhoeven Reviewed-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 689a117943a0..78bacd020221 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -2069,6 +2069,12 @@ static int serial_imx_probe(struct platform_device *pdev) else if (ret < 0) return ret; + if (sport->port.line >= ARRAY_SIZE(imx_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", + sport->port.line); + return -EINVAL; + } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(base)) -- cgit v1.2.3 From dd345a31bfdec350d2593e6de5964e55c7f19c76 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:32 +0100 Subject: serial: mxs-auart: Fix out-of-bounds access through serial port index The auart_port[] array is indexed using a value derived from the "serialN" alias in DT, or from platform data, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 1ea6607d4cdc9179 ("serial: mxs-auart: Allow device tree probing") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index 079dc47aa142..caa8a41b6e71 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1663,6 +1663,10 @@ static int mxs_auart_probe(struct platform_device *pdev) s->port.line = pdev->id < 0 ? 0 : pdev->id; else if (ret < 0) return ret; + if (s->port.line >= ARRAY_SIZE(auart_port)) { + dev_err(&pdev->dev, "serial%d out of range\n", s->port.line); + return -EINVAL; + } if (of_id) { pdev->id_entry = of_id->data; -- cgit v1.2.3 From afc7851fab8329eddcf321c9e0a58c893f351dd6 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:33 +0100 Subject: serial: pxa: Fix out-of-bounds access through serial port index The serial_pxa_ports[] array is indexed using a value derived from the "serialN" alias in DT, or from platform data, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 699c20f3e6310aa2 ("serial: pxa: add OF support") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/pxa.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/pxa.c b/drivers/tty/serial/pxa.c index baf552944d56..eda3c7710d6a 100644 --- a/drivers/tty/serial/pxa.c +++ b/drivers/tty/serial/pxa.c @@ -885,6 +885,10 @@ static int serial_pxa_probe(struct platform_device *dev) sport->port.line = dev->id; else if (ret < 0) goto err_clk; + if (sport->port.line >= ARRAY_SIZE(serial_pxa_ports)) { + dev_err(&dev->dev, "serial%d out of range\n", sport->port.line); + return -EINVAL; + } snprintf(sport->name, PXA_NAME_LEN - 1, "UART%d", sport->port.line + 1); sport->port.membase = ioremap(mmres->start, resource_size(mmres)); -- cgit v1.2.3 From 49ee23b71877831ac087d6083f6f397dc19c9664 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:34 +0100 Subject: serial: samsung: Fix out-of-bounds access through serial port index The s3c24xx_serial_ports[] array is indexed using a value derived from the "serialN" alias in DT, or from an incrementing probe index, which may lead to an out-of-bounds access. Fix this by adding a range check. Note that the array size is defined by a Kconfig symbol (CONFIG_SERIAL_SAMSUNG_UARTS), so this can even be triggered using a legitimate DTB or legitimate board code. Fixes: 13a9f6c64fdc55eb ("serial: samsung: Consider DT alias when probing ports") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/samsung.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c index f9fecc5ed0ce..3f2f8c118ce0 100644 --- a/drivers/tty/serial/samsung.c +++ b/drivers/tty/serial/samsung.c @@ -1818,6 +1818,10 @@ static int s3c24xx_serial_probe(struct platform_device *pdev) dbg("s3c24xx_serial_probe(%p) %d\n", pdev, index); + if (index >= ARRAY_SIZE(s3c24xx_serial_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", index); + return -EINVAL; + } ourport = &s3c24xx_serial_ports[index]; ourport->drv_data = s3c24xx_get_driver_data(pdev); -- cgit v1.2.3 From 090fa4b0dccfa3d04e1c5ab0fe4eba16e6713895 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:35 +0100 Subject: serial: sh-sci: Fix out-of-bounds access through DT alias The sci_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Note that the array size is defined by a Kconfig symbol (CONFIG_SERIAL_SH_SCI_NR_UARTS), so this can even be triggered using a legitimate DTB. Fixes: 97ed9790c514066b ("serial: sh-sci: Remove unused platform data capabilities field") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sh-sci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c index af1c3246cee1..0ec2d938011d 100644 --- a/drivers/tty/serial/sh-sci.c +++ b/drivers/tty/serial/sh-sci.c @@ -3109,6 +3109,10 @@ static struct plat_sci_port *sci_parse_dt(struct platform_device *pdev, dev_err(&pdev->dev, "failed to get alias id (%d)\n", id); return NULL; } + if (id >= ARRAY_SIZE(sci_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", id); + return NULL; + } sp = &sci_ports[id]; *dev_id = id; -- cgit v1.2.3 From 96c611c2b7bc897a6d16d58c76751f48707a4ac5 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:36 +0100 Subject: serial: sirf: Fix out-of-bounds access through DT alias The sirf_ports[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: a6ffe8966acbb66b ("serial: sirf: use dynamic method allocate uart structure") Signed-off-by: Geert Uytterhoeven Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/sirfsoc_uart.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c index 9925b00a9777..38622f2a30a9 100644 --- a/drivers/tty/serial/sirfsoc_uart.c +++ b/drivers/tty/serial/sirfsoc_uart.c @@ -1283,6 +1283,11 @@ static int sirfsoc_uart_probe(struct platform_device *pdev) goto err; } sirfport->port.line = of_alias_get_id(np, "serial"); + if (sirfport->port.line >= ARRAY_SIZE(sirf_ports)) { + dev_err(&pdev->dev, "serial%d out of range\n", + sirfport->port.line); + return -EINVAL; + } sirf_ports[sirfport->port.line] = sirfport; sirfport->port.iotype = UPIO_MEM; sirfport->port.flags = UPF_BOOT_AUTOCONF; -- cgit v1.2.3 From e7d75e18d0fc3f7193b65282b651f980c778d935 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Fri, 23 Feb 2018 14:38:37 +0100 Subject: serial: xuartps: Fix out-of-bounds access through DT alias The cdns_uart_port[] array is indexed using a value derived from the "serialN" alias in DT, which may lead to an out-of-bounds access. Fix this by adding a range check. Fixes: 928e9263492069ee ("tty: xuartps: Initialize ports according to aliases") Signed-off-by: Geert Uytterhoeven Reviewed-by: Michal Simek Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/xilinx_uartps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c index b9b2bc76bcac..abcb4d09a2d8 100644 --- a/drivers/tty/serial/xilinx_uartps.c +++ b/drivers/tty/serial/xilinx_uartps.c @@ -1110,7 +1110,7 @@ static struct uart_port *cdns_uart_get_port(int id) struct uart_port *port; /* Try the given port id if failed use default method */ - if (cdns_uart_port[id].mapbase != 0) { + if (id < CDNS_UART_NR_PORTS && cdns_uart_port[id].mapbase != 0) { /* Find the next unused port */ for (id = 0; id < CDNS_UART_NR_PORTS; id++) if (cdns_uart_port[id].mapbase == 0) -- cgit v1.2.3 From aad76f2c48b70d993706580c254a89326ad4d7de Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Fri, 2 Feb 2018 18:46:36 +0200 Subject: serial, pci_ids: Move duplicate IDs to PCI IDs database PCI ID database is for IDs used across several drivers. Here is the case for SUNIX combo cards. No functional change intended. Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/parport/parport_serial.c | 3 --- drivers/tty/serial/8250/8250_pci.c | 3 --- include/linux/pci_ids.h | 3 +++ 3 files changed, 3 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/parport/parport_serial.c b/drivers/parport/parport_serial.c index e15b4845f7c6..087e847b1da2 100644 --- a/drivers/parport/parport_serial.c +++ b/drivers/parport/parport_serial.c @@ -156,9 +156,6 @@ static struct parport_pc_pci cards[] = { /* sunix_2s1p */ { 1, { { 3, -1 }, } }, }; -#define PCI_VENDOR_ID_SUNIX 0x1fd4 -#define PCI_DEVICE_ID_SUNIX_1999 0x1999 - static struct pci_device_id parport_serial_pci_tbl[] = { /* PCI cards */ { PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_110L, diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c index 54adf8d56350..881730cd48c1 100644 --- a/drivers/tty/serial/8250/8250_pci.c +++ b/drivers/tty/serial/8250/8250_pci.c @@ -1685,9 +1685,6 @@ pci_wch_ch38x_setup(struct serial_private *priv, #define PCI_DEVICE_ID_BROADCOM_TRUMANAGE 0x160a #define PCI_DEVICE_ID_AMCC_ADDIDATA_APCI7800 0x818e -#define PCI_VENDOR_ID_SUNIX 0x1fd4 -#define PCI_DEVICE_ID_SUNIX_1999 0x1999 - #define PCIE_VENDOR_ID_WCH 0x1c00 #define PCIE_DEVICE_ID_WCH_CH382_2S1P 0x3250 #define PCIE_DEVICE_ID_WCH_CH384_4S 0x3470 diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index a6b30667a331..e4b0387956cf 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -2556,6 +2556,9 @@ #define PCI_DEVICE_ID_TEHUTI_3010 0x3010 #define PCI_DEVICE_ID_TEHUTI_3014 0x3014 +#define PCI_VENDOR_ID_SUNIX 0x1fd4 +#define PCI_DEVICE_ID_SUNIX_1999 0x1999 + #define PCI_VENDOR_ID_HINT 0x3388 #define PCI_DEVICE_ID_HINT_VXPROII_IDE 0x8013 -- cgit v1.2.3 From 302e8dcc3f78261f7f8fdd3baa452944c515a219 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 27 Feb 2018 22:44:55 +0100 Subject: serial: imx: Rename register fields to match newer reference manuals MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only the reference manual for the i.MX1 (I have MC9328MX1RM/D Rev 5 from 2004) uses TDMAEN and RDMAEN for these. All reference manuals for the newer chips use TXDMAEN and RXDMAEN. Update to the newer name with the assumption that most imx users don't use an imx1 any more. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 78bacd020221..dd763f349890 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -71,12 +71,12 @@ #define UCR1_IDEN (1<<12) /* Idle condition interrupt */ #define UCR1_ICD_REG(x) (((x) & 3) << 10) /* idle condition detect */ #define UCR1_RRDYEN (1<<9) /* Recv ready interrupt enable */ -#define UCR1_RDMAEN (1<<8) /* Recv ready DMA enable */ +#define UCR1_RXDMAEN (1<<8) /* Recv ready DMA enable */ #define UCR1_IREN (1<<7) /* Infrared interface enable */ #define UCR1_TXMPTYEN (1<<6) /* Transimitter empty interrupt enable */ #define UCR1_RTSDEN (1<<5) /* RTS delta interrupt enable */ #define UCR1_SNDBRK (1<<4) /* Send break */ -#define UCR1_TDMAEN (1<<3) /* Transmitter ready DMA enable */ +#define UCR1_TXDMAEN (1<<3) /* Transmitter ready DMA enable */ #define IMX1_UCR1_UARTCLKEN (1<<2) /* UART clock enabled, i.mx1 only */ #define UCR1_ATDMAEN (1<<2) /* Aging DMA Timer Enable */ #define UCR1_DOZE (1<<1) /* Doze */ @@ -441,7 +441,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) temp = readl(sport->port.membase + UCR1); temp &= ~UCR1_TXMPTYEN; if (sport->dma_is_txing) { - temp |= UCR1_TDMAEN; + temp |= UCR1_TXDMAEN; writel(temp, sport->port.membase + UCR1); } else { writel(temp, sport->port.membase + UCR1); @@ -481,7 +481,7 @@ static void dma_tx_callback(void *data) dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); temp = readl(sport->port.membase + UCR1); - temp &= ~UCR1_TDMAEN; + temp &= ~UCR1_TXDMAEN; writel(temp, sport->port.membase + UCR1); /* update the stat */ @@ -547,7 +547,7 @@ static void imx_dma_tx(struct imx_port *sport) uart_circ_chars_pending(xmit)); temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TDMAEN; + temp |= UCR1_TXDMAEN; writel(temp, sport->port.membase + UCR1); /* fire it */ @@ -591,7 +591,7 @@ static void imx_start_tx(struct uart_port *port) /* We have X-char to send, so enable TX IRQ and * disable TX DMA to let TX interrupt to send X-char */ temp = readl(sport->port.membase + UCR1); - temp &= ~UCR1_TDMAEN; + temp &= ~UCR1_TXDMAEN; temp |= UCR1_TXMPTYEN; writel(temp, sport->port.membase + UCR1); return; @@ -1177,7 +1177,7 @@ static void imx_enable_dma(struct imx_port *sport) /* set UCR1 */ temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; + temp |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; writel(temp, sport->port.membase + UCR1); imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); @@ -1191,7 +1191,7 @@ static void imx_disable_dma(struct imx_port *sport) /* clear UCR1 */ temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN); + temp &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); writel(temp, sport->port.membase + UCR1); /* clear UCR2 */ @@ -1380,7 +1380,7 @@ static void imx_flush_buffer(struct uart_port *port) dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); temp = readl(sport->port.membase + UCR1); - temp &= ~UCR1_TDMAEN; + temp &= ~UCR1_TXDMAEN; writel(temp, sport->port.membase + UCR1); sport->dma_is_txing = 0; } -- cgit v1.2.3 From 6aed2a885041f75ee9fdaa54a5d16134c1f83e51 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Tue, 27 Feb 2018 22:44:56 +0100 Subject: serial: imx: document functions that are called with port.lock taken MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Consistently indicate being called with irqs off and the port lock taken for all functions that this applies to. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dd763f349890..dc33b82cd887 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -342,9 +342,7 @@ static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) *ucr2 |= UCR2_CTSC; } -/* - * interrupts disabled on entry - */ +/* called with port.lock taken and irqs off */ static void imx_stop_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -377,9 +375,7 @@ static void imx_stop_tx(struct uart_port *port) } } -/* - * interrupts disabled on entry - */ +/* called with port.lock taken and irqs off */ static void imx_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -402,9 +398,7 @@ static void imx_stop_rx(struct uart_port *port) writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); } -/* - * Set the modem control timer to fire immediately. - */ +/* called with port.lock taken and irqs off */ static void imx_enable_ms(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -415,6 +409,8 @@ static void imx_enable_ms(struct uart_port *port) } static void imx_dma_tx(struct imx_port *sport); + +/* called with port.lock taken and irqs off */ static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -501,6 +497,7 @@ static void dma_tx_callback(void *data) spin_unlock_irqrestore(&sport->port.lock, flags); } +/* called with port.lock taken and irqs off */ static void imx_dma_tx(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -557,9 +554,7 @@ static void imx_dma_tx(struct imx_port *sport) return; } -/* - * interrupts disabled on entry - */ +/* called with port.lock taken and irqs off */ static void imx_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -850,6 +845,7 @@ static unsigned int imx_tx_empty(struct uart_port *port) return ret; } +/* called with port.lock taken and irqs off */ static unsigned int imx_get_mctrl(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -860,6 +856,7 @@ static unsigned int imx_get_mctrl(struct uart_port *port) return ret; } +/* called with port.lock taken and irqs off */ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct imx_port *sport = (struct imx_port *)port; @@ -1364,6 +1361,7 @@ static void imx_shutdown(struct uart_port *port) clk_disable_unprepare(sport->clk_ipg); } +/* called with port.lock taken and irqs off */ static void imx_flush_buffer(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -1689,6 +1687,7 @@ static void imx_poll_put_char(struct uart_port *port, unsigned char c) } #endif +/* called with port.lock taken and irqs off or from .probe without locking */ static int imx_rs485_config(struct uart_port *port, struct serial_rs485 *rs485conf) { -- cgit v1.2.3 From 27c844261b87f85f23784e78170883092428e5a1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:19 +0100 Subject: serial: imx: add wrappers for writel and readl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This prepares implementing shadow copies for the control registers and additionally provides a good place to hook in debug code to trace register usage. Most of this patch was done using pattern substitution: perl -p -i -e ' s/\breadl(?:_relaxed)?\((?:sport->port\.|port->)membase \+/imx_uart_readl(sport,/; s/\bwritel(?:_relaxed)?\(([^,]*), (sport->port\.|port->)membase \+/imx_uart_writel(sport, $1,/; ' drivers/tty/serial/imx.c Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 383 ++++++++++++++++++++++++----------------------- 1 file changed, 199 insertions(+), 184 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index dc33b82cd887..659a949bed8a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -273,6 +273,16 @@ static const struct of_device_id imx_uart_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_uart_dt_ids); +static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) +{ + writel(val, sport->port.membase + offset); +} + +static u32 imx_uart_readl(struct imx_port *sport, u32 offset) +{ + return readl(sport->port.membase + offset); +} + static inline unsigned uts_reg(struct imx_port *sport) { return sport->devdata->uts_reg; @@ -301,22 +311,22 @@ static inline int is_imx6q_uart(struct imx_port *sport) * Save and restore functions for UCR1, UCR2 and UCR3 registers */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) -static void imx_port_ucrs_save(struct uart_port *port, +static void imx_port_ucrs_save(struct imx_port *sport, struct imx_port_ucrs *ucr) { /* save control registers */ - ucr->ucr1 = readl(port->membase + UCR1); - ucr->ucr2 = readl(port->membase + UCR2); - ucr->ucr3 = readl(port->membase + UCR3); + ucr->ucr1 = imx_uart_readl(sport, UCR1); + ucr->ucr2 = imx_uart_readl(sport, UCR2); + ucr->ucr3 = imx_uart_readl(sport, UCR3); } -static void imx_port_ucrs_restore(struct uart_port *port, +static void imx_port_ucrs_restore(struct imx_port *sport, struct imx_port_ucrs *ucr) { /* restore control registers */ - writel(ucr->ucr1, port->membase + UCR1); - writel(ucr->ucr2, port->membase + UCR2); - writel(ucr->ucr3, port->membase + UCR3); + imx_uart_writel(sport, ucr->ucr1, UCR1); + imx_uart_writel(sport, ucr->ucr2, UCR2); + imx_uart_writel(sport, ucr->ucr3, UCR3); } #endif @@ -355,23 +365,23 @@ static void imx_stop_tx(struct uart_port *port) if (sport->dma_is_enabled && sport->dma_is_txing) return; - temp = readl(port->membase + UCR1); - writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1); + temp = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, temp & ~UCR1_TXMPTYEN, UCR1); /* in rs485 mode disable transmitter if shifter is empty */ if (port->rs485.flags & SER_RS485_ENABLED && - readl(port->membase + USR2) & USR2_TXDC) { - temp = readl(port->membase + UCR2); + imx_uart_readl(sport, USR2) & USR2_TXDC) { + temp = imx_uart_readl(sport, UCR2); if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) imx_port_rts_active(sport, &temp); else imx_port_rts_inactive(sport, &temp); temp |= UCR2_RXEN; - writel(temp, port->membase + UCR2); + imx_uart_writel(sport, temp, UCR2); - temp = readl(port->membase + UCR4); + temp = imx_uart_readl(sport, UCR4); temp &= ~UCR4_TCEN; - writel(temp, port->membase + UCR4); + imx_uart_writel(sport, temp, UCR4); } } @@ -390,12 +400,12 @@ static void imx_stop_rx(struct uart_port *port) } } - temp = readl(sport->port.membase + UCR2); - writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); + imx_uart_writel(sport, temp & ~UCR2_RXEN, UCR2); /* disable the `Receiver Ready Interrrupt` */ - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, temp & ~UCR1_RRDYEN, UCR1); } /* called with port.lock taken and irqs off */ @@ -418,7 +428,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) if (sport->port.x_char) { /* Send next char */ - writel(sport->port.x_char, sport->port.membase + URTX0); + imx_uart_writel(sport, sport->port.x_char, URTX0); sport->port.icount.tx++; sport->port.x_char = 0; return; @@ -434,13 +444,13 @@ static inline void imx_transmit_buffer(struct imx_port *sport) * We've just sent a X-char Ensure the TX DMA is enabled * and the TX IRQ is disabled. **/ - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~UCR1_TXMPTYEN; if (sport->dma_is_txing) { temp |= UCR1_TXDMAEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); } else { - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); imx_dma_tx(sport); } } @@ -449,10 +459,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport) return; while (!uart_circ_empty(xmit) && - !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) { + !(imx_uart_readl(sport, uts_reg(sport)) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ - writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); + imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); sport->port.icount.tx++; } @@ -476,9 +486,9 @@ static void dma_tx_callback(void *data) dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~UCR1_TXDMAEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); /* update the stat */ xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); @@ -543,9 +553,9 @@ static void imx_dma_tx(struct imx_port *sport) dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", uart_circ_chars_pending(xmit)); - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp |= UCR1_TXDMAEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); /* fire it */ sport->dma_is_txing = 1; @@ -561,34 +571,34 @@ static void imx_start_tx(struct uart_port *port) unsigned long temp; if (port->rs485.flags & SER_RS485_ENABLED) { - temp = readl(port->membase + UCR2); + temp = imx_uart_readl(sport, UCR2); if (port->rs485.flags & SER_RS485_RTS_ON_SEND) imx_port_rts_active(sport, &temp); else imx_port_rts_inactive(sport, &temp); if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) temp &= ~UCR2_RXEN; - writel(temp, port->membase + UCR2); + imx_uart_writel(sport, temp, UCR2); /* enable transmitter and shifter empty irq */ - temp = readl(port->membase + UCR4); + temp = imx_uart_readl(sport, UCR4); temp |= UCR4_TCEN; - writel(temp, port->membase + UCR4); + imx_uart_writel(sport, temp, UCR4); } if (!sport->dma_is_enabled) { - temp = readl(sport->port.membase + UCR1); - writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, temp | UCR1_TXMPTYEN, UCR1); } if (sport->dma_is_enabled) { if (sport->port.x_char) { /* We have X-char to send, so enable TX IRQ and * disable TX DMA to let TX interrupt to send X-char */ - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~UCR1_TXDMAEN; temp |= UCR1_TXMPTYEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); return; } @@ -607,8 +617,8 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) spin_lock_irqsave(&sport->port.lock, flags); - writel(USR1_RTSD, sport->port.membase + USR1); - val = readl(sport->port.membase + USR1) & USR1_RTSS; + imx_uart_writel(sport, USR1_RTSD, USR1); + val = imx_uart_readl(sport, USR1) & USR1_RTSS; uart_handle_cts_change(&sport->port, !!val); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); @@ -636,15 +646,15 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) spin_lock_irqsave(&sport->port.lock, flags); - while (readl(sport->port.membase + USR2) & USR2_RDR) { + while (imx_uart_readl(sport, USR2) & USR2_RDR) { flg = TTY_NORMAL; sport->port.icount.rx++; - rx = readl(sport->port.membase + URXD0); + rx = imx_uart_readl(sport, URXD0); - temp = readl(sport->port.membase + USR2); + temp = imx_uart_readl(sport, USR2); if (temp & USR2_BRCD) { - writel(USR2_BRCD, sport->port.membase + USR2); + imx_uart_writel(sport, USR2_BRCD, USR2); if (uart_handle_break(&sport->port)) continue; } @@ -705,8 +715,8 @@ static void clear_rx_errors(struct imx_port *sport); static unsigned int imx_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; - unsigned usr1 = readl(sport->port.membase + USR1); - unsigned usr2 = readl(sport->port.membase + USR2); + unsigned usr1 = imx_uart_readl(sport, USR1); + unsigned usr2 = imx_uart_readl(sport, USR2); if (usr1 & USR1_RTSS) tmp |= TIOCM_CTS; @@ -716,7 +726,7 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport) tmp |= TIOCM_CAR; if (sport->dte_mode) - if (!(readl(sport->port.membase + USR2) & USR2_RIIN)) + if (!(imx_uart_readl(sport, USR2) & USR2_RIIN)) tmp |= TIOCM_RI; return tmp; @@ -755,12 +765,12 @@ static irqreturn_t imx_int(int irq, void *dev_id) unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; irqreturn_t ret = IRQ_NONE; - usr1 = readl(sport->port.membase + USR1); - usr2 = readl(sport->port.membase + USR2); - ucr1 = readl(sport->port.membase + UCR1); - ucr2 = readl(sport->port.membase + UCR2); - ucr3 = readl(sport->port.membase + UCR3); - ucr4 = readl(sport->port.membase + UCR4); + usr1 = imx_uart_readl(sport, USR1); + usr2 = imx_uart_readl(sport, USR2); + ucr1 = imx_uart_readl(sport, UCR1); + ucr2 = imx_uart_readl(sport, UCR2); + ucr3 = imx_uart_readl(sport, UCR3); + ucr4 = imx_uart_readl(sport, UCR4); /* * Even if a condition is true that can trigger an irq only handle it if @@ -800,7 +810,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) if (usr1 & USR1_DTRD) { unsigned long flags; - writel(USR1_DTRD, sport->port.membase + USR1); + imx_uart_writel(sport, USR1_DTRD, USR1); spin_lock_irqsave(&sport->port.lock, flags); imx_mctrl_check(sport); @@ -815,13 +825,13 @@ static irqreturn_t imx_int(int irq, void *dev_id) } if (usr1 & USR1_AWAKE) { - writel(USR1_AWAKE, sport->port.membase + USR1); + imx_uart_writel(sport, USR1_AWAKE, USR1); ret = IRQ_HANDLED; } if (usr2 & USR2_ORE) { sport->port.icount.overrun++; - writel(USR2_ORE, sport->port.membase + USR2); + imx_uart_writel(sport, USR2_ORE, USR2); ret = IRQ_HANDLED; } @@ -836,7 +846,7 @@ static unsigned int imx_tx_empty(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned int ret; - ret = (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; /* If the TX DMA is working, return 0. */ if (sport->dma_is_enabled && sport->dma_is_txing) @@ -863,22 +873,22 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) unsigned long temp; if (!(port->rs485.flags & SER_RS485_ENABLED)) { - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp &= ~(UCR2_CTS | UCR2_CTSC); if (mctrl & TIOCM_RTS) temp |= UCR2_CTS | UCR2_CTSC; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); } - temp = readl(sport->port.membase + UCR3) & ~UCR3_DSR; + temp = imx_uart_readl(sport, UCR3) & ~UCR3_DSR; if (!(mctrl & TIOCM_DTR)) temp |= UCR3_DSR; - writel(temp, sport->port.membase + UCR3); + imx_uart_writel(sport, temp, UCR3); - temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; + temp = imx_uart_readl(sport, uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) temp |= UTS_LOOP; - writel(temp, sport->port.membase + uts_reg(sport)); + imx_uart_writel(sport, temp, uts_reg(sport)); mctrl_gpio_set(sport->gpios, mctrl); } @@ -893,12 +903,12 @@ static void imx_break_ctl(struct uart_port *port, int break_state) spin_lock_irqsave(&sport->port.lock, flags); - temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK; + temp = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK; if (break_state != 0) temp |= UCR1_SNDBRK; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1050,12 +1060,12 @@ static void clear_rx_errors(struct imx_port *sport) struct tty_port *port = &sport->port.state->port; unsigned int status_usr1, status_usr2; - status_usr1 = readl(sport->port.membase + USR1); - status_usr2 = readl(sport->port.membase + USR2); + status_usr1 = imx_uart_readl(sport, USR1); + status_usr2 = imx_uart_readl(sport, USR2); if (status_usr2 & USR2_BRCD) { sport->port.icount.brk++; - writel(USR2_BRCD, sport->port.membase + USR2); + imx_uart_writel(sport, USR2_BRCD, USR2); uart_handle_break(&sport->port); if (tty_insert_flip_char(port, 0, TTY_BREAK) == 0) sport->port.icount.buf_overrun++; @@ -1064,16 +1074,16 @@ static void clear_rx_errors(struct imx_port *sport) dev_err(sport->port.dev, "DMA transaction error.\n"); if (status_usr1 & USR1_FRAMERR) { sport->port.icount.frame++; - writel(USR1_FRAMERR, sport->port.membase + USR1); + imx_uart_writel(sport, USR1_FRAMERR, USR1); } else if (status_usr1 & USR1_PARITYERR) { sport->port.icount.parity++; - writel(USR1_PARITYERR, sport->port.membase + USR1); + imx_uart_writel(sport, USR1_PARITYERR, USR1); } } if (status_usr2 & USR2_ORE) { sport->port.icount.overrun++; - writel(USR2_ORE, sport->port.membase + USR2); + imx_uart_writel(sport, USR2_ORE, USR2); } } @@ -1089,9 +1099,9 @@ static void imx_setup_ufcr(struct imx_port *sport, unsigned int val; /* set receiver / transmitter trigger level */ - val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); + val = imx_uart_readl(sport, UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); val |= txwl << UFCR_TXTL_SHF | rxwl; - writel(val, sport->port.membase + UFCR); + imx_uart_writel(sport, val, UFCR); } static void imx_uart_dma_exit(struct imx_port *sport) @@ -1173,9 +1183,9 @@ static void imx_enable_dma(struct imx_port *sport) unsigned long temp; /* set UCR1 */ - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); @@ -1187,14 +1197,14 @@ static void imx_disable_dma(struct imx_port *sport) unsigned long temp; /* clear UCR1 */ - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); /* clear UCR2 */ - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); @@ -1225,13 +1235,13 @@ static int imx_startup(struct uart_port *port) /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs */ - temp = readl(sport->port.membase + UCR4); + temp = imx_uart_readl(sport, UCR4); /* set the trigger level for CTS */ temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); temp |= CTSTL << UCR4_CTSTL_SHF; - writel(temp & ~UCR4_DREN, sport->port.membase + UCR4); + imx_uart_writel(sport, temp & ~UCR4_DREN, UCR4); /* Can we enable the DMA support? */ if (!uart_console(port) && imx_uart_dma_init(sport) == 0) @@ -1241,37 +1251,37 @@ static int imx_startup(struct uart_port *port) /* Reset fifo's and state machines */ i = 100; - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); /* * Finally, clear and enable interrupts */ - writel(USR1_RTSD | USR1_DTRD, sport->port.membase + USR1); - writel(USR2_ORE, sport->port.membase + USR2); + imx_uart_writel(sport, USR1_RTSD | USR1_DTRD, USR1); + imx_uart_writel(sport, USR2_ORE, USR2); if (dma_is_inited) imx_enable_dma(sport); - temp = readl(sport->port.membase + UCR1) & ~UCR1_RRDYEN; + temp = imx_uart_readl(sport, UCR1) & ~UCR1_RRDYEN; if (!sport->dma_is_enabled) temp |= UCR1_RRDYEN; temp |= UCR1_UARTEN; if (sport->have_rtscts) temp |= UCR1_RTSDEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); - temp = readl(sport->port.membase + UCR4) & ~UCR4_OREN; + temp = imx_uart_readl(sport, UCR4) & ~UCR4_OREN; if (!sport->dma_is_enabled) temp |= UCR4_OREN; - writel(temp, sport->port.membase + UCR4); + imx_uart_writel(sport, temp, UCR4); - temp = readl(sport->port.membase + UCR2) & ~UCR2_ATEN; + temp = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN; temp |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) temp |= UCR2_IRTS; @@ -1281,10 +1291,10 @@ static int imx_startup(struct uart_port *port) */ if (!is_imx1_uart(sport)) temp &= ~UCR2_RTSEN; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); if (!is_imx1_uart(sport)) { - temp = readl(sport->port.membase + UCR3); + temp = imx_uart_readl(sport, UCR3); temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; @@ -1292,7 +1302,7 @@ static int imx_startup(struct uart_port *port) /* disable broken interrupts */ temp &= ~(UCR3_RI | UCR3_DCD); - writel(temp, sport->port.membase + UCR3); + imx_uart_writel(sport, temp, UCR3); } /* @@ -1336,9 +1346,9 @@ static void imx_shutdown(struct uart_port *port) mctrl_gpio_disable_ms(sport->gpios); spin_lock_irqsave(&sport->port.lock, flags); - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp &= ~(UCR2_TXEN); - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); /* @@ -1351,10 +1361,10 @@ static void imx_shutdown(struct uart_port *port) */ spin_lock_irqsave(&sport->port.lock, flags); - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); clk_disable_unprepare(sport->clk_per); @@ -1377,9 +1387,9 @@ static void imx_flush_buffer(struct uart_port *port) if (sport->dma_is_txing) { dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); temp &= ~UCR1_TXDMAEN; - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); sport->dma_is_txing = 0; } @@ -1394,21 +1404,21 @@ static void imx_flush_buffer(struct uart_port *port) * UTXD. UBRC is read only, so only save/restore the other three * registers. */ - ubir = readl(sport->port.membase + UBIR); - ubmr = readl(sport->port.membase + UBMR); - uts = readl(sport->port.membase + IMX21_UTS); + ubir = imx_uart_readl(sport, UBIR); + ubmr = imx_uart_readl(sport, UBMR); + uts = imx_uart_readl(sport, IMX21_UTS); - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); /* Restore the registers */ - writel(ubir, sport->port.membase + UBIR); - writel(ubmr, sport->port.membase + UBMR); - writel(uts, sport->port.membase + IMX21_UTS); + imx_uart_writel(sport, ubir, UBIR); + imx_uart_writel(sport, ubmr, UBMR); + imx_uart_writel(sport, uts, IMX21_UTS); } static void @@ -1520,17 +1530,17 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, /* * disable interrupts and drain transmitter */ - old_ucr1 = readl(sport->port.membase + UCR1); - writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), - sport->port.membase + UCR1); + old_ucr1 = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, + old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), + UCR1); - while (!(readl(sport->port.membase + USR2) & USR2_TXDC)) + while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)) barrier(); /* then, disable everything */ - old_ucr2 = readl(sport->port.membase + UCR2); - writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN), - sport->port.membase + UCR2); + old_ucr2 = imx_uart_readl(sport, UCR2); + imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN), UCR2); old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN); /* custom-baudrate handling */ @@ -1556,21 +1566,21 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, num -= 1; denom -= 1; - ufcr = readl(sport->port.membase + UFCR); + ufcr = imx_uart_readl(sport, UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); - writel(ufcr, sport->port.membase + UFCR); + imx_uart_writel(sport, ufcr, UFCR); - writel(num, sport->port.membase + UBIR); - writel(denom, sport->port.membase + UBMR); + imx_uart_writel(sport, num, UBIR); + imx_uart_writel(sport, denom, UBMR); if (!is_imx1_uart(sport)) - writel(sport->port.uartclk / div / 1000, - sport->port.membase + IMX21_ONEMS); + imx_uart_writel(sport, sport->port.uartclk / div / 1000, + IMX21_ONEMS); - writel(old_ucr1, sport->port.membase + UCR1); + imx_uart_writel(sport, old_ucr1, UCR1); /* set the parity, stop bits and data size */ - writel(ucr2 | old_ucr2, sport->port.membase + UCR2); + imx_uart_writel(sport, ucr2 | old_ucr2, UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_enable_ms(&sport->port); @@ -1644,16 +1654,16 @@ static int imx_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); - temp = readl(sport->port.membase + UCR1); + temp = imx_uart_readl(sport, UCR1); if (is_imx1_uart(sport)) temp |= IMX1_UCR1_UARTCLKEN; temp |= UCR1_UARTEN | UCR1_RRDYEN; temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); - writel(temp, sport->port.membase + UCR1); + imx_uart_writel(sport, temp, UCR1); - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp |= UCR2_RXEN; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1662,27 +1672,29 @@ static int imx_poll_init(struct uart_port *port) static int imx_poll_get_char(struct uart_port *port) { - if (!(readl_relaxed(port->membase + USR2) & USR2_RDR)) + struct imx_port *sport = (struct imx_port *)port; + if (!(imx_uart_readl(sport, USR2) & USR2_RDR)) return NO_POLL_CHAR; - return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA; + return imx_uart_readl(sport, URXD0) & URXD_RX_DATA; } static void imx_poll_put_char(struct uart_port *port, unsigned char c) { + struct imx_port *sport = (struct imx_port *)port; unsigned int status; /* drain */ do { - status = readl_relaxed(port->membase + USR1); + status = imx_uart_readl(sport, USR1); } while (~status & USR1_TRDY); /* write */ - writel_relaxed(c, port->membase + URTX0); + imx_uart_writel(sport, c, URTX0); /* flush */ do { - status = readl_relaxed(port->membase + USR2); + status = imx_uart_readl(sport, USR2); } while (~status & USR2_TXDC); } #endif @@ -1704,20 +1716,20 @@ static int imx_rs485_config(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { /* disable transmitter */ - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) imx_port_rts_active(sport, &temp); else imx_port_rts_inactive(sport, &temp); - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); } /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || rs485conf->flags & SER_RS485_RX_DURING_TX) { - temp = readl(sport->port.membase + UCR2); + temp = imx_uart_readl(sport, UCR2); temp |= UCR2_RXEN; - writel(temp, sport->port.membase + UCR2); + imx_uart_writel(sport, temp, UCR2); } port->rs485 = *rs485conf; @@ -1755,10 +1767,10 @@ static void imx_console_putchar(struct uart_port *port, int ch) { struct imx_port *sport = (struct imx_port *)port; - while (readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL) + while (imx_uart_readl(sport, uts_reg(sport)) & UTS_TXFULL) barrier(); - writel(ch, sport->port.membase + URTX0); + imx_uart_writel(sport, ch, URTX0); } /* @@ -1793,7 +1805,7 @@ imx_console_write(struct console *co, const char *s, unsigned int count) /* * First, save UCR1/2/3 and then disable interrupts */ - imx_port_ucrs_save(&sport->port, &old_ucr); + imx_port_ucrs_save(sport, &old_ucr); ucr1 = old_ucr.ucr1; if (is_imx1_uart(sport)) @@ -1801,9 +1813,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count) ucr1 |= UCR1_UARTEN; ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); - writel(ucr1, sport->port.membase + UCR1); + imx_uart_writel(sport, ucr1, UCR1); - writel(old_ucr.ucr2 | UCR2_TXEN, sport->port.membase + UCR2); + imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); uart_console_write(&sport->port, s, count, imx_console_putchar); @@ -1811,9 +1823,9 @@ imx_console_write(struct console *co, const char *s, unsigned int count) * Finally, wait for transmitter to become empty * and restore UCR1/2/3 */ - while (!(readl(sport->port.membase + USR2) & USR2_TXDC)); + while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)); - imx_port_ucrs_restore(&sport->port, &old_ucr); + imx_port_ucrs_restore(sport, &old_ucr); if (locked) spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1831,13 +1843,13 @@ imx_console_get_options(struct imx_port *sport, int *baud, int *parity, int *bits) { - if (readl(sport->port.membase + UCR1) & UCR1_UARTEN) { + if (imx_uart_readl(sport, UCR1) & UCR1_UARTEN) { /* ok, the port was enabled */ unsigned int ucr2, ubir, ubmr, uartclk; unsigned int baud_raw; unsigned int ucfr_rfdiv; - ucr2 = readl(sport->port.membase + UCR2); + ucr2 = imx_uart_readl(sport, UCR2); *parity = 'n'; if (ucr2 & UCR2_PREN) { @@ -1852,10 +1864,10 @@ imx_console_get_options(struct imx_port *sport, int *baud, else *bits = 7; - ubir = readl(sport->port.membase + UBIR) & 0xffff; - ubmr = readl(sport->port.membase + UBMR) & 0xffff; + ubir = imx_uart_readl(sport, UBIR) & 0xffff; + ubmr = imx_uart_readl(sport, UBMR) & 0xffff; - ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7; + ucfr_rfdiv = (imx_uart_readl(sport, UFCR) & UFCR_RFDIV) >> 7; if (ucfr_rfdiv == 6) ucfr_rfdiv = 7; else @@ -1950,10 +1962,12 @@ static struct console imx_console = { #ifdef CONFIG_OF static void imx_console_early_putchar(struct uart_port *port, int ch) { - while (readl_relaxed(port->membase + IMX21_UTS) & UTS_TXFULL) + struct imx_port *sport = (struct imx_port *)port; + + while (imx_uart_readl(sport, IMX21_UTS) & UTS_TXFULL) cpu_relax(); - writel_relaxed(ch, port->membase + URTX0); + imx_uart_writel(sport, ch, URTX0); } static void imx_console_early_write(struct console *con, const char *s, @@ -2131,10 +2145,10 @@ static int serial_imx_probe(struct platform_device *pdev) imx_rs485_config(&sport->port, &sport->port.rs485); /* Disable interrupts before requesting them */ - reg = readl_relaxed(sport->port.membase + UCR1); + reg = imx_uart_readl(sport, UCR1); reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_TXMPTYEN | UCR1_RTSDEN); - writel_relaxed(reg, sport->port.membase + UCR1); + imx_uart_writel(sport, reg, UCR1); if (!is_imx1_uart(sport) && sport->dte_mode) { /* @@ -2143,28 +2157,29 @@ static int serial_imx_probe(struct platform_device *pdev) * and DCD (when they are outputs) or enables the respective * irqs. So set this bit early, i.e. before requesting irqs. */ - reg = readl(sport->port.membase + UFCR); + reg = imx_uart_readl(sport, UFCR); if (!(reg & UFCR_DCEDTE)) - writel(reg | UFCR_DCEDTE, sport->port.membase + UFCR); + imx_uart_writel(sport, reg | UFCR_DCEDTE, UFCR); /* * Disable UCR3_RI and UCR3_DCD irqs. They are also not * enabled later because they cannot be cleared * (confirmed on i.MX25) which makes them unusable. */ - writel(IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR, - sport->port.membase + UCR3); + imx_uart_writel(sport, + IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR, + UCR3); } else { unsigned long ucr3 = UCR3_DSR; - reg = readl(sport->port.membase + UFCR); + reg = imx_uart_readl(sport, UFCR); if (reg & UFCR_DCEDTE) - writel(reg & ~UFCR_DCEDTE, sport->port.membase + UFCR); + imx_uart_writel(sport, reg & ~UFCR_DCEDTE, UFCR); if (!is_imx1_uart(sport)) ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; - writel(ucr3, sport->port.membase + UCR3); + imx_uart_writel(sport, ucr3, UCR3); } clk_disable_unprepare(sport->clk_ipg); @@ -2217,32 +2232,32 @@ static void serial_imx_restore_context(struct imx_port *sport) if (!sport->context_saved) return; - writel(sport->saved_reg[4], sport->port.membase + UFCR); - writel(sport->saved_reg[5], sport->port.membase + UESC); - writel(sport->saved_reg[6], sport->port.membase + UTIM); - writel(sport->saved_reg[7], sport->port.membase + UBIR); - writel(sport->saved_reg[8], sport->port.membase + UBMR); - writel(sport->saved_reg[9], sport->port.membase + IMX21_UTS); - writel(sport->saved_reg[0], sport->port.membase + UCR1); - writel(sport->saved_reg[1] | UCR2_SRST, sport->port.membase + UCR2); - writel(sport->saved_reg[2], sport->port.membase + UCR3); - writel(sport->saved_reg[3], sport->port.membase + UCR4); + imx_uart_writel(sport, sport->saved_reg[4], UFCR); + imx_uart_writel(sport, sport->saved_reg[5], UESC); + imx_uart_writel(sport, sport->saved_reg[6], UTIM); + imx_uart_writel(sport, sport->saved_reg[7], UBIR); + imx_uart_writel(sport, sport->saved_reg[8], UBMR); + imx_uart_writel(sport, sport->saved_reg[9], IMX21_UTS); + imx_uart_writel(sport, sport->saved_reg[0], UCR1); + imx_uart_writel(sport, sport->saved_reg[1] | UCR2_SRST, UCR2); + imx_uart_writel(sport, sport->saved_reg[2], UCR3); + imx_uart_writel(sport, sport->saved_reg[3], UCR4); sport->context_saved = false; } static void serial_imx_save_context(struct imx_port *sport) { /* Save necessary regs */ - sport->saved_reg[0] = readl(sport->port.membase + UCR1); - sport->saved_reg[1] = readl(sport->port.membase + UCR2); - sport->saved_reg[2] = readl(sport->port.membase + UCR3); - sport->saved_reg[3] = readl(sport->port.membase + UCR4); - sport->saved_reg[4] = readl(sport->port.membase + UFCR); - sport->saved_reg[5] = readl(sport->port.membase + UESC); - sport->saved_reg[6] = readl(sport->port.membase + UTIM); - sport->saved_reg[7] = readl(sport->port.membase + UBIR); - sport->saved_reg[8] = readl(sport->port.membase + UBMR); - sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS); + sport->saved_reg[0] = imx_uart_readl(sport, UCR1); + sport->saved_reg[1] = imx_uart_readl(sport, UCR2); + sport->saved_reg[2] = imx_uart_readl(sport, UCR3); + sport->saved_reg[3] = imx_uart_readl(sport, UCR4); + sport->saved_reg[4] = imx_uart_readl(sport, UFCR); + sport->saved_reg[5] = imx_uart_readl(sport, UESC); + sport->saved_reg[6] = imx_uart_readl(sport, UTIM); + sport->saved_reg[7] = imx_uart_readl(sport, UBIR); + sport->saved_reg[8] = imx_uart_readl(sport, UBMR); + sport->saved_reg[9] = imx_uart_readl(sport, IMX21_UTS); sport->context_saved = true; } @@ -2250,22 +2265,22 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) { unsigned int val; - val = readl(sport->port.membase + UCR3); + val = imx_uart_readl(sport, UCR3); if (on) { - writel(USR1_AWAKE, sport->port.membase + USR1); + imx_uart_writel(sport, USR1_AWAKE, USR1); val |= UCR3_AWAKEN; } else val &= ~UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); + imx_uart_writel(sport, val, UCR3); if (sport->have_rtscts) { - val = readl(sport->port.membase + UCR1); + val = imx_uart_readl(sport, UCR1); if (on) val |= UCR1_RTSDEN; else val &= ~UCR1_RTSDEN; - writel(val, sport->port.membase + UCR1); + imx_uart_writel(sport, val, UCR1); } } -- cgit v1.2.3 From 3a0ab62f43de5c6ec55fb9d6721168602008142a Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:20 +0100 Subject: serial: imx: implement shadow registers for UCRx and UFCR MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reduces the amount of read accesses to the register space by shadowing the values for five registers that only change on writing them. There is a single bit in UCR2 that might change without being written to it, this is handled accordingly. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 659a949bed8a..57891d21f20d 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -204,6 +204,13 @@ struct imx_port { struct mctrl_gpios *gpios; + /* shadow registers */ + unsigned int ucr1; + unsigned int ucr2; + unsigned int ucr3; + unsigned int ucr4; + unsigned int ufcr; + /* DMA fields */ unsigned int dma_is_enabled:1; unsigned int dma_is_rxing:1; @@ -275,12 +282,56 @@ MODULE_DEVICE_TABLE(of, imx_uart_dt_ids); static void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) { + switch (offset) { + case UCR1: + sport->ucr1 = val; + break; + case UCR2: + sport->ucr2 = val; + break; + case UCR3: + sport->ucr3 = val; + break; + case UCR4: + sport->ucr4 = val; + break; + case UFCR: + sport->ufcr = val; + break; + default: + break; + } writel(val, sport->port.membase + offset); } static u32 imx_uart_readl(struct imx_port *sport, u32 offset) { - return readl(sport->port.membase + offset); + switch (offset) { + case UCR1: + return sport->ucr1; + break; + case UCR2: + /* + * UCR2_SRST is the only bit in the cached registers that might + * differ from the value that was last written. As it only + * clears after being set, reread conditionally. + */ + if (sport->ucr2 & UCR2_SRST) + sport->ucr2 = readl(sport->port.membase + offset); + return sport->ucr2; + break; + case UCR3: + return sport->ucr3; + break; + case UCR4: + return sport->ucr4; + break; + case UFCR: + return sport->ufcr; + break; + default: + return readl(sport->port.membase + offset); + } } static inline unsigned uts_reg(struct imx_port *sport) @@ -2136,6 +2187,13 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; } + /* initialize shadow register values */ + sport->ucr1 = readl(sport->port.membase + UCR1); + sport->ucr2 = readl(sport->port.membase + UCR2); + sport->ucr3 = readl(sport->port.membase + UCR3); + sport->ucr4 = readl(sport->port.membase + UCR4); + sport->ufcr = readl(sport->port.membase + UFCR); + uart_get_rs485_mode(&pdev->dev, &sport->port.rs485); if (sport->port.rs485.flags & SER_RS485_ENABLED && -- cgit v1.2.3 From 686351f342fa745d10ddef08d0e930cf53b0c673 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:21 +0100 Subject: serial: imx: simplify some conditions related to dma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Neither .dma_is_txing nor .dma_is_rxing can evaluate to true if .dma_is_enabled evaluates to false: The only function that sets .dma_is_txing to a non-zero value is imx_dma_tx() which is only called if .dma_is_enabled is true. Same for .dma_is_rxing and start_rx_dma(). And before .dma_is_enabled is set to 0 when imx_shutdown calls imx_disable_dma(), .dma_is_rxing and .dma_is_txing are reset to zero before, too. For this reason sport->dma_is_enabled && sport->dma_is_rxing has the same value as sport->dma_is_rxing which allows to simplify three if conditions. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 57891d21f20d..b87e04334342 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -413,7 +413,7 @@ static void imx_stop_tx(struct uart_port *port) * We are maybe in the SMP context, so if the DMA TX thread is running * on other cpu, we have to wait for it to finish. */ - if (sport->dma_is_enabled && sport->dma_is_txing) + if (sport->dma_is_txing) return; temp = imx_uart_readl(sport, UCR1); @@ -442,7 +442,7 @@ static void imx_stop_rx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (sport->dma_is_enabled && sport->dma_is_rxing) { + if (sport->dma_is_rxing) { if (sport->port.suspended) { dmaengine_terminate_all(sport->dma_chan_rx); sport->dma_is_rxing = 0; @@ -900,7 +900,7 @@ static unsigned int imx_tx_empty(struct uart_port *port) ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; /* If the TX DMA is working, return 0. */ - if (sport->dma_is_enabled && sport->dma_is_txing) + if (sport->dma_is_txing) ret = 0; return ret; -- cgit v1.2.3 From 0c54922384c14c1794c75af07c542752ab11787d Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:22 +0100 Subject: serial: imx: simplify check that prevents starting PIO when DMA is in use MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The original code looks as follows: if (sport->dma_is_enabled) { ... make sure TX DMA is running, i.e. .dma_is_txing = 1 } if (sport->dma_is_txing) return; As .dma_is_txing can only be true if .dma_is_enabled is, the return can go at the end of the first if body without an additional check. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index b87e04334342..7356a848751e 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -504,10 +504,9 @@ static inline void imx_transmit_buffer(struct imx_port *sport) imx_uart_writel(sport, temp, UCR1); imx_dma_tx(sport); } - } - if (sport->dma_is_txing) return; + } while (!uart_circ_empty(xmit) && !(imx_uart_readl(sport, uts_reg(sport)) & UTS_TXFULL)) { -- cgit v1.2.3 From 4444dcf1fe7ea5af4e335658742d7c6868d91941 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:23 +0100 Subject: serial: imx: use u32 variables with matching names for registers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The serial/imx driver is full of inconsistently named and typed variables that hold different register values. Consistently use u32 as type (matching what readl and writel use) and name the variables after the register whose value they are holding. This makes it easier to notice when UCR2_RTSEN is written to UCR1. The only difference introduced by this commit in the compiled driver is that twice the second argument to warn_slowpath_null() changed because the two WARN_ON in dma_rx_callback() pass __LINE__ to warn_slowpath_null(). Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 346 ++++++++++++++++++++++++----------------------- 1 file changed, 179 insertions(+), 167 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 7356a848751e..23d591897e82 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -381,7 +381,7 @@ static void imx_port_ucrs_restore(struct imx_port *sport, } #endif -static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) +static void imx_port_rts_active(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); @@ -389,7 +389,7 @@ static void imx_port_rts_active(struct imx_port *sport, unsigned long *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) +static void imx_port_rts_inactive(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; @@ -398,7 +398,7 @@ static void imx_port_rts_inactive(struct imx_port *sport, unsigned long *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) +static void imx_port_rts_auto(struct imx_port *sport, u32 *ucr2) { *ucr2 |= UCR2_CTSC; } @@ -407,7 +407,7 @@ static void imx_port_rts_auto(struct imx_port *sport, unsigned long *ucr2) static void imx_stop_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + u32 ucr1; /* * We are maybe in the SMP context, so if the DMA TX thread is running @@ -416,23 +416,23 @@ static void imx_stop_tx(struct uart_port *port) if (sport->dma_is_txing) return; - temp = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, temp & ~UCR1_TXMPTYEN, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, ucr1 & ~UCR1_TXMPTYEN, UCR1); /* in rs485 mode disable transmitter if shifter is empty */ if (port->rs485.flags & SER_RS485_ENABLED && imx_uart_readl(sport, USR2) & USR2_TXDC) { - temp = imx_uart_readl(sport, UCR2); + u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4; if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &temp); + imx_port_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &temp); - temp |= UCR2_RXEN; - imx_uart_writel(sport, temp, UCR2); + imx_port_rts_inactive(sport, &ucr2); + ucr2 |= UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); - temp = imx_uart_readl(sport, UCR4); - temp &= ~UCR4_TCEN; - imx_uart_writel(sport, temp, UCR4); + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 &= ~UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); } } @@ -440,7 +440,7 @@ static void imx_stop_tx(struct uart_port *port) static void imx_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + u32 ucr1, ucr2; if (sport->dma_is_rxing) { if (sport->port.suspended) { @@ -451,12 +451,12 @@ static void imx_stop_rx(struct uart_port *port) } } - temp = imx_uart_readl(sport, UCR2); - imx_uart_writel(sport, temp & ~UCR2_RXEN, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + imx_uart_writel(sport, ucr2 & ~UCR2_RXEN, UCR2); /* disable the `Receiver Ready Interrrupt` */ - temp = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, temp & ~UCR1_RRDYEN, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, ucr1 & ~UCR1_RRDYEN, UCR1); } /* called with port.lock taken and irqs off */ @@ -475,7 +475,6 @@ static void imx_dma_tx(struct imx_port *sport); static inline void imx_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; - unsigned long temp; if (sport->port.x_char) { /* Send next char */ @@ -491,17 +490,18 @@ static inline void imx_transmit_buffer(struct imx_port *sport) } if (sport->dma_is_enabled) { + u32 ucr1; /* * We've just sent a X-char Ensure the TX DMA is enabled * and the TX IRQ is disabled. **/ - temp = imx_uart_readl(sport, UCR1); - temp &= ~UCR1_TXMPTYEN; + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~UCR1_TXMPTYEN; if (sport->dma_is_txing) { - temp |= UCR1_TXDMAEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 |= UCR1_TXDMAEN; + imx_uart_writel(sport, ucr1, UCR1); } else { - imx_uart_writel(sport, temp, UCR1); + imx_uart_writel(sport, ucr1, UCR1); imx_dma_tx(sport); } @@ -530,15 +530,15 @@ static void dma_tx_callback(void *data) struct scatterlist *sgl = &sport->tx_sgl[0]; struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; - unsigned long temp; + u32 ucr1; spin_lock_irqsave(&sport->port.lock, flags); dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); - temp = imx_uart_readl(sport, UCR1); - temp &= ~UCR1_TXDMAEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~UCR1_TXDMAEN; + imx_uart_writel(sport, ucr1, UCR1); /* update the stat */ xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); @@ -565,7 +565,7 @@ static void imx_dma_tx(struct imx_port *sport) struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; struct device *dev = sport->port.dev; - unsigned long temp; + u32 ucr1; int ret; if (sport->dma_is_txing) @@ -603,9 +603,9 @@ static void imx_dma_tx(struct imx_port *sport) dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", uart_circ_chars_pending(xmit)); - temp = imx_uart_readl(sport, UCR1); - temp |= UCR1_TXDMAEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_TXDMAEN; + imx_uart_writel(sport, ucr1, UCR1); /* fire it */ sport->dma_is_txing = 1; @@ -618,37 +618,39 @@ static void imx_dma_tx(struct imx_port *sport) static void imx_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + u32 ucr1; if (port->rs485.flags & SER_RS485_ENABLED) { - temp = imx_uart_readl(sport, UCR2); + u32 ucr2, ucr4; + + ucr2 = imx_uart_readl(sport, UCR2); if (port->rs485.flags & SER_RS485_RTS_ON_SEND) - imx_port_rts_active(sport, &temp); + imx_port_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &temp); + imx_port_rts_inactive(sport, &ucr2); if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) - temp &= ~UCR2_RXEN; - imx_uart_writel(sport, temp, UCR2); + ucr2 &= ~UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); /* enable transmitter and shifter empty irq */ - temp = imx_uart_readl(sport, UCR4); - temp |= UCR4_TCEN; - imx_uart_writel(sport, temp, UCR4); + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 |= UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); } if (!sport->dma_is_enabled) { - temp = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, temp | UCR1_TXMPTYEN, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + imx_uart_writel(sport, ucr1 | UCR1_TXMPTYEN, UCR1); } if (sport->dma_is_enabled) { if (sport->port.x_char) { /* We have X-char to send, so enable TX IRQ and * disable TX DMA to let TX interrupt to send X-char */ - temp = imx_uart_readl(sport, UCR1); - temp &= ~UCR1_TXDMAEN; - temp |= UCR1_TXMPTYEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~UCR1_TXDMAEN; + ucr1 |= UCR1_TXMPTYEN; + imx_uart_writel(sport, ucr1, UCR1); return; } @@ -662,14 +664,14 @@ static void imx_start_tx(struct uart_port *port) static irqreturn_t imx_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; - unsigned int val; + u32 usr1; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); imx_uart_writel(sport, USR1_RTSD, USR1); - val = imx_uart_readl(sport, USR1) & USR1_RTSS; - uart_handle_cts_change(&sport->port, !!val); + usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS; + uart_handle_cts_change(&sport->port, !!usr1); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -692,18 +694,20 @@ static irqreturn_t imx_rxint(int irq, void *dev_id) struct imx_port *sport = dev_id; unsigned int rx, flg, ignored = 0; struct tty_port *port = &sport->port.state->port; - unsigned long flags, temp; + unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); while (imx_uart_readl(sport, USR2) & USR2_RDR) { + u32 usr2; + flg = TTY_NORMAL; sport->port.icount.rx++; rx = imx_uart_readl(sport, URXD0); - temp = imx_uart_readl(sport, USR2); - if (temp & USR2_BRCD) { + usr2 = imx_uart_readl(sport, USR2); + if (usr2 & USR2_BRCD) { imx_uart_writel(sport, USR2_BRCD, USR2); if (uart_handle_break(&sport->port)) continue; @@ -920,25 +924,27 @@ static unsigned int imx_get_mctrl(struct uart_port *port) static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + u32 ucr3, uts; if (!(port->rs485.flags & SER_RS485_ENABLED)) { - temp = imx_uart_readl(sport, UCR2); - temp &= ~(UCR2_CTS | UCR2_CTSC); + u32 ucr2; + + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~(UCR2_CTS | UCR2_CTSC); if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS | UCR2_CTSC; - imx_uart_writel(sport, temp, UCR2); + ucr2 |= UCR2_CTS | UCR2_CTSC; + imx_uart_writel(sport, ucr2, UCR2); } - temp = imx_uart_readl(sport, UCR3) & ~UCR3_DSR; + ucr3 = imx_uart_readl(sport, UCR3) & ~UCR3_DSR; if (!(mctrl & TIOCM_DTR)) - temp |= UCR3_DSR; - imx_uart_writel(sport, temp, UCR3); + ucr3 |= UCR3_DSR; + imx_uart_writel(sport, ucr3, UCR3); - temp = imx_uart_readl(sport, uts_reg(sport)) & ~UTS_LOOP; + uts = imx_uart_readl(sport, uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) - temp |= UTS_LOOP; - imx_uart_writel(sport, temp, uts_reg(sport)); + uts |= UTS_LOOP; + imx_uart_writel(sport, uts, uts_reg(sport)); mctrl_gpio_set(sport->gpios, mctrl); } @@ -949,16 +955,17 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) static void imx_break_ctl(struct uart_port *port, int break_state) { struct imx_port *sport = (struct imx_port *)port; - unsigned long flags, temp; + unsigned long flags; + u32 ucr1; spin_lock_irqsave(&sport->port.lock, flags); - temp = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK; + ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_SNDBRK; if (break_state != 0) - temp |= UCR1_SNDBRK; + ucr1 |= UCR1_SNDBRK; - imx_uart_writel(sport, temp, UCR1); + imx_uart_writel(sport, ucr1, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -1108,12 +1115,12 @@ static int start_rx_dma(struct imx_port *sport) static void clear_rx_errors(struct imx_port *sport) { struct tty_port *port = &sport->port.state->port; - unsigned int status_usr1, status_usr2; + u32 usr1, usr2; - status_usr1 = imx_uart_readl(sport, USR1); - status_usr2 = imx_uart_readl(sport, USR2); + usr1 = imx_uart_readl(sport, USR1); + usr2 = imx_uart_readl(sport, USR2); - if (status_usr2 & USR2_BRCD) { + if (usr2 & USR2_BRCD) { sport->port.icount.brk++; imx_uart_writel(sport, USR2_BRCD, USR2); uart_handle_break(&sport->port); @@ -1122,16 +1129,16 @@ static void clear_rx_errors(struct imx_port *sport) tty_flip_buffer_push(port); } else { dev_err(sport->port.dev, "DMA transaction error.\n"); - if (status_usr1 & USR1_FRAMERR) { + if (usr1 & USR1_FRAMERR) { sport->port.icount.frame++; imx_uart_writel(sport, USR1_FRAMERR, USR1); - } else if (status_usr1 & USR1_PARITYERR) { + } else if (usr1 & USR1_PARITYERR) { sport->port.icount.parity++; imx_uart_writel(sport, USR1_PARITYERR, USR1); } } - if (status_usr2 & USR2_ORE) { + if (usr2 & USR2_ORE) { sport->port.icount.overrun++; imx_uart_writel(sport, USR2_ORE, USR2); } @@ -1230,12 +1237,12 @@ err: static void imx_enable_dma(struct imx_port *sport) { - unsigned long temp; + u32 ucr1; /* set UCR1 */ - temp = imx_uart_readl(sport, UCR1); - temp |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; + imx_uart_writel(sport, ucr1, UCR1); imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); @@ -1244,17 +1251,17 @@ static void imx_enable_dma(struct imx_port *sport) static void imx_disable_dma(struct imx_port *sport) { - unsigned long temp; + u32 ucr1, ucr2; /* clear UCR1 */ - temp = imx_uart_readl(sport, UCR1); - temp &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~(UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN); + imx_uart_writel(sport, ucr1, UCR1); /* clear UCR2 */ - temp = imx_uart_readl(sport, UCR2); - temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); + imx_uart_writel(sport, ucr2, UCR2); imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); @@ -1268,8 +1275,9 @@ static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; int retval, i; - unsigned long flags, temp; + unsigned long flags; int dma_is_inited = 0; + u32 ucr1, ucr2, ucr4; retval = clk_prepare_enable(sport->clk_per); if (retval) @@ -1285,13 +1293,13 @@ static int imx_startup(struct uart_port *port) /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs */ - temp = imx_uart_readl(sport, UCR4); + ucr4 = imx_uart_readl(sport, UCR4); /* set the trigger level for CTS */ - temp &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); - temp |= CTSTL << UCR4_CTSTL_SHF; + ucr4 &= ~(UCR4_CTSTL_MASK << UCR4_CTSTL_SHF); + ucr4 |= CTSTL << UCR4_CTSTL_SHF; - imx_uart_writel(sport, temp & ~UCR4_DREN, UCR4); + imx_uart_writel(sport, ucr4 & ~UCR4_DREN, UCR4); /* Can we enable the DMA support? */ if (!uart_console(port) && imx_uart_dma_init(sport) == 0) @@ -1301,9 +1309,9 @@ static int imx_startup(struct uart_port *port) /* Reset fifo's and state machines */ i = 100; - temp = imx_uart_readl(sport, UCR2); - temp &= ~UCR2_SRST; - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~UCR2_SRST; + imx_uart_writel(sport, ucr2, UCR2); while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); @@ -1317,42 +1325,44 @@ static int imx_startup(struct uart_port *port) if (dma_is_inited) imx_enable_dma(sport); - temp = imx_uart_readl(sport, UCR1) & ~UCR1_RRDYEN; + ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_RRDYEN; if (!sport->dma_is_enabled) - temp |= UCR1_RRDYEN; - temp |= UCR1_UARTEN; + ucr1 |= UCR1_RRDYEN; + ucr1 |= UCR1_UARTEN; if (sport->have_rtscts) - temp |= UCR1_RTSDEN; + ucr1 |= UCR1_RTSDEN; - imx_uart_writel(sport, temp, UCR1); + imx_uart_writel(sport, ucr1, UCR1); - temp = imx_uart_readl(sport, UCR4) & ~UCR4_OREN; + ucr4 = imx_uart_readl(sport, UCR4) & ~UCR4_OREN; if (!sport->dma_is_enabled) - temp |= UCR4_OREN; - imx_uart_writel(sport, temp, UCR4); + ucr4 |= UCR4_OREN; + imx_uart_writel(sport, ucr4, UCR4); - temp = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN; - temp |= (UCR2_RXEN | UCR2_TXEN); + ucr2 = imx_uart_readl(sport, UCR2) & ~UCR2_ATEN; + ucr2 |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) - temp |= UCR2_IRTS; + ucr2 |= UCR2_IRTS; /* * make sure the edge sensitive RTS-irq is disabled, * we're using RTSD instead. */ if (!is_imx1_uart(sport)) - temp &= ~UCR2_RTSEN; - imx_uart_writel(sport, temp, UCR2); + ucr2 &= ~UCR2_RTSEN; + imx_uart_writel(sport, ucr2, UCR2); if (!is_imx1_uart(sport)) { - temp = imx_uart_readl(sport, UCR3); + u32 ucr3; + + ucr3 = imx_uart_readl(sport, UCR3); - temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; + ucr3 |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; if (sport->dte_mode) /* disable broken interrupts */ - temp &= ~(UCR3_RI | UCR3_DCD); + ucr3 &= ~(UCR3_RI | UCR3_DCD); - imx_uart_writel(sport, temp, UCR3); + imx_uart_writel(sport, ucr3, UCR3); } /* @@ -1376,8 +1386,8 @@ static int imx_startup(struct uart_port *port) static void imx_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; unsigned long flags; + u32 ucr1, ucr2; if (sport->dma_is_enabled) { sport->dma_is_rxing = 0; @@ -1396,9 +1406,9 @@ static void imx_shutdown(struct uart_port *port) mctrl_gpio_disable_ms(sport->gpios); spin_lock_irqsave(&sport->port.lock, flags); - temp = imx_uart_readl(sport, UCR2); - temp &= ~(UCR2_TXEN); - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~UCR2_TXEN; + imx_uart_writel(sport, ucr2, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); /* @@ -1411,10 +1421,10 @@ static void imx_shutdown(struct uart_port *port) */ spin_lock_irqsave(&sport->port.lock, flags); - temp = imx_uart_readl(sport, UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - imx_uart_writel(sport, temp, UCR1); + imx_uart_writel(sport, ucr1, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); clk_disable_unprepare(sport->clk_per); @@ -1426,7 +1436,7 @@ static void imx_flush_buffer(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; struct scatterlist *sgl = &sport->tx_sgl[0]; - unsigned long temp; + u32 ucr2; int i = 100, ubir, ubmr, uts; if (!sport->dma_chan_tx) @@ -1435,11 +1445,13 @@ static void imx_flush_buffer(struct uart_port *port) sport->tx_bytes = 0; dmaengine_terminate_all(sport->dma_chan_tx); if (sport->dma_is_txing) { + u32 ucr1; + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); - temp = imx_uart_readl(sport, UCR1); - temp &= ~UCR1_TXDMAEN; - imx_uart_writel(sport, temp, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~UCR1_TXDMAEN; + imx_uart_writel(sport, ucr1, UCR1); sport->dma_is_txing = 0; } @@ -1458,9 +1470,9 @@ static void imx_flush_buffer(struct uart_port *port) ubmr = imx_uart_readl(sport, UBMR); uts = imx_uart_readl(sport, IMX21_UTS); - temp = imx_uart_readl(sport, UCR2); - temp &= ~UCR2_SRST; - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 &= ~UCR2_SRST; + imx_uart_writel(sport, ucr2, UCR2); while (!(imx_uart_readl(sport, UCR2) & UCR2_SRST) && (--i > 0)) udelay(1); @@ -1477,10 +1489,10 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned long ucr2, old_ucr1, old_ucr2; + u32 ucr2, old_ucr1, old_ucr2, ufcr; unsigned int baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; - unsigned long div, ufcr; + unsigned long div; unsigned long num, denom; uint64_t tdiv64; @@ -1690,7 +1702,7 @@ static int imx_poll_init(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned long temp; + u32 ucr1, ucr2; int retval; retval = clk_prepare_enable(sport->clk_ipg); @@ -1704,16 +1716,16 @@ static int imx_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); - temp = imx_uart_readl(sport, UCR1); + ucr1 = imx_uart_readl(sport, UCR1); if (is_imx1_uart(sport)) - temp |= IMX1_UCR1_UARTCLKEN; - temp |= UCR1_UARTEN | UCR1_RRDYEN; - temp &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); - imx_uart_writel(sport, temp, UCR1); + ucr1 |= IMX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN | UCR1_RRDYEN; + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); + imx_uart_writel(sport, ucr1, UCR1); - temp = imx_uart_readl(sport, UCR2); - temp |= UCR2_RXEN; - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 |= UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1754,7 +1766,7 @@ static int imx_rs485_config(struct uart_port *port, struct serial_rs485 *rs485conf) { struct imx_port *sport = (struct imx_port *)port; - unsigned long temp; + u32 ucr2; /* unimplemented */ rs485conf->delay_rts_before_send = 0; @@ -1766,20 +1778,20 @@ static int imx_rs485_config(struct uart_port *port, if (rs485conf->flags & SER_RS485_ENABLED) { /* disable transmitter */ - temp = imx_uart_readl(sport, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &temp); + imx_port_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &temp); - imx_uart_writel(sport, temp, UCR2); + imx_port_rts_inactive(sport, &ucr2); + imx_uart_writel(sport, ucr2, UCR2); } /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || rs485conf->flags & SER_RS485_RX_DURING_TX) { - temp = imx_uart_readl(sport, UCR2); - temp |= UCR2_RXEN; - imx_uart_writel(sport, temp, UCR2); + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 |= UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); } port->rs485 = *rs485conf; @@ -2118,7 +2130,8 @@ static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; void __iomem *base; - int ret = 0, reg; + int ret = 0; + u32 ucr1; struct resource *res; int txirq, rxirq, rtsirq; @@ -2202,10 +2215,10 @@ static int serial_imx_probe(struct platform_device *pdev) imx_rs485_config(&sport->port, &sport->port.rs485); /* Disable interrupts before requesting them */ - reg = imx_uart_readl(sport, UCR1); - reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | UCR1_TXMPTYEN | UCR1_RTSDEN); - imx_uart_writel(sport, reg, UCR1); + imx_uart_writel(sport, ucr1, UCR1); if (!is_imx1_uart(sport) && sport->dte_mode) { /* @@ -2214,9 +2227,9 @@ static int serial_imx_probe(struct platform_device *pdev) * and DCD (when they are outputs) or enables the respective * irqs. So set this bit early, i.e. before requesting irqs. */ - reg = imx_uart_readl(sport, UFCR); - if (!(reg & UFCR_DCEDTE)) - imx_uart_writel(sport, reg | UFCR_DCEDTE, UFCR); + u32 ufcr = imx_uart_readl(sport, UFCR); + if (!(ufcr & UFCR_DCEDTE)) + imx_uart_writel(sport, ufcr | UFCR_DCEDTE, UFCR); /* * Disable UCR3_RI and UCR3_DCD irqs. They are also not @@ -2228,11 +2241,10 @@ static int serial_imx_probe(struct platform_device *pdev) UCR3); } else { - unsigned long ucr3 = UCR3_DSR; - - reg = imx_uart_readl(sport, UFCR); - if (reg & UFCR_DCEDTE) - imx_uart_writel(sport, reg & ~UFCR_DCEDTE, UFCR); + u32 ucr3 = UCR3_DSR; + u32 ufcr = imx_uart_readl(sport, UFCR); + if (ufcr & UFCR_DCEDTE) + imx_uart_writel(sport, ufcr & ~UFCR_DCEDTE, UFCR); if (!is_imx1_uart(sport)) ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; @@ -2320,24 +2332,24 @@ static void serial_imx_save_context(struct imx_port *sport) static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) { - unsigned int val; + u32 ucr3; - val = imx_uart_readl(sport, UCR3); + ucr3 = imx_uart_readl(sport, UCR3); if (on) { imx_uart_writel(sport, USR1_AWAKE, USR1); - val |= UCR3_AWAKEN; + ucr3 |= UCR3_AWAKEN; + } else { + ucr3 &= ~UCR3_AWAKEN; } - else - val &= ~UCR3_AWAKEN; - imx_uart_writel(sport, val, UCR3); + imx_uart_writel(sport, ucr3, UCR3); if (sport->have_rtscts) { - val = imx_uart_readl(sport, UCR1); + u32 ucr1 = imx_uart_readl(sport, UCR1); if (on) - val |= UCR1_RTSDEN; + ucr1 |= UCR1_RTSDEN; else - val &= ~UCR1_RTSDEN; - imx_uart_writel(sport, val, UCR1); + ucr1 &= ~UCR1_RTSDEN; + imx_uart_writel(sport, ucr1, UCR1); } } -- cgit v1.2.3 From 02b0abd3bb93ea1d9818c5c5b1fcf293f81cee37 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:24 +0100 Subject: serial: imx: setup fifo waterlevel before enabling aging timer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The aging timer fires if there are characters in the RX fifo but the water level isn't reached yet. Make sure that the waterlevel is configured before the aging timer is enabled to trigger a DMA request (UCR1_ATDMAEN). Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 23d591897e82..9b92c49fc174 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -1239,13 +1239,13 @@ static void imx_enable_dma(struct imx_port *sport) { u32 ucr1; + imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + /* set UCR1 */ ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_RXDMAEN | UCR1_TXDMAEN | UCR1_ATDMAEN; imx_uart_writel(sport, ucr1, UCR1); - imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); - sport->dma_is_enabled = 1; } -- cgit v1.2.3 From dedc64e02f5da1c7bd0b4ec232341047a8b0142b Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:25 +0100 Subject: serial: imx: Stop to receive in .stop_rx() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When the UART is used in DMA mode, .stop_rx() does nothing if the port isn't suspended. This is wrong as .stop_rx() should stop receiving characters unconditionally. When the port is about to be closed the DMA channel is stopped in .shutdown(), so this isn't necessary to be in .stop_rx() here, too. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 9 --------- 1 file changed, 9 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 9b92c49fc174..0ea98827ecbe 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -442,15 +442,6 @@ static void imx_stop_rx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; u32 ucr1, ucr2; - if (sport->dma_is_rxing) { - if (sport->port.suspended) { - dmaengine_terminate_all(sport->dma_chan_rx); - sport->dma_is_rxing = 0; - } else { - return; - } - } - ucr2 = imx_uart_readl(sport, UCR2); imx_uart_writel(sport, ucr2 & ~UCR2_RXEN, UCR2); -- cgit v1.2.3 From 76821e222c189b81d553b855ee7054340607eb46 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:26 +0100 Subject: serial: imx: ensure that RX irqs are off if RX is off MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make sure that UCR1.RXDMAEN and UCR1.ATDMAEN (for the DMA case) and UCR1.RRDYEN (for the PIO case) are off iff UCR1.RXEN is disabled. This ensures that the fifo isn't read with RX disabled which results in an exception. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 92 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 28 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 0ea98827ecbe..3c1bfe8742a4 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -403,6 +403,28 @@ static void imx_port_rts_auto(struct imx_port *sport, u32 *ucr2) *ucr2 |= UCR2_CTSC; } +/* called with port.lock taken and irqs off */ +static void imx_start_rx(struct uart_port *port) +{ + struct imx_port *sport = (struct imx_port *)port; + unsigned int ucr1, ucr2; + + ucr1 = imx_uart_readl(sport, UCR1); + ucr2 = imx_uart_readl(sport, UCR2); + + ucr2 |= UCR2_RXEN; + + if (sport->dma_is_enabled) { + ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; + } else { + ucr1 |= UCR1_RRDYEN; + } + + /* Write UCR2 first as it includes RXEN */ + imx_uart_writel(sport, ucr2, UCR2); + imx_uart_writel(sport, ucr1, UCR1); +} + /* called with port.lock taken and irqs off */ static void imx_stop_tx(struct uart_port *port) { @@ -427,9 +449,10 @@ static void imx_stop_tx(struct uart_port *port) imx_port_rts_active(sport, &ucr2); else imx_port_rts_inactive(sport, &ucr2); - ucr2 |= UCR2_RXEN; imx_uart_writel(sport, ucr2, UCR2); + imx_start_rx(port); + ucr4 = imx_uart_readl(sport, UCR4); ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); @@ -442,12 +465,18 @@ static void imx_stop_rx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; u32 ucr1, ucr2; + ucr1 = imx_uart_readl(sport, UCR1); ucr2 = imx_uart_readl(sport, UCR2); - imx_uart_writel(sport, ucr2 & ~UCR2_RXEN, UCR2); - /* disable the `Receiver Ready Interrrupt` */ - ucr1 = imx_uart_readl(sport, UCR1); - imx_uart_writel(sport, ucr1 & ~UCR1_RRDYEN, UCR1); + if (sport->dma_is_enabled) { + ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN); + } else { + ucr1 &= ~UCR1_RRDYEN; + } + imx_uart_writel(sport, ucr1, UCR1); + + ucr2 &= ~UCR2_RXEN; + imx_uart_writel(sport, ucr2, UCR2); } /* called with port.lock taken and irqs off */ @@ -619,10 +648,11 @@ static void imx_start_tx(struct uart_port *port) imx_port_rts_active(sport, &ucr2); else imx_port_rts_inactive(sport, &ucr2); - if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) - ucr2 &= ~UCR2_RXEN; imx_uart_writel(sport, ucr2, UCR2); + if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) + imx_stop_rx(port); + /* enable transmitter and shifter empty irq */ ucr4 = imx_uart_readl(sport, UCR4); ucr4 |= UCR4_TCEN; @@ -1313,12 +1343,7 @@ static int imx_startup(struct uart_port *port) imx_uart_writel(sport, USR1_RTSD | USR1_DTRD, USR1); imx_uart_writel(sport, USR2_ORE, USR2); - if (dma_is_inited) - imx_enable_dma(sport); - ucr1 = imx_uart_readl(sport, UCR1) & ~UCR1_RRDYEN; - if (!sport->dma_is_enabled) - ucr1 |= UCR1_RRDYEN; ucr1 |= UCR1_UARTEN; if (sport->have_rtscts) ucr1 |= UCR1_RTSDEN; @@ -1361,13 +1386,14 @@ static int imx_startup(struct uart_port *port) */ imx_enable_ms(&sport->port); - /* - * Start RX DMA immediately instead of waiting for RX FIFO interrupts. - * In our iMX53 the average delay for the first reception dropped from - * approximately 35000 microseconds to 1000 microseconds. - */ - if (sport->dma_is_enabled) + if (dma_is_inited) { + imx_enable_dma(sport); start_rx_dma(sport); + } else { + ucr1 = imx_uart_readl(sport, UCR1); + ucr1 |= UCR1_RRDYEN; + imx_uart_writel(sport, ucr1, UCR1); + } spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1413,7 +1439,7 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); ucr1 = imx_uart_readl(sport, UCR1); - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN | UCR1_RXDMAEN | UCR1_ATDMAEN); imx_uart_writel(sport, ucr1, UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1707,17 +1733,30 @@ static int imx_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); + /* + * Be careful about the order of enabling bits here. First enable the + * receiver (UARTEN + RXEN) and only then the corresponding irqs. + * This prevents that a character that already sits in the RX fifo is + * triggering an irq but the try to fetch it from there results in an + * exception because UARTEN or RXEN is still off. + */ ucr1 = imx_uart_readl(sport, UCR1); + ucr2 = imx_uart_readl(sport, UCR2); + if (is_imx1_uart(sport)) ucr1 |= IMX1_UCR1_UARTCLKEN; - ucr1 |= UCR1_UARTEN | UCR1_RRDYEN; - ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN); - imx_uart_writel(sport, ucr1, UCR1); - ucr2 = imx_uart_readl(sport, UCR2); + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN); + ucr2 |= UCR2_RXEN; + + imx_uart_writel(sport, ucr1, UCR1); imx_uart_writel(sport, ucr2, UCR2); + /* now enable irqs */ + imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1); + spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -1779,11 +1818,8 @@ static int imx_rs485_config(struct uart_port *port, /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || - rs485conf->flags & SER_RS485_RX_DURING_TX) { - ucr2 = imx_uart_readl(sport, UCR2); - ucr2 |= UCR2_RXEN; - imx_uart_writel(sport, ucr2, UCR2); - } + rs485conf->flags & SER_RS485_RX_DURING_TX) + imx_start_rx(port); port->rs485 = *rs485conf; -- cgit v1.2.3 From 81ca8e8286c48df22eb798879d99aabac663b5f1 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:27 +0100 Subject: serial: imx: Also enable the aging timer in PIO mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows to increase the RX waterlevel which allows to delay the RRDY irq. The desired effect is that less irqs are needed to handle characters and so reduce irq count of the system. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 3c1bfe8742a4..e1f00d5aced9 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -418,6 +418,7 @@ static void imx_start_rx(struct uart_port *port) ucr1 |= UCR1_RXDMAEN | UCR1_ATDMAEN; } else { ucr1 |= UCR1_RRDYEN; + ucr2 |= UCR2_ATEN; } /* Write UCR2 first as it includes RXEN */ @@ -472,6 +473,7 @@ static void imx_stop_rx(struct uart_port *port) ucr1 &= ~(UCR1_RXDMAEN | UCR1_ATDMAEN); } else { ucr1 &= ~UCR1_RRDYEN; + ucr2 &= ~UCR2_ATEN; } imx_uart_writel(sport, ucr1, UCR1); @@ -1393,6 +1395,10 @@ static int imx_startup(struct uart_port *port) ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_RRDYEN; imx_uart_writel(sport, ucr1, UCR1); + + ucr2 = imx_uart_readl(sport, UCR2); + ucr2 |= UCR2_ATEN; + imx_uart_writel(sport, ucr2, UCR2); } spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1424,7 +1430,7 @@ static void imx_shutdown(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); ucr2 = imx_uart_readl(sport, UCR2); - ucr2 &= ~UCR2_TXEN; + ucr2 &= ~(UCR2_TXEN | UCR2_ATEN); imx_uart_writel(sport, ucr2, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1613,13 +1619,14 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, imx_uart_writel(sport, old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN), UCR1); + old_ucr2 = imx_uart_readl(sport, UCR2); + imx_uart_writel(sport, old_ucr2 & ~UCR2_ATEN, UCR2); while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)) barrier(); /* then, disable everything */ - old_ucr2 = imx_uart_readl(sport, UCR2); - imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN), UCR2); + imx_uart_writel(sport, old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN | UCR2_ATEN), UCR2); old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN); /* custom-baudrate handling */ @@ -1750,12 +1757,14 @@ static int imx_poll_init(struct uart_port *port) ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RTSDEN | UCR1_RRDYEN); ucr2 |= UCR2_RXEN; + ucr2 &= ~UCR2_ATEN; imx_uart_writel(sport, ucr1, UCR1); imx_uart_writel(sport, ucr2, UCR2); /* now enable irqs */ imx_uart_writel(sport, ucr1 | UCR1_RRDYEN, UCR1); + imx_uart_writel(sport, ucr2 | UCR2_ATEN, UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); -- cgit v1.2.3 From 1866541492641c02874bf51f9d8712b5510f2c64 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:28 +0100 Subject: serial: imx: Fix handling of TC irq in combination with DMA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When using RS485 half duplex the Transmitter Complete irq is needed to determine the moment when the transmitter can be disabled. When using DMA this irq must only be enabled when DMA has completed to transfer all data. Otherwise the CPU might busily trigger this irq which is not properly handled and so the also pending irq for the DMA transfer cannot trigger. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e1f00d5aced9..80456ea2603a 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -575,6 +575,11 @@ static void dma_tx_callback(void *data) if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) imx_dma_tx(sport); + else if (sport->port.rs485.flags & SER_RS485_ENABLED) { + u32 ucr4 = imx_uart_readl(sport, UCR4); + ucr4 |= UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + } spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -587,12 +592,16 @@ static void imx_dma_tx(struct imx_port *sport) struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; struct device *dev = sport->port.dev; - u32 ucr1; + u32 ucr1, ucr4; int ret; if (sport->dma_is_txing) return; + ucr4 = imx_uart_readl(sport, UCR4); + ucr4 &= ~UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + sport->tx_bytes = uart_circ_chars_pending(xmit); if (xmit->tail < xmit->head) { @@ -643,7 +652,7 @@ static void imx_start_tx(struct uart_port *port) u32 ucr1; if (port->rs485.flags & SER_RS485_ENABLED) { - u32 ucr2, ucr4; + u32 ucr2; ucr2 = imx_uart_readl(sport, UCR2); if (port->rs485.flags & SER_RS485_RTS_ON_SEND) @@ -655,10 +664,15 @@ static void imx_start_tx(struct uart_port *port) if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) imx_stop_rx(port); - /* enable transmitter and shifter empty irq */ - ucr4 = imx_uart_readl(sport, UCR4); - ucr4 |= UCR4_TCEN; - imx_uart_writel(sport, ucr4, UCR4); + /* + * Enable transmitter and shifter empty irq only if DMA is off. + * In the DMA case this is done in the tx-callback. + */ + if (!sport->dma_is_enabled) { + u32 ucr4 = imx_uart_readl(sport, UCR4); + ucr4 |= UCR4_TCEN; + imx_uart_writel(sport, ucr4, UCR4); + } } if (!sport->dma_is_enabled) { -- cgit v1.2.3 From 48669b69e3ecbabbd2936fbbe095901ba83a37f9 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:29 +0100 Subject: serial: imx: don't prepare to send if no data is available MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit serial_core might call the .start_tx callback without any data being available to send. In this case return early instead of going through all the setup needed for sending which might include disabling RX in RS485 half-duplex mode. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 80456ea2603a..3a954194d2f6 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -651,6 +651,9 @@ static void imx_start_tx(struct uart_port *port) struct imx_port *sport = (struct imx_port *)port; u32 ucr1; + if (!sport->port.x_char && uart_circ_empty(&port->state->xmit)) + return; + if (port->rs485.flags & SER_RS485_ENABLED) { u32 ucr2; -- cgit v1.2.3 From 9d1a50a2cceb3a8589531f7a2652f1a478df8907 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 2 Mar 2018 11:07:30 +0100 Subject: serial: imx: consistently use imx_uart_ as prefix for all functions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having a fixed prefix helps at several places. It ensures that another driver doesn't use the same function name which confuses the linker and tools like ctags. It simplifies working with function tracing and dynamic printk() support which can filter on function names. And last but not least it helps the human source code reader to understand if a given function belongs to a driver or a more general part of the kernel. Signed-off-by: Uwe Kleine-König Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/imx.c | 426 +++++++++++++++++++++++------------------------ 1 file changed, 213 insertions(+), 213 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index 3a954194d2f6..552fd050f2bb 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -334,27 +334,27 @@ static u32 imx_uart_readl(struct imx_port *sport, u32 offset) } } -static inline unsigned uts_reg(struct imx_port *sport) +static inline unsigned imx_uart_uts_reg(struct imx_port *sport) { return sport->devdata->uts_reg; } -static inline int is_imx1_uart(struct imx_port *sport) +static inline int imx_uart_is_imx1(struct imx_port *sport) { return sport->devdata->devtype == IMX1_UART; } -static inline int is_imx21_uart(struct imx_port *sport) +static inline int imx_uart_is_imx21(struct imx_port *sport) { return sport->devdata->devtype == IMX21_UART; } -static inline int is_imx53_uart(struct imx_port *sport) +static inline int imx_uart_is_imx53(struct imx_port *sport) { return sport->devdata->devtype == IMX53_UART; } -static inline int is_imx6q_uart(struct imx_port *sport) +static inline int imx_uart_is_imx6q(struct imx_port *sport) { return sport->devdata->devtype == IMX6Q_UART; } @@ -362,7 +362,7 @@ static inline int is_imx6q_uart(struct imx_port *sport) * Save and restore functions for UCR1, UCR2 and UCR3 registers */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) -static void imx_port_ucrs_save(struct imx_port *sport, +static void imx_uart_ucrs_save(struct imx_port *sport, struct imx_port_ucrs *ucr) { /* save control registers */ @@ -371,7 +371,7 @@ static void imx_port_ucrs_save(struct imx_port *sport, ucr->ucr3 = imx_uart_readl(sport, UCR3); } -static void imx_port_ucrs_restore(struct imx_port *sport, +static void imx_uart_ucrs_restore(struct imx_port *sport, struct imx_port_ucrs *ucr) { /* restore control registers */ @@ -381,7 +381,7 @@ static void imx_port_ucrs_restore(struct imx_port *sport, } #endif -static void imx_port_rts_active(struct imx_port *sport, u32 *ucr2) +static void imx_uart_rts_active(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~(UCR2_CTSC | UCR2_CTS); @@ -389,7 +389,7 @@ static void imx_port_rts_active(struct imx_port *sport, u32 *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -static void imx_port_rts_inactive(struct imx_port *sport, u32 *ucr2) +static void imx_uart_rts_inactive(struct imx_port *sport, u32 *ucr2) { *ucr2 &= ~UCR2_CTSC; *ucr2 |= UCR2_CTS; @@ -398,13 +398,13 @@ static void imx_port_rts_inactive(struct imx_port *sport, u32 *ucr2) mctrl_gpio_set(sport->gpios, sport->port.mctrl); } -static void imx_port_rts_auto(struct imx_port *sport, u32 *ucr2) +static void imx_uart_rts_auto(struct imx_port *sport, u32 *ucr2) { *ucr2 |= UCR2_CTSC; } /* called with port.lock taken and irqs off */ -static void imx_start_rx(struct uart_port *port) +static void imx_uart_start_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned int ucr1, ucr2; @@ -427,7 +427,7 @@ static void imx_start_rx(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static void imx_stop_tx(struct uart_port *port) +static void imx_uart_stop_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; u32 ucr1; @@ -447,12 +447,12 @@ static void imx_stop_tx(struct uart_port *port) imx_uart_readl(sport, USR2) & USR2_TXDC) { u32 ucr2 = imx_uart_readl(sport, UCR2), ucr4; if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &ucr2); + imx_uart_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &ucr2); + imx_uart_rts_inactive(sport, &ucr2); imx_uart_writel(sport, ucr2, UCR2); - imx_start_rx(port); + imx_uart_start_rx(port); ucr4 = imx_uart_readl(sport, UCR4); ucr4 &= ~UCR4_TCEN; @@ -461,7 +461,7 @@ static void imx_stop_tx(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static void imx_stop_rx(struct uart_port *port) +static void imx_uart_stop_rx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; u32 ucr1, ucr2; @@ -482,7 +482,7 @@ static void imx_stop_rx(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static void imx_enable_ms(struct uart_port *port) +static void imx_uart_enable_ms(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -491,10 +491,10 @@ static void imx_enable_ms(struct uart_port *port) mctrl_gpio_enable_ms(sport->gpios); } -static void imx_dma_tx(struct imx_port *sport); +static void imx_uart_dma_tx(struct imx_port *sport); /* called with port.lock taken and irqs off */ -static inline void imx_transmit_buffer(struct imx_port *sport) +static inline void imx_uart_transmit_buffer(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; @@ -507,7 +507,7 @@ static inline void imx_transmit_buffer(struct imx_port *sport) } if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - imx_stop_tx(&sport->port); + imx_uart_stop_tx(&sport->port); return; } @@ -524,14 +524,14 @@ static inline void imx_transmit_buffer(struct imx_port *sport) imx_uart_writel(sport, ucr1, UCR1); } else { imx_uart_writel(sport, ucr1, UCR1); - imx_dma_tx(sport); + imx_uart_dma_tx(sport); } return; } while (!uart_circ_empty(xmit) && - !(imx_uart_readl(sport, uts_reg(sport)) & UTS_TXFULL)) { + !(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ imx_uart_writel(sport, xmit->buf[xmit->tail], URTX0); @@ -543,10 +543,10 @@ static inline void imx_transmit_buffer(struct imx_port *sport) uart_write_wakeup(&sport->port); if (uart_circ_empty(xmit)) - imx_stop_tx(&sport->port); + imx_uart_stop_tx(&sport->port); } -static void dma_tx_callback(void *data) +static void imx_uart_dma_tx_callback(void *data) { struct imx_port *sport = data; struct scatterlist *sgl = &sport->tx_sgl[0]; @@ -574,7 +574,7 @@ static void dma_tx_callback(void *data) uart_write_wakeup(&sport->port); if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) - imx_dma_tx(sport); + imx_uart_dma_tx(sport); else if (sport->port.rs485.flags & SER_RS485_ENABLED) { u32 ucr4 = imx_uart_readl(sport, UCR4); ucr4 |= UCR4_TCEN; @@ -585,7 +585,7 @@ static void dma_tx_callback(void *data) } /* called with port.lock taken and irqs off */ -static void imx_dma_tx(struct imx_port *sport) +static void imx_uart_dma_tx(struct imx_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; struct scatterlist *sgl = sport->tx_sgl; @@ -628,7 +628,7 @@ static void imx_dma_tx(struct imx_port *sport) dev_err(dev, "We cannot prepare for the TX slave dma!\n"); return; } - desc->callback = dma_tx_callback; + desc->callback = imx_uart_dma_tx_callback; desc->callback_param = sport; dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", @@ -646,7 +646,7 @@ static void imx_dma_tx(struct imx_port *sport) } /* called with port.lock taken and irqs off */ -static void imx_start_tx(struct uart_port *port) +static void imx_uart_start_tx(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; u32 ucr1; @@ -659,13 +659,13 @@ static void imx_start_tx(struct uart_port *port) ucr2 = imx_uart_readl(sport, UCR2); if (port->rs485.flags & SER_RS485_RTS_ON_SEND) - imx_port_rts_active(sport, &ucr2); + imx_uart_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &ucr2); + imx_uart_rts_inactive(sport, &ucr2); imx_uart_writel(sport, ucr2, UCR2); if (!(port->rs485.flags & SER_RS485_RX_DURING_TX)) - imx_stop_rx(port); + imx_uart_stop_rx(port); /* * Enable transmitter and shifter empty irq only if DMA is off. @@ -696,12 +696,12 @@ static void imx_start_tx(struct uart_port *port) if (!uart_circ_empty(&port->state->xmit) && !uart_tx_stopped(port)) - imx_dma_tx(sport); + imx_uart_dma_tx(sport); return; } } -static irqreturn_t imx_rtsint(int irq, void *dev_id) +static irqreturn_t imx_uart_rtsint(int irq, void *dev_id) { struct imx_port *sport = dev_id; u32 usr1; @@ -718,18 +718,18 @@ static irqreturn_t imx_rtsint(int irq, void *dev_id) return IRQ_HANDLED; } -static irqreturn_t imx_txint(int irq, void *dev_id) +static irqreturn_t imx_uart_txint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - imx_transmit_buffer(sport); + imx_uart_transmit_buffer(sport); spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; } -static irqreturn_t imx_rxint(int irq, void *dev_id) +static irqreturn_t imx_uart_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int rx, flg, ignored = 0; @@ -801,12 +801,12 @@ out: return IRQ_HANDLED; } -static void clear_rx_errors(struct imx_port *sport); +static void imx_uart_clear_rx_errors(struct imx_port *sport); /* * We have a modem side uart, so the meanings of RTS and CTS are inverted. */ -static unsigned int imx_get_hwmctrl(struct imx_port *sport) +static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; unsigned usr1 = imx_uart_readl(sport, USR1); @@ -829,11 +829,11 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport) /* * Handle any change of modem status signal since we were last called. */ -static void imx_mctrl_check(struct imx_port *sport) +static void imx_uart_mctrl_check(struct imx_port *sport) { unsigned int status, changed; - status = imx_get_hwmctrl(sport); + status = imx_uart_get_hwmctrl(sport); changed = status ^ sport->old_status; if (changed == 0) @@ -853,7 +853,7 @@ static void imx_mctrl_check(struct imx_port *sport) wake_up_interruptible(&sport->port.state->port.delta_msr_wait); } -static irqreturn_t imx_int(int irq, void *dev_id) +static irqreturn_t imx_uart_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int usr1, usr2, ucr1, ucr2, ucr3, ucr4; @@ -892,12 +892,12 @@ static irqreturn_t imx_int(int irq, void *dev_id) usr2 &= ~USR2_ORE; if (usr1 & (USR1_RRDY | USR1_AGTIM)) { - imx_rxint(irq, dev_id); + imx_uart_rxint(irq, dev_id); ret = IRQ_HANDLED; } if ((usr1 & USR1_TRDY) || (usr2 & USR2_TXDC)) { - imx_txint(irq, dev_id); + imx_uart_txint(irq, dev_id); ret = IRQ_HANDLED; } @@ -907,14 +907,14 @@ static irqreturn_t imx_int(int irq, void *dev_id) imx_uart_writel(sport, USR1_DTRD, USR1); spin_lock_irqsave(&sport->port.lock, flags); - imx_mctrl_check(sport); + imx_uart_mctrl_check(sport); spin_unlock_irqrestore(&sport->port.lock, flags); ret = IRQ_HANDLED; } if (usr1 & USR1_RTSD) { - imx_rtsint(irq, dev_id); + imx_uart_rtsint(irq, dev_id); ret = IRQ_HANDLED; } @@ -935,7 +935,7 @@ static irqreturn_t imx_int(int irq, void *dev_id) /* * Return TIOCSER_TEMT when transmitter is not busy. */ -static unsigned int imx_tx_empty(struct uart_port *port) +static unsigned int imx_uart_tx_empty(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned int ret; @@ -950,10 +950,10 @@ static unsigned int imx_tx_empty(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static unsigned int imx_get_mctrl(struct uart_port *port) +static unsigned int imx_uart_get_mctrl(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - unsigned int ret = imx_get_hwmctrl(sport); + unsigned int ret = imx_uart_get_hwmctrl(sport); mctrl_gpio_get(sport->gpios, &ret); @@ -961,7 +961,7 @@ static unsigned int imx_get_mctrl(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) +static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct imx_port *sport = (struct imx_port *)port; u32 ucr3, uts; @@ -981,10 +981,10 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) ucr3 |= UCR3_DSR; imx_uart_writel(sport, ucr3, UCR3); - uts = imx_uart_readl(sport, uts_reg(sport)) & ~UTS_LOOP; + uts = imx_uart_readl(sport, imx_uart_uts_reg(sport)) & ~UTS_LOOP; if (mctrl & TIOCM_LOOP) uts |= UTS_LOOP; - imx_uart_writel(sport, uts, uts_reg(sport)); + imx_uart_writel(sport, uts, imx_uart_uts_reg(sport)); mctrl_gpio_set(sport->gpios, mctrl); } @@ -992,7 +992,7 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl) /* * Interrupts always disabled. */ -static void imx_break_ctl(struct uart_port *port, int break_state) +static void imx_uart_break_ctl(struct uart_port *port, int break_state) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; @@ -1014,14 +1014,14 @@ static void imx_break_ctl(struct uart_port *port, int break_state) * This is our per-port timeout handler, for checking the * modem status signals. */ -static void imx_timeout(struct timer_list *t) +static void imx_uart_timeout(struct timer_list *t) { struct imx_port *sport = from_timer(sport, t, timer); unsigned long flags; if (sport->port.state) { spin_lock_irqsave(&sport->port.lock, flags); - imx_mctrl_check(sport); + imx_uart_mctrl_check(sport); spin_unlock_irqrestore(&sport->port.lock, flags); mod_timer(&sport->timer, jiffies + MCTRL_TIMEOUT); @@ -1038,7 +1038,7 @@ static void imx_timeout(struct timer_list *t) * Condition [2] is triggered when a character has been sitting in the FIFO * for at least 8 byte durations. */ -static void dma_rx_callback(void *data) +static void imx_uart_dma_rx_callback(void *data) { struct imx_port *sport = data; struct dma_chan *chan = sport->dma_chan_rx; @@ -1054,7 +1054,7 @@ static void dma_rx_callback(void *data) status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); if (status == DMA_ERROR) { - clear_rx_errors(sport); + imx_uart_clear_rx_errors(sport); return; } @@ -1114,7 +1114,7 @@ static void dma_rx_callback(void *data) /* RX DMA buffer periods */ #define RX_DMA_PERIODS 4 -static int start_rx_dma(struct imx_port *sport) +static int imx_uart_start_rx_dma(struct imx_port *sport) { struct scatterlist *sgl = &sport->rx_sgl; struct dma_chan *chan = sport->dma_chan_rx; @@ -1142,7 +1142,7 @@ static int start_rx_dma(struct imx_port *sport) dev_err(dev, "We cannot prepare for the RX slave dma!\n"); return -EINVAL; } - desc->callback = dma_rx_callback; + desc->callback = imx_uart_dma_rx_callback; desc->callback_param = sport; dev_dbg(dev, "RX: prepare for the DMA.\n"); @@ -1152,7 +1152,7 @@ static int start_rx_dma(struct imx_port *sport) return 0; } -static void clear_rx_errors(struct imx_port *sport) +static void imx_uart_clear_rx_errors(struct imx_port *sport) { struct tty_port *port = &sport->port.state->port; u32 usr1, usr2; @@ -1190,8 +1190,8 @@ static void clear_rx_errors(struct imx_port *sport) #define TXTL_DMA 8 /* DMA burst setting */ #define RXTL_DMA 9 /* DMA burst setting */ -static void imx_setup_ufcr(struct imx_port *sport, - unsigned char txwl, unsigned char rxwl) +static void imx_uart_setup_ufcr(struct imx_port *sport, + unsigned char txwl, unsigned char rxwl) { unsigned int val; @@ -1275,11 +1275,11 @@ err: return ret; } -static void imx_enable_dma(struct imx_port *sport) +static void imx_uart_enable_dma(struct imx_port *sport) { u32 ucr1; - imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + imx_uart_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); /* set UCR1 */ ucr1 = imx_uart_readl(sport, UCR1); @@ -1289,7 +1289,7 @@ static void imx_enable_dma(struct imx_port *sport) sport->dma_is_enabled = 1; } -static void imx_disable_dma(struct imx_port *sport) +static void imx_uart_disable_dma(struct imx_port *sport) { u32 ucr1, ucr2; @@ -1303,7 +1303,7 @@ static void imx_disable_dma(struct imx_port *sport) ucr2 &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); imx_uart_writel(sport, ucr2, UCR2); - imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); sport->dma_is_enabled = 0; } @@ -1311,7 +1311,7 @@ static void imx_disable_dma(struct imx_port *sport) /* half the RX buffer size */ #define CTSTL 16 -static int imx_startup(struct uart_port *port) +static int imx_uart_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; int retval, i; @@ -1328,7 +1328,7 @@ static int imx_startup(struct uart_port *port) return retval; } - imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs @@ -1382,11 +1382,11 @@ static int imx_startup(struct uart_port *port) * make sure the edge sensitive RTS-irq is disabled, * we're using RTSD instead. */ - if (!is_imx1_uart(sport)) + if (!imx_uart_is_imx1(sport)) ucr2 &= ~UCR2_RTSEN; imx_uart_writel(sport, ucr2, UCR2); - if (!is_imx1_uart(sport)) { + if (!imx_uart_is_imx1(sport)) { u32 ucr3; ucr3 = imx_uart_readl(sport, UCR3); @@ -1403,11 +1403,11 @@ static int imx_startup(struct uart_port *port) /* * Enable modem status interrupts */ - imx_enable_ms(&sport->port); + imx_uart_enable_ms(&sport->port); if (dma_is_inited) { - imx_enable_dma(sport); - start_rx_dma(sport); + imx_uart_enable_dma(sport); + imx_uart_start_rx_dma(sport); } else { ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_RRDYEN; @@ -1423,7 +1423,7 @@ static int imx_startup(struct uart_port *port) return 0; } -static void imx_shutdown(struct uart_port *port) +static void imx_uart_shutdown(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; @@ -1436,9 +1436,9 @@ static void imx_shutdown(struct uart_port *port) dmaengine_terminate_sync(sport->dma_chan_rx); spin_lock_irqsave(&sport->port.lock, flags); - imx_stop_tx(port); - imx_stop_rx(port); - imx_disable_dma(sport); + imx_uart_stop_tx(port); + imx_uart_stop_rx(port); + imx_uart_disable_dma(sport); spin_unlock_irqrestore(&sport->port.lock, flags); imx_uart_dma_exit(sport); } @@ -1472,7 +1472,7 @@ static void imx_shutdown(struct uart_port *port) } /* called with port.lock taken and irqs off */ -static void imx_flush_buffer(struct uart_port *port) +static void imx_uart_flush_buffer(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; struct scatterlist *sgl = &sport->tx_sgl[0]; @@ -1524,8 +1524,8 @@ static void imx_flush_buffer(struct uart_port *port) } static void -imx_set_termios(struct uart_port *port, struct ktermios *termios, - struct ktermios *old) +imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, + struct ktermios *old) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; @@ -1563,11 +1563,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, */ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &ucr2); + imx_uart_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &ucr2); + imx_uart_rts_inactive(sport, &ucr2); } else { - imx_port_rts_auto(sport, &ucr2); + imx_uart_rts_auto(sport, &ucr2); } } else { termios->c_cflag &= ~CRTSCTS; @@ -1575,9 +1575,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, } else if (port->rs485.flags & SER_RS485_ENABLED) { /* disable transmitter */ if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &ucr2); + imx_uart_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &ucr2); + imx_uart_rts_inactive(sport, &ucr2); } @@ -1676,7 +1676,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, imx_uart_writel(sport, num, UBIR); imx_uart_writel(sport, denom, UBMR); - if (!is_imx1_uart(sport)) + if (!imx_uart_is_imx1(sport)) imx_uart_writel(sport, sport->port.uartclk / div / 1000, IMX21_ONEMS); @@ -1686,12 +1686,12 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, imx_uart_writel(sport, ucr2 | old_ucr2, UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) - imx_enable_ms(&sport->port); + imx_uart_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock, flags); } -static const char *imx_type(struct uart_port *port) +static const char *imx_uart_type(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; @@ -1701,7 +1701,7 @@ static const char *imx_type(struct uart_port *port) /* * Configure/autoconfigure the port. */ -static void imx_config_port(struct uart_port *port, int flags) +static void imx_uart_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; @@ -1715,7 +1715,7 @@ static void imx_config_port(struct uart_port *port, int flags) * even then only between PORT_IMX and PORT_UNKNOWN */ static int -imx_verify_port(struct uart_port *port, struct serial_struct *ser) +imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) { struct imx_port *sport = (struct imx_port *)port; int ret = 0; @@ -1739,7 +1739,7 @@ imx_verify_port(struct uart_port *port, struct serial_struct *ser) #if defined(CONFIG_CONSOLE_POLL) -static int imx_poll_init(struct uart_port *port) +static int imx_uart_poll_init(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; @@ -1753,7 +1753,7 @@ static int imx_poll_init(struct uart_port *port) if (retval) clk_disable_unprepare(sport->clk_ipg); - imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); spin_lock_irqsave(&sport->port.lock, flags); @@ -1767,7 +1767,7 @@ static int imx_poll_init(struct uart_port *port) ucr1 = imx_uart_readl(sport, UCR1); ucr2 = imx_uart_readl(sport, UCR2); - if (is_imx1_uart(sport)) + if (imx_uart_is_imx1(sport)) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; @@ -1788,7 +1788,7 @@ static int imx_poll_init(struct uart_port *port) return 0; } -static int imx_poll_get_char(struct uart_port *port) +static int imx_uart_poll_get_char(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; if (!(imx_uart_readl(sport, USR2) & USR2_RDR)) @@ -1797,7 +1797,7 @@ static int imx_poll_get_char(struct uart_port *port) return imx_uart_readl(sport, URXD0) & URXD_RX_DATA; } -static void imx_poll_put_char(struct uart_port *port, unsigned char c) +static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) { struct imx_port *sport = (struct imx_port *)port; unsigned int status; @@ -1818,8 +1818,8 @@ static void imx_poll_put_char(struct uart_port *port, unsigned char c) #endif /* called with port.lock taken and irqs off or from .probe without locking */ -static int imx_rs485_config(struct uart_port *port, - struct serial_rs485 *rs485conf) +static int imx_uart_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485conf) { struct imx_port *sport = (struct imx_port *)port; u32 ucr2; @@ -1836,53 +1836,53 @@ static int imx_rs485_config(struct uart_port *port, /* disable transmitter */ ucr2 = imx_uart_readl(sport, UCR2); if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) - imx_port_rts_active(sport, &ucr2); + imx_uart_rts_active(sport, &ucr2); else - imx_port_rts_inactive(sport, &ucr2); + imx_uart_rts_inactive(sport, &ucr2); imx_uart_writel(sport, ucr2, UCR2); } /* Make sure Rx is enabled in case Tx is active with Rx disabled */ if (!(rs485conf->flags & SER_RS485_ENABLED) || rs485conf->flags & SER_RS485_RX_DURING_TX) - imx_start_rx(port); + imx_uart_start_rx(port); port->rs485 = *rs485conf; return 0; } -static const struct uart_ops imx_pops = { - .tx_empty = imx_tx_empty, - .set_mctrl = imx_set_mctrl, - .get_mctrl = imx_get_mctrl, - .stop_tx = imx_stop_tx, - .start_tx = imx_start_tx, - .stop_rx = imx_stop_rx, - .enable_ms = imx_enable_ms, - .break_ctl = imx_break_ctl, - .startup = imx_startup, - .shutdown = imx_shutdown, - .flush_buffer = imx_flush_buffer, - .set_termios = imx_set_termios, - .type = imx_type, - .config_port = imx_config_port, - .verify_port = imx_verify_port, +static const struct uart_ops imx_uart_pops = { + .tx_empty = imx_uart_tx_empty, + .set_mctrl = imx_uart_set_mctrl, + .get_mctrl = imx_uart_get_mctrl, + .stop_tx = imx_uart_stop_tx, + .start_tx = imx_uart_start_tx, + .stop_rx = imx_uart_stop_rx, + .enable_ms = imx_uart_enable_ms, + .break_ctl = imx_uart_break_ctl, + .startup = imx_uart_startup, + .shutdown = imx_uart_shutdown, + .flush_buffer = imx_uart_flush_buffer, + .set_termios = imx_uart_set_termios, + .type = imx_uart_type, + .config_port = imx_uart_config_port, + .verify_port = imx_uart_verify_port, #if defined(CONFIG_CONSOLE_POLL) - .poll_init = imx_poll_init, - .poll_get_char = imx_poll_get_char, - .poll_put_char = imx_poll_put_char, + .poll_init = imx_uart_poll_init, + .poll_get_char = imx_uart_poll_get_char, + .poll_put_char = imx_uart_poll_put_char, #endif }; -static struct imx_port *imx_ports[UART_NR]; +static struct imx_port *imx_uart_ports[UART_NR]; #ifdef CONFIG_SERIAL_IMX_CONSOLE -static void imx_console_putchar(struct uart_port *port, int ch) +static void imx_uart_console_putchar(struct uart_port *port, int ch) { struct imx_port *sport = (struct imx_port *)port; - while (imx_uart_readl(sport, uts_reg(sport)) & UTS_TXFULL) + while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) barrier(); imx_uart_writel(sport, ch, URTX0); @@ -1892,9 +1892,9 @@ static void imx_console_putchar(struct uart_port *port, int ch) * Interrupts are disabled on entering */ static void -imx_console_write(struct console *co, const char *s, unsigned int count) +imx_uart_console_write(struct console *co, const char *s, unsigned int count) { - struct imx_port *sport = imx_ports[co->index]; + struct imx_port *sport = imx_uart_ports[co->index]; struct imx_port_ucrs old_ucr; unsigned int ucr1; unsigned long flags = 0; @@ -1920,10 +1920,10 @@ imx_console_write(struct console *co, const char *s, unsigned int count) /* * First, save UCR1/2/3 and then disable interrupts */ - imx_port_ucrs_save(sport, &old_ucr); + imx_uart_ucrs_save(sport, &old_ucr); ucr1 = old_ucr.ucr1; - if (is_imx1_uart(sport)) + if (imx_uart_is_imx1(sport)) ucr1 |= IMX1_UCR1_UARTCLKEN; ucr1 |= UCR1_UARTEN; ucr1 &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN); @@ -1932,7 +1932,7 @@ imx_console_write(struct console *co, const char *s, unsigned int count) imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); - uart_console_write(&sport->port, s, count, imx_console_putchar); + uart_console_write(&sport->port, s, count, imx_uart_console_putchar); /* * Finally, wait for transmitter to become empty @@ -1940,7 +1940,7 @@ imx_console_write(struct console *co, const char *s, unsigned int count) */ while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)); - imx_port_ucrs_restore(sport, &old_ucr); + imx_uart_ucrs_restore(sport, &old_ucr); if (locked) spin_unlock_irqrestore(&sport->port.lock, flags); @@ -1954,8 +1954,8 @@ imx_console_write(struct console *co, const char *s, unsigned int count) * try to determine the current setup. */ static void __init -imx_console_get_options(struct imx_port *sport, int *baud, - int *parity, int *bits) +imx_uart_console_get_options(struct imx_port *sport, int *baud, + int *parity, int *bits) { if (imx_uart_readl(sport, UCR1) & UCR1_UARTEN) { @@ -2013,7 +2013,7 @@ imx_console_get_options(struct imx_port *sport, int *baud, } static int __init -imx_console_setup(struct console *co, char *options) +imx_uart_console_setup(struct console *co, char *options) { struct imx_port *sport; int baud = 9600; @@ -2027,9 +2027,9 @@ imx_console_setup(struct console *co, char *options) * if so, search for the first available port that does have * console support. */ - if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports)) + if (co->index == -1 || co->index >= ARRAY_SIZE(imx_uart_ports)) co->index = 0; - sport = imx_ports[co->index]; + sport = imx_uart_ports[co->index]; if (sport == NULL) return -ENODEV; @@ -2041,9 +2041,9 @@ imx_console_setup(struct console *co, char *options) if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else - imx_console_get_options(sport, &baud, &parity, &bits); + imx_uart_console_get_options(sport, &baud, &parity, &bits); - imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); @@ -2061,21 +2061,21 @@ error_console: return retval; } -static struct uart_driver imx_reg; -static struct console imx_console = { +static struct uart_driver imx_uart_uart_driver; +static struct console imx_uart_console = { .name = DEV_NAME, - .write = imx_console_write, + .write = imx_uart_console_write, .device = uart_console_device, - .setup = imx_console_setup, + .setup = imx_uart_console_setup, .flags = CON_PRINTBUFFER, .index = -1, - .data = &imx_reg, + .data = &imx_uart_uart_driver, }; -#define IMX_CONSOLE &imx_console +#define IMX_CONSOLE &imx_uart_console #ifdef CONFIG_OF -static void imx_console_early_putchar(struct uart_port *port, int ch) +static void imx_uart_console_early_putchar(struct uart_port *port, int ch) { struct imx_port *sport = (struct imx_port *)port; @@ -2085,12 +2085,12 @@ static void imx_console_early_putchar(struct uart_port *port, int ch) imx_uart_writel(sport, ch, URTX0); } -static void imx_console_early_write(struct console *con, const char *s, - unsigned count) +static void imx_uart_console_early_write(struct console *con, const char *s, + unsigned count) { struct earlycon_device *dev = con->data; - uart_console_write(&dev->port, s, count, imx_console_early_putchar); + uart_console_write(&dev->port, s, count, imx_uart_console_early_putchar); } static int __init @@ -2099,7 +2099,7 @@ imx_console_early_setup(struct earlycon_device *dev, const char *opt) if (!dev->port.membase) return -ENODEV; - dev->con->write = imx_console_early_write; + dev->con->write = imx_uart_console_early_write; return 0; } @@ -2111,13 +2111,13 @@ OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup); #define IMX_CONSOLE NULL #endif -static struct uart_driver imx_reg = { +static struct uart_driver imx_uart_uart_driver = { .owner = THIS_MODULE, .driver_name = DRIVER_NAME, .dev_name = DEV_NAME, .major = SERIAL_IMX_MAJOR, .minor = MINOR_START, - .nr = ARRAY_SIZE(imx_ports), + .nr = ARRAY_SIZE(imx_uart_ports), .cons = IMX_CONSOLE, }; @@ -2126,8 +2126,8 @@ static struct uart_driver imx_reg = { * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it * could successfully get all information from dt or a negative errno. */ -static int serial_imx_probe_dt(struct imx_port *sport, - struct platform_device *pdev) +static int imx_uart_probe_dt(struct imx_port *sport, + struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; int ret; @@ -2157,15 +2157,15 @@ static int serial_imx_probe_dt(struct imx_port *sport, return 0; } #else -static inline int serial_imx_probe_dt(struct imx_port *sport, - struct platform_device *pdev) +static inline int imx_uart_probe_dt(struct imx_port *sport, + struct platform_device *pdev) { return 1; } #endif -static void serial_imx_probe_pdata(struct imx_port *sport, - struct platform_device *pdev) +static void imx_uart_probe_pdata(struct imx_port *sport, + struct platform_device *pdev) { struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev); @@ -2179,7 +2179,7 @@ static void serial_imx_probe_pdata(struct imx_port *sport, sport->have_rtscts = 1; } -static int serial_imx_probe(struct platform_device *pdev) +static int imx_uart_probe(struct platform_device *pdev) { struct imx_port *sport; void __iomem *base; @@ -2192,13 +2192,13 @@ static int serial_imx_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - ret = serial_imx_probe_dt(sport, pdev); + ret = imx_uart_probe_dt(sport, pdev); if (ret > 0) - serial_imx_probe_pdata(sport, pdev); + imx_uart_probe_pdata(sport, pdev); else if (ret < 0) return ret; - if (sport->port.line >= ARRAY_SIZE(imx_ports)) { + if (sport->port.line >= ARRAY_SIZE(imx_uart_ports)) { dev_err(&pdev->dev, "serial%d out of range\n", sport->port.line); return -EINVAL; @@ -2220,10 +2220,10 @@ static int serial_imx_probe(struct platform_device *pdev) sport->port.iotype = UPIO_MEM; sport->port.irq = rxirq; sport->port.fifosize = 32; - sport->port.ops = &imx_pops; - sport->port.rs485_config = imx_rs485_config; + sport->port.ops = &imx_uart_pops; + sport->port.rs485_config = imx_uart_rs485_config; sport->port.flags = UPF_BOOT_AUTOCONF; - timer_setup(&sport->timer, imx_timeout, 0); + timer_setup(&sport->timer, imx_uart_timeout, 0); sport->gpios = mctrl_gpio_init(&sport->port, 0); if (IS_ERR(sport->gpios)) @@ -2265,7 +2265,7 @@ static int serial_imx_probe(struct platform_device *pdev) (!sport->have_rtscts || !sport->have_rtsgpio)) dev_err(&pdev->dev, "no RTS control, disabling rs485\n"); - imx_rs485_config(&sport->port, &sport->port.rs485); + imx_uart_rs485_config(&sport->port, &sport->port.rs485); /* Disable interrupts before requesting them */ ucr1 = imx_uart_readl(sport, UCR1); @@ -2273,7 +2273,7 @@ static int serial_imx_probe(struct platform_device *pdev) UCR1_TXMPTYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); - if (!is_imx1_uart(sport) && sport->dte_mode) { + if (!imx_uart_is_imx1(sport) && sport->dte_mode) { /* * The DCEDTE bit changes the direction of DSR, DCD, DTR and RI * and influences if UCR3_RI and UCR3_DCD changes the level of RI @@ -2299,7 +2299,7 @@ static int serial_imx_probe(struct platform_device *pdev) if (ufcr & UFCR_DCEDTE) imx_uart_writel(sport, ufcr & ~UFCR_DCEDTE, UFCR); - if (!is_imx1_uart(sport)) + if (!imx_uart_is_imx1(sport)) ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; imx_uart_writel(sport, ucr3, UCR3); } @@ -2311,7 +2311,7 @@ static int serial_imx_probe(struct platform_device *pdev) * chips only have one interrupt. */ if (txirq > 0) { - ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, + ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_rxint, 0, dev_name(&pdev->dev), sport); if (ret) { dev_err(&pdev->dev, "failed to request rx irq: %d\n", @@ -2319,7 +2319,7 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; } - ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, + ret = devm_request_irq(&pdev->dev, txirq, imx_uart_txint, 0, dev_name(&pdev->dev), sport); if (ret) { dev_err(&pdev->dev, "failed to request tx irq: %d\n", @@ -2327,7 +2327,7 @@ static int serial_imx_probe(struct platform_device *pdev) return ret; } } else { - ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, + ret = devm_request_irq(&pdev->dev, rxirq, imx_uart_int, 0, dev_name(&pdev->dev), sport); if (ret) { dev_err(&pdev->dev, "failed to request irq: %d\n", ret); @@ -2335,21 +2335,21 @@ static int serial_imx_probe(struct platform_device *pdev) } } - imx_ports[sport->port.line] = sport; + imx_uart_ports[sport->port.line] = sport; platform_set_drvdata(pdev, sport); - return uart_add_one_port(&imx_reg, &sport->port); + return uart_add_one_port(&imx_uart_uart_driver, &sport->port); } -static int serial_imx_remove(struct platform_device *pdev) +static int imx_uart_remove(struct platform_device *pdev) { struct imx_port *sport = platform_get_drvdata(pdev); - return uart_remove_one_port(&imx_reg, &sport->port); + return uart_remove_one_port(&imx_uart_uart_driver, &sport->port); } -static void serial_imx_restore_context(struct imx_port *sport) +static void imx_uart_restore_context(struct imx_port *sport) { if (!sport->context_saved) return; @@ -2367,7 +2367,7 @@ static void serial_imx_restore_context(struct imx_port *sport) sport->context_saved = false; } -static void serial_imx_save_context(struct imx_port *sport) +static void imx_uart_save_context(struct imx_port *sport) { /* Save necessary regs */ sport->saved_reg[0] = imx_uart_readl(sport, UCR1); @@ -2383,7 +2383,7 @@ static void serial_imx_save_context(struct imx_port *sport) sport->context_saved = true; } -static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) +static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) { u32 ucr3; @@ -2406,19 +2406,19 @@ static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) } } -static int imx_serial_port_suspend_noirq(struct device *dev) +static int imx_uart_suspend_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - serial_imx_save_context(sport); + imx_uart_save_context(sport); clk_disable(sport->clk_ipg); return 0; } -static int imx_serial_port_resume_noirq(struct device *dev) +static int imx_uart_resume_noirq(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); @@ -2428,18 +2428,18 @@ static int imx_serial_port_resume_noirq(struct device *dev) if (ret) return ret; - serial_imx_restore_context(sport); + imx_uart_restore_context(sport); return 0; } -static int imx_serial_port_suspend(struct device *dev) +static int imx_uart_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); int ret; - uart_suspend_port(&imx_reg, &sport->port); + uart_suspend_port(&imx_uart_uart_driver, &sport->port); disable_irq(sport->port.irq); ret = clk_prepare_enable(sport->clk_ipg); @@ -2447,20 +2447,20 @@ static int imx_serial_port_suspend(struct device *dev) return ret; /* enable wakeup from i.MX UART */ - serial_imx_enable_wakeup(sport, true); + imx_uart_enable_wakeup(sport, true); return 0; } -static int imx_serial_port_resume(struct device *dev) +static int imx_uart_resume(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); /* disable wakeup from i.MX UART */ - serial_imx_enable_wakeup(sport, false); + imx_uart_enable_wakeup(sport, false); - uart_resume_port(&imx_reg, &sport->port); + uart_resume_port(&imx_uart_uart_driver, &sport->port); enable_irq(sport->port.irq); clk_disable_unprepare(sport->clk_ipg); @@ -2468,74 +2468,74 @@ static int imx_serial_port_resume(struct device *dev) return 0; } -static int imx_serial_port_freeze(struct device *dev) +static int imx_uart_freeze(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - uart_suspend_port(&imx_reg, &sport->port); + uart_suspend_port(&imx_uart_uart_driver, &sport->port); return clk_prepare_enable(sport->clk_ipg); } -static int imx_serial_port_thaw(struct device *dev) +static int imx_uart_thaw(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); struct imx_port *sport = platform_get_drvdata(pdev); - uart_resume_port(&imx_reg, &sport->port); + uart_resume_port(&imx_uart_uart_driver, &sport->port); clk_disable_unprepare(sport->clk_ipg); return 0; } -static const struct dev_pm_ops imx_serial_port_pm_ops = { - .suspend_noirq = imx_serial_port_suspend_noirq, - .resume_noirq = imx_serial_port_resume_noirq, - .freeze_noirq = imx_serial_port_suspend_noirq, - .restore_noirq = imx_serial_port_resume_noirq, - .suspend = imx_serial_port_suspend, - .resume = imx_serial_port_resume, - .freeze = imx_serial_port_freeze, - .thaw = imx_serial_port_thaw, - .restore = imx_serial_port_thaw, +static const struct dev_pm_ops imx_uart_pm_ops = { + .suspend_noirq = imx_uart_suspend_noirq, + .resume_noirq = imx_uart_resume_noirq, + .freeze_noirq = imx_uart_suspend_noirq, + .restore_noirq = imx_uart_resume_noirq, + .suspend = imx_uart_suspend, + .resume = imx_uart_resume, + .freeze = imx_uart_freeze, + .thaw = imx_uart_thaw, + .restore = imx_uart_thaw, }; -static struct platform_driver serial_imx_driver = { - .probe = serial_imx_probe, - .remove = serial_imx_remove, +static struct platform_driver imx_uart_platform_driver = { + .probe = imx_uart_probe, + .remove = imx_uart_remove, - .id_table = imx_uart_devtype, - .driver = { - .name = "imx-uart", + .id_table = imx_uart_devtype, + .driver = { + .name = "imx-uart", .of_match_table = imx_uart_dt_ids, - .pm = &imx_serial_port_pm_ops, + .pm = &imx_uart_pm_ops, }, }; -static int __init imx_serial_init(void) +static int __init imx_uart_init(void) { - int ret = uart_register_driver(&imx_reg); + int ret = uart_register_driver(&imx_uart_uart_driver); if (ret) return ret; - ret = platform_driver_register(&serial_imx_driver); + ret = platform_driver_register(&imx_uart_platform_driver); if (ret != 0) - uart_unregister_driver(&imx_reg); + uart_unregister_driver(&imx_uart_uart_driver); return ret; } -static void __exit imx_serial_exit(void) +static void __exit imx_uart_exit(void) { - platform_driver_unregister(&serial_imx_driver); - uart_unregister_driver(&imx_reg); + platform_driver_unregister(&imx_uart_platform_driver); + uart_unregister_driver(&imx_uart_uart_driver); } -module_init(imx_serial_init); -module_exit(imx_serial_exit); +module_init(imx_uart_init); +module_exit(imx_uart_exit); MODULE_AUTHOR("Sascha Hauer"); MODULE_DESCRIPTION("IMX generic serial port driver"); -- cgit v1.2.3 From 7d6e2143bed7dd61dac3a00321292b36d63c2a2f Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 1 Mar 2018 13:41:29 +0200 Subject: serial: 8250_dw: Switch to use acpi_dev_present() Special settings for APMC0D08 are applied when device is present in the system. To check its presence we may use acpi_dev_present() instead of current open coded variant. Cc: Feng Kan Signed-off-by: Andy Shevchenko Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_dw.c | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c index 41618b780146..6fcdb90f616a 100644 --- a/drivers/tty/serial/8250/8250_dw.c +++ b/drivers/tty/serial/8250/8250_dw.c @@ -357,17 +357,11 @@ static void dw8250_quirks(struct uart_port *p, struct dw8250_data *data) p->serial_in = dw8250_serial_in32be; p->serial_out = dw8250_serial_out32be; } - } else if (has_acpi_companion(p->dev)) { - const struct acpi_device_id *id; - - id = acpi_match_device(p->dev->driver->acpi_match_table, - p->dev); - if (id && !strcmp(id->id, "APMC0D08")) { - p->iotype = UPIO_MEM32; - p->regshift = 2; - p->serial_in = dw8250_serial_in32; - data->uart_16550_compatible = true; - } + } else if (acpi_dev_present("APMC0D08", NULL, -1)) { + p->iotype = UPIO_MEM32; + p->regshift = 2; + p->serial_in = dw8250_serial_in32; + data->uart_16550_compatible = true; } /* Platforms with iDMA */ -- cgit v1.2.3 From ca7c22fc9e8d16b11b8be81254d5f59c5a9f5bcf Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Sat, 3 Mar 2018 01:42:01 +0300 Subject: serial: mxs-auart: disable clks of Alphascale ASM9260 In case of Alphascale ASM9260 probe() enables s->clk and s->clk_ahb via mxs_get_clks(), but there is no disable of the clocks. The patch adds it to error paths and to mxs_auart_remove(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Fixes: 254da0d753fb ("serial: mxs-auart: add Alphascale ASM9260 support") Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mxs-auart.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c index caa8a41b6e71..76aa289652f7 100644 --- a/drivers/tty/serial/mxs-auart.c +++ b/drivers/tty/serial/mxs-auart.c @@ -1678,8 +1678,10 @@ static int mxs_auart_probe(struct platform_device *pdev) return ret; r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!r) - return -ENXIO; + if (!r) { + ret = -ENXIO; + goto out_disable_clks; + } s->port.mapbase = r->start; s->port.membase = ioremap(r->start, resource_size(r)); @@ -1694,21 +1696,23 @@ static int mxs_auart_probe(struct platform_device *pdev) s->mctrl_prev = 0; irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; + if (irq < 0) { + ret = irq; + goto out_disable_clks; + } s->port.irq = irq; ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s); if (ret) - return ret; + goto out_disable_clks; platform_set_drvdata(pdev, s); ret = mxs_auart_init_gpios(s, &pdev->dev); if (ret) { dev_err(&pdev->dev, "Failed to initialize GPIOs.\n"); - return ret; + goto out_disable_clks; } /* @@ -1716,7 +1720,7 @@ static int mxs_auart_probe(struct platform_device *pdev) */ ret = mxs_auart_request_gpio_irq(s); if (ret) - return ret; + goto out_disable_clks; auart_port[s->port.line] = s; @@ -1724,7 +1728,7 @@ static int mxs_auart_probe(struct platform_device *pdev) ret = uart_add_one_port(&auart_driver, &s->port); if (ret) - goto out_disable_clks_free_qpio_irq; + goto out_free_qpio_irq; /* ASM9260 don't have version reg */ if (is_asm9260_auart(s)) { @@ -1738,13 +1742,15 @@ static int mxs_auart_probe(struct platform_device *pdev) return 0; -out_disable_clks_free_qpio_irq: - if (s->clk) - clk_disable_unprepare(s->clk_ahb); - if (s->clk_ahb) - clk_disable_unprepare(s->clk_ahb); +out_free_qpio_irq: mxs_auart_free_gpio_irq(s); auart_port[pdev->id] = NULL; + +out_disable_clks: + if (is_asm9260_auart(s)) { + clk_disable_unprepare(s->clk); + clk_disable_unprepare(s->clk_ahb); + } return ret; } @@ -1755,6 +1761,10 @@ static int mxs_auart_remove(struct platform_device *pdev) uart_remove_one_port(&auart_driver, &s->port); auart_port[pdev->id] = NULL; mxs_auart_free_gpio_irq(s); + if (is_asm9260_auart(s)) { + clk_disable_unprepare(s->clk); + clk_disable_unprepare(s->clk_ahb); + } return 0; } -- cgit v1.2.3 From f597fbce38d230af95384f4a04e0a13a1d0ad45d Mon Sep 17 00:00:00 2001 From: Joel Stanley Date: Mon, 5 Mar 2018 22:17:38 +1030 Subject: serial: 8250: Add Nuvoton NPCM UART The Nuvoton UART is almost compatible with the 8250 driver when probed via the 8250_of driver, however it requires some extra configuration at startup. Reviewed-by: Rob Herring Signed-off-by: Joel Stanley Cc: stable Signed-off-by: Greg Kroah-Hartman --- Documentation/devicetree/bindings/serial/8250.txt | 1 + drivers/tty/serial/8250/8250_of.c | 1 + drivers/tty/serial/8250/8250_port.c | 33 +++++++++++++++++++++++ include/uapi/linux/serial_core.h | 3 +++ 4 files changed, 38 insertions(+) (limited to 'drivers/tty/serial') diff --git a/Documentation/devicetree/bindings/serial/8250.txt b/Documentation/devicetree/bindings/serial/8250.txt index dad3b2ec66d4..aeb6db4e35c3 100644 --- a/Documentation/devicetree/bindings/serial/8250.txt +++ b/Documentation/devicetree/bindings/serial/8250.txt @@ -24,6 +24,7 @@ Required properties: - "ti,da830-uart" - "aspeed,ast2400-vuart" - "aspeed,ast2500-vuart" + - "nuvoton,npcm750-uart" - "serial" if the port type is unknown. - reg : offset and length of the register set for the device. - interrupts : should contain uart interrupt. diff --git a/drivers/tty/serial/8250/8250_of.c b/drivers/tty/serial/8250/8250_of.c index 160b8906d9b9..9835b1c1cbe1 100644 --- a/drivers/tty/serial/8250/8250_of.c +++ b/drivers/tty/serial/8250/8250_of.c @@ -316,6 +316,7 @@ static const struct of_device_id of_platform_serial_table[] = { { .compatible = "mrvl,mmp-uart", .data = (void *)PORT_XSCALE, }, { .compatible = "ti,da830-uart", .data = (void *)PORT_DA830, }, + { .compatible = "nuvoton,npcm750-uart", .data = (void *)PORT_NPCM, }, { /* end of list */ }, }; MODULE_DEVICE_TABLE(of, of_platform_serial_table); diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c index ffbb955d1c06..95833cbc4338 100644 --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -47,6 +47,10 @@ #define UART_EXAR_SLEEP 0x8b /* Sleep mode */ #define UART_EXAR_DVID 0x8d /* Device identification */ +/* Nuvoton NPCM timeout register */ +#define UART_NPCM_TOR 7 +#define UART_NPCM_TOIE BIT(7) /* Timeout Interrupt Enable */ + /* * Debugging. */ @@ -293,6 +297,15 @@ static const struct serial8250_config uart_config[] = { UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, .flags = UART_CAP_FIFO, }, + [PORT_NPCM] = { + .name = "Nuvoton 16550", + .fifo_size = 16, + .tx_loadsz = 16, + .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 | + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT, + .rxtrig_bytes = {1, 4, 8, 14}, + .flags = UART_CAP_FIFO, + }, }; /* Uart divisor latch read */ @@ -2141,6 +2154,15 @@ int serial8250_do_startup(struct uart_port *port) UART_DA830_PWREMU_MGMT_FREE); } + if (port->type == PORT_NPCM) { + /* + * Nuvoton calls the scratch register 'UART_TOR' (timeout + * register). Enable it, and set TIOC (timeout interrupt + * comparator) to be 0x20 for correct operation. + */ + serial_port_out(port, UART_NPCM_TOR, UART_NPCM_TOIE | 0x20); + } + #ifdef CONFIG_SERIAL_8250_RSA /* * If this is an RSA port, see if we can kick it up to the @@ -2463,6 +2485,15 @@ static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up, return quot_16 >> 4; } +/* Nuvoton NPCM UARTs have a custom divisor calculation */ +static unsigned int npcm_get_divisor(struct uart_8250_port *up, + unsigned int baud) +{ + struct uart_port *port = &up->port; + + return DIV_ROUND_CLOSEST(port->uartclk, 16 * baud + 2) - 2; +} + static unsigned int serial8250_get_divisor(struct uart_8250_port *up, unsigned int baud, unsigned int *frac) @@ -2483,6 +2514,8 @@ static unsigned int serial8250_get_divisor(struct uart_8250_port *up, quot = 0x8002; else if (up->port.type == PORT_XR17V35X) quot = xr17v35x_get_divisor(up, baud, frac); + else if (up->port.type == PORT_NPCM) + quot = npcm_get_divisor(up, baud); else quot = uart_get_divisor(port, baud); diff --git a/include/uapi/linux/serial_core.h b/include/uapi/linux/serial_core.h index 1c8413f93e3d..dce5f9dae121 100644 --- a/include/uapi/linux/serial_core.h +++ b/include/uapi/linux/serial_core.h @@ -76,6 +76,9 @@ #define PORT_SUNZILOG 38 #define PORT_SUNSAB 39 +/* Nuvoton UART */ +#define PORT_NPCM 40 + /* Intel EG20 */ #define PORT_PCH_8LINE 44 #define PORT_PCH_2LINE 45 -- cgit v1.2.3 From 1bcda09d291081a7732fcaa9d1745312404a4e36 Mon Sep 17 00:00:00 2001 From: Bich HEMON Date: Mon, 12 Mar 2018 09:50:05 +0000 Subject: serial: stm32: add support for RS485 hardware control mode Implement Driver Enable signal (DE) to activate the transmission mode of the external transceiver. Signed-off-by: Yves Coppeaux Signed-off-by: Bich Hemon Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 130 ++++++++++++++++++++++++++++++++++++++- drivers/tty/serial/stm32-usart.h | 3 + 2 files changed, 132 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 0fa735b60f2d..345fbf314269 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -62,6 +62,113 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } +static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, + u32 delay_DDE, u32 baud) +{ + u32 rs485_deat_dedt; + u32 rs485_deat_dedt_max = (USART_CR1_DEAT_MASK >> USART_CR1_DEAT_SHIFT); + bool over8; + + *cr3 |= USART_CR3_DEM; + over8 = *cr1 & USART_CR1_OVER8; + + if (over8) + rs485_deat_dedt = delay_ADE * baud * 8; + else + rs485_deat_dedt = delay_ADE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEAT_SHIFT) & + USART_CR1_DEAT_MASK; + *cr1 |= rs485_deat_dedt; + + if (over8) + rs485_deat_dedt = delay_DDE * baud * 8; + else + rs485_deat_dedt = delay_DDE * baud * 16; + + rs485_deat_dedt = DIV_ROUND_CLOSEST(rs485_deat_dedt, 1000); + rs485_deat_dedt = rs485_deat_dedt > rs485_deat_dedt_max ? + rs485_deat_dedt_max : rs485_deat_dedt; + rs485_deat_dedt = (rs485_deat_dedt << USART_CR1_DEDT_SHIFT) & + USART_CR1_DEDT_MASK; + *cr1 |= rs485_deat_dedt; +} + +static int stm32_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct stm32_port *stm32_port = to_stm32_port(port); + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; + u32 usartdiv, baud, cr1, cr3; + bool over8; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + + port->rs485 = *rs485conf; + + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + if (rs485conf->flags & SER_RS485_ENABLED) { + cr1 = readl_relaxed(port->membase + ofs->cr1); + cr3 = readl_relaxed(port->membase + ofs->cr3); + usartdiv = readl_relaxed(port->membase + ofs->brr); + usartdiv = usartdiv & GENMASK(15, 0); + over8 = cr1 & USART_CR1_OVER8; + + if (over8) + usartdiv = usartdiv | (usartdiv & GENMASK(4, 0)) + << USART_BRR_04_R_SHIFT; + + baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + writel_relaxed(cr3, port->membase + ofs->cr3); + writel_relaxed(cr1, port->membase + ofs->cr1); + } else { + stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); + stm32_clr_bits(port, ofs->cr1, + USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); + spin_unlock_irqrestore(&port->lock, flags); + + return 0; +} + +static int stm32_init_rs485(struct uart_port *port, + struct platform_device *pdev) +{ + struct serial_rs485 *rs485conf = &port->rs485; + + rs485conf->flags = 0; + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + + if (!pdev->dev.of_node) + return -ENODEV; + + uart_get_rs485_mode(&pdev->dev, rs485conf); + + return 0; +} + static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, bool threaded) { @@ -498,6 +605,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, struct stm32_port *stm32_port = to_stm32_port(port); struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct stm32_usart_config *cfg = &stm32_port->info->cfg; + struct serial_rs485 *rs485conf = &port->rs485; unsigned int baud; u32 usartdiv, mantissa, fraction, oversampling; tcflag_t cflag = termios->c_cflag; @@ -515,7 +623,7 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, writel_relaxed(0, port->membase + ofs->cr1); cr1 = USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; - cr1 |= BIT(cfg->uart_enable_bit); + if (stm32_port->fifoen) cr1 |= USART_CR1_FIFOEN; cr2 = 0; @@ -553,9 +661,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, */ if (usartdiv < 16) { oversampling = 8; + cr1 |= USART_CR1_OVER8; stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); } else { oversampling = 16; + cr1 &= ~USART_CR1_OVER8; stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); } @@ -592,10 +702,28 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, if (stm32_port->rx_ch) cr3 |= USART_CR3_DMAR; + if (rs485conf->flags & SER_RS485_ENABLED) { + stm32_config_reg_rs485(&cr1, &cr3, + rs485conf->delay_rts_before_send, + rs485conf->delay_rts_after_send, baud); + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + cr3 &= ~USART_CR3_DEP; + rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; + } else { + cr3 |= USART_CR3_DEP; + rs485conf->flags |= SER_RS485_RTS_AFTER_SEND; + } + + } else { + cr3 &= ~(USART_CR3_DEM | USART_CR3_DEP); + cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); + } + writel_relaxed(cr3, port->membase + ofs->cr3); writel_relaxed(cr2, port->membase + ofs->cr2); writel_relaxed(cr1, port->membase + ofs->cr1); + stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); spin_unlock_irqrestore(&port->lock, flags); } diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h index 2294d0f05872..6f294e280ea3 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -135,6 +135,7 @@ struct stm32_usart_info stm32h7_info = { #define USART_BRR_DIV_F_MASK GENMASK(3, 0) #define USART_BRR_DIV_M_MASK GENMASK(15, 4) #define USART_BRR_DIV_M_SHIFT 4 +#define USART_BRR_04_R_SHIFT 1 /* USART_CR1 */ #define USART_CR1_SBK BIT(0) @@ -162,6 +163,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR1_M1 BIT(28) /* F7 */ #define USART_CR1_IE_MASK (GENMASK(8, 4) | BIT(14) | BIT(26) | BIT(27)) #define USART_CR1_FIFOEN BIT(29) /* H7 */ +#define USART_CR1_DEAT_SHIFT 21 +#define USART_CR1_DEDT_SHIFT 16 /* USART_CR2 */ #define USART_CR2_ADD_MASK GENMASK(3, 0) /* F4 */ -- cgit v1.2.3 From dfd9190ce8f4c96076849fe4d1ad7dbe3b92bb3d Mon Sep 17 00:00:00 2001 From: Patrice Chotard Date: Wed, 7 Mar 2018 18:35:32 +0100 Subject: tty: st-asc: Update tty alias Since dtc v1.4.6-9-gaadd0b65c987, aliases property name must include only lowercase and '-'. After having updated all STi boards serial aliases from "ttyASN" to "serialN", st-asc driver need to be updated accordingly as tty aliases id is retrieved using of_alias_get_id(). Signed-off-by: Patrice Chotard Reviewed-by: Rob Herring Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/st-asc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/st-asc.c b/drivers/tty/serial/st-asc.c index c763253514e9..5f9f01fac6dd 100644 --- a/drivers/tty/serial/st-asc.c +++ b/drivers/tty/serial/st-asc.c @@ -782,7 +782,9 @@ static struct asc_port *asc_of_get_asc_port(struct platform_device *pdev) if (!np) return NULL; - id = of_alias_get_id(np, ASC_SERIAL_NAME); + id = of_alias_get_id(np, "serial"); + if (id < 0) + id = of_alias_get_id(np, ASC_SERIAL_NAME); if (id < 0) id = 0; -- cgit v1.2.3 From 7d8f68619e4f530e19c17e7c0d04f0a791891a77 Mon Sep 17 00:00:00 2001 From: Bich HEMON Date: Thu, 15 Mar 2018 08:44:46 +0000 Subject: serial: stm32: fix initialization of RS485 mode Configure RS485 mode during port initialization. Fixes: 1bcda09d2910 ("serial: stm32: add support for RS485 hardware control mode") Signed-off-by: Bich Hemon Acked-by: Arnd Bergmann Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/stm32-usart.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 345fbf314269..e8d7a7bb4339 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -809,6 +809,10 @@ static int stm32_init_port(struct stm32_port *stm32port, port->ops = &stm32_uart_ops; port->dev = &pdev->dev; port->irq = platform_get_irq(pdev, 0); + port->rs485_config = stm32_config_rs485; + + stm32_init_rs485(port, pdev); + stm32port->wakeirq = platform_get_irq(pdev, 1); stm32port->fifoen = stm32port->info->cfg.has_fifo; -- cgit v1.2.3 From e2fea54e4592b5dccd97fc338d12bba95a2d16f0 Mon Sep 17 00:00:00 2001 From: Michael Moese Date: Mon, 5 Mar 2018 16:24:21 +0100 Subject: 8250-men-mcb: add support for 16z025 and 16z057 Add support for two MEN UARTs (16z025 and 16z057) to the 8250_men_mcb driver. The 16z025 consists of up to four ports, the 16z057 has exactly four ports. Apart from that, all of them share the Port settings. Signed-off-by: Michael Moese Reported-by: Ben Turner Tested-by: Ben Turner Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/8250/8250_men_mcb.c | 125 ++++++++++++++++++++++++--------- drivers/tty/serial/8250/Kconfig | 5 +- 2 files changed, 94 insertions(+), 36 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/8250/8250_men_mcb.c b/drivers/tty/serial/8250/8250_men_mcb.c index 308977807994..127017cc41d9 100644 --- a/drivers/tty/serial/8250/8250_men_mcb.c +++ b/drivers/tty/serial/8250/8250_men_mcb.c @@ -1,12 +1,19 @@ #include #include #include +#include #include #include #include #include #include +#define MEN_UART_ID_Z025 0x19 +#define MEN_UART_ID_Z057 0x39 +#define MEN_UART_ID_Z125 0x7d + +#define MEN_UART_MEM_SIZE 0x10 + struct serial_8250_men_mcb_data { struct uart_8250_port uart; int line; @@ -18,7 +25,7 @@ struct serial_8250_men_mcb_data { * parameter in order to really set the correct baudrate, and * do so if possible without user interaction */ -static u32 men_z125_lookup_uartclk(struct mcb_device *mdev) +static u32 men_lookup_uartclk(struct mcb_device *mdev) { /* use default value if board is not available below */ u32 clkval = 1041666; @@ -28,10 +35,12 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev) mdev->bus->name); if (strncmp(mdev->bus->name, "F075", 4) == 0) clkval = 1041666; - else if (strncmp(mdev->bus->name, "F216", 4) == 0) + else if (strncmp(mdev->bus->name, "F216", 4) == 0) clkval = 1843200; else if (strncmp(mdev->bus->name, "G215", 4) == 0) clkval = 1843200; + else if (strncmp(mdev->bus->name, "F210", 4) == 0) + clkval = 115200; else dev_info(&mdev->dev, "board not detected, using default uartclk\n"); @@ -41,62 +50,108 @@ static u32 men_z125_lookup_uartclk(struct mcb_device *mdev) return clkval; } +static unsigned int get_num_ports(struct mcb_device *mdev, + void __iomem *membase) +{ + switch (mdev->id) { + case MEN_UART_ID_Z125: + return 1U; + case MEN_UART_ID_Z025: + return readb(membase) >> 4; + case MEN_UART_ID_Z057: + return 4U; + default: + dev_err(&mdev->dev, "no supported device!\n"); + return -ENODEV; + } +} + static int serial_8250_men_mcb_probe(struct mcb_device *mdev, const struct mcb_device_id *id) { struct serial_8250_men_mcb_data *data; struct resource *mem; - - data = devm_kzalloc(&mdev->dev, - sizeof(struct serial_8250_men_mcb_data), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - mcb_set_drvdata(mdev, data); - data->uart.port.dev = mdev->dma_dev; - spin_lock_init(&data->uart.port.lock); - - data->uart.port.type = PORT_16550; - data->uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ | UPF_FIXED_TYPE; - data->uart.port.iotype = UPIO_MEM; - data->uart.port.uartclk = men_z125_lookup_uartclk(mdev); - data->uart.port.regshift = 0; - data->uart.port.fifosize = 60; + unsigned int num_ports; + unsigned int i; + void __iomem *membase; mem = mcb_get_resource(mdev, IORESOURCE_MEM); if (mem == NULL) return -ENXIO; + membase = devm_ioremap_resource(&mdev->dev, mem); + if (IS_ERR(membase)) + return PTR_ERR_OR_ZERO(membase); - data->uart.port.irq = mcb_get_irq(mdev); + num_ports = get_num_ports(mdev, membase); - data->uart.port.membase = devm_ioremap_resource(&mdev->dev, mem); - if (IS_ERR(data->uart.port.membase)) - return PTR_ERR_OR_ZERO(data->uart.port.membase); + dev_dbg(&mdev->dev, "found a 16z%03u with %u ports\n", + mdev->id, num_ports); - data->uart.port.mapbase = (unsigned long) mem->start; - data->uart.port.iobase = data->uart.port.mapbase; + if (num_ports == 0 || num_ports > 4) { + dev_err(&mdev->dev, "unexpected number of ports: %u\n", + num_ports); + return -ENODEV; + } - /* ok, register the port */ - data->line = serial8250_register_8250_port(&data->uart); - if (data->line < 0) - return data->line; + data = devm_kcalloc(&mdev->dev, num_ports, + sizeof(struct serial_8250_men_mcb_data), + GFP_KERNEL); + if (!data) + return -ENOMEM; - dev_info(&mdev->dev, "found 16Z125 UART: ttyS%d\n", data->line); + mcb_set_drvdata(mdev, data); + + for (i = 0; i < num_ports; i++) { + data[i].uart.port.dev = mdev->dma_dev; + spin_lock_init(&data[i].uart.port.lock); + + data[i].uart.port.type = PORT_16550; + data[i].uart.port.flags = UPF_SKIP_TEST | UPF_SHARE_IRQ + | UPF_FIXED_TYPE; + data[i].uart.port.iotype = UPIO_MEM; + data[i].uart.port.uartclk = men_lookup_uartclk(mdev); + data[i].uart.port.regshift = 0; + data[i].uart.port.irq = mcb_get_irq(mdev); + data[i].uart.port.membase = membase; + data[i].uart.port.fifosize = 60; + data[i].uart.port.mapbase = (unsigned long) mem->start + + i * MEN_UART_MEM_SIZE; + data[i].uart.port.iobase = data[i].uart.port.mapbase; + + /* ok, register the port */ + data[i].line = serial8250_register_8250_port(&data[i].uart); + if (data[i].line < 0) { + dev_err(&mdev->dev, "unable to register UART port\n"); + return data[i].line; + } + dev_info(&mdev->dev, "found MCB UART: ttyS%d\n", data[i].line); + } return 0; } static void serial_8250_men_mcb_remove(struct mcb_device *mdev) { + unsigned int num_ports, i; struct serial_8250_men_mcb_data *data = mcb_get_drvdata(mdev); - if (data) - serial8250_unregister_port(data->line); + if (!data) + return; + + num_ports = get_num_ports(mdev, data[0].uart.port.membase); + if (num_ports < 0 || num_ports > 4) { + dev_err(&mdev->dev, "error retrieving number of ports!\n"); + return; + } + + for (i = 0; i < num_ports; i++) + serial8250_unregister_port(data[i].line); } static const struct mcb_device_id serial_8250_men_mcb_ids[] = { - { .device = 0x7d }, + { .device = MEN_UART_ID_Z025 }, + { .device = MEN_UART_ID_Z057 }, + { .device = MEN_UART_ID_Z125 }, { } }; MODULE_DEVICE_TABLE(mcb, serial_8250_men_mcb_ids); @@ -113,6 +168,8 @@ static struct mcb_driver mcb_driver = { module_mcb_driver(mcb_driver); MODULE_LICENSE("GPL v2"); -MODULE_DESCRIPTION("MEN 16z125 8250 UART driver"); +MODULE_DESCRIPTION("MEN 8250 UART driver"); MODULE_AUTHOR("Michael Moese Date: Wed, 14 Mar 2018 17:58:49 -0600 Subject: tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP This driver supports GENI based UART Controller in the Qualcomm SOCs. The Qualcomm Generic Interface (GENI) is a programmable module supporting a wide range of serial interfaces including UART. This driver support console operations using FIFO mode of transfer. Signed-off-by: Girish Mahadevan Signed-off-by: Karthikeyan Ramasubramanian Signed-off-by: Sagar Dharia Signed-off-by: Doug Anderson Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/Kconfig | 15 + drivers/tty/serial/Makefile | 1 + drivers/tty/serial/qcom_geni_serial.c | 1158 +++++++++++++++++++++++++++++++++ 3 files changed, 1174 insertions(+) create mode 100644 drivers/tty/serial/qcom_geni_serial.c (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig index 3682fd3e960c..d132971605b6 100644 --- a/drivers/tty/serial/Kconfig +++ b/drivers/tty/serial/Kconfig @@ -1104,6 +1104,21 @@ config SERIAL_MSM_CONSOLE select SERIAL_CORE_CONSOLE select SERIAL_EARLYCON +config SERIAL_QCOM_GENI + tristate "QCOM on-chip GENI based serial port support" + depends on ARCH_QCOM || COMPILE_TEST + depends on QCOM_GENI_SE + select SERIAL_CORE + +config SERIAL_QCOM_GENI_CONSOLE + bool "QCOM GENI Serial Console support" + depends on SERIAL_QCOM_GENI=y + select SERIAL_CORE_CONSOLE + select SERIAL_EARLYCON + help + Serial console driver for Qualcomm Technologies Inc's GENI based + QUP hardware. + config SERIAL_VT8500 bool "VIA VT8500 on-chip serial port support" depends on ARCH_VT8500 diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile index 842d185d697e..64a8d8238007 100644 --- a/drivers/tty/serial/Makefile +++ b/drivers/tty/serial/Makefile @@ -63,6 +63,7 @@ obj-$(CONFIG_SERIAL_SGI_IOC3) += ioc3_serial.o obj-$(CONFIG_SERIAL_ATMEL) += atmel_serial.o obj-$(CONFIG_SERIAL_UARTLITE) += uartlite.o obj-$(CONFIG_SERIAL_MSM) += msm_serial.o +obj-$(CONFIG_SERIAL_QCOM_GENI) += qcom_geni_serial.o obj-$(CONFIG_SERIAL_NETX) += netx-serial.o obj-$(CONFIG_SERIAL_KS8695) += serial_ks8695.o obj-$(CONFIG_SERIAL_OMAP) += omap-serial.o diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c new file mode 100644 index 000000000000..14427778ad14 --- /dev/null +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -0,0 +1,1158 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2017-2018, The Linux foundation. All rights reserved. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* UART specific GENI registers */ +#define SE_UART_TX_TRANS_CFG 0x25c +#define SE_UART_TX_WORD_LEN 0x268 +#define SE_UART_TX_STOP_BIT_LEN 0x26c +#define SE_UART_TX_TRANS_LEN 0x270 +#define SE_UART_RX_TRANS_CFG 0x280 +#define SE_UART_RX_WORD_LEN 0x28c +#define SE_UART_RX_STALE_CNT 0x294 +#define SE_UART_TX_PARITY_CFG 0x2a4 +#define SE_UART_RX_PARITY_CFG 0x2a8 + +/* SE_UART_TRANS_CFG */ +#define UART_TX_PAR_EN BIT(0) +#define UART_CTS_MASK BIT(1) + +/* SE_UART_TX_WORD_LEN */ +#define TX_WORD_LEN_MSK GENMASK(9, 0) + +/* SE_UART_TX_STOP_BIT_LEN */ +#define TX_STOP_BIT_LEN_MSK GENMASK(23, 0) +#define TX_STOP_BIT_LEN_1 0 +#define TX_STOP_BIT_LEN_1_5 1 +#define TX_STOP_BIT_LEN_2 2 + +/* SE_UART_TX_TRANS_LEN */ +#define TX_TRANS_LEN_MSK GENMASK(23, 0) + +/* SE_UART_RX_TRANS_CFG */ +#define UART_RX_INS_STATUS_BIT BIT(2) +#define UART_RX_PAR_EN BIT(3) + +/* SE_UART_RX_WORD_LEN */ +#define RX_WORD_LEN_MASK GENMASK(9, 0) + +/* SE_UART_RX_STALE_CNT */ +#define RX_STALE_CNT GENMASK(23, 0) + +/* SE_UART_TX_PARITY_CFG/RX_PARITY_CFG */ +#define PAR_CALC_EN BIT(0) +#define PAR_MODE_MSK GENMASK(2, 1) +#define PAR_MODE_SHFT 1 +#define PAR_EVEN 0x00 +#define PAR_ODD 0x01 +#define PAR_SPACE 0x10 +#define PAR_MARK 0x11 + +/* UART M_CMD OP codes */ +#define UART_START_TX 0x1 +#define UART_START_BREAK 0x4 +#define UART_STOP_BREAK 0x5 +/* UART S_CMD OP codes */ +#define UART_START_READ 0x1 +#define UART_PARAM 0x1 + +#define UART_OVERSAMPLING 32 +#define STALE_TIMEOUT 16 +#define DEFAULT_BITS_PER_CHAR 10 +#define GENI_UART_CONS_PORTS 1 +#define DEF_FIFO_DEPTH_WORDS 16 +#define DEF_TX_WM 2 +#define DEF_FIFO_WIDTH_BITS 32 +#define UART_CONSOLE_RX_WM 2 + +#ifdef CONFIG_CONSOLE_POLL +#define RX_BYTES_PW 1 +#else +#define RX_BYTES_PW 4 +#endif + +struct qcom_geni_serial_port { + struct uart_port uport; + struct geni_se se; + char name[20]; + 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 xmit_size; + unsigned int baud; + unsigned int tx_bytes_pw; + unsigned int rx_bytes_pw; + bool brk; +}; + +static const struct uart_ops qcom_geni_serial_pops; +static struct uart_driver qcom_geni_console_driver; +static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop); +static unsigned int qcom_geni_serial_tx_empty(struct uart_port *port); +static void qcom_geni_serial_stop_rx(struct uart_port *uport); + +static const unsigned long root_freq[] = {7372800, 14745600, 19200000, 29491200, + 32000000, 48000000, 64000000, 80000000, + 96000000, 100000000}; + +#define to_dev_port(ptr, member) \ + container_of(ptr, struct qcom_geni_serial_port, member) + +static struct qcom_geni_serial_port qcom_geni_console_port; + +static int qcom_geni_serial_request_port(struct uart_port *uport) +{ + struct platform_device *pdev = to_platform_device(uport->dev); + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + uport->membase = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(uport->membase)) + return PTR_ERR(uport->membase); + port->se.base = uport->membase; + return 0; +} + +static void qcom_geni_serial_config_port(struct uart_port *uport, int cfg_flags) +{ + if (cfg_flags & UART_CONFIG_TYPE) { + uport->type = PORT_MSM; + qcom_geni_serial_request_port(uport); + } +} + +static unsigned int qcom_geni_cons_get_mctrl(struct uart_port *uport) +{ + return TIOCM_DSR | TIOCM_CAR | TIOCM_CTS; +} + +static void qcom_geni_cons_set_mctrl(struct uart_port *uport, + unsigned int mctrl) +{ +} + +static const char *qcom_geni_serial_get_type(struct uart_port *uport) +{ + return "MSM"; +} + +static struct qcom_geni_serial_port *get_port_from_line(int line) +{ + if (line < 0 || line >= GENI_UART_CONS_PORTS) + return ERR_PTR(-ENXIO); + return &qcom_geni_console_port; +} + +static bool qcom_geni_serial_poll_bit(struct uart_port *uport, + int offset, int field, bool set) +{ + u32 reg; + struct qcom_geni_serial_port *port; + unsigned int baud; + 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; + if (!baud) + baud = 115200; + fifo_bits = port->tx_fifo_depth * port->tx_fifo_width; + /* + * Total polling iterations based on FIFO worth of bytes to be + * sent at current baud. Add a little fluff to the wait. + */ + timeout_us = ((fifo_bits * USEC_PER_SEC) / baud) + 500; + } + + return !readl_poll_timeout_atomic(uport->membase + offset, reg, + (bool)(reg & field) == set, 10, timeout_us); +} + +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); + m_cmd = UART_START_TX << M_OPCODE_SHFT; + writel(m_cmd, uport->membase + SE_GENI_M_CMD0); +} + +static void qcom_geni_serial_poll_tx_done(struct uart_port *uport) +{ + int done; + u32 irq_clear = M_CMD_DONE_EN; + + 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 + + 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); +} + +static void qcom_geni_serial_abort_rx(struct uart_port *uport) +{ + u32 irq_clear = S_CMD_DONE_EN | S_CMD_ABORT_EN; + + 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); +} + +#ifdef CONFIG_CONSOLE_POLL +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_relaxed(uport->membase + SE_GENI_S_IRQ_STATUS); + writel_relaxed(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); + if (!(status & RX_FIFO_WC_MSK)) + return NO_POLL_CHAR; + + rx_fifo = readl(uport->membase + SE_GENI_RX_FIFOn); + return rx_fifo & 0xff; +} + +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); + 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); + qcom_geni_serial_poll_tx_done(uport); +} +#endif + +#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); +} + +static void +__qcom_geni_serial_console_write(struct uart_port *uport, const char *s, + unsigned int count) +{ + int i; + u32 bytes_to_send = count; + + for (i = 0; i < count; i++) { + if (s[i] == '\n') + bytes_to_send++; + } + + writel_relaxed(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; + size_t avail = DEF_FIFO_DEPTH_WORDS - DEF_TX_WM; + + /* + * If the WM bit never set, then the Tx state machine is not + * in a valid state, so break, cancel/abort any existing + * command. Unfortunately the current data being written is + * lost. + */ + if (!qcom_geni_serial_poll_bit(uport, SE_GENI_M_IRQ_STATUS, + M_TX_FIFO_WATERMARK_EN, true)) + break; + chars_to_write = min_t(size_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 + + SE_GENI_M_IRQ_CLEAR); + i += chars_to_write; + } + qcom_geni_serial_poll_tx_done(uport); +} + +static void qcom_geni_serial_console_write(struct console *co, const char *s, + unsigned int count) +{ + struct uart_port *uport; + struct qcom_geni_serial_port *port; + bool locked = true; + unsigned long flags; + + WARN_ON(co->index < 0 || co->index >= GENI_UART_CONS_PORTS); + + port = get_port_from_line(co->index); + if (IS_ERR(port)) + return; + + uport = &port->uport; + if (oops_in_progress) + locked = spin_trylock_irqsave(&uport->lock, flags); + else + spin_lock_irqsave(&uport->lock, flags); + + /* Cancel the current write to log the fault */ + if (!locked) { + 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_relaxed(M_CMD_CANCEL_EN, uport->membase + + SE_GENI_M_IRQ_CLEAR); + } + + __qcom_geni_serial_console_write(uport, s, count); + if (locked) + spin_unlock_irqrestore(&uport->lock, flags); +} + +static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) +{ + u32 i; + unsigned char buf[sizeof(u32)]; + struct tty_port *tport; + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + + tport = &uport->state->port; + for (i = 0; i < bytes; ) { + int c; + int chunk = min_t(int, bytes - i, port->rx_bytes_pw); + + ioread32_rep(uport->membase + SE_GENI_RX_FIFOn, buf, 1); + i += chunk; + if (drop) + continue; + + for (c = 0; c < chunk; c++) { + int sysrq; + + uport->icount.rx++; + if (port->brk && buf[c] == 0) { + port->brk = false; + if (uart_handle_break(uport)) + continue; + } + + sysrq = uart_handle_sysrq_char(uport, buf[c]); + if (!sysrq) + tty_insert_flip_char(tport, buf[c], TTY_NORMAL); + } + } + if (!drop) + tty_flip_buffer_push(tport); + return 0; +} +#else +static int handle_rx_console(struct uart_port *uport, u32 bytes, bool drop) +{ + return -EPERM; +} + +#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */ + +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) { + status = readl_relaxed(uport->membase + SE_GENI_STATUS); + if (status & M_GENI_CMD_ACTIVE) + return; + + if (!qcom_geni_serial_tx_empty(uport)) + return; + + /* + * Ensure writing to IRQ_EN & watermark registers are not + * re-ordered before checking the status of the Serial + * Engine and TX FIFO + */ + mb(); + + irq_en = readl_relaxed(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); + } +} + +static void qcom_geni_serial_stop_tx(struct uart_port *uport) +{ + u32 irq_en; + 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); + } + port->xmit_size = 0; + writel_relaxed(irq_en, uport->membase + SE_GENI_M_IRQ_EN); + status = readl_relaxed(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_relaxed(M_CMD_CANCEL_EN, uport->membase + SE_GENI_M_IRQ_CLEAR); +} + +static void qcom_geni_serial_start_rx(struct uart_port *uport) +{ + u32 irq_en; + u32 status; + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + + status = readl_relaxed(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_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); + } +} + +static void qcom_geni_serial_stop_rx(struct uart_port *uport) +{ + u32 irq_en; + u32 status; + 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_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); + } + + status = readl_relaxed(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); + if (status & S_GENI_CMD_ACTIVE) + qcom_geni_serial_abort_rx(uport); +} + +static void qcom_geni_serial_handle_rx(struct uart_port *uport, bool drop) +{ + u32 status; + u32 word_cnt; + u32 last_word_byte_cnt; + u32 last_word_partial; + u32 total_bytes; + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + + status = readl_relaxed(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) >> + RX_LAST_BYTE_VALID_SHFT; + + if (!word_cnt) + return; + total_bytes = port->rx_bytes_pw * (word_cnt - 1); + if (last_word_partial && last_word_byte_cnt) + total_bytes += last_word_byte_cnt; + else + total_bytes += port->rx_bytes_pw; + port->handle_rx(uport, total_bytes, drop); +} + +static void qcom_geni_serial_handle_tx(struct uart_port *uport) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + struct circ_buf *xmit = &uport->state->xmit; + size_t avail; + size_t remaining; + int i; + u32 status; + unsigned int chunk; + int tail; + + 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 == port->xmit_size && !status) { + port->xmit_size = 0; + uart_circ_clear(xmit); + qcom_geni_serial_stop_tx(uport); + goto out_write_wakeup; + } + chunk -= port->xmit_size; + + avail = (port->tx_fifo_depth - port->tx_wm) * port->tx_bytes_pw; + tail = (xmit->tail + port->xmit_size) & (UART_XMIT_SIZE - 1); + if (chunk > (UART_XMIT_SIZE - tail)) + chunk = UART_XMIT_SIZE - tail; + if (chunk > avail) + chunk = avail; + + if (!chunk) + goto out_write_wakeup; + + qcom_geni_serial_setup_tx(uport, chunk); + + remaining = chunk; + for (i = 0; i < chunk; ) { + unsigned int tx_bytes; + unsigned int buf = 0; + int c; + + tx_bytes = min_t(size_t, remaining, (size_t)port->tx_bytes_pw); + for (c = 0; c < tx_bytes ; c++) + buf |= (xmit->buf[tail + c] << (c * BITS_PER_BYTE)); + + writel_relaxed(buf, uport->membase + SE_GENI_TX_FIFOn); + + i += tx_bytes; + tail = (tail + tx_bytes) & (UART_XMIT_SIZE - 1); + uport->icount.tx += tx_bytes; + remaining -= tx_bytes; + } + qcom_geni_serial_poll_tx_done(uport); + port->xmit_size += chunk; +out_write_wakeup: + 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; + 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); + + if (uport->suspended) + return IRQ_HANDLED; + + 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); + + if (WARN_ON(m_irq_status & M_ILLEGAL_CMD_EN)) + goto out_unlock; + + if (s_irq_status & S_RX_FIFO_WR_ERR_EN) { + uport->icount.overrun++; + 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 (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) + uport->icount.parity++; + drop_rx = true; + } else if (s_irq_status & S_GP_IRQ_2_EN || + s_irq_status & S_GP_IRQ_3_EN) { + uport->icount.brk++; + port->brk = true; + } + + if (s_irq_status & S_RX_FIFO_WATERMARK_EN || + s_irq_status & S_RX_FIFO_LAST_EN) + qcom_geni_serial_handle_rx(uport, drop_rx); + +out_unlock: + spin_unlock_irqrestore(&uport->lock, flags); + return IRQ_HANDLED; +} + +static int get_tx_fifo_size(struct qcom_geni_serial_port *port) +{ + struct uart_port *uport; + + if (!port) + return -ENODEV; + + uport = &port->uport; + port->tx_fifo_depth = geni_se_get_tx_fifo_depth(&port->se); + port->tx_fifo_width = geni_se_get_tx_fifo_width(&port->se); + port->rx_fifo_depth = geni_se_get_rx_fifo_depth(&port->se); + uport->fifosize = + (port->tx_fifo_depth * port->tx_fifo_width) / BITS_PER_BYTE; + return 0; +} + +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) +{ + unsigned long flags; + + /* Stop the console before stopping the current tx */ + console_stop(uport->cons); + + disable_irq(uport->irq); + free_irq(uport->irq, uport); + spin_lock_irqsave(&uport->lock, flags); + qcom_geni_serial_stop_tx(uport); + qcom_geni_serial_stop_rx(uport); + spin_unlock_irqrestore(&uport->lock, flags); +} + +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; + + set_rfr_wm(port); + writel_relaxed(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; + 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); + port->setup = true; + return 0; +} + +static int qcom_geni_serial_startup(struct uart_port *uport) +{ + int ret; + u32 proto; + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + + scnprintf(port->name, sizeof(port->name), + "qcom_serial_geni%d", uport->line); + + proto = geni_se_read_proto(&port->se); + if (proto != GENI_SE_UART) { + dev_err(uport->dev, "Invalid FW loaded, proto: %d\n", proto); + return -ENXIO; + } + + get_tx_fifo_size(port); + if (!port->setup) { + ret = qcom_geni_serial_port_setup(uport); + if (ret) + return ret; + } + + ret = request_irq(uport->irq, qcom_geni_serial_isr, IRQF_TRIGGER_HIGH, + port->name, uport); + if (ret) + dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret); + return ret; +} + +static unsigned long get_clk_cfg(unsigned long clk_freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(root_freq); i++) { + if (!(root_freq[i] % clk_freq)) + return root_freq[i]; + } + return 0; +} + +static unsigned long get_clk_div_rate(unsigned int baud, unsigned int *clk_div) +{ + unsigned long ser_clk; + unsigned long desired_clk; + + desired_clk = baud * UART_OVERSAMPLING; + ser_clk = get_clk_cfg(desired_clk); + if (!ser_clk) { + pr_err("%s: Can't find matching DFS entry for baud %d\n", + __func__, baud); + return ser_clk; + } + + *clk_div = ser_clk / desired_clk; + return ser_clk; +} + +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; + unsigned int clk_div; + unsigned long ser_clk_cfg; + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + unsigned long clk_rate; + + qcom_geni_serial_stop_rx(uport); + /* baud rate */ + baud = uart_get_baud_rate(uport, termios, old, 300, 4000000); + port->baud = baud; + clk_rate = get_clk_div_rate(baud, &clk_div); + if (!clk_rate) + goto out_restart_rx; + + uport->uartclk = clk_rate; + clk_set_rate(port->se.clk, clk_rate); + ser_clk_cfg = SER_CLK_EN; + 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); + if (termios->c_cflag & PARENB) { + tx_trans_cfg |= UART_TX_PAR_EN; + rx_trans_cfg |= UART_RX_PAR_EN; + tx_parity_cfg |= PAR_CALC_EN; + rx_parity_cfg |= PAR_CALC_EN; + if (termios->c_cflag & PARODD) { + tx_parity_cfg |= PAR_ODD; + rx_parity_cfg |= PAR_ODD; + } else if (termios->c_cflag & CMSPAR) { + tx_parity_cfg |= PAR_SPACE; + rx_parity_cfg |= PAR_SPACE; + } else { + tx_parity_cfg |= PAR_EVEN; + rx_parity_cfg |= PAR_EVEN; + } + } else { + tx_trans_cfg &= ~UART_TX_PAR_EN; + rx_trans_cfg &= ~UART_RX_PAR_EN; + tx_parity_cfg &= ~PAR_CALC_EN; + rx_parity_cfg &= ~PAR_CALC_EN; + } + + /* bits per char */ + switch (termios->c_cflag & CSIZE) { + case CS5: + bits_per_char = 5; + break; + case CS6: + bits_per_char = 6; + break; + case CS7: + bits_per_char = 7; + break; + case CS8: + default: + bits_per_char = 8; + break; + } + + /* stop bits */ + if (termios->c_cflag & CSTOPB) + stop_bit_len = TX_STOP_BIT_LEN_2; + else + stop_bit_len = TX_STOP_BIT_LEN_1; + + /* flow control, clear the CTS_MASK bit if using flow control. */ + if (termios->c_cflag & CRTSCTS) + tx_trans_cfg &= ~UART_CTS_MASK; + else + tx_trans_cfg |= UART_CTS_MASK; + + if (baud) + uart_update_timeout(uport, termios->c_cflag, baud); + + 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); +out_restart_rx: + qcom_geni_serial_start_rx(uport); +} + +static unsigned int qcom_geni_serial_tx_empty(struct uart_port *uport) +{ + return !readl_relaxed(uport->membase + SE_GENI_TX_FIFO_STATUS); +} + +#ifdef CONFIG_SERIAL_QCOM_GENI_CONSOLE +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 bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (co->index >= GENI_UART_CONS_PORTS || co->index < 0) + return -ENXIO; + + port = get_port_from_line(co->index); + if (IS_ERR(port)) { + pr_err("Invalid line %d(%d)\n", co->index, (int)PTR_ERR(port)); + return PTR_ERR(port); + } + + uport = &port->uport; + + if (unlikely(!uport->membase)) + return -ENXIO; + + if (geni_se_resources_on(&port->se)) { + dev_err(port->se.dev, "Error turning on resources\n"); + return -ENXIO; + } + + if (unlikely(geni_se_read_proto(&port->se) != GENI_SE_UART)) { + geni_se_resources_off(&port->se); + return -ENXIO; + } + + if (!port->setup) { + port->tx_bytes_pw = 1; + port->rx_bytes_pw = RX_BYTES_PW; + qcom_geni_serial_stop_rx(uport); + qcom_geni_serial_port_setup(uport); + } + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + + return uart_set_options(uport, co, baud, parity, bits, flow); +} + +static int __init console_register(struct uart_driver *drv) +{ + return uart_register_driver(drv); +} + +static void console_unregister(struct uart_driver *drv) +{ + uart_unregister_driver(drv); +} + +static struct console cons_ops = { + .name = "ttyMSM", + .write = qcom_geni_serial_console_write, + .device = uart_console_device, + .setup = qcom_geni_console_setup, + .flags = CON_PRINTBUFFER, + .index = -1, + .data = &qcom_geni_console_driver, +}; + +static struct uart_driver qcom_geni_console_driver = { + .owner = THIS_MODULE, + .driver_name = "qcom_geni_console", + .dev_name = "ttyMSM", + .nr = GENI_UART_CONS_PORTS, + .cons = &cons_ops, +}; +#else +static int console_register(struct uart_driver *drv) +{ + return 0; +} + +static void console_unregister(struct uart_driver *drv) +{ +} +#endif /* CONFIG_SERIAL_QCOM_GENI_CONSOLE */ + +static void qcom_geni_serial_cons_pm(struct uart_port *uport, + unsigned int new_state, unsigned int old_state) +{ + struct qcom_geni_serial_port *port = to_dev_port(uport, uport); + + if (unlikely(!uart_console(uport))) + return; + + if (new_state == UART_PM_STATE_ON && old_state == UART_PM_STATE_OFF) + geni_se_resources_on(&port->se); + else if (new_state == UART_PM_STATE_OFF && + old_state == UART_PM_STATE_ON) + geni_se_resources_off(&port->se); +} + +static const struct uart_ops qcom_geni_console_pops = { + .tx_empty = qcom_geni_serial_tx_empty, + .stop_tx = qcom_geni_serial_stop_tx, + .start_tx = qcom_geni_serial_start_tx, + .stop_rx = qcom_geni_serial_stop_rx, + .set_termios = qcom_geni_serial_set_termios, + .startup = qcom_geni_serial_startup, + .request_port = qcom_geni_serial_request_port, + .config_port = qcom_geni_serial_config_port, + .shutdown = qcom_geni_serial_shutdown, + .type = qcom_geni_serial_get_type, + .set_mctrl = qcom_geni_cons_set_mctrl, + .get_mctrl = qcom_geni_cons_get_mctrl, +#ifdef CONFIG_CONSOLE_POLL + .poll_get_char = qcom_geni_serial_get_char, + .poll_put_char = qcom_geni_serial_poll_put_char, +#endif + .pm = qcom_geni_serial_cons_pm, +}; + +static int qcom_geni_serial_probe(struct platform_device *pdev) +{ + int ret = 0; + int line = -1; + struct qcom_geni_serial_port *port; + struct uart_port *uport; + struct resource *res; + + if (pdev->dev.of_node) + line = of_alias_get_id(pdev->dev.of_node, "serial"); + else + line = pdev->id; + + if (line < 0 || line >= GENI_UART_CONS_PORTS) + return -ENXIO; + port = get_port_from_line(line); + if (IS_ERR(port)) { + ret = PTR_ERR(port); + dev_err(&pdev->dev, "Invalid line %d(%d)\n", line, ret); + return ret; + } + + uport = &port->uport; + /* Don't allow 2 drivers to access the same port */ + if (uport->private_data) + return -ENODEV; + + uport->dev = &pdev->dev; + port->se.dev = &pdev->dev; + port->se.wrapper = dev_get_drvdata(pdev->dev.parent); + port->se.clk = devm_clk_get(&pdev->dev, "se"); + if (IS_ERR(port->se.clk)) { + ret = PTR_ERR(port->se.clk); + dev_err(&pdev->dev, "Err getting SE Core clk %d\n", ret); + return ret; + } + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (IS_ERR(res)) + return PTR_ERR(res); + uport->mapbase = res->start; + + port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS; + port->rx_fifo_depth = DEF_FIFO_DEPTH_WORDS; + port->tx_fifo_width = DEF_FIFO_WIDTH_BITS; + + uport->irq = platform_get_irq(pdev, 0); + if (uport->irq < 0) { + dev_err(&pdev->dev, "Failed to get IRQ %d\n", uport->irq); + return uport->irq; + } + + uport->private_data = &qcom_geni_console_driver; + platform_set_drvdata(pdev, port); + port->handle_rx = handle_rx_console; + port->setup = false; + return uart_add_one_port(&qcom_geni_console_driver, uport); +} + +static int qcom_geni_serial_remove(struct platform_device *pdev) +{ + struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_driver *drv = port->uport.private_data; + + uart_remove_one_port(drv, &port->uport); + return 0; +} + +static int __maybe_unused qcom_geni_serial_sys_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_port *uport = &port->uport; + + uart_suspend_port(uport->private_data, uport); + return 0; +} + +static int __maybe_unused qcom_geni_serial_sys_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct qcom_geni_serial_port *port = platform_get_drvdata(pdev); + struct uart_port *uport = &port->uport; + + if (console_suspend_enabled && uport->suspended) { + uart_resume_port(uport->private_data, uport); + disable_irq(uport->irq); + } + return 0; +} + +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) +}; + +static const struct of_device_id qcom_geni_serial_match_table[] = { + { .compatible = "qcom,geni-debug-uart", }, + {} +}; +MODULE_DEVICE_TABLE(of, qcom_geni_serial_match_table); + +static struct platform_driver qcom_geni_serial_platform_driver = { + .remove = qcom_geni_serial_remove, + .probe = qcom_geni_serial_probe, + .driver = { + .name = "qcom_geni_serial", + .of_match_table = qcom_geni_serial_match_table, + .pm = &qcom_geni_serial_pm_ops, + }, +}; + +static int __init qcom_geni_serial_init(void) +{ + int ret; + + qcom_geni_console_port.uport.iotype = UPIO_MEM; + qcom_geni_console_port.uport.ops = &qcom_geni_console_pops; + qcom_geni_console_port.uport.flags = UPF_BOOT_AUTOCONF; + qcom_geni_console_port.uport.line = 0; + + ret = console_register(&qcom_geni_console_driver); + if (ret) + return ret; + + ret = platform_driver_register(&qcom_geni_serial_platform_driver); + if (ret) + console_unregister(&qcom_geni_console_driver); + return ret; +} +module_init(qcom_geni_serial_init); + +static void __exit qcom_geni_serial_exit(void) +{ + platform_driver_unregister(&qcom_geni_serial_platform_driver); + console_unregister(&qcom_geni_console_driver); +} +module_exit(qcom_geni_serial_exit); + +MODULE_DESCRIPTION("Serial driver for GENI based QUP cores"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 7693b331d033ecda61097007330d3e7461ff7f27 Mon Sep 17 00:00:00 2001 From: Wei Yongjun Date: Thu, 22 Mar 2018 02:25:07 +0000 Subject: tty: serial: msm_geni_serial: Fix return value check in qcom_geni_serial_probe() In case of error, the function platform_get_resource() returns NULL pointer not ERR_PTR(). The IS_ERR() test in the return value check should be replaced with NULL test. Fixes: c4f528795d1a ("tty: serial: msm_geni_serial: Add serial driver support for GENI based QUP") Signed-off-by: Wei Yongjun Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/qcom_geni_serial.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index 14427778ad14..65ff669373d4 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -1053,8 +1053,8 @@ static int qcom_geni_serial_probe(struct platform_device *pdev) } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (IS_ERR(res)) - return PTR_ERR(res); + if (!res) + return -EINVAL; uport->mapbase = res->start; port->tx_fifo_depth = DEF_FIFO_DEPTH_WORDS; -- cgit v1.2.3 From c685af1108d7c303f0b901413405d68eaeac4477 Mon Sep 17 00:00:00 2001 From: Gabriel Matni Date: Thu, 22 Mar 2018 19:15:12 +0000 Subject: serial: mvebu-uart: fix tx lost characters Fixes missing characters on kernel console at low baud rates (i.e.9600). The driver should poll TX_RDY or TX_FIFO_EMP instead of TX_EMP to ensure that the transmitter holding register (THR) is ready to receive a new byte. TX_EMP tells us when it is possible to send a break sequence via SND_BRK_SEQ. While this also indicates that both the THR and the TSR are empty, it does not guarantee that a new byte can be written just yet. Fixes: 30530791a7a0 ("serial: mvebu-uart: initial support for Armada-3700 serial port") Reviewed-by: Miquel Raynal Acked-by: Gregory CLEMENT Signed-off-by: Gabriel Matni Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/mvebu-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/mvebu-uart.c b/drivers/tty/serial/mvebu-uart.c index a4176afb9404..750e5645dc85 100644 --- a/drivers/tty/serial/mvebu-uart.c +++ b/drivers/tty/serial/mvebu-uart.c @@ -618,7 +618,7 @@ static void wait_for_xmitr(struct uart_port *port) u32 val; readl_poll_timeout_atomic(port->membase + UART_STAT, val, - (val & STAT_TX_EMP), 1, 10000); + (val & STAT_TX_RDY(port)), 1, 10000); } static void mvebu_uart_console_putchar(struct uart_port *port, int ch) -- cgit v1.2.3 From 4f794097797f551917b68797e39f25fcb17d5b3a Mon Sep 17 00:00:00 2001 From: Jeremy Kerr Date: Wed, 21 Mar 2018 10:52:38 +0800 Subject: serial: expose buf_overrun count through proc interface The buf_overrun count is only every written, and not exposed to userspace anywhere. This means that dropped characters due to flip buffer overruns are never visible to userspace. The /proc/tty/driver/serial file exports a bunch of metrics (including hardware overruns) already, so add the buf_overrun (as "bo:") to this file. Signed-off-by: Jeremy Kerr Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/serial_core.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'drivers/tty/serial') diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 35b9201db3b4..0466f9f08a91 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -1786,6 +1786,8 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i) seq_printf(m, " brk:%d", uport->icount.brk); if (uport->icount.overrun) seq_printf(m, " oe:%d", uport->icount.overrun); + if (uport->icount.buf_overrun) + seq_printf(m, " bo:%d", uport->icount.buf_overrun); #define INFOBIT(bit, str) \ if (uport->mctrl & (bit)) \ -- cgit v1.2.3