--- zzzz-none-000/linux-3.10.107/drivers/tty/serial/imx.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/tty/serial/imx.c 2021-02-04 17:41:59.000000000 +0000 @@ -1,13 +1,10 @@ /* - * Driver for Motorola IMX serial ports + * Driver for Motorola/Freescale IMX serial ports * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. * - * Author: Sascha Hauer - * Copyright (C) 2004 Pengutronix - * - * Copyright (C) 2009 emlix GmbH - * Author: Fabian Godehardt (added IrDA support for iMX) + * Author: Sascha Hauer + * Copyright (C) 2004 Pengutronix * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -18,13 +15,6 @@ * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * [29-Mar-2005] Mike Lee - * Added hardware handshake */ #if defined(CONFIG_SERIAL_IMX_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) @@ -47,11 +37,12 @@ #include #include #include -#include #include +#include #include #include +#include /* Register definitions */ #define URXD0 0x0 /* Receiver Register */ @@ -73,16 +64,19 @@ #define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/ /* UART Control Register Bit Fields.*/ +#define URXD_DUMMY_READ (1<<16) #define URXD_CHARRDY (1<<15) #define URXD_ERR (1<<14) #define URXD_OVRRUN (1<<13) #define URXD_FRMERR (1<<12) #define URXD_BRK (1<<11) #define URXD_PRERR (1<<10) +#define URXD_RX_DATA (0xFF<<0) #define UCR1_ADEN (1<<15) /* Auto detect interrupt */ #define UCR1_ADBR (1<<14) /* Auto detect baud rate */ #define UCR1_TRDYEN (1<<13) /* Transmitter ready interrupt enable */ #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_IREN (1<<7) /* Infrared interface enable */ @@ -91,6 +85,7 @@ #define UCR1_SNDBRK (1<<4) /* Send break */ #define UCR1_TDMAEN (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 */ #define UCR1_UARTEN (1<<0) /* UART enabled */ #define UCR2_ESCI (1<<15) /* Escape seq interrupt enable */ @@ -113,7 +108,7 @@ #define UCR3_DSR (1<<10) /* Data set ready */ #define UCR3_DCD (1<<9) /* Data carrier detect */ #define UCR3_RI (1<<8) /* Ring indicator */ -#define UCR3_TIMEOUTEN (1<<7) /* Timeout interrupt enable */ +#define UCR3_ADNIMP (1<<7) /* Autobaud Detection Not Improved */ #define UCR3_RXDSEN (1<<6) /* Receive status interrupt enable */ #define UCR3_AIRINTEN (1<<5) /* Async IR wake interrupt enable */ #define UCR3_AWAKEN (1<<4) /* Async wake interrupt enable */ @@ -126,6 +121,7 @@ #define UCR4_ENIRI (1<<8) /* Serial infrared interrupt enable */ #define UCR4_WKEN (1<<7) /* Wake interrupt enable */ #define UCR4_REF16 (1<<6) /* Ref freq 16 MHz */ +#define UCR4_IDDMAEN (1<<6) /* DMA IDLE Condition Detected */ #define UCR4_IRSC (1<<5) /* IR special case */ #define UCR4_TCEN (1<<3) /* Transmit complete interrupt enable */ #define UCR4_BKEN (1<<2) /* Break condition interrupt enable */ @@ -143,6 +139,7 @@ #define USR1_ESCF (1<<11) /* Escape seq interrupt flag */ #define USR1_FRAMERR (1<<10) /* Frame error interrupt flag */ #define USR1_RRDY (1<<9) /* Receiver ready interrupt/dma flag */ +#define USR1_AGTIM (1<<8) /* Ageing timer interrupt flag */ #define USR1_TIMEOUT (1<<7) /* Receive timeout interrupt status */ #define USR1_RXDS (1<<6) /* Receiver idle interrupt flag */ #define USR1_AIRINT (1<<5) /* Async IR wake interrupt flag */ @@ -183,10 +180,11 @@ #define UART_NR 8 -/* i.mx21 type uart runs on all i.mx except i.mx1 */ +/* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */ enum imx_uart_type { IMX1_UART, IMX21_UART, + IMX6Q_UART, }; /* device type dependent stuff */ @@ -199,15 +197,28 @@ struct uart_port port; struct timer_list timer; unsigned int old_status; - int txirq, rxirq, rtsirq; unsigned int have_rtscts:1; - unsigned int use_irda:1; + unsigned int dte_mode:1; unsigned int irda_inv_rx:1; unsigned int irda_inv_tx:1; unsigned short trcv_delay; /* transceiver delay */ struct clk *clk_ipg; struct clk *clk_per; const struct imx_uart_data *devdata; + + /* 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; + struct dma_chan *dma_chan_rx, *dma_chan_tx; + struct scatterlist rx_sgl, tx_sgl[2]; + void *rx_buf; + unsigned int tx_bytes; + unsigned int dma_tx_nents; + wait_queue_head_t dma_wait; + unsigned int saved_reg[10]; + bool context_saved; }; struct imx_port_ucrs { @@ -216,12 +227,6 @@ unsigned int ucr3; }; -#ifdef CONFIG_IRDA -#define USE_IRDA(sport) ((sport)->use_irda) -#else -#define USE_IRDA(sport) (0) -#endif - static struct imx_uart_data imx_uart_devdata[] = { [IMX1_UART] = { .uts_reg = IMX1_UTS, @@ -231,9 +236,13 @@ .uts_reg = IMX21_UTS, .devtype = IMX21_UART, }, + [IMX6Q_UART] = { + .uts_reg = IMX21_UTS, + .devtype = IMX6Q_UART, + }, }; -static struct platform_device_id imx_uart_devtype[] = { +static const struct platform_device_id imx_uart_devtype[] = { { .name = "imx1-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX1_UART], @@ -241,12 +250,16 @@ .name = "imx21-uart", .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART], }, { + .name = "imx6q-uart", + .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART], + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, imx_uart_devtype); -static struct of_device_id imx_uart_dt_ids[] = { +static const struct of_device_id imx_uart_dt_ids[] = { + { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], }, { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], }, { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], }, { /* sentinel */ } @@ -268,9 +281,14 @@ return sport->devdata->devtype == IMX21_UART; } +static inline int is_imx6q_uart(struct imx_port *sport) +{ + return sport->devdata->devtype == IMX6Q_UART; +} /* * 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, struct imx_port_ucrs *ucr) { @@ -288,6 +306,7 @@ writel(ucr->ucr2, port->membase + UCR2); writel(ucr->ucr3, port->membase + UCR3); } +#endif /* * Handle any change of modem status signal since we were last called. @@ -342,50 +361,30 @@ struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex - wait for end of transmission */ - int n = 256; - while ((--n > 0) && - !(readl(sport->port.membase + USR2) & USR2_TXDC)) { - udelay(5); - barrier(); - } - /* - * irda transceiver - wait a bit more to avoid - * cutoff, hardware dependent - */ - udelay(sport->trcv_delay); - - /* - * half duplex - reactivate receive mode, - * flush receive pipe echo crap - */ - if (readl(sport->port.membase + USR2) & USR2_TXDC) { - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_TXMPTYEN | UCR1_TRDYEN); - writel(temp, sport->port.membase + UCR1); + /* + * 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) + return; - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_TCEN); - writel(temp, sport->port.membase + UCR4); - - while (readl(sport->port.membase + URXD0) & - URXD_CHARRDY) - barrier(); + temp = readl(port->membase + UCR1); + writel(temp & ~UCR1_TXMPTYEN, port->membase + UCR1); - temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN; - writel(temp, sport->port.membase + 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); + if (port->rs485.flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_DREN; - writel(temp, sport->port.membase + UCR4); - } - return; + temp = readl(port->membase + UCR4); + temp &= ~UCR4_TCEN; + writel(temp, port->membase + UCR4); } - - temp = readl(sport->port.membase + UCR1); - writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1); } /* @@ -396,8 +395,21 @@ struct imx_port *sport = (struct imx_port *)port; unsigned long temp; + if (sport->dma_is_enabled && sport->dma_is_rxing) { + if (sport->port.suspended) { + dmaengine_terminate_all(sport->dma_chan_rx); + sport->dma_is_rxing = 0; + } else { + return; + } + } + temp = readl(sport->port.membase + UCR2); writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2); + + /* disable the `Receiver Ready Interrrupt` */ + temp = readl(sport->port.membase + UCR1); + writel(temp & ~UCR1_RRDYEN, sport->port.membase + UCR1); } /* @@ -410,13 +422,43 @@ mod_timer(&sport->timer, jiffies); } +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 */ + writel(sport->port.x_char, sport->port.membase + URTX0); + sport->port.icount.tx++; + sport->port.x_char = 0; + return; + } + + if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { + imx_stop_tx(&sport->port); + return; + } + + if (sport->dma_is_enabled) { + /* + * 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 &= ~UCR1_TXMPTYEN; + if (sport->dma_is_txing) { + temp |= UCR1_TDMAEN; + writel(temp, sport->port.membase + UCR1); + } else { + writel(temp, sport->port.membase + UCR1); + imx_dma_tx(sport); + } + } while (!uart_circ_empty(xmit) && - !(readl(sport->port.membase + uts_reg(sport)) - & UTS_TXFULL)) { + !(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) { /* send xmit->buf[xmit->tail] * out the port here */ writel(xmit->buf[xmit->tail], sport->port.membase + URTX0); @@ -431,6 +473,103 @@ imx_stop_tx(&sport->port); } +static void dma_tx_callback(void *data) +{ + struct imx_port *sport = data; + struct scatterlist *sgl = &sport->tx_sgl[0]; + struct circ_buf *xmit = &sport->port.state->xmit; + unsigned long flags; + unsigned long temp; + + spin_lock_irqsave(&sport->port.lock, flags); + + dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + + temp = readl(sport->port.membase + UCR1); + temp &= ~UCR1_TDMAEN; + writel(temp, sport->port.membase + UCR1); + + /* update the stat */ + xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1); + sport->port.icount.tx += sport->tx_bytes; + + dev_dbg(sport->port.dev, "we finish the TX DMA.\n"); + + sport->dma_is_txing = 0; + + spin_unlock_irqrestore(&sport->port.lock, flags); + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(&sport->port); + + if (waitqueue_active(&sport->dma_wait)) { + wake_up(&sport->dma_wait); + dev_dbg(sport->port.dev, "exit in %s.\n", __func__); + return; + } + + spin_lock_irqsave(&sport->port.lock, flags); + if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port)) + imx_dma_tx(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +static void imx_dma_tx(struct imx_port *sport) +{ + struct circ_buf *xmit = &sport->port.state->xmit; + struct scatterlist *sgl = sport->tx_sgl; + struct dma_async_tx_descriptor *desc; + struct dma_chan *chan = sport->dma_chan_tx; + struct device *dev = sport->port.dev; + unsigned long temp; + int ret; + + if (sport->dma_is_txing) + return; + + sport->tx_bytes = uart_circ_chars_pending(xmit); + + if (xmit->tail < xmit->head) { + 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); + } + + ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE); + if (ret == 0) { + dev_err(dev, "DMA mapping error for TX.\n"); + return; + } + desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents, + DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT); + if (!desc) { + dma_unmap_sg(dev, sgl, sport->dma_tx_nents, + DMA_TO_DEVICE); + dev_err(dev, "We cannot prepare for the TX slave dma!\n"); + return; + } + desc->callback = dma_tx_callback; + desc->callback_param = 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 |= UCR1_TDMAEN; + writel(temp, sport->port.membase + UCR1); + + /* fire it */ + sport->dma_is_txing = 1; + dmaengine_submit(desc); + dma_async_issue_pending(chan); + return; +} + /* * interrupts disabled on entry */ @@ -439,32 +578,41 @@ struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - if (USE_IRDA(sport)) { - /* half duplex in IrDA mode; have to disable receive mode */ - temp = readl(sport->port.membase + UCR4); - temp &= ~(UCR4_DREN); - writel(temp, sport->port.membase + UCR4); + if (port->rs485.flags & SER_RS485_ENABLED) { + /* enable transmitter and shifter empty irq */ + temp = readl(port->membase + UCR2); + if (port->rs485.flags & SER_RS485_RTS_ON_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, port->membase + UCR2); - temp = readl(sport->port.membase + UCR1); - temp &= ~(UCR1_RRDYEN); - writel(temp, sport->port.membase + UCR1); + temp = readl(port->membase + UCR4); + temp |= UCR4_TCEN; + writel(temp, port->membase + UCR4); } - temp = readl(sport->port.membase + UCR1); - writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); - - if (USE_IRDA(sport)) { + if (!sport->dma_is_enabled) { temp = readl(sport->port.membase + UCR1); - temp |= UCR1_TRDYEN; - writel(temp, sport->port.membase + UCR1); - - temp = readl(sport->port.membase + UCR4); - temp |= UCR4_TCEN; - writel(temp, sport->port.membase + UCR4); + writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1); } - if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY) - imx_transmit_buffer(sport); + 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 &= ~UCR1_TDMAEN; + temp |= UCR1_TXMPTYEN; + writel(temp, sport->port.membase + UCR1); + return; + } + + if (!uart_circ_empty(&port->state->xmit) && + !uart_tx_stopped(port)) + imx_dma_tx(sport); + return; + } } static irqreturn_t imx_rtsint(int irq, void *dev_id) @@ -487,27 +635,10 @@ static irqreturn_t imx_txint(int irq, void *dev_id) { struct imx_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) { - /* Send next char */ - writel(sport->port.x_char, sport->port.membase + URTX0); - goto out; - } - - if (uart_circ_empty(xmit) || uart_tx_stopped(&sport->port)) { - imx_stop_tx(&sport->port); - goto out; - } - imx_transmit_buffer(sport); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(&sport->port); - -out: spin_unlock_irqrestore(&sport->port.lock, flags); return IRQ_HANDLED; } @@ -553,7 +684,7 @@ continue; } - rx &= sport->port.read_status_mask; + rx &= (sport->port.read_status_mask | 0xFF); if (rx & URXD_BRK) flg = TTY_BREAK; @@ -569,7 +700,11 @@ #endif } - tty_insert_flip_char(port, rx, flg); + if (sport->port.ignore_status_mask & URXD_DUMMY_READ) + goto out; + + if (tty_insert_flip_char(port, rx, flg) == 0) + sport->port.icount.buf_overrun++; } out: @@ -578,18 +713,58 @@ return IRQ_HANDLED; } +static int start_rx_dma(struct imx_port *sport); +/* + * If the RXFIFO is filled with some data, and then we + * arise a DMA operation to receive them. + */ +static void imx_dma_rxint(struct imx_port *sport) +{ + unsigned long temp; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + + temp = readl(sport->port.membase + USR2); + if ((temp & USR2_RDR) && !sport->dma_is_rxing) { + sport->dma_is_rxing = 1; + + /* disable the receiver ready and aging timer interrupts */ + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RRDYEN); + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_ATEN); + writel(temp, sport->port.membase + UCR2); + + /* tell the DMA to receive the data. */ + start_rx_dma(sport); + } + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + static irqreturn_t imx_int(int irq, void *dev_id) { struct imx_port *sport = dev_id; unsigned int sts; + unsigned int sts2; sts = readl(sport->port.membase + USR1); + sts2 = readl(sport->port.membase + USR2); - if (sts & USR1_RRDY) - imx_rxint(irq, dev_id); + if (sts & (USR1_RRDY | USR1_AGTIM)) { + if (sport->dma_is_enabled) + imx_dma_rxint(sport); + else + imx_rxint(irq, dev_id); + } - if (sts & USR1_TRDY && - readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) + if ((sts & USR1_TRDY && + readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN) || + (sts2 & USR2_TXDC && + readl(sport->port.membase + UCR4) & UCR4_TCEN)) imx_txint(irq, dev_id); if (sts & USR1_RTSD) @@ -598,6 +773,11 @@ if (sts & USR1_AWAKE) writel(USR1_AWAKE, sport->port.membase + USR1); + if (sts2 & USR2_ORE) { + sport->port.icount.overrun++; + writel(USR2_ORE, sport->port.membase + USR2); + } + return IRQ_HANDLED; } @@ -607,8 +787,15 @@ 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; - return (readl(sport->port.membase + USR2) & USR2_TXDC) ? TIOCSER_TEMT : 0; + /* If the TX DMA is working, return 0. */ + if (sport->dma_is_enabled && sport->dma_is_txing) + ret = 0; + + return ret; } /* @@ -625,6 +812,9 @@ if (readl(sport->port.membase + UCR2) & UCR2_CTS) tmp |= TIOCM_RTS; + if (readl(sport->port.membase + uts_reg(sport)) & UTS_LOOP) + tmp |= TIOCM_LOOP; + return tmp; } @@ -633,12 +823,18 @@ struct imx_port *sport = (struct imx_port *)port; unsigned long temp; - temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS; - - if (mctrl & TIOCM_RTS) - temp |= UCR2_CTS; + if (!(port->rs485.flags & SER_RS485_ENABLED)) { + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_CTS | UCR2_CTSC); + if (mctrl & TIOCM_RTS) + temp |= UCR2_CTS | UCR2_CTSC; + writel(temp, sport->port.membase + UCR2); + } - writel(temp, sport->port.membase + UCR2); + temp = readl(sport->port.membase + uts_reg(sport)) & ~UTS_LOOP; + if (mctrl & TIOCM_LOOP) + temp |= UTS_LOOP; + writel(temp, sport->port.membase + uts_reg(sport)); } /* @@ -661,18 +857,242 @@ spin_unlock_irqrestore(&sport->port.lock, flags); } -#define TXTL 2 /* reset default */ -#define RXTL 1 /* reset default */ +#define RX_BUF_SIZE (PAGE_SIZE) +static void imx_rx_dma_done(struct imx_port *sport) +{ + unsigned long temp; + unsigned long flags; + + spin_lock_irqsave(&sport->port.lock, flags); + + /* re-enable interrupts to get notified when new symbols are incoming */ + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RRDYEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_ATEN; + writel(temp, sport->port.membase + UCR2); + + sport->dma_is_rxing = 0; + + /* Is the shutdown waiting for us? */ + if (waitqueue_active(&sport->dma_wait)) + wake_up(&sport->dma_wait); + + spin_unlock_irqrestore(&sport->port.lock, flags); +} + +/* + * There are two kinds of RX DMA interrupts(such as in the MX6Q): + * [1] the RX DMA buffer is full. + * [2] the aging timer expires + * + * 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) +{ + struct imx_port *sport = data; + struct dma_chan *chan = sport->dma_chan_rx; + struct scatterlist *sgl = &sport->rx_sgl; + struct tty_port *port = &sport->port.state->port; + struct dma_tx_state state; + enum dma_status status; + unsigned int count; + + /* unmap it first */ + dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE); + + status = dmaengine_tx_status(chan, (dma_cookie_t)0, &state); + count = RX_BUF_SIZE - state.residue; + + dev_dbg(sport->port.dev, "We get %d bytes.\n", count); + + if (count) { + if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) { + int bytes = tty_insert_flip_string(port, sport->rx_buf, + count); + + if (bytes != count) + sport->port.icount.buf_overrun++; + } + tty_flip_buffer_push(port); + sport->port.icount.rx += count; + } + + /* + * Restart RX DMA directly if more data is available in order to skip + * the roundtrip through the IRQ handler. If there is some data already + * in the FIFO, DMA needs to be restarted soon anyways. + * + * Otherwise stop the DMA and reactivate FIFO IRQs to restart DMA once + * data starts to arrive again. + */ + if (readl(sport->port.membase + USR2) & USR2_RDR) + start_rx_dma(sport); + else + imx_rx_dma_done(sport); +} + +static int start_rx_dma(struct imx_port *sport) +{ + struct scatterlist *sgl = &sport->rx_sgl; + struct dma_chan *chan = sport->dma_chan_rx; + struct device *dev = sport->port.dev; + struct dma_async_tx_descriptor *desc; + int ret; + + sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); + ret = dma_map_sg(dev, sgl, 1, DMA_FROM_DEVICE); + if (ret == 0) { + dev_err(dev, "DMA mapping error for RX.\n"); + return -EINVAL; + } + desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { + dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE); + dev_err(dev, "We cannot prepare for the RX slave dma!\n"); + return -EINVAL; + } + desc->callback = dma_rx_callback; + desc->callback_param = sport; + + dev_dbg(dev, "RX: prepare for the DMA.\n"); + dmaengine_submit(desc); + dma_async_issue_pending(chan); + return 0; +} + +#define TXTL_DEFAULT 2 /* reset default */ +#define RXTL_DEFAULT 1 /* reset default */ +#define TXTL_DMA 8 /* DMA burst setting */ +#define RXTL_DMA 9 /* DMA burst setting */ -static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode) +static void imx_setup_ufcr(struct imx_port *sport, + unsigned char txwl, unsigned char rxwl) { unsigned int val; /* set receiver / transmitter trigger level */ val = readl(sport->port.membase + UFCR) & (UFCR_RFDIV | UFCR_DCEDTE); - val |= TXTL << UFCR_TXTL_SHF | RXTL; + val |= txwl << UFCR_TXTL_SHF | rxwl; writel(val, sport->port.membase + UFCR); +} + +static void imx_uart_dma_exit(struct imx_port *sport) +{ + if (sport->dma_chan_rx) { + dma_release_channel(sport->dma_chan_rx); + sport->dma_chan_rx = NULL; + + kfree(sport->rx_buf); + sport->rx_buf = NULL; + } + + if (sport->dma_chan_tx) { + 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) +{ + struct dma_slave_config slave_config = {}; + struct device *dev = sport->port.dev; + int ret; + + /* Prepare for RX : */ + sport->dma_chan_rx = dma_request_slave_channel(dev, "rx"); + if (!sport->dma_chan_rx) { + dev_dbg(dev, "cannot get the DMA channel.\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_addr = sport->port.mapbase + URXD0; + slave_config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + /* one byte less than the watermark level to enable the aging timer */ + slave_config.src_maxburst = RXTL_DMA - 1; + ret = dmaengine_slave_config(sport->dma_chan_rx, &slave_config); + if (ret) { + dev_err(dev, "error in RX dma configuration.\n"); + goto err; + } + + sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!sport->rx_buf) { + ret = -ENOMEM; + goto err; + } + + /* Prepare for TX : */ + sport->dma_chan_tx = dma_request_slave_channel(dev, "tx"); + if (!sport->dma_chan_tx) { + dev_err(dev, "cannot get the TX DMA channel!\n"); + ret = -EINVAL; + goto err; + } + + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_addr = sport->port.mapbase + URTX0; + slave_config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE; + slave_config.dst_maxburst = TXTL_DMA; + ret = dmaengine_slave_config(sport->dma_chan_tx, &slave_config); + if (ret) { + dev_err(dev, "error in TX dma configuration."); + goto err; + } + + sport->dma_is_inited = 1; + return 0; +err: + imx_uart_dma_exit(sport); + return ret; +} + +static void imx_enable_dma(struct imx_port *sport) +{ + unsigned long temp; + + init_waitqueue_head(&sport->dma_wait); + + /* set UCR1 */ + temp = readl(sport->port.membase + UCR1); + temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN; + writel(temp, sport->port.membase + UCR1); + + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_ATEN; + writel(temp, sport->port.membase + UCR2); + + imx_setup_ufcr(sport, TXTL_DMA, RXTL_DMA); + + sport->dma_is_enabled = 1; +} + +static void imx_disable_dma(struct imx_port *sport) +{ + unsigned long temp; + + /* clear UCR1 */ + temp = readl(sport->port.membase + UCR1); + temp &= ~(UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN); + writel(temp, sport->port.membase + UCR1); + + /* clear UCR2 */ + temp = readl(sport->port.membase + UCR2); + temp &= ~(UCR2_CTSC | UCR2_CTS | UCR2_ATEN); + writel(temp, sport->port.membase + UCR2); + + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + + sport->dma_is_enabled = 0; } /* half the RX buffer size */ @@ -681,118 +1101,74 @@ static int imx_startup(struct uart_port *port) { struct imx_port *sport = (struct imx_port *)port; - int retval; + int retval, i; unsigned long flags, temp; - imx_setup_ufcr(sport, 0); + retval = clk_prepare_enable(sport->clk_per); + if (retval) + return retval; + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) { + clk_disable_unprepare(sport->clk_per); + return retval; + } + + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); /* disable the DREN bit (Data Ready interrupt enable) before * requesting IRQs */ temp = readl(sport->port.membase + UCR4); - if (USE_IRDA(sport)) - temp |= UCR4_IRSC; - /* 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); - if (USE_IRDA(sport)) { - /* reset fifo's and state machines */ - int i = 100; - temp = readl(sport->port.membase + UCR2); - temp &= ~UCR2_SRST; - writel(temp, sport->port.membase + UCR2); - while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && - (--i > 0)) { - udelay(1); - } - } - - /* - * Allocate the IRQ(s) i.MX1 has three interrupts whereas later - * chips only have one interrupt. - */ - if (sport->txirq > 0) { - retval = request_irq(sport->rxirq, imx_rxint, 0, - DRIVER_NAME, sport); - if (retval) - goto error_out1; - - retval = request_irq(sport->txirq, imx_txint, 0, - DRIVER_NAME, sport); - if (retval) - goto error_out2; - - /* do not use RTS IRQ on IrDA */ - if (!USE_IRDA(sport)) { - retval = request_irq(sport->rtsirq, imx_rtsint, 0, - DRIVER_NAME, sport); - if (retval) - goto error_out3; - } - } else { - retval = request_irq(sport->port.irq, imx_int, 0, - DRIVER_NAME, sport); - if (retval) { - free_irq(sport->port.irq, sport); - goto error_out1; - } - } + /* Can we enable the DMA support? */ + if (is_imx6q_uart(sport) && !uart_console(port) && + !sport->dma_is_inited) + imx_uart_dma_init(sport); spin_lock_irqsave(&sport->port.lock, flags); + /* Reset fifo's and state machines */ + i = 100; + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0)) + udelay(1); + /* * Finally, clear and enable interrupts */ writel(USR1_RTSD, sport->port.membase + USR1); + writel(USR2_ORE, sport->port.membase + USR2); + + if (sport->dma_is_inited && !sport->dma_is_enabled) + imx_enable_dma(sport); temp = readl(sport->port.membase + UCR1); temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; - if (USE_IRDA(sport)) { - temp |= UCR1_IREN; - temp &= ~(UCR1_RTSDEN); - } - writel(temp, sport->port.membase + UCR1); + temp = readl(sport->port.membase + UCR4); + temp |= UCR4_OREN; + writel(temp, sport->port.membase + UCR4); + temp = readl(sport->port.membase + UCR2); temp |= (UCR2_RXEN | UCR2_TXEN); if (!sport->have_rtscts) temp |= UCR2_IRTS; writel(temp, sport->port.membase + UCR2); - if (USE_IRDA(sport)) { - /* clear RX-FIFO */ - int i = 64; - while ((--i > 0) && - (readl(sport->port.membase + URXD0) & URXD_CHARRDY)) { - barrier(); - } - } - - if (is_imx21_uart(sport)) { + if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - temp |= IMX21_UCR3_RXDMUXSEL; - writel(temp, sport->port.membase + UCR3); - } - - if (USE_IRDA(sport)) { - temp = readl(sport->port.membase + UCR4); - if (sport->irda_inv_rx) - temp |= UCR4_INVR; - else - temp &= ~(UCR4_INVR); - writel(temp | UCR4_DREN, sport->port.membase + UCR4); - - temp = readl(sport->port.membase + UCR3); - if (sport->irda_inv_tx) - temp |= UCR3_INVT; - else - temp &= ~(UCR3_INVT); + temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; writel(temp, sport->port.membase + UCR3); } @@ -802,26 +1178,7 @@ imx_enable_ms(&sport->port); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; - sport->irda_inv_rx = pdata->irda_inv_rx; - sport->irda_inv_tx = pdata->irda_inv_tx; - sport->trcv_delay = pdata->transceiver_delay; - if (pdata->irda_enable) - pdata->irda_enable(1); - } - return 0; - -error_out3: - if (sport->txirq) - free_irq(sport->txirq, sport); -error_out2: - if (sport->rxirq) - free_irq(sport->rxirq, sport); -error_out1: - return retval; } static void imx_shutdown(struct uart_port *port) @@ -830,47 +1187,95 @@ unsigned long temp; unsigned long flags; + if (sport->dma_is_enabled) { + int ret; + + /* We have to wait for the DMA to finish. */ + ret = wait_event_interruptible(sport->dma_wait, + !sport->dma_is_rxing && !sport->dma_is_txing); + if (ret != 0) { + sport->dma_is_rxing = 0; + sport->dma_is_txing = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + dmaengine_terminate_all(sport->dma_chan_rx); + } + spin_lock_irqsave(&sport->port.lock, flags); + imx_stop_tx(port); + imx_stop_rx(port); + imx_disable_dma(sport); + spin_unlock_irqrestore(&sport->port.lock, flags); + imx_uart_dma_exit(sport); + } + spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR2); temp &= ~(UCR2_TXEN); writel(temp, sport->port.membase + UCR2); spin_unlock_irqrestore(&sport->port.lock, flags); - if (USE_IRDA(sport)) { - struct imxuart_platform_data *pdata; - pdata = sport->port.dev->platform_data; - if (pdata->irda_enable) - pdata->irda_enable(0); - } - /* * Stop our timer. */ del_timer_sync(&sport->timer); /* - * Free the interrupts - */ - if (sport->txirq > 0) { - if (!USE_IRDA(sport)) - free_irq(sport->rtsirq, sport); - free_irq(sport->txirq, sport); - free_irq(sport->rxirq, sport); - } else - free_irq(sport->port.irq, sport); - - /* * Disable all interrupts, port and break condition. */ spin_lock_irqsave(&sport->port.lock, flags); temp = readl(sport->port.membase + UCR1); temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN); - if (USE_IRDA(sport)) - temp &= ~(UCR1_IREN); writel(temp, sport->port.membase + UCR1); spin_unlock_irqrestore(&sport->port.lock, flags); + + clk_disable_unprepare(sport->clk_per); + clk_disable_unprepare(sport->clk_ipg); +} + +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; + int i = 100, ubir, ubmr, uts; + + if (!sport->dma_chan_tx) + return; + + sport->tx_bytes = 0; + dmaengine_terminate_all(sport->dma_chan_tx); + 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 &= ~UCR1_TDMAEN; + writel(temp, sport->port.membase + UCR1); + sport->dma_is_txing = false; + } + + /* + * According to the Reference Manual description of the UART SRST bit: + * "Reset the transmit and receive state machines, + * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD + * and UTS[6-3]". As we don't need to restore the old values from + * USR1, USR2, URXD, UTXD, only save/restore the other four registers + */ + ubir = readl(sport->port.membase + UBIR); + ubmr = readl(sport->port.membase + UBMR); + uts = readl(sport->port.membase + IMX21_UTS); + + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_SRST; + writel(temp, sport->port.membase + UCR2); + + while (!(readl(sport->port.membase + 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); } static void @@ -879,22 +1284,13 @@ { struct imx_port *sport = (struct imx_port *)port; unsigned long flags; - unsigned int ucr2, old_ucr1, old_txrxen, baud, quot; + unsigned int ucr2, old_ucr1, old_ucr2, baud, quot; unsigned int old_csize = old ? old->c_cflag & CSIZE : CS8; unsigned int div, ufcr; unsigned long num, denom; uint64_t tdiv64; /* - * If we don't support modem control lines, don't allow - * these to be set. - */ - if (0) { - termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); - termios->c_cflag |= CLOCAL; - } - - /* * We only support CS7 and CS8. */ while ((termios->c_cflag & CSIZE) != CS7 && @@ -912,11 +1308,26 @@ if (termios->c_cflag & CRTSCTS) { if (sport->have_rtscts) { ucr2 &= ~UCR2_IRTS; - ucr2 |= UCR2_CTSC; + + if (port->rs485.flags & SER_RS485_ENABLED) { + /* + * RTS is mandatory for rs485 operation, so keep + * it under manual control and keep transmitter + * disabled. + */ + if (!(port->rs485.flags & + SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; + } else { + ucr2 |= UCR2_CTSC; + } } else { termios->c_cflag &= ~CRTSCTS; } - } + } else if (port->rs485.flags & SER_RS485_ENABLED) + /* disable transmitter */ + if (!(port->rs485.flags & SER_RS485_RTS_AFTER_SEND)) + ucr2 |= UCR2_CTS; if (termios->c_cflag & CSTOPB) ucr2 |= UCR2_STPB; @@ -947,7 +1358,7 @@ */ sport->port.ignore_status_mask = 0; if (termios->c_iflag & IGNPAR) - sport->port.ignore_status_mask |= URXD_PRERR; + sport->port.ignore_status_mask |= URXD_PRERR | URXD_FRMERR; if (termios->c_iflag & IGNBRK) { sport->port.ignore_status_mask |= URXD_BRK; /* @@ -958,6 +1369,9 @@ sport->port.ignore_status_mask |= URXD_OVRRUN; } + if ((termios->c_cflag & CREAD) == 0) + sport->port.ignore_status_mask |= URXD_DUMMY_READ; + /* * Update the per-port timeout. */ @@ -974,24 +1388,21 @@ barrier(); /* then, disable everything */ - old_txrxen = readl(sport->port.membase + UCR2); - writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN), + old_ucr2 = readl(sport->port.membase + UCR2); + writel(old_ucr2 & ~(UCR2_TXEN | UCR2_RXEN), sport->port.membase + UCR2); - old_txrxen &= (UCR2_TXEN | UCR2_RXEN); + old_ucr2 &= (UCR2_TXEN | UCR2_RXEN | UCR2_ATEN); - if (USE_IRDA(sport)) { - /* - * use maximum available submodule frequency to - * avoid missing short pulses due to low sampling rate - */ + /* custom-baudrate handling */ + div = sport->port.uartclk / (baud * 16); + if (baud == 38400 && quot != div) + baud = sport->port.uartclk / (quot * 16); + + div = sport->port.uartclk / (baud * 16); + if (div > 7) + div = 7; + if (!div) div = 1; - } else { - div = sport->port.uartclk / (baud * 16); - if (div > 7) - div = 7; - if (!div) - div = 1; - } rational_best_approximation(16 * div * baud, sport->port.uartclk, 1 << 16, 1 << 16, &num, &denom); @@ -1007,19 +1418,21 @@ ufcr = readl(sport->port.membase + UFCR); ufcr = (ufcr & (~UFCR_RFDIV)) | UFCR_RFDIV_REG(div); + if (sport->dte_mode) + ufcr |= UFCR_DCEDTE; writel(ufcr, sport->port.membase + UFCR); writel(num, sport->port.membase + UBIR); writel(denom, sport->port.membase + UBMR); - if (is_imx21_uart(sport)) + if (!is_imx1_uart(sport)) writel(sport->port.uartclk / div / 1000, sport->port.membase + IMX21_ONEMS); writel(old_ucr1, sport->port.membase + UCR1); /* set the parity, stop bits and data size */ - writel(ucr2 | old_txrxen, sport->port.membase + UCR2); + writel(ucr2 | old_ucr2, sport->port.membase + UCR2); if (UART_ENABLE_MS(&sport->port, termios->c_cflag)) imx_enable_ms(&sport->port); @@ -1035,44 +1448,13 @@ } /* - * Release the memory region(s) being used by 'port'. - */ -static void imx_release_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(mmres->start, resource_size(mmres)); -} - -/* - * Request the memory region(s) being used by 'port'. - */ -static int imx_request_port(struct uart_port *port) -{ - struct platform_device *pdev = to_platform_device(port->dev); - struct resource *mmres; - void *ret; - - mmres = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!mmres) - return -ENODEV; - - ret = request_mem_region(mmres->start, resource_size(mmres), "imx-uart"); - - return ret ? 0 : -EBUSY; -} - -/* * Configure/autoconfigure the port. */ static void imx_config_port(struct uart_port *port, int flags) { struct imx_port *sport = (struct imx_port *)port; - if (flags & UART_CONFIG_TYPE && - imx_request_port(&sport->port) == 0) + if (flags & UART_CONFIG_TYPE) sport->port.type = PORT_IMX; } @@ -1095,7 +1477,7 @@ ret = -EINVAL; if (sport->port.uartclk / 16 != ser->baud_base) ret = -EINVAL; - if ((void *)sport->port.mapbase != ser->iomem_base) + if (sport->port.mapbase != (unsigned long)ser->iomem_base) ret = -EINVAL; if (sport->port.iobase != ser->port) ret = -EINVAL; @@ -1105,69 +1487,100 @@ } #if defined(CONFIG_CONSOLE_POLL) -static int imx_poll_get_char(struct uart_port *port) + +static int imx_poll_init(struct uart_port *port) { - struct imx_port_ucrs old_ucr; - unsigned int status; - unsigned char c; + struct imx_port *sport = (struct imx_port *)port; + unsigned long flags; + unsigned long temp; + int retval; - /* save control registers */ - imx_port_ucrs_save(port, &old_ucr); + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) + return retval; + retval = clk_prepare_enable(sport->clk_per); + if (retval) + clk_disable_unprepare(sport->clk_ipg); - /* disable interrupts */ - writel(UCR1_UARTEN, port->membase + UCR1); - writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), - port->membase + UCR2); - writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), - port->membase + UCR3); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); - /* poll */ - do { - status = readl(port->membase + USR2); - } while (~status & USR2_RDR); + spin_lock_irqsave(&sport->port.lock, flags); - /* read */ - c = readl(port->membase + URXD0); + temp = readl(sport->port.membase + 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); - /* restore control registers */ - imx_port_ucrs_restore(port, &old_ucr); + temp = readl(sport->port.membase + UCR2); + temp |= UCR2_RXEN; + writel(temp, sport->port.membase + UCR2); + + spin_unlock_irqrestore(&sport->port.lock, flags); - return c; + return 0; } -static void imx_poll_put_char(struct uart_port *port, unsigned char c) +static int imx_poll_get_char(struct uart_port *port) { - struct imx_port_ucrs old_ucr; - unsigned int status; + if (!(readl_relaxed(port->membase + USR2) & USR2_RDR)) + return NO_POLL_CHAR; - /* save control registers */ - imx_port_ucrs_save(port, &old_ucr); + return readl_relaxed(port->membase + URXD0) & URXD_RX_DATA; +} - /* disable interrupts */ - writel(UCR1_UARTEN, port->membase + UCR1); - writel(old_ucr.ucr2 & ~(UCR2_ATEN | UCR2_RTSEN | UCR2_ESCI), - port->membase + UCR2); - writel(old_ucr.ucr3 & ~(UCR3_DCD | UCR3_RI | UCR3_DTREN), - port->membase + UCR3); +static void imx_poll_put_char(struct uart_port *port, unsigned char c) +{ + unsigned int status; /* drain */ do { - status = readl(port->membase + USR1); + status = readl_relaxed(port->membase + USR1); } while (~status & USR1_TRDY); /* write */ - writel(c, port->membase + URTX0); + writel_relaxed(c, port->membase + URTX0); /* flush */ do { - status = readl(port->membase + USR2); + status = readl_relaxed(port->membase + USR2); } while (~status & USR2_TXDC); - - /* restore control registers */ - imx_port_ucrs_restore(port, &old_ucr); } #endif +static int imx_rs485_config(struct uart_port *port, + struct serial_rs485 *rs485conf) +{ + struct imx_port *sport = (struct imx_port *)port; + + /* unimplemented */ + rs485conf->delay_rts_before_send = 0; + rs485conf->delay_rts_after_send = 0; + rs485conf->flags |= SER_RS485_RX_DURING_TX; + + /* RTS is required to control the transmitter */ + if (!sport->have_rtscts) + rs485conf->flags &= ~SER_RS485_ENABLED; + + if (rs485conf->flags & SER_RS485_ENABLED) { + unsigned long temp; + + /* disable transmitter */ + temp = readl(sport->port.membase + UCR2); + temp &= ~UCR2_CTSC; + if (rs485conf->flags & SER_RS485_RTS_AFTER_SEND) + temp &= ~UCR2_CTS; + else + temp |= UCR2_CTS; + writel(temp, sport->port.membase + UCR2); + } + + port->rs485 = *rs485conf; + + return 0; +} + static struct uart_ops imx_pops = { .tx_empty = imx_tx_empty, .set_mctrl = imx_set_mctrl, @@ -1179,13 +1592,13 @@ .break_ctl = imx_break_ctl, .startup = imx_startup, .shutdown = imx_shutdown, + .flush_buffer = imx_flush_buffer, .set_termios = imx_set_termios, .type = imx_type, - .release_port = imx_release_port, - .request_port = imx_request_port, .config_port = imx_config_port, .verify_port = imx_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, #endif @@ -1215,6 +1628,16 @@ unsigned int ucr1; unsigned long flags = 0; int locked = 1; + int retval; + + retval = clk_enable(sport->clk_per); + if (retval) + return; + retval = clk_enable(sport->clk_ipg); + if (retval) { + clk_disable(sport->clk_per); + return; + } if (sport->port.sysrq) locked = 0; @@ -1250,6 +1673,9 @@ if (locked) spin_unlock_irqrestore(&sport->port.lock, flags); + + clk_disable(sport->clk_ipg); + clk_disable(sport->clk_per); } /* @@ -1323,6 +1749,7 @@ int bits = 8; int parity = 'n'; int flow = 'n'; + int retval; /* * Check whether an invalid uart number has been specified, and @@ -1335,14 +1762,32 @@ if (sport == NULL) return -ENODEV; + /* For setting the registers, we only need to enable the ipg clock. */ + retval = clk_prepare_enable(sport->clk_ipg); + if (retval) + goto error_console; + if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); else imx_console_get_options(sport, &baud, &parity, &bits); - imx_setup_ufcr(sport, 0); + imx_setup_ufcr(sport, TXTL_DEFAULT, RXTL_DEFAULT); + + retval = uart_set_options(&sport->port, co, baud, parity, bits, flow); + + clk_disable(sport->clk_ipg); + if (retval) { + clk_unprepare(sport->clk_ipg); + goto error_console; + } + + retval = clk_prepare(sport->clk_per); + if (retval) + clk_disable_unprepare(sport->clk_ipg); - return uart_set_options(&sport->port, co, baud, parity, bits, flow); +error_console: + return retval; } static struct uart_driver imx_reg; @@ -1357,6 +1802,38 @@ }; #define IMX_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) + cpu_relax(); + + writel_relaxed(ch, port->membase + URTX0); +} + +static void imx_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); +} + +static int __init +imx_console_early_setup(struct earlycon_device *dev, const char *opt) +{ + if (!dev->port.membase) + return -ENODEV; + + dev->con->write = imx_console_early_write; + + return 0; +} +OF_EARLYCON_DECLARE(ec_imx6q, "fsl,imx6q-uart", imx_console_early_setup); +OF_EARLYCON_DECLARE(ec_imx21, "fsl,imx21-uart", imx_console_early_setup); +#endif + #else #define IMX_CONSOLE NULL #endif @@ -1371,36 +1848,6 @@ .cons = IMX_CONSOLE, }; -static int serial_imx_suspend(struct platform_device *dev, pm_message_t state) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* enable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val |= UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_suspend_port(&imx_reg, &sport->port); - - return 0; -} - -static int serial_imx_resume(struct platform_device *dev) -{ - struct imx_port *sport = platform_get_drvdata(dev); - unsigned int val; - - /* disable wakeup from i.MX UART */ - val = readl(sport->port.membase + UCR3); - val &= ~UCR3_AWAKEN; - writel(val, sport->port.membase + UCR3); - - uart_resume_port(&imx_reg, &sport->port); - - return 0; -} - #ifdef CONFIG_OF /* * This function returns 1 iff pdev isn't a device instatiated by dt, 0 iff it @@ -1428,8 +1875,8 @@ if (of_get_property(np, "fsl,uart-has-rtscts", NULL)) sport->have_rtscts = 1; - if (of_get_property(np, "fsl,irda-mode", NULL)) - sport->use_irda = 1; + if (of_get_property(np, "fsl,dte-mode", NULL)) + sport->dte_mode = 1; sport->devdata = of_id->data; @@ -1446,7 +1893,7 @@ static void serial_imx_probe_pdata(struct imx_port *sport, struct platform_device *pdev) { - struct imxuart_platform_data *pdata = pdev->dev.platform_data; + struct imxuart_platform_data *pdata = dev_get_platdata(&pdev->dev); sport->port.line = pdev->id; sport->devdata = (struct imx_uart_data *) pdev->id_entry->driver_data; @@ -1456,19 +1903,15 @@ if (pdata->flags & IMXUART_HAVE_RTSCTS) sport->have_rtscts = 1; - - if (pdata->flags & IMXUART_IRDA) - sport->use_irda = 1; } static int serial_imx_probe(struct platform_device *pdev) { struct imx_port *sport; - struct imxuart_platform_data *pdata; void __iomem *base; - int ret = 0; + int ret = 0, reg; struct resource *res; - struct pinctrl *pinctrl; + int txirq, rxirq, rtsirq; sport = devm_kzalloc(&pdev->dev, sizeof(*sport), GFP_KERNEL); if (!sport) @@ -1481,36 +1924,30 @@ return ret; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) - return -ENODEV; - - base = devm_ioremap(&pdev->dev, res->start, PAGE_SIZE); - if (!base) - return -ENOMEM; + base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(base)) + return PTR_ERR(base); + + rxirq = platform_get_irq(pdev, 0); + txirq = platform_get_irq(pdev, 1); + rtsirq = platform_get_irq(pdev, 2); sport->port.dev = &pdev->dev; sport->port.mapbase = res->start; sport->port.membase = base; sport->port.type = PORT_IMX, sport->port.iotype = UPIO_MEM; - sport->port.irq = platform_get_irq(pdev, 0); - sport->rxirq = platform_get_irq(pdev, 0); - sport->txirq = platform_get_irq(pdev, 1); - sport->rtsirq = platform_get_irq(pdev, 2); + sport->port.irq = rxirq; sport->port.fifosize = 32; sport->port.ops = &imx_pops; + sport->port.rs485_config = imx_rs485_config; + sport->port.rs485.flags = + SER_RS485_RTS_ON_SEND | SER_RS485_RX_DURING_TX; sport->port.flags = UPF_BOOT_AUTOCONF; init_timer(&sport->timer); sport->timer.function = imx_timeout; sport->timer.data = (unsigned long)sport; - pinctrl = devm_pinctrl_get_select_default(&pdev->dev); - if (IS_ERR(pinctrl)) { - ret = PTR_ERR(pinctrl); - dev_err(&pdev->dev, "failed to get default pinctrl: %d\n", ret); - return ret; - } - sport->clk_ipg = devm_clk_get(&pdev->dev, "ipg"); if (IS_ERR(sport->clk_ipg)) { ret = PTR_ERR(sport->clk_ipg); @@ -1525,76 +1962,192 @@ return ret; } - clk_prepare_enable(sport->clk_per); - clk_prepare_enable(sport->clk_ipg); - sport->port.uartclk = clk_get_rate(sport->clk_per); - imx_ports[sport->port.line] = sport; + /* For register access, we only need to enable the ipg clock. */ + ret = clk_prepare_enable(sport->clk_ipg); + if (ret) + return ret; + + /* Disable interrupts before requesting them */ + reg = readl_relaxed(sport->port.membase + UCR1); + reg &= ~(UCR1_ADEN | UCR1_TRDYEN | UCR1_IDEN | UCR1_RRDYEN | + UCR1_TXMPTYEN | UCR1_RTSDEN); + writel_relaxed(reg, sport->port.membase + UCR1); + + clk_disable_unprepare(sport->clk_ipg); + + /* + * Allocate the IRQ(s) i.MX1 has three interrupts whereas later + * chips only have one interrupt. + */ + if (txirq > 0) { + ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; - pdata = pdev->dev.platform_data; - if (pdata && pdata->init) { - ret = pdata->init(pdev); + ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0, + dev_name(&pdev->dev), sport); + if (ret) + return ret; + } else { + ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0, + dev_name(&pdev->dev), sport); if (ret) - goto clkput; + return ret; } - ret = uart_add_one_port(&imx_reg, &sport->port); - if (ret) - goto deinit; + imx_ports[sport->port.line] = sport; + platform_set_drvdata(pdev, sport); - return 0; -deinit: - if (pdata && pdata->exit) - pdata->exit(pdev); -clkput: - clk_disable_unprepare(sport->clk_per); - clk_disable_unprepare(sport->clk_ipg); - return ret; + return uart_add_one_port(&imx_reg, &sport->port); } static int serial_imx_remove(struct platform_device *pdev) { - struct imxuart_platform_data *pdata; struct imx_port *sport = platform_get_drvdata(pdev); - pdata = pdev->dev.platform_data; + return uart_remove_one_port(&imx_reg, &sport->port); +} - platform_set_drvdata(pdev, NULL); +static void serial_imx_restore_context(struct imx_port *sport) +{ + if (!sport->context_saved) + return; - uart_remove_one_port(&imx_reg, &sport->port); + 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); + 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->context_saved = true; +} - clk_disable_unprepare(sport->clk_per); - clk_disable_unprepare(sport->clk_ipg); +static void serial_imx_enable_wakeup(struct imx_port *sport, bool on) +{ + unsigned int val; - if (pdata && pdata->exit) - pdata->exit(pdev); + val = readl(sport->port.membase + UCR3); + if (on) + val |= UCR3_AWAKEN; + else + val &= ~UCR3_AWAKEN; + writel(val, sport->port.membase + UCR3); + + val = readl(sport->port.membase + UCR1); + if (on) + val |= UCR1_RTSDEN; + else + val &= ~UCR1_RTSDEN; + writel(val, sport->port.membase + UCR1); +} + +static int imx_serial_port_suspend_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + serial_imx_save_context(sport); + + clk_disable(sport->clk_ipg); return 0; } +static int imx_serial_port_resume_noirq(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + int ret; + + ret = clk_enable(sport->clk_ipg); + if (ret) + return ret; + + serial_imx_restore_context(sport); + + clk_disable(sport->clk_ipg); + + return 0; +} + +static int imx_serial_port_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct imx_port *sport = platform_get_drvdata(pdev); + + /* enable wakeup from i.MX UART */ + serial_imx_enable_wakeup(sport, true); + + uart_suspend_port(&imx_reg, &sport->port); + + return 0; +} + +static int imx_serial_port_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); + + uart_resume_port(&imx_reg, &sport->port); + + 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, + .suspend = imx_serial_port_suspend, + .resume = imx_serial_port_resume, +}; + static struct platform_driver serial_imx_driver = { .probe = serial_imx_probe, .remove = serial_imx_remove, - .suspend = serial_imx_suspend, - .resume = serial_imx_resume, .id_table = imx_uart_devtype, .driver = { .name = "imx-uart", - .owner = THIS_MODULE, .of_match_table = imx_uart_dt_ids, + .pm = &imx_serial_port_pm_ops, }, }; static int __init imx_serial_init(void) { - int ret; - - pr_info("Serial: IMX driver\n"); + int ret = uart_register_driver(&imx_reg); - ret = uart_register_driver(&imx_reg); if (ret) return ret;