All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer
@ 2013-07-16  2:43 Elen Song
  2013-07-16  2:43 ` [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC Elen Song
                   ` (9 more replies)
  0 siblings, 10 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

After at91sam9g45 socs, the usart only support dma transfer.
This patch serial focus on:
1) distinguish pdc and dma transfer
2) support usart dma rx and tx transfer
3) distinguish usart and uart
4) support uart dma rx and tx transfer

For those only support PDC transfer socs, we use "atmel,use-dma-rx/tx" to establish a PDC transfer.
For those only support DMA transfer socs, we not only use "atmel,use-dma-rx/tx", but also describe dma binding to establish a DMA transfer. 
We switch the name from "use-dma" to "use-pdc" in serial driver to state more clearly.
We also distinguish usart and uart by read ip name, the dbgu is regard as a uart.
Because uart lack timeout function, we use software timer to trigger rx.

Compare to v1, this patch serials improve:
1) use function pointer instead of if/else
2) "atmel,use-dma-rx/tx" represent a PDC transfer,
   but when add the dma bindings, it is a dma transfer
3) do not use strncmp in get ip name
4) remove modification in documentation part

Elen Song (7):
  serial: at91: correct definition from DMA to PDC
  serial: at91: add tx dma support
  serial: at91: add rx dma support
  serial: at91: make DBGU support dma and pdc transfers
  serial: at91: distinguish usart and uart
  serial: at91: modify UART to use software timer to trigger rx
  serial: at91: add dma support in usart binding descriptions

 Documentation/devicetree/bindings/serial/rs485.txt |    4 +-
 .../devicetree/bindings/tty/serial/atmel-usart.txt |   29 +-
 arch/arm/boot/dts/at91rm9200.dtsi                  |   16 +-
 arch/arm/boot/dts/at91sam9260.dtsi                 |   24 +-
 arch/arm/boot/dts/at91sam9263.dtsi                 |   12 +-
 arch/arm/boot/dts/at91sam9g45.dtsi                 |   16 +-
 arch/arm/mach-at91/at91rm9200_devices.c            |   20 +-
 arch/arm/mach-at91/at91sam9260_devices.c           |   28 +-
 arch/arm/mach-at91/at91sam9261_devices.c           |   16 +-
 arch/arm/mach-at91/at91sam9263_devices.c           |   16 +-
 arch/arm/mach-at91/at91sam9g45_devices.c           |   20 +-
 arch/arm/mach-at91/at91sam9rl_devices.c            |   20 +-
 drivers/tty/serial/atmel_serial.c                  |  582 ++++++++++++++++++--
 include/linux/atmel_serial.h                       |    2 +
 include/linux/platform_data/atmel.h                |    2 +
 15 files changed, 665 insertions(+), 142 deletions(-)

-- 
1.7.9.5

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

* [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-18  7:49   ` Jean-Christophe PLAGNIOL-VILLARD
  2013-07-16  2:43 ` [PATCH V2 2/8] serial: at91: use function pointer to choose pdc or pio Elen Song
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

The DMA is available since at91sam9x5 socs, before that, we use PDC.

Signed-off-by: Elen Song <elen.song@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |   71 +++++++++++++++++++------------------
 1 file changed, 36 insertions(+), 35 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 3467462..6c71ccf 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -140,11 +140,11 @@ struct atmel_uart_port {
 	u32			backup_imr;	/* IMR saved during suspend */
 	int			break_active;	/* break being received */
 
-	short			use_dma_rx;	/* enable PDC receiver */
+	short			use_pdc_rx;	/* enable PDC receiver */
 	short			pdc_rx_idx;	/* current PDC RX buffer */
 	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
 
-	short			use_dma_tx;	/* enable PDC transmitter */
+	short			use_pdc_tx;	/* enable PDC transmitter */
 	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
 
 	struct tasklet_struct	tasklet;
@@ -181,26 +181,26 @@ to_atmel_uart_port(struct uart_port *uart)
 }
 
 #ifdef CONFIG_SERIAL_ATMEL_PDC
-static bool atmel_use_dma_rx(struct uart_port *port)
+static bool atmel_use_pdc_rx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	return atmel_port->use_dma_rx;
+	return atmel_port->use_pdc_rx;
 }
 
-static bool atmel_use_dma_tx(struct uart_port *port)
+static bool atmel_use_pdc_tx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	return atmel_port->use_dma_tx;
+	return atmel_port->use_pdc_tx;
 }
 #else
-static bool atmel_use_dma_rx(struct uart_port *port)
+static bool atmel_use_pdc_rx(struct uart_port *port)
 {
 	return false;
 }
 
-static bool atmel_use_dma_tx(struct uart_port *port)
+static bool atmel_use_pdc_tx(struct uart_port *port)
 {
 	return false;
 }
@@ -233,7 +233,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 		mode |= ATMEL_US_USMODE_RS485;
 	} else {
 		dev_dbg(port->dev, "Setting UART to RS232\n");
-		if (atmel_use_dma_tx(port))
+		if (atmel_use_pdc_tx(port))
 			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
 				ATMEL_US_TXBUFE;
 		else
@@ -345,7 +345,7 @@ static void atmel_stop_tx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		/* disable PDC transmit */
 		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
 	}
@@ -364,7 +364,7 @@ static void atmel_start_tx(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
 			/* The transmitter is already running.  Yes, we
 			   really need this.*/
@@ -390,7 +390,7 @@ static void atmel_start_rx(struct uart_port *port)
 
 	UART_PUT_CR(port, ATMEL_US_RXEN);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* enable PDC controller */
 		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
 			port->read_status_mask);
