All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] serial: imx: add DMA support for imx6
@ 2013-07-08  9:14 ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

(1) This patch set adds the DMA support for the imx serial driver.
    The uart with the dma support is usually used by the Bluetooth.

    For the firmware's limit, i only enable the DMA for imx6 serials.
    If we have proper firmware for imx53 (or other chips), we can also
    enable the DMA for it.

(2) We only enable the DMA support when the following are meet:

    [1] The uart port supports the hardware flow control(CTS/RTS).
      (Some uart port does not support the CTS/RTS.)

    [2] The application enables the CTS/RTS.

    [3] The Soc is imx6 serials.
      For the sdma's firmware limit, we do not support the DMA except
      the imx6 platform.

    [4] The uart is not used as a console.


(3) Tested this patch set by:
	connecting a imx6q-arm2 board(DTE) with a imx53 board(DCE).

v3 --> v4:
	[0] add DTE pad for uart2

v2 --> v3:
	[0] add a new patch to fix the RTS/CTS pad name issue.
	[1] rename the uart DTE pinctrl, remove the "dte" from the pinctrl.
	[2] add a similar UART DTE pinctrl for IMX6DL.
	[3] move the "fsl,imx6q-uart" to the first of the compatible table.

v1 --> v2:
	[0] use the "fsl,imx6q-uart" as the new compatible value.
	[1] move dma_is_inited to imx_uart_dma_init();
	    move dma_is_enabled to imx_enable_dma();
	[2] move imx_disable_dma() to the front place of the imx_shutdown(),
	    just before calls the imx_uart_dma_exit().
	[3] misc    
	

Huang Shijie (6):
  serial: imx: distinguish the imx6q uart from the others
  serial: imx: add DMA support for imx6q
  ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible
  ARM: dts: imx6q{dl}: add DTE pads for uart
  ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
  ARM: dts: enable the uart2 for imx6q-arm2

 arch/arm/boot/dts/imx6dl-pinfunc.h |    4 +
 arch/arm/boot/dts/imx6dl.dtsi      |    9 +
 arch/arm/boot/dts/imx6q-arm2.dts   |   10 +
 arch/arm/boot/dts/imx6q-pinfunc.h  |    4 +
 arch/arm/boot/dts/imx6q.dtsi       |    9 +
 arch/arm/boot/dts/imx6sl.dtsi      |   15 +-
 drivers/tty/serial/imx.c           |  422 +++++++++++++++++++++++++++++++++++-
 7 files changed, 461 insertions(+), 12 deletions(-)



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4 0/6] serial: imx: add DMA support for imx6
@ 2013-07-08  9:14 ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

(1) This patch set adds the DMA support for the imx serial driver.
    The uart with the dma support is usually used by the Bluetooth.

    For the firmware's limit, i only enable the DMA for imx6 serials.
    If we have proper firmware for imx53 (or other chips), we can also
    enable the DMA for it.

(2) We only enable the DMA support when the following are meet:

    [1] The uart port supports the hardware flow control(CTS/RTS).
      (Some uart port does not support the CTS/RTS.)

    [2] The application enables the CTS/RTS.

    [3] The Soc is imx6 serials.
      For the sdma's firmware limit, we do not support the DMA except
      the imx6 platform.

    [4] The uart is not used as a console.


(3) Tested this patch set by:
	connecting a imx6q-arm2 board(DTE) with a imx53 board(DCE).

v3 --> v4:
	[0] add DTE pad for uart2

v2 --> v3:
	[0] add a new patch to fix the RTS/CTS pad name issue.
	[1] rename the uart DTE pinctrl, remove the "dte" from the pinctrl.
	[2] add a similar UART DTE pinctrl for IMX6DL.
	[3] move the "fsl,imx6q-uart" to the first of the compatible table.

v1 --> v2:
	[0] use the "fsl,imx6q-uart" as the new compatible value.
	[1] move dma_is_inited to imx_uart_dma_init();
	    move dma_is_enabled to imx_enable_dma();
	[2] move imx_disable_dma() to the front place of the imx_shutdown(),
	    just before calls the imx_uart_dma_exit().
	[3] misc    
	

Huang Shijie (6):
  serial: imx: distinguish the imx6q uart from the others
  serial: imx: add DMA support for imx6q
  ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible
  ARM: dts: imx6q{dl}: add DTE pads for uart
  ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
  ARM: dts: enable the uart2 for imx6q-arm2

 arch/arm/boot/dts/imx6dl-pinfunc.h |    4 +
 arch/arm/boot/dts/imx6dl.dtsi      |    9 +
 arch/arm/boot/dts/imx6q-arm2.dts   |   10 +
 arch/arm/boot/dts/imx6q-pinfunc.h  |    4 +
 arch/arm/boot/dts/imx6q.dtsi       |    9 +
 arch/arm/boot/dts/imx6sl.dtsi      |   15 +-
 drivers/tty/serial/imx.c           |  422 +++++++++++++++++++++++++++++++++++-
 7 files changed, 461 insertions(+), 12 deletions(-)

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4 1/6] serial: imx: distinguish the imx6q uart from the others
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

We will add the DMA support for the imx uart. For the firmware's limit,
only the imx6 serial chips (including the imx6q, imx6dl, imx6sl) can
support the DMA.

This patch adds the necessary macro and helper to distinguish the
imx6q uart from the other imx uart. Other chips can use the "fsl,imx6q-uart"
to enable the DMA support.

This patch also replaces the check "is_imx21_uart()" with "!is_imx1_uart()".

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/tty/serial/imx.c |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 48bace0..a9643ef 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -187,6 +187,7 @@
 enum imx_uart_type {
 	IMX1_UART,
 	IMX21_UART,
+	IMX6Q_UART,
 };
 
 /* device type dependent stuff */
@@ -232,6 +233,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
 		.uts_reg = IMX21_UTS,
 		.devtype = IMX21_UART,
 	},
+	[IMX6Q_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX6Q_UART,
+	},
 };
 
 static struct platform_device_id imx_uart_devtype[] = {
@@ -242,12 +247,16 @@ static struct platform_device_id imx_uart_devtype[] = {
 		.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[] = {
+	{ .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 */ }
@@ -269,6 +278,10 @@ static inline int is_imx21_uart(struct imx_port *sport)
 	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
  */
@@ -801,7 +814,7 @@ static int imx_startup(struct uart_port *port)
 		}
 	}
 
-	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);
@@ -1044,7 +1057,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 	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);
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 1/6] serial: imx: distinguish the imx6q uart from the others
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

