mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-30 10:39:04 +00:00
1adf51702e
Signed-off-by: John Crispin <john@phrozen.org> Signed-off-by: Felix Fietkau <nbd@nbd.name>
392 lines
12 KiB
Diff
392 lines
12 KiB
Diff
From afe108e638a2dd441b11cd2c7b1e0658bb47b5e8 Mon Sep 17 00:00:00 2001
|
|
From: Matthew McClintock <mmcclint@codeaurora.org>
|
|
Date: Tue, 26 Apr 2016 13:14:45 -0500
|
|
Subject: [PATCH 10/69] 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;
|