aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/bcm53xx
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/bcm53xx')
-rw-r--r--target/linux/bcm53xx/Makefile30
-rw-r--r--target/linux/bcm53xx/base-files.mk3
-rwxr-xr-xtarget/linux/bcm53xx/base-files/etc/board.d/02_network70
-rw-r--r--target/linux/bcm53xx/base-files/etc/diag.sh43
-rw-r--r--target/linux/bcm53xx/base-files/etc/uci-defaults/09_fix_crc7
-rw-r--r--target/linux/bcm53xx/base-files/lib/preinit/05_set_preinit_iface_bcm53xx7
-rw-r--r--target/linux/bcm53xx/base-files/lib/upgrade/platform.sh210
-rw-r--r--target/linux/bcm53xx/config-4.1305
-rw-r--r--target/linux/bcm53xx/config-4.3319
-rw-r--r--target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Kconfig11
-rw-r--r--target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Makefile1
-rw-r--r--target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/bcm47xx_nvram.c248
-rw-r--r--target/linux/bcm53xx/files-4.1/include/linux/bcm47xx_nvram.h49
-rw-r--r--target/linux/bcm53xx/files/drivers/misc/bcm47xx-sprom.c691
-rw-r--r--target/linux/bcm53xx/files/drivers/mtd/spi-nor/bcm53xxspiflash.c231
-rw-r--r--target/linux/bcm53xx/image/Makefile149
-rw-r--r--target/linux/bcm53xx/image/ubinize.cfg24
-rw-r--r--target/linux/bcm53xx/patches-4.1/030-PCI-iproc-Allow-override-of-device-tree-IRQ-mapping-.patch53
-rw-r--r--target/linux/bcm53xx/patches-4.1/031-PCI-iproc-Add-BCMA-PCIe-driver.patch177
-rw-r--r--target/linux/bcm53xx/patches-4.1/032-PCI-iproc-Directly-add-PCI-resources.patch90
-rw-r--r--target/linux/bcm53xx/patches-4.1/033-PCI-iproc-Free-resource-list-after-registration.patch57
-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/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch32
-rw-r--r--target/linux/bcm53xx/patches-4.1/070-ARM-l2c-restore-the-behaviour-documented-above-l2c_e.patch43
-rw-r--r--target/linux/bcm53xx/patches-4.1/071-ARM-l2c-write-auxiliary-control-register-first.patch30
-rw-r--r--target/linux/bcm53xx/patches-4.1/072-ARM-l2c-clean-up-l2c_configure.patch109
-rw-r--r--target/linux/bcm53xx/patches-4.1/073-ARM-l2c-only-unlock-caches-if-NS_LOCKDOWN-bit-is-set.patch149
-rw-r--r--target/linux/bcm53xx/patches-4.1/074-ARM-l2c-avoid-passing-auxiliary-control-register-thr.patch129
-rw-r--r--target/linux/bcm53xx/patches-4.1/075-ARM-8391-1-l2c-add-options-to-overwrite-prefetching-.patch60
-rw-r--r--target/linux/bcm53xx/patches-4.1/077-ARM-l2c-Add-support-for-the-arm-shared-override-prop.patch81
-rw-r--r--target/linux/bcm53xx/patches-4.1/079-ARM-BCM5301X-activate-some-additional-options-in-pl3.patch29
-rw-r--r--target/linux/bcm53xx/patches-4.1/080-ARM-BCM5301X-Enable-UART0-on-tested-devices.patch83
-rw-r--r--target/linux/bcm53xx/patches-4.1/081-ARM-BCM5301X-Add-profiling-support.patch25
-rw-r--r--target/linux/bcm53xx/patches-4.1/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch128
-rw-r--r--target/linux/bcm53xx/patches-4.1/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch218
-rw-r--r--target/linux/bcm53xx/patches-4.1/090-mtd-nand-add-common-DT-init-code.patch111
-rw-r--r--target/linux/bcm53xx/patches-4.1/092-Add-Broadcom-STB-NAND.patch2765
-rw-r--r--target/linux/bcm53xx/patches-4.1/101-use-part-parser.patch11
-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/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch635
-rw-r--r--target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch50
-rw-r--r--target/linux/bcm53xx/patches-4.1/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch57
-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/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch75
-rw-r--r--target/linux/bcm53xx/patches-4.1/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch62
-rw-r--r--target/linux/bcm53xx/patches-4.1/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch135
-rw-r--r--target/linux/bcm53xx/patches-4.1/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch75
-rw-r--r--target/linux/bcm53xx/patches-4.1/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch112
-rw-r--r--target/linux/bcm53xx/patches-4.1/197-USB-bcma-add-USB-3.0-support.patch295
-rw-r--r--target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch86
-rw-r--r--target/linux/bcm53xx/patches-4.1/301-ARM-BCM5301X-Add-SPROM.patch26
-rw-r--r--target/linux/bcm53xx/patches-4.1/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch69
-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.patch86
-rw-r--r--target/linux/bcm53xx/patches-4.1/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch170
-rw-r--r--target/linux/bcm53xx/patches-4.1/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch173
-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/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch111
-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/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.patch42
-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/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch42
-rw-r--r--target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch59
-rw-r--r--target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch292
-rw-r--r--target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch120
-rw-r--r--target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch219
-rw-r--r--target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch223
-rw-r--r--target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch158
-rw-r--r--target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch319
-rw-r--r--target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch153
-rw-r--r--target/linux/bcm53xx/patches-4.3/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch32
-rw-r--r--target/linux/bcm53xx/patches-4.3/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch128
-rw-r--r--target/linux/bcm53xx/patches-4.3/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch218
-rw-r--r--target/linux/bcm53xx/patches-4.3/101-use-part-parser.patch11
-rw-r--r--target/linux/bcm53xx/patches-4.3/112-bcm53xx-sprom-add-sprom-driver.patch69
-rw-r--r--target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch635
-rw-r--r--target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch50
-rw-r--r--target/linux/bcm53xx/patches-4.3/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch57
-rw-r--r--target/linux/bcm53xx/patches-4.3/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch75
-rw-r--r--target/linux/bcm53xx/patches-4.3/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch63
-rw-r--r--target/linux/bcm53xx/patches-4.3/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch135
-rw-r--r--target/linux/bcm53xx/patches-4.3/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch75
-rw-r--r--target/linux/bcm53xx/patches-4.3/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch112
-rw-r--r--target/linux/bcm53xx/patches-4.3/197-USB-bcma-add-USB-3.0-support.patch295
-rw-r--r--target/linux/bcm53xx/patches-4.3/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch86
-rw-r--r--target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch26
-rw-r--r--target/linux/bcm53xx/patches-4.3/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch69
-rw-r--r--target/linux/bcm53xx/patches-4.3/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch41
-rw-r--r--target/linux/bcm53xx/patches-4.3/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch86
-rw-r--r--target/linux/bcm53xx/patches-4.3/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch170
-rw-r--r--target/linux/bcm53xx/patches-4.3/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch173
-rw-r--r--target/linux/bcm53xx/patches-4.3/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch20
-rw-r--r--target/linux/bcm53xx/patches-4.3/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch111
-rw-r--r--target/linux/bcm53xx/patches-4.3/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch31
-rw-r--r--target/linux/bcm53xx/patches-4.3/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch20
-rw-r--r--target/linux/bcm53xx/patches-4.3/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch59
-rw-r--r--target/linux/bcm53xx/patches-4.3/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch42
-rw-r--r--target/linux/bcm53xx/patches-4.3/800-bcma-use-two-different-initcalls-if-built-in.patch65
-rw-r--r--target/linux/bcm53xx/patches-4.3/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch42
-rw-r--r--target/linux/bcm53xx/profiles/100-Generic.mk19
117 files changed, 15368 insertions, 0 deletions
diff --git a/target/linux/bcm53xx/Makefile b/target/linux/bcm53xx/Makefile
new file mode 100644
index 0000000..68cfa63
--- /dev/null
+++ b/target/linux/bcm53xx/Makefile
@@ -0,0 +1,30 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=arm
+BOARD:=bcm53xx
+BOARDNAME:=Broadcom BCM47xx/53xx (ARM)
+FEATURES:=squashfs nand usb pci pcie gpio
+MAINTAINER:=Hauke Mehrtens <hauke@hauke-m.de>
+CPU_TYPE:=cortex-a9
+
+KERNEL_PATCHVER:=4.1
+
+include $(INCLUDE_DIR)/target.mk
+
+define Target/Description
+ Build firmware images for Broadcom based BCM47xx/53xx routers with ARM CPU, *not* MIPS.
+endef
+
+KERNELNAME:=zImage dtbs
+
+DEFAULT_PACKAGES += swconfig wpad-mini nvram otrx \
+ kmod-gpio-button-hotplug \
+ kmod-leds-gpio kmod-ledtrig-default-on kmod-ledtrig-timer
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/bcm53xx/base-files.mk b/target/linux/bcm53xx/base-files.mk
new file mode 100644
index 0000000..fdd2c71
--- /dev/null
+++ b/target/linux/bcm53xx/base-files.mk
@@ -0,0 +1,3 @@
+define Package/base-files/install-target
+ rm -f $(1)/etc/config/network
+endef
diff --git a/target/linux/bcm53xx/base-files/etc/board.d/02_network b/target/linux/bcm53xx/base-files/etc/board.d/02_network
new file mode 100755
index 0000000..a164251
--- /dev/null
+++ b/target/linux/bcm53xx/base-files/etc/board.d/02_network
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Copyright (C) 2011 OpenWrt.org
+#
+
+. /lib/functions/uci-defaults-new.sh
+
+board_config_update
+
+board=$(cat /proc/device-tree/compatible | tr '\0' '\t' | cut -f 1)
+case "$board" in
+asus,rt-ac87u)
+ ifname=eth1
+ ;;
+netgear,r8000)
+ ifname=eth2
+ ;;
+*)
+ ifname=eth0
+ ;;
+esac
+
+# Workaround for devices using eth2
+case "$board" in
+netgear,r8000)
+ ifname=eth0
+ ;;
+esac
+
+ucidef_set_interface_loopback
+ucidef_set_interfaces_lan_wan "$ifname.1" "$ifname.2"
+ucidef_add_switch "switch0" "1" "1"
+
+# Workaround for devices using CPU port 8 (connected to eth2)
+case "$board" in
+netgear,r8000)
+ ucidef_add_switch_vlan "switch0" "1" "0 1 2 3 5t"
+ ucidef_add_switch_vlan "switch0" "2" "4 5t"
+ board_config_flush
+ exit 0
+ ;;
+esac
+
+# NVRAM entries may contain unsorted ports, e.g. Netgear R6250 uses
+# vlan1ports=3 2 1 0 5*
+# vlan2ports=4 5u
+# and early Netgear R8000 was using
+# vlan1ports=3 2 1 0 5 7 8*
+vlan1ports="$(echo $(nvram get vlan1ports | tr " " "\n" | sort))"
+vlan2ports="$(echo $(nvram get vlan2ports | tr " " "\n" | sort))"
+if echo "$vlan1ports" | egrep -q "^1 2 3 4 5" && \
+ echo "$vlan2ports" | egrep -q "^0 5"; then
+ ucidef_add_switch_vlan "switch0" "1" "1 2 3 4 5t"
+ ucidef_add_switch_vlan "switch0" "2" "0 5t"
+elif echo "$vlan1ports" | egrep -q "^1 2 3 5 7" && \
+ echo "$vlan2ports" | egrep -q "^0 7"; then
+ ucidef_add_switch_vlan "switch0" "1" "1 2 3 5 7t"
+ ucidef_add_switch_vlan "switch0" "2" "0 7t"
+elif echo "$vlan1ports" | egrep -q "^0 1 2 3 5 7 8" && \
+ echo "$vlan2ports" | egrep -q "^4 8"; then
+ ucidef_add_switch_vlan "switch0" "1" "0 1 2 3 5 7 8t"
+ ucidef_add_switch_vlan "switch0" "2" "4 8t"
+else
+ ucidef_add_switch_vlan "switch0" "1" "0 1 2 3 5t"
+ ucidef_add_switch_vlan "switch0" "2" "4 5t"
+fi
+
+board_config_flush
+
+exit 0
diff --git a/target/linux/bcm53xx/base-files/etc/diag.sh b/target/linux/bcm53xx/base-files/etc/diag.sh
new file mode 100644
index 0000000..0a8c5fb
--- /dev/null
+++ b/target/linux/bcm53xx/base-files/etc/diag.sh
@@ -0,0 +1,43 @@
+#!/bin/sh
+# Copyright (C) 2014 OpenWrt.org
+
+. /lib/functions/leds.sh
+
+get_status_led() {
+ local status_led_file
+
+ # There may be more than one color of power LED, try to avoid amber/red
+ status_led_file=$(find /sys/class/leds/ -name "*:power" -a ! -name "*:amber:*" -a ! -name "*:red:*" | head -n1)
+ if [ -d "$status_led_file" ]; then
+ status_led=$(basename $status_led_file)
+ return
+ fi;
+
+ # Now just pick any power LED
+ status_led_file=$(find /sys/class/leds/ -name "*:power:*" | head -n1)
+ if [ -d "$status_led_file" ]; then
+ status_led=$(basename $status_led_file)
+ return
+ fi;
+}
+
+set_state() {
+ get_status_led
+
+ [ -z "$status_led" ] && return
+
+ case "$1" in
+ preinit)
+ status_led_blink_preinit
+ ;;
+ failsafe)
+ status_led_blink_failsafe
+ ;;
+ preinit_regular)
+ status_led_blink_preinit_regular
+ ;;
+ done)
+ status_led_on
+ ;;
+ esac
+}
diff --git a/target/linux/bcm53xx/base-files/etc/uci-defaults/09_fix_crc b/target/linux/bcm53xx/base-files/etc/uci-defaults/09_fix_crc
new file mode 100644
index 0000000..346a532
--- /dev/null
+++ b/target/linux/bcm53xx/base-files/etc/uci-defaults/09_fix_crc
@@ -0,0 +1,7 @@
+#!/bin/sh
+#
+# Copyright (C) 2007 OpenWrt.org
+#
+#
+
+mtd fixtrx firmware
diff --git a/target/linux/bcm53xx/base-files/lib/preinit/05_set_preinit_iface_bcm53xx b/target/linux/bcm53xx/base-files/lib/preinit/05_set_preinit_iface_bcm53xx
new file mode 100644
index 0000000..0539b82
--- /dev/null
+++ b/target/linux/bcm53xx/base-files/lib/preinit/05_set_preinit_iface_bcm53xx
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+set_preinit_iface() {
+ ifname=eth0
+}
+
+boot_hook_add preinit_main set_preinit_iface
diff --git a/target/linux/bcm53xx/base-files/lib/upgrade/platform.sh b/target/linux/bcm53xx/base-files/lib/upgrade/platform.sh
new file mode 100644
index 0000000..eff7aff
--- /dev/null
+++ b/target/linux/bcm53xx/base-files/lib/upgrade/platform.sh
@@ -0,0 +1,210 @@
+PART_NAME=firmware
+
+# $(1): file to read magic from
+# $(2): offset in bytes
+get_magic_long_at() {
+ dd if="$1" skip=$2 bs=1 count=4 2>/dev/null | hexdump -v -e '1/1 "%02x"'
+}
+
+platform_machine() {
+ cat /proc/device-tree/compatible | tr '\0' '\t' | cut -f 1
+}
+
+platform_flash_type() {
+ # On NAND devices "rootfs" is UBI volume, so won't be find in /proc/mtd
+ grep -q "\"rootfs\"" /proc/mtd && {
+ echo "serial"
+ return
+ }
+
+ echo "nand"
+}
+
+platform_expected_image() {
+ local machine=$(platform_machine)
+
+ case "$machine" in
+ "netgear,r6250v1") echo "chk U12H245T00_NETGEAR"; return;;
+ "netgear,r6300v2") echo "chk U12H240T00_NETGEAR"; return;;
+ "netgear,r7000") echo "chk U12H270T00_NETGEAR"; return;;
+ "netgear,r8000") echo "chk U12H315T00_NETGEAR"; return;;
+ esac
+}
+
+platform_identify() {
+ local magic
+
+ magic=$(get_magic_long "$1")
+ case "$magic" in
+ "48445230")
+ echo "trx"
+ return
+ ;;
+ "2a23245e")
+ echo "chk"
+ return
+ ;;
+ esac
+
+ magic=$(get_magic_long_at "$1" 14)
+ [ "$magic" = "55324e44" ] && {
+ echo "cybertan"
+ return
+ }
+
+ echo "unknown"
+}
+
+platform_check_image() {
+ [ "$#" -gt 1 ] && return 1
+
+ local file_type=$(platform_identify "$1")
+ local magic
+ local error=0
+
+ case "$file_type" in
+ "chk")
+ local header_len=$((0x$(get_magic_long_at "$1" 4)))
+ local board_id_len=$(($header_len - 40))
+ local board_id=$(dd if="$1" skip=40 bs=1 count=$board_id_len 2>/dev/null | hexdump -v -e '1/1 "%c"')
+ local dev_board_id=$(platform_expected_image)
+ echo "Found CHK image with device board_id $board_id"
+
+ [ -n "$dev_board_id" -a "chk $board_id" != "$dev_board_id" ] && {
+ echo "Firmware board_id doesn't match device board_id ($dev_board_id)"
+ error=1
+ }
+
+ if ! otrx check "$1" -o "$header_len"; then
+ echo "No valid TRX firmware in the CHK image"
+ error=1
+ fi
+ ;;
+ "cybertan")
+ local pattern=$(dd if="$1" bs=1 count=4 2>/dev/null | hexdump -v -e '1/1 "%c"')
+ local dev_pattern=$(platform_expected_image)
+ echo "Found CyberTAN image with device pattern: $pattern"
+
+ [ -n "$dev_pattern" -a "cybertan $pattern" != "$dev_pattern" ] && {
+ echo "Firmware pattern doesn't match device pattern ($dev_pattern)"
+ error=1
+ }
+
+ if ! otrx check "$1" -o 32; then
+ echo "No valid TRX firmware in the CyberTAN image"
+ error=1
+ fi
+ ;;
+ "trx")
+ if ! otrx check "$1"; then
+ echo "Invalid (corrupted?) TRX firmware"
+ error=1
+ fi
+ ;;
+ *)
+ echo "Invalid image type. Please use only .trx files"
+ error=1
+ ;;
+ esac
+
+ return $error
+}
+
+platform_pre_upgrade() {
+ local file_type=$(platform_identify "$1")
+ local dir="/tmp/sysupgrade-bcm53xx"
+ local trx="$1"
+ local offset
+
+ [ "$(platform_flash_type)" != "nand" ] && return
+
+ # Find trx offset
+ case "$file_type" in
+ "chk") offset=$((0x$(get_magic_long_at "$1" 4)));;
+ "cybertan") offset=32;;
+ esac
+
+ # Extract partitions from trx
+ rm -fR $dir
+ mkdir -p $dir
+ otrx extract "$trx" \
+ ${offset:+-o $offset} \
+ -1 $dir/kernel \
+ -2 $dir/root
+ [ $? -ne 0 ] && {
+ echo "Failed to extract TRX partitions."
+ return
+ }
+
+ # Firmwares without UBI image should be flashed "normally"
+ local root_type=$(identify $dir/root)
+ [ "$root_type" != "ubi" ] && {
+ echo "Provided firmware doesn't use UBI for rootfs."
+ return
+ }
+
+ # Prepare TRX file with just a kernel that will replace current one
+ local linux_length=$(grep "\"linux\"" /proc/mtd | sed "s/mtd[0-9]*:[ \t]*\([^ \t]*\).*/\1/")
+ [ -z "$linux_length" ] && {
+ echo "Unable to find \"linux\" partition size"
+ exit 1
+ }
+ linux_length=$((0x$linux_length))
+ local kernel_length=$(wc -c $dir/kernel | cut -d ' ' -f 1)
+ [ $kernel_length -gt $linux_length ] && {
+ echo "New kernel doesn't fit \"linux\" partition."
+ return
+ }
+ rm -f /tmp/null.bin
+ rm -f /tmp/kernel.trx
+ touch /tmp/null.bin
+ otrx create /tmp/kernel.trx \
+ -f $dir/kernel -b $(($linux_length + 28)) \
+ -f /tmp/null.bin
+ [ $? -ne 0 ] && {
+ echo "Failed to create simple TRX with new kernel."
+ return
+ }
+
+ # Prepare UBI image (drop unwanted extra blocks)
+ local ubi_length=0
+ while [ "$(dd if=$dir/root skip=$ubi_length bs=1 count=4 2>/dev/null)" = "UBI#" ]; do
+ ubi_length=$(($ubi_length + 131072))
+ done
+ dd if=$dir/root of=/tmp/root.ubi bs=131072 count=$((ubi_length / 131072)) 2>/dev/null
+ [ $? -ne 0 ] && {
+ echo "Failed to prepare new UBI image."
+ return
+ }
+
+ # Flash
+ mtd write /tmp/kernel.trx firmware
+ nand_do_upgrade /tmp/root.ubi
+}
+
+platform_trx_from_chk_cmd() {
+ local header_len=$((0x$(get_magic_long_at "$1" 4)))
+
+ echo -n dd bs=$header_len skip=1
+}
+
+platform_trx_from_cybertan_cmd() {
+ echo -n dd bs=32 skip=1
+}
+
+platform_do_upgrade() {
+ local file_type=$(platform_identify "$1")
+ local trx="$1"
+ local cmd=
+
+ [ "$(platform_flash_type)" == "nand" ] && {
+ echo "Writing whole image to NAND flash. All erase counters will be lost."
+ }
+
+ case "$file_type" in
+ "chk") cmd=$(platform_trx_from_chk_cmd "$trx");;
+ "cybertan") cmd=$(platform_trx_from_cybertan_cmd "$trx");;
+ esac
+
+ default_do_upgrade "$trx" "$cmd"
+}
diff --git a/target/linux/bcm53xx/config-4.1 b/target/linux/bcm53xx/config-4.1
new file mode 100644
index 0000000..e2d122b
--- /dev/null
+++ b/target/linux/bcm53xx/config-4.1
@@ -0,0 +1,305 @@
+CONFIG_ALIGNMENT_TRAP=y
+# CONFIG_ARCH_ALPINE is not set
+CONFIG_ARCH_BCM=y
+# CONFIG_ARCH_BCM_21664 is not set
+# CONFIG_ARCH_BCM_281XX is not set
+CONFIG_ARCH_BCM_5301X=y
+# CONFIG_ARCH_BCM_63XX is not set
+# CONFIG_ARCH_BCM_CYGNUS is not set
+CONFIG_ARCH_BCM_IPROC=y
+# CONFIG_ARCH_BRCMSTB is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_APPENDED_DTB=y
+# CONFIG_ARM_ATAG_DTB_COMPAT is not set
+# CONFIG_ARM_CPU_SUSPEND is not set
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_ARM_ERRATA_798181=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GLOBAL_TIMER=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATAGS=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_B53=y
+# CONFIG_B53_MMAP_DRIVER is not set
+# CONFIG_B53_PHY_DRIVER is not set
+CONFIG_B53_SRAB_DRIVER=y
+CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM47XX_SPROM=y
+CONFIG_BCM47XX_WDT=y
+CONFIG_BCMA=y
+CONFIG_BCMA_BLOCKIO=y
+CONFIG_BCMA_DEBUG=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_BCMA_DRIVER_PCI=y
+CONFIG_BCMA_HOST_PCI=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+CONFIG_BCMA_HOST_SOC=y
+CONFIG_BGMAC=y
+CONFIG_BOUNCE=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_DEFLATE=y
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_XZ=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BCM_5301X=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
+CONFIG_DEBUG_UART_8250=y
+# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set
+CONFIG_DEBUG_UART_8250_SHIFT=0
+CONFIG_DEBUG_UART_PHYS=0x18000300
+CONFIG_DEBUG_UART_VIRT=0xf1000300
+CONFIG_DEBUG_UNCOMPRESS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_FIXED_PHY=y
+CONFIG_FRAME_POINTER=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_74X164=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_BCM47XX_PARTS=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BRCMNAND=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_PHYSMAP_OF is not set
+CONFIG_MTD_SPI_BCM53XXSPIFLASH=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=2
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+CONFIG_PCIE_IPROC=y
+CONFIG_PCIE_IPROC_BCMA=y
+# CONFIG_PCIE_IPROC_PLATFORM is not set
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PINCTRL=y
+# CONFIG_PL310_ERRATA_588369 is not set
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BCM53XX=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+CONFIG_SRCU=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SWCONFIG=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_RCU=y
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_XZ=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_VFP is not set
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/bcm53xx/config-4.3 b/target/linux/bcm53xx/config-4.3
new file mode 100644
index 0000000..16705a1
--- /dev/null
+++ b/target/linux/bcm53xx/config-4.3
@@ -0,0 +1,319 @@
+CONFIG_ALIGNMENT_TRAP=y
+CONFIG_ARCH_BCM=y
+# CONFIG_ARCH_BCM_21664 is not set
+# CONFIG_ARCH_BCM_281XX is not set
+CONFIG_ARCH_BCM_5301X=y
+# CONFIG_ARCH_BCM_63XX is not set
+# CONFIG_ARCH_BCM_CYGNUS is not set
+CONFIG_ARCH_BCM_IPROC=y
+# CONFIG_ARCH_BRCMSTB is not set
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+CONFIG_ARCH_HAS_GCOV_PROFILE_ALL=y
+CONFIG_ARCH_HAS_SG_CHAIN=y
+CONFIG_ARCH_HAS_TICK_BROADCAST=y
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MULTIPLATFORM=y
+# CONFIG_ARCH_MULTI_CPU_AUTO is not set
+CONFIG_ARCH_MULTI_V6_V7=y
+CONFIG_ARCH_MULTI_V7=y
+CONFIG_ARCH_NR_GPIO=0
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+CONFIG_ARCH_SUPPORTS_ATOMIC_RMW=y
+CONFIG_ARCH_SUPPORTS_UPROBES=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_USE_BUILTIN_BSWAP=y
+CONFIG_ARCH_USE_CMPXCHG_LOCKREF=y
+CONFIG_ARCH_WANT_GENERAL_HUGETLB=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+CONFIG_ARM=y
+CONFIG_ARM_AMBA=y
+CONFIG_ARM_APPENDED_DTB=y
+# CONFIG_ARM_ATAG_DTB_COMPAT is not set
+# CONFIG_ARM_CPU_SUSPEND is not set
+CONFIG_ARM_ERRATA_754322=y
+CONFIG_ARM_ERRATA_764369=y
+CONFIG_ARM_ERRATA_775420=y
+CONFIG_ARM_ERRATA_798181=y
+CONFIG_ARM_GIC=y
+CONFIG_ARM_GLOBAL_TIMER=y
+CONFIG_ARM_HAS_SG_CHAIN=y
+CONFIG_ARM_HEAVY_MB=y
+CONFIG_ARM_L1_CACHE_SHIFT=6
+CONFIG_ARM_L1_CACHE_SHIFT_6=y
+# CONFIG_ARM_LPAE is not set
+CONFIG_ARM_PATCH_PHYS_VIRT=y
+# CONFIG_ARM_SP805_WATCHDOG is not set
+CONFIG_ARM_THUMB=y
+# CONFIG_ARM_THUMBEE is not set
+CONFIG_ARM_VIRT_EXT=y
+CONFIG_ATAGS=y
+CONFIG_AUTO_ZRELADDR=y
+CONFIG_B53=y
+# CONFIG_B53_MMAP_DRIVER is not set
+# CONFIG_B53_PHY_DRIVER is not set
+CONFIG_B53_SRAB_DRIVER=y
+CONFIG_BCM47XX_NVRAM=y
+CONFIG_BCM47XX_SPROM=y
+CONFIG_BCM47XX_WDT=y
+CONFIG_BCMA=y
+CONFIG_BCMA_BLOCKIO=y
+CONFIG_BCMA_DEBUG=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
+CONFIG_BCMA_DRIVER_GPIO=y
+CONFIG_BCMA_DRIVER_PCI=y
+CONFIG_BCMA_HOST_PCI=y
+CONFIG_BCMA_HOST_PCI_POSSIBLE=y
+CONFIG_BCMA_HOST_SOC=y
+CONFIG_BGMAC=y
+CONFIG_BOUNCE=y
+CONFIG_CACHE_L2X0=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK=y
+CONFIG_CLKSRC_MMIO=y
+CONFIG_CLKSRC_OF=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_COMMON_CLK=y
+CONFIG_COMMON_CLK_IPROC=y
+CONFIG_CPU_32v6K=y
+CONFIG_CPU_32v7=y
+CONFIG_CPU_ABRT_EV7=y
+# CONFIG_CPU_BPREDICT_DISABLE is not set
+CONFIG_CPU_CACHE_V7=y
+CONFIG_CPU_CACHE_VIPT=y
+CONFIG_CPU_COPY_V6=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+CONFIG_CPU_HAS_ASID=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+CONFIG_CPU_PABRT_V7=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_TLB_V7=y
+CONFIG_CPU_V7=y
+CONFIG_CRC16=y
+CONFIG_CRYPTO_DEFLATE=y
+# CONFIG_CRYPTO_JITTERENTROPY is not set
+CONFIG_CRYPTO_LZO=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_WORKQUEUE=y
+CONFIG_CRYPTO_XZ=y
+CONFIG_DCACHE_WORD_ACCESS=y
+CONFIG_DEBUG_BCM_5301X=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_LL=y
+CONFIG_DEBUG_LL_INCLUDE="debug/8250.S"
+CONFIG_DEBUG_UART_8250=y
+# CONFIG_DEBUG_UART_8250_FLOW_CONTROL is not set
+CONFIG_DEBUG_UART_8250_SHIFT=0
+CONFIG_DEBUG_UART_PHYS=0x18000300
+CONFIG_DEBUG_UART_VIRT=0xf1000300
+CONFIG_DEBUG_UNCOMPRESS=y
+CONFIG_DEBUG_USER=y
+CONFIG_DTC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_EDAC_ATOMIC_SCRUB=y
+CONFIG_EDAC_SUPPORT=y
+CONFIG_FIXED_PHY=y
+CONFIG_FIX_EARLYCON_MEM=y
+CONFIG_FRAME_POINTER=y
+CONFIG_GENERIC_ALLOCATOR=y
+CONFIG_GENERIC_BUG=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
+CONFIG_GENERIC_IDLE_POLL_SETUP=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_IRQ_SHOW_LEVEL=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_PINCONF=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GENERIC_STRNCPY_FROM_USER=y
+CONFIG_GENERIC_STRNLEN_USER=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIOLIB_IRQCHIP=y
+CONFIG_GPIO_74X164=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_HANDLE_DOMAIN_IRQ=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_HAS_DMA=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT_MAP=y
+# CONFIG_HAVE_64BIT_ALIGNED_ACCESS is not set
+CONFIG_HAVE_ARCH_AUDITSYSCALL=y
+CONFIG_HAVE_ARCH_BITREVERSE=y
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_PFN_VALID=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_ARM_SCU=y
+CONFIG_HAVE_ARM_TWD=y
+# CONFIG_HAVE_BOOTMEM_INFO_NODE is not set
+CONFIG_HAVE_BPF_JIT=y
+CONFIG_HAVE_CC_STACKPROTECTOR=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_CLK_PREPARE=y
+CONFIG_HAVE_CONTEXT_TRACKING=y
+CONFIG_HAVE_C_RECORDMCOUNT=y
+CONFIG_HAVE_DEBUG_KMEMLEAK=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_HAVE_IDE=y
+CONFIG_HAVE_IRQ_TIME_ACCOUNTING=y
+CONFIG_HAVE_KERNEL_GZIP=y
+CONFIG_HAVE_KERNEL_LZ4=y
+CONFIG_HAVE_KERNEL_LZMA=y
+CONFIG_HAVE_KERNEL_LZO=y
+CONFIG_HAVE_KERNEL_XZ=y
+CONFIG_HAVE_MEMBLOCK=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_OPTPROBES=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_PERF_REGS=y
+CONFIG_HAVE_PERF_USER_STACK_DUMP=y
+CONFIG_HAVE_PROC_CPU=y
+CONFIG_HAVE_REGS_AND_STACK_ACCESS_API=y
+CONFIG_HAVE_SMP=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_UID16=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HIGHMEM=y
+# CONFIG_HIGHPTE is not set
+CONFIG_HZ_FIXED=0
+CONFIG_HZ_PERIODIC=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IOMMU_HELPER=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_DOMAIN_HIERARCHY=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_LIBFDT=y
+CONFIG_LOCK_SPIN_ON_OWNER=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_MAC80211_STA_HASH_MAX_SIZE=0
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIGHT_HAVE_CACHE_L2X0=y
+CONFIG_MIGHT_HAVE_PCI=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MTD_BCM47XX_PARTS=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BRCMNAND=y
+CONFIG_MTD_NAND_ECC=y
+# CONFIG_MTD_PHYSMAP_OF is not set
+CONFIG_MTD_SPI_BCM53XXSPIFLASH=y
+CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_UBI=y
+CONFIG_MTD_UBI_BEB_LIMIT=20
+CONFIG_MTD_UBI_BLOCK=y
+# CONFIG_MTD_UBI_FASTMAP is not set
+# CONFIG_MTD_UBI_GLUEBI is not set
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MULTI_IRQ_HANDLER=y
+CONFIG_MUTEX_SPIN_ON_OWNER=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NO_BOOTMEM=y
+CONFIG_NR_CPUS=2
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=y
+CONFIG_OF_ADDRESS_PCI=y
+CONFIG_OF_EARLY_FLATTREE=y
+CONFIG_OF_FLATTREE=y
+CONFIG_OF_GPIO=y
+CONFIG_OF_IRQ=y
+CONFIG_OF_MDIO=y
+CONFIG_OF_MTD=y
+CONFIG_OF_NET=y
+CONFIG_OF_PCI=y
+CONFIG_OF_PCI_IRQ=y
+CONFIG_OF_RESERVED_MEM=y
+CONFIG_OLD_SIGACTION=y
+CONFIG_OLD_SIGSUSPEND3=y
+CONFIG_OUTER_CACHE=y
+CONFIG_OUTER_CACHE_SYNC=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PCI=y
+CONFIG_PCIE_IPROC=y
+CONFIG_PCIE_IPROC_BCMA=y
+# CONFIG_PCIE_IPROC_PLATFORM is not set
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_DOMAINS_GENERIC=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PINCTRL=y
+# CONFIG_PL310_ERRATA_588369 is not set
+CONFIG_PL310_ERRATA_727915=y
+CONFIG_PL310_ERRATA_753970=y
+CONFIG_PL310_ERRATA_769419=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_RWSEM_SPIN_ON_OWNER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCHED_INFO is not set
+# CONFIG_SCSI_DMA is not set
+# CONFIG_SERIAL_AMBA_PL010 is not set
+# CONFIG_SERIAL_AMBA_PL011 is not set
+CONFIG_SERIAL_OF_PLATFORM=y
+# CONFIG_SG_SPLIT is not set
+CONFIG_SMP=y
+CONFIG_SMP_ON_UP=y
+CONFIG_SPARSE_IRQ=y
+CONFIG_SPI=y
+CONFIG_SPI_BCM53XX=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+CONFIG_SRCU=y
+CONFIG_STOP_MACHINE=y
+# CONFIG_SUNXI_SRAM is not set
+CONFIG_SWCONFIG=y
+CONFIG_SWIOTLB=y
+CONFIG_SWP_EMULATE=y
+# CONFIG_SYSTEM_DATA_VERIFICATION is not set
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+# CONFIG_THUMB2_KERNEL is not set
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_RCU=y
+CONFIG_UBIFS_FS=y
+# CONFIG_UBIFS_FS_ADVANCED_COMPR is not set
+CONFIG_UBIFS_FS_LZO=y
+CONFIG_UBIFS_FS_XZ=y
+CONFIG_UBIFS_FS_ZLIB=y
+CONFIG_UID16=y
+CONFIG_UNCOMPRESS_INCLUDE="debug/uncompress.h"
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_VECTORS_BASE=0xffff0000
+# CONFIG_VFP is not set
+CONFIG_WATCHDOG_CORE=y
+CONFIG_XPS=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_BCJ=y
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Kconfig b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Kconfig
new file mode 100644
index 0000000..6bed119
--- /dev/null
+++ b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Kconfig
@@ -0,0 +1,11 @@
+config BCM47XX_NVRAM
+ bool "Broadcom NVRAM driver"
+ depends on BCM47XX || ARCH_BCM_5301X
+ help
+ Broadcom home routers contain flash partition called "nvram" with all
+ important hardware configuration as well as some minor user setup.
+ NVRAM partition contains a text-like data representing name=value
+ pairs.
+ This driver provides an easy way to get value of requested parameter.
+ It simply reads content of NVRAM and parses it. It doesn't control any
+ hardware part itself.
diff --git a/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Makefile b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Makefile
new file mode 100644
index 0000000..d0e6835
--- /dev/null
+++ b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_BCM47XX_NVRAM) += bcm47xx_nvram.o
diff --git a/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/bcm47xx_nvram.c b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/bcm47xx_nvram.c
new file mode 100644
index 0000000..87add3f
--- /dev/null
+++ b/target/linux/bcm53xx/files-4.1/drivers/firmware/broadcom/bcm47xx_nvram.c
@@ -0,0 +1,248 @@
+/*
+ * BCM947xx nvram variable access
+ *
+ * Copyright (C) 2005 Broadcom Corporation
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mtd/mtd.h>
+#include <linux/bcm47xx_nvram.h>
+
+#define NVRAM_MAGIC 0x48534C46 /* 'FLSH' */
+#define NVRAM_SPACE 0x10000
+#define NVRAM_MAX_GPIO_ENTRIES 32
+#define NVRAM_MAX_GPIO_VALUE_LEN 30
+
+#define FLASH_MIN 0x00020000 /* Minimum flash size */
+
+struct nvram_header {
+ u32 magic;
+ u32 len;
+ u32 crc_ver_init; /* 0:7 crc, 8:15 ver, 16:31 sdram_init */
+ u32 config_refresh; /* 0:15 sdram_config, 16:31 sdram_refresh */
+ u32 config_ncdl; /* ncdl values for memc */
+};
+
+static char nvram_buf[NVRAM_SPACE];
+static size_t nvram_len;
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
+
+static u32 find_nvram_size(void __iomem *end)
+{
+ struct nvram_header __iomem *header;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
+ header = (struct nvram_header *)(end - nvram_sizes[i]);
+ if (header->magic == NVRAM_MAGIC)
+ return nvram_sizes[i];
+ }
+
+ return 0;
+}
+
+/* Probe for NVRAM header */
+static int nvram_find_and_copy(void __iomem *iobase, u32 lim)
+{
+ struct nvram_header __iomem *header;
+ int i;
+ u32 off;
+ u32 *src, *dst;
+ u32 size;
+
+ if (nvram_len) {
+ pr_warn("nvram already initialized\n");
+ return -EEXIST;
+ }
+
+ /* TODO: when nvram is on nand flash check for bad blocks first. */
+ off = FLASH_MIN;
+ while (off <= lim) {
+ /* Windowed flash access */
+ size = find_nvram_size(iobase + off);
+ if (size) {
+ header = (struct nvram_header *)(iobase + off - size);
+ goto found;
+ }
+ off <<= 1;
+ }
+
+ /* Try embedded NVRAM at 4 KB and 1 KB as last resorts */
+ header = (struct nvram_header *)(iobase + 4096);
+ if (header->magic == NVRAM_MAGIC) {
+ size = NVRAM_SPACE;
+ goto found;
+ }
+
+ header = (struct nvram_header *)(iobase + 1024);
+ if (header->magic == NVRAM_MAGIC) {
+ size = NVRAM_SPACE;
+ goto found;
+ }
+
+ pr_err("no nvram found\n");
+ return -ENXIO;
+
+found:
+ src = (u32 *)header;
+ dst = (u32 *)nvram_buf;
+ for (i = 0; i < sizeof(struct nvram_header); i += 4)
+ *dst++ = __raw_readl(src++);
+ header = (struct nvram_header *)nvram_buf;
+ nvram_len = header->len;
+ if (nvram_len > size) {
+ pr_err("The nvram size according to the header seems to be bigger than the partition on flash\n");
+ nvram_len = size;
+ }
+ if (nvram_len >= NVRAM_SPACE) {
+ pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+ header->len, NVRAM_SPACE - 1);
+ nvram_len = NVRAM_SPACE - 1;
+ }
+ /* proceed reading data after header */
+ for (; i < nvram_len; i += 4)
+ *dst++ = readl(src++);
+ nvram_buf[NVRAM_SPACE - 1] = '\0';
+
+ return 0;
+}
+
+/*
+ * On bcm47xx we need access to the NVRAM very early, so we can't use mtd
+ * subsystem to access flash. We can't even use platform device / driver to
+ * store memory offset.
+ * To handle this we provide following symbol. It's supposed to be called as
+ * soon as we get info about flash device, before any NVRAM entry is needed.
+ */
+int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
+{
+ void __iomem *iobase;
+ int err;
+
+ iobase = ioremap_nocache(base, lim);
+ if (!iobase)
+ return -ENOMEM;
+
+ err = nvram_find_and_copy(iobase, lim);
+
+ iounmap(iobase);
+
+ return err;
+}
+
+static int nvram_init(void)
+{
+#ifdef CONFIG_MTD
+ struct mtd_info *mtd;
+ struct nvram_header header;
+ size_t bytes_read;
+ int err;
+
+ mtd = get_mtd_device_nm("nvram");
+ if (IS_ERR(mtd))
+ return -ENODEV;
+
+ err = mtd_read(mtd, 0, sizeof(header), &bytes_read, (uint8_t *)&header);
+ if (!err && header.magic == NVRAM_MAGIC &&
+ header.len > sizeof(header)) {
+ nvram_len = header.len;
+ if (nvram_len >= NVRAM_SPACE) {
+ pr_err("nvram on flash (%i bytes) is bigger than the reserved space in memory, will just copy the first %i bytes\n",
+ header.len, NVRAM_SPACE);
+ nvram_len = NVRAM_SPACE - 1;
+ }
+
+ err = mtd_read(mtd, 0, nvram_len, &nvram_len,
+ (u8 *)nvram_buf);
+ return err;
+ }
+#endif
+
+ return -ENXIO;
+}
+
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len)
+{
+ char *var, *value, *end, *eq;
+ int err;
+
+ if (!name)
+ return -EINVAL;
+
+ if (!nvram_len) {
+ err = nvram_init();
+ if (err)
+ return err;
+ }
+
+ /* Look for name=value and return value */
+ var = &nvram_buf[sizeof(struct nvram_header)];
+ end = nvram_buf + sizeof(nvram_buf);
+ while (var < end && *var) {
+ eq = strchr(var, '=');
+ if (!eq)
+ break;
+ value = eq + 1;
+ if (eq - var == strlen(name) &&
+ strncmp(var, name, eq - var) == 0)
+ return snprintf(val, val_len, "%s", value);
+ var = value + strlen(value) + 1;
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_getenv);
+
+int bcm47xx_nvram_gpio_pin(const char *name)
+{
+ int i, err;
+ char nvram_var[] = "gpioXX";
+ char buf[NVRAM_MAX_GPIO_VALUE_LEN];
+
+ /* TODO: Optimize it to don't call getenv so many times */
+ for (i = 0; i < NVRAM_MAX_GPIO_ENTRIES; i++) {
+ err = snprintf(nvram_var, sizeof(nvram_var), "gpio%i", i);
+ if (err <= 0)
+ continue;
+ err = bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf));
+ if (err <= 0)
+ continue;
+ if (!strcmp(name, buf))
+ return i;
+ }
+ return -ENOENT;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_gpio_pin);
+
+char *bcm47xx_nvram_get_contents(size_t *nvram_size)
+{
+ int err;
+ char *nvram;
+
+ if (!nvram_len) {
+ err = nvram_init();
+ if (err)
+ return NULL;
+ }
+
+ *nvram_size = nvram_len - sizeof(struct nvram_header);
+ nvram = vmalloc(*nvram_size);
+ if (!nvram)
+ return NULL;
+ memcpy(nvram, &nvram_buf[sizeof(struct nvram_header)], *nvram_size);
+
+ return nvram;
+}
+EXPORT_SYMBOL(bcm47xx_nvram_get_contents);
+
+MODULE_LICENSE("GPLv2");
diff --git a/target/linux/bcm53xx/files-4.1/include/linux/bcm47xx_nvram.h b/target/linux/bcm53xx/files-4.1/include/linux/bcm47xx_nvram.h
new file mode 100644
index 0000000..2793652
--- /dev/null
+++ b/target/linux/bcm53xx/files-4.1/include/linux/bcm47xx_nvram.h
@@ -0,0 +1,49 @@
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef __BCM47XX_NVRAM_H
+#define __BCM47XX_NVRAM_H
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+
+#ifdef CONFIG_BCM47XX_NVRAM
+int bcm47xx_nvram_init_from_mem(u32 base, u32 lim);
+int bcm47xx_nvram_getenv(const char *name, char *val, size_t val_len);
+int bcm47xx_nvram_gpio_pin(const char *name);
+char *bcm47xx_nvram_get_contents(size_t *val_len);
+static inline void bcm47xx_nvram_release_contents(char *nvram)
+{
+ vfree(nvram);
+};
+#else
+static inline int bcm47xx_nvram_init_from_mem(u32 base, u32 lim)
+{
+ return -ENOTSUPP;
+};
+static inline int bcm47xx_nvram_getenv(const char *name, char *val,
+ size_t val_len)
+{
+ return -ENOTSUPP;
+};
+static inline int bcm47xx_nvram_gpio_pin(const char *name)
+{
+ return -ENOTSUPP;
+};
+
+static inline char *bcm47xx_nvram_get_contents(size_t *val_len)
+{
+ return NULL;
+};
+
+static inline void bcm47xx_nvram_release_contents(char *nvram)
+{
+};
+#endif
+
+#endif /* __BCM47XX_NVRAM_H */
diff --git a/target/linux/bcm53xx/files/drivers/misc/bcm47xx-sprom.c b/target/linux/bcm53xx/files/drivers/misc/bcm47xx-sprom.c
new file mode 100644
index 0000000..b695f0a
--- /dev/null
+++ b/target/linux/bcm53xx/files/drivers/misc/bcm47xx-sprom.c
@@ -0,0 +1,691 @@
+/*
+ * Copyright (C) 2004 Florian Schirmer <jolt@tuxbox.org>
+ * Copyright (C) 2006 Felix Fietkau <nbd@openwrt.org>
+ * Copyright (C) 2006 Michael Buesch <m@bues.ch>
+ * Copyright (C) 2010 Waldemar Brodkorb <wbx@openadk.org>
+ * Copyright (C) 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
+ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/of_address.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/ssb/ssb.h>
+#include <linux/bcma/bcma.h>
+#include <linux/bcm47xx_nvram.h>
+#include <linux/if_ether.h>
+#include <linux/etherdevice.h>
+
+static void create_key(const char *prefix, const char *postfix,
+ const char *name, char *buf, int len)
+{
+ if (prefix && postfix)
+ snprintf(buf, len, "%s%s%s", prefix, name, postfix);
+ else if (prefix)
+ snprintf(buf, len, "%s%s", prefix, name);
+ else if (postfix)
+ snprintf(buf, len, "%s%s", name, postfix);
+ else
+ snprintf(buf, len, "%s", name);
+}
+
+static int get_nvram_var(const char *prefix, const char *postfix,
+ const char *name, char *buf, int len, bool fallback)
+{
+ char key[40];
+ int err;
+
+ create_key(prefix, postfix, name, key, sizeof(key));
+
+ err = bcm47xx_nvram_getenv(key, buf, len);
+ if (fallback && err == -ENOENT && prefix) {
+ create_key(NULL, postfix, name, key, sizeof(key));
+ err = bcm47xx_nvram_getenv(key, buf, len);
+ }
+ return err;
+}
+
+#define NVRAM_READ_VAL(type) \
+static void nvram_read_ ## type (const char *prefix, \
+ const char *postfix, const char *name, \
+ type *val, type allset, bool fallback) \
+{ \
+ char buf[100]; \
+ int err; \
+ type var; \
+ \
+ err = get_nvram_var(prefix, postfix, name, buf, sizeof(buf), \
+ fallback); \
+ if (err < 0) \
+ return; \
+ err = kstrto ## type(strim(buf), 0, &var); \
+ if (err) { \
+ pr_warn("can not parse nvram name %s%s%s with value %s got %i\n", \
+ prefix, name, postfix, buf, err); \
+ return; \
+ } \
+ if (allset && var == allset) \
+ return; \
+ *val = var; \
+}
+
+NVRAM_READ_VAL(u8)
+NVRAM_READ_VAL(s8)
+NVRAM_READ_VAL(u16)
+NVRAM_READ_VAL(u32)
+
+#undef NVRAM_READ_VAL
+
+static void nvram_read_u32_2(const char *prefix, const char *name,
+ u16 *val_lo, u16 *val_hi, bool fallback)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ err = kstrtou32(strim(buf), 0, &val);
+ if (err) {
+ pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+ prefix, name, buf, err);
+ return;
+ }
+ *val_lo = (val & 0x0000FFFFU);
+ *val_hi = (val & 0xFFFF0000U) >> 16;
+}
+
+static void nvram_read_leddc(const char *prefix, const char *name,
+ u8 *leddc_on_time, u8 *leddc_off_time,
+ bool fallback)
+{
+ char buf[100];
+ int err;
+ u32 val;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ err = kstrtou32(strim(buf), 0, &val);
+ if (err) {
+ pr_warn("can not parse nvram name %s%s with value %s got %i\n",
+ prefix, name, buf, err);
+ return;
+ }
+
+ if (val == 0xffff || val == 0xffffffff)
+ return;
+
+ *leddc_on_time = val & 0xff;
+ *leddc_off_time = (val >> 16) & 0xff;
+}
+
+static void bcm47xx_nvram_parse_macaddr(char *buf, u8 macaddr[6])
+{
+ if (strchr(buf, ':'))
+ sscanf(buf, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else if (strchr(buf, '-'))
+ sscanf(buf, "%hhx-%hhx-%hhx-%hhx-%hhx-%hhx", &macaddr[0],
+ &macaddr[1], &macaddr[2], &macaddr[3], &macaddr[4],
+ &macaddr[5]);
+ else
+ pr_warn("Can not parse mac address: %s\n", buf);
+}
+
+static void nvram_read_macaddr(const char *prefix, const char *name,
+ u8 val[6], bool fallback)
+{
+ char buf[100];
+ int err;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+
+ bcm47xx_nvram_parse_macaddr(buf, val);
+}
+
+static void nvram_read_alpha2(const char *prefix, const char *name,
+ char val[2], bool fallback)
+{
+ char buf[10];
+ int err;
+
+ err = get_nvram_var(prefix, NULL, name, buf, sizeof(buf), fallback);
+ if (err < 0)
+ return;
+ if (buf[0] == '0')
+ return;
+ if (strlen(buf) > 2) {
+ pr_warn("alpha2 is too long %s\n", buf);
+ return;
+ }
+ memcpy(val, buf, 2);
+}
+
+/* This is one-function-only macro, it uses local "sprom" variable! */
+#define ENTRY(_revmask, _type, _prefix, _name, _val, _allset, _fallback) \
+ if (_revmask & BIT(sprom->revision)) \
+ nvram_read_ ## _type(_prefix, NULL, _name, &sprom->_val, \
+ _allset, _fallback)
+/*
+ * Special version of filling function that can be safely called for any SPROM
+ * revision. For every NVRAM to SPROM mapping it contains bitmask of revisions
+ * for which the mapping is valid.
+ * It obviously requires some hexadecimal/bitmasks knowledge, but allows
+ * writing cleaner code (easy revisions handling).
+ * Note that while SPROM revision 0 was never used, we still keep BIT(0)
+ * reserved for it, just to keep numbering sane.
+ */
+static void bcm47xx_sprom_fill_auto(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ const char *pre = prefix;
+ bool fb = fallback;
+
+ /* Broadcom extracts it for rev 8+ but it was found on 2 and 4 too */
+ ENTRY(0xfffffffe, u16, pre, "devid", dev_id, 0, fallback);
+
+ ENTRY(0xfffffffe, u16, pre, "boardrev", board_rev, 0, true);
+ ENTRY(0xfffffffe, u32, pre, "boardflags", boardflags, 0, fb);
+ ENTRY(0xfffffff0, u32, pre, "boardflags2", boardflags2, 0, fb);
+ ENTRY(0xfffff800, u32, pre, "boardflags3", boardflags3, 0, fb);
+ ENTRY(0x00000002, u16, pre, "boardflags", boardflags_lo, 0, fb);
+ ENTRY(0xfffffffc, u16, pre, "boardtype", board_type, 0, true);
+ ENTRY(0xfffffffe, u16, pre, "boardnum", board_num, 0, fb);
+ ENTRY(0x00000002, u8, pre, "cc", country_code, 0, fb);
+ ENTRY(0xfffffff8, u8, pre, "regrev", regrev, 0, fb);
+
+ ENTRY(0xfffffffe, u8, pre, "ledbh0", gpio0, 0xff, fb);
+ ENTRY(0xfffffffe, u8, pre, "ledbh1", gpio1, 0xff, fb);
+ ENTRY(0xfffffffe, u8, pre, "ledbh2", gpio2, 0xff, fb);
+ ENTRY(0xfffffffe, u8, pre, "ledbh3", gpio3, 0xff, fb);
+
+ ENTRY(0x0000070e, u16, pre, "pa0b0", pa0b0, 0, fb);
+ ENTRY(0x0000070e, u16, pre, "pa0b1", pa0b1, 0, fb);
+ ENTRY(0x0000070e, u16, pre, "pa0b2", pa0b2, 0, fb);
+ ENTRY(0x0000070e, u8, pre, "pa0itssit", itssi_bg, 0, fb);
+ ENTRY(0x0000070e, u8, pre, "pa0maxpwr", maxpwr_bg, 0, fb);
+
+ ENTRY(0x0000070c, u8, pre, "opo", opo, 0, fb);
+ ENTRY(0xfffffffe, u8, pre, "aa2g", ant_available_bg, 0, fb);
+ ENTRY(0xfffffffe, u8, pre, "aa5g", ant_available_a, 0, fb);
+ ENTRY(0x000007fe, s8, pre, "ag0", antenna_gain.a0, 0, fb);
+ ENTRY(0x000007fe, s8, pre, "ag1", antenna_gain.a1, 0, fb);
+ ENTRY(0x000007f0, s8, pre, "ag2", antenna_gain.a2, 0, fb);
+ ENTRY(0x000007f0, s8, pre, "ag3", antenna_gain.a3, 0, fb);
+
+ ENTRY(0x0000070e, u16, pre, "pa1b0", pa1b0, 0, fb);
+ ENTRY(0x0000070e, u16, pre, "pa1b1", pa1b1, 0, fb);
+ ENTRY(0x0000070e, u16, pre, "pa1b2", pa1b2, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1lob0", pa1lob0, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1lob1", pa1lob1, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1lob2", pa1lob2, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1hib0", pa1hib0, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1hib1", pa1hib1, 0, fb);
+ ENTRY(0x0000070c, u16, pre, "pa1hib2", pa1hib2, 0, fb);
+ ENTRY(0x0000070e, u8, pre, "pa1itssit", itssi_a, 0, fb);
+ ENTRY(0x0000070e, u8, pre, "pa1maxpwr", maxpwr_a, 0, fb);
+ ENTRY(0x0000070c, u8, pre, "pa1lomaxpwr", maxpwr_al, 0, fb);
+ ENTRY(0x0000070c, u8, pre, "pa1himaxpwr", maxpwr_ah, 0, fb);
+
+ ENTRY(0x00000708, u8, pre, "bxa2g", bxa2g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssisav2g", rssisav2g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssismc2g", rssismc2g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssismf2g", rssismf2g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "bxa5g", bxa5g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssisav5g", rssisav5g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssismc5g", rssismc5g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "rssismf5g", rssismf5g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "tri2g", tri2g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "tri5g", tri5g, 0, fb);
+ ENTRY(0x00000708, u8, pre, "tri5gl", tri5gl, 0, fb);
+ ENTRY(0x00000708, u8, pre, "tri5gh", tri5gh, 0, fb);
+ ENTRY(0x00000708, s8, pre, "rxpo2g", rxpo2g, 0, fb);
+ ENTRY(0x00000708, s8, pre, "rxpo5g", rxpo5g, 0, fb);
+ ENTRY(0xfffffff0, u8, pre, "txchain", txchain, 0xf, fb);
+ ENTRY(0xfffffff0, u8, pre, "rxchain", rxchain, 0xf, fb);
+ ENTRY(0xfffffff0, u8, pre, "antswitch", antswitch, 0xff, fb);
+ ENTRY(0x00000700, u8, pre, "tssipos2g", fem.ghz2.tssipos, 0, fb);
+ ENTRY(0x00000700, u8, pre, "extpagain2g", fem.ghz2.extpa_gain, 0, fb);
+ ENTRY(0x00000700, u8, pre, "pdetrange2g", fem.ghz2.pdet_range, 0, fb);
+ ENTRY(0x00000700, u8, pre, "triso2g", fem.ghz2.tr_iso, 0, fb);
+ ENTRY(0x00000700, u8, pre, "antswctl2g", fem.ghz2.antswlut, 0, fb);
+ ENTRY(0x00000700, u8, pre, "tssipos5g", fem.ghz5.tssipos, 0, fb);
+ ENTRY(0x00000700, u8, pre, "extpagain5g", fem.ghz5.extpa_gain, 0, fb);
+ ENTRY(0x00000700, u8, pre, "pdetrange5g", fem.ghz5.pdet_range, 0, fb);
+ ENTRY(0x00000700, u8, pre, "triso5g", fem.ghz5.tr_iso, 0, fb);
+ ENTRY(0x00000700, u8, pre, "antswctl5g", fem.ghz5.antswlut, 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid2ga0", txpid2g[0], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid2ga1", txpid2g[1], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid2ga2", txpid2g[2], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid2ga3", txpid2g[3], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5ga0", txpid5g[0], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5ga1", txpid5g[1], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5ga2", txpid5g[2], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5ga3", txpid5g[3], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gla0", txpid5gl[0], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gla1", txpid5gl[1], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gla2", txpid5gl[2], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gla3", txpid5gl[3], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gha0", txpid5gh[0], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gha1", txpid5gh[1], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gha2", txpid5gh[2], 0, fb);
+ ENTRY(0x000000f0, u8, pre, "txpid5gha3", txpid5gh[3], 0, fb);
+
+ ENTRY(0xffffff00, u8, pre, "tempthresh", tempthresh, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "tempoffset", tempoffset, 0, fb);
+ ENTRY(0xffffff00, u16, pre, "rawtempsense", rawtempsense, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "measpower", measpower, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "tempsense_slope", tempsense_slope, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "tempcorrx", tempcorrx, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "tempsense_option", tempsense_option, 0, fb);
+ ENTRY(0x00000700, u8, pre, "freqoffset_corr", freqoffset_corr, 0, fb);
+ ENTRY(0x00000700, u8, pre, "iqcal_swp_dis", iqcal_swp_dis, 0, fb);
+ ENTRY(0x00000700, u8, pre, "hw_iqcal_en", hw_iqcal_en, 0, fb);
+ ENTRY(0x00000700, u8, pre, "elna2g", elna2g, 0, fb);
+ ENTRY(0x00000700, u8, pre, "elna5g", elna5g, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "phycal_tempdelta", phycal_tempdelta, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "temps_period", temps_period, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "temps_hysteresis", temps_hysteresis, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "measpower1", measpower1, 0, fb);
+ ENTRY(0xffffff00, u8, pre, "measpower2", measpower2, 0, fb);
+
+ ENTRY(0x000001f0, u16, pre, "cck2gpo", cck2gpo, 0, fb);
+ ENTRY(0x000001f0, u32, pre, "ofdm2gpo", ofdm2gpo, 0, fb);
+ ENTRY(0x000001f0, u32, pre, "ofdm5gpo", ofdm5gpo, 0, fb);
+ ENTRY(0x000001f0, u32, pre, "ofdm5glpo", ofdm5glpo, 0, fb);
+ ENTRY(0x000001f0, u32, pre, "ofdm5ghpo", ofdm5ghpo, 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo0", mcs2gpo[0], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo1", mcs2gpo[1], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo2", mcs2gpo[2], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo3", mcs2gpo[3], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo4", mcs2gpo[4], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo5", mcs2gpo[5], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo6", mcs2gpo[6], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs2gpo7", mcs2gpo[7], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo0", mcs5gpo[0], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo1", mcs5gpo[1], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo2", mcs5gpo[2], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo3", mcs5gpo[3], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo4", mcs5gpo[4], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo5", mcs5gpo[5], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo6", mcs5gpo[6], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5gpo7", mcs5gpo[7], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo0", mcs5glpo[0], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo1", mcs5glpo[1], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo2", mcs5glpo[2], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo3", mcs5glpo[3], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo4", mcs5glpo[4], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo5", mcs5glpo[5], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo6", mcs5glpo[6], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5glpo7", mcs5glpo[7], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo0", mcs5ghpo[0], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo1", mcs5ghpo[1], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo2", mcs5ghpo[2], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo3", mcs5ghpo[3], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo4", mcs5ghpo[4], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo5", mcs5ghpo[5], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo6", mcs5ghpo[6], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "mcs5ghpo7", mcs5ghpo[7], 0, fb);
+ ENTRY(0x000001f0, u16, pre, "cddpo", cddpo, 0, fb);
+ ENTRY(0x000001f0, u16, pre, "stbcpo", stbcpo, 0, fb);
+ ENTRY(0x000001f0, u16, pre, "bw40po", bw40po, 0, fb);
+ ENTRY(0x000001f0, u16, pre, "bwduppo", bwduppo, 0, fb);
+
+ ENTRY(0xfffffe00, u16, pre, "cckbw202gpo", cckbw202gpo, 0, fb);
+ ENTRY(0xfffffe00, u16, pre, "cckbw20ul2gpo", cckbw20ul2gpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw202gpo", legofdmbw202gpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw20ul2gpo", legofdmbw20ul2gpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw205glpo", legofdmbw205glpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw20ul5glpo", legofdmbw20ul5glpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw205gmpo", legofdmbw205gmpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw20ul5gmpo", legofdmbw20ul5gmpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw205ghpo", legofdmbw205ghpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "legofdmbw20ul5ghpo", legofdmbw20ul5ghpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw202gpo", mcsbw202gpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "mcsbw20ul2gpo", mcsbw20ul2gpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw402gpo", mcsbw402gpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw205glpo", mcsbw205glpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "mcsbw20ul5glpo", mcsbw20ul5glpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw405glpo", mcsbw405glpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw205gmpo", mcsbw205gmpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "mcsbw20ul5gmpo", mcsbw20ul5gmpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw405gmpo", mcsbw405gmpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw205ghpo", mcsbw205ghpo, 0, fb);
+ ENTRY(0x00000600, u32, pre, "mcsbw20ul5ghpo", mcsbw20ul5ghpo, 0, fb);
+ ENTRY(0xfffffe00, u32, pre, "mcsbw405ghpo", mcsbw405ghpo, 0, fb);
+ ENTRY(0x00000600, u16, pre, "mcs32po", mcs32po, 0, fb);
+ ENTRY(0x00000600, u16, pre, "legofdm40duppo", legofdm40duppo, 0, fb);
+ ENTRY(0x00000700, u8, pre, "pcieingress_war", pcieingress_war, 0, fb);
+
+ /* TODO: rev 11 support */
+ ENTRY(0x00000700, u8, pre, "rxgainerr2ga0", rxgainerr2ga[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr2ga1", rxgainerr2ga[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr2ga2", rxgainerr2ga[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gla0", rxgainerr5gla[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gla1", rxgainerr5gla[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gla2", rxgainerr5gla[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gma0", rxgainerr5gma[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gma1", rxgainerr5gma[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gma2", rxgainerr5gma[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gha0", rxgainerr5gha[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gha1", rxgainerr5gha[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gha2", rxgainerr5gha[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gua0", rxgainerr5gua[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gua1", rxgainerr5gua[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "rxgainerr5gua2", rxgainerr5gua[2], 0, fb);
+
+ ENTRY(0xfffffe00, u8, pre, "sar2g", sar2g, 0, fb);
+ ENTRY(0xfffffe00, u8, pre, "sar5g", sar5g, 0, fb);
+
+ /* TODO: rev 11 support */
+ ENTRY(0x00000700, u8, pre, "noiselvl2ga0", noiselvl2ga[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl2ga1", noiselvl2ga[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl2ga2", noiselvl2ga[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gla0", noiselvl5gla[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gla1", noiselvl5gla[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gla2", noiselvl5gla[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gma0", noiselvl5gma[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gma1", noiselvl5gma[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gma2", noiselvl5gma[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gha0", noiselvl5gha[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gha1", noiselvl5gha[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gha2", noiselvl5gha[2], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gua0", noiselvl5gua[0], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gua1", noiselvl5gua[1], 0, fb);
+ ENTRY(0x00000700, u8, pre, "noiselvl5gua2", noiselvl5gua[2], 0, fb);
+}
+#undef ENTRY /* It's specififc, uses local variable, don't use it (again). */
+
+static void bcm47xx_fill_sprom_path_r4589(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ char postfix[2];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+ struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ snprintf(postfix, sizeof(postfix), "%i", i);
+ nvram_read_u8(prefix, postfix, "maxp2ga",
+ &pwr_info->maxpwr_2g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "itt2ga",
+ &pwr_info->itssi_2g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "itt5ga",
+ &pwr_info->itssi_5g, 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw0a",
+ &pwr_info->pa_2g[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw1a",
+ &pwr_info->pa_2g[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa2gw2a",
+ &pwr_info->pa_2g[2], 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5ga",
+ &pwr_info->maxpwr_5g, 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5gha",
+ &pwr_info->maxpwr_5gh, 0, fallback);
+ nvram_read_u8(prefix, postfix, "maxp5gla",
+ &pwr_info->maxpwr_5gl, 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw0a",
+ &pwr_info->pa_5g[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw1a",
+ &pwr_info->pa_5g[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw2a",
+ &pwr_info->pa_5g[2], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw0a",
+ &pwr_info->pa_5gl[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw1a",
+ &pwr_info->pa_5gl[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw2a",
+ &pwr_info->pa_5gl[2], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw0a",
+ &pwr_info->pa_5gh[0], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw1a",
+ &pwr_info->pa_5gh[1], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw2a",
+ &pwr_info->pa_5gh[2], 0, fallback);
+ }
+}
+
+static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ char postfix[2];
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sprom->core_pwr_info); i++) {
+ struct ssb_sprom_core_pwr_info *pwr_info = &sprom->core_pwr_info[i];
+ snprintf(postfix, sizeof(postfix), "%i", i);
+ nvram_read_u16(prefix, postfix, "pa2gw3a",
+ &pwr_info->pa_2g[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5gw3a",
+ &pwr_info->pa_5g[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5glw3a",
+ &pwr_info->pa_5gl[3], 0, fallback);
+ nvram_read_u16(prefix, postfix, "pa5ghw3a",
+ &pwr_info->pa_5gh[3], 0, fallback);
+ }
+}
+
+static bool bcm47xx_is_valid_mac(u8 *mac)
+{
+ return mac && !(mac[0] == 0x00 && mac[1] == 0x90 && mac[2] == 0x4c);
+}
+
+static int bcm47xx_increase_mac_addr(u8 *mac, u8 num)
+{
+ u8 *oui = mac + ETH_ALEN/2 - 1;
+ u8 *p = mac + ETH_ALEN - 1;
+
+ do {
+ (*p) += num;
+ if (*p > num)
+ break;
+ p--;
+ num = 1;
+ } while (p != oui);
+
+ if (p == oui) {
+ pr_err("unable to fetch mac address\n");
+ return -ENOENT;
+ }
+ return 0;
+}
+
+static int mac_addr_used = 2;
+
+static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,
+ const char *prefix, bool fallback)
+{
+ bool fb = fallback;
+
+ nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback);
+ nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0,
+ fallback);
+
+ nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback);
+ nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0,
+ fallback);
+ nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0,
+ fallback);
+
+ nvram_read_macaddr(prefix, "et2macaddr", sprom->et2mac, fb);
+ nvram_read_u8(prefix, NULL, "et2mdcport", &sprom->et2mdcport, 0, fb);
+ nvram_read_u8(prefix, NULL, "et2phyaddr", &sprom->et2phyaddr, 0, fb);
+
+ nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback);
+ nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);
+
+ /* The address prefix 00:90:4C is used by Broadcom in their initial
+ configuration. When a mac address with the prefix 00:90:4C is used
+ all devices from the same series are sharing the same mac address.
+ To prevent mac address collisions we replace them with a mac address
+ based on the base address. */
+ if (!bcm47xx_is_valid_mac(sprom->il0mac)) {
+ u8 mac[6];
+
+ nvram_read_macaddr(NULL, "et0macaddr", mac, false);
+ if (bcm47xx_is_valid_mac(mac)) {
+ int err = bcm47xx_increase_mac_addr(mac, mac_addr_used);
+
+ if (!err) {
+ ether_addr_copy(sprom->il0mac, mac);
+ mac_addr_used++;
+ }
+ }
+ }
+}
+
+static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ nvram_read_u32_2(prefix, "boardflags", &sprom->boardflags_lo,
+ &sprom->boardflags_hi, fallback);
+ nvram_read_u32_2(prefix, "boardflags2", &sprom->boardflags2_lo,
+ &sprom->boardflags2_hi, fallback);
+}
+
+void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix,
+ bool fallback)
+{
+ bcm47xx_fill_sprom_ethernet(sprom, prefix, fallback);
+ bcm47xx_fill_board_data(sprom, prefix, fallback);
+
+ nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0, fallback);
+
+ /* Entries requiring custom functions */
+ nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback);
+ if (sprom->revision >= 3)
+ nvram_read_leddc(prefix, "leddc", &sprom->leddc_on_time,
+ &sprom->leddc_off_time, fallback);
+
+ switch (sprom->revision) {
+ case 4:
+ case 5:
+ bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback);
+ bcm47xx_fill_sprom_path_r45(sprom, prefix, fallback);
+ break;
+ case 8:
+ case 9:
+ bcm47xx_fill_sprom_path_r4589(sprom, prefix, fallback);
+ break;
+ }
+
+ bcm47xx_sprom_fill_auto(sprom, prefix, fallback);
+}
+
+/*
+ * Having many NVRAM entries for PCI devices led to repeating prefixes like
+ * pci/1/1/ all the time and wasting flash space. So at some point Broadcom
+ * decided to introduce prefixes like 0: 1: 2: etc.
+ * If we find e.g. devpath0=pci/2/1 or devpath0=pci/2/1/ we should use 0:
+ * instead of pci/2/1/.
+ */
+static void bcm47xx_sprom_apply_prefix_alias(char *prefix, size_t prefix_size)
+{
+ size_t prefix_len = strlen(prefix);
+ size_t short_len = prefix_len - 1;
+ char nvram_var[10];
+ char buf[20];
+ int i;
+
+ if (prefix_len <= 0 || prefix[prefix_len - 1] != '/')
+ return;
+
+ for (i = 0; i < 3; i++) {
+ if (snprintf(nvram_var, sizeof(nvram_var), "devpath%d", i) <= 0)
+ continue;
+ if (bcm47xx_nvram_getenv(nvram_var, buf, sizeof(buf)) < 0)
+ continue;
+ if (!strcmp(buf, prefix) ||
+ (short_len && strlen(buf) == short_len && !strncmp(buf, prefix, short_len))) {
+ snprintf(prefix, prefix_size, "%d:", i);
+ return;
+ }
+ }
+}
+
+/*
+ * This function has to be called in a very precise moment. It has to be done:
+ * 1) After bcma registers flash cores, so we can read NVRAM.
+ * 2) Before any code needs SPROM content.
+ *
+ * This can be achieved only by using bcma callback.
+ */
+static int bcm47xx_sprom_init(struct bcma_bus *bus, struct ssb_sprom *out)
+{
+ char prefix[20];
+
+ switch (bus->hosttype) {
+ case BCMA_HOSTTYPE_PCI:
+ snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
+ pci_domain_nr(bus->host_pci->bus) + 1,
+ bus->host_pci->bus->number);
+ bcm47xx_sprom_apply_prefix_alias(prefix, sizeof(prefix));
+ bcm47xx_fill_sprom(out, prefix, false);
+ break;
+ case BCMA_HOSTTYPE_SOC:
+ bcm47xx_fill_sprom(out, NULL, false);
+ break;
+ default:
+ pr_err("Unable to fill SPROM for given hosttype.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+};
+
+static int bcm47xx_sprom_probe(struct platform_device *pdev)
+{
+ return bcma_arch_register_fallback_sprom(&bcm47xx_sprom_init);
+}
+
+static const struct of_device_id bcm47xx_sprom_of_match_table[] = {
+ { .compatible = "brcm,bcm47xx-sprom", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, bcm47xx_sprom_of_match_table);
+
+static struct platform_driver bcm47xx_sprom_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bcm47xx-sprom",
+ .of_match_table = bcm47xx_sprom_of_match_table,
+ /* driver unloading/unbinding currently not supported */
+ .suppress_bind_attrs = true,
+ },
+ .probe = bcm47xx_sprom_probe,
+};
+module_platform_driver(bcm47xx_sprom_driver);
+
+MODULE_AUTHOR("Hauke Mehrtens <hauke@hauke-m.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/target/linux/bcm53xx/files/drivers/mtd/spi-nor/bcm53xxspiflash.c b/target/linux/bcm53xx/files/drivers/mtd/spi-nor/bcm53xxspiflash.c
new file mode 100644
index 0000000..954b9c5
--- /dev/null
+++ b/target/linux/bcm53xx/files/drivers/mtd/spi-nor/bcm53xxspiflash.c
@@ -0,0 +1,231 @@
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <linux/mtd/spi-nor.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/cfi.h>
+#include <linux/mtd/partitions.h>
+
+static const char * const probes[] = { "ofpart", "bcm47xxpart", NULL };
+
+struct bcm53xxsf {
+ struct spi_device *spi;
+ struct mtd_info mtd;
+ struct spi_nor nor;
+};
+
+/**************************************************
+ * spi-nor API
+ **************************************************/
+
+static int bcm53xxspiflash_read_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+ int len)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+
+ return spi_write_then_read(b53sf->spi, &opcode, 1, buf, len);
+}
+
+static int bcm53xxspiflash_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf,
+ int len, int write_enable)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+ u8 *cmd = kzalloc(len + 1, GFP_KERNEL);
+ int err;
+
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd[0] = opcode;
+ memcpy(&cmd[1], buf, len);
+ err = spi_write(b53sf->spi, cmd, len + 1);
+
+ kfree(cmd);
+
+ return err;
+}
+
+static int bcm53xxspiflash_read(struct spi_nor *nor, loff_t from, size_t len,
+ size_t *retlen, u_char *buf)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+ struct spi_message m;
+ struct spi_transfer t[2] = { { 0 }, { 0 } };
+ unsigned char cmd[5];
+ int cmd_len = 0;
+ int err;
+
+ spi_message_init(&m);
+
+ cmd[cmd_len++] = SPINOR_OP_READ;
+ if (b53sf->mtd.size > 0x1000000)
+ cmd[cmd_len++] = (from & 0xFF000000) >> 24;
+ cmd[cmd_len++] = (from & 0x00FF0000) >> 16;
+ cmd[cmd_len++] = (from & 0x0000FF00) >> 8;
+ cmd[cmd_len++] = (from & 0x000000FF) >> 0;
+
+ t[0].tx_buf = cmd;
+ t[0].len = cmd_len;
+ spi_message_add_tail(&t[0], &m);
+
+ t[1].rx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+
+ err = spi_sync(b53sf->spi, &m);
+ if (err)
+ return err;
+
+ if (retlen && m.actual_length > cmd_len)
+ *retlen = m.actual_length - cmd_len;
+
+ return 0;
+}
+
+static void bcm53xxspiflash_write(struct spi_nor *nor, loff_t to, size_t len,
+ size_t *retlen, const u_char *buf)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+ struct spi_message m;
+ struct spi_transfer t = { 0 };
+ u8 *cmd = kzalloc(len + 5, GFP_KERNEL);
+ int cmd_len = 0;
+ int err;
+
+ if (!cmd)
+ return;
+
+ spi_message_init(&m);
+
+ cmd[cmd_len++] = nor->program_opcode;
+ if (b53sf->mtd.size > 0x1000000)
+ cmd[cmd_len++] = (to & 0xFF000000) >> 24;
+ cmd[cmd_len++] = (to & 0x00FF0000) >> 16;
+ cmd[cmd_len++] = (to & 0x0000FF00) >> 8;
+ cmd[cmd_len++] = (to & 0x000000FF) >> 0;
+ memcpy(&cmd[cmd_len], buf, len);
+
+ t.tx_buf = cmd;
+ t.len = cmd_len + len;
+ spi_message_add_tail(&t, &m);
+
+ err = spi_sync(b53sf->spi, &m);
+ if (err)
+ goto out;
+
+ if (retlen && m.actual_length > cmd_len)
+ *retlen += m.actual_length - cmd_len;
+
+out:
+ kfree(cmd);
+}
+
+static int bcm53xxspiflash_erase(struct spi_nor *nor, loff_t offs)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+ unsigned char cmd[5];
+ int i;
+
+ i = 0;
+ cmd[i++] = nor->erase_opcode;
+ if (b53sf->mtd.size > 0x1000000)
+ cmd[i++] = (offs & 0xFF000000) >> 24;
+ cmd[i++] = ((offs & 0x00FF0000) >> 16);
+ cmd[i++] = ((offs & 0x0000FF00) >> 8);
+ cmd[i++] = ((offs & 0x000000FF) >> 0);
+
+ return spi_write(b53sf->spi, cmd, i);
+}
+
+static const char *bcm53xxspiflash_chip_name(struct spi_nor *nor)
+{
+ struct bcm53xxsf *b53sf = nor->priv;
+ struct device *dev = &b53sf->spi->dev;
+ unsigned char cmd[4];
+ unsigned char resp[2];
+ int err;
+
+ /* SST and Winbond/NexFlash specific command */
+ cmd[0] = 0x90; /* Read Manufacturer / Device ID */
+ cmd[1] = 0;
+ cmd[2] = 0;
+ cmd[3] = 0;
+ err = spi_write_then_read(b53sf->spi, cmd, 4, resp, 2);
+ if (err < 0) {
+ dev_err(dev, "error reading SPI flash id\n");
+ return ERR_PTR(-EBUSY);
+ }
+ switch (resp[0]) {
+ case 0xef: /* Winbond/NexFlash */
+ switch (resp[1]) {
+ case 0x17:
+ return "w25q128";
+ }
+ dev_err(dev, "Unknown Winbond/NexFlash flash: %02X %02X\n",
+ resp[0], resp[1]);
+ return NULL;
+ }
+
+ /* TODO: Try more ID commands */
+
+ return NULL;
+}
+
+/**************************************************
+ * SPI driver
+ **************************************************/
+
+static int bcm53xxspiflash_probe(struct spi_device *spi)
+{
+ struct mtd_part_parser_data parser_data = {};
+ struct bcm53xxsf *b53sf;
+ struct spi_nor *nor;
+ int err;
+
+ b53sf = devm_kzalloc(&spi->dev, sizeof(*b53sf), GFP_KERNEL);
+ if (!b53sf)
+ return -ENOMEM;
+ spi_set_drvdata(spi, b53sf);
+
+ nor = &b53sf->nor;
+ b53sf->spi = spi;
+ b53sf->mtd.priv = &b53sf->nor;
+
+ nor->mtd = &b53sf->mtd;
+ nor->dev = &spi->dev;
+ nor->read_reg = bcm53xxspiflash_read_reg;
+ nor->write_reg = bcm53xxspiflash_write_reg;
+ nor->read = bcm53xxspiflash_read;
+ nor->write = bcm53xxspiflash_write;
+ nor->erase = bcm53xxspiflash_erase;
+ nor->priv = b53sf;
+
+ err = spi_nor_scan(&b53sf->nor, bcm53xxspiflash_chip_name(nor),
+ SPI_NOR_NORMAL);
+ if (err)
+ return err;
+
+ parser_data.of_node = spi->master->dev.parent->of_node;
+ err = mtd_device_parse_register(&b53sf->mtd, probes, &parser_data,
+ NULL, 0);
+ if (err)
+ return err;
+
+ return 0;
+}
+
+static int bcm53xxspiflash_remove(struct spi_device *spi)
+{
+ return 0;
+}
+
+static struct spi_driver bcm53xxspiflash_driver = {
+ .driver = {
+ .name = "bcm53xxspiflash",
+ .owner = THIS_MODULE,
+ },
+ .probe = bcm53xxspiflash_probe,
+ .remove = bcm53xxspiflash_remove,
+};
+
+module_spi_driver(bcm53xxspiflash_driver);
diff --git a/target/linux/bcm53xx/image/Makefile b/target/linux/bcm53xx/image/Makefile
new file mode 100644
index 0000000..c9987dd
--- /dev/null
+++ b/target/linux/bcm53xx/image/Makefile
@@ -0,0 +1,149 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/image.mk
+
+define Image/Prepare
+ $(CP) $(DTS_DIR)/*.dtb $(KDIR)/
+
+ rm -f $(KDIR)/fs_mark
+ echo -ne '\xde\xad\xc0\xde' > $(KDIR)/fs_mark
+ $(call prepare_generic_squashfs,$(KDIR)/fs_mark)
+
+ # For UBI we want only one extra block
+ rm -f $(KDIR)/ubi_mark
+ echo -ne '\xde\xad\xc0\xde' > $(KDIR)/ubi_mark
+
+ $(CP) ./ubinize.cfg $(KDIR)
+endef
+
+define Build/append-dtb
+ cat $(KDIR)/$(DT).dtb >> $@
+endef
+
+define Build/lzma-d16
+ $(STAGING_DIR_HOST)/bin/lzma e $@ -d16 $(1) $@.new
+ @mv $@.new $@
+endef
+
+define Build/mkfs/squashfs
+ ( cd $(KDIR); $(STAGING_DIR_HOST)/bin/ubinize -p 128KiB -m 2048 -o $(KDIR)/root-block-0x20000-min-0x800.ubi ubinize.cfg )
+endef
+
+define Build/trx-serial
+ $(STAGING_DIR_HOST)/bin/trx \
+ -o $@ \
+ -f $(word 1,$^) -a 1024 \
+ -f $(KDIR)/root.squashfs -a 0x10000 -A $(KDIR)/fs_mark
+endef
+
+define Build/trx-nand
+ # kernel: always use 4 MiB (-28 B or TRX header) to allow upgrades even
+ # if it grows up between releases
+ # root: UBI with one extra block containing UBI mark to trigger erasing
+ # rest of partition
+ $(STAGING_DIR_HOST)/bin/trx \
+ -o $@ \
+ -m 33554432 \
+ -f $(word 1,$^) -a 0x20000 -b 0x400000 \
+ -f $(KDIR)/root-block-0x20000-min-0x800.ubi \
+ -A $(KDIR)/ubi_mark -a 0x20000
+endef
+
+define Build/asus-trx
+ $(STAGING_DIR_HOST)/bin/asustrx \
+ -p $(PRODUCTID) -i $@ -o $@.new
+ mv $@.new $@
+endef
+
+DEVICE_VARS += DT PRODUCTID NETGEAR_BOARD_ID NETGEAR_REGION
+
+define Device/Default
+ # .dtb files are prefixed by SoC type, e.g. bcm4708- which is not included in device/image names
+ # extract the full dtb name based on the device info
+ DT := $(patsubst %.dtb,%,$(notdir $(wildcard $(if $(IB),$(KDIR),$(DTS_DIR))/*-$(1).dtb)))
+ KERNEL := kernel-bin | append-dtb | lzma-d16
+ FILESYSTEMS := squashfs
+ KERNEL_NAME := zImage
+ IMAGE_NAME = $$(IMAGE_PREFIX)-$$(1).$$(2)
+ IMAGES := trx
+ IMAGE/trx := trx-nand
+endef
+
+define Device/asus
+ IMAGES := trx
+ IMAGE/trx := trx-nand | asus-trx
+endef
+
+define AsusDevice
+ define Device/asus-$(1)
+ $$(Device/asus)
+ PRODUCTID := $(2)
+ endef
+ TARGET_DEVICES += asus-$(1)
+endef
+
+define Device/linksys
+ IMAGES := trx
+ IMAGE/trx := trx-nand
+endef
+
+define LinksysDevice
+ define Device/linksys-$(1)
+ $$(Device/linksys)
+ endef
+ TARGET_DEVICES += linksys-$(1)
+endef
+
+define Device/netgear
+ IMAGES := chk
+ IMAGE/chk := trx-nand | netgear-chk
+ NETGEAR_REGION := 1
+endef
+
+define NetgearDevice
+ define Device/netgear-$(1)
+ $$(Device/netgear)
+ NETGEAR_BOARD_ID := $(2)
+ endef
+ TARGET_DEVICES += netgear-$(1)
+endef
+
+define Device/netgear-r6250
+ $(Device/netgear)
+ NETGEAR_BOARD_ID := U12H245T00_NETGEAR
+endef
+
+define Device/netgear-r6300-v2
+ $(Device/netgear)
+ NETGEAR_BOARD_ID := U12H240T00_NETGEAR
+endef
+
+define Device/netgear-r8000
+ $(Device/netgear)
+ NETGEAR_BOARD_ID := U12H315T00_NETGEAR
+endef
+
+define Device/smartrg-sr400ac
+ IMAGES := trx
+ IMAGE/trx := trx-serial
+endef
+
+TARGET_DEVICES += \
+ buffalo-wzr-1750dhp buffalo-wzr-600dhp2 buffalo-wzr-900dhp \
+ buffalo-wxr-1900dhp \
+ netgear-r6250 netgear-r6300-v2 netgear-r8000 \
+ smartrg-sr400ac
+
+$(eval $(call AsusDevice,rt-ac56u,RT-AC56U))
+$(eval $(call AsusDevice,rt-ac68u,RT-AC68U))
+$(eval $(call AsusDevice,rt-ac87u,RT-AC87U))
+$(eval $(call AsusDevice,rt-n18u,RT-N18U))
+$(eval $(call LinksysDevice,ea6300-v1))
+$(eval $(call NetgearDevice,r7000,U12H270T00_NETGEAR))
+
+$(eval $(call BuildImage))
diff --git a/target/linux/bcm53xx/image/ubinize.cfg b/target/linux/bcm53xx/image/ubinize.cfg
new file mode 100644
index 0000000..a4f2f09
--- /dev/null
+++ b/target/linux/bcm53xx/image/ubinize.cfg
@@ -0,0 +1,24 @@
+[rootfs]
+# Volume mode (other option is static)
+mode=ubi
+# Source image
+image=root.squashfs
+# Volume ID in UBI image
+vol_id=0
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs
+
+[rootfs_data]
+# Volume mode (other option is static)
+mode=ubi
+# Volume ID in UBI image
+vol_id=1
+# Allow for dynamic resize
+vol_type=dynamic
+# Volume name
+vol_name=rootfs_data
+# Autoresize volume at first mount
+vol_flags=autoresize
+vol_size=1MiB
diff --git a/target/linux/bcm53xx/patches-4.1/030-PCI-iproc-Allow-override-of-device-tree-IRQ-mapping-.patch b/target/linux/bcm53xx/patches-4.1/030-PCI-iproc-Allow-override-of-device-tree-IRQ-mapping-.patch
new file mode 100644
index 0000000..9050f72
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/030-PCI-iproc-Allow-override-of-device-tree-IRQ-mapping-.patch
@@ -0,0 +1,53 @@
+From c1e02ceaf5739d32f092ac07bf886a0281ec40b1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Tue, 12 May 2015 23:23:00 +0200
+Subject: [PATCH 1/2] PCI: iproc: Allow override of device tree IRQ mapping
+ function
+
+The iProc core PCIe driver defaults to using of_irq_parse_and_map_pci() for
+IRQ mapping. Add iproc_pcie.map_irq so bus interfaces that don't use
+device tree can override this by supplying their own IRQ mapping function.
+
+[bhelgaas: changelog]
+Posting: http://lkml.kernel.org/r/1431465781-10753-1-git-send-email-hauke@hauke-m.de
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Ray Jui <rjui@broadcom.com.com>
+---
+ drivers/pci/host/pcie-iproc-platform.c | 2 ++
+ drivers/pci/host/pcie-iproc.c | 2 +-
+ drivers/pci/host/pcie-iproc.h | 1 +
+ 3 files changed, 4 insertions(+), 1 deletion(-)
+
+--- a/drivers/pci/host/pcie-iproc-platform.c
++++ b/drivers/pci/host/pcie-iproc-platform.c
+@@ -71,6 +71,8 @@ static int iproc_pcie_pltfm_probe(struct
+
+ pcie->resources = &res;
+
++ pcie->map_irq = of_irq_parse_and_map_pci;
++
+ ret = iproc_pcie_setup(pcie);
+ if (ret) {
+ dev_err(pcie->dev, "PCIe controller setup failed\n");
+--- a/drivers/pci/host/pcie-iproc.c
++++ b/drivers/pci/host/pcie-iproc.c
+@@ -229,7 +229,7 @@ int iproc_pcie_setup(struct iproc_pcie *
+
+ pci_scan_child_bus(bus);
+ pci_assign_unassigned_bus_resources(bus);
+- pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
++ pci_fixup_irqs(pci_common_swizzle, pcie->map_irq);
+ pci_bus_add_devices(bus);
+
+ return 0;
+--- a/drivers/pci/host/pcie-iproc.h
++++ b/drivers/pci/host/pcie-iproc.h
+@@ -34,6 +34,7 @@ struct iproc_pcie {
+ struct pci_bus *root_bus;
+ struct phy *phy;
+ int irqs[IPROC_PCIE_MAX_NUM_IRQS];
++ int (*map_irq)(const struct pci_dev *, u8, u8);
+ };
+
+ int iproc_pcie_setup(struct iproc_pcie *pcie);
diff --git a/target/linux/bcm53xx/patches-4.1/031-PCI-iproc-Add-BCMA-PCIe-driver.patch b/target/linux/bcm53xx/patches-4.1/031-PCI-iproc-Add-BCMA-PCIe-driver.patch
new file mode 100644
index 0000000..a850baf
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/031-PCI-iproc-Add-BCMA-PCIe-driver.patch
@@ -0,0 +1,177 @@
+From 4785ffbdc9b52e308e43b9e2dcc1dca44f056d76 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Tue, 12 May 2015 23:23:01 +0200
+Subject: [PATCH 2/2] PCI: iproc: Add BCMA PCIe driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This driver adds support for the PCIe 2.0 controller found on the BCMA bus.
+This controller can be found on (mostly) all Broadcom BCM470X / BCM5301X
+ARM SoCs.
+
+The driver found in the Broadcom SDK does some more stuff, like setting up
+some DMA memory areas, chaining MPS and MRRS to 512 and also some PHY
+changes like "improving" the PCIe jitter and doing some special
+initialization for the 3rd PCIe port.
+
+This was tested on a bcm4708 board with 2 PCIe ports and wireless cards
+connected to them.
+
+PCI_DOMAINS is needed by this driver, because normally there is more than
+one PCIe controller and without PCI_DOMAINS only the first controller gets
+registered. This controller gets 6 IRQs; the last one is trigged by all
+IRQ events.
+
+[bhelgaas: fix "GPLv2" MODULE_LICENSE typo]
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Acked-by: Rafał Miłecki <zajec5@gmail.com>
+Acked-by: Ray Jui <rjui@broadcom.com.com>
+---
+ drivers/pci/host/Kconfig | 11 ++++
+ drivers/pci/host/Makefile | 1 +
+ drivers/pci/host/pcie-iproc-bcma.c | 112 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 124 insertions(+)
+ create mode 100644 drivers/pci/host/pcie-iproc-bcma.c
+
+--- a/drivers/pci/host/Kconfig
++++ b/drivers/pci/host/Kconfig
+@@ -125,4 +125,15 @@ config PCIE_IPROC_PLATFORM
+ Say Y here if you want to use the Broadcom iProc PCIe controller
+ through the generic platform bus interface
+
++config PCIE_IPROC_BCMA
++ bool "Broadcom iProc PCIe BCMA bus driver"
++ depends on ARCH_BCM_IPROC || (ARM && COMPILE_TEST)
++ select PCIE_IPROC
++ select BCMA
++ select PCI_DOMAINS
++ default ARCH_BCM_5301X
++ help
++ Say Y here if you want to use the Broadcom iProc PCIe controller
++ through the BCMA bus interface
++
+ 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_PCIE_IPROC_BCMA) += pcie-iproc-bcma.o
+--- /dev/null
++++ b/drivers/pci/host/pcie-iproc-bcma.c
+@@ -0,0 +1,112 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ * Copyright (C) 2015 Hauke Mehrtens <hauke@hauke-m.de>
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/phy/phy.h>
++#include <linux/bcma/bcma.h>
++#include <linux/ioport.h>
++
++#include "pcie-iproc.h"
++
++
++/* 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);
++
++static int iproc_pcie_bcma_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
++{
++ struct pci_sys_data *sys = dev->sysdata;
++ struct iproc_pcie *pcie = sys->private_data;
++ struct bcma_device *bdev = container_of(pcie->dev, struct bcma_device, dev);
++
++ return bcma_core_irq(bdev, 5);
++}
++
++static int iproc_pcie_bcma_probe(struct bcma_device *bdev)
++{
++ struct iproc_pcie *pcie;
++ LIST_HEAD(res);
++ struct resource res_mem;
++ int ret;
++
++ pcie = devm_kzalloc(&bdev->dev, sizeof(*pcie), GFP_KERNEL);
++ if (!pcie)
++ return -ENOMEM;
++
++ pcie->dev = &bdev->dev;
++ bcma_set_drvdata(bdev, pcie);
++
++ pcie->base = bdev->io_addr;
++
++ res_mem.start = bdev->addr_s[0];
++ res_mem.end = bdev->addr_s[0] + SZ_128M - 1;
++ res_mem.name = "PCIe MEM space";
++ res_mem.flags = IORESOURCE_MEM;
++ pci_add_resource(&res, &res_mem);
++
++ pcie->resources = &res;
++
++ pcie->map_irq = iproc_pcie_bcma_map_irq;
++
++ ret = iproc_pcie_setup(pcie);
++ if (ret) {
++ dev_err(pcie->dev, "PCIe controller setup failed\n");
++ return ret;
++ }
++
++ return 0;
++}
++
++static void iproc_pcie_bcma_remove(struct bcma_device *bdev)
++{
++ struct iproc_pcie *pcie = bcma_get_drvdata(bdev);
++
++ iproc_pcie_remove(pcie);
++}
++
++static const struct bcma_device_id iproc_pcie_bcma_table[] = {
++ BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_PCIEG2, BCMA_ANY_REV, BCMA_ANY_CLASS),
++ {},
++};
++MODULE_DEVICE_TABLE(bcma, iproc_pcie_bcma_table);
++
++static struct bcma_driver iproc_pcie_bcma_driver = {
++ .name = KBUILD_MODNAME,
++ .id_table = iproc_pcie_bcma_table,
++ .probe = iproc_pcie_bcma_probe,
++ .remove = iproc_pcie_bcma_remove,
++};
++
++static int __init iproc_pcie_bcma_init(void)
++{
++ return bcma_driver_register(&iproc_pcie_bcma_driver);
++}
++module_init(iproc_pcie_bcma_init);
++
++static void __exit iproc_pcie_bcma_exit(void)
++{
++ bcma_driver_unregister(&iproc_pcie_bcma_driver);
++}
++module_exit(iproc_pcie_bcma_exit);
++
++MODULE_AUTHOR("Hauke Mehrtens");
++MODULE_DESCRIPTION("Broadcom iProc PCIe BCMA driver");
++MODULE_LICENSE("GPL v2");
diff --git a/target/linux/bcm53xx/patches-4.1/032-PCI-iproc-Directly-add-PCI-resources.patch b/target/linux/bcm53xx/patches-4.1/032-PCI-iproc-Directly-add-PCI-resources.patch
new file mode 100644
index 0000000..09d8226
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/032-PCI-iproc-Directly-add-PCI-resources.patch
@@ -0,0 +1,90 @@
+From 18c4342aa56d70176eea85021e6fe8f6f8f39c7b Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 24 May 2015 22:37:02 +0200
+Subject: [PATCH 1/2] PCI: iproc: Directly add PCI resources
+
+The struct iproc_pcie.resources member was pointing to a stack variable and
+is invalid after the registration function returned.
+
+Remove this pointer and add a parameter to the function.
+
+Tested-by: Ray Jui <rjui@broadcom.com>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Ray Jui <rjui@broadcom.com>
+---
+ drivers/pci/host/pcie-iproc-bcma.c | 4 +---
+ drivers/pci/host/pcie-iproc-platform.c | 4 +---
+ drivers/pci/host/pcie-iproc.c | 4 ++--
+ drivers/pci/host/pcie-iproc.h | 3 +--
+ 4 files changed, 5 insertions(+), 10 deletions(-)
+
+--- a/drivers/pci/host/pcie-iproc-bcma.c
++++ b/drivers/pci/host/pcie-iproc-bcma.c
+@@ -62,11 +62,9 @@ static int iproc_pcie_bcma_probe(struct
+ res_mem.flags = IORESOURCE_MEM;
+ pci_add_resource(&res, &res_mem);
+
+- pcie->resources = &res;
+-
+ pcie->map_irq = iproc_pcie_bcma_map_irq;
+
+- ret = iproc_pcie_setup(pcie);
++ ret = iproc_pcie_setup(pcie, &res);
+ if (ret) {
+ dev_err(pcie->dev, "PCIe controller setup failed\n");
+ return ret;
+--- a/drivers/pci/host/pcie-iproc-platform.c
++++ b/drivers/pci/host/pcie-iproc-platform.c
+@@ -69,11 +69,9 @@ static int iproc_pcie_pltfm_probe(struct
+ return ret;
+ }
+
+- pcie->resources = &res;
+-
+ pcie->map_irq = of_irq_parse_and_map_pci;
+
+- ret = iproc_pcie_setup(pcie);
++ ret = iproc_pcie_setup(pcie, &res);
+ if (ret) {
+ dev_err(pcie->dev, "PCIe controller setup failed\n");
+ return ret;
+--- a/drivers/pci/host/pcie-iproc.c
++++ b/drivers/pci/host/pcie-iproc.c
+@@ -183,7 +183,7 @@ static void iproc_pcie_enable(struct ipr
+ writel(SYS_RC_INTX_MASK, pcie->base + SYS_RC_INTX_EN);
+ }
+
+-int iproc_pcie_setup(struct iproc_pcie *pcie)
++int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res)
+ {
+ int ret;
+ struct pci_bus *bus;
+@@ -211,7 +211,7 @@ int iproc_pcie_setup(struct iproc_pcie *
+ pcie->sysdata.private_data = pcie;
+
+ bus = pci_create_root_bus(pcie->dev, 0, &iproc_pcie_ops,
+- &pcie->sysdata, pcie->resources);
++ &pcie->sysdata, res);
+ if (!bus) {
+ dev_err(pcie->dev, "unable to create PCI root bus\n");
+ ret = -ENOMEM;
+--- a/drivers/pci/host/pcie-iproc.h
++++ b/drivers/pci/host/pcie-iproc.h
+@@ -29,7 +29,6 @@
+ struct iproc_pcie {
+ struct device *dev;
+ void __iomem *base;
+- struct list_head *resources;
+ struct pci_sys_data sysdata;
+ struct pci_bus *root_bus;
+ struct phy *phy;
+@@ -37,7 +36,7 @@ struct iproc_pcie {
+ int (*map_irq)(const struct pci_dev *, u8, u8);
+ };
+
+-int iproc_pcie_setup(struct iproc_pcie *pcie);
++int iproc_pcie_setup(struct iproc_pcie *pcie, struct list_head *res);
+ int iproc_pcie_remove(struct iproc_pcie *pcie);
+
+ #endif /* _PCIE_IPROC_H */
diff --git a/target/linux/bcm53xx/patches-4.1/033-PCI-iproc-Free-resource-list-after-registration.patch b/target/linux/bcm53xx/patches-4.1/033-PCI-iproc-Free-resource-list-after-registration.patch
new file mode 100644
index 0000000..bbd3164
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/033-PCI-iproc-Free-resource-list-after-registration.patch
@@ -0,0 +1,57 @@
+From ef07991a95de76b07594448c3521361831ec2cfe Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 24 May 2015 22:37:03 +0200
+Subject: [PATCH 2/2] PCI: iproc: Free resource list after registration
+
+The resource list is only used in the setup process and was never freed.
+pci_add_resource() allocates a memory area to store the list item.
+
+Fix the memory leak.
+
+Tested-by: Ray Jui <rjui@broadcom.com>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
+Reviewed-by: Ray Jui <rjui@broadcom.com>
+---
+ drivers/pci/host/pcie-iproc-bcma.c | 8 ++++----
+ drivers/pci/host/pcie-iproc-platform.c | 8 ++++----
+ 2 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/pci/host/pcie-iproc-bcma.c
++++ b/drivers/pci/host/pcie-iproc-bcma.c
+@@ -65,12 +65,12 @@ static int iproc_pcie_bcma_probe(struct
+ pcie->map_irq = iproc_pcie_bcma_map_irq;
+
+ ret = iproc_pcie_setup(pcie, &res);
+- if (ret) {
++ if (ret)
+ dev_err(pcie->dev, "PCIe controller setup failed\n");
+- return ret;
+- }
+
+- return 0;
++ pci_free_resource_list(&res);
++
++ return ret;
+ }
+
+ static void iproc_pcie_bcma_remove(struct bcma_device *bdev)
+--- a/drivers/pci/host/pcie-iproc-platform.c
++++ b/drivers/pci/host/pcie-iproc-platform.c
+@@ -72,12 +72,12 @@ static int iproc_pcie_pltfm_probe(struct
+ pcie->map_irq = of_irq_parse_and_map_pci;
+
+ ret = iproc_pcie_setup(pcie, &res);
+- if (ret) {
++ if (ret)
+ dev_err(pcie->dev, "PCIe controller setup failed\n");
+- return ret;
+- }
+
+- return 0;
++ pci_free_resource_list(&res);
++
++ return ret;
+ }
+
+ static int iproc_pcie_pltfm_remove(struct platform_device *pdev)
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 0000000..290ea0a
--- /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 0000000..e16d39b
--- /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 0000000..dafae7b
--- /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 0000000..02e644e
--- /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 0000000..e72835b
--- /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 0000000..8716a0d
--- /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 0000000..aa99f37
--- /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 0000000..1422115
--- /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 0000000..5790c9a
--- /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/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch b/target/linux/bcm53xx/patches-4.1/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch
new file mode 100644
index 0000000..ccb8e27
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch
@@ -0,0 +1,32 @@
+From af8fe7176ec13de08b1bfb7ea2ae9cc147b2429a Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 12 Sep 2015 12:56:37 +0200
+Subject: [PATCH] ARM: BCM5301X: add NAND flash chip description for Asus
+ RT-AC87U
+
+The NAND flash chip description were not imported for the Asus RT-AC87U
+dts file when this was done for all the other dts files, because these
+patches were send in parallel.
+
+This adds a missing NAND flash chip description to this patch:
+commit 9faa5960eef3204cae6637b530f5e23e53b5a9ef
+Author: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri May 29 23:39:47 2015 +0200
+
+ARM: BCM5301X: add NAND flash chip description
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "asus,rt-ac87u", "brcm,bcm4709", "brcm,bcm4708";
diff --git a/target/linux/bcm53xx/patches-4.1/070-ARM-l2c-restore-the-behaviour-documented-above-l2c_e.patch b/target/linux/bcm53xx/patches-4.1/070-ARM-l2c-restore-the-behaviour-documented-above-l2c_e.patch
new file mode 100644
index 0000000..abee99d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/070-ARM-l2c-restore-the-behaviour-documented-above-l2c_e.patch
@@ -0,0 +1,43 @@
+From d965b0fca7dcde3f82c982e0bf1631069fdeb8c9 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Fri, 15 May 2015 11:56:45 +0100
+Subject: [PATCH 70/74] ARM: l2c: restore the behaviour documented above
+ l2c_enable()
+
+l2c_enable() is documented that it must not be called if the cache has
+already been enabled. Unfortunately, commit 6b49241ac252 ("ARM: 8259/1:
+l2c: Refactor the driver to use commit-like interface") changed this
+without updating the comment, for very little reason. Revert this
+change and restore the expected behaviour.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mm/cache-l2x0.c | 10 +++++-----
+ 1 file changed, 5 insertions(+), 5 deletions(-)
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -129,10 +129,6 @@ static void l2c_enable(void __iomem *bas
+ {
+ unsigned long flags;
+
+- /* Do not touch the controller if already enabled. */
+- if (readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN)
+- return;
+-
+ l2x0_saved_regs.aux_ctrl = aux;
+ l2c_configure(base);
+
+@@ -163,7 +159,11 @@ static void l2c_save(void __iomem *base)
+
+ static void l2c_resume(void)
+ {
+- l2c_enable(l2x0_base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock);
++ void __iomem *base = l2x0_base;
++
++ /* Do not touch the controller if already enabled. */
++ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
++ l2c_enable(base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock);
+ }
+
+ /*
diff --git a/target/linux/bcm53xx/patches-4.1/071-ARM-l2c-write-auxiliary-control-register-first.patch b/target/linux/bcm53xx/patches-4.1/071-ARM-l2c-write-auxiliary-control-register-first.patch
new file mode 100644
index 0000000..a9cca83
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/071-ARM-l2c-write-auxiliary-control-register-first.patch
@@ -0,0 +1,30 @@
+From 7705dd256ce363f8b01429efb2f0dc4d1ee23c89 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Fri, 15 May 2015 11:07:14 +0100
+Subject: [PATCH 71/74] ARM: l2c: write auxiliary control register first
+
+Before calling the controller specific configuration function, write
+the auxiliary control register first, so that bits shared with other
+registers (such as the prefetch control register) are not overwritten
+by the later write to the auxctrl register.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mm/cache-l2x0.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -115,10 +115,10 @@ static void l2c_configure(void __iomem *
+ return;
+ }
+
++ l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
++
+ if (l2x0_data->configure)
+ l2x0_data->configure(base);
+-
+- l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
+ }
+
+ /*
diff --git a/target/linux/bcm53xx/patches-4.1/072-ARM-l2c-clean-up-l2c_configure.patch b/target/linux/bcm53xx/patches-4.1/072-ARM-l2c-clean-up-l2c_configure.patch
new file mode 100644
index 0000000..72e9e76
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/072-ARM-l2c-clean-up-l2c_configure.patch
@@ -0,0 +1,109 @@
+From 50beefde30224888d6d63224405ace4bdd4b32a0 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Fri, 15 May 2015 11:05:54 +0100
+Subject: [PATCH 72/74] ARM: l2c: clean up l2c_configure()
+
+l2c_configure() does not follow the pattern of other l2c_* functions.
+Fix this so that it does to avoid future confusion.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mm/cache-l2x0.c | 23 ++++++++++++++---------
+ 1 file changed, 14 insertions(+), 9 deletions(-)
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -110,15 +110,7 @@ static inline void l2c_unlock(void __iom
+
+ static void l2c_configure(void __iomem *base)
+ {
+- if (outer_cache.configure) {
+- outer_cache.configure(&l2x0_saved_regs);
+- return;
+- }
+-
+ l2c_write_sec(l2x0_saved_regs.aux_ctrl, base, L2X0_AUX_CTRL);
+-
+- if (l2x0_data->configure)
+- l2x0_data->configure(base);
+ }
+
+ /*
+@@ -130,7 +122,11 @@ static void l2c_enable(void __iomem *bas
+ unsigned long flags;
+
+ l2x0_saved_regs.aux_ctrl = aux;
+- l2c_configure(base);
++
++ if (outer_cache.configure)
++ outer_cache.configure(&l2x0_saved_regs);
++ else
++ l2x0_data->configure(base);
+
+ l2c_unlock(base, num_lock);
+
+@@ -252,6 +248,7 @@ static const struct l2c_init_data l2c210
+ .num_lock = 1,
+ .enable = l2c_enable,
+ .save = l2c_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -409,6 +406,7 @@ static const struct l2c_init_data l2c220
+ .num_lock = 1,
+ .enable = l2c220_enable,
+ .save = l2c_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .inv_range = l2c220_inv_range,
+ .clean_range = l2c220_clean_range,
+@@ -569,6 +567,8 @@ static void l2c310_configure(void __iome
+ {
+ unsigned revision;
+
++ l2c_configure(base);
++
+ /* restore pl310 setup */
+ l2c_write_sec(l2x0_saved_regs.tag_latency, base,
+ L310_TAG_LATENCY_CTRL);
+@@ -1066,6 +1066,7 @@ static const struct l2c_init_data of_l2c
+ .of_parse = l2x0_of_parse,
+ .enable = l2c_enable,
+ .save = l2c_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -1084,6 +1085,7 @@ static const struct l2c_init_data of_l2c
+ .of_parse = l2x0_of_parse,
+ .enable = l2c220_enable,
+ .save = l2c_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .inv_range = l2c220_inv_range,
+ .clean_range = l2c220_clean_range,
+@@ -1416,6 +1418,7 @@ static const struct l2c_init_data of_aur
+ .enable = l2c_enable,
+ .fixup = aurora_fixup,
+ .save = aurora_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .inv_range = aurora_inv_range,
+ .clean_range = aurora_clean_range,
+@@ -1435,6 +1438,7 @@ static const struct l2c_init_data of_aur
+ .enable = aurora_enable_no_outer,
+ .fixup = aurora_fixup,
+ .save = aurora_save,
++ .configure = l2c_configure,
+ .outer_cache = {
+ .resume = l2c_resume,
+ },
+@@ -1608,6 +1612,7 @@ static void __init tauros3_save(void __i
+
+ static void tauros3_configure(void __iomem *base)
+ {
++ l2c_configure(base);
+ writel_relaxed(l2x0_saved_regs.aux2_ctrl,
+ base + TAUROS3_AUX2_CTRL);
+ writel_relaxed(l2x0_saved_regs.prefetch_ctrl,
diff --git a/target/linux/bcm53xx/patches-4.1/073-ARM-l2c-only-unlock-caches-if-NS_LOCKDOWN-bit-is-set.patch b/target/linux/bcm53xx/patches-4.1/073-ARM-l2c-only-unlock-caches-if-NS_LOCKDOWN-bit-is-set.patch
new file mode 100644
index 0000000..852dd02
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/073-ARM-l2c-only-unlock-caches-if-NS_LOCKDOWN-bit-is-set.patch
@@ -0,0 +1,149 @@
+From e946a8cbe4a47a7c2615ffb0d45712e72c7d0f3a Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Fri, 15 May 2015 11:51:51 +0100
+Subject: [PATCH 73/74] ARM: l2c: only unlock caches if NS_LOCKDOWN bit is set
+
+Some L2C caches have a bit which allows non-secure software to control
+the cache lockdown. Some platforms are unable to set this bit. To
+avoid receiving an abort while trying to unlock the cache lines, check
+the state of this bit before unlocking. We do this by providing a new
+method in the l2c_init_data to perform the unlocking.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mm/cache-l2x0.c | 26 +++++++++++++++++++++++++-
+ 1 file changed, 25 insertions(+), 1 deletion(-)
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -42,6 +42,7 @@ struct l2c_init_data {
+ void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
+ void (*save)(void __iomem *);
+ void (*configure)(void __iomem *);
++ void (*unlock)(void __iomem *, unsigned);
+ struct outer_cache_fns outer_cache;
+ };
+
+@@ -128,7 +129,7 @@ static void l2c_enable(void __iomem *bas
+ else
+ l2x0_data->configure(base);
+
+- l2c_unlock(base, num_lock);
++ l2x0_data->unlock(base, num_lock);
+
+ local_irq_save(flags);
+ __l2c_op_way(base + L2X0_INV_WAY);
+@@ -249,6 +250,7 @@ static const struct l2c_init_data l2c210
+ .enable = l2c_enable,
+ .save = l2c_save,
+ .configure = l2c_configure,
++ .unlock = l2c_unlock,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -400,6 +402,12 @@ static void l2c220_enable(void __iomem *
+ l2c_enable(base, aux, num_lock);
+ }
+
++static void l2c220_unlock(void __iomem *base, unsigned num_lock)
++{
++ if (readl_relaxed(base + L2X0_AUX_CTRL) & L220_AUX_CTRL_NS_LOCKDOWN)
++ l2c_unlock(base, num_lock);
++}
++
+ static const struct l2c_init_data l2c220_data = {
+ .type = "L2C-220",
+ .way_size_0 = SZ_8K,
+@@ -407,6 +415,7 @@ static const struct l2c_init_data l2c220
+ .enable = l2c220_enable,
+ .save = l2c_save,
+ .configure = l2c_configure,
++ .unlock = l2c220_unlock,
+ .outer_cache = {
+ .inv_range = l2c220_inv_range,
+ .clean_range = l2c220_clean_range,
+@@ -755,6 +764,12 @@ static void l2c310_resume(void)
+ set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
+ }
+
++static void l2c310_unlock(void __iomem *base, unsigned num_lock)
++{
++ if (readl_relaxed(base + L2X0_AUX_CTRL) & L310_AUX_CTRL_NS_LOCKDOWN)
++ l2c_unlock(base, num_lock);
++}
++
+ static const struct l2c_init_data l2c310_init_fns __initconst = {
+ .type = "L2C-310",
+ .way_size_0 = SZ_8K,
+@@ -763,6 +778,7 @@ static const struct l2c_init_data l2c310
+ .fixup = l2c310_fixup,
+ .save = l2c310_save,
+ .configure = l2c310_configure,
++ .unlock = l2c310_unlock,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -1067,6 +1083,7 @@ static const struct l2c_init_data of_l2c
+ .enable = l2c_enable,
+ .save = l2c_save,
+ .configure = l2c_configure,
++ .unlock = l2c_unlock,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -1086,6 +1103,7 @@ static const struct l2c_init_data of_l2c
+ .enable = l2c220_enable,
+ .save = l2c_save,
+ .configure = l2c_configure,
++ .unlock = l2c220_unlock,
+ .outer_cache = {
+ .inv_range = l2c220_inv_range,
+ .clean_range = l2c220_clean_range,
+@@ -1213,6 +1231,7 @@ static const struct l2c_init_data of_l2c
+ .fixup = l2c310_fixup,
+ .save = l2c310_save,
+ .configure = l2c310_configure,
++ .unlock = l2c310_unlock,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -1242,6 +1261,7 @@ static const struct l2c_init_data of_l2c
+ .fixup = l2c310_fixup,
+ .save = l2c310_save,
+ .configure = l2c310_configure,
++ .unlock = l2c310_unlock,
+ .outer_cache = {
+ .inv_range = l2c210_inv_range,
+ .clean_range = l2c210_clean_range,
+@@ -1419,6 +1439,7 @@ static const struct l2c_init_data of_aur
+ .fixup = aurora_fixup,
+ .save = aurora_save,
+ .configure = l2c_configure,
++ .unlock = l2c_unlock,
+ .outer_cache = {
+ .inv_range = aurora_inv_range,
+ .clean_range = aurora_clean_range,
+@@ -1439,6 +1460,7 @@ static const struct l2c_init_data of_aur
+ .fixup = aurora_fixup,
+ .save = aurora_save,
+ .configure = l2c_configure,
++ .unlock = l2c_unlock,
+ .outer_cache = {
+ .resume = l2c_resume,
+ },
+@@ -1589,6 +1611,7 @@ static const struct l2c_init_data of_bcm
+ .enable = l2c310_enable,
+ .save = l2c310_save,
+ .configure = l2c310_configure,
++ .unlock = l2c310_unlock,
+ .outer_cache = {
+ .inv_range = bcm_inv_range,
+ .clean_range = bcm_clean_range,
+@@ -1626,6 +1649,7 @@ static const struct l2c_init_data of_tau
+ .enable = l2c_enable,
+ .save = tauros3_save,
+ .configure = tauros3_configure,
++ .unlock = l2c_unlock,
+ /* Tauros3 broadcasts L1 cache operations to L2 */
+ .outer_cache = {
+ .resume = l2c_resume,
diff --git a/target/linux/bcm53xx/patches-4.1/074-ARM-l2c-avoid-passing-auxiliary-control-register-thr.patch b/target/linux/bcm53xx/patches-4.1/074-ARM-l2c-avoid-passing-auxiliary-control-register-thr.patch
new file mode 100644
index 0000000..05e739f
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/074-ARM-l2c-avoid-passing-auxiliary-control-register-thr.patch
@@ -0,0 +1,129 @@
+From 5b290ec2074c68b9f4f8f8789fa9b3e1782869e7 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk+kernel@arm.linux.org.uk>
+Date: Fri, 15 May 2015 12:03:29 +0100
+Subject: [PATCH 74/74] ARM: l2c: avoid passing auxiliary control register
+ through enable method
+
+Avoid passing the auxiliary control register value through the enable
+method. In the resume path, we have to read the value stored in
+l2x0_saved_regs.aux_ctrl, only to have it immediately written back by
+l2c_enable(). We can avoid this if we have __l2c_init() save the value
+directly to l2x0_saved_regs.aux_ctrl before calling the specific enable
+method.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mm/cache-l2x0.c | 32 +++++++++++++++++---------------
+ 1 file changed, 17 insertions(+), 15 deletions(-)
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -38,7 +38,7 @@ struct l2c_init_data {
+ unsigned way_size_0;
+ unsigned num_lock;
+ void (*of_parse)(const struct device_node *, u32 *, u32 *);
+- void (*enable)(void __iomem *, u32, unsigned);
++ void (*enable)(void __iomem *, unsigned);
+ void (*fixup)(void __iomem *, u32, struct outer_cache_fns *);
+ void (*save)(void __iomem *);
+ void (*configure)(void __iomem *);
+@@ -118,12 +118,10 @@ static void l2c_configure(void __iomem *
+ * Enable the L2 cache controller. This function must only be
+ * called when the cache controller is known to be disabled.
+ */
+-static void l2c_enable(void __iomem *base, u32 aux, unsigned num_lock)
++static void l2c_enable(void __iomem *base, unsigned num_lock)
+ {
+ unsigned long flags;
+
+- l2x0_saved_regs.aux_ctrl = aux;
+-
+ if (outer_cache.configure)
+ outer_cache.configure(&l2x0_saved_regs);
+ else
+@@ -160,7 +158,7 @@ static void l2c_resume(void)
+
+ /* Do not touch the controller if already enabled. */
+ if (!(readl_relaxed(base + L2X0_CTRL) & L2X0_CTRL_EN))
+- l2c_enable(base, l2x0_saved_regs.aux_ctrl, l2x0_data->num_lock);
++ l2c_enable(base, l2x0_data->num_lock);
+ }
+
+ /*
+@@ -390,16 +388,16 @@ static void l2c220_sync(void)
+ raw_spin_unlock_irqrestore(&l2x0_lock, flags);
+ }
+
+-static void l2c220_enable(void __iomem *base, u32 aux, unsigned num_lock)
++static void l2c220_enable(void __iomem *base, unsigned num_lock)
+ {
+ /*
+ * Always enable non-secure access to the lockdown registers -
+ * we write to them as part of the L2C enable sequence so they
+ * need to be accessible.
+ */
+- aux |= L220_AUX_CTRL_NS_LOCKDOWN;
++ l2x0_saved_regs.aux_ctrl |= L220_AUX_CTRL_NS_LOCKDOWN;
+
+- l2c_enable(base, aux, num_lock);
++ l2c_enable(base, num_lock);
+ }
+
+ static void l2c220_unlock(void __iomem *base, unsigned num_lock)
+@@ -612,10 +610,11 @@ static int l2c310_cpu_enable_flz(struct
+ return NOTIFY_OK;
+ }
+
+-static void __init l2c310_enable(void __iomem *base, u32 aux, unsigned num_lock)
++static void __init l2c310_enable(void __iomem *base, unsigned num_lock)
+ {
+ unsigned rev = readl_relaxed(base + L2X0_CACHE_ID) & L2X0_CACHE_ID_RTL_MASK;
+ bool cortex_a9 = read_cpuid_part() == ARM_CPU_PART_CORTEX_A9;
++ u32 aux = l2x0_saved_regs.aux_ctrl;
+
+ if (rev >= L310_CACHE_ID_RTL_R2P0) {
+ if (cortex_a9) {
+@@ -658,9 +657,9 @@ static void __init l2c310_enable(void __
+ * we write to them as part of the L2C enable sequence so they
+ * need to be accessible.
+ */
+- aux |= L310_AUX_CTRL_NS_LOCKDOWN;
++ l2x0_saved_regs.aux_ctrl = aux | L310_AUX_CTRL_NS_LOCKDOWN;
+
+- l2c_enable(base, aux, num_lock);
++ l2c_enable(base, num_lock);
+
+ /* Read back resulting AUX_CTRL value as it could have been altered. */
+ aux = readl_relaxed(base + L2X0_AUX_CTRL);
+@@ -872,8 +871,11 @@ static int __init __l2c_init(const struc
+ * Check if l2x0 controller is already enabled. If we are booting
+ * in non-secure mode accessing the below registers will fault.
+ */
+- if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN))
+- data->enable(l2x0_base, aux, data->num_lock);
++ if (!(readl_relaxed(l2x0_base + L2X0_CTRL) & L2X0_CTRL_EN)) {
++ l2x0_saved_regs.aux_ctrl = aux;
++
++ data->enable(l2x0_base, data->num_lock);
++ }
+
+ outer_cache = fns;
+
+@@ -1388,7 +1390,7 @@ static void aurora_save(void __iomem *ba
+ * For Aurora cache in no outer mode, enable via the CP15 coprocessor
+ * broadcasting of cache commands to L2.
+ */
+-static void __init aurora_enable_no_outer(void __iomem *base, u32 aux,
++static void __init aurora_enable_no_outer(void __iomem *base,
+ unsigned num_lock)
+ {
+ u32 u;
+@@ -1399,7 +1401,7 @@ static void __init aurora_enable_no_oute
+
+ isb();
+
+- l2c_enable(base, aux, num_lock);
++ l2c_enable(base, num_lock);
+ }
+
+ static void __init aurora_fixup(void __iomem *base, u32 cache_id,
diff --git a/target/linux/bcm53xx/patches-4.1/075-ARM-8391-1-l2c-add-options-to-overwrite-prefetching-.patch b/target/linux/bcm53xx/patches-4.1/075-ARM-8391-1-l2c-add-options-to-overwrite-prefetching-.patch
new file mode 100644
index 0000000..857d2c4
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/075-ARM-8391-1-l2c-add-options-to-overwrite-prefetching-.patch
@@ -0,0 +1,60 @@
+From ec3bd0e68a679a7af2c46af1ddc9af8b534a8b0e Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 10 Jun 2015 20:23:24 +0100
+Subject: [PATCH] ARM: 8391/1: l2c: add options to overwrite prefetching
+ behavior
+
+These options make it possible to overwrites the data and instruction
+prefetching behavior of the arm pl310 cache controller.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Acked-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ Documentation/devicetree/bindings/arm/l2cc.txt | 5 +++++
+ arch/arm/mm/cache-l2x0.c | 20 ++++++++++++++++++++
+ 2 files changed, 25 insertions(+)
+
+--- a/Documentation/devicetree/bindings/arm/l2cc.txt
++++ b/Documentation/devicetree/bindings/arm/l2cc.txt
+@@ -67,6 +67,11 @@ Optional properties:
+ disable if zero.
+ - arm,prefetch-offset : Override prefetch offset value. Valid values are
+ 0-7, 15, 23, and 31.
++- prefetch-data : Data prefetch. Value: <0> (forcibly disable), <1>
++ (forcibly enable), property absent (retain settings set by firmware)
++- prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
++ <1> (forcibly enable), property absent (retain settings set by
++ firmware)
+
+ Example:
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -1221,6 +1221,26 @@ static void __init l2c310_of_parse(const
+ pr_err("L2C-310 OF arm,prefetch-offset property value is missing\n");
+ }
+
++ ret = of_property_read_u32(np, "prefetch-data", &val);
++ if (ret == 0) {
++ if (val)
++ prefetch |= L310_PREFETCH_CTRL_DATA_PREFETCH;
++ else
++ prefetch &= ~L310_PREFETCH_CTRL_DATA_PREFETCH;
++ } else if (ret != -EINVAL) {
++ pr_err("L2C-310 OF prefetch-data property value is missing\n");
++ }
++
++ ret = of_property_read_u32(np, "prefetch-instr", &val);
++ if (ret == 0) {
++ if (val)
++ prefetch |= L310_PREFETCH_CTRL_INSTR_PREFETCH;
++ else
++ prefetch &= ~L310_PREFETCH_CTRL_INSTR_PREFETCH;
++ } else if (ret != -EINVAL) {
++ pr_err("L2C-310 OF prefetch-instr property value is missing\n");
++ }
++
+ l2x0_saved_regs.prefetch_ctrl = prefetch;
+ }
+
diff --git a/target/linux/bcm53xx/patches-4.1/077-ARM-l2c-Add-support-for-the-arm-shared-override-prop.patch b/target/linux/bcm53xx/patches-4.1/077-ARM-l2c-Add-support-for-the-arm-shared-override-prop.patch
new file mode 100644
index 0000000..cac4c0c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/077-ARM-l2c-Add-support-for-the-arm-shared-override-prop.patch
@@ -0,0 +1,81 @@
+From 1bc7c02e7f37ddfa09cb0db330ee8cd4034d6410 Mon Sep 17 00:00:00 2001
+From: Geert Uytterhoeven <geert+renesas@glider.be>
+Date: Thu, 7 May 2015 11:27:11 +0200
+Subject: [PATCH 1/4] ARM: l2c: Add support for the "arm, shared-override"
+ property
+
+"CoreLink Level 2 Cache Controller L2C-310", p. 2-15, section 2.3.2
+Shareable attribute" states:
+
+ "The default behavior of the cache controller with respect to the
+ shareable attribute is to transform Normal Memory Non-cacheable
+ transactions into:
+ - cacheable no allocate for reads
+ - write through no write allocate for writes."
+
+Depending on the system architecture, this may cause memory corruption
+in the presence of bus mastering devices (e.g. OHCI). To avoid such
+corruption, the default behavior can be disabled by setting the Shared
+Override bit in the Auxiliary Control register.
+
+Currently the Shared Override bit can be set only using C code:
+ - by calling l2x0_init() directly, which is deprecated,
+ - by setting/clearing the bit in the machine_desc.l2c_aux_val/mask
+ fields, but using values differing from 0/~0 is also deprecated.
+
+Hence add support for an "arm,shared-override" device tree property for
+the l2c device node. By specifying this property, affected systems can
+indicate that non-cacheable transactions must not be transformed.
+Then, it's up to the OS to decide. The current behavior is to set the
+"shared attribute override enable" bit, as there may exist kernel linear
+mappings and cacheable aliases for the DMA buffers, even if CMA is
+enabled.
+
+See also commit 1a8e41cd672f894b ("ARM: 6395/1: VExpress: Set bit 22 in
+the PL310 (cache controller) AuxCtlr register"):
+
+ "Clearing bit 22 in the PL310 Auxiliary Control register (shared
+ attribute override enable) has the side effect of transforming
+ Normal Shared Non-cacheable reads into Cacheable no-allocate reads.
+
+ Coherent DMA buffers in Linux always have a Cacheable alias via the
+ kernel linear mapping and the processor can speculatively load
+ cache lines into the PL310 controller. With bit 22 cleared,
+ Non-cacheable reads would unexpectedly hit such cache lines leading
+ to buffer corruption."
+
+Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
+---
+ Documentation/devicetree/bindings/arm/l2cc.txt | 6 ++++++
+ arch/arm/mm/cache-l2x0.c | 5 +++++
+ 2 files changed, 11 insertions(+)
+
+--- a/Documentation/devicetree/bindings/arm/l2cc.txt
++++ b/Documentation/devicetree/bindings/arm/l2cc.txt
+@@ -72,6 +72,12 @@ Optional properties:
+ - prefetch-instr : Instruction prefetch. Value: <0> (forcibly disable),
+ <1> (forcibly enable), property absent (retain settings set by
+ firmware)
++- arm,shared-override : The default behavior of the pl310 cache controller with
++ respect to the shareable attribute is to transform "normal memory
++ non-cacheable transactions" into "cacheable no allocate" (for reads) or
++ "write through no write allocate" (for writes).
++ On systems where this may cause DMA buffer corruption, this property must be
++ specified to indicate that such transforms are precluded.
+
+ Example:
+
+--- a/arch/arm/mm/cache-l2x0.c
++++ b/arch/arm/mm/cache-l2x0.c
+@@ -1171,6 +1171,11 @@ static void __init l2c310_of_parse(const
+ }
+ }
+
++ if (of_property_read_bool(np, "arm,shared-override")) {
++ *aux_val |= L2C_AUX_CTRL_SHARED_OVERRIDE;
++ *aux_mask &= ~L2C_AUX_CTRL_SHARED_OVERRIDE;
++ }
++
+ prefetch = l2x0_saved_regs.prefetch_ctrl;
+
+ ret = of_property_read_u32(np, "arm,double-linefill", &val);
diff --git a/target/linux/bcm53xx/patches-4.1/079-ARM-BCM5301X-activate-some-additional-options-in-pl3.patch b/target/linux/bcm53xx/patches-4.1/079-ARM-BCM5301X-activate-some-additional-options-in-pl3.patch
new file mode 100644
index 0000000..bfe4304
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/079-ARM-BCM5301X-activate-some-additional-options-in-pl3.patch
@@ -0,0 +1,29 @@
+From e8ec653c767f56346eb1fadbc07e0706d6dbd56f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Thu, 14 May 2015 00:38:28 +0200
+Subject: [PATCH 3/3] ARM: BCM5301X: activate some additional options in pl310
+ cache controller
+
+In the default Broadcom SDK the shared override is activated for this
+cache controller, do the same in the upstream code. Data and
+instruction prefetching is not activated by default for this cache
+controller on the bcm53xx SoC, do it manually like it is done in the
+vendor SDK.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/boot/dts/bcm5301x.dtsi | 3 +++
+ 1 file changed, 3 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -78,6 +78,9 @@
+ compatible = "arm,pl310-cache";
+ reg = <0x2000 0x1000>;
+ cache-unified;
++ arm,shared-override;
++ prefetch-data = <1>;
++ prefetch-instr = <1>;
+ cache-level = <2>;
+ };
+ };
diff --git a/target/linux/bcm53xx/patches-4.1/080-ARM-BCM5301X-Enable-UART0-on-tested-devices.patch b/target/linux/bcm53xx/patches-4.1/080-ARM-BCM5301X-Enable-UART0-on-tested-devices.patch
new file mode 100644
index 0000000..ce69cca
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/080-ARM-BCM5301X-Enable-UART0-on-tested-devices.patch
@@ -0,0 +1,83 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 29 Jun 2015 07:22:16 +0200
+Subject: [PATCH] ARM: BCM5301X: Enable UART0 on tested devices
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+There are two possible UARTs so we have (both of) them disabled by
+default. Override uart0 status on devices that were verified to use it.
+In case of Netgear R6250 also drop an old (and invalid) overwrite. It
+doesn't have uart1 connected.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Acked-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -135,3 +135,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
++++ b/arch/arm/boot/dts/bcm4708-luxul-xwc-1000.dts
+@@ -55,3 +55,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+@@ -24,16 +24,6 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
+- chipcommonA {
+- uart0: serial@0300 {
+- status = "okay";
+- };
+-
+- uart1: serial@0400 {
+- status = "okay";
+- };
+- };
+-
+ leds {
+ compatible = "gpio-leds";
+
+@@ -92,3 +82,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
++++ b/arch/arm/boot/dts/bcm4708-smartrg-sr400ac.dts
+@@ -118,3 +118,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
+@@ -122,3 +122,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.1/081-ARM-BCM5301X-Add-profiling-support.patch b/target/linux/bcm53xx/patches-4.1/081-ARM-BCM5301X-Add-profiling-support.patch
new file mode 100644
index 0000000..afd73f5
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/081-ARM-BCM5301X-Add-profiling-support.patch
@@ -0,0 +1,25 @@
+From: Felix Fietkau <nbd@openwrt.org>
+Date: Wed, 29 Jul 2015 23:51:00 +0200
+Subject: [PATCH] ARM: BCM5301X: Add profiling support
+
+Signed-off-by: Felix Fietkau <nbd@openwrt.org>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+Signed-off-by: Olof Johansson <olof@lixom.net>
+---
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -85,6 +85,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/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch b/target/linux/bcm53xx/patches-4.1/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch
new file mode 100644
index 0000000..02856d0
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch
@@ -0,0 +1,128 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 26 Aug 2015 16:11:38 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for Netgear R7000
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -68,6 +68,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm47081-buffalo-wzr-900dhp.dtb \
+ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
++ bcm4709-netgear-r7000.dtb \
+ bcm4709-netgear-r8000.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+ bcm963138dvt.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -0,0 +1,106 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Netgear R7000
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
++
++/ {
++ compatible = "netgear,r7000", "brcm,bcm4709", "brcm,bcm4708";
++ model = "Netgear R7000";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ power-white {
++ label = "bcm53xx:white:power";
++ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ power-amber {
++ label = "bcm53xx:amber:power";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ 5ghz {
++ label = "bcm53xx:white:5ghz";
++ gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ 2ghz {
++ label = "bcm53xx:white:2ghz";
++ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ wps {
++ label = "bcm53xx:white:wps";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wireless {
++ label = "bcm53xx:white:wireless";
++ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3 {
++ label = "bcm53xx:white:usb3";
++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb2 {
++ label = "bcm53xx:white:usb2";
++ gpios = <&chipcommon 18 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 4 GPIO_ACTIVE_LOW>;
++ };
++
++ rfkill {
++ label = "WiFi";
++ linux,code = <KEY_RFKILL>;
++ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.1/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch b/target/linux/bcm53xx/patches-4.1/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch
new file mode 100644
index 0000000..1d2c250
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch
@@ -0,0 +1,218 @@
+From a0aef7fbab0d8b5a0d445c74990e5233beda246e Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Wed, 21 Oct 2015 18:46:04 -0400
+Subject: [PATCH] ARM: dts: bcm5301x: Add BCM SVK DT files
+
+Add device tree files for Broadcom Northstar based SVKs. Since the
+bcm5301x.dtsi already exists, all that is necessary is the dts files to
+enable the UARTs. With these files, the SVKs are able to boot to shell.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ arch/arm/boot/dts/Makefile | 5 +++-
+ arch/arm/boot/dts/bcm94708.dts | 56 +++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm94709.dts | 56 +++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm953012k.dts | 63 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 179 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/bcm94708.dts
+ create mode 100644 arch/arm/boot/dts/bcm94709.dts
+ create mode 100644 arch/arm/boot/dts/bcm953012k.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -69,7 +69,10 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
+ bcm4709-netgear-r7000.dtb \
+- bcm4709-netgear-r8000.dtb
++ bcm4709-netgear-r8000.dtb \
++ bcm94708.dtb \
++ bcm94709.dtb \
++ bcm953012k.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+ bcm963138dvt.dtb
+ dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm94708.dts
+@@ -0,0 +1,56 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM94708)";
++ compatible = "brcm,bcm94708", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm94709.dts
+@@ -0,0 +1,56 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM94709)";
++ compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm953012k.dts
+@@ -0,0 +1,63 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM953012K)";
++ compatible = "brcm,bcm953012k", "brcm,brcm53012", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ serial1 = &uart1;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x10000000>;
++ };
++};
++
++&uart0 {
++ clock-frequency = <62499840>;
++ status = "okay";
++};
++
++&uart1 {
++ clock-frequency = <62499840>;
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.1/090-mtd-nand-add-common-DT-init-code.patch b/target/linux/bcm53xx/patches-4.1/090-mtd-nand-add-common-DT-init-code.patch
new file mode 100644
index 0000000..cb2141a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/090-mtd-nand-add-common-DT-init-code.patch
@@ -0,0 +1,111 @@
+From 5844feeaa4154d1c46d3462c7a4653d22356d8b4 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace@gmail.com>
+Date: Fri, 23 Jan 2015 00:22:27 -0800
+Subject: [PATCH 20/32] mtd: nand: add common DT init code
+
+These are already-documented common bindings for NAND chips. Let's
+handle them in nand_base.
+
+If NAND controller drivers need to act on this data before bringing up
+the NAND chip (e.g., fill out ECC callback functions, change HW modes,
+etc.), then they can do so between calling nand_scan_ident() and
+nand_scan_tail().
+
+Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+---
+ drivers/mtd/nand/nand_base.c | 41 +++++++++++++++++++++++++++++++++++++++++
+ include/linux/mtd/nand.h | 5 +++++
+ 2 files changed, 46 insertions(+)
+
+--- a/drivers/mtd/nand/nand_base.c
++++ b/drivers/mtd/nand/nand_base.c
+@@ -48,6 +48,7 @@
+ #include <linux/leds.h>
+ #include <linux/io.h>
+ #include <linux/mtd/partitions.h>
++#include <linux/of_mtd.h>
+
+ /* Define default oob placement schemes for large and small page devices */
+ static struct nand_ecclayout nand_oob_8 = {
+@@ -3798,6 +3799,39 @@ ident_done:
+ return type;
+ }
+
++static int nand_dt_init(struct mtd_info *mtd, struct nand_chip *chip,
++ struct device_node *dn)
++{
++ int ecc_mode, ecc_strength, ecc_step;
++
++ if (of_get_nand_bus_width(dn) == 16)
++ chip->options |= NAND_BUSWIDTH_16;
++
++ if (of_get_nand_on_flash_bbt(dn))
++ chip->bbt_options |= NAND_BBT_USE_FLASH;
++
++ ecc_mode = of_get_nand_ecc_mode(dn);
++ ecc_strength = of_get_nand_ecc_strength(dn);
++ ecc_step = of_get_nand_ecc_step_size(dn);
++
++ if ((ecc_step >= 0 && !(ecc_strength >= 0)) ||
++ (!(ecc_step >= 0) && ecc_strength >= 0)) {
++ pr_err("must set both strength and step size in DT\n");
++ return -EINVAL;
++ }
++
++ if (ecc_mode >= 0)
++ chip->ecc.mode = ecc_mode;
++
++ if (ecc_strength >= 0)
++ chip->ecc.strength = ecc_strength;
++
++ if (ecc_step > 0)
++ chip->ecc.size = ecc_step;
++
++ return 0;
++}
++
+ /**
+ * nand_scan_ident - [NAND Interface] Scan for the NAND device
+ * @mtd: MTD device structure
+@@ -3815,6 +3849,13 @@ int nand_scan_ident(struct mtd_info *mtd
+ int i, nand_maf_id, nand_dev_id;
+ struct nand_chip *chip = mtd->priv;
+ struct nand_flash_dev *type;
++ int ret;
++
++ if (chip->dn) {
++ ret = nand_dt_init(mtd, chip, chip->dn);
++ if (ret)
++ return ret;
++ }
+
+ /* Set the default functions */
+ nand_set_defaults(chip, chip->options & NAND_BUSWIDTH_16);
+--- a/include/linux/mtd/nand.h
++++ b/include/linux/mtd/nand.h
+@@ -26,6 +26,8 @@
+
+ struct mtd_info;
+ struct nand_flash_dev;
++struct device_node;
++
+ /* Scan and identify a NAND device */
+ extern int nand_scan(struct mtd_info *mtd, int max_chips);
+ /*
+@@ -542,6 +544,7 @@ struct nand_buffers {
+ * flash device
+ * @IO_ADDR_W: [BOARDSPECIFIC] address to write the 8 I/O lines of the
+ * flash device.
++ * @dn: [BOARDSPECIFIC] device node describing this instance
+ * @read_byte: [REPLACEABLE] read one byte from the chip
+ * @read_word: [REPLACEABLE] read one word from the chip
+ * @write_byte: [REPLACEABLE] write a single byte to the chip on the
+@@ -644,6 +647,8 @@ struct nand_chip {
+ void __iomem *IO_ADDR_R;
+ void __iomem *IO_ADDR_W;
+
++ struct device_node *dn;
++
+ uint8_t (*read_byte)(struct mtd_info *mtd);
+ u16 (*read_word)(struct mtd_info *mtd);
+ void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
diff --git a/target/linux/bcm53xx/patches-4.1/092-Add-Broadcom-STB-NAND.patch b/target/linux/bcm53xx/patches-4.1/092-Add-Broadcom-STB-NAND.patch
new file mode 100644
index 0000000..a6cf211
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/092-Add-Broadcom-STB-NAND.patch
@@ -0,0 +1,2765 @@
+This contains the following commits:
+
+commit bcb83a19d3ac95fe3c0e79e942fb628120738853
+Author: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun May 17 17:41:01 2015 +0200
+
+ mtd: brcmnand: do not make local variable static
+
+ Remove static in front of ctrl. This variable should not be shared
+ between different instances of brcmnand_probe(), it should be local to
+ this function and stored on the stack.
+
+ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+
+commit 802041247a0abbeaf1dddb8a8d56f491762ae357
+Author: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun May 17 17:41:00 2015 +0200
+
+ mtd: brcmnand: remove double new line from print
+
+ The caller already adds a new line and in the other cases there is no
+ new line added.
+
+ Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+
+commit f628ece6636c2f0354a52566cafdea6d2f963b3d
+Author: Brian Norris <computersforpeace@gmail.com>
+Date: Tue May 12 12:13:14 2015 -0700
+
+ mtd: brcmnand: add BCM63138 support
+
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+ Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+ Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+
+commit ca22f040dd145fc4d8069ce174f6eb0bc3ebd19f
+Author: Brian Norris <computersforpeace@gmail.com>
+Date: Tue May 12 12:12:02 2015 -0700
+
+ mtd: brcmnand: add support for Broadcom's IPROC family
+
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+
+
+commit c26211d37f11d5913d9803fdede6d053f918ba7b
+Author: Brian Norris <computersforpeace@gmail.com>
+Date: Tue May 12 12:09:28 2015 -0700
+
+ mtd: brcmnand: add extra SoC support to library
+
+ There are a few small hooks required for chips like BCM63138 and the
+ iProc family. Let's introduce those now.
+
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+ Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+ Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+
+commit 303b4420ff1896b444017b5b0eb8252ce197797d
+Author: Brian Norris <computersforpeace@gmail.com>
+Date: Tue May 12 17:00:57 2015 -0700
+
+ mtd: brcmnand: add support for STB chips
+
+ BCM7xxx chips are supported entirely by the library code, since they use
+ generic irqchip interfaces and don't need any extra SoC-specific
+ configuration.
+
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+
+commit 27c5b17cd1b10564fa36f8f51e4b4b41436ecc32
+Author: Brian Norris <computersforpeace@gmail.com>
+Date: Fri Mar 6 11:38:08 2015 -0800
+
+ mtd: nand: add NAND driver "library" for Broadcom STB NAND controller
+
+ This core originated in Set-Top Box chips (BCM7xxx) but is used in a
+ variety of other Broadcom chips, including some BCM63xxx, BCM33xx, and
+ iProc/Cygnus. It's been used only on ARM and MIPS SoCs, so restrict it
+ to those architectures.
+
+ There are multiple revisions of this core throughout the years, and
+ almost every version broke register compatibility in some small way, but
+ with some effort, this driver is able to support v4.0, v5.0, v6.x, v7.0,
+ and v7.1. It's been tested on v5.0, v6.0, v6.1, v7.0, and v7.1 recently,
+ so there hopefully are no more lurking inconsistencies.
+
+ This patch adds just some library support, on which platform drivers can
+ be built.
+
+ Signed-off-by: Brian Norris <computersforpeace@gmail.com>
+ Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
+ Tested-by: Florian Fainelli <f.fainelli@gmail.com>
+
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -394,6 +394,14 @@ config MTD_NAND_GPMI_NAND
+ block, such as SD card. So pay attention to it when you enable
+ the GPMI.
+
++config MTD_NAND_BRCMNAND
++ tristate "Broadcom STB NAND controller"
++ depends on ARM || MIPS
++ help
++ Enables the Broadcom NAND controller driver. The controller was
++ originally designed for Set-Top Box but is used on various BCM7xxx,
++ BCM3xxx, BCM63xxx, iProc/Cygnus and more.
++
+ config MTD_NAND_BCM47XXNFLASH
+ tristate "Support for NAND flash on BCM4706 BCMA bus"
+ depends on BCMA_NFLASH
+--- 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_BRCMNAND) += brcmnand/
+
+ nand-objs := nand_base.o nand_bbt.o nand_timings.o
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/Makefile
+@@ -0,0 +1,6 @@
++# link order matters; don't link the more generic brcmstb_nand.o before the
++# more specific iproc_nand.o, for instance
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += iproc_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += bcm63138_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmstb_nand.o
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/bcm63138_nand.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "brcmnand.h"
++
++struct bcm63138_nand_soc {
++ struct brcmnand_soc soc;
++ void __iomem *base;
++};
++
++#define BCM63138_NAND_INT_STATUS 0x00
++#define BCM63138_NAND_INT_EN 0x04
++
++enum {
++ BCM63138_CTLRDY = BIT(4),
++};
++
++static bool bcm63138_nand_intc_ack(struct brcmnand_soc *soc)
++{
++ struct bcm63138_nand_soc *priv =
++ container_of(soc, struct bcm63138_nand_soc, soc);
++ void __iomem *mmio = priv->base + BCM63138_NAND_INT_STATUS;
++ u32 val = brcmnand_readl(mmio);
++
++ if (val & BCM63138_CTLRDY) {
++ brcmnand_writel(val & ~BCM63138_CTLRDY, mmio);
++ return true;
++ }
++
++ return false;
++}
++
++static void bcm63138_nand_intc_set(struct brcmnand_soc *soc, bool en)
++{
++ struct bcm63138_nand_soc *priv =
++ container_of(soc, struct bcm63138_nand_soc, soc);
++ void __iomem *mmio = priv->base + BCM63138_NAND_INT_EN;
++ u32 val = brcmnand_readl(mmio);
++
++ if (en)
++ val |= BCM63138_CTLRDY;
++ else
++ val &= ~BCM63138_CTLRDY;
++
++ brcmnand_writel(val, mmio);
++}
++
++static int bcm63138_nand_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct bcm63138_nand_soc *priv;
++ struct brcmnand_soc *soc;
++ struct resource *res;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++ soc = &priv->soc;
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-int-base");
++ priv->base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->base))
++ return PTR_ERR(priv->base);
++
++ soc->ctlrdy_ack = bcm63138_nand_intc_ack;
++ soc->ctlrdy_set_enabled = bcm63138_nand_intc_set;
++
++ return brcmnand_probe(pdev, soc);
++}
++
++static const struct of_device_id bcm63138_nand_of_match[] = {
++ { .compatible = "brcm,nand-bcm63138" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, bcm63138_nand_of_match);
++
++static struct platform_driver bcm63138_nand_driver = {
++ .probe = bcm63138_nand_probe,
++ .remove = brcmnand_remove,
++ .driver = {
++ .name = "bcm63138_nand",
++ .pm = &brcmnand_pm_ops,
++ .of_match_table = bcm63138_nand_of_match,
++ }
++};
++module_platform_driver(bcm63138_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for BCM63138");
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -0,0 +1,2246 @@
++/*
++ * Copyright © 2010-2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/completion.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/dma-mapping.h>
++#include <linux/ioport.h>
++#include <linux/bug.h>
++#include <linux/kernel.h>
++#include <linux/bitops.h>
++#include <linux/mm.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/of.h>
++#include <linux/of_mtd.h>
++#include <linux/of_platform.h>
++#include <linux/slab.h>
++#include <linux/list.h>
++#include <linux/log2.h>
++
++#include "brcmnand.h"
++
++/*
++ * This flag controls if WP stays on between erase/write commands to mitigate
++ * flash corruption due to power glitches. Values:
++ * 0: NAND_WP is not used or not available
++ * 1: NAND_WP is set by default, cleared for erase/write operations
++ * 2: NAND_WP is always cleared
++ */
++static int wp_on = 1;
++module_param(wp_on, int, 0444);
++
++/***********************************************************************
++ * Definitions
++ ***********************************************************************/
++
++#define DRV_NAME "brcmnand"
++
++#define CMD_NULL 0x00
++#define CMD_PAGE_READ 0x01
++#define CMD_SPARE_AREA_READ 0x02
++#define CMD_STATUS_READ 0x03
++#define CMD_PROGRAM_PAGE 0x04
++#define CMD_PROGRAM_SPARE_AREA 0x05
++#define CMD_COPY_BACK 0x06
++#define CMD_DEVICE_ID_READ 0x07
++#define CMD_BLOCK_ERASE 0x08
++#define CMD_FLASH_RESET 0x09
++#define CMD_BLOCKS_LOCK 0x0a
++#define CMD_BLOCKS_LOCK_DOWN 0x0b
++#define CMD_BLOCKS_UNLOCK 0x0c
++#define CMD_READ_BLOCKS_LOCK_STATUS 0x0d
++#define CMD_PARAMETER_READ 0x0e
++#define CMD_PARAMETER_CHANGE_COL 0x0f
++#define CMD_LOW_LEVEL_OP 0x10
++
++struct brcm_nand_dma_desc {
++ u32 next_desc;
++ u32 next_desc_ext;
++ u32 cmd_irq;
++ u32 dram_addr;
++ u32 dram_addr_ext;
++ u32 tfr_len;
++ u32 total_len;
++ u32 flash_addr;
++ u32 flash_addr_ext;
++ u32 cs;
++ u32 pad2[5];
++ u32 status_valid;
++} __packed;
++
++/* Bitfields for brcm_nand_dma_desc::status_valid */
++#define FLASH_DMA_ECC_ERROR (1 << 8)
++#define FLASH_DMA_CORR_ERROR (1 << 9)
++
++/* 512B flash cache in the NAND controller HW */
++#define FC_SHIFT 9U
++#define FC_BYTES 512U
++#define FC_WORDS (FC_BYTES >> 2)
++
++#define BRCMNAND_MIN_PAGESIZE 512
++#define BRCMNAND_MIN_BLOCKSIZE (8 * 1024)
++#define BRCMNAND_MIN_DEVSIZE (4ULL * 1024 * 1024)
++
++/* Controller feature flags */
++enum {
++ BRCMNAND_HAS_1K_SECTORS = BIT(0),
++ BRCMNAND_HAS_PREFETCH = BIT(1),
++ BRCMNAND_HAS_CACHE_MODE = BIT(2),
++ BRCMNAND_HAS_WP = BIT(3),
++};
++
++struct brcmnand_controller {
++ struct device *dev;
++ struct nand_hw_control controller;
++ void __iomem *nand_base;
++ void __iomem *nand_fc; /* flash cache */
++ void __iomem *flash_dma_base;
++ unsigned int irq;
++ unsigned int dma_irq;
++ int nand_version;
++
++ /* Some SoCs provide custom interrupt status register(s) */
++ struct brcmnand_soc *soc;
++
++ int cmd_pending;
++ bool dma_pending;
++ struct completion done;
++ struct completion dma_done;
++
++ /* List of NAND hosts (one for each chip-select) */
++ struct list_head host_list;
++
++ struct brcm_nand_dma_desc *dma_desc;
++ dma_addr_t dma_pa;
++
++ /* in-memory cache of the FLASH_CACHE, used only for some commands */
++ u32 flash_cache[FC_WORDS];
++
++ /* Controller revision details */
++ const u16 *reg_offsets;
++ unsigned int reg_spacing; /* between CS1, CS2, ... regs */
++ const u8 *cs_offsets; /* within each chip-select */
++ const u8 *cs0_offsets; /* within CS0, if different */
++ unsigned int max_block_size;
++ const unsigned int *block_sizes;
++ unsigned int max_page_size;
++ const unsigned int *page_sizes;
++ unsigned int max_oob;
++ u32 features;
++
++ /* for low-power standby/resume only */
++ u32 nand_cs_nand_select;
++ u32 nand_cs_nand_xor;
++ u32 corr_stat_threshold;
++ u32 flash_dma_mode;
++};
++
++struct brcmnand_cfg {
++ u64 device_size;
++ unsigned int block_size;
++ unsigned int page_size;
++ unsigned int spare_area_size;
++ unsigned int device_width;
++ unsigned int col_adr_bytes;
++ unsigned int blk_adr_bytes;
++ unsigned int ful_adr_bytes;
++ unsigned int sector_size_1k;
++ unsigned int ecc_level;
++ /* use for low-power standby/resume only */
++ u32 acc_control;
++ u32 config;
++ u32 config_ext;
++ u32 timing_1;
++ u32 timing_2;
++};
++
++struct brcmnand_host {
++ struct list_head node;
++ struct device_node *of_node;
++
++ struct nand_chip chip;
++ struct mtd_info mtd;
++ struct platform_device *pdev;
++ int cs;
++
++ unsigned int last_cmd;
++ unsigned int last_byte;
++ u64 last_addr;
++ struct brcmnand_cfg hwcfg;
++ struct brcmnand_controller *ctrl;
++};
++
++enum brcmnand_reg {
++ BRCMNAND_CMD_START = 0,
++ BRCMNAND_CMD_EXT_ADDRESS,
++ BRCMNAND_CMD_ADDRESS,
++ BRCMNAND_INTFC_STATUS,
++ BRCMNAND_CS_SELECT,
++ BRCMNAND_CS_XOR,
++ BRCMNAND_LL_OP,
++ BRCMNAND_CS0_BASE,
++ BRCMNAND_CS1_BASE, /* CS1 regs, if non-contiguous */
++ BRCMNAND_CORR_THRESHOLD,
++ BRCMNAND_CORR_THRESHOLD_EXT,
++ BRCMNAND_UNCORR_COUNT,
++ BRCMNAND_CORR_COUNT,
++ BRCMNAND_CORR_EXT_ADDR,
++ BRCMNAND_CORR_ADDR,
++ BRCMNAND_UNCORR_EXT_ADDR,
++ BRCMNAND_UNCORR_ADDR,
++ BRCMNAND_SEMAPHORE,
++ BRCMNAND_ID,
++ BRCMNAND_ID_EXT,
++ BRCMNAND_LL_RDATA,
++ BRCMNAND_OOB_READ_BASE,
++ BRCMNAND_OOB_READ_10_BASE, /* offset 0x10, if non-contiguous */
++ BRCMNAND_OOB_WRITE_BASE,
++ BRCMNAND_OOB_WRITE_10_BASE, /* offset 0x10, if non-contiguous */
++ BRCMNAND_FC_BASE,
++};
++
++/* BRCMNAND v4.0 */
++static const u16 brcmnand_regs_v40[] = {
++ [BRCMNAND_CMD_START] = 0x04,
++ [BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
++ [BRCMNAND_CMD_ADDRESS] = 0x0c,
++ [BRCMNAND_INTFC_STATUS] = 0x6c,
++ [BRCMNAND_CS_SELECT] = 0x14,
++ [BRCMNAND_CS_XOR] = 0x18,
++ [BRCMNAND_LL_OP] = 0x178,
++ [BRCMNAND_CS0_BASE] = 0x40,
++ [BRCMNAND_CS1_BASE] = 0xd0,
++ [BRCMNAND_CORR_THRESHOLD] = 0x84,
++ [BRCMNAND_CORR_THRESHOLD_EXT] = 0,
++ [BRCMNAND_UNCORR_COUNT] = 0,
++ [BRCMNAND_CORR_COUNT] = 0,
++ [BRCMNAND_CORR_EXT_ADDR] = 0x70,
++ [BRCMNAND_CORR_ADDR] = 0x74,
++ [BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
++ [BRCMNAND_UNCORR_ADDR] = 0x7c,
++ [BRCMNAND_SEMAPHORE] = 0x58,
++ [BRCMNAND_ID] = 0x60,
++ [BRCMNAND_ID_EXT] = 0x64,
++ [BRCMNAND_LL_RDATA] = 0x17c,
++ [BRCMNAND_OOB_READ_BASE] = 0x20,
++ [BRCMNAND_OOB_READ_10_BASE] = 0x130,
++ [BRCMNAND_OOB_WRITE_BASE] = 0x30,
++ [BRCMNAND_OOB_WRITE_10_BASE] = 0,
++ [BRCMNAND_FC_BASE] = 0x200,
++};
++
++/* BRCMNAND v5.0 */
++static const u16 brcmnand_regs_v50[] = {
++ [BRCMNAND_CMD_START] = 0x04,
++ [BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
++ [BRCMNAND_CMD_ADDRESS] = 0x0c,
++ [BRCMNAND_INTFC_STATUS] = 0x6c,
++ [BRCMNAND_CS_SELECT] = 0x14,
++ [BRCMNAND_CS_XOR] = 0x18,
++ [BRCMNAND_LL_OP] = 0x178,
++ [BRCMNAND_CS0_BASE] = 0x40,
++ [BRCMNAND_CS1_BASE] = 0xd0,
++ [BRCMNAND_CORR_THRESHOLD] = 0x84,
++ [BRCMNAND_CORR_THRESHOLD_EXT] = 0,
++ [BRCMNAND_UNCORR_COUNT] = 0,
++ [BRCMNAND_CORR_COUNT] = 0,
++ [BRCMNAND_CORR_EXT_ADDR] = 0x70,
++ [BRCMNAND_CORR_ADDR] = 0x74,
++ [BRCMNAND_UNCORR_EXT_ADDR] = 0x78,
++ [BRCMNAND_UNCORR_ADDR] = 0x7c,
++ [BRCMNAND_SEMAPHORE] = 0x58,
++ [BRCMNAND_ID] = 0x60,
++ [BRCMNAND_ID_EXT] = 0x64,
++ [BRCMNAND_LL_RDATA] = 0x17c,
++ [BRCMNAND_OOB_READ_BASE] = 0x20,
++ [BRCMNAND_OOB_READ_10_BASE] = 0x130,
++ [BRCMNAND_OOB_WRITE_BASE] = 0x30,
++ [BRCMNAND_OOB_WRITE_10_BASE] = 0x140,
++ [BRCMNAND_FC_BASE] = 0x200,
++};
++
++/* BRCMNAND v6.0 - v7.1 */
++static const u16 brcmnand_regs_v60[] = {
++ [BRCMNAND_CMD_START] = 0x04,
++ [BRCMNAND_CMD_EXT_ADDRESS] = 0x08,
++ [BRCMNAND_CMD_ADDRESS] = 0x0c,
++ [BRCMNAND_INTFC_STATUS] = 0x14,
++ [BRCMNAND_CS_SELECT] = 0x18,
++ [BRCMNAND_CS_XOR] = 0x1c,
++ [BRCMNAND_LL_OP] = 0x20,
++ [BRCMNAND_CS0_BASE] = 0x50,
++ [BRCMNAND_CS1_BASE] = 0,
++ [BRCMNAND_CORR_THRESHOLD] = 0xc0,
++ [BRCMNAND_CORR_THRESHOLD_EXT] = 0xc4,
++ [BRCMNAND_UNCORR_COUNT] = 0xfc,
++ [BRCMNAND_CORR_COUNT] = 0x100,
++ [BRCMNAND_CORR_EXT_ADDR] = 0x10c,
++ [BRCMNAND_CORR_ADDR] = 0x110,
++ [BRCMNAND_UNCORR_EXT_ADDR] = 0x114,
++ [BRCMNAND_UNCORR_ADDR] = 0x118,
++ [BRCMNAND_SEMAPHORE] = 0x150,
++ [BRCMNAND_ID] = 0x194,
++ [BRCMNAND_ID_EXT] = 0x198,
++ [BRCMNAND_LL_RDATA] = 0x19c,
++ [BRCMNAND_OOB_READ_BASE] = 0x200,
++ [BRCMNAND_OOB_READ_10_BASE] = 0,
++ [BRCMNAND_OOB_WRITE_BASE] = 0x280,
++ [BRCMNAND_OOB_WRITE_10_BASE] = 0,
++ [BRCMNAND_FC_BASE] = 0x400,
++};
++
++enum brcmnand_cs_reg {
++ BRCMNAND_CS_CFG_EXT = 0,
++ BRCMNAND_CS_CFG,
++ BRCMNAND_CS_ACC_CONTROL,
++ BRCMNAND_CS_TIMING1,
++ BRCMNAND_CS_TIMING2,
++};
++
++/* Per chip-select offsets for v7.1 */
++static const u8 brcmnand_cs_offsets_v71[] = {
++ [BRCMNAND_CS_ACC_CONTROL] = 0x00,
++ [BRCMNAND_CS_CFG_EXT] = 0x04,
++ [BRCMNAND_CS_CFG] = 0x08,
++ [BRCMNAND_CS_TIMING1] = 0x0c,
++ [BRCMNAND_CS_TIMING2] = 0x10,
++};
++
++/* Per chip-select offsets for pre v7.1, except CS0 on <= v5.0 */
++static const u8 brcmnand_cs_offsets[] = {
++ [BRCMNAND_CS_ACC_CONTROL] = 0x00,
++ [BRCMNAND_CS_CFG_EXT] = 0x04,
++ [BRCMNAND_CS_CFG] = 0x04,
++ [BRCMNAND_CS_TIMING1] = 0x08,
++ [BRCMNAND_CS_TIMING2] = 0x0c,
++};
++
++/* Per chip-select offset for <= v5.0 on CS0 only */
++static const u8 brcmnand_cs_offsets_cs0[] = {
++ [BRCMNAND_CS_ACC_CONTROL] = 0x00,
++ [BRCMNAND_CS_CFG_EXT] = 0x08,
++ [BRCMNAND_CS_CFG] = 0x08,
++ [BRCMNAND_CS_TIMING1] = 0x10,
++ [BRCMNAND_CS_TIMING2] = 0x14,
++};
++
++/* BRCMNAND_INTFC_STATUS */
++enum {
++ INTFC_FLASH_STATUS = GENMASK(7, 0),
++
++ INTFC_ERASED = BIT(27),
++ INTFC_OOB_VALID = BIT(28),
++ INTFC_CACHE_VALID = BIT(29),
++ INTFC_FLASH_READY = BIT(30),
++ INTFC_CTLR_READY = BIT(31),
++};
++
++static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
++{
++ return brcmnand_readl(ctrl->nand_base + offs);
++}
++
++static inline void nand_writereg(struct brcmnand_controller *ctrl, u32 offs,
++ u32 val)
++{
++ brcmnand_writel(val, ctrl->nand_base + offs);
++}
++
++static int brcmnand_revision_init(struct brcmnand_controller *ctrl)
++{
++ static const unsigned int block_sizes_v6[] = { 8, 16, 128, 256, 512, 1024, 2048, 0 };
++ static const unsigned int block_sizes_v4[] = { 16, 128, 8, 512, 256, 1024, 2048, 0 };
++ static const unsigned int page_sizes[] = { 512, 2048, 4096, 8192, 0 };
++
++ ctrl->nand_version = nand_readreg(ctrl, 0) & 0xffff;
++
++ /* Only support v4.0+? */
++ if (ctrl->nand_version < 0x0400) {
++ dev_err(ctrl->dev, "version %#x not supported\n",
++ ctrl->nand_version);
++ return -ENODEV;
++ }
++
++ /* Register offsets */
++ if (ctrl->nand_version >= 0x0600)
++ ctrl->reg_offsets = brcmnand_regs_v60;
++ else if (ctrl->nand_version >= 0x0500)
++ ctrl->reg_offsets = brcmnand_regs_v50;
++ else if (ctrl->nand_version >= 0x0400)
++ ctrl->reg_offsets = brcmnand_regs_v40;
++
++ /* Chip-select stride */
++ if (ctrl->nand_version >= 0x0701)
++ ctrl->reg_spacing = 0x14;
++ else
++ ctrl->reg_spacing = 0x10;
++
++ /* Per chip-select registers */
++ if (ctrl->nand_version >= 0x0701) {
++ ctrl->cs_offsets = brcmnand_cs_offsets_v71;
++ } else {
++ ctrl->cs_offsets = brcmnand_cs_offsets;
++
++ /* v5.0 and earlier has a different CS0 offset layout */
++ if (ctrl->nand_version <= 0x0500)
++ ctrl->cs0_offsets = brcmnand_cs_offsets_cs0;
++ }
++
++ /* Page / block sizes */
++ if (ctrl->nand_version >= 0x0701) {
++ /* >= v7.1 use nice power-of-2 values! */
++ ctrl->max_page_size = 16 * 1024;
++ ctrl->max_block_size = 2 * 1024 * 1024;
++ } else {
++ ctrl->page_sizes = page_sizes;
++ if (ctrl->nand_version >= 0x0600)
++ ctrl->block_sizes = block_sizes_v6;
++ else
++ ctrl->block_sizes = block_sizes_v4;
++
++ if (ctrl->nand_version < 0x0400) {
++ ctrl->max_page_size = 4096;
++ ctrl->max_block_size = 512 * 1024;
++ }
++ }
++
++ /* Maximum spare area sector size (per 512B) */
++ if (ctrl->nand_version >= 0x0600)
++ ctrl->max_oob = 64;
++ else if (ctrl->nand_version >= 0x0500)
++ ctrl->max_oob = 32;
++ else
++ ctrl->max_oob = 16;
++
++ /* v6.0 and newer (except v6.1) have prefetch support */
++ if (ctrl->nand_version >= 0x0600 && ctrl->nand_version != 0x0601)
++ ctrl->features |= BRCMNAND_HAS_PREFETCH;
++
++ /*
++ * v6.x has cache mode, but it's implemented differently. Ignore it for
++ * now.
++ */
++ if (ctrl->nand_version >= 0x0700)
++ ctrl->features |= BRCMNAND_HAS_CACHE_MODE;
++
++ if (ctrl->nand_version >= 0x0500)
++ ctrl->features |= BRCMNAND_HAS_1K_SECTORS;
++
++ if (ctrl->nand_version >= 0x0700)
++ ctrl->features |= BRCMNAND_HAS_WP;
++ else if (of_property_read_bool(ctrl->dev->of_node, "brcm,nand-has-wp"))
++ ctrl->features |= BRCMNAND_HAS_WP;
++
++ return 0;
++}
++
++static inline u32 brcmnand_read_reg(struct brcmnand_controller *ctrl,
++ enum brcmnand_reg reg)
++{
++ u16 offs = ctrl->reg_offsets[reg];
++
++ if (offs)
++ return nand_readreg(ctrl, offs);
++ else
++ return 0;
++}
++
++static inline void brcmnand_write_reg(struct brcmnand_controller *ctrl,
++ enum brcmnand_reg reg, u32 val)
++{
++ u16 offs = ctrl->reg_offsets[reg];
++
++ if (offs)
++ nand_writereg(ctrl, offs, val);
++}
++
++static inline void brcmnand_rmw_reg(struct brcmnand_controller *ctrl,
++ enum brcmnand_reg reg, u32 mask, unsigned
++ int shift, u32 val)
++{
++ u32 tmp = brcmnand_read_reg(ctrl, reg);
++
++ tmp &= ~mask;
++ tmp |= val << shift;
++ brcmnand_write_reg(ctrl, reg, tmp);
++}
++
++static inline u32 brcmnand_read_fc(struct brcmnand_controller *ctrl, int word)
++{
++ return __raw_readl(ctrl->nand_fc + word * 4);
++}
++
++static inline void brcmnand_write_fc(struct brcmnand_controller *ctrl,
++ int word, u32 val)
++{
++ __raw_writel(val, ctrl->nand_fc + word * 4);
++}
++
++static inline u16 brcmnand_cs_offset(struct brcmnand_controller *ctrl, int cs,
++ enum brcmnand_cs_reg reg)
++{
++ u16 offs_cs0 = ctrl->reg_offsets[BRCMNAND_CS0_BASE];
++ u16 offs_cs1 = ctrl->reg_offsets[BRCMNAND_CS1_BASE];
++ u8 cs_offs;
++
++ if (cs == 0 && ctrl->cs0_offsets)
++ cs_offs = ctrl->cs0_offsets[reg];
++ else
++ cs_offs = ctrl->cs_offsets[reg];
++
++ if (cs && offs_cs1)
++ return offs_cs1 + (cs - 1) * ctrl->reg_spacing + cs_offs;
++
++ return offs_cs0 + cs * ctrl->reg_spacing + cs_offs;
++}
++
++static inline u32 brcmnand_count_corrected(struct brcmnand_controller *ctrl)
++{
++ if (ctrl->nand_version < 0x0600)
++ return 1;
++ return brcmnand_read_reg(ctrl, BRCMNAND_CORR_COUNT);
++}
++
++static void brcmnand_wr_corr_thresh(struct brcmnand_host *host, u8 val)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ unsigned int shift = 0, bits;
++ enum brcmnand_reg reg = BRCMNAND_CORR_THRESHOLD;
++ int cs = host->cs;
++
++ if (ctrl->nand_version >= 0x0600)
++ bits = 6;
++ else if (ctrl->nand_version >= 0x0500)
++ bits = 5;
++ else
++ bits = 4;
++
++ if (ctrl->nand_version >= 0x0600) {
++ if (cs >= 5)
++ reg = BRCMNAND_CORR_THRESHOLD_EXT;
++ shift = (cs % 5) * bits;
++ }
++ brcmnand_rmw_reg(ctrl, reg, (bits - 1) << shift, shift, val);
++}
++
++static inline int brcmnand_cmd_shift(struct brcmnand_controller *ctrl)
++{
++ if (ctrl->nand_version < 0x0700)
++ return 24;
++ return 0;
++}
++
++/***********************************************************************
++ * NAND ACC CONTROL bitfield
++ *
++ * Some bits have remained constant throughout hardware revision, while
++ * others have shifted around.
++ ***********************************************************************/
++
++/* Constant for all versions (where supported) */
++enum {
++ /* See BRCMNAND_HAS_CACHE_MODE */
++ ACC_CONTROL_CACHE_MODE = BIT(22),
++
++ /* See BRCMNAND_HAS_PREFETCH */
++ ACC_CONTROL_PREFETCH = BIT(23),
++
++ ACC_CONTROL_PAGE_HIT = BIT(24),
++ ACC_CONTROL_WR_PREEMPT = BIT(25),
++ ACC_CONTROL_PARTIAL_PAGE = BIT(26),
++ ACC_CONTROL_RD_ERASED = BIT(27),
++ ACC_CONTROL_FAST_PGM_RDIN = BIT(28),
++ ACC_CONTROL_WR_ECC = BIT(30),
++ ACC_CONTROL_RD_ECC = BIT(31),
++};
++
++static inline u32 brcmnand_spare_area_mask(struct brcmnand_controller *ctrl)
++{
++ if (ctrl->nand_version >= 0x0600)
++ return GENMASK(6, 0);
++ else
++ return GENMASK(5, 0);
++}
++
++#define NAND_ACC_CONTROL_ECC_SHIFT 16
++
++static inline u32 brcmnand_ecc_level_mask(struct brcmnand_controller *ctrl)
++{
++ u32 mask = (ctrl->nand_version >= 0x0600) ? 0x1f : 0x0f;
++
++ return mask << NAND_ACC_CONTROL_ECC_SHIFT;
++}
++
++static void brcmnand_set_ecc_enabled(struct brcmnand_host *host, int en)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u16 offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
++ u32 acc_control = nand_readreg(ctrl, offs);
++ u32 ecc_flags = ACC_CONTROL_WR_ECC | ACC_CONTROL_RD_ECC;
++
++ if (en) {
++ acc_control |= ecc_flags; /* enable RD/WR ECC */
++ acc_control |= host->hwcfg.ecc_level
++ << NAND_ACC_CONTROL_ECC_SHIFT;
++ } else {
++ acc_control &= ~ecc_flags; /* disable RD/WR ECC */
++ acc_control &= ~brcmnand_ecc_level_mask(ctrl);
++ }
++
++ nand_writereg(ctrl, offs, acc_control);
++}
++
++static inline int brcmnand_sector_1k_shift(struct brcmnand_controller *ctrl)
++{
++ if (ctrl->nand_version >= 0x0600)
++ return 7;
++ else if (ctrl->nand_version >= 0x0500)
++ return 6;
++ else
++ return -1;
++}
++
++static int brcmnand_get_sector_size_1k(struct brcmnand_host *host)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ int shift = brcmnand_sector_1k_shift(ctrl);
++ u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_ACC_CONTROL);
++
++ if (shift < 0)
++ return 0;
++
++ return (nand_readreg(ctrl, acc_control_offs) >> shift) & 0x1;
++}
++
++static void brcmnand_set_sector_size_1k(struct brcmnand_host *host, int val)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ int shift = brcmnand_sector_1k_shift(ctrl);
++ u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_ACC_CONTROL);
++ u32 tmp;
++
++ if (shift < 0)
++ return;
++
++ tmp = nand_readreg(ctrl, acc_control_offs);
++ tmp &= ~(1 << shift);
++ tmp |= (!!val) << shift;
++ nand_writereg(ctrl, acc_control_offs, tmp);
++}
++
++/***********************************************************************
++ * CS_NAND_SELECT
++ ***********************************************************************/
++
++enum {
++ CS_SELECT_NAND_WP = BIT(29),
++ CS_SELECT_AUTO_DEVICE_ID_CFG = BIT(30),
++};
++
++static inline void brcmnand_set_wp(struct brcmnand_controller *ctrl, bool en)
++{
++ u32 val = en ? CS_SELECT_NAND_WP : 0;
++
++ brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT, CS_SELECT_NAND_WP, 0, val);
++}
++
++/***********************************************************************
++ * Flash DMA
++ ***********************************************************************/
++
++enum flash_dma_reg {
++ FLASH_DMA_REVISION = 0x00,
++ FLASH_DMA_FIRST_DESC = 0x04,
++ FLASH_DMA_FIRST_DESC_EXT = 0x08,
++ FLASH_DMA_CTRL = 0x0c,
++ FLASH_DMA_MODE = 0x10,
++ FLASH_DMA_STATUS = 0x14,
++ FLASH_DMA_INTERRUPT_DESC = 0x18,
++ FLASH_DMA_INTERRUPT_DESC_EXT = 0x1c,
++ FLASH_DMA_ERROR_STATUS = 0x20,
++ FLASH_DMA_CURRENT_DESC = 0x24,
++ FLASH_DMA_CURRENT_DESC_EXT = 0x28,
++};
++
++static inline bool has_flash_dma(struct brcmnand_controller *ctrl)
++{
++ return ctrl->flash_dma_base;
++}
++
++static inline bool flash_dma_buf_ok(const void *buf)
++{
++ return buf && !is_vmalloc_addr(buf) &&
++ likely(IS_ALIGNED((uintptr_t)buf, 4));
++}
++
++static inline void flash_dma_writel(struct brcmnand_controller *ctrl, u8 offs,
++ u32 val)
++{
++ brcmnand_writel(val, ctrl->flash_dma_base + offs);
++}
++
++static inline u32 flash_dma_readl(struct brcmnand_controller *ctrl, u8 offs)
++{
++ return brcmnand_readl(ctrl->flash_dma_base + offs);
++}
++
++/* Low-level operation types: command, address, write, or read */
++enum brcmnand_llop_type {
++ LL_OP_CMD,
++ LL_OP_ADDR,
++ LL_OP_WR,
++ LL_OP_RD,
++};
++
++/***********************************************************************
++ * Internal support functions
++ ***********************************************************************/
++
++static inline bool is_hamming_ecc(struct brcmnand_cfg *cfg)
++{
++ return cfg->sector_size_1k == 0 && cfg->spare_area_size == 16 &&
++ cfg->ecc_level == 15;
++}
++
++/*
++ * Returns a nand_ecclayout strucutre for the given layout/configuration.
++ * Returns NULL on failure.
++ */
++static struct nand_ecclayout *brcmnand_create_layout(int ecc_level,
++ struct brcmnand_host *host)
++{
++ struct brcmnand_cfg *cfg = &host->hwcfg;
++ int i, j;
++ struct nand_ecclayout *layout;
++ int req;
++ int sectors;
++ int sas;
++ int idx1, idx2;
++
++ layout = devm_kzalloc(&host->pdev->dev, sizeof(*layout), GFP_KERNEL);
++ if (!layout)
++ return NULL;
++
++ sectors = cfg->page_size / (512 << cfg->sector_size_1k);
++ sas = cfg->spare_area_size << cfg->sector_size_1k;
++
++ /* Hamming */
++ if (is_hamming_ecc(cfg)) {
++ for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
++ /* First sector of each page may have BBI */
++ if (i == 0) {
++ layout->oobfree[idx2].offset = i * sas + 1;
++ /* Small-page NAND use byte 6 for BBI */
++ if (cfg->page_size == 512)
++ layout->oobfree[idx2].offset--;
++ layout->oobfree[idx2].length = 5;
++ } else {
++ layout->oobfree[idx2].offset = i * sas;
++ layout->oobfree[idx2].length = 6;
++ }
++ idx2++;
++ layout->eccpos[idx1++] = i * sas + 6;
++ layout->eccpos[idx1++] = i * sas + 7;
++ layout->eccpos[idx1++] = i * sas + 8;
++ layout->oobfree[idx2].offset = i * sas + 9;
++ layout->oobfree[idx2].length = 7;
++ idx2++;
++ /* Leave zero-terminated entry for OOBFREE */
++ if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
++ idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
++ break;
++ }
++ goto out;
++ }
++
++ /*
++ * CONTROLLER_VERSION:
++ * < v5.0: ECC_REQ = ceil(BCH_T * 13/8)
++ * >= v5.0: ECC_REQ = ceil(BCH_T * 14/8)
++ * But we will just be conservative.
++ */
++ req = DIV_ROUND_UP(ecc_level * 14, 8);
++ if (req >= sas) {
++ dev_err(&host->pdev->dev,
++ "error: ECC too large for OOB (ECC bytes %d, spare sector %d)\n",
++ req, sas);
++ return NULL;
++ }
++
++ layout->eccbytes = req * sectors;
++ for (i = 0, idx1 = 0, idx2 = 0; i < sectors; i++) {
++ for (j = sas - req; j < sas && idx1 <
++ MTD_MAX_ECCPOS_ENTRIES_LARGE; j++, idx1++)
++ layout->eccpos[idx1] = i * sas + j;
++
++ /* First sector of each page may have BBI */
++ if (i == 0) {
++ if (cfg->page_size == 512 && (sas - req >= 6)) {
++ /* Small-page NAND use byte 6 for BBI */
++ layout->oobfree[idx2].offset = 0;
++ layout->oobfree[idx2].length = 5;
++ idx2++;
++ if (sas - req > 6) {
++ layout->oobfree[idx2].offset = 6;
++ layout->oobfree[idx2].length =
++ sas - req - 6;
++ idx2++;
++ }
++ } else if (sas > req + 1) {
++ layout->oobfree[idx2].offset = i * sas + 1;
++ layout->oobfree[idx2].length = sas - req - 1;
++ idx2++;
++ }
++ } else if (sas > req) {
++ layout->oobfree[idx2].offset = i * sas;
++ layout->oobfree[idx2].length = sas - req;
++ idx2++;
++ }
++ /* Leave zero-terminated entry for OOBFREE */
++ if (idx1 >= MTD_MAX_ECCPOS_ENTRIES_LARGE ||
++ idx2 >= MTD_MAX_OOBFREE_ENTRIES_LARGE - 1)
++ break;
++ }
++out:
++ /* Sum available OOB */
++ for (i = 0; i < MTD_MAX_OOBFREE_ENTRIES_LARGE; i++)
++ layout->oobavail += layout->oobfree[i].length;
++ return layout;
++}
++
++static struct nand_ecclayout *brcmstb_choose_ecc_layout(
++ struct brcmnand_host *host)
++{
++ struct nand_ecclayout *layout;
++ struct brcmnand_cfg *p = &host->hwcfg;
++ unsigned int ecc_level = p->ecc_level;
++
++ if (p->sector_size_1k)
++ ecc_level <<= 1;
++
++ layout = brcmnand_create_layout(ecc_level, host);
++ if (!layout) {
++ dev_err(&host->pdev->dev,
++ "no proper ecc_layout for this NAND cfg\n");
++ return NULL;
++ }
++
++ return layout;
++}
++
++static void brcmnand_wp(struct mtd_info *mtd, int wp)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++
++ if ((ctrl->features & BRCMNAND_HAS_WP) && wp_on == 1) {
++ static int old_wp = -1;
++
++ if (old_wp != wp) {
++ dev_dbg(ctrl->dev, "WP %s\n", wp ? "on" : "off");
++ old_wp = wp;
++ }
++ brcmnand_set_wp(ctrl, wp);
++ }
++}
++
++/* Helper functions for reading and writing OOB registers */
++static inline u8 oob_reg_read(struct brcmnand_controller *ctrl, u32 offs)
++{
++ u16 offset0, offset10, reg_offs;
++
++ offset0 = ctrl->reg_offsets[BRCMNAND_OOB_READ_BASE];
++ offset10 = ctrl->reg_offsets[BRCMNAND_OOB_READ_10_BASE];
++
++ if (offs >= ctrl->max_oob)
++ return 0x77;
++
++ if (offs >= 16 && offset10)
++ reg_offs = offset10 + ((offs - 0x10) & ~0x03);
++ else
++ reg_offs = offset0 + (offs & ~0x03);
++
++ return nand_readreg(ctrl, reg_offs) >> (24 - ((offs & 0x03) << 3));
++}
++
++static inline void oob_reg_write(struct brcmnand_controller *ctrl, u32 offs,
++ u32 data)
++{
++ u16 offset0, offset10, reg_offs;
++
++ offset0 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_BASE];
++ offset10 = ctrl->reg_offsets[BRCMNAND_OOB_WRITE_10_BASE];
++
++ if (offs >= ctrl->max_oob)
++ return;
++
++ if (offs >= 16 && offset10)
++ reg_offs = offset10 + ((offs - 0x10) & ~0x03);
++ else
++ reg_offs = offset0 + (offs & ~0x03);
++
++ nand_writereg(ctrl, reg_offs, data);
++}
++
++/*
++ * read_oob_from_regs - read data from OOB registers
++ * @ctrl: NAND controller
++ * @i: sub-page sector index
++ * @oob: buffer to read to
++ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
++ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
++ */
++static int read_oob_from_regs(struct brcmnand_controller *ctrl, int i, u8 *oob,
++ int sas, int sector_1k)
++{
++ int tbytes = sas << sector_1k;
++ int j;
++
++ /* Adjust OOB values for 1K sector size */
++ if (sector_1k && (i & 0x01))
++ tbytes = max(0, tbytes - (int)ctrl->max_oob);
++ tbytes = min_t(int, tbytes, ctrl->max_oob);
++
++ for (j = 0; j < tbytes; j++)
++ oob[j] = oob_reg_read(ctrl, j);
++ return tbytes;
++}
++
++/*
++ * write_oob_to_regs - write data to OOB registers
++ * @i: sub-page sector index
++ * @oob: buffer to write from
++ * @sas: spare area sector size (i.e., OOB size per FLASH_CACHE)
++ * @sector_1k: 1 for 1KiB sectors, 0 for 512B, other values are illegal
++ */
++static int write_oob_to_regs(struct brcmnand_controller *ctrl, int i,
++ const u8 *oob, int sas, int sector_1k)
++{
++ int tbytes = sas << sector_1k;
++ int j;
++
++ /* Adjust OOB values for 1K sector size */
++ if (sector_1k && (i & 0x01))
++ tbytes = max(0, tbytes - (int)ctrl->max_oob);
++ tbytes = min_t(int, tbytes, ctrl->max_oob);
++
++ for (j = 0; j < tbytes; j += 4)
++ oob_reg_write(ctrl, j,
++ (oob[j + 0] << 24) |
++ (oob[j + 1] << 16) |
++ (oob[j + 2] << 8) |
++ (oob[j + 3] << 0));
++ return tbytes;
++}
++
++static irqreturn_t brcmnand_ctlrdy_irq(int irq, void *data)
++{
++ struct brcmnand_controller *ctrl = data;
++
++ /* Discard all NAND_CTLRDY interrupts during DMA */
++ if (ctrl->dma_pending)
++ return IRQ_HANDLED;
++
++ complete(&ctrl->done);
++ return IRQ_HANDLED;
++}
++
++/* Handle SoC-specific interrupt hardware */
++static irqreturn_t brcmnand_irq(int irq, void *data)
++{
++ struct brcmnand_controller *ctrl = data;
++
++ if (ctrl->soc->ctlrdy_ack(ctrl->soc))
++ return brcmnand_ctlrdy_irq(irq, data);
++
++ return IRQ_NONE;
++}
++
++static irqreturn_t brcmnand_dma_irq(int irq, void *data)
++{
++ struct brcmnand_controller *ctrl = data;
++
++ complete(&ctrl->dma_done);
++
++ return IRQ_HANDLED;
++}
++
++static void brcmnand_send_cmd(struct brcmnand_host *host, int cmd)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u32 intfc;
++
++ dev_dbg(ctrl->dev, "send native cmd %d addr_lo 0x%x\n", cmd,
++ brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS));
++ BUG_ON(ctrl->cmd_pending != 0);
++ ctrl->cmd_pending = cmd;
++
++ intfc = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
++ BUG_ON(!(intfc & INTFC_CTLR_READY));
++
++ mb(); /* flush previous writes */
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_START,
++ cmd << brcmnand_cmd_shift(ctrl));
++}
++
++/***********************************************************************
++ * NAND MTD API: read/program/erase
++ ***********************************************************************/
++
++static void brcmnand_cmd_ctrl(struct mtd_info *mtd, int dat,
++ unsigned int ctrl)
++{
++ /* intentionally left blank */
++}
++
++static int brcmnand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ unsigned long timeo = msecs_to_jiffies(100);
++
++ dev_dbg(ctrl->dev, "wait on native cmd %d\n", ctrl->cmd_pending);
++ if (ctrl->cmd_pending &&
++ wait_for_completion_timeout(&ctrl->done, timeo) <= 0) {
++ u32 cmd = brcmnand_read_reg(ctrl, BRCMNAND_CMD_START)
++ >> brcmnand_cmd_shift(ctrl);
++
++ dev_err_ratelimited(ctrl->dev,
++ "timeout waiting for command %#02x\n", cmd);
++ dev_err_ratelimited(ctrl->dev, "intfc status %08x\n",
++ brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS));
++ }
++ ctrl->cmd_pending = 0;
++ return brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
++ INTFC_FLASH_STATUS;
++}
++
++enum {
++ LLOP_RE = BIT(16),
++ LLOP_WE = BIT(17),
++ LLOP_ALE = BIT(18),
++ LLOP_CLE = BIT(19),
++ LLOP_RETURN_IDLE = BIT(31),
++
++ LLOP_DATA_MASK = GENMASK(15, 0),
++};
++
++static int brcmnand_low_level_op(struct brcmnand_host *host,
++ enum brcmnand_llop_type type, u32 data,
++ bool last_op)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *chip = &host->chip;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u32 tmp;
++
++ tmp = data & LLOP_DATA_MASK;
++ switch (type) {
++ case LL_OP_CMD:
++ tmp |= LLOP_WE | LLOP_CLE;
++ break;
++ case LL_OP_ADDR:
++ /* WE | ALE */
++ tmp |= LLOP_WE | LLOP_ALE;
++ break;
++ case LL_OP_WR:
++ /* WE */
++ tmp |= LLOP_WE;
++ break;
++ case LL_OP_RD:
++ /* RE */
++ tmp |= LLOP_RE;
++ break;
++ }
++ if (last_op)
++ /* RETURN_IDLE */
++ tmp |= LLOP_RETURN_IDLE;
++
++ dev_dbg(ctrl->dev, "ll_op cmd %#x\n", tmp);
++
++ brcmnand_write_reg(ctrl, BRCMNAND_LL_OP, tmp);
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_LL_OP);
++
++ brcmnand_send_cmd(host, CMD_LOW_LEVEL_OP);
++ return brcmnand_waitfunc(mtd, chip);
++}
++
++static void brcmnand_cmdfunc(struct mtd_info *mtd, unsigned command,
++ int column, int page_addr)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u64 addr = (u64)page_addr << chip->page_shift;
++ int native_cmd = 0;
++
++ if (command == NAND_CMD_READID || command == NAND_CMD_PARAM ||
++ command == NAND_CMD_RNDOUT)
++ addr = (u64)column;
++ /* Avoid propagating a negative, don't-care address */
++ else if (page_addr < 0)
++ addr = 0;
++
++ dev_dbg(ctrl->dev, "cmd 0x%x addr 0x%llx\n", command,
++ (unsigned long long)addr);
++
++ host->last_cmd = command;
++ host->last_byte = 0;
++ host->last_addr = addr;
++
++ switch (command) {
++ case NAND_CMD_RESET:
++ native_cmd = CMD_FLASH_RESET;
++ break;
++ case NAND_CMD_STATUS:
++ native_cmd = CMD_STATUS_READ;
++ break;
++ case NAND_CMD_READID:
++ native_cmd = CMD_DEVICE_ID_READ;
++ break;
++ case NAND_CMD_READOOB:
++ native_cmd = CMD_SPARE_AREA_READ;
++ break;
++ case NAND_CMD_ERASE1:
++ native_cmd = CMD_BLOCK_ERASE;
++ brcmnand_wp(mtd, 0);
++ break;
++ case NAND_CMD_PARAM:
++ native_cmd = CMD_PARAMETER_READ;
++ break;
++ case NAND_CMD_SET_FEATURES:
++ case NAND_CMD_GET_FEATURES:
++ brcmnand_low_level_op(host, LL_OP_CMD, command, false);
++ brcmnand_low_level_op(host, LL_OP_ADDR, column, false);
++ break;
++ case NAND_CMD_RNDOUT:
++ native_cmd = CMD_PARAMETER_CHANGE_COL;
++ addr &= ~((u64)(FC_BYTES - 1));
++ /*
++ * HW quirk: PARAMETER_CHANGE_COL requires SECTOR_SIZE_1K=0
++ * NB: hwcfg.sector_size_1k may not be initialized yet
++ */
++ if (brcmnand_get_sector_size_1k(host)) {
++ host->hwcfg.sector_size_1k =
++ brcmnand_get_sector_size_1k(host);
++ brcmnand_set_sector_size_1k(host, 0);
++ }
++ break;
++ }
++
++ if (!native_cmd)
++ return;
++
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++ (host->cs << 16) | ((addr >> 32) & 0xffff));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS, lower_32_bits(addr));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++
++ brcmnand_send_cmd(host, native_cmd);
++ brcmnand_waitfunc(mtd, chip);
++
++ if (native_cmd == CMD_PARAMETER_READ ||
++ native_cmd == CMD_PARAMETER_CHANGE_COL) {
++ int i;
++
++ brcmnand_soc_data_bus_prepare(ctrl->soc);
++
++ /*
++ * Must cache the FLASH_CACHE now, since changes in
++ * SECTOR_SIZE_1K may invalidate it
++ */
++ for (i = 0; i < FC_WORDS; i++)
++ ctrl->flash_cache[i] = brcmnand_read_fc(ctrl, i);
++
++ brcmnand_soc_data_bus_unprepare(ctrl->soc);
++
++ /* Cleanup from HW quirk: restore SECTOR_SIZE_1K */
++ if (host->hwcfg.sector_size_1k)
++ brcmnand_set_sector_size_1k(host,
++ host->hwcfg.sector_size_1k);
++ }
++
++ /* Re-enable protection is necessary only after erase */
++ if (command == NAND_CMD_ERASE1)
++ brcmnand_wp(mtd, 1);
++}
++
++static uint8_t brcmnand_read_byte(struct mtd_info *mtd)
++{
++ struct nand_chip *chip = mtd->priv;
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ uint8_t ret = 0;
++ int addr, offs;
++
++ switch (host->last_cmd) {
++ case NAND_CMD_READID:
++ if (host->last_byte < 4)
++ ret = brcmnand_read_reg(ctrl, BRCMNAND_ID) >>
++ (24 - (host->last_byte << 3));
++ else if (host->last_byte < 8)
++ ret = brcmnand_read_reg(ctrl, BRCMNAND_ID_EXT) >>
++ (56 - (host->last_byte << 3));
++ break;
++
++ case NAND_CMD_READOOB:
++ ret = oob_reg_read(ctrl, host->last_byte);
++ break;
++
++ case NAND_CMD_STATUS:
++ ret = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS) &
++ INTFC_FLASH_STATUS;
++ if (wp_on) /* hide WP status */
++ ret |= NAND_STATUS_WP;
++ break;
++
++ case NAND_CMD_PARAM:
++ case NAND_CMD_RNDOUT:
++ addr = host->last_addr + host->last_byte;
++ offs = addr & (FC_BYTES - 1);
++
++ /* At FC_BYTES boundary, switch to next column */
++ if (host->last_byte > 0 && offs == 0)
++ chip->cmdfunc(mtd, NAND_CMD_RNDOUT, addr, -1);
++
++ ret = ctrl->flash_cache[offs >> 2] >>
++ (24 - ((offs & 0x03) << 3));
++ break;
++ case NAND_CMD_GET_FEATURES:
++ if (host->last_byte >= ONFI_SUBFEATURE_PARAM_LEN) {
++ ret = 0;
++ } else {
++ bool last = host->last_byte ==
++ ONFI_SUBFEATURE_PARAM_LEN - 1;
++ brcmnand_low_level_op(host, LL_OP_RD, 0, last);
++ ret = brcmnand_read_reg(ctrl, BRCMNAND_LL_RDATA) & 0xff;
++ }
++ }
++
++ dev_dbg(ctrl->dev, "read byte = 0x%02x\n", ret);
++ host->last_byte++;
++
++ return ret;
++}
++
++static void brcmnand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
++{
++ int i;
++
++ for (i = 0; i < len; i++, buf++)
++ *buf = brcmnand_read_byte(mtd);
++}
++
++static void brcmnand_write_buf(struct mtd_info *mtd, const uint8_t *buf,
++ int len)
++{
++ int i;
++ struct nand_chip *chip = mtd->priv;
++ struct brcmnand_host *host = chip->priv;
++
++ switch (host->last_cmd) {
++ case NAND_CMD_SET_FEATURES:
++ for (i = 0; i < len; i++)
++ brcmnand_low_level_op(host, LL_OP_WR, buf[i],
++ (i + 1) == len);
++ break;
++ default:
++ BUG();
++ break;
++ }
++}
++
++/**
++ * Construct a FLASH_DMA descriptor as part of a linked list. You must know the
++ * following ahead of time:
++ * - Is this descriptor the beginning or end of a linked list?
++ * - What is the (DMA) address of the next descriptor in the linked list?
++ */
++static int brcmnand_fill_dma_desc(struct brcmnand_host *host,
++ struct brcm_nand_dma_desc *desc, u64 addr,
++ dma_addr_t buf, u32 len, u8 dma_cmd,
++ bool begin, bool end,
++ dma_addr_t next_desc)
++{
++ memset(desc, 0, sizeof(*desc));
++ /* Descriptors are written in native byte order (wordwise) */
++ desc->next_desc = lower_32_bits(next_desc);
++ desc->next_desc_ext = upper_32_bits(next_desc);
++ desc->cmd_irq = (dma_cmd << 24) |
++ (end ? (0x03 << 8) : 0) | /* IRQ | STOP */
++ (!!begin) | ((!!end) << 1); /* head, tail */
++#ifdef CONFIG_CPU_BIG_ENDIAN
++ desc->cmd_irq |= 0x01 << 12;
++#endif
++ desc->dram_addr = lower_32_bits(buf);
++ desc->dram_addr_ext = upper_32_bits(buf);
++ desc->tfr_len = len;
++ desc->total_len = len;
++ desc->flash_addr = lower_32_bits(addr);
++ desc->flash_addr_ext = upper_32_bits(addr);
++ desc->cs = host->cs;
++ desc->status_valid = 0x01;
++ return 0;
++}
++
++/**
++ * Kick the FLASH_DMA engine, with a given DMA descriptor
++ */
++static void brcmnand_dma_run(struct brcmnand_host *host, dma_addr_t desc)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ unsigned long timeo = msecs_to_jiffies(100);
++
++ flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC, lower_32_bits(desc));
++ (void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC);
++ flash_dma_writel(ctrl, FLASH_DMA_FIRST_DESC_EXT, upper_32_bits(desc));
++ (void)flash_dma_readl(ctrl, FLASH_DMA_FIRST_DESC_EXT);
++
++ /* Start FLASH_DMA engine */
++ ctrl->dma_pending = true;
++ mb(); /* flush previous writes */
++ flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0x03); /* wake | run */
++
++ if (wait_for_completion_timeout(&ctrl->dma_done, timeo) <= 0) {
++ dev_err(ctrl->dev,
++ "timeout waiting for DMA; status %#x, error status %#x\n",
++ flash_dma_readl(ctrl, FLASH_DMA_STATUS),
++ flash_dma_readl(ctrl, FLASH_DMA_ERROR_STATUS));
++ }
++ ctrl->dma_pending = false;
++ flash_dma_writel(ctrl, FLASH_DMA_CTRL, 0); /* force stop */
++}
++
++static int brcmnand_dma_trans(struct brcmnand_host *host, u64 addr, u32 *buf,
++ u32 len, u8 dma_cmd)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ dma_addr_t buf_pa;
++ int dir = dma_cmd == CMD_PAGE_READ ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
++
++ buf_pa = dma_map_single(ctrl->dev, buf, len, dir);
++ if (dma_mapping_error(ctrl->dev, buf_pa)) {
++ dev_err(ctrl->dev, "unable to map buffer for DMA\n");
++ return -ENOMEM;
++ }
++
++ brcmnand_fill_dma_desc(host, ctrl->dma_desc, addr, buf_pa, len,
++ dma_cmd, true, true, 0);
++
++ brcmnand_dma_run(host, ctrl->dma_pa);
++
++ dma_unmap_single(ctrl->dev, buf_pa, len, dir);
++
++ if (ctrl->dma_desc->status_valid & FLASH_DMA_ECC_ERROR)
++ return -EBADMSG;
++ else if (ctrl->dma_desc->status_valid & FLASH_DMA_CORR_ERROR)
++ return -EUCLEAN;
++
++ return 0;
++}
++
++/*
++ * Assumes proper CS is already set
++ */
++static int brcmnand_read_by_pio(struct mtd_info *mtd, struct nand_chip *chip,
++ u64 addr, unsigned int trans, u32 *buf,
++ u8 *oob, u64 *err_addr)
++{
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ int i, j, ret = 0;
++
++ /* Clear error addresses */
++ brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_ADDR, 0);
++ brcmnand_write_reg(ctrl, BRCMNAND_CORR_ADDR, 0);
++
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++ (host->cs << 16) | ((addr >> 32) & 0xffff));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++
++ for (i = 0; i < trans; i++, addr += FC_BYTES) {
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
++ lower_32_bits(addr));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++ /* SPARE_AREA_READ does not use ECC, so just use PAGE_READ */
++ brcmnand_send_cmd(host, CMD_PAGE_READ);
++ brcmnand_waitfunc(mtd, chip);
++
++ if (likely(buf)) {
++ brcmnand_soc_data_bus_prepare(ctrl->soc);
++
++ for (j = 0; j < FC_WORDS; j++, buf++)
++ *buf = brcmnand_read_fc(ctrl, j);
++
++ brcmnand_soc_data_bus_unprepare(ctrl->soc);
++ }
++
++ if (oob)
++ oob += read_oob_from_regs(ctrl, i, oob,
++ mtd->oobsize / trans,
++ host->hwcfg.sector_size_1k);
++
++ if (!ret) {
++ *err_addr = brcmnand_read_reg(ctrl,
++ BRCMNAND_UNCORR_ADDR) |
++ ((u64)(brcmnand_read_reg(ctrl,
++ BRCMNAND_UNCORR_EXT_ADDR)
++ & 0xffff) << 32);
++ if (*err_addr)
++ ret = -EBADMSG;
++ }
++
++ if (!ret) {
++ *err_addr = brcmnand_read_reg(ctrl,
++ BRCMNAND_CORR_ADDR) |
++ ((u64)(brcmnand_read_reg(ctrl,
++ BRCMNAND_CORR_EXT_ADDR)
++ & 0xffff) << 32);
++ if (*err_addr)
++ ret = -EUCLEAN;
++ }
++ }
++
++ return ret;
++}
++
++static int brcmnand_read(struct mtd_info *mtd, struct nand_chip *chip,
++ u64 addr, unsigned int trans, u32 *buf, u8 *oob)
++{
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u64 err_addr = 0;
++ int err;
++
++ dev_dbg(ctrl->dev, "read %llx -> %p\n", (unsigned long long)addr, buf);
++
++ brcmnand_write_reg(ctrl, BRCMNAND_UNCORR_COUNT, 0);
++
++ if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
++ err = brcmnand_dma_trans(host, addr, buf, trans * FC_BYTES,
++ CMD_PAGE_READ);
++ if (err) {
++ if (mtd_is_bitflip_or_eccerr(err))
++ err_addr = addr;
++ else
++ return -EIO;
++ }
++ } else {
++ if (oob)
++ memset(oob, 0x99, mtd->oobsize);
++
++ err = brcmnand_read_by_pio(mtd, chip, addr, trans, buf,
++ oob, &err_addr);
++ }
++
++ if (mtd_is_eccerr(err)) {
++ dev_dbg(ctrl->dev, "uncorrectable error at 0x%llx\n",
++ (unsigned long long)err_addr);
++ mtd->ecc_stats.failed++;
++ /* NAND layer expects zero on ECC errors */
++ return 0;
++ }
++
++ if (mtd_is_bitflip(err)) {
++ unsigned int corrected = brcmnand_count_corrected(ctrl);
++
++ dev_dbg(ctrl->dev, "corrected error at 0x%llx\n",
++ (unsigned long long)err_addr);
++ mtd->ecc_stats.corrected += corrected;
++ /* Always exceed the software-imposed threshold */
++ return max(mtd->bitflip_threshold, corrected);
++ }
++
++ return 0;
++}
++
++static int brcmnand_read_page(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ struct brcmnand_host *host = chip->priv;
++ u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
++
++ return brcmnand_read(mtd, chip, host->last_addr,
++ mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
++}
++
++static int brcmnand_read_page_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ uint8_t *buf, int oob_required, int page)
++{
++ struct brcmnand_host *host = chip->priv;
++ u8 *oob = oob_required ? (u8 *)chip->oob_poi : NULL;
++ int ret;
++
++ brcmnand_set_ecc_enabled(host, 0);
++ ret = brcmnand_read(mtd, chip, host->last_addr,
++ mtd->writesize >> FC_SHIFT, (u32 *)buf, oob);
++ brcmnand_set_ecc_enabled(host, 1);
++ return ret;
++}
++
++static int brcmnand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ return brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
++ mtd->writesize >> FC_SHIFT,
++ NULL, (u8 *)chip->oob_poi);
++}
++
++static int brcmnand_read_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ struct brcmnand_host *host = chip->priv;
++
++ brcmnand_set_ecc_enabled(host, 0);
++ brcmnand_read(mtd, chip, (u64)page << chip->page_shift,
++ mtd->writesize >> FC_SHIFT,
++ NULL, (u8 *)chip->oob_poi);
++ brcmnand_set_ecc_enabled(host, 1);
++ return 0;
++}
++
++static int brcmnand_read_subpage(struct mtd_info *mtd, struct nand_chip *chip,
++ uint32_t data_offs, uint32_t readlen,
++ uint8_t *bufpoi, int page)
++{
++ struct brcmnand_host *host = chip->priv;
++
++ return brcmnand_read(mtd, chip, host->last_addr + data_offs,
++ readlen >> FC_SHIFT, (u32 *)bufpoi, NULL);
++}
++
++static int brcmnand_write(struct mtd_info *mtd, struct nand_chip *chip,
++ u64 addr, const u32 *buf, u8 *oob)
++{
++ struct brcmnand_host *host = chip->priv;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ unsigned int i, j, trans = mtd->writesize >> FC_SHIFT;
++ int status, ret = 0;
++
++ dev_dbg(ctrl->dev, "write %llx <- %p\n", (unsigned long long)addr, buf);
++
++ if (unlikely((u32)buf & 0x03)) {
++ dev_warn(ctrl->dev, "unaligned buffer: %p\n", buf);
++ buf = (u32 *)((u32)buf & ~0x03);
++ }
++
++ brcmnand_wp(mtd, 0);
++
++ for (i = 0; i < ctrl->max_oob; i += 4)
++ oob_reg_write(ctrl, i, 0xffffffff);
++
++ if (has_flash_dma(ctrl) && !oob && flash_dma_buf_ok(buf)) {
++ if (brcmnand_dma_trans(host, addr, (u32 *)buf,
++ mtd->writesize, CMD_PROGRAM_PAGE))
++ ret = -EIO;
++ goto out;
++ }
++
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS,
++ (host->cs << 16) | ((addr >> 32) & 0xffff));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_EXT_ADDRESS);
++
++ for (i = 0; i < trans; i++, addr += FC_BYTES) {
++ /* full address MUST be set before populating FC */
++ brcmnand_write_reg(ctrl, BRCMNAND_CMD_ADDRESS,
++ lower_32_bits(addr));
++ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
++
++ if (buf) {
++ brcmnand_soc_data_bus_prepare(ctrl->soc);
++
++ for (j = 0; j < FC_WORDS; j++, buf++)
++ brcmnand_write_fc(ctrl, j, *buf);
++
++ brcmnand_soc_data_bus_unprepare(ctrl->soc);
++ } else if (oob) {
++ for (j = 0; j < FC_WORDS; j++)
++ brcmnand_write_fc(ctrl, j, 0xffffffff);
++ }
++
++ if (oob) {
++ oob += write_oob_to_regs(ctrl, i, oob,
++ mtd->oobsize / trans,
++ host->hwcfg.sector_size_1k);
++ }
++
++ /* we cannot use SPARE_AREA_PROGRAM when PARTIAL_PAGE_EN=0 */
++ brcmnand_send_cmd(host, CMD_PROGRAM_PAGE);
++ status = brcmnand_waitfunc(mtd, chip);
++
++ if (status & NAND_STATUS_FAIL) {
++ dev_info(ctrl->dev, "program failed at %llx\n",
++ (unsigned long long)addr);
++ ret = -EIO;
++ goto out;
++ }
++ }
++out:
++ brcmnand_wp(mtd, 1);
++ return ret;
++}
++
++static int brcmnand_write_page(struct mtd_info *mtd, struct nand_chip *chip,
++ const uint8_t *buf, int oob_required)
++{
++ struct brcmnand_host *host = chip->priv;
++ void *oob = oob_required ? chip->oob_poi : NULL;
++
++ brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
++ return 0;
++}
++
++static int brcmnand_write_page_raw(struct mtd_info *mtd,
++ struct nand_chip *chip, const uint8_t *buf,
++ int oob_required)
++{
++ struct brcmnand_host *host = chip->priv;
++ void *oob = oob_required ? chip->oob_poi : NULL;
++
++ brcmnand_set_ecc_enabled(host, 0);
++ brcmnand_write(mtd, chip, host->last_addr, (const u32 *)buf, oob);
++ brcmnand_set_ecc_enabled(host, 1);
++ return 0;
++}
++
++static int brcmnand_write_oob(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ return brcmnand_write(mtd, chip, (u64)page << chip->page_shift,
++ NULL, chip->oob_poi);
++}
++
++static int brcmnand_write_oob_raw(struct mtd_info *mtd, struct nand_chip *chip,
++ int page)
++{
++ struct brcmnand_host *host = chip->priv;
++ int ret;
++
++ brcmnand_set_ecc_enabled(host, 0);
++ ret = brcmnand_write(mtd, chip, (u64)page << chip->page_shift, NULL,
++ (u8 *)chip->oob_poi);
++ brcmnand_set_ecc_enabled(host, 1);
++
++ return ret;
++}
++
++/***********************************************************************
++ * Per-CS setup (1 NAND device)
++ ***********************************************************************/
++
++static int brcmnand_set_cfg(struct brcmnand_host *host,
++ struct brcmnand_cfg *cfg)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ struct nand_chip *chip = &host->chip;
++ u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
++ u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_CFG_EXT);
++ u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_ACC_CONTROL);
++ u8 block_size = 0, page_size = 0, device_size = 0;
++ u32 tmp;
++
++ if (ctrl->block_sizes) {
++ int i, found;
++
++ for (i = 0, found = 0; ctrl->block_sizes[i]; i++)
++ if (ctrl->block_sizes[i] * 1024 == cfg->block_size) {
++ block_size = i;
++ found = 1;
++ }
++ if (!found) {
++ dev_warn(ctrl->dev, "invalid block size %u\n",
++ cfg->block_size);
++ return -EINVAL;
++ }
++ } else {
++ block_size = ffs(cfg->block_size) - ffs(BRCMNAND_MIN_BLOCKSIZE);
++ }
++
++ if (cfg->block_size < BRCMNAND_MIN_BLOCKSIZE || (ctrl->max_block_size &&
++ cfg->block_size > ctrl->max_block_size)) {
++ dev_warn(ctrl->dev, "invalid block size %u\n",
++ cfg->block_size);
++ block_size = 0;
++ }
++
++ if (ctrl->page_sizes) {
++ int i, found;
++
++ for (i = 0, found = 0; ctrl->page_sizes[i]; i++)
++ if (ctrl->page_sizes[i] == cfg->page_size) {
++ page_size = i;
++ found = 1;
++ }
++ if (!found) {
++ dev_warn(ctrl->dev, "invalid page size %u\n",
++ cfg->page_size);
++ return -EINVAL;
++ }
++ } else {
++ page_size = ffs(cfg->page_size) - ffs(BRCMNAND_MIN_PAGESIZE);
++ }
++
++ if (cfg->page_size < BRCMNAND_MIN_PAGESIZE || (ctrl->max_page_size &&
++ cfg->page_size > ctrl->max_page_size)) {
++ dev_warn(ctrl->dev, "invalid page size %u\n", cfg->page_size);
++ return -EINVAL;
++ }
++
++ if (fls64(cfg->device_size) < fls64(BRCMNAND_MIN_DEVSIZE)) {
++ dev_warn(ctrl->dev, "invalid device size 0x%llx\n",
++ (unsigned long long)cfg->device_size);
++ return -EINVAL;
++ }
++ device_size = fls64(cfg->device_size) - fls64(BRCMNAND_MIN_DEVSIZE);
++
++ tmp = (cfg->blk_adr_bytes << 8) |
++ (cfg->col_adr_bytes << 12) |
++ (cfg->ful_adr_bytes << 16) |
++ (!!(cfg->device_width == 16) << 23) |
++ (device_size << 24);
++ if (cfg_offs == cfg_ext_offs) {
++ tmp |= (page_size << 20) | (block_size << 28);
++ nand_writereg(ctrl, cfg_offs, tmp);
++ } else {
++ nand_writereg(ctrl, cfg_offs, tmp);
++ tmp = page_size | (block_size << 4);
++ nand_writereg(ctrl, cfg_ext_offs, tmp);
++ }
++
++ tmp = nand_readreg(ctrl, acc_control_offs);
++ tmp &= ~brcmnand_ecc_level_mask(ctrl);
++ tmp |= cfg->ecc_level << NAND_ACC_CONTROL_ECC_SHIFT;
++ tmp &= ~brcmnand_spare_area_mask(ctrl);
++ tmp |= cfg->spare_area_size;
++ nand_writereg(ctrl, acc_control_offs, tmp);
++
++ brcmnand_set_sector_size_1k(host, cfg->sector_size_1k);
++
++ /* threshold = ceil(BCH-level * 0.75) */
++ brcmnand_wr_corr_thresh(host, DIV_ROUND_UP(chip->ecc.strength * 3, 4));
++
++ return 0;
++}
++
++static void brcmnand_print_cfg(char *buf, struct brcmnand_cfg *cfg)
++{
++ buf += sprintf(buf,
++ "%lluMiB total, %uKiB blocks, %u%s pages, %uB OOB, %u-bit",
++ (unsigned long long)cfg->device_size >> 20,
++ cfg->block_size >> 10,
++ cfg->page_size >= 1024 ? cfg->page_size >> 10 : cfg->page_size,
++ cfg->page_size >= 1024 ? "KiB" : "B",
++ cfg->spare_area_size, cfg->device_width);
++
++ /* Account for Hamming ECC and for BCH 512B vs 1KiB sectors */
++ if (is_hamming_ecc(cfg))
++ sprintf(buf, ", Hamming ECC");
++ else if (cfg->sector_size_1k)
++ sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
++ else
++ sprintf(buf, ", BCH-%u", cfg->ecc_level);
++}
++
++/*
++ * Minimum number of bytes to address a page. Calculated as:
++ * roundup(log2(size / page-size) / 8)
++ *
++ * NB: the following does not "round up" for non-power-of-2 'size'; but this is
++ * OK because many other things will break if 'size' is irregular...
++ */
++static inline int get_blk_adr_bytes(u64 size, u32 writesize)
++{
++ return ALIGN(ilog2(size) - ilog2(writesize), 8) >> 3;
++}
++
++static int brcmnand_setup_dev(struct brcmnand_host *host)
++{
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *chip = &host->chip;
++ struct brcmnand_controller *ctrl = host->ctrl;
++ struct brcmnand_cfg *cfg = &host->hwcfg;
++ char msg[128];
++ u32 offs, tmp, oob_sector;
++ int ret;
++
++ memset(cfg, 0, sizeof(*cfg));
++
++ ret = of_property_read_u32(chip->dn, "brcm,nand-oob-sector-size",
++ &oob_sector);
++ if (ret) {
++ /* Use detected size */
++ cfg->spare_area_size = mtd->oobsize /
++ (mtd->writesize >> FC_SHIFT);
++ } else {
++ cfg->spare_area_size = oob_sector;
++ }
++ if (cfg->spare_area_size > ctrl->max_oob)
++ cfg->spare_area_size = ctrl->max_oob;
++ /*
++ * Set oobsize to be consistent with controller's spare_area_size, as
++ * the rest is inaccessible.
++ */
++ mtd->oobsize = cfg->spare_area_size * (mtd->writesize >> FC_SHIFT);
++
++ cfg->device_size = mtd->size;
++ cfg->block_size = mtd->erasesize;
++ cfg->page_size = mtd->writesize;
++ cfg->device_width = (chip->options & NAND_BUSWIDTH_16) ? 16 : 8;
++ cfg->col_adr_bytes = 2;
++ cfg->blk_adr_bytes = get_blk_adr_bytes(mtd->size, mtd->writesize);
++
++ switch (chip->ecc.size) {
++ case 512:
++ if (chip->ecc.strength == 1) /* Hamming */
++ cfg->ecc_level = 15;
++ else
++ cfg->ecc_level = chip->ecc.strength;
++ cfg->sector_size_1k = 0;
++ break;
++ case 1024:
++ if (!(ctrl->features & BRCMNAND_HAS_1K_SECTORS)) {
++ dev_err(ctrl->dev, "1KB sectors not supported\n");
++ return -EINVAL;
++ }
++ if (chip->ecc.strength & 0x1) {
++ dev_err(ctrl->dev,
++ "odd ECC not supported with 1KB sectors\n");
++ return -EINVAL;
++ }
++
++ cfg->ecc_level = chip->ecc.strength >> 1;
++ cfg->sector_size_1k = 1;
++ break;
++ default:
++ dev_err(ctrl->dev, "unsupported ECC size: %d\n",
++ chip->ecc.size);
++ return -EINVAL;
++ }
++
++ cfg->ful_adr_bytes = cfg->blk_adr_bytes;
++ if (mtd->writesize > 512)
++ cfg->ful_adr_bytes += cfg->col_adr_bytes;
++ else
++ cfg->ful_adr_bytes += 1;
++
++ ret = brcmnand_set_cfg(host, cfg);
++ if (ret)
++ return ret;
++
++ brcmnand_set_ecc_enabled(host, 1);
++
++ brcmnand_print_cfg(msg, cfg);
++ dev_info(ctrl->dev, "detected %s\n", msg);
++
++ /* Configure ACC_CONTROL */
++ offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_ACC_CONTROL);
++ tmp = nand_readreg(ctrl, offs);
++ tmp &= ~ACC_CONTROL_PARTIAL_PAGE;
++ tmp &= ~ACC_CONTROL_RD_ERASED;
++ tmp &= ~ACC_CONTROL_FAST_PGM_RDIN;
++ if (ctrl->features & BRCMNAND_HAS_PREFETCH) {
++ /*
++ * FIXME: Flash DMA + prefetch may see spurious erased-page ECC
++ * errors
++ */
++ if (has_flash_dma(ctrl))
++ tmp &= ~ACC_CONTROL_PREFETCH;
++ else
++ tmp |= ACC_CONTROL_PREFETCH;
++ }
++ nand_writereg(ctrl, offs, tmp);
++
++ return 0;
++}
++
++static int brcmnand_init_cs(struct brcmnand_host *host)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ struct device_node *dn = host->of_node;
++ struct platform_device *pdev = host->pdev;
++ struct mtd_info *mtd;
++ struct nand_chip *chip;
++ int ret = 0;
++ struct mtd_part_parser_data ppdata = { .of_node = dn };
++
++ ret = of_property_read_u32(dn, "reg", &host->cs);
++ if (ret) {
++ dev_err(&pdev->dev, "can't get chip-select\n");
++ return -ENXIO;
++ }
++
++ mtd = &host->mtd;
++ chip = &host->chip;
++
++ chip->dn = dn;
++ chip->priv = host;
++ mtd->priv = chip;
++ mtd->name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "brcmnand.%d",
++ host->cs);
++ mtd->owner = THIS_MODULE;
++ mtd->dev.parent = &pdev->dev;
++
++ chip->IO_ADDR_R = (void __iomem *)0xdeadbeef;
++ chip->IO_ADDR_W = (void __iomem *)0xdeadbeef;
++
++ chip->cmd_ctrl = brcmnand_cmd_ctrl;
++ chip->cmdfunc = brcmnand_cmdfunc;
++ chip->waitfunc = brcmnand_waitfunc;
++ chip->read_byte = brcmnand_read_byte;
++ chip->read_buf = brcmnand_read_buf;
++ chip->write_buf = brcmnand_write_buf;
++
++ chip->ecc.mode = NAND_ECC_HW;
++ chip->ecc.read_page = brcmnand_read_page;
++ chip->ecc.read_subpage = brcmnand_read_subpage;
++ chip->ecc.write_page = brcmnand_write_page;
++ chip->ecc.read_page_raw = brcmnand_read_page_raw;
++ chip->ecc.write_page_raw = brcmnand_write_page_raw;
++ chip->ecc.write_oob_raw = brcmnand_write_oob_raw;
++ chip->ecc.read_oob_raw = brcmnand_read_oob_raw;
++ chip->ecc.read_oob = brcmnand_read_oob;
++ chip->ecc.write_oob = brcmnand_write_oob;
++
++ chip->controller = &ctrl->controller;
++
++ if (nand_scan_ident(mtd, 1, NULL))
++ return -ENXIO;
++
++ chip->options |= NAND_NO_SUBPAGE_WRITE;
++ /*
++ * Avoid (for instance) kmap()'d buffers from JFFS2, which we can't DMA
++ * to/from, and have nand_base pass us a bounce buffer instead, as
++ * needed.
++ */
++ chip->options |= NAND_USE_BOUNCE_BUFFER;
++
++ if (of_get_nand_on_flash_bbt(dn))
++ chip->bbt_options |= NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
++
++ if (brcmnand_setup_dev(host))
++ return -ENXIO;
++
++ chip->ecc.size = host->hwcfg.sector_size_1k ? 1024 : 512;
++ /* only use our internal HW threshold */
++ mtd->bitflip_threshold = 1;
++
++ chip->ecc.layout = brcmstb_choose_ecc_layout(host);
++ if (!chip->ecc.layout)
++ return -ENXIO;
++
++ if (nand_scan_tail(mtd))
++ return -ENXIO;
++
++ return mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
++}
++
++static void brcmnand_save_restore_cs_config(struct brcmnand_host *host,
++ int restore)
++{
++ struct brcmnand_controller *ctrl = host->ctrl;
++ u16 cfg_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_CFG);
++ u16 cfg_ext_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_CFG_EXT);
++ u16 acc_control_offs = brcmnand_cs_offset(ctrl, host->cs,
++ BRCMNAND_CS_ACC_CONTROL);
++ u16 t1_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING1);
++ u16 t2_offs = brcmnand_cs_offset(ctrl, host->cs, BRCMNAND_CS_TIMING2);
++
++ if (restore) {
++ nand_writereg(ctrl, cfg_offs, host->hwcfg.config);
++ if (cfg_offs != cfg_ext_offs)
++ nand_writereg(ctrl, cfg_ext_offs,
++ host->hwcfg.config_ext);
++ nand_writereg(ctrl, acc_control_offs, host->hwcfg.acc_control);
++ nand_writereg(ctrl, t1_offs, host->hwcfg.timing_1);
++ nand_writereg(ctrl, t2_offs, host->hwcfg.timing_2);
++ } else {
++ host->hwcfg.config = nand_readreg(ctrl, cfg_offs);
++ if (cfg_offs != cfg_ext_offs)
++ host->hwcfg.config_ext =
++ nand_readreg(ctrl, cfg_ext_offs);
++ host->hwcfg.acc_control = nand_readreg(ctrl, acc_control_offs);
++ host->hwcfg.timing_1 = nand_readreg(ctrl, t1_offs);
++ host->hwcfg.timing_2 = nand_readreg(ctrl, t2_offs);
++ }
++}
++
++static int brcmnand_suspend(struct device *dev)
++{
++ struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
++ struct brcmnand_host *host;
++
++ list_for_each_entry(host, &ctrl->host_list, node)
++ brcmnand_save_restore_cs_config(host, 0);
++
++ ctrl->nand_cs_nand_select = brcmnand_read_reg(ctrl, BRCMNAND_CS_SELECT);
++ ctrl->nand_cs_nand_xor = brcmnand_read_reg(ctrl, BRCMNAND_CS_XOR);
++ ctrl->corr_stat_threshold =
++ brcmnand_read_reg(ctrl, BRCMNAND_CORR_THRESHOLD);
++
++ if (has_flash_dma(ctrl))
++ ctrl->flash_dma_mode = flash_dma_readl(ctrl, FLASH_DMA_MODE);
++
++ return 0;
++}
++
++static int brcmnand_resume(struct device *dev)
++{
++ struct brcmnand_controller *ctrl = dev_get_drvdata(dev);
++ struct brcmnand_host *host;
++
++ if (has_flash_dma(ctrl)) {
++ flash_dma_writel(ctrl, FLASH_DMA_MODE, ctrl->flash_dma_mode);
++ flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
++ }
++
++ brcmnand_write_reg(ctrl, BRCMNAND_CS_SELECT, ctrl->nand_cs_nand_select);
++ brcmnand_write_reg(ctrl, BRCMNAND_CS_XOR, ctrl->nand_cs_nand_xor);
++ brcmnand_write_reg(ctrl, BRCMNAND_CORR_THRESHOLD,
++ ctrl->corr_stat_threshold);
++ if (ctrl->soc) {
++ /* Clear/re-enable interrupt */
++ ctrl->soc->ctlrdy_ack(ctrl->soc);
++ ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
++ }
++
++ list_for_each_entry(host, &ctrl->host_list, node) {
++ struct mtd_info *mtd = &host->mtd;
++ struct nand_chip *chip = mtd->priv;
++
++ brcmnand_save_restore_cs_config(host, 1);
++
++ /* Reset the chip, required by some chips after power-up */
++ chip->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
++ }
++
++ return 0;
++}
++
++const struct dev_pm_ops brcmnand_pm_ops = {
++ .suspend = brcmnand_suspend,
++ .resume = brcmnand_resume,
++};
++EXPORT_SYMBOL_GPL(brcmnand_pm_ops);
++
++static const struct of_device_id brcmnand_of_match[] = {
++ { .compatible = "brcm,brcmnand-v4.0" },
++ { .compatible = "brcm,brcmnand-v5.0" },
++ { .compatible = "brcm,brcmnand-v6.0" },
++ { .compatible = "brcm,brcmnand-v6.1" },
++ { .compatible = "brcm,brcmnand-v7.0" },
++ { .compatible = "brcm,brcmnand-v7.1" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, brcmnand_of_match);
++
++/***********************************************************************
++ * Platform driver setup (per controller)
++ ***********************************************************************/
++
++int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *dn = dev->of_node, *child;
++ struct brcmnand_controller *ctrl;
++ struct resource *res;
++ int ret;
++
++ /* We only support device-tree instantiation */
++ if (!dn)
++ return -ENODEV;
++
++ if (!of_match_node(brcmnand_of_match, dn))
++ return -ENODEV;
++
++ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
++ if (!ctrl)
++ return -ENOMEM;
++
++ dev_set_drvdata(dev, ctrl);
++ ctrl->dev = dev;
++
++ init_completion(&ctrl->done);
++ init_completion(&ctrl->dma_done);
++ spin_lock_init(&ctrl->controller.lock);
++ init_waitqueue_head(&ctrl->controller.wq);
++ INIT_LIST_HEAD(&ctrl->host_list);
++
++ /* NAND register range */
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ ctrl->nand_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ctrl->nand_base))
++ return PTR_ERR(ctrl->nand_base);
++
++ /* Initialize NAND revision */
++ ret = brcmnand_revision_init(ctrl);
++ if (ret)
++ return ret;
++
++ /*
++ * Most chips have this cache at a fixed offset within 'nand' block.
++ * Some must specify this region separately.
++ */
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand-cache");
++ if (res) {
++ ctrl->nand_fc = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ctrl->nand_fc))
++ return PTR_ERR(ctrl->nand_fc);
++ } else {
++ ctrl->nand_fc = ctrl->nand_base +
++ ctrl->reg_offsets[BRCMNAND_FC_BASE];
++ }
++
++ /* FLASH_DMA */
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "flash-dma");
++ if (res) {
++ ctrl->flash_dma_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(ctrl->flash_dma_base))
++ return PTR_ERR(ctrl->flash_dma_base);
++
++ flash_dma_writel(ctrl, FLASH_DMA_MODE, 1); /* linked-list */
++ flash_dma_writel(ctrl, FLASH_DMA_ERROR_STATUS, 0);
++
++ /* Allocate descriptor(s) */
++ ctrl->dma_desc = dmam_alloc_coherent(dev,
++ sizeof(*ctrl->dma_desc),
++ &ctrl->dma_pa, GFP_KERNEL);
++ if (!ctrl->dma_desc)
++ return -ENOMEM;
++
++ ctrl->dma_irq = platform_get_irq(pdev, 1);
++ if ((int)ctrl->dma_irq < 0) {
++ dev_err(dev, "missing FLASH_DMA IRQ\n");
++ return -ENODEV;
++ }
++
++ ret = devm_request_irq(dev, ctrl->dma_irq,
++ brcmnand_dma_irq, 0, DRV_NAME,
++ ctrl);
++ if (ret < 0) {
++ dev_err(dev, "can't allocate IRQ %d: error %d\n",
++ ctrl->dma_irq, ret);
++ return ret;
++ }
++
++ dev_info(dev, "enabling FLASH_DMA\n");
++ }
++
++ /* Disable automatic device ID config, direct addressing */
++ brcmnand_rmw_reg(ctrl, BRCMNAND_CS_SELECT,
++ CS_SELECT_AUTO_DEVICE_ID_CFG | 0xff, 0, 0);
++ /* Disable XOR addressing */
++ brcmnand_rmw_reg(ctrl, BRCMNAND_CS_XOR, 0xff, 0, 0);
++
++ if (ctrl->features & BRCMNAND_HAS_WP) {
++ /* Permanently disable write protection */
++ if (wp_on == 2)
++ brcmnand_set_wp(ctrl, false);
++ } else {
++ wp_on = 0;
++ }
++
++ /* IRQ */
++ ctrl->irq = platform_get_irq(pdev, 0);
++ if ((int)ctrl->irq < 0) {
++ dev_err(dev, "no IRQ defined\n");
++ return -ENODEV;
++ }
++
++ /*
++ * Some SoCs integrate this controller (e.g., its interrupt bits) in
++ * interesting ways
++ */
++ if (soc) {
++ ctrl->soc = soc;
++
++ ret = devm_request_irq(dev, ctrl->irq, brcmnand_irq, 0,
++ DRV_NAME, ctrl);
++
++ /* Enable interrupt */
++ ctrl->soc->ctlrdy_ack(ctrl->soc);
++ ctrl->soc->ctlrdy_set_enabled(ctrl->soc, true);
++ } else {
++ /* Use standard interrupt infrastructure */
++ ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
++ DRV_NAME, ctrl);
++ }
++ if (ret < 0) {
++ dev_err(dev, "can't allocate IRQ %d: error %d\n",
++ ctrl->irq, ret);
++ return ret;
++ }
++
++ for_each_available_child_of_node(dn, child) {
++ if (of_device_is_compatible(child, "brcm,nandcs")) {
++ struct brcmnand_host *host;
++
++ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
++ if (!host)
++ return -ENOMEM;
++ host->pdev = pdev;
++ host->ctrl = ctrl;
++ host->of_node = child;
++
++ ret = brcmnand_init_cs(host);
++ if (ret)
++ continue; /* Try all chip-selects */
++
++ list_add_tail(&host->node, &ctrl->host_list);
++ }
++ }
++
++ /* No chip-selects could initialize properly */
++ if (list_empty(&ctrl->host_list))
++ return -ENODEV;
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(brcmnand_probe);
++
++int brcmnand_remove(struct platform_device *pdev)
++{
++ struct brcmnand_controller *ctrl = dev_get_drvdata(&pdev->dev);
++ struct brcmnand_host *host;
++
++ list_for_each_entry(host, &ctrl->host_list, node)
++ nand_release(&host->mtd);
++
++ dev_set_drvdata(&pdev->dev, NULL);
++
++ return 0;
++}
++EXPORT_SYMBOL_GPL(brcmnand_remove);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Kevin Cernekee");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for Broadcom chips");
++MODULE_ALIAS("platform:brcmnand");
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/brcmnand.h
+@@ -0,0 +1,71 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __BRCMNAND_H__
++#define __BRCMNAND_H__
++
++#include <linux/types.h>
++#include <linux/io.h>
++
++struct platform_device;
++struct dev_pm_ops;
++
++struct brcmnand_soc {
++ bool (*ctlrdy_ack)(struct brcmnand_soc *soc);
++ void (*ctlrdy_set_enabled)(struct brcmnand_soc *soc, bool en);
++ void (*prepare_data_bus)(struct brcmnand_soc *soc, bool prepare);
++};
++
++static inline void brcmnand_soc_data_bus_prepare(struct brcmnand_soc *soc)
++{
++ if (soc && soc->prepare_data_bus)
++ soc->prepare_data_bus(soc, true);
++}
++
++static inline void brcmnand_soc_data_bus_unprepare(struct brcmnand_soc *soc)
++{
++ if (soc && soc->prepare_data_bus)
++ soc->prepare_data_bus(soc, false);
++}
++
++static inline u32 brcmnand_readl(void __iomem *addr)
++{
++ /*
++ * MIPS endianness is configured by boot strap, which also reverses all
++ * bus endianness (i.e., big-endian CPU + big endian bus ==> native
++ * endian I/O).
++ *
++ * Other architectures (e.g., ARM) either do not support big endian, or
++ * else leave I/O in little endian mode.
++ */
++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
++ return __raw_readl(addr);
++ else
++ return readl_relaxed(addr);
++}
++
++static inline void brcmnand_writel(u32 val, void __iomem *addr)
++{
++ /* See brcmnand_readl() comments */
++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
++ __raw_writel(val, addr);
++ else
++ writel_relaxed(val, addr);
++}
++
++int brcmnand_probe(struct platform_device *pdev, struct brcmnand_soc *soc);
++int brcmnand_remove(struct platform_device *pdev);
++
++extern const struct dev_pm_ops brcmnand_pm_ops;
++
++#endif /* __BRCMNAND_H__ */
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/brcmstb_nand.c
+@@ -0,0 +1,44 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/device.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++
++#include "brcmnand.h"
++
++static const struct of_device_id brcmstb_nand_of_match[] = {
++ { .compatible = "brcm,brcmnand" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, brcmstb_nand_of_match);
++
++static int brcmstb_nand_probe(struct platform_device *pdev)
++{
++ return brcmnand_probe(pdev, NULL);
++}
++
++static struct platform_driver brcmstb_nand_driver = {
++ .probe = brcmstb_nand_probe,
++ .remove = brcmnand_remove,
++ .driver = {
++ .name = "brcmstb_nand",
++ .pm = &brcmnand_pm_ops,
++ .of_match_table = brcmstb_nand_of_match,
++ }
++};
++module_platform_driver(brcmstb_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_DESCRIPTION("NAND driver for Broadcom STB chips");
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/iproc_nand.c
+@@ -0,0 +1,150 @@
++/*
++ * Copyright © 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/device.h>
++#include <linux/io.h>
++#include <linux/ioport.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++#include <linux/platform_device.h>
++#include <linux/slab.h>
++
++#include "brcmnand.h"
++
++struct iproc_nand_soc {
++ struct brcmnand_soc soc;
++
++ void __iomem *idm_base;
++ void __iomem *ext_base;
++ spinlock_t idm_lock;
++};
++
++#define IPROC_NAND_CTLR_READY_OFFSET 0x10
++#define IPROC_NAND_CTLR_READY BIT(0)
++
++#define IPROC_NAND_IO_CTRL_OFFSET 0x00
++#define IPROC_NAND_APB_LE_MODE BIT(24)
++#define IPROC_NAND_INT_CTRL_READ_ENABLE BIT(6)
++
++static bool iproc_nand_intc_ack(struct brcmnand_soc *soc)
++{
++ struct iproc_nand_soc *priv =
++ container_of(soc, struct iproc_nand_soc, soc);
++ void __iomem *mmio = priv->ext_base + IPROC_NAND_CTLR_READY_OFFSET;
++ u32 val = brcmnand_readl(mmio);
++
++ if (val & IPROC_NAND_CTLR_READY) {
++ brcmnand_writel(IPROC_NAND_CTLR_READY, mmio);
++ return true;
++ }
++
++ return false;
++}
++
++static void iproc_nand_intc_set(struct brcmnand_soc *soc, bool en)
++{
++ struct iproc_nand_soc *priv =
++ container_of(soc, struct iproc_nand_soc, soc);
++ void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
++ u32 val;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->idm_lock, flags);
++
++ val = brcmnand_readl(mmio);
++
++ if (en)
++ val |= IPROC_NAND_INT_CTRL_READ_ENABLE;
++ else
++ val &= ~IPROC_NAND_INT_CTRL_READ_ENABLE;
++
++ brcmnand_writel(val, mmio);
++
++ spin_unlock_irqrestore(&priv->idm_lock, flags);
++}
++
++static void iproc_nand_apb_access(struct brcmnand_soc *soc, bool prepare)
++{
++ struct iproc_nand_soc *priv =
++ container_of(soc, struct iproc_nand_soc, soc);
++ void __iomem *mmio = priv->idm_base + IPROC_NAND_IO_CTRL_OFFSET;
++ u32 val;
++ unsigned long flags;
++
++ spin_lock_irqsave(&priv->idm_lock, flags);
++
++ val = brcmnand_readl(mmio);
++
++ if (prepare)
++ val |= IPROC_NAND_APB_LE_MODE;
++ else
++ val &= ~IPROC_NAND_APB_LE_MODE;
++
++ brcmnand_writel(val, mmio);
++
++ spin_unlock_irqrestore(&priv->idm_lock, flags);
++}
++
++static int iproc_nand_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct iproc_nand_soc *priv;
++ struct brcmnand_soc *soc;
++ struct resource *res;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++ soc = &priv->soc;
++
++ spin_lock_init(&priv->idm_lock);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-idm");
++ priv->idm_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->idm_base))
++ return PTR_ERR(priv->idm_base);
++
++ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "iproc-ext");
++ priv->ext_base = devm_ioremap_resource(dev, res);
++ if (IS_ERR(priv->ext_base))
++ return PTR_ERR(priv->ext_base);
++
++ soc->ctlrdy_ack = iproc_nand_intc_ack;
++ soc->ctlrdy_set_enabled = iproc_nand_intc_set;
++ soc->prepare_data_bus = iproc_nand_apb_access;
++
++ return brcmnand_probe(pdev, soc);
++}
++
++static const struct of_device_id iproc_nand_of_match[] = {
++ { .compatible = "brcm,nand-iproc" },
++ {},
++};
++MODULE_DEVICE_TABLE(of, iproc_nand_of_match);
++
++static struct platform_driver iproc_nand_driver = {
++ .probe = iproc_nand_probe,
++ .remove = brcmnand_remove,
++ .driver = {
++ .name = "iproc_nand",
++ .pm = &brcmnand_pm_ops,
++ .of_match_table = iproc_nand_of_match,
++ }
++};
++module_platform_driver(iproc_nand_driver);
++
++MODULE_LICENSE("GPL v2");
++MODULE_AUTHOR("Brian Norris");
++MODULE_AUTHOR("Ray Jui");
++MODULE_DESCRIPTION("NAND driver for Broadcom IPROC-based SoCs");
diff --git a/target/linux/bcm53xx/patches-4.1/101-use-part-parser.patch b/target/linux/bcm53xx/patches-4.1/101-use-part-parser.patch
new file mode 100644
index 0000000..8d48673
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/101-use-part-parser.patch
@@ -0,0 +1,11 @@
+--- a/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
++++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
+@@ -19,6 +19,8 @@
+
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
++
++ linux,part-probe = "ofpart", "bcm47xxpart";
+ };
+ };
+ };
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 0000000..7486649
--- /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
+@@ -2106,6 +2106,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 0000000..b914fd9
--- /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/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.1/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch
new file mode 100644
index 0000000..5e3bd77
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch
@@ -0,0 +1,635 @@
+From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001
+From: Kapil Hali <kapilh@broadcom.com>
+Date: Wed, 14 Oct 2015 13:47:00 -0400
+Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP
+
+Add SMP support for Broadcom's Northstar Plus SoC,
+cpu enable method and pen_release procedures. This
+changes also consolidates iProc family's - BCM NSP
+and BCM Kona, SMP handling in a common file.
+
+Northstar Plus SoC is based on ARM Cortex-A9
+revision r3p0 which requires configuration for ARM
+Errata 764369 for SMP. This change adds the needed
+configuration option.
+
+Signed-off-by: Kapil Hali <kapilh@broadcom.com>
+---
+ arch/arm/mach-bcm/Makefile | 2 +-
+ arch/arm/mach-bcm/bcm_nsp.h | 19 +++
+ arch/arm/mach-bcm/headsmp.S | 37 +++++
+ arch/arm/mach-bcm/kona_smp.c | 202 ---------------------------
+ arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 383 insertions(+), 203 deletions(-)
+ create mode 100644 arch/arm/mach-bcm/bcm_nsp.h
+ create mode 100644 arch/arm/mach-bcm/headsmp.S
+ delete mode 100644 arch/arm/mach-bcm/kona_smp.c
+ create mode 100644 arch/arm/mach-bcm/platsmp.c
+
+--- a/arch/arm/mach-bcm/Makefile
++++ b/arch/arm/mach-bcm/Makefile
+@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc
+ obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
+
+ # BCM281XX and BCM21664 SMP support
+-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
++obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
+
+ # BCM281XX and BCM21664 L2 cache control
+ obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
+--- /dev/null
++++ b/arch/arm/mach-bcm/bcm_nsp.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __BCM_NSP_H
++#define __BCM_NSP_H
++
++extern void nsp_secondary_startup(void);
++
++#endif /* __BCM_NSP_H */
+--- /dev/null
++++ b/arch/arm/mach-bcm/headsmp.S
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/linkage.h>
++
++/*
++ * iProc specific entry point for secondary CPUs. This provides
++ * a "holding pen" into which all secondary cores are held until
++ * we are ready for them to initialise.
++ */
++ENTRY(nsp_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
++
++ b secondary_startup
++
++1: .long .
++ .long pen_release
++
++ENDPROC(nsp_secondary_startup)
+--- a/arch/arm/mach-bcm/kona_smp.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/*
+- * Copyright (C) 2014 Broadcom Corporation
+- * Copyright 2014 Linaro Limited
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License as
+- * published by the Free Software Foundation version 2.
+- *
+- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+- * kind, whether express or implied; without even the implied warranty
+- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- */
+-
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/of.h>
+-#include <linux/sched.h>
+-
+-#include <asm/smp.h>
+-#include <asm/smp_plat.h>
+-#include <asm/smp_scu.h>
+-
+-/* Size of mapped Cortex A9 SCU address space */
+-#define CORTEX_A9_SCU_SIZE 0x58
+-
+-#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
+-#define BOOT_ADDR_CPUID_MASK 0x3
+-
+-/* Name of device node property defining secondary boot register location */
+-#define OF_SECONDARY_BOOT "secondary-boot-reg"
+-
+-/* I/O address of register used to coordinate secondary core startup */
+-static u32 secondary_boot;
+-
+-/*
+- * Enable the Cortex A9 Snoop Control Unit
+- *
+- * By the time this is called we already know there are multiple
+- * cores present. We assume we're running on a Cortex A9 processor,
+- * so any trouble getting the base address register or getting the
+- * SCU base is a problem.
+- *
+- * Return 0 if successful or an error code otherwise.
+- */
+-static int __init scu_a9_enable(void)
+-{
+- unsigned long config_base;
+- void __iomem *scu_base;
+-
+- if (!scu_a9_has_base()) {
+- pr_err("no configuration base address register!\n");
+- return -ENXIO;
+- }
+-
+- /* Config base address register value is zero for uniprocessor */
+- config_base = scu_a9_get_base();
+- if (!config_base) {
+- pr_err("hardware reports only one core\n");
+- return -ENOENT;
+- }
+-
+- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
+- if (!scu_base) {
+- pr_err("failed to remap config base (%lu/%u) for SCU\n",
+- config_base, CORTEX_A9_SCU_SIZE);
+- return -ENOMEM;
+- }
+-
+- scu_enable(scu_base);
+-
+- iounmap(scu_base); /* That's the last we'll need of this */
+-
+- return 0;
+-}
+-
+-static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
+-{
+- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
+- struct device_node *node;
+- int ret;
+-
+- BUG_ON(secondary_boot); /* We're called only once */
+-
+- /*
+- * This function is only called via smp_ops->smp_prepare_cpu().
+- * That only happens if a "/cpus" device tree node exists
+- * and has an "enable-method" property that selects the SMP
+- * operations defined herein.
+- */
+- node = of_find_node_by_path("/cpus");
+- BUG_ON(!node);
+-
+- /*
+- * Our secondary enable method requires a "secondary-boot-reg"
+- * property to specify a register address used to request the
+- * ROM code boot a secondary code. If we have any trouble
+- * getting this we fall back to uniprocessor mode.
+- */
+- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
+- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
+- node->name);
+- ret = -ENOENT; /* Arrange to disable SMP */
+- goto out;
+- }
+-
+- /*
+- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
+- * returned, the SoC reported a uniprocessor configuration.
+- * We bail on any other error.
+- */
+- ret = scu_a9_enable();
+-out:
+- of_node_put(node);
+- if (ret) {
+- /* Update the CPU present map to reflect uniprocessor mode */
+- BUG_ON(ret != -ENOENT);
+- pr_warn("disabling SMP\n");
+- init_cpu_present(&only_cpu_0);
+- }
+-}
+-
+-/*
+- * The ROM code has the secondary cores looping, waiting for an event.
+- * When an event occurs each core examines the bottom two bits of the
+- * secondary boot register. When a core finds those bits contain its
+- * own core id, it performs initialization, including computing its boot
+- * address by clearing the boot register value's bottom two bits. The
+- * core signals that it is beginning its execution by writing its boot
+- * address back to the secondary boot register, and finally jumps to
+- * that address.
+- *
+- * So to start a core executing we need to:
+- * - Encode the (hardware) CPU id with the bottom bits of the secondary
+- * start address.
+- * - Write that value into the secondary boot register.
+- * - Generate an event to wake up the secondary CPU(s).
+- * - Wait for the secondary boot register to be re-written, which
+- * indicates the secondary core has started.
+- */
+-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
+-{
+- void __iomem *boot_reg;
+- phys_addr_t boot_func;
+- u64 start_clock;
+- u32 cpu_id;
+- u32 boot_val;
+- bool timeout = false;
+-
+- cpu_id = cpu_logical_map(cpu);
+- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
+- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
+- return -EINVAL;
+- }
+-
+- if (!secondary_boot) {
+- pr_err("required secondary boot register not specified\n");
+- return -EINVAL;
+- }
+-
+- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
+- if (!boot_reg) {
+- pr_err("unable to map boot register for cpu %u\n", cpu_id);
+- return -ENOSYS;
+- }
+-
+- /*
+- * Secondary cores will start in secondary_startup(),
+- * defined in "arch/arm/kernel/head.S"
+- */
+- boot_func = virt_to_phys(secondary_startup);
+- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
+- BUG_ON(boot_func > (phys_addr_t)U32_MAX);
+-
+- /* The core to start is encoded in the low bits */
+- boot_val = (u32)boot_func | cpu_id;
+- writel_relaxed(boot_val, boot_reg);
+-
+- sev();
+-
+- /* The low bits will be cleared once the core has started */
+- start_clock = local_clock();
+- while (!timeout && readl_relaxed(boot_reg) == boot_val)
+- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
+-
+- iounmap(boot_reg);
+-
+- if (!timeout)
+- return 0;
+-
+- pr_err("timeout waiting for cpu %u to start\n", cpu_id);
+-
+- return -ENOSYS;
+-}
+-
+-static struct smp_operations bcm_smp_ops __initdata = {
+- .smp_prepare_cpus = bcm_smp_prepare_cpus,
+- .smp_boot_secondary = bcm_boot_secondary,
+-};
+-CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
+- &bcm_smp_ops);
+--- /dev/null
++++ b/arch/arm/mach-bcm/platsmp.c
+@@ -0,0 +1,326 @@
++/*
++ * Copyright (C) 2014-2015 Broadcom Corporation
++ * Copyright 2014 Linaro Limited
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cpumask.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/of.h>
++#include <linux/sched.h>
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++#include <asm/smp.h>
++#include <asm/smp_plat.h>
++#include <asm/smp_scu.h>
++
++#include "bcm_nsp.h"
++
++/* Size of mapped Cortex A9 SCU address space */
++#define CORTEX_A9_SCU_SIZE 0x58
++
++#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
++#define BOOT_ADDR_CPUID_MASK 0x3
++
++/* Name of device node property defining secondary boot register location */
++#define OF_SECONDARY_BOOT "secondary-boot-reg"
++
++/* I/O address of register used to coordinate secondary core startup */
++static u32 secondary_boot;
++
++static DEFINE_SPINLOCK(boot_lock);
++
++/*
++ * Write pen_release in a way that is guaranteed to be visible to all
++ * observers, irrespective of whether they're taking part in coherency
++ * or not. This is necessary for the hotplug code to work reliably.
++ */
++static void write_pen_release(int val)
++{
++ pen_release = val;
++ /*
++ * Ensure write to pen_release is visible to the other cores,
++ * here - primary core
++ */
++ smp_wmb();
++ sync_cache_w(&pen_release);
++}
++
++/*
++ * Enable the Cortex A9 Snoop Control Unit
++ *
++ * By the time this is called we already know there are multiple
++ * cores present. We assume we're running on a Cortex A9 processor,
++ * so any trouble getting the base address register or getting the
++ * SCU base is a problem.
++ *
++ * Return 0 if successful or an error code otherwise.
++ */
++static int __init scu_a9_enable(void)
++{
++ unsigned long config_base;
++ void __iomem *scu_base;
++
++ if (!scu_a9_has_base()) {
++ pr_err("no configuration base address register!\n");
++ return -ENXIO;
++ }
++
++ /* Config base address register value is zero for uniprocessor */
++ config_base = scu_a9_get_base();
++ if (!config_base) {
++ pr_err("hardware reports only one core\n");
++ return -ENOENT;
++ }
++
++ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
++ if (!scu_base) {
++ pr_err("failed to remap config base (%lu/%u) for SCU\n",
++ config_base, CORTEX_A9_SCU_SIZE);
++ return -ENOMEM;
++ }
++
++ scu_enable(scu_base);
++
++ iounmap(scu_base); /* That's the last we'll need of this */
++
++ return 0;
++}
++
++static int nsp_write_lut(void (*secondary_startup) (void))
++{
++ void __iomem *sku_rom_lut;
++ phys_addr_t secondary_startup_phy;
++
++ if (!secondary_boot) {
++ pr_warn("required secondary boot register not specified\n");
++ return -EINVAL;
++ }
++
++ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot,
++ sizeof(secondary_boot));
++ if (!sku_rom_lut) {
++ pr_warn("unable to ioremap SKU-ROM LUT register\n");
++ return -ENOMEM;
++ }
++
++ secondary_startup_phy = virt_to_phys(secondary_startup);
++ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
++
++ writel_relaxed(secondary_startup_phy, sku_rom_lut);
++ /*
++ * Ensure the write is visible to the secondary core.
++ */
++ smp_wmb();
++
++ iounmap(sku_rom_lut);
++
++ return 0;
++}
++
++static void nsp_secondary_init(unsigned int cpu)
++{
++ /*
++ * Let the primary cpu know we are out of holding pen.
++ */
++ write_pen_release(-1);
++
++ /*
++ * Synchronise with the boot thread.
++ */
++ spin_lock(&boot_lock);
++ spin_unlock(&boot_lock);
++}
++
++static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
++{
++ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
++ struct device_node *node;
++ int ret;
++
++ BUG_ON(secondary_boot); /* We're called only once */
++
++ /*
++ * This function is only called via smp_ops->smp_prepare_cpu().
++ * That only happens if a "/cpus" device tree node exists
++ * and has an "enable-method" property that selects the SMP
++ * operations defined herein.
++ */
++ node = of_find_node_by_path("/cpus");
++ BUG_ON(!node);
++
++ /*
++ * Our secondary enable method requires a "secondary-boot-reg"
++ * property to specify a register address used to request the
++ * ROM code boot a secondary core. If we have any trouble
++ * getting this we fall back to uniprocessor mode.
++ */
++ if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
++ pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
++ node->name);
++ ret = -ENOENT; /* Arrange to disable SMP */
++ goto out;
++ }
++
++ /*
++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
++ * returned, the SoC reported a uniprocessor configuration.
++ * We bail on any other error.
++ */
++ ret = scu_a9_enable();
++out:
++ of_node_put(node);
++ if (ret) {
++ /* Update the CPU present map to reflect uniprocessor mode */
++ pr_warn("disabling SMP\n");
++ init_cpu_present(&only_cpu_0);
++ }
++}
++
++/*
++ * The ROM code has the secondary cores looping, waiting for an event.
++ * When an event occurs each core examines the bottom two bits of the
++ * secondary boot register. When a core finds those bits contain its
++ * own core id, it performs initialization, including computing its boot
++ * address by clearing the boot register value's bottom two bits. The
++ * core signals that it is beginning its execution by writing its boot
++ * address back to the secondary boot register, and finally jumps to
++ * that address.
++ *
++ * So to start a core executing we need to:
++ * - Encode the (hardware) CPU id with the bottom bits of the secondary
++ * start address.
++ * - Write that value into the secondary boot register.
++ * - Generate an event to wake up the secondary CPU(s).
++ * - Wait for the secondary boot register to be re-written, which
++ * indicates the secondary core has started.
++ */
++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++ void __iomem *boot_reg;
++ phys_addr_t boot_func;
++ u64 start_clock;
++ u32 cpu_id;
++ u32 boot_val;
++ bool timeout = false;
++
++ cpu_id = cpu_logical_map(cpu);
++ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
++ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
++ return -EINVAL;
++ }
++
++ if (!secondary_boot) {
++ pr_err("required secondary boot register not specified\n");
++ return -EINVAL;
++ }
++
++ boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
++ if (!boot_reg) {
++ pr_err("unable to map boot register for cpu %u\n", cpu_id);
++ return -ENOMEM;
++ }
++
++ /*
++ * Secondary cores will start in secondary_startup(),
++ * defined in "arch/arm/kernel/head.S"
++ */
++ boot_func = virt_to_phys(secondary_startup);
++ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
++ BUG_ON(boot_func > (phys_addr_t)U32_MAX);
++
++ /* The core to start is encoded in the low bits */
++ boot_val = (u32)boot_func | cpu_id;
++ writel_relaxed(boot_val, boot_reg);
++
++ sev();
++
++ /* The low bits will be cleared once the core has started */
++ start_clock = local_clock();
++ while (!timeout && readl_relaxed(boot_reg) == boot_val)
++ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
++
++ iounmap(boot_reg);
++
++ if (!timeout)
++ return 0;
++
++ pr_err("timeout waiting for cpu %u to start\n", cpu_id);
++
++ return -ENXIO;
++}
++
++static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++ unsigned long timeout;
++ int ret;
++
++ /*
++ * After wake up, secondary core branches to the startup
++ * address programmed at SKU ROM LUT location.
++ */
++ ret = nsp_write_lut(nsp_secondary_startup);
++ if (ret) {
++ pr_err("unable to write startup addr to SKU ROM LUT\n");
++ goto out;
++ }
++
++ /*
++ * 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.
++ */
++ spin_lock(&boot_lock);
++
++ write_pen_release(cpu_logical_map(cpu));
++ /*
++ * Send an Event to wake up the secondary core which is in
++ * WFE state. Updated pen_release should also be visible to
++ * the secondary core.
++ */
++ dsb_sev();
++
++ timeout = jiffies + (1 * HZ);
++ while (time_before(jiffies, timeout)) {
++ /* Make sure loads on other CPU is visible */
++ smp_rmb();
++ if (pen_release == -1)
++ break;
++
++ udelay(10);
++ }
++
++ spin_unlock(&boot_lock);
++
++ ret = pen_release != -1 ? -ENXIO : 0;
++
++out:
++ return ret;
++}
++
++static struct smp_operations bcm_smp_ops __initdata = {
++ .smp_prepare_cpus = bcm_smp_prepare_cpus,
++ .smp_boot_secondary = kona_boot_secondary,
++};
++CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
++ &bcm_smp_ops);
++
++struct smp_operations nsp_smp_ops __initdata = {
++ .smp_prepare_cpus = bcm_smp_prepare_cpus,
++ .smp_secondary_init = nsp_secondary_init,
++ .smp_boot_secondary = nsp_boot_secondary,
++};
++CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);
diff --git a/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch
new file mode 100644
index 0000000..4cd0473
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch
@@ -0,0 +1,50 @@
+From ddbf0ad85be06948dd214c7beb7b315ef2749e65 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 14:14:10 -0400
+Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom 4708
+
+ARM: BCM: Add SMP support for Broadcom 4708
+
+Add SMP support for Broadcom's 4708 SoCs.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ arch/arm/boot/dts/bcm4708.dtsi | 2 ++
+ arch/arm/mach-bcm/Kconfig | 2 ++
+ arch/arm/mach-bcm/Makefile | 3 +++
+ 3 files changed, 7 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708.dtsi
++++ b/arch/arm/boot/dts/bcm4708.dtsi
+@@ -15,6 +15,8 @@
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
++ enable-method = "brcm,bcm-nsp-smp";
++ secondary-boot-reg = <0xffff0400>;
+
+ cpu@0 {
+ device_type = "cpu";
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -38,6 +38,8 @@ config ARCH_BCM_CYGNUS
+ config ARCH_BCM_5301X
+ bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
++ select ARM_ERRATA_764369 if SMP
++ select HAVE_SMP
+ help
+ Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
+
+--- 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_ARCH_BCM_5301X),y)
++obj-$(CONFIG_SMP) += headsmp.o platsmp.o
++endif
+
+ # BCM63XXx
+ obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o
diff --git a/target/linux/bcm53xx/patches-4.1/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch b/target/linux/bcm53xx/patches-4.1/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch
new file mode 100644
index 0000000..c117774
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch
@@ -0,0 +1,57 @@
+From b58682598541262f967ecd6db04bacac38026d3c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 30 Oct 2015 15:29:52 +0100
+Subject: [PATCH] ARM: BCM5301X: Add missing Netgear R8000 LEDs
+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/bcm4709-netgear-r8000.dts | 30 +++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+index 446c586..b52927c 100644
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -50,6 +50,36 @@
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
++
++ wireless {
++ label = "bcm53xx:white:wireless";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wps {
++ label = "bcm53xx:white:wps";
++ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ 5ghz-2 {
++ label = "bcm53xx:white:5ghz-2";
++ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3 {
++ label = "bcm53xx:white:usb3";
++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb2 {
++ label = "bcm53xx:white:usb2";
++ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
+ };
+
+ gpio-keys {
+--
+1.8.4.5
+
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 0000000..e5e3010
--- /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 0000000..5ae4e0d
--- /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 0000000..700d354
--- /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 0000000..91cd0fa
--- /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 0000000..bca555c
--- /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 0000000..d9a8a1e
--- /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/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch b/target/linux/bcm53xx/patches-4.1/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch
new file mode 100644
index 0000000..5031886
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch
@@ -0,0 +1,75 @@
+From 0cb136f9882e4649ad6160bb7b48955ff728888c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 1 Nov 2015 08:17:21 +0100
+Subject: [PATCH V2] USB: bcma: switch to GPIO descriptor for power control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far we were using simple (legacy) GPIO functions & some poor logic to
+control power. It got many drawbacks: we were ignoring OF flags
+(GPIO_ACTIVE_LOW), we were not setting direction to output and we were
+assuming gpio_request success all the time.
+Fix it by switching to gpiod functions and adding appropriate checks.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
+index 5398e3d..291aaa2 100644
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -21,6 +21,7 @@
+ */
+ #include <linux/bcma/bcma.h>
+ #include <linux/delay.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/platform_device.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+@@ -36,6 +37,7 @@ MODULE_LICENSE("GPL");
+ struct bcma_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
++ struct gpio_desc *gpio_desc;
+ };
+
+ /* Wait for bitmask in a register to get set or cleared.
+@@ -228,19 +230,12 @@ static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
+
+ static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
+ {
+- int gpio;
++ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+
+- gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
+- if (!gpio_is_valid(gpio))
++ if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
+ return;
+
+- if (val) {
+- gpio_request(gpio, "bcma-hcd-gpio");
+- gpio_set_value(gpio, 1);
+- } else {
+- gpio_set_value(gpio, 0);
+- gpio_free(gpio);
+- }
++ gpiod_set_value(usb_dev->gpio_desc, val);
+ }
+
+ static const struct usb_ehci_pdata ehci_pdata = {
+@@ -314,7 +309,11 @@ static int bcma_hcd_probe(struct bcma_device *dev)
+ if (!usb_dev)
+ return -ENOMEM;
+
+- bcma_hci_platform_power_gpio(dev, true);
++ if (dev->dev.of_node)
++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
++ &dev->dev.of_node->fwnode);
++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
++ gpiod_direction_output(usb_dev->gpio_desc, 1);
+
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
diff --git a/target/linux/bcm53xx/patches-4.1/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch b/target/linux/bcm53xx/patches-4.1/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch
new file mode 100644
index 0000000..c404b7d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch
@@ -0,0 +1,62 @@
+From 1420e53fc88673683f8990aa5342e7b2640ce165 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Oct 2015 19:13:27 +0200
+Subject: [PATCH v3 1/6] usb: xhci: plat: fix adding usb3-lpm-capable quirk
+
+The xhci->quirks member is overwritten in xhci_gen_setup() with the
+quirks given through the module load parameter. Without this patch the
+usb3-lpm-capable quirk will be over written before it gets used. This
+patch moves the quirks code to the xhci_plat_quirks() callback function
+which gets called directly after the quirks member variable is
+overwritten with the module load parameter.
+
+I do not have any hardware which is using usb3-lpm-capabls so I can not
+test this on real hardware.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/xhci-plat.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -28,12 +28,20 @@ static struct hc_driver __read_mostly xh
+
+ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
+ {
++ struct platform_device *pdev = to_platform_device(dev);
++ struct device_node *node = pdev->dev.of_node;
++ struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
++
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_PLAT;
++
++ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
++ (pdata && pdata->usb3_lpm_capable))
++ xhci->quirks |= XHCI_LPM_SUPPORT;
+ }
+
+ /* called during probe() after chip reset completes */
+@@ -65,8 +73,6 @@ static int xhci_plat_start(struct usb_hc
+
+ static int xhci_plat_probe(struct platform_device *pdev)
+ {
+- struct device_node *node = pdev->dev.of_node;
+- struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+ const struct hc_driver *driver;
+ struct xhci_hcd *xhci;
+ struct resource *res;
+@@ -144,9 +150,6 @@ static int xhci_plat_probe(struct platfo
+ goto dealloc_usb2_hcd;
+ }
+
+- if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
+- (pdata && pdata->usb3_lpm_capable))
+- xhci->quirks |= XHCI_LPM_SUPPORT;
+ /*
+ * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+ * is called by usb_add_hcd().
diff --git a/target/linux/bcm53xx/patches-4.1/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch b/target/linux/bcm53xx/patches-4.1/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
new file mode 100644
index 0000000..f25a9e5
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
@@ -0,0 +1,135 @@
+From dd0e5f9a6a4aed849bdb80641c2a2350476cede7 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 v3 2/6] usb: 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.
+This quirk is also added to the platform data so we can activate it
+when we register our platform driver.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/xhci-plat.c | 3 +++
+ drivers/usb/host/xhci.c | 57 +++++++++++++++++++++++++++++++++++++---
+ drivers/usb/host/xhci.h | 1 +
+ include/linux/usb/xhci_pdriver.h | 1 +
+ 4 files changed, 59 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -42,6 +42,9 @@ static void xhci_plat_quirks(struct devi
+ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
+ (pdata && pdata->usb3_lpm_capable))
+ xhci->quirks |= XHCI_LPM_SUPPORT;
++
++ if (pdata && pdata->usb3_fake_doorbell)
++ xhci->quirks |= XHCI_FAKE_DOORBELL;
+ }
+
+ /* called during probe() after chip reset completes */
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -121,6 +121,39 @@ int xhci_halt(struct xhci_hcd *xhci)
+ return ret;
+ }
+
++static int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id)
++{
++ u32 temp;
++
++ /* alloc a virt device for slot */
++ if (!xhci_alloc_virt_device(xhci, slot_id, NULL, GFP_NOIO)) {
++ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
++ return -ENOMEM;
++ }
++
++ /* ring fake doorbell for slot_id ep 0 */
++ xhci_ring_ep_doorbell(xhci, slot_id, 0, 0);
++ usleep_range(1000, 1500);
++
++ /* read the status register to check if HSE is set or not? */
++ temp = readl(&xhci->op_regs->status);
++
++ /* clear HSE if set */
++ if (temp & STS_FATAL) {
++ xhci_dbg(xhci, "HSE problem detected, status: 0x%x\n", temp);
++ temp &= ~(0x1fff);
++ temp |= STS_FATAL;
++ writel(temp, &xhci->op_regs->status);
++ usleep_range(1000, 1500);
++ readl(&xhci->op_regs->status);
++ }
++
++ /* Free virt device */
++ xhci_free_virt_device(xhci, slot_id);
++
++ return 0;
++}
++
+ /*
+ * Set the run bit and wait for the host to be running.
+ */
+@@ -557,10 +590,25 @@ int xhci_init(struct usb_hcd *hcd)
+
+ static int xhci_run_finished(struct xhci_hcd *xhci)
+ {
+- if (xhci_start(xhci)) {
+- xhci_halt(xhci);
+- return -ENODEV;
++ int err;
++
++ err = xhci_start(xhci);
++ if (err) {
++ err = -ENODEV;
++ goto out_err;
++ }
++ if (xhci->quirks & XHCI_FAKE_DOORBELL) {
++ err = xhci_fake_doorbell(xhci, 1);
++ if (err)
++ goto out_err;
++
++ err = xhci_start(xhci);
++ if (err) {
++ err = -ENODEV;
++ goto out_err;
++ }
+ }
++
+ xhci->shared_hcd->state = HC_STATE_RUNNING;
+ xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
+
+@@ -570,6 +618,9 @@ static int xhci_run_finished(struct xhci
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Finished xhci_run for USB3 roothub");
+ return 0;
++out_err:
++ xhci_halt(xhci);
++ return err;
+ }
+
+ /*
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1568,6 +1568,7 @@ struct xhci_hcd {
+ /* For controllers with a broken beyond repair streams implementation */
+ #define XHCI_BROKEN_STREAMS (1 << 19)
+ #define XHCI_PME_STUCK_QUIRK (1 << 20)
++#define XHCI_FAKE_DOORBELL (1 << 21)
+ unsigned int num_active_eps;
+ unsigned int limit_active_eps;
+ /* There are two roothubs to keep track of bus suspend info for */
+--- a/include/linux/usb/xhci_pdriver.h
++++ b/include/linux/usb/xhci_pdriver.h
+@@ -22,6 +22,7 @@
+ */
+ struct usb_xhci_pdata {
+ unsigned usb3_lpm_capable:1;
++ unsigned usb3_fake_doorbell:1;
+ };
+
+ #endif /* __USB_CORE_XHCI_PDRIVER_H */
diff --git a/target/linux/bcm53xx/patches-4.1/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch b/target/linux/bcm53xx/patches-4.1/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
new file mode 100644
index 0000000..17a9260
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
@@ -0,0 +1,75 @@
+From c7c7bf7fcbacadac7781783de25fe1e13e2a2c35 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 v3 3/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ 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
+@@ -244,7 +244,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];
+@@ -259,8 +262,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);
+
+@@ -271,12 +273,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);
+@@ -333,11 +331,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/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch b/target/linux/bcm53xx/patches-4.1/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
new file mode 100644
index 0000000..262192b
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
@@ -0,0 +1,112 @@
+From fa5622c2fadae573dd6b0f5bffe436b230b411f6 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 v3 4/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ 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
+@@ -35,6 +35,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;
+ struct gpio_desc *gpio_desc;
+@@ -288,31 +289,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;
+-
+- if (dev->dev.of_node)
+- usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
+- &dev->dev.of_node->fwnode);
+- if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
+- gpiod_direction_output(usb_dev->gpio_desc, 1);
+-
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
+ bcma_hcd_init_chip_arm(dev);
+@@ -345,7 +331,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:
+@@ -353,6 +338,40 @@ 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;
++
++ if (dev->dev.of_node)
++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
++ &dev->dev.of_node->fwnode);
++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
++ gpiod_direction_output(usb_dev->gpio_desc, 1);
++
++ 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/197-USB-bcma-add-USB-3.0-support.patch b/target/linux/bcm53xx/patches-4.1/197-USB-bcma-add-USB-3.0-support.patch
new file mode 100644
index 0000000..34ab858
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/197-USB-bcma-add-USB-3.0-support.patch
@@ -0,0 +1,295 @@
+From 121ec6539abedbc0e975cf35f48ee044b323e4c3 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 v3 5/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 225 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 225 insertions(+)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -29,6 +29,7 @@
+ #include <linux/of_gpio.h>
+ #include <linux/usb/ehci_pdriver.h>
+ #include <linux/usb/ohci_pdriver.h>
++#include <linux/usb/xhci_pdriver.h>
+
+ MODULE_AUTHOR("Hauke Mehrtens");
+ MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
+@@ -38,6 +39,7 @@ struct bcma_hcd_device {
+ struct bcma_device *core;
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
++ struct platform_device *xhci_dev;
+ struct gpio_desc *gpio_desc;
+ };
+
+@@ -245,6 +247,10 @@ static const struct usb_ehci_pdata ehci_
+ static const struct usb_ohci_pdata ohci_pdata = {
+ };
+
++static const struct usb_xhci_pdata xhci_pdata = {
++ .usb3_fake_doorbell = 1
++};
++
+ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
+ const char *name, u32 addr,
+ const void *data,
+@@ -338,6 +344,216 @@ 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,
++ &xhci_pdata,
++ sizeof(xhci_pdata));
++ 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;
+@@ -364,6 +580,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;
+ }
+@@ -377,11 +598,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);
+ }
+@@ -418,6 +642,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/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 0000000..06254b3
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch
@@ -0,0 +1,86 @@
+From: Florian Fainelli <f.fainelli@gmail.com>
+Subject: [PATCH] ARM: BCM5301x: Disable MMU and Dcache during decompression
+Date: Tue, 14 Jul 2015 16:12:08 -0700
+
+Use the existing __armv7_mmu_cache_flush() to perform the cache flush
+since this does what we are after.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/compressed/Makefile | 4 +++
+ arch/arm/boot/compressed/head-bcm_5301x-mpcore.S | 37 ++++++++++++++++++++++++
+ arch/arm/boot/compressed/head.S | 2 ++
+ 3 files changed, 43 insertions(+)
+ create mode 100644 arch/arm/boot/compressed/head-bcm_5301x-mpcore.S
+
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -31,6 +31,10 @@ 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
++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 __armv7_mmu_cache_flush_fn
++ nop
++ mov r0,#0
++ ldr r3, =0x19022000 @ L2 cache controller, control reg
++ str r0, [r3, #0x100] @ Disable L2 cache
++ nop
++
++ @ Restore
++ mov r8, r12
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -1152,6 +1152,7 @@ __armv7_mmu_cache_flush:
+ hierarchical:
+ mcr p15, 0, r10, c7, c10, 5 @ DMB
+ stmfd sp!, {r0-r7, r9-r11}
++ENTRY(__armv7_mmu_cache_flush_fn)
+ 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
+@@ -1201,6 +1202,7 @@ iflush:
+ mcr p15, 0, r10, c7, c10, 4 @ DSB
+ mcr p15, 0, r10, c7, c5, 4 @ ISB
+ mov pc, lr
++ENDPROC(__armv7_mmu_cache_flush_fn)
+
+ __armv5tej_mmu_cache_flush:
+ tst r4, #1
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 0000000..9ca76b3
--- /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
+@@ -105,6 +105,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/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch b/target/linux/bcm53xx/patches-4.1/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch
new file mode 100644
index 0000000..a1cbbe9
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch
@@ -0,0 +1,69 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Subject: [PATCH] ARM: BCM5301X: Add DT for Linksys EA6300 V1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -59,6 +59,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
+ bcm4708-buffalo-wzr-1750dhp.dtb \
++ bcm4708-linksys-ea6300-v1.dtb \
+ bcm4708-luxul-xwc-1000.dtb \
+ bcm4708-netgear-r6250.dtb \
+ bcm4708-netgear-r6300-v2.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
+@@ -0,0 +1,48 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Linksys EA6300 V1
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
++
++/ {
++ compatible = "linksys,ea6300v1", "brcm,bcm4708";
++ model = "Linksys EA6300 V1";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ 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>;
++ };
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
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 0000000..802188d
--- /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
+@@ -24,6 +24,23 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ 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 0000000..ed4d1bc
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch
@@ -0,0 +1,86 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+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>
+---
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -24,6 +24,26 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ 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
+@@ -24,6 +24,17 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ axi@18000000 {
++ usb3@23000 {
++ reg = <0x00023000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -24,6 +24,26 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ axi@18000000 {
++ usb2@21000 {
++ reg = <0x00021000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
++ };
++
++ 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/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch b/target/linux/bcm53xx/patches-4.1/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
new file mode 100644
index 0000000..4e25647
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
@@ -0,0 +1,170 @@
+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
+@@ -17,7 +17,7 @@
+ model = "Asus RT-AC87U";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -17,7 +17,7 @@
+ model = "Netgear R7000";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
+@@ -17,7 +17,7 @@
+ model = "Linksys EA6300 V1";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
diff --git a/target/linux/bcm53xx/patches-4.1/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch b/target/linux/bcm53xx/patches-4.1/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
new file mode 100644
index 0000000..b53c57f
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
@@ -0,0 +1,173 @@
+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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ clocks {
+--- 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
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ 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 0000000..f9ca7eb
--- /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/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch b/target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
new file mode 100644
index 0000000..dad4f8a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.1/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
@@ -0,0 +1,111 @@
+From b49d7bb4825654f81bcee8e219028712811515a5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 29 Jun 2015 08:11:36 +0200
+Subject: [PATCH] ARM: BCM5301X: Enable ChipCommon UART on untested 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-asus-rt-ac56u.dts | 4 ++++
+ arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts | 4 ++++
+ arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 4 ++++
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 4 ++++
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts | 4 ++++
+ arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 5 +++++
+ arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 5 +++++
+ arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 5 +++++
+ 8 files changed, 35 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -96,3 +96,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -83,3 +83,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+@@ -83,3 +83,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -77,3 +77,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -37,3 +37,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -65,3 +65,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -144,3 +144,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -127,3 +127,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -104,4 +104,5 @@
+
+ &uart0 {
+ status = "okay";
++ clock-frequency = <125000000>;
+ };
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 0000000..ccdb28b
--- /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 0000000..41ef3b3
--- /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/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 0000000..a3d0f75
--- /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 0000000..6be75bb
--- /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 0000000..dfc422e
--- /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,42 @@
+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,18 @@ 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;
++
++ /*
++ * Workaround for devices using port 8 (connected to the 3rd iface).
++ * For some reason it doesn't work (no packets on eth2).
++ */
++ if (of_machine_is_compatible("netgear,r8000"))
++ sw_dev->cpu_port = 5;
++
+ /* 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 0000000..9f2cd39
--- /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/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 0000000..c1dfa92
--- /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) {
diff --git a/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch b/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch
new file mode 100644
index 0000000..20dd90e
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/043-clk-iproc-Fix-PLL-output-frequency-calculation.patch
@@ -0,0 +1,59 @@
+From 63243a4da7d0dfa19dcacd0a529782eeb2f86f92 Mon Sep 17 00:00:00 2001
+From: Simran Rai <ssimran@broadcom.com>
+Date: Mon, 19 Oct 2015 15:27:19 -0700
+Subject: [PATCH] clk: iproc: Fix PLL output frequency calculation
+
+This patch affects the clocks that use fractional ndivider in their
+PLL output frequency calculation. Instead of 2^20 divide factor, the
+clock's ndiv integer shift was used. Fixed the bug by replacing ndiv
+integer shift with 2^20 factor.
+
+Signed-off-by: Simran Rai <ssimran@broadcom.com>
+Signed-off-by: Ray Jui <rjui@broadcom.com>
+Reviewed-by: Scott Branden <sbranden@broadcom.com>
+Fixes: 5fe225c105fd ("clk: iproc: add initial common clock support")
+Cc: <stable@vger.kernel.org> # v4.1+
+Signed-off-by: Michael Turquette <mturquette@baylibre.com>
+---
+ drivers/clk/bcm/clk-iproc-pll.c | 13 +++++--------
+ 1 file changed, 5 insertions(+), 8 deletions(-)
+
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -345,8 +345,8 @@ static unsigned long iproc_pll_recalc_ra
+ struct iproc_pll *pll = clk->pll;
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+ u32 val;
+- u64 ndiv;
+- unsigned int ndiv_int, ndiv_frac, pdiv;
++ u64 ndiv, ndiv_int, ndiv_frac;
++ unsigned int pdiv;
+
+ if (parent_rate == 0)
+ return 0;
+@@ -366,22 +366,19 @@ static unsigned long iproc_pll_recalc_ra
+ val = readl(pll->pll_base + ctrl->ndiv_int.offset);
+ ndiv_int = (val >> ctrl->ndiv_int.shift) &
+ bit_mask(ctrl->ndiv_int.width);
+- ndiv = (u64)ndiv_int << ctrl->ndiv_int.shift;
++ ndiv = ndiv_int << 20;
+
+ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+ val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
+ ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
+ bit_mask(ctrl->ndiv_frac.width);
+-
+- if (ndiv_frac != 0)
+- ndiv = ((u64)ndiv_int << ctrl->ndiv_int.shift) |
+- ndiv_frac;
++ ndiv += ndiv_frac;
+ }
+
+ val = readl(pll->pll_base + ctrl->pdiv.offset);
+ pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
+
+- clk->rate = (ndiv * parent_rate) >> ctrl->ndiv_int.shift;
++ clk->rate = (ndiv * parent_rate) >> 20;
+
+ if (pdiv == 0)
+ clk->rate *= 2;
diff --git a/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch b/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch
new file mode 100644
index 0000000..f65aa9c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/044-clk-cygnus-Convert-all-macros-to-all-caps.patch
@@ -0,0 +1,292 @@
+From b5116083e227fa478e20d5ed945430088aa1a00b Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:25 -0400
+Subject: [PATCH 44/50] clk: cygnus: Convert all macros to all caps
+
+The macros that are being used to initialize the values of the clk
+structures should be all caps. Find and replace all of them with their
+relevant counterparts.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/clk-cygnus.c | 146 +++++++++++++++++++++----------------------
+ 1 file changed, 73 insertions(+), 73 deletions(-)
+
+--- a/drivers/clk/bcm/clk-cygnus.c
++++ b/drivers/clk/bcm/clk-cygnus.c
+@@ -23,28 +23,28 @@
+ #include <dt-bindings/clock/bcm-cygnus.h>
+ #include "clk-iproc.h"
+
+-#define reg_val(o, s, w) { .offset = o, .shift = s, .width = w, }
++#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, }
+
+-#define aon_val(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
++#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
+ .pwr_shift = ps, .iso_shift = is }
+
+-#define sw_ctrl_val(o, s) { .offset = o, .shift = s, }
++#define SW_CTRL_VAL(o, s) { .offset = o, .shift = s, }
+
+-#define asiu_div_val(o, es, hs, hw, ls, lw) \
++#define ASIU_DIV_VAL(o, es, hs, hw, ls, lw) \
+ { .offset = o, .en_shift = es, .high_shift = hs, \
+ .high_width = hw, .low_shift = ls, .low_width = lw }
+
+-#define reset_val(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
++#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
+ .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
+ .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
+ .ka_width = kaw }
+
+-#define vco_ctrl_val(uo, lo) { .u_offset = uo, .l_offset = lo }
++#define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo }
+
+-#define enable_val(o, es, hs, bs) { .offset = o, .enable_shift = es, \
++#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
+ .hold_shift = hs, .bypass_shift = bs }
+
+-#define asiu_gate_val(o, es) { .offset = o, .en_shift = es }
++#define ASIU_GATE_VAL(o, es) { .offset = o, .en_shift = es }
+
+ static void __init cygnus_armpll_init(struct device_node *node)
+ {
+@@ -55,52 +55,52 @@ CLK_OF_DECLARE(cygnus_armpll, "brcm,cygn
+ static const struct iproc_pll_ctrl genpll = {
+ .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+ IPROC_CLK_PLL_NEEDS_SW_CFG,
+- .aon = aon_val(0x0, 2, 1, 0),
+- .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
+- .sw_ctrl = sw_ctrl_val(0x10, 31),
+- .ndiv_int = reg_val(0x10, 20, 10),
+- .ndiv_frac = reg_val(0x10, 0, 20),
+- .pdiv = reg_val(0x14, 0, 4),
+- .vco_ctrl = vco_ctrl_val(0x18, 0x1c),
+- .status = reg_val(0x28, 12, 1),
++ .aon = AON_VAL(0x0, 2, 1, 0),
++ .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
++ .sw_ctrl = SW_CTRL_VAL(0x10, 31),
++ .ndiv_int = REG_VAL(0x10, 20, 10),
++ .ndiv_frac = REG_VAL(0x10, 0, 20),
++ .pdiv = REG_VAL(0x14, 0, 4),
++ .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
++ .status = REG_VAL(0x28, 12, 1),
+ };
+
+ static const struct iproc_clk_ctrl genpll_clk[] = {
+ [BCM_CYGNUS_GENPLL_AXI21_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_AXI21_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 6, 0, 12),
+- .mdiv = reg_val(0x20, 0, 8),
++ .enable = ENABLE_VAL(0x4, 6, 0, 12),
++ .mdiv = REG_VAL(0x20, 0, 8),
+ },
+ [BCM_CYGNUS_GENPLL_250MHZ_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_250MHZ_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 7, 1, 13),
+- .mdiv = reg_val(0x20, 10, 8),
++ .enable = ENABLE_VAL(0x4, 7, 1, 13),
++ .mdiv = REG_VAL(0x20, 10, 8),
+ },
+ [BCM_CYGNUS_GENPLL_IHOST_SYS_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_IHOST_SYS_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 8, 2, 14),
+- .mdiv = reg_val(0x20, 20, 8),
++ .enable = ENABLE_VAL(0x4, 8, 2, 14),
++ .mdiv = REG_VAL(0x20, 20, 8),
+ },
+ [BCM_CYGNUS_GENPLL_ENET_SW_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_ENET_SW_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 9, 3, 15),
+- .mdiv = reg_val(0x24, 0, 8),
++ .enable = ENABLE_VAL(0x4, 9, 3, 15),
++ .mdiv = REG_VAL(0x24, 0, 8),
+ },
+ [BCM_CYGNUS_GENPLL_AUDIO_125_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_AUDIO_125_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 10, 4, 16),
+- .mdiv = reg_val(0x24, 10, 8),
++ .enable = ENABLE_VAL(0x4, 10, 4, 16),
++ .mdiv = REG_VAL(0x24, 10, 8),
+ },
+ [BCM_CYGNUS_GENPLL_CAN_CLK] = {
+ .channel = BCM_CYGNUS_GENPLL_CAN_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x4, 11, 5, 17),
+- .mdiv = reg_val(0x24, 20, 8),
++ .enable = ENABLE_VAL(0x4, 11, 5, 17),
++ .mdiv = REG_VAL(0x24, 20, 8),
+ },
+ };
+
+@@ -113,51 +113,51 @@ CLK_OF_DECLARE(cygnus_genpll, "brcm,cygn
+
+ static const struct iproc_pll_ctrl lcpll0 = {
+ .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+- .aon = aon_val(0x0, 2, 5, 4),
+- .reset = reset_val(0x0, 31, 30, 27, 3, 23, 4, 19, 4),
+- .sw_ctrl = sw_ctrl_val(0x4, 31),
+- .ndiv_int = reg_val(0x4, 16, 10),
+- .pdiv = reg_val(0x4, 26, 4),
+- .vco_ctrl = vco_ctrl_val(0x10, 0x14),
+- .status = reg_val(0x18, 12, 1),
++ .aon = AON_VAL(0x0, 2, 5, 4),
++ .reset = RESET_VAL(0x0, 31, 30, 27, 3, 23, 4, 19, 4),
++ .sw_ctrl = SW_CTRL_VAL(0x4, 31),
++ .ndiv_int = REG_VAL(0x4, 16, 10),
++ .pdiv = REG_VAL(0x4, 26, 4),
++ .vco_ctrl = VCO_CTRL_VAL(0x10, 0x14),
++ .status = REG_VAL(0x18, 12, 1),
+ };
+
+ static const struct iproc_clk_ctrl lcpll0_clk[] = {
+ [BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK] = {
+ .channel = BCM_CYGNUS_LCPLL0_PCIE_PHY_REF_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 7, 1, 13),
+- .mdiv = reg_val(0x8, 0, 8),
++ .enable = ENABLE_VAL(0x0, 7, 1, 13),
++ .mdiv = REG_VAL(0x8, 0, 8),
+ },
+ [BCM_CYGNUS_LCPLL0_DDR_PHY_CLK] = {
+ .channel = BCM_CYGNUS_LCPLL0_DDR_PHY_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 8, 2, 14),
+- .mdiv = reg_val(0x8, 10, 8),
++ .enable = ENABLE_VAL(0x0, 8, 2, 14),
++ .mdiv = REG_VAL(0x8, 10, 8),
+ },
+ [BCM_CYGNUS_LCPLL0_SDIO_CLK] = {
+ .channel = BCM_CYGNUS_LCPLL0_SDIO_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 9, 3, 15),
+- .mdiv = reg_val(0x8, 20, 8),
++ .enable = ENABLE_VAL(0x0, 9, 3, 15),
++ .mdiv = REG_VAL(0x8, 20, 8),
+ },
+ [BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK] = {
+ .channel = BCM_CYGNUS_LCPLL0_USB_PHY_REF_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 10, 4, 16),
+- .mdiv = reg_val(0xc, 0, 8),
++ .enable = ENABLE_VAL(0x0, 10, 4, 16),
++ .mdiv = REG_VAL(0xc, 0, 8),
+ },
+ [BCM_CYGNUS_LCPLL0_SMART_CARD_CLK] = {
+ .channel = BCM_CYGNUS_LCPLL0_SMART_CARD_CLK,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 11, 5, 17),
+- .mdiv = reg_val(0xc, 10, 8),
++ .enable = ENABLE_VAL(0x0, 11, 5, 17),
++ .mdiv = REG_VAL(0xc, 10, 8),
+ },
+ [BCM_CYGNUS_LCPLL0_CH5_UNUSED] = {
+ .channel = BCM_CYGNUS_LCPLL0_CH5_UNUSED,
+ .flags = IPROC_CLK_AON,
+- .enable = enable_val(0x0, 12, 6, 18),
+- .mdiv = reg_val(0xc, 20, 8),
++ .enable = ENABLE_VAL(0x0, 12, 6, 18),
++ .mdiv = REG_VAL(0xc, 20, 8),
+ },
+ };
+
+@@ -189,52 +189,52 @@ static const struct iproc_pll_vco_param
+ static const struct iproc_pll_ctrl mipipll = {
+ .flags = IPROC_CLK_PLL_ASIU | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+ IPROC_CLK_NEEDS_READ_BACK,
+- .aon = aon_val(0x0, 4, 17, 16),
+- .asiu = asiu_gate_val(0x0, 3),
+- .reset = reset_val(0x0, 11, 10, 4, 3, 0, 4, 7, 4),
+- .ndiv_int = reg_val(0x10, 20, 10),
+- .ndiv_frac = reg_val(0x10, 0, 20),
+- .pdiv = reg_val(0x14, 0, 4),
+- .vco_ctrl = vco_ctrl_val(0x18, 0x1c),
+- .status = reg_val(0x28, 12, 1),
++ .aon = AON_VAL(0x0, 4, 17, 16),
++ .asiu = ASIU_GATE_VAL(0x0, 3),
++ .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 4),
++ .ndiv_int = REG_VAL(0x10, 20, 10),
++ .ndiv_frac = REG_VAL(0x10, 0, 20),
++ .pdiv = REG_VAL(0x14, 0, 4),
++ .vco_ctrl = VCO_CTRL_VAL(0x18, 0x1c),
++ .status = REG_VAL(0x28, 12, 1),
+ };
+
+ static const struct iproc_clk_ctrl mipipll_clk[] = {
+ [BCM_CYGNUS_MIPIPLL_CH0_UNUSED] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH0_UNUSED,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 12, 6, 18),
+- .mdiv = reg_val(0x20, 0, 8),
++ .enable = ENABLE_VAL(0x4, 12, 6, 18),
++ .mdiv = REG_VAL(0x20, 0, 8),
+ },
+ [BCM_CYGNUS_MIPIPLL_CH1_LCD] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH1_LCD,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 13, 7, 19),
+- .mdiv = reg_val(0x20, 10, 8),
++ .enable = ENABLE_VAL(0x4, 13, 7, 19),
++ .mdiv = REG_VAL(0x20, 10, 8),
+ },
+ [BCM_CYGNUS_MIPIPLL_CH2_V3D] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH2_V3D,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 14, 8, 20),
+- .mdiv = reg_val(0x20, 20, 8),
++ .enable = ENABLE_VAL(0x4, 14, 8, 20),
++ .mdiv = REG_VAL(0x20, 20, 8),
+ },
+ [BCM_CYGNUS_MIPIPLL_CH3_UNUSED] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH3_UNUSED,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 15, 9, 21),
+- .mdiv = reg_val(0x24, 0, 8),
++ .enable = ENABLE_VAL(0x4, 15, 9, 21),
++ .mdiv = REG_VAL(0x24, 0, 8),
+ },
+ [BCM_CYGNUS_MIPIPLL_CH4_UNUSED] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH4_UNUSED,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 16, 10, 22),
+- .mdiv = reg_val(0x24, 10, 8),
++ .enable = ENABLE_VAL(0x4, 16, 10, 22),
++ .mdiv = REG_VAL(0x24, 10, 8),
+ },
+ [BCM_CYGNUS_MIPIPLL_CH5_UNUSED] = {
+ .channel = BCM_CYGNUS_MIPIPLL_CH5_UNUSED,
+ .flags = IPROC_CLK_NEEDS_READ_BACK,
+- .enable = enable_val(0x4, 17, 11, 23),
+- .mdiv = reg_val(0x24, 20, 8),
++ .enable = ENABLE_VAL(0x4, 17, 11, 23),
++ .mdiv = REG_VAL(0x24, 20, 8),
+ },
+ };
+
+@@ -247,15 +247,15 @@ static void __init cygnus_mipipll_clk_in
+ CLK_OF_DECLARE(cygnus_mipipll, "brcm,cygnus-mipipll", cygnus_mipipll_clk_init);
+
+ static const struct iproc_asiu_div asiu_div[] = {
+- [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_div_val(0x0, 31, 16, 10, 0, 10),
+- [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_div_val(0x4, 31, 16, 10, 0, 10),
+- [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_div_val(0x8, 31, 16, 10, 0, 10),
++ [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_DIV_VAL(0x0, 31, 16, 10, 0, 10),
++ [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_DIV_VAL(0x4, 31, 16, 10, 0, 10),
++ [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_DIV_VAL(0x8, 31, 16, 10, 0, 10),
+ };
+
+ static const struct iproc_asiu_gate asiu_gate[] = {
+- [BCM_CYGNUS_ASIU_KEYPAD_CLK] = asiu_gate_val(0x0, 7),
+- [BCM_CYGNUS_ASIU_ADC_CLK] = asiu_gate_val(0x0, 9),
+- [BCM_CYGNUS_ASIU_PWM_CLK] = asiu_gate_val(IPROC_CLK_INVALID_OFFSET, 0),
++ [BCM_CYGNUS_ASIU_KEYPAD_CLK] = ASIU_GATE_VAL(0x0, 7),
++ [BCM_CYGNUS_ASIU_ADC_CLK] = ASIU_GATE_VAL(0x0, 9),
++ [BCM_CYGNUS_ASIU_PWM_CLK] = ASIU_GATE_VAL(IPROC_CLK_INVALID_OFFSET, 0),
+ };
+
+ static void __init cygnus_asiu_init(struct device_node *node)
diff --git a/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch b/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch
new file mode 100644
index 0000000..318bd5c
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/045-clk-iproc-Add-PWRCTRL-support.patch
@@ -0,0 +1,120 @@
+From 7c70cb333deb6e2f88da9c94ddd6b3b00c97b93a Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:26 -0400
+Subject: [PATCH 45/50] clk: iproc: Add PWRCTRL support
+
+Some iProc SoC clocks use a different way to control clock power, via
+the PWRDWN bit in the PLL control register. Since the PLL control
+register is used to access the PWRDWN bit, there is no need for the
+pwr_base when this is being used. A new flag, IPROC_CLK_EMBED_PWRCTRL,
+has been added to identify this usage. We can use the AON interface to
+write the values to enable/disable PWRDOWN.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/clk-iproc-pll.c | 55 ++++++++++++++++++++++++++++-------------
+ drivers/clk/bcm/clk-iproc.h | 6 +++++
+ 2 files changed, 44 insertions(+), 17 deletions(-)
+
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -148,14 +148,25 @@ static void __pll_disable(struct iproc_p
+ writel(val, pll->asiu_base + ctrl->asiu.offset);
+ }
+
+- /* latch input value so core power can be shut down */
+- val = readl(pll->pwr_base + ctrl->aon.offset);
+- val |= (1 << ctrl->aon.iso_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
+-
+- /* power down the core */
+- val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
++ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
++ val = readl(pll->pll_base + ctrl->aon.offset);
++ val |= (bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
++ writel(val, pll->pll_base + ctrl->aon.offset);
++
++ if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
++ readl(pll->pll_base + ctrl->aon.offset);
++ }
++
++ if (pll->pwr_base) {
++ /* latch input value so core power can be shut down */
++ val = readl(pll->pwr_base + ctrl->aon.offset);
++ val |= (1 << ctrl->aon.iso_shift);
++ writel(val, pll->pwr_base + ctrl->aon.offset);
++
++ /* power down the core */
++ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
++ writel(val, pll->pwr_base + ctrl->aon.offset);
++ }
+ }
+
+ static int __pll_enable(struct iproc_pll *pll)
+@@ -163,11 +174,22 @@ static int __pll_enable(struct iproc_pll
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+ u32 val;
+
+- /* power up the PLL and make sure it's not latched */
+- val = readl(pll->pwr_base + ctrl->aon.offset);
+- val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
+- val &= ~(1 << ctrl->aon.iso_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
++ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
++ val = readl(pll->pll_base + ctrl->aon.offset);
++ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
++ writel(val, pll->pll_base + ctrl->aon.offset);
++
++ if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
++ readl(pll->pll_base + ctrl->aon.offset);
++ }
++
++ if (pll->pwr_base) {
++ /* power up the PLL and make sure it's not latched */
++ val = readl(pll->pwr_base + ctrl->aon.offset);
++ val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
++ val &= ~(1 << ctrl->aon.iso_shift);
++ writel(val, pll->pwr_base + ctrl->aon.offset);
++ }
+
+ /* certain PLLs also need to be ungated from the ASIU top level */
+ if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
+@@ -607,9 +629,8 @@ void __init iproc_pll_clk_setup(struct d
+ if (WARN_ON(!pll->pll_base))
+ goto err_pll_iomap;
+
++ /* Some SoCs do not require the pwr_base, thus failing is not fatal */
+ pll->pwr_base = of_iomap(node, 1);
+- if (WARN_ON(!pll->pwr_base))
+- goto err_pwr_iomap;
+
+ /* some PLLs require gating control at the top ASIU level */
+ if (pll_ctrl->flags & IPROC_CLK_PLL_ASIU) {
+@@ -692,9 +713,9 @@ err_pll_register:
+ iounmap(pll->asiu_base);
+
+ err_asiu_iomap:
+- iounmap(pll->pwr_base);
++ if (pll->pwr_base)
++ iounmap(pll->pwr_base);
+
+-err_pwr_iomap:
+ iounmap(pll->pll_base);
+
+ err_pll_iomap:
+--- a/drivers/clk/bcm/clk-iproc.h
++++ b/drivers/clk/bcm/clk-iproc.h
+@@ -49,6 +49,12 @@
+ #define IPROC_CLK_PLL_NEEDS_SW_CFG BIT(4)
+
+ /*
++ * Some PLLs use a different way to control clock power, via the PWRDWN bit in
++ * the PLL control register
++ */
++#define IPROC_CLK_EMBED_PWRCTRL BIT(5)
++
++/*
+ * Parameters for VCO frequency configuration
+ *
+ * VCO frequency =
diff --git a/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch b/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch
new file mode 100644
index 0000000..c8eda8d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/046-clk-nsp-add-clock-support-for-Broadcom-Northstar-Plu.patch
@@ -0,0 +1,219 @@
+From d358480591b34d081806ecb5a9474930a4d59f8a Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:27 -0400
+Subject: [PATCH 46/50] clk: nsp: add clock support for Broadcom Northstar Plus
+ SoC
+
+The Broadcom Northstar Plus SoC is architected under the iProc
+architecture. It has the following PLLs: ARMPLL, GENPLL, LCPLL0, all
+derived from an onboard crystal.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/Makefile | 2 +
+ drivers/clk/bcm/clk-nsp.c | 135 ++++++++++++++++++++++++++++++++++++
+ include/dt-bindings/clock/bcm-nsp.h | 51 ++++++++++++++
+ 3 files changed, 188 insertions(+)
+ create mode 100644 drivers/clk/bcm/clk-nsp.c
+ create mode 100644 include/dt-bindings/clock/bcm-nsp.h
+
+--- a/drivers/clk/bcm/Makefile
++++ b/drivers/clk/bcm/Makefile
+@@ -4,3 +4,5 @@ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm281
+ obj-$(CONFIG_CLK_BCM_KONA) += clk-bcm21664.o
+ obj-$(CONFIG_COMMON_CLK_IPROC) += clk-iproc-armpll.o clk-iproc-pll.o clk-iproc-asiu.o
+ obj-$(CONFIG_ARCH_BCM_CYGNUS) += clk-cygnus.o
++obj-$(CONFIG_ARCH_BCM_NSP) += clk-nsp.o
++obj-$(CONFIG_ARCH_BCM_5301X) += clk-nsp.o
+--- /dev/null
++++ b/drivers/clk/bcm/clk-nsp.c
+@@ -0,0 +1,135 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/err.h>
++#include <linux/clk-provider.h>
++#include <linux/io.h>
++#include <linux/of.h>
++#include <linux/of_address.h>
++
++#include <dt-bindings/clock/bcm-nsp.h>
++#include "clk-iproc.h"
++
++#define REG_VAL(o, s, w) { .offset = o, .shift = s, .width = w, }
++
++#define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
++ .pwr_shift = ps, .iso_shift = is }
++
++#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
++ .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
++ .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
++ .ka_width = kaw }
++
++#define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
++ .hold_shift = hs, .bypass_shift = bs }
++
++static void __init nsp_armpll_init(struct device_node *node)
++{
++ iproc_armpll_setup(node);
++}
++CLK_OF_DECLARE(nsp_armpll, "brcm,nsp-armpll", nsp_armpll_init);
++
++static const struct iproc_pll_ctrl genpll = {
++ .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL,
++ .aon = AON_VAL(0x0, 1, 12, 0),
++ .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
++ .ndiv_int = REG_VAL(0x14, 20, 10),
++ .ndiv_frac = REG_VAL(0x14, 0, 20),
++ .pdiv = REG_VAL(0x18, 24, 3),
++ .status = REG_VAL(0x20, 12, 1),
++};
++
++static const struct iproc_clk_ctrl genpll_clk[] = {
++ [BCM_NSP_GENPLL_PHY_CLK] = {
++ .channel = BCM_NSP_GENPLL_PHY_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 12, 6, 18),
++ .mdiv = REG_VAL(0x18, 16, 8),
++ },
++ [BCM_NSP_GENPLL_ENET_SW_CLK] = {
++ .channel = BCM_NSP_GENPLL_ENET_SW_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 13, 7, 19),
++ .mdiv = REG_VAL(0x18, 8, 8),
++ },
++ [BCM_NSP_GENPLL_USB_PHY_REF_CLK] = {
++ .channel = BCM_NSP_GENPLL_USB_PHY_REF_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 14, 8, 20),
++ .mdiv = REG_VAL(0x18, 0, 8),
++ },
++ [BCM_NSP_GENPLL_IPROCFAST_CLK] = {
++ .channel = BCM_NSP_GENPLL_IPROCFAST_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 15, 9, 21),
++ .mdiv = REG_VAL(0x1c, 16, 8),
++ },
++ [BCM_NSP_GENPLL_SATA1_CLK] = {
++ .channel = BCM_NSP_GENPLL_SATA1_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 16, 10, 22),
++ .mdiv = REG_VAL(0x1c, 8, 8),
++ },
++ [BCM_NSP_GENPLL_SATA2_CLK] = {
++ .channel = BCM_NSP_GENPLL_SATA2_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x4, 17, 11, 23),
++ .mdiv = REG_VAL(0x1c, 0, 8),
++ },
++};
++
++static void __init nsp_genpll_clk_init(struct device_node *node)
++{
++ iproc_pll_clk_setup(node, &genpll, NULL, 0, genpll_clk,
++ ARRAY_SIZE(genpll_clk));
++}
++CLK_OF_DECLARE(nsp_genpll_clk, "brcm,nsp-genpll", nsp_genpll_clk_init);
++
++static const struct iproc_pll_ctrl lcpll0 = {
++ .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL,
++ .aon = AON_VAL(0x0, 1, 24, 0),
++ .reset = RESET_VAL(0x0, 23, 22, 16, 3, 12, 4, 19, 4),
++ .ndiv_int = REG_VAL(0x4, 20, 8),
++ .ndiv_frac = REG_VAL(0x4, 0, 20),
++ .pdiv = REG_VAL(0x4, 28, 3),
++ .status = REG_VAL(0x10, 12, 1),
++};
++
++static const struct iproc_clk_ctrl lcpll0_clk[] = {
++ [BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK] = {
++ .channel = BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x0, 6, 3, 9),
++ .mdiv = REG_VAL(0x8, 24, 8),
++ },
++ [BCM_NSP_LCPLL0_SDIO_CLK] = {
++ .channel = BCM_NSP_LCPLL0_SDIO_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x0, 7, 4, 10),
++ .mdiv = REG_VAL(0x8, 16, 8),
++ },
++ [BCM_NSP_LCPLL0_DDR_PHY_CLK] = {
++ .channel = BCM_NSP_LCPLL0_DDR_PHY_CLK,
++ .flags = IPROC_CLK_AON,
++ .enable = ENABLE_VAL(0x0, 8, 5, 11),
++ .mdiv = REG_VAL(0x8, 8, 8),
++ },
++};
++
++static void __init nsp_lcpll0_clk_init(struct device_node *node)
++{
++ iproc_pll_clk_setup(node, &lcpll0, NULL, 0, lcpll0_clk,
++ ARRAY_SIZE(lcpll0_clk));
++}
++CLK_OF_DECLARE(nsp_lcpll0_clk, "brcm,nsp-lcpll0", nsp_lcpll0_clk_init);
+--- /dev/null
++++ b/include/dt-bindings/clock/bcm-nsp.h
+@@ -0,0 +1,51 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++#ifndef _CLOCK_BCM_NSP_H
++#define _CLOCK_BCM_NSP_H
++
++/* GENPLL clock channel ID */
++#define BCM_NSP_GENPLL 0
++#define BCM_NSP_GENPLL_PHY_CLK 1
++#define BCM_NSP_GENPLL_ENET_SW_CLK 2
++#define BCM_NSP_GENPLL_USB_PHY_REF_CLK 3
++#define BCM_NSP_GENPLL_IPROCFAST_CLK 4
++#define BCM_NSP_GENPLL_SATA1_CLK 5
++#define BCM_NSP_GENPLL_SATA2_CLK 6
++
++/* LCPLL0 clock channel ID */
++#define BCM_NSP_LCPLL0 0
++#define BCM_NSP_LCPLL0_PCIE_PHY_REF_CLK 1
++#define BCM_NSP_LCPLL0_SDIO_CLK 2
++#define BCM_NSP_LCPLL0_DDR_PHY_CLK 3
++
++#endif /* _CLOCK_BCM_NSP_H */
diff --git a/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch b/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch
new file mode 100644
index 0000000..2f07cc6
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/047-clk-iproc-Add-PLL-base-write-function.patch
@@ -0,0 +1,223 @@
+From acbb7a3de7e4d83b23c0bbb3eaf77d15a041d865 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:28 -0400
+Subject: [PATCH 47/50] clk: iproc: Add PLL base write function
+
+All writes to the PLL base address must be flushed if the
+IPROC_CLK_NEEDS_READ_BACK flag is set. If we add a function to make the
+necessary write and reads, we can make sure that any future code which
+makes PLL base writes will do the correct thing.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/clk-iproc-pll.c | 80 +++++++++++++++++------------------------
+ 1 file changed, 33 insertions(+), 47 deletions(-)
+
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -137,6 +137,18 @@ static int pll_wait_for_lock(struct ipro
+ return -EIO;
+ }
+
++static void iproc_pll_write(const struct iproc_pll *pll, void __iomem *base,
++ const u32 offset, u32 val)
++{
++ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
++
++ writel(val, base + offset);
++
++ if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK &&
++ base == pll->pll_base))
++ val = readl(base + offset);
++}
++
+ static void __pll_disable(struct iproc_pll *pll)
+ {
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+@@ -145,27 +157,24 @@ static void __pll_disable(struct iproc_p
+ if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
+ val = readl(pll->asiu_base + ctrl->asiu.offset);
+ val &= ~(1 << ctrl->asiu.en_shift);
+- writel(val, pll->asiu_base + ctrl->asiu.offset);
++ iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
+ }
+
+ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
+ val = readl(pll->pll_base + ctrl->aon.offset);
+ val |= (bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- writel(val, pll->pll_base + ctrl->aon.offset);
+-
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->aon.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val);
+ }
+
+ if (pll->pwr_base) {
+ /* latch input value so core power can be shut down */
+ val = readl(pll->pwr_base + ctrl->aon.offset);
+ val |= (1 << ctrl->aon.iso_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
++ iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
+
+ /* power down the core */
+ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
++ iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
+ }
+ }
+
+@@ -177,10 +186,7 @@ static int __pll_enable(struct iproc_pll
+ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
+ val = readl(pll->pll_base + ctrl->aon.offset);
+ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- writel(val, pll->pll_base + ctrl->aon.offset);
+-
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->aon.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val);
+ }
+
+ if (pll->pwr_base) {
+@@ -188,14 +194,14 @@ static int __pll_enable(struct iproc_pll
+ val = readl(pll->pwr_base + ctrl->aon.offset);
+ val |= bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift;
+ val &= ~(1 << ctrl->aon.iso_shift);
+- writel(val, pll->pwr_base + ctrl->aon.offset);
++ iproc_pll_write(pll, pll->pwr_base, ctrl->aon.offset, val);
+ }
+
+ /* certain PLLs also need to be ungated from the ASIU top level */
+ if (ctrl->flags & IPROC_CLK_PLL_ASIU) {
+ val = readl(pll->asiu_base + ctrl->asiu.offset);
+ val |= (1 << ctrl->asiu.en_shift);
+- writel(val, pll->asiu_base + ctrl->asiu.offset);
++ iproc_pll_write(pll, pll->asiu_base, ctrl->asiu.offset, val);
+ }
+
+ return 0;
+@@ -209,9 +215,7 @@ static void __pll_put_in_reset(struct ip
+
+ val = readl(pll->pll_base + reset->offset);
+ val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift);
+- writel(val, pll->pll_base + reset->offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + reset->offset);
++ iproc_pll_write(pll, pll->pll_base, reset->offset, val);
+ }
+
+ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
+@@ -228,9 +232,7 @@ static void __pll_bring_out_reset(struct
+ val |= ki << reset->ki_shift | kp << reset->kp_shift |
+ ka << reset->ka_shift;
+ val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift;
+- writel(val, pll->pll_base + reset->offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + reset->offset);
++ iproc_pll_write(pll, pll->pll_base, reset->offset, val);
+ }
+
+ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index,
+@@ -285,9 +287,8 @@ static int pll_set_rate(struct iproc_clk
+ /* put PLL in reset */
+ __pll_put_in_reset(pll);
+
+- writel(0, pll->pll_base + ctrl->vco_ctrl.u_offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->vco_ctrl.u_offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.u_offset, 0);
++
+ val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
+
+ if (rate >= VCO_LOW && rate < VCO_MID)
+@@ -298,17 +299,13 @@ static int pll_set_rate(struct iproc_clk
+ else
+ val |= (1 << PLL_VCO_HIGH_SHIFT);
+
+- writel(val, pll->pll_base + ctrl->vco_ctrl.l_offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.l_offset, val);
+
+ /* program integer part of NDIV */
+ val = readl(pll->pll_base + ctrl->ndiv_int.offset);
+ val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
+ val |= vco->ndiv_int << ctrl->ndiv_int.shift;
+- writel(val, pll->pll_base + ctrl->ndiv_int.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->ndiv_int.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_int.offset, val);
+
+ /* program fractional part of NDIV */
+ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+@@ -316,18 +313,15 @@ static int pll_set_rate(struct iproc_clk
+ val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
+ ctrl->ndiv_frac.shift);
+ val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
+- writel(val, pll->pll_base + ctrl->ndiv_frac.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->ndiv_frac.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_frac.offset,
++ val);
+ }
+
+ /* program PDIV */
+ val = readl(pll->pll_base + ctrl->pdiv.offset);
+ val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
+ val |= vco->pdiv << ctrl->pdiv.shift;
+- writel(val, pll->pll_base + ctrl->pdiv.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->pdiv.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->pdiv.offset, val);
+
+ __pll_bring_out_reset(pll, kp, ka, ki);
+
+@@ -464,14 +458,12 @@ static int iproc_clk_enable(struct clk_h
+ /* channel enable is active low */
+ val = readl(pll->pll_base + ctrl->enable.offset);
+ val &= ~(1 << ctrl->enable.enable_shift);
+- writel(val, pll->pll_base + ctrl->enable.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
+
+ /* also make sure channel is not held */
+ val = readl(pll->pll_base + ctrl->enable.offset);
+ val &= ~(1 << ctrl->enable.hold_shift);
+- writel(val, pll->pll_base + ctrl->enable.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->enable.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
+
+ return 0;
+ }
+@@ -488,9 +480,7 @@ static void iproc_clk_disable(struct clk
+
+ val = readl(pll->pll_base + ctrl->enable.offset);
+ val |= 1 << ctrl->enable.enable_shift;
+- writel(val, pll->pll_base + ctrl->enable.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->enable.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
+ }
+
+ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
+@@ -559,9 +549,7 @@ static int iproc_clk_set_rate(struct clk
+ val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
+ val |= div << ctrl->mdiv.shift;
+ }
+- writel(val, pll->pll_base + ctrl->mdiv.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->mdiv.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->mdiv.offset, val);
+ clk->rate = parent_rate / div;
+
+ return 0;
+@@ -588,9 +576,7 @@ static void iproc_pll_sw_cfg(struct ipro
+
+ val = readl(pll->pll_base + ctrl->sw_ctrl.offset);
+ val |= BIT(ctrl->sw_ctrl.shift);
+- writel(val, pll->pll_base + ctrl->sw_ctrl.offset);
+- if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK))
+- readl(pll->pll_base + ctrl->sw_ctrl.offset);
++ iproc_pll_write(pll, pll->pll_base, ctrl->sw_ctrl.offset, val);
+ }
+ }
+
diff --git a/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch b/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch
new file mode 100644
index 0000000..528311f
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/048-clk-iproc-Split-off-dig_filter.patch
@@ -0,0 +1,158 @@
+From fb9e4932d17ad32786d03cb672fb62f2b337acf5 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:29 -0400
+Subject: [PATCH 48/50] clk: iproc: Split off dig_filter
+
+The PLL loop filter/gain can be located in a separate register on some
+SoCs. Split these off into a separate variable, so that an offset can
+be added if necessary. Also, make the necessary modifications to the
+Cygnus and NSP drivers for this change.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/clk-cygnus.c | 17 +++++++++++------
+ drivers/clk/bcm/clk-iproc-pll.c | 14 +++++++++-----
+ drivers/clk/bcm/clk-iproc.h | 10 +++++++++-
+ drivers/clk/bcm/clk-nsp.c | 14 +++++++++-----
+ 4 files changed, 38 insertions(+), 17 deletions(-)
+
+--- a/drivers/clk/bcm/clk-cygnus.c
++++ b/drivers/clk/bcm/clk-cygnus.c
+@@ -34,9 +34,11 @@
+ { .offset = o, .en_shift = es, .high_shift = hs, \
+ .high_width = hw, .low_shift = ls, .low_width = lw }
+
+-#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
+- .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
+- .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
++#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \
++ .p_reset_shift = prs }
++
++#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\
++ .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
+ .ka_width = kaw }
+
+ #define VCO_CTRL_VAL(uo, lo) { .u_offset = uo, .l_offset = lo }
+@@ -56,7 +58,8 @@ static const struct iproc_pll_ctrl genpl
+ .flags = IPROC_CLK_AON | IPROC_CLK_PLL_HAS_NDIV_FRAC |
+ IPROC_CLK_PLL_NEEDS_SW_CFG,
+ .aon = AON_VAL(0x0, 2, 1, 0),
+- .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
++ .reset = RESET_VAL(0x0, 11, 10),
++ .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+ .sw_ctrl = SW_CTRL_VAL(0x10, 31),
+ .ndiv_int = REG_VAL(0x10, 20, 10),
+ .ndiv_frac = REG_VAL(0x10, 0, 20),
+@@ -114,7 +117,8 @@ CLK_OF_DECLARE(cygnus_genpll, "brcm,cygn
+ static const struct iproc_pll_ctrl lcpll0 = {
+ .flags = IPROC_CLK_AON | IPROC_CLK_PLL_NEEDS_SW_CFG,
+ .aon = AON_VAL(0x0, 2, 5, 4),
+- .reset = RESET_VAL(0x0, 31, 30, 27, 3, 23, 4, 19, 4),
++ .reset = RESET_VAL(0x0, 31, 30),
++ .dig_filter = DF_VAL(0x0, 27, 3, 23, 4, 19, 4),
+ .sw_ctrl = SW_CTRL_VAL(0x4, 31),
+ .ndiv_int = REG_VAL(0x4, 16, 10),
+ .pdiv = REG_VAL(0x4, 26, 4),
+@@ -191,7 +195,8 @@ static const struct iproc_pll_ctrl mipip
+ IPROC_CLK_NEEDS_READ_BACK,
+ .aon = AON_VAL(0x0, 4, 17, 16),
+ .asiu = ASIU_GATE_VAL(0x0, 3),
+- .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 4),
++ .reset = RESET_VAL(0x0, 11, 10),
++ .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 4),
+ .ndiv_int = REG_VAL(0x10, 20, 10),
+ .ndiv_frac = REG_VAL(0x10, 0, 20),
+ .pdiv = REG_VAL(0x14, 0, 4),
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -224,13 +224,17 @@ static void __pll_bring_out_reset(struct
+ u32 val;
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+ const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
++ const struct iproc_pll_dig_filter_ctrl *dig_filter = &ctrl->dig_filter;
++
++ val = readl(pll->pll_base + dig_filter->offset);
++ val &= ~(bit_mask(dig_filter->ki_width) << dig_filter->ki_shift |
++ bit_mask(dig_filter->kp_width) << dig_filter->kp_shift |
++ bit_mask(dig_filter->ka_width) << dig_filter->ka_shift);
++ val |= ki << dig_filter->ki_shift | kp << dig_filter->kp_shift |
++ ka << dig_filter->ka_shift;
++ iproc_pll_write(pll, pll->pll_base, dig_filter->offset, val);
+
+ val = readl(pll->pll_base + reset->offset);
+- val &= ~(bit_mask(reset->ki_width) << reset->ki_shift |
+- bit_mask(reset->kp_width) << reset->kp_shift |
+- bit_mask(reset->ka_width) << reset->ka_shift);
+- val |= ki << reset->ki_shift | kp << reset->kp_shift |
+- ka << reset->ka_shift;
+ val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift;
+ iproc_pll_write(pll, pll->pll_base, reset->offset, val);
+ }
+--- a/drivers/clk/bcm/clk-iproc.h
++++ b/drivers/clk/bcm/clk-iproc.h
+@@ -94,12 +94,19 @@ struct iproc_pll_aon_pwr_ctrl {
+ };
+
+ /*
+- * Control of the PLL reset, with Ki, Kp, and Ka parameters
++ * Control of the PLL reset
+ */
+ struct iproc_pll_reset_ctrl {
+ unsigned int offset;
+ unsigned int reset_shift;
+ unsigned int p_reset_shift;
++};
++
++/*
++ * Control of the Ki, Kp, and Ka parameters
++ */
++struct iproc_pll_dig_filter_ctrl {
++ unsigned int offset;
+ unsigned int ki_shift;
+ unsigned int ki_width;
+ unsigned int kp_shift;
+@@ -129,6 +136,7 @@ struct iproc_pll_ctrl {
+ struct iproc_pll_aon_pwr_ctrl aon;
+ struct iproc_asiu_gate asiu;
+ struct iproc_pll_reset_ctrl reset;
++ struct iproc_pll_dig_filter_ctrl dig_filter;
+ struct iproc_pll_sw_ctrl sw_ctrl;
+ struct iproc_clk_reg_op ndiv_int;
+ struct iproc_clk_reg_op ndiv_frac;
+--- a/drivers/clk/bcm/clk-nsp.c
++++ b/drivers/clk/bcm/clk-nsp.c
+@@ -26,9 +26,11 @@
+ #define AON_VAL(o, pw, ps, is) { .offset = o, .pwr_width = pw, \
+ .pwr_shift = ps, .iso_shift = is }
+
+-#define RESET_VAL(o, rs, prs, kis, kiw, kps, kpw, kas, kaw) { .offset = o, \
+- .reset_shift = rs, .p_reset_shift = prs, .ki_shift = kis, \
+- .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
++#define RESET_VAL(o, rs, prs) { .offset = o, .reset_shift = rs, \
++ .p_reset_shift = prs }
++
++#define DF_VAL(o, kis, kiw, kps, kpw, kas, kaw) { .offset = o, .ki_shift = kis,\
++ .ki_width = kiw, .kp_shift = kps, .kp_width = kpw, .ka_shift = kas, \
+ .ka_width = kaw }
+
+ #define ENABLE_VAL(o, es, hs, bs) { .offset = o, .enable_shift = es, \
+@@ -43,7 +45,8 @@ CLK_OF_DECLARE(nsp_armpll, "brcm,nsp-arm
+ static const struct iproc_pll_ctrl genpll = {
+ .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL,
+ .aon = AON_VAL(0x0, 1, 12, 0),
+- .reset = RESET_VAL(0x0, 11, 10, 4, 3, 0, 4, 7, 3),
++ .reset = RESET_VAL(0x0, 11, 10),
++ .dig_filter = DF_VAL(0x0, 4, 3, 0, 4, 7, 3),
+ .ndiv_int = REG_VAL(0x14, 20, 10),
+ .ndiv_frac = REG_VAL(0x14, 0, 20),
+ .pdiv = REG_VAL(0x18, 24, 3),
+@@ -99,7 +102,8 @@ CLK_OF_DECLARE(nsp_genpll_clk, "brcm,nsp
+ static const struct iproc_pll_ctrl lcpll0 = {
+ .flags = IPROC_CLK_PLL_HAS_NDIV_FRAC | IPROC_CLK_EMBED_PWRCTRL,
+ .aon = AON_VAL(0x0, 1, 24, 0),
+- .reset = RESET_VAL(0x0, 23, 22, 16, 3, 12, 4, 19, 4),
++ .reset = RESET_VAL(0x0, 23, 22),
++ .dig_filter = DF_VAL(0x0, 16, 3, 12, 4, 19, 4),
+ .ndiv_int = REG_VAL(0x4, 20, 8),
+ .ndiv_frac = REG_VAL(0x4, 0, 20),
+ .pdiv = REG_VAL(0x4, 28, 3),
diff --git a/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch b/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch
new file mode 100644
index 0000000..1e7cbc0
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/049-clk-iproc-Separate-status-and-control-variables.patch
@@ -0,0 +1,319 @@
+From eeb32564795a3584dba6281f445ff2aa552be36b Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 15:48:30 -0400
+Subject: [PATCH 49/50] clk: iproc: Separate status and control variables
+
+Some PLLs have separate registers for Status and Control. The means the
+pll_base needs to be split into 2 new variables, so that those PLLs can
+specify device tree registers for those independently. Also, add a new
+driver flag to identify this presence of the split, and let the driver
+know that additional registers need to be used.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ drivers/clk/bcm/clk-iproc-pll.c | 96 ++++++++++++++++++++++++-----------------
+ drivers/clk/bcm/clk-iproc.h | 6 +++
+ 2 files changed, 62 insertions(+), 40 deletions(-)
+
+--- a/drivers/clk/bcm/clk-iproc-pll.c
++++ b/drivers/clk/bcm/clk-iproc-pll.c
+@@ -74,7 +74,8 @@ struct iproc_clk {
+ };
+
+ struct iproc_pll {
+- void __iomem *pll_base;
++ void __iomem *status_base;
++ void __iomem *control_base;
+ void __iomem *pwr_base;
+ void __iomem *asiu_base;
+
+@@ -127,7 +128,7 @@ static int pll_wait_for_lock(struct ipro
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+
+ for (i = 0; i < LOCK_DELAY; i++) {
+- u32 val = readl(pll->pll_base + ctrl->status.offset);
++ u32 val = readl(pll->status_base + ctrl->status.offset);
+
+ if (val & (1 << ctrl->status.shift))
+ return 0;
+@@ -145,7 +146,7 @@ static void iproc_pll_write(const struct
+ writel(val, base + offset);
+
+ if (unlikely(ctrl->flags & IPROC_CLK_NEEDS_READ_BACK &&
+- base == pll->pll_base))
++ (base == pll->status_base || base == pll->control_base)))
+ val = readl(base + offset);
+ }
+
+@@ -161,9 +162,9 @@ static void __pll_disable(struct iproc_p
+ }
+
+ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
+- val = readl(pll->pll_base + ctrl->aon.offset);
++ val = readl(pll->control_base + ctrl->aon.offset);
+ val |= (bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
+ }
+
+ if (pll->pwr_base) {
+@@ -184,9 +185,9 @@ static int __pll_enable(struct iproc_pll
+ u32 val;
+
+ if (ctrl->flags & IPROC_CLK_EMBED_PWRCTRL) {
+- val = readl(pll->pll_base + ctrl->aon.offset);
++ val = readl(pll->control_base + ctrl->aon.offset);
+ val &= ~(bit_mask(ctrl->aon.pwr_width) << ctrl->aon.pwr_shift);
+- iproc_pll_write(pll, pll->pll_base, ctrl->aon.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->aon.offset, val);
+ }
+
+ if (pll->pwr_base) {
+@@ -213,9 +214,9 @@ static void __pll_put_in_reset(struct ip
+ const struct iproc_pll_ctrl *ctrl = pll->ctrl;
+ const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
+
+- val = readl(pll->pll_base + reset->offset);
++ val = readl(pll->control_base + reset->offset);
+ val &= ~(1 << reset->reset_shift | 1 << reset->p_reset_shift);
+- iproc_pll_write(pll, pll->pll_base, reset->offset, val);
++ iproc_pll_write(pll, pll->control_base, reset->offset, val);
+ }
+
+ static void __pll_bring_out_reset(struct iproc_pll *pll, unsigned int kp,
+@@ -226,17 +227,17 @@ static void __pll_bring_out_reset(struct
+ const struct iproc_pll_reset_ctrl *reset = &ctrl->reset;
+ const struct iproc_pll_dig_filter_ctrl *dig_filter = &ctrl->dig_filter;
+
+- val = readl(pll->pll_base + dig_filter->offset);
++ val = readl(pll->control_base + dig_filter->offset);
+ val &= ~(bit_mask(dig_filter->ki_width) << dig_filter->ki_shift |
+ bit_mask(dig_filter->kp_width) << dig_filter->kp_shift |
+ bit_mask(dig_filter->ka_width) << dig_filter->ka_shift);
+ val |= ki << dig_filter->ki_shift | kp << dig_filter->kp_shift |
+ ka << dig_filter->ka_shift;
+- iproc_pll_write(pll, pll->pll_base, dig_filter->offset, val);
++ iproc_pll_write(pll, pll->control_base, dig_filter->offset, val);
+
+- val = readl(pll->pll_base + reset->offset);
++ val = readl(pll->control_base + reset->offset);
+ val |= 1 << reset->reset_shift | 1 << reset->p_reset_shift;
+- iproc_pll_write(pll, pll->pll_base, reset->offset, val);
++ iproc_pll_write(pll, pll->control_base, reset->offset, val);
+ }
+
+ static int pll_set_rate(struct iproc_clk *clk, unsigned int rate_index,
+@@ -291,9 +292,9 @@ static int pll_set_rate(struct iproc_clk
+ /* put PLL in reset */
+ __pll_put_in_reset(pll);
+
+- iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.u_offset, 0);
++ iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.u_offset, 0);
+
+- val = readl(pll->pll_base + ctrl->vco_ctrl.l_offset);
++ val = readl(pll->control_base + ctrl->vco_ctrl.l_offset);
+
+ if (rate >= VCO_LOW && rate < VCO_MID)
+ val |= (1 << PLL_VCO_LOW_SHIFT);
+@@ -303,29 +304,29 @@ static int pll_set_rate(struct iproc_clk
+ else
+ val |= (1 << PLL_VCO_HIGH_SHIFT);
+
+- iproc_pll_write(pll, pll->pll_base, ctrl->vco_ctrl.l_offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->vco_ctrl.l_offset, val);
+
+ /* program integer part of NDIV */
+- val = readl(pll->pll_base + ctrl->ndiv_int.offset);
++ val = readl(pll->control_base + ctrl->ndiv_int.offset);
+ val &= ~(bit_mask(ctrl->ndiv_int.width) << ctrl->ndiv_int.shift);
+ val |= vco->ndiv_int << ctrl->ndiv_int.shift;
+- iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_int.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->ndiv_int.offset, val);
+
+ /* program fractional part of NDIV */
+ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+- val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
++ val = readl(pll->control_base + ctrl->ndiv_frac.offset);
+ val &= ~(bit_mask(ctrl->ndiv_frac.width) <<
+ ctrl->ndiv_frac.shift);
+ val |= vco->ndiv_frac << ctrl->ndiv_frac.shift;
+- iproc_pll_write(pll, pll->pll_base, ctrl->ndiv_frac.offset,
++ iproc_pll_write(pll, pll->control_base, ctrl->ndiv_frac.offset,
+ val);
+ }
+
+ /* program PDIV */
+- val = readl(pll->pll_base + ctrl->pdiv.offset);
++ val = readl(pll->control_base + ctrl->pdiv.offset);
+ val &= ~(bit_mask(ctrl->pdiv.width) << ctrl->pdiv.shift);
+ val |= vco->pdiv << ctrl->pdiv.shift;
+- iproc_pll_write(pll, pll->pll_base, ctrl->pdiv.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->pdiv.offset, val);
+
+ __pll_bring_out_reset(pll, kp, ka, ki);
+
+@@ -372,7 +373,7 @@ static unsigned long iproc_pll_recalc_ra
+ return 0;
+
+ /* PLL needs to be locked */
+- val = readl(pll->pll_base + ctrl->status.offset);
++ val = readl(pll->status_base + ctrl->status.offset);
+ if ((val & (1 << ctrl->status.shift)) == 0) {
+ clk->rate = 0;
+ return 0;
+@@ -383,19 +384,19 @@ static unsigned long iproc_pll_recalc_ra
+ *
+ * ((ndiv_int + ndiv_frac / 2^20) * (parent clock rate / pdiv)
+ */
+- val = readl(pll->pll_base + ctrl->ndiv_int.offset);
++ val = readl(pll->control_base + ctrl->ndiv_int.offset);
+ ndiv_int = (val >> ctrl->ndiv_int.shift) &
+ bit_mask(ctrl->ndiv_int.width);
+ ndiv = ndiv_int << 20;
+
+ if (ctrl->flags & IPROC_CLK_PLL_HAS_NDIV_FRAC) {
+- val = readl(pll->pll_base + ctrl->ndiv_frac.offset);
++ val = readl(pll->control_base + ctrl->ndiv_frac.offset);
+ ndiv_frac = (val >> ctrl->ndiv_frac.shift) &
+ bit_mask(ctrl->ndiv_frac.width);
+ ndiv += ndiv_frac;
+ }
+
+- val = readl(pll->pll_base + ctrl->pdiv.offset);
++ val = readl(pll->control_base + ctrl->pdiv.offset);
+ pdiv = (val >> ctrl->pdiv.shift) & bit_mask(ctrl->pdiv.width);
+
+ clk->rate = (ndiv * parent_rate) >> 20;
+@@ -460,14 +461,14 @@ static int iproc_clk_enable(struct clk_h
+ u32 val;
+
+ /* channel enable is active low */
+- val = readl(pll->pll_base + ctrl->enable.offset);
++ val = readl(pll->control_base + ctrl->enable.offset);
+ val &= ~(1 << ctrl->enable.enable_shift);
+- iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
+
+ /* also make sure channel is not held */
+- val = readl(pll->pll_base + ctrl->enable.offset);
++ val = readl(pll->control_base + ctrl->enable.offset);
+ val &= ~(1 << ctrl->enable.hold_shift);
+- iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
+
+ return 0;
+ }
+@@ -482,9 +483,9 @@ static void iproc_clk_disable(struct clk
+ if (ctrl->flags & IPROC_CLK_AON)
+ return;
+
+- val = readl(pll->pll_base + ctrl->enable.offset);
++ val = readl(pll->control_base + ctrl->enable.offset);
+ val |= 1 << ctrl->enable.enable_shift;
+- iproc_pll_write(pll, pll->pll_base, ctrl->enable.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->enable.offset, val);
+ }
+
+ static unsigned long iproc_clk_recalc_rate(struct clk_hw *hw,
+@@ -499,7 +500,7 @@ static unsigned long iproc_clk_recalc_ra
+ if (parent_rate == 0)
+ return 0;
+
+- val = readl(pll->pll_base + ctrl->mdiv.offset);
++ val = readl(pll->control_base + ctrl->mdiv.offset);
+ mdiv = (val >> ctrl->mdiv.shift) & bit_mask(ctrl->mdiv.width);
+ if (mdiv == 0)
+ mdiv = 256;
+@@ -546,14 +547,14 @@ static int iproc_clk_set_rate(struct clk
+ if (div > 256)
+ return -EINVAL;
+
+- val = readl(pll->pll_base + ctrl->mdiv.offset);
++ val = readl(pll->control_base + ctrl->mdiv.offset);
+ if (div == 256) {
+ val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
+ } else {
+ val &= ~(bit_mask(ctrl->mdiv.width) << ctrl->mdiv.shift);
+ val |= div << ctrl->mdiv.shift;
+ }
+- iproc_pll_write(pll, pll->pll_base, ctrl->mdiv.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->mdiv.offset, val);
+ clk->rate = parent_rate / div;
+
+ return 0;
+@@ -578,9 +579,10 @@ static void iproc_pll_sw_cfg(struct ipro
+ if (ctrl->flags & IPROC_CLK_PLL_NEEDS_SW_CFG) {
+ u32 val;
+
+- val = readl(pll->pll_base + ctrl->sw_ctrl.offset);
++ val = readl(pll->control_base + ctrl->sw_ctrl.offset);
+ val |= BIT(ctrl->sw_ctrl.shift);
+- iproc_pll_write(pll, pll->pll_base, ctrl->sw_ctrl.offset, val);
++ iproc_pll_write(pll, pll->control_base, ctrl->sw_ctrl.offset,
++ val);
+ }
+ }
+
+@@ -615,8 +617,8 @@ void __init iproc_pll_clk_setup(struct d
+ if (WARN_ON(!pll->clks))
+ goto err_clks;
+
+- pll->pll_base = of_iomap(node, 0);
+- if (WARN_ON(!pll->pll_base))
++ pll->control_base = of_iomap(node, 0);
++ if (WARN_ON(!pll->control_base))
+ goto err_pll_iomap;
+
+ /* Some SoCs do not require the pwr_base, thus failing is not fatal */
+@@ -629,6 +631,16 @@ void __init iproc_pll_clk_setup(struct d
+ goto err_asiu_iomap;
+ }
+
++ if (pll_ctrl->flags & IPROC_CLK_PLL_SPLIT_STAT_CTRL) {
++ /* Some SoCs have a split status/control. If this does not
++ * exist, assume they are unified.
++ */
++ pll->status_base = of_iomap(node, 2);
++ if (!pll->status_base)
++ goto err_status_iomap;
++ } else
++ pll->status_base = pll->control_base;
++
+ /* initialize and register the PLL itself */
+ pll->ctrl = pll_ctrl;
+
+@@ -699,6 +711,10 @@ err_clk_register:
+ clk_unregister(pll->clk_data.clks[i]);
+
+ err_pll_register:
++ if (pll->status_base != pll->control_base)
++ iounmap(pll->status_base);
++
++err_status_iomap:
+ if (pll->asiu_base)
+ iounmap(pll->asiu_base);
+
+@@ -706,7 +722,7 @@ err_asiu_iomap:
+ if (pll->pwr_base)
+ iounmap(pll->pwr_base);
+
+- iounmap(pll->pll_base);
++ iounmap(pll->control_base);
+
+ err_pll_iomap:
+ kfree(pll->clks);
+--- a/drivers/clk/bcm/clk-iproc.h
++++ b/drivers/clk/bcm/clk-iproc.h
+@@ -55,6 +55,12 @@
+ #define IPROC_CLK_EMBED_PWRCTRL BIT(5)
+
+ /*
++ * Some PLLs have separate registers for Status and Control. Identify this to
++ * let the driver know if additional registers need to be used
++ */
++#define IPROC_CLK_PLL_SPLIT_STAT_CTRL BIT(6)
++
++/*
+ * Parameters for VCO frequency configuration
+ *
+ * VCO frequency =
diff --git a/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch b/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch
new file mode 100644
index 0000000..a9a5246
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/050-ARM-dts-enable-clock-support-for-BCM5301X.patch
@@ -0,0 +1,153 @@
+From e96ef422d0095fe9ae39b03c0805a0db8ff7e382 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Tue, 13 Oct 2015 17:22:25 -0400
+Subject: [PATCH 50/50] ARM: dts: enable clock support for BCM5301X
+
+Replace current device tree dummy clocks with real clock support for
+Broadcom Northstar SoCs.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ arch/arm/boot/dts/bcm5301x.dtsi | 88 ++++++++++++++++++++++++++++++++---------
+ 1 file changed, 69 insertions(+), 19 deletions(-)
+
+--- a/arch/arm/boot/dts/bcm5301x.dtsi
++++ b/arch/arm/boot/dts/bcm5301x.dtsi
+@@ -8,6 +8,7 @@
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
++#include <dt-bindings/clock/bcm-nsp.h>
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/input/input.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+@@ -42,41 +43,48 @@
+
+ mpcore {
+ compatible = "simple-bus";
+- ranges = <0x00000000 0x19020000 0x00003000>;
++ ranges = <0x00000000 0x19000000 0x00023000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+- scu@0000 {
++ a9pll: arm_clk@00000 {
++ #clock-cells = <0>;
++ compatible = "brcm,nsp-armpll";
++ clocks = <&osc>;
++ reg = <0x00000 0x1000>;
++ };
++
++ scu@20000 {
+ compatible = "arm,cortex-a9-scu";
+- reg = <0x0000 0x100>;
++ reg = <0x20000 0x100>;
+ };
+
+- timer@0200 {
++ timer@20200 {
+ compatible = "arm,cortex-a9-global-timer";
+- reg = <0x0200 0x100>;
++ reg = <0x20200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_periph>;
++ clocks = <&periph_clk>;
+ };
+
+- local-timer@0600 {
++ local-timer@20600 {
+ compatible = "arm,cortex-a9-twd-timer";
+- reg = <0x0600 0x100>;
++ reg = <0x20600 0x100>;
+ interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_HIGH>;
+- clocks = <&clk_periph>;
++ clocks = <&periph_clk>;
+ };
+
+- gic: interrupt-controller@1000 {
++ gic: interrupt-controller@21000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+- reg = <0x1000 0x1000>,
+- <0x0100 0x100>;
++ reg = <0x21000 0x1000>,
++ <0x20100 0x100>;
+ };
+
+- L2: cache-controller@2000 {
++ L2: cache-controller@22000 {
+ compatible = "arm,pl310-cache";
+- reg = <0x2000 0x1000>;
++ reg = <0x22000 0x1000>;
+ cache-unified;
+ arm,shared-override;
+ prefetch-data = <1>;
+@@ -94,14 +102,37 @@
+
+ clocks {
+ #address-cells = <1>;
+- #size-cells = <0>;
++ #size-cells = <1>;
++ ranges;
+
+- /* As long as we do not have a real clock driver us this
+- * fixed clock */
+- clk_periph: periph {
++ osc: oscillator {
++ #clock-cells = <0>;
+ compatible = "fixed-clock";
++ clock-frequency = <25000000>;
++ };
++
++ iprocmed: iprocmed {
+ #clock-cells = <0>;
+- clock-frequency = <400000000>;
++ compatible = "fixed-factor-clock";
++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
++ clock-div = <2>;
++ clock-mult = <1>;
++ };
++
++ iprocslow: iprocslow {
++ #clock-cells = <0>;
++ compatible = "fixed-factor-clock";
++ clocks = <&genpll BCM_NSP_GENPLL_IPROCFAST_CLK>;
++ clock-div = <4>;
++ clock-mult = <1>;
++ };
++
++ periph_clk: periph_clk {
++ #clock-cells = <0>;
++ compatible = "fixed-factor-clock";
++ clocks = <&a9pll>;
++ clock-div = <2>;
++ clock-mult = <1>;
+ };
+ };
+
+@@ -189,4 +220,23 @@
+
+ brcm,nand-has-wp;
+ };
++
++ lcpll0: lcpll0@1800c100 {
++ #clock-cells = <1>;
++ compatible = "brcm,nsp-lcpll0";
++ reg = <0x1800c100 0x14>;
++ clocks = <&osc>;
++ clock-output-names = "lcpll0", "pcie_phy", "sdio",
++ "ddr_phy";
++ };
++
++ genpll: genpll@1800c140 {
++ #clock-cells = <1>;
++ compatible = "brcm,nsp-genpll";
++ reg = <0x1800c140 0x24>;
++ clocks = <&osc>;
++ clock-output-names = "genpll", "phy", "ethernetclk",
++ "usbclk", "iprocfast", "sata1",
++ "sata2";
++ };
+ };
diff --git a/target/linux/bcm53xx/patches-4.3/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch b/target/linux/bcm53xx/patches-4.3/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch
new file mode 100644
index 0000000..ccb8e27
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/067-ARM-BCM5301X-add-NAND-flash-chip-description-for-Asu.patch
@@ -0,0 +1,32 @@
+From af8fe7176ec13de08b1bfb7ea2ae9cc147b2429a Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sat, 12 Sep 2015 12:56:37 +0200
+Subject: [PATCH] ARM: BCM5301X: add NAND flash chip description for Asus
+ RT-AC87U
+
+The NAND flash chip description were not imported for the Asus RT-AC87U
+dts file when this was done for all the other dts files, because these
+patches were send in parallel.
+
+This adds a missing NAND flash chip description to this patch:
+commit 9faa5960eef3204cae6637b530f5e23e53b5a9ef
+Author: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Fri May 29 23:39:47 2015 +0200
+
+ARM: BCM5301X: add NAND flash chip description
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -10,6 +10,7 @@
+ /dts-v1/;
+
+ #include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
+
+ / {
+ compatible = "asus,rt-ac87u", "brcm,bcm4709", "brcm,bcm4708";
diff --git a/target/linux/bcm53xx/patches-4.3/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch b/target/linux/bcm53xx/patches-4.3/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch
new file mode 100644
index 0000000..044fb80
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/082-ARM-BCM5301X-Add-DT-for-Netgear-R7000.patch
@@ -0,0 +1,128 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Wed, 26 Aug 2015 16:11:38 +0200
+Subject: [PATCH] ARM: BCM5301X: Add DT for Netgear R7000
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -72,6 +72,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm47081-buffalo-wzr-900dhp.dtb \
+ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
++ bcm4709-netgear-r7000.dtb \
+ bcm4709-netgear-r8000.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+ bcm963138dvt.dtb
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -0,0 +1,106 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Netgear R7000
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
++
++/ {
++ compatible = "netgear,r7000", "brcm,bcm4709", "brcm,bcm4708";
++ model = "Netgear R7000";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ leds {
++ compatible = "gpio-leds";
++
++ power-white {
++ label = "bcm53xx:white:power";
++ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-on";
++ };
++
++ power-amber {
++ label = "bcm53xx:amber:power";
++ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ 5ghz {
++ label = "bcm53xx:white:5ghz";
++ gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ 2ghz {
++ label = "bcm53xx:white:2ghz";
++ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ wps {
++ label = "bcm53xx:white:wps";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wireless {
++ label = "bcm53xx:white:wireless";
++ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3 {
++ label = "bcm53xx:white:usb3";
++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb2 {
++ label = "bcm53xx:white:usb2";
++ gpios = <&chipcommon 18 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 4 GPIO_ACTIVE_LOW>;
++ };
++
++ rfkill {
++ label = "WiFi";
++ linux,code = <KEY_RFKILL>;
++ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
++ };
++
++ restart {
++ label = "Reset";
++ linux,code = <KEY_RESTART>;
++ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
++ };
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.3/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch b/target/linux/bcm53xx/patches-4.3/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch
new file mode 100644
index 0000000..0dae7c9
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/083-ARM-dts-bcm5301x-Add-BCM-SVK-DT-files.patch
@@ -0,0 +1,218 @@
+From a0aef7fbab0d8b5a0d445c74990e5233beda246e Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Wed, 21 Oct 2015 18:46:04 -0400
+Subject: [PATCH] ARM: dts: bcm5301x: Add BCM SVK DT files
+
+Add device tree files for Broadcom Northstar based SVKs. Since the
+bcm5301x.dtsi already exists, all that is necessary is the dts files to
+enable the UARTs. With these files, the SVKs are able to boot to shell.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ arch/arm/boot/dts/Makefile | 5 +++-
+ arch/arm/boot/dts/bcm94708.dts | 56 +++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm94709.dts | 56 +++++++++++++++++++++++++++++++++++
+ arch/arm/boot/dts/bcm953012k.dts | 63 ++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 179 insertions(+), 1 deletion(-)
+ create mode 100644 arch/arm/boot/dts/bcm94708.dts
+ create mode 100644 arch/arm/boot/dts/bcm94709.dts
+ create mode 100644 arch/arm/boot/dts/bcm953012k.dts
+
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -73,7 +73,10 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4709-asus-rt-ac87u.dtb \
+ bcm4709-buffalo-wxr-1900dhp.dtb \
+ bcm4709-netgear-r7000.dtb \
+- bcm4709-netgear-r8000.dtb
++ bcm4709-netgear-r8000.dtb \
++ bcm94708.dtb \
++ bcm94709.dtb \
++ bcm953012k.dtb
+ dtb-$(CONFIG_ARCH_BCM_63XX) += \
+ bcm963138dvt.dtb
+ dtb-$(CONFIG_ARCH_BCM_CYGNUS) += \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm94708.dts
+@@ -0,0 +1,56 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM94708)";
++ compatible = "brcm,bcm94708", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm94709.dts
+@@ -0,0 +1,56 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM94709)";
++ compatible = "brcm,bcm94709", "brcm,bcm4709", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm953012k.dts
+@@ -0,0 +1,63 @@
++/*
++ * BSD LICENSE
++ *
++ * Copyright(c) 2015 Broadcom Corporation. All rights reserved.
++ *
++ * Redistribution and use in source and binary forms, with or without
++ * modification, are permitted provided that the following conditions
++ * are met:
++ *
++ * * Redistributions of source code must retain the above copyright
++ * notice, this list of conditions and the following disclaimer.
++ * * Redistributions in binary form must reproduce the above copyright
++ * notice, this list of conditions and the following disclaimer in
++ * the documentation and/or other materials provided with the
++ * distribution.
++ * * Neither the name of Broadcom Corporation nor the names of its
++ * contributors may be used to endorse or promote products derived
++ * from this software without specific prior written permission.
++ *
++ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
++ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
++ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
++ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
++ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
++ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
++ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
++ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
++ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++
++/ {
++ model = "NorthStar SVK (BCM953012K)";
++ compatible = "brcm,bcm953012k", "brcm,brcm53012", "brcm,bcm4708";
++
++ aliases {
++ serial0 = &uart0;
++ serial1 = &uart1;
++ };
++
++ chosen {
++ stdout-path = "serial0:115200n8";
++ };
++
++ memory {
++ reg = <0x00000000 0x10000000>;
++ };
++};
++
++&uart0 {
++ clock-frequency = <62499840>;
++ status = "okay";
++};
++
++&uart1 {
++ clock-frequency = <62499840>;
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.3/101-use-part-parser.patch b/target/linux/bcm53xx/patches-4.3/101-use-part-parser.patch
new file mode 100644
index 0000000..8d48673
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/101-use-part-parser.patch
@@ -0,0 +1,11 @@
+--- a/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
++++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch8.dtsi
+@@ -19,6 +19,8 @@
+
+ nand-ecc-strength = <8>;
+ nand-ecc-step-size = <512>;
++
++ linux,part-probe = "ofpart", "bcm47xxpart";
+ };
+ };
+ };
diff --git a/target/linux/bcm53xx/patches-4.3/112-bcm53xx-sprom-add-sprom-driver.patch b/target/linux/bcm53xx/patches-4.3/112-bcm53xx-sprom-add-sprom-driver.patch
new file mode 100644
index 0000000..70ab039
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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
+@@ -525,6 +525,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.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch b/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch
new file mode 100644
index 0000000..5e3bd77
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/130-ARM-BCM-Add-SMP-support-for-Broadcom-NSP.patch
@@ -0,0 +1,635 @@
+From a0ad1511d5805b95ac4c454d7904c670a1696055 Mon Sep 17 00:00:00 2001
+From: Kapil Hali <kapilh@broadcom.com>
+Date: Wed, 14 Oct 2015 13:47:00 -0400
+Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom NSP
+
+Add SMP support for Broadcom's Northstar Plus SoC,
+cpu enable method and pen_release procedures. This
+changes also consolidates iProc family's - BCM NSP
+and BCM Kona, SMP handling in a common file.
+
+Northstar Plus SoC is based on ARM Cortex-A9
+revision r3p0 which requires configuration for ARM
+Errata 764369 for SMP. This change adds the needed
+configuration option.
+
+Signed-off-by: Kapil Hali <kapilh@broadcom.com>
+---
+ arch/arm/mach-bcm/Makefile | 2 +-
+ arch/arm/mach-bcm/bcm_nsp.h | 19 +++
+ arch/arm/mach-bcm/headsmp.S | 37 +++++
+ arch/arm/mach-bcm/kona_smp.c | 202 ---------------------------
+ arch/arm/mach-bcm/platsmp.c | 326 +++++++++++++++++++++++++++++++++++++++++++
+ 5 files changed, 383 insertions(+), 203 deletions(-)
+ create mode 100644 arch/arm/mach-bcm/bcm_nsp.h
+ create mode 100644 arch/arm/mach-bcm/headsmp.S
+ delete mode 100644 arch/arm/mach-bcm/kona_smp.c
+ create mode 100644 arch/arm/mach-bcm/platsmp.c
+
+--- a/arch/arm/mach-bcm/Makefile
++++ b/arch/arm/mach-bcm/Makefile
+@@ -20,7 +20,7 @@ obj-$(CONFIG_ARCH_BCM_281XX) += board_bc
+ obj-$(CONFIG_ARCH_BCM_21664) += board_bcm21664.o
+
+ # BCM281XX and BCM21664 SMP support
+-obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += kona_smp.o
++obj-$(CONFIG_ARCH_BCM_MOBILE_SMP) += platsmp.o
+
+ # BCM281XX and BCM21664 L2 cache control
+ obj-$(CONFIG_ARCH_BCM_MOBILE_L2_CACHE) += kona_l2_cache.o
+--- /dev/null
++++ b/arch/arm/mach-bcm/bcm_nsp.h
+@@ -0,0 +1,19 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#ifndef __BCM_NSP_H
++#define __BCM_NSP_H
++
++extern void nsp_secondary_startup(void);
++
++#endif /* __BCM_NSP_H */
+--- /dev/null
++++ b/arch/arm/mach-bcm/headsmp.S
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2015 Broadcom Corporation
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/linkage.h>
++
++/*
++ * iProc specific entry point for secondary CPUs. This provides
++ * a "holding pen" into which all secondary cores are held until
++ * we are ready for them to initialise.
++ */
++ENTRY(nsp_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
++
++ b secondary_startup
++
++1: .long .
++ .long pen_release
++
++ENDPROC(nsp_secondary_startup)
+--- a/arch/arm/mach-bcm/kona_smp.c
++++ /dev/null
+@@ -1,202 +0,0 @@
+-/*
+- * Copyright (C) 2014 Broadcom Corporation
+- * Copyright 2014 Linaro Limited
+- *
+- * This program is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU General Public License as
+- * published by the Free Software Foundation version 2.
+- *
+- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+- * kind, whether express or implied; without even the implied warranty
+- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+- * GNU General Public License for more details.
+- */
+-
+-#include <linux/init.h>
+-#include <linux/errno.h>
+-#include <linux/io.h>
+-#include <linux/of.h>
+-#include <linux/sched.h>
+-
+-#include <asm/smp.h>
+-#include <asm/smp_plat.h>
+-#include <asm/smp_scu.h>
+-
+-/* Size of mapped Cortex A9 SCU address space */
+-#define CORTEX_A9_SCU_SIZE 0x58
+-
+-#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
+-#define BOOT_ADDR_CPUID_MASK 0x3
+-
+-/* Name of device node property defining secondary boot register location */
+-#define OF_SECONDARY_BOOT "secondary-boot-reg"
+-
+-/* I/O address of register used to coordinate secondary core startup */
+-static u32 secondary_boot;
+-
+-/*
+- * Enable the Cortex A9 Snoop Control Unit
+- *
+- * By the time this is called we already know there are multiple
+- * cores present. We assume we're running on a Cortex A9 processor,
+- * so any trouble getting the base address register or getting the
+- * SCU base is a problem.
+- *
+- * Return 0 if successful or an error code otherwise.
+- */
+-static int __init scu_a9_enable(void)
+-{
+- unsigned long config_base;
+- void __iomem *scu_base;
+-
+- if (!scu_a9_has_base()) {
+- pr_err("no configuration base address register!\n");
+- return -ENXIO;
+- }
+-
+- /* Config base address register value is zero for uniprocessor */
+- config_base = scu_a9_get_base();
+- if (!config_base) {
+- pr_err("hardware reports only one core\n");
+- return -ENOENT;
+- }
+-
+- scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
+- if (!scu_base) {
+- pr_err("failed to remap config base (%lu/%u) for SCU\n",
+- config_base, CORTEX_A9_SCU_SIZE);
+- return -ENOMEM;
+- }
+-
+- scu_enable(scu_base);
+-
+- iounmap(scu_base); /* That's the last we'll need of this */
+-
+- return 0;
+-}
+-
+-static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
+-{
+- static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
+- struct device_node *node;
+- int ret;
+-
+- BUG_ON(secondary_boot); /* We're called only once */
+-
+- /*
+- * This function is only called via smp_ops->smp_prepare_cpu().
+- * That only happens if a "/cpus" device tree node exists
+- * and has an "enable-method" property that selects the SMP
+- * operations defined herein.
+- */
+- node = of_find_node_by_path("/cpus");
+- BUG_ON(!node);
+-
+- /*
+- * Our secondary enable method requires a "secondary-boot-reg"
+- * property to specify a register address used to request the
+- * ROM code boot a secondary code. If we have any trouble
+- * getting this we fall back to uniprocessor mode.
+- */
+- if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
+- pr_err("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
+- node->name);
+- ret = -ENOENT; /* Arrange to disable SMP */
+- goto out;
+- }
+-
+- /*
+- * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
+- * returned, the SoC reported a uniprocessor configuration.
+- * We bail on any other error.
+- */
+- ret = scu_a9_enable();
+-out:
+- of_node_put(node);
+- if (ret) {
+- /* Update the CPU present map to reflect uniprocessor mode */
+- BUG_ON(ret != -ENOENT);
+- pr_warn("disabling SMP\n");
+- init_cpu_present(&only_cpu_0);
+- }
+-}
+-
+-/*
+- * The ROM code has the secondary cores looping, waiting for an event.
+- * When an event occurs each core examines the bottom two bits of the
+- * secondary boot register. When a core finds those bits contain its
+- * own core id, it performs initialization, including computing its boot
+- * address by clearing the boot register value's bottom two bits. The
+- * core signals that it is beginning its execution by writing its boot
+- * address back to the secondary boot register, and finally jumps to
+- * that address.
+- *
+- * So to start a core executing we need to:
+- * - Encode the (hardware) CPU id with the bottom bits of the secondary
+- * start address.
+- * - Write that value into the secondary boot register.
+- * - Generate an event to wake up the secondary CPU(s).
+- * - Wait for the secondary boot register to be re-written, which
+- * indicates the secondary core has started.
+- */
+-static int bcm_boot_secondary(unsigned int cpu, struct task_struct *idle)
+-{
+- void __iomem *boot_reg;
+- phys_addr_t boot_func;
+- u64 start_clock;
+- u32 cpu_id;
+- u32 boot_val;
+- bool timeout = false;
+-
+- cpu_id = cpu_logical_map(cpu);
+- if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
+- pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
+- return -EINVAL;
+- }
+-
+- if (!secondary_boot) {
+- pr_err("required secondary boot register not specified\n");
+- return -EINVAL;
+- }
+-
+- boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
+- if (!boot_reg) {
+- pr_err("unable to map boot register for cpu %u\n", cpu_id);
+- return -ENOSYS;
+- }
+-
+- /*
+- * Secondary cores will start in secondary_startup(),
+- * defined in "arch/arm/kernel/head.S"
+- */
+- boot_func = virt_to_phys(secondary_startup);
+- BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
+- BUG_ON(boot_func > (phys_addr_t)U32_MAX);
+-
+- /* The core to start is encoded in the low bits */
+- boot_val = (u32)boot_func | cpu_id;
+- writel_relaxed(boot_val, boot_reg);
+-
+- sev();
+-
+- /* The low bits will be cleared once the core has started */
+- start_clock = local_clock();
+- while (!timeout && readl_relaxed(boot_reg) == boot_val)
+- timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
+-
+- iounmap(boot_reg);
+-
+- if (!timeout)
+- return 0;
+-
+- pr_err("timeout waiting for cpu %u to start\n", cpu_id);
+-
+- return -ENOSYS;
+-}
+-
+-static struct smp_operations bcm_smp_ops __initdata = {
+- .smp_prepare_cpus = bcm_smp_prepare_cpus,
+- .smp_boot_secondary = bcm_boot_secondary,
+-};
+-CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
+- &bcm_smp_ops);
+--- /dev/null
++++ b/arch/arm/mach-bcm/platsmp.c
+@@ -0,0 +1,326 @@
++/*
++ * Copyright (C) 2014-2015 Broadcom Corporation
++ * Copyright 2014 Linaro Limited
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation version 2.
++ *
++ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
++ * kind, whether express or implied; without even the implied warranty
++ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/cpumask.h>
++#include <linux/delay.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/io.h>
++#include <linux/jiffies.h>
++#include <linux/of.h>
++#include <linux/sched.h>
++#include <linux/smp.h>
++
++#include <asm/cacheflush.h>
++#include <asm/smp.h>
++#include <asm/smp_plat.h>
++#include <asm/smp_scu.h>
++
++#include "bcm_nsp.h"
++
++/* Size of mapped Cortex A9 SCU address space */
++#define CORTEX_A9_SCU_SIZE 0x58
++
++#define SECONDARY_TIMEOUT_NS NSEC_PER_MSEC /* 1 msec (in nanoseconds) */
++#define BOOT_ADDR_CPUID_MASK 0x3
++
++/* Name of device node property defining secondary boot register location */
++#define OF_SECONDARY_BOOT "secondary-boot-reg"
++
++/* I/O address of register used to coordinate secondary core startup */
++static u32 secondary_boot;
++
++static DEFINE_SPINLOCK(boot_lock);
++
++/*
++ * Write pen_release in a way that is guaranteed to be visible to all
++ * observers, irrespective of whether they're taking part in coherency
++ * or not. This is necessary for the hotplug code to work reliably.
++ */
++static void write_pen_release(int val)
++{
++ pen_release = val;
++ /*
++ * Ensure write to pen_release is visible to the other cores,
++ * here - primary core
++ */
++ smp_wmb();
++ sync_cache_w(&pen_release);
++}
++
++/*
++ * Enable the Cortex A9 Snoop Control Unit
++ *
++ * By the time this is called we already know there are multiple
++ * cores present. We assume we're running on a Cortex A9 processor,
++ * so any trouble getting the base address register or getting the
++ * SCU base is a problem.
++ *
++ * Return 0 if successful or an error code otherwise.
++ */
++static int __init scu_a9_enable(void)
++{
++ unsigned long config_base;
++ void __iomem *scu_base;
++
++ if (!scu_a9_has_base()) {
++ pr_err("no configuration base address register!\n");
++ return -ENXIO;
++ }
++
++ /* Config base address register value is zero for uniprocessor */
++ config_base = scu_a9_get_base();
++ if (!config_base) {
++ pr_err("hardware reports only one core\n");
++ return -ENOENT;
++ }
++
++ scu_base = ioremap((phys_addr_t)config_base, CORTEX_A9_SCU_SIZE);
++ if (!scu_base) {
++ pr_err("failed to remap config base (%lu/%u) for SCU\n",
++ config_base, CORTEX_A9_SCU_SIZE);
++ return -ENOMEM;
++ }
++
++ scu_enable(scu_base);
++
++ iounmap(scu_base); /* That's the last we'll need of this */
++
++ return 0;
++}
++
++static int nsp_write_lut(void (*secondary_startup) (void))
++{
++ void __iomem *sku_rom_lut;
++ phys_addr_t secondary_startup_phy;
++
++ if (!secondary_boot) {
++ pr_warn("required secondary boot register not specified\n");
++ return -EINVAL;
++ }
++
++ sku_rom_lut = ioremap_nocache((phys_addr_t)secondary_boot,
++ sizeof(secondary_boot));
++ if (!sku_rom_lut) {
++ pr_warn("unable to ioremap SKU-ROM LUT register\n");
++ return -ENOMEM;
++ }
++
++ secondary_startup_phy = virt_to_phys(secondary_startup);
++ BUG_ON(secondary_startup_phy > (phys_addr_t)U32_MAX);
++
++ writel_relaxed(secondary_startup_phy, sku_rom_lut);
++ /*
++ * Ensure the write is visible to the secondary core.
++ */
++ smp_wmb();
++
++ iounmap(sku_rom_lut);
++
++ return 0;
++}
++
++static void nsp_secondary_init(unsigned int cpu)
++{
++ /*
++ * Let the primary cpu know we are out of holding pen.
++ */
++ write_pen_release(-1);
++
++ /*
++ * Synchronise with the boot thread.
++ */
++ spin_lock(&boot_lock);
++ spin_unlock(&boot_lock);
++}
++
++static void __init bcm_smp_prepare_cpus(unsigned int max_cpus)
++{
++ static cpumask_t only_cpu_0 = { CPU_BITS_CPU0 };
++ struct device_node *node;
++ int ret;
++
++ BUG_ON(secondary_boot); /* We're called only once */
++
++ /*
++ * This function is only called via smp_ops->smp_prepare_cpu().
++ * That only happens if a "/cpus" device tree node exists
++ * and has an "enable-method" property that selects the SMP
++ * operations defined herein.
++ */
++ node = of_find_node_by_path("/cpus");
++ BUG_ON(!node);
++
++ /*
++ * Our secondary enable method requires a "secondary-boot-reg"
++ * property to specify a register address used to request the
++ * ROM code boot a secondary core. If we have any trouble
++ * getting this we fall back to uniprocessor mode.
++ */
++ if (of_property_read_u32(node, OF_SECONDARY_BOOT, &secondary_boot)) {
++ pr_warn("%s: missing/invalid " OF_SECONDARY_BOOT " property\n",
++ node->name);
++ ret = -ENOENT; /* Arrange to disable SMP */
++ goto out;
++ }
++
++ /*
++ * Enable the SCU on Cortex A9 based SoCs. If -ENOENT is
++ * returned, the SoC reported a uniprocessor configuration.
++ * We bail on any other error.
++ */
++ ret = scu_a9_enable();
++out:
++ of_node_put(node);
++ if (ret) {
++ /* Update the CPU present map to reflect uniprocessor mode */
++ pr_warn("disabling SMP\n");
++ init_cpu_present(&only_cpu_0);
++ }
++}
++
++/*
++ * The ROM code has the secondary cores looping, waiting for an event.
++ * When an event occurs each core examines the bottom two bits of the
++ * secondary boot register. When a core finds those bits contain its
++ * own core id, it performs initialization, including computing its boot
++ * address by clearing the boot register value's bottom two bits. The
++ * core signals that it is beginning its execution by writing its boot
++ * address back to the secondary boot register, and finally jumps to
++ * that address.
++ *
++ * So to start a core executing we need to:
++ * - Encode the (hardware) CPU id with the bottom bits of the secondary
++ * start address.
++ * - Write that value into the secondary boot register.
++ * - Generate an event to wake up the secondary CPU(s).
++ * - Wait for the secondary boot register to be re-written, which
++ * indicates the secondary core has started.
++ */
++static int kona_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++ void __iomem *boot_reg;
++ phys_addr_t boot_func;
++ u64 start_clock;
++ u32 cpu_id;
++ u32 boot_val;
++ bool timeout = false;
++
++ cpu_id = cpu_logical_map(cpu);
++ if (cpu_id & ~BOOT_ADDR_CPUID_MASK) {
++ pr_err("bad cpu id (%u > %u)\n", cpu_id, BOOT_ADDR_CPUID_MASK);
++ return -EINVAL;
++ }
++
++ if (!secondary_boot) {
++ pr_err("required secondary boot register not specified\n");
++ return -EINVAL;
++ }
++
++ boot_reg = ioremap_nocache((phys_addr_t)secondary_boot, sizeof(u32));
++ if (!boot_reg) {
++ pr_err("unable to map boot register for cpu %u\n", cpu_id);
++ return -ENOMEM;
++ }
++
++ /*
++ * Secondary cores will start in secondary_startup(),
++ * defined in "arch/arm/kernel/head.S"
++ */
++ boot_func = virt_to_phys(secondary_startup);
++ BUG_ON(boot_func & BOOT_ADDR_CPUID_MASK);
++ BUG_ON(boot_func > (phys_addr_t)U32_MAX);
++
++ /* The core to start is encoded in the low bits */
++ boot_val = (u32)boot_func | cpu_id;
++ writel_relaxed(boot_val, boot_reg);
++
++ sev();
++
++ /* The low bits will be cleared once the core has started */
++ start_clock = local_clock();
++ while (!timeout && readl_relaxed(boot_reg) == boot_val)
++ timeout = local_clock() - start_clock > SECONDARY_TIMEOUT_NS;
++
++ iounmap(boot_reg);
++
++ if (!timeout)
++ return 0;
++
++ pr_err("timeout waiting for cpu %u to start\n", cpu_id);
++
++ return -ENXIO;
++}
++
++static int nsp_boot_secondary(unsigned int cpu, struct task_struct *idle)
++{
++ unsigned long timeout;
++ int ret;
++
++ /*
++ * After wake up, secondary core branches to the startup
++ * address programmed at SKU ROM LUT location.
++ */
++ ret = nsp_write_lut(nsp_secondary_startup);
++ if (ret) {
++ pr_err("unable to write startup addr to SKU ROM LUT\n");
++ goto out;
++ }
++
++ /*
++ * 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.
++ */
++ spin_lock(&boot_lock);
++
++ write_pen_release(cpu_logical_map(cpu));
++ /*
++ * Send an Event to wake up the secondary core which is in
++ * WFE state. Updated pen_release should also be visible to
++ * the secondary core.
++ */
++ dsb_sev();
++
++ timeout = jiffies + (1 * HZ);
++ while (time_before(jiffies, timeout)) {
++ /* Make sure loads on other CPU is visible */
++ smp_rmb();
++ if (pen_release == -1)
++ break;
++
++ udelay(10);
++ }
++
++ spin_unlock(&boot_lock);
++
++ ret = pen_release != -1 ? -ENXIO : 0;
++
++out:
++ return ret;
++}
++
++static struct smp_operations bcm_smp_ops __initdata = {
++ .smp_prepare_cpus = bcm_smp_prepare_cpus,
++ .smp_boot_secondary = kona_boot_secondary,
++};
++CPU_METHOD_OF_DECLARE(bcm_smp_bcm281xx, "brcm,bcm11351-cpu-method",
++ &bcm_smp_ops);
++
++struct smp_operations nsp_smp_ops __initdata = {
++ .smp_prepare_cpus = bcm_smp_prepare_cpus,
++ .smp_secondary_init = nsp_secondary_init,
++ .smp_boot_secondary = nsp_boot_secondary,
++};
++CPU_METHOD_OF_DECLARE(bcm_smp_nsp, "brcm,bcm-nsp-smp", &nsp_smp_ops);
diff --git a/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch b/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch
new file mode 100644
index 0000000..ad1c771
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/131-ARM-BCM-Add-SMP-support-for-Broadcom-4708.patch
@@ -0,0 +1,50 @@
+From ddbf0ad85be06948dd214c7beb7b315ef2749e65 Mon Sep 17 00:00:00 2001
+From: Jon Mason <jonmason@broadcom.com>
+Date: Thu, 15 Oct 2015 14:14:10 -0400
+Subject: [PATCH] ARM: BCM: Add SMP support for Broadcom 4708
+
+ARM: BCM: Add SMP support for Broadcom 4708
+
+Add SMP support for Broadcom's 4708 SoCs.
+
+Signed-off-by: Jon Mason <jonmason@broadcom.com>
+---
+ arch/arm/boot/dts/bcm4708.dtsi | 2 ++
+ arch/arm/mach-bcm/Kconfig | 2 ++
+ arch/arm/mach-bcm/Makefile | 3 +++
+ 3 files changed, 7 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708.dtsi
++++ b/arch/arm/boot/dts/bcm4708.dtsi
+@@ -15,6 +15,8 @@
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
++ enable-method = "brcm,bcm-nsp-smp";
++ secondary-boot-reg = <0xffff0400>;
+
+ cpu@0 {
+ device_type = "cpu";
+--- a/arch/arm/mach-bcm/Kconfig
++++ b/arch/arm/mach-bcm/Kconfig
+@@ -38,6 +38,8 @@ config ARCH_BCM_CYGNUS
+ config ARCH_BCM_5301X
+ bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
++ select ARM_ERRATA_764369 if SMP
++ select HAVE_SMP
+ help
+ Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
+
+--- 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_ARCH_BCM_5301X),y)
++obj-$(CONFIG_SMP) += headsmp.o platsmp.o
++endif
+
+ # BCM63XXx
+ ifeq ($(CONFIG_ARCH_BCM_63XX),y)
diff --git a/target/linux/bcm53xx/patches-4.3/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch b/target/linux/bcm53xx/patches-4.3/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch
new file mode 100644
index 0000000..c117774
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/132-ARM-BCM5301X-Add-missing-Netgear-R8000-LEDs.patch
@@ -0,0 +1,57 @@
+From b58682598541262f967ecd6db04bacac38026d3c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Fri, 30 Oct 2015 15:29:52 +0100
+Subject: [PATCH] ARM: BCM5301X: Add missing Netgear R8000 LEDs
+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/bcm4709-netgear-r8000.dts | 30 +++++++++++++++++++++++++++++
+ 1 file changed, 30 insertions(+)
+
+diff --git a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+index 446c586..b52927c 100644
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -50,6 +50,36 @@
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
++
++ wireless {
++ label = "bcm53xx:white:wireless";
++ gpios = <&chipcommon 14 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ wps {
++ label = "bcm53xx:white:wps";
++ gpios = <&chipcommon 15 GPIO_ACTIVE_HIGH>;
++ linux,default-trigger = "default-off";
++ };
++
++ 5ghz-2 {
++ label = "bcm53xx:white:5ghz-2";
++ gpios = <&chipcommon 16 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb3 {
++ label = "bcm53xx:white:usb3";
++ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
++
++ usb2 {
++ label = "bcm53xx:white:usb2";
++ gpios = <&chipcommon 18 GPIO_ACTIVE_LOW>;
++ linux,default-trigger = "default-off";
++ };
+ };
+
+ gpio-keys {
+--
+1.8.4.5
+
diff --git a/target/linux/bcm53xx/patches-4.3/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch b/target/linux/bcm53xx/patches-4.3/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch
new file mode 100644
index 0000000..5031886
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/186-USB-bcma-switch-to-GPIO-descriptor-for-power-control.patch
@@ -0,0 +1,75 @@
+From 0cb136f9882e4649ad6160bb7b48955ff728888c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Sun, 1 Nov 2015 08:17:21 +0100
+Subject: [PATCH V2] USB: bcma: switch to GPIO descriptor for power control
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+So far we were using simple (legacy) GPIO functions & some poor logic to
+control power. It got many drawbacks: we were ignoring OF flags
+(GPIO_ACTIVE_LOW), we were not setting direction to output and we were
+assuming gpio_request success all the time.
+Fix it by switching to gpiod functions and adding appropriate checks.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+ drivers/usb/host/bcma-hcd.c | 21 ++++++++++-----------
+ 1 file changed, 10 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
+index 5398e3d..291aaa2 100644
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -21,6 +21,7 @@
+ */
+ #include <linux/bcma/bcma.h>
+ #include <linux/delay.h>
++#include <linux/gpio/consumer.h>
+ #include <linux/platform_device.h>
+ #include <linux/module.h>
+ #include <linux/slab.h>
+@@ -36,6 +37,7 @@ MODULE_LICENSE("GPL");
+ struct bcma_hcd_device {
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
++ struct gpio_desc *gpio_desc;
+ };
+
+ /* Wait for bitmask in a register to get set or cleared.
+@@ -228,19 +230,12 @@ static void bcma_hcd_init_chip_arm(struct bcma_device *dev)
+
+ static void bcma_hci_platform_power_gpio(struct bcma_device *dev, bool val)
+ {
+- int gpio;
++ struct bcma_hcd_device *usb_dev = bcma_get_drvdata(dev);
+
+- gpio = of_get_named_gpio(dev->dev.of_node, "vcc-gpio", 0);
+- if (!gpio_is_valid(gpio))
++ if (IS_ERR_OR_NULL(usb_dev->gpio_desc))
+ return;
+
+- if (val) {
+- gpio_request(gpio, "bcma-hcd-gpio");
+- gpio_set_value(gpio, 1);
+- } else {
+- gpio_set_value(gpio, 0);
+- gpio_free(gpio);
+- }
++ gpiod_set_value(usb_dev->gpio_desc, val);
+ }
+
+ static const struct usb_ehci_pdata ehci_pdata = {
+@@ -314,7 +309,11 @@ static int bcma_hcd_probe(struct bcma_device *dev)
+ if (!usb_dev)
+ return -ENOMEM;
+
+- bcma_hci_platform_power_gpio(dev, true);
++ if (dev->dev.of_node)
++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
++ &dev->dev.of_node->fwnode);
++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
++ gpiod_direction_output(usb_dev->gpio_desc, 1);
+
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
diff --git a/target/linux/bcm53xx/patches-4.3/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch b/target/linux/bcm53xx/patches-4.3/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch
new file mode 100644
index 0000000..a769650
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/190-usb-xhci-plat-fix-adding-usb3-lpm-capable-quirk.patch
@@ -0,0 +1,63 @@
+From 1420e53fc88673683f8990aa5342e7b2640ce165 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Sun, 18 Oct 2015 19:13:27 +0200
+Subject: [PATCH v3 1/6] usb: xhci: plat: fix adding usb3-lpm-capable quirk
+
+The xhci->quirks member is overwritten in xhci_gen_setup() with the
+quirks given through the module load parameter. Without this patch the
+usb3-lpm-capable quirk will be over written before it gets used. This
+patch moves the quirks code to the xhci_plat_quirks() callback function
+which gets called directly after the quirks member variable is
+overwritten with the module load parameter.
+
+I do not have any hardware which is using usb3-lpm-capabls so I can not
+test this on real hardware.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/xhci-plat.c | 14 ++++++++------
+ 1 file changed, 8 insertions(+), 6 deletions(-)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -37,12 +37,20 @@ static const struct xhci_driver_override
+
+ static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
+ {
++ struct platform_device *pdev = to_platform_device(dev);
++ struct device_node *node = pdev->dev.of_node;
++ struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
++
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_PLAT;
++
++ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
++ (pdata && pdata->usb3_lpm_capable))
++ xhci->quirks |= XHCI_LPM_SUPPORT;
+ }
+
+ /* called during probe() after chip reset completes */
+@@ -74,8 +82,6 @@ static int xhci_plat_start(struct usb_hc
+
+ static int xhci_plat_probe(struct platform_device *pdev)
+ {
+- struct device_node *node = pdev->dev.of_node;
+- struct usb_xhci_pdata *pdata = dev_get_platdata(&pdev->dev);
+ const struct hc_driver *driver;
+ struct xhci_hcd *xhci;
+ struct resource *res;
+@@ -148,10 +154,6 @@ static int xhci_plat_probe(struct platfo
+ goto disable_clk;
+ }
+
+- if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
+- (pdata && pdata->usb3_lpm_capable))
+- xhci->quirks |= XHCI_LPM_SUPPORT;
+-
+ if (HCC_MAX_PSA(xhci->hcc_params) >= 4)
+ xhci->shared_hcd->can_do_streams = 1;
+
diff --git a/target/linux/bcm53xx/patches-4.3/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch b/target/linux/bcm53xx/patches-4.3/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
new file mode 100644
index 0000000..ae70f42
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/191-usb-xhci-add-Broadcom-specific-fake-doorbell.patch
@@ -0,0 +1,135 @@
+From dd0e5f9a6a4aed849bdb80641c2a2350476cede7 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 v3 2/6] usb: 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.
+This quirk is also added to the platform data so we can activate it
+when we register our platform driver.
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/xhci-plat.c | 3 +++
+ drivers/usb/host/xhci.c | 57 +++++++++++++++++++++++++++++++++++++---
+ drivers/usb/host/xhci.h | 1 +
+ include/linux/usb/xhci_pdriver.h | 1 +
+ 4 files changed, 59 insertions(+), 3 deletions(-)
+
+--- a/drivers/usb/host/xhci-plat.c
++++ b/drivers/usb/host/xhci-plat.c
+@@ -51,6 +51,9 @@ static void xhci_plat_quirks(struct devi
+ if ((node && of_property_read_bool(node, "usb3-lpm-capable")) ||
+ (pdata && pdata->usb3_lpm_capable))
+ xhci->quirks |= XHCI_LPM_SUPPORT;
++
++ if (pdata && pdata->usb3_fake_doorbell)
++ xhci->quirks |= XHCI_FAKE_DOORBELL;
+ }
+
+ /* called during probe() after chip reset completes */
+--- a/drivers/usb/host/xhci.c
++++ b/drivers/usb/host/xhci.c
+@@ -121,6 +121,39 @@ int xhci_halt(struct xhci_hcd *xhci)
+ return ret;
+ }
+
++static int xhci_fake_doorbell(struct xhci_hcd *xhci, int slot_id)
++{
++ u32 temp;
++
++ /* alloc a virt device for slot */
++ if (!xhci_alloc_virt_device(xhci, slot_id, NULL, GFP_NOIO)) {
++ xhci_warn(xhci, "Could not allocate xHCI USB device data structures\n");
++ return -ENOMEM;
++ }
++
++ /* ring fake doorbell for slot_id ep 0 */
++ xhci_ring_ep_doorbell(xhci, slot_id, 0, 0);
++ usleep_range(1000, 1500);
++
++ /* read the status register to check if HSE is set or not? */
++ temp = readl(&xhci->op_regs->status);
++
++ /* clear HSE if set */
++ if (temp & STS_FATAL) {
++ xhci_dbg(xhci, "HSE problem detected, status: 0x%x\n", temp);
++ temp &= ~(0x1fff);
++ temp |= STS_FATAL;
++ writel(temp, &xhci->op_regs->status);
++ usleep_range(1000, 1500);
++ readl(&xhci->op_regs->status);
++ }
++
++ /* Free virt device */
++ xhci_free_virt_device(xhci, slot_id);
++
++ return 0;
++}
++
+ /*
+ * Set the run bit and wait for the host to be running.
+ */
+@@ -557,10 +590,25 @@ int xhci_init(struct usb_hcd *hcd)
+
+ static int xhci_run_finished(struct xhci_hcd *xhci)
+ {
+- if (xhci_start(xhci)) {
+- xhci_halt(xhci);
+- return -ENODEV;
++ int err;
++
++ err = xhci_start(xhci);
++ if (err) {
++ err = -ENODEV;
++ goto out_err;
++ }
++ if (xhci->quirks & XHCI_FAKE_DOORBELL) {
++ err = xhci_fake_doorbell(xhci, 1);
++ if (err)
++ goto out_err;
++
++ err = xhci_start(xhci);
++ if (err) {
++ err = -ENODEV;
++ goto out_err;
++ }
+ }
++
+ xhci->shared_hcd->state = HC_STATE_RUNNING;
+ xhci->cmd_ring_state = CMD_RING_STATE_RUNNING;
+
+@@ -570,6 +618,9 @@ static int xhci_run_finished(struct xhci
+ xhci_dbg_trace(xhci, trace_xhci_dbg_init,
+ "Finished xhci_run for USB3 roothub");
+ return 0;
++out_err:
++ xhci_halt(xhci);
++ return err;
+ }
+
+ /*
+--- a/drivers/usb/host/xhci.h
++++ b/drivers/usb/host/xhci.h
+@@ -1575,6 +1575,7 @@ struct xhci_hcd {
+ /* For controllers with a broken beyond repair streams implementation */
+ #define XHCI_BROKEN_STREAMS (1 << 19)
+ #define XHCI_PME_STUCK_QUIRK (1 << 20)
++#define XHCI_FAKE_DOORBELL (1 << 21)
+ unsigned int num_active_eps;
+ unsigned int limit_active_eps;
+ /* There are two roothubs to keep track of bus suspend info for */
+--- a/include/linux/usb/xhci_pdriver.h
++++ b/include/linux/usb/xhci_pdriver.h
+@@ -22,6 +22,7 @@
+ */
+ struct usb_xhci_pdata {
+ unsigned usb3_lpm_capable:1;
++ unsigned usb3_fake_doorbell:1;
+ };
+
+ #endif /* __USB_CORE_XHCI_PDRIVER_H */
diff --git a/target/linux/bcm53xx/patches-4.3/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch b/target/linux/bcm53xx/patches-4.3/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
new file mode 100644
index 0000000..17a9260
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/195-USB-bcma-make-helper-creating-platform-dev-more-gene.patch
@@ -0,0 +1,75 @@
+From c7c7bf7fcbacadac7781783de25fe1e13e2a2c35 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 v3 3/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ 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
+@@ -244,7 +244,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];
+@@ -259,8 +262,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);
+
+@@ -271,12 +273,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);
+@@ -333,11 +331,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.3/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch b/target/linux/bcm53xx/patches-4.3/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
new file mode 100644
index 0000000..262192b
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/196-USB-bcma-use-separated-function-for-USB-2.0-initiali.patch
@@ -0,0 +1,112 @@
+From fa5622c2fadae573dd6b0f5bffe436b230b411f6 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 v3 4/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ 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
+@@ -35,6 +35,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;
+ struct gpio_desc *gpio_desc;
+@@ -288,31 +289,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;
+-
+- if (dev->dev.of_node)
+- usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
+- &dev->dev.of_node->fwnode);
+- if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
+- gpiod_direction_output(usb_dev->gpio_desc, 1);
+-
+ switch (dev->id.id) {
+ case BCMA_CORE_NS_USB20:
+ bcma_hcd_init_chip_arm(dev);
+@@ -345,7 +331,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:
+@@ -353,6 +338,40 @@ 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;
++
++ if (dev->dev.of_node)
++ usb_dev->gpio_desc = devm_get_gpiod_from_child(&dev->dev, "vcc",
++ &dev->dev.of_node->fwnode);
++ if (!IS_ERR_OR_NULL(usb_dev->gpio_desc))
++ gpiod_direction_output(usb_dev->gpio_desc, 1);
++
++ 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.3/197-USB-bcma-add-USB-3.0-support.patch b/target/linux/bcm53xx/patches-4.3/197-USB-bcma-add-USB-3.0-support.patch
new file mode 100644
index 0000000..34ab858
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/197-USB-bcma-add-USB-3.0-support.patch
@@ -0,0 +1,295 @@
+From 121ec6539abedbc0e975cf35f48ee044b323e4c3 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 v3 5/6] 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>
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+---
+ drivers/usb/host/bcma-hcd.c | 225 ++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 225 insertions(+)
+
+--- a/drivers/usb/host/bcma-hcd.c
++++ b/drivers/usb/host/bcma-hcd.c
+@@ -29,6 +29,7 @@
+ #include <linux/of_gpio.h>
+ #include <linux/usb/ehci_pdriver.h>
+ #include <linux/usb/ohci_pdriver.h>
++#include <linux/usb/xhci_pdriver.h>
+
+ MODULE_AUTHOR("Hauke Mehrtens");
+ MODULE_DESCRIPTION("Common USB driver for BCMA Bus");
+@@ -38,6 +39,7 @@ struct bcma_hcd_device {
+ struct bcma_device *core;
+ struct platform_device *ehci_dev;
+ struct platform_device *ohci_dev;
++ struct platform_device *xhci_dev;
+ struct gpio_desc *gpio_desc;
+ };
+
+@@ -245,6 +247,10 @@ static const struct usb_ehci_pdata ehci_
+ static const struct usb_ohci_pdata ohci_pdata = {
+ };
+
++static const struct usb_xhci_pdata xhci_pdata = {
++ .usb3_fake_doorbell = 1
++};
++
+ static struct platform_device *bcma_hcd_create_pdev(struct bcma_device *dev,
+ const char *name, u32 addr,
+ const void *data,
+@@ -338,6 +344,216 @@ 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,
++ &xhci_pdata,
++ sizeof(xhci_pdata));
++ 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;
+@@ -364,6 +580,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;
+ }
+@@ -377,11 +598,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);
+ }
+@@ -418,6 +642,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.3/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch b/target/linux/bcm53xx/patches-4.3/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch
new file mode 100644
index 0000000..06254b3
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/300-ARM-BCM5301X-Disable-MMU-and-Dcache-for-decompression.patch
@@ -0,0 +1,86 @@
+From: Florian Fainelli <f.fainelli@gmail.com>
+Subject: [PATCH] ARM: BCM5301x: Disable MMU and Dcache during decompression
+Date: Tue, 14 Jul 2015 16:12:08 -0700
+
+Use the existing __armv7_mmu_cache_flush() to perform the cache flush
+since this does what we are after.
+
+Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
+---
+ arch/arm/boot/compressed/Makefile | 4 +++
+ arch/arm/boot/compressed/head-bcm_5301x-mpcore.S | 37 ++++++++++++++++++++++++
+ arch/arm/boot/compressed/head.S | 2 ++
+ 3 files changed, 43 insertions(+)
+ create mode 100644 arch/arm/boot/compressed/head-bcm_5301x-mpcore.S
+
+--- a/arch/arm/boot/compressed/Makefile
++++ b/arch/arm/boot/compressed/Makefile
+@@ -31,6 +31,10 @@ 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
++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 __armv7_mmu_cache_flush_fn
++ nop
++ mov r0,#0
++ ldr r3, =0x19022000 @ L2 cache controller, control reg
++ str r0, [r3, #0x100] @ Disable L2 cache
++ nop
++
++ @ Restore
++ mov r8, r12
+--- a/arch/arm/boot/compressed/head.S
++++ b/arch/arm/boot/compressed/head.S
+@@ -1152,6 +1152,7 @@ __armv7_mmu_cache_flush:
+ hierarchical:
+ mcr p15, 0, r10, c7, c10, 5 @ DMB
+ stmfd sp!, {r0-r7, r9-r11}
++ENTRY(__armv7_mmu_cache_flush_fn)
+ 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
+@@ -1201,6 +1202,7 @@ iflush:
+ mcr p15, 0, r10, c7, c10, 4 @ DSB
+ mcr p15, 0, r10, c7, c5, 4 @ ISB
+ mov pc, lr
++ENDPROC(__armv7_mmu_cache_flush_fn)
+
+ __armv5tej_mmu_cache_flush:
+ tst r4, #1
diff --git a/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch b/target/linux/bcm53xx/patches-4.3/301-ARM-BCM5301X-Add-SPROM.patch
new file mode 100644
index 0000000..ed6cc73
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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
+@@ -136,6 +136,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.3/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch b/target/linux/bcm53xx/patches-4.3/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch
new file mode 100644
index 0000000..82ac24e
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/305-ARM-BCM5301X-Add-DT-for-Linksys-EA6300-V1.patch
@@ -0,0 +1,69 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Subject: [PATCH] ARM: BCM5301X: Add DT for Linksys EA6300 V1
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
+---
+--- a/arch/arm/boot/dts/Makefile
++++ b/arch/arm/boot/dts/Makefile
+@@ -63,6 +63,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-asus-rt-ac56u.dtb \
+ bcm4708-asus-rt-ac68u.dtb \
+ bcm4708-buffalo-wzr-1750dhp.dtb \
++ bcm4708-linksys-ea6300-v1.dtb \
+ bcm4708-luxul-xwc-1000.dtb \
+ bcm4708-netgear-r6250.dtb \
+ bcm4708-netgear-r6300-v2.dtb \
+--- /dev/null
++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
+@@ -0,0 +1,48 @@
++/*
++ * Broadcom BCM470X / BCM5301X ARM platform code.
++ * DTS for Linksys EA6300 V1
++ *
++ * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
++ *
++ * Licensed under the GNU/GPL. See COPYING for details.
++ */
++
++/dts-v1/;
++
++#include "bcm4708.dtsi"
++#include "bcm5301x-nand-cs0-bch8.dtsi"
++
++/ {
++ compatible = "linksys,ea6300v1", "brcm,bcm4708";
++ model = "Linksys EA6300 V1";
++
++ chosen {
++ bootargs = "console=ttyS0,115200";
++ };
++
++ memory {
++ reg = <0x00000000 0x08000000>;
++ };
++
++ gpio-keys {
++ compatible = "gpio-keys";
++ #address-cells = <1>;
++ #size-cells = <0>;
++
++ 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>;
++ };
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
diff --git a/target/linux/bcm53xx/patches-4.3/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch b/target/linux/bcm53xx/patches-4.3/320-ARM-BCM5301X-Add-Buffalo-WXR-1900DHP-clock-and-USB-p.patch
new file mode 100644
index 0000000..802188d
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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
+@@ -24,6 +24,23 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ 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.3/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch b/target/linux/bcm53xx/patches-4.3/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch
new file mode 100644
index 0000000..ed4d1bc
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/321-ARM-BCM5301X-Set-vcc-gpio-for-USB-controllers.patch
@@ -0,0 +1,86 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+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>
+---
+--- a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
++++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
+@@ -24,6 +24,26 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ 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
+@@ -24,6 +24,17 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ axi@18000000 {
++ usb3@23000 {
++ reg = <0x00023000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
++ };
++ };
++
+ leds {
+ compatible = "gpio-leds";
+
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -24,6 +24,26 @@
+ reg = <0x00000000 0x08000000>;
+ };
+
++ axi@18000000 {
++ usb2@21000 {
++ reg = <0x00021000 0x1000>;
++
++ #address-cells = <1>;
++ #size-cells = <1>;
++
++ vcc-gpio = <&chipcommon 0 GPIO_ACTIVE_HIGH>;
++ };
++
++ 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.3/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch b/target/linux/bcm53xx/patches-4.3/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
new file mode 100644
index 0000000..4e25647
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/330-ARM-BCM5310X-Enable-earlyprintk-on-tested-devices.patch
@@ -0,0 +1,170 @@
+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
+@@ -17,7 +17,7 @@
+ model = "Asus RT-AC87U";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -17,7 +17,7 @@
+ model = "Netgear R7000";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
+--- a/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
++++ b/arch/arm/boot/dts/bcm4708-linksys-ea6300-v1.dts
+@@ -17,7 +17,7 @@
+ model = "Linksys EA6300 V1";
+
+ chosen {
+- bootargs = "console=ttyS0,115200";
++ bootargs = "console=ttyS0,115200 earlyprintk";
+ };
+
+ memory {
diff --git a/target/linux/bcm53xx/patches-4.3/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch b/target/linux/bcm53xx/patches-4.3/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
new file mode 100644
index 0000000..b53c57f
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/331-ARM-BCM5301X-Specify-RAM-on-devices-by-including-HIG.patch
@@ -0,0 +1,173 @@
+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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ axi@18000000 {
+--- 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>;
+ };
+
+ clocks {
+--- 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
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -21,7 +21,8 @@
+ };
+
+ memory {
+- reg = <0x00000000 0x08000000>;
++ reg = <0x00000000 0x08000000
++ 0x88000000 0x08000000>;
+ };
+
+ leds {
diff --git a/target/linux/bcm53xx/patches-4.3/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch b/target/linux/bcm53xx/patches-4.3/332-ARM-BCM5301X-Add-power-button-for-Buffalo-WZR-1750DHP.patch
new file mode 100644
index 0000000..f9ca7eb
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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.3/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch b/target/linux/bcm53xx/patches-4.3/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
new file mode 100644
index 0000000..dad4f8a
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/351-ARM-BCM5301X-Enable-ChipCommon-UART-on-untested-devi.patch
@@ -0,0 +1,111 @@
+From b49d7bb4825654f81bcee8e219028712811515a5 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
+Date: Mon, 29 Jun 2015 08:11:36 +0200
+Subject: [PATCH] ARM: BCM5301X: Enable ChipCommon UART on untested 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-asus-rt-ac56u.dts | 4 ++++
+ arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts | 4 ++++
+ arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts | 4 ++++
+ arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts | 4 ++++
+ arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts | 4 ++++
+ arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts | 5 +++++
+ arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts | 5 +++++
+ arch/arm/boot/dts/bcm4709-netgear-r8000.dts | 5 +++++
+ 8 files changed, 35 insertions(+)
+
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac56u.dts
+@@ -96,3 +96,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
++++ b/arch/arm/boot/dts/bcm4708-asus-rt-ac68u.dts
+@@ -83,3 +83,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
++++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
+@@ -83,3 +83,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
++++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
+@@ -77,3 +77,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
++++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-900dhp.dts
+@@ -37,3 +37,7 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++};
+--- a/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
++++ b/arch/arm/boot/dts/bcm4709-asus-rt-ac87u.dts
+@@ -65,3 +65,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
++++ b/arch/arm/boot/dts/bcm4709-buffalo-wxr-1900dhp.dts
+@@ -144,3 +144,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r8000.dts
+@@ -127,3 +127,8 @@
+ };
+ };
+ };
++
++&uart0 {
++ status = "okay";
++ clock-frequency = <125000000>;
++};
+--- a/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
++++ b/arch/arm/boot/dts/bcm4709-netgear-r7000.dts
+@@ -104,4 +104,5 @@
+
+ &uart0 {
+ status = "okay";
++ clock-frequency = <125000000>;
+ };
diff --git a/target/linux/bcm53xx/patches-4.3/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch b/target/linux/bcm53xx/patches-4.3/400-mtd-bcm47xxpart-scan-whole-flash-on-ARCH_BCM_5301X.patch
new file mode 100644
index 0000000..ccdb28b
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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.3/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch b/target/linux/bcm53xx/patches-4.3/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch
new file mode 100644
index 0000000..79af785
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/404-mtd-bcm53xxspiflash-new-driver-for-SPI-flahes-on-Bro.patch
@@ -0,0 +1,20 @@
+--- a/drivers/mtd/spi-nor/Kconfig
++++ b/drivers/mtd/spi-nor/Kconfig
+@@ -40,4 +40,10 @@ config SPI_NXP_SPIFI
+ Flash. Enable this option if you have a device with a SPIFI
+ controller and want to access the Flash as a mtd device.
+
++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,3 +1,4 @@
+ obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
+ obj-$(CONFIG_SPI_FSL_QUADSPI) += fsl-quadspi.o
++obj-$(CONFIG_MTD_SPI_BCM53XXSPIFLASH) += bcm53xxspiflash.o
+ obj-$(CONFIG_SPI_NXP_SPIFI) += nxp-spifi.o
diff --git a/target/linux/bcm53xx/patches-4.3/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch b/target/linux/bcm53xx/patches-4.3/500-UBI-Detect-EOF-mark-and-erase-all-remaining-blocks.patch
new file mode 100644
index 0000000..a3d0f75
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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.3/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch b/target/linux/bcm53xx/patches-4.3/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch
new file mode 100644
index 0000000..dfc422e
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/710-b53-add-hacky-CPU-port-fixes-for-devices-not-using-p.patch
@@ -0,0 +1,42 @@
+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,18 @@ 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;
++
++ /*
++ * Workaround for devices using port 8 (connected to the 3rd iface).
++ * For some reason it doesn't work (no packets on eth2).
++ */
++ if (of_machine_is_compatible("netgear,r8000"))
++ sw_dev->cpu_port = 5;
++
+ /* 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.3/800-bcma-use-two-different-initcalls-if-built-in.patch b/target/linux/bcm53xx/patches-4.3/800-bcma-use-two-different-initcalls-if-built-in.patch
new file mode 100644
index 0000000..4e5793b
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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
+@@ -673,13 +673,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) {
+@@ -696,7 +708,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.3/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch b/target/linux/bcm53xx/patches-4.3/901-mtd-bcm47xxpart-workaround-for-Asus-RT-AC87U-asus-pa.patch
new file mode 100644
index 0000000..c1dfa92
--- /dev/null
+++ b/target/linux/bcm53xx/patches-4.3/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) {
diff --git a/target/linux/bcm53xx/profiles/100-Generic.mk b/target/linux/bcm53xx/profiles/100-Generic.mk
new file mode 100644
index 0000000..d7e9005
--- /dev/null
+++ b/target/linux/bcm53xx/profiles/100-Generic.mk
@@ -0,0 +1,19 @@
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Generic
+ NAME:=Broadcom SoC, BCM43xx WiFi (b43, brcmfmac, default)
+ PACKAGES:=kmod-b43 kmod-brcmfmac
+endef
+
+define Profile/Generic/Description
+ Package set compatible with hardware any Broadcom BCM47xx or BCM535x
+ SoC with a ARM CPU like the BCM4707, BCM4708, BCM4709, BCM53010
+endef
+
+$(eval $(call Profile,Generic))
+