[OpenWrt-Devel] [PATCH] bmips: add new target
Álvaro Fernández Rojas
noltari at gmail.com
Fri Oct 9 16:33:52 EDT 2015
Forget this one, I didn't want to send it :D
El 09/10/2015 a las 22:29, Álvaro Fernández Rojas escribió:
> 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))
_______________________________________________
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