X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=target%2Flinux%2Flayerscape%2Fpatches-5.4%2F819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch;fp=target%2Flinux%2Flayerscape%2Fpatches-5.4%2F819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch;h=0000000000000000000000000000000000000000;hb=3a14580411adfb75f9a44eded9f41245b9e44606;hp=f07abc2469a01b51fa0bd70d564b14138900eb1d;hpb=9f9477b2751231d57cdd8c227149b88c93491d93;p=openwrt%2Fopenwrt.git diff --git a/target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch b/target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch deleted file mode 100644 index f07abc2469..0000000000 --- a/target/linux/layerscape/patches-5.4/819-uart-0005-tty-serial-fsl_lpuart-enable-dma-mode-for-imx8qxp.patch +++ /dev/null @@ -1,558 +0,0 @@ -From 0d6e214f5a257f9b53619ef8aa3b6e767189bdcf Mon Sep 17 00:00:00 2001 -From: Fugang Duan -Date: Wed, 11 Sep 2019 16:21:06 +0800 -Subject: [PATCH] tty: serial: fsl_lpuart: enable dma mode for imx8qxp - -imx8qxp lpuart support eDMA for dma mode, support EOP (end-of-packet) -feature. But eDMA cannot detect the correct DADDR for current major -loop in cyclic mode, so it doesn't support cyclic mode. - -The patch is to enable lpuart prep slave sg dma mode for imx8qxp. - -Signed-off-by: Fugang Duan ---- - drivers/tty/serial/fsl_lpuart.c | 280 +++++++++++++++++++++++++++++++--------- - 1 file changed, 219 insertions(+), 61 deletions(-) - ---- a/drivers/tty/serial/fsl_lpuart.c -+++ b/drivers/tty/serial/fsl_lpuart.c -@@ -131,6 +131,7 @@ - #define UARTBAUD_M10 0x20000000 - #define UARTBAUD_TDMAE 0x00800000 - #define UARTBAUD_RDMAE 0x00200000 -+#define UARTBAUD_RIDMAE 0x00100000 - #define UARTBAUD_MATCFG 0x00400000 - #define UARTBAUD_BOTHEDGE 0x00020000 - #define UARTBAUD_RESYNCDIS 0x00010000 -@@ -179,7 +180,7 @@ - #define UARTCTRL_SBK 0x00010000 - #define UARTCTRL_MA1IE 0x00008000 - #define UARTCTRL_MA2IE 0x00004000 --#define UARTCTRL_IDLECFG 0x00000100 -+#define UARTCTRL_IDLECFG_OFF 0x8 - #define UARTCTRL_LOOPS 0x00000080 - #define UARTCTRL_DOZEEN 0x00000040 - #define UARTCTRL_RSRC 0x00000020 -@@ -197,6 +198,7 @@ - #define UARTDATA_MASK 0x3ff - - #define UARTMODIR_IREN 0x00020000 -+#define UARTMODIR_RTSWATER_S 0x8 - #define UARTMODIR_TXCTSSRC 0x00000020 - #define UARTMODIR_TXCTSC 0x00000010 - #define UARTMODIR_RXRTSE 0x00000008 -@@ -210,6 +212,8 @@ - #define UARTFIFO_RXUF 0x00010000 - #define UARTFIFO_TXFLUSH 0x00008000 - #define UARTFIFO_RXFLUSH 0x00004000 -+#define UARTFIFO_RXIDEN_MASK 0x7 -+#define UARTFIFO_RXIDEN_OFF 10 - #define UARTFIFO_TXOFE 0x00000200 - #define UARTFIFO_RXUFE 0x00000100 - #define UARTFIFO_TXFE 0x00000080 -@@ -226,6 +230,9 @@ - #define UARTWATER_TXWATER_OFF 0 - #define UARTWATER_RXWATER_OFF 16 - -+#define UARTFIFO_RXIDEN_RDRF 0x3 -+#define UARTCTRL_IDLECFG 0x7 -+ - /* Rx DMA timeout in ms, which is used to calculate Rx ring buffer size */ - #define DMA_RX_TIMEOUT (10) - -@@ -254,6 +261,9 @@ struct lpuart_port { - unsigned int txfifo_size; - unsigned int rxfifo_size; - -+ u8 rx_watermark; -+ bool dma_eeop; -+ bool rx_dma_cyclic; - bool lpuart_dma_tx_use; - bool lpuart_dma_rx_use; - struct dma_chan *dma_tx_chan; -@@ -279,33 +289,45 @@ struct lpuart_soc_data { - enum lpuart_type devtype; - char iotype; - u8 reg_off; -+ u8 rx_watermark; -+ bool rx_dma_cyclic; - }; - - static const struct lpuart_soc_data vf_data = { - .devtype = VF610_LPUART, - .iotype = UPIO_MEM, -+ .rx_watermark = 1, -+ .rx_dma_cyclic = true, - }; - - static const struct lpuart_soc_data ls1021a_data = { - .devtype = LS1021A_LPUART, - .iotype = UPIO_MEM32BE, -+ .rx_watermark = 0, -+ .rx_dma_cyclic = true, - }; - - static const struct lpuart_soc_data ls1028a_data = { - .devtype = LS1028A_LPUART, - .iotype = UPIO_MEM32, -+ .rx_watermark = 0, -+ .rx_dma_cyclic = true, - }; - - static struct lpuart_soc_data imx7ulp_data = { - .devtype = IMX7ULP_LPUART, - .iotype = UPIO_MEM32, - .reg_off = IMX_REG_OFF, -+ .rx_watermark = 0, -+ .rx_dma_cyclic = true, - }; - - static struct lpuart_soc_data imx8qxp_data = { - .devtype = IMX8QXP_LPUART, - .iotype = UPIO_MEM32, - .reg_off = IMX_REG_OFF, -+ .rx_watermark = 31, -+ .rx_dma_cyclic = false, - }; - - static const struct of_device_id lpuart_dt_ids[] = { -@@ -320,6 +342,7 @@ MODULE_DEVICE_TABLE(of, lpuart_dt_ids); - - /* Forward declare this for the dma callbacks*/ - static void lpuart_dma_tx_complete(void *arg); -+static int lpuart_sched_rx_dma(struct lpuart_port *sport); - - static inline bool is_layerscape_lpuart(struct lpuart_port *sport) - { -@@ -1011,19 +1034,15 @@ static irqreturn_t lpuart32_int(int irq, - if ((sts & UARTSTAT_TDRE) && !sport->lpuart_dma_tx_use) - lpuart32_txint(sport); - -+ if (sport->lpuart_dma_rx_use && sport->dma_eeop) -+ sts &= ~UARTSTAT_IDLE; -+ - lpuart32_write(&sport->port, sts, UARTSTAT); - return IRQ_HANDLED; - } - --static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) -+static void lpuart_rx_error_stat(struct lpuart_port *sport) - { -- struct tty_port *port = &sport->port.state->port; -- struct dma_tx_state state; -- enum dma_status dmastat; -- struct circ_buf *ring = &sport->rx_ring; -- unsigned long flags; -- int count = 0; -- - if (lpuart_is_32(sport)) { - unsigned long sr = lpuart32_read(&sport->port, UARTSTAT); - -@@ -1075,8 +1094,21 @@ static void lpuart_copy_rx_to_tty(struct - writeb(cr2, sport->port.membase + UARTCR2); - } - } -+} -+ -+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport) -+{ -+ struct tty_port *port = &sport->port.state->port; -+ struct dma_tx_state state; -+ enum dma_status dmastat; -+ struct circ_buf *ring = &sport->rx_ring; -+ unsigned long flags; -+ int count = 0; - -- async_tx_ack(sport->dma_rx_desc); -+ if (!is_imx8qxp_lpuart(sport)) { -+ lpuart_rx_error_stat(sport); -+ async_tx_ack(sport->dma_rx_desc); -+ } - - spin_lock_irqsave(&sport->port.lock, flags); - -@@ -1139,7 +1171,33 @@ static void lpuart_copy_rx_to_tty(struct - spin_unlock_irqrestore(&sport->port.lock, flags); - - tty_flip_buffer_push(port); -- mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout); -+ -+ if (!sport->dma_eeop) -+ mod_timer(&sport->lpuart_timer, -+ jiffies + sport->dma_rx_timeout); -+} -+ -+static void lpuart_dma_rx_post_handler(struct lpuart_port *sport) -+{ -+ unsigned long flags; -+ unsigned long rxcount; -+ -+ spin_lock_irqsave(&sport->port.lock, flags); -+ -+ /* For end of packet, clear the idle flag to avoid to trigger -+ * the next transfer. Only i.MX8x lpuart support EEOP. -+ */ -+ if (sport->dma_eeop && lpuart_is_32(sport)) { -+ rxcount = lpuart32_read(&sport->port, UARTWATER); -+ rxcount = rxcount >> UARTWATER_RXCNT_OFF; -+ if (!rxcount) -+ lpuart32_write(&sport->port, UARTSTAT_IDLE, UARTSTAT); -+ } -+ -+ lpuart_sched_rx_dma(sport); -+ -+ spin_unlock_irqrestore(&sport->port.lock, flags); -+ - } - - static void lpuart_dma_rx_complete(void *arg) -@@ -1147,6 +1205,8 @@ static void lpuart_dma_rx_complete(void - struct lpuart_port *sport = arg; - - lpuart_copy_rx_to_tty(sport); -+ if (!sport->rx_dma_cyclic) -+ lpuart_dma_rx_post_handler(sport); - } - - static void lpuart_timer_func(struct timer_list *t) -@@ -1154,13 +1214,78 @@ static void lpuart_timer_func(struct tim - struct lpuart_port *sport = from_timer(sport, t, lpuart_timer); - - lpuart_copy_rx_to_tty(sport); -+ if (!sport->rx_dma_cyclic) { -+ dmaengine_terminate_async(sport->dma_rx_chan); -+ lpuart_dma_rx_post_handler(sport); -+ } - } - --static inline int lpuart_start_rx_dma(struct lpuart_port *sport) -+static int lpuart_sched_rxdma_cyclic(struct lpuart_port *sport) -+{ -+ sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan, -+ sg_dma_address(&sport->rx_sgl), -+ sport->rx_sgl.length, -+ sport->rx_sgl.length / 2, -+ DMA_DEV_TO_MEM, -+ DMA_PREP_INTERRUPT); -+ if (!sport->dma_rx_desc) { -+ dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n"); -+ return -EFAULT; -+ } -+ -+ return 0; -+} -+ -+static int lpuart_sched_rxdma_slave_sg(struct lpuart_port *sport) -+{ -+ dma_sync_sg_for_device(sport->port.dev, &sport->rx_sgl, 1, -+ DMA_FROM_DEVICE); -+ sport->dma_rx_desc = dmaengine_prep_slave_sg(sport->dma_rx_chan, -+ &sport->rx_sgl, -+ 1, -+ DMA_DEV_TO_MEM, -+ DMA_PREP_INTERRUPT); -+ if (!sport->dma_rx_desc) { -+ dev_err(sport->port.dev, "Cannot prepare slave_sg DMA\n"); -+ return -EFAULT; -+ } -+ sport->rx_ring.tail = 0; -+ sport->rx_ring.head = 0; -+ -+ return 0; -+} -+ -+static int lpuart_sched_rx_dma(struct lpuart_port *sport) -+{ -+ unsigned long temp; -+ int ret; -+ -+ if (sport->rx_dma_cyclic) -+ ret = lpuart_sched_rxdma_cyclic(sport); -+ else -+ ret = lpuart_sched_rxdma_slave_sg(sport); -+ -+ sport->dma_rx_desc->callback = lpuart_dma_rx_complete; -+ sport->dma_rx_desc->callback_param = sport; -+ sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); -+ dma_async_issue_pending(sport->dma_rx_chan); -+ -+ if (lpuart_is_32(sport)) { -+ temp = lpuart32_read(&sport->port, UARTBAUD); -+ if (sport->dma_eeop) -+ temp |= UARTBAUD_RIDMAE; -+ temp |= UARTBAUD_RDMAE; -+ lpuart32_write(&sport->port, temp, UARTBAUD); -+ } else { -+ writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, -+ sport->port.membase + UARTCR5); -+ } -+ -+ return ret; -+} -+ -+static void lpuart_get_rx_dma_rng_len(struct lpuart_port *sport) - { -- struct dma_slave_config dma_rx_sconfig = {}; -- struct circ_buf *ring = &sport->rx_ring; -- int ret, nent; - int bits, baud; - struct tty_port *port = &sport->port.state->port; - struct tty_struct *tty = port->tty; -@@ -1180,6 +1305,18 @@ static inline int lpuart_start_rx_dma(st - sport->rx_dma_rng_buf_len = (1 << (fls(sport->rx_dma_rng_buf_len) - 1)); - if (sport->rx_dma_rng_buf_len < 16) - sport->rx_dma_rng_buf_len = 16; -+} -+ -+static inline int lpuart_start_rx_dma(struct lpuart_port *sport) -+{ -+ struct dma_slave_config dma_rx_sconfig = {}; -+ struct circ_buf *ring = &sport->rx_ring; -+ int ret, nent; -+ -+ if (!sport->dma_eeop) -+ lpuart_get_rx_dma_rng_len(sport); -+ else -+ sport->rx_dma_rng_buf_len = PAGE_SIZE; - - ring->buf = kzalloc(sport->rx_dma_rng_buf_len, GFP_ATOMIC); - if (!ring->buf) -@@ -1205,32 +1342,7 @@ static inline int lpuart_start_rx_dma(st - return ret; - } - -- sport->dma_rx_desc = dmaengine_prep_dma_cyclic(sport->dma_rx_chan, -- sg_dma_address(&sport->rx_sgl), -- sport->rx_sgl.length, -- sport->rx_sgl.length / 2, -- DMA_DEV_TO_MEM, -- DMA_PREP_INTERRUPT); -- if (!sport->dma_rx_desc) { -- dev_err(sport->port.dev, "Cannot prepare cyclic DMA\n"); -- return -EFAULT; -- } -- -- sport->dma_rx_desc->callback = lpuart_dma_rx_complete; -- sport->dma_rx_desc->callback_param = sport; -- sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc); -- dma_async_issue_pending(sport->dma_rx_chan); -- -- if (lpuart_is_32(sport)) { -- unsigned long temp = lpuart32_read(&sport->port, UARTBAUD); -- -- lpuart32_write(&sport->port, temp | UARTBAUD_RDMAE, UARTBAUD); -- } else { -- writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_RDMAS, -- sport->port.membase + UARTCR5); -- } -- -- return 0; -+ return lpuart_sched_rx_dma(sport); - } - - static void lpuart_dma_rx_free(struct uart_port *port) -@@ -1416,8 +1528,10 @@ static void lpuart_setup_watermark(struc - writeb(UARTSFIFO_RXUF, sport->port.membase + UARTSFIFO); - } - -+ if (uart_console(&sport->port)) -+ sport->rx_watermark = 1; - writeb(0, sport->port.membase + UARTTWFIFO); -- writeb(1, sport->port.membase + UARTRWFIFO); -+ writeb(sport->rx_watermark, sport->port.membase + UARTRWFIFO); - - /* Restore cr2 */ - writeb(cr2_saved, sport->port.membase + UARTCR2); -@@ -1438,6 +1552,7 @@ static void lpuart32_setup_watermark(str - { - unsigned long val, ctrl; - unsigned long ctrl_saved; -+ unsigned long rxiden_cnt; - - ctrl = lpuart32_read(&sport->port, UARTCTRL); - ctrl_saved = ctrl; -@@ -1449,12 +1564,26 @@ static void lpuart32_setup_watermark(str - val = lpuart32_read(&sport->port, UARTFIFO); - val |= UARTFIFO_TXFE | UARTFIFO_RXFE; - val |= UARTFIFO_TXFLUSH | UARTFIFO_RXFLUSH; -+ val &= ~(UARTFIFO_RXIDEN_MASK << UARTFIFO_RXIDEN_OFF); -+ rxiden_cnt = sport->dma_eeop ? 0 : UARTFIFO_RXIDEN_RDRF; -+ val |= ((rxiden_cnt & UARTFIFO_RXIDEN_MASK) << -+ UARTFIFO_RXIDEN_OFF); - lpuart32_write(&sport->port, val, UARTFIFO); - - /* set the watermark */ -- val = (0x1 << UARTWATER_RXWATER_OFF) | (0x0 << UARTWATER_TXWATER_OFF); -+ if (uart_console(&sport->port)) -+ sport->rx_watermark = 1; -+ val = (sport->rx_watermark << UARTWATER_RXWATER_OFF) | -+ (0x0 << UARTWATER_TXWATER_OFF); - lpuart32_write(&sport->port, val, UARTWATER); - -+ /* set RTS watermark */ -+ if (!uart_console(&sport->port)) { -+ val = lpuart32_read(&sport->port, UARTMODIR); -+ val = (sport->rxfifo_size >> 1) << UARTMODIR_RTSWATER_S; -+ lpuart32_write(&sport->port, val, UARTMODIR); -+ } -+ - /* Restore cr2 */ - lpuart32_write(&sport->port, ctrl_saved, UARTCTRL); - } -@@ -1466,17 +1595,29 @@ static void lpuart32_setup_watermark_ena - lpuart32_setup_watermark(sport); - - temp = lpuart32_read(&sport->port, UARTCTRL); -- temp |= UARTCTRL_RE | UARTCTRL_TE | UARTCTRL_ILIE; -+ temp |= UARTCTRL_RE | UARTCTRL_TE; -+ temp |= UARTCTRL_IDLECFG << UARTCTRL_IDLECFG_OFF; - lpuart32_write(&sport->port, temp, UARTCTRL); - } - - static void rx_dma_timer_init(struct lpuart_port *sport) - { -+ if (sport->dma_eeop) -+ return; -+ - timer_setup(&sport->lpuart_timer, lpuart_timer_func, 0); - sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout; - add_timer(&sport->lpuart_timer); - } - -+static void lpuart_del_timer_sync(struct lpuart_port *sport) -+{ -+ if (sport->dma_eeop) -+ return; -+ -+ del_timer_sync(&sport->lpuart_timer); -+} -+ - static void lpuart_tx_dma_startup(struct lpuart_port *sport) - { - u32 uartbaud; -@@ -1540,19 +1681,23 @@ static int lpuart_startup(struct uart_po - return 0; - } - -+static void lpuart32_hw_disable(struct lpuart_port *sport) -+{ -+ unsigned long temp; -+ -+ temp = lpuart32_read(&sport->port, UARTCTRL); -+ temp &= ~(UARTCTRL_RIE | UARTCTRL_ILIE | UARTCTRL_RE | -+ UARTCTRL_TIE | UARTCTRL_TE); -+ lpuart32_write(&sport->port, temp, UARTCTRL); -+} -+ - static void lpuart32_configure(struct lpuart_port *sport) - { - unsigned long temp; - -- 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; -+ temp |= UARTCTRL_RIE | UARTCTRL_ILIE; - if (!sport->lpuart_dma_tx_use) - temp |= UARTCTRL_TIE; - lpuart32_write(&sport->port, temp, UARTCTRL); -@@ -1596,12 +1741,12 @@ static int lpuart32_startup(struct uart_ - - spin_lock_irqsave(&sport->port.lock, flags); - -- lpuart32_setup_watermark_enable(sport); -- -+ lpuart32_hw_disable(sport); - - lpuart_rx_dma_startup(sport); - lpuart_tx_dma_startup(sport); - -+ lpuart32_setup_watermark_enable(sport); - lpuart32_configure(sport); - - spin_unlock_irqrestore(&sport->port.lock, flags); -@@ -1611,7 +1756,7 @@ static int lpuart32_startup(struct uart_ - static void lpuart_dma_shutdown(struct lpuart_port *sport) - { - if (sport->lpuart_dma_rx_use) { -- del_timer_sync(&sport->lpuart_timer); -+ lpuart_del_timer_sync(sport); - lpuart_dma_rx_free(&sport->port); - } - -@@ -1652,11 +1797,22 @@ static void lpuart32_shutdown(struct uar - - spin_lock_irqsave(&port->lock, flags); - -+ /* clear statue */ -+ temp = lpuart32_read(&sport->port, UARTSTAT); -+ lpuart32_write(&sport->port, temp, UARTSTAT); -+ -+ /* disable Rx/Tx DMA */ -+ temp = lpuart32_read(port, UARTBAUD); -+ temp &= ~(UARTBAUD_TDMAE | UARTBAUD_RDMAE | UARTBAUD_RIDMAE); -+ lpuart32_write(port, temp, UARTBAUD); -+ - /* disable Rx/Tx and interrupts */ - temp = lpuart32_read(port, UARTCTRL); -- temp &= ~(UARTCTRL_TE | UARTCTRL_RE | -- UARTCTRL_TIE | UARTCTRL_TCIE | UARTCTRL_RIE); -+ temp &= ~(UARTCTRL_TE | UARTCTRL_RE | UARTCTRL_TIE | -+ UARTCTRL_TCIE | UARTCTRL_RIE | UARTCTRL_ILIE | -+ UARTCTRL_LOOPS); - lpuart32_write(port, temp, UARTCTRL); -+ lpuart32_write(port, 0, UARTMODIR); - - spin_unlock_irqrestore(&port->lock, flags); - -@@ -1753,10 +1909,10 @@ lpuart_set_termios(struct uart_port *por - * baud rate and restart Rx DMA path. - * - * Since timer function acqures sport->port.lock, need to stop before -- * acquring same lock because otherwise del_timer_sync() can deadlock. -+ * acquring same lock because otherwise lpuart_del_timer_sync() can deadlock. - */ - if (old && sport->lpuart_dma_rx_use) { -- del_timer_sync(&sport->lpuart_timer); -+ lpuart_del_timer_sync(sport); - lpuart_dma_rx_free(&sport->port); - } - -@@ -1968,10 +2124,10 @@ lpuart32_set_termios(struct uart_port *p - * baud rate and restart Rx DMA path. - * - * Since timer function acqures sport->port.lock, need to stop before -- * acquring same lock because otherwise del_timer_sync() can deadlock. -+ * acquring same lock because otherwise lpuart_del_timer_sync() can deadlock. - */ - if (old && sport->lpuart_dma_rx_use) { -- del_timer_sync(&sport->lpuart_timer); -+ lpuart_del_timer_sync(sport); - lpuart_dma_rx_free(&sport->port); - } - -@@ -2483,6 +2639,10 @@ static int lpuart_probe(struct platform_ - sport->port.dev = &pdev->dev; - sport->port.type = PORT_LPUART; - sport->devtype = sdata->devtype; -+ sport->rx_dma_cyclic = sdata->rx_dma_cyclic; -+ sport->rx_watermark = sdata->rx_watermark; -+ sport->dma_eeop = is_imx8qxp_lpuart(sport); -+ - ret = platform_get_irq(pdev, 0); - if (ret < 0) - return ret; -@@ -2645,7 +2805,7 @@ static int lpuart_suspend(struct device - * Rx DMA path before suspend and start Rx DMA path on resume. - */ - if (irq_wake) { -- del_timer_sync(&sport->lpuart_timer); -+ lpuart_del_timer_sync(sport); - lpuart_dma_rx_free(&sport->port); - } -