Merge tag 'usb-4.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
[cascardo/linux.git] / drivers / tty / serial / imx.c
index 0df2b1c..a70356d 100644 (file)
 enum imx_uart_type {
        IMX1_UART,
        IMX21_UART,
+       IMX53_UART,
        IMX6Q_UART,
 };
 
@@ -222,6 +223,9 @@ struct imx_port {
        struct dma_chan         *dma_chan_rx, *dma_chan_tx;
        struct scatterlist      rx_sgl, tx_sgl[2];
        void                    *rx_buf;
+       struct circ_buf         rx_ring;
+       unsigned int            rx_periods;
+       dma_cookie_t            rx_cookie;
        unsigned int            tx_bytes;
        unsigned int            dma_tx_nents;
        wait_queue_head_t       dma_wait;
@@ -244,6 +248,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
                .uts_reg = IMX21_UTS,
                .devtype = IMX21_UART,
        },
+       [IMX53_UART] = {
+               .uts_reg = IMX21_UTS,
+               .devtype = IMX53_UART,
+       },
        [IMX6Q_UART] = {
                .uts_reg = IMX21_UTS,
                .devtype = IMX6Q_UART,
@@ -257,6 +265,9 @@ static const struct platform_device_id imx_uart_devtype[] = {
        }, {
                .name = "imx21-uart",
                .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX21_UART],
+       }, {
+               .name = "imx53-uart",
+               .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX53_UART],
        }, {
                .name = "imx6q-uart",
                .driver_data = (kernel_ulong_t) &imx_uart_devdata[IMX6Q_UART],
@@ -268,6 +279,7 @@ MODULE_DEVICE_TABLE(platform, imx_uart_devtype);
 
 static const struct of_device_id imx_uart_dt_ids[] = {
        { .compatible = "fsl,imx6q-uart", .data = &imx_uart_devdata[IMX6Q_UART], },
+       { .compatible = "fsl,imx53-uart", .data = &imx_uart_devdata[IMX53_UART], },
        { .compatible = "fsl,imx1-uart", .data = &imx_uart_devdata[IMX1_UART], },
        { .compatible = "fsl,imx21-uart", .data = &imx_uart_devdata[IMX21_UART], },
        { /* sentinel */ }
@@ -289,6 +301,11 @@ static inline int is_imx21_uart(struct imx_port *sport)
        return sport->devdata->devtype == IMX21_UART;
 }
 
+static inline int is_imx53_uart(struct imx_port *sport)
+{
+       return sport->devdata->devtype == IMX53_UART;
+}
+
 static inline int is_imx6q_uart(struct imx_port *sport)
 {
        return sport->devdata->devtype == IMX6Q_UART;
@@ -701,6 +718,7 @@ out:
        return IRQ_HANDLED;
 }
 
+static void clear_rx_errors(struct imx_port *sport);
 static int start_rx_dma(struct imx_port *sport);
 /*
  * If the RXFIFO is filled with some data, and then we
@@ -726,6 +744,11 @@ static void imx_dma_rxint(struct imx_port *sport)
                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);
+
                /* tell the DMA to receive the data. */
                start_rx_dma(sport);
        }
@@ -740,12 +763,13 @@ static unsigned int imx_get_hwmctrl(struct imx_port *sport)
 {
        unsigned int tmp = TIOCM_DSR;
        unsigned usr1 = readl(sport->port.membase + USR1);
+       unsigned usr2 = readl(sport->port.membase + USR2);
 
        if (usr1 & USR1_RTSS)
                tmp |= TIOCM_CTS;
 
        /* in DCE mode DCDIN is always 0 */
-       if (!(usr1 & USR2_DCDIN))
+       if (!(usr2 & USR2_DCDIN))
                tmp |= TIOCM_CAR;
 
        if (sport->dte_mode)
@@ -932,30 +956,6 @@ static void imx_timeout(unsigned long data)
 }
 
 #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):
@@ -972,43 +972,76 @@ static void dma_rx_callback(void *data)
        struct scatterlist *sgl = &sport->rx_sgl;
        struct tty_port *port = &sport->port.state->port;
        struct dma_tx_state state;
+       struct circ_buf *rx_ring = &sport->rx_ring;
        enum dma_status status;