We will add the DMA support for the imx uart. For the firmware's limit,
only the imx6 serial chips (including the imx6q, imx6dl, imx6sl) can
support the DMA.

This patch adds the necessary macro and helper to distinguish the
imx6q uart from the other imx uart. Other chips can use the "fsl,imx6q-uart"
to enable the DMA support.

This patch also replaces the check "is_imx21_uart()" with "!is_imx1_uart()".

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/tty/serial/imx.c |   17 +++++++++++++++--
 1 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 48bace0..a9643ef 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -187,6 +187,7 @@
 enum imx_uart_type {
 	IMX1_UART,
 	IMX21_UART,
+	IMX6Q_UART,
 };
 
 /* device type dependent stuff */
@@ -232,6 +233,10 @@ static struct imx_uart_data imx_uart_devdata[] = {
 		.uts_reg = IMX21_UTS,
 		.devtype = IMX21_UART,
 	},
+	[IMX6Q_UART] = {
+		.uts_reg = IMX21_UTS,
+		.devtype = IMX6Q_UART,
+	},
 };
 
 static struct platform_device_id imx_uart_devtype[] = {
@@ -242,12 +247,16 @@ static struct platform_device_id imx_uart_devtype[] = {
 		.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[] = {
+	{ .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 */ }
@@ -269,6 +278,10 @@ static inline int is_imx21_uart(struct imx_port *sport)
 	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
  */
@@ -801,7 +814,7 @@ static int imx_startup(struct uart_port *port)
 		}
 	}
 
-	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);
@@ -1044,7 +1057,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 	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);
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 2/6] serial: imx: add DMA support for imx6q
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

We only enable the DMA support when the following are meet:

  [1] The uart port supports the hardware flow control(CTS/RTS).
      (Some uart port does not support the CTS/RTS.)

  [2] The application enables the CTS/RTS.

  [3] The Soc is imx6q.
      For the sdma's firmware limit, we do not support the DMA except
      the imx6q platform.

  [4] The uart is not used as a console.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/tty/serial/imx.c |  405 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 400 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a9643ef..d04a09e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,9 +49,11 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
+#include <linux/platform_data/dma-imx.h>
 
 /* Register definitions */
 #define URXD0 0x0  /* Receiver Register */
@@ -83,6 +85,7 @@
 #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 +94,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 */
@@ -126,6 +130,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 */
@@ -210,6 +215,19 @@ struct imx_port {
 	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		rx_bytes, tx_bytes;
+	struct work_struct	tsk_dma_rx, tsk_dma_tx;
+	unsigned int		dma_tx_nents;
+	wait_queue_head_t	dma_wait;
 };
 
 struct imx_port_ucrs {
@@ -400,6 +418,13 @@ static void imx_stop_tx(struct uart_port *port)
 		return;
 	}
 
+	/*
+	 * 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 + UCR1);
 	writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
 }
@@ -412,6 +437,13 @@ static void imx_stop_rx(struct uart_port *port)
 	struct imx_port *sport = (struct imx_port *)port;
 	unsigned long temp;
 
+	/*
+	 * 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_rxing)
+		return;
+
 	temp = readl(sport->port.membase + UCR2);
 	writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
 }
@@ -447,6 +479,95 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
 		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;
+
+	dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+
+	sport->dma_is_txing = 0;
+
+	/* update the stat */
+	spin_lock_irqsave(&sport->port.lock, flags);
+	xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
+	sport->port.icount.tx += sport->tx_bytes;
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
+
+	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;
+	}
+
+	schedule_work(&sport->tsk_dma_tx);
+}
+
+static void dma_tx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
+	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;
+	enum dma_status status;
+	unsigned long flags;
+	int ret;
+
+	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL);
+	if (DMA_IN_PROGRESS == status)
+		return;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+	sport->tx_bytes = uart_circ_chars_pending(xmit);
+	if (sport->tx_bytes == 0) {
+		spin_unlock_irqrestore(&sport->port.lock, flags);
+		return;
+	}
+
+	if (xmit->tail > xmit->head) {
+		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);
+	} else {
+		sport->dma_tx_nents = 1;
+		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+	}
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	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) {
+		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));
+	/* fire it */
+	sport->dma_is_txing = 1;
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+	return;
+}
+
 /*
  * interrupts disabled on entry
  */
@@ -473,8 +594,10 @@ static void imx_start_tx(struct uart_port *port)
 	temp |= UCR4_OREN;
 	writel(temp, sport->port.membase + UCR4);
 
-	temp = readl(sport->port.membase + UCR1);
-	writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	if (!sport->dma_is_enabled) {
+		temp = readl(sport->port.membase + UCR1);
+		writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	}
 
 	if (USE_IRDA(sport)) {
 		temp = readl(sport->port.membase + UCR1);
@@ -486,6 +609,15 @@ static void imx_start_tx(struct uart_port *port)
 		writel(temp, sport->port.membase + UCR4);
 	}
 
+	if (sport->dma_is_enabled) {
+		/*
+		 * We may in the interrupt context, so arise a work_struct to
+		 * do the real job.
+		 */
+		schedule_work(&sport->tsk_dma_tx);
+		return;
+	}
+
 	if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
 		imx_transmit_buffer(sport);
 }
@@ -601,6 +733,28 @@ out:
 	return IRQ_HANDLED;
 }
 
+/*
+ * 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;
+
+	temp = readl(sport->port.membase + USR2);
+	if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
+		sport->dma_is_rxing = 1;
+
+		/* disable the `Recerver Ready Interrrupt` */
+		temp = readl(sport->port.membase + UCR1);
+		temp &= ~(UCR1_RRDYEN);
+		writel(temp, sport->port.membase + UCR1);
+
+		/* tell the DMA to receive the data. */
+		schedule_work(&sport->tsk_dma_rx);
+	}
+}
+
 static irqreturn_t imx_int(int irq, void *dev_id)
 {
 	struct imx_port *sport = dev_id;
@@ -609,8 +763,12 @@ static irqreturn_t imx_int(int irq, void *dev_id)
 
 	sts = readl(sport->port.membase + USR1);
 
-	if (sts & USR1_RRDY)
-		imx_rxint(irq, dev_id);
+	if (sts & USR1_RRDY) {
+		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)
@@ -667,7 +825,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
 
 	if (mctrl & TIOCM_RTS)
-		temp |= UCR2_CTS;
+		if (!sport->dma_is_enabled)
+			temp |= UCR2_CTS;
 
 	writel(temp, sport->port.membase + UCR2);
 }
@@ -706,6 +865,226 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
 	return 0;
 }
 
