aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm53xx/patches-4.1
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm53xx/patches-4.1')
-rw-r--r--target/linux/bcm53xx/patches-4.1/058-ARM-BCM5301X-Add-USB-LED-for-Buffalo-WZR-1750DHP.patch26
-rw-r--r--target/linux/bcm53xx/patches-4.1/059-ARM-BCM5301X-Add-DT-for-Buffalo-WXR-1900DHP.patch157
-rw-r--r--target/linux/bcm53xx/patches-4.1/060-ARM-BCM5301X-Add-DT-for-SmartRG-SR400ac.patch148
-rw-r--r--target/linux/bcm53xx/patches-4.1/061-ARM-BCM5301X-Add-DT-for-Asus-RT-AC68U.patch112
-rw-r--r--target/linux/bcm53xx/patches-4.1/062-ARM-BCM5301X-Add-DT-for-Asus-RT-AC56U.patch125
-rw-r--r--target/linux/bcm53xx/patches-4.1/063-ARM-BCM5301X-Ignore-another-BCM4709-specific-fault-c.patch41
-rw-r--r--target/linux/bcm53xx/patches-4.1/064-ARM-BCM5301X-add-NAND-flash-chip-description.patch210
-rw-r--r--target/linux/bcm53xx/patches-4.1/065-ARM-BCM5301X-add-IRQ-numbers-for-PCIe-controller.patch48
-rw-r--r--target/linux/bcm53xx/patches-4.1/066-ARM-BCM5301X-Add-DT-for-Asus-RT-AC87U.patch95
-rw-r--r--target/linux/bcm53xx/patches-4.1/110-firmware-backport-NVRAM-driver.patch49
-rw-r--r--target/linux/bcm53xx/patches-4.1/112-bcm53xx-sprom-add-sprom-driver.patch69
-rw-r--r--target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch314
-rw-r--r--target/linux/bcm53xx/patches-4.1/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch534
-rw-r--r--target/linux/bcm53xx/patches-4.1/180-USB-bcma-remove-chip-id-check.patch34
-rw-r--r--target/linux/bcm53xx/patches-4.1/181-USB-bcma-replace-numbers-with-constants.patch24
-rw-r--r--target/linux/bcm53xx/patches-4.1/182-USB-bcma-use-devm_kzalloc.patch47
-rw-r--r--target/linux/bcm53xx/patches-4.1/183-USB-bcma-fix-error-handling-in-bcma_hcd_create_pdev.patch33
-rw-r--r--target/linux/bcm53xx/patches-4.1/184-USB-bcma-add-bcm53xx-support.patch133
-rw-r--r--target/linux/bcm53xx/patches-4.1/185-USB-bcma-add-support-for-controlling-bus-power-throu.patch82
-rw-r--r--target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch195
-rw-r--r--target/linux/bcm53xx/patches-4.1/301-ARM-BCM5301X-Add-SPROM.patch26
-rw-r--r--target/linux/bcm53xx/patches-4.1/303-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch148
-rw-r--r--target/linux/bcm53xx/patches-4.1/305-ARM-BCM53XX-set-customized-AUXCTL.patch30
-rw-r--r--target/linux/bcm53xx/patches-4.1/306-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch161
-rw-r--r--target/linux/bcm53xx/patches-4.1/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch41
-rw-r--r--target/linux/bcm53xx/patches-4.1/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch63
-rw-r--r--target/linux/bcm53xx/patches-4.1/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch20
-rw-r--r--target/linux/bcm53xx/patches-4.1/340-ARM-BCM5301X-Add-profiling-support.patch20
-rw-r--r--target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-serial-console.patch250
-rw-r--r--target/linux/bcm53xx/patches-4.1/352-ARM-BCM5301X-Add-back-Luxul-XWC-1000-NAND-flash-layo.patch37
-rw-r--r--target/linux/bcm53xx/patches-4.1/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch31
-rw-r--r--target/linux/bcm53xx/patches-4.1/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch19
-rw-r--r--target/linux/bcm53xx/patches-4.1/420-mtd-bcm5301x_nand.patch1608
-rw-r--r--target/linux/bcm53xx/patches-4.1/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch59
-rw-r--r--target/linux/bcm53xx/patches-4.1/700-bgmac-add-support-for-the-3rd-bus-core-device.patch63
-rw-r--r--target/linux/bcm53xx/patches-4.1/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch35
-rw-r--r--target/linux/bcm53xx/patches-4.1/800-bcma-use-two-different-initcalls-if-built-in.patch65
-rw-r--r--target/linux/bcm53xx/patches-4.1/810-USB-bcma-make-helper-creating-platform-dev-more-gene.patch73
-rw-r--r--target/linux/bcm53xx/patches-4.1/811-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch102
-rw-r--r--target/linux/bcm53xx/patches-4.1/812-USB-bcma-add-USB-3.0-support.patch274
-rw-r--r--target/linux/bcm53xx/patches-4.1/813-USB-bcma-fix-setting-VCC-GPIO-value.patch45
-rw-r--r--target/linux/bcm53xx/patches-4.1/820-xhci-add-Broadcom-specific-fake-doorbell.patch94
-rw-r--r--target/linux/bcm53xx/patches-4.1/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch42
43 files changed, 5782 insertions, 0 deletions
diff --git a/target/linux/bcm53xx/patches-4.1/058-ARM-BCM5301X-Add-USB-LED-for-Buffalo-WZR-1750DHP.patch b/target/linux/bcm53xx/patches-4.1/058-ARM-BCM5301X-Add-USB-LED-for-Buffalo-WZR-1750DHP.patch
new file mode 100644
index 0000000000..290ea0aea9
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/058-ARM-BCM5301X-Add-USB-LED-for-Buffalo-WZR-1750DHP.patch
@@ -0,0 +1,26 @@
+From 35ad0e50bd6683c6699586e3bd5045f0695586d9 Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Wed, 13 May 2015 09:10:51 +0200
+Subject: [PATCH] ARM: BCM5301X: Add USB LED for Buffalo WZR-1750DHP
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -47,6 +47,12 @@
+ leds {
+ compatible = "gpio-leds";
+
++ usb {
++ label = "bcm53xx:blue:usb";
++ gpios = <&hc595 0 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
+ power0 {
+ label = "bcm53xx:red:power";
+ gpios = <&hc595 1 GPIO_ACTIVE_HIGH>;
diff --git a/target/linux/bcm53xx/patches-4.1/059-ARM-BCM5301X-Add-DT-for-Buffalo-WXR-1900DHP.patch b/target/linux/bcm53xx/patches-4.1/059-ARM-BCM5301X-Add-DT-for-Buffalo-WXR-1900DHP.patch
new file mode 100644
index 0000000000..e16d39b423
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/059-ARM-BCM5301X-Add-DT-for-Buffalo-WXR-1900DHP.patch
@@ -0,0 +1,157 @@
+From 35eecd10ee57b9d4f31e12598296b235ed2b34ae Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Wed, 13 May 2015 09:10:52 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for Buffalo WXR-1900DHP
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 127 ++++++++++++++++++++++
+ 2 files changed, 128 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -63,6 +63,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm47081-asus-rt-n18u.dtb \
+ bcm47081-buffalo-wzr-600dhp2.dtb \
+ bcm47081-buffalo-wzr-900dhp.dtb \
++ bcm4709-buffalo-wxr-1900dhp.dtb \
+ bcm4709-netgear-r8000.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+ bcm963138dvt.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -0,0 +1,127 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Buffalo WXR-1900DHP
++ *
++ * Copyright (C) 2015 Felix Fietkau <nbd@openwrt.org>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ compatible = "buffalo,wxr-1900dhp", "brcm,bcm4709", "brcm,bcm4708";
++ model = "Buffalo WXR-1900DHP";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ usb {
++ label = "bcm53xx:green:usb";
++ gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ power-amber {
++ label = "bcm53xx:amber:power";
++ gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ power-white {
++ label = "bcm53xx:white:power";
++ gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-on";
++ };
++
++ router-amber {
++ label = "bcm53xx:amber:router";
++ gpios = <&chipcommon 7 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ router-white {
++ label = "bcm53xx:white:router";
++ gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wan-amber {
++ label = "bcm53xx:amber:wan";
++ gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wan-white {
++ label = "bcm53xx:white:wan";
++ gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wireless-amber {
++ label = "bcm53xx:amber:wireless";
++ gpios = <&chipcommon 11 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wireless-white {
++ label = "bcm53xx:white:wireless";
++ gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ power {
++ label = "Power";
++ linux,code = <KEY_POWER>;
++ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
++ };
++
++ aoss {
++ label = "AOSS";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
++ };
++
++ /* Commit mode set by switch? */
++ mode {
++ label = "Mode";
++ linux,code = <KEY_SETUP>;
++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
++ };
++
++ /* Switch: AP mode */
++ sw_ap {
++ label = "AP";
++ linux,code = <BTN_0>;
++ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
++ };
++
++ eject {
++ label = "USB eject";
++ linux,code = <KEY_EJECTCD>;
++ gpios = <&chipcommon 20 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
diff --git a/target/linux/bcm53xx/patches-4.1/060-ARM-BCM5301X-Add-DT-for-SmartRG-SR400ac.patch b/target/linux/bcm53xx/patches-4.1/060-ARM-BCM5301X-Add-DT-for-SmartRG-SR400ac.patch
new file mode 100644
index 0000000000..dafae7b170
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/060-ARM-BCM5301X-Add-DT-for-SmartRG-SR400ac.patch
@@ -0,0 +1,148 @@
+From 691917f20cae813d242f7123a4dc97e7d48e6ff1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 13 May 2015 09:10:53 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for SmartRG SR400ac
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts | 119 ++++++++++++++++++++++++++
+ 2 files changed, 120 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -60,6 +60,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-luxul-xwc-1000.dtb \
+ bcm4708-netgear-r6250.dtb \
+ bcm4708-netgear-r6300-v2.dtb \
++ bcm4708-smartrg-sr400ac.dtb \
+ bcm47081-asus-rt-n18u.dtb \
+ bcm47081-buffalo-wzr-600dhp2.dtb \
+ bcm47081-buffalo-wzr-900dhp.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -0,0 +1,119 @@
++/*
++ * Broadcom BCM470X / BCM5301X arm platform code.
++ * DTS for SmartRG SR400ac
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ compatible = "smartrg,sr400ac", "brcm,bcm4708";
++ model = "SmartRG SR400ac";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ power-white {
++ label = "bcm53xx:white:power";
++ gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-on";
++ };
++
++ power-amber {
++ label = "bcm53xx:amber:power";
++ gpios = <&chipcommon 2 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb2 {
++ label = "bcm53xx:white:usb2";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3-white {
++ label = "bcm53xx:white:usb3";
++ gpios = <&chipcommon 4 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3-green {
++ label = "bcm53xx:green:usb3";
++ gpios = <&chipcommon 5 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wps {
++ label = "bcm53xx:white:wps";
++ gpios = <&chipcommon 6 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ status-red {
++ label = "bcm53xx:red:status";
++ gpios = <&chipcommon 8 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ status-green {
++ label = "bcm53xx:green:status";
++ gpios = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ status-blue {
++ label = "bcm53xx:blue:status";
++ gpios = <&chipcommon 10 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wan-white {
++ label = "bcm53xx:white:wan";
++ gpios = <&chipcommon 12 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wan-red {
++ label = "bcm53xx:red:wan";
++ gpios = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ rfkill {
++ label = "WiFi";
++ linux,code = <KEY_RFKILL>;
++ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
++ };
++
++ wps {
++ label = "WPS";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
diff --git a/target/linux/bcm53xx/patches-4.1/061-ARM-BCM5301X-Add-DT-for-Asus-RT-AC68U.patch b/target/linux/bcm53xx/patches-4.1/061-ARM-BCM5301X-Add-DT-for-Asus-RT-AC68U.patch
new file mode 100644
index 0000000000..02e644e7c0
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/061-ARM-BCM5301X-Add-DT-for-Asus-RT-AC68U.patch
@@ -0,0 +1,112 @@
+From b5f350c790ae6aaf3dda5a825d7e3fdeed731164 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 28 Mar 2015 15:01:38 +0100
+Subject: [PATCH] ARM: BCM5301X: Add DT for Asus RT-AC68U
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts | 83 +++++++++++++++++++++++++++++
+ 2 files changed, 84 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -56,6 +56,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2835-rpi-b.dtb \
+ bcm2835-rpi-b-plus.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
++ bcm4708-asus-rt-ac68u.dtb \
+ bcm4708-buffalo-wzr-1750dhp.dtb \
+ bcm4708-luxul-xwc-1000.dtb \
+ bcm4708-netgear-r6250.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -0,0 +1,83 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Asus RT-AC68U
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ compatible = "asus,rt-ac68u", "brcm,bcm4708";
++ model = "Asus RT-AC68U (BCM4708)";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ usb2 {
++ label = "bcm53xx:blue:usb2";
++ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ power {
++ label = "bcm53xx:blue:power";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ logo {
++ label = "bcm53xx:white:logo";
++ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ usb3 {
++ label = "bcm53xx:blue:usb3";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ brightness {
++ label = "Backlight";
++ linux,code = <KEY_BRIGHTNESS_ZERO>;
++ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
++ };
++
++ wps {
++ label = "WPS";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
++ };
++
++ rfkill {
++ label = "WiFi";
++ linux,code = <KEY_RFKILL>;
++ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
diff --git a/target/linux/bcm53xx/patches-4.1/062-ARM-BCM5301X-Add-DT-for-Asus-RT-AC56U.patch b/target/linux/bcm53xx/patches-4.1/062-ARM-BCM5301X-Add-DT-for-Asus-RT-AC56U.patch
new file mode 100644
index 0000000000..e72835b186
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/062-ARM-BCM5301X-Add-DT-for-Asus-RT-AC56U.patch
@@ -0,0 +1,125 @@
+From 16dc3bac722252a10e396546f44135ae1b6a7ff3 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 31 Mar 2015 17:29:18 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for Asus RT-AC56U
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts | 96 +++++++++++++++++++++++++++++
+ 2 files changed, 97 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -56,6 +56,7 @@ dtb-$(CONFIG_ARCH_BCM2835) += \
+ bcm2835-rpi-b.dtb \
+ bcm2835-rpi-b-plus.dtb
+ dtb-$(CONFIG_ARCH_BCM_5301X) += \
++ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
+ bcm4708-buffalo-wzr-1750dhp.dtb \
+ bcm4708-luxul-xwc-1000.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -0,0 +1,96 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Asus RT-AC56U
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ compatible = "asus,rt-ac56u", "brcm,bcm4708";
++ model = "Asus RT-AC56U (BCM4708)";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ usb3 {
++ label = "bcm53xx:blue:usb3";
++ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ wan {
++ label = "bcm53xx:blue:wan";
++ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ lan {
++ label = "bcm53xx:blue:lan";
++ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ power {
++ label = "bcm53xx:blue:power";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ all {
++ label = "bcm53xx:blue:all";
++ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ 2ghz {
++ label = "bcm53xx:blue:2ghz";
++ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++
++ usb2 {
++ label = "bcm53xx:blue:usb2";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ rfkill {
++ label = "WiFi";
++ linux,code = <KEY_RFKILL>;
++ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
++ };
++
++ wps {
++ label = "WPS";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
diff --git a/target/linux/bcm53xx/patches-4.1/063-ARM-BCM5301X-Ignore-another-BCM4709-specific-fault-c.patch b/target/linux/bcm53xx/patches-4.1/063-ARM-BCM5301X-Ignore-another-BCM4709-specific-fault-c.patch
new file mode 100644
index 0000000000..8716a0d5c6
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/063-ARM-BCM5301X-Ignore-another-BCM4709-specific-fault-c.patch
@@ -0,0 +1,41 @@
+From 7eb68a2a0519a77b93184c695d4d293c92dc2286 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 11 Feb 2015 16:40:58 +0100
+Subject: [PATCH] ARM: BCM5301X: Ignore another (BCM4709 specific) fault code
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Broadcom ARM devices seem to generate some fault once per boot. We
+already have an ignoring handler for BCM4707/BCM4708, but BCM4709
+generates different code.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/mach-bcm/bcm_5301x.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/mach-bcm/bcm_5301x.c
++++ b/arch/arm/mach-bcm/bcm_5301x.c
+@@ -18,15 +18,16 @@ static bool first_fault = true;
+ static int bcm5301x_abort_handler(unsigned long addr, unsigned int fsr,
+ struct pt_regs *regs)
+ {
+- if (fsr == 0x1c06 && first_fault) {
++ if ((fsr == 0x1406 || fsr == 0x1c06) && first_fault) {
+ first_fault = false;
+
+ /*
+- * These faults with code 0x1c06 happens for no good reason,
+- * possibly left over from the CFE boot loader.
++ * These faults with codes 0x1406 (BCM4709) or 0x1c06 happens
++ * for no good reason, possibly left over from the CFE boot
++ * loader.
+ */
+ pr_warn("External imprecise Data abort at addr=%#lx, fsr=%#x ignored.\n",
+- addr, fsr);
++ addr, fsr);
+
+ /* Returning non-zero causes fault display and panic */
+ return 0;
diff --git a/target/linux/bcm53xx/patches-4.1/064-ARM-BCM5301X-add-NAND-flash-chip-description.patch b/target/linux/bcm53xx/patches-4.1/064-ARM-BCM5301X-add-NAND-flash-chip-description.patch
new file mode 100644
index 0000000000..aa99f3758c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/064-ARM-BCM5301X-add-NAND-flash-chip-description.patch
@@ -0,0 +1,210 @@
+From 9faa5960eef3204cae6637b530f5e23e53b5a9ef Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 29 May 2015 23:39:47 +0200
+Subject: [PATCH] ARM: BCM5301X: add NAND flash chip description
+
+This adds the NAND flash chip description for a standard chip found
+connected to this SoC. This makes use of generic Broadcom NAND driver
+with the iProc interface.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts | 1 +
+ arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts | 1 +
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 1 +
+ arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts | 9 +++-----
+ arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 1 +
+ arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 1 +
+ arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts | 1 +
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 1 +
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 1 +
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts | 1 +
+ arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 1 +
+ arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 1 +
+ arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi | 24 ++++++++++++++++++++++
+ arch/arm/boot/dts/bcm5301x.dtsi | 12 +++++++++++
+ 14 files changed, 50 insertions(+), 6 deletions(-)
+ create mode 100644 arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
+
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "asus,rt-ac56u", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "asus,rt-ac68u", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "buffalo,wzr-1750dhp", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "luxul,xwc-1000", "brcm,bcm4708";
+@@ -23,12 +24,8 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
+- axi@18000000 {
+- nand@28000 {
+- reg = <0x00028000 0x1000>;
+- #address-cells = <1>;
+- #size-cells = <1>;
+-
++ nand: nand@18028000 {
++ nandcs@0 {
+ partition@0 {
+ label = "ubi";
+ reg = <0x00000000 0x08000000>;
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "netgear,r6250v1", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "netgear,r6300v2", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "smartrg,sr400ac", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm47081.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "asus,rt-n18u", "brcm,bcm47081", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm47081.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "buffalo,wzr-600dhp2", "brcm,bcm47081", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm47081.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "buffalo,wzr-900dhp", "brcm,bcm47081", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "buffalo,wxr-1900dhp", "brcm,bcm4709", "brcm,bcm4708";
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "netgear,r8000", "brcm,bcm4709", "brcm,bcm4708";
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
+@@ -0,0 +1,24 @@
++/*
++ * Broadcom BCM470X / BCM5301X Nand chip defaults.
++ *
++ * This should be included if the NAND controller is on chip select 0
++ * and uses 8 bit ECC.
++ *
++ * Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/ {
++ nand@18028000 {
++ nandcs@0 {
++ compatible = "brcm,nandcs";
++ reg = <0>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ nand-ecc-strength = <8>;
++ nand-ecc-step-size = <512>;
++ };
++ };
++};
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -143,4 +143,16 @@
+ #gpio-cells = <2>;
+ };
+ };
++
++ nand: nand@18028000 {
++ compatible = "brcm,nand-iproc", "brcm,brcmnand-v6.1", "brcm,brcmnand";
++ reg = <0x18028000 0x600>, <0x1811a408 0x600>, <0x18028f00 0x20>;
++ reg-names = "nand", "iproc-idm", "iproc-ext";
++ interrupts = <GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>;
++
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ brcm,nand-has-wp;
++ };
+ };
diff --git a/target/linux/bcm53xx/patches-4.1/065-ARM-BCM5301X-add-IRQ-numbers-for-PCIe-controller.patch b/target/linux/bcm53xx/patches-4.1/065-ARM-BCM5301X-add-IRQ-numbers-for-PCIe-controller.patch
new file mode 100644
index 0000000000..142211520e
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/065-ARM-BCM5301X-add-IRQ-numbers-for-PCIe-controller.patch
@@ -0,0 +1,48 @@
+From 1f80de6863ca0e36cabc622e858168fe5beb1e92 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 24 May 2015 21:08:14 +0200
+Subject: [PATCH] ARM: BCM5301X: add IRQ numbers for PCIe controller
+
+The driver for the PCIe controller was just added, this adds the
+missing definition of the IRQ numbers to device tree. The driver itself
+will be automatically detected by bcma.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/bcm5301x.dtsi | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -108,6 +108,30 @@
+ /* ChipCommon */
+ <0x00000000 0 &gic GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+
++ /* PCIe Controller 0 */
++ <0x00012000 0 &gic GIC_SPI 126 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00012000 1 &gic GIC_SPI 127 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00012000 2 &gic GIC_SPI 128 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00012000 3 &gic GIC_SPI 129 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00012000 4 &gic GIC_SPI 130 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00012000 5 &gic GIC_SPI 131 IRQ_TYPE_LEVEL_HIGH>,
++
++ /* PCIe Controller 1 */
++ <0x00013000 0 &gic GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00013000 1 &gic GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00013000 2 &gic GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00013000 3 &gic GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00013000 4 &gic GIC_SPI 136 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00013000 5 &gic GIC_SPI 137 IRQ_TYPE_LEVEL_HIGH>,
++
++ /* PCIe Controller 2 */
++ <0x00014000 0 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 1 &gic GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 2 &gic GIC_SPI 140 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 3 &gic GIC_SPI 141 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 4 &gic GIC_SPI 142 IRQ_TYPE_LEVEL_HIGH>,
++ <0x00014000 5 &gic GIC_SPI 143 IRQ_TYPE_LEVEL_HIGH>,
++
+ /* USB 2.0 Controller */
+ <0x00021000 0 &gic GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+
diff --git a/target/linux/bcm53xx/patches-4.1/066-ARM-BCM5301X-Add-DT-for-Asus-RT-AC87U.patch b/target/linux/bcm53xx/patches-4.1/066-ARM-BCM5301X-Add-DT-for-Asus-RT-AC87U.patch
new file mode 100644
index 0000000000..5790c9aaaf
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/066-ARM-BCM5301X-Add-DT-for-Asus-RT-AC87U.patch
@@ -0,0 +1,95 @@
+From 26343bdacfcdbf6ee3303d6078a015b908f90193 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sat, 16 May 2015 16:55:39 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for Asus RT-AC87U
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/dts/Makefile | 1 +
+ arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 65 +++++++++++++++++++++++++++++
+ 2 files changed, 66 insertions(+)
+ create mode 100644 arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -66,6 +66,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm47081-asus-rt-n18u.dtb \
+ bcm47081-buffalo-wzr-600dhp2.dtb \
+ bcm47081-buffalo-wzr-900dhp.dtb \
++ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
+ bcm4709-netgear-r8000.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -0,0 +1,65 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Asus RT-AC87U
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ compatible = "asus,rt-ac87u", "brcm,bcm4709", "brcm,bcm4708";
++ model = "Asus RT-AC87U";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ wps {
++ label = "bcm53xx:blue:wps";
++ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ power {
++ label = "bcm53xx:blue:power";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ wan {
++ label = "bcm53xx:red:wan";
++ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ wps {
++ label = "WPS";
++ linux,code = <KEY_WPS_BUTTON>;
++ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
diff --git a/target/linux/bcm53xx/patches-4.1/110-firmware-backport-NVRAM-driver.patch b/target/linux/bcm53xx/patches-4.1/110-firmware-backport-NVRAM-driver.patch
new file mode 100644
index 0000000000..5e944b0513
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/110-firmware-backport-NVRAM-driver.patch
@@ -0,0 +1,49 @@
+From 0509f6dcc46d10ea4bb8c70494dc7ae11bcb3f01 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 10 Dec 2014 21:14:10 +0100
+Subject: [PATCH] firmware: backport NVRAM driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/Kconfig | 2 ++
+ drivers/firmware/Kconfig | 1 +
+ drivers/firmware/Makefile | 1 +
+ drivers/net/ethernet/broadcom/b44.c | 2 +-
+ drivers/net/ethernet/broadcom/bgmac.c | 2 +-
+ drivers/ssb/driver_chipcommon_pmu.c | 2 +-
+ 6 files changed, 7 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -2105,6 +2105,8 @@ source "drivers/Kconfig"
+
+ source "drivers/firmware/Kconfig"
+
++source "drivers/firmware/Kconfig"
++
+ source "fs/Kconfig"
+
+ source "arch/arm/Kconfig.debug"
+--- a/drivers/firmware/Kconfig
++++ b/drivers/firmware/Kconfig
+@@ -136,6 +136,7 @@ config QCOM_SCM
+ bool
+ depends on ARM || ARM64
+
++source "drivers/firmware/broadcom/Kconfig"
+ source "drivers/firmware/google/Kconfig"
+ source "drivers/firmware/efi/Kconfig"
+
+--- a/drivers/firmware/Makefile
++++ b/drivers/firmware/Makefile
+@@ -14,6 +14,7 @@ obj-$(CONFIG_FIRMWARE_MEMMAP) += memmap.
+ obj-$(CONFIG_QCOM_SCM) += qcom_scm.o
+ CFLAGS_qcom_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1)
+
++obj-y += broadcom/
+ obj-$(CONFIG_GOOGLE_FIRMWARE) += google/
+ obj-$(CONFIG_EFI) += efi/
+ obj-$(CONFIG_UEFI_CPER) += efi/
diff --git a/target/linux/bcm53xx/patches-4.1/112-bcm53xx-sprom-add-sprom-driver.patch b/target/linux/bcm53xx/patches-4.1/112-bcm53xx-sprom-add-sprom-driver.patch
new file mode 100644
index 0000000000..b914fd995f
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/112-bcm53xx-sprom-add-sprom-driver.patch
@@ -0,0 +1,69 @@
+From 4e0ab3269a6d260a41a3673157753147f5f71341 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 4 May 2014 13:19:20 +0200
+Subject: [PATCH 03/17] bcm47xx-sprom: add Broadcom sprom parser driver
+
+This driver needs an nvram driver and fetches the sprom values from the
+nvram and provides it to any other driver. The calibration data for the
+wifi chip the mac address and some more board description data is
+stores in the sprom.
+
+This is based on a copy of arch/mips/bcm47xx/sprom.c and my plan is to
+make the bcm47xx MIPS SoCs also use this driver some time later.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ .../devicetree/bindings/misc/bcm47xx-sprom.txt | 16 +
+ drivers/misc/Kconfig | 11 +
+ drivers/misc/Makefile | 1 +
+ drivers/misc/bcm47xx-sprom.c | 690 +++++++++++++++++++++
+ 4 files changed, 718 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
+ create mode 100644 drivers/misc/bcm47xx-sprom.c
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/misc/bcm47xx-sprom.txt
+@@ -0,0 +1,16 @@
++Broadcom bcm47xx/bcm53xx sprom converter
++
++This driver provbides an sprom based on a given nvram.
++
++Required properties:
++
++- compatible : brcm,bcm47xx-sprom
++
++- nvram : reference to a nvram driver, e.g. bcm47xx-nvram
++
++Example:
++
++sprom0: sprom@0 {
++ compatible = "brcm,bcm47xx-sprom";
++ nvram = <&nvram0>;
++};
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -515,6 +515,17 @@ config VEXPRESS_SYSCFG
+ bus. System Configuration interface is one of the possible means
+ of generating transactions on this bus.
+
++config BCM47XX_SPROM
++ tristate "BCM47XX sprom driver"
++ help
++ This driver parses the sprom from a given nvram which is found on
++ Broadcom bcm47xx and bcm53xx SoCs.
++
++ The sprom contains board configuration data like the
++ calibration data fro the wifi chips, the mac addresses used
++ by the board and many other board configuration data. This
++ driver will provide the sprom to bcma.
++
+ source "drivers/misc/c2port/Kconfig"
+ source "drivers/misc/eeprom/Kconfig"
+ source "drivers/misc/cb710/Kconfig"
+--- a/drivers/misc/Makefile
++++ b/drivers/misc/Makefile
+@@ -56,3 +56,4 @@ obj-$(CONFIG_GENWQE) += genwqe/
+ obj-$(CONFIG_ECHO) += echo/
+ obj-$(CONFIG_VEXPRESS_SYSCFG) += vexpress-syscfg.o
+ obj-$(CONFIG_CXL_BASE) += cxl/
++obj-$(CONFIG_BCM47XX_SPROM) += bcm47xx-sprom.o
diff --git a/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
new file mode 100644
index 0000000000..bdc7dea9e1
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM5301X-Implement-SMP-support.patch
@@ -0,0 +1,314 @@
+From 707ab07695ea8953a5bb56512e7bb38ca79c5c38 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 19 Feb 2015 23:27:59 +0100
+Subject: [PATCH V2] ARM: BCM5301X: Implement SMP support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+V2: Change code after receiving Florian's comments:
+ 1) Use "mmio-sram"
+ 2) Remove commented out ASM call
+ 3) Fix coding style in ASM
+ 4) Simplify finding OF node
+---
+ Documentation/devicetree/bindings/arm/bcm4708.txt | 24 ++++
+ Documentation/devicetree/bindings/arm/cpus.txt | 1 +
+ arch/arm/boot/dts/bcm4708.dtsi | 13 ++
+ arch/arm/mach-bcm/Makefile | 3 +
+ arch/arm/mach-bcm/bcm5301x_headsmp.S | 45 ++++++
+ arch/arm/mach-bcm/bcm5301x_smp.c | 158 ++++++++++++++++++++++
+ 6 files changed, 244 insertions(+)
+ create mode 100644 arch/arm/mach-bcm/bcm5301x_headsmp.S
+ create mode 100644 arch/arm/mach-bcm/bcm5301x_smp.c
+
+--- a/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt
++++ b/Documentation/devicetree/bindings/arm/bcm/brcm,bcm4708.txt
+@@ -6,3 +6,27 @@ Boards with the BCM4708 SoC shall have t
+ Required root node property:
+
+ compatible = "brcm,bcm4708";
++
++Optional sub-node properties:
++
++compatible = "mmio-sram" for SRAM access with IO memory region
++ This is needed for SMP-capable SoCs which use part of
++ SRAM for storing location of code to be executed by the
++ extra cores.
++ SMP support requires another sub-node with compatible
++ property "brcm,bcm4708-sysram".
++
++Example:
++
++ sysram@ffff0000 {
++ compatible = "mmio-sram";
++ reg = <0xffff0000 0x10000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0xffff0000 0x10000>;
++
++ smp-sysram@0 {
++ compatible = "brcm,bcm4708-sysram";
++ reg = <0x0 0x1000>;
++ };
++ };
+--- a/Documentation/devicetree/bindings/arm/cpus.txt
++++ b/Documentation/devicetree/bindings/arm/cpus.txt
+@@ -189,6 +189,7 @@ nodes to be present and contain the prop
+ can be one of:
+ "allwinner,sun6i-a31"
+ "arm,psci"
++ "brcm,bcm4708-smp"
+ "brcm,brahma-b15"
+ "marvell,armada-375-smp"
+ "marvell,armada-380-smp"
+--- a/arch/arm/boot/dts/bcm4708.dtsi
++++ b/arch/arm/boot/dts/bcm4708.dtsi
+@@ -15,6 +15,7 @@
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
++ enable-method = "brcm,bcm4708-smp";
+
+ cpu@0 {
+ device_type = "cpu";
+@@ -31,4 +32,16 @@
+ };
+ };
+
++ sysram@ffff0000 {
++ compatible = "mmio-sram";
++ reg = <0xffff0000 0x10000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ ranges = <0 0xffff0000 0x10000>;
++
++ smp-sysram@0 {
++ compatible = "brcm,bcm4708-sysram";
++ reg = <0x0 0x1000>;
++ };
++ };
+ };
+--- a/arch/arm/mach-bcm/Makefile
++++ b/arch/arm/mach-bcm/Makefile
+@@ -36,6 +36,9 @@ obj-$(CONFIG_ARCH_BCM2835) += board_bcm2
+
+ # BCM5301X
+ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
++ifeq ($(CONFIG_SMP),y)
++obj-$(CONFIG_ARCH_BCM_5301X) += bcm5301x_smp.o bcm5301x_headsmp.o
++endif
+
+ # BCM63XXx
+ obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o
+--- /dev/null
++++ b/arch/arm/mach-bcm/bcm5301x_headsmp.S
+@@ -0,0 +1,45 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ *
++ * Copyright (c) 2003 ARM Limited
++ * All Rights Reserved
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++#include <linux/linkage.h>
++
++/*
++ * BCM5301X specific entry point for secondary CPUs.
++ */
++ENTRY(bcm5301x_secondary_startup)
++ mrc p15, 0, r0, c0, c0, 5
++ and r0, r0, #15
++ adr r4, 1f
++ ldmia r4, {r5, r6}
++ sub r4, r4, r5
++ add r6, r6, r4
++pen: ldr r7, [r6]
++ cmp r7, r0
++ bne pen
++
++ /*
++ * In case L1 cache has unpredictable contents at power-up
++ * clean its contents without flushing.
++ */
++ bl v7_invalidate_l1
++
++ mov r0, #0
++ mcr p15, 0, r0, c7, c5, 0 /* Invalidate icache */
++ dsb
++ isb
++
++ /*
++ * we've been released from the holding pen: secondary_stack
++ * should now contain the SVC stack for this core
++ */
++ b secondary_startup
++ENDPROC(bcm5301x_secondary_startup)
++
++ .align 2
++1: .long .
++ .long pen_release
+--- /dev/null
++++ b/arch/arm/mach-bcm/bcm5301x_smp.c
+@@ -0,0 +1,158 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ *
++ * Copyright (C) 2002 ARM Ltd.
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <asm/cacheflush.h>
++#include <asm/delay.h>
++#include <asm/smp_plat.h>
++#include <asm/smp_scu.h>
++
++#include <linux/clockchips.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++
++#define SOC_ROM_LUT_OFF 0x400
++
++extern void bcm5301x_secondary_startup(void);
++
++static void __cpuinit write_pen_release(int val)
++{
++ pen_release = val;
++ smp_wmb();
++ sync_cache_w(&pen_release);
++}
++
++static DEFINE_SPINLOCK(boot_lock);
++
++static void __init bcm5301x_smp_secondary_set_entry(void (*entry_point)(void))
++{
++ void __iomem *sysram_base_addr = NULL;
++ struct device_node *node;
++
++ node = of_find_compatible_node(NULL, NULL, "brcm,bcm4708-sysram");
++ if (!of_device_is_available(node))
++ return;
++
++ sysram_base_addr = of_iomap(node, 0);
++ if (!sysram_base_addr) {
++ pr_warn("Failed to map sysram\n");
++ return;
++ }
++
++ writel(virt_to_phys(entry_point), sysram_base_addr + SOC_ROM_LUT_OFF);
++
++ dsb_sev(); /* Exit WFI */
++ mb(); /* make sure write buffer is drained */
++
++ iounmap(sysram_base_addr);
++}
++
++static void __init bcm5301x_smp_prepare_cpus(unsigned int max_cpus)
++{
++ void __iomem *scu_base;
++
++ if (!scu_a9_has_base()) {
++ pr_warn("Unknown SCU base\n");
++ return;
++ }
++
++ scu_base = ioremap((phys_addr_t)scu_a9_get_base(), SZ_256);
++ if (!scu_base) {
++ pr_err("Failed to remap SCU\n");
++ return;
++ }
++
++ /* Initialise the SCU */
++ scu_enable(scu_base);
++
++ /* Let CPUs know where to start */
++ bcm5301x_smp_secondary_set_entry(bcm5301x_secondary_startup);
++
++ iounmap(scu_base);
++}
++
++static void __cpuinit bcm5301x_smp_secondary_init(unsigned int cpu)
++{
++ trace_hardirqs_off();
++
++ /*
++ * let the primary processor know we're out of the
++ * pen, then head off into the C entry point
++ */
++ write_pen_release(-1);
++
++ /*
++ * Synchronise with the boot thread.
++ */
++ spin_lock(&boot_lock);
++ spin_unlock(&boot_lock);
++}
++
++static int __cpuinit bcm5301x_smp_boot_secondary(unsigned int cpu,
++ struct task_struct *idle)
++{
++ unsigned long timeout;
++
++ /*
++ * set synchronisation state between this boot processor
++ * and the secondary one
++ */
++ spin_lock(&boot_lock);
++
++ /*
++ * The secondary processor is waiting to be released from
++ * the holding pen - release it, then wait for it to flag
++ * that it has been released by resetting pen_release.
++ *
++ * Note that "pen_release" is the hardware CPU ID, whereas
++ * "cpu" is Linux's internal ID.
++ */
++ write_pen_release(cpu_logical_map(cpu));
++
++ /* Send the secondary CPU SEV */
++ dsb_sev();
++
++ udelay(100);
++
++ /*
++ * Send the secondary CPU a soft interrupt, thereby causing
++ * the boot monitor to read the system wide flags register,
++ * and branch to the address found there.
++ */
++ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
++
++ /*
++ * Timeout set on purpose in jiffies so that on slow processors
++ * that must also have low HZ it will wait longer.
++ */
++ timeout = jiffies + (HZ * 10);
++ while (time_before(jiffies, timeout)) {
++ smp_rmb();
++ if (pen_release == -1)
++ break;
++
++ udelay(10);
++ }
++
++ /*
++ * now the secondary core is starting up let it run its
++ * calibrations, then wait for it to finish
++ */
++ spin_unlock(&boot_lock);
++
++ return pen_release != -1 ? -ENOSYS : 0;
++}
++
++static struct smp_operations bcm5301x_smp_ops __initdata = {
++ .smp_prepare_cpus = bcm5301x_smp_prepare_cpus,
++ .smp_secondary_init = bcm5301x_smp_secondary_init,
++ .smp_boot_secondary = bcm5301x_smp_boot_secondary,
++};
++
++CPU_METHOD_OF_DECLARE(bcm5301x_smp, "brcm,bcm4708-smp",
++ &bcm5301x_smp_ops);
diff --git a/target/linux/bcm53xx/patches-4.1/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch b/target/linux/bcm53xx/patches-4.1/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
new file mode 100644
index 0000000000..d4dedc0365
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/170-pcie2-bcma-add-new-PCIe2-driver-for-bcma.patch
@@ -0,0 +1,534 @@
+From cf067bf8bb993d6cfdc42d750ae241c43f88403f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 12 May 2014 11:55:20 +0200
+Subject: [PATCH 1/2] PCI: BCM5301X: add PCIe2 driver for BCM5301X SoCs
+
+This driver supports the PCIe controller found on the BCM4708 and
+similar SoCs. The controller itself is automatically detected by bcma.
+
+This controller is found on SoCs usually used in SOHO routers to
+connect the wifi cards to the SoC. All the of the BCM5301X SoCs I know
+of have 2 or 3 of these controllers in the SoC.
+
+I had to use PCI domains otherwise the pci_create_root_bus() function
+in drivers/pci/probe.c would fail for the second controller being
+registered because pci_find_bus() would find the same PCIe bus again
+and assume it is already registered, which ends up in a kernel panic in
+pcibios_init_hw() in arch/arm/kernel/bios32.c
+
+The ARM PCI code assumes that every controller has an I/O space and
+adds a dummy area if the driver does not specify one. This will work
+for the first controller, but when we register the second one this will
+result in an error. To prevent this problem we add an empty I/O space.
+
+Currently I have problems with probing the devices on the bus, because
+pci_bus_add_devices() is called too early in pci_scan_root_bus() in
+drivers/pci/probe.c, before pci_bus_assign_resources() was called in
+pci_common_init_dev() in arch/arm/kernel/bios32.c. When the devices are
+added too early they do not have any resources and adding fails. I have
+to remove the call to pci_bus_add_devices() in pci_scan_root_bus() to
+make registration work, calling pci_bus_add_devices() later again does
+not fix this problem.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/mach-bcm/Kconfig | 1 +
+ drivers/pci/host/Kconfig | 7 +
+ drivers/pci/host/Makefile | 1 +
+ drivers/pci/host/pci-host-bcm5301x.c | 428 +++++++++++++++++++++++++++++++++++
+ 4 files changed, 437 insertions(+)
+ create mode 100644 drivers/pci/host/pci-host-bcm5301x.c
+
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -38,6 +38,7 @@ config ARCH_BCM_CYGNUS
+ config ARCH_BCM_5301X
+ bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
++ select PCI_DOMAINS if PCI
+ help
+ Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
+
+--- a/drivers/pci/host/Kconfig
++++ b/drivers/pci/host/Kconfig
+@@ -125,4 +125,11 @@ config PCIE_IPROC_PLATFORM
+ Say Y here if you want to use the Broadcom iProc PCIe controller
+ through the generic platform bus interface
+
++config PCI_BCM5301X
++ bool "BCM5301X PCIe2 host controller"
++ depends on BCMA && OF && ARM && PCI_DOMAINS
++ help
++ Say Y here if you want to support the PCIe host controller found
++ on Broadcom BCM5301X and BCM470X (Northstar) SoCs.
++
+ endmenu
+--- 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_PCI_BCM5301X) += pci-host-bcm5301x.o
+--- /dev/null
++++ b/drivers/pci/host/pci-host-bcm5301x.c
+@@ -0,0 +1,459 @@
++/*
++ * Northstar PCI-Express driver
++ * Only supports Root-Complex (RC) mode
++ *
++ * Notes:
++ * PCI Domains are being used to identify the PCIe port 1:1.
++ *
++ * Only MEM access is supported, PAX does not support IO.
++ *
++ * Copyright 2012-2014, Broadcom Corporation
++ * Copyright 2014, Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/bcma/bcma.h>
++#include <linux/bcma/bcma_driver_pcie2.h>
++
++#define SOC_PCIE_HDR_OFF 0x400 /* 256 bytes per function */
++
++#define PCI_LINK_STATUS_CTRL_2_OFFSET 0xDC
++#define PCI_TARGET_LINK_SPEED_MASK 0xF
++#define PCI_TARGET_LINK_SPEED_GEN2 0x2
++#define PCI_TARGET_LINK_SPEED_GEN1 0x1
++
++static int bcma_pcie2_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
++{
++ struct pci_sys_data *sys = pdev->sysdata;
++ struct bcma_device *bdev = sys->private_data;
++
++ return bcma_core_irq(bdev, 5);
++}
++
++static u32 bcma_pcie2_cfg_base(struct bcma_device *bdev, int busno,
++ unsigned int devfn, int where)
++{
++ int slot = PCI_SLOT(devfn);
++ int fn = PCI_FUNC(devfn);
++ u32 addr_reg;
++
++ if (busno == 0) {
++ if (slot >= 1)
++ return 0;
++ bcma_write32(bdev, BCMA_CORE_PCIE2_CONFIGINDADDR,
++ where & 0xffc);
++ return BCMA_CORE_PCIE2_CONFIGINDDATA;
++ }
++ if (fn > 1)
++ return 0;
++ addr_reg = (busno & 0xff) << 20 | (slot << 15) | (fn << 12) |
++ (where & 0xffc) | (1 & 0x3);
++
++ bcma_write32(bdev, BCMA_CORE_PCIE2_CFG_ADDR, addr_reg);
++ return BCMA_CORE_PCIE2_CFG_DATA;
++}
++
++static u32 bcma_pcie2_read_config(struct bcma_device *bdev, int busno,
++ unsigned int devfn, int where, int size)
++{
++ u32 base;
++ u32 data_reg;
++ u32 mask;
++ int shift;
++
++ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
++
++ if (!base)
++ return ~0UL;
++
++ data_reg = bcma_read32(bdev, base);
++
++ if (size == 4)
++ return data_reg;
++
++ mask = (1 << (size * 8)) - 1;
++ shift = (where % 4) * 8;
++ return (data_reg >> shift) & mask;
++}
++
++static void bcma_pcie2_write_config(struct bcma_device *bdev, int busno,
++ unsigned int devfn, int where, int size,
++ u32 val)
++{
++ u32 base;
++ u32 data_reg;
++
++ base = bcma_pcie2_cfg_base(bdev, busno, devfn, where);
++
++ if (!base)
++ return;
++
++ if (size < 4) {
++ u32 mask = (1 << (size * 8)) - 1;
++ int shift = (where % 4) * 8;
++
++ data_reg = bcma_read32(bdev, base);
++ data_reg &= ~(mask << shift);
++ data_reg |= (val & mask) << shift;
++ } else {
++ data_reg = val;
++ }
++
++ bcma_write32(bdev, base, data_reg);
++}
++
++static int bcma_pcie2_read_config_pci(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 *val)
++{
++ struct pci_sys_data *sys = bus->sysdata;
++ struct bcma_device *bdev = sys->private_data;
++
++ *val = bcma_pcie2_read_config(bdev, bus->number, devfn, where, size);
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++static int bcma_pcie2_write_config_pci(struct pci_bus *bus, unsigned int devfn,
++ int where, int size, u32 val)
++{
++ struct pci_sys_data *sys = bus->sysdata;
++ struct bcma_device *bdev = sys->private_data;
++
++ bcma_pcie2_write_config(bdev, bus->number, devfn, where, size, val);
++
++ return PCIBIOS_SUCCESSFUL;
++}
++
++/*
++ * Methods for accessing configuration registers
++ */
++static struct pci_ops bcma_pcie2_ops = {
++ .read = bcma_pcie2_read_config_pci,
++ .write = bcma_pcie2_write_config_pci,
++};
++
++/* NS: CLASS field is R/O, and set to wrong 0x200 value */
++static void bcma_pcie2_fixup_class(struct pci_dev *dev)
++{
++ dev->class = PCI_CLASS_BRIDGE_PCI << 8;
++}
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8011, bcma_pcie2_fixup_class);
++DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_BROADCOM, 0x8012, bcma_pcie2_fixup_class);
++
++/*
++ * Check link status, return 0 if link is up in RC mode,
++ * otherwise return non-zero
++ */
++static int bcma_pcie2_check_link(struct bcma_device *bdev, struct pci_sys_data *sys)
++{
++ u32 tmp32;
++ u16 tmp16;
++ u16 pos;
++ u8 nlw;
++ /*
++ * Setup callback (bcma_pcie2_setup) is called in pcibios_init_hw before
++ * creating bus root, so we don't have it here yet. On the other hand
++ * we really want to use pci_bus_find_capability helper to check NLW.
++ * Let's fake simple pci_bus just to query for capabilities.
++ */
++ struct pci_bus bus = {
++ .number = 0,
++ .ops = &bcma_pcie2_ops,
++ .sysdata = sys,
++ };
++
++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_LINK_STATUS);
++ dev_dbg(&bdev->dev, "link status: 0x%08x\n", tmp32);
++
++ tmp32 = bcma_read32(bdev, BCMA_CORE_PCIE2_STRAP_STATUS);
++ dev_dbg(&bdev->dev, "strap status: 0x%08x\n", tmp32);
++
++ /* check link status to see if link is active */
++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP);
++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA, &tmp16);
++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >> PCI_EXP_LNKSTA_NLW_SHIFT;
++
++ if (nlw == 0) {
++ /* try GEN 1 link speed */
++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0,
++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4);
++ if ((tmp32 & PCI_TARGET_LINK_SPEED_MASK) ==
++ PCI_TARGET_LINK_SPEED_GEN2) {
++ tmp32 &= ~PCI_TARGET_LINK_SPEED_MASK;
++ tmp32 |= PCI_TARGET_LINK_SPEED_GEN1;
++ bcma_pcie2_write_config(bdev, 0, 0,
++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4, tmp32);
++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0,
++ PCI_LINK_STATUS_CTRL_2_OFFSET, 4);
++ msleep(100);
++
++ pos = pci_bus_find_capability(&bus, 0, PCI_CAP_ID_EXP);
++ pci_bus_read_config_word(&bus, 0, pos + PCI_EXP_LNKSTA,
++ &tmp16);
++ nlw = (tmp16 & PCI_EXP_LNKSTA_NLW) >>
++ PCI_EXP_LNKSTA_NLW_SHIFT;
++ }
++ }
++
++ dev_info(&bdev->dev, "link: %s\n", nlw ? "UP" : "DOWN");
++ return nlw ? 0 : -ENODEV;
++}
++
++/*
++ * Initializte the PCIe controller
++ */
++static void bcma_pcie2_hw_init(struct bcma_device *bdev)
++{
++ u32 tmp32;
++ u16 tmp16;
++
++ /* Change MPS and MRRS to 512 */
++ tmp16 = bcma_pcie2_read_config(bdev, 0, 0, 0x4d4, 2);
++ tmp16 &= ~7;
++ tmp16 |= 2;
++ bcma_pcie2_write_config(bdev, 0, 0, 0x4d4, 2, tmp16);
++
++ tmp32 = bcma_pcie2_read_config(bdev, 0, 0, 0xb4, 4);
++ tmp32 &= ~((7 << 12) | (7 << 5));
++ tmp32 |= (2 << 12) | (2 << 5);
++ bcma_pcie2_write_config(bdev, 0, 0, 0xb4, 4, tmp32);
++
++ /*
++ * Turn-on Root-Complex (RC) mode, from reset default of EP
++ * The mode is set by straps, can be overwritten via DMU
++ * register <cru_straps_control> bit 5, "1" means RC
++ */
++
++ /* Send a downstream reset */
++ bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL,
++ PCIE2_CLKC_RST_OE | PCIE2_CLKC_RST);
++ usleep_range(250, 400);
++ bcma_write32(bdev, BCMA_CORE_PCIE2_CLK_CONTROL, PCIE2_CLKC_RST_OE);
++ msleep(250);
++
++ /* TBD: take care of PM, check we're on */
++}
++
++/*
++ * Setup the address translation
++ *
++ * NOTE: All PCI-to-CPU address mapping are 1:1 for simplicity
++ */
++static int bcma_pcie2_map_init(struct bcma_device *bdev, u32 addr)
++{
++ /* 64MB alignment */
++ if (!addr || (addr & (SZ_64M - 1)))
++ return -EINVAL;
++
++ bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP0_LOWER, addr);
++ bcma_write32(bdev, BCMA_CORE_PCIE2_OARR0, addr | 0x01);
++
++ bcma_write32(bdev, BCMA_CORE_PCIE2_OMAP1_LOWER, addr + SZ_64M);
++ bcma_write32(bdev, BCMA_CORE_PCIE2_OARR1, (addr + SZ_64M) | 0x01);
++
++ /*
++ * Inbound address translation setup
++ * Northstar only maps up to 128 MiB inbound, DRAM could be up to 1 GiB.
++ *
++ * For now allow access to entire DRAM, assuming it is less than 128MiB,
++ * otherwise DMA bouncing mechanism may be required.
++ * Also consider DMA mask to limit DMA physical address
++ */
++ /* 64-bit LE regs, write low word, high is 0 at reset */
++ bcma_write32(bdev, BCMA_CORE_PCIE2_FUNC0_IMAP1, PHYS_OFFSET | 0x1);
++ bcma_write32(bdev, BCMA_CORE_PCIE2_IARR1_LOWER,
++ PHYS_OFFSET | ((SZ_128M >> 20) & 0xff));
++ return 0;
++}
++
++/*
++ * Setup PCIE Host bridge
++ */
++static int bcma_pcie2_bridge_init(struct bcma_device *bdev, u32 addr, u32 size)
++{
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1, 0);
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1, 1);
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1, 4);
++
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_PRIMARY_BUS, 1);
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_SECONDARY_BUS, 1);
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_SUBORDINATE_BUS, 1);
++
++ /* MEM_BASE, MEM_LIM require 1MB alignment */
++ if (((addr >> 16) & 0xf) || (((addr + size) >> 16) & 0xf))
++ return -EINVAL;
++
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_BASE, 2, addr >> 16);
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2,
++ (addr + size) >> 16);
++
++ /* These registers are not supported on the NS */
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_BASE_UPPER16, 2, 0);
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_IO_LIMIT_UPPER16, 2, 0);
++
++ /* Force class to that of a Bridge */
++ bcma_pcie2_write_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2,
++ PCI_CLASS_BRIDGE_PCI);
++
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_CLASS_DEVICE, 2);
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_BASE, 2);
++ bcma_pcie2_read_config(bdev, 0, 0, PCI_MEMORY_LIMIT, 2);
++ return 0;
++}
++
++static void bcma_pcie2_3rd_init(struct bcma_bus *bus)
++{
++ /* PCIE PLL block register (base 0x8000) */
++ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x57fe8000);
++ /* Check PCIE PLL lock status */
++ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x00000088, 0x67c60000);
++}
++
++/* To improve PCIE phy jitter */
++static void bcma_pcie2_improve_phy_jitter(struct bcma_bus *bus, int phyaddr)
++{
++ u32 val;
++
++ /* Change blkaddr */
++ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x1f << 18) |
++ (2 << 16) | (0x863 << 4);
++ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++
++ /* Write 0x0190 to 0x13 regaddr */
++ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x13 << 18) |
++ (2 << 16) | 0x0190;
++ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++
++ /* Write 0x0191 to 0x19 regaddr */
++ val = (1 << 30) | (1 << 28) | (phyaddr << 23) | (0x19 << 18) |
++ (2 << 16) | 0x0191;
++ bcma_chipco_b_mii_write(&bus->drv_cc_b, 0x0000009a, val);
++}
++
++static int bcma_pcie2_setup(int nr, struct pci_sys_data *sys)
++{
++ struct bcma_device *bdev = sys->private_data;
++ struct bcma_bus *bus = bdev->bus;
++ struct resource *res;
++ struct bcma_device *arm_core;
++ u32 cru_straps_ctrl;
++ int ret;
++ int phyaddr;
++
++ if (bdev->core_unit == 2) {
++ arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9);
++ cru_straps_ctrl = bcma_read32(arm_core, 0x2a0);
++
++ /* 3rd PCIE is not selected */
++ if (cru_straps_ctrl & 0x10)
++ return -ENODEV;
++
++ bcma_pcie2_3rd_init(bus);
++ phyaddr = 0xf;
++ } else {
++ phyaddr = bdev->core_unit;
++ }
++ bcma_pcie2_improve_phy_jitter(bus, phyaddr);
++
++ /* create mem resource */
++ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
++ if (!res)
++ return -EINVAL;
++
++ res->start = bdev->addr_s[0];
++ res->end = bdev->addr_s[0] + SZ_128M -1;
++ res->name = "PCIe dummy IO space";
++ res->flags = IORESOURCE_MEM;
++
++ pci_add_resource(&sys->resources, res);
++
++ /* This PCIe controller does not support IO Mem, so use a dummy one. */
++ res = devm_kzalloc(&bdev->dev, sizeof(*res), GFP_KERNEL);
++ if (!res)
++ return -EINVAL;
++
++ res->start = 0;
++ res->end = 0;
++ res->name = "PCIe dummy IO space";
++ res->flags = IORESOURCE_IO;
++
++ pci_add_resource(&sys->resources, res);
++
++ bcma_pcie2_hw_init(bdev);
++ ret = bcma_pcie2_map_init(bdev, bdev->addr_s[0]);
++ if (ret)
++ return ret;
++
++ /*
++ * Skip inactive ports -
++ * will need to change this for hot-plugging
++ */
++ ret = bcma_pcie2_check_link(bdev, sys);
++ if (ret)
++ return ret;
++
++ ret = bcma_pcie2_bridge_init(bdev, bdev->addr_s[0], SZ_128M);
++ if (ret)
++ return ret;
++
++ return 1;
++}
++
++static int bcma_pcie2_probe(struct bcma_device *bdev)
++{
++ struct hw_pci hw = {
++ .nr_controllers = 1,
++ .private_data = (void **)&bdev,
++ .setup = bcma_pcie2_setup,
++ .map_irq = bcma_pcie2_map_irq,
++ .ops = &bcma_pcie2_ops,
++ };
++
++ dev_info(&bdev->dev, "initializing PCIe controller\n");
++
++ /* Announce this port to ARM/PCI common code */
++ pci_common_init_dev(&bdev->dev, &hw);
++
++ /* Setup virtual-wire interrupts */
++ bcma_write32(bdev, BCMA_CORE_PCIE2_SYS_RC_INTX_EN, 0xf);
++
++ /* Enable memory and bus master */
++ bcma_write32(bdev, SOC_PCIE_HDR_OFF + 4, 0x6);
++
++ return 0;
++}
++
++static const struct bcma_device_id bcma_pcie2_table[] = {
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS),
++ {},
++};
++MODULE_DEVICE_TABLE(bcma, bcma_pcie2_table);
++
++static struct bcma_driver bcma_pcie2_driver = {
++ .name = KBUILD_MODNAME,
++ .id_table = bcma_pcie2_table,
++ .probe = bcma_pcie2_probe,
++};
++
++static int __init bcma_pcie2_init(void)
++{
++ return bcma_driver_register(&bcma_pcie2_driver);
++}
++module_init(bcma_pcie2_init);
++
++static void __exit bcma_pcie2_exit(void)
++{
++ bcma_driver_unregister(&bcma_pcie2_driver);
++}
++module_exit(bcma_pcie2_exit);
++
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("BCM5301X PCIe host controller");
++MODULE_LICENSE("GPLv2");
diff --git a/target/linux/bcm53xx/patches-4.1/180-USB-bcma-remove-chip-id-check.patch b/target/linux/bcm53xx/patches-4.1/180-USB-bcma-remove-chip-id-check.patch
new file mode 100644
index 0000000000..e5e3010356
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/180-USB-bcma-remove-chip-id-check.patch
@@ -0,0 +1,34 @@
+From baf3d128e5bdf9d322539609133a15b493b0c2ef Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:35 +0200
+Subject: [PATCH] USB: bcma: remove chip id check
+
+I have never seen any bcma device with an USB host core which was not a
+SoC, the bcma devices have an USB device core with a different core id.
+Some SoC have IDs with 47XX and 53XX in decimal form which would be
+rejected by this check. Instead of fixing this check just remove it.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 5 -----
+ 1 file changed, 5 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -214,16 +214,11 @@ err_alloc:
+ static int bcma_hcd_probe(struct bcma_device *dev)
+ {
+ int err;
+- u16 chipid_top;
+ u32 ohci_addr;
+ struct bcma_hcd_device *usb_dev;
+ struct bcma_chipinfo *chipinfo;
+
+ chipinfo = &dev->bus->chipinfo;
+- /* USBcores are only connected on embedded devices. */
+- chipid_top = (chipinfo->id & 0xFF00);
+- if (chipid_top != 0x4700 && chipid_top != 0x5300)
+- return -ENODEV;
+
+ /* TODO: Probably need checks here; is the core connected? */
+
diff --git a/target/linux/bcm53xx/patches-4.1/181-USB-bcma-replace-numbers-with-constants.patch b/target/linux/bcm53xx/patches-4.1/181-USB-bcma-replace-numbers-with-constants.patch
new file mode 100644
index 0000000000..5ae4e0d7aa
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/181-USB-bcma-replace-numbers-with-constants.patch
@@ -0,0 +1,24 @@
+From f5bc834917a8b1b9487749bdfe8eda52a01967b4 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:36 +0200
+Subject: [PATCH] USB: bcma: replace numbers with constants
+
+The constants for these numbers were added long time ago, use them.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -233,7 +233,8 @@ static int bcma_hcd_probe(struct bcma_de
+
+ /* In AI chips EHCI is addrspace 0, OHCI is 1 */
+ ohci_addr = dev->addr_s[0];
+- if ((chipinfo->id == 0x5357 || chipinfo->id == 0x4749)
++ if ((chipinfo->id == BCMA_CHIP_ID_BCM5357 ||
++ chipinfo->id == BCMA_CHIP_ID_BCM4749)
+ && chipinfo->rev == 0)
+ ohci_addr = 0x18009000;
+
diff --git a/target/linux/bcm53xx/patches-4.1/182-USB-bcma-use-devm_kzalloc.patch b/target/linux/bcm53xx/patches-4.1/182-USB-bcma-use-devm_kzalloc.patch
new file mode 100644
index 0000000000..700d354332
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/182-USB-bcma-use-devm_kzalloc.patch
@@ -0,0 +1,47 @@
+From 93724affb195149df6f7630901d878f6e273fa02 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:37 +0200
+Subject: [PATCH] USB: bcma: use devm_kzalloc
+
+Instead of manually handling the frees use devm. There was also a free
+missing in the unregister call which is not needed with devm.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 11 ++++-------
+ 1 file changed, 4 insertions(+), 7 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -225,7 +225,8 @@ static int bcma_hcd_probe(struct bcma_de
+ if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+- usb_dev = kzalloc(sizeof(struct bcma_hcd_device), GFP_KERNEL);
++ usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device),
++ GFP_KERNEL);
+ if (!usb_dev)
+ return -ENOMEM;
+
+@@ -239,10 +240,8 @@ static int bcma_hcd_probe(struct bcma_de
+ ohci_addr = 0x18009000;
+
+ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
+- if (IS_ERR(usb_dev->ohci_dev)) {
+- err = PTR_ERR(usb_dev->ohci_dev);
+- goto err_free_usb_dev;
+- }
++ if (IS_ERR(usb_dev->ohci_dev))
++ return PTR_ERR(usb_dev->ohci_dev);
+
+ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
+ if (IS_ERR(usb_dev->ehci_dev)) {
+@@ -255,8 +254,6 @@ static int bcma_hcd_probe(struct bcma_de
+
+ err_unregister_ohci_dev:
+ platform_device_unregister(usb_dev->ohci_dev);
+-err_free_usb_dev:
+- kfree(usb_dev);
+ return err;
+ }
+
diff --git a/target/linux/bcm53xx/patches-4.1/183-USB-bcma-fix-error-handling-in-bcma_hcd_create_pdev.patch b/target/linux/bcm53xx/patches-4.1/183-USB-bcma-fix-error-handling-in-bcma_hcd_create_pdev.patch
new file mode 100644
index 0000000000..91cd0fa320
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/183-USB-bcma-fix-error-handling-in-bcma_hcd_create_pdev.patch
@@ -0,0 +1,33 @@
+From 232996d1ba3002e7e80b18075e2838fc86f21412 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:38 +0200
+Subject: [PATCH] USB: bcma: fix error handling in bcma_hcd_create_pdev()
+
+This patch makes bcma_hcd_create_pdev() not return NULL, but a prober
+error code in case of an error.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -169,7 +169,7 @@ static struct platform_device *bcma_hcd_
+ {
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+- int ret = -ENOMEM;
++ int ret;
+
+ memset(hci_res, 0, sizeof(hci_res));
+
+@@ -183,7 +183,7 @@ static struct platform_device *bcma_hcd_
+ hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+ "ehci-platform" , 0);
+ if (!hci_dev)
+- return NULL;
++ return ERR_PTR(-ENOMEM);
+
+ hci_dev->dev.parent = &dev->dev;
+ hci_dev->dev.dma_mask = &hci_dev->dev.coherent_dma_mask;
diff --git a/target/linux/bcm53xx/patches-4.1/184-USB-bcma-add-bcm53xx-support.patch b/target/linux/bcm53xx/patches-4.1/184-USB-bcma-add-bcm53xx-support.patch
new file mode 100644
index 0000000000..bca555cf6a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/184-USB-bcma-add-bcm53xx-support.patch
@@ -0,0 +1,133 @@
+From b65851f41c22b8c69b8fe9ca7782d19ed2155efc Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:39 +0200
+Subject: [PATCH] USB: bcma: add bcm53xx support
+
+The Broadcom ARM SoCs with this usb core need a different
+initialization and they have a different core id. This patch adds
+support for these USB 2.0 core.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 81 +++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 78 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -2,7 +2,8 @@
+ * Broadcom specific Advanced Microcontroller Bus
+ * Broadcom USB-core driver (BCMA bus glue)
+ *
+- * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2011-2015 Hauke Mehrtens <hauke@hauke-m.de>
++ * Copyright 2015 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Based on ssb-ohci driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+@@ -88,7 +89,7 @@ static void bcma_hcd_4716wa(struct bcma_
+ }
+
+ /* based on arch/mips/brcm-boards/bcm947xx/pcibios.c */
+-static void bcma_hcd_init_chip(struct bcma_device *dev)
++static void bcma_hcd_init_chip_mips(struct bcma_device *dev)
+ {
+ u32 tmp;
+
+@@ -159,6 +160,70 @@ static void bcma_hcd_init_chip(struct bc
+ }
+ }
+
++static void bcma_hcd_init_chip_arm_phy(struct bcma_device *dev)
++{
++ struct bcma_device *arm_core;
++ void __iomem *dmu;
++
++ arm_core = bcma_find_core(dev->bus, BCMA_CORE_ARMCA9);
++ if (!arm_core) {
++ dev_err(&dev->dev, "can not find ARM Cortex A9 ihost core\n");
++ return;
++ }
++
++ dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000);
++ if (!dmu) {
++ dev_err(&dev->dev, "can not map ARM Cortex A9 ihost core\n");
++ return;
++ }
++
++ /* Unlock DMU PLL settings */
++ iowrite32(0x0000ea68, dmu + 0x180);
++
++ /* Write USB 2.0 PLL control setting */
++ iowrite32(0x00dd10c3, dmu + 0x164);
++
++ /* Lock DMU PLL settings */
++ iowrite32(0x00000000, dmu + 0x180);
++
++ iounmap(dmu);
++}
++
++static void bcma_hcd_init_chip_arm_hc(struct bcma_device *dev)
++{
++ u32 val;
++
++ /*
++ * Delay after PHY initialized to ensure HC is ready to be configured
++ */
++ usleep_range(1000, 2000);
++
++ /* Set packet buffer OUT threshold */
++ val = bcma_read32(dev, 0x94);
++ val &= 0xffff;
++ val |= 0x80 << 16;
++ bcma_write32(dev, 0x94, val);
++
++ /* Enable break memory transfer */
++ val = bcma_read32(dev, 0x9c);
++ val |= 1;
++ bcma_write32(dev, 0x9c, val);
++}
++
++static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
++{
++ bcma_core_enable(dev, 0);
++
++ if (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4707 ||
++ dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM53018) {
++ if (dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4707 ||
++ dev->bus->chipinfo.pkg == BCMA_PKG_ID_BCM4708)
++ bcma_hcd_init_chip_arm_phy(dev);
++
++ bcma_hcd_init_chip_arm_hc(dev);
++ }
++}
++
+ static const struct usb_ehci_pdata ehci_pdata = {
+ };
+
+@@ -230,7 +295,16 @@ static int bcma_hcd_probe(struct bcma_de
+ if (!usb_dev)
+ return -ENOMEM;
+
+- bcma_hcd_init_chip(dev);
++ switch (dev->id.id) {
++ case BCMA_CORE_NS_USB20:
++ bcma_hcd_init_chip_arm(dev);
++ break;
++ case BCMA_CORE_USB20_HOST:
++ bcma_hcd_init_chip_mips(dev);
++ break;
++ default:
++ return -ENODEV;
++ }
+
+ /* In AI chips EHCI is addrspace 0, OHCI is 1 */
+ ohci_addr = dev->addr_s[0];
+@@ -299,6 +373,7 @@ static int bcma_hcd_resume(struct bcma_d
+
+ static const struct bcma_device_id bcma_hcd_table[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ {},
+ };
+ MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
diff --git a/target/linux/bcm53xx/patches-4.1/185-USB-bcma-add-support-for-controlling-bus-power-throu.patch b/target/linux/bcm53xx/patches-4.1/185-USB-bcma-add-support-for-controlling-bus-power-throu.patch
new file mode 100644
index 0000000000..d9a8a1e621
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/185-USB-bcma-add-support-for-controlling-bus-power-throu.patch
@@ -0,0 +1,82 @@
+From f3cf44a313b3687efd55ba091558e20a4d218c31 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 11 Jun 2015 22:57:40 +0200
+Subject: [PATCH] USB: bcma: add support for controlling bus power through GPIO
+
+On some boards a GPIO is needed to activate USB controller. Make it
+possible to specify such a GPIO in device tree.
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 24 ++++++++++++++++++++++++
+ 1 file changed, 24 insertions(+)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -24,6 +24,8 @@
+ #include <linux/platform_device.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
+ #include <linux/usb/ehci_pdriver.h>
+ #include <linux/usb/ohci_pdriver.h>
+
+@@ -224,6 +226,23 @@ static void bcma_hcd_init_chip_arm(struc
+ }
+ }
+
++static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
++{
++ int gpio;
++
++ gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
++ if (!gpio_is_valid(gpio))
++ return;
++
++ if (val) {
++ gpio_request(gpio, "bcma-hcd-gpio");
++ gpio_set_value(gpio, 1);
++ } else {
++ gpio_set_value(gpio, 0);
++ gpio_free(gpio);
++ }
++}
++
+ static const struct usb_ehci_pdata ehci_pdata = {
+ };
+
+@@ -295,6 +314,8 @@ static int bcma_hcd_probe(struct bcma_de
+ if (!usb_dev)
+ return -ENOMEM;
+
++ bcma_hci_platform_power_gpio(dev, true);
++
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
+ bcma_hcd_init_chip_arm(dev);
+@@ -347,6 +368,7 @@ static void bcma_hcd_remove(struct bcma_
+
+ static void bcma_hcd_shutdown(struct bcma_device *dev)
+ {
++ bcma_hci_platform_power_gpio(dev, false);
+ bcma_core_disable(dev, 0);
+ }
+
+@@ -354,6 +376,7 @@ static void bcma_hcd_shutdown(struct bcm
+
+ static int bcma_hcd_suspend(struct bcma_device *dev)
+ {
++ bcma_hci_platform_power_gpio(dev, false);
+ bcma_core_disable(dev, 0);
+
+ return 0;
+@@ -361,6 +384,7 @@ static int bcma_hcd_suspend(struct bcma_
+
+ static int bcma_hcd_resume(struct bcma_device *dev)
+ {
++ bcma_hci_platform_power_gpio(dev, true);
+ bcma_core_enable(dev, 0);
+
+ return 0;
diff --git a/target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch b/target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch
new file mode 100644
index 0000000000..bc5757fb11
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch
@@ -0,0 +1,195 @@
+From 26023cdfacaf116545b1087b9d1fe50dc6fbda10 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 24 Sep 2014 22:14:07 +0200
+Subject: [PATCH] ARM: BCM5301X: Disable MMU and Dcache for decompression
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Without this fix kernel was randomly hanging in ~25% of tries during
+early init. Hangs used to happen at random places in the start_kernel.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/compressed/Makefile | 5 +
+ arch/arm/boot/compressed/head-bcm_5301x-mpcore.S | 37 +++++++
+ arch/arm/boot/compressed/mpcore_cache.S | 118 +++++++++++++++++++++++
+ 3 files changed, 160 insertions(+)
+ create mode 100644 arch/arm/boot/compressed/head-bcm_5301x-mpcore.S
+ create mode 100644 arch/arm/boot/compressed/mpcore_cache.S
+
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -31,6 +31,11 @@ ifeq ($(CONFIG_ARCH_ACORN),y)
+ OBJS += ll_char_wr.o font.o
+ endif
+
++ifeq ($(CONFIG_ARCH_BCM_5301X),y)
++OBJS += head-bcm_5301x-mpcore.o
++OBJS += mpcore_cache.o
++endif
++
+ ifeq ($(CONFIG_ARCH_SA1100),y)
+ OBJS += head-sa1100.o
+ endif
+--- /dev/null
++++ b/arch/arm/boot/compressed/head-bcm_5301x-mpcore.S
+@@ -0,0 +1,37 @@
++/*
++ *
++ * Platform specific tweaks. This is merged into head.S by the linker.
++ *
++ */
++
++#include <linux/linkage.h>
++#include <asm/assembler.h>
++#include <asm/cp15.h>
++
++ .section ".start", "ax"
++
++/*
++ * This code section is spliced into the head code by the linker
++ */
++
++__plat_uncompress_start:
++
++ @ Preserve r8/r7 i.e. kernel entry values
++ mov r12, r8
++
++ @ Clear MMU enable and Dcache enable bits
++ mrc p15, 0, r0, c1, c0, 0 @ Read SCTLR
++ bic r0, #CR_C|CR_M
++ mcr p15, 0, r0, c1, c0, 0 @ Write SCTLR
++ nop
++
++ @ Call the cache invalidation routine
++ bl v7_all_dcache_invalidate
++ nop
++ mov r0,#0
++ ldr r3, =0x19022000 @ L2 cache controller, control reg
++ str r0, [r3, #0x100] @ Disable L2 cache
++ nop
++
++ @ Restore
++ mov r8, r12
+--- /dev/null
++++ b/arch/arm/boot/compressed/mpcore_cache.S
+@@ -0,0 +1,118 @@
++/*****************************************************************************
++* Copyright 2003 - 2008 Broadcom Corporation. All rights reserved.
++*
++* Unless you and Broadcom execute a separate written software license
++* agreement governing use of this software, this software is licensed to you
++* under the terms of the GNU General Public License version 2, available at
++* http://www.broadcom.com/licenses/GPLv2.php (the "GPL").
++*
++* Notwithstanding the above, under no circumstances may you combine this
++* software in any way with any other Broadcom software provided under a
++* license other than the GPL, without Broadcom's express prior written
++* consent.
++*****************************************************************************/
++
++#include <linux/linkage.h>
++#include <linux/init.h>
++
++ __INIT
++
++/*
++ * v7_l1_cache_invalidate
++ *
++ * Invalidate contents of L1 cache without flushing its contents
++ * into outer cache and memory. This is needed when the contents
++ * of the cache are unpredictable after power-up.
++ *
++ * corrupts r0-r6
++ */
++
++ENTRY(v7_l1_cache_invalidate)
++ mov r0, #0
++ mcr p15, 2, r0, c0, c0, 0 @ set cache level to 1
++ mrc p15, 1, r0, c0, c0, 0 @ read CLIDR
++
++ ldr r1, =0x7fff
++ and r2, r1, r0, lsr #13 @ get max # of index size
++
++ ldr r1, =0x3ff
++ and r3, r1, r0, lsr #3 @ NumWays - 1
++ add r2, r2, #1 @ NumSets
++
++ and r0, r0, #0x7
++ add r0, r0, #4 @ SetShift
++
++ clz r1, r3 @ WayShift
++ add r4, r3, #1 @ NumWays
++1: sub r2, r2, #1 @ NumSets--
++ mov r3, r4 @ Temp = NumWays
++2: subs r3, r3, #1 @ Temp--
++ mov r5, r3, lsl r1
++ mov r6, r2, lsl r0
++ orr r5, r5, r6 @ Reg = (Temp<<WayShift)|(NumSets<<SetShift)
++ mcr p15, 0, r5, c7, c6, 2 @ Invalidate line
++ bgt 2b
++ cmp r2, #0
++ bgt 1b
++ dsb
++ mov r0,#0
++ mcr p15,0,r0,c7,c5,0 /* Invalidate icache */
++ isb
++ mov pc, lr
++ENDPROC(v7_l1_cache_invalidate)
++
++/*
++ * v7_all_dcache_invalidate
++ *
++ * Invalidate without flushing the contents of all cache levels
++ * accesible by the current processor core.
++ * This is useful when the contents of cache memory are undetermined
++ * at power-up.
++ * Corrupted registers: r0-r7, r9-r11
++ *
++ * Based on cache-v7.S: v7_flush_dcache_all()
++ */
++
++ENTRY(v7_all_dcache_invalidate)
++ mrc p15, 1, r0, c0, c0, 1 @ read clidr
++ ands r3, r0, #0x7000000 @ extract loc from clidr
++ mov r3, r3, lsr #23 @ left align loc bit field
++ beq finished @ if loc is 0, then no need to clean
++ mov r10, #0 @ start clean at cache level 0
++loop1:
++ add r2, r10, r10, lsr #1 @ work out 3x current cache level
++ mov r1, r0, lsr r2 @ extract cache type bits from clidr
++ and r1, r1, #7 @ mask of bits for current cache only
++ cmp r1, #2 @ see what cache we have at this level
++ blt skip @ skip if no cache, or just i-cache
++ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
++ isb @ isb to sych the new cssr&csidr
++ mrc p15, 1, r1, c0, c0, 0 @ read the new csidr
++ and r2, r1, #7 @ extract the length of the cache lines
++ add r2, r2, #4 @ add 4 (line length offset)
++ ldr r4, =0x3ff
++ ands r4, r4, r1, lsr #3 @ find maximum number on the way size
++ clz r5, r4 @ find bit pos of way size increment
++ ldr r7, =0x7fff
++ ands r7, r7, r1, lsr #13 @ extract max number of the index size
++loop2:
++ mov r9, r4 @ create working copy of max way size
++loop3:
++ orr r11, r10, r9, lsl r5 @ factor way and cache number into r11
++ orr r11, r11, r7, lsl r2 @ factor index number into r11
++ mcr p15, 0, r11, c7, c6, 2 @ Invalidate line
++ subs r9, r9, #1 @ decrement the way
++ bge loop3
++ subs r7, r7, #1 @ decrement the index
++ bge loop2
++skip:
++ add r10, r10, #2 @ increment cache number
++ cmp r3, r10
++ bgt loop1
++finished:
++ mov r10, #0 @ swith back to cache level 0
++ mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr
++ dsb
++ isb
++ mov pc, lr
++ENDPROC(v7_all_dcache_invalidate)
diff --git a/target/linux/bcm53xx/patches-4.1/301-ARM-BCM5301X-Add-SPROM.patch b/target/linux/bcm53xx/patches-4.1/301-ARM-BCM5301X-Add-SPROM.patch
new file mode 100644
index 0000000000..ca6462e3c7
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/301-ARM-BCM5301X-Add-SPROM.patch
@@ -0,0 +1,26 @@
+From d404e0b22356078a51719fa911f6e09cb1a72d80 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 7 Jun 2015 16:18:18 +0200
+Subject: [PATCH] ARM: BCM5301X: Add SPROM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm5301x.dtsi | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -95,6 +95,10 @@
+ };
+ };
+
++ sprom0: sprom@0 {
++ compatible = "brcm,bcm47xx-sprom";
++ };
++
+ axi@18000000 {
+ compatible = "brcm,bus-axi";
+ reg = <0x18000000 0x1000>;
diff --git a/target/linux/bcm53xx/patches-4.1/303-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch b/target/linux/bcm53xx/patches-4.1/303-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
new file mode 100644
index 0000000000..9b562ce1a9
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/303-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
@@ -0,0 +1,148 @@
+From eb1075cc48d3c315c7403822c33da9588ab76492 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 14 Jan 2015 08:33:25 +0100
+Subject: [PATCH] ARM: BCM5310X: Enable earlyprintk on tested devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 2 +-
+ arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 2 +-
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 2 +-
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 2 +-
+ 4 files changed, 4 insertions(+), 4 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -17,7 +17,7 @@
+ model = "Buffalo WZR-1750DHP (BCM4708)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -17,7 +17,7 @@
+ model = "Netgear R6250 V1 (BCM4708)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -17,7 +17,7 @@
+ model = "Asus RT-N18U (BCM47081)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+@@ -17,7 +17,7 @@
+ model = "Buffalo WZR-600DHP2 (BCM47081)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -17,7 +17,7 @@
+ model = "Buffalo WZR-900DHP (BCM47081)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -17,7 +17,7 @@
+ model = "Netgear R8000 (BCM4709)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -17,7 +17,7 @@
+ model = "Asus RT-AC56U (BCM4708)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -17,7 +17,7 @@
+ model = "Asus RT-AC68U (BCM4708)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+@@ -17,7 +17,7 @@
+ model = "Luxul XWC-1000 (BCM4708)";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -17,7 +17,7 @@
+ model = "Buffalo WXR-1900DHP";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -17,7 +17,7 @@
+ model = "SmartRG SR400ac";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -16,7 +16,7 @@
+ model = "Asus RT-AC87U";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
diff --git a/target/linux/bcm53xx/patches-4.1/305-ARM-BCM53XX-set-customized-AUXCTL.patch b/target/linux/bcm53xx/patches-4.1/305-ARM-BCM53XX-set-customized-AUXCTL.patch
new file mode 100644
index 0000000000..a2bed2aeb7
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/305-ARM-BCM53XX-set-customized-AUXCTL.patch
@@ -0,0 +1,30 @@
+From 4a658590f83c1e916ab63ed7fe6f0841924247db Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri, 3 Oct 2014 18:37:33 +0200
+Subject: [PATCH 2/2] ARM: BCM53XX: set customized AUXCTL
+
+This activated some more features in the l310 cache.
+
+This is based on some vendor code
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/mach-bcm/bcm_5301x.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/mach-bcm/bcm_5301x.c
++++ b/arch/arm/mach-bcm/bcm_5301x.c
+@@ -50,7 +50,12 @@ static const char __initconst *bcm5301x_
+ };
+
+ DT_MACHINE_START(BCM5301X, "BCM5301X")
+- .l2c_aux_val = 0,
++ .l2c_aux_val = L310_AUX_CTRL_CACHE_REPLACE_RR |
++ L310_AUX_CTRL_DATA_PREFETCH |
++ L310_AUX_CTRL_INSTR_PREFETCH |
++ L310_AUX_CTRL_EARLY_BRESP |
++ L2C_AUX_CTRL_SHARED_OVERRIDE |
++ L310_AUX_CTRL_FULL_LINE_ZERO,
+ .l2c_aux_mask = ~0,
+ .init_early = bcm5301x_init_early,
+ .dt_compat = bcm5301x_dt_compat,
diff --git a/target/linux/bcm53xx/patches-4.1/306-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch b/target/linux/bcm53xx/patches-4.1/306-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
new file mode 100644
index 0000000000..6637a62adc
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/306-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
@@ -0,0 +1,161 @@
+From 36b2fbb3badf0e32b371e1f7579a95d4fe25c0e1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 14 Jan 2015 09:13:58 +0100
+Subject: [PATCH] ARM: BCM5301X: Specify RAM on devices by including HIGHMEM
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 3 ++-
+ arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 3 ++-
+ arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 3 ++-
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 3 ++-
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 3 ++-
+ 5 files changed, 10 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x18000000>;
+ };
+
+ spi {
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ chipcommonA {
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ spi {
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ gpio-keys {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x18000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -20,7 +20,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
diff --git a/target/linux/bcm53xx/patches-4.1/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch b/target/linux/bcm53xx/patches-4.1/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch
new file mode 100644
index 0000000000..f99460aa46
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch
@@ -0,0 +1,41 @@
+From 504dba5b073a9009ae1e3f2fc53ea9c3aa10c38a Mon Sep 17 00:00:00 2001
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Wed, 13 May 2015 20:56:38 +0200
+Subject: [PATCH] ARM: BCM5301X: Add Buffalo WXR-1900DHP clock and USB power
+ control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 17 +++++++++++++++++
+ 1 file changed, 17 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -25,6 +25,23 @@
+ 0x88000000 0x18000000>;
+ };
+
++ clocks {
++ clk_periph: periph {
++ clock-frequency = <500000000>;
++ };
++ };
++
++ axi@18000000 {
++ usb2@21000 {
++ reg = <0x00021000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 13 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
diff --git a/target/linux/bcm53xx/patches-4.1/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch b/target/linux/bcm53xx/patches-4.1/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch
new file mode 100644
index 0000000000..7e5f018fd4
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch
@@ -0,0 +1,63 @@
+From f1ee1275f65e87e035260f4d09a0f0ba98c6854d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 21 Jun 2015 12:56:32 +0200
+Subject: [PATCH] ARM: BCM5301X: Set vcc-gpio for USB controllers
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 20 ++++++++++++++++++++
+ arch/arm/boot/dts/bcm4708-netgear-r6250.dts | 11 +++++++++++
+ 2 files changed, 31 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -25,6 +25,26 @@
+ 0x88000000 0x18000000>;
+ };
+
++ axi@18000000 {
++ usb2@21000 {
++ reg = <0x00021000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 9 GPIO_ACTIVE_HIGH>;
++ };
++
++ usb3@23000 {
++ reg = <0x00023000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 10 GPIO_ACTIVE_LOW>;
++ };
++ };
++
+ spi {
+ compatible = "spi-gpio";
+ num-chipselects = <1>;
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -35,6 +35,17 @@
+ };
+ };
+
++ axi@18000000 {
++ usb3@23000 {
++ reg = <0x00023000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
diff --git a/target/linux/bcm53xx/patches-4.1/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch b/target/linux/bcm53xx/patches-4.1/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch
new file mode 100644
index 0000000000..f9ca7eb7c1
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch
@@ -0,0 +1,20 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Subject: [PATCH] ARM: BCM5301X: Add power button for Buffalo WZR-1750DHP
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -123,6 +123,12 @@
+ #address-cells = <1>;
+ #size-cells = <0>;
+
++ power {
++ label = "Power";
++ linux,code = <KEY_POWER>;
++ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
++ };
++
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
diff --git a/target/linux/bcm53xx/patches-4.1/340-ARM-BCM5301X-Add-profiling-support.patch b/target/linux/bcm53xx/patches-4.1/340-ARM-BCM5301X-Add-profiling-support.patch
new file mode 100644
index 0000000000..291ec72f2c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/340-ARM-BCM5301X-Add-profiling-support.patch
@@ -0,0 +1,20 @@
+Subject: [PATCH] ARM: BCM5301X: Add profiling support
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+---
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -82,6 +82,13 @@
+ };
+ };
+
++ pmu {
++ compatible = "arm,cortex-a9-pmu";
++ interrupts =
++ <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
++ <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
++ };
++
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
diff --git a/target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-serial-console.patch b/target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-serial-console.patch
new file mode 100644
index 0000000000..87065de48a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-serial-console.patch
@@ -0,0 +1,250 @@
+From 6c223da976a9225ba9fae8d6f891a8fffaae6092 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 5 Dec 2014 17:38:40 +0100
+Subject: [PATCH] ARM: BCM5301X: Enable ChipCommon UART (serial console)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts | 10 ++++++++++
+ arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 10 ++++++++++
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 10 ++++++++++
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts | 10 ++++++++++
+ 4 files changed, 40 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x18000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ axi@18000000 {
+ usb2@21000 {
+ reg = <0x00021000 0x1000>;
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ spi {
+ compatible = "spi-gpio";
+ num-chipselects = <1>;
+--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+@@ -23,6 +23,16 @@
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
++
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
+
+ nand: nand@18028000 {
+ nandcs@0 {
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -46,6 +46,18 @@
+ };
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++ };
++
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -25,6 +25,18 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -25,6 +25,18 @@
+ 0x88000000 0x18000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ clock-frequency = <125000000>;
++ };
++ };
++
+ clocks {
+ clk_periph: periph {
+ clock-frequency = <500000000>;
+--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -25,6 +25,16 @@
+ 0x88000000 0x08000000>;
+ };
+
++ chipcommonA {
++ uart0: serial@0300 {
++ status = "okay";
++ };
++
++ uart1: serial@0400 {
++ status = "okay";
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
diff --git a/target/linux/bcm53xx/patches-4.1/352-ARM-BCM5301X-Add-back-Luxul-XWC-1000-NAND-flash-layo.patch b/target/linux/bcm53xx/patches-4.1/352-ARM-BCM5301X-Add-back-Luxul-XWC-1000-NAND-flash-layo.patch
new file mode 100644
index 0000000000..df65e0d03d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/352-ARM-BCM5301X-Add-back-Luxul-XWC-1000-NAND-flash-layo.patch
@@ -0,0 +1,37 @@
+From b97e582cd05f6ba80bdb63d9f677a3395edc7ff1 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 7 Jun 2015 15:37:43 +0200
+Subject: [PATCH] ARM: BCM5301X: Add back Luxul XWC-1000 NAND flash layout
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+In OpenWrt we still use old NAND driver instead of "brcm,nandcs", so
+we need to add this DT entry back.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+@@ -34,6 +34,18 @@
+ };
+ };
+
++ axi@18000000 {
++ nand@28000 {
++ reg = <0x00028000 0x1000>;
++ #address-cells = <1>;
++ #size-cells = <1>;
++ partition@0 {
++ label = "ubi";
++ reg = <0x00000000 0x08000000>;
++ };
++ };
++ };
++
+ nand: nand@18028000 {
+ nandcs@0 {
+ partition@0 {
diff --git a/target/linux/bcm53xx/patches-4.1/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch b/target/linux/bcm53xx/patches-4.1/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch
new file mode 100644
index 0000000000..ccdb28b54d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch
@@ -0,0 +1,31 @@
+From d658c21d6697293a928434fd6ac19264b5a8948d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 30 Jan 2015 08:25:54 +0100
+Subject: [PATCH] mtd: bcm47xxpart: scan whole flash on ARCH_BCM_5301X
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -120,9 +120,15 @@ static int bcm47xxpart_parse(struct mtd_
+ /* Parse block by block looking for magics */
+ for (offset = 0; offset <= master->size - blocksize;
+ offset += blocksize) {
++#ifndef CONFIG_ARCH_BCM_5301X
++ /*
++ * ARM routers may have partitions in higher memory. E.g.
++ * Netgear R8000 has board_data at 0x2600000.
++ */
+ /* Nothing more in higher memory */
+ if (offset >= 0x2000000)
+ break;
++#endif
+
+ if (curr_part >= BCM47XXPART_MAX_PARTS) {
+ pr_warn("Reached maximum number of partitions, scanning stopped!\n");
diff --git a/target/linux/bcm53xx/patches-4.1/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch b/target/linux/bcm53xx/patches-4.1/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch
new file mode 100644
index 0000000000..41ef3b300e
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch
@@ -0,0 +1,19 @@
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -28,4 +28,10 @@ config SPI_FSL_QUADSPI
+ This enables support for the Quad SPI controller in master mode.
+ We only connect the NOR to this controller now.
+
++config MTD_SPI_BCM53XXSPIFLASH
++ tristate "SPI-NOR flashes connected to the Broadcom ARM SoC"
++ depends on MTD_SPI_NOR
++ help
++ SPI driver for flashes used on Broadcom ARM SoCs.
++
+ endif # MTD_SPI_NOR
+--- a/drivers/mtd/spi-nor/Makefile
++++ b/drivers/mtd/spi-nor/Makefile
+@@ -1,2 +1,3 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
++obj-$(CONFIG_MTD_SPI_BCM53XXSPIFLASH) += bcm53xxspiflash.o
diff --git a/target/linux/bcm53xx/patches-4.1/420-mtd-bcm5301x_nand.patch b/target/linux/bcm53xx/patches-4.1/420-mtd-bcm5301x_nand.patch
new file mode 100644
index 0000000000..07cde2114a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/420-mtd-bcm5301x_nand.patch
@@ -0,0 +1,1608 @@
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -530,4 +530,10 @@ config MTD_NAND_HISI504
+ help
+ Enables support for NAND controller on Hisilicon SoC Hip04.
+
++config MTD_NAND_BCM
++ tristate "Support for NAND on some Broadcom SoC"
++ help
++ This driver is currently used for the NAND flash controller on the
++ Broadcom BCM5301X (NorthStar) SoCs.
++
+ endif # MTD_NAND
+--- 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_BCM) += bcm_nand.o
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- /dev/null
++++ b/drivers/mtd/nand/bcm_nand.c
+@@ -0,0 +1,1583 @@
++/*
++ * Nortstar NAND controller driver
++ *
++ * (c) Broadcom, Inc. 2012 All Rights Reserved.
++ * Copyright 2014 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ *
++ * This module interfaces the NAND controller and hardware ECC capabilities
++ * tp the generic NAND chip support in the NAND library.
++ *
++ * Notes:
++ * This driver depends on generic NAND driver, but works at the
++ * page level for operations.
++ *
++ * When a page is written, the ECC calculated also protects the OOB
++ * bytes not taken by ECC, and so the OOB must be combined with any
++ * OOB data that preceded the page-write operation in order for the
++ * ECC to be calculated correctly.
++ * Also, when the page is erased, but OOB data is not, HW ECC will
++ * indicate an error, because it checks OOB too, which calls for some
++ * help from the software in this driver.
++ *
++ * TBD:
++ * Block locking/unlocking support, OTP support
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/slab.h>
++#include <linux/bcma/bcma.h>
++#include <linux/of_irq.h>
++
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++
++#define NANDC_MAX_CHIPS 2 /* Only 2 CSn supported in NorthStar */
++
++/*
++ * Driver private control structure
++ */
++struct bcmnand_ctrl {
++ struct mtd_info mtd;
++ struct nand_chip nand;
++ struct bcma_device *core;
++
++ struct completion op_completion;
++
++ struct nand_ecclayout ecclayout;
++ int cmd_ret; /* saved error code */
++ unsigned char oob_index;
++ unsigned char id_byte_index;
++ unsigned char chip_num;
++ unsigned char last_cmd;
++ unsigned char ecc_level;
++ unsigned char sector_size_shift;
++ unsigned char sec_per_page_shift;
++};
++
++
++/*
++ * IRQ numbers - offset from first irq in nandc_irq resource
++ */
++#define NANDC_IRQ_RD_MISS 0
++#define NANDC_IRQ_ERASE_COMPLETE 1
++#define NANDC_IRQ_COPYBACK_COMPLETE 2
++#define NANDC_IRQ_PROGRAM_COMPLETE 3
++#define NANDC_IRQ_CONTROLLER_RDY 4
++#define NANDC_IRQ_RDBSY_RDY 5
++#define NANDC_IRQ_ECC_UNCORRECTABLE 6
++#define NANDC_IRQ_ECC_CORRECTABLE 7
++#define NANDC_IRQ_NUM 8
++
++struct bcmnand_reg_field {
++ unsigned int reg;
++ unsigned int pos;
++ unsigned int width;
++};
++
++/*
++ * REGISTERS
++ *
++ * Individual bit-fields aof registers are specificed here
++ * for clarity, and the rest of the code will access each field
++ * as if it was its own register.
++ *
++ * Following registers are off <reg_base>:
++ */
++#define REG_BIT_FIELD(r, p, w) ((struct bcmnand_reg_field){(r), (p), (w)})
++
++#define NANDC_8KB_PAGE_SUPPORT REG_BIT_FIELD(0x0, 31, 1)
++#define NANDC_REV_MAJOR REG_BIT_FIELD(0x0, 8, 8)
++#define NANDC_REV_MINOR REG_BIT_FIELD(0x0, 0, 8)
++
++#define NANDC_CMD_START_OPCODE REG_BIT_FIELD(0x4, 24, 5)
++
++#define NANDC_CMD_CS_SEL REG_BIT_FIELD(0x8, 16, 3)
++#define NANDC_CMD_EXT_ADDR REG_BIT_FIELD(0x8, 0, 16)
++
++#define NANDC_CMD_ADDRESS REG_BIT_FIELD(0xc, 0, 32)
++#define NANDC_CMD_END_ADDRESS REG_BIT_FIELD(0x10, 0, 32)
++
++#define NANDC_INT_STATUS REG_BIT_FIELD(0x14, 0, 32)
++#define NANDC_INT_STAT_CTLR_RDY REG_BIT_FIELD(0x14, 31, 1)
++#define NANDC_INT_STAT_FLASH_RDY REG_BIT_FIELD(0x14, 30, 1)
++#define NANDC_INT_STAT_CACHE_VALID REG_BIT_FIELD(0x14, 29, 1)
++#define NANDC_INT_STAT_SPARE_VALID REG_BIT_FIELD(0x14, 28, 1)
++#define NANDC_INT_STAT_ERASED REG_BIT_FIELD(0x14, 27, 1)
++#define NANDC_INT_STAT_PLANE_RDY REG_BIT_FIELD(0x14, 26, 1)
++#define NANDC_INT_STAT_FLASH_STATUS REG_BIT_FIELD(0x14, 0, 8)
++
++#define NANDC_CS_LOCK REG_BIT_FIELD(0x18, 31, 1)
++#define NANDC_CS_AUTO_CONFIG REG_BIT_FIELD(0x18, 30, 1)
++#define NANDC_CS_NAND_WP REG_BIT_FIELD(0x18, 29, 1)
++#define NANDC_CS_BLK0_WP REG_BIT_FIELD(0x18, 28, 1)
++#define NANDC_CS_SW_USING_CS(n) REG_BIT_FIELD(0x18, 8+(n), 1)
++#define NANDC_CS_MAP_SEL_CS(n) REG_BIT_FIELD(0x18, 0+(n), 1)
++
++#define NANDC_XOR_ADDR_BLK0_ONLY REG_BIT_FIELD(0x1c, 31, 1)
++#define NANDC_XOR_ADDR_CS(n) REG_BIT_FIELD(0x1c, 0+(n), 1)
++
++#define NANDC_LL_OP_RET_IDLE REG_BIT_FIELD(0x20, 31, 1)
++#define NANDC_LL_OP_CLE REG_BIT_FIELD(0x20, 19, 1)
++#define NANDC_LL_OP_ALE REG_BIT_FIELD(0x20, 18, 1)
++#define NANDC_LL_OP_WE REG_BIT_FIELD(0x20, 17, 1)
++#define NANDC_LL_OP_RE REG_BIT_FIELD(0x20, 16, 1)
++#define NANDC_LL_OP_DATA REG_BIT_FIELD(0x20, 0, 16)
++
++#define NANDC_MPLANE_ADDR_EXT REG_BIT_FIELD(0x24, 0, 16)
++#define NANDC_MPLANE_ADDR REG_BIT_FIELD(0x28, 0, 32)
++
++#define NANDC_ACC_CTRL_CS(n) REG_BIT_FIELD(0x50+((n)<<4), 0, 32)
++#define NANDC_ACC_CTRL_RD_ECC(n) REG_BIT_FIELD(0x50+((n)<<4), 31, 1)
++#define NANDC_ACC_CTRL_WR_ECC(n) REG_BIT_FIELD(0x50+((n)<<4), 30, 1)
++#define NANDC_ACC_CTRL_CE_CARE(n) REG_BIT_FIELD(0x50+((n)<<4), 29, 1)
++#define NANDC_ACC_CTRL_PGM_RDIN(n) REG_BIT_FIELD(0x50+((n)<<4), 28, 1)
++#define NANDC_ACC_CTRL_ERA_ECC_ERR(n) REG_BIT_FIELD(0x50+((n)<<4), 27, 1)
++#define NANDC_ACC_CTRL_PGM_PARTIAL(n) REG_BIT_FIELD(0x50+((n)<<4), 26, 1)
++#define NANDC_ACC_CTRL_WR_PREEMPT(n) REG_BIT_FIELD(0x50+((n)<<4), 25, 1)
++#define NANDC_ACC_CTRL_PG_HIT(n) REG_BIT_FIELD(0x50+((n)<<4), 24, 1)
++#define NANDC_ACC_CTRL_PREFETCH(n) REG_BIT_FIELD(0x50+((n)<<4), 23, 1)
++#define NANDC_ACC_CTRL_CACHE_MODE(n) REG_BIT_FIELD(0x50+((n)<<4), 22, 1)
++#define NANDC_ACC_CTRL_CACHE_LASTPG(n) REG_BIT_FIELD(0x50+((n)<<4), 21, 1)
++#define NANDC_ACC_CTRL_ECC_LEVEL(n) REG_BIT_FIELD(0x50+((n)<<4), 16, 5)
++#define NANDC_ACC_CTRL_SECTOR_1K(n) REG_BIT_FIELD(0x50+((n)<<4), 7, 1)
++#define NANDC_ACC_CTRL_SPARE_SIZE(n) REG_BIT_FIELD(0x50+((n)<<4), 0, 7)
++
++#define NANDC_CONFIG_CS(n) REG_BIT_FIELD(0x54+((n)<<4), 0, 32)
++#define NANDC_CONFIG_LOCK(n) REG_BIT_FIELD(0x54+((n)<<4), 31, 1)
++#define NANDC_CONFIG_BLK_SIZE(n) REG_BIT_FIELD(0x54+((n)<<4), 28, 3)
++#define NANDC_CONFIG_CHIP_SIZE(n) REG_BIT_FIELD(0x54+((n)<<4), 24, 4)
++#define NANDC_CONFIG_CHIP_WIDTH(n) REG_BIT_FIELD(0x54+((n)<<4), 23, 1)
++#define NANDC_CONFIG_PAGE_SIZE(n) REG_BIT_FIELD(0x54+((n)<<4), 20, 2)
++#define NANDC_CONFIG_FUL_ADDR_BYTES(n) REG_BIT_FIELD(0x54+((n)<<4), 16, 3)
++#define NANDC_CONFIG_COL_ADDR_BYTES(n) REG_BIT_FIELD(0x54+((n)<<4), 12, 3)
++#define NANDC_CONFIG_BLK_ADDR_BYTES(n) REG_BIT_FIELD(0x54+((n)<<4), 8, 3)
++
++#define NANDC_TIMING_1_CS(n) REG_BIT_FIELD(0x58+((n)<<4), 0, 32)
++#define NANDC_TIMING_2_CS(n) REG_BIT_FIELD(0x5c+((n)<<4), 0, 32)
++ /* Individual bits for Timing registers - TBD */
++
++#define NANDC_CORR_STAT_THRESH_CS(n) REG_BIT_FIELD(0xc0, 6*(n), 6)
++
++#define NANDC_BLK_WP_END_ADDR REG_BIT_FIELD(0xc8, 0, 32)
++
++#define NANDC_MPLANE_ERASE_CYC2_OPCODE REG_BIT_FIELD(0xcc, 24, 8)
++#define NANDC_MPLANE_READ_STAT_OPCODE REG_BIT_FIELD(0xcc, 16, 8)
++#define NANDC_MPLANE_PROG_ODD_OPCODE REG_BIT_FIELD(0xcc, 8, 8)
++#define NANDC_MPLANE_PROG_TRL_OPCODE REG_BIT_FIELD(0xcc, 0, 8)
++
++#define NANDC_MPLANE_PGCACHE_TRL_OPCODE REG_BIT_FIELD(0xd0, 24, 8)
++#define NANDC_MPLANE_READ_STAT2_OPCODE REG_BIT_FIELD(0xd0, 16, 8)
++#define NANDC_MPLANE_READ_EVEN_OPCODE REG_BIT_FIELD(0xd0, 8, 8)
++#define NANDC_MPLANE_READ_ODD__OPCODE REG_BIT_FIELD(0xd0, 0, 8)
++
++#define NANDC_MPLANE_CTRL_ERASE_CYC2_EN REG_BIT_FIELD(0xd4, 31, 1)
++#define NANDC_MPLANE_CTRL_RD_ADDR_SIZE REG_BIT_FIELD(0xd4, 30, 1)
++#define NANDC_MPLANE_CTRL_RD_CYC_ADDR REG_BIT_FIELD(0xd4, 29, 1)
++#define NANDC_MPLANE_CTRL_RD_COL_ADDR REG_BIT_FIELD(0xd4, 28, 1)
++
++#define NANDC_UNCORR_ERR_COUNT REG_BIT_FIELD(0xfc, 0, 32)
++
++#define NANDC_CORR_ERR_COUNT REG_BIT_FIELD(0x100, 0, 32)
++
++#define NANDC_READ_CORR_BIT_COUNT REG_BIT_FIELD(0x104, 0, 32)
++
++#define NANDC_BLOCK_LOCK_STATUS REG_BIT_FIELD(0x108, 0, 8)
++
++#define NANDC_ECC_CORR_ADDR_CS REG_BIT_FIELD(0x10c, 16, 3)
++#define NANDC_ECC_CORR_ADDR_EXT REG_BIT_FIELD(0x10c, 0, 16)
++
++#define NANDC_ECC_CORR_ADDR REG_BIT_FIELD(0x110, 0, 32)
++
++#define NANDC_ECC_UNC_ADDR_CS REG_BIT_FIELD(0x114, 16, 3)
++#define NANDC_ECC_UNC_ADDR_EXT REG_BIT_FIELD(0x114, 0, 16)
++
++#define NANDC_ECC_UNC_ADDR REG_BIT_FIELD(0x118, 0, 32)
++
++#define NANDC_READ_ADDR_CS REG_BIT_FIELD(0x11c, 16, 3)
++#define NANDC_READ_ADDR_EXT REG_BIT_FIELD(0x11c, 0, 16)
++#define NANDC_READ_ADDR REG_BIT_FIELD(0x120, 0, 32)
++
++#define NANDC_PROG_ADDR_CS REG_BIT_FIELD(0x124, 16, 3)
++#define NANDC_PROG_ADDR_EXT REG_BIT_FIELD(0x124, 0, 16)
++#define NANDC_PROG_ADDR REG_BIT_FIELD(0x128, 0, 32)
++
++#define NANDC_CPYBK_ADDR_CS REG_BIT_FIELD(0x12c, 16, 3)
++#define NANDC_CPYBK_ADDR_EXT REG_BIT_FIELD(0x12c, 0, 16)
++#define NANDC_CPYBK_ADDR REG_BIT_FIELD(0x130, 0, 32)
++
++#define NANDC_ERASE_ADDR_CS REG_BIT_FIELD(0x134, 16, 3)
++#define NANDC_ERASE_ADDR_EXT REG_BIT_FIELD(0x134, 0, 16)
++#define NANDC_ERASE_ADDR REG_BIT_FIELD(0x138, 0, 32)
++
++#define NANDC_INV_READ_ADDR_CS REG_BIT_FIELD(0x13c, 16, 3)
++#define NANDC_INV_READ_ADDR_EXT REG_BIT_FIELD(0x13c, 0, 16)
++#define NANDC_INV_READ_ADDR REG_BIT_FIELD(0x140, 0, 32)
++
++#define NANDC_INIT_STAT REG_BIT_FIELD(0x144, 0, 32)
++#define NANDC_INIT_ONFI_DONE REG_BIT_FIELD(0x144, 31, 1)
++#define NANDC_INIT_DEVID_DONE REG_BIT_FIELD(0x144, 30, 1)
++#define NANDC_INIT_SUCCESS REG_BIT_FIELD(0x144, 29, 1)
++#define NANDC_INIT_FAIL REG_BIT_FIELD(0x144, 28, 1)
++#define NANDC_INIT_BLANK REG_BIT_FIELD(0x144, 27, 1)
++#define NANDC_INIT_TIMEOUT REG_BIT_FIELD(0x144, 26, 1)
++#define NANDC_INIT_UNC_ERROR REG_BIT_FIELD(0x144, 25, 1)
++#define NANDC_INIT_CORR_ERROR REG_BIT_FIELD(0x144, 24, 1)
++#define NANDC_INIT_PARAM_RDY REG_BIT_FIELD(0x144, 23, 1)
++#define NANDC_INIT_AUTH_FAIL REG_BIT_FIELD(0x144, 22, 1)
++
++#define NANDC_ONFI_STAT REG_BIT_FIELD(0x148, 0, 32)
++#define NANDC_ONFI_DEBUG REG_BIT_FIELD(0x148, 28, 4)
++#define NANDC_ONFI_PRESENT REG_BIT_FIELD(0x148, 27, 1)
++#define NANDC_ONFI_BADID_PG2 REG_BIT_FIELD(0x148, 5, 1)
++#define NANDC_ONFI_BADID_PG1 REG_BIT_FIELD(0x148, 4, 1)
++#define NANDC_ONFI_BADID_PG0 REG_BIT_FIELD(0x148, 3, 1)
++#define NANDC_ONFI_BADCRC_PG2 REG_BIT_FIELD(0x148, 2, 1)
++#define NANDC_ONFI_BADCRC_PG1 REG_BIT_FIELD(0x148, 1, 1)
++#define NANDC_ONFI_BADCRC_PG0 REG_BIT_FIELD(0x148, 0, 1)
++
++#define NANDC_ONFI_DEBUG_DATA REG_BIT_FIELD(0x14c, 0, 32)
++
++#define NANDC_SEMAPHORE REG_BIT_FIELD(0x150, 0, 8)
++
++#define NANDC_DEVID_BYTE(b) REG_BIT_FIELD(0x194+((b)&0x4), \
++ 24-(((b)&3)<<3), 8)
++
++#define NANDC_LL_RDDATA REG_BIT_FIELD(0x19c, 0, 16)
++
++#define NANDC_INT_N_REG(n) REG_BIT_FIELD(0xf00|((n)<<2), 0, 1)
++#define NANDC_INT_DIREC_READ_MISS REG_BIT_FIELD(0xf00, 0, 1)
++#define NANDC_INT_ERASE_DONE REG_BIT_FIELD(0xf04, 0, 1)
++#define NANDC_INT_CPYBK_DONE REG_BIT_FIELD(0xf08, 0, 1)
++#define NANDC_INT_PROGRAM_DONE REG_BIT_FIELD(0xf0c, 0, 1)
++#define NANDC_INT_CONTROLLER_RDY REG_BIT_FIELD(0xf10, 0, 1)
++#define NANDC_INT_RDBSY_RDY REG_BIT_FIELD(0xf14, 0, 1)
++#define NANDC_INT_ECC_UNCORRECTABLE REG_BIT_FIELD(0xf18, 0, 1)
++#define NANDC_INT_ECC_CORRECTABLE REG_BIT_FIELD(0xf1c, 0, 1)
++
++/*
++ * Following registers are treated as contigous IO memory, offset is from
++ * <reg_base>, and the data is in big-endian byte order
++ */
++#define NANDC_SPARE_AREA_READ_OFF 0x200
++#define NANDC_SPARE_AREA_WRITE_OFF 0x280
++#define NANDC_CACHE_OFF 0x400
++#define NANDC_CACHE_SIZE (128*4)
++
++struct bcmnand_areg_field {
++ unsigned int reg;
++ unsigned int pos;
++ unsigned int width;
++};
++
++/*
++ * Following are IDM (a.k.a. Slave Wrapper) registers are off <idm_base>:
++ */
++#define IDMREG_BIT_FIELD(r, p, w) ((struct bcmnand_areg_field){(r), (p), (w)})
++
++#define NANDC_IDM_AXI_BIG_ENDIAN IDMREG_BIT_FIELD(0x408, 28, 1)
++#define NANDC_IDM_APB_LITTLE_ENDIAN IDMREG_BIT_FIELD(0x408, 24, 1)
++#define NANDC_IDM_TM IDMREG_BIT_FIELD(0x408, 16, 5)
++#define NANDC_IDM_IRQ_CORRECABLE_EN IDMREG_BIT_FIELD(0x408, 9, 1)
++#define NANDC_IDM_IRQ_UNCORRECABLE_EN IDMREG_BIT_FIELD(0x408, 8, 1)
++#define NANDC_IDM_IRQ_RDYBSY_RDY_EN IDMREG_BIT_FIELD(0x408, 7, 1)
++#define NANDC_IDM_IRQ_CONTROLLER_RDY_EN IDMREG_BIT_FIELD(0x408, 6, 1)
++#define NANDC_IDM_IRQ_PRPOGRAM_COMP_EN IDMREG_BIT_FIELD(0x408, 5, 1)
++#define NANDC_IDM_IRQ_COPYBK_COMP_EN IDMREG_BIT_FIELD(0x408, 4, 1)
++#define NANDC_IDM_IRQ_ERASE_COMP_EN IDMREG_BIT_FIELD(0x408, 3, 1)
++#define NANDC_IDM_IRQ_READ_MISS_EN IDMREG_BIT_FIELD(0x408, 2, 1)
++#define NANDC_IDM_IRQ_N_EN(n) IDMREG_BIT_FIELD(0x408, 2+(n), 1)
++
++#define NANDC_IDM_CLOCK_EN IDMREG_BIT_FIELD(0x408, 0, 1)
++
++#define NANDC_IDM_IO_ECC_CORR IDMREG_BIT_FIELD(0x500, 3, 1)
++#define NANDC_IDM_IO_ECC_UNCORR IDMREG_BIT_FIELD(0x500, 2, 1)
++#define NANDC_IDM_IO_RDYBSY IDMREG_BIT_FIELD(0x500, 1, 1)
++#define NANDC_IDM_IO_CTRL_RDY IDMREG_BIT_FIELD(0x500, 0, 1)
++
++#define NANDC_IDM_RESET IDMREG_BIT_FIELD(0x800, 0, 1)
++ /* Remaining IDM registers do not seem to be useful, skipped */
++
++/*
++ * NAND Controller has its own command opcodes
++ * different from opcodes sent to the actual flash chip
++ */
++#define NANDC_CMD_OPCODE_NULL 0
++#define NANDC_CMD_OPCODE_PAGE_READ 1
++#define NANDC_CMD_OPCODE_SPARE_READ 2
++#define NANDC_CMD_OPCODE_STATUS_READ 3
++#define NANDC_CMD_OPCODE_PAGE_PROG 4
++#define NANDC_CMD_OPCODE_SPARE_PROG 5
++#define NANDC_CMD_OPCODE_DEVID_READ 7
++#define NANDC_CMD_OPCODE_BLOCK_ERASE 8
++#define NANDC_CMD_OPCODE_FLASH_RESET 9
++
++/*
++ * NAND Controller hardware ECC data size
++ *
++ * The following table contains the number of bytes needed for
++ * each of the ECC levels, per "sector", which is either 512 or 1024 bytes.
++ * The actual layout is as follows:
++ * The entire spare area is equally divided into as many sections as there
++ * are sectors per page, and the ECC data is located at the end of each
++ * of these sections.
++ * For example, given a 2K per page and 64 bytes spare device, configured for
++ * sector size 1k and ECC level of 4, the spare area will be divided into 2
++ * sections 32 bytes each, and the last 14 bytes of 32 in each section will
++ * be filled with ECC data.
++ * Note: the name of the algorythm and the number of error bits it can correct
++ * is of no consequence to this driver, therefore omitted.
++ */
++struct bcmnand_ecc_size_s {
++ unsigned char sector_size_shift;
++ unsigned char ecc_level;
++ unsigned char ecc_bytes_per_sec;
++ unsigned char reserved;
++};
++
++static const struct bcmnand_ecc_size_s bcmnand_ecc_sizes[] = {
++ { 9, 0, 0 },
++ { 10, 0, 0 },
++ { 9, 1, 2 },
++ { 10, 1, 4 },
++ { 9, 2, 4 },
++ { 10, 2, 7 },
++ { 9, 3, 6 },
++ { 10, 3, 11 },
++ { 9, 4, 7 },
++ { 10, 4, 14 },
++ { 9, 5, 9 },
++ { 10, 5, 18 },
++ { 9, 6, 11 },
++ { 10, 6, 21 },
++ { 9, 7, 13 },
++ { 10, 7, 25 },
++ { 9, 8, 14 },
++ { 10, 8, 28 },
++
++ { 9, 9, 16 },
++ { 9, 10, 18 },
++ { 9, 11, 20 },
++ { 9, 12, 21 },
++
++ { 10, 9, 32 },
++ { 10, 10, 35 },
++ { 10, 11, 39 },
++ { 10, 12, 42 },
++};
++
++/*
++ * Populate the various fields that depend on how
++ * the hardware ECC data is located in the spare area
++ *
++ * For this controiller, it is easier to fill-in these
++ * structures at run time.
++ *
++ * The bad-block marker is assumed to occupy one byte
++ * at chip->badblockpos, which must be in the first
++ * sector of the spare area, namely it is either
++ * at offset 0 or 5.
++ * Some chips use both for manufacturer's bad block
++ * markers, but we ingore that issue here, and assume only
++ * one byte is used as bad-block marker always.
++ */
++static int bcmnand_hw_ecc_layout(struct bcmnand_ctrl *ctrl)
++{
++ struct nand_ecclayout *layout;
++ struct device *dev = &ctrl->core->dev;
++ unsigned int i, j, k;
++ unsigned int ecc_per_sec, oob_per_sec;
++ unsigned int bbm_pos = ctrl->nand.badblockpos;
++
++ /* Caclculate spare area per sector size */
++ oob_per_sec = ctrl->mtd.oobsize >> ctrl->sec_per_page_shift;
++
++ /* Try to calculate the amount of ECC bytes per sector with a formula */
++ if (ctrl->sector_size_shift == 9)
++ ecc_per_sec = ((ctrl->ecc_level * 14) + 7) >> 3;
++ else if (ctrl->sector_size_shift == 10)
++ ecc_per_sec = ((ctrl->ecc_level * 14) + 3) >> 2;
++ else
++ ecc_per_sec = oob_per_sec + 1; /* cause an error if not in table */
++
++ /* Now find out the answer according to the table */
++ for (i = 0; i < ARRAY_SIZE(bcmnand_ecc_sizes); i++) {
++ if (bcmnand_ecc_sizes[i].ecc_level == ctrl->ecc_level &&
++ bcmnand_ecc_sizes[i].sector_size_shift ==
++ ctrl->sector_size_shift) {
++ break;
++ }
++ }
++
++ /* Table match overrides formula */
++ if (bcmnand_ecc_sizes[i].ecc_level == ctrl->ecc_level &&
++ bcmnand_ecc_sizes[i].sector_size_shift == ctrl->sector_size_shift)
++ ecc_per_sec = bcmnand_ecc_sizes[i].ecc_bytes_per_sec;
++
++ /* Return an error if calculated ECC leaves no room for OOB */
++ if ((ctrl->sec_per_page_shift != 0 && ecc_per_sec >= oob_per_sec) ||
++ (ctrl->sec_per_page_shift == 0 && ecc_per_sec >= (oob_per_sec - 1))) {
++ dev_err(dev, "ECC level %d too high, leaves no room for OOB data\n",
++ ctrl->ecc_level);
++ return -EINVAL;
++ }
++
++ /* Fill in the needed fields */
++ ctrl->nand.ecc.size = ctrl->mtd.writesize >> ctrl->sec_per_page_shift;
++ ctrl->nand.ecc.bytes = ecc_per_sec;
++ ctrl->nand.ecc.steps = 1 << ctrl->sec_per_page_shift;
++ ctrl->nand.ecc.total = ecc_per_sec << ctrl->sec_per_page_shift;
++ ctrl->nand.ecc.strength = ctrl->ecc_level;
++
++ /* Build an ecc layout data structure */
++ layout = &ctrl->ecclayout;
++ memset(layout, 0, sizeof(*layout));
++
++ /* Total number of bytes used by HW ECC */
++ layout->eccbytes = ecc_per_sec << ctrl->sec_per_page_shift;
++
++ /* Location for each of the HW ECC bytes */
++ for (i = j = 0, k = 1;
++ i < ARRAY_SIZE(layout->eccpos) && i < layout->eccbytes;
++ i++, j++) {
++ /* switch sector # */
++ if (j == ecc_per_sec) {
++ j = 0;
++ k++;
++ }
++ /* save position of each HW-generated ECC byte */
++ layout->eccpos[i] = (oob_per_sec * k) - ecc_per_sec + j;
++
++ /* Check that HW ECC does not overlap bad-block marker */
++ if (bbm_pos == layout->eccpos[i]) {
++ dev_err(dev, "ECC level %d too high, HW ECC collides with bad-block marker position\n",
++ ctrl->ecc_level);
++ return -EINVAL;
++ }
++ }
++
++ /* Location of all user-available OOB byte-ranges */
++ for (i = 0; i < ARRAY_SIZE(layout->oobfree); i++) {
++ struct nand_oobfree *oobfree = &layout->oobfree[i];
++
++ if (i >= (1 << ctrl->sec_per_page_shift))
++ break;
++ oobfree->offset = oob_per_sec * i;
++ oobfree->length = oob_per_sec - ecc_per_sec;
++
++ /* Bad-block marker must be in the first sector spare area */
++ if (WARN_ON(bbm_pos >= (oobfree->offset + oobfree->length)))
++ return -EINVAL;
++
++ if (i != 0)
++ continue;
++
++ /* Remove bad-block marker from available byte range */
++ if (bbm_pos == oobfree->offset) {
++ oobfree->offset += 1;
++ oobfree->length -= 1;
++ } else if (bbm_pos == (oobfree->offset + oobfree->length - 1)) {
++ oobfree->length -= 1;
++ } else {
++ layout->oobfree[i + 1].offset = bbm_pos + 1;
++ layout->oobfree[i + 1].length =
++ oobfree->length - bbm_pos - 1;
++ oobfree->length = bbm_pos;
++ i++;
++ }
++ }
++
++ layout->oobavail = ((oob_per_sec - ecc_per_sec)
++ << ctrl->sec_per_page_shift) - 1;
++
++ ctrl->mtd.oobavail = layout->oobavail;
++ ctrl->nand.ecc.layout = layout;
++
++ /* Output layout for debugging */
++ dev_dbg(dev, "Spare area=%d eccbytes %d, ecc bytes located at:\n",
++ ctrl->mtd.oobsize, layout->eccbytes);
++ for (i = j = 0;
++ i < ARRAY_SIZE(layout->eccpos) && i < layout->eccbytes; i++)
++ pr_debug(" %d", layout->eccpos[i]);
++ pr_debug("\n");
++
++ dev_dbg(dev, "Available %d bytes at (off,len):\n", layout->oobavail);
++ for (i = 0; i < ARRAY_SIZE(layout->oobfree); i++)
++ pr_debug("(%d,%d) ", layout->oobfree[i].offset,
++ layout->oobfree[i].length);
++ pr_debug("\n");
++
++ return 0;
++}
++
++/*
++ * Register bit-field manipulation routines
++ */
++
++static inline unsigned int bcmnand_reg_read(struct bcmnand_ctrl *ctrl,
++ struct bcmnand_reg_field rbf)
++{
++ u32 val;
++
++ val = bcma_read32(ctrl->core, rbf.reg);
++ val >>= rbf.pos;
++ val &= (1 << rbf.width) - 1;
++
++ return val;
++}
++
++static inline void bcmnand_reg_write(struct bcmnand_ctrl *ctrl,
++ struct bcmnand_reg_field rbf,
++ unsigned newval)
++{
++ u32 val, msk;
++
++ msk = (1 << rbf.width) - 1;
++ msk <<= rbf.pos;
++ newval <<= rbf.pos;
++ newval &= msk;
++
++ val = bcma_read32(ctrl->core, rbf.reg);
++ val &= ~msk;
++ val |= newval;
++ bcma_write32(ctrl->core, rbf.reg, val);
++}
++
++static inline unsigned int bcmnand_reg_aread(struct bcmnand_ctrl *ctrl,
++ struct bcmnand_areg_field rbf)
++{
++ u32 val;
++
++ val = bcma_aread32(ctrl->core, rbf.reg);
++ val >>= rbf.pos;
++ val &= (1 << rbf.width) - 1;
++
++ return val;
++}
++
++static inline void bcmnand_reg_awrite(struct bcmnand_ctrl *ctrl,
++ struct bcmnand_areg_field rbf,
++ unsigned int newval)
++{
++ u32 val, msk;
++
++ msk = (1 << rbf.width) - 1;
++ msk <<= rbf.pos;
++ newval <<= rbf.pos;
++ newval &= msk;
++
++ val = bcma_aread32(ctrl->core, rbf.reg);
++ val &= ~msk;
++ val |= newval;
++ bcma_awrite32(ctrl->core, rbf.reg, val);
++}
++
++/*
++ * NAND Interface - dev_ready
++ *
++ * Return 1 iff device is ready, 0 otherwise
++ */
++static int bcmnand_dev_ready(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct bcmnand_ctrl *ctrl = chip->priv;
++
++ return bcmnand_reg_aread(ctrl, NANDC_IDM_IO_CTRL_RDY);
++}
++
++/*
++ * Interrupt service routines
++ */
++static irqreturn_t bcmnand_isr(int irq, void *dev_id)
++{
++ struct bcmnand_ctrl *ctrl = dev_id;
++ int irq_off;
++
++ irq_off = irq - ctrl->core->irq;
++ WARN_ON(irq_off < 0 || irq_off >= NANDC_IRQ_NUM);
++
++ if (!bcmnand_reg_read(ctrl, NANDC_INT_N_REG(irq_off)))
++ return IRQ_NONE;
++
++ /* Acknowledge interrupt */
++ bcmnand_reg_write(ctrl, NANDC_INT_N_REG(irq_off), 1);
++
++ /* Wake up task */
++ complete(&ctrl->op_completion);
++
++ return IRQ_HANDLED;
++}
++
++static int bcmnand_wait_interrupt(struct bcmnand_ctrl *ctrl,
++ unsigned int irq_off,
++ unsigned int timeout_usec)
++{
++ long timeout_jiffies;
++ int ret = 0;
++
++ reinit_completion(&ctrl->op_completion);
++
++ /* Acknowledge interrupt */
++ bcmnand_reg_write(ctrl, NANDC_INT_N_REG(irq_off), 1);
++
++ /* Enable IRQ to wait on */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_IRQ_N_EN(irq_off), 1);
++
++ timeout_jiffies = 1 + usecs_to_jiffies(timeout_usec);
++
++ if (irq_off != NANDC_IRQ_CONTROLLER_RDY ||
++ 0 == bcmnand_reg_aread(ctrl, NANDC_IDM_IO_CTRL_RDY)) {
++
++ timeout_jiffies = wait_for_completion_timeout(
++ &ctrl->op_completion, timeout_jiffies);
++
++ if (timeout_jiffies < 0)
++ ret = timeout_jiffies;
++ if (timeout_jiffies == 0)
++ ret = -ETIME;
++ }
++
++ /* Disable IRQ, we're done waiting */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_IRQ_N_EN(irq_off), 0);
++
++ if (bcmnand_reg_aread(ctrl, NANDC_IDM_IO_CTRL_RDY))
++ ret = 0;
++
++ return ret;
++}
++
++/*
++ * wait for command completion
++ */
++static int bcmnand_wait_cmd(struct bcmnand_ctrl *ctrl, unsigned int timeout_usec)
++{
++ unsigned int retries;
++
++ if (bcmnand_reg_read(ctrl, NANDC_INT_STAT_CTLR_RDY))
++ return 0;
++
++ /* If the timeout is long, wait for interrupt */
++ if (timeout_usec >= jiffies_to_usecs(1) >> 4)
++ return bcmnand_wait_interrupt(
++ ctrl, NANDC_IRQ_CONTROLLER_RDY, timeout_usec);
++
++ /* Wait for completion of the prior command */
++ retries = (timeout_usec >> 3) + 1;
++
++ while (retries-- &&
++ 0 == bcmnand_reg_read(ctrl, NANDC_INT_STAT_CTLR_RDY)) {
++ cpu_relax();
++ udelay(6);
++ }
++
++ if (retries == 0)
++ return -ETIME;
++
++ return 0;
++}
++
++
++/*
++ * NAND Interface - waitfunc
++ */
++static int bcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *chip)
++{
++ struct bcmnand_ctrl *ctrl = chip->priv;
++ unsigned int to;
++ int ret;
++
++ /* figure out timeout based on what command is on */
++ switch (ctrl->last_cmd) {
++ default:
++ case NAND_CMD_ERASE1:
++ case NAND_CMD_ERASE2:
++ to = 1 << 16;
++ break;
++ case NAND_CMD_STATUS:
++ case NAND_CMD_RESET:
++ to = 256;
++ break;
++ case NAND_CMD_READID:
++ to = 1024;
++ break;
++ case NAND_CMD_READ1:
++ case NAND_CMD_READ0:
++ to = 2048;
++ break;
++ case NAND_CMD_PAGEPROG:
++ to = 4096;
++ break;
++ case NAND_CMD_READOOB:
++ to = 512;
++ break;
++ }
++
++ /* deliver deferred error code if any */
++ ret = ctrl->cmd_ret;
++ if (ret < 0)
++ ctrl->cmd_ret = 0;
++ else
++ ret = bcmnand_wait_cmd(ctrl, to);
++
++ /* Timeout */
++ if (ret < 0)
++ return NAND_STATUS_FAIL;
++
++ ret = bcmnand_reg_read(ctrl, NANDC_INT_STAT_FLASH_STATUS);
++
++ return ret;
++}
++
++/*
++ * NAND Interface - read_oob
++ */
++static int bcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ struct bcmnand_ctrl *ctrl = chip->priv;
++ unsigned int n = ctrl->chip_num;
++ void __iomem *ctrl_spare;
++ unsigned int spare_per_sec, sector;
++ u64 nand_addr;
++
++ ctrl_spare = ctrl->core->io_addr + NANDC_SPARE_AREA_READ_OFF;
++
++ /* Set the page address for the following commands */
++ nand_addr = ((u64)page << chip->page_shift);
++ bcmnand_reg_write(ctrl, NANDC_CMD_EXT_ADDR, nand_addr >> 32);
++
++ spare_per_sec = mtd->oobsize >> ctrl->sec_per_page_shift;
++
++ /* Disable ECC validation for spare area reads */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_RD_ECC(n), 0);
++
++ /* Loop all sectors in page */
++ for (sector = 0; sector < (1<<ctrl->sec_per_page_shift); sector++) {
++ unsigned int col;
++
++ col = (sector << ctrl->sector_size_shift);
++
++ /* Issue command to read partial page */
++ bcmnand_reg_write(ctrl, NANDC_CMD_ADDRESS, nand_addr + col);
++
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_SPARE_READ);
++
++ /* Wait for the command to complete */
++ if (bcmnand_wait_cmd(ctrl, (sector == 0) ? 10000 : 100))
++ return -EIO;
++
++ if (!bcmnand_reg_read(ctrl, NANDC_INT_STAT_SPARE_VALID))
++ return -EIO;
++
++ /* Set controller to Little Endian mode for copying */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 1);
++
++ memcpy(chip->oob_poi + sector * spare_per_sec,
++ ctrl_spare, spare_per_sec);
++
++ /* Return to Big Endian mode for commands etc */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 0);
++ }
++
++ return 0;
++}
++
++/*
++ * NAND Interface - write_oob
++ */
++static int bcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ struct bcmnand_ctrl *ctrl = chip->priv;
++ unsigned int n = ctrl->chip_num;
++ void __iomem *ctrl_spare;
++ unsigned int spare_per_sec, sector, num_sec;
++ u64 nand_addr;
++ int to, status = 0;
++
++ ctrl_spare = ctrl->core->io_addr + NANDC_SPARE_AREA_WRITE_OFF;
++
++ /* Disable ECC generation for spare area writes */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_WR_ECC(n), 0);
++
++ spare_per_sec = mtd->oobsize >> ctrl->sec_per_page_shift;
++
++ /* Set the page address for the following commands */
++ nand_addr = ((u64)page << chip->page_shift);
++ bcmnand_reg_write(ctrl, NANDC_CMD_EXT_ADDR, nand_addr >> 32);
++
++ /* Must allow partial programming to change spare area only */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_PGM_PARTIAL(n), 1);
++
++ num_sec = 1 << ctrl->sec_per_page_shift;
++ /* Loop all sectors in page */
++ for (sector = 0; sector < num_sec; sector++) {
++ unsigned int col;
++
++ /* Spare area accessed by the data sector offset */
++ col = (sector << ctrl->sector_size_shift);
++
++ bcmnand_reg_write(ctrl, NANDC_CMD_ADDRESS, nand_addr + col);
++
++ /* Set controller to Little Endian mode for copying */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 1);
++
++ memcpy(ctrl_spare, chip->oob_poi + sector * spare_per_sec,
++ spare_per_sec);
++
++ /* Return to Big Endian mode for commands etc */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 0);
++
++ /* Push spare bytes into internal buffer, last goes to flash */
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_SPARE_PROG);
++
++ if (sector == (num_sec - 1))
++ to = 1 << 16;
++ else
++ to = 1 << 10;
++
++ if (bcmnand_wait_cmd(ctrl, to))
++ return -EIO;
++ }
++
++ /* Restore partial programming inhibition */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_PGM_PARTIAL(n), 0);
++
++ status = bcmnand_waitfunc(mtd, chip);
++ return status & NAND_STATUS_FAIL ? -EIO : 0;
++}
++
++/*
++ * verify that a buffer is all erased
++ */
++static bool bcmnand_buf_erased(const void *buf, unsigned int len)
++{
++ unsigned int i;
++ const u32 *p = buf;
++
++ for (i = 0; i < (len >> 2); i++) {
++ if (p[i] != 0xffffffff)
++ return false;
++ }
++ return true;
++}
++
++/*
++ * read a page, with or without ECC checking
++ */
++static int bcmnand_read_page_do(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int page, bool ecc)
++{
++ struct bcmnand_ctrl *ctrl = chip->priv;
++ unsigned int n = ctrl->chip_num;
++ void __iomem *ctrl_cache;
++ void __iomem *ctrl_spare;
++ unsigned int data_bytes;
++ unsigned int spare_per_sec;
++ unsigned int sector, to = 1 << 16;
++ u32 err_soft_reg, err_hard_reg;
++ unsigned int hard_err_count = 0;
++ int ret;
++ u64 nand_addr;
++
++ ctrl_cache = ctrl->core->io_addr + NANDC_CACHE_OFF;
++ ctrl_spare = ctrl->core->io_addr + NANDC_SPARE_AREA_READ_OFF;
++
++ /* Reset ECC error stats */
++ err_hard_reg = bcmnand_reg_read(ctrl, NANDC_UNCORR_ERR_COUNT);
++ err_soft_reg = bcmnand_reg_read(ctrl, NANDC_READ_CORR_BIT_COUNT);
++
++ spare_per_sec = mtd->oobsize >> ctrl->sec_per_page_shift;
++
++ /* Set the page address for the following commands */
++ nand_addr = ((u64)page << chip->page_shift);
++ bcmnand_reg_write(ctrl, NANDC_CMD_EXT_ADDR, nand_addr >> 32);
++
++ /* Enable ECC validation for ecc page reads */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_RD_ECC(n), ecc);
++
++ /* Loop all sectors in page */
++ for (sector = 0; sector < (1 << ctrl->sec_per_page_shift); sector++) {
++ data_bytes = 0;
++
++ /* Copy partial sectors sized by cache reg */
++ while (data_bytes < (1<<ctrl->sector_size_shift)) {
++ unsigned int col;
++
++ col = data_bytes + (sector << ctrl->sector_size_shift);
++
++ bcmnand_reg_write(ctrl, NANDC_CMD_ADDRESS,
++ nand_addr + col);
++
++ /* Issue command to read partial page */
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_PAGE_READ);
++
++ /* Wait for the command to complete */
++ ret = bcmnand_wait_cmd(ctrl, to);
++ if (ret < 0)
++ return ret;
++
++ /* Set controller to Little Endian mode for copying */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 1);
++
++ if (data_bytes == 0) {
++ memcpy(chip->oob_poi + sector * spare_per_sec,
++ ctrl_spare, spare_per_sec);
++ }
++
++ memcpy(buf + col, ctrl_cache, NANDC_CACHE_SIZE);
++ data_bytes += NANDC_CACHE_SIZE;
++
++ /* Return to Big Endian mode for commands etc */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 0);
++
++ /* Next iterations should go fast */
++ to = 1 << 10;
++
++ /* capture hard errors for each partial */
++ if (err_hard_reg != bcmnand_reg_read(ctrl, NANDC_UNCORR_ERR_COUNT)) {
++ int era = bcmnand_reg_read(ctrl, NANDC_INT_STAT_ERASED);
++
++ if (!era &&
++ !bcmnand_buf_erased(buf + col, NANDC_CACHE_SIZE))
++ hard_err_count++;
++
++ err_hard_reg = bcmnand_reg_read(ctrl,
++ NANDC_UNCORR_ERR_COUNT);
++ }
++ }
++ }
++
++ if (!ecc)
++ return 0;
++
++ /* Report hard ECC errors */
++ if (hard_err_count)
++ mtd->ecc_stats.failed++;
++
++ /* Get ECC soft error stats */
++ mtd->ecc_stats.corrected += err_soft_reg -
++ bcmnand_reg_read(ctrl, NANDC_READ_CORR_BIT_COUNT);
++
++ return 0;
++}
++
++/*
++ * NAND Interface - read_page_ecc
++ */
++static int bcmnand_read_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ return bcmnand_read_page_do(mtd, chip, buf, page, true);
++}
++
++/*
++ * NAND Interface - read_page_raw
++ */
++static int bcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ return bcmnand_read_page_do(mtd, chip, buf, page, true);
++}
++
++/*
++ * do page write, with or without ECC generation enabled
++ */
++static int bcmnand_write_page_do(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, bool ecc)
++{
++ struct bcmnand_ctrl *ctrl = chip->priv;
++ unsigned int n = ctrl->chip_num;
++ void __iomem *ctrl_cache;
++ void __iomem *ctrl_spare;
++ unsigned int spare_per_sec, sector, num_sec;
++ unsigned int data_bytes, spare_bytes;
++ int i, to;
++ uint8_t *tmp_poi;
++ u32 nand_addr;
++
++ ctrl_cache = ctrl->core->io_addr + NANDC_CACHE_OFF;
++ ctrl_spare = ctrl->core->io_addr + NANDC_SPARE_AREA_WRITE_OFF;
++
++ /* Get start-of-page address */
++ nand_addr = bcmnand_reg_read(ctrl, NANDC_CMD_ADDRESS);
++
++ tmp_poi = kmalloc(mtd->oobsize, GFP_KERNEL);
++ if (!tmp_poi)
++ return -ENOMEM;
++
++ /* Retreive pre-existing OOB values */
++ memcpy(tmp_poi, chip->oob_poi, mtd->oobsize);
++ ctrl->cmd_ret = bcmnand_read_oob(mtd, chip,
++ nand_addr >> chip->page_shift);
++ if (ctrl->cmd_ret < 0) {
++ kfree(tmp_poi);
++ return ctrl->cmd_ret;
++ }
++
++ /* Apply new OOB data bytes just like they would end up on the chip */
++ for (i = 0; i < mtd->oobsize; i++)
++ chip->oob_poi[i] &= tmp_poi[i];
++ kfree(tmp_poi);
++
++ spare_per_sec = mtd->oobsize >> ctrl->sec_per_page_shift;
++
++ /* Enable ECC generation for ecc page write, if requested */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_WR_ECC(n), ecc);
++
++ spare_bytes = 0;
++ num_sec = 1 << ctrl->sec_per_page_shift;
++
++ /* Loop all sectors in page */
++ for (sector = 0; sector < num_sec; sector++) {
++ data_bytes = 0;
++
++ /* Copy partial sectors sized by cache reg */
++ while (data_bytes < (1<<ctrl->sector_size_shift)) {
++ unsigned int col;
++
++ col = data_bytes +
++ (sector << ctrl->sector_size_shift);
++
++ /* Set address of 512-byte sub-page */
++ bcmnand_reg_write(ctrl, NANDC_CMD_ADDRESS,
++ nand_addr + col);
++
++ /* Set controller to Little Endian mode for copying */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN,
++ 1);
++
++ /* Set spare area is written at each sector start */
++ if (data_bytes == 0) {
++ memcpy(ctrl_spare,
++ chip->oob_poi + spare_bytes,
++ spare_per_sec);
++ spare_bytes += spare_per_sec;
++ }
++
++ /* Copy sub-page data */
++ memcpy(ctrl_cache, buf + col, NANDC_CACHE_SIZE);
++ data_bytes += NANDC_CACHE_SIZE;
++
++ /* Return to Big Endian mode for commands etc */
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 0);
++
++ /* Push data into internal cache */
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_PAGE_PROG);
++
++ /* Wait for the command to complete */
++ if (sector == (num_sec - 1))
++ to = 1 << 16;
++ else
++ to = 1 << 10;
++ ctrl->cmd_ret = bcmnand_wait_cmd(ctrl, to);
++ if (ctrl->cmd_ret < 0)
++ return ctrl->cmd_ret;
++ }
++ }
++ return 0;
++}
++
++/*
++ * NAND Interface = write_page_ecc
++ */
++static int bcmnand_write_page_ecc(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int oob_required)
++{
++ return bcmnand_write_page_do(mtd, chip, buf, true);
++}
++
++/*
++ * NAND Interface = write_page_raw
++ */
++static int bcmnand_write_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int oob_required)
++{
++ return bcmnand_write_page_do(mtd, chip, buf, false);
++}
++
++/*
++ * MTD Interface - read_byte
++ *
++ * This function emulates simple controllers behavior
++ * for just a few relevant commands
++ */
++static uint8_t bcmnand_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd->priv;
++ struct bcmnand_ctrl *ctrl = nand->priv;
++ struct device *dev = &ctrl->core->dev;
++ uint8_t b = ~0;
++
++ switch (ctrl->last_cmd) {
++ case NAND_CMD_READID:
++ if (ctrl->id_byte_index < 8) {
++ b = bcmnand_reg_read(ctrl, NANDC_DEVID_BYTE(
++ ctrl->id_byte_index));
++ ctrl->id_byte_index++;
++ }
++ break;
++ case NAND_CMD_READOOB:
++ if (ctrl->oob_index < mtd->oobsize)
++ b = nand->oob_poi[ctrl->oob_index++];
++ break;
++ case NAND_CMD_STATUS:
++ b = bcmnand_reg_read(ctrl, NANDC_INT_STAT_FLASH_STATUS);
++ break;
++ default:
++ dev_err(dev, "got unkown command: 0x%x in read_byte\n",
++ ctrl->last_cmd);
++ }
++ return b;
++}
++
++/*
++ * MTD Interface - read_word
++ *
++ * Can not be tested without x16 chip, but the SoC does not support x16 i/f.
++ */
++static u16 bcmnand_read_word(struct mtd_info *mtd)
++{
++ u16 w = ~0;
++
++ w = bcmnand_read_byte(mtd);
++ barrier();
++ w |= bcmnand_read_byte(mtd) << 8;
++
++ return w;
++}
++
++/*
++ * MTD Interface - select a chip from an array
++ */
++static void bcmnand_select_chip(struct mtd_info *mtd, int chip)
++{
++ struct nand_chip *nand = mtd->priv;
++ struct bcmnand_ctrl *ctrl = nand->priv;
++
++ ctrl->chip_num = chip;
++ bcmnand_reg_write(ctrl, NANDC_CMD_CS_SEL, chip);
++}
++
++/*
++ * NAND Interface - emulate low-level NAND commands
++ *
++ * Only a few low-level commands are really needed by generic NAND,
++ * and they do not call for CMD_LL operations the controller can support.
++ */
++static void bcmnand_cmdfunc(struct mtd_info *mtd, unsigned int command,
++ int column, int page_addr)
++{
++ struct nand_chip *nand = mtd->priv;
++ struct bcmnand_ctrl *ctrl = nand->priv;
++ struct device *dev = &ctrl->core->dev;
++ u64 nand_addr;
++ unsigned int to = 1;
++
++ ctrl->last_cmd = command;
++
++ /* Set address for some commands */
++ switch (command) {
++ case NAND_CMD_ERASE1:
++ column = 0;
++ /*FALLTHROUGH*/
++ case NAND_CMD_SEQIN:
++ case NAND_CMD_READ0:
++ case NAND_CMD_READ1:
++ WARN_ON(column >= mtd->writesize);
++ nand_addr = (u64) column |
++ ((u64)page_addr << nand->page_shift);
++ bcmnand_reg_write(ctrl, NANDC_CMD_EXT_ADDR, nand_addr >> 32);
++ bcmnand_reg_write(ctrl, NANDC_CMD_ADDRESS, nand_addr);
++ break;
++ case NAND_CMD_ERASE2:
++ case NAND_CMD_RESET:
++ case NAND_CMD_READID:
++ case NAND_CMD_READOOB:
++ case NAND_CMD_PAGEPROG:
++ default:
++ /* Do nothing, address not used */
++ break;
++ }
++
++ /* Issue appropriate command to controller */
++ switch (command) {
++ case NAND_CMD_SEQIN:
++ /* Only need to load command address, done */
++ return;
++
++ case NAND_CMD_RESET:
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_FLASH_RESET);
++ to = 1 << 8;
++ break;
++
++ case NAND_CMD_READID:
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_DEVID_READ);
++ ctrl->id_byte_index = 0;
++ to = 1 << 8;
++ break;
++
++ case NAND_CMD_READ0:
++ case NAND_CMD_READ1:
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_PAGE_READ);
++ to = 1 << 15;
++ break;
++ case NAND_CMD_STATUS:
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_STATUS_READ);
++ to = 1 << 8;
++ break;
++ case NAND_CMD_ERASE1:
++ return;
++
++ case NAND_CMD_ERASE2:
++ bcmnand_reg_write(ctrl, NANDC_CMD_START_OPCODE,
++ NANDC_CMD_OPCODE_BLOCK_ERASE);
++ to = 1 << 18;
++ break;
++
++ case NAND_CMD_PAGEPROG:
++ /* Cmd already set from write_page */
++ return;
++
++ case NAND_CMD_READOOB:
++ /* Emulate simple interface */
++ bcmnand_read_oob(mtd, nand, page_addr);
++ ctrl->oob_index = 0;
++ return;
++
++ default:
++ dev_err(dev, "got unkown command: 0x%x in cmdfunc\n",
++ ctrl->last_cmd);
++ }
++
++ /* Wait for command to complete */
++ ctrl->cmd_ret = bcmnand_wait_cmd(ctrl, to);
++
++}
++
++static int bcmnand_scan(struct mtd_info *mtd)
++{
++ struct nand_chip *nand = mtd->priv;
++ struct bcmnand_ctrl *ctrl = nand->priv;
++ struct device *dev = &ctrl->core->dev;
++ bool sector_1k = false;
++ unsigned int chip_num = 0;
++ int ecc_level = 0;
++ int ret;
++
++ ret = nand_scan_ident(mtd, NANDC_MAX_CHIPS, NULL);
++ if (ret)
++ return ret;
++
++ /* Get configuration from first chip */
++ sector_1k = bcmnand_reg_read(ctrl, NANDC_ACC_CTRL_SECTOR_1K(0));
++ ecc_level = bcmnand_reg_read(ctrl, NANDC_ACC_CTRL_ECC_LEVEL(0));
++ mtd->writesize_shift = nand->page_shift;
++
++ ctrl->ecc_level = ecc_level;
++ ctrl->sector_size_shift = sector_1k ? 10 : 9;
++
++ /* Configure spare area, tweak as needed */
++ do {
++ ctrl->sec_per_page_shift =
++ mtd->writesize_shift - ctrl->sector_size_shift;
++
++ /* will return -EINVAL if OOB space exhausted */
++ ret = bcmnand_hw_ecc_layout(ctrl);
++
++ /* First try to bump sector size to 1k, then decrease level */
++ if (ret && nand->page_shift > 9 && ctrl->sector_size_shift < 10)
++ ctrl->sector_size_shift = 10;
++ else if (ret)
++ ctrl->ecc_level--;
++
++ } while (ret && ctrl->ecc_level > 0);
++
++ if (WARN_ON(ctrl->ecc_level == 0))
++ return -ENOENT;
++
++ if ((ctrl->sector_size_shift > 9) != (sector_1k == 1)) {
++ dev_info(dev, "sector size adjusted to 1k\n");
++ sector_1k = 1;
++ }
++
++ if (ecc_level != ctrl->ecc_level) {
++ dev_info(dev, "ECC level adjusted from %u to %u\n",
++ ecc_level, ctrl->ecc_level);
++ ecc_level = ctrl->ecc_level;
++ }
++
++ /* handle the hardware chip config registers */
++ for (chip_num = 0; chip_num < nand->numchips; chip_num++) {
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_SECTOR_1K(chip_num),
++ sector_1k);
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_ECC_LEVEL(chip_num),
++ ecc_level);
++
++ /* Large pages: no partial page programming */
++ if (mtd->writesize > 512) {
++ bcmnand_reg_write(ctrl,
++ NANDC_ACC_CTRL_PGM_RDIN(chip_num), 0);
++ bcmnand_reg_write(ctrl,
++ NANDC_ACC_CTRL_PGM_PARTIAL(chip_num), 0);
++ }
++
++ /* Do not raise ECC error when reading erased pages */
++ /* This bit has only partial effect, driver needs to help */
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_ERA_ECC_ERR(chip_num),
++ 0);
++
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_PG_HIT(chip_num), 0);
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_PREFETCH(chip_num), 0);
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_CACHE_MODE(chip_num), 0);
++ bcmnand_reg_write(ctrl, NANDC_ACC_CTRL_CACHE_LASTPG(chip_num),
++ 0);
++
++ /* TBD: consolidate or at least verify the s/w and h/w geometries agree */
++ }
++
++ /* Allow writing on device */
++ if (!(nand->options & NAND_ROM))
++ bcmnand_reg_write(ctrl, NANDC_CS_NAND_WP, 0);
++
++ dev_dbg(dev, "layout.oobavail=%d\n", nand->ecc.layout->oobavail);
++
++ ret = nand_scan_tail(mtd);
++
++ if (nand->badblockbits == 0)
++ nand->badblockbits = 8;
++ if (WARN_ON((1 << nand->page_shift) != mtd->writesize))
++ return -EIO;
++
++ /* Spit out some key chip parameters as detected by nand_base */
++ dev_dbg(dev, "erasesize=%d writesize=%d oobsize=%d page_shift=%d badblockpos=%d badblockbits=%d\n",
++ mtd->erasesize, mtd->writesize, mtd->oobsize,
++ nand->page_shift, nand->badblockpos, nand->badblockbits);
++
++ return ret;
++}
++
++/*
++ * main intiailization function
++ */
++static int bcmnand_ctrl_init(struct bcmnand_ctrl *ctrl)
++{
++ unsigned int chip;
++ struct nand_chip *nand;
++ struct mtd_info *mtd;
++ struct device *dev = &ctrl->core->dev;
++ int ret;
++
++ /* Software variables init */
++ nand = &ctrl->nand;
++ mtd = &ctrl->mtd;
++
++ init_completion(&ctrl->op_completion);
++
++ mtd->priv = nand;
++ mtd->owner = THIS_MODULE;
++ mtd->name = KBUILD_MODNAME;
++
++ nand->priv = ctrl;
++
++ nand->chip_delay = 5; /* not used */
++ nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)~0L;
++
++ if (bcmnand_reg_read(ctrl, NANDC_CONFIG_CHIP_WIDTH(0)))
++ nand->options |= NAND_BUSWIDTH_16;
++ nand->options |= NAND_SKIP_BBTSCAN; /* Dont need BBTs */
++
++ nand->options |= NAND_NO_SUBPAGE_WRITE; /* Subpages unsupported */
++
++ nand->dev_ready = bcmnand_dev_ready;
++ nand->read_byte = bcmnand_read_byte;
++ nand->read_word = bcmnand_read_word;
++ nand->select_chip = bcmnand_select_chip;
++ nand->cmdfunc = bcmnand_cmdfunc;
++ nand->waitfunc = bcmnand_waitfunc;
++
++ nand->ecc.mode = NAND_ECC_HW;
++ nand->ecc.read_page_raw = bcmnand_read_page_raw;
++ nand->ecc.write_page_raw = bcmnand_write_page_raw;
++ nand->ecc.read_page = bcmnand_read_page_ecc;
++ nand->ecc.write_page = bcmnand_write_page_ecc;
++ nand->ecc.read_oob = bcmnand_read_oob;
++ nand->ecc.write_oob = bcmnand_write_oob;
++
++ /* Set AUTO_CNFIG bit - try to auto-detect chips */
++ bcmnand_reg_write(ctrl, NANDC_CS_AUTO_CONFIG, 1);
++
++ usleep_range(1000, 1500);
++
++ /* Print out current chip config */
++ for (chip = 0; chip < NANDC_MAX_CHIPS; chip++) {
++ dev_dbg(dev, "chip[%d]: size=%#x block=%#x page=%#x ecc_level=%#x\n",
++ chip,
++ bcmnand_reg_read(ctrl, NANDC_CONFIG_CHIP_SIZE(chip)),
++ bcmnand_reg_read(ctrl, NANDC_CONFIG_BLK_SIZE(chip)),
++ bcmnand_reg_read(ctrl, NANDC_CONFIG_PAGE_SIZE(chip)),
++ bcmnand_reg_read(ctrl, NANDC_ACC_CTRL_ECC_LEVEL(chip)));
++ }
++
++ dev_dbg(dev, "Nand controller is reads=%d\n",
++ bcmnand_reg_aread(ctrl, NANDC_IDM_IO_CTRL_RDY));
++
++ ret = bcmnand_scan(mtd);
++ if (ret) {
++ dev_err(dev, "scanning the nand flash chip failed with %i\n",
++ ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static int bcmnand_idm_init(struct bcmnand_ctrl *ctrl)
++{
++ int irq_off;
++ unsigned int retries = 0x1000;
++ struct device *dev = &ctrl->core->dev;
++
++ if (bcmnand_reg_aread(ctrl, NANDC_IDM_RESET))
++ dev_info(dev, "stuck in reset\n");
++
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_RESET, 1);
++ if (!bcmnand_reg_aread(ctrl, NANDC_IDM_RESET)) {
++ dev_err(dev, "reset of failed\n");
++ return -EIO;
++ }
++
++ while (bcmnand_reg_aread(ctrl, NANDC_IDM_RESET)) {
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_RESET, 0);
++ cpu_relax();
++ usleep_range(100, 150);
++ if (!(retries--)) {
++ dev_err(dev, "did not came back from reset\n");
++ return -ETIMEDOUT;
++ }
++ }
++
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_CLOCK_EN, 1);
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_APB_LITTLE_ENDIAN, 0);
++ udelay(10);
++
++ dev_info(dev, "NAND Controller rev %d.%02d\n",
++ bcmnand_reg_read(ctrl, NANDC_REV_MAJOR),
++ bcmnand_reg_read(ctrl, NANDC_REV_MINOR));
++
++ usleep_range(250, 350);
++
++ /* Disable all IRQs */
++ for (irq_off = 0; irq_off < NANDC_IRQ_NUM; irq_off++)
++ bcmnand_reg_awrite(ctrl, NANDC_IDM_IRQ_N_EN(irq_off), 0);
++
++ return 0;
++}
++
++static const char * const part_probes[] = { "ofpart", "bcm47xxpart", NULL };
++
++/*
++ * Top-level init function
++ */
++static int bcmnand_probe(struct bcma_device *core)
++{
++ struct mtd_part_parser_data parser_data;
++ struct device *dev = &core->dev;
++ struct bcmnand_ctrl *ctrl;
++ int res, i, irq;
++
++ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
++ if (!ctrl)
++ return -ENOMEM;
++
++ bcma_set_drvdata(core, ctrl);
++
++ ctrl->mtd.dev.parent = &core->dev;
++ ctrl->core = core;
++
++ /* Acquire all interrupt lines */
++ for (i = 0; i < NANDC_IRQ_NUM; i++) {
++ irq = bcma_core_irq(core, i);
++ if (!irq) {
++ dev_err(dev, "IRQ idx %i not available\n", i);
++ return -ENOENT;
++ }
++ res = devm_request_irq(dev, irq, bcmnand_isr, 0,
++ KBUILD_MODNAME, ctrl);
++ if (res < 0) {
++ dev_err(dev, "problem requesting irq: %i (idx: %i)\n",
++ irq, i);
++ return res;
++ }
++ }
++
++ res = bcmnand_idm_init(ctrl);
++ if (res)
++ return res;
++
++ res = bcmnand_ctrl_init(ctrl);
++ if (res)
++ return res;
++
++ parser_data.of_node = dev->of_node;
++ res = mtd_device_parse_register(&ctrl->mtd, part_probes, &parser_data, NULL, 0);
++ if (res) {
++ dev_err(dev, "Failed to register MTD device: %d\n", res);
++ return res;
++ }
++ return 0;
++}
++
++static void bcmnand_remove(struct bcma_device *core)
++{
++ struct bcmnand_ctrl *ctrl = bcma_get_drvdata(core);
++
++ mtd_device_unregister(&ctrl->mtd);
++}
++
++static const struct bcma_device_id bcmnand_bcma_tbl[] = {
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_NAND, BCMA_ANY_REV, BCMA_ANY_CLASS),
++ {},
++};
++MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
++
++static struct bcma_driver bcmnand_bcma_driver = {
++ .name = KBUILD_MODNAME,
++ .id_table = bcmnand_bcma_tbl,
++ .probe = bcmnand_probe,
++ .remove = bcmnand_remove,
++};
++
++static int __init bcmnand_init(void)
++{
++ return bcma_driver_register(&bcmnand_bcma_driver);
++}
++
++static void __exit bcmnand_exit(void)
++{
++ bcma_driver_unregister(&bcmnand_bcma_driver);
++}
++
++module_init(bcmnand_init)
++module_exit(bcmnand_exit)
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("Northstar on-chip NAND Flash Controller driver");
diff --git a/target/linux/bcm53xx/patches-4.1/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch b/target/linux/bcm53xx/patches-4.1/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
new file mode 100644
index 0000000000..a3d0f75b48
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
@@ -0,0 +1,59 @@
+From 2a2af518266a29323cf30c3f9ba9ef2ceb1dd84b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Thu, 16 Oct 2014 20:52:16 +0200
+Subject: [PATCH] UBI: Detect EOF mark and erase all remaining blocks
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/ubi/attach.c | 5 +++++
+ drivers/mtd/ubi/io.c | 4 ++++
+ drivers/mtd/ubi/ubi.h | 1 +
+ 3 files changed, 10 insertions(+)
+
+--- a/drivers/mtd/ubi/attach.c
++++ b/drivers/mtd/ubi/attach.c
+@@ -95,6 +95,9 @@ static int self_check_ai(struct ubi_devi
+ static struct ubi_ec_hdr *ech;
+ static struct ubi_vid_hdr *vidh;
+
++/* Set on finding block with 0xdeadc0de, indicates erasing all blocks behind */
++bool erase_all_next;
++
+ /**
+ * add_to_list - add physical eraseblock to a list.
+ * @ai: attaching information
+@@ -1427,6 +1430,8 @@ int ubi_attach(struct ubi_device *ubi, i
+ if (!ai)
+ return -ENOMEM;
+
++ erase_all_next = false;
++
+ #ifdef CONFIG_MTD_UBI_FASTMAP
+ /* On small flash devices we disable fastmap in any case. */
+ if ((int)mtd_div_by_eb(ubi->mtd->size, ubi->mtd) <= UBI_FM_MAX_START) {
+--- a/drivers/mtd/ubi/io.c
++++ b/drivers/mtd/ubi/io.c
+@@ -755,6 +755,10 @@ int ubi_io_read_ec_hdr(struct ubi_device
+ }
+
+ magic = be32_to_cpu(ec_hdr->magic);
++ if (magic == 0xdeadc0de)
++ erase_all_next = true;
++ if (erase_all_next)
++ return read_err ? UBI_IO_FF_BITFLIPS : UBI_IO_FF;
+ if (magic != UBI_EC_HDR_MAGIC) {
+ if (mtd_is_eccerr(read_err))
+ return UBI_IO_BAD_HDR_EBADMSG;
+--- a/drivers/mtd/ubi/ubi.h
++++ b/drivers/mtd/ubi/ubi.h
+@@ -781,6 +781,7 @@ extern struct mutex ubi_devices_mutex;
+ extern struct blocking_notifier_head ubi_notifiers;
+
+ /* attach.c */
++extern bool erase_all_next;
+ int ubi_add_to_av(struct ubi_device *ubi, struct ubi_attach_info *ai, int pnum,
+ int ec, const struct ubi_vid_hdr *vid_hdr, int bitflips);
+ struct ubi_ainf_volume *ubi_find_av(const struct ubi_attach_info *ai,
diff --git a/target/linux/bcm53xx/patches-4.1/700-bgmac-add-support-for-the-3rd-bus-core-device.patch b/target/linux/bcm53xx/patches-4.1/700-bgmac-add-support-for-the-3rd-bus-core-device.patch
new file mode 100644
index 0000000000..6be75bb806
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/700-bgmac-add-support-for-the-3rd-bus-core-device.patch
@@ -0,0 +1,63 @@
+From f5d5afc0b1402aae0f6a2350e43241603dbaff1e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 13 May 2015 10:46:47 +0200
+Subject: [PATCH] bgmac: add support for the 3rd bus core (device)
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far we were supporting up to 2 cores but recent devices (e.g. Netgear
+R8000) may use 3rd as well. Lower ones (1st, 2nd) are usually used for
+some offloading then.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/net/ethernet/broadcom/bgmac.c | 28 +++++++++++++++++++++++-----
+ 1 file changed, 23 insertions(+), 5 deletions(-)
+
+--- a/drivers/net/ethernet/broadcom/bgmac.c
++++ b/drivers/net/ethernet/broadcom/bgmac.c
+@@ -1561,11 +1561,20 @@ static int bgmac_probe(struct bcma_devic
+ struct net_device *net_dev;
+ struct bgmac *bgmac;
+ struct ssb_sprom *sprom = &core->bus->sprom;
+- u8 *mac = core->core_unit ? sprom->et1mac : sprom->et0mac;
++ u8 *mac;
+ int err;
+
+- /* We don't support 2nd, 3rd, ... units, SPROM has to be adjusted */
+- if (core->core_unit > 1) {
++ switch (core->core_unit) {
++ case 0:
++ mac = sprom->et0mac;
++ break;
++ case 1:
++ mac = sprom->et1mac;
++ break;
++ case 2:
++ mac = sprom->et2mac;
++ break;
++ default:
+ pr_err("Unsupported core_unit %d\n", core->core_unit);
+ return -ENOTSUPP;
+ }
+@@ -1600,8 +1609,17 @@ static int bgmac_probe(struct bcma_devic
+ }
+ bgmac->cmn = core->bus->drv_gmac_cmn.core;
+
+- bgmac->phyaddr = core->core_unit ? sprom->et1phyaddr :
+- sprom->et0phyaddr;
++ switch (core->core_unit) {
++ case 0:
++ bgmac->phyaddr = sprom->et0phyaddr;
++ break;
++ case 1:
++ bgmac->phyaddr = sprom->et1phyaddr;
++ break;
++ case 2:
++ bgmac->phyaddr = sprom->et2phyaddr;
++ break;
++ }
+ bgmac->phyaddr &= BGMAC_PHY_MASK;
+ if (bgmac->phyaddr == BGMAC_PHY_MASK) {
+ bgmac_err(bgmac, "No PHY found\n");
diff --git a/target/linux/bcm53xx/patches-4.1/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch b/target/linux/bcm53xx/patches-4.1/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch
new file mode 100644
index 0000000000..6015c4aaca
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch
@@ -0,0 +1,35 @@
+From 4abdde3ad6bc0b3b157c4bf6ec0bf139d11d07e8 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 13 May 2015 14:13:28 +0200
+Subject: [PATCH] b53: add hacky CPU port fixes for devices not using port 5
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/net/phy/b53/b53_common.c | 6 ++++++
+ 1 file changed, 6 insertions(+)
+
+--- a/drivers/net/phy/b53/b53_common.c
++++ b/drivers/net/phy/b53/b53_common.c
+@@ -25,6 +25,7 @@
+ #include <linux/module.h>
+ #include <linux/switch.h>
+ #include <linux/platform_data/b53.h>
++#include <linux/of.h>
+
+ #include "b53_regs.h"
+ #include "b53_priv.h"
+@@ -1313,6 +1314,11 @@ static int b53_switch_init(struct b53_de
+ sw_dev->cpu_port = 5;
+ }
+
++ if (of_machine_is_compatible("asus,rt-ac87u"))
++ sw_dev->cpu_port = 7;
++ else if (of_machine_is_compatible("netgear,r8000"))
++ sw_dev->cpu_port = 8;
++
+ /* cpu port is always last */
+ sw_dev->ports = sw_dev->cpu_port + 1;
+ dev->enabled_ports |= BIT(sw_dev->cpu_port);
diff --git a/target/linux/bcm53xx/patches-4.1/800-bcma-use-two-different-initcalls-if-built-in.patch b/target/linux/bcm53xx/patches-4.1/800-bcma-use-two-different-initcalls-if-built-in.patch
new file mode 100644
index 0000000000..9f2cd396ae
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/800-bcma-use-two-different-initcalls-if-built-in.patch
@@ -0,0 +1,65 @@
+From 666bdfc027cde41a171862dc698987a378c8b66a Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 9 Feb 2015 18:00:42 +0100
+Subject: [PATCH RFC] bcma: use two different initcalls if built-in
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This is needed as we can't initialize bus during fs_initcall.
+Initialization requires SPROM which depends on NVRAM which depends on
+mtd. Since mtd, spi, nand, spi-nor use standard module_init, we have to
+do the same in bcma.
+Without this we'll try to initialize SPROM without having a ready SPROM
+proviver registered using bcma_arch_register_fallback_sprom.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+While this patch seems to work and I can compile bcma as built-in and
+module, I'm not too proud of it. I don't really like these #if(n)def
+tricks and I'm afraid bcma_modinit may be called even if
+bcma_modinit_early failed.
+
+Do you see any better idea of solving this?
+---
+ drivers/bcma/main.c | 16 ++++++++++++++--
+ 1 file changed, 14 insertions(+), 2 deletions(-)
+
+--- a/drivers/bcma/main.c
++++ b/drivers/bcma/main.c
+@@ -637,13 +637,25 @@ static int bcma_device_uevent(struct dev
+ core->id.rev, core->id.class);
+ }
+
++/* Bus has to be registered early, before any bcma driver */
++static int __init bcma_modinit_early(void)
++{
++ return bus_register(&bcma_bus_type);
++}
++#ifndef MODULE
++fs_initcall(bcma_modinit_early);
++#endif
++
++/* Initialization has to be done later with SPI/mtd/NAND/SPROM available */
+ static int __init bcma_modinit(void)
+ {
+ int err;
+
+- err = bus_register(&bcma_bus_type);
++#ifdef MODULE
++ err = bcma_modinit_early();
+ if (err)
+ return err;
++#endif
+
+ err = bcma_host_soc_register_driver();
+ if (err) {
+@@ -660,7 +672,7 @@ static int __init bcma_modinit(void)
+
+ return err;
+ }
+-fs_initcall(bcma_modinit);
++module_init(bcma_modinit);
+
+ static void __exit bcma_modexit(void)
+ {
diff --git a/target/linux/bcm53xx/patches-4.1/810-USB-bcma-make-helper-creating-platform-dev-more-gene.patch b/target/linux/bcm53xx/patches-4.1/810-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
new file mode 100644
index 0000000000..d331ae6573
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/810-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
@@ -0,0 +1,73 @@
+From 5b4fed9fc917cc2bfc5297eeab03aeba5d340618 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 16 Jun 2015 12:33:46 +0200
+Subject: [PATCH] USB: bcma: make helper creating platform dev more generic
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Having "bool ohci" argument bounded us to two cases only and didn't
+allow re-using this code for XHCI.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 24 +++++++++++++-----------
+ 1 file changed, 13 insertions(+), 11 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -249,7 +249,10 @@ static const struct usb_ehci_pdata ehci_
+ static const struct usb_ohci_pdata ohci_pdata = {
+ };
+
+-static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev, bool ohci, u32 addr)
++static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
++ const char *name, u32 addr,
++ const void *data,
++ size_t size)
+ {
+ struct platform_device *hci_dev;
+ struct resource hci_res[2];
+@@ -264,8 +267,7 @@ static struct platform_device *bcma_hcd_
+ hci_res[1].start = dev->irq;
+ hci_res[1].flags = IORESOURCE_IRQ;
+
+- hci_dev = platform_device_alloc(ohci ? "ohci-platform" :
+- "ehci-platform" , 0);
++ hci_dev = platform_device_alloc(name, 0);
+ if (!hci_dev)
+ return ERR_PTR(-ENOMEM);
+
+@@ -276,12 +278,8 @@ static struct platform_device *bcma_hcd_
+ ARRAY_SIZE(hci_res));
+ if (ret)
+ goto err_alloc;
+- if (ohci)
+- ret = platform_device_add_data(hci_dev, &ohci_pdata,
+- sizeof(ohci_pdata));
+- else
+- ret = platform_device_add_data(hci_dev, &ehci_pdata,
+- sizeof(ehci_pdata));
++ if (data)
++ ret = platform_device_add_data(hci_dev, data, size);
+ if (ret)
+ goto err_alloc;
+ ret = platform_device_add(hci_dev);
+@@ -334,11 +332,15 @@ static int bcma_hcd_probe(struct bcma_de
+ && chipinfo->rev == 0)
+ ohci_addr = 0x18009000;
+
+- usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, true, ohci_addr);
++ usb_dev->ohci_dev = bcma_hcd_create_pdev(dev, "ohci-platform",
++ ohci_addr, &ohci_pdata,
++ sizeof(ohci_pdata));
+ if (IS_ERR(usb_dev->ohci_dev))
+ return PTR_ERR(usb_dev->ohci_dev);
+
+- usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, false, dev->addr);
++ usb_dev->ehci_dev = bcma_hcd_create_pdev(dev, "ehci-platform",
++ dev->addr, &ehci_pdata,
++ sizeof(ehci_pdata));
+ if (IS_ERR(usb_dev->ehci_dev)) {
+ err = PTR_ERR(usb_dev->ehci_dev);
+ goto err_unregister_ohci_dev;
diff --git a/target/linux/bcm53xx/patches-4.1/811-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch b/target/linux/bcm53xx/patches-4.1/811-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
new file mode 100644
index 0000000000..758b0ac1eb
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/811-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
@@ -0,0 +1,102 @@
+From 4aed231f49954114d5ae23e97789e9aa540a0b70 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 16 Jun 2015 12:52:07 +0200
+Subject: [PATCH] USB: bcma: use separated function for USB 2.0 initialization
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This will allow adding USB 3.0 (XHCI) support cleanly.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 51 +++++++++++++++++++++++++++++++--------------
+ 1 file changed, 35 insertions(+), 16 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -34,6 +34,7 @@ MODULE_DESCRIPTION("Common USB driver fo
+ MODULE_LICENSE("GPL");
+
+ struct bcma_hcd_device {
++ struct bcma_device *core;
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
+ };
+@@ -293,27 +294,16 @@ err_alloc:
+ return ERR_PTR(ret);
+ }
+
+-static int bcma_hcd_probe(struct bcma_device *dev)
++static int bcma_hcd_usb20_init(struct bcma_hcd_device *usb_dev)
+ {
+- int err;
++ struct bcma_device *dev = usb_dev->core;
++ struct bcma_chipinfo *chipinfo = &dev->bus->chipinfo;
+ u32 ohci_addr;
+- struct bcma_hcd_device *usb_dev;
+- struct bcma_chipinfo *chipinfo;
+-
+- chipinfo = &dev->bus->chipinfo;
+-
+- /* TODO: Probably need checks here; is the core connected? */
++ int err;
+
+ if (dma_set_mask_and_coherent(dev->dma_dev, DMA_BIT_MASK(32)))
+ return -EOPNOTSUPP;
+
+- usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device),
+- GFP_KERNEL);
+- if (!usb_dev)
+- return -ENOMEM;
+-
+- bcma_hci_platform_power_gpio(dev, true);
+-
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
+ bcma_hcd_init_chip_arm(dev);
+@@ -346,7 +336,6 @@ static int bcma_hcd_probe(struct bcma_de
+ goto err_unregister_ohci_dev;
+ }
+
+- bcma_set_drvdata(dev, usb_dev);
+ return 0;
+
+ err_unregister_ohci_dev:
+@@ -354,6 +343,36 @@ err_unregister_ohci_dev:
+ return err;
+ }
+
++static int bcma_hcd_probe(struct bcma_device *dev)
++{
++ int err;
++ struct bcma_hcd_device *usb_dev;
++
++ /* TODO: Probably need checks here; is the core connected? */
++
++ usb_dev = devm_kzalloc(&dev->dev, sizeof(struct bcma_hcd_device),
++ GFP_KERNEL);
++ if (!usb_dev)
++ return -ENOMEM;
++ usb_dev->core = dev;
++
++ bcma_hci_platform_power_gpio(dev, true);
++
++ switch (dev->id.id) {
++ case BCMA_CORE_USB20_HOST:
++ case BCMA_CORE_NS_USB20:
++ err = bcma_hcd_usb20_init(usb_dev);
++ if (err)
++ return err;
++ break;
++ default:
++ return -ENODEV;
++ }
++
++ bcma_set_drvdata(dev, usb_dev);
++ return 0;
++}
++
+ static void bcma_hcd_remove(struct bcma_device *dev)
+ {
+ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
diff --git a/target/linux/bcm53xx/patches-4.1/812-USB-bcma-add-USB-3.0-support.patch b/target/linux/bcm53xx/patches-4.1/812-USB-bcma-add-USB-3.0-support.patch
new file mode 100644
index 0000000000..3875da4fe4
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/812-USB-bcma-add-USB-3.0-support.patch
@@ -0,0 +1,274 @@
+From 12c6932caa6b1fce44d0f0c68ec77d4c00ac0be7 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Tue, 16 Jun 2015 17:14:26 +0200
+Subject: [PATCH] USB: bcma: add USB 3.0 support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 219 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 219 insertions(+)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -37,6 +37,7 @@ struct bcma_hcd_device {
+ struct bcma_device *core;
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
++ struct platform_device *xhci_dev;
+ };
+
+ /* Wait for bitmask in a register to get set or cleared.
+@@ -343,6 +344,215 @@ err_unregister_ohci_dev:
+ return err;
+ }
+
++static bool bcma_wait_reg(struct bcma_bus *bus, void __iomem *addr, u32 mask,
++ u32 value, int timeout)
++{
++ unsigned long deadline = jiffies + timeout;
++ u32 val;
++
++ do {
++ val = readl(addr);
++ if ((val & mask) == value)
++ return true;
++ cpu_relax();
++ udelay(10);
++ } while (!time_after_eq(jiffies, deadline));
++
++ pr_err("Timeout waiting for register %p\n", addr);
++
++ return false;
++}
++
++static void bcma_hcd_usb30_phy_init(struct bcma_hcd_device *bcma_hcd)
++{
++ struct bcma_device *core = bcma_hcd->core;
++ struct bcma_bus *bus = core->bus;
++ struct bcma_chipinfo *chipinfo = &bus->chipinfo;
++ struct bcma_drv_cc_b *ccb = &bus->drv_cc_b;
++ struct bcma_device *arm_core;
++ void __iomem *dmu = NULL;
++ u32 cru_straps_ctrl;
++
++ if (chipinfo->id != BCMA_CHIP_ID_BCM4707 &&
++ chipinfo->id != BCMA_CHIP_ID_BCM53018)
++ return;
++
++ arm_core = bcma_find_core(bus, BCMA_CORE_ARMCA9);
++ if (!arm_core)
++ return;
++
++ dmu = ioremap_nocache(arm_core->addr_s[0], 0x1000);
++ if (!dmu)
++ goto out;
++
++ /* Check strapping of PCIE/USB3 SEL */
++ cru_straps_ctrl = ioread32(dmu + 0x2a0);
++ if ((cru_straps_ctrl & 0x10) == 0)
++ goto out;
++
++ /* Perform USB3 system soft reset */
++ bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
++
++ /* Enable MDIO. Setting MDCDIV as 26 */
++ iowrite32(0x0000009a, ccb->mii + 0x000);
++ udelay(2);
++
++ switch (chipinfo->id) {
++ case BCMA_CHIP_ID_BCM4707:
++ if (chipinfo->rev == 4) {
++ /* For NS-B0, USB3 PLL Block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8000, ccb->mii + 0x004);
++
++ /* Clear ana_pllSeqStart */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58061000, ccb->mii + 0x004);
++
++ /* CMOS Divider ratio to 25 */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582a6400, ccb->mii + 0x004);
++
++ /* Asserting PLL Reset */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582ec000, ccb->mii + 0x004);
++
++ /* Deaaserting PLL Reset */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582e8000, ccb->mii + 0x004);
++
++ /* Deasserting USB3 system reset */
++ bcma_awrite32(core, BCMA_RESET_CTL, 0);
++
++ /* Set ana_pllSeqStart */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58069000, ccb->mii + 0x004);
++
++ /* RXPMD block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8020, ccb->mii + 0x004);
++
++ /* CDR int loop locking BW to 1 */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58120049, ccb->mii + 0x004);
++
++ /* CDR int loop acquisition BW to 1 */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580e0049, ccb->mii + 0x004);
++
++ /* CDR prop loop BW to 1 */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580a005c, ccb->mii + 0x004);
++
++ /* Waiting MII Mgt interface idle */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ } else {
++ /* PLL30 block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8000, ccb->mii + 0x004);
++
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582a6400, ccb->mii + 0x004);
++
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e80e0, ccb->mii + 0x004);
++
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580a009c, ccb->mii + 0x004);
++
++ /* Enable SSC */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8040, ccb->mii + 0x004);
++
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580a21d3, ccb->mii + 0x004);
++
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58061003, ccb->mii + 0x004);
++
++ /* Waiting MII Mgt interface idle */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++
++ /* Deasserting USB3 system reset */
++ bcma_awrite32(core, BCMA_RESET_CTL, 0);
++ }
++ break;
++ case BCMA_CHIP_ID_BCM53018:
++ /* USB3 PLL Block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8000, ccb->mii + 0x004);
++
++ /* Assert Ana_Pllseq start */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58061000, ccb->mii + 0x004);
++
++ /* Assert CML Divider ratio to 26 */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582a6400, ccb->mii + 0x004);
++
++ /* Asserting PLL Reset */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582ec000, ccb->mii + 0x004);
++
++ /* Deaaserting PLL Reset */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x582e8000, ccb->mii + 0x004);
++
++ /* Waiting MII Mgt interface idle */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++
++ /* Deasserting USB3 system reset */
++ bcma_awrite32(core, BCMA_RESET_CTL, 0);
++
++ /* PLL frequency monitor enable */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58069000, ccb->mii + 0x004);
++
++ /* PIPE Block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8060, ccb->mii + 0x004);
++
++ /* CMPMAX & CMPMINTH setting */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580af30d, ccb->mii + 0x004);
++
++ /* DEGLITCH MIN & MAX setting */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x580e6302, ccb->mii + 0x004);
++
++ /* TXPMD block */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x587e8040, ccb->mii + 0x004);
++
++ /* Enabling SSC */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++ iowrite32(0x58061003, ccb->mii + 0x004);
++
++ /* Waiting MII Mgt interface idle */
++ bcma_wait_reg(bus, ccb->mii + 0x000, 0x0100, 0x0000, 1000);
++
++ break;
++ }
++out:
++ if (dmu)
++ iounmap(dmu);
++}
++
++static int bcma_hcd_usb30_init(struct bcma_hcd_device *bcma_hcd)
++{
++ struct bcma_device *core = bcma_hcd->core;
++
++ bcma_core_enable(core, 0);
++
++ bcma_hcd_usb30_phy_init(bcma_hcd);
++
++ bcma_hcd->xhci_dev = bcma_hcd_create_pdev(core, "xhci-hcd", core->addr,
++ NULL, 0);
++ if (IS_ERR(bcma_hcd->ohci_dev))
++ return PTR_ERR(bcma_hcd->ohci_dev);
++
++ return 0;
++}
++
+ static int bcma_hcd_probe(struct bcma_device *dev)
+ {
+ int err;
+@@ -365,6 +575,11 @@ static int bcma_hcd_probe(struct bcma_de
+ if (err)
+ return err;
+ break;
++ case BCMA_CORE_NS_USB30:
++ err = bcma_hcd_usb30_init(usb_dev);
++ if (err)
++ return err;
++ break;
+ default:
+ return -ENODEV;
+ }
+@@ -378,11 +593,14 @@ static void bcma_hcd_remove(struct bcma_
+ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+ struct platform_device *ohci_dev = usb_dev->ohci_dev;
+ struct platform_device *ehci_dev = usb_dev->ehci_dev;
++ struct platform_device *xhci_dev = usb_dev->xhci_dev;
+
+ if (ohci_dev)
+ platform_device_unregister(ohci_dev);
+ if (ehci_dev)
+ platform_device_unregister(ehci_dev);
++ if (xhci_dev)
++ platform_device_unregister(xhci_dev);
+
+ bcma_core_disable(dev, 0);
+ }
+@@ -419,6 +637,7 @@ static int bcma_hcd_resume(struct bcma_d
+ static const struct bcma_device_id bcma_hcd_table[] = {
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB20, BCMA_ANY_REV, BCMA_ANY_CLASS),
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_USB30, BCMA_ANY_REV, BCMA_ANY_CLASS),
+ {},
+ };
+ MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
diff --git a/target/linux/bcm53xx/patches-4.1/813-USB-bcma-fix-setting-VCC-GPIO-value.patch b/target/linux/bcm53xx/patches-4.1/813-USB-bcma-fix-setting-VCC-GPIO-value.patch
new file mode 100644
index 0000000000..9ba3bdeece
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/813-USB-bcma-fix-setting-VCC-GPIO-value.patch
@@ -0,0 +1,45 @@
+From bdc3b01d94b22f8b5f9621a1c37336e78f4f1bce Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 21 Jun 2015 12:09:57 +0200
+Subject: [PATCH] USB: bcma: fix setting VCC GPIO value
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+It wasn't working (on most of devices?) without setting GPIO direction
+and wasn't respecting ACTIVE_LOW flag.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -230,17 +230,22 @@ static void bcma_hcd_init_chip_arm(struc
+
+ static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
+ {
++ enum of_gpio_flags of_flags;
+ int gpio;
+
+- gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
++ gpio = of_get_named_gpio_flags(dev->dev.of_node, "vcc-gpio", 0, &of_flags);
+ if (!gpio_is_valid(gpio))
+ return;
+
+ if (val) {
+- gpio_request(gpio, "bcma-hcd-gpio");
+- gpio_set_value(gpio, 1);
++ unsigned long flags = 0;
++ bool active_low = !!(of_flags & OF_GPIO_ACTIVE_LOW);
++
++ flags |= active_low ? GPIOF_ACTIVE_LOW : 0;
++ flags |= active_low ? GPIOF_INIT_LOW : GPIOF_INIT_HIGH;
++ gpio_request_one(gpio, flags, "bcma-hcd-gpio");
+ } else {
+- gpio_set_value(gpio, 0);
++ gpiod_set_value(gpio_to_desc(gpio), 0);
+ gpio_free(gpio);
+ }
+ }
diff --git a/target/linux/bcm53xx/patches-4.1/820-xhci-add-Broadcom-specific-fake-doorbell.patch b/target/linux/bcm53xx/patches-4.1/820-xhci-add-Broadcom-specific-fake-doorbell.patch
new file mode 100644
index 0000000000..9a87a75dd4
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/820-xhci-add-Broadcom-specific-fake-doorbell.patch
@@ -0,0 +1,94 @@
+From 9cc14ca0aae53c16d10ffea49848ac61a5015562 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 21 Jun 2015 11:10:49 +0200
+Subject: [PATCH] xhci: add Broadcom specific fake doorbell
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This fixes problem with controller seeing devices only in some small
+percentage of cold boots.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/xhci.c | 62 +++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 62 insertions(+)
+
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -121,6 +121,64 @@ int xhci_halt(struct xhci_hcd *xhci)
+ return ret;
+ }
+
++#ifdef CONFIG_ARCH_BCM_5301X
++int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id)
++{
++ unsigned int temp1, ret;
++
++ /* alloc a virt device for slot */
++ if (!xhci_alloc_virt_device(xhci, slot_id, 0, GFP_NOIO)) {
++ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
++ return 1;
++ }
++
++ /* ring fake doorbell for slot_id ep 0 */
++ xhci_ring_ep_doorbell(xhci, slot_id, 0, 0);
++ mdelay(1);
++
++ /* read the status register to check if HSE is set or not? */
++ temp1 = readl(&xhci->op_regs->status);
++ xhci_dbg(xhci, "op reg status = %x\n",temp1);
++
++ /* clear HSE if set */
++ if(temp1 & STS_FATAL) {
++ xhci_dbg(xhci, "HSE problem detected\n");
++ temp1 &= ~(0x1fff);
++ temp1 |= STS_FATAL;
++ xhci_dbg(xhci, "temp1=%x\n",temp1);
++ writel(temp1, &xhci->op_regs->status);
++ mdelay(1);
++ temp1 = readl(&xhci->op_regs->status);
++ xhci_dbg(xhci, "After clear op reg status=%x\n", temp1);
++ }
++
++ /* Free virt device */
++ xhci_free_virt_device(xhci, slot_id);
++
++ /* Run the controller if needed */
++ temp1 = readl(&xhci->op_regs->command);
++ if (temp1 & CMD_RUN)
++ return 0;
++ temp1 |= (CMD_RUN);
++
++ writel(temp1, &xhci->op_regs->command);
++ /*
++ * Wait for the HCHalted Status bit to be 0 to indicate the host is running.
++ */
++ ret = xhci_handshake(xhci, &xhci->op_regs->status,
++ STS_HALT, 0, XHCI_MAX_HALT_USEC);
++
++ if (ret == -ETIMEDOUT) {
++ xhci_err(xhci, "Host took too long to start, "
++ "waited %u microseconds.\n",
++ XHCI_MAX_HALT_USEC);
++ return 1;
++ }
++
++ return 0;
++}
++#endif /* CONFIG_ARCH_BCM_5301X */
++
+ /*
+ * Set the run bit and wait for the host to be running.
+ */
+@@ -145,6 +203,10 @@ static int xhci_start(struct xhci_hcd *x
+ xhci_err(xhci, "Host took too long to start, "
+ "waited %u microseconds.\n",
+ XHCI_MAX_HALT_USEC);
++#ifdef CONFIG_ARCH_BCM_5301X
++ xhci_fake_doorbell(xhci, 1);
++#endif /* CONFIG_ARCH_BCM_5301X */
++
+ if (!ret)
+ xhci->xhc_state &= ~XHCI_STATE_HALTED;
+ return ret;
diff --git a/target/linux/bcm53xx/patches-4.1/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch b/target/linux/bcm53xx/patches-4.1/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch
new file mode 100644
index 0000000000..c1dfa92013
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch
@@ -0,0 +1,42 @@
+From 21500872c1dba33848ddcf6bea97d58772675d36 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 17 May 2015 14:00:52 +0200
+Subject: [PATCH] mtd: bcm47xxpart: workaround for Asus RT-AC87U "asus"
+ partition
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/mtd/bcm47xxpart.c | 12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- a/drivers/mtd/bcm47xxpart.c
++++ b/drivers/mtd/bcm47xxpart.c
+@@ -14,6 +14,7 @@
+ #include <linux/slab.h>
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of.h>
+
+ #include <uapi/linux/magic.h>
+
+@@ -135,6 +136,17 @@ static int bcm47xxpart_parse(struct mtd_
+ break;
+ }
+
++ /*
++ * Ugly workaround for Asus RT-AC87U and its "asus" partition.
++ * It uses JFFS2 which we don't (want to) detect. We should
++ * probably use DT to define partitions but we need a working
++ * TRX firmware splitter first.
++ */
++ if (of_machine_is_compatible("asus,rt-ac87u") && offset == 0x7ec0000) {
++ bcm47xxpart_add_part(&parts[curr_part++], "asus", offset, MTD_WRITEABLE);
++ continue;
++ }
++
+ /* Read beginning of the block */
+ if (mtd_read(master, offset, BCM47XXPART_BYTES_TO_READ,
+ &bytes_read, (uint8_t *)buf) < 0) {