aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/ipq806x/patches-4.1
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/ipq806x/patches-4.1')
-rw-r--r--target/linux/ipq806x/patches-4.1/020-add-ap148-bootargs.patch46
-rw-r--r--target/linux/ipq806x/patches-4.1/021-add-ap148-partitions.patch19
-rw-r--r--target/linux/ipq806x/patches-4.1/022-add-db149-dts.patch160
-rw-r--r--target/linux/ipq806x/patches-4.1/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch53
-rw-r--r--target/linux/ipq806x/patches-4.1/024-ap148-add-memory-node.patch14
-rw-r--r--target/linux/ipq806x/patches-4.1/030-hwspinlock-core-add-device-tree-support.patch167
-rw-r--r--target/linux/ipq806x/patches-4.1/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch234
-rw-r--r--target/linux/ipq806x/patches-4.1/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch26
-rw-r--r--target/linux/ipq806x/patches-4.1/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch33
-rw-r--r--target/linux/ipq806x/patches-4.1/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch82
-rw-r--r--target/linux/ipq806x/patches-4.1/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch841
-rw-r--r--target/linux/ipq806x/patches-4.1/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch36
-rw-r--r--target/linux/ipq806x/patches-4.1/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch277
-rw-r--r--target/linux/ipq806x/patches-4.1/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch263
-rw-r--r--target/linux/ipq806x/patches-4.1/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch753
-rw-r--r--target/linux/ipq806x/patches-4.1/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch244
-rw-r--r--target/linux/ipq806x/patches-4.1/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch29
-rw-r--r--target/linux/ipq806x/patches-4.1/114-pcie-add-ctlr-init.patch311
-rw-r--r--target/linux/ipq806x/patches-4.1/115-add-pcie-aux-clk-dts.patch80
-rw-r--r--target/linux/ipq806x/patches-4.1/126-add-rpm-to-ipq8064-dts.patch87
-rw-r--r--target/linux/ipq806x/patches-4.1/133-ARM-Add-Krait-L2-register-accessor-functions.patch144
-rw-r--r--target/linux/ipq806x/patches-4.1/134-clk-mux-Split-out-register-accessors-for-reuse.patch192
-rw-r--r--target/linux/ipq806x/patches-4.1/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch130
-rw-r--r--target/linux/ipq806x/patches-4.1/136-clk-Add-safe-switch-hook.patch164
-rw-r--r--target/linux/ipq806x/patches-4.1/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch351
-rw-r--r--target/linux/ipq806x/patches-4.1/138-clk-qcom-Add-HFPLL-driver.patch206
-rw-r--r--target/linux/ipq806x/patches-4.1/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch127
-rw-r--r--target/linux/ipq806x/patches-4.1/140-clk-qcom-Add-support-for-Krait-clocks.patch271
-rw-r--r--target/linux/ipq806x/patches-4.1/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch205
-rw-r--r--target/linux/ipq806x/patches-4.1/142-clk-qcom-Add-Krait-clock-controller-driver.patch435
-rw-r--r--target/linux/ipq806x/patches-4.1/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch304
-rw-r--r--target/linux/ipq806x/patches-4.1/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch100
-rw-r--r--target/linux/ipq806x/patches-4.1/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch461
-rw-r--r--target/linux/ipq806x/patches-4.1/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch76
-rw-r--r--target/linux/ipq806x/patches-4.1/156-dmaengine-Add-ADM-driver.patch962
-rw-r--r--target/linux/ipq806x/patches-4.1/157-ARM-DT-ipq8064-Add-ADM-device-node.patch42
-rw-r--r--target/linux/ipq806x/patches-4.1/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch84
-rw-r--r--target/linux/ipq806x/patches-4.1/162-mtd-nand-Qualcomm-NAND-controller-driver.patch2024
-rw-r--r--target/linux/ipq806x/patches-4.1/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch82
-rw-r--r--target/linux/ipq806x/patches-4.1/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch51
-rw-r--r--target/linux/ipq806x/patches-4.1/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch76
-rw-r--r--target/linux/ipq806x/patches-4.1/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch11
-rw-r--r--target/linux/ipq806x/patches-4.1/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch62
-rw-r--r--target/linux/ipq806x/patches-4.1/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch367
-rw-r--r--target/linux/ipq806x/patches-4.1/302-mtd-qcom-smem-rename-rootfs-ubi.patch13
-rw-r--r--target/linux/ipq806x/patches-4.1/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch734
-rw-r--r--target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch2355
-rw-r--r--target/linux/ipq806x/patches-4.1/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch146
-rw-r--r--target/linux/ipq806x/patches-4.1/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch216
-rw-r--r--target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch31
-rw-r--r--target/linux/ipq806x/patches-4.1/710-stmmac-fix-ipq806x-DMA-configuration.patch117
51 files changed, 0 insertions, 14294 deletions
diff --git a/target/linux/ipq806x/patches-4.1/020-add-ap148-bootargs.patch b/target/linux/ipq806x/patches-4.1/020-add-ap148-bootargs.patch
deleted file mode 100644
index c0ad74c492..0000000000
--- a/target/linux/ipq806x/patches-4.1/020-add-ap148-bootargs.patch
+++ /dev/null
@@ -1,46 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -14,6 +14,14 @@
- };
- };
-
-+ alias {
-+ serial0 = &uart4;
-+ };
-+
-+ chosen {
-+ linux,stdout-path = "serial0:115200n8";
-+ };
-+
- soc {
- pinmux@800000 {
- i2c4_pins: i2c4_pinmux {
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -159,7 +159,7 @@
-
- syscon-tcsr = <&tcsr>;
-
-- serial@12490000 {
-+ uart2: serial@12490000 {
- compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
- reg = <0x12490000 0x1000>,
- <0x12480000 0x1000>;
-@@ -197,7 +197,7 @@
-
- syscon-tcsr = <&tcsr>;
-
-- serial@16340000 {
-+ uart4: serial@16340000 {
- compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
- reg = <0x16340000 0x1000>,
- <0x16300000 0x1000>;
-@@ -234,7 +234,7 @@
-
- syscon-tcsr = <&tcsr>;
-
-- serial@1a240000 {
-+ uart5: serial@1a240000 {
- compatible = "qcom,msm-uartdm-v1.3", "qcom,msm-uartdm";
- reg = <0x1a240000 0x1000>,
- <0x1a200000 0x1000>;
diff --git a/target/linux/ipq806x/patches-4.1/021-add-ap148-partitions.patch b/target/linux/ipq806x/patches-4.1/021-add-ap148-partitions.patch
deleted file mode 100644
index bfdb30fe14..0000000000
--- a/target/linux/ipq806x/patches-4.1/021-add-ap148-partitions.patch
+++ /dev/null
@@ -1,19 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -77,15 +77,7 @@
- spi-max-frequency = <50000000>;
- reg = <0>;
-
-- partition@0 {
-- label = "rootfs";
-- reg = <0x0 0x1000000>;
-- };
--
-- partition@1 {
-- label = "scratch";
-- reg = <0x1000000 0x1000000>;
-- };
-+ linux,part-probe = "qcom-smem";
- };
- };
- };
diff --git a/target/linux/ipq806x/patches-4.1/022-add-db149-dts.patch b/target/linux/ipq806x/patches-4.1/022-add-db149-dts.patch
deleted file mode 100644
index 7d8c8e8a81..0000000000
--- a/target/linux/ipq806x/patches-4.1/022-add-db149-dts.patch
+++ /dev/null
@@ -1,160 +0,0 @@
-From f26cc3733bdd697bd81ae505fc133fa7c9b6ea19 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Tue, 7 Apr 2015 19:58:58 -0700
-Subject: [PATCH] ARM: dts: qcom: add initial DB149 device-tree
-
-Add basic DB149 (IPQ806x based platform) device-tree. It supports UART,
-SATA, USB2, USB3 and NOR flash.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/qcom-ipq8064-db149.dts | 132 +++++++++++++++++++++++++++++++
- 2 files changed, 133 insertions(+)
- create mode 100644 arch/arm/boot/dts/qcom-ipq8064-db149.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -451,6 +451,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
- qcom-apq8084-ifc6540.dtb \
- qcom-apq8084-mtp.dtb \
- qcom-ipq8064-ap148.dtb \
-+ qcom-ipq8064-db149.dtb \
- qcom-msm8660-surf.dtb \
- qcom-msm8960-cdp.dtb \
- qcom-msm8974-sony-xperia-honami.dtb
---- /dev/null
-+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-@@ -0,0 +1,132 @@
-+#include "qcom-ipq8064-v1.0.dtsi"
-+
-+/ {
-+ model = "Qualcomm IPQ8064/DB149";
-+ compatible = "qcom,ipq8064-db149", "qcom,ipq8064";
-+
-+ reserved-memory {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges;
-+ rsvd@41200000 {
-+ reg = <0x41200000 0x300000>;
-+ no-map;
-+ };
-+ };
-+
-+ alias {
-+ serial0 = &uart2;
-+ };
-+
-+ chosen {
-+ linux,stdout-path = "serial0:115200n8";
-+ };
-+
-+ soc {
-+ pinmux@800000 {
-+ i2c4_pins: i2c4_pinmux {
-+ pins = "gpio12", "gpio13";
-+ function = "gsbi4";
-+ bias-disable;
-+ };
-+
-+ spi_pins: spi_pins {
-+ mux {
-+ pins = "gpio18", "gpio19", "gpio21";
-+ function = "gsbi5";
-+ drive-strength = <10>;
-+ bias-none;
-+ };
-+ };
-+ };
-+
-+ gsbi2: gsbi@12480000 {
-+ qcom,mode = <GSBI_PROT_I2C_UART>;
-+ status = "ok";
-+ uart2: serial@12490000 {
-+ status = "ok";
-+ };
-+ };
-+
-+ gsbi5: gsbi@1a200000 {
-+ qcom,mode = <GSBI_PROT_SPI>;
-+ status = "ok";
-+
-+ spi4: spi@1a280000 {
-+ status = "ok";
-+ spi-max-frequency = <50000000>;
-+
-+ pinctrl-0 = <&spi_pins>;
-+ pinctrl-names = "default";
-+
-+ cs-gpios = <&qcom_pinmux 20 0>;
-+
-+ flash: m25p80@0 {
-+ compatible = "s25fl256s1";
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ spi-max-frequency = <50000000>;
-+ reg = <0>;
-+ m25p,fast-read;
-+
-+ partition@0 {
-+ label = "lowlevel_init";
-+ reg = <0x0 0x1b0000>;
-+ };
-+
-+ partition@1 {
-+ label = "u-boot";
-+ reg = <0x1b0000 0x80000>;
-+ };
-+
-+ partition@2 {
-+ label = "u-boot-env";
-+ reg = <0x230000 0x40000>;
-+ };
-+
-+ partition@3 {
-+ label = "caldata";
-+ reg = <0x270000 0x40000>;
-+ };
-+
-+ partition@4 {
-+ label = "firmware";
-+ reg = <0x2b0000 0x1d50000>;
-+ };
-+ };
-+ };
-+ };
-+
-+ sata-phy@1b400000 {
-+ status = "ok";
-+ };
-+
-+ sata@29000000 {
-+ status = "ok";
-+ };
-+
-+ phy@100f8800 { /* USB3 port 1 HS phy */
-+ status = "ok";
-+ };
-+
-+ phy@100f8830 { /* USB3 port 1 SS phy */
-+ status = "ok";
-+ };
-+
-+ phy@110f8800 { /* USB3 port 0 HS phy */
-+ status = "ok";
-+ };
-+
-+ phy@110f8830 { /* USB3 port 0 SS phy */
-+ status = "ok";
-+ };
-+
-+ usb30@0 {
-+ status = "ok";
-+ };
-+
-+ usb30@1 {
-+ status = "ok";
-+ };
-+ };
-+};
diff --git a/target/linux/ipq806x/patches-4.1/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch b/target/linux/ipq806x/patches-4.1/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch
deleted file mode 100644
index 6b296377b6..0000000000
--- a/target/linux/ipq806x/patches-4.1/023-ARM-dts-ipq806x-Disable-i2c-device-on-gsbi4.patch
+++ /dev/null
@@ -1,53 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -46,15 +46,12 @@
- serial@16340000 {
- status = "ok";
- };
--
-- i2c4: i2c@16380000 {
-- status = "ok";
--
-- clock-frequency = <200000>;
--
-- pinctrl-0 = <&i2c4_pins>;
-- pinctrl-names = "default";
-- };
-+ /*
-+ * The i2c device on gsbi4 should not be enabled.
-+ * On ipq806x designs gsbi4 i2c is meant for exclusive
-+ * RPM usage. Turning this on in kernel manifests as
-+ * i2c failure for the RPM.
-+ */
- };
-
- gsbi5: gsbi@1a200000 {
---- a/drivers/clk/qcom/gcc-ipq806x.c
-+++ b/drivers/clk/qcom/gcc-ipq806x.c
-@@ -807,7 +807,7 @@ static struct clk_rcg gsbi7_qup_src = {
- .parent_names = gcc_pxo_pll8,
- .num_parents = 2,
- .ops = &clk_rcg_ops,
-- .flags = CLK_SET_PARENT_GATE,
-+ .flags = CLK_SET_PARENT_GATE | CLK_IGNORE_UNUSED,
- },
- },
- };
-@@ -823,7 +823,7 @@ static struct clk_branch gsbi7_qup_clk =
- .parent_names = (const char *[]){ "gsbi7_qup_src" },
- .num_parents = 1,
- .ops = &clk_branch_ops,
-- .flags = CLK_SET_RATE_PARENT,
-+ .flags = CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
- },
- },
- };
-@@ -871,7 +871,7 @@ static struct clk_branch gsbi4_h_clk = {
- .hw.init = &(struct clk_init_data){
- .name = "gsbi4_h_clk",
- .ops = &clk_branch_ops,
-- .flags = CLK_IS_ROOT,
-+ .flags = CLK_IS_ROOT | CLK_IGNORE_UNUSED,
- },
- },
- };
diff --git a/target/linux/ipq806x/patches-4.1/024-ap148-add-memory-node.patch b/target/linux/ipq806x/patches-4.1/024-ap148-add-memory-node.patch
deleted file mode 100644
index f026ed9394..0000000000
--- a/target/linux/ipq806x/patches-4.1/024-ap148-add-memory-node.patch
+++ /dev/null
@@ -1,14 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -4,6 +4,11 @@
- model = "Qualcomm IPQ8064/AP148";
- compatible = "qcom,ipq8064-ap148", "qcom,ipq8064";
-
-+ memory@0 {
-+ reg = <0x42000000 0x1e000000>;
-+ device_type = "memory";
-+ };
-+
- reserved-memory {
- #address-cells = <1>;
- #size-cells = <1>;
diff --git a/target/linux/ipq806x/patches-4.1/030-hwspinlock-core-add-device-tree-support.patch b/target/linux/ipq806x/patches-4.1/030-hwspinlock-core-add-device-tree-support.patch
deleted file mode 100644
index 04f35b7ec7..0000000000
--- a/target/linux/ipq806x/patches-4.1/030-hwspinlock-core-add-device-tree-support.patch
+++ /dev/null
@@ -1,167 +0,0 @@
-From fb7737e949e31d8a71acee6bbb670f32dbd2a2c0 Mon Sep 17 00:00:00 2001
-From: Suman Anna <s-anna@ti.com>
-Date: Wed, 4 Mar 2015 20:01:14 -0600
-Subject: [PATCH] hwspinlock/core: add device tree support
-
-This patch adds a new OF-friendly API of_hwspin_lock_get_id()
-for hwspinlock clients to use/request locks from a hwspinlock
-device instantiated through a device-tree blob. This new API
-can be used by hwspinlock clients to get the id for a specific
-lock using the phandle + args specifier, so that it can be
-requested using the available hwspin_lock_request_specific()
-API.
-
-Signed-off-by: Suman Anna <s-anna@ti.com>
-Reviewed-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-[small comment clarification]
-Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
----
- Documentation/hwspinlock.txt | 10 +++++
- drivers/hwspinlock/hwspinlock_core.c | 79 ++++++++++++++++++++++++++++++++++++
- include/linux/hwspinlock.h | 7 ++++
- 3 files changed, 96 insertions(+)
-
---- a/Documentation/hwspinlock.txt
-+++ b/Documentation/hwspinlock.txt
-@@ -48,6 +48,16 @@ independent, drivers.
- ids for predefined purposes.
- Should be called from a process context (might sleep).
-
-+ int of_hwspin_lock_get_id(struct device_node *np, int index);
-+ - retrieve the global lock id for an OF phandle-based specific lock.
-+ This function provides a means for DT users of a hwspinlock module
-+ to get the global lock id of a specific hwspinlock, so that it can
-+ be requested using the normal hwspin_lock_request_specific() API.
-+ The function returns a lock id number on success, -EPROBE_DEFER if
-+ the hwspinlock device is not yet registered with the core, or other
-+ error values.
-+ Should be called from a process context (might sleep).
-+
- int hwspin_lock_free(struct hwspinlock *hwlock);
- - free a previously-assigned hwspinlock; returns 0 on success, or an
- appropriate error code on failure (e.g. -EINVAL if the hwspinlock
---- a/drivers/hwspinlock/hwspinlock_core.c
-+++ b/drivers/hwspinlock/hwspinlock_core.c
-@@ -27,6 +27,7 @@
- #include <linux/hwspinlock.h>
- #include <linux/pm_runtime.h>
- #include <linux/mutex.h>
-+#include <linux/of.h>
-
- #include "hwspinlock_internal.h"
-
-@@ -257,6 +258,84 @@ void __hwspin_unlock(struct hwspinlock *
- }
- EXPORT_SYMBOL_GPL(__hwspin_unlock);
-
-+/**
-+ * of_hwspin_lock_simple_xlate - translate hwlock_spec to return a lock id
-+ * @bank: the hwspinlock device bank
-+ * @hwlock_spec: hwlock specifier as found in the device tree
-+ *
-+ * This is a simple translation function, suitable for hwspinlock platform
-+ * drivers that only has a lock specifier length of 1.
-+ *
-+ * Returns a relative index of the lock within a specified bank on success,
-+ * or -EINVAL on invalid specifier cell count.
-+ */
-+static inline int
-+of_hwspin_lock_simple_xlate(const struct of_phandle_args *hwlock_spec)
-+{
-+ if (WARN_ON(hwlock_spec->args_count != 1))
-+ return -EINVAL;
-+
-+ return hwlock_spec->args[0];
-+}
-+
-+/**
-+ * of_hwspin_lock_get_id() - get lock id for an OF phandle-based specific lock
-+ * @np: device node from which to request the specific hwlock
-+ * @index: index of the hwlock in the list of values
-+ *
-+ * This function provides a means for DT users of the hwspinlock module to
-+ * get the global lock id of a specific hwspinlock using the phandle of the
-+ * hwspinlock device, so that it can be requested using the normal
-+ * hwspin_lock_request_specific() API.
-+ *
-+ * Returns the global lock id number on success, -EPROBE_DEFER if the hwspinlock
-+ * device is not yet registered, -EINVAL on invalid args specifier value or an
-+ * appropriate error as returned from the OF parsing of the DT client node.
-+ */
-+int of_hwspin_lock_get_id(struct device_node *np, int index)
-+{
-+ struct of_phandle_args args;
-+ struct hwspinlock *hwlock;
-+ struct radix_tree_iter iter;
-+ void **slot;
-+ int id;
-+ int ret;
-+
-+ ret = of_parse_phandle_with_args(np, "hwlocks", "#hwlock-cells", index,
-+ &args);
-+ if (ret)
-+ return ret;
-+
-+ /* Find the hwspinlock device: we need its base_id */
-+ ret = -EPROBE_DEFER;
-+ rcu_read_lock();
-+ radix_tree_for_each_slot(slot, &hwspinlock_tree, &iter, 0) {
-+ hwlock = radix_tree_deref_slot(slot);
-+ if (unlikely(!hwlock))
-+ continue;
-+
-+ if (hwlock->bank->dev->of_node == args.np) {
-+ ret = 0;
-+ break;
-+ }
-+ }
-+ rcu_read_unlock();
-+ if (ret < 0)
-+ goto out;
-+
-+ id = of_hwspin_lock_simple_xlate(&args);
-+ if (id < 0 || id >= hwlock->bank->num_locks) {
-+ ret = -EINVAL;
-+ goto out;
-+ }
-+ id += hwlock->bank->base_id;
-+
-+out:
-+ of_node_put(args.np);
-+ return ret ? ret : id;
-+}
-+EXPORT_SYMBOL_GPL(of_hwspin_lock_get_id);
-+
- static int hwspin_lock_register_single(struct hwspinlock *hwlock, int id)
- {
- struct hwspinlock *tmp;
---- a/include/linux/hwspinlock.h
-+++ b/include/linux/hwspinlock.h
-@@ -26,6 +26,7 @@
- #define HWLOCK_IRQ 0x02 /* Disable interrupts, don't save state */
-
- struct device;
-+struct device_node;
- struct hwspinlock;
- struct hwspinlock_device;
- struct hwspinlock_ops;
-@@ -66,6 +67,7 @@ int hwspin_lock_unregister(struct hwspin
- struct hwspinlock *hwspin_lock_request(void);
- struct hwspinlock *hwspin_lock_request_specific(unsigned int id);
- int hwspin_lock_free(struct hwspinlock *hwlock);
-+int of_hwspin_lock_get_id(struct device_node *np, int index);
- int hwspin_lock_get_id(struct hwspinlock *hwlock);
- int __hwspin_lock_timeout(struct hwspinlock *, unsigned int, int,
- unsigned long *);
-@@ -120,6 +122,11 @@ void __hwspin_unlock(struct hwspinlock *
- {
- }
-
-+static inline int of_hwspin_lock_get_id(struct device_node *np, int index)
-+{
-+ return 0;
-+}
-+
- static inline int hwspin_lock_get_id(struct hwspinlock *hwlock)
- {
- return 0;
diff --git a/target/linux/ipq806x/patches-4.1/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch b/target/linux/ipq806x/patches-4.1/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch
deleted file mode 100644
index 581b199d7f..0000000000
--- a/target/linux/ipq806x/patches-4.1/031-hwspinlock-qcom-Add-support-for-Qualcomm-HW-Mutex-bl.patch
+++ /dev/null
@@ -1,234 +0,0 @@
-From 19a0f61224d2d91860fa8291ab63cb104ee86bdd Mon Sep 17 00:00:00 2001
-From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-Date: Tue, 24 Mar 2015 10:11:05 -0700
-Subject: [PATCH] hwspinlock: qcom: Add support for Qualcomm HW Mutex block
-
-Add driver for Qualcomm Hardware Mutex block found in many Qualcomm
-SoCs.
-
-Based on initial effort by Kumar Gala <galak@codeaurora.org>
-
-Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-Reviewed-by: Andy Gross <agross@codeaurora.org>
-Reviewed-by: Jeffrey Hugo <jhugo@codeaurora.org>
-Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
----
- drivers/hwspinlock/Kconfig | 12 +++
- drivers/hwspinlock/Makefile | 1 +
- drivers/hwspinlock/qcom_hwspinlock.c | 181 +++++++++++++++++++++++++++++++++++
- 3 files changed, 194 insertions(+)
- create mode 100644 drivers/hwspinlock/qcom_hwspinlock.c
-
---- a/drivers/hwspinlock/Kconfig
-+++ b/drivers/hwspinlock/Kconfig
-@@ -18,6 +18,18 @@ config HWSPINLOCK_OMAP
-
- If unsure, say N.
-
-+config HWSPINLOCK_QCOM
-+ tristate "Qualcomm Hardware Spinlock device"
-+ depends on ARCH_QCOM
-+ select HWSPINLOCK
-+ select MFD_SYSCON
-+ help
-+ Say y here to support the Qualcomm Hardware Mutex functionality, which
-+ provides a synchronisation mechanism for the various processors on
-+ the SoC.
-+
-+ If unsure, say N.
-+
- config HSEM_U8500
- tristate "STE Hardware Semaphore functionality"
- depends on ARCH_U8500
---- a/drivers/hwspinlock/Makefile
-+++ b/drivers/hwspinlock/Makefile
-@@ -4,4 +4,5 @@
-
- obj-$(CONFIG_HWSPINLOCK) += hwspinlock_core.o
- obj-$(CONFIG_HWSPINLOCK_OMAP) += omap_hwspinlock.o
-+obj-$(CONFIG_HWSPINLOCK_QCOM) += qcom_hwspinlock.o
- obj-$(CONFIG_HSEM_U8500) += u8500_hsem.o
---- /dev/null
-+++ b/drivers/hwspinlock/qcom_hwspinlock.c
-@@ -0,0 +1,181 @@
-+/*
-+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
-+ * Copyright (c) 2015, Sony Mobile Communications AB
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/hwspinlock.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_runtime.h>
-+#include <linux/regmap.h>
-+
-+#include "hwspinlock_internal.h"
-+
-+#define QCOM_MUTEX_APPS_PROC_ID 1
-+#define QCOM_MUTEX_NUM_LOCKS 32
-+
-+static int qcom_hwspinlock_trylock(struct hwspinlock *lock)
-+{
-+ struct regmap_field *field = lock->priv;
-+ u32 lock_owner;
-+ int ret;
-+
-+ ret = regmap_field_write(field, QCOM_MUTEX_APPS_PROC_ID);
-+ if (ret)
-+ return ret;
-+
-+ ret = regmap_field_read(field, &lock_owner);
-+ if (ret)
-+ return ret;
-+
-+ return lock_owner == QCOM_MUTEX_APPS_PROC_ID;
-+}
-+
-+static void qcom_hwspinlock_unlock(struct hwspinlock *lock)
-+{
-+ struct regmap_field *field = lock->priv;
-+ u32 lock_owner;
-+ int ret;
-+
-+ ret = regmap_field_read(field, &lock_owner);
-+ if (ret) {
-+ pr_err("%s: unable to query spinlock owner\n", __func__);
-+ return;
-+ }
-+
-+ if (lock_owner != QCOM_MUTEX_APPS_PROC_ID) {
-+ pr_err("%s: spinlock not owned by us (actual owner is %d)\n",
-+ __func__, lock_owner);
-+ }
-+
-+ ret = regmap_field_write(field, 0);
-+ if (ret)
-+ pr_err("%s: failed to unlock spinlock\n", __func__);
-+}
-+
-+static const struct hwspinlock_ops qcom_hwspinlock_ops = {
-+ .trylock = qcom_hwspinlock_trylock,
-+ .unlock = qcom_hwspinlock_unlock,
-+};
-+
-+static const struct of_device_id qcom_hwspinlock_of_match[] = {
-+ { .compatible = "qcom,sfpb-mutex" },
-+ { .compatible = "qcom,tcsr-mutex" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, qcom_hwspinlock_of_match);
-+
-+static int qcom_hwspinlock_probe(struct platform_device *pdev)
-+{
-+ struct hwspinlock_device *bank;
-+ struct device_node *syscon;
-+ struct reg_field field;
-+ struct regmap *regmap;
-+ size_t array_size;
-+ u32 stride;
-+ u32 base;
-+ int ret;
-+ int i;
-+
-+ syscon = of_parse_phandle(pdev->dev.of_node, "syscon", 0);
-+ if (!syscon) {
-+ dev_err(&pdev->dev, "no syscon property\n");
-+ return -ENODEV;
-+ }
-+
-+ regmap = syscon_node_to_regmap(syscon);
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 1, &base);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "no offset in syscon\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = of_property_read_u32_index(pdev->dev.of_node, "syscon", 2, &stride);
-+ if (ret < 0) {
-+ dev_err(&pdev->dev, "no stride syscon\n");
-+ return -EINVAL;
-+ }
-+
-+ array_size = QCOM_MUTEX_NUM_LOCKS * sizeof(struct hwspinlock);
-+ bank = devm_kzalloc(&pdev->dev, sizeof(*bank) + array_size, GFP_KERNEL);
-+ if (!bank)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, bank);
-+
-+ for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) {
-+ field.reg = base + i * stride;
-+ field.lsb = 0;
-+ field.msb = 32;
-+
-+ bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
-+ regmap, field);
-+ }
-+
-+ pm_runtime_enable(&pdev->dev);
-+
-+ ret = hwspin_lock_register(bank, &pdev->dev, &qcom_hwspinlock_ops,
-+ 0, QCOM_MUTEX_NUM_LOCKS);
-+ if (ret)
-+ pm_runtime_disable(&pdev->dev);
-+
-+ return ret;
-+}
-+
-+static int qcom_hwspinlock_remove(struct platform_device *pdev)
-+{
-+ struct hwspinlock_device *bank = platform_get_drvdata(pdev);
-+ int ret;
-+
-+ ret = hwspin_lock_unregister(bank);
-+ if (ret) {
-+ dev_err(&pdev->dev, "%s failed: %d\n", __func__, ret);
-+ return ret;
-+ }
-+
-+ pm_runtime_disable(&pdev->dev);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver qcom_hwspinlock_driver = {
-+ .probe = qcom_hwspinlock_probe,
-+ .remove = qcom_hwspinlock_remove,
-+ .driver = {
-+ .name = "qcom_hwspinlock",
-+ .of_match_table = qcom_hwspinlock_of_match,
-+ },
-+};
-+
-+static int __init qcom_hwspinlock_init(void)
-+{
-+ return platform_driver_register(&qcom_hwspinlock_driver);
-+}
-+/* board init code might need to reserve hwspinlocks for predefined purposes */
-+postcore_initcall(qcom_hwspinlock_init);
-+
-+static void __exit qcom_hwspinlock_exit(void)
-+{
-+ platform_driver_unregister(&qcom_hwspinlock_driver);
-+}
-+module_exit(qcom_hwspinlock_exit);
-+
-+MODULE_LICENSE("GPL v2");
-+MODULE_DESCRIPTION("Hardware spinlock driver for Qualcomm SoCs");
diff --git a/target/linux/ipq806x/patches-4.1/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch b/target/linux/ipq806x/patches-4.1/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch
deleted file mode 100644
index 70d5a58248..0000000000
--- a/target/linux/ipq806x/patches-4.1/032-hwspinlock-qcom-Correct-msb-in-regmap_field.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From bd5717a4632cdecafe82d03de7dcb3b1876e2828 Mon Sep 17 00:00:00 2001
-From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-Date: Fri, 26 Jun 2015 14:47:21 -0700
-Subject: [PATCH] hwspinlock: qcom: Correct msb in regmap_field
-
-msb of the regmap_field was mistakenly given the value 32, to set all bits
-in the regmap update mask; although incorrect this worked until 921cc294,
-where the mask calculation was corrected.
-
-Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
----
- drivers/hwspinlock/qcom_hwspinlock.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
-
---- a/drivers/hwspinlock/qcom_hwspinlock.c
-+++ b/drivers/hwspinlock/qcom_hwspinlock.c
-@@ -123,7 +123,7 @@ static int qcom_hwspinlock_probe(struct
- for (i = 0; i < QCOM_MUTEX_NUM_LOCKS; i++) {
- field.reg = base + i * stride;
- field.lsb = 0;
-- field.msb = 32;
-+ field.msb = 31;
-
- bank->lock[i].priv = devm_regmap_field_alloc(&pdev->dev,
- regmap, field);
diff --git a/target/linux/ipq806x/patches-4.1/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch b/target/linux/ipq806x/patches-4.1/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch
deleted file mode 100644
index a126d69441..0000000000
--- a/target/linux/ipq806x/patches-4.1/033-ARM-qcom-add-SFPB-nodes-to-IPQ806x-dts.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From c7c482da19a5e4ba7101198c21c2434056b0b2da Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Thu, 13 Aug 2015 09:45:26 -0700
-Subject: [PATCH 1/3] ARM: qcom: add SFPB nodes to IPQ806x dts
-
-Add one new node to the ipq806x.dtsi file to declare & register the
-hardware spinlock devices. This mechanism is required to be used by
-other drivers such as SMEM.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 11 +++++++++++
- 1 file changed, 11 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -329,5 +329,16 @@
- #reset-cells = <1>;
- };
-
-+ sfpb_mutex_block: syscon@1200600 {
-+ compatible = "syscon";
-+ reg = <0x01200600 0x100>;
-+ };
- };
-+
-+ sfpb_mutex: sfpb-mutex {
-+ compatible = "qcom,sfpb-mutex";
-+ syscon = <&sfpb_mutex_block 4 4>;
-+
-+ #hwlock-cells = <1>;
-+ };
- };
diff --git a/target/linux/ipq806x/patches-4.1/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch b/target/linux/ipq806x/patches-4.1/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch
deleted file mode 100644
index d22db2226e..0000000000
--- a/target/linux/ipq806x/patches-4.1/034-soc-qcom-Add-device-tree-binding-for-SMEM.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v2,1/2] soc: qcom: Add device tree binding for SMEM
-From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-X-Patchwork-Id: 6202201
-Message-Id: <1428795178-24312-1-git-send-email-bjorn.andersson@sonymobile.com>
-To: Rob Herring <robh+dt@kernel.org>, Pawel Moll <pawel.moll@arm.com>,
- Mark Rutland <mark.rutland@arm.com>,
- Ian Campbell <ijc+devicetree@hellion.org.uk>,
- Kumar Gala <galak@codeaurora.org>, Jeffrey Hugo <jhugo@codeaurora.org>,
- Andry Gross <agross@codeaurora.org>
-Cc: <devicetree@vger.kernel.org>,
- linux-arm-msm <linux-arm-msm@vger.kernel.org>,
- <linux-kernel@vger.kernel.org>
-Date: Sat, 11 Apr 2015 16:32:57 -0700
-
-Add device tree binding documentation for the Qualcom Shared Memory
-manager.
-
-Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-
----
-Changes since v1:
-- None
-
- .../devicetree/bindings/soc/qcom/qcom,smem.txt | 49 ++++++++++++++++++++++
- 1 file changed, 49 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/soc/qcom/qcom,smem.txt
-@@ -0,0 +1,49 @@
-+Qualcomm Shared Memory binding
-+
-+This binding describes the Qualcomm Shared Memory, used to share data between
-+various subsystems and OSes in Qualcomm platforms.
-+
-+- compatible:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: must be:
-+ "qcom,smem"
-+
-+- memory-region:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: handle to memory reservation for main smem memory region.
-+
-+- reg:
-+ Usage: optional
-+ Value type: <prop-encoded-array>
-+ Definition: base address and size pair for any additional memory areas
-+ of the shared memory.
-+
-+- hwspinlocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: reference to a hwspinlock used to protect allocations from
-+ the shared memory
-+
-+= EXAMPLE
-+
-+ reserved-memory {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges;
-+
-+ smem_region: smem@fa00000 {
-+ reg = <0xfa00000 0x200000>;
-+ no-map;
-+ };
-+ };
-+
-+ smem@fa00000 {
-+ compatible = "qcom,smem";
-+
-+ memory-region = <&smem_region>;
-+ reg = <0xfc428000 0x4000>;
-+
-+ hwlocks = <&tcsr_mutex 3>;
-+ };
diff --git a/target/linux/ipq806x/patches-4.1/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch b/target/linux/ipq806x/patches-4.1/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch
deleted file mode 100644
index 5598da26d8..0000000000
--- a/target/linux/ipq806x/patches-4.1/035-soc-qcom-Add-Shared-Memory-Manager-driver.patch
+++ /dev/null
@@ -1,841 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v2,2/2] soc: qcom: Add Shared Memory Manager driver
-From: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-X-Patchwork-Id: 6202211
-Message-Id: <1428795178-24312-2-git-send-email-bjorn.andersson@sonymobile.com>
-To: Kumar Gala <galak@codeaurora.org>, Andy Gross <agross@codeaurora.org>,
- David Brown <davidb@codeaurora.org>, Jeffrey Hugo <jhugo@codeaurora.org>
-Cc: <linux-kernel@vger.kernel.org>, <linux-arm-msm@vger.kernel.org>,
- <linux-soc@vger.kernel.org>
-Date: Sat, 11 Apr 2015 16:32:58 -0700
-
-The Shared Memory Manager driver implements an interface for allocating
-and accessing items in the memory area shared among all of the
-processors in a Qualcomm platform.
-
-Signed-off-by: Bjorn Andersson <bjorn.andersson@sonymobile.com>
-Reviewed-by: Andy Gross <agross@codeaurora.org>
-Tested-by: Andy Gross <agross@codeaurora.org>
-
----
-Changes since v1:
-- ioremapping the regions nocache
-- improved documentation of the two regions of partitions
-- corrected free space check in private allocator
-
- drivers/soc/qcom/Kconfig | 7 +
- drivers/soc/qcom/Makefile | 1 +
- drivers/soc/qcom/smem.c | 768 ++++++++++++++++++++++++++++++++++++++++++
- include/linux/soc/qcom/smem.h | 14 +
- 4 files changed, 790 insertions(+)
- create mode 100644 drivers/soc/qcom/smem.c
- create mode 100644 include/linux/soc/qcom/smem.h
-
---- a/drivers/soc/qcom/Kconfig
-+++ b/drivers/soc/qcom/Kconfig
-@@ -10,3 +10,10 @@ config QCOM_GSBI
- functions for connecting the underlying serial UART, SPI, and I2C
- devices to the output pins.
-
-+config QCOM_SMEM
-+ tristate "Qualcomm Shared Memory Manager (SMEM)"
-+ depends on ARCH_QCOM
-+ help
-+ Say y here to enable support for the Qualcomm Shared Memory Manager.
-+ The driver provides an interface to items in a heap shared among all
-+ processors in a Qualcomm platform.
---- a/drivers/soc/qcom/Makefile
-+++ b/drivers/soc/qcom/Makefile
-@@ -1 +1,2 @@
- obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o
-+obj-$(CONFIG_QCOM_SMEM) += smem.o
---- /dev/null
-+++ b/drivers/soc/qcom/smem.c
-@@ -0,0 +1,768 @@
-+/*
-+ * Copyright (c) 2015, Sony Mobile Communications AB.
-+ * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/hwspinlock.h>
-+#include <linux/io.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/platform_device.h>
-+#include <linux/slab.h>
-+#include <linux/soc/qcom/smem.h>
-+
-+/*
-+ * The Qualcomm shared memory system is a allocate only heap structure that
-+ * consists of one of more memory areas that can be accessed by the processors
-+ * in the SoC.
-+ *
-+ * All systems contains a global heap, accessible by all processors in the SoC,
-+ * with a table of contents data structure (@smem_header) at the beginning of
-+ * the main shared memory block.
-+ *
-+ * The global header contains metadata for allocations as well as a fixed list
-+ * of 512 entries (@smem_global_entry) that can be initialized to reference
-+ * parts of the shared memory space.
-+ *
-+ *
-+ * In addition to this global heap a set of "private" heaps can be set up at
-+ * boot time with access restrictions so that only certain processor pairs can
-+ * access the data.
-+ *
-+ * These partitions are referenced from an optional partition table
-+ * (@smem_ptable), that is found 4kB from the end of the main smem region. The
-+ * partition table entries (@smem_ptable_entry) lists the involved processors
-+ * (or hosts) and their location in the main shared memory region.
-+ *
-+ * Each partition starts with a header (@smem_partition_header) that identifies
-+ * the partition and holds properties for the two internal memory regions. The
-+ * two regions are cached and non-cached memory respectively. Each region
-+ * contain a link list of allocation headers (@smem_private_entry) followed by
-+ * their data.
-+ *
-+ * Items in the non-cached region are allocated from the start of the partition
-+ * while items in the cached region are allocated from the end. The free area
-+ * is hence the region between the cached and non-cached offsets.
-+ *
-+ *
-+ * To synchronize allocations in the shared memory heaps a remote spinlock must
-+ * be held - currently lock number 3 of the sfpb or tcsr is used for this on all
-+ * platforms.
-+ *
-+ */
-+
-+/**
-+ * struct smem_proc_comm - proc_comm communication struct (legacy)
-+ * @command: current command to be executed
-+ * @status: status of the currently requested command
-+ * @params: parameters to the command
-+ */
-+struct smem_proc_comm {
-+ u32 command;
-+ u32 status;
-+ u32 params[2];
-+};
-+
-+/**
-+ * struct smem_global_entry - entry to reference smem items on the heap
-+ * @allocated: boolean to indicate if this entry is used
-+ * @offset: offset to the allocated space
-+ * @size: size of the allocated space, 8 byte aligned
-+ * @aux_base: base address for the memory region used by this unit, or 0 for
-+ * the default region. bits 0,1 are reserved
-+ */
-+struct smem_global_entry {
-+ u32 allocated;
-+ u32 offset;
-+ u32 size;
-+ u32 aux_base; /* bits 1:0 reserved */
-+};
-+#define AUX_BASE_MASK 0xfffffffc
-+
-+/**
-+ * struct smem_header - header found in beginning of primary smem region
-+ * @proc_comm: proc_comm communication interface (legacy)
-+ * @version: array of versions for the various subsystems
-+ * @initialized: boolean to indicate that smem is initialized
-+ * @free_offset: index of the first unallocated byte in smem
-+ * @available: number of bytes available for allocation
-+ * @reserved: reserved field, must be 0
-+ * toc: array of references to items
-+ */
-+struct smem_header {
-+ struct smem_proc_comm proc_comm[4];
-+ u32 version[32];
-+ u32 initialized;
-+ u32 free_offset;
-+ u32 available;
-+ u32 reserved;
-+ struct smem_global_entry toc[];
-+};
-+
-+/**
-+ * struct smem_ptable_entry - one entry in the @smem_ptable list
-+ * @offset: offset, within the main shared memory region, of the partition
-+ * @size: size of the partition
-+ * @flags: flags for the partition (currently unused)
-+ * @host0: first processor/host with access to this partition
-+ * @host1: second processor/host with access to this partition
-+ * @reserved: reserved entries for later use
-+ */
-+struct smem_ptable_entry {
-+ u32 offset;
-+ u32 size;
-+ u32 flags;
-+ u16 host0;
-+ u16 host1;
-+ u32 reserved[8];
-+};
-+
-+/**
-+ * struct smem_ptable - partition table for the private partitions
-+ * @magic: magic number, must be SMEM_PTABLE_MAGIC
-+ * @version: version of the partition table
-+ * @num_entries: number of partitions in the table
-+ * @reserved: for now reserved entries
-+ * @entry: list of @smem_ptable_entry for the @num_entries partitions
-+ */
-+struct smem_ptable {
-+ u32 magic;
-+ u32 version;
-+ u32 num_entries;
-+ u32 reserved[5];
-+ struct smem_ptable_entry entry[];
-+};
-+#define SMEM_PTABLE_MAGIC 0x434f5424 /* "$TOC" */
-+
-+/**
-+ * struct smem_partition_header - header of the partitions
-+ * @magic: magic number, must be SMEM_PART_MAGIC
-+ * @host0: first processor/host with access to this partition
-+ * @host1: second processor/host with access to this partition
-+ * @size: size of the partition
-+ * @offset_free_uncached: offset to the first free byte of uncached memory in
-+ * this partition
-+ * @offset_free_cached: offset to the first free byte of cached memory in this
-+ * partition
-+ * @reserved: for now reserved entries
-+ */
-+struct smem_partition_header {
-+ u32 magic;
-+ u16 host0;
-+ u16 host1;
-+ u32 size;
-+ u32 offset_free_uncached;
-+ u32 offset_free_cached;
-+ u32 reserved[3];
-+};
-+#define SMEM_PART_MAGIC 0x54525024 /* "$PRT" */
-+
-+/**
-+ * struct smem_private_entry - header of each item in the private partition
-+ * @canary: magic number, must be SMEM_PRIVATE_CANARY
-+ * @item: identifying number of the smem item
-+ * @size: size of the data, including padding bytes
-+ * @padding_data: number of bytes of padding of data
-+ * @padding_hdr: number of bytes of padding between the header and the data
-+ * @reserved: for now reserved entry
-+ */
-+struct smem_private_entry {
-+ u16 canary;
-+ u16 item;
-+ u32 size; /* includes padding bytes */
-+ u16 padding_data;
-+ u16 padding_hdr;
-+ u32 reserved;
-+};
-+#define SMEM_PRIVATE_CANARY 0xa5a5
-+
-+/*
-+ * Item 3 of the global heap contains an array of versions for the various
-+ * software components in the SoC. We verify that the boot loader version is
-+ * what the expected version (SMEM_EXPECTED_VERSION) as a sanity check.
-+ */
-+#define SMEM_ITEM_VERSION 3
-+#define SMEM_MASTER_SBL_VERSION_INDEX 7
-+#define SMEM_EXPECTED_VERSION 11
-+
-+/*
-+ * The first 8 items are only to be allocated by the boot loader while
-+ * initializing the heap.
-+ */
-+#define SMEM_ITEM_LAST_FIXED 8
-+
-+/* Highest accepted item number, for both global and private heaps */
-+#define SMEM_ITEM_LAST 512
-+
-+/* Processor/host identifier for the application processor */
-+#define SMEM_HOST_APPS 0
-+
-+/* Max number of processors/hosts in a system */
-+#define SMEM_HOST_COUNT 7
-+
-+/**
-+ * struct smem_region - representation of a chunk of memory used for smem
-+ * @aux_base: identifier of aux_mem base
-+ * @virt_base: virtual base address of memory with this aux_mem identifier
-+ * @size: size of the memory region
-+ */
-+struct smem_region {
-+ u32 aux_base;
-+ void __iomem *virt_base;
-+ size_t size;
-+};
-+
-+/**
-+ * struct qcom_smem - device data for the smem device
-+ * @dev: device pointer
-+ * @hwlock: reference to a hwspinlock
-+ * @partitions: list of pointers to partitions affecting the current
-+ * processor/host
-+ * @num_regions: number of @regions
-+ * @regions: list of the memory regions defining the shared memory
-+ */
-+struct qcom_smem {
-+ struct device *dev;
-+
-+ struct hwspinlock *hwlock;
-+
-+ struct smem_partition_header *partitions[SMEM_HOST_COUNT];
-+
-+ unsigned num_regions;
-+ struct smem_region regions[0];
-+};
-+
-+/* Pointer to the one and only smem handle */
-+static struct qcom_smem *__smem;
-+
-+/* Timeout (ms) for the trylock of remote spinlocks */
-+#define HWSPINLOCK_TIMEOUT 1000
-+
-+static int qcom_smem_alloc_private(struct qcom_smem *smem,
-+ unsigned host,
-+ unsigned item,
-+ size_t size)
-+{
-+ struct smem_partition_header *phdr;
-+ struct smem_private_entry *hdr;
-+ size_t alloc_size;
-+ void *p;
-+
-+ /* We're not going to find it if there's no matching partition */
-+ if (host >= SMEM_HOST_COUNT || !smem->partitions[host])
-+ return -ENOENT;
-+
-+ phdr = smem->partitions[host];
-+
-+ p = (void *)phdr + sizeof(*phdr);
-+ while (p < (void *)phdr + phdr->offset_free_uncached) {
-+ hdr = p;
-+
-+ if (hdr->canary != SMEM_PRIVATE_CANARY) {
-+ dev_err(smem->dev,
-+ "Found invalid canary in host %d partition\n",
-+ host);
-+ return -EINVAL;
-+ }
-+
-+ if (hdr->item == item)
-+ return -EEXIST;
-+
-+ p += sizeof(*hdr) + hdr->padding_hdr + hdr->size;
-+ }
-+
-+ /* Check that we don't grow into the cached region */
-+ alloc_size = sizeof(*hdr) + ALIGN(size, 8);
-+ if (p + alloc_size >= (void *)phdr + phdr->offset_free_cached) {
-+ dev_err(smem->dev, "Out of memory\n");
-+ return -ENOSPC;
-+ }
-+
-+ hdr = p;
-+ hdr->canary = SMEM_PRIVATE_CANARY;
-+ hdr->item = item;
-+ hdr->size = ALIGN(size, 8);
-+ hdr->padding_data = hdr->size - size;
-+ hdr->padding_hdr = 0;
-+
-+ /*
-+ * Ensure the header is written before we advance the free offset, so
-+ * that remote processors that does not take the remote spinlock still
-+ * gets a consistent view of the linked list.
-+ */
-+ wmb();
-+ phdr->offset_free_uncached += alloc_size;
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_alloc_global(struct qcom_smem *smem,
-+ unsigned item,
-+ size_t size)
-+{
-+ struct smem_header *header;
-+ struct smem_global_entry *entry;
-+
-+ if (WARN_ON(item >= SMEM_ITEM_LAST))
-+ return -EINVAL;
-+
-+ header = smem->regions[0].virt_base;
-+ entry = &header->toc[item];
-+ if (entry->allocated)
-+ return -EEXIST;
-+
-+ size = ALIGN(size, 8);
-+ if (WARN_ON(size > header->available))
-+ return -ENOMEM;
-+
-+ entry->offset = header->free_offset;
-+ entry->size = size;
-+
-+ /*
-+ * Ensure the header is consistent before we mark the item allocated,
-+ * so that remote processors will get a consistent view of the item
-+ * even though they do not take the spinlock on read.
-+ */
-+ wmb();
-+ entry->allocated = 1;
-+
-+ header->free_offset += size;
-+ header->available -= size;
-+
-+ return 0;
-+}
-+
-+/**
-+ * qcom_smem_alloc - allocate space for a smem item
-+ * @host: remote processor id, or -1
-+ * @item: smem item handle
-+ * @size: number of bytes to be allocated
-+ *
-+ * Allocate space for a given smem item of size @size, given that the item is
-+ * not yet allocated.
-+ */
-+int qcom_smem_alloc(unsigned host, unsigned item, size_t size)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ if (!__smem)
-+ return -EPROBE_DEFER;
-+
-+ if (item < SMEM_ITEM_LAST_FIXED) {
-+ dev_err(__smem->dev,
-+ "Rejecting allocation of static entry %d\n", item);
-+ return -EINVAL;
-+ }
-+
-+ ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
-+ HWSPINLOCK_TIMEOUT,
-+ &flags);
-+ if (ret)
-+ return ret;
-+
-+ ret = qcom_smem_alloc_private(__smem, host, item, size);
-+ if (ret == -ENOENT)
-+ ret = qcom_smem_alloc_global(__smem, item, size);
-+
-+ hwspin_unlock_irqrestore(__smem->hwlock, &flags);
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_smem_alloc);
-+
-+static int qcom_smem_get_global(struct qcom_smem *smem,
-+ unsigned item,
-+ void **ptr,
-+ size_t *size)
-+{
-+ struct smem_header *header;
-+ struct smem_region *area;
-+ struct smem_global_entry *entry;
-+ u32 aux_base;
-+ unsigned i;
-+
-+ if (WARN_ON(item >= SMEM_ITEM_LAST))
-+ return -EINVAL;
-+
-+ header = smem->regions[0].virt_base;
-+ entry = &header->toc[item];
-+ if (!entry->allocated)
-+ return -ENXIO;
-+
-+ if (ptr != NULL) {
-+ aux_base = entry->aux_base & AUX_BASE_MASK;
-+
-+ for (i = 0; i < smem->num_regions; i++) {
-+ area = &smem->regions[i];
-+
-+ if (area->aux_base == aux_base || !aux_base) {
-+ *ptr = area->virt_base + entry->offset;
-+ break;
-+ }
-+ }
-+ }
-+ if (size != NULL)
-+ *size = entry->size;
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_get_private(struct qcom_smem *smem,
-+ unsigned host,
-+ unsigned item,
-+ void **ptr,
-+ size_t *size)
-+{
-+ struct smem_partition_header *phdr;
-+ struct smem_private_entry *hdr;
-+ void *p;
-+
-+ /* We're not going to find it if there's no matching partition */
-+ if (host >= SMEM_HOST_COUNT || !smem->partitions[host])
-+ return -ENOENT;
-+
-+ phdr = smem->partitions[host];
-+
-+ p = (void *)phdr + sizeof(*phdr);
-+ while (p < (void *)phdr + phdr->offset_free_uncached) {
-+ hdr = p;
-+
-+ if (hdr->canary != SMEM_PRIVATE_CANARY) {
-+ dev_err(smem->dev,
-+ "Found invalid canary in host %d partition\n",
-+ host);
-+ return -EINVAL;
-+ }
-+
-+ if (hdr->item == item) {
-+ if (ptr != NULL)
-+ *ptr = p + sizeof(*hdr) + hdr->padding_hdr;
-+
-+ if (size != NULL)
-+ *size = hdr->size - hdr->padding_data;
-+
-+ return 0;
-+ }
-+
-+ p += sizeof(*hdr) + hdr->padding_hdr + hdr->size;
-+ }
-+
-+ return -ENOENT;
-+}
-+
-+/**
-+ * qcom_smem_get - resolve ptr of size of a smem item
-+ * @host: the remote processor, or -1
-+ * @item: smem item handle
-+ * @ptr: pointer to be filled out with address of the item
-+ * @size: pointer to be filled out with size of the item
-+ *
-+ * Looks up pointer and size of a smem item.
-+ */
-+int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size)
-+{
-+ unsigned long flags;
-+ int ret;
-+
-+ if (!__smem)
-+ return -EPROBE_DEFER;
-+
-+ ret = hwspin_lock_timeout_irqsave(__smem->hwlock,
-+ HWSPINLOCK_TIMEOUT,
-+ &flags);
-+ if (ret)
-+ return ret;
-+
-+ ret = qcom_smem_get_private(__smem, host, item, ptr, size);
-+ if (ret == -ENOENT)
-+ ret = qcom_smem_get_global(__smem, item, ptr, size);
-+
-+ hwspin_unlock_irqrestore(__smem->hwlock, &flags);
-+ return ret;
-+
-+}
-+EXPORT_SYMBOL(qcom_smem_get);
-+
-+/**
-+ * qcom_smem_get_free_space - retrieve amont of free space in a partition
-+ * @host: the remote processor identifing a partition, or -1
-+ *
-+ * To be used by smem clients as a quick way to determine if any new
-+ * allocations has been made.
-+ */
-+int qcom_smem_get_free_space(unsigned host)
-+{
-+ struct smem_partition_header *phdr;
-+ struct smem_header *header;
-+ unsigned ret;
-+
-+ if (!__smem)
-+ return -EPROBE_DEFER;
-+
-+ if (host < SMEM_HOST_COUNT && __smem->partitions[host]) {
-+ phdr = __smem->partitions[host];
-+ ret = phdr->offset_free_uncached;
-+ } else {
-+ header = __smem->regions[0].virt_base;
-+ ret = header->available;
-+ }
-+
-+ return ret;
-+}
-+EXPORT_SYMBOL(qcom_smem_get_free_space);
-+
-+static int qcom_smem_get_sbl_version(struct qcom_smem *smem)
-+{
-+ unsigned *versions;
-+ size_t size;
-+ int ret;
-+
-+ ret = qcom_smem_get_global(smem, SMEM_ITEM_VERSION,
-+ (void **)&versions, &size);
-+ if (ret < 0) {
-+ dev_err(smem->dev, "Unable to read the version item\n");
-+ return -ENOENT;
-+ }
-+
-+ if (size < sizeof(unsigned) * SMEM_MASTER_SBL_VERSION_INDEX) {
-+ dev_err(smem->dev, "Version item is too small\n");
-+ return -EINVAL;
-+ }
-+
-+ return versions[SMEM_MASTER_SBL_VERSION_INDEX];
-+}
-+
-+static int qcom_smem_enumerate_partitions(struct qcom_smem *smem,
-+ unsigned local_host)
-+{
-+ struct smem_partition_header *header;
-+ struct smem_ptable_entry *entry;
-+ struct smem_ptable *ptable;
-+ unsigned remote_host;
-+ int i;
-+
-+ ptable = smem->regions[0].virt_base + smem->regions[0].size - 4 * 1024;
-+ if (ptable->magic != SMEM_PTABLE_MAGIC)
-+ return 0;
-+
-+ if (ptable->version != 1) {
-+ dev_err(smem->dev,
-+ "Unsupported partition header version %d\n",
-+ ptable->version);
-+ return -EINVAL;
-+ }
-+
-+ for (i = 0; i < ptable->num_entries; i++) {
-+ entry = &ptable->entry[i];
-+
-+ if (entry->host0 != local_host && entry->host1 != local_host)
-+ continue;
-+
-+ if (!entry->offset)
-+ continue;
-+
-+ if (!entry->size)
-+ continue;
-+
-+ if (entry->host0 == local_host)
-+ remote_host = entry->host1;
-+ else
-+ remote_host = entry->host0;
-+
-+ if (smem->partitions[remote_host]) {
-+ dev_err(smem->dev,
-+ "Already found a partition for host %d\n",
-+ remote_host);
-+ return -EINVAL;
-+ }
-+
-+ header = smem->regions[0].virt_base + entry->offset;
-+
-+ if (header->magic != SMEM_PART_MAGIC) {
-+ dev_err(smem->dev,
-+ "Partition %d has invalid magic\n", i);
-+ return -EINVAL;
-+ }
-+
-+ if (header->host0 != local_host && header->host1 != local_host) {
-+ dev_err(smem->dev,
-+ "Partition %d hosts are invalid\n", i);
-+ return -EINVAL;
-+ }
-+
-+ if (header->host0 != remote_host && header->host1 != remote_host) {
-+ dev_err(smem->dev,
-+ "Partition %d hosts are invalid\n", i);
-+ return -EINVAL;
-+ }
-+
-+ if (header->size != entry->size) {
-+ dev_err(smem->dev,
-+ "Partition %d has invalid size\n", i);
-+ return -EINVAL;
-+ }
-+
-+ if (header->offset_free_uncached > header->size) {
-+ dev_err(smem->dev,
-+ "Partition %d has invalid free pointer\n", i);
-+ return -EINVAL;
-+ }
-+
-+ smem->partitions[remote_host] = header;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_count_mem_regions(struct platform_device *pdev)
-+{
-+ struct resource *res;
-+ int num_regions = 0;
-+ int i;
-+
-+ for (i = 0; i < pdev->num_resources; i++) {
-+ res = &pdev->resource[i];
-+
-+ if (resource_type(res) == IORESOURCE_MEM)
-+ num_regions++;
-+ }
-+
-+ return num_regions;
-+}
-+
-+static int qcom_smem_probe(struct platform_device *pdev)
-+{
-+ struct smem_header *header;
-+ struct device_node *np;
-+ struct qcom_smem *smem;
-+ struct resource *res;
-+ struct resource r;
-+ size_t array_size;
-+ int num_regions = 0;
-+ int hwlock_id;
-+ u32 version;
-+ int ret;
-+ int i;
-+
-+ num_regions = qcom_smem_count_mem_regions(pdev) + 1;
-+
-+ array_size = num_regions * sizeof(struct smem_region);
-+ smem = devm_kzalloc(&pdev->dev, sizeof(*smem) + array_size, GFP_KERNEL);
-+ if (!smem)
-+ return -ENOMEM;
-+
-+ smem->dev = &pdev->dev;
-+ smem->num_regions = num_regions;
-+
-+ np = of_parse_phandle(pdev->dev.of_node, "memory-region", 0);
-+ if (!np) {
-+ dev_err(&pdev->dev, "No memory-region specified\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = of_address_to_resource(np, 0, &r);
-+ of_node_put(np);
-+ if (ret)
-+ return ret;
-+
-+ smem->regions[0].aux_base = (u32)r.start;
-+ smem->regions[0].size = resource_size(&r);
-+ smem->regions[0].virt_base = devm_ioremap_nocache(&pdev->dev,
-+ r.start,
-+ resource_size(&r));
-+ if (!smem->regions[0].virt_base)
-+ return -ENOMEM;
-+
-+ for (i = 1; i < num_regions; i++) {
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, i - 1);
-+
-+ smem->regions[i].aux_base = (u32)res->start;
-+ smem->regions[i].size = resource_size(res);
-+ smem->regions[i].virt_base = devm_ioremap_nocache(&pdev->dev,
-+ res->start,
-+ resource_size(res));
-+ if (!smem->regions[i].virt_base)
-+ return -ENOMEM;
-+ }
-+
-+ header = smem->regions[0].virt_base;
-+ if (header->initialized != 1 || header->reserved) {
-+ dev_err(&pdev->dev, "SMEM is not initilized by SBL\n");
-+ return -EINVAL;
-+ }
-+
-+ version = qcom_smem_get_sbl_version(smem);
-+ if (version >> 16 != SMEM_EXPECTED_VERSION) {
-+ dev_err(&pdev->dev, "Unsupported smem version 0x%x\n", version);
-+ return -EINVAL;
-+ }
-+
-+ ret = qcom_smem_enumerate_partitions(smem, SMEM_HOST_APPS);
-+ if (ret < 0)
-+ return ret;
-+
-+ hwlock_id = of_hwspin_lock_get_id(pdev->dev.of_node, 0);
-+ if (hwlock_id < 0) {
-+ dev_err(&pdev->dev, "failed to retrieve hwlock\n");
-+ return hwlock_id;
-+ }
-+
-+ smem->hwlock = hwspin_lock_request_specific(hwlock_id);
-+ if (!smem->hwlock)
-+ return -ENXIO;
-+
-+ __smem = smem;
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_remove(struct platform_device *pdev)
-+{
-+ hwspin_lock_free(__smem->hwlock);
-+ __smem = NULL;
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id qcom_smem_of_match[] = {
-+ { .compatible = "qcom,smem" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, qcom_smem_of_match);
-+
-+static struct platform_driver qcom_smem_driver = {
-+ .probe = qcom_smem_probe,
-+ .remove = qcom_smem_remove,
-+ .driver = {
-+ .name = "qcom_smem",
-+ .of_match_table = qcom_smem_of_match,
-+ .suppress_bind_attrs = true,
-+ },
-+};
-+
-+static int __init qcom_smem_init(void)
-+{
-+ return platform_driver_register(&qcom_smem_driver);
-+}
-+arch_initcall(qcom_smem_init);
-+
-+static void __exit qcom_smem_exit(void)
-+{
-+ platform_driver_unregister(&qcom_smem_driver);
-+}
-+module_exit(qcom_smem_exit)
-+
-+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
-+MODULE_DESCRIPTION("Qualcomm Shared Memory Manager");
-+MODULE_LICENSE("GPLv2");
---- /dev/null
-+++ b/include/linux/soc/qcom/smem.h
-@@ -0,0 +1,14 @@
-+#ifndef __QCOM_SMEM_H__
-+#define __QCOM_SMEM_H__
-+
-+struct device_node;
-+struct qcom_smem;
-+
-+#define QCOM_SMEM_HOST_ANY -1
-+
-+int qcom_smem_alloc(unsigned host, unsigned item, size_t size);
-+int qcom_smem_get(unsigned host, unsigned item, void **ptr, size_t *size);
-+
-+int qcom_smem_get_free_space(unsigned host);
-+
-+#endif
diff --git a/target/linux/ipq806x/patches-4.1/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch b/target/linux/ipq806x/patches-4.1/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch
deleted file mode 100644
index b55f17475e..0000000000
--- a/target/linux/ipq806x/patches-4.1/036-ARM-qcom-add-SMEM-device-node-to-IPQ806x-dts.patch
+++ /dev/null
@@ -1,36 +0,0 @@
-From f212be3a6134db8dd7c5f6f0987536a669401fae Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Fri, 14 Aug 2015 11:17:20 -0700
-Subject: [PATCH 2/3] ARM: qcom: add SMEM device node to IPQ806x dts
-
-SMEM is used on IPQ806x to store various board related information such
-as boot device and flash partition layout. We'll declare it as a device
-so we can make use of it thanks to the new SMEM soc driver.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 8 +++++++-
- 1 file changed, 7 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -55,7 +55,7 @@
- no-map;
- };
-
-- smem@41000000 {
-+ smem: smem@41000000 {
- reg = <0x41000000 0x200000>;
- no-map;
- };
-@@ -341,4 +341,10 @@
-
- #hwlock-cells = <1>;
- };
-+
-+ smem {
-+ compatible = "qcom,smem";
-+ memory-region = <&smem>;
-+ hwlocks = <&sfpb_mutex 3>;
-+ };
- };
diff --git a/target/linux/ipq806x/patches-4.1/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch b/target/linux/ipq806x/patches-4.1/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch
deleted file mode 100644
index 5fc54134de..0000000000
--- a/target/linux/ipq806x/patches-4.1/037-mtd-add-SMEM-parser-for-QCOM-platforms.patch
+++ /dev/null
@@ -1,277 +0,0 @@
-From 0501f76b138cf1dc11a313bb7a094da524b79337 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Thu, 13 Aug 2015 09:53:14 -0700
-Subject: [PATCH 3/3] mtd: add SMEM parser for QCOM platforms
-
-On QCOM platforms using MTD devices storage (such as IPQ806x), SMEM is
-used to store partition layout. This new parser can now be used to read
-SMEM and use it to register an MTD layout according to its content.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- drivers/mtd/Kconfig | 7 ++
- drivers/mtd/Makefile | 1 +
- drivers/mtd/qcom_smem_part.c | 231 +++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 239 insertions(+)
- create mode 100644 drivers/mtd/qcom_smem_part.c
-
---- a/drivers/mtd/Kconfig
-+++ b/drivers/mtd/Kconfig
-@@ -195,6 +195,13 @@ config MTD_MYLOADER_PARTS
- You will still need the parsing functions to be called by the driver
- for your particular device. It won't happen automatically.
-
-+config MTD_QCOM_SMEM_PARTS
-+ tristate "QCOM SMEM partitioning support"
-+ depends on QCOM_SMEM
-+ help
-+ This provides partitions parser for QCOM devices using SMEM
-+ such as IPQ806x.
-+
- comment "User Modules And Translation Layers"
-
- #
---- /dev/null
-+++ b/drivers/mtd/qcom_smem_part.c
-@@ -0,0 +1,231 @@
-+/*
-+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/device.h>
-+#include <linux/slab.h>
-+
-+#include <linux/mtd/mtd.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/spi/spi.h>
-+#include <linux/module.h>
-+
-+#include <linux/soc/qcom/smem.h>
-+
-+/* Processor/host identifier for the application processor */
-+#define SMEM_HOST_APPS 0
-+
-+/* SMEM items index */
-+#define SMEM_AARM_PARTITION_TABLE 9
-+#define SMEM_BOOT_FLASH_TYPE 421
-+#define SMEM_BOOT_FLASH_BLOCK_SIZE 424
-+
-+/* SMEM Flash types */
-+#define SMEM_FLASH_NAND 2
-+#define SMEM_FLASH_SPI 6
-+
-+#define SMEM_PART_NAME_SZ 16
-+#define SMEM_PARTS_MAX 32
-+
-+struct smem_partition {
-+ char name[SMEM_PART_NAME_SZ];
-+ __le32 start;
-+ __le32 size;
-+ __le32 attr;
-+};
-+
-+struct smem_partition_table {
-+ u8 magic[8];
-+ __le32 version;
-+ __le32 len;
-+ struct smem_partition parts[SMEM_PARTS_MAX];
-+};
-+
-+/* SMEM Magic values in partition table */
-+static const u8 SMEM_PTABLE_MAGIC[] = {
-+ 0xaa, 0x73, 0xee, 0x55,
-+ 0xdb, 0xbd, 0x5e, 0xe3,
-+};
-+
-+static int qcom_smem_get_flash_blksz(u64 **smem_blksz)
-+{
-+ int ret;
-+ size_t size;
-+
-+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_BLOCK_SIZE,
-+ (void **) smem_blksz, &size);
-+
-+ if (ret < 0) {
-+ pr_err("Unable to read flash blksz from SMEM\n");
-+ return -ENOENT;
-+ }
-+
-+ if (size != sizeof(**smem_blksz)) {
-+ pr_err("Invalid flash blksz size in SMEM\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_get_flash_type(u64 **smem_flash_type)
-+{
-+ int ret;
-+ size_t size;
-+
-+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_BOOT_FLASH_TYPE,
-+ (void **) smem_flash_type, &size);
-+
-+ if (ret < 0) {
-+ pr_err("Unable to read flash type from SMEM\n");
-+ return -ENOENT;
-+ }
-+
-+ if (size != sizeof(**smem_flash_type)) {
-+ pr_err("Invalid flash type size in SMEM\n");
-+ return -EINVAL;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_smem_get_flash_partitions(struct smem_partition_table **pparts)
-+{
-+ int ret;
-+ size_t size;
-+
-+ ret = qcom_smem_get(SMEM_HOST_APPS, SMEM_AARM_PARTITION_TABLE,
-+ (void **) pparts, &size);
-+
-+ if (ret < 0) {
-+ pr_err("Unable to read partition table from SMEM\n");
-+ return -ENOENT;
-+ }
-+
-+ return 0;
-+}
-+
-+static int of_dev_node_match(struct device *dev, void *data)
-+{
-+ return dev->of_node == data;
-+}
-+
-+static bool is_spi_device(struct device_node *np)
-+{
-+ struct device *dev;
-+
-+ dev = bus_find_device(&spi_bus_type, NULL, np, of_dev_node_match);
-+ if (!dev)
-+ return false;
-+
-+ put_device(dev);
-+ return true;
-+}
-+
-+static int parse_qcom_smem_partitions(struct mtd_info *master,
-+ struct mtd_partition **pparts,
-+ struct mtd_part_parser_data *data)
-+{
-+ struct smem_partition_table *smem_parts;
-+ u64 *smem_flash_type, *smem_blksz;
-+ struct mtd_partition *mtd_parts;
-+ struct device_node *of_node = data->of_node;
-+ int i, ret;
-+
-+ /*
-+ * SMEM will only store the partition table of the boot device.
-+ * If this is not the boot device, do not return any partition.
-+ */
-+ ret = qcom_smem_get_flash_type(&smem_flash_type);
-+ if (ret < 0)
-+ return ret;
-+
-+ if ((*smem_flash_type == SMEM_FLASH_NAND && !mtd_type_is_nand(master))
-+ || (*smem_flash_type == SMEM_FLASH_SPI && !is_spi_device(of_node)))
-+ return 0;
-+
-+ /*
-+ * Just for sanity purpose, make sure the block size in SMEM matches the
-+ * block size of the MTD device
-+ */
-+ ret = qcom_smem_get_flash_blksz(&smem_blksz);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (*smem_blksz != master->erasesize) {
-+ pr_err("SMEM block size differs from MTD block size\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Get partition pointer from SMEM */
-+ ret = qcom_smem_get_flash_partitions(&smem_parts);
-+ if (ret < 0)
-+ return ret;
-+
-+ if (memcmp(SMEM_PTABLE_MAGIC, smem_parts->magic,
-+ sizeof(SMEM_PTABLE_MAGIC))) {
-+ pr_err("SMEM partition magic invalid\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Allocate and populate the mtd structures */
-+ mtd_parts = kcalloc(le32_to_cpu(smem_parts->len), sizeof(*mtd_parts),
-+ GFP_KERNEL);
-+ if (!mtd_parts)
-+ return -ENOMEM;
-+
-+ for (i = 0; i < smem_parts->len; i++) {
-+ struct smem_partition *s_part = &smem_parts->parts[i];
-+ struct mtd_partition *m_part = &mtd_parts[i];
-+
-+ m_part->name = s_part->name;
-+ m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz);
-+ m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz);
-+
-+ /*
-+ * The last SMEM partition may have its size marked as
-+ * something like 0xffffffff, which means "until the end of the
-+ * flash device". In this case, truncate it.
-+ */
-+ if (m_part->offset + m_part->size > master->size)
-+ m_part->size = master->size - m_part->offset;
-+ }
-+
-+ *pparts = mtd_parts;
-+
-+ return smem_parts->len;
-+}
-+
-+static struct mtd_part_parser qcom_smem_parser = {
-+ .owner = THIS_MODULE,
-+ .parse_fn = parse_qcom_smem_partitions,
-+ .name = "qcom-smem",
-+};
-+
-+static int __init qcom_smem_parser_init(void)
-+{
-+ register_mtd_parser(&qcom_smem_parser);
-+ return 0;
-+}
-+
-+static void __exit qcom_smem_parser_exit(void)
-+{
-+ deregister_mtd_parser(&qcom_smem_parser);
-+}
-+
-+module_init(qcom_smem_parser_init);
-+module_exit(qcom_smem_parser_exit);
-+
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
-+MODULE_DESCRIPTION("Parsing code for SMEM based partition tables");
---- a/drivers/mtd/Makefile
-+++ b/drivers/mtd/Makefile
-@@ -16,6 +16,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
- obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
- obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
- obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
-+obj-$(CONFIG_MTD_QCOM_SMEM_PARTS) += qcom_smem_part.o
-
- # 'Users' - code which presents functionality to userspace.
- obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
diff --git a/target/linux/ipq806x/patches-4.1/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch b/target/linux/ipq806x/patches-4.1/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch
deleted file mode 100644
index 41f91fae7c..0000000000
--- a/target/linux/ipq806x/patches-4.1/110-DT-PCI-qcom-Document-PCIe-devicetree-bindings.patch
+++ /dev/null
@@ -1,263 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v2,3/5] DT: PCI: qcom: Document PCIe devicetree bindings
-From: Stanimir Varbanov <svarbanov@mm-sol.com>
-X-Patchwork-Id: 6326181
-Message-Id: <1430743338-10441-4-git-send-email-svarbanov@mm-sol.com>
-To: Rob Herring <robh+dt@kernel.org>, Kumar Gala <galak@codeaurora.org>,
- Mark Rutland <mark.rutland@arm.com>,
- Grant Likely <grant.likely@linaro.org>,
- Bjorn Helgaas <bhelgaas@google.com>,
- Kishon Vijay Abraham I <kishon@ti.com>,
- Russell King <linux@arm.linux.org.uk>, Arnd Bergmann <arnd@arndb.de>
-Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
- linux-pci@vger.kernel.org, Mathieu Olivari <mathieu@codeaurora.org>,
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
- Stanimir Varbanov <svarbanov@mm-sol.com>
-Date: Mon, 4 May 2015 15:42:16 +0300
-
-Document Qualcomm PCIe driver devicetree bindings.
-
-Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
-
----
-.../devicetree/bindings/pci/qcom,pcie.txt | 231 ++++++++++++++++++++
- 1 files changed, 231 insertions(+), 0 deletions(-)
- create mode 100644 Documentation/devicetree/bindings/pci/qcom,pcie.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/pci/qcom,pcie.txt
-@@ -0,0 +1,231 @@
-+* Qualcomm PCI express root complex
-+
-+- compatible:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: Value shall include
-+ - "qcom,pcie-v0" for apq/ipq8064
-+ - "qcom,pcie-v1" for apq8084
-+
-+- reg:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: Register ranges as listed in the reg-names property
-+
-+- reg-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: Must include the following entries
-+ - "parf" Qualcomm specific registers
-+ - "dbi" Designware PCIe registers
-+ - "elbi" External local bus interface registers
-+ - "config" PCIe configuration space
-+
-+- device_type:
-+ Usage: required
-+ Value type: <string>
-+ Definition: Should be "pci". As specified in designware-pcie.txt
-+
-+- #address-cells:
-+ Usage: required
-+ Value type: <u32>
-+ Definition: Should be set to 3. As specified in designware-pcie.txt
-+
-+- #size-cells:
-+ Usage: required
-+ Value type: <u32>
-+ Definition: Should be set 2. As specified in designware-pcie.txt
-+
-+- ranges:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: As specified in designware-pcie.txt
-+
-+- interrupts:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: MSI interrupt
-+
-+- interrupt-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: Should contain "msi"
-+
-+- #interrupt-cells:
-+ Usage: required
-+ Value type: <u32>
-+ Definition: Should be 1. As specified in designware-pcie.txt
-+
-+- interrupt-map-mask:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: As specified in designware-pcie.txt
-+
-+- interrupt-map:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: As specified in designware-pcie.txt
-+
-+- clocks:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: List of phandle and clock specifier pairs as listed
-+ in clock-names property
-+
-+- clock-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: Should contain the following entries
-+ * should be populated for v0 and v1
-+ - "iface" Configuration AHB clock
-+
-+ * should be populated for v0
-+ - "core" Clocks the pcie hw block
-+ - "phy" Clocks the pcie PHY block
-+
-+ * should be populated for v1
-+ - "aux" Auxiliary (AUX) clock
-+ - "bus_master" Master AXI clock
-+ - "bus_slave" Slave AXI clock
-+
-+- resets:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: List of phandle and reset specifier pairs as listed
-+ in reset-names property
-+
-+- reset-names:
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: Should contain the following entries
-+ * should be populated for v0
-+ - "axi" AXI reset
-+ - "ahb" AHB reset
-+ - "por" POR reset
-+ - "pci" PCI reset
-+ - "phy" PHY reset
-+
-+ * should be populated for v1
-+ - "core" Core reset
-+
-+- power-domains:
-+ Usage: required (for v1 only)
-+ Value type: <prop-encoded-array>
-+ Definition: A phandle and power domain specifier pair to the
-+ power domain which is responsible for collapsing
-+ and restoring power to the peripheral
-+
-+- <name>-supply:
-+ Usage: required
-+ Value type: <phandle>
-+ Definition: List of phandles to the power supply regulator(s)
-+ * should be populated for v0 and v1
-+ - "vdda" core analog power supply
-+
-+ * should be populated for v0
-+ - "vdda_phy" analog power supply for PHY
-+ - "vdda_refclk" analog power supply for IC which generate
-+ reference clock
-+
-+- phys:
-+ Usage: required (for v1 only)
-+ Value type: <phandle>
-+ Definition: List of phandle(s) as listed in phy-names property
-+
-+- phy-names:
-+ Usage: required (for v1 only)
-+ Value type: <stringlist>
-+ Definition: Should contain "pciephy"
-+
-+- <name>-gpio:
-+ Usage: optional
-+ Value type: <prop-encoded-array>
-+ Definition: List of phandle and gpio specifier pairs. Should contain
-+ - "perst" PCIe endpoint reset signal line
-+ - "pewake" PCIe endpoint wake signal line
-+
-+- pinctrl-0:
-+ Usage: required
-+ Value type: <phandle>
-+ Definition: List of phandles pointing at a pin(s) configuration
-+
-+- pinctrl-names
-+ Usage: required
-+ Value type: <stringlist>
-+ Definition: List of names of pinctrl-0 state
-+
-+* Example for v0
-+ pcie0: pci@1b500000 {
-+ compatible = "qcom,pcie-v0";
-+ reg = <0x1b500000 0x1000
-+ 0x1b502000 0x80
-+ 0x1b600000 0x100
-+ 0x0ff00000 0x100000>;
-+ reg-names = "dbi", "elbi", "parf", "config";
-+ device_type = "pci";
-+ linux,pci-domain = <0>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges = <0x81000000 0 0 0x0fe00000 0 0x00100000 /* I/O */
-+ 0x82000000 0 0x00000000 0x08000000 0 0x07e00000>; /* memory */
-+ interrupts = <GIC_SPI 35 IRQ_TYPE_NONE>;
-+ interrupt-names = "msi";
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-+ <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-+ <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-+ <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
-+ clocks = <&gcc PCIE_A_CLK>,
-+ <&gcc PCIE_H_CLK>,
-+ <&gcc PCIE_PHY_CLK>;
-+ clock-names = "core", "iface", "phy";
-+ resets = <&gcc PCIE_ACLK_RESET>,
-+ <&gcc PCIE_HCLK_RESET>,
-+ <&gcc PCIE_POR_RESET>,
-+ <&gcc PCIE_PCI_RESET>,
-+ <&gcc PCIE_PHY_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy";
-+ };
-+
-+* Example for v1
-+ pcie0@fc520000 {
-+ compatible = "qcom,pcie-v1";
-+ reg = <0xfc520000 0x2000>,
-+ <0xff000000 0x1000>,
-+ <0xff001000 0x1000>,
-+ <0xff002000 0x2000>;
-+ reg-names = "parf", "dbi", "elbi", "config";
-+ device_type = "pci";
-+ linux,pci-domain = <0>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+ ranges = <0x81000000 0 0 0xff200000 0 0x00100000 /* I/O */
-+ 0x82000000 0 0x00300000 0xff300000 0 0x00d00000>; /* memory */
-+ interrupts = <GIC_SPI 243 IRQ_TYPE_NONE>;
-+ interrupt-names = "msi";
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 244 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-+ <0 0 0 2 &intc 0 245 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-+ <0 0 0 3 &intc 0 247 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-+ <0 0 0 4 &intc 0 248 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
-+ clocks = <&gcc GCC_PCIE_0_CFG_AHB_CLK>,
-+ <&gcc GCC_PCIE_0_MSTR_AXI_CLK>,
-+ <&gcc GCC_PCIE_0_SLV_AXI_CLK>,
-+ <&gcc GCC_PCIE_0_AUX_CLK>;
-+ clock-names = "iface", "master_bus", "slave_bus", "aux";
-+ resets = <&gcc GCC_PCIE_0_BCR>;
-+ reset-names = "core";
-+ power-domains = <&gcc PCIE0_GDSC>;
-+ vdda-supply = <&pma8084_l3>;
-+ phys = <&pciephy0>;
-+ phy-names = "pciephy";
-+ perst-gpio = <&tlmm 70 GPIO_ACTIVE_LOW>;
-+ pinctrl-0 = <&pcie0_pins_default>;
-+ pinctrl-names = "default";
-+ };
diff --git a/target/linux/ipq806x/patches-4.1/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch b/target/linux/ipq806x/patches-4.1/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch
deleted file mode 100644
index dbf16a303a..0000000000
--- a/target/linux/ipq806x/patches-4.1/111-PCI-qcom-Add-Qualcomm-PCIe-controller-driver.patch
+++ /dev/null
@@ -1,753 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v2,4/5] PCI: qcom: Add Qualcomm PCIe controller driver
-From: Stanimir Varbanov <svarbanov@mm-sol.com>
-X-Patchwork-Id: 6326161
-Message-Id: <1430743338-10441-5-git-send-email-svarbanov@mm-sol.com>
-To: Rob Herring <robh+dt@kernel.org>, Kumar Gala <galak@codeaurora.org>,
- Mark Rutland <mark.rutland@arm.com>,
- Grant Likely <grant.likely@linaro.org>,
- Bjorn Helgaas <bhelgaas@google.com>,
- Kishon Vijay Abraham I <kishon@ti.com>,
- Russell King <linux@arm.linux.org.uk>, Arnd Bergmann <arnd@arndb.de>
-Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org, devicetree@vger.kernel.org,
- linux-pci@vger.kernel.org, Mathieu Olivari <mathieu@codeaurora.org>,
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>,
- Stanimir Varbanov <svarbanov@mm-sol.com>
-Date: Mon, 4 May 2015 15:42:17 +0300
-
-The PCIe driver reuse the Designware common code for host
-and MSI initialization, and also program the Qualcomm
-application specific registers.
-
-Signed-off-by: Stanimir Varbanov <svarbanov@mm-sol.com>
-
----
-MAINTAINERS | 7 +
- drivers/pci/host/Kconfig | 9 +
- drivers/pci/host/Makefile | 1 +
- drivers/pci/host/pcie-qcom.c | 677 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 694 insertions(+), 0 deletions(-)
- create mode 100644 drivers/pci/host/pcie-qcom.c
-
---- a/MAINTAINERS
-+++ b/MAINTAINERS
-@@ -7599,6 +7599,13 @@ L: linux-pci@vger.kernel.org
- S: Maintained
- F: drivers/pci/host/*spear*
-
-+PCIE DRIVER FOR QUALCOMM MSM
-+M: Stanimir Varbanov <svarbanov@mm-sol.com>
-+L: linux-pci@vger.kernel.org
-+L: linux-arm-msm@vger.kernel.org
-+S: Maintained
-+F: drivers/pci/host/*qcom*
-+
- PCMCIA SUBSYSTEM
- P: Linux PCMCIA Team
- L: linux-pcmcia@lists.infradead.org
---- a/drivers/pci/host/Kconfig
-+++ b/drivers/pci/host/Kconfig
-@@ -125,4 +125,13 @@ config PCIE_IPROC_PLATFORM
- Say Y here if you want to use the Broadcom iProc PCIe controller
- through the generic platform bus interface
-
-+config PCIE_QCOM
-+ bool "Qualcomm PCIe controller"
-+ depends on ARCH_QCOM && OF || (ARM && COMPILE_TEST)
-+ select PCIE_DW
-+ select PCIEPORTBUS
-+ help
-+ Say Y here to enable PCIe controller support on Qualcomm SoCs. The
-+ PCIe controller use Designware core plus Qualcomm specific hardware
-+ wrappers.
- endmenu
---- /dev/null
-+++ b/drivers/pci/host/pcie-qcom.c
-@@ -0,0 +1,677 @@
-+/*
-+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/delay.h>
-+#include <linux/gpio.h>
-+#include <linux/interrupt.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of_gpio.h>
-+#include <linux/pci.h>
-+#include <linux/platform_device.h>
-+#include <linux/phy/phy.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/reset.h>
-+#include <linux/slab.h>
-+#include <linux/types.h>
-+
-+#include "pcie-designware.h"
-+
-+#define PCIE20_PARF_PHY_CTRL 0x40
-+#define PCIE20_PARF_PHY_REFCLK 0x4C
-+#define PCIE20_PARF_DBI_BASE_ADDR 0x168
-+#define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c
-+#define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178
-+
-+#define PCIE20_ELBI_SYS_CTRL 0x04
-+#define PCIE20_ELBI_SYS_STTS 0x08
-+#define XMLH_LINK_UP BIT(10)
-+
-+#define PCIE20_CAP 0x70
-+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
-+
-+#define PERST_DELAY_MIN_US 1000
-+#define PERST_DELAY_MAX_US 1005
-+
-+#define LINKUP_DELAY_MIN_US 5000
-+#define LINKUP_DELAY_MAX_US 5100
-+#define LINKUP_RETRIES_COUNT 20
-+
-+#define PCIE_V0 0 /* apq8064 */
-+#define PCIE_V1 1 /* apq8084 */
-+
-+struct qcom_pcie_resources_v0 {
-+ struct clk *iface_clk;
-+ struct clk *core_clk;
-+ struct clk *phy_clk;
-+ struct reset_control *pci_reset;
-+ struct reset_control *axi_reset;
-+ struct reset_control *ahb_reset;
-+ struct reset_control *por_reset;
-+ struct reset_control *phy_reset;
-+ struct regulator *vdda;
-+ struct regulator *vdda_phy;
-+ struct regulator *vdda_refclk;
-+};
-+
-+struct qcom_pcie_resources_v1 {
-+ struct clk *iface;
-+ struct clk *aux;
-+ struct clk *master_bus;
-+ struct clk *slave_bus;
-+ struct reset_control *core;
-+ struct regulator *vdda;
-+};
-+
-+union pcie_resources {
-+ struct qcom_pcie_resources_v0 v0;
-+ struct qcom_pcie_resources_v1 v1;
-+};
-+
-+struct qcom_pcie {
-+ struct pcie_port pp;
-+ struct device *dev;
-+ union pcie_resources res;
-+ void __iomem *parf;
-+ void __iomem *dbi;
-+ void __iomem *elbi;
-+ struct phy *phy;
-+ struct gpio_desc *reset;
-+ unsigned int version;
-+};
-+
-+#define to_qcom_pcie(x) container_of(x, struct qcom_pcie, pp)
-+
-+static inline void
-+writel_masked(void __iomem *addr, u32 clear_mask, u32 set_mask)
-+{
-+ u32 val = readl(addr);
-+
-+ val &= ~clear_mask;
-+ val |= set_mask;
-+ writel(val, addr);
-+}
-+
-+static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert)
-+{
-+ int val, active_low;
-+
-+ if (IS_ERR_OR_NULL(pcie->reset))
-+ return;
-+
-+ active_low = gpiod_is_active_low(pcie->reset);
-+
-+ if (assert)
-+ val = !!active_low;
-+ else
-+ val = !active_low;
-+
-+ gpiod_set_value(pcie->reset, val);
-+
-+ usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US);
-+}
-+
-+static void qcom_ep_reset_assert(struct qcom_pcie *pcie)
-+{
-+ qcom_ep_reset_assert_deassert(pcie, 1);
-+}
-+
-+static void qcom_ep_reset_deassert(struct qcom_pcie *pcie)
-+{
-+ qcom_ep_reset_assert_deassert(pcie, 0);
-+}
-+
-+static irqreturn_t qcom_pcie_msi_irq_handler(int irq, void *arg)
-+{
-+ struct pcie_port *pp = arg;
-+
-+ return dw_handle_msi_irq(pp);
-+}
-+
-+static int qcom_pcie_link_up(struct pcie_port *pp)
-+{
-+ struct qcom_pcie *pcie = to_qcom_pcie(pp);
-+ u32 val = readl(pcie->dbi + PCIE20_CAP_LINKCTRLSTATUS);
-+
-+ return val & BIT(29) ? 1 : 0;
-+}
-+
-+static void qcom_pcie_disable_resources_v0(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
-+
-+ reset_control_assert(res->pci_reset);
-+ reset_control_assert(res->axi_reset);
-+ reset_control_assert(res->ahb_reset);
-+ reset_control_assert(res->por_reset);
-+ reset_control_assert(res->pci_reset);
-+ clk_disable_unprepare(res->iface_clk);
-+ clk_disable_unprepare(res->core_clk);
-+ clk_disable_unprepare(res->phy_clk);
-+ regulator_disable(res->vdda);
-+ regulator_disable(res->vdda_phy);
-+ regulator_disable(res->vdda_refclk);
-+}
-+
-+static void qcom_pcie_disable_resources_v1(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
-+
-+ reset_control_assert(res->core);
-+ clk_disable_unprepare(res->slave_bus);
-+ clk_disable_unprepare(res->master_bus);
-+ clk_disable_unprepare(res->iface);
-+ clk_disable_unprepare(res->aux);
-+ regulator_disable(res->vdda);
-+}
-+
-+static int qcom_pcie_enable_resources_v0(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
-+ struct device *dev = pcie->dev;
-+ int ret;
-+
-+ ret = regulator_enable(res->vdda);
-+ if (ret) {
-+ dev_err(dev, "cannot enable vdda regulator\n");
-+ return ret;
-+ }
-+
-+ ret = regulator_enable(res->vdda_refclk);
-+ if (ret) {
-+ dev_err(dev, "cannot enable vdda_refclk regulator\n");
-+ goto err_refclk;
-+ }
-+
-+ ret = regulator_enable(res->vdda_phy);
-+ if (ret) {
-+ dev_err(dev, "cannot enable vdda_phy regulator\n");
-+ goto err_vdda_phy;
-+ }
-+
-+ ret = clk_prepare_enable(res->iface_clk);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable iface clock\n");
-+ goto err_iface;
-+ }
-+
-+ ret = clk_prepare_enable(res->core_clk);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable core clock\n");
-+ goto err_clk_core;
-+ }
-+
-+ ret = clk_prepare_enable(res->phy_clk);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable phy clock\n");
-+ goto err_clk_phy;
-+ }
-+
-+ ret = reset_control_deassert(res->ahb_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert ahb reset\n");
-+ goto err_reset_ahb;
-+ }
-+
-+ return 0;
-+
-+err_reset_ahb:
-+ clk_disable_unprepare(res->phy_clk);
-+err_clk_phy:
-+ clk_disable_unprepare(res->core_clk);
-+err_clk_core:
-+ clk_disable_unprepare(res->iface_clk);
-+err_iface:
-+ regulator_disable(res->vdda_phy);
-+err_vdda_phy:
-+ regulator_disable(res->vdda_refclk);
-+err_refclk:
-+ regulator_disable(res->vdda);
-+ return ret;
-+}
-+
-+static int qcom_pcie_enable_resources_v1(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
-+ struct device *dev = pcie->dev;
-+ int ret;
-+
-+ ret = reset_control_deassert(res->core);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert core reset\n");
-+ return ret;
-+ }
-+
-+ ret = clk_prepare_enable(res->aux);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable aux clock\n");
-+ goto err_res;
-+ }
-+
-+ ret = clk_prepare_enable(res->iface);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable iface clock\n");
-+ goto err_aux;
-+ }
-+
-+ ret = clk_prepare_enable(res->master_bus);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable master_bus clock\n");
-+ goto err_iface;
-+ }
-+
-+ ret = clk_prepare_enable(res->slave_bus);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable slave_bus clock\n");
-+ goto err_master;
-+ }
-+
-+ ret = regulator_enable(res->vdda);
-+ if (ret) {
-+ dev_err(dev, "cannot enable vdda regulator\n");
-+ goto err_slave;
-+ }
-+
-+ return 0;
-+
-+err_slave:
-+ clk_disable_unprepare(res->slave_bus);
-+err_master:
-+ clk_disable_unprepare(res->master_bus);
-+err_iface:
-+ clk_disable_unprepare(res->iface);
-+err_aux:
-+ clk_disable_unprepare(res->aux);
-+err_res:
-+ reset_control_assert(res->core);
-+
-+ return ret;
-+}
-+
-+static int qcom_pcie_get_resources_v0(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
-+ struct device *dev = pcie->dev;
-+
-+ res->vdda = devm_regulator_get(dev, "vdda");
-+ if (IS_ERR(res->vdda))
-+ return PTR_ERR(res->vdda);
-+
-+ res->vdda_phy = devm_regulator_get(dev, "vdda_phy");
-+ if (IS_ERR(res->vdda_phy))
-+ return PTR_ERR(res->vdda_phy);
-+
-+ res->vdda_refclk = devm_regulator_get(dev, "vdda_refclk");
-+ if (IS_ERR(res->vdda_refclk))
-+ return PTR_ERR(res->vdda_refclk);
-+
-+ res->iface_clk = devm_clk_get(dev, "iface");
-+ if (IS_ERR(res->iface_clk))
-+ return PTR_ERR(res->iface_clk);
-+
-+ res->core_clk = devm_clk_get(dev, "core");
-+ if (IS_ERR(res->core_clk))
-+ return PTR_ERR(res->core_clk);
-+
-+ res->phy_clk = devm_clk_get(dev, "phy");
-+ if (IS_ERR(res->phy_clk))
-+ return PTR_ERR(res->phy_clk);
-+
-+ res->pci_reset = devm_reset_control_get(dev, "pci");
-+ if (IS_ERR(res->pci_reset))
-+ return PTR_ERR(res->pci_reset);
-+
-+ res->axi_reset = devm_reset_control_get(dev, "axi");
-+ if (IS_ERR(res->axi_reset))
-+ return PTR_ERR(res->axi_reset);
-+
-+ res->ahb_reset = devm_reset_control_get(dev, "ahb");
-+ if (IS_ERR(res->ahb_reset))
-+ return PTR_ERR(res->ahb_reset);
-+
-+ res->por_reset = devm_reset_control_get(dev, "por");
-+ if (IS_ERR(res->por_reset))
-+ return PTR_ERR(res->por_reset);
-+
-+ res->phy_reset = devm_reset_control_get(dev, "phy");
-+ if (IS_ERR(res->phy_reset))
-+ return PTR_ERR(res->phy_reset);
-+
-+ return 0;
-+}
-+
-+static int qcom_pcie_get_resources_v1(struct qcom_pcie *pcie)
-+{
-+ struct qcom_pcie_resources_v1 *res = &pcie->res.v1;
-+ struct device *dev = pcie->dev;
-+
-+ res->vdda = devm_regulator_get(dev, "vdda");
-+ if (IS_ERR(res->vdda))
-+ return PTR_ERR(res->vdda);
-+
-+ res->iface = devm_clk_get(dev, "iface");
-+ if (IS_ERR(res->iface))
-+ return PTR_ERR(res->iface);
-+
-+ res->aux = devm_clk_get(dev, "aux");
-+ if (IS_ERR(res->aux) && PTR_ERR(res->aux) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+ else if (IS_ERR(res->aux))
-+ res->aux = NULL;
-+
-+ res->master_bus = devm_clk_get(dev, "master_bus");
-+ if (IS_ERR(res->master_bus))
-+ return PTR_ERR(res->master_bus);
-+
-+ res->slave_bus = devm_clk_get(dev, "slave_bus");
-+ if (IS_ERR(res->slave_bus))
-+ return PTR_ERR(res->slave_bus);
-+
-+ res->core = devm_reset_control_get(dev, "core");
-+ if (IS_ERR(res->core))
-+ return PTR_ERR(res->core);
-+
-+ return 0;
-+}
-+
-+static int qcom_pcie_enable_link_training(struct pcie_port *pp)
-+{
-+ struct qcom_pcie *pcie = to_qcom_pcie(pp);
-+ struct device *dev = pp->dev;
-+ int retries;
-+ u32 val;
-+
-+ /* enable link training */
-+ writel_masked(pcie->elbi + PCIE20_ELBI_SYS_CTRL, 0, BIT(0));
-+
-+ /* wait for up to 100ms for the link to come up */
-+ retries = LINKUP_RETRIES_COUNT;
-+ do {
-+ val = readl(pcie->elbi + PCIE20_ELBI_SYS_STTS);
-+ if (val & XMLH_LINK_UP)
-+ break;
-+ usleep_range(LINKUP_DELAY_MIN_US, LINKUP_DELAY_MAX_US);
-+ } while (retries--);
-+
-+ if (retries < 0 || !dw_pcie_link_up(pp)) {
-+ dev_err(dev, "link initialization failed\n");
-+ return -ENXIO;
-+ }
-+
-+ return 0;
-+}
-+
-+static void qcom_pcie_host_init_v1(struct pcie_port *pp)
-+{
-+ struct qcom_pcie *pcie = to_qcom_pcie(pp);
-+ int ret;
-+
-+ qcom_ep_reset_assert(pcie);
-+
-+ ret = qcom_pcie_enable_resources_v1(pcie);
-+ if (ret)
-+ return;
-+
-+ /* change DBI base address */
-+ writel(0, pcie->parf + PCIE20_PARF_DBI_BASE_ADDR);
-+
-+ if (IS_ENABLED(CONFIG_PCI_MSI))
-+ writel_masked(pcie->parf + PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT,
-+ 0, BIT(31));
-+
-+ ret = phy_init(pcie->phy);
-+ if (ret)
-+ goto err_res;
-+
-+ ret = phy_power_on(pcie->phy);
-+ if (ret)
-+ goto err_phy;
-+
-+ dw_pcie_setup_rc(pp);
-+
-+ if (IS_ENABLED(CONFIG_PCI_MSI))
-+ dw_pcie_msi_init(pp);
-+
-+ qcom_ep_reset_deassert(pcie);
-+
-+ ret = qcom_pcie_enable_link_training(pp);
-+ if (ret)
-+ goto err;
-+
-+ return;
-+
-+err:
-+ qcom_ep_reset_assert(pcie);
-+ phy_power_off(pcie->phy);
-+err_phy:
-+ phy_exit(pcie->phy);
-+err_res:
-+ qcom_pcie_disable_resources_v1(pcie);
-+}
-+
-+static void qcom_pcie_host_init_v0(struct pcie_port *pp)
-+{
-+ struct qcom_pcie *pcie = to_qcom_pcie(pp);
-+ struct qcom_pcie_resources_v0 *res = &pcie->res.v0;
-+ struct device *dev = pcie->dev;
-+ int ret;
-+
-+ qcom_ep_reset_assert(pcie);
-+
-+ ret = qcom_pcie_enable_resources_v0(pcie);
-+ if (ret)
-+ return;
-+
-+ writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
-+
-+ /* enable external reference clock */
-+ writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
-+
-+ ret = reset_control_deassert(res->phy_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert phy reset\n");
-+ return;
-+ }
-+
-+ ret = reset_control_deassert(res->pci_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert pci reset\n");
-+ return;
-+ }
-+
-+ ret = reset_control_deassert(res->por_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert por reset\n");
-+ return;
-+ }
-+
-+ ret = reset_control_deassert(res->axi_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot deassert axi reset\n");
-+ return;
-+ }
-+
-+ /* wait 150ms for clock acquisition */
-+ usleep_range(10000, 15000);
-+
-+ dw_pcie_setup_rc(pp);
-+
-+ if (IS_ENABLED(CONFIG_PCI_MSI))
-+ dw_pcie_msi_init(pp);
-+
-+ qcom_ep_reset_deassert(pcie);
-+
-+ ret = qcom_pcie_enable_link_training(pp);
-+ if (ret)
-+ goto err;
-+
-+ return;
-+err:
-+ qcom_ep_reset_assert(pcie);
-+ qcom_pcie_disable_resources_v0(pcie);
-+}
-+
-+static void qcom_pcie_host_init(struct pcie_port *pp)
-+{
-+ struct qcom_pcie *pcie = to_qcom_pcie(pp);
-+
-+ if (pcie->version == PCIE_V0)
-+ return qcom_pcie_host_init_v0(pp);
-+ else
-+ return qcom_pcie_host_init_v1(pp);
-+}
-+
-+static int
-+qcom_pcie_rd_own_conf(struct pcie_port *pp, int where, int size, u32 *val)
-+{
-+ /* the device class is not reported correctly from the register */
-+ if (where == PCI_CLASS_REVISION && size == 4) {
-+ *val = readl(pp->dbi_base + PCI_CLASS_REVISION);
-+ *val &= ~(0xffff << 16);
-+ *val |= PCI_CLASS_BRIDGE_PCI << 16;
-+ return PCIBIOS_SUCCESSFUL;
-+ }
-+
-+ return dw_pcie_cfg_read(pp->dbi_base + (where & ~0x3), where,
-+ size, val);
-+}
-+
-+static struct pcie_host_ops qcom_pcie_ops = {
-+ .link_up = qcom_pcie_link_up,
-+ .host_init = qcom_pcie_host_init,
-+ .rd_own_conf = qcom_pcie_rd_own_conf,
-+};
-+
-+static const struct of_device_id qcom_pcie_match[] = {
-+ { .compatible = "qcom,pcie-v0", .data = (void *)PCIE_V0 },
-+ { .compatible = "qcom,pcie-v1", .data = (void *)PCIE_V1 },
-+ { }
-+};
-+
-+static int qcom_pcie_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ const struct of_device_id *match;
-+ struct resource *res;
-+ struct qcom_pcie *pcie;
-+ struct pcie_port *pp;
-+ int ret;
-+
-+ match = of_match_node(qcom_pcie_match, dev->of_node);
-+ if (!match)
-+ return -ENXIO;
-+
-+ pcie = devm_kzalloc(dev, sizeof(*pcie), GFP_KERNEL);
-+ if (!pcie)
-+ return -ENOMEM;
-+
-+ pcie->version = (unsigned int)match->data;
-+
-+ pcie->reset = devm_gpiod_get_optional(dev, "perst");
-+ if (IS_ERR(pcie->reset) && PTR_ERR(pcie->reset) == -EPROBE_DEFER)
-+ return PTR_ERR(pcie->reset);
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "parf");
-+ pcie->parf = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pcie->parf))
-+ return PTR_ERR(pcie->parf);
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dbi");
-+ pcie->dbi = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pcie->dbi))
-+ return PTR_ERR(pcie->dbi);
-+
-+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "elbi");
-+ pcie->elbi = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(pcie->elbi))
-+ return PTR_ERR(pcie->elbi);
-+
-+ pcie->phy = devm_phy_optional_get(dev, "pciephy");
-+ if (IS_ERR(pcie->phy))
-+ return PTR_ERR(pcie->phy);
-+
-+ pcie->dev = dev;
-+
-+ if (pcie->version == PCIE_V0)
-+ ret = qcom_pcie_get_resources_v0(pcie);
-+ else
-+ ret = qcom_pcie_get_resources_v1(pcie);
-+
-+ if (ret)
-+ return ret;
-+
-+ pp = &pcie->pp;
-+ pp->dev = dev;
-+ pp->dbi_base = pcie->dbi;
-+ pp->root_bus_nr = -1;
-+ pp->ops = &qcom_pcie_ops;
-+
-+ if (IS_ENABLED(CONFIG_PCI_MSI)) {
-+ pp->msi_irq = platform_get_irq_byname(pdev, "msi");
-+ if (pp->msi_irq < 0) {
-+ dev_err(dev, "cannot get msi irq\n");
-+ return pp->msi_irq;
-+ }
-+
-+ ret = devm_request_irq(dev, pp->msi_irq,
-+ qcom_pcie_msi_irq_handler,
-+ IRQF_SHARED, "qcom-pcie-msi", pp);
-+ if (ret) {
-+ dev_err(dev, "cannot request msi irq\n");
-+ return ret;
-+ }
-+ }
-+
-+ ret = dw_pcie_host_init(pp);
-+ if (ret) {
-+ dev_err(dev, "cannot initialize host\n");
-+ return ret;
-+ }
-+
-+ platform_set_drvdata(pdev, pcie);
-+
-+ return 0;
-+}
-+
-+static int qcom_pcie_remove(struct platform_device *pdev)
-+{
-+ struct qcom_pcie *pcie = platform_get_drvdata(pdev);
-+
-+ qcom_ep_reset_assert(pcie);
-+ phy_power_off(pcie->phy);
-+ phy_exit(pcie->phy);
-+ if (pcie->version == PCIE_V0)
-+ qcom_pcie_disable_resources_v0(pcie);
-+ else
-+ qcom_pcie_disable_resources_v1(pcie);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver qcom_pcie_driver = {
-+ .probe = qcom_pcie_probe,
-+ .remove = qcom_pcie_remove,
-+ .driver = {
-+ .name = "qcom-pcie",
-+ .of_match_table = qcom_pcie_match,
-+ },
-+};
-+
-+module_platform_driver(qcom_pcie_driver);
-+
-+MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
-+MODULE_DESCRIPTION("Qualcomm PCIe root complex driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:qcom-pcie");
---- a/drivers/pci/host/Makefile
-+++ b/drivers/pci/host/Makefile
-@@ -15,3 +15,4 @@ obj-$(CONFIG_PCI_LAYERSCAPE) += pci-laye
- obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
- obj-$(CONFIG_PCIE_IPROC) += pcie-iproc.o
- obj-$(CONFIG_PCIE_IPROC_PLATFORM) += pcie-iproc-platform.o
-+obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
diff --git a/target/linux/ipq806x/patches-4.1/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch b/target/linux/ipq806x/patches-4.1/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch
deleted file mode 100644
index 6ccb7d8080..0000000000
--- a/target/linux/ipq806x/patches-4.1/112-ARM-dts-qcom-add-pcie-nodes-to-ipq806x-platforms.patch
+++ /dev/null
@@ -1,244 +0,0 @@
-From 5b40516b2f5fb9b2a7d6d3e2e924f12ec9d183a8 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Tue, 21 Apr 2015 19:01:42 -0700
-Subject: [PATCH 8/9] ARM: dts: qcom: add pcie nodes to ipq806x platforms
-
-qcom-pcie driver now supports version 0 of the controller. This change
-adds the corresponding entries to the IPQ806x dtsi file and
-corresponding platform (AP148).
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 30 ++++++++
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 124 +++++++++++++++++++++++++++++++
- 2 files changed, 154 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -91,5 +91,15 @@
- sata@29000000 {
- status = "ok";
- };
-+
-+ pcie0: pci@1b500000 {
-+ status = "ok";
-+ phy-tx0-term-offset = <7>;
-+ };
-+
-+ pcie1: pci@1b700000 {
-+ status = "ok";
-+ phy-tx0-term-offset = <7>;
-+ };
- };
- };
---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-@@ -128,5 +128,17 @@
- usb30@1 {
- status = "ok";
- };
-+
-+ pcie0: pci@1b500000 {
-+ status = "ok";
-+ };
-+
-+ pcie1: pci@1b700000 {
-+ status = "ok";
-+ };
-+
-+ pcie2: pci@1b900000 {
-+ status = "ok";
-+ };
- };
- };
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -4,6 +4,9 @@
- #include <dt-bindings/clock/qcom,gcc-ipq806x.h>
- #include <dt-bindings/clock/qcom,lcc-ipq806x.h>
- #include <dt-bindings/soc/qcom,gsbi.h>
-+#include <dt-bindings/reset/qcom,gcc-ipq806x.h>
-+#include <dt-bindings/interrupt-controller/arm-gic.h>
-+#include <dt-bindings/gpio/gpio.h>
-
- / {
- model = "Qualcomm IPQ8064";
-@@ -99,6 +102,33 @@
- interrupt-controller;
- #interrupt-cells = <2>;
- interrupts = <0 16 0x4>;
-+
-+ pcie0_pins: pcie0_pinmux {
-+ mux {
-+ pins = "gpio3";
-+ function = "pcie1_rst";
-+ drive-strength = <12>;
-+ bias-disable;
-+ };
-+ };
-+
-+ pcie1_pins: pcie1_pinmux {
-+ mux {
-+ pins = "gpio48";
-+ function = "pcie2_rst";
-+ drive-strength = <12>;
-+ bias-disable;
-+ };
-+ };
-+
-+ pcie2_pins: pcie2_pinmux {
-+ mux {
-+ pins = "gpio63";
-+ function = "pcie3_rst";
-+ drive-strength = <12>;
-+ bias-disable;
-+ };
-+ };
- };
-
- intc: interrupt-controller@2000000 {
-@@ -333,6 +363,144 @@
- compatible = "syscon";
- reg = <0x01200600 0x100>;
- };
-+
-+ pcie0: pci@1b500000 {
-+ compatible = "qcom,pcie-v0";
-+ reg = <0x1b500000 0x1000
-+ 0x1b502000 0x80
-+ 0x1b600000 0x100
-+ 0x0ff00000 0x100000>;
-+ reg-names = "dbi", "elbi", "parf", "config";
-+ device_type = "pci";
-+ linux,pci-domain = <0>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+
-+ ranges = <0x81000000 0 0x0fe00000 0x0fe00000 0 0x00100000 /* downstream I/O */
-+ 0x82000000 0 0x08000000 0x08000000 0 0x07e00000>; /* non-prefetchable memory */
-+
-+ interrupts = <GIC_SPI 35 IRQ_TYPE_NONE>;
-+ interrupt-names = "msi";
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 36 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-+ <0 0 0 2 &intc 0 37 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-+ <0 0 0 3 &intc 0 38 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-+ <0 0 0 4 &intc 0 39 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
-+
-+ clocks = <&gcc PCIE_A_CLK>,
-+ <&gcc PCIE_H_CLK>,
-+ <&gcc PCIE_PHY_CLK>;
-+ clock-names = "core", "iface", "phy";
-+
-+ resets = <&gcc PCIE_ACLK_RESET>,
-+ <&gcc PCIE_HCLK_RESET>,
-+ <&gcc PCIE_POR_RESET>,
-+ <&gcc PCIE_PCI_RESET>,
-+ <&gcc PCIE_PHY_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy";
-+
-+ pinctrl-0 = <&pcie0_pins>;
-+ pinctrl-names = "default";
-+
-+ perst-gpio = <&qcom_pinmux 3 GPIO_ACTIVE_LOW>;
-+
-+ status = "disabled";
-+ };
-+
-+ pcie1: pci@1b700000 {
-+ compatible = "qcom,pcie-v0";
-+ reg = <0x1b700000 0x1000
-+ 0x1b702000 0x80
-+ 0x1b800000 0x100
-+ 0x31f00000 0x100000>;
-+ reg-names = "dbi", "elbi", "parf", "config";
-+ device_type = "pci";
-+ linux,pci-domain = <1>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+
-+ ranges = <0x81000000 0 0x31e00000 0x31e00000 0 0x00100000 /* downstream I/O */
-+ 0x82000000 0 0x2e000000 0x2e000000 0 0x03e00000>; /* non-prefetchable memory */
-+
-+ interrupts = <GIC_SPI 57 IRQ_TYPE_NONE>;
-+ interrupt-names = "msi";
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 58 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-+ <0 0 0 2 &intc 0 59 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-+ <0 0 0 3 &intc 0 60 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-+ <0 0 0 4 &intc 0 61 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
-+
-+ clocks = <&gcc PCIE_1_A_CLK>,
-+ <&gcc PCIE_1_H_CLK>,
-+ <&gcc PCIE_1_PHY_CLK>;
-+ clock-names = "core", "iface", "phy";
-+
-+ resets = <&gcc PCIE_1_ACLK_RESET>,
-+ <&gcc PCIE_1_HCLK_RESET>,
-+ <&gcc PCIE_1_POR_RESET>,
-+ <&gcc PCIE_1_PCI_RESET>,
-+ <&gcc PCIE_1_PHY_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy";
-+
-+ pinctrl-0 = <&pcie1_pins>;
-+ pinctrl-names = "default";
-+
-+ perst-gpio = <&qcom_pinmux 48 GPIO_ACTIVE_LOW>;
-+
-+ status = "disabled";
-+ };
-+
-+ pcie2: pci@1b900000 {
-+ compatible = "qcom,pcie-v0";
-+ reg = <0x1b900000 0x1000
-+ 0x1b902000 0x80
-+ 0x1ba00000 0x100
-+ 0x35f00000 0x100000>;
-+ reg-names = "dbi", "elbi", "parf", "config";
-+ device_type = "pci";
-+ linux,pci-domain = <2>;
-+ bus-range = <0x00 0xff>;
-+ num-lanes = <1>;
-+ #address-cells = <3>;
-+ #size-cells = <2>;
-+
-+ ranges = <0x81000000 0 0x35e00000 0x35e00000 0 0x00100000 /* downstream I/O */
-+ 0x82000000 0 0x32000000 0x32000000 0 0x03e00000>; /* non-prefetchable memory */
-+
-+ interrupts = <GIC_SPI 71 IRQ_TYPE_NONE>;
-+ interrupt-names = "msi";
-+ #interrupt-cells = <1>;
-+ interrupt-map-mask = <0 0 0 0x7>;
-+ interrupt-map = <0 0 0 1 &intc 0 72 IRQ_TYPE_LEVEL_HIGH>, /* int_a */
-+ <0 0 0 2 &intc 0 73 IRQ_TYPE_LEVEL_HIGH>, /* int_b */
-+ <0 0 0 3 &intc 0 74 IRQ_TYPE_LEVEL_HIGH>, /* int_c */
-+ <0 0 0 4 &intc 0 75 IRQ_TYPE_LEVEL_HIGH>; /* int_d */
-+
-+ clocks = <&gcc PCIE_2_A_CLK>,
-+ <&gcc PCIE_2_H_CLK>,
-+ <&gcc PCIE_2_PHY_CLK>;
-+ clock-names = "core", "iface", "phy";
-+
-+ resets = <&gcc PCIE_2_ACLK_RESET>,
-+ <&gcc PCIE_2_HCLK_RESET>,
-+ <&gcc PCIE_2_POR_RESET>,
-+ <&gcc PCIE_2_PCI_RESET>,
-+ <&gcc PCIE_2_PHY_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy";
-+
-+ pinctrl-0 = <&pcie2_pins>;
-+ pinctrl-names = "default";
-+
-+ perst-gpio = <&qcom_pinmux 63 GPIO_ACTIVE_LOW>;
-+
-+ status = "disabled";
-+ };
- };
-
- sfpb_mutex: sfpb-mutex {
diff --git a/target/linux/ipq806x/patches-4.1/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch b/target/linux/ipq806x/patches-4.1/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch
deleted file mode 100644
index e2d31354ed..0000000000
--- a/target/linux/ipq806x/patches-4.1/113-ARM-qcom-automatically-select-PCI_DOMAINS-if-PCI-is-.patch
+++ /dev/null
@@ -1,29 +0,0 @@
-From f004aa1dec6e2e206be025de15b115d60f2b21e3 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Tue, 21 Apr 2015 19:09:07 -0700
-Subject: [PATCH 9/9] ARM: qcom: automatically select PCI_DOMAINS if PCI is
- enabled
-
-If multiple PCIe devices are present in the system, the kernel will
-panic at boot time when trying to scan the PCI buses. This happens on
-IPQ806x based platforms, which has 3 PCIe ports.
-
-Enabling this option allows the kernel to assign the pci-domains
-according to the device-tree content. This allows multiple PCIe
-controllers to coexist in the system.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/mach-qcom/Kconfig | 1 +
- 1 file changed, 1 insertion(+)
-
---- a/arch/arm/mach-qcom/Kconfig
-+++ b/arch/arm/mach-qcom/Kconfig
-@@ -5,6 +5,7 @@ menuconfig ARCH_QCOM
- select ARM_AMBA
- select PINCTRL
- select QCOM_SCM if SMP
-+ select PCI_DOMAINS if PCI
- help
- Support for Qualcomm's devicetree based systems.
-
diff --git a/target/linux/ipq806x/patches-4.1/114-pcie-add-ctlr-init.patch b/target/linux/ipq806x/patches-4.1/114-pcie-add-ctlr-init.patch
deleted file mode 100644
index c00abca753..0000000000
--- a/target/linux/ipq806x/patches-4.1/114-pcie-add-ctlr-init.patch
+++ /dev/null
@@ -1,311 +0,0 @@
---- a/drivers/pci/host/pcie-qcom.c
-+++ b/drivers/pci/host/pcie-qcom.c
-@@ -29,8 +29,53 @@
-
- #include "pcie-designware.h"
-
-+/* DBI registers */
-+#define PCIE20_CAP 0x70
-+#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
-+
-+#define PCIE20_AXI_MSTR_RESP_COMP_CTRL0 0x818
-+#define PCIE20_AXI_MSTR_RESP_COMP_CTRL1 0x81c
-+
-+#define PCIE20_PLR_IATU_VIEWPORT 0x900
-+#define PCIE20_PLR_IATU_REGION_OUTBOUND (0x0 << 31)
-+#define PCIE20_PLR_IATU_REGION_INDEX(x) (x << 0)
-+
-+#define PCIE20_PLR_IATU_CTRL1 0x904
-+#define PCIE20_PLR_IATU_TYPE_CFG0 (0x4 << 0)
-+#define PCIE20_PLR_IATU_TYPE_MEM (0x0 << 0)
-+
-+#define PCIE20_PLR_IATU_CTRL2 0x908
-+#define PCIE20_PLR_IATU_ENABLE BIT(31)
-+
-+#define PCIE20_PLR_IATU_LBAR 0x90C
-+#define PCIE20_PLR_IATU_UBAR 0x910
-+#define PCIE20_PLR_IATU_LAR 0x914
-+#define PCIE20_PLR_IATU_LTAR 0x918
-+#define PCIE20_PLR_IATU_UTAR 0x91c
-+
-+#define MSM_PCIE_DEV_CFG_ADDR 0x01000000
-+
-+/* PARF registers */
-+#define PCIE20_PARF_PCS_DEEMPH 0x34
-+#define PCS_DEEMPH_TX_DEEMPH_GEN1(x) (x << 16)
-+#define PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(x) (x << 8)
-+#define PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(x) (x << 0)
-+
-+#define PCIE20_PARF_PCS_SWING 0x38
-+#define PCS_SWING_TX_SWING_FULL(x) (x << 8)
-+#define PCS_SWING_TX_SWING_LOW(x) (x << 0)
-+
- #define PCIE20_PARF_PHY_CTRL 0x40
-+#define PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK (0x1f << 16)
-+#define PHY_CTRL_PHY_TX0_TERM_OFFSET(x) (x << 16)
-+
- #define PCIE20_PARF_PHY_REFCLK 0x4C
-+#define REF_SSP_EN BIT(16)
-+#define REF_USE_PAD BIT(12)
-+
-+#define PCIE20_PARF_CONFIG_BITS 0x50
-+#define PHY_RX0_EQ(x) (x << 24)
-+
- #define PCIE20_PARF_DBI_BASE_ADDR 0x168
- #define PCIE20_PARF_SLV_ADDR_SPACE_SIZE 0x16c
- #define PCIE20_PARF_AXI_MSTR_WR_ADDR_HALT 0x178
-@@ -39,9 +84,6 @@
- #define PCIE20_ELBI_SYS_STTS 0x08
- #define XMLH_LINK_UP BIT(10)
-
--#define PCIE20_CAP 0x70
--#define PCIE20_CAP_LINKCTRLSTATUS (PCIE20_CAP + 0x10)
--
- #define PERST_DELAY_MIN_US 1000
- #define PERST_DELAY_MAX_US 1005
-
-@@ -56,14 +98,18 @@ struct qcom_pcie_resources_v0 {
- struct clk *iface_clk;
- struct clk *core_clk;
- struct clk *phy_clk;
-+ struct clk *aux_clk;
-+ struct clk *ref_clk;
- struct reset_control *pci_reset;
- struct reset_control *axi_reset;
- struct reset_control *ahb_reset;
- struct reset_control *por_reset;
- struct reset_control *phy_reset;
-+ struct reset_control *ext_reset;
- struct regulator *vdda;
- struct regulator *vdda_phy;
- struct regulator *vdda_refclk;
-+ uint8_t phy_tx0_term_offset;
- };
-
- struct qcom_pcie_resources_v1 {
-@@ -106,20 +152,10 @@ writel_masked(void __iomem *addr, u32 cl
-
- static void qcom_ep_reset_assert_deassert(struct qcom_pcie *pcie, int assert)
- {
-- int val, active_low;
--
- if (IS_ERR_OR_NULL(pcie->reset))
- return;
-
-- active_low = gpiod_is_active_low(pcie->reset);
--
-- if (assert)
-- val = !!active_low;
-- else
-- val = !active_low;
--
-- gpiod_set_value(pcie->reset, val);
--
-+ gpiod_set_value(pcie->reset, assert);
- usleep_range(PERST_DELAY_MIN_US, PERST_DELAY_MAX_US);
- }
-
-@@ -156,10 +192,13 @@ static void qcom_pcie_disable_resources_
- reset_control_assert(res->axi_reset);
- reset_control_assert(res->ahb_reset);
- reset_control_assert(res->por_reset);
-- reset_control_assert(res->pci_reset);
-+ reset_control_assert(res->phy_reset);
-+ reset_control_assert(res->ext_reset);
- clk_disable_unprepare(res->iface_clk);
- clk_disable_unprepare(res->core_clk);
- clk_disable_unprepare(res->phy_clk);
-+ clk_disable_unprepare(res->aux_clk);
-+ clk_disable_unprepare(res->ref_clk);
- regulator_disable(res->vdda);
- regulator_disable(res->vdda_phy);
- regulator_disable(res->vdda_refclk);
-@@ -201,6 +240,12 @@ static int qcom_pcie_enable_resources_v0
- goto err_vdda_phy;
- }
-
-+ ret = reset_control_deassert(res->ext_reset);
-+ if (ret) {
-+ dev_err(dev, "cannot assert ext reset\n");
-+ goto err_reset_ext;
-+ }
-+
- ret = clk_prepare_enable(res->iface_clk);
- if (ret) {
- dev_err(dev, "cannot prepare/enable iface clock\n");
-@@ -219,21 +264,40 @@ static int qcom_pcie_enable_resources_v0
- goto err_clk_phy;
- }
-
-+ ret = clk_prepare_enable(res->aux_clk);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable aux clock\n");
-+ goto err_clk_aux;
-+ }
-+
-+ ret = clk_prepare_enable(res->ref_clk);
-+ if (ret) {
-+ dev_err(dev, "cannot prepare/enable ref clock\n");
-+ goto err_clk_ref;
-+ }
-+
- ret = reset_control_deassert(res->ahb_reset);
- if (ret) {
- dev_err(dev, "cannot deassert ahb reset\n");
- goto err_reset_ahb;
- }
-+ udelay(1);
-
- return 0;
-
- err_reset_ahb:
-+ clk_disable_unprepare(res->ref_clk);
-+err_clk_ref:
-+ clk_disable_unprepare(res->aux_clk);
-+err_clk_aux:
- clk_disable_unprepare(res->phy_clk);
- err_clk_phy:
- clk_disable_unprepare(res->core_clk);
- err_clk_core:
- clk_disable_unprepare(res->iface_clk);
- err_iface:
-+ reset_control_assert(res->ext_reset);
-+err_reset_ext:
- regulator_disable(res->vdda_phy);
- err_vdda_phy:
- regulator_disable(res->vdda_refclk);
-@@ -329,6 +393,14 @@ static int qcom_pcie_get_resources_v0(st
- if (IS_ERR(res->phy_clk))
- return PTR_ERR(res->phy_clk);
-
-+ res->aux_clk = devm_clk_get(dev, "aux");
-+ if (IS_ERR(res->aux_clk))
-+ return PTR_ERR(res->aux_clk);
-+
-+ res->ref_clk = devm_clk_get(dev, "ref");
-+ if (IS_ERR(res->ref_clk))
-+ return PTR_ERR(res->ref_clk);
-+
- res->pci_reset = devm_reset_control_get(dev, "pci");
- if (IS_ERR(res->pci_reset))
- return PTR_ERR(res->pci_reset);
-@@ -349,6 +421,14 @@ static int qcom_pcie_get_resources_v0(st
- if (IS_ERR(res->phy_reset))
- return PTR_ERR(res->phy_reset);
-
-+ res->ext_reset = devm_reset_control_get(dev, "ext");
-+ if (IS_ERR(res->ext_reset))
-+ return PTR_ERR(res->ext_reset);
-+
-+ if (of_property_read_u8(dev->of_node, "phy-tx0-term-offset",
-+ &res->phy_tx0_term_offset))
-+ res->phy_tx0_term_offset = 0;
-+
- return 0;
- }
-
-@@ -461,6 +541,57 @@ err_res:
- qcom_pcie_disable_resources_v1(pcie);
- }
-
-+static void qcom_pcie_prog_viewport_cfg0(struct qcom_pcie *pcie, u32 busdev)
-+{
-+ struct pcie_port *pp = &pcie->pp;
-+
-+ /*
-+ * program and enable address translation region 0 (device config
-+ * address space); region type config;
-+ * axi config address range to device config address range
-+ */
-+ writel(PCIE20_PLR_IATU_REGION_OUTBOUND |
-+ PCIE20_PLR_IATU_REGION_INDEX(0),
-+ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT);
-+
-+ writel(PCIE20_PLR_IATU_TYPE_CFG0, pcie->dbi + PCIE20_PLR_IATU_CTRL1);
-+ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2);
-+ writel(pp->cfg0_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR);
-+ writel((pp->cfg0_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR);
-+ writel((pp->cfg0_mod_base + pp->cfg0_size - 1),
-+ pcie->dbi + PCIE20_PLR_IATU_LAR);
-+ writel(busdev, pcie->dbi + PCIE20_PLR_IATU_LTAR);
-+ writel(0, pcie->dbi + PCIE20_PLR_IATU_UTAR);
-+}
-+
-+static void qcom_pcie_prog_viewport_mem2_outbound(struct qcom_pcie *pcie)
-+{
-+ struct pcie_port *pp = &pcie->pp;
-+
-+ /*
-+ * program and enable address translation region 2 (device resource
-+ * address space); region type memory;
-+ * axi device bar address range to device bar address range
-+ */
-+ writel(PCIE20_PLR_IATU_REGION_OUTBOUND |
-+ PCIE20_PLR_IATU_REGION_INDEX(2),
-+ pcie->dbi + PCIE20_PLR_IATU_VIEWPORT);
-+
-+ writel(PCIE20_PLR_IATU_TYPE_MEM, pcie->dbi + PCIE20_PLR_IATU_CTRL1);
-+ writel(PCIE20_PLR_IATU_ENABLE, pcie->dbi + PCIE20_PLR_IATU_CTRL2);
-+ writel(pp->mem_mod_base, pcie->dbi + PCIE20_PLR_IATU_LBAR);
-+ writel((pp->mem_mod_base >> 32), pcie->dbi + PCIE20_PLR_IATU_UBAR);
-+ writel(pp->mem_mod_base + pp->mem_size - 1,
-+ pcie->dbi + PCIE20_PLR_IATU_LAR);
-+ writel(pp->mem_bus_addr, pcie->dbi + PCIE20_PLR_IATU_LTAR);
-+ writel(upper_32_bits(pp->mem_bus_addr),
-+ pcie->dbi + PCIE20_PLR_IATU_UTAR);
-+
-+ /* 256B PCIE buffer setting */
-+ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL0);
-+ writel(0x1, pcie->dbi + PCIE20_AXI_MSTR_RESP_COMP_CTRL1);
-+}
-+
- static void qcom_pcie_host_init_v0(struct pcie_port *pp)
- {
- struct qcom_pcie *pcie = to_qcom_pcie(pp);
-@@ -470,15 +601,34 @@ static void qcom_pcie_host_init_v0(struc
-
- qcom_ep_reset_assert(pcie);
-
-+ reset_control_assert(res->ahb_reset);
-+
- ret = qcom_pcie_enable_resources_v0(pcie);
- if (ret)
- return;
-
- writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL, BIT(0), 0);
-
-- /* enable external reference clock */
-- writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK, 0, BIT(16));
-+ /* Set Tx termination offset */
-+ writel_masked(pcie->parf + PCIE20_PARF_PHY_CTRL,
-+ PHY_CTRL_PHY_TX0_TERM_OFFSET_MASK,
-+ PHY_CTRL_PHY_TX0_TERM_OFFSET(res->phy_tx0_term_offset));
-+
-+ /* PARF programming */
-+ writel(PCS_DEEMPH_TX_DEEMPH_GEN1(0x18) |
-+ PCS_DEEMPH_TX_DEEMPH_GEN2_3_5DB(0x18) |
-+ PCS_DEEMPH_TX_DEEMPH_GEN2_6DB(0x22),
-+ pcie->parf + PCIE20_PARF_PCS_DEEMPH);
-+ writel(PCS_SWING_TX_SWING_FULL(0x78) |
-+ PCS_SWING_TX_SWING_LOW(0x78),
-+ pcie->parf + PCIE20_PARF_PCS_SWING);
-+ writel(PHY_RX0_EQ(0x4), pcie->parf + PCIE20_PARF_CONFIG_BITS);
-+
-+ /* Enable reference clock */
-+ writel_masked(pcie->parf + PCIE20_PARF_PHY_REFCLK,
-+ REF_USE_PAD, REF_SSP_EN);
-
-+ /* De-assert PHY, PCIe, POR and AXI resets */
- ret = reset_control_deassert(res->phy_reset);
- if (ret) {
- dev_err(dev, "cannot deassert phy reset\n");
-@@ -517,6 +667,9 @@ static void qcom_pcie_host_init_v0(struc
- if (ret)
- goto err;
-
-+ qcom_pcie_prog_viewport_cfg0(pcie, MSM_PCIE_DEV_CFG_ADDR);
-+ qcom_pcie_prog_viewport_mem2_outbound(pcie);
-+
- return;
- err:
- qcom_ep_reset_assert(pcie);
diff --git a/target/linux/ipq806x/patches-4.1/115-add-pcie-aux-clk-dts.patch b/target/linux/ipq806x/patches-4.1/115-add-pcie-aux-clk-dts.patch
deleted file mode 100644
index a99857e314..0000000000
--- a/target/linux/ipq806x/patches-4.1/115-add-pcie-aux-clk-dts.patch
+++ /dev/null
@@ -1,80 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -392,15 +392,21 @@
-
- clocks = <&gcc PCIE_A_CLK>,
- <&gcc PCIE_H_CLK>,
-- <&gcc PCIE_PHY_CLK>;
-- clock-names = "core", "iface", "phy";
-+ <&gcc PCIE_PHY_CLK>,
-+ <&gcc PCIE_AUX_CLK>,
-+ <&gcc PCIE_ALT_REF_CLK>;
-+ clock-names = "core", "iface", "phy", "aux", "ref";
-+
-+ assigned-clocks = <&gcc PCIE_ALT_REF_CLK>;
-+ assigned-clock-rates = <100000000>;
-
- resets = <&gcc PCIE_ACLK_RESET>,
- <&gcc PCIE_HCLK_RESET>,
- <&gcc PCIE_POR_RESET>,
- <&gcc PCIE_PCI_RESET>,
-- <&gcc PCIE_PHY_RESET>;
-- reset-names = "axi", "ahb", "por", "pci", "phy";
-+ <&gcc PCIE_PHY_RESET>,
-+ <&gcc PCIE_EXT_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
-
- pinctrl-0 = <&pcie0_pins>;
- pinctrl-names = "default";
-@@ -438,15 +444,21 @@
-
- clocks = <&gcc PCIE_1_A_CLK>,
- <&gcc PCIE_1_H_CLK>,
-- <&gcc PCIE_1_PHY_CLK>;
-- clock-names = "core", "iface", "phy";
-+ <&gcc PCIE_1_PHY_CLK>,
-+ <&gcc PCIE_1_AUX_CLK>,
-+ <&gcc PCIE_1_ALT_REF_CLK>;
-+ clock-names = "core", "iface", "phy", "aux", "ref";
-+
-+ assigned-clocks = <&gcc PCIE_1_ALT_REF_CLK>;
-+ assigned-clock-rates = <100000000>;
-
- resets = <&gcc PCIE_1_ACLK_RESET>,
- <&gcc PCIE_1_HCLK_RESET>,
- <&gcc PCIE_1_POR_RESET>,
- <&gcc PCIE_1_PCI_RESET>,
-- <&gcc PCIE_1_PHY_RESET>;
-- reset-names = "axi", "ahb", "por", "pci", "phy";
-+ <&gcc PCIE_1_PHY_RESET>,
-+ <&gcc PCIE_1_EXT_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
-
- pinctrl-0 = <&pcie1_pins>;
- pinctrl-names = "default";
-@@ -484,15 +496,21 @@
-
- clocks = <&gcc PCIE_2_A_CLK>,
- <&gcc PCIE_2_H_CLK>,
-- <&gcc PCIE_2_PHY_CLK>;
-- clock-names = "core", "iface", "phy";
-+ <&gcc PCIE_2_PHY_CLK>,
-+ <&gcc PCIE_2_AUX_CLK>,
-+ <&gcc PCIE_2_ALT_REF_CLK>;
-+ clock-names = "core", "iface", "phy", "aux", "ref";
-+
-+ assigned-clocks = <&gcc PCIE_2_ALT_REF_CLK>;
-+ assigned-clock-rates = <100000000>;
-
- resets = <&gcc PCIE_2_ACLK_RESET>,
- <&gcc PCIE_2_HCLK_RESET>,
- <&gcc PCIE_2_POR_RESET>,
- <&gcc PCIE_2_PCI_RESET>,
-- <&gcc PCIE_2_PHY_RESET>;
-- reset-names = "axi", "ahb", "por", "pci", "phy";
-+ <&gcc PCIE_2_PHY_RESET>,
-+ <&gcc PCIE_2_EXT_RESET>;
-+ reset-names = "axi", "ahb", "por", "pci", "phy", "ext";
-
- pinctrl-0 = <&pcie2_pins>;
- pinctrl-names = "default";
diff --git a/target/linux/ipq806x/patches-4.1/126-add-rpm-to-ipq8064-dts.patch b/target/linux/ipq806x/patches-4.1/126-add-rpm-to-ipq8064-dts.patch
deleted file mode 100644
index 7daa93163b..0000000000
--- a/target/linux/ipq806x/patches-4.1/126-add-rpm-to-ipq8064-dts.patch
+++ /dev/null
@@ -1,87 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -2,6 +2,7 @@
-
- #include "skeleton.dtsi"
- #include <dt-bindings/clock/qcom,gcc-ipq806x.h>
-+#include <dt-bindings/mfd/qcom-rpm.h>
- #include <dt-bindings/clock/qcom,lcc-ipq806x.h>
- #include <dt-bindings/soc/qcom,gsbi.h>
- #include <dt-bindings/reset/qcom,gcc-ipq806x.h>
-@@ -93,6 +94,63 @@
- reg-names = "lpass-lpaif";
- };
-
-+ rpm@108000 {
-+ compatible = "qcom,rpm-ipq8064";
-+ reg = <0x108000 0x1000>;
-+ qcom,ipc = <&l2cc 0x8 2>;
-+
-+ interrupts = <0 19 0>,
-+ <0 21 0>,
-+ <0 22 0>;
-+ interrupt-names = "ack",
-+ "err",
-+ "wakeup";
-+
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+
-+ smb208_s1a: smb208-s1a {
-+ compatible = "qcom,rpm-smb208";
-+ reg = <QCOM_RPM_SMB208_S1a>;
-+
-+ regulator-min-microvolt = <1050000>;
-+ regulator-max-microvolt = <1150000>;
-+
-+ qcom,switch-mode-frequency = <1200000>;
-+
-+ };
-+
-+ smb208_s1b: smb208-s1b {
-+ compatible = "qcom,rpm-smb208";
-+ reg = <QCOM_RPM_SMB208_S1b>;
-+
-+ regulator-min-microvolt = <1050000>;
-+ regulator-max-microvolt = <1150000>;
-+
-+ qcom,switch-mode-frequency = <1200000>;
-+ };
-+
-+ smb208_s2a: smb208-s2a {
-+ compatible = "qcom,rpm-smb208";
-+ reg = <QCOM_RPM_SMB208_S2a>;
-+
-+ regulator-min-microvolt = < 800000>;
-+ regulator-max-microvolt = <1250000>;
-+
-+ qcom,switch-mode-frequency = <1200000>;
-+ };
-+
-+ smb208_s2b: smb208-s2b {
-+ compatible = "qcom,rpm-smb208";
-+ reg = <QCOM_RPM_SMB208_S2b>;
-+
-+ regulator-min-microvolt = < 800000>;
-+ regulator-max-microvolt = <1250000>;
-+
-+ qcom,switch-mode-frequency = <1200000>;
-+ };
-+ };
-+
- qcom_pinmux: pinmux@800000 {
- compatible = "qcom,ipq8064-pinctrl";
- reg = <0x800000 0x4000>;
-@@ -164,6 +222,12 @@
- reg = <0x02098000 0x1000>, <0x02008000 0x1000>;
- };
-
-+ l2cc: clock-controller@2011000 {
-+ compatible = "qcom,kpss-gcc", "syscon";
-+ reg = <0x2011000 0x1000>;
-+ clock-output-names = "acpu_l2_aux";
-+ };
-+
- saw0: regulator@2089000 {
- compatible = "qcom,saw2";
- reg = <0x02089000 0x1000>, <0x02009000 0x1000>;
diff --git a/target/linux/ipq806x/patches-4.1/133-ARM-Add-Krait-L2-register-accessor-functions.patch b/target/linux/ipq806x/patches-4.1/133-ARM-Add-Krait-L2-register-accessor-functions.patch
deleted file mode 100644
index 36a92c858a..0000000000
--- a/target/linux/ipq806x/patches-4.1/133-ARM-Add-Krait-L2-register-accessor-functions.patch
+++ /dev/null
@@ -1,144 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,01/13] ARM: Add Krait L2 register accessor functions
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063051
-Message-Id: <1426920332-9340-2-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>,
- Mark Rutland <mark.rutland@arm.com>, Russell King <linux@arm.linux.org.uk>,
- Courtney Cavin <courtney.cavin@sonymobile.com>
-Date: Fri, 20 Mar 2015 23:45:20 -0700
-
-Krait CPUs have a handful of L2 cache controller registers that
-live behind a cp15 based indirection register. First you program
-the indirection register (l2cpselr) to point the L2 'window'
-register (l2cpdr) at what you want to read/write. Then you
-read/write the 'window' register to do what you want. The
-l2cpselr register is not banked per-cpu so we must lock around
-accesses to it to prevent other CPUs from re-pointing l2cpdr
-underneath us.
-
-Cc: Mark Rutland <mark.rutland@arm.com>
-Cc: Russell King <linux@arm.linux.org.uk>
-Cc: Courtney Cavin <courtney.cavin@sonymobile.com>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-arch/arm/common/Kconfig | 3 ++
- arch/arm/common/Makefile | 1 +
- arch/arm/common/krait-l2-accessors.c | 58 +++++++++++++++++++++++++++++++
- arch/arm/include/asm/krait-l2-accessors.h | 20 +++++++++++
- 4 files changed, 82 insertions(+)
- create mode 100644 arch/arm/common/krait-l2-accessors.c
- create mode 100644 arch/arm/include/asm/krait-l2-accessors.h
-
---- a/arch/arm/common/Kconfig
-+++ b/arch/arm/common/Kconfig
-@@ -9,6 +9,9 @@ config DMABOUNCE
- bool
- select ZONE_DMA
-
-+config KRAIT_L2_ACCESSORS
-+ bool
-+
- config SHARP_LOCOMO
- bool
-
---- a/arch/arm/common/Makefile
-+++ b/arch/arm/common/Makefile
-@@ -7,6 +7,7 @@ obj-y += firmware.o
- obj-$(CONFIG_ICST) += icst.o
- obj-$(CONFIG_SA1111) += sa1111.o
- obj-$(CONFIG_DMABOUNCE) += dmabounce.o
-+obj-$(CONFIG_KRAIT_L2_ACCESSORS) += krait-l2-accessors.o
- obj-$(CONFIG_SHARP_LOCOMO) += locomo.o
- obj-$(CONFIG_SHARP_PARAM) += sharpsl_param.o
- obj-$(CONFIG_SHARP_SCOOP) += scoop.o
---- /dev/null
-+++ b/arch/arm/common/krait-l2-accessors.c
-@@ -0,0 +1,58 @@
-+/*
-+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/spinlock.h>
-+#include <linux/export.h>
-+
-+#include <asm/barrier.h>
-+#include <asm/krait-l2-accessors.h>
-+
-+static DEFINE_RAW_SPINLOCK(krait_l2_lock);
-+
-+void krait_set_l2_indirect_reg(u32 addr, u32 val)
-+{
-+ unsigned long flags;
-+
-+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
-+ /*
-+ * Select the L2 window by poking l2cpselr, then write to the window
-+ * via l2cpdr.
-+ */
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
-+ isb();
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 7 @ l2cpdr" : : "r" (val));
-+ isb();
-+
-+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
-+}
-+EXPORT_SYMBOL(krait_set_l2_indirect_reg);
-+
-+u32 krait_get_l2_indirect_reg(u32 addr)
-+{
-+ u32 val;
-+ unsigned long flags;
-+
-+ raw_spin_lock_irqsave(&krait_l2_lock, flags);
-+ /*
-+ * Select the L2 window by poking l2cpselr, then read from the window
-+ * via l2cpdr.
-+ */
-+ asm volatile ("mcr p15, 3, %0, c15, c0, 6 @ l2cpselr" : : "r" (addr));
-+ isb();
-+ asm volatile ("mrc p15, 3, %0, c15, c0, 7 @ l2cpdr" : "=r" (val));
-+
-+ raw_spin_unlock_irqrestore(&krait_l2_lock, flags);
-+
-+ return val;
-+}
-+EXPORT_SYMBOL(krait_get_l2_indirect_reg);
---- /dev/null
-+++ b/arch/arm/include/asm/krait-l2-accessors.h
-@@ -0,0 +1,20 @@
-+/*
-+ * Copyright (c) 2011-2013, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __ASMARM_KRAIT_L2_ACCESSORS_H
-+#define __ASMARM_KRAIT_L2_ACCESSORS_H
-+
-+extern void krait_set_l2_indirect_reg(u32 addr, u32 val);
-+extern u32 krait_get_l2_indirect_reg(u32 addr);
-+
-+#endif
diff --git a/target/linux/ipq806x/patches-4.1/134-clk-mux-Split-out-register-accessors-for-reuse.patch b/target/linux/ipq806x/patches-4.1/134-clk-mux-Split-out-register-accessors-for-reuse.patch
deleted file mode 100644
index 3a475fba3d..0000000000
--- a/target/linux/ipq806x/patches-4.1/134-clk-mux-Split-out-register-accessors-for-reuse.patch
+++ /dev/null
@@ -1,192 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,02/13] clk: mux: Split out register accessors for reuse
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063111
-Message-Id: <1426920332-9340-3-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:21 -0700
-
-We want to reuse the logic in clk-mux.c for other clock drivers
-that don't use readl as register accessors. Fortunately, there
-really isn't much to the mux code besides the table indirection
-and quirk flags if you assume any bit shifting and masking has
-been done already. Pull that logic out into reusable functions
-that operate on an optional table and some flags so that other
-drivers can use the same logic.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-drivers/clk/clk-mux.c | 76 +++++++++++++++++++++++++++-----------------
- include/linux/clk-provider.h | 9 ++++--
- 2 files changed, 54 insertions(+), 31 deletions(-)
-
---- a/drivers/clk/clk-mux.c
-+++ b/drivers/clk/clk-mux.c
-@@ -29,35 +29,24 @@
-
- #define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
-
--static u8 clk_mux_get_parent(struct clk_hw *hw)
-+unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
-+ unsigned int *table, unsigned long flags)
- {
-- struct clk_mux *mux = to_clk_mux(hw);
- int num_parents = __clk_get_num_parents(hw->clk);
-- u32 val;
-
-- /*
-- * FIXME need a mux-specific flag to determine if val is bitwise or numeric
-- * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
-- * to 0x7 (index starts at one)
-- * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
-- * val = 0x4 really means "bit 2, index starts at bit 0"
-- */
-- val = clk_readl(mux->reg) >> mux->shift;
-- val &= mux->mask;
--
-- if (mux->table) {
-+ if (table) {
- int i;
-
- for (i = 0; i < num_parents; i++)
-- if (mux->table[i] == val)
-+ if (table[i] == val)
- return i;
- return -EINVAL;
- }
-
-- if (val && (mux->flags & CLK_MUX_INDEX_BIT))
-+ if (val && (flags & CLK_MUX_INDEX_BIT))
- val = ffs(val) - 1;
-
-- if (val && (mux->flags & CLK_MUX_INDEX_ONE))
-+ if (val && (flags & CLK_MUX_INDEX_ONE))
- val--;
-
- if (val >= num_parents)
-@@ -65,24 +54,53 @@ static u8 clk_mux_get_parent(struct clk_
-
- return val;
- }
-+EXPORT_SYMBOL_GPL(clk_mux_get_parent);
-
--static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
-+static u8 _clk_mux_get_parent(struct clk_hw *hw)
- {
- struct clk_mux *mux = to_clk_mux(hw);
- u32 val;
-- unsigned long flags = 0;
-
-- if (mux->table)
-- index = mux->table[index];
-+ /*
-+ * FIXME need a mux-specific flag to determine if val is bitwise or numeric
-+ * e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges from 0x1
-+ * to 0x7 (index starts at one)
-+ * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
-+ * val = 0x4 really means "bit 2, index starts at bit 0"
-+ */
-+ val = clk_readl(mux->reg) >> mux->shift;
-+ val &= mux->mask;
-+
-+ return clk_mux_get_parent(hw, val, mux->table, mux->flags);
-+}
-
-- else {
-- if (mux->flags & CLK_MUX_INDEX_BIT)
-- index = 1 << index;
-+unsigned int clk_mux_reindex(u8 index, unsigned int *table,
-+ unsigned long flags)
-+{
-+ unsigned int val = index;
-
-- if (mux->flags & CLK_MUX_INDEX_ONE)
-- index++;
-+ if (table) {
-+ val = table[val];
-+ } else {
-+ if (flags & CLK_MUX_INDEX_BIT)
-+ val = 1 << index;
-+
-+ if (flags & CLK_MUX_INDEX_ONE)
-+ val++;
- }
-
-+ return val;
-+}
-+EXPORT_SYMBOL_GPL(clk_mux_reindex);
-+
-+static int clk_mux_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct clk_mux *mux = to_clk_mux(hw);
-+ u32 val;
-+ unsigned long flags = 0;
-+
-+ index = clk_mux_reindex(index, mux->table, mux->flags);
-+
- if (mux->lock)
- spin_lock_irqsave(mux->lock, flags);
-
-@@ -102,21 +120,21 @@ static int clk_mux_set_parent(struct clk
- }
-
- const struct clk_ops clk_mux_ops = {
-- .get_parent = clk_mux_get_parent,
-+ .get_parent = _clk_mux_get_parent,
- .set_parent = clk_mux_set_parent,
- .determine_rate = __clk_mux_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_mux_ops);
-
- const struct clk_ops clk_mux_ro_ops = {
-- .get_parent = clk_mux_get_parent,
-+ .get_parent = _clk_mux_get_parent,
- };
- EXPORT_SYMBOL_GPL(clk_mux_ro_ops);
-
- struct clk *clk_register_mux_table(struct device *dev, const char *name,
- const char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u32 mask,
-- u8 clk_mux_flags, u32 *table, spinlock_t *lock)
-+ u8 clk_mux_flags, unsigned int *table, spinlock_t *lock)
- {
- struct clk_mux *mux;
- struct clk *clk;
---- a/include/linux/clk-provider.h
-+++ b/include/linux/clk-provider.h
-@@ -409,7 +409,7 @@ void clk_unregister_divider(struct clk *
- struct clk_mux {
- struct clk_hw hw;
- void __iomem *reg;
-- u32 *table;
-+ unsigned int *table;
- u32 mask;
- u8 shift;
- u8 flags;
-@@ -425,6 +425,11 @@ struct clk_mux {
- extern const struct clk_ops clk_mux_ops;
- extern const struct clk_ops clk_mux_ro_ops;
-
-+unsigned int clk_mux_get_parent(struct clk_hw *hw, unsigned int val,
-+ unsigned int *table, unsigned long flags);
-+unsigned int clk_mux_reindex(u8 index, unsigned int *table,
-+ unsigned long flags);
-+
- struct clk *clk_register_mux(struct device *dev, const char *name,
- const char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u8 width,
-@@ -433,7 +438,7 @@ struct clk *clk_register_mux(struct devi
- struct clk *clk_register_mux_table(struct device *dev, const char *name,
- const char **parent_names, u8 num_parents, unsigned long flags,
- void __iomem *reg, u8 shift, u32 mask,
-- u8 clk_mux_flags, u32 *table, spinlock_t *lock);
-+ u8 clk_mux_flags, unsigned int *table, spinlock_t *lock);
-
- void clk_unregister_mux(struct clk *clk);
-
diff --git a/target/linux/ipq806x/patches-4.1/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch b/target/linux/ipq806x/patches-4.1/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch
deleted file mode 100644
index 143e0795f0..0000000000
--- a/target/linux/ipq806x/patches-4.1/135-clk-Avoid-sending-high-rates-to-downstream-clocks-during-set_rate.patch
+++ /dev/null
@@ -1,130 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3, 03/13] clk: Avoid sending high rates to downstream clocks during
- set_rate
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063271
-Message-Id: <1426920332-9340-4-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:22 -0700
-
-If a clock is on and we call clk_set_rate() on it we may get into
-a situation where the clock temporarily increases in rate
-dramatically while we walk the tree and call .set_rate() ops. For
-example, consider a case where a PLL feeds into a divider.
-Initially the divider is set to divide by 1 and the PLL is
-running fairly slow (100MHz). The downstream consumer of the
-divider output can only handle rates =< 400 MHz, but the divider
-can only choose between divisors of 1 and 4.
-
- +-----+ +----------------+
- | PLL |-->| div 1 or div 4 |---> consumer device
- +-----+ +----------------+
-
-To achieve a rate of 400MHz on the output of the divider, we
-would have to set the rate of the PLL to 1.6 GHz and then divide
-it by 4. The current code would set the PLL to 1.6GHz first while
-the divider is still set to 1, thus causing the downstream
-consumer of the clock to receive a few clock cycles of 1.6GHz
-clock (far beyond it's maximum acceptable rate). We should be
-changing the divider first before increasing the PLL rate to
-avoid this problem.
-
-Therefore, set the rate of any child clocks that are increasing
-in rate from their current rate so that they can increase their
-dividers if necessary. We assume that there isn't such a thing as
-minimum rate requirements.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-drivers/clk/clk.c | 34 ++++++++++++++++++++++------------
- 1 file changed, 22 insertions(+), 12 deletions(-)
-
---- a/drivers/clk/clk.c
-+++ b/drivers/clk/clk.c
-@@ -1744,21 +1744,24 @@ static struct clk_core *clk_propagate_ra
- * walk down a subtree and set the new rates notifying the rate
- * change on the way
- */
--static void clk_change_rate(struct clk_core *clk)
-+static void
-+clk_change_rate(struct clk_core *clk, unsigned long best_parent_rate)
- {
- struct clk_core *child;
- struct hlist_node *tmp;
- unsigned long old_rate;
-- unsigned long best_parent_rate = 0;
- bool skip_set_rate = false;
- struct clk_core *old_parent;
-
-- old_rate = clk->rate;
-+ hlist_for_each_entry(child, &clk->children, child_node) {
-+ /* Skip children who will be reparented to another clock */
-+ if (child->new_parent && child->new_parent != clk)
-+ continue;
-+ if (child->new_rate > child->rate)
-+ clk_change_rate(child, clk->new_rate);
-+ }
-
-- if (clk->new_parent)
-- best_parent_rate = clk->new_parent->rate;
-- else if (clk->parent)
-- best_parent_rate = clk->parent->rate;
-+ old_rate = clk->rate;
-
- if (clk->new_parent && clk->new_parent != clk->parent) {
- old_parent = __clk_set_parent_before(clk, clk->new_parent);
-@@ -1784,7 +1787,7 @@ static void clk_change_rate(struct clk_c
-
- trace_clk_set_rate_complete(clk, clk->new_rate);
-
-- clk->rate = clk_recalc(clk, best_parent_rate);
-+ clk->rate = clk->new_rate;
-
- if (clk->notifier_count && old_rate != clk->rate)
- __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
-@@ -1797,12 +1800,13 @@ static void clk_change_rate(struct clk_c
- /* Skip children who will be reparented to another clock */
- if (child->new_parent && child->new_parent != clk)
- continue;
-- clk_change_rate(child);
-+ if (child->new_rate != child->rate)
-+ clk_change_rate(child, clk->new_rate);
- }
-
- /* handle the new child who might not be in clk->children yet */
-- if (clk->new_child)
-- clk_change_rate(clk->new_child);
-+ if (clk->new_child && clk->new_child->new_rate != clk->new_child->rate)
-+ clk_change_rate(clk->new_child, clk->new_rate);
- }
-
- static int clk_core_set_rate_nolock(struct clk_core *clk,
-@@ -1811,6 +1815,7 @@ static int clk_core_set_rate_nolock(stru
- struct clk_core *top, *fail_clk;
- unsigned long rate = req_rate;
- int ret = 0;
-+ unsigned long parent_rate;
-
- if (!clk)
- return 0;
-@@ -1836,8 +1841,13 @@ static int clk_core_set_rate_nolock(stru
- return -EBUSY;
- }
-
-+ if (top->parent)
-+ parent_rate = top->parent->rate;
-+ else
-+ parent_rate = 0;
-+
- /* change the rates */
-- clk_change_rate(top);
-+ clk_change_rate(top, parent_rate);
-
- clk->req_rate = req_rate;
-
diff --git a/target/linux/ipq806x/patches-4.1/136-clk-Add-safe-switch-hook.patch b/target/linux/ipq806x/patches-4.1/136-clk-Add-safe-switch-hook.patch
deleted file mode 100644
index b0d89a9681..0000000000
--- a/target/linux/ipq806x/patches-4.1/136-clk-Add-safe-switch-hook.patch
+++ /dev/null
@@ -1,164 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,04/13] clk: Add safe switch hook
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063211
-Message-Id: <1426920332-9340-5-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:23 -0700
-
-Sometimes clocks can't accept their parent source turning off
-while the source is reprogrammed to a different rate. Most
-notably CPU clocks require a way to switch away from the current
-PLL they're running on, reprogram that PLL to a new rate, and
-then switch back to the PLL with the new rate once they're done.
-Add a hook that drivers can implement allowing them to return a
-'safe parent' that they can switch their parent to while the
-upstream source is reprogrammed to support this.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-This patch is good enough for Krait, but soon I'll need to
-support a "safe rate" where we ask a clock what rate it needs to be running
-at to be sure it's within voltage constraints. Right now safe parent
-handles that problem on Krait, but on other platforms it won't work.
-
- drivers/clk/clk.c | 61 ++++++++++++++++++++++++++++++++++++++------
- include/linux/clk-provider.h | 1 +
- 2 files changed, 54 insertions(+), 8 deletions(-)
-
---- a/drivers/clk/clk.c
-+++ b/drivers/clk/clk.c
-@@ -56,9 +56,12 @@ struct clk_core {
- struct clk_core **parents;
- u8 num_parents;
- u8 new_parent_index;
-+ u8 safe_parent_index;
- unsigned long rate;
- unsigned long req_rate;
-+ unsigned long old_rate;
- unsigned long new_rate;
-+ struct clk_core *safe_parent;
- struct clk_core *new_parent;
- struct clk_core *new_child;
- unsigned long flags;
-@@ -1596,7 +1599,8 @@ out:
- static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
- struct clk_core *new_parent, u8 p_index)
- {
-- struct clk_core *child;
-+ struct clk_core *child, *parent;
-+ struct clk_hw *parent_hw;
-
- clk->new_rate = new_rate;
- clk->new_parent = new_parent;
-@@ -1606,6 +1610,18 @@ static void clk_calc_subtree(struct clk_
- if (new_parent && new_parent != clk->parent)
- new_parent->new_child = clk;
-
-+ if (clk->ops->get_safe_parent) {
-+ parent_hw = clk->ops->get_safe_parent(clk->hw);
-+ if (parent_hw) {
-+ parent = parent_hw->core;
-+ p_index = clk_fetch_parent_index(clk, parent);
-+ clk->safe_parent_index = p_index;
-+ clk->safe_parent = parent;
-+ }
-+ } else {
-+ clk->safe_parent = NULL;
-+ }
-+
- hlist_for_each_entry(child, &clk->children, child_node) {
- child->new_rate = clk_recalc(child, new_rate);
- clk_calc_subtree(child, child->new_rate, NULL, 0);
-@@ -1710,14 +1726,43 @@ static struct clk_core *clk_propagate_ra
- unsigned long event)
- {
- struct clk_core *child, *tmp_clk, *fail_clk = NULL;
-+ struct clk_core *old_parent;
- int ret = NOTIFY_DONE;
-
-- if (clk->rate == clk->new_rate)
-+ if (clk->rate == clk->new_rate && event != POST_RATE_CHANGE)
- return NULL;
-
-+ switch (event) {
-+ case PRE_RATE_CHANGE:
-+ if (clk->safe_parent)
-+ clk->ops->set_parent(clk->hw, clk->safe_parent_index);
-+ clk->old_rate = clk->rate;
-+ break;
-+ case POST_RATE_CHANGE:
-+ if (clk->safe_parent) {
-+ old_parent = __clk_set_parent_before(clk,
-+ clk->new_parent);
-+ if (clk->ops->set_rate_and_parent) {
-+ clk->ops->set_rate_and_parent(clk->hw,
-+ clk->new_rate,
-+ clk->new_parent ?
-+ clk->new_parent->rate : 0,
-+ clk->new_parent_index);
-+ } else if (clk->ops->set_parent) {
-+ clk->ops->set_parent(clk->hw,
-+ clk->new_parent_index);
-+ }
-+ __clk_set_parent_after(clk, clk->new_parent,
-+ old_parent);
-+ }
-+ break;
-+ }
-+
- if (clk->notifier_count) {
-- ret = __clk_notify(clk, event, clk->rate, clk->new_rate);
-- if (ret & NOTIFY_STOP_MASK)
-+ if (event != POST_RATE_CHANGE || clk->old_rate != clk->rate)
-+ ret = __clk_notify(clk, event, clk->old_rate,
-+ clk->new_rate);
-+ if (ret & NOTIFY_STOP_MASK && event != POST_RATE_CHANGE)
- fail_clk = clk;
- }
-
-@@ -1763,7 +1808,8 @@ clk_change_rate(struct clk_core *clk, un
-
- old_rate = clk->rate;
-
-- if (clk->new_parent && clk->new_parent != clk->parent) {
-+ if (clk->new_parent && clk->new_parent != clk->parent &&
-+ !clk->safe_parent) {
- old_parent = __clk_set_parent_before(clk, clk->new_parent);
- trace_clk_set_parent(clk, clk->new_parent);
-
-@@ -1789,9 +1835,6 @@ clk_change_rate(struct clk_core *clk, un
-
- clk->rate = clk->new_rate;
-
-- if (clk->notifier_count && old_rate != clk->rate)
-- __clk_notify(clk, POST_RATE_CHANGE, old_rate, clk->rate);
--
- /*
- * Use safe iteration, as change_rate can actually swap parents
- * for certain clock types.
-@@ -1851,6 +1894,8 @@ static int clk_core_set_rate_nolock(stru
-
- clk->req_rate = req_rate;
-
-+ clk_propagate_rate_change(top, POST_RATE_CHANGE);
-+
- return ret;
- }
-
---- a/include/linux/clk-provider.h
-+++ b/include/linux/clk-provider.h
-@@ -183,6 +183,7 @@ struct clk_ops {
- struct clk_hw **best_parent_hw);
- int (*set_parent)(struct clk_hw *hw, u8 index);
- u8 (*get_parent)(struct clk_hw *hw);
-+ struct clk_hw *(*get_safe_parent)(struct clk_hw *hw);
- int (*set_rate)(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate);
- int (*set_rate_and_parent)(struct clk_hw *hw,
diff --git a/target/linux/ipq806x/patches-4.1/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch b/target/linux/ipq806x/patches-4.1/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch
deleted file mode 100644
index 6fad6e8a0c..0000000000
--- a/target/linux/ipq806x/patches-4.1/137-clk-qcom-Add-support-for-High-Frequency-PLLs-HFPLLs.patch
+++ /dev/null
@@ -1,351 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,05/13] clk: qcom: Add support for High-Frequency PLLs (HFPLLs)
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063261
-Message-Id: <1426920332-9340-6-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:24 -0700
-
-HFPLLs are the main frequency source for Krait CPU clocks. Add
-support for changing the rate of these PLLs.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-I'd really like to get rid of __clk_hfpll_init_once() if possible...
-
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-hfpll.c | 253 +++++++++++++++++++++++++++++++++++++++++++
- drivers/clk/qcom/clk-hfpll.h | 54 +++++++++
- 3 files changed, 308 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-hfpll.c
- create mode 100644 drivers/clk/qcom/clk-hfpll.h
-
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -8,6 +8,7 @@ clk-qcom-y += clk-rcg2.o
- clk-qcom-y += clk-branch.o
- clk-qcom-y += clk-regmap-divider.o
- clk-qcom-y += clk-regmap-mux.o
-+clk-qcom-y += clk-hfpll.o
- clk-qcom-y += reset.o
-
- obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
---- /dev/null
-+++ b/drivers/clk/qcom/clk-hfpll.c
-@@ -0,0 +1,253 @@
-+/*
-+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+#include <linux/kernel.h>
-+#include <linux/export.h>
-+#include <linux/regmap.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+
-+#include "clk-regmap.h"
-+#include "clk-hfpll.h"
-+
-+#define PLL_OUTCTRL BIT(0)
-+#define PLL_BYPASSNL BIT(1)
-+#define PLL_RESET_N BIT(2)
-+
-+/* Initialize a HFPLL at a given rate and enable it. */
-+static void __clk_hfpll_init_once(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+
-+ if (likely(h->init_done))
-+ return;
-+
-+ /* Configure PLL parameters for integer mode. */
-+ if (hd->config_val)
-+ regmap_write(regmap, hd->config_reg, hd->config_val);
-+ regmap_write(regmap, hd->m_reg, 0);
-+ regmap_write(regmap, hd->n_reg, 1);
-+
-+ if (hd->user_reg) {
-+ u32 regval = hd->user_val;
-+ unsigned long rate;
-+
-+ rate = __clk_get_rate(hw->clk);
-+
-+ /* Pick the right VCO. */
-+ if (hd->user_vco_mask && rate > hd->low_vco_max_rate)
-+ regval |= hd->user_vco_mask;
-+ regmap_write(regmap, hd->user_reg, regval);
-+ }
-+
-+ if (hd->droop_reg)
-+ regmap_write(regmap, hd->droop_reg, hd->droop_val);
-+
-+ h->init_done = true;
-+}
-+
-+static void __clk_hfpll_enable(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 val;
-+
-+ __clk_hfpll_init_once(hw);
-+
-+ /* Disable PLL bypass mode. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_BYPASSNL, PLL_BYPASSNL);
-+
-+ /*
-+ * H/W requires a 5us delay between disabling the bypass and
-+ * de-asserting the reset. Delay 10us just to be safe.
-+ */
-+ udelay(10);
-+
-+ /* De-assert active-low PLL reset. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_RESET_N, PLL_RESET_N);
-+
-+ /* Wait for PLL to lock. */
-+ if (hd->status_reg) {
-+ do {
-+ regmap_read(regmap, hd->status_reg, &val);
-+ } while (!(val & BIT(hd->lock_bit)));
-+ } else {
-+ udelay(60);
-+ }
-+
-+ /* Enable PLL output. */
-+ regmap_update_bits(regmap, hd->mode_reg, PLL_OUTCTRL, PLL_OUTCTRL);
-+}
-+
-+/* Enable an already-configured HFPLL. */
-+static int clk_hfpll_enable(struct clk_hw *hw)
-+{
-+ unsigned long flags;
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ if (!(mode & (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)))
-+ __clk_hfpll_enable(hw);
-+ spin_unlock_irqrestore(&h->lock, flags);
-+
-+ return 0;
-+}
-+
-+static void __clk_hfpll_disable(struct clk_hfpll *h)
-+{
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+
-+ /*
-+ * Disable the PLL output, disable test mode, enable the bypass mode,
-+ * and assert the reset.
-+ */
-+ regmap_update_bits(regmap, hd->mode_reg,
-+ PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL, 0);
-+}
-+
-+static void clk_hfpll_disable(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+ __clk_hfpll_disable(h);
-+ spin_unlock_irqrestore(&h->lock, flags);
-+}
-+
-+static long clk_hfpll_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ unsigned long rrate;
-+
-+ rate = clamp(rate, hd->min_rate, hd->max_rate);
-+
-+ rrate = DIV_ROUND_UP(rate, *parent_rate) * *parent_rate;
-+ if (rrate > hd->max_rate)
-+ rrate -= *parent_rate;
-+
-+ return rrate;
-+}
-+
-+/*
-+ * For optimization reasons, assumes no downstream clocks are actively using
-+ * it.
-+ */
-+static int clk_hfpll_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ unsigned long flags;
-+ u32 l_val, val;
-+ bool enabled;
-+
-+ l_val = rate / parent_rate;
-+
-+ spin_lock_irqsave(&h->lock, flags);
-+
-+ enabled = __clk_is_enabled(hw->clk);
-+ if (enabled)
-+ __clk_hfpll_disable(h);
-+
-+ /* Pick the right VCO. */
-+ if (hd->user_reg && hd->user_vco_mask) {
-+ regmap_read(regmap, hd->user_reg, &val);
-+ if (rate <= hd->low_vco_max_rate)
-+ val &= ~hd->user_vco_mask;
-+ else
-+ val |= hd->user_vco_mask;
-+ regmap_write(regmap, hd->user_reg, val);
-+ }
-+
-+ regmap_write(regmap, hd->l_reg, l_val);
-+
-+ if (enabled)
-+ __clk_hfpll_enable(hw);
-+
-+ spin_unlock_irqrestore(&h->lock, flags);
-+
-+ return 0;
-+}
-+
-+static unsigned long clk_hfpll_recalc_rate(struct clk_hw *hw,
-+ unsigned long parent_rate)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 l_val;
-+
-+ regmap_read(regmap, hd->l_reg, &l_val);
-+
-+ return l_val * parent_rate;
-+}
-+
-+static void clk_hfpll_init(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode, status;
-+
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ if (mode != (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL)) {
-+ __clk_hfpll_init_once(hw);
-+ return;
-+ }
-+
-+ if (hd->status_reg) {
-+ regmap_read(regmap, hd->status_reg, &status);
-+ if (!(status & BIT(hd->lock_bit))) {
-+ WARN(1, "HFPLL %s is ON, but not locked!\n",
-+ __clk_get_name(hw->clk));
-+ clk_hfpll_disable(hw);
-+ __clk_hfpll_init_once(hw);
-+ }
-+ }
-+}
-+
-+static int hfpll_is_enabled(struct clk_hw *hw)
-+{
-+ struct clk_hfpll *h = to_clk_hfpll(hw);
-+ struct hfpll_data const *hd = h->d;
-+ struct regmap *regmap = h->clkr.regmap;
-+ u32 mode;
-+
-+ regmap_read(regmap, hd->mode_reg, &mode);
-+ mode &= 0x7;
-+ return mode == (PLL_BYPASSNL | PLL_RESET_N | PLL_OUTCTRL);
-+}
-+
-+const struct clk_ops clk_ops_hfpll = {
-+ .enable = clk_hfpll_enable,
-+ .disable = clk_hfpll_disable,
-+ .is_enabled = hfpll_is_enabled,
-+ .round_rate = clk_hfpll_round_rate,
-+ .set_rate = clk_hfpll_set_rate,
-+ .recalc_rate = clk_hfpll_recalc_rate,
-+ .init = clk_hfpll_init,
-+};
-+EXPORT_SYMBOL_GPL(clk_ops_hfpll);
---- /dev/null
-+++ b/drivers/clk/qcom/clk-hfpll.h
-@@ -0,0 +1,54 @@
-+/*
-+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+#ifndef __QCOM_CLK_HFPLL_H__
-+#define __QCOM_CLK_HFPLL_H__
-+
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+#include "clk-regmap.h"
-+
-+struct hfpll_data {
-+ u32 mode_reg;
-+ u32 l_reg;
-+ u32 m_reg;
-+ u32 n_reg;
-+ u32 user_reg;
-+ u32 droop_reg;
-+ u32 config_reg;
-+ u32 status_reg;
-+ u8 lock_bit;
-+
-+ u32 droop_val;
-+ u32 config_val;
-+ u32 user_val;
-+ u32 user_vco_mask;
-+ unsigned long low_vco_max_rate;
-+
-+ unsigned long min_rate;
-+ unsigned long max_rate;
-+};
-+
-+struct clk_hfpll {
-+ struct hfpll_data const *d;
-+ int init_done;
-+
-+ struct clk_regmap clkr;
-+ spinlock_t lock;
-+};
-+
-+#define to_clk_hfpll(_hw) \
-+ container_of(to_clk_regmap(_hw), struct clk_hfpll, clkr)
-+
-+extern const struct clk_ops clk_ops_hfpll;
-+
-+#endif
diff --git a/target/linux/ipq806x/patches-4.1/138-clk-qcom-Add-HFPLL-driver.patch b/target/linux/ipq806x/patches-4.1/138-clk-qcom-Add-HFPLL-driver.patch
deleted file mode 100644
index 4056784287..0000000000
--- a/target/linux/ipq806x/patches-4.1/138-clk-qcom-Add-HFPLL-driver.patch
+++ /dev/null
@@ -1,206 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,06/13] clk: qcom: Add HFPLL driver
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063231
-Message-Id: <1426920332-9340-7-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>, <devicetree@vger.kernel.org>
-Date: Fri, 20 Mar 2015 23:45:25 -0700
-
-On some devices (MSM8974 for example), the HFPLLs are
-instantiated within the Krait processor subsystem as separate
-register regions. Add a driver for these PLLs so that we can
-provide HFPLL clocks for use by the system.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-.../devicetree/bindings/clock/qcom,hfpll.txt | 40 ++++++++
- drivers/clk/qcom/Kconfig | 8 ++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/hfpll.c | 109 +++++++++++++++++++++
- 4 files changed, 158 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,hfpll.txt
- create mode 100644 drivers/clk/qcom/hfpll.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,hfpll.txt
-@@ -0,0 +1,40 @@
-+High-Frequency PLL (HFPLL)
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>
-+ Definition: must be "qcom,hfpll"
-+
-+- reg:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: address and size of HPLL registers. An optional second
-+ element specifies the address and size of the alias
-+ register region.
-+
-+- clock-output-names:
-+ Usage: required
-+ Value type: <string>
-+ Definition: Name of the PLL. Typically hfpllX where X is a CPU number
-+ starting at 0. Otherwise hfpll_Y where Y is more specific
-+ such as "l2".
-+
-+Example:
-+
-+1) An HFPLL for the L2 cache.
-+
-+ clock-controller@f9016000 {
-+ compatible = "qcom,hfpll";
-+ reg = <0xf9016000 0x30>;
-+ clock-output-names = "hfpll_l2";
-+ };
-+
-+2) An HFPLL for CPU0. This HFPLL has the alias register region.
-+
-+ clock-controller@f908a000 {
-+ compatible = "qcom,hfpll";
-+ reg = <0xf908a000 0x30>, <0xf900a000 0x30>;
-+ clock-output-names = "hfpll0";
-+ };
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -97,3 +97,11 @@ config MSM_MMCC_8974
- Support for the multimedia clock controller on msm8974 devices.
- Say Y if you want to support multimedia devices such as display,
- graphics, video encode/decode, camera, etc.
-+
-+config QCOM_HFPLL
-+ tristate "High-Frequency PLL (HFPLL) Clock Controller"
-+ depends on COMMON_CLK_QCOM
-+ help
-+ Support for the high-frequency PLLs present on Qualcomm devices.
-+ Say Y if you want to support CPU frequency scaling on devices
-+ such as MSM8974, APQ8084, etc.
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -22,3 +22,4 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm896
- obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
- obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
- obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
-+obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
---- /dev/null
-+++ b/drivers/clk/qcom/hfpll.c
-@@ -0,0 +1,109 @@
-+/*
-+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/of.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/regmap.h>
-+
-+#include "clk-regmap.h"
-+#include "clk-hfpll.h"
-+
-+static const struct hfpll_data hdata = {
-+ .mode_reg = 0x00,
-+ .l_reg = 0x04,
-+ .m_reg = 0x08,
-+ .n_reg = 0x0c,
-+ .user_reg = 0x10,
-+ .config_reg = 0x14,
-+ .config_val = 0x430405d,
-+ .status_reg = 0x1c,
-+ .lock_bit = 16,
-+
-+ .user_val = 0x8,
-+ .user_vco_mask = 0x100000,
-+ .low_vco_max_rate = 1248000000,
-+ .min_rate = 537600000UL,
-+ .max_rate = 2900000000UL,
-+};
-+
-+static const struct of_device_id qcom_hfpll_match_table[] = {
-+ { .compatible = "qcom,hfpll" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, qcom_hfpll_match_table);
-+
-+static const struct regmap_config hfpll_regmap_config = {
-+ .reg_bits = 32,
-+ .reg_stride = 4,
-+ .val_bits = 32,
-+ .max_register = 0x30,
-+ .fast_io = true,
-+};
-+
-+static int qcom_hfpll_probe(struct platform_device *pdev)
-+{
-+ struct clk *clk;
-+ struct resource *res;
-+ struct device *dev = &pdev->dev;
-+ void __iomem *base;
-+ struct regmap *regmap;
-+ struct clk_hfpll *h;
-+ struct clk_init_data init = {
-+ .parent_names = (const char *[]){ "xo" },
-+ .num_parents = 1,
-+ .ops = &clk_ops_hfpll,
-+ };
-+
-+ h = devm_kzalloc(dev, sizeof(*h), GFP_KERNEL);
-+ if (!h)
-+ return -ENOMEM;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ base = devm_ioremap_resource(dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ regmap = devm_regmap_init_mmio(&pdev->dev, base, &hfpll_regmap_config);
-+ if (IS_ERR(regmap))
-+ return PTR_ERR(regmap);
-+
-+ if (of_property_read_string_index(dev->of_node, "clock-output-names",
-+ 0, &init.name))
-+ return -ENODEV;
-+
-+ h->d = &hdata;
-+ h->clkr.hw.init = &init;
-+ spin_lock_init(&h->lock);
-+
-+ clk = devm_clk_register_regmap(&pdev->dev, &h->clkr);
-+
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static struct platform_driver qcom_hfpll_driver = {
-+ .probe = qcom_hfpll_probe,
-+ .driver = {
-+ .name = "qcom-hfpll",
-+ .of_match_table = qcom_hfpll_match_table,
-+ },
-+};
-+module_platform_driver(qcom_hfpll_driver);
-+
-+MODULE_DESCRIPTION("QCOM HFPLL Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:qcom-hfpll");
diff --git a/target/linux/ipq806x/patches-4.1/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch b/target/linux/ipq806x/patches-4.1/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch
deleted file mode 100644
index ffcd462d12..0000000000
--- a/target/linux/ipq806x/patches-4.1/139-clk-qcom-Add-IPQ806X-s-HFPLLs.patch
+++ /dev/null
@@ -1,127 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,08/13] clk: qcom: Add IPQ806X's HFPLLs
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063241
-Message-Id: <1426920332-9340-9-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:27 -0700
-
-Describe the HFPLLs present on IPQ806X devices.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-drivers/clk/qcom/gcc-ipq806x.c | 83 ++++++++++++++++++++++++++++++++++++++++++
- 1 file changed, 83 insertions(+)
-
---- a/drivers/clk/qcom/gcc-ipq806x.c
-+++ b/drivers/clk/qcom/gcc-ipq806x.c
-@@ -30,6 +30,7 @@
- #include "clk-pll.h"
- #include "clk-rcg.h"
- #include "clk-branch.h"
-+#include "clk-hfpll.h"
- #include "reset.h"
-
- static struct clk_pll pll0 = {
-@@ -113,6 +114,85 @@ static struct clk_regmap pll8_vote = {
- },
- };
-
-+static struct hfpll_data hfpll0_data = {
-+ .mode_reg = 0x3200,
-+ .l_reg = 0x3208,
-+ .m_reg = 0x320c,
-+ .n_reg = 0x3210,
-+ .config_reg = 0x3204,
-+ .status_reg = 0x321c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3214,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll0 = {
-+ .d = &hfpll0_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll0",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll0.lock),
-+};
-+
-+static struct hfpll_data hfpll1_data = {
-+ .mode_reg = 0x3240,
-+ .l_reg = 0x3248,
-+ .m_reg = 0x324c,
-+ .n_reg = 0x3250,
-+ .config_reg = 0x3244,
-+ .status_reg = 0x325c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll1 = {
-+ .d = &hfpll1_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll1",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll1.lock),
-+};
-+
-+static struct hfpll_data hfpll_l2_data = {
-+ .mode_reg = 0x3300,
-+ .l_reg = 0x3308,
-+ .m_reg = 0x330c,
-+ .n_reg = 0x3310,
-+ .config_reg = 0x3304,
-+ .status_reg = 0x331c,
-+ .config_val = 0x7845c665,
-+ .droop_reg = 0x3314,
-+ .droop_val = 0x0108c000,
-+ .min_rate = 600000000UL,
-+ .max_rate = 1800000000UL,
-+};
-+
-+static struct clk_hfpll hfpll_l2 = {
-+ .d = &hfpll_l2_data,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .name = "hfpll_l2",
-+ .ops = &clk_ops_hfpll,
-+ .flags = CLK_IGNORE_UNUSED,
-+ },
-+ .lock = __SPIN_LOCK_UNLOCKED(hfpll_l2.lock),
-+};
-+
-+
- static struct clk_pll pll14 = {
- .l_reg = 0x31c4,
- .m_reg = 0x31c8,
-@@ -2307,6 +2387,9 @@ static struct clk_regmap *gcc_ipq806x_cl
- [USB_FS1_SYSTEM_CLK] = &usb_fs1_sys_clk.clkr,
- [EBI2_CLK] = &ebi2_clk.clkr,
- [EBI2_AON_CLK] = &ebi2_aon_clk.clkr,
-+ [PLL9] = &hfpll0.clkr,
-+ [PLL10] = &hfpll1.clkr,
-+ [PLL12] = &hfpll_l2.clkr,
- };
-
- static const struct qcom_reset_map gcc_ipq806x_resets[] = {
diff --git a/target/linux/ipq806x/patches-4.1/140-clk-qcom-Add-support-for-Krait-clocks.patch b/target/linux/ipq806x/patches-4.1/140-clk-qcom-Add-support-for-Krait-clocks.patch
deleted file mode 100644
index 5fcc787c89..0000000000
--- a/target/linux/ipq806x/patches-4.1/140-clk-qcom-Add-support-for-Krait-clocks.patch
+++ /dev/null
@@ -1,271 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,09/13] clk: qcom: Add support for Krait clocks
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063251
-Message-Id: <1426920332-9340-10-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>
-Date: Fri, 20 Mar 2015 23:45:28 -0700
-
-The Krait clocks are made up of a series of muxes and a divider
-that choose between a fixed rate clock and dedicated HFPLLs for
-each CPU. Instead of using mmio accesses to remux parents, the
-Krait implementation exposes the remux control via cp15
-registers. Support these clocks.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-drivers/clk/qcom/Kconfig | 4 ++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/clk-krait.c | 166 +++++++++++++++++++++++++++++++++++++++++++
- drivers/clk/qcom/clk-krait.h | 49 +++++++++++++
- 4 files changed, 220 insertions(+)
- create mode 100644 drivers/clk/qcom/clk-krait.c
- create mode 100644 drivers/clk/qcom/clk-krait.h
-
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -105,3 +105,7 @@ config QCOM_HFPLL
- Support for the high-frequency PLLs present on Qualcomm devices.
- Say Y if you want to support CPU frequency scaling on devices
- such as MSM8974, APQ8084, etc.
-+
-+config KRAIT_CLOCKS
-+ bool
-+ select KRAIT_L2_ACCESSORS
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -8,6 +8,7 @@ clk-qcom-y += clk-rcg2.o
- clk-qcom-y += clk-branch.o
- clk-qcom-y += clk-regmap-divider.o
- clk-qcom-y += clk-regmap-mux.o
-+clk-qcom-$(CONFIG_KRAIT_CLOCKS) += clk-krait.o
- clk-qcom-y += clk-hfpll.o
- clk-qcom-y += reset.o
-
---- /dev/null
-+++ b/drivers/clk/qcom/clk-krait.c
-@@ -0,0 +1,166 @@
-+/*
-+ * Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/delay.h>
-+#include <linux/err.h>
-+#include <linux/clk-provider.h>
-+#include <linux/spinlock.h>
-+
-+#include <asm/krait-l2-accessors.h>
-+
-+#include "clk-krait.h"
-+
-+/* Secondary and primary muxes share the same cp15 register */
-+static DEFINE_SPINLOCK(krait_clock_reg_lock);
-+
-+#define LPL_SHIFT 8
-+static void __krait_mux_set_sel(struct krait_mux_clk *mux, int sel)
-+{
-+ unsigned long flags;
-+ u32 regval;
-+
-+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
-+ regval = krait_get_l2_indirect_reg(mux->offset);
-+ regval &= ~(mux->mask << mux->shift);
-+ regval |= (sel & mux->mask) << mux->shift;
-+ if (mux->lpl) {
-+ regval &= ~(mux->mask << (mux->shift + LPL_SHIFT));
-+ regval |= (sel & mux->mask) << (mux->shift + LPL_SHIFT);
-+ }
-+ krait_set_l2_indirect_reg(mux->offset, regval);
-+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
-+
-+ /* Wait for switch to complete. */
-+ mb();
-+ udelay(1);
-+}
-+
-+static int krait_mux_set_parent(struct clk_hw *hw, u8 index)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+ u32 sel;
-+
-+ sel = clk_mux_reindex(index, mux->parent_map, 0);
-+ mux->en_mask = sel;
-+ /* Don't touch mux if CPU is off as it won't work */
-+ if (__clk_is_enabled(hw->clk))
-+ __krait_mux_set_sel(mux, sel);
-+ return 0;
-+}
-+
-+static u8 krait_mux_get_parent(struct clk_hw *hw)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+ u32 sel;
-+
-+ sel = krait_get_l2_indirect_reg(mux->offset);
-+ sel >>= mux->shift;
-+ sel &= mux->mask;
-+ mux->en_mask = sel;
-+
-+ return clk_mux_get_parent(hw, sel, mux->parent_map, 0);
-+}
-+
-+static struct clk_hw *krait_mux_get_safe_parent(struct clk_hw *hw)
-+{
-+ int i;
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+ int num_parents = __clk_get_num_parents(hw->clk);
-+
-+ i = mux->safe_sel;
-+ for (i = 0; i < num_parents; i++)
-+ if (mux->safe_sel == mux->parent_map[i])
-+ break;
-+
-+ return __clk_get_hw(clk_get_parent_by_index(hw->clk, i));
-+}
-+
-+static int krait_mux_enable(struct clk_hw *hw)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+
-+ __krait_mux_set_sel(mux, mux->en_mask);
-+
-+ return 0;
-+}
-+
-+static void krait_mux_disable(struct clk_hw *hw)
-+{
-+ struct krait_mux_clk *mux = to_krait_mux_clk(hw);
-+
-+ __krait_mux_set_sel(mux, mux->safe_sel);
-+}
-+
-+const struct clk_ops krait_mux_clk_ops = {
-+ .enable = krait_mux_enable,
-+ .disable = krait_mux_disable,
-+ .set_parent = krait_mux_set_parent,
-+ .get_parent = krait_mux_get_parent,
-+ .determine_rate = __clk_mux_determine_rate_closest,
-+ .get_safe_parent = krait_mux_get_safe_parent,
-+};
-+EXPORT_SYMBOL_GPL(krait_mux_clk_ops);
-+
-+/* The divider can divide by 2, 4, 6 and 8. But we only really need div-2. */
-+static long krait_div2_round_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long *parent_rate)
-+{
-+ *parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), rate * 2);
-+ return DIV_ROUND_UP(*parent_rate, 2);
-+}
-+
-+static int krait_div2_set_rate(struct clk_hw *hw, unsigned long rate,
-+ unsigned long parent_rate)
-+{
-+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
-+ unsigned long flags;
-+ u32 val;
-+ u32 mask = BIT(d->width) - 1;
-+
-+ if (d->lpl)
-+ mask = mask << (d->shift + LPL_SHIFT) | mask << d->shift;
-+
-+ spin_lock_irqsave(&krait_clock_reg_lock, flags);
-+ val = krait_get_l2_indirect_reg(d->offset);
-+ val &= ~mask;
-+ krait_set_l2_indirect_reg(d->offset, val);
-+ spin_unlock_irqrestore(&krait_clock_reg_lock, flags);
-+
-+ return 0;
-+}
-+
-+static unsigned long
-+krait_div2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
-+{
-+ struct krait_div2_clk *d = to_krait_div2_clk(hw);
-+ u32 mask = BIT(d->width) - 1;
-+ u32 div;
-+
-+ div = krait_get_l2_indirect_reg(d->offset);
-+ div >>= d->shift;
-+ div &= mask;
-+ div = (div + 1) * 2;
-+
-+ return DIV_ROUND_UP(parent_rate, div);
-+}
-+
-+const struct clk_ops krait_div2_clk_ops = {
-+ .round_rate = krait_div2_round_rate,
-+ .set_rate = krait_div2_set_rate,
-+ .recalc_rate = krait_div2_recalc_rate,
-+};
-+EXPORT_SYMBOL_GPL(krait_div2_clk_ops);
---- /dev/null
-+++ b/drivers/clk/qcom/clk-krait.h
-@@ -0,0 +1,49 @@
-+/*
-+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#ifndef __QCOM_CLK_KRAIT_H
-+#define __QCOM_CLK_KRAIT_H
-+
-+#include <linux/clk-provider.h>
-+
-+struct krait_mux_clk {
-+ unsigned int *parent_map;
-+ bool has_safe_parent;
-+ u8 safe_sel;
-+ u32 offset;
-+ u32 mask;
-+ u32 shift;
-+ u32 en_mask;
-+ bool lpl;
-+
-+ struct clk_hw hw;
-+};
-+
-+#define to_krait_mux_clk(_hw) container_of(_hw, struct krait_mux_clk, hw)
-+
-+extern const struct clk_ops krait_mux_clk_ops;
-+
-+struct krait_div2_clk {
-+ u32 offset;
-+ u8 width;
-+ u32 shift;
-+ bool lpl;
-+
-+ struct clk_hw hw;
-+};
-+
-+#define to_krait_div2_clk(_hw) container_of(_hw, struct krait_div2_clk, hw)
-+
-+extern const struct clk_ops krait_div2_clk_ops;
-+
-+#endif
diff --git a/target/linux/ipq806x/patches-4.1/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch b/target/linux/ipq806x/patches-4.1/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch
deleted file mode 100644
index db4388812b..0000000000
--- a/target/linux/ipq806x/patches-4.1/141-clk-qcom-Add-KPSS-ACC-GCC-driver.patch
+++ /dev/null
@@ -1,205 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,10/13] clk: qcom: Add KPSS ACC/GCC driver
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063201
-Message-Id: <1426920332-9340-11-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>, <devicetree@vger.kernel.org>
-Date: Fri, 20 Mar 2015 23:45:29 -0700
-
-The ACC and GCC regions present in KPSSv1 contain registers to
-control clocks and power to each Krait CPU and L2. For CPUfreq
-purposes probe these devices and expose a mux clock that chooses
-between PXO and PLL8.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-.../devicetree/bindings/arm/msm/qcom,kpss-acc.txt | 7 ++
- .../devicetree/bindings/arm/msm/qcom,kpss-gcc.txt | 28 +++++++
- drivers/clk/qcom/Kconfig | 8 ++
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/kpss-xcc.c | 95 ++++++++++++++++++++++
- 5 files changed, 139 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
- create mode 100644 drivers/clk/qcom/kpss-xcc.c
-
---- a/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
-+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-acc.txt
-@@ -21,10 +21,17 @@ PROPERTIES
- the register region. An optional second element specifies
- the base address and size of the alias register region.
-
-+- clock-output-names:
-+ Usage: optional
-+ Value type: <string>
-+ Definition: Name of the output clock. Typically acpuX_aux where X is a
-+ CPU number starting at 0.
-+
- Example:
-
- clock-controller@2088000 {
- compatible = "qcom,kpss-acc-v2";
- reg = <0x02088000 0x1000>,
- <0x02008000 0x1000>;
-+ clock-output-names = "acpu0_aux";
- };
---- /dev/null
-+++ b/Documentation/devicetree/bindings/arm/msm/qcom,kpss-gcc.txt
-@@ -0,0 +1,28 @@
-+Krait Processor Sub-system (KPSS) Global Clock Controller (GCC)
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>
-+ Definition: should be one of:
-+ "qcom,kpss-gcc"
-+
-+- reg:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: base address and size of the register region
-+
-+- clock-output-names:
-+ Usage: required
-+ Value type: <string>
-+ Definition: Name of the output clock. Typically acpu_l2_aux indicating
-+ an L2 cache auxiliary clock.
-+
-+Example:
-+
-+ l2cc: clock-controller@2011000 {
-+ compatible = "qcom,kpss-gcc";
-+ reg = <0x2011000 0x1000>;
-+ clock-output-names = "acpu_l2_aux";
-+ };
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -106,6 +106,14 @@ config QCOM_HFPLL
- Say Y if you want to support CPU frequency scaling on devices
- such as MSM8974, APQ8084, etc.
-
-+config KPSS_XCC
-+ tristate "KPSS Clock Controller"
-+ depends on COMMON_CLK_QCOM
-+ help
-+ Support for the Krait ACC and GCC clock controllers. Say Y
-+ if you want to support CPU frequency scaling on devices such
-+ as MSM8960, APQ8064, etc.
-+
- config KRAIT_CLOCKS
- bool
- select KRAIT_L2_ACCESSORS
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -23,4 +23,5 @@ obj-$(CONFIG_MSM_LCC_8960) += lcc-msm896
- obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
- obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
- obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
-+obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
- obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
---- /dev/null
-+++ b/drivers/clk/qcom/kpss-xcc.c
-@@ -0,0 +1,95 @@
-+/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+
-+static const char *aux_parents[] = {
-+ "pll8_vote",
-+ "pxo",
-+};
-+
-+static unsigned int aux_parent_map[] = {
-+ 3,
-+ 0,
-+};
-+
-+static const struct of_device_id kpss_xcc_match_table[] = {
-+ { .compatible = "qcom,kpss-acc-v1", .data = (void *)1UL },
-+ { .compatible = "qcom,kpss-gcc" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, kpss_xcc_match_table);
-+
-+static int kpss_xcc_driver_probe(struct platform_device *pdev)
-+{
-+ const struct of_device_id *id;
-+ struct clk *clk;
-+ struct resource *res;
-+ void __iomem *base;
-+ const char *name;
-+
-+ id = of_match_device(kpss_xcc_match_table, &pdev->dev);
-+ if (!id)
-+ return -ENODEV;
-+
-+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ base = devm_ioremap_resource(&pdev->dev, res);
-+ if (IS_ERR(base))
-+ return PTR_ERR(base);
-+
-+ if (id->data) {
-+ if (of_property_read_string_index(pdev->dev.of_node,
-+ "clock-output-names", 0, &name))
-+ return -ENODEV;
-+ base += 0x14;
-+ } else {
-+ name = "acpu_l2_aux";
-+ base += 0x28;
-+ }
-+
-+ clk = clk_register_mux_table(&pdev->dev, name, aux_parents,
-+ ARRAY_SIZE(aux_parents), 0, base, 0, 0x3,
-+ 0, aux_parent_map, NULL);
-+
-+ platform_set_drvdata(pdev, clk);
-+
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static int kpss_xcc_driver_remove(struct platform_device *pdev)
-+{
-+ clk_unregister_mux(platform_get_drvdata(pdev));
-+ return 0;
-+}
-+
-+static struct platform_driver kpss_xcc_driver = {
-+ .probe = kpss_xcc_driver_probe,
-+ .remove = kpss_xcc_driver_remove,
-+ .driver = {
-+ .name = "kpss-xcc",
-+ .of_match_table = kpss_xcc_match_table,
-+ },
-+};
-+module_platform_driver(kpss_xcc_driver);
-+
-+MODULE_DESCRIPTION("Krait Processor Sub System (KPSS) Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:kpss-xcc");
diff --git a/target/linux/ipq806x/patches-4.1/142-clk-qcom-Add-Krait-clock-controller-driver.patch b/target/linux/ipq806x/patches-4.1/142-clk-qcom-Add-Krait-clock-controller-driver.patch
deleted file mode 100644
index 59fc44f1cb..0000000000
--- a/target/linux/ipq806x/patches-4.1/142-clk-qcom-Add-Krait-clock-controller-driver.patch
+++ /dev/null
@@ -1,435 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,11/13] clk: qcom: Add Krait clock controller driver
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063121
-Message-Id: <1426920332-9340-12-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>, <devicetree@vger.kernel.org>
-Date: Fri, 20 Mar 2015 23:45:30 -0700
-
-The Krait CPU clocks are made up of a primary mux and secondary
-mux for each CPU and the L2, controlled via cp15 accessors. For
-Kraits within KPSSv1 each secondary mux accepts a different aux
-source, but on KPSSv2 each secondary mux accepts the same aux
-source.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-.../devicetree/bindings/clock/qcom,krait-cc.txt | 22 ++
- drivers/clk/qcom/Kconfig | 8 +
- drivers/clk/qcom/Makefile | 1 +
- drivers/clk/qcom/krait-cc.c | 352 +++++++++++++++++++++
- 4 files changed, 383 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
- create mode 100644 drivers/clk/qcom/krait-cc.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/clock/qcom,krait-cc.txt
-@@ -0,0 +1,22 @@
-+Krait Clock Controller
-+
-+PROPERTIES
-+
-+- compatible:
-+ Usage: required
-+ Value type: <string>
-+ Definition: must be one of:
-+ "qcom,krait-cc-v1"
-+ "qcom,krait-cc-v2"
-+
-+- #clock-cells:
-+ Usage: required
-+ Value type: <u32>
-+ Definition: must be 1
-+
-+Example:
-+
-+ kraitcc: clock-controller {
-+ compatible = "qcom,krait-cc-v1";
-+ #clock-cells = <1>;
-+ };
---- a/drivers/clk/qcom/Kconfig
-+++ b/drivers/clk/qcom/Kconfig
-@@ -114,6 +114,14 @@ config KPSS_XCC
- if you want to support CPU frequency scaling on devices such
- as MSM8960, APQ8064, etc.
-
-+config KRAITCC
-+ tristate "Krait Clock Controller"
-+ depends on COMMON_CLK_QCOM && ARM
-+ select KRAIT_CLOCKS
-+ help
-+ Support for the Krait CPU clocks on Qualcomm devices.
-+ Say Y if you want to support CPU frequency scaling.
-+
- config KRAIT_CLOCKS
- bool
- select KRAIT_L2_ACCESSORS
---- a/drivers/clk/qcom/Makefile
-+++ b/drivers/clk/qcom/Makefile
-@@ -25,3 +25,4 @@ obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8
- obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
- obj-$(CONFIG_KPSS_XCC) += kpss-xcc.o
- obj-$(CONFIG_QCOM_HFPLL) += hfpll.o
-+obj-$(CONFIG_KRAITCC) += krait-cc.o
---- /dev/null
-+++ b/drivers/clk/qcom/krait-cc.c
-@@ -0,0 +1,352 @@
-+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/init.h>
-+#include <linux/module.h>
-+#include <linux/platform_device.h>
-+#include <linux/err.h>
-+#include <linux/io.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/clk.h>
-+#include <linux/clk-provider.h>
-+#include <linux/slab.h>
-+
-+#include "clk-krait.h"
-+
-+static unsigned int sec_mux_map[] = {
-+ 2,
-+ 0,
-+};
-+
-+static unsigned int pri_mux_map[] = {
-+ 1,
-+ 2,
-+ 0,
-+};
-+
-+static int
-+krait_add_div(struct device *dev, int id, const char *s, unsigned offset)
-+{
-+ struct krait_div2_clk *div;
-+ struct clk_init_data init = {
-+ .num_parents = 1,
-+ .ops = &krait_div2_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ const char *p_names[1];
-+ struct clk *clk;
-+
-+ div = devm_kzalloc(dev, sizeof(*div), GFP_KERNEL);
-+ if (!div)
-+ return -ENOMEM;
-+
-+ div->width = 2;
-+ div->shift = 6;
-+ div->lpl = id >= 0;
-+ div->offset = offset;
-+ div->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
-+ if (!init.name)
-+ return -ENOMEM;
-+
-+ init.parent_names = p_names;
-+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
-+ if (!p_names[0]) {
-+ kfree(init.name);
-+ return -ENOMEM;
-+ }
-+
-+ clk = devm_clk_register(dev, &div->hw);
-+ kfree(p_names[0]);
-+ kfree(init.name);
-+
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static int
-+krait_add_sec_mux(struct device *dev, int id, const char *s, unsigned offset,
-+ bool unique_aux)
-+{
-+ struct krait_mux_clk *mux;
-+ static const char *sec_mux_list[] = {
-+ "acpu_aux",
-+ "qsb",
-+ };
-+ struct clk_init_data init = {
-+ .parent_names = sec_mux_list,
-+ .num_parents = ARRAY_SIZE(sec_mux_list),
-+ .ops = &krait_mux_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ struct clk *clk;
-+
-+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
-+ if (!mux)
-+ return -ENOMEM;
-+
-+ mux->offset = offset;
-+ mux->lpl = id >= 0;
-+ mux->has_safe_parent = true;
-+ mux->safe_sel = 2;
-+ mux->mask = 0x3;
-+ mux->shift = 2;
-+ mux->parent_map = sec_mux_map;
-+ mux->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
-+ if (!init.name)
-+ return -ENOMEM;
-+
-+ if (unique_aux) {
-+ sec_mux_list[0] = kasprintf(GFP_KERNEL, "acpu%s_aux", s);
-+ if (!sec_mux_list[0]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_aux;
-+ }
-+ }
-+
-+ clk = devm_clk_register(dev, &mux->hw);
-+
-+ if (unique_aux)
-+ kfree(sec_mux_list[0]);
-+err_aux:
-+ kfree(init.name);
-+ return PTR_ERR_OR_ZERO(clk);
-+}
-+
-+static struct clk *
-+krait_add_pri_mux(struct device *dev, int id, const char *s, unsigned offset)
-+{
-+ struct krait_mux_clk *mux;
-+ const char *p_names[3];
-+ struct clk_init_data init = {
-+ .parent_names = p_names,
-+ .num_parents = ARRAY_SIZE(p_names),
-+ .ops = &krait_mux_clk_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ };
-+ struct clk *clk;
-+
-+ mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL);
-+ if (!mux)
-+ return ERR_PTR(-ENOMEM);
-+
-+ mux->has_safe_parent = true;
-+ mux->safe_sel = 0;
-+ mux->mask = 0x3;
-+ mux->shift = 0;
-+ mux->offset = offset;
-+ mux->lpl = id >= 0;
-+ mux->parent_map = pri_mux_map;
-+ mux->hw.init = &init;
-+
-+ init.name = kasprintf(GFP_KERNEL, "krait%s_pri_mux", s);
-+ if (!init.name)
-+ return ERR_PTR(-ENOMEM);
-+
-+ p_names[0] = kasprintf(GFP_KERNEL, "hfpll%s", s);
-+ if (!p_names[0]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p0;
-+ }
-+
-+ p_names[1] = kasprintf(GFP_KERNEL, "hfpll%s_div", s);
-+ if (!p_names[1]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p1;
-+ }
-+
-+ p_names[2] = kasprintf(GFP_KERNEL, "krait%s_sec_mux", s);
-+ if (!p_names[2]) {
-+ clk = ERR_PTR(-ENOMEM);
-+ goto err_p2;
-+ }
-+
-+ clk = devm_clk_register(dev, &mux->hw);
-+
-+ kfree(p_names[2]);
-+err_p2:
-+ kfree(p_names[1]);
-+err_p1:
-+ kfree(p_names[0]);
-+err_p0:
-+ kfree(init.name);
-+ return clk;
-+}
-+
-+/* id < 0 for L2, otherwise id == physical CPU number */
-+static struct clk *krait_add_clks(struct device *dev, int id, bool unique_aux)
-+{
-+ int ret;
-+ unsigned offset;
-+ void *p = NULL;
-+ const char *s;
-+ struct clk *clk;
-+
-+ if (id >= 0) {
-+ offset = 0x4501 + (0x1000 * id);
-+ s = p = kasprintf(GFP_KERNEL, "%d", id);
-+ if (!s)
-+ return ERR_PTR(-ENOMEM);
-+ } else {
-+ offset = 0x500;
-+ s = "_l2";
-+ }
-+
-+ ret = krait_add_div(dev, id, s, offset);
-+ if (ret) {
-+ clk = ERR_PTR(ret);
-+ goto err;
-+ }
-+
-+ ret = krait_add_sec_mux(dev, id, s, offset, unique_aux);
-+ if (ret) {
-+ clk = ERR_PTR(ret);
-+ goto err;
-+ }
-+
-+ clk = krait_add_pri_mux(dev, id, s, offset);
-+err:
-+ kfree(p);
-+ return clk;
-+}
-+
-+static struct clk *krait_of_get(struct of_phandle_args *clkspec, void *data)
-+{
-+ unsigned int idx = clkspec->args[0];
-+ struct clk **clks = data;
-+
-+ if (idx >= 5) {
-+ pr_err("%s: invalid clock index %d\n", __func__, idx);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ return clks[idx] ? : ERR_PTR(-ENODEV);
-+}
-+
-+static const struct of_device_id krait_cc_match_table[] = {
-+ { .compatible = "qcom,krait-cc-v1", (void *)1UL },
-+ { .compatible = "qcom,krait-cc-v2" },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, krait_cc_match_table);
-+
-+static int krait_cc_probe(struct platform_device *pdev)
-+{
-+ struct device *dev = &pdev->dev;
-+ const struct of_device_id *id;
-+ unsigned long cur_rate, aux_rate;
-+ int cpu;
-+ struct clk *clk;
-+ struct clk **clks;
-+ struct clk *l2_pri_mux_clk;
-+
-+ id = of_match_device(krait_cc_match_table, dev);
-+ if (!id)
-+ return -ENODEV;
-+
-+ /* Rate is 1 because 0 causes problems for __clk_mux_determine_rate */
-+ clk = clk_register_fixed_rate(dev, "qsb", NULL, CLK_IS_ROOT, 1);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+
-+ if (!id->data) {
-+ clk = clk_register_fixed_factor(dev, "acpu_aux",
-+ "gpll0_vote", 0, 1, 2);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+ }
-+
-+ /* Krait configurations have at most 4 CPUs and one L2 */
-+ clks = devm_kcalloc(dev, 5, sizeof(*clks), GFP_KERNEL);
-+ if (!clks)
-+ return -ENOMEM;
-+
-+ for_each_possible_cpu(cpu) {
-+ clk = krait_add_clks(dev, cpu, id->data);
-+ if (IS_ERR(clk))
-+ return PTR_ERR(clk);
-+ clks[cpu] = clk;
-+ }
-+
-+ l2_pri_mux_clk = krait_add_clks(dev, -1, id->data);
-+ if (IS_ERR(l2_pri_mux_clk))
-+ return PTR_ERR(l2_pri_mux_clk);
-+ clks[4] = l2_pri_mux_clk;
-+
-+ /*
-+ * We don't want the CPU or L2 clocks to be turned off at late init
-+ * if CPUFREQ or HOTPLUG configs are disabled. So, bump up the
-+ * refcount of these clocks. Any cpufreq/hotplug manager can assume
-+ * that the clocks have already been prepared and enabled by the time
-+ * they take over.
-+ */
-+ for_each_online_cpu(cpu) {
-+ clk_prepare_enable(l2_pri_mux_clk);
-+ WARN(clk_prepare_enable(clks[cpu]),
-+ "Unable to turn on CPU%d clock", cpu);
-+ }
-+
-+ /*
-+ * Force reinit of HFPLLs and muxes to overwrite any potential
-+ * incorrect configuration of HFPLLs and muxes by the bootloader.
-+ * While at it, also make sure the cores are running at known rates
-+ * and print the current rate.
-+ *
-+ * The clocks are set to aux clock rate first to make sure the
-+ * secondary mux is not sourcing off of QSB. The rate is then set to
-+ * two different rates to force a HFPLL reinit under all
-+ * circumstances.
-+ */
-+ cur_rate = clk_get_rate(l2_pri_mux_clk);
-+ aux_rate = 384000000;
-+ if (cur_rate == 1) {
-+ pr_info("L2 @ QSB rate. Forcing new rate.\n");
-+ cur_rate = aux_rate;
-+ }
-+ clk_set_rate(l2_pri_mux_clk, aux_rate);
-+ clk_set_rate(l2_pri_mux_clk, 2);
-+ clk_set_rate(l2_pri_mux_clk, cur_rate);
-+ pr_info("L2 @ %lu KHz\n", clk_get_rate(l2_pri_mux_clk) / 1000);
-+ for_each_possible_cpu(cpu) {
-+ clk = clks[cpu];
-+ cur_rate = clk_get_rate(clk);
-+ if (cur_rate == 1) {
-+ pr_info("CPU%d @ QSB rate. Forcing new rate.\n", cpu);
-+ cur_rate = aux_rate;
-+ }
-+ clk_set_rate(clk, aux_rate);
-+ clk_set_rate(clk, 2);
-+ clk_set_rate(clk, cur_rate);
-+ pr_info("CPU%d @ %lu KHz\n", cpu, clk_get_rate(clk) / 1000);
-+ }
-+
-+ of_clk_add_provider(dev->of_node, krait_of_get, clks);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver krait_cc_driver = {
-+ .probe = krait_cc_probe,
-+ .driver = {
-+ .name = "krait-cc",
-+ .of_match_table = krait_cc_match_table,
-+ },
-+};
-+module_platform_driver(krait_cc_driver);
-+
-+MODULE_DESCRIPTION("Krait CPU Clock Driver");
-+MODULE_LICENSE("GPL v2");
-+MODULE_ALIAS("platform:krait-cc");
diff --git a/target/linux/ipq806x/patches-4.1/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch b/target/linux/ipq806x/patches-4.1/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
deleted file mode 100644
index fd37c05425..0000000000
--- a/target/linux/ipq806x/patches-4.1/143-cpufreq-Add-module-to-register-cpufreq-on-Krait-CPUs.patch
+++ /dev/null
@@ -1,304 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,12/13] cpufreq: Add module to register cpufreq on Krait CPUs
-From: Stephen Boyd <sboyd@codeaurora.org>
-X-Patchwork-Id: 6063191
-Message-Id: <1426920332-9340-13-git-send-email-sboyd@codeaurora.org>
-To: Mike Turquette <mturquette@linaro.org>, Stephen Boyd <sboyd@codeaurora.org>
-Cc: linux-kernel@vger.kernel.org, linux-arm-msm@vger.kernel.org,
- linux-pm@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
- Viresh Kumar <viresh.kumar@linaro.org>, <devicetree@vger.kernel.org>
-Date: Fri, 20 Mar 2015 23:45:31 -0700
-
-Register a cpufreq-generic device whenever we detect that a
-"qcom,krait" compatible CPU is present in DT.
-
-Cc: <devicetree@vger.kernel.org>
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
-.../devicetree/bindings/arm/msm/qcom,pvs.txt | 38 ++++
- drivers/cpufreq/Kconfig.arm | 9 +
- drivers/cpufreq/Makefile | 1 +
- drivers/cpufreq/qcom-cpufreq.c | 204 +++++++++++++++++++++
- 4 files changed, 252 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
- create mode 100644 drivers/cpufreq/qcom-cpufreq.c
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/arm/msm/qcom,pvs.txt
-@@ -0,0 +1,38 @@
-+Qualcomm Process Voltage Scaling Tables
-+
-+The node name is required to be "qcom,pvs". There shall only be one
-+such node present in the root of the tree.
-+
-+PROPERTIES
-+
-+- qcom,pvs-format-a or qcom,pvs-format-b:
-+ Usage: required
-+ Value type: <empty>
-+ Definition: Indicates the format of qcom,speedX-pvsY-bin-vZ properties.
-+ If qcom,pvs-format-a is used the table is two columns
-+ (frequency and voltage in that order). If qcom,pvs-format-b is used the table is three columns (frequency, voltage,
-+ and current in that order).
-+
-+- qcom,speedX-pvsY-bin-vZ:
-+ Usage: required
-+ Value type: <prop-encoded-array>
-+ Definition: The PVS table corresponding to the speed bin X, pvs bin Y,
-+ and version Z.
-+Example:
-+
-+ qcom,pvs {
-+ qcom,pvs-format-a;
-+ qcom,speed0-pvs0-bin-v0 =
-+ < 384000000 950000 >,
-+ < 486000000 975000 >,
-+ < 594000000 1000000 >,
-+ < 702000000 1025000 >,
-+ < 810000000 1075000 >,
-+ < 918000000 1100000 >,
-+ < 1026000000 1125000 >,
-+ < 1134000000 1175000 >,
-+ < 1242000000 1200000 >,
-+ < 1350000000 1225000 >,
-+ < 1458000000 1237500 >,
-+ < 1512000000 1250000 >;
-+ };
---- a/drivers/cpufreq/Kconfig.arm
-+++ b/drivers/cpufreq/Kconfig.arm
-@@ -146,6 +146,15 @@ config ARM_OMAP2PLUS_CPUFREQ
- depends on ARCH_OMAP2PLUS
- default ARCH_OMAP2PLUS
-
-+config ARM_QCOM_CPUFREQ
-+ tristate "Qualcomm based"
-+ depends on ARCH_QCOM
-+ select PM_OPP
-+ help
-+ This adds the CPUFreq driver for Qualcomm SoC based boards.
-+
-+ If in doubt, say N.
-+
- config ARM_S3C_CPUFREQ
- bool
- help
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -66,6 +66,7 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += ki
- obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
- obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
- obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
-+obj-$(CONFIG_ARM_QCOM_CPUFREQ) += qcom-cpufreq.o
- obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o
- obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
- obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o
---- /dev/null
-+++ b/drivers/cpufreq/qcom-cpufreq.c
-@@ -0,0 +1,204 @@
-+/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/cpu.h>
-+#include <linux/err.h>
-+#include <linux/init.h>
-+#include <linux/io.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+#include <linux/pm_opp.h>
-+#include <linux/slab.h>
-+#include <linux/cpufreq-dt.h>
-+
-+static void __init get_krait_bin_format_a(int *speed, int *pvs, int *pvs_ver)
-+{
-+ void __iomem *base;
-+ u32 pte_efuse;
-+
-+ *speed = *pvs = *pvs_ver = 0;
-+
-+ base = ioremap(0x007000c0, 4);
-+ if (!base) {
-+ pr_warn("Unable to read efuse data. Defaulting to 0!\n");
-+ return;
-+ }
-+
-+ pte_efuse = readl_relaxed(base);
-+ iounmap(base);
-+
-+ *speed = pte_efuse & 0xf;
-+ if (*speed == 0xf)
-+ *speed = (pte_efuse >> 4) & 0xf;
-+
-+ if (*speed == 0xf) {
-+ *speed = 0;
-+ pr_warn("Speed bin: Defaulting to %d\n", *speed);
-+ } else {
-+ pr_info("Speed bin: %d\n", *speed);
-+ }
-+
-+ *pvs = (pte_efuse >> 10) & 0x7;
-+ if (*pvs == 0x7)
-+ *pvs = (pte_efuse >> 13) & 0x7;
-+
-+ if (*pvs == 0x7) {
-+ *pvs = 0;
-+ pr_warn("PVS bin: Defaulting to %d\n", *pvs);
-+ } else {
-+ pr_info("PVS bin: %d\n", *pvs);
-+ }
-+}
-+
-+static void __init get_krait_bin_format_b(int *speed, int *pvs, int *pvs_ver)
-+{
-+ u32 pte_efuse, redundant_sel;
-+ void __iomem *base;
-+
-+ *speed = 0;
-+ *pvs = 0;
-+ *pvs_ver = 0;
-+
-+ base = ioremap(0xfc4b80b0, 8);
-+ if (!base) {
-+ pr_warn("Unable to read efuse data. Defaulting to 0!\n");
-+ return;
-+ }
-+
-+ pte_efuse = readl_relaxed(base);
-+ redundant_sel = (pte_efuse >> 24) & 0x7;
-+ *speed = pte_efuse & 0x7;
-+ /* 4 bits of PVS are in efuse register bits 31, 8-6. */
-+ *pvs = ((pte_efuse >> 28) & 0x8) | ((pte_efuse >> 6) & 0x7);
-+ *pvs_ver = (pte_efuse >> 4) & 0x3;
-+
-+ switch (redundant_sel) {
-+ case 1:
-+ *speed = (pte_efuse >> 27) & 0xf;
-+ break;
-+ case 2:
-+ *pvs = (pte_efuse >> 27) & 0xf;
-+ break;
-+ }
-+
-+ /* Check SPEED_BIN_BLOW_STATUS */
-+ if (pte_efuse & BIT(3)) {
-+ pr_info("Speed bin: %d\n", *speed);
-+ } else {
-+ pr_warn("Speed bin not set. Defaulting to 0!\n");
-+ *speed = 0;
-+ }
-+
-+ /* Check PVS_BLOW_STATUS */
-+ pte_efuse = readl_relaxed(base + 0x4) & BIT(21);
-+ if (pte_efuse) {
-+ pr_info("PVS bin: %d\n", *pvs);
-+ } else {
-+ pr_warn("PVS bin not set. Defaulting to 0!\n");
-+ *pvs = 0;
-+ }
-+
-+ pr_info("PVS version: %d\n", *pvs_ver);
-+ iounmap(base);
-+}
-+
-+static int __init qcom_cpufreq_populate_opps(void)
-+{
-+ int len, rows, cols, i, k, speed, pvs, pvs_ver;
-+ char table_name[] = "qcom,speedXX-pvsXX-bin-vXX";
-+ struct device_node *np;
-+ struct device *dev;
-+ int cpu = 0;
-+
-+ np = of_find_node_by_name(NULL, "qcom,pvs");
-+ if (!np)
-+ return -ENODEV;
-+
-+ if (of_property_read_bool(np, "qcom,pvs-format-a")) {
-+ get_krait_bin_format_a(&speed, &pvs, &pvs_ver);
-+ cols = 2;
-+ } else if (of_property_read_bool(np, "qcom,pvs-format-b")) {
-+ get_krait_bin_format_b(&speed, &pvs, &pvs_ver);
-+ cols = 3;
-+ } else {
-+ return -ENODEV;
-+ }
-+
-+ snprintf(table_name, sizeof(table_name),
-+ "qcom,speed%d-pvs%d-bin-v%d", speed, pvs, pvs_ver);
-+
-+ if (!of_find_property(np, table_name, &len))
-+ return -EINVAL;
-+
-+ len /= sizeof(u32);
-+ if (len % cols || len == 0)
-+ return -EINVAL;
-+
-+ rows = len / cols;
-+
-+ for (i = 0, k = 0; i < rows; i++) {
-+ u32 freq, volt;
-+
-+ of_property_read_u32_index(np, table_name, k++, &freq);
-+ of_property_read_u32_index(np, table_name, k++, &volt);
-+ while (k % cols)
-+ k++; /* Skip uA entries if present */
-+ for (cpu = 0; cpu < num_possible_cpus(); cpu++) {
-+ dev = get_cpu_device(cpu);
-+ if (!dev)
-+ return -ENODEV;
-+ if (dev_pm_opp_add(dev, freq, volt))
-+ pr_warn("failed to add OPP %u\n", freq);
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+static int __init qcom_cpufreq_driver_init(void)
-+{
-+ struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
-+ struct platform_device_info devinfo = {
-+ .name = "cpufreq-dt",
-+ .data = &pdata,
-+ .size_data = sizeof(pdata),
-+ };
-+ struct device *cpu_dev;
-+ struct device_node *np;
-+ int ret;
-+
-+ cpu_dev = get_cpu_device(0);
-+ if (!cpu_dev)
-+ return -ENODEV;
-+
-+ np = of_node_get(cpu_dev->of_node);
-+ if (!np)
-+ return -ENOENT;
-+
-+ if (!of_device_is_compatible(np, "qcom,krait")) {
-+ of_node_put(np);
-+ return -ENODEV;
-+ }
-+ of_node_put(np);
-+
-+ ret = qcom_cpufreq_populate_opps();
-+ if (ret)
-+ return ret;
-+
-+ return PTR_ERR_OR_ZERO(platform_device_register_full(&devinfo));
-+}
-+module_init(qcom_cpufreq_driver_init);
-+
-+MODULE_DESCRIPTION("Qualcomm CPUfreq driver");
-+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/ipq806x/patches-4.1/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch b/target/linux/ipq806x/patches-4.1/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch
deleted file mode 100644
index aaf140126c..0000000000
--- a/target/linux/ipq806x/patches-4.1/144-ARM-dts-qcom-Add-necessary-DT-data-for-Krait-cpufreq.patch
+++ /dev/null
@@ -1,100 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -26,6 +26,11 @@
- next-level-cache = <&L2>;
- qcom,acc = <&acc0>;
- qcom,saw = <&saw0>;
-+ clocks = <&kraitcc 0>;
-+ clock-names = "cpu";
-+ clock-latency = <100000>;
-+ core-supply = <&smb208_s2a>;
-+ voltage-tolerance = <5>;
- };
-
- cpu@1 {
-@@ -36,11 +41,24 @@
- next-level-cache = <&L2>;
- qcom,acc = <&acc1>;
- qcom,saw = <&saw1>;
-+ clocks = <&kraitcc 1>;
-+ clock-names = "cpu";
-+ clock-latency = <100000>;
-+ core-supply = <&smb208_s2b>;
- };
-
- L2: l2-cache {
- compatible = "cache";
- cache-level = <2>;
-+ clocks = <&kraitcc 4>;
-+ clock-names = "cache";
-+ cache-points-kHz = <
-+ /* kHz uV CPU kHz */
-+ 1200000 1150000 1200000
-+ 1000000 1100000 600000
-+ 384000 1100000 384000
-+ >;
-+ vdd_dig-supply = <&smb208_s1a>;
- };
- };
-
-@@ -73,6 +91,46 @@
- };
- };
-
-+ kraitcc: clock-controller {
-+ compatible = "qcom,krait-cc-v1";
-+ #clock-cells = <1>;
-+ };
-+
-+ qcom,pvs {
-+ qcom,pvs-format-a;
-+ qcom,speed0-pvs0-bin-v0 =
-+ < 1400000000 1250000 >,
-+ < 1200000000 1200000 >,
-+ < 1000000000 1150000 >,
-+ < 800000000 1100000 >,
-+ < 600000000 1050000 >,
-+ < 384000000 1000000 >;
-+
-+ qcom,speed0-pvs1-bin-v0 =
-+ < 1400000000 1175000 >,
-+ < 1200000000 1125000 >,
-+ < 1000000000 1075000 >,
-+ < 800000000 1025000 >,
-+ < 600000000 975000 >,
-+ < 384000000 925000 >;
-+
-+ qcom,speed0-pvs2-bin-v0 =
-+ < 1400000000 1125000 >,
-+ < 1200000000 1075000 >,
-+ < 1000000000 1025000 >,
-+ < 800000000 995000 >,
-+ < 600000000 925000 >,
-+ < 384000000 875000 >;
-+
-+ qcom,speed0-pvs3-bin-v0 =
-+ < 1400000000 1050000 >,
-+ < 1200000000 1000000 >,
-+ < 1000000000 950000 >,
-+ < 800000000 900000 >,
-+ < 600000000 850000 >,
-+ < 384000000 800000 >;
-+ };
-+
- soc: soc {
- #address-cells = <1>;
- #size-cells = <1>;
-@@ -215,11 +273,13 @@
- acc0: clock-controller@2088000 {
- compatible = "qcom,kpss-acc-v1";
- reg = <0x02088000 0x1000>, <0x02008000 0x1000>;
-+ clock-output-names = "acpu0_aux";
- };
-
- acc1: clock-controller@2098000 {
- compatible = "qcom,kpss-acc-v1";
- reg = <0x02098000 0x1000>, <0x02008000 0x1000>;
-+ clock-output-names = "acpu1_aux";
- };
-
- l2cc: clock-controller@2011000 {
diff --git a/target/linux/ipq806x/patches-4.1/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch b/target/linux/ipq806x/patches-4.1/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch
deleted file mode 100644
index 84f856bbf6..0000000000
--- a/target/linux/ipq806x/patches-4.1/145-cpufreq-Add-a-cpufreq-krait-based-on-cpufre.patch
+++ /dev/null
@@ -1,461 +0,0 @@
-From dd77db4143290689d3a5e1ec61627233d0711b66 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Fri, 30 May 2014 16:36:11 -0700
-Subject: [PATCH] FROMLIST: cpufreq: Add a cpufreq-krait based on cpufreq-cpu0
-
-Krait processors have individual clocks for each CPU that can
-scale independently from one another. cpufreq-cpu0 is fairly
-close to this, but assumes that there is only one clock for all
-CPUs. Add a driver to support the Krait configuration.
-
-TODO: Merge into cpufreq-cpu0? Or make generic?
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
-
----
- drivers/cpufreq/Kconfig | 13 +++
- drivers/cpufreq/Makefile | 1 +
- drivers/cpufreq/cpufreq-krait.c | 190 ++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 204 insertions(+)
- create mode 100644 drivers/cpufreq/cpufreq-krait.c
-
---- a/drivers/cpufreq/Kconfig
-+++ b/drivers/cpufreq/Kconfig
-@@ -198,6 +198,19 @@ config CPUFREQ_DT
-
- If in doubt, say N.
-
-+config GENERIC_CPUFREQ_KRAIT
-+ tristate "Krait cpufreq driver"
-+ depends on HAVE_CLK && OF
-+ # if CPU_THERMAL is on and THERMAL=m, CPU0 cannot be =y:
-+ depends on !CPU_THERMAL || THERMAL
-+ select PM_OPP
-+ help
-+ This adds a generic cpufreq driver for CPU0 frequency management.
-+ It supports both uniprocessor (UP) and symmetric multiprocessor (SMP)
-+ systems which share clock and voltage across all CPUs.
-+
-+ If in doubt, say N.
-+
- if X86
- source "drivers/cpufreq/Kconfig.x86"
- endif
---- a/drivers/cpufreq/Makefile
-+++ b/drivers/cpufreq/Makefile
-@@ -14,6 +14,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE)
- obj-$(CONFIG_CPU_FREQ_GOV_COMMON) += cpufreq_governor.o
-
- obj-$(CONFIG_CPUFREQ_DT) += cpufreq-dt.o
-+obj-$(CONFIG_GENERIC_CPUFREQ_KRAIT) += cpufreq-krait.o
-
- ##################################################################################
- # x86 drivers.
---- /dev/null
-+++ b/drivers/cpufreq/cpufreq-krait.c
-@@ -0,0 +1,390 @@
-+/*
-+ * Copyright (C) 2012 Freescale Semiconductor, Inc.
-+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
-+ *
-+ * The OPP code in function krait_set_target() is reused from
-+ * drivers/cpufreq/omap-cpufreq.c
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/cpu.h>
-+#include <linux/cpu_cooling.h>
-+#include <linux/cpufreq.h>
-+#include <linux/cpumask.h>
-+#include <linux/err.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/pm_opp.h>
-+#include <linux/platform_device.h>
-+#include <linux/regulator/consumer.h>
-+#include <linux/slab.h>
-+#include <linux/thermal.h>
-+
-+static unsigned int transition_latency;
-+static unsigned int voltage_tolerance; /* in percentage */
-+
-+static struct device *cpu_dev;
-+static DEFINE_PER_CPU(struct clk *, krait_cpu_clks);
-+static DEFINE_PER_CPU(struct regulator *, krait_supply_core);
-+static struct cpufreq_frequency_table *freq_table;
-+static struct thermal_cooling_device *cdev;
-+
-+struct cache_points {
-+ unsigned long cache_freq;
-+ unsigned int cache_volt;
-+ unsigned long cpu_freq;
-+};
-+
-+static struct regulator *krait_l2_reg;
-+static struct clk *krait_l2_clk;
-+static struct cache_points *krait_l2_points;
-+static int nr_krait_l2_points;
-+
-+static int krait_parse_cache_points(struct device *dev,
-+ struct device_node *of_node)
-+{
-+ const struct property *prop;
-+ const __be32 *val;
-+ int nr, i;
-+
-+ prop = of_find_property(of_node, "cache-points-kHz", NULL);
-+ if (!prop)
-+ return -ENODEV;
-+ if (!prop->value)
-+ return -ENODATA;
-+
-+ /*
-+ * Each OPP is a set of tuples consisting of frequency and
-+ * cpu-frequency like <freq-kHz volt-uV freq-kHz>.
-+ */
-+ nr = prop->length / sizeof(u32);
-+ if (nr % 3) {
-+ dev_err(dev, "%s: Invalid cache points\n", __func__);
-+ return -EINVAL;
-+ }
-+ nr /= 3;
-+
-+ krait_l2_points = devm_kcalloc(dev, nr, sizeof(*krait_l2_points),
-+ GFP_KERNEL);
-+ if (!krait_l2_points)
-+ return -ENOMEM;
-+ nr_krait_l2_points = nr;
-+
-+ for (i = 0, val = prop->value; i < nr; i++) {
-+ unsigned long cache_freq = be32_to_cpup(val++) * 1000;
-+ unsigned int cache_volt = be32_to_cpup(val++);
-+ unsigned long cpu_freq = be32_to_cpup(val++) * 1000;
-+
-+ krait_l2_points[i].cache_freq = cache_freq;
-+ krait_l2_points[i].cache_volt = cache_volt;
-+ krait_l2_points[i].cpu_freq = cpu_freq;
-+ }
-+
-+ return 0;
-+}
-+
-+static int krait_set_target(struct cpufreq_policy *policy, unsigned int index)
-+{
-+ struct dev_pm_opp *opp;
-+ unsigned long volt = 0, volt_old = 0, tol = 0;
-+ unsigned long freq, max_cpu_freq = 0;
-+ unsigned int old_freq, new_freq;
-+ long freq_Hz, freq_exact;
-+ int ret, i;
-+ struct clk *cpu_clk;
-+ struct regulator *core;
-+ unsigned int cpu;
-+
-+ cpu_clk = per_cpu(krait_cpu_clks, policy->cpu);
-+
-+ freq_Hz = clk_round_rate(cpu_clk, freq_table[index].frequency * 1000);
-+ if (freq_Hz <= 0)
-+ freq_Hz = freq_table[index].frequency * 1000;
-+
-+ freq_exact = freq_Hz;
-+ new_freq = freq_Hz / 1000;
-+ old_freq = clk_get_rate(cpu_clk) / 1000;
-+
-+ core = per_cpu(krait_supply_core, policy->cpu);
-+
-+ rcu_read_lock();
-+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
-+ if (IS_ERR(opp)) {
-+ rcu_read_unlock();
-+ pr_err("failed to find OPP for %ld\n", freq_Hz);
-+ return PTR_ERR(opp);
-+ }
-+ volt = dev_pm_opp_get_voltage(opp);
-+ rcu_read_unlock();
-+ tol = volt * voltage_tolerance / 100;
-+ volt_old = regulator_get_voltage(core);
-+
-+ pr_debug("%u MHz, %ld mV --> %u MHz, %ld mV\n",
-+ old_freq / 1000, volt_old ? volt_old / 1000 : -1,
-+ new_freq / 1000, volt ? volt / 1000 : -1);
-+
-+ /* scaling up? scale voltage before frequency */
-+ if (new_freq > old_freq) {
-+ ret = regulator_set_voltage_tol(core, volt, tol);
-+ if (ret) {
-+ pr_err("failed to scale voltage up: %d\n", ret);
-+ return ret;
-+ }
-+ }
-+
-+ ret = clk_set_rate(cpu_clk, freq_exact);
-+ if (ret) {
-+ pr_err("failed to set clock rate: %d\n", ret);
-+ return ret;
-+ }
-+
-+ /* scaling down? scale voltage after frequency */
-+ if (new_freq < old_freq) {
-+ ret = regulator_set_voltage_tol(core, volt, tol);
-+ if (ret) {
-+ pr_err("failed to scale voltage down: %d\n", ret);
-+ clk_set_rate(cpu_clk, old_freq * 1000);
-+ }
-+ }
-+
-+ for_each_possible_cpu(cpu) {
-+ freq = clk_get_rate(per_cpu(krait_cpu_clks, cpu));
-+ max_cpu_freq = max(max_cpu_freq, freq);
-+ }
-+
-+ for (i = 0; i < nr_krait_l2_points; i++) {
-+ if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
-+ if (krait_l2_reg) {
-+ ret = regulator_set_voltage_tol(krait_l2_reg,
-+ krait_l2_points[i].cache_volt,
-+ tol);
-+ if (ret) {
-+ pr_err("failed to scale l2 voltage: %d\n",
-+ ret);
-+ }
-+ }
-+ ret = clk_set_rate(krait_l2_clk,
-+ krait_l2_points[i].cache_freq);
-+ if (ret)
-+ pr_err("failed to scale l2 clk: %d\n", ret);
-+ break;
-+ }
-+
-+ }
-+
-+ return ret;
-+}
-+
-+static int krait_cpufreq_init(struct cpufreq_policy *policy)
-+{
-+ int ret;
-+
-+ policy->clk = per_cpu(krait_cpu_clks, policy->cpu);
-+
-+ ret = cpufreq_table_validate_and_show(policy, freq_table);
-+ if (ret) {
-+ pr_err("%s: invalid frequency table: %d\n", __func__, ret);
-+ return ret;
-+ }
-+
-+ policy->cpuinfo.transition_latency = transition_latency;
-+
-+ return 0;
-+}
-+
-+static struct cpufreq_driver krait_cpufreq_driver = {
-+ .flags = CPUFREQ_STICKY,
-+ .verify = cpufreq_generic_frequency_table_verify,
-+ .target_index = krait_set_target,
-+ .get = cpufreq_generic_get,
-+ .init = krait_cpufreq_init,
-+ .name = "generic_krait",
-+ .attr = cpufreq_generic_attr,
-+};
-+
-+static int krait_cpufreq_probe(struct platform_device *pdev)
-+{
-+ struct device_node *np, *cache;
-+ int ret, i;
-+ unsigned int cpu;
-+ struct device *dev;
-+ struct clk *clk;
-+ struct regulator *core;
-+ unsigned long freq_Hz, freq, max_cpu_freq = 0;
-+ struct dev_pm_opp *opp;
-+ unsigned long volt, tol;
-+
-+ cpu_dev = get_cpu_device(0);
-+ if (!cpu_dev) {
-+ pr_err("failed to get krait device\n");
-+ return -ENODEV;
-+ }
-+
-+ np = of_node_get(cpu_dev->of_node);
-+ if (!np) {
-+ pr_err("failed to find krait node\n");
-+ return -ENOENT;
-+ }
-+
-+ ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
-+ if (ret) {
-+ pr_err("failed to init cpufreq table: %d\n", ret);
-+ goto out_put_node;
-+ }
-+
-+ of_property_read_u32(np, "voltage-tolerance", &voltage_tolerance);
-+
-+ if (of_property_read_u32(np, "clock-latency", &transition_latency))
-+ transition_latency = CPUFREQ_ETERNAL;
-+
-+ cache = of_find_next_cache_node(np);
-+ if (cache) {
-+ struct device_node *vdd;
-+
-+ vdd = of_parse_phandle(cache, "vdd_dig-supply", 0);
-+ if (vdd) {
-+ krait_l2_reg = regulator_get(NULL, vdd->name);
-+ if (IS_ERR(krait_l2_reg)) {
-+ pr_warn("failed to get l2 vdd_dig supply\n");
-+ krait_l2_reg = NULL;
-+ }
-+ of_node_put(vdd);
-+ }
-+
-+ krait_l2_clk = of_clk_get(cache, 0);
-+ if (!IS_ERR(krait_l2_clk)) {
-+ ret = krait_parse_cache_points(&pdev->dev, cache);
-+ if (ret)
-+ clk_put(krait_l2_clk);
-+ }
-+ if (IS_ERR(krait_l2_clk) || ret)
-+ krait_l2_clk = NULL;
-+ }
-+
-+ for_each_possible_cpu(cpu) {
-+ dev = get_cpu_device(cpu);
-+ if (!dev) {
-+ pr_err("failed to get krait device\n");
-+ ret = -ENOENT;
-+ goto out_free_table;
-+ }
-+ per_cpu(krait_cpu_clks, cpu) = clk = devm_clk_get(dev, NULL);
-+ if (IS_ERR(clk)) {
-+ ret = PTR_ERR(clk);
-+ goto out_free_table;
-+ }
-+ core = devm_regulator_get(dev, "core");
-+ if (IS_ERR(core)) {
-+ pr_debug("failed to get core regulator\n");
-+ ret = PTR_ERR(core);
-+ goto out_free_table;
-+ }
-+ per_cpu(krait_supply_core, cpu) = core;
-+
-+ freq = freq_Hz = clk_get_rate(clk);
-+
-+ rcu_read_lock();
-+ opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
-+ if (IS_ERR(opp)) {
-+ rcu_read_unlock();
-+ pr_err("failed to find OPP for %ld\n", freq_Hz);
-+ ret = PTR_ERR(opp);
-+ goto out_free_table;
-+ }
-+ volt = dev_pm_opp_get_voltage(opp);
-+ rcu_read_unlock();
-+
-+ tol = volt * voltage_tolerance / 100;
-+ ret = regulator_set_voltage_tol(core, volt, tol);
-+ if (ret) {
-+ pr_err("failed to scale voltage up: %d\n", ret);
-+ goto out_free_table;
-+ }
-+ ret = regulator_enable(core);
-+ if (ret) {
-+ pr_err("failed to enable regulator: %d\n", ret);
-+ goto out_free_table;
-+ }
-+ max_cpu_freq = max(max_cpu_freq, freq);
-+ }
-+
-+ for (i = 0; i < nr_krait_l2_points; i++) {
-+ if (max_cpu_freq >= krait_l2_points[i].cpu_freq) {
-+ if (krait_l2_reg) {
-+ ret = regulator_set_voltage_tol(krait_l2_reg,
-+ krait_l2_points[i].cache_volt,
-+ tol);
-+ if (ret)
-+ pr_err("failed to scale l2 voltage: %d\n",
-+ ret);
-+ ret = regulator_enable(krait_l2_reg);
-+ if (ret)
-+ pr_err("failed to enable l2 voltage: %d\n",
-+ ret);
-+ }
-+ break;
-+ }
-+
-+ }
-+
-+ ret = cpufreq_register_driver(&krait_cpufreq_driver);
-+ if (ret) {
-+ pr_err("failed register driver: %d\n", ret);
-+ goto out_free_table;
-+ }
-+ of_node_put(np);
-+
-+ /*
-+ * For now, just loading the cooling device;
-+ * thermal DT code takes care of matching them.
-+ */
-+ for_each_possible_cpu(cpu) {
-+ dev = get_cpu_device(cpu);
-+ np = of_node_get(dev->of_node);
-+ if (of_find_property(np, "#cooling-cells", NULL)) {
-+ cdev = of_cpufreq_cooling_register(np, cpumask_of(cpu));
-+ if (IS_ERR(cdev))
-+ pr_err("running cpufreq without cooling device: %ld\n",
-+ PTR_ERR(cdev));
-+ }
-+ of_node_put(np);
-+ }
-+
-+ return 0;
-+
-+out_free_table:
-+ regulator_put(krait_l2_reg);
-+ clk_put(krait_l2_clk);
-+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-+out_put_node:
-+ of_node_put(np);
-+ return ret;
-+}
-+
-+static int krait_cpufreq_remove(struct platform_device *pdev)
-+{
-+ cpufreq_cooling_unregister(cdev);
-+ cpufreq_unregister_driver(&krait_cpufreq_driver);
-+ dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
-+ clk_put(krait_l2_clk);
-+ regulator_put(krait_l2_reg);
-+
-+ return 0;
-+}
-+
-+static struct platform_driver krait_cpufreq_platdrv = {
-+ .driver = {
-+ .name = "cpufreq-krait",
-+ .owner = THIS_MODULE,
-+ },
-+ .probe = krait_cpufreq_probe,
-+ .remove = krait_cpufreq_remove,
-+};
-+module_platform_driver(krait_cpufreq_platdrv);
-+
-+MODULE_DESCRIPTION("Krait CPUfreq driver");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/cpufreq/qcom-cpufreq.c
-+++ b/drivers/cpufreq/qcom-cpufreq.c
-@@ -168,11 +168,8 @@ static int __init qcom_cpufreq_populate_
-
- static int __init qcom_cpufreq_driver_init(void)
- {
-- struct cpufreq_dt_platform_data pdata = { .independent_clocks = true };
- struct platform_device_info devinfo = {
-- .name = "cpufreq-dt",
-- .data = &pdata,
-- .size_data = sizeof(pdata),
-+ .name = "cpufreq-krait",
- };
- struct device *cpu_dev;
- struct device_node *np;
diff --git a/target/linux/ipq806x/patches-4.1/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch b/target/linux/ipq806x/patches-4.1/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch
deleted file mode 100644
index 4f5c0efb7b..0000000000
--- a/target/linux/ipq806x/patches-4.1/155-dt-bindings-qcom_adm-Fix-channel-specifiers.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,1/2] dt/bindings: qcom_adm: Fix channel specifiers
-From: Andy Gross <agross@codeaurora.org>
-X-Patchwork-Id: 6027361
-Message-Id: <1426571172-9711-2-git-send-email-agross@codeaurora.org>
-To: Vinod Koul <vinod.koul@intel.com>
-Cc: devicetree@vger.kernel.org, dmaengine@vger.kernel.org,
- linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org, Kumar Gala <galak@codeaurora.org>,
- Bjorn Andersson <bjorn.andersson@sonymobile.com>,
- Andy Gross <agross@codeaurora.org>
-Date: Tue, 17 Mar 2015 00:46:11 -0500
-
-This patch removes the crci information from the dma channel property. At least
-one client device requires using more than one CRCI value for a channel. This
-does not match the current binding and the crci information needs to be removed.
-
-Instead, the client device will provide this information via other means.
-
-Signed-off-by: Andy Gross <agross@codeaurora.org>
-
----
-Documentation/devicetree/bindings/dma/qcom_adm.txt | 16 ++++++----------
- 1 file changed, 6 insertions(+), 10 deletions(-)
-
---- a/Documentation/devicetree/bindings/dma/qcom_adm.txt
-+++ b/Documentation/devicetree/bindings/dma/qcom_adm.txt
-@@ -4,8 +4,7 @@ Required properties:
- - compatible: must contain "qcom,adm" for IPQ/APQ8064 and MSM8960
- - reg: Address range for DMA registers
- - interrupts: Should contain one interrupt shared by all channels
--- #dma-cells: must be <2>. First cell denotes the channel number. Second cell
-- denotes CRCI (client rate control interface) flow control assignment.
-+- #dma-cells: must be <1>. First cell denotes the channel number.
- - clocks: Should contain the core clock and interface clock.
- - clock-names: Must contain "core" for the core clock and "iface" for the
- interface clock.
-@@ -22,7 +21,7 @@ Example:
- compatible = "qcom,adm";
- reg = <0x18300000 0x100000>;
- interrupts = <0 170 0>;
-- #dma-cells = <2>;
-+ #dma-cells = <1>;
-
- clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
- clock-names = "core", "iface";
-@@ -35,15 +34,12 @@ Example:
- qcom,ee = <0>;
- };
-
--DMA clients must use the format descripted in the dma.txt file, using a three
-+DMA clients must use the format descripted in the dma.txt file, using a two
- cell specifier for each channel.
-
--Each dmas request consists of 3 cells:
-+Each dmas request consists of two cells:
- 1. phandle pointing to the DMA controller
- 2. channel number
-- 3. CRCI assignment, if applicable. If no CRCI flow control is required, use 0.
-- The CRCI is used for flow control. It identifies the peripheral device that
-- is the source/destination for the transferred data.
-
- Example:
-
-@@ -56,7 +52,7 @@ Example:
-
- cs-gpios = <&qcom_pinmux 20 0>;
-
-- dmas = <&adm_dma 6 9>,
-- <&adm_dma 5 10>;
-+ dmas = <&adm_dma 6>,
-+ <&adm_dma 5>;
- dma-names = "rx", "tx";
- };
diff --git a/target/linux/ipq806x/patches-4.1/156-dmaengine-Add-ADM-driver.patch b/target/linux/ipq806x/patches-4.1/156-dmaengine-Add-ADM-driver.patch
deleted file mode 100644
index 29e8eaaec4..0000000000
--- a/target/linux/ipq806x/patches-4.1/156-dmaengine-Add-ADM-driver.patch
+++ /dev/null
@@ -1,962 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v6,2/2] dmaengine: Add ADM driver
-From: Andy Gross <agross@codeaurora.org>
-X-Patchwork-Id: 6027351
-Message-Id: <1426571172-9711-3-git-send-email-agross@codeaurora.org>
-To: Vinod Koul <vinod.koul@intel.com>
-Cc: devicetree@vger.kernel.org, dmaengine@vger.kernel.org,
- linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
- linux-arm-kernel@lists.infradead.org, Kumar Gala <galak@codeaurora.org>,
- Bjorn Andersson <bjorn.andersson@sonymobile.com>,
- Andy Gross <agross@codeaurora.org>
-Date: Tue, 17 Mar 2015 00:46:12 -0500
-
-Add the DMA engine driver for the QCOM Application Data Mover (ADM) DMA
-controller found in the MSM8x60 and IPQ/APQ8064 platforms.
-
-The ADM supports both memory to memory transactions and memory
-to/from peripheral device transactions. The controller also provides flow
-control capabilities for transactions to/from peripheral devices.
-
-The initial release of this driver supports slave transfers to/from peripherals
-and also incorporates CRCI (client rate control interface) flow control.
-
-Signed-off-by: Andy Gross <agross@codeaurora.org>
-Reviewed-by: sricharan <sricharan@codeaurora.org>
-
----
-drivers/dma/Kconfig | 10 +
- drivers/dma/Makefile | 1 +
- drivers/dma/qcom_adm.c | 900 ++++++++++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 911 insertions(+)
- create mode 100644 drivers/dma/qcom_adm.c
-
---- a/drivers/dma/Kconfig
-+++ b/drivers/dma/Kconfig
-@@ -492,4 +492,14 @@ config QCOM_BAM_DMA
- Enable support for the QCOM BAM DMA controller. This controller
- provides DMA capabilities for a variety of on-chip devices.
-
-+config QCOM_ADM
-+ tristate "Qualcomm ADM support"
-+ depends on ARCH_QCOM || (COMPILE_TEST && OF && ARM)
-+ select DMA_ENGINE
-+ select DMA_VIRTUAL_CHANNELS
-+ ---help---
-+ Enable support for the Qualcomm ADM DMA controller. This controller
-+ provides DMA capabilities for both general purpose and on-chip
-+ peripheral devices.
-+
- endif
---- /dev/null
-+++ b/drivers/dma/qcom_adm.c
-@@ -0,0 +1,900 @@
-+/*
-+ * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 and
-+ * only version 2 as published by the Free Software Foundation.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/io.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/scatterlist.h>
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/of.h>
-+#include <linux/of_address.h>
-+#include <linux/of_irq.h>
-+#include <linux/of_dma.h>
-+#include <linux/reset.h>
-+#include <linux/clk.h>
-+#include <linux/dmaengine.h>
-+
-+#include "dmaengine.h"
-+#include "virt-dma.h"
-+
-+/* ADM registers - calculated from channel number and security domain */
-+#define ADM_CHAN_MULTI 0x4
-+#define ADM_CI_MULTI 0x4
-+#define ADM_CRCI_MULTI 0x4
-+#define ADM_EE_MULTI 0x800
-+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan)
-+#define ADM_EE_OFFS(ee) (ADM_EE_MULTI * ee)
-+#define ADM_CHAN_EE_OFFS(chan, ee) (ADM_CHAN_OFFS(chan) + ADM_EE_OFFS(ee))
-+#define ADM_CHAN_OFFS(chan) (ADM_CHAN_MULTI * chan)
-+#define ADM_CI_OFFS(ci) (ADM_CHAN_OFF(ci))
-+#define ADM_CH_CMD_PTR(chan, ee) (ADM_CHAN_EE_OFFS(chan, ee))
-+#define ADM_CH_RSLT(chan, ee) (0x40 + ADM_CHAN_EE_OFFS(chan, ee))
-+#define ADM_CH_FLUSH_STATE0(chan, ee) (0x80 + ADM_CHAN_EE_OFFS(chan, ee))
-+#define ADM_CH_STATUS_SD(chan, ee) (0x200 + ADM_CHAN_EE_OFFS(chan, ee))
-+#define ADM_CH_CONF(chan) (0x240 + ADM_CHAN_OFFS(chan))
-+#define ADM_CH_RSLT_CONF(chan, ee) (0x300 + ADM_CHAN_EE_OFFS(chan, ee))
-+#define ADM_SEC_DOMAIN_IRQ_STATUS(ee) (0x380 + ADM_EE_OFFS(ee))
-+#define ADM_CI_CONF(ci) (0x390 + ci * ADM_CI_MULTI)
-+#define ADM_GP_CTL 0x3d8
-+#define ADM_CRCI_CTL(crci, ee) (0x400 + crci * ADM_CRCI_MULTI + \
-+ ADM_EE_OFFS(ee))
-+
-+/* channel status */
-+#define ADM_CH_STATUS_VALID BIT(1)
-+
-+/* channel result */
-+#define ADM_CH_RSLT_VALID BIT(31)
-+#define ADM_CH_RSLT_ERR BIT(3)
-+#define ADM_CH_RSLT_FLUSH BIT(2)
-+#define ADM_CH_RSLT_TPD BIT(1)
-+
-+/* channel conf */
-+#define ADM_CH_CONF_SHADOW_EN BIT(12)
-+#define ADM_CH_CONF_MPU_DISABLE BIT(11)
-+#define ADM_CH_CONF_PERM_MPU_CONF BIT(9)
-+#define ADM_CH_CONF_FORCE_RSLT_EN BIT(7)
-+#define ADM_CH_CONF_SEC_DOMAIN(ee) (((ee & 0x3) << 4) | ((ee & 0x4) << 11))
-+
-+/* channel result conf */
-+#define ADM_CH_RSLT_CONF_FLUSH_EN BIT(1)
-+#define ADM_CH_RSLT_CONF_IRQ_EN BIT(0)
-+
-+/* CRCI CTL */
-+#define ADM_CRCI_CTL_MUX_SEL BIT(18)
-+#define ADM_CRCI_CTL_RST BIT(17)
-+
-+/* CI configuration */
-+#define ADM_CI_RANGE_END(x) (x << 24)
-+#define ADM_CI_RANGE_START(x) (x << 16)
-+#define ADM_CI_BURST_4_WORDS BIT(2)
-+#define ADM_CI_BURST_8_WORDS BIT(3)
-+
-+/* GP CTL */
-+#define ADM_GP_CTL_LP_EN BIT(12)
-+#define ADM_GP_CTL_LP_CNT(x) (x << 8)
-+
-+/* Command pointer list entry */
-+#define ADM_CPLE_LP BIT(31)
-+#define ADM_CPLE_CMD_PTR_LIST BIT(29)
-+
-+/* Command list entry */
-+#define ADM_CMD_LC BIT(31)
-+#define ADM_CMD_DST_CRCI(n) (((n) & 0xf) << 7)
-+#define ADM_CMD_SRC_CRCI(n) (((n) & 0xf) << 3)
-+
-+#define ADM_CMD_TYPE_SINGLE 0x0
-+#define ADM_CMD_TYPE_BOX 0x3
-+
-+#define ADM_CRCI_MUX_SEL BIT(4)
-+#define ADM_DESC_ALIGN 8
-+#define ADM_MAX_XFER (SZ_64K-1)
-+#define ADM_MAX_ROWS (SZ_64K-1)
-+#define ADM_MAX_CHANNELS 16
-+
-+struct adm_desc_hw_box {
-+ u32 cmd;
-+ u32 src_addr;
-+ u32 dst_addr;
-+ u32 row_len;
-+ u32 num_rows;
-+ u32 row_offset;
-+};
-+
-+struct adm_desc_hw_single {
-+ u32 cmd;
-+ u32 src_addr;
-+ u32 dst_addr;
-+ u32 len;
-+};
-+
-+struct adm_async_desc {
-+ struct virt_dma_desc vd;
-+ struct adm_device *adev;
-+
-+ size_t length;
-+ enum dma_transfer_direction dir;
-+ dma_addr_t dma_addr;
-+ size_t dma_len;
-+
-+ void *cpl;
-+ dma_addr_t cp_addr;
-+ u32 crci;
-+ u32 mux;
-+ u32 blk_size;
-+};
-+
-+struct adm_chan {
-+ struct virt_dma_chan vc;
-+ struct adm_device *adev;
-+
-+ /* parsed from DT */
-+ u32 id; /* channel id */
-+
-+ struct adm_async_desc *curr_txd;
-+ struct dma_slave_config slave;
-+ struct list_head node;
-+
-+ int error;
-+ int initialized;
-+};
-+
-+static inline struct adm_chan *to_adm_chan(struct dma_chan *common)
-+{
-+ return container_of(common, struct adm_chan, vc.chan);
-+}
-+
-+struct adm_device {
-+ void __iomem *regs;
-+ struct device *dev;
-+ struct dma_device common;
-+ struct device_dma_parameters dma_parms;
-+ struct adm_chan *channels;
-+
-+ u32 ee;
-+
-+ struct clk *core_clk;
-+ struct clk *iface_clk;
-+
-+ struct reset_control *clk_reset;
-+ struct reset_control *c0_reset;
-+ struct reset_control *c1_reset;
-+ struct reset_control *c2_reset;
-+ int irq;
-+};
-+
-+/**
-+ * adm_free_chan - Frees dma resources associated with the specific channel
-+ *
-+ * Free all allocated descriptors associated with this channel
-+ *
-+ */
-+static void adm_free_chan(struct dma_chan *chan)
-+{
-+ /* free all queued descriptors */
-+ vchan_free_chan_resources(to_virt_chan(chan));
-+}
-+
-+/**
-+ * adm_get_blksize - Get block size from burst value
-+ *
-+ */
-+static int adm_get_blksize(unsigned int burst)
-+{
-+ int ret;
-+
-+ switch (burst) {
-+ case 16:
-+ case 32:
-+ case 64:
-+ case 128:
-+ ret = ffs(burst>>4) - 1;
-+ break;
-+ case 192:
-+ ret = 4;
-+ break;
-+ case 256:
-+ ret = 5;
-+ break;
-+ default:
-+ ret = -EINVAL;
-+ break;
-+ }
-+
-+ return ret;
-+}
-+
-+/**
-+ * adm_process_fc_descriptors - Process descriptors for flow controlled xfers
-+ *
-+ * @achan: ADM channel
-+ * @desc: Descriptor memory pointer
-+ * @sg: Scatterlist entry
-+ * @crci: CRCI value
-+ * @burst: Burst size of transaction
-+ * @direction: DMA transfer direction
-+ */
-+static void *adm_process_fc_descriptors(struct adm_chan *achan,
-+ void *desc, struct scatterlist *sg, u32 crci, u32 burst,
-+ enum dma_transfer_direction direction)
-+{
-+ struct adm_desc_hw_box *box_desc = NULL;
-+ struct adm_desc_hw_single *single_desc;
-+ u32 remainder = sg_dma_len(sg);
-+ u32 rows, row_offset, crci_cmd;
-+ u32 mem_addr = sg_dma_address(sg);
-+ u32 *incr_addr = &mem_addr;
-+ u32 *src, *dst;
-+
-+ if (direction == DMA_DEV_TO_MEM) {
-+ crci_cmd = ADM_CMD_SRC_CRCI(crci);
-+ row_offset = burst;
-+ src = &achan->slave.src_addr;
-+ dst = &mem_addr;
-+ } else {
-+ crci_cmd = ADM_CMD_DST_CRCI(crci);
-+ row_offset = burst << 16;
-+ src = &mem_addr;
-+ dst = &achan->slave.dst_addr;
-+ }
-+
-+ while (remainder >= burst) {
-+ box_desc = desc;
-+ box_desc->cmd = ADM_CMD_TYPE_BOX | crci_cmd;
-+ box_desc->row_offset = row_offset;
-+ box_desc->src_addr = *src;
-+ box_desc->dst_addr = *dst;
-+
-+ rows = remainder / burst;
-+ rows = min_t(u32, rows, ADM_MAX_ROWS);
-+ box_desc->num_rows = rows << 16 | rows;
-+ box_desc->row_len = burst << 16 | burst;
-+
-+ *incr_addr += burst * rows;
-+ remainder -= burst * rows;
-+ desc += sizeof(*box_desc);
-+ }
-+
-+ /* if leftover bytes, do one single descriptor */
-+ if (remainder) {
-+ single_desc = desc;
-+ single_desc->cmd = ADM_CMD_TYPE_SINGLE | crci_cmd;
-+ single_desc->len = remainder;
-+ single_desc->src_addr = *src;
-+ single_desc->dst_addr = *dst;
-+ desc += sizeof(*single_desc);
-+
-+ if (sg_is_last(sg))
-+ single_desc->cmd |= ADM_CMD_LC;
-+ } else {
-+ if (box_desc && sg_is_last(sg))
-+ box_desc->cmd |= ADM_CMD_LC;
-+ }
-+
-+ return desc;
-+}
-+
-+/**
-+ * adm_process_non_fc_descriptors - Process descriptors for non-fc xfers
-+ *
-+ * @achan: ADM channel
-+ * @desc: Descriptor memory pointer
-+ * @sg: Scatterlist entry
-+ * @direction: DMA transfer direction
-+ */
-+static void *adm_process_non_fc_descriptors(struct adm_chan *achan,
-+ void *desc, struct scatterlist *sg,
-+ enum dma_transfer_direction direction)
-+{
-+ struct adm_desc_hw_single *single_desc;
-+ u32 remainder = sg_dma_len(sg);
-+ u32 mem_addr = sg_dma_address(sg);
-+ u32 *incr_addr = &mem_addr;
-+ u32 *src, *dst;
-+
-+ if (direction == DMA_DEV_TO_MEM) {
-+ src = &achan->slave.src_addr;
-+ dst = &mem_addr;
-+ } else {
-+ src = &mem_addr;
-+ dst = &achan->slave.dst_addr;
-+ }
-+
-+ do {
-+ single_desc = desc;
-+ single_desc->cmd = ADM_CMD_TYPE_SINGLE;
-+ single_desc->src_addr = *src;
-+ single_desc->dst_addr = *dst;
-+ single_desc->len = (remainder > ADM_MAX_XFER) ?
-+ ADM_MAX_XFER : remainder;
-+
-+ remainder -= single_desc->len;
-+ *incr_addr += single_desc->len;
-+ desc += sizeof(*single_desc);
-+ } while (remainder);
-+
-+ /* set last command if this is the end of the whole transaction */
-+ if (sg_is_last(sg))
-+ single_desc->cmd |= ADM_CMD_LC;
-+
-+ return desc;
-+}
-+
-+/**
-+ * adm_prep_slave_sg - Prep slave sg transaction
-+ *
-+ * @chan: dma channel
-+ * @sgl: scatter gather list
-+ * @sg_len: length of sg
-+ * @direction: DMA transfer direction
-+ * @flags: DMA flags
-+ * @context: transfer context (unused)
-+ */
-+static struct dma_async_tx_descriptor *adm_prep_slave_sg(struct dma_chan *chan,
-+ struct scatterlist *sgl, unsigned int sg_len,
-+ enum dma_transfer_direction direction, unsigned long flags,
-+ void *context)
-+{
-+ struct adm_chan *achan = to_adm_chan(chan);
-+ struct adm_device *adev = achan->adev;
-+ struct adm_async_desc *async_desc;
-+ struct scatterlist *sg;
-+ u32 i, burst;
-+ u32 single_count = 0, box_count = 0, crci = 0;
-+ void *desc;
-+ u32 *cple;
-+ int blk_size = 0;
-+
-+ if (!is_slave_direction(direction)) {
-+ dev_err(adev->dev, "invalid dma direction\n");
-+ return NULL;
-+ }
-+
-+ /*
-+ * get burst value from slave configuration
-+ */
-+ burst = (direction == DMA_MEM_TO_DEV) ?
-+ achan->slave.dst_maxburst :
-+ achan->slave.src_maxburst;
-+
-+ /* if using flow control, validate burst and crci values */
-+ if (achan->slave.device_fc) {
-+
-+ blk_size = adm_get_blksize(burst);
-+ if (blk_size < 0) {
-+ dev_err(adev->dev, "invalid burst value: %d\n",
-+ burst);
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ crci = achan->slave.slave_id & 0xf;
-+ if (!crci || achan->slave.slave_id > 0x1f) {
-+ dev_err(adev->dev, "invalid crci value\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+ }
-+
-+ /* iterate through sgs and compute allocation size of structures */
-+ for_each_sg(sgl, sg, sg_len, i) {
-+ if (achan->slave.device_fc) {
-+ box_count += DIV_ROUND_UP(sg_dma_len(sg) / burst,
-+ ADM_MAX_ROWS);
-+ if (sg_dma_len(sg) % burst)
-+ single_count++;
-+ } else {
-+ single_count += DIV_ROUND_UP(sg_dma_len(sg),
-+ ADM_MAX_XFER);
-+ }
-+ }
-+
-+ async_desc = kzalloc(sizeof(*async_desc), GFP_NOWAIT);
-+ if (!async_desc)
-+ return ERR_PTR(-ENOMEM);
-+
-+ if (crci)
-+ async_desc->mux = achan->slave.slave_id & ADM_CRCI_MUX_SEL ?
-+ ADM_CRCI_CTL_MUX_SEL : 0;
-+ async_desc->crci = crci;
-+ async_desc->blk_size = blk_size;
-+ async_desc->dma_len = single_count * sizeof(struct adm_desc_hw_single) +
-+ box_count * sizeof(struct adm_desc_hw_box) +
-+ sizeof(*cple) + 2 * ADM_DESC_ALIGN;
-+
-+ async_desc->cpl = dma_alloc_writecombine(adev->dev, async_desc->dma_len,
-+ &async_desc->dma_addr, GFP_NOWAIT);
-+
-+ if (!async_desc->cpl) {
-+ kfree(async_desc);
-+ return ERR_PTR(-ENOMEM);
-+ }
-+
-+ async_desc->adev = adev;
-+
-+ /* both command list entry and descriptors must be 8 byte aligned */
-+ cple = PTR_ALIGN(async_desc->cpl, ADM_DESC_ALIGN);
-+ desc = PTR_ALIGN(cple + 1, ADM_DESC_ALIGN);
-+
-+ /* init cmd list */
-+ *cple = ADM_CPLE_LP;
-+ *cple |= (desc - async_desc->cpl + async_desc->dma_addr) >> 3;
-+
-+ for_each_sg(sgl, sg, sg_len, i) {
-+ async_desc->length += sg_dma_len(sg);
-+
-+ if (achan->slave.device_fc)
-+ desc = adm_process_fc_descriptors(achan, desc, sg, crci,
-+ burst, direction);
-+ else
-+ desc = adm_process_non_fc_descriptors(achan, desc, sg,
-+ direction);
-+ }
-+
-+ return vchan_tx_prep(&achan->vc, &async_desc->vd, flags);
-+}
-+
-+/**
-+ * adm_terminate_all - terminate all transactions on a channel
-+ * @achan: adm dma channel
-+ *
-+ * Dequeues and frees all transactions, aborts current transaction
-+ * No callbacks are done
-+ *
-+ */
-+static int adm_terminate_all(struct dma_chan *chan)
-+{
-+ struct adm_chan *achan = to_adm_chan(chan);
-+ struct adm_device *adev = achan->adev;
-+ unsigned long flags;
-+ LIST_HEAD(head);
-+
-+ spin_lock_irqsave(&achan->vc.lock, flags);
-+ vchan_get_all_descriptors(&achan->vc, &head);
-+
-+ /* send flush command to terminate current transaction */
-+ writel_relaxed(0x0,
-+ adev->regs + ADM_CH_FLUSH_STATE0(achan->id, adev->ee));
-+
-+ spin_unlock_irqrestore(&achan->vc.lock, flags);
-+
-+ vchan_dma_desc_free_list(&achan->vc, &head);
-+
-+ return 0;
-+}
-+
-+static int adm_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
-+{
-+ struct adm_chan *achan = to_adm_chan(chan);
-+ unsigned long flag;
-+
-+ spin_lock_irqsave(&achan->vc.lock, flag);
-+ memcpy(&achan->slave, cfg, sizeof(struct dma_slave_config));
-+ spin_unlock_irqrestore(&achan->vc.lock, flag);
-+
-+ return 0;
-+}
-+
-+/**
-+ * adm_start_dma - start next transaction
-+ * @achan - ADM dma channel
-+ */
-+static void adm_start_dma(struct adm_chan *achan)
-+{
-+ struct virt_dma_desc *vd = vchan_next_desc(&achan->vc);
-+ struct adm_device *adev = achan->adev;
-+ struct adm_async_desc *async_desc;
-+
-+ lockdep_assert_held(&achan->vc.lock);
-+
-+ if (!vd)
-+ return;
-+
-+ list_del(&vd->node);
-+
-+ /* write next command list out to the CMD FIFO */
-+ async_desc = container_of(vd, struct adm_async_desc, vd);
-+ achan->curr_txd = async_desc;
-+
-+ /* reset channel error */
-+ achan->error = 0;
-+
-+ if (!achan->initialized) {
-+ /* enable interrupts */
-+ writel(ADM_CH_CONF_SHADOW_EN |
-+ ADM_CH_CONF_PERM_MPU_CONF |
-+ ADM_CH_CONF_MPU_DISABLE |
-+ ADM_CH_CONF_SEC_DOMAIN(adev->ee),
-+ adev->regs + ADM_CH_CONF(achan->id));
-+
-+ writel(ADM_CH_RSLT_CONF_IRQ_EN | ADM_CH_RSLT_CONF_FLUSH_EN,
-+ adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
-+
-+ achan->initialized = 1;
-+ }
-+
-+ /* set the crci block size if this transaction requires CRCI */
-+ if (async_desc->crci) {
-+ writel(async_desc->mux | async_desc->blk_size,
-+ adev->regs + ADM_CRCI_CTL(async_desc->crci, adev->ee));
-+ }
-+
-+ /* make sure IRQ enable doesn't get reordered */
-+ wmb();
-+
-+ /* write next command list out to the CMD FIFO */
-+ writel(ALIGN(async_desc->dma_addr, ADM_DESC_ALIGN) >> 3,
-+ adev->regs + ADM_CH_CMD_PTR(achan->id, adev->ee));
-+}
-+
-+/**
-+ * adm_dma_irq - irq handler for ADM controller
-+ * @irq: IRQ of interrupt
-+ * @data: callback data
-+ *
-+ * IRQ handler for the bam controller
-+ */
-+static irqreturn_t adm_dma_irq(int irq, void *data)
-+{
-+ struct adm_device *adev = data;
-+ u32 srcs, i;
-+ struct adm_async_desc *async_desc;
-+ unsigned long flags;
-+
-+ srcs = readl_relaxed(adev->regs +
-+ ADM_SEC_DOMAIN_IRQ_STATUS(adev->ee));
-+
-+ for (i = 0; i < ADM_MAX_CHANNELS; i++) {
-+ struct adm_chan *achan = &adev->channels[i];
-+ u32 status, result;
-+
-+ if (srcs & BIT(i)) {
-+ status = readl_relaxed(adev->regs +
-+ ADM_CH_STATUS_SD(i, adev->ee));
-+
-+ /* if no result present, skip */
-+ if (!(status & ADM_CH_STATUS_VALID))
-+ continue;
-+
-+ result = readl_relaxed(adev->regs +
-+ ADM_CH_RSLT(i, adev->ee));
-+
-+ /* no valid results, skip */
-+ if (!(result & ADM_CH_RSLT_VALID))
-+ continue;
-+
-+ /* flag error if transaction was flushed or failed */
-+ if (result & (ADM_CH_RSLT_ERR | ADM_CH_RSLT_FLUSH))
-+ achan->error = 1;
-+
-+ spin_lock_irqsave(&achan->vc.lock, flags);
-+ async_desc = achan->curr_txd;
-+
-+ achan->curr_txd = NULL;
-+
-+ if (async_desc) {
-+ vchan_cookie_complete(&async_desc->vd);
-+
-+ /* kick off next DMA */
-+ adm_start_dma(achan);
-+ }
-+
-+ spin_unlock_irqrestore(&achan->vc.lock, flags);
-+ }
-+ }
-+
-+ return IRQ_HANDLED;
-+}
-+
-+/**
-+ * adm_tx_status - returns status of transaction
-+ * @chan: dma channel
-+ * @cookie: transaction cookie
-+ * @txstate: DMA transaction state
-+ *
-+ * Return status of dma transaction
-+ */
-+static enum dma_status adm_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
-+ struct dma_tx_state *txstate)
-+{
-+ struct adm_chan *achan = to_adm_chan(chan);
-+ struct virt_dma_desc *vd;
-+ enum dma_status ret;
-+ unsigned long flags;
-+ size_t residue = 0;
-+
-+ ret = dma_cookie_status(chan, cookie, txstate);
-+ if (ret == DMA_COMPLETE || !txstate)
-+ return ret;
-+
-+ spin_lock_irqsave(&achan->vc.lock, flags);
-+
-+ vd = vchan_find_desc(&achan->vc, cookie);
-+ if (vd)
-+ residue = container_of(vd, struct adm_async_desc, vd)->length;
-+
-+ spin_unlock_irqrestore(&achan->vc.lock, flags);
-+
-+ /*
-+ * residue is either the full length if it is in the issued list, or 0
-+ * if it is in progress. We have no reliable way of determining
-+ * anything inbetween
-+ */
-+ dma_set_residue(txstate, residue);
-+
-+ if (achan->error)
-+ return DMA_ERROR;
-+
-+ return ret;
-+}
-+
-+/**
-+ * adm_issue_pending - starts pending transactions
-+ * @chan: dma channel
-+ *
-+ * Issues all pending transactions and starts DMA
-+ */
-+static void adm_issue_pending(struct dma_chan *chan)
-+{
-+ struct adm_chan *achan = to_adm_chan(chan);
-+ unsigned long flags;
-+
-+ spin_lock_irqsave(&achan->vc.lock, flags);
-+
-+ if (vchan_issue_pending(&achan->vc) && !achan->curr_txd)
-+ adm_start_dma(achan);
-+ spin_unlock_irqrestore(&achan->vc.lock, flags);
-+}
-+
-+/**
-+ * adm_dma_free_desc - free descriptor memory
-+ * @vd: virtual descriptor
-+ *
-+ */
-+static void adm_dma_free_desc(struct virt_dma_desc *vd)
-+{
-+ struct adm_async_desc *async_desc = container_of(vd,
-+ struct adm_async_desc, vd);
-+
-+ dma_free_writecombine(async_desc->adev->dev, async_desc->dma_len,
-+ async_desc->cpl, async_desc->dma_addr);
-+ kfree(async_desc);
-+}
-+
-+static void adm_channel_init(struct adm_device *adev, struct adm_chan *achan,
-+ u32 index)
-+{
-+ achan->id = index;
-+ achan->adev = adev;
-+
-+ vchan_init(&achan->vc, &adev->common);
-+ achan->vc.desc_free = adm_dma_free_desc;
-+}
-+
-+static int adm_dma_probe(struct platform_device *pdev)
-+{
-+ struct adm_device *adev;
-+ struct resource *iores;
-+ int ret;
-+ u32 i;
-+
-+ adev = devm_kzalloc(&pdev->dev, sizeof(*adev), GFP_KERNEL);
-+ if (!adev)
-+ return -ENOMEM;
-+
-+ adev->dev = &pdev->dev;
-+
-+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ adev->regs = devm_ioremap_resource(&pdev->dev, iores);
-+ if (IS_ERR(adev->regs))
-+ return PTR_ERR(adev->regs);
-+
-+ adev->irq = platform_get_irq(pdev, 0);
-+ if (adev->irq < 0)
-+ return adev->irq;
-+
-+ ret = of_property_read_u32(pdev->dev.of_node, "qcom,ee", &adev->ee);
-+ if (ret) {
-+ dev_err(adev->dev, "Execution environment unspecified\n");
-+ return ret;
-+ }
-+
-+ adev->core_clk = devm_clk_get(adev->dev, "core");
-+ if (IS_ERR(adev->core_clk))
-+ return PTR_ERR(adev->core_clk);
-+
-+ ret = clk_prepare_enable(adev->core_clk);
-+ if (ret) {
-+ dev_err(adev->dev, "failed to prepare/enable core clock\n");
-+ return ret;
-+ }
-+
-+ adev->iface_clk = devm_clk_get(adev->dev, "iface");
-+ if (IS_ERR(adev->iface_clk)) {
-+ ret = PTR_ERR(adev->iface_clk);
-+ goto err_disable_core_clk;
-+ }
-+
-+ ret = clk_prepare_enable(adev->iface_clk);
-+ if (ret) {
-+ dev_err(adev->dev, "failed to prepare/enable iface clock\n");
-+ goto err_disable_core_clk;
-+ }
-+
-+ adev->clk_reset = devm_reset_control_get(&pdev->dev, "clk");
-+ if (IS_ERR(adev->clk_reset)) {
-+ dev_err(adev->dev, "failed to get ADM0 reset\n");
-+ ret = PTR_ERR(adev->clk_reset);
-+ goto err_disable_clks;
-+ }
-+
-+ adev->c0_reset = devm_reset_control_get(&pdev->dev, "c0");
-+ if (IS_ERR(adev->c0_reset)) {
-+ dev_err(adev->dev, "failed to get ADM0 C0 reset\n");
-+ ret = PTR_ERR(adev->c0_reset);
-+ goto err_disable_clks;
-+ }
-+
-+ adev->c1_reset = devm_reset_control_get(&pdev->dev, "c1");
-+ if (IS_ERR(adev->c1_reset)) {
-+ dev_err(adev->dev, "failed to get ADM0 C1 reset\n");
-+ ret = PTR_ERR(adev->c1_reset);
-+ goto err_disable_clks;
-+ }
-+
-+ adev->c2_reset = devm_reset_control_get(&pdev->dev, "c2");
-+ if (IS_ERR(adev->c2_reset)) {
-+ dev_err(adev->dev, "failed to get ADM0 C2 reset\n");
-+ ret = PTR_ERR(adev->c2_reset);
-+ goto err_disable_clks;
-+ }
-+
-+ reset_control_assert(adev->clk_reset);
-+ reset_control_assert(adev->c0_reset);
-+ reset_control_assert(adev->c1_reset);
-+ reset_control_assert(adev->c2_reset);
-+
-+ reset_control_deassert(adev->clk_reset);
-+ reset_control_deassert(adev->c0_reset);
-+ reset_control_deassert(adev->c1_reset);
-+ reset_control_deassert(adev->c2_reset);
-+
-+ adev->channels = devm_kcalloc(adev->dev, ADM_MAX_CHANNELS,
-+ sizeof(*adev->channels), GFP_KERNEL);
-+
-+ if (!adev->channels) {
-+ ret = -ENOMEM;
-+ goto err_disable_clks;
-+ }
-+
-+ /* allocate and initialize channels */
-+ INIT_LIST_HEAD(&adev->common.channels);
-+
-+ for (i = 0; i < ADM_MAX_CHANNELS; i++)
-+ adm_channel_init(adev, &adev->channels[i], i);
-+
-+ /* reset CRCIs */
-+ for (i = 0; i < 16; i++)
-+ writel(ADM_CRCI_CTL_RST, adev->regs +
-+ ADM_CRCI_CTL(i, adev->ee));
-+
-+ /* configure client interfaces */
-+ writel(ADM_CI_RANGE_START(0x40) | ADM_CI_RANGE_END(0xb0) |
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(0));
-+ writel(ADM_CI_RANGE_START(0x2a) | ADM_CI_RANGE_END(0x2c) |
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(1));
-+ writel(ADM_CI_RANGE_START(0x12) | ADM_CI_RANGE_END(0x28) |
-+ ADM_CI_BURST_8_WORDS, adev->regs + ADM_CI_CONF(2));
-+ writel(ADM_GP_CTL_LP_EN | ADM_GP_CTL_LP_CNT(0xf),
-+ adev->regs + ADM_GP_CTL);
-+
-+ ret = devm_request_irq(adev->dev, adev->irq, adm_dma_irq,
-+ 0, "adm_dma", adev);
-+ if (ret)
-+ goto err_disable_clks;
-+
-+ platform_set_drvdata(pdev, adev);
-+
-+ adev->common.dev = adev->dev;
-+ adev->common.dev->dma_parms = &adev->dma_parms;
-+
-+ /* set capabilities */
-+ dma_cap_zero(adev->common.cap_mask);
-+ dma_cap_set(DMA_SLAVE, adev->common.cap_mask);
-+ dma_cap_set(DMA_PRIVATE, adev->common.cap_mask);
-+
-+ /* initialize dmaengine apis */
-+ adev->common.directions = BIT(DMA_DEV_TO_MEM | DMA_MEM_TO_DEV);
-+ adev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
-+ adev->common.src_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ adev->common.dst_addr_widths = DMA_SLAVE_BUSWIDTH_4_BYTES;
-+ adev->common.device_free_chan_resources = adm_free_chan;
-+ adev->common.device_prep_slave_sg = adm_prep_slave_sg;
-+ adev->common.device_issue_pending = adm_issue_pending;
-+ adev->common.device_tx_status = adm_tx_status;
-+ adev->common.device_terminate_all = adm_terminate_all;
-+ adev->common.device_config = adm_slave_config;
-+
-+ ret = dma_async_device_register(&adev->common);
-+ if (ret) {
-+ dev_err(adev->dev, "failed to register dma async device\n");
-+ goto err_disable_clks;
-+ }
-+
-+ ret = of_dma_controller_register(pdev->dev.of_node,
-+ of_dma_xlate_by_chan_id,
-+ &adev->common);
-+ if (ret)
-+ goto err_unregister_dma;
-+
-+ return 0;
-+
-+err_unregister_dma:
-+ dma_async_device_unregister(&adev->common);
-+err_disable_clks:
-+ clk_disable_unprepare(adev->iface_clk);
-+err_disable_core_clk:
-+ clk_disable_unprepare(adev->core_clk);
-+
-+ return ret;
-+}
-+
-+static int adm_dma_remove(struct platform_device *pdev)
-+{
-+ struct adm_device *adev = platform_get_drvdata(pdev);
-+ struct adm_chan *achan;
-+ u32 i;
-+
-+ of_dma_controller_free(pdev->dev.of_node);
-+ dma_async_device_unregister(&adev->common);
-+
-+ for (i = 0; i < ADM_MAX_CHANNELS; i++) {
-+ achan = &adev->channels[i];
-+
-+ /* mask IRQs for this channel/EE pair */
-+ writel(0, adev->regs + ADM_CH_RSLT_CONF(achan->id, adev->ee));
-+
-+ adm_terminate_all(&adev->channels[i].vc.chan);
-+ }
-+
-+ devm_free_irq(adev->dev, adev->irq, adev);
-+
-+ clk_disable_unprepare(adev->core_clk);
-+ clk_disable_unprepare(adev->iface_clk);
-+
-+ return 0;
-+}
-+
-+static const struct of_device_id adm_of_match[] = {
-+ { .compatible = "qcom,adm", },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, adm_of_match);
-+
-+static struct platform_driver adm_dma_driver = {
-+ .probe = adm_dma_probe,
-+ .remove = adm_dma_remove,
-+ .driver = {
-+ .name = "adm-dma-engine",
-+ .of_match_table = adm_of_match,
-+ },
-+};
-+
-+module_platform_driver(adm_dma_driver);
-+
-+MODULE_AUTHOR("Andy Gross <agross@codeaurora.org>");
-+MODULE_DESCRIPTION("QCOM ADM DMA engine driver");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/dma/Makefile
-+++ b/drivers/dma/Makefile
-@@ -54,3 +54,4 @@ obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
- obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
- obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
- obj-$(CONFIG_XGENE_DMA) += xgene-dma.o
-+obj-$(CONFIG_QCOM_ADM) += qcom_adm.o
diff --git a/target/linux/ipq806x/patches-4.1/157-ARM-DT-ipq8064-Add-ADM-device-node.patch b/target/linux/ipq806x/patches-4.1/157-ARM-DT-ipq8064-Add-ADM-device-node.patch
deleted file mode 100644
index 6f1013e32e..0000000000
--- a/target/linux/ipq806x/patches-4.1/157-ARM-DT-ipq8064-Add-ADM-device-node.patch
+++ /dev/null
@@ -1,42 +0,0 @@
-From 1fb18acab2d71e7e4efd9c10492edb1baf84dcc0 Mon Sep 17 00:00:00 2001
-From: Andy Gross <agross@codeaurora.org>
-Date: Wed, 20 May 2015 15:41:07 +0530
-Subject: [PATCH] ARM: DT: ipq8064: Add ADM device node
-
-This patch adds support for the ADM DMA on the IPQ8064 SOC
-
-Signed-off-by: Andy Gross <agross@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 4 ++++
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 21 +++++++++++++++++++++
- 2 files changed, 25 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -643,6 +643,26 @@
-
- status = "disabled";
- };
-+
-+ adm_dma: dma@18300000 {
-+ compatible = "qcom,adm";
-+ reg = <0x18300000 0x100000>;
-+ interrupts = <0 170 0>;
-+ #dma-cells = <1>;
-+
-+ clocks = <&gcc ADM0_CLK>, <&gcc ADM0_PBUS_CLK>;
-+ clock-names = "core", "iface";
-+
-+ resets = <&gcc ADM0_RESET>,
-+ <&gcc ADM0_PBUS_RESET>,
-+ <&gcc ADM0_C0_RESET>,
-+ <&gcc ADM0_C1_RESET>,
-+ <&gcc ADM0_C2_RESET>;
-+ reset-names = "clk", "pbus", "c0", "c1", "c2";
-+ qcom,ee = <0>;
-+
-+ status = "disabled";
-+ };
- };
-
- sfpb_mutex: sfpb-mutex {
diff --git a/target/linux/ipq806x/patches-4.1/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch b/target/linux/ipq806x/patches-4.1/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch
deleted file mode 100644
index 088b8cb5a1..0000000000
--- a/target/linux/ipq806x/patches-4.1/161-mtd-nand-Create-a-BBT-flag-to-access-bad-block-markers-in-raw-mode.patch
+++ /dev/null
@@ -1,84 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,
- 1/5] mtd: nand: Create a BBT flag to access bad block markers in raw
- mode
-From: Archit Taneja <architt@codeaurora.org>
-X-Patchwork-Id: 6927081
-Message-Id: <1438578498-32254-2-git-send-email-architt@codeaurora.org>
-To: linux-mtd@lists.infradead.org, dehrenberg@google.com,
- cernekee@gmail.com, computersforpeace@gmail.com
-Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org,
- sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
- Archit Taneja <architt@codeaurora.org>
-Date: Mon, 3 Aug 2015 10:38:14 +0530
-
-Some controllers can access the factory bad block marker from OOB only
-when they read it in raw mode. When ECC is enabled, these controllers
-discard reading/writing bad block markers, preventing access to them
-altogether.
-
-The bbt driver assumes MTD_OPS_PLACE_OOB when scanning for bad blocks.
-This results in the nand driver's ecc->read_oob() op to be called, which
-works with ECC enabled.
-
-Create a new BBT option flag that tells nand_bbt to force the mode to
-MTD_OPS_RAW. This would result in the correct op being called for the
-underlying nand controller driver.
-
-Reviewed-by: Andy Gross <agross@codeaurora.org>
-Signed-off-by: Archit Taneja <architt@codeaurora.org>
-
----
-drivers/mtd/nand/nand_base.c | 6 +++++-
- drivers/mtd/nand/nand_bbt.c | 6 +++++-
- include/linux/mtd/bbm.h | 7 +++++++
- 3 files changed, 17 insertions(+), 2 deletions(-)
-
---- a/drivers/mtd/nand/nand_base.c
-+++ b/drivers/mtd/nand/nand_base.c
-@@ -395,7 +395,11 @@ static int nand_default_block_markbad(st
- } else {
- ops.len = ops.ooblen = 1;
- }
-- ops.mode = MTD_OPS_PLACE_OOB;
-+
-+ if (unlikely(chip->bbt_options & NAND_BBT_ACCESS_BBM_RAW))
-+ ops.mode = MTD_OPS_RAW;
-+ else
-+ ops.mode = MTD_OPS_PLACE_OOB;
-
- /* Write to first/last page(s) if necessary */
- if (chip->bbt_options & NAND_BBT_SCANLASTPAGE)
---- a/drivers/mtd/nand/nand_bbt.c
-+++ b/drivers/mtd/nand/nand_bbt.c
-@@ -423,7 +423,11 @@ static int scan_block_fast(struct mtd_in
- ops.oobbuf = buf;
- ops.ooboffs = 0;
- ops.datbuf = NULL;
-- ops.mode = MTD_OPS_PLACE_OOB;
-+
-+ if (unlikely(bd->options & NAND_BBT_ACCESS_BBM_RAW))
-+ ops.mode = MTD_OPS_RAW;
-+ else
-+ ops.mode = MTD_OPS_PLACE_OOB;
-
- for (j = 0; j < numpages; j++) {
- /*
---- a/include/linux/mtd/bbm.h
-+++ b/include/linux/mtd/bbm.h
-@@ -116,6 +116,13 @@ struct nand_bbt_descr {
- #define NAND_BBT_NO_OOB_BBM 0x00080000
-
- /*
-+ * Force MTD_OPS_RAW mode when trying to access bad block markes from OOB. To
-+ * be used by controllers which can access BBM only when ECC is disabled, i.e,
-+ * when in RAW access mode
-+ */
-+#define NAND_BBT_ACCESS_BBM_RAW 0x00100000
-+
-+/*
- * Flag set by nand_create_default_bbt_descr(), marking that the nand_bbt_descr
- * was allocated dynamicaly and must be freed in nand_release(). Has no meaning
- * in nand_chip.bbt_options.
diff --git a/target/linux/ipq806x/patches-4.1/162-mtd-nand-Qualcomm-NAND-controller-driver.patch b/target/linux/ipq806x/patches-4.1/162-mtd-nand-Qualcomm-NAND-controller-driver.patch
deleted file mode 100644
index 4be7ecb1b9..0000000000
--- a/target/linux/ipq806x/patches-4.1/162-mtd-nand-Qualcomm-NAND-controller-driver.patch
+++ /dev/null
@@ -1,2024 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,2/5] mtd: nand: Qualcomm NAND controller driver
-From: Archit Taneja <architt@codeaurora.org>
-X-Patchwork-Id: 6927101
-Message-Id: <1438578498-32254-3-git-send-email-architt@codeaurora.org>
-To: linux-mtd@lists.infradead.org, dehrenberg@google.com,
- cernekee@gmail.com, computersforpeace@gmail.com
-Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org,
- sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
- Archit Taneja <architt@codeaurora.org>
-Date: Mon, 3 Aug 2015 10:38:15 +0530
-
-The Qualcomm NAND controller is found in SoCs like IPQ806x, MSM7xx,
-MDM9x15 series.
-
-It exists as a sub block inside the IPs EBI2 (External Bus Interface 2)
-and QPIC (Qualcomm Parallel Interface Controller). These IPs provide a
-broader interface for external slow peripheral devices such as LCD and
-NAND/NOR flash memory or SRAM like interfaces.
-
-We add support for the NAND controller found within EBI2. For the SoCs
-of our interest, we only use the NAND controller within EBI2. Therefore,
-it's safe for us to assume that the NAND controller is a standalone block
-within the SoC.
-
-The controller supports 512B, 2kB, 4kB and 8kB page 8-bit and 16-bit NAND
-flash devices. It contains a HW ECC block that supports BCH ECC (4, 8 and
-16 bit correction/step) and RS ECC(4 bit correction/step) that covers main
-and spare data. The controller contains an internal 512 byte page buffer
-to which we read/write via DMA. The EBI2 type NAND controller uses ADM DMA
-for register read/write and data transfers. The controller performs page
-reads and writes at a codeword/step level of 512 bytes. It can support up
-to 2 external chips of different configurations.
-
-The driver prepares register read and write configuration descriptors for
-each codeword, followed by data descriptors to read or write data from the
-controller's internal buffer. It uses a single ADM DMA channel that we get
-via dmaengine API. The controller requires 2 ADM CRCIs for command and
-data flow control. These are passed via DT.
-
-The ecc layout used by the controller is syndrome like, but we can't use
-the standard syndrome ecc ops because of several reasons. First, the amount
-of data bytes covered by ecc isn't same in each step. Second, writing to
-free oob space requires us writing to the entire step in which the oob
-lies. This forces us to create our own ecc ops.
-
-One more difference is how the controller accesses the bad block marker.
-The controller ignores reading the marker when ECC is enabled. ECC needs
-to be explicity disabled to read or write to the bad block marker. For
-this reason, we use the newly created flag NAND_BBT_ACCESS_BBM_RAW to
-read the factory provided bad block markers.
-
-v3:
-- Refactor dma functions for maximum reuse
-- Use dma_slave_confing on stack
-- optimize and clean upempty_page_fixup using memchr_inv
-- ensure portability with dma register reads using le32_* funcs
-- use NAND_USE_BOUNCE_BUFFER instead of doing it ourselves
-- fix handling of return values of dmaengine funcs
-- constify wherever possible
-- Remove dependency on ADM DMA in Kconfig
-- Misc fixes and clean ups
-
-v2:
-- Use new BBT flag that allows us to read BBM in raw mode
-- reduce memcpy-s in the driver
-- some refactor and clean ups because of above changes
-
-Reviewed-by: Andy Gross <agross@codeaurora.org>
-Signed-off-by: Archit Taneja <architt@codeaurora.org>
-
----
-drivers/mtd/nand/Kconfig | 7 +
- drivers/mtd/nand/Makefile | 1 +
- drivers/mtd/nand/qcom_nandc.c | 1913 +++++++++++++++++++++++++++++++++++++++++
- 3 files changed, 1921 insertions(+)
- create mode 100644 drivers/mtd/nand/qcom_nandc.c
-
---- a/drivers/mtd/nand/Kconfig
-+++ b/drivers/mtd/nand/Kconfig
-@@ -530,4 +530,11 @@ config MTD_NAND_HISI504
- help
- Enables support for NAND controller on Hisilicon SoC Hip04.
-
-+config MTD_NAND_QCOM
-+ tristate "Support for NAND on QCOM SoCs"
-+ depends on ARCH_QCOM
-+ help
-+ Enables support for NAND flash chips on SoCs containing the EBI2 NAND
-+ controller. This controller is found on IPQ806x SoC.
-+
- endif # MTD_NAND
---- /dev/null
-+++ b/drivers/mtd/nand/qcom_nandc.c
-@@ -0,0 +1,1918 @@
-+/*
-+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
-+ *
-+ * This software is licensed under the terms of the GNU General Public
-+ * License version 2, as published by the Free Software Foundation, and
-+ * may be copied, distributed, and modified under those terms.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-+ * GNU General Public License for more details.
-+ */
-+
-+#include <linux/clk.h>
-+#include <linux/slab.h>
-+#include <linux/bitops.h>
-+#include <linux/dma-mapping.h>
-+#include <linux/dmaengine.h>
-+#include <linux/module.h>
-+#include <linux/mtd/nand.h>
-+#include <linux/mtd/partitions.h>
-+#include <linux/of.h>
-+#include <linux/of_device.h>
-+#include <linux/of_mtd.h>
-+#include <linux/delay.h>
-+
-+/* NANDc reg offsets */
-+#define NAND_FLASH_CMD 0x00
-+#define NAND_ADDR0 0x04
-+#define NAND_ADDR1 0x08
-+#define NAND_FLASH_CHIP_SELECT 0x0c
-+#define NAND_EXEC_CMD 0x10
-+#define NAND_FLASH_STATUS 0x14
-+#define NAND_BUFFER_STATUS 0x18
-+#define NAND_DEV0_CFG0 0x20
-+#define NAND_DEV0_CFG1 0x24
-+#define NAND_DEV0_ECC_CFG 0x28
-+#define NAND_DEV1_ECC_CFG 0x2c
-+#define NAND_DEV1_CFG0 0x30
-+#define NAND_DEV1_CFG1 0x34
-+#define NAND_READ_ID 0x40
-+#define NAND_READ_STATUS 0x44
-+#define NAND_DEV_CMD0 0xa0
-+#define NAND_DEV_CMD1 0xa4
-+#define NAND_DEV_CMD2 0xa8
-+#define NAND_DEV_CMD_VLD 0xac
-+#define SFLASHC_BURST_CFG 0xe0
-+#define NAND_ERASED_CW_DETECT_CFG 0xe8
-+#define NAND_ERASED_CW_DETECT_STATUS 0xec
-+#define NAND_EBI2_ECC_BUF_CFG 0xf0
-+#define FLASH_BUF_ACC 0x100
-+
-+#define NAND_CTRL 0xf00
-+#define NAND_VERSION 0xf08
-+#define NAND_READ_LOCATION_0 0xf20
-+#define NAND_READ_LOCATION_1 0xf24
-+
-+/* dummy register offsets, used by write_reg_dma */
-+#define NAND_DEV_CMD1_RESTORE 0xdead
-+#define NAND_DEV_CMD_VLD_RESTORE 0xbeef
-+
-+/* NAND_FLASH_CMD bits */
-+#define PAGE_ACC BIT(4)
-+#define LAST_PAGE BIT(5)
-+
-+/* NAND_FLASH_CHIP_SELECT bits */
-+#define NAND_DEV_SEL 0
-+#define DM_EN BIT(2)
-+
-+/* NAND_FLASH_STATUS bits */
-+#define FS_OP_ERR BIT(4)
-+#define FS_READY_BSY_N BIT(5)
-+#define FS_MPU_ERR BIT(8)
-+#define FS_DEVICE_STS_ERR BIT(16)
-+#define FS_DEVICE_WP BIT(23)
-+
-+/* NAND_BUFFER_STATUS bits */
-+#define BS_UNCORRECTABLE_BIT BIT(8)
-+#define BS_CORRECTABLE_ERR_MSK 0x1f
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DISABLE_STATUS_AFTER_WRITE 4
-+#define CW_PER_PAGE 6
-+#define UD_SIZE_BYTES 9
-+#define ECC_PARITY_SIZE_BYTES_RS 19
-+#define SPARE_SIZE_BYTES 23
-+#define NUM_ADDR_CYCLES 27
-+#define STATUS_BFR_READ 30
-+#define SET_RD_MODE_AFTER_STATUS 31
-+
-+/* NAND_DEVn_CFG0 bits */
-+#define DEV0_CFG1_ECC_DISABLE 0
-+#define WIDE_FLASH 1
-+#define NAND_RECOVERY_CYCLES 2
-+#define CS_ACTIVE_BSY 5
-+#define BAD_BLOCK_BYTE_NUM 6
-+#define BAD_BLOCK_IN_SPARE_AREA 16
-+#define WR_RD_BSY_GAP 17
-+#define ENABLE_BCH_ECC 27
-+
-+/* NAND_DEV0_ECC_CFG bits */
-+#define ECC_CFG_ECC_DISABLE 0
-+#define ECC_SW_RESET 1
-+#define ECC_MODE 4
-+#define ECC_PARITY_SIZE_BYTES_BCH 8
-+#define ECC_NUM_DATA_BYTES 16
-+#define ECC_FORCE_CLK_OPEN 30
-+
-+/* NAND_DEV_CMD1 bits */
-+#define READ_ADDR 0
-+
-+/* NAND_DEV_CMD_VLD bits */
-+#define READ_START_VLD 0
-+
-+/* NAND_EBI2_ECC_BUF_CFG bits */
-+#define NUM_STEPS 0
-+
-+/* NAND_ERASED_CW_DETECT_CFG bits */
-+#define ERASED_CW_ECC_MASK 1
-+#define AUTO_DETECT_RES 0
-+#define MASK_ECC (1 << ERASED_CW_ECC_MASK)
-+#define RESET_ERASED_DET (1 << AUTO_DETECT_RES)
-+#define ACTIVE_ERASED_DET (0 << AUTO_DETECT_RES)
-+#define CLR_ERASED_PAGE_DET (RESET_ERASED_DET | MASK_ECC)
-+#define SET_ERASED_PAGE_DET (ACTIVE_ERASED_DET | MASK_ECC)
-+
-+/* NAND_ERASED_CW_DETECT_STATUS bits */
-+#define PAGE_ALL_ERASED BIT(7)
-+#define CODEWORD_ALL_ERASED BIT(6)
-+#define PAGE_ERASED BIT(5)
-+#define CODEWORD_ERASED BIT(4)
-+#define ERASED_PAGE (PAGE_ALL_ERASED | PAGE_ERASED)
-+#define ERASED_CW (CODEWORD_ALL_ERASED | CODEWORD_ERASED)
-+
-+/* Version Mask */
-+#define NAND_VERSION_MAJOR_MASK 0xf0000000
-+#define NAND_VERSION_MAJOR_SHIFT 28
-+#define NAND_VERSION_MINOR_MASK 0x0fff0000
-+#define NAND_VERSION_MINOR_SHIFT 16
-+
-+/* NAND OP_CMDs */
-+#define PAGE_READ 0x2
-+#define PAGE_READ_WITH_ECC 0x3
-+#define PAGE_READ_WITH_ECC_SPARE 0x4
-+#define PROGRAM_PAGE 0x6
-+#define PAGE_PROGRAM_WITH_ECC 0x7
-+#define PROGRAM_PAGE_SPARE 0x9
-+#define BLOCK_ERASE 0xa
-+#define FETCH_ID 0xb
-+#define RESET_DEVICE 0xd
-+
-+/*
-+ * the NAND controller performs reads/writes with ECC in 516 byte chunks.
-+ * the driver calls the chunks 'step' or 'codeword' interchangeably
-+ */
-+#define NANDC_STEP_SIZE 512
-+
-+/*
-+ * the largest page size we support is 8K, this will have 16 steps/codewords
-+ * of 512 bytes each
-+ */
-+#define MAX_NUM_STEPS (SZ_8K / NANDC_STEP_SIZE)
-+
-+/* we read at most 3 registers per codeword scan */
-+#define MAX_REG_RD (3 * MAX_NUM_STEPS)
-+
-+/* ECC modes */
-+#define ECC_NONE BIT(0)
-+#define ECC_RS_4BIT BIT(1)
-+#define ECC_BCH_4BIT BIT(2)
-+#define ECC_BCH_8BIT BIT(3)
-+
-+struct desc_info {
-+ struct list_head list;
-+
-+ enum dma_transfer_direction dir;
-+ struct scatterlist sgl;
-+ struct dma_async_tx_descriptor *dma_desc;
-+};
-+
-+/*
-+ * holds the current register values that we want to write. acts as a contiguous
-+ * chunk of memory which we use to write the controller registers through DMA.
-+ */
-+struct nandc_regs {
-+ u32 cmd;
-+ u32 addr0;
-+ u32 addr1;
-+ u32 chip_sel;
-+ u32 exec;
-+
-+ u32 cfg0;
-+ u32 cfg1;
-+ u32 ecc_bch_cfg;
-+
-+ u32 clrflashstatus;
-+ u32 clrreadstatus;
-+
-+ u32 cmd1;
-+ u32 vld;
-+
-+ u32 orig_cmd1;
-+ u32 orig_vld;
-+
-+ u32 ecc_buf_cfg;
-+};
-+
-+/*
-+ * @cmd_crci: ADM DMA CRCI for command flow control
-+ * @data_crci: ADM DMA CRCI for data flow control
-+ * @list: DMA descriptor list (list of desc_infos)
-+ * @dma_done: completion param to denote end of last
-+ * descriptor in the list
-+ * @data_buffer: our local DMA buffer for page read/writes,
-+ * used when we can't use the buffer provided
-+ * by upper layers directly
-+ * @buf_size/count/start: markers for chip->read_buf/write_buf functions
-+ * @reg_read_buf: buffer for reading register data via DMA
-+ * @reg_read_pos: marker for data read in reg_read_buf
-+ * @cfg0, cfg1, cfg0_raw..: NANDc register configurations needed for
-+ * ecc/non-ecc mode for the current nand flash
-+ * device
-+ * @regs: a contiguous chunk of memory for DMA register
-+ * writes
-+ * @ecc_strength: 4 bit or 8 bit ecc, received via DT
-+ * @bus_width: 8 bit or 16 bit NAND bus width, received via DT
-+ * @ecc_modes: supported ECC modes by the current controller,
-+ * initialized via DT match data
-+ * @cw_size: the number of bytes in a single step/codeword
-+ * of a page, consisting of all data, ecc, spare
-+ * and reserved bytes
-+ * @cw_data: the number of bytes within a codeword protected
-+ * by ECC
-+ * @bch_enabled: flag to tell whether BCH or RS ECC mode is used
-+ * @status: value to be returned if NAND_CMD_STATUS command
-+ * is executed
-+ */
-+struct qcom_nandc_data {
-+ struct platform_device *pdev;
-+ struct device *dev;
-+
-+ void __iomem *base;
-+ struct resource *res;
-+
-+ struct clk *core_clk;
-+ struct clk *aon_clk;
-+
-+ /* DMA stuff */
-+ struct dma_chan *chan;
-+ struct dma_slave_config slave_conf;
-+ unsigned int cmd_crci;
-+ unsigned int data_crci;
-+ struct list_head list;
-+ struct completion dma_done;
-+
-+ /* MTD stuff */
-+ struct nand_chip chip;
-+ struct mtd_info mtd;
-+
-+ /* local data buffer and markers */
-+ u8 *data_buffer;
-+ int buf_size;
-+ int buf_count;
-+ int buf_start;
-+
-+ /* local buffer to read back registers */
-+ u32 *reg_read_buf;
-+ int reg_read_pos;
-+
-+ /* required configs */
-+ u32 cfg0, cfg1;
-+ u32 cfg0_raw, cfg1_raw;
-+ u32 ecc_buf_cfg;
-+ u32 ecc_bch_cfg;
-+ u32 clrflashstatus;
-+ u32 clrreadstatus;
-+ u32 sflashc_burst_cfg;
-+ u32 cmd1, vld;
-+
-+ /* register state */
-+ struct nandc_regs *regs;
-+
-+ /* things we get from DT */
-+ int ecc_strength;
-+ int bus_width;
-+
-+ u32 ecc_modes;
-+
-+ /* misc params */
-+ int cw_size;
-+ int cw_data;
-+ bool use_ecc;
-+ bool bch_enabled;
-+ u8 status;
-+ int last_command;
-+};
-+
-+static inline u32 nandc_read(struct qcom_nandc_data *this, int offset)
-+{
-+ return ioread32(this->base + offset);
-+}
-+
-+static inline void nandc_write(struct qcom_nandc_data *this, int offset,
-+ u32 val)
-+{
-+ iowrite32(val, this->base + offset);
-+}
-+
-+/* helper to configure address register values */
-+static void set_address(struct qcom_nandc_data *this, u16 column, int page)
-+{
-+ struct nand_chip *chip = &this->chip;
-+ struct nandc_regs *regs = this->regs;
-+
-+ if (chip->options & NAND_BUSWIDTH_16)
-+ column >>= 1;
-+
-+ regs->addr0 = page << 16 | column;
-+ regs->addr1 = page >> 16 & 0xff;
-+}
-+
-+/*
-+ * update_rw_regs: set up read/write register values, these will be
-+ * written to the NAND controller registers via DMA
-+ *
-+ * @num_cw: number of steps for the read/write operation
-+ * @read: read or write operation
-+ */
-+static void update_rw_regs(struct qcom_nandc_data *this, int num_cw, bool read)
-+{
-+ struct nandc_regs *regs = this->regs;
-+
-+ if (read) {
-+ if (this->use_ecc)
-+ regs->cmd = PAGE_READ_WITH_ECC | PAGE_ACC | LAST_PAGE;
-+ else
-+ regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
-+ } else {
-+ regs->cmd = PROGRAM_PAGE | PAGE_ACC | LAST_PAGE;
-+ }
-+
-+ if (this->use_ecc) {
-+ regs->cfg0 = (this->cfg0 & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+
-+ regs->cfg1 = this->cfg1;
-+ regs->ecc_bch_cfg = this->ecc_bch_cfg;
-+ } else {
-+ regs->cfg0 = (this->cfg0_raw & ~(7U << CW_PER_PAGE)) |
-+ (num_cw - 1) << CW_PER_PAGE;
-+
-+ regs->cfg1 = this->cfg1_raw;
-+ regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+ }
-+
-+ regs->ecc_buf_cfg = this->ecc_buf_cfg;
-+ regs->clrflashstatus = this->clrflashstatus;
-+ regs->clrreadstatus = this->clrreadstatus;
-+ regs->exec = 1;
-+}
-+
-+static int prep_dma_desc(struct qcom_nandc_data *this, bool read, int reg_off,
-+ const void *vaddr, int size, bool flow_control)
-+{
-+ struct desc_info *desc;
-+ struct dma_async_tx_descriptor *dma_desc;
-+ struct scatterlist *sgl;
-+ struct dma_slave_config slave_conf;
-+ int r;
-+
-+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
-+ if (!desc)
-+ return -ENOMEM;
-+
-+ list_add_tail(&desc->list, &this->list);
-+
-+ sgl = &desc->sgl;
-+
-+ sg_init_one(sgl, vaddr, size);
-+
-+ desc->dir = read ? DMA_DEV_TO_MEM : DMA_MEM_TO_DEV;
-+
-+ r = dma_map_sg(this->dev, sgl, 1, desc->dir);
-+ if (r == 0) {
-+ r = -ENOMEM;
-+ goto err;
-+ }
-+
-+ memset(&slave_conf, 0x00, sizeof(slave_conf));
-+
-+ slave_conf.device_fc = flow_control;
-+ if (read) {
-+ slave_conf.src_maxburst = 16;
-+ slave_conf.src_addr = this->res->start + reg_off;
-+ slave_conf.slave_id = this->data_crci;
-+ } else {
-+ slave_conf.dst_maxburst = 16;
-+ slave_conf.dst_addr = this->res->start + reg_off;
-+ slave_conf.slave_id = this->cmd_crci;
-+ }
-+
-+ r = dmaengine_slave_config(this->chan, &slave_conf);
-+ if (r) {
-+ dev_err(this->dev, "failed to configure dma channel\n");
-+ goto err;
-+ }
-+
-+ dma_desc = dmaengine_prep_slave_sg(this->chan, sgl, 1, desc->dir, 0);
-+ if (!dma_desc) {
-+ dev_err(this->dev, "failed to prepare desc\n");
-+ r = -EINVAL;
-+ goto err;
-+ }
-+
-+ desc->dma_desc = dma_desc;
-+
-+ return 0;
-+err:
-+ kfree(desc);
-+
-+ return r;
-+}
-+
-+/*
-+ * read_reg_dma: prepares a descriptor to read a given number of
-+ * contiguous registers to the reg_read_buf pointer
-+ *
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to read
-+ */
-+static int read_reg_dma(struct qcom_nandc_data *this, int first, int num_regs)
-+{
-+ bool flow_control = false;
-+ void *vaddr;
-+ int size;
-+
-+ if (first == NAND_READ_ID || first == NAND_FLASH_STATUS)
-+ flow_control = true;
-+
-+ size = num_regs * sizeof(u32);
-+ vaddr = this->reg_read_buf + this->reg_read_pos;
-+ this->reg_read_pos += num_regs;
-+
-+ return prep_dma_desc(this, true, first, vaddr, size, flow_control);
-+}
-+
-+/*
-+ * write_reg_dma: prepares a descriptor to write a given number of
-+ * contiguous registers
-+ *
-+ * @first: offset of the first register in the contiguous block
-+ * @num_regs: number of registers to write
-+ */
-+static int write_reg_dma(struct qcom_nandc_data *this, int first, int num_regs)
-+{
-+ bool flow_control = false;
-+ struct nandc_regs *regs = this->regs;
-+ void *vaddr;
-+ int size;
-+
-+ switch (first) {
-+ case NAND_FLASH_CMD:
-+ vaddr = &regs->cmd;
-+ flow_control = true;
-+ break;
-+ case NAND_EXEC_CMD:
-+ vaddr = &regs->exec;
-+ break;
-+ case NAND_FLASH_STATUS:
-+ vaddr = &regs->clrflashstatus;
-+ break;
-+ case NAND_DEV0_CFG0:
-+ vaddr = &regs->cfg0;
-+ break;
-+ case NAND_READ_STATUS:
-+ vaddr = &regs->clrreadstatus;
-+ break;
-+ case NAND_DEV_CMD1:
-+ vaddr = &regs->cmd1;
-+ break;
-+ case NAND_DEV_CMD1_RESTORE:
-+ first = NAND_DEV_CMD1;
-+ vaddr = &regs->orig_cmd1;
-+ break;
-+ case NAND_DEV_CMD_VLD:
-+ vaddr = &regs->vld;
-+ break;
-+ case NAND_DEV_CMD_VLD_RESTORE:
-+ first = NAND_DEV_CMD_VLD;
-+ vaddr = &regs->orig_vld;
-+ break;
-+ case NAND_EBI2_ECC_BUF_CFG:
-+ vaddr = &regs->ecc_buf_cfg;
-+ break;
-+ default:
-+ dev_err(this->dev, "invalid starting register\n");
-+ return -EINVAL;
-+ }
-+
-+ size = num_regs * sizeof(u32);
-+
-+ return prep_dma_desc(this, false, first, vaddr, size, flow_control);
-+}
-+
-+/*
-+ * read_data_dma: prepares a DMA descriptor to transfer data from the
-+ * controller's internal buffer to the buffer 'vaddr'
-+ *
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to write to
-+ * @size: DMA transaction size in bytes
-+ */
-+static int read_data_dma(struct qcom_nandc_data *this, int reg_off,
-+ const u8 *vaddr, int size)
-+{
-+ return prep_dma_desc(this, true, reg_off, vaddr, size, false);
-+}
-+
-+/*
-+ * write_data_dma: prepares a DMA descriptor to transfer data from
-+ * 'vaddr' to the controller's internal buffer
-+ *
-+ * @reg_off: offset within the controller's data buffer
-+ * @vaddr: virtual address of the buffer we want to read from
-+ * @size: DMA transaction size in bytes
-+ */
-+static int write_data_dma(struct qcom_nandc_data *this, int reg_off,
-+ const u8 *vaddr, int size)
-+{
-+ return prep_dma_desc(this, false, reg_off, vaddr, size, false);
-+}
-+
-+/*
-+ * helper to prepare dma descriptors to configure registers needed for reading a
-+ * codeword/step in a page
-+ */
-+static void config_cw_read(struct qcom_nandc_data *this)
-+{
-+ write_reg_dma(this, NAND_FLASH_CMD, 3);
-+ write_reg_dma(this, NAND_DEV0_CFG0, 3);
-+ write_reg_dma(this, NAND_EBI2_ECC_BUF_CFG, 1);
-+
-+ write_reg_dma(this, NAND_EXEC_CMD, 1);
-+
-+ read_reg_dma(this, NAND_FLASH_STATUS, 2);
-+ read_reg_dma(this, NAND_ERASED_CW_DETECT_STATUS, 1);
-+}
-+
-+/*
-+ * helpers to prepare dma descriptors used to configure registers needed for
-+ * writing a codeword/step in a page
-+ */
-+static void config_cw_write_pre(struct qcom_nandc_data *this)
-+{
-+ write_reg_dma(this, NAND_FLASH_CMD, 3);
-+ write_reg_dma(this, NAND_DEV0_CFG0, 3);
-+ write_reg_dma(this, NAND_EBI2_ECC_BUF_CFG, 1);
-+}
-+
-+static void config_cw_write_post(struct qcom_nandc_data *this)
-+{
-+ write_reg_dma(this, NAND_EXEC_CMD, 1);
-+
-+ read_reg_dma(this, NAND_FLASH_STATUS, 1);
-+
-+ write_reg_dma(this, NAND_FLASH_STATUS, 1);
-+ write_reg_dma(this, NAND_READ_STATUS, 1);
-+}
-+
-+/*
-+ * the following functions are used within chip->cmdfunc() to perform different
-+ * NAND_CMD_* commands
-+ */
-+
-+/* sets up descriptors for NAND_CMD_PARAM */
-+static int nandc_param(struct qcom_nandc_data *this)
-+{
-+ struct nandc_regs *regs = this->regs;
-+
-+ /*
-+ * NAND_CMD_PARAM is called before we know much about the FLASH chip
-+ * in use. we configure the controller to perform a raw read of 512
-+ * bytes to read onfi params
-+ */
-+ regs->cmd = PAGE_READ | PAGE_ACC | LAST_PAGE;
-+ regs->addr0 = 0;
-+ regs->addr1 = 0;
-+ regs->cfg0 = 0 << CW_PER_PAGE
-+ | 512 << UD_SIZE_BYTES
-+ | 5 << NUM_ADDR_CYCLES
-+ | 0 << SPARE_SIZE_BYTES;
-+
-+ regs->cfg1 = 7 << NAND_RECOVERY_CYCLES
-+ | 0 << CS_ACTIVE_BSY
-+ | 17 << BAD_BLOCK_BYTE_NUM
-+ | 1 << BAD_BLOCK_IN_SPARE_AREA
-+ | 2 << WR_RD_BSY_GAP
-+ | 0 << WIDE_FLASH
-+ | 1 << DEV0_CFG1_ECC_DISABLE;
-+
-+ regs->ecc_bch_cfg = 1 << ECC_CFG_ECC_DISABLE;
-+
-+ /* configure CMD1 and VLD for ONFI param probing */
-+ regs->vld = (this->vld & ~(1 << READ_START_VLD))
-+ | 0 << READ_START_VLD;
-+
-+ regs->cmd1 = (this->cmd1 & ~(0xFF << READ_ADDR))
-+ | NAND_CMD_PARAM << READ_ADDR;
-+
-+ regs->exec = 1;
-+
-+ regs->orig_cmd1 = this->cmd1;
-+ regs->orig_vld = this->vld;
-+
-+ write_reg_dma(this, NAND_DEV_CMD_VLD, 1);
-+ write_reg_dma(this, NAND_DEV_CMD1, 1);
-+
-+ this->buf_count = 512;
-+ memset(this->data_buffer, 0xff, this->buf_count);
-+
-+ config_cw_read(this);
-+
-+ read_data_dma(this, FLASH_BUF_ACC, this->data_buffer, this->buf_count);
-+
-+ /* restore CMD1 and VLD regs */
-+ write_reg_dma(this, NAND_DEV_CMD1_RESTORE, 1);
-+ write_reg_dma(this, NAND_DEV_CMD_VLD_RESTORE, 1);
-+
-+ return 0;
-+}
-+
-+/* sets up descriptors for NAND_CMD_ERASE1 */
-+static int erase_block(struct qcom_nandc_data *this, int page_addr)
-+{
-+ struct nandc_regs *regs = this->regs;
-+
-+ regs->cmd = BLOCK_ERASE | PAGE_ACC | LAST_PAGE;
-+ regs->addr0 = page_addr;
-+ regs->addr1 = 0;
-+ regs->cfg0 = this->cfg0_raw & ~(7 << CW_PER_PAGE);
-+ regs->cfg1 = this->cfg1_raw;
-+ regs->exec = 1;
-+ regs->clrflashstatus = this->clrflashstatus;
-+ regs->clrreadstatus = this->clrreadstatus;
-+
-+ write_reg_dma(this, NAND_FLASH_CMD, 3);
-+ write_reg_dma(this, NAND_DEV0_CFG0, 2);
-+ write_reg_dma(this, NAND_EXEC_CMD, 1);
-+
-+ read_reg_dma(this, NAND_FLASH_STATUS, 1);
-+
-+ write_reg_dma(this, NAND_FLASH_STATUS, 1);
-+ write_reg_dma(this, NAND_READ_STATUS, 1);
-+
-+ return 0;
-+}
-+
-+/* sets up descriptors for NAND_CMD_READID */
-+static int read_id(struct qcom_nandc_data *this, int column)
-+{
-+ struct nandc_regs *regs = this->regs;
-+
-+ if (column == -1)
-+ return 0;
-+
-+ regs->cmd = FETCH_ID;
-+ regs->addr0 = column;
-+ regs->addr1 = 0;
-+ regs->chip_sel = DM_EN;
-+ regs->exec = 1;
-+
-+ write_reg_dma(this, NAND_FLASH_CMD, 4);
-+ write_reg_dma(this, NAND_EXEC_CMD, 1);
-+
-+ read_reg_dma(this, NAND_READ_ID, 1);
-+
-+ return 0;
-+}
-+
-+/* sets up descriptors for NAND_CMD_RESET */
-+static int reset(struct qcom_nandc_data *this)
-+{
-+ struct nandc_regs *regs = this->regs;
-+
-+ regs->cmd = RESET_DEVICE;
-+ regs->exec = 1;
-+
-+ write_reg_dma(this, NAND_FLASH_CMD, 1);
-+ write_reg_dma(this, NAND_EXEC_CMD, 1);
-+
-+ read_reg_dma(this, NAND_FLASH_STATUS, 1);
-+
-+ return 0;
-+}
-+
-+/* helpers to submit/free our list of dma descriptors */
-+static void dma_callback(void *param)
-+{
-+ struct qcom_nandc_data *this = param;
-+ struct completion *c = &this->dma_done;
-+
-+ complete(c);
-+}
-+
-+static int submit_descs(struct qcom_nandc_data *this)
-+{
-+ struct completion *c = &this->dma_done;
-+ struct desc_info *desc;
-+ int r;
-+
-+ init_completion(c);
-+
-+ list_for_each_entry(desc, &this->list, list) {
-+ /*
-+ * we add a callback to the last descriptor in our list to
-+ * notify completion of command
-+ */
-+ if (list_is_last(&desc->list, &this->list)) {
-+ desc->dma_desc->callback = dma_callback;
-+ desc->dma_desc->callback_param = this;
-+ }
-+
-+ dmaengine_submit(desc->dma_desc);
-+ }
-+
-+ dma_async_issue_pending(this->chan);
-+
-+ r = wait_for_completion_timeout(c, msecs_to_jiffies(500));
-+ if (!r)
-+ return -ETIMEDOUT;
-+
-+ return 0;
-+}
-+
-+static void free_descs(struct qcom_nandc_data *this)
-+{
-+ struct desc_info *desc, *n;
-+
-+ list_for_each_entry_safe(desc, n, &this->list, list) {
-+ list_del(&desc->list);
-+ dma_unmap_sg(this->dev, &desc->sgl, 1, desc->dir);
-+ kfree(desc);
-+ }
-+}
-+
-+/* reset the register read buffer for next NAND operation */
-+static void clear_read_regs(struct qcom_nandc_data *this)
-+{
-+ this->reg_read_pos = 0;
-+ memset(this->reg_read_buf, 0, MAX_REG_RD * sizeof(*this->reg_read_buf));
-+}
-+
-+static void pre_command(struct qcom_nandc_data *this, int command)
-+{
-+ this->buf_count = 0;
-+ this->buf_start = 0;
-+ this->use_ecc = false;
-+ this->last_command = command;
-+
-+ clear_read_regs(this);
-+}
-+
-+/*
-+ * this is called after NAND_CMD_PAGEPROG and NAND_CMD_ERASE1 to set our
-+ * privately maintained status byte, this status byte can be read after
-+ * NAND_CMD_STATUS is called
-+ */
-+static void parse_erase_write_errors(struct qcom_nandc_data *this, int command)
-+{
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int num_cw;
-+ int i;
-+
-+ num_cw = command == NAND_CMD_PAGEPROG ? ecc->steps : 1;
-+
-+ for (i = 0; i < num_cw; i++) {
-+ __le32 flash_status = le32_to_cpu(this->reg_read_buf[i]);
-+
-+ if (flash_status & FS_MPU_ERR)
-+ this->status &= ~NAND_STATUS_WP;
-+
-+ if (flash_status & FS_OP_ERR || (i == (num_cw - 1) &&
-+ (flash_status & FS_DEVICE_STS_ERR)))
-+ this->status |= NAND_STATUS_FAIL;
-+ }
-+}
-+
-+static void post_command(struct qcom_nandc_data *this, int command)
-+{
-+ switch (command) {
-+ case NAND_CMD_READID:
-+ memcpy(this->data_buffer, this->reg_read_buf, this->buf_count);
-+ break;
-+ case NAND_CMD_PAGEPROG:
-+ case NAND_CMD_ERASE1:
-+ parse_erase_write_errors(this, command);
-+ break;
-+ default:
-+ break;
-+ }
-+}
-+
-+/*
-+ * Implements chip->cmdfunc. It's only used for a limited set of commands.
-+ * The rest of the commands wouldn't be called by upper layers. For example,
-+ * NAND_CMD_READOOB would never be called because we have our own versions
-+ * of read_oob ops for nand_ecc_ctrl.
-+ */
-+static void qcom_nandc_command(struct mtd_info *mtd, unsigned int command,
-+ int column, int page_addr)
-+{
-+ struct nand_chip *chip = mtd->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ struct qcom_nandc_data *this = chip->priv;
-+ bool wait = false;
-+ int r = 0;
-+
-+ pre_command(this, command);
-+
-+ switch (command) {
-+ case NAND_CMD_RESET:
-+ r = reset(this);
-+ wait = true;
-+ break;
-+
-+ case NAND_CMD_READID:
-+ this->buf_count = 4;
-+ r = read_id(this, column);
-+ wait = true;
-+ break;
-+
-+ case NAND_CMD_PARAM:
-+ r = nandc_param(this);
-+ wait = true;
-+ break;
-+
-+ case NAND_CMD_ERASE1:
-+ r = erase_block(this, page_addr);
-+ wait = true;
-+ break;
-+
-+ case NAND_CMD_READ0:
-+ /* we read the entire page for now */
-+ WARN_ON(column != 0);
-+
-+ this->use_ecc = true;
-+ set_address(this, 0, page_addr);
-+ update_rw_regs(this, ecc->steps, true);
-+ break;
-+
-+ case NAND_CMD_SEQIN:
-+ WARN_ON(column != 0);
-+ set_address(this, 0, page_addr);
-+ break;
-+
-+ case NAND_CMD_PAGEPROG:
-+ case NAND_CMD_STATUS:
-+ case NAND_CMD_NONE:
-+ default:
-+ break;
-+ }
-+
-+ if (r) {
-+ dev_err(this->dev, "failure executing command %d\n",
-+ command);
-+ free_descs(this);
-+ return;
-+ }
-+
-+ if (wait) {
-+ r = submit_descs(this);
-+ if (r)
-+ dev_err(this->dev,
-+ "failure submitting descs for command %d\n",
-+ command);
-+ }
-+
-+ free_descs(this);
-+
-+ post_command(this, command);
-+}
-+
-+/*
-+ * when using RS ECC, the NAND controller flags an error when reading an
-+ * erased page. however, there are special characters at certain offsets when
-+ * we read the erased page. we check here if the page is really empty. if so,
-+ * we replace the magic characters with 0xffs
-+ */
-+static bool empty_page_fixup(struct qcom_nandc_data *this, u8 *data_buf)
-+{
-+ struct mtd_info *mtd = &this->mtd;
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int cwperpage = ecc->steps;
-+ u8 orig1[MAX_NUM_STEPS], orig2[MAX_NUM_STEPS];
-+ int i, j;
-+
-+ /* if BCH is enabled, HW will take care of detecting erased pages */
-+ if (this->bch_enabled || !this->use_ecc)
-+ return false;
-+
-+ for (i = 0; i < cwperpage; i++) {
-+ u8 *empty1, *empty2;
-+ __le32 flash_status = le32_to_cpu(this->reg_read_buf[3 * i]);
-+
-+ /*
-+ * an erased page flags an error in NAND_FLASH_STATUS, check if
-+ * the page is erased by looking for 0x54s at offsets 3 and 175
-+ * from the beginning of each codeword
-+ */
-+ if (!(flash_status & FS_OP_ERR))
-+ break;
-+
-+ empty1 = &data_buf[3 + i * this->cw_data];
-+ empty2 = &data_buf[175 + i * this->cw_data];
-+
-+ /*
-+ * if the error wasn't because of an erased page, bail out and
-+ * and let someone else do the error checking
-+ */
-+ if ((*empty1 == 0x54 && *empty2 == 0xff) ||
-+ (*empty1 == 0xff && *empty2 == 0x54)) {
-+ orig1[i] = *empty1;
-+ orig2[i] = *empty2;
-+
-+ *empty1 = 0xff;
-+ *empty2 = 0xff;
-+ } else {
-+ break;
-+ }
-+ }
-+
-+ if (i < cwperpage || memchr_inv(data_buf, 0xff, mtd->writesize))
-+ goto not_empty;
-+
-+ /*
-+ * tell the caller that the page was empty and is fixed up, so that
-+ * parse_read_errors() doesn't think it's an error
-+ */
-+ return true;
-+
-+not_empty:
-+ /* restore original values if not empty*/
-+ for (j = 0; j < i; j++) {
-+ data_buf[3 + j * this->cw_data] = orig1[j];
-+ data_buf[175 + j * this->cw_data] = orig2[j];
-+ }
-+
-+ return false;
-+}
-+
-+struct read_stats {
-+ __le32 flash;
-+ __le32 buffer;
-+ __le32 erased_cw;
-+};
-+
-+/*
-+ * reads back status registers set by the controller to notify page read
-+ * errors. this is equivalent to what 'ecc->correct()' would do.
-+ */
-+static int parse_read_errors(struct qcom_nandc_data *this, bool erased_page)
-+{
-+ struct mtd_info *mtd = &this->mtd;
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int cwperpage = ecc->steps;
-+ unsigned int max_bitflips = 0;
-+ int i;
-+
-+ for (i = 0; i < cwperpage; i++) {
-+ int stat;
-+ struct read_stats *buf;
-+
-+ buf = (struct read_stats *) (this->reg_read_buf + 3 * i);
-+
-+ buf->flash = le32_to_cpu(buf->flash);
-+ buf->buffer = le32_to_cpu(buf->buffer);
-+ buf->erased_cw = le32_to_cpu(buf->erased_cw);
-+
-+ if (buf->flash & (FS_OP_ERR | FS_MPU_ERR)) {
-+
-+ /* ignore erased codeword errors */
-+ if (this->bch_enabled) {
-+ if ((buf->erased_cw & ERASED_CW) == ERASED_CW)
-+ continue;
-+ } else if (erased_page) {
-+ continue;
-+ }
-+
-+ if (buf->buffer & BS_UNCORRECTABLE_BIT) {
-+ mtd->ecc_stats.failed++;
-+ continue;
-+ }
-+ }
-+
-+ stat = buf->buffer & BS_CORRECTABLE_ERR_MSK;
-+ mtd->ecc_stats.corrected += stat;
-+
-+ max_bitflips = max_t(unsigned int, max_bitflips, stat);
-+ }
-+
-+ return max_bitflips;
-+}
-+
-+/*
-+ * helper to perform the actual page read operation, used by ecc->read_page()
-+ * and ecc->read_oob()
-+ */
-+static int read_page_low(struct qcom_nandc_data *this, u8 *data_buf,
-+ u8 *oob_buf)
-+{
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int i, r;
-+
-+ /* queue cmd descs for each codeword */
-+ for (i = 0; i < ecc->steps; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (ecc->steps - 1)) {
-+ data_size = ecc->size - ((ecc->steps - 1) << 2);
-+ oob_size = (ecc->steps << 2) + ecc->bytes;
-+ } else {
-+ data_size = this->cw_data;
-+ oob_size = ecc->bytes;
-+ }
-+
-+ config_cw_read(this);
-+
-+ if (data_buf)
-+ read_data_dma(this, FLASH_BUF_ACC, data_buf, data_size);
-+
-+ if (oob_buf)
-+ read_data_dma(this, FLASH_BUF_ACC + data_size, oob_buf,
-+ oob_size);
-+
-+ if (data_buf)
-+ data_buf += data_size;
-+ if (oob_buf)
-+ oob_buf += oob_size;
-+ }
-+
-+ r = submit_descs(this);
-+ if (r)
-+ dev_err(this->dev, "failure to read page/oob\n");
-+
-+ free_descs(this);
-+
-+ return r;
-+}
-+
-+/*
-+ * a helper that copies the last step/codeword of a page (containing free oob)
-+ * into our local buffer
-+ */
-+static int copy_last_cw(struct qcom_nandc_data *this, bool use_ecc, int page)
-+{
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int size;
-+ int r;
-+
-+ clear_read_regs(this);
-+
-+ size = use_ecc ? this->cw_data : this->cw_size;
-+
-+ /* prepare a clean read buffer */
-+ memset(this->data_buffer, 0xff, size);
-+
-+ this->use_ecc = use_ecc;
-+ set_address(this, this->cw_size * (ecc->steps - 1), page);
-+ update_rw_regs(this, 1, true);
-+
-+ config_cw_read(this);
-+
-+ read_data_dma(this, FLASH_BUF_ACC, this->data_buffer, size);
-+
-+ r = submit_descs(this);
-+ if (r)
-+ dev_err(this->dev, "failed to copy last codeword\n");
-+
-+ free_descs(this);
-+
-+ return r;
-+}
-+
-+/* implements ecc->read_page() */
-+static int qcom_nandc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
-+ uint8_t *buf, int oob_required, int page)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ u8 *data_buf, *oob_buf = NULL;
-+ bool erased_page;
-+ int r;
-+
-+ data_buf = buf;
-+ oob_buf = oob_required ? chip->oob_poi : NULL;
-+
-+ r = read_page_low(this, data_buf, oob_buf);
-+ if (r) {
-+ dev_err(this->dev, "failure to read page\n");
-+ return r;
-+ }
-+
-+ erased_page = empty_page_fixup(this, data_buf);
-+
-+ return parse_read_errors(this, erased_page);
-+}
-+
-+/* implements ecc->read_oob() */
-+static int qcom_nandc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int r;
-+
-+ clear_read_regs(this);
-+
-+ this->use_ecc = true;
-+ set_address(this, 0, page);
-+ update_rw_regs(this, ecc->steps, true);
-+
-+ r = read_page_low(this, NULL, chip->oob_poi);
-+ if (r)
-+ dev_err(this->dev, "failure to read oob\n");
-+
-+ return r;
-+}
-+
-+/* implements ecc->read_oob_raw(), used to read the bad block marker flag */
-+static int qcom_nandc_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ uint8_t *oob = chip->oob_poi;
-+ int start, length;
-+ int r;
-+
-+ /*
-+ * configure registers for a raw page read, the address is set to the
-+ * beginning of the last codeword, we don't care about reading ecc
-+ * portion of oob, just the free stuff
-+ */
-+ r = copy_last_cw(this, false, page);
-+ if (r)
-+ return r;
-+
-+ /*
-+ * reading raw oob has 2 parts, first the bad block byte, then the
-+ * actual free oob region. perform a memcpy in two steps
-+ */
-+ start = mtd->writesize - (this->cw_size * (ecc->steps - 1));
-+ length = chip->options & NAND_BUSWIDTH_16 ? 2 : 1;
-+
-+ memcpy(oob, this->data_buffer + start, length);
-+
-+ oob += length;
-+
-+ start = this->cw_data - (ecc->steps << 2) + 1;
-+ length = ecc->steps << 2;
-+
-+ memcpy(oob, this->data_buffer + start, length);
-+
-+ return 0;
-+}
-+
-+/* implements ecc->write_page() */
-+static int qcom_nandc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-+ const uint8_t *buf, int oob_required)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ u8 *data_buf, *oob_buf;
-+ int i, r = 0;
-+
-+ clear_read_regs(this);
-+
-+ data_buf = (u8 *) buf;
-+ oob_buf = chip->oob_poi;
-+
-+ this->use_ecc = true;
-+ update_rw_regs(this, ecc->steps, false);
-+
-+ for (i = 0; i < ecc->steps; i++) {
-+ int data_size, oob_size;
-+
-+ if (i == (ecc->steps - 1)) {
-+ data_size = ecc->size - ((ecc->steps - 1) << 2);
-+ oob_size = (ecc->steps << 2) + ecc->bytes;
-+ } else {
-+ data_size = this->cw_data;
-+ oob_size = ecc->bytes;
-+ }
-+
-+ config_cw_write_pre(this);
-+ write_data_dma(this, FLASH_BUF_ACC, data_buf, data_size);
-+
-+ /*
-+ * we don't really need to write anything to oob for the
-+ * first n - 1 codewords since these oob regions just
-+ * contain ecc that's written by the controller itself
-+ */
-+ if (i == (ecc->steps - 1))
-+ write_data_dma(this, FLASH_BUF_ACC + data_size,
-+ oob_buf, oob_size);
-+ config_cw_write_post(this);
-+
-+ data_buf += data_size;
-+ oob_buf += oob_size;
-+ }
-+
-+ r = submit_descs(this);
-+ if (r)
-+ dev_err(this->dev, "failure to write page\n");
-+
-+ free_descs(this);
-+
-+ return r;
-+}
-+
-+/*
-+ * implements ecc->write_oob()
-+ *
-+ * the NAND controller cannot write only data or only oob within a codeword,
-+ * since ecc is calculated for the combined codeword. we first copy the
-+ * entire contents for the last codeword(data + oob), replace the old oob
-+ * with the new one in chip->oob_poi, and then write the entire codeword.
-+ * this read-copy-write operation results in a slight perormance loss.
-+ */
-+static int qcom_nandc_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
-+ int page)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ uint8_t *oob = chip->oob_poi;
-+ int free_boff;
-+ int data_size, oob_size;
-+ int r, status = 0;
-+
-+ r = copy_last_cw(this, true, page);
-+ if (r)
-+ return r;
-+
-+ clear_read_regs(this);
-+
-+ /* calculate the data and oob size for the last codeword/step */
-+ data_size = ecc->size - ((ecc->steps - 1) << 2);
-+ oob_size = (ecc->steps << 2) + ecc->bytes;
-+
-+ /*
-+ * the location of spare data in the oob buffer, we could also use
-+ * ecc->layout.oobfree here
-+ */
-+ free_boff = ecc->bytes * (ecc->steps - 1);
-+
-+ /* override new oob content to last codeword */
-+ memcpy(this->data_buffer + data_size, oob + free_boff, oob_size);
-+
-+ this->use_ecc = true;
-+ set_address(this, this->cw_size * (ecc->steps - 1), page);
-+ update_rw_regs(this, 1, false);
-+
-+ config_cw_write_pre(this);
-+ write_data_dma(this, FLASH_BUF_ACC, this->data_buffer,
-+ data_size + oob_size);
-+ config_cw_write_post(this);
-+
-+ r = submit_descs(this);
-+
-+ free_descs(this);
-+
-+ if (r) {
-+ dev_err(this->dev, "failure to write oob\n");
-+ return -EIO;
-+ }
-+
-+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+
-+ status = chip->waitfunc(mtd, chip);
-+
-+ return status & NAND_STATUS_FAIL ? -EIO : 0;
-+}
-+
-+/* implements ecc->write_oob_raw(), used to write bad block marker flag */
-+static int qcom_nandc_write_oob_raw(struct mtd_info *mtd,
-+ struct nand_chip *chip, int page)
-+{
-+ struct qcom_nandc_data *this = chip->priv;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ uint8_t *oob = chip->oob_poi;
-+ int start, length;
-+ int r, status = 0;
-+
-+ r = copy_last_cw(this, false, page);
-+ if (r)
-+ return r;
-+
-+ clear_read_regs(this);
-+
-+ /*
-+ * writing raw oob has 2 parts, first the bad block region, then the
-+ * actual free region
-+ */
-+ start = mtd->writesize - (this->cw_size * (ecc->steps - 1));
-+ length = chip->options & NAND_BUSWIDTH_16 ? 2 : 1;
-+
-+ memcpy(this->data_buffer + start, oob, length);
-+
-+ oob += length;
-+
-+ start = this->cw_data - (ecc->steps << 2) + 1;
-+ length = ecc->steps << 2;
-+
-+ memcpy(this->data_buffer + start, oob, length);
-+
-+ /* prepare write */
-+ this->use_ecc = false;
-+ set_address(this, this->cw_size * (ecc->steps - 1), page);
-+ update_rw_regs(this, 1, false);
-+
-+ config_cw_write_pre(this);
-+ write_data_dma(this, FLASH_BUF_ACC, this->data_buffer, this->cw_size);
-+ config_cw_write_post(this);
-+
-+ r = submit_descs(this);
-+
-+ free_descs(this);
-+
-+ if (r) {
-+ dev_err(this->dev, "failure to write updated oob\n");
-+ return -EIO;
-+ }
-+
-+ chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-+
-+ status = chip->waitfunc(mtd, chip);
-+
-+ return status & NAND_STATUS_FAIL ? -EIO : 0;
-+}
-+
-+/*
-+ * the three functions below implement chip->read_byte(), chip->read_buf()
-+ * and chip->write_buf() respectively. these aren't used for
-+ * reading/writing page data, they are used for smaller data like reading
-+ * id, status etc
-+ */
-+static uint8_t qcom_nandc_read_byte(struct mtd_info *mtd)
-+{
-+ struct nand_chip *chip = mtd->priv;
-+ struct qcom_nandc_data *this = chip->priv;
-+ uint8_t *buf = this->data_buffer;
-+ uint8_t ret = 0x0;
-+
-+ if (this->last_command == NAND_CMD_STATUS) {
-+ ret = this->status;
-+
-+ this->status = NAND_STATUS_READY | NAND_STATUS_WP;
-+
-+ return ret;
-+ }
-+
-+ if (this->buf_start < this->buf_count)
-+ ret = buf[this->buf_start++];
-+
-+ return ret;
-+}
-+
-+static void qcom_nandc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
-+{
-+ struct nand_chip *chip = mtd->priv;
-+ struct qcom_nandc_data *this = chip->priv;
-+ int real_len = min_t(size_t, len, this->buf_count - this->buf_start);
-+
-+ memcpy(buf, this->data_buffer + this->buf_start, real_len);
-+ this->buf_start += real_len;
-+}
-+
-+static void qcom_nandc_write_buf(struct mtd_info *mtd, const uint8_t *buf,
-+ int len)
-+{
-+ struct nand_chip *chip = mtd->priv;
-+ struct qcom_nandc_data *this = chip->priv;
-+ int real_len = min_t(size_t, len, this->buf_count - this->buf_start);
-+
-+ memcpy(this->data_buffer + this->buf_start, buf, real_len);
-+
-+ this->buf_start += real_len;
-+}
-+
-+/* we support only one external chip for now */
-+static void qcom_nandc_select_chip(struct mtd_info *mtd, int chipnr)
-+{
-+ struct nand_chip *chip = mtd->priv;
-+ struct qcom_nandc_data *this = chip->priv;
-+
-+ if (chipnr <= 0)
-+ return;
-+
-+ dev_warn(this->dev, "invalid chip select\n");
-+}
-+
-+/*
-+ * NAND controller page layout info
-+ *
-+ * |-----------------------| |---------------------------------|
-+ * | xx.......xx| | *********xx.......xx|
-+ * | DATA xx..ECC..xx| | DATA **SPARE**xx..ECC..xx|
-+ * | (516) xx.......xx| | (516-n*4) **(n*4)**xx.......xx|
-+ * | xx.......xx| | *********xx.......xx|
-+ * |-----------------------| |---------------------------------|
-+ * codeword 1,2..n-1 codeword n
-+ * <---(528/532 Bytes)----> <-------(528/532 Bytes)---------->
-+ *
-+ * n = number of codewords in the page
-+ * . = ECC bytes
-+ * * = spare bytes
-+ * x = unused/reserved bytes
-+ *
-+ * 2K page: n = 4, spare = 16 bytes
-+ * 4K page: n = 8, spare = 32 bytes
-+ * 8K page: n = 16, spare = 64 bytes
-+ *
-+ * the qcom nand controller operates at a sub page/codeword level. each
-+ * codeword is 528 and 532 bytes for 4 bit and 8 bit ECC modes respectively.
-+ * the number of ECC bytes vary based on the ECC strength and the bus width.
-+ *
-+ * the first n - 1 codewords contains 516 bytes of user data, the remaining
-+ * 12/16 bytes consist of ECC and reserved data. The nth codeword contains
-+ * both user data and spare(oobavail) bytes that sum up to 516 bytes.
-+ *
-+ * the layout described above is used by the controller when the ECC block is
-+ * enabled. When we read a page with ECC enabled, the unused/reserved bytes are
-+ * skipped and not copied to our internal buffer. therefore, the nand_ecclayout
-+ * layouts defined below doesn't consider the positions occupied by the reserved
-+ * bytes
-+ *
-+ * when the ECC block is disabled, one unused byte (or two for 16 bit bus width)
-+ * in the last codeword is the position of bad block marker. the bad block
-+ * marker cannot be accessed when ECC is enabled.
-+ *
-+ */
-+
-+/*
-+ * Layouts for different page sizes and ecc modes. We skip the eccpos field
-+ * since it isn't needed for this driver
-+ */
-+
-+/* 2K page, 4 bit ECC */
-+static struct nand_ecclayout layout_oob_64 = {
-+ .eccbytes = 40,
-+ .oobfree = {
-+ { 30, 16 },
-+ },
-+};
-+
-+/* 4K page, 4 bit ECC, 8/16 bit bus width */
-+static struct nand_ecclayout layout_oob_128 = {
-+ .eccbytes = 80,
-+ .oobfree = {
-+ { 70, 32 },
-+ },
-+};
-+
-+/* 4K page, 8 bit ECC, 8 bit bus width */
-+static struct nand_ecclayout layout_oob_224_x8 = {
-+ .eccbytes = 104,
-+ .oobfree = {
-+ { 91, 32 },
-+ },
-+};
-+
-+/* 4K page, 8 bit ECC, 16 bit bus width */
-+static struct nand_ecclayout layout_oob_224_x16 = {
-+ .eccbytes = 112,
-+ .oobfree = {
-+ { 98, 32 },
-+ },
-+};
-+
-+/* 8K page, 4 bit ECC, 8/16 bit bus width */
-+static struct nand_ecclayout layout_oob_256 = {
-+ .eccbytes = 160,
-+ .oobfree = {
-+ { 151, 64 },
-+ },
-+};
-+
-+/*
-+ * this is called before scan_ident, we do some minimal configurations so
-+ * that reading ID and ONFI params work
-+ */
-+static void qcom_nandc_pre_init(struct qcom_nandc_data *this)
-+{
-+ /* kill onenand */
-+ nandc_write(this, SFLASHC_BURST_CFG, 0);
-+
-+ /* enable ADM DMA */
-+ nandc_write(this, NAND_FLASH_CHIP_SELECT, DM_EN);
-+
-+ /* save the original values of these registers */
-+ this->cmd1 = nandc_read(this, NAND_DEV_CMD1);
-+ this->vld = nandc_read(this, NAND_DEV_CMD_VLD);
-+
-+ /* initial status value */
-+ this->status = NAND_STATUS_READY | NAND_STATUS_WP;
-+}
-+
-+static int qcom_nandc_ecc_init(struct qcom_nandc_data *this)
-+{
-+ struct mtd_info *mtd = &this->mtd;
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int cwperpage;
-+ bool wide_bus;
-+
-+ /* the nand controller fetches codewords/chunks of 512 bytes */
-+ cwperpage = mtd->writesize >> 9;
-+
-+ ecc->strength = this->ecc_strength;
-+
-+ wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
-+
-+ if (ecc->strength >= 8) {
-+ /* 8 bit ECC defaults to BCH ECC on all platforms */
-+ ecc->bytes = wide_bus ? 14 : 13;
-+ } else {
-+ /*
-+ * if the controller supports BCH for 4 bit ECC, the controller
-+ * uses lesser bytes for ECC. If RS is used, the ECC bytes is
-+ * always 10 bytes
-+ */
-+ if (this->ecc_modes & ECC_BCH_4BIT)
-+ ecc->bytes = wide_bus ? 8 : 7;
-+ else
-+ ecc->bytes = 10;
-+ }
-+
-+ /* each step consists of 512 bytes of data */
-+ ecc->size = NANDC_STEP_SIZE;
-+
-+ ecc->read_page = qcom_nandc_read_page;
-+ ecc->read_oob = qcom_nandc_read_oob;
-+ ecc->write_page = qcom_nandc_write_page;
-+ ecc->write_oob = qcom_nandc_write_oob;
-+
-+ /*
-+ * the bad block marker is readable only when we read the page with ECC
-+ * disabled. all the ops above run with ECC enabled. We need raw read
-+ * and write function for oob in order to access bad block marker.
-+ */
-+ ecc->read_oob_raw = qcom_nandc_read_oob_raw;
-+ ecc->write_oob_raw = qcom_nandc_write_oob_raw;
-+
-+ switch (mtd->oobsize) {
-+ case 64:
-+ ecc->layout = &layout_oob_64;
-+ break;
-+ case 128:
-+ ecc->layout = &layout_oob_128;
-+ break;
-+ case 224:
-+ if (wide_bus)
-+ ecc->layout = &layout_oob_224_x16;
-+ else
-+ ecc->layout = &layout_oob_224_x8;
-+ break;
-+ case 256:
-+ ecc->layout = &layout_oob_256;
-+ break;
-+ default:
-+ dev_err(this->dev, "unsupported NAND device, oobsize %d\n",
-+ mtd->oobsize);
-+ return -ENODEV;
-+ }
-+
-+ ecc->mode = NAND_ECC_HW;
-+
-+ /* enable ecc by default */
-+ this->use_ecc = true;
-+
-+ return 0;
-+}
-+
-+static void qcom_nandc_hw_post_init(struct qcom_nandc_data *this)
-+{
-+ struct mtd_info *mtd = &this->mtd;
-+ struct nand_chip *chip = &this->chip;
-+ struct nand_ecc_ctrl *ecc = &chip->ecc;
-+ int cwperpage = mtd->writesize / ecc->size;
-+ int spare_bytes, bad_block_byte;
-+ bool wide_bus;
-+ int ecc_mode = 0;
-+
-+ wide_bus = chip->options & NAND_BUSWIDTH_16 ? true : false;
-+
-+ if (ecc->strength >= 8) {
-+ this->cw_size = 532;
-+
-+ spare_bytes = wide_bus ? 0 : 2;
-+
-+ this->bch_enabled = true;
-+ ecc_mode = 1;
-+ } else {
-+ this->cw_size = 528;
-+
-+ if (this->ecc_modes & ECC_BCH_4BIT) {
-+ spare_bytes = wide_bus ? 2 : 4;
-+
-+ this->bch_enabled = true;
-+ ecc_mode = 0;
-+ } else {
-+ spare_bytes = wide_bus ? 0 : 1;
-+ }
-+ }
-+
-+ /*
-+ * DATA_UD_BYTES varies based on whether the read/write command protects
-+ * spare data with ECC too. We protect spare data by default, so we set
-+ * it to main + spare data, which are 512 and 4 bytes respectively.
-+ */
-+ this->cw_data = 516;
-+
-+ bad_block_byte = mtd->writesize - this->cw_size * (cwperpage - 1) + 1;
-+
-+ this->cfg0 = (cwperpage - 1) << CW_PER_PAGE
-+ | this->cw_data << UD_SIZE_BYTES
-+ | 0 << DISABLE_STATUS_AFTER_WRITE
-+ | 5 << NUM_ADDR_CYCLES
-+ | ecc->bytes << ECC_PARITY_SIZE_BYTES_RS
-+ | 0 << STATUS_BFR_READ
-+ | 1 << SET_RD_MODE_AFTER_STATUS
-+ | spare_bytes << SPARE_SIZE_BYTES;
-+
-+ this->cfg1 = 7 << NAND_RECOVERY_CYCLES
-+ | 0 << CS_ACTIVE_BSY
-+ | bad_block_byte << BAD_BLOCK_BYTE_NUM
-+ | 0 << BAD_BLOCK_IN_SPARE_AREA
-+ | 2 << WR_RD_BSY_GAP
-+ | wide_bus << WIDE_FLASH
-+ | this->bch_enabled << ENABLE_BCH_ECC;
-+
-+ this->cfg0_raw = (cwperpage - 1) << CW_PER_PAGE
-+ | this->cw_size << UD_SIZE_BYTES
-+ | 5 << NUM_ADDR_CYCLES
-+ | 0 << SPARE_SIZE_BYTES;
-+
-+ this->cfg1_raw = 7 << NAND_RECOVERY_CYCLES
-+ | 0 << CS_ACTIVE_BSY
-+ | 17 << BAD_BLOCK_BYTE_NUM
-+ | 1 << BAD_BLOCK_IN_SPARE_AREA
-+ | 2 << WR_RD_BSY_GAP
-+ | wide_bus << WIDE_FLASH
-+ | 1 << DEV0_CFG1_ECC_DISABLE;
-+
-+ this->ecc_bch_cfg = this->bch_enabled << ECC_CFG_ECC_DISABLE
-+ | 0 << ECC_SW_RESET
-+ | this->cw_data << ECC_NUM_DATA_BYTES
-+ | 1 << ECC_FORCE_CLK_OPEN
-+ | ecc_mode << ECC_MODE
-+ | ecc->bytes << ECC_PARITY_SIZE_BYTES_BCH;
-+
-+ this->ecc_buf_cfg = 0x203 << NUM_STEPS;
-+
-+ this->clrflashstatus = FS_READY_BSY_N;
-+ this->clrreadstatus = 0xc0;
-+
-+ dev_dbg(this->dev,
-+ "cfg0 %x cfg1 %x ecc_buf_cfg %x ecc_bch cfg %x cw_size %d cw_data %d strength %d parity_bytes %d steps %d\n",
-+ this->cfg0, this->cfg1, this->ecc_buf_cfg,
-+ this->ecc_bch_cfg, this->cw_size, this->cw_data,
-+ ecc->strength, ecc->bytes, cwperpage);
-+}
-+
-+static int qcom_nandc_alloc(struct qcom_nandc_data *this)
-+{
-+ int r;
-+
-+ r = dma_set_coherent_mask(this->dev, DMA_BIT_MASK(32));
-+ if (r) {
-+ dev_err(this->dev, "failed to set DMA mask\n");
-+ return r;
-+ }
-+
-+ /*
-+ * we use the internal buffer for reading ONFI params, reading small
-+ * data like ID and status, and preforming read-copy-write operations
-+ * when writing to a codeword partially. 532 is the maximum possible
-+ * size of a codeword for our nand controller
-+ */
-+ this->buf_size = 532;
-+
-+ this->data_buffer = devm_kzalloc(this->dev, this->buf_size, GFP_KERNEL);
-+ if (!this->data_buffer)
-+ return -ENOMEM;
-+
-+ this->regs = devm_kzalloc(this->dev, sizeof(*this->regs), GFP_KERNEL);
-+ if (!this->regs)
-+ return -ENOMEM;
-+
-+ this->reg_read_buf = devm_kzalloc(this->dev,
-+ MAX_REG_RD * sizeof(*this->reg_read_buf),
-+ GFP_KERNEL);
-+ if (!this->reg_read_buf)
-+ return -ENOMEM;
-+
-+ INIT_LIST_HEAD(&this->list);
-+
-+ this->chan = dma_request_slave_channel(this->dev, "rxtx");
-+ if (!this->chan) {
-+ dev_err(this->dev, "failed to request slave channel\n");
-+ return -ENODEV;
-+ }
-+
-+ return 0;
-+}
-+
-+static void qcom_nandc_unalloc(struct qcom_nandc_data *this)
-+{
-+ dma_release_channel(this->chan);
-+}
-+
-+static int qcom_nandc_init(struct qcom_nandc_data *this)
-+{
-+ struct mtd_info *mtd = &this->mtd;
-+ struct nand_chip *chip = &this->chip;
-+ struct device_node *np = this->dev->of_node;
-+ struct mtd_part_parser_data ppdata = { .of_node = np };
-+ int r;
-+
-+ mtd->priv = chip;
-+ mtd->name = "qcom-nandc";
-+ mtd->owner = THIS_MODULE;
-+
-+ chip->priv = this;
-+
-+ chip->cmdfunc = qcom_nandc_command;
-+ chip->select_chip = qcom_nandc_select_chip;
-+ chip->read_byte = qcom_nandc_read_byte;
-+ chip->read_buf = qcom_nandc_read_buf;
-+ chip->write_buf = qcom_nandc_write_buf;
-+
-+ chip->options |= NAND_NO_SUBPAGE_WRITE | NAND_USE_BOUNCE_BUFFER;
-+ if (this->bus_width == 16)
-+ chip->options |= NAND_BUSWIDTH_16;
-+
-+ chip->bbt_options = NAND_BBT_ACCESS_BBM_RAW;
-+ if (of_get_nand_on_flash_bbt(np))
-+ chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
-+
-+ qcom_nandc_pre_init(this);
-+
-+ r = nand_scan_ident(mtd, 1, NULL);
-+ if (r)
-+ return r;
-+
-+ r = qcom_nandc_ecc_init(this);
-+ if (r)
-+ return r;
-+
-+ qcom_nandc_hw_post_init(this);
-+
-+ r = nand_scan_tail(mtd);
-+ if (r)
-+ return r;
-+
-+ return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
-+}
-+
-+static int qcom_nandc_parse_dt(struct platform_device *pdev)
-+{
-+ struct qcom_nandc_data *this = platform_get_drvdata(pdev);
-+ struct device_node *np = this->dev->of_node;
-+ int r;
-+
-+ this->ecc_strength = of_get_nand_ecc_strength(np);
-+ if (this->ecc_strength < 0) {
-+ dev_warn(this->dev,
-+ "incorrect ecc strength, setting to 4 bits/step\n");
-+ this->ecc_strength = 4;
-+ }
-+
-+ this->bus_width = of_get_nand_bus_width(np);
-+ if (this->bus_width < 0) {
-+ dev_warn(this->dev, "incorrect bus width, setting to 8\n");
-+ this->bus_width = 8;
-+ }
-+
-+ r = of_property_read_u32(np, "qcom,cmd-crci", &this->cmd_crci);
-+ if (r) {
-+ dev_err(this->dev, "command CRCI unspecified\n");
-+ return r;
-+ }
-+
-+ r = of_property_read_u32(np, "qcom,data-crci", &this->data_crci);
-+ if (r) {
-+ dev_err(this->dev, "data CRCI unspecified\n");
-+ return r;
-+ }
-+
-+ return 0;
-+}
-+
-+static int qcom_nandc_probe(struct platform_device *pdev)
-+{
-+ struct qcom_nandc_data *this;
-+ const struct of_device_id *match;
-+ int r;
-+
-+ this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
-+ if (!this)
-+ return -ENOMEM;
-+
-+ platform_set_drvdata(pdev, this);
-+
-+ this->pdev = pdev;
-+ this->dev = &pdev->dev;
-+
-+ match = of_match_device(pdev->dev.driver->of_match_table, &pdev->dev);
-+ if (!match) {
-+ dev_err(&pdev->dev, "failed to match device\n");
-+ return -ENODEV;
-+ }
-+
-+ if (!match->data) {
-+ dev_err(&pdev->dev, "failed to get device data\n");
-+ return -ENODEV;
-+ }
-+
-+ this->ecc_modes = (u32) match->data;
-+
-+ this->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-+ this->base = devm_ioremap_resource(&pdev->dev, this->res);
-+ if (IS_ERR(this->base))
-+ return PTR_ERR(this->base);
-+
-+ this->core_clk = devm_clk_get(&pdev->dev, "core");
-+ if (IS_ERR(this->core_clk))
-+ return PTR_ERR(this->core_clk);
-+
-+ this->aon_clk = devm_clk_get(&pdev->dev, "aon");
-+ if (IS_ERR(this->aon_clk))
-+ return PTR_ERR(this->aon_clk);
-+
-+ r = qcom_nandc_parse_dt(pdev);
-+ if (r)
-+ return r;
-+
-+ r = qcom_nandc_alloc(this);
-+ if (r)
-+ return r;
-+
-+ r = clk_prepare_enable(this->core_clk);
-+ if (r)
-+ goto err_core_clk;
-+
-+ r = clk_prepare_enable(this->aon_clk);
-+ if (r)
-+ goto err_aon_clk;
-+
-+ r = qcom_nandc_init(this);
-+ if (r)
-+ goto err_init;
-+
-+ return 0;
-+
-+err_init:
-+ clk_disable_unprepare(this->aon_clk);
-+err_aon_clk:
-+ clk_disable_unprepare(this->core_clk);
-+err_core_clk:
-+ qcom_nandc_unalloc(this);
-+
-+ return r;
-+}
-+
-+static int qcom_nandc_remove(struct platform_device *pdev)
-+{
-+ struct qcom_nandc_data *this = platform_get_drvdata(pdev);
-+
-+ qcom_nandc_unalloc(this);
-+
-+ clk_disable_unprepare(this->aon_clk);
-+ clk_disable_unprepare(this->core_clk);
-+
-+ return 0;
-+}
-+
-+#define EBI2_NANDC_ECC_MODES (ECC_RS_4BIT | ECC_BCH_8BIT)
-+
-+/*
-+ * data will hold a struct pointer containing more differences once we support
-+ * more IPs
-+ */
-+static const struct of_device_id qcom_nandc_of_match[] = {
-+ { .compatible = "qcom,ebi2-nandc",
-+ .data = (void *) EBI2_NANDC_ECC_MODES,
-+ },
-+ {}
-+};
-+MODULE_DEVICE_TABLE(of, qcom_nandc_of_match);
-+
-+static struct platform_driver qcom_nandc_driver = {
-+ .driver = {
-+ .name = "qcom-nandc",
-+ .of_match_table = qcom_nandc_of_match,
-+ },
-+ .probe = qcom_nandc_probe,
-+ .remove = qcom_nandc_remove,
-+};
-+module_platform_driver(qcom_nandc_driver);
-+
-+MODULE_AUTHOR("Archit Taneja <architt@codeaurora.org>");
-+MODULE_DESCRIPTION("Qualcomm NAND Controller driver");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/mtd/nand/Makefile
-+++ b/drivers/mtd/nand/Makefile
-@@ -52,5 +52,6 @@ obj-$(CONFIG_MTD_NAND_XWAY) += xway_nan
- obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
- obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
- obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
-+obj-$(CONFIG_MTD_NAND_QCOM) += qcom_nandc.o
-
- nand-objs := nand_base.o nand_bbt.o nand_timings.o
diff --git a/target/linux/ipq806x/patches-4.1/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch b/target/linux/ipq806x/patches-4.1/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch
deleted file mode 100644
index 6530eb1c86..0000000000
--- a/target/linux/ipq806x/patches-4.1/163-dt-bindings-qcom_nandc-Add-DT-bindings.patch
+++ /dev/null
@@ -1,82 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,3/5] dt/bindings: qcom_nandc: Add DT bindings
-From: Archit Taneja <architt@codeaurora.org>
-X-Patchwork-Id: 6927141
-Message-Id: <1438578498-32254-4-git-send-email-architt@codeaurora.org>
-To: linux-mtd@lists.infradead.org, dehrenberg@google.com,
- cernekee@gmail.com, computersforpeace@gmail.com
-Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org,
- sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
- Archit Taneja <architt@codeaurora.org>, devicetree@vger.kernel.org
-Date: Mon, 3 Aug 2015 10:38:16 +0530
-
-Add DT bindings document for the Qualcomm NAND controller driver.
-
-Cc: devicetree@vger.kernel.org
-
-v3:
-- Don't use '0x' when specifying nand controller address space
-- Add optional property for on-flash bbt usage
-
-Acked-by: Andy Gross <agross@codeaurora.org>
-Signed-off-by: Archit Taneja <architt@codeaurora.org>
-
----
-.../devicetree/bindings/mtd/qcom_nandc.txt | 49 ++++++++++++++++++++++
- 1 file changed, 49 insertions(+)
- create mode 100644 Documentation/devicetree/bindings/mtd/qcom_nandc.txt
-
---- /dev/null
-+++ b/Documentation/devicetree/bindings/mtd/qcom_nandc.txt
-@@ -0,0 +1,49 @@
-+* Qualcomm NAND controller
-+
-+Required properties:
-+- compatible: should be "qcom,ebi2-nand" for IPQ806x
-+- reg: MMIO address range
-+- clocks: must contain core clock and always on clock
-+- clock-names: must contain "core" for the core clock and "aon" for the
-+ always on clock
-+- dmas: DMA specifier, consisting of a phandle to the ADM DMA
-+ controller node and the channel number to be used for
-+ NAND. Refer to dma.txt and qcom_adm.txt for more details
-+- dma-names: must be "rxtx"
-+- qcom,cmd-crci: must contain the ADM command type CRCI block instance
-+ number specified for the NAND controller on the given
-+ platform
-+- qcom,data-crci: must contain the ADM data type CRCI block instance
-+ number specified for the NAND controller on the given
-+ platform
-+
-+Optional properties:
-+- nand-bus-width: bus width. Must be 8 or 16. If not present, 8 is chosen
-+ as default
-+
-+- nand-ecc-strength: number of bits to correct per ECC step. Must be 4 or 8
-+ bits. If not present, 4 is chosen as default
-+- nand-on-flash-bbt: Create/use on-flash bad block table
-+
-+The device tree may optionally contain sub-nodes describing partitions of the
-+address space. See partition.txt for more detail.
-+
-+Example:
-+
-+nand@1ac00000 {
-+ compatible = "qcom,ebi2-nandc";
-+ reg = <0x1ac00000 0x800>;
-+
-+ clocks = <&gcc EBI2_CLK>,
-+ <&gcc EBI2_AON_CLK>;
-+ clock-names = "core", "aon";
-+
-+ dmas = <&adm_dma 3>;
-+ dma-names = "rxtx";
-+ qcom,cmd-crci = <15>;
-+ qcom,data-crci = <3>;
-+
-+ partition@0 {
-+ ...
-+ };
-+};
diff --git a/target/linux/ipq806x/patches-4.1/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch b/target/linux/ipq806x/patches-4.1/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch
deleted file mode 100644
index 6bdd5e05cc..0000000000
--- a/target/linux/ipq806x/patches-4.1/164-arm-qcom-dts-Add-NAND-controller-node-for-ipq806x.patch
+++ /dev/null
@@ -1,51 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,4/5] arm: qcom: dts: Add NAND controller node for ipq806x
-From: Archit Taneja <architt@codeaurora.org>
-X-Patchwork-Id: 6927121
-Message-Id: <1438578498-32254-5-git-send-email-architt@codeaurora.org>
-To: linux-mtd@lists.infradead.org, dehrenberg@google.com,
- cernekee@gmail.com, computersforpeace@gmail.com
-Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org,
- sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
- Archit Taneja <architt@codeaurora.org>, devicetree@vger.kernel.org
-Date: Mon, 3 Aug 2015 10:38:17 +0530
-
-The nand controller in IPQ806x is of the 'EBI2 type'. Use the corresponding
-compatible string.
-
-Cc: devicetree@vger.kernel.org
-
-Reviewed-by: Andy Gross <agross@codeaurora.org>
-Signed-off-by: Archit Taneja <architt@codeaurora.org>
-
----
-arch/arm/boot/dts/qcom-ipq8064.dtsi | 15 +++++++++++++++
- 1 file changed, 15 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -663,6 +663,22 @@
-
- status = "disabled";
- };
-+
-+ nand@1ac00000 {
-+ compatible = "qcom,ebi2-nandc";
-+ reg = <0x1ac00000 0x800>;
-+
-+ clocks = <&gcc EBI2_CLK>,
-+ <&gcc EBI2_AON_CLK>;
-+ clock-names = "core", "aon";
-+
-+ dmas = <&adm_dma 3>;
-+ dma-names = "rxtx";
-+ qcom,cmd-crci = <15>;
-+ qcom,data-crci = <3>;
-+
-+ status = "disabled";
-+ };
- };
-
- sfpb_mutex: sfpb-mutex {
diff --git a/target/linux/ipq806x/patches-4.1/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch b/target/linux/ipq806x/patches-4.1/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch
deleted file mode 100644
index da1ec46c4e..0000000000
--- a/target/linux/ipq806x/patches-4.1/165-arm-qcom-dts-Enable-NAND-node-on-IPQ8064-AP148-platform.patch
+++ /dev/null
@@ -1,76 +0,0 @@
-Content-Type: text/plain; charset="utf-8"
-MIME-Version: 1.0
-Content-Transfer-Encoding: 7bit
-Subject: [v3,5/5] arm: qcom: dts: Enable NAND node on IPQ8064 AP148 platform
-From: Archit Taneja <architt@codeaurora.org>
-X-Patchwork-Id: 6927091
-Message-Id: <1438578498-32254-6-git-send-email-architt@codeaurora.org>
-To: linux-mtd@lists.infradead.org, dehrenberg@google.com,
- cernekee@gmail.com, computersforpeace@gmail.com
-Cc: linux-arm-msm@vger.kernel.org, agross@codeaurora.org,
- sboyd@codeaurora.org, linux-kernel@vger.kernel.org,
- Archit Taneja <architt@codeaurora.org>, devicetree@vger.kernel.org
-Date: Mon, 3 Aug 2015 10:38:18 +0530
-
-Enable the NAND controller node on the AP148 platform. Provide pinmux
-information.
-
-Cc: devicetree@vger.kernel.org
-
-Signed-off-by: Archit Taneja <architt@codeaurora.org>
-
----
-arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 36 ++++++++++++++++++++++++++++++++
- 1 file changed, 36 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -43,6 +43,28 @@
- bias-none;
- };
- };
-+ nand_pins: nand_pins {
-+ mux {
-+ pins = "gpio34", "gpio35", "gpio36",
-+ "gpio37", "gpio38", "gpio39",
-+ "gpio40", "gpio41", "gpio42",
-+ "gpio43", "gpio44", "gpio45",
-+ "gpio46", "gpio47";
-+ function = "nand";
-+ drive-strength = <10>;
-+ bias-disable;
-+ };
-+ pullups {
-+ pins = "gpio39";
-+ bias-pull-up;
-+ };
-+ hold {
-+ pins = "gpio40", "gpio41", "gpio42",
-+ "gpio43", "gpio44", "gpio45",
-+ "gpio46", "gpio47";
-+ bias-bus-hold;
-+ };
-+ };
- };
-
- gsbi@16300000 {
-@@ -101,5 +123,19 @@
- status = "ok";
- phy-tx0-term-offset = <7>;
- };
-+
-+ nand@1ac00000 {
-+ status = "ok";
-+
-+ pinctrl-0 = <&nand_pins>;
-+ pinctrl-names = "default";
-+
-+ nand-ecc-strength = <4>;
-+ nand-bus-width = <8>;
-+ };
- };
- };
-+
-+&adm_dma {
-+ status = "ok";
-+};
diff --git a/target/linux/ipq806x/patches-4.1/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch b/target/linux/ipq806x/patches-4.1/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch
deleted file mode 100644
index 9005de4eb5..0000000000
--- a/target/linux/ipq806x/patches-4.1/166-arch-qcom-dts-enable-qcom-smem-on-AP148-NAND.patch
+++ /dev/null
@@ -1,11 +0,0 @@
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -132,6 +132,8 @@
-
- nand-ecc-strength = <4>;
- nand-bus-width = <8>;
-+
-+ linux,part-probe = "qcom-smem";
- };
- };
- };
diff --git a/target/linux/ipq806x/patches-4.1/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch b/target/linux/ipq806x/patches-4.1/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch
deleted file mode 100644
index 18b7a80b12..0000000000
--- a/target/linux/ipq806x/patches-4.1/300-arch-arm-force-ZRELADDR-on-arch-qcom.patch
+++ /dev/null
@@ -1,62 +0,0 @@
-From b12e230f09d4481424e6a5d7e2ae566b6954e83f Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Wed, 29 Apr 2015 15:21:46 -0700
-Subject: [PATCH] HACK: arch: arm: force ZRELADDR on arch-qcom
-
-ARCH_QCOM is using the ARCH_MULTIPLATFORM option, as now recommended
-on most ARM architectures. This automatically calculate ZRELADDR by
-masking PHYS_OFFSET with 0xf8000000.
-
-However, on IPQ806x, the first ~20MB of RAM is reserved for the hardware
-network accelerators, and the bootloader removes this section from the
-layout passed from the ATAGS (when used).
-
-For newer bootloader, when DT is used, this is not a problem, we just
-reserve this memory in the device tree. But if the bootloader doesn't
-have DT support, then ATAGS have to be used. In this case, the ARM
-decompressor will position the kernel in this low mem, which will not be
-in the RAM section mapped by the bootloader, which means the kernel will
-freeze in the middle of the boot process trying to map the memory.
-
-As a work around, this patch allows disabling AUTO_ZRELADDR when
-ARCH_QCOM is selected. It makes the zImage usage possible on bootloaders
-which don't support device-tree, which is the case on certain early
-IPQ806x based designs.
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/Kconfig | 2 +-
- arch/arm/Makefile | 2 ++
- arch/arm/mach-qcom/Makefile.boot | 1 +
- 3 files changed, 4 insertions(+), 1 deletion(-)
- create mode 100644 arch/arm/mach-qcom/Makefile.boot
-
---- a/arch/arm/Kconfig
-+++ b/arch/arm/Kconfig
-@@ -320,7 +320,7 @@ config ARCH_MULTIPLATFORM
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_HAS_SG_CHAIN
- select ARM_PATCH_PHYS_VIRT
-- select AUTO_ZRELADDR
-+ select AUTO_ZRELADDR if !ARCH_QCOM
- select CLKSRC_OF
- select COMMON_CLK
- select GENERIC_CLOCKEVENTS
---- a/arch/arm/Makefile
-+++ b/arch/arm/Makefile
-@@ -248,9 +248,11 @@ MACHINE := arch/arm/mach-$(word 1,$(mac
- else
- MACHINE :=
- endif
-+ifeq ($(CONFIG_ARCH_QCOM),)
- ifeq ($(CONFIG_ARCH_MULTIPLATFORM),y)
- MACHINE :=
- endif
-+endif
-
- machdirs := $(patsubst %,arch/arm/mach-%/,$(machine-y))
- platdirs := $(patsubst %,arch/arm/plat-%/,$(sort $(plat-y)))
---- /dev/null
-+++ b/arch/arm/mach-qcom/Makefile.boot
-@@ -0,0 +1 @@
-+zreladdr-y+= 0x42208000
diff --git a/target/linux/ipq806x/patches-4.1/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch b/target/linux/ipq806x/patches-4.1/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch
deleted file mode 100644
index 1f5eba8377..0000000000
--- a/target/linux/ipq806x/patches-4.1/301-ARM-qcom-add-Netgear-Nighthawk-X4-R7500-device-tree.patch
+++ /dev/null
@@ -1,367 +0,0 @@
-From 7e77aa188a7a7c4391856a9e5ef5ef58f769e679 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <jogo@openwrt.org>
-Date: Sun, 9 Aug 2015 13:02:38 +0200
-Subject: [PATCH] ARM: qcom: add Netgear Nighthawk X4 R7500 device tree
-
-Signed-off-by: Jonas Gorski <jogo@openwrt.org>
----
- arch/arm/boot/dts/Makefile | 1 +
- arch/arm/boot/dts/qcom-ipq8064-r7500.dts | 370 +++++++++++++++++++++++++++++++
- 2 files changed, 371 insertions(+)
- create mode 100644 arch/arm/boot/dts/qcom-ipq8064-r7500.dts
-
---- a/arch/arm/boot/dts/Makefile
-+++ b/arch/arm/boot/dts/Makefile
-@@ -452,6 +452,7 @@ dtb-$(CONFIG_ARCH_QCOM) += \
- qcom-apq8084-mtp.dtb \
- qcom-ipq8064-ap148.dtb \
- qcom-ipq8064-db149.dtb \
-+ qcom-ipq8064-r7500.dtb \
- qcom-msm8660-surf.dtb \
- qcom-msm8960-cdp.dtb \
- qcom-msm8974-sony-xperia-honami.dtb
---- /dev/null
-+++ b/arch/arm/boot/dts/qcom-ipq8064-r7500.dts
-@@ -0,0 +1,342 @@
-+#include "qcom-ipq8064-v1.0.dtsi"
-+
-+#include <dt-bindings/input/input.h>
-+
-+/ {
-+ model = "Netgear Nighthawk X4 R7500";
-+ compatible = "netgear,r7500", "qcom,ipq8064";
-+
-+ memory@0 {
-+ reg = <0x42000000 0xe000000>;
-+ device_type = "memory";
-+ };
-+
-+ reserved-memory {
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+ ranges;
-+ rsvd@41200000 {
-+ reg = <0x41200000 0x300000>;
-+ no-map;
-+ };
-+ };
-+
-+ aliases {
-+ serial0 = &uart4;
-+ mdio-gpio0 = &mdio0;
-+ };
-+
-+ chosen {
-+ bootargs = "rootfstype=squashfs noinitrd";
-+ linux,stdout-path = "serial0:115200n8";
-+ };
-+
-+ soc {
-+ pinmux@800000 {
-+ i2c4_pins: i2c4_pinmux {
-+ pins = "gpio12", "gpio13";
-+ function = "gsbi4";
-+ bias-disable;
-+ };
-+
-+ nand_pins: nand_pins {
-+ mux {
-+ pins = "gpio34", "gpio35", "gpio36",
-+ "gpio37", "gpio38", "gpio39",
-+ "gpio40", "gpio41", "gpio42",
-+ "gpio43", "gpio44", "gpio45",
-+ "gpio46", "gpio47";
-+ function = "nand";
-+ drive-strength = <10>;
-+ bias-disable;
-+ };
-+ pullups {
-+ pins = "gpio39";
-+ bias-pull-up;
-+ };
-+ hold {
-+ pins = "gpio40", "gpio41", "gpio42",
-+ "gpio43", "gpio44", "gpio45",
-+ "gpio46", "gpio47";
-+ bias-bus-hold;
-+ };
-+ };
-+
-+ 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 {
-+ qcom,mode = <GSBI_PROT_I2C_UART>;
-+ status = "ok";
-+ serial@16340000 {
-+ status = "ok";
-+ };
-+ /*
-+ * The i2c device on gsbi4 should not be enabled.
-+ * On ipq806x designs gsbi4 i2c is meant for exclusive
-+ * RPM usage. Turning this on in kernel manifests as
-+ * i2c failure for the RPM.
-+ */
-+ };
-+
-+ sata-phy@1b400000 {
-+ status = "ok";
-+ };
-+
-+ sata@29000000 {
-+ status = "ok";
-+ };
-+
-+ phy@100f8800 { /* USB3 port 1 HS phy */
-+ status = "ok";
-+ };
-+
-+ phy@100f8830 { /* USB3 port 1 SS phy */
-+ status = "ok";
-+ };
-+
-+ phy@110f8800 { /* USB3 port 0 HS phy */
-+ status = "ok";
-+ };
-+
-+ phy@110f8830 { /* USB3 port 0 SS phy */
-+ status = "ok";
-+ };
-+
-+ usb30@0 {
-+ status = "ok";
-+ };
-+
-+ usb30@1 {
-+ status = "ok";
-+ };
-+
-+ pcie0: pci@1b500000 {
-+ status = "ok";
-+ };
-+
-+ pcie1: pci@1b700000 {
-+ status = "ok";
-+ };
-+
-+ nand@1ac00000 {
-+ status = "ok";
-+
-+ pinctrl-0 = <&nand_pins>;
-+ pinctrl-names = "default";
-+
-+ nand-ecc-strength = <4>;
-+ nand-bus-width = <8>;
-+
-+ #address-cells = <1>;
-+ #size-cells = <1>;
-+
-+ qcadata@0 {
-+ label = "qcadata";
-+ reg = <0x0000000 0x0c80000>;
-+ read-only;
-+ };
-+
-+ APPSBL@c80000 {
-+ label = "APPSBL";
-+ reg = <0x0c80000 0x0500000>;
-+ read-only;
-+ };
-+
-+ APPSBLENV@1180000 {
-+ label = "APPSBLENV";
-+ reg = <0x1180000 0x0080000>;
-+ read-only;
-+ };
-+
-+ art: art@1200000 {
-+ label = "art";
-+ reg = <0x1200000 0x0140000>;
-+ read-only;
-+ };
-+
-+ kernel@1340000 {
-+ label = "kernel";
-+ reg = <0x1340000 0x0200000>;
-+ };
-+
-+ ubi@1540000 {
-+ label = "ubi";
-+ reg = <0x1540000 0x1800000>;
-+ };
-+
-+ netgear@2d40000 {
-+ label = "netgear";
-+ reg = <0x2d40000 0x0c00000>;
-+ read-only;
-+ };
-+
-+ reserve@3940000 {
-+ label = "reserve";
-+ reg = <0x3940000 0x46c0000>;
-+ read-only;
-+ };
-+
-+ firmware@1340000 {
-+ label = "firmware";
-+ reg = <0x1340000 0x1a00000>;
-+ };
-+
-+ };
-+
-+ mdio0: mdio {
-+ compatible = "virtual,mdio-gpio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
-+ pinctrl-0 = <&mdio0_pins>;
-+ pinctrl-names = "default";
-+
-+ 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>;
-+ };
-+ };
-+
-+ gmac1: ethernet@37200000 {
-+ status = "ok";
-+ phy-mode = "rgmii";
-+ qcom,id = <1>;
-+
-+ pinctrl-0 = <&rgmii2_pins>;
-+ pinctrl-names = "default";
-+
-+ mtd-mac-address = <&art 6>;
-+
-+ fixed-link {
-+ speed = <1000>;
-+ full-duplex;
-+ };
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <2>;
-+
-+ mtd-mac-address = <&art 0>;
-+
-+ fixed-link {
-+ speed = <1000>;
-+ full-duplex;
-+ };
-+ };
-+ };
-+
-+ gpio-keys {
-+ compatible = "gpio-keys";
-+
-+ wifi {
-+ label = "wifi";
-+ gpios = <&qcom_pinmux 6 1>;
-+ linux,code = <KEY_WLAN>;
-+ };
-+
-+ reset {
-+ label = "reset";
-+ gpios = <&qcom_pinmux 54 1>;
-+ linux,code = <KEY_RESTART>;
-+ };
-+
-+ wps {
-+ label = "wps";
-+ gpios = <&qcom_pinmux 65 1>;
-+ linux,code = <KEY_WPS_BUTTON>;
-+ };
-+ };
-+
-+ gpio-leds {
-+ compatible = "gpio-leds";
-+
-+ usb1 {
-+ label = "r7500:amber:usb1";
-+ gpios = <&qcom_pinmux 7 0>;
-+ };
-+
-+ usb3 {
-+ label = "r7500:amber:usb3";
-+ gpios = <&qcom_pinmux 8 0>;
-+ };
-+
-+ status {
-+ label = "r7500:amber:status";
-+ gpios = <&qcom_pinmux 9 0>;
-+ };
-+
-+ internet {
-+ label = "r7500:white:internet";
-+ gpios = <&qcom_pinmux 22 0>;
-+ };
-+
-+ wan {
-+ label = "r7500:white:wan";
-+ gpios = <&qcom_pinmux 23 0>;
-+ };
-+
-+ wps {
-+ label = "r7500:white:wps";
-+ gpios = <&qcom_pinmux 24 0>;
-+ };
-+
-+ esata {
-+ label = "r7500:white:esata";
-+ gpios = <&qcom_pinmux 26 0>;
-+ };
-+
-+ power {
-+ label = "r7500:white:power";
-+ gpios = <&qcom_pinmux 53 0>;
-+ default-state = "on";
-+ };
-+
-+ rfkill {
-+ label = "r7500:white:rfkill";
-+ gpios = <&qcom_pinmux 64 0>;
-+ };
-+
-+ wifi5g {
-+ label = "r7500:white:wifi5g";
-+ gpios = <&qcom_pinmux 67 0>;
-+ };
-+ };
-+};
-+
-+&adm_dma {
-+ status = "ok";
-+};
diff --git a/target/linux/ipq806x/patches-4.1/302-mtd-qcom-smem-rename-rootfs-ubi.patch b/target/linux/ipq806x/patches-4.1/302-mtd-qcom-smem-rename-rootfs-ubi.patch
deleted file mode 100644
index 471a87ba68..0000000000
--- a/target/linux/ipq806x/patches-4.1/302-mtd-qcom-smem-rename-rootfs-ubi.patch
+++ /dev/null
@@ -1,13 +0,0 @@
---- a/drivers/mtd/qcom_smem_part.c
-+++ b/drivers/mtd/qcom_smem_part.c
-@@ -192,6 +192,10 @@ static int parse_qcom_smem_partitions(st
- m_part->size = le32_to_cpu(s_part->size) * (*smem_blksz);
- m_part->offset = le32_to_cpu(s_part->start) * (*smem_blksz);
-
-+ /* "rootfs" conflicts with OpenWrt auto mounting */
-+ if (mtd_type_is_nand(master) && !strcmp(m_part->name, "rootfs"))
-+ m_part->name = "ubi";
-+
- /*
- * The last SMEM partition may have its size marked as
- * something like 0xffffffff, which means "until the end of the
diff --git a/target/linux/ipq806x/patches-4.1/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch b/target/linux/ipq806x/patches-4.1/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch
deleted file mode 100644
index dfe716953f..0000000000
--- a/target/linux/ipq806x/patches-4.1/700-clk-qcom-Add-support-for-NSS-GMAC-clocks-and-resets.patch
+++ /dev/null
@@ -1,734 +0,0 @@
-From 2fbb18f85826a9ba308fedb2cf90d3a661a39fd7 Mon Sep 17 00:00:00 2001
-From: Stephen Boyd <sboyd@codeaurora.org>
-Date: Fri, 27 Mar 2015 00:16:14 -0700
-Subject: [PATCH] clk: qcom: Add support for NSS/GMAC clocks and resets
-
-Add the NSS/GMAC clocks and the TCM clock and NSS resets.
-
-Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
----
- drivers/clk/qcom/gcc-ipq806x.c | 594 ++++++++++++++++++++++++++-
- drivers/clk/qcom/gcc-ipq806x.c.rej | 50 +++
- include/dt-bindings/clock/qcom,gcc-ipq806x.h | 2 +
- include/dt-bindings/reset/qcom,gcc-ipq806x.h | 43 ++
- 4 files changed, 688 insertions(+), 1 deletion(-)
- create mode 100644 drivers/clk/qcom/gcc-ipq806x.c.rej
-
---- a/drivers/clk/qcom/gcc-ipq806x.c
-+++ b/drivers/clk/qcom/gcc-ipq806x.c
-@@ -220,12 +220,47 @@ static struct clk_regmap pll14_vote = {
- },
- };
-
-+#define NSS_PLL_RATE(f, _l, _m, _n, i) \
-+ { \
-+ .freq = f, \
-+ .l = _l, \
-+ .m = _m, \
-+ .n = _n, \
-+ .ibits = i, \
-+ }
-+
-+static struct pll_freq_tbl pll18_freq_tbl[] = {
-+ NSS_PLL_RATE(550000000, 44, 0, 1, 0x01495625),
-+ NSS_PLL_RATE(733000000, 58, 16, 25, 0x014b5625),
-+};
-+
-+static struct clk_pll pll18 = {
-+ .l_reg = 0x31a4,
-+ .m_reg = 0x31a8,
-+ .n_reg = 0x31ac,
-+ .config_reg = 0x31b4,
-+ .mode_reg = 0x31a0,
-+ .status_reg = 0x31b8,
-+ .status_bit = 16,
-+ .post_div_shift = 16,
-+ .post_div_width = 1,
-+ .freq_tbl = pll18_freq_tbl,
-+ .clkr.hw.init = &(struct clk_init_data){
-+ .name = "pll18",
-+ .parent_names = (const char *[]){ "pxo" },
-+ .num_parents = 1,
-+ .ops = &clk_pll_ops,
-+ },
-+};
-+
- enum {
- P_PXO,
- P_PLL8,
- P_PLL3,
- P_PLL0,
- P_CXO,
-+ P_PLL14,
-+ P_PLL18,
- };
-
- static const struct parent_map gcc_pxo_pll8_map[] = {
-@@ -277,6 +312,22 @@ static const char *gcc_pxo_pll8_pll0_map
- "pll0_vote",
- };
-
-+static const struct parent_map gcc_pxo_pll8_pll14_pll18_pll0_map[] = {
-+ { P_PXO, 0 },
-+ { P_PLL8, 4 },
-+ { P_PLL0, 2 },
-+ { P_PLL14, 5 },
-+ { P_PLL18, 1 },
-+};
-+
-+static const char *gcc_pxo_pll8_pll14_pll18_pll0[] = {
-+ "pxo",
-+ "pll8_vote",
-+ "pll0_vote",
-+ "pll14",
-+ "pll18",
-+};
-+
- static struct freq_tbl clk_tbl_gsbi_uart[] = {
- { 1843200, P_PLL8, 2, 6, 625 },
- { 3686400, P_PLL8, 2, 12, 625 },
-@@ -2282,6 +2333,472 @@ static struct clk_branch ebi2_aon_clk =
- },
- };
-
-+static const struct freq_tbl clk_tbl_gmac[] = {
-+ { 133000000, P_PLL0, 1, 50, 301 },
-+ { 266000000, P_PLL0, 1, 127, 382 },
-+ { }
-+};
-+
-+static struct clk_dyn_rcg gmac_core1_src = {
-+ .ns_reg[0] = 0x3cac,
-+ .ns_reg[1] = 0x3cb0,
-+ .md_reg[0] = 0x3ca4,
-+ .md_reg[1] = 0x3ca8,
-+ .bank_reg = 0x3ca0,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_gmac,
-+ .clkr = {
-+ .enable_reg = 0x3ca0,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core1_src",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ },
-+ },
-+};
-+
-+static struct clk_branch gmac_core1_clk = {
-+ .halt_reg = 0x3c20,
-+ .halt_bit = 4,
-+ .hwcg_reg = 0x3cb4,
-+ .hwcg_bit = 6,
-+ .clkr = {
-+ .enable_reg = 0x3cb4,
-+ .enable_mask = BIT(4),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core1_clk",
-+ .parent_names = (const char *[]){
-+ "gmac_core1_src",
-+ },
-+ .num_parents = 1,
-+ .ops = &clk_branch_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ },
-+ },
-+};
-+
-+static struct clk_dyn_rcg gmac_core2_src = {
-+ .ns_reg[0] = 0x3ccc,
-+ .ns_reg[1] = 0x3cd0,
-+ .md_reg[0] = 0x3cc4,
-+ .md_reg[1] = 0x3cc8,
-+ .bank_reg = 0x3ca0,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_gmac,
-+ .clkr = {
-+ .enable_reg = 0x3cc0,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core2_src",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ },
-+ },
-+};
-+
-+static struct clk_branch gmac_core2_clk = {
-+ .halt_reg = 0x3c20,
-+ .halt_bit = 5,
-+ .hwcg_reg = 0x3cd4,
-+ .hwcg_bit = 6,
-+ .clkr = {
-+ .enable_reg = 0x3cd4,
-+ .enable_mask = BIT(4),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core2_clk",
-+ .parent_names = (const char *[]){
-+ "gmac_core2_src",
-+ },
-+ .num_parents = 1,
-+ .ops = &clk_branch_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ },
-+ },
-+};
-+
-+static struct clk_dyn_rcg gmac_core3_src = {
-+ .ns_reg[0] = 0x3cec,
-+ .ns_reg[1] = 0x3cf0,
-+ .md_reg[0] = 0x3ce4,
-+ .md_reg[1] = 0x3ce8,
-+ .bank_reg = 0x3ce0,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_gmac,
-+ .clkr = {
-+ .enable_reg = 0x3ce0,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core3_src",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ },
-+ },
-+};
-+
-+static struct clk_branch gmac_core3_clk = {
-+ .halt_reg = 0x3c20,
-+ .halt_bit = 6,
-+ .hwcg_reg = 0x3cf4,
-+ .hwcg_bit = 6,
-+ .clkr = {
-+ .enable_reg = 0x3cf4,
-+ .enable_mask = BIT(4),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core3_clk",
-+ .parent_names = (const char *[]){
-+ "gmac_core3_src",
-+ },
-+ .num_parents = 1,
-+ .ops = &clk_branch_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ },
-+ },
-+};
-+
-+static struct clk_dyn_rcg gmac_core4_src = {
-+ .ns_reg[0] = 0x3d0c,
-+ .ns_reg[1] = 0x3d10,
-+ .md_reg[0] = 0x3d04,
-+ .md_reg[1] = 0x3d08,
-+ .bank_reg = 0x3d00,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_gmac,
-+ .clkr = {
-+ .enable_reg = 0x3d00,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core4_src",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ },
-+ },
-+};
-+
-+static struct clk_branch gmac_core4_clk = {
-+ .halt_reg = 0x3c20,
-+ .halt_bit = 7,
-+ .hwcg_reg = 0x3d14,
-+ .hwcg_bit = 6,
-+ .clkr = {
-+ .enable_reg = 0x3d14,
-+ .enable_mask = BIT(4),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "gmac_core4_clk",
-+ .parent_names = (const char *[]){
-+ "gmac_core4_src",
-+ },
-+ .num_parents = 1,
-+ .ops = &clk_branch_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ },
-+ },
-+};
-+
-+static const struct freq_tbl clk_tbl_nss_tcm[] = {
-+ { 266000000, P_PLL0, 3, 0, 0 },
-+ { 400000000, P_PLL0, 2, 0, 0 },
-+ { }
-+};
-+
-+static struct clk_dyn_rcg nss_tcm_src = {
-+ .ns_reg[0] = 0x3dc4,
-+ .ns_reg[1] = 0x3dc8,
-+ .bank_reg = 0x3dc0,
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 4,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 4,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_nss_tcm,
-+ .clkr = {
-+ .enable_reg = 0x3dc0,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "nss_tcm_src",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ },
-+ },
-+};
-+
-+static struct clk_branch nss_tcm_clk = {
-+ .halt_reg = 0x3c20,
-+ .halt_bit = 14,
-+ .clkr = {
-+ .enable_reg = 0x3dd0,
-+ .enable_mask = BIT(6) | BIT(4),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "nss_tcm_clk",
-+ .parent_names = (const char *[]){
-+ "nss_tcm_src",
-+ },
-+ .num_parents = 1,
-+ .ops = &clk_branch_ops,
-+ .flags = CLK_SET_RATE_PARENT,
-+ },
-+ },
-+};
-+
-+static const struct freq_tbl clk_tbl_nss[] = {
-+ { 110000000, P_PLL18, 1, 1, 5 },
-+ { 275000000, P_PLL18, 2, 0, 0 },
-+ { 550000000, P_PLL18, 1, 0, 0 },
-+ { 733000000, P_PLL18, 1, 0, 0 },
-+ { }
-+};
-+
-+static struct clk_dyn_rcg ubi32_core1_src_clk = {
-+ .ns_reg[0] = 0x3d2c,
-+ .ns_reg[1] = 0x3d30,
-+ .md_reg[0] = 0x3d24,
-+ .md_reg[1] = 0x3d28,
-+ .bank_reg = 0x3d20,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_nss,
-+ .clkr = {
-+ .enable_reg = 0x3d20,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "ubi32_core1_src_clk",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
-+ },
-+ },
-+};
-+
-+static struct clk_dyn_rcg ubi32_core2_src_clk = {
-+ .ns_reg[0] = 0x3d4c,
-+ .ns_reg[1] = 0x3d50,
-+ .md_reg[0] = 0x3d44,
-+ .md_reg[1] = 0x3d48,
-+ .bank_reg = 0x3d40,
-+ .mn[0] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .mn[1] = {
-+ .mnctr_en_bit = 8,
-+ .mnctr_reset_bit = 7,
-+ .mnctr_mode_shift = 5,
-+ .n_val_shift = 16,
-+ .m_val_shift = 16,
-+ .width = 8,
-+ },
-+ .s[0] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .s[1] = {
-+ .src_sel_shift = 0,
-+ .parent_map = gcc_pxo_pll8_pll14_pll18_pll0_map,
-+ },
-+ .p[0] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .p[1] = {
-+ .pre_div_shift = 3,
-+ .pre_div_width = 2,
-+ },
-+ .mux_sel_bit = 0,
-+ .freq_tbl = clk_tbl_nss,
-+ .clkr = {
-+ .enable_reg = 0x3d40,
-+ .enable_mask = BIT(1),
-+ .hw.init = &(struct clk_init_data){
-+ .name = "ubi32_core2_src_clk",
-+ .parent_names = gcc_pxo_pll8_pll14_pll18_pll0,
-+ .num_parents = 5,
-+ .ops = &clk_dyn_rcg_ops,
-+ .flags = CLK_SET_RATE_PARENT | CLK_GET_RATE_NOCACHE,
-+ },
-+ },
-+};
-+
- static struct clk_regmap *gcc_ipq806x_clks[] = {
- [PLL0] = &pll0.clkr,
- [PLL0_VOTE] = &pll0_vote,
-@@ -2291,6 +2808,7 @@ static struct clk_regmap *gcc_ipq806x_cl
- [PLL8_VOTE] = &pll8_vote,
- [PLL14] = &pll14.clkr,
- [PLL14_VOTE] = &pll14_vote,
-+ [PLL18] = &pll18.clkr,
- [GSBI1_UART_SRC] = &gsbi1_uart_src.clkr,
- [GSBI1_UART_CLK] = &gsbi1_uart_clk.clkr,
- [GSBI2_UART_SRC] = &gsbi2_uart_src.clkr,
-@@ -2390,6 +2908,18 @@ static struct clk_regmap *gcc_ipq806x_cl
- [PLL9] = &hfpll0.clkr,
- [PLL10] = &hfpll1.clkr,
- [PLL12] = &hfpll_l2.clkr,
-+ [GMAC_CORE1_CLK_SRC] = &gmac_core1_src.clkr,
-+ [GMAC_CORE1_CLK] = &gmac_core1_clk.clkr,
-+ [GMAC_CORE2_CLK_SRC] = &gmac_core2_src.clkr,
-+ [GMAC_CORE2_CLK] = &gmac_core2_clk.clkr,
-+ [GMAC_CORE3_CLK_SRC] = &gmac_core3_src.clkr,
-+ [GMAC_CORE3_CLK] = &gmac_core3_clk.clkr,
-+ [GMAC_CORE4_CLK_SRC] = &gmac_core4_src.clkr,
-+ [GMAC_CORE4_CLK] = &gmac_core4_clk.clkr,
-+ [UBI32_CORE1_CLK_SRC] = &ubi32_core1_src_clk.clkr,
-+ [UBI32_CORE2_CLK_SRC] = &ubi32_core2_src_clk.clkr,
-+ [NSSTCM_CLK_SRC] = &nss_tcm_src.clkr,
-+ [NSSTCM_CLK] = &nss_tcm_clk.clkr,
- };
-
- static const struct qcom_reset_map gcc_ipq806x_resets[] = {
-@@ -2508,6 +3038,48 @@ static const struct qcom_reset_map gcc_i
- [USB30_1_PHY_RESET] = { 0x3b58, 0 },
- [NSSFB0_RESET] = { 0x3b60, 6 },
- [NSSFB1_RESET] = { 0x3b60, 7 },
-+ [UBI32_CORE1_CLKRST_CLAMP_RESET] = { 0x3d3c, 3},
-+ [UBI32_CORE1_CLAMP_RESET] = { 0x3d3c, 2 },
-+ [UBI32_CORE1_AHB_RESET] = { 0x3d3c, 1 },
-+ [UBI32_CORE1_AXI_RESET] = { 0x3d3c, 0 },
-+ [UBI32_CORE2_CLKRST_CLAMP_RESET] = { 0x3d5c, 3 },
-+ [UBI32_CORE2_CLAMP_RESET] = { 0x3d5c, 2 },
-+ [UBI32_CORE2_AHB_RESET] = { 0x3d5c, 1 },
-+ [UBI32_CORE2_AXI_RESET] = { 0x3d5c, 0 },
-+ [GMAC_CORE1_RESET] = { 0x3cbc, 0 },
-+ [GMAC_CORE2_RESET] = { 0x3cdc, 0 },
-+ [GMAC_CORE3_RESET] = { 0x3cfc, 0 },
-+ [GMAC_CORE4_RESET] = { 0x3d1c, 0 },
-+ [GMAC_AHB_RESET] = { 0x3e24, 0 },
-+ [NSS_CH0_RST_RX_CLK_N_RESET] = { 0x3b60, 0 },
-+ [NSS_CH0_RST_TX_CLK_N_RESET] = { 0x3b60, 1 },
-+ [NSS_CH0_RST_RX_125M_N_RESET] = { 0x3b60, 2 },
-+ [NSS_CH0_HW_RST_RX_125M_N_RESET] = { 0x3b60, 3 },
-+ [NSS_CH0_RST_TX_125M_N_RESET] = { 0x3b60, 4 },
-+ [NSS_CH1_RST_RX_CLK_N_RESET] = { 0x3b60, 5 },
-+ [NSS_CH1_RST_TX_CLK_N_RESET] = { 0x3b60, 6 },
-+ [NSS_CH1_RST_RX_125M_N_RESET] = { 0x3b60, 7 },
-+ [NSS_CH1_HW_RST_RX_125M_N_RESET] = { 0x3b60, 8 },
-+ [NSS_CH1_RST_TX_125M_N_RESET] = { 0x3b60, 9 },
-+ [NSS_CH2_RST_RX_CLK_N_RESET] = { 0x3b60, 10 },
-+ [NSS_CH2_RST_TX_CLK_N_RESET] = { 0x3b60, 11 },
-+ [NSS_CH2_RST_RX_125M_N_RESET] = { 0x3b60, 12 },
-+ [NSS_CH2_HW_RST_RX_125M_N_RESET] = { 0x3b60, 13 },
-+ [NSS_CH2_RST_TX_125M_N_RESET] = { 0x3b60, 14 },
-+ [NSS_CH3_RST_RX_CLK_N_RESET] = { 0x3b60, 15 },
-+ [NSS_CH3_RST_TX_CLK_N_RESET] = { 0x3b60, 16 },
-+ [NSS_CH3_RST_RX_125M_N_RESET] = { 0x3b60, 17 },
-+ [NSS_CH3_HW_RST_RX_125M_N_RESET] = { 0x3b60, 18 },
-+ [NSS_CH3_RST_TX_125M_N_RESET] = { 0x3b60, 19 },
-+ [NSS_RST_RX_250M_125M_N_RESET] = { 0x3b60, 20 },
-+ [NSS_RST_TX_250M_125M_N_RESET] = { 0x3b60, 21 },
-+ [NSS_QSGMII_TXPI_RST_N_RESET] = { 0x3b60, 22 },
-+ [NSS_QSGMII_CDR_RST_N_RESET] = { 0x3b60, 23 },
-+ [NSS_SGMII2_CDR_RST_N_RESET] = { 0x3b60, 24 },
-+ [NSS_SGMII3_CDR_RST_N_RESET] = { 0x3b60, 25 },
-+ [NSS_CAL_PRBS_RST_N_RESET] = { 0x3b60, 26 },
-+ [NSS_LCKDT_RST_N_RESET] = { 0x3b60, 27 },
-+ [NSS_SRDS_N_RESET] = { 0x3b60, 28 },
- };
-
- static const struct regmap_config gcc_ipq806x_regmap_config = {
-@@ -2536,6 +3108,8 @@ static int gcc_ipq806x_probe(struct plat
- {
- struct clk *clk;
- struct device *dev = &pdev->dev;
-+ struct regmap *regmap;
-+ int ret;
-
- /* Temporary until RPM clocks supported */
- clk = clk_register_fixed_rate(dev, "cxo", NULL, CLK_IS_ROOT, 25000000);
-@@ -2546,7 +3120,25 @@ static int gcc_ipq806x_probe(struct plat
- if (IS_ERR(clk))
- return PTR_ERR(clk);
-
-- return qcom_cc_probe(pdev, &gcc_ipq806x_desc);
-+ ret = qcom_cc_probe(pdev, &gcc_ipq806x_desc);
-+ if (ret)
-+ return ret;
-+
-+ regmap = dev_get_regmap(dev, NULL);
-+ if (!regmap)
-+ return -ENODEV;
-+
-+ /* Setup PLL18 static bits */
-+ regmap_update_bits(regmap, 0x31a4, 0xffffffc0, 0x40000400);
-+ regmap_write(regmap, 0x31b0, 0x3080);
-+
-+ /* Set GMAC footswitch sleep/wakeup values */
-+ regmap_write(regmap, 0x3cb8, 8);
-+ regmap_write(regmap, 0x3cd8, 8);
-+ regmap_write(regmap, 0x3cf8, 8);
-+ regmap_write(regmap, 0x3d18, 8);
-+
-+ return 0;
- }
-
- static int gcc_ipq806x_remove(struct platform_device *pdev)
---- a/include/dt-bindings/reset/qcom,gcc-ipq806x.h
-+++ b/include/dt-bindings/reset/qcom,gcc-ipq806x.h
-@@ -129,4 +129,47 @@
- #define USB30_1_PHY_RESET 112
- #define NSSFB0_RESET 113
- #define NSSFB1_RESET 114
-+#define UBI32_CORE1_CLKRST_CLAMP_RESET 115
-+#define UBI32_CORE1_CLAMP_RESET 116
-+#define UBI32_CORE1_AHB_RESET 117
-+#define UBI32_CORE1_AXI_RESET 118
-+#define UBI32_CORE2_CLKRST_CLAMP_RESET 119
-+#define UBI32_CORE2_CLAMP_RESET 120
-+#define UBI32_CORE2_AHB_RESET 121
-+#define UBI32_CORE2_AXI_RESET 122
-+#define GMAC_CORE1_RESET 123
-+#define GMAC_CORE2_RESET 124
-+#define GMAC_CORE3_RESET 125
-+#define GMAC_CORE4_RESET 126
-+#define GMAC_AHB_RESET 127
-+#define NSS_CH0_RST_RX_CLK_N_RESET 128
-+#define NSS_CH0_RST_TX_CLK_N_RESET 129
-+#define NSS_CH0_RST_RX_125M_N_RESET 130
-+#define NSS_CH0_HW_RST_RX_125M_N_RESET 131
-+#define NSS_CH0_RST_TX_125M_N_RESET 132
-+#define NSS_CH1_RST_RX_CLK_N_RESET 133
-+#define NSS_CH1_RST_TX_CLK_N_RESET 134
-+#define NSS_CH1_RST_RX_125M_N_RESET 135
-+#define NSS_CH1_HW_RST_RX_125M_N_RESET 136
-+#define NSS_CH1_RST_TX_125M_N_RESET 137
-+#define NSS_CH2_RST_RX_CLK_N_RESET 138
-+#define NSS_CH2_RST_TX_CLK_N_RESET 139
-+#define NSS_CH2_RST_RX_125M_N_RESET 140
-+#define NSS_CH2_HW_RST_RX_125M_N_RESET 141
-+#define NSS_CH2_RST_TX_125M_N_RESET 142
-+#define NSS_CH3_RST_RX_CLK_N_RESET 143
-+#define NSS_CH3_RST_TX_CLK_N_RESET 144
-+#define NSS_CH3_RST_RX_125M_N_RESET 145
-+#define NSS_CH3_HW_RST_RX_125M_N_RESET 146
-+#define NSS_CH3_RST_TX_125M_N_RESET 147
-+#define NSS_RST_RX_250M_125M_N_RESET 148
-+#define NSS_RST_TX_250M_125M_N_RESET 149
-+#define NSS_QSGMII_TXPI_RST_N_RESET 150
-+#define NSS_QSGMII_CDR_RST_N_RESET 151
-+#define NSS_SGMII2_CDR_RST_N_RESET 152
-+#define NSS_SGMII3_CDR_RST_N_RESET 153
-+#define NSS_CAL_PRBS_RST_N_RESET 154
-+#define NSS_LCKDT_RST_N_RESET 155
-+#define NSS_SRDS_N_RESET 156
-+
- #endif
---- a/include/dt-bindings/clock/qcom,gcc-ipq806x.h
-+++ b/include/dt-bindings/clock/qcom,gcc-ipq806x.h
-@@ -289,5 +289,7 @@
- #define UBI32_CORE1_CLK 279
- #define UBI32_CORE2_CLK 280
- #define EBI2_AON_CLK 281
-+#define NSSTCM_CLK_SRC 282
-+#define NSSTCM_CLK 283
-
- #endif
diff --git a/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch b/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
deleted file mode 100644
index 22450d4bbe..0000000000
--- a/target/linux/ipq806x/patches-4.1/701-stmmac_update_to_4.3.patch
+++ /dev/null
@@ -1,2355 +0,0 @@
---- a/drivers/net/ethernet/stmicro/Kconfig
-+++ b/drivers/net/ethernet/stmicro/Kconfig
-@@ -7,9 +7,7 @@ config NET_VENDOR_STMICRO
- default y
- depends on HAS_IOMEM
- ---help---
-- If you have a network (Ethernet) card belonging to this class, say Y
-- and read the Ethernet-HOWTO, available from
-- <http://www.tldp.org/docs.html#howto>.
-+ If you have a network (Ethernet) card belonging to this class, say Y.
-
- Note that the answer to this question doesn't directly affect the
- kernel: saying N will just cause the configurator to skip all
---- a/drivers/net/ethernet/stmicro/stmmac/Kconfig
-+++ b/drivers/net/ethernet/stmicro/stmmac/Kconfig
-@@ -16,6 +16,7 @@ if STMMAC_ETH
- config STMMAC_PLATFORM
- tristate "STMMAC Platform bus support"
- depends on STMMAC_ETH
-+ select MFD_SYSCON
- default y
- ---help---
- This selects the platform specific bus support for the stmmac driver.
-@@ -26,6 +27,95 @@ config STMMAC_PLATFORM
-
- If unsure, say N.
-
-+if STMMAC_PLATFORM
-+
-+config DWMAC_GENERIC
-+ tristate "Generic driver for DWMAC"
-+ default STMMAC_PLATFORM
-+ ---help---
-+ Generic DWMAC driver for platforms that don't require any
-+ platform specific code to function or is using platform
-+ data for setup.
-+
-+config DWMAC_IPQ806X
-+ tristate "QCA IPQ806x DWMAC support"
-+ default ARCH_QCOM
-+ depends on OF
-+ select MFD_SYSCON
-+ help
-+ Support for QCA IPQ806X DWMAC Ethernet.
-+
-+ This selects the IPQ806x SoC glue layer support for the stmmac
-+ device driver. This driver does not use any of the hardware
-+ acceleration features available on this SoC. Network devices
-+ will behave like standard non-accelerated ethernet interfaces.
-+
-+config DWMAC_LPC18XX
-+ tristate "NXP LPC18xx/43xx DWMAC support"
-+ default ARCH_LPC18XX
-+ depends on OF
-+ select MFD_SYSCON
-+ ---help---
-+ Support for NXP LPC18xx/43xx DWMAC Ethernet.
-+
-+config DWMAC_MESON
-+ tristate "Amlogic Meson dwmac support"
-+ default ARCH_MESON
-+ depends on OF
-+ help
-+ Support for Ethernet controller on Amlogic Meson SoCs.
-+
-+ This selects the Amlogic Meson SoC glue layer support for
-+ the stmmac device driver. This driver is used for Meson6 and
-+ Meson8 SoCs.
-+
-+config DWMAC_ROCKCHIP
-+ tristate "Rockchip dwmac support"
-+ default ARCH_ROCKCHIP
-+ depends on OF
-+ select MFD_SYSCON
-+ help
-+ Support for Ethernet controller on Rockchip RK3288 SoC.
-+
-+ This selects the Rockchip RK3288 SoC glue layer support for
-+ the stmmac device driver.
-+
-+config DWMAC_SOCFPGA
-+ tristate "SOCFPGA dwmac support"
-+ default ARCH_SOCFPGA
-+ depends on OF
-+ select MFD_SYSCON
-+ help
-+ Support for ethernet controller on Altera SOCFPGA
-+
-+ This selects the Altera SOCFPGA SoC glue layer support
-+ for the stmmac device driver. This driver is used for
-+ arria5 and cyclone5 FPGA SoCs.
-+
-+config DWMAC_STI
-+ tristate "STi GMAC support"
-+ default ARCH_STI
-+ depends on OF
-+ select MFD_SYSCON
-+ ---help---
-+ Support for ethernet controller on STi SOCs.
-+
-+ This selects STi SoC glue layer support for the stmmac
-+ device driver. This driver is used on for the STi series
-+ SOCs GMAC ethernet controller.
-+
-+config DWMAC_SUNXI
-+ tristate "Allwinner GMAC support"
-+ default ARCH_SUNXI
-+ depends on OF
-+ ---help---
-+ Support for Allwinner A20/A31 GMAC ethernet controllers.
-+
-+ This selects Allwinner SoC glue layer support for the
-+ stmmac device driver. This driver is used for A20/A31
-+ GMAC ethernet controller.
-+endif
-+
- config STMMAC_PCI
- tristate "STMMAC PCI bus support"
- depends on STMMAC_ETH && PCI
---- a/drivers/net/ethernet/stmicro/stmmac/Makefile
-+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
-@@ -4,9 +4,17 @@ stmmac-objs:= stmmac_main.o stmmac_ethto
- dwmac100_core.o dwmac100_dma.o enh_desc.o norm_desc.o \
- mmc_core.o stmmac_hwtstamp.o stmmac_ptp.o $(stmmac-y)
-
--obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
--stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \
-- dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
-+# Ordering matters. Generic driver must be last.
-+obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
-+obj-$(CONFIG_DWMAC_IPQ806X) += dwmac-ipq806x.o
-+obj-$(CONFIG_DWMAC_LPC18XX) += dwmac-lpc18xx.o
-+obj-$(CONFIG_DWMAC_MESON) += dwmac-meson.o
-+obj-$(CONFIG_DWMAC_ROCKCHIP) += dwmac-rk.o
-+obj-$(CONFIG_DWMAC_SOCFPGA) += dwmac-socfpga.o
-+obj-$(CONFIG_DWMAC_STI) += dwmac-sti.o
-+obj-$(CONFIG_DWMAC_SUNXI) += dwmac-sunxi.o
-+obj-$(CONFIG_DWMAC_GENERIC) += dwmac-generic.o
-+stmmac-platform-objs:= stmmac_platform.o
-
- obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
- stmmac-pci-objs:= stmmac_pci.o
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-generic.c
-@@ -0,0 +1,81 @@
-+/*
-+ * Generic DWMAC platform driver
-+ *
-+ * Copyright (C) 2007-2011 STMicroelectronics Ltd
-+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/platform_device.h>
-+
-+#include "stmmac.h"
-+#include "stmmac_platform.h"
-+
-+static int dwmac_generic_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ int ret;
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ if (pdev->dev.of_node) {
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat)) {
-+ dev_err(&pdev->dev, "dt configuration failed\n");
-+ return PTR_ERR(plat_dat);
-+ }
-+ } else {
-+ plat_dat = dev_get_platdata(&pdev->dev);
-+ if (!plat_dat) {
-+ dev_err(&pdev->dev, "no platform data provided\n");
-+ return -EINVAL;
-+ }
-+
-+ /* Set default value for multicast hash bins */
-+ plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
-+
-+ /* Set default value for unicast filter entries */
-+ plat_dat->unicast_filter_entries = 1;
-+ }
-+
-+ /* Custom initialisation (if needed) */
-+ if (plat_dat->init) {
-+ ret = plat_dat->init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+ }
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id dwmac_generic_match[] = {
-+ { .compatible = "st,spear600-gmac"},
-+ { .compatible = "snps,dwmac-3.610"},
-+ { .compatible = "snps,dwmac-3.70a"},
-+ { .compatible = "snps,dwmac-3.710"},
-+ { .compatible = "snps,dwmac"},
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, dwmac_generic_match);
-+
-+static struct platform_driver dwmac_generic_driver = {
-+ .probe = dwmac_generic_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = STMMAC_RESOURCE_NAME,
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = of_match_ptr(dwmac_generic_match),
-+ },
-+};
-+module_platform_driver(dwmac_generic_driver);
-+
-+MODULE_DESCRIPTION("Generic dwmac driver");
-+MODULE_LICENSE("GPL v2");
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-@@ -0,0 +1,373 @@
-+/*
-+ * Qualcomm Atheros IPQ806x GMAC glue layer
-+ *
-+ * Copyright (C) 2015 The Linux Foundation
-+ *
-+ * Permission to use, copy, modify, and/or distribute this software for any
-+ * purpose with or without fee is hereby granted, provided that the above
-+ * copyright notice and this permission notice appear in all copies.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
-+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
-+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
-+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-+ */
-+
-+#include <linux/device.h>
-+#include <linux/platform_device.h>
-+#include <linux/phy.h>
-+#include <linux/regmap.h>
-+#include <linux/clk.h>
-+#include <linux/reset.h>
-+#include <linux/of_net.h>
-+#include <linux/mfd/syscon.h>
-+#include <linux/stmmac.h>
-+#include <linux/of_mdio.h>
-+#include <linux/module.h>
-+
-+#include "stmmac_platform.h"
-+
-+#define NSS_COMMON_CLK_GATE 0x8
-+#define NSS_COMMON_CLK_GATE_PTP_EN(x) BIT(0x10 + x)
-+#define NSS_COMMON_CLK_GATE_RGMII_RX_EN(x) BIT(0x9 + (x * 2))
-+#define NSS_COMMON_CLK_GATE_RGMII_TX_EN(x) BIT(0x8 + (x * 2))
-+#define NSS_COMMON_CLK_GATE_GMII_RX_EN(x) BIT(0x4 + x)
-+#define NSS_COMMON_CLK_GATE_GMII_TX_EN(x) BIT(0x0 + x)
-+
-+#define NSS_COMMON_CLK_DIV0 0xC
-+#define NSS_COMMON_CLK_DIV_OFFSET(x) (x * 8)
-+#define NSS_COMMON_CLK_DIV_MASK 0x7f
-+
-+#define NSS_COMMON_CLK_SRC_CTRL 0x14
-+#define NSS_COMMON_CLK_SRC_CTRL_OFFSET(x) (x)
-+/* Mode is coded on 1 bit but is different depending on the MAC ID:
-+ * MAC0: QSGMII=0 RGMII=1
-+ * MAC1: QSGMII=0 SGMII=0 RGMII=1
-+ * MAC2 & MAC3: QSGMII=0 SGMII=1
-+ */
-+#define NSS_COMMON_CLK_SRC_CTRL_RGMII(x) 1
-+#define NSS_COMMON_CLK_SRC_CTRL_SGMII(x) ((x >= 2) ? 1 : 0)
-+
-+#define NSS_COMMON_MACSEC_CTL 0x28
-+#define NSS_COMMON_MACSEC_CTL_EXT_BYPASS_EN(x) (1 << x)
-+
-+#define NSS_COMMON_GMAC_CTL(x) (0x30 + (x * 4))
-+#define NSS_COMMON_GMAC_CTL_CSYS_REQ BIT(19)
-+#define NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL BIT(16)
-+#define NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET 8
-+#define NSS_COMMON_GMAC_CTL_IFG_OFFSET 0
-+#define NSS_COMMON_GMAC_CTL_IFG_MASK 0x3f
-+
-+#define NSS_COMMON_CLK_DIV_RGMII_1000 1
-+#define NSS_COMMON_CLK_DIV_RGMII_100 9
-+#define NSS_COMMON_CLK_DIV_RGMII_10 99
-+#define NSS_COMMON_CLK_DIV_SGMII_1000 0
-+#define NSS_COMMON_CLK_DIV_SGMII_100 4
-+#define NSS_COMMON_CLK_DIV_SGMII_10 49
-+
-+#define QSGMII_PCS_MODE_CTL 0x68
-+#define QSGMII_PCS_MODE_CTL_AUTONEG_EN(x) BIT((x * 8) + 7)
-+
-+#define QSGMII_PCS_CAL_LCKDT_CTL 0x120
-+#define QSGMII_PCS_CAL_LCKDT_CTL_RST BIT(19)
-+
-+/* Only GMAC1/2/3 support SGMII and their CTL register are not contiguous */
-+#define QSGMII_PHY_SGMII_CTL(x) ((x == 1) ? 0x134 : \
-+ (0x13c + (4 * (x - 2))))
-+#define QSGMII_PHY_CDR_EN BIT(0)
-+#define QSGMII_PHY_RX_FRONT_EN BIT(1)
-+#define QSGMII_PHY_RX_SIGNAL_DETECT_EN BIT(2)
-+#define QSGMII_PHY_TX_DRIVER_EN BIT(3)
-+#define QSGMII_PHY_QSGMII_EN BIT(7)
-+#define QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET 12
-+#define QSGMII_PHY_PHASE_LOOP_GAIN_MASK 0x7
-+#define QSGMII_PHY_RX_DC_BIAS_OFFSET 18
-+#define QSGMII_PHY_RX_DC_BIAS_MASK 0x3
-+#define QSGMII_PHY_RX_INPUT_EQU_OFFSET 20
-+#define QSGMII_PHY_RX_INPUT_EQU_MASK 0x3
-+#define QSGMII_PHY_CDR_PI_SLEW_OFFSET 22
-+#define QSGMII_PHY_CDR_PI_SLEW_MASK 0x3
-+#define QSGMII_PHY_TX_DRV_AMP_OFFSET 28
-+#define QSGMII_PHY_TX_DRV_AMP_MASK 0xf
-+
-+struct ipq806x_gmac {
-+ struct platform_device *pdev;
-+ struct regmap *nss_common;
-+ struct regmap *qsgmii_csr;
-+ uint32_t id;
-+ struct clk *core_clk;
-+ phy_interface_t phy_mode;
-+};
-+
-+static int get_clk_div_sgmii(struct ipq806x_gmac *gmac, unsigned int speed)
-+{
-+ struct device *dev = &gmac->pdev->dev;
-+ int div;
-+
-+ switch (speed) {
-+ case SPEED_1000:
-+ div = NSS_COMMON_CLK_DIV_SGMII_1000;
-+ break;
-+
-+ case SPEED_100:
-+ div = NSS_COMMON_CLK_DIV_SGMII_100;
-+ break;
-+
-+ case SPEED_10:
-+ div = NSS_COMMON_CLK_DIV_SGMII_10;
-+ break;
-+
-+ default:
-+ dev_err(dev, "Speed %dMbps not supported in SGMII\n", speed);
-+ return -EINVAL;
-+ }
-+
-+ return div;
-+}
-+
-+static int get_clk_div_rgmii(struct ipq806x_gmac *gmac, unsigned int speed)
-+{
-+ struct device *dev = &gmac->pdev->dev;
-+ int div;
-+
-+ switch (speed) {
-+ case SPEED_1000:
-+ div = NSS_COMMON_CLK_DIV_RGMII_1000;
-+ break;
-+
-+ case SPEED_100:
-+ div = NSS_COMMON_CLK_DIV_RGMII_100;
-+ break;
-+
-+ case SPEED_10:
-+ div = NSS_COMMON_CLK_DIV_RGMII_10;
-+ break;
-+
-+ default:
-+ dev_err(dev, "Speed %dMbps not supported in RGMII\n", speed);
-+ return -EINVAL;
-+ }
-+
-+ return div;
-+}
-+
-+static int ipq806x_gmac_set_speed(struct ipq806x_gmac *gmac, unsigned int speed)
-+{
-+ uint32_t clk_bits, val;
-+ int div;
-+
-+ switch (gmac->phy_mode) {
-+ case PHY_INTERFACE_MODE_RGMII:
-+ div = get_clk_div_rgmii(gmac, speed);
-+ clk_bits = NSS_COMMON_CLK_GATE_RGMII_RX_EN(gmac->id) |
-+ NSS_COMMON_CLK_GATE_RGMII_TX_EN(gmac->id);
-+ break;
-+
-+ case PHY_INTERFACE_MODE_SGMII:
-+ div = get_clk_div_sgmii(gmac, speed);
-+ clk_bits = NSS_COMMON_CLK_GATE_GMII_RX_EN(gmac->id) |
-+ NSS_COMMON_CLK_GATE_GMII_TX_EN(gmac->id);
-+ break;
-+
-+ default:
-+ dev_err(&gmac->pdev->dev, "Unsupported PHY mode: \"%s\"\n",
-+ phy_modes(gmac->phy_mode));
-+ return -EINVAL;
-+ }
-+
-+ /* Disable the clocks */
-+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
-+ val &= ~clk_bits;
-+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
-+
-+ /* Set the divider */
-+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_DIV0, &val);
-+ val &= ~(NSS_COMMON_CLK_DIV_MASK
-+ << NSS_COMMON_CLK_DIV_OFFSET(gmac->id));
-+ val |= div << NSS_COMMON_CLK_DIV_OFFSET(gmac->id);
-+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_DIV0, val);
-+
-+ /* Enable the clock back */
-+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
-+ val |= clk_bits;
-+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
-+
-+ return 0;
-+}
-+
-+static void *ipq806x_gmac_of_parse(struct ipq806x_gmac *gmac)
-+{
-+ struct device *dev = &gmac->pdev->dev;
-+
-+ gmac->phy_mode = of_get_phy_mode(dev->of_node);
-+ if (gmac->phy_mode < 0) {
-+ dev_err(dev, "missing phy mode property\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ if (of_property_read_u32(dev->of_node, "qcom,id", &gmac->id) < 0) {
-+ dev_err(dev, "missing qcom id property\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ /* The GMACs are called 1 to 4 in the documentation, but to simplify the
-+ * code and keep it consistent with the Linux convention, we'll number
-+ * them from 0 to 3 here.
-+ */
-+ if (gmac->id < 0 || gmac->id > 3) {
-+ dev_err(dev, "invalid gmac id\n");
-+ return ERR_PTR(-EINVAL);
-+ }
-+
-+ gmac->core_clk = devm_clk_get(dev, "stmmaceth");
-+ if (IS_ERR(gmac->core_clk)) {
-+ dev_err(dev, "missing stmmaceth clk property\n");
-+ return gmac->core_clk;
-+ }
-+ clk_set_rate(gmac->core_clk, 266000000);
-+
-+ /* Setup the register map for the nss common registers */
-+ gmac->nss_common = syscon_regmap_lookup_by_phandle(dev->of_node,
-+ "qcom,nss-common");
-+ if (IS_ERR(gmac->nss_common)) {
-+ dev_err(dev, "missing nss-common node\n");
-+ return gmac->nss_common;
-+ }
-+
-+ /* Setup the register map for the qsgmii csr registers */
-+ gmac->qsgmii_csr = syscon_regmap_lookup_by_phandle(dev->of_node,
-+ "qcom,qsgmii-csr");
-+ if (IS_ERR(gmac->qsgmii_csr)) {
-+ dev_err(dev, "missing qsgmii-csr node\n");
-+ return gmac->qsgmii_csr;
-+ }
-+
-+ return NULL;
-+}
-+
-+static void ipq806x_gmac_fix_mac_speed(void *priv, unsigned int speed)
-+{
-+ struct ipq806x_gmac *gmac = priv;
-+
-+ ipq806x_gmac_set_speed(gmac, speed);
-+}
-+
-+static int ipq806x_gmac_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ struct device *dev = &pdev->dev;
-+ struct ipq806x_gmac *gmac;
-+ int val;
-+ void *err;
-+
-+ val = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (val)
-+ return val;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
-+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-+ if (!gmac)
-+ return -ENOMEM;
-+
-+ gmac->pdev = pdev;
-+
-+ err = ipq806x_gmac_of_parse(gmac);
-+ if (IS_ERR(err)) {
-+ dev_err(dev, "device tree parsing error\n");
-+ return PTR_ERR(err);
-+ }
-+
-+ regmap_write(gmac->qsgmii_csr, QSGMII_PCS_CAL_LCKDT_CTL,
-+ QSGMII_PCS_CAL_LCKDT_CTL_RST);
-+
-+ /* Inter frame gap is set to 12 */
-+ val = 12 << NSS_COMMON_GMAC_CTL_IFG_OFFSET |
-+ 12 << NSS_COMMON_GMAC_CTL_IFG_LIMIT_OFFSET;
-+ /* We also initiate an AXI low power exit request */
-+ val |= NSS_COMMON_GMAC_CTL_CSYS_REQ;
-+ switch (gmac->phy_mode) {
-+ case PHY_INTERFACE_MODE_RGMII:
-+ val |= NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
-+ break;
-+ case PHY_INTERFACE_MODE_SGMII:
-+ val &= ~NSS_COMMON_GMAC_CTL_PHY_IFACE_SEL;
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
-+ phy_modes(gmac->phy_mode));
-+ return -EINVAL;
-+ }
-+ regmap_write(gmac->nss_common, NSS_COMMON_GMAC_CTL(gmac->id), val);
-+
-+ /* Configure the clock src according to the mode */
-+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, &val);
-+ val &= ~(1 << NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id));
-+ switch (gmac->phy_mode) {
-+ case PHY_INTERFACE_MODE_RGMII:
-+ val |= NSS_COMMON_CLK_SRC_CTRL_RGMII(gmac->id) <<
-+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
-+ break;
-+ case PHY_INTERFACE_MODE_SGMII:
-+ val |= NSS_COMMON_CLK_SRC_CTRL_SGMII(gmac->id) <<
-+ NSS_COMMON_CLK_SRC_CTRL_OFFSET(gmac->id);
-+ break;
-+ default:
-+ dev_err(&pdev->dev, "Unsupported PHY mode: \"%s\"\n",
-+ phy_modes(gmac->phy_mode));
-+ return -EINVAL;
-+ }
-+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_SRC_CTRL, val);
-+
-+ /* Enable PTP clock */
-+ regmap_read(gmac->nss_common, NSS_COMMON_CLK_GATE, &val);
-+ val |= NSS_COMMON_CLK_GATE_PTP_EN(gmac->id);
-+ regmap_write(gmac->nss_common, NSS_COMMON_CLK_GATE, val);
-+
-+ if (gmac->phy_mode == PHY_INTERFACE_MODE_SGMII) {
-+ regmap_write(gmac->qsgmii_csr, QSGMII_PHY_SGMII_CTL(gmac->id),
-+ QSGMII_PHY_CDR_EN |
-+ QSGMII_PHY_RX_FRONT_EN |
-+ QSGMII_PHY_RX_SIGNAL_DETECT_EN |
-+ QSGMII_PHY_TX_DRIVER_EN |
-+ QSGMII_PHY_QSGMII_EN |
-+ 0x4 << QSGMII_PHY_PHASE_LOOP_GAIN_OFFSET |
-+ 0x3 << QSGMII_PHY_RX_DC_BIAS_OFFSET |
-+ 0x1 << QSGMII_PHY_RX_INPUT_EQU_OFFSET |
-+ 0x2 << QSGMII_PHY_CDR_PI_SLEW_OFFSET |
-+ 0xC << QSGMII_PHY_TX_DRV_AMP_OFFSET);
-+ }
-+
-+ plat_dat->has_gmac = true;
-+ plat_dat->bsp_priv = gmac;
-+ plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id ipq806x_gmac_dwmac_match[] = {
-+ { .compatible = "qcom,ipq806x-gmac" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, ipq806x_gmac_dwmac_match);
-+
-+static struct platform_driver ipq806x_gmac_dwmac_driver = {
-+ .probe = ipq806x_gmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "ipq806x-gmac-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = ipq806x_gmac_dwmac_match,
-+ },
-+};
-+module_platform_driver(ipq806x_gmac_dwmac_driver);
-+
-+MODULE_AUTHOR("Mathieu Olivari <mathieu@codeaurora.org>");
-+MODULE_DESCRIPTION("Qualcomm Atheros IPQ806x DWMAC specific glue layer");
-+MODULE_LICENSE("Dual BSD/GPL");
---- /dev/null
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-lpc18xx.c
-@@ -0,0 +1,86 @@
-+/*
-+ * DWMAC glue for NXP LPC18xx/LPC43xx Ethernet
-+ *
-+ * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com>
-+ *
-+ * This file is licensed under the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#include <linux/mfd/syscon.h>
-+#include <linux/module.h>
-+#include <linux/of.h>
-+#include <linux/of_net.h>
-+#include <linux/phy.h>
-+#include <linux/platform_device.h>
-+#include <linux/regmap.h>
-+#include <linux/stmmac.h>
-+
-+#include "stmmac_platform.h"
-+
-+/* Register defines for CREG syscon */
-+#define LPC18XX_CREG_CREG6 0x12c
-+# define LPC18XX_CREG_CREG6_ETHMODE_MASK 0x7
-+# define LPC18XX_CREG_CREG6_ETHMODE_MII 0x0
-+# define LPC18XX_CREG_CREG6_ETHMODE_RMII 0x4
-+
-+static int lpc18xx_dwmac_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ struct regmap *reg;
-+ u8 ethmode;
-+ int ret;
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
-+ plat_dat->has_gmac = true;
-+
-+ reg = syscon_regmap_lookup_by_compatible("nxp,lpc1850-creg");
-+ if (IS_ERR(reg)) {
-+ dev_err(&pdev->dev, "syscon lookup failed\n");
-+ return PTR_ERR(reg);
-+ }
-+
-+ if (plat_dat->interface == PHY_INTERFACE_MODE_MII) {
-+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_MII;
-+ } else if (plat_dat->interface == PHY_INTERFACE_MODE_RMII) {
-+ ethmode = LPC18XX_CREG_CREG6_ETHMODE_RMII;
-+ } else {
-+ dev_err(&pdev->dev, "Only MII and RMII mode supported\n");
-+ return -EINVAL;
-+ }
-+
-+ regmap_update_bits(reg, LPC18XX_CREG_CREG6,
-+ LPC18XX_CREG_CREG6_ETHMODE_MASK, ethmode);
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id lpc18xx_dwmac_match[] = {
-+ { .compatible = "nxp,lpc1850-dwmac" },
-+ { }
-+};
-+MODULE_DEVICE_TABLE(of, lpc18xx_dwmac_match);
-+
-+static struct platform_driver lpc18xx_dwmac_driver = {
-+ .probe = lpc18xx_dwmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "lpc18xx-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = lpc18xx_dwmac_match,
-+ },
-+};
-+module_platform_driver(lpc18xx_dwmac_driver);
-+
-+MODULE_AUTHOR("Joachim Eastwood <manabian@gmail.com>");
-+MODULE_DESCRIPTION("DWMAC glue for LPC18xx/43xx Ethernet");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-meson.c
-@@ -15,6 +15,7 @@
- #include <linux/ethtool.h>
- #include <linux/io.h>
- #include <linux/ioport.h>
-+#include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/stmmac.h>
-
-@@ -46,24 +47,54 @@ static void meson6_dwmac_fix_mac_speed(v
- writel(val, dwmac->reg);
- }
-
--static void *meson6_dwmac_setup(struct platform_device *pdev)
-+static int meson6_dwmac_probe(struct platform_device *pdev)
- {
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
- struct meson_dwmac *dwmac;
- struct resource *res;
-+ int ret;
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-
- dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
- if (!dwmac)
-- return ERR_PTR(-ENOMEM);
-+ return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- dwmac->reg = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(dwmac->reg))
-- return ERR_CAST(dwmac->reg);
-+ return PTR_ERR(dwmac->reg);
-+
-+ plat_dat->bsp_priv = dwmac;
-+ plat_dat->fix_mac_speed = meson6_dwmac_fix_mac_speed;
-
-- return dwmac;
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- }
-
--const struct stmmac_of_data meson6_dwmac_data = {
-- .setup = meson6_dwmac_setup,
-- .fix_mac_speed = meson6_dwmac_fix_mac_speed,
-+static const struct of_device_id meson6_dwmac_match[] = {
-+ { .compatible = "amlogic,meson6-dwmac" },
-+ { }
- };
-+MODULE_DEVICE_TABLE(of, meson6_dwmac_match);
-+
-+static struct platform_driver meson6_dwmac_driver = {
-+ .probe = meson6_dwmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "meson6-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = meson6_dwmac_match,
-+ },
-+};
-+module_platform_driver(meson6_dwmac_driver);
-+
-+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
-+MODULE_DESCRIPTION("Amlogic Meson DWMAC glue layer");
-+MODULE_LICENSE("GPL v2");
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
-@@ -22,17 +22,31 @@
- #include <linux/phy.h>
- #include <linux/of_net.h>
- #include <linux/gpio.h>
-+#include <linux/module.h>
- #include <linux/of_gpio.h>
- #include <linux/of_device.h>
-+#include <linux/platform_device.h>
- #include <linux/regulator/consumer.h>
- #include <linux/delay.h>
- #include <linux/mfd/syscon.h>
- #include <linux/regmap.h>
-
-+#include "stmmac_platform.h"
-+
-+struct rk_priv_data;
-+struct rk_gmac_ops {
-+ void (*set_to_rgmii)(struct rk_priv_data *bsp_priv,
-+ int tx_delay, int rx_delay);
-+ void (*set_to_rmii)(struct rk_priv_data *bsp_priv);
-+ void (*set_rgmii_speed)(struct rk_priv_data *bsp_priv, int speed);
-+ void (*set_rmii_speed)(struct rk_priv_data *bsp_priv, int speed);
-+};
-+
- struct rk_priv_data {
- struct platform_device *pdev;
- int phy_iface;
- struct regulator *regulator;
-+ const struct rk_gmac_ops *ops;
-
- bool clk_enabled;
- bool clock_input;
-@@ -60,103 +74,228 @@ struct rk_priv_data {
-
- #define RK3288_GRF_SOC_CON1 0x0248
- #define RK3288_GRF_SOC_CON3 0x0250
--#define RK3288_GRF_GPIO3D_E 0x01ec
--#define RK3288_GRF_GPIO4A_E 0x01f0
--#define RK3288_GRF_GPIO4B_E 0x01f4
-
- /*RK3288_GRF_SOC_CON1*/
--#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
--#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
--#define GMAC_FLOW_CTRL GRF_BIT(9)
--#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
--#define GMAC_SPEED_10M GRF_CLR_BIT(10)
--#define GMAC_SPEED_100M GRF_BIT(10)
--#define GMAC_RMII_CLK_25M GRF_BIT(11)
--#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
--#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
--#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
--#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
--#define GMAC_RMII_MODE GRF_BIT(14)
--#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
-+#define RK3288_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | \
-+ GRF_CLR_BIT(8))
-+#define RK3288_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | \
-+ GRF_BIT(8))
-+#define RK3288_GMAC_FLOW_CTRL GRF_BIT(9)
-+#define RK3288_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
-+#define RK3288_GMAC_SPEED_10M GRF_CLR_BIT(10)
-+#define RK3288_GMAC_SPEED_100M GRF_BIT(10)
-+#define RK3288_GMAC_RMII_CLK_25M GRF_BIT(11)
-+#define RK3288_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
-+#define RK3288_GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
-+#define RK3288_GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
-+#define RK3288_GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
-+#define RK3288_GMAC_RMII_MODE GRF_BIT(14)
-+#define RK3288_GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
-
- /*RK3288_GRF_SOC_CON3*/
--#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
--#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
--#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
--#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
--#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
--#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-+#define RK3288_GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
-+#define RK3288_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
-+#define RK3288_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-+#define RK3288_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-+#define RK3288_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
-+#define RK3288_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-
--static void set_to_rgmii(struct rk_priv_data *bsp_priv,
-- int tx_delay, int rx_delay)
-+static void rk3288_set_to_rgmii(struct rk_priv_data *bsp_priv,
-+ int tx_delay, int rx_delay)
- {
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
-- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-- GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR);
-+ RK3288_GMAC_PHY_INTF_SEL_RGMII |
-+ RK3288_GMAC_RMII_MODE_CLR);
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
-- GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE |
-- GMAC_CLK_RX_DL_CFG(rx_delay) |
-- GMAC_CLK_TX_DL_CFG(tx_delay));
-+ RK3288_GMAC_RXCLK_DLY_ENABLE |
-+ RK3288_GMAC_TXCLK_DLY_ENABLE |
-+ RK3288_GMAC_CLK_RX_DL_CFG(rx_delay) |
-+ RK3288_GMAC_CLK_TX_DL_CFG(tx_delay));
- }
-
--static void set_to_rmii(struct rk_priv_data *bsp_priv)
-+static void rk3288_set_to_rmii(struct rk_priv_data *bsp_priv)
- {
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
-- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-- GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE);
-+ RK3288_GMAC_PHY_INTF_SEL_RMII | RK3288_GMAC_RMII_MODE);
- }
-
--static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-+static void rk3288_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
- {
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
-- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10)
-- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
-+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-+ RK3288_GMAC_CLK_2_5M);
- else if (speed == 100)
-- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
-+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-+ RK3288_GMAC_CLK_25M);
- else if (speed == 1000)
-- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
-+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-+ RK3288_GMAC_CLK_125M);
- else
- dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
- }
-
--static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-+static void rk3288_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
- {
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (IS_ERR(bsp_priv->grf)) {
-- dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ dev_err(dev, "Missing rockchip,grf property\n");
- return;
- }
-
- if (speed == 10) {
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-- GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M);
-+ RK3288_GMAC_RMII_CLK_2_5M |
-+ RK3288_GMAC_SPEED_10M);
- } else if (speed == 100) {
- regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
-- GMAC_RMII_CLK_25M | GMAC_SPEED_100M);
-+ RK3288_GMAC_RMII_CLK_25M |
-+ RK3288_GMAC_SPEED_100M);
-+ } else {
-+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
-+ }
-+}
-+
-+static const struct rk_gmac_ops rk3288_ops = {
-+ .set_to_rgmii = rk3288_set_to_rgmii,
-+ .set_to_rmii = rk3288_set_to_rmii,
-+ .set_rgmii_speed = rk3288_set_rgmii_speed,
-+ .set_rmii_speed = rk3288_set_rmii_speed,
-+};
-+
-+#define RK3368_GRF_SOC_CON15 0x043c
-+#define RK3368_GRF_SOC_CON16 0x0440
-+
-+/* RK3368_GRF_SOC_CON15 */
-+#define RK3368_GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(9) | GRF_CLR_BIT(10) | \
-+ GRF_CLR_BIT(11))
-+#define RK3368_GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(9) | GRF_CLR_BIT(10) | \
-+ GRF_BIT(11))
-+#define RK3368_GMAC_FLOW_CTRL GRF_BIT(8)
-+#define RK3368_GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(8)
-+#define RK3368_GMAC_SPEED_10M GRF_CLR_BIT(7)
-+#define RK3368_GMAC_SPEED_100M GRF_BIT(7)
-+#define RK3368_GMAC_RMII_CLK_25M GRF_BIT(3)
-+#define RK3368_GMAC_RMII_CLK_2_5M GRF_CLR_BIT(3)
-+#define RK3368_GMAC_CLK_125M (GRF_CLR_BIT(4) | GRF_CLR_BIT(5))
-+#define RK3368_GMAC_CLK_25M (GRF_BIT(4) | GRF_BIT(5))
-+#define RK3368_GMAC_CLK_2_5M (GRF_CLR_BIT(4) | GRF_BIT(5))
-+#define RK3368_GMAC_RMII_MODE GRF_BIT(6)
-+#define RK3368_GMAC_RMII_MODE_CLR GRF_CLR_BIT(6)
-+
-+/* RK3368_GRF_SOC_CON16 */
-+#define RK3368_GMAC_TXCLK_DLY_ENABLE GRF_BIT(7)
-+#define RK3368_GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(7)
-+#define RK3368_GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
-+#define RK3368_GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
-+#define RK3368_GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 8)
-+#define RK3368_GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
-+
-+static void rk3368_set_to_rgmii(struct rk_priv_data *bsp_priv,
-+ int tx_delay, int rx_delay)
-+{
-+ struct device *dev = &bsp_priv->pdev->dev;
-+
-+ if (IS_ERR(bsp_priv->grf)) {
-+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ return;
-+ }
-+
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_PHY_INTF_SEL_RGMII |
-+ RK3368_GMAC_RMII_MODE_CLR);
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON16,
-+ RK3368_GMAC_RXCLK_DLY_ENABLE |
-+ RK3368_GMAC_TXCLK_DLY_ENABLE |
-+ RK3368_GMAC_CLK_RX_DL_CFG(rx_delay) |
-+ RK3368_GMAC_CLK_TX_DL_CFG(tx_delay));
-+}
-+
-+static void rk3368_set_to_rmii(struct rk_priv_data *bsp_priv)
-+{
-+ struct device *dev = &bsp_priv->pdev->dev;
-+
-+ if (IS_ERR(bsp_priv->grf)) {
-+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ return;
-+ }
-+
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_PHY_INTF_SEL_RMII | RK3368_GMAC_RMII_MODE);
-+}
-+
-+static void rk3368_set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
-+{
-+ struct device *dev = &bsp_priv->pdev->dev;
-+
-+ if (IS_ERR(bsp_priv->grf)) {
-+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ return;
-+ }
-+
-+ if (speed == 10)
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_CLK_2_5M);
-+ else if (speed == 100)
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_CLK_25M);
-+ else if (speed == 1000)
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_CLK_125M);
-+ else
-+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
-+}
-+
-+static void rk3368_set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
-+{
-+ struct device *dev = &bsp_priv->pdev->dev;
-+
-+ if (IS_ERR(bsp_priv->grf)) {
-+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
-+ return;
-+ }
-+
-+ if (speed == 10) {
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_RMII_CLK_2_5M |
-+ RK3368_GMAC_SPEED_10M);
-+ } else if (speed == 100) {
-+ regmap_write(bsp_priv->grf, RK3368_GRF_SOC_CON15,
-+ RK3368_GMAC_RMII_CLK_25M |
-+ RK3368_GMAC_SPEED_100M);
- } else {
- dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
- }
- }
-
-+static const struct rk_gmac_ops rk3368_ops = {
-+ .set_to_rgmii = rk3368_set_to_rgmii,
-+ .set_to_rmii = rk3368_set_to_rmii,
-+ .set_rgmii_speed = rk3368_set_rgmii_speed,
-+ .set_rmii_speed = rk3368_set_rmii_speed,
-+};
-+
- static int gmac_clk_init(struct rk_priv_data *bsp_priv)
- {
- struct device *dev = &bsp_priv->pdev->dev;
-@@ -165,46 +304,46 @@ static int gmac_clk_init(struct rk_priv_
-
- bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
- if (IS_ERR(bsp_priv->mac_clk_rx))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "mac_clk_rx");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "mac_clk_rx");
-
- bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
- if (IS_ERR(bsp_priv->mac_clk_tx))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "mac_clk_tx");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "mac_clk_tx");
-
- bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
- if (IS_ERR(bsp_priv->aclk_mac))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "aclk_mac");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "aclk_mac");
-
- bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
- if (IS_ERR(bsp_priv->pclk_mac))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "pclk_mac");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "pclk_mac");
-
- bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
- if (IS_ERR(bsp_priv->clk_mac))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "stmmaceth");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "stmmaceth");
-
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
- bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
- if (IS_ERR(bsp_priv->clk_mac_ref))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "clk_mac_ref");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "clk_mac_ref");
-
- if (!bsp_priv->clock_input) {
- bsp_priv->clk_mac_refout =
- devm_clk_get(dev, "clk_mac_refout");
- if (IS_ERR(bsp_priv->clk_mac_refout))
-- dev_err(dev, "%s: cannot get clock %s\n",
-- __func__, "clk_mac_refout");
-+ dev_err(dev, "cannot get clock %s\n",
-+ "clk_mac_refout");
- }
- }
-
- if (bsp_priv->clock_input) {
-- dev_info(dev, "%s: clock input from PHY\n", __func__);
-+ dev_info(dev, "clock input from PHY\n");
- } else {
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
- clk_set_rate(bsp_priv->clk_mac, 50000000);
-@@ -291,26 +430,25 @@ static int phy_power_on(struct rk_priv_d
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (!ldo) {
-- dev_err(dev, "%s: no regulator found\n", __func__);
-+ dev_err(dev, "no regulator found\n");
- return -1;
- }
-
- if (enable) {
- ret = regulator_enable(ldo);
- if (ret)
-- dev_err(dev, "%s: fail to enable phy-supply\n",
-- __func__);
-+ dev_err(dev, "fail to enable phy-supply\n");
- } else {
- ret = regulator_disable(ldo);
- if (ret)
-- dev_err(dev, "%s: fail to disable phy-supply\n",
-- __func__);
-+ dev_err(dev, "fail to disable phy-supply\n");
- }
-
- return 0;
- }
-
--static void *rk_gmac_setup(struct platform_device *pdev)
-+static struct rk_priv_data *rk_gmac_setup(struct platform_device *pdev,
-+ const struct rk_gmac_ops *ops)
- {
- struct rk_priv_data *bsp_priv;
- struct device *dev = &pdev->dev;
-@@ -323,6 +461,7 @@ static void *rk_gmac_setup(struct platfo
- return ERR_PTR(-ENOMEM);
-
- bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
-+ bsp_priv->ops = ops;
-
- bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
- if (IS_ERR(bsp_priv->regulator)) {
-@@ -336,12 +475,11 @@ static void *rk_gmac_setup(struct platfo
-
- ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
- if (ret) {
-- dev_err(dev, "%s: Can not read property: clock_in_out.\n",
-- __func__);
-+ dev_err(dev, "Can not read property: clock_in_out.\n");
- bsp_priv->clock_input = true;
- } else {
-- dev_info(dev, "%s: clock input or output? (%s).\n",
-- __func__, strings);
-+ dev_info(dev, "clock input or output? (%s).\n",
-+ strings);
- if (!strcmp(strings, "input"))
- bsp_priv->clock_input = true;
- else
-@@ -351,22 +489,22 @@ static void *rk_gmac_setup(struct platfo
- ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
- if (ret) {
- bsp_priv->tx_delay = 0x30;
-- dev_err(dev, "%s: Can not read property: tx_delay.", __func__);
-- dev_err(dev, "%s: set tx_delay to 0x%x\n",
-- __func__, bsp_priv->tx_delay);
-+ dev_err(dev, "Can not read property: tx_delay.");
-+ dev_err(dev, "set tx_delay to 0x%x\n",
-+ bsp_priv->tx_delay);
- } else {
-- dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value);
-+ dev_info(dev, "TX delay(0x%x).\n", value);
- bsp_priv->tx_delay = value;
- }
-
- ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
- if (ret) {
- bsp_priv->rx_delay = 0x10;
-- dev_err(dev, "%s: Can not read property: rx_delay.", __func__);
-- dev_err(dev, "%s: set rx_delay to 0x%x\n",
-- __func__, bsp_priv->rx_delay);
-+ dev_err(dev, "Can not read property: rx_delay.");
-+ dev_err(dev, "set rx_delay to 0x%x\n",
-+ bsp_priv->rx_delay);
- } else {
-- dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value);
-+ dev_info(dev, "RX delay(0x%x).\n", value);
- bsp_priv->rx_delay = value;
- }
-
-@@ -376,13 +514,14 @@ static void *rk_gmac_setup(struct platfo
-
- /*rmii or rgmii*/
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
-- dev_info(dev, "%s: init for RGMII\n", __func__);
-- set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
-+ dev_info(dev, "init for RGMII\n");
-+ bsp_priv->ops->set_to_rgmii(bsp_priv, bsp_priv->tx_delay,
-+ bsp_priv->rx_delay);
- } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
-- dev_info(dev, "%s: init for RMII\n", __func__);
-- set_to_rmii(bsp_priv);
-+ dev_info(dev, "init for RMII\n");
-+ bsp_priv->ops->set_to_rmii(bsp_priv);
- } else {
-- dev_err(dev, "%s: NO interface defined!\n", __func__);
-+ dev_err(dev, "NO interface defined!\n");
- }
-
- gmac_clk_init(bsp_priv);
-@@ -420,17 +559,68 @@ static void rk_fix_speed(void *priv, uns
- struct device *dev = &bsp_priv->pdev->dev;
-
- if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
-- set_rgmii_speed(bsp_priv, speed);
-+ bsp_priv->ops->set_rgmii_speed(bsp_priv, speed);
- else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
-- set_rmii_speed(bsp_priv, speed);
-+ bsp_priv->ops->set_rmii_speed(bsp_priv, speed);
- else
- dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
- }
-
--const struct stmmac_of_data rk3288_gmac_data = {
-- .has_gmac = 1,
-- .fix_mac_speed = rk_fix_speed,
-- .setup = rk_gmac_setup,
-- .init = rk_gmac_init,
-- .exit = rk_gmac_exit,
-+static int rk_gmac_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ const struct rk_gmac_ops *data;
-+ int ret;
-+
-+ data = of_device_get_match_data(&pdev->dev);
-+ if (!data) {
-+ dev_err(&pdev->dev, "no of match data provided\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
-+ plat_dat->has_gmac = true;
-+ plat_dat->init = rk_gmac_init;
-+ plat_dat->exit = rk_gmac_exit;
-+ plat_dat->fix_mac_speed = rk_fix_speed;
-+
-+ plat_dat->bsp_priv = rk_gmac_setup(pdev, data);
-+ if (IS_ERR(plat_dat->bsp_priv))
-+ return PTR_ERR(plat_dat->bsp_priv);
-+
-+ ret = rk_gmac_init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id rk_gmac_dwmac_match[] = {
-+ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_ops },
-+ { .compatible = "rockchip,rk3368-gmac", .data = &rk3368_ops },
-+ { }
- };
-+MODULE_DEVICE_TABLE(of, rk_gmac_dwmac_match);
-+
-+static struct platform_driver rk_gmac_dwmac_driver = {
-+ .probe = rk_gmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "rk_gmac-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = rk_gmac_dwmac_match,
-+ },
-+};
-+module_platform_driver(rk_gmac_dwmac_driver);
-+
-+MODULE_AUTHOR("Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>");
-+MODULE_DESCRIPTION("Rockchip RK3288 DWMAC specific glue layer");
-+MODULE_LICENSE("GPL");
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-socfpga.c
-@@ -175,31 +175,6 @@ static int socfpga_dwmac_setup(struct so
- return 0;
- }
-
--static void *socfpga_dwmac_probe(struct platform_device *pdev)
--{
-- struct device *dev = &pdev->dev;
-- int ret;
-- struct socfpga_dwmac *dwmac;
--
-- dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
-- if (!dwmac)
-- return ERR_PTR(-ENOMEM);
--
-- ret = socfpga_dwmac_parse_data(dwmac, dev);
-- if (ret) {
-- dev_err(dev, "Unable to parse OF data\n");
-- return ERR_PTR(ret);
-- }
--
-- ret = socfpga_dwmac_setup(dwmac);
-- if (ret) {
-- dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
-- return ERR_PTR(ret);
-- }
--
-- return dwmac;
--}
--
- static void socfpga_dwmac_exit(struct platform_device *pdev, void *priv)
- {
- struct socfpga_dwmac *dwmac = priv;
-@@ -257,9 +232,65 @@ static int socfpga_dwmac_init(struct pla
- return ret;
- }
-
--const struct stmmac_of_data socfpga_gmac_data = {
-- .setup = socfpga_dwmac_probe,
-- .init = socfpga_dwmac_init,
-- .exit = socfpga_dwmac_exit,
-- .fix_mac_speed = socfpga_dwmac_fix_mac_speed,
-+static int socfpga_dwmac_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ struct device *dev = &pdev->dev;
-+ int ret;
-+ struct socfpga_dwmac *dwmac;
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
-+ dwmac = devm_kzalloc(dev, sizeof(*dwmac), GFP_KERNEL);
-+ if (!dwmac)
-+ return -ENOMEM;
-+
-+ ret = socfpga_dwmac_parse_data(dwmac, dev);
-+ if (ret) {
-+ dev_err(dev, "Unable to parse OF data\n");
-+ return ret;
-+ }
-+
-+ ret = socfpga_dwmac_setup(dwmac);
-+ if (ret) {
-+ dev_err(dev, "couldn't setup SoC glue (%d)\n", ret);
-+ return ret;
-+ }
-+
-+ plat_dat->bsp_priv = dwmac;
-+ plat_dat->init = socfpga_dwmac_init;
-+ plat_dat->exit = socfpga_dwmac_exit;
-+ plat_dat->fix_mac_speed = socfpga_dwmac_fix_mac_speed;
-+
-+ ret = socfpga_dwmac_init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id socfpga_dwmac_match[] = {
-+ { .compatible = "altr,socfpga-stmmac" },
-+ { }
- };
-+MODULE_DEVICE_TABLE(of, socfpga_dwmac_match);
-+
-+static struct platform_driver socfpga_dwmac_driver = {
-+ .probe = socfpga_dwmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "socfpga-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = socfpga_dwmac_match,
-+ },
-+};
-+module_platform_driver(socfpga_dwmac_driver);
-+
-+MODULE_LICENSE("GPL v2");
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
-@@ -17,9 +17,11 @@
- #include <linux/stmmac.h>
- #include <linux/phy.h>
- #include <linux/mfd/syscon.h>
-+#include <linux/module.h>
- #include <linux/regmap.h>
- #include <linux/clk.h>
- #include <linux/of.h>
-+#include <linux/of_device.h>
- #include <linux/of_net.h>
-
- #include "stmmac_platform.h"
-@@ -127,6 +129,11 @@ struct sti_dwmac {
- struct device *dev;
- struct regmap *regmap;
- u32 speed;
-+ void (*fix_retime_src)(void *priv, unsigned int speed);
-+};
-+
-+struct sti_dwmac_of_data {
-+ void (*fix_retime_src)(void *priv, unsigned int speed);
- };
-
- static u32 phy_intf_sels[] = {
-@@ -221,8 +228,9 @@ static void stid127_fix_retime_src(void
- regmap_update_bits(dwmac->regmap, reg, STID127_RETIME_SRC_MASK, val);
- }
-
--static void sti_dwmac_ctrl_init(struct sti_dwmac *dwmac)
-+static int sti_dwmac_init(struct platform_device *pdev, void *priv)
- {
-+ struct sti_dwmac *dwmac = priv;
- struct regmap *regmap = dwmac->regmap;
- int iface = dwmac->interface;
- struct device *dev = dwmac->dev;
-@@ -240,28 +248,8 @@ static void sti_dwmac_ctrl_init(struct s
-
- val = (iface == PHY_INTERFACE_MODE_REVMII) ? 0 : ENMII;
- regmap_update_bits(regmap, reg, ENMII_MASK, val);
--}
--
--static int stix4xx_init(struct platform_device *pdev, void *priv)
--{
-- struct sti_dwmac *dwmac = priv;
-- u32 spd = dwmac->speed;
-
-- sti_dwmac_ctrl_init(dwmac);
--
-- stih4xx_fix_retime_src(priv, spd);
--
-- return 0;
--}
--
--static int stid127_init(struct platform_device *pdev, void *priv)
--{
-- struct sti_dwmac *dwmac = priv;
-- u32 spd = dwmac->speed;
--
-- sti_dwmac_ctrl_init(dwmac);
--
-- stid127_fix_retime_src(priv, spd);
-+ dwmac->fix_retime_src(priv, dwmac->speed);
-
- return 0;
- }
-@@ -333,34 +321,80 @@ static int sti_dwmac_parse_data(struct s
- return 0;
- }
-
--static void *sti_dwmac_setup(struct platform_device *pdev)
-+static int sti_dwmac_probe(struct platform_device *pdev)
- {
-+ struct plat_stmmacenet_data *plat_dat;
-+ const struct sti_dwmac_of_data *data;
-+ struct stmmac_resources stmmac_res;
- struct sti_dwmac *dwmac;
- int ret;
-
-+ data = of_device_get_match_data(&pdev->dev);
-+ if (!data) {
-+ dev_err(&pdev->dev, "No OF match data provided\n");
-+ return -EINVAL;
-+ }
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
- dwmac = devm_kzalloc(&pdev->dev, sizeof(*dwmac), GFP_KERNEL);
- if (!dwmac)
-- return ERR_PTR(-ENOMEM);
-+ return -ENOMEM;
-
- ret = sti_dwmac_parse_data(dwmac, pdev);
- if (ret) {
- dev_err(&pdev->dev, "Unable to parse OF data\n");
-- return ERR_PTR(ret);
-+ return ret;
- }
-
-- return dwmac;
-+ dwmac->fix_retime_src = data->fix_retime_src;
-+
-+ plat_dat->bsp_priv = dwmac;
-+ plat_dat->init = sti_dwmac_init;
-+ plat_dat->exit = sti_dwmac_exit;
-+ plat_dat->fix_mac_speed = data->fix_retime_src;
-+
-+ ret = sti_dwmac_init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- }
-
--const struct stmmac_of_data stih4xx_dwmac_data = {
-- .fix_mac_speed = stih4xx_fix_retime_src,
-- .setup = sti_dwmac_setup,
-- .init = stix4xx_init,
-- .exit = sti_dwmac_exit,
-+static const struct sti_dwmac_of_data stih4xx_dwmac_data = {
-+ .fix_retime_src = stih4xx_fix_retime_src,
-+};
-+
-+static const struct sti_dwmac_of_data stid127_dwmac_data = {
-+ .fix_retime_src = stid127_fix_retime_src,
- };
-
--const struct stmmac_of_data stid127_dwmac_data = {
-- .fix_mac_speed = stid127_fix_retime_src,
-- .setup = sti_dwmac_setup,
-- .init = stid127_init,
-- .exit = sti_dwmac_exit,
-+static const struct of_device_id sti_dwmac_match[] = {
-+ { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
-+ { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
-+ { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
-+ { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
-+ { }
- };
-+MODULE_DEVICE_TABLE(of, sti_dwmac_match);
-+
-+static struct platform_driver sti_dwmac_driver = {
-+ .probe = sti_dwmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "sti-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = sti_dwmac_match,
-+ },
-+};
-+module_platform_driver(sti_dwmac_driver);
-+
-+MODULE_AUTHOR("Srinivas Kandagatla <srinivas.kandagatla@st.com>");
-+MODULE_DESCRIPTION("STMicroelectronics DWMAC Specific Glue layer");
-+MODULE_LICENSE("GPL");
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sunxi.c
-@@ -18,7 +18,9 @@
-
- #include <linux/stmmac.h>
- #include <linux/clk.h>
-+#include <linux/module.h>
- #include <linux/phy.h>
-+#include <linux/platform_device.h>
- #include <linux/of_net.h>
- #include <linux/regulator/consumer.h>
-
-@@ -31,35 +33,6 @@ struct sunxi_priv_data {
- struct regulator *regulator;
- };
-
--static void *sun7i_gmac_setup(struct platform_device *pdev)
--{
-- struct sunxi_priv_data *gmac;
-- struct device *dev = &pdev->dev;
--
-- gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-- if (!gmac)
-- return ERR_PTR(-ENOMEM);
--
-- gmac->interface = of_get_phy_mode(dev->of_node);
--
-- gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
-- if (IS_ERR(gmac->tx_clk)) {
-- dev_err(dev, "could not get tx clock\n");
-- return gmac->tx_clk;
-- }
--
-- /* Optional regulator for PHY */
-- gmac->regulator = devm_regulator_get_optional(dev, "phy");
-- if (IS_ERR(gmac->regulator)) {
-- if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
-- return ERR_PTR(-EPROBE_DEFER);
-- dev_info(dev, "no regulator found\n");
-- gmac->regulator = NULL;
-- }
--
-- return gmac;
--}
--
- #define SUN7I_GMAC_GMII_RGMII_RATE 125000000
- #define SUN7I_GMAC_MII_RATE 25000000
-
-@@ -130,13 +103,76 @@ static void sun7i_fix_speed(void *priv,
- }
- }
-
--/* of_data specifying hardware features and callbacks.
-- * hardware features were copied from Allwinner drivers. */
--const struct stmmac_of_data sun7i_gmac_data = {
-- .has_gmac = 1,
-- .tx_coe = 1,
-- .fix_mac_speed = sun7i_fix_speed,
-- .setup = sun7i_gmac_setup,
-- .init = sun7i_gmac_init,
-- .exit = sun7i_gmac_exit,
-+static int sun7i_gmac_probe(struct platform_device *pdev)
-+{
-+ struct plat_stmmacenet_data *plat_dat;
-+ struct stmmac_resources stmmac_res;
-+ struct sunxi_priv_data *gmac;
-+ struct device *dev = &pdev->dev;
-+ int ret;
-+
-+ ret = stmmac_get_platform_resources(pdev, &stmmac_res);
-+ if (ret)
-+ return ret;
-+
-+ plat_dat = stmmac_probe_config_dt(pdev, &stmmac_res.mac);
-+ if (IS_ERR(plat_dat))
-+ return PTR_ERR(plat_dat);
-+
-+ gmac = devm_kzalloc(dev, sizeof(*gmac), GFP_KERNEL);
-+ if (!gmac)
-+ return -ENOMEM;
-+
-+ gmac->interface = of_get_phy_mode(dev->of_node);
-+
-+ gmac->tx_clk = devm_clk_get(dev, "allwinner_gmac_tx");
-+ if (IS_ERR(gmac->tx_clk)) {
-+ dev_err(dev, "could not get tx clock\n");
-+ return PTR_ERR(gmac->tx_clk);
-+ }
-+
-+ /* Optional regulator for PHY */
-+ gmac->regulator = devm_regulator_get_optional(dev, "phy");
-+ if (IS_ERR(gmac->regulator)) {
-+ if (PTR_ERR(gmac->regulator) == -EPROBE_DEFER)
-+ return -EPROBE_DEFER;
-+ dev_info(dev, "no regulator found\n");
-+ gmac->regulator = NULL;
-+ }
-+
-+ /* platform data specifying hardware features and callbacks.
-+ * hardware features were copied from Allwinner drivers. */
-+ plat_dat->tx_coe = 1;
-+ plat_dat->has_gmac = true;
-+ plat_dat->bsp_priv = gmac;
-+ plat_dat->init = sun7i_gmac_init;
-+ plat_dat->exit = sun7i_gmac_exit;
-+ plat_dat->fix_mac_speed = sun7i_fix_speed;
-+
-+ ret = sun7i_gmac_init(pdev, plat_dat->bsp_priv);
-+ if (ret)
-+ return ret;
-+
-+ return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
-+}
-+
-+static const struct of_device_id sun7i_dwmac_match[] = {
-+ { .compatible = "allwinner,sun7i-a20-gmac" },
-+ { }
- };
-+MODULE_DEVICE_TABLE(of, sun7i_dwmac_match);
-+
-+static struct platform_driver sun7i_dwmac_driver = {
-+ .probe = sun7i_gmac_probe,
-+ .remove = stmmac_pltfr_remove,
-+ .driver = {
-+ .name = "sun7i-dwmac",
-+ .pm = &stmmac_pltfr_pm_ops,
-+ .of_match_table = sun7i_dwmac_match,
-+ },
-+};
-+module_platform_driver(sun7i_dwmac_driver);
-+
-+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
-+MODULE_DESCRIPTION("Allwinner sunxi DWMAC specific glue layer");
-+MODULE_LICENSE("GPL");
---- a/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/mmc_core.c
-@@ -73,7 +73,7 @@
- #define MMC_RX_OCTETCOUNT_G 0x00000188
- #define MMC_RX_BROADCASTFRAME_G 0x0000018c
- #define MMC_RX_MULTICASTFRAME_G 0x00000190
--#define MMC_RX_CRC_ERRROR 0x00000194
-+#define MMC_RX_CRC_ERROR 0x00000194
- #define MMC_RX_ALIGN_ERROR 0x00000198
- #define MMC_RX_RUN_ERROR 0x0000019C
- #define MMC_RX_JABBER_ERROR 0x000001A0
-@@ -196,7 +196,7 @@ void dwmac_mmc_read(void __iomem *ioaddr
- mmc->mmc_rx_octetcount_g += readl(ioaddr + MMC_RX_OCTETCOUNT_G);
- mmc->mmc_rx_broadcastframe_g += readl(ioaddr + MMC_RX_BROADCASTFRAME_G);
- mmc->mmc_rx_multicastframe_g += readl(ioaddr + MMC_RX_MULTICASTFRAME_G);
-- mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERRROR);
-+ mmc->mmc_rx_crc_error += readl(ioaddr + MMC_RX_CRC_ERROR);
- mmc->mmc_rx_align_error += readl(ioaddr + MMC_RX_ALIGN_ERROR);
- mmc->mmc_rx_run_error += readl(ioaddr + MMC_RX_RUN_ERROR);
- mmc->mmc_rx_jabber_error += readl(ioaddr + MMC_RX_JABBER_ERROR);
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h
-@@ -34,6 +34,14 @@
- #include <linux/ptp_clock_kernel.h>
- #include <linux/reset.h>
-
-+struct stmmac_resources {
-+ void __iomem *addr;
-+ const char *mac;
-+ int wol_irq;
-+ int lpi_irq;
-+ int irq;
-+};
-+
- struct stmmac_tx_info {
- dma_addr_t buf;
- bool map_as_page;
-@@ -135,9 +143,9 @@ void stmmac_ptp_unregister(struct stmmac
- int stmmac_resume(struct net_device *ndev);
- int stmmac_suspend(struct net_device *ndev);
- int stmmac_dvr_remove(struct net_device *ndev);
--struct stmmac_priv *stmmac_dvr_probe(struct device *device,
-- struct plat_stmmacenet_data *plat_dat,
-- void __iomem *addr);
-+int stmmac_dvr_probe(struct device *device,
-+ struct plat_stmmacenet_data *plat_dat,
-+ struct stmmac_resources *res);
- void stmmac_disable_eee_mode(struct stmmac_priv *priv);
- bool stmmac_eee_init(struct stmmac_priv *priv);
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -52,6 +52,7 @@
- #include "stmmac_ptp.h"
- #include "stmmac.h"
- #include <linux/reset.h>
-+#include <linux/of_mdio.h>
-
- #define STMMAC_ALIGN(x) L1_CACHE_ALIGN(x)
-
-@@ -816,18 +817,25 @@ static int stmmac_init_phy(struct net_de
- priv->speed = 0;
- priv->oldduplex = -1;
-
-- if (priv->plat->phy_bus_name)
-- snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
-- priv->plat->phy_bus_name, priv->plat->bus_id);
-- else
-- snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
-- priv->plat->bus_id);
-+ if (priv->plat->phy_node) {
-+ phydev = of_phy_connect(dev, priv->plat->phy_node,
-+ &stmmac_adjust_link, 0, interface);
-+ } else {
-+ if (priv->plat->phy_bus_name)
-+ snprintf(bus_id, MII_BUS_ID_SIZE, "%s-%x",
-+ priv->plat->phy_bus_name, priv->plat->bus_id);
-+ else
-+ snprintf(bus_id, MII_BUS_ID_SIZE, "stmmac-%x",
-+ priv->plat->bus_id);
-
-- snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
-- priv->plat->phy_addr);
-- pr_debug("stmmac_init_phy: trying to attach to %s\n", phy_id_fmt);
-+ snprintf(phy_id_fmt, MII_BUS_ID_SIZE + 3, PHY_ID_FMT, bus_id,
-+ priv->plat->phy_addr);
-+ pr_debug("stmmac_init_phy: trying to attach to %s\n",
-+ phy_id_fmt);
-
-- phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link, interface);
-+ phydev = phy_connect(dev, phy_id_fmt, &stmmac_adjust_link,
-+ interface);
-+ }
-
- if (IS_ERR_OR_NULL(phydev)) {
- pr_err("%s: Could not attach to PHY\n", dev->name);
-@@ -851,7 +859,7 @@ static int stmmac_init_phy(struct net_de
- * device as well.
- * Note: phydev->phy_id is the result of reading the UID PHY registers.
- */
-- if (phydev->phy_id == 0) {
-+ if (!priv->plat->phy_node && phydev->phy_id == 0) {
- phy_disconnect(phydev);
- return -ENODEV;
- }
-@@ -978,13 +986,11 @@ static int stmmac_init_rx_buffers(struct
- {
- struct sk_buff *skb;
-
-- skb = __netdev_alloc_skb(priv->dev, priv->dma_buf_sz + NET_IP_ALIGN,
-- flags);
-+ skb = __netdev_alloc_skb_ip_align(priv->dev, priv->dma_buf_sz, flags);
- if (!skb) {
- pr_err("%s: Rx init fails; skb is NULL\n", __func__);
- return -ENOMEM;
- }
-- skb_reserve(skb, NET_IP_ALIGN);
- priv->rx_skbuff[i] = skb;
- priv->rx_skbuff_dma[i] = dma_map_single(priv->device, skb->data,
- priv->dma_buf_sz,
-@@ -2803,16 +2809,15 @@ static int stmmac_hw_init(struct stmmac_
- * stmmac_dvr_probe
- * @device: device pointer
- * @plat_dat: platform data pointer
-- * @addr: iobase memory address
-+ * @res: stmmac resource pointer
- * Description: this is the main probe function used to
- * call the alloc_etherdev, allocate the priv structure.
- * Return:
-- * on success the new private structure is returned, otherwise the error
-- * pointer.
-+ * returns 0 on success, otherwise errno.
- */
--struct stmmac_priv *stmmac_dvr_probe(struct device *device,
-- struct plat_stmmacenet_data *plat_dat,
-- void __iomem *addr)
-+int stmmac_dvr_probe(struct device *device,
-+ struct plat_stmmacenet_data *plat_dat,
-+ struct stmmac_resources *res)
- {
- int ret = 0;
- struct net_device *ndev = NULL;
-@@ -2820,7 +2825,7 @@ struct stmmac_priv *stmmac_dvr_probe(str
-
- ndev = alloc_etherdev(sizeof(struct stmmac_priv));
- if (!ndev)
-- return ERR_PTR(-ENOMEM);
-+ return -ENOMEM;
-
- SET_NETDEV_DEV(ndev, device);
-
-@@ -2831,8 +2836,17 @@ struct stmmac_priv *stmmac_dvr_probe(str
- stmmac_set_ethtool_ops(ndev);
- priv->pause = pause;
- priv->plat = plat_dat;
-- priv->ioaddr = addr;
-- priv->dev->base_addr = (unsigned long)addr;
-+ priv->ioaddr = res->addr;
-+ priv->dev->base_addr = (unsigned long)res->addr;
-+
-+ priv->dev->irq = res->irq;
-+ priv->wol_irq = res->wol_irq;
-+ priv->lpi_irq = res->lpi_irq;
-+
-+ if (res->mac)
-+ memcpy(priv->dev->dev_addr, res->mac, ETH_ALEN);
-+
-+ dev_set_drvdata(device, priv->dev);
-
- /* Verify driver arguments */
- stmmac_verify_args();
-@@ -2947,7 +2961,7 @@ struct stmmac_priv *stmmac_dvr_probe(str
- }
- }
-
-- return priv;
-+ return 0;
-
- error_mdio_register:
- unregister_netdev(ndev);
-@@ -2960,7 +2974,7 @@ error_pclk_get:
- error_clk_get:
- free_netdev(ndev);
-
-- return ERR_PTR(ret);
-+ return ret;
- }
- EXPORT_SYMBOL_GPL(stmmac_dvr_probe);
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_mdio.c
-@@ -161,11 +161,16 @@ int stmmac_mdio_reset(struct mii_bus *bu
-
- if (!gpio_request(reset_gpio, "mdio-reset")) {
- gpio_direction_output(reset_gpio, active_low ? 1 : 0);
-- udelay(data->delays[0]);
-+ if (data->delays[0])
-+ msleep(DIV_ROUND_UP(data->delays[0], 1000));
-+
- gpio_set_value(reset_gpio, active_low ? 0 : 1);
-- udelay(data->delays[1]);
-+ if (data->delays[1])
-+ msleep(DIV_ROUND_UP(data->delays[1], 1000));
-+
- gpio_set_value(reset_gpio, active_low ? 1 : 0);
-- udelay(data->delays[2]);
-+ if (data->delays[2])
-+ msleep(DIV_ROUND_UP(data->delays[2], 1000));
- }
- }
- #endif
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
-@@ -163,7 +163,7 @@ static int stmmac_pci_probe(struct pci_d
- {
- struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
- struct plat_stmmacenet_data *plat;
-- struct stmmac_priv *priv;
-+ struct stmmac_resources res;
- int i;
- int ret;
-
-@@ -214,19 +214,12 @@ static int stmmac_pci_probe(struct pci_d
-
- pci_enable_msi(pdev);
-
-- priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]);
-- if (IS_ERR(priv)) {
-- dev_err(&pdev->dev, "%s: main driver probe failed\n", __func__);
-- return PTR_ERR(priv);
-- }
-- priv->dev->irq = pdev->irq;
-- priv->wol_irq = pdev->irq;
--
-- pci_set_drvdata(pdev, priv->dev);
--
-- dev_dbg(&pdev->dev, "STMMAC PCI driver registration completed\n");
-+ memset(&res, 0, sizeof(res));
-+ res.addr = pcim_iomap_table(pdev)[i];
-+ res.wol_irq = pdev->irq;
-+ res.irq = pdev->irq;
-
-- return 0;
-+ return stmmac_dvr_probe(&pdev->dev, plat, &res);
- }
-
- /**
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -28,29 +28,11 @@
- #include <linux/of.h>
- #include <linux/of_net.h>
- #include <linux/of_device.h>
-+#include <linux/of_mdio.h>
-
- #include "stmmac.h"
- #include "stmmac_platform.h"
-
--static const struct of_device_id stmmac_dt_ids[] = {
-- /* SoC specific glue layers should come before generic bindings */
-- { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
-- { .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
-- { .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
-- { .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
-- { .compatible = "st,stih416-dwmac", .data = &stih4xx_dwmac_data},
-- { .compatible = "st,stid127-dwmac", .data = &stid127_dwmac_data},
-- { .compatible = "st,stih407-dwmac", .data = &stih4xx_dwmac_data},
-- { .compatible = "altr,socfpga-stmmac", .data = &socfpga_gmac_data },
-- { .compatible = "st,spear600-gmac"},
-- { .compatible = "snps,dwmac-3.610"},
-- { .compatible = "snps,dwmac-3.70a"},
-- { .compatible = "snps,dwmac-3.710"},
-- { .compatible = "snps,dwmac"},
-- { /* sentinel */ }
--};
--MODULE_DEVICE_TABLE(of, stmmac_dt_ids);
--
- #ifdef CONFIG_OF
-
- /**
-@@ -122,37 +104,16 @@ static int dwmac1000_validate_ucast_entr
- * this function is to read the driver parameters from device-tree and
- * set some private fields that will be used by the main at runtime.
- */
--static int stmmac_probe_config_dt(struct platform_device *pdev,
-- struct plat_stmmacenet_data *plat,
-- const char **mac)
-+struct plat_stmmacenet_data *
-+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
- {
- struct device_node *np = pdev->dev.of_node;
-+ struct plat_stmmacenet_data *plat;
- struct stmmac_dma_cfg *dma_cfg;
-- const struct of_device_id *device;
--
-- if (!np)
-- return -ENODEV;
-
-- device = of_match_device(stmmac_dt_ids, &pdev->dev);
-- if (!device)
-- return -ENODEV;
--
-- if (device->data) {
-- const struct stmmac_of_data *data = device->data;
-- plat->has_gmac = data->has_gmac;
-- plat->enh_desc = data->enh_desc;
-- plat->tx_coe = data->tx_coe;
-- plat->rx_coe = data->rx_coe;
-- plat->bugged_jumbo = data->bugged_jumbo;
-- plat->pmt = data->pmt;
-- plat->riwt_off = data->riwt_off;
-- plat->fix_mac_speed = data->fix_mac_speed;
-- plat->bus_setup = data->bus_setup;
-- plat->setup = data->setup;
-- plat->free = data->free;
-- plat->init = data->init;
-- plat->exit = data->exit;
-- }
-+ plat = devm_kzalloc(&pdev->dev, sizeof(*plat), GFP_KERNEL);
-+ if (!plat)
-+ return ERR_PTR(-ENOMEM);
-
- *mac = of_get_mac_address(np);
- plat->interface = of_get_phy_mode(np);
-@@ -168,13 +129,24 @@ static int stmmac_probe_config_dt(struct
- /* Default to phy auto-detection */
- plat->phy_addr = -1;
-
-+ /* If we find a phy-handle property, use it as the PHY */
-+ plat->phy_node = of_parse_phandle(np, "phy-handle", 0);
-+
-+ /* If phy-handle is not specified, check if we have a fixed-phy */
-+ if (!plat->phy_node && of_phy_is_fixed_link(np)) {
-+ if ((of_phy_register_fixed_link(np) < 0))
-+ return ERR_PTR(-ENODEV);
-+
-+ plat->phy_node = of_node_get(np);
-+ }
-+
- /* "snps,phy-addr" is not a standard property. Mark it as deprecated
- * and warn of its use. Remove this when phy node support is added.
- */
- if (of_property_read_u32(np, "snps,phy-addr", &plat->phy_addr) == 0)
- dev_warn(&pdev->dev, "snps,phy-addr property is deprecated\n");
-
-- if (plat->phy_bus_name)
-+ if (plat->phy_node || plat->phy_bus_name)
- plat->mdio_bus_data = NULL;
- else
- plat->mdio_bus_data =
-@@ -194,6 +166,12 @@ static int stmmac_probe_config_dt(struct
- */
- plat->maxmtu = JUMBO_LEN;
-
-+ /* Set default value for multicast hash bins */
-+ plat->multicast_filter_bins = HASH_TABLE_SIZE;
-+
-+ /* Set default value for unicast filter entries */
-+ plat->unicast_filter_entries = 1;
-+
- /*
- * Currently only the properties needed on SPEAr600
- * are provided. All other properties should be added
-@@ -232,8 +210,10 @@ static int stmmac_probe_config_dt(struct
- if (of_find_property(np, "snps,pbl", NULL)) {
- dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
- GFP_KERNEL);
-- if (!dma_cfg)
-- return -ENOMEM;
-+ if (!dma_cfg) {
-+ of_node_put(np);
-+ return ERR_PTR(-ENOMEM);
-+ }
- plat->dma_cfg = dma_cfg;
- of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
- dma_cfg->fixed_burst =
-@@ -250,45 +230,34 @@ static int stmmac_probe_config_dt(struct
- pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
- }
-
-- return 0;
-+ return plat;
- }
- #else
--static int stmmac_probe_config_dt(struct platform_device *pdev,
-- struct plat_stmmacenet_data *plat,
-- const char **mac)
-+struct plat_stmmacenet_data *
-+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
- {
-- return -ENOSYS;
-+ return ERR_PTR(-ENOSYS);
- }
- #endif /* CONFIG_OF */
-+EXPORT_SYMBOL_GPL(stmmac_probe_config_dt);
-
--/**
-- * stmmac_pltfr_probe - platform driver probe.
-- * @pdev: platform device pointer
-- * Description: platform_device probe function. It is to allocate
-- * the necessary platform resources, invoke custom helper (if required) and
-- * invoke the main probe function.
-- */
--static int stmmac_pltfr_probe(struct platform_device *pdev)
-+int stmmac_get_platform_resources(struct platform_device *pdev,
-+ struct stmmac_resources *stmmac_res)
- {
-- int ret = 0;
- struct resource *res;
-- struct device *dev = &pdev->dev;
-- void __iomem *addr = NULL;
-- struct stmmac_priv *priv = NULL;
-- struct plat_stmmacenet_data *plat_dat = NULL;
-- const char *mac = NULL;
-- int irq, wol_irq, lpi_irq;
-+
-+ memset(stmmac_res, 0, sizeof(*stmmac_res));
-
- /* Get IRQ information early to have an ability to ask for deferred
- * probe if needed before we went too far with resource allocation.
- */
-- irq = platform_get_irq_byname(pdev, "macirq");
-- if (irq < 0) {
-- if (irq != -EPROBE_DEFER) {
-- dev_err(dev,
-+ stmmac_res->irq = platform_get_irq_byname(pdev, "macirq");
-+ if (stmmac_res->irq < 0) {
-+ if (stmmac_res->irq != -EPROBE_DEFER) {
-+ dev_err(&pdev->dev,
- "MAC IRQ configuration information not found\n");
- }
-- return irq;
-+ return stmmac_res->irq;
- }
-
- /* On some platforms e.g. SPEAr the wake up irq differs from the mac irq
-@@ -298,82 +267,23 @@ static int stmmac_pltfr_probe(struct pla
- * In case the wake up interrupt is not passed from the platform
- * so the driver will continue to use the mac irq (ndev->irq)
- */
-- wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
-- if (wol_irq < 0) {
-- if (wol_irq == -EPROBE_DEFER)
-+ stmmac_res->wol_irq = platform_get_irq_byname(pdev, "eth_wake_irq");
-+ if (stmmac_res->wol_irq < 0) {
-+ if (stmmac_res->wol_irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-- wol_irq = irq;
-+ stmmac_res->wol_irq = stmmac_res->irq;
- }
-
-- lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-- if (lpi_irq == -EPROBE_DEFER)
-+ stmmac_res->lpi_irq = platform_get_irq_byname(pdev, "eth_lpi");
-+ if (stmmac_res->lpi_irq == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-- addr = devm_ioremap_resource(dev, res);
-- if (IS_ERR(addr))
-- return PTR_ERR(addr);
--
-- plat_dat = dev_get_platdata(&pdev->dev);
--
-- if (!plat_dat)
-- plat_dat = devm_kzalloc(&pdev->dev,
-- sizeof(struct plat_stmmacenet_data),
-- GFP_KERNEL);
-- if (!plat_dat) {
-- pr_err("%s: ERROR: no memory", __func__);
-- return -ENOMEM;
-- }
--
-- /* Set default value for multicast hash bins */
-- plat_dat->multicast_filter_bins = HASH_TABLE_SIZE;
-+ stmmac_res->addr = devm_ioremap_resource(&pdev->dev, res);
-
-- /* Set default value for unicast filter entries */
-- plat_dat->unicast_filter_entries = 1;
--
-- if (pdev->dev.of_node) {
-- ret = stmmac_probe_config_dt(pdev, plat_dat, &mac);
-- if (ret) {
-- pr_err("%s: main dt probe failed", __func__);
-- return ret;
-- }
-- }
--
-- /* Custom setup (if needed) */
-- if (plat_dat->setup) {
-- plat_dat->bsp_priv = plat_dat->setup(pdev);
-- if (IS_ERR(plat_dat->bsp_priv))
-- return PTR_ERR(plat_dat->bsp_priv);
-- }
--
-- /* Custom initialisation (if needed)*/
-- if (plat_dat->init) {
-- ret = plat_dat->init(pdev, plat_dat->bsp_priv);
-- if (unlikely(ret))
-- return ret;
-- }
--
-- priv = stmmac_dvr_probe(&(pdev->dev), plat_dat, addr);
-- if (IS_ERR(priv)) {
-- pr_err("%s: main driver probe failed", __func__);
-- return PTR_ERR(priv);
-- }
--
-- /* Copy IRQ values to priv structure which is now avaialble */
-- priv->dev->irq = irq;
-- priv->wol_irq = wol_irq;
-- priv->lpi_irq = lpi_irq;
--
-- /* Get MAC address if available (DT) */
-- if (mac)
-- memcpy(priv->dev->dev_addr, mac, ETH_ALEN);
--
-- platform_set_drvdata(pdev, priv->dev);
--
-- pr_debug("STMMAC platform driver registration completed");
--
-- return 0;
-+ return PTR_ERR_OR_ZERO(stmmac_res->addr);
- }
-+EXPORT_SYMBOL_GPL(stmmac_get_platform_resources);
-
- /**
- * stmmac_pltfr_remove
-@@ -381,7 +291,7 @@ static int stmmac_pltfr_probe(struct pla
- * Description: this function calls the main to free the net resources
- * and calls the platforms hook and release the resources (e.g. mem).
- */
--static int stmmac_pltfr_remove(struct platform_device *pdev)
-+int stmmac_pltfr_remove(struct platform_device *pdev)
- {
- struct net_device *ndev = platform_get_drvdata(pdev);
- struct stmmac_priv *priv = netdev_priv(ndev);
-@@ -390,11 +300,9 @@ static int stmmac_pltfr_remove(struct pl
- if (priv->plat->exit)
- priv->plat->exit(pdev, priv->plat->bsp_priv);
-
-- if (priv->plat->free)
-- priv->plat->free(pdev, priv->plat->bsp_priv);
--
- return ret;
- }
-+EXPORT_SYMBOL_GPL(stmmac_pltfr_remove);
-
- #ifdef CONFIG_PM_SLEEP
- /**
-@@ -438,21 +346,10 @@ static int stmmac_pltfr_resume(struct de
- }
- #endif /* CONFIG_PM_SLEEP */
-
--static SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops,
-- stmmac_pltfr_suspend, stmmac_pltfr_resume);
--
--static struct platform_driver stmmac_pltfr_driver = {
-- .probe = stmmac_pltfr_probe,
-- .remove = stmmac_pltfr_remove,
-- .driver = {
-- .name = STMMAC_RESOURCE_NAME,
-- .pm = &stmmac_pltfr_pm_ops,
-- .of_match_table = of_match_ptr(stmmac_dt_ids),
-- },
--};
--
--module_platform_driver(stmmac_pltfr_driver);
-+SIMPLE_DEV_PM_OPS(stmmac_pltfr_pm_ops, stmmac_pltfr_suspend,
-+ stmmac_pltfr_resume);
-+EXPORT_SYMBOL_GPL(stmmac_pltfr_pm_ops);
-
--MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet PLATFORM driver");
-+MODULE_DESCRIPTION("STMMAC 10/100/1000 Ethernet platform support");
- MODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>");
- MODULE_LICENSE("GPL");
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
-@@ -19,11 +19,15 @@
- #ifndef __STMMAC_PLATFORM_H__
- #define __STMMAC_PLATFORM_H__
-
--extern const struct stmmac_of_data meson6_dwmac_data;
--extern const struct stmmac_of_data sun7i_gmac_data;
--extern const struct stmmac_of_data stih4xx_dwmac_data;
--extern const struct stmmac_of_data stid127_dwmac_data;
--extern const struct stmmac_of_data socfpga_gmac_data;
--extern const struct stmmac_of_data rk3288_gmac_data;
-+#include "stmmac.h"
-+
-+struct plat_stmmacenet_data *
-+stmmac_probe_config_dt(struct platform_device *pdev, const char **mac);
-+
-+int stmmac_get_platform_resources(struct platform_device *pdev,
-+ struct stmmac_resources *stmmac_res);
-+
-+int stmmac_pltfr_remove(struct platform_device *pdev);
-+extern const struct dev_pm_ops stmmac_pltfr_pm_ops;
-
- #endif /* __STMMAC_PLATFORM_H__ */
---- a/include/linux/stmmac.h
-+++ b/include/linux/stmmac.h
-@@ -99,6 +99,7 @@ struct plat_stmmacenet_data {
- int phy_addr;
- int interface;
- struct stmmac_mdio_bus_data *mdio_bus_data;
-+ struct device_node *phy_node;
- struct stmmac_dma_cfg *dma_cfg;
- int clk_csr;
- int has_gmac;
-@@ -118,30 +119,8 @@ struct plat_stmmacenet_data {
- int rx_fifo_size;
- void (*fix_mac_speed)(void *priv, unsigned int speed);
- void (*bus_setup)(void __iomem *ioaddr);
-- void *(*setup)(struct platform_device *pdev);
-- void (*free)(struct platform_device *pdev, void *priv);
- int (*init)(struct platform_device *pdev, void *priv);
- void (*exit)(struct platform_device *pdev, void *priv);
-- void *custom_cfg;
-- void *custom_data;
- void *bsp_priv;
- };
--
--/* of_data for SoC glue layer device tree bindings */
--
--struct stmmac_of_data {
-- int has_gmac;
-- int enh_desc;
-- int tx_coe;
-- int rx_coe;
-- int bugged_jumbo;
-- int pmt;
-- int riwt_off;
-- void (*fix_mac_speed)(void *priv, unsigned int speed);
-- void (*bus_setup)(void __iomem *ioaddr);
-- void *(*setup)(struct platform_device *pdev);
-- void (*free)(struct platform_device *pdev, void *priv);
-- int (*init)(struct platform_device *pdev, void *priv);
-- void (*exit)(struct platform_device *pdev, void *priv);
--};
- #endif
diff --git a/target/linux/ipq806x/patches-4.1/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch b/target/linux/ipq806x/patches-4.1/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch
deleted file mode 100644
index 5126e9061e..0000000000
--- a/target/linux/ipq806x/patches-4.1/707-ARM-dts-qcom-add-mdio-nodes-to-ap148-db149.patch
+++ /dev/null
@@ -1,146 +0,0 @@
-From e81de9d28bd0421c236df322872e64edf4ee1852 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Mon, 11 May 2015 16:32:09 -0700
-Subject: [PATCH 7/8] ARM: dts: qcom: add mdio nodes to ap148 & db149
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 40 ++++++++++++++++++++++++++-
- arch/arm/boot/dts/qcom-ipq8064-db149.dts | 46 ++++++++++++++++++++++++++++++++
- 2 files changed, 85 insertions(+), 1 deletion(-)
-
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -19,8 +19,9 @@
- };
- };
-
-- alias {
-+ aliases {
- serial0 = &uart4;
-+ mdio-gpio0 = &mdio0;
- };
-
- chosen {
-@@ -65,6 +66,15 @@
- bias-bus-hold;
- };
- };
-+
-+ mdio0_pins: mdio0_pins {
-+ mux {
-+ pins = "gpio0", "gpio1";
-+ function = "gpio";
-+ drive-strength = <8>;
-+ bias-disable;
-+ };
-+ };
- };
-
- gsbi@16300000 {
-@@ -135,6 +145,34 @@
-
- linux,part-probe = "qcom-smem";
- };
-+
-+ mdio0: mdio {
-+ compatible = "virtual,mdio-gpio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
-+ pinctrl-0 = <&mdio0_pins>;
-+ pinctrl-names = "default";
-+
-+ 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>;
-+ };
-+ };
- };
- };
-
---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-@@ -16,6 +16,7 @@
-
- alias {
- serial0 = &uart2;
-+ mdio-gpio0 = &mdio0;
- };
-
- chosen {
-@@ -38,6 +39,15 @@
- bias-none;
- };
- };
-+
-+ mdio0_pins: mdio0_pins {
-+ mux {
-+ pins = "gpio0", "gpio1";
-+ function = "gpio";
-+ drive-strength = <8>;
-+ bias-disable;
-+ };
-+ };
- };
-
- gsbi2: gsbi@12480000 {
-@@ -140,5 +150,44 @@
- pcie2: pci@1b900000 {
- status = "ok";
- };
-+
-+ mdio0: mdio {
-+ compatible = "virtual,mdio-gpio";
-+ #address-cells = <1>;
-+ #size-cells = <0>;
-+ gpios = <&qcom_pinmux 1 0 &qcom_pinmux 0 0>;
-+
-+ pinctrl-0 = <&mdio0_pins>;
-+ pinctrl-names = "default";
-+
-+ 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>;
-+ };
-+
-+ phy6: ethernet-phy@6 {
-+ device_type = "ethernet-phy";
-+ reg = <6>;
-+ };
-+
-+ phy7: ethernet-phy@7 {
-+ device_type = "ethernet-phy";
-+ reg = <7>;
-+ };
-+ };
- };
- };
diff --git a/target/linux/ipq806x/patches-4.1/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch b/target/linux/ipq806x/patches-4.1/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch
deleted file mode 100644
index 37dfaabf05..0000000000
--- a/target/linux/ipq806x/patches-4.1/708-ARM-dts-qcom-add-gmac-nodes-to-ipq806x-platforms.patch
+++ /dev/null
@@ -1,216 +0,0 @@
-From cab1f4720e82f2e17eaeed9a9ad9e4f07c742977 Mon Sep 17 00:00:00 2001
-From: Mathieu Olivari <mathieu@codeaurora.org>
-Date: Mon, 11 May 2015 12:29:18 -0700
-Subject: [PATCH 8/8] ARM: dts: qcom: add gmac nodes to ipq806x platforms
-
-Signed-off-by: Mathieu Olivari <mathieu@codeaurora.org>
----
- arch/arm/boot/dts/qcom-ipq8064-ap148.dts | 31 ++++++++++++
- arch/arm/boot/dts/qcom-ipq8064-db149.dts | 43 ++++++++++++++++
- arch/arm/boot/dts/qcom-ipq8064.dtsi | 86 ++++++++++++++++++++++++++++++++
- 3 files changed, 160 insertions(+)
-
---- a/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-ap148.dts
-@@ -75,6 +75,16 @@
- 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 {
-@@ -173,6 +183,31 @@
- reg = <4>;
- };
- };
-+
-+ gmac1: ethernet@37200000 {
-+ status = "ok";
-+ phy-mode = "rgmii";
-+ qcom,id = <1>;
-+
-+ pinctrl-0 = <&rgmii2_pins>;
-+ pinctrl-names = "default";
-+
-+ fixed-link {
-+ speed = <1000>;
-+ full-duplex;
-+ };
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <2>;
-+
-+ fixed-link {
-+ speed = <1000>;
-+ full-duplex;
-+ };
-+ };
- };
- };
-
---- a/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-+++ b/arch/arm/boot/dts/qcom-ipq8064-db149.dts
-@@ -48,6 +48,14 @@
- bias-disable;
- };
- };
-+
-+ rgmii0_pins: rgmii0_pins {
-+ mux {
-+ pins = "gpio2", "gpio66";
-+ drive-strength = <8>;
-+ bias-disable;
-+ };
-+ };
- };
-
- gsbi2: gsbi@12480000 {
-@@ -189,5 +197,40 @@
- reg = <7>;
- };
- };
-+
-+ gmac0: ethernet@37000000 {
-+ status = "ok";
-+ phy-mode = "rgmii";
-+ qcom,id = <0>;
-+ phy-handle = <&phy4>;
-+
-+ pinctrl-0 = <&rgmii0_pins>;
-+ pinctrl-names = "default";
-+ };
-+
-+ gmac1: ethernet@37200000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <1>;
-+
-+ fixed-link {
-+ speed = <1000>;
-+ full-duplex;
-+ };
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <2>;
-+ phy-handle = <&phy6>;
-+ };
-+
-+ gmac3: ethernet@37600000 {
-+ status = "ok";
-+ phy-mode = "sgmii";
-+ qcom,id = <3>;
-+ phy-handle = <&phy7>;
-+ };
- };
- };
---- a/arch/arm/boot/dts/qcom-ipq8064.dtsi
-+++ b/arch/arm/boot/dts/qcom-ipq8064.dtsi
-@@ -679,6 +679,92 @@
-
- status = "disabled";
- };
-+
-+ nss_common: syscon@03000000 {
-+ compatible = "syscon";
-+ reg = <0x03000000 0x0000FFFF>;
-+ };
-+
-+ qsgmii_csr: syscon@1bb00000 {
-+ compatible = "syscon";
-+ reg = <0x1bb00000 0x000001FF>;
-+ };
-+
-+ gmac0: ethernet@37000000 {
-+ device_type = "network";
-+ compatible = "qcom,ipq806x-gmac";
-+ reg = <0x37000000 0x200000>;
-+ interrupts = <GIC_SPI 220 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "macirq";
-+
-+ qcom,nss-common = <&nss_common>;
-+ qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+ clocks = <&gcc GMAC_CORE1_CLK>;
-+ clock-names = "stmmaceth";
-+
-+ resets = <&gcc GMAC_CORE1_RESET>;
-+ reset-names = "stmmaceth";
-+
-+ status = "disabled";
-+ };
-+
-+ gmac1: ethernet@37200000 {
-+ device_type = "network";
-+ compatible = "qcom,ipq806x-gmac";
-+ reg = <0x37200000 0x200000>;
-+ interrupts = <GIC_SPI 223 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "macirq";
-+
-+ qcom,nss-common = <&nss_common>;
-+ qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+ clocks = <&gcc GMAC_CORE2_CLK>;
-+ clock-names = "stmmaceth";
-+
-+ resets = <&gcc GMAC_CORE2_RESET>;
-+ reset-names = "stmmaceth";
-+
-+ status = "disabled";
-+ };
-+
-+ gmac2: ethernet@37400000 {
-+ device_type = "network";
-+ compatible = "qcom,ipq806x-gmac";
-+ reg = <0x37400000 0x200000>;
-+ interrupts = <GIC_SPI 226 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "macirq";
-+
-+ qcom,nss-common = <&nss_common>;
-+ qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+ clocks = <&gcc GMAC_CORE3_CLK>;
-+ clock-names = "stmmaceth";
-+
-+ resets = <&gcc GMAC_CORE3_RESET>;
-+ reset-names = "stmmaceth";
-+
-+ status = "disabled";
-+ };
-+
-+ gmac3: ethernet@37600000 {
-+ device_type = "network";
-+ compatible = "qcom,ipq806x-gmac";
-+ reg = <0x37600000 0x200000>;
-+ interrupts = <GIC_SPI 229 IRQ_TYPE_LEVEL_HIGH>;
-+ interrupt-names = "macirq";
-+
-+ qcom,nss-common = <&nss_common>;
-+ qcom,qsgmii-csr = <&qsgmii_csr>;
-+
-+ clocks = <&gcc GMAC_CORE4_CLK>;
-+ clock-names = "stmmaceth";
-+
-+ resets = <&gcc GMAC_CORE4_RESET>;
-+ reset-names = "stmmaceth";
-+
-+ status = "disabled";
-+ };
- };
-
- sfpb_mutex: sfpb-mutex {
diff --git a/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch b/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch
deleted file mode 100644
index d385c9a36c..0000000000
--- a/target/linux/ipq806x/patches-4.1/709-stmac-platform-add-support-for-retreiving-mac-from-m.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From 5bf2dabde1fa3af0c9082b42b6847ef3fd198b13 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <jogo@openwrt.org>
-Date: Sun, 9 Aug 2015 12:53:55 +0200
-Subject: [PATCH] stmac: platform: add support for retreiving mac from mtd
-
----
- drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 10 ++++++++++
- 1 file changed, 10 insertions(+)
-
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
-@@ -116,6 +116,19 @@ stmmac_probe_config_dt(struct platform_d
- return ERR_PTR(-ENOMEM);
-
- *mac = of_get_mac_address(np);
-+ if (!*mac) {
-+ u8 mtd_mac[ETH_ALEN];
-+ int ret;
-+
-+ ret = of_get_mac_address_mtd(np, mtd_mac);
-+ if (ret == -EPROBE_DEFER)
-+ return ERR_PTR(ret);
-+
-+ if (is_valid_ether_addr(mtd_mac))
-+ *mac = devm_kmemdup(&pdev->dev, mtd_mac, ETH_ALEN,
-+ GFP_KERNEL);
-+ }
-+
- plat->interface = of_get_phy_mode(np);
-
- /* Get max speed of operation from device tree */
diff --git a/target/linux/ipq806x/patches-4.1/710-stmmac-fix-ipq806x-DMA-configuration.patch b/target/linux/ipq806x/patches-4.1/710-stmmac-fix-ipq806x-DMA-configuration.patch
deleted file mode 100644
index c99f60768f..0000000000
--- a/target/linux/ipq806x/patches-4.1/710-stmmac-fix-ipq806x-DMA-configuration.patch
+++ /dev/null
@@ -1,117 +0,0 @@
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-ipq806x.c
-@@ -259,6 +259,7 @@ static int ipq806x_gmac_probe(struct pla
- {
- struct plat_stmmacenet_data *plat_dat;
- struct stmmac_resources stmmac_res;
-+ struct stmmac_dma_cfg *dma_cfg;
- struct device *dev = &pdev->dev;
- struct ipq806x_gmac *gmac;
- int val;
-@@ -348,6 +349,17 @@ static int ipq806x_gmac_probe(struct pla
- plat_dat->bsp_priv = gmac;
- plat_dat->fix_mac_speed = ipq806x_gmac_fix_mac_speed;
-
-+ dma_cfg = devm_kzalloc(&pdev->dev, sizeof(*dma_cfg),
-+ GFP_KERNEL);
-+
-+ dma_cfg->pbl = 32;
-+ dma_cfg->aal = 1;
-+ dma_cfg->burst_len = DMA_AXI_BLEN_16 |
-+ (7 << DMA_AXI_RD_OSR_LMT_SHIFT) |
-+ (7 << DMA_AXI_WR_OSR_LMT_SHIFT);
-+
-+ plat_dat->dma_cfg = dma_cfg;
-+
- return stmmac_dvr_probe(&pdev->dev, plat_dat, &stmmac_res);
- }
-
---- a/include/linux/stmmac.h
-+++ b/include/linux/stmmac.h
-@@ -73,6 +73,9 @@
- | DMA_AXI_BLEN_32 | DMA_AXI_BLEN_64 \
- | DMA_AXI_BLEN_128 | DMA_AXI_BLEN_256)
-
-+#define DMA_AXI_RD_OSR_LMT_SHIFT 16
-+#define DMA_AXI_WR_OSR_LMT_SHIFT 20
-+
- /* Platfrom data for platform device structure's platform_data field */
-
- struct stmmac_mdio_bus_data {
-@@ -88,6 +91,7 @@ struct stmmac_mdio_bus_data {
-
- struct stmmac_dma_cfg {
- int pbl;
-+ int aal;
- int fixed_burst;
- int mixed_burst;
- int burst_len;
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
-@@ -31,7 +31,8 @@
- #include "dwmac_dma.h"
-
- static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-- int burst_len, u32 dma_tx, u32 dma_rx, int atds)
-+ int burst_len, u32 dma_tx, u32 dma_rx, int atds,
-+ int aal)
- {
- u32 value = readl(ioaddr + DMA_BUS_MODE);
- int limit;
-@@ -62,6 +63,10 @@ static int dwmac1000_dma_init(void __iom
- value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
- (pbl << DMA_BUS_MODE_RPBL_SHIFT));
-
-+ /* Address Aligned Beats */
-+ if (aal)
-+ value |= DMA_BUS_MODE_AAL;
-+
- /* Set the Fixed burst mode */
- if (fb)
- value |= DMA_BUS_MODE_FB;
---- a/drivers/net/ethernet/stmicro/stmmac/common.h
-+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
-@@ -352,7 +352,7 @@ extern const struct stmmac_desc_ops ndes
- struct stmmac_dma_ops {
- /* DMA core initialization */
- int (*init) (void __iomem *ioaddr, int pbl, int fb, int mb,
-- int burst_len, u32 dma_tx, u32 dma_rx, int atds);
-+ int burst_len, u32 dma_tx, u32 dma_rx, int atds, int aal);
- /* Dump DMA registers */
- void (*dump_regs) (void __iomem *ioaddr);
- /* Set tx/rx threshold in the csr6 register
---- a/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
-@@ -33,7 +33,8 @@
- #include "dwmac_dma.h"
-
- static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-- int burst_len, u32 dma_tx, u32 dma_rx, int atds)
-+ int burst_len, u32 dma_tx, u32 dma_rx, int atds,
-+ int aal)
- {
- u32 value = readl(ioaddr + DMA_BUS_MODE);
- int limit;
---- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
-@@ -1639,9 +1639,11 @@ static int stmmac_init_dma_engine(struct
- int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;
- int mixed_burst = 0;
- int atds = 0;
-+ int aal = 0;
-
- if (priv->plat->dma_cfg) {
- pbl = priv->plat->dma_cfg->pbl;
-+ aal = priv->plat->dma_cfg->aal;
- fixed_burst = priv->plat->dma_cfg->fixed_burst;
- mixed_burst = priv->plat->dma_cfg->mixed_burst;
- burst_len = priv->plat->dma_cfg->burst_len;
-@@ -1652,7 +1654,7 @@ static int stmmac_init_dma_engine(struct
-
- return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
- burst_len, priv->dma_tx_phy,
-- priv->dma_rx_phy, atds);
-+ priv->dma_rx_phy, atds, aal);
- }
-
- /**