+#define RX_BUF_SIZE	(PAGE_SIZE)
+static int start_rx_dma(struct imx_port *sport);
+static void dma_rx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx);
+	struct tty_port *port = &sport->port.state->port;
+
+	if (sport->rx_bytes) {
+		tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes);
+		tty_flip_buffer_push(port);
+		sport->rx_bytes = 0;
+	}
+
+	if (sport->dma_is_rxing)
+		start_rx_dma(sport);
+}
+
+static void imx_rx_dma_done(struct imx_port *sport)
+{
+	unsigned long temp;
+
+	/* Enable this interrupt when the RXFIFO is empty. */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RRDYEN;
+	writel(temp, sport->port.membase + UCR1);
+
+	sport->dma_is_rxing = 0;
+
+	/* Is the shutdown waiting for us? */
+	if (waitqueue_active(&sport->dma_wait))
+		wake_up(&sport->dma_wait);
+}
+
+/*
+ * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ *   [1] the RX DMA buffer is full.
+ *   [2] the Aging timer expires(wait for 8 bytes long)
+ *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *
+ * The [2] is trigger when a character was been sitting in the FIFO
+ * meanwhile [3] can wait for 32 bytes long when the RX line is
+ * on IDLE state and RxFIFO is empty.
+ */
+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 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 = chan->device->device_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) {
+		sport->rx_bytes = count;
+		schedule_work(&sport->tsk_dma_rx);
+	} 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) {
+		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;
+}
+
+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;
+	slave_config.src_maxburst = RXTL;
+	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) {
+		dev_err(dev, "cannot alloc DMA buffer.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	sport->rx_bytes = 0;
+
+	/* 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;
+	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;
+	struct tty_port *port = &sport->port.state->port;
+
+	port->low_latency = 1;
+	INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
+	INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
+	init_waitqueue_head(&sport->dma_wait);
+
+	/* set UCR1 */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
+		/* wait for 32 idle frames for IDDMA interrupt */
+		UCR1_ICD_REG(3);
+	writel(temp, sport->port.membase + UCR1);
+
+	/* set UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp |= UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 1;
+}
+
+static void imx_disable_dma(struct imx_port *sport)
+{
+	unsigned long temp;
+	struct tty_port *port = &sport->port.state->port;
+
+	/* 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);
+	writel(temp, sport->port.membase + UCR2);
+
+	/* clear UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp &= ~UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 0;
+	port->low_latency = 0;
+}
+
 /* half the RX buffer size */
 #define CTSTL 16
 
@@ -870,6 +1249,15 @@ static void imx_shutdown(struct uart_port *port)
 	unsigned long temp;
 	unsigned long flags;
 
+	if (sport->dma_is_enabled) {
+		/* We have to wait for the DMA to finish. */
+		wait_event(sport->dma_wait,
+			!sport->dma_is_rxing && !sport->dma_is_txing);
+		imx_stop_rx(port);
+		imx_disable_dma(sport);
+		imx_uart_dma_exit(sport);
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 	temp = readl(sport->port.membase + UCR2);
 	temp &= ~(UCR2_TXEN);
@@ -956,6 +1344,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 		if (sport->have_rtscts) {
 			ucr2 &= ~UCR2_IRTS;
 			ucr2 |= UCR2_CTSC;
+
+			/* Can we enable the DMA support? */
+			if (is_imx6q_uart(sport) && !uart_console(port)
+				&& !sport->dma_is_inited)
+				imx_uart_dma_init(sport);
 		} else {
 			termios->c_cflag &= ~CRTSCTS;
 		}
@@ -1069,6 +1462,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
 		imx_enable_ms(&sport->port);
 
+	if (sport->dma_is_inited && !sport->dma_is_enabled)
+		imx_enable_dma(sport);
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 2/6] serial: imx: add DMA support for imx6q
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

We only enable the DMA support when the following are meet:

  [1] The uart port supports the hardware flow control(CTS/RTS).
      (Some uart port does not support the CTS/RTS.)

  [2] The application enables the CTS/RTS.

  [3] The Soc is imx6q.
      For the sdma's firmware limit, we do not support the DMA except
      the imx6q platform.

  [4] The uart is not used as a console.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 drivers/tty/serial/imx.c |  405 +++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 400 insertions(+), 5 deletions(-)

diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index a9643ef..d04a09e 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -49,9 +49,11 @@
 #include <linux/of_device.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/io.h>
+#include <linux/dma-mapping.h>
 
 #include <asm/irq.h>
 #include <linux/platform_data/serial-imx.h>
+#include <linux/platform_data/dma-imx.h>
 
 /* Register definitions */
 #define URXD0 0x0  /* Receiver Register */
@@ -83,6 +85,7 @@
 #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 +94,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 */
@@ -126,6 +130,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 */
@@ -210,6 +215,19 @@ struct imx_port {
 	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		rx_bytes, tx_bytes;
+	struct work_struct	tsk_dma_rx, tsk_dma_tx;
+	unsigned int		dma_tx_nents;
+	wait_queue_head_t	dma_wait;
 };
 
 struct imx_port_ucrs {
@@ -400,6 +418,13 @@ static void imx_stop_tx(struct uart_port *port)
 		return;
 	}
 
+	/*
+	 * 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 + UCR1);
 	writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
 }
@@ -412,6 +437,13 @@ static void imx_stop_rx(struct uart_port *port)
 	struct imx_port *sport = (struct imx_port *)port;
 	unsigned long temp;
 
+	/*
+	 * 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_rxing)
+		return;
+
 	temp = readl(sport->port.membase + UCR2);
 	writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
 }
@@ -447,6 +479,95 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
 		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;
+
+	dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
+
+	sport->dma_is_txing = 0;
+
+	/* update the stat */
+	spin_lock_irqsave(&sport->port.lock, flags);
+	xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
+	sport->port.icount.tx += sport->tx_bytes;
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
+
+	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;
+	}
+
+	schedule_work(&sport->tsk_dma_tx);
+}
+
+static void dma_tx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_tx);
+	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;
+	enum dma_status status;
+	unsigned long flags;
+	int ret;
+
+	status = chan->device->device_tx_status(chan, (dma_cookie_t)0, NULL);
+	if (DMA_IN_PROGRESS == status)
+		return;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+	sport->tx_bytes = uart_circ_chars_pending(xmit);
+	if (sport->tx_bytes == 0) {
+		spin_unlock_irqrestore(&sport->port.lock, flags);
+		return;
+	}
+
+	if (xmit->tail > xmit->head) {
+		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);
+	} else {
+		sport->dma_tx_nents = 1;
+		sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+	}
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+
+	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) {
+		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));
+	/* fire it */
+	sport->dma_is_txing = 1;
+	dmaengine_submit(desc);
+	dma_async_issue_pending(chan);
+	return;
+}
+
 /*
  * interrupts disabled on entry
  */
