diff options
Diffstat (limited to 'drivers/tty/serial/imx.c')
| -rw-r--r-- | drivers/tty/serial/imx.c | 125 |
1 files changed, 86 insertions, 39 deletions
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c index e3e152cbc75e..9e3162bf3bd1 100644 --- a/drivers/tty/serial/imx.c +++ b/drivers/tty/serial/imx.c @@ -186,6 +186,11 @@ #define UART_NR 8 +/* RX DMA buffer periods */ +#define RX_DMA_PERIODS 4 +#define RX_BUF_SIZE (PAGE_SIZE) + + /* i.MX21 type uart runs on all i.mx except i.MX1 and i.MX6q */ enum imx_uart_type { IMX1_UART, @@ -207,9 +212,6 @@ struct imx_port { unsigned int have_rtscts:1; unsigned int have_rtsgpio: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; @@ -224,6 +226,7 @@ struct imx_port { struct dma_chan *dma_chan_rx, *dma_chan_tx; struct scatterlist rx_sgl, tx_sgl[2]; void *rx_buf; + unsigned int rx_buf_size; struct circ_buf rx_ring; unsigned int rx_periods; dma_cookie_t rx_cookie; @@ -719,6 +722,27 @@ out: return IRQ_HANDLED; } +static void imx_disable_rx_int(struct imx_port *sport) +{ + unsigned long temp; + + 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); + + /* disable the rx errors interrupts */ + temp = readl(sport->port.membase + UCR4); + temp &= ~UCR4_OREN; + writel(temp, sport->port.membase + UCR4); +} + static void clear_rx_errors(struct imx_port *sport); static int start_rx_dma(struct imx_port *sport); /* @@ -734,21 +758,8 @@ static void imx_dma_rxint(struct imx_port *sport) 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); - - /* disable the rx errors interrupts */ - temp = readl(sport->port.membase + UCR4); - temp &= ~UCR4_OREN; - writel(temp, sport->port.membase + UCR4); + imx_disable_rx_int(sport); /* tell the DMA to receive the data. */ start_rx_dma(sport); @@ -956,8 +967,6 @@ static void imx_timeout(unsigned long data) } } -#define RX_BUF_SIZE (PAGE_SIZE) - /* * There are two kinds of RX DMA interrupts(such as in the MX6Q): * [1] the RX DMA buffer is full. @@ -1040,9 +1049,6 @@ static void dma_rx_callback(void *data) } } -/* RX DMA buffer periods */ -#define RX_DMA_PERIODS 4 - static int start_rx_dma(struct imx_port *sport) { struct scatterlist *sgl = &sport->rx_sgl; @@ -1053,9 +1059,8 @@ static int start_rx_dma(struct imx_port *sport) sport->rx_ring.head = 0; sport->rx_ring.tail = 0; - sport->rx_periods = RX_DMA_PERIODS; - sg_init_one(sgl, sport->rx_buf, RX_BUF_SIZE); + sg_init_one(sgl, sport->rx_buf, sport->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"); @@ -1166,7 +1171,7 @@ static int imx_uart_dma_init(struct imx_port *sport) goto err; } - sport->rx_buf = kzalloc(PAGE_SIZE, GFP_KERNEL); + sport->rx_buf = kzalloc(sport->rx_buf_size, GFP_KERNEL); if (!sport->rx_buf) { ret = -ENOMEM; goto err; @@ -1294,7 +1299,9 @@ static int imx_startup(struct uart_port *port) imx_enable_dma(sport); temp = readl(sport->port.membase + UCR1); - temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN; + temp |= UCR1_RRDYEN | UCR1_UARTEN; + if (sport->have_rtscts) + temp |= UCR1_RTSDEN; writel(temp, sport->port.membase + UCR1); @@ -1317,19 +1324,10 @@ static int imx_startup(struct uart_port *port) if (!is_imx1_uart(sport)) { temp = readl(sport->port.membase + UCR3); - /* - * The effect of RI and DCD differs depending on the UFCR_DCEDTE - * bit. In DCE mode they control the outputs, in DTE mode they - * enable the respective irqs. At least the DCD irq cannot be - * cleared on i.MX25 at least, so it's not usable and must be - * disabled. I don't have test hardware to check if RI has the - * same problem but I consider this likely so it's disabled for - * now, too. - */ - temp |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | - UCR3_DTRDEN | UCR3_RI | UCR3_DCD; + temp |= UCR3_DTRDEN | UCR3_RI | UCR3_DCD; if (sport->dte_mode) + /* disable broken interrupts */ temp &= ~(UCR3_RI | UCR3_DCD); writel(temp, sport->port.membase + UCR3); @@ -1339,6 +1337,17 @@ static int imx_startup(struct uart_port *port) * Enable modem status interrupts */ imx_enable_ms(&sport->port); + + /* + * Start RX DMA immediately instead of waiting for RX FIFO interrupts. + * In our iMX53 the average delay for the first reception dropped from + * approximately 35000 microseconds to 1000 microseconds. + */ + if (sport->dma_is_enabled) { + imx_disable_rx_int(sport); + start_rx_dma(sport); + } + spin_unlock_irqrestore(&sport->port.lock, flags); return 0; @@ -1584,8 +1593,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios, 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); @@ -2029,6 +2036,7 @@ static int serial_imx_probe_dt(struct imx_port *sport, { struct device_node *np = pdev->dev.of_node; int ret; + u32 dma_buf_size[2]; sport->devdata = of_device_get_match_data(&pdev->dev); if (!sport->devdata) @@ -2052,6 +2060,14 @@ static int serial_imx_probe_dt(struct imx_port *sport, if (of_get_property(np, "rts-gpios", NULL)) sport->have_rtsgpio = 1; + if (!of_property_read_u32_array(np, "fsl,dma-size", dma_buf_size, 2)) { + sport->rx_buf_size = dma_buf_size[0] * dma_buf_size[1]; + sport->rx_periods = dma_buf_size[1]; + } else { + sport->rx_buf_size = RX_BUF_SIZE; + sport->rx_periods = RX_DMA_PERIODS; + } + return 0; } #else @@ -2153,6 +2169,37 @@ static int serial_imx_probe(struct platform_device *pdev) UCR1_TXMPTYEN | UCR1_RTSDEN); writel_relaxed(reg, sport->port.membase + UCR1); + if (!is_imx1_uart(sport) && sport->dte_mode) { + /* + * The DCEDTE bit changes the direction of DSR, DCD, DTR and RI + * and influences if UCR3_RI and UCR3_DCD changes the level of RI + * and DCD (when they are outputs) or enables the respective + * irqs. So set this bit early, i.e. before requesting irqs. + */ + reg = readl(sport->port.membase + UFCR); + if (!(reg & UFCR_DCEDTE)) + writel(reg | UFCR_DCEDTE, sport->port.membase + UFCR); + + /* + * Disable UCR3_RI and UCR3_DCD irqs. They are also not + * enabled later because they cannot be cleared + * (confirmed on i.MX25) which makes them unusable. + */ + writel(IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP | UCR3_DSR, + sport->port.membase + UCR3); + + } else { + unsigned long ucr3 = UCR3_DSR; + + reg = readl(sport->port.membase + UFCR); + if (reg & UFCR_DCEDTE) + writel(reg & ~UFCR_DCEDTE, sport->port.membase + UFCR); + + if (!is_imx1_uart(sport)) + ucr3 |= IMX21_UCR3_RXDMUXSEL | UCR3_ADNIMP; + writel(ucr3, sport->port.membase + UCR3); + } + clk_disable_unprepare(sport->clk_ipg); /* |