@@ -407,7 +407,7 @@ static void atmel_stop_rx(struct uart_port *port)
 {
 	UART_PUT_CR(port, ATMEL_US_RXDIS);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* disable PDC receive */
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
 		UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
@@ -572,7 +572,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/*
 		 * PDC receive. Just schedule the tasklet and let it
 		 * figure out the details.
@@ -661,7 +661,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 /*
  * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
  */
-static void atmel_tx_dma(struct uart_port *port)
+static void atmel_tx_pdc(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct circ_buf *xmit = &port->state->xmit;
@@ -778,7 +778,7 @@ static void atmel_rx_from_ring(struct uart_port *port)
 	spin_lock(&port->lock);
 }
 
-static void atmel_rx_from_dma(struct uart_port *port)
+static void atmel_rx_from_pdc(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct tty_port *tport = &port->state->port;
@@ -868,8 +868,8 @@ static void atmel_tasklet_func(unsigned long data)
 	/* The interrupt handler does not take the lock */
 	spin_lock(&port->lock);
 
-	if (atmel_use_dma_tx(port))
-		atmel_tx_dma(port);
+	if (atmel_use_pdc_tx(port))
+		atmel_tx_pdc(port);
 	else
 		atmel_tx_chars(port);
 
@@ -893,8 +893,8 @@ static void atmel_tasklet_func(unsigned long data)
 		atmel_port->irq_status_prev = status;
 	}
 
-	if (atmel_use_dma_rx(port))
-		atmel_rx_from_dma(port);
+	if (atmel_use_pdc_rx(port))
+		atmel_rx_from_pdc(port);
 	else
 		atmel_rx_from_ring(port);
 
@@ -930,7 +930,7 @@ static int atmel_startup(struct uart_port *port)
 	/*
 	 * Initialize DMA (if necessary)
 	 */
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		int i;
 
 		for (i = 0; i < 2; i++) {
@@ -964,7 +964,7 @@ static int atmel_startup(struct uart_port *port)
 		UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
 		UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
 	}
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
 		struct circ_buf *xmit = &port->state->xmit;
 
@@ -1000,7 +1000,7 @@ static int atmel_startup(struct uart_port *port)
 	/* enable xmit & rcvr */
 	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
 
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		/* set UART timeout */
 		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
 		UART_PUT_CR(port, ATMEL_US_STTTO);
@@ -1031,7 +1031,7 @@ static void atmel_shutdown(struct uart_port *port)
 	/*
 	 * Shut-down the DMA.
 	 */
-	if (atmel_use_dma_rx(port)) {
+	if (atmel_use_pdc_rx(port)) {
 		int i;
 
 		for (i = 0; i < 2; i++) {
@@ -1044,7 +1044,7 @@ static void atmel_shutdown(struct uart_port *port)
 			kfree(pdc->buf);
 		}
 	}
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
 
 		dma_unmap_single(port->dev,
@@ -1080,7 +1080,7 @@ static void atmel_flush_buffer(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_dma_tx(port)) {
+	if (atmel_use_pdc_tx(port)) {
 		UART_PUT_TCR(port, 0);
 		atmel_port->pdc_tx.ofs = 0;
 	}
@@ -1193,7 +1193,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
 	if (termios->c_iflag & (BRKINT | PARMRK))
 		port->read_status_mask |= ATMEL_US_RXBRK;
 
-	if (atmel_use_dma_rx(port))
+	if (atmel_use_pdc_rx(port))
 		/* need to enable error interrupts */
 		UART_PUT_IER(port, port->read_status_mask);
 
@@ -1430,13 +1430,14 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
 
 	/* DMA/PDC usage specification */
 	if (of_get_property(np, "atmel,use-dma-rx", NULL))
-		atmel_port->use_dma_rx	= 1;
+		atmel_port->use_pdc_rx	= 1;
 	else
-		atmel_port->use_dma_rx	= 0;
+		atmel_port->use_pdc_rx	= 0;
+
 	if (of_get_property(np, "atmel,use-dma-tx", NULL))
-		atmel_port->use_dma_tx	= 1;
+		atmel_port->use_pdc_tx	= 1;
 	else
-		atmel_port->use_dma_tx	= 0;
+		atmel_port->use_pdc_tx	= 0;
 
 	/* rs485 properties */
 	if (of_property_read_u32_array(np, "rs485-rts-delay",
@@ -1467,8 +1468,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 	if (pdev->dev.of_node) {
 		atmel_of_init_port(atmel_port, pdev->dev.of_node);
 	} else {
-		atmel_port->use_dma_rx	= pdata->use_dma_rx;
-		atmel_port->use_dma_tx	= pdata->use_dma_tx;
+		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
+		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
 		atmel_port->rs485	= pdata->rs485;
 	}
 
@@ -1505,7 +1506,7 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
 	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
 		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
-	else if (atmel_use_dma_tx(port)) {
+	else if (atmel_use_pdc_tx(port)) {
 		port->fifosize = PDC_BUFFER_SIZE;
 		atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
 	} else {
@@ -1794,7 +1795,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
 		goto err;
 	}
 
-	if (!atmel_use_dma_rx(&port->uart)) {
+	if (!atmel_use_pdc_rx(&port->uart)) {
 		ret = -ENOMEM;
 		data = kmalloc(sizeof(struct atmel_uart_char)
 				* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
-- 
1.7.9.5

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

* [PATCH V2 2/8] serial: at91: use function pointer to choose pdc or pio
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
  2013-07-16  2:43 ` [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-16  2:43 ` [PATCH V3 3/8] serial: at91: add tx dma support Elen Song
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

use function pointer can avoid define atmel_use_pdc_tx/rx everywhere.
(*prepare_rx/tx)() is in setup transfer stage.
(*schedule_rx/tx)() is in tasklet schedule stage.
(*release_rx/tx)() is used when shutdown the transfer.

Signed-off-by: Elen Song <elen.song@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |  203 ++++++++++++++++++++++++-------------
 1 file changed, 130 insertions(+), 73 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 6c71ccf..2b0fe2e 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -155,6 +155,12 @@ struct atmel_uart_port {
 
 	struct serial_rs485	rs485;		/* rs485 settings */
 	unsigned int		tx_done_mask;
+	int (*prepare_rx)(struct uart_port *port);
+	int (*prepare_tx)(struct uart_port *port);
+	void (*schedule_rx)(struct uart_port *port);
+	void (*schedule_tx)(struct uart_port *port);
+	void (*release_rx)(struct uart_port *port);
+	void (*release_tx)(struct uart_port *port);
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
@@ -658,6 +664,17 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
 	return pass_counter ? IRQ_HANDLED : IRQ_NONE;
 }
 
+static void atmel_release_tx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+	dma_unmap_single(port->dev,
+			 pdc->dma_addr,
+			 pdc->dma_size,
+			 DMA_TO_DEVICE);
+}
+
 /*
  * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
  */
@@ -710,6 +727,23 @@ static void atmel_tx_pdc(struct uart_port *port)
 		uart_write_wakeup(port);
 }
 
+static int atmel_prepare_tx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+	struct circ_buf *xmit = &port->state->xmit;
+
+	pdc->buf = xmit->buf;
+	pdc->dma_addr = dma_map_single(port->dev,
+					pdc->buf,
+					UART_XMIT_SIZE,
+					DMA_TO_DEVICE);
+	pdc->dma_size = UART_XMIT_SIZE;
+	pdc->ofs = 0;
+
+	return 0;
+}
+
 static void atmel_rx_from_ring(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -778,6 +812,22 @@ static void atmel_rx_from_ring(struct uart_port *port)
 	spin_lock(&port->lock);
 }
 
+static void atmel_release_rx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+		dma_unmap_single(port->dev,
+				 pdc->dma_addr,
+				 pdc->dma_size,
+				 DMA_FROM_DEVICE);
+		kfree(pdc->buf);
+	}
+}
+
 static void atmel_rx_from_pdc(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -855,6 +905,45 @@ static void atmel_rx_from_pdc(struct uart_port *port)
 	UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
 }
 
+static int atmel_prepare_rx_pdc(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int i;
+
+	for (i = 0; i < 2; i++) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+		pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+		if (pdc->buf == NULL) {
+			if (i != 0) {
+				dma_unmap_single(port->dev,
+					atmel_port->pdc_rx[0].dma_addr,
+					PDC_BUFFER_SIZE,
+					DMA_FROM_DEVICE);
+				kfree(atmel_port->pdc_rx[0].buf);
+			}
+			atmel_port->use_pdc_rx = 0;
+			return -ENOMEM;
+		}
+		pdc->dma_addr = dma_map_single(port->dev,
+						pdc->buf,
+						PDC_BUFFER_SIZE,
+						DMA_FROM_DEVICE);
+		pdc->dma_size = PDC_BUFFER_SIZE;
+		pdc->ofs = 0;
+	}
+
+	atmel_port->pdc_rx_idx = 0;
+
+	UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+	UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+	UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+	UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+
+	return 0;
+}
+
 /*
  * tasklet handling tty stuff outside the interrupt handler.
  */
@@ -868,10 +957,7 @@ static void atmel_tasklet_func(unsigned long data)
 	/* The interrupt handler does not take the lock */
 	spin_lock(&port->lock);
 
-	if (atmel_use_pdc_tx(port))
-		atmel_tx_pdc(port);
-	else
-		atmel_tx_chars(port);
+	atmel_port->schedule_tx(port);
 
 	status = atmel_port->irq_status;
 	status_change = status ^ atmel_port->irq_status_prev;
@@ -893,14 +979,36 @@ static void atmel_tasklet_func(unsigned long data)
 		atmel_port->irq_status_prev = status;
 	}
 
-	if (atmel_use_pdc_rx(port))
-		atmel_rx_from_pdc(port);
-	else
-		atmel_rx_from_ring(port);
+	atmel_port->schedule_rx(port);
 
 	spin_unlock(&port->lock);
 }
 
+static void atmel_set_ops(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	if (atmel_use_pdc_rx(port)) {
+		atmel_port->prepare_rx = &atmel_prepare_rx_pdc;
+		atmel_port->schedule_rx = &atmel_rx_from_pdc;
+		atmel_port->release_rx = &atmel_release_rx_pdc;
+	} else {
+		atmel_port->prepare_rx = NULL;
+		atmel_port->schedule_rx = &atmel_rx_from_ring;
+		atmel_port->release_rx = NULL;
+	}
+
+	if (atmel_use_pdc_tx(port)) {
+		atmel_port->prepare_tx = &atmel_prepare_tx_pdc;
+		atmel_port->schedule_tx = &atmel_tx_pdc;
+		atmel_port->release_tx = &atmel_release_tx_pdc;
+	} else {
+		atmel_port->prepare_tx = NULL;
+		atmel_port->schedule_tx = &atmel_tx_chars;
+		atmel_port->release_tx = NULL;
+	}
+}
+
 /*
  * Perform initialization and enable port for reception
  */
@@ -930,53 +1038,17 @@ static int atmel_startup(struct uart_port *port)
 	/*
 	 * Initialize DMA (if necessary)
 	 */
-	if (atmel_use_pdc_rx(port)) {
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-			pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
-			if (pdc->buf == NULL) {
-				if (i != 0) {
-					dma_unmap_single(port->dev,
-						atmel_port->pdc_rx[0].dma_addr,
-						PDC_BUFFER_SIZE,
-						DMA_FROM_DEVICE);
-					kfree(atmel_port->pdc_rx[0].buf);
-				}
-				free_irq(port->irq, port);
-				return -ENOMEM;
-			}
-			pdc->dma_addr = dma_map_single(port->dev,
-						       pdc->buf,
-						       PDC_BUFFER_SIZE,
-						       DMA_FROM_DEVICE);
-			pdc->dma_size = PDC_BUFFER_SIZE;
-			pdc->ofs = 0;
-		}
-
-		atmel_port->pdc_rx_idx = 0;
-
-		UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
-		UART_PUT_RCR(port, PDC_BUFFER_SIZE);
-
-		UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
-		UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+	if (atmel_port->prepare_rx) {
+		retval = atmel_port->prepare_rx(port);
+		if (retval < 0)
+			atmel_set_ops(port);
 	}
-	if (atmel_use_pdc_tx(port)) {
-		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-		struct circ_buf *xmit = &port->state->xmit;
 
-		pdc->buf = xmit->buf;
-		pdc->dma_addr = dma_map_single(port->dev,
-					       pdc->buf,
-					       UART_XMIT_SIZE,
-					       DMA_TO_DEVICE);
-		pdc->dma_size = UART_XMIT_SIZE;
-		pdc->ofs = 0;
+	if (atmel_port->prepare_tx) {
+		retval = atmel_port->prepare_tx(port);
+		if (retval < 0)
+			atmel_set_ops(port);
 	}
-
 	/*
 	 * If there is a specific "open" function (to register
 	 * control line interrupts)
@@ -1031,27 +1103,10 @@ static void atmel_shutdown(struct uart_port *port)
 	/*
 	 * Shut-down the DMA.
 	 */
-	if (atmel_use_pdc_rx(port)) {
-		int i;
-
-		for (i = 0; i < 2; i++) {
-			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
-
-			dma_unmap_single(port->dev,
-					 pdc->dma_addr,
-					 pdc->dma_size,
-					 DMA_FROM_DEVICE);
-			kfree(pdc->buf);
-		}
-	}
-	if (atmel_use_pdc_tx(port)) {
-		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
-
-		dma_unmap_single(port->dev,
-				 pdc->dma_addr,
-				 pdc->dma_size,
-				 DMA_TO_DEVICE);
-	}
+	if (atmel_port->release_rx)
+		atmel_port->release_rx(port);
+	if (atmel_port->release_tx)
+		atmel_port->release_tx(port);
 
 	/*
 	 * Disable all interrupts, port and break condition.
@@ -1473,6 +1528,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 		atmel_port->rs485	= pdata->rs485;
 	}
 
+	atmel_set_ops(port);
+
 	port->iotype		= UPIO_MEM;
 	port->flags		= UPF_BOOT_AUTOCONF;
 	port->ops		= &atmel_pops;
-- 
1.7.9.5

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

* [PATCH V3 3/8] serial: at91: add tx dma support
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
  2013-07-16  2:43 ` [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC Elen Song
  2013-07-16  2:43 ` [PATCH V2 2/8] serial: at91: use function pointer to choose pdc or pio Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-16  2:43 ` [PATCH V2 4/8] serial: at91: add rx " Elen Song
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Request a slave dma channel for tx dma use. Tx dma will setup a single transfer,
when transfer complete, it will call atmel_complete_tx_dma to do finish stuff.

Signed-off-by: Elen Song <elen.song@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |  210 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 206 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 2b0fe2e..1176daa 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -144,9 +144,15 @@ struct atmel_uart_port {
 	short			pdc_rx_idx;	/* current PDC RX buffer */
 	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
 
+	short                   use_dma_tx;     /* enable DMA transmitter */
 	short			use_pdc_tx;	/* enable PDC transmitter */
 	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
 
+	spinlock_t			lock_tx;	/* port lock */
+	struct dma_chan			*chan_tx;
+	struct dma_async_tx_descriptor	*desc_tx;
+	dma_cookie_t			cookie_tx;
+	struct scatterlist		sg_tx;
 	struct tasklet_struct	tasklet;
 	unsigned int		irq_status;
 	unsigned int		irq_status_prev;
@@ -212,6 +218,13 @@ static bool atmel_use_pdc_tx(struct uart_port *port)
 }
 #endif
 
+static bool atmel_use_dma_tx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	return atmel_port->use_dma_tx;
+}
+
 /* Enable or disable the rs485 support */
 void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 {
@@ -570,6 +583,182 @@ static void atmel_tx_chars(struct uart_port *port)
 		UART_PUT_IER(port, atmel_port->tx_done_mask);
 }
 
+static void atmel_complete_tx_dma(void *arg)
+{
+	struct atmel_uart_port *atmel_port = arg;
+	struct uart_port *port = &atmel_port->uart;
+	struct circ_buf *xmit = &port->state->xmit;
+	struct dma_chan *chan = atmel_port->chan_tx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&port->lock, flags);
+
+	if (chan)
+		dmaengine_terminate_all(chan);
+	xmit->tail += sg_dma_len(&atmel_port->sg_tx);
+	xmit->tail &= UART_XMIT_SIZE - 1;
+
+	port->icount.tx += sg_dma_len(&atmel_port->sg_tx);
+
+	spin_lock_irq(&atmel_port->lock_tx);
+	async_tx_ack(atmel_port->desc_tx);
+	atmel_port->cookie_tx = -EINVAL;
+	atmel_port->desc_tx = NULL;
+	spin_unlock_irq(&atmel_port->lock_tx);
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+
+	/* Do we really need this? */
+	if (!uart_circ_empty(xmit))
+		tasklet_schedule(&atmel_port->tasklet);
+
+	spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void atmel_release_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_chan *chan = atmel_port->chan_tx;
+
+	if (chan) {
+		dmaengine_terminate_all(chan);
+		dma_release_channel(chan);
+		dma_unmap_sg(port->dev, &atmel_port->sg_tx, 1,
+				DMA_MEM_TO_DEV);
+	}
+
+	atmel_port->desc_tx = NULL;
+	atmel_port->chan_tx = NULL;
+	atmel_port->cookie_tx = -EINVAL;
+}
+
+/*
+ * Called from tasklet with TXRDY interrupt is disabled.
+ */
+static void atmel_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct circ_buf *xmit = &port->state->xmit;
+	struct dma_chan *chan = atmel_port->chan_tx;
+	struct dma_async_tx_descriptor *desc;
+	struct scatterlist *sg = &atmel_port->sg_tx;
+
+	/* Make sure we have an idle channel */
+	if (atmel_port->desc_tx != NULL)
+		return;
+
+	if (!uart_circ_empty(xmit) && !uart_tx_stopped(port)) {
+		/*
+		 * DMA is idle now.
+		 * Port xmit buffer is already mapped,
+		 * and it is one page... Just adjust
+		 * offsets and lengths. Since it is a circular buffer,
+		 * we have to transmit till the end, and then the rest.
+		 * Take the port lock to get a
+		 * consistent xmit buffer state.
+		 */
+		sg->offset = xmit->tail & (UART_XMIT_SIZE - 1);
+		sg_dma_address(sg) = (sg_dma_address(sg) &
+					~(UART_XMIT_SIZE - 1))
+					+ sg->offset;
+		sg_dma_len(sg) = CIRC_CNT_TO_END(xmit->head,
+						xmit->tail,
+						UART_XMIT_SIZE);
+		BUG_ON(!sg_dma_len(sg));
+
+		desc = dmaengine_prep_slave_sg(chan,
+						sg,
+						1,
+						DMA_MEM_TO_DEV,
+						DMA_PREP_INTERRUPT |
+						DMA_CTRL_ACK);
+		if (!desc) {
+			dev_err(port->dev, "Failed to send via dma!\n");
+			return;
+		}
+
+		dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+
+		atmel_port->desc_tx = desc;
+		desc->callback = atmel_complete_tx_dma;
+		desc->callback_param = atmel_port;
+		atmel_port->cookie_tx = dmaengine_submit(desc);
+
+	} else {
+		if (atmel_port->rs485.flags & SER_RS485_ENABLED) {
+			/* DMA done, stop TX, start RX for RS485 */
+			atmel_start_rx(port);
+		}
+	}
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+}
+
+static int atmel_prepare_tx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	dma_cap_mask_t		mask;
+	struct dma_slave_config config;
+	int ret, nent;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_SLAVE, mask);
+
+	atmel_port->chan_tx = dma_request_slave_channel(port->dev, "tx");
+	if (atmel_port->chan_tx == NULL)
+		goto chan_err;
+	dev_info(port->dev, "using %s for tx DMA transfers\n",
+		dma_chan_name(atmel_port->chan_tx));
+
+	spin_lock_init(&atmel_port->lock_tx);
+	sg_init_table(&atmel_port->sg_tx, 1);
+	/* UART circular tx buffer is an aligned page. */
+	BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+	sg_set_page(&atmel_port->sg_tx,
+			virt_to_page(port->state->xmit.buf),
+			UART_XMIT_SIZE,
+			(int)port->state->xmit.buf & ~PAGE_MASK);
+	nent = dma_map_sg(port->dev,
+				&atmel_port->sg_tx,
+				1,
+				DMA_MEM_TO_DEV);
+
+	if (!nent) {
+		dev_dbg(port->dev, "need to release resource of dma\n");
+		goto chan_err;
+	} else {
+		dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+			sg_dma_len(&atmel_port->sg_tx),
+			port->state->xmit.buf,
+			sg_dma_address(&atmel_port->sg_tx));
+	}
+
+	/* Configure the slave DMA */
+	memset(&config, 0, sizeof(config));
+	config.direction = DMA_MEM_TO_DEV;
+	config.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.dst_addr = port->mapbase + ATMEL_US_THR;
+
+	ret = dmaengine_device_control(atmel_port->chan_tx,
+					DMA_SLAVE_CONFIG,
+					(unsigned long)&config);
+	if (ret) {
+		dev_err(port->dev, "DMA tx slave configuration failed\n");
+		goto chan_err;
+	}
+
+	return 0;
+
+chan_err:
+	dev_err(port->dev, "TX channel not available, switch to pio\n");
+	atmel_port->use_dma_tx = 0;
+	if (atmel_port->chan_tx)
+		atmel_release_tx_dma(port);
+	return -EINVAL;
+}
+
 /*
  * receive interrupt handler.
  */