-       unsigned int count;
-
-       /* unmap it first */
-       dma_unmap_sg(sport->port.dev, sgl, 1, DMA_FROM_DEVICE);
+       unsigned int w_bytes = 0;
+       unsigned int r_bytes;
+       unsigned int bd_size;
 
        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 (status == DMA_ERROR) {
+               dev_err(sport->port.dev, "DMA transaction error.\n");
+               clear_rx_errors(sport);
+               return;
+       }
+
+       if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
+
+               /*
+                * The state-residue variable represents the empty space
+                * relative to the entire buffer. Taking this in consideration
+                * the head is always calculated base on the buffer total
+                * length - DMA transaction residue. The UART script from the
+                * SDMA firmware will jump to the next buffer descriptor,
+                * once a DMA transaction if finalized (IMX53 RM - A.4.1.2.4).
+                * Taking this in consideration the tail is always at the
+                * beginning of the buffer descriptor that contains the head.
+                */
+
+               /* Calculate the head */
+               rx_ring->head = sg_dma_len(sgl) - state.residue;
+
+               /* Calculate the tail. */
+               bd_size = sg_dma_len(sgl) / sport->rx_periods;
+               rx_ring->tail = ((rx_ring->head-1) / bd_size) * bd_size;
+
+               if (rx_ring->head <= sg_dma_len(sgl) &&
+                   rx_ring->head > rx_ring->tail) {
+
+                       /* Move data from tail to head */
+                       r_bytes = rx_ring->head - rx_ring->tail;
 
-       if (count) {
-               if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ)) {
-                       int bytes = tty_insert_flip_string(port, sport->rx_buf,
-                                       count);
+                       /* CPU claims ownership of RX DMA buffer */
+                       dma_sync_sg_for_cpu(sport->port.dev, sgl, 1,
+                               DMA_FROM_DEVICE);
 
-                       if (bytes != count)
+                       w_bytes = tty_insert_flip_string(port,
+                               sport->rx_buf + rx_ring->tail, r_bytes);
+
+                       /* UART retrieves ownership of RX DMA buffer */
+                       dma_sync_sg_for_device(sport->port.dev, sgl, 1,
+                               DMA_FROM_DEVICE);
+
+                       if (w_bytes != r_bytes)
                                sport->port.icount.buf_overrun++;
+
+                       sport->port.icount.rx += w_bytes;
+               } else  {
+                       WARN_ON(rx_ring->head > sg_dma_len(sgl));
+                       WARN_ON(rx_ring->head <= rx_ring->tail);
                }
-               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);
+       if (w_bytes) {
+               tty_flip_buffer_push(port);
+               dev_dbg(sport->port.dev, "We get %d bytes.\n", w_bytes);
+       }
 }
 
+/* RX DMA buffer periods */
+#define RX_DMA_PERIODS 4
+
 static int start_rx_dma(struct imx_port *sport)
 {
        struct scatterlist *sgl = &sport->rx_sgl;
@@ -1017,14 +1050,21 @@ static int start_rx_dma(struct imx_port *sport)
        struct dma_async_tx_descriptor *desc;
        int ret;
 
+       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);
        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);
+
+       desc = dmaengine_prep_dma_cyclic(chan, sg_dma_address(sgl),
+               sg_dma_len(sgl), sg_dma_len(sgl) / sport->rx_periods,
+               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");
@@ -1034,11 +1074,36 @@ static int start_rx_dma(struct imx_port *sport)
        desc->callback_param = sport;
 
        dev_dbg(dev, "RX: prepare for the DMA.\n");
-       dmaengine_submit(desc);
+       sport->rx_cookie = dmaengine_submit(desc);
        dma_async_issue_pending(chan);
        return 0;
 }
 