@@ -473,8 +594,10 @@ static void imx_start_tx(struct uart_port *port)
 	temp |= UCR4_OREN;
 	writel(temp, sport->port.membase + UCR4);
 
-	temp = readl(sport->port.membase + UCR1);
-	writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	if (!sport->dma_is_enabled) {
+		temp = readl(sport->port.membase + UCR1);
+		writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+	}
 
 	if (USE_IRDA(sport)) {
 		temp = readl(sport->port.membase + UCR1);
@@ -486,6 +609,15 @@ static void imx_start_tx(struct uart_port *port)
 		writel(temp, sport->port.membase + UCR4);
 	}
 
+	if (sport->dma_is_enabled) {
+		/*
+		 * We may in the interrupt context, so arise a work_struct to
+		 * do the real job.
+		 */
+		schedule_work(&sport->tsk_dma_tx);
+		return;
+	}
+
 	if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
 		imx_transmit_buffer(sport);
 }
@@ -601,6 +733,28 @@ out:
 	return IRQ_HANDLED;
 }
 
+/*
+ * 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;
+
+	temp = readl(sport->port.membase + USR2);
+	if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
+		sport->dma_is_rxing = 1;
+
+		/* disable the `Recerver Ready Interrrupt` */
+		temp = readl(sport->port.membase + UCR1);
+		temp &= ~(UCR1_RRDYEN);
+		writel(temp, sport->port.membase + UCR1);
+
+		/* tell the DMA to receive the data. */
+		schedule_work(&sport->tsk_dma_rx);
+	}
+}
+
 static irqreturn_t imx_int(int irq, void *dev_id)
 {
 	struct imx_port *sport = dev_id;
@@ -609,8 +763,12 @@ static irqreturn_t imx_int(int irq, void *dev_id)
 
 	sts = readl(sport->port.membase + USR1);
 
-	if (sts & USR1_RRDY)
-		imx_rxint(irq, dev_id);
+	if (sts & USR1_RRDY) {
+		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)
@@ -667,7 +825,8 @@ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
 	temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
 
 	if (mctrl & TIOCM_RTS)
-		temp |= UCR2_CTS;
+		if (!sport->dma_is_enabled)
+			temp |= UCR2_CTS;
 
 	writel(temp, sport->port.membase + UCR2);
 }
@@ -706,6 +865,226 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
 	return 0;
 }
 
+#define RX_BUF_SIZE	(PAGE_SIZE)
+static int start_rx_dma(struct imx_port *sport);
+static void dma_rx_work(struct work_struct *w)
+{
+	struct imx_port *sport = container_of(w, struct imx_port, tsk_dma_rx);
+	struct tty_port *port = &sport->port.state->port;
+
+	if (sport->rx_bytes) {
+		tty_insert_flip_string(port, sport->rx_buf, sport->rx_bytes);
+		tty_flip_buffer_push(port);
+		sport->rx_bytes = 0;
+	}
+
+	if (sport->dma_is_rxing)
+		start_rx_dma(sport);
+}
+
+static void imx_rx_dma_done(struct imx_port *sport)
+{
+	unsigned long temp;
+
+	/* Enable this interrupt when the RXFIFO is empty. */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RRDYEN;
+	writel(temp, sport->port.membase + UCR1);
+
+	sport->dma_is_rxing = 0;
+
+	/* Is the shutdown waiting for us? */
+	if (waitqueue_active(&sport->dma_wait))
+		wake_up(&sport->dma_wait);
+}
+
+/*
+ * There are three kinds of RX DMA interrupts(such as in the MX6Q):
+ *   [1] the RX DMA buffer is full.
+ *   [2] the Aging timer expires(wait for 8 bytes long)
+ *   [3] the Idle Condition Detect(enabled the UCR4_IDDMAEN).
+ *
+ * The [2] is trigger when a character was been sitting in the FIFO
+ * meanwhile [3] can wait for 32 bytes long when the RX line is
+ * on IDLE state and RxFIFO is empty.
+ */
+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 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 = chan->device->device_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) {
+		sport->rx_bytes = count;
+		schedule_work(&sport->tsk_dma_rx);
+	} 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) {
+		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;
+}
+
+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;
+	slave_config.src_maxburst = RXTL;
+	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) {
+		dev_err(dev, "cannot alloc DMA buffer.\n");
+		ret = -ENOMEM;
+		goto err;
+	}
+	sport->rx_bytes = 0;
+
+	/* 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;
+	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;
+	struct tty_port *port = &sport->port.state->port;
+
+	port->low_latency = 1;
+	INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
+	INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);
+	init_waitqueue_head(&sport->dma_wait);
+
+	/* set UCR1 */
+	temp = readl(sport->port.membase + UCR1);
+	temp |= UCR1_RDMAEN | UCR1_TDMAEN | UCR1_ATDMAEN |
+		/* wait for 32 idle frames for IDDMA interrupt */
+		UCR1_ICD_REG(3);
+	writel(temp, sport->port.membase + UCR1);
+
+	/* set UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp |= UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 1;
+}
+
+static void imx_disable_dma(struct imx_port *sport)
+{
+	unsigned long temp;
+	struct tty_port *port = &sport->port.state->port;
+
+	/* 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);
+	writel(temp, sport->port.membase + UCR2);
+
+	/* clear UCR4 */
+	temp = readl(sport->port.membase + UCR4);
+	temp &= ~UCR4_IDDMAEN;
+	writel(temp, sport->port.membase + UCR4);
+
+	sport->dma_is_enabled = 0;
+	port->low_latency = 0;
+}
+
 /* half the RX buffer size */
 #define CTSTL 16
 
@@ -870,6 +1249,15 @@ static void imx_shutdown(struct uart_port *port)
 	unsigned long temp;
 	unsigned long flags;
 
+	if (sport->dma_is_enabled) {
+		/* We have to wait for the DMA to finish. */
+		wait_event(sport->dma_wait,
+			!sport->dma_is_rxing && !sport->dma_is_txing);
+		imx_stop_rx(port);
+		imx_disable_dma(sport);
+		imx_uart_dma_exit(sport);
+	}
+
 	spin_lock_irqsave(&sport->port.lock, flags);
 	temp = readl(sport->port.membase + UCR2);
 	temp &= ~(UCR2_TXEN);
