diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
-rw-r--r-- | drivers/tty/serial/imx.c | 315 |
1 files changed, 241 insertions, 74 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e14813250616..9c59ec128bb4 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -8,6 +8,7 @@ * Copyright (C) 2004 Pengutronix */ +#include <linux/circ_buf.h> #include <linux/module.h> #include <linux/ioport.h> #include <linux/init.h> @@ -26,6 +27,7 @@ #include <linux/slab.h> #include <linux/of.h> #include <linux/io.h> +#include <linux/iopoll.h> #include <linux/dma-mapping.h> #include <asm/irq.h> @@ -118,6 +120,7 @@ #define UCR4_OREN (1<<1) /* Receiver overrun interrupt enable */ #define UCR4_DREN (1<<0) /* Recv data ready interrupt enable */ #define UFCR_RXTL_SHF 0 /* Receiver trigger level shift */ +#define UFCR_RXTL_MASK 0x3F /* Receiver trigger 6 bits wide */ #define UFCR_DCEDTE (1<<6) /* DCE/DTE mode select */ #define UFCR_RFDIV (7<<7) /* Reference freq divider mask */ #define UFCR_RFDIV_REG(x) (((x) < 7 ? 6 - (x) : 6) << 7) @@ -227,6 +230,8 @@ struct imx_port { unsigned int saved_reg[10]; bool context_saved; + bool last_putchar_was_newline; + enum imx_tx_state tx_state; struct hrtimer trigger_start_tx; struct hrtimer trigger_stop_tx; @@ -262,6 +267,11 @@ static const struct of_device_id imx_uart_dt_ids[] = { }; MODULE_DEVICE_TABLE(of, imx_uart_dt_ids); +static inline struct imx_port *to_imx_port(struct uart_port *port) +{ + return container_of(port, struct imx_port, port); +} + static inline void imx_uart_writel(struct imx_port *sport, u32 val, u32 offset) { writel(val, sport->port.membase + offset); @@ -362,6 +372,7 @@ static void imx_uart_soft_reset(struct imx_port *sport) sport->idle_counter = 0; } +/* called with port.lock taken and irqs off */ static void imx_uart_disable_loopback_rs485(struct imx_port *sport) { unsigned int uts; @@ -375,7 +386,7 @@ static void imx_uart_disable_loopback_rs485(struct imx_port *sport) /* called with port.lock taken and irqs off */ static void imx_uart_start_rx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ucr1, ucr2; ucr1 = imx_uart_readl(sport, UCR1); @@ -399,7 +410,7 @@ static void imx_uart_start_rx(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_stop_tx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); u32 ucr1, ucr4, usr2; if (sport->tx_state == OFF) @@ -462,9 +473,10 @@ static void imx_uart_stop_tx(struct uart_port *port) } } +/* called with port.lock taken and irqs off */ static void imx_uart_stop_rx_with_loopback_ctrl(struct uart_port *port, bool loopback) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); u32 ucr1, ucr2, ucr4, uts; ucr1 = imx_uart_readl(sport, UCR1); @@ -509,7 +521,7 @@ static void imx_uart_stop_rx(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_enable_ms(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); mod_timer(&sport->timer, jiffies); @@ -521,7 +533,8 @@ static void imx_uart_dma_tx(struct imx_port *sport); /* called with port.lock taken and irqs off */ static inline void imx_uart_transmit_buffer(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; + unsigned char c; if (sport->port.x_char) { /* Send next char */ @@ -531,7 +544,8 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + if (kfifo_is_empty(&tport->xmit_fifo) || + uart_tx_stopped(&sport->port)) { imx_uart_stop_tx(&sport->port); return; } @@ -555,26 +569,22 @@ static inline void imx_uart_transmit_buffer(struct imx_port *sport) return; } - while (!uart_circ_empty(xmit) && - !(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); - uart_xmit_advance(&sport->port, 1); - } + while (!(imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) && + uart_fifo_get(&sport->port, &c)) + imx_uart_writel(sport, c, URTX0); - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (uart_circ_empty(xmit)) + if (kfifo_is_empty(&tport->xmit_fifo)) imx_uart_stop_tx(&sport->port); } static void imx_uart_dma_tx_callback(void *data) { struct imx_port *sport = data; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = &sport->tx_sgl[0]; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; u32 ucr1; @@ -592,10 +602,11 @@ static void imx_uart_dma_tx_callback(void *data) sport->dma_is_txing = 0; - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + if (kfifo_len(&tport->xmit_fifo) < WAKEUP_CHARS) uart_write_wakeup(&sport->port); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + if (!kfifo_is_empty(&tport->xmit_fifo) && + !uart_tx_stopped(&sport->port)) imx_uart_dma_tx(sport); else if (sport->port.rs485.flags & SER_RS485_ENABLED) { u32 ucr4 = imx_uart_readl(sport, UCR4); @@ -609,7 +620,7 @@ static void imx_uart_dma_tx_callback(void *data) /* called with port.lock taken and irqs off */ static void imx_uart_dma_tx(struct imx_port *sport) { - struct circ_buf *xmit = &sport->port.state->xmit; + struct tty_port *tport = &sport->port.state->port; struct scatterlist *sgl = sport->tx_sgl; struct dma_async_tx_descriptor *desc; struct dma_chan *chan = sport->dma_chan_tx; @@ -624,18 +635,10 @@ static void imx_uart_dma_tx(struct imx_port *sport) ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); - sport->tx_bytes = uart_circ_chars_pending(xmit); - - if (xmit->tail < xmit->head || xmit->head == 0) { - sport->dma_tx_nents = 1; - sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes); - } else { - sport->dma_tx_nents = 2; - sg_init_table(sgl, 2); - sg_set_buf(sgl, xmit->buf + xmit->tail, - UART_XMIT_SIZE - xmit->tail); - sg_set_buf(sgl + 1, xmit->buf, xmit->head); - } + sg_init_table(sgl, ARRAY_SIZE(sport->tx_sgl)); + sport->tx_bytes = kfifo_len(&tport->xmit_fifo); + sport->dma_tx_nents = kfifo_dma_out_prepare(&tport->xmit_fifo, sgl, + ARRAY_SIZE(sport->tx_sgl), sport->tx_bytes); ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); if (ret == 0) { @@ -653,8 +656,7 @@ static void imx_uart_dma_tx(struct imx_port *sport) desc->callback = imx_uart_dma_tx_callback; desc->callback_param = sport; - dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n", - uart_circ_chars_pending(xmit)); + dev_dbg(dev, "TX: prepare to send %u bytes by DMA.\n", sport->tx_bytes); ucr1 = imx_uart_readl(sport, UCR1); ucr1 |= UCR1_TXDMAEN; @@ -670,10 +672,11 @@ static void imx_uart_dma_tx(struct imx_port *sport) /* called with port.lock taken and irqs off */ static void imx_uart_start_tx(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); + struct tty_port *tport = &sport->port.state->port; u32 ucr1; - if (!sport->port.x_char && uart_circ_empty(&port->state->xmit)) + if (!sport->port.x_char && kfifo_is_empty(&tport->xmit_fifo)) return; /* @@ -749,7 +752,7 @@ static void imx_uart_start_tx(struct uart_port *port) return; } - if (!uart_circ_empty(&port->state->xmit) && + if (!kfifo_is_empty(&tport->xmit_fifo) && !uart_tx_stopped(port)) imx_uart_dma_tx(sport); return; @@ -763,6 +766,21 @@ static irqreturn_t __imx_uart_rtsint(int irq, void *dev_id) imx_uart_writel(sport, USR1_RTSD, USR1); usr1 = imx_uart_readl(sport, USR1) & USR1_RTSS; + /* + * Update sport->old_status here, so any follow-up calls to + * imx_uart_mctrl_check() will be able to recognize that RTS + * state changed since last imx_uart_mctrl_check() call. + * + * In case RTS has been detected as asserted here and later on + * deasserted by the time imx_uart_mctrl_check() was called, + * imx_uart_mctrl_check() can detect the RTS state change and + * trigger uart_handle_cts_change() to unblock the port for + * further TX transfers. + */ + if (usr1 & USR1_RTSS) + sport->old_status |= TIOCM_CTS; + else + sport->old_status &= ~TIOCM_CTS; uart_handle_cts_change(&sport->port, usr1); wake_up_interruptible(&sport->port.state->port.delta_msr_wait); @@ -804,6 +822,8 @@ static irqreturn_t imx_uart_txint(int irq, void *dev_id) * issuing soft reset to the UART (just stop/start of RX does not help). Note * that what we do here is sending isolated start bit about 2.4 times shorter * than it is to be on UART configured baud rate. + * + * Called with port.lock taken and irqs off. */ static void imx_uart_check_flood(struct imx_port *sport, u32 usr2) { @@ -839,6 +859,7 @@ static void imx_uart_check_flood(struct imx_port *sport, u32 usr2) } } +/* called with port.lock taken and irqs off */ static irqreturn_t __imx_uart_rxint(int irq, void *dev_id) { struct imx_port *sport = dev_id; @@ -917,6 +938,7 @@ 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. */ +/* called with port.lock taken and irqs off */ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) { unsigned int tmp = TIOCM_DSR; @@ -939,6 +961,8 @@ static unsigned int imx_uart_get_hwmctrl(struct imx_port *sport) /* * Handle any change of modem status signal since we were last called. + * + * Called with port.lock taken and irqs off. */ static void imx_uart_mctrl_check(struct imx_port *sport) { @@ -1050,7 +1074,7 @@ static irqreturn_t imx_uart_int(int irq, void *dev_id) */ static unsigned int imx_uart_tx_empty(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ret; ret = (imx_uart_readl(sport, USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; @@ -1065,7 +1089,7 @@ static unsigned int imx_uart_tx_empty(struct uart_port *port) /* called with port.lock taken and irqs off */ static unsigned int imx_uart_get_mctrl(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int ret = imx_uart_get_hwmctrl(sport); mctrl_gpio_get(sport->gpios, &ret); @@ -1076,7 +1100,7 @@ static unsigned int imx_uart_get_mctrl(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); u32 ucr3, uts; if (!(port->rs485.flags & SER_RS485_ENABLED)) { @@ -1119,7 +1143,7 @@ static void imx_uart_set_mctrl(struct uart_port *port, unsigned int mctrl) */ static void imx_uart_break_ctl(struct uart_port *port, int break_state) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr1; @@ -1278,6 +1302,7 @@ static int imx_uart_start_rx_dma(struct imx_port *sport) return 0; } +/* called with port.lock taken and irqs off */ static void imx_uart_clear_rx_errors(struct imx_port *sport) { struct tty_port *port = &sport->port.state->port; @@ -1312,7 +1337,7 @@ static void imx_uart_clear_rx_errors(struct imx_port *sport) } -#define TXTL_DEFAULT 2 /* reset default */ +#define TXTL_DEFAULT 8 #define RXTL_DEFAULT 8 /* 8 characters or aging timer */ #define TXTL_DMA 8 /* DMA burst setting */ #define RXTL_DMA 9 /* DMA burst setting */ @@ -1408,6 +1433,7 @@ err: return ret; } +/* called with port.lock taken and irqs off */ static void imx_uart_enable_dma(struct imx_port *sport) { u32 ucr1; @@ -1441,7 +1467,7 @@ static void imx_uart_disable_dma(struct imx_port *sport) static int imx_uart_startup(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); int retval; unsigned long flags; int dma_is_inited = 0; @@ -1555,9 +1581,10 @@ static int imx_uart_startup(struct uart_port *port) static void imx_uart_shutdown(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr1, ucr2, ucr4, uts; + int loops; if (sport->dma_is_enabled) { dmaengine_terminate_sync(sport->dma_chan_tx); @@ -1620,6 +1647,56 @@ static void imx_uart_shutdown(struct uart_port *port) ucr4 &= ~UCR4_TCEN; imx_uart_writel(sport, ucr4, UCR4); + /* + * We have to ensure the tx state machine ends up in OFF. This + * is especially important for rs485 where we must not leave + * the RTS signal high, blocking the bus indefinitely. + * + * All interrupts are now disabled, so imx_uart_stop_tx() will + * no longer be called from imx_uart_transmit_buffer(). It may + * still be called via the hrtimers, and if those are in play, + * we have to honour the delays. + */ + if (sport->tx_state == WAIT_AFTER_RTS || sport->tx_state == SEND) + imx_uart_stop_tx(port); + + /* + * In many cases (rs232 mode, or if tx_state was + * WAIT_AFTER_RTS, or if tx_state was SEND and there is no + * delay_rts_after_send), this will have moved directly to + * OFF. In rs485 mode, tx_state might already have been + * WAIT_AFTER_SEND and the hrtimer thus already started, or + * the above imx_uart_stop_tx() call could have started it. In + * those cases, we have to wait for the hrtimer to fire and + * complete the transition to OFF. + */ + loops = port->rs485.flags & SER_RS485_ENABLED ? + port->rs485.delay_rts_after_send : 0; + while (sport->tx_state != OFF && loops--) { + uart_port_unlock_irqrestore(&sport->port, flags); + msleep(1); + uart_port_lock_irqsave(&sport->port, &flags); + } + + if (sport->tx_state != OFF) { + dev_warn(sport->port.dev, "unexpected tx_state %d\n", + sport->tx_state); + /* + * This machine may be busted, but ensure the RTS + * signal is inactive in order not to block other + * devices. + */ + if (port->rs485.flags & SER_RS485_ENABLED) { + ucr2 = imx_uart_readl(sport, UCR2); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + imx_uart_rts_active(sport, &ucr2); + else + imx_uart_rts_inactive(sport, &ucr2); + imx_uart_writel(sport, ucr2, UCR2); + } + sport->tx_state = OFF; + } + uart_port_unlock_irqrestore(&sport->port, flags); clk_disable_unprepare(sport->clk_per); @@ -1629,7 +1706,7 @@ static void imx_uart_shutdown(struct uart_port *port) /* called with port.lock taken and irqs off */ static void imx_uart_flush_buffer(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); struct scatterlist *sgl = &sport->tx_sgl[0]; if (!sport->dma_chan_tx) @@ -1656,7 +1733,7 @@ static void imx_uart_set_termios(struct uart_port *port, struct ktermios *termios, const struct ktermios *old) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr2, old_ucr2, ufcr; unsigned int baud, quot; @@ -1859,7 +1936,7 @@ imx_uart_verify_port(struct uart_port *port, struct serial_struct *ser) static int imx_uart_poll_init(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned long flags; u32 ucr1, ucr2; int retval; @@ -1908,7 +1985,7 @@ static int imx_uart_poll_init(struct uart_port *port) static int imx_uart_poll_get_char(struct uart_port *port) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); if (!(imx_uart_readl(sport, USR2) & USR2_RDR)) return NO_POLL_CHAR; @@ -1917,7 +1994,7 @@ static int imx_uart_poll_get_char(struct uart_port *port) static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); unsigned int status; /* drain */ @@ -1939,8 +2016,8 @@ static void imx_uart_poll_put_char(struct uart_port *port, unsigned char c) static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termios, struct serial_rs485 *rs485conf) { - struct imx_port *sport = (struct imx_port *)port; - u32 ucr2; + struct imx_port *sport = to_imx_port(port); + u32 ucr2, ufcr; if (rs485conf->flags & SER_RS485_ENABLED) { /* Enable receiver if low-active RTS signal is requested */ @@ -1959,8 +2036,13 @@ static int imx_uart_rs485_config(struct uart_port *port, struct ktermios *termio /* 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) + rs485conf->flags & SER_RS485_RX_DURING_TX) { + /* If the receiver trigger is 0, set it to a default value */ + ufcr = imx_uart_readl(sport, UFCR); + if ((ufcr & UFCR_RXTL_MASK) == 0) + imx_uart_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); imx_uart_start_rx(port); + } return 0; } @@ -1993,32 +2075,40 @@ static struct imx_port *imx_uart_ports[UART_NR]; #if IS_ENABLED(CONFIG_SERIAL_IMX_CONSOLE) static void imx_uart_console_putchar(struct uart_port *port, unsigned char ch) { - struct imx_port *sport = (struct imx_port *)port; + struct imx_port *sport = to_imx_port(port); while (imx_uart_readl(sport, imx_uart_uts_reg(sport)) & UTS_TXFULL) barrier(); imx_uart_writel(sport, ch, URTX0); + + sport->last_putchar_was_newline = (ch == '\n'); } -/* - * Interrupts are disabled on entering - */ -static void -imx_uart_console_write(struct console *co, const char *s, unsigned int count) +static void imx_uart_console_device_lock(struct console *co, unsigned long *flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_lock_irqsave(up, flags); +} + +static void imx_uart_console_device_unlock(struct console *co, unsigned long flags) +{ + struct uart_port *up = &imx_uart_ports[co->index]->port; + + return __uart_port_unlock_irqrestore(up, flags); +} + +static void imx_uart_console_write_atomic(struct console *co, + struct nbcon_write_context *wctxt) { struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; struct imx_port_ucrs old_ucr; - unsigned long flags; - unsigned int ucr1; - int locked = 1; + unsigned int ucr1, usr2; - if (sport->port.sysrq) - locked = 0; - else if (oops_in_progress) - locked = uart_port_trylock_irqsave(&sport->port, &flags); - else - uart_port_lock_irqsave(&sport->port, &flags); + if (!nbcon_enter_unsafe(wctxt)) + return; /* * First, save UCR1/2/3 and then disable interrupts @@ -2032,21 +2122,88 @@ imx_uart_console_write(struct console *co, const char *s, unsigned int count) ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); imx_uart_writel(sport, ucr1, UCR1); - imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); - uart_console_write(&sport->port, s, count, imx_uart_console_putchar); + if (!sport->last_putchar_was_newline) + uart_console_write(port, "\n", 1, imx_uart_console_putchar); + uart_console_write(port, wctxt->outbuf, wctxt->len, + imx_uart_console_putchar); /* * Finally, wait for transmitter to become empty * and restore UCR1/2/3 */ - while (!(imx_uart_readl(sport, USR2) & USR2_TXDC)); + read_poll_timeout_atomic(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); + imx_uart_ucrs_restore(sport, &old_ucr); + + nbcon_exit_unsafe(wctxt); +} + +static void imx_uart_console_write_thread(struct console *co, + struct nbcon_write_context *wctxt) +{ + struct imx_port *sport = imx_uart_ports[co->index]; + struct uart_port *port = &sport->port; + struct imx_port_ucrs old_ucr; + unsigned int ucr1, usr2; + + if (!nbcon_enter_unsafe(wctxt)) + return; + + /* + * First, save UCR1/2/3 and then disable interrupts + */ + imx_uart_ucrs_save(sport, &old_ucr); + ucr1 = old_ucr.ucr1; + if (imx_uart_is_imx1(sport)) + ucr1 |= IMX1_UCR1_UARTCLKEN; + ucr1 |= UCR1_UARTEN; + ucr1 &= ~(UCR1_TRDYEN | UCR1_RRDYEN | UCR1_RTSDEN); + + imx_uart_writel(sport, ucr1, UCR1); + imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2); + + if (nbcon_exit_unsafe(wctxt)) { + int len = READ_ONCE(wctxt->len); + int i; + + /* + * Write out the message. Toggle unsafe for each byte in order + * to give another (higher priority) context the opportunity + * for a friendly takeover. If such a takeover occurs, this + * context must reacquire ownership in order to perform final + * actions (such as re-enabling the interrupts). + * + * IMPORTANT: wctxt->outbuf and wctxt->len are no longer valid + * after a reacquire so writing the message must be + * aborted. + */ + for (i = 0; i < len; i++) { + if (!nbcon_enter_unsafe(wctxt)) + break; + + uart_console_write(port, wctxt->outbuf + i, 1, + imx_uart_console_putchar); + + if (!nbcon_exit_unsafe(wctxt)) + break; + } + } + + while (!nbcon_enter_unsafe(wctxt)) + nbcon_reacquire_nobuf(wctxt); + + /* + * Finally, wait for transmitter to become empty + * and restore UCR1/2/3 + */ + read_poll_timeout(imx_uart_readl, usr2, usr2 & USR2_TXDC, + 0, USEC_PER_SEC, false, sport, USR2); imx_uart_ucrs_restore(sport, &old_ucr); - if (locked) - uart_port_unlock_irqrestore(&sport->port, flags); + nbcon_exit_unsafe(wctxt); } /* @@ -2138,6 +2295,8 @@ imx_uart_console_setup(struct console *co, char *options) if (retval) goto error_console; + sport->last_putchar_was_newline = true; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else @@ -2174,11 +2333,14 @@ imx_uart_console_exit(struct console *co) static struct uart_driver imx_uart_uart_driver; static struct console imx_uart_console = { .name = DEV_NAME, - .write = imx_uart_console_write, + .write_atomic = imx_uart_console_write_atomic, + .write_thread = imx_uart_console_write_thread, + .device_lock = imx_uart_console_device_lock, + .device_unlock = imx_uart_console_device_unlock, + .flags = CON_PRINTBUFFER | CON_NBCON, .device = uart_console_device, .setup = imx_uart_console_setup, .exit = imx_uart_console_exit, - .flags = CON_PRINTBUFFER, .index = -1, .data = &imx_uart_uart_driver, }; @@ -2525,10 +2687,13 @@ static void imx_uart_save_context(struct imx_port *sport) uart_port_unlock_irqrestore(&sport->port, flags); } +/* called with irq off */ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) { u32 ucr3; + uart_port_lock_irq(&sport->port); + ucr3 = imx_uart_readl(sport, UCR3); if (on) { imx_uart_writel(sport, USR1_AWAKE, USR1); @@ -2548,6 +2713,8 @@ static void imx_uart_enable_wakeup(struct imx_port *sport, bool on) } imx_uart_writel(sport, ucr1, UCR1); } + + uart_port_unlock_irq(&sport->port); } static int imx_uart_suspend_noirq(struct device *dev) @@ -2647,7 +2814,7 @@ static const struct dev_pm_ops imx_uart_pm_ops = { static struct platform_driver imx_uart_platform_driver = { .probe = imx_uart_probe, - .remove_new = imx_uart_remove, + .remove = imx_uart_remove, .driver = { .name = "imx-uart", |