[OpenWrt-Devel] [PATCH] ipq806x: rename patches in patches-3.18

Mathieu Olivari mathieu at codeaurora.org
Thu Mar 5 23:25:55 EST 2015


This will allow ipq806x to support multiple kernel version more easily.

Signed-off-by: Mathieu Olivari <mathieu at codeaurora.org>
---
 .../001-spi-qup-Add-DMA-capabilities.patch         | 522 +++++++++++++++++++++
 ...-v3-spi-qup-Fix-incorrect-block-transfers.patch | 376 +++++++++++++++
 .../003-spi-qup-Ensure-done-detection.patch        |  56 +++
 ...atchdog-qcom-use-timer-devicetree-binding.patch |  72 +++
 ...m-add-description-of-KPSS-WDT-for-IPQ8064.patch |  53 +++
 ...-watchdog-entries-to-DT-timer-binding-doc.patch |  50 ++
 .../patches-3.18/700-add-gmac-dts-suport.patch     | 172 +++++++
 .../patches/001-spi-qup-Add-DMA-capabilities.patch | 522 ---------------------
 ...-v3-spi-qup-Fix-incorrect-block-transfers.patch | 376 ---------------
 .../003-spi-qup-Ensure-done-detection.patch        |  56 ---
 ...atchdog-qcom-use-timer-devicetree-binding.patch |  72 ---
 ...m-add-description-of-KPSS-WDT-for-IPQ8064.patch |  53 ---
 ...-watchdog-entries-to-DT-timer-binding-doc.patch |  50 --
 .../ipq806x/patches/700-add-gmac-dts-suport.patch  | 172 -------
 14 files changed, 1301 insertions(+), 1301 deletions(-)
 create mode 100644 target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
 create mode 100644 target/linux/ipq806x/patches-3.18/700-add-gmac-dts-suport.patch
 delete mode 100644 target/linux/ipq806x/patches/001-spi-qup-Add-DMA-capabilities.patch
 delete mode 100644 target/linux/ipq806x/patches/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
 delete mode 100644 target/linux/ipq806x/patches/003-spi-qup-Ensure-done-detection.patch
 delete mode 100644 target/linux/ipq806x/patches/011-watchdog-qcom-use-timer-devicetree-binding.patch
 delete mode 100644 target/linux/ipq806x/patches/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
 delete mode 100644 target/linux/ipq806x/patches/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
 delete mode 100644 target/linux/ipq806x/patches/700-add-gmac-dts-suport.patch

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
new file mode 100644
index 0000000..62badd5
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/001-spi-qup-Add-DMA-capabilities.patch
@@ -0,0 +1,522 @@
+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 at codeaurora.org>
+X-Patchwork-Id: 4432401
+Message-Id: <1403816781-31008-1-git-send-email-agross at codeaurora.org>
+To: Mark Brown <broonie at kernel.org>
+Cc: linux-spi at vger.kernel.org, Sagar Dharia <sdharia at codeaurora.org>,
+	Daniel Sneddon <dsneddon at codeaurora.org>,
+	Bjorn Andersson <bjorn.andersson at sonymobile.com>,
+	"Ivan T. Ivanov" <iivanov at mm-sol.com>,
+	linux-kernel at vger.kernel.org, linux-arm-kernel at lists.infradead.org,
+	linux-arm-msm at vger.kernel.org, Andy Gross <agross at 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 at 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);
+ 
diff --git a/target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch b/target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
new file mode 100644
index 0000000..62ee5b4
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
@@ -0,0 +1,376 @@
+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 at codeaurora.org>
+X-Patchwork-Id: 5007321
+Message-Id: <1412112088-25928-1-git-send-email-agross at codeaurora.org>
+To: Mark Brown <broonie at kernel.org>
+Cc: linux-spi at vger.kernel.org, linux-kernel at vger.kernel.org,
+	linux-arm-kernel at lists.infradead.org, linux-arm-msm at vger.kernel.org,
+	"Ivan T. Ivanov" <iivanov at mm-sol.com>,
+	Bjorn Andersson <bjorn.andersson at sonymobile.com>,
+	Kumar Gala <galak at codeaurora.org>, Andy Gross <agross at 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 at 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;
+ }
+ 
diff --git a/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch b/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch
new file mode 100644
index 0000000..7052227
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/003-spi-qup-Ensure-done-detection.patch
@@ -0,0 +1,56 @@
+From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001
+From: Andy Gross <agross at 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 at 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);
+ 		}
diff --git a/target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch b/target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch
new file mode 100644
index 0000000..0cd7da1
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/011-watchdog-qcom-use-timer-devicetree-binding.patch
@@ -0,0 +1,72 @@
+From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu at 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 at 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
+
diff --git a/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch b/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
new file mode 100644
index 0000000..24a093a
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
@@ -0,0 +1,53 @@
+From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu at 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 at codeaurora.org>
+Signed-off-by: Mathieu Olivari <mathieu at 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
+
diff --git a/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch b/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
new file mode 100644
index 0000000..6876768
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
@@ -0,0 +1,50 @@
+From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001
+From: Mathieu Olivari <mathieu at 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 at 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>;
+        };
diff --git a/target/linux/ipq806x/patches-3.18/700-add-gmac-dts-suport.patch b/target/linux/ipq806x/patches-3.18/700-add-gmac-dts-suport.patch
new file mode 100644
index 0000000..89ebe66
--- /dev/null
+++ b/target/linux/ipq806x/patches-3.18/700-add-gmac-dts-suport.patch
@@ -0,0 +1,172 @@
+--- 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 at 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 at 16300000 {
+@@ -72,6 +98,7 @@
+ 					#size-cells = <1>;
+ 					spi-max-frequency = <50000000>;
+ 					reg = <0>;
++					m25p,fast-read;
+ 
+ 					partition at 0 {
+ 						label = "0:SBL1";
+@@ -148,5 +175,66 @@
+ 		sata at 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 at 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 at 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 at 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 at 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 at 37000000 {
++			device_type = "network";
++			compatible = "qcom,nss-gmac";
++			reg = <0x37000000 0x200000>;
++			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++		};
++
++		gmac1: ethernet at 37200000 {
++			device_type = "network";
++			compatible = "qcom,nss-gmac";
++			reg = <0x37200000 0x200000>;
++			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++		};
++
++		gmac2: ethernet at 37400000 {
++			device_type = "network";
++			compatible = "qcom,nss-gmac";
++			reg = <0x37400000 0x200000>;
++			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++		};
++
++		gmac3: ethernet at 37600000 {
++			device_type = "network";
++			compatible = "qcom,nss-gmac";
++			reg = <0x37600000 0x200000>;
++			interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
++			status = "disabled";
++		};
+ 	};
+ };
diff --git a/target/linux/ipq806x/patches/001-spi-qup-Add-DMA-capabilities.patch b/target/linux/ipq806x/patches/001-spi-qup-Add-DMA-capabilities.patch
deleted file mode 100644
index 62badd5..0000000
--- a/target/linux/ipq806x/patches/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 at codeaurora.org>
-X-Patchwork-Id: 4432401
-Message-Id: <1403816781-31008-1-git-send-email-agross at codeaurora.org>
-To: Mark Brown <broonie at kernel.org>
-Cc: linux-spi at vger.kernel.org, Sagar Dharia <sdharia at codeaurora.org>,
-	Daniel Sneddon <dsneddon at codeaurora.org>,
-	Bjorn Andersson <bjorn.andersson at sonymobile.com>,
-	"Ivan T. Ivanov" <iivanov at mm-sol.com>,
-	linux-kernel at vger.kernel.org, linux-arm-kernel at lists.infradead.org,
-	linux-arm-msm at vger.kernel.org, Andy Gross <agross at 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 at 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);
- 
diff --git a/target/linux/ipq806x/patches/002-v3-spi-qup-Fix-incorrect-block-transfers.patch b/target/linux/ipq806x/patches/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
deleted file mode 100644
index 62ee5b4..0000000
--- a/target/linux/ipq806x/patches/002-v3-spi-qup-Fix-incorrect-block-transfers.patch
+++ /dev/null
@@ -1,376 +0,0 @@
-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 at codeaurora.org>
-X-Patchwork-Id: 5007321
-Message-Id: <1412112088-25928-1-git-send-email-agross at codeaurora.org>
-To: Mark Brown <broonie at kernel.org>
-Cc: linux-spi at vger.kernel.org, linux-kernel at vger.kernel.org,
-	linux-arm-kernel at lists.infradead.org, linux-arm-msm at vger.kernel.org,
-	"Ivan T. Ivanov" <iivanov at mm-sol.com>,
-	Bjorn Andersson <bjorn.andersson at sonymobile.com>,
-	Kumar Gala <galak at codeaurora.org>, Andy Gross <agross at 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 at 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;
- }
- 
diff --git a/target/linux/ipq806x/patches/003-spi-qup-Ensure-done-detection.patch b/target/linux/ipq806x/patches/003-spi-qup-Ensure-done-detection.patch
deleted file mode 100644
index 7052227..0000000
--- a/target/linux/ipq806x/patches/003-spi-qup-Ensure-done-detection.patch
+++ /dev/null
@@ -1,56 +0,0 @@
-From 4faba89e3ffbb1c5f6232651375b9b3212b50f02 Mon Sep 17 00:00:00 2001
-From: Andy Gross <agross at 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 at 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);
- 		}
diff --git a/target/linux/ipq806x/patches/011-watchdog-qcom-use-timer-devicetree-binding.patch b/target/linux/ipq806x/patches/011-watchdog-qcom-use-timer-devicetree-binding.patch
deleted file mode 100644
index 0cd7da1..0000000
--- a/target/linux/ipq806x/patches/011-watchdog-qcom-use-timer-devicetree-binding.patch
+++ /dev/null
@@ -1,72 +0,0 @@
-From fded70251b1b58f68de1d3757ece9965f0b75452 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu at 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 at 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
-
diff --git a/target/linux/ipq806x/patches/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch b/target/linux/ipq806x/patches/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
deleted file mode 100644
index 24a093a..0000000
--- a/target/linux/ipq806x/patches/012-ARM-qcom-add-description-of-KPSS-WDT-for-IPQ8064.patch
+++ /dev/null
@@ -1,53 +0,0 @@
-From 297cf8136ecd6a56520888fd28948393766b8ee7 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu at 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 at codeaurora.org>
-Signed-off-by: Mathieu Olivari <mathieu at 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
-
diff --git a/target/linux/ipq806x/patches/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch b/target/linux/ipq806x/patches/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
deleted file mode 100644
index 6876768..0000000
--- a/target/linux/ipq806x/patches/013-ARM-msm-add-watchdog-entries-to-DT-timer-binding-doc.patch
+++ /dev/null
@@ -1,50 +0,0 @@
-From e535f01dffb6dd9e09934fa219be52af3437a8f6 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu at 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 at 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>;
-        };
diff --git a/target/linux/ipq806x/patches/700-add-gmac-dts-suport.patch b/target/linux/ipq806x/patches/700-add-gmac-dts-suport.patch
deleted file mode 100644
index 89ebe66..0000000
--- a/target/linux/ipq806x/patches/700-add-gmac-dts-suport.patch
+++ /dev/null
@@ -1,172 +0,0 @@
---- 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 at 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 at 16300000 {
-@@ -72,6 +98,7 @@
- 					#size-cells = <1>;
- 					spi-max-frequency = <50000000>;
- 					reg = <0>;
-+					m25p,fast-read;
- 
- 					partition at 0 {
- 						label = "0:SBL1";
-@@ -148,5 +175,66 @@
- 		sata at 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 at 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 at 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 at 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 at 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 at 37000000 {
-+			device_type = "network";
-+			compatible = "qcom,nss-gmac";
-+			reg = <0x37000000 0x200000>;
-+			interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-+			status = "disabled";
-+		};
-+
-+		gmac1: ethernet at 37200000 {
-+			device_type = "network";
-+			compatible = "qcom,nss-gmac";
-+			reg = <0x37200000 0x200000>;
-+			interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
-+			status = "disabled";
-+		};
-+
-+		gmac2: ethernet at 37400000 {
-+			device_type = "network";
-+			compatible = "qcom,nss-gmac";
-+			reg = <0x37400000 0x200000>;
-+			interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-+			status = "disabled";
-+		};
-+
-+		gmac3: ethernet at 37600000 {
-+			device_type = "network";
-+			compatible = "qcom,nss-gmac";
-+			reg = <0x37600000 0x200000>;
-+			interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
-+			status = "disabled";
-+		};
- 	};
- };
-- 
1.9.1

_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel



More information about the openwrt-devel mailing list