@@ -956,6 +1344,11 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 		if (sport->have_rtscts) {
 			ucr2 &= ~UCR2_IRTS;
 			ucr2 |= UCR2_CTSC;
+
+			/* Can we enable the DMA support? */
+			if (is_imx6q_uart(sport) && !uart_console(port)
+				&& !sport->dma_is_inited)
+				imx_uart_dma_init(sport);
 		} else {
 			termios->c_cflag &= ~CRTSCTS;
 		}
@@ -1069,6 +1462,8 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
 		imx_enable_ms(&sport->port);
 
+	if (sport->dma_is_inited && !sport->dma_is_enabled)
+		imx_enable_dma(sport);
 	spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 3/6] ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

In order to enable the DMA for some uart port in imx6sl, we add the
"fsl,imx6q-uart" to the uart's compatible property.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6sl.dtsi |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 9138c67..0a297af 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -152,7 +152,8 @@
 				};
 
 				uart5: serial@02018000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02018000 0x4000>;
 					interrupts = <0 30 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -162,7 +163,8 @@
 				};
 
 				uart1: serial@02020000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02020000 0x4000>;
 					interrupts = <0 26 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -172,7 +174,8 @@
 				};
 
 				uart2: serial@02024000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02024000 0x4000>;
 					interrupts = <0 27 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -209,7 +212,8 @@
 				};
 
 				uart3: serial@02034000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02034000 0x4000>;
 					interrupts = <0 28 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -219,7 +223,8 @@
 				};
 
 				uart4: serial@02038000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02038000 0x4000>;
 					interrupts = <0 29 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 3/6] ARM: dts: imx6sl: add "fsl, imx6q-uart" for uart compatible
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

In order to enable the DMA for some uart port in imx6sl, we add the
"fsl,imx6q-uart" to the uart's compatible property.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6sl.dtsi |   15 ++++++++++-----
 1 files changed, 10 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index 9138c67..0a297af 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -152,7 +152,8 @@
 				};
 
 				uart5: serial at 02018000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02018000 0x4000>;
 					interrupts = <0 30 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -162,7 +163,8 @@
 				};
 
 				uart1: serial at 02020000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02020000 0x4000>;
 					interrupts = <0 26 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -172,7 +174,8 @@
 				};
 
 				uart2: serial at 02024000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02024000 0x4000>;
 					interrupts = <0 27 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -209,7 +212,8 @@
 				};
 
 				uart3: serial at 02034000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02034000 0x4000>;
 					interrupts = <0 28 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
@@ -219,7 +223,8 @@
 				};
 
 				uart4: serial at 02038000 {
-					compatible = "fsl,imx6sl-uart", "fsl,imx21-uart";
+					compatible = "fsl,imx6sl-uart",
+						   "fsl,imx6q-uart", "fsl,imx21-uart";
 					reg = <0x02038000 0x4000>;
 					interrupts = <0 29 0x04>;
 					clocks = <&clks IMX6SL_CLK_UART>,
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 4/6] ARM: dts: imx6q{dl}: add DTE pads for uart
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

The uart2 in the imx6q-arm2 board is used as a DTE uart,
this patch adds the necessary DTE pads for uart2.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6dl-pinfunc.h |    4 ++++
 arch/arm/boot/dts/imx6q-pinfunc.h  |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl-pinfunc.h b/arch/arm/boot/dts/imx6dl-pinfunc.h
index 9aab950..dc44d0a 100644
--- a/arch/arm/boot/dts/imx6dl-pinfunc.h
+++ b/arch/arm/boot/dts/imx6dl-pinfunc.h
@@ -461,6 +461,8 @@
 #define MX6DL_PAD_EIM_D28__IPU1_CSI1_DATA12        0x174 0x544 0x890 0x3 0x1
 #define MX6DL_PAD_EIM_D28__UART2_CTS_B             0x174 0x544 0x000 0x4 0x0
 #define MX6DL_PAD_EIM_D28__UART2_RTS_B             0x174 0x544 0x900 0x4 0x0
+#define MX6DL_PAD_EIM_D28__UART2_DTE_CTS_B         0x174 0x544 0x900 0x4 0x0
+#define MX6DL_PAD_EIM_D28__UART2_DTE_RTS_B         0x174 0x544 0x000 0x4 0x0
 #define MX6DL_PAD_EIM_D28__GPIO3_IO28              0x174 0x544 0x000 0x5 0x0
 #define MX6DL_PAD_EIM_D28__IPU1_EXT_TRIG           0x174 0x544 0x000 0x6 0x0
 #define MX6DL_PAD_EIM_D28__IPU1_DI0_PIN13          0x174 0x544 0x000 0x7 0x0
@@ -470,6 +472,8 @@
 #define MX6DL_PAD_EIM_D29__ECSPI4_SS0              0x178 0x548 0x808 0x2 0x1
 #define MX6DL_PAD_EIM_D29__UART2_RTS_B             0x178 0x548 0x900 0x4 0x1
 #define MX6DL_PAD_EIM_D29__UART2_CTS_B             0x178 0x548 0x000 0x4 0x0
+#define MX6DL_PAD_EIM_D29__UART2_DTE_RTS_B         0x178 0x548 0x000 0x4 0x0
+#define MX6DL_PAD_EIM_D29__UART2_DTE_CTS_B         0x178 0x548 0x900 0x4 0x1
 #define MX6DL_PAD_EIM_D29__GPIO3_IO29              0x178 0x548 0x000 0x5 0x0
 #define MX6DL_PAD_EIM_D29__IPU1_CSI1_VSYNC         0x178 0x548 0x8bc 0x6 0x0
 #define MX6DL_PAD_EIM_D29__IPU1_DI0_PIN14          0x178 0x548 0x000 0x7 0x0
diff --git a/arch/arm/boot/dts/imx6q-pinfunc.h b/arch/arm/boot/dts/imx6q-pinfunc.h
index faea6e1..01365f7 100644
--- a/arch/arm/boot/dts/imx6q-pinfunc.h
+++ b/arch/arm/boot/dts/imx6q-pinfunc.h
@@ -197,6 +197,8 @@
 #define MX6Q_PAD_EIM_D28__IPU2_CSI1_DATA12        0x0c4 0x3d8 0x8b8 0x3 0x0
 #define MX6Q_PAD_EIM_D28__UART2_CTS_B             0x0c4 0x3d8 0x000 0x4 0x0
 #define MX6Q_PAD_EIM_D28__UART2_RTS_B             0x0c4 0x3d8 0x924 0x4 0x0
