diff options
Diffstat (limited to 'drivers/tty/serial/fsl_lpuart.c')
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 614 |
1 files changed, 340 insertions, 274 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index 92dad2b4ec36..91e2805e6441 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -5,10 +5,6 @@ * Copyright 2012-2014 Freescale Semiconductor, Inc. */ -#if defined(CONFIG_SERIAL_FSL_LPUART_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) -#define SUPPORT_SYSRQ -#endif - #include <linux/clk.h> #include <linux/console.h> #include <linux/dma-mapping.h> @@ -214,6 +210,7 @@ #define UARTFIFO_TXSIZE_OFF 4 #define UARTFIFO_RXFE 0x00000008 #define UARTFIFO_RXSIZE_OFF 0 +#define UARTFIFO_DEPTH(x) (0x1 << ((x) ? ((x) + 1) : 0)) #define UARTWATER_COUNT_MASK 0xff #define UARTWATER_TXCNT_OFF 8 @@ -436,8 +433,8 @@ static void lpuart_dma_tx(struct lpuart_port *sport) } sport->dma_tx_desc = dmaengine_prep_slave_sg(sport->dma_tx_chan, sgl, - sport->dma_tx_nents, - DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + ret, DMA_MEM_TO_DEV, + DMA_PREP_INTERRUPT); if (!sport->dma_tx_desc) { dma_unmap_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); dev_err(dev, "Cannot prepare TX slave DMA!\n"); @@ -451,6 +448,11 @@ static void lpuart_dma_tx(struct lpuart_port *sport) dma_async_issue_pending(sport->dma_tx_chan); } +static bool lpuart_stopped_or_empty(struct uart_port *port) +{ + return uart_circ_empty(&port->state->xmit) || uart_tx_stopped(port); +} + static void lpuart_dma_tx_complete(void *arg) { struct lpuart_port *sport = arg; @@ -478,7 +480,7 @@ static void lpuart_dma_tx_complete(void *arg) spin_lock_irqsave(&sport->port.lock, flags); - if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + if (!lpuart_stopped_or_empty(&sport->port)) lpuart_dma_tx(sport); spin_unlock_irqrestore(&sport->port.lock, flags); @@ -517,9 +519,16 @@ static int lpuart_dma_tx_request(struct uart_port *port) return 0; } +static bool lpuart_is_32(struct lpuart_port *sport) +{ + return sport->port.iotype == UPIO_MEM32 || + sport->port.iotype == UPIO_MEM32BE; +} + static void lpuart_flush_buffer(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + u32 val; if (sport->lpuart_dma_tx_use) { if (sport->dma_tx_in_progress) { @@ -529,6 +538,30 @@ static void lpuart_flush_buffer(struct uart_port *port) } dmaengine_terminate_all(sport->dma_tx_chan); } + + if (lpuart_is_32(sport)) { + val = lpuart32_read(&sport->port, UARTFIFO); + val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; + lpuart32_write(&sport->port, val, UARTFIFO); + } else { + val = readb(sport->port.membase + UARTCFIFO); + val |= UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH; + writeb(val, sport->port.membase + UARTCFIFO); + } +} + +static void lpuart_wait_bit_set(struct uart_port *port, unsigned int offset, + u8 bit) +{ + while (!(readb(port->membase + offset) & bit)) + cpu_relax(); +} + +static void lpuart32_wait_bit_set(struct uart_port *port, unsigned int offset, + u32 bit) +{ + while (!(lpuart32_read(port, offset) & bit)) + cpu_relax(); } #if defined(CONFIG_CONSOLE_POLL) @@ -574,9 +607,7 @@ static int lpuart_poll_init(struct uart_port *port) static void lpuart_poll_put_char(struct uart_port *port, unsigned char c) { /* drain */ - while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE)) - barrier(); - + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE); writeb(c, port->membase + UARTDR); } @@ -599,26 +630,26 @@ static int lpuart32_poll_init(struct uart_port *port) spin_lock_irqsave(&sport->port.lock, flags); /* Disable Rx & Tx */ - writel(0, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, 0); - temp = readl(sport->port.membase + UARTFIFO); + temp = lpuart32_read(&sport->port, UARTFIFO); /* Enable Rx and Tx FIFO */ - writel(temp | UARTFIFO_RXFE | UARTFIFO_TXFE, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + temp | UARTFIFO_RXFE | UARTFIFO_TXFE); /* flush Tx and Rx FIFO */ - writel(UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH, - sport->port.membase + UARTFIFO); + lpuart32_write(&sport->port, UARTFIFO, + UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH); /* explicitly clear RDRF */ - if (readl(sport->port.membase + UARTSTAT) & UARTSTAT_RDRF) { - readl(sport->port.membase + UARTDATA); - writel(UARTFIFO_RXUF, sport->port.membase + UARTFIFO); + if (lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_RDRF) { + lpuart32_read(&sport->port, UARTDATA); + lpuart32_write(&sport->port, UARTFIFO, UARTFIFO_RXUF); } /* Enable Rx and Tx */ - writel(UARTCTRL_RE | UARTCTRL_TE, sport->port.membase + UARTCTRL); + lpuart32_write(&sport->port, UARTCTRL, UARTCTRL_RE | UARTCTRL_TE); spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -626,18 +657,16 @@ static int lpuart32_poll_init(struct uart_port *port) static void lpuart32_poll_put_char(struct uart_port *port, unsigned char c) { - while (!(readl(port->membase + UARTSTAT) & UARTSTAT_TDRE)) - barrier(); - - writel(c, port->membase + UARTDATA); + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); + lpuart32_write(port, UARTDATA, c); } static int lpuart32_poll_get_char(struct uart_port *port) { - if (!(readl(port->membase + UARTSTAT) & UARTSTAT_RDRF)) + if (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_RDRF)) return NO_POLL_CHAR; - return readl(port->membase + UARTDATA); + return lpuart32_read(port, UARTDATA); } #endif @@ -645,6 +674,18 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport) { struct circ_buf *xmit = &sport->port.state->xmit; + if (sport->port.x_char) { + writeb(sport->port.x_char, sport->port.membase + UARTDR); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + if (lpuart_stopped_or_empty(&sport->port)) { + lpuart_stop_tx(&sport->port); + return; + } + while (!uart_circ_empty(xmit) && (readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size)) { writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR); @@ -664,6 +705,18 @@ static inline void lpuart32_transmit_buffer(struct lpuart_port *sport) struct circ_buf *xmit = &sport->port.state->xmit; unsigned long txcnt; + if (sport->port.x_char) { + lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + if (lpuart_stopped_or_empty(&sport->port)) { + lpuart32_stop_tx(&sport->port); + return; + } + txcnt = lpuart32_read(&sport->port, UARTWATER); txcnt = txcnt >> UARTWATER_TXCNT_OFF; txcnt &= UARTWATER_COUNT_MASK; @@ -687,14 +740,13 @@ static void lpuart_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - struct circ_buf *xmit = &sport->port.state->xmit; unsigned char temp; temp = readb(port->membase + UARTCR2); writeb(temp | UARTCR2_TIE, port->membase + UARTCR2); if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + if (!lpuart_stopped_or_empty(port)) lpuart_dma_tx(sport); } else { if (readb(port->membase + UARTSR1) & UARTSR1_TDRE) @@ -705,11 +757,10 @@ static void lpuart_start_tx(struct uart_port *port) static void lpuart32_start_tx(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long temp; if (sport->lpuart_dma_tx_use) { - if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) + if (!lpuart_stopped_or_empty(port)) lpuart_dma_tx(sport); } else { temp = lpuart32_read(port, UARTCTRL); @@ -753,52 +804,18 @@ static unsigned int lpuart32_tx_empty(struct uart_port *port) return 0; } -static bool lpuart_is_32(struct lpuart_port *sport) -{ - return sport->port.iotype == UPIO_MEM32 || - sport->port.iotype == UPIO_MEM32BE; -} - -static irqreturn_t lpuart_txint(int irq, void *dev_id) +static void lpuart_txint(struct lpuart_port *sport) { - struct lpuart_port *sport = dev_id; - struct circ_buf *xmit = &sport->port.state->xmit; unsigned long flags; spin_lock_irqsave(&sport->port.lock, flags); - if (sport->port.x_char) { - if (lpuart_is_32(sport)) - lpuart32_write(&sport->port, sport->port.x_char, UARTDATA); - else - writeb(sport->port.x_char, sport->port.membase + UARTDR); - goto out; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - if (lpuart_is_32(sport)) - lpuart32_stop_tx(&sport->port); - else - lpuart_stop_tx(&sport->port); - goto out; - } - - if (lpuart_is_32(sport)) - lpuart32_transmit_buffer(sport); - else - lpuart_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - -out: + lpuart_transmit_buffer(sport); spin_unlock_irqrestore(&sport->port.lock, flags); - return IRQ_HANDLED; } -static irqreturn_t lpuart_rxint(int irq, void *dev_id) +static void lpuart_rxint(struct lpuart_port *sport) { - struct lpuart_port *sport = dev_id; - unsigned int flg, ignored = 0; + unsigned int flg, ignored = 0, overrun = 0; struct tty_port *port = &sport->port.state->port; unsigned long flags; unsigned char rx, sr; @@ -825,7 +842,7 @@ static irqreturn_t lpuart_rxint(int irq, void *dev_id) sport->port.icount.frame++; if (sr & UARTSR1_OR) - sport->port.icount.overrun++; + overrun++; if (sr & sport->port.ignore_status_mask) { if (++ignored > 100) @@ -843,24 +860,40 @@ static irqreturn_t lpuart_rxint(int irq, void *dev_id) if (sr & UARTSR1_OR) flg = TTY_OVERRUN; -#ifdef SUPPORT_SYSRQ sport->port.sysrq = 0; -#endif } tty_insert_flip_char(port, rx, flg); } out: + if (overrun) { + sport->port.icount.overrun += overrun; + + /* + * Overruns cause FIFO pointers to become missaligned. + * Flushing the receive FIFO reinitializes the pointers. + */ + writeb(UARTCFIFO_RXFLUSH, sport->port.membase + UARTCFIFO); + writeb(UARTSFIFO_RXOF, sport->port.membase + UARTSFIFO); + } + spin_unlock_irqrestore(&sport->port.lock, flags); tty_flip_buffer_push(port); - return IRQ_HANDLED; } -static irqreturn_t lpuart32_rxint(int irq, void *dev_id) +static void lpuart32_txint(struct lpuart_port *sport) +{ + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + lpuart32_transmit_buffer(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void lpuart32_rxint(struct lpuart_port *sport) { - struct lpuart_port *sport = dev_id; unsigned int flg, ignored = 0; struct tty_port *port = &sport->port.state->port; unsigned long flags; @@ -907,9 +940,7 @@ static irqreturn_t lpuart32_rxint(int irq, void *dev_id) if (sr & UARTSTAT_OR) flg = TTY_OVERRUN; -#ifdef SUPPORT_SYSRQ sport->port.sysrq = 0; -#endif } tty_insert_flip_char(port, rx, flg); @@ -919,7 +950,6 @@ out: spin_unlock_irqrestore(&sport->port.lock, flags); tty_flip_buffer_push(port); - return IRQ_HANDLED; } static irqreturn_t lpuart_int(int irq, void *dev_id) @@ -929,11 +959,11 @@ static irqreturn_t lpuart_int(int irq, void *dev_id) sts = readb(sport->port.membase + UARTSR1); - if (sts & UARTSR1_RDRF) - lpuart_rxint(irq, dev_id); + if (sts & UARTSR1_RDRF && !sport->lpuart_dma_rx_use) + lpuart_rxint(sport); - if (sts & UARTSR1_TDRE) - lpuart_txint(irq, dev_id); + if (sts & UARTSR1_TDRE && !sport->lpuart_dma_tx_use) + lpuart_txint(sport); return IRQ_HANDLED; } @@ -948,10 +978,10 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) rxcount = rxcount >> UARTWATER_RXCNT_OFF; if ((sts & UARTSTAT_RDRF || rxcount > 0) && !sport->lpuart_dma_rx_use) - lpuart32_rxint(irq, dev_id); + lpuart32_rxint(sport); if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) - lpuart_txint(irq, dev_id); + lpuart32_txint(sport); lpuart32_write(&sport->port, sts, UARTSTAT); return IRQ_HANDLED; @@ -982,6 +1012,13 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) unsigned char sr = readb(sport->port.membase + UARTSR1); if (sr & (UARTSR1_PE | UARTSR1_FE)) { + unsigned char cr2; + + /* Disable receiver during this operation... */ + cr2 = readb(sport->port.membase + UARTCR2); + cr2 &= ~UARTCR2_RE; + writeb(cr2, sport->port.membase + UARTCR2); + /* Read DR to clear the error flags */ readb(sport->port.membase + UARTDR); @@ -989,6 +1026,25 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) sport->port.icount.parity++; else if (sr & UARTSR1_FE) sport->port.icount.frame++; + /* + * At this point parity/framing error is + * cleared However, since the DMA already read + * the data register and we had to read it + * again after reading the status register to + * properly clear the flags, the FIFO actually + * underflowed... This requires a clearing of + * the FIFO... + */ + if (readb(sport->port.membase + UARTSFIFO) & + UARTSFIFO_RXUF) { + writeb(UARTSFIFO_RXUF, + sport->port.membase + UARTSFIFO); + writeb(UARTCFIFO_RXFLUSH, + sport->port.membase + UARTCFIFO); + } + + cr2 |= UARTCR2_RE; + writeb(cr2, sport->port.membase + UARTCR2); } } @@ -1097,12 +1153,11 @@ static inline int lpuart_start_rx_dma(struct lpuart_port *sport) if (sport->rx_dma_rng_buf_len < 16) sport->rx_dma_rng_buf_len = 16; - ring->buf = kmalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); + ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); if (!ring->buf) return -ENOMEM; sg_init_one(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); - sg_set_buf(&sport->rx_sgl, ring->buf, sport->rx_dma_rng_buf_len); nent = dma_map_sg(sport->port.dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE); if (!nent) { @@ -1217,6 +1272,57 @@ static int lpuart_config_rs485(struct uart_port *port, return 0; } +static int lpuart32_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485) +{ + struct lpuart_port *sport = container_of(port, + struct lpuart_port, port); + + unsigned long modem = lpuart32_read(&sport->port, UARTMODIR) + & ~(UARTMODEM_TXRTSPOL | UARTMODEM_TXRTSE); + lpuart32_write(&sport->port, modem, UARTMODIR); + + /* clear unsupported configurations */ + rs485->delay_rts_before_send = 0; + rs485->delay_rts_after_send = 0; + rs485->flags &= ~SER_RS485_RX_DURING_TX; + + if (rs485->flags & SER_RS485_ENABLED) { + /* Enable auto RS-485 RTS mode */ + modem |= UARTMODEM_TXRTSE; + + /* + * RTS needs to be logic HIGH either during transer _or_ after + * transfer, other variants are not supported by the hardware. + */ + + if (!(rs485->flags & (SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND))) + rs485->flags |= SER_RS485_RTS_ON_SEND; + + if (rs485->flags & SER_RS485_RTS_ON_SEND && + rs485->flags & SER_RS485_RTS_AFTER_SEND) + rs485->flags &= ~SER_RS485_RTS_AFTER_SEND; + + /* + * The hardware defaults to RTS logic HIGH while transfer. + * Switch polarity in case RTS shall be logic HIGH + * after transfer. + * Note: UART is assumed to be active high. + */ + if (rs485->flags & SER_RS485_RTS_ON_SEND) + modem &= ~UARTMODEM_TXRTSPOL; + else if (rs485->flags & SER_RS485_RTS_AFTER_SEND) + modem |= UARTMODEM_TXRTSPOL; + } + + /* Store the new configuration */ + sport->port.rs485 = *rs485; + + lpuart32_write(&sport->port, modem, UARTMODIR); + return 0; +} + static unsigned int lpuart_get_mctrl(struct uart_port *port) { unsigned int temp = 0; @@ -1270,18 +1376,7 @@ static void lpuart_set_mctrl(struct uart_port *port, unsigned int mctrl) static void lpuart32_set_mctrl(struct uart_port *port, unsigned int mctrl) { - unsigned long temp; - - temp = lpuart32_read(port, UARTMODIR) & - ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); - if (mctrl & TIOCM_RTS) - temp |= UARTMODIR_RXRTSE; - - if (mctrl & TIOCM_CTS) - temp |= UARTMODIR_TXCTSE; - - lpuart32_write(port, temp, UARTMODIR); } static void lpuart_break_ctl(struct uart_port *port, int break_state) @@ -1340,6 +1435,17 @@ static void lpuart_setup_watermark(struct lpuart_port *sport) writeb(cr2_saved, sport->port.membase + UARTCR2); } +static void lpuart_setup_watermark_enable(struct lpuart_port *sport) +{ + unsigned char cr2; + + lpuart_setup_watermark(sport); + + cr2 = readb(sport->port.membase + UARTCR2); + cr2 |= UARTCR2_RIE | UARTCR2_RE | UARTCR2_TE; + writeb(cr2, sport->port.membase + UARTCR2); +} + static void lpuart32_setup_watermark(struct lpuart_port *sport) { unsigned long val, ctrl; @@ -1365,109 +1471,90 @@ static void lpuart32_setup_watermark(struct lpuart_port *sport) lpuart32_write(&sport->port, ctrl_saved, UARTCTRL); } -static void rx_dma_timer_init(struct lpuart_port *sport) +static void lpuart32_setup_watermark_enable(struct lpuart_port *sport) { - timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); - sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; - add_timer(&sport->lpuart_timer); -} - -static int lpuart_startup(struct uart_port *port) -{ - struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned long flags; - unsigned char temp; - - /* determine FIFO size and enable FIFO mode */ - temp = readb(sport->port.membase + UARTPFIFO); - - sport->txfifo_size = 0x1 << (((temp >> UARTPFIFO_TXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); + u32 temp; - sport->port.fifosize = sport->txfifo_size; + lpuart32_setup_watermark(sport); - sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) & - UARTPFIFO_FIFOSIZE_MASK) + 1); + temp = lpuart32_read(&sport->port, UARTCTRL); + temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; + lpuart32_write(&sport->port, temp, UARTCTRL); +} - spin_lock_irqsave(&sport->port.lock, flags); +static void rx_dma_timer_init(struct lpuart_port *sport) +{ + timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); + sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; + add_timer(&sport->lpuart_timer); +} - lpuart_setup_watermark(sport); +static void lpuart_tx_dma_startup(struct lpuart_port *sport) +{ + u32 uartbaud; - temp = readb(sport->port.membase + UARTCR2); - temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); - writeb(temp, sport->port.membase + UARTCR2); + if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { + init_waitqueue_head(&sport->dma_wait); + sport->lpuart_dma_tx_use = true; + if (lpuart_is_32(sport)) { + uartbaud = lpuart32_read(&sport->port, UARTBAUD); + lpuart32_write(&sport->port, + uartbaud | UARTBAUD_TDMAE, UARTBAUD); + } else { + writeb(readb(sport->port.membase + UARTCR5) | + UARTCR5_TDMAS, sport->port.membase + UARTCR5); + } + } else { + sport->lpuart_dma_tx_use = false; + } +} +static void lpuart_rx_dma_startup(struct lpuart_port *sport) +{ if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { /* set Rx DMA timeout */ sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); if (!sport->dma_rx_timeout) - sport->dma_rx_timeout = 1; + sport->dma_rx_timeout = 1; sport->lpuart_dma_rx_use = true; rx_dma_timer_init(sport); } else { sport->lpuart_dma_rx_use = false; } - - if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - temp = readb(port->membase + UARTCR5); - writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5); - } else { - sport->lpuart_dma_tx_use = false; - } - - spin_unlock_irqrestore(&sport->port.lock, flags); - - return 0; } -static int lpuart32_startup(struct uart_port *port) +static int lpuart_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); unsigned long flags; - unsigned long temp; - - /* determine FIFO size */ - temp = lpuart32_read(&sport->port, UARTFIFO); + unsigned char temp; - sport->txfifo_size = 0x1 << (((temp >> UARTFIFO_TXSIZE_OFF) & - UARTFIFO_FIFOSIZE_MASK) - 1); + /* determine FIFO size and enable FIFO mode */ + temp = readb(sport->port.membase + UARTPFIFO); + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_TXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); sport->port.fifosize = sport->txfifo_size; - sport->rxfifo_size = 0x1 << (((temp >> UARTFIFO_RXSIZE_OFF) & - UARTFIFO_FIFOSIZE_MASK) - 1); + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) & + UARTPFIFO_FIFOSIZE_MASK); spin_lock_irqsave(&sport->port.lock, flags); - lpuart32_setup_watermark(sport); + lpuart_setup_watermark_enable(sport); - temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; - lpuart32_write(&sport->port, temp, UARTCTRL); + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); - if (sport->dma_rx_chan && !lpuart_start_rx_dma(sport)) { - /* set Rx DMA timeout */ - sport->dma_rx_timeout = msecs_to_jiffies(DMA_RX_TIMEOUT); - if (!sport->dma_rx_timeout) - sport->dma_rx_timeout = 1; + spin_unlock_irqrestore(&sport->port.lock, flags); - sport->lpuart_dma_rx_use = true; - rx_dma_timer_init(sport); - } else { - sport->lpuart_dma_rx_use = false; - } + return 0; +} - if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - temp = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, temp | UARTBAUD_TDMAE, UARTBAUD); - } else { - sport->lpuart_dma_tx_use = false; - } +static void lpuart32_configure(struct lpuart_port *sport) +{ + unsigned long temp; if (sport->lpuart_dma_rx_use) { /* RXWATER must be 0 */ @@ -1481,27 +1568,40 @@ static int lpuart32_startup(struct uart_port *port) if (!sport->lpuart_dma_tx_use) temp |= UARTCTRL_TIE; lpuart32_write(&sport->port, temp, UARTCTRL); - - spin_unlock_irqrestore(&sport->port.lock, flags); - return 0; } -static void lpuart_shutdown(struct uart_port *port) +static int lpuart32_startup(struct uart_port *port) { struct lpuart_port *sport = container_of(port, struct lpuart_port, port); - unsigned char temp; unsigned long flags; + unsigned long temp; - spin_lock_irqsave(&port->lock, flags); + /* determine FIFO size */ + temp = lpuart32_read(&sport->port, UARTFIFO); - /* disable Rx/Tx and interrupts */ - temp = readb(port->membase + UARTCR2); - temp &= ~(UARTCR2_TE | UARTCR2_RE | - UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); - writeb(temp, port->membase + UARTCR2); + sport->txfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_TXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); + sport->port.fifosize = sport->txfifo_size; - spin_unlock_irqrestore(&port->lock, flags); + sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTFIFO_RXSIZE_OFF) & + UARTFIFO_FIFOSIZE_MASK); + + spin_lock_irqsave(&sport->port.lock, flags); + + lpuart32_setup_watermark_enable(sport); + + + lpuart_rx_dma_startup(sport); + lpuart_tx_dma_startup(sport); + + lpuart32_configure(sport); + + spin_unlock_irqrestore(&sport->port.lock, flags); + return 0; +} +static void lpuart_dma_shutdown(struct lpuart_port *sport) +{ if (sport->lpuart_dma_rx_use) { del_timer_sync(&sport->lpuart_timer); lpuart_dma_rx_free(&sport->port); @@ -1513,11 +1613,28 @@ static void lpuart_shutdown(struct uart_port *port) sport->dma_tx_in_progress = false; dmaengine_terminate_all(sport->dma_tx_chan); } - - lpuart_stop_tx(port); } } +static void lpuart_shutdown(struct uart_port *port) +{ + struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + unsigned char temp; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + + /* disable Rx/Tx and interrupts */ + temp = readb(port->membase + UARTCR2); + temp &= ~(UARTCR2_TE | UARTCR2_RE | + UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); + writeb(temp, port->membase + UARTCR2); + + spin_unlock_irqrestore(&port->lock, flags); + + lpuart_dma_shutdown(sport); +} + static void lpuart32_shutdown(struct uart_port *port) { struct lpuart_port *sport = @@ -1535,20 +1652,7 @@ static void lpuart32_shutdown(struct uart_port *port) spin_unlock_irqrestore(&port->lock, flags); - if (sport->lpuart_dma_rx_use) { - del_timer_sync(&sport->lpuart_timer); - lpuart_dma_rx_free(&sport->port); - } - - if (sport->lpuart_dma_tx_use) { - if (wait_event_interruptible(sport->dma_wait, - !sport->dma_tx_in_progress)) { - sport->dma_tx_in_progress = false; - dmaengine_terminate_all(sport->dma_tx_chan); - } - - lpuart32_stop_tx(port); - } + lpuart_dma_shutdown(sport); } static void @@ -1602,21 +1706,18 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, if (sport->port.rs485.flags & SER_RS485_ENABLED) termios->c_cflag &= ~CRTSCTS; - if (termios->c_cflag & CRTSCTS) { - modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - } else { - termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) + modem |= UARTMODEM_RXRTSE | UARTMODEM_TXCTSE; + else modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); - } - if (termios->c_cflag & CSTOPB) - termios->c_cflag &= ~CSTOPB; + termios->c_cflag &= ~CSTOPB; /* parity must be enabled when CS7 to match 8-bits format */ if ((termios->c_cflag & CSIZE) == CS7) termios->c_cflag |= PARENB; - if ((termios->c_cflag & PARENB)) { + if (termios->c_cflag & PARENB) { if (termios->c_cflag & CMSPAR) { cr1 &= ~UARTCR1_PE; if (termios->c_cflag & PARODD) @@ -1655,7 +1756,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= (UARTSR1_FE | UARTSR1_PE); + sport->port.read_status_mask |= UARTSR1_FE | UARTSR1_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSR1_FE; @@ -1677,8 +1778,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) - barrier(); + lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); /* disable transmit and receive */ writeb(old_cr2 & ~(UARTCR2_TE | UARTCR2_RE), @@ -1769,7 +1869,7 @@ lpuart32_serial_setbrg(struct lpuart_port *sport, unsigned int baudrate) tmp |= UARTBAUD_BOTHEDGE; tmp &= ~(UARTBAUD_OSR_MASK << UARTBAUD_OSR_SHIFT); - tmp |= (((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT); + tmp |= ((osr-1) & UARTBAUD_OSR_MASK) << UARTBAUD_OSR_SHIFT; tmp &= ~UARTBAUD_SBR_MASK; tmp |= sbr & UARTBAUD_SBR_MASK; @@ -1821,11 +1921,18 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, ctrl |= UARTCTRL_M; } + /* + * When auto RS-485 RTS mode is enabled, + * hardware flow control need to be disabled. + */ + if (sport->port.rs485.flags & SER_RS485_ENABLED) + termios->c_cflag &= ~CRTSCTS; + if (termios->c_cflag & CRTSCTS) { - modem |= (UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + modem |= (UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); } else { termios->c_cflag &= ~CRTSCTS; - modem &= ~(UARTMODEM_RXRTSE | UARTMODEM_TXCTSE); + modem &= ~(UARTMODIR_RXRTSE | UARTMODIR_TXCTSE); } if (termios->c_cflag & CSTOPB) @@ -1871,7 +1978,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, sport->port.read_status_mask = 0; if (termios->c_iflag & INPCK) - sport->port.read_status_mask |= (UARTSTAT_FE | UARTSTAT_PE); + sport->port.read_status_mask |= UARTSTAT_FE | UARTSTAT_PE; if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK)) sport->port.read_status_mask |= UARTSTAT_FE; @@ -1893,8 +2000,7 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios, uart_update_timeout(port, termios->c_cflag, baud); /* wait transmit engin complete */ - while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC)) - barrier(); + lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); /* disable transmit and receive */ lpuart32_write(&sport->port, old_ctrl & ~(UARTCTRL_TE | UARTCTRL_RE), @@ -2009,17 +2115,13 @@ static struct lpuart_port *lpuart_ports[UART_NR]; #ifdef CONFIG_SERIAL_FSL_LPUART_CONSOLE static void lpuart_console_putchar(struct uart_port *port, int ch) { - while (!(readb(port->membase + UARTSR1) & UARTSR1_TDRE)) - barrier(); - + lpuart_wait_bit_set(port, UARTSR1, UARTSR1_TDRE); writeb(ch, port->membase + UARTDR); } static void lpuart32_console_putchar(struct uart_port *port, int ch) { - while (!(lpuart32_read(port, UARTSTAT) & UARTSTAT_TDRE)) - barrier(); - + lpuart32_wait_bit_set(port, UARTSTAT, UARTSTAT_TDRE); lpuart32_write(port, ch, UARTDATA); } @@ -2038,15 +2140,14 @@ lpuart_console_write(struct console *co, const char *s, unsigned int count) /* first save CR2 and then disable interrupts */ cr2 = old_cr2 = readb(sport->port.membase + UARTCR2); - cr2 |= (UARTCR2_TE | UARTCR2_RE); + cr2 |= UARTCR2_TE | UARTCR2_RE; cr2 &= ~(UARTCR2_TIE | UARTCR2_TCIE | UARTCR2_RIE); writeb(cr2, sport->port.membase + UARTCR2); uart_console_write(&sport->port, s, count, lpuart_console_putchar); /* wait for transmitter finish complete and restore CR2 */ - while (!(readb(sport->port.membase + UARTSR1) & UARTSR1_TC)) - barrier(); + lpuart_wait_bit_set(&sport->port, UARTSR1, UARTSR1_TC); writeb(old_cr2, sport->port.membase + UARTCR2); @@ -2069,15 +2170,14 @@ lpuart32_console_write(struct console *co, const char *s, unsigned int count) /* first save CR2 and then disable interrupts */ cr = old_cr = lpuart32_read(&sport->port, UARTCTRL); - cr |= (UARTCTRL_TE | UARTCTRL_RE); + cr |= UARTCTRL_TE | UARTCTRL_RE; cr &= ~(UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); lpuart32_write(&sport->port, cr, UARTCTRL); uart_console_write(&sport->port, s, count, lpuart32_console_putchar); /* wait for transmitter finish complete and restore CR2 */ - while (!(lpuart32_read(&sport->port, UARTSTAT) & UARTSTAT_TC)) - barrier(); + lpuart32_wait_bit_set(&sport->port, UARTSTAT, UARTSTAT_TC); lpuart32_write(&sport->port, old_cr, UARTCTRL); @@ -2268,7 +2368,9 @@ static int __init lpuart32_early_console_setup(struct earlycon_device *device, if (!device->port.membase) return -ENODEV; - device->port.iotype = UPIO_MEM32BE; + if (device->port.iotype != UPIO_MEM32) + device->port.iotype = UPIO_MEM32BE; + device->con->write = lpuart32_early_write; return 0; } @@ -2288,8 +2390,6 @@ static int __init lpuart32_imx_early_console_setup(struct earlycon_device *devic OF_EARLYCON_DECLARE(lpuart, "fsl,vf610-lpuart", lpuart_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,ls1021a-lpuart", lpuart32_early_console_setup); OF_EARLYCON_DECLARE(lpuart32, "fsl,imx7ulp-lpuart", lpuart32_imx_early_console_setup); -EARLYCON_DECLARE(lpuart, lpuart_early_console_setup); -EARLYCON_DECLARE(lpuart32, lpuart32_early_console_setup); #define LPUART_CONSOLE (&lpuart_console) #define LPUART32_CONSOLE (&lpuart32_console) @@ -2320,8 +2420,6 @@ static int lpuart_probe(struct platform_device *pdev) if (!sport) return -ENOMEM; - pdev->dev.coherent_dma_mask = 0; - ret = of_alias_get_id(np, "serial"); if (ret < 0) { ret = ida_simple_get(&fsl_lpuart_ida, 0, UART_NR, GFP_KERNEL); @@ -2346,19 +2444,21 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.type = PORT_LPUART; sport->devtype = sdata->devtype; ret = platform_get_irq(pdev, 0); - if (ret < 0) { - dev_err(&pdev->dev, "cannot obtain irq\n"); + if (ret < 0) return ret; - } sport->port.irq = ret; sport->port.iotype = sdata->iotype; if (lpuart_is_32(sport)) sport->port.ops = &lpuart32_pops; else sport->port.ops = &lpuart_pops; + sport->port.has_sysrq = IS_ENABLED(CONFIG_SERIAL_FSL_LPUART_CONSOLE); sport->port.flags = UPF_BOOT_AUTOCONF; - sport->port.rs485_config = lpuart_config_rs485; + if (lpuart_is_32(sport)) + sport->port.rs485_config = lpuart32_config_rs485; + else + sport->port.rs485_config = lpuart_config_rs485; sport->ipg_clk = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->ipg_clk)) { @@ -2412,7 +2512,7 @@ static int lpuart_probe(struct platform_device *pdev) sport->port.rs485.delay_rts_after_send) dev_err(&pdev->dev, "driver doesn't support RTS delays\n"); - lpuart_config_rs485(&sport->port, &sport->port.rs485); + sport->port.rs485_config(&sport->port, &sport->port.rs485); sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx"); if (!sport->dma_tx_chan) @@ -2514,22 +2614,14 @@ static int lpuart_resume(struct device *dev) { struct lpuart_port *sport = dev_get_drvdata(dev); bool irq_wake = irqd_is_wakeup_set(irq_get_irq_data(sport->port.irq)); - unsigned long temp; if (sport->port.suspended && !irq_wake) lpuart_enable_clks(sport); - if (lpuart_is_32(sport)) { - lpuart32_setup_watermark(sport); - temp = lpuart32_read(&sport->port, UARTCTRL); - temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; - lpuart32_write(&sport->port, temp, UARTCTRL); - } else { - lpuart_setup_watermark(sport); - temp = readb(sport->port.membase + UARTCR2); - temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); - writeb(temp, sport->port.membase + UARTCR2); - } + if (lpuart_is_32(sport)) + lpuart32_setup_watermark_enable(sport); + else + lpuart_setup_watermark_enable(sport); if (sport->lpuart_dma_rx_use) { if (irq_wake) { @@ -2540,36 +2632,10 @@ static int lpuart_resume(struct device *dev) } } - if (sport->dma_tx_chan && !lpuart_dma_tx_request(&sport->port)) { - init_waitqueue_head(&sport->dma_wait); - sport->lpuart_dma_tx_use = true; - if (lpuart_is_32(sport)) { - temp = lpuart32_read(&sport->port, UARTBAUD); - lpuart32_write(&sport->port, - temp | UARTBAUD_TDMAE, UARTBAUD); - } else { - writeb(readb(sport->port.membase + UARTCR5) | - UARTCR5_TDMAS, sport->port.membase + UARTCR5); - } - } else { - sport->lpuart_dma_tx_use = false; - } + lpuart_tx_dma_startup(sport); - if (lpuart_is_32(sport)) { - if (sport->lpuart_dma_rx_use) { - /* RXWATER must be 0 */ - temp = lpuart32_read(&sport->port, UARTWATER); - temp &= ~(UARTWATER_WATER_MASK << - UARTWATER_RXWATER_OFF); - lpuart32_write(&sport->port, temp, UARTWATER); - } - temp = lpuart32_read(&sport->port, UARTCTRL); - if (!sport->lpuart_dma_rx_use) - temp |= UARTCTRL_RIE; - if (!sport->lpuart_dma_tx_use) - temp |= UARTCTRL_TIE; - lpuart32_write(&sport->port, temp, UARTCTRL); - } + if (lpuart_is_32(sport)) + lpuart32_configure(sport); uart_resume_port(&lpuart_reg, &sport->port); |