From bb255f74290d889b65a563bac7a4be0427fdbec8 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Thu, 16 Feb 2017 12:25:25 +0100 Subject: ipq806x: add v4.9 support Signed-off-by: John Crispin --- ...ow-block-mode-to-generate-multiple-transa.patch | 268 +++++++++++++++++++++ 1 file changed, 268 insertions(+) create mode 100644 target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch (limited to 'target/linux/ipq806x/patches-4.9/0014-spi-qup-allow-block-mode-to-generate-multiple-transa.patch') 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 +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 +--- + 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); + -- cgit v1.2.3