+#define MX6Q_PAD_EIM_D28__UART2_DTE_CTS_B         0x0c4 0x3d8 0x924 0x4 0x0
+#define MX6Q_PAD_EIM_D28__UART2_DTE_RTS_B         0x0c4 0x3d8 0x000 0x4 0x0
 #define MX6Q_PAD_EIM_D28__GPIO3_IO28              0x0c4 0x3d8 0x000 0x5 0x0
 #define MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG           0x0c4 0x3d8 0x000 0x6 0x0
 #define MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13          0x0c4 0x3d8 0x000 0x7 0x0
@@ -205,6 +207,8 @@
 #define MX6Q_PAD_EIM_D29__ECSPI4_SS0              0x0c8 0x3dc 0x824 0x2 0x1
 #define MX6Q_PAD_EIM_D29__UART2_RTS_B             0x0c8 0x3dc 0x924 0x4 0x1
 #define MX6Q_PAD_EIM_D29__UART2_CTS_B             0x0c8 0x3dc 0x000 0x4 0x0
+#define MX6Q_PAD_EIM_D29__UART2_DTE_RTS_B         0x0c4 0x3dc 0x000 0x4 0x0
+#define MX6Q_PAD_EIM_D29__UART2_DTE_CTS_B         0x0c4 0x3dc 0x924 0x4 0x1
 #define MX6Q_PAD_EIM_D29__GPIO3_IO29              0x0c8 0x3dc 0x000 0x5 0x0
 #define MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC         0x0c8 0x3dc 0x8e4 0x6 0x0
 #define MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14          0x0c8 0x3dc 0x000 0x7 0x0
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 4/6] ARM: dts: imx6q{dl}: add DTE pads for uart
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

The uart2 in the imx6q-arm2 board is used as a DTE uart,
this patch adds the necessary DTE pads for uart2.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6dl-pinfunc.h |    4 ++++
 arch/arm/boot/dts/imx6q-pinfunc.h  |    4 ++++
 2 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl-pinfunc.h b/arch/arm/boot/dts/imx6dl-pinfunc.h
index 9aab950..dc44d0a 100644
--- a/arch/arm/boot/dts/imx6dl-pinfunc.h
+++ b/arch/arm/boot/dts/imx6dl-pinfunc.h
@@ -461,6 +461,8 @@
 #define MX6DL_PAD_EIM_D28__IPU1_CSI1_DATA12        0x174 0x544 0x890 0x3 0x1
 #define MX6DL_PAD_EIM_D28__UART2_CTS_B             0x174 0x544 0x000 0x4 0x0
 #define MX6DL_PAD_EIM_D28__UART2_RTS_B             0x174 0x544 0x900 0x4 0x0
+#define MX6DL_PAD_EIM_D28__UART2_DTE_CTS_B         0x174 0x544 0x900 0x4 0x0
+#define MX6DL_PAD_EIM_D28__UART2_DTE_RTS_B         0x174 0x544 0x000 0x4 0x0
 #define MX6DL_PAD_EIM_D28__GPIO3_IO28              0x174 0x544 0x000 0x5 0x0
 #define MX6DL_PAD_EIM_D28__IPU1_EXT_TRIG           0x174 0x544 0x000 0x6 0x0
 #define MX6DL_PAD_EIM_D28__IPU1_DI0_PIN13          0x174 0x544 0x000 0x7 0x0
@@ -470,6 +472,8 @@
 #define MX6DL_PAD_EIM_D29__ECSPI4_SS0              0x178 0x548 0x808 0x2 0x1
 #define MX6DL_PAD_EIM_D29__UART2_RTS_B             0x178 0x548 0x900 0x4 0x1
 #define MX6DL_PAD_EIM_D29__UART2_CTS_B             0x178 0x548 0x000 0x4 0x0
+#define MX6DL_PAD_EIM_D29__UART2_DTE_RTS_B         0x178 0x548 0x000 0x4 0x0
+#define MX6DL_PAD_EIM_D29__UART2_DTE_CTS_B         0x178 0x548 0x900 0x4 0x1
 #define MX6DL_PAD_EIM_D29__GPIO3_IO29              0x178 0x548 0x000 0x5 0x0
 #define MX6DL_PAD_EIM_D29__IPU1_CSI1_VSYNC         0x178 0x548 0x8bc 0x6 0x0
 #define MX6DL_PAD_EIM_D29__IPU1_DI0_PIN14          0x178 0x548 0x000 0x7 0x0
diff --git a/arch/arm/boot/dts/imx6q-pinfunc.h b/arch/arm/boot/dts/imx6q-pinfunc.h
index faea6e1..01365f7 100644
--- a/arch/arm/boot/dts/imx6q-pinfunc.h
+++ b/arch/arm/boot/dts/imx6q-pinfunc.h
@@ -197,6 +197,8 @@
 #define MX6Q_PAD_EIM_D28__IPU2_CSI1_DATA12        0x0c4 0x3d8 0x8b8 0x3 0x0
 #define MX6Q_PAD_EIM_D28__UART2_CTS_B             0x0c4 0x3d8 0x000 0x4 0x0
 #define MX6Q_PAD_EIM_D28__UART2_RTS_B             0x0c4 0x3d8 0x924 0x4 0x0
+#define MX6Q_PAD_EIM_D28__UART2_DTE_CTS_B         0x0c4 0x3d8 0x924 0x4 0x0
+#define MX6Q_PAD_EIM_D28__UART2_DTE_RTS_B         0x0c4 0x3d8 0x000 0x4 0x0
 #define MX6Q_PAD_EIM_D28__GPIO3_IO28              0x0c4 0x3d8 0x000 0x5 0x0
 #define MX6Q_PAD_EIM_D28__IPU1_EXT_TRIG           0x0c4 0x3d8 0x000 0x6 0x0
 #define MX6Q_PAD_EIM_D28__IPU1_DI0_PIN13          0x0c4 0x3d8 0x000 0x7 0x0
@@ -205,6 +207,8 @@
 #define MX6Q_PAD_EIM_D29__ECSPI4_SS0              0x0c8 0x3dc 0x824 0x2 0x1
 #define MX6Q_PAD_EIM_D29__UART2_RTS_B             0x0c8 0x3dc 0x924 0x4 0x1
 #define MX6Q_PAD_EIM_D29__UART2_CTS_B             0x0c8 0x3dc 0x000 0x4 0x0
