Re: [PATCH v3] spi: spi-fsl-dspi: Add DMA support for Vybrid

2016-11-11 Thread Mark Brown
On Thu, Nov 10, 2016 at 05:49:15PM +0530, Sanchayan Maity wrote:

A couple of small things, please send followup patches fixing them.

> + rx_word = is_double_byte_mode(dspi);
> +
> + len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;

Please use normal if statements, they're much easier to read.

> +err_slave_config:
> + devm_kfree(dev, dma->rx_dma_buf);
> +err_rx_dma_buf:
> + devm_kfree(dev, dma->tx_dma_buf);

You really shouldn't need to explicitly free things like this if you're
using devm_, especially in the error path from the probe function like
this where a failure is just going to result in the device failing to
instantiate so you won't have the allocation sitting around unused for
any length of time.


signature.asc
Description: PGP signature


Re: [PATCH v3] spi: spi-fsl-dspi: Add DMA support for Vybrid

2016-11-11 Thread Mark Brown
On Thu, Nov 10, 2016 at 05:49:15PM +0530, Sanchayan Maity wrote:

A couple of small things, please send followup patches fixing them.

> + rx_word = is_double_byte_mode(dspi);
> +
> + len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;

Please use normal if statements, they're much easier to read.

> +err_slave_config:
> + devm_kfree(dev, dma->rx_dma_buf);
> +err_rx_dma_buf:
> + devm_kfree(dev, dma->tx_dma_buf);

You really shouldn't need to explicitly free things like this if you're
using devm_, especially in the error path from the probe function like
this where a failure is just going to result in the device failing to
instantiate so you won't have the allocation sitting around unused for
any length of time.


signature.asc
Description: PGP signature


[PATCH v3] spi: spi-fsl-dspi: Add DMA support for Vybrid

2016-11-10 Thread Sanchayan Maity
Add DMA support for Vybrid.

Signed-off-by: Sanchayan Maity 
---
Changes since v2:
1. Rebase on top of Shawn's latest for-next branch
2. Make DMA mode the default for Vybrid. We no longer use the EOQ mode.
Since devtype_data has been constantified it's no longer makes sense to
change the trans_mode at run time.

Tested on Toradex Colibri Vybrid VF61 module using spidev and MCP CAN.

v1 Patch:
https://patchwork.kernel.org/patch/9360583/

v2 Patch:
https://patchwork.kernel.org/patch/9361601/

Regards,
Sanchayan.
---
 drivers/spi/spi-fsl-dspi.c | 301 -
 1 file changed, 300 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 35c0dd9..bc64700 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -15,6 +15,8 @@
 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -40,6 +42,7 @@
 #define TRAN_STATE_WORD_ODD_NUM0x04
 
 #define DSPI_FIFO_SIZE 4
+#define DSPI_DMA_BUFSIZE   (DSPI_FIFO_SIZE * 1024)
 
 #define SPI_MCR0x00
 #define SPI_MCR_MASTER (1 << 31)
@@ -71,6 +74,11 @@
 #define SPI_SR_EOQF0x1000
 #define SPI_SR_TCFQF   0x8000
 
+#define SPI_RSER_TFFFE BIT(25)
+#define SPI_RSER_TFFFD BIT(24)
+#define SPI_RSER_RFDFE BIT(17)
+#define SPI_RSER_RFDFD BIT(16)
+
 #define SPI_RSER   0x30
 #define SPI_RSER_EOQFE 0x1000
 #define SPI_RSER_TCFQE 0x8000
@@ -108,6 +116,8 @@
 
 #define SPI_TCR_TCNT_MAX   0x1
 
