aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch')
-rw-r--r--target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch268
1 files changed, 268 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch b/target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch
new file mode 100644
index 0000000000..6c275f61d3
--- /dev/null
+++ b/target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch
@@ -0,0 +1,268 @@
+From 05a08cc5620df0fcf8e260feee04b9671705723e Mon Sep 17 00:00:00 2001
+From: Matthew McClintock <mmcclint@codeaurora.org>
+Date: Tue, 26 Apr 2016 15:46:24 -0500
+Subject: [PATCH 14/37] spi: qup: allow block mode to generate multiple
+ transactions
+
+This let's you write more to the SPI bus than 64K-1 which is important
+if the block size of a SPI device is >= 64K or some other device wants
+to something larger.
+
+This has the benefit of completly removing spi_message from the spi-qup
+transactions
+
+Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
+---
+ drivers/spi/spi-qup.c | 120 ++++++++++++++++++++++++++++++-------------------
+ 1 file changed, 75 insertions(+), 45 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -120,7 +120,7 @@
+
+ #define SPI_NUM_CHIPSELECTS 4
+
+-#define SPI_MAX_DMA_XFER (SZ_64K - 64)
++#define SPI_MAX_XFER (SZ_64K - 64)
+
+ /* high speed mode is when bus rate is greater then 26MHz */
+ #define SPI_HS_MIN_RATE 26000000
+@@ -150,6 +150,8 @@ struct spi_qup {
+ int n_words;
+ int tx_bytes;
+ int rx_bytes;
++ const u8 *tx_buf;
++ u8 *rx_buf;
+ int qup_v1;
+
+ int mode;
+@@ -172,6 +174,12 @@ static inline bool spi_qup_is_dma_xfer(i
+ return false;
+ }
+
++/* get's the transaction size length */
++static inline unsigned spi_qup_len(struct spi_qup *controller)
++{
++ return controller->n_words * controller->w_size;
++}
++
+ static inline bool spi_qup_is_valid_state(struct spi_qup *controller)
+ {
+ u32 opstate = readl_relaxed(controller->base + QUP_STATE);
+@@ -224,10 +232,9 @@ static int spi_qup_set_state(struct spi_
+ return 0;
+ }
+
+-static void spi_qup_read_from_fifo(struct spi_qup *controller,
+- struct spi_transfer *xfer, u32 num_words)
++static void spi_qup_read_from_fifo(struct spi_qup *controller, u32 num_words)
+ {
+- u8 *rx_buf = xfer->rx_buf;
++ u8 *rx_buf = controller->rx_buf;
+ int i, shift, num_bytes;
+ u32 word;
+
+@@ -235,7 +242,7 @@ static void spi_qup_read_from_fifo(struc
+
+ word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+
+- num_bytes = min_t(int, xfer->len - controller->rx_bytes,
++ num_bytes = min_t(int, spi_qup_len(controller) - controller->rx_bytes,
+ controller->w_size);
+
+ if (!rx_buf) {
+@@ -257,13 +264,12 @@ static void spi_qup_read_from_fifo(struc
+ }
+ }
+
+-static void spi_qup_read(struct spi_qup *controller,
+- struct spi_transfer *xfer)
++static void spi_qup_read(struct spi_qup *controller)
+ {
+ u32 remainder, words_per_block, num_words;
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+
+- remainder = DIV_ROUND_UP(xfer->len - controller->rx_bytes,
++ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->rx_bytes,
+ controller->w_size);
+ words_per_block = controller->in_blk_sz >> 2;
+
+@@ -284,7 +290,7 @@ static void spi_qup_read(struct spi_qup
+ }
+
+ /* read up to the maximum transfer size available */
+- spi_qup_read_from_fifo(controller, xfer, num_words);
++ spi_qup_read_from_fifo(controller, num_words);
+
+ remainder -= num_words;
+
+@@ -306,17 +312,16 @@ static void spi_qup_read(struct spi_qup
+
+ }
+
+-static void spi_qup_write_to_fifo(struct spi_qup *controller,
+- struct spi_transfer *xfer, u32 num_words)
++static void spi_qup_write_to_fifo(struct spi_qup *controller, u32 num_words)
+ {
+- const u8 *tx_buf = xfer->tx_buf;
++ const u8 *tx_buf = controller->tx_buf;
+ int i, num_bytes;
+ u32 word, data;
+
+ for (; num_words; num_words--) {
+ word = 0;
+
+- num_bytes = min_t(int, xfer->len - controller->tx_bytes,
++ num_bytes = min_t(int, spi_qup_len(controller) - controller->tx_bytes,
+ controller->w_size);
+ if (tx_buf)
+ for (i = 0; i < num_bytes; i++) {
+@@ -337,13 +342,12 @@ static void spi_qup_dma_done(void *data)
+ complete(done);
+ }
+
+-static void spi_qup_write(struct spi_qup *controller,
+- struct spi_transfer *xfer)
++static void spi_qup_write(struct spi_qup *controller)
+ {
+ bool is_block_mode = controller->mode == QUP_IO_M_MODE_BLOCK;
+ u32 remainder, words_per_block, num_words;
+
+- remainder = DIV_ROUND_UP(xfer->len - controller->tx_bytes,
++ remainder = DIV_ROUND_UP(spi_qup_len(controller) - controller->tx_bytes,
+ controller->w_size);
+ words_per_block = controller->out_blk_sz >> 2;
+
+@@ -363,7 +367,7 @@ static void spi_qup_write(struct spi_qup
+ num_words = 1;
+ }
+
+- spi_qup_write_to_fifo(controller, xfer, num_words);
++ spi_qup_write_to_fifo(controller, num_words);
+
+ remainder -= num_words;
+
+@@ -629,35 +633,61 @@ static int spi_qup_do_pio(struct spi_dev
+ {
+ struct spi_master *master = spi->master;
+ struct spi_qup *qup = spi_master_get_devdata(master);
+- int ret;
++ int ret, n_words, iterations, offset = 0;
+
+- ret = spi_qup_io_config(spi, xfer);
+- if (ret)
+- return ret;
++ n_words = qup->n_words;
++ iterations = n_words / SPI_MAX_XFER; /* round down */
+
+- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+- if (ret) {
+- dev_warn(qup->dev, "cannot set RUN state\n");
+- return ret;
+- }
++ qup->rx_buf = xfer->rx_buf;
++ qup->tx_buf = xfer->tx_buf;
+
+- ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
+- if (ret) {
+- dev_warn(qup->dev, "cannot set PAUSE state\n");
+- return ret;
+- }
++ do {
++ if (iterations)
++ qup->n_words = SPI_MAX_XFER;
++ else
++ qup->n_words = n_words % SPI_MAX_XFER;
++
++ if (qup->tx_buf && offset)
++ qup->tx_buf = xfer->tx_buf + offset * SPI_MAX_XFER;
++
++ if (qup->rx_buf && offset)
++ qup->rx_buf = xfer->rx_buf + offset * SPI_MAX_XFER;
++
++ /* if the transaction is small enough, we need
++ * to fallback to FIFO mode */
++ if (qup->n_words <= (qup->in_fifo_sz / sizeof(u32)))
++ qup->mode = QUP_IO_M_MODE_FIFO;
+
+- if (qup->mode == QUP_IO_M_MODE_FIFO)
+- spi_qup_write(qup, xfer);
++ ret = spi_qup_io_config(spi, xfer);
++ if (ret)
++ return ret;
+
+- ret = spi_qup_set_state(qup, QUP_STATE_RUN);
+- if (ret) {
+- dev_warn(qup->dev, "cannot set RUN state\n");
+- return ret;
+- }
++ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
++ if (ret) {
++ dev_warn(qup->dev, "cannot set RUN state\n");
++ return ret;
++ }
+
+- if (!wait_for_completion_timeout(&qup->done, timeout))
+- return -ETIMEDOUT;
++ ret = spi_qup_set_state(qup, QUP_STATE_PAUSE);
++ if (ret) {
++ dev_warn(qup->dev, "cannot set PAUSE state\n");
++ return ret;
++ }
++
++ if (qup->mode == QUP_IO_M_MODE_FIFO)
++ spi_qup_write(qup);
++
++ ret = spi_qup_set_state(qup, QUP_STATE_RUN);
++ if (ret) {
++ dev_warn(qup->dev, "cannot set RUN state\n");
++ return ret;
++ }
++
++ if (!wait_for_completion_timeout(&qup->done, timeout))
++ return -ETIMEDOUT;
++
++ offset++;
++ } while (iterations--);
+
+ return 0;
+ }
+@@ -722,17 +752,17 @@ static irqreturn_t spi_qup_qup_irq(int i
+ complete(&controller->dma_tx_done);
+ } else {
+ if (opflags & QUP_OP_IN_SERVICE_FLAG)
+- spi_qup_read(controller, xfer);
++ spi_qup_read(controller);
+
+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+- spi_qup_write(controller, xfer);
++ spi_qup_write(controller);
+ }
+
+ /* re-read opflags as flags may have changed due to actions above */
+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
+ opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
+
+- if ((controller->rx_bytes == xfer->len &&
++ if ((controller->rx_bytes == spi_qup_len(controller) &&
+ (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) || error)
+ done = true;
+
+@@ -794,7 +824,7 @@ static int spi_qup_transfer_one(struct s
+ return ret;
+
+ timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
+- timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
++ timeout = DIV_ROUND_UP(min_t(unsigned long, SPI_MAX_XFER, xfer->len) * 8, timeout);
+ timeout = 100 * msecs_to_jiffies(timeout);
+
+ if (spi_qup_is_dma_xfer(controller->mode))
+@@ -983,7 +1013,7 @@ static int spi_qup_probe(struct platform
+ master->dev.of_node = pdev->dev.of_node;
+ master->auto_runtime_pm = true;
+ master->dma_alignment = dma_get_cache_alignment();
+- master->max_dma_len = SPI_MAX_DMA_XFER;
++ master->max_dma_len = SPI_MAX_XFER;
+
+ platform_set_drvdata(pdev, master);
+