openwrt/target/linux/ipq806x/patches-4.9/0013-spi-qup-call-io_config-in-mode-specific-function.patch
John Crispin bb255f7429 ipq806x: add v4.9 support
Signed-off-by: John Crispin <john@phrozen.org>
2017-02-16 20:25:32 +01:00

392 lines
12 KiB
Diff

From 9263d98e255e1d51b41c752d53e39877728a9419 Mon Sep 17 00:00:00 2001
From: Matthew McClintock <mmcclint@codeaurora.org>
Date: Tue, 26 Apr 2016 13:14:45 -0500
Subject: [PATCH 13/37] spi: qup: call io_config in mode specific function
DMA transactions should only only need to call io_config only once, but
block mode might call it several times to setup several transactions so
it can handle reads/writes larger than the max size per transaction, so
we move the call to the do_ functions.
This is just refactoring, there should be no functional change
Signed-off-by: Matthew McClintock <mmcclint@codeaurora.org>
---
drivers/spi/spi-qup.c | 327 +++++++++++++++++++++++++------------------------
1 file changed, 166 insertions(+), 161 deletions(-)
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -418,13 +418,170 @@ static void spi_qup_dma_terminate(struct
dmaengine_terminate_all(master->dma_rx);
}
-static int spi_qup_do_dma(struct spi_master *master, struct spi_transfer *xfer,
+/* prep qup for another spi transaction of specific type */
+static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
+{
+ struct spi_qup *controller = spi_master_get_devdata(spi->master);
+ u32 config, iomode, control;
+ unsigned long flags;
+
+ reinit_completion(&controller->done);
+ reinit_completion(&controller->dma_tx_done);
+
+ spin_lock_irqsave(&controller->lock, flags);
+ controller->xfer = xfer;
+ controller->error = 0;
+ controller->rx_bytes = 0;
+ controller->tx_bytes = 0;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
+ dev_err(controller->dev, "cannot set RESET state\n");
+ return -EIO;
+ }
+
+ switch (controller->mode) {
+ case QUP_IO_M_MODE_FIFO:
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_WRITE_CNT);
+ /* must be zero for FIFO */
+ writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ break;
+ case QUP_IO_M_MODE_BAM:
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ if (!controller->qup_v1) {
+ void __iomem *input_cnt;
+
+ input_cnt = controller->base + QUP_MX_INPUT_CNT;
+ /*
+ * for DMA transfers, both QUP_MX_INPUT_CNT and
+ * QUP_MX_OUTPUT_CNT must be zero to all cases
+ * but one. That case is a non-balanced
+ * transfer when there is only a rx_buf.
+ */
+ if (xfer->tx_buf)
+ writel_relaxed(0, input_cnt);
+ else
+ writel_relaxed(controller->n_words,
+ input_cnt);
+
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ }
+ break;
+ case QUP_IO_M_MODE_BLOCK:
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_INPUT_CNT);
+ writel_relaxed(controller->n_words,
+ controller->base + QUP_MX_OUTPUT_CNT);
+ /* must be zero for BLOCK and BAM */
+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ break;
+ default:
+ dev_err(controller->dev, "unknown mode = %d\n",
+ controller->mode);
+ return -EIO;
+ }
+
+ iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
+ /* Set input and output transfer mode */
+ iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
+
+ if (!spi_qup_is_dma_xfer(controller->mode))
+ iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
+ else
+ iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
+
+ iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
+ iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
+
+ writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+
+ control = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+ if (spi->mode & SPI_CPOL)
+ control |= SPI_IO_C_CLK_IDLE_HIGH;
+ else
+ control &= ~SPI_IO_C_CLK_IDLE_HIGH;
+
+ writel_relaxed(control, controller->base + SPI_IO_CONTROL);
+
+ config = readl_relaxed(controller->base + SPI_CONFIG);
+
+ if (spi->mode & SPI_LOOP)
+ config |= SPI_CONFIG_LOOPBACK;
+ else
+ config &= ~SPI_CONFIG_LOOPBACK;
+
+ if (spi->mode & SPI_CPHA)
+ config &= ~SPI_CONFIG_INPUT_FIRST;
+ else
+ config |= SPI_CONFIG_INPUT_FIRST;
+
+ /*
+ * HS_MODE improves signal stability for spi-clk high rates,
+ * but is invalid in loop back mode.
+ */
+ if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
+ config |= SPI_CONFIG_HS_MODE;
+ else
+ config &= ~SPI_CONFIG_HS_MODE;
+
+ writel_relaxed(config, controller->base + SPI_CONFIG);
+
+ config = readl_relaxed(controller->base + QUP_CONFIG);
+ config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
+ config |= xfer->bits_per_word - 1;
+ config |= QUP_CONFIG_SPI_MODE;
+
+ if (spi_qup_is_dma_xfer(controller->mode)) {
+ if (!xfer->tx_buf)
+ config |= QUP_CONFIG_NO_OUTPUT;
+ if (!xfer->rx_buf)
+ config |= QUP_CONFIG_NO_INPUT;
+ }
+
+ writel_relaxed(config, controller->base + QUP_CONFIG);
+
+ /* only write to OPERATIONAL_MASK when register is present */
+ if (!controller->qup_v1) {
+ u32 mask = 0;
+
+ /*
+ * mask INPUT and OUTPUT service flags to prevent IRQs on FIFO
+ * status change in BAM mode
+ */
+
+ if (spi_qup_is_dma_xfer(controller->mode))
+ mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
+
+ writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
+ }
+
+ return 0;
+}
+
+static int spi_qup_do_dma(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
+ struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
dma_async_tx_callback rx_done = NULL, tx_done = NULL;
int ret;
+ ret = spi_qup_io_config(spi, xfer);
+ if (ret)
+ return ret;
+
/* before issuing the descriptors, set the QUP to run */
ret = spi_qup_set_state(qup, QUP_STATE_RUN);
if (ret) {
@@ -467,12 +624,17 @@ unsigned long timeout)
return ret;
}
-static int spi_qup_do_pio(struct spi_master *master, struct spi_transfer *xfer,
+static int spi_qup_do_pio(struct spi_device *spi, struct spi_transfer *xfer,
unsigned long timeout)
{
+ struct spi_master *master = spi->master;
struct spi_qup *qup = spi_master_get_devdata(master);
int ret;
+ 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");
@@ -619,159 +781,6 @@ static int spi_qup_io_prep(struct spi_de
return 0;
}
-/* prep qup for another spi transaction of specific type */
-static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
-{
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
- u32 config, iomode, control;
- unsigned long flags;
-
- reinit_completion(&controller->done);
- reinit_completion(&controller->dma_tx_done);
-
- spin_lock_irqsave(&controller->lock, flags);
- controller->xfer = xfer;
- controller->error = 0;
- controller->rx_bytes = 0;
- controller->tx_bytes = 0;
- spin_unlock_irqrestore(&controller->lock, flags);
-
-
- if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
- dev_err(controller->dev, "cannot set RESET state\n");
- return -EIO;
- }
-
- switch (controller->mode) {
- case QUP_IO_M_MODE_FIFO:
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_READ_CNT);
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_WRITE_CNT);
- /* must be zero for FIFO */
- writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
- writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
- break;
- case QUP_IO_M_MODE_BAM:
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_INPUT_CNT);
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_OUTPUT_CNT);
- /* must be zero for BLOCK and BAM */
- writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
- writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
- if (!controller->qup_v1) {
- void __iomem *input_cnt;
-
- input_cnt = controller->base + QUP_MX_INPUT_CNT;
- /*
- * for DMA transfers, both QUP_MX_INPUT_CNT and
- * QUP_MX_OUTPUT_CNT must be zero to all cases
- * but one. That case is a non-balanced
- * transfer when there is only a rx_buf.
- */
- if (xfer->tx_buf)
- writel_relaxed(0, input_cnt);
- else
- writel_relaxed(controller->n_words,
- input_cnt);
-
- writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
- }
- break;
- case QUP_IO_M_MODE_BLOCK:
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_INPUT_CNT);
- writel_relaxed(controller->n_words,
- controller->base + QUP_MX_OUTPUT_CNT);
- /* must be zero for BLOCK and BAM */
- writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
- writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
- break;
- default:
- dev_err(controller->dev, "unknown mode = %d\n",
- controller->mode);
- return -EIO;
- }
-
- iomode = readl_relaxed(controller->base + QUP_IO_M_MODES);
- /* Set input and output transfer mode */
- iomode &= ~(QUP_IO_M_INPUT_MODE_MASK | QUP_IO_M_OUTPUT_MODE_MASK);
-
- if (!spi_qup_is_dma_xfer(controller->mode))
- iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
- else
- iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
-
- iomode |= (controller->mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
- iomode |= (controller->mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
-
- writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
-
- control = readl_relaxed(controller->base + SPI_IO_CONTROL);
-
- if (spi->mode & SPI_CPOL)
- control |= SPI_IO_C_CLK_IDLE_HIGH;
- else
- control &= ~SPI_IO_C_CLK_IDLE_HIGH;
-
- writel_relaxed(control, controller->base + SPI_IO_CONTROL);
-
- config = readl_relaxed(controller->base + SPI_CONFIG);
-
- if (spi->mode & SPI_LOOP)
- config |= SPI_CONFIG_LOOPBACK;
- else
- config &= ~SPI_CONFIG_LOOPBACK;
-
- if (spi->mode & SPI_CPHA)
- config &= ~SPI_CONFIG_INPUT_FIRST;
- else
- config |= SPI_CONFIG_INPUT_FIRST;
-
- /*
- * HS_MODE improves signal stability for spi-clk high rates,
- * but is invalid in loop back mode.
- */
- if ((xfer->speed_hz >= SPI_HS_MIN_RATE) && !(spi->mode & SPI_LOOP))
- config |= SPI_CONFIG_HS_MODE;
- else
- config &= ~SPI_CONFIG_HS_MODE;
-
- writel_relaxed(config, controller->base + SPI_CONFIG);
-
- config = readl_relaxed(controller->base + QUP_CONFIG);
- config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
- config |= xfer->bits_per_word - 1;
- config |= QUP_CONFIG_SPI_MODE;
-
- if (spi_qup_is_dma_xfer(controller->mode)) {
- if (!xfer->tx_buf)
- config |= QUP_CONFIG_NO_OUTPUT;
- if (!xfer->rx_buf)
- config |= QUP_CONFIG_NO_INPUT;
- }
-
- writel_relaxed(config, controller->base + QUP_CONFIG);
-
- /* only write to OPERATIONAL_MASK when register is present */
- if (!controller->qup_v1) {
- u32 mask = 0;
-
- /*
- * mask INPUT and OUTPUT service flags to prevent IRQs on FIFO
- * status change in BAM mode
- */
-
- if (spi_qup_is_dma_xfer(controller->mode))
- mask = QUP_OP_IN_SERVICE_FLAG | QUP_OP_OUT_SERVICE_FLAG;
-
- writel_relaxed(mask, controller->base + QUP_OPERATIONAL_MASK);
- }
-
- return 0;
-}
-
static int spi_qup_transfer_one(struct spi_master *master,
struct spi_device *spi,
struct spi_transfer *xfer)
@@ -784,18 +793,14 @@ static int spi_qup_transfer_one(struct s
if (ret)
return ret;
- ret = spi_qup_io_config(spi, xfer);
- if (ret)
- return ret;
-
timeout = DIV_ROUND_UP(xfer->speed_hz, MSEC_PER_SEC);
timeout = DIV_ROUND_UP(xfer->len * 8, timeout);
timeout = 100 * msecs_to_jiffies(timeout);
if (spi_qup_is_dma_xfer(controller->mode))
- ret = spi_qup_do_dma(master, xfer, timeout);
+ ret = spi_qup_do_dma(spi, xfer, timeout);
else
- ret = spi_qup_do_pio(master, xfer, timeout);
+ ret = spi_qup_do_pio(spi, xfer, timeout);
if (ret)
goto exit;