@@ -998,7 +1187,11 @@ static void atmel_set_ops(struct uart_port *port)
 		atmel_port->release_rx = NULL;
 	}
 
-	if (atmel_use_pdc_tx(port)) {
+	if (atmel_use_dma_tx(port)) {
+		atmel_port->prepare_tx = &atmel_prepare_tx_dma;
+		atmel_port->schedule_tx = &atmel_tx_dma;
+		atmel_port->release_tx = &atmel_release_tx_dma;
+	} else if (atmel_use_pdc_tx(port)) {
 		atmel_port->prepare_tx = &atmel_prepare_tx_pdc;
 		atmel_port->schedule_tx = &atmel_tx_pdc;
 		atmel_port->release_tx = &atmel_release_tx_pdc;
@@ -1489,10 +1682,18 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
 	else
 		atmel_port->use_pdc_rx	= 0;
 
-	if (of_get_property(np, "atmel,use-dma-tx", NULL))
-		atmel_port->use_pdc_tx	= 1;
-	else
+	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
+		if (of_get_property(np, "dmas", NULL)) {
+			atmel_port->use_dma_tx	= 1;
+			atmel_port->use_pdc_tx	= 0;
+		} else {
+			atmel_port->use_dma_tx	= 0;
+			atmel_port->use_pdc_tx	= 1;
+		}
+	} else {
+		atmel_port->use_dma_tx	= 0;
 		atmel_port->use_pdc_tx	= 0;
+	}
 
 	/* rs485 properties */
 	if (of_property_read_u32_array(np, "rs485-rts-delay",
@@ -1525,6 +1726,7 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 	} else {
 		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
 		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
+		atmel_port->use_dma_tx	= 0;
 		atmel_port->rs485	= pdata->rs485;
 	}
 
-- 
1.7.9.5

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

* [PATCH V2 4/8] serial: at91: add rx dma support
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (2 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V3 3/8] serial: at91: add tx dma support Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-16  2:43 ` [PATCH V2 5/8] serial: at91: support run time switch transfer mode Elen Song
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Request a cyclic dma channel for rx dma use. Use cyclic transfer is to prevent
receive data overrun.

We allocate a cycle dma cookie after request channel,
after that, enable uart timeout interrupt in startup stage, when data successful
received, the timeout callback will check the residual bytes and insert
receiving datas into the framework during the transfer interval.

When current descriptor finished, the dma callback will also check the residual
bytes and filp the receiving data.

Signed-off-by: Elen Song <elen.song@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |  224 ++++++++++++++++++++++++++++++++++++-
 1 file changed, 220 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 1176daa..298b58c 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -140,6 +140,7 @@ struct atmel_uart_port {
 	u32			backup_imr;	/* IMR saved during suspend */
 	int			break_active;	/* break being received */
 
+	short			use_dma_rx;	/* enable DMA receiver */
 	short			use_pdc_rx;	/* enable PDC receiver */
 	short			pdc_rx_idx;	/* current PDC RX buffer */
 	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
@@ -149,10 +150,15 @@ struct atmel_uart_port {
 	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
 
 	spinlock_t			lock_tx;	/* port lock */
+	spinlock_t			lock_rx;	/* port lock */
 	struct dma_chan			*chan_tx;
+	struct dma_chan			*chan_rx;
 	struct dma_async_tx_descriptor	*desc_tx;
+	struct dma_async_tx_descriptor	*desc_rx;
 	dma_cookie_t			cookie_tx;
+	dma_cookie_t			cookie_rx;
 	struct scatterlist		sg_tx;
+	struct scatterlist		sg_rx;
 	struct tasklet_struct	tasklet;
 	unsigned int		irq_status;
 	unsigned int		irq_status_prev;
@@ -225,6 +231,13 @@ static bool atmel_use_dma_tx(struct uart_port *port)
 	return atmel_port->use_dma_tx;
 }
 
+static bool atmel_use_dma_rx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	return atmel_port->use_dma_rx;
+}
+
 /* Enable or disable the rs485 support */
 void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
 {
@@ -759,6 +772,184 @@ chan_err:
 	return -EINVAL;
 }
 
+static void atmel_flip_buffer_rx_dma(struct uart_port *port,
+					char *buf, size_t count)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct tty_port *tport = &port->state->port;
+
+	dma_sync_sg_for_cpu(port->dev,
+				&atmel_port->sg_rx,
+				1,
+				DMA_DEV_TO_MEM);
+
+	tty_insert_flip_string(tport, buf, count);
+
+	dma_sync_sg_for_device(port->dev,
+				&atmel_port->sg_rx,
+				1,
+				DMA_DEV_TO_MEM);
+	/*
+	 * Drop the lock here since it might end up calling
+	 * uart_start(), which takes the lock.
+	 */
+	spin_unlock(&port->lock);
+	tty_flip_buffer_push(tport);
+	spin_lock(&port->lock);
+}
+
+static void atmel_complete_rx_dma(void *arg)
+{
+	struct uart_port *port = arg;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	tasklet_schedule(&atmel_port->tasklet);
+}
+
+static void atmel_release_rx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_chan *chan = atmel_port->chan_rx;
+
+	if (chan) {
+		dmaengine_terminate_all(chan);
+		dma_release_channel(chan);
+		dma_unmap_sg(port->dev, &atmel_port->sg_rx, 1,
+				DMA_DEV_TO_MEM);
+	}
+
+	atmel_port->desc_rx = NULL;
+	atmel_port->chan_rx = NULL;
+	atmel_port->cookie_rx = -EINVAL;
+}
+
+static void atmel_rx_from_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct circ_buf *ring = &atmel_port->rx_ring;
+	struct dma_chan *chan = atmel_port->chan_rx;
+	struct dma_tx_state state;
+	enum dma_status dmastat;
+	size_t pending, count;
+
+
+	/* Reset the UART timeout early so that we don't miss one */
+	UART_PUT_CR(port, ATMEL_US_STTTO);
+	dmastat = dmaengine_tx_status(chan,
+				atmel_port->cookie_rx,
+				&state);
+	/* Restart a new tasklet if DMA status is error */
+	if (dmastat == DMA_ERROR) {
+		dev_dbg(port->dev, "Get residue error, restart tasklet\n");
+		UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+		tasklet_schedule(&atmel_port->tasklet);
+		return;
+	}
+	/* current transfer size should no larger than dma buffer */
+	pending = sg_dma_len(&atmel_port->sg_rx) - state.residue;
+	BUG_ON(pending > sg_dma_len(&atmel_port->sg_rx));
+
+	/*
+	 * This will take the chars we have so far,
+	 * ring->head will record the transfer size, only new bytes come
+	 * will insert into the framework.
+	 */
+	if (pending > ring->head) {
+		count = pending - ring->head;
+
+		atmel_flip_buffer_rx_dma(port, ring->buf + ring->head, count);
+
+		ring->head += count;
+		if (ring->head == sg_dma_len(&atmel_port->sg_rx))
+			ring->head = 0;
+
+		port->icount.rx += count;
+	}
+
+	UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+}
+
+static int atmel_prepare_rx_dma(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	struct dma_async_tx_descriptor *desc;
+	dma_cap_mask_t		mask;
+	struct dma_slave_config config;
+	struct circ_buf		*ring;
+	int ret, nent;
+
+	ring = &atmel_port->rx_ring;
+
+	dma_cap_zero(mask);
+	dma_cap_set(DMA_CYCLIC, mask);
+
+	atmel_port->chan_rx = dma_request_slave_channel(port->dev, "rx");
+	if (atmel_port->chan_rx == NULL)
+		goto chan_err;
+	dev_info(port->dev, "using %s for rx DMA transfers\n",
+		dma_chan_name(atmel_port->chan_rx));
+
+	spin_lock_init(&atmel_port->lock_rx);
+	sg_init_table(&atmel_port->sg_rx, 1);
+	/* UART circular rx buffer is an aligned page. */
+	BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
+	sg_set_page(&atmel_port->sg_rx,
+			virt_to_page(ring->buf),
+			ATMEL_SERIAL_RINGSIZE,
+			(int)ring->buf & ~PAGE_MASK);
+			nent = dma_map_sg(port->dev,
+					&atmel_port->sg_rx,
+					1,
+					DMA_DEV_TO_MEM);
+
+	if (!nent) {
+		dev_dbg(port->dev, "need to release resource of dma\n");
+		goto chan_err;
+	} else {
+		dev_dbg(port->dev, "%s: mapped %d@%p to %x\n", __func__,
+			sg_dma_len(&atmel_port->sg_rx),
+			ring->buf,
+			sg_dma_address(&atmel_port->sg_rx));
+	}
+
+	/* Configure the slave DMA */
+	memset(&config, 0, sizeof(config));
+	config.direction = DMA_DEV_TO_MEM;
+	config.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+	config.src_addr = port->mapbase + ATMEL_US_RHR;
+
+	ret = dmaengine_device_control(atmel_port->chan_rx,
+					DMA_SLAVE_CONFIG,
+					(unsigned long)&config);
+	if (ret) {
+		dev_err(port->dev, "DMA rx slave configuration failed\n");
+		goto chan_err;
+	}
+	/*
+	 * Prepare a cyclic dma transfer, assign 2 descriptors,
+	 * each one is half ring buffer size
+	 */
+	desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
+				sg_dma_address(&atmel_port->sg_rx),
+				sg_dma_len(&atmel_port->sg_rx),
+				sg_dma_len(&atmel_port->sg_rx)/2,
+				DMA_DEV_TO_MEM,
+				DMA_PREP_INTERRUPT);
+	desc->callback = atmel_complete_rx_dma;
+	desc->callback_param = port;
+	atmel_port->desc_rx = desc;
+	atmel_port->cookie_rx = dmaengine_submit(desc);
+
+	return 0;
+
+chan_err:
+	dev_err(port->dev, "RX channel not available, switch to pio\n");
+	atmel_port->use_dma_rx = 0;
+	if (atmel_port->chan_rx)
+		atmel_release_rx_dma(port);
+	return -EINVAL;
+}
+
 /*
  * receive interrupt handler.
  */
@@ -786,6 +977,13 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
 			atmel_pdc_rxerr(port, pending);
 	}
 
+	if (atmel_use_dma_rx(port)) {
+		if (pending & ATMEL_US_TIMEOUT) {
+			UART_PUT_IDR(port, ATMEL_US_TIMEOUT);
+			tasklet_schedule(&atmel_port->tasklet);
+		}
+	}
+
 	/* Interrupt receive */
 	if (pending & ATMEL_US_RXRDY)
 		atmel_rx_chars(port);
@@ -1177,7 +1375,11 @@ static void atmel_set_ops(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 
-	if (atmel_use_pdc_rx(port)) {
+	if (atmel_use_dma_rx(port)) {
+		atmel_port->prepare_rx = &atmel_prepare_rx_dma;
+		atmel_port->schedule_rx = &atmel_rx_from_dma;
+		atmel_port->release_rx = &atmel_release_rx_dma;
+	} else if (atmel_use_pdc_rx(port)) {
 		atmel_port->prepare_rx = &atmel_prepare_rx_pdc;
 		atmel_port->schedule_rx = &atmel_rx_from_pdc;
 		atmel_port->release_rx = &atmel_release_rx_pdc;
@@ -1273,6 +1475,11 @@ static int atmel_startup(struct uart_port *port)
 		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
 		/* enable PDC controller */
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
+	} else if (atmel_use_dma_rx(port)) {
+		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+		UART_PUT_CR(port, ATMEL_US_STTTO);
+
+		UART_PUT_IER(port, ATMEL_US_TIMEOUT);
 	} else {
 		/* enable receive only */
 		UART_PUT_IER(port, ATMEL_US_RXRDY);
@@ -1677,10 +1884,18 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
 	u32 rs485_delay[2];
 
 	/* DMA/PDC usage specification */
-	if (of_get_property(np, "atmel,use-dma-rx", NULL))
-		atmel_port->use_pdc_rx	= 1;
-	else
+	if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
+		if (of_get_property(np, "dmas", NULL)) {
+			atmel_port->use_dma_rx	= 1;
+			atmel_port->use_pdc_rx	= 0;
+		} else {
+			atmel_port->use_dma_rx	= 0;
+			atmel_port->use_pdc_rx	= 1;
+		}
+	} else {
+		atmel_port->use_dma_rx	= 0;
 		atmel_port->use_pdc_rx	= 0;
+	}
 
 	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
 		if (of_get_property(np, "dmas", NULL)) {
@@ -1726,6 +1941,7 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 	} else {
 		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
 		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
+		atmel_port->use_dma_rx	= 0;
 		atmel_port->use_dma_tx	= 0;
 		atmel_port->rs485	= pdata->rs485;
 	}
-- 
1.7.9.5

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

* [PATCH V2 5/8] serial: at91: support run time switch transfer mode
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (3 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V2 4/8] serial: at91: add rx " Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-18  8:15   ` Jean-Christophe PLAGNIOL-VILLARD
  2013-07-16  2:43 ` [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers Elen Song
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

We will switch to pio mode when request of dma or pdc fail.
But soon or later, when the request is success, the transfer mode can switch to them at
next open serial port action.
So in startup stage, we should get original transfer mode.

Signed-off-by: Elen Song <elen.song@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |  139 +++++++++++++++++++++----------------
 1 file changed, 80 insertions(+), 59 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 298b58c..ad787fd1 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -1371,6 +1371,80 @@ static void atmel_tasklet_func(unsigned long data)
 	spin_unlock(&port->lock);
 }
 
+static int atmel_init_property(struct atmel_uart_port *atmel_port,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct atmel_uart_data *pdata = pdev->dev.platform_data;
+
+	if (np) {
+		/* DMA/PDC usage specification */
+		if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
+			if (of_get_property(np, "dmas", NULL)) {
+				atmel_port->use_dma_rx  = 1;
+				atmel_port->use_pdc_rx  = 0;
+			} else {
+				atmel_port->use_dma_rx  = 0;
+				atmel_port->use_pdc_rx  = 1;
+			}
+		} else {
+			atmel_port->use_dma_rx  = 0;
+			atmel_port->use_pdc_rx  = 0;
+		}
+
+		if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
+			if (of_get_property(np, "dmas", NULL)) {
+				atmel_port->use_dma_tx  = 1;
+				atmel_port->use_pdc_tx  = 0;
+			} else {
+				atmel_port->use_dma_tx  = 0;
+				atmel_port->use_pdc_tx  = 1;
+			}
+		} else {
+			atmel_port->use_dma_tx  = 0;
+			atmel_port->use_pdc_tx  = 0;
+		}
+
+	} else {
+		atmel_port->use_pdc_rx  = pdata->use_dma_rx;
+		atmel_port->use_pdc_tx  = pdata->use_dma_tx;
+		atmel_port->use_dma_rx  = 0;
+		atmel_port->use_dma_tx  = 0;
+	}
+
+	return 0;
+}
+
+static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
+				struct platform_device *pdev)
+{
+	struct device_node *np = pdev->dev.of_node;
+	struct atmel_uart_data *pdata = pdev->dev.platform_data;
+
+	if (np) {
+		u32 rs485_delay[2];
+		/* rs485 properties */
+		if (of_property_read_u32_array(np, "rs485-rts-delay",
+					rs485_delay, 2) == 0) {
+			struct serial_rs485 *rs485conf = &atmel_port->rs485;
+
+			rs485conf->delay_rts_before_send = rs485_delay[0];
+			rs485conf->delay_rts_after_send = rs485_delay[1];
+			rs485conf->flags = 0;
+
+		if (of_get_property(np, "rs485-rx-during-tx", NULL))
+			rs485conf->flags |= SER_RS485_RX_DURING_TX;
+
+		if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
+								NULL))
+			rs485conf->flags |= SER_RS485_ENABLED;
+		}
+	} else {
+		atmel_port->rs485       = pdata->rs485;
+	}
+
+}
+
 static void atmel_set_ops(struct uart_port *port)
 {
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
@@ -1409,6 +1483,7 @@ static void atmel_set_ops(struct uart_port *port)
  */
 static int atmel_startup(struct uart_port *port)
 {
+	struct platform_device *pdev = to_platform_device(port->dev);
 	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
 	struct tty_struct *tty = port->state->port.tty;
 	int retval;
@@ -1433,6 +1508,8 @@ static int atmel_startup(struct uart_port *port)
 	/*
 	 * Initialize DMA (if necessary)
 	 */
+	atmel_init_property(atmel_port, pdev);
+
 	if (atmel_port->prepare_rx) {
 		retval = atmel_port->prepare_rx(port);
 		if (retval < 0)
@@ -1878,55 +1955,6 @@ static struct uart_ops atmel_pops = {
 #endif
 };
 
-static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
-					 struct device_node *np)
-{
-	u32 rs485_delay[2];
-
-	/* DMA/PDC usage specification */
-	if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
-		if (of_get_property(np, "dmas", NULL)) {
-			atmel_port->use_dma_rx	= 1;
-			atmel_port->use_pdc_rx	= 0;
-		} else {
-			atmel_port->use_dma_rx	= 0;
-			atmel_port->use_pdc_rx	= 1;
-		}
-	} else {
-		atmel_port->use_dma_rx	= 0;
-		atmel_port->use_pdc_rx	= 0;
-	}
-
-	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
-		if (of_get_property(np, "dmas", NULL)) {
-			atmel_port->use_dma_tx	= 1;
-			atmel_port->use_pdc_tx	= 0;
-		} else {
-			atmel_port->use_dma_tx	= 0;
-			atmel_port->use_pdc_tx	= 1;
-		}
-	} else {
-		atmel_port->use_dma_tx	= 0;
-		atmel_port->use_pdc_tx	= 0;
-	}
-
-	/* rs485 properties */
-	if (of_property_read_u32_array(np, "rs485-rts-delay",
-					    rs485_delay, 2) == 0) {
-		struct serial_rs485 *rs485conf = &atmel_port->rs485;
-
-		rs485conf->delay_rts_before_send = rs485_delay[0];
-		rs485conf->delay_rts_after_send = rs485_delay[1];
-		rs485conf->flags = 0;
-
-		if (of_get_property(np, "rs485-rx-during-tx", NULL))
-			rs485conf->flags |= SER_RS485_RX_DURING_TX;
-
-		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
-			rs485conf->flags |= SER_RS485_ENABLED;
-	}
-}
-
 /*
  * Configure the port from the platform device resource info.
  */
@@ -1936,17 +1964,10 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
 	struct uart_port *port = &atmel_port->uart;
 	struct atmel_uart_data *pdata = pdev->dev.platform_data;
 
-	if (pdev->dev.of_node) {
-		atmel_of_init_port(atmel_port, pdev->dev.of_node);
-	} else {
-		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
-		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
-		atmel_port->use_dma_rx	= 0;
-		atmel_port->use_dma_tx	= 0;
-		atmel_port->rs485	= pdata->rs485;
-	}
+	if (!atmel_init_property(atmel_port, pdev))
+		atmel_set_ops(port);
 
-	atmel_set_ops(port);
+	atmel_init_rs485(atmel_port, pdev);
 
 	port->iotype		= UPIO_MEM;
 	port->flags		= UPF_BOOT_AUTOCONF;
-- 
1.7.9.5

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

* [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (4 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V2 5/8] serial: at91: support run time switch transfer mode Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-18  8:18   ` Jean-Christophe PLAGNIOL-VILLARD
  2013-07-16  2:43 ` [PATCH V2 7/8] serial: at91: distinguish usart and uart Elen Song
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Because the DBGU lack of receive timeout register, so we use a timer to trigger
data receive.

Signed-off-by: Elen Song <elen.song@atmel.com>
Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |   48 ++++++++++++++++++++++++++++++++-----
 1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index ad787fd1..afecdfa 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -41,6 +41,7 @@
 #include <linux/uaccess.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_data/atmel.h>
+#include <linux/timer.h>
 
 #include <asm/io.h>
 #include <asm/ioctls.h>
@@ -167,6 +168,7 @@ struct atmel_uart_port {
 
 	struct serial_rs485	rs485;		/* rs485 settings */
 	unsigned int		tx_done_mask;
+	struct timer_list       uart_timer;     /* dbgu timer */
 	int (*prepare_rx)(struct uart_port *port);
 	int (*prepare_tx)(struct uart_port *port);
 	void (*schedule_rx)(struct uart_port *port);
@@ -821,6 +823,9 @@ static void atmel_release_rx_dma(struct uart_port *port)
 	atmel_port->desc_rx = NULL;
 	atmel_port->chan_rx = NULL;
 	atmel_port->cookie_rx = -EINVAL;
+
+	if (port->line == 0)
+		del_timer_sync(&atmel_port->uart_timer);
 }
 
 static void atmel_rx_from_dma(struct uart_port *port)
@@ -950,6 +955,15 @@ chan_err:
 	return -EINVAL;
 }
 
+static void atmel_uart_timer_callback(unsigned long data)
+{
+	struct uart_port *port = (void *)data;
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+
+	tasklet_schedule(&atmel_port->tasklet);
+	mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
+}
+
 /*
  * receive interrupt handler.
  */
@@ -1213,6 +1227,9 @@ static void atmel_release_rx_pdc(struct uart_port *port)
 				 DMA_FROM_DEVICE);
 		kfree(pdc->buf);
 	}
+
+	if (port->line == 0)
+		del_timer_sync(&atmel_port->uart_timer);
 }
 
 static void atmel_rx_from_pdc(struct uart_port *port)
@@ -1546,17 +1563,36 @@ static int atmel_startup(struct uart_port *port)
 
 	if (atmel_use_pdc_rx(port)) {
 		/* set UART timeout */
-		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-		UART_PUT_CR(port, ATMEL_US_STTTO);
+		if (port->line == 0) {
+			setup_timer(&atmel_port->uart_timer,
+					atmel_uart_timer_callback,
+					(unsigned long)port);
+			mod_timer(&atmel_port->uart_timer,
+					jiffies + uart_poll_timeout(port));
+		/* set USART timeout */
+		} else {
+			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+			UART_PUT_CR(port, ATMEL_US_STTTO);
 
-		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+			UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+		}
 		/* enable PDC controller */
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
 	} else if (atmel_use_dma_rx(port)) {
-		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
-		UART_PUT_CR(port, ATMEL_US_STTTO);
+		/* set UART timeout */
+		if (port->line == 0) {
+			setup_timer(&atmel_port->uart_timer,
+					atmel_uart_timer_callback,
+					(unsigned long)port);
+			mod_timer(&atmel_port->uart_timer,
+					jiffies + uart_poll_timeout(port));
+		/* set USART timeout */
+		} else {
+			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
+			UART_PUT_CR(port, ATMEL_US_STTTO);
 
-		UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+			UART_PUT_IER(port, ATMEL_US_TIMEOUT);
+		}
 	} else {
 		/* enable receive only */
 		UART_PUT_IER(port, ATMEL_US_RXRDY);
-- 
1.7.9.5

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

* [PATCH V2 7/8] serial: at91: distinguish usart and uart
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (5 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-16  2:43 ` [PATCH V2 8/8] serial: at91: modify UART to use software timer to trigger rx Elen Song
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Distinguish usart and uart by read ip name register,
dbgu regards as uart.

Signed-off-by: Elen Song <elen.song@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |   37 +++++++++++++++++++++++++++++++++++++
 include/linux/atmel_serial.h      |    2 ++
 2 files changed, 39 insertions(+)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index afecdfa..769b90b 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -99,6 +99,7 @@ static void atmel_stop_rx(struct uart_port *port);
 #define UART_PUT_BRGR(port,v)	__raw_writel(v, (port)->membase + ATMEL_US_BRGR)
 #define UART_PUT_RTOR(port,v)	__raw_writel(v, (port)->membase + ATMEL_US_RTOR)
 #define UART_PUT_TTGR(port, v)	__raw_writel(v, (port)->membase + ATMEL_US_TTGR)
+#define UART_GET_IP_NAME(port)	__raw_readl((port)->membase + ATMEL_US_NAME)
 
  /* PDC registers */
 #define UART_PUT_PTCR(port,v)	__raw_writel(v, (port)->membase + ATMEL_PDC_PTCR)
@@ -169,6 +170,7 @@ struct atmel_uart_port {
 	struct serial_rs485	rs485;		/* rs485 settings */
 	unsigned int		tx_done_mask;
 	struct timer_list       uart_timer;     /* dbgu timer */
+	bool			is_usart;	/* usart or uart */
 	int (*prepare_rx)(struct uart_port *port);
 	int (*prepare_tx)(struct uart_port *port);
 	void (*schedule_rx)(struct uart_port *port);
@@ -1496,6 +1498,34 @@ static void atmel_set_ops(struct uart_port *port)
 }
 
 /*
+ * Get ip name usart or uart
+ */
+static int atmel_get_ip_name(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+	int name = UART_GET_IP_NAME(port);
+	int usart, uart;
+	/* usart and uart ascii */
+	usart = 0x55534152;
+	uart = 0x44424755;
+
+	atmel_port->is_usart = false;
+
+	if (name == usart) {
+		dev_dbg(port->dev, "This is usart\n");
+		atmel_port->is_usart = true;
+	} else if (name == uart) {
+		dev_dbg(port->dev, "This is uart\n");
+		atmel_port->is_usart = false;
+	} else {
+		dev_err(port->dev, "Not supported ip name, set to uart\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/*
  * Perform initialization and enable port for reception
  */
 static int atmel_startup(struct uart_port *port)
@@ -2359,6 +2389,13 @@ static int atmel_serial_probe(struct platform_device *pdev)
 		UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
 	}
 
+	/*
+	 * Get port name of usart or uart
+	 */
+	ret = atmel_get_ip_name(&port->uart);
+	if (ret < 0)
+		goto err_add_port;
+
 	return 0;
 
 err_add_port:
diff --git a/include/linux/atmel_serial.h b/include/linux/atmel_serial.h
index fd68337..be201ca 100644
--- a/include/linux/atmel_serial.h
+++ b/include/linux/atmel_serial.h
@@ -124,4 +124,6 @@
 #define ATMEL_US_NER		0x44			/* Number of Errors Register */
 #define ATMEL_US_IF		0x4c			/* IrDA Filter Register */
 
+#define ATMEL_US_NAME		0xf0			/* Ip Name */
+
 #endif
-- 
1.7.9.5

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

* [PATCH V2 8/8] serial: at91: modify UART to use software timer to trigger rx
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (6 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V2 7/8] serial: at91: distinguish usart and uart Elen Song
@ 2013-07-16  2:43 ` Elen Song
  2013-07-18  7:48 ` [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Jean-Christophe PLAGNIOL-VILLARD
  2013-07-18  8:19 ` Jean-Christophe PLAGNIOL-VILLARD
  9 siblings, 0 replies; 17+ messages in thread
From: Elen Song @ 2013-07-16  2:43 UTC (permalink / raw)
  To: linux-arm-kernel

Signed-off-by: Elen Song <elen.song@atmel.com>
---
 drivers/tty/serial/atmel_serial.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 769b90b..67617a8 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -826,7 +826,7 @@ static void atmel_release_rx_dma(struct uart_port *port)
 	atmel_port->chan_rx = NULL;
 	atmel_port->cookie_rx = -EINVAL;
 
-	if (port->line == 0)
+	if (!atmel_port->is_usart)
 		del_timer_sync(&atmel_port->uart_timer);
 }
 
@@ -1230,7 +1230,7 @@ static void atmel_release_rx_pdc(struct uart_port *port)
 		kfree(pdc->buf);
 	}
 
-	if (port->line == 0)
+	if (!atmel_port->is_usart)
 		del_timer_sync(&atmel_port->uart_timer);
 }
 
@@ -1593,7 +1593,7 @@ static int atmel_startup(struct uart_port *port)
 
 	if (atmel_use_pdc_rx(port)) {
 		/* set UART timeout */
-		if (port->line == 0) {
+		if (!atmel_port->is_usart) {
 			setup_timer(&atmel_port->uart_timer,
 					atmel_uart_timer_callback,
 					(unsigned long)port);
@@ -1610,7 +1610,7 @@ static int atmel_startup(struct uart_port *port)
 		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
 	} else if (atmel_use_dma_rx(port)) {
 		/* set UART timeout */
-		if (port->line == 0) {
+		if (!atmel_port->is_usart) {
 			setup_timer(&atmel_port->uart_timer,
 					atmel_uart_timer_callback,
 					(unsigned long)port);
-- 
1.7.9.5

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

* [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (7 preceding siblings ...)
  2013-07-16  2:43 ` [PATCH V2 8/8] serial: at91: modify UART to use software timer to trigger rx Elen Song
@ 2013-07-18  7:48 ` Jean-Christophe PLAGNIOL-VILLARD
  2013-07-18  8:19 ` Jean-Christophe PLAGNIOL-VILLARD
  9 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  7:48 UTC (permalink / raw)
  To: linux-arm-kernel

On 10:43 Tue 16 Jul     , Elen Song wrote:
> After at91sam9g45 socs, the usart only support dma transfer.
> This patch serial focus on:
> 1) distinguish pdc and dma transfer
> 2) support usart dma rx and tx transfer
> 3) distinguish usart and uart
> 4) support uart dma rx and tx transfer
> 
> For those only support PDC transfer socs, we use "atmel,use-dma-rx/tx" to establish a PDC transfer.
> For those only support DMA transfer socs, we not only use "atmel,use-dma-rx/tx", but also describe dma binding to establish a DMA transfer. 
> We switch the name from "use-dma" to "use-pdc" in serial driver to state more clearly.
> We also distinguish usart and uart by read ip name, the dbgu is regard as a uart.
> Because uart lack timeout function, we use software timer to trigger rx.
> 
> Compare to v1, this patch serials improve:
> 1) use function pointer instead of if/else
> 2) "atmel,use-dma-rx/tx" represent a PDC transfer,
>    but when add the dma bindings, it is a dma transfer
> 3) do not use strncmp in get ip name
> 4) remove modification in documentation part