+#define MX6Q_PAD_EIM_D29__UART2_DTE_RTS_B         0x0c4 0x3dc 0x000 0x4 0x0
+#define MX6Q_PAD_EIM_D29__UART2_DTE_CTS_B         0x0c4 0x3dc 0x924 0x4 0x1
 #define MX6Q_PAD_EIM_D29__GPIO3_IO29              0x0c8 0x3dc 0x000 0x5 0x0
 #define MX6Q_PAD_EIM_D29__IPU2_CSI1_VSYNC         0x0c8 0x3dc 0x8e4 0x6 0x0
 #define MX6Q_PAD_EIM_D29__IPU1_DI0_PIN14          0x0c8 0x3dc 0x000 0x7 0x0
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 5/6] ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

In the arm2 board, the UART2 works in the dte mode.
So add a pinctrl for both the imx6q{dl} boards.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6dl.dtsi |    9 +++++++++
 arch/arm/boot/dts/imx6q.dtsi  |    9 +++++++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 2b5628d..a1302ed 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -223,6 +223,15 @@
 							MX6DL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
 						>;
 					};
+
+					pinctrl_uart2_2: uart2grp-2 { /* DTE mode */
+						fsl,pins = <
+							MX6DL_PAD_EIM_D26__UART2_RX_DATA   0x1b0b1
+							MX6DL_PAD_EIM_D27__UART2_TX_DATA   0x1b0b1
+							MX6DL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1
+							MX6DL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1
+						>;
+					};
 				};
 
 				uart4 {
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 6f4d6ab..e0b7bad 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -266,6 +266,15 @@
 							MX6Q_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
 						>;
 					};
+
+					pinctrl_uart2_2: uart2grp-2 { /* DTE mode */
+						fsl,pins = <
+							MX6Q_PAD_EIM_D26__UART2_RX_DATA   0x1b0b1
+							MX6Q_PAD_EIM_D27__UART2_TX_DATA   0x1b0b1
+							MX6Q_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1
+							MX6Q_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1
+						>;
+					};
 				};
 
 				uart4 {
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 5/6] ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

In the arm2 board, the UART2 works in the dte mode.
So add a pinctrl for both the imx6q{dl} boards.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6dl.dtsi |    9 +++++++++
 arch/arm/boot/dts/imx6q.dtsi  |    9 +++++++++
 2 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index 2b5628d..a1302ed 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -223,6 +223,15 @@
 							MX6DL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
 						>;
 					};
+
+					pinctrl_uart2_2: uart2grp-2 { /* DTE mode */
+						fsl,pins = <
+							MX6DL_PAD_EIM_D26__UART2_RX_DATA   0x1b0b1
+							MX6DL_PAD_EIM_D27__UART2_TX_DATA   0x1b0b1
+							MX6DL_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1
+							MX6DL_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1
+						>;
+					};
 				};
 
 				uart4 {
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index 6f4d6ab..e0b7bad 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -266,6 +266,15 @@
 							MX6Q_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
 						>;
 					};
+
+					pinctrl_uart2_2: uart2grp-2 { /* DTE mode */
+						fsl,pins = <
+							MX6Q_PAD_EIM_D26__UART2_RX_DATA   0x1b0b1
+							MX6Q_PAD_EIM_D27__UART2_TX_DATA   0x1b0b1
+							MX6Q_PAD_EIM_D28__UART2_DTE_CTS_B 0x1b0b1
+							MX6Q_PAD_EIM_D29__UART2_DTE_RTS_B 0x1b0b1
+						>;
+					};
 				};
 
 				uart4 {
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 6/6] ARM: dts: enable the uart2 for imx6q-arm2
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-08  9:14   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: gregkh; +Cc: linux-serial, shawn.guo, linux-arm-kernel, Huang Shijie

enable the uart2 for imx6q-arm2 board.
The uart2 works in the DTE mode, with the RTS/CTS and DMA enabled.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6q-arm2.dts |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts
index 4e54fde..e7e3b56 100644
--- a/arch/arm/boot/dts/imx6q-arm2.dts
+++ b/arch/arm/boot/dts/imx6q-arm2.dts
@@ -97,6 +97,16 @@
 	status = "okay";
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2_2>;
+	fsl,dte-mode;
+	fsl,uart-has-rtscts;
+	dma-names = "rx", "tx";
+	dmas = <&sdma 27 4 0>, <&sdma 28 4 0>;
+	status = "okay";
+};
+
 &uart4 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart4_1>;
-- 
1.7.1



^ permalink raw reply related	[flat|nested] 18+ messages in thread

* [PATCH v4 6/6] ARM: dts: enable the uart2 for imx6q-arm2
@ 2013-07-08  9:14   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-08  9:14 UTC (permalink / raw)
  To: linux-arm-kernel

enable the uart2 for imx6q-arm2 board.
The uart2 works in the DTE mode, with the RTS/CTS and DMA enabled.

Signed-off-by: Huang Shijie <b32955@freescale.com>
---
 arch/arm/boot/dts/imx6q-arm2.dts |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/arm/boot/dts/imx6q-arm2.dts b/arch/arm/boot/dts/imx6q-arm2.dts
index 4e54fde..e7e3b56 100644
--- a/arch/arm/boot/dts/imx6q-arm2.dts
+++ b/arch/arm/boot/dts/imx6q-arm2.dts
@@ -97,6 +97,16 @@
 	status = "okay";
 };
 
+&uart2 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_uart2_2>;
+	fsl,dte-mode;
+	fsl,uart-has-rtscts;
+	dma-names = "rx", "tx";
+	dmas = <&sdma 27 4 0>, <&sdma 28 4 0>;
+	status = "okay";
+};
+
 &uart4 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart4_1>;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 18+ messages in thread

* Re: [PATCH v4 0/6] serial: imx: add DMA support for imx6
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-09  6:12   ` Shawn Guo
  -1 siblings, 0 replies; 18+ messages in thread
From: Shawn Guo @ 2013-07-09  6:12 UTC (permalink / raw)
  To: Huang Shijie; +Cc: gregkh, linux-serial, linux-arm-kernel

On Mon, Jul 08, 2013 at 05:14:16PM +0800, Huang Shijie wrote:
>   ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible
>   ARM: dts: imx6q{dl}: add DTE pads for uart
>   ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
>   ARM: dts: enable the uart2 for imx6q-arm2

Applied these 4, thanks.


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4 0/6] serial: imx: add DMA support for imx6
@ 2013-07-09  6:12   ` Shawn Guo
  0 siblings, 0 replies; 18+ messages in thread
From: Shawn Guo @ 2013-07-09  6:12 UTC (permalink / raw)
  To: linux-arm-kernel

