diff options
Diffstat (limited to 'target/linux/ipq806x/patches-4.9/0010-spi-qup-call-io_config-in-mode-specific-function.patch')
-rw-r--r-- | target/linux/ipq806x/patches-4.9/0010-spi-qup-call-io_config-in-mode-specific-function.patch | 391 |
1 files changed, 391 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-4.9/0010-spi-qup-call-io_config-in-mode-specific-function.patch b/target/linux/ipq806x/patches-4.9/0010-spi-qup-call-io_config-in-mode-specific-function.patch new file mode 100644 index 0000000000..dfbed620f3 --- /dev/null +++ b/target/linux/ipq806x/patches-4.9/0010-spi-qup-call-io_config-in-mode-specific-function.patch @@ -0,0 +1,391 @@ +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; |