+#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
+
 struct chip_data {
u32 mcr_val;
u32 ctar_val;
@@ -117,6 +127,7 @@ struct chip_data {
 enum dspi_trans_mode {
DSPI_EOQ_MODE = 0,
DSPI_TCFQ_MODE,
+   DSPI_DMA_MODE,
 };
 
 struct fsl_dspi_devtype_data {
@@ -125,7 +136,7 @@ struct fsl_dspi_devtype_data {
 };
 
 static const struct fsl_dspi_devtype_data vf610_data = {
-   .trans_mode = DSPI_EOQ_MODE,
+   .trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 2,
 };
 
@@ -139,6 +150,22 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
.max_clock_factor = 8,
 };
 
+struct fsl_dspi_dma {
+   u32 curr_xfer_len;
+
+   u32 *tx_dma_buf;
+   struct dma_chan *chan_tx;
+   dma_addr_t tx_dma_phys;
+   struct completion cmd_tx_complete;
+   struct dma_async_tx_descriptor *tx_desc;
+
+   u32 *rx_dma_buf;
+   struct dma_chan *chan_rx;
+   dma_addr_t rx_dma_phys;
+   struct completion cmd_rx_complete;
+   struct dma_async_tx_descriptor *rx_desc;
+};
+
 struct fsl_dspi {
struct spi_master   *master;
struct platform_device  *pdev;
@@ -165,6 +192,7 @@ struct fsl_dspi {
u32 waitflags;
 
u32 spi_tcnt;
+   struct fsl_dspi_dma *dma;
 };
 
 static inline int is_double_byte_mode(struct fsl_dspi *dspi)
@@ -176,6 +204,263 @@ static inline int is_double_byte_mode(struct fsl_dspi 
*dspi)
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
 }
 
+static void dspi_tx_dma_callback(void *arg)
+{
+   struct fsl_dspi *dspi = arg;
+   struct fsl_dspi_dma *dma = dspi->dma;
+
+   complete(>cmd_tx_complete);
+}
+
+static void dspi_rx_dma_callback(void *arg)
+{
+   struct fsl_dspi *dspi = arg;
+   struct fsl_dspi_dma *dma = dspi->dma;
+   int rx_word;
+   int i, len;
+   u16 d;
+
+   rx_word = is_double_byte_mode(dspi);
+
+   len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
+
+   if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
+   for (i = 0; i < len; i++) {
+   d = dspi->dma->rx_dma_buf[i];
+   rx_word ? (*(u16 *)dspi->rx = d) :
+   (*(u8 *)dspi->rx = d);
+   dspi->rx += rx_word + 1;
+   }
+   }
+
+   complete(>cmd_rx_complete);
+}
+
+static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
+{
+   struct fsl_dspi_dma *dma = dspi->dma;
+   struct device *dev = >pdev->dev;
+   int time_left;
+   int tx_word;
+   int i, len;
+   u16 val;
+
+   tx_word = is_double_byte_mode(dspi);
+
+   len = tx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
+
+   for (i = 0; i < len - 1; i++) {
+   val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+   dspi->dma->tx_dma_buf[i] =
+   SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
+   SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
+   dspi->tx += tx_word + 1;
+   }
+
+   val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+   dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
+   SPI_PUSHR_PCS(dspi->cs) |
+  

[PATCH v3] spi: spi-fsl-dspi: Add DMA support for Vybrid

2016-11-10 Thread Sanchayan Maity
Add DMA support for Vybrid.

Signed-off-by: Sanchayan Maity 
---
Changes since v2:
1. Rebase on top of Shawn's latest for-next branch
2. Make DMA mode the default for Vybrid. We no longer use the EOQ mode.
Since devtype_data has been constantified it's no longer makes sense to
change the trans_mode at run time.

Tested on Toradex Colibri Vybrid VF61 module using spidev and MCP CAN.

v1 Patch:
https://patchwork.kernel.org/patch/9360583/

v2 Patch:
https://patchwork.kernel.org/patch/9361601/

Regards,
Sanchayan.
---
 drivers/spi/spi-fsl-dspi.c | 301 -
 1 file changed, 300 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 35c0dd9..bc64700 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -15,6 +15,8 @@
 
 #include 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -40,6 +42,7 @@
 #define TRAN_STATE_WORD_ODD_NUM0x04
 
 #define DSPI_FIFO_SIZE 4
+#define DSPI_DMA_BUFSIZE   (DSPI_FIFO_SIZE * 1024)
 
 #define SPI_MCR0x00
 #define SPI_MCR_MASTER (1 << 31)
@@ -71,6 +74,11 @@
 #define SPI_SR_EOQF0x1000
 #define SPI_SR_TCFQF   0x8000
 
+#define SPI_RSER_TFFFE BIT(25)
+#define SPI_RSER_TFFFD BIT(24)
+#define SPI_RSER_RFDFE BIT(17)
+#define SPI_RSER_RFDFD BIT(16)
+
 #define SPI_RSER   0x30
 #define SPI_RSER_EOQFE 0x1000
 #define SPI_RSER_TCFQE 0x8000
@@ -108,6 +116,8 @@
 
 #define SPI_TCR_TCNT_MAX   0x1
 
+#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
+
 struct chip_data {
u32 mcr_val;
u32 ctar_val;
@@ -117,6 +127,7 @@ struct chip_data {
 enum dspi_trans_mode {
DSPI_EOQ_MODE = 0,
DSPI_TCFQ_MODE,
+   DSPI_DMA_MODE,
 };
 
 struct fsl_dspi_devtype_data {
@@ -125,7 +136,7 @@ struct fsl_dspi_devtype_data {
 };
 
 static const struct fsl_dspi_devtype_data vf610_data = {
-   .trans_mode = DSPI_EOQ_MODE,
+   .trans_mode = DSPI_DMA_MODE,
.max_clock_factor = 2,
 };
 
@@ -139,6 +150,22 @@ static const struct fsl_dspi_devtype_data ls2085a_data = {
.max_clock_factor = 8,
 };
 
+struct fsl_dspi_dma {
+   u32 curr_xfer_len;
+
+   u32 *tx_dma_buf;
+   struct dma_chan *chan_tx;
+   dma_addr_t tx_dma_phys;
+   struct completion cmd_tx_complete;
+   struct dma_async_tx_descriptor *tx_desc;
+
+   u32 *rx_dma_buf;
+   struct dma_chan *chan_rx;
+   dma_addr_t rx_dma_phys;
+   struct completion cmd_rx_complete;
+   struct dma_async_tx_descriptor *rx_desc;
+};
+
 struct fsl_dspi {
struct spi_master   *master;
struct platform_device  *pdev;
@@ -165,6 +192,7 @@ struct fsl_dspi {
u32 waitflags;
 
u32 spi_tcnt;
+   struct fsl_dspi_dma *dma;
 };
 
 static inline int is_double_byte_mode(struct fsl_dspi *dspi)
@@ -176,6 +204,263 @@ static inline int is_double_byte_mode(struct fsl_dspi 
*dspi)
return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
 }
 
+static void dspi_tx_dma_callback(void *arg)
+{
+   struct fsl_dspi *dspi = arg;
+   struct fsl_dspi_dma *dma = dspi->dma;
+
+   complete(>cmd_tx_complete);
+}
+
+static void dspi_rx_dma_callback(void *arg)
+{
+   struct fsl_dspi *dspi = arg;
+   struct fsl_dspi_dma *dma = dspi->dma;
+   int rx_word;
+   int i, len;
+   u16 d;
+
+   rx_word = is_double_byte_mode(dspi);
+
+   len = rx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
+
+   if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
+   for (i = 0; i < len; i++) {
+   d = dspi->dma->rx_dma_buf[i];
+   rx_word ? (*(u16 *)dspi->rx = d) :
+   (*(u8 *)dspi->rx = d);
+   dspi->rx += rx_word + 1;
+   }
+   }
+
+   complete(>cmd_rx_complete);
+}
+
+static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
+{
+   struct fsl_dspi_dma *dma = dspi->dma;
+   struct device *dev = >pdev->dev;
+   int time_left;
+   int tx_word;
+   int i, len;
+   u16 val;
+
+   tx_word = is_double_byte_mode(dspi);
+
+   len = tx_word ? (dma->curr_xfer_len / 2) : dma->curr_xfer_len;
+
+   for (i = 0; i < len - 1; i++) {
+   val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+   dspi->dma->tx_dma_buf[i] =
+   SPI_PUSHR_TXDATA(val) | SPI_PUSHR_PCS(dspi->cs) |
+   SPI_PUSHR_CTAS(0) | SPI_PUSHR_CONT;
+   dspi->tx += tx_word + 1;
+   }
+
+   val = tx_word ? *(u16 *) dspi->tx : *(u8 *) dspi->tx;
+   dspi->dma->tx_dma_buf[i] = SPI_PUSHR_TXDATA(val) |
+   SPI_PUSHR_PCS(dspi->cs) |
+