On Mon, Jul 08, 2013 at 05:14:16PM +0800, Huang Shijie wrote:
>   ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible
>   ARM: dts: imx6q{dl}: add DTE pads for uart
>   ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2
>   ARM: dts: enable the uart2 for imx6q-arm2

Applied these 4, thanks.

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v4 0/6] serial: imx: add DMA support for imx6
  2013-07-08  9:14 ` Huang Shijie
@ 2013-07-17  7:30   ` Huang Shijie
  -1 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-17  7:30 UTC (permalink / raw)
  To: Huang Shijie; +Cc: gregkh, linux-serial, shawn.guo, linux-arm-kernel

于 2013年07月08日 17:14, Huang Shijie 写道:
> (1) This patch set adds the DMA support for the imx serial driver.
>     The uart with the dma support is usually used by the Bluetooth.
>
>     For the firmware's limit, i only enable the DMA for imx6 serials.
>     If we have proper firmware for imx53 (or other chips), we can also
>     enable the DMA for it.
>
> (2) We only enable the DMA support when the following are meet:
>
>     [1] The uart port supports the hardware flow control(CTS/RTS).
>       (Some uart port does not support the CTS/RTS.)
>
>     [2] The application enables the CTS/RTS.
>
>     [3] The Soc is imx6 serials.
>       For the sdma's firmware limit, we do not support the DMA except
>       the imx6 platform.
>
>     [4] The uart is not used as a console.
>
>
> (3) Tested this patch set by:
> 	connecting a imx6q-arm2 board(DTE) with a imx53 board(DCE).
>
> v3 --> v4:
> 	[0] add DTE pad for uart2
>
> v2 --> v3:
> 	[0] add a new patch to fix the RTS/CTS pad name issue.
> 	[1] rename the uart DTE pinctrl, remove the "dte" from the pinctrl.
> 	[2] add a similar UART DTE pinctrl for IMX6DL.
> 	[3] move the "fsl,imx6q-uart" to the first of the compatible table.
>
> v1 --> v2:
> 	[0] use the "fsl,imx6q-uart" as the new compatible value.
> 	[1] move dma_is_inited to imx_uart_dma_init();
> 	    move dma_is_enabled to imx_enable_dma();
> 	[2] move imx_disable_dma() to the front place of the imx_shutdown(),
> 	    just before calls the imx_uart_dma_exit().
> 	[3] misc    
> 	
>
> Huang Shijie (6):
>   serial: imx: distinguish the imx6q uart from the others
>   serial: imx: add DMA support for imx6q 
Hi Greg:
Could you merge the two patches as above?


thanks
Huang Shijie

--
To unsubscribe from this list: send the line "unsubscribe linux-serial" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v4 0/6] serial: imx: add DMA support for imx6
@ 2013-07-17  7:30   ` Huang Shijie
  0 siblings, 0 replies; 18+ messages in thread
From: Huang Shijie @ 2013-07-17  7:30 UTC (permalink / raw)
  To: linux-arm-kernel

? 2013?07?08? 17:14, Huang Shijie ??:
> (1) This patch set adds the DMA support for the imx serial driver.
>     The uart with the dma support is usually used by the Bluetooth.
>
>     For the firmware's limit, i only enable the DMA for imx6 serials.
>     If we have proper firmware for imx53 (or other chips), we can also
>     enable the DMA for it.
>
> (2) We only enable the DMA support when the following are meet:
>
>     [1] The uart port supports the hardware flow control(CTS/RTS).
>       (Some uart port does not support the CTS/RTS.)
>
>     [2] The application enables the CTS/RTS.
>
>     [3] The Soc is imx6 serials.
>       For the sdma's firmware limit, we do not support the DMA except
>       the imx6 platform.
>
>     [4] The uart is not used as a console.
>
>
> (3) Tested this patch set by:
> 	connecting a imx6q-arm2 board(DTE) with a imx53 board(DCE).
>
> v3 --> v4:
> 	[0] add DTE pad for uart2
>
> v2 --> v3:
> 	[0] add a new patch to fix the RTS/CTS pad name issue.
> 	[1] rename the uart DTE pinctrl, remove the "dte" from the pinctrl.
> 	[2] add a similar UART DTE pinctrl for IMX6DL.
> 	[3] move the "fsl,imx6q-uart" to the first of the compatible table.
>
> v1 --> v2:
> 	[0] use the "fsl,imx6q-uart" as the new compatible value.
> 	[1] move dma_is_inited to imx_uart_dma_init();
> 	    move dma_is_enabled to imx_enable_dma();
> 	[2] move imx_disable_dma() to the front place of the imx_shutdown(),
> 	    just before calls the imx_uart_dma_exit().
> 	[3] misc    
> 	
>
> Huang Shijie (6):
>   serial: imx: distinguish the imx6q uart from the others
>   serial: imx: add DMA support for imx6q 
Hi Greg:
Could you merge the two patches as above?


thanks
Huang Shijie

^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2013-07-17  7:30 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-08  9:14 [PATCH v4 0/6] serial: imx: add DMA support for imx6 Huang Shijie
2013-07-08  9:14 ` Huang Shijie
2013-07-08  9:14 ` [PATCH v4 1/6] serial: imx: distinguish the imx6q uart from the others Huang Shijie
2013-07-08  9:14   ` Huang Shijie
2013-07-08  9:14 ` [PATCH v4 2/6] serial: imx: add DMA support for imx6q Huang Shijie
2013-07-08  9:14   ` Huang Shijie
2013-07-08  9:14 ` [PATCH v4 3/6] ARM: dts: imx6sl: add "fsl,imx6q-uart" for uart compatible Huang Shijie
2013-07-08  9:14   ` [PATCH v4 3/6] ARM: dts: imx6sl: add "fsl, imx6q-uart" " Huang Shijie
2013-07-08  9:14 ` [PATCH v4 4/6] ARM: dts: imx6q{dl}: add DTE pads for uart Huang Shijie
2013-07-08  9:14   ` Huang Shijie
2013-07-08  9:14 ` [PATCH v4 5/6] ARM: dts: imx6q{dl}: add a DTE uart pinctrl for uart2 Huang Shijie
2013-07-08  9:14   ` Huang Shijie
2013-07-08  9:14 ` [PATCH v4 6/6] ARM: dts: enable the uart2 for imx6q-arm2 Huang Shijie
2013-07-08  9:14   ` Huang Shijie
2013-07-09  6:12 ` [PATCH v4 0/6] serial: imx: add DMA support for imx6 Shawn Guo
2013-07-09  6:12   ` Shawn Guo
2013-07-17  7:30 ` Huang Shijie
2013-07-17  7:30   ` Huang Shijie

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.