This will allow ipq806x to support multiple kernel version more easily.
Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
SVN-Revision: 44616
--- /dev/null
+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);
+@@ -553,6 +816,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);
+
+@@ -618,6 +882,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);
+
+@@ -730,6 +1044,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);
+
--- /dev/null
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [v3] spi: qup: Fix incorrect block transfers
+From: Andy Gross <agross@codeaurora.org>
+X-Patchwork-Id: 5007321
+Message-Id: <1412112088-25928-1-git-send-email-agross@codeaurora.org>
+To: Mark Brown <broonie@kernel.org>
+Cc: linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org,
+ linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org,
+ "Ivan T. Ivanov" <iivanov@mm-sol.com>,
+ Bjorn Andersson <bjorn.andersson@sonymobile.com>,
+ Kumar Gala <galak@codeaurora.org>, Andy Gross <agross@codeaurora.org>
+Date: Tue, 30 Sep 2014 16:21:28 -0500
+
+This patch fixes a number of errors with the QUP block transfer mode. Errors
+manifested themselves as input underruns, output overruns, and timed out
+transactions.
+
+The block mode does not require the priming that occurs in FIFO mode. At the
+moment that the QUP is placed into the RUN state, the QUP will immediately raise
+an interrupt if the request is a write. Therefore, there is no need to prime
+the pump.
+
+In addition, the block transfers require that whole blocks of data are
+read/written at a time. The last block of data that completes a transaction may
+contain less than a full blocks worth of data.
+
+Each block of data results in an input/output service interrupt accompanied with
+a input/output block flag set. Additional block reads/writes require clearing
+of the service flag. It is ok to check for additional blocks of data in the
+ISR, but you have to ack every block you transfer. Imbalanced acks result in
+early return from complete transactions with pending interrupts that still have
+to be ack'd. The next transaction can be affected by these interrupts.
+Transactions are deemed complete when the MAX_INPUT or MAX_OUTPUT flag are set.
+
+Changes from v2:
+- Added in additional completion check so that transaction done is not
+ prematurely signaled.
+- Fixed various review comments.
+
+Changes from v1:
+- Split out read/write block function.
+- Removed extraneous checks for transfer length
+
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+
+---
+drivers/spi/spi-qup.c | 201 ++++++++++++++++++++++++++++++++++++-------------
+ 1 file changed, 148 insertions(+), 53 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -82,6 +82,8 @@
+ #define QUP_IO_M_MODE_BAM 3
+
+ /* QUP_OPERATIONAL fields */
++#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
++#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
+ #define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
+ #define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
+ #define QUP_OP_IN_SERVICE_FLAG BIT(9)
+@@ -147,6 +149,7 @@ struct spi_qup {
+ int tx_bytes;
+ int rx_bytes;
+ int qup_v1;
++ int mode;
+
+ int use_dma;
+
+@@ -213,30 +216,14 @@ static int spi_qup_set_state(struct spi_
+ return 0;
+ }
+
+-
+-static void spi_qup_fifo_read(struct spi_qup *controller,
+- struct spi_transfer *xfer)
++static void spi_qup_fill_read_buffer(struct spi_qup *controller,
++ struct spi_transfer *xfer, u32 data)
+ {
+ u8 *rx_buf = xfer->rx_buf;
+- u32 word, state;
+- int idx, shift, w_size;
+-
+- w_size = controller->w_size;
+-
+- while (controller->rx_bytes < xfer->len) {
+-
+- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
+- break;
+-
+- word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
+-
+- if (!rx_buf) {
+- controller->rx_bytes += w_size;
+- continue;
+- }
++ int idx, shift;
+
+- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
++ if (rx_buf)
++ for (idx = 0; idx < controller->w_size; idx++) {
+ /*
+ * The data format depends on bytes per SPI word:
+ * 4 bytes: 0x12345678
+@@ -244,41 +231,139 @@ static void spi_qup_fifo_read(struct spi
+ * 1 byte : 0x00000012
+ */
+ shift = BITS_PER_BYTE;
+- shift *= (w_size - idx - 1);
+- rx_buf[controller->rx_bytes] = word >> shift;
++ shift *= (controller->w_size - idx - 1);
++ rx_buf[controller->rx_bytes + idx] = data >> shift;
++ }
++
++ controller->rx_bytes += controller->w_size;
++}
++
++static void spi_qup_prepare_write_data(struct spi_qup *controller,
++ struct spi_transfer *xfer, u32 *data)
++{
++ const u8 *tx_buf = xfer->tx_buf;
++ u32 val;
++ int idx;
++
++ *data = 0;
++
++ if (tx_buf)
++ for (idx = 0; idx < controller->w_size; idx++) {
++ val = tx_buf[controller->tx_bytes + idx];
++ *data |= val << (BITS_PER_BYTE * (3 - idx));
+ }
++
++ controller->tx_bytes += controller->w_size;
++}
++
++static void spi_qup_fifo_read(struct spi_qup *controller,
++ struct spi_transfer *xfer)
++{
++ u32 data;
++
++ /* clear service request */
++ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++ controller->base + QUP_OPERATIONAL);
++
++ while (controller->rx_bytes < xfer->len) {
++ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++ QUP_OP_IN_FIFO_NOT_EMPTY))
++ break;
++
++ data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
++
++ spi_qup_fill_read_buffer(controller, xfer, data);
+ }
+ }
+
+ static void spi_qup_fifo_write(struct spi_qup *controller,
+- struct spi_transfer *xfer)
++ struct spi_transfer *xfer)
+ {
+- const u8 *tx_buf = xfer->tx_buf;
+- u32 word, state, data;
+- int idx, w_size;
++ u32 data;
+
+- w_size = controller->w_size;
++ /* clear service request */
++ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
++ controller->base + QUP_OPERATIONAL);
+
+ while (controller->tx_bytes < xfer->len) {
+
+- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
+- if (state & QUP_OP_OUT_FIFO_FULL)
++ if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
++ QUP_OP_OUT_FIFO_FULL)
+ break;
+
+- word = 0;
+- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
++ spi_qup_prepare_write_data(controller, xfer, &data);
++ writel_relaxed(data, controller->base + QUP_OUTPUT_FIFO);
+
+- if (!tx_buf) {
+- controller->tx_bytes += w_size;
+- break;
+- }
++ }
++}
+
+- data = tx_buf[controller->tx_bytes];
+- word |= data << (BITS_PER_BYTE * (3 - idx));
+- }
++static void spi_qup_block_read(struct spi_qup *controller,
++ struct spi_transfer *xfer)
++{
++ u32 data;
++ u32 reads_per_blk = controller->in_blk_sz >> 2;
++ u32 num_words = (xfer->len - controller->rx_bytes) / controller->w_size;
++ int i;
++
++ do {
++ /* ACK by clearing service flag */
++ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++ controller->base + QUP_OPERATIONAL);
++
++ /* transfer up to a block size of data in a single pass */
++ for (i = 0; num_words && i < reads_per_blk; i++, num_words--) {
++
++ /* read data and fill up rx buffer */
++ data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
++ spi_qup_fill_read_buffer(controller, xfer, data);
++ }
++
++ /* check to see if next block is ready */
++ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++ QUP_OP_IN_BLOCK_READ_REQ))
++ break;
+
+- writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
+- }
++ } while (num_words);
++
++ /*
++ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
++ * reads, it has to be cleared again at the very end
++ */
++ if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
++ QUP_OP_MAX_INPUT_DONE_FLAG)
++ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
++ controller->base + QUP_OPERATIONAL);
++
++}
++
++static void spi_qup_block_write(struct spi_qup *controller,
++ struct spi_transfer *xfer)
++{
++ u32 data;
++ u32 writes_per_blk = controller->out_blk_sz >> 2;
++ u32 num_words = (xfer->len - controller->tx_bytes) / controller->w_size;
++ int i;
++
++ do {
++ /* ACK by clearing service flag */
++ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
++ controller->base + QUP_OPERATIONAL);
++
++ /* transfer up to a block size of data in a single pass */
++ for (i = 0; num_words && i < writes_per_blk; i++, num_words--) {
++
++ /* swizzle the bytes for output and write out */
++ spi_qup_prepare_write_data(controller, xfer, &data);
++ writel_relaxed(data,
++ controller->base + QUP_OUTPUT_FIFO);
++ }
++
++ /* check to see if next block is ready */
++ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
++ QUP_OP_OUT_BLOCK_WRITE_REQ))
++ break;
++
++ } while (num_words);
+ }
+
+ static void qup_dma_callback(void *data)
+@@ -515,9 +600,9 @@ static irqreturn_t spi_qup_qup_irq(int i
+
+ writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
+ writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
+- writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+
+ if (!xfer) {
++ writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
+ dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
+ qup_err, spi_err, opflags);
+ return IRQ_HANDLED;
+@@ -546,11 +631,19 @@ static irqreturn_t spi_qup_qup_irq(int i
+ }
+
+ if (!controller->use_dma) {
+- if (opflags & QUP_OP_IN_SERVICE_FLAG)
+- spi_qup_fifo_read(controller, xfer);
++ if (opflags & QUP_OP_IN_SERVICE_FLAG) {
++ if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
++ spi_qup_block_read(controller, xfer);
++ else
++ 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) {
++ if (opflags & QUP_OP_OUT_BLOCK_WRITE_REQ)
++ spi_qup_block_write(controller, xfer);
++ else
++ spi_qup_fifo_write(controller, xfer);
++ }
+ }
+
+ spin_lock_irqsave(&controller->lock, flags);
+@@ -558,7 +651,8 @@ static irqreturn_t spi_qup_qup_irq(int i
+ controller->xfer = xfer;
+ spin_unlock_irqrestore(&controller->lock, flags);
+
+- if (controller->rx_bytes == xfer->len || error)
++ if ((controller->rx_bytes == xfer->len &&
++ (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) || error)
+ complete(&controller->done);
+
+ return IRQ_HANDLED;
+@@ -569,7 +663,7 @@ static irqreturn_t spi_qup_qup_irq(int i
+ 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, mode;
++ u32 config, iomode;
+ int ret, n_words, w_size;
+ size_t dma_align = dma_get_cache_alignment();
+ u32 dma_available = 0;
+@@ -607,7 +701,7 @@ static int spi_qup_io_config(struct spi_
+ dma_available = 1;
+
+ if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
+- mode = QUP_IO_M_MODE_FIFO;
++ controller->mode = QUP_IO_M_MODE_FIFO;
+ writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
+ writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
+ /* must be zero for FIFO */
+@@ -615,7 +709,7 @@ static int spi_qup_io_config(struct spi_
+ writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
+ controller->use_dma = 0;
+ } else if (!dma_available) {
+- mode = QUP_IO_M_MODE_BLOCK;
++ controller->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 */
+@@ -623,7 +717,7 @@ static int spi_qup_io_config(struct spi_
+ writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
+ controller->use_dma = 0;
+ } else {
+- mode = QUP_IO_M_MODE_DMOV;
++ controller->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;
+@@ -638,8 +732,8 @@ static int spi_qup_io_config(struct spi_
+ 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);
++ 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);
+
+@@ -724,7 +818,8 @@ static int spi_qup_transfer_one(struct s
+ goto exit;
+ }
+
+- spi_qup_fifo_write(controller, xfer);
++ if (controller->mode == QUP_IO_M_MODE_FIFO)
++ spi_qup_fifo_write(controller, xfer);
+
+ if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
+ dev_warn(controller->dev, "cannot set EXECUTE state\n");
+@@ -741,6 +836,7 @@ exit:
+ if (!ret)
+ ret = controller->error;
+ spin_unlock_irqrestore(&controller->lock, flags);
++
+ return ret;
+ }
+
--- /dev/null
+From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001
+From: Andy Gross <agross@codeaurora.org>
+Date: Thu, 15 Jan 2015 17:56:02 -0800
+Subject: [PATCH] spi: qup: Ensure done detection
+
+This patch fixes an issue where a SPI transaction has completed, but the done
+condition is missed. This occurs because at the time of interrupt the
+MAX_INPUT_DONE_FLAG is not asserted. However, in the process of reading blocks
+of data from the FIFO, the last portion of data comes in.
+
+The opflags read at the beginning of the irq handler no longer matches the
+current opflag state. To get around this condition, the block read function
+should update the opflags so that done detection is correct after the return.
+
+Change-Id: If109e0eeb432f96000d765c4b34dbb2269f8093f
+Signed-off-by: Andy Gross <agross@codeaurora.org>
+---
+ drivers/spi/spi-qup.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/drivers/spi/spi-qup.c
++++ b/drivers/spi/spi-qup.c
+@@ -298,7 +298,7 @@ static void spi_qup_fifo_write(struct sp
+ }
+
+ static void spi_qup_block_read(struct spi_qup *controller,
+- struct spi_transfer *xfer)
++ struct spi_transfer *xfer, u32 *opflags)
+ {
+ u32 data;
+ u32 reads_per_blk = controller->in_blk_sz >> 2;
+@@ -327,10 +327,12 @@ static void spi_qup_block_read(struct sp
+
+ /*
+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
+- * reads, it has to be cleared again at the very end
++ * reads, it has to be cleared again at the very end. However, be sure
++ * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
++ * present and this is used to determine if transaction is complete
+ */
+- if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
+- QUP_OP_MAX_INPUT_DONE_FLAG)
++ *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
++ if (*opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
+ controller->base + QUP_OPERATIONAL);
+
+@@ -633,7 +635,7 @@ static irqreturn_t spi_qup_qup_irq(int i
+ if (!controller->use_dma) {
+ if (opflags & QUP_OP_IN_SERVICE_FLAG) {
+ if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
+- spi_qup_block_read(controller, xfer);
++ spi_qup_block_read(controller, xfer, &opflags);
+ else
+ spi_qup_fifo_read(controller, xfer);
+ }
--- /dev/null
+From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:19:30 -0800
+Subject: [PATCH 1/3] watchdog: qcom: use timer devicetree binding
+
+MSM watchdog configuration happens in the same register block as the
+timer, so we'll use the same binding as the existing timer.
+
+The qcom-wdt will now be probed when devicetree has an entry compatible
+with "qcom,kpss-timer" or "qcom-scss-timer".
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ drivers/watchdog/qcom-wdt.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
+index aa85618..aa03ca8 100644
+--- a/drivers/watchdog/qcom-wdt.c
++++ b/drivers/watchdog/qcom-wdt.c
+@@ -20,9 +20,9 @@
+ #include <linux/reboot.h>
+ #include <linux/watchdog.h>
+
+-#define WDT_RST 0x0
+-#define WDT_EN 0x8
+-#define WDT_BITE_TIME 0x24
++#define WDT_RST 0x38
++#define WDT_EN 0x40
++#define WDT_BITE_TIME 0x5C
+
+ struct qcom_wdt {
+ struct watchdog_device wdd;
+@@ -117,6 +117,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
+ {
+ struct qcom_wdt *wdt;
+ struct resource *res;
++ struct device_node *np = pdev->dev.of_node;
++ u32 percpu_offset;
+ int ret;
+
+ wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+@@ -124,6 +126,14 @@ static int qcom_wdt_probe(struct platform_device *pdev)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++ /* We use CPU0's DGT for the watchdog */
++ if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
++ percpu_offset = 0;
++
++ res->start += percpu_offset;
++ res->end += percpu_offset;
++
+ wdt->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(wdt->base))
+ return PTR_ERR(wdt->base);
+@@ -203,9 +213,8 @@ static int qcom_wdt_remove(struct platform_device *pdev)
+ }
+
+ static const struct of_device_id qcom_wdt_of_table[] = {
+- { .compatible = "qcom,kpss-wdt-msm8960", },
+- { .compatible = "qcom,kpss-wdt-apq8064", },
+- { .compatible = "qcom,kpss-wdt-ipq8064", },
++ { .compatible = "qcom,kpss-timer" },
++ { .compatible = "qcom,scss-timer" },
+ { },
+ };
+ MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
+--
+1.9.1
+
--- /dev/null
+From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:27:39 -0800
+Subject: [PATCH 2/3] ARM: qcom: add description of KPSS WDT for IPQ8064
+
+Add the watchdog related entries to the Krait Processor Sub-system
+(KPSS) timer IPQ8064 devicetree section. Also, add a fixed-clock
+description of SLEEP_CLK, which will do for now.
+
+Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ arch/arm/boot/dts/qcom-ipq8064.dtsi | 14 +++++++++++++-
+ 1 file changed, 13 insertions(+), 1 deletion(-)
+
+diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+index cb225da..d01f618 100644
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -60,6 +60,14 @@
+ };
+ };
+
++ clocks {
++ sleep_clk: sleep_clk {
++ compatible = "fixed-clock";
++ clock-frequency = <32768>;
++ #clock-cells = <0>;
++ };
++ };
++
+ soc: soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+@@ -89,10 +97,14 @@
+ compatible = "qcom,kpss-timer", "qcom,msm-timer";
+ interrupts = <1 1 0x301>,
+ <1 2 0x301>,
+- <1 3 0x301>;
++ <1 3 0x301>,
++ <1 4 0x301>,
++ <1 5 0x301>;
+ reg = <0x0200a000 0x100>;
+ clock-frequency = <25000000>,
+ <32768>;
++ clocks = <&sleep_clk>;
++ clock-names = "sleep";
+ cpu-offset = <0x80000>;
+ };
+
+--
+1.9.1
+
--- /dev/null
+From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu@codeaurora.org>
+Date: Thu, 19 Feb 2015 20:36:27 -0800
+Subject: [PATCH 3/3] ARM: msm: add watchdog entries to DT timer binding doc
+
+The watchdog has been reworked to use the same DT node as the timer.
+This change is updating the device tree doc accordingly.
+
+Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
+---
+ Documentation/devicetree/bindings/arm/msm/timer.txt | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/Documentation/devicetree/bindings/arm/msm/timer.txt
++++ b/Documentation/devicetree/bindings/arm/msm/timer.txt
+@@ -9,11 +9,17 @@ Properties:
+ "qcom,scss-timer" - scorpion subsystem
+
+ - interrupts : Interrupts for the the debug timer, the first general purpose
+- timer, and optionally a second general purpose timer in that
+- order.
++ timer, and optionally a second general purpose timer, and
++ optionally as well, 2 watchdog interrupts, in that order.
+
+ - reg : Specifies the base address of the timer registers.
+
++- clocks: Reference to the parent clocks, one per output clock. The parents
++ must appear in the same order as the clock names.
++
++- clock-names: The name of the clocks as free-form strings. They should be in
++ the same order as the clocks.
++
+ - clock-frequency : The frequency of the debug timer and the general purpose
+ timer(s) in Hz in that order.
+
+@@ -29,9 +35,13 @@ Example:
+ compatible = "qcom,scss-timer", "qcom,msm-timer";
+ interrupts = <1 1 0x301>,
+ <1 2 0x301>,
+- <1 3 0x301>;
++ <1 3 0x301>,
++ <1 4 0x301>,
++ <1 5 0x301>;
+ reg = <0x0200a000 0x100>;
+ clock-frequency = <19200000>,
+ <32768>;
++ clocks = <&sleep_clk>;
++ clock-names = "sleep";
+ cpu-offset = <0x40000>;
+ };
--- /dev/null
+--- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
++++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
+@@ -18,8 +18,15 @@
+ bootargs = "console=ttyMSM0,115200 root=/dev/mtdblock12 rootfstype=squashfs,jffs2";
+ };
+
++ aliases {
++ mdio-gpio0 = &mdio0;
++ };
++
+ soc {
+ pinmux@800000 {
++ pinctrl-0 = <&mdio0_pins &rgmii2_pins>;
++ pinctrl-names = "default";
++
+ i2c4_pins: i2c4_pinmux {
+ pins = "gpio12", "gpio13";
+ function = "gsbi4";
+@@ -34,6 +41,25 @@
+ bias-none;
+ };
+ };
++
++ mdio0_pins: mdio0_pins {
++ mux {
++ pins = "gpio0", "gpio1";
++ function = "gpio";
++ drive-strength = <8>;
++ bias-disable;
++ };
++ };
++
++ rgmii2_pins: rgmii2_pins {
++ mux {
++ pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
++ "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
++ function = "rgmii2";
++ drive-strength = <8>;
++ bias-disable;
++ };
++ };
+ };
+
+ gsbi@16300000 {
+@@ -72,6 +98,7 @@
+ #size-cells = <1>;
+ spi-max-frequency = <50000000>;
+ reg = <0>;
++ m25p,fast-read;
+
+ partition@0 {
+ label = "0:SBL1";
+@@ -148,5 +175,66 @@
+ sata@29000000 {
+ status = "ok";
+ };
++
++ mdio0: mdio {
++ compatible = "virtual,mdio-gpio";
++ #address-cells = <1>;
++ #size-cells = <0>;
++ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
++
++ phy0: ethernet-phy@0 {
++ device_type = "ethernet-phy";
++ reg = <0>;
++ qca,ar8327-initvals = <
++ 0x00004 0x7600000 /* PAD0_MODE */
++ 0x00008 0x1000000 /* PAD5_MODE */
++ 0x0000c 0x80 /* PAD6_MODE */
++ 0x000e4 0xaa545 /* MAC_POWER_SEL */
++ 0x000e0 0xc74164de /* SGMII_CTRL */
++ 0x0007c 0x4e /* PORT0_STATUS */
++ 0x00094 0x4e /* PORT6_STATUS */
++ >;
++ };
++
++ phy4: ethernet-phy@4 {
++ device_type = "ethernet-phy";
++ reg = <4>;
++ };
++ };
++
++ nss-gmac-common {
++ reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
++ reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
++ };
++
++ gmac1: ethernet@37200000 {
++ status = "ok";
++ phy-mode = "rgmii";
++ qcom,id = <1>;
++ qcom,phy_mdio_addr = <4>;
++ qcom,poll_required = <1>;
++ qcom,rgmii_delay = <0>;
++ qcom,emulation = <0>;
++ qcom,forced_speed = <1000>;
++ qcom,forced_duplex = <1>;
++ qcom,socver = <0>;
++ local-mac-address = [000000000000];
++ mdiobus = <&mdio0>;
++ };
++
++ gmac2: ethernet@37400000 {
++ status = "ok";
++ phy-mode = "sgmii";
++ qcom,id = <2>;
++ qcom,phy_mdio_addr = <0>;
++ qcom,poll_required = <0>;
++ qcom,rgmii_delay = <0>;
++ qcom,emulation = <0>;
++ qcom,forced_speed = <1000>;
++ qcom,forced_duplex = <1>;
++ qcom,socver = <0>;
++ local-mac-address = [000000000000];
++ mdiobus = <&mdio0>;
++ };
+ };
+ };
+--- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
++++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
+@@ -3,6 +3,7 @@
+ #include "skeleton.dtsi"
+ #include <dt-bindings/clock/qcom,gcc-ipq806x.h>
+ #include <dt-bindings/soc/qcom,gsbi.h>
++#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ / {
+ model = "Qualcomm IPQ8064";
+@@ -279,5 +280,42 @@
+ #clock-cells = <1>;
+ #reset-cells = <1>;
+ };
++
++ nss-gmac-common {
++ reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
++ reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
++ };
++
++ gmac0: ethernet@37000000 {
++ device_type = "network";
++ compatible = "qcom,nss-gmac";
++ reg = <0x37000000 0x200000>;
++ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ gmac1: ethernet@37200000 {
++ device_type = "network";
++ compatible = "qcom,nss-gmac";
++ reg = <0x37200000 0x200000>;
++ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ gmac2: ethernet@37400000 {
++ device_type = "network";
++ compatible = "qcom,nss-gmac";
++ reg = <0x37400000 0x200000>;
++ interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
++
++ gmac3: ethernet@37600000 {
++ device_type = "network";
++ compatible = "qcom,nss-gmac";
++ reg = <0x37600000 0x200000>;
++ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
++ status = "disabled";
++ };
+ };
+ };
+++ /dev/null
-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);
-@@ -553,6 +816,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);
-
-@@ -618,6 +882,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);
-
-@@ -730,6 +1044,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);
-
+++ /dev/null
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3] spi: qup: Fix incorrect block transfers
-From: Andy Gross <agross@codeaurora.org>
-X-Patchwork-Id: 5007321
-Message-Id: <1412112088-25928-1-git-send-email-agross@codeaurora.org>
-To: Mark Brown <broonie@kernel.org>
-Cc: linux-spi@vger.kernel.org, linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org, linux-arm-msm@vger.kernel.org,
- "Ivan T. Ivanov" <iivanov@mm-sol.com>,
- Bjorn Andersson <bjorn.andersson@sonymobile.com>,
- Kumar Gala <galak@codeaurora.org>, Andy Gross <agross@codeaurora.org>
-Date: Tue, 30 Sep 2014 16:21:28 -0500
-
-This patch fixes a number of errors with the QUP block transfer mode. Errors
-manifested themselves as input underruns, output overruns, and timed out
-transactions.
-
-The block mode does not require the priming that occurs in FIFO mode. At the
-moment that the QUP is placed into the RUN state, the QUP will immediately raise
-an interrupt if the request is a write. Therefore, there is no need to prime
-the pump.
-
-In addition, the block transfers require that whole blocks of data are
-read/written at a time. The last block of data that completes a transaction may
-contain less than a full blocks worth of data.
-
-Each block of data results in an input/output service interrupt accompanied with
-a input/output block flag set. Additional block reads/writes require clearing
-of the service flag. It is ok to check for additional blocks of data in the
-ISR, but you have to ack every block you transfer. Imbalanced acks result in
-early return from complete transactions with pending interrupts that still have
-to be ack'd. The next transaction can be affected by these interrupts.
-Transactions are deemed complete when the MAX_INPUT or MAX_OUTPUT flag are set.
-
-Changes from v2:
-- Added in additional completion check so that transaction done is not
- prematurely signaled.
-- Fixed various review comments.
-
-Changes from v1:
-- Split out read/write block function.
-- Removed extraneous checks for transfer length
-
-Signed-off-by: Andy Gross <agross@codeaurora.org>
-
----
-drivers/spi/spi-qup.c | 201 ++++++++++++++++++++++++++++++++++++-------------
- 1 file changed, 148 insertions(+), 53 deletions(-)
-
---- a/drivers/spi/spi-qup.c
-+++ b/drivers/spi/spi-qup.c
-@@ -82,6 +82,8 @@
- #define QUP_IO_M_MODE_BAM 3
-
- /* QUP_OPERATIONAL fields */
-+#define QUP_OP_IN_BLOCK_READ_REQ BIT(13)
-+#define QUP_OP_OUT_BLOCK_WRITE_REQ BIT(12)
- #define QUP_OP_MAX_INPUT_DONE_FLAG BIT(11)
- #define QUP_OP_MAX_OUTPUT_DONE_FLAG BIT(10)
- #define QUP_OP_IN_SERVICE_FLAG BIT(9)
-@@ -147,6 +149,7 @@ struct spi_qup {
- int tx_bytes;
- int rx_bytes;
- int qup_v1;
-+ int mode;
-
- int use_dma;
-
-@@ -213,30 +216,14 @@ static int spi_qup_set_state(struct spi_
- return 0;
- }
-
--
--static void spi_qup_fifo_read(struct spi_qup *controller,
-- struct spi_transfer *xfer)
-+static void spi_qup_fill_read_buffer(struct spi_qup *controller,
-+ struct spi_transfer *xfer, u32 data)
- {
- u8 *rx_buf = xfer->rx_buf;
-- u32 word, state;
-- int idx, shift, w_size;
--
-- w_size = controller->w_size;
--
-- while (controller->rx_bytes < xfer->len) {
--
-- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
-- if (0 == (state & QUP_OP_IN_FIFO_NOT_EMPTY))
-- break;
--
-- word = readl_relaxed(controller->base + QUP_INPUT_FIFO);
--
-- if (!rx_buf) {
-- controller->rx_bytes += w_size;
-- continue;
-- }
-+ int idx, shift;
-
-- for (idx = 0; idx < w_size; idx++, controller->rx_bytes++) {
-+ if (rx_buf)
-+ for (idx = 0; idx < controller->w_size; idx++) {
- /*
- * The data format depends on bytes per SPI word:
- * 4 bytes: 0x12345678
-@@ -244,41 +231,139 @@ static void spi_qup_fifo_read(struct spi
- * 1 byte : 0x00000012
- */
- shift = BITS_PER_BYTE;
-- shift *= (w_size - idx - 1);
-- rx_buf[controller->rx_bytes] = word >> shift;
-+ shift *= (controller->w_size - idx - 1);
-+ rx_buf[controller->rx_bytes + idx] = data >> shift;
-+ }
-+
-+ controller->rx_bytes += controller->w_size;
-+}
-+
-+static void spi_qup_prepare_write_data(struct spi_qup *controller,
-+ struct spi_transfer *xfer, u32 *data)
-+{
-+ const u8 *tx_buf = xfer->tx_buf;
-+ u32 val;
-+ int idx;
-+
-+ *data = 0;
-+
-+ if (tx_buf)
-+ for (idx = 0; idx < controller->w_size; idx++) {
-+ val = tx_buf[controller->tx_bytes + idx];
-+ *data |= val << (BITS_PER_BYTE * (3 - idx));
- }
-+
-+ controller->tx_bytes += controller->w_size;
-+}
-+
-+static void spi_qup_fifo_read(struct spi_qup *controller,
-+ struct spi_transfer *xfer)
-+{
-+ u32 data;
-+
-+ /* clear service request */
-+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
-+ controller->base + QUP_OPERATIONAL);
-+
-+ while (controller->rx_bytes < xfer->len) {
-+ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
-+ QUP_OP_IN_FIFO_NOT_EMPTY))
-+ break;
-+
-+ data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
-+
-+ spi_qup_fill_read_buffer(controller, xfer, data);
- }
- }
-
- static void spi_qup_fifo_write(struct spi_qup *controller,
-- struct spi_transfer *xfer)
-+ struct spi_transfer *xfer)
- {
-- const u8 *tx_buf = xfer->tx_buf;
-- u32 word, state, data;
-- int idx, w_size;
-+ u32 data;
-
-- w_size = controller->w_size;
-+ /* clear service request */
-+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
-+ controller->base + QUP_OPERATIONAL);
-
- while (controller->tx_bytes < xfer->len) {
-
-- state = readl_relaxed(controller->base + QUP_OPERATIONAL);
-- if (state & QUP_OP_OUT_FIFO_FULL)
-+ if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
-+ QUP_OP_OUT_FIFO_FULL)
- break;
-
-- word = 0;
-- for (idx = 0; idx < w_size; idx++, controller->tx_bytes++) {
-+ spi_qup_prepare_write_data(controller, xfer, &data);
-+ writel_relaxed(data, controller->base + QUP_OUTPUT_FIFO);
-
-- if (!tx_buf) {
-- controller->tx_bytes += w_size;
-- break;
-- }
-+ }
-+}
-
-- data = tx_buf[controller->tx_bytes];
-- word |= data << (BITS_PER_BYTE * (3 - idx));
-- }
-+static void spi_qup_block_read(struct spi_qup *controller,
-+ struct spi_transfer *xfer)
-+{
-+ u32 data;
-+ u32 reads_per_blk = controller->in_blk_sz >> 2;
-+ u32 num_words = (xfer->len - controller->rx_bytes) / controller->w_size;
-+ int i;
-+
-+ do {
-+ /* ACK by clearing service flag */
-+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
-+ controller->base + QUP_OPERATIONAL);
-+
-+ /* transfer up to a block size of data in a single pass */
-+ for (i = 0; num_words && i < reads_per_blk; i++, num_words--) {
-+
-+ /* read data and fill up rx buffer */
-+ data = readl_relaxed(controller->base + QUP_INPUT_FIFO);
-+ spi_qup_fill_read_buffer(controller, xfer, data);
-+ }
-+
-+ /* check to see if next block is ready */
-+ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
-+ QUP_OP_IN_BLOCK_READ_REQ))
-+ break;
-
-- writel_relaxed(word, controller->base + QUP_OUTPUT_FIFO);
-- }
-+ } while (num_words);
-+
-+ /*
-+ * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
-+ * reads, it has to be cleared again at the very end
-+ */
-+ if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
-+ QUP_OP_MAX_INPUT_DONE_FLAG)
-+ writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
-+ controller->base + QUP_OPERATIONAL);
-+
-+}
-+
-+static void spi_qup_block_write(struct spi_qup *controller,
-+ struct spi_transfer *xfer)
-+{
-+ u32 data;
-+ u32 writes_per_blk = controller->out_blk_sz >> 2;
-+ u32 num_words = (xfer->len - controller->tx_bytes) / controller->w_size;
-+ int i;
-+
-+ do {
-+ /* ACK by clearing service flag */
-+ writel_relaxed(QUP_OP_OUT_SERVICE_FLAG,
-+ controller->base + QUP_OPERATIONAL);
-+
-+ /* transfer up to a block size of data in a single pass */
-+ for (i = 0; num_words && i < writes_per_blk; i++, num_words--) {
-+
-+ /* swizzle the bytes for output and write out */
-+ spi_qup_prepare_write_data(controller, xfer, &data);
-+ writel_relaxed(data,
-+ controller->base + QUP_OUTPUT_FIFO);
-+ }
-+
-+ /* check to see if next block is ready */
-+ if (!(readl_relaxed(controller->base + QUP_OPERATIONAL) &
-+ QUP_OP_OUT_BLOCK_WRITE_REQ))
-+ break;
-+
-+ } while (num_words);
- }
-
- static void qup_dma_callback(void *data)
-@@ -515,9 +600,9 @@ static irqreturn_t spi_qup_qup_irq(int i
-
- writel_relaxed(qup_err, controller->base + QUP_ERROR_FLAGS);
- writel_relaxed(spi_err, controller->base + SPI_ERROR_FLAGS);
-- writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
-
- if (!xfer) {
-+ writel_relaxed(opflags, controller->base + QUP_OPERATIONAL);
- dev_err_ratelimited(controller->dev, "unexpected irq %08x %08x %08x\n",
- qup_err, spi_err, opflags);
- return IRQ_HANDLED;
-@@ -546,11 +631,19 @@ static irqreturn_t spi_qup_qup_irq(int i
- }
-
- if (!controller->use_dma) {
-- if (opflags & QUP_OP_IN_SERVICE_FLAG)
-- spi_qup_fifo_read(controller, xfer);
-+ if (opflags & QUP_OP_IN_SERVICE_FLAG) {
-+ if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
-+ spi_qup_block_read(controller, xfer);
-+ else
-+ 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) {
-+ if (opflags & QUP_OP_OUT_BLOCK_WRITE_REQ)
-+ spi_qup_block_write(controller, xfer);
-+ else
-+ spi_qup_fifo_write(controller, xfer);
-+ }
- }
-
- spin_lock_irqsave(&controller->lock, flags);
-@@ -558,7 +651,8 @@ static irqreturn_t spi_qup_qup_irq(int i
- controller->xfer = xfer;
- spin_unlock_irqrestore(&controller->lock, flags);
-
-- if (controller->rx_bytes == xfer->len || error)
-+ if ((controller->rx_bytes == xfer->len &&
-+ (opflags & QUP_OP_MAX_INPUT_DONE_FLAG)) || error)
- complete(&controller->done);
-
- return IRQ_HANDLED;
-@@ -569,7 +663,7 @@ static irqreturn_t spi_qup_qup_irq(int i
- 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, mode;
-+ u32 config, iomode;
- int ret, n_words, w_size;
- size_t dma_align = dma_get_cache_alignment();
- u32 dma_available = 0;
-@@ -607,7 +701,7 @@ static int spi_qup_io_config(struct spi_
- dma_available = 1;
-
- if (n_words <= (controller->in_fifo_sz / sizeof(u32))) {
-- mode = QUP_IO_M_MODE_FIFO;
-+ controller->mode = QUP_IO_M_MODE_FIFO;
- writel_relaxed(n_words, controller->base + QUP_MX_READ_CNT);
- writel_relaxed(n_words, controller->base + QUP_MX_WRITE_CNT);
- /* must be zero for FIFO */
-@@ -615,7 +709,7 @@ static int spi_qup_io_config(struct spi_
- writel_relaxed(0, controller->base + QUP_MX_OUTPUT_CNT);
- controller->use_dma = 0;
- } else if (!dma_available) {
-- mode = QUP_IO_M_MODE_BLOCK;
-+ controller->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 */
-@@ -623,7 +717,7 @@ static int spi_qup_io_config(struct spi_
- writel_relaxed(0, controller->base + QUP_MX_WRITE_CNT);
- controller->use_dma = 0;
- } else {
-- mode = QUP_IO_M_MODE_DMOV;
-+ controller->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;
-@@ -638,8 +732,8 @@ static int spi_qup_io_config(struct spi_
- 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);
-+ 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);
-
-@@ -724,7 +818,8 @@ static int spi_qup_transfer_one(struct s
- goto exit;
- }
-
-- spi_qup_fifo_write(controller, xfer);
-+ if (controller->mode == QUP_IO_M_MODE_FIFO)
-+ spi_qup_fifo_write(controller, xfer);
-
- if (spi_qup_set_state(controller, QUP_STATE_RUN)) {
- dev_warn(controller->dev, "cannot set EXECUTE state\n");
-@@ -741,6 +836,7 @@ exit:
- if (!ret)
- ret = controller->error;
- spin_unlock_irqrestore(&controller->lock, flags);
-+
- return ret;
- }
-
+++ /dev/null
-From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001
-From: Andy Gross <agross@codeaurora.org>
-Date: Thu, 15 Jan 2015 17:56:02 -0800
-Subject: [PATCH] spi: qup: Ensure done detection
-
-This patch fixes an issue where a SPI transaction has completed, but the done
-condition is missed. This occurs because at the time of interrupt the
-MAX_INPUT_DONE_FLAG is not asserted. However, in the process of reading blocks
-of data from the FIFO, the last portion of data comes in.
-
-The opflags read at the beginning of the irq handler no longer matches the
-current opflag state. To get around this condition, the block read function
-should update the opflags so that done detection is correct after the return.
-
-Change-Id: If109e0eeb432f96000d765c4b34dbb2269f8093f
-Signed-off-by: Andy Gross <agross@codeaurora.org>
----
- drivers/spi/spi-qup.c | 12 +++++++-----
- 1 file changed, 7 insertions(+), 5 deletions(-)
-
---- a/drivers/spi/spi-qup.c
-+++ b/drivers/spi/spi-qup.c
-@@ -298,7 +298,7 @@ static void spi_qup_fifo_write(struct sp
- }
-
- static void spi_qup_block_read(struct spi_qup *controller,
-- struct spi_transfer *xfer)
-+ struct spi_transfer *xfer, u32 *opflags)
- {
- u32 data;
- u32 reads_per_blk = controller->in_blk_sz >> 2;
-@@ -327,10 +327,12 @@ static void spi_qup_block_read(struct sp
-
- /*
- * Due to extra stickiness of the QUP_OP_IN_SERVICE_FLAG during block
-- * reads, it has to be cleared again at the very end
-+ * reads, it has to be cleared again at the very end. However, be sure
-+ * to refresh opflags value because MAX_INPUT_DONE_FLAG may now be
-+ * present and this is used to determine if transaction is complete
- */
-- if (readl_relaxed(controller->base + QUP_OPERATIONAL) &
-- QUP_OP_MAX_INPUT_DONE_FLAG)
-+ *opflags = readl_relaxed(controller->base + QUP_OPERATIONAL);
-+ if (*opflags & QUP_OP_MAX_INPUT_DONE_FLAG)
- writel_relaxed(QUP_OP_IN_SERVICE_FLAG,
- controller->base + QUP_OPERATIONAL);
-
-@@ -633,7 +635,7 @@ static irqreturn_t spi_qup_qup_irq(int i
- if (!controller->use_dma) {
- if (opflags & QUP_OP_IN_SERVICE_FLAG) {
- if (opflags & QUP_OP_IN_BLOCK_READ_REQ)
-- spi_qup_block_read(controller, xfer);
-+ spi_qup_block_read(controller, xfer, &opflags);
- else
- spi_qup_fifo_read(controller, xfer);
- }
+++ /dev/null
-From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Thu, 19 Feb 2015 20:19:30 -0800
-Subject: [PATCH 1/3] watchdog: qcom: use timer devicetree binding
-
-MSM watchdog configuration happens in the same register block as the
-timer, so we'll use the same binding as the existing timer.
-
-The qcom-wdt will now be probed when devicetree has an entry compatible
-with "qcom,kpss-timer" or "qcom-scss-timer".
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- drivers/watchdog/qcom-wdt.c | 21 +++++++++++++++------
- 1 file changed, 15 insertions(+), 6 deletions(-)
-
-diff --git a/drivers/watchdog/qcom-wdt.c b/drivers/watchdog/qcom-wdt.c
-index aa85618..aa03ca8 100644
---- a/drivers/watchdog/qcom-wdt.c
-+++ b/drivers/watchdog/qcom-wdt.c
-@@ -20,9 +20,9 @@
- #include <linux/reboot.h>
- #include <linux/watchdog.h>
-
--#define WDT_RST 0x0
--#define WDT_EN 0x8
--#define WDT_BITE_TIME 0x24
-+#define WDT_RST 0x38
-+#define WDT_EN 0x40
-+#define WDT_BITE_TIME 0x5C
-
- struct qcom_wdt {
- struct watchdog_device wdd;
-@@ -117,6 +117,8 @@ static int qcom_wdt_probe(struct platform_device *pdev)
- {
- struct qcom_wdt *wdt;
- struct resource *res;
-+ struct device_node *np = pdev->dev.of_node;
-+ u32 percpu_offset;
- int ret;
-
- wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
-@@ -124,6 +126,14 @@ static int qcom_wdt_probe(struct platform_device *pdev)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+
-+ /* We use CPU0's DGT for the watchdog */
-+ if (of_property_read_u32(np, "cpu-offset", &percpu_offset))
-+ percpu_offset = 0;
-+
-+ res->start += percpu_offset;
-+ res->end += percpu_offset;
-+
- wdt->base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(wdt->base))
- return PTR_ERR(wdt->base);
-@@ -203,9 +213,8 @@ static int qcom_wdt_remove(struct platform_device *pdev)
- }
-
- static const struct of_device_id qcom_wdt_of_table[] = {
-- { .compatible = "qcom,kpss-wdt-msm8960", },
-- { .compatible = "qcom,kpss-wdt-apq8064", },
-- { .compatible = "qcom,kpss-wdt-ipq8064", },
-+ { .compatible = "qcom,kpss-timer" },
-+ { .compatible = "qcom,scss-timer" },
- { },
- };
- MODULE_DEVICE_TABLE(of, qcom_wdt_of_table);
---
-1.9.1
-
+++ /dev/null
-From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Thu, 19 Feb 2015 20:27:39 -0800
-Subject: [PATCH 2/3] ARM: qcom: add description of KPSS WDT for IPQ8064
-
-Add the watchdog related entries to the Krait Processor Sub-system
-(KPSS) timer IPQ8064 devicetree section. Also, add a fixed-clock
-description of SLEEP_CLK, which will do for now.
-
-Signed-off-by: Josh Cartwright <joshc@codeaurora.org>
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 14 +++++++++++++-
- 1 file changed, 13 insertions(+), 1 deletion(-)
-
-diff --git a/arch/arm/boot/dts/qcom-ipq8064.dtsi b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-index cb225da..d01f618 100644
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -60,6 +60,14 @@
- };
- };
-
-+ clocks {
-+ sleep_clk: sleep_clk {
-+ compatible = "fixed-clock";
-+ clock-frequency = <32768>;
-+ #clock-cells = <0>;
-+ };
-+ };
-+
- soc: soc {
- #address-cells = <1>;
- #size-cells = <1>;
-@@ -89,10 +97,14 @@
- compatible = "qcom,kpss-timer", "qcom,msm-timer";
- interrupts = <1 1 0x301>,
- <1 2 0x301>,
-- <1 3 0x301>;
-+ <1 3 0x301>,
-+ <1 4 0x301>,
-+ <1 5 0x301>;
- reg = <0x0200a000 0x100>;
- clock-frequency = <25000000>,
- <32768>;
-+ clocks = <&sleep_clk>;
-+ clock-names = "sleep";
- cpu-offset = <0x80000>;
- };
-
---
-1.9.1
-
+++ /dev/null
-From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Thu, 19 Feb 2015 20:36:27 -0800
-Subject: [PATCH 3/3] ARM: msm: add watchdog entries to DT timer binding doc
-
-The watchdog has been reworked to use the same DT node as the timer.
-This change is updating the device tree doc accordingly.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- Documentation/devicetree/bindings/arm/msm/timer.txt | 16 +++++++++++++---
- 1 file changed, 13 insertions(+), 3 deletions(-)
-
---- a/Documentation/devicetree/bindings/arm/msm/timer.txt
-+++ b/Documentation/devicetree/bindings/arm/msm/timer.txt
-@@ -9,11 +9,17 @@ Properties:
- "qcom,scss-timer" - scorpion subsystem
-
- - interrupts : Interrupts for the the debug timer, the first general purpose
-- timer, and optionally a second general purpose timer in that
-- order.
-+ timer, and optionally a second general purpose timer, and
-+ optionally as well, 2 watchdog interrupts, in that order.
-
- - reg : Specifies the base address of the timer registers.
-
-+- clocks: Reference to the parent clocks, one per output clock. The parents
-+ must appear in the same order as the clock names.
-+
-+- clock-names: The name of the clocks as free-form strings. They should be in
-+ the same order as the clocks.
-+
- - clock-frequency : The frequency of the debug timer and the general purpose
- timer(s) in Hz in that order.
-
-@@ -29,9 +35,13 @@ Example:
- compatible = "qcom,scss-timer", "qcom,msm-timer";
- interrupts = <1 1 0x301>,
- <1 2 0x301>,
-- <1 3 0x301>;
-+ <1 3 0x301>,
-+ <1 4 0x301>,
-+ <1 5 0x301>;
- reg = <0x0200a000 0x100>;
- clock-frequency = <19200000>,
- <32768>;
-+ clocks = <&sleep_clk>;
-+ clock-names = "sleep";
- cpu-offset = <0x40000>;
- };
+++ /dev/null
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -18,8 +18,15 @@
- bootargs = "console=ttyMSM0,115200 root=/dev/mtdblock12 rootfstype=squashfs,jffs2";
- };
-
-+ aliases {
-+ mdio-gpio0 = &mdio0;
-+ };
-+
- soc {
- pinmux@800000 {
-+ pinctrl-0 = <&mdio0_pins &rgmii2_pins>;
-+ pinctrl-names = "default";
-+
- i2c4_pins: i2c4_pinmux {
- pins = "gpio12", "gpio13";
- function = "gsbi4";
-@@ -34,6 +41,25 @@
- bias-none;
- };
- };
-+
-+ mdio0_pins: mdio0_pins {
-+ mux {
-+ pins = "gpio0", "gpio1";
-+ function = "gpio";
-+ drive-strength = <8>;
-+ bias-disable;
-+ };
-+ };
-+
-+ rgmii2_pins: rgmii2_pins {
-+ mux {
-+ pins = "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
-+ "gpio51", "gpio52", "gpio59", "gpio60", "gpio61", "gpio62" ;
-+ function = "rgmii2";
-+ drive-strength = <8>;
-+ bias-disable;
-+ };
-+ };
- };
-
- gsbi@16300000 {
-@@ -72,6 +98,7 @@
- #size-cells = <1>;
- spi-max-frequency = <50000000>;
- reg = <0>;
-+ m25p,fast-read;
-
- partition@0 {
- label = "0:SBL1";
-@@ -148,5 +175,66 @@
- sata@29000000 {
- status = "ok";
- };
-+
-+ mdio0: mdio {
-+ compatible = "virtual,mdio-gpio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
-+
-+ phy0: ethernet-phy@0 {
-+ device_type = "ethernet-phy";
-+ reg = <0>;
-+ qca,ar8327-initvals = <
-+ 0x00004 0x7600000 /* PAD0_MODE */
-+ 0x00008 0x1000000 /* PAD5_MODE */
-+ 0x0000c 0x80 /* PAD6_MODE */
-+ 0x000e4 0xaa545 /* MAC_POWER_SEL */
-+ 0x000e0 0xc74164de /* SGMII_CTRL */
-+ 0x0007c 0x4e /* PORT0_STATUS */
-+ 0x00094 0x4e /* PORT6_STATUS */
-+ >;
-+ };
-+
-+ phy4: ethernet-phy@4 {
-+ device_type = "ethernet-phy";
-+ reg = <4>;
-+ };
-+ };
-+
-+ nss-gmac-common {
-+ reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
-+ reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
-+ };
-+
-+ gmac1: ethernet@37200000 {
-+ status = "ok";
-+ phy-mode = "rgmii";
-+ qcom,id = <1>;
-+ qcom,phy_mdio_addr = <4>;
-+ qcom,poll_required = <1>;
-+ qcom,rgmii_delay = <0>;
-+ qcom,emulation = <0>;
-+ qcom,forced_speed = <1000>;
-+ qcom,forced_duplex = <1>;
-+ qcom,socver = <0>;
-+ local-mac-address = [000000000000];
-+ mdiobus = <&mdio0>;
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <2>;
-+ qcom,phy_mdio_addr = <0>;
-+ qcom,poll_required = <0>;
-+ qcom,rgmii_delay = <0>;
-+ qcom,emulation = <0>;
-+ qcom,forced_speed = <1000>;
-+ qcom,forced_duplex = <1>;
-+ qcom,socver = <0>;
-+ local-mac-address = [000000000000];
-+ mdiobus = <&mdio0>;
-+ };
- };
- };
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -3,6 +3,7 @@
- #include "skeleton.dtsi"
- #include <dt-bindings/clock/qcom,gcc-ipq806x.h>
- #include <dt-bindings/soc/qcom,gsbi.h>
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
-
- / {
- model = "Qualcomm IPQ8064";
-@@ -279,5 +280,42 @@
- #clock-cells = <1>;
- #reset-cells = <1>;
- };
-+
-+ nss-gmac-common {
-+ reg = <0x03000000 0x0000FFFF 0x1bb00000 0x0000FFFF 0x00900000 0x00004000>;
-+ reg-names = "nss_reg_base" , "qsgmii_reg_base", "clk_ctl_base";
-+ };
-+
-+ gmac0: ethernet@37000000 {
-+ device_type = "network";
-+ compatible = "qcom,nss-gmac";
-+ reg = <0x37000000 0x200000>;
-+ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+ };
-+
-+ gmac1: ethernet@37200000 {
-+ device_type = "network";
-+ compatible = "qcom,nss-gmac";
-+ reg = <0x37200000 0x200000>;
-+ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ device_type = "network";
-+ compatible = "qcom,nss-gmac";
-+ reg = <0x37400000 0x200000>;
-+ interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+ };
-+
-+ gmac3: ethernet@37600000 {
-+ device_type = "network";
-+ compatible = "qcom,nss-gmac";
-+ reg = <0x37600000 0x200000>;
-+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
-+ status = "disabled";
-+ };
- };
- };