linux-serial.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
@ 2014-01-22  4:09 Yuan Yao
  2014-01-22  4:09 ` [PATCH v4 1/3] ARM: dts: vf610: lpuart: Add eDMA support Yuan Yao
                   ` (3 more replies)
  0 siblings, 4 replies; 11+ messages in thread
From: Yuan Yao @ 2014-01-22  4:09 UTC (permalink / raw)
  To: gregkh, shawn.guo
  Cc: linux, arnd, mark.rutland, linux-arm-kernel, linux-serial

Changed in v4:
- Move dma properties from dtsi to dts.
- Cancle the macro(SERIAL_FSL_LPUART_DMA)  .
- Separate the document for clocks which undocumented before into a single patch.
- Change some explanations in document(clocks, clock-names, dmas, dma-names).
- Change "lpuart-tx" and "lpuart-rx" to "tx" and "rx".

Changed in v3:
- Use the streaming DMA API for receive.
- Add the macro(SERIAL_FSL_LPUART_DMA) and dts node propertie for whether using the dma.
- Adjust some coding style.
 
Changed in v2:
- Add eDMA support for lpuart receive.
- Use dma_mapping_error test dma_map_single.
- Change some names of variable.
- Fix some bugs.
 
Added in v1:
- Add device tree bindings for lupart eDMA support.
- Add eDMA support for lpuart send.



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

* [PATCH v4 1/3] ARM: dts: vf610: lpuart: Add eDMA support
  2014-01-22  4:09 [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Yuan Yao
@ 2014-01-22  4:09 ` Yuan Yao
  2014-01-22  4:09 ` [PATCH v4 2/3] serial: fsl_lpuart: add DMA support Yuan Yao
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 11+ messages in thread
From: Yuan Yao @ 2014-01-22  4:09 UTC (permalink / raw)
  To: gregkh, shawn.guo
  Cc: linux, arnd, mark.rutland, linux-arm-kernel, linux-serial

Add lpuart dts node properties for eDMA support, them depend on the eDMA driver.

Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
 arch/arm/boot/dts/vf610-twr.dts | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index 80db14e..4149ed6 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -101,5 +101,8 @@
 &uart1 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&pinctrl_uart1>;
+	dmas = <&edma0 0 4>,
+		<&edma0 0 5>;
+	dma-names = "rx","tx";
 	status = "okay";
 };
-- 
1.8.4



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

