aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
diff options
context:
space:
mode:
authorRam Chandra Jangir <rjangi@codeaurora.org>2016-05-21 14:48:31 +0530
committerJohn Crispin <john@phrozen.org>2016-05-27 15:50:17 +0200
commit5e49c5795697868f6317f17fda5a2b04f299e116 (patch)
treebf6ebcc54ae88fa08f268f02a8f118939fe6bf6a /target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
parent955c341d3bec0eb4971a03924e99156367255d7b (diff)
downloadupstream-5e49c5795697868f6317f17fda5a2b04f299e116.tar.gz
upstream-5e49c5795697868f6317f17fda5a2b04f299e116.tar.bz2
upstream-5e49c5795697868f6317f17fda5a2b04f299e116.zip
ipq806x: Add support for linux-4.4
1)Changes - Rebased the patches for linux-4.4.7 - Added patch to fix spi nor fifo and dma support - Added patch to configure watchdog barktime 2)Testing Tested on IPQ AP148 Board: a. NOR boot and NAND boot b. ethernet network and ath10k wifi c. ubi sysupgrade UnTested dwc3 usb has not been validated on IPQ board(AP148) 3)Known Issues: Once we flash ubi image on AP148, and if we reset the board, uboot on first boot creates PEB and LEB for dynamic sized partitions, which is incorrect and not what linux expects which causes errors when trying to mount rootfs. In order to test this, we can use the below steps: a. Flash the ubi image on board and don't reset the board b. load the kernel fit image in RAM and boot from there. Signed-off-by: Ram Chandra Jangir <rjangi@codeaurora.org>
Diffstat (limited to 'target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch')
-rw-r--r--target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch522
1 files changed, 0 insertions, 522 deletions
diff --git a/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch b/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
deleted file mode 100644
index e110bf726c..0000000000
--- a/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
+++ /dev/null
@@ -1,522 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: spi: qup: Add DMA capabilities
-From: Andy Gross <agross@codeaurora.org>
-X-Patchwork-Id: 4432401
-Message-Id: <1403816781-31008-1-git-send-email-agross@codeaurora.org>
-To: Mark Brown <broonie@kernel.org>
-Cc: linux-spi@vger.kernel.org, Sagar Dharia <sdharia@codeaurora.org>,
- Daniel Sneddon <dsneddon@codeaurora.org>,
- Bjorn Andersson <bjorn.andersson@sonymobile.com>,
- "Ivan T. Ivanov" <iivanov@mm-sol.com>,
- linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- linux-arm-msm@vger.kernel.org, Andy Gross <agross@codeaurora.org>
-Date: Thu, 26 Jun 2014 16:06:21 -0500
-
-This patch adds DMA capabilities to the spi-qup driver. If DMA channels are
-present, the QUP will use DMA instead of block mode for transfers to/from SPI
-peripherals for transactions larger than the length of a block.
-
-Signed-off-by: Andy Gross <agross@codeaurora.org>
-
----
-.../devicetree/bindings/spi/qcom,spi-qup.txt | 10 +
- drivers/spi/spi-qup.c | 361 ++++++++++++++++++--
- 2 files changed, 350 insertions(+), 21 deletions(-)
-
---- a/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
-+++ b/Documentation/devicetree/bindings/spi/qcom,spi-qup.txt
-@@ -27,6 +27,11 @@ Optional properties:
- - spi-max-frequency: Specifies maximum SPI clock frequency,
- Units - Hz. Definition as per
- Documentation/devicetree/bindings/spi/spi-bus.txt
-+- dmas : Two DMA channel specifiers following the convention outlined
-+ in bindings/dma/dma.txt
-+- dma-names: Names for the dma channels, if present. There must be at
-+ least one channel named "tx" for transmit and named "rx" for
-+ receive.
- - num-cs: total number of chipselects
- - cs-gpios: should specify GPIOs used for chipselects.
- The gpios will be referred to as reg = <index> in the SPI child
-@@ -51,6 +56,10 @@ Example:
- clocks = <&gcc GCC_BLSP2_QUP2_SPI_APPS_CLK>, <&gcc GCC_BLSP2_AHB_CLK>;
- clock-names = "core", "iface";
-
-+ dmas = <&blsp2_bam 2>,
-+ <&blsp2_bam 3>;
-+ dma-names = "rx", "tx";
-+
- pinctrl-names = "default";
- pinctrl-0 = <&spi8_default>;
-
---- a/drivers/spi/spi-qup.c
-+++ b/drivers/spi/spi-qup.c
-@@ -22,6 +22,8 @@
- #include <linux/platform_device.h>
- #include <linux/pm_runtime.h>
- #include <linux/spi/spi.h>
-+#include <linux/dmaengine.h>
-+#include <linux/dma-mapping.h>
-
- #define QUP_CONFIG 0x0000
- #define QUP_STATE 0x0004
-@@ -116,6 +118,8 @@
-
- #define SPI_NUM_CHIPSELECTS 4
-
-+#define SPI_MAX_XFER (SZ_64K - 64)
-+
- /* high speed mode is when bus rate is greater then 26MHz */
- #define SPI_HS_MIN_RATE 26000000
- #define SPI_MAX_RATE 50000000
-@@ -143,6 +147,17 @@ struct spi_qup {
- int tx_bytes;
- int rx_bytes;
- int qup_v1;
-+
-+ int use_dma;
-+
-+ struct dma_chan *rx_chan;
-+ struct dma_slave_config rx_conf;
-+ struct dma_chan *tx_chan;
-+ struct dma_slave_config tx_conf;
-+ dma_addr_t rx_dma;
-+ dma_addr_t tx_dma;
-+ void *dummy;
-+ atomic_t dma_outstanding;
- };
-
-
-@@ -266,6 +281,221 @@ static void spi_qup_fifo_write(struct sp
- }
- }
-
-+static void qup_dma_callback(void *data)
-+{
-+ struct spi_qup *controller = data;
-+
-+ if (atomic_dec_and_test(&controller->dma_outstanding))
-+ complete(&controller->done);
-+}
-+
-+static int spi_qup_do_dma(struct spi_qup *controller, struct spi_transfer *xfer)
-+{
-+ struct dma_async_tx_descriptor *rxd, *txd;
-+ dma_cookie_t rx_cookie, tx_cookie;
-+ u32 xfer_len, rx_align = 0, tx_align = 0, n_words;
-+ struct scatterlist tx_sg[2], rx_sg[2];
-+ int ret = 0;
-+ u32 bytes_to_xfer = xfer->len;
-+ u32 offset = 0;
-+ u32 rx_nents = 0, tx_nents = 0;
-+ dma_addr_t rx_dma = 0, tx_dma = 0, rx_dummy_dma = 0, tx_dummy_dma = 0;
-+
-+
-+ if (xfer->rx_buf) {
-+ rx_dma = dma_map_single(controller->dev, xfer->rx_buf,
-+ xfer->len, DMA_FROM_DEVICE);
-+
-+ if (dma_mapping_error(controller->dev, rx_dma)) {
-+ ret = -ENOMEM;
-+ return ret;
-+ }
-+
-+ /* check to see if we need dummy buffer for leftover bytes */
-+ rx_align = xfer->len % controller->in_blk_sz;
-+ if (rx_align) {
-+ rx_dummy_dma = dma_map_single(controller->dev,
-+ controller->dummy, controller->in_fifo_sz,
-+ DMA_FROM_DEVICE);
-+
-+ if (dma_mapping_error(controller->dev, rx_dummy_dma)) {
-+ ret = -ENOMEM;
-+ goto err_map_rx_dummy;
-+ }
-+ }
-+ }
-+
-+ if (xfer->tx_buf) {
-+ tx_dma = dma_map_single(controller->dev,
-+ (void *)xfer->tx_buf, xfer->len, DMA_TO_DEVICE);
-+
-+ if (dma_mapping_error(controller->dev, tx_dma)) {
-+ ret = -ENOMEM;
-+ goto err_map_tx;
-+ }
-+
-+ /* check to see if we need dummy buffer for leftover bytes */
-+ tx_align = xfer->len % controller->out_blk_sz;
-+ if (tx_align) {
-+ memcpy(controller->dummy + SZ_1K,
-+ xfer->tx_buf + xfer->len - tx_align,
-+ tx_align);
-+ memset(controller->dummy + SZ_1K + tx_align, 0,
-+ controller->out_blk_sz - tx_align);
-+
-+ tx_dummy_dma = dma_map_single(controller->dev,
-+ controller->dummy + SZ_1K,
-+ controller->out_blk_sz, DMA_TO_DEVICE);
-+
-+ if (dma_mapping_error(controller->dev, tx_dummy_dma)) {
-+ ret = -ENOMEM;
-+ goto err_map_tx_dummy;
-+ }
-+ }
-+ }
-+
-+ atomic_set(&controller->dma_outstanding, 0);
-+
-+ while (bytes_to_xfer > 0) {
-+ xfer_len = min_t(u32, bytes_to_xfer, SPI_MAX_XFER);
-+ n_words = DIV_ROUND_UP(xfer_len, controller->w_size);
-+
-+ /* write out current word count to controller */
-+ writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
-+ writel_relaxed(n_words, controller->base + QUP_MX_OUTPUT_CNT);
-+
-+ reinit_completion(&controller->done);
-+
-+ if (xfer->tx_buf) {
-+ /* recalc align for each transaction */
-+ tx_align = xfer_len % controller->out_blk_sz;
-+
-+ if (tx_align)
-+ tx_nents = 2;
-+ else
-+ tx_nents = 1;
-+
-+ /* initialize scatterlists */
-+ sg_init_table(tx_sg, tx_nents);
-+ sg_dma_len(&tx_sg[0]) = xfer_len - tx_align;
-+ sg_dma_address(&tx_sg[0]) = tx_dma + offset;
-+
-+ /* account for non block size transfer */
-+ if (tx_align) {
-+ sg_dma_len(&tx_sg[1]) = controller->out_blk_sz;
-+ sg_dma_address(&tx_sg[1]) = tx_dummy_dma;
-+ }
-+
-+ txd = dmaengine_prep_slave_sg(controller->tx_chan,
-+ tx_sg, tx_nents, DMA_MEM_TO_DEV, 0);
-+ if (!txd) {
-+ ret = -ENOMEM;
-+ goto err_unmap;
-+ }
-+
-+ atomic_inc(&controller->dma_outstanding);
-+
-+ txd->callback = qup_dma_callback;
-+ txd->callback_param = controller;
-+
-+ tx_cookie = dmaengine_submit(txd);
-+
-+ dma_async_issue_pending(controller->tx_chan);
-+ }
-+
-+ if (xfer->rx_buf) {
-+ /* recalc align for each transaction */
-+ rx_align = xfer_len % controller->in_blk_sz;
-+
-+ if (rx_align)
-+ rx_nents = 2;
-+ else
-+ rx_nents = 1;
-+
-+ /* initialize scatterlists */
-+ sg_init_table(rx_sg, rx_nents);
-+ sg_dma_address(&rx_sg[0]) = rx_dma + offset;
-+ sg_dma_len(&rx_sg[0]) = xfer_len - rx_align;
-+
-+ /* account for non block size transfer */
-+ if (rx_align) {
-+ sg_dma_len(&rx_sg[1]) = controller->in_blk_sz;
-+ sg_dma_address(&rx_sg[1]) = rx_dummy_dma;
-+ }
-+
-+ rxd = dmaengine_prep_slave_sg(controller->rx_chan,
-+ rx_sg, rx_nents, DMA_DEV_TO_MEM, 0);
-+ if (!rxd) {
-+ ret = -ENOMEM;
-+ goto err_unmap;
-+ }
-+
-+ atomic_inc(&controller->dma_outstanding);
-+
-+ rxd->callback = qup_dma_callback;
-+ rxd->callback_param = controller;
-+
-+ rx_cookie = dmaengine_submit(rxd);
-+
-+ dma_async_issue_pending(controller->rx_chan);
-+ }
-+
-+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
-+ goto err_unmap;
-+ }
-+
-+ if (!wait_for_completion_timeout(&controller->done,
-+ msecs_to_jiffies(1000))) {
-+ ret = -ETIMEDOUT;
-+
-+ /* clear out all the DMA transactions */
-+ if (xfer->tx_buf)
-+ dmaengine_terminate_all(controller->tx_chan);
-+ if (xfer->rx_buf)
-+ dmaengine_terminate_all(controller->rx_chan);
-+
-+ goto err_unmap;
-+ }
-+
-+ if (rx_align)
-+ memcpy(xfer->rx_buf + offset + xfer->len - rx_align,
-+ controller->dummy, rx_align);
-+
-+ /* adjust remaining bytes to transfer */
-+ bytes_to_xfer -= xfer_len;
-+ offset += xfer_len;
-+
-+
-+ /* reset mini-core state so we can program next transaction */
-+ if (spi_qup_set_state(controller, QUP_STATE_RESET)) {
-+ dev_err(controller->dev, "cannot set RESET state\n");
-+ goto err_unmap;
-+ }
-+ }
-+
-+ ret = 0;
-+
-+err_unmap:
-+ if (tx_align)
-+ dma_unmap_single(controller->dev, tx_dummy_dma,
-+ controller->out_fifo_sz, DMA_TO_DEVICE);
-+err_map_tx_dummy:
-+ if (xfer->tx_buf)
-+ dma_unmap_single(controller->dev, tx_dma, xfer->len,
-+ DMA_TO_DEVICE);
-+err_map_tx:
-+ if (rx_align)
-+ dma_unmap_single(controller->dev, rx_dummy_dma,
-+ controller->in_fifo_sz, DMA_FROM_DEVICE);
-+err_map_rx_dummy:
-+ if (xfer->rx_buf)
-+ dma_unmap_single(controller->dev, rx_dma, xfer->len,
-+ DMA_FROM_DEVICE);
-+
-+ return ret;
-+}
-+
- static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
- {
- struct spi_qup *controller = dev_id;
-@@ -315,11 +545,13 @@ static irqreturn_t spi_qup_qup_irq(int i
- error = -EIO;
- }
-
-- if (opflags & QUP_OP_IN_SERVICE_FLAG)
-- spi_qup_fifo_read(controller, xfer);
-+ if (!controller->use_dma) {
-+ if (opflags & QUP_OP_IN_SERVICE_FLAG)
-+ spi_qup_fifo_read(controller, xfer);
-
-- if (opflags & QUP_OP_OUT_SERVICE_FLAG)
-- spi_qup_fifo_write(controller, xfer);
-+ if (opflags & QUP_OP_OUT_SERVICE_FLAG)
-+ spi_qup_fifo_write(controller, xfer);
-+ }
-
- spin_lock_irqsave(&controller->lock, flags);
- controller->error = error;
-@@ -339,6 +571,8 @@ static int spi_qup_io_config(struct spi_
- struct spi_qup *controller = spi_master_get_devdata(spi->master);
- u32 config, iomode, mode;
- int ret, n_words, w_size;
-+ size_t dma_align = dma_get_cache_alignment();
-+ u32 dma_available = 0;
-
- if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
- dev_err(controller->dev, "too big size for loopback %d > %d\n",
-@@ -367,6 +601,11 @@ static int spi_qup_io_config(struct spi_
- n_words = xfer->len / w_size;
- controller->w_size = w_size;
-
-+ if (controller->rx_chan &&
-+ IS_ALIGNED((size_t)xfer->tx_buf, dma_align) &&
-+ IS_ALIGNED((size_t)xfer->rx_buf, dma_align))
-+ dma_available = 1;
-+
- if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
- mode = QUP_IO_M_MODE_FIFO;
- writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
-@@ -374,19 +613,31 @@ static int spi_qup_io_config(struct spi_
- /* must be zero for FIFO */
- writel_relaxed(0, controller->base + QUP_MX_INPUT_CNT);
- writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
-- } else {
-+ controller->use_dma = 0;
-+ } else if (!dma_available) {
- mode = QUP_IO_M_MODE_BLOCK;
- writel_relaxed(n_words, controller->base + QUP_MX_INPUT_CNT);
- writel_relaxed(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);
-+ controller->use_dma = 0;
-+ } else {
-+ mode = QUP_IO_M_MODE_DMOV;
-+ writel_relaxed(0, controller->base + QUP_MX_READ_CNT);
-+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
-+ controller->use_dma = 1;
- }
-
- 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);
-- iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
-+
-+ if (!controller->use_dma)
-+ iomode &= ~(QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN);
-+ else
-+ iomode |= QUP_IO_M_PACK_EN | QUP_IO_M_UNPACK_EN;
-+
- iomode |= (mode << QUP_IO_M_OUTPUT_MODE_MASK_SHIFT);
- iomode |= (mode << QUP_IO_M_INPUT_MODE_MASK_SHIFT);
-
-@@ -419,6 +670,14 @@ static int spi_qup_io_config(struct spi_
- config &= ~(QUP_CONFIG_NO_INPUT | QUP_CONFIG_NO_OUTPUT | QUP_CONFIG_N);
- config |= xfer->bits_per_word - 1;
- config |= QUP_CONFIG_SPI_MODE;
-+
-+ if (controller->use_dma) {
-+ 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 */
-@@ -452,25 +711,29 @@ static int spi_qup_transfer_one(struct s
- controller->tx_bytes = 0;
- spin_unlock_irqrestore(&controller->lock, flags);
-
-- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-- dev_warn(controller->dev, "cannot set RUN state\n");
-- goto exit;
-- }
-+ if (controller->use_dma) {
-+ ret = spi_qup_do_dma(controller, xfer);
-+ } else {
-+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-+ dev_warn(controller->dev, "cannot set RUN state\n");
-+ goto exit;
-+ }
-
-- if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
-- dev_warn(controller->dev, "cannot set PAUSE state\n");
-- goto exit;
-- }
-+ if (spi_qup_set_state(controller, QUP_STATE_PAUSE)) {
-+ dev_warn(controller->dev, "cannot set PAUSE state\n");
-+ goto exit;
-+ }
-
-- spi_qup_fifo_write(controller, xfer);
-+ spi_qup_fifo_write(controller, xfer);
-
-- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-- dev_warn(controller->dev, "cannot set EXECUTE state\n");
-- goto exit;
-- }
-+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
-+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
-+ goto exit;
-+ }
-
-- if (!wait_for_completion_timeout(&controller->done, timeout))
-- ret = -ETIMEDOUT;
-+ if (!wait_for_completion_timeout(&controller->done, timeout))
-+ ret = -ETIMEDOUT;
-+ }
- exit:
- spi_qup_set_state(controller, QUP_STATE_RESET);
- spin_lock_irqsave(&controller->lock, flags);
-@@ -554,6 +817,7 @@ static int spi_qup_probe(struct platform
- master->transfer_one = spi_qup_transfer_one;
- master->dev.of_node = pdev->dev.of_node;
- master->auto_runtime_pm = true;
-+ master->dma_alignment = dma_get_cache_alignment();
-
- platform_set_drvdata(pdev, master);
-
-@@ -619,6 +883,56 @@ static int spi_qup_probe(struct platform
- QUP_ERROR_INPUT_UNDER_RUN | QUP_ERROR_OUTPUT_UNDER_RUN,
- base + QUP_ERROR_FLAGS_EN);
-
-+ /* allocate dma resources, if available */
-+ controller->rx_chan = dma_request_slave_channel(&pdev->dev, "rx");
-+ if (controller->rx_chan) {
-+ controller->tx_chan =
-+ dma_request_slave_channel(&pdev->dev, "tx");
-+
-+ if (!controller->tx_chan) {
-+ dev_err(&pdev->dev, "Failed to allocate dma tx chan");
-+ dma_release_channel(controller->rx_chan);
-+ }
-+
-+ /* set DMA parameters */
-+ controller->rx_conf.device_fc = 1;
-+ controller->rx_conf.src_addr = res->start + QUP_INPUT_FIFO;
-+ controller->rx_conf.src_maxburst = controller->in_blk_sz;
-+
-+ controller->tx_conf.device_fc = 1;
-+ controller->tx_conf.dst_addr = res->start + QUP_OUTPUT_FIFO;
-+ controller->tx_conf.dst_maxburst = controller->out_blk_sz;
-+
-+ if (dmaengine_slave_config(controller->rx_chan,
-+ &controller->rx_conf)) {
-+ dev_err(&pdev->dev, "failed to configure RX channel\n");
-+
-+ dma_release_channel(controller->rx_chan);
-+ dma_release_channel(controller->tx_chan);
-+ controller->tx_chan = NULL;
-+ controller->rx_chan = NULL;
-+ } else if (dmaengine_slave_config(controller->tx_chan,
-+ &controller->tx_conf)) {
-+ dev_err(&pdev->dev, "failed to configure TX channel\n");
-+
-+ dma_release_channel(controller->rx_chan);
-+ dma_release_channel(controller->tx_chan);
-+ controller->tx_chan = NULL;
-+ controller->rx_chan = NULL;
-+ }
-+
-+ controller->dummy = devm_kmalloc(controller->dev, PAGE_SIZE,
-+ GFP_KERNEL);
-+
-+ if (!controller->dummy) {
-+ dma_release_channel(controller->rx_chan);
-+ dma_release_channel(controller->tx_chan);
-+ controller->tx_chan = NULL;
-+ controller->rx_chan = NULL;
-+ }
-+ }
-+
-+
- writel_relaxed(0, base + SPI_CONFIG);
- writel_relaxed(SPI_IO_C_NO_TRI_STATE, base + SPI_IO_CONTROL);
-
-@@ -731,6 +1045,11 @@ static int spi_qup_remove(struct platfor
- if (ret)
- return ret;
-
-+ if (controller->rx_chan)
-+ dma_release_channel(controller->rx_chan);
-+ if (controller->tx_chan)
-+ dma_release_channel(controller->tx_chan);
-+
- clk_disable_unprepare(controller->cclk);
- clk_disable_unprepare(controller->iclk);
-