[OpenWrt-Devel] [PATCH] bmips: add new target
Álvaro Fernández Rojas
noltari at gmail.com
Fri Oct 9 16:29:44 EDT 2015
Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
target/linux/bmips/Makefile | 25 +
target/linux/bmips/base-files/etc/diag.sh | 66 +
.../bmips/base-files/etc/uci-defaults/02_network | 16 +
target/linux/bmips/base-files/lib/bmips.sh | 76 +
.../base-files/lib/preinit/03_preinit_do_bmips.sh | 12 +
target/linux/bmips/config-4.1 | 222 ++
target/linux/bmips/dts/ar-5381u.dts | 59 +
target/linux/bmips/dts/ar-5387un.dts | 65 +
target/linux/bmips/dts/bcm3368.dtsi | 130 ++
target/linux/bmips/dts/bcm6318.dtsi | 137 ++
target/linux/bmips/dts/bcm63268.dtsi | 159 ++
target/linux/bmips/dts/bcm6328.dtsi | 158 ++
target/linux/bmips/dts/bcm6338.dtsi | 102 +
target/linux/bmips/dts/bcm6345.dtsi | 102 +
target/linux/bmips/dts/bcm6348.dtsi | 127 ++
target/linux/bmips/dts/bcm6358.dtsi | 179 ++
target/linux/bmips/dts/bcm6362.dtsi | 157 ++
target/linux/bmips/dts/bcm6368.dtsi | 179 ++
target/linux/bmips/dts/fast1704.dts | 24 +
target/linux/bmips/dts/hg520v.dts | 67 +
target/linux/bmips/dts/hg556a-a.dts | 138 ++
target/linux/bmips/dts/hg556a-b.dts | 138 ++
target/linux/bmips/dts/hg556a-c.dts | 133 ++
target/linux/bmips/dts/nb4-fxc-r1.dts | 104 +
target/linux/bmips/dts/nb4-ser-r0.dts | 104 +
target/linux/bmips/dts/vg-8050.dts | 125 ++
target/linux/bmips/dts/vr-3025u.dts | 82 +
target/linux/bmips/dts/vr-3025un.dts | 82 +
target/linux/bmips/dts/vr-3032u.dts | 153 ++
target/linux/bmips/dts/wap-5813n.dts | 94 +
target/linux/bmips/image/Makefile | 245 +++
target/linux/bmips/image/lzma-loader/Makefile | 62 +
.../linux/bmips/image/lzma-loader/src/LzmaDecode.c | 584 +++++
.../linux/bmips/image/lzma-loader/src/LzmaDecode.h | 113 +
.../linux/bmips/image/lzma-loader/src/LzmaTypes.h | 45 +
target/linux/bmips/image/lzma-loader/src/Makefile | 86 +
target/linux/bmips/image/lzma-loader/src/board.c | 103 +
target/linux/bmips/image/lzma-loader/src/cache.c | 46 +
target/linux/bmips/image/lzma-loader/src/cache.h | 17 +
.../linux/bmips/image/lzma-loader/src/cacheops.h | 85 +
target/linux/bmips/image/lzma-loader/src/config.h | 31 +
.../linux/bmips/image/lzma-loader/src/cp0regdef.h | 54 +
target/linux/bmips/image/lzma-loader/src/head.S | 118 +
target/linux/bmips/image/lzma-loader/src/loader.c | 175 ++
.../linux/bmips/image/lzma-loader/src/loader.lds | 34 +
.../linux/bmips/image/lzma-loader/src/loader2.lds | 10 +
.../bmips/image/lzma-loader/src/lzma-data.lds | 8 +
target/linux/bmips/image/lzma-loader/src/printf.c | 350 +++
target/linux/bmips/image/lzma-loader/src/printf.h | 18 +
...-Add-support-for-vmlinux.bin-appended-dtb.patch | 112 +
...PS-BMIPS-Build-all-dtbs-if-no-builtin-dtb.patch | 48 +
...PS-Accept-UHI-interface-for-passing-a-dtb.patch | 37 +
...IPS-Add-support-for-Broadcom-BCM97435SVMB.patch | 112 +
.../020-leds-add-BCM6328-LED-driver.patch | 464 ++++
.../021-leds-add-BCM6358-LED-driver.patch | 293 +++
.../030-mtd-nand-add-common-DT-init-code.patch | 111 +
...d-NAND-driver-library-for-Broadcom-STB-NA.patch | 2323 ++++++++++++++++++++
...32-mtd-brcmnand-add-support-for-STB-chips.patch | 68 +
...brcmnand-add-extra-SoC-support-to-library.patch | 167 ++
...d-add-support-for-Broadcom-s-IPROC-family.patch | 173 ++
.../035-mtd-brcmnand-add-BCM63138-support.patch | 137 ++
...rcmnand-remove-double-new-line-from-print.patch | 25 +
...rcmnand-do-not-make-local-variable-static.patch | 26 +
...-brcmnand-drop-unnecessary-initialization.patch | 21 +
...039-mtd-brcmnand-Fix-misuse-of-IS_ENABLED.patch | 38 +
.../patches-4.1/100-BMIPS-select-gpiolib.patch | 10 +
...-support-for-bcm6345-style-periphery-irq-.patch | 455 ++++
...-support-for-bcm6345-style-external-inter.patch | 380 ++++
.../122-MIPS-BMIPS-enable-bcm6345-irq.patch | 12 +
...cm6345-style-peripher-irq-ensure-disabled.patch | 12 +
.../210-MIPS-BMIPS-BCM3368-basic-support.patch | 22 +
.../212-MIPS-BMIPS-BCM6338-basic-support.patch | 22 +
.../213-MIPS-BMIPS-BCM6345-basic-support.patch | 22 +
.../214-MIPS-BMIPS-BCM6348-basic-support.patch | 22 +
.../215-MIPS-BMIPS-BCM6358-basic-support.patch | 22 +
.../216-MIPS-BMIPS-BCM6362-basic-support.patch | 22 +
.../217-MIPS-BMIPS-BCM63268-basic-support.patch | 22 +
.../218-MIPS-BMIPS-BCM6318-basic-support.patch | 22 +
.../patches-4.1/220-MIPS-BMIPS-uart-hacks.patch | 26 +
.../221-MIPS-BMIPS-export-dma_mem_page.patch | 10 +
.../bmips/patches-4.1/222-MIPS-BMIPS-ioremap.patch | 35 +
...Revert-provide-a-plat_post_dma_flush-hook.patch | 12 +
...gpio-add-a-simple-GPIO-driver-for-BCM63XX.patch | 160 ++
...240-mtd-brcmnand-add-polling-mode-support.patch | 136 ++
...8-add-more-configuration-options-and-fix-.patch | 106 +
target/linux/bmips/profiles/00-default.mk | 15 +
target/linux/bmips/profiles/comtrend.mk | 69 +
target/linux/bmips/profiles/huawei.mk | 33 +
target/linux/bmips/profiles/sagem.mk | 15 +
target/linux/bmips/profiles/sfr.mk | 15 +
90 files changed, 11231 insertions(+)
create mode 100644 target/linux/bmips/Makefile
create mode 100644 target/linux/bmips/base-files/etc/diag.sh
create mode 100644 target/linux/bmips/base-files/etc/uci-defaults/02_network
create mode 100644 target/linux/bmips/base-files/lib/bmips.sh
create mode 100644 target/linux/bmips/base-files/lib/preinit/03_preinit_do_bmips.sh
create mode 100644 target/linux/bmips/config-4.1
create mode 100644 target/linux/bmips/dts/ar-5381u.dts
create mode 100644 target/linux/bmips/dts/ar-5387un.dts
create mode 100644 target/linux/bmips/dts/bcm3368.dtsi
create mode 100644 target/linux/bmips/dts/bcm6318.dtsi
create mode 100644 target/linux/bmips/dts/bcm63268.dtsi
create mode 100644 target/linux/bmips/dts/bcm6328.dtsi
create mode 100644 target/linux/bmips/dts/bcm6338.dtsi
create mode 100644 target/linux/bmips/dts/bcm6345.dtsi
create mode 100644 target/linux/bmips/dts/bcm6348.dtsi
create mode 100644 target/linux/bmips/dts/bcm6358.dtsi
create mode 100644 target/linux/bmips/dts/bcm6362.dtsi
create mode 100644 target/linux/bmips/dts/bcm6368.dtsi
create mode 100644 target/linux/bmips/dts/fast1704.dts
create mode 100644 target/linux/bmips/dts/hg520v.dts
create mode 100644 target/linux/bmips/dts/hg556a-a.dts
create mode 100644 target/linux/bmips/dts/hg556a-b.dts
create mode 100644 target/linux/bmips/dts/hg556a-c.dts
create mode 100644 target/linux/bmips/dts/nb4-fxc-r1.dts
create mode 100644 target/linux/bmips/dts/nb4-ser-r0.dts
create mode 100644 target/linux/bmips/dts/vg-8050.dts
create mode 100644 target/linux/bmips/dts/vr-3025u.dts
create mode 100644 target/linux/bmips/dts/vr-3025un.dts
create mode 100644 target/linux/bmips/dts/vr-3032u.dts
create mode 100644 target/linux/bmips/dts/wap-5813n.dts
create mode 100644 target/linux/bmips/image/Makefile
create mode 100644 target/linux/bmips/image/lzma-loader/Makefile
create mode 100644 target/linux/bmips/image/lzma-loader/src/LzmaDecode.c
create mode 100644 target/linux/bmips/image/lzma-loader/src/LzmaDecode.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/LzmaTypes.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/Makefile
create mode 100644 target/linux/bmips/image/lzma-loader/src/board.c
create mode 100644 target/linux/bmips/image/lzma-loader/src/cache.c
create mode 100644 target/linux/bmips/image/lzma-loader/src/cache.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/cacheops.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/config.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/cp0regdef.h
create mode 100644 target/linux/bmips/image/lzma-loader/src/head.S
create mode 100644 target/linux/bmips/image/lzma-loader/src/loader.c
create mode 100644 target/linux/bmips/image/lzma-loader/src/loader.lds
create mode 100644 target/linux/bmips/image/lzma-loader/src/loader2.lds
create mode 100644 target/linux/bmips/image/lzma-loader/src/lzma-data.lds
create mode 100644 target/linux/bmips/image/lzma-loader/src/printf.c
create mode 100644 target/linux/bmips/image/lzma-loader/src/printf.h
create mode 100644 target/linux/bmips/patches-4.1/001-MIPS-Add-support-for-vmlinux.bin-appended-dtb.patch
create mode 100644 target/linux/bmips/patches-4.1/010-MIPS-BMIPS-Build-all-dtbs-if-no-builtin-dtb.patch
create mode 100644 target/linux/bmips/patches-4.1/011-MIPS-BMIPS-Accept-UHI-interface-for-passing-a-dtb.patch
create mode 100644 target/linux/bmips/patches-4.1/012-MIPS-BMIPS-Add-support-for-Broadcom-BCM97435SVMB.patch
create mode 100644 target/linux/bmips/patches-4.1/020-leds-add-BCM6328-LED-driver.patch
create mode 100644 target/linux/bmips/patches-4.1/021-leds-add-BCM6358-LED-driver.patch
create mode 100644 target/linux/bmips/patches-4.1/030-mtd-nand-add-common-DT-init-code.patch
create mode 100644 target/linux/bmips/patches-4.1/031-mtd-nand-add-NAND-driver-library-for-Broadcom-STB-NA.patch
create mode 100644 target/linux/bmips/patches-4.1/032-mtd-brcmnand-add-support-for-STB-chips.patch
create mode 100644 target/linux/bmips/patches-4.1/033-mtd-brcmnand-add-extra-SoC-support-to-library.patch
create mode 100644 target/linux/bmips/patches-4.1/034-mtd-brcmnand-add-support-for-Broadcom-s-IPROC-family.patch
create mode 100644 target/linux/bmips/patches-4.1/035-mtd-brcmnand-add-BCM63138-support.patch
create mode 100644 target/linux/bmips/patches-4.1/036-mtd-brcmnand-remove-double-new-line-from-print.patch
create mode 100644 target/linux/bmips/patches-4.1/037-mtd-brcmnand-do-not-make-local-variable-static.patch
create mode 100644 target/linux/bmips/patches-4.1/038-mtd-brcmnand-drop-unnecessary-initialization.patch
create mode 100644 target/linux/bmips/patches-4.1/039-mtd-brcmnand-Fix-misuse-of-IS_ENABLED.patch
create mode 100644 target/linux/bmips/patches-4.1/100-BMIPS-select-gpiolib.patch
create mode 100644 target/linux/bmips/patches-4.1/120-irqchip-add-support-for-bcm6345-style-periphery-irq-.patch
create mode 100644 target/linux/bmips/patches-4.1/121-irqchip-add-support-for-bcm6345-style-external-inter.patch
create mode 100644 target/linux/bmips/patches-4.1/122-MIPS-BMIPS-enable-bcm6345-irq.patch
create mode 100644 target/linux/bmips/patches-4.1/200-irqchip-bcm6345-style-peripher-irq-ensure-disabled.patch
create mode 100644 target/linux/bmips/patches-4.1/210-MIPS-BMIPS-BCM3368-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/212-MIPS-BMIPS-BCM6338-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/213-MIPS-BMIPS-BCM6345-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/214-MIPS-BMIPS-BCM6348-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/215-MIPS-BMIPS-BCM6358-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/216-MIPS-BMIPS-BCM6362-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/217-MIPS-BMIPS-BCM63268-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/218-MIPS-BMIPS-BCM6318-basic-support.patch
create mode 100644 target/linux/bmips/patches-4.1/220-MIPS-BMIPS-uart-hacks.patch
create mode 100644 target/linux/bmips/patches-4.1/221-MIPS-BMIPS-export-dma_mem_page.patch
create mode 100644 target/linux/bmips/patches-4.1/222-MIPS-BMIPS-ioremap.patch
create mode 100644 target/linux/bmips/patches-4.1/223-MIPS-BMIPS-Revert-provide-a-plat_post_dma_flush-hook.patch
create mode 100644 target/linux/bmips/patches-4.1/230-gpio-add-a-simple-GPIO-driver-for-BCM63XX.patch
create mode 100644 target/linux/bmips/patches-4.1/240-mtd-brcmnand-add-polling-mode-support.patch
create mode 100644 target/linux/bmips/patches-4.1/250-leds-bcm6328-add-more-configuration-options-and-fix-.patch
create mode 100644 target/linux/bmips/profiles/00-default.mk
create mode 100644 target/linux/bmips/profiles/comtrend.mk
create mode 100644 target/linux/bmips/profiles/huawei.mk
create mode 100644 target/linux/bmips/profiles/sagem.mk
create mode 100644 target/linux/bmips/profiles/sfr.mk
diff --git a/target/linux/bmips/Makefile b/target/linux/bmips/Makefile
new file mode 100644
index 0000000..7ce78a9
--- /dev/null
+++ b/target/linux/bmips/Makefile
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+ARCH:=mips
+BOARD:=bmips
+BOARDNAME:=Broadcom Generic BMIPS
+FEATURES:=squashfs usb atm pci pcmcia usbgadget
+KERNEL_PATCHVER:=4.1
+CPU_TYPE:=mips32
+
+include $(INCLUDE_DIR)/target.mk
+
+DEFAULT_PACKAGES += swconfig kmod-input-gpio-keys-polled kmod-button-hotplug
+
+define Target/Description
+ Build firmware images for BCM33xx cable modem chips,
+ BCM63xx DSL chips, and BCM7xxx set-top box chips.
+endef
+
+$(eval $(call BuildTarget))
diff --git a/target/linux/bmips/base-files/etc/diag.sh b/target/linux/bmips/base-files/etc/diag.sh
new file mode 100644
index 0000000..4498da8
--- /dev/null
+++ b/target/linux/bmips/base-files/etc/diag.sh
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+. /lib/functions/leds.sh
+. /lib/bmips.sh
+
+get_status_led() {
+ case $(bmips_board_name) in
+ "ar-5381u")
+ status_led="AR-5381u:green:power"
+ ;;
+ "ar-5387un")
+ status_led="AR-5387un:green:power"
+ ;;
+ "hg520v")
+ status_led="HG520v:green:net"
+ ;;
+ "hg556a-a" |\
+ "hg556a-b" |\
+ "hg556a-c")
+ status_led="HG556a:red:power"
+ ;;
+ "nb4-fxc")
+ status_led="NB4-FXC-r1:green:service"
+ ;;
+ "nb4-ser")
+ status_led="NB4-SER-r0:green:service"
+ ;;
+ "vg-8050")
+ status_led="VG-8050:green:power"
+ ;;
+ "vr-3025u")
+ status_led="VR-3025u:green:power"
+ ;;
+ "vr-3025un")
+ status_led="VR-3025un:green:power"
+ ;;
+ "vr-3032u")
+ status_led="VR-3032u:green:power"
+ ;;
+ "wap-5813n")
+ status_led="WAP-5813n:green:power"
+ ;;
+ esac
+}
+
+set_state() {
+ get_status_led
+
+ 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/bmips/base-files/etc/uci-defaults/02_network b/target/linux/bmips/base-files/etc/uci-defaults/02_network
new file mode 100644
index 0000000..956f355
--- /dev/null
+++ b/target/linux/bmips/base-files/etc/uci-defaults/02_network
@@ -0,0 +1,16 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+[ -e /etc/config/network ] && exit 0
+
+touch /etc/config/network
+
+. /lib/functions/uci-defaults.sh
+
+ucidef_set_interface_loopback
+
+uci commit network
+
+exit 0
diff --git a/target/linux/bmips/base-files/lib/bmips.sh b/target/linux/bmips/base-files/lib/bmips.sh
new file mode 100644
index 0000000..ce23e66
--- /dev/null
+++ b/target/linux/bmips/base-files/lib/bmips.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+BMIPS_BOARD_NAME=
+BMIPS_MODEL=
+
+bmips_board_detect() {
+ local machine
+ local name
+
+ machine=$(awk 'BEGIN{FS="[ \t]+:[ \t]"} /machine/ {print $2}' /proc/cpuinfo)
+
+ case "$machine" in
+ "Comtrend AR-5381u")
+ name="ar-5381u"
+ ;;
+ "Comtrend AR-5387un")
+ name="ar-5387un"
+ ;;
+ "Comtrend VG-8050")
+ name="vg-8050"
+ ;;
+ "Comtrend VR-3025u")
+ name="vr-3025u"
+ ;;
+ "Comtrend VR-3025un")
+ name="vr-3025un"
+ ;;
+ "Comtrend VR-3032u")
+ name="vr-3032u"
+ ;;
+ "Comtrend WAP-5813n")
+ name="wap-5813n"
+ ;;
+ "Huawei EchoLife HG520v")
+ name="hg520v"
+ ;;
+ "Huawei EchoLife HG556a (version A)")
+ name="hg556a-a"
+ ;;
+ "Huawei EchoLife HG556a (version B)")
+ name="hg556a-b"
+ ;;
+ "Huawei EchoLife HG556a (version C)")
+ name="hg556a-c"
+ ;;
+ "SFR Neuf Box 4 (Foxconn)")
+ name="nb4-fxc"
+ ;;
+ "SFR Neuf Box 4 (Sercomm)")
+ name="nb4-ser"
+ ;;
+ *)
+ name="generic"
+ ;;
+ esac
+
+ [ -z "$BMIPS_BOARD_NAME" ] && BMIPS_BOARD_NAME="$name"
+ [ -z "$BMIPS_MODEL" ] && BMIPS_MODEL="$machine"
+
+ [ -e "/tmp/sysinfo/" ] || mkdir -p "/tmp/sysinfo/"
+
+ echo "$BMIPS_BOARD_NAME" > /tmp/sysinfo/board_name
+ echo "$BMIPS_MODEL" > /tmp/sysinfo/model
+}
+
+bmips_board_name() {
+ local name
+
+ [ -f /tmp/sysinfo/board_name ] && name=$(cat /tmp/sysinfo/board_name)
+ [ -z "$name" ] && name="unknown"
+
+ echo "$name"
+}
diff --git a/target/linux/bmips/base-files/lib/preinit/03_preinit_do_bmips.sh b/target/linux/bmips/base-files/lib/preinit/03_preinit_do_bmips.sh
new file mode 100644
index 0000000..3422fa6
--- /dev/null
+++ b/target/linux/bmips/base-files/lib/preinit/03_preinit_do_bmips.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+
+do_bmips() {
+ . /lib/bmips.sh
+
+ bmips_board_detect
+}
+
+boot_hook_add preinit_main do_bmips
diff --git a/target/linux/bmips/config-4.1 b/target/linux/bmips/config-4.1
new file mode 100644
index 0000000..0cfb84a
--- /dev/null
+++ b/target/linux/bmips/config-4.1
@@ -0,0 +1,222 @@
+CONFIG_ARCH_BINFMT_ELF_STATE=y
+CONFIG_ARCH_DISCARD_MEMBLOCK=y
+CONFIG_ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE=y
+CONFIG_ARCH_HAS_ELF_RANDOMIZE=y
+# CONFIG_ARCH_HAS_GCOV_PROFILE_ALL is not set
+# CONFIG_ARCH_HAS_SG_CHAIN is not set
+CONFIG_ARCH_HAVE_CUSTOM_GPIO_H=y
+CONFIG_ARCH_HIBERNATION_POSSIBLE=y
+CONFIG_ARCH_MIGHT_HAVE_PC_PARPORT=y
+CONFIG_ARCH_MIGHT_HAVE_PC_SERIO=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_ARCH_WANT_IPC_PARSE_VERSION=y
+CONFIG_BCM6345_EXT_IRQ=y
+CONFIG_BCM6345_PERIPH_IRQ=y
+CONFIG_BCM7038_L1_IRQ=y
+CONFIG_BCM7120_L2_IRQ=y
+CONFIG_BMIPS_GENERIC=y
+CONFIG_BOARD_SCACHE=y
+CONFIG_BRCMSTB_L2_IRQ=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_CEVT_R4K=y
+CONFIG_CLKDEV_LOOKUP=y
+CONFIG_CLONE_BACKWARDS=y
+CONFIG_CMDLINE="earlycon noinitrd"
+CONFIG_CMDLINE_BOOL=y
+# CONFIG_CMDLINE_OVERRIDE is not set
+CONFIG_COMMON_CLK=y
+CONFIG_CPU_BIG_ENDIAN=y
+CONFIG_CPU_BMIPS=y
+CONFIG_CPU_BMIPS32_3300=y
+CONFIG_CPU_BMIPS4350=y
+CONFIG_CPU_BMIPS4380=y
+CONFIG_CPU_BMIPS5000=y
+CONFIG_CPU_GENERIC_DUMP_TLB=y
+CONFIG_CPU_HAS_PREFETCH=y
+CONFIG_CPU_HAS_SYNC=y
+# CONFIG_CPU_LITTLE_ENDIAN is not set
+CONFIG_CPU_MIPS32=y
+CONFIG_CPU_NEEDS_NO_SMARTMIPS_OR_MICROMIPS=y
+CONFIG_CPU_R4K_CACHE_TLB=y
+CONFIG_CPU_R4K_FPU=y
+CONFIG_CPU_RMAP=y
+CONFIG_CPU_SUPPORTS_32BIT_KERNEL=y
+CONFIG_CPU_SUPPORTS_HIGHMEM=y
+CONFIG_CRASH_DUMP=y
+CONFIG_CSRC_R4K=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DMA_NONCOHERENT=y
+CONFIG_DTC=y
+# CONFIG_DT_BCM93384WVG is not set
+# CONFIG_DT_BCM93384WVG_VIPER is not set
+# CONFIG_DT_BCM96368MVWG is not set
+# CONFIG_DT_BCM97125CBMB is not set
+# CONFIG_DT_BCM97346DBSMB is not set
+# CONFIG_DT_BCM97358SVMB is not set
+# CONFIG_DT_BCM97360SVMB is not set
+# CONFIG_DT_BCM97362SVMB is not set
+# CONFIG_DT_BCM97420C is not set
+# CONFIG_DT_BCM97425SVMB is not set
+# CONFIG_DT_BCM97435SVMB is not set
+# CONFIG_DT_BCM9EJTAGPRB is not set
+CONFIG_DT_NONE=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_GENERIC_ATOMIC64=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_IO=y
+CONFIG_GENERIC_IRQ_CHIP=y
+CONFIG_GENERIC_IRQ_SHOW=y
+CONFIG_GENERIC_PCI_IOMAP=y
+CONFIG_GENERIC_SCHED_CLOCK=y
+CONFIG_GENERIC_SMP_IDLE_THREAD=y
+CONFIG_GPIOLIB=y
+CONFIG_GPIO_BCM63XX=y
+CONFIG_GPIO_DEVRES=y
+CONFIG_GPIO_GENERIC=y
+CONFIG_GPIO_SYSFS=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_BITREVERSE is not set
+CONFIG_HAVE_ARCH_JUMP_LABEL=y
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_HAVE_ARCH_SECCOMP_FILTER=y
+CONFIG_HAVE_ARCH_TRACEHOOK=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_DEBUG_STACKOVERFLOW=y
+CONFIG_HAVE_DMA_API_DEBUG=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_HAVE_DMA_CONTIGUOUS=y
+CONFIG_HAVE_DYNAMIC_FTRACE=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_MEMBLOCK=y
+CONFIG_HAVE_MEMBLOCK_NODE_MAP=y
+CONFIG_HAVE_MOD_ARCH_SPECIFIC=y
+CONFIG_HAVE_NET_DSA=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_HAVE_SYSCALL_TRACEPOINTS=y
+CONFIG_HAVE_VIRT_CPU_ACCOUNTING_GEN=y
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_IMAGE_CMDLINE_HACK=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_IP_PIMSM_V1=y
+CONFIG_IP_PIMSM_V2=y
+CONFIG_IRQCHIP=y
+CONFIG_IRQ_CPU=y
+CONFIG_IRQ_DOMAIN=y
+CONFIG_IRQ_FORCED_THREADING=y
+CONFIG_IRQ_WORK=y
+CONFIG_LEDS_BCM6328=y
+CONFIG_LEDS_BCM6358=y
+CONFIG_LEDS_GPIO=y
+CONFIG_LIBFDT=y
+CONFIG_MDIO_BOARDINFO=y
+CONFIG_MIPS=y
+CONFIG_MIPS_CPU_SCACHE=y
+# CONFIG_MIPS_HUGE_TLB_SUPPORT is not set
+CONFIG_MIPS_L1_CACHE_SHIFT=7
+CONFIG_MIPS_L1_CACHE_SHIFT_6=y
+CONFIG_MIPS_L1_CACHE_SHIFT_7=y
+# CONFIG_MIPS_MACHINE is not set
+# CONFIG_MIPS_NO_APPENDED_DTB is not set
+CONFIG_MIPS_O32_FP64_SUPPORT=y
+CONFIG_MIPS_RAW_APPENDED_DTB=y
+CONFIG_MODULES_USE_ELF_REL=y
+CONFIG_MODULE_FORCE_LOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_BE_BYTE_SWAP=y
+# CONFIG_MTD_CFI_GEOMETRY is not set
+# CONFIG_MTD_CFI_NOSWAP is not set
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BRCMNAND=y
+CONFIG_MTD_NAND_ECC=y
+CONFIG_MTD_PHYSMAP=y
+CONFIG_NEED_DMA_MAP_STATE=y
+CONFIG_NET_FLOW_LIMIT=y
+CONFIG_NO_EXCEPT_FILL=y
+# CONFIG_NO_IOPORT_MAP is not set
+CONFIG_NR_CPUS=2
+CONFIG_OF=y
+CONFIG_OF_ADDRESS=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_PAGEFLAGS_EXTENDED=y
+CONFIG_PERF_USE_VMALLOC=y
+CONFIG_PGTABLE_LEVELS=2
+CONFIG_PHYLIB=y
+CONFIG_PHYSICAL_START=0x80010000
+CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
+CONFIG_PROC_VMCORE=y
+CONFIG_RCU_STALL_COMMON=y
+CONFIG_RELAY=y
+CONFIG_RFS_ACCEL=y
+CONFIG_RPS=y
+CONFIG_SCHED_HRTICK=y
+# CONFIG_SCSI_DMA is not set
+CONFIG_SERIAL_BCM63XX=y
+CONFIG_SERIAL_BCM63XX_CONSOLE=y
+CONFIG_SMP=y
+CONFIG_SMP_UP=y
+CONFIG_SPI=y
+CONFIG_SPI_BITBANG=y
+CONFIG_SPI_GPIO=y
+CONFIG_SPI_MASTER=y
+CONFIG_SQUASHFS_EMBEDDED=y
+CONFIG_SRCU=y
+CONFIG_STOP_MACHINE=y
+CONFIG_SWAP_IO_SPACE=y
+CONFIG_SWCONFIG=y
+CONFIG_SYNC_R4K=y
+CONFIG_SYSCTL_EXCEPTION_TRACE=y
+CONFIG_SYS_HAS_CPU_BMIPS=y
+CONFIG_SYS_HAS_CPU_BMIPS32_3300=y
+CONFIG_SYS_HAS_CPU_BMIPS4350=y
+CONFIG_SYS_HAS_CPU_BMIPS4380=y
+CONFIG_SYS_HAS_CPU_BMIPS5000=y
+CONFIG_SYS_SUPPORTS_32BIT_KERNEL=y
+CONFIG_SYS_SUPPORTS_ARBIT_HZ=y
+CONFIG_SYS_SUPPORTS_BIG_ENDIAN=y
+CONFIG_SYS_SUPPORTS_HIGHMEM=y
+CONFIG_SYS_SUPPORTS_HOTPLUG_CPU=y
+CONFIG_SYS_SUPPORTS_LITTLE_ENDIAN=y
+CONFIG_SYS_SUPPORTS_SMP=y
+CONFIG_TICK_CPU_ACCOUNTING=y
+CONFIG_TREE_RCU=y
+CONFIG_USB_EHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_EHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_OHCI_BIG_ENDIAN_DESC=y
+CONFIG_USB_OHCI_BIG_ENDIAN_MMIO=y
+CONFIG_USB_SUPPORT=y
+CONFIG_USE_OF=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+CONFIG_WEAK_ORDERING=y
+CONFIG_XPS=y
+CONFIG_ZONE_DMA_FLAG=0
diff --git a/target/linux/bmips/dts/ar-5381u.dts b/target/linux/bmips/dts/ar-5381u.dts
new file mode 100644
index 0000000..9d72109
--- /dev/null
+++ b/target/linux/bmips/dts/ar-5381u.dts
@@ -0,0 +1,59 @@
+/dts-v1/;
+
+#include "bcm6328.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,ar-5381u", "brcm,bcm6328";
+ model = "Comtrend AR-5381u";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio0 23 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+
+ alarm_red at 2 {
+ reg = <2>;
+ active-low;
+ label = "AR-5381u:red:alarm";
+ };
+ inet_green at 3 {
+ reg = <3>;
+ active-low;
+ label = "AR-5381u:green:inet";
+ };
+ power_green at 4 {
+ reg = <4>;
+ active-low;
+ label = "AR-5381u:green:power";
+ default-state = "on";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/ar-5387un.dts b/target/linux/bmips/dts/ar-5387un.dts
new file mode 100644
index 0000000..c421996
--- /dev/null
+++ b/target/linux/bmips/dts/ar-5387un.dts
@@ -0,0 +1,65 @@
+/dts-v1/;
+
+#include "bcm6328.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,ar-5387un", "brcm,bcm6328";
+ model = "Comtrend AR-5387un";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio0 23 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+
+ inet_red at 1 {
+ reg = <1>;
+ label = "AR-5387un:red:inet";
+ };
+ power_red at 4 {
+ reg = <4>;
+ label = "AR-5387un:red:power";
+ };
+ inet_green at 7 {
+ reg = <7>;
+ label = "AR-5387un:green:inet";
+ };
+ power_green at 8 {
+ reg = <8>;
+ label = "AR-5387un:green:power";
+ default-state = "on";
+ };
+ dsl_green at 11 {
+ reg = <11>;
+ active-low;
+ label = "AR-5387un:green:dsl";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/bcm3368.dtsi b/target/linux/bmips/dts/bcm3368.dtsi
new file mode 100644
index 0000000..fc1b76e
--- /dev/null
+++ b/target/linux/bmips/dts/bcm3368.dtsi
@@ -0,0 +1,130 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm3368";
+
+ aliases {
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ pflash = &pflash;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <150000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pflash: nor at 1e000000 {
+ compatible = "cfi-flash";
+ reg = <0x1e000000 0x2000000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: interrupt-controller at fff8c00c {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0xfffe000c 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ ext_intc0: interrupt-controller at fff8c014 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0xfffe0014 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <24>, <25>, <26>, <27>;
+ };
+
+ gpio1: gpio-controller at fff8c080 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfff8c080 4>, <0xfff8c088 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <8>;
+ };
+
+ gpio0: gpio-controller at fff8c084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfff8c084 4>, <0xfff8c08c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart0: serial at fff8c100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfff8c100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ uart1: serial at fff8c120 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfff8c120 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <3>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6318.dtsi b/target/linux/bmips/dts/bcm6318.dtsi
new file mode 100644
index 0000000..9fdd3a5
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6318.dtsi
@@ -0,0 +1,137 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6318";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ leds0 = &leds0;
+ ohci0 = &ohci0;
+ uart0 = &uart0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <160000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips3300", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ ext_intc: interrupt-controller at 10000018 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x10000018 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <24>, <25>, <26>, <27>;
+ };
+
+ periph_intc: interrupt-controller at 10000020 {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0x10000020 0x20>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ gpio1: gpio-controller at 10000080 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000080 4>, <0x10000088 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <18>;
+ };
+
+ gpio0: gpio-controller at 10000084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000084 4>, <0x1000008c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart0: serial at 10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <28>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ leds0: led-controller at 10000200 {
+ compatible = "brcm,bcm6328-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10000200 0x24>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at 10005000 {
+ compatible = "brcm,bcm6328-ehci", "generic-ehci";
+ reg = <0x10005000 0x100>;
+ num-ports = <1>;
+ big-endian;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <42>;
+
+ status = "disabled";
+ };
+
+ ohci0: usb at 10005100 {
+ compatible = "brcm,bcm6328-ohci", "generic-ohci";
+ reg = <0x10005100 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <41>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm63268.dtsi b/target/linux/bmips/dts/bcm63268.dtsi
new file mode 100644
index 0000000..ebc4cd2
--- /dev/null
+++ b/target/linux/bmips/dts/bcm63268.dtsi
@@ -0,0 +1,159 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm63268";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ leds0 = &leds0;
+ nflash = &nflash;
+ ohci0 = &ohci0;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <200000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ ext_intc: interrupt-controller at 10000018 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x10000018 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <44>, <45>, <46>, <47>;
+ };
+
+ periph_intc: interrupt-controller at 10000020 {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0x10000020 0x20>,
+ <0x10000040 0x20>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ gpio1: gpio-controller at 100000c0 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x100000c0 4>, <0x100000c8 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <20>;
+ };
+
+ gpio0: gpio-controller at 100000c4 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x100000c4 4>, <0x100000cc 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart0: serial at 10000180 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000180 0x18>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <5>;
+ clocks = <&periph_clk>;
+ status = "disabled";
+ };
+
+ uart1: serial at 100001a0 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x100001a0 0x18>;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <34>;
+ clocks = <&periph_clk>;
+ status = "disabled";
+ };
+
+ nflash: nand at 10000200 {
+ compatible = "brcm,brcmnand-v4.0", "brcm,brcmnand";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10000200 0x400>, <0x10000600 0x200>;
+ reg-names = "nand", "nand-cache";
+ brcm,cmd-poll;
+
+ status = "disabled";
+ };
+
+ leds0: led-controller at 10001900 {
+ compatible = "brcm,bcm6328-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10001900 0x24>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at 10002500 {
+ compatible = "brcm,bcm63268-ehci", "generic-ehci";
+ reg = <0x10002500 0x100>;
+ num-ports = <1>;
+ big-endian;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <10>;
+ status = "disabled";
+ };
+
+ ohci0: usb at 10002600 {
+ compatible = "brcm,bcm63268-ohci", "generic-ohci";
+ reg = <0x10002600 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+ interrupt-parent = <&periph_intc>;
+ interrupts = <9>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6328.dtsi b/target/linux/bmips/dts/bcm6328.dtsi
new file mode 100644
index 0000000..fd46877
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6328.dtsi
@@ -0,0 +1,158 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6328";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ leds0 = &leds0;
+ ohci0 = &ohci0;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <160000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ ext_intc: interrupt-controller at 10000018 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x10000018 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <24>, <25>, <26>, <27>;
+ };
+
+ periph_intc: interrupt-controller at 10000020 {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0x10000020 0x10>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ timer: timer at 10000040 {
+ compatible = "syscon";
+ reg = <0x10000040 0x2c>;
+ little-endian;
+ };
+
+ reboot {
+ compatible = "syscon-reboot";
+ regmap = <&timer>;
+ offset = <0x28>;
+ mask = <0x1>;
+ };
+
+ gpio0: gpio-controller at 10000084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000084 4>, <0x1000008c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart0: serial at 10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <28>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ uart1: serial at 10000120 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000120 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <39>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ leds0: led-controller at 10000800 {
+ compatible = "brcm,bcm6328-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10000800 0x24>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at 10002500 {
+ compatible = "brcm,bcm6328-ehci", "generic-ehci";
+ reg = <0x10002500 0x100>;
+ num-ports = <1>;
+ big-endian;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <42>;
+
+ status = "disabled";
+ };
+
+ ohci0: usb at 10002600 {
+ compatible = "brcm,bcm6328-ohci", "generic-ohci";
+ reg = <0x10002600 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <41>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6338.dtsi b/target/linux/bmips/dts/bcm6338.dtsi
new file mode 100644
index 0000000..be2c3dd
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6338.dtsi
@@ -0,0 +1,102 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6338";
+
+ aliases {
+ gpio0 = &gpio0;
+ pflash = &pflash;
+ uart0 = &uart0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <120000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips3300", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pflash: nor at 1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: interrupt-controller at fffe000c {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0xfffe000c 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ ext_intc: interrupt-controller at fffe0014 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0xfffe0014 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <3>, <4>, <5>, <6>;
+ };
+
+ uart0: serial at fffe0300 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfffe0300 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ gpio0: gpio-controller at fffe0404 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0404 4>, <0xfffe040c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <8>;
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6345.dtsi b/target/linux/bmips/dts/bcm6345.dtsi
new file mode 100644
index 0000000..2d97b77
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6345.dtsi
@@ -0,0 +1,102 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6345";
+
+ aliases {
+ gpio0 = &gpio0;
+ pflash = &pflash;
+ uart0 = &uart0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <70000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips32", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pflash: nor at 1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: interrupt-controller at fffe000c {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0xfffe000c 0x9>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ ext_intc: interrupt-controller at fffe0014 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0xfffe0014 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <3>, <4>, <5>, <6>;
+ };
+
+ uart0: serial at fffe0300 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfffe0300 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ gpio0: gpio-controller at fffe0404 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0404 4>, <0xfffe0408 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <16>;
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6348.dtsi b/target/linux/bmips/dts/bcm6348.dtsi
new file mode 100644
index 0000000..82ac37a
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6348.dtsi
@@ -0,0 +1,127 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6348";
+
+ aliases {
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ ohci0 = &ohci0;
+ pflash = &pflash;
+ uart0 = &uart0;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <120000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips3300", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pflash: nor at 1fc00000 {
+ compatible = "cfi-flash";
+ reg = <0x1fc00000 0x400000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: interrupt-controller at fffe000c {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0xfffe000c 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>;
+ };
+
+ ext_intc: interrupt-controller at fffe0014 {
+ compatible = "brcm,bcm6348-ext-intc";
+ reg = <0xfffe0014 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <3>, <4>, <5>, <6>;
+
+ brcm,field-width = <5>;
+ };
+
+ uart0: serial at fffe0300 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfffe0300 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ gpio1: gpio-controller at fffe0400 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0400 4>, <0xfffe0408 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <5>;
+ };
+
+ gpio0: gpio-controller at fffe0404 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0404 4>, <0xfffe040c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ ohci0: usb at fffe1b00 {
+ compatible = "brcm,bcm6348-ohci", "generic-ohci";
+ reg = <0xfffe1b00 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <12>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6358.dtsi b/target/linux/bmips/dts/bcm6358.dtsi
new file mode 100644
index 0000000..452ef35
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6358.dtsi
@@ -0,0 +1,179 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6358";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ les0 = &leds0;
+ ohci0 = &ohci0;
+ pflash = &pflash;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <150000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ pflash: nor at 1e000000 {
+ compatible = "cfi-flash";
+ reg = <0x1e000000 0x2000000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ periph_intc: interrupt-controller at fffe000c {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0xfffe000c 0x8>,
+ <0xfffe0038 0x8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ ext_intc0: interrupt-controller at fffe0014 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0xfffe0014 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <25>, <26>, <27>, <28>;
+ };
+
+ ext_intc1: interrupt-controller at fffe001c {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0xfffe001c 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <20>, <21>;
+ };
+
+ gpio1: gpio-controller at fffe0080 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0080 4>, <0xfffe0088 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <8>;
+ };
+
+ gpio0: gpio-controller at fffe0084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0xfffe0084 4>, <0xfffe008c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ leds0: led-controller at fffe00d0 {
+ compatible = "brcm,bcm6358-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfffe00d0 0x8>;
+
+ status = "disabled";
+ };
+
+ uart0: serial at fffe0100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfffe0100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ uart1: serial at fffe0120 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0xfffe0120 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <3>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at fffe1300 {
+ compatible = "brcm,bcm6358-ehci", "generic-ehci";
+ reg = <0xfffe1300 0x100>;
+ num-ports = <1>;
+ big-endian;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <10>;
+
+ status = "disabled";
+ };
+
+ ohci0: usb at fffe1400 {
+ compatible = "brcm,bcm6358-ohci", "generic-ohci";
+ reg = <0xfffe1400 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6362.dtsi b/target/linux/bmips/dts/bcm6362.dtsi
new file mode 100644
index 0000000..0b0e8ec
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6362.dtsi
@@ -0,0 +1,157 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6362";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ leds0 = &leds0;
+ ohci0 = &ohci0;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <200000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ ext_intc: interrupt-controller at 10000018 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x10000018 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <40>, <41>, <42>, <43>;
+ };
+
+ periph_intc: interrupt-controller at 10000020 {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0x10000020 0x10>,
+ <0x10000030 0x10>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ gpio1: gpio-controller at 10000080 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000080 4>, <0x10000088 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <16>;
+ };
+
+ gpio0: gpio-controller at 10000084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000084 4>, <0x1000008c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ uart0: serial at 10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <3>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ uart1: serial at 10000120 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000120 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <4>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ leds0: led-controller at 10001900 {
+ compatible = "brcm,bcm6328-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10001900 0x24>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at 10002500 {
+ compatible = "brcm,bcm6362-ehci", "generic-ehci";
+ reg = <0x10002500 0x100>;
+ num-ports = <1>;
+ big-endian;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <10>;
+
+ status = "disabled";
+ };
+
+ ohci0: usb at 10002600 {
+ compatible = "brcm,bcm6362-ohci", "generic-ohci";
+ reg = <0x10002600 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <9>;
+
+ status = "disabled";
+ };
+ };
+};
diff --git a/target/linux/bmips/dts/bcm6368.dtsi b/target/linux/bmips/dts/bcm6368.dtsi
new file mode 100644
index 0000000..35ab8ad
--- /dev/null
+++ b/target/linux/bmips/dts/bcm6368.dtsi
@@ -0,0 +1,179 @@
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "brcm,bcm6368";
+
+ aliases {
+ ehci0 = &ehci0;
+ gpio0 = &gpio0;
+ gpio1 = &gpio1;
+ leds0 = &leds0;
+ ohci0 = &ohci0;
+ pflash = &pflash;
+ uart0 = &uart0;
+ uart1 = &uart1;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mips-hpt-frequency = <200000000>;
+
+ cpu at 0 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <0>;
+ };
+
+ cpu at 1 {
+ compatible = "brcm,bmips4350", "mips,mips4Kc";
+ device_type = "cpu";
+ reg = <1>;
+ };
+ };
+
+ clocks {
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ };
+ };
+
+ cpu_intc: cpu_intc {
+ #address-cells = <0>;
+ compatible = "mti,cpu-interrupt-controller";
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+
+ ubus {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ compatible = "simple-bus";
+ ranges;
+
+ ext_intc0: interrupt-controller at 10000018 {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x10000018 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <20>, <21>, <22>, <23>;
+ };
+
+ ext_intc1: interrupt-controller at 1000001c {
+ compatible = "brcm,bcm6345-ext-intc";
+ reg = <0x1000001c 0x4>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <24>, <25>;
+ };
+
+ periph_intc: interrupt-controller at 10000020 {
+ compatible = "brcm,bcm6345-periph-intc";
+ reg = <0x10000020 0x10>,
+ <0x10000030 0x10>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ interrupt-parent = <&cpu_intc>;
+ interrupts = <2>, <3>;
+ };
+
+ gpio1: gpio-controller at 10000080 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000080 4>, <0x10000088 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ngpios = <6>;
+ };
+
+ gpio0: gpio-controller at 10000084 {
+ compatible = "brcm,bcm6345-gpio";
+ reg = <0x10000084 4>, <0x1000008c 4>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ leds0: led-controller at 100000d0 {
+ compatible = "brcm,bcm6358-leds";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x100000d0 0x8>;
+
+ status = "disabled";
+ };
+
+ uart0: serial at 10000100 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000100 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <2>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ uart1: serial at 10000120 {
+ compatible = "brcm,bcm6345-uart";
+ reg = <0x10000120 0x18>;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <3>;
+
+ clocks = <&periph_clk>;
+
+ status = "disabled";
+ };
+
+ ehci0: usb at 10001500 {
+ compatible = "brcm,bcm6368-ehci", "generic-ehci";
+ reg = <0x10001500 0x100>;
+ num-ports = <1>;
+ big-endian;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <7>;
+
+ status = "disabled";
+ };
+
+ ohci0: usb at 10001600 {
+ compatible = "brcm,bcm6368-ohci", "generic-ohci";
+ reg = <0x10001600 0x100>;
+ num-ports = <1>;
+ big-endian;
+ no-big-frame-no;
+
+ interrupt-parent = <&periph_intc>;
+ interrupts = <5>;
+
+ status = "disabled";
+ };
+ };
+
+ pflash: nor at 18000000 {
+ compatible = "cfi-flash";
+ reg = <0x18000000 0x2000000>;
+ bank-width = <2>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ status = "disabled";
+ };
+};
diff --git a/target/linux/bmips/dts/fast1704.dts b/target/linux/bmips/dts/fast1704.dts
new file mode 100644
index 0000000..9d56e50
--- /dev/null
+++ b/target/linux/bmips/dts/fast1704.dts
@@ -0,0 +1,24 @@
+/dts-v1/;
+
+#include "bcm6338.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "sagem,f at st1704", "brcm,bcm6338";
+ model = "Sagem F at ST1704";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x01000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/hg520v.dts b/target/linux/bmips/dts/hg520v.dts
new file mode 100644
index 0000000..f6c6630
--- /dev/null
+++ b/target/linux/bmips/dts/hg520v.dts
@@ -0,0 +1,67 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "huawei,hg520v", "brcm,bcm6358";
+ model = "Huawei EchoLife HG520v";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x02000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio1 5 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ inet_green {
+ label = "HG520v:green:net";
+ gpios = <&gpio1 0 1>;
+ };
+ };
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "CFE";
+ reg = <0x000000 0x010000>;
+ read-only;
+ };
+
+ linux at 10000 {
+ label = "linux";
+ reg = <0x010000 0x3e0000>;
+ };
+
+ nvram at 3f0000 {
+ label = "nvram";
+ reg = <0x3f0000 0x010000>;
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/hg556a-a.dts b/target/linux/bmips/dts/hg556a-a.dts
new file mode 100644
index 0000000..cf6b6b3
--- /dev/null
+++ b/target/linux/bmips/dts/hg556a-a.dts
@@ -0,0 +1,138 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "huawei,hg556a-a", "brcm,bcm6358";
+ model = "Huawei EchoLife HG556a (version A)";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ help {
+ label = "help";
+ gpios = <&gpio0 8 1>;
+ linux,code = <KEY_HELP>;
+ };
+ wlan {
+ label = "wlan";
+ gpios = <&gpio0 9 1>;
+ linux,code = <KEY_WLAN>;
+ };
+ restart {
+ label = "restart";
+ gpios = <&gpio0 10 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio0 11 1>;
+ linux,code = <KEY_CONFIG>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ message_red {
+ label = "HG556a:red:message";
+ gpios = <&gpio0 0 1>;
+ };
+ hspa_red {
+ label = "HG556a:red:hspa";
+ gpios = <&gpio0 1 1>;
+ };
+ dsl_red {
+ label = "HG556a:red:dsl";
+ gpios = <&gpio0 2 1>;
+ };
+ power_red {
+ label = "HG556a:red:power";
+ gpios = <&gpio0 3 1>;
+ default-state = "on";
+ };
+ all_red {
+ label = "HG556a:red:all";
+ gpios = <&gpio0 6 1>;
+ default-state = "on";
+ };
+ lan1_green {
+ label = "HG556a:green:lan1";
+ gpios = <&gpio0 12 1>;
+ };
+ lan1_red {
+ label = "HG556a:red:lan1";
+ gpios = <&gpio0 13 1>;
+ };
+ lan2_green {
+ label = "HG556a:green:lan2";
+ gpios = <&gpio0 15 1>;
+ };
+ lan2_red {
+ label = "HG556a:red:lan2";
+ gpios = <&gpio0 22 1>;
+ };
+ lan3_green {
+ label = "HG556a:green:lan3";
+ gpios = <&gpio0 23 1>;
+ };
+ lan3_red {
+ label = "HG556a:red:lan3";
+ gpios = <&gpio0 26 1>;
+ };
+ lan4_green {
+ label = "HG556a:green:lan4";
+ gpios = <&gpio0 27 1>;
+ };
+ lan4_red {
+ label = "HG556a:red:lan4";
+ gpios = <&gpio0 28 1>;
+ };
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "CFE";
+ reg = <0x000000 0x020000>;
+ read-only;
+ };
+
+ linux at 20000 {
+ label = "linux";
+ reg = <0x020000 0xec0000>;
+ };
+
+ cal_data at ee0000 {
+ label = "cal_data";
+ reg = <0xee0000 0x100000>;
+ read-only;
+ };
+
+ nvram at fe0000 {
+ label = "nvram";
+ reg = <0xfe0000 0x020000>;
+ };
+};
diff --git a/target/linux/bmips/dts/hg556a-b.dts b/target/linux/bmips/dts/hg556a-b.dts
new file mode 100644
index 0000000..0b7ac55
--- /dev/null
+++ b/target/linux/bmips/dts/hg556a-b.dts
@@ -0,0 +1,138 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "huawei,hg556a-b", "brcm,bcm6358";
+ model = "Huawei EchoLife HG556a (version B)";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ help {
+ label = "help";
+ gpios = <&gpio0 8 1>;
+ linux,code = <KEY_HELP>;
+ };
+ wlan {
+ label = "wlan";
+ gpios = <&gpio0 9 1>;
+ linux,code = <KEY_WLAN>;
+ };
+ restart {
+ label = "restart";
+ gpios = <&gpio0 10 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio0 11 1>;
+ linux,code = <KEY_CONFIG>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ message_red {
+ label = "HG556a:red:message";
+ gpios = <&gpio0 0 1>;
+ };
+ hspa_red {
+ label = "HG556a:red:hspa";
+ gpios = <&gpio0 1 1>;
+ };
+ dsl_red {
+ label = "HG556a:red:dsl";
+ gpios = <&gpio0 2 1>;
+ };
+ power_red {
+ label = "HG556a:red:power";
+ gpios = <&gpio0 3 1>;
+ default-state = "on";
+ };
+ all_red {
+ label = "HG556a:red:all";
+ gpios = <&gpio0 6 1>;
+ default-state = "on";
+ };
+ lan1_green {
+ label = "HG556a:green:lan1";
+ gpios = <&gpio0 12 1>;
+ };
+ lan1_red {
+ label = "HG556a:red:lan1";
+ gpios = <&gpio0 13 1>;
+ };
+ lan2_green {
+ label = "HG556a:green:lan2";
+ gpios = <&gpio0 15 1>;
+ };
+ lan2_red {
+ label = "HG556a:red:lan2";
+ gpios = <&gpio0 22 1>;
+ };
+ lan3_green {
+ label = "HG556a:green:lan3";
+ gpios = <&gpio0 23 1>;
+ };
+ lan3_red {
+ label = "HG556a:red:lan3";
+ gpios = <&gpio0 26 1>;
+ };
+ lan4_green {
+ label = "HG556a:green:lan4";
+ gpios = <&gpio0 27 1>;
+ };
+ lan4_red {
+ label = "HG556a:red:lan4";
+ gpios = <&gpio0 28 1>;
+ };
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "CFE";
+ reg = <0x000000 0x020000>;
+ read-only;
+ };
+
+ linux at 20000 {
+ label = "linux";
+ reg = <0x020000 0xec0000>;
+ };
+
+ cal_data at ee0000 {
+ label = "cal_data";
+ reg = <0xee0000 0x100000>;
+ read-only;
+ };
+
+ nvram at fe0000 {
+ label = "nvram";
+ reg = <0xfe0000 0x020000>;
+ };
+};
diff --git a/target/linux/bmips/dts/hg556a-c.dts b/target/linux/bmips/dts/hg556a-c.dts
new file mode 100644
index 0000000..1ad5a84
--- /dev/null
+++ b/target/linux/bmips/dts/hg556a-c.dts
@@ -0,0 +1,133 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "huawei,hg556a-c", "brcm,bcm6358";
+ model = "Huawei EchoLife HG556a (version C)";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ help {
+ label = "help";
+ gpios = <&gpio0 8 1>;
+ linux,code = <KEY_HELP>;
+ };
+ wlan {
+ label = "wlan";
+ gpios = <&gpio0 9 1>;
+ linux,code = <KEY_WLAN>;
+ };
+ restart {
+ label = "restart";
+ gpios = <&gpio0 10 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio0 11 1>;
+ linux,code = <KEY_CONFIG>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ lan1_green {
+ label = "HG556a:green:lan1";
+ gpios = <&gpio0 0 1>;
+ };
+ lan2_green {
+ label = "HG556a:green:lan2";
+ gpios = <&gpio0 1 1>;
+ };
+ dsl_red {
+ label = "HG556a:red:dsl";
+ gpios = <&gpio0 2 1>;
+ };
+ power_red {
+ label = "HG556a:red:power";
+ gpios = <&gpio0 3 1>;
+ default-state = "on";
+ };
+ message_red {
+ label = "HG556a:red:message";
+ gpios = <&gpio0 12 1>;
+ };
+ lan1_red {
+ label = "HG556a:red:lan1";
+ gpios = <&gpio0 13 1>;
+ };
+ hspa_red {
+ label = "HG556a:red:hspa";
+ gpios = <&gpio0 15 1>;
+ };
+ lan2_red {
+ label = "HG556a:red:lan2";
+ gpios = <&gpio0 22 1>;
+ };
+ lan3_green {
+ label = "HG556a:green:lan3";
+ gpios = <&gpio0 23 1>;
+ };
+ lan3_red {
+ label = "HG556a:red:lan3";
+ gpios = <&gpio0 26 1>;
+ };
+ lan4_green {
+ label = "HG556a:green:lan4";
+ gpios = <&gpio0 27 1>;
+ };
+ lan4_red {
+ label = "HG556a:red:lan4";
+ gpios = <&gpio0 28 1>;
+ };
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "CFE";
+ reg = <0x000000 0x020000>;
+ read-only;
+ };
+
+ linux at 20000 {
+ label = "linux";
+ reg = <0x020000 0xec0000>;
+ };
+
+ cal_data at ee0000 {
+ label = "cal_data";
+ reg = <0xee0000 0x100000>;
+ read-only;
+ };
+
+ nvram at fe0000 {
+ label = "nvram";
+ reg = <0xfe0000 0x020000>;
+ };
+};
diff --git a/target/linux/bmips/dts/nb4-fxc-r1.dts b/target/linux/bmips/dts/nb4-fxc-r1.dts
new file mode 100644
index 0000000..2cad77c
--- /dev/null
+++ b/target/linux/bmips/dts/nb4-fxc-r1.dts
@@ -0,0 +1,104 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "SFR Neuf Box 4 (Foxconn)";
+ compatible = "sfr,nb4-fxc-r1", "brcm,bcm6358";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x02000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ service {
+ label = "service";
+ gpios = <&gpio0 27 1>;
+ linux,code = <BTN_0>;
+ };
+ clip {
+ label = "clip";
+ gpios = <&gpio0 31 1>;
+ linux,code = <BTN_1>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio1 2 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ wps {
+ label = "wps";
+ gpios = <&gpio1 5 1>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ traffic_white {
+ label = "NB4-FXC-r1:white:traffic";
+ gpios = <&gpio0 2 0>;
+ };
+ service_blue {
+ label = "NB4-FXC-r1:blue:service";
+ gpios = <&gpio0 4 0>;
+ };
+ wifi_white {
+ label = "NB4-FXC-r1:white:wifi";
+ gpios = <&gpio0 15 0>;
+ };
+ service_red {
+ label = "NB4-FXC-r1:red:service";
+ gpios = <&gpio0 29 0>;
+ };
+ service_green {
+ label = "NB4-FXC-r1:green:service";
+ gpios = <&gpio0 30 0>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+ brcm,clk-div = <1>;
+
+ alarm_white at 0 {
+ reg = <0>;
+ active-low;
+ label = "NB4-FXC-r1:white:alarm";
+ };
+ tv_white at 2 {
+ reg = <2>;
+ active-low;
+ label = "NB4-FXC-r1:white:tv";
+ };
+ tel_white at 3 {
+ reg = <3>;
+ active-low;
+ label = "NB4-FXC-r1:white:tel";
+ };
+ adsl_white at 4 {
+ reg = <4>;
+ active-low;
+ label = "NB4-FXC-r0:white:adsl";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/nb4-ser-r0.dts b/target/linux/bmips/dts/nb4-ser-r0.dts
new file mode 100644
index 0000000..0c1111f
--- /dev/null
+++ b/target/linux/bmips/dts/nb4-ser-r0.dts
@@ -0,0 +1,104 @@
+/dts-v1/;
+
+#include "bcm6358.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "SFR Neuf Box 4 (Sercomm)";
+ compatible = "sfr,nb4-ser-r0", "brcm,bcm6358";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x02000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ service {
+ label = "service";
+ gpios = <&gpio0 27 1>;
+ linux,code = <BTN_0>;
+ };
+ clip {
+ label = "clip";
+ gpios = <&gpio0 31 1>;
+ linux,code = <BTN_1>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio1 2 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ wps {
+ label = "wps";
+ gpios = <&gpio1 5 1>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ traffic_white {
+ label = "NB4-SER-r0:white:traffic";
+ gpios = <&gpio0 2 1>;
+ };
+ service_blue {
+ label = "NB4-SER-r0:blue:service";
+ gpios = <&gpio0 4 1>;
+ };
+ wifi_white {
+ label = "NB4-SER-r0:white:wifi";
+ gpios = <&gpio0 15 1>;
+ };
+ service_red {
+ label = "NB4-SER-r0:red:service";
+ gpios = <&gpio0 29 1>;
+ };
+ service_green {
+ label = "NB4-SER-r0:green:service";
+ gpios = <&gpio0 30 1>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+ brcm,clk-div = <1>;
+
+ alarm_white at 0 {
+ reg = <0>;
+ active-low;
+ label = "NB4-SER-r0:white:alarm";
+ };
+ tv_white at 2 {
+ reg = <2>;
+ active-low;
+ label = "NB4-SER-r0:white:tv";
+ };
+ tel_white at 3 {
+ reg = <3>;
+ active-low;
+ label = "NB4-SER-r0:white:tel";
+ };
+ adsl_white at 4 {
+ reg = <4>;
+ active-low;
+ label = "NB4-SER-r0:white:adsl";
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/vg-8050.dts b/target/linux/bmips/dts/vg-8050.dts
new file mode 100644
index 0000000..0a355b5
--- /dev/null
+++ b/target/linux/bmips/dts/vg-8050.dts
@@ -0,0 +1,125 @@
+/dts-v1/;
+
+#include "bcm63268.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,vg-8050", "brcm,bcm63268";
+ model = "Comtrend VG-8050";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x08000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio1 0 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ wps {
+ label = "wps";
+ gpios = <&gpio1 1 1>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+ brcm,serial-leds;
+ brcm,serial-dat-low;
+ brcm,serial-shift-inv;
+
+ inet_red at 2 {
+ reg = <2>;
+ active-low;
+ label = "VG-8050:red:inet";
+ };
+ power_red at 3 {
+ reg = <3>;
+ active-low;
+ label = "VG-8050:red:power";
+ };
+ power_green at 6 {
+ reg = <6>;
+ active-low;
+ label = "VG-8050:green:power";
+ default-state = "on";
+ };
+ wps_green at 7 {
+ reg = <7>;
+ active-low;
+ label = "VG-8050:green:wps";
+ };
+ inet_green at 8 {
+ reg = <8>;
+ active-low;
+ label = "VG-8050:green:inet";
+ };
+ voip_green at 10 {
+ reg = <10>;
+ active-low;
+ label = "VG-8050:green:voip";
+ };
+ voip_red at 12 {
+ reg = <12>;
+ active-low;
+ label = "VG-8050:red:voip";
+ };
+ wps_red at 14 {
+ reg = <14>;
+ active-low;
+ label = "VG-8050:red:wps";
+ };
+};
+
+&nflash {
+ status = "ok";
+
+ nandcs at 0 {
+ compatible = "brcm,nandcs";
+ #size-cells = <1>;
+ #address-cells = <1>;
+ reg = <0>;
+ nand-ecc-step-size = <512>;
+ nand-ecc-strength = <15>;
+ nand-on-flash-bbt;
+ brcm,nand-oob-sector-size = <64>;
+
+ cfe at 0 {
+ label = "cfe";
+ reg = <0x0000000 0x0020000>;
+ read-only;
+ };
+
+ linux at 20000 {
+ label = "linux";
+ reg = <0x0020000 0x7ae0000>;
+ read-only;
+ };
+
+ data at 7b00000 {
+ label = "data";
+ reg = <0x7b00000 0x0500000>;
+ read-only;
+ };
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/vr-3025u.dts b/target/linux/bmips/dts/vr-3025u.dts
new file mode 100644
index 0000000..e06f3d0
--- /dev/null
+++ b/target/linux/bmips/dts/vr-3025u.dts
@@ -0,0 +1,82 @@
+/dts-v1/;
+
+#include "bcm6368.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,vr-3025u", "brcm,bcm6368";
+ model = "Comtrend VR-3025u";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio1 2 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ dsl_green {
+ label = "VR-3025u:green:dsl";
+ gpios = <&gpio0 2 1>;
+ };
+ inet_green {
+ label = "VR-3025u:green:inet";
+ gpios = <&gpio0 5 0>;
+ };
+ power_green {
+ label = "VR-3025u:green:power";
+ gpios = <&gpio0 22 0>;
+ default-state = "on";
+ };
+ power_red {
+ label = "VR-3025u:red:power";
+ gpios = <&gpio0 24 0>;
+ };
+ inet_red {
+ label = "VR-3025u:red:inet";
+ gpios = <&gpio0 31 0>;
+ };
+ };
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "cfe";
+ reg = <0x0000000 0x0020000>;
+ read-only;
+ };
+ linux at 20000 {
+ label = "linux";
+ reg = <0x0020000 0x1fc0000>;
+ };
+ nvram at 1fe0000 {
+ label = "nvram";
+ reg = <0x1fe0000 0x020000>;
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/vr-3025un.dts b/target/linux/bmips/dts/vr-3025un.dts
new file mode 100644
index 0000000..9a3b1df
--- /dev/null
+++ b/target/linux/bmips/dts/vr-3025un.dts
@@ -0,0 +1,82 @@
+/dts-v1/;
+
+#include "bcm6368.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,vr-3025un", "brcm,bcm6368";
+ model = "Comtrend VR-3025un";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio1 2 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ dsl_green {
+ label = "VR-3025un:green:dsl";
+ gpios = <&gpio0 2 1>;
+ };
+ inet_green {
+ label = "VR-3025un:green:inet";
+ gpios = <&gpio0 5 0>;
+ };
+ power_green {
+ label = "VR-3025un:green:power";
+ gpios = <&gpio0 22 0>;
+ default-state = "on";
+ };
+ power_red {
+ label = "VR-3025un:red:power";
+ gpios = <&gpio0 24 0>;
+ };
+ inet_red {
+ label = "VR-3025un:red:inet";
+ gpios = <&gpio0 31 0>;
+ };
+ };
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "cfe";
+ reg = <0x000000 0x010000>;
+ read-only;
+ };
+ linux at 10000 {
+ label = "linux";
+ reg = <0x010000 0x7e0000>;
+ };
+ nvram at 7f0000 {
+ label = "nvram";
+ reg = <0x7f0000 0x010000>;
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/vr-3032u.dts b/target/linux/bmips/dts/vr-3032u.dts
new file mode 100644
index 0000000..e43f1ac
--- /dev/null
+++ b/target/linux/bmips/dts/vr-3032u.dts
@@ -0,0 +1,153 @@
+/dts-v1/;
+
+#include "bcm63268.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,vr-3032u", "brcm,bcm63268";
+ model = "Comtrend VR-3032u";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ reset {
+ label = "reset";
+ gpios = <&gpio1 0 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ wps {
+ label = "wps";
+ gpios = <&gpio1 1 1>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+};
+
+&leds0 {
+ status = "ok";
+ brcm,serial-leds;
+ brcm,serial-dat-low;
+ brcm,serial-shift-inv;
+
+ gphy0_spd0 at 0 {
+ reg = <0>;
+ brcm,hardware-controlled;
+ brcm,link-signal-sources = <0>;
+ };
+ gphy0_spd1 at 1 {
+ reg = <1>;
+ brcm,hardware-controlled;
+ brcm,link-signal-sources = <1>;
+ };
+ inet_red at 2 {
+ reg = <2>;
+ active-low;
+ label = "VR-3032u:red:inet";
+ };
+ dsl_green at 3 {
+ reg = <3>;
+ active-low;
+ label = "VR-3032u:green:dsl";
+ };
+ usb_green at 4 {
+ reg = <4>;
+ active-low;
+ label = "VR-3032u:green:usb";
+ };
+ wps_green at 7 {
+ reg = <7>;
+ active-low;
+ label = "VR-3032u:green:wps";
+ };
+ inet_green at 8 {
+ reg = <8>;
+ active-low;
+ label = "VR-3032u:green:inet";
+ };
+ ephy0_act at 9 {
+ reg = <9>;
+ brcm,hardware-controlled;
+ };
+ ephy1_act at 10 {
+ reg = <10>;
+ brcm,hardware-controlled;
+ };
+ ephy2_act at 11 {
+ reg = <11>;
+ brcm,hardware-controlled;
+ };
+ gphy0_act at 12 {
+ reg = <12>;
+ brcm,hardware-controlled;
+ };
+ ephy0_spd at 13 {
+ reg = <13>;
+ brcm,hardware-controlled;
+ };
+ ephy1_spd at 14 {
+ reg = <14>;
+ brcm,hardware-controlled;
+ };
+ ephy2_spd at 15 {
+ reg = <15>;
+ brcm,hardware-controlled;
+ };
+ power_green at 20 {
+ reg = <20>;
+ active-low;
+ label = "VR-3032u:green:power";
+ default-state = "on";
+ };
+};
+
+&nflash {
+ status = "ok";
+
+ nandcs at 0 {
+ compatible = "brcm,nandcs";
+ #size-cells = <1>;
+ #address-cells = <1>;
+ reg = <0>;
+ nand-ecc-step-size = <512>;
+ nand-ecc-strength = <15>;
+ nand-on-flash-bbt;
+ brcm,nand-oob-sector-size = <64>;
+
+ cfe at 0 {
+ label = "cfe";
+ reg = <0x0000000 0x0020000>;
+ read-only;
+ };
+
+ linux at 20000 {
+ label = "linux";
+ reg = <0x0020000 0x7ae0000>;
+ read-only;
+ };
+
+ data at 7b00000 {
+ label = "data";
+ reg = <0x7b00000 0x0500000>;
+ read-only;
+ };
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/dts/wap-5813n.dts b/target/linux/bmips/dts/wap-5813n.dts
new file mode 100644
index 0000000..6ace557
--- /dev/null
+++ b/target/linux/bmips/dts/wap-5813n.dts
@@ -0,0 +1,94 @@
+/dts-v1/;
+
+#include "bcm6368.dtsi"
+
+#include <dt-bindings/input/input.h>
+
+/ {
+ compatible = "comtrend,wap-5813n", "brcm,bcm6368";
+ model = "Comtrend WAP-5813n";
+
+ memory at 0 {
+ device_type = "memory";
+ reg = <0x00000000 0x04000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ stdout-path = &uart0;
+ };
+
+ gpio-keys-polled {
+ compatible = "gpio-keys-polled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <20>;
+ debounce-interval = <60>;
+
+ wlan {
+ label = "wlan";
+ gpios = <&gpio1 0 1>;
+ linux,code = <KEY_WLAN>;
+ };
+ reset {
+ label = "reset";
+ gpios = <&gpio1 2 1>;
+ linux,code = <KEY_RESTART>;
+ };
+ wps {
+ label = "wps";
+ gpios = <&gpio1 3 1>;
+ linux,code = <KEY_WPS_BUTTON>;
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ inet_green {
+ label = "WAP-5813n:green:inet";
+ gpios = <&gpio0 5 0>;
+ };
+ power_green {
+ label = "WAP-5813n:green:power";
+ gpios = <&gpio0 22 0>;
+ default-state = "on";
+ };
+ wps_green {
+ label = "WAP-5813n:green:wps";
+ gpios = <&gpio0 23 1>;
+ };
+ power_red {
+ label = "WAP-5813n:red:power";
+ gpios = <&gpio0 24 0>;
+ };
+ inet_red {
+ label = "WAP-5813n:red:inet";
+ gpios = <&gpio0 31 0>;
+ };
+ };
+};
+
+&pflash {
+ status = "ok";
+
+ cfe at 0 {
+ label = "CFE";
+ reg = <0x000000 0x010000>;
+ read-only;
+ };
+
+ linux at 10000 {
+ label = "linux";
+ reg = <0x010000 0x7e0000>;
+ };
+
+ nvram at 7f0000 {
+ label = "nvram";
+ reg = <0x7f0000 0x010000>;
+ };
+};
+
+&uart0 {
+ status = "ok";
+};
diff --git a/target/linux/bmips/image/Makefile b/target/linux/bmips/image/Makefile
new file mode 100644
index 0000000..bfb8395
--- /dev/null
+++ b/target/linux/bmips/image/Makefile
@@ -0,0 +1,245 @@
+#
+# Copyright (C) 2015 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
+
+LOADADDR = 0x80010000 # RAM start + 64K
+KERNEL_ENTRY = $(LOADADDR) # Newer kernels add a jmp to the kernel_entry at the start of the binary
+LOADER_ENTRY = 0x80a00000 # RAM start + 10M, for relocate
+RAMSIZE = 0x02000000 # 32MB
+LZMA_TEXT_START = 0x81800000 # 32MB - 8MB
+
+LOADER_MAKEOPTS= \
+ KDIR=$(KDIR) \
+ LOADADDR=$(LOADADDR) \
+ KERNEL_ENTRY=$(KERNEL_ENTRY) \
+ RAMSIZE=$(RAMSIZE) \
+ LZMA_TEXT_START=$(LZMA_TEXT_START) \
+
+RELOCATE_MAKEOPTS= \
+ CACHELINE_SIZE=16 \
+ KERNEL_ADDR=$(KERNEL_ENTRY) \
+ CROSS_COMPILE=$(TARGET_CROSS) \
+ LZMA_TEXT_START=$(LOADER_ENTRY)
+
+define Build/Compile
+ rm -rf $(KDIR)/relocate
+ $(CP) ../../generic/image/relocate $(KDIR)
+ $(MAKE) -C $(KDIR)/relocate $(RELOCATE_MAKEOPTS)
+endef
+
+### Kernel scripts ###
+define Build/append-dtb
+ $(call Image/BuildDTB,../dts/$(DEVICE_DTS).dts,$@.dtb)
+ cat $@.dtb >> $@
+endef
+
+define Build/gzip
+ gzip -9 -c $@ > $@.gz
+ mv $@.gz $@
+endef
+
+define Build/hcs-initramfs
+ $(STAGING_DIR_HOST)/bin/hcsmakeimage --magic_bytes=$(HCS_MAGIC_BYTES) \
+ --rev_maj=$(HCS_REV_MAJ) --rev_min=$(HCS_REV_MIN) --input_file=$@ \
+ --output_file=$@.hcs --ldaddress=$(LOADADDR)
+ mv $@.hcs $@
+endef
+
+define Build/loader-lzma
+ rm -rf $@.src
+ $(MAKE) -C lzma-loader \
+ $(LOADER_MAKEOPTS) \
+ PKG_BUILD_DIR="$@.src" \
+ TARGET_DIR="$(dir $@)" \
+ LOADER_DATA="$@" \
+ LOADER_NAME="$(notdir $@)" \
+ compile loader.$(1)
+ mv "$@.$(1)" "$@"
+ rm -rf $@.src
+endef
+
+define Build/lzma
+ # CFE is a LZMA nazi! It took me hours to find out the parameters!
+ # Also I think lzma has a bug cause it generates different output depending on
+ # if you use stdin / stdout or not. Use files instead of stdio here, cause
+ # otherwise CFE will complain and not boot the image.
+ $(STAGING_DIR_HOST)/bin/lzma e $@ -d22 -fb64 -a1 $@.lzma
+ mv $@.lzma $@
+endef
+
+define Build/lzma-cfe
+ # Strip out the length, CFE doesn't like this
+ dd if=$@ of=$@.lzma.cfe bs=5 count=1
+ dd if=$@ of=$@.lzma.cfe ibs=13 obs=5 skip=1 seek=1 conv=notrunc
+ mv $@.lzma.cfe $@
+endef
+
+define Build/relocate-kernel
+ # CFE only allows ~4 MiB for the uncompressed kernels, but uncompressed
+ # kernel might get larger than that, so let CFE unpack and load at a
+ # higher address and make the kernel relocate itself to the expected
+ # location.
+ ( \
+ dd if=$(KDIR)/relocate/loader.bin bs=32 conv=sync && \
+ perl -e '@s = stat("$@"); print pack("N", @s[7])' && \
+ cat $@ \
+ ) > $@.relocate
+ mv $@.relocate $@
+endef
+
+### Image scripts ###
+define rootfspad/jffs2-128k
+--align-rootfs
+endef
+define rootfspad/jffs2-64k
+--align-rootfs
+endef
+define rootfspad/squashfs
+endef
+
+define Image/LimitName16
+$(shell expr substr "$(1)" 1 16)
+endef
+
+define Image/FileSystemStrip
+$(subst root.,,$(notdir $(1)))
+endef
+
+define Build/cfe-bin
+ $(STAGING_DIR_HOST)/bin/imagetag -i $(word 1,$^) -f $(word 2,$^) \
+ --output $@ --boardid $(CFE_BOARD_ID) --chipid $(CFE_CHIP_ID) \
+ --entry $(LOADER_ENTRY) --load-addr $(LOADER_ENTRY) \
+ --info1 "$(call Image/LimitName16,$(DEVICE_NAME))" \
+ --info2 "$(call Image/FileSystemStrip,$(word 2,$^))" \
+ $(call rootfspad/$(call Image/FileSystemStrip,$(word 2,$^))) \
+ $(CFE_EXTRAS) $(1)
+endef
+
+# Shared device definition: applies to every defined device
+define Device/Default
+ PROFILES = Default $$(DEVICE_PROFILE)
+ KERNEL_INITRAMFS_IMAGE = $$(KERNEL_INITRAMFS_PREFIX).elf
+ DEVICE_PROFILE :=
+ DEVICE_NAME :=
+ DEVICE_DTS :=
+endef
+DEVICE_VARS += DEVICE_PROFILE DEVICE_NAME DEVICE_DTS
+
+# BCM33xx HCS devices: only generates ramdisks (unsupported bin images)
+define Device/bcm33xxHcsRamdisk
+ KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | loader-lzma bin | hcs-initramfs
+ IMAGES :=
+ HCS_MAGIC_BYTES :=
+ HCS_REV_MIN :=
+ HCS_REV_MAJ :=
+endef
+DEVICE_VARS += HCS_MAGIC_BYTES HCS_REV_MIN HCS_REV_MAJ
+
+# Shared BCM63xx CFE device definitios
+define Device/bcm63xxCfeCommon
+ FILESYSTEMS := squashfs jffs2-64k jffs2-128k
+ KERNEL := kernel-bin | append-dtb | relocate-kernel | lzma | lzma-cfe
+ KERNEL_INITRAMFS := kernel-bin | append-dtb | lzma | loader-lzma elf
+endef
+
+# BCM63xx CFE devices: only generates ramdisks (unsupported bin images)
+define Device/bcm63xxCfeRamdisk
+ $(Device/bcm63xxCfeCommon)
+ IMAGES :=
+endef
+
+# BCM63xx CFE devices: both ramdisks and parallel/spi bin images
+# New versions of CFE bootloader compatible with imagetag
+define Device/bcm63xxCfe
+ $(Device/bcm63xxCfeCommon)
+ IMAGES := cfe.bin
+ IMAGE/cfe.bin := cfe-bin
+ CFE_BOARD_ID :=
+ CFE_CHIP_ID :=
+ CFE_EXTRAS :=
+endef
+DEVICE_VARS += CFE_BOARD_ID CFE_CHIP_ID CFE_EXTRAS
+
+# $(2) = image name
+# $(3) = dts
+# $(4) = hcs magic bytes
+# $(5) = hcs rev min
+# $(6) = hcs rev major
+define bcm33xxHcsRamdisk
+ define Device/$(2)
+ $$(Device/bcm33xxHcsRamdisk)
+ DEVICE_PROFILE := $(1)
+ DEVICE_NAME := $(2)
+ DEVICE_DTS := $(3)
+ HCS_MAGIC_BYTES := $(4)
+ HCS_REV_MIN := $(5)
+ HCS_REV_MAJ := $(6)
+ endef
+ TARGET_DEVICES += $(2)
+endef
+
+# $(1) = profile
+# $(2) = image name
+# $(3) = dts
+define bcm63xxCfeRamdisk
+ define Device/$(2)
+ $$(Device/bcm63xxCfeRamdisk)
+ DEVICE_PROFILE := $(1)
+ DEVICE_NAME := $(2)
+ DEVICE_DTS := $(3)
+ endef
+ TARGET_DEVICES += $(2)
+endef
+
+# $(1) = profile
+# $(2) = image name
+# $(3) = dts
+# $(4) = cfe board name
+# $(5) = cfe chip id
+# $(6) = cfe additional options
+define bcm63xxCfe
+ define Device/$(2)
+ $$(Device/bcm63xxCfe)
+ DEVICE_PROFILE := $(1)
+ DEVICE_NAME := $(2)
+ DEVICE_DTS := $(3)
+ CFE_BOARD_ID := $(4)
+ CFE_CHIP_ID := $(5)
+ CFE_EXTRAS := $(6)
+ endef
+ TARGET_DEVICES += $(2)
+endef
+
+### Devices ###
+# Comtrend AR-5381u
+$(eval $(call bcm63xxCfe,AR5381u,AR-5381u,ar-5381u,96328A-1241N,6328,--pad 8))
+# Comtrend AR-5387un
+$(eval $(call bcm63xxCfe,AR5387un,AR-5387un,ar-5387un,96328A-1441N1,6328,--pad 8))
+# Comtrend VG-8050
+$(eval $(call bcm63xxCfeRamdisk,VG8050,VG-8050,vg-8050,963169P-1861N5,63268))
+# Comtrend VR-3025u
+$(eval $(call bcm63xxCfe,VR3025u,VR-3025u,vr-3025u,96368M-1541N,6368,--pad 16 --image-offset 0x20000 --block-size 0x20000))
+# Comtrend VR-3025un
+$(eval $(call bcm63xxCfe,VR3025un,VR-3025un,vr-3025un,96368M-1341N,6368,--pad 4))
+# Comtrend VR-3032u
+$(eval $(call bcm63xxCfeRamdisk,VR3032u,VR-3032u,vr-3032u,963168M-1841N1,63268))
+# Comtrend WAP-5813n
+$(eval $(call bcm63xxCfe,WAP5813n,WAP-5813n,wap-5813n,96369R-1231N,6368,--pad 4))
+# Huawei HG520v
+$(eval $(call bcm63xxCfe,HG520v,HG520v,hg520v,HW6358GW_B,6358,--rsa-signature "EchoLife_HG520v"))
+# Huawei HG556a
+$(eval $(call bcm63xxCfe,HG556a_AB,HG556a_A,hg556a-a,HW556,6358,--rsa-signature "EchoLife_HG556a" --image-offset 0x20000 --block-size 0x10000 --tag-version 8))
+$(eval $(call bcm63xxCfe,HG556a_AB,HG556a_B,hg556a-b,HW556,6358,--rsa-signature "EchoLife_HG556a" --image-offset 0x20000 --block-size 0x20000 --tag-version 8))
+$(eval $(call bcm63xxCfe,HG556a_C,HG556a_C,hg556a-c,HW556,6358,--rsa-signature "EchoLife_HG556a" --image-offset 0x20000 --block-size 0x20000 --tag-version 8))
+# SFR Neufbox 4
+$(eval $(call bcm63xxCfe,Neufbox4,NEUFBOX4-SER,nb4-ser-r0,96358VW,6358,--rsa-signature "OpenWRT-$(REVISION)"))
+$(eval $(call bcm63xxCfe,Neufbox4,NEUFBOX4-FXC,nb4-fxc-r1,96358VW,6358,--rsa-signature "OpenWRT-$(REVISION)"))
+# Sagem F at ST1704
+$(eval $(call bcm63xxCfe,FAST1704,F at ST1704,fast1704,F at ST1704,6338))
+
+$(eval $(call BuildImage))
diff --git a/target/linux/bmips/image/lzma-loader/Makefile b/target/linux/bmips/image/lzma-loader/Makefile
new file mode 100644
index 0000000..8d36691
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/Makefile
@@ -0,0 +1,62 @@
+#
+# Copyright (C) 2011 OpenWrt.org
+# Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+LZMA_TEXT_START := 0x80a00000
+LOADER := loader.bin
+LOADER_NAME := $(basename $(notdir $(LOADER)))
+LOADER_DATA :=
+TARGET_DIR :=
+FLASH_OFFS :=
+FLASH_MAX :=
+
+ifeq ($(TARGET_DIR),)
+TARGET_DIR := $(KDIR)
+endif
+
+LOADER_BIN := $(TARGET_DIR)/$(LOADER_NAME).bin
+LOADER_GZ := $(TARGET_DIR)/$(LOADER_NAME).gz
+LOADER_ELF := $(TARGET_DIR)/$(LOADER_NAME).elf
+
+PKG_NAME := lzma-loader
+PKG_BUILD_DIR := $(KDIR)/$(PKG_NAME)
+
+.PHONY : loader-compile loader.bin loader.elf loader.gz
+
+$(PKG_BUILD_DIR)/.prepared:
+ mkdir $(PKG_BUILD_DIR)
+ $(CP) ./src/* $(PKG_BUILD_DIR)/
+ touch $@
+
+loader-compile: $(PKG_BUILD_DIR)/.prepared
+ $(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)" \
+ LZMA_TEXT_START=$(LZMA_TEXT_START) \
+ LOADER_DATA=$(LOADER_DATA) \
+ FLASH_OFFS=$(FLASH_OFFS) \
+ FLASH_MAX=$(FLASH_MAX) \
+ clean all
+
+loader.gz: $(PKG_BUILD_DIR)/loader.bin
+ gzip -nc9 $< > $(LOADER_GZ)
+
+loader.elf: $(PKG_BUILD_DIR)/loader.elf
+ $(CP) $< $(LOADER_ELF)
+
+loader.bin: $(PKG_BUILD_DIR)/loader.bin
+ $(CP) $< $(LOADER_BIN)
+
+download:
+prepare: $(PKG_BUILD_DIR)/.prepared
+compile: loader-compile
+
+install:
+
+clean:
+ rm -rf $(PKG_BUILD_DIR)
+
diff --git a/target/linux/bmips/image/lzma-loader/src/LzmaDecode.c b/target/linux/bmips/image/lzma-loader/src/LzmaDecode.c
new file mode 100644
index 0000000..cb83453
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/LzmaDecode.c
@@ -0,0 +1,584 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder (optimized for Speed version)
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this Code, expressly permits you to
+ statically or dynamically link your Code (or bind by name) to the
+ interfaces of this file without subjecting your linked Code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include "LzmaDecode.h"
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_READ_BYTE (*Buffer++)
+
+#define RC_INIT2 Code = 0; Range = 0xFFFFFFFF; \
+ { int i; for(i = 0; i < 5; i++) { RC_TEST; Code = (Code << 8) | RC_READ_BYTE; }}
+
+#ifdef _LZMA_IN_CB
+
+#define RC_TEST { if (Buffer == BufferLim) \
+ { SizeT size; int result = InCallback->Read(InCallback, &Buffer, &size); if (result != LZMA_RESULT_OK) return result; \
+ BufferLim = Buffer + size; if (size == 0) return LZMA_RESULT_DATA_ERROR; }}
+
+#define RC_INIT Buffer = BufferLim = 0; RC_INIT2
+
+#else
+
+#define RC_TEST { if (Buffer == BufferLim) return LZMA_RESULT_DATA_ERROR; }
+
+#define RC_INIT(buffer, bufferSize) Buffer = buffer; BufferLim = buffer + bufferSize; RC_INIT2
+
+#endif
+
+#define RC_NORMALIZE if (Range < kTopValue) { RC_TEST; Range <<= 8; Code = (Code << 8) | RC_READ_BYTE; }
+
+#define IfBit0(p) RC_NORMALIZE; bound = (Range >> kNumBitModelTotalBits) * *(p); if (Code < bound)
+#define UpdateBit0(p) Range = bound; *(p) += (kBitModelTotal - *(p)) >> kNumMoveBits;
+#define UpdateBit1(p) Range -= bound; Code -= bound; *(p) -= (*(p)) >> kNumMoveBits;
+
+#define RC_GET_BIT2(p, mi, A0, A1) IfBit0(p) \
+ { UpdateBit0(p); mi <<= 1; A0; } else \
+ { UpdateBit1(p); mi = (mi + mi) + 1; A1; }
+
+#define RC_GET_BIT(p, mi) RC_GET_BIT2(p, mi, ; , ;)
+
+#define RangeDecoderBitTreeDecode(probs, numLevels, res) \
+ { int i = numLevels; res = 1; \
+ do { CProb *p = probs + res; RC_GET_BIT(p, res) } while(--i != 0); \
+ res -= (1 << numLevels); }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size)
+{
+ unsigned char prop0;
+ if (size < LZMA_PROPERTIES_SIZE)
+ return LZMA_RESULT_DATA_ERROR;
+ prop0 = propsData[0];
+ if (prop0 >= (9 * 5 * 5))
+ return LZMA_RESULT_DATA_ERROR;
+ {
+ for (propsRes->pb = 0; prop0 >= (9 * 5); propsRes->pb++, prop0 -= (9 * 5));
+ for (propsRes->lp = 0; prop0 >= 9; propsRes->lp++, prop0 -= 9);
+ propsRes->lc = prop0;
+ /*
+ unsigned char remainder = (unsigned char)(prop0 / 9);
+ propsRes->lc = prop0 % 9;
+ propsRes->pb = remainder / 5;
+ propsRes->lp = remainder % 5;
+ */
+ }
+
+ #ifdef _LZMA_OUT_READ
+ {
+ int i;
+ propsRes->DictionarySize = 0;
+ for (i = 0; i < 4; i++)
+ propsRes->DictionarySize += (UInt32)(propsData[1 + i]) << (i * 8);
+ if (propsRes->DictionarySize == 0)
+ propsRes->DictionarySize = 1;
+ }
+ #endif
+ return LZMA_RESULT_OK;
+}
+
+#define kLzmaStreamWasFinishedId (-1)
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed)
+{
+ CProb *p = vs->Probs;
+ SizeT nowPos = 0;
+ Byte previousByte = 0;
+ UInt32 posStateMask = (1 << (vs->Properties.pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->Properties.lp)) - 1;
+ int lc = vs->Properties.lc;
+
+ #ifdef _LZMA_OUT_READ
+
+ UInt32 Range = vs->Range;
+ UInt32 Code = vs->Code;
+ #ifdef _LZMA_IN_CB
+ const Byte *Buffer = vs->Buffer;
+ const Byte *BufferLim = vs->BufferLim;
+ #else
+ const Byte *Buffer = inStream;
+ const Byte *BufferLim = inStream + inSize;
+ #endif
+ int state = vs->State;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+ UInt32 distanceLimit = vs->DistanceLimit;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->Properties.DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ Byte tempDictionary[4];
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+ if (len == kLzmaStreamWasFinishedId)
+ return LZMA_RESULT_OK;
+
+ if (dictionarySize == 0)
+ {
+ dictionary = tempDictionary;
+ dictionarySize = 1;
+ tempDictionary[0] = vs->TempDictionary[0];
+ }
+
+ if (len == kLzmaNeedInitId)
+ {
+ {
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ UInt32 i;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ rep0 = rep1 = rep2 = rep3 = 1;
+ state = 0;
+ globalPos = 0;
+ distanceLimit = 0;
+ dictionaryPos = 0;
+ dictionary[dictionarySize - 1] = 0;
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+ }
+ len = 0;
+ }
+ while(len != 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+
+ #else /* if !_LZMA_OUT_READ */
+
+ int state = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ int len = 0;
+ const Byte *Buffer;
+ const Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+
+ #ifndef _LZMA_IN_CB
+ *inSizeProcessed = 0;
+ #endif
+ *outSizeProcessed = 0;
+
+ {
+ UInt32 i;
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + vs->Properties.lp));
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ }
+
+ #ifdef _LZMA_IN_CB
+ RC_INIT;
+ #else
+ RC_INIT(inStream, inSize);
+ #endif
+
+ #endif /* _LZMA_OUT_READ */
+
+ while(nowPos < outSize)
+ {
+ CProb *prob;
+ UInt32 bound;
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+
+ prob = p + IsMatch + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ int symbol = 1;
+ UpdateBit0(prob)
+ prob = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state >= kNumLitStates)
+ {
+ int matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ do
+ {
+ int bit;
+ CProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & 0x100);
+ probLit = prob + 0x100 + bit + symbol;
+ RC_GET_BIT2(probLit, symbol, if (bit != 0) break, if (bit == 0) break)
+ }
+ while (symbol < 0x100);
+ }
+ while (symbol < 0x100)
+ {
+ CProb *probLit = prob + symbol;
+ RC_GET_BIT(probLit, symbol)
+ }
+ previousByte = (Byte)symbol;
+
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRep + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < kNumLitStates ? 0 : 3;
+ prob = p + LenCoder;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG0 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ prob = p + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IfBit0(prob)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ UpdateBit0(prob);
+
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit == 0)
+ #else
+ if (nowPos == 0)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ state = state < kNumLitStates ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ if (distanceLimit < dictionarySize)
+ distanceLimit++;
+ #endif
+
+ continue;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ UpdateBit1(prob);
+ prob = p + IsRepG1 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ prob = p + IsRepG2 + state;
+ IfBit0(prob)
+ {
+ UpdateBit0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UpdateBit1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = p + RepLenCoder;
+ }
+ {
+ int numBits, offset;
+ CProb *probLen = prob + LenChoice;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ numBits = kLenNumLowBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenChoice2;
+ IfBit0(probLen)
+ {
+ UpdateBit0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ numBits = kLenNumMidBits;
+ }
+ else
+ {
+ UpdateBit1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ numBits = kLenNumHighBits;
+ }
+ }
+ RangeDecoderBitTreeDecode(probLen, numBits, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ int posSlot;
+ state += kNumLitStates;
+ prob = p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ RangeDecoderBitTreeDecode(prob, kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = (2 | ((UInt32)posSlot & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 <<= numDirectBits;
+ prob = p + SpecPos + rep0 - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ RC_NORMALIZE
+ Range >>= 1;
+ rep0 <<= 1;
+ if (Code >= Range)
+ {
+ Code -= Range;
+ rep0 |= 1;
+ }
+ }
+ while (--numDirectBits != 0);
+ prob = p + Align;
+ rep0 <<= kNumAlignBits;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ int i = 1;
+ int mi = 1;
+ do
+ {
+ CProb *prob3 = prob + mi;
+ RC_GET_BIT2(prob3, mi, ; , rep0 |= i);
+ i <<= 1;
+ }
+ while(--numDirectBits != 0);
+ }
+ }
+ else
+ rep0 = posSlot;
+ if (++rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = kLzmaStreamWasFinishedId;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+ #ifdef _LZMA_OUT_READ
+ if (rep0 > distanceLimit)
+ #else
+ if (rep0 > nowPos)
+ #endif
+ return LZMA_RESULT_DATA_ERROR;
+
+ #ifdef _LZMA_OUT_READ
+ if (dictionarySize - distanceLimit > (UInt32)len)
+ distanceLimit += len;
+ else
+ distanceLimit = dictionarySize;
+ #endif
+
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ len--;
+ outStream[nowPos++] = previousByte;
+ }
+ while(len != 0 && nowPos < outSize);
+ }
+ }
+ RC_NORMALIZE;
+
+ #ifdef _LZMA_OUT_READ
+ vs->Range = Range;
+ vs->Code = Code;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + (UInt32)nowPos;
+ vs->DistanceLimit = distanceLimit;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->RemainLen = len;
+ vs->TempDictionary[0] = tempDictionary[0];
+ #endif
+
+ #ifdef _LZMA_IN_CB
+ vs->Buffer = Buffer;
+ vs->BufferLim = BufferLim;
+ #else
+ *inSizeProcessed = (SizeT)(Buffer - inStream);
+ #endif
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/LzmaDecode.h b/target/linux/bmips/image/lzma-loader/src/LzmaDecode.h
new file mode 100644
index 0000000..2870eeb
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/LzmaDecode.h
@@ -0,0 +1,113 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.40 Copyright (c) 1999-2006 Igor Pavlov (2006-05-01)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+#include "LzmaTypes.h"
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb UInt16
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, const unsigned char **buffer, SizeT *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LZMA_PROPERTIES_SIZE 5
+
+typedef struct _CLzmaProperties
+{
+ int lc;
+ int lp;
+ int pb;
+ #ifdef _LZMA_OUT_READ
+ UInt32 DictionarySize;
+ #endif
+}CLzmaProperties;
+
+int LzmaDecodeProperties(CLzmaProperties *propsRes, const unsigned char *propsData, int size);
+
+#define LzmaGetNumProbs(Properties) (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((Properties)->lc + (Properties)->lp)))
+
+#define kLzmaNeedInitId (-2)
+
+typedef struct _CLzmaDecoderState
+{
+ CLzmaProperties Properties;
+ CProb *Probs;
+
+ #ifdef _LZMA_IN_CB
+ const unsigned char *Buffer;
+ const unsigned char *BufferLim;
+ #endif
+
+ #ifdef _LZMA_OUT_READ
+ unsigned char *Dictionary;
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 DistanceLimit;
+ UInt32 Reps[4];
+ int State;
+ int RemainLen;
+ unsigned char TempDictionary[4];
+ #endif
+} CLzmaDecoderState;
+
+#ifdef _LZMA_OUT_READ
+#define LzmaDecoderInit(vs) { (vs)->RemainLen = kLzmaNeedInitId; }
+#endif
+
+int LzmaDecode(CLzmaDecoderState *vs,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ const unsigned char *inStream, SizeT inSize, SizeT *inSizeProcessed,
+ #endif
+ unsigned char *outStream, SizeT outSize, SizeT *outSizeProcessed);
+
+#endif
diff --git a/target/linux/bmips/image/lzma-loader/src/LzmaTypes.h b/target/linux/bmips/image/lzma-loader/src/LzmaTypes.h
new file mode 100644
index 0000000..9c27290
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/LzmaTypes.h
@@ -0,0 +1,45 @@
+/*
+LzmaTypes.h
+
+Types for LZMA Decoder
+
+This file written and distributed to public domain by Igor Pavlov.
+This file is part of LZMA SDK 4.40 (2006-05-01)
+*/
+
+#ifndef __LZMATYPES_H
+#define __LZMATYPES_H
+
+#ifndef _7ZIP_BYTE_DEFINED
+#define _7ZIP_BYTE_DEFINED
+typedef unsigned char Byte;
+#endif
+
+#ifndef _7ZIP_UINT16_DEFINED
+#define _7ZIP_UINT16_DEFINED
+typedef unsigned short UInt16;
+#endif
+
+#ifndef _7ZIP_UINT32_DEFINED
+#define _7ZIP_UINT32_DEFINED
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef unsigned long UInt32;
+#else
+typedef unsigned int UInt32;
+#endif
+#endif
+
+/* #define _LZMA_NO_SYSTEM_SIZE_T */
+/* You can use it, if you don't want <stddef.h> */
+
+#ifndef _7ZIP_SIZET_DEFINED
+#define _7ZIP_SIZET_DEFINED
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+#include <stddef.h>
+typedef size_t SizeT;
+#endif
+#endif
+
+#endif
diff --git a/target/linux/bmips/image/lzma-loader/src/Makefile b/target/linux/bmips/image/lzma-loader/src/Makefile
new file mode 100644
index 0000000..50c22d8
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/Makefile
@@ -0,0 +1,86 @@
+#
+# Makefile for the LZMA compressed kernel loader for
+# Atheros AR7XXX/AR9XXX based boards
+#
+# Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+#
+# Some parts of this file was based on the OpenWrt specific lzma-loader
+# for the BCM47xx and ADM5120 based boards:
+# Copyright (C) 2004 Manuel Novoa III (mjn3 at codepoet.org)
+# Copyright (C) 2005 Mineharu Takahara <mtakahar at yahoo.com>
+# Copyright (C) 2005 by Oleg I. Vdovikin <oleg at cs.msu.su>
+#
+# 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.
+#
+
+LOADADDR :=
+LZMA_TEXT_START := 0x80a00000
+LOADER_DATA :=
+
+CC := $(CROSS_COMPILE)gcc
+LD := $(CROSS_COMPILE)ld
+OBJCOPY := $(CROSS_COMPILE)objcopy
+OBJDUMP := $(CROSS_COMPILE)objdump
+
+BIN_FLAGS := -O binary -R .reginfo -R .note -R .comment -R .mdebug -S
+
+CFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -Wno-trigraphs -Os \
+ -fno-strict-aliasing -fno-common -fomit-frame-pointer -G 0 \
+ -mno-abicalls -fno-pic -ffunction-sections -pipe \
+ -ffreestanding -fhonour-copts \
+ -mabi=32 -march=mips32 \
+ -Wa,-32 -Wa,-march=mips32 -Wa,-mips32 -Wa,--trap
+CFLAGS += -D_LZMA_PROB32
+
+ASFLAGS = $(CFLAGS) -D__ASSEMBLY__
+
+LDFLAGS = -static --gc-sections -no-warn-mismatch
+LDFLAGS += -e startup -T loader.lds -Ttext $(LZMA_TEXT_START)
+
+O_FORMAT = $(shell $(OBJDUMP) -i | head -2 | grep elf32)
+
+OBJECTS := head.o loader.o cache.o board.o printf.o LzmaDecode.o
+
+ifneq ($(strip $(LOADER_DATA)),)
+OBJECTS += data.o
+CFLAGS += -DLZMA_WRAPPER=1 -DLOADADDR=$(LOADADDR)
+endif
+
+
+all: loader.elf
+
+# Don't build dependencies, this may die if $(CC) isn't gcc
+dep:
+
+install:
+
+%.o : %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+%.o : %.S
+ $(CC) $(ASFLAGS) -c -o $@ $<
+
+data.o: $(LOADER_DATA)
+ $(LD) -r -b binary --oformat $(O_FORMAT) -T lzma-data.lds -o $@ $<
+
+loader: $(OBJECTS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJECTS)
+
+loader.bin: loader
+ $(OBJCOPY) $(BIN_FLAGS) $< $@
+
+loader2.o: loader.bin
+ $(LD) -r -b binary --oformat $(O_FORMAT) -o $@ $<
+
+loader.elf: loader2.o
+ $(LD) -e startup -T loader2.lds -Ttext $(LOADADDR) -o $@ $<
+
+mrproper: clean
+
+clean:
+ rm -f loader *.elf *.bin *.o
+
+
+
diff --git a/target/linux/bmips/image/lzma-loader/src/board.c b/target/linux/bmips/image/lzma-loader/src/board.c
new file mode 100644
index 0000000..1c715e3
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/board.c
@@ -0,0 +1,103 @@
+/*
+ * BCM63XX specific implementation parts
+ *
+ * Copyright (C) 2014 Jonas Gorski <jogo at openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <stddef.h>
+#include "config.h"
+#include "cp0regdef.h"
+
+#define READREG(r) *(volatile unsigned int *)(r)
+#define WRITEREG(r,v) *(volatile unsigned int *)(r) = v
+
+#define UART_IR_REG 0x10
+#define UART_FIFO_REG 0x14
+
+unsigned long uart_base;
+
+static void wait_xfered(void)
+{
+ unsigned int val;
+
+ do {
+ val = READREG(uart_base + UART_IR_REG);
+ if (val & (1 << 5))
+ break;
+ } while (1);
+}
+
+void board_putc(int ch)
+{
+ if (!uart_base)
+ return;
+
+ wait_xfered();
+ WRITEREG(uart_base + UART_FIFO_REG, ch);
+ wait_xfered();
+}
+
+#define PRID_IMP_BMIPS32_REV4 0x4000
+#define PRID_IMP_BMIPS32_REV8 0x8000
+#define PRID_IMP_BMIPS3300 0x9000
+#define PRID_IMP_BMIPS3300_ALT 0x9100
+#define PRID_IMP_BMIPS3300_BUG 0x0000
+#define PRID_IMP_BMIPS43XX 0xa000
+
+void board_init(void)
+{
+ unsigned long prid, chipid, chipid_reg;
+
+ prid = read_32bit_c0_register($15, 0);
+
+ switch (prid & 0xff00) {
+ case PRID_IMP_BMIPS32_REV4:
+ case PRID_IMP_BMIPS32_REV8:
+ case PRID_IMP_BMIPS3300_ALT:
+ case PRID_IMP_BMIPS3300_BUG:
+ chipid_reg = 0xfffe0000;
+ break;
+ case PRID_IMP_BMIPS3300:
+ if ((prid & 0xff) >= 0x33)
+ chipid_reg = 0xb0000000;
+ else
+ chipid_reg = 0xfffe0000;
+ break;
+ case PRID_IMP_BMIPS43XX:
+ if ((prid & 0xff) >= 0x30)
+ chipid_reg = 0xb0000000;
+ else
+ chipid_reg = 0xfffe0000;
+ break;
+ default:
+ return;
+ }
+
+ chipid = READREG(chipid_reg);
+
+ switch (chipid >> 16) {
+ case 0x6318:
+ case 0x6328:
+ case 0x6358:
+ case 0x6362:
+ case 0x6368:
+ case 0x6369:
+ uart_base = chipid_reg + 0x100;
+ break;
+ case 0x6316:
+ case 0x6326:
+ uart_base = chipid_reg + 0x180;
+ break;
+ case 0x6338:
+ case 0x6345:
+ case 0x6348:
+ uart_base = chipid_reg + 0x300;
+ break;
+ default:
+ return;
+ }
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/cache.c b/target/linux/bmips/image/lzma-loader/src/cache.c
new file mode 100644
index 0000000..93751c3
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/cache.c
@@ -0,0 +1,46 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * The cache manipulation routine has been taken from the U-Boot project.
+ * (C) Copyright 2003
+ * Wolfgang Denk, DENX Software Engineering, <wd at denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include "cache.h"
+#include "cacheops.h"
+#include "config.h"
+#include "printf.h"
+
+#define cache_op(op,addr) \
+ __asm__ __volatile__( \
+ " .set push \n" \
+ " .set noreorder \n" \
+ " .set mips3\n\t \n" \
+ " cache %0, %1 \n" \
+ " .set pop \n" \
+ : \
+ : "i" (op), "R" (*(unsigned char *)(addr)))
+
+void flush_cache(unsigned long start_addr, unsigned long size)
+{
+ unsigned long lsize = CONFIG_CACHELINE_SIZE;
+ unsigned long addr = start_addr & ~(lsize - 1);
+ unsigned long aend = (start_addr + size + (lsize - 1)) & ~(lsize - 1);
+
+ printf("blasting from 0x%08x to 0x%08x (0x%08x - 0x%08x)\n", start_addr, size, addr, aend);
+
+ while (1) {
+ cache_op(Hit_Writeback_Inv_D, addr);
+ cache_op(Hit_Invalidate_I, addr);
+ if (addr == aend)
+ break;
+ addr += lsize;
+ }
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/cache.h b/target/linux/bmips/image/lzma-loader/src/cache.h
new file mode 100644
index 0000000..506a235
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/cache.h
@@ -0,0 +1,17 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CACHE_H
+#define __CACHE_H
+
+void flush_cache(unsigned long start_addr, unsigned long size);
+
+#endif /* __CACHE_H */
diff --git a/target/linux/bmips/image/lzma-loader/src/cacheops.h b/target/linux/bmips/image/lzma-loader/src/cacheops.h
new file mode 100644
index 0000000..70bcad7
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/cacheops.h
@@ -0,0 +1,85 @@
+/*
+ * Cache operations for the cache instruction.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * (C) Copyright 1996, 97, 99, 2002, 03 Ralf Baechle
+ * (C) Copyright 1999 Silicon Graphics, Inc.
+ */
+#ifndef __ASM_CACHEOPS_H
+#define __ASM_CACHEOPS_H
+
+/*
+ * Cache Operations available on all MIPS processors with R4000-style caches
+ */
+#define Index_Invalidate_I 0x00
+#define Index_Writeback_Inv_D 0x01
+#define Index_Load_Tag_I 0x04
+#define Index_Load_Tag_D 0x05
+#define Index_Store_Tag_I 0x08
+#define Index_Store_Tag_D 0x09
+#if defined(CONFIG_CPU_LOONGSON2)
+#define Hit_Invalidate_I 0x00
+#else
+#define Hit_Invalidate_I 0x10
+#endif
+#define Hit_Invalidate_D 0x11
+#define Hit_Writeback_Inv_D 0x15
+
+/*
+ * R4000-specific cacheops
+ */
+#define Create_Dirty_Excl_D 0x0d
+#define Fill 0x14
+#define Hit_Writeback_I 0x18
+#define Hit_Writeback_D 0x19
+
+/*
+ * R4000SC and R4400SC-specific cacheops
+ */
+#define Index_Invalidate_SI 0x02
+#define Index_Writeback_Inv_SD 0x03
+#define Index_Load_Tag_SI 0x06
+#define Index_Load_Tag_SD 0x07
+#define Index_Store_Tag_SI 0x0A
+#define Index_Store_Tag_SD 0x0B
+#define Create_Dirty_Excl_SD 0x0f
+#define Hit_Invalidate_SI 0x12
+#define Hit_Invalidate_SD 0x13
+#define Hit_Writeback_Inv_SD 0x17
+#define Hit_Writeback_SD 0x1b
+#define Hit_Set_Virtual_SI 0x1e
+#define Hit_Set_Virtual_SD 0x1f
+
+/*
+ * R5000-specific cacheops
+ */
+#define R5K_Page_Invalidate_S 0x17
+
+/*
+ * RM7000-specific cacheops
+ */
+#define Page_Invalidate_T 0x16
+
+/*
+ * R10000-specific cacheops
+ *
+ * Cacheops 0x02, 0x06, 0x0a, 0x0c-0x0e, 0x16, 0x1a and 0x1e are unused.
+ * Most of the _S cacheops are identical to the R4000SC _SD cacheops.
+ */
+#define Index_Writeback_Inv_S 0x03
+#define Index_Load_Tag_S 0x07
+#define Index_Store_Tag_S 0x0B
+#define Hit_Invalidate_S 0x13
+#define Cache_Barrier 0x14
+#define Hit_Writeback_Inv_S 0x17
+#define Index_Load_Data_I 0x18
+#define Index_Load_Data_D 0x19
+#define Index_Load_Data_S 0x1b
+#define Index_Store_Data_I 0x1c
+#define Index_Store_Data_D 0x1d
+#define Index_Store_Data_S 0x1f
+
+#endif /* __ASM_CACHEOPS_H */
diff --git a/target/linux/bmips/image/lzma-loader/src/config.h b/target/linux/bmips/image/lzma-loader/src/config.h
new file mode 100644
index 0000000..ce391f8
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/config.h
@@ -0,0 +1,31 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * 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.
+ *
+ */
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+#define CONFIG_ICACHE_SIZE (32 * 1024)
+#define CONFIG_DCACHE_SIZE (32 * 1024)
+#define CONFIG_CACHELINE_SIZE 16
+
+#ifndef CONFIG_FLASH_OFFS
+#define CONFIG_FLASH_OFFS 0
+#endif
+
+#ifndef CONFIG_FLASH_MAX
+#define CONFIG_FLASH_MAX 0
+#endif
+
+#ifndef CONFIG_FLASH_STEP
+#define CONFIG_FLASH_STEP 0x1000
+#endif
+
+#endif /* _CONFIG_H_ */
diff --git a/target/linux/bmips/image/lzma-loader/src/cp0regdef.h b/target/linux/bmips/image/lzma-loader/src/cp0regdef.h
new file mode 100644
index 0000000..0d824f4
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/cp0regdef.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 1994, 1995, 1996, 1997, 2000, 2001 by Ralf Baechle
+ *
+ * Copyright (C) 2001, Monta Vista Software
+ * Author: jsun at mvista.com or jsun at junsun.net
+ */
+#ifndef _cp0regdef_h_
+#define _cp0regdef_h_
+
+#define CP0_INDEX $0
+#define CP0_RANDOM $1
+#define CP0_ENTRYLO0 $2
+#define CP0_ENTRYLO1 $3
+#define CP0_CONTEXT $4
+#define CP0_PAGEMASK $5
+#define CP0_WIRED $6
+#define CP0_BADVADDR $8
+#define CP0_COUNT $9
+#define CP0_ENTRYHI $10
+#define CP0_COMPARE $11
+#define CP0_STATUS $12
+#define CP0_CAUSE $13
+#define CP0_EPC $14
+#define CP0_PRID $15
+#define CP0_CONFIG $16
+#define CP0_LLADDR $17
+#define CP0_WATCHLO $18
+#define CP0_WATCHHI $19
+#define CP0_XCONTEXT $20
+#define CP0_FRAMEMASK $21
+#define CP0_DIAGNOSTIC $22
+#define CP0_PERFORMANCE $25
+#define CP0_ECC $26
+#define CP0_CACHEERR $27
+#define CP0_TAGLO $28
+#define CP0_TAGHI $29
+#define CP0_ERROREPC $30
+
+#define read_32bit_c0_register(reg,sel) \
+({ int __res; \
+ if (sel == 0) \
+ __asm__ __volatile__( \
+ "mfc0\t%0, " #reg "\n\t" \
+ : "=r" (__res)); \
+ else \
+ __asm__ __volatile__( \
+ ".set\tmips32\n\t" \
+ "mfc0\t%0, " #reg ", " #sel "\n\t" \
+ ".set mips0\n\t" \
+ : "=r" (__res)); \
+ __res; \
+})
+
+#endif
diff --git a/target/linux/bmips/image/lzma-loader/src/head.S b/target/linux/bmips/image/lzma-loader/src/head.S
new file mode 100644
index 0000000..543996a
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/head.S
@@ -0,0 +1,118 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ * Copyright (C) 2004 Manuel Novoa III (mjn3 at codepoet.org)
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg at cs.msu.su>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include "cp0regdef.h"
+#include "cacheops.h"
+#include "config.h"
+
+#define KSEG0 0x80000000
+
+ .macro ehb
+ sll zero, 3
+ .endm
+
+ .text
+
+LEAF(startup)
+ .set noreorder
+ .set mips32
+
+ mtc0 zero, CP0_WATCHLO # clear watch registers
+ mtc0 zero, CP0_WATCHHI
+ mtc0 zero, CP0_CAUSE # clear before writing status register
+
+ mfc0 t0, CP0_STATUS
+ li t1, 0x1000001f
+ or t0, t1
+ xori t0, 0x1f
+ mtc0 t0, CP0_STATUS
+ ehb
+
+ mtc0 zero, CP0_COUNT
+ mtc0 zero, CP0_COMPARE
+ ehb
+
+ la t0, __reloc_label # get linked address of label
+ bal __reloc_label # branch and link to label to
+ nop # get actual address
+__reloc_label:
+ subu t0, ra, t0 # get reloc_delta
+
+ beqz t0, __reloc_done # if delta is 0 we are in the right place
+ nop
+
+ /* Copy our code to the right place */
+ la t1, _code_start # get linked address of _code_start
+ la t2, _code_end # get linked address of _code_end
+ addu t0, t0, t1 # calculate actual address of _code_start
+
+__reloc_copy:
+ lw t3, 0(t0)
+ sw t3, 0(t1)
+ add t1, 4
+ blt t1, t2, __reloc_copy
+ add t0, 4
+
+ /* flush cache */
+ la t0, _code_start
+ la t1, _code_end
+
+ li t2, ~(CONFIG_CACHELINE_SIZE - 1)
+ and t0, t2
+ and t1, t2
+ li t2, CONFIG_CACHELINE_SIZE
+
+ b __flush_check
+ nop
+
+__flush_line:
+ cache Hit_Writeback_Inv_D, 0(t0)
+ cache Hit_Invalidate_I, 0(t0)
+ add t0, t2
+
+__flush_check:
+ bne t0, t1, __flush_line
+ nop
+
+ sync
+
+__reloc_done:
+
+ /* clear bss */
+ la t0, _bss_start
+ la t1, _bss_end
+ b __bss_check
+ nop
+
+__bss_fill:
+ sw zero, 0(t0)
+ addi t0, 4
+
+__bss_check:
+ bne t0, t1, __bss_fill
+ nop
+
+ /* Setup new "C" stack */
+ la sp, _stack
+
+ /* jump to the decompressor routine */
+ la t0, loader_main
+ jr t0
+ nop
+
+ .set reorder
+END(startup)
diff --git a/target/linux/bmips/image/lzma-loader/src/loader.c b/target/linux/bmips/image/lzma-loader/src/loader.c
new file mode 100644
index 0000000..0848ce6
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/loader.c
@@ -0,0 +1,175 @@
+/*
+ * LZMA compressed kernel loader for Atheros AR7XXX/AR9XXX based boards
+ *
+ * Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>
+ *
+ * Some parts of this code was based on the OpenWrt specific lzma-loader
+ * for the BCM47xx and ADM5120 based boards:
+ * Copyright (C) 2004 Manuel Novoa III (mjn3 at codepoet.org)
+ * Copyright (C) 2005 Mineharu Takahara <mtakahar at yahoo.com>
+ * Copyright (C) 2005 by Oleg I. Vdovikin <oleg at cs.msu.su>
+ *
+ * The image_header structure has been taken from the U-Boot project.
+ * (C) Copyright 2008 Semihalf
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "config.h"
+#include "cache.h"
+#include "printf.h"
+#include "LzmaDecode.h"
+
+#define KSEG0 0x80000000
+#define KSEG1 0xa0000000
+
+#define KSEG1ADDR(a) ((((unsigned)(a)) & 0x1fffffffU) | KSEG1)
+
+#undef LZMA_DEBUG
+
+#ifdef LZMA_DEBUG
+# define DBG(f, a...) printf(f, ## a)
+#else
+# define DBG(f, a...) do {} while (0)
+#endif
+
+/* beyond the image end, size not known in advance */
+extern unsigned char workspace[];
+
+
+extern void board_init(void);
+
+static CLzmaDecoderState lzma_state;
+static unsigned char *lzma_data;
+static unsigned long lzma_datasize;
+static unsigned long lzma_outsize;
+static unsigned long kernel_la;
+
+static void halt(void)
+{
+ printf("\nSystem halted!\n");
+ for(;;);
+}
+
+static __inline__ unsigned char lzma_get_byte(void)
+{
+ unsigned char c;
+
+ lzma_datasize--;
+ c = *lzma_data++;
+
+ return c;
+}
+
+static int lzma_init_props(void)
+{
+ unsigned char props[LZMA_PROPERTIES_SIZE];
+ int res;
+ int i;
+
+ /* read lzma properties */
+ for (i = 0; i < LZMA_PROPERTIES_SIZE; i++)
+ props[i] = lzma_get_byte();
+
+ /* read the lower half of uncompressed size in the header */
+ lzma_outsize = ((SizeT) lzma_get_byte()) +
+ ((SizeT) lzma_get_byte() << 8) +
+ ((SizeT) lzma_get_byte() << 16) +
+ ((SizeT) lzma_get_byte() << 24);
+
+ /* skip rest of the header (upper half of uncompressed size) */
+ for (i = 0; i < 4; i++)
+ lzma_get_byte();
+
+ res = LzmaDecodeProperties(&lzma_state.Properties, props,
+ LZMA_PROPERTIES_SIZE);
+ return res;
+}
+
+static int lzma_decompress(unsigned char *outStream)
+{
+ SizeT ip, op;
+ int ret;
+
+ lzma_state.Probs = (CProb *) workspace;
+
+ ret = LzmaDecode(&lzma_state, lzma_data, lzma_datasize, &ip, outStream,
+ lzma_outsize, &op);
+
+ if (ret != LZMA_RESULT_OK) {
+ int i;
+
+ DBG("LzmaDecode error %d at %08x, osize:%d ip:%d op:%d\n",
+ ret, lzma_data + ip, lzma_outsize, ip, op);
+
+ for (i = 0; i < 16; i++)
+ DBG("%02x ", lzma_data[ip + i]);
+
+ DBG("\n");
+ }
+
+ return ret;
+}
+
+static void lzma_init_data(void)
+{
+ extern unsigned char _lzma_data_start[];
+ extern unsigned char _lzma_data_end[];
+
+ kernel_la = LOADADDR;
+ lzma_data = _lzma_data_start;
+ lzma_datasize = _lzma_data_end - _lzma_data_start;
+}
+
+void loader_main(unsigned long reg_a0, unsigned long reg_a1,
+ unsigned long reg_a2, unsigned long reg_a3)
+{
+ void (*kernel_entry) (unsigned long, unsigned long, unsigned long,
+ unsigned long);
+ int res;
+
+ board_init();
+
+ printf("\n\nOpenWrt kernel loader for BCM63XX\n");
+ printf("Copyright (C) 2011 Gabor Juhos <juhosg at openwrt.org>\n");
+ printf("Copyright (C) 2014 Jonas Gorski <jogo at openwrt.org>\n");
+
+ lzma_init_data();
+
+ res = lzma_init_props();
+ if (res != LZMA_RESULT_OK) {
+ printf("Incorrect LZMA stream properties!\n");
+ halt();
+ }
+
+ printf("Decompressing kernel... ");
+
+ res = lzma_decompress((unsigned char *) kernel_la);
+ if (res != LZMA_RESULT_OK) {
+ printf("failed, ");
+ switch (res) {
+ case LZMA_RESULT_DATA_ERROR:
+ printf("data error!\n");
+ break;
+ default:
+ printf("unknown error %d!\n", res);
+ }
+ halt();
+ } else {
+ printf("done!\n");
+ }
+
+ flush_cache(kernel_la, lzma_outsize);
+
+ printf("Starting kernel at %08x...\n\n", kernel_la);
+
+ kernel_entry = (void *) kernel_la;
+ kernel_entry(reg_a0, reg_a1, reg_a2, reg_a3);
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/loader.lds b/target/linux/bmips/image/lzma-loader/src/loader.lds
new file mode 100644
index 0000000..01ff852
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/loader.lds
@@ -0,0 +1,34 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+ .text : {
+ _code_start = .;
+ *(.text)
+ *(.text.*)
+ *(.rodata)
+ *(.rodata.*)
+ *(.data.lzma)
+ }
+
+ . = ALIGN(32);
+ .data : {
+ *(.data)
+ *(.data.*)
+ }
+
+ . = ALIGN(32);
+ _code_end = .;
+
+ _bss_start = .;
+ .bss : {
+ *(.bss)
+ *(.bss.*)
+ }
+
+ . = ALIGN(32);
+ _bss_end = .;
+
+ . = . + 8192;
+ _stack = .;
+
+ workspace = .;
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/loader2.lds b/target/linux/bmips/image/lzma-loader/src/loader2.lds
new file mode 100644
index 0000000..db0bb46
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/loader2.lds
@@ -0,0 +1,10 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+ .text : {
+ startup = .;
+ *(.text)
+ *(.text.*)
+ *(.data)
+ *(.data.*)
+ }
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/lzma-data.lds b/target/linux/bmips/image/lzma-loader/src/lzma-data.lds
new file mode 100644
index 0000000..abf756b
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/lzma-data.lds
@@ -0,0 +1,8 @@
+OUTPUT_ARCH(mips)
+SECTIONS {
+ .data.lzma : {
+ _lzma_data_start = .;
+ *(.data)
+ _lzma_data_end = .;
+ }
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/printf.c b/target/linux/bmips/image/lzma-loader/src/printf.c
new file mode 100644
index 0000000..7bb5a86
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/printf.c
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun at mvista.com or jsun at junsun.net
+ *
+ * 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 "printf.h"
+
+extern void board_putc(int ch);
+
+/* this is the maximum width for a variable */
+#define LP_MAX_BUF 256
+
+/* macros */
+#define IsDigit(x) ( ((x) >= '0') && ((x) <= '9') )
+#define Ctod(x) ( (x) - '0')
+
+/* forward declaration */
+static int PrintChar(char *, char, int, int);
+static int PrintString(char *, char *, int, int);
+static int PrintNum(char *, unsigned long, int, int, int, int, char, int);
+
+/* private variable */
+static const char theFatalMsg[] = "fatal error in lp_Print!";
+
+/* -*-
+ * A low level printf() function.
+ */
+static void
+lp_Print(void (*output)(void *, char *, int),
+ void * arg,
+ char *fmt,
+ va_list ap)
+{
+
+#define OUTPUT(arg, s, l) \
+ { if (((l) < 0) || ((l) > LP_MAX_BUF)) { \
+ (*output)(arg, (char*)theFatalMsg, sizeof(theFatalMsg)-1); for(;;); \
+ } else { \
+ (*output)(arg, s, l); \
+ } \
+ }
+
+ char buf[LP_MAX_BUF];
+
+ char c;
+ char *s;
+ long int num;
+
+ int longFlag;
+ int negFlag;
+ int width;
+ int prec;
+ int ladjust;
+ char padc;
+
+ int length;
+
+ for(;;) {
+ {
+ /* scan for the next '%' */
+ char *fmtStart = fmt;
+ while ( (*fmt != '\0') && (*fmt != '%')) {
+ fmt ++;
+ }
+
+ /* flush the string found so far */
+ OUTPUT(arg, fmtStart, fmt-fmtStart);
+
+ /* are we hitting the end? */
+ if (*fmt == '\0') break;
+ }
+
+ /* we found a '%' */
+ fmt ++;
+
+ /* check for long */
+ if (*fmt == 'l') {
+ longFlag = 1;
+ fmt ++;
+ } else {
+ longFlag = 0;
+ }
+
+ /* check for other prefixes */
+ width = 0;
+ prec = -1;
+ ladjust = 0;
+ padc = ' ';
+
+ if (*fmt == '-') {
+ ladjust = 1;
+ fmt ++;
+ }
+
+ if (*fmt == '0') {
+ padc = '0';
+ fmt++;
+ }
+
+ if (IsDigit(*fmt)) {
+ while (IsDigit(*fmt)) {
+ width = 10 * width + Ctod(*fmt++);
+ }
+ }
+
+ if (*fmt == '.') {
+ fmt ++;
+ if (IsDigit(*fmt)) {
+ prec = 0;
+ while (IsDigit(*fmt)) {
+ prec = prec*10 + Ctod(*fmt++);
+ }
+ }
+ }
+
+
+ /* check format flag */
+ negFlag = 0;
+ switch (*fmt) {
+ case 'b':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 2, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'd':
+ case 'D':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ if (num < 0) {
+ num = - num;
+ negFlag = 1;
+ }
+ length = PrintNum(buf, num, 10, negFlag, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'o':
+ case 'O':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 8, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'u':
+ case 'U':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 10, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'x':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 0);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'X':
+ if (longFlag) {
+ num = va_arg(ap, long int);
+ } else {
+ num = va_arg(ap, int);
+ }
+ length = PrintNum(buf, num, 16, 0, width, ladjust, padc, 1);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 'c':
+ c = (char)va_arg(ap, int);
+ length = PrintChar(buf, c, width, ladjust);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case 's':
+ s = (char*)va_arg(ap, char *);
+ length = PrintString(buf, s, width, ladjust);
+ OUTPUT(arg, buf, length);
+ break;
+
+ case '\0':
+ fmt --;
+ break;
+
+ default:
+ /* output this char as it is */
+ OUTPUT(arg, fmt, 1);
+ } /* switch (*fmt) */
+
+ fmt ++;
+ } /* for(;;) */
+
+ /* special termination call */
+ OUTPUT(arg, "\0", 1);
+}
+
+
+/* --------------- local help functions --------------------- */
+static int
+PrintChar(char * buf, char c, int length, int ladjust)
+{
+ int i;
+
+ if (length < 1) length = 1;
+ if (ladjust) {
+ *buf = c;
+ for (i=1; i< length; i++) buf[i] = ' ';
+ } else {
+ for (i=0; i< length-1; i++) buf[i] = ' ';
+ buf[length - 1] = c;
+ }
+ return length;
+}
+
+static int
+PrintString(char * buf, char* s, int length, int ladjust)
+{
+ int i;
+ int len=0;
+ char* s1 = s;
+ while (*s1++) len++;
+ if (length < len) length = len;
+
+ if (ladjust) {
+ for (i=0; i< len; i++) buf[i] = s[i];
+ for (i=len; i< length; i++) buf[i] = ' ';
+ } else {
+ for (i=0; i< length-len; i++) buf[i] = ' ';
+ for (i=length-len; i < length; i++) buf[i] = s[i-length+len];
+ }
+ return length;
+}
+
+static int
+PrintNum(char * buf, unsigned long u, int base, int negFlag,
+ int length, int ladjust, char padc, int upcase)
+{
+ /* algorithm :
+ * 1. prints the number from left to right in reverse form.
+ * 2. fill the remaining spaces with padc if length is longer than
+ * the actual length
+ * TRICKY : if left adjusted, no "0" padding.
+ * if negtive, insert "0" padding between "0" and number.
+ * 3. if (!ladjust) we reverse the whole string including paddings
+ * 4. otherwise we only reverse the actual string representing the num.
+ */
+
+ int actualLength =0;
+ char *p = buf;
+ int i;
+
+ do {
+ int tmp = u %base;
+ if (tmp <= 9) {
+ *p++ = '0' + tmp;
+ } else if (upcase) {
+ *p++ = 'A' + tmp - 10;
+ } else {
+ *p++ = 'a' + tmp - 10;
+ }
+ u /= base;
+ } while (u != 0);
+
+ if (negFlag) {
+ *p++ = '-';
+ }
+
+ /* figure out actual length and adjust the maximum length */
+ actualLength = p - buf;
+ if (length < actualLength) length = actualLength;
+
+ /* add padding */
+ if (ladjust) {
+ padc = ' ';
+ }
+ if (negFlag && !ladjust && (padc == '0')) {
+ for (i = actualLength-1; i< length-1; i++) buf[i] = padc;
+ buf[length -1] = '-';
+ } else {
+ for (i = actualLength; i< length; i++) buf[i] = padc;
+ }
+
+
+ /* prepare to reverse the string */
+ {
+ int begin = 0;
+ int end;
+ if (ladjust) {
+ end = actualLength - 1;
+ } else {
+ end = length -1;
+ }
+
+ while (end > begin) {
+ char tmp = buf[begin];
+ buf[begin] = buf[end];
+ buf[end] = tmp;
+ begin ++;
+ end --;
+ }
+ }
+
+ /* adjust the string pointer */
+ return length;
+}
+
+static void printf_output(void *arg, char *s, int l)
+{
+ int i;
+
+ // special termination call
+ if ((l==1) && (s[0] == '\0')) return;
+
+ for (i=0; i< l; i++) {
+ board_putc(s[i]);
+ if (s[i] == '\n') board_putc('\r');
+ }
+}
+
+void printf(char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ lp_Print(printf_output, 0, fmt, ap);
+ va_end(ap);
+}
diff --git a/target/linux/bmips/image/lzma-loader/src/printf.h b/target/linux/bmips/image/lzma-loader/src/printf.h
new file mode 100644
index 0000000..9b1c1df
--- /dev/null
+++ b/target/linux/bmips/image/lzma-loader/src/printf.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2001 MontaVista Software Inc.
+ * Author: Jun Sun, jsun at mvista.com or jsun at junsun.net
+ *
+ * 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 _printf_h_
+#define _printf_h_
+
+#include <stdarg.h>
+void printf(char *fmt, ...);
+
+#endif /* _printf_h_ */
diff --git a/target/linux/bmips/patches-4.1/001-MIPS-Add-support-for-vmlinux.bin-appended-dtb.patch b/target/linux/bmips/patches-4.1/001-MIPS-Add-support-for-vmlinux.bin-appended-dtb.patch
new file mode 100644
index 0000000..fa7732b
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/001-MIPS-Add-support-for-vmlinux.bin-appended-dtb.patch
@@ -0,0 +1,112 @@
+From 1da8f1798e307fb8422753984339beb00025f97d Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Sun, 12 Apr 2015 12:24:58 +0200
+Subject: [PATCH] MIPS: Add support for vmlinux.bin appended dtb
+
+Add support for detecting a vmlinux.bin appended dtb and overriding
+the boot arguments to match the UHI interface.
+
+Due to the PERCPU section being empty for !SMP, but still modifying
+the current address by aligning it to the page size, do not define
+it for !SMP builds to allow __appended_dtb to still point to
+the actual end of the data.
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+Cc: linux-mips at linux-mips.org
+Cc: devicetree at vger.kernel.org
+Cc: John Crispin <blogic at openwrt.org>
+Cc: Kevin Cernekee <cernekee at gmail.com>
+Cc: Florian Fainelli <f.fainelli at gmail.com>
+Cc: Aaro Koskinen <aaro.koskinen at iki.fi>
+Cc: Markos Chandras <markos.chandras at imgtec.com>
+Cc: Andrew Bresticker <abrestic at chromium.org>
+Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
+Cc: Paul Burton <paul.burton at imgtec.com>
+Cc: James Hartley <James.Hartley at imgtec.com>
+Patchwork: https://patchwork.linux-mips.org/patch/9739/
+Signed-off-by: Ralf Baechle <ralf at linux-mips.org>
+---
+ arch/mips/Kconfig | 27 +++++++++++++++++++++++++++
+ arch/mips/kernel/head.S | 16 ++++++++++++++++
+ arch/mips/kernel/vmlinux.lds.S | 8 +++++++-
+ 3 files changed, 50 insertions(+), 1 deletion(-)
+
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -2703,6 +2703,33 @@ config BOOT_RAW
+
+
+
++choice
++ prompt "Kernel appended dtb support" if OF
++ default MIPS_NO_APPENDED_DTB
++
++ config MIPS_NO_APPENDED_DTB
++ bool "None"
++ help
++ Do not enable appended dtb support.
++
++ config MIPS_RAW_APPENDED_DTB
++ bool "vmlinux.bin"
++ help
++ With this option, the boot code will look for a device tree binary
++ DTB) appended to raw vmlinux.bin (without decompressor).
++ (e.g. cat vmlinux.bin <filename>.dtb > vmlinux_w_dtb).
++
++ This is meant as a backward compatibility convenience for those
++ systems with a bootloader that can't be upgraded to accommodate
++ the documented boot protocol using a device tree.
++
++ Beware that there is very little in terms of protection against
++ this option being confused by leftover garbage in memory that might
++ look like a DTB header after a reboot if no actual DTB is appended
++ to vmlinux.bin. Do not leave this option active in a production kernel
++ if you don't intend to always append a DTB.
++endchoice
++
+ endmenu
+
+ config LOCKDEP_SUPPORT
+--- a/arch/mips/kernel/head.S
++++ b/arch/mips/kernel/head.S
+@@ -100,6 +100,22 @@ NESTED(kernel_entry, 16, sp) # kernel
+ jr t0
+ 0:
+
++#ifdef CONFIG_MIPS_RAW_APPENDED_DTB
++ PTR_LA t0, __appended_dtb
++
++#ifdef CONFIG_CPU_BIG_ENDIAN
++ li t1, 0xd00dfeed
++#else
++ li t1, 0xedfe0dd0
++#endif
++ lw t2, (t0)
++ bne t1, t2, not_found
++ nop
++
++ move a1, t0
++ PTR_LI a0, -2
++not_found:
++#endif
+ PTR_LA t0, __bss_start # clear .bss
+ LONG_S zero, (t0)
+ PTR_LA t1, __bss_stop - LONGSIZE
+--- a/arch/mips/kernel/vmlinux.lds.S
++++ b/arch/mips/kernel/vmlinux.lds.S
+@@ -125,8 +125,14 @@ SECTIONS
+ .exit.data : {
+ EXIT_DATA
+ }
+-
++#ifdef CONFIG_SMP
+ PERCPU_SECTION(1 << CONFIG_MIPS_L1_CACHE_SHIFT)
++#endif
++#ifdef CONFIG_MIPS_RAW_APPENDED_DTB
++ __appended_dtb = .;
++ /* leave space for appended DTB */
++ . += 0x100000;
++#endif
+ /*
+ * Align to 64K in attempt to eliminate holes before the
+ * .bss..swapper_pg_dir section at the start of .bss. This
diff --git a/target/linux/bmips/patches-4.1/010-MIPS-BMIPS-Build-all-dtbs-if-no-builtin-dtb.patch b/target/linux/bmips/patches-4.1/010-MIPS-BMIPS-Build-all-dtbs-if-no-builtin-dtb.patch
new file mode 100644
index 0000000..a918dc9
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/010-MIPS-BMIPS-Build-all-dtbs-if-no-builtin-dtb.patch
@@ -0,0 +1,48 @@
+From 0e12f4a3ab52f8be48c5ebbc556f53acb1afb280 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Sun, 12 Apr 2015 12:25:00 +0200
+Subject: [PATCH] MIPS: BMIPS: Build all dtbs if no builtin dtb
+
+Build all available dtbs to allow them to be appended to the resulting
+kernel in case there is no builtin dtb.
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+Cc: linux-mips at linux-mips.org
+Cc: devicetree at vger.kernel.org
+Cc: John Crispin <blogic at openwrt.org>
+Cc: Kevin Cernekee <cernekee at gmail.com>
+Cc: Florian Fainelli <f.fainelli at gmail.com>
+Cc: Aaro Koskinen <aaro.koskinen at iki.fi>
+Cc: Markos Chandras <markos.chandras at imgtec.com>
+Cc: Andrew Bresticker <abrestic at chromium.org>
+Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
+Cc: Paul Burton <paul.burton at imgtec.com>
+Cc: James Hartley <James.Hartley at imgtec.com>
+Patchwork: https://patchwork.linux-mips.org/patch/9740/
+Signed-off-by: Ralf Baechle <ralf at linux-mips.org>
+---
+ arch/mips/boot/dts/brcm/Makefile | 13 +++++++++++++
+ 1 file changed, 13 insertions(+)
+
+--- a/arch/mips/boot/dts/brcm/Makefile
++++ b/arch/mips/boot/dts/brcm/Makefile
+@@ -10,6 +10,19 @@ dtb-$(CONFIG_DT_BCM97362SVMB) += bcm973
+ dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb
+ dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb
+
++dtb-$(CONFIG_DT_NONE) += \
++ bcm93384wvg.dtb \
++ bcm93384wvg_viper.dtb \
++ bcm96368mvwg.dtb \
++ bcm9ejtagprb.dtb \
++ bcm97125cbmb.dtb \
++ bcm97346dbsmb.dtb \
++ bcm97358svmb.dtb \
++ bcm97360svmb.dtb \
++ bcm97362svmb.dtb \
++ bcm97420c.dtb \
++ bcm97425svmb.dtb
++
+ obj-y += $(patsubst %.dtb, %.dtb.o, $(dtb-y))
+
+ # Force kbuild to make empty built-in.o if necessary
diff --git a/target/linux/bmips/patches-4.1/011-MIPS-BMIPS-Accept-UHI-interface-for-passing-a-dtb.patch b/target/linux/bmips/patches-4.1/011-MIPS-BMIPS-Accept-UHI-interface-for-passing-a-dtb.patch
new file mode 100644
index 0000000..72aafe5
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/011-MIPS-BMIPS-Accept-UHI-interface-for-passing-a-dtb.patch
@@ -0,0 +1,37 @@
+From ca668a2da4687f23e65ce630742b6784a5fca595 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Sun, 12 Apr 2015 12:25:01 +0200
+Subject: [PATCH] MIPS: BMIPS: Accept UHI interface for passing a dtb
+
+Detect and use passed dtb address using the UHI interface. This allows for
+booting with a vmlinux.bin appended dtb instead of using a built-in one.
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+Cc: linux-mips at linux-mips.org
+Cc: devicetree at vger.kernel.org
+Cc: John Crispin <blogic at openwrt.org>
+Cc: Kevin Cernekee <cernekee at gmail.com>
+Cc: Florian Fainelli <f.fainelli at gmail.com>
+Cc: Aaro Koskinen <aaro.koskinen at iki.fi>
+Cc: Markos Chandras <markos.chandras at imgtec.com>
+Cc: Andrew Bresticker <abrestic at chromium.org>
+Cc: Daniel Schwierzeck <daniel.schwierzeck at gmail.com>
+Cc: Paul Burton <paul.burton at imgtec.com>
+Cc: James Hartley <James.Hartley at imgtec.com>
+Patchwork: https://patchwork.linux-mips.org/patch/9742/
+Signed-off-by: Ralf Baechle <ralf at linux-mips.org>
+---
+ arch/mips/bmips/setup.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -149,6 +149,8 @@ void __init plat_mem_setup(void)
+ /* intended to somewhat resemble ARM; see Documentation/arm/Booting */
+ if (fw_arg0 == 0 && fw_arg1 == 0xffffffff)
+ dtb = phys_to_virt(fw_arg2);
++ else if (fw_arg0 == -2) /* UHI interface */
++ dtb = (void *)fw_arg1;
+ else if (__dtb_start != __dtb_end)
+ dtb = (void *)__dtb_start;
+ else
diff --git a/target/linux/bmips/patches-4.1/012-MIPS-BMIPS-Add-support-for-Broadcom-BCM97435SVMB.patch b/target/linux/bmips/patches-4.1/012-MIPS-BMIPS-Add-support-for-Broadcom-BCM97435SVMB.patch
new file mode 100644
index 0000000..a6d7968
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/012-MIPS-BMIPS-Add-support-for-Broadcom-BCM97435SVMB.patch
@@ -0,0 +1,112 @@
+From 380e4270f53b1ce848de7c3c9f21c7d6ccab3d2e Mon Sep 17 00:00:00 2001
+From: Florian Fainelli <f.fainelli at gmail.com>
+Date: Mon, 4 May 2015 18:10:57 -0700
+Subject: [PATCH] MIPS: BMIPS: Add support for Broadcom BCM97435SVMB
+
+Add a DTS file and Kconfig entry for the BCM97435SVMB evaluation board
+using bcm7435.dtsi as an example.
+
+The current code needs some tweaking to allow us to use the
+dual-threaded dual BMIPS5200 CPUs, so for now we limit ourselves to
+allowing just a single CPU to be booted.
+
+Signed-off-by: Florian Fainelli <f.fainelli at gmail.com>
+Cc: linux-mips at linux-mips.org
+Cc: blogic at openwrt.org
+Cc: cernekee at chromium.org
+Cc: Steven.Hill at imgtec.com
+Patchwork: https://patchwork.linux-mips.org/patch/9972/
+Signed-off-by: Ralf Baechle <ralf at linux-mips.org>
+---
+ arch/mips/bmips/Kconfig | 4 +++
+ arch/mips/boot/dts/brcm/Makefile | 1 +
+ arch/mips/boot/dts/brcm/bcm97435svmb.dts | 60 ++++++++++++++++++++++++++++++++
+ 3 files changed, 65 insertions(+)
+ create mode 100644 arch/mips/boot/dts/brcm/bcm97435svmb.dts
+
+--- a/arch/mips/bmips/Kconfig
++++ b/arch/mips/bmips/Kconfig
+@@ -57,6 +57,10 @@ config DT_BCM97425SVMB
+ bool "BCM97425SVMB"
+ select BUILTIN_DTB
+
++config DT_BCM97435SVMB
++ bool "BCM97435SVMB"
++ select BUILTIN_DTB
++
+ endchoice
+
+ endif
+--- a/arch/mips/boot/dts/brcm/Makefile
++++ b/arch/mips/boot/dts/brcm/Makefile
+@@ -9,6 +9,7 @@ dtb-$(CONFIG_DT_BCM97360SVMB) += bcm973
+ dtb-$(CONFIG_DT_BCM97362SVMB) += bcm97362svmb.dtb
+ dtb-$(CONFIG_DT_BCM97420C) += bcm97420c.dtb
+ dtb-$(CONFIG_DT_BCM97425SVMB) += bcm97425svmb.dtb
++dtb-$(CONFIG_DT_BCM97435SVMB) += bcm97435svmb.dtb
+
+ dtb-$(CONFIG_DT_NONE) += \
+ bcm93384wvg.dtb \
+--- /dev/null
++++ b/arch/mips/boot/dts/brcm/bcm97435svmb.dts
+@@ -0,0 +1,60 @@
++/dts-v1/;
++
++/include/ "bcm7435.dtsi"
++
++/ {
++ compatible = "brcm,bcm97435svmb", "brcm,bcm7435";
++ model = "Broadcom BCM97435SVMB";
++
++ memory at 0 {
++ device_type = "memory";
++ reg = <0x00000000 0x10000000>,
++ <0x20000000 0x30000000>,
++ <0x90000000 0x40000000>;
++ };
++
++ chosen {
++ bootargs = "console=ttyS0,115200 maxcpus=1";
++ stdout-path = &uart0;
++ };
++};
++
++&uart0 {
++ status = "okay";
++};
++
++&enet0 {
++ status = "okay";
++};
++
++&ehci0 {
++ status = "okay";
++};
++
++&ohci0 {
++ status = "okay";
++};
++
++&ehci1 {
++ status = "okay";
++};
++
++&ohci1 {
++ status = "okay";
++};
++
++&ehci2 {
++ status = "okay";
++};
++
++&ohci2 {
++ status = "okay";
++};
++
++&ehci3 {
++ status = "okay";
++};
++
++&ohci3 {
++ status = "okay";
++};
diff --git a/target/linux/bmips/patches-4.1/020-leds-add-BCM6328-LED-driver.patch b/target/linux/bmips/patches-4.1/020-leds-add-BCM6328-LED-driver.patch
new file mode 100644
index 0000000..fc3d03a
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/020-leds-add-BCM6328-LED-driver.patch
@@ -0,0 +1,464 @@
+From fd7b025a238d0a5440bfa26c585eb78097bf48dc Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari at gmail.com>
+Date: Tue, 28 Apr 2015 09:50:50 -0700
+Subject: [PATCH] leds: add BCM6328 LED driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds support for the LED controller on Broadcom's BCM6328.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+Acked-by: Jacek Anaszewski <j.anaszewski at samsung.com>
+Signed-off-by: Bryan Wu <cooloney at gmail.com>
+---
+ drivers/leds/Kconfig | 8 +
+ drivers/leds/Makefile | 1 +
+ drivers/leds/leds-bcm6328.c | 413 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 422 insertions(+)
+ create mode 100644 drivers/leds/leds-bcm6328.c
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -42,6 +42,14 @@ config LEDS_88PM860X
+ This option enables support for on-chip LED drivers found on Marvell
+ Semiconductor 88PM8606 PMIC.
+
++config LEDS_BCM6328
++ tristate "LED Support for Broadcom BCM6328"
++ depends on LEDS_CLASS
++ depends on OF
++ help
++ This option enables support for LEDs connected to the BCM6328
++ LED HW controller accessed via MMIO registers.
++
+ config LEDS_LM3530
+ tristate "LCD Backlight driver for LM3530"
+ depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -7,6 +7,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-trig
+
+ # LED Platform Drivers
+ obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
++obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
+ obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
+ obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
+ obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
+--- /dev/null
++++ b/drivers/leds/leds-bcm6328.c
+@@ -0,0 +1,413 @@
++/*
++ * Driver for BCM6328 memory-mapped LEDs, based on leds-syscon.c
++ *
++ * Copyright 2015 Álvaro Fernández Rojas <noltari at gmail.com>
++ * Copyright 2015 Jonas Gorski <jogo at openwrt.org>
++ *
++ * 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/leds.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++
++#define BCM6328_REG_INIT 0x00
++#define BCM6328_REG_MODE_HI 0x04
++#define BCM6328_REG_MODE_LO 0x08
++#define BCM6328_REG_HWDIS 0x0c
++#define BCM6328_REG_STROBE 0x10
++#define BCM6328_REG_LNKACTSEL_HI 0x14
++#define BCM6328_REG_LNKACTSEL_LO 0x18
++#define BCM6328_REG_RBACK 0x1c
++#define BCM6328_REG_SERMUX 0x20
++
++#define BCM6328_LED_MAX_COUNT 24
++#define BCM6328_LED_DEF_DELAY 500
++#define BCM6328_LED_INTERVAL_MS 20
++
++#define BCM6328_LED_INTV_MASK 0x3f
++#define BCM6328_LED_FAST_INTV_SHIFT 6
++#define BCM6328_LED_FAST_INTV_MASK (BCM6328_LED_INTV_MASK << \
++ BCM6328_LED_FAST_INTV_SHIFT)
++#define BCM6328_SERIAL_LED_EN BIT(12)
++#define BCM6328_SERIAL_LED_MUX BIT(13)
++#define BCM6328_SERIAL_LED_CLK_NPOL BIT(14)
++#define BCM6328_SERIAL_LED_DATA_PPOL BIT(15)
++#define BCM6328_SERIAL_LED_SHIFT_DIR BIT(16)
++#define BCM6328_LED_SHIFT_TEST BIT(30)
++#define BCM6328_LED_TEST BIT(31)
++
++#define BCM6328_LED_MODE_MASK 3
++#define BCM6328_LED_MODE_OFF 0
++#define BCM6328_LED_MODE_FAST 1
++#define BCM6328_LED_MODE_BLINK 2
++#define BCM6328_LED_MODE_ON 3
++#define BCM6328_LED_SHIFT(X) ((X) << 1)
++
++/**
++ * struct bcm6328_led - state container for bcm6328 based LEDs
++ * @cdev: LED class device for this LED
++ * @mem: memory resource
++ * @lock: memory lock
++ * @pin: LED pin number
++ * @blink_leds: blinking LEDs
++ * @blink_delay: blinking delay
++ * @active_low: LED is active low
++ */
++struct bcm6328_led {
++ struct led_classdev cdev;
++ void __iomem *mem;
++ spinlock_t *lock;
++ unsigned long pin;
++ unsigned long *blink_leds;
++ unsigned long *blink_delay;
++ bool active_low;
++};
++
++static void bcm6328_led_write(void __iomem *reg, unsigned long data)
++{
++ iowrite32be(data, reg);
++}
++
++static unsigned long bcm6328_led_read(void __iomem *reg)
++{
++ return ioread32be(reg);
++}
++
++/**
++ * LEDMode 64 bits / 24 LEDs
++ * bits [31:0] -> LEDs 8-23
++ * bits [47:32] -> LEDs 0-7
++ * bits [63:48] -> unused
++ */
++static unsigned long bcm6328_pin2shift(unsigned long pin)
++{
++ if (pin < 8)
++ return pin + 16; /* LEDs 0-7 (bits 47:32) */
++ else
++ return pin - 8; /* LEDs 8-23 (bits 31:0) */
++}
++
++static void bcm6328_led_mode(struct bcm6328_led *led, unsigned long value)
++{
++ void __iomem *mode;
++ unsigned long val, shift;
++
++ shift = bcm6328_pin2shift(led->pin);
++ if (shift / 16)
++ mode = led->mem + BCM6328_REG_MODE_HI;
++ else
++ mode = led->mem + BCM6328_REG_MODE_LO;
++
++ val = bcm6328_led_read(mode);
++ val &= ~(BCM6328_LED_MODE_MASK << BCM6328_LED_SHIFT(shift % 16));
++ val |= (value << BCM6328_LED_SHIFT(shift % 16));
++ bcm6328_led_write(mode, val);
++}
++
++static void bcm6328_led_set(struct led_classdev *led_cdev,
++ enum led_brightness value)
++{
++ struct bcm6328_led *led =
++ container_of(led_cdev, struct bcm6328_led, cdev);
++ unsigned long flags;
++
++ spin_lock_irqsave(led->lock, flags);
++ *(led->blink_leds) &= ~BIT(led->pin);
++ if ((led->active_low && value == LED_OFF) ||
++ (!led->active_low && value != LED_OFF))
++ bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
++ else
++ bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
++ spin_unlock_irqrestore(led->lock, flags);
++}
++
++static int bcm6328_blink_set(struct led_classdev *led_cdev,
++ unsigned long *delay_on, unsigned long *delay_off)
++{
++ struct bcm6328_led *led =
++ container_of(led_cdev, struct bcm6328_led, cdev);
++ unsigned long delay, flags;
++
++ if (!*delay_on)
++ *delay_on = BCM6328_LED_DEF_DELAY;
++ if (!*delay_off)
++ *delay_off = BCM6328_LED_DEF_DELAY;
++
++ if (*delay_on != *delay_off) {
++ dev_dbg(led_cdev->dev,
++ "fallback to soft blinking (delay_on != delay_off)\n");
++ return -EINVAL;
++ }
++
++ delay = *delay_on / BCM6328_LED_INTERVAL_MS;
++ if (delay == 0)
++ delay = 1;
++ else if (delay > BCM6328_LED_INTV_MASK) {
++ dev_dbg(led_cdev->dev,
++ "fallback to soft blinking (delay > %ums)\n",
++ BCM6328_LED_INTV_MASK * BCM6328_LED_INTERVAL_MS);
++ return -EINVAL;
++ }
++
++ spin_lock_irqsave(led->lock, flags);
++ if (*(led->blink_leds) == 0 ||
++ *(led->blink_leds) == BIT(led->pin) ||
++ *(led->blink_delay) == delay) {
++ unsigned long val;
++
++ *(led->blink_leds) |= BIT(led->pin);
++ *(led->blink_delay) = delay;
++
++ val = bcm6328_led_read(led->mem + BCM6328_REG_INIT);
++ val &= ~BCM6328_LED_FAST_INTV_MASK;
++ val |= (delay << BCM6328_LED_FAST_INTV_SHIFT);
++ bcm6328_led_write(led->mem + BCM6328_REG_INIT, val);
++
++ bcm6328_led_mode(led, BCM6328_LED_MODE_BLINK);
++
++ spin_unlock_irqrestore(led->lock, flags);
++ } else {
++ spin_unlock_irqrestore(led->lock, flags);
++ dev_dbg(led_cdev->dev,
++ "fallback to soft blinking (delay already set)\n");
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++static int bcm6328_hwled(struct device *dev, struct device_node *nc, u32 reg,
++ void __iomem *mem, spinlock_t *lock)
++{
++ int i, cnt;
++ unsigned long flags, val;
++
++ spin_lock_irqsave(lock, flags);
++ val = bcm6328_led_read(mem + BCM6328_REG_HWDIS);
++ val &= ~BIT(reg);
++ bcm6328_led_write(mem + BCM6328_REG_HWDIS, val);
++ spin_unlock_irqrestore(lock, flags);
++
++ /* Only LEDs 0-7 can be activity/link controlled */
++ if (reg >= 8)
++ return 0;
++
++ cnt = of_property_count_elems_of_size(nc, "brcm,link-signal-sources",
++ sizeof(u32));
++ for (i = 0; i < cnt; i++) {
++ u32 sel;
++ void __iomem *addr;
++
++ if (reg < 4)
++ addr = mem + BCM6328_REG_LNKACTSEL_LO;
++ else
++ addr = mem + BCM6328_REG_LNKACTSEL_HI;
++
++ of_property_read_u32_index(nc, "brcm,link-signal-sources", i,
++ &sel);
++
++ if (reg / 4 != sel / 4) {
++ dev_warn(dev, "invalid link signal source\n");
++ continue;
++ }
++
++ spin_lock_irqsave(lock, flags);
++ val = bcm6328_led_read(addr);
++ val |= (BIT(reg) << (((sel % 4) * 4) + 16));
++ bcm6328_led_write(addr, val);
++ spin_unlock_irqrestore(lock, flags);
++ }
++
++ cnt = of_property_count_elems_of_size(nc,
++ "brcm,activity-signal-sources",
++ sizeof(u32));
++ for (i = 0; i < cnt; i++) {
++ u32 sel;
++ void __iomem *addr;
++
++ if (reg < 4)
++ addr = mem + BCM6328_REG_LNKACTSEL_LO;
++ else
++ addr = mem + BCM6328_REG_LNKACTSEL_HI;
++
++ of_property_read_u32_index(nc, "brcm,activity-signal-sources",
++ i, &sel);
++
++ if (reg / 4 != sel / 4) {
++ dev_warn(dev, "invalid activity signal source\n");
++ continue;
++ }
++
++ spin_lock_irqsave(lock, flags);
++ val = bcm6328_led_read(addr);
++ val |= (BIT(reg) << ((sel % 4) * 4));
++ bcm6328_led_write(addr, val);
++ spin_unlock_irqrestore(lock, flags);
++ }
++
++ return 0;
++}
++
++static int bcm6328_led(struct device *dev, struct device_node *nc, u32 reg,
++ void __iomem *mem, spinlock_t *lock,
++ unsigned long *blink_leds, unsigned long *blink_delay)
++{
++ struct bcm6328_led *led;
++ unsigned long flags;
++ const char *state;
++ int rc;
++
++ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->pin = reg;
++ led->mem = mem;
++ led->lock = lock;
++ led->blink_leds = blink_leds;
++ led->blink_delay = blink_delay;
++
++ if (of_property_read_bool(nc, "active-low"))
++ led->active_low = true;
++
++ led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
++ led->cdev.default_trigger = of_get_property(nc,
++ "linux,default-trigger",
++ NULL);
++
++ if (!of_property_read_string(nc, "default-state", &state)) {
++ spin_lock_irqsave(lock, flags);
++ if (!strcmp(state, "on")) {
++ led->cdev.brightness = LED_FULL;
++ bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
++ } else if (!strcmp(state, "keep")) {
++ void __iomem *mode;
++ unsigned long val, shift;
++
++ shift = bcm6328_pin2shift(led->pin);
++ if (shift / 16)
++ mode = mem + BCM6328_REG_MODE_HI;
++ else
++ mode = mem + BCM6328_REG_MODE_LO;
++
++ val = bcm6328_led_read(mode) >> (shift % 16);
++ val &= BCM6328_LED_MODE_MASK;
++ if (val == BCM6328_LED_MODE_ON)
++ led->cdev.brightness = LED_FULL;
++ else {
++ led->cdev.brightness = LED_OFF;
++ bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
++ }
++ } else {
++ led->cdev.brightness = LED_OFF;
++ bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
++ }
++ spin_unlock_irqrestore(lock, flags);
++ }
++
++ led->cdev.brightness_set = bcm6328_led_set;
++ led->cdev.blink_set = bcm6328_blink_set;
++
++ rc = led_classdev_register(dev, &led->cdev);
++ if (rc < 0)
++ return rc;
++
++ dev_dbg(dev, "registered LED %s\n", led->cdev.name);
++
++ return 0;
++}
++
++static int bcm6328_leds_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *child;
++ struct resource *mem_r;
++ void __iomem *mem;
++ spinlock_t *lock;
++ unsigned long val, *blink_leds, *blink_delay;
++
++ mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem_r)
++ return -EINVAL;
++
++ mem = devm_ioremap_resource(dev, mem_r);
++ if (IS_ERR(mem))
++ return PTR_ERR(mem);
++
++ lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
++ if (!lock)
++ return -ENOMEM;
++
++ blink_leds = devm_kzalloc(dev, sizeof(*blink_leds), GFP_KERNEL);
++ if (!blink_leds)
++ return -ENOMEM;
++
++ blink_delay = devm_kzalloc(dev, sizeof(*blink_delay), GFP_KERNEL);
++ if (!blink_delay)
++ return -ENOMEM;
++
++ spin_lock_init(lock);
++
++ bcm6328_led_write(mem + BCM6328_REG_HWDIS, ~0);
++ bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_HI, 0);
++ bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
++
++ val = bcm6328_led_read(mem + BCM6328_REG_INIT);
++ val &= ~BCM6328_SERIAL_LED_EN;
++ if (of_property_read_bool(np, "brcm,serial-leds"))
++ val |= BCM6328_SERIAL_LED_EN;
++ bcm6328_led_write(mem + BCM6328_REG_INIT, val);
++
++ for_each_available_child_of_node(np, child) {
++ int rc;
++ u32 reg;
++
++ if (of_property_read_u32(child, "reg", ®))
++ continue;
++
++ if (reg >= BCM6328_LED_MAX_COUNT) {
++ dev_err(dev, "invalid LED (>= %d)\n",
++ BCM6328_LED_MAX_COUNT);
++ continue;
++ }
++
++ if (of_property_read_bool(child, "brcm,hardware-controlled"))
++ rc = bcm6328_hwled(dev, child, reg, mem, lock);
++ else
++ rc = bcm6328_led(dev, child, reg, mem, lock,
++ blink_leds, blink_delay);
++
++ if (rc < 0)
++ return rc;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id bcm6328_leds_of_match[] = {
++ { .compatible = "brcm,bcm6328-leds", },
++ { },
++};
++
++static struct platform_driver bcm6328_leds_driver = {
++ .probe = bcm6328_leds_probe,
++ .driver = {
++ .name = "leds-bcm6328",
++ .of_match_table = bcm6328_leds_of_match,
++ },
++};
++
++module_platform_driver(bcm6328_leds_driver);
++
++MODULE_AUTHOR("Álvaro Fernández Rojas <noltari at gmail.com>");
++MODULE_AUTHOR("Jonas Gorski <jogo at openwrt.org>");
++MODULE_DESCRIPTION("LED driver for BCM6328 controllers");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:leds-bcm6328");
diff --git a/target/linux/bmips/patches-4.1/021-leds-add-BCM6358-LED-driver.patch b/target/linux/bmips/patches-4.1/021-leds-add-BCM6358-LED-driver.patch
new file mode 100644
index 0000000..dead890
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/021-leds-add-BCM6358-LED-driver.patch
@@ -0,0 +1,293 @@
+From 589fca16c14adec7ebeb601e22850826e18b8f8d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari at gmail.com>
+Date: Thu, 21 May 2015 10:11:10 -0700
+Subject: [PATCH] leds: add BCM6358 LED driver
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+This adds support for the LED controller on Broadcom's BCM6358.
+
+Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
+Acked-by: Jacek Anaszewski <j.anaszewski at samsung.com>
+Signed-off-by: Bryan Wu <cooloney at gmail.com>
+---
+ drivers/leds/Kconfig | 8 ++
+ drivers/leds/Makefile | 1 +
+ drivers/leds/leds-bcm6358.c | 243 ++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 252 insertions(+)
+ create mode 100644 drivers/leds/leds-bcm6358.c
+
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -50,6 +50,14 @@ config LEDS_BCM6328
+ This option enables support for LEDs connected to the BCM6328
+ LED HW controller accessed via MMIO registers.
+
++config LEDS_BCM6358
++ tristate "LED Support for Broadcom BCM6358"
++ depends on LEDS_CLASS
++ depends on OF
++ help
++ This option enables support for LEDs connected to the BCM6358
++ LED HW controller accessed via MMIO registers.
++
+ config LEDS_LM3530
+ tristate "LCD Backlight driver for LM3530"
+ depends on LEDS_CLASS
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-trig
+ # LED Platform Drivers
+ obj-$(CONFIG_LEDS_88PM860X) += leds-88pm860x.o
+ obj-$(CONFIG_LEDS_BCM6328) += leds-bcm6328.o
++obj-$(CONFIG_LEDS_BCM6358) += leds-bcm6358.o
+ obj-$(CONFIG_LEDS_BD2802) += leds-bd2802.o
+ obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o
+ obj-$(CONFIG_LEDS_LM3530) += leds-lm3530.o
+--- /dev/null
++++ b/drivers/leds/leds-bcm6358.c
+@@ -0,0 +1,243 @@
++/*
++ * Driver for BCM6358 memory-mapped LEDs, based on leds-syscon.c
++ *
++ * Copyright 2015 Álvaro Fernández Rojas <noltari at gmail.com>
++ *
++ * 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/delay.h>
++#include <linux/io.h>
++#include <linux/leds.h>
++#include <linux/module.h>
++#include <linux/of.h>
++#include <linux/platform_device.h>
++#include <linux/spinlock.h>
++
++#define BCM6358_REG_MODE 0x0
++#define BCM6358_REG_CTRL 0x4
++
++#define BCM6358_SLED_CLKDIV_MASK 3
++#define BCM6358_SLED_CLKDIV_1 0
++#define BCM6358_SLED_CLKDIV_2 1
++#define BCM6358_SLED_CLKDIV_4 2
++#define BCM6358_SLED_CLKDIV_8 3
++
++#define BCM6358_SLED_POLARITY BIT(2)
++#define BCM6358_SLED_BUSY BIT(3)
++
++#define BCM6358_SLED_MAX_COUNT 32
++#define BCM6358_SLED_WAIT 100
++
++/**
++ * struct bcm6358_led - state container for bcm6358 based LEDs
++ * @cdev: LED class device for this LED
++ * @mem: memory resource
++ * @lock: memory lock
++ * @pin: LED pin number
++ * @active_low: LED is active low
++ */
++struct bcm6358_led {
++ struct led_classdev cdev;
++ void __iomem *mem;
++ spinlock_t *lock;
++ unsigned long pin;
++ bool active_low;
++};
++
++static void bcm6358_led_write(void __iomem *reg, unsigned long data)
++{
++ iowrite32be(data, reg);
++}
++
++static unsigned long bcm6358_led_read(void __iomem *reg)
++{
++ return ioread32be(reg);
++}
++
++static unsigned long bcm6358_led_busy(void __iomem *mem)
++{
++ unsigned long val;
++
++ while ((val = bcm6358_led_read(mem + BCM6358_REG_CTRL)) &
++ BCM6358_SLED_BUSY)
++ udelay(BCM6358_SLED_WAIT);
++
++ return val;
++}
++
++static void bcm6358_led_mode(struct bcm6358_led *led, unsigned long value)
++{
++ unsigned long val;
++
++ bcm6358_led_busy(led->mem);
++
++ val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
++ if ((led->active_low && value == LED_OFF) ||
++ (!led->active_low && value != LED_OFF))
++ val |= BIT(led->pin);
++ else
++ val &= ~(BIT(led->pin));
++ bcm6358_led_write(led->mem + BCM6358_REG_MODE, val);
++}
++
++static void bcm6358_led_set(struct led_classdev *led_cdev,
++ enum led_brightness value)
++{
++ struct bcm6358_led *led =
++ container_of(led_cdev, struct bcm6358_led, cdev);
++ unsigned long flags;
++
++ spin_lock_irqsave(led->lock, flags);
++ bcm6358_led_mode(led, value);
++ spin_unlock_irqrestore(led->lock, flags);
++}
++
++static int bcm6358_led(struct device *dev, struct device_node *nc, u32 reg,
++ void __iomem *mem, spinlock_t *lock)
++{
++ struct bcm6358_led *led;
++ unsigned long flags;
++ const char *state;
++ int rc;
++
++ led = devm_kzalloc(dev, sizeof(*led), GFP_KERNEL);
++ if (!led)
++ return -ENOMEM;
++
++ led->pin = reg;
++ led->mem = mem;
++ led->lock = lock;
++
++ if (of_property_read_bool(nc, "active-low"))
++ led->active_low = true;
++
++ led->cdev.name = of_get_property(nc, "label", NULL) ? : nc->name;
++ led->cdev.default_trigger = of_get_property(nc,
++ "linux,default-trigger",
++ NULL);
++
++ spin_lock_irqsave(lock, flags);
++ if (!of_property_read_string(nc, "default-state", &state)) {
++ if (!strcmp(state, "on")) {
++ led->cdev.brightness = LED_FULL;
++ } else if (!strcmp(state, "keep")) {
++ unsigned long val;
++
++ bcm6358_led_busy(led->mem);
++
++ val = bcm6358_led_read(led->mem + BCM6358_REG_MODE);
++ val &= BIT(led->pin);
++ if ((led->active_low && !val) ||
++ (!led->active_low && val))
++ led->cdev.brightness = LED_FULL;
++ else
++ led->cdev.brightness = LED_OFF;
++ } else {
++ led->cdev.brightness = LED_OFF;
++ }
++ } else {
++ led->cdev.brightness = LED_OFF;
++ }
++ bcm6358_led_mode(led, led->cdev.brightness);
++ spin_unlock_irqrestore(lock, flags);
++
++ led->cdev.brightness_set = bcm6358_led_set;
++
++ rc = led_classdev_register(dev, &led->cdev);
++ if (rc < 0)
++ return rc;
++
++ dev_dbg(dev, "registered LED %s\n", led->cdev.name);
++
++ return 0;
++}
++
++static int bcm6358_leds_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct device_node *np = pdev->dev.of_node;
++ struct device_node *child;
++ struct resource *mem_r;
++ void __iomem *mem;
++ spinlock_t *lock; /* memory lock */
++ unsigned long val;
++ u32 clk_div;
++
++ mem_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!mem_r)
++ return -EINVAL;
++
++ mem = devm_ioremap_resource(dev, mem_r);
++ if (IS_ERR(mem))
++ return PTR_ERR(mem);
++
++ lock = devm_kzalloc(dev, sizeof(*lock), GFP_KERNEL);
++ if (!lock)
++ return -ENOMEM;
++
++ spin_lock_init(lock);
++
++ val = bcm6358_led_busy(mem);
++ val &= ~(BCM6358_SLED_POLARITY | BCM6358_SLED_CLKDIV_MASK);
++ if (of_property_read_bool(np, "brcm,clk-dat-low"))
++ val |= BCM6358_SLED_POLARITY;
++ of_property_read_u32(np, "brcm,clk-div", &clk_div);
++ switch (clk_div) {
++ case 8:
++ val |= BCM6358_SLED_CLKDIV_8;
++ break;
++ case 4:
++ val |= BCM6358_SLED_CLKDIV_4;
++ break;
++ case 2:
++ val |= BCM6358_SLED_CLKDIV_2;
++ break;
++ default:
++ val |= BCM6358_SLED_CLKDIV_1;
++ break;
++ }
++ bcm6358_led_write(mem + BCM6358_REG_CTRL, val);
++
++ for_each_available_child_of_node(np, child) {
++ int rc;
++ u32 reg;
++
++ if (of_property_read_u32(child, "reg", ®))
++ continue;
++
++ if (reg >= BCM6358_SLED_MAX_COUNT) {
++ dev_err(dev, "invalid LED (%u >= %d)\n", reg,
++ BCM6358_SLED_MAX_COUNT);
++ continue;
++ }
++
++ rc = bcm6358_led(dev, child, reg, mem, lock);
++ if (rc < 0)
++ return rc;
++ }
++
++ return 0;
++}
++
++static const struct of_device_id bcm6358_leds_of_match[] = {
++ { .compatible = "brcm,bcm6358-leds", },
++ { },
++};
++
++static struct platform_driver bcm6358_leds_driver = {
++ .probe = bcm6358_leds_probe,
++ .driver = {
++ .name = "leds-bcm6358",
++ .of_match_table = bcm6358_leds_of_match,
++ },
++};
++
++module_platform_driver(bcm6358_leds_driver);
++
++MODULE_AUTHOR("Álvaro Fernández Rojas <noltari at gmail.com>");
++MODULE_DESCRIPTION("LED driver for BCM6358 controllers");
++MODULE_LICENSE("GPL v2");
++MODULE_ALIAS("platform:leds-bcm6358");
diff --git a/target/linux/bmips/patches-4.1/030-mtd-nand-add-common-DT-init-code.patch b/target/linux/bmips/patches-4.1/030-mtd-nand-add-common-DT-init-code.patch
new file mode 100644
index 0000000..9a5ad1f
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/030-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 at gmail.com>
+Date: Fri, 23 Jan 2015 00:22:27 -0800
+Subject: [PATCH] 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 at 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/bmips/patches-4.1/031-mtd-nand-add-NAND-driver-library-for-Broadcom-STB-NA.patch b/target/linux/bmips/patches-4.1/031-mtd-nand-add-NAND-driver-library-for-Broadcom-STB-NA.patch
new file mode 100644
index 0000000..552be21
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/031-mtd-nand-add-NAND-driver-library-for-Broadcom-STB-NA.patch
@@ -0,0 +1,2323 @@
+From 27c5b17cd1b10564fa36f8f51e4b4b41436ecc32 Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Fri, 6 Mar 2015 11:38:08 -0800
+Subject: [PATCH] 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 at gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+Tested-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ drivers/mtd/nand/Kconfig | 8 +
+ drivers/mtd/nand/Makefile | 1 +
+ drivers/mtd/nand/brcmnand/Makefile | 1 +
+ drivers/mtd/nand/brcmnand/brcmnand.c | 2195 ++++++++++++++++++++++++++++++++++
+ drivers/mtd/nand/brcmnand/brcmnand.h | 58 +
+ 5 files changed, 2263 insertions(+)
+ create mode 100644 drivers/mtd/nand/brcmnand/Makefile
+ create mode 100644 drivers/mtd/nand/brcmnand/brcmnand.c
+ create mode 100644 drivers/mtd/nand/brcmnand/brcmnand.h
+
+--- 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 @@
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
+--- /dev/null
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -0,0 +1,2195 @@
++/*
++ * 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;
++
++ 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;
++}
++
++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;
++ /*
++ * 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);
++ /* 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))
++ for (j = 0; j < FC_WORDS; j++, buf++)
++ *buf = brcmnand_read_fc(ctrl, j);
++
++ 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)
++ for (j = 0; j < FC_WORDS; j++, buf++)
++ brcmnand_write_fc(ctrl, j, *buf);
++ 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\n", 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);
++
++ 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;
++ static 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;
++ }
++
++ 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,58 @@
++/*
++ * 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 {
++ struct platform_device *pdev;
++ void *priv;
++};
++
++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__ */
diff --git a/target/linux/bmips/patches-4.1/032-mtd-brcmnand-add-support-for-STB-chips.patch b/target/linux/bmips/patches-4.1/032-mtd-brcmnand-add-support-for-STB-chips.patch
new file mode 100644
index 0000000..f0a3c19
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/032-mtd-brcmnand-add-support-for-STB-chips.patch
@@ -0,0 +1,68 @@
+From 303b4420ff1896b444017b5b0eb8252ce197797d Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Tue, 12 May 2015 17:00:57 -0700
+Subject: [PATCH] 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 at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/Makefile | 1 +
+ drivers/mtd/nand/brcmnand/brcmstb_nand.c | 44 ++++++++++++++++++++++++++++++++
+ 2 files changed, 45 insertions(+)
+ create mode 100644 drivers/mtd/nand/brcmnand/brcmstb_nand.c
+
+--- a/drivers/mtd/nand/brcmnand/Makefile
++++ b/drivers/mtd/nand/brcmnand/Makefile
+@@ -1 +1,2 @@
++obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmstb_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
+--- /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");
diff --git a/target/linux/bmips/patches-4.1/033-mtd-brcmnand-add-extra-SoC-support-to-library.patch b/target/linux/bmips/patches-4.1/033-mtd-brcmnand-add-extra-SoC-support-to-library.patch
new file mode 100644
index 0000000..afc8413
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/033-mtd-brcmnand-add-extra-SoC-support-to-library.patch
@@ -0,0 +1,167 @@
+From c26211d37f11d5913d9803fdede6d053f918ba7b Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Tue, 12 May 2015 12:09:28 -0700
+Subject: [PATCH] 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 at gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+Tested-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.c | 61 +++++++++++++++++++++++++++++++++---
+ drivers/mtd/nand/brcmnand/brcmnand.h | 15 +++++++++
+ 2 files changed, 71 insertions(+), 5 deletions(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -119,6 +119,9 @@ struct brcmnand_controller {
+ 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;
+@@ -965,6 +968,17 @@ static irqreturn_t brcmnand_ctlrdy_irq(i
+ 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;
+@@ -1153,12 +1167,18 @@ static void brcmnand_cmdfunc(struct mtd_
+ 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,
+@@ -1371,10 +1391,15 @@ static int brcmnand_read_by_pio(struct m
+ brcmnand_send_cmd(host, CMD_PAGE_READ);
+ brcmnand_waitfunc(mtd, chip);
+
+- if (likely(buf))
++ 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,
+@@ -1546,12 +1571,17 @@ static int brcmnand_write(struct mtd_inf
+ lower_32_bits(addr));
+ (void)brcmnand_read_reg(ctrl, BRCMNAND_CMD_ADDRESS);
+
+- if (buf)
++ if (buf) {
++ brcmnand_soc_data_bus_prepare(ctrl->soc);
++
+ for (j = 0; j < FC_WORDS; j++, buf++)
+ brcmnand_write_fc(ctrl, j, *buf);
+- else if (oob)
++
++ 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,
+@@ -1995,6 +2025,11 @@ static int brcmnand_resume(struct device
+ 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;
+@@ -2139,8 +2174,24 @@ int brcmnand_probe(struct platform_devic
+ return -ENODEV;
+ }
+
+- ret = devm_request_irq(dev, ctrl->irq, brcmnand_ctlrdy_irq, 0,
+- DRV_NAME, ctrl);
++ /*
++ * 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);
+--- a/drivers/mtd/nand/brcmnand/brcmnand.h
++++ b/drivers/mtd/nand/brcmnand/brcmnand.h
+@@ -23,8 +23,23 @@ struct dev_pm_ops;
+ struct brcmnand_soc {
+ struct platform_device *pdev;
+ void *priv;
++ 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)
+ {
+ /*
diff --git a/target/linux/bmips/patches-4.1/034-mtd-brcmnand-add-support-for-Broadcom-s-IPROC-family.patch b/target/linux/bmips/patches-4.1/034-mtd-brcmnand-add-support-for-Broadcom-s-IPROC-family.patch
new file mode 100644
index 0000000..550e320
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/034-mtd-brcmnand-add-support-for-Broadcom-s-IPROC-family.patch
@@ -0,0 +1,173 @@
+From ca22f040dd145fc4d8069ce174f6eb0bc3ebd19f Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Tue, 12 May 2015 12:12:02 -0700
+Subject: [PATCH] mtd: brcmnand: add support for Broadcom's IPROC family
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/Makefile | 3 +
+ drivers/mtd/nand/brcmnand/iproc_nand.c | 150 +++++++++++++++++++++++++++++++++
+ 2 files changed, 153 insertions(+)
+ create mode 100644 drivers/mtd/nand/brcmnand/iproc_nand.c
+
+--- a/drivers/mtd/nand/brcmnand/Makefile
++++ b/drivers/mtd/nand/brcmnand/Makefile
+@@ -1,2 +1,5 @@
++# 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) += brcmstb_nand.o
+ obj-$(CONFIG_MTD_NAND_BRCMNAND) += brcmnand.o
+--- /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_priv {
++ 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 *priv = soc->priv;
++ 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 *priv = soc->priv;
++ 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 *priv = soc->priv;
++ 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 *priv;
++ struct brcmnand_soc *soc;
++ struct resource *res;
++
++ soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
++ if (!soc)
++ return -ENOMEM;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ 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->pdev = pdev;
++ soc->priv = priv;
++ 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/bmips/patches-4.1/035-mtd-brcmnand-add-BCM63138-support.patch b/target/linux/bmips/patches-4.1/035-mtd-brcmnand-add-BCM63138-support.patch
new file mode 100644
index 0000000..b6c25a2
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/035-mtd-brcmnand-add-BCM63138-support.patch
@@ -0,0 +1,137 @@
+From f628ece6636c2f0354a52566cafdea6d2f963b3d Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Tue, 12 May 2015 12:13:14 -0700
+Subject: [PATCH] mtd: brcmnand: add BCM63138 support
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+Reviewed-by: Florian Fainelli <f.fainelli at gmail.com>
+Tested-by: Florian Fainelli <f.fainelli at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/Makefile | 1 +
+ drivers/mtd/nand/brcmnand/bcm63138_nand.c | 111 ++++++++++++++++++++++++++++++
+ 2 files changed, 112 insertions(+)
+ create mode 100644 drivers/mtd/nand/brcmnand/bcm63138_nand.c
+
+--- a/drivers/mtd/nand/brcmnand/Makefile
++++ b/drivers/mtd/nand/brcmnand/Makefile
+@@ -1,5 +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,111 @@
++/*
++ * 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_priv {
++ 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 *priv = soc->priv;
++ 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 *priv = soc->priv;
++ 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 *priv;
++ struct brcmnand_soc *soc;
++ struct resource *res;
++
++ soc = devm_kzalloc(dev, sizeof(*soc), GFP_KERNEL);
++ if (!soc)
++ return -ENOMEM;
++
++ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
++ if (!priv)
++ return -ENOMEM;
++
++ 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->pdev = pdev;
++ soc->priv = priv;
++ 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");
diff --git a/target/linux/bmips/patches-4.1/036-mtd-brcmnand-remove-double-new-line-from-print.patch b/target/linux/bmips/patches-4.1/036-mtd-brcmnand-remove-double-new-line-from-print.patch
new file mode 100644
index 0000000..ccf9e27
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/036-mtd-brcmnand-remove-double-new-line-from-print.patch
@@ -0,0 +1,25 @@
+From 802041247a0abbeaf1dddb8a8d56f491762ae357 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke at hauke-m.de>
+Date: Sun, 17 May 2015 17:41:00 +0200
+Subject: [PATCH] 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 at hauke-m.de>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -1765,7 +1765,7 @@ static void brcmnand_print_cfg(char *buf
+ else if (cfg->sector_size_1k)
+ sprintf(buf, ", BCH-%u (1KiB sector)", cfg->ecc_level << 1);
+ else
+- sprintf(buf, ", BCH-%u\n", cfg->ecc_level);
++ sprintf(buf, ", BCH-%u", cfg->ecc_level);
+ }
+
+ /*
diff --git a/target/linux/bmips/patches-4.1/037-mtd-brcmnand-do-not-make-local-variable-static.patch b/target/linux/bmips/patches-4.1/037-mtd-brcmnand-do-not-make-local-variable-static.patch
new file mode 100644
index 0000000..7d0f1d6
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/037-mtd-brcmnand-do-not-make-local-variable-static.patch
@@ -0,0 +1,26 @@
+From bcb83a19d3ac95fe3c0e79e942fb628120738853 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke at hauke-m.de>
+Date: Sun, 17 May 2015 17:41:01 +0200
+Subject: [PATCH] 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 at hauke-m.de>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -2069,7 +2069,7 @@ int brcmnand_probe(struct platform_devic
+ {
+ struct device *dev = &pdev->dev;
+ struct device_node *dn = dev->of_node, *child;
+- static struct brcmnand_controller *ctrl;
++ struct brcmnand_controller *ctrl;
+ struct resource *res;
+ int ret;
+
diff --git a/target/linux/bmips/patches-4.1/038-mtd-brcmnand-drop-unnecessary-initialization.patch b/target/linux/bmips/patches-4.1/038-mtd-brcmnand-drop-unnecessary-initialization.patch
new file mode 100644
index 0000000..fa22b03
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/038-mtd-brcmnand-drop-unnecessary-initialization.patch
@@ -0,0 +1,21 @@
+From 5e65d48b6049e090fdc57490db9d797124f2a9eb Mon Sep 17 00:00:00 2001
+From: Brian Norris <computersforpeace at gmail.com>
+Date: Thu, 28 May 2015 15:07:45 -0700
+Subject: [PATCH] mtd: brcmnand: drop unnecessary initialization
+
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -1887,7 +1887,7 @@ static int brcmnand_init_cs(struct brcmn
+ struct platform_device *pdev = host->pdev;
+ struct mtd_info *mtd;
+ struct nand_chip *chip;
+- int ret = 0;
++ int ret;
+ struct mtd_part_parser_data ppdata = { .of_node = dn };
+
+ ret = of_property_read_u32(dn, "reg", &host->cs);
diff --git a/target/linux/bmips/patches-4.1/039-mtd-brcmnand-Fix-misuse-of-IS_ENABLED.patch b/target/linux/bmips/patches-4.1/039-mtd-brcmnand-Fix-misuse-of-IS_ENABLED.patch
new file mode 100644
index 0000000..51e9065
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/039-mtd-brcmnand-Fix-misuse-of-IS_ENABLED.patch
@@ -0,0 +1,38 @@
+From ddb2c42b677eb2883e532f0928e445fc205d0019 Mon Sep 17 00:00:00 2001
+From: Axel Lin <axel.lin at ingics.com>
+Date: Thu, 6 Aug 2015 12:29:37 +0800
+Subject: [PATCH] mtd: brcmnand: Fix misuse of IS_ENABLED
+
+While IS_ENABLED() is perfectly fine for CONFIG_* symbols, it is not
+for other symbols such as __BIG_ENDIAN that is provided directly by
+the compiler.
+
+Switch to use CONFIG_CPU_BIG_ENDIAN instead of __BIG_ENDIAN.
+
+Fixes: 27c5b17cd1b1 ("mtd: nand: add NAND driver "library" for Broadcom STB NAND controller")
+Signed-off-by: Axel Lin <axel.lin at ingics.com>
+Signed-off-by: Brian Norris <computersforpeace at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.h | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.h
++++ b/drivers/mtd/nand/brcmnand/brcmnand.h
+@@ -50,7 +50,7 @@ static inline u32 brcmnand_readl(void __
+ * 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))
++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ return __raw_readl(addr);
+ else
+ return readl_relaxed(addr);
+@@ -59,7 +59,7 @@ static inline u32 brcmnand_readl(void __
+ static inline void brcmnand_writel(u32 val, void __iomem *addr)
+ {
+ /* See brcmnand_readl() comments */
+- if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(__BIG_ENDIAN))
++ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ __raw_writel(val, addr);
+ else
+ writel_relaxed(val, addr);
diff --git a/target/linux/bmips/patches-4.1/100-BMIPS-select-gpiolib.patch b/target/linux/bmips/patches-4.1/100-BMIPS-select-gpiolib.patch
new file mode 100644
index 0000000..d6b506a
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/100-BMIPS-select-gpiolib.patch
@@ -0,0 +1,10 @@
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -149,6 +149,7 @@ config BMIPS_GENERIC
+ select IRQ_CPU
+ select RAW_IRQ_ACCESSORS
+ select DMA_NONCOHERENT
++ select GPIOLIB
+ select SYS_SUPPORTS_32BIT_KERNEL
+ select SYS_SUPPORTS_LITTLE_ENDIAN
+ select SYS_SUPPORTS_BIG_ENDIAN
diff --git a/target/linux/bmips/patches-4.1/120-irqchip-add-support-for-bcm6345-style-periphery-irq-.patch b/target/linux/bmips/patches-4.1/120-irqchip-add-support-for-bcm6345-style-periphery-irq-.patch
new file mode 100644
index 0000000..4a5b629
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/120-irqchip-add-support-for-bcm6345-style-periphery-irq-.patch
@@ -0,0 +1,455 @@
+From 301744ecbeece89ab3a9d6beef7802fa22598f00 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Sun, 30 Nov 2014 14:53:12 +0100
+Subject: [PATCH 1/5] irqchip: add support for bcm6345-style periphery irq
+ controller
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+---
+ .../brcm,bcm6345-periph-intc.txt | 50 +++
+ drivers/irqchip/Kconfig | 4 +
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-bcm6345-periph.c | 339 ++++++++++++++++++++
+ include/linux/irqchip/irq-bcm6345-periph.h | 16 +
+ 5 files changed, 410 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-periph-intc.txt
+ create mode 100644 drivers/irqchip/irq-bcm6345-periph.c
+ create mode 100644 include/linux/irqchip/irq-bcm6345-periph.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-periph-intc.txt
+@@ -0,0 +1,50 @@
++Broadcom BCM6345 Level 1 periphery interrupt controller
++
++This block is a interrupt controller that is typically connected directly
++to one of the HW INT lines on each CPU. Every BCM63XX xDSL chip since
++BCM6345 has contained this hardware.
++
++Key elements of the hardware design include:
++
++- 32, 64, or 128 incoming level IRQ lines
++
++- All onchip peripherals are wired directly to an L2 input
++
++- A separate instance of the register set for each CPU, allowing individual
++ peripheral IRQs to be routed to any CPU
++
++- No atomic mask/unmask operations
++
++- No polarity/level/edge settings
++
++- No FIFO or priority encoder logic; software is expected to read all
++ 1-4 status words to determine which IRQs are pending
++
++Required properties:
++
++- compatible: Should be "brcm,bcm6345-periph-intc".
++- reg: Specifies the base physical address and size of the registers.
++ Multiple register addresses may be specified, and must match the amount of
++ parent interrupts.
++- interrupt-controller: Identifies the node as an interrupt controller.
++- #interrupt-cells: Specifies the number of cells needed to encode an interrupt
++ source, should be 1.
++- interrupt-parent: Specifies the phandle to the parent interrupt controller
++ this one is cascaded from.
++- interrupts: Specifies the interrupt line(s) in the interrupt-parent controller
++ node, valid values depend on the type of parent interrupt controller.
++ Multiple lines are used to route interrupts to different cpus, with the first
++ assumed to be for the boot CPU.
++
++Example:
++
++periph_intc: interrupt-controller at f0406800 {
++ compatible = "brcm,bcm6345-periph-intc";
++ reg = <0x10000020 0x10>, <0x10000030 0x10>;
++
++ interrupt-controller;
++ #interrupt-cells = <1>;
++
++ interrupt-parent = <&cpu_intc>;
++ interrupts = <2>, <3>;
++};
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -75,6 +75,10 @@ config BRCMSTB_L2_IRQ
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
++config BCM6345_PERIPH_IRQ
++ bool
++ select IRQ_DOMAIN
++
+ config DW_APB_ICTL
+ bool
+ select GENERIC_IRQ_CHIP
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_MVEBU) += irq-armada-
+ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
+ obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
+ obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
++obj-$(CONFIG_BCM6345_PERIPH_IRQ) += irq-bcm6345-periph.o
+ obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
+ obj-$(CONFIG_METAG) += irq-metag-ext.o
+ obj-$(CONFIG_METAG_PERFCOUNTER_IRQS) += irq-metag.o
+--- /dev/null
++++ b/drivers/irqchip/irq-bcm6345-periph.c
+@@ -0,0 +1,339 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2014 Jonas Gorski <jogo at openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqchip/irq-bcm6345-periph.h>
++#include <linux/kernel.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++#ifdef CONFIG_BCM63XX
++#include <asm/mach-bcm63xx/bcm63xx_irq.h>
++
++#define VIRQ_BASE IRQ_INTERNAL_BASE
++#else
++#define VIRQ_BASE 0
++#endif
++
++#include "irqchip.h"
++
++#define MAX_WORDS 4
++#define MAX_PARENT_IRQS 2
++#define IRQS_PER_WORD 32
++
++struct intc_block {
++ int parent_irq;
++ void __iomem *base;
++ void __iomem *en_reg[MAX_WORDS];
++ void __iomem *status_reg[MAX_WORDS];
++ u32 mask_cache[MAX_WORDS];
++};
++
++struct intc_data {
++ struct irq_chip chip;
++ struct intc_block block[MAX_PARENT_IRQS];
++
++ int num_words;
++
++ struct irq_domain *domain;
++ raw_spinlock_t lock;
++};
++
++static void bcm6345_periph_irq_handle(unsigned int irq, struct irq_desc *desc)
++{
++ struct intc_data *data = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ struct intc_block *block;
++ unsigned int idx;
++
++ chained_irq_enter(chip, desc);
++
++ for (idx = 0; idx < MAX_PARENT_IRQS; idx++)
++ if (irq == data->block[idx].parent_irq)
++ block = &data->block[idx];
++
++ for (idx = 0; idx < data->num_words; idx++) {
++ int base = idx * IRQS_PER_WORD;
++ unsigned long pending;
++ int hw_irq;
++
++ raw_spin_lock(&data->lock);
++ pending = __raw_readl(block->en_reg[idx]) &
++ __raw_readl(block->status_reg[idx]);
++ raw_spin_unlock(&data->lock);
++
++ for_each_set_bit(hw_irq, &pending, IRQS_PER_WORD) {
++ int virq;
++
++ virq = irq_find_mapping(data->domain, base + hw_irq);
++ generic_handle_irq(virq);
++ }
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void __bcm6345_periph_enable(struct intc_block *block, int reg, int bit,
++ bool enable)
++{
++ u32 val;
++
++ val = __raw_readl(block->en_reg[reg]);
++ if (enable)
++ val |= BIT(bit);
++ else
++ val &= ~BIT(bit);
++ __raw_writel(val, block->en_reg[reg]);
++}
++
++static void bcm6345_periph_irq_mask(struct irq_data *data)
++{
++ unsigned int i, reg, bit;
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ raw_spin_lock(&priv->lock);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_periph_irq_unmask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ unsigned int i, reg, bit;
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ raw_spin_lock(&priv->lock);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ if (block->mask_cache[reg] & BIT(bit))
++ __bcm6345_periph_enable(block, reg, bit, true);
++ else
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ raw_spin_unlock(&priv->lock);
++}
++
++#ifdef CONFIG_SMP
++static int bcm6345_periph_set_affinity(struct irq_data *data,
++ const struct cpumask *mask, bool force)
++{
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ struct intc_data *priv = data->domain->host_data;
++ unsigned int i, reg, bit;
++ unsigned long flags;
++ bool enabled;
++ int cpu;
++
++ reg = hwirq / IRQS_PER_WORD;
++ bit = hwirq % IRQS_PER_WORD;
++
++ /* we could route to more than one cpu, but performance
++ suffers, so fix it to one.
++ */
++ cpu = cpumask_any_and(mask, cpu_online_mask);
++ if (cpu >= nr_cpu_ids)
++ return -EINVAL;
++
++ if (cpu >= MAX_PARENT_IRQS)
++ return -EINVAL;
++
++ if (!priv->block[cpu].parent_irq)
++ return -EINVAL;
++
++ raw_spin_lock_irqsave(&priv->lock, flags);
++ enabled = !irqd_irq_masked(data);
++ for (i = 0; i < MAX_PARENT_IRQS; i++) {
++ struct intc_block *block = &priv->block[i];
++
++ if (!block->parent_irq)
++ break;
++
++ if (i == cpu) {
++ block->mask_cache[reg] |= BIT(bit);
++ __bcm6345_periph_enable(block, reg, bit, enabled);
++ } else {
++ block->mask_cache[reg] &= ~BIT(bit);
++ __bcm6345_periph_enable(block, reg, bit, false);
++ }
++ }
++ raw_spin_unlock_irqrestore(&priv->lock, flags);
++
++ return 0;
++}
++#endif
++
++static int bcm6345_periph_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hw)
++{
++ struct intc_data *priv = d->host_data;
++
++ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
++
++ return 0;
++}
++
++static const struct irq_domain_ops bcm6345_periph_domain_ops = {
++ .xlate = irq_domain_xlate_onecell,
++ .map = bcm6345_periph_map,
++};
++
++static int __init __bcm6345_periph_intc_init(struct device_node *node,
++ int num_blocks, int *irq,
++ void __iomem **base, int num_words)
++{
++ struct intc_data *data;
++ unsigned int i, w, status_offset;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ raw_spin_lock_init(&data->lock);
++
++ status_offset = num_words * sizeof(u32);
++
++ for (i = 0; i < num_blocks; i++) {
++ struct intc_block *block = &data->block[i];
++
++ block->parent_irq = irq[i];
++ block->base = base[i];
++
++ for (w = 0; w < num_words; w++) {
++ int word_offset = sizeof(u32) * ((num_words - w) - 1);
++
++ block->en_reg[w] = base[i] + word_offset;
++ block->status_reg[w] = base[i] + status_offset;
++ block->status_reg[w] += word_offset;
++
++ /* route all interrupts to line 0 by default */
++ if (i == 0)
++ block->mask_cache[w] = 0xffffffff;
++ }
++
++ irq_set_handler_data(block->parent_irq, data);
++ irq_set_chained_handler(block->parent_irq,
++ bcm6345_periph_irq_handle);
++ }
++
++ data->num_words = num_words;
++
++ data->chip.name = "bcm6345-periph-intc";
++ data->chip.irq_mask = bcm6345_periph_irq_mask;
++ data->chip.irq_unmask = bcm6345_periph_irq_unmask;
++
++#ifdef CONFIG_SMP
++ if (num_blocks > 1)
++ data->chip.irq_set_affinity = bcm6345_periph_set_affinity;
++#endif
++
++ data->domain = irq_domain_add_simple(node, IRQS_PER_WORD * num_words,
++ VIRQ_BASE,
++ &bcm6345_periph_domain_ops, data);
++ if (!data->domain) {
++ kfree(data);
++ return -EINVAL;
++ }
++
++ return 0;
++}
++
++void __init bcm6345_periph_intc_init(int num_blocks, int *irq,
++ void __iomem **base, int num_words)
++{
++ __bcm6345_periph_intc_init(NULL, num_blocks, irq, base, num_words);
++}
++
++#ifdef CONFIG_OF
++static int __init bcm6345_periph_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ struct resource res;
++ int num_irqs, ret = -EINVAL;
++ int irqs[MAX_PARENT_IRQS] = { 0 };
++ void __iomem *bases[MAX_PARENT_IRQS] = { NULL };
++ int words = 0;
++ int i;
++
++ num_irqs = of_irq_count(node);
++
++ if (num_irqs < 1 || num_irqs > MAX_PARENT_IRQS)
++ return -EINVAL;
++
++ for (i = 0; i < num_irqs; i++) {
++ resource_size_t size;
++
++ irqs[i] = irq_of_parse_and_map(node, i);
++ if (!irqs[i])
++ goto out_unmap;
++
++ if (of_address_to_resource(node, i, &res))
++ goto out_unmap;
++
++ size = resource_size(&res);
++ switch (size) {
++ case 8:
++ case 16:
++ case 32:
++ size = size / 8;
++ break;
++ default:
++ goto out_unmap;
++ }
++
++ if (words && words != size) {
++ ret = -EINVAL;
++ goto out_unmap;
++ }
++ words = size;
++
++ bases[i] = of_iomap(node, i);
++ if (!bases[i]) {
++ ret = -ENOMEM;
++ goto out_unmap;
++ }
++ }
++
++ ret = __bcm6345_periph_intc_init(node, num_irqs, irqs, bases, words);
++ if (!ret)
++ return 0;
++
++out_unmap:
++ for (i = 0; i < num_irqs; i++) {
++ iounmap(bases[i]);
++ irq_dispose_mapping(irqs[i]);
++ }
++
++ return ret;
++}
++
++IRQCHIP_DECLARE(bcm6345_periph_intc, "brcm,bcm6345-periph-intc",
++ bcm6345_periph_of_init);
++#endif
+--- /dev/null
++++ b/include/linux/irqchip/irq-bcm6345-periph.h
+@@ -0,0 +1,16 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2008 Maxime Bizon <mbizon at freebox.fr>
++ * Copyright (C) 2008 Nicolas Schichan <nschichan at freebox.fr>
++ */
++
++#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H
++#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H
++
++void bcm6345_periph_intc_init(int num_blocks, int *irq, void __iomem **base,
++ int num_words);
++
++#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_PERIPH_H */
diff --git a/target/linux/bmips/patches-4.1/121-irqchip-add-support-for-bcm6345-style-external-inter.patch b/target/linux/bmips/patches-4.1/121-irqchip-add-support-for-bcm6345-style-external-inter.patch
new file mode 100644
index 0000000..7eca81b
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/121-irqchip-add-support-for-bcm6345-style-external-inter.patch
@@ -0,0 +1,380 @@
+From cf908990d4a8ccdb73ee4484aa8cadad379ca314 Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Sun, 30 Nov 2014 14:54:27 +0100
+Subject: [PATCH 2/5] irqchip: add support for bcm6345-style external
+ interrupt controller
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+---
+ .../interrupt-controller/brcm,bcm6345-ext-intc.txt | 29 ++
+ drivers/irqchip/Kconfig | 4 +
+ drivers/irqchip/Makefile | 1 +
+ drivers/irqchip/irq-bcm6345-ext.c | 287 ++++++++++++++++++++
+ include/linux/irqchip/irq-bcm6345-ext.h | 14 +
+ 5 files changed, 335 insertions(+)
+ create mode 100644 Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
+ create mode 100644 drivers/irqchip/irq-bcm6345-ext.c
+ create mode 100644 include/linux/irqchip/irq-bcm6345-ext.h
+
+--- /dev/null
++++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm6345-ext-intc.txt
+@@ -0,0 +1,29 @@
++Broadcom BCM6345-style external interrupt controller
++
++Required properties:
++
++- compatible: Should be "brcm,bcm6345-l2-intc".
++- reg: Specifies the base physical addresses and size of the registers.
++- interrupt-controller: identifies the node as an interrupt controller.
++- #interrupt-cells: Specifies the number of cells needed to encode an interrupt
++ source, Should be 2.
++- interrupt-parent: Specifies the phandle to the parent interrupt controller
++ this one is cascaded from.
++- interrupts: Specifies the interrupt line(s) in the interrupt-parent controller
++ node, valid values depend on the type of parent interrupt controller.
++
++Optional properties:
++
++- brcm,field-width: Size of each field (mask, clear, sense, ...) in bits in the
++ register. Defaults to 4.
++
++Example:
++
++ext_intc: interrupt-controller at 10000018 {
++ compatible = "brcm,bcm6345-l2-intc";
++ interrupt-parent = <&periph_intc>;
++ #interrupt-cells = <2>;
++ reg = <0x10000018 0x4>;
++ interrupt-controller;
++ interrupts = <24>, <25>, <26>, <27>;
++};
+--- a/drivers/irqchip/Kconfig
++++ b/drivers/irqchip/Kconfig
+@@ -75,6 +75,10 @@ config BRCMSTB_L2_IRQ
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
++config BCM6345_EXT_IRQ
++ bool
++ select IRQ_DOMAIN
++
+ config BCM6345_PERIPH_IRQ
+ bool
+ select IRQ_DOMAIN
+--- a/drivers/irqchip/Makefile
++++ b/drivers/irqchip/Makefile
+@@ -8,6 +8,7 @@ obj-$(CONFIG_ARCH_MVEBU) += irq-armada-
+ obj-$(CONFIG_ARCH_MXS) += irq-mxs.o
+ obj-$(CONFIG_ARCH_TEGRA) += irq-tegra.o
+ obj-$(CONFIG_ARCH_S3C24XX) += irq-s3c24xx.o
++obj-$(CONFIG_BCM6345_EXT_IRQ) += irq-bcm6345-ext.o
+ obj-$(CONFIG_BCM6345_PERIPH_IRQ) += irq-bcm6345-periph.o
+ obj-$(CONFIG_DW_APB_ICTL) += irq-dw-apb-ictl.o
+ obj-$(CONFIG_METAG) += irq-metag-ext.o
+--- /dev/null
++++ b/drivers/irqchip/irq-bcm6345-ext.c
+@@ -0,0 +1,287 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2014 Jonas Gorski <jogo at openwrt.org>
++ */
++
++#include <linux/ioport.h>
++#include <linux/irq.h>
++#include <linux/irqchip/chained_irq.h>
++#include <linux/irqchip/irq-bcm6345-ext.h>
++#include <linux/kernel.h>
++#include <linux/of.h>
++#include <linux/of_irq.h>
++#include <linux/of_address.h>
++#include <linux/slab.h>
++#include <linux/spinlock.h>
++
++#include "irqchip.h"
++
++#ifdef CONFIG_BCM63XX
++#include <asm/mach-bcm63xx/bcm63xx_irq.h>
++
++#define VIRQ_BASE IRQ_EXTERNAL_BASE
++#else
++#define VIRQ_BASE 0
++#endif
++
++#define MAX_IRQS 4
++
++#define EXTIRQ_CFG_SENSE 0
++#define EXTIRQ_CFG_STAT 1
++#define EXTIRQ_CFG_CLEAR 2
++#define EXTIRQ_CFG_MASK 3
++#define EXTIRQ_CFG_BOTHEDGE 4
++#define EXTIRQ_CFG_LEVELSENSE 5
++
++struct intc_data {
++ struct irq_chip chip;
++ struct irq_domain *domain;
++ raw_spinlock_t lock;
++
++ int parent_irq[MAX_IRQS];
++ void __iomem *reg;
++ int shift;
++};
++
++static void bcm6345_ext_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
++{
++ struct intc_data *data = irq_desc_get_handler_data(desc);
++ struct irq_chip *chip = irq_desc_get_chip(desc);
++ unsigned int idx;
++
++ chained_irq_enter(chip, desc);
++
++ for (idx = 0; idx < MAX_IRQS; idx++) {
++ if (data->parent_irq[idx] != irq)
++ continue;
++
++ generic_handle_irq(irq_find_mapping(data->domain, idx));
++ }
++
++ chained_irq_exit(chip, desc);
++}
++
++static void bcm6345_ext_intc_irq_ack(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg |= hwirq << (EXTIRQ_CFG_CLEAR * priv->shift);
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_ext_intc_irq_mask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg &= ~(hwirq << (EXTIRQ_CFG_MASK * priv->shift));
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static void bcm6345_ext_intc_irq_unmask(struct irq_data *data)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ u32 reg;
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++ reg |= hwirq << (EXTIRQ_CFG_MASK * priv->shift);
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++}
++
++static int bcm6345_ext_intc_set_type(struct irq_data *data,
++ unsigned int flow_type)
++{
++ struct intc_data *priv = data->domain->host_data;
++ irq_hw_number_t hwirq = irqd_to_hwirq(data);
++ bool levelsense = 0, sense = 0, bothedge = 0;
++ u32 reg;
++
++ flow_type &= IRQ_TYPE_SENSE_MASK;
++
++ if (flow_type == IRQ_TYPE_NONE)
++ flow_type = IRQ_TYPE_LEVEL_LOW;
++
++ switch (flow_type) {
++ case IRQ_TYPE_EDGE_BOTH:
++ bothedge = 1;
++ break;
++
++ case IRQ_TYPE_EDGE_RISING:
++ break;
++
++ case IRQ_TYPE_EDGE_FALLING:
++ sense = 1;
++ break;
++
++ case IRQ_TYPE_LEVEL_HIGH:
++ levelsense = 1;
++ sense = 1;
++ break;
++
++ case IRQ_TYPE_LEVEL_LOW:
++ levelsense = 1;
++ break;
++
++ default:
++ pr_err("bogus flow type combination given!\n");
++ return -EINVAL;
++ }
++
++ raw_spin_lock(&priv->lock);
++ reg = __raw_readl(priv->reg);
++
++ if (levelsense)
++ reg |= hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_LEVELSENSE * priv->shift));
++ if (sense)
++ reg |= hwirq << (EXTIRQ_CFG_SENSE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_SENSE * priv->shift));
++ if (bothedge)
++ reg |= hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift);
++ else
++ reg &= ~(hwirq << (EXTIRQ_CFG_BOTHEDGE * priv->shift));
++
++ __raw_writel(reg, priv->reg);
++ raw_spin_unlock(&priv->lock);
++
++ irqd_set_trigger_type(data, flow_type);
++ if (flow_type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
++ __irq_set_handler_locked(data->irq, handle_level_irq);
++ else
++ __irq_set_handler_locked(data->irq, handle_edge_irq);
++
++ return 0;
++}
++
++static int bcm6345_ext_intc_map(struct irq_domain *d, unsigned int irq,
++ irq_hw_number_t hw)
++{
++ struct intc_data *priv = d->host_data;
++
++ irq_set_chip_and_handler(irq, &priv->chip, handle_level_irq);
++
++ return 0;
++}
++
++static const struct irq_domain_ops bcm6345_ext_domain_ops = {
++ .xlate = irq_domain_xlate_twocell,
++ .map = bcm6345_ext_intc_map,
++};
++
++static int __init __bcm6345_ext_intc_init(struct device_node *node,
++ int num_irqs, int *irqs,
++ void __iomem *reg, int shift)
++{
++ struct intc_data *data;
++ unsigned int i;
++ int start = VIRQ_BASE;
++
++ data = kzalloc(sizeof(*data), GFP_KERNEL);
++ if (!data)
++ return -ENOMEM;
++
++ raw_spin_lock_init(&data->lock);
++
++ for (i = 0; i < num_irqs; i++) {
++ data->parent_irq[i] = irqs[i];
++
++ irq_set_handler_data(irqs[i], data);
++ irq_set_chained_handler(irqs[i], bcm6345_ext_intc_irq_handle);
++ }
++
++ data->reg = reg;
++
++ data->chip.name = "bcm6345-ext-intc";
++ data->chip.irq_ack = bcm6345_ext_intc_irq_ack;
++ data->chip.irq_mask = bcm6345_ext_intc_irq_mask;
++ data->chip.irq_unmask = bcm6345_ext_intc_irq_unmask;
++ data->chip.irq_set_type = bcm6345_ext_intc_set_type;
++
++ /*
++ * If we have less than 4 irqs, this is the second controller on
++ * bcm63xx. So increase the VIRQ start to not overlap with the first
++ * one, but only do so if we actually use a non-zero start.
++ *
++ * This can be removed when bcm63xx has no legacy users anymore.
++ */
++ if (start && num_irqs < 4)
++ start += 4;
++
++ data->domain = irq_domain_add_simple(node, num_irqs, start,
++ &bcm6345_ext_domain_ops, data);
++ if (!data->domain) {
++ kfree(data);
++ return -ENOMEM;
++ }
++
++ return 0;
++}
++
++void __init bcm6345_ext_intc_init(int num_irqs, int *irqs, void __iomem *reg,
++ int shift)
++{
++ __bcm6345_ext_intc_init(NULL, num_irqs, irqs, reg, shift);
++}
++
++#ifdef CONFIG_OF
++static int __init bcm6345_ext_intc_of_init(struct device_node *node,
++ struct device_node *parent)
++{
++ int num_irqs, ret = -EINVAL;
++ unsigned i;
++ void __iomem *base;
++ int irqs[MAX_IRQS] = { 0 };
++ u32 shift;
++
++ num_irqs = of_irq_count(node);
++
++ if (!num_irqs || num_irqs > MAX_IRQS)
++ return -EINVAL;
++
++ if (of_property_read_u32(node, "brcm,field-width", &shift))
++ shift = 4;
++
++ for (i = 0; i < num_irqs; i++) {
++ irqs[i] = irq_of_parse_and_map(node, i);
++ if (!irqs[i]) {
++ ret = -ENOMEM;
++ goto out_unmap;
++ }
++ }
++
++ base = of_iomap(node, 0);
++ if (!base)
++ goto out_unmap;
++
++ ret = __bcm6345_ext_intc_init(node, num_irqs, irqs, base, shift);
++ if (!ret)
++ return 0;
++out_unmap:
++ iounmap(base);
++
++ for (i = 0; i < num_irqs; i++)
++ irq_dispose_mapping(irqs[i]);
++
++ return ret;
++}
++
++IRQCHIP_DECLARE(bcm6345_ext_intc, "brcm,bcm6345-ext-intc",
++ bcm6345_ext_intc_of_init);
++#endif
+--- /dev/null
++++ b/include/linux/irqchip/irq-bcm6345-ext.h
+@@ -0,0 +1,14 @@
++/*
++ * This file is subject to the terms and conditions of the GNU General Public
++ * License. See the file "COPYING" in the main directory of this archive
++ * for more details.
++ *
++ * Copyright (C) 2014 Jonas Gorski <jogo at openwrt.org>
++ */
++
++#ifndef __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H
++#define __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H
++
++void bcm6345_ext_intc_init(int n_irqs, int *irqs, void __iomem *reg, int shift);
++
++#endif /* __INCLUDE_LINUX_IRQCHIP_IRQ_BCM6345_EXT_H */
diff --git a/target/linux/bmips/patches-4.1/122-MIPS-BMIPS-enable-bcm6345-irq.patch b/target/linux/bmips/patches-4.1/122-MIPS-BMIPS-enable-bcm6345-irq.patch
new file mode 100644
index 0000000..697c20a
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/122-MIPS-BMIPS-enable-bcm6345-irq.patch
@@ -0,0 +1,12 @@
+--- a/arch/mips/Kconfig
++++ b/arch/mips/Kconfig
+@@ -147,6 +147,9 @@ config BMIPS_GENERIC
+ select BCM7120_L2_IRQ
+ select BRCMSTB_L2_IRQ
+ select IRQ_CPU
++ select BCM6345_EXT_IRQ
++ select BCM6345_PERIPH_IRQ
++ select IRQ_DOMAIN
+ select RAW_IRQ_ACCESSORS
+ select DMA_NONCOHERENT
+ select GPIOLIB
diff --git a/target/linux/bmips/patches-4.1/200-irqchip-bcm6345-style-peripher-irq-ensure-disabled.patch b/target/linux/bmips/patches-4.1/200-irqchip-bcm6345-style-peripher-irq-ensure-disabled.patch
new file mode 100644
index 0000000..7aa6128
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/200-irqchip-bcm6345-style-peripher-irq-ensure-disabled.patch
@@ -0,0 +1,12 @@
+--- a/drivers/irqchip/irq-bcm6345-periph.c
++++ b/drivers/irqchip/irq-bcm6345-periph.c
+@@ -236,6 +236,9 @@ static int __init __bcm6345_periph_intc_
+ /* route all interrupts to line 0 by default */
+ if (i == 0)
+ block->mask_cache[w] = 0xffffffff;
++
++ /* ensure all interrupts are disabled */
++ __raw_writel(0, block->en_reg[w]);
+ }
+
+ irq_set_handler_data(block->parent_irq, data);
diff --git a/target/linux/bmips/patches-4.1/210-MIPS-BMIPS-BCM3368-basic-support.patch b/target/linux/bmips/patches-4.1/210-MIPS-BMIPS-BCM3368-basic-support.patch
new file mode 100644
index 0000000..f50bd73
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/210-MIPS-BMIPS-BCM3368-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -47,6 +47,11 @@ static void kbase_setup(void)
+ ebase = kbase;
+ }
+
++static void bcm3368_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm3384_viper_quirks(void)
+ {
+ /*
+@@ -101,6 +106,7 @@ static void bcm6368_quirks(void)
+ }
+
+ static const struct bmips_quirk bmips_quirk_list[] = {
++ { "brcm,bcm3368", &bcm3368_quirks },
+ { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
diff --git a/target/linux/bmips/patches-4.1/212-MIPS-BMIPS-BCM6338-basic-support.patch b/target/linux/bmips/patches-4.1/212-MIPS-BMIPS-BCM6338-basic-support.patch
new file mode 100644
index 0000000..4c7131e
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/212-MIPS-BMIPS-BCM6338-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -100,6 +100,11 @@ static void bcm6328_quirks(void)
+ bcm63xx_fixup_cpu1();
+ }
+
++static void bcm6338_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm6368_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -110,6 +115,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
++ { "brcm,bcm6338", &bcm6338_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+ };
diff --git a/target/linux/bmips/patches-4.1/213-MIPS-BMIPS-BCM6345-basic-support.patch b/target/linux/bmips/patches-4.1/213-MIPS-BMIPS-BCM6345-basic-support.patch
new file mode 100644
index 0000000..75aeef4
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/213-MIPS-BMIPS-BCM6345-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -105,6 +105,11 @@ static void bcm6338_quirks(void)
+ bmips_smp_enabled = 0;
+ }
+
++static void bcm6345_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm6368_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -116,6 +121,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
+ { "brcm,bcm6338", &bcm6338_quirks },
++ { "brcm,bcm6345", &bcm6345_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+ };
diff --git a/target/linux/bmips/patches-4.1/214-MIPS-BMIPS-BCM6348-basic-support.patch b/target/linux/bmips/patches-4.1/214-MIPS-BMIPS-BCM6348-basic-support.patch
new file mode 100644
index 0000000..fdf1e0e
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/214-MIPS-BMIPS-BCM6348-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -110,6 +110,11 @@ static void bcm6345_quirks(void)
+ bmips_smp_enabled = 0;
+ }
+
++static void bcm6348_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm6368_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -122,6 +127,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm6328", &bcm6328_quirks },
+ { "brcm,bcm6338", &bcm6338_quirks },
+ { "brcm,bcm6345", &bcm6345_quirks },
++ { "brcm,bcm6348", &bcm6348_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+ };
diff --git a/target/linux/bmips/patches-4.1/215-MIPS-BMIPS-BCM6358-basic-support.patch b/target/linux/bmips/patches-4.1/215-MIPS-BMIPS-BCM6358-basic-support.patch
new file mode 100644
index 0000000..1cdf84c
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/215-MIPS-BMIPS-BCM6358-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -115,6 +115,11 @@ static void bcm6348_quirks(void)
+ bmips_smp_enabled = 0;
+ }
+
++static void bcm6358_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm6368_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -128,6 +133,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm6338", &bcm6338_quirks },
+ { "brcm,bcm6345", &bcm6345_quirks },
+ { "brcm,bcm6348", &bcm6348_quirks },
++ { "brcm,bcm6358", &bcm6358_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+ };
diff --git a/target/linux/bmips/patches-4.1/216-MIPS-BMIPS-BCM6362-basic-support.patch b/target/linux/bmips/patches-4.1/216-MIPS-BMIPS-BCM6362-basic-support.patch
new file mode 100644
index 0000000..2bdcd04
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/216-MIPS-BMIPS-BCM6362-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -120,6 +120,11 @@ static void bcm6358_quirks(void)
+ bmips_smp_enabled = 0;
+ }
+
++static void bcm6362_quirks(void)
++{
++ bcm63xx_fixup_cpu1();
++}
++
+ static void bcm6368_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -134,6 +139,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm6345", &bcm6345_quirks },
+ { "brcm,bcm6348", &bcm6348_quirks },
+ { "brcm,bcm6358", &bcm6358_quirks },
++ { "brcm,bcm6362", &bcm6362_quirks },
+ { "brcm,bcm6368", &bcm6368_quirks },
+ { },
+ };
diff --git a/target/linux/bmips/patches-4.1/217-MIPS-BMIPS-BCM63268-basic-support.patch b/target/linux/bmips/patches-4.1/217-MIPS-BMIPS-BCM63268-basic-support.patch
new file mode 100644
index 0000000..06de96e
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/217-MIPS-BMIPS-BCM63268-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -91,6 +91,11 @@ static void bcm63xx_fixup_cpu1(void)
+ cpumask_set_cpu(1, &bmips_booted_mask);
+ }
+
++static void bcm63268_quirks(void)
++{
++ bcm63xx_fixup_cpu1();
++}
++
+ static void bcm6328_quirks(void)
+ {
+ /* Check CPU1 status in OTP (it is usually disabled) */
+@@ -135,6 +140,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
++ { "brcm,bcm63268", &bcm63268_quirks },
+ { "brcm,bcm6338", &bcm6338_quirks },
+ { "brcm,bcm6345", &bcm6345_quirks },
+ { "brcm,bcm6348", &bcm6348_quirks },
diff --git a/target/linux/bmips/patches-4.1/218-MIPS-BMIPS-BCM6318-basic-support.patch b/target/linux/bmips/patches-4.1/218-MIPS-BMIPS-BCM6318-basic-support.patch
new file mode 100644
index 0000000..091bc7d
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/218-MIPS-BMIPS-BCM6318-basic-support.patch
@@ -0,0 +1,22 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -91,6 +91,11 @@ static void bcm63xx_fixup_cpu1(void)
+ cpumask_set_cpu(1, &bmips_booted_mask);
+ }
+
++static void bcm6318_quirks(void)
++{
++ bmips_smp_enabled = 0;
++}
++
+ static void bcm63268_quirks(void)
+ {
+ bcm63xx_fixup_cpu1();
+@@ -139,6 +144,7 @@ static const struct bmips_quirk bmips_qu
+ { "brcm,bcm3368", &bcm3368_quirks },
+ { "brcm,bcm3384-viper", &bcm3384_viper_quirks },
+ { "brcm,bcm33843-viper", &bcm3384_viper_quirks },
++ { "brcm,bcm6318", &bcm6318_quirks },
+ { "brcm,bcm6328", &bcm6328_quirks },
+ { "brcm,bcm63268", &bcm63268_quirks },
+ { "brcm,bcm6338", &bcm6338_quirks },
diff --git a/target/linux/bmips/patches-4.1/220-MIPS-BMIPS-uart-hacks.patch b/target/linux/bmips/patches-4.1/220-MIPS-BMIPS-uart-hacks.patch
new file mode 100644
index 0000000..4b1446a
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/220-MIPS-BMIPS-uart-hacks.patch
@@ -0,0 +1,26 @@
+--- a/arch/mips/bmips/setup.c
++++ b/arch/mips/bmips/setup.c
+@@ -241,4 +241,4 @@ static int __init plat_dev_init(void)
+ return 0;
+ }
+
+-device_initcall(plat_dev_init);
++arch_initcall(plat_dev_init);
+--- a/drivers/tty/serial/bcm63xx_uart.c
++++ b/drivers/tty/serial/bcm63xx_uart.c
+@@ -905,14 +905,7 @@ static int __init bcm_uart_init(void)
+ return ret;
+ }
+
+-static void __exit bcm_uart_exit(void)
+-{
+- platform_driver_unregister(&bcm_uart_platform_driver);
+- uart_unregister_driver(&bcm_uart_driver);
+-}
+-
+-module_init(bcm_uart_init);
+-module_exit(bcm_uart_exit);
++subsys_initcall(bcm_uart_init);
+
+ MODULE_AUTHOR("Maxime Bizon <mbizon at freebox.fr>");
+ MODULE_DESCRIPTION("Broadcom 63xx integrated uart driver");
diff --git a/target/linux/bmips/patches-4.1/221-MIPS-BMIPS-export-dma_mem_page.patch b/target/linux/bmips/patches-4.1/221-MIPS-BMIPS-export-dma_mem_page.patch
new file mode 100644
index 0000000..81a9f15
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/221-MIPS-BMIPS-export-dma_mem_page.patch
@@ -0,0 +1,10 @@
+--- a/arch/mips/bmips/dma.c
++++ b/arch/mips/bmips/dma.c
+@@ -61,6 +61,7 @@ dma_addr_t plat_map_dma_mem_page(struct
+ {
+ return bmips_phys_to_dma(dev, page_to_phys(page));
+ }
++EXPORT_SYMBOL(plat_map_dma_mem_page);
+
+ unsigned long plat_dma_addr_to_phys(struct device *dev, dma_addr_t dma_addr)
+ {
diff --git a/target/linux/bmips/patches-4.1/222-MIPS-BMIPS-ioremap.patch b/target/linux/bmips/patches-4.1/222-MIPS-BMIPS-ioremap.patch
new file mode 100644
index 0000000..a2a17b1
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/222-MIPS-BMIPS-ioremap.patch
@@ -0,0 +1,35 @@
+--- /dev/null
++++ b/arch/mips/include/asm/mach-bmips/ioremap.h
+@@ -0,0 +1,32 @@
++#ifndef __ASM_MACH_BMIPS_IOREMAP_H
++#define __ASM_MACH_BMIPS_IOREMAP_H
++
++#include <linux/types.h>
++
++static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr, phys_addr_t size)
++{
++ return phys_addr;
++}
++
++static inline int is_bmips_internal_registers(phys_addr_t offset)
++{
++ if (offset >= 0xfff00000)
++ return 1;
++
++ return 0;
++}
++
++static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
++ unsigned long flags)
++{
++ if (is_bmips_internal_registers(offset))
++ return (void __iomem *)offset;
++ return NULL;
++}
++
++static inline int plat_iounmap(const volatile void __iomem *addr)
++{
++ return is_bmips_internal_registers((unsigned long)addr);
++}
++
++#endif /* __ASM_MACH_BMIPS_IOREMAP_H */
diff --git a/target/linux/bmips/patches-4.1/223-MIPS-BMIPS-Revert-provide-a-plat_post_dma_flush-hook.patch b/target/linux/bmips/patches-4.1/223-MIPS-BMIPS-Revert-provide-a-plat_post_dma_flush-hook.patch
new file mode 100644
index 0000000..ab5538f
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/223-MIPS-BMIPS-Revert-provide-a-plat_post_dma_flush-hook.patch
@@ -0,0 +1,12 @@
+--- a/arch/mips/include/asm/mach-bmips/dma-coherence.h
++++ b/arch/mips/include/asm/mach-bmips/dma-coherence.h
+@@ -49,6 +49,8 @@ static inline int plat_device_is_coheren
+ return 0;
+ }
+
+-#define plat_post_dma_flush bmips_post_dma_flush
++static inline void plat_post_dma_flush(struct device *dev)
++{
++}
+
+ #endif /* __ASM_MACH_BMIPS_DMA_COHERENCE_H */
diff --git a/target/linux/bmips/patches-4.1/230-gpio-add-a-simple-GPIO-driver-for-BCM63XX.patch b/target/linux/bmips/patches-4.1/230-gpio-add-a-simple-GPIO-driver-for-BCM63XX.patch
new file mode 100644
index 0000000..ce9438b
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/230-gpio-add-a-simple-GPIO-driver-for-BCM63XX.patch
@@ -0,0 +1,160 @@
+From dbe94a8daaa63ef81b7414f2a17bca8e36dd6daa Mon Sep 17 00:00:00 2001
+From: Jonas Gorski <jogo at openwrt.org>
+Date: Fri, 20 Feb 2015 19:55:32 +0100
+Subject: [PATCH 1/6] gpio: add a simple GPIO driver for bcm63xx
+
+
+Signed-off-by: Jonas Gorski <jogo at openwrt.org>
+---
+ drivers/gpio/Kconfig | 8 +++
+ drivers/gpio/Makefile | 1 +
+ drivers/gpio/gpio-bcm63xx.c | 117 +++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 126 insertions(+)
+ create mode 100644 drivers/gpio/gpio-bcm63xx.c
+
+--- a/drivers/gpio/Kconfig
++++ b/drivers/gpio/Kconfig
+@@ -126,6 +126,13 @@ config GPIO_BCM_KONA
+ help
+ Turn on GPIO support for Broadcom "Kona" chips.
+
++config GPIO_BCM63XX
++ bool "Broadcom BCM63XX GPIO"
++ depends on MIPS || COMPILE_TEST
++ select GPIO_GENERIC
++ help
++ Turn on GPIO support for Broadcom BCM63XX xDSL chips.
++
+ config GPIO_CLPS711X
+ tristate "CLPS711X GPIO support"
+ depends on ARCH_CLPS711X || COMPILE_TEST
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -21,6 +21,7 @@ obj-$(CONFIG_GPIO_ALTERA) += gpio-alte
+ obj-$(CONFIG_GPIO_AMD8111) += gpio-amd8111.o
+ obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o
+ obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o
++obj-$(CONFIG_GPIO_BCM63XX) += gpio-bcm63xx.o
+ obj-$(CONFIG_GPIO_BT8XX) += gpio-bt8xx.o
+ obj-$(CONFIG_GPIO_CLPS711X) += gpio-clps711x.o
+ obj-$(CONFIG_GPIO_CS5535) += gpio-cs5535.o
+--- /dev/null
++++ b/drivers/gpio/gpio-bcm63xx.c
+@@ -0,0 +1,117 @@
++/*
++ * Driver for BCM63XX memory-mapped GPIO controllers, based on
++ * Generic driver for memory-mapped GPIO controllers.
++ *
++ * Copyright 2008 MontaVista Software, Inc.
++ * Copyright 2008,2010 Anton Vorontsov <cbouatmailru at gmail.com>
++ * Copyright 2015 Jonas Gorski <jogo at openwrt.org>
++ *
++ * 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/init.h>
++#include <linux/err.h>
++#include <linux/bug.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/compiler.h>
++#include <linux/types.h>
++#include <linux/errno.h>
++#include <linux/log2.h>
++#include <linux/ioport.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/mod_devicetable.h>
++#include <linux/basic_mmio_gpio.h>
++#include <linux/of.h>
++#include <linux/of_gpio.h>
++
++static int bcm63xx_gpio_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct resource *dat_r, *dirout_r;
++ void __iomem *dat;
++ void __iomem *dirout;
++ unsigned long sz;
++ int err;
++ struct bgpio_chip *bgc;
++ struct bgpio_pdata *pdata = dev_get_platdata(dev);
++
++ dirout_r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ dat_r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++ if (!dat_r || !dirout_r)
++ return -EINVAL;
++
++ if (resource_size(dat_r) != resource_size(dirout_r))
++ return -EINVAL;
++
++ sz = resource_size(dat_r);
++
++ dat = devm_ioremap_resource(dev, dat_r);
++ if (IS_ERR(dat))
++ return PTR_ERR(dat);
++
++ dirout = devm_ioremap_resource(dev, dirout_r);
++ if (IS_ERR(dirout))
++ return PTR_ERR(dirout);
++
++ bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
++ if (!bgc)
++ return -ENOMEM;
++
++ err = bgpio_init(bgc, dev, sz, dat, NULL, NULL, dirout, NULL,
++ BGPIOF_BIG_ENDIAN_BYTE_ORDER);
++ if (err)
++ return err;
++
++ platform_set_drvdata(pdev, bgc);
++
++ if (dev->of_node) {
++ u32 ngpios;
++
++ if (!of_property_read_u32(dev->of_node, "ngpios", &ngpios))
++ bgc->gc.ngpio = ngpios;
++
++ } else if (pdata) {
++ bgc->gc.base = pdata->base;
++ if (pdata->ngpio > 0)
++ bgc->gc.ngpio = pdata->ngpio;
++ }
++
++ return gpiochip_add(&bgc->gc);
++}
++
++static int bcm63xx_gpio_remove(struct platform_device *pdev)
++{
++ struct bgpio_chip *bgc = platform_get_drvdata(pdev);
++
++ return bgpio_remove(bgc);
++}
++
++#ifdef CONFIG_OF
++static struct of_device_id bcm63xx_gpio_of_match[] = {
++ { .compatible = "brcm,bcm6345-gpio" },
++ { },
++};
++#endif
++
++static struct platform_driver bcm63xx_gpio_driver = {
++ .probe = bcm63xx_gpio_probe,
++ .remove = bcm63xx_gpio_remove,
++ .driver = {
++ .name = "bcm63xx-gpio",
++ .of_match_table = of_match_ptr(bcm63xx_gpio_of_match),
++ },
++};
++
++module_platform_driver(bcm63xx_gpio_driver);
++
++MODULE_DESCRIPTION("Driver for BCM63XX memory-mapped GPIO controllers");
++MODULE_AUTHOR("Jonas Gorski <jogo at openwrt.org>");
++MODULE_LICENSE("GPL");
diff --git a/target/linux/bmips/patches-4.1/240-mtd-brcmnand-add-polling-mode-support.patch b/target/linux/bmips/patches-4.1/240-mtd-brcmnand-add-polling-mode-support.patch
new file mode 100644
index 0000000..f778441
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/240-mtd-brcmnand-add-polling-mode-support.patch
@@ -0,0 +1,136 @@
+From e797c468f4a7ac63053ea0e70494d9c02d82e257 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari at gmail.com>
+Date: Fri, 31 Jul 2015 09:41:53 +0200
+Subject: [PATCH] brcmnand: add polling mode support
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
+---
+ drivers/mtd/nand/brcmnand/brcmnand.c | 89 +++++++++++++++++++++++-------------
+ 1 file changed, 56 insertions(+), 33 deletions(-)
+
+--- a/drivers/mtd/nand/brcmnand/brcmnand.c
++++ b/drivers/mtd/nand/brcmnand/brcmnand.c
+@@ -123,6 +123,7 @@ struct brcmnand_controller {
+ struct brcmnand_soc *soc;
+
+ int cmd_pending;
++ bool cmd_poll;
+ bool dma_pending;
+ struct completion done;
+ struct completion dma_done;
+@@ -355,6 +356,13 @@ enum {
+ INTFC_CTLR_READY = BIT(31),
+ };
+
++#define BRCMNAND_POLL_MASK (INTFC_OOB_VALID | \
++ INTFC_CACHE_VALID | \
++ INTFC_FLASH_READY | \
++ INTFC_CTLR_READY)
++#define BRCMNAND_POLL_RETRIES 10000
++#define BRCMNAND_POLL_TIMEOUT 100
++
+ static inline u32 nand_readreg(struct brcmnand_controller *ctrl, u32 offs)
+ {
+ return brcmnand_readl(ctrl->nand_base + offs);
+@@ -1024,15 +1032,24 @@ static int brcmnand_waitfunc(struct mtd_
+ 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));
++
++ if (ctrl->cmd_pending) {
++ if (ctrl->cmd_poll) {
++ int i;
++ for (i = 0; i < BRCMNAND_POLL_RETRIES; i++) {
++ u32 ready = brcmnand_read_reg(ctrl, BRCMNAND_INTFC_STATUS);
++ if ((ready & BRCMNAND_POLL_MASK) == BRCMNAND_POLL_MASK)
++ break;
++ udelay(BRCMNAND_POLL_TIMEOUT);
++ }
++ } else if (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) &
+@@ -2168,34 +2185,40 @@ int brcmnand_probe(struct platform_devic
+ }
+
+ /* IRQ */
+- ctrl->irq = platform_get_irq(pdev, 0);
+- if ((int)ctrl->irq < 0) {
+- dev_err(dev, "no IRQ defined\n");
+- return -ENODEV;
+- }
++ if (of_property_read_bool(dn, "brcm,cmd-poll")) {
++ /* Polling mode for non-IRQ systems */
++ ctrl->cmd_poll = true;
++ dev_info(dev, "enabling polling mode\n");
++ } else {
++ 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;
++ /*
++ * 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,
++ 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;
++ /* 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) {
diff --git a/target/linux/bmips/patches-4.1/250-leds-bcm6328-add-more-configuration-options-and-fix-.patch b/target/linux/bmips/patches-4.1/250-leds-bcm6328-add-more-configuration-options-and-fix-.patch
new file mode 100644
index 0000000..0371122
--- /dev/null
+++ b/target/linux/bmips/patches-4.1/250-leds-bcm6328-add-more-configuration-options-and-fix-.patch
@@ -0,0 +1,106 @@
+From 7a4f726f42d600f526155d6c66b8c4e5a0feb5f6 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari at gmail.com>
+Date: Thu, 30 Jul 2015 08:38:33 +0200
+Subject: [PATCH] leds-bcm6328: add more configuration options and fix default
+ state initialization
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
+---
+ .../devicetree/bindings/leds/leds-bcm6328.txt | 8 +++++
+ drivers/leds/leds-bcm6328.c | 41 ++++++++++++++++------
+ 1 files changed, 30 insertions(+), 11 deletions(-)
+
+--- a/drivers/leds/leds-bcm6328.c
++++ b/drivers/leds/leds-bcm6328.c
+@@ -41,6 +41,11 @@
+ #define BCM6328_SERIAL_LED_SHIFT_DIR BIT(16)
+ #define BCM6328_LED_SHIFT_TEST BIT(30)
+ #define BCM6328_LED_TEST BIT(31)
++#define BCM6328_INIT_MASK (BCM6328_SERIAL_LED_EN | \
++ BCM6328_SERIAL_LED_MUX | \
++ BCM6328_SERIAL_LED_CLK_NPOL | \
++ BCM6328_SERIAL_LED_DATA_PPOL | \
++ BCM6328_SERIAL_LED_SHIFT_DIR)
+
+ #define BCM6328_LED_MODE_MASK 3
+ #define BCM6328_LED_MODE_OFF 0
+@@ -281,11 +286,10 @@ static int bcm6328_led(struct device *de
+ "linux,default-trigger",
+ NULL);
+
++ spin_lock_irqsave(lock, flags);
+ if (!of_property_read_string(nc, "default-state", &state)) {
+- spin_lock_irqsave(lock, flags);
+ if (!strcmp(state, "on")) {
+ led->cdev.brightness = LED_FULL;
+- bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
+ } else if (!strcmp(state, "keep")) {
+ void __iomem *mode;
+ unsigned long val, shift;
+@@ -296,21 +300,28 @@ static int bcm6328_led(struct device *de
+ else
+ mode = mem + BCM6328_REG_MODE_LO;
+
+- val = bcm6328_led_read(mode) >> (shift % 16);
++ val = bcm6328_led_read(mode) >>
++ BCM6328_LED_SHIFT(shift % 16);
+ val &= BCM6328_LED_MODE_MASK;
+- if (val == BCM6328_LED_MODE_ON)
++ if ((led->active_low && val == BCM6328_LED_MODE_ON) ||
++ (!led->active_low && val == BCM6328_LED_MODE_OFF))
+ led->cdev.brightness = LED_FULL;
+- else {
++ else
+ led->cdev.brightness = LED_OFF;
+- bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
+- }
+ } else {
+ led->cdev.brightness = LED_OFF;
+- bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
+ }
+- spin_unlock_irqrestore(lock, flags);
++ } else {
++ led->cdev.brightness = LED_OFF;
+ }
+
++ if ((led->active_low && led->cdev.brightness == LED_FULL) ||
++ (!led->active_low && led->cdev.brightness == LED_OFF))
++ bcm6328_led_mode(led, BCM6328_LED_MODE_ON);
++ else
++ bcm6328_led_mode(led, BCM6328_LED_MODE_OFF);
++ spin_unlock_irqrestore(lock, flags);
++
+ led->cdev.brightness_set = bcm6328_led_set;
+ led->cdev.blink_set = bcm6328_blink_set;
+
+@@ -360,9 +371,17 @@ static int bcm6328_leds_probe(struct pla
+ bcm6328_led_write(mem + BCM6328_REG_LNKACTSEL_LO, 0);
+
+ val = bcm6328_led_read(mem + BCM6328_REG_INIT);
+- val &= ~BCM6328_SERIAL_LED_EN;
++ val &= ~(BCM6328_INIT_MASK);
+ if (of_property_read_bool(np, "brcm,serial-leds"))
+ val |= BCM6328_SERIAL_LED_EN;
++ if (of_property_read_bool(np, "brcm,serial-mux"))
++ val |= BCM6328_SERIAL_LED_MUX;
++ if (of_property_read_bool(np, "brcm,serial-clk-low"))
++ val |= BCM6328_SERIAL_LED_CLK_NPOL;
++ if (!of_property_read_bool(np, "brcm,serial-dat-low"))
++ val |= BCM6328_SERIAL_LED_DATA_PPOL;
++ if (!of_property_read_bool(np, "brcm,serial-shift-inv"))
++ val |= BCM6328_SERIAL_LED_SHIFT_DIR;
+ bcm6328_led_write(mem + BCM6328_REG_INIT, val);
+
+ for_each_available_child_of_node(np, child) {
+@@ -373,7 +392,7 @@ static int bcm6328_leds_probe(struct pla
+ continue;
+
+ if (reg >= BCM6328_LED_MAX_COUNT) {
+- dev_err(dev, "invalid LED (>= %d)\n",
++ dev_err(dev, "invalid LED (%u >= %d)\n", reg,
+ BCM6328_LED_MAX_COUNT);
+ continue;
+ }
diff --git a/target/linux/bmips/profiles/00-default.mk b/target/linux/bmips/profiles/00-default.mk
new file mode 100644
index 0000000..65d47be
--- /dev/null
+++ b/target/linux/bmips/profiles/00-default.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Default
+ NAME:=Default Profile
+ PACKAGES:=
+endef
+define Profile/Default/description
+ Package set compatible with most boards.
+endef
+$(eval $(call Profile,Default))
diff --git a/target/linux/bmips/profiles/comtrend.mk b/target/linux/bmips/profiles/comtrend.mk
new file mode 100644
index 0000000..ac20c06
--- /dev/null
+++ b/target/linux/bmips/profiles/comtrend.mk
@@ -0,0 +1,69 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/AR5381u
+ NAME:=Comtrend AR-5381u
+ PACKAGES:=
+endef
+define Profile/AR5381u/Description
+ Package set optimized for AR-5381u.
+endef
+$(eval $(call Profile,AR5381u))
+
+define Profile/AR5387un
+ NAME:=Comtrend AR-5387un
+ PACKAGES:=
+endef
+define Profile/AR5387un/Description
+ Package set optimized for AR-5387un.
+endef
+$(eval $(call Profile,AR5387un))
+
+define Profile/VG8050
+ NAME:=Comtrend VG-8050
+ PACKAGES:=
+endef
+define Profile/VG8050/Description
+ Package set optimized for VG-8050.
+endef
+$(eval $(call Profile,VG8050))
+
+define Profile/VR3025u
+ NAME:=Comtrend VR-3025u
+ PACKAGES:=
+endef
+define Profile/VR3025u/Description
+ Package set optimized for VR-3025u.
+endef
+$(eval $(call Profile,VR3025u))
+
+define Profile/VR3025un
+ NAME:=Comtrend VR-3025un
+ PACKAGES:=
+endef
+define Profile/VR3025un/Description
+ Package set optimized for VR-3025un.
+endef
+$(eval $(call Profile,VR3025un))
+
+define Profile/VR3032u
+ NAME:=Comtrend VR-3032u
+ PACKAGES:=
+endef
+define Profile/VR3032u/Description
+ Package set optimized for VR-3032u.
+endef
+$(eval $(call Profile,VR3032u))
+
+define Profile/WAP5813n
+ NAME:=Comtrend WAP-5813n
+ PACKAGES:=
+endef
+define Profile/WAP5813n/Description
+ Package set optimized for WAP-5813n.
+endef
+$(eval $(call Profile,WAP5813n))
diff --git a/target/linux/bmips/profiles/huawei.mk b/target/linux/bmips/profiles/huawei.mk
new file mode 100644
index 0000000..853fd35
--- /dev/null
+++ b/target/linux/bmips/profiles/huawei.mk
@@ -0,0 +1,33 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/HG520v
+ NAME:=Huawei EchoLife HG520v
+ PACKAGES:=
+endef
+define Profile/HG520v/Description
+ Package set optimized for Huawei HG520v.
+endef
+$(eval $(call Profile,HG520v))
+
+define Profile/HG556a_AB
+ NAME:=Huawei EchoLife HG556a (version A/B - Atheros)
+ PACKAGES:=
+endef
+define Profile/HG556a_AB/Description
+ Package set optimized for Huawei HG556a version A/B (Atheros).
+endef
+$(eval $(call Profile,HG556a_AB))
+
+define Profile/HG556a_C
+ NAME:=Huawei EchoLife HG556a (version C - Ralink)
+ PACKAGES:=
+endef
+define Profile/HG556a_C/Description
+ Package set optimized for Huawei HG556a version C (Ralink).
+endef
+$(eval $(call Profile,HG556a_C))
diff --git a/target/linux/bmips/profiles/sagem.mk b/target/linux/bmips/profiles/sagem.mk
new file mode 100644
index 0000000..0034ac2
--- /dev/null
+++ b/target/linux/bmips/profiles/sagem.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/FAST1704
+ NAME:=Sagem F at ST1704
+ PACKAGES:=
+endef
+define Profile/FAST1704/Description
+ Package set optimized for Sagem F at ST1704.
+endef
+$(eval $(call Profile,FAST1704))
diff --git a/target/linux/bmips/profiles/sfr.mk b/target/linux/bmips/profiles/sfr.mk
new file mode 100644
index 0000000..d5bf054
--- /dev/null
+++ b/target/linux/bmips/profiles/sfr.mk
@@ -0,0 +1,15 @@
+#
+# Copyright (C) 2015 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+define Profile/Neufbox4
+ NAME:=SFR Neufbox4
+ PACKAGES:=
+endef
+define Profile/Neufbox4/Description
+ Package set optimized for Neufbox4.
+endef
+$(eval $(call Profile,Neufbox4))
--
1.9.1
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel
More information about the openwrt-devel
mailing list