please next time update this too when sending a new verison as I was nearly
NACKing it as I thought it was the same version

Please be carefull next time

Best Regards,
J.
> 
> Elen Song (7):
>   serial: at91: correct definition from DMA to PDC
>   serial: at91: add tx dma support
>   serial: at91: add rx dma support
>   serial: at91: make DBGU support dma and pdc transfers
>   serial: at91: distinguish usart and uart
>   serial: at91: modify UART to use software timer to trigger rx
>   serial: at91: add dma support in usart binding descriptions
> 
>  Documentation/devicetree/bindings/serial/rs485.txt |    4 +-
>  .../devicetree/bindings/tty/serial/atmel-usart.txt |   29 +-
>  arch/arm/boot/dts/at91rm9200.dtsi                  |   16 +-
>  arch/arm/boot/dts/at91sam9260.dtsi                 |   24 +-
>  arch/arm/boot/dts/at91sam9263.dtsi                 |   12 +-
>  arch/arm/boot/dts/at91sam9g45.dtsi                 |   16 +-
>  arch/arm/mach-at91/at91rm9200_devices.c            |   20 +-
>  arch/arm/mach-at91/at91sam9260_devices.c           |   28 +-
>  arch/arm/mach-at91/at91sam9261_devices.c           |   16 +-
>  arch/arm/mach-at91/at91sam9263_devices.c           |   16 +-
>  arch/arm/mach-at91/at91sam9g45_devices.c           |   20 +-
>  arch/arm/mach-at91/at91sam9rl_devices.c            |   20 +-
>  drivers/tty/serial/atmel_serial.c                  |  582 ++++++++++++++++++--
>  include/linux/atmel_serial.h                       |    2 +
>  include/linux/platform_data/atmel.h                |    2 +
>  15 files changed, 665 insertions(+), 142 deletions(-)
> 
> -- 
> 1.7.9.5
> 

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