+static void clear_rx_errors(struct imx_port *sport)
+{
+       unsigned int status_usr1, status_usr2;
+
+       status_usr1 = readl(sport->port.membase + USR1);
+       status_usr2 = readl(sport->port.membase + USR2);
+
+       if (status_usr2 & USR2_BRCD) {
+               sport->port.icount.brk++;
+               writel(USR2_BRCD, sport->port.membase + USR2);
+       } else if (status_usr1 & USR1_FRAMERR) {
+               sport->port.icount.frame++;
+               writel(USR1_FRAMERR, sport->port.membase + USR1);
+       } else if (status_usr1 & USR1_PARITYERR) {
+               sport->port.icount.parity++;
+               writel(USR1_PARITYERR, sport->port.membase + USR1);
+       }
+
+       if (status_usr2 & USR2_ORE) {
+               sport->port.icount.overrun++;
+               writel(USR2_ORE, sport->port.membase + USR2);
+       }
+
+}
+
 #define TXTL_DEFAULT 2 /* reset default */
 #define RXTL_DEFAULT 1 /* reset default */
 #define TXTL_DMA 8 /* DMA burst setting */
@@ -1058,14 +1123,16 @@ static void imx_setup_ufcr(struct imx_port *sport,
 static void imx_uart_dma_exit(struct imx_port *sport)
 {
        if (sport->dma_chan_rx) {
+               dmaengine_terminate_sync(sport->dma_chan_rx);
                dma_release_channel(sport->dma_chan_rx);
                sport->dma_chan_rx = NULL;
-
+               sport->rx_cookie = -EINVAL;
                kfree(sport->rx_buf);
                sport->rx_buf = NULL;
        }
 
        if (sport->dma_chan_tx) {
+               dmaengine_terminate_sync(sport->dma_chan_tx);
                dma_release_channel(sport->dma_chan_tx);
                sport->dma_chan_tx = NULL;
        }
@@ -1103,6 +1170,7 @@ static int imx_uart_dma_init(struct imx_port *sport)
                ret = -ENOMEM;
                goto err;
        }
+       sport->rx_ring.buf = sport->rx_buf;
 
        /* Prepare for TX : */
        sport->dma_chan_tx = dma_request_slave_channel(dev, "tx");
@@ -1201,8 +1269,7 @@ static int imx_startup(struct uart_port *port)
        writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 
        /* Can we enable the DMA support? */
-       if (is_imx6q_uart(sport) && !uart_console(port) &&
-           !sport->dma_is_inited)
+       if (!uart_console(port) && !sport->dma_is_inited)
                imx_uart_dma_init(sport);
 
        spin_lock_irqsave(&sport->port.lock, flags);
@@ -1283,17 +1350,11 @@ static void imx_shutdown(struct uart_port *port)
        unsigned long flags;
 
        if (sport->dma_is_enabled) {
-               int ret;
+               sport->dma_is_rxing = 0;
+               sport->dma_is_txing = 0;
+               dmaengine_terminate_sync(sport->dma_chan_tx);
+               dmaengine_terminate_sync(sport->dma_chan_rx);
 
-               /* 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);
@@ -1690,7 +1751,7 @@ static int imx_rs485_config(struct uart_port *port,
        return 0;
 }
 
-static struct uart_ops imx_pops = {
+static const struct uart_ops imx_pops = {
        .tx_empty       = imx_tx_empty,
        .set_mctrl      = imx_set_mctrl,
        .get_mctrl      = imx_get_mctrl,
@@ -2077,8 +2138,10 @@ static int serial_imx_probe(struct platform_device *pdev)
 
        /* For register access, we only need to enable the ipg clock. */
        ret = clk_prepare_enable(sport->clk_ipg);
-       if (ret)
+       if (ret) {
+               dev_err(&pdev->dev, "failed to enable per clk: %d\n", ret);
                return ret;
+       }
 
        /* Disable interrupts before requesting them */
        reg = readl_relaxed(sport->port.membase + UCR1);
@@ -2095,18 +2158,26 @@ static int serial_imx_probe(struct platform_device *pdev)
        if (txirq > 0) {
                ret = devm_request_irq(&pdev->dev, rxirq, imx_rxint, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request rx irq: %d\n",
+                               ret);
                        return ret;
+               }
 
                ret = devm_request_irq(&pdev->dev, txirq, imx_txint, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request tx irq: %d\n",
+                               ret);
                        return ret;
+               }
        } else {
                ret = devm_request_irq(&pdev->dev, rxirq, imx_int, 0,
                                       dev_name(&pdev->dev), sport);
-               if (ret)
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to request irq: %d\n", ret);
                        return ret;
+               }
        }
 
        imx_ports[sport->port.line] = sport;