* [PATCH v4 2/3] serial: fsl_lpuart: add DMA support
  2014-01-22  4:09 [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Yuan Yao
  2014-01-22  4:09 ` [PATCH v4 1/3] ARM: dts: vf610: lpuart: Add eDMA support Yuan Yao
@ 2014-01-22  4:09 ` Yuan Yao
  2014-01-24 11:31   ` Mark Rutland
  2014-01-22  4:09 ` [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement Yuan Yao
  2014-01-27  7:50 ` [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Shawn Guo
  3 siblings, 1 reply; 11+ messages in thread
From: Yuan Yao @ 2014-01-22  4:09 UTC (permalink / raw)
  To: gregkh, shawn.guo
  Cc: linux, arnd, mark.rutland, linux-arm-kernel, linux-serial

Add dma support for lpuart. This function depend on DMA driver.
You can turn on it by write both the dmas and dma-name properties in dts node.

Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
 .../devicetree/bindings/serial/fsl-lpuart.txt      |  19 +-
 drivers/tty/serial/fsl_lpuart.c                    | 430 ++++++++++++++++++++-
 2 files changed, 433 insertions(+), 16 deletions(-)

diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6fd1dd1..6e1cbbf 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -5,10 +5,21 @@ Required properties:
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
 
+Optional properties:
+- dmas: Generic dma devicetree binding as described
+	in Documentation/devicetree/bindings/dma/dma.txt.
+- dma-names: Two dmas have to be defined, "rx" and "tx".
+	An ordered list of channel names affiliated to the above.
+
+Note: Optional properties for DMA support. Write them both or both not.
+
 Example:
 
 uart0: serial@40027000 {
-	       compatible = "fsl,vf610-lpuart";
-	       reg = <0x40027000 0x1000>;
-	       interrupts = <0 61 0x00>;
-       };
+		compatible = "fsl,vf610-lpuart";
+		reg = <0x40027000 0x1000>;
+		interrupts = <0 61 0x00>;
+		dmas = <&edma0 0 2>,
+			<&edma0 0 3>;
+		dma-names = "rx","tx";
+	};
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 8978dc9..c5eb897 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -13,14 +13,19 @@
 #define SUPPORT_SYSRQ
 #endif
 
-#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
 #include <linux/io.h>
 #include <linux/irq.h>
-#include <linux/clk.h>
+#include <linux/module.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
-#include <linux/console.h>
+#include <linux/of_dma.h>
 #include <linux/serial_core.h>
+#include <linux/slab.h>
 #include <linux/tty_flip.h>
 
 /* All registers are 8-bit width */
@@ -112,6 +117,10 @@
 #define UARTSFIFO_TXOF		0x02
 #define UARTSFIFO_RXUF		0x01
 
+#define DMA_MAXBURST		16
+#define DMA_MAXBURST_MASK	(DMA_MAXBURST - 1)
+#define FSL_UART_RX_DMA_BUFFER_SIZE	64
+
 #define DRIVER_NAME	"fsl-lpuart"
 #define DEV_NAME	"ttyLP"
 #define UART_NR		6
@@ -121,6 +130,24 @@ struct lpuart_port {
 	struct clk		*clk;
 	unsigned int		txfifo_size;
 	unsigned int		rxfifo_size;
+
+	bool			lpuart_dma_use;
+	struct dma_chan		*dma_tx_chan;
+	struct dma_chan		*dma_rx_chan;
+	struct dma_async_tx_descriptor  *dma_tx_desc;
+	struct dma_async_tx_descriptor  *dma_rx_desc;
+	dma_addr_t		dma_tx_buf_bus;
+	dma_addr_t		dma_rx_buf_bus;
+	dma_cookie_t		dma_tx_cookie;
+	dma_cookie_t		dma_rx_cookie;
+	unsigned char		*dma_tx_buf_virt;
+	unsigned char		*dma_rx_buf_virt;
+	unsigned int		dma_tx_bytes;
+	unsigned int		dma_rx_bytes;
+	int			dma_tx_in_progress;
+	int			dma_rx_in_progress;
+	unsigned int		dma_rx_timeout;
+	struct timer_list	lpuart_timer;
 };
 
 static struct of_device_id lpuart_dt_ids[] = {
@@ -131,6 +158,10 @@ static struct of_device_id lpuart_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, lpuart_dt_ids);
 
+/* Forward declare this for the dma callbacks*/
+static void lpuart_dma_tx_complete(void *arg);
+static void lpuart_dma_rx_complete(void *arg);
+
 static void lpuart_stop_tx(struct uart_port *port)
 {
 	unsigned char temp;
@@ -152,6 +183,210 @@ static void lpuart_enable_ms(struct uart_port *port)
 {
 }
 
+static void lpuart_copy_rx_to_tty(struct lpuart_port *sport,
+		struct tty_port *tty, int count)
+{
+	int copied;
+
+	sport->port.icount.rx += count;
+
+	if (!tty) {
+		dev_err(sport->port.dev, "No tty port\n");
+		return;
+	}
+
+	dma_sync_single_for_cpu(sport->port.dev, sport->dma_rx_buf_bus,
+			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+	copied = tty_insert_flip_string(tty,
+			((unsigned char *)(sport->dma_rx_buf_virt)), count);
+
+	if (copied != count) {
+		WARN_ON(1);
+		dev_err(sport->port.dev, "RxData copy to tty layer failed\n");
+	}
+
+	dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+}
+
+static void lpuart_pio_tx(struct lpuart_port *sport)
+{
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	unsigned long flags;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	while (!uart_circ_empty(xmit) &&
+		readb(sport->port.membase + UARTTCFIFO) < sport->txfifo_size) {
+		writeb(xmit->buf[xmit->tail], sport->port.membase + UARTDR);
+		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+		sport->port.icount.tx++;
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&sport->port);
+
+	if (uart_circ_empty(xmit))
+		writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+			sport->port.membase + UARTCR5);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_tx(struct lpuart_port *sport, unsigned long count)
+{
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	dma_addr_t tx_bus_addr;
+
+	dma_sync_single_for_device(sport->port.dev, sport->dma_tx_buf_bus,
+				UART_XMIT_SIZE, DMA_TO_DEVICE);
+	sport->dma_tx_bytes = count & ~(DMA_MAXBURST_MASK);
+	tx_bus_addr = sport->dma_tx_buf_bus + xmit->tail;
+	sport->dma_tx_desc = dmaengine_prep_slave_single(sport->dma_tx_chan,
+					tx_bus_addr, sport->dma_tx_bytes,
+					DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+
+	if (!sport->dma_tx_desc) {
+		dev_err(sport->port.dev, "Not able to get desc for tx\n");
+		return -EIO;
+	}
+
+	sport->dma_tx_desc->callback = lpuart_dma_tx_complete;
+	sport->dma_tx_desc->callback_param = sport;
+	sport->dma_tx_in_progress = 1;
+	sport->dma_tx_cookie = dmaengine_submit(sport->dma_tx_desc);
+	dma_async_issue_pending(sport->dma_tx_chan);
+
+	return 0;
+}
+
+static void lpuart_prepare_tx(struct lpuart_port *sport)
+{
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	unsigned long count =  CIRC_CNT_TO_END(xmit->head,
+					xmit->tail, UART_XMIT_SIZE);
+
+	if (!count)
+		return;
+
+	if (count < DMA_MAXBURST)
+		writeb(readb(sport->port.membase + UARTCR5) & ~UARTCR5_TDMAS,
+				sport->port.membase + UARTCR5);
+	else {
+		writeb(readb(sport->port.membase + UARTCR5) | UARTCR5_TDMAS,
+				sport->port.membase + UARTCR5);
+		lpuart_dma_tx(sport, count);
+	}
+}
+
+static void lpuart_dma_tx_complete(void *arg)
+{
+	struct lpuart_port *sport = arg;
+	struct circ_buf *xmit = &sport->port.state->xmit;
+	unsigned long flags;
+
+	async_tx_ack(sport->dma_tx_desc);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	xmit->tail = (xmit->tail + sport->dma_tx_bytes) & (UART_XMIT_SIZE - 1);
+	sport->dma_tx_in_progress = 0;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(&sport->port);
+
+	lpuart_prepare_tx(sport);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static int lpuart_dma_rx(struct lpuart_port *sport)
+{
+	dma_sync_single_for_device(sport->port.dev, sport->dma_rx_buf_bus,
+			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_TO_DEVICE);
+	sport->dma_rx_desc = dmaengine_prep_slave_single(sport->dma_rx_chan,
+			sport->dma_rx_buf_bus, FSL_UART_RX_DMA_BUFFER_SIZE,
+			DMA_DEV_TO_MEM, DMA_PREP_INTERRUPT);
+
+	if (!sport->dma_rx_desc) {
+		dev_err(sport->port.dev, "Not able to get desc for rx\n");
+		return -EIO;
+	}
+
+	sport->dma_rx_desc->callback = lpuart_dma_rx_complete;
+	sport->dma_rx_desc->callback_param = sport;
+	sport->dma_rx_in_progress = 1;
+	sport->dma_rx_cookie = dmaengine_submit(sport->dma_rx_desc);
+	dma_async_issue_pending(sport->dma_rx_chan);
+
+	return 0;
+}
+
+static void lpuart_dma_rx_complete(void *arg)
+{
+	struct lpuart_port *sport = arg;
+	struct tty_port *port = &sport->port.state->port;
+	unsigned long flags;
+
+	async_tx_ack(sport->dma_rx_desc);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	sport->dma_rx_in_progress = 0;
+	lpuart_copy_rx_to_tty(sport, port, FSL_UART_RX_DMA_BUFFER_SIZE);
+	tty_flip_buffer_push(port);
+	lpuart_dma_rx(sport);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static void lpuart_timer_func(unsigned long data)
+{
+	struct lpuart_port *sport = (struct lpuart_port *)data;
+	struct tty_port *port = &sport->port.state->port;
+	struct dma_tx_state state;
+	unsigned long flags;
+	unsigned char temp;
+	int count;
+
+	del_timer(&sport->lpuart_timer);
+	dmaengine_pause(sport->dma_rx_chan);
+	dmaengine_tx_status(sport->dma_rx_chan, sport->dma_rx_cookie, &state);
+	dmaengine_terminate_all(sport->dma_rx_chan);
+	count = FSL_UART_RX_DMA_BUFFER_SIZE - state.residue;
+	async_tx_ack(sport->dma_rx_desc);
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	sport->dma_rx_in_progress = 0;
+	lpuart_copy_rx_to_tty(sport, port, count);
+	tty_flip_buffer_push(port);
+	temp = readb(sport->port.membase + UARTCR5);
+	writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
+static inline void lpuart_prepare_rx(struct lpuart_port *sport)
+{
+	unsigned long flags;
+	unsigned char temp;
+
+	spin_lock_irqsave(&sport->port.lock, flags);
+
+	init_timer(&sport->lpuart_timer);
+	sport->lpuart_timer.function = lpuart_timer_func;
+	sport->lpuart_timer.data = (unsigned long)sport;
+	sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
+	add_timer(&sport->lpuart_timer);
+
+	lpuart_dma_rx(sport);
+	temp = readb(sport->port.membase + UARTCR5);
+	writeb(temp | UARTCR5_RDMAS, sport->port.membase + UARTCR5);
+
+	spin_unlock_irqrestore(&sport->port.lock, flags);
+}
+
 static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 {
 	struct circ_buf *xmit = &sport->port.state->xmit;
@@ -172,14 +407,21 @@ static inline void lpuart_transmit_buffer(struct lpuart_port *sport)
 
 static void lpuart_start_tx(struct uart_port *port)
 {
-	struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+	struct lpuart_port *sport = container_of(port,
+			struct lpuart_port, port);
+	struct circ_buf *xmit = &sport->port.state->xmit;
 	unsigned char temp;
 
 	temp = readb(port->membase + UARTCR2);
 	writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
 
-	if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
-		lpuart_transmit_buffer(sport);
+	if (sport->lpuart_dma_use) {
+		if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
+			lpuart_prepare_tx(sport);
+	} else {
+		if (readb(port->membase + UARTSR1) & UARTSR1_TDRE)
+			lpuart_transmit_buffer(sport);
+	}
 }
 
 static irqreturn_t lpuart_txint(int irq, void *dev_id)
@@ -279,12 +521,19 @@ static irqreturn_t lpuart_int(int irq, void *dev_id)
 
 	sts = readb(sport->port.membase + UARTSR1);
 
-	if (sts & UARTSR1_RDRF)
-		lpuart_rxint(irq, dev_id);
-
+	if (sts & UARTSR1_RDRF) {
+		if (sport->lpuart_dma_use)
+			lpuart_prepare_rx(sport);
+		else
+			lpuart_rxint(irq, dev_id);
+	}
 	if (sts & UARTSR1_TDRE &&
-		!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS))
-		lpuart_txint(irq, dev_id);
+		!(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
+		if (sport->lpuart_dma_use)
+			lpuart_pio_tx(sport);
+		else
+			lpuart_txint(irq, dev_id);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -366,13 +615,156 @@ static void lpuart_setup_watermark(struct lpuart_port *sport)
 	writeb(UARTCFIFO_TXFLUSH | UARTCFIFO_RXFLUSH,
 			sport->port.membase + UARTCFIFO);
 
-	writeb(2, sport->port.membase + UARTTWFIFO);
+	writeb(0, sport->port.membase + UARTTWFIFO);
 	writeb(1, sport->port.membase + UARTRWFIFO);
 
 	/* Restore cr2 */
 	writeb(cr2_saved, sport->port.membase + UARTCR2);
 }
 
+static int lpuart_dma_tx_request(struct uart_port *port)
+{
+	struct lpuart_port *sport = container_of(port,
+					struct lpuart_port, port);
+	struct dma_chan *tx_chan;
+	struct dma_slave_config dma_tx_sconfig;
+	dma_addr_t dma_bus;
+	unsigned char *dma_buf;
+	int ret;
+
+	tx_chan  = dma_request_slave_channel(sport->port.dev, "tx");
+
+	if (!tx_chan) {
+		dev_err(sport->port.dev, "Dma tx channel request failed!\n");
+		return -ENODEV;
+	}
+
+	dma_bus = dma_map_single(tx_chan->device->dev,
+				sport->port.state->xmit.buf,
+				UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+	if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+		dev_err(sport->port.dev, "dma_map_single tx failed\n");
+		dma_release_channel(tx_chan);
+		return -ENOMEM;
+	}
+
+	dma_buf = sport->port.state->xmit.buf;
+	dma_tx_sconfig.dst_addr = sport->port.mapbase + UARTDR;
+	dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_tx_sconfig.dst_maxburst = DMA_MAXBURST;
+	dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
+	ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+
+	if (ret < 0) {
+		dev_err(sport->port.dev,
+				"Dma slave config failed, err = %d\n", ret);
+		dma_release_channel(tx_chan);
+		return ret;
+	}
+
+	sport->dma_tx_chan = tx_chan;
+	sport->dma_tx_buf_virt = dma_buf;
+	sport->dma_tx_buf_bus = dma_bus;
+	sport->dma_tx_in_progress = 0;
+
+	return 0;
+}
+
+static int lpuart_dma_rx_request(struct uart_port *port)
+{
+	struct lpuart_port *sport = container_of(port,
+					struct lpuart_port, port);
+	struct dma_chan *rx_chan;
+	struct dma_slave_config dma_rx_sconfig;
+	dma_addr_t dma_bus;
+	unsigned char *dma_buf;
+	int ret;
+
+	rx_chan  = dma_request_slave_channel(sport->port.dev, "rx");
+
+	if (!rx_chan) {
+		dev_err(sport->port.dev, "Dma rx channel request failed!\n");
+		return -ENODEV;
+	}
+
+	dma_buf = devm_kzalloc(sport->port.dev,
+				FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
+
+	if (!dma_buf) {
+		dev_err(sport->port.dev, "Dma rx alloc failed\n");
+		dma_release_channel(rx_chan);
+		return -ENOMEM;
+	}
+
+	dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+				FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+	if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+		dev_err(sport->port.dev, "dma_map_single rx failed\n");
+		dma_release_channel(rx_chan);
+		return -ENOMEM;
+	}
+
+	dma_rx_sconfig.src_addr = sport->port.mapbase + UARTDR;
+	dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	dma_rx_sconfig.src_maxburst = 1;
+	dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
+	ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+
+	if (ret < 0) {
+		dev_err(sport->port.dev,
+				"Dma slave config failed, err = %d\n", ret);
+		dma_release_channel(rx_chan);
+		return ret;
+	}
+
+	sport->dma_rx_chan = rx_chan;
+	sport->dma_rx_buf_virt = dma_buf;
+	sport->dma_rx_buf_bus = dma_bus;
+	sport->dma_rx_in_progress = 0;
+
+	sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
+				FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
+				sport->rxfifo_size / 2;
+
+	if (sport->dma_rx_timeout < msecs_to_jiffies(20))
+		sport->dma_rx_timeout = msecs_to_jiffies(20);
+
+	return 0;
+}
+
+static void lpuart_dma_tx_free(struct uart_port *port)
+{
+	struct lpuart_port *sport = container_of(port,
+					struct lpuart_port, port);
+	struct dma_chan *dma_chan;
+
+	dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
+			UART_XMIT_SIZE, DMA_TO_DEVICE);
+	dma_chan = sport->dma_tx_chan;
+	sport->dma_tx_chan = NULL;
+	sport->dma_tx_buf_bus = 0;
+	sport->dma_tx_buf_virt = NULL;
+	dma_release_channel(dma_chan);
+}
+
+static void lpuart_dma_rx_free(struct uart_port *port)
+{
+	struct lpuart_port *sport = container_of(port,
+					struct lpuart_port, port);
+	struct dma_chan *dma_chan;
+
+	dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
+			FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
+
+	dma_chan = sport->dma_rx_chan;
+	sport->dma_rx_chan = NULL;
+	sport->dma_rx_buf_bus = 0;
+	sport->dma_rx_buf_virt = NULL;
+	dma_release_channel(dma_chan);
+}
+
 static int lpuart_startup(struct uart_port *port)
 {
 	struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
@@ -380,6 +772,15 @@ static int lpuart_startup(struct uart_port *port)
 	unsigned long flags;
 	unsigned char temp;
 
+	/*whether use dma support by dma request results*/
+	if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
+		sport->lpuart_dma_use = false;
+	} else {
+		sport->lpuart_dma_use = true;
+		temp = readb(port->membase + UARTCR5);
+		writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
+	}
+
 	ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
 				DRIVER_NAME, sport);
 	if (ret)
@@ -414,6 +815,11 @@ static void lpuart_shutdown(struct uart_port *port)
 	spin_unlock_irqrestore(&port->lock, flags);
 
 	devm_free_irq(port->dev, port->irq, sport);
+
+	if (sport->lpuart_dma_use) {
+		lpuart_dma_tx_free(port);
+		lpuart_dma_rx_free(port);
+	}
 }
 
 static void
-- 
1.8.4



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

* [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement.
  2014-01-22  4:09 [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Yuan Yao
  2014-01-22  4:09 ` [PATCH v4 1/3] ARM: dts: vf610: lpuart: Add eDMA support Yuan Yao
  2014-01-22  4:09 ` [PATCH v4 2/3] serial: fsl_lpuart: add DMA support Yuan Yao
@ 2014-01-22  4:09 ` Yuan Yao
  2014-01-24 11:26   ` Mark Rutland
  2014-01-27  7:50 ` [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Shawn Guo
  3 siblings, 1 reply; 11+ messages in thread
From: Yuan Yao @ 2014-01-22  4:09 UTC (permalink / raw)
  To: gregkh, shawn.guo
  Cc: linux, arnd, mark.rutland, linux-arm-kernel, linux-serial

It was previously required but not documented.
Add the text to the binding along with the new "dmas" addition.

Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
---
 Documentation/devicetree/bindings/serial/fsl-lpuart.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
index 6e1cbbf..9666f97 100644
--- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
+++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
@@ -4,6 +4,8 @@ Required properties:
 - compatible : Should be "fsl,<soc>-lpuart"
 - reg : Address and length of the register set for the device
 - interrupts : Should contain uart interrupt
+- clocks : phandle + clock specifier pairs, one for each entry in clock-names
+- clock-names : should contain: "ipg" - the uart clock
 
 Optional properties:
 - dmas: Generic dma devicetree binding as described
@@ -19,6 +21,8 @@ uart0: serial@40027000 {
 		compatible = "fsl,vf610-lpuart";
 		reg = <0x40027000 0x1000>;
 		interrupts = <0 61 0x00>;
+		clocks = <&clks VF610_CLK_UART0>;
+		clock-names = "ipg";
 		dmas = <&edma0 0 2>,
 			<&edma0 0 3>;
 		dma-names = "rx","tx";
-- 
1.8.4



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

* Re: [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement.
  2014-01-22  4:09 ` [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement Yuan Yao
@ 2014-01-24 11:26   ` Mark Rutland
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Rutland @ 2014-01-24 11:26 UTC (permalink / raw)
  To: Yuan Yao
  Cc: gregkh@linuxfoundation.org, shawn.guo@linaro.org,
	linux@arm.linux.org.uk, arnd@arndb.de,
	linux-arm-kernel@lists.infradead.org,
	linux-serial@vger.kernel.org

On Wed, Jan 22, 2014 at 04:09:33AM +0000, Yuan Yao wrote:
> It was previously required but not documented.
> Add the text to the binding along with the new "dmas" addition.
> 
> Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
> ---
>  Documentation/devicetree/bindings/serial/fsl-lpuart.txt | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> index 6e1cbbf..9666f97 100644
> --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> @@ -4,6 +4,8 @@ Required properties:
>  - compatible : Should be "fsl,<soc>-lpuart"
>  - reg : Address and length of the register set for the device
>  - interrupts : Should contain uart interrupt
> +- clocks : phandle + clock specifier pairs, one for each entry in clock-names
> +- clock-names : should contain: "ipg" - the uart clock
>  
>  Optional properties:
>  - dmas: Generic dma devicetree binding as described
> @@ -19,6 +21,8 @@ uart0: serial@40027000 {
>  		compatible = "fsl,vf610-lpuart";
>  		reg = <0x40027000 0x1000>;
>  		interrupts = <0 61 0x00>;
> +		clocks = <&clks VF610_CLK_UART0>;
> +		clock-names = "ipg";
>  		dmas = <&edma0 0 2>,
>  			<&edma0 0 3>;
>  		dma-names = "rx","tx";

As this was a previous requirement, and this is a correction to the
documentation rather than a binding change:

Acked-by: Mark Rutland <mark.rutland@arm.com>

Thanks,
Mark.

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

* Re: [PATCH v4 2/3] serial: fsl_lpuart: add DMA support
  2014-01-22  4:09 ` [PATCH v4 2/3] serial: fsl_lpuart: add DMA support Yuan Yao
@ 2014-01-24 11:31   ` Mark Rutland
  0 siblings, 0 replies; 11+ messages in thread
From: Mark Rutland @ 2014-01-24 11:31 UTC (permalink / raw)
  To: Yuan Yao
  Cc: gregkh@linuxfoundation.org, shawn.guo@linaro.org,
	linux@arm.linux.org.uk, arnd@arndb.de,
	linux-arm-kernel@lists.infradead.org,
	linux-serial@vger.kernel.org

On Wed, Jan 22, 2014 at 04:09:32AM +0000, Yuan Yao wrote:
> Add dma support for lpuart. This function depend on DMA driver.
> You can turn on it by write both the dmas and dma-name properties in dts node.
> 
> Signed-off-by: Yuan Yao <yao.yuan@freescale.com>
> ---
>  .../devicetree/bindings/serial/fsl-lpuart.txt      |  19 +-
>  drivers/tty/serial/fsl_lpuart.c                    | 430 ++++++++++++++++++++-
>  2 files changed, 433 insertions(+), 16 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> index 6fd1dd1..6e1cbbf 100644
> --- a/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> +++ b/Documentation/devicetree/bindings/serial/fsl-lpuart.txt
> @@ -5,10 +5,21 @@ Required properties:
>  - reg : Address and length of the register set for the device
>  - interrupts : Should contain uart interrupt
> 
> +Optional properties:
> +- dmas: Generic dma devicetree binding as described
> +       in Documentation/devicetree/bindings/dma/dma.txt.
> +- dma-names: Two dmas have to be defined, "rx" and "tx".
> +       An ordered list of channel names affiliated to the above.

Please describe dmas in terms of dma-names (as with the patch describing
clocks and clock-names).

It would be nice to describe the type of the dmas property, but I see
that we have a propblem with inconsistent terminology in the area of
${THING}-specifiers, so I'll try to get that cleaned up separately.

Cheers,
Mark.

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

* Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
  2014-01-22  4:09 [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Yuan Yao
                   ` (2 preceding siblings ...)
  2014-01-22  4:09 ` [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement Yuan Yao
@ 2014-01-27  7:50 ` Shawn Guo
  2014-02-11  1:50   ` Yao Yuan
  3 siblings, 1 reply; 11+ messages in thread
From: Shawn Guo @ 2014-01-27  7:50 UTC (permalink / raw)
  To: Yuan Yao
  Cc: gregkh, linux, arnd, mark.rutland, linux-arm-kernel, linux-serial

On Wed, Jan 22, 2014 at 12:09:30PM +0800, Yuan Yao wrote:
> Changed in v4:
> - Move dma properties from dtsi to dts.

Why this change?  DMA is a SoC level resource rather than board one.

Shawn


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

* RE: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
  2014-01-27  7:50 ` [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Shawn Guo
@ 2014-02-11  1:50   ` Yao Yuan
  2014-02-11  2:59     ` Shawn Guo
  0 siblings, 1 reply; 11+ messages in thread
From: Yao Yuan @ 2014-02-11  1:50 UTC (permalink / raw)
  To: Shawn Guo
  Cc: mark.rutland@arm.com, linux@arm.linux.org.uk, arnd@arndb.de,
	gregkh@linuxfoundation.org, linux-serial@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org

Hi, Shawn

Here I just want the DMA be a selectable property for each board. 
Is it suitable?

> -----Original Message-----
> From: Shawn Guo [mailto:shawn.guo@linaro.org]
> Sent: Monday, January 27, 2014 3:50 PM
> To: Yuan Yao-B46683
> Cc: gregkh@linuxfoundation.org; linux@arm.linux.org.uk; arnd@arndb.de;
> mark.rutland@arm.com; linux-arm-kernel@lists.infradead.org; linux-
> serial@vger.kernel.org
> Subject: Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
> 
> On Wed, Jan 22, 2014 at 12:09:30PM +0800, Yuan Yao wrote:
> > Changed in v4:
> > - Move dma properties from dtsi to dts.
> 
> Why this change?  DMA is a SoC level resource rather than board one.
> 
> Shawn

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

* Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
  2014-02-11  1:50   ` Yao Yuan
@ 2014-02-11  2:59     ` Shawn Guo
  2014-02-11  5:34       ` Yao Yuan
  0 siblings, 1 reply; 11+ messages in thread
From: Shawn Guo @ 2014-02-11  2:59 UTC (permalink / raw)
  To: Yao Yuan
  Cc: gregkh@linuxfoundation.org, linux@arm.linux.org.uk, arnd@arndb.de,
	mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org,
	linux-serial@vger.kernel.org

On Tue, Feb 11, 2014 at 01:50:14AM +0000, Yao Yuan wrote:
> Hi, Shawn
> 
> Here I just want the DMA be a selectable property for each board. 
> Is it suitable?

No, it's not.  Just like IRQ line, DMA channel is a SoC level resource.
It should just be there once the SoC is out there.  Nothing to do with
board level configuration.

Shawn

> 
> > -----Original Message-----
> > From: Shawn Guo [mailto:shawn.guo@linaro.org]
> > Sent: Monday, January 27, 2014 3:50 PM
> > To: Yuan Yao-B46683
> > Cc: gregkh@linuxfoundation.org; linux@arm.linux.org.uk; arnd@arndb.de;
> > mark.rutland@arm.com; linux-arm-kernel@lists.infradead.org; linux-
> > serial@vger.kernel.org
> > Subject: Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
> > 
> > On Wed, Jan 22, 2014 at 12:09:30PM +0800, Yuan Yao wrote:
> > > Changed in v4:
> > > - Move dma properties from dtsi to dts.
> > 
> > Why this change?  DMA is a SoC level resource rather than board one.
> > 
> > Shawn
> 


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

* RE: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
  2014-02-11  2:59     ` Shawn Guo
@ 2014-02-11  5:34       ` Yao Yuan
  2014-02-11  5:45         ` Shawn Guo
  0 siblings, 1 reply; 11+ messages in thread
From: Yao Yuan @ 2014-02-11  5:34 UTC (permalink / raw)
  To: Shawn Guo
  Cc: gregkh@linuxfoundation.org, linux@arm.linux.org.uk, arnd@arndb.de,
	mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org,
	linux-serial@vger.kernel.org

> -----Original Message-----
> From: Shawn Guo [mailto:shawn.guo@linaro.org]
> Sent: Tuesday, February 11, 2014 11:00 AM
> To: Yuan Yao-B46683
> Cc: gregkh@linuxfoundation.org; linux@arm.linux.org.uk; arnd@arndb.de;
> mark.rutland@arm.com; linux-arm-kernel@lists.infradead.org; linux-
> serial@vger.kernel.org
> Subject: Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
> 
> On Tue, Feb 11, 2014 at 01:50:14AM +0000, Yao Yuan wrote:
> > Hi, Shawn
> >
> > Here I just want the DMA be a selectable property for each board.
> > Is it suitable?
> 
> No, it's not.  Just like IRQ line, DMA channel is a SoC level resource.
> It should just be there once the SoC is out there.  Nothing to do with
> board level configuration.
> 
> Shawn

Here I also have a confusion.
IRQ is must. But DMA isn't very necessary.
How to deal with if one board is need DMA but another is not need?
You mean if DMA is be support once all of them must use dma as first?

--
Best Regards,
YuanYao
> 
> >
> > > -----Original Message-----
> > > From: Shawn Guo [mailto:shawn.guo@linaro.org]
> > > Sent: Monday, January 27, 2014 3:50 PM
> > > To: Yuan Yao-B46683
> > > Cc: gregkh@linuxfoundation.org; linux@arm.linux.org.uk;
> > > arnd@arndb.de; mark.rutland@arm.com;
> > > linux-arm-kernel@lists.infradead.org; linux- serial@vger.kernel.org
> > > Subject: Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
> > >
> > > On Wed, Jan 22, 2014 at 12:09:30PM +0800, Yuan Yao wrote:
> > > > Changed in v4:
> > > > - Move dma properties from dtsi to dts.
> > >
> > > Why this change?  DMA is a SoC level resource rather than board one.
> > >
> > > Shawn
> >


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

* Re: [PATCH v4 0/3] serial: fsl_lpuart: add DMA support
  2014-02-11  5:34       ` Yao Yuan
@ 2014-02-11  5:45         ` Shawn Guo
  0 siblings, 0 replies; 11+ messages in thread
From: Shawn Guo @ 2014-02-11  5:45 UTC (permalink / raw)
  To: Yao Yuan
  Cc: gregkh@linuxfoundation.org, linux@arm.linux.org.uk, arnd@arndb.de,
	mark.rutland@arm.com, linux-arm-kernel@lists.infradead.org,
	linux-serial@vger.kernel.org

On Tue, Feb 11, 2014 at 05:34:49AM +0000, Yao Yuan wrote:
> Here I also have a confusion.
> IRQ is must. But DMA isn't very necessary.
> How to deal with if one board is need DMA but another is not need?
> You mean if DMA is be support once all of them must use dma as first?

That's the point.  Why whether using DMA or not is a board decision?
The DMA resource should be defined at SoC level from the beginning
just like IO and interrupt resource.  And using DMA or PIO should be a
decision made by device driver not device tree.

Shawn


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

end of thread, other threads:[~2014-02-11  5:45 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2014-01-22  4:09 [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Yuan Yao
2014-01-22  4:09 ` [PATCH v4 1/3] ARM: dts: vf610: lpuart: Add eDMA support Yuan Yao
2014-01-22  4:09 ` [PATCH v4 2/3] serial: fsl_lpuart: add DMA support Yuan Yao
2014-01-24 11:31   ` Mark Rutland
2014-01-22  4:09 ` [PATCH v4 3/3] serial: fsl_lpuart: documented the clock requirement Yuan Yao
2014-01-24 11:26   ` Mark Rutland
2014-01-27  7:50 ` [PATCH v4 0/3] serial: fsl_lpuart: add DMA support Shawn Guo
2014-02-11  1:50   ` Yao Yuan
2014-02-11  2:59     ` Shawn Guo
2014-02-11  5:34       ` Yao Yuan
2014-02-11  5:45         ` Shawn Guo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).