* [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC
  2013-07-16  2:43 ` [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC Elen Song
@ 2013-07-18  7:49   ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  7:49 UTC (permalink / raw)
  To: linux-arm-kernel

On 10:43 Tue 16 Jul     , Elen Song wrote:
> The DMA is available since at91sam9x5 socs, before that, we use PDC.
> 
> Signed-off-by: Elen Song <elen.song@atmel.com>
> ---
>  drivers/tty/serial/atmel_serial.c |   71 +++++++++++++++++++------------------
>  1 file changed, 36 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 3467462..6c71ccf 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -140,11 +140,11 @@ struct atmel_uart_port {
>  	u32			backup_imr;	/* IMR saved during suspend */
>  	int			break_active;	/* break being received */
>  
> -	short			use_dma_rx;	/* enable PDC receiver */
> +	short			use_pdc_rx;	/* enable PDC receiver */
	as this is a boolean you should update the type too
>  	short			pdc_rx_idx;	/* current PDC RX buffer */
>  	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
>  
> -	short			use_dma_tx;	/* enable PDC transmitter */
> +	short			use_pdc_tx;	/* enable PDC transmitter */
ditto
>  	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
>  
>  	struct tasklet_struct	tasklet;
> @@ -181,26 +181,26 @@ to_atmel_uart_port(struct uart_port *uart)
>  }
>  
>  #ifdef CONFIG_SERIAL_ATMEL_PDC
> -static bool atmel_use_dma_rx(struct uart_port *port)
> +static bool atmel_use_pdc_rx(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	return atmel_port->use_dma_rx;
> +	return atmel_port->use_pdc_rx;
>  }
>  
> -static bool atmel_use_dma_tx(struct uart_port *port)
> +static bool atmel_use_pdc_tx(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	return atmel_port->use_dma_tx;
> +	return atmel_port->use_pdc_tx;
>  }
>  #else
> -static bool atmel_use_dma_rx(struct uart_port *port)
> +static bool atmel_use_pdc_rx(struct uart_port *port)
>  {
>  	return false;
>  }
>  
> -static bool atmel_use_dma_tx(struct uart_port *port)
> +static bool atmel_use_pdc_tx(struct uart_port *port)
>  {
>  	return false;
>  }
> @@ -233,7 +233,7 @@ void atmel_config_rs485(struct uart_port *port, struct serial_rs485 *rs485conf)
>  		mode |= ATMEL_US_USMODE_RS485;
>  	} else {
>  		dev_dbg(port->dev, "Setting UART to RS232\n");
> -		if (atmel_use_dma_tx(port))
> +		if (atmel_use_pdc_tx(port))
>  			atmel_port->tx_done_mask = ATMEL_US_ENDTX |
>  				ATMEL_US_TXBUFE;
>  		else
> @@ -345,7 +345,7 @@ static void atmel_stop_tx(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	if (atmel_use_dma_tx(port)) {
> +	if (atmel_use_pdc_tx(port)) {
>  		/* disable PDC transmit */
>  		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);
>  	}
> @@ -364,7 +364,7 @@ static void atmel_start_tx(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	if (atmel_use_dma_tx(port)) {
> +	if (atmel_use_pdc_tx(port)) {
>  		if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
>  			/* The transmitter is already running.  Yes, we
>  			   really need this.*/
> @@ -390,7 +390,7 @@ static void atmel_start_rx(struct uart_port *port)
>  
>  	UART_PUT_CR(port, ATMEL_US_RXEN);
>  
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		/* enable PDC controller */
>  		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
>  			port->read_status_mask);
> @@ -407,7 +407,7 @@ static void atmel_stop_rx(struct uart_port *port)
>  {
>  	UART_PUT_CR(port, ATMEL_US_RXDIS);
>  
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		/* disable PDC receive */
>  		UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);
>  		UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT |
> @@ -572,7 +572,7 @@ atmel_handle_receive(struct uart_port *port, unsigned int pending)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		/*
>  		 * PDC receive. Just schedule the tasklet and let it
>  		 * figure out the details.
> @@ -661,7 +661,7 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id)
>  /*
>   * Called from tasklet with ENDTX and TXBUFE interrupts disabled.
>   */
> -static void atmel_tx_dma(struct uart_port *port)
> +static void atmel_tx_pdc(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	struct circ_buf *xmit = &port->state->xmit;
> @@ -778,7 +778,7 @@ static void atmel_rx_from_ring(struct uart_port *port)
>  	spin_lock(&port->lock);
>  }
>  
> -static void atmel_rx_from_dma(struct uart_port *port)
> +static void atmel_rx_from_pdc(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	struct tty_port *tport = &port->state->port;
> @@ -868,8 +868,8 @@ static void atmel_tasklet_func(unsigned long data)
>  	/* The interrupt handler does not take the lock */
>  	spin_lock(&port->lock);
>  
> -	if (atmel_use_dma_tx(port))
> -		atmel_tx_dma(port);
> +	if (atmel_use_pdc_tx(port))
> +		atmel_tx_pdc(port);
>  	else
>  		atmel_tx_chars(port);
>  
> @@ -893,8 +893,8 @@ static void atmel_tasklet_func(unsigned long data)
>  		atmel_port->irq_status_prev = status;
>  	}
>  
> -	if (atmel_use_dma_rx(port))
> -		atmel_rx_from_dma(port);
> +	if (atmel_use_pdc_rx(port))
> +		atmel_rx_from_pdc(port);
>  	else
>  		atmel_rx_from_ring(port);
>  
> @@ -930,7 +930,7 @@ static int atmel_startup(struct uart_port *port)
>  	/*
>  	 * Initialize DMA (if necessary)
>  	 */
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		int i;
>  
>  		for (i = 0; i < 2; i++) {
> @@ -964,7 +964,7 @@ static int atmel_startup(struct uart_port *port)
>  		UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
>  		UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
>  	}
> -	if (atmel_use_dma_tx(port)) {
> +	if (atmel_use_pdc_tx(port)) {
>  		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
>  		struct circ_buf *xmit = &port->state->xmit;
>  
> @@ -1000,7 +1000,7 @@ static int atmel_startup(struct uart_port *port)
>  	/* enable xmit & rcvr */
>  	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);
>  
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		/* set UART timeout */
>  		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
>  		UART_PUT_CR(port, ATMEL_US_STTTO);
> @@ -1031,7 +1031,7 @@ static void atmel_shutdown(struct uart_port *port)
>  	/*
>  	 * Shut-down the DMA.
>  	 */
> -	if (atmel_use_dma_rx(port)) {
> +	if (atmel_use_pdc_rx(port)) {
>  		int i;
>  
>  		for (i = 0; i < 2; i++) {
> @@ -1044,7 +1044,7 @@ static void atmel_shutdown(struct uart_port *port)
>  			kfree(pdc->buf);
>  		}
>  	}
> -	if (atmel_use_dma_tx(port)) {
> +	if (atmel_use_pdc_tx(port)) {
>  		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
>  
>  		dma_unmap_single(port->dev,
> @@ -1080,7 +1080,7 @@ static void atmel_flush_buffer(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  
> -	if (atmel_use_dma_tx(port)) {
> +	if (atmel_use_pdc_tx(port)) {
>  		UART_PUT_TCR(port, 0);
>  		atmel_port->pdc_tx.ofs = 0;
>  	}
> @@ -1193,7 +1193,7 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
>  	if (termios->c_iflag & (BRKINT | PARMRK))
>  		port->read_status_mask |= ATMEL_US_RXBRK;
>  
> -	if (atmel_use_dma_rx(port))
> +	if (atmel_use_pdc_rx(port))
>  		/* need to enable error interrupts */
>  		UART_PUT_IER(port, port->read_status_mask);
>  
> @@ -1430,13 +1430,14 @@ static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
>  
>  	/* DMA/PDC usage specification */
>  	if (of_get_property(np, "atmel,use-dma-rx", NULL))
> -		atmel_port->use_dma_rx	= 1;
> +		atmel_port->use_pdc_rx	= 1;
>  	else
> -		atmel_port->use_dma_rx	= 0;
> +		atmel_port->use_pdc_rx	= 0;
> +
>  	if (of_get_property(np, "atmel,use-dma-tx", NULL))
> -		atmel_port->use_dma_tx	= 1;
> +		atmel_port->use_pdc_tx	= 1;
>  	else
> -		atmel_port->use_dma_tx	= 0;
> +		atmel_port->use_pdc_tx	= 0;
>  
>  	/* rs485 properties */
>  	if (of_property_read_u32_array(np, "rs485-rts-delay",
> @@ -1467,8 +1468,8 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
>  	if (pdev->dev.of_node) {
>  		atmel_of_init_port(atmel_port, pdev->dev.of_node);
>  	} else {
> -		atmel_port->use_dma_rx	= pdata->use_dma_rx;
> -		atmel_port->use_dma_tx	= pdata->use_dma_tx;
> +		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
> +		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
>  		atmel_port->rs485	= pdata->rs485;
>  	}
>  
> @@ -1505,7 +1506,7 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
>  	/* Use TXEMPTY for interrupt when rs485 else TXRDY or ENDTX|TXBUFE */
>  	if (atmel_port->rs485.flags & SER_RS485_ENABLED)
>  		atmel_port->tx_done_mask = ATMEL_US_TXEMPTY;
> -	else if (atmel_use_dma_tx(port)) {
> +	else if (atmel_use_pdc_tx(port)) {
>  		port->fifosize = PDC_BUFFER_SIZE;
>  		atmel_port->tx_done_mask = ATMEL_US_ENDTX | ATMEL_US_TXBUFE;
>  	} else {
> @@ -1794,7 +1795,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
>  		goto err;
>  	}
>  
> -	if (!atmel_use_dma_rx(&port->uart)) {
> +	if (!atmel_use_pdc_rx(&port->uart)) {
>  		ret = -ENOMEM;
>  		data = kmalloc(sizeof(struct atmel_uart_char)
>  				* ATMEL_SERIAL_RINGSIZE, GFP_KERNEL);
> -- 
> 1.7.9.5
> 

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

* [PATCH V2 5/8] serial: at91: support run time switch transfer mode
  2013-07-16  2:43 ` [PATCH V2 5/8] serial: at91: support run time switch transfer mode Elen Song
@ 2013-07-18  8:15   ` Jean-Christophe PLAGNIOL-VILLARD
  2013-07-18  9:21     ` elen.song
       [not found]     ` <51E7A756.6010004@atmel.com>
  0 siblings, 2 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:15 UTC (permalink / raw)
  To: linux-arm-kernel

On 10:43 Tue 16 Jul     , Elen Song wrote:
> We will switch to pio mode when request of dma or pdc fail.
> But soon or later, when the request is success, the transfer mode can switch to them at
> next open serial port action.
> So in startup stage, we should get original transfer mode.

You need to update the Documentation of the binding to said the driver support
dmas bindings for the new IP

and please use true/false for boolean

and check the white space
> 
> Signed-off-by: Elen Song <elen.song@atmel.com>
> ---
>  drivers/tty/serial/atmel_serial.c |  139 +++++++++++++++++++++----------------
>  1 file changed, 80 insertions(+), 59 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 298b58c..ad787fd1 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -1371,6 +1371,80 @@ static void atmel_tasklet_func(unsigned long data)
>  	spin_unlock(&port->lock);
>  }
>  
> +static int atmel_init_property(struct atmel_uart_port *atmel_port,
> +				struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
> +
> +	if (np) {
> +		/* DMA/PDC usage specification */
> +		if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
> +			if (of_get_property(np, "dmas", NULL)) {
> +				atmel_port->use_dma_rx  = 1;
> +				atmel_port->use_pdc_rx  = 0;
> +			} else {
> +				atmel_port->use_dma_rx  = 0;
> +				atmel_port->use_pdc_rx  = 1;
> +			}
> +		} else {
> +			atmel_port->use_dma_rx  = 0;
> +			atmel_port->use_pdc_rx  = 0;
> +		}
> +
> +		if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
> +			if (of_get_property(np, "dmas", NULL)) {
> +				atmel_port->use_dma_tx  = 1;
> +				atmel_port->use_pdc_tx  = 0;
> +			} else {
> +				atmel_port->use_dma_tx  = 0;
> +				atmel_port->use_pdc_tx  = 1;
> +			}
> +		} else {
> +			atmel_port->use_dma_tx  = 0;
> +			atmel_port->use_pdc_tx  = 0;
> +		}
> +
> +	} else {
> +		atmel_port->use_pdc_rx  = pdata->use_dma_rx;
> +		atmel_port->use_pdc_tx  = pdata->use_dma_tx;
> +		atmel_port->use_dma_rx  = 0;
> +		atmel_port->use_dma_tx  = 0;
> +	}
> +
> +	return 0;
> +}
> +
> +static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
> +				struct platform_device *pdev)
> +{
> +	struct device_node *np = pdev->dev.of_node;
> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
> +
> +	if (np) {
> +		u32 rs485_delay[2];
> +		/* rs485 properties */
> +		if (of_property_read_u32_array(np, "rs485-rts-delay",
> +					rs485_delay, 2) == 0) {
> +			struct serial_rs485 *rs485conf = &atmel_port->rs485;
> +
> +			rs485conf->delay_rts_before_send = rs485_delay[0];
> +			rs485conf->delay_rts_after_send = rs485_delay[1];
> +			rs485conf->flags = 0;
> +
> +		if (of_get_property(np, "rs485-rx-during-tx", NULL))
> +			rs485conf->flags |= SER_RS485_RX_DURING_TX;
> +
> +		if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
> +								NULL))
> +			rs485conf->flags |= SER_RS485_ENABLED;
> +		}
> +	} else {
> +		atmel_port->rs485       = pdata->rs485;
> +	}
> +
> +}
> +
>  static void atmel_set_ops(struct uart_port *port)
>  {
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> @@ -1409,6 +1483,7 @@ static void atmel_set_ops(struct uart_port *port)
>   */
>  static int atmel_startup(struct uart_port *port)
>  {
> +	struct platform_device *pdev = to_platform_device(port->dev);
>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>  	struct tty_struct *tty = port->state->port.tty;
>  	int retval;
> @@ -1433,6 +1508,8 @@ static int atmel_startup(struct uart_port *port)
>  	/*
>  	 * Initialize DMA (if necessary)
>  	 */
> +	atmel_init_property(atmel_port, pdev);
> +
>  	if (atmel_port->prepare_rx) {
>  		retval = atmel_port->prepare_rx(port);
>  		if (retval < 0)
> @@ -1878,55 +1955,6 @@ static struct uart_ops atmel_pops = {
>  #endif
>  };
>  
> -static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
> -					 struct device_node *np)
> -{
> -	u32 rs485_delay[2];
> -
> -	/* DMA/PDC usage specification */
> -	if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
> -		if (of_get_property(np, "dmas", NULL)) {
> -			atmel_port->use_dma_rx	= 1;
> -			atmel_port->use_pdc_rx	= 0;
> -		} else {
> -			atmel_port->use_dma_rx	= 0;
> -			atmel_port->use_pdc_rx	= 1;
> -		}
> -	} else {
> -		atmel_port->use_dma_rx	= 0;
> -		atmel_port->use_pdc_rx	= 0;
> -	}
> -
> -	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
> -		if (of_get_property(np, "dmas", NULL)) {
> -			atmel_port->use_dma_tx	= 1;
> -			atmel_port->use_pdc_tx	= 0;
> -		} else {
> -			atmel_port->use_dma_tx	= 0;
> -			atmel_port->use_pdc_tx	= 1;
> -		}
> -	} else {
> -		atmel_port->use_dma_tx	= 0;
> -		atmel_port->use_pdc_tx	= 0;
> -	}
> -
> -	/* rs485 properties */
> -	if (of_property_read_u32_array(np, "rs485-rts-delay",
> -					    rs485_delay, 2) == 0) {
> -		struct serial_rs485 *rs485conf = &atmel_port->rs485;
> -
> -		rs485conf->delay_rts_before_send = rs485_delay[0];
> -		rs485conf->delay_rts_after_send = rs485_delay[1];
> -		rs485conf->flags = 0;
> -
> -		if (of_get_property(np, "rs485-rx-during-tx", NULL))
> -			rs485conf->flags |= SER_RS485_RX_DURING_TX;
> -
> -		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
> -			rs485conf->flags |= SER_RS485_ENABLED;
> -	}
> -}
> -
>  /*
>   * Configure the port from the platform device resource info.
>   */
> @@ -1936,17 +1964,10 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
>  	struct uart_port *port = &atmel_port->uart;
>  	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>  
> -	if (pdev->dev.of_node) {
> -		atmel_of_init_port(atmel_port, pdev->dev.of_node);
> -	} else {
> -		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
> -		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
> -		atmel_port->use_dma_rx	= 0;
> -		atmel_port->use_dma_tx	= 0;
> -		atmel_port->rs485	= pdata->rs485;
> -	}
> +	if (!atmel_init_property(atmel_port, pdev))
> +		atmel_set_ops(port);
>  
> -	atmel_set_ops(port);
> +	atmel_init_rs485(atmel_port, pdev);
>  
>  	port->iotype		= UPIO_MEM;
>  	port->flags		= UPF_BOOT_AUTOCONF;
> -- 
> 1.7.9.5
> 

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

* [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers
  2013-07-16  2:43 ` [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers Elen Song
@ 2013-07-18  8:18   ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:18 UTC (permalink / raw)
  To: linux-arm-kernel

On 10:43 Tue 16 Jul     , Elen Song wrote:
> Because the DBGU lack of receive timeout register, so we use a timer to trigger
> data receive.

please re-order the patch put patch 7 before 6
so we can distinguish the uart type not by line = 0 which is wrong as if you
can have no dbgu registered and line == 0 can be a normal usart

Best Regards,
J.
> 
> Signed-off-by: Elen Song <elen.song@atmel.com>
> Signed-off-by: Ludovic Desroches <ludovic.desroches@atmel.com>
> ---
>  drivers/tty/serial/atmel_serial.c |   48 ++++++++++++++++++++++++++++++++-----
>  1 file changed, 42 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index ad787fd1..afecdfa 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -41,6 +41,7 @@
>  #include <linux/uaccess.h>
>  #include <linux/pinctrl/consumer.h>
>  #include <linux/platform_data/atmel.h>
> +#include <linux/timer.h>
>  
>  #include <asm/io.h>
>  #include <asm/ioctls.h>
> @@ -167,6 +168,7 @@ struct atmel_uart_port {
>  
>  	struct serial_rs485	rs485;		/* rs485 settings */
>  	unsigned int		tx_done_mask;
> +	struct timer_list       uart_timer;     /* dbgu timer */
>  	int (*prepare_rx)(struct uart_port *port);
>  	int (*prepare_tx)(struct uart_port *port);
>  	void (*schedule_rx)(struct uart_port *port);
> @@ -821,6 +823,9 @@ static void atmel_release_rx_dma(struct uart_port *port)
>  	atmel_port->desc_rx = NULL;
>  	atmel_port->chan_rx = NULL;
>  	atmel_port->cookie_rx = -EINVAL;
> +
> +	if (port->line == 0)
> +		del_timer_sync(&atmel_port->uart_timer);
>  }
>  
>  static void atmel_rx_from_dma(struct uart_port *port)
> @@ -950,6 +955,15 @@ chan_err:
>  	return -EINVAL;
>  }
>  
> +static void atmel_uart_timer_callback(unsigned long data)
> +{
> +	struct uart_port *port = (void *)data;
> +	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
> +
> +	tasklet_schedule(&atmel_port->tasklet);
> +	mod_timer(&atmel_port->uart_timer, jiffies + uart_poll_timeout(port));
> +}
> +
>  /*
>   * receive interrupt handler.
>   */
> @@ -1213,6 +1227,9 @@ static void atmel_release_rx_pdc(struct uart_port *port)
>  				 DMA_FROM_DEVICE);
>  		kfree(pdc->buf);
>  	}
> +
> +	if (port->line == 0)
> +		del_timer_sync(&atmel_port->uart_timer);
>  }
>  
>  static void atmel_rx_from_pdc(struct uart_port *port)
> @@ -1546,17 +1563,36 @@ static int atmel_startup(struct uart_port *port)
>  
>  	if (atmel_use_pdc_rx(port)) {
>  		/* set UART timeout */
> -		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
> -		UART_PUT_CR(port, ATMEL_US_STTTO);
> +		if (port->line == 0) {
> +			setup_timer(&atmel_port->uart_timer,
> +					atmel_uart_timer_callback,
> +					(unsigned long)port);
> +			mod_timer(&atmel_port->uart_timer,
> +					jiffies + uart_poll_timeout(port));
> +		/* set USART timeout */
> +		} else {
> +			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
> +			UART_PUT_CR(port, ATMEL_US_STTTO);
>  
> -		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
> +			UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
> +		}
>  		/* enable PDC controller */
>  		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);
>  	} else if (atmel_use_dma_rx(port)) {
> -		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
> -		UART_PUT_CR(port, ATMEL_US_STTTO);
> +		/* set UART timeout */
> +		if (port->line == 0) {
> +			setup_timer(&atmel_port->uart_timer,
> +					atmel_uart_timer_callback,
> +					(unsigned long)port);
> +			mod_timer(&atmel_port->uart_timer,
> +					jiffies + uart_poll_timeout(port));
> +		/* set USART timeout */
> +		} else {
> +			UART_PUT_RTOR(port, PDC_RX_TIMEOUT);
> +			UART_PUT_CR(port, ATMEL_US_STTTO);
>  
> -		UART_PUT_IER(port, ATMEL_US_TIMEOUT);
> +			UART_PUT_IER(port, ATMEL_US_TIMEOUT);
> +		}
>  	} else {
>  		/* enable receive only */
>  		UART_PUT_IER(port, ATMEL_US_RXRDY);
> -- 
> 1.7.9.5
> 

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

* [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer
  2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
                   ` (8 preceding siblings ...)
  2013-07-18  7:48 ` [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Jean-Christophe PLAGNIOL-VILLARD
@ 2013-07-18  8:19 ` Jean-Christophe PLAGNIOL-VILLARD
  9 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18  8:19 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

	except the comment this looks good

Best Regards,
J.
On 10:43 Tue 16 Jul     , Elen Song wrote:
> After at91sam9g45 socs, the usart only support dma transfer.
> This patch serial focus on:
> 1) distinguish pdc and dma transfer
> 2) support usart dma rx and tx transfer
> 3) distinguish usart and uart
> 4) support uart dma rx and tx transfer
> 
> For those only support PDC transfer socs, we use "atmel,use-dma-rx/tx" to establish a PDC transfer.
> For those only support DMA transfer socs, we not only use "atmel,use-dma-rx/tx", but also describe dma binding to establish a DMA transfer. 
> We switch the name from "use-dma" to "use-pdc" in serial driver to state more clearly.
> We also distinguish usart and uart by read ip name, the dbgu is regard as a uart.
> Because uart lack timeout function, we use software timer to trigger rx.
> 
> Compare to v1, this patch serials improve:
> 1) use function pointer instead of if/else
> 2) "atmel,use-dma-rx/tx" represent a PDC transfer,
>    but when add the dma bindings, it is a dma transfer
> 3) do not use strncmp in get ip name
> 4) remove modification in documentation part
> 
> Elen Song (7):
>   serial: at91: correct definition from DMA to PDC
>   serial: at91: add tx dma support
>   serial: at91: add rx dma support
>   serial: at91: make DBGU support dma and pdc transfers
>   serial: at91: distinguish usart and uart
>   serial: at91: modify UART to use software timer to trigger rx
>   serial: at91: add dma support in usart binding descriptions
> 
>  Documentation/devicetree/bindings/serial/rs485.txt |    4 +-
>  .../devicetree/bindings/tty/serial/atmel-usart.txt |   29 +-
>  arch/arm/boot/dts/at91rm9200.dtsi                  |   16 +-
>  arch/arm/boot/dts/at91sam9260.dtsi                 |   24 +-
>  arch/arm/boot/dts/at91sam9263.dtsi                 |   12 +-
>  arch/arm/boot/dts/at91sam9g45.dtsi                 |   16 +-
>  arch/arm/mach-at91/at91rm9200_devices.c            |   20 +-
>  arch/arm/mach-at91/at91sam9260_devices.c           |   28 +-
>  arch/arm/mach-at91/at91sam9261_devices.c           |   16 +-
>  arch/arm/mach-at91/at91sam9263_devices.c           |   16 +-
>  arch/arm/mach-at91/at91sam9g45_devices.c           |   20 +-
>  arch/arm/mach-at91/at91sam9rl_devices.c            |   20 +-
>  drivers/tty/serial/atmel_serial.c                  |  582 ++++++++++++++++++--
>  include/linux/atmel_serial.h                       |    2 +
>  include/linux/platform_data/atmel.h                |    2 +
>  15 files changed, 665 insertions(+), 142 deletions(-)
> 
> -- 
> 1.7.9.5
> 

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

* [PATCH V2 5/8] serial: at91: support run time switch transfer mode
  2013-07-18  8:15   ` Jean-Christophe PLAGNIOL-VILLARD
@ 2013-07-18  9:21     ` elen.song
  2013-07-18 12:36       ` Nicolas Ferre
       [not found]     ` <51E7A756.6010004@atmel.com>
  1 sibling, 1 reply; 17+ messages in thread
From: elen.song @ 2013-07-18  9:21 UTC (permalink / raw)
  To: linux-arm-kernel

Hi JC:
On 7/18/2013 4:15 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
> On 10:43 Tue 16 Jul     , Elen Song wrote:
>> We will switch to pio mode when request of dma or pdc fail.
>> But soon or later, when the request is success, the transfer mode can switch to them at
>> next open serial port action.
>> So in startup stage, we should get original transfer mode.
> You need to update the Documentation of the binding to said the driver support
> dmas bindings for the new IP

one question, it seems the document should write like:

use DMA:
     usart0: serial at f001c000{
         compatible = "atmel,at91sam9260-usart";
         dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>,
                      <&dma0 2 
(AT91_DMA_CFG_PER_ID(3)|AT91_DMA_CFG_FIFOCFG_ASAP)>;
         dma-names = "tx","rx";
};

Should I replace macros with typical values?

Best regards
> and please use true/false for boolean
>
> and check the white space
>> Signed-off-by: Elen Song <elen.song@atmel.com>
>> ---
>>   drivers/tty/serial/atmel_serial.c |  139 +++++++++++++++++++++----------------
>>   1 file changed, 80 insertions(+), 59 deletions(-)
>>
>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>> index 298b58c..ad787fd1 100644
>> --- a/drivers/tty/serial/atmel_serial.c
>> +++ b/drivers/tty/serial/atmel_serial.c
>> @@ -1371,6 +1371,80 @@ static void atmel_tasklet_func(unsigned long data)
>>   	spin_unlock(&port->lock);
>>   }
>>   
>> +static int atmel_init_property(struct atmel_uart_port *atmel_port,
>> +				struct platform_device *pdev)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>> +
>> +	if (np) {
>> +		/* DMA/PDC usage specification */
>> +		if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
>> +			if (of_get_property(np, "dmas", NULL)) {
>> +				atmel_port->use_dma_rx  = 1;
>> +				atmel_port->use_pdc_rx  = 0;
>> +			} else {
>> +				atmel_port->use_dma_rx  = 0;
>> +				atmel_port->use_pdc_rx  = 1;
>> +			}
>> +		} else {
>> +			atmel_port->use_dma_rx  = 0;
>> +			atmel_port->use_pdc_rx  = 0;
>> +		}
>> +
>> +		if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
>> +			if (of_get_property(np, "dmas", NULL)) {
>> +				atmel_port->use_dma_tx  = 1;
>> +				atmel_port->use_pdc_tx  = 0;
>> +			} else {
>> +				atmel_port->use_dma_tx  = 0;
>> +				atmel_port->use_pdc_tx  = 1;
>> +			}
>> +		} else {
>> +			atmel_port->use_dma_tx  = 0;
>> +			atmel_port->use_pdc_tx  = 0;
>> +		}
>> +
>> +	} else {
>> +		atmel_port->use_pdc_rx  = pdata->use_dma_rx;
>> +		atmel_port->use_pdc_tx  = pdata->use_dma_tx;
>> +		atmel_port->use_dma_rx  = 0;
>> +		atmel_port->use_dma_tx  = 0;
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
>> +				struct platform_device *pdev)
>> +{
>> +	struct device_node *np = pdev->dev.of_node;
>> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>> +
>> +	if (np) {
>> +		u32 rs485_delay[2];
>> +		/* rs485 properties */
>> +		if (of_property_read_u32_array(np, "rs485-rts-delay",
>> +					rs485_delay, 2) == 0) {
>> +			struct serial_rs485 *rs485conf = &atmel_port->rs485;
>> +
>> +			rs485conf->delay_rts_before_send = rs485_delay[0];
>> +			rs485conf->delay_rts_after_send = rs485_delay[1];
>> +			rs485conf->flags = 0;
>> +
>> +		if (of_get_property(np, "rs485-rx-during-tx", NULL))
>> +			rs485conf->flags |= SER_RS485_RX_DURING_TX;
>> +
>> +		if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
>> +								NULL))
>> +			rs485conf->flags |= SER_RS485_ENABLED;
>> +		}
>> +	} else {
>> +		atmel_port->rs485       = pdata->rs485;
>> +	}
>> +
>> +}
>> +
>>   static void atmel_set_ops(struct uart_port *port)
>>   {
>>   	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>> @@ -1409,6 +1483,7 @@ static void atmel_set_ops(struct uart_port *port)
>>    */
>>   static int atmel_startup(struct uart_port *port)
>>   {
>> +	struct platform_device *pdev = to_platform_device(port->dev);
>>   	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>>   	struct tty_struct *tty = port->state->port.tty;
>>   	int retval;
>> @@ -1433,6 +1508,8 @@ static int atmel_startup(struct uart_port *port)
>>   	/*
>>   	 * Initialize DMA (if necessary)
>>   	 */
>> +	atmel_init_property(atmel_port, pdev);
>> +
>>   	if (atmel_port->prepare_rx) {
>>   		retval = atmel_port->prepare_rx(port);
>>   		if (retval < 0)
>> @@ -1878,55 +1955,6 @@ static struct uart_ops atmel_pops = {
>>   #endif
>>   };
>>   
>> -static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
>> -					 struct device_node *np)
>> -{
>> -	u32 rs485_delay[2];
>> -
>> -	/* DMA/PDC usage specification */
>> -	if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
>> -		if (of_get_property(np, "dmas", NULL)) {
>> -			atmel_port->use_dma_rx	= 1;
>> -			atmel_port->use_pdc_rx	= 0;
>> -		} else {
>> -			atmel_port->use_dma_rx	= 0;
>> -			atmel_port->use_pdc_rx	= 1;
>> -		}
>> -	} else {
>> -		atmel_port->use_dma_rx	= 0;
>> -		atmel_port->use_pdc_rx	= 0;
>> -	}
>> -
>> -	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
>> -		if (of_get_property(np, "dmas", NULL)) {
>> -			atmel_port->use_dma_tx	= 1;
>> -			atmel_port->use_pdc_tx	= 0;
>> -		} else {
>> -			atmel_port->use_dma_tx	= 0;
>> -			atmel_port->use_pdc_tx	= 1;
>> -		}
>> -	} else {
>> -		atmel_port->use_dma_tx	= 0;
>> -		atmel_port->use_pdc_tx	= 0;
>> -	}
>> -
>> -	/* rs485 properties */
>> -	if (of_property_read_u32_array(np, "rs485-rts-delay",
>> -					    rs485_delay, 2) == 0) {
>> -		struct serial_rs485 *rs485conf = &atmel_port->rs485;
>> -
>> -		rs485conf->delay_rts_before_send = rs485_delay[0];
>> -		rs485conf->delay_rts_after_send = rs485_delay[1];
>> -		rs485conf->flags = 0;
>> -
>> -		if (of_get_property(np, "rs485-rx-during-tx", NULL))
>> -			rs485conf->flags |= SER_RS485_RX_DURING_TX;
>> -
>> -		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
>> -			rs485conf->flags |= SER_RS485_ENABLED;
>> -	}
>> -}
>> -
>>   /*
>>    * Configure the port from the platform device resource info.
>>    */
>> @@ -1936,17 +1964,10 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
>>   	struct uart_port *port = &atmel_port->uart;
>>   	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>>   
>> -	if (pdev->dev.of_node) {
>> -		atmel_of_init_port(atmel_port, pdev->dev.of_node);
>> -	} else {
>> -		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
>> -		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
>> -		atmel_port->use_dma_rx	= 0;
>> -		atmel_port->use_dma_tx	= 0;
>> -		atmel_port->rs485	= pdata->rs485;
>> -	}
>> +	if (!atmel_init_property(atmel_port, pdev))
>> +		atmel_set_ops(port);
>>   
>> -	atmel_set_ops(port);
>> +	atmel_init_rs485(atmel_port, pdev);
>>   
>>   	port->iotype		= UPIO_MEM;
>>   	port->flags		= UPF_BOOT_AUTOCONF;
>> -- 
>> 1.7.9.5
>>

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

* [PATCH V2 5/8] serial: at91: support run time switch transfer mode
       [not found]     ` <51E7A756.6010004@atmel.com>
@ 2013-07-18 10:45       ` Jean-Christophe PLAGNIOL-VILLARD
  0 siblings, 0 replies; 17+ messages in thread
From: Jean-Christophe PLAGNIOL-VILLARD @ 2013-07-18 10:45 UTC (permalink / raw)
  To: linux-arm-kernel


On Jul 18, 2013, at 4:29 PM, elen.song <elen.song@atmel.com> wrote:

> Hi JC:
> On 7/18/2013 4:15 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> On 10:43 Tue 16 Jul     , Elen Song wrote:
>> 
>>> We will switch to pio mode when request of dma or pdc fail.
>>> But soon or later, when the request is success, the transfer mode can switch to them at
>>> next open serial port action.
>>> So in startup stage, we should get original transfer mode.
>>> 
>> You need to update the Documentation of the binding to said the driver support
>> dmas bindings for the new IP
>> 
> one question, it seems the document should write like:
>  
> +- use DMA:
> +       usart0: serial at f001c000 {
> +               compatible = "atmel,at91sam9260-usart";
> +               reg = <0xf001c000 0x100>;
> +               interrupts = <12 IRQ_TYPE_LEVEL_HIGH 5>;
> +               dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>,
> +                      <&dma0 2 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
> +               dma-names = "tx", "rx";
> +       };
> 
> Should I instead macros with typical values?
> 

Value as MACRO is a linux artefact

Best Regards,
J.


> Best regards
>>  
>> and please use true/false for boolean
>> 
>> and check the white space
>> 
>>> Signed-off-by: Elen Song <elen.song@atmel.com>
>>> 
>>> ---
>>>  drivers/tty/serial/atmel_serial.c |  139 +++++++++++++++++++++----------------
>>>  1 file changed, 80 insertions(+), 59 deletions(-)
>>> 
>>> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
>>> index 298b58c..ad787fd1 100644
>>> --- a/drivers/tty/serial/atmel_serial.c
>>> +++ b/drivers/tty/serial/atmel_serial.c
>>> @@ -1371,6 +1371,80 @@ static void atmel_tasklet_func(unsigned long data)
>>>  	spin_unlock(&port->lock);
>>>  }
>>>  
>>> +static int atmel_init_property(struct atmel_uart_port *atmel_port,
>>> +				struct platform_device *pdev)
>>> +{
>>> +	struct device_node *np = pdev->dev.of_node;
>>> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>>> +
>>> +	if (np) {
>>> +		/* DMA/PDC usage specification */
>>> +		if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
>>> +			if (of_get_property(np, "dmas", NULL)) {
>>> +				atmel_port->use_dma_rx  = 1;
>>> +				atmel_port->use_pdc_rx  = 0;
>>> +			} else {
>>> +				atmel_port->use_dma_rx  = 0;
>>> +				atmel_port->use_pdc_rx  = 1;
>>> +			}
>>> +		} else {
>>> +			atmel_port->use_dma_rx  = 0;
>>> +			atmel_port->use_pdc_rx  = 0;
>>> +		}
>>> +
>>> +		if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
>>> +			if (of_get_property(np, "dmas", NULL)) {
>>> +				atmel_port->use_dma_tx  = 1;
>>> +				atmel_port->use_pdc_tx  = 0;
>>> +			} else {
>>> +				atmel_port->use_dma_tx  = 0;
>>> +				atmel_port->use_pdc_tx  = 1;
>>> +			}
>>> +		} else {
>>> +			atmel_port->use_dma_tx  = 0;
>>> +			atmel_port->use_pdc_tx  = 0;
>>> +		}
>>> +
>>> +	} else {
>>> +		atmel_port->use_pdc_rx  = pdata->use_dma_rx;
>>> +		atmel_port->use_pdc_tx  = pdata->use_dma_tx;
>>> +		atmel_port->use_dma_rx  = 0;
>>> +		atmel_port->use_dma_tx  = 0;
>>> +	}
>>> +
>>> +	return 0;
>>> +}
>>> +
>>> +static void atmel_init_rs485(struct atmel_uart_port *atmel_port,
>>> +				struct platform_device *pdev)
>>> +{
>>> +	struct device_node *np = pdev->dev.of_node;
>>> +	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>>> +
>>> +	if (np) {
>>> +		u32 rs485_delay[2];
>>> +		/* rs485 properties */
>>> +		if (of_property_read_u32_array(np, "rs485-rts-delay",
>>> +					rs485_delay, 2) == 0) {
>>> +			struct serial_rs485 *rs485conf = &atmel_port->rs485;
>>> +
>>> +			rs485conf->delay_rts_before_send = rs485_delay[0];
>>> +			rs485conf->delay_rts_after_send = rs485_delay[1];
>>> +			rs485conf->flags = 0;
>>> +
>>> +		if (of_get_property(np, "rs485-rx-during-tx", NULL))
>>> +			rs485conf->flags |= SER_RS485_RX_DURING_TX;
>>> +
>>> +		if (of_get_property(np, "linux,rs485-enabled-at-boot-time",
>>> +								NULL))
>>> +			rs485conf->flags |= SER_RS485_ENABLED;
>>> +		}
>>> +	} else {
>>> +		atmel_port->rs485       = pdata->rs485;
>>> +	}
>>> +
>>> +}
>>> +
>>>  static void atmel_set_ops(struct uart_port *port)
>>>  {
>>>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>>> @@ -1409,6 +1483,7 @@ static void atmel_set_ops(struct uart_port *port)
>>>   */
>>>  static int atmel_startup(struct uart_port *port)
>>>  {
>>> +	struct platform_device *pdev = to_platform_device(port->dev);
>>>  	struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
>>>  	struct tty_struct *tty = port->state->port.tty;
>>>  	int retval;
>>> @@ -1433,6 +1508,8 @@ static int atmel_startup(struct uart_port *port)
>>>  	/*
>>>  	 * Initialize DMA (if necessary)
>>>  	 */
>>> +	atmel_init_property(atmel_port, pdev);
>>> +
>>>  	if (atmel_port->prepare_rx) {
>>>  		retval = atmel_port->prepare_rx(port);
>>>  		if (retval < 0)
>>> @@ -1878,55 +1955,6 @@ static struct uart_ops atmel_pops = {
>>>  #endif
>>>  };
>>>  
>>> -static void atmel_of_init_port(struct atmel_uart_port *atmel_port,
>>> -					 struct device_node *np)
>>> -{
>>> -	u32 rs485_delay[2];
>>> -
>>> -	/* DMA/PDC usage specification */
>>> -	if (of_get_property(np, "atmel,use-dma-rx", NULL)) {
>>> -		if (of_get_property(np, "dmas", NULL)) {
>>> -			atmel_port->use_dma_rx	= 1;
>>> -			atmel_port->use_pdc_rx	= 0;
>>> -		} else {
>>> -			atmel_port->use_dma_rx	= 0;
>>> -			atmel_port->use_pdc_rx	= 1;
>>> -		}
>>> -	} else {
>>> -		atmel_port->use_dma_rx	= 0;
>>> -		atmel_port->use_pdc_rx	= 0;
>>> -	}
>>> -
>>> -	if (of_get_property(np, "atmel,use-dma-tx", NULL)) {
>>> -		if (of_get_property(np, "dmas", NULL)) {
>>> -			atmel_port->use_dma_tx	= 1;
>>> -			atmel_port->use_pdc_tx	= 0;
>>> -		} else {
>>> -			atmel_port->use_dma_tx	= 0;
>>> -			atmel_port->use_pdc_tx	= 1;
>>> -		}
>>> -	} else {
>>> -		atmel_port->use_dma_tx	= 0;
>>> -		atmel_port->use_pdc_tx	= 0;
>>> -	}
>>> -
>>> -	/* rs485 properties */
>>> -	if (of_property_read_u32_array(np, "rs485-rts-delay",
>>> -					    rs485_delay, 2) == 0) {
>>> -		struct serial_rs485 *rs485conf = &atmel_port->rs485;
>>> -
>>> -		rs485conf->delay_rts_before_send = rs485_delay[0];
>>> -		rs485conf->delay_rts_after_send = rs485_delay[1];
>>> -		rs485conf->flags = 0;
>>> -
>>> -		if (of_get_property(np, "rs485-rx-during-tx", NULL))
>>> -			rs485conf->flags |= SER_RS485_RX_DURING_TX;
>>> -
>>> -		if (of_get_property(np, "linux,rs485-enabled-at-boot-time", NULL))
>>> -			rs485conf->flags |= SER_RS485_ENABLED;
>>> -	}
>>> -}
>>> -
>>>  /*
>>>   * Configure the port from the platform device resource info.
>>>   */
>>> @@ -1936,17 +1964,10 @@ static void atmel_init_port(struct atmel_uart_port *atmel_port,
>>>  	struct uart_port *port = &atmel_port->uart;
>>>  	struct atmel_uart_data *pdata = pdev->dev.platform_data;
>>>  
>>> -	if (pdev->dev.of_node) {
>>> -		atmel_of_init_port(atmel_port, pdev->dev.of_node);
>>> -	} else {
>>> -		atmel_port->use_pdc_rx	= pdata->use_dma_rx;
>>> -		atmel_port->use_pdc_tx	= pdata->use_dma_tx;
>>> -		atmel_port->use_dma_rx	= 0;
>>> -		atmel_port->use_dma_tx	= 0;
>>> -		atmel_port->rs485	= pdata->rs485;
>>> -	}
>>> +	if (!atmel_init_property(atmel_port, pdev))
>>> +		atmel_set_ops(port);
>>>  
>>> -	atmel_set_ops(port);
>>> +	atmel_init_rs485(atmel_port, pdev);
>>>  
>>>  	port->iotype		= UPIO_MEM;
>>>  	port->flags		= UPF_BOOT_AUTOCONF;
>>> -- 
>>> 1.7.9.5
>>> 
>>> 
> 

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

* [PATCH V2 5/8] serial: at91: support run time switch transfer mode
  2013-07-18  9:21     ` elen.song
@ 2013-07-18 12:36       ` Nicolas Ferre
  0 siblings, 0 replies; 17+ messages in thread
From: Nicolas Ferre @ 2013-07-18 12:36 UTC (permalink / raw)
  To: linux-arm-kernel

On 18/07/2013 11:21, elen.song :
> Hi JC:
> On 7/18/2013 4:15 PM, Jean-Christophe PLAGNIOL-VILLARD wrote:
>> On 10:43 Tue 16 Jul     , Elen Song wrote:
>>> We will switch to pio mode when request of dma or pdc fail.
>>> But soon or later, when the request is success, the transfer mode can switch to them at
>>> next open serial port action.
>>> So in startup stage, we should get original transfer mode.
>> You need to update the Documentation of the binding to said the driver support
>> dmas bindings for the new IP
>
> one question, it seems the document should write like:
>
> use DMA:
>       usart0: serial at f001c000{
>           compatible = "atmel,at91sam9260-usart";
>           dmas = <&dma0 2 AT91_DMA_CFG_PER_ID(3)>,
>                        <&dma0 2
> (AT91_DMA_CFG_PER_ID(3)|AT91_DMA_CFG_FIFOCFG_ASAP)>;
>           dma-names = "tx","rx";
> };
>
> Should I replace macros with typical values?

Yes. That is the common rule for DT documentation.

Bye,
-- 
Nicolas Ferre

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

end of thread, other threads:[~2013-07-18 12:36 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-07-16  2:43 [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Elen Song
2013-07-16  2:43 ` [PATCH V2 1/8] serial: at91: correct definition from DMA to PDC Elen Song
2013-07-18  7:49   ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-16  2:43 ` [PATCH V2 2/8] serial: at91: use function pointer to choose pdc or pio Elen Song
2013-07-16  2:43 ` [PATCH V3 3/8] serial: at91: add tx dma support Elen Song
2013-07-16  2:43 ` [PATCH V2 4/8] serial: at91: add rx " Elen Song
2013-07-16  2:43 ` [PATCH V2 5/8] serial: at91: support run time switch transfer mode Elen Song
2013-07-18  8:15   ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-18  9:21     ` elen.song
2013-07-18 12:36       ` Nicolas Ferre
     [not found]     ` <51E7A756.6010004@atmel.com>
2013-07-18 10:45       ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-16  2:43 ` [PATCH V2 6/8] serial: at91: make DBGU support dma and pdc transfers Elen Song
2013-07-18  8:18   ` Jean-Christophe PLAGNIOL-VILLARD
2013-07-16  2:43 ` [PATCH V2 7/8] serial: at91: distinguish usart and uart Elen Song
2013-07-16  2:43 ` [PATCH V2 8/8] serial: at91: modify UART to use software timer to trigger rx Elen Song
2013-07-18  7:48 ` [PATCH V2 0/8] serial: at91: make usart and uart support dma transfer Jean-Christophe PLAGNIOL-VILLARD
2013-07-18  8:19 ` Jean-Christophe PLAGNIOL-VILLARD

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.