ASR_BASE

Change-Id: Icf3719cc0afe3eeb3edc7fa80a2eb5199ca9dda1
diff --git a/package/boot/arm-trusted-firmware-bcm63xx/Makefile b/package/boot/arm-trusted-firmware-bcm63xx/Makefile
new file mode 100644
index 0000000..12571e8
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-bcm63xx/Makefile
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: GPL-2.0
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=2.2
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=$(PROJECT_GIT)/project/bcm63xx/atf.git
+PKG_SOURCE_DATE:=2021-12-24
+PKG_SOURCE_VERSION:=e6d46baf3fae79f693f90bf34f7284c3dfc64aef
+PKG_MIRROR_HASH:=9d5d04f572b1b6ddc6eb3064b9cb09f5fe982e82d350790041d35316349af124
+
+PKG_MAINTAINER:=Rafał Miłecki <rafal@milecki.pl>
+
+include $(INCLUDE_DIR)/trusted-firmware-a.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Trusted-Firmware-A/Default
+  PLAT:=bcm
+  DEFAULT:=y
+endef
+
+define Trusted-Firmware-A/bcm4908
+  BUILD_TARGET:=bcm4908
+  NAME:=BCM4908
+  BRCM_CHIP=4908
+  TFA_IMAGE:=bl31.bin
+endef
+
+TFA_TARGETS:= \
+	bcm4908
+
+TFA_MAKE_FLAGS += \
+	BRCM_CHIP=$(BRCM_CHIP)
+
+define Package/trusted-firmware-a/install
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/build/$(PLAT)/release/$(TFA_IMAGE) $(STAGING_DIR_IMAGE)/
+endef
+
+$(eval $(call BuildPackage/Trusted-Firmware-A))
diff --git a/package/boot/arm-trusted-firmware-mediatek/Makefile b/package/boot/arm-trusted-firmware-mediatek/Makefile
new file mode 100644
index 0000000..98d421e
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-mediatek/Makefile
@@ -0,0 +1,161 @@
+#
+# Copyright (C) 2017 Hauke Mehrtens
+# Copyright (C) 2021 Daniel Golle
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=arm-trusted-firmware-mediatek
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=https://github.com/mtk-openwrt/arm-trusted-firmware.git
+PKG_SOURCE_DATE:=2020-11-09
+PKG_SOURCE_VERSION:=03017334ccd8c0fac12e7db36749b95b9a7d745f
+PKG_MIRROR_HASH:=b211b2f9143d4debc7ad8dc959cb606888af20af790855dd66c87e451b6a1bc7
+
+PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
+
+PKG_LICENSE_FILES:=LICENCE.mediatek
+
+BLOBS_TARBALL:=tfa-mtk-files-for-2020-11-09.tgz
+BROMIMAGE_EXEC:=bromimage-x64
+
+include $(INCLUDE_DIR)/trusted-firmware-a.mk
+include $(INCLUDE_DIR)/package.mk
+
+PKG_LICENSE+=proprietary
+
+define Download/tfa-files
+  URL:=@OPENWRT
+  URL_FILE:=$(BLOBS_TARBALL)
+  FILE:=$(BLOBS_TARBALL)
+  HASH:=689b097e4531d3eeca0c477675ab3dc3cace6ba4ed8a339116a9ede6537839d7
+endef
+
+define Download/mt7622-header-emmc
+  URL:=https://raw.githubusercontent.com/frank-w/BPI-R64-ATF/a36efa5f7435b8079479d13b562fedc0aa0d42f0
+  URL_FILE:=header_emmc.bin
+  FILE:=mt7622-header_emmc.bin
+  HASH:=0a09c55d90c5fc375c59468a4331555f77cbc3e1dd107ca83b5b8c9625f38d8c
+endef
+
+define Download/mt7622-header-sdmmc
+  URL:=https://raw.githubusercontent.com/frank-w/BPI-R64-ATF/a36efa5f7435b8079479d13b562fedc0aa0d42f0
+  URL_FILE:=header_sdmmc.bin
+  FILE:=mt7622-header_sdmmc.bin
+  HASH:=242908c04e25289d25ba9fab61a1930425af173051c43d275d1ac9877d6accb1
+endef
+
+define Trusted-Firmware-A/Default
+  BUILD_TARGET:=mediatek
+  BUILD_SUBTARGET:=mt7622
+  PLAT:=mt7622
+  TFA_IMAGE:=bl2.img bl31.bin
+  BOOT_DEVICE:=
+  DDR_BLOB:=
+endef
+
+define Trusted-Firmware-A/mt7622-nor-1ddr
+  NAME:=MediaTek MT7622 (SPI-NOR, 1x DDR3)
+  BOOT_DEVICE:=nor
+  DDR_BLOB:=1
+endef
+
+define Trusted-Firmware-A/mt7622-nor-2ddr
+  NAME:=MediaTek MT7622 (SPI-NOR, 2x DDR3)
+  BOOT_DEVICE:=nor
+  DDR_BLOB:=2
+endef
+
+define Trusted-Firmware-A/mt7622-snand-1ddr
+  NAME:=MediaTek MT7622 (SPI-NAND, 1x DDR3)
+  BOOT_DEVICE:=snand
+  DDR_BLOB:=1
+endef
+
+define Trusted-Firmware-A/mt7622-snand-2ddr
+  NAME:=MediaTek MT7622 (SPI-SNAND, 2x DDR3)
+  BOOT_DEVICE:=snand
+  DDR_BLOB:=2
+endef
+
+define Trusted-Firmware-A/mt7622-emmc-1ddr
+  NAME:=MediaTek MT7622 (eMMC, 1x DDR3)
+  BOOT_DEVICE:=emmc
+  DDR_BLOB:=1
+endef
+
+define Trusted-Firmware-A/mt7622-emmc-2ddr
+  NAME:=MediaTek MT7622 (eMMC, 2x DDR3)
+  BOOT_DEVICE:=emmc
+  DDR_BLOB:=2
+endef
+
+define Trusted-Firmware-A/mt7622-sdmmc-1ddr
+  NAME:=MediaTek MT7622 (SDcard, 1x DDR3)
+  BOOT_DEVICE:=sdmmc
+  DDR_BLOB:=1
+endef
+
+define Trusted-Firmware-A/mt7622-sdmmc-2ddr
+  NAME:=MediaTek MT7622 (SDcard, 2x DDR3)
+  BOOT_DEVICE:=sdmmc
+  DDR_BLOB:=2
+endef
+
+TFA_TARGETS:= \
+        mt7622-nor-1ddr \
+        mt7622-nor-2ddr \
+        mt7622-snand-1ddr \
+        mt7622-snand-2ddr \
+        mt7622-emmc-1ddr \
+        mt7622-emmc-2ddr \
+        mt7622-sdmmc-1ddr \
+        mt7622-sdmmc-2ddr
+
+TFA_MAKE_FLAGS += BOOT_DEVICE=$(BOOT_DEVICE) all
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+ifeq ($(BOOT_DEVICE),emmc)
+	$(eval $(call Download,mt7622-header-emmc))
+endif
+ifeq ($(BOOT_DEVICE),sdmmc)
+	$(eval $(call Download,mt7622-header-sdmmc))
+endif
+	$(eval $(call Download,tfa-files))
+# replace 'bromimage' tool by static version
+	$(TAR) -vxzf $(DL_DIR)/$(BLOBS_TARBALL) --wildcards \
+		-O "*/$(BROMIMAGE_EXEC)" > $(PKG_BUILD_DIR)/tools/mediatek/bromimage/bromimage
+	$(TAR) -vxzf $(DL_DIR)/$(BLOBS_TARBALL) --wildcards \
+		-C $(PKG_BUILD_DIR) \
+		--strip-components=1 */LICENCE.mediatek
+endef
+
+define Build/Configure
+	$(call Build/Configure/Default)
+# replace DRAM calib blobs if needed (variant '2' is shipped upstream)
+ifeq ($(DDR_BLOB),1)
+	$(TAR) -vxzf $(DL_DIR)/$(BLOBS_TARBALL) --wildcards \
+		-C $(PKG_BUILD_DIR)/plat/mediatek/mt7622/drivers/dram/release \
+		--strip-components=1 */*.o
+endif
+endef
+
+define Package/trusted-firmware-a/install
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/build/mt7622/release/bl2.img $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl2.img
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/build/mt7622/release/bl31.bin $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-bl31.bin
+ifeq ($(BOOT_DEVICE),emmc)
+	$(INSTALL_DATA) $(DL_DIR)/mt7622-header_emmc.bin $(STAGING_DIR_IMAGE)/
+endif
+ifeq ($(BOOT_DEVICE),sdmmc)
+	$(INSTALL_DATA) $(DL_DIR)/mt7622-header_sdmmc.bin $(STAGING_DIR_IMAGE)/
+endif
+endef
+
+$(eval $(call BuildPackage/Trusted-Firmware-A))
diff --git a/package/boot/arm-trusted-firmware-mvebu/Makefile b/package/boot/arm-trusted-firmware-mvebu/Makefile
new file mode 100644
index 0000000..c4669ed
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-mvebu/Makefile
@@ -0,0 +1,174 @@
+#
+# Copyright (C) 2019 Sartura Ltd.
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=2.4
+PKG_RELEASE:=1
+PKG_HASH:=bf3eb3617a74cddd7fb0e0eacbfe38c3258ee07d4c8ed730deef7a175cc3d55b
+
+PKG_MAINTAINER:=Vladimir Vid <vladimir.vid@sartura.hr>
+
+include $(INCLUDE_DIR)/trusted-firmware-a.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Trusted-Firmware-A/Default
+  BUILD_TARGET:=mvebu
+  BUILD_SUBTARGET:=cortexa53
+  TFA_IMAGE:=flash-image.bin uart-images.tgz.bin
+  UBOOT:=
+  DDR_TOPOLOGY:=
+  CLOCKSPRESET:=
+endef
+
+
+define Trusted-Firmware-A/espressobin-512mb
+  NAME:=Marvell ESPRESSObin (512MB)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=0
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/espressobin-v3-v5-1gb-1cs
+  NAME:=Marvell ESPRESSObin V3-V5 (1GB 1CS)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=4
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/espressobin-v3-v5-1gb-2cs
+  NAME:=Marvell ESPRESSObin V3-V5 (1GB, 2CS)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=2
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/espressobin-v3-v5-2gb
+  NAME:=Marvell ESPRESSObin V3-V5 (2GB)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=7
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/espressobin-v7-1gb
+  NAME:=Marvell ESPRESSObin V7 (1GB)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin-v7
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=5
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/espressobin-v7-2gb
+  NAME:=Marvell ESPRESSObin V7 (2GB)
+  DEPENDS:=+u-boot-espressobin
+  BUILD_DEVICES:=globalscale_espressobin-v7
+  UBOOT:=espressobin
+  DDR_TOPOLOGY:=6
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+define Trusted-Firmware-A/udpu
+  NAME:=Methode uDPU
+  DEPENDS:=+u-boot-uDPU
+  BUILD_DEVICES:=methode_udpu
+  UBOOT:=uDPU
+  DDR_TOPOLOGY:=0
+  CLOCKSPRESET:=CPU_1000_DDR_800
+  PLAT:=a3700
+endef
+
+
+TFA_TARGETS:= \
+	espressobin-512mb \
+	espressobin-v3-v5-1gb-1cs \
+	espressobin-v3-v5-1gb-2cs \
+	espressobin-v3-v5-2gb \
+	espressobin-v7-1gb \
+	espressobin-v7-2gb \
+	udpu
+
+TFA_MAKE_FLAGS += \
+		CROSS_CM3=$(STAGING_DIR_IMAGE)/$(LINARO_NAME)-$(LINARO_RELEASE).$(LINARO_VERSION)/bin/arm-linux-gnueabi- \
+		BL33=$(STAGING_DIR_IMAGE)/$(UBOOT)-u-boot.bin \
+		MV_DDR_PATH=$(STAGING_DIR_IMAGE)/$(MV_DDR_NAME) \
+		WTP=$(STAGING_DIR_IMAGE)/$(A3700_UTILS_NAME) \
+		DDR_TOPOLOGY=$(DDR_TOPOLOGY) \
+		CLOCKSPRESET=$(CLOCKSPRESET) \
+		A3700_UTILS_COMMIT_ID=$(A3700_UTILS_RELEASE) \
+		MV_DDR_COMMIT_ID=$(MV_DDR_RELEASE) \
+		all \
+		mrvl_flash
+
+A3700_UTILS_NAME:=a3700-utils
+A3700_UTILS_RELEASE:=5598e150
+A3700_UTILS_SOURCE=$(A3700_UTILS_NAME)-$(A3700_UTILS_RELEASE).tar.bz2
+
+define Download/a3700-utils
+  FILE:=$(A3700_UTILS_SOURCE)
+  PROTO:=git
+  URL:=https://github.com/MarvellEmbeddedProcessors/A3700-utils-marvell.git
+  VERSION:=5598e150fa3a1568256c30223fd2b214d729f26a
+  MIRROR_HASH:=4c3a3bed97833d08af4e42995c0c5af6c107f990fd492cd90aa3e79134d2751e
+  SUBDIR:=$(A3700_UTILS_NAME)
+endef
+
+MV_DDR_NAME:=mv-ddr-marvell
+MV_DDR_RELEASE:=6fb99002
+MV_DDR_SOURCE:=$(MV_DDR_NAME)-$(MV_DDR_RELEASE).tar.bz2
+
+define Download/mv-ddr-marvell
+  FILE:=$(MV_DDR_SOURCE)
+  PROTO:=git
+  URL:=https://github.com/MarvellEmbeddedProcessors/mv-ddr-marvell.git
+  VERSION:=6fb99002be5dec9c7f5375b074f53148dbc0739c
+  MIRROR_HASH:=6836e5ea47618a7ee2f96a1a6bd8218f003789b877e521fdfcb008f2f6475dd6
+  SUBDIR:=$(MV_DDR_NAME)
+endef
+
+LINARO_NAME:=gcc-linaro
+LINARO_RELEASE:=6
+LINARO_VERSION:=5.0-2018.12-$(HOST_ARCH)_arm-linux-gnueabi
+LINARO_SOURCE=$(LINARO_NAME)-$(LINARO_RELEASE).$(LINARO_VERSION).tar.xz
+
+define Download/gcc-linaro
+  FILE:=$(LINARO_SOURCE)
+  URL:=https://releases.linaro.org/components/toolchain/binaries/latest-$(LINARO_RELEASE)/arm-linux-gnueabi/
+  HASH:=2d4a92d6c8b384ae404b2e02c1c412e3ec18f9b714135acf046b2b1b510e9ace
+endef
+
+define Build/Prepare
+	# Download sources
+	$(eval $(call Download,a3700-utils))
+	$(eval $(call Download,mv-ddr-marvell))
+	$(eval $(call Download,gcc-linaro))
+
+	$(call Build/Prepare/Default,)
+
+	mkdir -p $(STAGING_DIR_IMAGE)
+	$(TAR) -C $(STAGING_DIR_IMAGE) -xf $(DL_DIR)/$(A3700_UTILS_SOURCE)
+	$(call PatchDir/Default,$(STAGING_DIR_IMAGE)/$(A3700_UTILS_NAME),./patches-a3700-utils)
+	$(TAR) -C $(STAGING_DIR_IMAGE) -xf $(DL_DIR)/$(MV_DDR_SOURCE)
+	$(call PatchDir/Default,$(STAGING_DIR_IMAGE)/$(MV_DDR_NAME),./patches-mv-ddr-marvell)
+	$(TAR) -C $(STAGING_DIR_IMAGE) -xf $(DL_DIR)/$(LINARO_SOURCE)
+endef
+
+$(eval $(call BuildPackage/Trusted-Firmware-A))
diff --git a/package/boot/arm-trusted-firmware-mvebu/patches-a3700-utils/001-version.patch b/package/boot/arm-trusted-firmware-mvebu/patches-a3700-utils/001-version.patch
new file mode 100644
index 0000000..745e615
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-mvebu/patches-a3700-utils/001-version.patch
@@ -0,0 +1,13 @@
+diff --git a/wtmi/sys_init/Makefile b/wtmi/sys_init/Makefile
+--- a/wtmi/sys_init/Makefile
++++ b/wtmi/sys_init/Makefile
+@@ -51,7 +51,8 @@ ECHO     = @echo
+ SED      = @sed
+ 
+ LOCAL_VERSION_STRING	?= -armada
+-BUILD_STRING		:= $(shell git log -n 1 --pretty=format:"%h")
++A3700_UTILS_COMMIT_ID	?= $(shell git log -n 1 --pretty=format:"%h")
++BUILD_STRING		:= $(A3700_UTILS_COMMIT_ID)
+ VERSION_STRING		:= $(LOCAL_VERSION_STRING)-$(BUILD_STRING)
+ 
+ CPUOPTS  = -mthumb -mcpu=cortex-m3 -mlittle-endian
diff --git a/package/boot/arm-trusted-firmware-mvebu/patches-mv-ddr-marvell/001-version.patch b/package/boot/arm-trusted-firmware-mvebu/patches-mv-ddr-marvell/001-version.patch
new file mode 100644
index 0000000..1c7c61d
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-mvebu/patches-mv-ddr-marvell/001-version.patch
@@ -0,0 +1,12 @@
+diff --git a/scripts/localversion.sh b/scripts/localversion.sh
+--- a/scripts/localversion.sh
++++ b/scripts/localversion.sh
+@@ -103,7 +103,7 @@ MV_DDR_ROOT=$1
+ MV_DDR_VER_CSRC=$2
+ 
+ # get mv_ddr git commit id
+-MV_DDR_COMMIT_ID=`git -C $MV_DDR_ROOT rev-parse --verify --quiet --short HEAD 2> /dev/null`
++test -z "$MV_DDR_COMMIT_ID" && MV_DDR_COMMIT_ID=`git -C $MV_DDR_ROOT rev-parse --verify --quiet --short HEAD 2> /dev/null`
+ 
+ # check for uncommitted changes in mv_ddr git
+ MV_DDR_DIRTY_CHK=`git -C $MV_DDR_ROOT diff-index --name-only HEAD 2> /dev/null`
diff --git a/package/boot/arm-trusted-firmware-mvebu/patches/200-hostssl.patch b/package/boot/arm-trusted-firmware-mvebu/patches/200-hostssl.patch
new file mode 100644
index 0000000..ad4e1e9
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-mvebu/patches/200-hostssl.patch
@@ -0,0 +1,20 @@
+--- a/tools/fiptool/Makefile
++++ b/tools/fiptool/Makefile
+@@ -20,7 +20,7 @@ ifeq (${DEBUG},1)
+ else
+   HOSTCCFLAGS += -O2
+ endif
+-LDLIBS := -lcrypto
++LDLIBS := -L${OPENSSL_DIR}/lib -lcrypto
+ 
+ ifeq (${V},0)
+   Q := @
+@@ -28,7 +28,7 @@ else
+   Q :=
+ endif
+ 
+-INCLUDE_PATHS := -I../../include/tools_share
++INCLUDE_PATHS := -I../../include/tools_share -I${OPENSSL_DIR}/include
+ 
+ HOSTCC ?= gcc
+ 
diff --git a/package/boot/arm-trusted-firmware-rockchip/Makefile b/package/boot/arm-trusted-firmware-rockchip/Makefile
new file mode 100644
index 0000000..b712a35
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-rockchip/Makefile
@@ -0,0 +1,49 @@
+#
+# Copyright (C) 2020 Tobias Maedel <openwrt@tbspace.de>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=arm-trusted-firmware-rockchip
+PKG_VERSION:=2.3
+PKG_RELEASE:=1
+
+PKG_SOURCE:=atf-v$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=https://github.com/atf-builds/atf/releases/download/v$(PKG_VERSION)/atf-v$(PKG_VERSION).tar.gz?
+PKG_HASH:=bf352298743aed594cf2958dd588e06ab6713fc514bb6f809bf55a85a87134c1
+
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=license.md
+
+PKG_MAINTAINER:=Tobias Maedel <openwrt@tbspace.de>
+
+MAKE_PATH:=$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/arm-trusted-firmware-rockchip
+    SECTION:=boot
+    CATEGORY:=Boot Loaders
+    TITLE:=ARM Trusted Firmware for Rockchip
+    DEPENDS:=@TARGET_rockchip_armv8
+endef
+
+define Build/Prepare
+	$(TAR) -C $(PKG_BUILD_DIR) -xf $(DL_DIR)/$(PKG_SOURCE)
+endef
+
+define Build/Compile
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) -p $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/rk*.elf $(STAGING_DIR_IMAGE)/
+endef
+
+define Package/arm-trusted-firmware-rockchip/install
+endef
+
+$(eval $(call BuildPackage,arm-trusted-firmware-rockchip))
diff --git a/package/boot/arm-trusted-firmware-sunxi/Makefile b/package/boot/arm-trusted-firmware-sunxi/Makefile
new file mode 100644
index 0000000..0211e5e
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-sunxi/Makefile
@@ -0,0 +1,51 @@
+#
+# Copyright (C) 2017 Hauke Mehrtens
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=arm-trusted-firmware-sunxi
+PKG_RELEASE:=1
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL=https://github.com/ARM-software/arm-trusted-firmware
+PKG_SOURCE_DATE:=2018-10-02
+PKG_SOURCE_VERSION:=dbc8d9496ead9ecdd7c2a276b542a4fbbbf64027
+PKG_MIRROR_HASH:=c81521a27b86f606e927b4e346286540b862828c8d49292eae1f5c6adfc24001
+
+PKG_LICENSE:=BSD-3-Clause
+PKG_LICENSE_FILES:=license.md
+
+PKG_MAINTAINER:=Hauke Mehrtens <hauke@hauke-m.de>
+
+include $(INCLUDE_DIR)/package.mk
+
+
+define Package/arm-trusted-firmware-sunxi
+    SECTION:=boot
+    CATEGORY:=Boot Loaders
+    TITLE:=ARM Trusted Firmware for Allwinner
+    DEPENDS:=@TARGET_sunxi_cortexa53
+endef
+
+export GCC_HONOUR_COPTS=s
+
+MAKE_VARS = \
+	CROSS_COMPILE="$(TARGET_CROSS)"
+
+MAKE_FLAGS += \
+	PLAT=sun50i_a64 \
+	bl31
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/build/sun50i_a64/release/bl31.bin $(STAGING_DIR_IMAGE)/bl31.bin
+endef
+
+define Package/arm-trusted-firmware-sunxi/install
+endef
+
+$(eval $(call BuildPackage,arm-trusted-firmware-sunxi))
diff --git a/package/boot/arm-trusted-firmware-tools/Makefile b/package/boot/arm-trusted-firmware-tools/Makefile
new file mode 100644
index 0000000..a711272
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-tools/Makefile
@@ -0,0 +1,57 @@
+#
+# Copyright 2021 Daniel Golle
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=arm-trusted-firmware-tools
+PKG_VERSION:=2.4
+PKG_RELEASE:=1
+PKG_HASH:=bf3eb3617a74cddd7fb0e0eacbfe38c3258ee07d4c8ed730deef7a175cc3d55b
+
+PKG_MAINTAINER:=Daniel Golle <daniel@makrotopia.org>
+PKG_HOST_ONLY:=1
+
+HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/trusted-firmware-a-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/trusted-firmware-a.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define Package/arm-trusted-firmware-tools
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  TITLE:=ARM Trusted Firmware tools
+  URL:=https://www.trustedfirmware.org
+  BUILDONLY:=1
+endef
+
+define Host/Compile
+	$(MAKE) -C \
+		$(HOST_BUILD_DIR)/tools/fiptool \
+		CPPFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)"
+	$(MAKE) -C \
+		$(HOST_BUILD_DIR)/tools/sptool \
+		CPPFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)"
+endef
+
+define Host/Install
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/fiptool/fiptool $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/sptool/sptool $(STAGING_DIR_HOST)/bin/
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/sptool/sp_mk_generator.py $(STAGING_DIR_HOST)/bin/
+endef
+
+define Host/Clean
+	rm -f $(STAGING_DIR_HOST)/bin/fiptool
+	rm -f $(STAGING_DIR_HOST)/bin/sptool
+	rm -f $(STAGING_DIR_HOST)/bin/sp_mk_generator.py
+endef
+
+$(eval $(call BuildPackage,arm-trusted-firmware-tools))
+$(eval $(call HostBuild))
diff --git a/package/boot/arm-trusted-firmware-tools/patches/001-respect-LDFLAGS.patch b/package/boot/arm-trusted-firmware-tools/patches/001-respect-LDFLAGS.patch
new file mode 100644
index 0000000..0b79891
--- /dev/null
+++ b/package/boot/arm-trusted-firmware-tools/patches/001-respect-LDFLAGS.patch
@@ -0,0 +1,11 @@
+--- a/tools/fiptool/Makefile
++++ b/tools/fiptool/Makefile
+@@ -38,7 +38,7 @@
+ 
+ ${PROJECT}: ${OBJECTS} Makefile
+ 	@echo "  HOSTLD  $@"
+-	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS}
++	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS} $(LDFLAGS)
+ 	@${ECHO_BLANK_LINE}
+ 	@echo "Built $@ successfully"
+ 	@${ECHO_BLANK_LINE}
diff --git a/package/boot/at91bootstrap/Makefile b/package/boot/at91bootstrap/Makefile
new file mode 100644
index 0000000..f66472f
--- /dev/null
+++ b/package/boot/at91bootstrap/Makefile
@@ -0,0 +1,142 @@
+#
+# Copyright (C) 2016 Microchip Technology Inc.
+#     <Sandeepsheriker.mallikarjun@microchip.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=at91bootstrap
+PKG_VERSION:=v3.9.3
+PKG_RELEASE:=2
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/linux4sam/at91bootstrap.git
+PKG_MIRROR_HASH:=06753d673756edc9753932db00f4e5b8c1f9fa7708337c4d6ce280573efb86b4
+PKG_SOURCE_VERSION:=d96833a4b6680b237708eb4dc9f10708b9e709d8
+PKG_BUILD_DIR = \
+	$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+include at91bootstrap.mk
+include $(INCLUDE_DIR)/package.mk
+
+define AT91Bootstrap/Default
+  BUILD_TARGET:=at91
+  HIDDEN:=1
+  AT91BOOTSTRAP_IMAGE:=at91bootstrap.bin
+endef
+
+define AT91Bootstrap/at91sam9x5eknf_uboot
+  NAME:=AT91Bootstrap for AT91SAM9X5-EK board (NandFlash)
+  BUILD_SUBTARGET:=sam9x
+  BUILD_DEVICES:=atmel_at91sam9x25ek atmel_at91sam9x35ek
+endef
+
+define AT91Bootstrap/at91sam9x5eksd_uboot
+  NAME:=AT91Bootstrap for AT91SAM9X5-EK board (SDcard)
+  BUILD_SUBTARGET:=sam9x
+  BUILD_DEVICES:=atmel_at91sam9x25ek atmel_at91sam9x35ek
+endef
+
+define AT91Bootstrap/sama5d2_xplaineddf_uboot
+  TITLE:=AT91Bootstrap for SAMA5D2 Xplained board (SPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-xplained
+endef
+
+define AT91Bootstrap/sama5d2_xplaineddf_qspi_uboot
+  TITLE:=AT91Bootstrap for SAMA5D2 Xplained board (QSPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-xplained
+endef
+
+define AT91Bootstrap/sama5d2_xplainedsd_uboot
+  TITLE:=AT91Bootstrap for SAMA5D2 Xplained board (SDcard/EMMC)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-xplained
+endef
+
+define AT91Bootstrap/sama5d3_xplainednf_uboot
+  TITLE:=AT91Bootstrap for SAMA5D3 Xplained board (Nand Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d3-xplained
+endef
+
+define AT91Bootstrap/sama5d3_xplainedsd_uboot
+  TITLE:=AT91Bootstrap for SAMA5D3 Xplained board (SDcard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d3-xplained
+endef
+
+define AT91Bootstrap/sama5d4_xplainednf_uboot_secure
+  TITLE:=AT91Bootstrap for SAMA5D4 Xplained board (Nand Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d4-xplained
+endef
+
+define AT91Bootstrap/sama5d4_xplaineddf_uboot_secure
+  TITLE:=AT91Bootstrap for SAMA5D4 Xplained board (SPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d4-xplained
+endef
+
+define AT91Bootstrap/sama5d4_xplainedsd_uboot_secure
+  TITLE:=AT91Bootstrap for SAMA5D4 Xplained board (SDcard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d4-xplained
+endef
+
+define AT91Bootstrap/sama5d27_som1_eksd_uboot
+  TITLE:=AT91Bootstrap for SAMA5D27 SOM1 Ek (SDcard0)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d27-som1-ek
+endef
+
+define AT91Bootstrap/sama5d27_som1_eksd1_uboot
+  TITLE:=AT91Bootstrap for SAMA5D27 SOM1 Ek (SDcard1)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d27-som1-ek
+endef
+
+define AT91Bootstrap/sama5d27_som1_ekqspi_uboot
+  TITLE:=AT91Bootstrap for SAMA5D27 SOM1 Ek (QSPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d27-som1-ek
+endef
+
+define AT91Bootstrap/sama5d2_ptc_eknf_uboot
+  TITLE:=AT91Bootstrap for SAMA5D2 PTC EK (Nand Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-ptc-ek
+endef
+
+define AT91Bootstrap/sama5d2_ptc_eksd_uboot
+  TITLE:=AT91Bootstrap for SAMA5D2 PTC EK (SDCard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-ptc-ek
+endef
+
+AT91BOOTSTRAP_TARGETS := \
+	at91sam9x5eknf_uboot \
+	at91sam9x5eksd_uboot \
+	sama5d2_xplaineddf_uboot \
+	sama5d2_xplaineddf_qspi_uboot \
+	sama5d2_xplainedsd_uboot \
+	sama5d3_xplainednf_uboot \
+	sama5d3_xplainedsd_uboot \
+	sama5d4_xplainednf_uboot_secure \
+	sama5d4_xplaineddf_uboot_secure \
+	sama5d4_xplainedsd_uboot_secure \
+	sama5d27_som1_eksd1_uboot \
+	sama5d27_som1_ekqspi_uboot \
+	sama5d2_ptc_eknf_uboot \
+	sama5d2_ptc_eksd_uboot
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS)
+endef
+
+$(eval $(call BuildPackage/AT91Bootstrap))
diff --git a/package/boot/at91bootstrap/at91bootstrap.mk b/package/boot/at91bootstrap/at91bootstrap.mk
new file mode 100644
index 0000000..fe6577f
--- /dev/null
+++ b/package/boot/at91bootstrap/at91bootstrap.mk
@@ -0,0 +1,88 @@
+
+PKG_TARGETS := bin
+PKG_FLAGS:=nonshared
+
+export GCC_HONOUR_COPTS=s
+
+define Package/at91bootstrap/install/default
+	$(CP) -avL $(PKG_BUILD_DIR)/binaries/at91bootstrap.bin $(1)/
+endef
+
+Package/at91bootstrap/install = $(Package/at91bootstrap/install/default)
+
+define AT91Bootstrap/Init
+  BUILD_TARGET:=
+  BUILD_SUBTARGET:=
+  BUILD_DEVICES:=
+  NAME:=
+  DEPENDS:=
+  HIDDEN:=
+  DEFAULT:=
+  VARIANT:=$(1)
+  AT91BOOTSTRAP_CONFIG:=$(1)
+endef
+
+TARGET_DEP = TARGET_$(BUILD_TARGET)$(if $(BUILD_SUBTARGET),_$(BUILD_SUBTARGET))
+
+AT91BOOTSTRAP_MAKE_FLAGS = \
+	HOSTCC="$(HOSTCC)" \
+	HOSTCFLAGS="$(HOST_CFLAGS) $(HOST_CPPFLAGS)" \
+	HOSTLDFLAGS=""
+
+define Build/AT91Bootstrap/Target
+  $(eval $(call AT91Bootstrap/Init,$(1)))
+  $(eval $(call AT91Bootstrap/Default,$(1)))
+  $(eval $(call AT91Bootstrap/$(1),$(1)))
+
+  define Package/at91bootstrap-$(1)
+    SECTION:=boot
+    CATEGORY:=Boot Loaders
+    TITLE:= .$(NAME)
+    VARIANT:=$(VARIANT)
+    DEPENDS:=@!IN_SDK $(DEPENDS)
+    HIDDEN:=$(HIDDEN)
+    ifneq ($(BUILD_TARGET),)
+      DEPENDS += @$(TARGET_DEP)
+      ifneq ($(BUILD_DEVICES),)
+        DEFAULT := y if ($(TARGET_DEP)_Default \
+          $(patsubst %,|| $(TARGET_DEP)_DEVICE_%,$(BUILD_DEVICES)) \
+          $(patsubst %,|| $(patsubst TARGET_%,TARGET_DEVICE_%, \
+          $(TARGET_DEP))_DEVICE_%,$(BUILD_DEVICES)))
+      endif
+    endif
+    $(if $(DEFAULT),DEFAULT:=$(DEFAULT))
+    URL:=https://www.at91.com/linux4sam/bin/view/Linux4SAM/AT91Bootstrap
+  endef
+
+  define Package/at91bootstrap-$(1)/install
+    $$(Package/at91bootstrap/install)
+  endef
+endef
+
+define Build/Configure/AT91Bootstrap
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		$(AT91BOOTSTRAP_CONFIG)_defconfig
+endef
+
+
+define Build/Compile/AT91Bootstrap
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS) \
+		$(AT91BOOTSTRAP_MAKE_FLAGS)
+endef
+
+define BuildPackage/AT91Bootstrap/Defaults
+	Build/Configure/Default = $$$$(Build/Configure/AT91Bootstrap)
+	Build/Compile/Default = $$$$(Build/Compile/AT91Bootstrap)
+endef
+
+define BuildPackage/AT91Bootstrap
+	$(eval $(call BuildPackage/AT91Bootstrap/Defaults))
+	$(foreach type,$(if $(DUMP),$(AT91BOOTSTRAP_TARGETS),$(BUILD_VARIANT)), \
+		$(eval $(call Build/AT91Bootstrap/Target,$(type)))
+	)
+	$(eval $(call Build/DefaultTargets))
+	$(foreach type,$(if $(DUMP),$(AT91BOOTSTRAP_TARGETS),$(BUILD_VARIANT)), \
+		$(call BuildPackage,at91bootstrap-$(type))
+	)
+endef
diff --git a/package/boot/fconfig/Makefile b/package/boot/fconfig/Makefile
new file mode 100644
index 0000000..5784477
--- /dev/null
+++ b/package/boot/fconfig/Makefile
@@ -0,0 +1,38 @@
+#
+# Copyright (C) 2006-2008 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=fconfig
+PKG_VERSION:=20080329
+PKG_RELEASE:=1
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=@OPENWRT
+PKG_HASH:=4ff0e8f07e35e46b705c0dbe9d9544ede01ea092a69e3f7db03e55a3f2bb8eb7
+
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/fconfig
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Boot Loaders
+  TITLE:=RedBoot configuration editor
+endef
+
+define Package/fconfig/description
+	displays and (if writable) also edits the RedBoot configuration.
+endef
+
+define Package/fconfig/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/fconfig $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,fconfig))
diff --git a/package/boot/grub2/Makefile b/package/boot/grub2/Makefile
new file mode 100644
index 0000000..46e3597
--- /dev/null
+++ b/package/boot/grub2/Makefile
@@ -0,0 +1,157 @@
+#
+# Copyright (C) 2006-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)/kernel.mk
+
+PKG_NAME:=grub
+PKG_CPE_ID:=cpe:/a:gnu:grub2
+PKG_VERSION:=2.04
+PKG_RELEASE:=3
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@GNU/grub
+PKG_HASH:=e5292496995ad42dabe843a0192cf2a2c502e7ffcc7479398232b10a472df77d
+
+HOST_BUILD_PARALLEL:=1
+PKG_BUILD_DEPENDS:=grub2/host
+
+PKG_ASLR_PIE:=0
+PKG_SSP:=0
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+define Package/grub2/Default
+  CATEGORY:=Boot Loaders
+  SECTION:=boot
+  TITLE:=GRand Unified Bootloader ($(1))
+  URL:=http://www.gnu.org/software/grub/
+  DEPENDS:=@TARGET_x86
+  VARIANT:=$(1)
+endef
+
+Package/grub2=$(call Package/grub2/Default,pc)
+Package/grub2-efi=$(call Package/grub2/Default,efi)
+
+define Package/grub2-editenv
+  CATEGORY:=Utilities
+  SECTION:=utils
+  SUBMENU:=Boot Loaders
+  TITLE:=Grub2 Environment editor
+  URL:=http://www.gnu.org/software/grub/
+  DEPENDS:=@TARGET_x86
+  VARIANT:=pc
+endef
+
+define Package/grub2-editenv/description
+	Edit grub2 environment files.
+endef
+
+HOST_BUILD_PREFIX := $(STAGING_DIR_HOST)
+
+CONFIGURE_VARS += \
+	grub_build_mkfont_excuse="don't want fonts"
+
+CONFIGURE_ARGS += \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--disable-werror \
+	--disable-nls \
+	--disable-device-mapper \
+	--disable-libzfs \
+	--disable-grub-mkfont \
+	--with-platform=$(BUILD_VARIANT)
+
+HOST_CONFIGURE_VARS += \
+	grub_build_mkfont_excuse="don't want fonts"
+
+HOST_CONFIGURE_ARGS += \
+	--disable-grub-mkfont \
+	--target=$(REAL_GNU_TARGET_NAME) \
+	--sbindir="$(STAGING_DIR_HOST)/bin" \
+	--disable-werror \
+	--disable-libzfs \
+	--disable-nls \
+	--with-platform=none
+
+HOST_MAKE_FLAGS += \
+	TARGET_RANLIB=$(TARGET_RANLIB) \
+	LIBLZMA=$(STAGING_DIR_HOST)/lib/liblzma.a
+
+TARGET_CFLAGS := $(filter-out -fno-plt,$(TARGET_CFLAGS))
+
+define Host/Configure
+	$(SED) 's,(RANLIB),(TARGET_RANLIB),' $(HOST_BUILD_DIR)/grub-core/Makefile.in
+	$(Host/Configure/Default)
+endef
+
+define Package/grub2/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/grub-bios-setup $(1)/usr/sbin/
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)/grub2
+	$(CP) $(PKG_BUILD_DIR)/grub-core/boot.img $(STAGING_DIR_IMAGE)/grub2/
+	$(CP) $(PKG_BUILD_DIR)/grub-core/cdboot.img $(STAGING_DIR_IMAGE)/grub2/
+	sed 's#msdos1#gpt1#g' ./files/grub-early.cfg >$(PKG_BUILD_DIR)/grub-early.cfg
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O i386-pc \
+		-c $(PKG_BUILD_DIR)/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/gpt-core.img \
+		at_keyboard biosdisk boot chain configfile fat linux ls part_gpt reboot serial vga
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O i386-pc \
+		-c ./files/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/generic-core.img \
+		at_keyboard biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O i386-pc \
+		-c ./files/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/eltorito.img \
+		at_keyboard biosdisk boot chain configfile iso9660 linux ls part_msdos reboot serial test vga
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O i386-pc \
+		-c ./files/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/legacy-core.img \
+		biosdisk boot chain configfile ext2 linux ls part_msdos reboot serial vga
+endef
+
+define Package/grub2-efi/install
+	sed 's#msdos1#gpt1#g' ./files/grub-early.cfg >$(PKG_BUILD_DIR)/grub-early.cfg
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O $(CONFIG_ARCH)-efi \
+		-c $(PKG_BUILD_DIR)/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/boot$(if $(CONFIG_x86_64),x64,ia32).efi \
+		at_keyboard boot chain configfile fat linux ls part_gpt reboot serial efi_gop efi_uga
+	$(STAGING_DIR_HOST)/bin/grub-mkimage \
+		-d $(PKG_BUILD_DIR)/grub-core \
+		-p /boot/grub \
+		-O $(CONFIG_ARCH)-efi \
+		-c ./files/grub-early.cfg \
+		-o $(STAGING_DIR_IMAGE)/grub2/iso-boot$(if $(CONFIG_x86_64),x64,ia32).efi \
+		at_keyboard boot chain configfile fat iso9660 linux ls part_msdos part_gpt reboot serial test efi_gop efi_uga
+endef
+
+define Package/grub2-editenv/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/grub-editenv $(1)/usr/sbin/
+endef
+
+$(eval $(call HostBuild))
+$(eval $(call BuildPackage,grub2))
+$(eval $(call BuildPackage,grub2-efi))
+$(eval $(call BuildPackage,grub2-editenv))
diff --git a/package/boot/grub2/files/grub-early.cfg b/package/boot/grub2/files/grub-early.cfg
new file mode 100644
index 0000000..4a5b5a6
--- /dev/null
+++ b/package/boot/grub2/files/grub-early.cfg
@@ -0,0 +1 @@
+configfile (hd0,msdos1)/boot/grub/grub.cfg
diff --git a/package/boot/grub2/patches/001-verifiers-Blocklist-fallout-cleanup.patch b/package/boot/grub2/patches/001-verifiers-Blocklist-fallout-cleanup.patch
new file mode 100644
index 0000000..74d68a6
--- /dev/null
+++ b/package/boot/grub2/patches/001-verifiers-Blocklist-fallout-cleanup.patch
@@ -0,0 +1,31 @@
+From: David Michael <fedora.dm0@gmail.com>
+Date: Fri, 5 Jul 2019 07:45:59 -0400
+Subject: [PATCH] verifiers: Blocklist fallout cleanup
+
+Blocklist fallout cleanup after commit 5c6f9bc15 (generic/blocklist: Fix
+implicit declaration of function grub_file_filter_disable_compression()).
+
+Signed-off-by: David Michael <fedora.dm0@gmail.com>
+Reviewed-by: Daniel Kiper <daniel.kiper@oracle.com>
+---
+
+--- a/grub-core/osdep/generic/blocklist.c
++++ b/grub-core/osdep/generic/blocklist.c
+@@ -59,7 +59,7 @@ grub_install_get_blocklist (grub_device_
+ 
+       grub_disk_cache_invalidate_all ();
+ 
+-      file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | FILE_TYPE_NO_DECOMPRESS);
++      file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | GRUB_FILE_TYPE_NO_DECOMPRESS);
+       if (file)
+ 	{
+ 	  if (grub_file_size (file) != core_size)
+@@ -116,7 +116,7 @@ grub_install_get_blocklist (grub_device_
+ 
+   grub_file_t file;
+   /* Now read the core image to determine where the sectors are.  */
+-  file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | FILE_TYPE_NO_DECOMPRESS);
++  file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | GRUB_FILE_TYPE_NO_DECOMPRESS);
+   if (! file)
+     grub_util_error ("%s", grub_errmsg);
+ 
diff --git a/package/boot/grub2/patches/100-grub_setup_root.patch b/package/boot/grub2/patches/100-grub_setup_root.patch
new file mode 100644
index 0000000..df671bc
--- /dev/null
+++ b/package/boot/grub2/patches/100-grub_setup_root.patch
@@ -0,0 +1,118 @@
+--- a/util/grub-setup.c
++++ b/util/grub-setup.c
+@@ -87,6 +87,8 @@ static struct argp_option options[] = {
+    N_("install even if problems are detected"), 0},
+   {"skip-fs-probe",'s',0,      0,
+    N_("do not probe for filesystems in DEVICE"), 0},
++  {"root-device", 'r', N_("DEVICE"), 0,
++   N_("use DEVICE as the root device"), 0},
+   {"verbose",     'v', 0,      0, N_("print verbose messages."), 0},
+   {"allow-floppy", 'a', 0,      0,
+    /* TRANSLATORS: The potential breakage isn't limited to floppies but it's
+@@ -130,6 +132,7 @@ struct arguments
+   char *core_file;
+   char *dir;
+   char *dev_map;
++  char *root_dev;
+   int  force;
+   int  fs_probe;
+   int allow_floppy;
+@@ -178,6 +181,13 @@ argp_parser (int key, char *arg, struct
+         arguments->dev_map = xstrdup (arg);
+         break;
+ 
++      case 'r':
++        if (arguments->root_dev)
++          free (arguments->root_dev);
++
++        arguments->root_dev = xstrdup (arg);
++        break;
++
+       case 'f':
+         arguments->force = 1;
+         break;
+@@ -313,7 +323,7 @@ main (int argc, char *argv[])
+   GRUB_SETUP_FUNC (arguments.dir ? : DEFAULT_DIRECTORY,
+ 		   arguments.boot_file ? : DEFAULT_BOOT_FILE,
+ 		   arguments.core_file ? : DEFAULT_CORE_FILE,
+-		   dest_dev, arguments.force,
++		   arguments.root_dev, dest_dev, arguments.force,
+ 		   arguments.fs_probe, arguments.allow_floppy,
+ 		   arguments.add_rs_codes);
+ 
+--- a/util/setup.c
++++ b/util/setup.c
+@@ -252,13 +252,12 @@ identify_partmap (grub_disk_t disk __att
+ void
+ SETUP (const char *dir,
+        const char *boot_file, const char *core_file,
+-       const char *dest, int force,
++       const char *root, const char *dest, int force,
+        int fs_probe, int allow_floppy,
+        int add_rs_codes __attribute__ ((unused))) /* unused on sparc64 */
+ {
+   char *core_path;
+   char *boot_img, *core_img, *boot_path;
+-  char *root = 0;
+   size_t boot_size, core_size;
+   grub_uint16_t core_sectors;
+   grub_device_t root_dev = 0, dest_dev, core_dev;
+@@ -307,7 +306,10 @@ SETUP (const char *dir,
+ 
+   core_dev = dest_dev;
+ 
+-  {
++  if (root)
++    root_dev = grub_device_open(root);
++
++  if (!root_dev) {
+     char **root_devices = grub_guess_root_devices (dir);
+     char **cur;
+     int found = 0;
+@@ -320,6 +322,8 @@ SETUP (const char *dir,
+ 	char *drive;
+ 	grub_device_t try_dev;
+ 
++	if (root_dev)
++	  break;
+ 	drive = grub_util_get_grub_dev (*cur);
+ 	if (!drive)
+ 	  continue;
+--- a/include/grub/util/install.h
++++ b/include/grub/util/install.h
+@@ -191,13 +191,13 @@ grub_install_get_image_target (const cha
+ void
+ grub_util_bios_setup (const char *dir,
+ 		      const char *boot_file, const char *core_file,
+-		      const char *dest, int force,
++		      const char *root, const char *dest, int force,
+ 		      int fs_probe, int allow_floppy,
+ 		      int add_rs_codes);
+ void
+ grub_util_sparc_setup (const char *dir,
+ 		       const char *boot_file, const char *core_file,
+-		       const char *dest, int force,
++		       const char *root, const char *dest, int force,
+ 		       int fs_probe, int allow_floppy,
+ 		       int add_rs_codes);
+ 
+--- a/util/grub-install.c
++++ b/util/grub-install.c
+@@ -1712,7 +1712,7 @@ main (int argc, char *argv[])
+ 	/*  Now perform the installation.  */
+ 	if (install_bootsector)
+ 	  grub_util_bios_setup (platdir, "boot.img", "core.img",
+-				install_drive, force,
++				NULL, install_drive, force,
+ 				fs_probe, allow_floppy, add_rs_codes);
+ 	break;
+       }
+@@ -1738,7 +1738,7 @@ main (int argc, char *argv[])
+ 	/*  Now perform the installation.  */
+ 	if (install_bootsector)
+ 	  grub_util_sparc_setup (platdir, "boot.img", "core.img",
+-				 install_drive, force,
++				 NULL, install_drive, force,
+ 				 fs_probe, allow_floppy,
+ 				 0 /* unused */ );
+ 	break;
diff --git a/package/boot/grub2/patches/300-CVE-2015-8370.patch b/package/boot/grub2/patches/300-CVE-2015-8370.patch
new file mode 100644
index 0000000..22f6c90
--- /dev/null
+++ b/package/boot/grub2/patches/300-CVE-2015-8370.patch
@@ -0,0 +1,40 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Hector Marco-Gisbert <hecmargi@upv.es>
+Date: Fri, 13 Nov 2015 16:21:09 +0100
+Subject: [PATCH] Fix security issue when reading username and password
+
+  This patch fixes two integer underflows at:
+    * grub-core/lib/crypto.c
+    * grub-core/normal/auth.c
+
+Resolves: CVE-2015-8370
+
+Signed-off-by: Hector Marco-Gisbert <hecmargi@upv.es>
+Signed-off-by: Ismael Ripoll-Ripoll <iripoll@disca.upv.es>
+---
+ grub-core/lib/crypto.c  | 2 +-
+ grub-core/normal/auth.c | 2 +-
+ 2 files changed, 2 insertions(+), 2 deletions(-)
+
+--- a/grub-core/lib/crypto.c
++++ b/grub-core/lib/crypto.c
+@@ -468,7 +468,7 @@ grub_password_get (char buf[], unsigned
+ 	  break;
+ 	}
+ 
+-      if (key == '\b')
++      if (key == '\b' && cur_len)
+ 	{
+ 	  if (cur_len)
+ 	    cur_len--;
+--- a/grub-core/normal/auth.c
++++ b/grub-core/normal/auth.c
+@@ -172,7 +172,7 @@ grub_username_get (char buf[], unsigned
+ 	  break;
+ 	}
+ 
+-      if (key == GRUB_TERM_BACKSPACE)
++      if (key == GRUB_TERM_BACKSPACE && cur_len)
+ 	{
+ 	  if (cur_len)
+ 	    {
diff --git a/package/boot/imx-bootlets/Makefile b/package/boot/imx-bootlets/Makefile
new file mode 100644
index 0000000..742c8a3
--- /dev/null
+++ b/package/boot/imx-bootlets/Makefile
@@ -0,0 +1,42 @@
+#
+# Copyright (C) 2006 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=imx-bootlets
+PKG_VERSION:=10.05.02
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://trabant.uid0.hu/openwrt/
+PKG_HASH:=09ecd81a64db5166a235932146faf08d0689bfc7ac04ac9fcc3a5bd809fba74a
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/imx-bootlets
+	SECTION:=boot
+	CATEGORY:=Boot Loaders
+	TITLE:=i.MX23/i.MX28 bootlets
+	DEPENDS:=@TARGET_mxs
+endef
+
+define Package/imx-bootlets/description
+ i.MX23/i.MX28 bootlets (for oLinuxino)
+endef
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE="$(TARGET_CROSS)"
+endef
+
+define Package/imx-bootlets/install
+	@echo Copying boot_prep and power_prep into staging - $(STAGING_DIR)
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/boot_prep/boot_prep $(STAGING_DIR)/boot_prep
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/linux_prep/output-target/linux_prep $(STAGING_DIR)/linux_prep
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/power_prep/power_prep $(STAGING_DIR)/power_prep
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/linux_prebuilt.db $(STAGING_DIR)/linux_prebuilt.db
+endef
+
+$(eval $(call BuildPackage,imx-bootlets))
+
diff --git a/package/boot/imx-bootlets/patches/001-skip_sb_generation.patch b/package/boot/imx-bootlets/patches/001-skip_sb_generation.patch
new file mode 100644
index 0000000..7267dff
--- /dev/null
+++ b/package/boot/imx-bootlets/patches/001-skip_sb_generation.patch
@@ -0,0 +1,18 @@
+--- imx-bootlets-src-10.05.02.orig/Makefile	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-src-10.05.02/Makefile	2012-10-24 21:41:44.000000000 +0200
+@@ -32,10 +32,11 @@
+ 	sed -i 's,[^ *]image.*;,\timage="$(DFT_UBOOT)";,' uboot.db
+ 	elftosb2 -z -c ./uboot.db -o i$(ARCH)_uboot.sb
+ else
+-	@echo "by using the pre-built kernel"
+-	elftosb2 -z -c ./linux_prebuilt.db -o i$(ARCH)_linux.sb
+-	@echo "generating U-Boot boot stream image"
+-	elftosb2 -z -c ./uboot_prebuilt.db -o i$(ARCH)_uboot.sb
++	@echo "... not generating any image for now."
++	#@echo "by using the pre-built kernel"
++	#elftosb2 -z -c ./linux_prebuilt.db -o i$(ARCH)_linux.sb
++	#@echo "generating U-Boot boot stream image"
++	#elftosb2 -z -c ./uboot_prebuilt.db -o i$(ARCH)_uboot.sb
+ endif
+ 	#@echo "generating kernel bootstream file sd_mmc_bootstream.raw"
+ 	#Please use cfimager to burn xxx_linux.sb. The below way will no
diff --git a/package/boot/imx-bootlets/patches/002-set_elftosb_config.patch b/package/boot/imx-bootlets/patches/002-set_elftosb_config.patch
new file mode 100644
index 0000000..88b904e
--- /dev/null
+++ b/package/boot/imx-bootlets/patches/002-set_elftosb_config.patch
@@ -0,0 +1,17 @@
+--- imx-bootlets-10.05.02.orig/linux_prebuilt.db	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/linux_prebuilt.db	2012-10-24 22:04:37.000000000 +0200
+@@ -4,10 +4,10 @@
+ 	flags = 0x01;
+ }
+ sources {
+-	power_prep="./power_prep/power_prep";
+-	sdram_prep="./boot_prep/boot_prep";
+-	linux_prep="./linux_prep/output-target/linux_prep";
+-	zImage = "./zImage";
++	power_prep="./power_prep";
++	sdram_prep="./boot_prep";
++	linux_prep="./linux_prep";
++	zImage = "./zImage_dtb";
+ }
+ 
+ section (0) {
diff --git a/package/boot/imx-bootlets/patches/003-add-olinuxino.patch b/package/boot/imx-bootlets/patches/003-add-olinuxino.patch
new file mode 100644
index 0000000..ddc25bc
--- /dev/null
+++ b/package/boot/imx-bootlets/patches/003-add-olinuxino.patch
@@ -0,0 +1,150 @@
+diff -ruN imx-bootlets-10.05.02.orig/linux_prep/board/imx23_olinuxino_dev.c imx-bootlets-10.05.02/linux_prep/board/imx23_olinuxino_dev.c
+--- imx-bootlets-10.05.02.orig/linux_prep/board/imx23_olinuxino_dev.c	1970-01-01 01:00:00.000000000 +0100
++++ imx-bootlets-10.05.02/linux_prep/board/imx23_olinuxino_dev.c	2013-05-19 00:11:40.000000000 +0200
+@@ -0,0 +1,54 @@
++/*
++ * Platform specific data for the IMX23_OLINUXINO development board
++ *
++ * Fadil Berisha <fadil.r.berisha@gmail.com>
++ *
++ * Copyright 2008 SigmaTel, Inc
++ * Copyright 2008 Embedded Alley Solutions, Inc
++ * Copyright 2009-2010 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ * This file is licensed under the terms of the GNU General Public License
++ * version 2. This program is licensed "as is" without any warranty of any
++ * kind, whether express or implied.
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++#include <setup.h>
++#include <keys.h>
++#include <lradc_buttons.h>
++
++/************************************************
++ * LRADC keyboard data *
++ ************************************************/
++int lradc_keypad_ch = LRADC_CH0;
++int lradc_vddio_ch = LRADC_CH6;
++
++struct lradc_keycode lradc_keycodes[] = {
++ { 100, KEY4 },
++ { 306, KEY5 },
++ { 601, KEY6 },
++ { 932, KEY7 },
++ { 1260, KEY8 },
++ { 1424, KEY9 },
++ { 1707, KEY10 },
++ { 2207, KEY11 },
++ { 2525, KEY12 },
++ { 2831, KEY13 },
++ { 3134, KEY14 },
++ { -1, 0 },
++};
++
++/************************************************
++ * Magic key combinations for Armadillo *
++ ************************************************/
++u32 magic_keys[MAGIC_KEY_NR] = {
++ [MAGIC_KEY1] = KEY4,
++ [MAGIC_KEY2] = KEY6,
++ [MAGIC_KEY3] = KEY10,
++};
++
++/************************************************
++ * Default command line *
++ ************************************************/
++char cmdline_def[] = "console=ttyAMA0,115200";
+diff -ruN imx-bootlets-10.05.02.orig/linux_prep/cmdlines/imx23_olinuxino_dev.txt imx-bootlets-10.05.02/linux_prep/cmdlines/imx23_olinuxino_dev.txt
+--- imx-bootlets-10.05.02.orig/linux_prep/cmdlines/imx23_olinuxino_dev.txt	1970-01-01 01:00:00.000000000 +0100
++++ imx-bootlets-10.05.02/linux_prep/cmdlines/imx23_olinuxino_dev.txt	2013-05-19 00:12:56.000000000 +0200
+@@ -0,0 +1 @@
++noinitrd console=ttyAMA0,115200 root=/dev/mmcblk0p2 rw rootwait ssp1=mmc
+diff -ruN imx-bootlets-10.05.02.orig/linux_prep/core/setup.c imx-bootlets-10.05.02/linux_prep/core/setup.c
+--- imx-bootlets-10.05.02.orig/linux_prep/core/setup.c	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/linux_prep/core/setup.c	2013-05-19 00:11:40.000000000 +0200
+@@ -84,6 +84,8 @@
+ #include "../../mach-mx28/includes/registers/regsrtc.h"
+ #elif defined(STMP378X)
+ #include "../../mach-mx23/includes/registers/regsrtc.h"
++#elif defined(IMX23_OLINUXINO)
++#include "../../mach-mx23/includes/registers/regsrtc.h"
+ #endif
+ 
+ #define NAND_SECONDARY_BOOT          0x00000002
+diff -ruN imx-bootlets-10.05.02.orig/linux_prep/include/mx23/platform.h imx-bootlets-10.05.02/linux_prep/include/mx23/platform.h
+--- imx-bootlets-10.05.02.orig/linux_prep/include/mx23/platform.h	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/linux_prep/include/mx23/platform.h	2013-05-19 00:11:40.000000000 +0200
+@@ -19,6 +19,10 @@
+ 
+ #if defined (BOARD_STMP378X_DEV)
+ #define	MACHINE_ID	0xa45
++
++#elif defined (BOARD_IMX23_OLINUXINO_DEV)
++#define MACHINE_ID 0x1009
++
+ #else
+ #error "Allocate a machine ID for your board"
+ #endif
+diff -ruN imx-bootlets-10.05.02.orig/linux_prep/Makefile imx-bootlets-10.05.02/linux_prep/Makefile
+--- imx-bootlets-10.05.02.orig/linux_prep/Makefile	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/linux_prep/Makefile	2013-05-19 00:11:40.000000000 +0200
+@@ -69,6 +69,11 @@
+ HW_OBJS = $(LRADC_OBJS)
+ CFLAGS += -DMX28 -DBOARD_MX28_EVK
+ endif
++ifeq ($(BOARD), imx23_olinuxino_dev)
++ARCH = mx23
++HW_OBJS = $(LRADC_OBJS)
++CFLAGS += -DIMX23_OLINUXINO -DBOARD_IMX23_OLINUXINO_DEV
++endif
+ 
+ # Generic code
+ CORE_OBJS = entry.o resume.o cmdlines.o setup.o keys.o
+diff -ruN imx-bootlets-10.05.02.orig/Makefile imx-bootlets-10.05.02/Makefile
+--- imx-bootlets-10.05.02.orig/Makefile	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/Makefile	2013-05-19 00:15:02.000000000 +0200
+@@ -3,9 +3,9 @@
+ export MEM_TYPE
+ 
+ DFT_IMAGE=$(DEV_IMAGE)/boot/zImage
+-DFT_UBOOT=$(DEV_IMAGE)/boot/u-boot
++DFT_UBOOT=../boot/u-boot
+ 
+-BOARD ?= stmp378x_dev
++BOARD ?= imx23_olinuxino_dev
+ 
+ ifeq ($(BOARD), stmp37xx_dev)
+ ARCH = 37xx
+@@ -16,6 +16,9 @@
+ ifeq ($(BOARD), iMX28_EVK)
+ ARCH = mx28
+ endif
++ifeq ($(BOARD), imx23_olinuxino_dev)
++ARCH = mx23
++endif
+ 
+ all: build_prep gen_bootstream
+ 
+@@ -93,6 +96,8 @@
+ clean:
+ 	-rm -rf *.sb
+ 	rm -f sd_mmc_bootstream.raw
++	rm -f linux_prep/board/*.o
++	rm -f power_prep/*.o
+ 	$(MAKE) -C linux_prep clean ARCH=$(ARCH)
+ 	$(MAKE) -C boot_prep clean ARCH=$(ARCH)
+ 	$(MAKE) -C power_prep clean ARCH=$(ARCH)
+diff -ruN imx-bootlets-10.05.02.orig/uboot.db imx-bootlets-10.05.02/uboot.db
+--- imx-bootlets-10.05.02.orig/uboot.db	2010-05-14 06:56:28.000000000 +0200
++++ imx-bootlets-10.05.02/uboot.db	2013-05-19 00:11:40.000000000 +0200
+@@ -3,7 +3,7 @@
+ sources {
+ 	power_prep="./power_prep/power_prep";
+ 	sdram_prep="./boot_prep/boot_prep";
+-	image="/home/b18647/repos/ltib_latest/rootfs/boot/u-boot";
++	image="../boot/u-boot";
+ }
+ 
+ section (0) {
diff --git a/package/boot/kexec-tools/Config.in b/package/boot/kexec-tools/Config.in
new file mode 100644
index 0000000..068c27e
--- /dev/null
+++ b/package/boot/kexec-tools/Config.in
@@ -0,0 +1,14 @@
+menu "Configuration"
+	depends on PACKAGE_kexec
+
+config KEXEC_ZLIB
+	bool
+	prompt "zlib support"
+	default y
+
+config KEXEC_LZMA
+	bool
+	prompt "lzma support"
+	default n
+
+endmenu
diff --git a/package/boot/kexec-tools/Makefile b/package/boot/kexec-tools/Makefile
new file mode 100644
index 0000000..269345a
--- /dev/null
+++ b/package/boot/kexec-tools/Makefile
@@ -0,0 +1,135 @@
+#
+# Copyright (C) 2006-2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=kexec-tools
+PKG_VERSION:=2.0.16
+PKG_RELEASE:=2
+
+PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.xz
+PKG_SOURCE_URL:=@KERNEL/linux/utils/kernel/kexec
+PKG_HASH:=5b103351ad752c9badd1d65b00eb6de4bce579f944f4df4e3ef3a755ba567010
+
+PKG_FIXUP:=autoreconf
+
+PKG_CONFIG_DEPENDS := CONFIG_KEXEC_ZLIB CONFIG_KEXEC_LZMA
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/kexec-tools/Default
+  SECTION:=utils
+  CATEGORY:=Utilities
+  URL:=http://kernel.org/pub/linux/kernel/people/horms/kexec-tools/
+endef
+
+define Package/kexec-tools
+  $(call Package/kexec-tools/Default)
+  TITLE:=kexec-tools transition meta package
+  DEPENDS:=+kexec
+endef
+
+define Package/kexec-tools/description
+ kexec is a set of system calls that allows you to load
+ another kernel from the currently executing Linux kernel.
+ The kexec utility allows to load and boot another kernel.
+endef
+
+define Package/kexec
+  $(call Package/kexec-tools/Default)
+  TITLE:=Kernel boots kernel
+  DEPENDS:=\
+	@(armeb||arm||i386||x86_64||powerpc64||mipsel||mips) \
+	+KEXEC_ZLIB:zlib +KEXEC_LZMA:liblzma @KERNEL_KEXEC
+endef
+
+define Package/kexec/description
+ The kexec utility allows to load and boot another kernel.
+endef
+
+define Package/kdump
+  $(call Package/kexec-tools/Default)
+  TITLE:=Kernel crash analysis
+  DEPENDS:=+kexec @(i386||x86_64||arm) @KERNEL_CRASH_DUMP
+endef
+
+define Package/kdump/description
+ The kdump package allows to automatically boot into a
+ special kernel for analyzing kernel crashes using kdump.
+endef
+
+define Package/kexec/config
+	source "$(SOURCE)/Config.in"
+endef
+
+KEXEC_TARGET_NAME:=$(ARCH)-linux-$(TARGET_SUFFIX)
+
+CONFIGURE_ARGS = \
+		--target=$(KEXEC_TARGET_NAME) \
+		--host=$(REAL_GNU_TARGET_NAME) \
+		--build=$(GNU_HOST_NAME) \
+		--program-prefix="" \
+		--program-suffix="" \
+		--prefix=/usr \
+		--exec-prefix=/usr \
+		--bindir=/usr/bin \
+		--sbindir=/usr/sbin \
+		--libexecdir=/usr/lib \
+		--sysconfdir=/etc \
+		$(if $(CONFIG_KEXEC_ZLIB),--with,--without)-zlib \
+		$(if $(CONFIG_KEXEC_LZMA),--with,--without)-lzma \
+		TARGET_LD="$(TARGET_CROSS)ld"
+
+TARGET_CFLAGS += -ffunction-sections -fdata-sections
+TARGET_LDFLAGS += -Wl,--gc-sections
+
+CONFIGURE_VARS += \
+	BUILD_CC="$(HOSTCC)" \
+	TARGET_CC="$(TARGET_CC)"
+
+define Build/Compile
+	$(MAKE) -C $(PKG_BUILD_DIR) DESTDIR="$(PKG_INSTALL_DIR)" all install
+endef
+
+define Package/kexec-tools/install
+	:
+endef
+
+define Package/kexec/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/kexec $(1)/usr/sbin
+
+# make a link for compatability with other distros
+	$(INSTALL_DIR) $(1)/sbin
+	$(LN) ../usr/sbin/kexec $(1)/sbin/kexec
+endef
+
+define Package/kdump/install
+	$(INSTALL_DIR) $(1)/usr/sbin $(1)/etc/init.d $(1)/etc/config $(1)/etc/uci-defaults
+	$(INSTALL_BIN) $(PKG_INSTALL_DIR)/usr/sbin/kdump $(PKG_INSTALL_DIR)/usr/sbin/vmcore-dmesg $(1)/usr/sbin
+	$(INSTALL_BIN) ./files/kdump.init $(1)/etc/init.d/kdump
+	$(INSTALL_BIN) ./files/kdump.defaults $(1)/etc/uci-defaults/kdump
+	$(INSTALL_CONF) ./files/kdump.config $(1)/etc/config/kdump
+endef
+
+define Package/kdump/prerm
+#!/bin/sh
+
+case $$(uname -m) in
+	i?86|x86_64)
+		if grep -q " crashkernel=" /boot/grub/grub.cfg; then
+			mount /boot -o remount,rw
+			sed -i 's/ crashkernel=[^ ]*//' /boot/grub/grub.cfg
+			mount /boot -o remount,ro
+		fi
+		;;
+esac
+endef
+
+$(eval $(call BuildPackage,kexec-tools))
+$(eval $(call BuildPackage,kexec))
+$(eval $(call BuildPackage,kdump))
diff --git a/package/boot/kexec-tools/files/kdump.config b/package/boot/kexec-tools/files/kdump.config
new file mode 100644
index 0000000..dc6054f
--- /dev/null
+++ b/package/boot/kexec-tools/files/kdump.config
@@ -0,0 +1,7 @@
+
+config kdump
+	option enabled '1'
+	option save_dmesg '1'
+	option save_vmcore '0'
+# using an external partition to store vmcore is highly recommended!
+#	option path '/mnt/crashdump'
diff --git a/package/boot/kexec-tools/files/kdump.defaults b/package/boot/kexec-tools/files/kdump.defaults
new file mode 100644
index 0000000..62366a2
--- /dev/null
+++ b/package/boot/kexec-tools/files/kdump.defaults
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+# kB disable if mem low than 256MB
+memtotal=`grep MemTotal /proc/meminfo | awk '{print $2}'`
+if test $memtotal -le 262144; then
+	exit 0
+fi
+KZ=128
+if test $memtotal -ge 8388608; then
+	KZ=512
+elif test $memtotal -ge 4194304; then
+	KZ=256
+fi
+
+case $(uname -m) in
+	i?86|x86_64)
+		if ! grep -q crashkernel /boot/grub/grub.cfg; then
+			mount /boot -o remount,rw
+			sed -i "s/linux.*/& crashkernel=${KZ}M/" /boot/grub/grub.cfg
+			mount /boot -o remount,ro
+		fi
+		;;
+esac
diff --git a/package/boot/kexec-tools/files/kdump.init b/package/boot/kexec-tools/files/kdump.init
new file mode 100755
index 0000000..9d0d2fc
--- /dev/null
+++ b/package/boot/kexec-tools/files/kdump.init
@@ -0,0 +1,186 @@
+#!/bin/sh /etc/rc.common
+
+START=41
+STOP=90
+
+BOOT_IMAGE=/boot/vmlinuz
+
+EXTRA_COMMANDS="status"
+EXTRA_HELP="        status  Print crashkernel status"
+
+verify_kdump() {
+	local cfg="$1"
+	local enabled
+	local path
+	local save_vmcore
+	local save_dmesg
+
+	config_get_bool enabled "$cfg" enabled 1
+	config_get_bool save_dmesg "$cfg" save_dmesg 1
+	config_get_bool save_vmcore "$cfg" save_vmcore 0
+
+	[ "$enabled" -gt 0 ] || return 2
+
+	[ "$save_dmesg" -gt 0 ] || [ "$save_vmcore" -gt 0 ] || return 2
+
+	config_get path "$cfg" path "/"
+
+	[ -d "$path" ] || mkdir -p "$path" 2>/dev/null || return 1
+}
+
+run_kdump() {
+	local cfg="$1"
+	local enabled
+	local path
+	local save_vmcore
+	local save_dmesg
+
+	config_get_bool enabled "$cfg" enabled 1
+	[ "$enabled" -gt 0 ] || return
+
+	config_get_bool save_dmesg "$cfg" save_dmesg 1
+	config_get_bool save_vmcore "$cfg" save_vmcore 0
+	config_get path "$cfg" path "/"
+
+	timestamp=$(date "+%Y%m%dT%H%M%S")
+
+	if [ "$save_vmcore" -eq 1 ]; then
+		echo -n "Saving vmcore (this may take a while)..."
+		# would like 'sparse' but busybox doesn't support it
+		dd if=/proc/vmcore of="$path/vmcore-$timestamp" conv=fsync bs=1M
+		echo " done"
+	fi
+
+	if [ "$save_dmesg" -eq 1 ]; then
+		vmcore-dmesg /proc/vmcore > "$path/dmesg-$timestamp"
+	fi
+
+	sync
+	reboot -f
+}
+
+find_kernel() {
+	. /lib/functions.sh
+	local kernel
+
+	kernel="$BOOT_IMAGE"
+	if [ -r "$kernel" ]; then
+		echo $kernel
+		return 0
+	fi
+
+	kernel="$(find_mtd_part kernel)"
+	if [ -r "$kernel" ]; then
+		echo $kernel
+		return 0
+	fi
+
+	for voldir in /sys/class/ubi/ubi*_*; do
+		[ ! -e "$voldir" ] && continue
+		if [ "$(cat "${voldir}/name")" = "kernel" ]; then
+			kernel="/dev/$(basename "$voldir")"
+			echo $kernel
+			return 0
+		fi
+	done
+
+	return 1
+}
+
+load_crashkernel() {
+	local append_cmdline
+	local kernel
+
+	kernel="$(find_kernel)"
+	[ $? -gt 0 ] && return 1
+
+	case "$(uname -m)" in
+		i?86|x86_64)
+			grep -q "crashkernel=" /proc/cmdline || return 1
+			append_cmdline="1 irqpoll reset_devices maxcpus=1"
+			;;
+		arm*)
+			append_cmdline="1 maxcpus=1 reset_devices"
+			;;
+	esac
+	kexec -p "$kernel" --reuse-cmdline --append="$append_cmdline"
+	return $?
+}
+
+start() {
+	local retval
+
+	if [ ! -e /sys/kernel/kexec_crash_loaded ]; then
+		return 1
+	fi
+
+	if [ -e /proc/vmcore ]; then
+		config_load kdump
+		config_foreach run_kdump kdump
+	else
+		config_load kdump
+		config_foreach verify_kdump kdump
+		retval=$?
+		[ $retval = 1 ] && return 1
+		[ $retval = 0 ] && load_crashkernel
+		return $?
+	fi
+}
+
+stop() {
+	[ "$(cat /sys/kernel/kexec_crash_loaded)" = "1" ] || return
+
+	if [ -e "$BOOT_IMAGE" ]; then
+		kexec -p -u "$BOOT_IMAGE"
+	fi
+}
+
+status() {
+	local retval kernel
+
+	if [ ! -e /sys/kernel/kexec_crash_loaded ]; then
+		echo "crashdump not supported by kernel"
+		return
+	fi
+
+	if [ $(cat /sys/kernel/kexec_crash_size) -eq 0 ]; then
+		echo "memory for crashdump kernel not reserved!"
+		echo "check crashkernel= kernel cmdline parameter"
+		echo "(a reboot is required after installing kdump)"
+		return
+	fi
+
+	kernel="$(find_kernel)"
+	if [ $? -gt 0 ]; then
+		echo "cannot find kernel image"
+		return
+	else
+		echo "using kernel image $kernel"
+	fi
+
+	echo -n "kdump configuration is "
+	config_load kdump
+	retval=$?
+	if [ $retval = 0 ]; then
+		if [ "$(config_foreach echo kdump)" ]; then
+			config_foreach verify_kdump kdump
+			retval=$?
+		else
+			retval=1
+		fi
+	fi
+
+	if [ $retval = 0 ]; then
+		echo "valid"
+	elif [ $retval = 2 ]; then
+		echo "disabled"
+	else
+		echo "BROKEN"
+	fi
+
+	echo -n "kexec crash kernel "
+	if [ "$(cat /sys/kernel/kexec_crash_loaded)" = "0" ]; then
+		echo -n "not "
+	fi
+	echo "loaded"
+}
diff --git a/package/boot/kexec-tools/patches/100-kexec-tools-fix-for-Unhandled-rela-relocation-R_X86_64_PLT32-error.patch b/package/boot/kexec-tools/patches/100-kexec-tools-fix-for-Unhandled-rela-relocation-R_X86_64_PLT32-error.patch
new file mode 100644
index 0000000..dfad219
--- /dev/null
+++ b/package/boot/kexec-tools/patches/100-kexec-tools-fix-for-Unhandled-rela-relocation-R_X86_64_PLT32-error.patch
@@ -0,0 +1,14 @@
+diff --git a/kexec/arch/x86_64/kexec-elf-rel-x86_64.c b/kexec/arch/x86_64/kexec-elf-rel-x86_64.c
+index 7fdde73..af33689 100644
+--- a/kexec/arch/x86_64/kexec-elf-rel-x86_64.c
++++ b/kexec/arch/x86_64/kexec-elf-rel-x86_64.c
+@@ -78,7 +78,8 @@ void machine_apply_elf_rel(struct mem_ehdr *UNUSED(ehdr),
+ 		if ((int64_t)value != *(int32_t *)location)
+ 			goto overflow;
+ 		break;
+-	case R_X86_64_PC32: 
++	case R_X86_64_PC32:
++	case R_X86_64_PLT32:
+ 		*(uint32_t *)location = value - address;
+ 		break;
+ 	default:
diff --git a/package/boot/kobs-ng/Makefile b/package/boot/kobs-ng/Makefile
new file mode 100644
index 0000000..3fa8302
--- /dev/null
+++ b/package/boot/kobs-ng/Makefile
@@ -0,0 +1,46 @@
+#
+# Copyright (C) 2013-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=kobs-ng
+PKG_VERSION:=5.4
+PKG_RELEASE:=1
+
+PKG_SOURCE:=imx-kobs-$(PKG_VERSION).tar.gz
+PKG_SOURCE_URL:=http://www.freescale.com/lgfiles/NMG/MAD/YOCTO/
+PKG_HASH:=85171b46068ac47c42fedb8104167bf9afd33dd9527ed127e1ca2eb29d7a86bf
+PKG_BUILD_DIR:=$(BUILD_DIR)/imx-kobs-$(PKG_VERSION)
+
+PKG_LICENSE:=GPLv2
+PKG_LICENSE_FILES:=COPYING
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/kobs-ng
+  SECTION:=utils
+  CATEGORY:=Utilities
+  TITLE:=Application for writing bootstreams to NAND flash
+  DEPENDS:=@TARGET_imx6
+endef
+
+define Package/kobs-ng/description
+ The kobs-ng application writes a bootstream to NAND flash with the proper
+ FCB/DBBT headers and replicated streams.
+endef
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+	echo "const char* git_sha = \"$(PKG_VERSION)\";" > $(PKG_BUILD_DIR)/autoversion.h
+endef
+
+define Package/kobs-ng/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/src/kobs-ng $(1)/usr/sbin/
+endef
+
+$(eval $(call BuildPackage,kobs-ng))
diff --git a/package/boot/kobs-ng/patches/001-compile.patch b/package/boot/kobs-ng/patches/001-compile.patch
new file mode 100644
index 0000000..8648dc8
--- /dev/null
+++ b/package/boot/kobs-ng/patches/001-compile.patch
@@ -0,0 +1,24 @@
+--- a/src/mtd.c
++++ b/src/mtd.c
+@@ -28,6 +28,7 @@
+ #include <unistd.h>
+ #include <stdlib.h>
+ #include <string.h>
++#include <stddef.h>
+ #include <fcntl.h>
+ #include <ctype.h>
+ #include <errno.h>
+--- a/src/mtd.h
++++ b/src/mtd.h
+@@ -25,8 +25,11 @@
+ #ifndef MTD_H
+ #define MTD_H
+ 
++#define _GNU_SOURCE
+ #include <mtd/mtd-user.h>
+ #include <endian.h>
++#include <stdint.h>
++#include <fcntl.h>
+ 
+ #include "BootControlBlocks.h"
+ #include "rom_nand_hamming_code_ecc.h"
diff --git a/package/boot/kobs-ng/patches/002-add-init-size-param.patch b/package/boot/kobs-ng/patches/002-add-init-size-param.patch
new file mode 100644
index 0000000..8ad34e9
--- /dev/null
+++ b/package/boot/kobs-ng/patches/002-add-init-size-param.patch
@@ -0,0 +1,45 @@
+Add --chip_0_size param to override the size of the mtd partition which is
+required if the SPL does not occupy the entire partition. For Gateworks
+Ventana boards the 'uboot' partition contains both the SPL and uboot.
+--- a/src/main.c
++++ b/src/main.c
+@@ -94,6 +94,7 @@ void usage(void)
+ 	"  [KOBS] boot structures config options\n"
+ 	"    --chip_0_device_path=<path> .......... Device of boot (default /dev/mtd0)\n"
+ 	"    --chip_1_device_path=<path> .......... The second chip in case of multichip NAND\n"
++	"    --chip_0_size=<size> ................. Override size of chip_0 device\n"
+ 	"    --search_exponent=<value> ............ NCB field (default 2)\n"
+ 	"    --data_setup_time=<value> ............ NCB field (default 80)\n"
+ 	"    --data_hold_time=<value> ............. NCB field (default 60)\n"
+--- a/src/mtd.c
++++ b/src/mtd.c
+@@ -876,6 +876,11 @@ struct mtd_data *mtd_open(const struct m
+ 			goto out;
+ 		}
+ 
++		/* override MTD size */
++		if (md->cfg.chip_0_size) {
++			miu->size = md->cfg.chip_0_size;
++		}
++
+ 		/* verify it's a nand */
+ 		if (miu->type != MTD_NANDFLASH
+ 			&& miu->type != MTD_MLCNANDFLASH) {
+@@ -3385,7 +3390,7 @@ static const struct {
+ } mtd_int_args[] = {
+ 	ARG_IGNORE(chip_count),
+ 	ARG_IGNORE(chip_0_offset),
+-	ARG_IGNORE(chip_0_size),
++	ARG(chip_0_size),
+ 	ARG_IGNORE(chip_1_offset),
+ 	ARG_IGNORE(chip_1_size),
+ 	ARG(search_exponent),
+@@ -3578,7 +3583,7 @@ void mtd_cfg_dump(struct mtd_config *cfg
+ //	Pd(chip_count);
+ 	Ps(chip_0_device_path);
+ //	Pd(chip_0_offset);
+-//	Pd(chip_0_size);
++	Pd(chip_0_size);
+ 	Ps(chip_1_device_path);
+ //	Pd(chip_1_offset);
+ //	Pd(chip_1_size);
diff --git a/package/boot/kobs-ng/patches/003-raw-mode.patch b/package/boot/kobs-ng/patches/003-raw-mode.patch
new file mode 100644
index 0000000..5a3be5f
--- /dev/null
+++ b/package/boot/kobs-ng/patches/003-raw-mode.patch
@@ -0,0 +1,45 @@
+The downstream Freescale vendor kernel has a patch that allows determining
+if raw NAND flash mode is provided via a debugfs file. This is not present
+in upstream kernels, but the raw access support was added in the 3.19
+kernel, so we will check the kernel version if we can't find the file.
+--- a/src/mtd.c
++++ b/src/mtd.c
+@@ -34,6 +34,7 @@
+ #include <errno.h>
+ #include <sys/types.h>
+ #include <sys/ioctl.h>
++#include <sys/utsname.h>
+ 
+ #include "mtd.h"
+ #include "rand.h"
+@@ -808,15 +809,27 @@ struct mtd_data *mtd_open(const struct m
+ 	md->cfg = *cfg;
+ 
+ 	/* check if use new raw access mode */
++	/* by looking for debugfs from fsl patch */
++	md->raw_mode_flag = 0;
+ 	fp = fopen("/sys/kernel/debug/gpmi-nand/raw_mode", "r");
+ 	if (!fp) {
+-		md->raw_mode_flag = 0;
+-		vp(md, "mtd: use legacy raw access mode\n");
++		/* fallback to kernel version: raw access added in 3.19 */
++		struct utsname uts;
++		if (!uname(&uts)) {
++			int major = 0, minor = 0;
++			sscanf(uts.release, "%d.%d", &major, &minor);
++			vp(md, "mtd: Linux %d.%d\n", major, minor);
++			if ((major << 8 | minor) > (3 << 8 | 18))
++				md->raw_mode_flag = 1;
++		}
+ 	} else {
+ 		fclose(fp);
+ 		md->raw_mode_flag = 1;
+-		vp(md, "mtd: use new bch layout raw access mode\n");
+ 	}
++	if (md->raw_mode_flag)
++		vp(md, "mtd: use new bch layout raw access mode\n");
++	else
++		vp(md, "mtd: use legacy raw access mode\n");
+ 
+ 	if (plat_config_data->m_u32UseMultiBootArea) {
+ 
diff --git a/package/boot/kobs-ng/patches/004-fix-cal_nfc_geometry.patch b/package/boot/kobs-ng/patches/004-fix-cal_nfc_geometry.patch
new file mode 100644
index 0000000..ebfd623
--- /dev/null
+++ b/package/boot/kobs-ng/patches/004-fix-cal_nfc_geometry.patch
@@ -0,0 +1,27 @@
+The Freescale downstream vendor kernel has a patch that exports the bch
+flash geometry via a debugfs file. This is not available in mainline linux
+kernels so the fallback method calculates the geometry based on known info
+from the mtd partition. A bug exists in this funcion where it fails to
+assume that block0 ECC is the same as the other blocks by default.
+--- a/src/mtd.c
++++ b/src/mtd.c
+@@ -610,7 +610,7 @@ static int cal_nfc_geometry(struct mtd_d
+ 	/* The two are fixed, please change them when the driver changes. */
+ 	geo->metadata_size_in_bytes = 10;
+ 	geo->gf_len = 13;
+-	geo->ecc_chunkn_size_in_bytes = 512;
++	geo->ecc_chunkn_size_in_bytes = geo->ecc_chunk0_size_in_bytes = 512;
+ 
+ 	if (mtd->oobsize > geo->ecc_chunkn_size_in_bytes) {
+ 		geo->gf_len = 14;
+@@ -700,8 +700,9 @@ int parse_nfc_geometry(struct mtd_data *
+ 	unsigned int       value;
+ 
+ 	if (!plat_config_data->m_u32UseNfcGeo) {
++		/* fsl kernel patch provides bch_geometry via debugfs */
+ 		if (!(node = fopen(dbg_geometry_node_path, "r"))) {
+-			fprintf(stderr, "Cannot open BCH geometry node: \"%s\"",
++			fprintf(stderr, "Cannot open BCH geometry node: \"%s\"\n",
+ 				dbg_geometry_node_path);
+ 			return cal_nfc_geometry(md);
+ 		}
diff --git a/package/boot/mt7623n-preloader/Makefile b/package/boot/mt7623n-preloader/Makefile
new file mode 100644
index 0000000..0faaf46
--- /dev/null
+++ b/package/boot/mt7623n-preloader/Makefile
@@ -0,0 +1,83 @@
+#
+# Copyright © 2020 David Woodhouse <dwmw2@infradead.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)/kernel.mk
+
+PKG_NAME:=mt7623n-preloader
+PKG_VERSION:=2020-03-11
+PKG_RELEASE:=b27114e184449a33b5d875fda14198f5e6fee2bb
+
+PKG_MAINTAINER:=David Woodhouse <dwmw2@infradead.org>
+
+PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/$(PKG_NAME)/$(PKG_NAME)-$(PKG_RELEASE)
+
+PKG_FLAGS:=nonshared
+
+include $(INCLUDE_DIR)/package.mk
+
+BPI_PRELOADER_URL:=@GITHUB/BPI-SINOVOIP/BPI-files/$(PKG_RELEASE)/SD/100MB/
+BPI_PRELOADER_PREFIX:=bpi-preloader-$(PKG_RELEASE)
+
+define Download/BPI-R2-preloader-2k.img.gz
+  FILE:=$(BPI_PRELOADER_PREFIX)-BPI-R2-preloader-DDR1600-20191024-2k.img.gz
+  URL:=$(BPI_PRELOADER_URL)
+  URL_FILE:=BPI-R2-preloader-DDR1600-20191024-2k.img.gz
+  HASH:=c731cc166c912c84846e2ed5faf727504e4dec1463754baa6328e9908c84a373
+endef
+$(eval $(call Download,BPI-R2-preloader-2k.img.gz))
+
+define Download/BPI-R64-preloader-2k.img.gz
+  FILE:=$(BPI_PRELOADER_PREFIX)-BPI-R64-preloader-2k.img.gz
+  URL:=$(BPI_PRELOADER_URL)
+  URL_FILE:=BPI-R64-preloader-2k.img.gz
+  HASH:=1a4b55da1717190aa4e790ce93850605e9b15aae4c3248bcf8734aac020ab0e4
+endef
+$(eval $(call Download,BPI-R64-preloader-2k.img.gz))
+
+
+define Package/mt7623n-preloader
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_mediatek_mt7623
+  TITLE:=mt7623n-preloader
+  DEFAULT:=y if TARGET_mediatek
+endef
+
+define Package/mt7623n-preloader/description
+  Preloader image for mt7623n based boards like Banana Pi R2.
+endef
+
+define Package/mt7622-preloader
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_mediatek_mt7622
+  TITLE:=mt7622-preloader
+  DEFAULT:=y if TARGET_mediatek
+endef
+
+define Package/mt7622-preloader/description
+  Preloader image for mt7622 based boards like Banana Pi R64.
+endef
+
+define Build/Prepare
+	rm -rf $(PKG_BUILD_DIR)
+	mkdir -p $(PKG_BUILD_DIR)
+	cp $(DL_DIR)/$(BPI_PRELOADER_PREFIX)-BPI-R2-preloader-DDR1600-20191024-2k.img.gz $(PKG_BUILD_DIR)/mt7623n_bpir2-preloader.bin.gz
+	cp $(DL_DIR)/$(BPI_PRELOADER_PREFIX)-BPI-R64-preloader-2k.img.gz $(PKG_BUILD_DIR)/mt7622_bpir64-preloader.bin.gz
+endef
+
+define Build/Compile
+	true
+endef
+
+define Build/InstallDev
+	mkdir -p $(STAGING_DIR_IMAGE)
+	gunzip -c $(PKG_BUILD_DIR)/mt7623n_bpir2-preloader.bin.gz > $(STAGING_DIR_IMAGE)/mt7623n_bpir2-preloader.bin
+endef
+
+$(eval $(call BuildPackage,mt7623n-preloader))
+$(eval $(call BuildPackage,mt7622-preloader))
diff --git a/package/boot/obm-mmp/Makefile b/package/boot/obm-mmp/Makefile
new file mode 100644
index 0000000..8f998d8
--- /dev/null
+++ b/package/boot/obm-mmp/Makefile
@@ -0,0 +1,213 @@
+#
+# Copyright (C) 2012 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)/kernel.mk
+
+PKG_NAME:=obm
+PKG_VERSION:=2014
+PKG_RELEASE:=1
+
+USE_SOURCE_DIR:=$(MRVLDIR)/obm
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define obm/Default
+  TITLE:=
+  CONFIG:=
+  IMAGE:=
+  PLAT:=
+  FLASH:=
+endef
+
+define obm/falcon_p401
+  TITLE:=obm for ASR1803
+  PLAT:=FALCON
+  DEPS:=@TARGET_mmp_asr1803_FALCON401
+  FLASH:=QSPINAND
+endef
+
+define obm/falcon_p403
+  TITLE:=obm for ASR1803
+  PLAT:=FALCON
+  DEPS:=@TARGET_mmp_asr1803_FALCON403
+  FLASH:=QSPINOR
+endef
+
+define obm/fact_p301
+  TITLE:=obm for ASR1806
+  PLAT:=FACT
+  DEPS:=@TARGET_mmp_asr1806_FACT301
+  FLASH:=QSPINAND
+endef
+
+define obm/fact_p306
+  TITLE:=obm for ASR1806
+  PLAT:=FACT
+  DEPS:=@TARGET_mmp_asr1806_FACT306
+  FLASH:=eMMC
+endef
+
+define obm/kagu_p801
+  TITLE:=obm for ASR1828
+  PLAT:=KAGU
+  DEPS:=@TARGET_mmp_asr1828_KAGU801
+  FLASH:=QSPINAND
+endef
+
+define obm/kstr_p901
+  TITLE:=obm for ASR1901
+  PLAT:=KSTR
+  DEPS:=@TARGET_mmp_asr1901_KSTR901
+  FLASH:=QSPINAND
+endef
+
+define obm/kstrz_p906
+  TITLE:=obm for ASR1906
+  PLAT:=KSTRZ
+  DEPS:=@TARGET_mmp_asr1906_KSTRZ906
+  FLASH:=QSPINAND
+endef
+
+define obm/lapw_p501
+  TITLE:=obm for ASR1903
+  PLAT:=LAPW
+  DEPS:=@TARGET_mmp_asr1903_LAPW501
+  FLASH:=QSPINAND
+endef
+
+define obm/lapw_p503
+  TITLE:=obm for ASR1903
+  PLAT:=LAPW
+  DEPS:=@TARGET_mmp_asr1903_LAPW503
+  FLASH:=QSPINOR
+endef
+
+OBMS:=falcon_p401 falcon_p403 kagu_p801 kstr_p901 \
+	fact_p301 fact_p306 kstrz_p906 lapw_p501 lapw_p503
+
+define Package/obm/template
+define Package/obm-mmp-$(1)
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=$(3)
+  TITLE:=$(2)
+  URL:=
+  VARIANT:=$(1)
+  MAINTAINER:=Yu Zhang <zhangy@asrmicro.com>
+endef
+endef
+
+ifdef BUILD_VARIANT
+$(eval $(call obm/$(BUILD_VARIANT)))
+OBM_PLAT:=$(if $(PLAT),$(PLAT),$(BUILD_VARIANT))
+OBM_FLASH:=$(FLASH)
+OBM_IMAGE:=$(BUILD_VARIANT)_TLoader_$(FLASH).bin
+endif
+
+define BuildObmPackage
+	$(eval $(obm/Default))
+	$(eval $(obm/$(1)))
+	$(call Package/obm/template,$(1),$(TITLE),$(DEPS))
+endef
+
+ifdef BUILD_VARIANT
+$(eval $(call obm/$(BUILD_VARIANT)))
+endif
+
+define Build/Configure
+
+endef
+
+ifeq ($(CONFIG_SECURE_IMA),y)
+	HLADDR:="HLADDR"
+endif
+
+ifeq ($(CONFIG_SEC),y)
+ifeq ($(PROFILE),$(filter $(PROFILE),FACT306))
+	# for eMMC only
+	# obm load address to 0x5e80000 since kernel zImage exceed 4MB
+	HLADDR:="HLADDR"
+endif
+endif
+
+define Build/Compile
+	cd $(USE_SOURCE_DIR) && \
+	./make_GUI_release.sh $(OBM_PLAT) $(TARGET_CROSS) $(OBM_FLASH) $(PROFILE) $(HLADDR)
+endef
+
+define Build/Clean
+  cd $(USE_SOURCE_DIR) && \
+  ./make_GUI_release.sh $(OBM_PLAT) $(TARGET_CROSS) $(OBM_FLASH) $(PROFILE) clean
+endef
+
+define Package/obm/install/default
+	$(INSTALL_DIR) $(BIN_DIR)
+ifeq ($(PROFILE),$(filter $(PROFILE),FALCON401 FACT306 KAGU801))
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TLoader_$(2)_NOSWAP.bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TLoader_$(2)_ProductBuild_NOSWAP.bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2)_ProductBuild.bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2)_ProductBuild.bin
+else ifeq ($(PROFILE),$(filter $(PROFILE),FACT301 KSTR901 KSTRZ906 LAPW501 FALCON403 LAPW503))
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TLoader_$(2)_NOSWAP.bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TLoader_$(2)_ProductBuild_NOSWAP.bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2)_ProductBuild.bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2)_ProductBuild.bin
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TUpdater_$(2).bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TUpdater_$(2).bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TUpdater_$(2).bin
+else
+	$(CP) $(PKG_BUILD_DIR)/Bootloader_3.3.6_Linux/$(1)_DKB/$(1)_TLoader_$(2).bin \
+		$(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+	chmod 644 $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(2).bin
+endif
+endef
+
+define Package/obm/install/template
+define Package/obm-mmp-$(1)/install
+	$(call Package/obm/install/default,$(2),$(3),$(4))
+	mkdir -p  $(BIN_DIR)/swd
+ifeq ($(CONFIG_TEE_OS),y)
+	cp -fpr $(MRVLDIR)/swd/$(2)/*_$(BLF_PREFIX)_$(3)_*$(BLF_TEETAG)_*  $(BIN_DIR)/swd/
+else
+ifneq ($(CONFIG_QSPINAND_64M),y)
+	find $(MRVLDIR)/swd/$(2)/ -maxdepth 1 -name "*_$(BLF_PREFIX)_$(3)_*" ! -name "*$(BLF_TEETAG)*" | xargs cp -fpr -t $(BIN_DIR)/swd/
+	rm -f $(BIN_DIR)/swd/*NAND64M*
+else
+	find $(MRVLDIR)/swd/$(2)/ -maxdepth 1 -name "*_$(BLF_PREFIX)_$(3)_*NAND64M*" ! -name "*$(BLF_TEETAG)*" | xargs cp -fpr -t $(BIN_DIR)/swd/
+endif
+endif
+ifneq ($(CONFIG_AB_SYSTEM),y)
+	rm -f $(BIN_DIR)/swd/*_AB*
+endif
+	$(MRVLDIR)/swd/extra_blfs.sh $(BIN_DIR) $(MRVLDIR)/swd/$(2) || $(MRVLDIR)/swd/$(2)/extra_blfs.sh $(BIN_DIR) $(MRVLDIR)/swd/$(2)
+ifeq ($(PROFILE),$(filter $(PROFILE),NEZHA701 NEZHA702))
+	mkdir -p  $(BIN_DIR)/swd_sec
+	mv $(BIN_DIR)/$(ARCH_PACKAGES)_TLoader_$(3)_ProductBuild.bin $(BIN_DIR)/swd_sec/$(ARCH_PACKAGES)_TLoader_$(3).bin
+endif
+ifeq ($(PROFILE),NEZAS201)
+	mkdir -p  $(BIN_DIR)/swd/secure
+	$(MRVLDIR)/swd/gen_pb.sh $(BIN_DIR)/swd
+	mv $(BIN_DIR)/*_ProductBuild.bin $(BIN_DIR)/swd/secure
+	echo "Warning: secure blf/obm will burn OTP fuse, be careful!" > $(BIN_DIR)/swd/secure/README
+endif
+endef
+endef
+
+$(foreach u,$(OBMS), \
+	$(eval $(call Package/obm/install/template,$(u),$(OBM_PLAT),$(OBM_FLASH))) \
+)
+
+$(foreach u,$(OBMS), \
+	$(eval $(call BuildObmPackage,$(u))) \
+	$(eval $(call BuildPackage,obm-mmp-$(u))) \
+)
diff --git a/package/boot/tfa-layerscape/Makefile b/package/boot/tfa-layerscape/Makefile
new file mode 100644
index 0000000..6285da6
--- /dev/null
+++ b/package/boot/tfa-layerscape/Makefile
@@ -0,0 +1,183 @@
+#
+# Copyright 2019 NXP
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=tfa-layerscape
+PKG_VERSION:=LSDK-20.04-update-290520
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/atf
+PKG_SOURCE_VERSION:=7d748e6f0ec652ba7c43733dc67a3d0b0217390a
+PKG_MIRROR_HASH:=d209c9ad18aac9f18375450b98b8dab00f0382ccb485df14623bf9b72ea1dd9b
+PKG_BUILD_DEPENDS:=tfa-layerscape/host
+
+include $(INCLUDE_DIR)/host-build.mk
+include $(INCLUDE_DIR)/package.mk
+
+HOST_CFLAGS += -Wall -Werror -pedantic -std=c99
+define Host/Compile
+	$(MAKE) -C \
+		$(HOST_BUILD_DIR)/tools/fiptool \
+		CFLAGS="$(HOST_CFLAGS)" \
+		LDFLAGS="$(HOST_LDFLAGS)"
+	$(MAKE) -C \
+		$(HOST_BUILD_DIR)/plat/nxp/tools \
+		CFLAGS="$(HOST_CFLAGS)"
+endef
+
+define Host/Install
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/tools/fiptool/fiptool $(STAGING_DIR_HOST)/bin/fiptool-layerscape
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/plat/nxp/tools/create_pbl $(STAGING_DIR_HOST)/bin/tfa-create-pbl
+	$(INSTALL_BIN) $(HOST_BUILD_DIR)/plat/nxp/tools/byte_swap $(STAGING_DIR_HOST)/bin/tfa-byte-swap
+endef
+
+define Package/tfa-generic
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=@TARGET_layerscape_armv8_64b +layerscape-rcw +u-boot-fsl_$(subst tfa-,,$(1))
+  VARIANT:=$(subst tfa-,,$(1))
+endef
+
+define Package/tfa-ls1012a-frdm
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1012AFRDM Trusted Firmware
+  PLAT:=ls1012afrdm
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1012a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1012ARDB Trusted Firmware
+  PLAT:=ls1012ardb
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1012a-frwy-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1012AFRWY Trusted Firmware
+  PLAT:=ls1012afrwy
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1043a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1043ARDB Trusted Firmware
+  PLAT:=ls1043ardb
+  BOOT_MODE:=nor
+endef
+
+define Package/tfa-ls1043a-rdb-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1043ARDB SD Boot Trusted Firmware
+  PLAT:=ls1043ardb
+  BOOT_MODE:=sd
+endef
+
+define Package/tfa-ls1046a-frwy
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1046AFRWY Trusted Firmware
+  PLAT:=ls1046afrwy
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1046a-frwy-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1046AFRWY SD Boot Trusted Firmware
+  PLAT:=ls1046afrwy
+  BOOT_MODE:=sd
+endef
+
+define Package/tfa-ls1046a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1046ARDB Trusted Firmware
+  PLAT:=ls1046ardb
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1046a-rdb-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1046ARDB SD Boot Trusted Firmware
+  PLAT:=ls1046ardb
+  BOOT_MODE:=sd
+endef
+
+define Package/tfa-ls1088a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1088ARDB Trusted Firmware
+  PLAT:=ls1088ardb
+  BOOT_MODE:=qspi
+endef
+
+define Package/tfa-ls1088a-rdb-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LS1088ARDB SD Boot Trusted Firmware
+  PLAT:=ls1088ardb
+  BOOT_MODE:=sd
+endef
+
+define Package/tfa-ls2088a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LS2088ARDB Trusted Firmware
+  PLAT:=ls2088ardb
+  BOOT_MODE:=nor
+endef
+
+define Package/tfa-lx2160a-rdb
+  $(Package/tfa-generic)
+  TITLE:=NXP LX2160ARDB Trusted Firmware
+  PLAT:=lx2160ardb
+  BOOT_MODE:=flexspi_nor
+endef
+
+define Package/tfa-lx2160a-rdb-sdboot
+  $(Package/tfa-generic)
+  TITLE:=NXP LX2160ARDB SD Boot Trusted Firmware
+  PLAT:=lx2160ardb
+  BOOT_MODE:=sd
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/build/$(PLAT)/release/bl2_$(BOOT_MODE).pbl \
+		$(STAGING_DIR_IMAGE)/fsl_$(BUILD_VARIANT)-bl2.pbl
+	$(CP) $(PKG_BUILD_DIR)/build/$(PLAT)/release/fip.bin \
+		$(STAGING_DIR_IMAGE)/fsl_$(BUILD_VARIANT)-fip.bin
+endef
+
+define Build/Compile
+	$(eval $(Package/tfa-$(BUILD_VARIANT))) \
+	$(MAKE) -C $(PKG_BUILD_DIR) CROSS_COMPILE=$(TARGET_CROSS) \
+		fip pbl PLAT=$(PLAT) BOOT_MODE=$(BOOT_MODE) \
+		RCW=$(STAGING_DIR_IMAGE)/fsl_$(BUILD_VARIANT)-rcw.bin \
+		BL33=$(STAGING_DIR_IMAGE)/fsl_$(BUILD_VARIANT)-uboot.bin \
+		FIPTOOL=$(STAGING_DIR_HOST)/bin/fiptool-layerscape \
+		CREATE_PBL=$(STAGING_DIR_HOST)/bin/tfa-create-pbl \
+		BYTE_SWAP=$(STAGING_DIR_HOST)/bin/tfa-byte-swap
+endef
+
+TFAS := \
+  ls1012a-frdm \
+  ls1012a-rdb \
+  ls1012a-frwy-sdboot \
+  ls1043a-rdb \
+  ls1043a-rdb-sdboot \
+  ls1046a-frwy \
+  ls1046a-frwy-sdboot \
+  ls1046a-rdb \
+  ls1046a-rdb-sdboot \
+  ls1088a-rdb \
+  ls1088a-rdb-sdboot \
+  ls2088a-rdb \
+  lx2160a-rdb \
+  lx2160a-rdb-sdboot
+
+$(eval $(call HostBuild))
+$(foreach tfa,$(TFAS), \
+  $(eval $(call BuildPackage,tfa-$(tfa))) \
+)
diff --git a/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch
new file mode 100644
index 0000000..0567e58
--- /dev/null
+++ b/package/boot/tfa-layerscape/patches/001-fiptool-hostbuild-fixes.patch
@@ -0,0 +1,71 @@
+--- a/Makefile
++++ b/Makefile
+@@ -448,10 +448,6 @@ endif
+ CRTTOOLPATH		?=	tools/cert_create
+ CRTTOOL			?=	${CRTTOOLPATH}/cert_create${BIN_EXT}
+ 
+-# Variables for use with Firmware Image Package
+-FIPTOOLPATH		?=	tools/fiptool
+-FIPTOOL			?=	${FIPTOOLPATH}/fiptool${BIN_EXT}
+-
+ ################################################################################
+ # Include BL specific makefiles
+ ################################################################################
+@@ -661,14 +657,12 @@ endif
+ clean:
+ 	@echo "  CLEAN"
+ 	$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
+-	${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
+ 	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+ 
+ realclean distclean:
+ 	@echo "  REALCLEAN"
+ 	$(call SHELL_REMOVE_DIR,${BUILD_BASE})
+ 	$(call SHELL_DELETE_ALL, ${CURDIR}/cscope.*)
+-	${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
+ 	${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
+ 
+ checkcodebase:		locate-checkpatch
+@@ -717,7 +711,7 @@ certificates: ${CRT_DEPS} ${CRTTOOL}
+ 	@${ECHO_BLANK_LINE}
+ endif
+ 
+-${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS} ${FIPTOOL}
++${BUILD_PLAT}/${FIP_NAME}: ${FIP_DEPS}
+ 	${Q}${FIPTOOL} create ${FIP_ARGS} $@
+ 	${Q}${FIPTOOL} info $@
+ 	@${ECHO_BLANK_LINE}
+@@ -733,21 +727,16 @@ fwu_certificates: ${FWU_CRT_DEPS} ${CRTT
+ 	@${ECHO_BLANK_LINE}
+ endif
+ 
+-${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS} ${FIPTOOL}
++${BUILD_PLAT}/${FWU_FIP_NAME}: ${FWU_FIP_DEPS}
+ 	${Q}${FIPTOOL} create ${FWU_FIP_ARGS} $@
+ 	${Q}${FIPTOOL} info $@
+ 	@${ECHO_BLANK_LINE}
+ 	@echo "Built $@ successfully"
+ 	@${ECHO_BLANK_LINE}
+ 
+-fiptool: ${FIPTOOL}
+ fip: ${BUILD_PLAT}/${FIP_NAME}
+ fwu_fip: ${BUILD_PLAT}/${FWU_FIP_NAME}
+ 
+-.PHONY: ${FIPTOOL}
+-${FIPTOOL}:
+-	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${FIPTOOLPATH}
+-
+ cscope:
+ 	@echo "  CSCOPE"
+ 	${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
+--- a/tools/fiptool/Makefile
++++ b/tools/fiptool/Makefile
+@@ -37,7 +37,7 @@ all: ${PROJECT} fip_create
+ 
+ ${PROJECT}: ${OBJECTS} Makefile
+ 	@echo "  LD      $@"
+-	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS}
++	${Q}${HOSTCC} ${OBJECTS} -o $@ ${LDLIBS} $(LDFLAGS)
+ 	@${ECHO_BLANK_LINE}
+ 	@echo "Built $@ successfully"
+ 	@${ECHO_BLANK_LINE}
diff --git a/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch b/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch
new file mode 100644
index 0000000..ce4d9c4
--- /dev/null
+++ b/package/boot/tfa-layerscape/patches/003-plat-nxp-tools-fix-create_pbl-and-byte_swap-host-bui.patch
@@ -0,0 +1,60 @@
+From 8a458876013991fe2f288bbe4694264b16c3b9e9 Mon Sep 17 00:00:00 2001
+From: Biwen Li <biwen.li@nxp.com>
+Date: Fri, 26 Jul 2019 15:44:10 +0800
+Subject: [PATCH 3/3] plat/nxp/tools: fix create_pbl and byte_swap host build
+
+Not compile create_pbl and byte_swap in the process of cross compilation
+
+Signed-off-by: Biwen Li <biwen.li@nxp.com>
+---
+ plat/nxp/tools/pbl_ch2.mk | 3 ---
+ plat/nxp/tools/pbl_ch3.mk | 5 -----
+ 2 files changed, 8 deletions(-)
+
+diff --git a/plat/nxp/tools/pbl_ch2.mk b/plat/nxp/tools/pbl_ch2.mk
+index afa43520..ff624dd9 100644
+--- a/plat/nxp/tools/pbl_ch2.mk
++++ b/plat/nxp/tools/pbl_ch2.mk
+@@ -20,8 +20,6 @@ ifeq ($(RCW),"")
+ else
+ 	# Generate header for bl2.bin
+ 	$(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE}
+-	# Compile create_pbl tool
+-	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};\
+ 	# Add bl2.bin to RCW
+ 	${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\
+ 			-o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ;\
+@@ -43,7 +41,6 @@ ifeq ($(RCW),"")
+ 	${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+ else
+ 	# -a option appends the image for Chassis 3 devices in case of non secure boot
+-	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};
+ 	${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \
+ 	-o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl ;
+ # Swapping of RCW is required for QSPi Chassis 2 devices
+diff --git a/plat/nxp/tools/pbl_ch3.mk b/plat/nxp/tools/pbl_ch3.mk
+index 944ae3bb..9aa8f635 100644
+--- a/plat/nxp/tools/pbl_ch3.mk
++++ b/plat/nxp/tools/pbl_ch3.mk
+@@ -27,9 +27,6 @@ else
+ 	# Generate header for bl2.bin
+ 	$(Q)$(CST_DIR)/create_hdr_isbc --in ${BUILD_PLAT}/bl2.bin --out ${BUILD_PLAT}/hdr_bl2 ${BL2_INPUT_FILE}
+ 
+-	# Compile create_pbl tool
+-	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};\
+-
+ 	# Add Block Copy command for bl2.bin to RCW
+ 	${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE}\
+ 			-o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -f ${BL2_SRC_OFFSET};\
+@@ -57,8 +54,6 @@ else  #SECURE_BOOT
+ ifeq ($(RCW),"")
+ 	${Q}echo "Platform ${PLAT} requires rcw file. Please set RCW to point to the right RCW file for boot mode ${BOOT_MODE}"
+ else
+-	${Q}${MAKE} CPPFLAGS="-DVERSION='\"${VERSION_STRING}\"'" --no-print-directory -C ${PLAT_TOOL_PATH};
+-
+ 	# Add Block Copy command and populate boot loc ptrfor bl2.bin to RCW
+ 	${CREATE_PBL} -r ${RCW} -i ${BUILD_PLAT}/bl2.bin -b ${BOOT_MODE} -c ${SOC_NUM} -d ${BL2_BASE} -e ${BL2_BASE} \
+ 	-o ${BUILD_PLAT}/bl2_${BOOT_MODE}.pbl -f ${BL2_SRC_OFFSET};
+-- 
+2.17.1
+
diff --git a/package/boot/uboot-at91/Makefile b/package/boot/uboot-at91/Makefile
new file mode 100644
index 0000000..a8a7123
--- /dev/null
+++ b/package/boot/uboot-at91/Makefile
@@ -0,0 +1,140 @@
+#
+# Copyright (C) 2016 Ben Whitten <ben.whitten@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=linux4sam-2020.04
+PKG_RELEASE:=2
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://github.com/linux4sam/u-boot-at91.git
+PKG_MIRROR_HASH:=4f106d215c01c4d024c4612bbd3ef189188d19abc1ab2cc316b257d308534feb
+PKG_SOURCE_VERSION:=0e1d1b6efb7f8e27c372279a906fcd2524df09da
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=at91
+  HIDDEN:=1
+  UBOOT_IMAGE:=u-boot.bin
+endef
+
+define U-Boot/at91sam9m10g45ek_nandflash
+  NAME:=AT91SAM9M10G45-EK board (NandFlash)
+  BUILD_SUBTARGET:=sam9x
+  BUILD_DEVICES:=atmel_at91sam9m10g45ek
+endef
+
+define U-Boot/at91sam9x5ek_nandflash
+  NAME:=AT91SAM9X5-EK board (NandFlash)
+  BUILD_SUBTARGET:=sam9x
+  BUILD_DEVICES:=atmel_at91sam9g15ek atmel_at91sam9g25ek \
+                 atmel_at91sam9g35ek atmel_at91sam9x25ek \
+                 atmel_at91sam9x35ek
+endef
+
+define U-Boot/at91sam9x5ek_mmc
+  NAME:=AT91SAM9X5-EK board (SDcard)
+  BUILD_SUBTARGET:=sam9x
+  BUILD_DEVICES:=atmel_at91sam9g15ek atmel_at91sam9g25ek \
+                 atmel_at91sam9g35ek atmel_at91sam9x25ek \
+                 atmel_at91sam9x35ek
+endef
+
+define U-Boot/sama5d3_xplained_nandflash
+  NAME:=SAMA5D3 Xplained board (NandFlash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d3-xplained
+endef
+
+define U-Boot/sama5d3_xplained_mmc
+  NAME:=SAMA5D3 Xplained board (SDcard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d3-xplained
+endef
+
+define U-Boot/sama5d2_xplained_spiflash
+  NAME:=SAMA5D2 Xplained board (SPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-xplained
+endef
+
+define U-Boot/sama5d2_xplained_mmc
+  NAME:=SAMA5D2 Xplained board (SDcard/EMMC)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-xplained
+endef
+
+define U-Boot/sama5d4_xplained_spiflash
+  NAME:=SAMA5D4 Xplained board (SPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d4-xplained
+endef
+
+define U-Boot/sama5d4_xplained_mmc
+  NAME:=SAMA5D4 Xplained board (SDcard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d4-xplained
+endef
+
+define U-Boot/sama5d4_xplained_nandflash
+  NAME:=SAMA5D4 Xplained board (NandFlash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d3-xplained
+endef
+
+define U-Boot/sama5d27_som1_ek_mmc1
+  NAME:=SAMA5D27 SOM1 Ek (SDCard1)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d27-som1-ek
+endef
+
+define U-Boot/sama5d27_som1_ek_qspiflash
+  NAME:=SAMA5D27 SOM1 Ek (QSPI Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d27-som1-ek
+endef
+
+define U-Boot/sama5d2_ptc_ek_nandflash
+  NAME:=SAMA5D2 PTC Ek (Nand Flash)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-ptc-ek
+endef
+
+define U-Boot/sama5d2_ptc_ek_mmc
+  NAME:=SAMA5D2 PTC Ek (SDCard)
+  BUILD_SUBTARGET:=sama5
+  BUILD_DEVICES:=microchip_sama5d2-ptc-ek
+endef
+
+UBOOT_TARGETS := \
+	at91sam9m10g45ek_nandflash \
+	at91sam9x5ek_nandflash \
+	at91sam9x5ek_mmc \
+	sama5d3_xplained_nandflash \
+	sama5d3_xplained_mmc \
+	sama5d2_xplained_mmc \
+	sama5d2_xplained_spiflash \
+	sama5d4_xplained_mmc \
+	sama5d4_xplained_spiflash \
+	sama5d4_xplained_nandflash\
+	sama5d27_som1_ek_mmc1 \
+	sama5d27_som1_ek_qspiflash \
+	sama5d2_ptc_ek_nandflash \
+	sama5d2_ptc_ek_mmc
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		CROSS_COMPILE=$(TARGET_CROSS) \
+		DTC=$(PKG_BUILD_DIR)/scripts/dtc/dtc \
+		KCFLAGS="$(filter-out -fstack-protector \
+		-mfloat-abi=hard, $(TARGET_CFLAGS)) -mfloat-abi=soft"
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-at91/patches/001-fix-Wformat-security.patch b/package/boot/uboot-at91/patches/001-fix-Wformat-security.patch
new file mode 100644
index 0000000..4c968a2
--- /dev/null
+++ b/package/boot/uboot-at91/patches/001-fix-Wformat-security.patch
@@ -0,0 +1,33 @@
+--- a/cmd/version.c
++++ b/cmd/version.c
+@@ -18,7 +18,7 @@ static int do_version(cmd_tbl_t *cmdtp,
+ {
+ 	char buf[DISPLAY_OPTIONS_BANNER_LENGTH];
+ 
+-	printf(display_options_get_banner(false, buf, sizeof(buf)));
++	printf("%s",display_options_get_banner(false, buf, sizeof(buf)));
+ #ifdef CC_VERSION_STRING
+ 	puts(CC_VERSION_STRING "\n");
+ #endif
+--- a/drivers/pinctrl/pinctrl-uclass.c
++++ b/drivers/pinctrl/pinctrl-uclass.c
+@@ -368,7 +368,7 @@ int pinctrl_get_pin_name(struct udevice
+ 	if (!ops->get_pin_name)
+ 		return -ENOSYS;
+ 
+-	snprintf(buf, size, ops->get_pin_name(dev, selector));
++	snprintf(buf, size, "%s", ops->get_pin_name(dev, selector));
+ 
+ 	return 0;
+ }
+--- a/lib/efi_loader/efi_variable.c
++++ b/lib/efi_loader/efi_variable.c
+@@ -522,7 +522,7 @@ efi_status_t EFIAPI efi_set_variable(u16
+ 
+ 	if (old_size)
+ 		/* APPEND_WRITE */
+-		s += sprintf(s, old_val);
++		s += sprintf(s, "%s", old_val);
+ 	else
+ 		s += sprintf(s, "(blob)");
+ 
diff --git a/package/boot/uboot-at91/patches/010-fix_dtc_compilation_on_host_gcc10.patch b/package/boot/uboot-at91/patches/010-fix_dtc_compilation_on_host_gcc10.patch
new file mode 100644
index 0000000..6abb151
--- /dev/null
+++ b/package/boot/uboot-at91/patches/010-fix_dtc_compilation_on_host_gcc10.patch
@@ -0,0 +1,46 @@
+From e33a814e772cdc36436c8c188d8c42d019fda639 Mon Sep 17 00:00:00 2001
+From: Dirk Mueller <dmueller@suse.com>
+Date: Tue, 14 Jan 2020 18:53:41 +0100
+Subject: [PATCH] scripts/dtc: Remove redundant YYLOC global declaration
+
+gcc 10 will default to -fno-common, which causes this error at link
+time:
+
+  (.text+0x0): multiple definition of `yylloc'; dtc-lexer.lex.o (symbol from plugin):(.text+0x0): first defined here
+
+This is because both dtc-lexer as well as dtc-parser define the same
+global symbol yyloc. Before with -fcommon those were merged into one
+defintion. The proper solution would be to to mark this as "extern",
+however that leads to:
+
+  dtc-lexer.l:26:16: error: redundant redeclaration of 'yylloc' [-Werror=redundant-decls]
+   26 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+In file included from dtc-lexer.l:24:
+dtc-parser.tab.h:127:16: note: previous declaration of 'yylloc' was here
+  127 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+cc1: all warnings being treated as errors
+
+which means the declaration is completely redundant and can just be
+dropped.
+
+Signed-off-by: Dirk Mueller <dmueller@suse.com>
+Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
+[robh: cherry-pick from upstream]
+Cc: stable@vger.kernel.org
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ scripts/dtc/dtc-lexer.l | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -38,7 +38,6 @@ LINECOMMENT	"//".*\n
+ #include "srcpos.h"
+ #include "dtc-parser.tab.h"
+ 
+-YYLTYPE yylloc;
+ extern bool treesource_error;
+ 
+ /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
diff --git a/package/boot/uboot-bcm4908/Makefile b/package/boot/uboot-bcm4908/Makefile
new file mode 100644
index 0000000..dc862f4
--- /dev/null
+++ b/package/boot/uboot-bcm4908/Makefile
@@ -0,0 +1,48 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://git.openwrt.org/project/bcm63xx/u-boot.git
+PKG_SOURCE_DATE:=2022-03-03
+PKG_SOURCE_VERSION:=92e9eca819c9c898d9d2010e1a217726c42c8c47
+PKG_MIRROR_HASH:=11c37fe4c18d55e799153600d1cfd8ee9ca7da8326d0024c1d825f4a327c5f0d
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=bcm4908
+  UBOOT_IMAGE:=u-boot-nodtb.bin
+  DEFAULT:=y
+endef
+
+define U-Boot/bcm4908
+  NAME:=Broadcom's BCM4908
+  UBOOT_CONFIG:=bcm94908
+endef
+
+UBOOT_TARGETS := \
+	bcm4908
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+	mkdir -p $(PKG_BUILD_DIR)/include/generated/
+	( cd $(PKG_BUILD_DIR)/board/broadcom/bcmbca/httpd/html/ && \
+	  $(STAGING_DIR_HOST)/bin/xxd -i index.html > ../../../../../include/generated/index.h && \
+	  $(STAGING_DIR_HOST)/bin/xxd -i flashing.html > ../../../../../include/generated/flashing.h && \
+	  $(STAGING_DIR_HOST)/bin/xxd -i fail.html > ../../../../../include/generated/fail.h && \
+	  $(STAGING_DIR_HOST)/bin/xxd -i 404.html > ../../../../../include/generated/404.h )
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)/u-boot
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/u-boot/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/u-boot.dtb $(STAGING_DIR_IMAGE)/u-boot/
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/arch/arm/dts/*.dtb $(STAGING_DIR_IMAGE)/u-boot/
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-bcm4908/patches/100-check-config-allow-to-complete-build-even-with-ad-ho.patch b/package/boot/uboot-bcm4908/patches/100-check-config-allow-to-complete-build-even-with-ad-ho.patch
new file mode 100644
index 0000000..44aa4c1
--- /dev/null
+++ b/package/boot/uboot-bcm4908/patches/100-check-config-allow-to-complete-build-even-with-ad-ho.patch
@@ -0,0 +1,40 @@
+From: Masahiro Yamada <yamada.masahiro@socionext.com>
+Date: Mon, 26 Sep 2016 13:05:02 +0900
+Subject: [PATCH] check-config: allow to complete build even with ad-hoc CONFIG
+ options
+
+Currently, the check-config.sh terminates the build when unknown
+ad-hoc options are detected.  I think it is too much because we may
+want to patch config headers locally in a build/deployment project.
+
+So, let's relax check-config.sh to just warn even if it detects
+options that are not in the whitelist.  Instead, this check can be
+done at the end of build, along with other checks.  It will catch
+more attention.
+
+Even with this change, the Buildman tool catches new warnings,
+so Tom can give NACK to new ad-hoc options.
+
+Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
+---
+ scripts/check-config.sh | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/scripts/check-config.sh
++++ b/scripts/check-config.sh
+@@ -50,14 +50,13 @@ cat `find ${srctree} -name "Kconfig*"` |sed -n \
+ 	|sort |uniq > ${ok}
+ comm -23 ${suspects} ${ok} >${new_adhoc}
+ if [ -s ${new_adhoc} ]; then
+-	echo >&2 "Error: You must add new CONFIG options using Kconfig"
++	echo >&2 "Warning: You must add new CONFIG options using Kconfig"
+ 	echo >&2 "The following new ad-hoc CONFIG options were detected:"
+ 	cat >&2 ${new_adhoc}
+ 	echo >&2
+ 	echo >&2 "Please add these via Kconfig instead. Find a suitable Kconfig"
+ 	echo >&2 "file and add a 'config' or 'menuconfig' option."
+ 	# Don't delete the temporary files in case they are useful
+-	exit 1
+ else
+ 	rm ${suspects} ${ok} ${new_adhoc}
+ fi
diff --git a/package/boot/uboot-bcm4908/patches/101-tools-fix-mkimage-static-compilation.patch b/package/boot/uboot-bcm4908/patches/101-tools-fix-mkimage-static-compilation.patch
new file mode 100644
index 0000000..9b50071
--- /dev/null
+++ b/package/boot/uboot-bcm4908/patches/101-tools-fix-mkimage-static-compilation.patch
@@ -0,0 +1,24 @@
+From 8efe417aa9de654425cc01d0fc93be355a3f648d Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Wed, 13 Oct 2021 11:04:45 +0200
+Subject: [PATCH] tools: fix mkimage static compilation
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ tools/Makefile | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -157,7 +157,7 @@ ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CON
+ HOSTCFLAGS_kwbimage.o += \
+ 	$(shell pkg-config --cflags libssl libcrypto 2> /dev/null || echo "")
+ HOSTLOADLIBES_mkimage += \
+-	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
++	$(shell pkg-config --libs --static libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto -lpthread")
+ 
+ # OS X deprecate openssl in favour of CommonCrypto, supress deprecation
+ # warnings on those systems
diff --git a/package/boot/uboot-bcm4908/patches/200-configs-bcm94908-unset-CONFIG_SPL.patch b/package/boot/uboot-bcm4908/patches/200-configs-bcm94908-unset-CONFIG_SPL.patch
new file mode 100644
index 0000000..26189bc
--- /dev/null
+++ b/package/boot/uboot-bcm4908/patches/200-configs-bcm94908-unset-CONFIG_SPL.patch
@@ -0,0 +1,38 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 4 Mar 2022 09:21:32 +0100
+Subject: [PATCH] configs: bcm94908: unset CONFIG_SPL
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Compiling SPL is always tricky as it needs to fit limited resources.
+Fortunately in most cases there is no need to replace SPL or TPL while
+flashing a new firmware.
+
+Compiling SPL for BCM4908 seems to fail with non-Broadcom toolchain:
+aarch64-openwrt-linux-musl-ld.bfd: u-boot-spl section `.u_boot_list' will not fit in region `.sram'
+aarch64-openwrt-linux-musl-ld.bfd: section .bss VMA [00000000822b9000,00000000822b93ef] overlaps section .u_boot_list VMA [00000000822b8f60,00000000822b9a87]
+aarch64-openwrt-linux-musl-ld.bfd: region `.sram' overflowed by 2696 bytes
+
+It also requires hashtable.h which has to be generated using some
+Broadcom's custom perl script that isn't integrated as this point.
+
+For now just disable SPL and use only last-stage U-Boot that must be
+shipped with every firmware.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ configs/bcm94908_defconfig | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/configs/bcm94908_defconfig
++++ b/configs/bcm94908_defconfig
+@@ -21,7 +21,7 @@ CONFIG_SPL_SERIAL_SUPPORT=y
+ CONFIG_TPL_LIBCOMMON_SUPPORT=y
+ CONFIG_TPL_LIBGENERIC_SUPPORT=y
+ CONFIG_NR_DRAM_BANKS=1
+-CONFIG_SPL=y
++# CONFIG_SPL is not set
+ CONFIG_SPL_LIBDISK_SUPPORT=y
+ CONFIG_ENV_VARS_UBOOT_CONFIG=y
+ CONFIG_TPL_SYS_MALLOC_F_LEN=0x11000
diff --git a/package/boot/uboot-bcm4908/patches/201-Assume-TPL-support-for-ATF-when-compiling-U-Boot-wit.patch b/package/boot/uboot-bcm4908/patches/201-Assume-TPL-support-for-ATF-when-compiling-U-Boot-wit.patch
new file mode 100644
index 0000000..1e59705
--- /dev/null
+++ b/package/boot/uboot-bcm4908/patches/201-Assume-TPL-support-for-ATF-when-compiling-U-Boot-wit.patch
@@ -0,0 +1,55 @@
+From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
+Date: Fri, 4 Mar 2022 09:23:34 +0100
+Subject: [PATCH] Assume TPL support for ATF when compiling U-Boot without TPL
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Broadcom's U-Boot behaviour depends on compilation time check whether
+TPL was compiled with or without ATF support. There is no proper runtime
+check.
+
+When compiling just U-Boot (without SPL & TPL) there is no way to tell
+if it's going to work with TPL with or without ATF support.
+
+Modify code to blindly assume ATF support in TPL in such cases. It seems
+to be always true for Broadcom and we need some assumption as we don't
+deal with compiling SPL or TPL.
+
+Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
+---
+ arch/arm/mach-bcmbca/bcm4908/cpu.c | 2 +-
+ board/broadcom/bcmbca/board.c      | 4 ++--
+ 2 files changed, 3 insertions(+), 3 deletions(-)
+
+--- a/arch/arm/mach-bcmbca/bcm4908/cpu.c
++++ b/arch/arm/mach-bcmbca/bcm4908/cpu.c
+@@ -138,7 +138,7 @@ int get_nr_cpus()
+ 	return nr_cpus;
+ }
+ 
+-#if !defined(CONFIG_TPL_ATF)
++#if defined(CONFIG_TPL) && !defined(CONFIG_TPL_ATF)
+ void boot_secondary_cpu(unsigned long vector)
+ {
+ 	uint32_t cpu, nr_cpus = QUAD_CPUS;
+--- a/board/broadcom/bcmbca/board.c
++++ b/board/broadcom/bcmbca/board.c
+@@ -103,7 +103,7 @@ void board_spinor_init(void)
+ 
+ int board_init(void)
+ {
+-#if !defined(CONFIG_TPL_ATF)
++#if defined(CONFIG_TPL) && !defined(CONFIG_TPL_ATF)
+ 	unsigned long vector;
+ #endif
+ 	board_sdk_init_e();
+@@ -121,7 +121,7 @@ int board_init(void)
+ 	printf("$Uboot: "BUILD_TAG" $\n");
+ #endif
+ 
+-#if !defined(CONFIG_TPL_ATF)
++#if defined(CONFIG_TPL) && !defined(CONFIG_TPL_ATF)
+ #if defined(CONFIG_ARM64)
+ 	vector  = (unsigned long)&_start;
+ #else
diff --git a/package/boot/uboot-envtools/Makefile b/package/boot/uboot-envtools/Makefile
new file mode 100644
index 0000000..a9eccec
--- /dev/null
+++ b/package/boot/uboot-envtools/Makefile
@@ -0,0 +1,79 @@
+#
+# Copyright (C) 2006-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uboot-envtools
+PKG_DISTNAME:=u-boot
+PKG_VERSION:=2021.01
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE:=$(PKG_DISTNAME)-$(PKG_VERSION).tar.bz2
+PKG_SOURCE_URL:= \
+    https://ftp.denx.de/pub/u-boot \
+    https://mirror.cyberbits.eu/u-boot \
+    ftp://ftp.denx.de/pub/u-boot
+PKG_HASH:=b407e1510a74e863b8b5cb42a24625344f0e0c2fc7582d8c866bd899367d0454
+PKG_SOURCE_SUBDIR:=$(PKG_DISTNAME)-$(PKG_VERSION)
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_DISTNAME)-$(PKG_VERSION)
+
+PKG_BUILD_DEPENDS:=fstools
+
+PKG_LICENSE:=GPL-2.0 GPL-2.0+
+PKG_LICENSE_FILES:=Licenses/README
+
+PKG_FLAGS:=nonshared
+
+PKG_BUILD_PARALLEL:=1
+
+include $(INCLUDE_DIR)/package.mk
+
+define Package/uboot-envtools
+  SECTION:=utils
+  CATEGORY:=Utilities
+  SUBMENU:=Boot Loaders
+  TITLE:=read/modify U-Boot bootloader environment
+  URL:=http://www.denx.de/wiki/U-Boot
+endef
+
+define Package/uboot-envtools/description
+ This package includes tools to read and modify U-Boot bootloader environment.
+endef
+
+define Build/Configure
+	touch $(PKG_BUILD_DIR)/include/config.h
+	mkdir -p $(PKG_BUILD_DIR)/include/config
+	touch $(PKG_BUILD_DIR)/include/config/auto.conf
+	mkdir -p $(PKG_BUILD_DIR)/include/generated
+	touch $(PKG_BUILD_DIR)/include/generated/autoconf.h
+endef
+
+MAKE_FLAGS += \
+	TARGET_CFLAGS="$(TARGET_CFLAGS)" \
+	TARGET_LDFLAGS="$(TARGET_LDFLAGS)" \
+	no-dot-config-targets=envtools \
+	envtools
+
+define Package/uboot-envtools/conffiles
+/etc/config/ubootenv
+/etc/fw_env.config
+endef
+
+define Package/uboot-envtools/install
+	$(INSTALL_DIR) $(1)/usr/sbin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/env/fw_printenv $(1)/usr/sbin
+	$(LN) fw_printenv $(1)/usr/sbin/fw_setenv
+	$(INSTALL_DIR) $(1)/lib
+	$(INSTALL_DATA) ./files/uboot-envtools.sh $(1)/lib
+	$(INSTALL_DIR) $(1)/etc/uci-defaults
+	$(if $(wildcard ./files/$(BOARD)), \
+		$(INSTALL_DATA) ./files/$(BOARD) \
+		$(1)/etc/uci-defaults/30_uboot-envtools \
+	)
+endef
+
+$(eval $(call BuildPackage,uboot-envtools))
diff --git a/package/boot/uboot-envtools/files/apm821xx b/package/boot/uboot-envtools/files/apm821xx
new file mode 100644
index 0000000..6bcc3ad
--- /dev/null
+++ b/package/boot/uboot-envtools/files/apm821xx
@@ -0,0 +1,29 @@
+#!/bin/sh
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+meraki,mr24)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x4000" "0x4000" "4"
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x4000" "0x4000" "4"
+	;;
+meraki,mx60)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000" "4"
+	;;
+netgear,wndap620|\
+netgear,wndap660)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x4000" "0x4000" "4"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ath79 b/package/boot/uboot-envtools/files/ath79
new file mode 100644
index 0000000..abcb996
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ath79
@@ -0,0 +1,118 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+alfa-network,ap121f|\
+alfa-network,ap121fe|\
+alfa-network,n2q|\
+alfa-network,n5q|\
+alfa-network,pi-wifi4|\
+alfa-network,r36a|\
+allnet,all-wap02860ac|\
+arduino,yun|\
+buffalo,bhr-4grv2|\
+devolo,magic-2-wifi|\
+engenius,eap1200h|\
+engenius,eap300-v2|\
+engenius,eap350-v1|\
+engenius,eap600|\
+engenius,ecb1200|\
+engenius,ecb1750|\
+engenius,ecb350-v1|\
+engenius,ecb600|\
+engenius,enh202-v1|\
+engenius,ens202ext-v1|\
+engenius,enstationac-v1|\
+etactica,eg200|\
+glinet,gl-ar750s-nor|\
+glinet,gl-ar750s-nor-nand|\
+librerouter,librerouter-v1|\
+netgear,ex6400|\
+netgear,ex7300|\
+netgear,wndr4300-v2|\
+netgear,wndr4500-v3|\
+netgear,wnr1000-v2|\
+netgear,wnr2000-v3|\
+netgear,wnr2200-8m|\
+netgear,wnr2200-16m|\
+netgear,wnr612-v2|\
+ocedo,koala|\
+ocedo,raccoon|\
+openmesh,mr600-v1|\
+openmesh,mr600-v2|\
+openmesh,mr900-v1|\
+openmesh,mr900-v2|\
+openmesh,mr1750-v1|\
+openmesh,mr1750-v2|\
+openmesh,om5p|\
+openmesh,om5p-ac-v2|\
+samsung,wam250|\
+ubnt,nanostation-m|\
+yuncore,a770|\
+yuncore,a782|\
+yuncore,xd4200|\
+zyxel,nbg6616)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000"
+	;;
+buffalo,wzr-hp-ag300h)
+	ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x10000" "0x10000"
+	;;
+domywifi,dw33d)
+	ubootenv_add_uci_config "/dev/mtd4" "0x0" "0x10000" "0x10000"
+	;;
+glinet,gl-ar150)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x8000" "0x10000"
+	;;
+glinet,gl-ar300m-lite|\
+glinet,gl-ar300m-nand|\
+glinet,gl-ar300m-nor|\
+glinet,gl-ar300m16)
+	idx="$(find_mtd_index u-boot-env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000"
+	;;
+netgear,wndr3700|\
+netgear,wndr3700-v2|\
+netgear,wndrmac-v1)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x10000"
+	;;
+netgear,wndr3700-v4|\
+netgear,wndr4300|\
+netgear,wndr4300tn|\
+netgear,wndr4300sw)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x20000"
+	;;
+openmesh,om2p-v2|\
+openmesh,om2p-v4|\
+openmesh,om2p-hs-v1|\
+openmesh,om2p-hs-v2|\
+openmesh,om2p-hs-v3|\
+openmesh,om2p-hs-v4|\
+openmesh,om2p-lc|\
+plasmacloud,pa300|\
+plasmacloud,pa300e)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x40000"
+	;;
+qihoo,c301)
+	ubootenv_add_uci_config "/dev/mtd9" "0x0" "0x10000" "0x10000"
+	;;
+wallys,dr531)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0xf800" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/cns3xxx b/package/boot/uboot-envtools/files/cns3xxx
new file mode 100644
index 0000000..f998de4
--- /dev/null
+++ b/package/boot/uboot-envtools/files/cns3xxx
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+laguna)
+	# Laguna uboot env size/erasesize vary depending on NOR vs SPI FLASH
+	size=$(grep mtd1 /proc/mtd | awk '{print $2}')
+	erasesize=$(grep mtd1 /proc/mtd | awk '{print $3}')
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x$size" "0x$erasesize"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/imx6 b/package/boot/uboot-envtools/files/imx6
new file mode 100644
index 0000000..5d960df
--- /dev/null
+++ b/package/boot/uboot-envtools/files/imx6
@@ -0,0 +1,65 @@
+#!/bin/sh
+#
+# Copyright (C) 2013-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/imx6.sh
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+gw,imx6dl-gw51xx |\
+gw,imx6dl-gw52xx |\
+gw,imx6dl-gw53xx |\
+gw,imx6dl-gw54xx |\
+gw,imx6dl-gw551x |\
+gw,imx6dl-gw552x |\
+gw,imx6dl-gw553x |\
+gw,imx6dl-gw5904 |\
+gw,imx6dl-gw5907 |\
+gw,imx6dl-gw5910 |\
+gw,imx6dl-gw5912 |\
+gw,imx6dl-gw5913 |\
+gw,imx6q-gw51xx |\
+gw,imx6q-gw52xx |\
+gw,imx6q-gw53xx |\
+gw,imx6q-gw5400-a |\
+gw,imx6q-gw54xx |\
+gw,imx6q-gw551x |\
+gw,imx6q-gw552x |\
+gw,imx6q-gw553x |\
+gw,imx6q-gw5904 |\
+gw,imx6q-gw5907 |\
+gw,imx6q-gw5910 |\
+gw,imx6q-gw5912 |\
+gw,imx6q-gw5913 )
+	if [ -c /dev/mtd1 ]; then
+		# board boots from NAND
+		ubootenv_add_uci_config /dev/mtd1 0x0 0x20000 0x40000
+		ubootenv_add_uci_config /dev/mtd1 0x80000 0x20000 0x40000
+	else
+		# board boots from microSD
+		ubootenv_add_uci_config /dev/mmcblk0 0xb1400 0x20000
+		ubootenv_add_uci_config /dev/mmcblk0 0xd1400 0x20000
+	fi
+	;;
+toradex,apalis_imx6q-eval |\
+toradex,apalis_imx6q-ixora |\
+toradex,apalis_imx6q-ixora-v1.1 )
+	ubootenv_add_uci_config $(bootdev_from_uuid)boot0 -0x2200 0x2000 0x200 10
+	;;
+wand,imx6dl-wandboard)
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x60000" "0x2000" "0x2000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ipq40xx b/package/boot/uboot-envtools/files/ipq40xx
new file mode 100644
index 0000000..b24cbf9
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ipq40xx
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 LEDE
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+ubootenv_mtdinfo () {
+	UBOOTENV_PART=$(cat /proc/mtd | grep APPSBLENV)
+	mtd_dev=$(echo $UBOOTENV_PART | awk '{print $1}' | sed 's/:$//')
+	mtd_size=$(echo $UBOOTENV_PART | awk '{print "0x"$2}')
+	mtd_erase=$(echo $UBOOTENV_PART | awk '{print "0x"$3}')
+	nor_flash=$(find /sys/bus/spi/devices/*/mtd -name ${mtd_dev})
+
+	if [ -n "$nor_flash" ]; then
+		ubootenv_size=$mtd_size
+	else
+		# size is fixed to 0x40000 in u-boot
+		ubootenv_size=0x40000
+	fi
+
+	sectors=$(( $ubootenv_size / $mtd_erase ))
+	echo /dev/$mtd_dev 0x0 $ubootenv_size $mtd_erase $sectors
+}
+
+case "$board" in
+alfa-network,ap120c-ac |\
+devolo,magic-2-wifi-next |\
+edgecore,ecw5211 |\
+glinet,gl-ap1300 |\
+glinet,gl-b1300 |\
+luma,wrtq-329acn |\
+openmesh,a42 |\
+openmesh,a62 |\
+plasmacloud,pa1200 |\
+plasmacloud,pa2200)
+	ubootenv_add_uci_config "/dev/mtd5" "0x0" "0x10000" "0x10000"
+	;;
+aruba,ap-303)
+	ubootenv_add_uci_config "/dev/mtd13" "0x0" "0x10000" "0x10000"
+	;;
+aruba,ap-365)
+	ubootenv_add_uci_config "/dev/mtd8" "0x0" "0x10000" "0x10000"
+	;;
+buffalo,wtr-m2133hp)
+	ubootenv_add_uci_config "/dev/mtd8" "0x0" "0x40000" "0x20000"
+	;;
+linksys,ea6350v3)
+	ubootenv_add_uci_config "/dev/mtd7" "0x0" "0x20000" "0x20000"
+	;;
+linksys,ea8300 |\
+linksys,mr8300)
+	ubootenv_add_uci_config "/dev/mtd7" "0x0" "0x40000" "0x20000"
+	;;
+zyxel,nbg6617)
+	ubootenv_add_uci_config "/dev/mtd6" "0x0" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ipq806x b/package/boot/uboot-envtools/files/ipq806x
new file mode 100644
index 0000000..96a4ee6
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ipq806x
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 LEDE
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+ubootenv_mtdinfo () {
+	UBOOTENV_PART=$(cat /proc/mtd | grep APPSBLENV)
+	mtd_dev=$(echo $UBOOTENV_PART | awk '{print $1}' | sed 's/:$//')
+	mtd_size=$(echo $UBOOTENV_PART | awk '{print "0x"$2}')
+	mtd_erase=$(echo $UBOOTENV_PART | awk '{print "0x"$3}')
+	nor_flash=$(find /sys/bus/spi/devices/*/mtd -name ${mtd_dev})
+
+	if [ -n "$nor_flash" ]; then
+		ubootenv_size=$mtd_size
+	else
+		# size is fixed to 0x40000 in u-boot
+		ubootenv_size=0x40000
+	fi
+
+	sectors=$(( $ubootenv_size / $mtd_erase ))
+	echo /dev/$mtd_dev 0x0 $ubootenv_size $mtd_erase $sectors
+}
+
+case "$board" in
+edgecore,ecw5410)
+	ubootenv_add_uci_config "/dev/mtd11" "0x0" "0x10000" "0x10000"
+	;;
+linksys,ea7500-v1 |\
+linksys,ea8500)
+	ubootenv_add_uci_config "/dev/mtd10" "0x0" "0x20000" "0x20000"
+	;;
+netgear,r7800)
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x040000" "0x20000"
+	;;
+qcom,ipq8064-ap148 |\
+qcom,ipq8064-db149)
+	ubootenv_add_uci_config $(ubootenv_mtdinfo)
+	;;
+ubnt,unifi-ac-hd |\
+zyxel,nbg6817)
+	ubootenv_add_uci_config "/dev/mtdblock9" "0x0" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/kirkwood b/package/boot/uboot-envtools/files/kirkwood
new file mode 100644
index 0000000..401df74
--- /dev/null
+++ b/package/boot/uboot-envtools/files/kirkwood
@@ -0,0 +1,37 @@
+#!/bin/sh
+#
+# Copyright (C) 2012-2014 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+checkpoint,l-50|\
+cloudengines,pogoe02|\
+cloudengines,pogoplugv4|\
+iom,ix2-200|\
+linksys,e4200-v2|\
+linksys,ea4500|\
+raidsonic,ib-nas62x0|\
+seagate,dockstar|\
+zyxel,nsa310b|\
+zyxel,nsa310s|\
+zyxel,nsa325)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	;;
+linksys,ea3500)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x4000" "0x4000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/lantiq b/package/boot/uboot-envtools/files/lantiq
new file mode 100644
index 0000000..87dfac8
--- /dev/null
+++ b/package/boot/uboot-envtools/files/lantiq
@@ -0,0 +1,38 @@
+#!/bin/sh
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+bt,homehub-v2b)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" "1"
+	;;
+bt,homehub-v3a)
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x4000" "0x4000" "1"
+	;;
+siemens,gigaset-sx76x)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000" "1"
+	;;
+zyxel,p-2812hnu-f1)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x2000" "0x20000" "1"
+	;;
+buffalo,wbmr-300hpd)
+	idx="$(find_mtd_index u-boot-env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x2000" "0x1000" "2"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/layerscape b/package/boot/uboot-envtools/files/layerscape
new file mode 100644
index 0000000..732f148
--- /dev/null
+++ b/package/boot/uboot-envtools/files/layerscape
@@ -0,0 +1,25 @@
+#!/bin/sh
+#
+# Copyright (C) 2016 LEDE
+#
+
+[ -f /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+	traverse,ls1043v | \
+	traverse,ls1043s)
+		ubootenv_add_uci_config "/dev/mtd1" "0x40000" "0x2000"  "0x20000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/mpc85xx b/package/boot/uboot-envtools/files/mpc85xx
new file mode 100644
index 0000000..d219b57
--- /dev/null
+++ b/package/boot/uboot-envtools/files/mpc85xx
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+ocedo,panda)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x20000" "0x20000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/mvebu b/package/boot/uboot-envtools/files/mvebu
new file mode 100644
index 0000000..92b1443
--- /dev/null
+++ b/package/boot/uboot-envtools/files/mvebu
@@ -0,0 +1,66 @@
+#!/bin/sh
+#
+# Copyright (C) 2014-2016 OpenWrt.org
+# Copyright (C) 2016 LEDE-Project.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+buffalo,ls421de)
+	ubootenv_add_uci_config "/dev/mtd3" "0x0" "0x10000"
+	;;
+cznic,turris-omnia)
+	if grep -q 'U-Boot 2015.10-rc2' /dev/mtd0; then
+		ubootenv_add_uci_config "/dev/mtd0" "0xc0000" "0x10000" "0x40000"
+	else
+		ubootenv_add_uci_config "/dev/mtd0" "0xf0000" "0x10000" "0x10000"
+	fi
+	;;
+glinet,gl-mv1000)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x8000" "0x8000" "1"
+	;;
+globalscale,espressobin|\
+globalscale,espressobin-emmc|\
+globalscale,espressobin-ultra|\
+globalscale,espressobin-v7|\
+globalscale,espressobin-v7-emmc)
+	idx="$(find_mtd_index u-boot-env)"
+	if [ -n "$idx" ]; then
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000" "1"
+	else
+		ubootenv_add_uci_config "/dev/mtd0" "0x3f0000" "0x10000" "0x10000" "1"
+	fi
+	;;
+marvell,armada8040-mcbin-doubleshot|\
+marvell,armada8040-mcbin-singleshot)
+	ubootenv_add_uci_config "/dev/mtd0" "0x3f0000" "0x10000" "0x10000" "1"
+	;;
+linksys,wrt1200ac|\
+linksys,wrt1900ac-v2|\
+linksys,wrt1900acs)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x40000"
+	;;
+linksys,wrt1900ac-v1)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x40000" "0x20000"
+	;;
+linksys,wrt3200acm|\
+linksys,wrt32x)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	;;
+methode,udpu)
+	ubootenv_add_uci_config "/dev/mtd0" "0x180000" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/mxs b/package/boot/uboot-envtools/files/mxs
new file mode 100644
index 0000000..e087d60
--- /dev/null
+++ b/package/boot/uboot-envtools/files/mxs
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+i2se,duckbill)
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x20000" "0x20000"
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x40000" "0x20000"
+	;;
+olimex,imx23-olinuxino)
+	ubootenv_add_uci_config "/dev/mmcblk0" "0x40000" "0x4000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/oxnas b/package/boot/uboot-envtools/files/oxnas
new file mode 100644
index 0000000..4427bb5
--- /dev/null
+++ b/package/boot/uboot-envtools/files/oxnas
@@ -0,0 +1,28 @@
+#!/bin/sh
+#
+# Copyright (C) 2013 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+"cloudengines,pogoplug"* | \
+"shuttle,kd20")
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x2000" "0x2000" "1"
+	;;
+"mitrastar,stg-212")
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x20000" "0x20000" "1"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/pistachio b/package/boot/uboot-envtools/files/pistachio
new file mode 100644
index 0000000..e4aa7b0
--- /dev/null
+++ b/package/boot/uboot-envtools/files/pistachio
@@ -0,0 +1,27 @@
+#!/bin/sh
+#
+# Copyright (C) 2017 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+img,pistachio-marduk)
+	ubootenv_add_uci_config "/dev/mtd2" "0x0" "0x2000" "0x1000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/ramips b/package/boot/uboot-envtools/files/ramips
new file mode 100644
index 0000000..0de062b
--- /dev/null
+++ b/package/boot/uboot-envtools/files/ramips
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+alfa-network,ac1200rm|\
+alfa-network,awusfree1|\
+alfa-network,quad-e4g|\
+alfa-network,r36m-e4g|\
+alfa-network,tube-e4g|\
+engenius,esr600h)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x1000"
+	;;
+allnet,all0256n-4m|\
+allnet,all0256n-8m|\
+allnet,all5002)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x10000" "0x10000"
+	;;
+ampedwireless,ally-00x19k|\
+ampedwireless,ally-r1900k)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x20000" "4"
+	;;
+buffalo,wsr-1166dhp|\
+buffalo,wsr-600dhp|\
+mediatek,linkit-smart-7688|\
+samknows,whitebox-v8|\
+xiaomi,mi-router-3g-v2|\
+xiaomi,mi-router-4a-gigabit|\
+xiaomi,mi-router-4c|\
+xiaomi,miwifi-nano|\
+zbtlink,zbt-wg2626|\
+zte,mf283plus)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x10000"
+	;;
+hootoo,ht-tm05|\
+ravpower,rp-wd03)
+	idx="$(find_mtd_index u-boot-env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x4000" "0x1000" "0x1000"
+	;;
+jcg,q20)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x20000" "0x20000"
+	;;
+linksys,ea7300-v1|\
+linksys,ea7300-v2|\
+linksys,ea7500-v2|\
+linksys,ea8100-v1|\
+xiaomi,mi-router-3g|\
+xiaomi,mi-router-3-pro|\
+xiaomi,mi-router-4|\
+xiaomi,mi-router-ac2100|\
+xiaomi,redmi-router-ac2100)
+	ubootenv_add_uci_config "/dev/mtd1" "0x0" "0x1000" "0x20000"
+	;;
+zyxel,nr7101)
+	idx="$(find_mtd_index Config)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x1000" "0x80000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/realtek b/package/boot/uboot-envtools/files/realtek
new file mode 100644
index 0000000..a91ca82
--- /dev/null
+++ b/package/boot/uboot-envtools/files/realtek
@@ -0,0 +1,32 @@
+[ -e /etc/config/ubootenv ] && exit 0
+
+touch /etc/config/ubootenv
+
+. /lib/uboot-envtools.sh
+. /lib/functions.sh
+
+board=$(board_name)
+
+case "$board" in
+d-link,dgs-1210-16|\
+d-link,dgs-1210-28|\
+d-link,dgs-1210-10p|\
+zyxel,gs1900-8|\
+zyxel,gs1900-8hp-v1|\
+zyxel,gs1900-8hp-v2|\
+zyxel,gs1900-10hp)
+	idx="$(find_mtd_index u-boot-env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x400" "0x10000"
+	;;
+*)
+	idx="$(find_mtd_index u-boot-env)"
+	[ -n "$idx" ] && \
+		ubootenv_add_uci_config "/dev/mtd$idx" "0x0" "0x10000" "0x10000"
+	;;
+esac
+
+config_load ubootenv
+config_foreach ubootenv_add_app_config ubootenv
+
+exit 0
diff --git a/package/boot/uboot-envtools/files/uboot-envtools.sh b/package/boot/uboot-envtools/files/uboot-envtools.sh
new file mode 100644
index 0000000..9218bc4
--- /dev/null
+++ b/package/boot/uboot-envtools/files/uboot-envtools.sh
@@ -0,0 +1,36 @@
+#!/bin/sh
+#
+# Copyright (C) 2011-2012 OpenWrt.org
+#
+
+ubootenv_add_uci_config() {
+	local dev=$1
+	local offset=$2
+	local envsize=$3
+	local secsize=$4
+	local numsec=$5
+	uci batch <<EOF
+add ubootenv ubootenv
+set ubootenv.@ubootenv[-1].dev='$dev'
+set ubootenv.@ubootenv[-1].offset='$offset'
+set ubootenv.@ubootenv[-1].envsize='$envsize'
+set ubootenv.@ubootenv[-1].secsize='$secsize'
+set ubootenv.@ubootenv[-1].numsec='$numsec'
+EOF
+	uci commit ubootenv
+}
+
+ubootenv_add_app_config() {
+	local dev
+	local offset
+	local envsize
+	local secsize
+	local numsec
+	config_get dev "$1" dev
+	config_get offset "$1" offset
+	config_get envsize "$1" envsize
+	config_get secsize "$1" secsize
+	config_get numsec "$1" numsec
+	grep -q "^[[:space:]]*${dev}[[:space:]]*${offset}" /etc/fw_env.config || echo "$dev $offset $envsize $secsize $numsec" >>/etc/fw_env.config
+}
+
diff --git a/package/boot/uboot-envtools/patches/001-compile.patch b/package/boot/uboot-envtools/patches/001-compile.patch
new file mode 100644
index 0000000..9b1b6b5
--- /dev/null
+++ b/package/boot/uboot-envtools/patches/001-compile.patch
@@ -0,0 +1,16 @@
+--- a/tools/env/Makefile
++++ b/tools/env/Makefile
+@@ -8,6 +8,13 @@
+ # with "CC" here for the maximum code reuse of scripts/Makefile.host.
+ override HOSTCC = $(CC)
+ 
++ifneq ($(TARGET_CFLAGS),)
++KBUILD_HOSTCFLAGS = $(TARGET_CFLAGS)
++endif
++ifneq ($(TARGET_LDFLAGS),)
++KBUILD_HOSTLDFLAGS = $(TARGET_LDFLAGS)
++endif
++
+ # Compile for a hosted environment on the target
+ HOST_EXTRACFLAGS  = -I$(srctree)/tools \
+ 		$(patsubst -I%,-idirafter%, $(filter -I%, $(UBOOTINCLUDE))) \
diff --git a/package/boot/uboot-fritz4040/Makefile b/package/boot/uboot-fritz4040/Makefile
new file mode 100644
index 0000000..2130581
--- /dev/null
+++ b/package/boot/uboot-fritz4040/Makefile
@@ -0,0 +1,77 @@
+#
+# Copyright (C) 2013-2014 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)/kernel.mk
+
+PKG_SOURCE_URL:=https://github.com/chunkeey/FritzBox-4040-UBOOT
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_VERSION:=f92be9d783b1210c020d5d6129e210a94bb7e290
+PKG_SOURCE_DATE:=2019-10-19
+PKG_MIRROR_HASH:=e40a7f624b1758b276f81c765ef1da568c595b8bd54568b9cceca7d170ebc612
+
+PKG_RELEASE:=1
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=ipq40xx
+  BUILD_SUBTARGET:=generic
+  UBOOT_BOARD:=$(1)
+  UBOOT_IMAGE:=uboot-$(1).bin
+endef
+
+define U-Boot/fritz1200
+  NAME:=FritzRepeater 1200
+  BUILD_DEVICES:=avm_fritzrepeater-1200
+endef
+
+define U-Boot/fritz3000
+  NAME:=FritzRepeater 3000
+  BUILD_DEVICES:=avm_fritzrepeater-3000
+endef
+
+define U-Boot/fritz4040
+  NAME:=FritzBox 4040
+  BUILD_DEVICES:=avm_fritzbox-4040
+endef
+
+define U-Boot/fritz7530
+  NAME:=FritzBox 7530
+  BUILD_DEVICES:=avm_fritzbox-7530
+endef
+
+UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes
+UBOOT_MAKE_FLAGS = USE_PRIVATE_LIBGCC=yes
+export DTC
+
+define Build/Configure
+	$(Build/Configure/U-Boot)
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $(PKG_BUILD_DIR)/fritz/lzma2eva $(PKG_BUILD_DIR)/fritz/src/lzma2eva.c -lz
+	$(HOSTCC) $(HOST_CFLAGS) $(HOST_LDFLAGS) -o $(PKG_BUILD_DIR)/fritz/tichksum $(PKG_BUILD_DIR)/fritz/src/tichksum.c
+	ln -sf $(STAGING_DIR_HOST)/bin/lzma $(PKG_BUILD_DIR)/fritz
+endef
+
+define Build/Compile
+	$(Build/Compile/U-Boot)
+	(cd $(PKG_BUILD_DIR); ./fritz/fritzcreator.sh $(UBOOT_BOARD);)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(UBOOT_IMAGE)
+endef
+
+define Package/u-boot/install
+	$(Package/u-boot/install/default)
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/upload-to-f4040.sh $(1)/
+endef
+
+UBOOT_TARGETS := fritz1200 fritz3000 fritz4040 fritz7530
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-imx6/Makefile b/package/boot/uboot-imx6/Makefile
new file mode 100644
index 0000000..da069b5
--- /dev/null
+++ b/package/boot/uboot-imx6/Makefile
@@ -0,0 +1,92 @@
+#
+# Copyright (C) 2013-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=2020.04
+PKG_RELEASE:=1
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=imx6
+  UBOOT_IMAGE:=u-boot.imx
+endef
+
+define U-Boot/apalis_imx6
+  NAME:=Toradex Apalis
+  UBOOT_IMAGE:=SPL u-boot.img u-boot-with-spl.imx
+  UBOOT_MAKE_FLAGS:=SPL u-boot.img u-boot-with-spl.imx
+  BUILD_DEVICES:=apalis
+endef
+
+define U-Boot/mx6cuboxi
+   NAME:=SolidRun Cubox-i boards
+   UBOOT_IMAGE:=SPL u-boot.img
+   UBOOT_MAKE_FLAGS:=SPL u-boot.img
+   BUILD_DEVICES:=cubox-i
+   HIDDEN:=1
+endef
+
+define U-Boot/mx6sabresd
+  NAME:=SABRE i.MX6Quad board
+endef
+
+define U-Boot/nitrogen6dl
+  NAME:=Nitrogen6x i.MX6Dual-Lite 1GB board
+endef
+
+define U-Boot/nitrogen6dl2g
+  NAME:=Nitrogen6x i.MX6Dual-Lite 2GB board
+endef
+
+define U-Boot/nitrogen6q
+  NAME:=Nitrogen6x/SABRE Lite (MX6Q/1GB)
+endef
+
+define U-Boot/nitrogen6q2g
+  NAME:=Nitrogen6x i.MX6Quad 2GB board
+endef
+
+define U-Boot/nitrogen6s
+  NAME:=Nitrogen6x i.MX6Solo 512MB board
+endef
+
+define U-Boot/nitrogen6s1g
+  NAME:=Nitrogen6x i.MX6Solo 1GB board
+endef
+
+define U-Boot/wandboard
+  NAME:=Wandboard Dual Lite/Quad/Solo
+  BUILD_DEVICES:=wandboard
+endef
+
+UBOOT_TARGETS := \
+	apalis_imx6 \
+	mx6cuboxi \
+	mx6sabresd \
+	nitrogen6dl \
+	nitrogen6dl2g \
+	nitrogen6q \
+	nitrogen6q2g \
+	nitrogen6s \
+	nitrogen6s1g \
+	wandboard
+
+UBOOT_MAKE_FLAGS += u-boot.imx
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(foreach img,$(UBOOT_IMAGE), \
+		$(CP) $(PKG_BUILD_DIR)/$(img) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(img); \
+	)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-imx6/patches/0001-apalis_imx6_defconfig-enable-some-useful-commands.patch b/package/boot/uboot-imx6/patches/0001-apalis_imx6_defconfig-enable-some-useful-commands.patch
new file mode 100644
index 0000000..10ed918
--- /dev/null
+++ b/package/boot/uboot-imx6/patches/0001-apalis_imx6_defconfig-enable-some-useful-commands.patch
@@ -0,0 +1,37 @@
+From 630b39c46b29de1874149c6b2c18c64966a0fabf Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Sun, 1 Mar 2020 22:47:31 +0100
+Subject: [PATCH] apalis_imx6_defconfig: enable some useful commands
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+partition table info, EXT4 write support, support for FAT and generic FS
+commands like load/ls that work for multiple FS types.
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ configs/apalis_imx6_defconfig | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/configs/apalis_imx6_defconfig
++++ b/configs/apalis_imx6_defconfig
+@@ -44,6 +44,7 @@ CONFIG_CMD_GPIO=y
+ CONFIG_CMD_GPT=y
+ CONFIG_CMD_I2C=y
+ CONFIG_CMD_MMC=y
++CONFIG_CMD_PART=y
+ CONFIG_CMD_USB=y
+ CONFIG_CMD_USB_SDP=y
+ CONFIG_CMD_USB_MASS_STORAGE=y
+@@ -53,6 +54,10 @@ CONFIG_CMD_PMIC=y
+ CONFIG_CMD_REGULATOR=y
+ CONFIG_OF_CONTROL=y
+ CONFIG_DEFAULT_DEVICE_TREE="imx6-apalis"
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_EXT4_WRITE=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_FS_GENERIC=y
+ CONFIG_ENV_IS_IN_MMC=y
+ CONFIG_SYS_RELOC_GD_ENV_ADDR=y
+ CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
diff --git a/package/boot/uboot-imx6/patches/110-mx6cuboxi-mmc-fallback.patch b/package/boot/uboot-imx6/patches/110-mx6cuboxi-mmc-fallback.patch
new file mode 100644
index 0000000..9d490dd
--- /dev/null
+++ b/package/boot/uboot-imx6/patches/110-mx6cuboxi-mmc-fallback.patch
@@ -0,0 +1,15 @@
+--- a/board/solidrun/mx6cuboxi/mx6cuboxi.c
++++ b/board/solidrun/mx6cuboxi/mx6cuboxi.c
+@@ -286,6 +286,12 @@ static void setup_iomux_enet(void)
+ 	gpio_free_list_nodev(&desc, 1);
+ }
+ 
++void board_boot_order(u32 *spl_boot_list)
++{
++	spl_boot_list[0] = spl_boot_device();
++	spl_boot_list[1] = BOOT_DEVICE_MMC1;
++}
++
+ int board_phy_config(struct phy_device *phydev)
+ {
+ 	if (phydev->drv->config)
diff --git a/package/boot/uboot-imx6/patches/111-mx6cuboxi_defconfig-force-mmc-boot.patch b/package/boot/uboot-imx6/patches/111-mx6cuboxi_defconfig-force-mmc-boot.patch
new file mode 100644
index 0000000..4c3dc4c
--- /dev/null
+++ b/package/boot/uboot-imx6/patches/111-mx6cuboxi_defconfig-force-mmc-boot.patch
@@ -0,0 +1,23 @@
+From 00ad8b42dfe801107db25ead8249cb10afcd0f94 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Petr=20=C5=A0tetiar?= <ynezz@true.cz>
+Date: Sun, 1 Mar 2020 22:10:23 +0100
+Subject: [PATCH] mx6cuboxi_defconfig: force mmc boot
+MIME-Version: 1.0
+Content-Type: text/plain; charset=UTF-8
+Content-Transfer-Encoding: 8bit
+
+Signed-off-by: Petr Štetiar <ynezz@true.cz>
+---
+ configs/mx6cuboxi_defconfig | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/configs/mx6cuboxi_defconfig
++++ b/configs/mx6cuboxi_defconfig
+@@ -9,6 +9,7 @@ CONFIG_ENV_SIZE=0x2000
+ CONFIG_ENV_OFFSET=0xFE000
+ CONFIG_DM_GPIO=y
+ CONFIG_SPL_MMC_SUPPORT=y
++CONFIG_SPL_FORCE_MMC_BOOT=y
+ CONFIG_SPL_SERIAL_SUPPORT=y
+ CONFIG_NR_DRAM_BANKS=1
+ CONFIG_SPL=y
diff --git a/package/boot/uboot-kirkwood/Makefile b/package/boot/uboot-kirkwood/Makefile
new file mode 100644
index 0000000..1ed1743
--- /dev/null
+++ b/package/boot/uboot-kirkwood/Makefile
@@ -0,0 +1,144 @@
+#
+# Copyright (C) 2010-2014 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION:=2020.04
+PKG_RELEASE:=1
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=kirkwood
+endef
+
+define U-Boot/dockstar
+  NAME:=Seagate DockStar
+  BUILD_DEVICES:=seagate_dockstar
+endef
+
+define U-Boot/dockstar_second_stage
+  NAME:=Seagate DockStar (second stage)
+  BUILD_DEVICES:=seagate_dockstar
+endef
+
+define U-Boot/goflexhome
+  NAME:=the Seagate GoFlexHome/GoFlexNet
+  BUILD_DEVICES:=seagate_goflexhome seagate_goflexnet
+endef
+
+define U-Boot/ib62x0
+  NAME:=RaidSonic ICY BOX NAS6210 and NAS6220
+  BUILD_DEVICES:=raidsonic_ib-nas62x0
+endef
+
+define U-Boot/ib62x0_second_stage
+  NAME:=RaidSonic ICY BOX NAS6210 and NAS6220 (second stage)
+  BUILD_DEVICES:=raidsonic_ib-nas62x0
+endef
+
+define U-Boot/iconnect
+  NAME:=Iomega iConnect Wireless
+  BUILD_DEVICES:=iom_iconnect-1.1
+endef
+
+define U-Boot/iconnect_second_stage
+  NAME:=Iomega iConnect Wireless (second stage)
+  BUILD_DEVICES:=iom_iconnect-1.1
+endef
+
+define U-Boot/l-50
+  NAME:=CheckPoint L-50
+  BUILD_DEVICES:=checkpoint_l-50
+endef
+
+define U-Boot/nas220
+  NAME:=Seagate Blackarmor NAS220
+  BUILD_DEVICES:=seagate_blackarmor-nas220
+endef
+
+define U-Boot/nsa310
+  NAME:=Zyxel NSA310
+  BUILD_DEVICES:=zyxel_nsa310b
+endef
+
+define U-Boot/nsa310s
+  NAME:=Zyxel NSA310S
+  BUILD_DEVICES:=zyxel_nsa310s
+endef
+
+define U-Boot/nsa325
+  NAME:=Zyxel NSA325v1 and v2
+  BUILD_DEVICES:=zyxel_nsa325
+endef
+
+define U-Boot/pogo_e02
+  NAME:=Cloud Engines Pogoplug E02
+  BUILD_DEVICES:=cloudengines_pogoe02
+endef
+
+define U-Boot/pogo_e02_second_stage
+  NAME:=Cloud Engines Pogoplug E02 (second stage)
+  BUILD_DEVICES:=cloudengines_pogoe02
+endef
+
+define U-Boot/pogoplugv4
+  NAME:=Cloud Engines Pogoplug V4
+  BUILD_DEVICES:=cloudengines_pogoplugv4
+endef
+
+UBOOT_TARGETS := \
+	dockstar dockstar_second_stage \
+	goflexhome \
+	ib62x0 ib62x0_second_stage \
+	iconnect iconnect_second_stage \
+	l-50 \
+	nas220 \
+	nsa310 \
+	nsa310s \
+	nsa325 \
+	pogo_e02 pogo_e02_second_stage \
+	pogoplugv4
+
+define Build/Configure
+	$(if $(findstring _second_stage,$(BUILD_VARIANT)),
+		$(CP) \
+			$(PKG_BUILD_DIR)/configs/$(subst _second_stage,,$(BUILD_VARIANT))_defconfig \
+			$(PKG_BUILD_DIR)/configs/$(BUILD_VARIANT)_defconfig
+		echo CONFIG_SECOND_STAGE=y >> $(PKG_BUILD_DIR)/configs/$(BUILD_VARIANT)_defconfig
+	)
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		$(BUILD_VARIANT)_config V=1
+endef
+
+define Build/Compile
+	+$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR) \
+		u-boot.kwb \
+		CROSS_COMPILE=$(TARGET_CROSS)
+	mkimage -A $(ARCH) -O linux -T kernel -C none \
+		-a 0x600000 -e 0x600000 \
+		-n 'U-Boot uImage' \
+		-d $(PKG_BUILD_DIR)/u-boot.bin $(PKG_BUILD_DIR)/u-boot.img
+endef
+
+define Package/u-boot/install
+	$(CP) \
+		$(PKG_BUILD_DIR)/u-boot.bin \
+		$(PKG_BUILD_DIR)/u-boot.kwb \
+		$(PKG_BUILD_DIR)/u-boot.img \
+		$(1)/
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_HOST)/bin
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/tools/kwboot $(STAGING_DIR_HOST)/bin/
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-kirkwood/patches/007-nsa310-uboot-generic.patch b/package/boot/uboot-kirkwood/patches/007-nsa310-uboot-generic.patch
new file mode 100644
index 0000000..09dc587
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/007-nsa310-uboot-generic.patch
@@ -0,0 +1,662 @@
+
+arm: kirkwood: add ZyXEL NSA310 device
+
+This patch add ZyXEL NSA310 1-Bay Media Server
+
+The ZyXEL NSA310 device is a Kirkwood based NAS:
+
+- SoC: Marvell 88F6702 1200Mhz
+- SDRAM memory: 256MB DDR2 400Mhz
+- Gigabit ethernet: PHY Realtek
+- Flash memory: 128MB
+- 1 Power button
+- 1 Power LED (blue)
+- 5 Status LED (green/red)
+- 1 Copy/Sync button
+- 1 Reset button
+- 2 SATA II port (1 internal and 1 external eSata)
+- 2 USB 2.0 ports (1 front and 1 back)
+- Smart fan
+
+Signed-off-by: Alberto Bursi <alberto.bursi@outlook.it>
+
+NOTE: this patch is ready for upstream, LEDE-specific parts are in
+      another patch
+
+--- a/arch/arm/mach-kirkwood/Kconfig
++++ b/arch/arm/mach-kirkwood/Kconfig
+@@ -53,6 +53,9 @@ config TARGET_GOFLEXHOME
+ config TARGET_NAS220
+ 	bool "BlackArmor NAS220"
+
++config TARGET_NSA310
++	bool "Zyxel NSA310 Board"
++
+ config TARGET_NSA310S
+ 	bool "Zyxel NSA310S"
+
+@@ -86,6 +89,7 @@ source "board/raidsonic/ib62x0/Kconfig"
+ source "board/Seagate/dockstar/Kconfig"
+ source "board/Seagate/goflexhome/Kconfig"
+ source "board/Seagate/nas220/Kconfig"
++source "board/zyxel/nsa310/Kconfig"
+ source "board/zyxel/nsa310s/Kconfig"
+ source "board/alliedtelesis/SBx81LIFKW/Kconfig"
+ source "board/alliedtelesis/SBx81LIFXCAT/Kconfig"
+--- /dev/null
++++ b/board/zyxel/nsa310/Kconfig
+@@ -0,0 +1,12 @@
++if TARGET_NSA310
++
++config SYS_BOARD
++	default "nsa310"
++
++config SYS_VENDOR
++	default "zyxel"
++
++config SYS_CONFIG_NAME
++	default "nsa310"
++
++endif
+--- /dev/null
++++ b/board/zyxel/nsa310/MAINTAINERS
+@@ -0,0 +1,6 @@
++NSA310 BOARD
++M:	Alberto Bursi <alberto.bursi@outlook.it>
++S:	Maintained
++F:	board/zyxel/nsa310/
++F:	include/configs/nsa310.h
++F:	configs/nsa310_defconfig
+--- /dev/null
++++ b/board/zyxel/nsa310/Makefile
+@@ -0,0 +1,12 @@
++#
++# (C) Copyright 2015 bodhi <mibodhi@gmail.com>
++#
++# Based on
++# (C) Copyright 2009
++# Marvell Semiconductor <www.marvell.com>
++# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++obj-y	:= nsa310.o
+--- /dev/null
++++ b/board/zyxel/nsa310/kwbimage.cfg
+@@ -0,0 +1,166 @@
++#
++# Copyright (C) 2013  Rafal Kazmierowski
++#
++# Based on guruplug.c originally written by
++# Siddarth Gore <gores@marvell.com>
++# (C) Copyright 2009
++# Marvell Semiconductor <www.marvell.com>
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This 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.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++# MA 02110-1301 USA
++#
++# Refer docs/README.kwimage for more details about how-to configure
++# and create kirkwood boot image
++#
++
++# Boot Media configurations
++BOOT_FROM	nand
++#BOOT_FROM	uart
++NAND_ECC_MODE	default
++NAND_PAGE_SIZE	0x0800
++
++# SOC registers configuration using bootrom header extension
++# Maximum KWBIMAGE_MAX_CONFIG configurations allowed
++
++# Configure RGMII-0 interface pad voltage to 1.8V
++DATA 0xFFD100e0 0x1b1b1b9b
++
++#Dram initalization for SINGLE x16 CL=5 @ 400MHz
++DATA 0xFFD01400 0x43010c30	# DDR Configuration register
++# bit13-0:  0xc30 (3120 DDR2 clks refresh rate)
++# bit23-14: zero
++# bit24: 1= enable exit self refresh mode on DDR access
++# bit25: 1 required
++# bit29-26: zero
++# bit31-30: 01
++
++DATA 0xFFD01404 0x37543000	# DDR Controller Control Low
++# bit 4:    0=addr/cmd in smame cycle
++# bit 5:    0=clk is driven during self refresh, we don't care for APX
++# bit 6:    0=use recommended falling edge of clk for addr/cmd
++# bit14:    0=input buffer always powered up
++# bit18:    1=cpu lock transaction enabled
++# bit23-20: 5=recommended value for CL=5 and STARTBURST_DEL disabled bit31=0
++# bit27-24: 7= CL+2, STARTBURST sample stages, for freqs 400MHz, unbuffered DIMM
++# bit30-28: 3 required
++# bit31:    0=no additional STARTBURST delay
++
++DATA 0xFFD01408 0x22125451	# DDR Timing (Low) (active cycles value +1)
++# bit3-0:   TRAS lsbs
++# bit7-4:   TRCD
++# bit11- 8: TRP
++# bit15-12: TWR
++# bit19-16: TWTR
++# bit20:    TRAS msb
++# bit23-21: 0x0
++# bit27-24: TRRD
++# bit31-28: TRTP
++
++DATA 0xFFD0140C 0x00000a33	#  DDR Timing (High)
++# bit6-0:   TRFC
++# bit8-7:   TR2R
++# bit10-9:  TR2W
++# bit12-11: TW2W
++# bit31-13: zero required
++
++DATA 0xFFD01410 0x0000000c	#  DDR Address Control
++# bit1-0:   01, Cs0width=x8
++# bit3-2:   10, Cs0size=1Gb
++# bit5-4:   01, Cs1width=x8
++# bit7-6:   10, Cs1size=1Gb
++# bit9-8:   00, Cs2width=nonexistent
++# bit11-10: 00, Cs2size =nonexistent
++# bit13-12: 00, Cs3width=nonexistent
++# bit15-14: 00, Cs3size =nonexistent
++# bit16:    0,  Cs0AddrSel
++# bit17:    0,  Cs1AddrSel
++# bit18:    0,  Cs2AddrSel
++# bit19:    0,  Cs3AddrSel
++# bit31-20: 0 required
++
++DATA 0xFFD01414 0x00000000	#  DDR Open Pages Control
++# bit0:    0,  OpenPage enabled
++# bit31-1: 0 required
++
++DATA 0xFFD01418 0x00000000	#  DDR Operation
++# bit3-0:   0x0, DDR cmd
++# bit31-4:  0 required
++
++DATA 0xFFD0141C 0x00000652	#  DDR Mode
++# bit2-0:   2, BurstLen=2 required
++# bit3:     0, BurstType=0 required
++# bit6-4:   4, CL=5
++# bit7:     0, TestMode=0 normal
++# bit8:     0, DLL reset=0 normal
++# bit11-9:  6, auto-precharge write recovery ????????????
++# bit12:    0, PD must be zero
++# bit31-13: 0 required
++
++DATA 0xFFD01420 0x00000004	#  DDR Extended Mode
++# bit0:    0,  DDR DLL enabled
++# bit1:    0,  DDR drive strenght normal
++# bit2:    0,  DDR ODT control lsd (disabled)
++# bit5-3:  000, required
++# bit6:    1,  DDR ODT control msb, (disabled)
++# bit9-7:  000, required
++# bit10:   0,  differential DQS enabled
++# bit11:   0, required
++# bit12:   0, DDR output buffer enabled
++# bit31-13: 0 required
++
++DATA 0xFFD01424 0x0000F17F	#  DDR Controller Control High
++# bit2-0:  111, required
++# bit3  :  1  , MBUS Burst Chop disabled
++# bit6-4:  111, required
++# bit7  :  0
++# bit8  :  1  , add writepath sample stage, must be 1 for DDR freq >= 300MHz
++# bit9  :  0  , no half clock cycle addition to dataout
++# bit10 :  0  , 1/4 clock cycle skew enabled for addr/ctl signals
++# bit11 :  0  , 1/4 clock cycle skew disabled for write mesh
++# bit15-12: 1111 required
++# bit31-16: 0    required
++
++DATA 0xFFD01428 0x00085520	# DDR2 ODT Read Timing (default values)
++DATA 0xFFD0147C 0x00008552	# DDR2 ODT Write Timing (default values)
++
++
++DATA 0xFFD01504 0x0FFFFFF1	# CS[0]n Size
++#DATA 0xFFD01500 0x00000000	# CS[0]n Base address to 0x0
++# bit0:    1,  Window enabled
++# bit1:    0,  Write Protect disabled
++# bit3-2:  00, CS0 hit selected
++# bit23-4: ones, required
++# bit31-24: 0x0F, Size (i.e. 256MB)
++
++DATA 0xFFD01508 0x10000000	# CS[1]n Base address to 256Mb
++DATA 0xFFD0150C 0x00000000	# CS[2]n Size, window disabled        KAZ z 400db
++DATA 0xFFD01514 0x00000000	# CS[3]n Size, window disabled
++
++DATA 0xFFD0151C 0x00000000	#  DDR ODT Control (Low)
++DATA 0xFFD01494 0x00120012	#  DDR ODT Control (High)              KAZ  z nowy  STATIC_SDRAM_ODT_CTRL_LOW
++# bit1-0:  00, ODT0 controlled by ODT Control (low) register above
++# bit3-2:  01, ODT1 active NEVER!
++# bit31-4: zero, required
++
++DATA 0xFFD01498 0x00000000	# CPU ODT Control                     KAZ STATIC_SDRAM_ODT_CTRL_HI
++DATA 0xFFD0149C 0x0000E403	# DDR Initialization Control          KAZ STATIC_SDRAM_DUNIT_ODT_CTRL
++DATA 0xFFD01480 0x00000001	# DDR Initialization Control
++#bit0=1, enable DDR init upon this register write
++
++# End of Header extension
++DATA 0x0 0x0
+--- /dev/null
++++ b/board/zyxel/nsa310/nsa310.c
+@@ -0,0 +1,190 @@
++/*
++ * Copyright (C) 2013 Rafal Kazmierowski
++ *
++ * Based on NSA320.c Peter Schildmann <linux@schildmann.info>
++ * originally written by
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#include <common.h>
++#include <miiphy.h>
++#include <asm/arch/cpu.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/mpp.h>
++#include <asm/io.h>
++#include "nsa310.h"
++
++DECLARE_GLOBAL_DATA_PTR;
++
++int board_early_init_f(void)
++{
++	/*
++	 * default gpio configuration
++	 * There are maximum 64 gpios controlled through 2 sets of registers
++	 * the below configuration configures mainly initial LED status
++	 */
++	mvebu_config_gpio(NSA310_VAL_LOW, NSA310_VAL_HIGH,
++		       NSA310_OE_LOW, NSA310_OE_HIGH);
++
++	/* Multi-Purpose Pins Functionality configuration */
++	/* (all LEDs & power off active high) */
++	static const u32 kwmpp_config[] = {
++		MPP0_NF_IO2,
++		MPP1_NF_IO3,
++		MPP2_NF_IO4,
++		MPP3_NF_IO5,
++		MPP4_NF_IO6,
++		MPP5_NF_IO7,
++		MPP6_SYSRST_OUTn,
++		MPP7_GPO,
++		MPP8_TW_SDA,	/* PCF8563 RTC chip   */
++		MPP9_TW_SCK,	/* connected to TWSI  */
++		MPP10_UART0_TXD,
++		MPP11_UART0_RXD,
++		MPP12_GPO,		/* SATA2 LED (green)  */
++		MPP13_GPIO,		/* SATA2 LED (red)    */
++		MPP14_GPIO,		/* MCU DATA pin (in)  */
++		MPP15_GPIO,		/* USB LED (green)    */
++		MPP16_GPIO,		/* MCU CLK pin (out)  */
++		MPP17_GPIO,		/* MCU ACT pin (out)  */
++		MPP18_NF_IO0,
++		MPP19_NF_IO1,
++		MPP20_GPIO,
++		MPP21_GPIO,		/* USB LED (red)-Power*/
++		MPP22_GPIO,
++		MPP23_GPIO,
++		MPP24_GPIO,
++		MPP25_GPIO,
++		MPP26_GPIO,
++		MPP27_GPIO,
++		MPP28_GPIO,		/* SYS LED (green)    */
++		MPP29_GPIO,		/* SYS LED (red)      */
++		MPP30_GPIO,
++		MPP31_GPIO,
++		MPP32_GPIO,
++		MPP33_GPIO,
++		MPP34_GPIO,
++		MPP35_GPIO,
++		MPP36_GPIO,		/* Reset button       */
++		MPP37_GPIO,		/* Copy button        */
++		MPP38_GPIO,		/* VID B0             */
++		MPP39_GPIO,		/* COPY LED (green)   */
++		MPP40_GPIO,		/* COPY LED (red)     */
++		MPP41_GPIO,		/* SATA1 LED (green)  */
++		MPP42_GPIO,		/* SATA1 LED (red)    */
++		MPP43_GPIO,		/* HTP pin            */
++		MPP44_GPIO,		/* Buzzer             */
++		MPP45_GPIO,		/* VID B1             */
++		MPP46_GPIO,		/* Power button       */
++		MPP47_GPIO,		/* Power resume data  */
++		MPP48_GPIO,		/* Power off          */
++		MPP49_GPIO,		/* Power resume clock */
++		0
++	};
++	kirkwood_mpp_conf(kwmpp_config,NULL);
++	return 0;
++}
++
++int board_init(void)
++{
++	/* address of boot parameters */
++	gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
++
++	return 0;
++}
++
++#ifdef CONFIG_RESET_PHY_R
++/* Configure and enable MV88E1318 PHY */
++void reset_phy(void)
++{
++	u16 reg;
++	u16 devadr;
++	char *name = "egiga0";
++
++	if (miiphy_set_current_dev(name))
++		return;
++
++	/* command to read PHY dev address */
++	if (miiphy_read(name, 0xEE, 0xEE, (u16 *) &devadr)) {
++		printf("Err..%s could not read PHY dev address\n",
++			__FUNCTION__);
++		return;
++	}
++
++	/* Set RGMII delay */
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, 2);
++	miiphy_read(name, devadr, MV88E1318_MAC_CTRL_REG, &reg);
++	reg |= (MV88E1318_RGMII_RXTM_CTRL | MV88E1318_RGMII_TXTM_CTRL);
++	miiphy_write(name, devadr, MV88E1318_MAC_CTRL_REG, reg);
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, 0);
++
++	/* reset the phy */
++	miiphy_reset(name, devadr);
++
++	printf("MV88E1318 PHY initialized on %s\n", name);
++}
++#endif /* CONFIG_RESET_PHY_R */
++
++#ifdef CONFIG_SHOW_BOOT_PROGRESS
++void show_boot_progress(int val)
++{
++	struct kwgpio_registers *gpio0 = (struct kwgpio_registers *)MVEBU_GPIO0_BASE;
++	u32 dout0 = readl(&gpio0->dout);
++	u32 blen0 = readl(&gpio0->blink_en);
++
++	struct kwgpio_registers *gpio1 = (struct kwgpio_registers *)MVEBU_GPIO1_BASE;
++	u32 dout1 = readl(&gpio1->dout);
++	u32 blen1 = readl(&gpio1->blink_en);
++
++	switch (val) {
++	case BOOTSTAGE_ID_DECOMP_IMAGE:
++		writel(blen0 & ~(SYS_GREEN_LED | SYS_RED_LED), &gpio0->blink_en);
++		writel((dout0 & ~SYS_GREEN_LED) | SYS_RED_LED, &gpio0->dout);
++		break;
++	case BOOTSTAGE_ID_RUN_OS:
++		writel(dout0 & ~SYS_RED_LED, &gpio0->dout);
++		writel(blen0 | SYS_GREEN_LED, &gpio0->blink_en);
++		break;
++	case BOOTSTAGE_ID_NET_START:
++		writel(dout1 & ~COPY_RED_LED, &gpio1->dout);
++		writel((blen1 & ~COPY_RED_LED) | COPY_GREEN_LED, &gpio1->blink_en);
++		break;
++	case BOOTSTAGE_ID_NET_LOADED:
++		writel(blen1 & ~(COPY_RED_LED | COPY_GREEN_LED), &gpio1->blink_en);
++		writel((dout1 & ~COPY_RED_LED) | COPY_GREEN_LED, &gpio1->dout);
++		break;
++	case -BOOTSTAGE_ID_NET_NETLOOP_OK:
++	case -BOOTSTAGE_ID_NET_LOADED:
++		writel(dout1 & ~COPY_GREEN_LED, &gpio1->dout);
++		writel((blen1 & ~COPY_GREEN_LED) | COPY_RED_LED, &gpio1->blink_en);
++		break;
++	default:
++		if (val < 0) {
++			/* error */
++			printf("Error occured, error code = %d\n", -val);
++			writel(dout0 & ~SYS_GREEN_LED, &gpio0->dout);
++			writel(blen0 | SYS_RED_LED, &gpio0->blink_en);
++		}
++		break;
++	}
++}
++#endif
+--- /dev/null
++++ b/board/zyxel/nsa310/nsa310.h
+@@ -0,0 +1,56 @@
++/*
++ * Copyright (C) 2013 Rafal Kazmierowski
++ *
++ * Based on Peter Schildmann <linux@schildmann.info>
++ * and  guruplug.h originally written by
++ * Siddarth Gore <gores@marvell.com>
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#ifndef __NSA310_H
++#define __NSA310_H
++
++/* GPIO's */
++#define SYS_GREEN_LED		(1 << 28)
++#define SYS_RED_LED		(1 << 29)
++#define SATA1_GREEN_LED		(1ULL << 41)
++#define SATA1_RED_LED		(1ULL << 42)
++#define SATA2_GREEN_LED		(1 << 12)
++#define SATA2_RED_LED		(1 << 13)
++#define USB_GREEN_LED		(1 << 15)
++#define USB_RED_LED		(1 << 21)
++#define COPY_GREEN_LED		(1ULL << 39)
++#define COPY_RED_LED		(1ULL << 40)
++
++#define NSA310_OE_LOW   (0)
++#define NSA310_VAL_LOW    (SYS_GREEN_LED)
++#define NSA310_OE_HIGH		(((COPY_GREEN_LED | COPY_RED_LED | \
++                                   SATA1_GREEN_LED | SATA1_RED_LED)) >> 32UL)
++#define NSA310_VAL_HIGH		(0)
++
++/* PHY related */
++#define MV88E1318_MAC_CTRL_REG		21
++#define MV88E1318_PGADR_REG		22
++#define MV88E1318_RGMII_TXTM_CTRL	(1 << 4)
++#define MV88E1318_RGMII_RXTM_CTRL	(1 << 5)
++
++#endif /* __NSA310_H */
+--- /dev/null
++++ b/configs/nsa310_defconfig
+@@ -0,0 +1,48 @@
++CONFIG_ARM=y
++CONFIG_SYS_DCACHE_OFF=y
++CONFIG_ARCH_CPU_INIT=y
++CONFIG_KIRKWOOD=y
++CONFIG_SYS_TEXT_BASE=0x600000
++CONFIG_TARGET_NSA310=y
++CONFIG_IDENT_STRING="\nZyXEL NSA310 1-Bay Power Media Server"
++CONFIG_NR_DRAM_BANKS=2
++CONFIG_BOOTDELAY=3
++CONFIG_SYS_PROMPT="NSA310> "
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++CONFIG_MVGBE=y
++CONFIG_MII=y
++CONFIG_SYS_NS16550=y
++CONFIG_CMD_FDT=y
++CONFIG_OF_LIBFDT=y
++CONFIG_CMD_SETEXPR=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_DNS=y
++CONFIG_CMD_SNTP=y
++CONFIG_CMD_USB=y
++CONFIG_CMD_DATE=y
++CONFIG_CMD_EXT2=y
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_JFFS2=y
++CONFIG_MTD=y
++CONFIG_MTD_RAW_NAND=y
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0x0c0000(uboot),0x80000(uboot_env),0x7ec0000(ubi)"
++CONFIG_CMD_MTDPARTS=y
++CONFIG_CMD_ENV=y
++CONFIG_CMD_NAND=y
++CONFIG_EFI_PARTITION=y
++CONFIG_ENV_IS_IN_NAND=y
++CONFIG_ENV_SIZE=0x20000
++CONFIG_ENV_OFFSET=0xC0000
++CONFIG_ENV_SECT_SIZE=0x20000
++CONFIG_ENV_ADDR=0xC0000
++CONFIG_CMD_UBI=y
++CONFIG_USB=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_STORAGE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
++CONFIG_SYS_LONGHELP=y
+--- /dev/null
++++ b/include/configs/nsa310.h
+@@ -0,0 +1,103 @@
++/* Copyright (C) 2015-2016 bodhi <mibodhi@gmail.com>
++ *
++ * Based on
++ * Copyright (C) 2012  Peter Schildmann <linux@schildmann.info>
++ *
++ * Based on guruplug.h originally written by
++ * Siddarth Gore <gores@marvell.com>
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#ifndef _CONFIG_NSA310_H
++#define _CONFIG_NSA310_H
++
++/*
++ * High Level Configuration Options (easy to change)
++ */
++#define CONFIG_FEROCEON_88FR131		/* CPU Core subversion */
++#define CONFIG_KW88F6281		/* SOC Name */
++
++#define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
++
++/*
++ * Misc Configuration Options
++ */
++#define CONFIG_SHOW_BOOT_PROGRESS 1     /* boot progess display (LED's) */
++
++/*
++ * Commands configuration
++ */
++#define CONFIG_PREBOOT
++
++/*
++ * mv-common.h should be defined after CMD configs since it used them
++ * to enable certain macros
++ */
++#include "mv-common.h"
++
++/*
++ * Default environment variables
++ */
++#define CONFIG_BOOTCOMMAND \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
++
++/*
++ * Ethernet Driver configuration
++ */
++#ifdef CONFIG_CMD_NET
++#define CONFIG_NETCONSOLE
++#define CONFIG_NET_MULTI
++#define CONFIG_MVGBE_PORTS		{1, 0}	/* enable port 0 only */
++#define CONFIG_PHY_BASE_ADR		0x1
++#define CONFIG_RESET_PHY_R
++#endif /* CONFIG_CMD_NET */
++
++/*
++ * SATA Driver configuration
++ */
++#ifdef CONFIG_MVSATA_IDE
++#define CONFIG_SYS_ATA_IDE0_OFFSET      MV_SATA_PORT0_OFFSET
++#define CONFIG_SYS_ATA_IDE1_OFFSET      MV_SATA_PORT1_OFFSET
++#endif /* CONFIG_MVSATA_IDE */
++
++/*
++ * File system
++ */
++#define CONFIG_JFFS2_NAND
++#define CONFIG_JFFS2_LZO
++
++/*
++ *  Date Time
++ */
++#ifdef CONFIG_CMD_DATE
++#define CONFIG_RTC_MV
++#endif /* CONFIG_CMD_DATE */
++
++#endif /* _CONFIG_NSA310_H */
diff --git a/package/boot/uboot-kirkwood/patches/008-nsa325-uboot-generic.patch b/package/boot/uboot-kirkwood/patches/008-nsa325-uboot-generic.patch
new file mode 100644
index 0000000..db9a7a6
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/008-nsa325-uboot-generic.patch
@@ -0,0 +1,649 @@
+--- a/arch/arm/mach-kirkwood/Kconfig
++++ b/arch/arm/mach-kirkwood/Kconfig
+@@ -68,6 +68,9 @@ config TARGET_SBx81LIFXCAT
+ config TARGET_DB_88F6281_BP
+ 	bool "Marvell DB-88F6281-BP"
+ 
++config TARGET_NSA325
++	bool "Zyxel NSA325 board"
++
+ endchoice
+ 
+ config SYS_SOC
+@@ -91,6 +94,7 @@ source "board/Seagate/goflexhome/Kconfig
+ source "board/Seagate/nas220/Kconfig"
+ source "board/zyxel/nsa310/Kconfig"
+ source "board/zyxel/nsa310s/Kconfig"
++source "board/zyxel/nsa325/Kconfig"
+ source "board/alliedtelesis/SBx81LIFKW/Kconfig"
+ source "board/alliedtelesis/SBx81LIFXCAT/Kconfig"
+ source "board/Marvell/db-88f6281-bp/Kconfig"
+--- /dev/null
++++ b/board/zyxel/nsa325/Kconfig
+@@ -0,0 +1,12 @@
++if TARGET_NSA325
++
++config SYS_BOARD
++	default "nsa325"
++
++config SYS_VENDOR
++	default "zyxel"
++
++config SYS_CONFIG_NAME
++	default "nsa325"
++
++endif
+--- /dev/null
++++ b/board/zyxel/nsa325/MAINTAINERS
+@@ -0,0 +1,6 @@
++NSA325 BOARD
++M:	Alberto Bursi <alberto.bursi@outlook.it>
++S:	Maintained
++F:	board/zyxel/nsa325/
++F:	include/configs/nsa325.h
++F:	configs/nsa325_defconfig
+--- /dev/null
++++ b/board/zyxel/nsa325/Makefile
+@@ -0,0 +1,13 @@
++#
++# (C) Copyright 2015 bodhi <mibodhi@gmail.com>
++#
++# Based on
++# (C) Copyright 2009
++# Marvell Semiconductor <www.marvell.com>
++# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++obj-y	:= nsa325.o
++
+--- /dev/null
++++ b/board/zyxel/nsa325/kwbimage.cfg
+@@ -0,0 +1,78 @@
++# Copyright (C) 2015 bodhi <mibodhi@gmail.com>
++#
++# Extracted from Zyxel GPL source for u-boot-1.1.4_NSA325v2
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This 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.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; if not, write to the Free Software
++# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++# MA 02110-1301 USA
++#
++# Refer docs/README.kwimage for more details about how-to configure
++# and create kirkwood boot image
++#
++
++# Boot Media configurations
++#BOOT_FROM	uart
++BOOT_FROM       nand
++NAND_ECC_MODE   default
++NAND_PAGE_SIZE  0x0800
++
++# SOC registers configuration using bootrom header extension
++# Maximum KWBIMAGE_MAX_CONFIG configurations allowed
++
++# Configure RGMII-0 interface pad voltage to 1.8V
++DATA 0xFFD100e0 0x1b1b1b9b
++
++#Dram initalization
++DATA 0xFFD01400 0x4301503E      # DDR Configuration register
++DATA 0xFFD01404 0xB9843000      # DDR Controller Control Low
++DATA 0xFFD01408 0x33137777      # DDR Timing (Low)
++DATA 0xFFD0140C 0x16000C55      # DDR Timing (High)
++DATA 0xFFD01410 0x04000000      # DDR Address Control
++DATA 0xFFD01414 0x00000000	#  DDR Open Pages Control
++DATA 0xFFD01418 0x00000000	#  DDR Operation
++DATA 0xFFD0141C 0x00000672	#  DDR Mode
++DATA 0xFFD01420 0x00000004	#  DDR Extended Mode
++DATA 0xFFD01424 0x0000F14F	#  DDR Controller Control High
++DATA 0xFFD01428 0x000D6720	# DDR3 ODT Read Timing
++DATA 0xFFD0147C 0x0000B571	# DDR2 ODT Write Timing
++DATA 0xFFD01504 0x1FFFFFF1      # CS[0]n Size
++DATA 0xFFD01508 0x20000000      # CS[1]n Base address to 512Mb
++DATA 0xFFD0150C 0x1FFFFFF4      # CS[1]n Size 512Mb Window enabled for CS1
++DATA 0xFFD01514 0x00000000      # CS[2]n Size, window disabled
++DATA 0xFFD0151C 0x00000000      # CS[3]n Size, window disabled
++DATA 0xFFD01494 0x00120000      #  DDR ODT Control (Low)
++DATA 0xFFD01498 0x00000000      #  DDR ODT Control (High)
++DATA 0xFFD0149C 0x0000E803      # CPU ODT Control
++
++DATA 0xFFD015D0 0x00000630
++DATA 0xFFD015D4 0x00000046
++DATA 0xFFD015D8 0x00000008
++DATA 0xFFD015DC 0x00000000
++DATA 0xFFD015E0 0x00000023
++DATA 0xFFD015E4 0x00203C18
++DATA 0xFFD01620 0x00384800
++DATA 0xFFD01480 0x00000001
++DATA 0xFFD20134 0x66666666
++DATA 0xFFD20138 0x00066666
++
++#Disable nsa325 hardware watchdog to allow successful kwbooting
++DATA 0xFFD10100 0x00004000 # set GPIO 14 to high to disable the watchdog
++DATA 0xFFD10104 0xFFFFBFFF # set GPIO 14 to output (to block any other input to it)
++
++# End of Header extension
++DATA 0x0 0x0
++
+--- /dev/null
++++ b/board/zyxel/nsa325/nsa325.c
+@@ -0,0 +1,265 @@
++/*
++ * Copyright (C) 2015 bodhi <mibodhi@gmail.com>
++ *
++ * Based on
++ * Copyright (C) 2014  Jason Plum <jplum@archlinuxarm.org>
++ *
++ * Based on nsa320.c originall written by
++ * Copyright (C) 2012  Peter Schildmann <linux@schildmann.info>
++ *
++ * Based on guruplug.c originally written by
++ * Siddarth Gore <gores@marvell.com>
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#include <common.h>
++#include <miiphy.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/mpp.h>
++#include <asm/arch/cpu.h>
++#include <asm/gpio.h>
++#include <asm/io.h>
++#include "nsa325.h"
++#include <asm/arch/gpio.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++int board_early_init_f(void)
++{
++	/*
++	 * default gpio configuration
++	 * There are maximum 64 gpios controlled through 2 sets of registers
++	 * the below configuration configures mainly initial LED status
++	 */
++	mvebu_config_gpio(NSA325_VAL_LOW, NSA325_VAL_HIGH,
++		       NSA325_OE_LOW, NSA325_OE_HIGH);
++
++	/* Multi-Purpose Pins Functionality configuration */
++	/* (all LEDs & power off active high) */
++	u32 kwmpp_config[] = {
++		MPP0_NF_IO2,
++		MPP1_NF_IO3,
++		MPP2_NF_IO4,
++		MPP3_NF_IO5,
++		MPP4_NF_IO6,
++		MPP5_NF_IO7,
++		MPP6_SYSRST_OUTn,
++		MPP7_GPO,
++		MPP8_TW_SDA,		/* PCF8563 RTC chip   */
++		MPP9_TW_SCK,		/* connected to TWSI  */
++		MPP10_UART0_TXD,
++		MPP11_UART0_RXD,
++		MPP12_GPO,		/* HDD2 LED (green)   */
++		MPP13_GPIO,		/* HDD2 LED (red)     */
++		MPP14_GPIO,		/* MCU DATA pin (in)  */
++		MPP15_GPIO,		/* USB LED (green)    */
++		MPP16_GPIO,		/* MCU CLK pin (out)  */
++		MPP17_GPIO,		/* MCU ACT pin (out)  */
++		MPP18_NF_IO0,
++		MPP19_NF_IO1,
++		MPP20_GPIO,
++		MPP21_GPIO,		/* USB power          */
++		MPP22_GPIO,
++		MPP23_GPIO,
++		MPP24_GPIO,
++		MPP25_GPIO,
++		MPP26_GPIO,
++		MPP27_GPIO,
++		MPP28_GPIO,		/* SYS LED (green)    */
++		MPP29_GPIO,		/* SYS LED (orange)   */
++		MPP30_GPIO,
++		MPP31_GPIO,
++		MPP32_GPIO,
++		MPP33_GPIO,
++		MPP34_GPIO,
++		MPP35_GPIO,
++		MPP36_GPIO,		/* reset button       */
++		MPP37_GPIO,		/* copy button        */
++		MPP38_GPIO,		/* VID B0             */
++		MPP39_GPIO,		/* COPY LED (green)   */
++		MPP40_GPIO,		/* COPY LED (red)     */
++		MPP41_GPIO,		/* HDD1 LED (green)   */
++		MPP42_GPIO,		/* HDD1 LED (red)     */
++		MPP43_GPIO,		/* HTP pin            */
++		MPP44_GPIO,		/* buzzer             */
++		MPP45_GPIO,		/* VID B1             */
++		MPP46_GPIO,		/* power button       */
++		MPP47_GPIO,		/* HDD2 power         */
++		MPP48_GPIO,		/* power off          */
++		0
++	};
++	kirkwood_mpp_conf(kwmpp_config, NULL);
++	return 0;
++}
++
++int board_init(void)
++{
++
++	/* address of boot parameters */
++	gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
++
++	/* This disables the hardware watchdog in the mcu on this board. */
++	kw_gpio_set_valid(14, 1);
++	kw_gpio_direction_output(14, 0);
++	kw_gpio_set_value(14, 1);
++
++	return 0;
++}
++
++#ifdef CONFIG_RESET_PHY_R
++/* Configure and enable MV88E1318 PHY */
++void reset_phy(void)
++{
++	u16 reg;
++	u16 devadr;
++	char *name = "egiga0";
++
++	if (miiphy_set_current_dev(name))
++		return;
++
++	/* command to read PHY dev address */
++	if (miiphy_read(name, 0xEE, 0xEE, (u16 *) &devadr)) {
++		printf("Err..%s could not read PHY dev address\n",
++			__FUNCTION__);
++		return;
++	}
++
++	/* Set RGMII delay */
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, MV88E1318_MAC_CTRL_PG);
++	miiphy_read(name, devadr, MV88E1318_MAC_CTRL_REG, &reg);
++	reg |= (MV88E1318_RGMII_RXTM_CTRL | MV88E1318_RGMII_TXTM_CTRL);
++	miiphy_write(name, devadr, MV88E1318_MAC_CTRL_REG, reg);
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, 0);
++
++	/* reset the phy */
++	miiphy_reset(name, devadr);
++
++	/* The ZyXEL NSA325 uses the 88E1310S Alaska (interface identical to 88E1318) */
++	/* and has an MCU attached to the LED[2] via tristate interrupt */
++	reg = 0;
++
++	/* switch to LED register page */
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, MV88E1318_LED_PG);
++	/* read out LED polarity register */
++	miiphy_read(name, devadr, MV88E1318_LED_POL_REG, &reg);
++	/* clear 4, set 5 - LED2 low, tri-state */
++	reg &= ~(MV88E1318_LED2_4);
++	reg |= (MV88E1318_LED2_5);
++	/* write back LED polarity register */
++	miiphy_write(name, devadr, MV88E1318_LED_POL_REG, reg);
++	/* jump back to page 0, per the PHY chip documenation. */
++	miiphy_write(name, devadr, MV88E1318_PGADR_REG, 0);
++
++	/* Set the phy back to auto-negotiation mode. Onboard mcu sets it as 10Mbits/s on poweroff for WoL function */
++	miiphy_write(name, devadr, 0x4, 0x1e1);
++	miiphy_write(name, devadr, 0x9, 0x300);
++	/* Downshift */
++	miiphy_write(name, devadr, 0x10, 0x3860);
++	miiphy_write(name, devadr, 0x0, 0x9140);
++
++	printf("MV88E1318 PHY initialized on %s\n", name);
++
++}
++#endif /* CONFIG_RESET_PHY_R */
++
++#ifdef CONFIG_SHOW_BOOT_PROGRESS
++void show_boot_progress(int val)
++{
++	struct kwgpio_registers *gpio0 = (struct kwgpio_registers *)MVEBU_GPIO0_BASE;
++	u32 dout0 = readl(&gpio0->dout);
++	u32 blen0 = readl(&gpio0->blink_en);
++
++	struct kwgpio_registers *gpio1 = (struct kwgpio_registers *)MVEBU_GPIO1_BASE;
++	u32 dout1 = readl(&gpio1->dout);
++	u32 blen1 = readl(&gpio1->blink_en);
++
++	switch (val) {
++	case BOOTSTAGE_ID_DECOMP_IMAGE:
++		writel(blen0 & ~(SYS_GREEN_LED | SYS_ORANGE_LED), &gpio0->blink_en);
++		writel((dout0 & ~SYS_GREEN_LED) | SYS_ORANGE_LED, &gpio0->dout);
++		break;
++	case BOOTSTAGE_ID_RUN_OS:
++		writel(dout0 & ~SYS_ORANGE_LED, &gpio0->dout);
++		writel(blen0 | SYS_GREEN_LED, &gpio0->blink_en);
++		break;
++	case BOOTSTAGE_ID_NET_START:
++		writel(dout1 & ~COPY_RED_LED, &gpio1->dout);
++		writel((blen1 & ~COPY_RED_LED) | COPY_GREEN_LED, &gpio1->blink_en);
++		break;
++	case BOOTSTAGE_ID_NET_LOADED:
++		writel(blen1 & ~(COPY_RED_LED | COPY_GREEN_LED), &gpio1->blink_en);
++		writel((dout1 & ~COPY_RED_LED) | COPY_GREEN_LED, &gpio1->dout);
++		break;
++	case -BOOTSTAGE_ID_NET_NETLOOP_OK:
++	case -BOOTSTAGE_ID_NET_LOADED:
++		writel(dout1 & ~COPY_GREEN_LED, &gpio1->dout);
++		writel((blen1 & ~COPY_GREEN_LED) | COPY_RED_LED, &gpio1->blink_en);
++		break;
++	default:
++		if (val < 0) {
++			/* error */
++			printf("Error occured, error code = %d\n", -val);
++			writel(dout0 & ~SYS_GREEN_LED, &gpio0->dout);
++			writel(blen0 | SYS_ORANGE_LED, &gpio0->blink_en);
++		}
++		break;
++	}
++}
++#endif
++
++#if defined(CONFIG_KIRKWOOD_GPIO)
++/* Return GPIO button status */
++/*
++un-pressed:
++ gpio-36 (Reset Button ) in hi (act lo) - IRQ edge (clear )
++ gpio-37 (Copy Button  ) in hi (act lo) - IRQ edge (clear )
++ gpio-46 (Power Button ) in lo (act hi) - IRQ edge (clear )
++pressed
++ gpio-36 (Reset Button ) in lo (act hi) - IRQ edge (clear )
++ gpio-37 (Copy Button  ) in lo (act hi) - IRQ edge (clear )
++ gpio-46 (Power Button ) in hi (act lo) - IRQ edge (clear )
++*/
++
++static int
++do_read_button(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++	if (strcmp(argv[1], "power") == 0) {
++			kw_gpio_set_valid(BTN_POWER, GPIO_INPUT_OK);
++			kw_gpio_direction_input(BTN_POWER);
++			return !kw_gpio_get_value(BTN_POWER);
++	}
++	else if (strcmp(argv[1], "reset") == 0)
++		return kw_gpio_get_value(BTN_RESET);
++	else if (strcmp(argv[1], "copy") == 0)
++		return kw_gpio_get_value(BTN_COPY);
++	else
++		return -1;
++}
++
++
++U_BOOT_CMD(button, 2, 0, do_read_button,
++	   "Return GPIO button status 0=off 1=on",
++	   "- button power|reset|copy: test buttons states\n"
++);
++
++#endif
++
+--- /dev/null
++++ b/board/zyxel/nsa325/nsa325.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright (C) 2014  Jason Plum <jplum@archlinuxarm.org>
++ *
++ * Based on nsa320.h originall written by
++ * Copyright (C) 2012  Peter Schildmann <linux@schildmann.info>
++ *
++ * Based on guruplug.h originally written by
++ * Siddarth Gore <gores@marvell.com>
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#ifndef __NSA325_H
++#define __NSA325_H
++
++/* low GPIO's */
++#define HDD2_GREEN_LED		(1 << 12)
++#define HDD2_RED_LED		(1 << 13)
++#define USB_GREEN_LED		(1 << 15)
++#define USB_POWER		(1 << 21)
++#define SYS_GREEN_LED		(1 << 28)
++#define SYS_ORANGE_LED		(1 << 29)
++
++#define PIN_USB_GREEN_LED	15
++#define PIN_USB_POWER		21
++
++#define NSA325_OE_LOW		(~(HDD2_GREEN_LED | HDD2_RED_LED | \
++				   USB_GREEN_LED | USB_POWER | \
++				   SYS_GREEN_LED | SYS_ORANGE_LED))
++#define NSA325_VAL_LOW		(SYS_GREEN_LED | USB_POWER)
++
++/* high GPIO's */
++#define COPY_GREEN_LED		(1 << 7)
++#define COPY_RED_LED		(1 << 8)
++#define HDD1_GREEN_LED		(1 << 9)
++#define HDD1_RED_LED		(1 << 10)
++#define HDD2_POWER          (1 << 15)
++#define WATCHDOG_SIGNAL     (1 << 14)
++
++#define NSA325_OE_HIGH		(~(COPY_GREEN_LED | COPY_RED_LED | \
++				   HDD1_GREEN_LED | HDD1_RED_LED | HDD2_POWER | WATCHDOG_SIGNAL ))
++#define NSA325_VAL_HIGH		(WATCHDOG_SIGNAL | HDD2_POWER)
++
++/* PHY related */
++#define MV88E1318_PGADR_REG		22
++#define MV88E1318_MAC_CTRL_PG	2
++#define MV88E1318_MAC_CTRL_REG	21
++#define MV88E1318_RGMII_TXTM_CTRL	(1 << 4)
++#define MV88E1318_RGMII_RXTM_CTRL	(1 << 5)
++#define MV88E1318_LED_PG        3
++#define MV88E1318_LED_POL_REG	17
++#define MV88E1318_LED2_4	    (1 << 4)
++#define MV88E1318_LED2_5	    (1 << 5)
++
++#define BTN_POWER				46
++#define BTN_RESET				36
++#define BTN_COPY				37
++
++#endif /* __NSA325_H */
+--- /dev/null
++++ b/configs/nsa325_defconfig
+@@ -0,0 +1,48 @@
++CONFIG_ARM=y
++CONFIG_SYS_DCACHE_OFF=y
++CONFIG_ARCH_CPU_INIT=y
++CONFIG_KIRKWOOD=y
++CONFIG_SYS_TEXT_BASE=0x600000
++CONFIG_TARGET_NSA325=y
++CONFIG_IDENT_STRING="\nZyXEL NSA325 2-Bay Power Media Server"
++CONFIG_NR_DRAM_BANKS=2
++CONFIG_BOOTDELAY=3
++CONFIG_SYS_PROMPT="NSA325> "
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++CONFIG_MVGBE=y
++CONFIG_MII=y
++CONFIG_SYS_NS16550=y
++CONFIG_CMD_FDT=y
++CONFIG_OF_LIBFDT=y
++CONFIG_CMD_SETEXPR=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_DNS=y
++CONFIG_CMD_SNTP=y
++CONFIG_CMD_USB=y
++CONFIG_USB=y
++CONFIG_CMD_DATE=y
++CONFIG_CMD_EXT2=y
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_JFFS2=y
++CONFIG_MTD=y
++CONFIG_MTD_RAW_NAND=y
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0x0c0000(uboot),0x80000(uboot_env),0x7ec0000(ubi)"
++CONFIG_CMD_MTDPARTS=y
++CONFIG_CMD_ENV=y
++CONFIG_CMD_NAND=y
++CONFIG_EFI_PARTITION=y
++CONFIG_ENV_IS_IN_NAND=y
++CONFIG_ENV_SIZE=0x20000
++CONFIG_ENV_OFFSET=0xC0000
++CONFIG_ENV_SECT_SIZE=0x20000
++CONFIG_ENV_ADDR=0xC0000
++CONFIG_CMD_UBI=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_STORAGE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
++CONFIG_SYS_LONGHELP=y
+--- /dev/null
++++ b/include/configs/nsa325.h
+@@ -0,0 +1,106 @@
++/*
++ * (C) Copyright 2016 bodhi <mibodhi@gmail.com>
++ *
++ * Based on
++ * Copyright (C) 2014 Jason Plum <jplum@archlinuxarm.org>
++ * Based on
++ * Copyright (C) 2012  Peter Schildmann <linux@schildmann.info>
++ *
++ * Based on guruplug.h originally written by
++ * Siddarth Gore <gores@marvell.com>
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301 USA
++ */
++
++#ifndef _CONFIG_NSA325_H
++#define _CONFIG_NSA325_H
++
++/*
++ * High Level Configuration Options (easy to change)
++ */
++#define CONFIG_FEROCEON_88FR131	1	/* CPU Core subversion */
++#define CONFIG_KW88F6281	1	/* SOC Name */
++
++#define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
++
++/*
++ * Misc Configuration Options
++ */
++#define CONFIG_SHOW_BOOT_PROGRESS 1	/* boot progess display (LED's) */
++
++/*
++ * Commands configuration
++ */
++#define CONFIG_PREBOOT
++
++/*
++ * mv-common.h should be defined after CMD configs since it used them
++ * to enable certain macros
++ */
++#include "mv-common.h"
++
++/*
++ * Default environment variables
++ */
++#define CONFIG_BOOTCOMMAND \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
++
++/*
++ * Ethernet Driver configuration
++ */
++#ifdef CONFIG_CMD_NET
++#define CONFIG_MVGBE_PORTS		{1, 0}	/* enable port 0 only */
++#define CONFIG_PHY_BASE_ADR		0x1
++#define CONFIG_NETCONSOLE
++#endif /* CONFIG_CMD_NET */
++
++/*
++ * SATA Driver configuration
++ */
++#ifdef CONFIG_MVSATA_IDE
++#define CONFIG_SYS_ATA_IDE0_OFFSET      MV_SATA_PORT0_OFFSET
++#define CONFIG_SYS_ATA_IDE1_OFFSET      MV_SATA_PORT1_OFFSET
++#endif /* CONFIG_MVSATA_IDE */
++
++/*
++ * File system
++ */
++#define CONFIG_JFFS2_NAND
++#define CONFIG_JFFS2_LZO
++
++/*
++ *  Date Time
++ */
++#ifdef CONFIG_CMD_DATE
++#define CONFIG_RTC_MV
++#endif /* CONFIG_CMD_DATE */
++
++#define CONFIG_KIRKWOOD_GPIO /* Enable GPIO Support */
++
++#endif /* _CONFIG_NSA325_H */
diff --git a/package/boot/uboot-kirkwood/patches/010-pogoplug_v4.patch b/package/boot/uboot-kirkwood/patches/010-pogoplug_v4.patch
new file mode 100644
index 0000000..58bf664
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/010-pogoplug_v4.patch
@@ -0,0 +1,1520 @@
+--- a/arch/arm/mach-kirkwood/Kconfig
++++ b/arch/arm/mach-kirkwood/Kconfig
+@@ -25,6 +25,9 @@ config TARGET_LSXL
+ config TARGET_POGO_E02
+ 	bool "pogo_e02 Board"
+
++config TARGET_POGOPLUGV4
++    bool "Pogoplug V4 Board"
++
+ config TARGET_DNS325
+ 	bool "dns325 Board"
+
+@@ -83,6 +86,7 @@ source "board/Marvell/guruplug/Kconfig"
+ source "board/Marvell/sheevaplug/Kconfig"
+ source "board/buffalo/lsxl/Kconfig"
+ source "board/cloudengines/pogo_e02/Kconfig"
++source "board/cloudengines/pogoplugv4/Kconfig"
+ source "board/d-link/dns325/Kconfig"
+ source "board/iomega/iconnect/Kconfig"
+ source "board/keymile/Kconfig"
+--- a/arch/arm/mach-kirkwood/include/mach/kw88f6192.h
++++ b/arch/arm/mach-kirkwood/include/mach/kw88f6192.h
+@@ -15,6 +15,6 @@
+ #define KW_REGS_PHY_BASE		KW88F6192_REGS_PHYS_BASE
+
+ /* TCLK Core Clock defination */
+-#define CONFIG_SYS_TCLK	  166000000 /* 166MHz */
++#define CONFIG_SYS_TCLK	  166666667 /* 166MHz */
+
+ #endif /* _CONFIG_KW88F6192_H */
+--- a/arch/arm/mach-kirkwood/include/mach/mpp.h
++++ b/arch/arm/mach-kirkwood/include/mach/mpp.h
+@@ -216,10 +216,12 @@
+ #define MPP33_GPIO		MPP( 33, 0x0, 1, 1, 0,   1,   1,   1    )
+ #define MPP33_TDM_DTX		MPP( 33, 0x2, 0, 1, 0,   0,   1,   1    )
+ #define MPP33_GE1_13		MPP( 33, 0x3, 0, 0, 0,   1,   1,   1    )
++#define MPP33_SATA1_ACTn        MPP( 33, 0x5, 0, 1, 0,   1,   1,   1    )
+
+ #define MPP34_GPIO		MPP( 34, 0x0, 1, 1, 0,   1,   1,   1    )
+ #define MPP34_TDM_SPI_CS1	MPP( 34, 0x2, 0, 1, 0,   0,   1,   1    )
+ #define MPP34_GE1_14		MPP( 34, 0x3, 0, 0, 0,   1,   1,   1    )
++#define MPP34_SATA1_ACTn       MPP( 34, 0x5, 0, 1, 0,   1,   1,   1    )
+
+ #define MPP35_GPIO		MPP( 35, 0x0, 1, 1, 1,   1,   1,   1    )
+ #define MPP35_TDM_CH0_TX_QL	MPP( 35, 0x2, 0, 1, 0,   0,   1,   1    )
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/Kconfig
+@@ -0,0 +1,12 @@
++if TARGET_POGOPLUGV4
++
++config SYS_BOARD
++	default "pogoplugv4"
++
++config SYS_VENDOR
++	default "cloudengines"
++
++config SYS_CONFIG_NAME
++	default "pogoplugv4"
++
++endif
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/MAINTAINERS
+@@ -0,0 +1,6 @@
++POGOPLUGV4 BOARD
++M:	Alberto Bursi <alberto.bursi@outlook.it>
++S:	Maintained
++F:	board/cloudengines/pogoplugv4/
++F:	include/configs/pogoplugv4.h
++F:	configs/pogoplugv4_defconfig
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/Makefile
+@@ -0,0 +1,11 @@
++#
++# (C) Copyright 2009 bodhi <mibodhi@gmail.com>
++#
++# Based on
++# Marvell Semiconductor <www.marvell.com>
++# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++obj-y	:= pogoplugv4.o
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/kwbimage.cfg
+@@ -0,0 +1,167 @@
++#
++# Copyright (C) 2012
++# David Purdy <david.c.purdy@gmail.com>
++#
++# Based on Kirkwood support:
++# (C) Copyright 2009
++# Marvell Semiconductor <www.marvell.com>
++# Written-by: Prafulla Wadaskar <prafulla <at> marvell.com>
++#
++# See file CREDITS for list of people who contributed to this
++# project.
++#
++# This program is free software; you can redistribute it and/or
++# modify it under the terms of the GNU General Public License as
++# published by the Free Software Foundation; either version 2 of
++# the License, or (at your option) any later version.
++#
++# This 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.
++#
++# You should have received a copy of the GNU General Public License
++# along with this program; If not, see <http://www.gnu.org/licenses/>.
++#
++# Refer docs/README.kwimage for more details about how-to configure
++# and create kirkwood boot image
++#
++
++# Boot Media configurations   (DONE)
++BOOT_FROM	nand
++NAND_ECC_MODE	default
++NAND_PAGE_SIZE	0x0800
++
++# SOC registers configuration using bootrom header extension
++# Maximum KWBIMAGE_MAX_CONFIG configurations allowed
++
++# Configure RGMII-0 interface pad voltage to 1.8V (SHOULD BE SAME)
++DATA 0xffd100e0 0x1b1b1b9b
++
++#Dram initalization for SINGLE x16 CL=3 @ 200MHz   (need CL=3 @ 200MHz?)
++DATA 0xffd01400 0x43000618	# DDR Configuration register
++# bit13-0:  0x200 (200 DDR2 clks refresh rate)
++# bit23-14: zero
++# bit24: 1= enable exit self refresh mode on DDR access
++# bit25: 1 required
++# bit29-26: zero
++# bit31-30: 01
++
++DATA 0xffd01404 0x34143000	# DDR Controller Control Low
++# bit 4:    0=addr/cmd in smame cycle
++# bit 5:    0=clk is driven during self refresh, we don't care for APX
++# bit 6:    0=use recommended falling edge of clk for addr/cmd
++# bit14:    0=input buffer always powered up
++# bit18:    1=cpu lock transaction enabled
++# bit23-20: 3=recommended value for CL=3 and STARTBURST_DEL disabled bit31=0
++# bit27-24: 6= CL+3, STARTBURST sample stages, for freqs 400MHz, unbuffered DIMM
++# bit30-28: 3 required
++# bit31:    0=no additional STARTBURST delay
++
++DATA 0xffd01408 0x11012227	# DDR Timing (Low) (active cycles value +1)
++# bit3-0:   TRAS lsbs
++# bit7-4:   TRCD
++# bit11- 8: TRP
++# bit15-12: TWR
++# bit19-16: TWTR
++# bit20:    TRAS msb
++# bit23-21: 0x0
++# bit27-24: TRRD
++# bit31-28: TRTP
++
++DATA 0xffd0140c 0x00000819	#  DDR Timing (High)
++# bit6-0:   TRFC
++# bit8-7:   TR2R
++# bit10-9:  TR2W
++# bit12-11: TW2W
++# bit31-13: zero required
++
++DATA 0xffd01410 0x00000001	#  DDR Address Control  (changed to Dockstar vals)
++# bit1-0:   00, Cs0width=x16
++# bit3-2:   10, Cs0size=512Mb
++# bit5-4:   00, Cs2width=nonexistent
++# bit7-6:   00, Cs1size =nonexistent
++# bit9-8:   00, Cs2width=nonexistent
++# bit11-10: 00, Cs2size =nonexistent
++# bit13-12: 00, Cs3width=nonexistent
++# bit15-14: 00, Cs3size =nonexistent
++# bit16:    0,  Cs0AddrSel
++# bit17:    0,  Cs1AddrSel
++# bit18:    0,  Cs2AddrSel
++# bit19:    0,  Cs3AddrSel
++# bit31-20: 0 required
++
++DATA 0xffd01414 0x00000000	#  DDR Open Pages Control
++# bit0:    0,  OpenPage enabled
++# bit31-1: 0 required
++
++DATA 0xffd01418 0x00000000	#  DDR Operation
++# bit3-0:   0x0, DDR cmd
++# bit31-4:  0 required
++
++DATA 0xffd0141c 0x00000632	#  DDR Mode
++# bit2-0:   2, BurstLen=2 required
++# bit3:     0, BurstType=0 required
++# bit6-4:   4, CL=5				(<===== change to CL=3 ?)
++# bit7:     0, TestMode=0 normal
++# bit8:     0, DLL reset=0 normal
++# bit11-9:  6, auto-precharge write recovery ????????????
++# bit12:    0, PD must be zero
++# bit31-13: 0 required
++
++DATA 0xffd01420 0x00000040	#  DDR Extended Mode
++# bit0:    0,  DDR DLL enabled
++# bit1:    0,  DDR drive strenght normal
++# bit2:    0,  DDR ODT control lsd (disabled)
++# bit5-3:  000, required
++# bit6:    1,  DDR ODT control msb, (disabled)
++# bit9-7:  000, required
++# bit10:   0,  differential DQS enabled
++# bit11:   0, required
++# bit12:   0, DDR output buffer enabled
++# bit31-13: 0 required
++
++DATA 0xffd01424 0x0000F07F	#  DDR Controller Control High
++# bit2-0:  111, required
++# bit3  :  1  , MBUS Burst Chop disabled
++# bit6-4:  111, required
++# bit7  :  0
++# bit8  :  0  , no sample stage
++# bit9  :  0  , no half clock cycle addition to dataout
++# bit10 :  0  , 1/4 clock cycle skew enabled for addr/ctl signals
++# bit11 :  0  , 1/4 clock cycle skew disabled for write mesh
++# bit15-12: 1111 required
++# bit31-16: 0    required
++
++DATA 0xffd01428 0x00085520	# DDR2 ODT Read Timing (default values)
++DATA 0xffd0147c 0x00008552	# DDR2 ODT Write Timing (default values)
++
++DATA 0xFFD01500 0x00000000	# CS[0]n Base address to 0x0
++DATA 0xFFD01504 0x07FFFFF1	# CS[0]n Size
++# bit0:    1,  Window enabled
++# bit1:    0,  Write Protect disabled
++# bit3-2:  00, CS0 hit selected
++# bit23-4: ones, required
++# bit31-24: 0x07, Size (i.e. 128MB)
++
++DATA 0xFFD0150C 0x00000000	# CS[1]n Size, window disabled
++DATA 0xFFD01514 0x00000000	# CS[2]n Size, window disabled
++DATA 0xFFD0151C 0x00000000	# CS[3]n Size, window disabled
++
++DATA 0xffd01494 0x00030000	#  DDR ODT Control (Low)		 (DONE)
++# bit3-0:  2, ODT0Rd, MODT[0] asserted during read from DRAM CS1
++# bit7-4:  1, ODT0Rd, MODT[0] asserted during read from DRAM CS0
++# bit19-16:2, ODT0Wr, MODT[0] asserted during write to DRAM CS1
++# bit23-20:1, ODT0Wr, MODT[0] asserted during write to DRAM CS0
++
++DATA 0xffd01498 0x00000000	#  DDR ODT Control (High)  (DONE)
++# bit1-0:  00, ODT0 controlled by ODT Control (low) register above
++# bit3-2:  01, ODT1 active NEVER!
++# bit31-4: zero, required
++
++DATA 0xffd0149c 0x0000e803	# CPU ODT Control	 (DONE)
++DATA 0xffd01480 0x00000001	# DDR Initialization Control	 (DONE)
++#bit0=1, enable DDR init upon this register write
++
++# End of Header extension
++DATA 0x0 0x0
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/pogoplugv4.c
+@@ -0,0 +1,223 @@
++/*
++ * Copyright (C) 2016 bodhi <mibodhi@gmail.com>
++ * Copyright (C) 2014 bodhi <mibodhi@gmail.com>
++ *
++ * Based on
++ *
++ * Copyright (C) 2014 <ebbes.ebbes@gmail.com>
++ *
++ * Copyright (C) 2012
++ * David Purdy <david.c.purdy@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#include <common.h>
++#include <miiphy.h>
++#include <asm/arch/cpu.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/mpp.h>
++#include <asm/io.h>
++#include "pogoplugv4.h"
++#include <asm/arch/gpio.h>
++
++#ifdef CONFIG_KIRKWOOD_MMC
++#include <kirkwood_mmc.h>
++#endif /* CONFIG_KIRKWOOD_MMC */
++
++
++DECLARE_GLOBAL_DATA_PTR;
++
++int board_early_init_f(void)
++{
++	/*
++	 * default gpio configuration
++	 * There are maximum 64 gpios controlled through 2 sets of registers
++	 * the  below configuration configures mainly initial LED status
++	 */
++	mvebu_config_gpio(POGOPLUGV4_OE_VAL_LOW,
++			POGOPLUGV4_OE_VAL_HIGH,
++			POGOPLUGV4_OE_LOW, POGOPLUGV4_OE_HIGH);
++
++	/* Multi-Purpose Pins Functionality configuration */
++	u32 kwmpp_config[] = {
++		MPP0_NF_IO2,
++		MPP1_NF_IO3,
++		MPP2_NF_IO4,
++		MPP3_NF_IO5,
++		MPP4_NF_IO6,
++		MPP5_NF_IO7,
++		MPP6_SYSRST_OUTn,
++		MPP7_GPO,
++		MPP8_TW_SDA,
++		MPP9_TW_SCK,
++		MPP10_UART0_TXD,
++		MPP11_UART0_RXD,
++		MPP12_SD_CLK,
++		MPP13_SD_CMD,
++		MPP14_SD_D0,
++		MPP15_SD_D1,
++		MPP16_SD_D2,
++		MPP17_SD_D3,
++		MPP18_NF_IO0,
++		MPP19_NF_IO1,
++		MPP20_SATA1_ACTn,
++		MPP21_SATA0_ACTn,
++		MPP22_GPIO,	/* Green LED */
++		MPP23_GPIO,
++		MPP24_GPIO,	/* Red LED */
++		MPP25_GPIO,
++		MPP26_GPIO,
++		MPP27_GPIO,
++		MPP28_GPIO,
++		MPP29_GPIO,	/* Eject button */
++		MPP30_GPIO,
++		MPP31_GPIO,
++		MPP32_GPIO,
++		MPP33_GPIO,
++		MPP34_GPIO,
++		MPP35_GPIO,	/* FR6192 has only 36 GPIOs */
++		0
++	};
++	kirkwood_mpp_conf(kwmpp_config, NULL);
++
++	return 0;
++}
++
++int board_init(void)
++{
++	/* Boot parameters address */
++	gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
++
++        kw_gpio_set_valid(20, 1);
++        kw_gpio_set_valid(21, 1);
++        kw_gpio_set_valid(22, 1);
++        kw_gpio_set_valid(24, 1);
++
++	return 0;
++}
++
++#ifdef CONFIG_RESET_PHY_R
++/* Configure and initialize PHY */
++void reset_phy(void)
++{
++	u16 reg;
++	u16 devadr;
++	char *name = "egiga0";
++
++	if (miiphy_set_current_dev(name))
++		return;
++
++	/* command to read PHY dev address */
++	if (miiphy_read(name, 0xEE, 0xEE, (u16 *) &devadr)) {
++		printf("Err..(%s) could not read PHY dev address\n", __func__);
++		return;
++	}
++
++	/*
++	 * Enable RGMII delay on Tx and Rx for CPU port
++	 * Ref: sec 4.7.2 of chip datasheet
++	 */
++	miiphy_write(name, devadr, MV88E1116_PGADR_REG, 2);
++	miiphy_read(name, devadr, MV88E1116_MAC_CTRL_REG, &reg);
++	reg |= (MV88E1116_RGMII_RXTM_CTRL | MV88E1116_RGMII_TXTM_CTRL);
++	miiphy_write(name, devadr, MV88E1116_MAC_CTRL_REG, reg);
++	miiphy_write(name, devadr, MV88E1116_PGADR_REG, 0);
++
++	/* reset the phy */
++	miiphy_reset(name, devadr);
++
++	debug("88E1116 Initialized on %s\n", name);
++}
++#endif /* CONFIG_RESET_PHY_R */
++
++#ifdef CONFIG_KIRKWOOD_MMC
++int board_mmc_init(bd_t *bis)
++{
++       kw_mmc_initialize(bis);
++       return 0;
++}
++#endif /* CONFIG_KIRKWOOD_MMC */
++
++
++#define GREEN_LED	(1 << 22)
++#define RED_LED		(1 << 24)
++#define BOTH_LEDS	(GREEN_LED | RED_LED)
++#define NEITHER_LED	0
++
++static void set_leds(u32 leds, u32 blinking)
++{
++	struct kwgpio_registers *r;
++	u32 oe;
++	u32 bl;
++
++	r = (struct kwgpio_registers *)MVEBU_GPIO0_BASE;
++	oe = readl(&r->oe) | BOTH_LEDS;
++	writel(oe & ~leds, &r->oe);	/* active low */
++	bl = readl(&r->blink_en) & ~BOTH_LEDS;
++	writel(bl | blinking, &r->blink_en);
++}
++
++void show_boot_progress(int val)
++{
++	switch (val) {
++	case BOOTSTAGE_ID_RUN_OS:		/* booting Linux */
++		set_leds(BOTH_LEDS, NEITHER_LED);
++		break;
++	case BOOTSTAGE_ID_NET_ETH_START:	/* Ethernet initialization */
++		set_leds(GREEN_LED, GREEN_LED);
++		break;
++	default:
++		if (val < 0)	/* error */
++			set_leds(RED_LED, RED_LED);
++		break;
++	}
++}
++
++#if defined(CONFIG_KIRKWOOD_GPIO)
++/* Return GPIO button status */
++/*
++un-pressed:
++ gpio-29 (Eject Button ) in hi (act lo) - IRQ edge (clear )
++pressed
++ gpio-29 (Eject Button ) in lo (act hi) - IRQ edge (clear )
++*/
++
++static int
++do_read_button(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
++{
++	if (strcmp(argv[1], "eject") == 0) {
++			kw_gpio_set_valid(BTN_EJECT, GPIO_INPUT_OK);
++			kw_gpio_direction_input(BTN_EJECT);
++			return kw_gpio_get_value(BTN_EJECT);
++	}
++	else
++		return -1;
++}
++
++
++U_BOOT_CMD(button, 2, 0, do_read_button,
++	   "Return GPIO button status 0=off 1=on",
++	   "- button eject: test buttons states\n"
++);
++
++#endif
+--- /dev/null
++++ b/board/cloudengines/pogoplugv4/pogoplugv4.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (C) 2016
++ * bodhi <mibodhi@gmail.com>
++ *
++ * Copyright (C) 2012
++ * David Purdy <david.c.purdy@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef __POGOPLUGV4_H
++#define __POGOPLUGV4_H
++
++/* GPIO configuration */
++#define POGOPLUGV4_OE_LOW				(~(0))
++#define POGOPLUGV4_OE_HIGH				(~(0))
++#define POGOPLUGV4_OE_VAL_LOW			(1 << 29)
++#define POGOPLUGV4_OE_VAL_HIGH			0
++
++/* PHY related */
++#define MV88E1116_LED_FCTRL_REG			10
++#define MV88E1116_CPRSP_CR3_REG			21
++#define MV88E1116_MAC_CTRL_REG			21
++#define MV88E1116_PGADR_REG			22
++#define MV88E1116_RGMII_TXTM_CTRL		(1 << 4)
++#define MV88E1116_RGMII_RXTM_CTRL		(1 << 5)
++
++/* button */
++#define BTN_EJECT				29
++
++#endif /* __POGOPLUGV4_H */
+--- /dev/null
++++ b/configs/pogoplugv4_defconfig
+@@ -0,0 +1,51 @@
++CONFIG_ARM=y
++CONFIG_SYS_DCACHE_OFF=y
++CONFIG_ARCH_CPU_INIT=y
++CONFIG_KIRKWOOD=y
++CONFIG_SYS_TEXT_BASE=0x600000
++CONFIG_TARGET_POGOPLUGV4=y
++CONFIG_SYS_PROMPT="pogoplugv4> "
++CONFIG_IDENT_STRING="\nPogoplug V4"
++CONFIG_NR_DRAM_BANKS=2
++CONFIG_BOOTDELAY=3
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++CONFIG_MVGBE=y
++CONFIG_MII=y
++CONFIG_SYS_NS16550=y
++CONFIG_CMD_FDT=y
++CONFIG_OF_LIBFDT=y
++CONFIG_OF_BOOTZ=y
++CONFIG_CMD_SETEXPR=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_DNS=y
++CONFIG_CMD_SNTP=y
++CONFIG_CMD_USB=y
++CONFIG_CMD_DATE=y
++CONFIG_CMD_EXT2=y
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_JFFS2=y
++CONFIG_MTD=y
++CONFIG_MTD_RAW_NAND=y
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0x1c0000(uboot),0x40000(uboot_env),0x7e00000(ubi)"
++CONFIG_CMD_MTDPARTS=y
++CONFIG_CMD_ENV=y
++CONFIG_CMD_NAND=y
++CONFIG_CMD_MMC=y
++CONFIG_CMD_GPIO=y
++CONFIG_EFI_PARTITION=y
++CONFIG_ENV_IS_IN_NAND=y
++CONFIG_ENV_SIZE=0x20000
++CONFIG_ENV_OFFSET=0x1C0000
++CONFIG_ENV_SECT_SIZE=0x20000
++CONFIG_ENV_ADDR=0x1C0000
++CONFIG_CMD_UBI=y
++CONFIG_USB=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_STORAGE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
++CONFIG_SYS_LONGHELP=y
+--- a/drivers/gpio/kw_gpio.c
++++ b/drivers/gpio/kw_gpio.c
+@@ -147,3 +147,36 @@ void kw_gpio_set_blink(unsigned pin, int
+ 	/* Set blinking. */
+ 	__set_blinking(pin, blink);
+ }
++
++
++/*
++ *  Hooks to  GENERIC_GPIO primitives
++ */
++
++int gpio_direction_input(unsigned pin)
++{
++       return kw_gpio_direction_input(pin);
++}
++
++int gpio_direction_output(unsigned pin, int value)
++{
++        return kw_gpio_direction_output(pin, value);
++}
++
++void gpio_set_value(unsigned pin, int value) {
++       kw_gpio_set_value(pin, value);
++}
++
++int gpio_get_value(unsigned pin) {
++       return kw_gpio_get_value(pin);
++}
++
++int gpio_request(unsigned gpio, const char *label)
++{
++       return 0;
++}
++
++int gpio_free(unsigned gpio)
++{
++       return 0;
++}
+--- a/drivers/mmc/Makefile
++++ b/drivers/mmc/Makefile
+@@ -66,6 +66,7 @@ obj-$(CONFIG_MMC_SDHCI_TANGIER)		+= tang
+ obj-$(CONFIG_MMC_SDHCI_TEGRA)		+= tegra_mmc.o
+ obj-$(CONFIG_MMC_SDHCI_XENON)		+= xenon_sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_ZYNQ)		+= zynq_sdhci.o
++obj-$(CONFIG_KIRKWOOD_MMC)		+= kirkwood_mmc.o
+
+ obj-$(CONFIG_MMC_SUNXI)			+= sunxi_mmc.o
+ obj-$(CONFIG_MMC_UNIPHIER)		+= tmio-common.o uniphier-sd.o
+--- /dev/null
++++ b/drivers/mmc/kirkwood_mmc.c
+@@ -0,0 +1,482 @@
++/*
++ * (C) Copyright 2014 bodhi <mibodhi@gmail.com>
++ *
++ * Based on
++ *
++ * (C) Copyright 2014 <ebbes.ebbes@gmail.com>
++ *
++ * Based on
++ *
++ * Driver for Marvell SDIO/MMC controller
++ *
++ * (C) Copyright 2012
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Gérald Kerma <uboot at doukki.net>
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <part.h>
++#include <mmc.h>
++#include <asm/io.h>
++#include <asm/arch/cpu.h>
++#include <asm/arch/soc.h>
++
++#include <kirkwood_mmc.h>
++
++#define DRIVER_NAME	"kwsdio"
++
++static int kw_mmc_setup_data(struct mmc_data *data)
++{
++	u32 ctrl_reg;
++
++#ifdef DEBUG
++	printf("%s, data %s : blocks=%d blksz=%d\n", DRIVER_NAME,
++		(data->flags & MMC_DATA_READ) ? "read" : "write",
++		data->blocks, data->blocksize);
++#endif
++
++	/* default to maximum timeout */
++	ctrl_reg = kwsd_read(SDIO_HOST_CTRL);
++	ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
++	kwsd_write(SDIO_HOST_CTRL, ctrl_reg);
++
++	if (data->flags & MMC_DATA_READ) {
++		kwsd_write(SDIO_SYS_ADDR_LOW,(u32)data->dest & 0xffff);
++		kwsd_write(SDIO_SYS_ADDR_HI,(u32)data->dest >> 16);
++	} else {
++		kwsd_write(SDIO_SYS_ADDR_LOW,(u32)data->src & 0xffff);
++		kwsd_write(SDIO_SYS_ADDR_HI,(u32)data->src >> 16);
++	}
++
++	kwsd_write(SDIO_BLK_COUNT, data->blocks);
++	kwsd_write(SDIO_BLK_SIZE, data->blocksize);
++
++	return 0;
++}
++
++static int kw_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd, struct mmc_data *data)
++{
++	int	timeout = 10;
++	int err;
++	ushort waittype = 0;
++	ushort resptype = 0;
++	ushort xfertype = 0;
++	ushort resp_indx = 0;
++
++#ifdef CONFIG_MMC_DEBUG
++	printf("cmdidx [0x%x] resp_type[0x%x] cmdarg[0x%x]\n", cmd->cmdidx, cmd->resp_type, cmd->cmdarg);
++#endif
++
++	udelay(10000);
++
++#ifdef CONFIG_MMC_DEBUG
++	printf("%s: cmd %d (hw state 0x%04x)\n", DRIVER_NAME, cmd->cmdidx, kwsd_read(SDIO_HW_STATE));
++#endif
++
++	/* Checking if card is busy */
++	while ((kwsd_read(SDIO_HW_STATE) & CARD_BUSY)) {
++		if (timeout == 0) {
++			printf("%s: card busy!\n", DRIVER_NAME);
++			return -1;
++		}
++		timeout--;
++		udelay(1000);
++	}
++
++	/* Set up for a data transfer if we have one */
++	if (data) {
++		if ((err = kw_mmc_setup_data(data)))
++			return err;
++	}
++
++	resptype = SDIO_CMD_INDEX(cmd->cmdidx);
++
++	/* Analyzing resptype/xfertype/waittype for the command */
++	if (cmd->resp_type & MMC_RSP_BUSY)
++		resptype |= SDIO_CMD_RSP_48BUSY;
++	else if (cmd->resp_type & MMC_RSP_136)
++		resptype |= SDIO_CMD_RSP_136;
++	else if (cmd->resp_type & MMC_RSP_PRESENT)
++		resptype |= SDIO_CMD_RSP_48;
++	else
++		resptype |= SDIO_CMD_RSP_NONE;
++
++	if (cmd->resp_type & MMC_RSP_CRC)
++		resptype |= SDIO_CMD_CHECK_CMDCRC;
++
++	if (cmd->resp_type & MMC_RSP_OPCODE)
++		resptype |= SDIO_CMD_INDX_CHECK;
++
++	if (cmd->resp_type & MMC_RSP_PRESENT) {
++		resptype |= SDIO_UNEXPECTED_RESP;
++		waittype |= SDIO_NOR_UNEXP_RSP;
++	}
++
++	if (data) {
++		resptype |= SDIO_CMD_DATA_PRESENT | SDIO_CMD_CHECK_DATACRC16;
++		xfertype |= SDIO_XFER_MODE_HW_WR_DATA_EN;
++		if (data->flags & MMC_DATA_READ) {
++			xfertype |= SDIO_XFER_MODE_TO_HOST;
++			waittype = SDIO_NOR_DMA_INI;
++		} else
++			waittype |= SDIO_NOR_XFER_DONE;
++	} else
++		waittype |= SDIO_NOR_CMD_DONE;
++
++	/* Setting cmd arguments */
++	kwsd_write(SDIO_ARG_LOW, cmd->cmdarg & 0xffff);
++	kwsd_write(SDIO_ARG_HI, cmd->cmdarg >> 16);
++
++	/* Setting Xfer mode */
++	kwsd_write(SDIO_XFER_MODE, xfertype);
++
++	kwsd_write(SDIO_NOR_INTR_STATUS, ~SDIO_NOR_CARD_INT);
++	kwsd_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
++
++	/* Sending command */
++	kwsd_write(SDIO_CMD, resptype);
++/*
++	kwsd_write(SDIO_CMD, KW_MMC_MAKE_CMD(cmd->cmdidx, resptype));
++*/
++
++	kwsd_write(SDIO_NOR_INTR_EN, SDIO_POLL_MASK);
++	kwsd_write(SDIO_ERR_INTR_EN, SDIO_POLL_MASK);
++
++	/* Waiting for completion */
++	timeout = 1000000;
++
++	while (!((kwsd_read(SDIO_NOR_INTR_STATUS)) & waittype)) {
++		if (kwsd_read(SDIO_NOR_INTR_STATUS) & SDIO_NOR_ERROR) {
++#ifdef DEBUG
++			printf("%s: kw_mmc_send_cmd: error! cmdidx : %d, err reg: %04x\n", DRIVER_NAME, cmd->cmdidx,
++wsd_read(SDIO_ERR_INTR_STATUS));
++#endif
++			if (kwsd_read(SDIO_ERR_INTR_STATUS) & (SDIO_ERR_CMD_TIMEOUT | SDIO_ERR_DATA_TIMEOUT)) {
++				return -ETIMEDOUT;
++			}
++			return -ECOMM;
++		}
++
++		timeout--;
++		udelay(1);
++		if (timeout <= 0) {
++			printf("%s: command timed out\n", DRIVER_NAME);
++			return -ETIMEDOUT;
++		}
++	}
++
++	/* Handling response */
++	if (cmd->resp_type & MMC_RSP_136) {
++		uint response[8];
++		for (resp_indx = 0; resp_indx < 8; resp_indx++)
++			response[resp_indx] = kwsd_read(SDIO_RSP(resp_indx));
++
++		cmd->response[0] =		((response[0] & 0x03ff) << 22) |
++								((response[1] & 0xffff) << 6) |
++								((response[2] & 0xfc00) >> 10);
++		cmd->response[1] =		((response[2] & 0x03ff) << 22) |
++								((response[3] & 0xffff) << 6) |
++								((response[4] & 0xfc00) >> 10);
++		cmd->response[2] =		((response[4] & 0x03ff) << 22) |
++								((response[5] & 0xffff) << 6) |
++								((response[6] & 0xfc00) >> 10);
++		cmd->response[3] =		((response[6] & 0x03ff) << 22) |
++								((response[7] & 0x3fff) << 8);
++	} else if (cmd->resp_type & MMC_RSP_PRESENT) {
++		uint response[3];
++		for (resp_indx = 0; resp_indx < 3; resp_indx++)
++			response[resp_indx] = kwsd_read(SDIO_RSP(resp_indx));
++
++		cmd->response[0] = 		((response[2] & 0x003f) << (8 - 8))		|
++								((response[1] & 0xffff) << (14 - 8))	|
++								((response[0] & 0x03ff) << (30 - 8));
++		cmd->response[1] = 		((response[0] & 0xfc00) >> 10);
++		cmd->response[2] =		0;
++		cmd->response[3] =		0;
++	}
++
++#ifdef CONFIG_MMC_DEBUG
++	printf("%s: resp[0x%x] ", DRIVER_NAME, cmd->resp_type);
++	printf("[0x%x] ", cmd->response[0]);
++	printf("[0x%x] ", cmd->response[1]);
++	printf("[0x%x] ", cmd->response[2]);
++	printf("[0x%x] ", cmd->response[3]);
++	printf("\n");
++#endif
++
++	return 0;
++}
++
++#if 0
++/* Disable these three functions as they are not used anyway */
++
++static void kwsd_power_up(void)
++{
++#ifdef DEBUG
++	printf("%s: power up\n", DRIVER_NAME);
++#endif
++	/* disable interrupts */
++	kwsd_write(SDIO_NOR_INTR_EN, 0);
++	kwsd_write(SDIO_ERR_INTR_EN, 0);
++
++	/* SW reset */
++	kwsd_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
++
++	kwsd_write(SDIO_XFER_MODE, 0);
++
++	/* enable status */
++	kwsd_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
++	kwsd_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
++
++	/* enable interrupts status */
++	kwsd_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
++	kwsd_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
++}
++
++static void kwsd_power_down(void)
++{
++#ifdef DEBUG
++	printf("%s: power down\n", DRIVER_NAME);
++#endif
++	/* disable interrupts */
++	kwsd_write(SDIO_NOR_INTR_EN, 0);
++	kwsd_write(SDIO_ERR_INTR_EN, 0);
++
++	/* SW reset */
++	kwsd_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
++
++	kwsd_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
++
++	/* disable status */
++	kwsd_write(SDIO_NOR_STATUS_EN, 0);
++	kwsd_write(SDIO_ERR_STATUS_EN, 0);
++
++	/* enable interrupts status */
++	kwsd_write(SDIO_NOR_INTR_STATUS, SDIO_POLL_MASK);
++	kwsd_write(SDIO_ERR_INTR_STATUS, SDIO_POLL_MASK);
++}
++
++static u32 kw_mmc_get_base_clock(void)
++{
++	/* Original version did a check for board device id and revision id
++	 * and assigned one of these clocks:
++	 *   KW_MMC_BASE_FAST_CLK_100 (revid == 0 && devid != MV88F6282_DEV_ID)
++	 *   KW_MMC_BASE_FAST_CLK_200 (revid != 0 || devid == MV88F6282_DEV_ID)
++	 * However, this check was disabled and
++	 *   KW_MMC_BASE_FAST_CLOCK
++	 * was returned in every case.
++	 * Therefore, all of the dead logic was removed. */
++	return KW_MMC_BASE_FAST_CLOCK;
++}
++#endif /* #if 0 */
++
++static inline u32 kw_mmc_get_base_clock(void)
++{
++	/* get MMC base clock. If any logic other than just returning
++	 * a fixed value is ever used, remove inline modifier. */
++
++	/* Possible values:
++	 *  - KW_MMC_BASE_FAST_CLOCK   (166 MHz)
++	 *  - KW_MMC_BASE_FAST_CLK_100 (100 MHz)
++	 *  - KW_MMC_BASE_FAST_CLK_200 (200 MHz)
++	 *
++	 * Tests have shown that 200 MHz is more reliable than
++	 * 166 MHz, so this value is used. */
++	return KW_MMC_BASE_FAST_CLK_200;
++}
++
++static void kw_mmc_set_clk(unsigned int clock)
++{
++	unsigned int m;
++
++	if (clock == 0) {
++#ifdef DEBUG
++		printf("%s: clock off\n", DRIVER_NAME);
++#endif
++		kwsd_write(SDIO_XFER_MODE, SDIO_XFER_MODE_STOP_CLK);
++		kwsd_write(SDIO_CLK_DIV, KW_MMC_BASE_DIV_MAX);
++	} else {
++		m = kw_mmc_get_base_clock() / (2 * clock) - 1;
++		if (m > KW_MMC_BASE_DIV_MAX)
++			m = KW_MMC_BASE_DIV_MAX;
++#ifdef DEBUG
++		printf("%s: kw_mmc_set_clk: base = %d dividor = 0x%x clock=%d\n", DRIVER_NAME,
++w_mmc_get_base_clock(), m, clock);
++#endif
++		kwsd_write(SDIO_CLK_DIV, m & KW_MMC_BASE_DIV_MAX);
++	}
++	udelay(10000);
++}
++
++static void kw_mmc_set_bus(unsigned int bus)
++{
++	u32 ctrl_reg = 0;
++
++	ctrl_reg = kwsd_read(SDIO_HOST_CTRL);
++	ctrl_reg &= ~SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
++
++	switch (bus) {
++		case 4:
++			ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_4_BITS;
++			break;
++		case 1:
++		default:
++			ctrl_reg |= SDIO_HOST_CTRL_DATA_WIDTH_1_BIT;
++	}
++	/* default transfer mode */
++	ctrl_reg |= SDIO_HOST_CTRL_BIG_ENDIAN;
++	ctrl_reg &= ~SDIO_HOST_CTRL_LSB_FIRST;
++
++	/* default to maximum timeout */
++	ctrl_reg |= SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX);
++
++	ctrl_reg |= SDIO_HOST_CTRL_PUSH_PULL_EN;
++
++	ctrl_reg |= SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY;
++
++	/*
++	 * The HI_SPEED_EN bit is causing trouble with many (but not all)
++	 * high speed SD, SDHC and SDIO cards.  Not enabling that bit
++	 * makes all cards work.  So let's just ignore that bit for now
++	 * and revisit this issue if problems for not enabling this bit
++	 * are ever reported.
++	 */
++#if 0
++	if (ios->timing == MMC_TIMING_MMC_HS ||
++	    ios->timing == MMC_TIMING_SD_HS)
++		ctrl_reg |= SDIO_HOST_CTRL_HI_SPEED_EN;
++#endif
++
++#ifdef DEBUG
++	printf("%s: ctrl 0x%04x: %s %s %s\n", DRIVER_NAME, ctrl_reg,
++		(ctrl_reg & SDIO_HOST_CTRL_PUSH_PULL_EN) ?
++			"push-pull" : "open-drain",
++		(ctrl_reg & SDIO_HOST_CTRL_DATA_WIDTH_4_BITS) ?
++			"4bit-width" : "1bit-width",
++		(ctrl_reg & SDIO_HOST_CTRL_HI_SPEED_EN) ?
++			"high-speed" : "");
++#endif
++
++	kwsd_write(SDIO_HOST_CTRL, ctrl_reg);
++	udelay(10000);
++}
++
++static void kw_mmc_set_ios(struct mmc *mmc)
++{
++#ifdef DEBUG
++	printf("%s: bus[%d] clock[%d]\n", DRIVER_NAME, mmc->bus_width, mmc->clock);
++#endif
++	kw_mmc_set_bus(mmc->bus_width);
++	kw_mmc_set_clk(mmc->clock);
++}
++
++static int kw_mmc_init(struct mmc *mmc)
++{
++#ifdef DEBUG
++	printf("%s: kw_mmc_init\n", DRIVER_NAME);
++#endif
++
++	/*
++	* Setting host parameters
++	* Initial Host Ctrl : Timeout : max , Normal Speed mode, 4-bit data mode
++	* Big Endian, SD memory Card, Push_pull CMD Line
++	*/
++	kwsd_write(SDIO_HOST_CTRL,
++		SDIO_HOST_CTRL_TMOUT(SDIO_HOST_CTRL_TMOUT_MAX) |
++		SDIO_HOST_CTRL_DATA_WIDTH_4_BITS |
++		SDIO_HOST_CTRL_BIG_ENDIAN |
++		SDIO_HOST_CTRL_PUSH_PULL_EN |
++		SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY);
++
++	kwsd_write(SDIO_CLK_CTRL, 0);
++
++	/* enable status */
++	kwsd_write(SDIO_NOR_STATUS_EN, SDIO_POLL_MASK);
++	kwsd_write(SDIO_ERR_STATUS_EN, SDIO_POLL_MASK);
++
++	/* disable interrupts */
++	kwsd_write(SDIO_NOR_INTR_EN, 0);
++	kwsd_write(SDIO_ERR_INTR_EN, 0);
++
++	/* SW reset */
++	kwsd_write(SDIO_SW_RESET, SDIO_SW_RESET_NOW);
++
++	udelay(10000);
++	return 0;
++}
++
++int kw_mmc_initialize(bd_t *bis)
++{
++	struct mmc *mmc = NULL;
++        struct mmc_config *cfg = NULL;
++        struct mmc_ops *ops = NULL;
++	char *name = NULL;
++
++#ifdef DEBUG
++	printf("%s: %s base_clock = %d\n", DRIVER_NAME, kirkwood_id(), kw_mmc_get_base_clock());
++#endif
++	mmc = malloc(sizeof(struct mmc));
++	if (!mmc)
++		return -1;
++        memset(mmc, 0, sizeof(*mmc));
++
++        cfg = malloc(sizeof(*cfg));
++        if (cfg == NULL)
++                return -1;
++        memset(cfg, 0, sizeof(*cfg));
++        mmc->cfg = cfg;   /* provided configuration */
++
++        ops = malloc(sizeof(*ops));
++        if (ops == NULL)
++                return -1;
++        memset(ops, 0, sizeof(*ops));
++        cfg->ops = ops;
++
++        name = malloc(sizeof(DRIVER_NAME)+1);
++        if (name == NULL)
++                return -1;
++        cfg->name = name;
++
++	sprintf(cfg->name, DRIVER_NAME);
++
++	ops->send_cmd	= kw_mmc_send_cmd;
++	ops->set_ios	= kw_mmc_set_ios;
++	ops->init	= kw_mmc_init;
++
++	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34;
++	cfg->host_caps = MMC_MODE_4BIT | MMC_MODE_HS;
++
++	cfg->f_min = kw_mmc_get_base_clock()/KW_MMC_BASE_DIV_MAX;
++	cfg->f_max = KW_MMC_CLOCKRATE_MAX;
++	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
++
++	mmc = mmc_create (cfg, NULL);
++
++        if (mmc == NULL) {
++		free(name);
++		free(ops);
++                free(cfg);
++	        printf("\nFailed to Initialize MMC\n");
++                return -1;
++        }
++
++	return 0;
++}
+--- a/include/configs/mv-common.h
++++ b/include/configs/mv-common.h
+@@ -75,4 +75,10 @@
+ #define CONFIG_SYS_MAX_NAND_DEVICE     1
+ #endif
+
++/*
++ * Kirkwood MMC
++ */
++#if defined(CONFIG_KIRKWOOD) && defined(CONFIG_CMD_MMC)
++#define CONFIG_SYS_MMC_BASE KW_SDIO_BASE
++#endif /* defined(CONFIG_KIRKWOOD) && defined(CONFIG_CMD_MMC) */
+ #endif /* _MV_COMMON_H */
+--- /dev/null
++++ b/include/configs/pogoplugv4.h
+@@ -0,0 +1,113 @@
++/*
++ * Copyright (C) 2014-2016 bodhi <mibodhi@gmail.com>
++ * Based on
++ *
++ * Copyright (C) 2012
++ * David Purdy <david.c.purdy@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ *
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; If not, see <http://www.gnu.org/licenses/>.
++ */
++
++#ifndef _CONFIG_POGOPLUGV4_H
++#define _CONFIG_POGOPLUGV4_H
++
++/*
++ * Machine type definition and ID
++ */
++#define MACH_TYPE_POGOPLUGV4		3960
++#define CONFIG_MACH_TYPE		MACH_TYPE_POGOPLUGV4
++
++/*
++ * High Level Configuration Options (easy to change)
++ */
++#define CONFIG_FEROCEON_88FR131		/* #define CPU Core subversion */
++#define CONFIG_KW88F6192		/* SOC Name */
++#define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
++
++#define CONFIG_FEATURE_COMMAND_EDITING
++#define CONFIG_SYS_64BIT_LBA
++
++/*
++ * Commands configuration
++ */
++
++#define CONFIG_KIRKWOOD_GPIO
++#define CONFIG_PREBOOT
++
++/*
++ * mv-common.h should be defined after CMD configs since it used them
++ * to enable certain macros
++ */
++#include "mv-common.h"
++
++/*
++ * Default environment variables
++ */
++#define CONFIG_BOOTCOMMAND \
++	"usb reset ; " \
++	"fatload usb 0:1 0x2000000 initramfs.bin ; "\
++	"bootm 0x2000000 ; " \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
++
++/*
++ * Ethernet Driver configuration
++ */
++#ifdef CONFIG_CMD_NET
++#define CONFIG_NETCONSOLE
++#define CONFIG_MVGBE_PORTS	{1, 0}	/* enable port 0 only */
++#define CONFIG_PHY_BASE_ADR	0
++#endif /* CONFIG_CMD_NET */
++
++/*
++ * File system
++ */
++#define CONFIG_JFFS2_NAND
++#define CONFIG_JFFS2_LZO
++
++/*
++ * SATA
++ */
++#ifdef CONFIG_MVSATA_IDE
++#define CONFIG_SYS_ATA_IDE0_OFFSET	MV_SATA_PORT0_OFFSET
++#endif
++
++/*
++ *  Date Time
++ */
++#ifdef CONFIG_CMD_DATE
++#define CONFIG_RTC_MV
++#endif /* CONFIG_CMD_DATE */
++
++/*
++ * Kirkwood GPIO
++ */
++#define CONFIG_KIRKWOOD_GPIO
++
++#endif /* _CONFIG_POGOPLUGV4_H */
+--- /dev/null
++++ b/include/kirkwood_mmc.h
+@@ -0,0 +1,268 @@
++/*
++ * (C) Copyright 2014 <ebbes.ebbes@gmail.com>
++ *
++ * Based on
++ *
++ * (C) Copyright 2012
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Gérald Kerma <uboot at doukki.net>
++ * See file CREDITS for list of people who contributed to this
++ * project.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License as
++ * published by the Free Software Foundation; either version 2 of
++ * the License, or (at your option) any later version.
++ *
++ * This 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.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
++ * MA 02111-1307 USA
++ */
++
++#ifndef __KIRKWOOD_MMC_H__
++#define __KIRKWOOD_MMC_H__
++
++/*
++ * Clock rates
++ */
++
++#define KW_MMC_CLOCKRATE_MAX			50000000
++#define KW_MMC_BASE_DIV_MAX			0x7ff
++#define KW_MMC_BASE_FAST_CLOCK		CONFIG_SYS_TCLK
++#define KW_MMC_BASE_FAST_CLK_100		100000000
++#define KW_MMC_BASE_FAST_CLK_200		200000000
++
++/*
++ * Macros
++ */
++#define kwsd_write(offs, val)	writel(val, CONFIG_SYS_MMC_BASE + (offs))
++#define kwsd_read(offs)			readl(CONFIG_SYS_MMC_BASE + (offs))
++
++#define KW_MMC_MAKE_CMD(c, f) (((c & 0xff) << 8) | (f & 0xff))
++
++/* SDIO register */
++#define SDIO_SYS_ADDR_LOW			0x000
++#define SDIO_SYS_ADDR_HI			0x004
++#define SDIO_BLK_SIZE				0x008
++#define SDIO_BLK_COUNT				0x00c
++#define SDIO_ARG_LOW				0x010
++#define SDIO_ARG_HI					0x014
++#define SDIO_XFER_MODE				0x018
++#define SDIO_CMD					0x01c
++#define SDIO_RSP(i)					(0x020 + ((i)<<2))
++#define SDIO_RSP0					0x020
++#define SDIO_RSP1					0x024
++#define SDIO_RSP2					0x028
++#define SDIO_RSP3					0x02c
++#define SDIO_RSP4					0x030
++#define SDIO_RSP5					0x034
++#define SDIO_RSP6					0x038
++#define SDIO_RSP7					0x03c
++#define SDIO_BUF_DATA_PORT			0x040
++#define SDIO_RSVED					0x044
++#define SDIO_HW_STATE				0x048
++#define SDIO_PRESENT_STATE0			0x048
++#define SDIO_PRESENT_STATE1			0x04c
++#define SDIO_HOST_CTRL				0x050
++#define SDIO_BLK_GAP_CTRL			0x054
++#define SDIO_CLK_CTRL				0x058
++#define SDIO_SW_RESET				0x05c
++#define SDIO_NOR_INTR_STATUS		0x060
++#define SDIO_ERR_INTR_STATUS		0x064
++#define SDIO_NOR_STATUS_EN			0x068
++#define SDIO_ERR_STATUS_EN			0x06c
++#define SDIO_NOR_INTR_EN			0x070
++#define SDIO_ERR_INTR_EN			0x074
++#define SDIO_AUTOCMD12_ERR_STATUS	0x078
++#define SDIO_CURR_BYTE_LEFT			0x07c
++#define SDIO_CURR_BLK_LEFT			0x080
++#define SDIO_AUTOCMD12_ARG_LOW		0x084
++#define SDIO_AUTOCMD12_ARG_HI		0x088
++#define SDIO_AUTOCMD12_INDEX		0x08c
++#define SDIO_AUTO_RSP(i)			(0x090 + ((i)<<2))
++#define SDIO_AUTO_RSP0				0x090
++#define SDIO_AUTO_RSP1				0x094
++#define SDIO_AUTO_RSP2				0x098
++#define SDIO_CLK_DIV				0x128
++
++#define WINDOW_CTRL(i)				(0x108 + ((i) << 3))
++#define WINDOW_BASE(i)				(0x10c + ((i) << 3))
++
++/* SDIO_PRESENT_STATE */
++#define CARD_BUSY				(1 << 1)
++#define CMD_INHIBIT				(1 << 0)
++#define CMD_TXACTIVE			(1 << 8)
++#define CMD_RXACTIVE			(1 << 9)
++#define CMD_AUTOCMD12ACTIVE		(1 << 14)
++#define CMD_BUS_BUSY			(CMD_AUTOCMD12ACTIVE |	\
++								CMD_RXACTIVE |	\
++								CMD_TXACTIVE |	\
++								CMD_INHIBIT |	\
++								CARD_BUSY)
++
++/*
++ * SDIO_CMD
++ */
++
++#define SDIO_CMD_RSP_NONE				(0 << 0)
++#define SDIO_CMD_RSP_136				(1 << 0)
++#define SDIO_CMD_RSP_48					(2 << 0)
++#define SDIO_CMD_RSP_48BUSY				(3 << 0)
++
++#define SDIO_CMD_CHECK_DATACRC16		(1 << 2)
++#define SDIO_CMD_CHECK_CMDCRC			(1 << 3)
++#define SDIO_CMD_INDX_CHECK				(1 << 4)
++#define SDIO_CMD_DATA_PRESENT			(1 << 5)
++#define SDIO_UNEXPECTED_RESP			(1 << 7)
++
++#define SDIO_CMD_INDEX(x)				((x) << 8)
++
++/*
++ * SDIO_XFER_MODE
++ */
++
++#define SDIO_XFER_MODE_STOP_CLK			(1 << 5)
++#define SDIO_XFER_MODE_HW_WR_DATA_EN	(1 << 1)
++#define SDIO_XFER_MODE_AUTO_CMD12		(1 << 2)
++#define SDIO_XFER_MODE_INT_CHK_EN		(1 << 3)
++#define SDIO_XFER_MODE_TO_HOST			(1 << 4)
++#define SDIO_XFER_MODE_DMA				(0 << 6)
++
++/*
++ * SDIO_HOST_CTRL
++ */
++
++#define SDIO_HOST_CTRL_PUSH_PULL_EN 		(1 << 0)
++
++#define SDIO_HOST_CTRL_CARD_TYPE_MEM_ONLY 	(0 << 1)
++#define SDIO_HOST_CTRL_CARD_TYPE_IO_ONLY 	(1 << 1)
++#define SDIO_HOST_CTRL_CARD_TYPE_IO_MEM_COMBO 	(2 << 1)
++#define SDIO_HOST_CTRL_CARD_TYPE_IO_MMC 	(3 << 1)
++#define SDIO_HOST_CTRL_CARD_TYPE_MASK	 	(3 << 1)
++
++#define SDIO_HOST_CTRL_BIG_ENDIAN 		(1 << 3)
++#define SDIO_HOST_CTRL_LSB_FIRST 		(1 << 4)
++#define SDIO_HOST_CTRL_DATA_WIDTH_1_BIT 	(0 << 9)
++#define SDIO_HOST_CTRL_DATA_WIDTH_4_BITS 	(1 << 9)
++#define SDIO_HOST_CTRL_HI_SPEED_EN 		(1 << 10)
++
++#define SDIO_HOST_CTRL_TMOUT_MAX 		0xf
++#define SDIO_HOST_CTRL_TMOUT_MASK 		(0xf << 11)
++#define SDIO_HOST_CTRL_TMOUT(x) 		((x) << 11)
++#define SDIO_HOST_CTRL_TMOUT_EN 		(1 << 15)
++
++/*
++ * SDIO_SW_RESET
++ */
++
++#define SDIO_SW_RESET_NOW			(1 << 8)
++
++/*
++ * Normal interrupt status bits
++ */
++
++#define SDIO_NOR_ERROR				(1 << 15)
++#define SDIO_NOR_UNEXP_RSP			(1 << 14)
++#define SDIO_NOR_AUTOCMD12_DONE		(1 << 13)
++#define SDIO_NOR_SUSPEND_ON			(1 << 12)
++#define SDIO_NOR_LMB_FF_8W_AVAIL	(1 << 11)
++#define SDIO_NOR_LMB_FF_8W_FILLED	(1 << 10)
++#define SDIO_NOR_READ_WAIT_ON		(1 << 9)
++#define SDIO_NOR_CARD_INT			(1 << 8)
++#define SDIO_NOR_READ_READY			(1 << 5)
++#define SDIO_NOR_WRITE_READY		(1 << 4)
++#define SDIO_NOR_DMA_INI			(1 << 3)
++#define SDIO_NOR_BLK_GAP_EVT		(1 << 2)
++#define SDIO_NOR_XFER_DONE			(1 << 1)
++#define SDIO_NOR_CMD_DONE			(1 << 0)
++
++/*
++ * Error status bits
++ */
++
++#define SDIO_ERR_CRC_STATUS			(1 << 14)
++#define SDIO_ERR_CRC_STARTBIT		(1 << 13)
++#define SDIO_ERR_CRC_ENDBIT			(1 << 12)
++#define SDIO_ERR_RESP_TBIT			(1 << 11)
++#define SDIO_ERR_XFER_SIZE			(1 << 10)
++#define SDIO_ERR_CMD_STARTBIT		(1 << 9)
++#define SDIO_ERR_AUTOCMD12			(1 << 8)
++#define SDIO_ERR_DATA_ENDBIT		(1 << 6)
++#define SDIO_ERR_DATA_CRC			(1 << 5)
++#define SDIO_ERR_DATA_TIMEOUT		(1 << 4)
++#define SDIO_ERR_CMD_INDEX			(1 << 3)
++#define SDIO_ERR_CMD_ENDBIT			(1 << 2)
++#define SDIO_ERR_CMD_CRC			(1 << 1)
++#define SDIO_ERR_CMD_TIMEOUT		(1 << 0)
++#define SDIO_POLL_MASK 				0xffff /* enable all for polling */
++
++#define MMC_BLOCK_SIZE                  512
++
++/*
++ * CMD12 error status bits
++ */
++
++#define SDIO_AUTOCMD12_ERR_NOTEXE		(1 << 0)
++#define SDIO_AUTOCMD12_ERR_TIMEOUT		(1 << 1)
++#define SDIO_AUTOCMD12_ERR_CRC			(1 << 2)
++#define SDIO_AUTOCMD12_ERR_ENDBIT		(1 << 3)
++#define SDIO_AUTOCMD12_ERR_INDEX		(1 << 4)
++#define SDIO_AUTOCMD12_ERR_RESP_T_BIT		(1 << 5)
++#define SDIO_AUTOCMD12_ERR_RESP_STARTBIT	(1 << 6)
++
++#define MMC_RSP_PRESENT	(1 << 0)
++#define MMC_RSP_136	(1 << 1)		/* 136 bit response */
++#define MMC_RSP_CRC	(1 << 2)		/* expect valid crc */
++#define MMC_RSP_BUSY	(1 << 3)		/* card may send busy */
++#define MMC_RSP_OPCODE	(1 << 4)		/* response contains opcode */
++
++#define MMC_BUSMODE_OPENDRAIN	1
++#define MMC_BUSMODE_PUSHPULL	2
++
++#define MMC_BUS_WIDTH_1		0
++#define MMC_BUS_WIDTH_4		2
++#define MMC_BUS_WIDTH_8		3
++
++#define MMC_CAP_4_BIT_DATA	(1 << 0)	/* Can the host do 4 bit transfers */
++#define MMC_CAP_MMC_HIGHSPEED	(1 << 1)	/* Can do MMC high-speed timing */
++#define MMC_CAP_SD_HIGHSPEED	(1 << 2)	/* Can do SD high-speed timing */
++#define MMC_CAP_SDIO_IRQ	(1 << 3)	/* Can signal pending SDIO IRQs */
++#define MMC_CAP_SPI		(1 << 4)	/* Talks only SPI protocols */
++#define MMC_CAP_NEEDS_POLL	(1 << 5)	/* Needs polling for card-detection */
++#define MMC_CAP_8_BIT_DATA	(1 << 6)	/* Can the host do 8 bit transfers */
++
++#define MMC_CAP_NONREMOVABLE	(1 << 8)	/* Nonremovable e.g. eMMC */
++#define MMC_CAP_WAIT_WHILE_BUSY	(1 << 9)	/* Waits while card is busy */
++#define MMC_CAP_ERASE		(1 << 10)	/* Allow erase/trim commands */
++#define MMC_CAP_1_8V_DDR	(1 << 11)	/* can support */
++						/* DDR mode at 1.8V */
++#define MMC_CAP_1_2V_DDR	(1 << 12)	/* can support */
++						/* DDR mode at 1.2V */
++#define MMC_CAP_POWER_OFF_CARD	(1 << 13)	/* Can power off after boot */
++#define MMC_CAP_BUS_WIDTH_TEST	(1 << 14)	/* CMD14/CMD19 bus width ok */
++#define MMC_CAP_UHS_SDR12	(1 << 15)	/* Host supports UHS SDR12 mode */
++#define MMC_CAP_UHS_SDR25	(1 << 16)	/* Host supports UHS SDR25 mode */
++#define MMC_CAP_UHS_SDR50	(1 << 17)	/* Host supports UHS SDR50 mode */
++#define MMC_CAP_UHS_SDR104	(1 << 18)	/* Host supports UHS SDR104 mode */
++#define MMC_CAP_UHS_DDR50	(1 << 19)	/* Host supports UHS DDR50 mode */
++#define MMC_CAP_DRIVER_TYPE_A	(1 << 23)	/* Host supports Driver Type A */
++#define MMC_CAP_DRIVER_TYPE_C	(1 << 24)	/* Host supports Driver Type C */
++#define MMC_CAP_DRIVER_TYPE_D	(1 << 25)	/* Host supports Driver Type D */
++#define MMC_CAP_CMD23		(1 << 30)	/* CMD23 supported. */
++#define MMC_CAP_HW_RESET	(1 << 31)	/* Hardware reset */
++
++/*
++ * Functions prototypes
++ *
++ * Original patch had static function declarations in this header file.
++ * Those should rather not be declared in the header as they only cause compiler warnings.
++ */
++int kw_mmc_initialize(bd_t *bis);
++
++#endif /* __KIRKWOOD_MMC_H__ */
diff --git a/package/boot/uboot-kirkwood/patches/110-dockstar.patch b/package/boot/uboot-kirkwood/patches/110-dockstar.patch
new file mode 100644
index 0000000..b383795
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/110-dockstar.patch
@@ -0,0 +1,57 @@
+--- a/include/configs/dockstar.h
++++ b/include/configs/dockstar.h
+@@ -17,6 +17,7 @@
+ #define CONFIG_FEROCEON_88FR131	1	/* CPU Core subversion */
+ #define CONFIG_KW88F6281	1	/* SOC Name */
+ #define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
++#define CONFIG_SYS_MVFS
+
+ /*
+  * mv-common.h should be defined after CMD configs since it used them
+@@ -37,19 +38,15 @@
+  */
+ #define CONFIG_BOOTCOMMAND \
+ 	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; "	\
+-	"ubi part root; " \
+-	"ubifsmount ubi:root; " \
+-	"ubifsload 0x800000 ${kernel}; " \
+-	"ubifsload 0x1100000 ${initrd}; " \
+-	"bootm 0x800000 0x1100000"
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+-	"console=console=ttyS0,115200\0" \
+-	"mtdids=nand0=orion_nand\0" \
+-	"mtdparts="CONFIG_MTDPARTS_DEFAULT \
+-	"kernel=/boot/uImage\0" \
+-	"initrd=/boot/uInitrd\0" \
+-	"bootargs_root=ubi.mtd=1 root=ubi0:root rootfstype=ubifs ro\0"
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
+
+ /*
+  * Ethernet Driver configuration
+--- a/configs/dockstar_defconfig
++++ b/configs/dockstar_defconfig
+@@ -5,7 +5,7 @@ CONFIG_KIRKWOOD=y
+ CONFIG_SYS_TEXT_BASE=0x600000
+ CONFIG_TARGET_DOCKSTAR=y
+ CONFIG_ENV_SIZE=0x20000
+-CONFIG_ENV_OFFSET=0x80000
++CONFIG_ENV_OFFSET=0xE0000
+ CONFIG_NR_DRAM_BANKS=2
+ CONFIG_IDENT_STRING="\nSeagate FreeAgent DockStar"
+ CONFIG_BOOTDELAY=3
+@@ -23,7 +23,7 @@ CONFIG_CMD_EXT2=y
+ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
+-CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:1m(uboot),-(root)"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),0x100000@0x100000(second_stage_uboot),-@0x200000(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_OF_CONTROL=y
diff --git a/package/boot/uboot-kirkwood/patches/120-iconnect.patch b/package/boot/uboot-kirkwood/patches/120-iconnect.patch
new file mode 100644
index 0000000..770a52f
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/120-iconnect.patch
@@ -0,0 +1,51 @@
+--- a/include/configs/iconnect.h
++++ b/include/configs/iconnect.h
+@@ -44,17 +44,15 @@
+  */
+ #define CONFIG_BOOTCOMMAND \
+ 	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; "	\
+-	"ubi part rootfs; "						\
+-	"ubifsmount ubi:rootfs; "					\
+-	"ubifsload 0x800000 ${kernel}; "				\
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
+ 	"bootm 0x800000"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+ 	"console=console=ttyS0,115200\0"	\
+ 	"mtdids=nand0=orion_nand\0"		\
+-	"mtdparts="CONFIG_MTDPARTS_DEFAULT	\
+-	"kernel=/boot/uImage\0"			\
+-	"bootargs_root=noinitrd ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs\0"
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
+
+ /*
+  * Ethernet driver configuration
+--- a/configs/iconnect_defconfig
++++ b/configs/iconnect_defconfig
+@@ -5,7 +5,7 @@ CONFIG_KIRKWOOD=y
+ CONFIG_SYS_TEXT_BASE=0x600000
+ CONFIG_TARGET_ICONNECT=y
+ CONFIG_ENV_SIZE=0x20000
+-CONFIG_ENV_OFFSET=0x80000
++CONFIG_ENV_OFFSET=0xE0000
+ CONFIG_NR_DRAM_BANKS=2
+ CONFIG_IDENT_STRING=" Iomega iConnect"
+ CONFIG_BOOTDELAY=3
+@@ -16,13 +16,14 @@ CONFIG_SYS_PROMPT="iconnect => "
+ CONFIG_CMD_NAND=y
+ CONFIG_CMD_USB=y
+ # CONFIG_CMD_SETEXPR is not set
++CONFIG_CMD_DHCP=y
+ CONFIG_CMD_MII=y
+ CONFIG_CMD_PING=y
+ CONFIG_CMD_EXT2=y
+ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
+-CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0x80000@0x0(uboot),0x20000@0x80000(uboot_env),-@0xa0000(rootfs)"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),0x100000@0x100000(second_stage_uboot),-@0x200000(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_OF_CONTROL=y
diff --git a/package/boot/uboot-kirkwood/patches/130-ib62x0.patch b/package/boot/uboot-kirkwood/patches/130-ib62x0.patch
new file mode 100644
index 0000000..0092d98
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/130-ib62x0.patch
@@ -0,0 +1,40 @@
+--- a/include/configs/ib62x0.h
++++ b/include/configs/ib62x0.h
+@@ -39,21 +39,15 @@
+  */
+ #define CONFIG_BOOTCOMMAND \
+ 	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; "	\
+-	"ubi part root; "						\
+-	"ubifsmount ubi:rootfs; "					\
+-	"ubifsload 0x800000 ${kernel}; "				\
+-	"ubifsload 0x700000 ${fdt}; "					\
+-	"ubifsumount; "							\
+-	"fdt addr 0x700000; fdt resize; fdt chosen; "			\
+-	"bootz 0x800000 - 0x700000"
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+ 	"console=console=ttyS0,115200\0"				\
+ 	"mtdids=nand0=orion_nand\0"					\
+-	"mtdparts="CONFIG_MTDPARTS_DEFAULT			\
+-	"kernel=/boot/zImage\0"						\
+-	"fdt=/boot/ib62x0.dtb\0"					\
+-	"bootargs_root=ubi.mtd=2 root=ubi0:rootfs rootfstype=ubifs rw\0"
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"			\
++	"bootargs_root=\0"
+
+ /*
+  * Ethernet driver configuration
+--- a/configs/ib62x0_defconfig
++++ b/configs/ib62x0_defconfig
+@@ -26,7 +26,7 @@ CONFIG_CMD_EXT2=y
+ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
+-CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),-@0x100000(root)"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),0x100000@0x100000(second_stage_uboot),-@0x200000(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_OF_CONTROL=y
diff --git a/package/boot/uboot-kirkwood/patches/140-pogoplug_e02.patch b/package/boot/uboot-kirkwood/patches/140-pogoplug_e02.patch
new file mode 100644
index 0000000..d077915
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/140-pogoplug_e02.patch
@@ -0,0 +1,48 @@
+--- a/include/configs/pogo_e02.h
++++ b/include/configs/pogo_e02.h
+@@ -42,17 +42,17 @@
+  * Default environment variables
+  */
+ #define CONFIG_BOOTCOMMAND \
+-	"setenv bootargs $(bootargs_console); " \
+-	"run bootcmd_usb; " \
+-	"bootm 0x00800000 0x01100000"
++	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; "	\
++	"ubi part ubi; "						\
++	"ubifsmount ubi:rootfs; "					\
++	"ubi read 0x800000 kernel; "					\
++	"bootm 0x800000"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+-	"mtdparts=mtdparts=orion_nand:1M(u-boot),4M(uImage)," \
+-	"32M(rootfs),-(data)\0"\
+-	"mtdids=nand0=orion_nand\0"\
+-	"bootargs_console=console=ttyS0,115200\0" \
+-	"bootcmd_usb=usb start; ext2load usb 0:1 0x00800000 /uImage; " \
+-	"ext2load usb 0:1 0x01100000 /uInitrd\0"
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
+
+ /*
+  * Ethernet Driver configuration
+--- a/configs/pogo_e02_defconfig
++++ b/configs/pogo_e02_defconfig
+@@ -5,7 +5,7 @@ CONFIG_KIRKWOOD=y
+ CONFIG_SYS_TEXT_BASE=0x600000
+ CONFIG_TARGET_POGO_E02=y
+ CONFIG_ENV_SIZE=0x20000
+-CONFIG_ENV_OFFSET=0x60000
++CONFIG_ENV_OFFSET=0xE0000
+ CONFIG_NR_DRAM_BANKS=2
+ CONFIG_IDENT_STRING="\nPogo E02"
+ CONFIG_BOOTDELAY=3
+@@ -23,6 +23,7 @@ CONFIG_CMD_EXT2=y
+ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),0x100000@0x100000(second_stage_uboot),-@0x200000(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_OF_CONTROL=y
diff --git a/package/boot/uboot-kirkwood/patches/150-goflexhome.patch b/package/boot/uboot-kirkwood/patches/150-goflexhome.patch
new file mode 100644
index 0000000..55d69b8
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/150-goflexhome.patch
@@ -0,0 +1,35 @@
+--- a/include/configs/goflexhome.h
++++ b/include/configs/goflexhome.h
+@@ -60,17 +60,15 @@
+  */
+ #define CONFIG_BOOTCOMMAND \
+ 	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; " \
+-	"ubi part root; " \
+-	"ubifsmount ubi:root; " \
+-	"ubifsload 0x800000 ${kernel}; " \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
+ 	"bootm 0x800000"
+
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+ 	"console=console=ttyS0,115200\0" \
+ 	"mtdids=nand0=orion_nand\0" \
+-	"mtdparts="CONFIG_MTDPARTS_DEFAULT \
+-	"kernel=/boot/uImage\0" \
+-	"bootargs_root=ubi.mtd=root root=ubi0:root rootfstype=ubifs ro\0"
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0" \
++	"bootargs_root=\0"
+
+ /*
+  * Ethernet Driver configuration
+--- a/configs/goflexhome_defconfig
++++ b/configs/goflexhome_defconfig
+@@ -28,7 +28,7 @@ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
+ CONFIG_MTDIDS_DEFAULT="nand0=orion_nand"
+-CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:1m(uboot),6M(uImage),-(root)"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:1m(uboot),255m(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_OF_CONTROL=y
diff --git a/package/boot/uboot-kirkwood/patches/151-arm-kirkwood-add-CheckPoint-L-50-device.patch b/package/boot/uboot-kirkwood/patches/151-arm-kirkwood-add-CheckPoint-L-50-device.patch
new file mode 100644
index 0000000..b228be6
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/151-arm-kirkwood-add-CheckPoint-L-50-device.patch
@@ -0,0 +1,928 @@
+From 742f780f62ace452b83e2463f1f1afdda4b724ea Mon Sep 17 00:00:00 2001
+From: Pawel Dembicki <paweldembicki@gmail.com>
+Date: Sun, 26 Jan 2020 07:27:24 +0100
+Subject: [PATCH] arm: kirkwood: add CheckPoint L-50 device
+
+This patch adds support for the Check Point L-50 from 600/1100 series
+routers.
+
+Specification:
+-CPU: Marvell Kirkwood 88F6821 1200MHz
+-RAM: 512MB
+-Flash: NAND 512MB
+-WiFi: mPCIe card based on Atheros AR9287 b/g/n
+-WAN: 1 Gigabit Port (Marvell 88E1116R PHY)
+-LAN: 9 Gigabit Ports (2x Marvell 88E6171(5+4))
+-USB: 2x USB2.0
+-Express card slot
+-SD card slot
+-Serial console: RJ-45 115200 8n1
+-Unsupported DSL
+
+Known limitations:
+- In board is used two switches in chain. Second Marvell is not used
+  in u-Boot.
+
+Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
+---
+ arch/arm/dts/Makefile              |   1 +
+ arch/arm/dts/kirkwood-l-50.dts     | 439 +++++++++++++++++++++++++++++
+ arch/arm/mach-kirkwood/Kconfig     |   4 +
+ board/checkpoint/l-50/Kconfig      |  12 +
+ board/checkpoint/l-50/MAINTAINERS  |   6 +
+ board/checkpoint/l-50/Makefile     |  11 +
+ board/checkpoint/l-50/kwbimage.cfg |  36 +++
+ board/checkpoint/l-50/l-50.c       | 172 +++++++++++
+ board/checkpoint/l-50/l-50.h       |  29 ++
+ configs/l-50_defconfig             |  59 ++++
+ include/configs/l-50.h             |  59 ++++
+ 11 files changed, 828 insertions(+)
+ create mode 100644 arch/arm/dts/kirkwood-l-50.dts
+ create mode 100644 board/checkpoint/l-50/Kconfig
+ create mode 100644 board/checkpoint/l-50/MAINTAINERS
+ create mode 100644 board/checkpoint/l-50/Makefile
+ create mode 100644 board/checkpoint/l-50/kwbimage.cfg
+ create mode 100644 board/checkpoint/l-50/l-50.c
+ create mode 100644 board/checkpoint/l-50/l-50.h
+ create mode 100644 configs/l-50_defconfig
+ create mode 100644 include/configs/l-50.h
+
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -51,6 +51,7 @@ dtb-$(CONFIG_KIRKWOOD) += \
+ 	kirkwood-iconnect.dtb \
+ 	kirkwood-is2.dtb \
+ 	kirkwood-km_kirkwood.dtb \
++	kirkwood-l-50.dtb \
+ 	kirkwood-lsxhl.dtb \
+ 	kirkwood-lschlv2.dtb \
+ 	kirkwood-net2big.dtb \
+--- /dev/null
++++ b/arch/arm/dts/kirkwood-l-50.dts
+@@ -0,0 +1,439 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Check Point L-50 Board Description
++ * Copyright 2020 Pawel Dembicki <paweldembicki@gmail.com>
++ */
++
++/dts-v1/;
++
++#include "kirkwood.dtsi"
++#include "kirkwood-6281.dtsi"
++
++/ {
++	model = "Check Point L-50";
++	compatible = "checkpoint,l-50", "marvell,kirkwood-88f6281", "marvell,kirkwood";
++
++	memory {
++		device_type = "memory";
++		reg = <0x00000000 0x20000000>;
++	};
++
++	chosen {
++		bootargs = "console=ttyS0,115200n8";
++		stdout-path = &uart0;
++	};
++
++	ocp@f1000000 {
++		pinctrl: pin-controller@10000 {
++			pinctrl-0 = <&pmx_led38 &pmx_sysrst &pmx_button29>;
++			pinctrl-names = "default";
++
++			pmx_sysrst: pmx-sysrst {
++				marvell,pins = "mpp6";
++				marvell,function = "sysrst";
++			};
++
++			pmx_button29: pmx_button29 {
++				marvell,pins = "mpp29";
++				marvell,function = "gpio";
++			};
++
++			pmx_led38: pmx_led38 {
++				marvell,pins = "mpp38";
++				marvell,function = "gpio";
++			};
++
++			pmx_sdio_cd: pmx-sdio-cd {
++				marvell,pins = "mpp46";
++				marvell,function = "gpio";
++			};
++		};
++
++		serial@12000 {
++			status = "okay";
++		};
++
++		mvsdio@90000 {
++			status = "okay";
++			cd-gpios = <&gpio1 14 9>;
++		};
++
++		i2c@11000 {
++			status = "okay";
++			clock-frequency = <400000>;
++
++			gpio2: gpio-expander@20{
++				#gpio-cells = <2>;
++				#interrupt-cells = <2>;
++				compatible = "semtech,sx1505q";
++				reg = <0x20>;
++
++				gpio-controller;
++			};
++
++			/* Three GPIOs from 0x21 exp. are undescribed in dts:
++			 * 1: DSL module reset (active low)
++			 * 5: mPCIE reset (active low)
++			 * 6: Express card reset (active low)
++			 */
++			gpio3: gpio-expander@21{
++				#gpio-cells = <2>;
++				#interrupt-cells = <2>;
++				compatible = "semtech,sx1505q";
++				reg = <0x21>;
++
++				gpio-controller;
++			};
++
++			rtc@30 {
++				compatible = "s35390a";
++				reg = <0x30>;
++			};
++		};
++	};
++
++	leds {
++		compatible = "gpio-leds";
++
++		status_green {
++			label = "l-50:green:status";
++			gpios = <&gpio1 6 GPIO_ACTIVE_LOW>;
++		};
++
++		status_red {
++			label = "l-50:red:status";
++			gpios = <&gpio3 2 GPIO_ACTIVE_LOW>;
++		};
++
++		wifi {
++			label = "l-50:green:wifi";
++			gpios = <&gpio2 7 GPIO_ACTIVE_LOW>;
++			linux,default-trigger = "phy0tpt";
++		};
++
++		internet_green {
++			label = "l-50:green:internet";
++			gpios = <&gpio2 3 GPIO_ACTIVE_LOW>;
++		};
++
++		internet_red {
++			label = "l-50:red:internet";
++			gpios = <&gpio2 1 GPIO_ACTIVE_LOW>;
++		};
++
++		usb1_green {
++			label = "l-50:green:usb1";
++			gpios = <&gpio2 0 GPIO_ACTIVE_LOW>;
++			linux,default-trigger = "usbport";
++			trigger-sources = <&hub_port3>;
++		};
++
++		usb1_red {
++			label = "l-50:red:usb1";
++			gpios = <&gpio2 4 GPIO_ACTIVE_LOW>;
++		};
++
++		usb2_green {
++			label = "l-50:green:usb2";
++			gpios = <&gpio2 2 GPIO_ACTIVE_LOW>;
++			linux,default-trigger = "usbport";
++			trigger-sources = <&hub_port1>;
++		};
++
++		usb2_red {
++			label = "l-50:red:usb2";
++			gpios = <&gpio2 5 GPIO_ACTIVE_LOW>;
++		};
++	};
++
++	usb2_pwr {
++		compatible = "regulator-fixed";
++		regulator-name = "usb2_pwr";
++
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++		gpio = <&gpio3 3 GPIO_ACTIVE_LOW>;
++		regulator-always-on;
++	};
++
++	usb1_pwr {
++		compatible = "regulator-fixed";
++		regulator-name = "usb1_pwr";
++
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++		gpio = <&gpio3 4 GPIO_ACTIVE_LOW>;
++		regulator-always-on;
++	};
++
++	mpcie_pwr {
++		compatible = "regulator-fixed";
++		regulator-name = "mpcie_pwr";
++
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		gpio = <&gpio3 5 GPIO_ACTIVE_HIGH>;
++		enable-active-high;
++		regulator-always-on;
++	};
++
++	express_card_pwr {
++		compatible = "regulator-fixed";
++		regulator-name = "express_card_pwr";
++
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		gpio = <&gpio3 7 GPIO_ACTIVE_HIGH>;
++		enable-active-high;
++		regulator-always-on;
++	};
++
++	keys {
++		compatible = "gpio-keys";
++
++		factory_defaults {
++			label = "factory_defaults";
++			gpios = <&gpio0 29 GPIO_ACTIVE_LOW>;
++			linux,code = <KEY_RESTART>;
++		};
++	};
++};
++
++&mdio {
++	status = "okay";
++
++	ethphy8: ethernet-phy@8 {
++		reg = <0x08>;
++	};
++
++	switch0: switch@10 {
++		compatible = "marvell,mv88e6085";
++		#address-cells = <1>;
++		#size-cells = <0>;
++		reg = <0x10>;
++		dsa,member = <0 0>;
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++				label = "lan5";
++			};
++
++			port@1 {
++			       reg = <1>;
++			       label = "lan1";
++			};
++
++			port@2 {
++			       reg = <2>;
++			       label = "lan6";
++			};
++
++			port@3 {
++			       reg = <3>;
++			       label = "lan2";
++			};
++
++			port@4 {
++				reg = <4>;
++				label = "lan7";
++			};
++
++			switch0port5: port@5 {
++				reg = <5>;
++				phy-mode = "rgmii-txid";
++				link = <&switch1port5>;
++				fixed-link {
++					speed = <1000>;
++					full-duplex;
++				};
++			};
++
++			port@6 {
++				reg = <6>;
++				label = "cpu";
++				phy-mode = "rgmii-id";
++				ethernet = <&eth1port>;
++				fixed-link {
++					speed = <1000>;
++					full-duplex;
++				};
++			};
++		};
++	};
++
++	switch@11 {
++		compatible = "marvell,mv88e6085";
++		#address-cells = <1>;
++		#size-cells = <0>;
++		reg = <0x11>;
++		dsa,member = <0 1>;
++
++		ports {
++			#address-cells = <1>;
++			#size-cells = <0>;
++
++			port@0 {
++				reg = <0>;
++				label = "lan3";
++			};
++
++			port@1 {
++			       reg = <1>;
++			       label = "lan8";
++			};
++
++			port@2 {
++			       reg = <2>;
++			       label = "lan4";
++			};
++
++			port@3 {
++			       reg = <3>;
++			       label = "dmz";
++			};
++
++			switch1port5: port@5 {
++				reg = <5>;
++				phy-mode = "rgmii-txid";
++				link = <&switch0port5>;
++				fixed-link {
++					speed = <1000>;
++					full-duplex;
++				};
++			};
++
++			port@6 {
++				reg = <6>;
++				label = "dsl";
++				fixed-link {
++					speed = <100>;
++					full-duplex;
++				};
++			};
++		};
++	};
++};
++
++&eth0 {
++	status = "okay";
++	ethernet0-port@0 {
++		phy-handle = <&ethphy8>;
++	};
++};
++
++&eth1 {
++	status = "okay";
++	ethernet1-port@0 {
++		speed = <1000>;
++		duplex = <1>;
++		phy-handle = <&switch0>;
++	};
++};
++
++&nand {
++	status = "okay";
++	pinctrl-0 = <&pmx_nand>;
++	pinctrl-names = "default";
++
++	partition@0 {
++		label = "u-boot";
++		reg = <0x00000000 0x000c0000>;
++	};
++
++	partition@a0000 {
++		label = "bootldr-env";
++		reg = <0x000c0000 0x00040000>;
++	};
++
++	partition@100000 {
++		label = "kernel-1";
++		reg = <0x00100000 0x00800000>;
++	};
++
++	partition@900000 {
++		label = "rootfs-1";
++		reg = <0x00900000 0x07100000>;
++	};
++
++	partition@7a00000 {
++		label = "kernel-2";
++		reg = <0x07a00000 0x00800000>;
++	};
++
++	partition@8200000 {
++		label = "rootfs-2";
++		reg = <0x08200000 0x07100000>;
++	};
++
++	partition@f300000 {
++		label = "default_sw";
++		reg = <0x0f300000 0x07900000>;
++	};
++
++	partition@16c00000 {
++		label = "logs";
++		reg = <0x16c00000 0x01800000>;
++	};
++
++	partition@18400000 {
++		label = "preset_cfg";
++		reg = <0x18400000 0x00100000>;
++	};
++
++	partition@18500000 {
++		label = "adsl";
++		reg = <0x18500000 0x00100000>;
++	};
++
++	partition@18600000 {
++		label = "storage";
++		reg = <0x18600000 0x07a00000>;
++	};
++};
++
++&rtc {
++	status = "disabled";
++};
++
++&pciec {
++	status = "okay";
++};
++
++&pcie0 {
++	status = "okay";
++};
++
++&sata_phy0 {
++	status = "disabled";
++};
++
++&sata_phy1 {
++	status = "disabled";
++};
++
++&usb0 {
++	#address-cells = <1>;
++	#size-cells = <0>;
++	status = "okay";
++
++	port@1 {
++		#address-cells = <1>;
++		#size-cells = <0>;
++		reg = <1>;
++		#trigger-source-cells = <0>;
++
++		hub_port1: port@1 {
++			reg = <1>;
++			#trigger-source-cells = <0>;
++		};
++
++		hub_port3: port@3 {
++			reg = <3>;
++			#trigger-source-cells = <0>;
++		};
++	};
++};
+--- a/arch/arm/mach-kirkwood/Kconfig
++++ b/arch/arm/mach-kirkwood/Kconfig
+@@ -74,6 +74,9 @@ config TARGET_DB_88F6281_BP
+ config TARGET_NSA325
+ 	bool "Zyxel NSA325 board"
+ 
++config TARGET_L50
++	bool "Check Point L-50"
++
+ endchoice
+ 
+ config SYS_SOC
+@@ -102,5 +105,6 @@ source "board/zyxel/nsa325/Kconfig"
+ source "board/alliedtelesis/SBx81LIFKW/Kconfig"
+ source "board/alliedtelesis/SBx81LIFXCAT/Kconfig"
+ source "board/Marvell/db-88f6281-bp/Kconfig"
++source "board/checkpoint/l-50/Kconfig"
+ 
+ endif
+--- /dev/null
++++ b/board/checkpoint/l-50/Kconfig
+@@ -0,0 +1,12 @@
++if TARGET_L50
++
++config SYS_BOARD
++	default "l-50"
++
++config SYS_VENDOR
++	default "checkpoint"
++
++config SYS_CONFIG_NAME
++	default "l-50"
++
++endif
+--- /dev/null
++++ b/board/checkpoint/l-50/MAINTAINERS
+@@ -0,0 +1,6 @@
++L50 BOARD
++M:	Pawel Dembicki <paweldembicki@gmail.com>
++S:	Maintained
++F:	board/checkpoint/l-50/
++F:	include/configs/l-50.h
++F:	configs/l-50_defconfig
+--- /dev/null
++++ b/board/checkpoint/l-50/Makefile
+@@ -0,0 +1,11 @@
++# SPDX-License-Identifier: GPL-2.0+
++#
++# (C) Copyright 2020
++# Pawel Dembicki <paweldembicki@gmail.com>
++#
++# Based on Kirkwood support:
++# (C) Copyright 2009
++# Marvell Semiconductor <www.marvell.com>
++# Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++
++obj-y	:= l-50.o
+--- /dev/null
++++ b/board/checkpoint/l-50/kwbimage.cfg
+@@ -0,0 +1,36 @@
++# SPDX-License-Identifier: GPL-2.0+
++#
++# Values taken from original bootloader source.
++# Based on:
++# dramregs_seattle_400rd_A.txt from uboot_src_CP600_1100.
++
++# Boot Media configurations
++BOOT_FROM	nand
++NAND_ECC_MODE	default
++NAND_PAGE_SIZE	0x0800
++
++DATA 0xFFD100e0 0x1b1b1b9b
++DATA 0xFFD01400 0x43000c30
++DATA 0xFFD01404 0x39543000
++DATA 0xFFD01408 0x22125451
++DATA 0xFFD0140C 0x00000833
++DATA 0xFFD01410 0x000000cc
++DATA 0xFFD01414 0x00000000
++DATA 0xFFD01418 0x00000000
++DATA 0xFFD0141C 0x00000C52
++DATA 0xFFD01420 0x00000004
++DATA 0xFFD01424 0x0000F17F
++DATA 0xFFD01428 0x00085520
++DATA 0xFFD0147C 0x00008552
++DATA 0xFFD01504 0x0FFFFFF1
++DATA 0xFFD01508 0x10000000
++DATA 0xFFD0150C 0x0FFFFFF5
++DATA 0xFFD01514 0x00000000
++DATA 0xFFD0151C 0x00000000
++DATA 0xFFD01494 0x00120012
++DATA 0xFFD01498 0x00000000
++DATA 0xFFD0149C 0x0000E40F
++DATA 0xFFD01480 0x00000001
++DATA 0xFFD20134 0x66666666
++DATA 0xFFD20138 0x66666666
++DATA 0x0 0x0
+--- /dev/null
++++ b/board/checkpoint/l-50/l-50.c
+@@ -0,0 +1,172 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2020
++ * Pawel Dembicki <paweldembicki@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ */
++
++#include <common.h>
++#include <dm.h>
++#include <i2c.h>
++#include <miiphy.h>
++#include <netdev.h>
++#include <asm/arch/cpu.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/mpp.h>
++#include <asm/arch/gpio.h>
++#include "l-50.h"
++
++DECLARE_GLOBAL_DATA_PTR;
++
++int board_early_init_f(void)
++{
++	/* Gpio configuration */
++	mvebu_config_gpio(L50_OE_VAL_LOW, L50_OE_VAL_HIGH,
++			  L50_OE_LOW, L50_OE_HIGH);
++
++	/* Multi-Purpose Pins Functionality configuration */
++	static const u32 kwmpp_config[] = {
++		MPP0_NF_IO2,
++		MPP1_NF_IO3,
++		MPP2_NF_IO4,
++		MPP3_NF_IO5,
++		MPP4_NF_IO6,
++		MPP5_NF_IO7,
++		MPP6_SYSRST_OUTn,
++		MPP7_SPI_SCn,
++		MPP8_TW_SDA,
++		MPP9_TW_SCK,
++		MPP10_UART0_TXD,
++		MPP11_UART0_RXD,
++		MPP12_SD_CLK,
++		MPP13_SD_CMD,
++		MPP14_SD_D0,
++		MPP15_SD_D1,
++		MPP16_SD_D2,
++		MPP17_SD_D3,
++		MPP18_NF_IO0,
++		MPP19_NF_IO1,
++		MPP20_GE1_0,
++		MPP21_GE1_1,
++		MPP22_GE1_2,
++		MPP23_GE1_3,
++		MPP24_GE1_4,
++		MPP25_GE1_5,
++		MPP26_GE1_6,
++		MPP27_GE1_7,
++		MPP28_GPIO,
++		MPP29_GPIO,
++		MPP30_GE1_10,
++		MPP31_GE1_11,
++		MPP32_GE1_12,
++		MPP33_GE1_13,
++		MPP34_GPIO,
++		MPP35_GPIO,
++		MPP36_AUDIO_SPDIFI,	/* value from stock u-boot */
++		MPP37_GPIO,
++		MPP38_GPIO,
++		MPP39_TDM_SPI_CS0,
++		MPP40_GPIO,
++		MPP41_GPIO,
++		MPP42_TDM_SPI_MOSI,
++		MPP43_TDM_CODEC_INTn,
++		MPP44_GPIO,
++		MPP45_TDM_PCLK,
++		MPP46_GPIO,
++		MPP47_TDM_DRX,
++		MPP48_GPIO,
++		MPP49_GPIO,
++		0
++	};
++	kirkwood_mpp_conf(kwmpp_config, NULL);
++
++	return 0;
++}
++
++void board_gpio_expander_init(void)
++{
++	struct udevice *dev0, *dev1;
++	uchar data_buffer;
++	int ret;
++
++	ret = i2c_get_chip_for_busnum(0, L50_GPIO0_I2C_ADDRESS, 1, &dev0);
++	if (ret) {
++		debug("%s: Cannot find I2C GPIO expander chip 0x02%X\n",
++		      __func__, L50_GPIO0_I2C_ADDRESS);
++		return;
++	}
++
++	ret = i2c_get_chip_for_busnum(0, L50_GPIO1_I2C_ADDRESS, 1, &dev1);
++	if (ret) {
++		debug("%s: Cannot find I2C GPIO expander chip 0x02%X\n",
++		      __func__, L50_GPIO1_I2C_ADDRESS);
++		return;
++	}
++
++	/* Set IO as output */
++	data_buffer = 0x0;
++	dm_i2c_write(dev0, 1, &data_buffer, 1);
++	dm_i2c_write(dev1, 1, &data_buffer, 1);
++
++	/* Set all leds off, reset asserted, pwr off */
++	data_buffer = 0xbf;
++	dm_i2c_write(dev0, 0, &data_buffer, 1);
++	data_buffer = 0x1c;
++	dm_i2c_write(dev1, 0, &data_buffer, 1);
++
++	mdelay(100);
++
++	/* Set pwr on */
++	data_buffer = 0xa5;
++	dm_i2c_write(dev1, 0, &data_buffer, 1);
++
++	mdelay(100);
++
++	/* Set reset deasserted, status red led enabled*/
++	data_buffer = 0xff;
++	dm_i2c_write(dev0, 0, &data_buffer, 1);
++	data_buffer = 0xe3;
++	dm_i2c_write(dev1, 0, &data_buffer, 1);
++}
++
++int board_init(void)
++{
++	/* Boot parameters address */
++	gd->bd->bi_boot_params = mvebu_sdram_bar(0) + 0x100;
++
++	board_gpio_expander_init();
++
++	return 0;
++}
++
++#ifdef CONFIG_RESET_PHY_R
++/* Configure and initialize PHY */
++void reset_phy(void)
++{
++	u16 devadr;
++	char *name = "ethernet-controller@72000";
++
++	if (miiphy_set_current_dev(name))
++		return;
++
++	/* command to read PHY dev address */
++	if (miiphy_read(name, 0xEE, 0xEE, (u16 *)&devadr)) {
++		printf("Err..(%s) could not read PHY dev address\n", __func__);
++		return;
++	}
++
++	/*
++	 * Fix PHY led configuration
++	 */
++	miiphy_write(name, devadr, MV88E1116_PGADR_REG, 3);
++	miiphy_write(name, devadr, 0x10, 0x1177);
++	miiphy_write(name, devadr, 0x11, 0x4417);
++	miiphy_write(name, devadr, MV88E1116_PGADR_REG, 0);
++
++	debug("88E1116 Initialized on %s\n", name);
++}
++#endif /* CONFIG_RESET_PHY_R */
+--- /dev/null
++++ b/board/checkpoint/l-50/l-50.h
+@@ -0,0 +1,29 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2020
++ * Pawel Dembicki <paweldembicki@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ */
++
++#ifndef __L50_H
++#define __L50_H
++
++/* GPIO configuration */
++#define L50_OE_LOW			0x30000000
++#define L50_OE_HIGH			0x0000004c
++#define L50_OE_VAL_LOW		0x00000000
++#define L50_OE_VAL_HIGH		0x00000000
++
++/* Expander GPIO addresses */
++
++#define L50_GPIO0_I2C_ADDRESS		0x20
++#define L50_GPIO1_I2C_ADDRESS		0x21
++
++/* PHY register */
++#define MV88E1116_PGADR_REG		22
++
++#endif /* __L50_H */
+--- /dev/null
++++ b/configs/l-50_defconfig
+@@ -0,0 +1,59 @@
++CONFIG_ARM=y
++CONFIG_SYS_DCACHE_OFF=y
++CONFIG_ARCH_CPU_INIT=y
++CONFIG_KIRKWOOD=y
++CONFIG_SYS_TEXT_BASE=0x600000
++CONFIG_TARGET_L50=y
++CONFIG_ENV_SIZE=0x20000
++CONFIG_ENV_OFFSET=0xC0000
++CONFIG_ENV_SECT_SIZE=0x20000
++CONFIG_ENV_ADDR=0xC0000
++CONFIG_IDENT_STRING="\nCheck Point L-50"
++CONFIG_NR_DRAM_BANKS=2
++# CONFIG_SYS_MALLOC_F is not set
++CONFIG_BOOTDELAY=1
++CONFIG_CONSOLE_MUX=y
++CONFIG_DISPLAY_BOARDINFO=y
++CONFIG_HUSH_PARSER=y
++# CONFIG_CMD_FLASH is not set
++#CONFIG_CMD_IDE=y
++CONFIG_CMD_I2C=y
++CONFIG_CMD_NAND=y
++CONFIG_CMD_USB=y
++# CONFIG_CMD_SETEXPR is not set
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_EXT2=y
++CONFIG_CMD_FAT=y
++CONFIG_CMD_JFFS2=y
++CONFIG_CMD_MTDPARTS=y
++CONFIG_MTD=y
++CONFIG_MTD_RAW_NAND=y
++CONFIG_MTDIDS_DEFAULT="nand0=orion_nand"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xc0000@0x0(u-boot)ro,0x40000@0xc0000(bootldr-env),0x7900000@0x100000(ubi),0x800000@0x7a00000(kernel-2),0x7100000@0x8200000(rootfs-2),0x7900000@0xf300000(default_sw),0x1800000@0x16c00000(logs),0x100000@0x18400000(preset_cfg),0x100000@0x18500000(adsl),-@0x18600000(storage)"
++CONFIG_CMD_UBI=y
++CONFIG_ISO_PARTITION=y
++CONFIG_OF_CONTROL=y
++CONFIG_DEFAULT_DEVICE_TREE="kirkwood-l-50"
++CONFIG_ENV_IS_IN_NAND=y
++CONFIG_DM=y
++CONFIG_DM_ETH=y
++#CONFIG_MVSATA_IDE=y
++CONFIG_MMC=y
++CONFIG_MVGBE=y
++CONFIG_MII=y
++CONFIG_PHYLIB=y
++CONFIG_PHY_MARVELL=y
++CONFIG_MV88E61XX_SWITCH=y
++CONFIG_MV88E61XX_CPU_PORT=6
++CONFIG_MV88E61XX_PHY_PORTS=0x01f
++CONFIG_MV88E61XX_FIXED_PORTS=0
++#CONFIG_DM_RTC=y
++#CONFIG_RTC_MV=y
++CONFIG_SYS_NS16550=y
++CONFIG_DM_I2C=y
++CONFIG_SYS_I2C_MVTWSI=y
++CONFIG_USB=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_STORAGE=y
+--- /dev/null
++++ b/include/configs/l-50.h
+@@ -0,0 +1,59 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2020
++ * Pawel Dembicki <paweldembicki@gmail.com>
++ *
++ * Based on Kirkwood support:
++ * (C) Copyright 2009
++ * Marvell Semiconductor <www.marvell.com>
++ * Written-by: Prafulla Wadaskar <prafulla@marvell.com>
++ */
++
++#ifndef _CONFIG_L50_H
++#define _CONFIG_L50_H
++
++/*
++ * High Level Configuration Options (easy to change)
++ */
++#define CONFIG_FEROCEON_88FR131		/* CPU Core subversion */
++#define CONFIG_KW88F6281		/* SOC Name */
++#define CONFIG_SKIP_LOWLEVEL_INIT	/* disable board lowlevel_init */
++
++/*
++ * mv-common.h should be defined after CMD configs since it used them
++ * to enable certain macros
++ */
++#include "mv-common.h"
++
++/* Remove or override few declarations from mv-common.h */
++
++/*
++ * Ethernet Driver configuration
++ */
++#ifdef CONFIG_CMD_NET
++#define CONFIG_MVGBE_PORTS		{1, 1} /* enable port 0 only */
++#define CONFIG_NETCONSOLE
++#endif
++
++#define CONFIG_MV88E61XX_CPU_PORT_RX_DELAY
++#define CONFIG_MV88E61XX_CPU_PORT_TX_DELAY
++
++/*
++ * Enable GPI0 support
++ */
++#define CONFIG_KIRKWOOD_GPIO
++
++/*
++ * Default environment variables
++ */
++#define CONFIG_BOOTCOMMAND \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"bootargs=console=ttyS0,115200\0"	\
++	"mtdids=" CONFIG_MTDIDS_DEFAULT "\0"	\
++	"mtdparts=" CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
++#endif /* _CONFIG_L50_H */
diff --git a/package/boot/uboot-kirkwood/patches/160-nsa310s.patch b/package/boot/uboot-kirkwood/patches/160-nsa310s.patch
new file mode 100644
index 0000000..fe0cd3f
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/160-nsa310s.patch
@@ -0,0 +1,54 @@
+--- a/configs/nsa310s_defconfig
++++ b/configs/nsa310s_defconfig
+@@ -5,7 +5,7 @@ CONFIG_KIRKWOOD=y
+ CONFIG_SYS_TEXT_BASE=0x600000
+ CONFIG_TARGET_NSA310S=y
+ CONFIG_ENV_SIZE=0x20000
+-CONFIG_ENV_OFFSET=0xE0000
++CONFIG_ENV_OFFSET=0xC0000
+ CONFIG_NR_DRAM_BANKS=2
+ CONFIG_BOOTDELAY=3
+ CONFIG_USE_PREBOOT=y
+@@ -25,7 +25,7 @@ CONFIG_CMD_EXT2=y
+ CONFIG_CMD_FAT=y
+ CONFIG_CMD_JFFS2=y
+ CONFIG_CMD_MTDPARTS=y
+-CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xe0000@0x0(uboot),0x20000@0xe0000(uboot_env),0x100000@0x100000(second_stage_uboot),-@0x200000(root)"
++CONFIG_MTDPARTS_DEFAULT="mtdparts=orion_nand:0xc0000@0x0(uboot),0x80000@0xc0000(uboot_env),-@0x140000(ubi)"
+ CONFIG_CMD_UBI=y
+ CONFIG_ISO_PARTITION=y
+ CONFIG_ENV_IS_IN_NAND=y
+--- a/include/configs/nsa310s.h
++++ b/include/configs/nsa310s.h
+@@ -30,22 +30,17 @@
+ 
+ /* default environment variables */
+ #define CONFIG_BOOTCOMMAND \
+-	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; " \
+-	"ubi part root; " \
+-	"ubifsmount ubi:rootfs; " \
+-	"ubifsload 0x800000 ${kernel}; " \
+-	"ubifsload 0x700000 ${fdt}; " \
+-	"ubifsumount; " \
+-	"fdt addr 0x700000; fdt resize; fdt chosen; " \
+-	"bootz 0x800000 - 0x700000"
++	"setenv bootargs ${console} ${mtdparts} ${bootargs_root}; "	\
++	"ubi part ubi; "						\
++	"ubifsmount ubi:rootfs; "					\
++	"ubi read 0x800000 kernel; "					\
++	"bootm 0x800000"
+ 
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+-	"console=console=ttyS0,115200\0" \
+-	"mtdids=nand0=orion_nand\0" \
+-	"mtdparts="CONFIG_MTDPARTS_DEFAULT \
+-	"kernel=/boot/zImage\0" \
+-	"fdt=/boot/nsa310s.dtb\0" \
+-	"bootargs_root=ubi.mtd=3 root=ubi0:rootfs rootfstype=ubifs rw\0"
++	"console=console=ttyS0,115200\0"	\
++	"mtdids=nand0=orion_nand\0"		\
++	"mtdparts="CONFIG_MTDPARTS_DEFAULT "\0"	\
++	"bootargs_root=\0"
+ 
+ /* Ethernet driver configuration */
+ #ifdef CONFIG_CMD_NET
diff --git a/package/boot/uboot-kirkwood/patches/200-openwrt-config.patch b/package/boot/uboot-kirkwood/patches/200-openwrt-config.patch
new file mode 100644
index 0000000..83eb0f9
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/200-openwrt-config.patch
@@ -0,0 +1,206 @@
+--- a/arch/arm/mach-kirkwood/Kconfig
++++ b/arch/arm/mach-kirkwood/Kconfig
+@@ -107,4 +107,7 @@ source "board/alliedtelesis/SBx81LIFXCAT
+ source "board/Marvell/db-88f6281-bp/Kconfig"
+ source "board/checkpoint/l-50/Kconfig"
+
++config SECOND_STAGE
++	bool "OpenWrt second stage hack"
++
+ endif
+--- a/include/configs/dockstar.h
++++ b/include/configs/dockstar.h
+@@ -60,4 +60,6 @@
+  * File system
+  */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_DOCKSTAR_H */
+--- a/include/configs/ib62x0.h
++++ b/include/configs/ib62x0.h
+@@ -77,4 +77,6 @@
+ #define CONFIG_RTC_MV
+ #endif /* CONFIG_CMD_DATE */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_IB62x0_H */
+--- a/include/configs/iconnect.h
++++ b/include/configs/iconnect.h
+@@ -67,4 +67,6 @@
+  * File system
+  */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_ICONNECT_H */
+--- a/include/configs/l-50.h
++++ b/include/configs/l-50.h
+@@ -12,6 +12,8 @@
+ #ifndef _CONFIG_L50_H
+ #define _CONFIG_L50_H
+
++#include "openwrt-kirkwood-common.h"
++
+ /*
+  * High Level Configuration Options (easy to change)
+  */
+--- /dev/null
++++ b/include/configs/openwrt-kirkwood-common.h
+@@ -0,0 +1,31 @@
++/*
++ * Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __OPENWRT_KIRKWOOD_COMMON_H
++#define __OPENWRT_KIRKWOOD_COMMON_H
++
++/* Ethernet */
++#if defined(CONFIG_CMD_NET)
++#define CONFIG_SERVERIP		192.168.1.2
++#define CONFIG_IPADDR		192.168.1.1
++#endif
++
++/* second stage loader */
++#if defined(CONFIG_SECOND_STAGE)
++#undef CONFIG_ENV_IS_IN_NAND
++#undef CONFIG_ENV_SECT_SIZE
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++/* Various */
++#define CONFIG_BZIP2
++
++/* Unnecessary */
++#undef CONFIG_BOOTM_NETBSD
++#undef CONFIG_BOOTM_PLAN9
++#undef CONFIG_BOOTM_RTEMS
++
++#endif /* __OPENWRT_KIRKWOOD_COMMON_H */
+--- a/include/configs/pogo_e02.h
++++ b/include/configs/pogo_e02.h
+@@ -66,4 +66,6 @@
+  * File system
+  */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_POGO_E02_H */
+--- a/include/configs/goflexhome.h
++++ b/include/configs/goflexhome.h
+@@ -85,4 +85,6 @@
+ #define CONFIG_SYS_ATA_IDE0_OFFSET      MV_SATA_PORT0_OFFSET
+ #endif /*CONFIG_MVSATA_IDE*/
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_GOFLEXHOME_H */
+--- a/include/configs/nsa310.h
++++ b/include/configs/nsa310.h
+@@ -100,4 +100,6 @@
+ #define CONFIG_RTC_MV
+ #endif /* CONFIG_CMD_DATE */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_NSA310_H */
+--- a/configs/dockstar_defconfig
++++ b/configs/dockstar_defconfig
+@@ -38,3 +38,8 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/goflexhome_defconfig
++++ b/configs/goflexhome_defconfig
+@@ -49,3 +49,8 @@ CONFIG_USB=y
+ CONFIG_DM_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/ib62x0_defconfig
++++ b/configs/ib62x0_defconfig
+@@ -43,4 +43,7 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
+ CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/iconnect_defconfig
++++ b/configs/iconnect_defconfig
+@@ -39,4 +39,8 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
+ CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/l-50_defconfig
++++ b/configs/l-50_defconfig
+@@ -57,3 +57,8 @@ CONFIG_SYS_I2C_MVTWSI=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/nsa310_defconfig
++++ b/configs/nsa310_defconfig
+@@ -43,6 +43,9 @@ CONFIG_CMD_UBI=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
+ CONFIG_LZMA=y
+ CONFIG_LZO=y
+ CONFIG_SYS_LONGHELP=y
+--- a/configs/pogo_e02_defconfig
++++ b/configs/pogo_e02_defconfig
+@@ -39,3 +39,8 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_LZMA=y
++CONFIG_LZO=y
+--- a/configs/nsa310s_defconfig
++++ b/configs/nsa310s_defconfig
+@@ -40,5 +40,8 @@ CONFIG_SYS_NS16550=y
+ CONFIG_USB=y
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_STORAGE=y
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
+ CONFIG_LZMA=y
++CONFIG_LZO=y
+ CONFIG_OF_LIBFDT=y
+--- a/include/configs/nsa310s.h
++++ b/include/configs/nsa310s.h
+@@ -63,4 +63,6 @@
+ #define CONFIG_RTC_MV
+ #endif /* CONFIG_CMD_DATE */
+
++#include "openwrt-kirkwood-common.h"
++
+ #endif /* _CONFIG_NSA310S_H */
diff --git a/package/boot/uboot-kirkwood/patches/201-blackarmor-nas220.patch b/package/boot/uboot-kirkwood/patches/201-blackarmor-nas220.patch
new file mode 100644
index 0000000..50de4e7
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/201-blackarmor-nas220.patch
@@ -0,0 +1,29 @@
+--- a/include/configs/nas220.h
++++ b/include/configs/nas220.h
+@@ -54,17 +54,22 @@
+ /*
+  * Default environment variables
+  */
+-#define CONFIG_BOOTCOMMAND ""
++#define CONFIG_BOOTCOMMAND \
++	"ubi part ubi; " \
++	"ubi read 0x800000 kernel; " \
++	"bootm 0x800000"
+ 
+ #define CONFIG_EXTRA_ENV_SETTINGS \
+ 	"bootargs=console=ttyS0,115200\0" \
+ 	"mtdparts=mtdparts=orion_nand:0xa0000@0x0(uboot),"\
+ 	"0x010000@0xa0000(env),"\
+-	"0x500000@0xc0000(uimage),"\
+-	"0x1a40000@0x5c0000(rootfs)\0" \
++	"0x1e80000@0xc0000(ubi)\0"\
+ 	"mtdids=nand0=orion_nand\0"\
+ 	"autostart=no\0"\
+-	"autoload=no\0"
++	"autoload=no\0"\
++	"ipaddr=10.4.50.165\0"\
++	"serverip=10.4.50.5\0"\
++	"bootdelay=3"
+ 
+ /*
+  * Ethernet Driver configuration
diff --git a/package/boot/uboot-kirkwood/patches/701-phy-mv88e61xx-add-support-for-RGMII-TX-RX-delay.patch b/package/boot/uboot-kirkwood/patches/701-phy-mv88e61xx-add-support-for-RGMII-TX-RX-delay.patch
new file mode 100644
index 0000000..6e35885
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/701-phy-mv88e61xx-add-support-for-RGMII-TX-RX-delay.patch
@@ -0,0 +1,53 @@
+From 940e9a5828480e4185c9a276ad7f35a4069a2393 Mon Sep 17 00:00:00 2001
+From: Pawel Dembicki <paweldembicki@gmail.com>
+Date: Thu, 23 Jan 2020 22:04:15 +0100
+Subject: [PATCH 1/2] phy: mv88e61xx: add support for RGMII TX/RX delay
+
+Clock delay in RGMII is required for some boards.
+This patch introduce CONFIG_MV88E61XX_CPU_PORT_TX_DELAY and
+CONFIG_MV88E61XX_CPU_PORT_RX_DELAY defines, which are setting
+proper bits in PORT_REG_PHYS_CTRL register.
+
+Cc: Chris Packham <judge.packham@gmail.com>
+Cc: Joe Hershberger <joe.hershberger@ni.com>
+Cc: Anatolij Gustschin <agust@denx.de>
+Cc: Tim Harvey <tharvey@gateworks.com>
+Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
+---
+ drivers/net/phy/mv88e61xx.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
+index 5aff7ed397..889327639d 100644
+--- a/drivers/net/phy/mv88e61xx.c
++++ b/drivers/net/phy/mv88e61xx.c
+@@ -94,6 +94,8 @@
+ #define PORT_REG_STATUS_CMODE_1000BASE_X	0x9
+ #define PORT_REG_STATUS_CMODE_SGMII		0xa
+ 
++#define PORT_REG_PHYS_CTRL_RGMII_RX_DELAY	BIT(15)
++#define PORT_REG_PHYS_CTRL_RGMII_TX_DELAY	BIT(14)
+ #define PORT_REG_PHYS_CTRL_PCS_AN_EN	BIT(10)
+ #define PORT_REG_PHYS_CTRL_PCS_AN_RST	BIT(9)
+ #define PORT_REG_PHYS_CTRL_FC_VALUE	BIT(7)
+@@ -747,9 +749,16 @@ static int mv88e61xx_fixed_port_setup(struct phy_device *phydev, u8 port)
+ 		       PORT_REG_PHYS_CTRL_SPD1000;
+ 	}
+ 
+-	if (port == CONFIG_MV88E61XX_CPU_PORT)
++	if (port == CONFIG_MV88E61XX_CPU_PORT) {
+ 		val |= PORT_REG_PHYS_CTRL_LINK_VALUE |
+ 		       PORT_REG_PHYS_CTRL_LINK_FORCE;
++#if defined(CONFIG_MV88E61XX_CPU_PORT_RX_DELAY)
++		val |= PORT_REG_PHYS_CTRL_RGMII_RX_DELAY;
++#endif
++#if defined(CONFIG_MV88E61XX_CPU_PORT_TX_DELAY)
++		val |= PORT_REG_PHYS_CTRL_RGMII_TX_DELAY;
++#endif
++	}
+ 
+ 	return mv88e61xx_port_write(phydev, port, PORT_REG_PHYS_CTRL,
+ 				   val);
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-kirkwood/patches/702-phy-mv88e61xx-add-support-for-MV88E6171.patch b/package/boot/uboot-kirkwood/patches/702-phy-mv88e61xx-add-support-for-MV88E6171.patch
new file mode 100644
index 0000000..c91a06c
--- /dev/null
+++ b/package/boot/uboot-kirkwood/patches/702-phy-mv88e61xx-add-support-for-MV88E6171.patch
@@ -0,0 +1,67 @@
+From 7ffab66a99831ce5e3037b608d73565c9d1abd20 Mon Sep 17 00:00:00 2001
+From: Pawel Dembicki <paweldembicki@gmail.com>
+Date: Thu, 23 Jan 2020 22:09:51 +0100
+Subject: [PATCH 2/2] phy: mv88e61xx: add support for MV88E6171
+
+This patch add MV88E6171 id to driver data.
+
+Tested on Checkpoint L-50 board.
+
+Cc: Chris Packham <judge.packham@gmail.com>
+Cc: Joe Hershberger <joe.hershberger@ni.com>
+Cc: Anatolij Gustschin <agust@denx.de>
+Cc: Tim Harvey <tharvey@gateworks.com>
+Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
+---
+ drivers/net/phy/mv88e61xx.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/drivers/net/phy/mv88e61xx.c b/drivers/net/phy/mv88e61xx.c
+index 889327639d..e0b648a54e 100644
+--- a/drivers/net/phy/mv88e61xx.c
++++ b/drivers/net/phy/mv88e61xx.c
+@@ -180,6 +180,7 @@
+ #define PORT_SWITCH_ID_6071		0x0710
+ #define PORT_SWITCH_ID_6096		0x0980
+ #define PORT_SWITCH_ID_6097		0x0990
++#define PORT_SWITCH_ID_6171		0x1710
+ #define PORT_SWITCH_ID_6172		0x1720
+ #define PORT_SWITCH_ID_6176		0x1760
+ #define PORT_SWITCH_ID_6220		0x2200
+@@ -997,6 +998,7 @@ static int mv88e61xx_probe(struct phy_device *phydev)
+ 	switch (priv->id) {
+ 	case PORT_SWITCH_ID_6096:
+ 	case PORT_SWITCH_ID_6097:
++	case PORT_SWITCH_ID_6171:
+ 	case PORT_SWITCH_ID_6172:
+ 	case PORT_SWITCH_ID_6176:
+ 	case PORT_SWITCH_ID_6240:
+@@ -1152,6 +1154,17 @@ static struct phy_driver mv88e61xx_driver = {
+ 	.shutdown = &genphy_shutdown,
+ };
+ 
++static struct phy_driver mv88e617x_driver = {
++	.name = "Marvell MV88E617x",
++	.uid = 0x01410e70,
++	.mask = 0xfffffff0,
++	.features = PHY_GBIT_FEATURES,
++	.probe = mv88e61xx_probe,
++	.config = mv88e61xx_phy_config,
++	.startup = mv88e61xx_phy_startup,
++	.shutdown = &genphy_shutdown,
++};
++
+ static struct phy_driver mv88e609x_driver = {
+ 	.name = "Marvell MV88E609x",
+ 	.uid = 0x1410c89,
+@@ -1177,6 +1190,7 @@ static struct phy_driver mv88e6071_driver = {
+ int phy_mv88e61xx_init(void)
+ {
+ 	phy_register(&mv88e61xx_driver);
++	phy_register(&mv88e617x_driver);
+ 	phy_register(&mv88e609x_driver);
+ 	phy_register(&mv88e6071_driver);
+ 
+-- 
+2.20.1
+
diff --git a/package/boot/uboot-lantiq/Makefile b/package/boot/uboot-lantiq/Makefile
new file mode 100644
index 0000000..55038fd
--- /dev/null
+++ b/package/boot/uboot-lantiq/Makefile
@@ -0,0 +1,390 @@
+#
+# Copyright (C) 2012-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=2013.10
+PKG_RELEASE:=1
+
+PKG_HASH:=0d71e62beb952b41ebafb20a7ee4df2f960db64c31b054721ceb79ff14014c55
+
+FIRMWARE_LANTIQ_SOURCE:=$(TOPDIR)/target/linux/lantiq/files/firmware/lantiq
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=lantiq
+  DDR_SETTINGS:=
+endef
+
+define U-Boot/arv4519pw_ram
+  NAME:=Arcadyan arv4519pw (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4519pw
+  DDR_SETTINGS:=board/arcadyan/arv4519pw/ddr_settings.h
+endef
+
+define U-Boot/arv4519pw_nor
+  NAME:=Arcadyan arv4519pw (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4519pw
+endef
+
+define U-Boot/arv4519pw_brn
+  NAME:=Arcadyan arv4519pw (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4519pw
+endef
+
+define U-Boot/arv7506pw11_ram
+  NAME:=Arcadyan ARV7506PW11 (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7506pw11
+  DDR_SETTINGS:=board/arcadyan/arv7506pw11/ddr_settings.h
+endef
+
+define U-Boot/arv7506pw11_nor
+  NAME:=Arcadyan ARV7506PW11 (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7506pw11
+endef
+
+define U-Boot/arv7506pw11_brn
+  NAME:=Arcadyan ARV7506PW11 (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7506pw11
+endef
+
+define U-Boot/arv7510pw_ram
+  NAME:=Arcadyan arv7510pw (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4510pw
+  DDR_SETTINGS:=board/arcadyan/arv7510pw/ddr_settings.h
+endef
+
+define U-Boot/arv7510pw_nor
+  NAME:=Arcadyan arv7510pw (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4510pw
+endef
+
+define U-Boot/arv7510pw_brn
+  NAME:=Arcadyan arv7510pw (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv4510pw
+endef
+
+define U-Boot/arv7510pw22_ram
+  NAME:=Arcadyan arv7510pw22 (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7510pw22
+  DDR_SETTINGS:=board/arcadyan/arv7510pw22/ddr_settings.h
+endef
+
+define U-Boot/arv7510pw22_nor
+  NAME:=Arcadyan arv7510pw22 (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7510pw22
+endef
+
+define U-Boot/arv7510pw22_brn
+  NAME:=Arcadyan arv7510pw22 (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7510pw22
+endef
+
+define U-Boot/arv7518pw_ram
+  NAME:=Arcadyan arv7518pw (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7518pw
+  DDR_SETTINGS:=board/arcadyan/arv7518pw/ddr_settings.h
+endef
+
+define U-Boot/arv7518pw_nor
+  NAME:=Arcadyan arv7518pw (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7518pw
+endef
+
+define U-Boot/arv7518pw_brn
+  NAME:=Arcadyan arv7518pw (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv7518pw
+endef
+
+define U-Boot/arv752dpw_ram
+  NAME:=Arcadyan arv752dpw (RAM)
+  BUILD_SUBTARGET:=xway
+  DDR_SETTINGS:=board/arcadyan/arv752dpw/ddr_settings.h
+  BUILD_DEVICES:=arcadyan_arv752dpw
+endef
+
+define U-Boot/arv752dpw_nor
+  NAME:=Arcadyan arv752dpw (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv752dpw
+endef
+
+define U-Boot/arv752dpw_brn
+  NAME:=Arcadyan arv752dpw (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv752dpw
+endef
+
+define U-Boot/arv752dpw22_ram
+  NAME:=Arcadyan arv752dpw22 (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv752dpw22
+  DDR_SETTINGS:=board/arcadyan/arv752dpw22/ddr_settings.h
+endef
+
+define U-Boot/arv752dpw22_nor
+  NAME:=Arcadyan arv752dpw22 (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv752dpw22
+endef
+
+define U-Boot/arv752dpw22_brn
+  NAME:=Arcadyan arv752dpw22 (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv752dpw22
+endef
+
+define U-Boot/arv8539pw22_ram
+  NAME:=Speedport W 504V Typ A (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv8539pw22
+  DDR_SETTINGS:=board/arcadyan/arv8539pw22/ddr_settings.h
+endef
+
+define U-Boot/arv8539pw22_nor
+  NAME:=Speedport W 504V Typ A (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv8539pw22
+endef
+
+define U-Boot/arv8539pw22_brn
+  NAME:=Speedport W 504V Typ A (BRN)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=arcadyan_arv8539pw22
+endef
+
+define U-Boot/gigasx76x_ram
+  NAME:=Siemens Gigaset sx76x (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=siemens_gigaset-sx76x
+  DDR_SETTINGS:=board/gigaset/sx76x/ddr_settings.h
+endef
+
+define U-Boot/gigasx76x_nor
+  NAME:=Siemens Gigaset sx76x (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=siemens_gigaset-sx76x
+endef
+
+define U-Boot/acmp252_ram
+  NAME:=AudioCodes MP-252 (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=audiocodes_mp-252
+  DDR_SETTINGS:=board/audiocodes/acmp252/ddr_settings.h
+endef
+
+define U-Boot/acmp252_nor
+  NAME:=AudioCodes MP-252 (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=audiocodes_mp-252
+endef
+
+define U-Boot/bthomehubv5a_ram
+  NAME:=BT Home Hub 5A (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=bt_homehub-v5a
+  DDR_SETTINGS:=board/bt/bthomehubv5a/ddr_settings.h
+endef
+
+define U-Boot/easy50712_ram
+  NAME:=Lantiq EASY50712 (RAM)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=lantiq_easy50712
+  DDR_SETTINGS:=board/lantiq/easy50712/ddr_settings.h
+endef
+
+define U-Boot/easy50712_nor
+  NAME:=Lantiq EASY50712 (NOR)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=lantiq_easy50712
+endef
+
+define U-Boot/easy50712_norspl
+  NAME:=Lantiq EASY50712 (NOR SPL)
+  BUILD_SUBTARGET:=xway
+  BUILD_DEVICES:=lantiq_easy50712
+  UBOOT_IMAGE:=u-boot.ltq.lzo.norspl
+  DEPENDS+=@BROKEN
+endef
+
+define U-Boot/easy80920_ram
+  NAME:=Lantiq EASY80920 (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=lantiq_easy80920-nor lantiq_easy80920-nand
+  DDR_SETTINGS:=board/lantiq/easy80920/ddr_settings.h
+endef
+
+define U-Boot/easy80920_nor
+  NAME:=Lantiq EASY80920 (NOR)
+  BUILD_DEVICES:=lantiq_easy80920-nor lantiq_easy80920-nand
+  BUILD_SUBTARGET:=xrx200
+endef
+
+define U-Boot/easy80920_norspl
+  NAME:=Lantiq EASY80920 (NOR SPL)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=lantiq_easy80920-nor lantiq_easy80920-nand
+  UBOOT_IMAGE:=u-boot.ltq.lzo.norspl
+  DEPENDS+=@BROKEN
+endef
+
+define U-Boot/easy80920_sfspl
+  NAME:=Lantiq EASY80920 (SPI SPL)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=lantiq_easy80920-nor lantiq_easy80920-nand
+  UBOOT_IMAGE:=u-boot.ltq.lzo.sfspl
+  DEPENDS+=@BROKEN
+endef
+
+define U-Boot/fb3370_eva
+  NAME:=AVM FRITZ3370 (EVA)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=avm_fritz3370
+endef
+
+define U-Boot/fb3370_ram
+  NAME:=AVM FRITZ3370 (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=avm_fritz3370
+  DDR_SETTINGS:=board/avm/fb3370/ddr_settings.h
+endef
+
+define U-Boot/fb3370_sfspl
+  NAME:=AVM FRITZ3370 (SPI SPL)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=avm_fritz3370
+  UBOOT_IMAGE:=u-boot.ltq.lzo.sfspl
+  DEPENDS+=@BROKEN
+endef
+
+define U-Boot/p2812hnufx_ram
+  NAME:=ZyXEL P-2812HNU-Fx (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=zyxel_p-2812hnu-f1
+  DDR_SETTINGS:=board/zyxel/p2812hnufx/ddr_settings.h
+endef
+
+define U-Boot/p2812hnufx_nandspl
+  NAME:=ZyXEL P-2812HNU-Fx (NAND SPL)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=zyxel_p-2812hnu-f1
+  UBOOT_IMAGE:=u-boot.ltq.lzo.nandspl
+  DEPENDS+=@BROKEN
+endef
+
+define U-Boot/vgv7510kw22_brn
+  NAME:=Arcadyan VGV7510KW22 (BRN)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7510kw22-nor
+endef
+
+define U-Boot/vgv7510kw22_nor
+  NAME:=Arcadyan VGV7510KW22 (NOR)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7510kw22-nor
+endef
+
+define U-Boot/vgv7510kw22_ram
+  NAME:=Arcadyan VGV7510KW22 (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7510kw22-nor
+  DDR_SETTINGS:=board/arcadyan/vgv7510kw22/ddr_settings.h
+endef
+
+define U-Boot/vgv7519_brn
+  NAME:=Arcadyan VGV7519 (BRN)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7519-nor arcadyan_vgv7519-brn
+endef
+
+define U-Boot/vgv7519_nor
+  NAME:=Arcadyan VGV7519 (NOR)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7519-nor arcadyan_vgv7519-brn
+endef
+
+define U-Boot/vgv7519_ram
+  NAME:=Arcadyan VGV7519 (RAM)
+  BUILD_SUBTARGET:=xrx200
+  BUILD_DEVICES:=arcadyan_vgv7519-nor arcadyan_vgv7519-brn
+  DDR_SETTINGS:=board/arcadyan/vgv7519/ddr_settings.h
+endef
+
+UBOOT_TARGETS:= \
+	arv4519pw_ram arv4519pw_nor arv4519pw_brn \
+	arv7506pw11_ram arv7506pw11_nor arv7506pw11_brn \
+	arv7510pw_ram arv7510pw_nor arv7510pw_brn \
+	arv7510pw22_ram arv7510pw22_nor arv7510pw22_brn \
+	arv7518pw_ram arv7518pw_nor arv7518pw_brn \
+	arv752dpw_ram arv752dpw_nor arv752dpw_brn \
+	arv752dpw22_ram arv752dpw22_nor arv752dpw22_brn \
+	arv8539pw22_brn arv8539pw22_nor arv8539pw22_ram \
+	bthomehubv5a_ram \
+	gigasx76x_ram gigasx76x_nor \
+	acmp252_ram acmp252_nor \
+	easy50712_ram easy50712_nor easy50712_norspl \
+	easy80920_ram easy80920_nor easy80920_norspl easy80920_sfspl \
+	fb3370_eva fb3370_ram fb3370_sfspl \
+	p2812hnufx_ram p2812hnufx_nandspl \
+	vgv7510kw22_brn vgv7510kw22_nor vgv7510kw22_ram \
+	vgv7519_brn vgv7519_nor vgv7519_ram
+
+define CompressVR9Firmware
+	$(STAGING_DIR_HOST)/bin/lzma e \
+		$(FIRMWARE_LANTIQ_SOURCE)/xrx200_phy$(1)_a$(2)$(3).bin \
+		$(PKG_BUILD_DIR)/arch/mips/cpu/mips32/vrx200/fw_phy$(1)_a$(2)x.blob
+endef
+
+define Build/Prepare
+	$(call Build/Prepare/Default)
+	mkdir -p $(PKG_BUILD_DIR)/arch/mips/cpu/mips32/vrx200/
+	$(call CompressVR9Firmware,11g,1,4)
+	$(call CompressVR9Firmware,11g,2,2)
+	$(call CompressVR9Firmware,22f,1,4)
+	$(call CompressVR9Firmware,22f,2,2)
+endef
+
+UBOOT_MAKE_FLAGS :=
+
+ifeq ($(SUBTARGET),xway)
+  SOC:=danube
+else
+  SOC:=vr9
+endif
+
+define Package/u-boot/install/uart
+	awk -f $(PKG_BUILD_DIR)/tools/lantiq_ram_init_uart.awk \
+		-v soc=$(SOC) $(PKG_BUILD_DIR)/$(DDR_SETTINGS) \
+		> $(PKG_BUILD_DIR)/ddr_settings
+	perl $(PKG_BUILD_DIR)/tools/gct.pl \
+		$(PKG_BUILD_DIR)/ddr_settings $(PKG_BUILD_DIR)/u-boot.srec \
+		$(1)/u-boot.asc
+endef
+
+define Package/u-boot/install
+	$(Package/u-boot/install/$(if $(DDR_SETTINGS),uart,default))
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-lantiq/README b/package/boot/uboot-lantiq/README
new file mode 100644
index 0000000..44ed2bb
--- /dev/null
+++ b/package/boot/uboot-lantiq/README
@@ -0,0 +1,6 @@
+# How to refresh patches
+
+$ git clone git@github.com:danielschwierzeck/u-boot-lantiq.git
+$ mkdir -p $OPENWRT_ROOT/packages/boot/uboot-lantiq/patches
+$ cd u-boot-lantiq.git
+$ git format-patch -p -k --no-renames --no-binary -o $OPENWRT_ROOT/package/boot/uboot-lantiq/patches v2013.10..u-boot-lantiq-v2013.10-openwrtN
diff --git a/package/boot/uboot-lantiq/patches/0001-sf-fix-out-of-order-calls-for-spi_claim_bus-and-spi_.patch b/package/boot/uboot-lantiq/patches/0001-sf-fix-out-of-order-calls-for-spi_claim_bus-and-spi_.patch
new file mode 100644
index 0000000..7ecf544
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0001-sf-fix-out-of-order-calls-for-spi_claim_bus-and-spi_.patch
@@ -0,0 +1,170 @@
+From 909840ef844013379e5ec399c1e76c65d1a6eb1d Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sat, 12 Oct 2013 21:09:47 +0200
+Subject: sf: fix out-of-order calls for spi_claim_bus and spi_release_bus
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_ops.c
++++ b/drivers/mtd/spi/sf_ops.c
+@@ -132,12 +132,6 @@ int spi_flash_write_common(struct spi_fl
+ 	if (buf == NULL)
+ 		timeout = SPI_FLASH_PAGE_ERASE_TIMEOUT;
+ 
+-	ret = spi_claim_bus(flash->spi);
+-	if (ret) {
+-		debug("SF: unable to claim SPI bus\n");
+-		return ret;
+-	}
+-
+ 	ret = spi_flash_cmd_write_enable(flash);
+ 	if (ret < 0) {
+ 		debug("SF: enabling write failed\n");
+@@ -158,8 +152,6 @@ int spi_flash_write_common(struct spi_fl
+ 		return ret;
+ 	}
+ 
+-	spi_release_bus(spi);
+-
+ 	return ret;
+ }
+ 
+@@ -175,12 +167,18 @@ int spi_flash_cmd_erase_ops(struct spi_f
+ 		return -1;
+ 	}
+ 
++	ret = spi_claim_bus(flash->spi);
++	if (ret) {
++		debug("SF: unable to claim SPI bus\n");
++		return ret;
++	}
++
+ 	cmd[0] = flash->erase_cmd;
+ 	while (len) {
+ #ifdef CONFIG_SPI_FLASH_BAR
+ 		ret = spi_flash_bank(flash, offset);
+ 		if (ret < 0)
+-			return ret;
++			goto done;
+ #endif
+ 		spi_flash_addr(offset, cmd);
+ 
+@@ -190,13 +188,16 @@ int spi_flash_cmd_erase_ops(struct spi_f
+ 		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
+ 		if (ret < 0) {
+ 			debug("SF: erase failed\n");
+-			break;
++			goto done;
+ 		}
+ 
+ 		offset += erase_size;
+ 		len -= erase_size;
+ 	}
+ 
++done:
++	spi_release_bus(flash->spi);
++
+ 	return ret;
+ }
+ 
+@@ -208,6 +209,12 @@ int spi_flash_cmd_write_ops(struct spi_f
+ 	u8 cmd[4];
+ 	int ret = -1;
+ 
++	ret = spi_claim_bus(flash->spi);
++	if (ret) {
++		debug("SF: unable to claim SPI bus\n");
++		return ret;
++	}
++
+ 	page_size = flash->page_size;
+ 
+ 	cmd[0] = CMD_PAGE_PROGRAM;
+@@ -215,7 +222,7 @@ int spi_flash_cmd_write_ops(struct spi_f
+ #ifdef CONFIG_SPI_FLASH_BAR
+ 		ret = spi_flash_bank(flash, offset);
+ 		if (ret < 0)
+-			return ret;
++			goto done;
+ #endif
+ 		byte_addr = offset % page_size;
+ 		chunk_len = min(len - actual, page_size - byte_addr);
+@@ -232,12 +239,15 @@ int spi_flash_cmd_write_ops(struct spi_f
+ 					buf + actual, chunk_len);
+ 		if (ret < 0) {
+ 			debug("SF: write failed\n");
+-			break;
++			goto done;
+ 		}
+ 
+ 		offset += chunk_len;
+ 	}
+ 
++done:
++	spi_release_bus(flash->spi);
++
+ 	return ret;
+ }
+ 
+@@ -247,20 +257,12 @@ int spi_flash_read_common(struct spi_fla
+ 	struct spi_slave *spi = flash->spi;
+ 	int ret;
+ 
+-	ret = spi_claim_bus(flash->spi);
+-	if (ret) {
+-		debug("SF: unable to claim SPI bus\n");
+-		return ret;
+-	}
+-
+ 	ret = spi_flash_cmd_read(spi, cmd, cmd_len, data, data_len);
+ 	if (ret < 0) {
+ 		debug("SF: read cmd failed\n");
+ 		return ret;
+ 	}
+ 
+-	spi_release_bus(spi);
+-
+ 	return ret;
+ }
+ 
+@@ -271,6 +273,12 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 	u32 remain_len, read_len;
+ 	int ret = -1;
+ 
++	ret = spi_claim_bus(flash->spi);
++	if (ret) {
++		debug("SF: unable to claim SPI bus\n");
++		return ret;
++	}
++
+ 	/* Handle memory-mapped SPI */
+ 	if (flash->memory_map) {
+ 		spi_xfer(flash->spi, 0, NULL, NULL, SPI_XFER_MMAP);
+@@ -289,7 +297,7 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 		ret = spi_flash_cmd_bankaddr_write(flash, bank_sel);
+ 		if (ret) {
+ 			debug("SF: fail to set bank%d\n", bank_sel);
+-			return ret;
++			goto done;
+ 		}
+ #endif
+ 		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset;
+@@ -304,7 +312,7 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 							data, read_len);
+ 		if (ret < 0) {
+ 			debug("SF: read failed\n");
+-			break;
++			goto done;
+ 		}
+ 
+ 		offset += read_len;
+@@ -312,6 +320,9 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 		data += read_len;
+ 	}
+ 
++done:
++	spi_release_bus(flash->spi);
++
+ 	return ret;
+ }
+ 
diff --git a/package/boot/uboot-lantiq/patches/0002-sf-consistently-use-debug-for-warning-error-messages.patch b/package/boot/uboot-lantiq/patches/0002-sf-consistently-use-debug-for-warning-error-messages.patch
new file mode 100644
index 0000000..af2612f
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0002-sf-consistently-use-debug-for-warning-error-messages.patch
@@ -0,0 +1,49 @@
+From bb7df8c6ff30be3786483767d3afb0e77a69a640 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sat, 12 Oct 2013 21:21:18 +0200
+Subject: sf: consistently use debug() for warning/error messages
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -176,8 +176,8 @@ static struct spi_flash *spi_flash_valid
+ 	}
+ 
+ 	if (i == ARRAY_SIZE(spi_flash_params_table)) {
+-		printf("SF: Unsupported flash IDs: ");
+-		printf("manuf %02x, jedec %04x, ext_jedec %04x\n",
++		debug("SF: Unsupported flash IDs: ");
++		debug("manuf %02x, jedec %04x, ext_jedec %04x\n",
+ 		       idcode[0], jedec, ext_jedec);
+ 		return NULL;
+ 	}
+@@ -296,7 +296,7 @@ struct spi_flash *spi_flash_probe(unsign
+ 	/* Setup spi_slave */
+ 	spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
+ 	if (!spi) {
+-		printf("SF: Failed to set up slave\n");
++		debug("SF: Failed to set up slave\n");
+ 		return NULL;
+ 	}
+ 
+@@ -310,7 +310,7 @@ struct spi_flash *spi_flash_probe(unsign
+ 	/* Read the ID codes */
+ 	ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
+ 	if (ret) {
+-		printf("SF: Failed to get idcodes\n");
++		debug("SF: Failed to get idcodes\n");
+ 		goto err_read_id;
+ 	}
+ 
+@@ -341,8 +341,8 @@ struct spi_flash *spi_flash_probe(unsign
+ #endif
+ #ifndef CONFIG_SPI_FLASH_BAR
+ 	if (flash->size > SPI_FLASH_16MB_BOUN) {
+-		puts("SF: Warning - Only lower 16MiB accessible,");
+-		puts(" Full access #define CONFIG_SPI_FLASH_BAR\n");
++		debug("SF: Warning - Only lower 16MiB accessible,");
++		debug(" Full access #define CONFIG_SPI_FLASH_BAR\n");
+ 	}
+ #endif
+ 
diff --git a/package/boot/uboot-lantiq/patches/0003-sf-move-malloc-of-spi_flash-to-spi_flash_probe.patch b/package/boot/uboot-lantiq/patches/0003-sf-move-malloc-of-spi_flash-to-spi_flash_probe.patch
new file mode 100644
index 0000000..d47d3df
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0003-sf-move-malloc-of-spi_flash-to-spi_flash_probe.patch
@@ -0,0 +1,110 @@
+From 36b7400465fe2339f1c78274b3fd258ade3a4c00 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sat, 12 Oct 2013 21:30:07 +0200
+Subject: sf: move malloc of spi_flash to spi_flash_probe()
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -153,11 +153,10 @@ static const struct spi_flash_params spi
+ 	 */
+ };
+ 
+-static struct spi_flash *spi_flash_validate_params(struct spi_slave *spi,
++static int spi_flash_validate_params(struct spi_flash *flash,
+ 		u8 *idcode)
+ {
+ 	const struct spi_flash_params *params;
+-	struct spi_flash *flash;
+ 	int i;
+ 	u16 jedec = idcode[1] << 8 | idcode[2];
+ 	u16 ext_jedec = idcode[3] << 8 | idcode[4];
+@@ -179,20 +178,12 @@ static struct spi_flash *spi_flash_valid
+ 		debug("SF: Unsupported flash IDs: ");
+ 		debug("manuf %02x, jedec %04x, ext_jedec %04x\n",
+ 		       idcode[0], jedec, ext_jedec);
+-		return NULL;
+-	}
+-
+-	flash = malloc(sizeof(*flash));
+-	if (!flash) {
+-		debug("SF: Failed to allocate spi_flash\n");
+-		return NULL;
++		return -1;
+ 	}
+-	memset(flash, '\0', sizeof(*flash));
+ 
+ 	/* Assign spi data */
+-	flash->spi = spi;
+ 	flash->name = params->name;
+-	flash->memory_map = spi->memory_map;
++	flash->memory_map = flash->spi->memory_map;
+ 
+ 	/* Assign spi_flash ops */
+ 	flash->write = spi_flash_cmd_write_ops;
+@@ -239,7 +230,7 @@ static struct spi_flash *spi_flash_valid
+ 		if (spi_flash_read_common(flash, &flash->bank_read_cmd, 1,
+ 					  &curr_bank, 1)) {
+ 			debug("SF: fail to read bank addr register\n");
+-			return NULL;
++			return -1;
+ 		}
+ 		flash->bank_curr = curr_bank;
+ 	} else {
+@@ -254,7 +245,7 @@ static struct spi_flash *spi_flash_valid
+ 		spi_flash_cmd_write_status(flash, 0);
+ #endif
+ 
+-	return flash;
++	return 0;
+ }
+ 
+ #ifdef CONFIG_OF_CONTROL
+@@ -289,15 +280,22 @@ struct spi_flash *spi_flash_probe(unsign
+ 		unsigned int max_hz, unsigned int spi_mode)
+ {
+ 	struct spi_slave *spi;
+-	struct spi_flash *flash = NULL;
++	struct spi_flash *flash;
+ 	u8 idcode[5];
+ 	int ret;
+ 
++	flash = malloc(sizeof(*flash));
++	if (!flash) {
++		debug("SF: Failed to allocate spi_flash\n");
++		return NULL;
++	}
++	memset(flash, 0, sizeof(*flash));
++
+ 	/* Setup spi_slave */
+ 	spi = spi_setup_slave(bus, cs, max_hz, spi_mode);
+ 	if (!spi) {
+ 		debug("SF: Failed to set up slave\n");
+-		return NULL;
++		goto err_setup;
+ 	}
+ 
+ 	/* Claim spi bus */
+@@ -320,8 +318,9 @@ struct spi_flash *spi_flash_probe(unsign
+ #endif
+ 
+ 	/* Validate params from spi_flash_params table */
+-	flash = spi_flash_validate_params(spi, idcode);
+-	if (!flash)
++	flash->spi = spi;
++	ret = spi_flash_validate_params(flash, idcode);
++	if (ret)
+ 		goto err_read_id;
+ 
+ #ifdef CONFIG_OF_CONTROL
+@@ -355,6 +354,9 @@ err_read_id:
+ 	spi_release_bus(spi);
+ err_claim_bus:
+ 	spi_free_slave(spi);
++err_setup:
++	free(flash);
++
+ 	return NULL;
+ }
+ 
diff --git a/package/boot/uboot-lantiq/patches/0004-sf-add-slim-probe-funtions-for-SPL.patch b/package/boot/uboot-lantiq/patches/0004-sf-add-slim-probe-funtions-for-SPL.patch
new file mode 100644
index 0000000..960085c
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0004-sf-add-slim-probe-funtions-for-SPL.patch
@@ -0,0 +1,80 @@
+From da11da943487e2f724f25d409bcaa1f099637c0b Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 13 Oct 2013 14:56:45 +0200
+Subject: sf: add slim probe funtions for SPL
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -365,3 +365,58 @@ void spi_flash_free(struct spi_flash *fl
+ 	spi_free_slave(flash->spi);
+ 	free(flash);
+ }
++
++#ifdef CONFIG_SPI_SPL_SIMPLE
++int spl_spi_flash_probe(struct spi_flash *flash)
++{
++	struct spi_slave *spi;
++	u8 idcode[5];
++	int ret;
++
++	/* Setup spi_slave */
++	spi = spi_setup_slave(CONFIG_SPL_SPI_BUS, CONFIG_SPL_SPI_CS,
++		CONFIG_SPL_SPI_MAX_HZ, CONFIG_SPL_SPI_MODE);
++	if (!spi) {
++		debug("SF: Failed to set up slave\n");
++		return -1;
++	}
++
++	/* Claim spi bus */
++	ret = spi_claim_bus(spi);
++	if (ret) {
++		debug("SF: Failed to claim SPI bus: %d\n", ret);
++		goto err_claim_bus;
++	}
++
++	/* Read the ID codes */
++	ret = spi_flash_cmd(spi, CMD_READ_ID, idcode, sizeof(idcode));
++	if (ret) {
++		debug("SF: Failed to get idcodes\n");
++		goto err_read_id;
++	}
++
++	/* Validate params from spi_flash_params table */
++	flash->spi = spi;
++	ret = spi_flash_validate_params(flash, idcode);
++	if (ret)
++		goto err_read_id;
++
++	/* Release spi bus */
++	spi_release_bus(spi);
++
++	return 0;
++
++err_read_id:
++	spi_release_bus(spi);
++err_claim_bus:
++	spi_free_slave(spi);
++	flash->spi = NULL;
++
++	return ret;
++}
++
++void spl_spi_flash_free(struct spi_flash *flash)
++{
++	spi_free_slave(flash->spi);
++}
++#endif
+--- a/include/spi_flash.h
++++ b/include/spi_flash.h
+@@ -69,6 +69,9 @@ struct spi_flash *spi_flash_probe(unsign
+ 		unsigned int max_hz, unsigned int spi_mode);
+ void spi_flash_free(struct spi_flash *flash);
+ 
++int spl_spi_flash_probe(struct spi_flash *flash);
++void spl_spi_flash_free(struct spi_flash *flash);
++
+ static inline int spi_flash_read(struct spi_flash *flash, u32 offset,
+ 		size_t len, void *buf)
+ {
diff --git a/package/boot/uboot-lantiq/patches/0005-sf-make-calculatiom-of-address-bytes-completely-conf.patch b/package/boot/uboot-lantiq/patches/0005-sf-make-calculatiom-of-address-bytes-completely-conf.patch
new file mode 100644
index 0000000..8000ff0
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0005-sf-make-calculatiom-of-address-bytes-completely-conf.patch
@@ -0,0 +1,134 @@
+From 6fb5f86b094756d94de8abe7425e3d290ff22dd2 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 13 Oct 2013 15:09:28 +0200
+Subject: sf: make calculatiom of address bytes completely configurable
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_ops.c
++++ b/drivers/mtd/spi/sf_ops.c
+@@ -15,12 +15,17 @@
+ 
+ #include "sf_internal.h"
+ 
+-static void spi_flash_addr(u32 addr, u8 *cmd)
++static void spi_flash_addr(const struct spi_flash *flash, u32 addr, u8 *cmd)
+ {
+ 	/* cmd[0] is actual command */
+-	cmd[1] = addr >> 16;
+-	cmd[2] = addr >> 8;
+-	cmd[3] = addr >> 0;
++	cmd[1] = addr >> (flash->addr_width * 8 - 8);
++	cmd[2] = addr >> (flash->addr_width * 8 - 16);
++	cmd[3] = addr >> (flash->addr_width * 8 - 24);
++}
++
++static int spi_flash_cmdsz(const struct spi_flash *flash)
++{
++	return 1 + flash->addr_width;
+ }
+ 
+ int spi_flash_cmd_write_status(struct spi_flash *flash, u8 sr)
+@@ -158,7 +163,7 @@ int spi_flash_write_common(struct spi_fl
+ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+ {
+ 	u32 erase_size;
+-	u8 cmd[4];
++	u8 cmd[4], cmd_len;
+ 	int ret = -1;
+ 
+ 	erase_size = flash->erase_size;
+@@ -180,12 +185,13 @@ int spi_flash_cmd_erase_ops(struct spi_f
+ 		if (ret < 0)
+ 			goto done;
+ #endif
+-		spi_flash_addr(offset, cmd);
++		spi_flash_addr(flash, offset, cmd);
++		cmd_len = spi_flash_cmdsz(flash);
+ 
+ 		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
+ 		      cmd[2], cmd[3], offset);
+ 
+-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd), NULL, 0);
++		ret = spi_flash_write_common(flash, cmd, cmd_len, NULL, 0);
+ 		if (ret < 0) {
+ 			debug("SF: erase failed\n");
+ 			goto done;
+@@ -206,7 +212,7 @@ int spi_flash_cmd_write_ops(struct spi_f
+ {
+ 	unsigned long byte_addr, page_size;
+ 	size_t chunk_len, actual;
+-	u8 cmd[4];
++	u8 cmd[4], cmd_len;
+ 	int ret = -1;
+ 
+ 	ret = spi_claim_bus(flash->spi);
+@@ -230,12 +236,13 @@ int spi_flash_cmd_write_ops(struct spi_f
+ 		if (flash->spi->max_write_size)
+ 			chunk_len = min(chunk_len, flash->spi->max_write_size);
+ 
+-		spi_flash_addr(offset, cmd);
++		spi_flash_addr(flash, offset, cmd);
++		cmd_len = spi_flash_cmdsz(flash);
+ 
+ 		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
+ 		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
+ 
+-		ret = spi_flash_write_common(flash, cmd, sizeof(cmd),
++		ret = spi_flash_write_common(flash, cmd, cmd_len,
+ 					buf + actual, chunk_len);
+ 		if (ret < 0) {
+ 			debug("SF: write failed\n");
+@@ -269,7 +276,7 @@ int spi_flash_read_common(struct spi_fla
+ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+ 		size_t len, void *data)
+ {
+-	u8 cmd[5], bank_sel = 0;
++	u8 cmd[5], cmd_len, bank_sel = 0;
+ 	u32 remain_len, read_len;
+ 	int ret = -1;
+ 
+@@ -288,7 +295,6 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 	}
+ 
+ 	cmd[0] = CMD_READ_ARRAY_FAST;
+-	cmd[4] = 0x00;
+ 
+ 	while (len) {
+ #ifdef CONFIG_SPI_FLASH_BAR
+@@ -306,9 +312,11 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 		else
+ 			read_len = remain_len;
+ 
+-		spi_flash_addr(offset, cmd);
++		spi_flash_addr(flash, offset, cmd);
++		cmd_len = spi_flash_cmdsz(flash);
++		cmd[cmd_len] = 0x00;
+ 
+-		ret = spi_flash_read_common(flash, cmd, sizeof(cmd),
++		ret = spi_flash_read_common(flash, cmd, cmd_len + 1,
+ 							data, read_len);
+ 		if (ret < 0) {
+ 			debug("SF: read failed\n");
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -218,6 +218,9 @@ static int spi_flash_validate_params(str
+ 		flash->poll_cmd = CMD_FLAG_STATUS;
+ #endif
+ 
++	/* Configure default 3-byte addressing */
++	flash->addr_width = 3;
++
+ 	/* Configure the BAR - discover bank cmds and read current bank */
+ #ifdef CONFIG_SPI_FLASH_BAR
+ 	u8 curr_bank = 0;
+--- a/include/spi_flash.h
++++ b/include/spi_flash.h
+@@ -57,6 +57,7 @@ struct spi_flash {
+ #endif
+ 	u8 poll_cmd;
+ 	u8 erase_cmd;
++	u8 addr_width;
+ 
+ 	void *memory_map;
+ 	int (*read)(struct spi_flash *flash, u32 offset, size_t len, void *buf);
diff --git a/package/boot/uboot-lantiq/patches/0006-sf-add-support-for-4-byte-addressing.patch b/package/boot/uboot-lantiq/patches/0006-sf-add-support-for-4-byte-addressing.patch
new file mode 100644
index 0000000..b903114
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0006-sf-add-support-for-4-byte-addressing.patch
@@ -0,0 +1,160 @@
+From 3af3addee645bd81537be1ddee49969f8dfc64ee Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 13 Oct 2013 15:24:56 +0200
+Subject: sf: add support for 4-byte addressing
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_internal.h
++++ b/drivers/mtd/spi/sf_internal.h
+@@ -38,12 +38,14 @@
+ #define CMD_READ_ID			0x9f
+ 
+ /* Bank addr access commands */
+-#ifdef CONFIG_SPI_FLASH_BAR
+-# define CMD_BANKADDR_BRWR		0x17
+-# define CMD_BANKADDR_BRRD		0x16
+-# define CMD_EXTNADDR_WREAR		0xC5
+-# define CMD_EXTNADDR_RDEAR		0xC8
+-#endif
++#define CMD_BANKADDR_BRWR		0x17
++#define CMD_BANKADDR_BRRD		0x16
++#define CMD_EXTNADDR_WREAR		0xC5
++#define CMD_EXTNADDR_RDEAR		0xC8
++
++/* Macronix style 4-byte addressing */
++#define CMD_EN4B			0xb7
++#define CMD_EX4B			0xe9
+ 
+ /* Common status */
+ #define STATUS_WIP			0x01
+--- a/drivers/mtd/spi/sf_ops.c
++++ b/drivers/mtd/spi/sf_ops.c
+@@ -21,6 +21,7 @@ static void spi_flash_addr(const struct
+ 	cmd[1] = addr >> (flash->addr_width * 8 - 8);
+ 	cmd[2] = addr >> (flash->addr_width * 8 - 16);
+ 	cmd[3] = addr >> (flash->addr_width * 8 - 24);
++	cmd[4] = addr >> (flash->addr_width * 8 - 32);
+ }
+ 
+ static int spi_flash_cmdsz(const struct spi_flash *flash)
+@@ -163,7 +164,7 @@ int spi_flash_write_common(struct spi_fl
+ int spi_flash_cmd_erase_ops(struct spi_flash *flash, u32 offset, size_t len)
+ {
+ 	u32 erase_size;
+-	u8 cmd[4], cmd_len;
++	u8 cmd[5], cmd_len;
+ 	int ret = -1;
+ 
+ 	erase_size = flash->erase_size;
+@@ -188,8 +189,8 @@ int spi_flash_cmd_erase_ops(struct spi_f
+ 		spi_flash_addr(flash, offset, cmd);
+ 		cmd_len = spi_flash_cmdsz(flash);
+ 
+-		debug("SF: erase %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
+-		      cmd[2], cmd[3], offset);
++		debug("SF: erase %2x %2x %2x %2x %2x (%x)\n", cmd[0], cmd[1],
++		      cmd[2], cmd[3], cmd[4], offset);
+ 
+ 		ret = spi_flash_write_common(flash, cmd, cmd_len, NULL, 0);
+ 		if (ret < 0) {
+@@ -212,7 +213,7 @@ int spi_flash_cmd_write_ops(struct spi_f
+ {
+ 	unsigned long byte_addr, page_size;
+ 	size_t chunk_len, actual;
+-	u8 cmd[4], cmd_len;
++	u8 cmd[5], cmd_len;
+ 	int ret = -1;
+ 
+ 	ret = spi_claim_bus(flash->spi);
+@@ -239,8 +240,8 @@ int spi_flash_cmd_write_ops(struct spi_f
+ 		spi_flash_addr(flash, offset, cmd);
+ 		cmd_len = spi_flash_cmdsz(flash);
+ 
+-		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x } chunk_len = %zu\n",
+-		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], chunk_len);
++		debug("PP: 0x%p => cmd = { 0x%02x 0x%02x%02x%02x%02x } chunk_len = %zu\n",
++		      buf + actual, cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], chunk_len);
+ 
+ 		ret = spi_flash_write_common(flash, cmd, cmd_len,
+ 					buf + actual, chunk_len);
+@@ -276,9 +277,13 @@ int spi_flash_read_common(struct spi_fla
+ int spi_flash_cmd_read_ops(struct spi_flash *flash, u32 offset,
+ 		size_t len, void *data)
+ {
+-	u8 cmd[5], cmd_len, bank_sel = 0;
+-	u32 remain_len, read_len;
++	u8 cmd[6], cmd_len;
++	u32 read_len;
+ 	int ret = -1;
++#ifdef CONFIG_SPI_FLASH_BAR
++	u8 bank_sel = 0;
++	u32 remain_len;
++#endif
+ 
+ 	ret = spi_claim_bus(flash->spi);
+ 	if (ret) {
+@@ -305,12 +310,15 @@ int spi_flash_cmd_read_ops(struct spi_fl
+ 			debug("SF: fail to set bank%d\n", bank_sel);
+ 			goto done;
+ 		}
+-#endif
++
+ 		remain_len = (SPI_FLASH_16MB_BOUN * (bank_sel + 1)) - offset;
+ 		if (len < remain_len)
+ 			read_len = len;
+ 		else
+ 			read_len = remain_len;
++#else
++		read_len = len;
++#endif
+ 
+ 		spi_flash_addr(flash, offset, cmd);
+ 		cmd_len = spi_flash_cmdsz(flash);
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -153,6 +153,25 @@ static const struct spi_flash_params spi
+ 	 */
+ };
+ 
++int spi_flash_4byte_set(struct spi_flash *flash, u8 idcode0, int enable)
++{
++	u8 cmd, bankaddr;
++
++	switch (idcode0) {
++	case 0xc2:
++	case 0xef:
++	case 0x1c:
++		/* Macronix style */
++		cmd = enable ? CMD_EN4B : CMD_EX4B;
++		return spi_flash_cmd(flash->spi, cmd, NULL, 0);
++	default:
++		/* Spansion style */
++		cmd = CMD_BANKADDR_BRWR;
++		bankaddr = enable << 7;
++		return spi_flash_cmd_write(flash->spi, &cmd, 1, &bankaddr, 1);
++	}
++}
++
+ static int spi_flash_validate_params(struct spi_flash *flash,
+ 		u8 *idcode)
+ {
+@@ -218,8 +237,18 @@ static int spi_flash_validate_params(str
+ 		flash->poll_cmd = CMD_FLAG_STATUS;
+ #endif
+ 
++#ifndef CONFIG_SPI_FLASH_BAR
++	/* enable 4-byte addressing if the device exceeds 16MiB */
++	if (flash->size > SPI_FLASH_16MB_BOUN) {
++		flash->addr_width = 4;
++		spi_flash_4byte_set(flash, idcode[0], 1);
++	} else {
++		flash->addr_width = 3;
++	}
++#else
+ 	/* Configure default 3-byte addressing */
+ 	flash->addr_width = 3;
++#endif
+ 
+ 	/* Configure the BAR - discover bank cmds and read current bank */
+ #ifdef CONFIG_SPI_FLASH_BAR
diff --git a/package/boot/uboot-lantiq/patches/0007-sf-add-support-for-EN25QH256.patch b/package/boot/uboot-lantiq/patches/0007-sf-add-support-for-EN25QH256.patch
new file mode 100644
index 0000000..04d008f
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0007-sf-add-support-for-EN25QH256.patch
@@ -0,0 +1,17 @@
+From d5aa0d4117a439803a3d074d2745372036d2a1eb Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 13 Oct 2013 15:35:34 +0200
+Subject: sf: add support for EN25QH256
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -53,6 +53,7 @@ static const struct spi_flash_params spi
+ 	{"EN25Q64",	   0x1c3017, 0x0,	64 * 1024,   128,	       SECT_4K},
+ 	{"EN25Q128B",	   0x1c3018, 0x0,       64 * 1024,   256,	             0},
+ 	{"EN25S64",	   0x1c3817, 0x0,	64 * 1024,   128,		     0},
++	{"EN25QH256",	   0x1c7019, 0x0,	64 * 1024,   512,		     0},
+ #endif
+ #ifdef CONFIG_SPI_FLASH_GIGADEVICE	/* GIGADEVICE */
+ 	{"GD25Q64B",	   0xc84017, 0x0,	64 * 1024,   128,	       SECT_4K},
diff --git a/package/boot/uboot-lantiq/patches/0008-sf-fix-sector-layout-of-S25FL256S_256K-and-S25FL512S.patch b/package/boot/uboot-lantiq/patches/0008-sf-fix-sector-layout-of-S25FL256S_256K-and-S25FL512S.patch
new file mode 100644
index 0000000..64f80bf
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0008-sf-fix-sector-layout-of-S25FL256S_256K-and-S25FL512S.patch
@@ -0,0 +1,21 @@
+From 5a6d8045190c887c7f65e65fb1bfc8854774c458 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 13 Oct 2013 15:40:07 +0200
+Subject: sf: fix sector layout of S25FL256S_256K and S25FL512S_256K
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/mtd/spi/sf_probe.c
++++ b/drivers/mtd/spi/sf_probe.c
+@@ -80,9 +80,9 @@ static const struct spi_flash_params spi
+ 	{"S25FL032P",	   0x010215, 0x4d00,    64 * 1024,    64,	             0},
+ 	{"S25FL064P",	   0x010216, 0x4d00,    64 * 1024,   128,	             0},
+ 	{"S25FL128S_64K",  0x012018, 0x4d01,    64 * 1024,   256,		     0},
+-	{"S25FL256S_256K", 0x010219, 0x4d00,    64 * 1024,   512,	             0},
++	{"S25FL256S_256K", 0x010219, 0x4d00,   256 * 1024,   128,	             0},
+ 	{"S25FL256S_64K",  0x010219, 0x4d01,    64 * 1024,   512,	             0},
+-	{"S25FL512S_256K", 0x010220, 0x4d00,    64 * 1024,  1024,	             0},
++	{"S25FL512S_256K", 0x010220, 0x4d00,   256 * 1024,   256,	             0},
+ 	{"S25FL512S_64K",  0x010220, 0x4d01,    64 * 1024,  1024,	             0},
+ #endif
+ #ifdef CONFIG_SPI_FLASH_STMICRO		/* STMICRO */
diff --git a/package/boot/uboot-lantiq/patches/0009-net-switchlib-add-framework-for-ethernet-switch-driv.patch b/package/boot/uboot-lantiq/patches/0009-net-switchlib-add-framework-for-ethernet-switch-driv.patch
new file mode 100644
index 0000000..de6f51b
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0009-net-switchlib-add-framework-for-ethernet-switch-driv.patch
@@ -0,0 +1,244 @@
+From 0dff8c753c8929a478357abb38db0d1c1a60ec94 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Wed, 29 Aug 2012 22:08:15 +0200
+Subject: net: switchlib: add framework for ethernet switch drivers
+
+Add a generic framework similar to phylib for ethernet switch
+drivers and devices. This is useful to share the init and
+setup code for switch devices across different boards.
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Cc: Joe Hershberger <joe.hershberger@gmail.com>
+
+--- a/Makefile
++++ b/Makefile
+@@ -280,6 +280,7 @@ LIBS-y += drivers/mtd/ubi/libubi.o
+ LIBS-y += drivers/mtd/spi/libspi_flash.o
+ LIBS-y += drivers/net/libnet.o
+ LIBS-y += drivers/net/phy/libphy.o
++LIBS-y += drivers/net/switch/libswitch.o
+ LIBS-y += drivers/pci/libpci.o
+ LIBS-y += drivers/pcmcia/libpcmcia.o
+ LIBS-y += drivers/power/libpower.o \
+--- /dev/null
++++ b/drivers/net/switch/Makefile
+@@ -0,0 +1,30 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	:= $(obj)libswitch.o
++
++COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
++
++COBJS	:= $(COBJS-y)
++SRCS	:= $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++
++all:	$(LIB)
++
++$(LIB):	$(obj).depend $(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/drivers/net/switch/switch.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <netdev.h>
++#include <miiphy.h>
++#include <switch.h>
++
++static struct list_head switch_drivers;
++static struct list_head switch_devices;
++
++void switch_init(void)
++{
++	INIT_LIST_HEAD(&switch_drivers);
++	INIT_LIST_HEAD(&switch_devices);
++
++	board_switch_init();
++}
++
++void switch_driver_register(struct switch_driver *drv)
++{
++	INIT_LIST_HEAD(&drv->list);
++	list_add_tail(&drv->list, &switch_drivers);
++}
++
++int switch_device_register(struct switch_device *dev)
++{
++	struct switch_driver *drv;
++
++	/* Add switch device only, if an adequate driver is registered */
++	list_for_each_entry(drv, &switch_drivers, list) {
++		if (!strcmp(drv->name, dev->name)) {
++			dev->drv = drv;
++
++			INIT_LIST_HEAD(&dev->list);
++			list_add_tail(&dev->list, &switch_devices);
++
++			return 0;
++		}
++	}
++
++	return -1;
++}
++
++struct switch_device *switch_connect(struct mii_dev *bus)
++{
++	struct switch_device *sw;
++	int err;
++
++	list_for_each_entry(sw, &switch_devices, list) {
++		sw->bus = bus;
++
++		err = sw->drv->probe(sw);
++		if (!err)
++			return sw;
++	}
++
++	return NULL;
++}
+--- /dev/null
++++ b/include/switch.h
+@@ -0,0 +1,102 @@
++/*
++ * This file is released under the terms of GPL v2 and any later version.
++ * See the file COPYING in the root directory of the source tree for details.
++ *
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ */
++
++#ifndef __SWITCH_H
++#define __SWITCH_H
++
++#include <linux/list.h>
++
++#define SWITCH_NAME_SIZE	32
++
++struct switch_device;
++struct mii_dev;
++
++struct switch_driver {
++	struct list_head list;
++
++	/* Switch device name */
++	const char name[SWITCH_NAME_SIZE];
++
++	/*
++	 * Called to probe the switch chip. Must return 0 if the switch
++	 * chip matches the given switch device/driver combination. Otherwise
++	 * 1 must be returned.
++	 */
++	int (*probe) (struct switch_device *dev);
++
++	/*
++	 * Called to initialize the switch chip.
++	 */
++	void (*setup) (struct switch_device *dev);
++};
++
++struct switch_device {
++	struct list_head list;
++	struct switch_driver *drv;
++
++	/* MII bus the switch chip is connected to */
++	struct mii_dev *bus;
++
++	/* Switch device name */
++	const char name[SWITCH_NAME_SIZE];
++
++	/* Bitmask for board specific setup of used switch ports */
++	u16 port_mask;
++
++	/* Number of switch port that is connected to host CPU */
++	u16 cpu_port;
++};
++
++/*
++ * Board specific switch initialization.
++ *
++ * Called from switch_init to register the board specific switch_device
++ * structure.
++ */
++extern int board_switch_init(void);
++
++/* Initialize switch subsystem */
++#ifdef CONFIG_SWITCH_MULTI
++extern void switch_init(void);
++#else
++static inline void switch_init(void)
++{
++}
++#endif
++
++/* Register a switch driver */
++extern void switch_driver_register(struct switch_driver *drv);
++
++/* Register a switch device */
++extern int switch_device_register(struct switch_device *dev);
++
++/*
++ * Probe the available switch chips and connect the found one
++ * with the given MII bus
++ */
++#ifdef CONFIG_SWITCH_MULTI
++extern struct switch_device *switch_connect(struct mii_dev *bus);
++#else
++static inline struct switch_device *switch_connect(struct mii_dev *bus)
++{
++	return NULL;
++}
++#endif
++
++/*
++ * Setup the given switch device
++ */
++static inline void switch_setup(struct switch_device *dev)
++{
++	if (dev->drv->setup)
++		dev->drv->setup(dev);
++}
++
++/* Init functions for supported Switch drivers */
++
++#endif /* __SWITCH_H */
++
+--- a/net/eth.c
++++ b/net/eth.c
+@@ -10,6 +10,7 @@
+ #include <net.h>
+ #include <miiphy.h>
+ #include <phy.h>
++#include <switch.h>
+ 
+ void eth_parse_enetaddr(const char *addr, uchar *enetaddr)
+ {
+@@ -287,6 +288,8 @@ int eth_initialize(bd_t *bis)
+ 	phy_init();
+ #endif
+ 
++	switch_init();
++
+ 	eth_env_init(bis);
+ 
+ 	/*
diff --git a/package/boot/uboot-lantiq/patches/0010-net-switchlib-add-driver-for-Lantiq-PSB697X-switch-f.patch b/package/boot/uboot-lantiq/patches/0010-net-switchlib-add-driver-for-Lantiq-PSB697X-switch-f.patch
new file mode 100644
index 0000000..8f486e8
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0010-net-switchlib-add-driver-for-Lantiq-PSB697X-switch-f.patch
@@ -0,0 +1,161 @@
+From e2c59cedebf72e4a002134a2932f722b508a5448 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Wed, 29 Aug 2012 22:08:15 +0200
+Subject: net: switchlib: add driver for Lantiq PSB697X switch family
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/net/switch/Makefile
++++ b/drivers/net/switch/Makefile
+@@ -10,6 +10,7 @@ include $(TOPDIR)/config.mk
+ LIB	:= $(obj)libswitch.o
+ 
+ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
++COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
+ 
+ COBJS	:= $(COBJS-y)
+ SRCS	:= $(COBJS:.o=.c)
+--- /dev/null
++++ b/drivers/net/switch/psb697x.c
+@@ -0,0 +1,118 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <switch.h>
++#include <miiphy.h>
++
++#define PSB697X_CHIPID1		0x2599
++#define PSB697X_PORT_COUNT	7
++
++#define PSB697X_PORT_BASE(p)	(p * 0x20)
++#define PSB697X_REG_PS(p)	(PSB697X_PORT_BASE(p) + 0x00)
++#define PSB697X_REG_PBC(p)	(PSB697X_PORT_BASE(p) + 0x01)
++#define PSB697X_REG_PEC(p)	(PSB697X_PORT_BASE(p) + 0x02)
++
++#define PSB697X_REG_SGC1	0x0E0	/* Switch Global Control Register 1 */
++#define PSB697X_REG_SGC2	0x0E1	/* Switch Global Control Register 2 */
++#define PSB697X_REG_CMH		0x0E2	/* CPU Port & Mirror Control */
++#define PSB697X_REG_MIICR	0x0F5	/* MII Port Control */
++#define PSB697X_REG_CI0		0x100	/* Chip Identifier 0 */
++#define PSB697X_REG_CI1		0x101	/* Chip Identifier 1 */
++#define PSB697X_REG_MIIAC	0x120	/* MII Indirect Access Control */
++#define PSB697X_REG_MIIWD	0x121	/* MII Indirect Write Data */
++#define PSB697X_REG_MIIRD	0x122	/* MII Indirect Read Data */
++
++#define PSB697X_REG_PORT_FLP	(1 << 2)	/* Force link up */
++#define PSB697X_REG_PORT_FLD	(1 << 1)	/* Force link down */
++
++#define PSB697X_REG_SGC2_SE	(1 << 15)	/* Switch enable */
++
++#define PSB697X_REG_CMH_CPN_MASK	0x7
++#define PSB697X_REG_CMH_CPN_SHIFT	5
++
++
++static inline int psb697x_mii_read(struct mii_dev *bus, u16 reg)
++{
++	int ret;
++
++	ret = bus->read(bus, (reg >> 5) & 0x1f, MDIO_DEVAD_NONE, reg & 0x1f);
++
++	return ret;
++}
++
++static inline int psb697x_mii_write(struct mii_dev *bus, u16 reg, u16 val)
++{
++	int ret;
++
++	ret = bus->write(bus, (reg >> 5) & 0x1f, MDIO_DEVAD_NONE,
++		reg & 0x1f, val);
++
++	return ret;
++}
++
++static int psb697x_probe(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	int ci1;
++
++	ci1 = psb697x_mii_read(bus, PSB697X_REG_CI1);
++
++	if (ci1 == PSB697X_CHIPID1)
++		return 0;
++
++	return 1;
++}
++
++static void psb697x_setup(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	int i, state;
++
++	/* Enable switch */
++	psb697x_mii_write(bus, PSB697X_REG_SGC2, PSB697X_REG_SGC2_SE);
++
++	/*
++	 * Force 100 Mbps as default value for CPU ports 5 and 6 to get
++	 * full speed.
++	 */
++	psb697x_mii_write(bus, PSB697X_REG_MIICR, 0x0773);
++
++	for (i = 0; i < PSB697X_PORT_COUNT; i++) {
++		state = dev->port_mask & (1 << i);
++
++		/*
++		 * Software workaround from Errata Sheet:
++		 * Force link down and reset internal PHY, keep that state
++		 * for all unconnected ports and disable force link down
++		 * for all connected ports
++		 */
++		psb697x_mii_write(bus, PSB697X_REG_PBC(i),
++			PSB697X_REG_PORT_FLD);
++
++		if (i == dev->cpu_port)
++			/* Force link up for CPU port */
++			psb697x_mii_write(bus, PSB697X_REG_PBC(i),
++				PSB697X_REG_PORT_FLP);
++		else if (state)
++			/* Disable force link down for active LAN ports */
++			psb697x_mii_write(bus, PSB697X_REG_PBC(i), 0);
++	}
++}
++
++static struct switch_driver psb697x_drv = {
++	.name = "psb697x",
++};
++
++void switch_psb697x_init(void)
++{
++	/* For archs with manual relocation */
++	psb697x_drv.probe = psb697x_probe;
++	psb697x_drv.setup = psb697x_setup;
++
++	switch_driver_register(&psb697x_drv);
++}
+--- a/drivers/net/switch/switch.c
++++ b/drivers/net/switch/switch.c
+@@ -17,6 +17,10 @@ void switch_init(void)
+ 	INIT_LIST_HEAD(&switch_drivers);
+ 	INIT_LIST_HEAD(&switch_devices);
+ 
++#if defined(CONFIG_SWITCH_PSB697X)
++	switch_psb697x_init();
++#endif
++
+ 	board_switch_init();
+ }
+ 
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -97,6 +97,7 @@ static inline void switch_setup(struct s
+ }
+ 
+ /* Init functions for supported Switch drivers */
++extern void switch_psb697x_init(void);
+ 
+ #endif /* __SWITCH_H */
+ 
diff --git a/package/boot/uboot-lantiq/patches/0011-net-switchlib-add-driver-for-Lantiq-ADM6996I-switch-.patch b/package/boot/uboot-lantiq/patches/0011-net-switchlib-add-driver-for-Lantiq-ADM6996I-switch-.patch
new file mode 100644
index 0000000..a8b142e
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0011-net-switchlib-add-driver-for-Lantiq-ADM6996I-switch-.patch
@@ -0,0 +1,157 @@
+From c291443dc97dadcf0c6afd04688a7d9f79a221b5 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Wed, 29 Aug 2012 22:08:16 +0200
+Subject: net: switchlib: add driver for Lantiq ADM6996I switch family
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/net/switch/Makefile
++++ b/drivers/net/switch/Makefile
+@@ -11,6 +11,7 @@ LIB	:= $(obj)libswitch.o
+ 
+ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
+ COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
++COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
+ 
+ COBJS	:= $(COBJS-y)
+ SRCS	:= $(COBJS:.o=.c)
+--- /dev/null
++++ b/drivers/net/switch/adm6996i.c
+@@ -0,0 +1,115 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <switch.h>
++#include <miiphy.h>
++
++#define ADM6996I_CHIPID0	0x1020
++#define ADM6996I_CHIPID1	0x0007
++#define ADM6996I_PORT_COUNT	6
++
++#define ADM6996I_REG_P0BC	0x001	/* P0 Basic Control */
++#define ADM6996I_REG_P1BC	0x003	/* P1 Basic Control */
++#define ADM6996I_REG_P2BC	0x005	/* P2 Basic Control */
++#define ADM6996I_REG_P3BC	0x007	/* P3 Basic Control */
++#define ADM6996I_REG_P4BC	0x008	/* P4 Basic Control */
++#define ADM6996I_REG_P5BC	0x009	/* P5 Basic Control */
++
++#define ADM6996I_REG_P0EC	0x002	/* P0 Extended Control */
++#define ADM6996I_REG_P1EC	0x002	/* P1 Extended Control */
++#define ADM6996I_REG_P2EC	0x004	/* P2 Extended Control */
++#define ADM6996I_REG_P3EC	0x004	/* P3 Extended Control */
++#define ADM6996I_REG_P4EC	0x006	/* P4 Extended Control */
++#define ADM6996I_REG_P5EC	0x006	/* P5 Extended Control */
++
++#define ADM6996I_REG_SC4	0x012	/* System Control 4 */
++
++#define ADM6996I_REG_CI0	0xA0	/* Chip Identifier 0 */
++#define ADM6996I_REG_CI1	0xA1	/* Chip Identifier 1 */
++
++#define ADM6996I_REG_PXBC_DEFAULT	0x040F
++#define ADM6996I_REG_PXBC_CROSS_EE	(1 << 15)
++#define ADM6996I_REG_PXBC_PD		(1 << 5)
++
++#define ADM6996I_REG_SC4_DEFAULT	0x3600
++#define ADM6996I_REG_SC4_LED_ENABLE	(1 << 1)
++
++#define ADM6996I_REG_CI0_PC_MASK	0xFFF0
++#define ADM6996I_REG_CI0_VN_MASK	0xF
++#define ADM6996I_REG_CI1_PC_MASK	0xF
++
++
++static inline int adm6996i_mii_read(struct mii_dev *bus, u16 reg)
++{
++	int ret;
++
++	ret = bus->read(bus, (reg >> 5) & 0x1f, MDIO_DEVAD_NONE, reg & 0x1f);
++
++	return ret;
++}
++
++static inline int adm6996i_mii_write(struct mii_dev *bus, u16 reg, u16 val)
++{
++	int ret;
++
++	ret = bus->write(bus, (reg >> 5) & 0x1f, MDIO_DEVAD_NONE,
++		reg & 0x1f, val);
++
++	return ret;
++}
++
++static int adm6996i_probe(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	u16 ci0, ci1;
++
++	ci0 = adm6996i_mii_read(bus, ADM6996I_REG_CI0);
++	ci1 = adm6996i_mii_read(bus, ADM6996I_REG_CI1);
++
++	ci0 &= ADM6996I_REG_CI0_PC_MASK;
++	ci1 &= ADM6996I_REG_CI1_PC_MASK;
++
++	if (ci0 == ADM6996I_CHIPID0 && ci1 == ADM6996I_CHIPID1)
++		return 0;
++
++	return 1;
++}
++
++static void adm6996i_setup(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	u16 val;
++
++	/*
++	 * Write default values (Port enable, 100 Mbps, Full Duplex,
++	 * Auto negotiation, Flow control) and enable crossover auto-detect
++	 */
++	val = ADM6996I_REG_PXBC_DEFAULT | ADM6996I_REG_PXBC_CROSS_EE;
++	adm6996i_mii_write(bus, ADM6996I_REG_P0BC, val);
++	adm6996i_mii_write(bus, ADM6996I_REG_P1BC, val);
++	adm6996i_mii_write(bus, ADM6996I_REG_P2BC, val);
++	adm6996i_mii_write(bus, ADM6996I_REG_P3BC, val);
++	adm6996i_mii_write(bus, ADM6996I_REG_P4BC, val);
++	adm6996i_mii_write(bus, ADM6996I_REG_P5BC, val);
++
++	val = ADM6996I_REG_SC4_DEFAULT | ADM6996I_REG_SC4_LED_ENABLE;
++	adm6996i_mii_write(bus, ADM6996I_REG_SC4, val);
++}
++
++static struct switch_driver adm6996i_drv = {
++	.name = "adm6996i",
++};
++
++void switch_adm6996i_init(void)
++{
++	/* For archs with manual relocation */
++	adm6996i_drv.probe = adm6996i_probe;
++	adm6996i_drv.setup = adm6996i_setup;
++
++	switch_driver_register(&adm6996i_drv);
++}
+--- a/drivers/net/switch/switch.c
++++ b/drivers/net/switch/switch.c
+@@ -20,6 +20,9 @@ void switch_init(void)
+ #if defined(CONFIG_SWITCH_PSB697X)
+ 	switch_psb697x_init();
+ #endif
++#if defined(CONFIG_SWITCH_ADM6996I)
++	switch_adm6996i_init();
++#endif
+ 
+ 	board_switch_init();
+ }
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -98,6 +98,7 @@ static inline void switch_setup(struct s
+ 
+ /* Init functions for supported Switch drivers */
+ extern void switch_psb697x_init(void);
++extern void switch_adm6996i_init(void);
+ 
+ #endif /* __SWITCH_H */
+ 
diff --git a/package/boot/uboot-lantiq/patches/0012-net-switchlib-add-driver-for-Atheros-AR8216.patch b/package/boot/uboot-lantiq/patches/0012-net-switchlib-add-driver-for-Atheros-AR8216.patch
new file mode 100644
index 0000000..568f9ad
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0012-net-switchlib-add-driver-for-Atheros-AR8216.patch
@@ -0,0 +1,157 @@
+From 1a1d61a2faf0390033a3766559ce0e758e15894e Mon Sep 17 00:00:00 2001
+From: Luka Perkov <openwrt@lukaperkov.net>
+Date: Wed, 29 Aug 2012 22:08:16 +0200
+Subject: net: switchlib: add driver for Atheros AR8216
+
+Signed-off-by: Luka Perkov <openwrt@lukaperkov.net>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/net/switch/Makefile
++++ b/drivers/net/switch/Makefile
+@@ -12,6 +12,7 @@ LIB	:= $(obj)libswitch.o
+ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
+ COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
+ COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
++COBJS-$(CONFIG_SWITCH_AR8216) += ar8216.o
+ 
+ COBJS	:= $(COBJS-y)
+ SRCS	:= $(COBJS:.o=.c)
+--- /dev/null
++++ b/drivers/net/switch/ar8216.c
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <miiphy.h>
++#include <switch.h>
++#include <netdev.h>
++
++#define BITS(_s, _n)  (((1UL << (_n)) - 1) << _s)
++
++#define AR8216_REG_CTRL			0x0000
++#define   AR8216_CTRL_REVISION		BITS(0, 8)
++#define   AR8216_CTRL_VERSION		BITS(8, 8)
++
++#define AR8216_PROBE_RETRIES		10
++
++static void split_addr(u32 regaddr, u16 *r1, u16 *r2, u16 *page)
++{
++	regaddr >>= 1;
++	*r1 = regaddr & 0x1e;
++
++	regaddr >>= 5;
++	*r2 = regaddr & 0x7;
++
++	regaddr >>= 3;
++	*page = regaddr & 0x1ff;
++}
++
++static int ar8216_mii_read(struct mii_dev *bus, u32 reg)
++{
++	u16 r1, r2, page;
++	u16 lo, hi;
++
++	split_addr(reg, &r1, &r2, &page);
++
++	bus->write(bus, 0x18, MDIO_DEVAD_NONE, 0, page);
++	__udelay(1000);
++
++	lo = bus->read(bus, 0x10 | r2, MDIO_DEVAD_NONE, r1);
++	hi = bus->read(bus, 0x10 | r2, MDIO_DEVAD_NONE, r1 + 1);
++
++	return (hi << 16) | lo;
++}
++
++static void ar8216_mii_write(struct mii_dev *bus, u16 reg, u32 val)
++{
++	u16 r1, r2, r3;
++	u16 lo, hi;
++
++	split_addr((u32) reg, &r1, &r2, &r3);
++
++	bus->write(bus, 0x18, MDIO_DEVAD_NONE, 0, r3);
++	__udelay(1000);
++
++	lo = val & 0xffff;
++	hi = (u16) (val >> 16);
++	bus->write(bus, 0x10 | r2, MDIO_DEVAD_NONE, r1 + 1, hi);
++	bus->write(bus, 0x10 | r2, MDIO_DEVAD_NONE, r1, lo);
++}
++
++static int ar8216_probe(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	u32 val;
++	u16 id;
++
++	val = ar8216_mii_read(bus, AR8216_REG_CTRL);
++	if (val == ~0)
++		return 1;
++
++	id = val & (AR8216_CTRL_REVISION | AR8216_CTRL_VERSION);
++
++	switch (id) {
++		case 0x0101:
++			return 0;
++		default:
++			return 1;
++	}
++}
++
++static void ar8216_setup(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++
++	ar8216_mii_write(bus, 0x200, 0x200);
++	ar8216_mii_write(bus, 0x300, 0x200);
++	ar8216_mii_write(bus, 0x400, 0x200);
++	ar8216_mii_write(bus, 0x500, 0x200);
++	ar8216_mii_write(bus, 0x600, 0x7d);
++	ar8216_mii_write(bus, 0x38, 0xc000050e);
++	ar8216_mii_write(bus, 0x104, 0x4004);
++	ar8216_mii_write(bus, 0x60, 0xffffffff);
++	ar8216_mii_write(bus, 0x64, 0xaaaaaaaa);
++	ar8216_mii_write(bus, 0x68, 0x55555555);
++	ar8216_mii_write(bus, 0x6c, 0x0);
++	ar8216_mii_write(bus, 0x70, 0x41af);
++}
++
++static struct switch_driver ar8216_drv = {
++	.name = "ar8216",
++};
++
++void switch_ar8216_init(void)
++{
++	/* for archs with manual relocation */
++	ar8216_drv.probe = ar8216_probe;
++	ar8216_drv.setup = ar8216_setup;
++
++	switch_driver_register(&ar8216_drv);
++}
+--- a/drivers/net/switch/switch.c
++++ b/drivers/net/switch/switch.c
+@@ -23,6 +23,9 @@ void switch_init(void)
+ #if defined(CONFIG_SWITCH_ADM6996I)
+ 	switch_adm6996i_init();
+ #endif
++#if defined(CONFIG_SWITCH_AR8216)
++	switch_ar8216_init();
++#endif
+ 
+ 	board_switch_init();
+ }
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -99,6 +99,7 @@ static inline void switch_setup(struct s
+ /* Init functions for supported Switch drivers */
+ extern void switch_psb697x_init(void);
+ extern void switch_adm6996i_init(void);
++extern void switch_ar8216_init(void);
+ 
+ #endif /* __SWITCH_H */
+ 
diff --git a/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch b/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
new file mode 100644
index 0000000..72b885a
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0013-net-switchlib-add-driver-for-REALTEK-RTL8306.patch
@@ -0,0 +1,375 @@
+From 42cb399df978a33539b95d668b3f973d927cb902 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 17 Dec 2012 23:37:57 +0100
+Subject: net: switchlib: add driver for REALTEK RTL8306
+
+Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/drivers/net/switch/Makefile
++++ b/drivers/net/switch/Makefile
+@@ -13,6 +13,7 @@ COBJS-$(CONFIG_SWITCH_MULTI) += switch.o
+ COBJS-$(CONFIG_SWITCH_PSB697X) += psb697x.o
+ COBJS-$(CONFIG_SWITCH_ADM6996I) += adm6996i.o
+ COBJS-$(CONFIG_SWITCH_AR8216) += ar8216.o
++COBJS-$(CONFIG_SWITCH_RTL8306) += rtl8306.o
+ 
+ COBJS	:= $(COBJS-y)
+ SRCS	:= $(COBJS:.o=.c)
+--- /dev/null
++++ b/drivers/net/switch/rtl8306.c
+@@ -0,0 +1,332 @@
++/*
++ * Based on OpenWrt linux driver
++ *
++ * Copyright (C) 2011-2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ * Copyright (C) 2009 Felix Fietkau <nbd@nbd.name>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++#define DEBUG
++#include <common.h>
++#include <malloc.h>
++#include <switch.h>
++#include <miiphy.h>
++
++#define RTL8306_REG_PAGE		16
++#define RTL8306_REG_PAGE_LO		(1 << 15)
++#define RTL8306_REG_PAGE_HI		(1 << 1) /* inverted */
++#define RTL8306_CHIPID			0x5988
++
++#define RTL8306_NUM_VLANS		16
++#define RTL8306_NUM_PORTS		6
++#define RTL8306_PORT_CPU		5
++#define RTL8306_NUM_PAGES		4
++#define RTL8306_NUM_REGS		32
++
++enum {
++	RTL_TYPE_S,
++	RTL_TYPE_SD,
++	RTL_TYPE_SDM,
++};
++
++struct rtl_reg {
++	int page;
++	int phy;
++	int reg;
++	int bits;
++	int shift;
++	int inverted;
++};
++
++enum rtl_regidx {
++	RTL_REG_CHIPID,
++	RTL_REG_CHIPVER,
++	RTL_REG_CHIPTYPE,
++	RTL_REG_CPUPORT,
++
++	RTL_REG_EN_CPUPORT,
++	RTL_REG_EN_TAG_OUT,
++	RTL_REG_EN_TAG_CLR,
++	RTL_REG_EN_TAG_IN,
++	RTL_REG_TRAP_CPU,
++	RTL_REG_TRUNK_PORTSEL,
++	RTL_REG_EN_TRUNK,
++	RTL_REG_RESET,
++	RTL_REG_PHY_RESET,
++	RTL_REG_CPU_LINKUP,
++
++	RTL_REG_VLAN_ENABLE,
++	RTL_REG_VLAN_FILTER,
++	RTL_REG_VLAN_TAG_ONLY,
++	RTL_REG_VLAN_TAG_AWARE,
++#define RTL_VLAN_ENUM(id) \
++	RTL_REG_VLAN##id##_VID, \
++	RTL_REG_VLAN##id##_PORTMASK
++	RTL_VLAN_ENUM(0),
++	RTL_VLAN_ENUM(1),
++	RTL_VLAN_ENUM(2),
++	RTL_VLAN_ENUM(3),
++	RTL_VLAN_ENUM(4),
++	RTL_VLAN_ENUM(5),
++	RTL_VLAN_ENUM(6),
++	RTL_VLAN_ENUM(7),
++	RTL_VLAN_ENUM(8),
++	RTL_VLAN_ENUM(9),
++	RTL_VLAN_ENUM(10),
++	RTL_VLAN_ENUM(11),
++	RTL_VLAN_ENUM(12),
++	RTL_VLAN_ENUM(13),
++	RTL_VLAN_ENUM(14),
++	RTL_VLAN_ENUM(15),
++#define RTL_PORT_ENUM(id) \
++	RTL_REG_PORT##id##_PVID, \
++	RTL_REG_PORT##id##_NULL_VID_REPLACE, \
++	RTL_REG_PORT##id##_NON_PVID_DISCARD, \
++	RTL_REG_PORT##id##_VID_INSERT, \
++	RTL_REG_PORT##id##_TAG_INSERT, \
++	RTL_REG_PORT##id##_LINK, \
++	RTL_REG_PORT##id##_SPEED, \
++	RTL_REG_PORT##id##_NWAY, \
++	RTL_REG_PORT##id##_NRESTART, \
++	RTL_REG_PORT##id##_DUPLEX, \
++	RTL_REG_PORT##id##_RXEN, \
++	RTL_REG_PORT##id##_TXEN, \
++	RTL_REG_PORT##id##_LRNEN
++	RTL_PORT_ENUM(0),
++	RTL_PORT_ENUM(1),
++	RTL_PORT_ENUM(2),
++	RTL_PORT_ENUM(3),
++	RTL_PORT_ENUM(4),
++	RTL_PORT_ENUM(5),
++};
++
++static const struct rtl_reg rtl_regs[] = {
++	[RTL_REG_CHIPID]         = { 0, 4, 30, 16,  0, 0 },
++	[RTL_REG_CHIPVER]        = { 0, 4, 31,  8,  0, 0 },
++	[RTL_REG_CHIPTYPE]       = { 0, 4, 31,  2,  8, 0 },
++
++	/* CPU port number */
++	[RTL_REG_CPUPORT]        = { 2, 4, 21,  3,  0, 0 },
++	/* Enable CPU port function */
++	[RTL_REG_EN_CPUPORT]     = { 3, 2, 21,  1, 15, 1 },
++	/* Enable CPU port tag insertion */
++	[RTL_REG_EN_TAG_OUT]     = { 3, 2, 21,  1, 12, 0 },
++	/* Enable CPU port tag removal */
++	[RTL_REG_EN_TAG_CLR]     = { 3, 2, 21,  1, 11, 0 },
++	/* Enable CPU port tag checking */
++	[RTL_REG_EN_TAG_IN]      = { 0, 4, 21,  1,  7, 0 },
++	[RTL_REG_EN_TRUNK]       = { 0, 0, 19,  1, 11, 1 },
++	[RTL_REG_TRUNK_PORTSEL]  = { 0, 0, 16,  1,  6, 1 },
++	[RTL_REG_RESET]          = { 0, 0, 16,  1, 12, 0 },
++	[RTL_REG_PHY_RESET]	 = { 0, 0,  0,  1, 15, 0 },
++	[RTL_REG_CPU_LINKUP]	 = { 0, 6, 22,  1, 15, 0 },
++	[RTL_REG_TRAP_CPU]       = { 3, 2, 22,  1,  6, 0 },
++
++	[RTL_REG_VLAN_TAG_ONLY]  = { 0, 0, 16,  1,  8, 1 },
++	[RTL_REG_VLAN_FILTER]    = { 0, 0, 16,  1,  9, 1 },
++	[RTL_REG_VLAN_TAG_AWARE] = { 0, 0, 16,  1, 10, 1 },
++	[RTL_REG_VLAN_ENABLE]    = { 0, 0, 18,  1,  8, 1 },
++
++#define RTL_VLAN_REGS(id, phy, page, regofs) \
++	[RTL_REG_VLAN##id##_VID] = { page, phy, 25 + regofs, 12, 0, 0 }, \
++	[RTL_REG_VLAN##id##_PORTMASK] = { page, phy, 24 + regofs, 6, 0, 0 }
++	RTL_VLAN_REGS( 0, 0, 0, 0),
++	RTL_VLAN_REGS( 1, 1, 0, 0),
++	RTL_VLAN_REGS( 2, 2, 0, 0),
++	RTL_VLAN_REGS( 3, 3, 0, 0),
++	RTL_VLAN_REGS( 4, 4, 0, 0),
++	RTL_VLAN_REGS( 5, 0, 1, 2),
++	RTL_VLAN_REGS( 6, 1, 1, 2),
++	RTL_VLAN_REGS( 7, 2, 1, 2),
++	RTL_VLAN_REGS( 8, 3, 1, 2),
++	RTL_VLAN_REGS( 9, 4, 1, 2),
++	RTL_VLAN_REGS(10, 0, 1, 4),
++	RTL_VLAN_REGS(11, 1, 1, 4),
++	RTL_VLAN_REGS(12, 2, 1, 4),
++	RTL_VLAN_REGS(13, 3, 1, 4),
++	RTL_VLAN_REGS(14, 4, 1, 4),
++	RTL_VLAN_REGS(15, 0, 1, 6),
++
++#define REG_PORT_SETTING(port, phy) \
++	[RTL_REG_PORT##port##_SPEED] = { 0, phy, 0, 1, 13, 0 }, \
++	[RTL_REG_PORT##port##_NWAY] = { 0, phy, 0, 1, 12, 0 }, \
++	[RTL_REG_PORT##port##_NRESTART] = { 0, phy, 0, 1, 9, 0 }, \
++	[RTL_REG_PORT##port##_DUPLEX] = { 0, phy, 0, 1, 8, 0 }, \
++	[RTL_REG_PORT##port##_TXEN] = { 0, phy, 24, 1, 11, 0 }, \
++	[RTL_REG_PORT##port##_RXEN] = { 0, phy, 24, 1, 10, 0 }, \
++	[RTL_REG_PORT##port##_LRNEN] = { 0, phy, 24, 1, 9, 0 }, \
++	[RTL_REG_PORT##port##_LINK] = { 0, phy, 1, 1, 2, 0 }, \
++	[RTL_REG_PORT##port##_NULL_VID_REPLACE] = { 0, phy, 22, 1, 12, 0 }, \
++	[RTL_REG_PORT##port##_NON_PVID_DISCARD] = { 0, phy, 22, 1, 11, 0 }, \
++	[RTL_REG_PORT##port##_VID_INSERT] = { 0, phy, 22, 2, 9, 0 }, \
++	[RTL_REG_PORT##port##_TAG_INSERT] = { 0, phy, 22, 2, 0, 0 }
++
++	REG_PORT_SETTING(0, 0),
++	REG_PORT_SETTING(1, 1),
++	REG_PORT_SETTING(2, 2),
++	REG_PORT_SETTING(3, 3),
++	REG_PORT_SETTING(4, 4),
++	REG_PORT_SETTING(5, 6),
++
++#define REG_PORT_PVID(phy, page, regofs) \
++	{ page, phy, 24 + regofs, 4, 12, 0 }
++	[RTL_REG_PORT0_PVID] = REG_PORT_PVID(0, 0, 0),
++	[RTL_REG_PORT1_PVID] = REG_PORT_PVID(1, 0, 0),
++	[RTL_REG_PORT2_PVID] = REG_PORT_PVID(2, 0, 0),
++	[RTL_REG_PORT3_PVID] = REG_PORT_PVID(3, 0, 0),
++	[RTL_REG_PORT4_PVID] = REG_PORT_PVID(4, 0, 0),
++	[RTL_REG_PORT5_PVID] = REG_PORT_PVID(0, 1, 2),
++};
++
++static void rtl_set_page(struct mii_dev *bus, unsigned int page)
++{
++	u16 pgsel;
++
++	BUG_ON(page > RTL8306_NUM_PAGES);
++
++	pgsel = bus->read(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE);
++	pgsel &= ~(RTL8306_REG_PAGE_LO | RTL8306_REG_PAGE_HI);
++
++	if (page & (1 << 0))
++		pgsel |= RTL8306_REG_PAGE_LO;
++
++	if (!(page & (1 << 1))) /* bit is inverted */
++		pgsel |= RTL8306_REG_PAGE_HI;
++
++	bus->write(bus, 0, MDIO_DEVAD_NONE, RTL8306_REG_PAGE, pgsel);
++
++}
++
++static __maybe_unused int rtl_w16(struct mii_dev *bus, unsigned int page, unsigned int phy,
++			unsigned int reg, u16 val)
++{
++	rtl_set_page(bus, page);
++
++	bus->write(bus, phy, MDIO_DEVAD_NONE, reg, val);
++	bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
++
++	return 0;
++}
++
++static int rtl_r16(struct mii_dev *bus, unsigned int page, unsigned int phy,
++			unsigned int reg)
++{
++	rtl_set_page(bus, page);
++
++	return bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
++}
++
++static u16 rtl_rmw(struct mii_dev *bus, unsigned int page, unsigned int phy,
++			unsigned int reg, u16 mask, u16 val)
++{
++	u16 r;
++
++	rtl_set_page(bus, page);
++
++	r = bus->read(bus, phy, MDIO_DEVAD_NONE, reg);
++	r &= ~mask;
++	r |= val;
++	bus->write(bus, phy, MDIO_DEVAD_NONE, reg, r);
++
++	return bus->read(bus, phy, MDIO_DEVAD_NONE, reg); /* flush */
++}
++
++static int rtl_get(struct mii_dev *bus, enum rtl_regidx s)
++{
++	const struct rtl_reg *r = &rtl_regs[s];
++	u16 val;
++
++	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
++
++	if (r->bits == 0) /* unimplemented */
++		return 0;
++
++	val = rtl_r16(bus, r->page, r->phy, r->reg);
++
++	if (r->shift > 0)
++		val >>= r->shift;
++
++	if (r->inverted)
++		val = ~val;
++
++	val &= (1 << r->bits) - 1;
++
++	return val;
++}
++
++static __maybe_unused int rtl_set(struct mii_dev *bus, enum rtl_regidx s, unsigned int val)
++{
++	const struct rtl_reg *r = &rtl_regs[s];
++	u16 mask = 0xffff;
++
++	BUG_ON(s >= ARRAY_SIZE(rtl_regs));
++
++	if (r->bits == 0) /* unimplemented */
++		return 0;
++
++	if (r->shift > 0)
++		val <<= r->shift;
++
++	if (r->inverted)
++		val = ~val;
++
++	if (r->bits != 16) {
++		mask = (1 << r->bits) - 1;
++		mask <<= r->shift;
++	}
++
++	val &= mask;
++
++	return rtl_rmw(bus, r->page, r->phy, r->reg, mask, val);
++}
++
++static int rtl8306_probe(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++	unsigned int chipid, chipver, chiptype;
++
++	chipid = rtl_get(bus, RTL_REG_CHIPID);
++	chipver = rtl_get(bus, RTL_REG_CHIPVER);
++	chiptype = rtl_get(bus, RTL_REG_CHIPTYPE);
++
++	debug("%s: chipid %x, chipver %x, chiptype %x\n",
++		__func__, chipid, chipver, chiptype);
++
++	if (chipid == RTL8306_CHIPID)
++		return 0;
++
++	return 1;
++}
++
++static void rtl8306_setup(struct switch_device *dev)
++{
++	struct mii_dev *bus = dev->bus;
++
++	/* initialize cpu port settings */
++	rtl_set(bus, RTL_REG_CPUPORT, dev->cpu_port);
++	rtl_set(bus, RTL_REG_EN_CPUPORT, 1);
++
++	/* enable phy 5 link status */
++	rtl_set(bus, RTL_REG_CPU_LINKUP, 1);
++//	rtl_set(bus, RTL_REG_PORT5_TXEN, 1);
++//	rtl_set(bus, RTL_REG_PORT5_RXEN, 1);
++//	rtl_set(bus, RTL_REG_PORT5_LRNEN, 1);
++#ifdef DEBUG
++ debug("%s: CPU link up: %i\n",
++		__func__, rtl_get(bus, RTL_REG_PORT5_LINK));
++#endif
++
++}
++
++static struct switch_driver rtl8306_drv = {
++	.name = "rtl8306",
++};
++
++void switch_rtl8306_init(void)
++{
++	/* For archs with manual relocation */
++	rtl8306_drv.probe = rtl8306_probe;
++	rtl8306_drv.setup = rtl8306_setup;
++
++	switch_driver_register(&rtl8306_drv);
++}
+--- a/drivers/net/switch/switch.c
++++ b/drivers/net/switch/switch.c
+@@ -26,6 +26,9 @@ void switch_init(void)
+ #if defined(CONFIG_SWITCH_AR8216)
+ 	switch_ar8216_init();
+ #endif
++#if defined(CONFIG_SWITCH_RTL8306)
++	switch_rtl8306_init();
++#endif
+ 
+ 	board_switch_init();
+ }
+--- a/include/switch.h
++++ b/include/switch.h
+@@ -100,6 +100,7 @@ static inline void switch_setup(struct s
+ extern void switch_psb697x_init(void);
+ extern void switch_adm6996i_init(void);
+ extern void switch_ar8216_init(void);
++extern void switch_rtl8306_init(void);
+ 
+ #endif /* __SWITCH_H */
+ 
diff --git a/package/boot/uboot-lantiq/patches/0014-MIPS-add-support-for-Lantiq-XWAY-SoCs.patch b/package/boot/uboot-lantiq/patches/0014-MIPS-add-support-for-Lantiq-XWAY-SoCs.patch
new file mode 100644
index 0000000..cb695ff
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0014-MIPS-add-support-for-Lantiq-XWAY-SoCs.patch
@@ -0,0 +1,8707 @@
+From 11553b0de8992ded6240d034bd49f561d17bea53 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Thu, 13 Jun 2013 01:18:02 +0200
+Subject: MIPS: add support for Lantiq XWAY SoCs
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/.gitignore
++++ b/.gitignore
+@@ -49,6 +49,13 @@
+ /u-boot.sb
+ /u-boot.bd
+ /u-boot.geany
++/u-boot.bin.lzma
++/u-boot.bin.lzo
++/u-boot.ltq.lzma.norspl
++/u-boot.ltq.lzo.norspl
++/u-boot.ltq.norspl
++/u-boot.lzma.img
++/u-boot.lzo.img
+ 
+ #
+ # Generated files
+--- a/Makefile
++++ b/Makefile
+@@ -435,6 +435,12 @@ $(obj)u-boot.bin:	$(obj)u-boot
+ 		$(OBJCOPY) ${OBJCFLAGS} -O binary $< $@
+ 		$(BOARD_SIZE_CHECK)
+ 
++$(obj)u-boot.bin.lzma:	$(obj)u-boot.bin
++		cat $< | lzma -9 -f - > $@
++
++$(obj)u-boot.bin.lzo:	$(obj)u-boot.bin
++		cat $< | lzop -9 -f - > $@
++
+ $(obj)u-boot.ldr:	$(obj)u-boot
+ 		$(CREATE_LDR_ENV)
+ 		$(LDR) -T $(CONFIG_BFIN_CPU) -c $@ $< $(LDR_FLAGS)
+@@ -454,13 +460,23 @@ ifndef CONFIG_SYS_UBOOT_START
+ CONFIG_SYS_UBOOT_START := 0
+ endif
+ 
+-$(obj)u-boot.img:	$(obj)u-boot.bin
+-		$(obj)tools/mkimage -A $(ARCH) -T firmware -C none \
++define GEN_UBOOT_IMAGE
++		$(obj)tools/mkimage -A $(ARCH) -T firmware -C $(1) \
+ 		-O u-boot -a $(CONFIG_SYS_TEXT_BASE) \
+ 		-e $(CONFIG_SYS_UBOOT_START) \
+ 		-n $(shell sed -n -e 's/.*U_BOOT_VERSION//p' $(VERSION_FILE) | \
+ 			sed -e 's/"[	 ]*$$/ for $(BOARD) board"/') \
+ 		-d $< $@
++endef
++
++$(obj)u-boot.img:	$(obj)u-boot.bin
++		$(call GEN_UBOOT_IMAGE,none)
++
++$(obj)u-boot.lzma.img:	$(obj)u-boot.bin.lzma
++		$(call GEN_UBOOT_IMAGE,lzma)
++
++$(obj)u-boot.lzo.img:	$(obj)u-boot.bin.lzo
++		$(call GEN_UBOOT_IMAGE,lzo)
+ 
+ $(obj)u-boot.imx: $(obj)u-boot.bin depend
+ 		$(MAKE) -C $(SRCTREE)/arch/arm/imx-common $(OBJTREE)/u-boot.imx
+@@ -571,6 +587,27 @@ $(obj)u-boot-img-spl-at-end.bin: $(obj)s
+ 			conv=notrunc 2>/dev/null
+ 		cat $(obj)u-boot-pad.img $(obj)spl/u-boot-spl.bin > $@
+ 
++$(obj)u-boot.ltq.sfspl:	$(obj)u-boot.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
++$(obj)u-boot.ltq.lzo.sfspl: $(obj)u-boot.lzo.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
++$(obj)u-boot.ltq.lzma.sfspl: $(obj)u-boot.lzma.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
++$(obj)u-boot.ltq.norspl: $(obj)u-boot.img $(obj)spl/u-boot-spl.bin
++	cat $(obj)spl/u-boot-spl.bin $< > $@
++
++$(obj)u-boot.ltq.lzo.norspl: $(obj)u-boot.lzo.img $(obj)spl/u-boot-spl.bin
++	cat $(obj)spl/u-boot-spl.bin $< > $@
++
++$(obj)u-boot.ltq.lzma.norspl: $(obj)u-boot.lzma.img $(obj)spl/u-boot-spl.bin
++	cat $(obj)spl/u-boot-spl.bin $< > $@
++
+ ifeq ($(CONFIG_SANDBOX),y)
+ GEN_UBOOT = \
+ 		cd $(LNDIR) && $(CC) $(SYMS) -T $(obj)u-boot.lds \
+--- a/README
++++ b/README
+@@ -468,6 +468,11 @@ The following options need to be configu
+ 			CONF_CM_CACHABLE_CUW
+ 			CONF_CM_CACHABLE_ACCELERATED
+ 
++		CONFIG_SYS_MIPS_CACHE_EXT_INIT
++
++		Enable this to use extended cache initialization for recent
++		MIPS CPU cores.
++
+ 		CONFIG_SYS_XWAY_EBU_BOOTCFG
+ 
+ 		Special option for Lantiq XWAY SoCs for booting from NOR flash.
+--- a/arch/mips/config.mk
++++ b/arch/mips/config.mk
+@@ -45,9 +45,13 @@ PLATFORM_CPPFLAGS += -DCONFIG_MIPS -D__M
+ # On the other hand, we want PIC in the U-Boot code to relocate it from ROM
+ # to RAM. $28 is always used as gp.
+ #
+-PLATFORM_CPPFLAGS		+= -G 0 -mabicalls -fpic $(ENDIANNESS)
++PF_ABICALLS			?= -mabicalls
++PF_PIC				?= -fpic
++PF_PIE				?= -pie
++
++PLATFORM_CPPFLAGS		+= -G 0 $(PF_ABICALLS) $(PF_PIC) $(ENDIANNESS)
+ PLATFORM_CPPFLAGS		+= -msoft-float
+ PLATFORM_LDFLAGS		+= -G 0 -static -n -nostdlib $(ENDIANNESS)
+ PLATFORM_RELFLAGS		+= -ffunction-sections -fdata-sections
+-LDFLAGS_FINAL			+= --gc-sections -pie
++LDFLAGS_FINAL			+= --gc-sections $(PF_PIE)
+ OBJCFLAGS			+= --remove-section=.dynsym
+--- a/arch/mips/cpu/mips32/cache.S
++++ b/arch/mips/cpu/mips32/cache.S
+@@ -29,7 +29,11 @@
+  */
+ #define MIPS_MAX_CACHE_SIZE	0x10000
+ 
++#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
++#define INDEX_BASE	0x9fc00000
++#else
+ #define INDEX_BASE	CKSEG0
++#endif
+ 
+ 	.macro	cache_op op addr
+ 	.set	push
+@@ -65,7 +69,11 @@
+  */
+ LEAF(mips_init_icache)
+ 	blez		a1, 9f
++#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
++	mtc0		zero, CP0_ITAGLO
++#else
+ 	mtc0		zero, CP0_TAGLO
++#endif
+ 	/* clear tag to invalidate */
+ 	PTR_LI		t0, INDEX_BASE
+ 	PTR_ADDU	t1, t0, a1
+@@ -90,7 +98,11 @@ LEAF(mips_init_icache)
+  */
+ LEAF(mips_init_dcache)
+ 	blez		a1, 9f
++#ifdef CONFIG_SYS_MIPS_CACHE_EXT_INIT
++	mtc0		zero, CP0_DTAGLO
++#else
+ 	mtc0		zero, CP0_TAGLO
++#endif
+ 	/* clear all tags */
+ 	PTR_LI		t0, INDEX_BASE
+ 	PTR_ADDU	t1, t0, a1
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/Makefile
+@@ -0,0 +1,31 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(SOC).o
++
++COBJS-y	+= cgu.o chipid.o ebu.o mem.o pmu.o rcu.o
++SOBJS-y	+= cgu_init.o mem_init.o
++
++COBJS	:= $(COBJS-y)
++SOBJS	:= $(SOBJS-y)
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
++
++all:	$(LIB)
++
++$(LIB):	$(obj).depend $(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/cgu.c
+@@ -0,0 +1,117 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/io.h>
++
++#define LTQ_CGU_SYS_DDR_MASK		0x0003
++#define LTQ_CGU_SYS_DDR_SHIFT		0
++#define LTQ_CGU_SYS_CPU0_MASK		0x000C
++#define LTQ_CGU_SYS_CPU0_SHIFT		2
++#define LTQ_CGU_SYS_FPI_MASK		0x0040
++#define LTQ_CGU_SYS_FPI_SHIFT		6
++
++struct ltq_cgu_regs {
++	u32	rsvd0;
++	u32	pll0_cfg;	/* PLL0 config */
++	u32	pll1_cfg;	/* PLL1 config */
++	u32	pll2_cfg;	/* PLL2 config */
++	u32	sys;		/* System clock */
++	u32	update;		/* CGU update control */
++	u32	if_clk;		/* Interface clock */
++	u32	osc_con;	/* Update OSC Control */
++	u32	smd;		/* SDRAM Memory Control */
++	u32	rsvd1[3];
++	u32	pcm_cr;		/* PCM control */
++	u32	pci_cr;		/* PCI clock control */
++};
++
++static struct ltq_cgu_regs *ltq_cgu_regs =
++	(struct ltq_cgu_regs *) CKSEG1ADDR(LTQ_CGU_BASE);
++
++static inline u32 ltq_cgu_sys_readl(u32 mask, u32 shift)
++{
++	return (ltq_readl(&ltq_cgu_regs->sys) & mask) >> shift;
++}
++
++unsigned long ltq_get_io_region_clock(void)
++{
++	u32 ddr_sel;
++	unsigned long clk;
++
++	ddr_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_DDR_MASK,
++					LTQ_CGU_SYS_DDR_SHIFT);
++
++	switch (ddr_sel) {
++	case 0:
++		clk = CLOCK_166_MHZ;
++		break;
++	case 1:
++		clk = CLOCK_133_MHZ;
++		break;
++	case 2:
++		clk = CLOCK_111_MHZ;
++		break;
++	case 3:
++		clk = CLOCK_83_MHZ;
++		break;
++	default:
++		clk = 0;
++		break;
++	}
++
++	return clk;
++}
++
++unsigned long ltq_get_cpu_clock(void)
++{
++	u32 cpu0_sel;
++	unsigned long clk;
++
++	cpu0_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_CPU0_MASK,
++					LTQ_CGU_SYS_CPU0_SHIFT);
++
++	switch (cpu0_sel) {
++		/* Same as PLL0 output (333,33 MHz) */
++	case 0:
++		clk = CLOCK_333_MHZ;
++		break;
++		/* 1/1 fixed ratio to DDR clock */
++	case 1:
++		clk = ltq_get_io_region_clock();
++		break;
++		/* 1/2 fixed ratio to DDR clock */
++	case 2:
++		clk = ltq_get_io_region_clock() << 1;
++		break;
++	default:
++		clk = 0;
++		break;
++	}
++
++	return clk;
++}
++
++unsigned long ltq_get_bus_clock(void)
++{
++	u32 fpi_sel;
++	unsigned long clk;
++
++	fpi_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_FPI_MASK,
++					LTQ_CGU_SYS_FPI_SHIFT);
++
++	if (fpi_sel)
++		/* Half the DDR clock */
++		clk = ltq_get_io_region_clock() >> 1;
++	else
++		/* Same as DDR clock */
++		clk = ltq_get_io_region_clock();
++
++	return clk;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/cgu_init.S
+@@ -0,0 +1,142 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* RCU module register */
++#define LTQ_RCU_RST_REQ			0x0010
++#define LTQ_RCU_RST_STAT		0x0014
++#define LTQ_RCU_RST_REQ_VALUE		0x40000008
++#define LTQ_RCU_RST_STAT_XTAL_F	0x20000
++
++/* CGU module register */
++#define LTQ_CGU_PLL0_CFG		0x0004	/* PLL0 config */
++#define LTQ_CGU_PLL1_CFG		0x0008	/* PLL1 config */
++#define LTQ_CGU_PLL2_CFG		0x000C	/* PLL2 config */
++#define LTQ_CGU_SYS			0x0010	/* System clock */
++
++/* Valid SYS.CPU0/1 values */
++#define LTQ_CGU_SYS_CPU0_SHIFT		2
++#define LTQ_CGU_SYS_CPU1_SHIFT		4
++#define LTQ_CGU_SYS_CPU_PLL0		0x0
++#define LTQ_CGU_SYS_CPU_DDR_EQUAL	0x1
++#define LTQ_CGU_SYS_CPU_DDR_TWICE	0x2
++
++/* Valid SYS.DDR values */
++#define LTQ_CGU_SYS_DDR_SHIFT		0
++#define LTQ_CGU_SYS_DDR_167_MHZ	0x0
++#define LTQ_CGU_SYS_DDR_133_MHZ	0x1
++#define LTQ_CGU_SYS_DDR_111_MHZ	0x2
++#define LTQ_CGU_SYS_DDR_83_MHZ		0x3
++
++/* Valid SYS.FPI values */
++#define LTQ_CGU_SYS_FPI_SHIFT		6
++#define LTQ_CGU_SYS_FPI_DDR_EQUAL	0x0
++#define LTQ_CGU_SYS_FPI_DDR_HALF	0x1
++
++/* Valid SYS.PPE values */
++#define LTQ_CGU_SYS_PPE_SHIFT		7
++#define LTQ_CGU_SYS_PPE_266_MHZ	0x0
++#define LTQ_CGU_SYS_PPE_240_MHZ	0x1
++#define LTQ_CGU_SYS_PPE_222_MHZ	0x2
++#define LTQ_CGU_SYS_PPE_133_MHZ	0x3
++
++#if (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_333_DDR_167)
++#define LTQ_CGU_SYS_CPU_CONFIG		LTQ_CGU_SYS_CPU_DDR_TWICE
++#define LTQ_CGU_SYS_DDR_CONFIG		LTQ_CGU_SYS_DDR_167_MHZ
++#define LTQ_CGU_SYS_FPI_CONFIG		LTQ_CGU_SYS_FPI_DDR_HALF
++#define LTQ_CGU_SYS_PPE_CONFIG		LTQ_CGU_SYS_PPE_266_MHZ
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_111_DDR_111)
++#define LTQ_CGU_SYS_CPU_CONFIG		LTQ_CGU_SYS_CPU_DDR_EQUAL
++#define LTQ_CGU_SYS_DDR_CONFIG		LTQ_CGU_SYS_DDR_111_MHZ
++#define LTQ_CGU_SYS_FPI_CONFIG		LTQ_CGU_SYS_FPI_DDR_HALF
++#define LTQ_CGU_SYS_PPE_CONFIG		LTQ_CGU_SYS_PPE_133_MHZ
++#else
++#error "Invalid system clock configuration!"
++#endif
++
++/* Build register values */
++#define LTQ_CGU_SYS_VALUE	((LTQ_CGU_SYS_PPE_CONFIG << \
++					LTQ_CGU_SYS_PPE_SHIFT) | \
++				(LTQ_CGU_SYS_FPI_CONFIG << \
++					LTQ_CGU_SYS_FPI_SHIFT) | \
++				(LTQ_CGU_SYS_CPU_CONFIG << \
++					LTQ_CGU_SYS_CPU1_SHIFT) | \
++				(LTQ_CGU_SYS_CPU_CONFIG << \
++					LTQ_CGU_SYS_CPU0_SHIFT) | \
++				LTQ_CGU_SYS_DDR_CONFIG)
++
++/* Reset values for PLL registers for usage with 35.328 MHz crystal */
++#define PLL0_35MHZ_CONFIG	0x9D861059
++#define PLL1_35MHZ_CONFIG	0x1A260CD9
++#define PLL2_35MHZ_CONFIG	0x8000f1e5
++
++/* Reset values for PLL registers for usage with 36 MHz crystal */
++#define PLL0_36MHZ_CONFIG	0x1000125D
++#define PLL1_36MHZ_CONFIG	0x1B1E0C99
++#define PLL2_36MHZ_CONFIG	0x8002f2a1
++
++LEAF(ltq_cgu_init)
++	/* Load current CGU register value */
++	li	t0, (LTQ_CGU_BASE | KSEG1)
++	lw	t1, LTQ_CGU_SYS(t0)
++
++	/* Load target CGU register values */
++	li	t3, LTQ_CGU_SYS_VALUE
++
++	/* Only update registers if values differ */
++	beq	t1, t3, finished
++
++	/*
++	 * Check whether the XTAL_F bit in RST_STAT register is set or not.
++	 * This bit is latched in via pin strapping. If bit is set then
++	 * clock source is a 36 MHz crystal. Otherwise a 35.328 MHz crystal.
++	 */
++	 li	t1, (LTQ_RCU_BASE | KSEG1)
++	 lw	t2, LTQ_RCU_RST_STAT(t1)
++	 and	t2, t2, LTQ_RCU_RST_STAT_XTAL_F
++	 beq	t2, LTQ_RCU_RST_STAT_XTAL_F, boot_36mhz
++
++boot_35mhz:
++	/* Configure PLL for 35.328 MHz */
++	li	t2, PLL0_35MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL0_CFG(t0)
++	li	t2, PLL1_35MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL1_CFG(t0)
++	li	t2, PLL2_35MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL2_CFG(t0)
++
++	b	do_reset
++
++boot_36mhz:
++	/* Configure PLL for 36 MHz */
++	li	t2, PLL0_36MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL0_CFG(t0)
++	li	t2, PLL1_36MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL1_CFG(t0)
++	li	t2, PLL2_36MHZ_CONFIG
++	sw	t2, LTQ_CGU_PLL2_CFG(t0)
++
++do_reset:
++	/* Store new clock config */
++	sw	t3, LTQ_CGU_SYS(t0)
++
++	/* Perform software reset to activate new clock config */
++	li	t2, LTQ_RCU_RST_REQ_VALUE
++	sw	t2, LTQ_RCU_RST_REQ(t1)
++
++wait_reset:
++	b	wait_reset
++
++finished:
++	jr	ra
++
++	END(ltq_cgu_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/chipid.c
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_CHIPID_VERSION_SHIFT	28
++#define LTQ_CHIPID_VERSION_MASK		(0xF << LTQ_CHIPID_VERSION_SHIFT)
++#define LTQ_CHIPID_PNUM_SHIFT		12
++#define LTQ_CHIPID_PNUM_MASK		(0xFFFF << LTQ_CHIPID_PNUM_SHIFT)
++
++struct ltq_chipid_regs {
++	u32	manid;		/* Manufacturer identification */
++	u32	chipid;		/* Chip identification */
++};
++
++static struct ltq_chipid_regs *ltq_chipid_regs =
++	(struct ltq_chipid_regs *) CKSEG1ADDR(LTQ_CHIPID_BASE);
++
++unsigned int ltq_chip_version_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_VERSION_MASK) >> LTQ_CHIPID_VERSION_SHIFT;
++}
++
++unsigned int ltq_chip_partnum_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_PNUM_MASK) >> LTQ_CHIPID_PNUM_SHIFT;
++}
++
++const char *ltq_chip_partnum_str(void)
++{
++	enum ltq_chip_partnum partnum = ltq_chip_partnum_get();
++
++	switch (partnum) {
++	case LTQ_SOC_DANUBE:
++		return "Danube";
++	case LTQ_SOC_DANUBE_S:
++		return "Danube-S";
++	case LTQ_SOC_TWINPASS:
++		return "Twinpass";
++	default:
++		printf("Unknown partnum: %x\n", partnum);
++	}
++
++	return "";
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/config.mk
+@@ -0,0 +1,25 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PF_CPPFLAGS_DANUBE := $(call cc-option,-mtune=24kec,)
++PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_DANUBE)
++
++ifdef CONFIG_SPL_BUILD
++PF_ABICALLS		:= -mno-abicalls
++PF_PIC			:= -fno-pic
++PF_PIE			:=
++USE_PRIVATE_LIBGCC	:= yes
++endif
++
++LIBS-y += $(CPUDIR)/lantiq-common/liblantiq-common.o
++
++ifndef CONFIG_SPL_BUILD
++ifdef CONFIG_SYS_BOOT_NORSPL
++ALL-y += $(obj)u-boot.ltq.norspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
++endif
++endif
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/ebu.c
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++#define EBU_ADDRSEL_MASK(mask)		((mask & 0xf) << 4)
++#define EBU_ADDRSEL_REGEN		(1 << 0)
++
++#define EBU_CON_WRDIS			(1 << 31)
++#define EBU_CON_AGEN_DEMUX		(0x0 << 24)
++#define EBU_CON_AGEN_MUX		(0x2 << 24)
++#define EBU_CON_SETUP			(1 << 22)
++#define EBU_CON_WAIT_DIS		(0x0 << 20)
++#define EBU_CON_WAIT_ASYNC		(0x1 << 20)
++#define EBU_CON_WAIT_SYNC		(0x2 << 20)
++#define EBU_CON_WINV			(1 << 19)
++#define EBU_CON_PW_8BIT			(0x0 << 16)
++#define EBU_CON_PW_16BIT		(0x1 << 16)
++#define EBU_CON_ALEC(cycles)		((cycles & 0x3) << 14)
++#define EBU_CON_BCGEN_CS		(0x0 << 12)
++#define EBU_CON_BCGEN_INTEL		(0x1 << 12)
++#define EBU_CON_BCGEN_MOTOROLA		(0x2 << 12)
++#define EBU_CON_WAITWRC(cycles)		((cycles & 0x7) << 8)
++#define EBU_CON_WAITRDC(cycles)		((cycles & 0x3) << 6)
++#define EBU_CON_HOLDC(cycles)		((cycles & 0x3) << 4)
++#define EBU_CON_RECOVC(cycles)		((cycles & 0x3) << 2)
++#define EBU_CON_CMULT_1			0x0
++#define EBU_CON_CMULT_4			0x1
++#define EBU_CON_CMULT_8			0x2
++#define EBU_CON_CMULT_16		0x3
++
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define ebu_region0_enable		1
++#else
++#define ebu_region0_enable		0
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define ebu_region1_enable		1
++#else
++#define ebu_region1_enable		0
++#endif
++
++struct ltq_ebu_regs {
++	u32	clc;
++	u32	rsvd0[3];
++	u32	con;
++	u32	rsvd1[3];
++	u32	addr_sel_0;
++	u32	addr_sel_1;
++	u32	rsvd2[14];
++	u32	con_0;
++	u32	con_1;
++};
++
++static struct ltq_ebu_regs *ltq_ebu_regs =
++	(struct ltq_ebu_regs *) CKSEG1ADDR(LTQ_EBU_BASE);
++
++void ltq_ebu_init(void)
++{
++	if (ebu_region0_enable) {
++		/*
++		 * Map EBU region 0 to range 0x10000000-0x13ffffff and enable
++		 * region control. This supports up to 32 MiB NOR flash in
++		 * bank 0.
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_0, LTQ_EBU_REGION0_BASE |
++			EBU_ADDRSEL_MASK(1) | EBU_ADDRSEL_REGEN);
++
++		ltq_writel(&ltq_ebu_regs->con_0, EBU_CON_AGEN_DEMUX |
++			EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
++			EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++			EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
++			EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
++			EBU_CON_CMULT_16);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_0, EBU_ADDRSEL_REGEN);
++
++	if (ebu_region1_enable) {
++		/*
++		 * Map EBU region 1 to range 0x14000000-0x13ffffff and enable
++		 * region control. This supports NAND flash in bank 1.
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_1, LTQ_EBU_REGION1_BASE |
++			EBU_ADDRSEL_MASK(3) | EBU_ADDRSEL_REGEN);
++
++		ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
++			EBU_CON_SETUP | EBU_CON_WAIT_DIS | EBU_CON_PW_8BIT |
++			EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++			EBU_CON_WAITWRC(2) | EBU_CON_WAITRDC(2) |
++			EBU_CON_HOLDC(1) | EBU_CON_RECOVC(1) |
++			EBU_CON_CMULT_4);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_1, EBU_ADDRSEL_REGEN);
++}
++
++void *flash_swap_addr(unsigned long addr)
++{
++	return (void *)(addr ^ 2);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/mem.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++static void *ltq_mc_ddr_base = (void *) CKSEG1ADDR(LTQ_MC_DDR_BASE);
++
++static inline u32 ltq_mc_dc_read(u32 index)
++{
++	return ltq_readl(ltq_mc_ddr_base + LTQ_MC_DDR_DC_OFFSET(index));
++}
++
++phys_size_t initdram(int board_type)
++{
++	u32 col, row, dc04, dc19, dc20;
++
++	dc04 = ltq_mc_dc_read(4);
++	dc19 = ltq_mc_dc_read(19);
++	dc20 = ltq_mc_dc_read(20);
++
++	row = (dc04 & 0xF) - ((dc19 & 0x700) >> 8);
++	col = ((dc04 & 0xF00) >> 8) - (dc20 & 0x7);
++
++	return (1 << (row + col)) * 4 * 2;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/mem_init.S
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* Must be configured in BOARDDIR */
++#include <ddr_settings.h>
++
++#define LTQ_MC_GEN_ERRCAUSE		0x0010
++#define LTQ_MC_GEN_ERRADDR		0x0020
++#define LTQ_MC_GEN_CON			0x0060
++#define LTQ_MC_GEN_STAT			0x0070
++#define LTQ_MC_GEN_CON_SRAM_DDR_ENABLE	0x5
++#define LTQ_MC_GEN_STAT_DLCK_PWRON	0xC
++
++#define LTQ_MC_DDR_DC03_MC_START	0x100
++
++	/* Store given value in MC DDR CCRx register */
++	.macro dc_sw num, val
++	li	t2, \val
++	sw	t2, LTQ_MC_DDR_DC_OFFSET(\num)(t1)
++	.endm
++
++LEAF(ltq_mem_init)
++	/* Load MC General and MC DDR module base */
++	li	t0, (LTQ_MC_GEN_BASE | KSEG1)
++	li	t1, (LTQ_MC_DDR_BASE | KSEG1)
++
++	/* Clear access error log registers */
++	sw	zero, LTQ_MC_GEN_ERRCAUSE(t0)
++	sw	zero, LTQ_MC_GEN_ERRADDR(t0)
++
++	/* Enable DDR and SRAM module in memory controller */
++	li	t2, LTQ_MC_GEN_CON_SRAM_DDR_ENABLE
++	sw	t2, LTQ_MC_GEN_CON(t0)
++
++	/* Clear start bit of DDR memory controller */
++	sw	zero, LTQ_MC_DDR_DC_OFFSET(3)(t1)
++
++	/* Init memory controller registers with values ddr_settings.h */
++	dc_sw	0, MC_DC00_VALUE
++	dc_sw	1, MC_DC01_VALUE
++	dc_sw	2, MC_DC02_VALUE
++	dc_sw	4, MC_DC04_VALUE
++	dc_sw	5, MC_DC05_VALUE
++	dc_sw	6, MC_DC06_VALUE
++	dc_sw	7, MC_DC07_VALUE
++	dc_sw	8, MC_DC08_VALUE
++	dc_sw	9, MC_DC09_VALUE
++
++	dc_sw	10, MC_DC10_VALUE
++	dc_sw	11, MC_DC11_VALUE
++	dc_sw	12, MC_DC12_VALUE
++	dc_sw	13, MC_DC13_VALUE
++	dc_sw	14, MC_DC14_VALUE
++	dc_sw	15, MC_DC15_VALUE
++	dc_sw	16, MC_DC16_VALUE
++	dc_sw	17, MC_DC17_VALUE
++	dc_sw	18, MC_DC18_VALUE
++	dc_sw	19, MC_DC19_VALUE
++
++	dc_sw	20, MC_DC20_VALUE
++	dc_sw	21, MC_DC21_VALUE
++	dc_sw	22, MC_DC22_VALUE
++	dc_sw	23, MC_DC23_VALUE
++	dc_sw	24, MC_DC24_VALUE
++	dc_sw	25, MC_DC25_VALUE
++	dc_sw	26, MC_DC26_VALUE
++	dc_sw	27, MC_DC27_VALUE
++	dc_sw	28, MC_DC28_VALUE
++	dc_sw	29, MC_DC29_VALUE
++
++	dc_sw	30, MC_DC30_VALUE
++	dc_sw	31, MC_DC31_VALUE
++	dc_sw	32, MC_DC32_VALUE
++	dc_sw	33, MC_DC33_VALUE
++	dc_sw	34, MC_DC34_VALUE
++	dc_sw	35, MC_DC35_VALUE
++	dc_sw	36, MC_DC36_VALUE
++	dc_sw	37, MC_DC37_VALUE
++	dc_sw	38, MC_DC38_VALUE
++	dc_sw	39, MC_DC39_VALUE
++
++	dc_sw	40, MC_DC40_VALUE
++	dc_sw	41, MC_DC41_VALUE
++	dc_sw	42, MC_DC42_VALUE
++	dc_sw	43, MC_DC43_VALUE
++	dc_sw	44, MC_DC44_VALUE
++	dc_sw	45, MC_DC45_VALUE
++	dc_sw	46, MC_DC46_VALUE
++
++	/* Set start bit of DDR memory controller */
++	li	t2, LTQ_MC_DDR_DC03_MC_START
++	sw	t2, LTQ_MC_DDR_DC_OFFSET(3)(t1)
++
++	/* Wait until DLL has locked and core is ready for data transfers */
++wait_ready:
++	lw	t2, LTQ_MC_GEN_STAT(t0)
++	li	t3, LTQ_MC_GEN_STAT_DLCK_PWRON
++	and	t2, t3
++	bne	t2, t3, wait_ready
++
++finished:
++	jr	ra
++
++	END(ltq_mem_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/pmu.c
+@@ -0,0 +1,117 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/pm.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_PMU_PWDCR_RESERVED		0xFD0C001C
++
++#define LTQ_PMU_PWDCR_TDM		(1 << 25)
++#define LTQ_PMU_PWDCR_PPE_ENET0		(1 << 23)
++#define LTQ_PMU_PWDCR_PPE_ENET1		(1 << 22)
++#define LTQ_PMU_PWDCR_PPE_TC		(1 << 21)
++#define LTQ_PMU_PWDCR_DEU		(1 << 20)
++#define LTQ_PMU_PWDCR_UART1		(1 << 17)
++#define LTQ_PMU_PWDCR_SDIO		(1 << 16)
++#define LTQ_PMU_PWDCR_AHB		(1 << 15)
++#define LTQ_PMU_PWDCR_FPI0		(1 << 14)
++#define LTQ_PMU_PWDCR_PPE		(1 << 13)
++#define LTQ_PMU_PWDCR_GPTC		(1 << 12)
++#define LTQ_PMU_PWDCR_LEDC		(1 << 11)
++#define LTQ_PMU_PWDCR_EBU		(1 << 10)
++#define LTQ_PMU_PWDCR_DSL		(1 << 9)
++#define LTQ_PMU_PWDCR_SPI		(1 << 8)
++#define LTQ_PMU_PWDCR_UART0		(1 << 7)
++#define LTQ_PMU_PWDCR_USB		(1 << 6)
++#define LTQ_PMU_PWDCR_DMA		(1 << 5)
++#define LTQ_PMU_PWDCR_FPI1		(1 << 1)
++#define LTQ_PMU_PWDCR_USB_PHY		(1 << 0)
++
++struct ltq_pmu_regs {
++	u32	rsvd0[7];
++	u32	pwdcr;
++	u32	sr;
++	u32	pwdcr1;
++	u32	sr1;
++};
++
++static struct ltq_pmu_regs *ltq_pmu_regs =
++	(struct ltq_pmu_regs *) CKSEG1ADDR(LTQ_PMU_BASE);
++
++u32 ltq_pm_map(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_PM_CORE:
++		val = LTQ_PMU_PWDCR_UART1 | LTQ_PMU_PWDCR_FPI0 |
++			LTQ_PMU_PWDCR_LEDC | LTQ_PMU_PWDCR_EBU;
++		break;
++	case LTQ_PM_DMA:
++		val = LTQ_PMU_PWDCR_DMA;
++		break;
++	case LTQ_PM_ETH:
++		val = LTQ_PMU_PWDCR_PPE_ENET0 | LTQ_PMU_PWDCR_PPE_TC |
++			LTQ_PMU_PWDCR_PPE;
++		break;
++	case LTQ_PM_SPI:
++		val = LTQ_PMU_PWDCR_SPI;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_pm_enable(enum ltq_pm_modules module)
++{
++	const unsigned long timeout = 1000;
++	unsigned long timebase;
++	u32 sr, val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_pmu_regs->pwdcr, val);
++
++	timebase = get_timer(0);
++
++	do {
++		sr = ltq_readl(&ltq_pmu_regs->sr);
++		if (~sr & val)
++			return 0;
++	} while (get_timer(timebase) < timeout);
++
++	return 1;
++}
++
++int ltq_pm_disable(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_pmu_regs->pwdcr, val);
++
++	return 0;
++}
++
++void ltq_pmu_init(void)
++{
++	u32 set, clr;
++
++	clr = ltq_pm_map(LTQ_PM_CORE);
++	set = ~(LTQ_PMU_PWDCR_RESERVED | clr);
++
++	ltq_clrsetbits(&ltq_pmu_regs->pwdcr, clr, set);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/danube/rcu.c
+@@ -0,0 +1,125 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_RCU_RD_SRST		(1 << 30)	/* Global SW Reset */
++#define LTQ_RCU_RD_MC		(1 << 14)	/* Memory Controller */
++#define LTQ_RCU_RD_PCI		(1 << 13)	/* PCI core */
++#define LTQ_RCU_RD_DFE_AFE	(1 << 12)	/* Voice DFE/AFE */
++#define LTQ_RCU_RD_DSL_AFE	(1 << 11)	/* DSL AFE */
++#define LTQ_RCU_RD_SDIO		(1 << 10)	/* SDIO core */
++#define LTQ_RCU_RD_DMA		(1 << 9)	/* DMA core */
++#define LTQ_RCU_RD_PPE		(1 << 8)	/* PPE core */
++#define LTQ_RCU_RD_ARC_DFE	(1 << 7)	/* ARC/DFE core */
++#define LTQ_RCU_RD_AHB		(1 << 6)	/* AHB bus */
++#define LTQ_RCU_RD_ENET_MAC1	(1 << 5)	/* Ethernet MAC1 */
++#define LTQ_RCU_RD_USB		(1 << 4)	/* USB and Phy core */
++#define LTQ_RCU_RD_CPU1		(1 << 3)	/* CPU1 subsystem */
++#define LTQ_RCU_RD_FPI		(1 << 2)	/* FPI bus */
++#define LTQ_RCU_RD_CPU0		(1 << 1)	/* CPU0 subsystem */
++#define LTQ_RCU_RD_HRST		(1 << 0)	/* HW reset via HRST pin */
++
++#define LTQ_RCU_STAT_BOOT_SHIFT		18
++#define LTQ_RCU_STAT_BOOT_MASK		(0x7 << LTQ_RCU_STAT_BOOT_SHIFT)
++
++struct ltq_rcu_regs {
++	u32	rsvd0[4];
++	u32	req;		/* Reset request */
++	u32	stat;		/* Reset status */
++	u32	usb_cfg;	/* USB configure */
++	u32	rsvd1[2];
++	u32	pci_rdy;	/* PCI boot ready */
++};
++
++static struct ltq_rcu_regs *ltq_rcu_regs =
++	(struct ltq_rcu_regs *) CKSEG1ADDR(LTQ_RCU_BASE);
++
++u32 ltq_reset_map(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_RESET_CORE:
++	case LTQ_RESET_SOFT:
++		val = LTQ_RCU_RD_SRST | LTQ_RCU_RD_CPU1;
++		break;
++	case LTQ_RESET_DMA:
++		val = LTQ_RCU_RD_DMA;
++		break;
++	case LTQ_RESET_ETH:
++		val = LTQ_RCU_RD_PPE;
++		break;
++	case LTQ_RESET_HARD:
++		val = LTQ_RCU_RD_HRST;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_reset_activate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++int ltq_reset_deactivate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++enum ltq_boot_select ltq_boot_select(void)
++{
++	u32 stat;
++	unsigned int bootstrap;
++
++	stat = ltq_readl(&ltq_rcu_regs->stat);
++	bootstrap = (stat & LTQ_RCU_STAT_BOOT_MASK) >> LTQ_RCU_STAT_BOOT_SHIFT;
++
++	switch (bootstrap) {
++	case 0:
++		return BOOT_NOR_NO_BOOTROM;
++	case 1:
++		return BOOT_NOR;
++	case 2:
++		return BOOT_MII0;
++	case 3:
++		return BOOT_PCI;
++	case 4:
++		return BOOT_UART;
++	case 5:
++		return BOOT_SPI;
++	case 6:
++		return BOOT_NAND;
++	case 7:
++		return BOOT_RMII0;
++	default:
++		return BOOT_UNKNOWN;
++	}
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/Makefile
+@@ -0,0 +1,34 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)liblantiq-common.o
++
++START	= start.o
++COBJS-y	= cpu.o pmu.o
++COBJS-$(CONFIG_SPL_BUILD) += spl.o
++SOBJS-y	= lowlevel_init.o
++
++COBJS	:= $(COBJS-y)
++SOBJS	:= $(SOBJS-y)
++SRCS	:= $(START:.o=.S) $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
++START	:= $(addprefix $(obj),$(START))
++
++all:	$(LIB)
++
++$(LIB):	$(obj).depend $(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/cpu.c
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/cpu.h>
++
++static const char ltq_bootsel_strings[][16] = {
++	"NOR",
++	"NOR w/o BootROM",
++	"UART",
++	"UART w/o EEPROM",
++	"SPI",
++	"NAND",
++	"PCI",
++	"MII0",
++	"RMII0",
++	"RGMII1",
++	"unknown",
++};
++
++const char *ltq_boot_select_str(void)
++{	enum ltq_boot_select bootsel = ltq_boot_select();
++
++	if (bootsel > BOOT_UNKNOWN)
++		bootsel = BOOT_UNKNOWN;
++
++	return ltq_bootsel_strings[bootsel];
++}
++
++void ltq_chip_print_info(void)
++{
++	char buf[32];
++
++	printf("SoC:   Lantiq %s v1.%u\n", ltq_chip_partnum_str(),
++		ltq_chip_version_get());
++	printf("CPU:   %s MHz\n", strmhz(buf, ltq_get_cpu_clock()));
++	printf("IO:    %s MHz\n", strmhz(buf, ltq_get_io_region_clock()));
++	printf("BUS:   %s MHz\n", strmhz(buf, ltq_get_bus_clock()));
++	printf("BOOT:  %s\n", ltq_boot_select_str());
++}
++
++int arch_cpu_init(void)
++{
++	ltq_pmu_init();
++	ltq_ebu_init();
++
++	return 0;
++}
++
++void _machine_restart(void)
++{
++	ltq_reset_activate(LTQ_RESET_CORE);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/lowlevel_init.S
+@@ -0,0 +1,20 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <asm/asm.h>
++#include <asm/regdef.h>
++
++NESTED(lowlevel_init, 0, ra)
++	move	t8, ra
++
++	la	t7, ltq_cgu_init
++	jalr	t7
++
++	la	t7, ltq_mem_init
++	jalr	t7
++
++	jr	t8
++	END(lowlevel_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/pmu.c
+@@ -0,0 +1,9 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/pm.h>
++
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/spl.c
+@@ -0,0 +1,403 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <image.h>
++#include <version.h>
++#include <spi_flash.h>
++#include <linux/compiler.h>
++#include <lzma/LzmaDec.h>
++#include <linux/lzo.h>
++#include <asm/mipsregs.h>
++
++#if defined(CONFIG_LTQ_SPL_CONSOLE)
++#define spl_has_console		1
++
++#if defined(CONFIG_LTQ_SPL_DEBUG)
++#define spl_has_debug		1
++#else
++#define spl_has_debug		0
++#endif
++
++#else
++#define spl_has_console		0
++#define spl_has_debug		0
++#endif
++
++#define spl_debug(fmt, args...)			\
++	do {					\
++		if (spl_has_debug)		\
++			printf(fmt, ##args);	\
++	} while (0)
++
++#define spl_puts(msg)				\
++	do {					\
++		if (spl_has_console)		\
++			puts(msg);		\
++	} while (0)
++
++#if defined(CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH) && defined(CONFIG_SYS_BOOT_SFSPL)
++#define spl_boot_spi_flash	1
++#else
++#define spl_boot_spi_flash	0
++#ifndef CONFIG_SPL_SPI_BUS
++#define CONFIG_SPL_SPI_BUS	0
++#endif
++#ifndef CONFIG_SPL_SPI_CS
++#define CONFIG_SPL_SPI_CS	0
++#endif
++#ifndef CONFIG_SPL_SPI_MAX_HZ
++#define CONFIG_SPL_SPI_MAX_HZ	0
++#endif
++#ifndef CONFIG_SPL_SPI_MODE
++#define CONFIG_SPL_SPI_MODE	0
++#endif
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH) && defined(CONFIG_SYS_BOOT_NORSPL)
++#define spl_boot_nor_flash	1
++#else
++#define spl_boot_nor_flash	0
++#endif
++
++#define spl_sync()	__asm__ __volatile__("sync");
++
++struct spl_image {
++	ulong data_addr;
++	ulong entry_addr;
++	ulong data_size;
++	ulong entry_size;
++	ulong data_crc;
++	u8 comp;
++};
++
++DECLARE_GLOBAL_DATA_PTR;
++
++/* Emulated malloc area needed for LZMA allocator in BSS */
++static u8 *spl_mem_ptr __maybe_unused;
++static size_t spl_mem_size __maybe_unused;
++
++static int spl_is_comp_lzma(const struct spl_image *spl)
++{
++#if defined(CONFIG_LTQ_SPL_COMP_LZMA)
++	return spl->comp == IH_COMP_LZMA;
++#else
++	return 0;
++#endif
++}
++
++static int spl_is_comp_lzo(const struct spl_image *spl)
++{
++#if defined(CONFIG_LTQ_SPL_COMP_LZO)
++	return spl->comp == IH_COMP_LZO;
++#else
++	return 0;
++#endif
++}
++
++static int spl_is_compressed(const struct spl_image *spl)
++{
++	if (spl_is_comp_lzma(spl))
++		return 1;
++
++	if (spl_is_comp_lzo(spl))
++		return 1;
++
++	return 0;
++}
++
++static void spl_console_init(void)
++{
++	if (!spl_has_console)
++		return;
++
++	gd->flags |= GD_FLG_RELOC;
++	gd->baudrate = CONFIG_BAUDRATE;
++
++	serial_init();
++
++	gd->have_console = 1;
++
++	spl_puts("\nU-Boot SPL " PLAIN_VERSION " (" U_BOOT_DATE " - " \
++		U_BOOT_TIME ")\n");
++}
++
++static int spl_parse_image(const image_header_t *hdr, struct spl_image *spl)
++{
++	spl_puts("SPL: checking U-Boot image\n");
++
++	if (!image_check_magic(hdr)) {
++		spl_puts("SPL: invalid magic\n");
++		return -1;
++	}
++
++        if (!image_check_hcrc(hdr)) {
++		spl_puts("SPL: invalid header CRC\n");
++		return -1;
++	}
++
++	spl->data_addr += image_get_header_size();
++	spl->entry_addr = image_get_load(hdr);
++	spl->data_size = image_get_data_size(hdr);
++	spl->data_crc = image_get_dcrc(hdr);
++	spl->comp = image_get_comp(hdr);
++
++	spl_debug("SPL: data %08lx, size %lu, entry %08lx, comp %u\n",
++		spl->data_addr, spl->data_size, spl->entry_addr, spl->comp);
++
++	return 0;
++}
++
++static int spl_check_data(const struct spl_image *spl, ulong loadaddr)
++{
++	ulong dcrc = crc32(0, (unsigned char *)loadaddr, spl->data_size);
++
++	if (dcrc != spl->data_crc) {
++		spl_puts("SPL: invalid data CRC\n");
++		return 0;
++	}
++
++	return 1;
++}
++
++static void *spl_lzma_alloc(void *p, size_t size)
++{
++	u8 *ret;
++
++	if (size > spl_mem_size)
++		return NULL;
++
++	ret = spl_mem_ptr;
++	spl_mem_ptr += size;
++	spl_mem_size -= size;
++
++	return ret;
++}
++
++static void spl_lzma_free(void *p, void *addr)
++{
++}
++
++static int spl_copy_image(struct spl_image *spl)
++{
++	spl_puts("SPL: copying U-Boot to RAM\n");
++
++	memcpy((void *) spl->entry_addr, (const void *) spl->data_addr,
++		spl->data_size);
++
++	spl->entry_size = spl->data_size;
++
++	return 0;
++}
++
++static int spl_uncompress_lzma(struct spl_image *spl, unsigned long loadaddr)
++{
++	SRes res;
++	const Byte *prop = (const Byte *) loadaddr;
++	const Byte *src = (const Byte *) loadaddr + LZMA_PROPS_SIZE +
++							sizeof(uint64_t);
++	Byte *dest = (Byte *) spl->entry_addr;
++	SizeT dest_len = 0xFFFFFFFF;
++	SizeT src_len = spl->data_size - LZMA_PROPS_SIZE;
++	ELzmaStatus status = 0;
++	ISzAlloc alloc;
++
++	spl_puts("SPL: decompressing U-Boot with LZMA\n");
++
++	alloc.Alloc = spl_lzma_alloc;
++	alloc.Free = spl_lzma_free;
++	spl_mem_ptr = (u8 *) CONFIG_SPL_MALLOC_BASE;
++	spl_mem_size = CONFIG_SPL_MALLOC_MAX_SIZE;
++
++	res = LzmaDecode(dest, &dest_len, src, &src_len, prop, LZMA_PROPS_SIZE,
++		LZMA_FINISH_ANY, &status, &alloc);
++	if (res != SZ_OK)
++		return 1;
++
++	spl->entry_size = dest_len;
++
++	return 0;
++}
++
++static int spl_uncompress_lzo(struct spl_image *spl, unsigned long loadaddr)
++{
++	size_t len = CONFIG_SYS_LOAD_SIZE;
++	int ret;
++
++	spl_puts("SPL: decompressing U-Boot with LZO\n");
++
++	ret = lzop_decompress(
++		(const unsigned char*) loadaddr, spl->data_size,
++		(unsigned char *) spl->entry_addr, &len);
++
++	spl->entry_size = len;
++
++	return ret;
++}
++
++static int spl_uncompress(struct spl_image *spl, unsigned long loadaddr)
++{
++	int ret;
++
++	if (spl_is_comp_lzma(spl))
++		ret = spl_uncompress_lzma(spl, loadaddr);
++	else if (spl_is_comp_lzo(spl))
++		ret = spl_uncompress_lzo(spl, loadaddr);
++	else
++		ret = 1;
++
++	return ret;
++}
++
++static int spl_load_spi_flash(struct spl_image *spl)
++{
++	struct spi_flash sf = { 0 };
++	image_header_t hdr;
++	int ret;
++	unsigned long loadaddr;
++
++	/*
++	 * Image format:
++	 *
++	 * - 12 byte non-volatile bootstrap header
++	 * - SPL binary
++	 * - 12 byte non-volatile bootstrap header
++	 * - 64 byte U-Boot mkimage header
++	 * - U-Boot binary
++	 */
++	spl->data_addr = image_copy_end() - CONFIG_SPL_TEXT_BASE + 24;
++
++	spl_puts("SPL: probing SPI flash\n");
++
++	spi_init();
++	ret = spl_spi_flash_probe(&sf);
++	if (ret)
++		return ret;
++
++	spl_debug("SPL: reading image header at offset %lx\n", spl->data_addr);
++
++	ret = spi_flash_read(&sf, spl->data_addr, sizeof(hdr), &hdr);
++	if (ret)
++		return ret;
++
++	spl_debug("SPL: checking image header at offset %lx\n", spl->data_addr);
++
++	ret = spl_parse_image(&hdr, spl);
++	if (ret)
++		return ret;
++
++	if (spl_is_compressed(spl))
++		loadaddr = CONFIG_LOADADDR;
++	else
++		loadaddr = spl->entry_addr;
++
++	spl_puts("SPL: loading U-Boot to RAM\n");
++
++	ret = spi_flash_read(&sf, spl->data_addr, spl->data_size,
++				(void *) loadaddr);
++
++	if (!spl_check_data(spl, loadaddr))
++		return -1;
++
++	if (spl_is_compressed(spl))
++		ret = spl_uncompress(spl, loadaddr);
++
++	return ret;
++}
++
++static int spl_load_nor_flash(struct spl_image *spl)
++{
++	const image_header_t *hdr;
++	int ret;
++
++	/*
++	 * Image format:
++	 *
++	 * - SPL binary
++	 * - 64 byte U-Boot mkimage header
++	 * - U-Boot binary
++	 */
++	spl->data_addr = image_copy_end();
++	hdr = (const image_header_t *) image_copy_end();
++
++	spl_debug("SPL: checking image header at address %p\n", hdr);
++
++	ret = spl_parse_image(hdr, spl);
++	if (ret)
++		return ret;
++
++	if (spl_is_compressed(spl))
++		ret = spl_uncompress(spl, spl->data_addr);
++	else
++		ret = spl_copy_image(spl);
++
++	return ret;
++}
++
++static int spl_load(struct spl_image *spl)
++{
++	int ret;
++
++	if (spl_boot_spi_flash)
++		ret = spl_load_spi_flash(spl);
++	else if (spl_boot_nor_flash)
++		ret = spl_load_nor_flash(spl);
++	else
++		ret = 1;
++
++	return ret;
++}
++
++void __noreturn spl_lantiq_init(void)
++{
++	void (*uboot)(void) __noreturn;
++	struct spl_image spl;
++	gd_t gd_data;
++	int ret;
++
++	gd = &gd_data;
++	barrier();
++	memset((void *)gd, 0, sizeof(gd_t));
++
++	spl_console_init();
++
++	spl_debug("SPL: initializing\n");
++
++#if 0
++	spl_debug("CP0_CONFIG:   %08x\n", read_c0_config());
++	spl_debug("CP0_CONFIG1:  %08x\n", read_c0_config1());
++	spl_debug("CP0_CONFIG2:  %08x\n", read_c0_config2());
++	spl_debug("CP0_CONFIG3:  %08x\n", read_c0_config3());
++	spl_debug("CP0_CONFIG6:  %08x\n", read_c0_config6());
++	spl_debug("CP0_CONFIG7:  %08x\n", read_c0_config7());
++	spl_debug("CP0_STATUS:   %08x\n", read_c0_status());
++	spl_debug("CP0_PRID:     %08x\n", read_c0_prid());
++#endif
++
++	board_early_init_f();
++	timer_init();
++
++	memset(&spl, 0, sizeof(spl));
++
++	ret = spl_load(&spl);
++	if (ret)
++		goto hang;
++
++	spl_debug("SPL: U-Boot entry %08lx\n", spl.entry_addr);
++	spl_puts("SPL: jumping to U-Boot\n");
++
++	flush_cache(spl.entry_addr, spl.entry_size);
++	spl_sync();
++
++	uboot = (void *) spl.entry_addr;
++	uboot();
++
++hang:
++	spl_puts("SPL: cannot start U-Boot\n");
++
++	for (;;)
++		;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/start.S
+@@ -0,0 +1,143 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/regdef.h>
++#include <asm/mipsregs.h>
++
++#define S_PRIdCoID	16		/* Company ID (R) */
++#define M_PRIdCoID	(0xff << S_PRIdCoID)
++#define S_PRIdImp	8		/* Implementation ID (R) */
++#define M_PRIdImp	(0xff << S_PRIdImp)
++
++#define K_CacheAttrCWTnWA	0	/* Cacheable, write-thru, no write allocate */
++#define K_CacheAttrCWTWA	1	/* Cacheable, write-thru, write allocate */
++#define K_CacheAttrU		2	/* Uncached */
++#define K_CacheAttrC		3	/* Cacheable */
++#define K_CacheAttrCN		3	/* Cacheable, non-coherent */
++#define K_CacheAttrCCE		4	/* Cacheable, coherent, exclusive */
++#define K_CacheAttrCCS		5	/* Cacheable, coherent, shared */
++#define K_CacheAttrCCU		6	/* Cacheable, coherent, update */
++#define K_CacheAttrUA		7	/* Uncached accelerated */
++
++#define S_ConfigK23		28	/* Kseg2/3 coherency algorithm (FM MMU only) (R/W) */
++#define M_ConfigK23		(0x7 << S_ConfigK23)
++#define W_ConfigK23		3
++#define S_ConfigKU		25	/* Kuseg coherency algorithm (FM MMU only) (R/W) */
++#define M_ConfigKU		(0x7 << S_ConfigKU)
++#define W_ConfigKU		3
++
++#define S_ConfigMM		18	/* Merge mode (implementation specific) */
++#define M_ConfigMM		(0x1 << S_ConfigMM)
++
++#define S_StatusBEV		22	/* Enable Boot Exception Vectors (R/W) */
++#define M_StatusBEV		(0x1 << S_StatusBEV)
++
++#define S_StatusFR		26	/* Enable 64-bit FPRs (R/W) */
++#define M_StatusFR		(0x1 << S_StatusFR)
++
++#define S_ConfigK0		0	/* Kseg0 coherency algorithm (R/W) */
++#define M_ConfigK0		(0x7 << S_ConfigK0)
++
++#define CONFIG0_MIPS32_64_MSK	0x8000ffff
++#define STATUS_MIPS32_64_MSK	0xfffcffff
++
++#define STATUS_MIPS24K		0
++#define CONFIG0_MIPS24K		((K_CacheAttrCN << S_ConfigK23) |\
++				(K_CacheAttrCN << S_ConfigKU)  |\
++				(M_ConfigMM))
++
++#define STATUS_MIPS34K		0
++#define CONFIG0_MIPS34K		((K_CacheAttrCN << S_ConfigK23) |\
++				(K_CacheAttrCN << S_ConfigKU) |\
++				(M_ConfigMM))
++
++#define STATUS_MIPS32_64	(M_StatusBEV | M_StatusFR)
++#define CONFIG0_MIPS32_64	(K_CacheAttrCN << S_ConfigK0)
++
++#ifdef CONFIG_SOC_XWAY_DANUBE
++#define CONFIG0_LANTIQ		(CONFIG0_MIPS24K | CONFIG0_MIPS32_64)
++#define STATUS_LANTIQ		(STATUS_MIPS24K | STATUS_MIPS32_64)
++#endif
++
++#ifdef CONFIG_SOC_XWAY_VRX200
++#define CONFIG0_LANTIQ		(CONFIG0_MIPS34K | CONFIG0_MIPS32_64)
++#define STATUS_LANTIQ		(STATUS_MIPS34K | STATUS_MIPS32_64)
++#endif
++
++
++	.set noreorder
++
++	.globl _start
++	.text
++_start:
++	/* Entry point */
++	b	main
++	 nop
++
++	/* Lantiq SoC Boot config word */
++	.org	0x10
++#ifdef CONFIG_SYS_XWAY_EBU_BOOTCFG
++	.word	CONFIG_SYS_XWAY_EBU_BOOTCFG
++#else
++	.word	0
++#endif
++	.word	0
++
++	.align	4
++main:
++
++	/* Init Timer */
++	mtc0	zero, CP0_COUNT
++	mtc0	zero, CP0_COMPARE
++
++	/* Setup MIPS24K/MIPS34K specifics (implementation dependent fields) */
++	mfc0	t0, CP0_CONFIG
++	li	t1, CONFIG0_MIPS32_64_MSK
++	and	t0, t1
++	li	t1, CONFIG0_LANTIQ
++	or	t0, t1
++	mtc0	t0, CP0_CONFIG
++
++	mfc0	t0, CP0_STATUS
++	li	t1, STATUS_MIPS32_64_MSK
++	and	t0, t1
++	li	t1, STATUS_LANTIQ
++	or	t0, t1
++	mtc0	t0, CP0_STATUS
++
++	/* Initialize CGU */
++	la	t9, ltq_cgu_init
++	jalr	t9
++	 nop
++
++	/* Initialize memory controller */
++	la	t9, ltq_mem_init
++	jalr	t9
++	 nop
++
++	/* Initialize caches... */
++	la	t9, mips_cache_reset
++	jalr	t9
++	 nop
++
++	/* Clear BSS */
++	la	t1, __bss_start
++	la	t2, __bss_end
++	sub	t1, 4
++1:
++	addi	t1, 4
++	bltl	t1, t2, 1b
++	 sw	zero, 0(t1)
++
++	/* Setup stack pointer and force alignment on a 16 byte boundary */
++	li	t0, (CONFIG_SPL_STACK_BASE & ~0xF)
++	la	sp, 0(t0)
++
++	la	t9, spl_lantiq_init
++	jr	t9
++	 nop
+--- /dev/null
++++ b/arch/mips/cpu/mips32/lantiq-common/u-boot-spl.lds
+@@ -0,0 +1,48 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++MEMORY { .spl_mem : ORIGIN = CONFIG_SPL_TEXT_BASE, \
++		LENGTH = CONFIG_SPL_MAX_SIZE }
++MEMORY { .bss_mem : ORIGIN = CONFIG_SPL_BSS_BASE, \
++		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
++
++OUTPUT_FORMAT("elf32-tradbigmips", "elf32-tradbigmips", "elf32-tradlittlemips")
++OUTPUT_ARCH(mips)
++ENTRY(_start)
++SECTIONS
++{
++	. = ALIGN(4);
++	.text : {
++		*(.text*)
++	} > .spl_mem
++
++	. = ALIGN(4);
++	.rodata : {
++		*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*)))
++	} > .spl_mem
++
++	. = ALIGN(4);
++	.data : {
++		*(SORT_BY_ALIGNMENT(.data*))
++		*(SORT_BY_ALIGNMENT(.sdata*))
++	} > .spl_mem
++
++	. = ALIGN(4);
++	__image_copy_end = .;
++	uboot_end_data = .;
++
++	.bss : {
++		__bss_start = .;
++		*(.bss*)
++		*(.sbss*)
++		. = ALIGN(4);
++		__bss_end = .;
++	} > .bss_mem
++
++	. = ALIGN(4);
++	__end = .;
++	uboot_end = .;
++}
+--- a/arch/mips/cpu/mips32/start.S
++++ b/arch/mips/cpu/mips32/start.S
+@@ -105,7 +105,7 @@ reset:
+ 	mtc0	zero, CP0_COUNT
+ 	mtc0	zero, CP0_COMPARE
+ 
+-#ifndef CONFIG_SKIP_LOWLEVEL_INIT
++#if !defined(CONFIG_SKIP_LOWLEVEL_INIT) || defined(CONFIG_SYS_DISABLE_CACHE)
+ 	/* CONFIG0 register */
+ 	li	t0, CONF_CM_UNCACHED
+ 	mtc0	t0, CP0_CONFIG
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/Makefile
+@@ -0,0 +1,32 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(SOC).o
++
++COBJS-y	+= cgu.o chipid.o dcdc.o ebu.o gphy.o mem.o pmu.o rcu.o
++SOBJS-y	+= cgu_init.o mem_init.o
++SOBJS-y	+= gphy_fw.o
++
++COBJS	:= $(COBJS-y)
++SOBJS	:= $(SOBJS-y)
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
++
++all:	$(LIB)
++
++$(LIB):	$(obj).depend $(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/cgu.c
+@@ -0,0 +1,208 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/gphy.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/io.h>
++
++#define LTQ_CGU_PLL1_PLLN_SHIFT		6
++#define LTQ_CGU_PLL1_PLLN_MASK		(0x3F << LTQ_CGU_PLL1_PLLN_SHIFT)
++#define LTQ_CGU_PLL1_PLLM_SHIFT		2
++#define LTQ_CGU_PLL1_PLLM_MASK		(0xF << LTQ_CGU_PLL1_PLLM_SHIFT)
++#define LTQ_CGU_PLL1_PLLL		(1 << 1)
++#define LTQ_CGU_PLL1_PLL_EN		1
++
++#define LTQ_CGU_SYS_OCP_SHIFT		0
++#define LTQ_CGU_SYS_OCP_MASK		(0x3 << LTQ_CGU_SYS_OCP_SHIFT)
++#define LTQ_CGU_SYS_CPU_SHIFT		4
++#define LTQ_CGU_SYS_CPU_MASK		(0xF << LTQ_CGU_SYS_CPU_SHIFT)
++
++#define LTQ_CGU_UPDATE			1
++
++#define LTQ_CGU_IFCLK_GPHY_SEL_SHIFT	2
++#define LTQ_CGU_IFCLK_GPHY_SEL_MASK	(0x7 << LTQ_CGU_IFCLK_GPHY_SEL_SHIFT)
++
++struct ltq_cgu_regs {
++	u32	rsvd0;
++	u32	pll0_cfg;	/* PLL0 config */
++	u32	pll1_cfg;	/* PLL1 config */
++	u32	sys;		/* System clock */
++	u32	clk_fsr;	/* Clock frequency select */
++	u32	clk_gsr;	/* Clock gating status */
++	u32	clk_gcr0;	/* Clock gating control 0 */
++	u32	clk_gcr1;	/* Clock gating control 1 */
++	u32	update;		/* CGU update control */
++	u32	if_clk;		/* Interface clock */
++	u32	ddr;		/* DDR memory control */
++	u32	ct1_sr;		/* CT status 1 */
++	u32	ct_kval;	/* CT K value */
++	u32	pcm_cr;		/* PCM control */
++	u32	pci_cr;		/* PCI clock control */
++	u32	rsvd1;
++	u32	gphy1_cfg;	/* GPHY1 config */
++	u32	gphy0_cfg;	/* GPHY0 config */
++	u32	rsvd2[6];
++	u32	pll2_cfg;	/* PLL2 config */
++};
++
++static struct ltq_cgu_regs *ltq_cgu_regs =
++	(struct ltq_cgu_regs *) CKSEG1ADDR(LTQ_CGU_BASE);
++
++static inline u32 ltq_cgu_sys_readl(u32 mask, u32 shift)
++{
++	return (ltq_readl(&ltq_cgu_regs->sys) & mask) >> shift;
++}
++
++unsigned long ltq_get_io_region_clock(void)
++{
++	unsigned int ocp_sel;
++	unsigned long clk, cpu_clk;
++
++	cpu_clk = ltq_get_cpu_clock();
++
++	ocp_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_OCP_MASK,
++			LTQ_CGU_SYS_OCP_SHIFT);
++
++	switch (ocp_sel) {
++	case 0:
++		/* OCP ratio 1 */
++		clk = cpu_clk;
++		break;
++	case 2:
++		/* OCP ratio 2 */
++		clk = cpu_clk / 2;
++		break;
++	case 3:
++		/* OCP ratio 2.5 */
++		clk = (cpu_clk * 2) / 5;
++		break;
++	case 4:
++		/* OCP ratio 3 */
++		clk = cpu_clk / 3;
++		break;
++	default:
++		clk = 0;
++		break;
++	}
++
++	return clk;
++}
++
++unsigned long ltq_get_cpu_clock(void)
++{
++	unsigned int cpu_sel;
++	unsigned long clk;
++
++	cpu_sel = ltq_cgu_sys_readl(LTQ_CGU_SYS_CPU_MASK,
++			LTQ_CGU_SYS_CPU_SHIFT);
++
++	switch (cpu_sel) {
++	case 0:
++		clk = CLOCK_600_MHZ;
++		break;
++	case 1:
++		clk = CLOCK_500_MHZ;
++		break;
++	case 2:
++		clk = CLOCK_393_MHZ;
++		break;
++	case 3:
++		clk = CLOCK_333_MHZ;
++		break;
++	case 5:
++	case 6:
++		clk = CLOCK_197_MHZ;
++		break;
++	case 7:
++		clk = CLOCK_166_MHZ;
++		break;
++	case 4:
++	case 8:
++	case 9:
++		clk = CLOCK_125_MHZ;
++		break;
++	default:
++		clk = 0;
++		break;
++	}
++
++	return clk;
++}
++
++unsigned long ltq_get_bus_clock(void)
++{
++	return ltq_get_io_region_clock();
++}
++
++void ltq_cgu_gphy_clk_src(enum ltq_gphy_clk clk)
++{
++	ltq_clrbits(&ltq_cgu_regs->if_clk, LTQ_CGU_IFCLK_GPHY_SEL_MASK);
++	ltq_setbits(&ltq_cgu_regs->if_clk, clk << LTQ_CGU_IFCLK_GPHY_SEL_SHIFT);
++}
++
++static inline int ltq_cgu_pll1_locked(void)
++{
++	u32 pll1_cfg = ltq_readl(&ltq_cgu_regs->pll1_cfg);
++
++	return pll1_cfg & LTQ_CGU_PLL1_PLLL;
++}
++
++static inline void ltq_cgu_pll1_restart(unsigned m, unsigned n)
++{
++	u32 pll1_cfg;
++
++	ltq_clrbits(&ltq_cgu_regs->pll1_cfg, LTQ_CGU_PLL1_PLL_EN);
++	ltq_setbits(&ltq_cgu_regs->update, LTQ_CGU_UPDATE);
++
++	pll1_cfg = ltq_readl(&ltq_cgu_regs->pll1_cfg);
++	pll1_cfg &= ~(LTQ_CGU_PLL1_PLLN_MASK | LTQ_CGU_PLL1_PLLM_MASK);
++	pll1_cfg |= n << LTQ_CGU_PLL1_PLLN_SHIFT;
++	pll1_cfg |= m << LTQ_CGU_PLL1_PLLM_SHIFT;
++	pll1_cfg |= LTQ_CGU_PLL1_PLL_EN;
++	ltq_writel(&ltq_cgu_regs->pll1_cfg, pll1_cfg);
++	ltq_setbits(&ltq_cgu_regs->update, LTQ_CGU_UPDATE);
++
++	__udelay(1000);
++}
++
++/*
++ * From chapter 9 in errata sheet:
++ *
++ * Under certain condition, the PLL1 may failed to enter into lock
++ * status by hardware default N, M setting.
++ *
++ * Since system always starts from PLL0, the system software can run
++ * and re-program the PLL1 settings.
++ */
++static void ltq_cgu_pll1_init(void)
++{
++	unsigned i;
++	const unsigned pll1_m[] = { 1, 2, 3, 4 };
++	const unsigned pll1_n[] = { 21, 32, 43, 54 };
++
++	/* Check if PLL1 has locked with hardware default settings */
++	if (ltq_cgu_pll1_locked())
++		return;
++
++	for (i = 0; i < 4; i++) {
++		ltq_cgu_pll1_restart(pll1_m[i], pll1_n[i]);
++
++		if (ltq_cgu_pll1_locked())
++			goto done;
++	}
++
++done:
++	/* Restart with hardware default values M=5, N=64 */
++	ltq_cgu_pll1_restart(5, 64);
++}
++
++void ltq_pll_init(void)
++{
++	ltq_cgu_pll1_init();
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/cgu_init.S
+@@ -0,0 +1,119 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* RCU module register */
++#define LTQ_RCU_RST_REQ			0x0010	/* Reset request */
++#define LTQ_RCU_RST_REQ_VALUE		((1 << 14) | (1 << 1))
++
++/* CGU module register */
++#define LTQ_CGU_PLL0_CFG		0x0004	/* PLL0 config */
++#define LTQ_CGU_PLL1_CFG		0x0008	/* PLL1 config */
++#define LTQ_CGU_PLL2_CFG		0x0060	/* PLL2 config */
++#define LTQ_CGU_SYS			0x000C	/* System clock */
++#define LTQ_CGU_CLK_FSR			0x0010	/* Clock frequency select */
++#define LTQ_CGU_UPDATE			0x0020	/* Clock update control */
++
++/* Valid SYS.CPU values */
++#define LTQ_CGU_SYS_CPU_SHIFT		4
++#define LTQ_CGU_SYS_CPU_600_MHZ		0x0
++#define LTQ_CGU_SYS_CPU_500_MHZ		0x1
++#define LTQ_CGU_SYS_CPU_393_MHZ		0x2
++#define LTQ_CGU_SYS_CPU_333_MHZ		0x3
++#define LTQ_CGU_SYS_CPU_197_MHZ		0x5
++#define LTQ_CGU_SYS_CPU_166_MHZ		0x7
++#define LTQ_CGU_SYS_CPU_125_MHZ		0x9
++
++/* Valid SYS.OCP values */
++#define LTQ_CGU_SYS_OCP_SHIFT		0
++#define LTQ_CGU_SYS_OCP_1		0x0
++#define LTQ_CGU_SYS_OCP_2		0x2
++#define LTQ_CGU_SYS_OCP_2_5		0x3
++#define LTQ_CGU_SYS_OCP_3		0x4
++
++/* Valid CLK_FSR.ETH values */
++#define LTQ_CGU_CLK_FSR_ETH_SHIFT	24
++#define LTQ_CGU_CLK_FSR_ETH_50_MHZ	0x0
++#define LTQ_CGU_CLK_FSR_ETH_25_MHZ	0x1
++#define LTQ_CGU_CLK_FSR_ETH_2_5_MHZ	0x2
++#define LTQ_CGU_CLK_FSR_ETH_125_MHZ	0x3
++
++/* Valid CLK_FSR.PPE values */
++#define LTQ_CGU_CLK_FSR_PPE_SHIFT	16
++#define LTQ_CGU_CLK_FSR_PPE_500_MHZ	0x0	/* Overclock frequency */
++#define LTQ_CGU_CLK_FSR_PPE_450_MHZ	0x1	/* High frequency */
++#define LTQ_CGU_CLK_FSR_PPE_400_MHZ	0x2	/* Low frequency */
++
++#if (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_500_DDR_250)
++#define LTQ_CGU_SYS_CPU_CONFIG		LTQ_CGU_SYS_CPU_500_MHZ
++#define LTQ_CGU_SYS_OCP_CONFIG		LTQ_CGU_SYS_OCP_2
++#define LTQ_CGU_CLK_FSR_ETH_CONFIG	LTQ_CGU_CLK_FSR_ETH_125_MHZ
++#define LTQ_CGU_CLK_FSR_PPE_CONFIG	LTQ_CGU_CLK_FSR_PPE_450_MHZ
++#else
++#error "Invalid system clock configuration!"
++#endif
++
++/* Build register values */
++#define LTQ_CGU_SYS_VALUE	((LTQ_CGU_SYS_CPU_CONFIG << \
++					LTQ_CGU_SYS_CPU_SHIFT) | \
++					LTQ_CGU_SYS_OCP_CONFIG)
++
++#define LTQ_CGU_CLK_FSR_VALUE	((LTQ_CGU_CLK_FSR_ETH_CONFIG << \
++					LTQ_CGU_CLK_FSR_ETH_SHIFT) | \
++				(LTQ_CGU_CLK_FSR_PPE_CONFIG << \
++					LTQ_CGU_CLK_FSR_PPE_SHIFT))
++
++	.set noreorder
++
++LEAF(ltq_cgu_init)
++	/* Load current CGU register values */
++	li	t0, (LTQ_CGU_BASE | KSEG1)
++	lw	t1, LTQ_CGU_SYS(t0)
++	lw	t2, LTQ_CGU_CLK_FSR(t0)
++
++	/* Load target CGU register values */
++	li	t3, LTQ_CGU_SYS_VALUE
++	li	t4, LTQ_CGU_CLK_FSR_VALUE
++
++	/* Only update registers if values differ */
++	bne	t1, t3, update
++	 nop
++	beq	t2, t4, finished
++	 nop
++
++update:
++	/* Store target register values */
++	sw	t3, LTQ_CGU_SYS(t0)
++	sw	t4, LTQ_CGU_CLK_FSR(t0)
++
++	/* Perform software reset to activate new clock config */
++#if 0
++	li	t0, (LTQ_RCU_BASE | KSEG1)
++	lw	t1, LTQ_RCU_RST_REQ(t0)
++	or	t1, LTQ_RCU_RST_REQ_VALUE
++	sw	t1, LTQ_RCU_RST_REQ(t0)
++#else
++	li	t1, 1
++	sw	t1, LTQ_CGU_UPDATE(t0)
++#endif
++
++#if 0
++wait_reset:
++	b	wait_reset
++	 nop
++#endif
++
++finished:
++	jr	ra
++	 nop
++
++	END(ltq_cgu_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/chipid.c
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_CHIPID_VERSION_SHIFT	28
++#define LTQ_CHIPID_VERSION_MASK		(0x7 << LTQ_CHIPID_VERSION_SHIFT)
++#define LTQ_CHIPID_PNUM_SHIFT		12
++#define LTQ_CHIPID_PNUM_MASK		(0xFFFF << LTQ_CHIPID_PNUM_SHIFT)
++
++struct ltq_chipid_regs {
++	u32	manid;		/* Manufacturer identification */
++	u32	chipid;		/* Chip identification */
++};
++
++static struct ltq_chipid_regs *ltq_chipid_regs =
++	(struct ltq_chipid_regs *) CKSEG1ADDR(LTQ_CHIPID_BASE);
++
++unsigned int ltq_chip_version_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_VERSION_MASK) >> LTQ_CHIPID_VERSION_SHIFT;
++}
++
++unsigned int ltq_chip_partnum_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_PNUM_MASK) >> LTQ_CHIPID_PNUM_SHIFT;
++}
++
++const char *ltq_chip_partnum_str(void)
++{
++	enum ltq_chip_partnum partnum = ltq_chip_partnum_get();
++
++	switch (partnum) {
++	case LTQ_SOC_VRX268:
++	case LTQ_SOC_VRX268_2:
++		return "VRX268";
++	case LTQ_SOC_VRX288:
++	case LTQ_SOC_VRX288_2:
++		return "VRX288";
++	case LTQ_SOC_GRX288:
++	case LTQ_SOC_GRX288_2:
++		return "GRX288";
++	default:
++		printf("Unknown partnum: %x\n", partnum);
++	}
++
++	return "";
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/config.mk
+@@ -0,0 +1,30 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PF_CPPFLAGS_XRX := $(call cc-option,-mtune=34kc,)
++PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_XRX)
++
++ifdef CONFIG_SPL_BUILD
++PF_ABICALLS		:= -mno-abicalls
++PF_PIC			:= -fno-pic
++PF_PIE			:=
++USE_PRIVATE_LIBGCC	:= yes
++endif
++
++LIBS-y += $(CPUDIR)/lantiq-common/liblantiq-common.o
++
++ifndef CONFIG_SPL_BUILD
++ifdef CONFIG_SYS_BOOT_SFSPL
++ALL-y += $(obj)u-boot.ltq.sfspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.sfspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.sfspl
++endif
++ifdef CONFIG_SYS_BOOT_NORSPL
++ALL-y += $(obj)u-boot.ltq.norspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
++endif
++endif
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/dcdc.c
+@@ -0,0 +1,106 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++#define LTQ_DCDC_CLK_SET0_CLK_SEL_P		(1 << 6)
++#define LTQ_DCDC_CLK_SET1_SEL_DIV25		(1 << 5)
++#define LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE	(1 << 5)
++
++struct ltq_dcdc_regs {
++	u8	b0_coeh;		/* Coefficient b0 */
++	u8	b0_coel;		/* Coefficient b0 */
++	u8	b1_coeh;		/* Coefficient b1 */
++	u8	b1_coel;		/* Coefficient b1 */
++	u8	b2_coeh;		/* Coefficient b2 */
++	u8	b2_coel;		/* Coefficient b2 */
++	u8	clk_set0;		/* Clock setup */
++	u8	clk_set1;		/* Clock setup */
++	u8	pwm_confh;		/* Configure PWM */
++	u8	pwm_confl;		/* Configure PWM */
++	u8	bias_vreg0;		/* Bias and regulator setup */
++	u8	bias_vreg1;		/* Bias and regulator setup */
++	u8	adc_gen0;		/* ADC and general control */
++	u8	adc_gen1;		/* ADC and general control */
++	u8	adc_con0;		/* ADC and general config */
++	u8	adc_con1;		/* ADC and general config */
++	u8	conf_test_ana;		/* not documented */
++	u8	conf_test_dig;		/* not documented */
++	u8	dcdc_status;		/* not documented */
++	u8	pid_status;		/* not documented */
++	u8	duty_cycle;		/* not documented */
++	u8	non_ov_delay;		/* not documented */
++	u8	analog_gain;		/* not documented */
++	u8	duty_cycle_max_sat;	/* not documented */
++	u8	duty_cycle_min_sat;	/* not documented */
++	u8	duty_cycle_max;		/* not documented */
++	u8	duty_cycle_min;		/* not documented */
++	u8	error_max;		/* not documented */
++	u8	error_read;		/* not documented */
++	u8	delay_deglitch;		/* not documented */
++	u8	latch_control;		/* not documented */
++	u8	rsvd[240];
++	u8	osc_conf;		/* OSC general config */
++	u8	osc_stat;		/* OSC general status */
++};
++
++static struct ltq_dcdc_regs *ltq_dcdc_regs =
++	(struct ltq_dcdc_regs *) CKSEG1ADDR(LTQ_DCDC_BASE);
++
++void ltq_dcdc_init(unsigned int dig_ref)
++{
++	u8 dig_ref_cur, val;
++
++	/* Set duty cycle max sat. to 70/90, enable PID freeze */
++	ltq_writeb(&ltq_dcdc_regs->duty_cycle_max_sat, 0x5A);
++	ltq_writeb(&ltq_dcdc_regs->duty_cycle_min_sat, 0x46);
++	val = ltq_readb(&ltq_dcdc_regs->conf_test_dig);
++	val |= LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE;
++	ltq_writeb(&ltq_dcdc_regs->conf_test_dig, val);
++
++	/* Program new coefficients */
++	ltq_writeb(&ltq_dcdc_regs->b0_coeh, 0x00);
++	ltq_writeb(&ltq_dcdc_regs->b0_coel, 0x00);
++	ltq_writeb(&ltq_dcdc_regs->b1_coeh, 0xFF);
++	ltq_writeb(&ltq_dcdc_regs->b1_coel, 0xE6);
++	ltq_writeb(&ltq_dcdc_regs->b2_coeh, 0x00);
++	ltq_writeb(&ltq_dcdc_regs->b2_coel, 0x1B);
++	ltq_writeb(&ltq_dcdc_regs->non_ov_delay, 0x8B);
++
++	/* Set duty cycle max sat. to 60/108, disable PID freeze */
++	ltq_writeb(&ltq_dcdc_regs->duty_cycle_max_sat, 0x6C);
++	ltq_writeb(&ltq_dcdc_regs->duty_cycle_min_sat, 0x3C);
++	val = ltq_readb(&ltq_dcdc_regs->conf_test_dig);
++	val &= ~LTQ_DCDC_CONF_TEST_DIG_PID_FREEZE;
++	ltq_writeb(&ltq_dcdc_regs->conf_test_dig, val);
++
++	/* Init clock and DLL settings */
++	val = ltq_readb(&ltq_dcdc_regs->clk_set0);
++	val |= LTQ_DCDC_CLK_SET0_CLK_SEL_P;
++	ltq_writeb(&ltq_dcdc_regs->clk_set0, val);
++	val = ltq_readb(&ltq_dcdc_regs->clk_set1);
++	val |= LTQ_DCDC_CLK_SET1_SEL_DIV25;
++	ltq_writeb(&ltq_dcdc_regs->clk_set1, val);
++	ltq_writeb(&ltq_dcdc_regs->pwm_confh, 0xF9);
++
++	wmb();
++
++	/* Adapt value of digital reference of DCDC converter */
++	dig_ref_cur = ltq_readb(&ltq_dcdc_regs->bias_vreg1);
++
++	while (dig_ref_cur != dig_ref) {
++		if (dig_ref >= dig_ref_cur)
++			dig_ref_cur++;
++		else if (dig_ref < dig_ref_cur)
++			dig_ref_cur--;
++
++		ltq_writeb(&ltq_dcdc_regs->bias_vreg1, dig_ref_cur);
++		__udelay(1000);
++	}
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/ebu.c
+@@ -0,0 +1,126 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++#define EBU_ADDRSEL_MASK(mask)		((mask & 0xf) << 4)
++#define EBU_ADDRSEL_REGEN		(1 << 0)
++
++#define EBU_CON_WRDIS			(1 << 31)
++#define EBU_CON_AGEN_DEMUX		(0x0 << 24)
++#define EBU_CON_AGEN_MUX		(0x2 << 24)
++#define EBU_CON_SETUP			(1 << 22)
++#define EBU_CON_WAIT_DIS		(0x0 << 20)
++#define EBU_CON_WAIT_ASYNC		(0x1 << 20)
++#define EBU_CON_WAIT_SYNC		(0x2 << 20)
++#define EBU_CON_WINV			(1 << 19)
++#define EBU_CON_PW_8BIT			(0x0 << 16)
++#define EBU_CON_PW_16BIT		(0x1 << 16)
++#define EBU_CON_ALEC(cycles)		((cycles & 0x3) << 14)
++#define EBU_CON_BCGEN_CS		(0x0 << 12)
++#define EBU_CON_BCGEN_INTEL		(0x1 << 12)
++#define EBU_CON_BCGEN_MOTOROLA		(0x2 << 12)
++#define EBU_CON_WAITWRC(cycles)		((cycles & 0x7) << 8)
++#define EBU_CON_WAITRDC(cycles)		((cycles & 0x3) << 6)
++#define EBU_CON_HOLDC(cycles)		((cycles & 0x3) << 4)
++#define EBU_CON_RECOVC(cycles)		((cycles & 0x3) << 2)
++#define EBU_CON_CMULT_1			0x0
++#define EBU_CON_CMULT_4			0x1
++#define EBU_CON_CMULT_8			0x2
++#define EBU_CON_CMULT_16		0x3
++
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define ebu_region0_enable		1
++#else
++#define ebu_region0_enable		0
++#endif
++
++#if ((CONFIG_SYS_MAX_FLASH_BANKS == 2) && defined(CONFIG_LTQ_SUPPORT_NOR_FLASH) )
++#define ebu_region0_addrsel_mask	3
++#else
++#define ebu_region0_addrsel_mask	1
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH) || ((CONFIG_SYS_MAX_FLASH_BANKS == 2) && defined(CONFIG_LTQ_SUPPORT_NOR_FLASH) )
++#define ebu_region1_enable		1
++#else
++#define ebu_region1_enable		0
++#endif
++
++struct ltq_ebu_regs {
++	u32	clc;
++	u32	rsvd0;
++	u32	id;
++	u32	rsvd1;
++	u32	con;
++	u32	rsvd2[3];
++	u32	addr_sel_0;
++	u32	addr_sel_1;
++	u32	addr_sel_2;
++	u32	addr_sel_3;
++	u32	rsvd3[12];
++	u32	con_0;
++	u32	con_1;
++	u32	con_2;
++	u32	con_3;
++};
++
++static struct ltq_ebu_regs *ltq_ebu_regs =
++	(struct ltq_ebu_regs *) CKSEG1ADDR(LTQ_EBU_BASE);
++
++void ltq_ebu_init(void)
++{
++	if (ebu_region0_enable) {
++		/*
++		 * Map EBU region 0 to range 0x10000000-0x13ffffff and enable
++		 * region control. This supports up to 32 MiB NOR flash in
++		 * bank 0.
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_0, LTQ_EBU_REGION0_BASE |
++			EBU_ADDRSEL_MASK(ebu_region0_addrsel_mask) | EBU_ADDRSEL_REGEN);
++
++		ltq_writel(&ltq_ebu_regs->con_0, EBU_CON_AGEN_DEMUX |
++			EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
++			EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++			EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
++			EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
++			EBU_CON_CMULT_16);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_0, EBU_ADDRSEL_REGEN);
++
++	if (ebu_region1_enable) {
++		/*
++		 * Map EBU region 1 to range 0x14000000-0x13ffffff and enable
++		 * region control. This supports NAND flash in bank 1. (and  NOR flash in bank 2)
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_1, LTQ_EBU_REGION1_BASE |
++			EBU_ADDRSEL_MASK(3) | EBU_ADDRSEL_REGEN);
++
++		if (ebu_region0_addrsel_mask == 1)
++			ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
++				EBU_CON_SETUP | EBU_CON_WAIT_DIS | EBU_CON_PW_8BIT |
++				EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++				EBU_CON_WAITWRC(2) | EBU_CON_WAITRDC(2) |
++				EBU_CON_HOLDC(1) | EBU_CON_RECOVC(1) |
++				EBU_CON_CMULT_4);
++
++		if (ebu_region0_addrsel_mask == 3)
++			ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
++				EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
++				EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++				EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
++				EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
++				EBU_CON_CMULT_16);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_1, EBU_ADDRSEL_REGEN);
++}
++
++void *flash_swap_addr(unsigned long addr)
++{
++	return (void *)(addr ^ 2);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/gphy.c
+@@ -0,0 +1,68 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/gphy.h>
++#include <lzma/LzmaTypes.h>
++#include <lzma/LzmaDec.h>
++#include <lzma/LzmaTools.h>
++
++static inline void ltq_gphy_decompress(const void *fw_start, const void *fw_end,
++				ulong dst_addr)
++{
++	const ulong fw_len = (ulong) fw_end - (ulong) fw_start;
++	const ulong addr = CKSEG1ADDR(dst_addr);
++
++	debug("ltq_gphy_decompress: addr %08lx, fw_start %p, fw_end %p\n",
++		addr, fw_start, fw_end);
++
++	SizeT lzma_len = 65536;
++	int ret = lzmaBuffToBuffDecompress(
++	(unsigned char *)addr, &lzma_len,
++	(unsigned char *)fw_start, fw_len);
++}
++
++void ltq_gphy_phy11g_a1x_load(ulong addr)
++{
++	extern ulong __ltq_fw_phy11g_a1x_start;
++	extern ulong __ltq_fw_phy11g_a1x_end;
++
++	ltq_gphy_decompress(&__ltq_fw_phy11g_a1x_start,
++			    &__ltq_fw_phy11g_a1x_end,
++			    addr);
++}
++
++void ltq_gphy_phy11g_a2x_load(ulong addr)
++{
++	extern ulong __ltq_fw_phy11g_a2x_start;
++	extern ulong __ltq_fw_phy11g_a2x_end;
++
++	ltq_gphy_decompress(&__ltq_fw_phy11g_a2x_start,
++			    &__ltq_fw_phy11g_a2x_end,
++			    addr);
++}
++
++void ltq_gphy_phy22f_a1x_load(ulong addr)
++{
++	extern ulong __ltq_fw_phy22f_a1x_start;
++	extern ulong __ltq_fw_phy22f_a1x_end;
++
++	ltq_gphy_decompress(&__ltq_fw_phy22f_a1x_start,
++			    &__ltq_fw_phy22f_a1x_end,
++			    addr);
++}
++
++void ltq_gphy_phy22f_a2x_load(ulong addr)
++{
++	extern ulong __ltq_fw_phy22f_a2x_start;
++	extern ulong __ltq_fw_phy22f_a2x_end;
++
++	ltq_gphy_decompress(&__ltq_fw_phy22f_a2x_start,
++			    &__ltq_fw_phy22f_a2x_end,
++			    addr);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/gphy_fw.S
+@@ -0,0 +1,27 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <asm/asm.h>
++
++	.section .rodata.__ltq_fw_phy11g_a1x
++EXPORT(__ltq_fw_phy11g_a1x_start)
++	.incbin "fw_phy11g_a1x.blob"
++EXPORT(__ltq_fw_phy11g_a1x_end)
++
++	.section .rodata.__ltq_fw_phy11g_a2x
++EXPORT(__ltq_fw_phy11g_a2x_start)
++	.incbin "fw_phy11g_a2x.blob"
++EXPORT(__ltq_fw_phy11g_a2x_end)
++
++	.section .rodata.__ltq_fw_phy22f_a1x
++EXPORT(__ltq_fw_phy22f_a1x_start)
++	.incbin "fw_phy22f_a1x.blob"
++EXPORT(__ltq_fw_phy22f_a1x_end)
++
++	.section .rodata.__ltq_fw_phy22f_a2x
++EXPORT(__ltq_fw_phy22f_a2x_start)
++	.incbin "fw_phy22f_a2x.blob"
++EXPORT(__ltq_fw_phy22f_a2x_end)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/mem.c
+@@ -0,0 +1,57 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++#define LTQ_CCR03_EIGHT_BANK_MODE	(1 << 0)
++#define LTQ_CCR08_CS_MAP_SHIFT		24
++#define LTQ_CCR08_CS_MAP_MASK		(0x3 << LTQ_CCR08_CS_MAP_SHIFT)
++#define LTQ_CCR11_COLUMN_SIZE_SHIFT	24
++#define LTQ_CCR11_COLUMN_SIZE_MASK	(0x7 << LTQ_CCR11_COLUMN_SIZE_SHIFT)
++#define LTQ_CCR11_ADDR_PINS_MASK	0x7
++#define LTQ_CCR15_MAX_COL_REG_SHIFT	24
++#define LTQ_CCR15_MAX_COL_REG_MASK	(0xF << LTQ_CCR15_MAX_COL_REG_SHIFT)
++#define LTQ_CCR16_MAX_ROW_REG_MASK	0xF
++
++static void *ltq_mc_ddr_base = (void *) CKSEG1ADDR(LTQ_MC_DDR_BASE);
++
++static inline u32 ltq_mc_ccr_read(u32 index)
++{
++	return ltq_readl(ltq_mc_ddr_base + LTQ_MC_DDR_CCR_OFFSET(index));
++}
++
++phys_size_t initdram(int board_type)
++{
++	u32 max_col_reg, max_row_reg, column_size, addr_pins;
++	u32 banks, cs_map;
++	phys_size_t size;
++
++	banks = (ltq_mc_ccr_read(3) & LTQ_CCR03_EIGHT_BANK_MODE) ? 8 : 4;
++
++	cs_map = (ltq_mc_ccr_read(8) & LTQ_CCR08_CS_MAP_MASK) >>
++		LTQ_CCR08_CS_MAP_SHIFT;
++
++	column_size = (ltq_mc_ccr_read(11) & LTQ_CCR11_COLUMN_SIZE_MASK) >>
++		LTQ_CCR11_COLUMN_SIZE_SHIFT;
++
++	addr_pins = ltq_mc_ccr_read(11) & LTQ_CCR11_ADDR_PINS_MASK;
++
++	max_col_reg = (ltq_mc_ccr_read(15) & LTQ_CCR15_MAX_COL_REG_MASK) >>
++		LTQ_CCR15_MAX_COL_REG_SHIFT;
++
++	max_row_reg = ltq_mc_ccr_read(16) & LTQ_CCR16_MAX_ROW_REG_MASK;
++
++	/*
++	 * size (bytes) = 2 ^ rowsize * 2 ^ colsize * banks * chipselects
++	 *                 * datawidth (bytes)
++	 */
++	size = (2 << (max_col_reg - column_size - 1)) *
++		(2 << (max_row_reg - addr_pins - 1)) * banks * cs_map * 2;
++
++	return size;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/mem_init.S
+@@ -0,0 +1,233 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* Must be configured in BOARDDIR */
++#include <ddr_settings.h>
++
++#define LTQ_MC_DDR_START		(1 << 8)
++#define LTQ_MC_DDR_DLL_LOCK_IND	1
++
++#define CCS_ALWAYS_LAST			0x0430
++#define CCS_AHBM_CR_BURST_EN		(1 << 2)
++#define CCS_FPIM_CR_BURST_EN		(1 << 1)
++
++#define CCR03_EIGHT_BANK_MODE		(1 << 0)
++
++	/* Store given value in MC DDR CCRx register */
++	.macro ccr_sw num, val
++	li	t1, \val
++	sw	t1, LTQ_MC_DDR_CCR_OFFSET(\num)(t0)
++	.endm
++
++LEAF(ltq_mem_init)
++	/* Load MC DDR module base */
++	li	t0, (LTQ_MC_DDR_BASE | KSEG1)
++
++	/* Put memory controller in inactive mode */
++	sw	zero, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
++
++	/* Init MC DDR CCR registers with values from ddr_settings.h */
++	ccr_sw	0, MC_CCR00_VALUE
++	ccr_sw	1, MC_CCR01_VALUE
++	ccr_sw	2, MC_CCR02_VALUE
++	ccr_sw	3, MC_CCR03_VALUE
++	ccr_sw	4, MC_CCR04_VALUE
++	ccr_sw	5, MC_CCR05_VALUE
++	ccr_sw	6, MC_CCR06_VALUE
++	ccr_sw	7, MC_CCR07_VALUE
++	ccr_sw	8, MC_CCR08_VALUE
++	ccr_sw	9, MC_CCR09_VALUE
++
++	ccr_sw	10, MC_CCR10_VALUE
++	ccr_sw	11, MC_CCR11_VALUE
++	ccr_sw	12, MC_CCR12_VALUE
++	ccr_sw	13, MC_CCR13_VALUE
++	ccr_sw	14, MC_CCR14_VALUE
++	ccr_sw	15, MC_CCR15_VALUE
++	ccr_sw	16, MC_CCR16_VALUE
++	ccr_sw	17, MC_CCR17_VALUE
++	ccr_sw	18, MC_CCR18_VALUE
++	ccr_sw	19, MC_CCR19_VALUE
++
++	ccr_sw	20, MC_CCR20_VALUE
++	ccr_sw	21, MC_CCR21_VALUE
++	ccr_sw	22, MC_CCR22_VALUE
++	ccr_sw	23, MC_CCR23_VALUE
++	ccr_sw	24, MC_CCR24_VALUE
++	ccr_sw	25, MC_CCR25_VALUE
++	ccr_sw	26, MC_CCR26_VALUE
++	ccr_sw	27, MC_CCR27_VALUE
++	ccr_sw	28, MC_CCR28_VALUE
++	ccr_sw	29, MC_CCR29_VALUE
++
++	ccr_sw	30, MC_CCR30_VALUE
++	ccr_sw	31, MC_CCR31_VALUE
++	ccr_sw	32, MC_CCR32_VALUE
++	ccr_sw	33, MC_CCR33_VALUE
++	ccr_sw	34, MC_CCR34_VALUE
++	ccr_sw	35, MC_CCR35_VALUE
++	ccr_sw	36, MC_CCR36_VALUE
++	ccr_sw	37, MC_CCR37_VALUE
++	ccr_sw	38, MC_CCR38_VALUE
++	ccr_sw	39, MC_CCR39_VALUE
++
++	ccr_sw	40, MC_CCR40_VALUE
++	ccr_sw	41, MC_CCR41_VALUE
++	ccr_sw	42, MC_CCR42_VALUE
++	ccr_sw	43, MC_CCR43_VALUE
++	ccr_sw	44, MC_CCR44_VALUE
++	ccr_sw	45, MC_CCR45_VALUE
++	ccr_sw	46, MC_CCR46_VALUE
++
++	ccr_sw	52, MC_CCR52_VALUE
++	ccr_sw	53, MC_CCR53_VALUE
++	ccr_sw	54, MC_CCR54_VALUE
++	ccr_sw	55, MC_CCR55_VALUE
++	ccr_sw	56, MC_CCR56_VALUE
++	ccr_sw	57, MC_CCR57_VALUE
++	ccr_sw	58, MC_CCR58_VALUE
++	ccr_sw	59, MC_CCR59_VALUE
++
++	ccr_sw	60, MC_CCR60_VALUE
++	ccr_sw	61, MC_CCR61_VALUE
++
++	/* Disable bursts between FPI Master bus and XBAR bus */
++	li	t4, (LTQ_MC_GLOBAL_BASE | KSEG1)
++	li	t5, CCS_AHBM_CR_BURST_EN
++	sw	t5, CCS_ALWAYS_LAST(t4)
++
++	/* Init abort condition for DRAM probe */
++	move	t4, zero
++
++	/*
++	 * Put memory controller in active mode and start initialitation
++	 * sequence for connected DDR-SDRAM device
++	 */
++mc_start:
++	lw	t1, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
++	li	t2, LTQ_MC_DDR_START
++	or	t1, t1, t2
++	sw	t1, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
++
++	/*
++	 * Wait until DLL has locked and core is ready for data transfers.
++	 * DLL lock indication is in register CCR47 and CCR48
++	 */
++wait_ready:
++	li	t1, LTQ_MC_DDR_DLL_LOCK_IND
++	lw	t2, LTQ_MC_DDR_CCR_OFFSET(47)(t0)
++	and	t2, t2, t1
++	bne	t1, t2, wait_ready
++
++	lw	t2, LTQ_MC_DDR_CCR_OFFSET(48)(t0)
++	and	t2, t2, t1
++	bne	t1, t2, wait_ready
++
++#ifdef CONFIG_SYS_DRAM_PROBE
++dram_probe:
++	/* Initialization is finished after the second MC start */
++	bnez	t4, mc_finished
++
++	/*
++	 * Preload register values for CCR03 and CCR11. Initial settings
++	 * are 8-bank mode enabled, 14 use address row bits, 10 used
++	 * column address bits.
++	 */
++	li	t1, CONFIG_SYS_SDRAM_BASE_UC
++	li	t5, MC_CCR03_VALUE
++	li	t6, MC_CCR11_VALUE
++	addi	t4, t4, 1
++
++	/*
++	 * Store test values to DRAM at offsets 0 and 2^13 (bit 2 in bank select
++	 * address BA[3]) and read back the value at offset 0. If the resulting
++	 * value is equal to 1 we can skip to the next test. Otherwise
++	 * the 8-bank mode does not work with the current DRAM device,
++	 * thus we need to clear the according bit in register CCR03.
++	 */
++	li	t2, 1
++	sw	t2, 0x0(t1)
++	li	t3, (1 << 13)
++	add	t3, t3, t1
++	sw	zero, 0(t3)
++	lw	t3, 0(t1)
++	bnez	t3, row_col_test
++
++	/* Clear CCR03.EIGHT_BANK_MODE */
++	li	t3, ~CCR03_EIGHT_BANK_MODE
++	and	t5, t5, t3
++
++row_col_test:
++	/*
++	 * Store test values to DRAM at offsets 0, 2^27 (bit 13 of row address
++	 * RA[14]) and 2^26 (bit 12 of RA[14]). The chosen test values
++	 * represent the difference between max. row address bits (14) and used
++	 * row address bits. Then the read back value at offset 0 indicates
++	 * the useable row address bits with the current DRAM device. This
++	 * value must be set in the CCR11 register.
++	 */
++	sw	zero, 0(t1)
++
++	li	t2, 1
++	li	t3, (1 << 27)
++	add	t3, t3, t1
++	sw	t2, 0(t3)
++
++	li	t2, 2
++	li	t3, (1 << 26)
++	add	t3, t3, t1
++	sw	t2, 0(t3)
++
++	/* Update CCR11.ADDR_PINS */
++	lw	t3, 0(t1)
++	add	t6, t6, t3
++
++	/*
++	 * Store test values to DRAM at offsets 0, 2^10 (bit 9 of column address
++	 * CA[10]) and 2^9 (bit 8 of CA[10]). The chosen test values represent
++	 * the difference between max. column address bits (12) and used
++	 * column address bits. Then the read back value at offset 0 indicates
++	 * the useable column address bits with the current DRAM device. This
++	 * value must be set in the CCR11 register.
++	 */
++	sw	zero, 0(t1)
++
++	li	t2, 1
++	li	t3, (1 << 10)
++	add	t3, t3, t1
++	sw	t2, 0(t3)
++
++	li	t2, 2
++	li	t3, (1 << 9)
++	add	t3, t3, t1
++	sw	t2, 0(t3)
++
++	/* Update CCR11.COLUMN_SIZE */
++	lw	t3, 0(t1)
++	sll	t3, t3, 24
++	add	t6, t6, t3
++
++	/* Put memory controller in inactive mode */
++	sw	zero, LTQ_MC_DDR_CCR_OFFSET(7)(t0)
++
++	/* Update CCR03 and CCR11 and restart memory controller initialiation */
++	sw	t5, LTQ_MC_DDR_CCR_OFFSET(3)(t0)
++	sw	t6, LTQ_MC_DDR_CCR_OFFSET(11)(t0)
++	b	mc_start
++
++mc_finished:
++#endif /* CONFIG_SYS_DRAM_PROBE */
++
++	jr	ra
++
++	END(ltq_mem_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/pmu.c
+@@ -0,0 +1,130 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/pm.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_PMU_PWDCR_RESERVED		((1 << 13) | (1 << 4))
++
++#define LTQ_PMU_PWDCR_PCIELOC_EN	(1 << 31)
++#define LTQ_PMU_PWDCR_GPHY		(1 << 30)
++#define LTQ_PMU_PWDCR_PPE_TOP		(1 << 29)
++#define LTQ_PMU_PWDCR_SWITCH		(1 << 28)
++#define LTQ_PMU_PWDCR_USB1		(1 << 27)
++#define LTQ_PMU_PWDCR_USB1_PHY		(1 << 26)
++#define LTQ_PMU_PWDCR_TDM		(1 << 25)
++#define LTQ_PMU_PWDCR_PPE_DPLUS		(1 << 24)
++#define LTQ_PMU_PWDCR_PPE_DPLUM		(1 << 23)
++#define LTQ_PMU_PWDCR_PPE_EMA		(1 << 22)
++#define LTQ_PMU_PWDCR_PPE_TC		(1 << 21)
++#define LTQ_PMU_PWDCR_DEU		(1 << 20)
++#define LTQ_PMU_PWDCR_PPE_SLL01		(1 << 19)
++#define LTQ_PMU_PWDCR_PPE_QSB		(1 << 18)
++#define LTQ_PMU_PWDCR_UART1		(1 << 17)
++#define LTQ_PMU_PWDCR_SDIO		(1 << 16)
++#define LTQ_PMU_PWDCR_AHBM		(1 << 15)
++#define LTQ_PMU_PWDCR_FPIM		(1 << 14)
++#define LTQ_PMU_PWDCR_GPTC		(1 << 12)
++#define LTQ_PMU_PWDCR_LEDC		(1 << 11)
++#define LTQ_PMU_PWDCR_EBU		(1 << 10)
++#define LTQ_PMU_PWDCR_DSL		(1 << 9)
++#define LTQ_PMU_PWDCR_SPI		(1 << 8)
++#define LTQ_PMU_PWDCR_USIF		(1 << 7)
++#define LTQ_PMU_PWDCR_USB0		(1 << 6)
++#define LTQ_PMU_PWDCR_DMA		(1 << 5)
++#define LTQ_PMU_PWDCR_DFEV1		(1 << 3)
++#define LTQ_PMU_PWDCR_DFEV0		(1 << 2)
++#define LTQ_PMU_PWDCR_FPIS		(1 << 1)
++#define LTQ_PMU_PWDCR_USB0_PHY		(1 << 0)
++
++struct ltq_pmu_regs {
++	u32	rsvd0[7];
++	u32	pwdcr;		/* Power down control */
++	u32	sr;		/* Power down status */
++	u32	pwdcr1;		/* Power down control 1 */
++	u32	sr1;		/* Power down status 1 */
++};
++
++static struct ltq_pmu_regs *ltq_pmu_regs =
++	(struct ltq_pmu_regs *) CKSEG1ADDR(LTQ_PMU_BASE);
++
++u32 ltq_pm_map(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_PM_CORE:
++		val = LTQ_PMU_PWDCR_UART1 | LTQ_PMU_PWDCR_FPIM |
++			LTQ_PMU_PWDCR_LEDC | LTQ_PMU_PWDCR_EBU;
++		break;
++	case LTQ_PM_DMA:
++		val = LTQ_PMU_PWDCR_DMA;
++		break;
++	case LTQ_PM_ETH:
++		val = LTQ_PMU_PWDCR_GPHY | LTQ_PMU_PWDCR_PPE_TOP |
++			LTQ_PMU_PWDCR_SWITCH | LTQ_PMU_PWDCR_PPE_DPLUS |
++			LTQ_PMU_PWDCR_PPE_DPLUM | LTQ_PMU_PWDCR_PPE_EMA |
++			LTQ_PMU_PWDCR_PPE_TC | LTQ_PMU_PWDCR_PPE_SLL01 |
++			LTQ_PMU_PWDCR_PPE_QSB;
++		break;
++	case LTQ_PM_SPI:
++		val = LTQ_PMU_PWDCR_SPI;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_pm_enable(enum ltq_pm_modules module)
++{
++	const unsigned long timeout = 1000;
++	unsigned long timebase;
++	u32 sr, val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_pmu_regs->pwdcr, val);
++
++	timebase = get_timer(0);
++
++	do {
++		sr = ltq_readl(&ltq_pmu_regs->sr);
++		if (~sr & val)
++			return 0;
++	} while (get_timer(timebase) < timeout);
++
++	return 1;
++}
++
++int ltq_pm_disable(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_pmu_regs->pwdcr, val);
++
++	return 0;
++}
++
++void ltq_pmu_init(void)
++{
++	u32 set, clr;
++
++	clr = ltq_pm_map(LTQ_PM_CORE);
++	set = ~(LTQ_PMU_PWDCR_RESERVED | clr);
++
++	ltq_clrsetbits(&ltq_pmu_regs->pwdcr, clr, set);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/vrx200/rcu.c
+@@ -0,0 +1,194 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_RCU_RD_GPHY0	(1 << 31)	/* GPHY0 */
++#define LTQ_RCU_RD_SRST		(1 << 30)	/* Global SW Reset */
++#define LTQ_RCU_RD_GPHY1	(1 << 29)	/* GPHY1 */
++#define LTQ_RCU_RD_ENMIP2	(1 << 28)	/* Enable NMI of PLL2 */
++#define LTQ_RCU_RD_REG25_PD	(1 << 26)	/* Power down 2.5V regulator */
++#define LTQ_RCU_RD_ENDINIT	(1 << 25)	/* FPI slave bus access */
++#define LTQ_RCU_RD_PPE_ATM_TC	(1 << 23)	/* PPE ATM TC */
++#define LTQ_RCU_RD_PCIE		(1 << 22)	/* PCI-E core */
++#define LTQ_RCU_RD_ETHSW	(1 << 21)	/* Ethernet switch */
++#define LTQ_RCU_RD_DSP_DEN	(1 << 20)	/* Enable DSP JTAG */
++#define LTQ_RCU_RD_TDM		(1 << 19)	/* TDM module interface */
++#define LTQ_RCU_RD_ENMIP1	(1 << 18)	/* Enable NMI of PLL1 */
++#define LTQ_RCU_RD_SWBCK	(1 << 17)	/* Switch backward compat */
++#define LTQ_RCU_RD_HSNAND	(1 << 16)	/* HSNAND controller */
++#define LTQ_RCU_RD_ENMIP0	(1 << 15)	/* Enable NMI of PLL0 */
++#define LTQ_RCU_RD_MC		(1 << 14)	/* Memory Controller */
++#define LTQ_RCU_RD_PCI		(1 << 13)	/* PCI core */
++#define LTQ_RCU_RD_PCIE_PHY	(1 << 12)	/* PCI-E Phy */
++#define LTQ_RCU_RD_DFE_CORE	(1 << 11)	/* DFE core */
++#define LTQ_RCU_RD_SDIO		(1 << 10)	/* SDIO core */
++#define LTQ_RCU_RD_DMA		(1 << 9)	/* DMA core */
++#define LTQ_RCU_RD_PPE		(1 << 8)	/* PPE core */
++#define LTQ_RCU_RD_DFE		(1 << 7)	/* DFE core */
++#define LTQ_RCU_RD_AHB		(1 << 6)	/* AHB bus */
++#define LTQ_RCU_RD_HRST_CFG	(1 << 5)	/* HW reset configuration */
++#define LTQ_RCU_RD_USB		(1 << 4)	/* USB and Phy core */
++#define LTQ_RCU_RD_PPE_DSP	(1 << 3)	/* PPE DSP interface */
++#define LTQ_RCU_RD_FPI		(1 << 2)	/* FPI bus */
++#define LTQ_RCU_RD_CPU		(1 << 1)	/* CPU subsystem */
++#define LTQ_RCU_RD_HRST		(1 << 0)	/* HW reset via HRST pin */
++
++#define LTQ_RCU_STAT_BOOT_SHIFT		17
++#define LTQ_RCU_STAT_BOOT_MASK		(0xF << LTQ_RCU_STAT_BOOT_SHIFT)
++#define LTQ_RCU_STAT_BOOT_H		(1 << 12)
++
++#define LTQ_RCU_GP_STRAP_CLOCKSOURCE	(1 << 15)
++
++struct ltq_rcu_regs {
++	u32	rsvd0[4];
++	u32	req;		/* Reset request */
++	u32	stat;		/* Reset status */
++	u32	usb0_cfg;	/* USB0 configure */
++	u32	gp_strap;	/* GPIO strapping */
++	u32	gfs_add0;	/* GPHY0 firmware base addr */
++	u32	stat2;		/* SLIC and USB reset status */
++	u32	pci_rdy;	/* PCI boot ready */
++	u32	ppe_conf;	/* PPE ethernet config */
++	u32	pcie_phy_con;	/* PCIE PHY config/status */
++	u32	usb1_cfg;	/* USB1 configure */
++	u32	usb_ana_cfg1a;	/* USB analog config 1a */
++	u32	usb_ana_cfg1b;	/* USB analog config 1b */
++	u32	rsvd1;
++	u32	gf_mdio_add;	/* GPHY0/1 MDIO address */
++	u32	req2;		/* SLIC and USB reset request */
++	u32	ahb_endian;	/* AHB bus endianess */
++	u32	rsvd2[4];
++	u32	gcc;		/* General CPU config */
++	u32	rsvd3;
++	u32	gfs_add1;	/* GPHY1 firmware base addr */
++};
++
++static struct ltq_rcu_regs *ltq_rcu_regs =
++	(struct ltq_rcu_regs *) CKSEG1ADDR(LTQ_RCU_BASE);
++
++u32 ltq_reset_map(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_RESET_CORE:
++	case LTQ_RESET_SOFT:
++		val = LTQ_RCU_RD_SRST | LTQ_RCU_RD_CPU | LTQ_RCU_RD_ENMIP2 |
++			LTQ_RCU_RD_GPHY1 | LTQ_RCU_RD_GPHY0;
++		break;
++	case LTQ_RESET_DMA:
++		val = LTQ_RCU_RD_DMA;
++		break;
++	case LTQ_RESET_ETH:
++		val = LTQ_RCU_RD_PPE | LTQ_RCU_RD_ETHSW;
++		break;
++	case LTQ_RESET_PHY:
++		val = LTQ_RCU_RD_GPHY1 | LTQ_RCU_RD_GPHY0;
++		break;
++	case LTQ_RESET_HARD:
++		val = LTQ_RCU_RD_HRST;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_reset_activate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++int ltq_reset_deactivate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++enum ltq_boot_select ltq_boot_select(void)
++{
++	u32 stat;
++	unsigned int bootstrap;
++
++	/*
++	 * Boot select value is built from bits 20-17 and bit 12.
++	 * The bit sequence is read as 4-2-1-0-3.
++	 */
++	stat = ltq_readl(&ltq_rcu_regs->stat);
++	bootstrap = ((stat & LTQ_RCU_STAT_BOOT_H) << 4) |
++		((stat & LTQ_RCU_STAT_BOOT_MASK) >> LTQ_RCU_STAT_BOOT_SHIFT);
++
++	switch (bootstrap) {
++	case 0:
++		return BOOT_NOR_NO_BOOTROM;
++	case 1:
++		return BOOT_RGMII1;
++	case 2:
++		return BOOT_NOR;
++	case 4:
++		return BOOT_UART_NO_EEPROM;
++	case 6:
++		return BOOT_PCI;
++	case 8:
++		return BOOT_UART;
++	case 10:
++		return BOOT_SPI;
++	case 12:
++		return BOOT_NAND;
++	default:
++		return BOOT_UNKNOWN;
++	}
++}
++
++void ltq_rcu_gphy_boot(unsigned int id, ulong addr)
++{
++	u32 module;
++	void *gfs_add;
++
++	switch (id) {
++	case 0:
++		module = LTQ_RCU_RD_GPHY0;
++		gfs_add = &ltq_rcu_regs->gfs_add0;
++		break;
++	case 1:
++		module = LTQ_RCU_RD_GPHY1;
++		gfs_add = &ltq_rcu_regs->gfs_add1;
++		break;
++	default:
++		BUG();
++	}
++
++	/* Stop and reset GPHY */
++	ltq_setbits(&ltq_rcu_regs->req, module);
++
++	/* Configure firmware and boot address */
++	ltq_writel(gfs_add, CPHYSADDR(addr & 0xFFFFC000));
++
++	/* Start GPHY by releasing reset */
++	ltq_clrbits(&ltq_rcu_regs->req, module);
++}
+--- /dev/null
++++ b/arch/mips/include/asm/arch-danube/config.h
+@@ -0,0 +1,164 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ *
++ * Common board configuration for Lantiq XWAY Danube family
++ *
++ * Use following defines in your board config to enable specific features
++ * and drivers for this SoC:
++ *
++ * CONFIG_LTQ_SUPPORT_UART
++ * - support the Danube ASC/UART interface and console
++ *
++ * CONFIG_LTQ_SUPPORT_NOR_FLASH
++ * - support a parallel NOR flash via the CFI interface in flash bank 0
++ *
++ * CONFIG_LTQ_SUPPORT_ETHERNET
++ * - support the Danube ETOP and MAC interface
++ *
++ * CONFIG_LTQ_SUPPORT_SPI_FLASH
++ * - support the Danube SPI interface and serial flash drivers
++ * - specific SPI flash drivers must be configured separately
++ */
++
++#ifndef __DANUBE_CONFIG_H__
++#define __DANUBE_CONFIG_H__
++
++/* CPU and SoC type */
++#define CONFIG_SOC_LANTIQ
++#define CONFIG_SOC_XWAY_DANUBE
++
++/* Cache configuration */
++#define CONFIG_SYS_MIPS_CACHE_MODE	CONF_CM_CACHABLE_NONCOHERENT
++#define CONFIG_SYS_DCACHE_SIZE		(16 * 1024)
++#define CONFIG_SYS_ICACHE_SIZE		(16 * 1024)
++#define CONFIG_SYS_CACHELINE_SIZE	32
++#define CONFIG_SYS_MIPS_CACHE_EXT_INIT
++
++/*
++ * Supported clock modes
++ * PLL0 clock output is 333 MHz
++ * PLL1 clock output is 262.144 MHz
++ */
++#define LTQ_CLK_CPU_333_DDR_167		0	/* Base PLL0, OCP 2 */
++#define LTQ_CLK_CPU_111_DDR_111		1	/* Base PLL0, OCP 1 */
++
++/* CPU speed */
++#define CONFIG_SYS_CLOCK_MODE		LTQ_CLK_CPU_333_DDR_167
++#define CONFIG_SYS_MIPS_TIMER_FREQ	166666667
++#define CONFIG_SYS_HZ			1000
++
++/* RAM */
++#define CONFIG_NR_DRAM_BANKS		1
++#define CONFIG_SYS_SDRAM_BASE		0x80000000
++#define CONFIG_SYS_MEMTEST_START	0x81000000
++#define CONFIG_SYS_MEMTEST_END		0x82000000
++#define CONFIG_SYS_LOAD_ADDR		0x81000000
++#define CONFIG_SYS_LOAD_SIZE		(2 * 1024 * 1024)
++#define CONFIG_SYS_INIT_SP_OFFSET	0x4000
++
++/* SRAM */
++#define CONFIG_SYS_SRAM_BASE		0xBE1A0000
++#define CONFIG_SYS_SRAM_SIZE		0x10000
++
++/* ASC/UART driver and console */
++#define CONFIG_LANTIQ_SERIAL
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
++
++/* GPIO */
++#define CONFIG_LANTIQ_GPIO
++#define CONFIG_LTQ_GPIO_MAX_BANKS	2
++
++/* FLASH driver */
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define CONFIG_SYS_MAX_FLASH_BANKS	1
++#define CONFIG_SYS_MAX_FLASH_SECT	256
++#define CONFIG_SYS_FLASH_BASE		0xB0000000
++#define CONFIG_FLASH_16BIT
++#define CONFIG_SYS_FLASH_CFI
++#define CONFIG_FLASH_CFI_DRIVER
++#define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_16BIT
++#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
++#define CONFIG_FLASH_SHOW_PROGRESS	50
++#define CONFIG_SYS_FLASH_PROTECTION
++#define CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
++
++#define CONFIG_CMD_FLASH
++#else
++#define CONFIG_SYS_NO_FLASH
++#endif /* CONFIG_NOR_FLASH */
++
++#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
++#define CONFIG_LANTIQ_SPI
++#define CONFIG_SPI_FLASH
++
++#define CONFIG_CMD_SF
++#define CONFIG_CMD_SPI
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define CONFIG_NAND_LANTIQ
++#define CONFIG_SYS_MAX_NAND_DEVICE	1
++#define CONFIG_SYS_NAND_BASE		0xB4000000
++
++#define CONFIG_CMD_NAND
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
++#define CONFIG_LANTIQ_DMA
++#define CONFIG_LANTIQ_DANUBE_ETOP
++
++#define CONFIG_PHYLIB
++#define CONFIG_MII
++
++#define CONFIG_CMD_MII
++#define CONFIG_CMD_NET
++#endif
++
++#define CONFIG_SPL_MAX_SIZE		(32 * 1024)
++#define CONFIG_SPL_BSS_MAX_SIZE		(8 * 1024)
++#define CONFIG_SPL_STACK_MAX_SIZE	(8 * 1024)
++#define CONFIG_SPL_MALLOC_MAX_SIZE	(32 * 1024)
++/*#define CONFIG_SPL_STACK_BSS_IN_SRAM*/
++
++#if defined(CONFIG_SPL_STACK_BSS_IN_SRAM)
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SRAM_BASE + \
++					CONFIG_SPL_MAX_SIZE + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE	  	(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET)
++#else
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE		(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SPL_BSS_BASE + \
++					CONFIG_SPL_BSS_MAX_SIZE)
++#endif
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define CONFIG_SYS_TEXT_BASE		0xa0100000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_SYS_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SPL_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR) || defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_XWAY_EBU_BOOTCFG	0x688C688C
++#define CONFIG_XWAY_SWAP_BYTES
++#endif
++
++#define	CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
++
++#endif /* __DANUBE_CONFIG_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-danube/gpio.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __DANUBE_GPIO_H__
++#define __DANUBE_GPIO_H__
++
++#include <asm/lantiq/gpio.h>
++
++#endif /* __DANUBE_GPIO_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-danube/nand.h
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __DANUBE_NAND_H__
++#define __DANUBE_NAND_H__
++
++struct nand_chip;
++int ltq_nand_init(struct nand_chip *nand);
++
++#endif /* __DANUBE_NAND_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-danube/soc.h
+@@ -0,0 +1,38 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __DANUBE_SOC_H__
++#define __DANUBE_SOC_H__
++
++#define LTQ_ASC0_BASE			0x1E100400
++#define LTQ_SPI_BASE			0x1E100800
++#define LTQ_GPIO_BASE			0x1E100B00
++#define LTQ_SSIO_BASE			0x1E100BB0
++#define LTQ_ASC1_BASE			0x1E100C00
++#define LTQ_DMA_BASE			0x1E104100
++
++#define LTQ_EBU_BASE			0x1E105300
++#define LTQ_EBU_REGION0_BASE		0x10000000
++#define LTQ_EBU_REGION1_BASE		0x14000000
++#define LTQ_EBU_NAND_BASE		(LTQ_EBU_BASE + 0xB0)
++
++#define LTQ_PPE_BASE			0x1E180000
++#define LTQ_PPE_ETOP_BASE		(LTQ_PPE_BASE + 0x11800)
++#define LTQ_PPE_ENET0_BASE		(LTQ_PPE_BASE + 0x11840)
++
++#define LTQ_PMU_BASE			0x1F102000
++#define LTQ_CGU_BASE			0x1F103000
++#define LTQ_MPS_BASE			0x1F107000
++#define LTQ_CHIPID_BASE			(LTQ_MPS_BASE + 0x340)
++#define LTQ_RCU_BASE			0x1F203000
++
++#define LTQ_MC_GEN_BASE			0x1F800000
++#define LTQ_MC_SDR_BASE			0x1F800200
++#define LTQ_MC_DDR_BASE			0x1F801000
++#define LTQ_MC_DDR_DC_OFFSET(x)		(x * 0x10)
++
++#endif /* __DANUBE_SOC_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/config.h
+@@ -0,0 +1,188 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ *
++ * Common board configuration for Lantiq XWAY VRX200 family
++ *
++ * Use following defines in your board config to enable specific features
++ * and drivers for this SoC:
++ *
++ * CONFIG_LTQ_SUPPORT_UART
++ * - support the VRX200 ASC/UART interface and console
++ *
++ * CONFIG_LTQ_SUPPORT_NOR_FLASH
++ * - support a parallel NOR flash via the CFI interface in flash bank 0
++ *
++ * CONFIG_LTQ_SUPPORT_ETHERNET
++ * - support the VRX200 internal switch
++ *
++ * CONFIG_LTQ_SUPPORT_SPI_FLASH
++ * - support the VRX200 SPI interface and serial flash drivers
++ * - specific SPI flash drivers must be configured separately
++ *
++ * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
++ * - build a preloader that runs in the internal SRAM and loads
++ *   the U-Boot from SPI flash into RAM
++ */
++
++#ifndef __VRX200_CONFIG_H__
++#define __VRX200_CONFIG_H__
++
++/* CPU and SoC type */
++#define CONFIG_SOC_LANTIQ
++#define CONFIG_SOC_XWAY_VRX200
++
++/* Cache configuration */
++#define CONFIG_SYS_MIPS_CACHE_MODE	CONF_CM_CACHABLE_NONCOHERENT
++#define CONFIG_SYS_DCACHE_SIZE		(32 * 1024)
++#define CONFIG_SYS_ICACHE_SIZE		(32 * 1024)
++#define CONFIG_SYS_CACHELINE_SIZE	32
++#define CONFIG_SYS_MIPS_CACHE_EXT_INIT
++
++/*
++ * Supported clock modes
++ * PLL0 clock output is 1000 MHz
++ * PLL1 clock output is 393.219 MHz
++ */
++#define LTQ_CLK_CPU_600_DDR_300	0	/* Base PLL0, OCP 2 */
++#define LTQ_CLK_CPU_600_DDR_200	1	/* Base PLL0, OCP 3 */
++#define LTQ_CLK_CPU_500_DDR_250	2	/* Base PLL0, OCP 2 */
++#define LTQ_CLK_CPU_500_DDR_200	3	/* Base PLL0, OCP 2.5 */
++#define LTQ_CLK_CPU_333_DDR_167	4	/* Base PLL0, OCP 2 */
++#define LTQ_CLK_CPU_167_DDR_167	5	/* Base PLL0, OCP 1 */
++#define LTQ_CLK_CPU_125_DDR_125	6	/* Base PLL0, OCP 1 */
++#define LTQ_CLK_CPU_393_DDR_197	7	/* Base PLL1, OCP 2 */
++#define LTQ_CLK_CPU_197_DDR_197	8	/* Base PLL1, OCP 1 */
++
++/* CPU speed */
++#define CONFIG_SYS_CLOCK_MODE		LTQ_CLK_CPU_500_DDR_250
++#define CONFIG_SYS_MIPS_TIMER_FREQ	250000000
++#define CONFIG_SYS_HZ			1000
++
++/* RAM */
++#define CONFIG_NR_DRAM_BANKS		1
++#define CONFIG_SYS_SDRAM_BASE		0x80000000
++#define CONFIG_SYS_SDRAM_BASE_UC	0xa0000000
++#define CONFIG_SYS_MEMTEST_START	0x81000000
++#define CONFIG_SYS_MEMTEST_END		0x82000000
++#define CONFIG_SYS_LOAD_ADDR		0x81000000
++#define CONFIG_SYS_LOAD_SIZE		(2 * 1024 * 1024)
++#define CONFIG_SYS_INIT_SP_OFFSET	(32 * 1024)
++
++/* SRAM */
++#define CONFIG_SYS_SRAM_BASE		0xBE220000
++#define CONFIG_SYS_SRAM_SIZE		0x10000
++
++/* ASC/UART driver and console */
++#define CONFIG_LANTIQ_SERIAL
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
++
++/* GPIO */
++#define CONFIG_LANTIQ_GPIO
++#define CONFIG_LTQ_GPIO_MAX_BANKS	3
++#define CONFIG_LTQ_HAS_GPIO_BANK3
++
++/* FLASH driver */
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#ifndef CONFIG_SYS_MAX_FLASH_BANKS
++#define CONFIG_SYS_MAX_FLASH_BANKS	1
++#endif
++#define CONFIG_SYS_MAX_FLASH_SECT	256
++#define CONFIG_SYS_FLASH_BASE		0xB0000000
++#define CONFIG_SYS_FLASH2_BASE		0xB4000000
++#define CONFIG_FLASH_16BIT
++#define CONFIG_SYS_FLASH_CFI
++#define CONFIG_FLASH_CFI_DRIVER
++#define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_16BIT
++#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
++#define CONFIG_FLASH_SHOW_PROGRESS	50
++#define CONFIG_SYS_FLASH_PROTECTION
++#define CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
++
++#define CONFIG_CMD_FLASH
++#else
++#define CONFIG_SYS_NO_FLASH
++#endif /* CONFIG_NOR_FLASH */
++
++#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
++#define CONFIG_LANTIQ_SPI
++#define CONFIG_SPI_FLASH
++
++#define CONFIG_CMD_SF
++#define CONFIG_CMD_SPI
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define CONFIG_NAND_LANTIQ
++#define CONFIG_SYS_MAX_NAND_DEVICE	1
++#define CONFIG_SYS_NAND_BASE		0xB4000000
++
++#define CONFIG_CMD_NAND
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
++#define CONFIG_LANTIQ_DMA
++#define CONFIG_LANTIQ_VRX200_SWITCH
++#define CONFIG_PHY_LANTIQ
++
++#define CONFIG_SYS_RX_ETH_BUFFER	8
++#define CONFIG_PHYLIB
++#define CONFIG_MII
++#define CONFIG_UDP_CHECKSUM
++
++#define CONFIG_CMD_MII
++#define CONFIG_CMD_NET
++#endif
++
++#define CONFIG_SPL_MAX_SIZE		(32 * 1024)
++#define CONFIG_SPL_BSS_MAX_SIZE		(8 * 1024)
++#define CONFIG_SPL_STACK_MAX_SIZE	(8 * 1024)
++#define CONFIG_SPL_MALLOC_MAX_SIZE	(32 * 1024)
++#define CONFIG_SPL_STACK_BSS_IN_SRAM
++
++#if defined(CONFIG_SPL_STACK_BSS_IN_SRAM)
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SRAM_BASE + \
++					CONFIG_SPL_MAX_SIZE + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE	  	(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET)
++#else
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE		(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SPL_BSS_BASE + \
++					CONFIG_SPL_BSS_MAX_SIZE)
++#endif
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define CONFIG_SYS_TEXT_BASE		0xA0100000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_SYS_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_SFSPL)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SPL_TEXT_BASE		0xBE220000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SPL_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR) || defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_XWAY_EBU_BOOTCFG	0x688C688C
++#define CONFIG_XWAY_SWAP_BYTES
++#endif
++
++#define	CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
++
++#endif /* __VRX200_CONFIG_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/gphy.h
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_GPHY_H__
++#define __VRX200_GPHY_H__
++
++enum ltq_gphy_clk {
++	/* XTAL 36 MHz input */
++	LTQ_GPHY_CLK_36MHZ_XTAL = 1,
++	/* 25 MHz from PLL0 with divider */
++	LTQ_GPHY_CLK_25MHZ_PLL0 = 2,
++	/* derived from PLL2 output (XTAL is 36 MHz) */
++	LTQ_GPHY_CLK_24MHZ_PLL2 = 3,
++	/* 25 MHz Clock from Pin GPIO3 */
++	LTQ_GPHY_CLK_25MHZ_GPIO3 = 4,
++};
++
++/*
++ * Load PHY11G firmware for VRX200 v1.1 to given RAM address
++ *
++ * Address must be 16k aligned!
++ */
++extern void ltq_gphy_phy11g_a1x_load(ulong addr);
++
++/*
++ * Load PHY11G firmware for VRX200 v1.2 to given RAM address
++ *
++ * Address must be 16k aligned!
++ */
++extern void ltq_gphy_phy11g_a2x_load(ulong addr);
++
++/*
++ * Load PHY22F firmware for VRX200 v1.1 to given RAM address
++ *
++ * Address must be 16k aligned!
++ */
++extern void ltq_gphy_phy22f_a1x_load(ulong addr);
++
++/*
++ * Load PHY22F firmware for VRX200 v1.2 to given RAM address
++ *
++ * Address must be 16k aligned!
++ */
++extern void ltq_gphy_phy22f_a2x_load(ulong addr);
++
++/*
++ * Set clock source of internal GPHYs
++ *
++ * According registers resides in CGU address space. Thus this function
++ * is implemented by the CGU driver.
++ */
++extern void ltq_cgu_gphy_clk_src(enum ltq_gphy_clk clk);
++
++/*
++ * Boot internal GPHY with id from given RAM address
++ *
++ * According registers resides in RCU address space. Thus this function
++ * is implemented by the RCU driver.
++ */
++extern void ltq_rcu_gphy_boot(unsigned int id, ulong addr);
++
++#endif /* __VRX200_GPHY_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/gpio.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_GPIO_H__
++#define __VRX200_GPIO_H__
++
++#include <asm/lantiq/gpio.h>
++
++#endif /* __VRX200_GPIO_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/nand.h
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_NAND_H__
++#define __VRX200_NAND_H__
++
++struct nand_chip;
++int ltq_nand_init(struct nand_chip *nand);
++
++#endif /* __VRX200_NAND_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/soc.h
+@@ -0,0 +1,45 @@
++/*
++ * Copyright (C) 2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_SOC_H__
++#define __VRX200_SOC_H__
++
++#define LTQ_ASC0_BASE			0x1E100400
++#define LTQ_SPI_BASE			0x1E100800
++#define LTQ_GPIO_BASE			0x1E100B00
++#define LTQ_SSIO_BASE			0x1E100BB0
++#define LTQ_ASC1_BASE			0x1E100C00
++#define LTQ_DMA_BASE			0x1E104100
++
++#define LTQ_EBU_BASE			0x1E105300
++#define LTQ_EBU_REGION0_BASE		0x10000000
++#define LTQ_EBU_REGION1_BASE		0x14000000
++#define LTQ_EBU_NAND_BASE		(LTQ_EBU_BASE + 0xB0)
++
++#define LTQ_SWITCH_BASE			0x1E108000
++#define LTQ_SWITCH_CORE_BASE		LTQ_SWITCH_BASE
++#define LTQ_SWITCH_TOP_PDI_BASE		LTQ_SWITCH_CORE_BASE
++#define LTQ_SWITCH_BM_PDI_BASE		(LTQ_SWITCH_CORE_BASE + 4 * 0x40)
++#define LTQ_SWITCH_MAC_PDI_0_BASE	(LTQ_SWITCH_CORE_BASE + 4 * 0x900)
++#define LTQ_SWITCH_MAC_PDI_X_BASE(x)	(LTQ_SWITCH_MAC_PDI_0_BASE + x * 0x30)
++#define LTQ_SWITCH_TOPLEVEL_BASE	(LTQ_SWITCH_BASE + 4 * 0xC40)
++#define LTQ_SWITCH_MDIO_PDI_BASE	(LTQ_SWITCH_TOPLEVEL_BASE)
++#define LTQ_SWITCH_MII_PDI_BASE		(LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x36)
++#define LTQ_SWITCH_PMAC_PDI_BASE	(LTQ_SWITCH_TOPLEVEL_BASE + 4 * 0x82)
++
++#define LTQ_PMU_BASE			0x1F102000
++#define LTQ_CGU_BASE			0x1F103000
++#define LTQ_DCDC_BASE			0x1F106A00
++#define LTQ_MPS_BASE			0x1F107000
++#define LTQ_CHIPID_BASE			(LTQ_MPS_BASE + 0x340)
++#define LTQ_RCU_BASE			0x1F203000
++
++#define LTQ_MC_GLOBAL_BASE		0x1F400000
++#define LTQ_MC_DDR_BASE			0x1F401000
++#define LTQ_MC_DDR_CCR_OFFSET(x)	(x * 0x10)
++
++#endif /* __VRX200_SOC_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-vrx200/switch.h
+@@ -0,0 +1,502 @@
++/*
++ *   Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ *   SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_SWITCH_H__
++#define __VRX200_SWITCH_H__
++
++/* Switch core registers */
++struct vr9_switch_core_regs {
++	__be32 swres;
++	/* TODO: implement registers */
++	__be32 rsvd0[0x3f];
++};
++
++/* Switch buffer management registers */
++struct vr9_switch_bm_regs {
++	struct bm_core {
++		__be32 ram_val3;	/* RAM value 3 */
++		__be32 ram_val2;	/* RAM value 2 */
++		__be32 ram_val1;	/* RAM value 1 */
++		__be32 ram_val0;	/* RAM value 0 */
++		__be32 ram_addr;	/* RAM address */
++		__be32 ram_ctrl;	/* RAM access control */
++		__be32 fsqm_gctrl;	/* Free segment queue global control */
++		__be32 cons_sel;	/* Number of consumed segments */
++		__be32 cons_pkt;	/* Number of consumed packet pointers */
++		__be32 gctrl;		/* Global control */
++		__be32 queue_gctrl;	/* Queue manager global control */
++		/* TODO: implement registers */
++		__be32 rsvd0[0x35];
++	} core;
++
++	struct bm_port {
++		__be32 pcfg;		/* Port config */
++		__be32 rmon_ctrl;	/* RMON control */
++	} port[13];
++
++	__be32 rsvd0[0x66];
++
++	struct bm_queue {
++		__be32 rsvd0;
++		__be32 pqm_rs;		/* Packet queue manager rate shape assignment */
++	} queue[32];
++
++	struct bm_shaper {
++		__be32 ctrl;		/* Rate shaper control */
++		__be32 cbs;		/* Rate shaper committed burst size */
++		__be32 ibs;		/* Rate shaper instantaneous burst size */
++		__be32 cir_ext;		/* Rate shaper rate exponent */
++		__be32 cir_mant;	/* Rate shaper rate mantissa */
++	} shaper[16];
++
++	__be32 rsvd1[0x2a8];
++};
++
++/* Switch parser and classification engine registers */
++struct vr9_switch_pce_regs {
++	struct pce_core {
++		__be32 tbl_key[16];	/* Table key data */
++		__be32 tbl_mask;	/* Table mask */
++		__be32 tbl_val[5];	/* Table value */
++		__be32 tbl_addr;	/* Table entry address */
++		__be32 tbl_ctrl;	/* Table access control */
++		__be32 tbl_stat;	/* Table general status */
++		__be32 age_0;		/* Aging counter config 0 */
++		__be32 age_1;		/* Aging counter config 1 */
++		__be32 pmap_1;		/* Port map (monitoring) */
++		__be32 pmap_2;		/* Port map (multicast) */
++		__be32 pmap_3;		/* Port map (unknown unicast) */
++		__be32 gctrl_0;		/* Global control 0 */
++		__be32 gctrl_1;		/* Global control 1 */
++		__be32 tcm_gctrl;	/* Three-color marker global control */
++		__be32 igmp_ctrl;	/* IGMP control */
++		__be32 igmp_drpm;	/* IGMP default router port map */
++		__be32 igmp_age_0;	/* IGMP aging 0 */
++		__be32 igmp_age_1;	/* IGMP aging 1 */
++		__be32 igmp_stat;	/* IGMP status */
++		__be32 wol_gctrl;	/* Wake-on-LAN control */
++		__be32 wol_da_0;	/* Wake-on-LAN destination address 0 */
++		__be32 wol_da_1;	/* Wake-on-LAN destination address 1 */
++		__be32 wol_da_2;	/* Wake-on-LAN destination address 2 */
++		__be32 wol_pw_0;	/* Wake-on-LAN password 0 */
++		__be32 wol_pw_1;	/* Wake-on-LAN password 1 */
++		__be32 wol_pw_2;	/* Wake-on-LAN password 2 */
++		__be32 ier_0;		/* PCE global interrupt enable 0 */
++		__be32 ier_1;		/* PCE global interrupt enable 1 */
++		__be32 isr_0;		/* PCE global interrupt status 0 */
++		__be32 isr_1;		/* PCE global interrupt status 1 */
++		__be32 parser_stat;	/* Parser status */
++		__be32 rsvd0[0x6];
++	} core;
++
++	__be32 rsvd0[0x10];
++
++	struct pce_port {
++		__be32 pctrl_0;		/* Port control 0 */
++		__be32 pctrl_1;		/* Port control 1 */
++		__be32 pctrl_2;		/* Port control 2 */
++		__be32 pctrl_3;		/* Port control 3 */
++		__be32 wol_ctrl;	/* Wake-on-LAN control */
++		__be32 vlan_ctrl;	/* VLAN control */
++		__be32 def_pvid;	/* Default port VID */
++		__be32 pstat;		/* Port status */
++		__be32 pier;		/* Interrupt enable */
++		__be32 pisr;		/* Interrupt status */
++	} port[13];
++
++	__be32 rsvd1[0x7e];
++
++	struct pce_meter {
++		/* TODO: implement registers */
++		__be32 rsvd0[0x7];
++	} meter[8];
++
++	__be32 rsvd2[0x308];
++};
++
++static inline unsigned int to_pce_tbl_key_id(unsigned int id)
++{
++	BUG_ON(id > 15);
++
++	return 15 - id;
++}
++
++static inline unsigned int to_pce_tbl_value_id(unsigned int id)
++{
++	BUG_ON(id > 4);
++
++	return 4 - id;
++}
++
++/* Switch ethernet MAC registers */
++struct vr9_switch_mac_regs {
++	struct mac_core {
++		__be32 test;		/* MAC test */
++		__be32 pfad_cfg;	/* Pause frame source address config */
++		__be32 pfsa_0;		/* Pause frame source address 0 */
++		__be32 pfsa_1;		/* Pause frame source address 1 */
++		__be32 pfsa_2;		/* Pause frame source address 2 */
++		__be32 flen;		/* Frame length */
++		__be32 vlan_etype_0;	/* VLAN ethertype 0 */
++		__be32 vlan_etype_1;	/* VLAN ethertype 1 */
++		__be32 ier;		/* Interrupt enable */
++		__be32 isr;		/* Interrupt status */
++		__be32 rsvd0[0x36];
++	} core;
++
++	struct mac_port {
++		__be32 pstat;		/* Port status */
++		__be32 pisr;		/* Interrupt status */
++		__be32 pier;		/* Interrupt enable */
++		__be32 ctrl_0;		/* Control 0 */
++		__be32 ctrl_1;		/* Control 1 */
++		__be32 ctrl_2;		/* Control 2 */
++		__be32 ctrl_3;		/* Control 3 */
++		__be32 ctrl_4;		/* Control 4 */
++		__be32 ctrl_5;		/* Control 5 */
++		__be32 rsvd0[0x2];
++		__be32 testen;		/* Test enable */
++	} port[13];
++
++	__be32 rsvd0[0xa4];
++};
++
++/* Switch Fetch DMA registers */
++struct vr9_switch_fdma_regs {
++	struct fdma_core {
++		__be32 ctrl;		/* FDMA control */
++		__be32 stetype;		/* Special tag ethertype control */
++		__be32 vtetype;		/* VLAN tag ethertype control */
++		__be32 stat;		/* FDMA status */
++		__be32 ier;		/* FDMA interrupt enable */
++		__be32 isr;		/* FDMA interrupt status */
++	} core;
++
++	__be32 rsvd0[0x3a];
++
++	struct fdma_port {
++		__be32 pctrl;		/* Port control */
++		__be32 prio;		/* Port priority */
++		__be32 pstat_0;		/* Port status 0 */
++		__be32 pstat_1;		/* Port status 1 */
++		__be32 tstamp_0;	/* Egress time stamp 0 */
++		__be32 tstamp_1;	/* Egress time stamp 1 */
++	} port[13];
++
++	__be32 rsvd1[0x72];
++};
++
++/* Switch Store DMA registers */
++struct vr9_switch_sdma_regs {
++	struct sdma_core {
++		__be32 ctrl;		/* SDMA Control */
++		__be32 fcthr_1;		/* Flow control threshold 1 */
++		__be32 rsvd0;
++		__be32 fcthr_3;		/* Flow control threshold 3 */
++		__be32 fcthr_4;		/* Flow control threshold 4 */
++		__be32 fcthr_5;		/* Flow control threshold 5 */
++		__be32 fcthr_6;		/* Flow control threshold 6 */
++		__be32 fcthr_7;		/* Flow control threshold 7 */
++		__be32 stat_0;		/* SDMA status 0 */
++		__be32 stat_1;		/* SDMA status 1 */
++		__be32 stat_2;		/* SDMA status 2 */
++		__be32 ier;		/* SDMA interrupt enable */
++		__be32 isr;		/* SDMA interrupt status */
++	} core;
++
++	__be32 rsvd0[0x73];
++
++	struct sdma_port {
++		__be32 pctrl;		/* Port control */
++		__be32 prio;		/* Port priority */
++		__be32 pstat_0;		/* Port status 0 */
++		__be32 pstat_1;		/* Port status 1 */
++		__be32 tstamp_0;	/* Ingress time stamp 0 */
++		__be32 tstamp_1;	/* Ingress time stamp 1 */
++	} port[13];
++
++	__be32 rsvd1[0x32];
++};
++
++/* Switch MDIO control and status registers */
++struct vr9_switch_mdio_regs {
++	__be32 glob_ctrl;	/* Global control 0 */
++	__be32 rsvd0[7];
++	__be32 mdio_ctrl;	/* MDIO control */
++	__be32 mdio_read;	/* MDIO read data */
++	__be32 mdio_write;	/* MDIO write data */
++	__be32 mdc_cfg_0;	/* MDC clock configuration 0 */
++	__be32 mdc_cfg_1;	/* MDC clock configuration 1 */
++	__be32 rsvd1[0x3];
++	__be32 phy_addr[6];	/* PHY address port 5..0 */
++	__be32 mdio_stat[6];	/* MDIO PHY polling status port 0..5 */
++	__be32 aneg_eee[6];	/* EEE auto-neg overrides port 0..5 */
++	__be32 rsvd2[0x14];
++};
++
++static inline unsigned int to_mdio_phyaddr_id(unsigned int id)
++{
++	BUG_ON(id > 5);
++
++	return 5 - id;
++}
++
++/* Switch xMII control registers */
++struct vr9_switch_mii_regs {
++	__be32 mii_cfg0;	/* xMII port 0 configuration */
++	__be32 pcdu0;		/* Port 0 clock delay configuration */
++	__be32 mii_cfg1;	/* xMII port 1 configuration */
++	__be32 pcdu1;		/* Port 1 clock delay configuration */
++	__be32 rsvd0[0x6];
++	__be32 mii_cfg5;	/* xMII port 5 configuration */
++	__be32 pcdu5;		/* Port 5 clock delay configuration */
++	__be32 rsvd1[0x14];
++	__be32 rxb_ctl_0;	/* Port 0 receive buffer control */
++	__be32 rxb_ctl_1;	/* Port 1 receive buffer control */
++	__be32 rxb_ctl_5;	/* Port 5 receive buffer control */
++	__be32 rsvd2[0x28];
++	__be32 dbg_ctl;		/* Debug control */
++};
++
++/* Switch Pseudo-MAC registers */
++struct vr9_switch_pmac_regs {
++	__be32 hd_ctl;		/* PMAC header control */
++	__be32 tl;		/* PMAC type/length */
++	__be32 sa1;		/* PMAC source address 1 */
++	__be32 sa2;		/* PMAC source address 2 */
++	__be32 sa3;		/* PMAC source address 3 */
++	__be32 da1;		/* PMAC destination address 1 */
++	__be32 da2;		/* PMAC destination address 2 */
++	__be32 da3;		/* PMAC destination address 3 */
++	__be32 vlan;		/* PMAC VLAN */
++	__be32 rx_ipg;		/* PMAC interpacket gap in RX direction */
++	__be32 st_etype;	/* PMAC special tag ethertype */
++	__be32 ewan;		/* PMAC ethernet WAN group */
++	__be32 ctl;		/* PMAC control */
++	__be32 rsvd0[0x2];
++};
++
++struct vr9_switch_regs {
++	struct vr9_switch_core_regs core;
++	struct vr9_switch_bm_regs bm;
++	struct vr9_switch_pce_regs pce;
++	struct vr9_switch_mac_regs mac;
++	struct vr9_switch_fdma_regs fdma;
++	struct vr9_switch_sdma_regs sdma;
++	struct vr9_switch_mdio_regs mdio;
++	struct vr9_switch_mii_regs mii;
++	struct vr9_switch_pmac_regs pmac;
++};
++
++static inline void *to_pce_tbl_key(struct vr9_switch_regs *regs,
++						unsigned int id)
++{
++	return &regs->pce.core.tbl_key[to_pce_tbl_key_id(id)];
++}
++
++static inline void *to_pce_tbl_value(struct vr9_switch_regs *regs,
++						unsigned int id)
++{
++	return &regs->pce.core.tbl_val[to_pce_tbl_value_id(id)];
++}
++
++static inline void *to_mac_ctrl(struct vr9_switch_regs *regs,
++					unsigned int id, unsigned int ctrl)
++{
++	struct mac_port *mac = &regs->mac.port[id];
++
++	switch (ctrl) {
++	case 0:
++		return &mac->ctrl_0;
++	case 1:
++		return &mac->ctrl_1;
++	case 2:
++		return &mac->ctrl_2;
++	case 3:
++		return &mac->ctrl_3;
++	case 4:
++		return &mac->ctrl_4;
++	case 5:
++		return &mac->ctrl_5;
++	default:
++		return NULL;
++	}
++}
++
++static inline void *to_mdio_phyaddr(struct vr9_switch_regs *regs,
++					unsigned int id)
++{
++	return &regs->mdio.phy_addr[to_mdio_phyaddr_id(id)];
++}
++
++static inline void *to_mii_miicfg(struct vr9_switch_regs *regs,
++					unsigned int id)
++{
++	switch (id) {
++	case 0:
++		return &regs->mii.mii_cfg0;
++	case 1:
++		return &regs->mii.mii_cfg1;
++	case 5:
++		return &regs->mii.mii_cfg5;
++	default:
++		return NULL;
++	}
++}
++
++static inline void *to_mii_pcdu(struct vr9_switch_regs *regs,
++					unsigned int id)
++{
++	switch (id) {
++	case 0:
++		return &regs->mii.pcdu0;
++	case 1:
++		return &regs->mii.pcdu1;
++	case 5:
++		return &regs->mii.pcdu5;
++	default:
++		return NULL;
++	}
++}
++
++#define VR9_SWITCH_REG_OFFSET(reg)	(4 * (reg))
++
++#define BUILD_CHECK_VR9_REG(name, offset)	\
++	BUILD_BUG_ON(offsetof(struct vr9_switch_regs, name) != (4 * offset))
++
++static inline void build_check_vr9_registers(void)
++{
++	BUILD_CHECK_VR9_REG(core, 0x0);
++	BUILD_CHECK_VR9_REG(bm.core, 0x40);
++	BUILD_CHECK_VR9_REG(bm.core.queue_gctrl, 0x4a);
++	BUILD_CHECK_VR9_REG(bm.port[0], 0x80);
++	BUILD_CHECK_VR9_REG(bm.queue, 0x100);
++	BUILD_CHECK_VR9_REG(bm.shaper, 0x140);
++	BUILD_CHECK_VR9_REG(pce.core, 0x438);
++	BUILD_CHECK_VR9_REG(pce.core.tbl_ctrl, 0x44f);
++	BUILD_CHECK_VR9_REG(pce.core.parser_stat, 0x469);
++	BUILD_CHECK_VR9_REG(pce.port[0], 0x480);
++	BUILD_CHECK_VR9_REG(pce.meter[0], 0x580);
++	BUILD_CHECK_VR9_REG(mac.core, 0x8c0);
++	BUILD_CHECK_VR9_REG(mac.port[0].pstat, 0x900);
++	BUILD_CHECK_VR9_REG(mac.port[0].ctrl_0, 0x903);
++	BUILD_CHECK_VR9_REG(mac.port[1].pstat, 0x90c);
++	BUILD_CHECK_VR9_REG(mac.port[1].ctrl_0, 0x90f);
++	BUILD_CHECK_VR9_REG(mac.port[2].pstat, 0x918);
++	BUILD_CHECK_VR9_REG(mac.port[2].ctrl_0, 0x91b);
++	BUILD_CHECK_VR9_REG(fdma.core, 0xa40);
++	BUILD_CHECK_VR9_REG(fdma.port[0], 0xa80);
++	BUILD_CHECK_VR9_REG(sdma.core, 0xb40);
++	BUILD_CHECK_VR9_REG(sdma.port[0], 0xbc0);
++	BUILD_CHECK_VR9_REG(mdio, 0xc40);
++	BUILD_CHECK_VR9_REG(mii, (0xc40 + 0x36));
++	BUILD_CHECK_VR9_REG(pmac, (0xc40 + 0x82));
++}
++
++#define BM_GCTRL_F_SRES		1
++
++#define MAC_CTRL0_BM		(1 << 12)
++#define MAC_CTRL0_APADEN	(1 << 11)
++#define MAC_CTRL0_VPAD2EN	(1 << 10)
++#define MAC_CTRL0_VPADEN	(1 << 9)
++#define MAC_CTRL0_PADEN		(1 << 8)
++#define MAC_CTRL0_FCS		(1 << 7)
++#define MAC_CTRL0_FCON_SHIFT	4
++#define MAC_CTRL0_FCON_AUTO	(0x0 << MAC_CTRL0_FCON_SHIFT)
++#define MAC_CTRL0_FCON_RX	(0x1 << MAC_CTRL0_FCON_SHIFT)
++#define MAC_CTRL0_FCON_TX	(0x2 << MAC_CTRL0_FCON_SHIFT)
++#define MAC_CTRL0_FCON_RXTX	(0x3 << MAC_CTRL0_FCON_SHIFT)
++#define MAC_CTRL0_FCON_NONE	(0x4 << MAC_CTRL0_FCON_SHIFT)
++#define MAC_CTRL0_FDUP_SHIFT	2
++#define MAC_CTRL0_FDUP_AUTO	(0x0 << MAC_CTRL0_FDUP_SHIFT)
++#define MAC_CTRL0_FDUP_EN	(0x1 << MAC_CTRL0_FDUP_SHIFT)
++#define MAC_CTRL0_FDUP_DIS	(0x3 << MAC_CTRL0_FDUP_SHIFT)
++#define MAC_CTRL0_GMII_AUTO	0x0
++#define MAC_CTRL0_GMII_MII	0x1
++#define MAC_CTRL0_GMII_GMII	0x2
++#define MAC_CTRL0_GMII_GMII_2G	0x3
++
++#define MAC_CTRL1_DEFERMODE	(1 << 15)
++#define MAC_CTRL1_SHORTPRE	(1 << 8)
++
++#define MAC_CTRL2_MLEN		(1 << 3)
++#define MAC_CTRL2_LCHKL		(1 << 2)
++#define MAC_CTRL2_LCHKS_DIS	0x0
++#define MAC_CTRL2_LCHKS_UNTAG	0x1
++#define MAC_CTRL2_LCHKS_TAG	0x2
++
++#define PHY_ADDR_LNKST_SHIFT	13
++#define PHY_ADDR_LNKST_AUTO	(0x0 << PHY_ADDR_LNKST_SHIFT)
++#define PHY_ADDR_LNKST_UP	(0x1 << PHY_ADDR_LNKST_SHIFT)
++#define PHY_ADDR_LNKST_DOWN	(0x2 << PHY_ADDR_LNKST_SHIFT)
++#define PHY_ADDR_SPEED_SHIFT	11
++#define PHY_ADDR_SPEED_M10	(0x0 << PHY_ADDR_SPEED_SHIFT)
++#define PHY_ADDR_SPEED_M100	(0x1 << PHY_ADDR_SPEED_SHIFT)
++#define PHY_ADDR_SPEED_G1	(0x2 << PHY_ADDR_SPEED_SHIFT)
++#define PHY_ADDR_SPEED_AUTO	(0x3 << PHY_ADDR_SPEED_SHIFT)
++#define PHY_ADDR_FDUP_SHIFT	9
++#define PHY_ADDR_FDUP_AUTO	(0x0 << PHY_ADDR_FDUP_SHIFT)
++#define PHY_ADDR_FDUP_EN	(0x1 << PHY_ADDR_FDUP_SHIFT)
++#define PHY_ADDR_FDUP_DIS	(0x3 << PHY_ADDR_FDUP_SHIFT)
++#define PHY_ADDR_FCONTX_SHIFT	7
++#define PHY_ADDR_FCONTX_AUTO	(0x0 << PHY_ADDR_FCONTX_SHIFT)
++#define PHY_ADDR_FCONTX_EN	(0x1 << PHY_ADDR_FCONTX_SHIFT)
++#define PHY_ADDR_FCONTX_DIS	(0x3 << PHY_ADDR_FCONTX_SHIFT)
++#define PHY_ADDR_FCONRX_SHIFT	5
++#define PHY_ADDR_FCONRX_AUTO	(0x0 << PHY_ADDR_FCONRX_SHIFT)
++#define PHY_ADDR_FCONRX_EN	(0x1 << PHY_ADDR_FCONRX_SHIFT)
++#define PHY_ADDR_FCONRX_DIS	(0x3 << PHY_ADDR_FCONRX_SHIFT)
++
++#define MII_CFG_RES		(1 << 15)
++#define MII_CFG_EN		(1 << 14)
++#define MII_CFG_LDCLKDIS	(1 << 12)
++#define MII_CFG_MIIRATE_SHIFT	4
++#define MII_CFG_MIIRATE_MASK	(0x7 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIRATE_M2P5	(0x0 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIRATE_M25	(0x1 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIRATE_M125	(0x2 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIRATE_M50	(0x3 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIRATE_AUTO	(0x4 << MII_CFG_MIIRATE_SHIFT)
++#define MII_CFG_MIIMODE_MASK	0xf
++#define MII_CFG_MIIMODE_MIIP	0x0
++#define MII_CFG_MIIMODE_MIIM	0x1
++#define MII_CFG_MIIMODE_RMIIP	0x2
++#define MII_CFG_MIIMODE_RMIIM	0x3
++#define MII_CFG_MIIMODE_RGMII	0x4
++
++#define PCDU_RXDLY_SHIFT	7
++#define PCDU_RXDLY_MASK		(0x7 << PCDU_RXDLY_SHIFT)
++#define PCDU_TXDLY_MASK		0x7
++
++#define PMAC_HD_CTL_FC		(1 << 10)
++#define PMAC_HD_CTL_CCRC	(1 << 9)
++#define PMAC_HD_CTL_RST		(1 << 8)
++#define PMAC_HD_CTL_AST		(1 << 7)
++#define PMAC_HD_CTL_RXSH	(1 << 6)
++#define PMAC_HD_CTL_RC		(1 << 4)
++#define PMAC_HD_CTL_AS		(1 << 3)
++#define PMAC_HD_CTL_AC		(1 << 2)
++
++#define PCE_PCTRL_0_IGSTEN	(1 << 11)
++
++#define FDMA_PCTRL_STEN		(1 << 1)
++#define FDMA_PCTRL_EN		(1 << 0)
++
++#define SDMA_PCTRL_EN		(1 << 0)
++
++#define MDIO_GLOB_CTRL_SE	(1 << 15)
++
++#define MDIO_MDC_CFG1_RES	(1 << 15)
++#define MDIO_MDC_CFG1_MCEN	(1 << 8)
++
++#define MDIO_CTRL_MBUSY		(1 << 12)
++#define MDIO_CTRL_OP_READ	(1 << 11)
++#define MDIO_CTRL_OP_WRITE	(1 << 10)
++#define MDIO_CTRL_PHYAD_SHIFT	5
++#define MDIO_CTRL_PHYAD_MASK	(0x1f << MDIO_CTRL_PHYAD_SHIFT)
++#define MDIO_CTRL_REGAD_MASK	0x1f
++
++#endif /* __VRX200_SWITCH_H__ */
+--- a/arch/mips/include/asm/asm.h
++++ b/arch/mips/include/asm/asm.h
+@@ -53,6 +53,7 @@
+ 		.align	2;                              \
+ 		.type	symbol, @function;              \
+ 		.ent	symbol, 0;                      \
++		.section .text.symbol,"x";              \
+ symbol:		.frame	sp, 0, ra
+ 
+ /*
+@@ -62,7 +63,8 @@ symbol:		.frame	sp, 0, ra
+ 		.globl	symbol;                         \
+ 		.align	2;                              \
+ 		.type	symbol, @function;              \
+-		.ent	symbol, 0;                       \
++		.ent	symbol, 0;                      \
++		.section .text.symbol,"x";              \
+ symbol:		.frame	sp, framesize, rpc
+ 
+ /*
+--- /dev/null
++++ b/arch/mips/include/asm/gpio.h
+@@ -0,0 +1,6 @@
++/*
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <asm/arch/gpio.h>
++#include <asm-generic/gpio.h>
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/chipid.h
+@@ -0,0 +1,73 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_CHIPID_H__
++#define __LANTIQ_CHIPID_H__
++
++enum ltq_chip_partnum {
++	LTQ_SOC_UNKNOWN = 0,
++	LTQ_SOC_VRX288_2 = 0x000B,	/* VRX288 v1.2 */
++	LTQ_SOC_VRX268_2 = 0x000C,	/* VRX268 v1.2 */
++	LTQ_SOC_GRX288_2 = 0x000D,	/* GRX288 v1.2 */
++	LTQ_SOC_DANUBE = 0x0129,
++	LTQ_SOC_DANUBE_S = 0x012B,
++	LTQ_SOC_TWINPASS = 0x012D,
++	LTQ_SOC_VRX288 = 0x01C0,	/* VRX288 v1.1 */
++	LTQ_SOC_VRX268 = 0x01C2,	/* VRX268 v1.1 */
++	LTQ_SOC_GRX288 = 0x01C9,	/* GRX288 v1.1 */
++};
++
++extern unsigned int ltq_chip_version_get(void);
++extern unsigned int ltq_chip_partnum_get(void);
++extern const char *ltq_chip_partnum_str(void);
++
++extern void ltq_chip_print_info(void);
++
++#ifdef CONFIG_SOC_XWAY_DANUBE
++static inline int ltq_soc_is_danube(void)
++{
++	return 1;
++}
++#else
++static inline int ltq_soc_is_danube(void)
++{
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_SOC_XWAY_VRX200
++static inline int ltq_soc_is_vrx200(void)
++{
++	return 1;
++}
++
++static inline int ltq_soc_is_vrx200_v1(void)
++{
++	return ltq_chip_version_get() == 1;
++}
++
++static inline int ltq_soc_is_vrx200_v2(void)
++{
++	return ltq_chip_version_get() == 2;
++}
++#else
++static inline int ltq_soc_is_vrx200(void)
++{
++	return 0;
++}
++
++static inline int ltq_soc_is_vrx200_v1(void)
++{
++	return 0;
++}
++
++static inline int ltq_soc_is_vrx200_v2(void)
++{
++	return 0;
++}
++#endif
++
++#endif /* __LANTIQ_CHIPID_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/clk.h
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ * *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_CLK_H__
++#define __LANTIQ_CLK_H__
++
++/* Symbolic clock speeds */
++enum ltq_clk {
++	CLOCK_83_MHZ = 83333333,
++	CLOCK_111_MHZ = 111111111,
++	CLOCK_125_MHZ = 125000000,
++	CLOCK_133_MHZ = 133333333,
++	CLOCK_166_MHZ = 166666667,
++	CLOCK_197_MHZ = 197000000,
++	CLOCK_333_MHZ = 333333333,
++	CLOCK_393_MHZ = 393219000,
++	CLOCK_500_MHZ = 500000000,
++	CLOCK_600_MHZ = 600000000,
++	CLOCK_1000_MHZ = 1000000000,
++};
++
++extern unsigned long ltq_get_cpu_clock(void);
++extern unsigned long ltq_get_bus_clock(void);
++extern unsigned long ltq_get_io_region_clock(void);
++
++#endif /* __LANTIQ_CLK_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/config.h
+@@ -0,0 +1,164 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_CONFIG_H__
++#define __LANTIQ_CONFIG_H__
++
++/* Memory usage */
++#define CONFIG_SYS_MAXARGS		24
++#define CONFIG_SYS_MALLOC_LEN		1024*1024
++#define CONFIG_SYS_BOOTPARAMS_LEN	128*1024
++
++/* Command line */
++#define CONFIG_SYS_PROMPT		CONFIG_MACH_TYPE " # "
++#define CONFIG_SYS_CBSIZE		512
++#define CONFIG_SYS_PBSIZE		(CONFIG_SYS_CBSIZE + \
++					sizeof(CONFIG_SYS_PROMPT)+16)
++
++#define CONFIG_SYS_HUSH_PARSER
++#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
++
++/*
++ * Enable advanced console features on demand to reduce
++ * flash and RAM footprint
++ */
++#if defined(CONFIG_LTQ_ADVANCED_CONSOLE)
++#define CONFIG_SYS_LONGHELP
++#define CONFIG_AUTO_COMPLETE
++#define CONFIG_CMDLINE_EDITING
++#endif
++
++/* SPI flash SPL */
++#if defined(CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH) && defined(CONFIG_SYS_BOOT_SFSPL)
++#define CONFIG_SPL
++#define CONFIG_SPL_SPI_SUPPORT
++#define CONFIG_SPL_SPI_FLASH_SUPPORT
++#define CONFIG_SPI_SPL_SIMPLE
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH) && defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SPL
++#endif
++
++/* Common SPL */
++#if defined(CONFIG_SPL)
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SPL_LIBGENERIC_SUPPORT
++#define CONFIG_SPL_GPIO_SUPPORT
++#define CONFIG_SPL_START_S_PATH		\
++		"arch/mips/cpu/mips32/lantiq-common"
++#define CONFIG_SPL_LDSCRIPT		\
++		"arch/mips/cpu/mips32/lantiq-common/u-boot-spl.lds"
++#endif
++
++#if defined(CONFIG_LTQ_SPL_CONSOLE)
++#define CONFIG_SPL_SERIAL_SUPPORT
++#define CONFIG_SPL_LIBCOMMON_SUPPORT
++#endif
++
++#if defined(CONFIG_LTQ_SPL_COMP_LZMA)
++#define CONFIG_LZMA
++#define CONFIG_SPL_LZMA_SUPPORT
++#endif
++
++#if defined(CONFIG_LTQ_SPL_COMP_LZO)
++#define CONFIG_LZO
++#define CONFIG_SPL_LZO_SUPPORT
++#endif
++
++/* Basic commands */
++#define CONFIG_CMD_BDI
++#define CONFIG_CMD_EDITENV
++#define CONFIG_CMD_IMI
++#define CONFIG_CMD_MEMORY
++#define CONFIG_CMD_RUN
++#define CONFIG_CMD_SAVEENV
++#define CONFIG_CMD_LOADB
++
++/* Other U-Boot settings */
++#define CONFIG_TIMESTAMP
++
++/* Default environment */
++#define CONFIG_ENV_CONSOLEDEV					\
++	"consoledev=" CONFIG_CONSOLE_DEV "\0"
++
++#define CONFIG_ENV_ADDCONSOLE					\
++	"addconsole=setenv bootargs $bootargs"			\
++	" console=$consoledev,$baudrate\0"
++
++#if defined(CONFIG_NET_DEV)
++#define CONFIG_ENV_NETDEV					\
++	"netdev=" CONFIG_NET_DEV "\0"
++#else
++#define CONFIG_ENV_NETDEV					\
++	"netdev=eth0\0"
++#endif
++
++#define CONFIG_ENV_ADDIP					\
++	"addip=setenv bootargs $bootargs"			\
++	" ip=$ipaddr:$serverip::::$netdev:off\0"
++
++#define CONFIG_ENV_ADDETH					\
++	"addeth=setenv bootargs $bootargs"			\
++	" ethaddr=$ethaddr\0"
++
++#define CONFIG_ENV_ADDMACHTYPE					\
++	"addmachtype=setenv bootargs $bootargs"			\
++	" machtype=" CONFIG_MACH_TYPE "\0"
++
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define CONFIG_ENV_WRITE_UBOOT_NOR					\
++	"write-uboot-nor="						\
++	"protect off " __stringify(CONFIG_SYS_FLASH_BASE) " +$filesize && " \
++	"erase " __stringify(CONFIG_SYS_FLASH_BASE) " +$filesize && "	\
++	"cp.b $fileaddr " __stringify(CONFIG_SYS_FLASH_BASE) " $filesize\0"
++
++#define CONFIG_ENV_LOAD_UBOOT_NOR					\
++	"load-uboot-nor=tftpboot u-boot.bin\0"				\
++	"load-uboot-norspl=tftpboot u-boot.ltq.norspl\0"		\
++	"load-uboot-norspl-lzo=tftpboot u-boot.ltq.lzo.norspl\0"	\
++	"load-uboot-norspl-lzma=tftpboot u-boot.ltq.lzma.norspl\0"
++#else
++#define CONFIG_ENV_WRITE_UBOOT_NOR
++#define CONFIG_ENV_LOAD_UBOOT_NOR
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
++#define CONFIG_ENV_SF_PROBE					\
++	"sf-probe=sf probe " __stringify(CONFIG_ENV_SPI_CS) " "	\
++	__stringify(CONFIG_ENV_SPI_MAX_HZ) " "			\
++	__stringify(CONFIG_ENV_SPI_MODE) " \0"
++
++#define CONFIG_ENV_WRITE_UBOOT_SF				\
++	"write-uboot-sf="					\
++	"run sf-probe && sf erase 0 +$filesize && "		\
++	"sf write $fileaddr 0 $filesize\0"
++
++#define CONFIG_ENV_LOAD_UBOOT_SF					\
++	"load-uboot-sfspl=tftpboot u-boot.ltq.sfspl\0"			\
++	"load-uboot-sfspl-lzo=tftpboot u-boot.ltq.lzo.sfspl\0"		\
++	"load-uboot-sfspl-lzma=tftpboot u-boot.ltq.lzma.sfspl\0"
++#else
++#define CONFIG_ENV_SF_PROBE
++#define CONFIG_ENV_WRITE_UBOOT_SF
++#define CONFIG_ENV_LOAD_UBOOT_SF
++#endif
++
++#define CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_CONSOLEDEV		\
++	CONFIG_ENV_ADDCONSOLE		\
++	CONFIG_ENV_NETDEV		\
++	CONFIG_ENV_ADDIP		\
++	CONFIG_ENV_ADDETH		\
++	CONFIG_ENV_ADDMACHTYPE		\
++	CONFIG_ENV_WRITE_UBOOT_NOR	\
++	CONFIG_ENV_LOAD_UBOOT_NOR	\
++	CONFIG_ENV_SF_PROBE		\
++	CONFIG_ENV_WRITE_UBOOT_SF	\
++	CONFIG_ENV_LOAD_UBOOT_SF
++
++#endif /* __LANTIQ_CONFIG_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/cpu.h
+@@ -0,0 +1,34 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_CPU_H__
++#define __LANTIQ_CPU_H__
++
++enum ltq_boot_select {
++	BOOT_NOR,
++	BOOT_NOR_NO_BOOTROM,
++	BOOT_UART,
++	BOOT_UART_NO_EEPROM,
++	BOOT_SPI,
++	BOOT_NAND,
++	BOOT_PCI,
++	BOOT_MII0,
++	BOOT_RMII0,
++	BOOT_RGMII1,
++	BOOT_UNKNOWN,
++};
++
++enum ltq_boot_select ltq_boot_select(void);
++const char *ltq_boot_select_str(void);
++
++void ltq_pmu_init(void);
++void ltq_ebu_init(void);
++void ltq_gpio_init(void);
++
++void ltq_pll_init(void);
++void ltq_dcdc_init(unsigned int dig_ref);
++
++#endif /* __LANTIQ_CPU_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/dma.h
+@@ -0,0 +1,94 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_DMA_H__
++#define __LANTIQ_DMA_H__
++
++enum ltq_dma_endianess {
++	LTQ_DMA_ENDIANESS_B0_B1_B2_B3,	/* No byte swapping */
++	LTQ_DMA_ENDIANESS_B1_B0_B3_B2,	/* B0B1B2B3 => B1B0B3B2 */
++	LTQ_DMA_ENDIANESS_B2_B3_B0_B1,	/* B0B1B2B3 => B2B3B0B1 */
++	LTQ_DMA_ENDIANESS_B3_B2_B1_B0,	/* B0B1B2B3 => B3B2B1B0 */
++};
++
++enum ltq_dma_burst_len {
++	LTQ_DMA_BURST_2WORDS = 1,
++	LTQ_DMA_BURST_4WORDS = 2,
++	LTQ_DMA_BURST_8WORDS = 3,
++};
++
++struct ltq_dma_desc {
++	u32 ctl;
++	u32 addr;
++};
++
++struct ltq_dma_channel {
++	struct ltq_dma_device *dev;
++	u8 chan_no;
++	u8 class;
++	u16 num_desc;
++	struct ltq_dma_desc *desc_base;
++	void *mem_base;
++	u32 dma_addr;
++};
++
++struct ltq_dma_device {
++	enum ltq_dma_endianess rx_endian_swap;
++	enum ltq_dma_endianess tx_endian_swap;
++	enum ltq_dma_burst_len rx_burst_len;
++	enum ltq_dma_burst_len tx_burst_len;
++	struct ltq_dma_channel rx_chan;
++	struct ltq_dma_channel tx_chan;
++	u8 port;
++};
++
++/**
++ * Initialize DMA hardware and driver
++ */
++void ltq_dma_init(void);
++
++/**
++ * Register given DMA client context
++ *
++ * @returns 0 on success, negative value otherwise
++ */
++int ltq_dma_register(struct ltq_dma_device *dev);
++
++/**
++ * Reset and halt all channels related to given DMA client
++ */
++void ltq_dma_reset(struct ltq_dma_device *dev);
++void ltq_dma_enable(struct ltq_dma_device *dev);
++void ltq_dma_disable(struct ltq_dma_device *dev);
++
++/**
++ * Map RX DMA descriptor to memory region
++ *
++ * @returns 0 on success, negative value otherwise
++ */
++int ltq_dma_rx_map(struct ltq_dma_device *dev, int index, void *data, int len);
++
++/**
++ * Check if new data is available.
++ *
++ * @returns length of received data, 0 otherwise
++ */
++int ltq_dma_rx_poll(struct ltq_dma_device *dev, int index);
++
++int ltq_dma_rx_length(struct ltq_dma_device *dev, int index);
++
++/**
++ * Map TX DMA descriptor to memory region
++ *
++ * @returns 0 on success, negative value otherwise
++ */
++int ltq_dma_tx_map(struct ltq_dma_device *dev, int index, void *data, int len,
++			unsigned long timeout);
++
++int ltq_dma_tx_wait(struct ltq_dma_device *dev, int index,
++			unsigned long timeout);
++
++#endif /* __LANTIQ_DMA_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/eth.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_ETH_H__
++#define __LANTIQ_ETH_H__
++
++#include <phy.h>
++
++enum LTQ_ETH_PORT_FLAGS {
++	LTQ_ETH_PORT_NONE	= 0,
++	LTQ_ETH_PORT_PHY	= 1,
++	LTQ_ETH_PORT_SWITCH	= (1 << 1),
++	LTQ_ETH_PORT_MAC	= (1 << 2),
++};
++
++struct ltq_eth_port_config {
++	u8 num;
++	u8 phy_addr;
++	u16 flags;
++	phy_interface_t phy_if;
++	u8 rgmii_rx_delay;
++	u8 rgmii_tx_delay;
++};
++
++struct ltq_eth_board_config {
++	const struct ltq_eth_port_config *ports;
++	int num_ports;
++};
++
++extern int ltq_eth_initialize(const struct ltq_eth_board_config *board_config);
++
++#endif /* __LANTIQ_ETH_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/gpio.h
+@@ -0,0 +1,50 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_GPIO_H__
++#define __LANTIQ_GPIO_H__
++
++enum ltq_gpio_dir {
++	GPIO_DIR_IN = 0,
++	GPIO_DIR_OUT
++};
++
++enum ltq_gpio_od {
++	GPIO_OD_ACTIVE = 0,
++	GPIO_OD_NORMAL
++};
++
++enum ltq_gpio_altsel {
++	GPIO_ALTSEL_CLR = 0,
++	GPIO_ALTSEL_SET
++};
++
++extern int gpio_set_altfunc(unsigned gpio, int altsel0, int altsel1, int dir);
++extern int gpio_set_opendrain(unsigned gpio, int od);
++
++static inline int gpio_to_port(unsigned gpio)
++{
++	return gpio >> 4;
++}
++
++static inline int gpio_to_pin(unsigned gpio)
++{
++	return gpio & 0xF;
++}
++
++static inline int gpio_to_bit(unsigned gpio)
++{
++	return 1 << gpio_to_pin(gpio);
++}
++
++static inline int gpio_to_gpio(unsigned port, unsigned pin)
++{
++	return (port << 4) | (pin & 0xF);
++}
++
++#include <asm-generic/gpio.h>
++
++#endif /* __LANTIQ_GPIO_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/io.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2010 John Crispin <blogic@openwrt.org>
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_IO_H__
++#define __LANTIQ_IO_H__
++
++#include <asm/io.h>
++
++#define ltq_readb(a)		__raw_readb(a)
++#define ltq_writeb(a, v)	__raw_writeb(v, a)
++
++#define ltq_readl(a)		__raw_readl(a)
++#define ltq_writel(a, v)	__raw_writel(v, a)
++
++#define ltq_clrbits(a, clear) \
++	ltq_writel(a, ltq_readl(a) & ~(clear))
++
++#define ltq_setbits(a, set) \
++	ltq_writel(a, ltq_readl(a) | (set))
++
++#define ltq_clrsetbits(a, clear, set) \
++	ltq_writel(a, (ltq_readl(a) & ~(clear)) | (set))
++
++static inline void ltq_reg_dump(const void *addr, const char *desc)
++{
++	u32 data;
++
++	data = ltq_readl(addr);
++	printf("ltq_reg_dump: %s 0x%p = 0x%08x\n",
++		desc, addr, data);
++}
++
++#endif /* __LANTIQ_IO_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/pm.h
+@@ -0,0 +1,21 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_PM_H__
++#define __LANTIQ_PM_H__
++
++enum ltq_pm_modules {
++	LTQ_PM_CORE,
++	LTQ_PM_DMA,
++	LTQ_PM_ETH,
++	LTQ_PM_SPI,
++};
++
++u32 ltq_pm_map(enum ltq_pm_modules module);
++int ltq_pm_enable(enum ltq_pm_modules module);
++int ltq_pm_disable(enum ltq_pm_modules module);
++
++#endif /* __LANTIQ_PM_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/lantiq/reset.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __LANTIQ_RESET_H__
++#define __LANTIQ_RESET_H__
++
++enum ltq_reset_modules {
++	LTQ_RESET_CORE,
++	LTQ_RESET_DMA,
++	LTQ_RESET_ETH,
++	LTQ_RESET_PHY,
++	LTQ_RESET_HARD,
++	LTQ_RESET_SOFT,
++};
++
++extern u32 ltq_reset_map(enum ltq_reset_modules module);
++extern int ltq_reset_activate(enum ltq_reset_modules module);
++extern int ltq_reset_deactivate(enum ltq_reset_modules module);
++
++static inline int ltq_reset_once(enum ltq_reset_modules module, ulong usec)
++{
++	int ret;
++
++	ret = ltq_reset_activate(module);
++	if (ret)
++		return ret;
++
++	__udelay(usec);
++	ret = ltq_reset_deactivate(module);
++
++	return ret;
++}
++
++#endif /* __LANTIQ_RESET_H__ */
+--- a/arch/mips/include/asm/mipsregs.h
++++ b/arch/mips/include/asm/mipsregs.h
+@@ -46,7 +46,10 @@
+ #define CP0_ENTRYLO1 $3
+ #define CP0_CONF $3
+ #define CP0_CONTEXT $4
++#define CP0_CONTEXTCONFIG $4,1
++#define CP0_USERLOCAL $4,1
+ #define CP0_PAGEMASK $5
++#define CP0_PAGEGRAIN $5,1
+ #define CP0_WIRED $6
+ #define CP0_INFO $7
+ #define CP0_BADVADDR $8
+@@ -54,10 +57,19 @@
+ #define CP0_ENTRYHI $10
+ #define CP0_COMPARE $11
+ #define CP0_STATUS $12
++#define CP0_INTCTL $12,1
++#define CP0_SRSCTL $12,2
++#define CP0_SRSMAP $12,3
++#define CP0_SRSHIGH $12,4
+ #define CP0_CAUSE $13
+ #define CP0_EPC $14
+ #define CP0_PRID $15
++#define CP0_EBASE $15,1
+ #define CP0_CONFIG $16
++#define CP0_CONFIG1 $16,1
++#define CP0_CONFIG2 $16,2
++#define CP0_CONFIG3 $16,3
++#define CP0_CONFIG7 $16,7
+ #define CP0_LLADDR $17
+ #define CP0_WATCHLO $18
+ #define CP0_WATCHHI $19
+@@ -70,7 +82,17 @@
+ #define CP0_ECC $26
+ #define CP0_CACHEERR $27
+ #define CP0_TAGLO $28
++#define CP0_ITAGLO $28
++#define CP0_IDATALO $28,1
++#define CP0_DTAGLO $28,2
++#define CP0_DDATALO $28,3
++#define CP0_L23TAGLO $28,4
++#define CP0_L23DATALO $28,5
+ #define CP0_TAGHI $29
++#define CP0_IDATAHI $29,1
++#define CP0_DTAGHI $29,2
++#define CP0_L23TAGHI $29,4
++#define CP0_L23DATAHI $29,5
+ #define CP0_ERROREPC $30
+ #define CP0_DESAVE $31
+ 
+@@ -395,6 +417,12 @@
+ #define  CAUSEF_BD		(_ULCAST_(1)   << 31)
+ 
+ /*
++ * Bits in the coprocessor 0 EBase register.
++ */
++#define EBASEB_CPUNUM		0
++#define EBASEF_CPUNUM		(_ULCAST_(1023))
++
++/*
+  * Bits in the coprocessor 0 config register.
+  */
+ /* Generic bits.  */
+--- a/arch/mips/include/asm/u-boot-mips.h
++++ b/arch/mips/include/asm/u-boot-mips.h
+@@ -23,3 +23,4 @@ static inline unsigned long image_copy_e
+ }
+ 
+ extern int incaip_set_cpuclk(void);
++extern int arch_cpu_init(void);
+--- a/arch/mips/lib/board.c
++++ b/arch/mips/lib/board.c
+@@ -33,6 +33,16 @@ static char *failed = "*** failed ***\n"
+  */
+ const unsigned long mips_io_port_base = -1;
+ 
++int __arch_cpu_init(void)
++{
++	/*
++	 * Nothing to do in this dummy implementation
++	 */
++	return 0;
++}
++int arch_cpu_init(void)
++	__attribute__((weak, alias("__arch_cpu_init")));
++
+ int __board_early_init_f(void)
+ {
+ 	/*
+@@ -106,6 +116,7 @@ static int init_baudrate(void)
+ typedef int (init_fnc_t)(void);
+ 
+ init_fnc_t *init_sequence[] = {
++	arch_cpu_init,
+ 	board_early_init_f,
+ 	timer_init,
+ 	env_init,		/* initialize environment */
+--- a/drivers/dma/Makefile
++++ b/drivers/dma/Makefile
+@@ -12,6 +12,7 @@ LIB	:= $(obj)libdma.o
+ COBJS-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
+ COBJS-$(CONFIG_APBH_DMA) += apbh_dma.o
+ COBJS-$(CONFIG_FSL_DMA) += fsl_dma.o
++COBJS-$(CONFIG_LANTIQ_DMA) += lantiq_dma.o
+ COBJS-$(CONFIG_OMAP3_DMA) += omap3_dma.o
+ 
+ COBJS	:= $(COBJS-y)
+--- /dev/null
++++ b/drivers/dma/lantiq_dma.c
+@@ -0,0 +1,387 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <watchdog.h>
++#include <linux/compiler.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/dma.h>
++#include <asm/lantiq/pm.h>
++#include <asm/lantiq/reset.h>
++#include <asm/arch/soc.h>
++#include <asm/processor.h>
++
++#define DMA_CTRL_PKTARB			(1 << 31)
++#define DMA_CTRL_MBRSTARB		(1 << 30)
++#define DMA_CTRL_MBRSTCNT_SHIFT		16
++#define DMA_CTRL_MBRSTCNT_MASK		(0x3ff << DMA_CTRL_MBRSTCNT_SHIFT)
++#define DMA_CTRL_DRB			(1 << 8)
++#define DMA_CTRL_RESET			(1 << 0)
++
++#define DMA_CPOLL_EN			(1 << 31)
++#define DMA_CPOLL_CNT_SHIFT		4
++#define DMA_CPOLL_CNT_MASK		(0xFFF << DMA_CPOLL_CNT_SHIFT)
++
++#define DMA_CCTRL_TXWGT_SHIFT		16
++#define DMA_CCTRL_TXWGT_MASK		(0x3 << DMA_CCTRL_TXWGT_SHIFT)
++#define DMA_CCTRL_CLASS_SHIFT		9
++#define DMA_CCTRL_CLASS_MASK		(0x3 << DMA_CCTRL_CLASS_SHIFT)
++#define DMA_CCTRL_RST			(1 << 1)
++#define DMA_CCTRL_ONOFF			(1 << 0)
++
++#define DMA_PCTRL_TXBL_SHIFT		4
++#define DMA_PCTRL_TXBL_2WORDS		(1 << DMA_PCTRL_TXBL_SHIFT)
++#define DMA_PCTRL_TXBL_4WORDS		(2 << DMA_PCTRL_TXBL_SHIFT)
++#define DMA_PCTRL_TXBL_8WORDS		(3 << DMA_PCTRL_TXBL_SHIFT)
++#define DMA_PCTRL_RXBL_SHIFT		2
++#define DMA_PCTRL_RXBL_2WORDS		(1 << DMA_PCTRL_RXBL_SHIFT)
++#define DMA_PCTRL_RXBL_4WORDS		(2 << DMA_PCTRL_RXBL_SHIFT)
++#define DMA_PCTRL_RXBL_8WORDS		(3 << DMA_PCTRL_RXBL_SHIFT)
++#define DMA_PCTRL_TXENDI_SHIFT		10
++#define DMA_PCTRL_TXENDI_MASK		(0x3 << DMA_PCTRL_TXENDI_SHIFT)
++#define DMA_PCTRL_RXENDI_SHIFT		8
++#define DMA_PCTRL_RXENDI_MASK		(0x3 << DMA_PCTRL_RXENDI_SHIFT)
++
++#define DMA_DESC_OWN			(1 << 31)
++#define DMA_DESC_C			(1 << 30)
++#define DMA_DESC_SOP			(1 << 29)
++#define DMA_DESC_EOP			(1 << 28)
++#define DMA_DESC_TX_OFFSET(x)		((x & 0x1f) << 23)
++#define DMA_DESC_RX_OFFSET(x)		((x & 0x3) << 23)
++#define DMA_DESC_LENGTH(x)		(x & 0xffff)
++
++#define PTR_ALIGN(p, a)		((typeof(p))ALIGN((unsigned long)(p), (a)))
++
++struct ltq_dma_regs {
++	u32	clc;		/* Clock control */
++	u32	rsvd0;
++	u32	id;		/* Identification */
++	u32	rsvd1;
++	u32	ctrl;		/* Control */
++	u32	cpoll;		/* Channel polling */
++	u32	cs;		/* Channel select */
++	u32	cctrl;		/* Channel control */
++	u32	cdba;		/* Channel descriptor base address */
++	u32	cdlen;		/* Channel descriptor length */
++	u32	cis;		/* Channel interrupt status */
++	u32	cie;		/* Channel interrupt enable */
++	u32	cgbl;		/* Channel global buffer length */
++	u32	cdptnrd;	/* Current descriptor pointer */
++	u32	rsvd2[2];
++	u32	ps;		/* Port select */
++	u32	pctrl;		/* Port control */
++	u32	rsvd3[43];
++	u32	irnen;		/* Interrupt node enable */
++	u32	irncr;		/* Interrupt node control */
++	u32	irnicr;		/* Interrupt capture */
++};
++
++static struct ltq_dma_regs *ltq_dma_regs =
++	(struct ltq_dma_regs *) CKSEG1ADDR(LTQ_DMA_BASE);
++
++static inline unsigned long ltq_dma_addr_to_virt(u32 dma_addr)
++{
++	return KSEG0ADDR(dma_addr);
++}
++
++static inline u32 ltq_virt_to_dma_addr(void *addr)
++{
++	return CPHYSADDR(addr);
++}
++
++static inline int ltq_dma_burst_align(enum ltq_dma_burst_len burst_len)
++{
++	switch (burst_len) {
++	case LTQ_DMA_BURST_2WORDS:
++		return 2 * 4;
++	case LTQ_DMA_BURST_4WORDS:
++		return 4 * 4;
++	case LTQ_DMA_BURST_8WORDS:
++		return 8 * 4;
++	}
++
++	return 0;
++}
++
++static inline void ltq_dma_sync(void)
++{
++	__asm__ __volatile__("sync");
++}
++
++static inline void ltq_dma_dcache_wb_inv(const void *ptr, size_t size)
++{
++	unsigned long addr = (unsigned long) ptr;
++
++	flush_dcache_range(addr, addr + size);
++	ltq_dma_sync();
++}
++
++static inline void ltq_dma_dcache_inv(const void *ptr, size_t size)
++{
++	unsigned long addr = (unsigned long) ptr;
++
++	invalidate_dcache_range(addr, addr + size);
++}
++
++void ltq_dma_init(void)
++{
++	/* Power up DMA */
++	ltq_pm_enable(LTQ_PM_DMA);
++
++	/* Reset DMA */
++	ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_RESET);
++
++	/* Disable and clear all interrupts */
++	ltq_writel(&ltq_dma_regs->irnen, 0);
++	ltq_writel(&ltq_dma_regs->irncr, 0xFFFFF);
++
++#if 0
++	/* Enable packet arbitration */
++	ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_PKTARB);
++#endif
++
++#if 0
++	/* Enable descriptor read back */
++	ltq_setbits(&ltq_dma_regs->ctrl, DMA_CTRL_DRB);
++#endif
++
++	/* Enable polling for descriptor fetching for all channels */
++	ltq_writel(&ltq_dma_regs->cpoll, DMA_CPOLL_EN |
++		(4 << DMA_CPOLL_CNT_SHIFT));
++}
++
++static void ltq_dma_channel_reset(struct ltq_dma_channel *chan)
++{
++	ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
++	ltq_setbits(&ltq_dma_regs->cctrl, DMA_CCTRL_RST);
++}
++
++static void ltq_dma_channel_enable(struct ltq_dma_channel *chan)
++{
++	ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
++	ltq_setbits(&ltq_dma_regs->cctrl, DMA_CCTRL_ONOFF);
++}
++
++static void ltq_dma_channel_disable(struct ltq_dma_channel *chan)
++{
++	ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
++	ltq_clrbits(&ltq_dma_regs->cctrl, DMA_CCTRL_ONOFF);
++}
++
++static void ltq_dma_port_init(struct ltq_dma_device *dev)
++{
++	u32 pctrl;
++
++	pctrl = dev->tx_endian_swap << DMA_PCTRL_TXENDI_SHIFT;
++	pctrl |= dev->rx_endian_swap << DMA_PCTRL_RXENDI_SHIFT;
++	pctrl |= dev->tx_burst_len << DMA_PCTRL_TXBL_SHIFT;
++	pctrl |= dev->rx_burst_len << DMA_PCTRL_RXBL_SHIFT;
++
++	ltq_writel(&ltq_dma_regs->ps, dev->port);
++	ltq_writel(&ltq_dma_regs->pctrl, pctrl);
++}
++
++static int ltq_dma_alloc_descriptors(struct ltq_dma_device *dev,
++					struct ltq_dma_channel *chan)
++{
++	size_t size;
++	void *desc_base;
++
++	size = ALIGN(sizeof(struct ltq_dma_desc) * chan->num_desc +
++			ARCH_DMA_MINALIGN, ARCH_DMA_MINALIGN);
++
++	chan->mem_base = malloc(size);
++	if (!chan->mem_base)
++		return 1;
++
++	memset(chan->mem_base, 0, size);
++	ltq_dma_dcache_wb_inv(chan->mem_base, size);
++
++	desc_base = PTR_ALIGN(chan->mem_base, ARCH_DMA_MINALIGN);
++
++	debug("DMA: mem %p, desc %p\n", chan->mem_base, desc_base);
++
++	/* Align descriptor base to 8 bytes */
++	chan->desc_base = (void *) CKSEG1ADDR(desc_base);
++	chan->dma_addr = CPHYSADDR(desc_base);
++	chan->dev = dev;
++
++	debug("DMA: desc_base %p, size %u\n", chan->desc_base, size);
++
++	/* Configure hardware with location of descriptor list */
++	ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
++	ltq_writel(&ltq_dma_regs->cdba, chan->dma_addr);
++	ltq_writel(&ltq_dma_regs->cdlen, chan->num_desc);
++	ltq_writel(&ltq_dma_regs->cctrl, (3 << DMA_CCTRL_TXWGT_SHIFT) |
++		(chan->class << DMA_CCTRL_CLASS_SHIFT));
++	ltq_writel(&ltq_dma_regs->cctrl, DMA_CCTRL_RST);
++
++	return 0;
++}
++
++static void ltq_dma_free_descriptors(struct ltq_dma_channel *chan)
++{
++	ltq_writel(&ltq_dma_regs->cs, chan->chan_no);
++	ltq_writel(&ltq_dma_regs->cdba, 0);
++	ltq_writel(&ltq_dma_regs->cdlen, 0);
++
++	ltq_dma_channel_reset(chan);
++
++	free(chan->mem_base);
++}
++
++int ltq_dma_register(struct ltq_dma_device *dev)
++{
++	int ret;
++
++	ltq_dma_port_init(dev);
++
++	ret = ltq_dma_alloc_descriptors(dev, &dev->rx_chan);
++	if (ret)
++		return ret;
++
++	ret = ltq_dma_alloc_descriptors(dev, &dev->tx_chan);
++	if (ret) {
++		ltq_dma_free_descriptors(&dev->rx_chan);
++		return ret;
++	}
++
++	return 0;
++}
++
++void ltq_dma_reset(struct ltq_dma_device *dev)
++{
++	ltq_dma_channel_reset(&dev->rx_chan);
++	ltq_dma_channel_reset(&dev->tx_chan);
++}
++
++void ltq_dma_enable(struct ltq_dma_device *dev)
++{
++	ltq_dma_channel_enable(&dev->rx_chan);
++	ltq_dma_channel_enable(&dev->tx_chan);
++}
++
++void ltq_dma_disable(struct ltq_dma_device *dev)
++{
++	ltq_dma_channel_disable(&dev->rx_chan);
++	ltq_dma_channel_disable(&dev->tx_chan);
++}
++
++int ltq_dma_rx_map(struct ltq_dma_device *dev, int index, void *data, int len)
++{
++	struct ltq_dma_channel *chan = &dev->rx_chan;
++	struct ltq_dma_desc *desc = &chan->desc_base[index];
++	u32 dma_addr = ltq_virt_to_dma_addr(data);
++	unsigned int offset;
++
++	offset = dma_addr % ltq_dma_burst_align(dev->rx_burst_len);
++
++	ltq_dma_dcache_inv(data, len);
++
++#if 0
++	printf("%s: index %d, data %p, dma_addr %08x, offset %u, len %d\n",
++		__func__, index, data, dma_addr, offset, len);
++#endif
++
++
++	desc->addr = dma_addr - offset;
++	desc->ctl = DMA_DESC_OWN | DMA_DESC_RX_OFFSET(offset) |
++			DMA_DESC_LENGTH(len);
++
++#if 0
++	printf("%s: index %d, desc %p, desc->ctl %08x\n",
++		__func__, index, desc, desc->ctl);
++#endif
++
++	return 0;
++}
++
++int ltq_dma_rx_poll(struct ltq_dma_device *dev, int index)
++{
++	struct ltq_dma_channel *chan = &dev->rx_chan;
++	struct ltq_dma_desc *desc = &chan->desc_base[index];
++
++#if 0
++	printf("%s: index %d, desc %p, desc->ctl %08x\n",
++		__func__, index, desc, desc->ctl);
++#endif
++
++	if (desc->ctl & DMA_DESC_OWN)
++		return 0;
++
++	if (desc->ctl & DMA_DESC_C)
++		return 1;
++
++	return 0;
++}
++
++int ltq_dma_rx_length(struct ltq_dma_device *dev, int index)
++{
++	struct ltq_dma_channel *chan = &dev->rx_chan;
++	struct ltq_dma_desc *desc = &chan->desc_base[index];
++
++	return DMA_DESC_LENGTH(desc->ctl);
++}
++
++int ltq_dma_tx_map(struct ltq_dma_device *dev, int index, void *data, int len,
++			unsigned long timeout)
++{
++	struct ltq_dma_channel *chan = &dev->tx_chan;
++	struct ltq_dma_desc *desc = &chan->desc_base[index];
++	unsigned int offset;
++	unsigned long timebase = get_timer(0);
++	u32 dma_addr = ltq_virt_to_dma_addr(data);
++
++	while (desc->ctl & DMA_DESC_OWN) {
++		WATCHDOG_RESET();
++
++		if (get_timer(timebase) >= timeout) {
++#if 0
++			printf("%s: timeout: index %d, desc %p, desc->ctl %08x\n",
++				__func__, index, desc, desc->ctl);
++#endif
++			return -1;
++		}
++	}
++
++	offset = dma_addr % ltq_dma_burst_align(dev->rx_burst_len);
++
++#if 0
++	printf("%s: index %d, desc %p, data %p, dma_addr %08x, offset %u, len %d\n",
++		__func__, index, desc, data, dma_addr, offset, len);
++#endif
++
++	ltq_dma_dcache_wb_inv(data, len);
++
++	desc->addr = dma_addr - offset;
++	desc->ctl = DMA_DESC_OWN | DMA_DESC_SOP | DMA_DESC_EOP |
++			DMA_DESC_TX_OFFSET(offset) | DMA_DESC_LENGTH(len);
++
++#if 0
++	printf("%s: index %d, desc %p, desc->ctl %08x\n",
++		__func__, index, desc, desc->ctl);
++#endif
++
++	return 0;
++}
++
++int ltq_dma_tx_wait(struct ltq_dma_device *dev, int index,
++			unsigned long timeout)
++{
++	struct ltq_dma_channel *chan = &dev->tx_chan;
++	struct ltq_dma_desc *desc = &chan->desc_base[index];
++	unsigned long timebase = get_timer(0);
++
++	while ((desc->ctl & (DMA_DESC_OWN | DMA_DESC_C)) != DMA_DESC_C) {
++		WATCHDOG_RESET();
++
++		if (get_timer(timebase) >= timeout)
++			return -1;
++	}
++
++	return 0;
++}
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -12,6 +12,7 @@ LIB 	:= $(obj)libgpio.o
+ COBJS-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
+ COBJS-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
+ COBJS-$(CONFIG_KIRKWOOD_GPIO)	+= kw_gpio.o
++COBJS-$(CONFIG_LANTIQ_GPIO)	+= lantiq_gpio.o
+ COBJS-$(CONFIG_MARVELL_GPIO)	+= mvgpio.o
+ COBJS-$(CONFIG_MARVELL_MFP)	+= mvmfp.o
+ COBJS-$(CONFIG_MXC_GPIO)	+= mxc_gpio.o
+--- /dev/null
++++ b/drivers/gpio/lantiq_gpio.c
+@@ -0,0 +1,329 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/gpio.h>
++#include <asm/lantiq/io.h>
++
++#define SSIO_GPIO_BASE		64
++
++#define SSIO_CON0_SWU		(1 << 31)
++#define SSIO_CON0_RZFL		(1 << 26)
++#define SSIO_CON0_GPHY1_SHIFT	27
++#define SSIO_CON0_GPHY1_CONFIG	((CONFIG_LTQ_SSIO_GPHY1_MODE & 0x7) << 27)
++
++#define SSIO_CON1_US_FPI	(2 << 30)
++#define SSIO_CON1_FPID_2HZ	(0 << 23)
++#define SSIO_CON1_FPID_4HZ	(1 << 23)
++#define SSIO_CON1_FPID_8HZ	(2 << 23)
++#define SSIO_CON1_FPID_10HZ	(3 << 23)
++#define SSIO_CON1_FPIS_1_2	(1 << 20)
++#define SSIO_CON1_FPIS_1_32	(2 << 20)
++#define SSIO_CON1_FPIS_1_64	(3 << 20)
++
++#define SSIO_CON1_GPHY2_SHIFT	15
++#define SSIO_CON1_GPHY2_CONFIG	((CONFIG_LTQ_SSIO_GPHY2_MODE & 0x7) << 15)
++
++#define SSIO_CON1_GROUP2	(1 << 2)
++#define SSIO_CON1_GROUP1	(1 << 1)
++#define SSIO_CON1_GROUP0	(1 << 0)
++#define SSIO_CON1_GROUP_CONFIG	(0x3)
++
++#ifdef CONFIG_LTQ_SSIO_SHIFT_REGS
++#define enable_ssio	1
++#else
++#define enable_ssio	0
++
++#define CONFIG_LTQ_SSIO_GPHY1_MODE	0
++#define CONFIG_LTQ_SSIO_GPHY2_MODE	0
++#define CONFIG_LTQ_SSIO_INIT_VALUE	0
++#endif
++
++#ifdef CONFIG_LTQ_SSIO_EDGE_FALLING
++#define SSIO_RZFL_CONFIG	SSIO_CON0_RZFL
++#else
++#define SSIO_RZFL_CONFIG	0
++#endif
++
++struct ltq_gpio_port_regs {
++	__be32	out;
++	__be32	in;
++	__be32	dir;
++	__be32	altsel0;
++	__be32	altsel1;
++	__be32	od;
++	__be32	stoff;
++	__be32	pudsel;
++	__be32	puden;
++	__be32	rsvd1[3];
++};
++
++struct ltq_gpio_regs {
++	u32				rsvd[4];
++	struct ltq_gpio_port_regs	ports[CONFIG_LTQ_GPIO_MAX_BANKS];
++};
++
++struct ltq_gpio3_regs {
++	u32	rsvd0[13];
++	__be32	od;
++	__be32	pudsel;
++	__be32	puden;
++	u32	rsvd1[9];
++	__be32	altsel1;
++	u32	rsvd2[14];
++	__be32	out;
++	__be32	in;
++	__be32	dir;
++	__be32	altsel0;
++};
++
++struct ltq_ssio_regs {
++	__be32	con0;
++	__be32	con1;
++	__be32	cpu0;
++	__be32	cpu1;
++	__be32	ar;
++};
++
++static struct ltq_gpio_regs *ltq_gpio_regs =
++	(struct ltq_gpio_regs *) CKSEG1ADDR(LTQ_GPIO_BASE);
++
++static struct ltq_gpio3_regs *ltq_gpio3_regs =
++	(struct ltq_gpio3_regs *) CKSEG1ADDR(LTQ_GPIO_BASE);
++
++static struct ltq_ssio_regs *ltq_ssio_regs =
++	(struct ltq_ssio_regs *) CKSEG1ADDR(LTQ_SSIO_BASE);
++
++static int is_gpio_bank3(unsigned int port)
++{
++#ifdef CONFIG_LTQ_HAS_GPIO_BANK3
++	return port == 3;
++#else
++	return 0;
++#endif
++}
++
++static int is_gpio_ssio(unsigned int gpio)
++{
++#ifdef CONFIG_LTQ_SSIO_SHIFT_REGS
++	return gpio >= SSIO_GPIO_BASE;
++#else
++	return 0;
++#endif
++}
++
++static inline int ssio_gpio_to_bit(unsigned gpio)
++{
++	return 1 << (gpio - SSIO_GPIO_BASE);
++}
++
++int ltq_gpio_init(void)
++{
++	ltq_writel(&ltq_ssio_regs->ar, 0);
++	ltq_writel(&ltq_ssio_regs->cpu0, CONFIG_LTQ_SSIO_INIT_VALUE);
++	ltq_writel(&ltq_ssio_regs->cpu1, 0);
++	ltq_writel(&ltq_ssio_regs->con0, SSIO_CON0_SWU);
++
++	if (enable_ssio) {
++		ltq_writel(&ltq_ssio_regs->con0, SSIO_CON0_GPHY1_CONFIG |
++			SSIO_RZFL_CONFIG);
++		ltq_writel(&ltq_ssio_regs->con1, SSIO_CON1_US_FPI |
++			SSIO_CON1_FPID_8HZ | SSIO_CON1_GPHY2_CONFIG |
++			SSIO_CON1_GROUP_CONFIG);
++	}
++
++	return 0;
++}
++
++int gpio_request(unsigned gpio, const char *label)
++{
++	return 0;
++}
++
++int gpio_free(unsigned gpio)
++{
++	return 0;
++}
++
++int gpio_direction_input(unsigned gpio)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_od = &ltq_gpio_regs->ports[port].od;
++	const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
++	const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
++	const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
++
++	if (is_gpio_ssio(gpio))
++		return 0;
++
++	if (is_gpio_bank3(port)) {
++		gpio_od = &ltq_gpio3_regs->od;
++		gpio_altsel0 = &ltq_gpio3_regs->altsel0;
++		gpio_altsel1 = &ltq_gpio3_regs->altsel1;
++		gpio_dir = &ltq_gpio3_regs->dir;
++	}
++
++	/*
++	 * Reset open drain and altsel configs to workaround improper
++	 * reset values or unwanted modifications by BootROM
++	 */
++	ltq_clrbits(gpio_od, gpio_to_bit(gpio));
++	ltq_clrbits(gpio_altsel0, gpio_to_bit(gpio));
++	ltq_clrbits(gpio_altsel1, gpio_to_bit(gpio));
++
++	/* Switch to input */
++	ltq_clrbits(gpio_dir, gpio_to_bit(gpio));
++
++	return 0;
++}
++
++int gpio_direction_output(unsigned gpio, int value)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_od = &ltq_gpio_regs->ports[port].od;
++	const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
++	const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
++	const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
++	const void *gpio_out = &ltq_gpio_regs->ports[port].out;
++	u32 data = gpio_to_bit(gpio);
++
++	if (is_gpio_ssio(gpio)) {
++		data = ssio_gpio_to_bit(gpio);
++		if (value)
++			ltq_setbits(&ltq_ssio_regs->cpu0, data);
++		else
++			ltq_clrbits(&ltq_ssio_regs->cpu0, data);
++
++		return 0;
++	}
++
++	if (is_gpio_bank3(port)) {
++		gpio_od = &ltq_gpio3_regs->od;
++		gpio_altsel0 = &ltq_gpio3_regs->altsel0;
++		gpio_altsel1 = &ltq_gpio3_regs->altsel1;
++		gpio_dir = &ltq_gpio3_regs->dir;
++		gpio_out = &ltq_gpio3_regs->out;
++	}
++
++	/*
++	 * Reset open drain and altsel configs to workaround improper
++	 * reset values or unwanted modifications by BootROM
++	 */
++	ltq_setbits(gpio_od, data);
++	ltq_clrbits(gpio_altsel0, data);
++	ltq_clrbits(gpio_altsel1, data);
++
++	if (value)
++		ltq_setbits(gpio_out, data);
++	else
++		ltq_clrbits(gpio_out, data);
++
++	/* Switch to output */
++	ltq_setbits(gpio_dir, data);
++
++	return 0;
++}
++
++int gpio_get_value(unsigned gpio)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_in = &ltq_gpio_regs->ports[port].in;
++	u32 data = gpio_to_bit(gpio);
++	u32 val;
++
++	if (is_gpio_ssio(gpio)) {
++		gpio_in = &ltq_ssio_regs->cpu0;
++		data = ssio_gpio_to_bit(gpio);
++	}
++
++	if (is_gpio_bank3(port))
++		gpio_in = &ltq_gpio3_regs->in;
++
++	val = ltq_readl(gpio_in);
++
++	return !!(val & data);
++}
++
++int gpio_set_value(unsigned gpio, int value)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_out = &ltq_gpio_regs->ports[port].out;
++	u32 data = gpio_to_bit(gpio);
++
++	if (is_gpio_ssio(gpio)) {
++		gpio_out = &ltq_ssio_regs->cpu0;
++		data = ssio_gpio_to_bit(gpio);
++	}
++
++	if (is_gpio_bank3(port))
++		gpio_out = &ltq_gpio3_regs->out;
++
++	if (value)
++		ltq_setbits(gpio_out, data);
++	else
++		ltq_clrbits(gpio_out, data);
++
++	return 0;
++}
++
++int gpio_set_altfunc(unsigned gpio, int altsel0, int altsel1, int dir)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_od = &ltq_gpio_regs->ports[port].od;
++	const void *gpio_altsel0 = &ltq_gpio_regs->ports[port].altsel0;
++	const void *gpio_altsel1 = &ltq_gpio_regs->ports[port].altsel1;
++	const void *gpio_dir = &ltq_gpio_regs->ports[port].dir;
++
++	if (is_gpio_ssio(gpio))
++		return 0;
++
++	if (is_gpio_bank3(port)) {
++		gpio_od = &ltq_gpio3_regs->od;
++		gpio_altsel0 = &ltq_gpio3_regs->altsel0;
++		gpio_altsel1 = &ltq_gpio3_regs->altsel1;
++		gpio_dir = &ltq_gpio3_regs->dir;
++	}
++
++	if (altsel0)
++		ltq_setbits(gpio_altsel0, gpio_to_bit(gpio));
++	else
++		ltq_clrbits(gpio_altsel0, gpio_to_bit(gpio));
++
++	if (altsel1)
++		ltq_setbits(gpio_altsel1, gpio_to_bit(gpio));
++	else
++		ltq_clrbits(gpio_altsel1, gpio_to_bit(gpio));
++
++	if (dir) {
++		ltq_setbits(gpio_od, gpio_to_bit(gpio));
++		ltq_setbits(gpio_dir, gpio_to_bit(gpio));
++	} else {
++		ltq_clrbits(gpio_od, gpio_to_bit(gpio));
++		ltq_clrbits(gpio_dir, gpio_to_bit(gpio));
++	}
++
++	return 0;
++}
++
++int gpio_set_opendrain(unsigned gpio, int od)
++{
++	unsigned port = gpio_to_port(gpio);
++	const void *gpio_od = &ltq_gpio_regs->ports[port].od;
++
++	if (is_gpio_ssio(gpio))
++		return 0;
++
++	if (is_gpio_bank3(port))
++		gpio_od = &ltq_gpio3_regs->od;
++
++	if (od)
++		ltq_setbits(gpio_od, gpio_to_bit(gpio));
++	else
++		ltq_clrbits(gpio_od, gpio_to_bit(gpio));
++
++	return 0;
++}
+--- a/drivers/mtd/cfi_flash.c
++++ b/drivers/mtd/cfi_flash.c
+@@ -161,6 +161,18 @@ u64 flash_read64(void *addr)__attribute_
+ #define flash_read64	__flash_read64
+ #endif
+ 
++static inline void *__flash_swap_addr(unsigned long addr)
++{
++	return (void *) addr;
++}
++
++#ifdef CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
++void *flash_swap_addr(unsigned long addr)
++		__attribute__((weak, alias("__flash_swap_addr")));
++#else
++#define flash_swap_addr	__flash_swap_addr
++#endif
++
+ /*-----------------------------------------------------------------------
+  */
+ #if defined(CONFIG_ENV_IS_IN_FLASH) || defined(CONFIG_ENV_ADDR_REDUND) || (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
+@@ -196,7 +208,7 @@ flash_map (flash_info_t * info, flash_se
+ {
+ 	unsigned int byte_offset = offset * info->portwidth;
+ 
+-	return (void *)(info->start[sect] + byte_offset);
++	return flash_swap_addr(info->start[sect] + byte_offset);
+ }
+ 
+ static inline void flash_unmap(flash_info_t *info, flash_sect_t sect,
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -53,6 +53,7 @@ COBJS-$(CONFIG_NAND_JZ4740) += jz4740_na
+ COBJS-$(CONFIG_NAND_KB9202) += kb9202_nand.o
+ COBJS-$(CONFIG_NAND_KIRKWOOD) += kirkwood_nand.o
+ COBJS-$(CONFIG_NAND_KMETER1) += kmeter1_nand.o
++COBJS-$(CONFIG_NAND_LANTIQ) += lantiq_nand.o
+ COBJS-$(CONFIG_NAND_MPC5121_NFC) += mpc5121_nfc.o
+ COBJS-$(CONFIG_NAND_MXC) += mxc_nand.o
+ COBJS-$(CONFIG_NAND_MXS) += mxs_nand.o
+--- /dev/null
++++ b/drivers/mtd/nand/lantiq_nand.c
+@@ -0,0 +1,126 @@
++/*
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <linux/mtd/nand.h>
++#include <linux/compiler.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/nand.h>
++#include <asm/lantiq/io.h>
++
++#define NAND_CON_ECC_ON		(1 << 31)
++#define NAND_CON_LATCH_PRE	(1 << 23)
++#define NAND_CON_LATCH_WP	(1 << 22)
++#define NAND_CON_LATCH_SE	(1 << 21)
++#define NAND_CON_LATCH_CS	(1 << 20)
++#define NAND_CON_LATCH_CLE	(1 << 19)
++#define NAND_CON_LATCH_ALE	(1 << 18)
++#define NAND_CON_OUT_CS1	(1 << 10)
++#define NAND_CON_IN_CS1		(1 << 8)
++#define NAND_CON_PRE_P		(1 << 7)
++#define NAND_CON_WP_P		(1 << 6)
++#define NAND_CON_SE_P		(1 << 5)
++#define NAND_CON_CS_P		(1 << 4)
++#define NAND_CON_CLE_P		(1 << 3)
++#define NAND_CON_ALE_P		(1 << 2)
++#define NAND_CON_CSMUX		(1 << 1)
++#define NAND_CON_NANDM		(1 << 0)
++
++#define NAND_WAIT_WR_C		(1 << 3)
++#define NAND_WAIT_RDBY		(1 << 0)
++
++#define NAND_CMD_ALE		(1 << 2)
++#define NAND_CMD_CLE		(1 << 3)
++#define NAND_CMD_CS		(1 << 4)
++#define NAND_CMD_SE		(1 << 5)
++#define NAND_CMD_WP		(1 << 6)
++#define NAND_CMD_PRE		(1 << 7)
++
++struct ltq_nand_regs {
++	__be32	con;		/* NAND controller control */
++	__be32	wait;		/* NAND Flash Device RD/BY State */
++	__be32	ecc0;		/* NAND Flash ECC Register 0 */
++	__be32	ecc_ac;		/* NAND Flash ECC Register address counter */
++	__be32	ecc_cr;		/* NAND Flash ECC Comparison */
++};
++
++static struct ltq_nand_regs *ltq_nand_regs =
++	(struct ltq_nand_regs *) CKSEG1ADDR(LTQ_EBU_NAND_BASE);
++
++static void ltq_nand_wait_ready(void)
++{
++	while ((ltq_readl(&ltq_nand_regs->wait) & NAND_WAIT_WR_C) == 0)
++		;
++}
++
++static int ltq_nand_dev_ready(struct mtd_info *mtd)
++{
++	u32 data = ltq_readl(&ltq_nand_regs->wait);
++	return data & NAND_WAIT_RDBY;
++}
++
++static void ltq_nand_select_chip(struct mtd_info *mtd, int chip)
++{
++	if (chip == 0) {
++		ltq_setbits(&ltq_nand_regs->con, NAND_CON_NANDM);
++		ltq_setbits(&ltq_nand_regs->con, NAND_CON_LATCH_CS);
++	} else {
++		ltq_clrbits(&ltq_nand_regs->con, NAND_CON_LATCH_CS);
++		ltq_clrbits(&ltq_nand_regs->con, NAND_CON_NANDM);
++	}
++}
++
++static void ltq_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl)
++{
++	struct nand_chip *chip = mtd->priv;
++	unsigned long addr = (unsigned long) chip->IO_ADDR_W;
++
++	if (ctrl & NAND_CTRL_CHANGE) {
++		if (ctrl & NAND_ALE)
++			addr |= NAND_CMD_ALE;
++		else
++			addr &= ~NAND_CMD_ALE;
++
++		if (ctrl & NAND_CLE)
++			addr |= NAND_CMD_CLE;
++		else
++			addr &= ~NAND_CMD_CLE;
++
++		chip->IO_ADDR_W = (void __iomem *) addr;
++	}
++
++	if (cmd != NAND_CMD_NONE) {
++		writeb(cmd, chip->IO_ADDR_W);
++		ltq_nand_wait_ready();
++	}
++}
++
++int ltq_nand_init(struct nand_chip *nand)
++{
++	/* Enable NAND, set NAND CS to EBU CS1, enable EBU CS mux */
++	ltq_writel(&ltq_nand_regs->con, NAND_CON_OUT_CS1 | NAND_CON_IN_CS1 |
++		NAND_CON_PRE_P | NAND_CON_WP_P | NAND_CON_SE_P |
++		NAND_CON_CS_P | NAND_CON_CSMUX);
++
++	nand->dev_ready = ltq_nand_dev_ready;
++	nand->select_chip = ltq_nand_select_chip;
++	nand->cmd_ctrl = ltq_nand_cmd_ctrl;
++
++	nand->chip_delay = 30;
++	nand->options = 0;
++	nand->ecc.mode = NAND_ECC_SOFT;
++
++	/* Enable CS bit in address offset */
++	nand->IO_ADDR_R = nand->IO_ADDR_R + NAND_CMD_CS;
++	nand->IO_ADDR_W = nand->IO_ADDR_W + NAND_CMD_CS;
++
++	return 0;
++}
++
++__weak int board_nand_init(struct nand_chip *chip)
++{
++	return ltq_nand_init(chip);
++}
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -37,6 +37,8 @@ COBJS-$(CONFIG_INCA_IP_SWITCH) += inca-i
+ COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks8695eth.o
+ COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
+ COBJS-$(CONFIG_LAN91C96) += lan91c96.o
++COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
++COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
+ COBJS-$(CONFIG_MACB) += macb.o
+ COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+ COBJS-$(CONFIG_MPC5xxx_FEC) += mpc5xxx_fec.o
+--- /dev/null
++++ b/drivers/net/lantiq_danube_etop.c
+@@ -0,0 +1,410 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <malloc.h>
++#include <netdev.h>
++#include <miiphy.h>
++#include <switch.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/pm.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/dma.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_PPE_ETOP_MDIO_ACC_RA	(1 << 31)
++#define LTQ_PPE_ETOP_MDIO_CFG_UMM1	(1 << 2)
++#define LTQ_PPE_ETOP_MDIO_CFG_UMM0	(1 << 1)
++
++#define LTQ_PPE_ETOP_CFG_TCKINV1	(1 << 11)
++#define LTQ_PPE_ETOP_CFG_TCKINV0	(1 << 10)
++#define LTQ_PPE_ETOP_CFG_FEN1		(1 << 9)
++#define LTQ_PPE_ETOP_CFG_FEN0		(1 << 8)
++#define LTQ_PPE_ETOP_CFG_SEN1		(1 << 7)
++#define LTQ_PPE_ETOP_CFG_SEN0		(1 << 6)
++#define LTQ_PPE_ETOP_CFG_TURBO1		(1 << 5)
++#define LTQ_PPE_ETOP_CFG_REMII1		(1 << 4)
++#define LTQ_PPE_ETOP_CFG_OFF1		(1 << 3)
++#define LTQ_PPE_ETOP_CFG_TURBO0		(1 << 2)
++#define LTQ_PPE_ETOP_CFG_REMII0		(1 << 1)
++#define LTQ_PPE_ETOP_CFG_OFF0		(1 << 0)
++
++#define LTQ_PPE_ENET0_MAC_CFG_CGEN	(1 << 11)
++#define LTQ_PPE_ENET0_MAC_CFG_DUPLEX	(1 << 2)
++#define LTQ_PPE_ENET0_MAC_CFG_SPEED	(1 << 1)
++#define LTQ_PPE_ENET0_MAC_CFG_LINK	(1 << 0)
++
++#define LTQ_PPE_ENETS0_CFG_FTUC		(1 << 28)
++
++#define LTQ_ETH_RX_BUFFER_CNT		PKTBUFSRX
++#define LTQ_ETH_TX_BUFFER_CNT		8
++#define LTQ_ETH_RX_DATA_SIZE		PKTSIZE_ALIGN
++#define LTQ_ETH_IP_ALIGN		2
++
++#define LTQ_MDIO_DRV_NAME		"ltq-mdio"
++#define LTQ_ETH_DRV_NAME		"ltq-eth"
++
++struct ltq_ppe_etop_regs {
++	u32	mdio_cfg;		/* MDIO configuration */
++	u32	mdio_acc;		/* MDIO access */
++	u32	cfg;			/* ETOP configuration */
++	u32	ig_vlan_cos;		/* IG VLAN priority CoS mapping */
++	u32	ig_dscp_cos3;		/* IG DSCP CoS mapping 3 */
++	u32	ig_dscp_cos2;		/* IG DSCP CoS mapping 2 */
++	u32	ig_dscp_cos1;		/* IG DSCP CoS mapping 1 */
++	u32	ig_dscp_cos0;		/* IG DSCP CoS mapping 0 */
++	u32	ig_plen_ctrl;		/* IG frame length control */
++	u32	rsvd0[3];
++	u32	vpid;			/* VLAN protocol ID */
++};
++
++struct ltq_ppe_enet_regs {
++	u32	mac_cfg;		/* MAC configuration */
++	u32	rsvd0[3];
++	u32	ig_cfg;			/* Ingress configuration */
++	u32	ig_pgcnt;		/* Ingress buffer used page count */
++	u32	rsvd1;
++	u32	ig_buf_ctrl;		/* Ingress buffer backpressure ctrl */
++	u32	cos_cfg;		/* Classification configuration */
++	u32	ig_drop;		/* Total ingress drop frames */
++	u32	ig_err;			/* Total ingress error frames */
++	u32	mac_da0;		/* Ingress MAC address 0 */
++	u32	mac_da1;		/* Ingress MAC address 1 */
++	u32	rsvd2[22];
++	u32	pgcnt;			/* Page counter */
++	u32	rsvd3;
++	u32	hf_ctrl;		/* Half duplex control */
++	u32	tx_ctrl;		/* Transmit control */
++	u32	rsvd4;
++	u32	vlcos0;			/* VLAN insertion config CoS 0 */
++	u32	vlcos1;			/* VLAN insertion config CoS 1 */
++	u32	vlcos2;			/* VLAN insertion config CoS 2 */
++	u32	vlcos3;			/* VLAN insertion config CoS 3 */
++	u32	eg_col;			/* Total egress collision frames */
++	u32	eg_drop;		/* Total egress drop frames */
++};
++
++struct ltq_eth_priv {
++	struct ltq_dma_device dma_dev;
++	struct mii_dev *bus;
++	struct eth_device *dev;
++	int rx_num;
++	int tx_num;
++};
++
++struct ltq_mdio_access {
++	union {
++		struct {
++			unsigned ra:1;
++			unsigned rw:1;
++			unsigned rsvd:4;
++			unsigned phya:5;
++			unsigned rega:5;
++			unsigned phyd:16;
++		} reg;
++		u32 val;
++	};
++};
++
++static struct ltq_ppe_etop_regs *ltq_ppe_etop_regs =
++	(struct ltq_ppe_etop_regs *) CKSEG1ADDR(LTQ_PPE_ETOP_BASE);
++
++static struct ltq_ppe_enet_regs *ltq_ppe_enet0_regs =
++	(struct ltq_ppe_enet_regs *) CKSEG1ADDR(LTQ_PPE_ENET0_BASE);
++
++static inline int ltq_mdio_poll(void)
++{
++	struct ltq_mdio_access acc;
++	unsigned cnt = 10000;
++
++	while (likely(cnt--)) {
++		acc.val = ltq_readl(&ltq_ppe_etop_regs->mdio_acc);
++		if (!acc.reg.ra)
++			return 0;
++	}
++
++	return 1;
++}
++
++static int ltq_mdio_read(struct mii_dev *bus, int addr, int dev_addr,
++				int regnum)
++{
++	struct ltq_mdio_access acc;
++	int ret;
++
++	acc.val = 0;
++	acc.reg.ra = 1;
++	acc.reg.rw = 1;
++	acc.reg.phya = addr;
++	acc.reg.rega = regnum;
++
++	ret = ltq_mdio_poll();
++	if (ret)
++		return ret;
++
++	ltq_writel(&ltq_ppe_etop_regs->mdio_acc, acc.val);
++
++	ret = ltq_mdio_poll();
++	if (ret)
++		return ret;
++
++	acc.val = ltq_readl(&ltq_ppe_etop_regs->mdio_acc);
++
++	return acc.reg.phyd;
++}
++
++static int ltq_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
++				int regnum, u16 val)
++{
++	struct ltq_mdio_access acc;
++	int ret;
++
++	acc.val = 0;
++	acc.reg.ra = 1;
++	acc.reg.rw = 0;
++	acc.reg.phya = addr;
++	acc.reg.rega = regnum;
++	acc.reg.phyd = val;
++
++	ret = ltq_mdio_poll();
++	if (ret)
++		return ret;
++
++	ltq_writel(&ltq_ppe_etop_regs->mdio_acc, acc.val);
++
++	return 0;
++}
++
++static inline void ltq_eth_write_hwaddr(const struct eth_device *dev)
++{
++	u32 da0, da1;
++
++	da0 = (dev->enetaddr[0] << 24) + (dev->enetaddr[1] << 16) +
++		(dev->enetaddr[2] << 8) + dev->enetaddr[3];
++	da1 = (dev->enetaddr[4] << 24) + (dev->enetaddr[5] << 16);
++
++	ltq_writel(&ltq_ppe_enet0_regs->mac_da0, da0);
++	ltq_writel(&ltq_ppe_enet0_regs->mac_da1, da1);
++}
++
++static inline u8 *ltq_eth_rx_packet_align(int rx_num)
++{
++	u8 *packet = (u8 *) NetRxPackets[rx_num];
++
++	/*
++	 * IP header needs
++	 */
++	return packet + LTQ_ETH_IP_ALIGN;
++}
++
++static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	int i;
++
++	ltq_eth_write_hwaddr(dev);
++
++	for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
++		ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
++			LTQ_ETH_RX_DATA_SIZE);
++
++	ltq_dma_enable(dma_dev);
++
++	priv->rx_num = 0;
++	priv->tx_num = 0;
++
++	return 0;
++}
++
++static void ltq_eth_halt(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++
++	ltq_dma_reset(dma_dev);
++}
++
++static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	int err;
++
++	/* Minimum payload length w/ CRC is 60 bytes */
++	if (length < 60)
++		length = 60;
++
++	err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
++	if (err) {
++		puts("NET: timeout on waiting for TX descriptor\n");
++		return -1;
++	}
++
++	priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
++
++	return err;
++}
++
++static int ltq_eth_recv(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	u8 *packet;
++	int len;
++
++	if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
++		return 0;
++
++#if 0
++	printf("%s: rx_num %d\n", __func__, priv->rx_num);
++#endif
++
++	len = ltq_dma_rx_length(dma_dev, priv->rx_num);
++	packet = ltq_eth_rx_packet_align(priv->rx_num);
++
++#if 0
++	printf("%s: received: packet %p, len %u, rx_num %d\n",
++		__func__, packet, len, priv->rx_num);
++#endif
++
++	if (len)
++		NetReceive(packet, len);
++
++	ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
++		LTQ_ETH_RX_DATA_SIZE);
++
++	priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
++
++	return 0;
++}
++
++static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
++{
++	u32 data;
++
++	/* Power up ethernet subsystems */
++	ltq_pm_enable(LTQ_PM_ETH);
++
++	/* Reset ethernet subsystems */
++	ltq_reset_once(LTQ_RESET_ETH, 1);
++
++	/* Disable MDIO auto-detection */
++	ltq_clrbits(&ltq_ppe_etop_regs->mdio_cfg, LTQ_PPE_ETOP_MDIO_CFG_UMM1 |
++			LTQ_PPE_ETOP_MDIO_CFG_UMM0);
++
++	/* Enable CRC generation, Full Duplex, 100Mbps, Link up */
++	ltq_writel(&ltq_ppe_enet0_regs->mac_cfg, LTQ_PPE_ENET0_MAC_CFG_CGEN |
++			LTQ_PPE_ENET0_MAC_CFG_DUPLEX |
++			LTQ_PPE_ENET0_MAC_CFG_SPEED |
++			LTQ_PPE_ENET0_MAC_CFG_LINK);
++
++	/* Reset ETOP cfg and disable all */
++	data = LTQ_PPE_ETOP_CFG_OFF0 | LTQ_PPE_ETOP_CFG_OFF1;
++
++	/* Enable ENET0, enable store and fetch */
++	data &= ~LTQ_PPE_ETOP_CFG_OFF0;
++	data |= LTQ_PPE_ETOP_CFG_SEN0 | LTQ_PPE_ETOP_CFG_FEN0;
++
++	if (port->phy_if == PHY_INTERFACE_MODE_RMII)
++		data |= LTQ_PPE_ETOP_CFG_REMII0;
++	else
++		data &= ~LTQ_PPE_ETOP_CFG_REMII0;
++
++	ltq_writel(&ltq_ppe_etop_regs->cfg, data);
++
++	/* Set allowed packet length from 64 bytes to 1518 bytes */
++	ltq_writel(&ltq_ppe_etop_regs->ig_plen_ctrl, (64 << 16) | 1518);
++
++	/* Enable filter for unicast packets */
++	ltq_setbits(&ltq_ppe_enet0_regs->ig_cfg, LTQ_PPE_ENETS0_CFG_FTUC);
++}
++
++int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
++{
++	struct eth_device *dev;
++	struct mii_dev *bus;
++	struct ltq_eth_priv *priv;
++	struct ltq_dma_device *dma_dev;
++	const struct ltq_eth_port_config *port = &board_config->ports[0];
++	struct phy_device *phy;
++	struct switch_device *sw;
++	int ret;
++
++	ltq_dma_init();
++	ltq_eth_hw_init(port);
++
++	dev = calloc(1, sizeof(*dev));
++	if (!dev)
++		return -1;
++
++	priv = calloc(1, sizeof(*priv));
++	if (!priv)
++		return -1;
++
++	bus = mdio_alloc();
++	if (!bus)
++		return -1;
++
++	sprintf(dev->name, LTQ_ETH_DRV_NAME);
++	dev->priv = priv;
++	dev->init = ltq_eth_init;
++	dev->halt = ltq_eth_halt;
++	dev->recv = ltq_eth_recv;
++	dev->send = ltq_eth_send;
++
++	sprintf(bus->name, LTQ_MDIO_DRV_NAME);
++	bus->read = ltq_mdio_read;
++	bus->write = ltq_mdio_write;
++	bus->priv = priv;
++
++	dma_dev = &priv->dma_dev;
++	dma_dev->port = 0;
++	dma_dev->rx_chan.chan_no = 6;
++	dma_dev->rx_chan.class = 3;
++	dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
++	dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
++	dma_dev->tx_chan.chan_no = 7;
++	dma_dev->tx_chan.class = 3;
++	dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
++	dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
++
++	priv->bus = bus;
++	priv->dev = dev;
++
++	ret = ltq_dma_register(dma_dev);
++	if (ret)
++		return ret;
++
++	ret = mdio_register(bus);
++	if (ret)
++		return ret;
++
++	ret = eth_register(dev);
++	if (ret)
++		return ret;
++
++	if (port->flags & LTQ_ETH_PORT_SWITCH) {
++		sw = switch_connect(bus);
++		if (!sw)
++			return -1;
++
++		switch_setup(sw);
++	}
++
++	if (port->flags & LTQ_ETH_PORT_PHY) {
++		phy = phy_connect(bus, port->phy_addr, dev, port->phy_if);
++		if (!phy)
++			return -1;
++
++		phy_config(phy);
++	}
++
++	return 0;
++}
+--- /dev/null
++++ b/drivers/net/lantiq_vrx200_switch.c
+@@ -0,0 +1,675 @@
++/*
++ * Copyright (C) 2010-2011 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define DEBUG
++
++#include <common.h>
++#include <malloc.h>
++#include <netdev.h>
++#include <miiphy.h>
++#include <linux/compiler.h>
++#include <asm/gpio.h>
++#include <asm/processor.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/pm.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/dma.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/switch.h>
++
++#define LTQ_ETH_RX_BUFFER_CNT		PKTBUFSRX
++#define LTQ_ETH_TX_BUFFER_CNT		8
++#define LTQ_ETH_RX_DATA_SIZE		PKTSIZE_ALIGN
++#define LTQ_ETH_IP_ALIGN		2
++
++#define LTQ_MDIO_DRV_NAME		"ltq-mdio"
++#define LTQ_ETH_DRV_NAME		"ltq-eth"
++
++#define LTQ_ETHSW_MAX_GMAC		6
++#define LTQ_ETHSW_PMAC			6
++
++struct ltq_mdio_phy_addr_reg {
++	union {
++		struct {
++			unsigned rsvd:1;
++			unsigned lnkst:2;	/* Link status control */
++			unsigned speed:2;	/* Speed control */
++			unsigned fdup:2;	/* Full duplex control */
++			unsigned fcontx:2;	/* Flow control mode TX */
++			unsigned fconrx:2;	/* Flow control mode RX */
++			unsigned addr:5;	/* PHY address */
++		} bits;
++		u16 val;
++	};
++};
++
++enum ltq_mdio_phy_addr_lnkst {
++	LTQ_MDIO_PHY_ADDR_LNKST_AUTO = 0,
++	LTQ_MDIO_PHY_ADDR_LNKST_UP = 1,
++	LTQ_MDIO_PHY_ADDR_LNKST_DOWN = 2,
++};
++
++enum ltq_mdio_phy_addr_speed {
++	LTQ_MDIO_PHY_ADDR_SPEED_M10 = 0,
++	LTQ_MDIO_PHY_ADDR_SPEED_M100 = 1,
++	LTQ_MDIO_PHY_ADDR_SPEED_G1 = 2,
++	LTQ_MDIO_PHY_ADDR_SPEED_AUTO = 3,
++};
++
++enum ltq_mdio_phy_addr_fdup {
++	LTQ_MDIO_PHY_ADDR_FDUP_AUTO = 0,
++	LTQ_MDIO_PHY_ADDR_FDUP_ENABLE = 1,
++	LTQ_MDIO_PHY_ADDR_FDUP_DISABLE = 3,
++};
++
++enum ltq_mdio_phy_addr_fcon {
++	LTQ_MDIO_PHY_ADDR_FCON_AUTO = 0,
++	LTQ_MDIO_PHY_ADDR_FCON_ENABLE = 1,
++	LTQ_MDIO_PHY_ADDR_FCON_DISABLE = 3,
++};
++
++struct ltq_mii_mii_cfg_reg {
++	union {
++		struct {
++			unsigned res:1;		/* Hardware reset */
++			unsigned en:1;		/* xMII interface enable */
++			unsigned isol:1;	/* xMII interface isolate */
++			unsigned ldclkdis:1;	/* Link down clock disable */
++			unsigned rsvd:1;
++			unsigned crs:2;		/* CRS sensitivity config */
++			unsigned rgmii_ibs:1;	/* RGMII In Band status */
++			unsigned rmii:1;	/* RMII ref clock direction */
++			unsigned miirate:3;	/* xMII interface clock rate */
++			unsigned miimode:4;	/* xMII interface mode */
++		} bits;
++		u16 val;
++	};
++};
++
++enum ltq_mii_mii_cfg_miirate {
++	LTQ_MII_MII_CFG_MIIRATE_M2P5 = 0,
++	LTQ_MII_MII_CFG_MIIRATE_M25 = 1,
++	LTQ_MII_MII_CFG_MIIRATE_M125 = 2,
++	LTQ_MII_MII_CFG_MIIRATE_M50 = 3,
++	LTQ_MII_MII_CFG_MIIRATE_AUTO = 4,
++};
++
++enum ltq_mii_mii_cfg_miimode {
++	LTQ_MII_MII_CFG_MIIMODE_MIIP = 0,
++	LTQ_MII_MII_CFG_MIIMODE_MIIM = 1,
++	LTQ_MII_MII_CFG_MIIMODE_RMIIP = 2,
++	LTQ_MII_MII_CFG_MIIMODE_RMIIM = 3,
++	LTQ_MII_MII_CFG_MIIMODE_RGMII = 4,
++};
++
++struct ltq_eth_priv {
++	struct ltq_dma_device dma_dev;
++	struct mii_dev *bus;
++	struct eth_device *dev;
++	struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
++	int rx_num;
++	int tx_num;
++};
++
++static struct vr9_switch_regs *switch_regs =
++	(struct vr9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
++
++static inline void vr9_switch_sync(void)
++{
++	__asm__("sync");
++}
++
++static inline int vr9_switch_mdio_is_busy(void)
++{
++	u32 mdio_ctrl = ltq_readl(&switch_regs->mdio.mdio_ctrl);
++
++	return mdio_ctrl & MDIO_CTRL_MBUSY;
++}
++
++static inline void vr9_switch_mdio_poll(void)
++{
++	while (vr9_switch_mdio_is_busy())
++		cpu_relax();
++}
++
++static int vr9_switch_mdio_read(struct mii_dev *bus, int phyad, int devad,
++					int regad)
++{
++	u32 mdio_ctrl;
++	int retval;
++
++	mdio_ctrl = MDIO_CTRL_OP_READ |
++		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
++		(regad & MDIO_CTRL_REGAD_MASK);
++
++	vr9_switch_mdio_poll();
++	ltq_writel(&switch_regs->mdio.mdio_ctrl, mdio_ctrl);
++	vr9_switch_mdio_poll();
++	retval = ltq_readl(&switch_regs->mdio.mdio_read);
++
++	return retval;
++}
++
++static int vr9_switch_mdio_write(struct mii_dev *bus, int phyad, int devad,
++					int regad, u16 val)
++{
++	u32 mdio_ctrl;
++
++	mdio_ctrl = MDIO_CTRL_OP_WRITE |
++		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
++		(regad & MDIO_CTRL_REGAD_MASK);
++
++	vr9_switch_mdio_poll();
++	ltq_writel(&switch_regs->mdio.mdio_write, val);
++	ltq_writel(&switch_regs->mdio.mdio_ctrl, mdio_ctrl);
++
++	return 0;
++}
++
++static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
++{
++	struct ltq_mdio_phy_addr_reg phy_addr_reg;
++	struct ltq_mii_mii_cfg_reg mii_cfg_reg;
++
++	phy_addr_reg.val = ltq_readl(to_mdio_phyaddr(switch_regs, num));
++
++	switch (num) {
++	case 0:
++	case 1:
++	case 5:
++		mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs, num));
++		break;
++	default:
++		mii_cfg_reg.val = 0;
++		break;
++	}
++
++	phy_addr_reg.bits.addr = phydev->addr;
++
++	if (phydev->link)
++		phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_UP;
++	else
++		phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN;
++
++	switch (phydev->speed) {
++	case SPEED_1000:
++		phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_G1;
++		mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M125;
++		break;
++	case SPEED_100:
++		phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M100;
++		switch (mii_cfg_reg.bits.miimode) {
++		case LTQ_MII_MII_CFG_MIIMODE_RMIIM:
++		case LTQ_MII_MII_CFG_MIIMODE_RMIIP:
++			mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M50;
++			break;
++		default:
++			mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M25;
++			break;
++		}
++		break;
++	default:
++		phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10;
++		mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5;
++		break;
++	}
++
++	if (phydev->duplex == DUPLEX_FULL)
++		phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_ENABLE;
++	else
++		phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE;
++
++	ltq_writel(to_mdio_phyaddr(switch_regs, num), phy_addr_reg.val);
++
++	switch (num) {
++	case 0:
++	case 1:
++	case 5:
++		ltq_writel(to_mii_miicfg(switch_regs, num), mii_cfg_reg.val);
++		break;
++	default:
++		break;
++	}
++}
++
++static inline u8 *ltq_eth_rx_packet_align(int rx_num)
++{
++	u8 *packet = (u8 *) NetRxPackets[rx_num];
++
++	/*
++	 * IP header needs
++	 */
++	return packet + LTQ_ETH_IP_ALIGN;
++}
++
++static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	struct phy_device *phydev;
++	int i;
++
++	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
++		phydev = priv->phymap[i];
++		if (!phydev)
++			continue;
++
++		phy_startup(phydev);
++		ltq_eth_gmac_update(phydev, i);
++	}
++
++	for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
++		ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
++			LTQ_ETH_RX_DATA_SIZE);
++
++	ltq_dma_enable(dma_dev);
++
++	priv->rx_num = 0;
++	priv->tx_num = 0;
++
++	return 0;
++}
++
++static void ltq_eth_halt(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	struct phy_device *phydev;
++	int i;
++
++	ltq_dma_reset(dma_dev);
++
++	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
++		phydev = priv->phymap[i];
++		if (!phydev)
++			continue;
++
++		phy_shutdown(phydev);
++		phydev->link = 0;
++		ltq_eth_gmac_update(phydev, i);
++	}
++}
++
++static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++
++#if 0
++	printf("%s: packet %p, len %d\n", __func__, packet, length);
++#endif
++
++	ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
++	priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
++
++	return 0;
++}
++
++static int ltq_eth_recv(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	u8 *packet;
++	int len;
++
++	if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
++		return 0;
++
++#if 0
++	printf("%s: rx_num %d\n", __func__, priv->rx_num);
++#endif
++
++	len = ltq_dma_rx_length(dma_dev, priv->rx_num);
++	packet = ltq_eth_rx_packet_align(priv->rx_num);
++
++#if 0
++	printf("%s: received: packet %p, len %u, rx_num %d\n",
++		__func__, packet, len, priv->rx_num);
++#endif
++
++	if (len)
++		NetReceive(packet, len);
++
++	ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
++		LTQ_ETH_RX_DATA_SIZE);
++
++	priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
++
++	return 0;
++}
++
++static void ltq_eth_gmac_init(int num)
++{
++	struct ltq_mdio_phy_addr_reg phy_addr_reg;
++	struct ltq_mii_mii_cfg_reg mii_cfg_reg;
++
++	/* Reset PHY status to link down */
++	phy_addr_reg.val = ltq_readl(to_mdio_phyaddr(switch_regs, num));
++	phy_addr_reg.bits.addr = num;
++	phy_addr_reg.bits.lnkst = LTQ_MDIO_PHY_ADDR_LNKST_DOWN;
++	phy_addr_reg.bits.speed = LTQ_MDIO_PHY_ADDR_SPEED_M10;
++	phy_addr_reg.bits.fdup = LTQ_MDIO_PHY_ADDR_FDUP_DISABLE;
++	ltq_writel(to_mdio_phyaddr(switch_regs, num), phy_addr_reg.val);
++
++	/* Reset and disable MII interface */
++	switch (num) {
++	case 0:
++	case 1:
++	case 5:
++		mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs, num));
++		mii_cfg_reg.bits.en = 0;
++		mii_cfg_reg.bits.res = 1;
++		mii_cfg_reg.bits.miirate = LTQ_MII_MII_CFG_MIIRATE_M2P5;
++		ltq_writel(to_mii_miicfg(switch_regs, num), mii_cfg_reg.val);
++		break;
++	default:
++		break;
++	}
++
++	/*
++	 * - enable frame checksum generation
++	 * - enable padding of short frames
++	 * - disable flow control
++	 */
++	ltq_writel(to_mac_ctrl(switch_regs, num, 0),
++		MAC_CTRL0_PADEN | MAC_CTRL0_FCS | MAC_CTRL0_FCON_NONE);
++
++	vr9_switch_sync();
++}
++
++static void ltq_eth_pmac_init(void)
++{
++	/*
++	 * WAR: buffer congestion:
++	 * - shorten preambel to 1 byte
++	 * - set TX IPG to 7 bytes
++	 */
++#if 1
++	ltq_writel(to_mac_ctrl(switch_regs, LTQ_ETHSW_PMAC, 1),
++		MAC_CTRL1_SHORTPRE | 7);
++#endif
++
++	/*
++	 * WAR: systematical concept weakness ACM bug
++	 * - set maximum number of used buffer segments to 254
++	 * - soft-reset BM FSQM
++	 */
++#if 1
++	ltq_writel(&switch_regs->bm.core.fsqm_gctrl, 253);
++	ltq_setbits(&switch_regs->bm.core.gctrl, BM_GCTRL_F_SRES);
++	ltq_clrbits(&switch_regs->bm.core.gctrl, BM_GCTRL_F_SRES);
++#endif
++
++	/*
++	 * WAR: switch MAC drop bug
++	 */
++#if 1
++	ltq_writel(to_pce_tbl_key(switch_regs, 0), 0xf);
++	ltq_writel(to_pce_tbl_value(switch_regs, 0), 0x40);
++	ltq_writel(&switch_regs->pce.core.tbl_addr, 0x3);
++	ltq_writel(&switch_regs->pce.core.tbl_ctrl, 0x902f);
++#endif
++
++	/*
++	 * Configure frame header control:
++	 * - enable flow control
++	 * - enable CRC check for packets from DMA to PMAC
++	 * - remove special tag from packets from PMAC to DMA
++	 * - add CRC for packets from DMA to PMAC
++	 */
++	ltq_writel(&switch_regs->pmac.hd_ctl, /*PMAC_HD_CTL_FC |*/
++		PMAC_HD_CTL_CCRC | PMAC_HD_CTL_RST | PMAC_HD_CTL_AC |
++		PMAC_HD_CTL_RC);
++
++#if 1
++	ltq_writel(&switch_regs->pmac.rx_ipg, 0x8b);
++#endif
++
++	/*
++	 * - enable frame checksum generation
++	 * - enable padding of short frames
++	 * - disable flow control
++	 */
++	ltq_writel(to_mac_ctrl(switch_regs, LTQ_ETHSW_PMAC, 0),
++		MAC_CTRL0_PADEN | MAC_CTRL0_FCS | MAC_CTRL0_FCON_NONE);
++
++	vr9_switch_sync();
++}
++
++static void ltq_eth_hw_init(void)
++{
++	int i;
++
++	/* Power up ethernet and switch subsystems */
++	ltq_pm_enable(LTQ_PM_ETH);
++
++	/* Reset ethernet and switch subsystems */
++#if 0
++	ltq_reset_once(LTQ_RESET_ETH, 10);
++#endif
++
++	/* Enable switch macro */
++	ltq_setbits(&switch_regs->mdio.glob_ctrl, MDIO_GLOB_CTRL_SE);
++
++	/* Disable MDIO auto-polling for all ports */
++	ltq_writel(&switch_regs->mdio.mdc_cfg_0, 0);
++
++	/*
++	 * Enable and set MDIO management clock to 2.5 MHz. This is the
++	 * maximum clock for FE PHYs.
++	 * Formula for clock is:
++	 *
++	 *      50 MHz
++	 * x = ----------- - 1
++	 *      2 * f_MDC
++	 */
++	ltq_writel(&switch_regs->mdio.mdc_cfg_1, MDIO_MDC_CFG1_RES |
++		MDIO_MDC_CFG1_MCEN | 5);
++
++	vr9_switch_sync();
++
++	/* Init MAC connected to CPU  */
++	ltq_eth_pmac_init();
++
++	/* Init MACs connected to external MII interfaces */
++	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++)
++		ltq_eth_gmac_init(i);
++}
++
++static void ltq_eth_port_config(struct ltq_eth_priv *priv,
++					const struct ltq_eth_port_config *port)
++{
++	struct ltq_mii_mii_cfg_reg mii_cfg_reg;
++	struct phy_device *phydev;
++	int setup_gpio = 0;
++
++	switch (port->num) {
++	case 0:	/* xMII0 */
++	case 1:	/* xMII1 */
++		mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs,
++					port->num));
++		mii_cfg_reg.bits.en = port->flags ? 1 : 0;
++
++		switch (port->phy_if) {
++		case PHY_INTERFACE_MODE_MII:
++			if (port->flags & LTQ_ETH_PORT_PHY)
++				/* MII MAC mode, connected to external PHY */
++				mii_cfg_reg.bits.miimode =
++					LTQ_MII_MII_CFG_MIIMODE_MIIM;
++			else
++				/* MII PHY mode, connected to external MAC */
++				mii_cfg_reg.bits.miimode =
++					LTQ_MII_MII_CFG_MIIMODE_MIIP;
++			setup_gpio = 1;
++			break;
++		case PHY_INTERFACE_MODE_RMII:
++			if (port->flags & LTQ_ETH_PORT_PHY)
++				/* RMII MAC mode, connected to external PHY */
++				mii_cfg_reg.bits.miimode =
++					LTQ_MII_MII_CFG_MIIMODE_RMIIM;
++			else
++				/* RMII PHY mode, connected to external MAC */
++				mii_cfg_reg.bits.miimode =
++					LTQ_MII_MII_CFG_MIIMODE_RMIIP;
++			setup_gpio = 1;
++			break;
++		case PHY_INTERFACE_MODE_RGMII:
++			/* RGMII MAC mode, connected to external PHY */
++			mii_cfg_reg.bits.miimode =
++				LTQ_MII_MII_CFG_MIIMODE_RGMII;
++			setup_gpio = 1;
++
++			/* RGMII clock delays */
++			ltq_writel(to_mii_pcdu(switch_regs, port->num),
++				port->rgmii_rx_delay << PCDU_RXDLY_SHIFT |
++				port->rgmii_tx_delay);
++			break;
++		default:
++			break;
++		}
++
++		ltq_writel(to_mii_miicfg(switch_regs, port->num),
++			mii_cfg_reg.val);
++		break;
++	case 2:	/* internal GPHY0 */
++	case 3:	/* internal GPHY0 */
++	case 4:	/* internal GPHY1 */
++		switch (port->phy_if) {
++		case PHY_INTERFACE_MODE_MII:
++		case PHY_INTERFACE_MODE_GMII:
++			setup_gpio = 1;
++			break;
++		default:
++			break;
++		}
++		break;
++	case 5:	/* internal GPHY1 or xMII2 */
++		mii_cfg_reg.val = ltq_readl(to_mii_miicfg(switch_regs,
++					port->num));
++		mii_cfg_reg.bits.en = port->flags ? 1 : 0;
++
++		switch (port->phy_if) {
++		case PHY_INTERFACE_MODE_MII:
++			/* MII MAC mode, connected to internal GPHY */
++			mii_cfg_reg.bits.miimode =
++				LTQ_MII_MII_CFG_MIIMODE_MIIM;
++			setup_gpio = 1;
++			break;
++		case PHY_INTERFACE_MODE_RGMII:
++			/* RGMII MAC mode, connected to external PHY */
++			mii_cfg_reg.bits.miimode =
++				LTQ_MII_MII_CFG_MIIMODE_RGMII;
++			setup_gpio = 1;
++
++			/* RGMII clock delays */
++			ltq_writel(to_mii_pcdu(switch_regs, port->num),
++				port->rgmii_rx_delay << PCDU_RXDLY_SHIFT |
++				port->rgmii_tx_delay);
++			break;
++		default:
++			break;
++		}
++
++		ltq_writel(to_mii_miicfg(switch_regs, port->num),
++			mii_cfg_reg.val);
++		break;
++	default:
++		break;
++	}
++
++	/* Setup GPIOs for MII with external PHYs/MACs */
++	if (setup_gpio) {
++		/* MII/MDIO */
++		gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR,
++					GPIO_DIR_OUT);
++		/* MII/MDC */
++		gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR,
++					GPIO_DIR_OUT);
++	}
++
++	/* Connect to internal/external PHYs */
++	if (port->flags & LTQ_ETH_PORT_PHY) {
++		phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
++					port->phy_if);
++		if (phydev)
++			phy_config(phydev);
++
++		priv->phymap[port->num] = phydev;
++	}
++}
++
++int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
++{
++	struct eth_device *dev;
++	struct mii_dev *bus;
++	struct ltq_eth_priv *priv;
++	struct ltq_dma_device *dma_dev;
++	int i, ret;
++
++	build_check_vr9_registers();
++
++	ltq_dma_init();
++	ltq_eth_hw_init();
++
++	dev = calloc(1, sizeof(struct eth_device));
++	if (!dev)
++		return -1;
++
++	priv = calloc(1, sizeof(struct ltq_eth_priv));
++	if (!priv)
++		return -1;
++
++	bus = mdio_alloc();
++	if (!bus)
++		return -1;
++
++	sprintf(dev->name, LTQ_ETH_DRV_NAME);
++	dev->priv = priv;
++	dev->init = ltq_eth_init;
++	dev->halt = ltq_eth_halt;
++	dev->recv = ltq_eth_recv;
++	dev->send = ltq_eth_send;
++
++	sprintf(bus->name, LTQ_MDIO_DRV_NAME);
++	bus->read = vr9_switch_mdio_read;
++	bus->write = vr9_switch_mdio_write;
++	bus->priv = priv;
++
++	dma_dev = &priv->dma_dev;
++	dma_dev->port = 0;
++	dma_dev->rx_chan.chan_no = 0;
++	dma_dev->rx_chan.class = 0;
++	dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
++	dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
++	dma_dev->tx_chan.chan_no = 1;
++	dma_dev->tx_chan.class = 0;
++	dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
++	dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
++
++	priv->bus = bus;
++	priv->dev = dev;
++
++	ret = ltq_dma_register(dma_dev);
++	if (ret)
++		return -1;
++
++	ret = mdio_register(bus);
++	if (ret)
++		return -1;
++
++	ret = eth_register(dev);
++	if (ret)
++		return -1;
++
++	for (i = 0; i < board_config->num_ports; i++)
++		ltq_eth_port_config(priv, &board_config->ports[i]);
++
++	return 0;
++}
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -20,6 +20,7 @@ COBJS-$(CONFIG_PHY_BROADCOM) += broadcom
+ COBJS-$(CONFIG_PHY_DAVICOM) += davicom.o
+ COBJS-$(CONFIG_PHY_ET1011C) += et1011c.o
+ COBJS-$(CONFIG_PHY_ICPLUS) += icplus.o
++COBJS-$(CONFIG_PHY_LANTIQ) += lantiq.o
+ COBJS-$(CONFIG_PHY_LXT) += lxt.o
+ COBJS-$(CONFIG_PHY_MARVELL) += marvell.o
+ COBJS-$(CONFIG_PHY_MICREL) += micrel.o
+--- /dev/null
++++ b/drivers/net/phy/lantiq.c
+@@ -0,0 +1,238 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define DEBUG
++
++#include <common.h>
++#include <miiphy.h>
++
++#define ADVERTIZE_MPD		(1 << 10)
++
++DECLARE_GLOBAL_DATA_PTR;
++
++/*
++ * Update link status.
++ *
++ * Based on genphy_update_link in phylib.c
++ */
++static int ltq_phy_update_link(struct phy_device *phydev)
++{
++	unsigned int mii_reg;
++
++	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
++
++	/*
++	 * If we already saw the link up, and it hasn't gone down, then
++	 * we don't need to wait for autoneg again
++	 */
++	if (phydev->link && mii_reg & BMSR_LSTATUS)
++		return 0;
++
++	if ((mii_reg & BMSR_ANEGCAPABLE) && !(mii_reg & BMSR_ANEGCOMPLETE)) {
++		phydev->link = 0;
++		return 0;
++	} else {
++		/* Read the link a second time to clear the latched state */
++		mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
++
++		if (mii_reg & BMSR_LSTATUS)
++			phydev->link = 1;
++		else
++			phydev->link = 0;
++	}
++
++	return 0;
++}
++
++/*
++ * Update speed and duplex.
++ *
++ * Based on genphy_parse_link in phylib.c
++ */
++static int ltq_phy_parse_link(struct phy_device *phydev)
++{
++	unsigned int mii_reg;
++
++	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);
++
++	/* We're using autonegotiation */
++	if (mii_reg & BMSR_ANEGCAPABLE) {
++		u32 lpa = 0;
++		u32 gblpa = 0;
++
++		/* Check for gigabit capability */
++		if (mii_reg & BMSR_ERCAP) {
++			/* We want a list of states supported by
++			 * both PHYs in the link
++			 */
++			gblpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_STAT1000);
++			gblpa &= phy_read(phydev,
++					MDIO_DEVAD_NONE, MII_CTRL1000) << 2;
++		}
++
++		/* Set the baseline so we only have to set them
++		 * if they're different
++		 */
++		phydev->speed = SPEED_10;
++		phydev->duplex = DUPLEX_HALF;
++
++		/* Check the gigabit fields */
++		if (gblpa & (PHY_1000BTSR_1000FD | PHY_1000BTSR_1000HD)) {
++			phydev->speed = SPEED_1000;
++
++			if (gblpa & PHY_1000BTSR_1000FD)
++				phydev->duplex = DUPLEX_FULL;
++
++			/* We're done! */
++			return 0;
++		}
++
++		lpa = phy_read(phydev, MDIO_DEVAD_NONE, MII_ADVERTISE);
++		lpa &= phy_read(phydev, MDIO_DEVAD_NONE, MII_LPA);
++
++		if (lpa & (LPA_100FULL | LPA_100HALF)) {
++			phydev->speed = SPEED_100;
++
++			if (lpa & LPA_100FULL)
++				phydev->duplex = DUPLEX_FULL;
++
++		} else if (lpa & LPA_10FULL)
++			phydev->duplex = DUPLEX_FULL;
++	} else {
++		u32 bmcr = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
++
++		phydev->speed = SPEED_10;
++		phydev->duplex = DUPLEX_HALF;
++
++		if (bmcr & BMCR_FULLDPLX)
++			phydev->duplex = DUPLEX_FULL;
++
++		if (bmcr & BMCR_SPEED1000)
++			phydev->speed = SPEED_1000;
++		else if (bmcr & BMCR_SPEED100)
++			phydev->speed = SPEED_100;
++	}
++
++	return 0;
++}
++
++static int ltq_phy_config(struct phy_device *phydev)
++{
++	u16 val;
++
++	/* Advertise as Multi-port device */
++	val = phy_read(phydev, MDIO_DEVAD_NONE, MII_CTRL1000);
++	val |= ADVERTIZE_MPD;
++	phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, val);
++
++	genphy_config_aneg(phydev);
++
++	return 0;
++}
++
++static int ltq_phy_startup(struct phy_device *phydev)
++{
++	/*
++	 * Update PHY status immediately without any delays as genphy_startup
++	 * does because VRX200 switch needs to be configured dependent
++	 * on this information.
++	 */
++	ltq_phy_update_link(phydev);
++	ltq_phy_parse_link(phydev);
++
++	debug("ltq_phy: addr %d, link %d, speed %d, duplex %d\n",
++		phydev->addr, phydev->link, phydev->speed, phydev->duplex);
++
++	return 0;
++}
++
++static struct phy_driver xrx_11g_13_driver = {
++	.name = "Lantiq XWAY XRX PHY11G v1.3 and earlier",
++	.uid = 0x030260D0,
++	.mask = 0xFFFFFFF0,
++	.features = PHY_GBIT_FEATURES,
++	.config = ltq_phy_config,
++	.startup = ltq_phy_startup,
++	.shutdown = genphy_shutdown,
++};
++
++static struct phy_driver xrx_11g_14_driver = {
++	.name = "Lantiq XWAY XRX PHY11G v1.4 and later",
++	.uid = 0xd565a408,
++	.mask = 0xFFFFFFF8,
++	.features = PHY_GBIT_FEATURES,
++	.config = ltq_phy_config,
++	.startup = ltq_phy_startup,
++	.shutdown = genphy_shutdown,
++};
++
++static struct phy_driver xrx_22f_14_driver = {
++	.name = "Lantiq XWAY XRX PHY22F v1.4 and later",
++	.uid = 0xd565a418,
++	.mask = 0xFFFFFFF8,
++	.features = PHY_BASIC_FEATURES,
++	.config = ltq_phy_config,
++	.startup = ltq_phy_startup,
++	.shutdown = genphy_shutdown,
++};
++
++static struct phy_driver pef7071_driver = {
++	.name = "Lantiq XWAY PEF7071",
++	.uid = 0xd565a400,
++	.mask = 0xFFFFFFF8,
++	.features = PHY_GBIT_FEATURES,
++	.config = ltq_phy_config,
++	.startup = ltq_phy_startup,
++	.shutdown = genphy_shutdown,
++};
++
++static struct phy_driver xrx_genphy_driver = {
++	.name = "Generic PHY at Lantiq XWAY XRX switch",
++	.uid = 0,
++	.mask = 0,
++	.features = 0,
++	.config = genphy_config,
++	.startup = ltq_phy_startup,
++	.shutdown = genphy_shutdown,
++};
++
++int phy_lantiq_init(void)
++{
++#ifdef CONFIG_NEEDS_MANUAL_RELOC
++	xrx_11g_13_driver.config = ltq_phy_config;
++	xrx_11g_13_driver.startup = ltq_phy_startup;
++	xrx_11g_13_driver.shutdown = genphy_shutdown;
++	xrx_11g_13_driver.name += gd->reloc_off;
++
++	xrx_11g_14_driver.config = ltq_phy_config;
++	xrx_11g_14_driver.startup = ltq_phy_startup;
++	xrx_11g_14_driver.shutdown = genphy_shutdown;
++	xrx_11g_14_driver.name += gd->reloc_off;
++
++	xrx_22f_14_driver.config = ltq_phy_config;
++	xrx_22f_14_driver.startup = ltq_phy_startup;
++	xrx_22f_14_driver.shutdown = genphy_shutdown;
++	xrx_22f_14_driver.name += gd->reloc_off;
++
++	pef7071_driver.config = ltq_phy_config;
++	pef7071_driver.startup = ltq_phy_startup;
++	pef7071_driver.shutdown = genphy_shutdown;
++	pef7071_driver.name += gd->reloc_off;
++
++	xrx_genphy_driver.config = genphy_config;
++	xrx_genphy_driver.startup = ltq_phy_startup;
++	xrx_genphy_driver.shutdown = genphy_shutdown;
++	xrx_genphy_driver.name += gd->reloc_off;
++#endif
++
++	phy_register(&xrx_11g_13_driver);
++	phy_register(&xrx_11g_14_driver);
++	phy_register(&xrx_22f_14_driver);
++	phy_register(&pef7071_driver);
++	phy_register(&xrx_genphy_driver);
++
++	return 0;
++}
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -16,9 +16,10 @@
+ #include <command.h>
+ #include <miiphy.h>
+ #include <phy.h>
+-#include <errno.h>
+ #include <linux/err.h>
+ 
++DECLARE_GLOBAL_DATA_PTR;
++
+ /* Generic PHY support and helper functions */
+ 
+ /**
+@@ -440,6 +441,16 @@ static LIST_HEAD(phy_drivers);
+ 
+ int phy_init(void)
+ {
++#ifdef CONFIG_NEEDS_MANUAL_RELOC
++	INIT_LIST_HEAD(&phy_drivers);
++
++	genphy_driver.config = genphy_config;
++	genphy_driver.startup = genphy_startup;
++	genphy_driver.shutdown = genphy_shutdown;
++
++	genphy_driver.name += gd->reloc_off;
++#endif
++
+ #ifdef CONFIG_PHY_ATHEROS
+ 	phy_atheros_init();
+ #endif
+@@ -455,6 +466,9 @@ int phy_init(void)
+ #ifdef CONFIG_PHY_ICPLUS
+ 	phy_icplus_init();
+ #endif
++#ifdef CONFIG_PHY_LANTIQ
++	phy_lantiq_init();
++#endif
+ #ifdef CONFIG_PHY_LXT
+ 	phy_lxt_init();
+ #endif
+--- a/drivers/serial/Makefile
++++ b/drivers/serial/Makefile
+@@ -24,6 +24,7 @@ COBJS-$(CONFIG_SYS_NS16550_SERIAL) += se
+ COBJS-$(CONFIG_IMX_SERIAL) += serial_imx.o
+ COBJS-$(CONFIG_IXP_SERIAL) += serial_ixp.o
+ COBJS-$(CONFIG_KS8695_SERIAL) += serial_ks8695.o
++COBJS-$(CONFIG_LANTIQ_SERIAL) += serial_lantiq.o
+ COBJS-$(CONFIG_MAX3100_SERIAL) += serial_max3100.o
+ COBJS-$(CONFIG_MXC_UART) += serial_mxc.o
+ COBJS-$(CONFIG_PL010_SERIAL) += serial_pl01x.o
+--- a/drivers/serial/serial.c
++++ b/drivers/serial/serial.c
+@@ -160,6 +160,7 @@ serial_initfunc(sa1100_serial_initialize
+ serial_initfunc(sh_serial_initialize);
+ serial_initfunc(arm_dcc_initialize);
+ serial_initfunc(mxs_auart_initialize);
++serial_initfunc(ltq_serial_initialize);
+ 
+ /**
+  * serial_register() - Register serial driver with serial driver core
+@@ -253,6 +254,7 @@ void serial_initialize(void)
+ 	sh_serial_initialize();
+ 	arm_dcc_initialize();
+ 	mxs_auart_initialize();
++	ltq_serial_initialize();
+ 
+ 	serial_assign(default_serial_console()->name);
+ }
+--- /dev/null
++++ b/drivers/serial/serial_lantiq.c
+@@ -0,0 +1,263 @@
++/*
++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <serial.h>
++#include <asm/errno.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/io.h>
++
++#if CONFIG_CONSOLE_ASC == 0
++#define LTQ_ASC_BASE			LTQ_ASC0_BASE
++#else
++#define LTQ_ASC_BASE			LTQ_ASC1_BASE
++#endif
++
++#define LTQ_ASC_ID_TXFS_SHIFT		24
++#define LTQ_ASC_ID_TXFS_MASK		(0x3F << LTQ_ASC_ID_TXFS_SHIFT)
++#define LTQ_ASC_ID_RXFS_SHIFT		16
++#define LTQ_ASC_ID_RXFS_MASK		(0x3F << LTQ_ASC_ID_RXFS_SHIFT)
++
++#define LTQ_ASC_MCON_R			(1 << 15)
++#define LTQ_ASC_MCON_FDE		(1 << 9)
++
++#define LTQ_ASC_WHBSTATE_SETREN		(1 << 1)
++#define LTQ_ASC_WHBSTATE_CLRREN		(1 << 0)
++
++#define LTQ_ASC_RXFCON_RXFITL_SHIFT	8
++#define LTQ_ASC_RXFCON_RXFITL_MASK	(0x3F << LTQ_ASC_RXFCON_RXFITL_SHIFT)
++#define LTQ_ASC_RXFCON_RXFITL_RXFFLU	(1 << 1)
++#define LTQ_ASC_RXFCON_RXFITL_RXFEN	(1 << 0)
++
++#define LTQ_ASC_TXFCON_TXFITL_SHIFT	8
++#define LTQ_ASC_TXFCON_TXFITL_MASK	(0x3F << LTQ_ASC_TXFCON_TXFITL_SHIFT)
++#define LTQ_ASC_TXFCON_TXFITL_TXFFLU	(1 << 1)
++#define LTQ_ASC_TXFCON_TXFITL_TXFEN	(1 << 0)
++
++#define LTQ_ASC_FSTAT_TXFREE_SHIFT	24
++#define LTQ_ASC_FSTAT_TXFREE_MASK	(0x3F << LTQ_ASC_FSTAT_TXFREE_SHIFT)
++#define LTQ_ASC_FSTAT_RXFREE_SHIFT	16
++#define LTQ_ASC_FSTAT_RXFREE_MASK	(0x3F << LTQ_ASC_FSTAT_RXFREE_SHIFT)
++#define LTQ_ASC_FSTAT_TXFFL_SHIFT	8
++#define LTQ_ASC_FSTAT_TXFFL_MASK	(0x3F << LTQ_ASC_FSTAT_TXFFL_SHIFT)
++#define LTQ_ASC_FSTAT_RXFFL_MASK	0x3F
++
++#ifdef __BIG_ENDIAN
++#define LTQ_ASC_RBUF_OFFSET		3
++#define LTQ_ASC_TBUF_OFFSET		3
++#else
++#define LTQ_ASC_RBUF_OFFSET		0
++#define LTQ_ASC_TBUF_OFFSET		0
++#endif
++
++struct ltq_asc_regs {
++	u32	clc;
++	u32	pisel;
++	u32	id;
++	u32	rsvd0;
++	u32	mcon;
++	u32	state;
++	u32	whbstate;
++	u32	rsvd1;
++	u8	tbuf[4];
++	u8	rbuf[4];
++	u32	rsvd2[2];
++	u32	abcon;
++	u32	abstat;
++	u32	whbabcon;
++	u32	whbabstat;
++	u32	rxfcon;
++	u32	txfcon;
++	u32	fstat;
++	u32	rsvd3;
++	u32	bg;
++	u32	bg_timer;
++	u32	fdv;
++	u32	pmw;
++	u32	modcon;
++	u32	modstat;
++};
++
++DECLARE_GLOBAL_DATA_PTR;
++
++static struct ltq_asc_regs *ltq_asc_regs =
++	(struct ltq_asc_regs *) CKSEG1ADDR(LTQ_ASC_BASE);
++
++static int ltq_serial_init(void)
++{
++	/* Set clock divider for normal run mode to 1 and enable module */
++	ltq_writel(&ltq_asc_regs->clc, 0x100);
++
++	/* Reset MCON register */
++	ltq_writel(&ltq_asc_regs->mcon, 0);
++
++	/* Use Port A as receiver input */
++	ltq_writel(&ltq_asc_regs->pisel, 0);
++
++	/* Enable and flush RX/TX FIFOs */
++	ltq_setbits(&ltq_asc_regs->rxfcon,
++		LTQ_ASC_RXFCON_RXFITL_RXFFLU | LTQ_ASC_RXFCON_RXFITL_RXFEN);
++	ltq_setbits(&ltq_asc_regs->txfcon,
++		LTQ_ASC_TXFCON_TXFITL_TXFFLU | LTQ_ASC_TXFCON_TXFITL_TXFEN);
++
++	serial_setbrg();
++
++	/* Disable error flags, enable receiver */
++	ltq_writel(&ltq_asc_regs->whbstate, LTQ_ASC_WHBSTATE_SETREN);
++
++	return 0;
++}
++
++/*
++ *             fdv       asc_clk
++ * Baudrate = ----- * -------------
++ *             512    16 * (bg + 1)
++ */
++static void ltq_serial_calc_br_fdv(unsigned long asc_clk,
++					unsigned long baudrate, u16 *fdv,
++					u16 *bg)
++{
++	const u32 c = asc_clk / (16 * 512);
++	u32 diff1, diff2;
++	u32 bg_calc, br_calc, i;
++
++	diff1 = baudrate;
++	for (i = 512; i > 0; i--) {
++		/* Calc bg for current fdv value */
++		bg_calc = i * c / baudrate;
++
++		/* Impossible baudrate */
++		if (!bg_calc)
++			return;
++
++		/*
++		 * Calc diff to target baudrate dependent on current
++		 * bg and fdv values
++		 */
++		br_calc = i * c / bg_calc;
++		if (br_calc > baudrate)
++			diff2 = br_calc - baudrate;
++		else
++			diff2 = baudrate - br_calc;
++
++		/* Perfect values found */
++		if (diff2 == 0) {
++			*fdv = i;
++			*bg = bg_calc - 1;
++			return;
++		}
++
++		if (diff2 < diff1) {
++			*fdv = i;
++			*bg = bg_calc - 1;
++			diff1 = diff2;
++		}
++	}
++}
++
++static void ltq_serial_setbrg(void)
++{
++	unsigned long asc_clk, baudrate;
++	u16 bg = 0;
++	u16 fdv = 511;
++
++	/* ASC clock is same as FPI clock with CLC.RMS = 1 */
++	asc_clk = ltq_get_bus_clock();
++	baudrate = gd->baudrate;
++
++	/* Calculate FDV and BG values */
++	ltq_serial_calc_br_fdv(asc_clk, baudrate, &fdv, &bg);
++
++	/* Disable baudrate generator */
++	ltq_clrbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_R);
++
++	/* Enable fractional divider */
++	ltq_setbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_FDE);
++
++	/* Set fdv and bg values */
++	ltq_writel(&ltq_asc_regs->fdv, fdv);
++	ltq_writel(&ltq_asc_regs->bg, bg);
++
++	/* Enable baudrate generator */
++	ltq_setbits(&ltq_asc_regs->mcon, LTQ_ASC_MCON_R);
++}
++
++static unsigned int ltq_serial_tx_free(void)
++{
++	unsigned int txfree;
++
++	txfree = (ltq_readl(&ltq_asc_regs->fstat) &
++			LTQ_ASC_FSTAT_TXFREE_MASK) >>
++			LTQ_ASC_FSTAT_TXFREE_SHIFT;
++
++	return txfree;
++}
++
++static unsigned int ltq_serial_rx_fill(void)
++{
++	unsigned int rxffl;
++
++	rxffl = ltq_readl(&ltq_asc_regs->fstat) & LTQ_ASC_FSTAT_RXFFL_MASK;
++
++	return rxffl;
++}
++
++static void ltq_serial_tx(const char c)
++{
++	ltq_writeb(&ltq_asc_regs->tbuf[LTQ_ASC_TBUF_OFFSET], c);
++}
++
++static u8 ltq_serial_rx(void)
++{
++	return ltq_readb(&ltq_asc_regs->rbuf[LTQ_ASC_RBUF_OFFSET]);
++}
++
++static void ltq_serial_putc(const char c)
++{
++	if (c == '\n')
++		ltq_serial_putc('\r');
++
++	while (!ltq_serial_tx_free())
++		;
++
++	ltq_serial_tx(c);
++}
++
++static int ltq_serial_getc(void)
++{
++	while (!ltq_serial_rx_fill())
++		;
++
++	return ltq_serial_rx();
++}
++
++static int ltq_serial_tstc(void)
++{
++	return (0 != ltq_serial_rx_fill());
++}
++
++static struct serial_device ltq_serial_drv = {
++	.name	= "ltq_serial",
++	.start	= ltq_serial_init,
++	.stop	= NULL,
++	.setbrg	= ltq_serial_setbrg,
++	.putc	= ltq_serial_putc,
++	.puts	= default_serial_puts,
++	.getc	= ltq_serial_getc,
++	.tstc	= ltq_serial_tstc,
++};
++
++void ltq_serial_initialize(void)
++{
++	serial_register(&ltq_serial_drv);
++}
++
++__weak struct serial_device *default_serial_console(void)
++{
++	return &ltq_serial_drv;
++}
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -25,6 +25,7 @@ COBJS-$(CONFIG_DAVINCI_SPI) += davinci_s
+ COBJS-$(CONFIG_EXYNOS_SPI) += exynos_spi.o
+ COBJS-$(CONFIG_ICH_SPI) +=  ich.o
+ COBJS-$(CONFIG_KIRKWOOD_SPI) += kirkwood_spi.o
++COBJS-$(CONFIG_LANTIQ_SPI) += lantiq_spi.o
+ COBJS-$(CONFIG_MPC52XX_SPI) += mpc52xx_spi.o
+ COBJS-$(CONFIG_MPC8XXX_SPI) += mpc8xxx_spi.o
+ COBJS-$(CONFIG_MXC_SPI) += mxc_spi.o
+--- /dev/null
++++ b/drivers/spi/lantiq_spi.c
+@@ -0,0 +1,666 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <spi.h>
++#include <malloc.h>
++#include <watchdog.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/pm.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_SPI_CLC_RMC_SHIFT		8
++#define LTQ_SPI_CLC_RMC_MASK		(0xFF << LTQ_SPI_CLC_RMC_SHIFT)
++#define LTQ_SPI_CLC_DISS		(1 << 1)
++#define LTQ_SPI_CLC_DISR		1
++
++#define LTQ_SPI_ID_TXFS_SHIFT		24
++#define LTQ_SPI_ID_TXFS_MASK		(0x3F << LTQ_SPI_ID_TXFS_SHIFT)
++#define LTQ_SPI_ID_RXFS_SHIFT		16
++#define LTQ_SPI_ID_RXFS_MASK		(0x3F << LTQ_SPI_ID_RXFS_SHIFT)
++
++#define LTQ_SPI_CON_ENBV		(1 << 22)
++#define LTQ_SPI_CON_BM_SHIFT		16
++#define LTQ_SPI_CON_BM_MASK		(0x1F << LTQ_SPI_CON_BM_SHIFT)
++#define LTQ_SPI_CON_IDLE		(1 << 23)
++#define LTQ_SPI_CON_RUEN		(1 << 12)
++#define LTQ_SPI_CON_AEN			(1 << 10)
++#define LTQ_SPI_CON_REN			(1 << 9)
++#define LTQ_SPI_CON_TEN			(1 << 8)
++#define LTQ_SPI_CON_LB			(1 << 7)
++#define LTQ_SPI_CON_PO			(1 << 6)
++#define LTQ_SPI_CON_PH			(1 << 5)
++#define LTQ_SPI_CON_HB			(1 << 4)
++#define LTQ_SPI_CON_RXOFF		(1 << 1)
++#define LTQ_SPI_CON_TXOFF		1
++
++#define LTQ_SPI_STAT_RXBV_SHIFT		28
++#define LTQ_SPI_STAT_RXBV_MASK		(0x7 << LTQ_SPI_STAT_RXBV_SHIFT)
++#define LTQ_SPI_STAT_BSY		(1 << 13)
++
++#define LTQ_SPI_WHBSTATE_SETMS		(1 << 3)
++#define LTQ_SPI_WHBSTATE_CLRMS		(1 << 2)
++#define LTQ_SPI_WHBSTATE_SETEN		(1 << 1)
++#define LTQ_SPI_WHBSTATE_CLREN		1
++#define LTQ_SPI_WHBSTATE_CLR_ERRORS	0x0F50
++
++#define LTQ_SPI_TXFCON_TXFLU		(1 << 1)
++#define LTQ_SPI_TXFCON_TXFEN		1
++
++#define LTQ_SPI_RXFCON_RXFLU		(1 << 1)
++#define LTQ_SPI_RXFCON_RXFEN		1
++
++#define LTQ_SPI_FSTAT_RXFFL_MASK	0x3f
++#define LTQ_SPI_FSTAT_TXFFL_SHIFT	8
++#define LTQ_SPI_FSTAT_TXFFL_MASK	(0x3f << LTQ_SPI_FSTAT_TXFFL_SHIFT)
++
++#define LTQ_SPI_RXREQ_RXCNT_MASK	0xFFFF
++#define LTQ_SPI_RXCNT_TODO_MASK		0xFFFF
++
++#define LTQ_SPI_GPIO_DIN		16
++#define LTQ_SPI_GPIO_DOUT		17
++#define LTQ_SPI_GPIO_CLK		18
++
++struct ltq_spi_regs {
++	__be32	clc;		/* Clock control */
++	__be32	pisel;		/* Port input select */
++	__be32	id;		/* Identification */
++	__be32	rsvd0;
++	__be32	con;		/* Control */
++	__be32	stat;		/* Status */
++	__be32	whbstate;	/* Write HW modified state */
++	__be32	rsvd1;
++	__be32	tb;		/* Transmit buffer */
++	__be32	rb;		/* Receive buffer */
++	__be32	rsvd2[2];
++	__be32	rxfcon;		/* Recevie FIFO control */
++	__be32	txfcon;		/* Transmit FIFO control */
++	__be32	fstat;		/* FIFO status */
++	__be32	rsvd3;
++	__be32	brt;		/* Baudrate timer */
++	__be32	brstat;		/* Baudrate timer status */
++	__be32	rsvd4[6];
++	__be32	sfcon;		/* Serial frame control */
++	__be32	sfstat;		/* Serial frame status */
++	__be32	rsvd5[2];
++	__be32	gpocon;		/* General purpose output control */
++	__be32	gpostat;	/* General purpose output status */
++	__be32	fgpo;		/* Force general purpose output */
++	__be32	rsvd6;
++	__be32	rxreq;		/* Receive request */
++	__be32	rxcnt;		/* Receive count */
++	__be32	rsvd7[25];
++	__be32	dmacon;		/* DMA control */
++	__be32	rsvd8;
++	__be32	irnen;		/* Interrupt node enable */
++	__be32	irnicr;		/* Interrupt node interrupt capture */
++	__be32	irncr;		/* Interrupt node control */
++};
++
++struct ltq_spi_drv_data {
++	struct ltq_spi_regs __iomem *regs;
++
++	struct spi_slave slave;
++	unsigned int max_hz;
++	unsigned int mode;
++	unsigned int tx_todo;
++	unsigned int rx_todo;
++	unsigned int rx_req;
++	unsigned int bits_per_word;
++	unsigned int speed_hz;
++	const u8 *tx;
++	u8 *rx;
++	int status;
++};
++
++static struct ltq_spi_drv_data *to_ltq_spi_slave(struct spi_slave *slave)
++{
++	return container_of(slave, struct ltq_spi_drv_data, slave);
++}
++
++#ifdef CONFIG_SPL_BUILD
++/*
++ * We do not have or want malloc in a SPI flash SPL.
++ * Neither we have to support multiple SPI slaves. Thus we put the
++ * SPI slave context in BSS for SPL builds.
++ */
++static struct ltq_spi_drv_data ltq_spi_slave;
++
++static struct ltq_spi_drv_data *ltq_spi_slave_alloc(unsigned int bus,
++							unsigned int cs)
++{
++	ltq_spi_slave.slave.bus = bus;
++	ltq_spi_slave.slave.cs = cs;
++
++	return &ltq_spi_slave;
++}
++
++static void ltq_spi_slave_free(struct spi_slave *slave)
++{
++}
++#else
++static struct ltq_spi_drv_data *ltq_spi_slave_alloc(unsigned int bus,
++							unsigned int cs)
++{
++	return spi_alloc_slave(struct ltq_spi_drv_data, bus, cs);
++}
++
++static void ltq_spi_slave_free(struct spi_slave *slave)
++{
++	struct ltq_spi_drv_data *drv;
++
++	if (slave) {
++		drv = to_ltq_spi_slave(slave);
++		free(drv);
++	}
++}
++#endif
++
++static unsigned int tx_fifo_size(struct ltq_spi_drv_data *drv)
++{
++	u32 id = ltq_readl(&drv->regs->id);
++
++	return (id & LTQ_SPI_ID_TXFS_MASK) >> LTQ_SPI_ID_TXFS_SHIFT;
++}
++
++static unsigned int rx_fifo_size(struct ltq_spi_drv_data *drv)
++{
++	u32 id = ltq_readl(&drv->regs->id);
++
++	return (id & LTQ_SPI_ID_RXFS_MASK) >> LTQ_SPI_ID_RXFS_SHIFT;
++}
++
++static unsigned int tx_fifo_level(struct ltq_spi_drv_data *drv)
++{
++	u32 fstat = ltq_readl(&drv->regs->fstat);
++
++	return (fstat & LTQ_SPI_FSTAT_TXFFL_MASK) >> LTQ_SPI_FSTAT_TXFFL_SHIFT;
++}
++
++static unsigned int rx_fifo_level(struct ltq_spi_drv_data *drv)
++{
++	u32 fstat = ltq_readl(&drv->regs->fstat);
++
++	return fstat & LTQ_SPI_FSTAT_RXFFL_MASK;
++}
++
++static unsigned int tx_fifo_free(struct ltq_spi_drv_data *drv)
++{
++	return tx_fifo_size(drv) - tx_fifo_level(drv);
++}
++
++static void hw_power_on(struct ltq_spi_drv_data *drv)
++{
++	u32 clc;
++
++	/* Power-up mdule */
++	ltq_pm_enable(LTQ_PM_SPI);
++
++	/*
++	 * Set clock divider for run mode to 1 to
++	 * run at same frequency as FPI bus
++	 */
++	clc = (1 << LTQ_SPI_CLC_RMC_SHIFT);
++	ltq_writel(&drv->regs->clc, clc);
++}
++
++static void hw_reset_fifos(struct ltq_spi_drv_data *drv)
++{
++	u32 val;
++
++	val = LTQ_SPI_TXFCON_TXFEN | LTQ_SPI_TXFCON_TXFLU;
++	ltq_writel(&drv->regs->txfcon, val);
++
++	val = LTQ_SPI_RXFCON_RXFEN | LTQ_SPI_RXFCON_RXFLU;
++	ltq_writel(&drv->regs->rxfcon, val);
++}
++
++static int hw_is_busy(struct ltq_spi_drv_data *drv)
++{
++	u32 stat = ltq_readl(&drv->regs->stat);
++
++	return stat & LTQ_SPI_STAT_BSY;
++}
++
++static void hw_enter_config_mode(struct ltq_spi_drv_data *drv)
++{
++	ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_CLREN);
++}
++
++static void hw_enter_active_mode(struct ltq_spi_drv_data *drv)
++{
++	ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_SETEN);
++}
++
++static void hw_setup_speed_hz(struct ltq_spi_drv_data *drv,
++				unsigned int max_speed_hz)
++{
++	unsigned int spi_hz, speed_hz, brt;
++
++	/*
++	 * SPI module clock is derived from FPI bus clock dependent on
++	 * divider value in CLC.RMS which is always set to 1.
++	 *
++	 *                 f_SPI
++	 * baudrate = --------------
++	 *             2 * (BR + 1)
++	 */
++	spi_hz = ltq_get_bus_clock() / 2;
++
++	/* TODO: optimize baudrate calculation */
++	for (brt = 0; brt < 0xFFFF; brt++) {
++		speed_hz = spi_hz / (brt + 1);
++		if (speed_hz <= max_speed_hz)
++			break;
++	}
++
++	ltq_writel(&drv->regs->brt, brt);
++}
++
++static void hw_setup_bits_per_word(struct ltq_spi_drv_data *drv,
++					unsigned int bits_per_word)
++{
++	u32 bm;
++
++	/* CON.BM value = bits_per_word - 1 */
++	bm = (bits_per_word - 1) << LTQ_SPI_CON_BM_SHIFT;
++
++	ltq_clrsetbits(&drv->regs->con, LTQ_SPI_CON_BM_MASK, bm);
++}
++
++static void hw_setup_clock_mode(struct ltq_spi_drv_data *drv, unsigned int mode)
++{
++	u32 con_set = 0, con_clr = 0;
++
++	/*
++	 * SPI mode mapping in CON register:
++	 * Mode CPOL CPHA CON.PO CON.PH
++	 *  0    0    0      0      1
++	 *  1    0    1      0      0
++	 *  2    1    0      1      1
++	 *  3    1    1      1      0
++	 */
++	if (mode & SPI_CPHA)
++		con_clr |= LTQ_SPI_CON_PH;
++	else
++		con_set |= LTQ_SPI_CON_PH;
++
++	if (mode & SPI_CPOL)
++		con_set |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
++	else
++		con_clr |= LTQ_SPI_CON_PO | LTQ_SPI_CON_IDLE;
++
++	/* Set heading control */
++	if (mode & SPI_LSB_FIRST)
++		con_clr |= LTQ_SPI_CON_HB;
++	else
++		con_set |= LTQ_SPI_CON_HB;
++
++	/* Set loopback mode */
++	if (mode & SPI_LOOP)
++		con_set |= LTQ_SPI_CON_LB;
++	else
++		con_clr |= LTQ_SPI_CON_LB;
++
++	ltq_clrsetbits(&drv->regs->con, con_clr, con_set);
++}
++
++static void hw_set_rxtx(struct ltq_spi_drv_data *drv)
++{
++	u32 con;
++
++	/* Configure transmitter and receiver */
++	con = ltq_readl(&drv->regs->con);
++	if (drv->tx)
++		con &= ~LTQ_SPI_CON_TXOFF;
++	else
++		con |= LTQ_SPI_CON_TXOFF;
++
++	if (drv->rx)
++		con &= ~LTQ_SPI_CON_RXOFF;
++	else
++		con |= LTQ_SPI_CON_RXOFF;
++
++	ltq_writel(&drv->regs->con, con);
++}
++
++static void hw_init(struct ltq_spi_drv_data *drv)
++{
++	hw_power_on(drv);
++
++	/* Put controller into config mode */
++	hw_enter_config_mode(drv);
++
++	/* Disable all interrupts */
++	ltq_writel(&drv->regs->irnen, 0);
++
++	/* Clear error flags */
++	ltq_clrsetbits(&drv->regs->whbstate, 0, LTQ_SPI_WHBSTATE_CLR_ERRORS);
++
++	/* Enable error checking, disable TX/RX */
++	ltq_writel(&drv->regs->con, LTQ_SPI_CON_RUEN | LTQ_SPI_CON_AEN |
++			LTQ_SPI_CON_TEN | LTQ_SPI_CON_REN | LTQ_SPI_CON_TXOFF |
++			LTQ_SPI_CON_RXOFF);
++
++	/* Setup default SPI mode */
++	drv->bits_per_word = 8;
++	drv->speed_hz = 0;
++	hw_setup_bits_per_word(drv, drv->bits_per_word);
++	hw_setup_clock_mode(drv, SPI_MODE_0);
++
++	/* Enable master mode and clear error flags */
++	ltq_writel(&drv->regs->whbstate, LTQ_SPI_WHBSTATE_SETMS |
++			LTQ_SPI_WHBSTATE_CLR_ERRORS);
++
++	/* Reset GPIO/CS registers */
++	ltq_writel(&drv->regs->gpocon, 0);
++	ltq_writel(&drv->regs->fgpo, 0xFF00);
++
++	/* Enable and flush FIFOs */
++	hw_reset_fifos(drv);
++
++	/* SPI/DIN input */
++	gpio_set_altfunc(16, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
++	/* SPI/DOUT output */
++	gpio_set_altfunc(17, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* SPI/CLK output */
++	gpio_set_altfunc(18, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++}
++
++static void tx_fifo_write(struct ltq_spi_drv_data *drv)
++{
++	const u8 *tx8;
++	const u16 *tx16;
++	const u32 *tx32;
++	u32 data;
++	unsigned int tx_free = tx_fifo_free(drv);
++
++	while (drv->tx_todo && tx_free) {
++		switch (drv->bits_per_word) {
++		case 8:
++			tx8 = drv->tx;
++			data = *tx8;
++			drv->tx_todo--;
++			drv->tx++;
++			break;
++		case 16:
++			tx16 = (u16 *) drv->tx;
++			data = *tx16;
++			drv->tx_todo -= 2;
++			drv->tx += 2;
++			break;
++		case 32:
++			tx32 = (u32 *) drv->tx;
++			data = *tx32;
++			drv->tx_todo -= 4;
++			drv->tx += 4;
++			break;
++		default:
++			return;
++		}
++
++		ltq_writel(&drv->regs->tb, data);
++		tx_free--;
++	}
++}
++
++static void rx_fifo_read_full_duplex(struct ltq_spi_drv_data *drv)
++{
++	u8 *rx8;
++	u16 *rx16;
++	u32 *rx32;
++	u32 data;
++	unsigned int rx_fill = rx_fifo_level(drv);
++
++	while (rx_fill) {
++		data = ltq_readl(&drv->regs->rb);
++
++		switch (drv->bits_per_word) {
++		case 8:
++			rx8 = drv->rx;
++			*rx8 = data;
++			drv->rx_todo--;
++			drv->rx++;
++			break;
++		case 16:
++			rx16 = (u16 *) drv->rx;
++			*rx16 = data;
++			drv->rx_todo -= 2;
++			drv->rx += 2;
++			break;
++		case 32:
++			rx32 = (u32 *) drv->rx;
++			*rx32 = data;
++			drv->rx_todo -= 4;
++			drv->rx += 4;
++			break;
++		default:
++			return;
++		}
++
++		rx_fill--;
++	}
++}
++
++static void rx_fifo_read_half_duplex(struct ltq_spi_drv_data *drv)
++{
++	u32 data, *rx32;
++	u8 *rx8;
++	unsigned int rxbv, shift;
++	unsigned int rx_fill = rx_fifo_level(drv);
++
++	/*
++	 * In RX-only mode the bits per word value is ignored by HW. A value
++	 * of 32 is used instead. Thus all 4 bytes per FIFO must be read.
++	 * If remaining RX bytes are less than 4, the FIFO must be read
++	 * differently. The amount of received and valid bytes is indicated
++	 * by STAT.RXBV register value.
++	 */
++	while (rx_fill) {
++		if (drv->rx_todo < 4) {
++			rxbv = (ltq_readl(&drv->regs->stat) &
++				LTQ_SPI_STAT_RXBV_MASK) >>
++				LTQ_SPI_STAT_RXBV_SHIFT;
++			data = ltq_readl(&drv->regs->rb);
++
++			shift = (rxbv - 1) * 8;
++			rx8 = drv->rx;
++
++			while (rxbv) {
++				*rx8++ = (data >> shift) & 0xFF;
++				rxbv--;
++				shift -= 8;
++				drv->rx_todo--;
++				drv->rx++;
++
++				if (drv->rx_req)
++					drv->rx_req --;
++			}
++		} else {
++			data = ltq_readl(&drv->regs->rb);
++			rx32 = (u32 *) drv->rx;
++
++			*rx32++ = data;
++			drv->rx_todo -= 4;
++			drv->rx += 4;
++
++			if (drv->rx_req >= 4)
++				drv->rx_req -= 4;
++		}
++		rx_fill--;
++	}
++}
++
++static void rx_request(struct ltq_spi_drv_data *drv)
++{
++	unsigned int rxreq, rxreq_max;
++
++	if (drv->rx_req)
++		return;
++
++	/*
++	 * To avoid receive overflows at high clocks it is better to request
++	 * only the amount of bytes that fits into all FIFOs. This value
++	 * depends on the FIFO size implemented in hardware.
++	 */
++	rxreq = drv->rx_todo;
++	rxreq_max = rx_fifo_size(drv) * 4;
++	if (rxreq > rxreq_max)
++		rxreq = rxreq_max;
++
++	drv->rx_req = rxreq;
++	ltq_writel(&drv->regs->rxreq, rxreq);
++}
++
++void spi_init(void)
++{
++}
++
++struct spi_slave *spi_setup_slave(unsigned int bus, unsigned int cs,
++				  unsigned int max_hz, unsigned int mode)
++{
++	struct ltq_spi_drv_data *drv;
++
++	if (!spi_cs_is_valid(bus, cs))
++		return NULL;
++
++	drv = ltq_spi_slave_alloc(bus, cs);
++	if (!drv)
++		return NULL;
++
++	drv->regs = (struct ltq_spi_regs *) CKSEG1ADDR(LTQ_SPI_BASE);
++
++	hw_init(drv);
++
++	drv->max_hz = max_hz;
++	drv->mode = mode;
++
++	return &drv->slave;
++}
++
++void spi_free_slave(struct spi_slave *slave)
++{
++	ltq_spi_slave_free(slave);
++}
++
++static int ltq_spi_wait_ready(struct ltq_spi_drv_data *drv)
++{
++	const unsigned long timeout = 20000;
++	unsigned long timebase;
++
++	timebase = get_timer(0);
++
++	do {
++		WATCHDOG_RESET();
++
++		if (!hw_is_busy(drv))
++			return 0;
++	} while (get_timer(timebase) < timeout);
++
++	return 1;
++}
++
++int spi_claim_bus(struct spi_slave *slave)
++{
++	struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
++	int ret;
++
++	ret = ltq_spi_wait_ready(drv);
++	if (ret) {
++		debug("cannot claim bus\n");
++		return ret;
++	}
++
++	hw_enter_config_mode(drv);
++	hw_setup_clock_mode(drv, drv->mode);
++	hw_setup_speed_hz(drv, drv->max_hz);
++	hw_setup_bits_per_word(drv, drv->bits_per_word);
++	hw_enter_active_mode(drv);
++
++	return 0;
++}
++
++void spi_release_bus(struct spi_slave *slave)
++{
++	struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
++
++	hw_enter_config_mode(drv);
++}
++
++int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
++		const void *dout, void *din, unsigned long flags)
++{
++
++	struct ltq_spi_drv_data *drv = to_ltq_spi_slave(slave);
++	int ret = 0;
++
++	if (bitlen % 8)
++		return 1;
++
++	if (!bitlen) {
++		ret = 0;
++		goto done;
++	}
++
++	if (flags & SPI_XFER_BEGIN)
++		spi_cs_activate(slave);
++
++	drv->tx = dout;
++	drv->tx_todo = 0;
++	drv->rx = din;
++	drv->rx_todo = 0;
++	hw_set_rxtx(drv);
++
++	if (drv->tx) {
++		drv->tx_todo = bitlen / 8;
++
++		tx_fifo_write(drv);
++	}
++
++	if (drv->rx) {
++		drv->rx_todo = bitlen / 8;
++
++		if (!drv->tx)
++			rx_request(drv);
++	}
++
++	for (;;) {
++		if (drv->tx) {
++			if (drv->rx && drv->rx_todo)
++				rx_fifo_read_full_duplex(drv);
++
++			if (drv->tx_todo)
++				tx_fifo_write(drv);
++			else
++				goto done;
++		} else if (drv->rx) {
++			if (drv->rx_todo) {
++				rx_fifo_read_half_duplex(drv);
++
++				if (drv->rx_todo)
++					rx_request(drv);
++				else
++					goto done;
++			} else {
++				goto done;
++			}
++		}
++	}
++
++done:
++	ret = ltq_spi_wait_ready(drv);
++
++	drv->rx = NULL;
++	drv->tx = NULL;
++	hw_set_rxtx(drv);
++
++	if (flags & SPI_XFER_END)
++		spi_cs_deactivate(slave);
++
++	return ret;
++}
+--- a/include/phy.h
++++ b/include/phy.h
+@@ -214,6 +214,7 @@ int phy_atheros_init(void);
+ int phy_broadcom_init(void);
+ int phy_davicom_init(void);
+ int phy_et1011c_init(void);
++int phy_lantiq_init(void);
+ int phy_lxt_init(void);
+ int phy_marvell_init(void);
+ int phy_micrel_init(void);
+--- a/spl/Makefile
++++ b/spl/Makefile
+@@ -100,6 +100,8 @@ LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += dri
+ LIBS-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += drivers/usb/musb-new/libusb_musb-new.o
+ LIBS-$(CONFIG_SPL_USBETH_SUPPORT) += drivers/usb/gadget/libusb_gadget.o
+ LIBS-$(CONFIG_SPL_WATCHDOG_SUPPORT) += drivers/watchdog/libwatchdog.o
++LIBS-$(CONFIG_SPL_LZMA_SUPPORT) += lib/lzma/liblzma.o
++LIBS-$(CONFIG_SPL_LZO_SUPPORT) += lib/lzo/liblzo.o
+ 
+ ifneq ($(CONFIG_OMAP_COMMON),)
+ LIBS-y += $(CPUDIR)/omap-common/libomap-common.o
+--- a/tools/.gitignore
++++ b/tools/.gitignore
+@@ -2,6 +2,7 @@
+ /envcrc
+ /gen_eth_addr
+ /img2srec
++/ltq-boot-image
+ /kwboot
+ /mkenvimage
+ /mkimage
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -49,6 +49,7 @@ BIN_FILES-$(CONFIG_VIDEO_LOGO) += bmp_lo
+ BIN_FILES-$(CONFIG_BUILD_ENVCRC) += envcrc$(SFX)
+ BIN_FILES-$(CONFIG_CMD_NET) += gen_eth_addr$(SFX)
+ BIN_FILES-$(CONFIG_CMD_LOADS) += img2srec$(SFX)
++BIN_FILES-$(CONFIG_SOC_LANTIQ) += ltq-boot-image$(SFX)
+ BIN_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes$(SFX)
+ BIN_FILES-y += mkenvimage$(SFX)
+ BIN_FILES-y += mkimage$(SFX)
+@@ -95,6 +96,7 @@ OBJ_FILES-$(CONFIG_MX28) += mxsboot.o
+ OBJ_FILES-$(CONFIG_NETCONSOLE) += ncb.o
+ OBJ_FILES-$(CONFIG_SHA1_CHECK_UB_IMG) += ubsha1.o
+ OBJ_FILES-$(CONFIG_SMDK5250) += mkexynosspl.o
++OBJ_FILES-$(CONFIG_SOC_LANTIQ) += ltq-boot-image.o
+ OBJ_FILES-$(CONFIG_VIDEO_LOGO) += bmp_logo.o
+ OBJ_FILES-$(CONFIG_XWAY_SWAP_BYTES) += xway-swap-bytes.o
+ 
+@@ -195,6 +197,10 @@ $(obj)img2srec$(SFX):	$(obj)img2srec.o
+ 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ 	$(HOSTSTRIP) $@
+ 
++$(obj)ltq-boot-image$(SFX):	$(obj)ltq-boot-image.o
++	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
++	$(HOSTSTRIP) $@
++
+ $(obj)xway-swap-bytes$(SFX):	$(obj)xway-swap-bytes.o
+ 	$(HOSTCC) $(HOSTCFLAGS) $(HOSTLDFLAGS) -o $@ $^
+ 	$(HOSTSTRIP) $@
+--- /dev/null
++++ b/tools/ltq-boot-image.c
+@@ -0,0 +1,315 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <string.h>
++#include <unistd.h>
++#include <getopt.h>
++#include <compiler.h>
++#include <sys/stat.h>
++
++enum image_types {
++	IMAGE_NONE,
++	IMAGE_SFSPL
++};
++
++/* Lantiq non-volatile bootstrap command IDs */
++enum nvb_cmd_ids {
++	NVB_CMD_DEBUG	= 0x11,
++	NVB_CMD_REGCFG	= 0x22,
++	NVB_CMD_IDWNLD	= 0x33,
++	NVB_CMD_CDWNLD	= 0x44,
++	NVB_CMD_DWNLD	= 0x55,
++	NVB_CMD_IFCFG	= 0x66,
++	NVB_CMD_START	= 0x77
++};
++
++/* Lantiq non-volatile bootstrap command flags */
++enum nvb_cmd_flags {
++	NVB_FLAG_START	= 1,
++	NVB_FLAG_DEC	= (1 << 1),
++	NVB_FLAG_DBG	= (1 << 2),
++	NVB_FLAG_SDBG	= (1 << 3),
++	NVB_FLAG_CFG0	= (1 << 4),
++	NVB_FLAG_CFG1	= (1 << 5),
++	NVB_FLAG_CFG2	= (1 << 6),
++	NVB_FLAG_RST	= (1 << 7)
++};
++
++struct args {
++	enum image_types type;
++	__u32		entry_addr;
++	const char	*uboot_bin;
++	const char	*spl_bin;
++	const char	*out_bin;
++};
++
++static void usage_msg(const char *name)
++{
++	fprintf(stderr, "%s: [-h] -t type -e entry-addr -u uboot-bin [-s spl-bin] -o out-bin\n",
++		name);
++	fprintf(stderr, " Image types:\n"
++			"  sfspl  - SPL + [compressed] U-Boot for SPI flash\n");
++}
++
++static enum image_types parse_image_type(const char *type)
++{
++	if (!type)
++		return IMAGE_NONE;
++
++	if (!strncmp(type, "sfspl", 6))
++		return IMAGE_SFSPL;
++
++	return IMAGE_NONE;
++}
++
++static int parse_args(int argc, char *argv[], struct args *arg)
++{
++	int opt;
++
++	memset(arg, 0, sizeof(*arg));
++
++	while ((opt = getopt(argc, argv, "ht:e:u:s:o:")) != -1) {
++		switch (opt) {
++		case 'h':
++			usage_msg(argv[0]);
++			return 1;
++		case 't':
++			arg->type = parse_image_type(optarg);
++			break;
++		case 'e':
++			arg->entry_addr = strtoul(optarg, NULL, 16);
++			break;
++		case 'u':
++			arg->uboot_bin = optarg;
++			break;
++		case 's':
++			arg->spl_bin = optarg;
++			break;
++		case 'o':
++			arg->out_bin = optarg;
++			break;
++		default:
++			fprintf(stderr, "Invalid option -%c\n", opt);
++			goto parse_error;
++		}
++	}
++
++	if (arg->type == IMAGE_NONE) {
++		fprintf(stderr, "Invalid image type\n");
++		goto parse_error;
++	}
++
++	if (!arg->uboot_bin) {
++		fprintf(stderr, "Missing U-Boot binary\n");
++		goto parse_error;
++	}
++
++	if (!arg->out_bin) {
++		fprintf(stderr, "Missing output binary\n");
++		goto parse_error;
++	}
++
++	if (arg->type == IMAGE_SFSPL && !arg->spl_bin) {
++		fprintf(stderr, "Missing SPL binary\n");
++		goto parse_error;
++	}
++
++	return 0;
++
++parse_error:
++	usage_msg(argv[0]);
++	return -1;
++}
++
++static __u32 build_nvb_command(unsigned cmdid, unsigned cmdflags)
++{
++	__u32 cmd;
++	__u16 tag;
++
++	tag = (cmdid << 8) | cmdflags;
++	cmd = (tag << 16) | (0xFFFF - tag);
++
++	return cpu_to_be32(cmd);
++}
++
++static int write_header(int fd, const void *hdr, size_t size)
++{
++	ssize_t n;
++
++	n = write(fd, hdr, size);
++	if (n != size) {
++		fprintf(stderr, "Cannot write header: %s\n",
++			strerror(errno));
++		return -1;
++	}
++
++	return 0;
++}
++
++static int write_nvb_dwnld_header(int fd, size_t size, __u32 addr)
++{
++	__u32 hdr[3];
++
++	hdr[0] = build_nvb_command(NVB_CMD_DWNLD, NVB_FLAG_START |
++					NVB_FLAG_SDBG);
++	hdr[1] = cpu_to_be32(size + 4);
++	hdr[2] = cpu_to_be32(addr);
++
++	return write_header(fd, hdr, sizeof(hdr));
++}
++
++static int write_nvb_start_header(int fd, __u32 addr)
++{
++	__u32 hdr[3];
++
++	hdr[0] = build_nvb_command(NVB_CMD_START, NVB_FLAG_SDBG);
++	hdr[1] = cpu_to_be32(4);
++	hdr[2] = cpu_to_be32(addr);
++
++	return write_header(fd, hdr, sizeof(hdr));
++}
++
++static int open_input_bin(const char *name, void **ptr, size_t *size)
++{
++	struct stat sbuf;
++	int ret, fd;
++
++	fd = open(name, O_RDONLY | O_BINARY);
++	if (0 > fd) {
++		fprintf(stderr, "Cannot open %s: %s\n", name,
++			strerror(errno));
++		return -1;
++	}
++
++	ret = fstat(fd, &sbuf);
++	if (0 > ret) {
++		fprintf(stderr, "Cannot fstat %s: %s\n", name,
++			strerror(errno));
++		return -1;
++	}
++
++	*ptr = mmap(0, sbuf.st_size, PROT_READ, MAP_SHARED, fd, 0);
++	if (*ptr == MAP_FAILED) {
++		fprintf(stderr, "Cannot mmap %s: %s\n", name,
++			strerror(errno));
++		return -1;
++	}
++
++	*size = sbuf.st_size;
++
++	return fd;
++}
++
++static void close_input_bin(int fd, void *ptr, size_t size)
++{
++	munmap(ptr, size);
++	close(fd);
++}
++
++static int copy_bin(int fd, void *ptr, size_t size)
++{
++	ssize_t n;
++
++	n = write(fd, ptr, size);
++	if (n != size) {
++		fprintf(stderr, "Cannot copy binary: %s\n", strerror(errno));
++		return -1;
++	}
++
++	return 0;
++}
++
++static int open_output_bin(const char *name)
++{
++	int fd;
++
++	fd = open(name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY, 0666);
++	if (0 > fd) {
++		fprintf(stderr, "Cannot open %s: %s\n", name,
++			strerror(errno));
++		return -1;
++	}
++
++	return fd;
++}
++
++static int create_sfspl(const struct args *arg)
++{
++	int out_fd, uboot_fd, spl_fd, ret;
++	void *uboot_ptr, *spl_ptr;
++	size_t uboot_size, spl_size;
++
++	out_fd = open_output_bin(arg->out_bin);
++	if (0 > out_fd)
++		goto err;
++
++	spl_fd = open_input_bin(arg->spl_bin, &spl_ptr, &spl_size);
++	if (0 > spl_fd)
++		goto err_spl;
++
++	uboot_fd = open_input_bin(arg->uboot_bin, &uboot_ptr, &uboot_size);
++	if (0 > uboot_fd)
++		goto err_uboot;
++
++	ret = write_nvb_dwnld_header(out_fd, spl_size, arg->entry_addr);
++	if (ret)
++		goto err_write;
++
++	ret = copy_bin(out_fd, spl_ptr, spl_size);
++	if (ret)
++		goto err_write;
++
++	ret = write_nvb_start_header(out_fd, arg->entry_addr);
++	if (ret)
++		goto err_write;
++
++	ret = copy_bin(out_fd, uboot_ptr, uboot_size);
++	if (ret)
++		goto err_write;
++
++	close_input_bin(uboot_fd, uboot_ptr, uboot_size);
++	close_input_bin(spl_fd, spl_ptr, spl_size);
++	close(out_fd);
++
++	return 0;
++
++err_write:
++	close_input_bin(uboot_fd, uboot_ptr, uboot_size);
++err_uboot:
++	close_input_bin(spl_fd, spl_ptr, spl_size);
++err_spl:
++	close(out_fd);
++err:
++	return -1;
++}
++
++int main(int argc, char *argv[])
++{
++	int ret;
++	struct args arg;
++
++	ret = parse_args(argc, argv, &arg);
++	if (ret)
++		goto done;
++
++	switch (arg.type) {
++	case IMAGE_SFSPL:
++		ret = create_sfspl(&arg);
++		break;
++	default:
++		fprintf(stderr, "Image type not implemented\n");
++		ret = -1;
++		break;
++	}
++
++done:
++	if (ret >= 0)
++		return EXIT_SUCCESS;
++
++	return EXIT_FAILURE;
++}
diff --git a/package/boot/uboot-lantiq/patches/0015-MIPS-lantiq-add-support-for-Lantiq-XWAY-ARX100-SoC-f.patch b/package/boot/uboot-lantiq/patches/0015-MIPS-lantiq-add-support-for-Lantiq-XWAY-ARX100-SoC-f.patch
new file mode 100644
index 0000000..a12d2eb
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0015-MIPS-lantiq-add-support-for-Lantiq-XWAY-ARX100-SoC-f.patch
@@ -0,0 +1,1229 @@
+From 4953294aa8f8b9023e6b5f7f39059706c72d916c Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 9 Dec 2012 17:54:56 +0100
+Subject: MIPS: lantiq: add support for Lantiq XWAY ARX100 SoC family
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: John Crispin <blogic@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/Makefile
+@@ -0,0 +1,31 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(SOC).o
++
++COBJS-y	+= cgu.o chipid.o ebu.o mem.o pmu.o rcu.o
++SOBJS-y	+= cgu_init.o mem_init.o
++
++COBJS	:= $(COBJS-y)
++SOBJS	:= $(SOBJS-y)
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(SOBJS) $(COBJS))
++
++all:	$(LIB)
++
++$(LIB):	$(obj).depend $(OBJS)
++	$(call cmd_link_o_target, $(OBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/cgu.c
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/clk.h>
++#include <asm/lantiq/io.h>
++
++#define CGU_SYS_DDR_SEL		(1 << 0)
++#define CGU_SYS_CPU_SEL		(1 << 2)
++#define CGU_SYS_SYS_SHIFT	3
++#define CGU_SYS_SYS_MASK	(0x3 << CGU_SYS_SYS_SHIFT)
++#define CGU_SYS_FPI_SEL		(1 << 6)
++#define CGU_SYS_PPE_SEL		(1 << 7)
++
++struct ltq_cgu_regs {
++	u32	rsvd0;
++	__be32	pll0_cfg;	/* PLL0 config */
++	__be32	pll1_cfg;	/* PLL1 config */
++	u32	rsvd2;
++	__be32	sys;		/* System clock */
++	__be32	update;		/* CGU update control */
++	__be32	if_clk;		/* Interface clock */
++	u32	rsvd3;
++	__be32	smd;		/* SDRAM Memory Control */
++	u32	rsvd4;
++	__be32	ct1_sr;		/* CT status 1 */
++	__be32	ct_kval;	/* CT K value */
++	__be32	pcm_cr;		/* PCM control */
++};
++
++static struct ltq_cgu_regs *ltq_cgu_regs =
++	(struct ltq_cgu_regs *) CKSEG1ADDR(LTQ_CGU_BASE);
++
++static inline u32 ltq_cgu_sys_readl(u32 mask, u32 shift)
++{
++	return (ltq_readl(&ltq_cgu_regs->sys) & mask) >> shift;
++}
++
++static unsigned long ltq_get_system_clock(void)
++{
++	u32 sys_sel;
++	unsigned long clk;
++
++	sys_sel = ltq_cgu_sys_readl(CGU_SYS_SYS_MASK, CGU_SYS_SYS_SHIFT);
++
++	switch (sys_sel) {
++	case 0:
++		clk = CLOCK_333_MHZ;
++		break;
++	case 2:
++		clk = CLOCK_393_MHZ;
++		break;
++	default:
++		clk = 0;
++		break;
++	}
++
++	return clk;
++}
++
++unsigned long ltq_get_io_region_clock(void)
++{
++	u32 ddr_sel;
++	unsigned long clk;
++
++	ddr_sel = ltq_cgu_sys_readl(1, CGU_SYS_DDR_SEL);
++
++	if (ddr_sel)
++		clk = ltq_get_system_clock() / 3;
++	else
++		clk = ltq_get_system_clock() / 2;
++
++	return clk;
++}
++
++unsigned long ltq_get_cpu_clock(void)
++{
++	u32 cpu_sel;
++	unsigned long clk;
++
++	cpu_sel = ltq_cgu_sys_readl(1, CGU_SYS_CPU_SEL);
++
++	if (cpu_sel)
++		clk = ltq_get_io_region_clock();
++	else
++		clk = ltq_get_system_clock();
++
++	return clk;
++}
++
++unsigned long ltq_get_bus_clock(void)
++{
++	u32 fpi_sel;
++	unsigned long clk;
++
++	fpi_sel = ltq_cgu_sys_readl(1, CGU_SYS_FPI_SEL);
++
++	if (fpi_sel)
++		clk = ltq_get_io_region_clock() / 2;
++	else
++		clk = ltq_get_io_region_clock();
++
++	return clk;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/cgu_init.S
+@@ -0,0 +1,105 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* CGU module register */
++#define CGU_PLL0_CFG			0x0004	/* PLL0 config */
++#define CGU_PLL1_CFG			0x0008	/* PLL1 config */
++#define CGU_SYS				0x0010	/* System clock */
++#define CGU_UPDATE			0x0014	/* Clock update control */
++
++/* Valid SYS.PPE_SEL values */
++#define CGU_SYS_PPESEL_SHIFT		7
++#define CGU_SYS_PPESEL_250_MHZ		(0x1 << CGU_SYS_PPESEL_SHIFT)
++
++/* Valid SYS.SYS_SEL values */
++#define CGU_SYS_SYSSEL_SHIFT		3
++#define CGU_SYS_SYSSEL_PLL0_333_MHZ	(0x0 << CGU_SYS_SYSSEL_SHIFT)
++#define CGU_SYS_SYSSEL_PLL1_393_MHZ	(0x2 << CGU_SYS_SYSSEL_SHIFT)
++
++/* Valid SYS.CPU_SEL values */
++#define CGU_SYS_CPUSEL_SHIFT		2
++#define CGU_SYS_CPUSEL_EQUAL_SYSCLK	(0x0 << CGU_SYS_CPUSEL_SHIFT)
++#define CGU_SYS_CPUSEL_EQUAL_DDRCLK	(0x1 << CGU_SYS_CPUSEL_SHIFT)
++
++/* Valid SYS.DDR_SEL values */
++#define CGU_SYS_DDRSEL_HALF_SYSCLK	0x0
++#define CGU_SYS_DDRSEL_THIRD_SYSCLK	0x1
++
++#define CGU_UPDATE_UPD			0x1
++
++#if (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_393_DDR_197)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL1_393_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_SYSCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_HALF_SYSCLK
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_197_DDR_197)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL1_393_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_DDRCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_HALF_SYSCLK
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_333_DDR_167)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL0_333_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_SYSCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_HALF_SYSCLK
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_167_DDR_167)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL0_333_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_DDRCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_HALF_SYSCLK
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_131_DDR_131)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL1_393_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_DDRCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_THIRD_SYSCLK
++#elif (CONFIG_SYS_CLOCK_MODE == LTQ_CLK_CPU_111_DDR_111)
++#define CGU_SYS_PPESEL_CONFIG		CGU_SYS_PPESEL_250_MHZ
++#define CGU_SYS_SYSSEL_CONFIG		CGU_SYS_SYSSEL_PLL0_333_MHZ
++#define CGU_SYS_CPUSEL_CONFIG		CGU_SYS_CPUSEL_EQUAL_DDRCLK
++#define CGU_SYS_DDRSEL_CONFIG		CGU_SYS_DDRSEL_THIRD_SYSCLK
++#else
++#error "Invalid system clock configuration!"
++#endif
++
++/* Build register values */
++#define CGU_SYS_VALUE		(CGU_SYS_PPESEL_CONFIG | \
++				CGU_SYS_SYSSEL_CONFIG | \
++				CGU_SYS_CPUSEL_CONFIG | \
++				CGU_SYS_DDRSEL_CONFIG)
++
++	.set noreorder
++
++LEAF(ltq_cgu_init)
++	/* Load current CGU register value */
++	li	t0, (LTQ_CGU_BASE | KSEG1)
++	lw	t1, CGU_SYS(t0)
++
++	/* Load target CGU register values */
++	li	t2, CGU_SYS_VALUE
++
++	/* Only update registers if values differ */
++	beq	t1, t2, finished
++	 nop
++
++	/* Store target register values */
++	sw	t2, CGU_SYS(t0)
++
++	/* Trigger CGU update */
++	li	t1, CGU_UPDATE_UPD
++	sw	t1, CGU_UPDATE(t0)
++
++finished:
++	jr	ra
++	 nop
++
++	END(ltq_cgu_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/chipid.c
+@@ -0,0 +1,60 @@
++/*
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_CHIPID_VERSION_SHIFT	28
++#define LTQ_CHIPID_VERSION_MASK		(0xF << LTQ_CHIPID_VERSION_SHIFT)
++#define LTQ_CHIPID_PNUM_SHIFT		12
++#define LTQ_CHIPID_PNUM_MASK		(0xFFFF << LTQ_CHIPID_PNUM_SHIFT)
++
++struct ltq_chipid_regs {
++	u32	manid;		/* Manufacturer identification */
++	u32	chipid;		/* Chip identification */
++};
++
++static struct ltq_chipid_regs *ltq_chipid_regs =
++	(struct ltq_chipid_regs *) CKSEG1ADDR(LTQ_CHIPID_BASE);
++
++unsigned int ltq_chip_version_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_VERSION_MASK) >> LTQ_CHIPID_VERSION_SHIFT;
++}
++
++unsigned int ltq_chip_partnum_get(void)
++{
++	u32 chipid;
++
++	chipid = ltq_readl(&ltq_chipid_regs->chipid);
++
++	return (chipid & LTQ_CHIPID_PNUM_MASK) >> LTQ_CHIPID_PNUM_SHIFT;
++}
++
++const char *ltq_chip_partnum_str(void)
++{
++	enum ltq_chip_partnum partnum = ltq_chip_partnum_get();
++
++	switch (partnum) {
++	case LTQ_SOC_ARX188:
++		return "ARX188";
++	case LTQ_SOC_ARX186:
++	case LTQ_SOC_ARX186_2:
++		return "ARX186";
++	case LTQ_SOC_ARX182:
++		return "ARX182";
++	default:
++		printf("Unknown partnum: %x\n", partnum);
++	}
++
++	return "";
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/config.mk
+@@ -0,0 +1,30 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PF_CPPFLAGS_XRX := $(call cc-option,-mtune=34kc,)
++PLATFORM_CPPFLAGS += $(PF_CPPFLAGS_XRX)
++
++ifdef CONFIG_SPL_BUILD
++PF_ABICALLS		:= -mno-abicalls
++PF_PIC			:= -fno-pic
++PF_PIE			:=
++USE_PRIVATE_LIBGCC	:= yes
++endif
++
++LIBS-y += $(CPUDIR)/lantiq-common/liblantiq-common.o
++
++ifndef CONFIG_SPL_BUILD
++ifdef CONFIG_SYS_BOOT_SFSPL
++ALL-y += $(obj)u-boot.ltq.sfspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.sfspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.sfspl
++endif
++ifdef CONFIG_SYS_BOOT_NORSPL
++ALL-y += $(obj)u-boot.ltq.norspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
++endif
++endif
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/ebu.c
+@@ -0,0 +1,111 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++#define EBU_ADDRSEL_MASK(mask)		((mask & 0xf) << 4)
++#define EBU_ADDRSEL_REGEN		(1 << 0)
++
++#define EBU_CON_WRDIS			(1 << 31)
++#define EBU_CON_AGEN_DEMUX		(0x0 << 24)
++#define EBU_CON_AGEN_MUX		(0x2 << 24)
++#define EBU_CON_SETUP			(1 << 22)
++#define EBU_CON_WAIT_DIS		(0x0 << 20)
++#define EBU_CON_WAIT_ASYNC		(0x1 << 20)
++#define EBU_CON_WAIT_SYNC		(0x2 << 20)
++#define EBU_CON_WINV			(1 << 19)
++#define EBU_CON_PW_8BIT			(0x0 << 16)
++#define EBU_CON_PW_16BIT		(0x1 << 16)
++#define EBU_CON_ALEC(cycles)		((cycles & 0x3) << 14)
++#define EBU_CON_BCGEN_CS		(0x0 << 12)
++#define EBU_CON_BCGEN_INTEL		(0x1 << 12)
++#define EBU_CON_BCGEN_MOTOROLA		(0x2 << 12)
++#define EBU_CON_WAITWRC(cycles)		((cycles & 0x7) << 8)
++#define EBU_CON_WAITRDC(cycles)		((cycles & 0x3) << 6)
++#define EBU_CON_HOLDC(cycles)		((cycles & 0x3) << 4)
++#define EBU_CON_RECOVC(cycles)		((cycles & 0x3) << 2)
++#define EBU_CON_CMULT_1			0x0
++#define EBU_CON_CMULT_4			0x1
++#define EBU_CON_CMULT_8			0x2
++#define EBU_CON_CMULT_16		0x3
++
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define ebu_region0_enable		1
++#else
++#define ebu_region0_enable		0
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define ebu_region1_enable		1
++#else
++#define ebu_region1_enable		0
++#endif
++
++struct ltq_ebu_regs {
++	u32	clc;
++	u32	rsvd0;
++	u32	id;
++	u32	rsvd1;
++	u32	con;
++	u32	rsvd2[3];
++	u32	addr_sel_0;
++	u32	addr_sel_1;
++	u32	addr_sel_2;
++	u32	addr_sel_3;
++	u32	rsvd3[12];
++	u32	con_0;
++	u32	con_1;
++	u32	con_2;
++	u32	con_3;
++};
++
++static struct ltq_ebu_regs *ltq_ebu_regs =
++	(struct ltq_ebu_regs *) CKSEG1ADDR(LTQ_EBU_BASE);
++
++void ltq_ebu_init(void)
++{
++	if (ebu_region0_enable) {
++		/*
++		 * Map EBU region 0 to range 0x10000000-0x13ffffff and enable
++		 * region control. This supports up to 32 MiB NOR flash in
++		 * bank 0.
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_0, LTQ_EBU_REGION0_BASE |
++			EBU_ADDRSEL_MASK(1) | EBU_ADDRSEL_REGEN);
++
++		ltq_writel(&ltq_ebu_regs->con_0, EBU_CON_AGEN_DEMUX |
++			EBU_CON_WAIT_DIS | EBU_CON_PW_16BIT |
++			EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++			EBU_CON_WAITWRC(7) | EBU_CON_WAITRDC(3) |
++			EBU_CON_HOLDC(3) | EBU_CON_RECOVC(3) |
++			EBU_CON_CMULT_16);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_0, EBU_ADDRSEL_REGEN);
++
++	if (ebu_region1_enable) {
++		/*
++		 * Map EBU region 1 to range 0x14000000-0x13ffffff and enable
++		 * region control. This supports NAND flash in bank 1.
++		 */
++		ltq_writel(&ltq_ebu_regs->addr_sel_1, LTQ_EBU_REGION1_BASE |
++			EBU_ADDRSEL_MASK(3) | EBU_ADDRSEL_REGEN);
++
++		ltq_writel(&ltq_ebu_regs->con_1, EBU_CON_AGEN_DEMUX |
++			EBU_CON_SETUP | EBU_CON_WAIT_DIS | EBU_CON_PW_8BIT |
++			EBU_CON_ALEC(3) | EBU_CON_BCGEN_INTEL |
++			EBU_CON_WAITWRC(2) | EBU_CON_WAITRDC(2) |
++			EBU_CON_HOLDC(1) | EBU_CON_RECOVC(1) |
++			EBU_CON_CMULT_4);
++	} else
++		ltq_clrbits(&ltq_ebu_regs->addr_sel_1, EBU_ADDRSEL_REGEN);
++}
++
++void *flash_swap_addr(unsigned long addr)
++{
++	return (void *)(addr ^ 2);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/mem.c
+@@ -0,0 +1,30 @@
++/*
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/arch/soc.h>
++#include <asm/lantiq/io.h>
++
++static void *ltq_mc_ddr_base = (void *) CKSEG1ADDR(LTQ_MC_DDR_BASE);
++
++static inline u32 ltq_mc_dc_read(u32 index)
++{
++	return ltq_readl(ltq_mc_ddr_base + LTQ_MC_DDR_DC_OFFSET(index));
++}
++
++phys_size_t initdram(int board_type)
++{
++	u32 col, row, dc04, dc19, dc20;
++
++	dc04 = ltq_mc_dc_read(4);
++	dc19 = ltq_mc_dc_read(19);
++	dc20 = ltq_mc_dc_read(20);
++
++	row = (dc04 & 0xF) - ((dc19 & 0x700) >> 8);
++	col = ((dc04 & 0xF00) >> 8) - (dc20 & 0x7);
++
++	return (1 << (row + col)) * 4 * 2;
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/mem_init.S
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <config.h>
++#include <asm/asm.h>
++#include <asm/regdef.h>
++#include <asm/addrspace.h>
++#include <asm/arch/soc.h>
++
++/* Must be configured in BOARDDIR */
++#include <ddr_settings.h>
++
++#define LTQ_MC_GEN_ERRCAUSE		0x0010
++#define LTQ_MC_GEN_ERRADDR		0x0020
++#define LTQ_MC_GEN_CON			0x0060
++#define LTQ_MC_GEN_STAT			0x0070
++#define LTQ_MC_GEN_CON_SRAM_DDR_ENABLE	0xD
++#define LTQ_MC_GEN_STAT_DLCK_PWRON	0xC
++
++#define LTQ_MC_DDR_DC03_MC_START	0x100
++
++	/* Store given value in MC DDR CCRx register */
++	.macro dc_sw num, val
++	li	t2, \val
++	sw	t2, LTQ_MC_DDR_DC_OFFSET(\num)(t1)
++	.endm
++
++LEAF(ltq_mem_init)
++	/* Load MC General and MC DDR module base */
++	li	t0, (LTQ_MC_GEN_BASE | KSEG1)
++	li	t1, (LTQ_MC_DDR_BASE | KSEG1)
++
++	/* Clear access error log registers */
++	sw	zero, LTQ_MC_GEN_ERRCAUSE(t0)
++	sw	zero, LTQ_MC_GEN_ERRADDR(t0)
++
++	/* Enable DDR and SRAM module in memory controller */
++	li	t2, LTQ_MC_GEN_CON_SRAM_DDR_ENABLE
++	sw	t2, LTQ_MC_GEN_CON(t0)
++
++	/* Clear start bit of DDR memory controller */
++	sw	zero, LTQ_MC_DDR_DC_OFFSET(3)(t1)
++
++	/* Init memory controller registers with values ddr_settings.h */
++	dc_sw	0, MC_DC00_VALUE
++	dc_sw	1, MC_DC01_VALUE
++	dc_sw	2, MC_DC02_VALUE
++	dc_sw	4, MC_DC04_VALUE
++	dc_sw	5, MC_DC05_VALUE
++	dc_sw	6, MC_DC06_VALUE
++	dc_sw	7, MC_DC07_VALUE
++	dc_sw	8, MC_DC08_VALUE
++	dc_sw	9, MC_DC09_VALUE
++
++	dc_sw	10, MC_DC10_VALUE
++	dc_sw	11, MC_DC11_VALUE
++	dc_sw	12, MC_DC12_VALUE
++	dc_sw	13, MC_DC13_VALUE
++	dc_sw	14, MC_DC14_VALUE
++	dc_sw	15, MC_DC15_VALUE
++	dc_sw	16, MC_DC16_VALUE
++	dc_sw	17, MC_DC17_VALUE
++	dc_sw	18, MC_DC18_VALUE
++	dc_sw	19, MC_DC19_VALUE
++
++	dc_sw	20, MC_DC20_VALUE
++	dc_sw	21, MC_DC21_VALUE
++	dc_sw	22, MC_DC22_VALUE
++	dc_sw	23, MC_DC23_VALUE
++	dc_sw	24, MC_DC24_VALUE
++	dc_sw	25, MC_DC25_VALUE
++	dc_sw	26, MC_DC26_VALUE
++	dc_sw	27, MC_DC27_VALUE
++	dc_sw	28, MC_DC28_VALUE
++	dc_sw	29, MC_DC29_VALUE
++
++	dc_sw	30, MC_DC30_VALUE
++	dc_sw	31, MC_DC31_VALUE
++	dc_sw	32, MC_DC32_VALUE
++	dc_sw	33, MC_DC33_VALUE
++	dc_sw	34, MC_DC34_VALUE
++	dc_sw	35, MC_DC35_VALUE
++	dc_sw	36, MC_DC36_VALUE
++	dc_sw	37, MC_DC37_VALUE
++	dc_sw	38, MC_DC38_VALUE
++	dc_sw	39, MC_DC39_VALUE
++
++	dc_sw	40, MC_DC40_VALUE
++	dc_sw	41, MC_DC41_VALUE
++	dc_sw	42, MC_DC42_VALUE
++	dc_sw	43, MC_DC43_VALUE
++	dc_sw	44, MC_DC44_VALUE
++	dc_sw	45, MC_DC45_VALUE
++	dc_sw	46, MC_DC46_VALUE
++
++	/* Set start bit of DDR memory controller */
++	li	t2, LTQ_MC_DDR_DC03_MC_START
++	sw	t2, LTQ_MC_DDR_DC_OFFSET(3)(t1)
++
++	/* Wait until DLL has locked and core is ready for data transfers */
++wait_ready:
++	lw	t2, LTQ_MC_GEN_STAT(t0)
++	li	t3, LTQ_MC_GEN_STAT_DLCK_PWRON
++	and	t2, t3
++	bne	t2, t3, wait_ready
++
++finished:
++	jr	ra
++
++	END(ltq_mem_init)
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/pmu.c
+@@ -0,0 +1,120 @@
++/*
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/pm.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_PMU_PWDCR_RESERVED		0xE00C200C
++
++#define LTQ_PMU_PWDCR_SWITCH		(1 << 28)
++#define LTQ_PMU_PWDCR_USB1		(1 << 27)
++#define LTQ_PMU_PWDCR_USB1_PHY		(1 << 26)
++#define LTQ_PMU_PWDCR_TDM		(1 << 25)
++#define LTQ_PMU_PWDCR_DDR_MEM		(1 << 24)
++#define LTQ_PMU_PWDCR_PPE_DP		(1 << 23)
++#define LTQ_PMU_PWDCR_PPE_EMA		(1 << 22)
++#define LTQ_PMU_PWDCR_PPE_TC		(1 << 21)
++#define LTQ_PMU_PWDCR_DEU		(1 << 20)
++#define LTQ_PMU_PWDCR_UART1		(1 << 17)
++#define LTQ_PMU_PWDCR_SDIO		(1 << 16)
++#define LTQ_PMU_PWDCR_AHB		(1 << 15)
++#define LTQ_PMU_PWDCR_FPI0		(1 << 14)
++#define LTQ_PMU_PWDCR_GPTC		(1 << 12)
++#define LTQ_PMU_PWDCR_LEDC		(1 << 11)
++#define LTQ_PMU_PWDCR_EBU		(1 << 10)
++#define LTQ_PMU_PWDCR_DSL		(1 << 9)
++#define LTQ_PMU_PWDCR_SPI		(1 << 8)
++#define LTQ_PMU_PWDCR_UART0		(1 << 7)
++#define LTQ_PMU_PWDCR_USB		(1 << 6)
++#define LTQ_PMU_PWDCR_DMA		(1 << 5)
++#define LTQ_PMU_PWDCR_PCI		(1 << 4)
++#define LTQ_PMU_PWDCR_FPI1		(1 << 1)
++#define LTQ_PMU_PWDCR_USB0_PHY		(1 << 0)
++
++struct ltq_pmu_regs {
++	u32	rsvd0[7];
++	__be32	pwdcr;
++	__be32	sr;
++};
++
++static struct ltq_pmu_regs *ltq_pmu_regs =
++	(struct ltq_pmu_regs *) CKSEG1ADDR(LTQ_PMU_BASE);
++
++u32 ltq_pm_map(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_PM_CORE:
++		val = LTQ_PMU_PWDCR_DDR_MEM | LTQ_PMU_PWDCR_UART1 |
++			LTQ_PMU_PWDCR_FPI0 | LTQ_PMU_PWDCR_LEDC |
++			LTQ_PMU_PWDCR_EBU;
++		break;
++	case LTQ_PM_DMA:
++		val = LTQ_PMU_PWDCR_DMA;
++		break;
++	case LTQ_PM_ETH:
++		val = LTQ_PMU_PWDCR_SWITCH | LTQ_PMU_PWDCR_PPE_DP |
++			LTQ_PMU_PWDCR_PPE_EMA | LTQ_PMU_PWDCR_PPE_TC;
++		break;
++	case LTQ_PM_SPI:
++		val = LTQ_PMU_PWDCR_SPI;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_pm_enable(enum ltq_pm_modules module)
++{
++	const unsigned long timeout = 1000;
++	unsigned long timebase;
++	u32 sr, val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_pmu_regs->pwdcr, val);
++
++	timebase = get_timer(0);
++
++	do {
++		sr = ltq_readl(&ltq_pmu_regs->sr);
++		if (~sr & val)
++			return 0;
++	} while (get_timer(timebase) < timeout);
++
++	return 1;
++}
++
++int ltq_pm_disable(enum ltq_pm_modules module)
++{
++	u32 val;
++
++	val = ltq_pm_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_pmu_regs->pwdcr, val);
++
++	return 0;
++}
++
++void ltq_pmu_init(void)
++{
++	u32 set, clr;
++
++	clr = ltq_pm_map(LTQ_PM_CORE);
++	set = ~(LTQ_PMU_PWDCR_RESERVED | clr);
++
++	ltq_clrsetbits(&ltq_pmu_regs->pwdcr, clr, set);
++}
+--- /dev/null
++++ b/arch/mips/cpu/mips32/arx100/rcu.c
+@@ -0,0 +1,130 @@
++/*
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/soc.h>
++
++#define LTQ_RCU_RD_SRST		(1 << 30)	/* Global SW Reset */
++#define LTQ_RCU_RD_USB1		(1 << 28)	/* USB1 MAC and PHY */
++#define LTQ_RCU_RD_REG25_PD	(1 << 26)	/* Power down 2.5V regulator */
++#define LTQ_RCU_RD_PPE_ATM_TC	(1 << 22)	/* PPE ATM TC */
++#define LTQ_RCU_RD_ETHSW	(1 << 21)	/* Ethernet switch */
++#define LTQ_RCU_RD_DSP_DEN	(1 << 20)	/* Enable DSP JTAG */
++#define LTQ_RCU_RD_TDM		(1 << 19)	/* TDM module interface */
++#define LTQ_RCU_RD_MC		(1 << 14)	/* Memory Controller */
++#define LTQ_RCU_RD_PCI		(1 << 13)	/* PCI core */
++#define LTQ_RCU_RD_SDIO		(1 << 10)	/* SDIO core */
++#define LTQ_RCU_RD_DMA		(1 << 9)	/* DMA core */
++#define LTQ_RCU_RD_PPE		(1 << 8)	/* PPE core */
++#define LTQ_RCU_RD_ARC_DFE	(1 << 7)	/* ARC/DFE core */
++#define LTQ_RCU_RD_AHB		(1 << 6)	/* AHB bus */
++#define LTQ_RCU_RD_USB		(1 << 4)	/* USB and Phy core */
++#define LTQ_RCU_RD_FPI		(1 << 2)	/* FPI bus */
++#define LTQ_RCU_RD_CPU0		(1 << 1)	/* CPU0 subsystem */
++#define LTQ_RCU_RD_HRST		(1 << 0)	/* HW reset via HRST pin */
++
++#define LTQ_RCU_STAT_BOOT_SHIFT		17
++#define LTQ_RCU_STAT_BOOT_MASK		(0xf << LTQ_RCU_STAT_BOOT_SHIFT)
++
++struct ltq_rcu_regs {
++	u32	rsvd0[4];
++	__be32	req;		/* Reset request */
++	__be32	stat;		/* Reset status */
++	__be32	usb0_cfg;	/* USB0 config */
++	u32	rsvd1[2];
++	__be32	pci_rdy;	/* PCI boot ready */
++	__be32	ppe_conf;	/* PPE config */
++	u32	rsvd2;
++	__be32	usb1_cfg;	/* USB1 config */
++};
++
++static struct ltq_rcu_regs *ltq_rcu_regs =
++	(struct ltq_rcu_regs *) CKSEG1ADDR(LTQ_RCU_BASE);
++
++u32 ltq_reset_map(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	switch (module) {
++	case LTQ_RESET_CORE:
++	case LTQ_RESET_SOFT:
++		val = LTQ_RCU_RD_SRST | LTQ_RCU_RD_CPU0;
++		break;
++	case LTQ_RESET_DMA:
++		val = LTQ_RCU_RD_DMA;
++		break;
++	case LTQ_RESET_ETH:
++		val = LTQ_RCU_RD_PPE | LTQ_RCU_RD_ETHSW;
++		break;
++	case LTQ_RESET_HARD:
++		val = LTQ_RCU_RD_HRST;
++		break;
++	default:
++		val = 0;
++		break;
++	}
++
++	return val;
++}
++
++int ltq_reset_activate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_setbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++int ltq_reset_deactivate(enum ltq_reset_modules module)
++{
++	u32 val;
++
++	val = ltq_reset_map(module);
++	if (unlikely(!val))
++		return 1;
++
++	ltq_clrbits(&ltq_rcu_regs->req, val);
++
++	return 0;
++}
++
++enum ltq_boot_select ltq_boot_select(void)
++{
++	u32 stat;
++	unsigned int bootstrap;
++
++	stat = ltq_readl(&ltq_rcu_regs->stat);
++	bootstrap = (stat & LTQ_RCU_STAT_BOOT_MASK) >> LTQ_RCU_STAT_BOOT_SHIFT;
++
++	switch (bootstrap) {
++	case 0:
++		return BOOT_NOR_NO_BOOTROM;
++	case 1:
++		return BOOT_RGMII0;
++	case 2:
++		return BOOT_NOR;
++	case 3:
++		return BOOT_MII0;
++	case 5:
++		return BOOT_RMII0;
++	case 6:
++		return BOOT_PCI;
++	case 8:
++		return BOOT_UART;
++	case 10:
++		return BOOT_SPI;
++	default:
++		return BOOT_UNKNOWN;
++	}
++}
+--- a/arch/mips/cpu/mips32/lantiq-common/cpu.c
++++ b/arch/mips/cpu/mips32/lantiq-common/cpu.c
+@@ -20,6 +20,7 @@ static const char ltq_bootsel_strings[][
+ 	"PCI",
+ 	"MII0",
+ 	"RMII0",
++	"RGMII0",
+ 	"RGMII1",
+ 	"unknown",
+ };
+--- a/arch/mips/cpu/mips32/lantiq-common/start.S
++++ b/arch/mips/cpu/mips32/lantiq-common/start.S
+@@ -64,6 +64,11 @@
+ #define STATUS_LANTIQ		(STATUS_MIPS24K | STATUS_MIPS32_64)
+ #endif
+ 
++#ifdef CONFIG_SOC_XWAY_ARX100
++#define CONFIG0_LANTIQ		(CONFIG0_MIPS34K | CONFIG0_MIPS32_64)
++#define STATUS_LANTIQ		(STATUS_MIPS34K | STATUS_MIPS32_64)
++#endif
++
+ #ifdef CONFIG_SOC_XWAY_VRX200
+ #define CONFIG0_LANTIQ		(CONFIG0_MIPS34K | CONFIG0_MIPS32_64)
+ #define STATUS_LANTIQ		(STATUS_MIPS34K | STATUS_MIPS32_64)
+--- /dev/null
++++ b/arch/mips/include/asm/arch-arx100/config.h
+@@ -0,0 +1,176 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ *
++ * Common board configuration for Lantiq XWAY ARX100 family
++ *
++ * Use following defines in your board config to enable specific features
++ * and drivers for this SoC:
++ *
++ * CONFIG_LTQ_SUPPORT_UART
++ * - support the Danube ASC/UART interface and console
++ *
++ * CONFIG_LTQ_SUPPORT_NOR_FLASH
++ * - support a parallel NOR flash via the CFI interface in flash bank 0
++ *
++ * CONFIG_LTQ_SUPPORT_ETHERNET
++ * - support the Danube ETOP and MAC interface
++ *
++ * CONFIG_LTQ_SUPPORT_SPI_FLASH
++ * - support the Danube SPI interface and serial flash drivers
++ * - specific SPI flash drivers must be configured separately
++ */
++
++#ifndef __ARX100_CONFIG_H__
++#define __ARX100_CONFIG_H__
++
++/* CPU and SoC type */
++#define CONFIG_SOC_LANTIQ
++#define CONFIG_SOC_XWAY_ARX100
++
++/* Cache configuration */
++#define CONFIG_SYS_MIPS_CACHE_MODE	CONF_CM_CACHABLE_NONCOHERENT
++#define CONFIG_SYS_DCACHE_SIZE		(16 * 1024)
++#define CONFIG_SYS_ICACHE_SIZE		(32 * 1024)
++#define CONFIG_SYS_CACHELINE_SIZE	32
++#define CONFIG_SYS_MIPS_CACHE_EXT_INIT
++
++/*
++ * Supported clock modes
++ * PLL0: rational PLL running at 500 MHz
++ * PLL1: fractional PLL running at 393.219 MHz
++ */
++#define LTQ_CLK_CPU_393_DDR_197		0
++#define LTQ_CLK_CPU_197_DDR_197		1
++#define LTQ_CLK_CPU_333_DDR_167		2
++#define LTQ_CLK_CPU_167_DDR_167		3
++#define LTQ_CLK_CPU_131_DDR_131		4
++#define LTQ_CLK_CPU_111_DDR_111		5
++
++/* CPU speed */
++#define CONFIG_SYS_CLOCK_MODE		LTQ_CLK_CPU_333_DDR_167
++#define CONFIG_SYS_MIPS_TIMER_FREQ	166666667
++#define CONFIG_SYS_HZ			1000
++
++/* RAM */
++#define CONFIG_NR_DRAM_BANKS		1
++#define CONFIG_SYS_SDRAM_BASE		0x80000000
++#define CONFIG_SYS_SDRAM_BASE_UC	0xa0000000
++#define CONFIG_SYS_MEMTEST_START	0x81000000
++#define CONFIG_SYS_MEMTEST_END		0x82000000
++#define CONFIG_SYS_LOAD_ADDR		0x81000000
++#define CONFIG_SYS_LOAD_SIZE		(2 * 1024 * 1024)
++#define CONFIG_SYS_INIT_SP_OFFSET	(32 * 1024)
++
++/* SRAM */
++#define CONFIG_SYS_SRAM_BASE		0xBE1A0000
++#define CONFIG_SYS_SRAM_SIZE		0x10000
++
++/* ASC/UART driver and console */
++#define CONFIG_LANTIQ_SERIAL
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200 }
++
++/* GPIO */
++#define CONFIG_LANTIQ_GPIO
++#define CONFIG_LTQ_GPIO_MAX_BANKS	3
++#define CONFIG_LTQ_HAS_GPIO_BANK3
++
++/* FLASH driver */
++#if defined(CONFIG_LTQ_SUPPORT_NOR_FLASH)
++#define CONFIG_SYS_MAX_FLASH_BANKS	1
++#define CONFIG_SYS_MAX_FLASH_SECT	256
++#define CONFIG_SYS_FLASH_BASE		0xB0000000
++#define CONFIG_FLASH_16BIT
++#define CONFIG_SYS_FLASH_CFI
++#define CONFIG_FLASH_CFI_DRIVER
++#define CONFIG_SYS_FLASH_CFI_WIDTH	FLASH_CFI_16BIT
++#define CONFIG_SYS_FLASH_USE_BUFFER_WRITE
++#define CONFIG_FLASH_SHOW_PROGRESS	50
++#define CONFIG_SYS_FLASH_PROTECTION
++#define CONFIG_CFI_FLASH_USE_WEAK_ADDR_SWAP
++
++#define CONFIG_CMD_FLASH
++#else
++#define CONFIG_SYS_NO_FLASH
++#endif /* CONFIG_NOR_FLASH */
++
++#if defined(CONFIG_LTQ_SUPPORT_SPI_FLASH)
++#define CONFIG_LANTIQ_SPI
++#define CONFIG_SPI_FLASH
++
++#define CONFIG_CMD_SF
++#define CONFIG_CMD_SPI
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define CONFIG_NAND_LANTIQ
++#define CONFIG_SYS_MAX_NAND_DEVICE	1
++#define CONFIG_SYS_NAND_BASE		0xB4000000
++
++#define CONFIG_CMD_NAND
++#endif
++
++#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
++#define CONFIG_LANTIQ_DMA
++#define CONFIG_LANTIQ_ARX100_SWITCH
++
++#define CONFIG_PHYLIB
++#define CONFIG_MII
++#define CONFIG_UDP_CHECKSUM
++
++#define CONFIG_CMD_MII
++#define CONFIG_CMD_NET
++#endif
++
++#define CONFIG_SPL_MAX_SIZE		(32 * 1024)
++#define CONFIG_SPL_BSS_MAX_SIZE		(8 * 1024)
++#define CONFIG_SPL_STACK_MAX_SIZE	(8 * 1024)
++#define CONFIG_SPL_MALLOC_MAX_SIZE	(32 * 1024)
++#define CONFIG_SPL_STACK_BSS_IN_SRAM
++
++#if defined(CONFIG_SPL_STACK_BSS_IN_SRAM)
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SRAM_BASE + \
++					CONFIG_SPL_MAX_SIZE + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE	  	(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET)
++#else
++#define CONFIG_SPL_STACK_BASE		(CONFIG_SYS_SDRAM_BASE + \
++					CONFIG_SYS_INIT_SP_OFFSET + \
++					CONFIG_SPL_STACK_MAX_SIZE - 1)
++#define CONFIG_SPL_BSS_BASE		(CONFIG_SPL_STACK_BASE + 1)
++#define CONFIG_SPL_MALLOC_BASE		(CONFIG_SPL_BSS_BASE + \
++					CONFIG_SPL_BSS_MAX_SIZE)
++#endif
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define CONFIG_SYS_TEXT_BASE		0xA0100000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_SYS_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_SFSPL) || defined(CONFIG_SYS_BOOT_NANDSPL)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SPL_TEXT_BASE		0xBE1A0000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SPL_TEXT_BASE		0xB0000000
++#endif
++
++#if defined(CONFIG_SYS_BOOT_NOR) || defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_SYS_XWAY_EBU_BOOTCFG	0x688C688C
++#define CONFIG_XWAY_SWAP_BYTES
++#endif
++
++#define	CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
++
++#endif /* __ARX100_CONFIG_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-arx100/gpio.h
+@@ -0,0 +1,12 @@
++/*
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __ARX100_GPIO_H__
++#define __ARX100_GPIO_H__
++
++#include <asm/lantiq/gpio.h>
++
++#endif /* __ARX100_GPIO_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-arx100/nand.h
+@@ -0,0 +1,13 @@
++/*
++ * Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __VRX200_NAND_H__
++#define __VRX200_NAND_H__
++
++struct nand_chip;
++int ltq_nand_init(struct nand_chip *nand);
++
++#endif /* __VRX200_NAND_H__ */
+--- /dev/null
++++ b/arch/mips/include/asm/arch-arx100/soc.h
+@@ -0,0 +1,37 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2012 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __ARX100_SOC_H__
++#define __ARX100_SOC_H__
++
++#define LTQ_ASC0_BASE			0x1E100400
++#define LTQ_SPI_BASE			0x1E100800
++#define LTQ_GPIO_BASE			0x1E100B00
++#define LTQ_SSIO_BASE			0x1E100BB0
++#define LTQ_ASC1_BASE			0x1E100C00
++#define LTQ_DMA_BASE			0x1E104100
++
++#define LTQ_EBU_BASE			0x1E105300
++#define LTQ_EBU_REGION0_BASE		0x10000000
++#define LTQ_EBU_REGION1_BASE		0x14000000
++#define LTQ_EBU_NAND_BASE		(LTQ_EBU_BASE + 0xB0)
++
++#define LTQ_PPE_BASE			0x1E180000
++#define LTQ_SWITCH_BASE			0x1E108000
++
++#define LTQ_PMU_BASE			0x1F102000
++#define LTQ_CGU_BASE			0x1F103000
++#define LTQ_MPS_BASE			0x1F107000
++#define LTQ_CHIPID_BASE			(LTQ_MPS_BASE + 0x340)
++#define LTQ_RCU_BASE			0x1F203000
++
++#define LTQ_MC_GEN_BASE			0x1F800000
++#define LTQ_MC_SDR_BASE			0x1F800200
++#define LTQ_MC_DDR_BASE			0x1F801000
++#define LTQ_MC_DDR_DC_OFFSET(x)		(x * 0x10)
++
++#endif /* __ARX100_SOC_H__ */
+--- a/arch/mips/include/asm/lantiq/chipid.h
++++ b/arch/mips/include/asm/lantiq/chipid.h
+@@ -15,6 +15,10 @@ enum ltq_chip_partnum {
+ 	LTQ_SOC_DANUBE = 0x0129,
+ 	LTQ_SOC_DANUBE_S = 0x012B,
+ 	LTQ_SOC_TWINPASS = 0x012D,
++	LTQ_SOC_ARX188 = 0x016C,	/* ARX188 */
++	LTQ_SOC_ARX186 = 0x016D,	/* ARX186 v1.1 */
++	LTQ_SOC_ARX186_2 = 0x016E,	/* ARX186 v1.2 */
++	LTQ_SOC_ARX182 = 0x016F,	/* ARX182 */
+ 	LTQ_SOC_VRX288 = 0x01C0,	/* VRX288 v1.1 */
+ 	LTQ_SOC_VRX268 = 0x01C2,	/* VRX268 v1.1 */
+ 	LTQ_SOC_GRX288 = 0x01C9,	/* GRX288 v1.1 */
+@@ -36,6 +40,38 @@ static inline int ltq_soc_is_danube(void
+ {
+ 	return 0;
+ }
++#endif
++
++#ifdef CONFIG_SOC_XWAY_ARX100
++static inline int ltq_soc_is_arx100(void)
++{
++	return 1;
++}
++
++static inline int ltq_soc_is_arx100_v1(void)
++{
++	return ltq_chip_version_get() == 1;
++}
++
++static inline int ltq_soc_is_arx100_v2(void)
++{
++	return ltq_chip_version_get() == 2;
++}
++#else
++static inline int ltq_soc_is_arx100(void)
++{
++	return 0;
++}
++
++static inline int ltq_soc_is_arx100_v1(void)
++{
++	return 0;
++}
++
++static inline int ltq_soc_is_arx100_v2(void)
++{
++	return 0;
++}
+ #endif
+ 
+ #ifdef CONFIG_SOC_XWAY_VRX200
+--- a/arch/mips/include/asm/lantiq/clk.h
++++ b/arch/mips/include/asm/lantiq/clk.h
+@@ -13,9 +13,10 @@ enum ltq_clk {
+ 	CLOCK_83_MHZ = 83333333,
+ 	CLOCK_111_MHZ = 111111111,
+ 	CLOCK_125_MHZ = 125000000,
++	CLOCK_131_MHZ = 131073000,
+ 	CLOCK_133_MHZ = 133333333,
+ 	CLOCK_166_MHZ = 166666667,
+-	CLOCK_197_MHZ = 197000000,
++	CLOCK_197_MHZ = 196609500,
+ 	CLOCK_333_MHZ = 333333333,
+ 	CLOCK_393_MHZ = 393219000,
+ 	CLOCK_500_MHZ = 500000000,
+--- a/arch/mips/include/asm/lantiq/cpu.h
++++ b/arch/mips/include/asm/lantiq/cpu.h
+@@ -17,6 +17,7 @@ enum ltq_boot_select {
+ 	BOOT_PCI,
+ 	BOOT_MII0,
+ 	BOOT_RMII0,
++	BOOT_RGMII0,
+ 	BOOT_RGMII1,
+ 	BOOT_UNKNOWN,
+ };
diff --git a/package/boot/uboot-lantiq/patches/0016-net-add-driver-for-Lantiq-XWAY-ARX100-switch.patch b/package/boot/uboot-lantiq/patches/0016-net-add-driver-for-Lantiq-XWAY-ARX100-switch.patch
new file mode 100644
index 0000000..16e16d0
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0016-net-add-driver-for-Lantiq-XWAY-ARX100-switch.patch
@@ -0,0 +1,546 @@
+From 7288414298b34dcda1216fee1fe38d05ea0027a2 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 17 Dec 2012 23:32:39 +0100
+Subject: net: add driver for Lantiq XWAY ARX100 switch
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/arch/mips/include/asm/arch-arx100/config.h
++++ b/arch/mips/include/asm/arch-arx100/config.h
+@@ -10,17 +10,21 @@
+  * and drivers for this SoC:
+  *
+  * CONFIG_LTQ_SUPPORT_UART
+- * - support the Danube ASC/UART interface and console
++ * - support the ARX100 ASC/UART interface and console
+  *
+  * CONFIG_LTQ_SUPPORT_NOR_FLASH
+  * - support a parallel NOR flash via the CFI interface in flash bank 0
+  *
+  * CONFIG_LTQ_SUPPORT_ETHERNET
+- * - support the Danube ETOP and MAC interface
++ * - support the ARX100 ETOP and MAC interface
+  *
+  * CONFIG_LTQ_SUPPORT_SPI_FLASH
+- * - support the Danube SPI interface and serial flash drivers
++ * - support the ARX100 SPI interface and serial flash drivers
+  * - specific SPI flash drivers must be configured separately
++ *
++ * CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH
++ * - build a preloader that runs in the internal SRAM and loads
++ *   the U-Boot from SPI flash into RAM
+  */
+ 
+ #ifndef __ARX100_CONFIG_H__
+--- /dev/null
++++ b/arch/mips/include/asm/arch-arx100/switch.h
+@@ -0,0 +1,86 @@
++/*
++ *   Copyright (C) 2012-2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++ *
++ *   SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __ARX100_SWITCH_H__
++#define __ARX100_SWITCH_H__
++
++struct ar9_switch_regs {
++	__be32	ps;		/* Port status*/
++	__be32	p0_ctl;		/* Port 0 control */
++	__be32	p1_ctl;		/* Port 1 control */
++	__be32	p2_ctl;		/* Port 2 control */
++	__be32	p0_vlan;	/* Port 0 VLAN control */
++	__be32	p1_vlan;	/* Port 1 VLAN control */
++	__be32	p2_vlan;	/* Port 2 VLAN control */
++	__be32	p0_inctl;	/* Port 0 ingress control */
++	__be32	p1_inctl;	/* Port 1 ingress control */
++	__be32	p2_inctl;	/* Port 2 ingress control */
++	u32	rsvd0[16];
++	__be32	sw_gctl0;	/* Switch global control 0 */
++	__be32	sw_gctl1;	/* Switch global control 1 */
++	__be32	arp;		/* ARP/RARP */
++	__be32	strm_ctl;	/* Storm control */
++	__be32	rgmii_ctl;	/* RGMII/GMII port control */
++	u32	rsvd1[4];
++	__be32	pmac_hd_ctl;	/* PMAC header control */
++	u32	rsvd2[15];
++	__be32	mdio_ctrl;	/* MDIO indirect access control */
++	__be32	mdio_data;	/* MDIO indirect read data */
++};
++
++#define BUILD_CHECK_AR9_REG(name, offset)	\
++	BUILD_BUG_ON(offsetof(struct ar9_switch_regs, name) != (offset))
++
++static inline void build_check_ar9_registers(void)
++{
++	BUILD_CHECK_AR9_REG(sw_gctl0, 0x68);
++	BUILD_CHECK_AR9_REG(rgmii_ctl, 0x78);
++	BUILD_CHECK_AR9_REG(pmac_hd_ctl, 0x8c);
++	BUILD_CHECK_AR9_REG(mdio_ctrl, 0xcc);
++	BUILD_CHECK_AR9_REG(mdio_data, 0xd0);
++}
++
++#define P0_CTL_FLP		(1 << 18)
++#define P0_CTL_FLD		(1 << 17)
++
++#define SW_GCTL0_SE		(1 << 31)
++
++#define RGMII_CTL_P1_SHIFT	10
++#define RGMII_CTL_P1_MASK	(0x3FF << RGMII_CTL_P1_SHIFT)
++#define RGMII_CTL_P0_MASK	0x3FF
++#define RGMII_CTL_P0IS_SHIFT	8
++#define RGMII_CTL_P0IS_RGMII	(0x0 << RGMII_CTL_P0IS_SHIFT)
++#define RGMII_CTL_P0IS_MII	(0x1 << RGMII_CTL_P0IS_SHIFT)
++#define RGMII_CTL_P0IS_REVMII	(0x2 << RGMII_CTL_P0IS_SHIFT)
++#define RGMII_CTL_P0IS_RMII	(0x3 << RGMII_CTL_P0IS_SHIFT)
++#define RGMII_CTL_P0RDLY_SHIFT	6
++#define RGMII_CTL_P0RDLY_0_0	(0x0 << RGMII_CTL_P0RDLY_SHIFT)
++#define RGMII_CTL_P0RDLY_1_5	(0x1 << RGMII_CTL_P0RDLY_SHIFT)
++#define RGMII_CTL_P0RDLY_1_75	(0x2 << RGMII_CTL_P0RDLY_SHIFT)
++#define RGMII_CTL_P0RDLY_2_0	(0x3 << RGMII_CTL_P0RDLY_SHIFT)
++#define RGMII_CTL_P0TDLY_SHIFT	4
++#define RGMII_CTL_P0TDLY_0_0	(0x0 << RGMII_CTL_P0TDLY_SHIFT)
++#define RGMII_CTL_P0TDLY_1_5	(0x1 << RGMII_CTL_P0TDLY_SHIFT)
++#define RGMII_CTL_P0TDLY_1_75	(0x2 << RGMII_CTL_P0TDLY_SHIFT)
++#define RGMII_CTL_P0TDLY_2_0	(0x3 << RGMII_CTL_P0TDLY_SHIFT)
++#define RGMII_CTL_P0SPD_SHIFT	2
++#define RGMII_CTL_P0SPD_10	(0x0 << RGMII_CTL_P0SPD_SHIFT)
++#define RGMII_CTL_P0SPD_100	(0x1 << RGMII_CTL_P0SPD_SHIFT)
++#define RGMII_CTL_P0SPD_1000	(0x2 << RGMII_CTL_P0SPD_SHIFT)
++#define RGMII_CTL_P0DUP_FULL	(1 << 1)
++#define RGMII_CTL_P0FCE_EN	(1 << 0)
++
++#define PMAC_HD_CTL_AC		(1 << 18)
++
++#define MDIO_CTRL_WD_SHIFT	16
++#define MDIO_CTRL_MBUSY		(1 << 15)
++#define MDIO_CTRL_OP_READ	(1 << 11)
++#define MDIO_CTRL_OP_WRITE	(1 << 10)
++#define MDIO_CTRL_PHYAD_SHIFT	5
++#define MDIO_CTRL_PHYAD_MASK	(0x1f << MDIO_CTRL_PHYAD_SHIFT)
++#define MDIO_CTRL_REGAD_MASK	0x1f
++
++#endif /* __ARX100_SWITCH_H__ */
+--- a/drivers/net/Makefile
++++ b/drivers/net/Makefile
+@@ -38,6 +38,7 @@ COBJS-$(CONFIG_DRIVER_KS8695ETH) += ks86
+ COBJS-$(CONFIG_KS8851_MLL) += ks8851_mll.o
+ COBJS-$(CONFIG_LAN91C96) += lan91c96.o
+ COBJS-$(CONFIG_LANTIQ_DANUBE_ETOP) += lantiq_danube_etop.o
++COBJS-$(CONFIG_LANTIQ_ARX100_SWITCH) += lantiq_arx100_switch.o
+ COBJS-$(CONFIG_LANTIQ_VRX200_SWITCH) += lantiq_vrx200_switch.o
+ COBJS-$(CONFIG_MACB) += macb.o
+ COBJS-$(CONFIG_MCFFEC) += mcffec.o mcfmii.o
+--- /dev/null
++++ b/drivers/net/lantiq_arx100_switch.c
+@@ -0,0 +1,410 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++#define DEBUG
++#include <common.h>
++#include <malloc.h>
++#include <netdev.h>
++#include <miiphy.h>
++#include <switch.h>
++#include <linux/compiler.h>
++#include <asm/gpio.h>
++#include <asm/processor.h>
++#include <asm/lantiq/io.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/pm.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/dma.h>
++#include <asm/arch/soc.h>
++#include <asm/arch/switch.h>
++
++#define LTQ_ETH_RX_BUFFER_CNT		PKTBUFSRX
++#define LTQ_ETH_TX_BUFFER_CNT		8
++#define LTQ_ETH_RX_DATA_SIZE		PKTSIZE_ALIGN
++#define LTQ_ETH_IP_ALIGN		2
++
++#define LTQ_MDIO_DRV_NAME		"ltq-mdio"
++#define LTQ_ETH_DRV_NAME		"ltq-eth"
++
++#define LTQ_ETHSW_MAX_GMAC		2
++#define LTQ_ETHSW_PMAC			2
++
++struct ltq_eth_priv {
++	struct ltq_dma_device dma_dev;
++	struct mii_dev *bus;
++	struct eth_device *dev;
++	struct phy_device *phymap[LTQ_ETHSW_MAX_GMAC];
++	int rx_num;
++	int tx_num;
++};
++
++static struct ar9_switch_regs *switch_regs =
++	(struct ar9_switch_regs *) CKSEG1ADDR(LTQ_SWITCH_BASE);
++
++static int ltq_mdio_is_busy(void)
++{
++	u32 mdio_ctrl = ltq_readl(&switch_regs->mdio_ctrl);
++
++	return mdio_ctrl & MDIO_CTRL_MBUSY;
++}
++
++static void ltq_mdio_poll(void)
++{
++	while (ltq_mdio_is_busy())
++		cpu_relax();
++
++	__udelay(1000);
++}
++
++static int ltq_mdio_read(struct mii_dev *bus, int phyad, int devad,
++					int regad)
++{
++	u32 mdio_ctrl;
++	int retval;
++
++	mdio_ctrl = MDIO_CTRL_MBUSY | MDIO_CTRL_OP_READ |
++		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
++		(regad & MDIO_CTRL_REGAD_MASK);
++
++	ltq_mdio_poll();
++	ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
++	ltq_mdio_poll();
++	retval = ltq_readl(&switch_regs->mdio_data);
++	ltq_writel(&switch_regs->mdio_data, 0xFFFF);
++
++	debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, retval);
++
++	return retval;
++}
++
++static int ltq_mdio_write(struct mii_dev *bus, int phyad, int devad,
++					int regad, u16 val)
++{
++	u32 mdio_ctrl;
++
++	debug("%s: phyad %02x, regad %02x, val %02x\n", __func__, phyad, regad, val);
++
++	mdio_ctrl = (val << MDIO_CTRL_WD_SHIFT) | MDIO_CTRL_MBUSY |
++		MDIO_CTRL_OP_WRITE |
++		((phyad << MDIO_CTRL_PHYAD_SHIFT) & MDIO_CTRL_PHYAD_MASK) |
++		(regad & MDIO_CTRL_REGAD_MASK);
++
++	ltq_mdio_poll();
++	ltq_writel(&switch_regs->mdio_ctrl, mdio_ctrl);
++
++	return 0;
++}
++
++static void ltq_eth_gmac_update(struct phy_device *phydev, int num)
++{
++}
++
++static inline u8 *ltq_eth_rx_packet_align(int rx_num)
++{
++	u8 *packet = (u8 *) NetRxPackets[rx_num];
++
++	/*
++	 * IP header needs
++	 */
++	return packet + LTQ_ETH_IP_ALIGN;
++}
++
++static int ltq_eth_init(struct eth_device *dev, bd_t *bis)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	struct phy_device *phydev;
++	int i;
++
++	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
++		phydev = priv->phymap[i];
++		if (!phydev)
++			continue;
++
++		phy_startup(phydev);
++		ltq_eth_gmac_update(phydev, i);
++	}
++
++	for (i = 0; i < LTQ_ETH_RX_BUFFER_CNT; i++)
++		ltq_dma_rx_map(dma_dev, i, ltq_eth_rx_packet_align(i),
++			LTQ_ETH_RX_DATA_SIZE);
++
++	ltq_dma_enable(dma_dev);
++
++	priv->rx_num = 0;
++	priv->tx_num = 0;
++
++	return 0;
++}
++
++static void ltq_eth_halt(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	struct phy_device *phydev;
++	int i;
++
++	ltq_dma_reset(dma_dev);
++
++	for (i = 0; i < LTQ_ETHSW_MAX_GMAC; i++) {
++		phydev = priv->phymap[i];
++		if (!phydev)
++			continue;
++
++		phy_shutdown(phydev);
++		phydev->link = 0;
++		ltq_eth_gmac_update(phydev, i);
++	}
++}
++
++static int ltq_eth_send(struct eth_device *dev, void *packet, int length)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	int err;
++
++	err = ltq_dma_tx_map(dma_dev, priv->tx_num, packet, length, 10);
++	if (err) {
++		puts("NET: timeout on waiting for TX descriptor\n");
++		return -1;
++	}
++
++	priv->tx_num = (priv->tx_num + 1) % LTQ_ETH_TX_BUFFER_CNT;
++
++	return err;
++}
++
++static int ltq_eth_recv(struct eth_device *dev)
++{
++	struct ltq_eth_priv *priv = dev->priv;
++	struct ltq_dma_device *dma_dev = &priv->dma_dev;
++	u8 *packet;
++	int len;
++
++	if (!ltq_dma_rx_poll(dma_dev, priv->rx_num))
++		return 0;
++
++#if 0
++	printf("%s: rx_num %d\n", __func__, priv->rx_num);
++#endif
++
++	len = ltq_dma_rx_length(dma_dev, priv->rx_num);
++	packet = ltq_eth_rx_packet_align(priv->rx_num);
++
++#if 0
++	printf("%s: received: packet %p, len %u, rx_num %d\n",
++		__func__, packet, len, priv->rx_num);
++#endif
++
++	if (len)
++		NetReceive(packet, len);
++
++	ltq_dma_rx_map(dma_dev, priv->rx_num, packet,
++		LTQ_ETH_RX_DATA_SIZE);
++
++	priv->rx_num = (priv->rx_num + 1) % LTQ_ETH_RX_BUFFER_CNT;
++
++	return 0;
++}
++
++static void ltq_eth_pmac_init(void)
++{
++	/* Add CRC to packets from DMA to PMAC */
++	ltq_setbits(&switch_regs->pmac_hd_ctl, PMAC_HD_CTL_AC);
++
++	/* Force link up */
++	ltq_setbits(&switch_regs->p2_ctl, P0_CTL_FLP);
++}
++
++static void ltq_eth_hw_init(const struct ltq_eth_port_config *port)
++{
++	/* Power up ethernet subsystems */
++	ltq_pm_enable(LTQ_PM_ETH);
++
++	/* Enable switch core */
++	ltq_setbits(&switch_regs->sw_gctl0, SW_GCTL0_SE);
++
++	/* MII/MDIO */
++	gpio_set_altfunc(42, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* MII/MDC */
++	gpio_set_altfunc(43, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++
++	ltq_eth_pmac_init();
++}
++
++static void ltq_eth_port_config(struct ltq_eth_priv *priv,
++				const struct ltq_eth_port_config *port)
++{
++	struct phy_device *phydev;
++	struct switch_device *sw;
++	u32 rgmii_ctl;
++	unsigned int port_ctl, port_xmii = 0;
++
++	if (port->num > 1)
++		return;
++
++	rgmii_ctl = ltq_readl(&switch_regs->rgmii_ctl);
++
++	if (port->num == 1)
++		port_ctl = ltq_readl(&switch_regs->p1_ctl);
++	else
++		port_ctl = ltq_readl(&switch_regs->p0_ctl);
++
++	switch (port->phy_if) {
++	case PHY_INTERFACE_MODE_RGMII:
++		port_xmii = RGMII_CTL_P0IS_RGMII;
++
++		switch (port->rgmii_tx_delay) {
++		case 1:
++			port_xmii |= RGMII_CTL_P0TDLY_1_5;
++			break;
++		case 2:
++			port_xmii |= RGMII_CTL_P0TDLY_1_75;
++			break;
++		case 3:
++			port_xmii |= RGMII_CTL_P0TDLY_2_0;
++			break;
++		default:
++			break;
++		}
++
++		switch (port->rgmii_rx_delay) {
++		case 1:
++			port_xmii |= RGMII_CTL_P0RDLY_1_5;
++			break;
++		case 2:
++			port_xmii |= RGMII_CTL_P0RDLY_1_75;
++			break;
++		case 3:
++			port_xmii |= RGMII_CTL_P0RDLY_2_0;
++			break;
++		default:
++			break;
++		}
++
++		if (!(port->flags & LTQ_ETH_PORT_PHY)) {
++			port_xmii |= (RGMII_CTL_P0SPD_1000 |
++					RGMII_CTL_P0DUP_FULL);
++			port_ctl |= P0_CTL_FLP;
++		}
++
++		break;
++	case PHY_INTERFACE_MODE_MII:
++		port_xmii = RGMII_CTL_P0IS_MII;
++
++		if (!(port->flags & LTQ_ETH_PORT_PHY)) {
++			port_xmii |= (RGMII_CTL_P0SPD_100 |
++					RGMII_CTL_P0DUP_FULL);
++			port_ctl |= P0_CTL_FLP;
++		}
++
++		break;
++	default:
++		break;
++	}
++
++	if (port->num == 1) {
++		ltq_writel(&switch_regs->p1_ctl, port_ctl);
++
++		rgmii_ctl &= ~RGMII_CTL_P1_MASK;
++		rgmii_ctl |= (port_xmii << RGMII_CTL_P1_SHIFT);
++	} else {
++		ltq_writel(&switch_regs->p0_ctl, port_ctl);
++
++		rgmii_ctl &= ~RGMII_CTL_P0_MASK;
++		rgmii_ctl |= port_xmii;
++	}
++
++	ltq_writel(&switch_regs->rgmii_ctl, rgmii_ctl);
++
++	/* Connect to external switch */
++	if (port->flags & LTQ_ETH_PORT_SWITCH) {
++		sw = switch_connect(priv->bus);
++		if (sw)
++			switch_setup(sw);
++	}
++
++	/* Connect to internal/external PHYs */
++	if (port->flags & LTQ_ETH_PORT_PHY) {
++		phydev = phy_connect(priv->bus, port->phy_addr, priv->dev,
++					port->phy_if);
++		if (phydev)
++			phy_config(phydev);
++
++		priv->phymap[port->num] = phydev;
++	}
++}
++
++int ltq_eth_initialize(const struct ltq_eth_board_config *board_config)
++{
++	struct eth_device *dev;
++	struct mii_dev *bus;
++	struct ltq_eth_priv *priv;
++	struct ltq_dma_device *dma_dev;
++	const struct ltq_eth_port_config *port = &board_config->ports[0];
++	int i, ret;
++
++	build_check_ar9_registers();
++
++	ltq_dma_init();
++	ltq_eth_hw_init(port);
++
++	dev = calloc(1, sizeof(*dev));
++	if (!dev)
++		return -1;
++
++	priv = calloc(1, sizeof(*priv));
++	if (!priv)
++		return -1;
++
++	bus = mdio_alloc();
++	if (!bus)
++		return -1;
++
++	sprintf(dev->name, LTQ_ETH_DRV_NAME);
++	dev->priv = priv;
++	dev->init = ltq_eth_init;
++	dev->halt = ltq_eth_halt;
++	dev->recv = ltq_eth_recv;
++	dev->send = ltq_eth_send;
++
++	sprintf(bus->name, LTQ_MDIO_DRV_NAME);
++	bus->read = ltq_mdio_read;
++	bus->write = ltq_mdio_write;
++	bus->priv = priv;
++
++	dma_dev = &priv->dma_dev;
++	dma_dev->port = 0;
++	dma_dev->rx_chan.chan_no = 0;
++	dma_dev->rx_chan.class = 0;
++	dma_dev->rx_chan.num_desc = LTQ_ETH_RX_BUFFER_CNT;
++	dma_dev->rx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->rx_burst_len = LTQ_DMA_BURST_2WORDS;
++	dma_dev->tx_chan.chan_no = 1;
++	dma_dev->tx_chan.class = 0;
++	dma_dev->tx_chan.num_desc = LTQ_ETH_TX_BUFFER_CNT;
++	dma_dev->tx_endian_swap = LTQ_DMA_ENDIANESS_B3_B2_B1_B0;
++	dma_dev->tx_burst_len = LTQ_DMA_BURST_2WORDS;
++
++	priv->bus = bus;
++	priv->dev = dev;
++
++	ret = ltq_dma_register(dma_dev);
++	if (ret)
++		return ret;
++
++	ret = mdio_register(bus);
++	if (ret)
++		return ret;
++
++	ret = eth_register(dev);
++	if (ret)
++		return ret;
++
++	for (i = 0; i < board_config->num_ports; i++)
++		ltq_eth_port_config(priv, &board_config->ports[i]);
++
++	return 0;
++}
diff --git a/package/boot/uboot-lantiq/patches/0017-tools-add-some-helper-tools-for-Lantiq-SoCs.patch b/package/boot/uboot-lantiq/patches/0017-tools-add-some-helper-tools-for-Lantiq-SoCs.patch
new file mode 100644
index 0000000..ef6666a
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0017-tools-add-some-helper-tools-for-Lantiq-SoCs.patch
@@ -0,0 +1,477 @@
+From 1da5479d59b39d7931a2b0efabdfa314f6788b6d Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: tools: add some helper tools for Lantiq SoCs
+
+Signed-off-by: Luka Perkov Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/tools/gct.pl
+@@ -0,0 +1,155 @@
++#!/usr/bin/perl
++
++#use strict;
++#use Cwd;
++#use Env;
++
++my $aline;
++my $lineid;
++my $length;
++my $address;
++my @bytes;
++my $addstr;
++my $chsum=0;
++my $count=0;
++my $firstime=1;
++my $i;
++my $currentaddr;
++my $tmp;
++my $holder="";
++my $loadaddr;
++
++if(@ARGV < 2){
++	die("\n Syntax: perl gct.pl uart_ddr_settings.conf u-boot.srec u-boot.asc\n");
++}
++
++open(IN_UART_DDR_SETTINGS, "<$ARGV[0]") || die("failed to open uart_ddr_settings.conf\n");
++open(IN_UART_SREC, "<$ARGV[1]") || die("failed to open u-boot.srec\n");
++open(OUT_UBOOT_ASC, ">$ARGV[2]") || die("failed to open u-boot.asc\n");
++
++$i=0;
++while ($line = <IN_UART_DDR_SETTINGS>){
++	if($line=~/\w/){
++		if($line!~/[;#\*]/){
++			if($i eq 0){
++				printf OUT_UBOOT_ASC ("33333333");
++			}
++			chomp($line);
++			$line=~s/\t//;
++			@array=split(/ +/,$line);
++			$j=0;
++			while(@array[$j]!~/\w/){
++				$j=$j+1;
++			}
++			$addr=@array[$j];
++			$regval=@array[$j+1];
++			$addr=~s/0x//;
++			$regval=~s/0x//;
++			printf OUT_UBOOT_ASC ("%08x%08x",hex($addr),hex($regval));
++			$i=$i+1;
++			if($i eq 8){
++				$i=0;
++				printf OUT_UBOOT_ASC ("\n");
++			}
++		}
++	}
++}
++
++while($i lt 8 && $i gt 0){
++	printf OUT_UBOOT_ASC "00"x8;
++	$i=$i+1;
++}
++
++if($i eq 8){
++	printf OUT_UBOOT_ASC ("\n");
++}
++
++while($aline=<IN_UART_SREC>){
++	$aline=uc($aline);
++	chomp($aline);
++	next if(($aline=~/^S0/) || ($aline=~/^S7/));
++	($lineid, $length, $address, @bytes) = unpack"A2A2A8"."A2"x300, $aline;
++	$length = hex($length);
++	$address = hex($address);
++	$length -=5;
++	$i=0;
++
++	while($length>0){
++		if($firstime==1){
++			$addstr = sprintf("%x", $address);
++			$addstr = "0"x(8-length($addstr)).$addstr;
++			print OUT_UBOOT_ASC $addstr;
++			addchsum($addstr);
++			$firstime=0;
++			$currentaddr=$address;
++			$loadaddr = $addstr;
++		}
++		else{
++			if($count==64){
++				$addstr = sprintf("%x", $currentaddr);
++				$addstr = "0"x(8-length($addstr)).$addstr;
++				print OUT_UBOOT_ASC $addstr;
++				addchsum($addstr);
++				$count=0;
++			}
++#printf("*** %x != %x\n", $address, $currentaddr) if $address != $currentaddr;
++		}
++		if($currentaddr < $address) {
++			print OUT_UBOOT_ASC "00";
++			addchsum("00");
++			$count++;
++			$currentaddr++;
++		}
++		else {
++			while($count<64){
++				$bytes[$i]=~tr/ABCDEF/abcdef/;
++				print OUT_UBOOT_ASC "$bytes[$i]";
++				addchsum($bytes[$i]);
++				$i++;
++				$count++;
++				$currentaddr++;
++				$length--;
++				last if($length==0);
++			}
++		}
++		if($count==64){
++			print OUT_UBOOT_ASC "\n";
++		}
++	}
++}
++if($count != 64){
++	$tmp = "00";
++	for($i=0;$i<(64-$count);$i++){
++		print OUT_UBOOT_ASC "00";
++		addchsum($tmp);
++	}
++	print OUT_UBOOT_ASC "\n";
++}
++
++
++print OUT_UBOOT_ASC "11"x4;
++use integer;
++$chsum=$chsum & 0xffffffff;
++$chsum = sprintf("%X", $chsum);
++$chsum = "0"x(8-length($chsum)).$chsum;
++$chsum =~tr/ABCDEF/abcdef/;
++print OUT_UBOOT_ASC $chsum;
++print OUT_UBOOT_ASC "00"x60;
++print OUT_UBOOT_ASC "\n";
++
++print OUT_UBOOT_ASC "99"x4;
++print OUT_UBOOT_ASC $loadaddr;
++print OUT_UBOOT_ASC "00"x60;
++print OUT_UBOOT_ASC "\n";
++
++close OUT_UBOOT_ASC;
++
++sub addchsum{
++	my $cc=$_[0];
++	$holder=$holder.$cc;
++	if(length($holder)==8){
++		$holder = hex($holder);
++		$chsum+=$holder;
++		$holder="";
++	}
++}
+--- /dev/null
++++ b/tools/lantiq_bdi_conf.awk
+@@ -0,0 +1,116 @@
++#!/usr/bin/awk -f
++#
++# Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++# Copyright (C) 2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++#
++# Usage:
++#  awk -f lantiq_bdi_conf.awk -v soc=ar9 board=<name> PATH_TO_BOARD/ddr_settings.h
++#
++# Additional information:
++#  http://www.abatron.ch/fileadmin/user_upload/products/pdf/ManGDBR4K-3000.pdf
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++function print_header()
++{
++	print ";                                                                         "
++	print "; Copyright (C) 2013 Luka Perkov <luka@openwrt.org>                       "
++	print "; Copyright (C) 2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>    "
++	print ";                                                                         "
++	print "; This file has been generated with lantiq_bdi_conf.awk script.           "
++	print ";                                                                         "
++	print "; SPDX-License-Identifier:	GPL-2.0+                                 "
++	print ";                                                                         "
++	print ""
++}
++
++function init_ar9_prologue()
++{
++	print "WM32 0xBF103010 0x80		; CGU for CPU 333Mhz, DDR 167Mhz"
++	print "WM32 0xBF103014 0x01		; CGU update"
++	print "WM32 0xBF800010 0x0		; Clear error access log register"
++	print "WM32 0xBF800020 0x0		; Clear error access log register"
++	print "WM32 0xBF800060 0xD		; Enable FPI, DDR and SRAM module in memory controller"
++	print "WM32 0xBF801030 0x0		; Clear start bit of DDR memory controller"
++}
++
++function init_ar9_epilogue()
++{
++	print "WM32 0xBE105360 0x4001D7FF	; EBU setup"
++}
++
++function init_ddr1_epilogue()
++{
++	print "WM32 0xBF801030 0x100		; Set start bit of DDR memory controller"
++}
++
++function ar9_target()
++{
++	print "CPUTYPE		M34K"
++	print "ENDIAN		BIG"
++	print "JTAGCLOCK	1"
++	print "BDIMODE		AGENT		; [ LOADONLY, AGENT ]"
++	print "RESET		JTAG		; [ NONE, JTAG, HARD ]"
++	print "POWERUP		100"
++	print "WAKEUP		100"
++	print "BREAKMODE	HARD		; [ SOFT, HARD ]"
++	print  "STEPMODE	SWBP		; [ JTAG, HWBP, SWBP ]"
++	print "VECTOR		CATCH"
++	print  "SCANSUCC	1 5"
++}
++
++function flash_p2601hnfx()
++{
++	print "CHIPTYPE	MIRRORX16"
++	print "CHIPSIZE	0x1000000"
++	print "BUSWIDTH	16"
++}
++
++BEGIN {
++	switch (soc) {
++	case "ar9":
++		reg_base = 0xbf801000
++		print_header()
++		print "[INIT]"
++		init_ar9_prologue()
++		break
++	default:
++		print "Invalid or no value for SoC specified!"
++		exit 1
++	}
++}
++
++/^#define/ {
++	/* DC03 contains MC enable bit and must not be set here */
++	if (tolower($2) != "mc_dc03_value")
++		printf("WM32 0x%x %s\n", reg_base, tolower($3))
++
++	reg_base += 0x10
++}
++
++END {
++	switch (soc) {
++	case "ar9":
++		init_ddr1_epilogue()
++		init_ar9_epilogue()
++		print ""
++		print "[TARGET]"
++		ar9_target()
++		print ""
++		print "[HOST]"
++		print "PROMPT		\"ar9> \""
++		print ""
++		break
++	default:
++	}
++
++	switch (board) {
++	case "p2601hnfx":
++		print "[FLASH]"
++		flash_p2601hnfx()
++		print ""
++		break
++	default:
++	}
++}
+--- /dev/null
++++ b/tools/lantiq_ram_extract_magic.awk
+@@ -0,0 +1,69 @@
++#
++# Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++#
++# Usage:
++# mips-openwrt-linux-objdump -EB -b binary -m mips:isa32r2 -D YOUR_IMAGE_DUMP | awk -f lantiq_ram_extract_magic.awk
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++BEGIN {
++	print "/*                                                                            "
++	print " * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>                     "
++	print " *                                                                            "
++	print " * This file has been generated with lantiq_ram_extract_magic.awk script.     "
++	print " *                                                                            "
++	print " * SPDX-License-Identifier:	GPL-2.0+                                     "
++	print " */                                                                           "
++	print ""
++
++	mc_dc_value=0
++	mc_dc_number=0
++	right_section=0
++	mc_dc_value_print=0
++	mc_dc_number_print=0
++}
++
++/t2,[0-9]+$/ {
++	if (right_section) {
++		split($4, tmp, ",")
++		mc_dc_value=sprintf("%X", tmp[2])
++		mc_dc_value_print=1
++	}
++}
++
++/t2,0x[0-9a-f]+$/ {
++	if (right_section) {
++		split($4, tmp, ",0x")
++		mc_dc_value=sprintf("%s", tmp[2])
++		mc_dc_value=toupper(mc_dc_value)
++		mc_dc_value_print=1
++	}
++}
++
++/t2,[0-9]+\(t1\)$/ {
++	if (right_section) {
++		split($4, tmp, ",")
++		split(tmp[2], tmp, "(")
++		mc_dc_number=tmp[1]/16
++		mc_dc_number_print=1
++	}
++}
++
++{
++	if (right_section && mc_dc_number_print && mc_dc_value_print) {
++		if (mc_dc_number < 10)
++			print "#define MC_DC0" mc_dc_number "_VALUE\t0x" mc_dc_value
++		else
++			print "#define MC_DC" mc_dc_number "_VALUE\t0x" mc_dc_value
++		mc_dc_value_print=0
++		mc_dc_number_print=0
++	}
++
++	if ($4 == "t1,t1,0x1000")
++		right_section=1
++
++
++	if ($4 == "t2,736(t1)")
++		right_section=0
++}
+--- /dev/null
++++ b/tools/lantiq_ram_init_uart.awk
+@@ -0,0 +1,117 @@
++#!/usr/bin/awk -f
++#
++# Copyright (C) 2011-2012 Luka Perkov <luka@openwrt.org>
++# Copyright (C) 2012 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++#
++# Usage:
++# awk -f lantiq_ram_init_uart.awk -v soc=<danube|ar9|vr9> PATH_TO_BOARD/ddr_settings.h
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++function print_header()
++{
++	print ";                                                                            "
++	print "; Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>                     "
++	print "; Copyright (C) 2012-2013 Daniel Schwierzeck <daniel.schwierzeck@gmail.com>  "
++	print ";                                                                            "
++	print "; This file has been generated with lantiq_ram_init_uart.awk script.         "
++	print ";                                                                            "
++	print "; SPDX-License-Identifier:	GPL-2.0+                                    "
++	print ""
++}
++
++function mc_danube_prologue()
++{
++	/* Clear access error log registers */
++	print "0xbf800010", "0x0"
++	print "0xbf800020", "0x0"
++
++	/* Enable DDR and SRAM module in memory controller */
++	print "0xbf800060", "0x5"
++
++	/* Clear start bit of DDR memory controller */
++	print "0xbf801030", "0x0"
++}
++
++function mc_ar9_prologue()
++{
++	/* Clear access error log registers */
++	print "0xbf800010", "0x0"
++	print "0xbf800020", "0x0"
++
++	/* Enable FPI, DDR and SRAM module in memory controller */
++	print "0xbf800060", "0xD"
++
++	/* Clear start bit of DDR memory controller */
++	print "0xbf801030", "0x0"
++}
++
++function mc_ddr1_epilogue()
++{
++	/* Set start bit of DDR memory controller */
++	print "0xbf801030", "0x100"
++}
++
++function mc_ddr2_prologue()
++{
++	/* Put memory controller in inactive mode */
++	print "0xbf401070", "0x0"
++}
++
++function mc_ddr2_epilogue(mc_ccr07_value)
++{
++	/* Put memory controller in active mode */
++	mc_ccr07_value = or(mc_ccr07_value, 0x100)
++	printf("0xbf401070 0x%x\n", mc_ccr07_value)
++}
++
++BEGIN {
++	switch (soc) {
++	case "danube":
++		reg_base = 0xbf801000
++		print_header()
++		mc_danube_prologue()
++		break
++	case "ar9":
++		reg_base = 0xbf801000
++		print_header()
++		mc_ar9_prologue()
++		break
++	case "vr9":
++		reg_base = 0xbf401000
++		print_header()
++		mc_ddr2_prologue()
++		break
++	default:
++		print "Invalid or no value for soc specified!"
++		exit 1
++	}
++
++	mc_ccr07_value = 0
++}
++
++/^#define/ {
++	/* CCR07 contains MC enable bit and must not be set here */
++	if (tolower($2) == "mc_ccr07_value")
++		mc_ccr07_value = strtonum($3)
++	if (tolower($2) == "mc_dc03_value")
++		/* CCR07 contains MC enable bit and must not be set here */
++	else
++		printf("0x%x %s\n", reg_base, tolower($3))
++
++	reg_base += 0x10
++}
++
++END {
++	switch (soc) {
++	case "danube":
++	case "ar9":
++		mc_ddr1_epilogue()
++		break
++	case "vr9":
++		mc_ddr2_epilogue(mc_ccr07_value)
++		break
++	default:
++	}
++}
diff --git a/package/boot/uboot-lantiq/patches/0018-tools-lantiq-add-NAND-SPL-support.patch b/package/boot/uboot-lantiq/patches/0018-tools-lantiq-add-NAND-SPL-support.patch
new file mode 100644
index 0000000..6d1b8dc
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0018-tools-lantiq-add-NAND-SPL-support.patch
@@ -0,0 +1,223 @@
+From 43b9a7c9b903302c56d0a1d292a146dbf4de8e49 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 12 Aug 2013 01:17:08 +0200
+Subject: tools: lantiq: add NAND SPL support
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/tools/ltq-boot-image.c
++++ b/tools/ltq-boot-image.c
+@@ -14,7 +14,8 @@
+ 
+ enum image_types {
+ 	IMAGE_NONE,
+-	IMAGE_SFSPL
++	IMAGE_SFSPL,
++	IMAGE_NANDSPL
+ };
+ 
+ /* Lantiq non-volatile bootstrap command IDs */
+@@ -43,6 +44,8 @@ enum nvb_cmd_flags {
+ struct args {
+ 	enum image_types type;
+ 	__u32		entry_addr;
++	off_t		uboot_offset;
++	unsigned int	page_size;
+ 	const char	*uboot_bin;
+ 	const char	*spl_bin;
+ 	const char	*out_bin;
+@@ -50,10 +53,11 @@ struct args {
+ 
+ static void usage_msg(const char *name)
+ {
+-	fprintf(stderr, "%s: [-h] -t type -e entry-addr -u uboot-bin [-s spl-bin] -o out-bin\n",
++	fprintf(stderr, "%s: [-h] -t type -e entry-addr [-x uboot-offset] [-p page-size] -u uboot-bin [-s spl-bin] -o out-bin\n",
+ 		name);
+ 	fprintf(stderr, " Image types:\n"
+-			"  sfspl  - SPL + [compressed] U-Boot for SPI flash\n");
++			"  sfspl   - SPL + [compressed] U-Boot for SPI flash\n"
++			"  nandspl - SPL + [compressed] U-Boot for NAND flash\n");
+ }
+ 
+ static enum image_types parse_image_type(const char *type)
+@@ -64,6 +68,9 @@ static enum image_types parse_image_type
+ 	if (!strncmp(type, "sfspl", 6))
+ 		return IMAGE_SFSPL;
+ 
++	if (!strncmp(type, "nandspl", 6))
++		return IMAGE_NANDSPL;
++
+ 	return IMAGE_NONE;
+ }
+ 
+@@ -73,7 +80,7 @@ static int parse_args(int argc, char *ar
+ 
+ 	memset(arg, 0, sizeof(*arg));
+ 
+-	while ((opt = getopt(argc, argv, "ht:e:u:s:o:")) != -1) {
++	while ((opt = getopt(argc, argv, "ht:e:x:p:u:s:o:")) != -1) {
+ 		switch (opt) {
+ 		case 'h':
+ 			usage_msg(argv[0]);
+@@ -84,6 +91,12 @@ static int parse_args(int argc, char *ar
+ 		case 'e':
+ 			arg->entry_addr = strtoul(optarg, NULL, 16);
+ 			break;
++		case 'x':
++			arg->uboot_offset = strtoul(optarg, NULL, 16);
++			break;
++		case 'p':
++			arg->page_size = strtoul(optarg, NULL, 10);
++			break;
+ 		case 'u':
+ 			arg->uboot_bin = optarg;
+ 			break;
+@@ -114,11 +127,22 @@ static int parse_args(int argc, char *ar
+ 		goto parse_error;
+ 	}
+ 
+-	if (arg->type == IMAGE_SFSPL && !arg->spl_bin) {
++	if ((arg->type == IMAGE_SFSPL || arg->type == IMAGE_NANDSPL) &&
++		!arg->spl_bin) {
+ 		fprintf(stderr, "Missing SPL binary\n");
+ 		goto parse_error;
+ 	}
+ 
++	if (arg->type == IMAGE_NANDSPL && !arg->uboot_offset) {
++		fprintf(stderr, "Missing U-Boot offset\n");
++		goto parse_error;
++	}
++
++	if (arg->type == IMAGE_NANDSPL && !arg->page_size) {
++		fprintf(stderr, "Missing NAND page size\n");
++		goto parse_error;
++	}
++
+ 	return 0;
+ 
+ parse_error:
+@@ -174,6 +198,19 @@ static int write_nvb_start_header(int fd
+ 	return write_header(fd, hdr, sizeof(hdr));
+ }
+ 
++#if 0
++static int write_nvb_regcfg_header(int fd, __u32 addr)
++{
++	__u32 hdr[2];
++
++	hdr[0] = build_nvb_command(NVB_CMD_REGCFG, NVB_FLAG_SDBG |
++					NVB_FLAG_DBG);
++	hdr[1] = cpu_to_be32(addr);
++
++	return write_header(fd, hdr, sizeof(hdr));
++}
++#endif
++
+ static int open_input_bin(const char *name, void **ptr, size_t *size)
+ {
+ 	struct stat sbuf;
+@@ -238,9 +275,37 @@ static int open_output_bin(const char *n
+ 	return fd;
+ }
+ 
+-static int create_sfspl(const struct args *arg)
++static int pad_to_offset(int fd, off_t offset)
+ {
+-	int out_fd, uboot_fd, spl_fd, ret;
++	off_t pos;
++	size_t size;
++	ssize_t n;
++	__u8 *buf;
++
++	pos = lseek(fd, 0, SEEK_CUR);
++	size = offset - pos;
++
++	buf = malloc(size);
++	if (!buf) {
++		fprintf(stderr, "Failed to malloc buffer\n");
++		return -1;
++	}
++
++	memset(buf, 0xff, size);
++	n = write(fd, buf, size);
++	free(buf);
++
++	if (n != size) {
++		fprintf(stderr, "Failed to write pad bytes\n");
++		return -1;
++	}
++
++	return 0;
++}
++
++static int create_spl_image(const struct args *arg)
++{
++	int out_fd, uboot_fd, spl_fd, ret = 0;
+ 	void *uboot_ptr, *spl_ptr;
+ 	size_t uboot_size, spl_size;
+ 
+@@ -256,9 +321,22 @@ static int create_sfspl(const struct arg
+ 	if (0 > uboot_fd)
+ 		goto err_uboot;
+ 
++#if 0
++	ret = write_nvb_regcfg_header(out_fd, 0);
++	if (ret)
++		goto err_write;
++#endif
++
+ 	ret = write_nvb_dwnld_header(out_fd, spl_size, arg->entry_addr);
+ 	if (ret)
+ 		goto err_write;
++#if 0
++	if (arg->page_size) {
++		ret = pad_to_offset(out_fd, arg->page_size);
++		if (ret)
++			goto err_write;
++	}
++#endif
+ 
+ 	ret = copy_bin(out_fd, spl_ptr, spl_size);
+ 	if (ret)
+@@ -268,16 +346,16 @@ static int create_sfspl(const struct arg
+ 	if (ret)
+ 		goto err_write;
+ 
++	if (arg->uboot_offset) {
++		ret = pad_to_offset(out_fd, arg->uboot_offset);
++		if (ret)
++			goto err_write;
++	}
++
+ 	ret = copy_bin(out_fd, uboot_ptr, uboot_size);
+ 	if (ret)
+ 		goto err_write;
+ 
+-	close_input_bin(uboot_fd, uboot_ptr, uboot_size);
+-	close_input_bin(spl_fd, spl_ptr, spl_size);
+-	close(out_fd);
+-
+-	return 0;
+-
+ err_write:
+ 	close_input_bin(uboot_fd, uboot_ptr, uboot_size);
+ err_uboot:
+@@ -285,7 +363,7 @@ err_uboot:
+ err_spl:
+ 	close(out_fd);
+ err:
+-	return -1;
++	return ret;
+ }
+ 
+ int main(int argc, char *argv[])
+@@ -299,7 +377,8 @@ int main(int argc, char *argv[])
+ 
+ 	switch (arg.type) {
+ 	case IMAGE_SFSPL:
+-		ret = create_sfspl(&arg);
++	case IMAGE_NANDSPL:
++		ret = create_spl_image(&arg);
+ 		break;
+ 	default:
+ 		fprintf(stderr, "Image type not implemented\n");
diff --git a/package/boot/uboot-lantiq/patches/0019-Makefile-add-Lantiq-NAND-SPL-images.patch b/package/boot/uboot-lantiq/patches/0019-Makefile-add-Lantiq-NAND-SPL-images.patch
new file mode 100644
index 0000000..53df7ac
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0019-Makefile-add-Lantiq-NAND-SPL-images.patch
@@ -0,0 +1,46 @@
+From 2e01dc015bc8bb9ca45f369025c342ede990863e Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 12 Aug 2013 01:16:09 +0200
+Subject: Makefile: add Lantiq NAND SPL images
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/.gitignore
++++ b/.gitignore
+@@ -54,6 +54,9 @@
+ /u-boot.ltq.lzma.norspl
+ /u-boot.ltq.lzo.norspl
+ /u-boot.ltq.norspl
++/u-boot.ltq.lzma.nandspl
++/u-boot.ltq.lzo.nandspl
++/u-boot.ltq.nandspl
+ /u-boot.lzma.img
+ /u-boot.lzo.img
+ 
+--- a/Makefile
++++ b/Makefile
+@@ -599,6 +599,24 @@ $(obj)u-boot.ltq.lzma.sfspl: $(obj)u-boo
+ 		$(obj)tools/ltq-boot-image -t sfspl -e $(CONFIG_SPL_TEXT_BASE) \
+ 			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
+ 
++$(obj)u-boot.ltq.nandspl:	$(obj)u-boot.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t nandspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-x $(CONFIG_SYS_NAND_U_BOOT_OFFS) \
++			-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
++$(obj)u-boot.ltq.lzo.nandspl: $(obj)u-boot.lzo.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t nandspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-x $(CONFIG_SYS_NAND_U_BOOT_OFFS) \
++			-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
++$(obj)u-boot.ltq.lzma.nandspl: $(obj)u-boot.lzma.img $(obj)spl/u-boot-spl.bin
++		$(obj)tools/ltq-boot-image -t nandspl -e $(CONFIG_SPL_TEXT_BASE) \
++			-x $(CONFIG_SYS_NAND_U_BOOT_OFFS) \
++			-p $(CONFIG_SYS_NAND_PAGE_SIZE) \
++			-s $(obj)spl/u-boot-spl.bin -u $< -o $@
++
+ $(obj)u-boot.ltq.norspl: $(obj)u-boot.img $(obj)spl/u-boot-spl.bin
+ 	cat $(obj)spl/u-boot-spl.bin $< > $@
+ 
diff --git a/package/boot/uboot-lantiq/patches/0020-MIPS-lantiq-add-NAND-SPL-support.patch b/package/boot/uboot-lantiq/patches/0020-MIPS-lantiq-add-NAND-SPL-support.patch
new file mode 100644
index 0000000..8d9eca7
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0020-MIPS-lantiq-add-NAND-SPL-support.patch
@@ -0,0 +1,165 @@
+From e17398316e82d8b28217232b4fd6030c65138e74 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 12 Aug 2013 01:18:00 +0200
+Subject: MIPS: lantiq: add NAND SPL support
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/arch/mips/cpu/mips32/lantiq-common/spl.c
++++ b/arch/mips/cpu/mips32/lantiq-common/spl.c
+@@ -8,6 +8,7 @@
+ #include <image.h>
+ #include <version.h>
+ #include <spi_flash.h>
++#include <nand.h>
+ #include <linux/compiler.h>
+ #include <lzma/LzmaDec.h>
+ #include <linux/lzo.h>
+@@ -63,6 +64,18 @@
+ #define spl_boot_nor_flash	0
+ #endif
+ 
++#if defined(CONFIG_LTQ_SUPPORT_SPL_NAND_FLASH) && defined(CONFIG_SYS_BOOT_NANDSPL)
++#define spl_boot_nand_flash	1
++#else
++#define spl_boot_nand_flash	0
++#ifndef CONFIG_SYS_NAND_U_BOOT_OFFS
++#define CONFIG_SYS_NAND_U_BOOT_OFFS	0
++#endif
++#ifndef CONFIG_SYS_NAND_PAGE_SIZE
++#define CONFIG_SYS_NAND_PAGE_SIZE	0
++#endif
++#endif
++
+ #define spl_sync()	__asm__ __volatile__("sync");
+ 
+ struct spl_image {
+@@ -337,6 +350,58 @@ static int spl_load_nor_flash(struct spl
+ 	return ret;
+ }
+ 
++static int spl_load_nand_flash(struct spl_image *spl)
++{
++	image_header_t *hdr;
++	int ret;
++	unsigned long loadaddr;
++
++	/*
++	 * Image format:
++	 *
++	 * - 12 byte non-volatile bootstrap header
++	 * - SPL binary
++	 * - 12 byte non-volatile bootstrap header
++	 * - padding bytes up to CONFIG_SYS_NAND_U_BOOT_OFFS
++	 * - 64 byte U-Boot mkimage header
++	 * - U-Boot binary
++	 */
++	spl->data_addr = CONFIG_SYS_NAND_U_BOOT_OFFS;
++
++	spl_puts("SPL: initializing NAND flash\n");
++	nand_init();
++
++	spl_debug("SPL: reading image header at page offset %lx\n",
++		  spl->data_addr);
++
++	hdr = (image_header_t *) CONFIG_LOADADDR;
++	ret = nand_spl_load_image(spl->data_addr,
++				  CONFIG_SYS_NAND_PAGE_SIZE, hdr);
++	if (ret)
++		return ret;
++
++	spl_debug("SPL: checking image header at address %p\n", hdr);
++
++	ret = spl_parse_image(hdr, spl);
++	if (ret)
++		return ret;
++
++	if (spl_is_compressed(spl))
++		loadaddr = CONFIG_LOADADDR;
++	else
++		loadaddr = spl->entry_addr;
++
++	spl_puts("SPL: loading U-Boot to RAM\n");
++
++	ret = nand_spl_load_image(spl->data_addr, spl->data_size,
++				  (void *) loadaddr);
++
++	if (spl_is_compressed(spl))
++		ret = spl_uncompress(spl, loadaddr);
++
++	return ret;
++}
++
+ static int spl_load(struct spl_image *spl)
+ {
+ 	int ret;
+@@ -345,6 +410,8 @@ static int spl_load(struct spl_image *sp
+ 		ret = spl_load_spi_flash(spl);
+ 	else if (spl_boot_nor_flash)
+ 		ret = spl_load_nor_flash(spl);
++	else if (spl_boot_nand_flash)
++		ret = spl_load_nand_flash(spl);
+ 	else
+ 		ret = 1;
+ 
+--- a/arch/mips/include/asm/lantiq/config.h
++++ b/arch/mips/include/asm/lantiq/config.h
+@@ -40,6 +40,26 @@
+ #define CONFIG_SPI_SPL_SIMPLE
+ #endif
+ 
++/*
++ * NAND flash SPL
++ * BOOT CFG 06 only (address cycle based probing, 2KB or 512B page size)
++ */
++#if defined(CONFIG_LTQ_SUPPORT_SPL_NAND_FLASH) && defined(CONFIG_SYS_BOOT_NANDSPL)
++#define CONFIG_SPL
++#define CONFIG_SPL_NAND_SUPPORT
++#define CONFIG_SPL_NAND_DRIVERS
++#define CONFIG_SPL_NAND_SIMPLE
++#define CONFIG_SPL_NAND_ECC
++
++/* use software ECC until driver supports HW ECC */
++#define CONFIG_SPL_NAND_SOFTECC
++#define CONFIG_SYS_NAND_ECCSIZE		256
++#define CONFIG_SYS_NAND_ECCBYTES	3
++#define CONFIG_SYS_NAND_ECCPOS		{40, 41, 42, 43, 44, 45, 46, 47, \
++					48, 49, 50, 51, 52, 53, 54, 55, \
++					56, 57, 58, 59, 60, 61, 62, 63}
++#endif
++
+ #if defined(CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH) && defined(CONFIG_SYS_BOOT_NORSPL)
+ #define CONFIG_SPL
+ #endif
+@@ -148,6 +168,21 @@
+ #define CONFIG_ENV_LOAD_UBOOT_SF
+ #endif
+ 
++#if defined(CONFIG_LTQ_SUPPORT_NAND_FLASH)
++#define CONFIG_ENV_WRITE_UBOOT_NAND				\
++	"write-uboot-nand="					\
++	"nand erase 0 $filesize && "				\
++	"nand write $fileaddr 0 $filesize\0"
++
++#define CONFIG_ENV_LOAD_UBOOT_NAND						\
++	"load-uboot-nandspl=tftpboot u-boot.ltq.nandspl\0"			\
++	"load-uboot-nandspl-lzo=tftpboot u-boot.ltq.lzo.nandspl\0"		\
++	"load-uboot-nandspl-lzma=tftpboot u-boot.ltq.lzma.nandspl\0"
++#else
++#define CONFIG_ENV_WRITE_UBOOT_NAND
++#define CONFIG_ENV_LOAD_UBOOT_NAND
++#endif
++
+ #define CONFIG_ENV_LANTIQ_DEFAULTS	\
+ 	CONFIG_ENV_CONSOLEDEV		\
+ 	CONFIG_ENV_ADDCONSOLE		\
+@@ -159,6 +194,8 @@
+ 	CONFIG_ENV_LOAD_UBOOT_NOR	\
+ 	CONFIG_ENV_SF_PROBE		\
+ 	CONFIG_ENV_WRITE_UBOOT_SF	\
+-	CONFIG_ENV_LOAD_UBOOT_SF
++	CONFIG_ENV_LOAD_UBOOT_SF	\
++	CONFIG_ENV_WRITE_UBOOT_NAND	\
++	CONFIG_ENV_LOAD_UBOOT_NAND
+ 
+ #endif /* __LANTIQ_CONFIG_H__ */
diff --git a/package/boot/uboot-lantiq/patches/0021-MIPS-vrx200-add-NAND-SPL-support.patch b/package/boot/uboot-lantiq/patches/0021-MIPS-vrx200-add-NAND-SPL-support.patch
new file mode 100644
index 0000000..8296f2c
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0021-MIPS-vrx200-add-NAND-SPL-support.patch
@@ -0,0 +1,30 @@
+From 7361581a1baaec43058f5b9350c32c7ac4e58064 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Mon, 12 Aug 2013 00:11:16 +0200
+Subject: MIPS: vrx200: add NAND SPL support
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/arch/mips/cpu/mips32/vrx200/config.mk
++++ b/arch/mips/cpu/mips32/vrx200/config.mk
+@@ -27,4 +27,9 @@ ALL-y += $(obj)u-boot.ltq.norspl
+ ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.norspl
+ ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.norspl
+ endif
++ifdef CONFIG_SYS_BOOT_NANDSPL
++ALL-y += $(obj)u-boot.ltq.nandspl
++ALL-$(CONFIG_SPL_LZO_SUPPORT) += $(obj)u-boot.ltq.lzo.nandspl
++ALL-$(CONFIG_SPL_LZMA_SUPPORT) += $(obj)u-boot.ltq.lzma.nandspl
++endif
+ endif
+--- a/arch/mips/include/asm/arch-vrx200/config.h
++++ b/arch/mips/include/asm/arch-vrx200/config.h
+@@ -167,7 +167,7 @@
+ #define CONFIG_SYS_TEXT_BASE		0xB0000000
+ #endif
+ 
+-#if defined(CONFIG_SYS_BOOT_SFSPL)
++#if defined(CONFIG_SYS_BOOT_SFSPL) || defined(CONFIG_SYS_BOOT_NANDSPL)
+ #define CONFIG_SYS_TEXT_BASE		0x80100000
+ #define CONFIG_SPL_TEXT_BASE		0xBE220000
+ #endif
diff --git a/package/boot/uboot-lantiq/patches/0022-MIPS-lantiq-add-default-openwrt-config.patch b/package/boot/uboot-lantiq/patches/0022-MIPS-lantiq-add-default-openwrt-config.patch
new file mode 100644
index 0000000..20bff44
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0022-MIPS-lantiq-add-default-openwrt-config.patch
@@ -0,0 +1,51 @@
+From 8f584936adad0fca8beece5f55eadcdcd02fad0a Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Sat, 17 Aug 2013 03:44:46 +0200
+Subject: MIPS: lantiq: add default openwrt config
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/include/configs/openwrt-lantiq-common.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __OPENWRT_LANTIQ_COMMON_H
++#define __OPENWRT_LANTIQ_COMMON_H
++
++/* Commands */
++#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
++#define CONFIG_CMD_PING
++#define CONFIG_CMD_TFTPPUT
++#endif
++
++/* Compression */
++#define CONFIG_LZMA
++
++/* Auto boot */
++#define CONFIG_BOOTDELAY	2
++
++/* Environment */
++#if !defined(CONFIG_SYS_BOOT_RAM)
++#define CONFIG_BOOTCOMMAND \
++	"bootm ${kernel_addr}"
++#endif
++
++/* Ethernet */
++#if defined(CONFIG_LTQ_SUPPORT_ETHERNET)
++#define CONFIG_ETHADDR		00:01:02:03:04:05
++#define CONFIG_SERVERIP		192.168.1.2
++#define CONFIG_IPADDR		192.168.1.1
++#endif
++
++/* Unnecessary */
++#undef CONFIG_BOOTM_NETBSD
++#undef CONFIG_BOOTM_PLAN9
++#undef CONFIG_BOOTM_RTEMS
++
++#endif /* __OPENWRT_LANTIQ_COMMON_H */
diff --git a/package/boot/uboot-lantiq/patches/0023-lzma-fixup.patch b/package/boot/uboot-lantiq/patches/0023-lzma-fixup.patch
new file mode 100644
index 0000000..7c15938
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0023-lzma-fixup.patch
@@ -0,0 +1,39 @@
+From: Antonios Vamporakis <ant@area128.com>
+Date: Tue, 31 Dec 2013 01:05:42 +0100
+Subject: [PATCH] lzma: fix buffer bound check error
+
+Variable uncompressedSize references the space available, while outSizeFull is
+the actual expected uncompressed size. Using the wrong value causes LzmaDecode
+to return SZ_ERROR_INPUT_EOF. Problem was introduced in commit afca294. While
+at it add additional debug message.
+
+Signed-off-by: Antonios Vamporakis <ant@area128.com>
+CC: Kees Cook <keescook@chromium.org>
+CC: Simon Glass <sjg@chromium.org>
+CC: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+CC: Luka Perkov <luka@openwrt.org>
+---
+ lib/lzma/LzmaTools.c | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+--- a/lib/lzma/LzmaTools.c
++++ b/lib/lzma/LzmaTools.c
+@@ -102,7 +102,7 @@ int lzmaBuffToBuffDecompress (unsigned c
+         return SZ_ERROR_OUTPUT_EOF;
+ 
+     /* Decompress */
+-    outProcessed = *uncompressedSize;
++    outProcessed = outSizeFull;
+ 
+     WATCHDOG_RESET();
+ 
+@@ -111,6 +111,9 @@ int lzmaBuffToBuffDecompress (unsigned c
+         inStream + LZMA_DATA_OFFSET, &compressedSize,
+         inStream, LZMA_PROPS_SIZE, LZMA_FINISH_END, &state, &g_Alloc);
+     *uncompressedSize = outProcessed;
++
++    debug("LZMA: Uncompresed ................ 0x%zx\n", outProcessed);
++
+     if (res != SZ_OK)  {
+         return res;
+     }
diff --git a/package/boot/uboot-lantiq/patches/0024-Makefile-prepare-u-boot-lantiq-v2013.10-openwrt4.patch b/package/boot/uboot-lantiq/patches/0024-Makefile-prepare-u-boot-lantiq-v2013.10-openwrt4.patch
new file mode 100644
index 0000000..1f89e54
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0024-Makefile-prepare-u-boot-lantiq-v2013.10-openwrt4.patch
@@ -0,0 +1,18 @@
+From 7e2f79bc40b572763a4a1ed69f63aa2eaa6df254 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sun, 20 Oct 2013 19:39:17 +0200
+Subject: Makefile: prepare u-boot-lantiq-v2013.10-openwrt4
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- a/Makefile
++++ b/Makefile
+@@ -8,7 +8,7 @@
+ VERSION = 2013
+ PATCHLEVEL = 10
+ SUBLEVEL =
+-EXTRAVERSION =
++EXTRAVERSION = -openwrt4
+ ifneq "$(SUBLEVEL)" ""
+ U_BOOT_VERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
+ else
diff --git a/package/boot/uboot-lantiq/patches/0025-arx100-cgu-fixes.patch b/package/boot/uboot-lantiq/patches/0025-arx100-cgu-fixes.patch
new file mode 100644
index 0000000..ff2f99c
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0025-arx100-cgu-fixes.patch
@@ -0,0 +1,148 @@
+From patchwork Tue Jan 20 11:28:45 2015
+Content-Type: text/plain; charset="utf-8"
+MIME-Version: 1.0
+Content-Transfer-Encoding: 7bit
+Subject: [OpenWrt-Devel] uboot-lantiq cgu settings for ramboot image
+From: Ben Mulvihill <ben.mulvihill@gmail.com>
+X-Patchwork-Id: 431024
+Message-Id: <1421753325.25187.58.camel@merveille.lan>
+To: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Cc: OpenWrt Development List <openwrt-devel@lists.openwrt.org>
+Date: Tue, 20 Jan 2015 12:28:45 +0100
+
+On Tue, 2015-01-20 at 00:39 +0100, Ben Mulvihill wrote:
+> On Mon, 2015-01-19 at 19:21 +0100, Ben Mulvihill wrote:
+> > On Mon, 2015-01-19 at 16:47 +0100, Daniel Schwierzeck wrote:
+> > > 2015-01-19 15:44 GMT+01:00 Ben Mulvihill <ben.mulvihill@gmail.com>:
+> > > > On Mon, 2015-01-19 at 11:51 +0000, Conor O'Gorman wrote:
+> > > >> On 19/01/15 10:46, Ben Mulvihill wrote:
+> > > >> > Hello,
+> > > >> >
+> > > >> > I am trying to build uboot-lantiq for the BT Home Hub 3A (lantiq
+> > > >> > ar9), and am wondering where to initialise the cgu, in the case
+> > > >> > of a ramboot image for uart booting. Normally the cgu is initialised
+> > > >> > in lowlevel_init, but that code is bypassed in ramboot images. The
+> > > >> > result is that the board boots with the wrong cgu settings, which
+> > > >> > sends the console haywire. So far I have tried two solutions:
+> > > >>
+> > > >> Another option is to try and not change anything. The console is already
+> > > >> configured and running. The ram does need config.
+> > > >>
+> > > >> I was used to seeing the ramboot version running at half clock speed, at
+> > > >> least on danube, previous to ar9.
+> > > >>
+> > > >> Conor
+> > > >
+> > > > Hi Conor,
+> > > >
+> > > > Thanks for the reply. But with the latest uboot-lantiq, not changing
+> > > > anything means that I don't get a usable console. With an older
+> > > > version I do at least get a uboot console, but no linux console when
+> > > > I boot openwrt. Correcting the cgu settings solves both problems.
+> > > >
+> > > 
+> > > could you try this?
+> > > 
+> > > diff --git a/arch/mips/cpu/mips32/arx100/cgu.c
+> > > b/arch/mips/cpu/mips32/arx100/cgu.c
+> > > index 6e71ee7..e0afbda 100644
+> > > --- a/arch/mips/cpu/mips32/arx100/cgu.c
+> > > +++ b/arch/mips/cpu/mips32/arx100/cgu.c
+> > > @@ -95,15 +95,5 @@ unsigned long ltq_get_cpu_clock(void)
+> > > 
+> > >  unsigned long ltq_get_bus_clock(void)
+> > >  {
+> > > -       u32 fpi_sel;
+> > > -       unsigned long clk;
+> > > -
+> > > -       fpi_sel = ltq_cgu_sys_readl(1, CGU_SYS_FPI_SEL);
+> > > -
+> > > -       if (fpi_sel)
+> > > -               clk = ltq_get_io_region_clock() / 2;
+> > > -       else
+> > > -               clk = ltq_get_io_region_clock();
+> > > -
+> > > -       return clk;
+> > > +       return ltq_get_io_region_clock();
+> > >  }
+> > > 
+> > > the UART driver calculates the baudrate from the FPI bus clock, but
+> > > FPI_SEL is not available on AR9. FPI bus clock is always the same as
+> > > DDR clock, Obviously a copy&paste error from VR9 code ;)
+> > > 
+> > 
+> > No, even with this patch, I still don't get a working console I'm
+> > afraid. If I don't set anything explicitly, the board comes up with
+> > CGU_SYS set to 0x05, ie CGU_SYS_SYSSEL_PLL0_333_MHZ |
+> > CGU_SYS_CPUSEL_EQUAL_DDRCLK | CGU_SYS_DDRSEL_THIRD_SYSCLK.
+> > Is this a valid combination without CGU_SYS_PPESEL_250_MHZ ?
+> > I don't understand what CGU_SYS_PPESEL_250_MHZ does?
+> > The "right setting", as set by the stock uboot, is 0x80.
+> 
+> P.S. There also seems to be a discrepancy between the uboot and
+> linux code. I take it from what you say above that fpi clock, ddr
+> clock and io region clock are all the same. Now if the least 
+> significant bit of CGU_SYS is set, then according to the uboot
+> code - function ltq_get_bus_clock() - their value is one
+> third of the system clock. But according to the linux code
+> - function ltq_ar9_fpi_hz() in arch/mips/lantiq/xway/clk.c -
+> their value in this case is equal to the system clock.
+> 
+> Or am I getting muddled? It's past my bedtime!
+> 
+> 
+
+Some of the bitshifting in arch/mips/cpu/mips32/arx100/cgu.c is 1
+out. A patch along these lines should fix it:
+
+--- a/arch/mips/cpu/mips32/arx100/cgu.c
++++ b/arch/mips/cpu/mips32/arx100/cgu.c
+@@ -10,12 +10,17 @@
+ #include <asm/lantiq/clk.h>
+ #include <asm/lantiq/io.h>
+ 
+-#define CGU_SYS_DDR_SEL		(1 << 0)
+-#define CGU_SYS_CPU_SEL		(1 << 2)
++#define CGU_SYS_DDR_SHIFT	0
++#define CGU_SYS_CPU_SHIFT	2
+ #define CGU_SYS_SYS_SHIFT	3
++#define CGU_SYS_FPI_SHIFT	6
++#define CGU_SYS_PPE_SHIFT	7
++
++#define CGU_SYS_DDR_MASK	(1 << CGU_SYS_DDR_SHIFT)
++#define CGU_SYS_CPU_MASK	(1 << CGU_SYS_CPU_SHIFT)
+ #define CGU_SYS_SYS_MASK	(0x3 << CGU_SYS_SYS_SHIFT)
+-#define CGU_SYS_FPI_SEL		(1 << 6)
+-#define CGU_SYS_PPE_SEL		(1 << 7)
++#define CGU_SYS_FPI_MASK	(1 << CGU_SYS_FPI_SHIFT)
++#define CGU_SYS_PPE_MASK	(1 << CGU_SYS_PPE_SHIFT)
+ 
+ struct ltq_cgu_regs {
+ 	u32	rsvd0;
+@@ -68,7 +73,7 @@ unsigned long ltq_get_io_region_clock(vo
+ 	u32 ddr_sel;
+ 	unsigned long clk;
+ 
+-	ddr_sel = ltq_cgu_sys_readl(1, CGU_SYS_DDR_SEL);
++	ddr_sel = ltq_cgu_sys_readl(CGU_SYS_DDR_MASK, CGU_SYS_DDR_SHIFT);
+ 
+ 	if (ddr_sel)
+ 		clk = ltq_get_system_clock() / 3;
+@@ -83,7 +88,7 @@ unsigned long ltq_get_cpu_clock(void)
+ 	u32 cpu_sel;
+ 	unsigned long clk;
+ 
+-	cpu_sel = ltq_cgu_sys_readl(1, CGU_SYS_CPU_SEL);
++	cpu_sel = ltq_cgu_sys_readl(CGU_SYS_CPU_MASK, CGU_SYS_CPU_SHIFT);
+ 
+ 	if (cpu_sel)
+ 		clk = ltq_get_io_region_clock();
+@@ -98,7 +103,7 @@ unsigned long ltq_get_bus_clock(void)
+ 	u32 fpi_sel;
+ 	unsigned long clk;
+ 
+-	fpi_sel = ltq_cgu_sys_readl(1, CGU_SYS_FPI_SEL);
++	fpi_sel = ltq_cgu_sys_readl(CGU_SYS_FPI_MASK, CGU_SYS_FPI_SHIFT);
+ 
+ 	if (fpi_sel)
+ 		clk = ltq_get_io_region_clock() / 2;
diff --git a/package/boot/uboot-lantiq/patches/0026-no_extern_inline.patch b/package/boot/uboot-lantiq/patches/0026-no_extern_inline.patch
new file mode 100644
index 0000000..70216f2
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0026-no_extern_inline.patch
@@ -0,0 +1,97 @@
+From b11c5d1dc29e81326d1215011d19377737082aeb Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Wed, 1 Jul 2015 16:36:43 +0200
+Subject: [PATCH] MIPS: change 'extern inline' to 'static inline'
+
+The kernel changed it a long time ago. Also this is now broken
+on gcc-5.x.
+
+Reported-by: Andy Kennedy <andy.kennedy@adtran.com>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+---
+ arch/mips/include/asm/io.h     | 12 ++++++------
+ arch/mips/include/asm/system.h |  6 +++---
+ 2 files changed, 9 insertions(+), 9 deletions(-)
+
+--- a/arch/mips/include/asm/io.h
++++ b/arch/mips/include/asm/io.h
+@@ -118,7 +118,7 @@ static inline void set_io_port_base(unsi
+  * Change virtual addresses to physical addresses and vv.
+  * These are trivial on the 1:1 Linux/MIPS mapping
+  */
+-extern inline phys_addr_t virt_to_phys(volatile void * address)
++static inline phys_addr_t virt_to_phys(volatile void * address)
+ {
+ #ifndef CONFIG_64BIT
+ 	return CPHYSADDR(address);
+@@ -127,7 +127,7 @@ extern inline phys_addr_t virt_to_phys(v
+ #endif
+ }
+ 
+-extern inline void * phys_to_virt(unsigned long address)
++static inline void * phys_to_virt(unsigned long address)
+ {
+ #ifndef CONFIG_64BIT
+ 	return (void *)KSEG0ADDR(address);
+@@ -139,7 +139,7 @@ extern inline void * phys_to_virt(unsign
+ /*
+  * IO bus memory addresses are also 1:1 with the physical address
+  */
+-extern inline unsigned long virt_to_bus(volatile void * address)
++static inline unsigned long virt_to_bus(volatile void * address)
+ {
+ #ifndef CONFIG_64BIT
+ 	return CPHYSADDR(address);
+@@ -148,7 +148,7 @@ extern inline unsigned long virt_to_bus(
+ #endif
+ }
+ 
+-extern inline void * bus_to_virt(unsigned long address)
++static inline void * bus_to_virt(unsigned long address)
+ {
+ #ifndef CONFIG_64BIT
+ 	return (void *)KSEG0ADDR(address);
+@@ -166,12 +166,12 @@ extern unsigned long isa_slot_offset;
+ extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
+ 
+ #if 0
+-extern inline void *ioremap(unsigned long offset, unsigned long size)
++static inline void *ioremap(unsigned long offset, unsigned long size)
+ {
+ 	return __ioremap(offset, size, _CACHE_UNCACHED);
+ }
+ 
+-extern inline void *ioremap_nocache(unsigned long offset, unsigned long size)
++static inline void *ioremap_nocache(unsigned long offset, unsigned long size)
+ {
+ 	return __ioremap(offset, size, _CACHE_UNCACHED);
+ }
+--- a/arch/mips/include/asm/system.h
++++ b/arch/mips/include/asm/system.h
+@@ -23,7 +23,7 @@
+ #include <linux/kernel.h>
+ #endif
+ 
+-extern __inline__ void
++static __inline__ void
+ __sti(void)
+ {
+ 	__asm__ __volatile__(
+@@ -47,7 +47,7 @@ __sti(void)
+  * R4000/R4400 need three nops, the R4600 two nops and the R10000 needs
+  * no nops at all.
+  */
+-extern __inline__ void
++static __inline__ void
+ __cli(void)
+ {
+ 	__asm__ __volatile__(
+@@ -208,7 +208,7 @@ do { \
+  * For 32 and 64 bit operands we can take advantage of ll and sc.
+  * FIXME: This doesn't work for R3000 machines.
+  */
+-extern __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
++static __inline__ unsigned long xchg_u32(volatile int * m, unsigned long val)
+ {
+ #ifdef CONFIG_CPU_HAS_LLSC
+ 	unsigned long dummy;
diff --git a/package/boot/uboot-lantiq/patches/0027-no_weak_alias.patch b/package/boot/uboot-lantiq/patches/0027-no_weak_alias.patch
new file mode 100644
index 0000000..da519a5
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0027-no_weak_alias.patch
@@ -0,0 +1,26 @@
+From 3422299dc28fa8257677d03cc1253e3c9bf17e9f Mon Sep 17 00:00:00 2001
+From: Jeroen Hofstee <jeroen@myspectrum.nl>
+Date: Thu, 26 Jun 2014 20:18:31 +0200
+Subject: [PATCH] common: main.c: make show_boot_progress __weak
+
+This not only looks a bit better it also prevents a
+warning with W=1 (no previous prototype).
+
+Signed-off-by: Jeroen Hofstee <jeroen@myspectrum.nl>
+Acked-by: Simon Glass <sjg@chromium.org>
+---
+ common/main.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/common/main.c
++++ b/common/main.c
+@@ -27,8 +27,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ /*
+  * Board-specific Platform code can reimplement show_boot_progress () if needed
+  */
+-void inline __show_boot_progress (int val) {}
+-void show_boot_progress (int val) __attribute__((weak, alias("__show_boot_progress")));
++__weak void show_boot_progress(int val) {}
+ 
+ #define MAX_DELAY_STOP_STR 32
+ 
diff --git a/package/boot/uboot-lantiq/patches/0028-gcc-compat.patch b/package/boot/uboot-lantiq/patches/0028-gcc-compat.patch
new file mode 100644
index 0000000..7955429
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0028-gcc-compat.patch
@@ -0,0 +1,852 @@
+From 9b2c282b348dfe966bbba967dc7a45ce817cce50 Mon Sep 17 00:00:00 2001
+From: Tom Rini <trini@konsulko.com>
+Date: Mon, 29 Feb 2016 11:34:15 -0500
+Subject: [PATCH] compiler*.h: sync include/linux/compiler*.h with Linux
+ 4.5-rc6
+
+Copy these from Linux v4.5-rc6 tag.
+
+This is needed so that we can keep up with newer gcc versions.  Note
+that we don't have the uapi/ hierarchy from the kernel so continue to
+use <linux/types.h>
+
+Signed-off-by: Tom Rini <trini@konsulko.com>
+---
+ include/linux/compiler-gcc.h   | 266 ++++++++++++++++++++++++++++++++++------
+ include/linux/compiler-gcc3.h  |  21 ----
+ include/linux/compiler-gcc4.h  |  63 ----------
+ include/linux/compiler-intel.h |  45 +++++++
+ include/linux/compiler.h       | 270 +++++++++++++++++++++++++++++++++++++++--
+ 5 files changed, 534 insertions(+), 131 deletions(-)
+ delete mode 100644 include/linux/compiler-gcc3.h
+ delete mode 100644 include/linux/compiler-gcc4.h
+ create mode 100644 include/linux/compiler-intel.h
+
+diff --git a/include/linux/compiler-gcc.h b/include/linux/compiler-gcc.h
+index 9896e54..22ab246 100644
+--- a/include/linux/compiler-gcc.h
++++ b/include/linux/compiler-gcc.h
+@@ -5,11 +5,28 @@
+ /*
+  * Common definitions for all gcc versions go here.
+  */
+-
++#define GCC_VERSION (__GNUC__ * 10000		\
++		     + __GNUC_MINOR__ * 100	\
++		     + __GNUC_PATCHLEVEL__)
+ 
+ /* Optimization barrier */
++
+ /* The "volatile" is due to gcc bugs */
+ #define barrier() __asm__ __volatile__("": : :"memory")
++/*
++ * This version is i.e. to prevent dead stores elimination on @ptr
++ * where gcc and llvm may behave differently when otherwise using
++ * normal barrier(): while gcc behavior gets along with a normal
++ * barrier(), llvm needs an explicit input variable to be assumed
++ * clobbered. The issue is as follows: while the inline asm might
++ * access any memory it wants, the compiler could have fit all of
++ * @ptr into memory registers instead, and since @ptr never escaped
++ * from that, it proofed that the inline asm wasn't touching any of
++ * it. This version works well with both compilers, i.e. we're telling
++ * the compiler that the inline asm absolutely may see the contents
++ * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495
++ */
++#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
+ 
+ /*
+  * This macro obfuscates arithmetic on a variable address so that gcc
+@@ -29,41 +46,63 @@
+  * the inline assembly constraint from =g to =r, in this particular
+  * case either is valid.
+  */
+-#define RELOC_HIDE(ptr, off)					\
+-  ({ unsigned long __ptr;					\
+-    __asm__ ("" : "=r"(__ptr) : "0"(ptr));		\
+-    (typeof(ptr)) (__ptr + (off)); })
++#define RELOC_HIDE(ptr, off)						\
++({									\
++	unsigned long __ptr;						\
++	__asm__ ("" : "=r"(__ptr) : "0"(ptr));				\
++	(typeof(ptr)) (__ptr + (off));					\
++})
++
++/* Make the optimizer believe the variable can be manipulated arbitrarily. */
++#define OPTIMIZER_HIDE_VAR(var)						\
++	__asm__ ("" : "=r" (var) : "0" (var))
+ 
++#ifdef __CHECKER__
++#define __must_be_array(a)	0
++#else
+ /* &a[0] degrades to a pointer: a different type from an array */
+-#define __must_be_array(a) \
+-  BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(typeof(a), typeof(&a[0])))
++#define __must_be_array(a)	BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
++#endif
+ 
+ /*
+  * Force always-inline if the user requests it so via the .config,
+  * or if gcc is too old:
+  */
+-#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) || \
++#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
+     !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
+-# define inline		inline		__attribute__((always_inline))
+-# define __inline__	__inline__	__attribute__((always_inline))
+-# define __inline	__inline	__attribute__((always_inline))
++#define inline		inline		__attribute__((always_inline)) notrace
++#define __inline__	__inline__	__attribute__((always_inline)) notrace
++#define __inline	__inline	__attribute__((always_inline)) notrace
++#else
++/* A lot of inline functions can cause havoc with function tracing */
++#define inline		inline		notrace
++#define __inline__	__inline__	notrace
++#define __inline	__inline	notrace
+ #endif
+ 
+-#define __deprecated			__attribute__((deprecated))
+-#ifndef __packed
+-# define __packed			__attribute__((packed))
+-#endif
+-#define __weak				__attribute__((weak))
++#define __always_inline	inline __attribute__((always_inline))
++#define  noinline	__attribute__((noinline))
++
++#define __deprecated	__attribute__((deprecated))
++#define __packed	__attribute__((packed))
++#define __weak		__attribute__((weak))
++#define __alias(symbol)	__attribute__((alias(#symbol)))
+ 
+ /*
+- * it doesn't make sense on ARM (currently the only user of __naked) to trace
+- * naked functions because then mcount is called without stack and frame pointer
+- * being set up and there is no chance to restore the lr register to the value
+- * before mcount was called.
++ * it doesn't make sense on ARM (currently the only user of __naked)
++ * to trace naked functions because then mcount is called without
++ * stack and frame pointer being set up and there is no chance to
++ * restore the lr register to the value before mcount was called.
++ *
++ * The asm() bodies of naked functions often depend on standard calling
++ * conventions, therefore they must be noinline and noclone.
++ *
++ * GCC 4.[56] currently fail to enforce this, so we must do so ourselves.
++ * See GCC PR44290.
+  */
+-#define __naked				__attribute__((naked)) notrace
++#define __naked		__attribute__((naked)) noinline __noclone notrace
+ 
+-#define __noreturn			__attribute__((noreturn))
++#define __noreturn	__attribute__((noreturn))
+ 
+ /*
+  * From the GCC manual:
+@@ -75,19 +114,170 @@
+  * would be.
+  * [...]
+  */
+-#ifndef __pure
+-# define __pure				__attribute__((pure))
+-#endif
+-#ifndef __aligned
+-# define __aligned(x)			__attribute__((aligned(x)))
+-#endif
+-#define __printf(a,b)			__attribute__((format(printf,a,b)))
+-#define  noinline			__attribute__((noinline))
+-#define __attribute_const__		__attribute__((__const__))
+-#define __maybe_unused			__attribute__((unused))
+-#define __always_unused			__attribute__((unused))
+-
+-#define __gcc_header(x) #x
+-#define _gcc_header(x) __gcc_header(linux/compiler-gcc##x.h)
+-#define gcc_header(x) _gcc_header(x)
+-#include gcc_header(__GNUC__)
++#define __pure			__attribute__((pure))
++#define __aligned(x)		__attribute__((aligned(x)))
++#define __printf(a, b)		__attribute__((format(printf, a, b)))
++#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
++#define __attribute_const__	__attribute__((__const__))
++#define __maybe_unused		__attribute__((unused))
++#define __always_unused		__attribute__((unused))
++
++/* gcc version specific checks */
++
++#if GCC_VERSION < 30200
++# error Sorry, your compiler is too old - please upgrade it.
++#endif
++
++#if GCC_VERSION < 30300
++# define __used			__attribute__((__unused__))
++#else
++# define __used			__attribute__((__used__))
++#endif
++
++#ifdef CONFIG_GCOV_KERNEL
++# if GCC_VERSION < 30400
++#   error "GCOV profiling support for gcc versions below 3.4 not included"
++# endif /* __GNUC_MINOR__ */
++#endif /* CONFIG_GCOV_KERNEL */
++
++#if GCC_VERSION >= 30400
++#define __must_check		__attribute__((warn_unused_result))
++#endif
++
++#if GCC_VERSION >= 40000
++
++/* GCC 4.1.[01] miscompiles __weak */
++#ifdef __KERNEL__
++# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
++#  error Your version of gcc miscompiles the __weak directive
++# endif
++#endif
++
++#define __used			__attribute__((__used__))
++#define __compiler_offsetof(a, b)					\
++	__builtin_offsetof(a, b)
++
++#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
++# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
++#endif
++
++#if GCC_VERSION >= 40300
++/* Mark functions as cold. gcc will assume any path leading to a call
++ * to them will be unlikely.  This means a lot of manual unlikely()s
++ * are unnecessary now for any paths leading to the usual suspects
++ * like BUG(), printk(), panic() etc. [but let's keep them for now for
++ * older compilers]
++ *
++ * Early snapshots of gcc 4.3 don't support this and we can't detect this
++ * in the preprocessor, but we can live with this because they're unreleased.
++ * Maketime probing would be overkill here.
++ *
++ * gcc also has a __attribute__((__hot__)) to move hot functions into
++ * a special section, but I don't see any sense in this right now in
++ * the kernel context
++ */
++#define __cold			__attribute__((__cold__))
++
++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
++
++#ifndef __CHECKER__
++# define __compiletime_warning(message) __attribute__((warning(message)))
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* __CHECKER__ */
++#endif /* GCC_VERSION >= 40300 */
++
++#if GCC_VERSION >= 40500
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased.  Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++
++/* Mark a function definition as prohibited from being cloned. */
++#define __noclone	__attribute__((__noclone__))
++
++#endif /* GCC_VERSION >= 40500 */
++
++#if GCC_VERSION >= 40600
++/*
++ * When used with Link Time Optimization, gcc can optimize away C functions or
++ * variables which are referenced only from assembly code.  __visible tells the
++ * optimizer that something else uses this function or variable, thus preventing
++ * this.
++ */
++#define __visible	__attribute__((externally_visible))
++#endif
++
++
++#if GCC_VERSION >= 40900 && !defined(__CHECKER__)
++/*
++ * __assume_aligned(n, k): Tell the optimizer that the returned
++ * pointer can be assumed to be k modulo n. The second argument is
++ * optional (default 0), so we use a variadic macro to make the
++ * shorthand.
++ *
++ * Beware: Do not apply this to functions which may return
++ * ERR_PTRs. Also, it is probably unwise to apply it to functions
++ * returning extra information in the low bits (but in that case the
++ * compiler should see some alignment anyway, when the return value is
++ * massaged by 'flags = ptr & 3; ptr &= ~3;').
++ */
++#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))
++#endif
++
++/*
++ * GCC 'asm goto' miscompiles certain code sequences:
++ *
++ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
++ *
++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
++ *
++ * (asm goto is automatically volatile - the naming reflects this.)
++ */
++#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
++
++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
++#if GCC_VERSION >= 40400
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#endif
++#if GCC_VERSION >= 40800 || (defined(__powerpc__) && GCC_VERSION >= 40600)
++#define __HAVE_BUILTIN_BSWAP16__
++#endif
++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
++
++#if GCC_VERSION >= 50000
++#define KASAN_ABI_VERSION 4
++#elif GCC_VERSION >= 40902
++#define KASAN_ABI_VERSION 3
++#endif
++
++#if GCC_VERSION >= 40902
++/*
++ * Tell the compiler that address safety instrumentation (KASAN)
++ * should not be applied to that function.
++ * Conflicts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ */
++#define __no_sanitize_address __attribute__((no_sanitize_address))
++#endif
++
++#endif	/* gcc version >= 40000 specific checks */
++
++#if !defined(__noclone)
++#define __noclone	/* not needed */
++#endif
++
++#if !defined(__no_sanitize_address)
++#define __no_sanitize_address
++#endif
++
++/*
++ * A trick to suppress uninitialized variable warning without generating any
++ * code
++ */
++#define uninitialized_var(x) x = x
+diff --git a/include/linux/compiler-gcc3.h b/include/linux/compiler-gcc3.h
+deleted file mode 100644
+index 2befe65..0000000
+--- a/include/linux/compiler-gcc3.h
++++ /dev/null
+@@ -1,21 +0,0 @@
+-#ifndef __LINUX_COMPILER_H
+-#error "Please don't include <linux/compiler-gcc3.h> directly, include <linux/compiler.h> instead."
+-#endif
+-
+-#if __GNUC_MINOR__ >= 3
+-# define __used			__attribute__((__used__))
+-#else
+-# define __used			__attribute__((__unused__))
+-#endif
+-
+-#if __GNUC_MINOR__ >= 4
+-#define __must_check		__attribute__((warn_unused_result))
+-#endif
+-
+-/*
+- * A trick to suppress uninitialized variable warning without generating any
+- * code
+- */
+-#define uninitialized_var(x) x = x
+-
+-#define __always_inline		inline __attribute__((always_inline))
+diff --git a/include/linux/compiler-gcc4.h b/include/linux/compiler-gcc4.h
+deleted file mode 100644
+index 27d11ca..0000000
+--- a/include/linux/compiler-gcc4.h
++++ /dev/null
+@@ -1,63 +0,0 @@
+-#ifndef __LINUX_COMPILER_H
+-#error "Please don't include <linux/compiler-gcc4.h> directly, include <linux/compiler.h> instead."
+-#endif
+-
+-/* GCC 4.1.[01] miscompiles __weak */
+-#ifdef __KERNEL__
+-# if __GNUC_MINOR__ == 1 && __GNUC_PATCHLEVEL__ <= 1
+-#  error Your version of gcc miscompiles the __weak directive
+-# endif
+-#endif
+-
+-#define __used			__attribute__((__used__))
+-#define __must_check 		__attribute__((warn_unused_result))
+-#define __compiler_offsetof(a,b) __builtin_offsetof(a,b)
+-#ifndef __always_inline
+-# define __always_inline		inline __attribute__((always_inline))
+-#endif
+-
+-/*
+- * A trick to suppress uninitialized variable warning without generating any
+- * code
+- */
+-#define uninitialized_var(x) x = x
+-
+-#if __GNUC_MINOR__ >= 3
+-/* Mark functions as cold. gcc will assume any path leading to a call
+-   to them will be unlikely.  This means a lot of manual unlikely()s
+-   are unnecessary now for any paths leading to the usual suspects
+-   like BUG(), printk(), panic() etc. [but let's keep them for now for
+-   older compilers]
+-
+-   Early snapshots of gcc 4.3 don't support this and we can't detect this
+-   in the preprocessor, but we can live with this because they're unreleased.
+-   Maketime probing would be overkill here.
+-
+-   gcc also has a __attribute__((__hot__)) to move hot functions into
+-   a special section, but I don't see any sense in this right now in
+-   the kernel context */
+-#define __cold			__attribute__((__cold__))
+-
+-
+-#if __GNUC_MINOR__ >= 5
+-/*
+- * Mark a position in code as unreachable.  This can be used to
+- * suppress control flow warnings after asm blocks that transfer
+- * control elsewhere.
+- *
+- * Early snapshots of gcc 4.5 don't support this and we can't detect
+- * this in the preprocessor, but we can live with this because they're
+- * unreleased.  Really, we need to have autoconf for the kernel.
+- */
+-#define unreachable() __builtin_unreachable()
+-#endif
+-
+-#endif
+-
+-#if __GNUC_MINOR__ > 0
+-#define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
+-#endif
+-#if __GNUC_MINOR__ >= 4
+-#define __compiletime_warning(message) __attribute__((warning(message)))
+-#define __compiletime_error(message) __attribute__((error(message)))
+-#endif
+diff --git a/include/linux/compiler-intel.h b/include/linux/compiler-intel.h
+new file mode 100644
+index 0000000..d4c7113
+--- /dev/null
++++ b/include/linux/compiler-intel.h
+@@ -0,0 +1,45 @@
++#ifndef __LINUX_COMPILER_H
++#error "Please don't include <linux/compiler-intel.h> directly, include <linux/compiler.h> instead."
++#endif
++
++#ifdef __ECC
++
++/* Some compiler specific definitions are overwritten here
++ * for Intel ECC compiler
++ */
++
++#include <asm/intrinsics.h>
++
++/* Intel ECC compiler doesn't support gcc specific asm stmts.
++ * It uses intrinsics to do the equivalent things.
++ */
++#undef barrier
++#undef barrier_data
++#undef RELOC_HIDE
++#undef OPTIMIZER_HIDE_VAR
++
++#define barrier() __memory_barrier()
++#define barrier_data(ptr) barrier()
++
++#define RELOC_HIDE(ptr, off)					\
++  ({ unsigned long __ptr;					\
++     __ptr = (unsigned long) (ptr);				\
++    (typeof(ptr)) (__ptr + (off)); })
++
++/* This should act as an optimization barrier on var.
++ * Given that this compiler does not have inline assembly, a compiler barrier
++ * is the best we can do.
++ */
++#define OPTIMIZER_HIDE_VAR(var) barrier()
++
++/* Intel ECC compiler doesn't support __builtin_types_compatible_p() */
++#define __must_be_array(a) 0
++
++#endif
++
++#ifndef __HAVE_BUILTIN_BSWAP16__
++/* icc has this, but it's called _bswap16 */
++#define __HAVE_BUILTIN_BSWAP16__
++#define __builtin_bswap16 _bswap16
++#endif
++
+diff --git a/include/linux/compiler.h b/include/linux/compiler.h
+index 5be3dab..020ad16 100644
+--- a/include/linux/compiler.h
++++ b/include/linux/compiler.h
+@@ -5,16 +5,24 @@
+ 
+ #ifdef __CHECKER__
+ # define __user		__attribute__((noderef, address_space(1)))
+-# define __kernel	/* default address space */
++# define __kernel	__attribute__((address_space(0)))
+ # define __safe		__attribute__((safe))
+ # define __force	__attribute__((force))
+ # define __nocast	__attribute__((nocast))
+ # define __iomem	__attribute__((noderef, address_space(2)))
++# define __must_hold(x)	__attribute__((context(x,1,1)))
+ # define __acquires(x)	__attribute__((context(x,0,1)))
+ # define __releases(x)	__attribute__((context(x,1,0)))
+ # define __acquire(x)	__context__(x,1)
+ # define __release(x)	__context__(x,-1)
+ # define __cond_lock(x,c)	((c) ? ({ __acquire(x); 1; }) : 0)
++# define __percpu	__attribute__((noderef, address_space(3)))
++# define __pmem		__attribute__((noderef, address_space(5)))
++#ifdef CONFIG_SPARSE_RCU_POINTER
++# define __rcu		__attribute__((noderef, address_space(4)))
++#else
++# define __rcu
++#endif
+ extern void __chk_user_ptr(const volatile void __user *);
+ extern void __chk_io_ptr(const volatile void __iomem *);
+ #else
+@@ -27,20 +35,32 @@ extern void __chk_io_ptr(const volatile void __iomem *);
+ # define __chk_user_ptr(x) (void)0
+ # define __chk_io_ptr(x) (void)0
+ # define __builtin_warning(x, y...) (1)
++# define __must_hold(x)
+ # define __acquires(x)
+ # define __releases(x)
+ # define __acquire(x) (void)0
+ # define __release(x) (void)0
+ # define __cond_lock(x,c) (c)
++# define __percpu
++# define __rcu
++# define __pmem
+ #endif
+ 
++/* Indirect macros required for expanded argument pasting, eg. __LINE__. */
++#define ___PASTE(a,b) a##b
++#define __PASTE(a,b) ___PASTE(a,b)
++
+ #ifdef __KERNEL__
+ 
+ #ifdef __GNUC__
+ #include <linux/compiler-gcc.h>
+ #endif
+ 
++#if defined(CC_USING_HOTPATCH) && !defined(__CHECKER__)
++#define notrace __attribute__((hotpatch(0,0)))
++#else
+ #define notrace __attribute__((no_instrument_function))
++#endif
+ 
+ /* Intel compiler defines __GNUC__. So we will overwrite implementations
+  * coming from above header files here
+@@ -49,6 +69,13 @@ extern void __chk_io_ptr(const volatile void __iomem *);
+ # include <linux/compiler-intel.h>
+ #endif
+ 
++/* Clang compiler defines __GNUC__. So we will overwrite implementations
++ * coming from above header files here
++ */
++#ifdef __clang__
++#include <linux/compiler-clang.h>
++#endif
++
+ /*
+  * Generic compiler-dependent macros required for kernel
+  * build go below this comment. Actual compiler/compiler version
+@@ -117,7 +144,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+  */
+ #define if(cond, ...) __trace_if( (cond , ## __VA_ARGS__) )
+ #define __trace_if(cond) \
+-	if (__builtin_constant_p((cond)) ? !!(cond) :			\
++	if (__builtin_constant_p(!!(cond)) ? !!(cond) :			\
+ 	({								\
+ 		int ______r;						\
+ 		static struct ftrace_branch_data			\
+@@ -144,6 +171,10 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ # define barrier() __memory_barrier()
+ #endif
+ 
++#ifndef barrier_data
++# define barrier_data(ptr) barrier()
++#endif
++
+ /* Unreachable code */
+ #ifndef unreachable
+ # define unreachable() do { } while (1)
+@@ -156,6 +187,135 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+     (typeof(ptr)) (__ptr + (off)); })
+ #endif
+ 
++#ifndef OPTIMIZER_HIDE_VAR
++#define OPTIMIZER_HIDE_VAR(var) barrier()
++#endif
++
++/* Not-quite-unique ID. */
++#ifndef __UNIQUE_ID
++# define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __LINE__)
++#endif
++
++#include <linux/types.h>
++
++#define __READ_ONCE_SIZE						\
++({									\
++	switch (size) {							\
++	case 1: *(__u8 *)res = *(volatile __u8 *)p; break;		\
++	case 2: *(__u16 *)res = *(volatile __u16 *)p; break;		\
++	case 4: *(__u32 *)res = *(volatile __u32 *)p; break;		\
++	case 8: *(__u64 *)res = *(volatile __u64 *)p; break;		\
++	default:							\
++		barrier();						\
++		__builtin_memcpy((void *)res, (const void *)p, size);	\
++		barrier();						\
++	}								\
++})
++
++static __always_inline
++void __read_once_size(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++
++#ifdef CONFIG_KASAN
++/*
++ * This function is not 'inline' because __no_sanitize_address confilcts
++ * with inlining. Attempt to inline it may cause a build failure.
++ * 	https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ * '__maybe_unused' allows us to avoid defined-but-not-used warnings.
++ */
++static __no_sanitize_address __maybe_unused
++void __read_once_size_nocheck(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++#else
++static __always_inline
++void __read_once_size_nocheck(const volatile void *p, void *res, int size)
++{
++	__READ_ONCE_SIZE;
++}
++#endif
++
++static __always_inline void __write_once_size(volatile void *p, void *res, int size)
++{
++	switch (size) {
++	case 1: *(volatile __u8 *)p = *(__u8 *)res; break;
++	case 2: *(volatile __u16 *)p = *(__u16 *)res; break;
++	case 4: *(volatile __u32 *)p = *(__u32 *)res; break;
++	case 8: *(volatile __u64 *)p = *(__u64 *)res; break;
++	default:
++		barrier();
++		__builtin_memcpy((void *)p, (const void *)res, size);
++		barrier();
++	}
++}
++
++/*
++ * Prevent the compiler from merging or refetching reads or writes. The
++ * compiler is also forbidden from reordering successive instances of
++ * READ_ONCE, WRITE_ONCE and ACCESS_ONCE (see below), but only when the
++ * compiler is aware of some particular ordering.  One way to make the
++ * compiler aware of ordering is to put the two invocations of READ_ONCE,
++ * WRITE_ONCE or ACCESS_ONCE() in different C statements.
++ *
++ * In contrast to ACCESS_ONCE these two macros will also work on aggregate
++ * data types like structs or unions. If the size of the accessed data
++ * type exceeds the word size of the machine (e.g., 32 bits or 64 bits)
++ * READ_ONCE() and WRITE_ONCE()  will fall back to memcpy and print a
++ * compile-time warning.
++ *
++ * Their two major use cases are: (1) Mediating communication between
++ * process-level code and irq/NMI handlers, all running on the same CPU,
++ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
++ * mutilate accesses that either do not require ordering or that interact
++ * with an explicit memory barrier or atomic instruction that provides the
++ * required ordering.
++ */
++
++#define __READ_ONCE(x, check)						\
++({									\
++	union { typeof(x) __val; char __c[1]; } __u;			\
++	if (check)							\
++		__read_once_size(&(x), __u.__c, sizeof(x));		\
++	else								\
++		__read_once_size_nocheck(&(x), __u.__c, sizeof(x));	\
++	__u.__val;							\
++})
++#define READ_ONCE(x) __READ_ONCE(x, 1)
++
++/*
++ * Use READ_ONCE_NOCHECK() instead of READ_ONCE() if you need
++ * to hide memory access from KASAN.
++ */
++#define READ_ONCE_NOCHECK(x) __READ_ONCE(x, 0)
++
++#define WRITE_ONCE(x, val) \
++({							\
++	union { typeof(x) __val; char __c[1]; } __u =	\
++		{ .__val = (__force typeof(x)) (val) }; \
++	__write_once_size(&(x), __u.__c, sizeof(x));	\
++	__u.__val;					\
++})
++
++/**
++ * smp_cond_acquire() - Spin wait for cond with ACQUIRE ordering
++ * @cond: boolean expression to wait for
++ *
++ * Equivalent to using smp_load_acquire() on the condition variable but employs
++ * the control dependency of the wait to reduce the barrier on many platforms.
++ *
++ * The control dependency provides a LOAD->STORE order, the additional RMB
++ * provides LOAD->LOAD order, together they provide LOAD->{LOAD,STORE} order,
++ * aka. ACQUIRE.
++ */
++#define smp_cond_acquire(cond)	do {		\
++	while (!(cond))				\
++		cpu_relax();			\
++	smp_rmb(); /* ctrl + rmb := acquire */	\
++} while (0)
++
+ #endif /* __KERNEL__ */
+ 
+ #endif /* __ASSEMBLY__ */
+@@ -228,7 +388,7 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ 
+ /*
+  * Rather then using noinline to prevent stack consumption, use
+- * noinline_for_stack instead.  For documentaiton reasons.
++ * noinline_for_stack instead.  For documentation reasons.
+  */
+ #define noinline_for_stack noinline
+ 
+@@ -270,11 +430,28 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ # define __section(S) __attribute__ ((__section__(#S)))
+ #endif
+ 
++#ifndef __visible
++#define __visible
++#endif
++
++/*
++ * Assume alignment of return value.
++ */
++#ifndef __assume_aligned
++#define __assume_aligned(a, ...)
++#endif
++
++
+ /* Are two types/vars the same type (ignoring qualifiers)? */
+ #ifndef __same_type
+ # define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
+ #endif
+ 
++/* Is this type a native word size -- useful for atomic operations */
++#ifndef __native_word
++# define __native_word(t) (sizeof(t) == sizeof(char) || sizeof(t) == sizeof(short) || sizeof(t) == sizeof(int) || sizeof(t) == sizeof(long))
++#endif
++
+ /* Compile time object size, -1 for unknown */
+ #ifndef __compiletime_object_size
+ # define __compiletime_object_size(obj) -1
+@@ -284,7 +461,48 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+ #endif
+ #ifndef __compiletime_error
+ # define __compiletime_error(message)
++/*
++ * Sparse complains of variable sized arrays due to the temporary variable in
++ * __compiletime_assert. Unfortunately we can't just expand it out to make
++ * sparse see a constant array size without breaking compiletime_assert on old
++ * versions of GCC (e.g. 4.2.4), so hide the array from sparse altogether.
++ */
++# ifndef __CHECKER__
++#  define __compiletime_error_fallback(condition) \
++	do { ((void)sizeof(char[1 - 2 * condition])); } while (0)
++# endif
+ #endif
++#ifndef __compiletime_error_fallback
++# define __compiletime_error_fallback(condition) do { } while (0)
++#endif
++
++#define __compiletime_assert(condition, msg, prefix, suffix)		\
++	do {								\
++		bool __cond = !(condition);				\
++		extern void prefix ## suffix(void) __compiletime_error(msg); \
++		if (__cond)						\
++			prefix ## suffix();				\
++		__compiletime_error_fallback(__cond);			\
++	} while (0)
++
++#define _compiletime_assert(condition, msg, prefix, suffix) \
++	__compiletime_assert(condition, msg, prefix, suffix)
++
++/**
++ * compiletime_assert - break build and emit msg if condition is false
++ * @condition: a compile-time constant condition to check
++ * @msg:       a message to emit if condition is false
++ *
++ * In tradition of POSIX assert, this macro will break the build if the
++ * supplied condition is *false*, emitting the supplied error message if the
++ * compiler has support to do so.
++ */
++#define compiletime_assert(condition, msg) \
++	_compiletime_assert(condition, msg, __compiletime_assert_, __LINE__)
++
++#define compiletime_assert_atomic_type(t)				\
++	compiletime_assert(__native_word(t),				\
++		"Need native word sized stores/loads for atomicity.")
+ 
+ /*
+  * Prevent the compiler from merging or refetching accesses.  The compiler
+@@ -293,11 +511,45 @@ void ftrace_likely_update(struct ftrace_branch_data *f, int val, int expect);
+  * to make the compiler aware of ordering is to put the two invocations of
+  * ACCESS_ONCE() in different C statements.
+  *
+- * This macro does absolutely -nothing- to prevent the CPU from reordering,
+- * merging, or refetching absolutely anything at any time.  Its main intended
+- * use is to mediate communication between process-level code and irq/NMI
+- * handlers, all running on the same CPU.
++ * ACCESS_ONCE will only work on scalar types. For union types, ACCESS_ONCE
++ * on a union member will work as long as the size of the member matches the
++ * size of the union and the size is smaller than word size.
++ *
++ * The major use cases of ACCESS_ONCE used to be (1) Mediating communication
++ * between process-level code and irq/NMI handlers, all running on the same CPU,
++ * and (2) Ensuring that the compiler does not  fold, spindle, or otherwise
++ * mutilate accesses that either do not require ordering or that interact
++ * with an explicit memory barrier or atomic instruction that provides the
++ * required ordering.
++ *
++ * If possible use READ_ONCE()/WRITE_ONCE() instead.
+  */
+-#define ACCESS_ONCE(x) (*(volatile typeof(x) *)&(x))
+-
++#define __ACCESS_ONCE(x) ({ \
++	 __maybe_unused typeof(x) __var = (__force typeof(x)) 0; \
++	(volatile typeof(x) *)&(x); })
++#define ACCESS_ONCE(x) (*__ACCESS_ONCE(x))
++
++/**
++ * lockless_dereference() - safely load a pointer for later dereference
++ * @p: The pointer to load
++ *
++ * Similar to rcu_dereference(), but for situations where the pointed-to
++ * object's lifetime is managed by something other than RCU.  That
++ * "something other" might be reference counting or simple immortality.
++ */
++#define lockless_dereference(p) \
++({ \
++	typeof(p) _________p1 = READ_ONCE(p); \
++	smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
++	(_________p1); \
++})
++
++/* Ignore/forbid kprobes attach on very low level functions marked by this attribute: */
++#ifdef CONFIG_KPROBES
++# define __kprobes	__attribute__((__section__(".kprobes.text")))
++# define nokprobe_inline	__always_inline
++#else
++# define __kprobes
++# define nokprobe_inline	inline
++#endif
+ #endif /* __LINUX_COMPILER_H */
+-- 
+2.7.4
+
diff --git a/package/boot/uboot-lantiq/patches/0029-net-Use_packed_structures-for_networking.patch b/package/boot/uboot-lantiq/patches/0029-net-Use_packed_structures-for_networking.patch
new file mode 100644
index 0000000..f2f7736
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0029-net-Use_packed_structures-for_networking.patch
@@ -0,0 +1,142 @@
+From 704f3acfcf55343043bbed01c5fb0a0094a68e8a Mon Sep 17 00:00:00 2001
+From: Denis Pynkin <denis.pynkin@collabora.com>
+Date: Fri, 21 Jul 2017 19:28:42 +0300
+Subject: [PATCH] net: Use packed structures for networking
+
+PXE boot is broken with GCC 7.1 due option '-fstore-merging' enabled
+by default for '-O2':
+
+BOOTP broadcast 1
+data abort
+pc : [<8ff8bb30>]          lr : [<00004f1f>]
+reloc pc : [<17832b30>]    lr : [<878abf1f>]
+sp : 8f558bc0  ip : 00000000     fp : 8ffef5a4
+r10: 8ffed248  r9 : 8f558ee0     r8 : 8ffef594
+r7 : 0000000e  r6 : 8ffed700     r5 : 00000000  r4 : 8ffed74e
+r3 : 00060101  r2 : 8ffed230     r1 : 8ffed706  r0 : 00000ddd
+Flags: nzcv  IRQs off  FIQs off  Mode SVC_32
+Resetting CPU ...
+
+Core reason is usage of structures for network headers without packed
+attribute.
+
+Reviewed-by: Yauheni Kaliuta <yauheni.kaliuta@redhat.com>
+Signed-off-by: Denis Pynkin <denis.pynkin@collabora.com>
+Acked-by: Joe Hershberger <joe.hershberger@ni.com>
+---
+ include/net.h | 14 +++++++-------
+ net/bootp.h   |  2 +-
+ net/dns.h     |  2 +-
+ net/nfs.h     |  2 +-
+ net/sntp.h    |  2 +-
+ 5 files changed, 11 insertions(+), 11 deletions(-)
+
+--- a/include/net.h
++++ b/include/net.h
+@@ -203,7 +203,7 @@ struct ethernet_hdr {
+ 	uchar		et_dest[6];	/* Destination node		*/
+ 	uchar		et_src[6];	/* Source node			*/
+ 	ushort		et_protlen;	/* Protocol or length		*/
+-};
++} __attribute__((packed));
+ 
+ /* Ethernet header size */
+ #define ETHER_HDR_SIZE	(sizeof(struct ethernet_hdr))
+@@ -219,7 +219,7 @@ struct e802_hdr {
+ 	uchar		et_snap2;
+ 	uchar		et_snap3;
+ 	ushort		et_prot;	/* 802 protocol			*/
+-};
++} __attribute__((packed));
+ 
+ /* 802 + SNAP + ethernet header size */
+ #define E802_HDR_SIZE	(sizeof(struct e802_hdr))
+@@ -233,7 +233,7 @@ struct vlan_ethernet_hdr {
+ 	ushort		vet_vlan_type;	/* PROT_VLAN			*/
+ 	ushort		vet_tag;	/* TAG of VLAN			*/
+ 	ushort		vet_type;	/* protocol type		*/
+-};
++} __attribute__((packed));
+ 
+ /* VLAN Ethernet header size */
+ #define VLAN_ETHER_HDR_SIZE	(sizeof(struct vlan_ethernet_hdr))
+@@ -260,7 +260,7 @@ struct ip_hdr {
+ 	ushort		ip_sum;		/* checksum			*/
+ 	IPaddr_t	ip_src;		/* Source IP address		*/
+ 	IPaddr_t	ip_dst;		/* Destination IP address	*/
+-};
++} __attribute__((packed));
+ 
+ #define IP_OFFS		0x1fff /* ip offset *= 8 */
+ #define IP_FLAGS	0xe000 /* first 3 bits */
+@@ -288,7 +288,7 @@ struct ip_udp_hdr {
+ 	ushort		udp_dst;	/* UDP destination port		*/
+ 	ushort		udp_len;	/* Length of UDP packet		*/
+ 	ushort		udp_xsum;	/* Checksum			*/
+-};
++} __attribute__((packed));
+ 
+ #define IP_UDP_HDR_SIZE		(sizeof(struct ip_udp_hdr))
+ #define UDP_HDR_SIZE		(IP_UDP_HDR_SIZE - IP_HDR_SIZE)
+@@ -327,7 +327,7 @@ struct arp_hdr {
+ 	uchar		ar_tha[];	/* Target hardware address	*/
+ 	uchar		ar_tpa[];	/* Target protocol address	*/
+ #endif /* 0 */
+-};
++} __attribute__((packed));
+ 
+ #define ARP_HDR_SIZE	(8+20)		/* Size assuming ethernet	*/
+ 
+@@ -362,7 +362,7 @@ struct icmp_hdr {
+ 		} frag;
+ 		uchar data[0];
+ 	} un;
+-};
++} __attribute__((packed));
+ 
+ #define ICMP_HDR_SIZE		(sizeof(struct icmp_hdr))
+ #define IP_ICMP_HDR_SIZE	(IP_HDR_SIZE + ICMP_HDR_SIZE)
+--- a/net/bootp.h
++++ b/net/bootp.h
+@@ -49,7 +49,7 @@ struct Bootp_t {
+ 	char		bp_sname[64];	/* Server host name		*/
+ 	char		bp_file[128];	/* Boot file name		*/
+ 	char		bp_vend[OPT_FIELD_SIZE]; /* Vendor information	*/
+-};
++} __attribute__((packed));
+ 
+ #define BOOTP_HDR_SIZE	sizeof(struct Bootp_t)
+ 
+--- a/net/dns.h
++++ b/net/dns.h
+@@ -29,7 +29,7 @@ struct header {
+ 	uint16_t	nauth;		/* Authority PRs */
+ 	uint16_t	nother;		/* Other PRs */
+ 	unsigned char	data[1];	/* Data, variable length */
+-};
++} __attribute__((packed));
+ 
+ extern void DnsStart(void);		/* Begin DNS */
+ 
+--- a/net/sntp.h
++++ b/net/sntp.h
+@@ -51,7 +51,7 @@ struct sntp_pkt_t {
+ 	unsigned long long originate_timestamp;
+ 	unsigned long long receive_timestamp;
+ 	unsigned long long transmit_timestamp;
+-};
++} __attribute__((packed));
+ 
+ extern void SntpStart(void);	/* Begin SNTP */
+ 
+--- a/net/nfs.h
++++ b/net/nfs.h
+@@ -68,7 +68,7 @@ struct rpc_t {
+ 			uint32_t data[19];
+ 		} reply;
+ 	} u;
+-};
++} __attribute__((packed));
+ extern void NfsStart(void);	/* Begin NFS */
+ 
+ 
diff --git a/package/boot/uboot-lantiq/patches/0030-lzma-force-8bit-reads.patch b/package/boot/uboot-lantiq/patches/0030-lzma-force-8bit-reads.patch
new file mode 100644
index 0000000..a934dab
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0030-lzma-force-8bit-reads.patch
@@ -0,0 +1,57 @@
+From a40a6e16ed76e5e26a0f60226b64c311d4a62c9f Mon Sep 17 00:00:00 2001
+From: Mathias Kresin <dev@kresin.me>
+Date: Sun, 31 Oct 2021 23:04:54 +0100
+Subject: [PATCH] lzma: force 8bit reads
+
+At least since gcc 7.3.0 (OpenWrt 18.06) lwr/lwl are used in the
+assembly of LzmaProps_Decode. While the decission made by the compiler
+looks perfect fine, it triggers some obscure hang on lantiq danube-s
+v1.5 with MX29LV640EB NOR flash chips.
+
+Only if the offset 1 is used, the hang can be observed. Using any other
+offset works fine:
+
+  lwl s0,0(a1) - s0 == 0x6d000080
+  lwl s0,1(a1) - hangs
+  lwl s0,2(a1) - s0 == 0x0080xxxx
+  lwl s0,3(a1) - s0 == 0x80xxxxxx
+
+It isn't clear whether it is a limitation of the flash chip, the EBU or
+something else.
+
+Force 8bit reads to prevent gcc optimizing the read with lwr/lwl
+instructions.
+
+Signed-off-by: Mathias Kresin <dev@kresin.me>
+---
+ lib/lzma/LzmaDec.c | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+--- a/lib/lzma/LzmaDec.c
++++ b/lib/lzma/LzmaDec.c
+@@ -7,6 +7,7 @@
+ #include "LzmaDec.h"
+ 
+ #include <linux/string.h>
++#include <asm/io.h>
+ 
+ #define kNumTopBits 24
+ #define kTopValue ((UInt32)1 << kNumTopBits)
+@@ -703,7 +704,7 @@ static ELzmaDummy LzmaDec_TryDummy(const
+ 
+ static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+ {
+-  p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
++  p->code = ((UInt32)readb(&data[1]) << 24) | ((UInt32)readb(&data[2]) << 16) | ((UInt32)readb(&data[3]) << 8) | ((UInt32)readb(&data[4]));
+   p->range = 0xFFFFFFFF;
+   p->needFlush = 0;
+ }
+@@ -929,7 +930,7 @@ SRes LzmaProps_Decode(CLzmaProps *p, con
+   if (size < LZMA_PROPS_SIZE)
+     return SZ_ERROR_UNSUPPORTED;
+   else
+-    dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
++    dicSize = readb(&data[1]) | ((UInt32)readb(&data[2]) << 8) | ((UInt32)readb(&data[3]) << 16) | ((UInt32)readb(&data[4]) << 24);
+ 
+   if (dicSize < LZMA_DIC_MIN)
+     dicSize = LZMA_DIC_MIN;
diff --git a/package/boot/uboot-lantiq/patches/0100-MIPS-add-board-support-for-Easy-50712.patch b/package/boot/uboot-lantiq/patches/0100-MIPS-add-board-support-for-Easy-50712.patch
new file mode 100644
index 0000000..9d6dc2d
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0100-MIPS-add-board-support-for-Easy-50712.patch
@@ -0,0 +1,306 @@
+--- /dev/null
++++ b/board/lantiq/easy50712/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/lantiq/easy50712/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/lantiq/easy50712/ddr_settings.h
+@@ -0,0 +1,54 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70a
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xc02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x13c
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xd
++#define MC_DC18_VALUE	0x300
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA04
++#define MC_DC21_VALUE	0xd00
++#define MC_DC22_VALUE	0xd0d
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x62
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x2d89
++#define MC_DC30_VALUE	0x8300
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- /dev/null
++++ b/board/lantiq/easy50712/easy50712.c
+@@ -0,0 +1,112 @@
++/*
++ * Copyright (C) 2010 Thomas Langer <thomas.langer@lantiq.com>
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <spi.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++static void gpio_init(void)
++{
++	/* SPI/CS output (low-active) for serial flash */
++	gpio_direction_output(22, 1);
++
++	/* EBU.FL_CS1 as output for NAND CE */
++	gpio_set_altfunc(23, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A23 as output for NAND CLE */
++	gpio_set_altfunc(24, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A24 as output for NAND ALE */
++	gpio_set_altfunc(13, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++
++	/* enable CLK_OUT2 for external switch */
++	gpio_set_altfunc(3, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++}
++
++int board_early_init_f(void)
++{
++	gpio_init();
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Lantiq ADM6996I switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device adm6996i_dev = {
++	.name = "adm6996i",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	/* Deactivate HRST line to release reset of ADM6996I switch */
++	ltq_reset_once(LTQ_RESET_HARD, 200000);
++
++	/* ADM6996I needs some time to come out of reset */
++	__udelay(50000);
++
++	return switch_device_register(&adm6996i_dev);
++}
++
++int spi_cs_is_valid(unsigned int bus, unsigned int cs)
++{
++	if (bus)
++		return 0;
++
++	switch (cs) {
++	case 2:
++		return 1;
++	default:
++		return 0;
++	}
++}
++
++void spi_cs_activate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 2:
++		gpio_set_value(22, 0);
++		break;
++	default:
++		break;
++	}
++}
++
++void spi_cs_deactivate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 2:
++		gpio_set_value(22, 1);
++		break;
++	default:
++		break;
++	}
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -502,6 +502,9 @@ Active  mips        mips32         au1x0
+ Active  mips        mips32         au1x00      -               dbau1x00            dbau1550                             dbau1x00:DBAU1550                                                                                                                 Thomas Lange <thomas@corelatus.se>
+ Active  mips        mips32         au1x00      -               dbau1x00            dbau1550_el                          dbau1x00:DBAU1550,SYS_LITTLE_ENDIAN                                                                                               Thomas Lange <thomas@corelatus.se>
+ Active  mips        mips32         au1x00      -               pb1x00              pb1000                               pb1x00:PB1000                                                                                                                     -
++Active  mips        mips32         danube      lantiq          easy50712           easy50712_nor                        easy50712:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         danube      lantiq          easy50712           easy50712_norspl                     easy50712:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         danube      lantiq          easy50712           easy50712_ram                        easy50712:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         incaip      -               incaip              incaip                               -                                                                                                                                 Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_100MHz                        incaip:CPU_CLOCK_RATE=100000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_133MHz                        incaip:CPU_CLOCK_RATE=133000000                                                                                                   Wolfgang Denk <wd@denx.de>
+--- /dev/null
++++ b/include/configs/easy50712.h
+@@ -0,0 +1,79 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"EASY50712"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Lantiq EASY50712 Danube Reference Board"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_LTQ_SUPPORT_SPI_FLASH
++#define CONFIG_SPI_FLASH_ATMEL		/* Have an AT45DB321D serial flash */
++
++#define CONFIG_LTQ_SUPPORT_NAND_FLASH
++
++#define CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH	/* Build NOR flash SPL */
++
++#define CONFIG_LTQ_SPL_COMP_LZO
++#define CONFIG_LTQ_SPL_CONSOLE
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_ADM6996I
++
++/* Environment */
++#define CONFIG_ENV_SPI_BUS		0
++#define CONFIG_ENV_SPI_CS		2
++#define CONFIG_ENV_SPI_MAX_HZ		20000000
++#define CONFIG_ENV_SPI_MODE		0
++
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#elif defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(128 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR					\
++	"update-uboot-nor=run load-uboot-norspl-lzo write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0101-MIPS-add-board-support-for-Easy-80920.patch b/package/boot/uboot-lantiq/patches/0101-MIPS-add-board-support-for-Easy-80920.patch
new file mode 100644
index 0000000..fcc9163
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0101-MIPS-add-board-support-for-Easy-80920.patch
@@ -0,0 +1,379 @@
+--- /dev/null
++++ b/board/lantiq/easy80920/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/lantiq/easy80920/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/lantiq/easy80920/ddr_settings.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000100
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x101
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000300
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x0
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141b42
++#define	MC_CCR42_VALUE	0x141b42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x0
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- /dev/null
++++ b/board/lantiq/easy80920/easy80920.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <spi.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SPL_BUILD)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	0
++#elif defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++static void gpio_init(void)
++{
++	/* SPI CS 0.4 to serial flash */
++	gpio_direction_output(10, 1);
++
++	/* EBU.FL_CS1 as output for NAND CE */
++	gpio_set_altfunc(23, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A23 as output for NAND CLE */
++	gpio_set_altfunc(24, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A24 as output for NAND ALE */
++	gpio_set_altfunc(13, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* GPIO 3.0 as input for NAND Ready Busy */
++	gpio_set_altfunc(48, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
++	/* GPIO 3.1 as output for NAND Read */
++	gpio_set_altfunc(49, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */
++	{ 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */
++	{ 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC2: internal GPHY0 with 10/100/1000 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC3: unused */
++	{ 3, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* GMAC4: internal GPHY1 with 10/100/1000 firmware for LAN port 3 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC5: external Lantiq PEF7071 10/100/1000 PHY for WANoE port */
++	{ 5, 0x5, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FF0000;
++
++	ltq_gphy_phy11g_a1x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++int spi_cs_is_valid(unsigned int bus, unsigned int cs)
++{
++	if (bus)
++		return 0;
++
++	if (cs == 4)
++		return 1;
++
++	return 0;
++}
++
++void spi_cs_activate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 4:
++		gpio_set_value(10, 0);
++		break;
++	default:
++		break;
++	}
++}
++
++void spi_cs_deactivate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 4:
++		gpio_set_value(10, 1);
++		break;
++	default:
++		break;
++	}
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -509,6 +509,11 @@ Active  mips        mips32         incai
+ Active  mips        mips32         incaip      -               incaip              incaip_100MHz                        incaip:CPU_CLOCK_RATE=100000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_133MHz                        incaip:CPU_CLOCK_RATE=133000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_150MHz                        incaip:CPU_CLOCK_RATE=150000000                                                                                                   Wolfgang Denk <wd@denx.de>
++Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nandspl                    easy80920:SYS_BOOT_NANDSPL                                                                                                        Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nor                        easy80920:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_norspl                     easy80920:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_ram                        easy80920:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_sfspl                      easy80920:SYS_BOOT_SFSPL                                                                                                          Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips64         -           -               qemu-mips           qemu_mips64                          qemu-mips64:SYS_BIG_ENDIAN                                                                                                        -
+ Active  mips        mips64         -           -               qemu-mips           qemu_mips64el                        qemu-mips64:SYS_LITTLE_ENDIAN                                                                                                     -
+ Active  nds32       n1213          ag101       AndesTech       adp-ag101           adp-ag101                            -                                                                                                                                 Andes <uboot@andestech.com>
+--- /dev/null
++++ b/include/configs/easy80920.h
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"EASY80920"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Lantiq EASY80920 VRX200 Family Board"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_LTQ_SUPPORT_SPI_FLASH
++#define CONFIG_SPI_FLASH_MACRONIX	/* Have a MX29LV620 serial flash */
++
++#define CONFIG_LTQ_SUPPORT_NAND_FLASH
++
++#define CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH	/* Build SPI flash SPL */
++#define CONFIG_SPL_SPI_BUS		0
++#define CONFIG_SPL_SPI_CS		4
++#define CONFIG_SPL_SPI_MAX_HZ		25000000
++#define CONFIG_SPL_SPI_MODE		0
++
++#define CONFIG_LTQ_SUPPORT_SPL_NOR_FLASH	/* Build NOR flash SPL */
++
++#define CONFIG_LTQ_SUPPORT_SPL_NAND_FLASH	/* Build NAND flash SPL */
++#define CONFIG_SYS_NAND_PAGE_COUNT	128
++#define CONFIG_SYS_NAND_PAGE_SIZE	2048
++#define CONFIG_SYS_NAND_OOBSIZE		64
++#define CONFIG_SYS_NAND_BLOCK_SIZE	(256 * 1024)
++#define CONFIG_SYS_NAND_BAD_BLOCK_POS	NAND_LARGE_BADBLOCK_POS
++#define CONFIG_SYS_NAND_U_BOOT_OFFS	0x4000
++
++#define CONFIG_LTQ_SPL_COMP_LZO
++#define CONFIG_LTQ_SPL_CONSOLE
++
++#define CONFIG_SYS_DRAM_PROBE
++
++/* Environment */
++#define CONFIG_ENV_SPI_BUS		CONFIG_SPL_SPI_BUS
++#define CONFIG_ENV_SPI_CS		CONFIG_SPL_SPI_CS
++#define CONFIG_ENV_SPI_MAX_HZ		CONFIG_SPL_SPI_MAX_HZ
++#define CONFIG_ENV_SPI_MODE		CONFIG_SPL_SPI_MODE
++
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(384 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#elif defined(CONFIG_SYS_BOOT_NORSPL)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#elif defined(CONFIG_SYS_BOOT_SFSPL)
++#define CONFIG_ENV_IS_IN_SPI_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#elif defined(CONFIG_SYS_BOOT_NANDSPL)
++#define CONFIG_ENV_IS_IN_NAND
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(256 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR					\
++	"update-uboot-nor=run load-uboot-norspl-lzo write-uboot-nor\0"
++
++#define CONFIG_ENV_UPDATE_UBOOT_SF					\
++	"update-uboot-sf=run load-uboot-sfspl-lzo write-uboot-sf\0"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NAND					\
++	"update-uboot-nand=run load-uboot-nandspl-lzo write-uboot-nand\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	CONFIG_ENV_UPDATE_UBOOT_SF	\
++	CONFIG_ENV_UPDATE_UBOOT_NAND
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0102-MIPS-add-board-support-for-Arcadyan-ARV4519PW.patch b/package/boot/uboot-lantiq/patches/0102-MIPS-add-board-support-for-Arcadyan-ARV4519PW.patch
new file mode 100644
index 0000000..413061c
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0102-MIPS-add-board-support-for-Arcadyan-ARV4519PW.patch
@@ -0,0 +1,244 @@
+From 9f915cf9550a6234adecaf3031c2b279835e14af Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: MIPS: add board support for Arcadyan ARV4519
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/arcadyan/arv4519pw/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv4519pw/arv4519pw.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Atheros ar8216 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_NONE },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device ar8216_dev = {
++	.name = "ar8216",
++	.cpu_port = 0,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&ar8216_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv4519pw/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv4519pw/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x131
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA04
++#define MC_DC21_VALUE	0x1700
++#define MC_DC22_VALUE	0x1717
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5A
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -502,6 +502,9 @@ Active  mips        mips32         au1x0
+ Active  mips        mips32         au1x00      -               dbau1x00            dbau1550                             dbau1x00:DBAU1550                                                                                                                 Thomas Lange <thomas@corelatus.se>
+ Active  mips        mips32         au1x00      -               dbau1x00            dbau1550_el                          dbau1x00:DBAU1550,SYS_LITTLE_ENDIAN                                                                                               Thomas Lange <thomas@corelatus.se>
+ Active  mips        mips32         au1x00      -               pb1x00              pb1000                               pb1x00:PB1000                                                                                                                     -
++Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_brn                        arv4519pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_nor                        arv4519pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_ram                        arv4519pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_nor                        easy50712:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_norspl                     easy50712:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_ram                        easy50712:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/arv4519pw.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV4519PW"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV4519PW"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_AR8216
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Brnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0103-MIPS-add-board-support-for-Arcadyan-ARV7518PW.patch b/package/boot/uboot-lantiq/patches/0103-MIPS-add-board-support-for-Arcadyan-ARV7518PW.patch
new file mode 100644
index 0000000..490ab2d
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0103-MIPS-add-board-support-for-Arcadyan-ARV7518PW.patch
@@ -0,0 +1,244 @@
+From 54a31b334162e8dc2ea891057ddeab42978db8b3 Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: MIPS: add board support for Arcadyan ARV7518
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/arcadyan/arv7518pw/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv7518pw/arv7518pw.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Atheros ar8216 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_NONE },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device ar8216_dev = {
++	.name = "ar8216",
++	.cpu_port = 0,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&ar8216_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv7518pw/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv7518pw/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x134
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1400
++#define MC_DC22_VALUE	0x1414
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5B
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -505,6 +505,9 @@ Active  mips        mips32         au1x0
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_brn                        arv4519pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_nor                        arv4519pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_ram                        arv4519pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_brn                        arv7518pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_nor                        arv7518pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_nor                        easy50712:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_norspl                     easy50712:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_ram                        easy50712:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/arv7518pw.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV7518PW"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV7518PW"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_AR8216
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Brnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0104-MIPS-add-board-support-for-AudioCodes-MP-252.patch b/package/boot/uboot-lantiq/patches/0104-MIPS-add-board-support-for-AudioCodes-MP-252.patch
new file mode 100644
index 0000000..16a44cc
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0104-MIPS-add-board-support-for-AudioCodes-MP-252.patch
@@ -0,0 +1,250 @@
+From 4bacfc80eae768be45f9ddf7588ec55281354648 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel.golle@gmail.com>
+Date: Fri, 8 Mar 2013 13:29:04 +0200
+Subject: MIPS: add board support for AudioCodes MP-252
+
+Signed-off-by: Daniel Golle <dgolle@allnet.de>
+
+--- /dev/null
++++ b/board/audiocodes/acmp252/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/audiocodes/acmp252/acmp252.c
+@@ -0,0 +1,66 @@
++/*
++ * Copyright (C) 2013 Daniel Golle <daniel.golle@gmail.com>
++ * Copyright (C) 2011 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++static void gpio_init(void)
++{
++	/* Activate reset line of ADM6996I switch */
++	gpio_direction_output(19, 0);
++}
++
++int board_early_init_f(void)
++{
++	gpio_init();
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Lantiq ADM6996I switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device adm6996i_dev = {
++	.name = "adm6996i",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	/* Deactivate reset line of ADM6996I switch */
++	gpio_set_value(19, 1);
++
++	/* ADM6996I needs some time to come out of reset */
++	__udelay(50000);
++
++	return switch_device_register(&adm6996i_dev);
++}
+--- /dev/null
++++ b/board/audiocodes/acmp252/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/audiocodes/acmp252/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x403
++#define MC_DC08_VALUE	0x103
++#define MC_DC09_VALUE	0x80B
++#define MC_DC10_VALUE	0x304
++#define MC_DC11_VALUE	0xD03
++#define MC_DC12_VALUE	0x2C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x13C
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x402
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1700
++#define MC_DC22_VALUE	0x1717
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5C
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x2D93
++#define MC_DC30_VALUE	0x8300
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -508,6 +508,8 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_brn                        arv7518pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_nor                        arv7518pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      audiocodes      acmp252             acmp252_nor                          acmp252:SYS_BOOT_NOR                                                                                                              Daniel Golle <daniel.golle@gmail.com>
++Active  mips        mips32         danube      audiocodes      acmp252             acmp252_ram                          acmp252:SYS_BOOT_RAM                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_nor                        easy50712:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_norspl                     easy50712:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_ram                        easy50712:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/acmp252.h
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2013 Daniel Golle <daniel.golle@gmail.com>
++ * Copyright (C) 2011 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ACMP252"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"AudioCodes MP-252"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_ADM6996I
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0105-MIPS-add-board-support-for-AVM-FritzBox-3370.patch b/package/boot/uboot-lantiq/patches/0105-MIPS-add-board-support-for-AVM-FritzBox-3370.patch
new file mode 100644
index 0000000..d7850e4
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0105-MIPS-add-board-support-for-AVM-FritzBox-3370.patch
@@ -0,0 +1,356 @@
+From 37a95ae4ba75407a26862ece6f48fa68aa6c5c78 Mon Sep 17 00:00:00 2001
+From: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: MIPS: add board support for AVM FritzBox 3370
+
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/avm/fb3370/Makefile
+@@ -0,0 +1,28 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++# Copyright (C) 2011 Daniel Schwierzeck, daniel.schwierzeck@googlemail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/avm/fb3370/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011 Daniel Schwierzeck, daniel.schwierzeck@googlemail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/avm/fb3370/ddr_settings.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2007-2010 Lantiq Deutschland GmbH
++ * Copyright (C) 2011 Daniel Schwierzeck, daniel.schwierzeck@googlemail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000100
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x101
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000300
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x0
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141B42
++#define	MC_CCR42_VALUE	0x141B42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x0
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- /dev/null
++++ b/board/avm/fb3370/fb3370.c
+@@ -0,0 +1,138 @@
++/*
++ * Copyright (C) 2011 Daniel Schwierzeck, daniel.schwierzeck@googlemail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <spi.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SPL_BUILD)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	0
++#elif defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++static void gpio_init(void)
++{
++	/* SPI CS 0.4 to serial flash */
++	gpio_direction_output(10, 1);
++
++	/* EBU.FL_CS1 as output for NAND CE */
++	gpio_set_altfunc(23, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A23 as output for NAND CLE */
++	gpio_set_altfunc(24, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A24 as output for NAND ALE */
++	gpio_set_altfunc(13, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* GPIO 3.0 as input for NAND Ready Busy */
++	gpio_set_altfunc(48, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
++	/* GPIO 3.1 as output for NAND Read */
++	gpio_set_altfunc(49, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */
++	{ 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */
++	{ 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC2: internal GPHY0 with 10/100/1000 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC3: unused */
++	{ 3, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* GMAC4: internal GPHY1 with 10/100/1000 firmware for LAN port 3 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC5: external Lantiq PEF7071 10/100/1000 PHY for WANoE port */
++	{ 5, 0x5, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FF0000;
++
++	ltq_gphy_phy11g_a1x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++int spi_cs_is_valid(unsigned int bus, unsigned int cs)
++{
++	if (bus)
++		return 0;
++
++	if (cs == 4)
++		return 1;
++
++	return 0;
++}
++
++void spi_cs_activate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 4:
++		gpio_set_value(10, 0);
++		break;
++	default:
++		break;
++	}
++}
++
++void spi_cs_deactivate(struct spi_slave *slave)
++{
++	switch (slave->cs) {
++	case 4:
++		gpio_set_value(10, 1);
++		break;
++	default:
++		break;
++	}
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -517,6 +517,9 @@ Active  mips        mips32         incai
+ Active  mips        mips32         incaip      -               incaip              incaip_100MHz                        incaip:CPU_CLOCK_RATE=100000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_133MHz                        incaip:CPU_CLOCK_RATE=133000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_150MHz                        incaip:CPU_CLOCK_RATE=150000000                                                                                                   Wolfgang Denk <wd@denx.de>
++Active  mips        mips32         vrx200      avm             fb3370              fb3370_eva                           fb3370:SYS_BOOT_EVA                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      avm             fb3370              fb3370_ram                           fb3370:SYS_BOOT_RAM                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      avm             fb3370              fb3370_sfspl                         fb3370:SYS_BOOT_SFSPL                                                                                                             Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nandspl                    easy80920:SYS_BOOT_NANDSPL                                                                                                        Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nor                        easy80920:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_norspl                     easy80920:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/fb3370.h
+@@ -0,0 +1,80 @@
++/*
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@googlemail.com
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"FB3370"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"AVM FritzBox 3370"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART			/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET		/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_SPI_FLASH
++#define CONFIG_SPI_FLASH_MACRONIX		/* Have a MX29LV620 serial flash */
++
++#define CONFIG_LTQ_SUPPORT_NAND_FLASH
++
++#define CONFIG_LTQ_SUPPORT_SPL_SPI_FLASH	/* Build SPI flash SPL */
++#define CONFIG_LTQ_SPL_COMP_LZO			/* Compress SPL with LZO */
++#define CONFIG_LTQ_SPL_CONSOLE			/* Enable SPL console */
++
++#define CONFIG_SPL_SPI_BUS		0
++#define CONFIG_SPL_SPI_CS		4
++#define CONFIG_SPL_SPI_MAX_HZ		25000000
++#define CONFIG_SPL_SPI_MODE		0
++
++#define CONFIG_SYS_DRAM_PROBE
++
++#define CONFIG_SYS_BOOTM_LEN          0x1000000       /* 16 MB */
++
++/* Environment */
++#define CONFIG_ENV_SPI_BUS		CONFIG_SPL_SPI_BUS
++#define CONFIG_ENV_SPI_CS		CONFIG_SPL_SPI_CS
++#define CONFIG_ENV_SPI_MAX_HZ		CONFIG_SPL_SPI_MAX_HZ
++#define CONFIG_ENV_SPI_MODE		CONFIG_SPL_SPI_MODE
++
++#if defined(CONFIG_SYS_BOOT_SFSPL)
++#define CONFIG_ENV_IS_IN_SPI_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++#if defined(CONFIG_SYS_BOOT_EVA)
++#define CONFIG_SYS_TEXT_BASE		0x80100000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_SF					\
++	"update-uboot-sf=run load-uboot-sfspl-lzo write-uboot-sf\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_SF
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0106-MIPS-add-board-support-for-Gigaset-SX76X.patch b/package/boot/uboot-lantiq/patches/0106-MIPS-add-board-support-for-Gigaset-SX76X.patch
new file mode 100644
index 0000000..16946e9
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0106-MIPS-add-board-support-for-Gigaset-SX76X.patch
@@ -0,0 +1,249 @@
+From 9e9dec563e4d061e7b34d2d59a89eb05c60f43a7 Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: MIPS: add board support for Gigaset SX76X
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/gigaset/sx76x/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/gigaset/sx76x/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/gigaset/sx76x/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x202
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0xF3E
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x300
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA04
++#define MC_DC21_VALUE	0xF00
++#define MC_DC22_VALUE	0xF0F
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x63
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x100
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x514
++#define MC_DC29_VALUE	0x2D89
++#define MC_DC30_VALUE	0x8300
++#define MC_DC31_VALUE	0x2002
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- /dev/null
++++ b/board/gigaset/sx76x/sx76x.c
+@@ -0,0 +1,65 @@
++/*
++ * Copyright (C) 2011 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++static void gpio_init(void)
++{
++	/* Activate reset line of ADM6996I switch */
++	gpio_direction_output(19, 0);
++}
++
++int board_early_init_f(void)
++{
++	gpio_init();
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Lantiq ADM6996I switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device adm6996i_dev = {
++	.name = "adm6996i",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	/* Deactivate reset line of ADM6996I switch */
++	gpio_set_value(19, 1);
++
++	/* ADM6996I needs some time to come out of reset */
++	__udelay(50000);
++
++	return switch_device_register(&adm6996i_dev);
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -510,6 +510,8 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_nor                          acmp252:SYS_BOOT_NOR                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_ram                          acmp252:SYS_BOOT_RAM                                                                                                              Daniel Golle <daniel.golle@gmail.com>
++Active  mips        mips32         danube      gigaset         sx76x               gigasx76x_nor                        sx76x:SYS_BOOT_NOR                                                                                                                Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      gigaset         sx76x               gigasx76x_ram                        sx76x:SYS_BOOT_RAM                                                                                                                Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_nor                        easy50712:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_norspl                     easy50712:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         danube      lantiq          easy50712           easy50712_ram                        easy50712:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/sx76x.h
+@@ -0,0 +1,61 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"GIGASX76X"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Gigaset sx76x"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_ADM6996I
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0107-MIPS-add-board-support-for-ZyXEL-P-2812HNU-Fx.patch b/package/boot/uboot-lantiq/patches/0107-MIPS-add-board-support-for-ZyXEL-P-2812HNU-Fx.patch
new file mode 100644
index 0000000..3f77d98
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0107-MIPS-add-board-support-for-ZyXEL-P-2812HNU-Fx.patch
@@ -0,0 +1,303 @@
+From 3f7be04a148d23cdb5fd320e0e2923983f8bd1f4 Mon Sep 17 00:00:00 2001
+From: Luka Perkov <luka@openwrt.org>
+Date: Tue, 6 Aug 2013 22:51:00 +0200
+Subject: MIPS: add board support for ZyXEL P-2812HNU-Fx
+
+Signed-off-by: Luka Perkov <luka@openwrt.org>
+
+--- /dev/null
++++ b/board/zyxel/p2812hnufx/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/zyxel/p2812hnufx/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/zyxel/p2812hnufx/ddr_settings.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * The values have been extracted from original ZyXEL U-Boot.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000100
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x101
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000300
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x0
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141B42
++#define	MC_CCR42_VALUE	0x141B42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x0
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- /dev/null
++++ b/board/zyxel/p2812hnufx/p2812hnufx.c
+@@ -0,0 +1,97 @@
++/*
++ * Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SPL_BUILD)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	0
++#elif defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++static void gpio_init(void)
++{
++	/* EBU.FL_CS1 as output for NAND CE */
++	gpio_set_altfunc(23, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A23 as output for NAND CLE */
++	gpio_set_altfunc(24, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A24 as output for NAND ALE */
++	gpio_set_altfunc(13, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* GPIO 3.0 as input for NAND Ready Busy */
++	gpio_set_altfunc(48, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
++	/* GPIO 3.1 as output for NAND Read */
++	gpio_set_altfunc(49, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */
++	{ 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */
++	{ 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC2: internal GPHY0 with 10/100/1000 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC3: unused */
++	{ 3, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* GMAC4: internal GPHY1 with 10/100/1000 firmware for LAN port 3 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC5: external Lantiq PEF7071 10/100/1000 PHY for WANoE port */
++	{ 5, 0x5, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FF0000;
++
++	ltq_gphy_phy11g_a1x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -527,6 +527,8 @@ Active  mips        mips32         vrx20
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_norspl                     easy80920:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_ram                        easy80920:SYS_BOOT_RAM                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_sfspl                      easy80920:SYS_BOOT_SFSPL                                                                                                          Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      zyxel           p2812hnufx          p2812hnufx_nandspl                   p2812hnufx:SYS_BOOT_NANDSPL                                                                                                       Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         vrx200      zyxel           p2812hnufx          p2812hnufx_ram                       p2812hnufx:SYS_BOOT_RAM                                                                                                           Luka Perkov <luka@openwrt.org>
+ Active  mips        mips64         -           -               qemu-mips           qemu_mips64                          qemu-mips64:SYS_BIG_ENDIAN                                                                                                        -
+ Active  mips        mips64         -           -               qemu-mips           qemu_mips64el                        qemu-mips64:SYS_LITTLE_ENDIAN                                                                                                     -
+ Active  nds32       n1213          ag101       AndesTech       adp-ag101           adp-ag101                            -                                                                                                                                 Andes <uboot@andestech.com>
+--- /dev/null
++++ b/include/configs/p2812hnufx.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"P-2812HNU-Fx"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"ZyXEL P-2812HNU-Fx"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART			/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET		/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NAND_FLASH		/* Have a K9F1G08U0D NAND flash */
++
++#define CONFIG_LTQ_SUPPORT_SPL_NAND_FLASH	/* Build NAND flash SPL */
++#define CONFIG_LTQ_SPL_COMP_LZO			/* Compress SPL with LZO */
++#define CONFIG_LTQ_SPL_CONSOLE			/* Enable SPL console */
++
++#define CONFIG_SYS_NAND_PAGE_COUNT	64
++#define CONFIG_SYS_NAND_PAGE_SIZE	2048
++#define CONFIG_SYS_NAND_OOBSIZE		64
++#define CONFIG_SYS_NAND_BLOCK_SIZE	(128 * 1024)
++#define CONFIG_SYS_NAND_BAD_BLOCK_POS	NAND_LARGE_BADBLOCK_POS
++#define CONFIG_SYS_NAND_U_BOOT_OFFS	0x4000
++
++#define CONFIG_SYS_DRAM_PROBE
++
++#define CONFIG_SYS_BOOTM_LEN          0x1000000       /* 16 MB */
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NANDSPL)
++#define CONFIG_ENV_IS_IN_NAND
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NAND					\
++	"update-uboot-nand=run load-uboot-nandspl-lzo write-uboot-nand\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NAND
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0108-MIPS-add-board-support-for-Arcadyan-ARV752DPW.patch b/package/boot/uboot-lantiq/patches/0108-MIPS-add-board-support-for-Arcadyan-ARV752DPW.patch
new file mode 100644
index 0000000..0849305
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0108-MIPS-add-board-support-for-Arcadyan-ARV752DPW.patch
@@ -0,0 +1,244 @@
+From fbdbf2ddf2b34d675d53de679c179788b0604c1a Mon Sep 17 00:00:00 2001
+From: Oliver Muth <dr.o.muth@gmx.de>
+Date: Sat, 12 Oct 2013 16:49:53 +0200
+Subject: MIPS: add board support for Arcadyan ARV752DPW
+
+Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/arcadyan/arv752dpw/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv752dpw/arv752dpw.c
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ * Copyright (C) 2013 Oliver Muth <dr.o.muth@gmx.de>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Realtek rtl8306 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++static struct switch_device rtl8306_dev = {
++	.name = "rtl8306",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&rtl8306_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv752dpw/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv752dpw/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.     
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x134
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1400
++#define MC_DC22_VALUE	0x1414
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5B
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -508,6 +508,9 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_brn                        arv7518pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_nor                        arv7518pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_brn                        arv752dpw:SYS_BOOT_BRN                                                                                                            -
++Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_nor                        arv752dpw:SYS_BOOT_NOR                                                                                                            -
++Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_ram                        arv752dpw:SYS_BOOT_RAM                                                                                                            -
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_nor                          acmp252:SYS_BOOT_NOR                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_ram                          acmp252:SYS_BOOT_RAM                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      gigaset         sx76x               gigasx76x_nor                        sx76x:SYS_BOOT_NOR                                                                                                                Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv752dpw.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV752DPW"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV752DPW"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_RTL8306
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Brnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0109-MIPS-add-board-support-for-Arcadyan-ARV752DPW22.patch b/package/boot/uboot-lantiq/patches/0109-MIPS-add-board-support-for-Arcadyan-ARV752DPW22.patch
new file mode 100644
index 0000000..29b9648
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0109-MIPS-add-board-support-for-Arcadyan-ARV752DPW22.patch
@@ -0,0 +1,246 @@
+From 09f411b4d10f10a62f147264121bb853b4649c3e Mon Sep 17 00:00:00 2001
+From: Oliver Muth <dr.o.muth@gmx.de>
+Date: Sat, 12 Oct 2013 16:49:53 +0200
+Subject: MIPS: add board support for Arcadyan ARV752DPW22
+
+Signed-off-by: Oliver Muth <dr.o.muth@gmx.de>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/arcadyan/arv752dpw22/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv752dpw22/arv752dpw22.c
+@@ -0,0 +1,52 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ * Copyright (C) 2013 Oliver Muth <dr.o.muth@gmx.de>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Atheros ar8216 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_MII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device ar8216_dev = {
++	.name = "ar8216",
++	.cpu_port = 0,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&ar8216_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv752dpw22/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv752dpw22/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.     
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x134
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1400
++#define MC_DC22_VALUE	0x1414
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5B
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -511,6 +511,9 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_brn                        arv752dpw:SYS_BOOT_BRN                                                                                                            -
+ Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_nor                        arv752dpw:SYS_BOOT_NOR                                                                                                            -
+ Active  mips        mips32         danube      arcadyan        arv752dpw           arv752dpw_ram                        arv752dpw:SYS_BOOT_RAM                                                                                                            -
++Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_brn                      arv752dpw22:SYS_BOOT_BRN                                                                                                          -
++Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_nor                      arv752dpw22:SYS_BOOT_NOR                                                                                                          -
++Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_ram                      arv752dpw22:SYS_BOOT_RAM                                                                                                          -
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_nor                          acmp252:SYS_BOOT_NOR                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_ram                          acmp252:SYS_BOOT_RAM                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      gigaset         sx76x               gigasx76x_nor                        sx76x:SYS_BOOT_NOR                                                                                                                Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv752dpw22.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV752DPW22"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV752DPW22"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_AR8216
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(192 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Burnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0110-MIPS-add-board-support-for-Arcadyan-ARV7510PW.patch b/package/boot/uboot-lantiq/patches/0110-MIPS-add-board-support-for-Arcadyan-ARV7510PW.patch
new file mode 100644
index 0000000..902f7b7
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0110-MIPS-add-board-support-for-Arcadyan-ARV7510PW.patch
@@ -0,0 +1,271 @@
+From ba27086a5174130d138d645c2f4a49b08c3f2386 Mon Sep 17 00:00:00 2001
+From: Matti Laakso <malaakso@elisanet.fi>
+Date: Sat, 2 Mar 2013 23:34:00 +0100
+Subject: MIPS: add board support for Arcadyan ARV7510
+
+Signed-off-by: Matti Laakso <malaakso@elisanet.fi>
+Signed-off-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+
+--- /dev/null
++++ b/board/arcadyan/arv7510pw/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv7510pw/arv7510pw.c
+@@ -0,0 +1,72 @@
++/*
++ * Copyright (C) 2013 Matti Laakso <malaakso@elisanet.fi>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++
++static void gpio_init(void)
++{
++	/* Initialize SSIO GPIOs */
++	gpio_set_altfunc(4, 1, 0, 1);
++	gpio_set_altfunc(5, 1, 0, 1);
++	gpio_set_altfunc(6, 1, 0, 1);
++	ltq_gpio_init();
++
++	/* Power led on */
++	gpio_direction_output(76, 1);
++}
++
++int board_early_init_f(void)
++{
++	gpio_init();
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: ADM6996I */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device adm6996i_dev = {
++	.name = "adm6996i",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	/* Deactivate HRST line to release reset of ADM6996I switch */
++	ltq_reset_once(LTQ_RESET_HARD, 200000);
++
++	/* ADM6996I needs some time to come out of reset */
++	__udelay(50000);
++
++	return switch_device_register(&adm6996i_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv7510pw/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv7510pw/ddr_settings.h
+@@ -0,0 +1,53 @@
++/*
++ * Copyright (C) 2013 Matti Laakso <malaakso@elisanet.fi>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x120
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA04
++#define MC_DC21_VALUE	0x1700
++#define MC_DC22_VALUE	0x1717
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x52
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -505,6 +505,9 @@ Active  mips        mips32         au1x0
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_brn                        arv4519pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_nor                        arv4519pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_ram                        arv4519pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_brn                        arv7510pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_nor                        arv7510pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_ram                        arv7510pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_brn                        arv7518pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_nor                        arv7518pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv7510pw.h
+@@ -0,0 +1,77 @@
++/*
++ * Copyright (C) 2013 Matti Laakso <malaakso@elisanet.fi>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV7510PW"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV7510PW"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_ADM6996I
++
++/* SSIO */
++#define CONFIG_LTQ_SSIO_SHIFT_REGS
++#define CONFIG_LTQ_SSIO_EDGE_FALLING
++#define CONFIG_LTQ_SSIO_GPHY1_MODE	0
++#define CONFIG_LTQ_SSIO_GPHY2_MODE	0
++#define CONFIG_LTQ_SSIO_INIT_VALUE	0
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Brnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Buffered write broken in ARV7510PW */
++#undef CONFIG_SYS_FLASH_USE_BUFFER_WRITE
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS		\
++	CONFIG_ENV_LANTIQ_DEFAULTS		\
++	CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"kernel_addr=0xB0060000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0111-MIPS-add-board-support-for-Arcadyan-ARV7510PW22.patch b/package/boot/uboot-lantiq/patches/0111-MIPS-add-board-support-for-Arcadyan-ARV7510PW22.patch
new file mode 100644
index 0000000..416f16e
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0111-MIPS-add-board-support-for-Arcadyan-ARV7510PW22.patch
@@ -0,0 +1,240 @@
+--- /dev/null
++++ b/board/arcadyan/arv7510pw22/arv7510pw22.c
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++	/* Switch on Power LED */
++	gpio_direction_output(2, 0);
++	gpio_set_value(2, 0);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Atheros ar8216 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_NONE },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device ar8216_dev = {
++	.name = "ar8216",
++	.cpu_port = 0,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&ar8216_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv7510pw22/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv7510pw22/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.     
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x134
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1400
++#define MC_DC22_VALUE	0x1414
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x5B
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- /dev/null
++++ b/board/arcadyan/arv7510pw22/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -508,6 +508,9 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_brn                        arv7510pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_nor                        arv7510pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_ram                        arv7510pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7510pw22         arv7510pw22_brn                        arv7510pw22:SYS_BOOT_BRN                                                                                                          Álvaro Fernández Rojas <noltari@gmail.com>
++Active  mips        mips32         danube      arcadyan        arv7510pw22         arv7510pw22_nor                        arv7510pw22:SYS_BOOT_NOR                                                                                                          Álvaro Fernández Rojas <noltari@gmail.com>
++Active  mips        mips32         danube      arcadyan        arv7510pw22         arv7510pw22_ram                        arv7510pw22:SYS_BOOT_RAM                                                                                                          Álvaro Fernández Rojas <noltari@gmail.com>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_brn                        arv7518pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_nor                        arv7518pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7518pw           arv7518pw_ram                        arv7518pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv7510pw22.h
+@@ -0,0 +1,69 @@
++/*
++ * Copyright (C) 2014 Álvaro Fernández Rojas <noltari@gmail.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV7510PW22"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV7510PW22"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_AR8216
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Burnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR		\
++	"update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	CONFIG_ENV_UPDATE_UBOOT_NOR	\
++	"kernel_addr=0xB0060000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0112-MIPS-add-board-support-for-Arcadyan-VGV7510KW22.patch b/package/boot/uboot-lantiq/patches/0112-MIPS-add-board-support-for-Arcadyan-VGV7510KW22.patch
new file mode 100644
index 0000000..39499fc
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0112-MIPS-add-board-support-for-Arcadyan-VGV7510KW22.patch
@@ -0,0 +1,307 @@
+--- /dev/null
++++ b/board/arcadyan/vgv7510kw22/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/vgv7510kw22/vgv7510kw22.c
+@@ -0,0 +1,116 @@
++/*
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++#define GPIO_POWER_GREEN	14
++#define GPIO_POWER_RED	28
++
++static void gpio_init(void)
++{
++	/* Turn on the green power LED */
++	gpio_direction_output(GPIO_POWER_GREEN, 0);
++
++	/* Turn off the red power LED */
++	gpio_direction_output(GPIO_POWER_RED, 1);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++void show_boot_progress(int arg)
++{
++	if (!do_gpio_init)
++		return 0;
++
++	if (arg >= 0) {
++		/* Success - turn off the red power LED and turn on the green power LED */
++		gpio_set_value(GPIO_POWER_RED, 1);
++		gpio_set_value(GPIO_POWER_GREEN, 0);
++	} else {
++		/* Failure - turn off green power LED and turn on red power LED */
++		gpio_set_value(GPIO_POWER_GREEN, 1);
++		gpio_set_value(GPIO_POWER_RED, 0);
++	}
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* unused */
++	{ 0, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* unused */
++	{ 1, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* Internal GPHY0 with 10/100 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_MII },
++	/* Internal GPHY0 with 10/100 firmware for LAN port 1 */
++	{ 3, 0x12, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_MII },
++	/* Internal GPHY1 with 10/100 firmware for LAN port 4 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_MII },
++	/* Internal GPHY1 with 10/100 firmware for LAN port 3 */
++	{ 5, 0x14, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_MII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FF0000;
++
++	if (ltq_chip_version_get() == 1)
++		ltq_gphy_phy22f_a1x_load(fw_addr);
++	else
++		ltq_gphy_phy22f_a2x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
+--- /dev/null
++++ b/board/arcadyan/vgv7510kw22/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/vgv7510kw22/ddr_settings.h
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ * Copyright (C) 2016 Mathias Kresin <dev@kresin.me>
++ *
++ * The values have been extracted from original brnboot.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000100
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x100
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000401
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x2040F
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141B42
++#define	MC_CCR42_VALUE	0x141B42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x2040F
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -531,6 +531,9 @@ Active  mips        mips32         incai
+ Active  mips        mips32         incaip      -               incaip              incaip_100MHz                        incaip:CPU_CLOCK_RATE=100000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_133MHz                        incaip:CPU_CLOCK_RATE=133000000                                                                                                   Wolfgang Denk <wd@denx.de>
+ Active  mips        mips32         incaip      -               incaip              incaip_150MHz                        incaip:CPU_CLOCK_RATE=150000000                                                                                                   Wolfgang Denk <wd@denx.de>
++Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_brn                      vgv7510kw22:SYS_BOOT_BRN                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_nor                      vgv7510kw22:SYS_BOOT_NOR                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_ram                      vgv7510kw22:SYS_BOOT_RAM                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_eva                           fb3370:SYS_BOOT_EVA                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_ram                           fb3370:SYS_BOOT_RAM                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_sfspl                         fb3370:SYS_BOOT_SFSPL                                                                                                             Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/vgv7510kw22.h
+@@ -0,0 +1,59 @@
++/*
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"VGV7510KW22"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan VGV7510KW22"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART			/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET		/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH		/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_IS_NOWHERE
++#define CONFIG_ENV_OVERWRITE		1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(384 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(128 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	"kernel_addr=0xB0080000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0113-MIPS-add-board-support-for-Arcadyan-ARV8539PW22.patch b/package/boot/uboot-lantiq/patches/0113-MIPS-add-board-support-for-Arcadyan-ARV8539PW22.patch
new file mode 100644
index 0000000..5185c94
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0113-MIPS-add-board-support-for-Arcadyan-ARV8539PW22.patch
@@ -0,0 +1,241 @@
+--- /dev/null
++++ b/board/arcadyan/arv8539pw22/Makefile
+@@ -0,0 +1,28 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:     GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB    = $(obj)lib$(BOARD).o
++
++COBJS  = $(BOARD).o
++
++SRCS   := $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS   := $(addprefix $(obj),$(COBJS))
++SOBJS  := $(addprefix $(obj),$(SOBJS))
++
++$(LIB):        $(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
++
+--- /dev/null
++++ b/board/arcadyan/arv8539pw22/arv8539pw22.c
+@@ -0,0 +1,53 @@
++/*
++ * Copyright (C) 2012 Luka Perkov <luka@openwrt.org>
++ * Copyright (C) 2013 Oliver Muth <dr.o.muth@gmx.de>
++ *
++ * SPDX-License-Identifier:    GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++int board_early_init_f(void)
++{
++       return 0;
++}
++
++int checkboard(void)
++{
++       puts("Board: " CONFIG_BOARD_NAME "\n");
++       ltq_chip_print_info();
++
++       return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++       /* MAC0: Atheros ar8216 switch */
++       { 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_MII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++       .ports = eth_port_config,
++       .num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++       return ltq_eth_initialize(&eth_board_config);
++}
++
++static struct switch_device ar8216_dev = {
++       .name = "ar8216",
++       .cpu_port = 0,
++       .port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++       return switch_device_register(&ar8216_dev);
++}
++
+--- /dev/null
++++ b/board/arcadyan/arv8539pw22/config.mk
+@@ -0,0 +1,8 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:     GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
++
+--- /dev/null
++++ b/board/arcadyan/arv8539pw22/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script.     
++ *
++ * SPDX-License-Identifier:    GPL-2.0+
++ */
++
++#define MC_DC00_VALUE  0x1B1B
++#define MC_DC01_VALUE  0x0
++#define MC_DC02_VALUE  0x0
++#define MC_DC03_VALUE  0x0
++#define MC_DC04_VALUE  0x0
++#define MC_DC05_VALUE  0x200
++#define MC_DC06_VALUE  0x605
++#define MC_DC07_VALUE  0x303
++#define MC_DC08_VALUE  0x102
++#define MC_DC09_VALUE  0x70A
++#define MC_DC10_VALUE  0x203
++#define MC_DC11_VALUE  0xC02
++#define MC_DC12_VALUE  0x1C8
++#define MC_DC13_VALUE  0x1
++#define MC_DC14_VALUE  0x0
++#define MC_DC15_VALUE  0x134
++#define MC_DC16_VALUE  0xC800
++#define MC_DC17_VALUE  0xD
++#define MC_DC18_VALUE  0x301
++#define MC_DC19_VALUE  0x200
++#define MC_DC20_VALUE  0xA03
++#define MC_DC21_VALUE  0x1400
++#define MC_DC22_VALUE  0x1414
++#define MC_DC23_VALUE  0x0
++#define MC_DC24_VALUE  0x5B
++#define MC_DC25_VALUE  0x0
++#define MC_DC26_VALUE  0x0
++#define MC_DC27_VALUE  0x0
++#define MC_DC28_VALUE  0x510
++#define MC_DC29_VALUE  0x4E20
++#define MC_DC30_VALUE  0x8235
++#define MC_DC31_VALUE  0x0
++#define MC_DC32_VALUE  0x0
++#define MC_DC33_VALUE  0x0
++#define MC_DC34_VALUE  0x0
++#define MC_DC35_VALUE  0x0
++#define MC_DC36_VALUE  0x0
++#define MC_DC37_VALUE  0x0
++#define MC_DC38_VALUE  0x0
++#define MC_DC39_VALUE  0x0
++#define MC_DC40_VALUE  0x0
++#define MC_DC41_VALUE  0x0
++#define MC_DC42_VALUE  0x0
++#define MC_DC43_VALUE  0x0
++#define MC_DC44_VALUE  0x0
++#define MC_DC45_VALUE  0x500
++#define MC_DC46_VALUE  0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -520,6 +520,9 @@ Active  mips        mips32         danub
+ Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_brn                      arv752dpw22:SYS_BOOT_BRN                                                                                                          -
+ Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_nor                      arv752dpw22:SYS_BOOT_NOR                                                                                                          -
+ Active  mips        mips32         danube      arcadyan        arv752dpw22         arv752dpw22_ram                      arv752dpw22:SYS_BOOT_RAM                                                                                                          -
++Active  mips        mips32         danube      arcadyan        arv8539pw22         arv8539pw22_brn                      arv8539pw22:SYS_BOOT_BRN                                                                                                          -
++Active  mips        mips32         danube      arcadyan        arv8539pw22         arv8539pw22_nor                      arv8539pw22:SYS_BOOT_NOR                                                                                                          -
++Active  mips        mips32         danube      arcadyan        arv8539pw22         arv8539pw22_ram                      arv8539pw22:SYS_BOOT_RAM                                                                                                          -
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_nor                          acmp252:SYS_BOOT_NOR                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      audiocodes      acmp252             acmp252_ram                          acmp252:SYS_BOOT_RAM                                                                                                              Daniel Golle <daniel.golle@gmail.com>
+ Active  mips        mips32         danube      gigaset         sx76x               gigasx76x_nor                        sx76x:SYS_BOOT_NOR                                                                                                                Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv8539pw22.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2012-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:    GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE       "ARV8539PW22"
++#define CONFIG_IDENT_STRING    " "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME      "Speedport W 504V Typ A"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART                /* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET    /* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH   /* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_AR8216
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET              (192 * 1024)
++#define CONFIG_ENV_SECT_SIZE           (64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE                        (8 * 1024)
++#define CONFIG_LOADADDR                        CONFIG_SYS_LOAD_ADDR
++
++/* Burnboot loadable image */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE           0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_OVERWRITE 1
++#endif
++
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE                        115200
++#define CONFIG_CONSOLE_ASC             1
++#define CONFIG_CONSOLE_DEV             "ttyS1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_ENV_UPDATE_UBOOT_NOR            \
++       "update-uboot-nor=run load-uboot-nor write-uboot-nor\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS      \
++       CONFIG_ENV_LANTIQ_DEFAULTS      \
++       CONFIG_ENV_UPDATE_UBOOT_NOR     \
++       "kernel_addr=0xB0040000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0114-MIPS-add-board-support-for-Arcadyan-VGV7519.patch b/package/boot/uboot-lantiq/patches/0114-MIPS-add-board-support-for-Arcadyan-VGV7519.patch
new file mode 100644
index 0000000..2ac7856
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0114-MIPS-add-board-support-for-Arcadyan-VGV7519.patch
@@ -0,0 +1,290 @@
+--- /dev/null
++++ b/board/arcadyan/vgv7519/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/vgv7519/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/vgv7519/ddr_settings.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2016 Mathias Kresin <dev@kresin.me>
++ *
++ * The values have been extracted from original brnboot.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000100
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x100
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000401
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x2040F
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141B42
++#define	MC_CCR42_VALUE	0x141B42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x2040F
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- /dev/null
++++ b/board/arcadyan/vgv7519/vgv7519.c
+@@ -0,0 +1,95 @@
++/*
++ * This file is released under the terms of GPL v2 and any later version.
++ * See the file COPYING in the root directory of the source tree for details.
++ *
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ */
++
++#include <common.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++#define GPIO_GPHY_RESET	47
++
++static void gpio_init(void)
++{
++	/* Disable reset on external eth PHY */
++	gpio_direction_output(GPIO_GPHY_RESET, 1);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 0 */
++	{ 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 1 */
++	{ 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC2: internal GPHY0 with 10/100/1000 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC3: unused */
++	{ 3, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* GMAC4: internal GPHY1 with 10/100/1000 firmware for LAN port 3 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC5: external Lantiq PEF7071 10/100/1000 PHY for WANoE port */
++	{ 5, 0x5, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FF0000;
++
++	if (ltq_chip_version_get() == 1)
++		ltq_gphy_phy22f_a1x_load(fw_addr);
++	else
++		ltq_gphy_phy22f_a2x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -537,6 +537,9 @@ Active  mips        mips32         incai
+ Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_brn                      vgv7510kw22:SYS_BOOT_BRN                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_nor                      vgv7510kw22:SYS_BOOT_NOR                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ Active  mips        mips32         vrx200      arcadyan        vgv7510kw22         vgv7510kw22_ram                      vgv7510kw22:SYS_BOOT_RAM                                                                                                           Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++Active  mips        mips32         vrx200      arcadyan        vgv7519             vgv7519_brn                          vgv7519:SYS_BOOT_BRN                                                                                                              Mathias Kresin <dev@kresin.me>
++Active  mips        mips32         vrx200      arcadyan        vgv7519             vgv7519_nor                          vgv7519:SYS_BOOT_NOR                                                                                                              Eddi De Pieri <eddi@depieri.net>
++Active  mips        mips32         vrx200      arcadyan        vgv7519             vgv7519_ram                          vgv7519:SYS_BOOT_RAM                                                                                                              Eddi De Pieri <eddi@depieri.net>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_eva                           fb3370:SYS_BOOT_EVA                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_ram                           fb3370:SYS_BOOT_RAM                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_sfspl                         fb3370:SYS_BOOT_SFSPL                                                                                                             Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/vgv7519.h
+@@ -0,0 +1,64 @@
++/*
++ * This file is released under the terms of GPL v2 and any later version.
++ * See the file COPYING in the root directory of the source tree for details.
++ *
++ * Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"VGV7519"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan VGV7519"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++#define CONFIG_SYS_MAX_FLASH_BANKS	2	/* max number of memory banks */
++#define CONFIG_SYS_FLASH_BANKS_LIST { CONFIG_SYS_FLASH_BASE, CONFIG_SYS_FLASH2_BASE }
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_IS_NOWHERE
++#define CONFIG_ENV_OVERWRITE		1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(384 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(8 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS \
++	"kernel_addr=0xB0080000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0115-MIPS-add-board-support-for-Arcadyan-ARV7506PW11.patch b/package/boot/uboot-lantiq/patches/0115-MIPS-add-board-support-for-Arcadyan-ARV7506PW11.patch
new file mode 100644
index 0000000..2a7c49c
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0115-MIPS-add-board-support-for-Arcadyan-ARV7506PW11.patch
@@ -0,0 +1,277 @@
+--- /dev/null
++++ b/board/arcadyan/arv7506pw11/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/arcadyan/arv7506pw11/arv7506pw11.c
+@@ -0,0 +1,97 @@
++/*
++ * Copyright (C) 2016 Mathias Kresin <dev@kresin.me>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <switch.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/reset.h>
++#include <asm/lantiq/chipid.h>
++
++#if defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define do_gpio_init	1
++#else
++#define do_gpio_init	0
++#endif
++
++#define GPIO_POWER_GREEN	3
++#define GPIO_POWER_RED	6
++#define GPIO_GPHY_RESET 19
++
++static void gpio_init(void)
++{
++	/* Reset switch to have him in a clean state on reboot */
++	gpio_direction_output(GPIO_GPHY_RESET, 0);
++	udelay(20);
++	gpio_direction_output(GPIO_GPHY_RESET, 1);
++
++	/* Turn on the green power LED */
++	gpio_direction_output(GPIO_POWER_GREEN, 0);
++
++	/* Turn off the red power LED */
++	gpio_direction_output(GPIO_POWER_RED, 1);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++void show_boot_progress(int arg)
++{
++	if (!do_gpio_init)
++		return 0;
++
++	if (arg >= 0) {
++		/* Success - turn off the red power LED and turn on the green power LED */
++		gpio_set_value(GPIO_POWER_RED, 1);
++		gpio_set_value(GPIO_POWER_GREEN, 0);
++	} else {
++		/* Failure - turn off green power LED and turn on red power LED */
++		gpio_set_value(GPIO_POWER_GREEN, 1);
++		gpio_set_value(GPIO_POWER_RED, 0);
++	}
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* MAC0: Realtek rtl8306 switch */
++	{ 0, 0x0, LTQ_ETH_PORT_SWITCH, PHY_INTERFACE_MODE_RMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t *bis)
++{
++	return ltq_eth_initialize(&eth_board_config);
++}
++static struct switch_device rtl8306_dev = {
++	.name = "rtl8306",
++	.cpu_port = 5,
++	.port_mask = 0xF,
++};
++
++int board_switch_init(void)
++{
++	return switch_device_register(&rtl8306_dev);
++}
+--- /dev/null
++++ b/board/arcadyan/arv7506pw11/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2011-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/arcadyan/arv7506pw11/ddr_settings.h
+@@ -0,0 +1,55 @@
++/*
++ * Copyright (C) 2011-2013 Luka Perkov <luka@openwrt.org>
++ *
++ * This file has been generated with lantiq_ram_extract_magic.awk script. 
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define MC_DC00_VALUE	0x1B1B
++#define MC_DC01_VALUE	0x0
++#define MC_DC02_VALUE	0x0
++#define MC_DC03_VALUE	0x0
++#define MC_DC04_VALUE	0x0
++#define MC_DC05_VALUE	0x200
++#define MC_DC06_VALUE	0x605
++#define MC_DC07_VALUE	0x303
++#define MC_DC08_VALUE	0x102
++#define MC_DC09_VALUE	0x70A
++#define MC_DC10_VALUE	0x203
++#define MC_DC11_VALUE	0xC02
++#define MC_DC12_VALUE	0x1C8
++#define MC_DC13_VALUE	0x1
++#define MC_DC14_VALUE	0x0
++#define MC_DC15_VALUE	0x142
++#define MC_DC16_VALUE	0xC800
++#define MC_DC17_VALUE	0xD
++#define MC_DC18_VALUE	0x301
++#define MC_DC19_VALUE	0x200
++#define MC_DC20_VALUE	0xA03
++#define MC_DC21_VALUE	0x1300
++#define MC_DC22_VALUE	0x1313
++#define MC_DC23_VALUE	0x0
++#define MC_DC24_VALUE	0x68
++#define MC_DC25_VALUE	0x0
++#define MC_DC26_VALUE	0x0
++#define MC_DC27_VALUE	0x0
++#define MC_DC28_VALUE	0x510
++#define MC_DC29_VALUE	0x4E20
++#define MC_DC30_VALUE	0x8235
++#define MC_DC31_VALUE	0x0
++#define MC_DC32_VALUE	0x0
++#define MC_DC33_VALUE	0x0
++#define MC_DC34_VALUE	0x0
++#define MC_DC35_VALUE	0x0
++#define MC_DC36_VALUE	0x0
++#define MC_DC37_VALUE	0x0
++#define MC_DC38_VALUE	0x0
++#define MC_DC39_VALUE	0x0
++#define MC_DC40_VALUE	0x0
++#define MC_DC41_VALUE	0x0
++#define MC_DC42_VALUE	0x0
++#define MC_DC43_VALUE	0x0
++#define MC_DC44_VALUE	0x0
++#define MC_DC45_VALUE	0x500
++#define MC_DC46_VALUE	0x0
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -505,6 +505,9 @@ Active  mips        mips32         au1x0
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_brn                        arv4519pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_nor                        arv4519pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv4519pw           arv4519pw_ram                        arv4519pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
++Active  mips        mips32         danube      arcadyan        arv7506pw11         arv7506pw11_brn                      arv7506pw11:SYS_BOOT_BRN                                                                                                          Mathias Kresin <dev@kresin.me>
++Active  mips        mips32         danube      arcadyan        arv7506pw11         arv7506pw11_nor                      arv7506pw11:SYS_BOOT_NOR                                                                                                          Mathias Kresin <dev@kresin.me>
++Active  mips        mips32         danube      arcadyan        arv7506pw11         arv7506pw11_ram                      arv7506pw11:SYS_BOOT_RAM                                                                                                          Mathias Kresin <dev@kresin.me>
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_brn                        arv7510pw:SYS_BOOT_BRN                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_nor                        arv7510pw:SYS_BOOT_NOR                                                                                                            Luka Perkov <luka@openwrt.org>
+ Active  mips        mips32         danube      arcadyan        arv7510pw           arv7510pw_ram                        arv7510pw:SYS_BOOT_RAM                                                                                                            Luka Perkov <luka@openwrt.org>
+--- /dev/null
++++ b/include/configs/arv7506pw11.h
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) 2016 Mathias Kresin <dev@kresin.me>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"ARV7506PW11"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"Arcadyan ARV7506PW11"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART		/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET	/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NOR_FLASH	/* Have a parallel NOR flash */
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* Switch devices */
++#define CONFIG_SWITCH_MULTI
++#define CONFIG_SWITCH_RTL8306
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_BRN)
++#define CONFIG_SYS_TEXT_BASE		0x80002000
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#define CONFIG_SYS_DISABLE_CACHE
++#define CONFIG_ENV_IS_NOWHERE
++#define CONFIG_ENV_OVERWRITE 1
++#elif defined(CONFIG_SYS_BOOT_NOR)
++#define CONFIG_ENV_IS_IN_FLASH
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(256 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(64 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(64 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY Danube */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS	\
++	"kernel_addr=0xB0050000\0"
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/0116-MIPS-add-board-support-for-BT-Home-Hub-5A.patch b/package/boot/uboot-lantiq/patches/0116-MIPS-add-board-support-for-BT-Home-Hub-5A.patch
new file mode 100644
index 0000000..fd709bc
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/0116-MIPS-add-board-support-for-BT-Home-Hub-5A.patch
@@ -0,0 +1,344 @@
+--- /dev/null
++++ b/board/bt/bthomehubv5a/Makefile
+@@ -0,0 +1,27 @@
++#
++# Copyright (C) 2000-2011 Wolfgang Denk, DENX Software Engineering, wd@denx.de
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++include $(TOPDIR)/config.mk
++
++LIB	= $(obj)lib$(BOARD).o
++
++COBJS	= $(BOARD).o
++
++SRCS	:= $(SOBJS:.o=.S) $(COBJS:.o=.c)
++OBJS	:= $(addprefix $(obj),$(COBJS))
++SOBJS	:= $(addprefix $(obj),$(SOBJS))
++
++$(LIB):	$(obj).depend $(OBJS) $(SOBJS)
++	$(call cmd_link_o_target, $(OBJS) $(SOBJS))
++
++#########################################################################
++
++# defines $(obj).depend target
++include $(SRCTREE)/rules.mk
++
++sinclude $(obj).depend
++
++#########################################################################
+--- /dev/null
++++ b/board/bt/bthomehubv5a/bthomehubv5a.c
+@@ -0,0 +1,125 @@
++/*
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ * Based on p2812hnufx.c: (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#include <common.h>
++#include <asm/gpio.h>
++#include <asm/lantiq/eth.h>
++#include <asm/lantiq/chipid.h>
++#include <asm/lantiq/cpu.h>
++#include <asm/arch/gphy.h>
++
++#if defined(CONFIG_SPL_BUILD)
++#define do_gpio_init	1
++#define do_pll_init	1
++#define do_dcdc_init	0
++#elif defined(CONFIG_SYS_BOOT_RAM)
++#define do_gpio_init	1
++#define do_pll_init	0
++#define do_dcdc_init	1
++#else
++#define do_gpio_init	0
++#define do_pll_init	0
++#define do_dcdc_init	1
++#endif
++
++#define GPIO_POWER_GREEN	14
++#define GPIO_POWER_RED	12
++
++static void gpio_init(void)
++{
++	/* EBU.FL_CS1 as output for NAND CE */
++	gpio_set_altfunc(23, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A23 as output for NAND CLE */
++	gpio_set_altfunc(24, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* EBU.FL_A24 as output for NAND ALE */
++	gpio_set_altfunc(13, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++	/* GPIO 3.0 as input for NAND Ready Busy */
++	gpio_set_altfunc(48, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_IN);
++	/* GPIO 3.1 as output for NAND Read */
++	gpio_set_altfunc(49, GPIO_ALTSEL_SET, GPIO_ALTSEL_CLR, GPIO_DIR_OUT);
++
++	/* Turn on the green power LED */
++	gpio_direction_output(GPIO_POWER_GREEN, 0);
++
++	/* Turn off the red power LED */
++	gpio_direction_output(GPIO_POWER_RED, 1);
++}
++
++int board_early_init_f(void)
++{
++	if (do_gpio_init)
++		gpio_init();
++
++	if (do_pll_init)
++		ltq_pll_init();
++
++	if (do_dcdc_init)
++		ltq_dcdc_init(0x7F);
++
++	return 0;
++}
++
++int checkboard(void)
++{
++	puts("Board: " CONFIG_BOARD_NAME "\n");
++	ltq_chip_print_info();
++
++	return 0;
++}
++
++void show_boot_progress(int arg)
++{
++	if (!do_gpio_init)
++		return 0;
++
++	if (arg >= 0) {
++		/* Success - turn off the red power LED and turn on the green power LED */
++		gpio_set_value(GPIO_POWER_RED, 1);
++		gpio_set_value(GPIO_POWER_GREEN, 0);
++	} else {
++		/* Failure - turn off green power LED and turn on red power LED */
++		gpio_set_value(GPIO_POWER_GREEN, 1);
++		gpio_set_value(GPIO_POWER_RED, 0);
++	}
++
++	return 0;
++}
++
++static const struct ltq_eth_port_config eth_port_config[] = {
++	/* GMAC0: external Lantiq PEF7071 10/100/1000 PHY for LAN port 3 */
++	{ 0, 0x0, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC1: external Lantiq PEF7071 10/100/1000 PHY for LAN port 4 */
++	{ 1, 0x1, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++	/* GMAC2: internal GPHY0 with 10/100/1000 firmware for LAN port 2 */
++	{ 2, 0x11, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC3: unused */
++	{ 3, 0x0, LTQ_ETH_PORT_NONE, PHY_INTERFACE_MODE_NONE },
++	/* GMAC4: internal GPHY1 with 10/100/1000 firmware for LAN port 1 */
++	{ 4, 0x13, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_GMII },
++	/* GMAC5: external Lantiq PEF7071 10/100/1000 PHY for WANoE port */
++	{ 5, 0x5, LTQ_ETH_PORT_PHY, PHY_INTERFACE_MODE_RGMII },
++};
++
++static const struct ltq_eth_board_config eth_board_config = {
++	.ports = eth_port_config,
++	.num_ports = ARRAY_SIZE(eth_port_config),
++};
++
++int board_eth_init(bd_t * bis)
++{
++	const enum ltq_gphy_clk clk = LTQ_GPHY_CLK_25MHZ_PLL0;
++	const ulong fw_addr = 0x80FE0000;
++
++	ltq_gphy_phy11g_a2x_load(fw_addr);
++
++	ltq_cgu_gphy_clk_src(clk);
++
++	ltq_rcu_gphy_boot(0, fw_addr);
++	ltq_rcu_gphy_boot(1, fw_addr);
++
++	return ltq_eth_initialize(&eth_board_config);
++}
+--- /dev/null
++++ b/board/bt/bthomehubv5a/config.mk
+@@ -0,0 +1,7 @@
++#
++# Copyright (C) 2012-2013 Daniel Schwierzeck, daniel.schwierzeck@gmail.com
++#
++# SPDX-License-Identifier:	GPL-2.0+
++#
++
++PLATFORM_CPPFLAGS += -I$(TOPDIR)/board/$(BOARDDIR)
+--- /dev/null
++++ b/board/bt/bthomehubv5a/ddr_settings.h
+@@ -0,0 +1,70 @@
++/*
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ *
++ * The values have been taken from the HH5A GPL source.
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#define	MC_CCR00_VALUE	0x101
++#define	MC_CCR01_VALUE	0x1000101
++#define	MC_CCR02_VALUE	0x1010000
++#define	MC_CCR03_VALUE	0x101
++#define	MC_CCR04_VALUE	0x1000000
++#define	MC_CCR05_VALUE	0x1000101
++#define	MC_CCR06_VALUE	0x1000100
++#define	MC_CCR07_VALUE	0x1010000
++#define	MC_CCR08_VALUE	0x1000101
++#define	MC_CCR09_VALUE	0x0
++#define	MC_CCR10_VALUE	0x2000100
++#define	MC_CCR11_VALUE	0x2000401
++#define	MC_CCR12_VALUE	0x30000
++#define	MC_CCR13_VALUE	0x202
++#define	MC_CCR14_VALUE	0x7080A0F
++#define	MC_CCR15_VALUE	0x2040F
++#define	MC_CCR16_VALUE	0x40000
++#define	MC_CCR17_VALUE	0x70102
++#define	MC_CCR18_VALUE	0x4020002
++#define	MC_CCR19_VALUE	0x30302
++#define	MC_CCR20_VALUE	0x8000700
++#define	MC_CCR21_VALUE	0x40F020A
++#define	MC_CCR22_VALUE	0x0
++#define	MC_CCR23_VALUE	0xC020000
++#define	MC_CCR24_VALUE	0x4401B04
++#define	MC_CCR25_VALUE	0x0
++#define	MC_CCR26_VALUE	0x0
++#define	MC_CCR27_VALUE	0x6420000
++#define	MC_CCR28_VALUE	0x0
++#define	MC_CCR29_VALUE	0x0
++#define	MC_CCR30_VALUE	0x798
++#define	MC_CCR31_VALUE	0x0
++#define	MC_CCR32_VALUE	0x0
++#define	MC_CCR33_VALUE	0x650000
++#define	MC_CCR34_VALUE	0x200C8
++#define	MC_CCR35_VALUE	0x1D445D
++#define	MC_CCR36_VALUE	0xC8
++#define	MC_CCR37_VALUE	0xC351
++#define	MC_CCR38_VALUE	0x0
++#define	MC_CCR39_VALUE	0x141F04
++#define	MC_CCR40_VALUE	0x142704
++#define	MC_CCR41_VALUE	0x141b42
++#define	MC_CCR42_VALUE	0x141b42
++#define	MC_CCR43_VALUE	0x566504
++#define	MC_CCR44_VALUE	0x566504
++#define	MC_CCR45_VALUE	0x565F17
++#define	MC_CCR46_VALUE	0x565F17
++#define	MC_CCR47_VALUE	0x0
++#define	MC_CCR48_VALUE	0x0
++#define	MC_CCR49_VALUE	0x0
++#define	MC_CCR50_VALUE	0x0
++#define	MC_CCR51_VALUE	0x0
++#define	MC_CCR52_VALUE	0x133
++#define	MC_CCR53_VALUE	0xF3014B27
++#define	MC_CCR54_VALUE	0xF3014B27
++#define	MC_CCR55_VALUE	0xF3014B27
++#define	MC_CCR56_VALUE	0xF3014B27
++#define	MC_CCR57_VALUE	0x7800301
++#define	MC_CCR58_VALUE	0x7800301
++#define	MC_CCR59_VALUE	0x7800301
++#define	MC_CCR60_VALUE	0x7800301
++#define	MC_CCR61_VALUE	0x4
+--- a/boards.cfg
++++ b/boards.cfg
+@@ -546,6 +546,8 @@ Active  mips        mips32         vrx20
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_eva                           fb3370:SYS_BOOT_EVA                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_ram                           fb3370:SYS_BOOT_RAM                                                                                                               Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      avm             fb3370              fb3370_sfspl                         fb3370:SYS_BOOT_SFSPL                                                                                                             Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
++Active  mips        mips32         vrx200      bt              bthomehubv5a        bthomehubv5a_nandspl                 bthomehubv5a:SYS_BOOT_NANDSPL                                                                                                     Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++Active  mips        mips32         vrx200      bt              bthomehubv5a        bthomehubv5a_ram                     bthomehubv5a:SYS_BOOT_RAM                                                                                                         Martin Blumenstingl <martin.blumenstingl@googlemail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nandspl                    easy80920:SYS_BOOT_NANDSPL                                                                                                        Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_nor                        easy80920:SYS_BOOT_NOR                                                                                                            Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+ Active  mips        mips32         vrx200      lantiq          easy80920           easy80920_norspl                     easy80920:SYS_BOOT_NORSPL                                                                                                         Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
+--- /dev/null
++++ b/include/configs/bthomehubv5a.h
+@@ -0,0 +1,89 @@
++/*
++ * Copyright (C) 2016 Mathias Kresin <openwrt@kresin.me>
++ * Copyright (C) 2015 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
++ * Based on p2812hnufx.h: (C) 2013 Luka Perkov <luka@openwrt.org>
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ */
++
++#ifndef __CONFIG_H
++#define __CONFIG_H
++
++#define CONFIG_MACH_TYPE	"BTHOMEHUBV5A"
++#define CONFIG_IDENT_STRING	" "CONFIG_MACH_TYPE
++#define CONFIG_BOARD_NAME	"BT Home Hub 5A"
++
++/* Configure SoC */
++#define CONFIG_LTQ_SUPPORT_UART			/* Enable ASC and UART */
++
++#define CONFIG_LTQ_SUPPORT_ETHERNET		/* Enable ethernet */
++
++#define CONFIG_LTQ_SUPPORT_NAND_FLASH		/* Have a ML01G100BHI00 NAND flash */
++#define CONFIG_SYS_NAND_USE_FLASH_BBT
++
++#define CONFIG_LTQ_SUPPORT_SPL_NAND_FLASH	/* Build NAND flash SPL */
++#define CONFIG_SYS_NAND_PAGE_COUNT	64
++#define CONFIG_SYS_NAND_PAGE_SIZE	2048
++#define CONFIG_SYS_NAND_OOBSIZE		64
++#define CONFIG_SYS_NAND_BLOCK_SIZE	(128 * 1024)
++#define CONFIG_SYS_NAND_5_ADDR_CYCLE
++
++#define CONFIG_LTQ_SPL_COMP_LZO			/* Compress SPL with LZO */
++#define CONFIG_LTQ_SPL_CONSOLE			/* Enable SPL console */
++#define CONFIG_LTQ_SPL_MC_TUNE
++
++#define CONFIG_SYS_BOOTM_LEN		0x1000000	/* 16 MB */
++
++/* MTD devices */
++#define CONFIG_MTD_PARTITIONS
++#define CONFIG_MTD_DEVICE
++#define CONFIG_CMD_MTDPARTS
++#define MTDIDS_DEFAULT			"nand0=nand-xway"
++#define MTDPARTS_DEFAULT		"mtdparts=nand-xway:0x07e80000@0x100000(UBI)"
++
++/* UBI */
++#define CONFIG_RBTREE
++#define CONFIG_CMD_UBI
++#define CONFIG_CMD_UBIFS
++
++/* Environment */
++#if defined(CONFIG_SYS_BOOT_NANDSPL)
++#define CONFIG_SPL_TPL_OFFS		0x800
++#define CONFIG_SPL_TPL_SIZE		0x5000
++#define CONFIG_SPL_MC_TUNE_OFFS		0x5800
++#define CONFIG_SPL_U_BOOT_OFFS		0x6000
++#define CONFIG_SPL_U_BOOT_SIZE		0x3a000
++
++#define CONFIG_ENV_IS_IN_NAND
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_ENV_OFFSET		(640 * 1024)
++#define CONFIG_ENV_SECT_SIZE		(128 * 1024)
++#else
++#define CONFIG_ENV_IS_NOWHERE
++#endif
++
++#define CONFIG_ENV_SIZE			(128 * 1024)
++
++#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
++
++/* Console */
++#define CONFIG_LTQ_ADVANCED_CONSOLE
++#define CONFIG_BAUDRATE			115200
++#define CONFIG_CONSOLE_ASC		1
++#define CONFIG_CONSOLE_DEV		"ttyLTQ1"
++
++/* Pull in default board configs for Lantiq XWAY VRX200 */
++#include <asm/lantiq/config.h>
++#include <asm/arch/config.h>
++
++/* Pull in default OpenWrt configs for Lantiq SoC */
++#include "openwrt-lantiq-common.h"
++
++#undef CONFIG_BOOTCOMMAND
++#define CONFIG_BOOTCOMMAND \
++	"mtdparts default; ubi part UBI; ubi read ${loadaddr} kernel; bootm ${loadaddr}"
++
++#define CONFIG_EXTRA_ENV_SETTINGS	\
++	CONFIG_ENV_LANTIQ_DEFAULTS
++
++#endif /* __CONFIG_H */
diff --git a/package/boot/uboot-lantiq/patches/100-portability.patch b/package/boot/uboot-lantiq/patches/100-portability.patch
new file mode 100644
index 0000000..4539e3e
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/100-portability.patch
@@ -0,0 +1,18 @@
+--- a/include/image.h
++++ b/include/image.h
+@@ -17,7 +17,6 @@
+ #define __IMAGE_H__
+ 
+ #include "compiler.h"
+-#include <asm/byteorder.h>
+ 
+ /* Define this to avoid #ifdefs later on */
+ struct lmb;
+@@ -36,6 +35,7 @@ struct lmb;
+ 
+ #include <lmb.h>
+ #include <asm/u-boot.h>
++#include <asm/byteorder.h>
+ #include <command.h>
+ 
+ /* Take notice of the 'ignore' property for hashes */
diff --git a/package/boot/uboot-lantiq/patches/101-fix-crypt-header-clash.patch b/package/boot/uboot-lantiq/patches/101-fix-crypt-header-clash.patch
new file mode 100644
index 0000000..fcb1a3d
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/101-fix-crypt-header-clash.patch
@@ -0,0 +1,172 @@
+Fix header clash with system /usr/include/sha1.h and sha256.h when libmd
+is installed.
+
+Backport of u-boot commit "includes: move openssl headers to include/u-boot"
+https://github.com/u-boot/u-boot/commit/2b9912e6a7df7b1f60beb7942bd0e6fa5f9d0167
+
+--- a/board/gdsys/p1022/controlcenterd-id.c
++++ b/board/gdsys/p1022/controlcenterd-id.c
+@@ -30,7 +30,7 @@
+ #include <i2c.h>
+ #include <mmc.h>
+ #include <tpm.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <asm/byteorder.h>
+ #include <asm/unaligned.h>
+ #include <pca9698.h>
+--- a/board/pcs440ep/pcs440ep.c
++++ b/board/pcs440ep/pcs440ep.c
+@@ -13,7 +13,7 @@
+ #include <asm/processor.h>
+ #include <spd_sdram.h>
+ #include <status_led.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <asm/io.h>
+ #include <net.h>
+ #include <ata.h>
+--- a/common/cmd_sha1sum.c
++++ b/common/cmd_sha1sum.c
+@@ -11,7 +11,7 @@
+ #include <common.h>
+ #include <command.h>
+ #include <hash.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ 
+ int do_sha1sum(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+ {
+--- a/common/hash.c
++++ b/common/hash.c
+@@ -14,8 +14,8 @@
+ #include <command.h>
+ #include <hw_sha.h>
+ #include <hash.h>
+-#include <sha1.h>
+-#include <sha256.h>
++#include <u-boot/sha1.h>
++#include <u-boot/sha256.h>
+ #include <asm/io.h>
+ #include <asm/errno.h>
+ 
+--- a/common/image-fit.c
++++ b/common/image-fit.c
+@@ -21,7 +21,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ #endif /* !USE_HOSTCC*/
+ 
+ #include <bootstage.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <u-boot/crc.h>
+ #include <u-boot/md5.h>
+ 
+--- a/common/image.c
++++ b/common/image.c
+@@ -34,7 +34,7 @@
+ #endif
+ 
+ #include <u-boot/md5.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <asm/errno.h>
+ #include <asm/io.h>
+ 
+--- a/drivers/crypto/ace_sha.c
++++ b/drivers/crypto/ace_sha.c
+@@ -5,8 +5,8 @@
+  * SPDX-License-Identifier:	GPL-2.0+
+  */
+ #include <common.h>
+-#include <sha256.h>
+-#include <sha1.h>
++#include <u-boot/sha256.h>
++#include <u-boot/sha1.h>
+ #include <asm/errno.h>
+ #include "ace_sha.h"
+ 
+--- /dev/null
++++ b/include/u-boot/sha1.h
+@@ -0,0 +1 @@
++#include "../sha1.h"
+--- /dev/null
++++ b/include/u-boot/sha256.h
+@@ -0,0 +1 @@
++#include "../sha256.h"
+--- a/lib/rsa/rsa-verify.c
++++ b/lib/rsa/rsa-verify.c
+@@ -7,7 +7,7 @@
+ #include <common.h>
+ #include <fdtdec.h>
+ #include <rsa.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <asm/byteorder.h>
+ #include <asm/errno.h>
+ #include <asm/unaligned.h>
+--- a/lib/sha1.c
++++ b/lib/sha1.c
+@@ -36,7 +36,7 @@
+ #include <string.h>
+ #endif /* USE_HOSTCC */
+ #include <watchdog.h>
+-#include "sha1.h"
++#include <u-boot/sha1.h>
+ 
+ /*
+  * 32-bit integer manipulation macros (big endian)
+--- a/lib/sha256.c
++++ b/lib/sha256.c
+@@ -11,7 +11,7 @@
+ #endif /* USE_HOSTCC */
+ #include <watchdog.h>
+ #include <linux/string.h>
+-#include <sha256.h>
++#include <u-boot/sha256.h>
+ 
+ /*
+  * 32-bit integer manipulation macros (big endian)
+--- a/lib/tpm.c
++++ b/lib/tpm.c
+@@ -7,7 +7,7 @@
+ 
+ #include <common.h>
+ #include <stdarg.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <tpm.h>
+ #include <asm/unaligned.h>
+ 
+--- a/tools/imls/imls.c
++++ b/tools/imls/imls.c
+@@ -24,7 +24,7 @@
+ #include <mtd/mtd-user.h>
+ #endif
+ 
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include <libfdt.h>
+ #include <fdt_support.h>
+ #include <image.h>
+--- a/tools/mkimage.h
++++ b/tools/mkimage.h
+@@ -18,7 +18,7 @@
+ #include <sys/stat.h>
+ #include <time.h>
+ #include <unistd.h>
+-#include <sha1.h>
++#include <u-boot/sha1.h>
+ #include "fdt_host.h"
+ 
+ #undef MKIMAGE_DEBUG
+--- a/tools/ubsha1.c
++++ b/tools/ubsha1.c
+@@ -13,7 +13,7 @@
+ #include <errno.h>
+ #include <string.h>
+ #include <sys/stat.h>
+-#include "sha1.h"
++#include <u-boot/sha1.h>
+ 
+ int main (int argc, char **argv)
+ {
diff --git a/package/boot/uboot-lantiq/patches/200-fix-dtc-header-guard.patch b/package/boot/uboot-lantiq/patches/200-fix-dtc-header-guard.patch
new file mode 100644
index 0000000..88d914b
--- /dev/null
+++ b/package/boot/uboot-lantiq/patches/200-fix-dtc-header-guard.patch
@@ -0,0 +1,19 @@
+--- a/include/libfdt_env.h
++++ b/include/libfdt_env.h
+@@ -8,6 +8,7 @@
+ 
+ #ifndef _LIBFDT_ENV_H
+ #define _LIBFDT_ENV_H
++#define LIBFDT_ENV_H
+ 
+ #include "compiler.h"
+ #include "linux/types.h"
+--- a/include/libfdt.h
++++ b/include/libfdt.h
+@@ -1,5 +1,6 @@
+ #ifndef _LIBFDT_H
+ #define _LIBFDT_H
++#define LIBFDT_H
+ /*
+  * libfdt - Flat Device Tree manipulation
+  * Copyright (C) 2006 David Gibson, IBM Corporation.
diff --git a/package/boot/uboot-layerscape/Makefile b/package/boot/uboot-layerscape/Makefile
new file mode 100644
index 0000000..f023567
--- /dev/null
+++ b/package/boot/uboot-layerscape/Makefile
@@ -0,0 +1,157 @@
+#
+# Copyright (C) 2016 Jiang Yutang <jiangyutang1978@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=uboot-layerscape
+PKG_VERSION:=LSDK-20.04-update-290520
+PKG_RELEASE:=$(AUTORELEASE)
+
+PKG_SOURCE_PROTO:=git
+PKG_SOURCE_URL:=https://source.codeaurora.org/external/qoriq/qoriq-components/u-boot
+PKG_SOURCE_VERSION:=1e55b2f9e7f56b76569089b9e950f49c1579580e
+PKG_MIRROR_HASH:=46aace27e1367f40b424a64215d524a99c3bd62f49057550039e72d5a1ab7edb
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=layerscape
+  BUILD_SUBTARGET:=armv8_64b
+  BUILD_DEVICES:=$(1)
+  UBOOT_IMAGE:=u-boot-dtb.bin
+  ENV_SIZE:=0x2000
+endef
+
+define U-Boot/fsl_ls1012a-frdm
+  NAME:=NXP LS1012AFRDM
+  UBOOT_CONFIG:=ls1012afrdm_tfa
+  ENV_SIZE:=0x40000
+endef
+
+define U-Boot/fsl_ls1012a-rdb
+  NAME:=NXP LS1012ARDB
+  UBOOT_CONFIG:=ls1012ardb_tfa
+  ENV_SIZE:=0x40000
+endef
+
+define U-Boot/fsl_ls1012a-frwy-sdboot
+  NAME:=NXP LS1012AFRWY
+  UBOOT_CONFIG:=ls1012afrwy_tfa
+  ENV_SIZE:=0x10000
+endef
+
+define U-Boot/fsl_ls1043a-rdb
+  NAME:=NXP LS1043ARDB
+  UBOOT_CONFIG:=ls1043ardb_tfa
+endef
+
+define U-Boot/fsl_ls1043a-rdb-sdboot
+  NAME:=NXP LS1043ARDB SD Card Boot
+  UBOOT_CONFIG:=ls1043ardb_tfa
+endef
+
+define U-Boot/fsl_ls1046a-frwy
+  NAME:=NXP LS1046AFRWY
+  UBOOT_CONFIG:=ls1046afrwy_tfa
+endef
+
+define U-Boot/fsl_ls1046a-frwy-sdboot
+  NAME:=NXP LS1046AFRWY SD Card Boot
+  UBOOT_CONFIG:=ls1046afrwy_tfa
+endef
+
+define U-Boot/fsl_ls1046a-rdb
+  NAME:=NXP LS1046ARDB
+  UBOOT_CONFIG:=ls1046ardb_tfa
+endef
+
+define U-Boot/fsl_ls1046a-rdb-sdboot
+  NAME:=NXP LS1046ARDB SD Card Boot
+  UBOOT_CONFIG:=ls1046ardb_tfa
+endef
+
+define U-Boot/fsl_ls1088a-rdb
+  NAME:=NXP LS1088ARDB
+  UBOOT_CONFIG:=ls1088ardb_tfa
+endef
+
+define U-Boot/fsl_ls1088a-rdb-sdboot
+  NAME:=NXP LS1088ARDB SD Card Boot
+  UBOOT_CONFIG:=ls1088ardb_tfa
+endef
+
+define U-Boot/fsl_ls2088a-rdb
+  NAME:=NXP LS2088ARDB
+  UBOOT_CONFIG:=ls2088ardb_tfa
+endef
+
+define U-Boot/fsl_lx2160a-rdb
+  NAME:=NXP LX2160ARDB
+  UBOOT_CONFIG:=lx2160ardb_tfa
+endef
+
+define U-Boot/fsl_lx2160a-rdb-sdboot
+  NAME:=NXP LX2160ARDB SD Card Boot
+  UBOOT_CONFIG:=lx2160ardb_tfa
+endef
+
+define U-Boot/fsl_ls1021a-twr
+  NAME:=NXP LS1021ATWR
+  BUILD_SUBTARGET:=armv7
+  UBOOT_CONFIG:=ls1021atwr_nor
+  ENV_SIZE:=0x20000
+endef
+
+define U-Boot/fsl_ls1021a-twr-sdboot
+  NAME:=NXP LS1021ATWR SD Card Boot
+  BUILD_SUBTARGET:=armv7
+  UBOOT_CONFIG:=ls1021atwr_sdcard_ifc
+  UBOOT_IMAGE:=u-boot-with-spl-pbl.bin
+  ENV_SIZE:=0x20000
+endef
+
+define U-Boot/fsl_ls1021a-iot-sdboot
+  NAME:=NXP LS1021AIOT SD Card Boot
+  BUILD_SUBTARGET:=armv7
+  UBOOT_CONFIG:=ls1021aiot_sdcard
+  UBOOT_IMAGE:=u-boot-with-spl-pbl.bin
+  ENV_SIZE:=0x2000
+endef
+
+UBOOT_TARGETS := \
+  fsl_ls1012a-frdm \
+  fsl_ls1012a-rdb \
+  fsl_ls1012a-frwy-sdboot \
+  fsl_ls1043a-rdb \
+  fsl_ls1043a-rdb-sdboot \
+  fsl_ls1046a-frwy \
+  fsl_ls1046a-frwy-sdboot \
+  fsl_ls1046a-rdb \
+  fsl_ls1046a-rdb-sdboot \
+  fsl_ls1088a-rdb \
+  fsl_ls1088a-rdb-sdboot \
+  fsl_ls2088a-rdb \
+  fsl_lx2160a-rdb \
+  fsl_lx2160a-rdb-sdboot \
+  fsl_ls1021a-twr \
+  fsl_ls1021a-twr-sdboot \
+  fsl_ls1021a-iot-sdboot
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_DATA) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) \
+		$(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-uboot.bin
+	$(PKG_BUILD_DIR)/tools/mkenvimage -s $(ENV_SIZE) \
+		-o $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-uboot-env.bin \
+		files/$(BUILD_VARIANT)-uEnv.txt
+endef
+
+define Package/u-boot/install/default
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1012a-frdm-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1012a-frdm-uEnv.txt
new file mode 100644
index 0000000..b0923b5
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1012a-frdm-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffffffffffff
+qspi_boot=sf probe 0:0;sf read $loadaddr 1000000 2800000;bootm $loadaddr
+bootargs=rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=1550000.spi:1m(bl2),4m(fip),1m(u-boot-env),4m(reserved-1),3m(pfe),2m(reserved-2),1m(dtb),-(firmware)
+bootcmd=echo starting OpenWrt ...;pfe stop;run qspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1012a-frwy-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1012a-frwy-sdboot-uEnv.txt
new file mode 100644
index 0000000..1fcd769
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1012a-frwy-sdboot-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffffffffffff
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;pfe stop;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1012a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1012a-rdb-uEnv.txt
new file mode 100644
index 0000000..1d108a1
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1012a-rdb-uEnv.txt
@@ -0,0 +1,7 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+qspi_boot=sf probe 0:0;sf read $fdtaddr f00000 100000;sf read $loadaddr 1000000 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock8 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=1550000.spi:1m(bl2),4m(fip),1m(u-boot-env),4m(reserved-1),3m(pfe),2m(reserved-2),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;pfe stop;run qspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1021a-iot-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1021a-iot-sdboot-uEnv.txt
new file mode 100644
index 0000000..ed8661b
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1021a-iot-sdboot-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffff
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-sdboot-uEnv.txt
new file mode 100644
index 0000000..ed8661b
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-sdboot-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffff
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-uEnv.txt
new file mode 100644
index 0000000..6e39e05
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1021a-twr-uEnv.txt
@@ -0,0 +1,7 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+nor_boot=cp.b 60f00000 $fdtaddr 100000;cp.b 61000000 $loadaddr 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock6 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=60000000.nor:1m(rcw),2m(u-boot),1m(u-boot-env),11m(reserved-1),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware) cma=64M@0x0-0xb0000000
+bootcmd=echo starting openwrt ...;run nor_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-sdboot-uEnv.txt
new file mode 100644
index 0000000..6034033
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-sdboot-uEnv.txt
@@ -0,0 +1,9 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffffffffffff
+hwconfig=fsl_ddr:bank_intlv=auto
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-uEnv.txt
new file mode 100644
index 0000000..b381bde
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1043a-rdb-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+nor_boot=cp.b 60f00000 $fdtaddr 100000;cp.b 61000000 $loadaddr 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock8 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=60000000.nor:1m(bl2),4m(fip),1m(u-boot-env),3m(reserved-1),256k(fman),5888k(reserved-2),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run nor_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-sdboot-uEnv.txt
new file mode 100644
index 0000000..ed16dde
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-sdboot-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+sd_boot=ext4load mmc 0:1 ${loadaddr} fitImage;bootm ${loadaddr}
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-uEnv.txt
new file mode 100644
index 0000000..9daba4a
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1046a-frwy-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+qspi_boot=sf probe 0:0;sf read $fdtaddr f00000 100000;sf read $loadaddr 1000000 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock9 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=1550000.spi:1m(bl2),4m(fip),1m(u-boot-env),3m(reserved-1),256k(fman),5888k(reserved-2),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run qspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-sdboot-uEnv.txt
new file mode 100644
index 0000000..6034033
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-sdboot-uEnv.txt
@@ -0,0 +1,9 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0x8fffffff
+initrd_high=0xffffffffffffffff
+hwconfig=fsl_ddr:bank_intlv=auto
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-uEnv.txt
new file mode 100644
index 0000000..d24f9ec
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1046a-rdb-uEnv.txt
@@ -0,0 +1,8 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+qspi_boot=sf probe 0:0;sf read $fdtaddr f00000 100000;sf read $loadaddr 1000000 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock9 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=1550000.spi-0:1m(bl2),4m(fip),1m(u-boot-env),3m(reserved-1),256k(fman),5888k(reserved-2),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run qspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-sdboot-uEnv.txt
new file mode 100644
index 0000000..b25e9c8
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-sdboot-uEnv.txt
@@ -0,0 +1,10 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0xa0000000
+initrd_high=0xffffffffffffffff
+hwconfig=fsl_ddr:bank_intlv=auto
+mc_init=mmc read 80000000 5000 1800;mmc read 80300000 7000 800;fsl_mc start mc 80000000 80300000;mmc read 80400000 6800 800;fsl_mc apply dpl 80400000
+sd_boot=ext4load mmc 0:1 $loadaddr fitImage;bootm $loadaddr
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200
+bootcmd=echo starting openwrt ...;run mc_init;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-uEnv.txt
new file mode 100644
index 0000000..6ac6216
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls1088a-rdb-uEnv.txt
@@ -0,0 +1,10 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0xa0000000
+initrd_high=0xffffffffffffffff
+hwconfig=fsl_ddr:bank_intlv=auto
+mc_init=sf probe 0:0;sf read 80000000 a00000 300000;sf read 80300000 e00000 100000;fsl_mc start mc 80000000 80300000;sf read 80400000 d00000 100000;fsl_mc apply dpl 80400000
+qspi_boot=sf probe 0:0;sf read $fdtaddr f00000 100000;sf read $loadaddr 1000000 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock10 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS0,115200 mtdparts=20c0000.spi-0:1m(bl2),4m(fip),1m(u-boot-env),4m(reserved-1),3m(mc),1m(dpl),1m(dpc),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run mc_init;run qspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_ls2088a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_ls2088a-rdb-uEnv.txt
new file mode 100644
index 0000000..eb10a88
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_ls2088a-rdb-uEnv.txt
@@ -0,0 +1,10 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+fdt_high=0xa0000000
+initrd_high=0xffffffffffffffff
+hwconfig=fsl_ddr:bank_intlv=auto
+mc_init=fsl_mc start mc 580a00000 580e00000;fsl_mc apply dpl 580d00000
+nor_boot=cp.b 580f00000 $fdtaddr 100000;cp.b 581000000 $loadaddr 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock9 rootfstype=squashfs,jffs2 noinitrd earlycon=uart8250,mmio,0x21c0500 console=ttyS1,115200 mtdparts=580000000.nor:1m(bl2),4m(fip),1m(u-boot-env),4m(reserved-1),3m(mc),1m(dpl),1m(dpc),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run mc_init;run nor_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-sdboot-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-sdboot-uEnv.txt
new file mode 100644
index 0000000..6b4e920
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-sdboot-uEnv.txt
@@ -0,0 +1,9 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+mc_init=mmc read 80000000 5000 1800;mmc read 80300000 7000 800;fsl_mc start mc 80000000 80300000;mmc read 80400000 6800 800;fsl_mc apply dpl 80400000
+sd_boot=ext4load mmc 0:1 ${loadaddr} fitImage;bootm ${loadaddr}
+bootargs=root=/dev/mmcblk0p2 rw rootwait rootfstype=squashfs,f2fs noinitrd earlycon=pl011,mmio32,0x21c0000 console=ttyAMA0,115200
+bootcmd=echo starting openwrt ...;run mc_init;run sd_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-uEnv.txt b/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-uEnv.txt
new file mode 100644
index 0000000..08757b4
--- /dev/null
+++ b/package/boot/uboot-layerscape/files/fsl_lx2160a-rdb-uEnv.txt
@@ -0,0 +1,9 @@
+fdtaddr=0x8f000000
+loadaddr=0x81000000
+bootm_size=0x10000000
+hwconfig=fsl_ddr:bank_intlv=auto
+mc_init=sf probe 0:0;sf read 80000000 a00000 300000;sf read 80300000 e00000 100000;fsl_mc start mc 80000000 80300000;sf read 80400000 d00000 100000;fsl_mc apply dpl 80400000
+xspi_boot=sf probe 0:0;sf read $fdtaddr f00000 100000;sf read $loadaddr 1000000 1000000;bootm $loadaddr - $fdtaddr
+bootargs=root=/dev/mtdblock9 rootfstype=squashfs,jffs2 noinitrd earlycon=pl011,mmio32,0x21c0000 console=ttyAMA0,115200 mtdparts=20c0000.spi-0:1m(bl2),4m(fip),1m(u-boot-env),4m(reserved-1),3m(mc),1m(dpl),1m(dpc),1m(dtb),16m(kernel),32m(rootfs),49m@0xf00000(firmware)
+bootcmd=echo starting openwrt ...;run mc_init;run xspi_boot
+bootdelay=3
diff --git a/package/boot/uboot-layerscape/patches/010-fix_dtc_compilation_on_host_gcc10.patch b/package/boot/uboot-layerscape/patches/010-fix_dtc_compilation_on_host_gcc10.patch
new file mode 100644
index 0000000..6abb151
--- /dev/null
+++ b/package/boot/uboot-layerscape/patches/010-fix_dtc_compilation_on_host_gcc10.patch
@@ -0,0 +1,46 @@
+From e33a814e772cdc36436c8c188d8c42d019fda639 Mon Sep 17 00:00:00 2001
+From: Dirk Mueller <dmueller@suse.com>
+Date: Tue, 14 Jan 2020 18:53:41 +0100
+Subject: [PATCH] scripts/dtc: Remove redundant YYLOC global declaration
+
+gcc 10 will default to -fno-common, which causes this error at link
+time:
+
+  (.text+0x0): multiple definition of `yylloc'; dtc-lexer.lex.o (symbol from plugin):(.text+0x0): first defined here
+
+This is because both dtc-lexer as well as dtc-parser define the same
+global symbol yyloc. Before with -fcommon those were merged into one
+defintion. The proper solution would be to to mark this as "extern",
+however that leads to:
+
+  dtc-lexer.l:26:16: error: redundant redeclaration of 'yylloc' [-Werror=redundant-decls]
+   26 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+In file included from dtc-lexer.l:24:
+dtc-parser.tab.h:127:16: note: previous declaration of 'yylloc' was here
+  127 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+cc1: all warnings being treated as errors
+
+which means the declaration is completely redundant and can just be
+dropped.
+
+Signed-off-by: Dirk Mueller <dmueller@suse.com>
+Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
+[robh: cherry-pick from upstream]
+Cc: stable@vger.kernel.org
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ scripts/dtc/dtc-lexer.l | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -38,7 +38,6 @@ LINECOMMENT	"//".*\n
+ #include "srcpos.h"
+ #include "dtc-parser.tab.h"
+ 
+-YYLTYPE yylloc;
+ extern bool treesource_error;
+ 
+ /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
diff --git a/package/boot/uboot-mediatek/Makefile b/package/boot/uboot-mediatek/Makefile
new file mode 100644
index 0000000..c46b906
--- /dev/null
+++ b/package/boot/uboot-mediatek/Makefile
@@ -0,0 +1,53 @@
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2020.10
+PKG_HASH:=0d481bbdc05c0ee74908ec2f56a6daa53166cc6a78a0e4fac2ac5d025770a622
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=mediatek
+  UBOOT_IMAGE:=u-boot-mtk.bin
+  DEFAULT:=y
+endef
+
+define U-Boot/mt7622
+  NAME:=MT7622
+  BUILD_SUBTARGET:=mt7622
+  UBOOT_CONFIG:=mt7622_rfb
+endef
+
+define U-Boot/mt7623a_unielec_u7623
+  NAME:=UniElec U7623 (mt7623)
+  BUILD_SUBTARGET:=mt7623
+  UBOOT_CONFIG:=mt7623a_unielec_u7623_02
+endef
+
+define U-Boot/mt7623n_bpir2
+  NAME:=Banana Pi R2 (mt7623)
+  BUILD_SUBTARGET:=mt7623
+  UBOOT_IMAGE:=u-boot.bin
+  UBOOT_CONFIG:=mt7623n_bpir2
+endef
+
+define U-Boot/mt7629
+  NAME:=MT7629
+  BUILD_SUBTARGET:=mt7629
+  UBOOT_CONFIG:=mt7629_rfb
+endef
+
+UBOOT_TARGETS := mt7629 mt7622 mt7623n_bpir2 mt7623a_unielec_u7623
+
+UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE)
+
+Build/Exports:=$(Host/Exports)
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch b/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch
new file mode 100644
index 0000000..dc3ebaf
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/002-nand-add-spi-nand-driver.patch
@@ -0,0 +1,8659 @@
+From de8b6cf615be20b25d0f3c817866de2c0d46a704 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Mon, 20 Apr 2020 17:10:05 +0800
+Subject: [PATCH 1/3] nand: add spi nand driver
+
+Add spi nand driver support for mt7622 based on nfi controller
+
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ drivers/mtd/Kconfig                           |    7 +
+ drivers/mtd/Makefile                          |    4 +
+ drivers/mtd/nand/raw/nand.c                   |    2 +
+ drivers/mtd/nandx/NOTICE                      |   52 +
+ drivers/mtd/nandx/Nandx.config                |   17 +
+ drivers/mtd/nandx/Nandx.mk                    |   91 ++
+ drivers/mtd/nandx/README                      |   31 +
+ drivers/mtd/nandx/core/Nandx.mk               |   38 +
+ drivers/mtd/nandx/core/core_io.c              |  735 +++++++++
+ drivers/mtd/nandx/core/core_io.h              |   39 +
+ drivers/mtd/nandx/core/nand/device_spi.c      |  200 +++
+ drivers/mtd/nandx/core/nand/device_spi.h      |  132 ++
+ drivers/mtd/nandx/core/nand/nand_spi.c        |  526 +++++++
+ drivers/mtd/nandx/core/nand/nand_spi.h        |   35 +
+ drivers/mtd/nandx/core/nand_base.c            |  304 ++++
+ drivers/mtd/nandx/core/nand_base.h            |   71 +
+ drivers/mtd/nandx/core/nand_chip.c            |  272 ++++
+ drivers/mtd/nandx/core/nand_chip.h            |  103 ++
+ drivers/mtd/nandx/core/nand_device.c          |  285 ++++
+ drivers/mtd/nandx/core/nand_device.h          |  608 ++++++++
+ drivers/mtd/nandx/core/nfi.h                  |   51 +
+ drivers/mtd/nandx/core/nfi/nfi_base.c         | 1357 +++++++++++++++++
+ drivers/mtd/nandx/core/nfi/nfi_base.h         |   95 ++
+ drivers/mtd/nandx/core/nfi/nfi_regs.h         |  114 ++
+ drivers/mtd/nandx/core/nfi/nfi_spi.c          |  689 +++++++++
+ drivers/mtd/nandx/core/nfi/nfi_spi.h          |   44 +
+ drivers/mtd/nandx/core/nfi/nfi_spi_regs.h     |   64 +
+ drivers/mtd/nandx/core/nfi/nfiecc.c           |  510 +++++++
+ drivers/mtd/nandx/core/nfi/nfiecc.h           |   90 ++
+ drivers/mtd/nandx/core/nfi/nfiecc_regs.h      |   51 +
+ drivers/mtd/nandx/driver/Nandx.mk             |   18 +
+ drivers/mtd/nandx/driver/bbt/bbt.c            |  408 +++++
+ drivers/mtd/nandx/driver/uboot/driver.c       |  574 +++++++
+ drivers/mtd/nandx/include/Nandx.mk            |   16 +
+ drivers/mtd/nandx/include/internal/bbt.h      |   62 +
+ .../mtd/nandx/include/internal/nandx_core.h   |  250 +++
+ .../mtd/nandx/include/internal/nandx_errno.h  |   40 +
+ .../mtd/nandx/include/internal/nandx_util.h   |  221 +++
+ drivers/mtd/nandx/include/uboot/nandx_os.h    |   78 +
+ include/configs/mt7622.h                      |   25 +
+ 40 files changed, 8309 insertions(+)
+ create mode 100644 drivers/mtd/nandx/NOTICE
+ create mode 100644 drivers/mtd/nandx/Nandx.config
+ create mode 100644 drivers/mtd/nandx/Nandx.mk
+ create mode 100644 drivers/mtd/nandx/README
+ create mode 100644 drivers/mtd/nandx/core/Nandx.mk
+ create mode 100644 drivers/mtd/nandx/core/core_io.c
+ create mode 100644 drivers/mtd/nandx/core/core_io.h
+ create mode 100644 drivers/mtd/nandx/core/nand/device_spi.c
+ create mode 100644 drivers/mtd/nandx/core/nand/device_spi.h
+ create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.c
+ create mode 100644 drivers/mtd/nandx/core/nand/nand_spi.h
+ create mode 100644 drivers/mtd/nandx/core/nand_base.c
+ create mode 100644 drivers/mtd/nandx/core/nand_base.h
+ create mode 100644 drivers/mtd/nandx/core/nand_chip.c
+ create mode 100644 drivers/mtd/nandx/core/nand_chip.h
+ create mode 100644 drivers/mtd/nandx/core/nand_device.c
+ create mode 100644 drivers/mtd/nandx/core/nand_device.h
+ create mode 100644 drivers/mtd/nandx/core/nfi.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.c
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_base.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_regs.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.c
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.c
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc.h
+ create mode 100644 drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+ create mode 100644 drivers/mtd/nandx/driver/Nandx.mk
+ create mode 100644 drivers/mtd/nandx/driver/bbt/bbt.c
+ create mode 100644 drivers/mtd/nandx/driver/uboot/driver.c
+ create mode 100644 drivers/mtd/nandx/include/Nandx.mk
+ create mode 100644 drivers/mtd/nandx/include/internal/bbt.h
+ create mode 100644 drivers/mtd/nandx/include/internal/nandx_core.h
+ create mode 100644 drivers/mtd/nandx/include/internal/nandx_errno.h
+ create mode 100644 drivers/mtd/nandx/include/internal/nandx_util.h
+ create mode 100644 drivers/mtd/nandx/include/uboot/nandx_os.h
+
+diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
+index 5e7571cf3d..34a59b44b9 100644
+--- a/drivers/mtd/Kconfig
++++ b/drivers/mtd/Kconfig
+@@ -101,6 +101,13 @@ config HBMC_AM654
+ 	 This is the driver for HyperBus controller on TI's AM65x and
+ 	 other SoCs
+ 
++config MTK_SPI_NAND
++	tristate "Mediatek SPI Nand"
++	depends on DM_MTD
++	help
++	  This option will support SPI Nand device via Mediatek
++	  NFI controller.
++
+ source "drivers/mtd/nand/Kconfig"
+ 
+ source "drivers/mtd/spi/Kconfig"
+diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
+index 318788c5e2..1df1031b23 100644
+--- a/drivers/mtd/Makefile
++++ b/drivers/mtd/Makefile
+@@ -41,3 +41,7 @@ obj-$(CONFIG_$(SPL_TPL_)SPI_FLASH_SUPPORT) += spi/
+ obj-$(CONFIG_SPL_UBI) += ubispl/
+ 
+ endif
++
++ifeq ($(CONFIG_MTK_SPI_NAND), y)
++include $(srctree)/drivers/mtd/nandx/Nandx.mk
++endif
+diff --git a/drivers/mtd/nand/raw/nand.c b/drivers/mtd/nand/raw/nand.c
+index 026419e4e6..4be0c7d8f3 100644
+--- a/drivers/mtd/nand/raw/nand.c
++++ b/drivers/mtd/nand/raw/nand.c
+@@ -91,8 +91,10 @@ static void nand_init_chip(int i)
+ 	if (board_nand_init(nand))
+ 		return;
+ 
++#ifndef CONFIG_MTK_SPI_NAND
+ 	if (nand_scan(mtd, maxchips))
+ 		return;
++#endif
+ 
+ 	nand_register(i, mtd);
+ }
+diff --git a/drivers/mtd/nandx/NOTICE b/drivers/mtd/nandx/NOTICE
+new file mode 100644
+index 0000000000..1a06ca3867
+--- /dev/null
++++ b/drivers/mtd/nandx/NOTICE
+@@ -0,0 +1,52 @@
++
++/*
++ * Nandx - Mediatek Common Nand Driver
++ * Copyright (C) 2017 MediaTek Inc.
++ *
++ * Nandx is dual licensed: you can use it either under the terms of
++ * the GPL, or the BSD license, at your option.
++ *
++ *  a) 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 library 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.
++ *
++ *     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 http://www.gnu.org/licenses/gpl-2.0.html for more details.
++ *
++ * Alternatively,
++ *
++ *  b) Redistribution and use in source and binary forms, with or
++ *     without modification, are permitted provided that the following
++ *     conditions are met:
++ *
++ *     1. Redistributions of source code must retain the above
++ *        copyright notice, this list of conditions and the following
++ *        disclaimer.
++ *     2. Redistributions in binary form must reproduce the above
++ *        copyright notice, this list of conditions and the following
++ *        disclaimer in the documentation and/or other materials
++ *        provided with the distribution.
++ *
++ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
++ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
++ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
++ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
++ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
++ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
++ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
++ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
++ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
++ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
++ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ */
++
++####################################################################################################
+\ No newline at end of file
+diff --git a/drivers/mtd/nandx/Nandx.config b/drivers/mtd/nandx/Nandx.config
+new file mode 100644
+index 0000000000..35705ee28d
+--- /dev/null
++++ b/drivers/mtd/nandx/Nandx.config
+@@ -0,0 +1,17 @@
++NANDX_SIMULATOR_SUPPORT := n
++NANDX_CTP_SUPPORT := n
++NANDX_DA_SUPPORT := n
++NANDX_PRELOADER_SUPPORT := n
++NANDX_LK_SUPPORT := n
++NANDX_KERNEL_SUPPORT := n
++NANDX_BROM_SUPPORT := n
++NANDX_UBOOT_SUPPORT := y
++NANDX_BBT_SUPPORT := y
++
++NANDX_NAND_SPI := y
++NANDX_NAND_SLC := n
++NANDX_NAND_MLC := n
++NANDX_NAND_TLC := n
++NANDX_NFI_BASE := y
++NANDX_NFI_ECC := y
++NANDX_NFI_SPI := y
+diff --git a/drivers/mtd/nandx/Nandx.mk b/drivers/mtd/nandx/Nandx.mk
+new file mode 100644
+index 0000000000..f5a6f2a628
+--- /dev/null
++++ b/drivers/mtd/nandx/Nandx.mk
+@@ -0,0 +1,91 @@
++#
++# Copyright (C) 2017 MediaTek Inc.
++# Licensed under either
++#     BSD Licence, (see NOTICE for more details)
++#     GNU General Public License, version 2.0, (see NOTICE for more details)
++#
++
++nandx_dir := $(shell dirname $(lastword $(MAKEFILE_LIST)))
++include $(nandx_dir)/Nandx.config
++
++ifeq ($(NANDX_SIMULATOR_SUPPORT), y)
++sim-obj :=
++sim-inc :=
++nandx-obj := sim-obj
++nandx-prefix := .
++nandx-postfix := %.o
++sim-inc += -I$(nandx-prefix)/include/internal
++sim-inc += -I$(nandx-prefix)/include/simulator
++endif
++
++ifeq ($(NANDX_CTP_SUPPORT), y)
++nandx-obj := C_SRC_FILES
++nandx-prefix := $(nandx_dir)
++nandx-postfix := %.c
++INC_DIRS += $(nandx_dir)/include/internal
++INC_DIRS += $(nandx_dir)/include/ctp
++endif
++
++ifeq ($(NANDX_DA_SUPPORT), y)
++nandx-obj := obj-y
++nandx-prefix := $(nandx_dir)
++nandx-postfix := %.o
++INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/internal
++INCLUDE_PATH += $(TOPDIR)/platform/$(CODE_BASE)/dev/nand/nandx/include/da
++endif
++
++ifeq ($(NANDX_PRELOADER_SUPPORT), y)
++nandx-obj := MOD_SRC
++nandx-prefix := $(nandx_dir)
++nandx-postfix := %.c
++C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/internal
++C_OPTION += -I$(MTK_PATH_PLATFORM)/src/drivers/nandx/include/preloader
++endif
++
++ifeq ($(NANDX_LK_SUPPORT), y)
++nandx-obj := MODULE_SRCS
++nandx-prefix := $(nandx_dir)
++nandx-postfix := %.c
++GLOBAL_INCLUDES += $(nandx_dir)/include/internal
++GLOBAL_INCLUDES += $(nandx_dir)/include/lk
++endif
++
++ifeq ($(NANDX_KERNEL_SUPPORT), y)
++nandx-obj := obj-y
++nandx-prefix := nandx
++nandx-postfix := %.o
++ccflags-y += -I$(nandx_dir)/include/internal
++ccflags-y += -I$(nandx_dir)/include/kernel
++endif
++
++ifeq ($(NANDX_UBOOT_SUPPORT), y)
++nandx-obj := obj-y
++nandx-prefix := nandx
++nandx-postfix := %.o
++ccflags-y += -I$(nandx_dir)/include/internal
++ccflags-y += -I$(nandx_dir)/include/uboot
++endif
++
++nandx-y :=
++include $(nandx_dir)/core/Nandx.mk
++nandx-target := $(nandx-prefix)/core/$(nandx-postfix)
++$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y))
++
++
++nandx-y :=
++include $(nandx_dir)/driver/Nandx.mk
++nandx-target := $(nandx-prefix)/driver/$(nandx-postfix)
++$(nandx-obj) += $(patsubst %.c, $(nandx-target), $(nandx-y))
++
++ifeq ($(NANDX_SIMULATOR_SUPPORT), y)
++cc := gcc
++CFLAGS += $(sim-inc)
++
++.PHONY:nandx
++nandx: $(sim-obj)
++	$(cc)  $(sim-obj) -o nandx
++
++.PHONY:clean
++clean:
++	rm -rf $(sim-obj) nandx
++endif
+diff --git a/drivers/mtd/nandx/README b/drivers/mtd/nandx/README
+new file mode 100644
+index 0000000000..0feaeaeb88
+--- /dev/null
++++ b/drivers/mtd/nandx/README
+@@ -0,0 +1,31 @@
++
++                          NAND2.0
++                ===============================
++
++    NAND2.0 is a common nand driver which designed for accessing
++different type of NANDs(SLC, SPI-NAND, MLC, TLC) on various OS. This
++driver can work on mostly SoCs of Mediatek.
++
++    Although there already has a common nand driver, it doesn't cover
++SPI-NAND, and not match our IC-Verification's reqirement. We need
++a driver that can be exten or cut easily.
++
++    This driver is base on NANDX & SLC. We try to refactor structures,
++and make them inheritable. We also refactor some operations' flow
++principally for adding SPI-NAND support.
++
++    This driver's architecture is like:
++
++          Driver @LK/Uboot/DA...           |IC verify/other purposes
++    ----------------------------------------------------------------
++      partition       |        BBM         |
++    -------------------------------------- |       extend_core
++             nandx_core/core_io            |
++    ----------------------------------------------------------------
++             nand_chip/nand_base           |
++    -------------------------------------- |        extend_nfi
++      nand_device     |    nfi/nfi_base    |
++
++    Any block of above graph can be extended at your will, if you
++want add new feature into this code, please make sure that your code
++would follow the framework, and we will be appreciated about it.
+diff --git a/drivers/mtd/nandx/core/Nandx.mk b/drivers/mtd/nandx/core/Nandx.mk
+new file mode 100644
+index 0000000000..7a5661c044
+--- /dev/null
++++ b/drivers/mtd/nandx/core/Nandx.mk
+@@ -0,0 +1,38 @@
++#
++# Copyright (C) 2017 MediaTek Inc.
++# Licensed under either
++#     BSD Licence, (see NOTICE for more details)
++#     GNU General Public License, version 2.0, (see NOTICE for more details)
++#
++
++nandx-y += nand_device.c
++nandx-y += nand_base.c
++nandx-y += nand_chip.c
++nandx-y += core_io.c
++
++nandx-header-y += nand_device.h
++nandx-header-y += nand_base.h
++nandx-header-y += nand_chip.h
++nandx-header-y += core_io.h
++nandx-header-y += nfi.h
++
++nandx-$(NANDX_NAND_SPI) += nand/device_spi.c
++nandx-$(NANDX_NAND_SPI) += nand/nand_spi.c
++nandx-$(NANDX_NAND_SLC) += nand/device_slc.c
++nandx-$(NANDX_NAND_SLC) += nand/nand_slc.c
++
++nandx-header-$(NANDX_NAND_SPI) += nand/device_spi.h
++nandx-header-$(NANDX_NAND_SPI) += nand/nand_spi.h
++nandx-header-$(NANDX_NAND_SLC) += nand/device_slc.h
++nandx-header-$(NANDX_NAND_SLC) += nand/nand_slc.h
++
++nandx-$(NANDX_NFI_BASE) += nfi/nfi_base.c
++nandx-$(NANDX_NFI_ECC) += nfi/nfiecc.c
++nandx-$(NANDX_NFI_SPI) += nfi/nfi_spi.c
++
++nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_base.h
++nandx-header-$(NANDX_NFI_BASE) += nfi/nfi_regs.h
++nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc.h
++nandx-header-$(NANDX_NFI_ECC) += nfi/nfiecc_regs.h
++nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi.h
++nandx-header-$(NANDX_NFI_SPI) += nfi/nfi_spi_regs.h
+diff --git a/drivers/mtd/nandx/core/core_io.c b/drivers/mtd/nandx/core/core_io.c
+new file mode 100644
+index 0000000000..716eeed38d
+--- /dev/null
++++ b/drivers/mtd/nandx/core/core_io.c
+@@ -0,0 +1,735 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++/*NOTE: switch cache/multi*/
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "nand_chip.h"
++#include "core_io.h"
++
++static struct nandx_desc *g_nandx;
++
++static inline bool is_sector_align(u64 val)
++{
++	return reminder(val, g_nandx->chip->sector_size) ? false : true;
++}
++
++static inline bool is_page_align(u64 val)
++{
++	return reminder(val, g_nandx->chip->page_size) ? false : true;
++}
++
++static inline bool is_block_align(u64 val)
++{
++	return reminder(val, g_nandx->chip->block_size) ? false : true;
++}
++
++static inline u32 page_sectors(void)
++{
++	return div_down(g_nandx->chip->page_size, g_nandx->chip->sector_size);
++}
++
++static inline u32 sector_oob(void)
++{
++	return div_down(g_nandx->chip->oob_size, page_sectors());
++}
++
++static inline u32 sector_padded_size(void)
++{
++	return g_nandx->chip->sector_size + g_nandx->chip->sector_spare_size;
++}
++
++static inline u32 page_padded_size(void)
++{
++	return page_sectors() * sector_padded_size();
++}
++
++static inline u32 offset_to_padded_col(u64 offset)
++{
++	struct nandx_desc *nandx = g_nandx;
++	u32 col, sectors;
++
++	col = reminder(offset, nandx->chip->page_size);
++	sectors = div_down(col, nandx->chip->sector_size);
++
++	return col + sectors * nandx->chip->sector_spare_size;
++}
++
++static inline u32 offset_to_row(u64 offset)
++{
++	return div_down(offset, g_nandx->chip->page_size);
++}
++
++static inline u32 offset_to_col(u64 offset)
++{
++	return reminder(offset, g_nandx->chip->page_size);
++}
++
++static inline u32 oob_upper_size(void)
++{
++	return g_nandx->ecc_en ? g_nandx->chip->oob_size :
++	       g_nandx->chip->sector_spare_size * page_sectors();
++}
++
++static inline bool is_upper_oob_align(u64 val)
++{
++	return reminder(val, oob_upper_size()) ? false : true;
++}
++
++#define prepare_op(_op, _row, _col, _len, _data, _oob) \
++	do { \
++		(_op).row = (_row); \
++		(_op).col = (_col); \
++		(_op).len = (_len); \
++		(_op).data = (_data); \
++		(_op).oob = (_oob); \
++	} while (0)
++
++static int operation_multi(enum nandx_op_mode mode, u8 *data, u8 *oob,
++			   u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++	u32 row = offset_to_row(offset);
++	u32 col = offset_to_padded_col(offset);
++
++	if (nandx->mode == NANDX_IDLE) {
++		nandx->mode = mode;
++		nandx->ops_current = 0;
++	} else if (nandx->mode != mode) {
++		pr_info("forbid mixed operations.\n");
++		return -EOPNOTSUPP;
++	}
++
++	prepare_op(nandx->ops[nandx->ops_current], row, col, len, data, oob);
++	nandx->ops_current++;
++
++	if (nandx->ops_current == nandx->ops_multi_len)
++		return nandx_sync();
++
++	return nandx->ops_multi_len - nandx->ops_current;
++}
++
++static int operation_sequent(enum nandx_op_mode mode, u8 *data, u8 *oob,
++			     u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++	struct nand_chip *chip = nandx->chip;
++	u32 row = offset_to_row(offset);
++	func_chip_ops chip_ops;
++	u8 *ref_data = data, *ref_oob = oob;
++	int align, ops, row_step;
++	int i, rem;
++
++	align = data ? chip->page_size : oob_upper_size();
++	ops = data ? div_down(len, align) : div_down(len, oob_upper_size());
++	row_step = 1;
++
++	switch (mode) {
++	case NANDX_ERASE:
++		chip_ops = chip->erase_block;
++		align = chip->block_size;
++		ops = div_down(len, align);
++		row_step = chip->block_pages;
++		break;
++
++	case NANDX_READ:
++		chip_ops = chip->read_page;
++		break;
++
++	case NANDX_WRITE:
++		chip_ops = chip->write_page;
++		break;
++
++	default:
++		return -EINVAL;
++	}
++
++	if (!data) {
++		ref_data = nandx->head_buf;
++		memset(ref_data, 0xff, chip->page_size);
++	}
++
++	if (!oob) {
++		ref_oob = nandx->head_buf + chip->page_size;
++		memset(ref_oob, 0xff, oob_upper_size());
++	}
++
++	for (i = 0; i < ops; i++) {
++		prepare_op(nandx->ops[nandx->ops_current],
++			   row + i * row_step, 0, align, ref_data, ref_oob);
++		nandx->ops_current++;
++		/* if data or oob is null, nandx->head_buf or
++		 * nandx->head_buf + chip->page_size should not been used
++		 * so, here it is safe to use the buf.
++		 */
++		ref_data = data ? ref_data + chip->page_size : nandx->head_buf;
++		ref_oob = oob ? ref_oob + oob_upper_size() :
++			  nandx->head_buf + chip->page_size;
++	}
++
++	if (nandx->mode == NANDX_WRITE) {
++		rem = reminder(nandx->ops_current, nandx->min_write_pages);
++		if (rem)
++			return nandx->min_write_pages - rem;
++	}
++
++	nandx->ops_current = 0;
++	return chip_ops(chip, nandx->ops, ops);
++}
++
++static int read_pages(u8 *data, u8 *oob, u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++	struct nand_chip *chip = nandx->chip;
++	struct nandx_split64 split = {0};
++	u8 *ref_data = data, *ref_oob;
++	u32 row, col;
++	int ret = 0, i, ops;
++	u32 head_offset = 0;
++	u64 val;
++
++	if (!data)
++		return operation_sequent(NANDX_READ, NULL, oob, offset, len);
++
++	ref_oob = oob ? oob : nandx->head_buf + chip->page_size;
++
++	nandx_split(&split, offset, len, val, chip->page_size);
++
++	if (split.head_len) {
++		row = offset_to_row(split.head);
++		col = offset_to_col(split.head);
++		prepare_op(nandx->ops[nandx->ops_current], row, 0,
++			   chip->page_size,
++			   nandx->head_buf, ref_oob);
++		nandx->ops_current++;
++
++		head_offset = col;
++
++		ref_data += split.head_len;
++		ref_oob = oob ? ref_oob + oob_upper_size() :
++			  nandx->head_buf + chip->page_size;
++	}
++
++	if (split.body_len) {
++		ops = div_down(split.body_len, chip->page_size);
++		row = offset_to_row(split.body);
++		for (i = 0; i < ops; i++) {
++			prepare_op(nandx->ops[nandx->ops_current],
++				   row + i, 0, chip->page_size,
++				   ref_data, ref_oob);
++			nandx->ops_current++;
++			ref_data += chip->page_size;
++			ref_oob = oob ? ref_oob + oob_upper_size() :
++				  nandx->head_buf + chip->page_size;
++		}
++	}
++
++	if (split.tail_len) {
++		row = offset_to_row(split.tail);
++		prepare_op(nandx->ops[nandx->ops_current], row, 0,
++			   chip->page_size, nandx->tail_buf, ref_oob);
++		nandx->ops_current++;
++	}
++
++	ret = chip->read_page(chip, nandx->ops, nandx->ops_current);
++
++	if (split.head_len)
++		memcpy(data, nandx->head_buf + head_offset, split.head_len);
++	if (split.tail_len)
++		memcpy(ref_data, nandx->tail_buf, split.tail_len);
++
++	nandx->ops_current = 0;
++	return ret;
++}
++
++int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++
++	if (!len || len > nandx->info.total_size)
++		return -EINVAL;
++	if (div_up(len, nandx->chip->page_size) > nandx->ops_len)
++		return -EINVAL;
++	if (!data && !oob)
++		return -EINVAL;
++	/**
++	 * as design, oob not support partial read
++	 * and, the length of oob buf should be oob size aligned
++	 */
++	if (!data && !is_upper_oob_align(len))
++		return -EINVAL;
++
++	if (g_nandx->multi_en) {
++		/* as design, there only 2 buf for partial read,
++		 * if partial read allowed for multi read,
++		 * there are not enough buf
++		 */
++		if (!is_sector_align(offset))
++			return -EINVAL;
++		if (data && !is_sector_align(len))
++			return -EINVAL;
++		return operation_multi(NANDX_READ, data, oob, offset, len);
++	}
++
++	nandx->ops_current = 0;
++	nandx->mode = NANDX_IDLE;
++	return read_pages(data, oob, offset, len);
++}
++
++static int write_pages(u8 *data, u8 *oob, u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++	struct nand_chip *chip = nandx->chip;
++	struct nandx_split64 split = {0};
++	int ret, rem, i, ops;
++	u32 row, col;
++	u8 *ref_oob = oob;
++	u64 val;
++
++	nandx->mode = NANDX_WRITE;
++
++	if (!data)
++		return operation_sequent(NANDX_WRITE, NULL, oob, offset, len);
++
++	if (!oob) {
++		ref_oob = nandx->head_buf + chip->page_size;
++		memset(ref_oob, 0xff, oob_upper_size());
++	}
++
++	nandx_split(&split, offset, len, val, chip->page_size);
++
++	/*NOTE: slc can support sector write, here copy too many data.*/
++	if (split.head_len) {
++		row = offset_to_row(split.head);
++		col = offset_to_col(split.head);
++		memset(nandx->head_buf, 0xff, page_padded_size());
++		memcpy(nandx->head_buf + col, data, split.head_len);
++		prepare_op(nandx->ops[nandx->ops_current], row, 0,
++			   chip->page_size, nandx->head_buf, ref_oob);
++		nandx->ops_current++;
++
++		data += split.head_len;
++		ref_oob = oob ? ref_oob + oob_upper_size() :
++			  nandx->head_buf + chip->page_size;
++	}
++
++	if (split.body_len) {
++		row = offset_to_row(split.body);
++		ops = div_down(split.body_len, chip->page_size);
++		for (i = 0; i < ops; i++) {
++			prepare_op(nandx->ops[nandx->ops_current],
++				   row + i, 0, chip->page_size, data, ref_oob);
++			nandx->ops_current++;
++			data += chip->page_size;
++			ref_oob = oob ? ref_oob + oob_upper_size() :
++				  nandx->head_buf + chip->page_size;
++		}
++	}
++
++	if (split.tail_len) {
++		row = offset_to_row(split.tail);
++		memset(nandx->tail_buf, 0xff, page_padded_size());
++		memcpy(nandx->tail_buf, data, split.tail_len);
++		prepare_op(nandx->ops[nandx->ops_current], row, 0,
++			   chip->page_size, nandx->tail_buf, ref_oob);
++		nandx->ops_current++;
++	}
++
++	rem = reminder(nandx->ops_current, nandx->min_write_pages);
++	if (rem)
++		return nandx->min_write_pages - rem;
++
++	ret = chip->write_page(chip, nandx->ops, nandx->ops_current);
++
++	nandx->ops_current = 0;
++	nandx->mode = NANDX_IDLE;
++	return ret;
++}
++
++int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++
++	if (!len || len > nandx->info.total_size)
++		return -EINVAL;
++	if (div_up(len, nandx->chip->page_size) > nandx->ops_len)
++		return -EINVAL;
++	if (!data && !oob)
++		return -EINVAL;
++	if (!data && !is_upper_oob_align(len))
++		return -EINVAL;
++
++	if (nandx->multi_en) {
++		if (!is_page_align(offset))
++			return -EINVAL;
++		if (data && !is_page_align(len))
++			return -EINVAL;
++
++		return operation_multi(NANDX_WRITE, data, oob, offset, len);
++	}
++
++	return write_pages(data, oob, offset, len);
++}
++
++int nandx_erase(u64 offset, size_t len)
++{
++	struct nandx_desc *nandx = g_nandx;
++
++	if (!len || len > nandx->info.total_size)
++		return -EINVAL;
++	if (div_down(len, nandx->chip->block_size) > nandx->ops_len)
++		return -EINVAL;
++	if (!is_block_align(offset) || !is_block_align(len))
++		return -EINVAL;
++
++	if (g_nandx->multi_en)
++		return operation_multi(NANDX_ERASE, NULL, NULL, offset, len);
++
++	nandx->ops_current = 0;
++	nandx->mode = NANDX_IDLE;
++	return operation_sequent(NANDX_ERASE, NULL, NULL, offset, len);
++}
++
++int nandx_sync(void)
++{
++	struct nandx_desc *nandx = g_nandx;
++	struct nand_chip *chip = nandx->chip;
++	func_chip_ops chip_ops;
++	int ret, i, rem;
++
++	if (!nandx->ops_current)
++		return 0;
++
++	rem = reminder(nandx->ops_current, nandx->ops_multi_len);
++	if (nandx->multi_en && rem) {
++		ret = -EIO;
++		goto error;
++	}
++
++	switch (nandx->mode) {
++	case NANDX_IDLE:
++		return 0;
++	case NANDX_ERASE:
++		chip_ops = chip->erase_block;
++		break;
++	case NANDX_READ:
++		chip_ops = chip->read_page;
++		break;
++	case NANDX_WRITE:
++		chip_ops = chip->write_page;
++		break;
++	default:
++		return -EINVAL;
++	}
++
++	rem = reminder(nandx->ops_current, nandx->min_write_pages);
++	if (!nandx->multi_en && nandx->mode == NANDX_WRITE && rem) {
++		/* in one process of program, only allow 2 pages to do partial
++		 * write, here we supposed 1st buf would be used, and 2nd
++		 * buf should be not used.
++		 */
++		memset(nandx->tail_buf, 0xff,
++		       chip->page_size + oob_upper_size());
++		for (i = 0; i < rem; i++) {
++			prepare_op(nandx->ops[nandx->ops_current],
++				   nandx->ops[nandx->ops_current - 1].row + 1,
++				   0, chip->page_size, nandx->tail_buf,
++				   nandx->tail_buf + chip->page_size);
++			nandx->ops_current++;
++		}
++	}
++
++	ret = chip_ops(nandx->chip, nandx->ops, nandx->ops_current);
++
++error:
++	nandx->mode = NANDX_IDLE;
++	nandx->ops_current = 0;
++
++	return ret;
++}
++
++int nandx_ioctl(int cmd, void *arg)
++{
++	struct nandx_desc *nandx = g_nandx;
++	struct nand_chip *chip = nandx->chip;
++	int ret = 0;
++
++	switch (cmd) {
++	case CORE_CTRL_NAND_INFO:
++		*(struct nandx_info *)arg = nandx->info;
++		break;
++
++	case CHIP_CTRL_OPS_MULTI:
++		ret = chip->chip_ctrl(chip, cmd, arg);
++		if (!ret)
++			nandx->multi_en = *(bool *)arg;
++		break;
++
++	case NFI_CTRL_ECC:
++		ret = chip->chip_ctrl(chip, cmd, arg);
++		if (!ret)
++			nandx->ecc_en = *(bool *)arg;
++		break;
++
++	default:
++		ret = chip->chip_ctrl(chip, cmd, arg);
++		break;
++	}
++
++	return ret;
++}
++
++bool nandx_is_bad_block(u64 offset)
++{
++	struct nandx_desc *nandx = g_nandx;
++
++	prepare_op(nandx->ops[0], offset_to_row(offset), 0,
++		   nandx->chip->page_size, nandx->head_buf,
++		   nandx->head_buf + nandx->chip->page_size);
++
++	return nandx->chip->is_bad_block(nandx->chip, nandx->ops, 1);
++}
++
++int nandx_suspend(void)
++{
++	return g_nandx->chip->suspend(g_nandx->chip);
++}
++
++int nandx_resume(void)
++{
++	return g_nandx->chip->resume(g_nandx->chip);
++}
++
++int nandx_init(struct nfi_resource *res)
++{
++	struct nand_chip *chip;
++	struct nandx_desc *nandx;
++	int ret = 0;
++
++	if (!res)
++		return -EINVAL;
++
++	chip = nand_chip_init(res);
++	if (!chip) {
++		pr_info("nand chip init fail.\n");
++		return -EFAULT;
++	}
++
++	nandx = (struct nandx_desc *)mem_alloc(1, sizeof(struct nandx_desc));
++	if (!nandx)
++		return -ENOMEM;
++
++	g_nandx = nandx;
++
++	nandx->chip = chip;
++	nandx->min_write_pages = chip->min_program_pages;
++	nandx->ops_multi_len = nandx->min_write_pages * chip->plane_num;
++	nandx->ops_len = chip->block_pages * chip->plane_num;
++	nandx->ops = mem_alloc(1, sizeof(struct nand_ops) * nandx->ops_len);
++	if (!nandx->ops) {
++		ret = -ENOMEM;
++		goto ops_error;
++	}
++
++#if NANDX_BULK_IO_USE_DRAM
++	nandx->head_buf = NANDX_CORE_BUF_ADDR;
++#else
++	nandx->head_buf = mem_alloc(2, page_padded_size());
++#endif
++	if (!nandx->head_buf) {
++		ret = -ENOMEM;
++		goto buf_error;
++	}
++	nandx->tail_buf = nandx->head_buf + page_padded_size();
++	memset(nandx->head_buf, 0xff, 2 * page_padded_size());
++	nandx->multi_en = false;
++	nandx->ecc_en = false;
++	nandx->ops_current = 0;
++	nandx->mode = NANDX_IDLE;
++
++	nandx->info.max_io_count = nandx->ops_len;
++	nandx->info.min_write_pages = nandx->min_write_pages;
++	nandx->info.plane_num = chip->plane_num;
++	nandx->info.oob_size = chip->oob_size;
++	nandx->info.page_parity_size = chip->sector_spare_size * page_sectors();
++	nandx->info.page_size = chip->page_size;
++	nandx->info.block_size = chip->block_size;
++	nandx->info.total_size = chip->block_size * chip->block_num;
++	nandx->info.fdm_ecc_size = chip->fdm_ecc_size;
++	nandx->info.fdm_reg_size = chip->fdm_reg_size;
++	nandx->info.ecc_strength = chip->ecc_strength;
++	nandx->info.sector_size = chip->sector_size;
++
++	return 0;
++
++buf_error:
++#if !NANDX_BULK_IO_USE_DRAM
++	mem_free(nandx->head_buf);
++#endif
++ops_error:
++	mem_free(nandx);
++
++	return ret;
++}
++
++void nandx_exit(void)
++{
++	nand_chip_exit(g_nandx->chip);
++#if !NANDX_BULK_IO_USE_DRAM
++	mem_free(g_nandx->head_buf);
++#endif
++	mem_free(g_nandx->ops);
++	mem_free(g_nandx);
++}
++
++#ifdef NANDX_UNIT_TEST
++static void dump_buf(u8 *buf, u32 len)
++{
++	u32 i;
++
++	pr_info("dump buf@0x%X start", (u32)buf);
++	for (i = 0; i < len; i++) {
++		if (!reminder(i, 16))
++			pr_info("\n0x");
++		pr_info("%x ", buf[i]);
++	}
++	pr_info("\ndump buf done.\n");
++}
++
++int nandx_unit_test(u64 offset, size_t len)
++{
++	u8 *src_buf, *dst_buf;
++	u32 i, j;
++	int ret;
++
++	if (!len || len > g_nandx->chip->block_size)
++		return -EINVAL;
++
++#if NANDX_BULK_IO_USE_DRAM
++	src_buf = NANDX_UT_SRC_ADDR;
++	dst_buf = NANDX_UT_DST_ADDR;
++
++#else
++	src_buf = mem_alloc(1, g_nandx->chip->page_size);
++	if (!src_buf)
++		return -ENOMEM;
++	dst_buf = mem_alloc(1, g_nandx->chip->page_size);
++	if (!dst_buf) {
++		mem_free(src_buf);
++		return -ENOMEM;
++	}
++#endif
++
++	pr_info("%s: src_buf address 0x%x, dst_buf address 0x%x\n",
++		 __func__, (int)((unsigned long)src_buf),
++		 (int)((unsigned long)dst_buf));
++
++	memset(dst_buf, 0, g_nandx->chip->page_size);
++	pr_info("read page 0 data...!\n");
++	ret = nandx_read(dst_buf, NULL, 0, g_nandx->chip->page_size);
++	if (ret < 0) {
++		pr_info("read fail with ret %d\n", ret);
++	} else {
++		pr_info("read page success!\n");
++	}
++
++	for (i = 0; i < g_nandx->chip->page_size; i++) {
++		src_buf[i] = 0x5a;
++	}
++
++	ret = nandx_erase(offset, g_nandx->chip->block_size);
++	if (ret < 0) {
++		pr_info("erase fail with ret %d\n", ret);
++		goto error;
++	}
++
++	for (j = 0; j < g_nandx->chip->block_pages; j++) {
++		memset(dst_buf, 0, g_nandx->chip->page_size);
++		pr_info("check data after erase...!\n");
++		ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
++		if (ret < 0) {
++			pr_info("read fail with ret %d\n", ret);
++			goto error;
++		}
++
++		for (i = 0; i < g_nandx->chip->page_size; i++) {
++			if (dst_buf[i] != 0xff) {
++				pr_info("read after erase, check fail @%d\n", i);
++				pr_info("all data should be 0xff\n");
++				ret = -ENANDERASE;
++				dump_buf(dst_buf, 128);
++				//goto error;
++				break;
++			}
++		}
++
++		pr_info("write data...!\n");
++		ret = nandx_write(src_buf, NULL, offset, g_nandx->chip->page_size);
++		if (ret < 0) {
++			pr_info("write fail with ret %d\n", ret);
++			goto error;
++		}
++
++		memset(dst_buf, 0, g_nandx->chip->page_size);
++		pr_info("read data...!\n");
++		ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
++		if (ret < 0) {
++			pr_info("read fail with ret %d\n", ret);
++			goto error;
++		}
++
++		for (i = 0; i < g_nandx->chip->page_size; i++) {
++			if (dst_buf[i] != src_buf[i]) {
++				pr_info("read after write, check fail @%d\n", i);
++				pr_info("dst_buf should be same as src_buf\n");
++				ret = -EIO;
++				dump_buf(src_buf + i, 128);
++				dump_buf(dst_buf + i, 128);
++				break;
++			}
++		}
++
++		pr_err("%s %d %s@%d\n", __func__, __LINE__, ret?"Failed":"OK", j);
++		if (ret)
++			break;
++
++		offset += g_nandx->chip->page_size;
++	}
++
++	ret = nandx_erase(offset, g_nandx->chip->block_size);
++	if (ret < 0) {
++		pr_info("erase fail with ret %d\n", ret);
++		goto error;
++	}
++
++	memset(dst_buf, 0, g_nandx->chip->page_size);
++	ret = nandx_read(dst_buf, NULL, offset, g_nandx->chip->page_size);
++	if (ret < 0) {
++		pr_info("read fail with ret %d\n", ret);
++		goto error;
++	}
++
++	for (i = 0; i < g_nandx->chip->page_size; i++) {
++		if (dst_buf[i] != 0xff) {
++			pr_info("read after erase, check fail\n");
++			pr_info("all data should be 0xff\n");
++			ret = -ENANDERASE;
++			dump_buf(dst_buf, 128);
++			goto error;
++		}
++	}
++
++	return 0;
++
++error:
++#if !NANDX_BULK_IO_USE_DRAM
++	mem_free(src_buf);
++	mem_free(dst_buf);
++#endif
++	return ret;
++}
++#endif
+diff --git a/drivers/mtd/nandx/core/core_io.h b/drivers/mtd/nandx/core/core_io.h
+new file mode 100644
+index 0000000000..edcb60908a
+--- /dev/null
++++ b/drivers/mtd/nandx/core/core_io.h
+@@ -0,0 +1,39 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __CORE_IO_H__
++#define __CORE_IO_H__
++
++typedef int (*func_chip_ops)(struct nand_chip *, struct nand_ops *,
++			     int);
++
++enum nandx_op_mode {
++	NANDX_IDLE,
++	NANDX_WRITE,
++	NANDX_READ,
++	NANDX_ERASE
++};
++
++struct nandx_desc {
++	struct nand_chip *chip;
++	struct nandx_info info;
++	enum nandx_op_mode mode;
++
++	bool multi_en;
++	bool ecc_en;
++
++	struct nand_ops *ops;
++	int ops_len;
++	int ops_multi_len;
++	int ops_current;
++	int min_write_pages;
++
++	u8 *head_buf;
++	u8 *tail_buf;
++};
++
++#endif /* __CORE_IO_H__ */
+diff --git a/drivers/mtd/nandx/core/nand/device_spi.c b/drivers/mtd/nandx/core/nand/device_spi.c
+new file mode 100644
+index 0000000000..db338c28c2
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand/device_spi.c
+@@ -0,0 +1,200 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "../nand_device.h"
++#include "device_spi.h"
++
++/* spi nand basic commands */
++static struct nand_cmds spi_cmds = {
++	.reset = 0xff,
++	.read_id = 0x9f,
++	.read_status = 0x0f,
++	.read_param_page = 0x03,
++	.set_feature = 0x1f,
++	.get_feature = 0x0f,
++	.read_1st = 0x13,
++	.read_2nd = -1,
++	.random_out_1st = 0x03,
++	.random_out_2nd = -1,
++	.program_1st = 0x02,
++	.program_2nd = 0x10,
++	.erase_1st = 0xd8,
++	.erase_2nd = -1,
++	.read_cache = 0x30,
++	.read_cache_last = 0x3f,
++	.program_cache = 0x02
++};
++
++/* spi nand extend commands */
++static struct spi_extend_cmds spi_extend_cmds = {
++	.die_select = 0xc2,
++	.write_enable = 0x06
++};
++
++/* means the start bit of addressing type */
++static struct nand_addressing spi_addressing = {
++	.row_bit_start = 0,
++	.block_bit_start = 0,
++	.plane_bit_start = 12,
++	.lun_bit_start = 0,
++};
++
++/* spi nand endurance */
++static struct nand_endurance spi_endurance = {
++	.pe_cycle = 100000,
++	.ecc_req = 1,
++	.max_bitflips = 1
++};
++
++/* array_busy, write_protect, erase_fail, program_fail */
++static struct nand_status spi_status[] = {
++	{.array_busy = BIT(0),
++	.write_protect = BIT(1),
++	.erase_fail = BIT(2),
++	.program_fail = BIT(3)}
++};
++
++/* measure time by the us */
++static struct nand_array_timing spi_array_timing = {
++	.tRST = 500,
++	.tWHR = 1,
++	.tR = 25,
++	.tRCBSY = 25,
++	.tFEAT = 1,
++	.tPROG = 600,
++	.tPCBSY = 600,
++	.tBERS = 10000,
++	.tDBSY = 1
++};
++
++/* spi nand device table */
++static struct device_spi spi_nand[] = {
++	{
++		NAND_DEVICE("W25N01GV",
++			    NAND_PACK_ID(0xef, 0xaa, 0x21, 0, 0, 0, 0, 0),
++			    3, 0, 3, 3,
++			    1, 1, 1, 1024, KB(128), KB(2), 64, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 0),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	},
++	{
++		NAND_DEVICE("MX35LF1G",
++			    NAND_PACK_ID(0xc2, 0x12, 0x21, 0, 0, 0, 0, 0),
++			    2, 0, 3, 3,
++			    1, 1, 1, 1024, KB(128), KB(2), 64, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 1),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	},
++	{
++		NAND_DEVICE("MT29F4G01ABAFDWB",
++			    NAND_PACK_ID(0x2c, 0x34, 0, 0, 0, 0, 0, 0),
++			    2, 0, 3, 3,
++			    1, 1, 1, 2048, KB(256), KB(4), 256, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 1),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	},
++	{
++		NAND_DEVICE("GD5F4GQ4UB",
++			    NAND_PACK_ID(0xc8, 0xd4, 0, 0, 0, 0, 0, 0),
++			    2, 0, 3, 3,
++			    1, 1, 1, 2048, KB(256), KB(4), 256, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 1),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	},
++	{
++		NAND_DEVICE("TC58CVG2S0HRAIJ",
++			    NAND_PACK_ID(0x98, 0xED, 0x51, 0, 0, 0, 0, 0),
++			    3, 0, 3, 3,
++			    1, 1, 1, 2048, KB(256), KB(4), 256, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 1),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	},
++	{
++		NAND_DEVICE("NO-DEVICE",
++			    NAND_PACK_ID(0, 0, 0, 0, 0, 0, 0, 0), 0, 0, 0, 0,
++			    0, 0, 0, 0, 0, 0, 0, 1,
++			    &spi_cmds, &spi_addressing, &spi_status[0],
++			    &spi_endurance, &spi_array_timing),
++		{
++			NAND_SPI_PROTECT(0xa0, 1, 2, 6),
++			NAND_SPI_CONFIG(0xb0, 4, 6, 0),
++			NAND_SPI_STATUS(0xc0, 4, 5),
++			NAND_SPI_CHARACTER(0xff, 0xff, 0xff, 0xff)
++		},
++		&spi_extend_cmds, 0xff, 0xff
++	}
++};
++
++u8 spi_replace_rx_cmds(u8 mode)
++{
++	u8 rx_replace_cmds[] = {0x03, 0x3b, 0x6b, 0xbb, 0xeb};
++
++	return rx_replace_cmds[mode];
++}
++
++u8 spi_replace_tx_cmds(u8 mode)
++{
++	u8 tx_replace_cmds[] = {0x02, 0x32};
++
++	return tx_replace_cmds[mode];
++}
++
++u8 spi_replace_rx_col_cycle(u8 mode)
++{
++	u8 rx_replace_col_cycle[] = {3, 3, 3, 3, 4};
++
++	return rx_replace_col_cycle[mode];
++}
++
++u8 spi_replace_tx_col_cycle(u8 mode)
++{
++	u8 tx_replace_col_cycle[] = {2, 2};
++
++	return tx_replace_col_cycle[mode];
++}
++
++struct nand_device *nand_get_device(int index)
++{
++	return &spi_nand[index].dev;
++}
++
+diff --git a/drivers/mtd/nandx/core/nand/device_spi.h b/drivers/mtd/nandx/core/nand/device_spi.h
+new file mode 100644
+index 0000000000..1676b61fc8
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand/device_spi.h
+@@ -0,0 +1,132 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __DEVICE_SPI_H__
++#define __DEVICE_SPI_H__
++
++/*
++ * extend commands
++ * @die_select: select nand device die command
++ * @write_enable: enable write command before write data to spi nand
++ *    spi nand device will auto to be disable after write done
++ */
++struct spi_extend_cmds {
++	short die_select;
++	short write_enable;
++};
++
++/*
++ * protection feature register
++ * @addr: register address
++ * @wp_en_bit: write protection enable bit
++ * @bp_start_bit: block protection mask start bit
++ * @bp_end_bit: block protection mask end bit
++ */
++struct feature_protect {
++	u8 addr;
++	u8 wp_en_bit;
++	u8 bp_start_bit;
++	u8 bp_end_bit;
++};
++
++/*
++ * configuration feature register
++ * @addr: register address
++ * @ecc_en_bit: in-die ecc enable bit
++ * @otp_en_bit: enter otp access mode bit
++ * @need_qe: quad io enable bit
++ */
++struct feature_config {
++	u8 addr;
++	u8 ecc_en_bit;
++	u8 otp_en_bit;
++	u8 need_qe;
++};
++
++/*
++ * status feature register
++ * @addr: register address
++ * @ecc_start_bit: ecc status mask start bit for error bits number
++ * @ecc_end_bit: ecc status mask end bit for error bits number
++ * note that:
++ *   operations status (ex. array busy status) could see on struct nand_status
++ */
++struct feature_status {
++	u8 addr;
++	u8 ecc_start_bit;
++	u8 ecc_end_bit;
++};
++
++/*
++ * character feature register
++ * @addr: register address
++ * @die_sel_bit: die select bit
++ * @drive_start_bit: drive strength mask start bit
++ * @drive_end_bit: drive strength mask end bit
++ */
++struct feature_character {
++	u8 addr;
++	u8 die_sel_bit;
++	u8 drive_start_bit;
++	u8 drive_end_bit;
++};
++
++/*
++ * spi features
++ * @protect: protection feature register
++ * @config: configuration feature register
++ * @status: status feature register
++ * @character: character feature register
++ */
++struct spi_features {
++	struct feature_protect protect;
++	struct feature_config config;
++	struct feature_status status;
++	struct feature_character character;
++};
++
++/*
++ * device_spi
++ *    configurations of spi nand device table
++ * @dev: base information of nand device
++ * @feature: feature information for spi nand
++ * @extend_cmds: extended the nand base commands
++ * @tx_mode_mask: tx mode mask for chip read
++ * @rx_mode_mask: rx mode mask for chip write
++ */
++struct device_spi {
++	struct nand_device dev;
++	struct spi_features feature;
++	struct spi_extend_cmds *extend_cmds;
++
++	u8 tx_mode_mask;
++	u8 rx_mode_mask;
++};
++
++#define NAND_SPI_PROTECT(addr, wp_en_bit, bp_start_bit, bp_end_bit) \
++	{addr, wp_en_bit, bp_start_bit, bp_end_bit}
++
++#define NAND_SPI_CONFIG(addr, ecc_en_bit, otp_en_bit, need_qe) \
++	{addr, ecc_en_bit, otp_en_bit, need_qe}
++
++#define NAND_SPI_STATUS(addr, ecc_start_bit, ecc_end_bit) \
++	{addr, ecc_start_bit, ecc_end_bit}
++
++#define NAND_SPI_CHARACTER(addr, die_sel_bit, drive_start_bit, drive_end_bit) \
++	{addr, die_sel_bit, drive_start_bit, drive_end_bit}
++
++static inline struct device_spi *device_to_spi(struct nand_device *dev)
++{
++	return container_of(dev, struct device_spi, dev);
++}
++
++u8 spi_replace_rx_cmds(u8 mode);
++u8 spi_replace_tx_cmds(u8 mode);
++u8 spi_replace_rx_col_cycle(u8 mode);
++u8 spi_replace_tx_col_cycle(u8 mode);
++
++#endif /* __DEVICE_SPI_H__ */
+diff --git a/drivers/mtd/nandx/core/nand/nand_spi.c b/drivers/mtd/nandx/core/nand/nand_spi.c
+new file mode 100644
+index 0000000000..2ae03e1cf4
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand/nand_spi.c
+@@ -0,0 +1,526 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "../nand_chip.h"
++#include "../nand_device.h"
++#include "../nfi.h"
++#include "../nand_base.h"
++#include "device_spi.h"
++#include "nand_spi.h"
++
++#define READY_TIMEOUT   500000 /* us */
++
++static int nand_spi_read_status(struct nand_base *nand)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	u8 status;
++
++	nand->get_feature(nand, dev->feature.status.addr, &status, 1);
++
++	return status;
++}
++
++static int nand_spi_wait_ready(struct nand_base *nand, u32 timeout)
++{
++	u64 now, end;
++	int status;
++
++	end = get_current_time_us() + timeout;
++
++	do {
++		status = nand_spi_read_status(nand);
++		status &= nand->dev->status->array_busy;
++		now = get_current_time_us();
++
++		if (now > end)
++			break;
++	} while (status);
++
++	return status ? -EBUSY : 0;
++}
++
++static int nand_spi_set_op_mode(struct nand_base *nand, u8 mode)
++{
++	struct nand_spi *spi_nand = base_to_spi(nand);
++	struct nfi *nfi = nand->nfi;
++	int ret = 0;
++
++	if (spi_nand->op_mode != mode) {
++		ret = nfi->nfi_ctrl(nfi, SNFI_CTRL_OP_MODE, (void *)&mode);
++		spi_nand->op_mode = mode;
++	}
++
++	return ret;
++}
++
++static int nand_spi_set_config(struct nand_base *nand, u8 addr, u8 mask,
++			       bool en)
++{
++	u8 configs = 0;
++
++	nand->get_feature(nand, addr, &configs, 1);
++
++	if (en)
++		configs |= mask;
++	else
++		configs &= ~mask;
++
++	nand->set_feature(nand, addr, &configs, 1);
++
++	configs = 0;
++	nand->get_feature(nand, addr, &configs, 1);
++
++	return (configs & mask) == en ? 0 : -EFAULT;
++}
++
++static int nand_spi_die_select(struct nand_base *nand, int *row)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nfi *nfi = nand->nfi;
++	int lun_blocks, block_pages, lun, blocks;
++	int page = *row, ret = 0;
++	u8 param = 0, die_sel;
++
++	if (nand->dev->lun_num < 2)
++		return 0;
++
++	block_pages = nand_block_pages(nand->dev);
++	lun_blocks = nand_lun_blocks(nand->dev);
++	blocks = div_down(page, block_pages);
++	lun = div_down(blocks, lun_blocks);
++
++	if (dev->extend_cmds->die_select == -1) {
++		die_sel = (u8)(lun << dev->feature.character.die_sel_bit);
++		nand->get_feature(nand, dev->feature.character.addr, &param, 1);
++		param |= die_sel;
++		nand->set_feature(nand, dev->feature.character.addr, &param, 1);
++		param = 0;
++		nand->get_feature(nand, dev->feature.character.addr, &param, 1);
++		ret = (param & die_sel) ? 0 : -EFAULT;
++	} else {
++		nfi->reset(nfi);
++		nfi->send_cmd(nfi, dev->extend_cmds->die_select);
++		nfi->send_addr(nfi, lun, 0, 1, 0);
++		nfi->trigger(nfi);
++	}
++
++	*row =  page - (lun_blocks * block_pages) * lun;
++
++	return ret;
++}
++
++static int nand_spi_select_device(struct nand_base *nand, int cs)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	return parent->select_device(nand, cs);
++}
++
++static int nand_spi_reset(struct nand_base *nand)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	parent->reset(nand);
++
++	return nand_spi_wait_ready(nand, READY_TIMEOUT);
++}
++
++static int nand_spi_read_id(struct nand_base *nand, u8 *id, int count)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	return parent->read_id(nand, id, count);
++}
++
++static int nand_spi_read_param_page(struct nand_base *nand, u8 *data,
++				    int count)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nfi *nfi = nand->nfi;
++	int sectors, value;
++	u8 param = 0;
++
++	sectors = div_round_up(count, nfi->sector_size);
++
++	nand->get_feature(nand, dev->feature.config.addr, &param, 1);
++	param |= BIT(dev->feature.config.otp_en_bit);
++	nand->set_feature(nand, dev->feature.config.addr, &param, 1);
++
++	param = 0;
++	nand->get_feature(nand, dev->feature.config.addr, &param, 1);
++	if (param & BIT(dev->feature.config.otp_en_bit)) {
++		value = 0;
++		nfi->nfi_ctrl(nfi, NFI_CTRL_ECC, &value);
++		nand->dev->col_cycle  = spi_replace_rx_col_cycle(spi->rx_mode);
++		nand->read_page(nand, 0x01);
++		nand->read_data(nand, 0x01, 0, sectors, data, NULL);
++	}
++
++	param &= ~BIT(dev->feature.config.otp_en_bit);
++	nand->set_feature(nand, dev->feature.config.addr, &param, 1);
++
++	return 0;
++}
++
++static int nand_spi_set_feature(struct nand_base *nand, u8 addr,
++				u8 *param,
++				int count)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand->write_enable(nand);
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	return parent->set_feature(nand, addr, param, count);
++}
++
++static int nand_spi_get_feature(struct nand_base *nand, u8 addr,
++				u8 *param,
++				int count)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	return parent->get_feature(nand, addr, param, count);
++}
++
++static int nand_spi_addressing(struct nand_base *nand, int *row,
++			       int *col)
++{
++	struct nand_device *dev = nand->dev;
++	int plane, block, block_pages;
++	int ret;
++
++	ret = nand_spi_die_select(nand, row);
++	if (ret)
++		return ret;
++
++	block_pages = nand_block_pages(dev);
++	block = div_down(*row, block_pages);
++
++	plane = block % dev->plane_num;
++	*col |= (plane << dev->addressing->plane_bit_start);
++
++	return 0;
++}
++
++static int nand_spi_read_page(struct nand_base *nand, int row)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	if (spi->op_mode == SNFI_AUTO_MODE)
++		nand_spi_set_op_mode(nand, SNFI_AUTO_MODE);
++	else
++		nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	parent->read_page(nand, row);
++
++	return nand_spi_wait_ready(nand, READY_TIMEOUT);
++}
++
++static int nand_spi_read_data(struct nand_base *nand, int row, int col,
++			      int sectors, u8 *data, u8 *oob)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++	int ret;
++
++	if ((spi->rx_mode == SNFI_RX_114 || spi->rx_mode == SNFI_RX_144) &&
++	    dev->feature.config.need_qe)
++		nand_spi_set_config(nand, dev->feature.config.addr,
++				    BIT(0), true);
++
++	nand->dev->col_cycle  = spi_replace_rx_col_cycle(spi->rx_mode);
++
++	nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE);
++
++	ret = parent->read_data(nand, row, col, sectors, data, oob);
++	if (ret)
++		return -ENANDREAD;
++
++	if (spi->ondie_ecc) {
++		ret = nand_spi_read_status(nand);
++		ret &= GENMASK(dev->feature.status.ecc_end_bit,
++			       dev->feature.status.ecc_start_bit);
++		ret >>= dev->feature.status.ecc_start_bit;
++		if (ret > nand->dev->endurance->ecc_req)
++			return -ENANDREAD;
++		else if (ret > nand->dev->endurance->max_bitflips)
++			return -ENANDFLIPS;
++	}
++
++	return 0;
++}
++
++static int nand_spi_write_enable(struct nand_base *nand)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nfi *nfi = nand->nfi;
++	int status;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->extend_cmds->write_enable);
++
++	nfi->trigger(nfi);
++
++	status = nand_spi_read_status(nand);
++	status &= nand->dev->status->write_protect;
++
++	return !status;
++}
++
++static int nand_spi_program_data(struct nand_base *nand, int row,
++				 int col,
++				 u8 *data, u8 *oob)
++{
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nand_spi *spi = base_to_spi(nand);
++
++	if (spi->tx_mode == SNFI_TX_114 && dev->feature.config.need_qe)
++		nand_spi_set_config(nand, dev->feature.config.addr,
++				    BIT(0), true);
++
++	nand_spi_set_op_mode(nand, SNFI_CUSTOM_MODE);
++
++	nand->dev->col_cycle  = spi_replace_tx_col_cycle(spi->tx_mode);
++
++	return spi->parent->program_data(nand, row, col, data, oob);
++}
++
++static int nand_spi_program_page(struct nand_base *nand, int row)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_device *dev = nand->dev;
++	struct nfi *nfi = nand->nfi;
++
++	if (spi->op_mode == SNFI_AUTO_MODE)
++		nand_spi_set_op_mode(nand, SNFI_AUTO_MODE);
++	else
++		nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->program_2nd);
++	nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
++	nfi->trigger(nfi);
++
++	return nand_spi_wait_ready(nand, READY_TIMEOUT);
++}
++
++static int nand_spi_erase_block(struct nand_base *nand, int row)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nand_base *parent = spi->parent;
++
++	nand_spi_set_op_mode(nand, SNFI_MAC_MODE);
++
++	parent->erase_block(nand, row);
++
++	return nand_spi_wait_ready(nand, READY_TIMEOUT);
++}
++
++static int nand_chip_spi_ctrl(struct nand_chip *chip, int cmd,
++			      void *args)
++{
++	struct nand_base *nand = chip->nand;
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nand_spi *spi = base_to_spi(nand);
++	struct nfi *nfi = nand->nfi;
++	int ret = 0, value = *(int *)args;
++
++	switch (cmd) {
++	case CHIP_CTRL_ONDIE_ECC:
++		spi->ondie_ecc = (bool)value;
++		ret = nand_spi_set_config(nand, dev->feature.config.addr,
++					  BIT(dev->feature.config.ecc_en_bit),
++					  spi->ondie_ecc);
++		break;
++
++	case SNFI_CTRL_TX_MODE:
++		if (value < 0 || value > SNFI_TX_114)
++			return -EOPNOTSUPP;
++
++		if (dev->tx_mode_mask & BIT(value)) {
++			spi->tx_mode = value;
++			nand->dev->cmds->random_out_1st = spi_replace_tx_cmds(
++								  spi->tx_mode);
++			ret = nfi->nfi_ctrl(nfi, cmd, args);
++		}
++
++		break;
++
++	case SNFI_CTRL_RX_MODE:
++		if (value < 0 || value > SNFI_RX_144)
++			return -EOPNOTSUPP;
++
++		if (dev->rx_mode_mask & BIT(value)) {
++			spi->rx_mode = value;
++			nand->dev->cmds->program_1st = spi_replace_rx_cmds(
++							       spi->rx_mode);
++			ret = nfi->nfi_ctrl(nfi, cmd, args);
++		}
++
++		break;
++
++	case CHIP_CTRL_OPS_CACHE:
++	case CHIP_CTRL_OPS_MULTI:
++	case CHIP_CTRL_PSLC_MODE:
++	case CHIP_CTRL_DDR_MODE:
++	case CHIP_CTRL_DRIVE_STRENGTH:
++	case CHIP_CTRL_TIMING_MODE:
++		ret = -EOPNOTSUPP;
++		break;
++
++	default:
++		ret = nfi->nfi_ctrl(nfi, cmd, args);
++		break;
++	}
++
++	return ret;
++}
++
++int nand_chip_spi_resume(struct nand_chip *chip)
++{
++	struct nand_base *nand = chip->nand;
++	struct nand_spi *spi = base_to_spi(nand);
++	struct device_spi *dev = device_to_spi(nand->dev);
++	struct nfi *nfi = nand->nfi;
++	struct nfi_format format;
++	u8 mask;
++
++	nand->reset(nand);
++
++	mask = GENMASK(dev->feature.protect.bp_end_bit,
++		       dev->feature.protect.bp_start_bit);
++	nand_spi_set_config(nand, dev->feature.config.addr, mask, false);
++	mask =  BIT(dev->feature.config.ecc_en_bit);
++	nand_spi_set_config(nand, dev->feature.config.addr, mask,
++			    spi->ondie_ecc);
++
++	format.page_size = nand->dev->page_size;
++	format.spare_size = nand->dev->spare_size;
++	format.ecc_req = nand->dev->endurance->ecc_req;
++
++	return nfi->set_format(nfi, &format);
++}
++
++static int nand_spi_set_format(struct nand_base *nand)
++{
++	struct nfi_format format = {
++		nand->dev->page_size,
++		nand->dev->spare_size,
++		nand->dev->endurance->ecc_req
++	};
++
++	return nand->nfi->set_format(nand->nfi, &format);
++}
++
++struct nand_base *nand_device_init(struct nand_chip *chip)
++{
++	struct nand_base *nand;
++	struct nand_spi *spi;
++	struct device_spi *dev;
++	int ret;
++	u8 mask;
++
++	spi = mem_alloc(1, sizeof(struct nand_spi));
++	if (!spi) {
++		pr_info("alloc nand_spi fail\n");
++		return NULL;
++	}
++
++	spi->ondie_ecc = false;
++	spi->op_mode = SNFI_CUSTOM_MODE;
++	spi->rx_mode = SNFI_RX_114;
++	spi->tx_mode = SNFI_TX_114;
++
++	spi->parent = chip->nand;
++	nand = &spi->base;
++	nand->dev = spi->parent->dev;
++	nand->nfi = spi->parent->nfi;
++
++	nand->select_device = nand_spi_select_device;
++	nand->reset = nand_spi_reset;
++	nand->read_id = nand_spi_read_id;
++	nand->read_param_page = nand_spi_read_param_page;
++	nand->set_feature = nand_spi_set_feature;
++	nand->get_feature = nand_spi_get_feature;
++	nand->read_status = nand_spi_read_status;
++	nand->addressing = nand_spi_addressing;
++	nand->read_page = nand_spi_read_page;
++	nand->read_data = nand_spi_read_data;
++	nand->write_enable = nand_spi_write_enable;
++	nand->program_data = nand_spi_program_data;
++	nand->program_page = nand_spi_program_page;
++	nand->erase_block = nand_spi_erase_block;
++
++	chip->chip_ctrl = nand_chip_spi_ctrl;
++	chip->nand_type = NAND_SPI;
++	chip->resume = nand_chip_spi_resume;
++
++	ret = nand_detect_device(nand);
++	if (ret)
++		goto err;
++
++	nand->select_device(nand, 0);
++
++	ret = nand_spi_set_format(nand);
++	if (ret)
++		goto err;
++
++	dev = (struct device_spi *)nand->dev;
++
++	nand->dev->cmds->random_out_1st =
++		spi_replace_rx_cmds(spi->rx_mode);
++	nand->dev->cmds->program_1st =
++		spi_replace_tx_cmds(spi->tx_mode);
++
++	mask = GENMASK(dev->feature.protect.bp_end_bit,
++		       dev->feature.protect.bp_start_bit);
++	ret = nand_spi_set_config(nand, dev->feature.protect.addr, mask, false);
++	if (ret)
++		goto err;
++
++	mask =  BIT(dev->feature.config.ecc_en_bit);
++	ret = nand_spi_set_config(nand, dev->feature.config.addr, mask,
++				  spi->ondie_ecc);
++	if (ret)
++		goto err;
++
++	return nand;
++
++err:
++	mem_free(spi);
++	return NULL;
++}
++
++void nand_exit(struct nand_base *nand)
++{
++	struct nand_spi *spi = base_to_spi(nand);
++
++	nand_base_exit(spi->parent);
++	mem_free(spi);
++}
+diff --git a/drivers/mtd/nandx/core/nand/nand_spi.h b/drivers/mtd/nandx/core/nand/nand_spi.h
+new file mode 100644
+index 0000000000..e55e4de6f7
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand/nand_spi.h
+@@ -0,0 +1,35 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NAND_SPI_H__
++#define __NAND_SPI_H__
++
++/*
++ * spi nand handler
++ * @base: spi nand base functions
++ * @parent: common parent nand base functions
++ * @tx_mode: spi bus width of transfer to device
++ * @rx_mode: spi bus width of transfer from device
++ * @op_mode: spi nand controller (NFI) operation mode
++ * @ondie_ecc: spi nand on-die ecc flag
++ */
++
++struct nand_spi {
++	struct nand_base base;
++	struct nand_base *parent;
++	u8 tx_mode;
++	u8 rx_mode;
++	u8 op_mode;
++	bool ondie_ecc;
++};
++
++static inline struct nand_spi *base_to_spi(struct nand_base *base)
++{
++	return container_of(base, struct nand_spi, base);
++}
++
++#endif /* __NAND_SPI_H__ */
+diff --git a/drivers/mtd/nandx/core/nand_base.c b/drivers/mtd/nandx/core/nand_base.c
+new file mode 100644
+index 0000000000..65998e5460
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_base.c
+@@ -0,0 +1,304 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "nand_chip.h"
++#include "nand_device.h"
++#include "nfi.h"
++#include "nand_base.h"
++
++static int nand_base_select_device(struct nand_base *nand, int cs)
++{
++	struct nfi *nfi = nand->nfi;
++
++	nfi->reset(nfi);
++
++	return nfi->select_chip(nfi, cs);
++}
++
++static int nand_base_reset(struct nand_base *nand)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->reset);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRST);
++}
++
++static int nand_base_read_id(struct nand_base *nand, u8 *id, int count)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_id);
++	nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR);
++	nfi->send_addr(nfi, 0, 0, 1, 0);
++
++	return nfi->read_bytes(nfi, id, count);
++}
++
++static int nand_base_read_param_page(struct nand_base *nand, u8 *data,
++				     int count)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_param_page);
++	nfi->send_addr(nfi, 0, 0, 1, 0);
++
++	nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR);
++
++	return nfi->read_bytes(nfi, data, count);
++}
++
++static int nand_base_set_feature(struct nand_base *nand, u8 addr,
++				 u8 *param,
++				 int count)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->set_feature);
++	nfi->send_addr(nfi, addr, 0, 1, 0);
++
++	nfi->write_bytes(nfi, param, count);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tFEAT);
++}
++
++static int nand_base_get_feature(struct nand_base *nand, u8 addr,
++				 u8 *param,
++				 int count)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->get_feature);
++	nfi->send_addr(nfi, addr, 0, 1, 0);
++	nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tFEAT);
++
++	return nfi->read_bytes(nfi, param, count);
++}
++
++static int nand_base_read_status(struct nand_base *nand)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++	u8 status = 0;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_status);
++	nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tWHR);
++	nfi->read_bytes(nfi, &status, 1);
++
++	return status;
++}
++
++static int nand_base_addressing(struct nand_base *nand, int *row,
++				int *col)
++{
++	struct nand_device *dev = nand->dev;
++	int lun, plane, block, page, cs = 0;
++	int block_pages, target_blocks, wl = 0;
++	int icol = *col;
++
++	if (dev->target_num > 1) {
++		block_pages = nand_block_pages(dev);
++		target_blocks = nand_target_blocks(dev);
++		cs = div_down(*row, block_pages * target_blocks);
++		*row -= cs * block_pages * target_blocks;
++	}
++
++	nand->select_device(nand, cs);
++
++	block_pages = nand_block_pages(dev);
++	block = div_down(*row, block_pages);
++	page = *row - block * block_pages;
++	plane = reminder(block, dev->plane_num);
++	lun = div_down(block, nand_lun_blocks(dev));
++
++	wl |= (page << dev->addressing->row_bit_start);
++	wl |= (block << dev->addressing->block_bit_start);
++	wl |= (plane << dev->addressing->plane_bit_start);
++	wl |= (lun << dev->addressing->lun_bit_start);
++
++	*row = wl;
++	*col = icol;
++
++	return 0;
++}
++
++static int nand_base_read_page(struct nand_base *nand, int row)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_1st);
++	nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
++	nfi->send_cmd(nfi, dev->cmds->read_2nd);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tR);
++}
++
++static int nand_base_read_data(struct nand_base *nand, int row, int col,
++			       int sectors, u8 *data, u8 *oob)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->random_out_1st);
++	nfi->send_addr(nfi, col, row, dev->col_cycle, dev->row_cycle);
++	nfi->send_cmd(nfi, dev->cmds->random_out_2nd);
++	nfi->wait_ready(nfi, NAND_WAIT_POLLING, dev->array_timing->tRCBSY);
++
++	return nfi->read_sectors(nfi, data, oob, sectors);
++}
++
++static int nand_base_write_enable(struct nand_base *nand)
++{
++	struct nand_device *dev = nand->dev;
++	int status;
++
++	status = nand_base_read_status(nand);
++	if (status & dev->status->write_protect)
++		return 0;
++
++	return -ENANDWP;
++}
++
++static int nand_base_program_data(struct nand_base *nand, int row,
++				  int col,
++				  u8 *data, u8 *oob)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->program_1st);
++	nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
++
++	return nfi->write_page(nfi, data, oob);
++}
++
++static int nand_base_program_page(struct nand_base *nand, int row)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->program_2nd);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tPROG);
++}
++
++static int nand_base_erase_block(struct nand_base *nand, int row)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->erase_1st);
++	nfi->send_addr(nfi, 0, row, 0, dev->row_cycle);
++	nfi->send_cmd(nfi, dev->cmds->erase_2nd);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tBERS);
++}
++
++static int nand_base_read_cache(struct nand_base *nand, int row)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_1st);
++	nfi->send_addr(nfi, 0, row, dev->col_cycle, dev->row_cycle);
++	nfi->send_cmd(nfi, dev->cmds->read_cache);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tRCBSY);
++}
++
++static int nand_base_read_last(struct nand_base *nand)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->read_cache_last);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tRCBSY);
++}
++
++static int nand_base_program_cache(struct nand_base *nand)
++{
++	struct nfi *nfi = nand->nfi;
++	struct nand_device *dev = nand->dev;
++
++	nfi->reset(nfi);
++	nfi->send_cmd(nfi, dev->cmds->program_cache);
++	nfi->trigger(nfi);
++
++	return nfi->wait_ready(nfi, NAND_WAIT_POLLING,
++			       dev->array_timing->tPCBSY);
++}
++
++struct nand_base *nand_base_init(struct nand_device *dev,
++				 struct nfi *nfi)
++{
++	struct nand_base *nand;
++
++	nand = mem_alloc(1, sizeof(struct nand_base));
++	if (!nand)
++		return NULL;
++
++	nand->dev = dev;
++	nand->nfi = nfi;
++	nand->select_device = nand_base_select_device;
++	nand->reset = nand_base_reset;
++	nand->read_id = nand_base_read_id;
++	nand->read_param_page = nand_base_read_param_page;
++	nand->set_feature = nand_base_set_feature;
++	nand->get_feature = nand_base_get_feature;
++	nand->read_status = nand_base_read_status;
++	nand->addressing = nand_base_addressing;
++	nand->read_page = nand_base_read_page;
++	nand->read_data = nand_base_read_data;
++	nand->read_cache = nand_base_read_cache;
++	nand->read_last = nand_base_read_last;
++	nand->write_enable = nand_base_write_enable;
++	nand->program_data = nand_base_program_data;
++	nand->program_page = nand_base_program_page;
++	nand->program_cache = nand_base_program_cache;
++	nand->erase_block = nand_base_erase_block;
++
++	return nand;
++}
++
++void nand_base_exit(struct nand_base *base)
++{
++	nfi_exit(base->nfi);
++	mem_free(base);
++}
+diff --git a/drivers/mtd/nandx/core/nand_base.h b/drivers/mtd/nandx/core/nand_base.h
+new file mode 100644
+index 0000000000..13217978e5
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_base.h
+@@ -0,0 +1,71 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NAND_BASE_H__
++#define __NAND_BASE_H__
++
++/*
++ * nand base functions
++ * @dev: nand device infomations
++ * @nfi: nand host controller
++ * @select_device: select one nand device of multi nand on chip
++ * @reset: reset current nand device
++ * @read_id: read current nand id
++ * @read_param_page: read current nand parameters page
++ * @set_feature: configurate the nand device feature
++ * @get_feature: get the nand device feature
++ * @read_status: read nand device status
++ * @addressing: addressing the address to nand device physical address
++ * @read_page: read page data to device cache register
++ * @read_data: read data from device cache register by bus protocol
++ * @read_cache: nand cache read operation for data output
++ * @read_last: nand cache read operation for last page output
++ * @write_enable: enable program/erase for nand, especially spi nand
++ * @program_data: program data to nand device cache register
++ * @program_page: program page data from nand device cache register to array
++ * @program_cache: nand cache program operation for data input
++ * @erase_block: erase nand block operation
++ */
++struct nand_base {
++	struct nand_device *dev;
++	struct nfi *nfi;
++	int (*select_device)(struct nand_base *nand, int cs);
++	int (*reset)(struct nand_base *nand);
++	int (*read_id)(struct nand_base *nand, u8 *id, int count);
++	int (*read_param_page)(struct nand_base *nand, u8 *data, int count);
++	int (*set_feature)(struct nand_base *nand, u8 addr, u8 *param,
++			   int count);
++	int (*get_feature)(struct nand_base *nand, u8 addr, u8 *param,
++			   int count);
++	int (*read_status)(struct nand_base *nand);
++	int (*addressing)(struct nand_base *nand, int *row, int *col);
++
++	int (*read_page)(struct nand_base *nand, int row);
++	int (*read_data)(struct nand_base *nand, int row, int col, int sectors,
++			 u8 *data, u8 *oob);
++	int (*read_cache)(struct nand_base *nand, int row);
++	int (*read_last)(struct nand_base *nand);
++
++	int (*write_enable)(struct nand_base *nand);
++	int (*program_data)(struct nand_base *nand, int row, int col, u8 *data,
++			    u8 *oob);
++	int (*program_page)(struct nand_base *nand, int row);
++	int (*program_cache)(struct nand_base *nand);
++
++	int (*erase_block)(struct nand_base *nand, int row);
++};
++
++struct nand_base *nand_base_init(struct nand_device *device,
++				 struct nfi *nfi);
++void nand_base_exit(struct nand_base *base);
++
++struct nand_base *nand_device_init(struct nand_chip *nand);
++void nand_exit(struct nand_base *nand);
++
++int nand_detect_device(struct nand_base *nand);
++
++#endif /* __NAND_BASE_H__ */
+diff --git a/drivers/mtd/nandx/core/nand_chip.c b/drivers/mtd/nandx/core/nand_chip.c
+new file mode 100644
+index 0000000000..02adc6f52e
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_chip.c
+@@ -0,0 +1,272 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "nand_chip.h"
++#include "nand_device.h"
++#include "nfi.h"
++#include "nand_base.h"
++
++static int nand_chip_read_page(struct nand_chip *chip,
++			       struct nand_ops *ops,
++			       int count)
++{
++	struct nand_base *nand = chip->nand;
++	struct nand_device *dev = nand->dev;
++	int i, ret = 0;
++	int row, col, sectors;
++	u8 *data, *oob;
++
++	for (i = 0; i < count; i++) {
++		row = ops[i].row;
++		col = ops[i].col;
++
++		nand->addressing(nand, &row, &col);
++		ops[i].status = nand->read_page(nand, row);
++		if (ops[i].status < 0) {
++			ret = ops[i].status;
++			continue;
++		}
++
++		data = ops[i].data;
++		oob = ops[i].oob;
++		sectors = ops[i].len / chip->sector_size;
++		ops[i].status = nand->read_data(nand, row, col,
++						sectors, data, oob);
++		if (ops[i].status > 0)
++			ops[i].status = ops[i].status >=
++					dev->endurance->max_bitflips ?
++					-ENANDFLIPS : 0;
++
++		ret = min_t(int, ret, ops[i].status);
++	}
++
++	return ret;
++}
++
++static int nand_chip_write_page(struct nand_chip *chip,
++				struct nand_ops *ops,
++				int count)
++{
++	struct nand_base *nand = chip->nand;
++	struct nand_device *dev = nand->dev;
++	int i, ret = 0;
++	int row, col;
++	u8 *data, *oob;
++
++	for (i = 0; i < count; i++) {
++		row = ops[i].row;
++		col = ops[i].col;
++
++		nand->addressing(nand, &row, &col);
++
++		ops[i].status = nand->write_enable(nand);
++		if (ops[i].status) {
++			pr_debug("Write Protect at %x!\n", row);
++			ops[i].status = -ENANDWP;
++			return -ENANDWP;
++		}
++
++		data = ops[i].data;
++		oob = ops[i].oob;
++		ops[i].status = nand->program_data(nand, row, col, data, oob);
++		if (ops[i].status < 0) {
++			ret = ops[i].status;
++			continue;
++		}
++
++		ops[i].status = nand->program_page(nand, row);
++		if (ops[i].status < 0) {
++			ret = ops[i].status;
++			continue;
++		}
++
++		ops[i].status = nand->read_status(nand);
++		if (ops[i].status & dev->status->program_fail)
++			ops[i].status = -ENANDWRITE;
++
++		ret = min_t(int, ret, ops[i].status);
++	}
++
++	return ret;
++}
++
++static int nand_chip_erase_block(struct nand_chip *chip,
++				 struct nand_ops *ops,
++				 int count)
++{
++	struct nand_base *nand = chip->nand;
++	struct nand_device *dev = nand->dev;
++	int i, ret = 0;
++	int row, col;
++
++	for (i = 0; i < count; i++) {
++		row = ops[i].row;
++		col = ops[i].col;
++
++		nand->addressing(nand, &row, &col);
++
++		ops[i].status = nand->write_enable(nand);
++		if (ops[i].status) {
++			pr_debug("Write Protect at %x!\n", row);
++			ops[i].status = -ENANDWP;
++			return -ENANDWP;
++		}
++
++		ops[i].status = nand->erase_block(nand, row);
++		if (ops[i].status < 0) {
++			ret = ops[i].status;
++			continue;
++		}
++
++		ops[i].status = nand->read_status(nand);
++		if (ops[i].status & dev->status->erase_fail)
++			ops[i].status = -ENANDERASE;
++
++		ret = min_t(int, ret, ops[i].status);
++	}
++
++	return ret;
++}
++
++/* read first bad mark on spare */
++static int nand_chip_is_bad_block(struct nand_chip *chip,
++				  struct nand_ops *ops,
++				  int count)
++{
++	int i, ret, value;
++	int status = 0;
++	u8 *data, *tmp_buf;
++
++	tmp_buf = mem_alloc(1, chip->page_size);
++	if (!tmp_buf)
++		return -ENOMEM;
++
++	memset(tmp_buf, 0x00, chip->page_size);
++
++	/* Disable ECC */
++	value = 0;
++	ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value);
++	if (ret)
++		goto out;
++
++	ret = chip->read_page(chip, ops, count);
++	if (ret)
++		goto out;
++
++	for (i = 0; i < count; i++) {
++		data = ops[i].data;
++
++		/* temp solution for mt7622, because of no bad mark swap */
++		if (!memcmp(data, tmp_buf, chip->page_size)) {
++			ops[i].status = -ENANDBAD;
++			status = -ENANDBAD;
++			
++		} else {
++			ops[i].status = 0;
++		}
++	}
++
++	/* Enable ECC */
++	value = 1;
++	ret = chip->chip_ctrl(chip, NFI_CTRL_ECC, &value);
++	if (ret)
++		goto out;
++
++	mem_free(tmp_buf);
++	return status;
++
++out:
++	mem_free(tmp_buf);
++	return ret;
++}
++
++static int nand_chip_ctrl(struct nand_chip *chip, int cmd, void *args)
++{
++	return -EOPNOTSUPP;
++}
++
++static int nand_chip_suspend(struct nand_chip *chip)
++{
++	return 0;
++}
++
++static int nand_chip_resume(struct nand_chip *chip)
++{
++	return 0;
++}
++
++struct nand_chip *nand_chip_init(struct nfi_resource *res)
++{
++	struct nand_chip *chip;
++	struct nand_base *nand;
++	struct nfi *nfi;
++
++	chip = mem_alloc(1, sizeof(struct nand_chip));
++	if (!chip) {
++		pr_info("nand chip alloc fail!\n");
++		return NULL;
++	}
++
++	nfi = nfi_init(res);
++	if (!nfi) {
++		pr_info("nfi init fail!\n");
++		goto nfi_err;
++	}
++
++	nand = nand_base_init(NULL, nfi);
++	if (!nand) {
++		pr_info("nand base init fail!\n");
++		goto base_err;
++	}
++
++	chip->nand = (void *)nand;
++	chip->read_page = nand_chip_read_page;
++	chip->write_page = nand_chip_write_page;
++	chip->erase_block = nand_chip_erase_block;
++	chip->is_bad_block = nand_chip_is_bad_block;
++	chip->chip_ctrl = nand_chip_ctrl;
++	chip->suspend = nand_chip_suspend;
++	chip->resume = nand_chip_resume;
++
++	nand = nand_device_init(chip);
++	if (!nand)
++		goto nand_err;
++
++	chip->nand = (void *)nand;
++	chip->plane_num = nand->dev->plane_num;
++	chip->block_num = nand_total_blocks(nand->dev);
++	chip->block_size = nand->dev->block_size;
++	chip->block_pages = nand_block_pages(nand->dev);
++	chip->page_size = nand->dev->page_size;
++	chip->oob_size = nfi->fdm_size * div_down(chip->page_size,
++						  nfi->sector_size);
++	chip->sector_size = nfi->sector_size;
++	chip->sector_spare_size = nfi->sector_spare_size;
++	chip->min_program_pages = nand->dev->min_program_pages;
++	chip->ecc_strength = nfi->ecc_strength;
++	chip->ecc_parity_size = nfi->ecc_parity_size;
++	chip->fdm_ecc_size = nfi->fdm_ecc_size;
++	chip->fdm_reg_size = nfi->fdm_size;
++
++	return chip;
++
++nand_err:
++	mem_free(nand);
++base_err:
++	nfi_exit(nfi);
++nfi_err:
++	mem_free(chip);
++	return NULL;
++}
++
++void nand_chip_exit(struct nand_chip *chip)
++{
++	nand_exit(chip->nand);
++	mem_free(chip);
++}
+diff --git a/drivers/mtd/nandx/core/nand_chip.h b/drivers/mtd/nandx/core/nand_chip.h
+new file mode 100644
+index 0000000000..3e9c8e6ca3
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_chip.h
+@@ -0,0 +1,103 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NAND_CHIP_H__
++#define __NAND_CHIP_H__
++
++enum nand_type {
++	NAND_SPI,
++	NAND_SLC,
++	NAND_MLC,
++	NAND_TLC
++};
++
++/*
++ * nand chip operation unit
++ *    one nand_ops indicates one row operation
++ * @row: nand chip row address, like as nand row
++ * @col: nand chip column address, like as nand column
++ * @len: operate data length, min is sector_size,
++ *    max is page_size and sector_size aligned
++ * @status: one operation result status
++ * @data: data buffer for operation
++ * @oob: oob buffer for operation, like as nand spare area
++ */
++struct nand_ops {
++	int row;
++	int col;
++	int len;
++	int status;
++	void *data;
++	void *oob;
++};
++
++/*
++ * nand chip descriptions
++ *    nand chip includes nand controller and the several same nand devices
++ * @nand_type: the nand type on this chip,
++ *    the chip maybe have several nand device and the type must be same
++ * @plane_num: the whole plane number on the chip
++ * @block_num: the whole block number on the chip
++ * @block_size: nand device block size
++ * @block_pages: nand device block has page number
++ * @page_size: nand device page size
++ * @oob_size: chip out of band size, like as nand spare szie,
++ *    but restricts this:
++ *    the size is provied by nand controller(NFI),
++ *    because NFI would use some nand spare size
++ * @min_program_pages: chip needs min pages per program operations
++ *    one page as one nand_ops
++ * @sector_size: chip min read size
++ * @sector_spare_size: spare size for sector, is spare_size/page_sectors
++ * @ecc_strength: ecc stregth per sector_size, it would be for calculated ecc
++ * @ecc_parity_size: ecc parity size for one  sector_size data
++ * @nand: pointer to inherited struct nand_base
++ * @read_page: read %count pages on chip
++ * @write_page: write %count pages on chip
++ * @erase_block: erase %count blocks on chip, one block is one nand_ops
++ *    it is better to set nand_ops.row to block start row
++ * @is_bad_block: judge the %count blocks on chip if they are bad
++ *    by vendor specification
++ * @chip_ctrl: control the chip features by nandx_ctrl_cmd
++ * @suspend: suspend nand chip
++ * @resume: resume nand chip
++ */
++struct nand_chip {
++	int nand_type;
++	int plane_num;
++	int block_num;
++	int block_size;
++	int block_pages;
++	int page_size;
++	int oob_size;
++
++	int min_program_pages;
++	int sector_size;
++	int sector_spare_size;
++	int ecc_strength;
++	int ecc_parity_size;
++	u32 fdm_ecc_size;
++	u32 fdm_reg_size;
++
++	void *nand;
++
++	int (*read_page)(struct nand_chip *chip, struct nand_ops *ops,
++			 int count);
++	int (*write_page)(struct nand_chip *chip, struct nand_ops *ops,
++			  int count);
++	int (*erase_block)(struct nand_chip *chip, struct nand_ops *ops,
++			   int count);
++	int (*is_bad_block)(struct nand_chip *chip, struct nand_ops *ops,
++			    int count);
++	int (*chip_ctrl)(struct nand_chip *chip, int cmd, void *args);
++	int (*suspend)(struct nand_chip *chip);
++	int (*resume)(struct nand_chip *chip);
++};
++
++struct nand_chip *nand_chip_init(struct nfi_resource *res);
++void nand_chip_exit(struct nand_chip *chip);
++#endif /* __NAND_CHIP_H__ */
+diff --git a/drivers/mtd/nandx/core/nand_device.c b/drivers/mtd/nandx/core/nand_device.c
+new file mode 100644
+index 0000000000..9f6764d1bc
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_device.c
+@@ -0,0 +1,285 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "nand_chip.h"
++#include "nand_device.h"
++#include "nand_base.h"
++
++#define MAX_CHIP_DEVICE 4
++#define PARAM_PAGE_LEN  2048
++#define ONFI_CRC_BASE   0x4f4e
++
++static u16 nand_onfi_crc16(u16 crc, u8 const *p, size_t len)
++{
++	int i;
++
++	while (len--) {
++		crc ^= *p++ << 8;
++
++		for (i = 0; i < 8; i++)
++			crc = (crc << 1) ^ ((crc & 0x8000) ? 0x8005 : 0);
++	}
++
++	return crc;
++}
++
++static inline void decode_addr_cycle(u8 addr_cycle, u8 *row_cycle,
++				     u8 *col_cycle)
++{
++	*row_cycle = addr_cycle & 0xf;
++	*col_cycle = (addr_cycle >> 4) & 0xf;
++}
++
++static int detect_onfi(struct nand_device *dev,
++		       struct nand_onfi_params *onfi)
++{
++	struct nand_endurance *endurance = dev->endurance;
++	u16 size, i, crc16;
++	u8 *id;
++
++	size = sizeof(struct nand_onfi_params) - sizeof(u16);
++
++	for (i = 0; i < 3; i++) {
++		crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&onfi[i], size);
++
++		if (onfi[i].signature[0] == 'O' &&
++		    onfi[i].signature[1] == 'N' &&
++		    onfi[i].signature[2] == 'F' &&
++		    onfi[i].signature[3] == 'I' &&
++		    onfi[i].crc16 == crc16)
++			break;
++
++		/* in some spi nand, onfi signature maybe "NAND" */
++		if (onfi[i].signature[0] == 'N' &&
++		    onfi[i].signature[1] == 'A' &&
++		    onfi[i].signature[2] == 'N' &&
++		    onfi[i].signature[3] == 'D' &&
++		    onfi[i].crc16 == crc16)
++			break;
++	}
++
++	if (i == 3)
++		return -ENODEV;
++
++	memcpy(dev->name, onfi[i].model, 20);
++	id = onfi[i].manufacturer;
++	dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6],
++			       id[7]);
++	dev->id_len = MAX_ID_NUM;
++	dev->io_width = (onfi[i].features & 1) ? NAND_IO16 : NAND_IO8;
++	decode_addr_cycle(onfi[i].addr_cycle, &dev->row_cycle,
++			  &dev->col_cycle);
++	dev->target_num = 1;
++	dev->lun_num = onfi[i].lun_num;
++	dev->plane_num = BIT(onfi[i].plane_address_bits);
++	dev->block_num = onfi[i].lun_blocks / dev->plane_num;
++	dev->block_size = onfi[i].block_pages * onfi[i].page_size;
++	dev->page_size = onfi[i].page_size;
++	dev->spare_size = onfi[i].spare_size;
++
++	endurance->ecc_req = onfi[i].ecc_req;
++	endurance->pe_cycle = onfi[i].valid_block_endurance;
++	endurance->max_bitflips = endurance->ecc_req >> 1;
++
++	return 0;
++}
++
++static int detect_jedec(struct nand_device *dev,
++			struct nand_jedec_params *jedec)
++{
++	struct nand_endurance *endurance = dev->endurance;
++	u16 size, i, crc16;
++	u8 *id;
++
++	size = sizeof(struct nand_jedec_params) - sizeof(u16);
++
++	for (i = 0; i < 3; i++) {
++		crc16 = nand_onfi_crc16(ONFI_CRC_BASE, (u8 *)&jedec[i], size);
++
++		if (jedec[i].signature[0] == 'J' &&
++		    jedec[i].signature[1] == 'E' &&
++		    jedec[i].signature[2] == 'S' &&
++		    jedec[i].signature[3] == 'D' &&
++		    jedec[i].crc16 == crc16)
++			break;
++	}
++
++	if (i == 3)
++		return -ENODEV;
++
++	memcpy(dev->name, jedec[i].model, 20);
++	id = jedec[i].manufacturer;
++	dev->id = NAND_PACK_ID(id[0], id[1], id[2], id[3], id[4], id[5], id[6],
++			       id[7]);
++	dev->id_len = MAX_ID_NUM;
++	dev->io_width = (jedec[i].features & 1) ? NAND_IO16 : NAND_IO8;
++	decode_addr_cycle(jedec[i].addr_cycle, &dev->row_cycle,
++			  &dev->col_cycle);
++	dev->target_num = 1;
++	dev->lun_num = jedec[i].lun_num;
++	dev->plane_num = BIT(jedec[i].plane_address_bits);
++	dev->block_num = jedec[i].lun_blocks / dev->plane_num;
++	dev->block_size = jedec[i].block_pages * jedec[i].page_size;
++	dev->page_size = jedec[i].page_size;
++	dev->spare_size = jedec[i].spare_size;
++
++	endurance->ecc_req = jedec[i].endurance_block0[0];
++	endurance->pe_cycle = jedec[i].valid_block_endurance;
++	endurance->max_bitflips = endurance->ecc_req >> 1;
++
++	return 0;
++}
++
++static struct nand_device *detect_parameters_page(struct nand_base
++						  *nand)
++{
++	struct nand_device *dev = nand->dev;
++	void *params;
++	int ret;
++
++	params = mem_alloc(1, PARAM_PAGE_LEN);
++	if (!params)
++		return NULL;
++
++	memset(params, 0, PARAM_PAGE_LEN);
++	ret = nand->read_param_page(nand, params, PARAM_PAGE_LEN);
++	if (ret < 0) {
++		pr_info("read parameters page fail!\n");
++		goto error;
++	}
++
++	ret = detect_onfi(dev, params);
++	if (ret) {
++		pr_info("detect onfi device fail! try to detect jedec\n");
++		ret = detect_jedec(dev, params);
++		if (ret) {
++			pr_info("detect jedec device fail!\n");
++			goto error;
++		}
++	}
++
++	mem_free(params);
++	return dev;
++
++error:
++	mem_free(params);
++	return NULL;
++}
++
++static int read_device_id(struct nand_base *nand, int cs, u8 *id)
++{
++	int i;
++
++	nand->select_device(nand, cs);
++	nand->reset(nand);
++	nand->read_id(nand, id, MAX_ID_NUM);
++	pr_info("device %d ID: ", cs);
++
++	for (i = 0; i < MAX_ID_NUM; i++)
++		pr_info("%x ", id[i]);
++
++	pr_info("\n");
++
++	return 0;
++}
++
++static int detect_more_device(struct nand_base *nand, u8 *id)
++{
++	u8 id_ext[MAX_ID_NUM];
++	int i, j, target_num = 0;
++
++	for (i = 1; i < MAX_CHIP_DEVICE; i++) {
++		memset(id_ext, 0xff, MAX_ID_NUM);
++		read_device_id(nand, i, id_ext);
++
++		for (j = 0; j < MAX_ID_NUM; j++) {
++			if (id_ext[j] != id[j])
++				goto out;
++		}
++
++		target_num += 1;
++	}
++
++out:
++	return target_num;
++}
++
++static struct nand_device *scan_device_table(const u8 *id, int id_len)
++{
++	struct nand_device *dev;
++	int i = 0, j;
++	u8 ids[MAX_ID_NUM] = {0};
++
++	while (1) {
++		dev = nand_get_device(i);
++
++		if (!strcmp(dev->name, "NO-DEVICE"))
++			break;
++
++		if (id_len < dev->id_len) {
++			i += 1;
++			continue;
++		}
++
++		NAND_UNPACK_ID(dev->id, ids, MAX_ID_NUM);
++		for (j = 0; j < dev->id_len; j++) {
++			if (ids[j] != id[j])
++				break;
++		}
++
++		if (j == dev->id_len)
++			break;
++
++		i += 1;
++	}
++
++	return dev;
++}
++
++int nand_detect_device(struct nand_base *nand)
++{
++	struct nand_device *dev;
++	u8 id[MAX_ID_NUM] = { 0 };
++	int target_num = 0;
++
++	/* Get nand device default setting for reset/read_id */
++	nand->dev = scan_device_table(NULL, -1);
++
++	read_device_id(nand, 0, id);
++	dev = scan_device_table(id, MAX_ID_NUM);
++
++	if (!strcmp(dev->name, "NO-DEVICE")) {
++		pr_info("device scan fail\n");
++		return -ENODEV;
++	}
++
++	/* TobeFix: has null pointer issue in this funciton */
++	if (!strcmp(dev->name, "NO-DEVICE")) {
++		pr_info("device scan fail, detect parameters page\n");
++		dev = detect_parameters_page(nand);
++		if (!dev) {
++			pr_info("detect parameters fail\n");
++			return -ENODEV;
++		}
++	}
++
++	if (dev->target_num > 1)
++		target_num = detect_more_device(nand, id);
++
++	target_num += 1;
++	pr_debug("chip has target device num: %d\n", target_num);
++
++	if (dev->target_num != target_num)
++		dev->target_num = target_num;
++
++	nand->dev = dev;
++
++	return 0;
++}
++
+diff --git a/drivers/mtd/nandx/core/nand_device.h b/drivers/mtd/nandx/core/nand_device.h
+new file mode 100644
+index 0000000000..e142cf529d
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nand_device.h
+@@ -0,0 +1,608 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NAND_DEVICE_H__
++#define __NAND_DEVICE_H__
++
++/* onfi 3.2 */
++struct nand_onfi_params {
++	/* Revision information and features block. 0 */
++	/*
++	 * Byte 0: 4Fh,
++	 * Byte 1: 4Eh,
++	 * Byte 2: 46h,
++	 * Byte 3: 49h,
++	 */
++	u8 signature[4];
++	/*
++	 * 9-15 Reserved (0)
++	 * 8 1 = supports ONFI version 3.2
++	 * 7 1 = supports ONFI version 3.1
++	 * 6 1 = supports ONFI version 3.0
++	 * 5 1 = supports ONFI version 2.3
++	 * 4 1 = supports ONFI version 2.2
++	 * 3 1 = supports ONFI version 2.1
++	 * 2 1 = supports ONFI version 2.0
++	 * 1 1 = supports ONFI version 1.0
++	 * 0 Reserved (0)
++	 */
++	u16 revision;
++	/*
++	 * 13-15 Reserved (0)
++	 * 12 1 = supports external Vpp
++	 * 11 1 = supports Volume addressing
++	 * 10 1 = supports NV-DDR2
++	 * 9 1 = supports EZ NAND
++	 * 8 1 = supports program page register clear enhancement
++	 * 7 1 = supports extended parameter page
++	 * 6 1 = supports multi-plane read operations
++	 * 5 1 = supports NV-DDR
++	 * 4 1 = supports odd to even page Copyback
++	 * 3 1 = supports multi-plane program and erase operations
++	 * 2 1 = supports non-sequential page programming
++	 * 1 1 = supports multiple LUN operations
++	 * 0 1 = supports 16-bit data bus width
++	 */
++	u16 features;
++	/*
++	 * 13-15 Reserved (0)
++	 * 12 1 = supports LUN Get and LUN Set Features
++	 * 11 1 = supports ODT Configure
++	 * 10 1 = supports Volume Select
++	 * 9 1 = supports Reset LUN
++	 * 8 1 = supports Small Data Move
++	 * 7 1 = supports Change Row Address
++	 * 6 1 = supports Change Read Column Enhanced
++	 * 5 1 = supports Read Unique ID
++	 * 4 1 = supports Copyback
++	 * 3 1 = supports Read Status Enhanced
++	 * 2 1 = supports Get Features and Set Features
++	 * 1 1 = supports Read Cache commands
++	 * 0 1 = supports Page Cache Program command
++	 */
++	u16 opt_cmds;
++	/*
++	 * 4-7 Reserved (0)
++	 * 3 1 = supports Multi-plane Block Erase
++	 * 2 1 = supports Multi-plane Copyback Program
++	 * 1 1 = supports Multi-plane Page Program
++	 * 0 1 = supports Random Data Out
++	 */
++	u8 advance_cmds;
++	u8 reserved0[1];
++	u16 extend_param_len;
++	u8 param_page_num;
++	u8 reserved1[17];
++
++	/* Manufacturer information block. 32 */
++	u8 manufacturer[12];
++	u8 model[20];
++	u8 jedec_id;
++	u16 data_code;
++	u8 reserved2[13];
++
++	/* Memory organization block. 80 */
++	u32 page_size;
++	u16 spare_size;
++	u32 partial_page_size; /* obsolete */
++	u16 partial_spare_size; /* obsolete */
++	u32 block_pages;
++	u32 lun_blocks;
++	u8 lun_num;
++	/*
++	 * 4-7 Column address cycles
++	 * 0-3 Row address cycles
++	 */
++	u8 addr_cycle;
++	u8 cell_bits;
++	u16 lun_max_bad_blocks;
++	u16 block_endurance;
++	u8 target_begin_valid_blocks;
++	u16 valid_block_endurance;
++	u8 page_program_num;
++	u8 partial_program_attr; /* obsolete */
++	u8 ecc_req;
++	/*
++	 * 4-7 Reserved (0)
++	 * 0-3 Number of plane address bits
++	 */
++	u8 plane_address_bits;
++	/*
++	 * 6-7 Reserved (0)
++	 * 5 1 = lower bit XNOR block address restriction
++	 * 4 1 = read cache supported
++	 * 3 Address restrictions for cache operations
++	 * 2 1 = program cache supported
++	 * 1 1 = no block address restrictions
++	 * 0 Overlapped / concurrent multi-plane support
++	 */
++	u8 multi_plane_attr;
++	u8 ez_nand_support;
++	u8 reserved3[12];
++
++	/* Electrical parameters block. 128 */
++	u8 io_pin_max_capacitance;
++	/*
++	 * 6-15 Reserved (0)
++	 * 5 1 = supports timing mode 5
++	 * 4 1 = supports timing mode 4
++	 * 3 1 = supports timing mode 3
++	 * 2 1 = supports timing mode 2
++	 * 1 1 = supports timing mode 1
++	 * 0 1 = supports timing mode 0, shall be 1
++	 */
++	u16 sdr_timing_mode;
++	u16 sdr_program_cache_timing_mode; /* obsolete */
++	u16 tPROG;
++	u16 tBERS;
++	u16 tR;
++	u16 tCCS;
++	/*
++	 * 7 Reserved (0)
++	 * 6 1 = supports NV-DDR2 timing mode 8
++	 * 5 1 = supports NV-DDR timing mode 5
++	 * 4 1 = supports NV-DDR timing mode 4
++	 * 3 1 = supports NV-DDR timing mode 3
++	 * 2 1 = supports NV-DDR timing mode 2
++	 * 1 1 = supports NV-DDR timing mode 1
++	 * 0 1 = supports NV-DDR timing mode 0
++	 */
++	u8 nvddr_timing_mode;
++	/*
++	 * 7 1 = supports timing mode 7
++	 * 6 1 = supports timing mode 6
++	 * 5 1 = supports timing mode 5
++	 * 4 1 = supports timing mode 4
++	 * 3 1 = supports timing mode 3
++	 * 2 1 = supports timing mode 2
++	 * 1 1 = supports timing mode 1
++	 * 0 1 = supports timing mode 0
++	 */
++	u8 nvddr2_timing_mode;
++	/*
++	 * 4-7 Reserved (0)
++	 * 3 1 = device requires Vpp enablement sequence
++	 * 2 1 = device supports CLK stopped for data input
++	 * 1 1 = typical capacitance
++	 * 0 tCAD value to use
++	 */
++	u8 nvddr_fetures;
++	u16 clk_pin_capacitance;
++	u16 io_pin_capacitance;
++	u16 input_pin_capacitance;
++	u8 input_pin_max_capacitance;
++	/*
++	 * 3-7 Reserved (0)
++	 * 2 1 = supports 18 Ohm drive strength
++	 * 1 1 = supports 25 Ohm drive strength
++	 * 0 1 = supports driver strength settings
++	 */
++	u8 drive_strength;
++	u16 tR_multi_plane;
++	u16 tADL;
++	u16 tR_ez_nand;
++	/*
++	 * 6-7 Reserved (0)
++	 * 5 1 = external VREFQ required for >= 200 MT/s
++	 * 4 1 = supports differential signaling for DQS
++	 * 3 1 = supports differential signaling for RE_n
++	 * 2 1 = supports ODT value of 30 Ohms
++	 * 1 1 = supports matrix termination ODT
++	 * 0 1 = supports self-termination ODT
++	 */
++	u8 nvddr2_features;
++	u8 nvddr2_warmup_cycles;
++	u8 reserved4[4];
++
++	/* vendor block. 164 */
++	u16 vendor_revision;
++	u8      vendor_spec[88];
++
++	/* CRC for Parameter Page. 254 */
++	u16 crc16;
++} __packed;
++
++/* JESD230-B */
++struct nand_jedec_params {
++	/* Revision information and features block. 0 */
++	/*
++	 * Byte 0:4Ah
++	 * Byte 1:45h
++	 * Byte 2:53h
++	 * Byte 3:44h
++	 */
++	u8 signature[4];
++	/*
++	 * 3-15: Reserved (0)
++	 * 2: 1 = supports parameter page revision 1.0 and standard revision 1.0
++	 * 1: 1 = supports vendor specific parameter page
++	 * 0: Reserved (0)
++	 */
++	u16 revision;
++	/*
++	 * 9-15 Reserved (0)
++	 * 8: 1 = supports program page register clear enhancement
++	 * 7: 1 = supports external Vpp
++	 * 6: 1 = supports Toggle Mode DDR
++	 * 5: 1 = supports Synchronous DDR
++	 * 4: 1 = supports multi-plane read operations
++	 * 3: 1 = supports multi-plane program and erase operations
++	 * 2: 1 = supports non-sequential page programming
++	 * 1: 1 = supports multiple LUN operations
++	 * 0: 1 = supports 16-bit data bus width
++	 */
++	u16 features;
++	/*
++	 * 11-23: Reserved (0)
++	 * 10: 1 = supports Synchronous Reset
++	 * 9: 1 = supports Reset LUN (Primary)
++	 * 8: 1 = supports Small Data Move
++	 * 7: 1 = supports Multi-plane Copyback Program (Primary)
++	 * 6: 1 = supports Random Data Out (Primary)
++	 * 5: 1 = supports Read Unique ID
++	 * 4: 1 = supports Copyback
++	 * 3: 1 = supports Read Status Enhanced (Primary)
++	 * 2: 1 = supports Get Features and Set Features
++	 * 1: 1 = supports Read Cache commands
++	 * 0: 1 = supports Page Cache Program command
++	 */
++	u8 opt_cmds[3];
++	/*
++	 * 8-15: Reserved (0)
++	 * 7: 1 = supports secondary Read Status Enhanced
++	 * 6: 1 = supports secondary Multi-plane Block Erase
++	 * 5: 1 = supports secondary Multi-plane Copyback Program
++	 * 4: 1 = supports secondary Multi-plane Program
++	 * 3: 1 = supports secondary Random Data Out
++	 * 2: 1 = supports secondary Multi-plane Copyback Read
++	 * 1: 1 = supports secondary Multi-plane Read Cache Random
++	 * 0: 1 = supports secondary Multi-plane Read
++	 */
++	u16 secondary_cmds;
++	u8 param_page_num;
++	u8 reserved0[18];
++
++	/* Manufacturer information block. 32*/
++	u8 manufacturer[12];
++	u8 model[20];
++	u8 jedec_id[6];
++	u8 reserved1[10];
++
++	/* Memory organization block. 80 */
++	u32 page_size;
++	u16 spare_size;
++	u8 reserved2[6];
++	u32 block_pages;
++	u32 lun_blocks;
++	u8 lun_num;
++	/*
++	 * 4-7 Column address cycles
++	 * 0-3 Row address cycles
++	 */
++	u8 addr_cycle;
++	u8 cell_bits;
++	u8 page_program_num;
++	/*
++	 * 4-7 Reserved (0)
++	 * 0-3 Number of plane address bits
++	 */
++	u8 plane_address_bits;
++	/*
++	 * 3-7: Reserved (0)
++	 * 2: 1= read cache supported
++	 * 1: 1 = program cache supported
++	 * 0: 1= No multi-plane block address restrictions
++	 */
++	u8 multi_plane_attr;
++	u8 reserved3[38];
++
++	/* Electrical parameters block. 144 */
++	/*
++	 * 6-15: Reserved (0)
++	 * 5: 1 = supports 20 ns speed grade (50 MHz)
++	 * 4: 1 = supports 25 ns speed grade (40 MHz)
++	 * 3: 1 = supports 30 ns speed grade (~33 MHz)
++	 * 2: 1 = supports 35 ns speed grade (~28 MHz)
++	 * 1: 1 = supports 50 ns speed grade (20 MHz)
++	 * 0: 1 = supports 100 ns speed grade (10 MHz)
++	 */
++	u16 sdr_speed;
++	/*
++	 * 8-15: Reserved (0)
++	 * 7: 1 = supports 5 ns speed grade (200 MHz)
++	 * 6: 1 = supports 6 ns speed grade (~166 MHz)
++	 * 5: 1 = supports 7.5 ns speed grade (~133 MHz)
++	 * 4: 1 = supports 10 ns speed grade (100 MHz)
++	 * 3: 1 = supports 12 ns speed grade (~83 MHz)
++	 * 2: 1 = supports 15 ns speed grade (~66 MHz)
++	 * 1: 1 = supports 25 ns speed grade (40 MHz)
++	 * 0: 1 = supports 30 ns speed grade (~33 MHz)
++	 */
++	u16 toggle_ddr_speed;
++	/*
++	 * 6-15: Reserved (0)
++	 * 5: 1 = supports 10 ns speed grade (100 MHz)
++	 * 4: 1 = supports 12 ns speed grade (~83 MHz)
++	 * 3: 1 = supports 15 ns speed grade (~66 MHz)
++	 * 2: 1 = supports 20 ns speed grade (50 MHz)
++	 * 1: 1 = supports 30 ns speed grade (~33 MHz)
++	 * 0: 1 = supports 50 ns speed grade (20 MHz)
++	 */
++	u16 sync_ddr_speed;
++	u8 sdr_features;
++	u8 toggle_ddr_features;
++	/*
++	 * 2-7: Reserved (0)
++	 * 1: Device supports CK stopped for data input
++	 * 0: tCAD value to use
++	 */
++	u8 sync_ddr_features;
++	u16 tPROG;
++	u16 tBERS;
++	u16 tR;
++	u16 tR_multi_plane;
++	u16 tCCS;
++	u16 io_pin_capacitance;
++	u16 input_pin_capacitance;
++	u16 ck_pin_capacitance;
++	/*
++	 * 3-7: Reserved (0)
++	 * 2: 1 = supports 18 ohm drive strength
++	 * 1: 1 = supports 25 ohm drive strength
++	 * 0: 1 = supports 35ohm/50ohm drive strength
++	 */
++	u8 drive_strength;
++	u16 tADL;
++	u8 reserved4[36];
++
++	/* ECC and endurance block. 208 */
++	u8 target_begin_valid_blocks;
++	u16 valid_block_endurance;
++	/*
++	 * Byte 0: Number of bits ECC correctability
++	 * Byte 1: Codeword size
++	 * Byte 2-3: Bad blocks maximum per LUN
++	 * Byte 4-5: Block endurance
++	 * Byte 6-7: Reserved (0)
++	 */
++	u8 endurance_block0[8];
++	u8 endurance_block1[8];
++	u8 endurance_block2[8];
++	u8 endurance_block3[8];
++	u8 reserved5[29];
++
++	/* Reserved. 272 */
++	u8 reserved6[148];
++
++	/* Vendor specific block. 420  */
++	u16 vendor_revision;
++	u8      vendor_spec[88];
++
++	/* CRC for Parameter Page. 510 */
++	u16 crc16;
++} __packed;
++
++/* parallel nand io width */
++enum nand_io_width {
++	NAND_IO8,
++	NAND_IO16
++};
++
++/* all supported nand timming type */
++enum nand_timing_type {
++	NAND_TIMING_SDR,
++	NAND_TIMING_SYNC_DDR,
++	NAND_TIMING_TOGGLE_DDR,
++	NAND_TIMING_NVDDR2
++};
++
++/* nand basic commands */
++struct nand_cmds {
++	short reset;
++	short read_id;
++	short read_status;
++	short read_param_page;
++	short set_feature;
++	short get_feature;
++	short read_1st;
++	short read_2nd;
++	short random_out_1st;
++	short random_out_2nd;
++	short program_1st;
++	short program_2nd;
++	short erase_1st;
++	short erase_2nd;
++	short read_cache;
++	short read_cache_last;
++	short program_cache;
++};
++
++/*
++ * addressing for nand physical address
++ * @row_bit_start: row address start bit
++ * @block_bit_start: block address start bit
++ * @plane_bit_start: plane address start bit
++ * @lun_bit_start: lun address start bit
++ */
++struct nand_addressing {
++	u8 row_bit_start;
++	u8 block_bit_start;
++	u8 plane_bit_start;
++	u8 lun_bit_start;
++};
++
++/*
++ * nand operations status
++ * @array_busy: indicates device array operation busy
++ * @write_protect: indicates the device cannot be wrote or erased
++ * @erase_fail: indicates erase operation fail
++ * @program_fail: indicates program operation fail
++ */
++struct nand_status {
++	u8 array_busy;
++	u8 write_protect;
++	u8 erase_fail;
++	u8 program_fail;
++};
++
++/*
++ * nand endurance information
++ * @pe_cycle: max program/erase cycle for nand stored data stability
++ * @ecc_req: ecc strength required for the nand, measured per 1KB
++ * @max_bitflips: bitflips is ecc corrected bits,
++ *    max_bitflips is the threshold for nand stored data stability
++ *    if corrected bits is over max_bitflips, stored data must be moved
++ *    to another good block
++ */
++struct nand_endurance {
++	int pe_cycle;
++	int ecc_req;
++	int max_bitflips;
++};
++
++/* wait for nand busy type */
++enum nand_wait_type {
++	NAND_WAIT_IRQ,
++	NAND_WAIT_POLLING,
++	NAND_WAIT_TWHR2,
++};
++
++/* each nand array operations time */
++struct nand_array_timing {
++	u16 tRST;
++	u16 tWHR;
++	u16 tR;
++	u16 tRCBSY;
++	u16 tFEAT;
++	u16 tPROG;
++	u16 tPCBSY;
++	u16 tBERS;
++	u16 tDBSY;
++};
++
++/* nand sdr interface timing required */
++struct nand_sdr_timing {
++	u16 tREA;
++	u16 tREH;
++	u16 tCR;
++	u16 tRP;
++	u16 tWP;
++	u16 tWH;
++	u16 tWHR;
++	u16 tCLS;
++	u16 tALS;
++	u16 tCLH;
++	u16 tALH;
++	u16 tWC;
++	u16 tRC;
++};
++
++/* nand onfi ddr (nvddr) interface timing required */
++struct nand_onfi_timing {
++	u16 tCAD;
++	u16 tWPRE;
++	u16 tWPST;
++	u16 tWRCK;
++	u16 tDQSCK;
++	u16 tWHR;
++};
++
++/* nand toggle ddr (toggle 1.0) interface timing required */
++struct nand_toggle_timing {
++	u16 tCS;
++	u16 tCH;
++	u16 tCAS;
++	u16 tCAH;
++	u16 tCALS;
++	u16 tCALH;
++	u16 tWP;
++	u16 tWPRE;
++	u16 tWPST;
++	u16 tWPSTH;
++	u16 tCR;
++	u16 tRPRE;
++	u16 tRPST;
++	u16 tRPSTH;
++	u16 tCDQSS;
++	u16 tWHR;
++};
++
++/* nand basic device information */
++struct nand_device {
++	u8 *name;
++	u64 id;
++	u8 id_len;
++	u8 io_width;
++	u8 row_cycle;
++	u8 col_cycle;
++	u8 target_num;
++	u8 lun_num;
++	u8 plane_num;
++	int block_num;
++	int block_size;
++	int page_size;
++	int spare_size;
++	int min_program_pages;
++	struct nand_cmds *cmds;
++	struct nand_addressing *addressing;
++	struct nand_status *status;
++	struct nand_endurance *endurance;
++	struct nand_array_timing *array_timing;
++};
++
++#define NAND_DEVICE(_name, _id, _id_len, _io_width, _row_cycle, \
++		    _col_cycle, _target_num, _lun_num, _plane_num, \
++		    _block_num, _block_size, _page_size, _spare_size, \
++		    _min_program_pages, _cmds, _addressing, _status, \
++		    _endurance, _array_timing) \
++{ \
++	_name, _id, _id_len, _io_width, _row_cycle, \
++	_col_cycle, _target_num, _lun_num, _plane_num, \
++	_block_num, _block_size, _page_size, _spare_size, \
++	_min_program_pages, _cmds, _addressing, _status, \
++	_endurance, _array_timing \
++}
++
++#define MAX_ID_NUM      sizeof(u64)
++
++#define NAND_PACK_ID(id0, id1, id2, id3, id4, id5, id6, id7) \
++	( \
++	  id0 | id1 << 8 | id2 << 16 | id3 << 24 | \
++	  (u64)id4 << 32 | (u64)id5 << 40 | \
++	  (u64)id6 << 48 | (u64)id7 << 56 \
++	)
++
++#define NAND_UNPACK_ID(id, ids, len) \
++	do { \
++		int _i; \
++		for (_i = 0; _i < len; _i++) \
++			ids[_i] = id >> (_i << 3) & 0xff; \
++	} while (0)
++
++static inline int nand_block_pages(struct nand_device *device)
++{
++	return div_down(device->block_size, device->page_size);
++}
++
++static inline int nand_lun_blocks(struct nand_device *device)
++{
++	return device->plane_num * device->block_num;
++}
++
++static inline int nand_target_blocks(struct nand_device *device)
++{
++	return device->lun_num * device->plane_num * device->block_num;
++}
++
++static inline int nand_total_blocks(struct nand_device *device)
++{
++	return device->target_num * device->lun_num * device->plane_num *
++	       device->block_num;
++}
++
++struct nand_device *nand_get_device(int index);
++#endif /* __NAND_DEVICE_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi.h b/drivers/mtd/nandx/core/nfi.h
+new file mode 100644
+index 0000000000..ba84e73ccc
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFI_H__
++#define __NFI_H__
++
++struct nfi_format {
++	int page_size;
++	int spare_size;
++	int ecc_req;
++};
++
++struct nfi {
++	int sector_size;
++	int sector_spare_size;
++	int fdm_size; /*for sector*/
++	int fdm_ecc_size;
++	int ecc_strength;
++	int ecc_parity_size; /*for sector*/
++
++	int (*select_chip)(struct nfi *nfi, int cs);
++	int (*set_format)(struct nfi *nfi, struct nfi_format *format);
++	int (*set_timing)(struct nfi *nfi, void *timing, int type);
++	int (*nfi_ctrl)(struct nfi *nfi, int cmd, void *args);
++
++	int (*reset)(struct nfi *nfi);
++	int (*send_cmd)(struct nfi *nfi, short cmd);
++	int (*send_addr)(struct nfi *nfi, int col, int row,
++			 int col_cycle, int row_cycle);
++	int (*trigger)(struct nfi *nfi);
++
++	int (*write_page)(struct nfi *nfi, u8 *data, u8 *fdm);
++	int (*write_bytes)(struct nfi *nfi, u8 *data, int count);
++	int (*read_sectors)(struct nfi *nfi, u8 *data, u8 *fdm,
++			    int sectors);
++	int (*read_bytes)(struct nfi *nfi, u8 *data, int count);
++
++	int (*wait_ready)(struct nfi *nfi, int type, u32 timeout);
++
++	int (*enable_randomizer)(struct nfi *nfi, u32 row, bool encode);
++	int (*disable_randomizer)(struct nfi *nfi);
++};
++
++struct nfi *nfi_init(struct nfi_resource *res);
++void nfi_exit(struct nfi *nfi);
++
++#endif /* __NFI_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_base.c b/drivers/mtd/nandx/core/nfi/nfi_base.c
+new file mode 100644
+index 0000000000..d8679d7aa3
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_base.c
+@@ -0,0 +1,1357 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++/**
++ * nfi_base.c - the base logic for nfi to access nand flash
++ *
++ * slc/mlc/tlc could use same code to access nand
++ * of cause, there still some work need to do
++ * even for spi nand, there should be a chance to integrate code together
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "../nfi.h"
++#include "../nand_device.h"
++#include "nfi_regs.h"
++#include "nfiecc.h"
++#include "nfi_base.h"
++
++static const int spare_size_mt7622[] = {
++	16, 26, 27, 28
++};
++
++#define RAND_SEED_SHIFT(op) \
++	((op) == RAND_ENCODE ? ENCODE_SEED_SHIFT : DECODE_SEED_SHIFT)
++#define RAND_EN(op) \
++	((op) == RAND_ENCODE ? RAN_ENCODE_EN : RAN_DECODE_EN)
++
++#define SS_SEED_NUM     128
++static u16 ss_randomizer_seed[SS_SEED_NUM] = {
++	0x576A, 0x05E8, 0x629D, 0x45A3, 0x649C, 0x4BF0, 0x2342, 0x272E,
++	0x7358, 0x4FF3, 0x73EC, 0x5F70, 0x7A60, 0x1AD8, 0x3472, 0x3612,
++	0x224F, 0x0454, 0x030E, 0x70A5, 0x7809, 0x2521, 0x484F, 0x5A2D,
++	0x492A, 0x043D, 0x7F61, 0x3969, 0x517A, 0x3B42, 0x769D, 0x0647,
++	0x7E2A, 0x1383, 0x49D9, 0x07B8, 0x2578, 0x4EEC, 0x4423, 0x352F,
++	0x5B22, 0x72B9, 0x367B, 0x24B6, 0x7E8E, 0x2318, 0x6BD0, 0x5519,
++	0x1783, 0x18A7, 0x7B6E, 0x7602, 0x4B7F, 0x3648, 0x2C53, 0x6B99,
++	0x0C23, 0x67CF, 0x7E0E, 0x4D8C, 0x5079, 0x209D, 0x244A, 0x747B,
++	0x350B, 0x0E4D, 0x7004, 0x6AC3, 0x7F3E, 0x21F5, 0x7A15, 0x2379,
++	0x1517, 0x1ABA, 0x4E77, 0x15A1, 0x04FA, 0x2D61, 0x253A, 0x1302,
++	0x1F63, 0x5AB3, 0x049A, 0x5AE8, 0x1CD7, 0x4A00, 0x30C8, 0x3247,
++	0x729C, 0x5034, 0x2B0E, 0x57F2, 0x00E4, 0x575B, 0x6192, 0x38F8,
++	0x2F6A, 0x0C14, 0x45FC, 0x41DF, 0x38DA, 0x7AE1, 0x7322, 0x62DF,
++	0x5E39, 0x0E64, 0x6D85, 0x5951, 0x5937, 0x6281, 0x33A1, 0x6A32,
++	0x3A5A, 0x2BAC, 0x743A, 0x5E74, 0x3B2E, 0x7EC7, 0x4FD2, 0x5D28,
++	0x751F, 0x3EF8, 0x39B1, 0x4E49, 0x746B, 0x6EF6, 0x44BE, 0x6DB7
++};
++
++#if 0
++static void dump_register(void *regs)
++{
++	int i;
++
++	pr_info("registers:\n");
++	for (i = 0; i < 0x600; i += 0x10) {
++		pr_info("    address 0x%X : %X %X %X %X\n",
++			(u32)((unsigned long)regs + i),
++			(u32)readl(regs + i),
++			(u32)readl(regs + i + 0x4),
++			(u32)readl(regs + i + 0x8),
++			(u32)readl(regs + i + 0xC));
++	}
++}
++#endif
++
++static int nfi_enable_randomizer(struct nfi *nfi, u32 row, bool encode)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	enum randomizer_op op = RAND_ENCODE;
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	if (!encode)
++		op = RAND_DECODE;
++
++	/* randomizer type and reseed type setup */
++	val = readl(regs + NFI_CNFG);
++	val |= CNFG_RAND_SEL | CNFG_RESEED_SEC_EN;
++	writel(val, regs + NFI_CNFG);
++
++	/* randomizer seed and type setup */
++	val = ss_randomizer_seed[row % SS_SEED_NUM] & RAN_SEED_MASK;
++	val <<= RAND_SEED_SHIFT(op);
++	val |= RAND_EN(op);
++	writel(val, regs + NFI_RANDOM_CNFG);
++
++	return 0;
++}
++
++static int nfi_disable_randomizer(struct nfi *nfi)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++
++	writel(0, nb->res.nfi_regs + NFI_RANDOM_CNFG);
++
++	return 0;
++}
++
++static int nfi_irq_handler(int irq, void *data)
++{
++	struct nfi_base *nb = (struct nfi_base *) data;
++	void *regs = nb->res.nfi_regs;
++	u16 status, en;
++
++	status = readw(regs + NFI_INTR_STA);
++	en = readw(regs + NFI_INTR_EN);
++
++	if (!(status & en))
++		return NAND_IRQ_NONE;
++
++	writew(~status & en, regs + NFI_INTR_EN);
++
++	nandx_event_complete(nb->done);
++
++	return NAND_IRQ_HANDLED;
++}
++
++static int nfi_select_chip(struct nfi *nfi, int cs)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++
++	writel(cs, nb->res.nfi_regs + NFI_CSEL);
++
++	return 0;
++}
++
++static inline void set_op_mode(void *regs, u32 mode)
++{
++	u32 val = readl(regs + NFI_CNFG);
++
++	val &= ~CNFG_OP_MODE_MASK;
++	val |= mode;
++
++	writel(val, regs + NFI_CNFG);
++}
++
++static int nfi_reset(struct nfi *nfi)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	int ret, val;
++
++	/* The NFI reset to reset all registers and force the NFI
++	 * master be early terminated
++	 */
++	writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON);
++
++	/* check state of NFI internal FSM and NAND interface FSM */
++	ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA, val,
++					!(val & MASTER_BUS_BUSY),
++					10, NFI_TIMEOUT);
++	if (ret)
++		pr_info("nfi reset timeout...\n");
++
++	writel(CON_FIFO_FLUSH | CON_NFI_RST, regs + NFI_CON);
++	writew(STAR_DE, regs + NFI_STRDATA);
++
++	return ret;
++}
++
++static void bad_mark_swap(struct nfi *nfi, u8 *buf, u8 *fdm)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	u32 start_sector = div_down(nb->col, nfi->sector_size);
++	u32 data_mark_pos;
++	u8 temp;
++
++	/* raw access, no need to do swap. */
++	if (!nb->ecc_en)
++		return;
++
++	if (!buf || !fdm)
++		return;
++
++	if (nb->bad_mark_ctrl.sector < start_sector ||
++	    nb->bad_mark_ctrl.sector > start_sector + nb->rw_sectors)
++		return;
++
++	data_mark_pos = nb->bad_mark_ctrl.position +
++			(nb->bad_mark_ctrl.sector - start_sector) *
++			nfi->sector_size;
++
++	temp = *fdm;
++	*fdm = *(buf + data_mark_pos);
++	*(buf + data_mark_pos) = temp;
++}
++
++static u8 *fdm_shift(struct nfi *nfi, u8 *fdm, int sector)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	u8 *pos;
++
++	if (!fdm)
++		return NULL;
++
++	/* map the sector's FDM data to free oob:
++	 * the beginning of the oob area stores the FDM data of bad mark sectors
++	 */
++	if (sector < nb->bad_mark_ctrl.sector)
++		pos = fdm + (sector + 1) * nfi->fdm_size;
++	else if (sector == nb->bad_mark_ctrl.sector)
++		pos = fdm;
++	else
++		pos = fdm + sector * nfi->fdm_size;
++
++	return pos;
++
++}
++
++static void set_bad_mark_ctrl(struct nfi_base *nb)
++{
++	int temp, page_size = nb->format.page_size;
++
++	nb->bad_mark_ctrl.bad_mark_swap = bad_mark_swap;
++	nb->bad_mark_ctrl.fdm_shift = fdm_shift;
++
++	temp = nb->nfi.sector_size + nb->nfi.sector_spare_size;
++	nb->bad_mark_ctrl.sector = div_down(page_size, temp);
++	nb->bad_mark_ctrl.position = reminder(page_size, temp);
++}
++
++/* NOTE: check if page_size valid future */
++static int setup_format(struct nfi_base *nb, int spare_idx)
++{
++	struct nfi *nfi = &nb->nfi;
++	u32 page_size = nb->format.page_size;
++	u32 val;
++
++	switch (page_size) {
++	case 512:
++		val = PAGEFMT_512_2K | PAGEFMT_SEC_SEL_512;
++		break;
++
++	case KB(2):
++		if (nfi->sector_size == 512)
++			val = PAGEFMT_2K_4K | PAGEFMT_SEC_SEL_512;
++		else
++			val = PAGEFMT_512_2K;
++
++		break;
++
++	case KB(4):
++		if (nfi->sector_size == 512)
++			val = PAGEFMT_4K_8K | PAGEFMT_SEC_SEL_512;
++		else
++			val = PAGEFMT_2K_4K;
++
++		break;
++
++	case KB(8):
++		if (nfi->sector_size == 512)
++			val = PAGEFMT_8K_16K | PAGEFMT_SEC_SEL_512;
++		else
++			val = PAGEFMT_4K_8K;
++
++		break;
++
++	case KB(16):
++		val = PAGEFMT_8K_16K;
++		break;
++
++	default:
++		pr_info("invalid page len: %d\n", page_size);
++		return -EINVAL;
++	}
++
++	val |= spare_idx << PAGEFMT_SPARE_SHIFT;
++	val |= nfi->fdm_size << PAGEFMT_FDM_SHIFT;
++	val |= nfi->fdm_ecc_size << PAGEFMT_FDM_ECC_SHIFT;
++	writel(val, nb->res.nfi_regs + NFI_PAGEFMT);
++
++	if (nb->custom_sector_en) {
++		val = nfi->sector_spare_size + nfi->sector_size;
++		val |= SECCUS_SIZE_EN;
++		writel(val, nb->res.nfi_regs + NFI_SECCUS_SIZE);
++	}
++
++	return 0;
++}
++
++static int adjust_spare(struct nfi_base *nb, int *spare)
++{
++	int multi = nb->nfi.sector_size == 512 ? 1 : 2;
++	int i, count = nb->caps->spare_size_num;
++
++	if (*spare >= nb->caps->spare_size[count - 1] * multi) {
++		*spare = nb->caps->spare_size[count - 1] * multi;
++		return count - 1;
++	}
++
++	if (*spare < nb->caps->spare_size[0] * multi)
++		return -EINVAL;
++
++	for (i = 1; i < count; i++) {
++		if (*spare < nb->caps->spare_size[i] * multi) {
++			*spare = nb->caps->spare_size[i - 1] * multi;
++			return i - 1;
++		}
++	}
++
++	return -EINVAL;
++}
++
++static int nfi_set_format(struct nfi *nfi, struct nfi_format *format)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfiecc *ecc = nb->ecc;
++	int ecc_strength = format->ecc_req;
++	int min_fdm, min_ecc, max_ecc;
++	u32 temp, page_sectors;
++	int spare_idx = 0;
++
++	if (!nb->buf) {
++#if NANDX_BULK_IO_USE_DRAM
++		nb->buf = NANDX_NFI_BUF_ADDR;
++#else
++		nb->buf = mem_alloc(1, format->page_size + format->spare_size);
++#endif
++		if (!nb->buf)
++			return -ENOMEM;
++	}
++
++	nb->format = *format;
++
++	/* ToBeFixed: for spi nand, now sector size is 512,
++	 * it should be same with slc.
++	 */
++	nfi->sector_size = 512;
++	/* format->ecc_req is the requirement per 1KB */
++	ecc_strength >>= 1;
++
++	page_sectors = div_down(format->page_size, nfi->sector_size);
++	nfi->sector_spare_size = div_down(format->spare_size, page_sectors);
++
++	if (!nb->custom_sector_en) {
++		spare_idx = adjust_spare(nb, &nfi->sector_spare_size);
++		if (spare_idx < 0)
++			return -EINVAL;
++	}
++
++	/* calculate ecc strength and fdm size */
++	temp = (nfi->sector_spare_size - nb->caps->max_fdm_size) * 8;
++	min_ecc = div_down(temp, nb->caps->ecc_parity_bits);
++	min_ecc = ecc->adjust_strength(ecc, min_ecc);
++	if (min_ecc < 0)
++		return -EINVAL;
++
++	temp = div_up(nb->res.min_oob_req, page_sectors);
++	temp = (nfi->sector_spare_size - temp) * 8;
++	max_ecc = div_down(temp, nb->caps->ecc_parity_bits);
++	max_ecc = ecc->adjust_strength(ecc, max_ecc);
++	if (max_ecc < 0)
++		return -EINVAL;
++
++	temp = div_up(temp * nb->caps->ecc_parity_bits, 8);
++	temp = nfi->sector_spare_size - temp;
++	min_fdm = min_t(u32, temp, (u32)nb->caps->max_fdm_size);
++
++	if (ecc_strength > max_ecc) {
++		pr_info("required ecc strength %d, max supported %d\n",
++			ecc_strength, max_ecc);
++		nfi->ecc_strength = max_ecc;
++		nfi->fdm_size = min_fdm;
++	} else if (format->ecc_req < min_ecc) {
++		nfi->ecc_strength = min_ecc;
++		nfi->fdm_size = nb->caps->max_fdm_size;
++	} else {
++		ecc_strength = ecc->adjust_strength(ecc, ecc_strength);
++		if (ecc_strength < 0)
++			return -EINVAL;
++
++		nfi->ecc_strength = ecc_strength;
++		temp = div_up(ecc_strength * nb->caps->ecc_parity_bits, 8);
++		nfi->fdm_size = nfi->sector_spare_size - temp;
++	}
++
++	nb->page_sectors = div_down(format->page_size, nfi->sector_size);
++
++	/* some IC has fixed fdm_ecc_size, if not assigend, set to fdm_size */
++	nfi->fdm_ecc_size = nb->caps->fdm_ecc_size ? : nfi->fdm_size;
++
++	nfi->ecc_parity_size = div_up(nfi->ecc_strength *
++				      nb->caps->ecc_parity_bits,
++				      8);
++	set_bad_mark_ctrl(nb);
++
++	pr_debug("sector_size: %d\n", nfi->sector_size);
++	pr_debug("sector_spare_size: %d\n", nfi->sector_spare_size);
++	pr_debug("fdm_size: %d\n", nfi->fdm_size);
++	pr_debug("fdm_ecc_size: %d\n", nfi->fdm_ecc_size);
++	pr_debug("ecc_strength: %d\n", nfi->ecc_strength);
++	pr_debug("ecc_parity_size: %d\n", nfi->ecc_parity_size);
++
++	return setup_format(nb, spare_idx);
++}
++
++static int nfi_ctrl(struct nfi *nfi, int cmd, void *args)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	int ret = 0;
++
++	switch (cmd) {
++	case NFI_CTRL_DMA:
++		nb->dma_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_AUTOFORMAT:
++		nb->auto_format = *(bool *)args;
++		break;
++
++	case NFI_CTRL_NFI_IRQ:
++		nb->nfi_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_PAGE_IRQ:
++		nb->page_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_BAD_MARK_SWAP:
++		nb->bad_mark_swap_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC:
++		nb->ecc_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_MODE:
++		nb->ecc_mode = *(enum nfiecc_mode *)args;
++		break;
++
++	case NFI_CTRL_ECC_CLOCK:
++		/* NOTE: it seems that there's nothing need to do
++		 * if new IC need, just add tht logic
++		 */
++		nb->ecc_clk_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_IRQ:
++		nb->ecc_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_DECODE_MODE:
++		nb->ecc_deccon = *(enum nfiecc_deccon *)args;
++		break;
++
++	default:
++		pr_info("invalid arguments.\n");
++		ret = -EOPNOTSUPP;
++		break;
++	}
++
++	pr_debug("%s: set cmd(%d) to %d\n", __func__, cmd, *(int *)args);
++	return ret;
++}
++
++static int nfi_send_cmd(struct nfi *nfi, short cmd)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	int ret;
++	u32 val;
++
++	pr_debug("%s: cmd 0x%x\n", __func__, cmd);
++
++	if (cmd < 0)
++		return -EINVAL;
++
++	set_op_mode(regs, nb->op_mode);
++
++	writel(cmd, regs + NFI_CMD);
++
++	ret = readl_poll_timeout_atomic(regs + NFI_STA,
++					val, !(val & STA_CMD),
++					5, NFI_TIMEOUT);
++	if (ret)
++		pr_info("send cmd 0x%x timeout\n", cmd);
++
++	return ret;
++}
++
++static int nfi_send_addr(struct nfi *nfi, int col, int row,
++			 int col_cycle, int row_cycle)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	int ret;
++	u32 val;
++
++	pr_debug("%s: col 0x%x, row 0x%x, col_cycle 0x%x, row_cycle 0x%x\n",
++		 __func__, col, row, col_cycle, row_cycle);
++
++	nb->col = col;
++	nb->row = row;
++
++	writel(col, regs + NFI_COLADDR);
++	writel(row, regs + NFI_ROWADDR);
++	writel(col_cycle | (row_cycle << ROW_SHIFT), regs + NFI_ADDRNOB);
++
++	ret = readl_poll_timeout_atomic(regs + NFI_STA,
++					val, !(val & STA_ADDR),
++					5, NFI_TIMEOUT);
++	if (ret)
++		pr_info("send address timeout\n");
++
++	return ret;
++}
++
++static int nfi_trigger(struct nfi *nfi)
++{
++	/* Nothing need to do. */
++	return 0;
++}
++
++static inline int wait_io_ready(void *regs)
++{
++	u32 val;
++	int ret;
++
++	ret = readl_poll_timeout_atomic(regs + NFI_PIO_DIRDY,
++					val, val & PIO_DI_RDY,
++					2, NFI_TIMEOUT);
++	if (ret)
++		pr_info("wait io ready timeout\n");
++
++	return ret;
++}
++
++static int wait_ready_irq(struct nfi_base *nb, u32 timeout)
++{
++	void *regs = nb->res.nfi_regs;
++	int ret;
++	u32 val;
++
++	writel(0xf1, regs + NFI_CNRNB);
++	nandx_event_init(nb->done);
++
++	writel(INTR_BUSY_RETURN_EN, (void *)(regs + NFI_INTR_EN));
++
++	/**
++	 * check if nand already bean ready,
++	 * avoid issue that casued by missing irq-event.
++	 */
++	val = readl(regs + NFI_STA);
++	if (val & STA_BUSY2READY) {
++		readl(regs + NFI_INTR_STA);
++		writel(0, (void *)(regs + NFI_INTR_EN));
++		return 0;
++	}
++
++	ret = nandx_event_wait_complete(nb->done, timeout);
++
++	writew(0, regs + NFI_CNRNB);
++	return ret;
++}
++
++static void wait_ready_twhr2(struct nfi_base *nb, u32 timeout)
++{
++	/* NOTE: this for tlc */
++}
++
++static int wait_ready_poll(struct nfi_base *nb, u32 timeout)
++{
++	void *regs = nb->res.nfi_regs;
++	int ret;
++	u32 val;
++
++	writel(0x21, regs + NFI_CNRNB);
++	ret = readl_poll_timeout_atomic(regs + NFI_STA, val,
++					val & STA_BUSY2READY,
++					2, timeout);
++	writew(0, regs + NFI_CNRNB);
++
++	return ret;
++}
++
++static int nfi_wait_ready(struct nfi *nfi, int type, u32 timeout)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	int ret;
++
++	switch (type) {
++	case NAND_WAIT_IRQ:
++		if (nb->nfi_irq_en)
++			ret = wait_ready_irq(nb, timeout);
++		else
++			ret = -EINVAL;
++
++		break;
++
++	case NAND_WAIT_POLLING:
++		ret = wait_ready_poll(nb, timeout);
++		break;
++
++	case NAND_WAIT_TWHR2:
++		wait_ready_twhr2(nb, timeout);
++		ret = 0;
++		break;
++
++	default:
++		ret = -EINVAL;
++		break;
++	}
++
++	if (ret)
++		pr_info("%s: type 0x%x, timeout 0x%x\n",
++		       __func__, type, timeout);
++
++	return ret;
++}
++
++static int enable_ecc_decode(struct nfi_base *nb, int sectors)
++{
++	struct nfi *nfi = &nb->nfi;
++	struct nfiecc *ecc = nb->ecc;
++
++	ecc->config.op = ECC_DECODE;
++	ecc->config.mode = nb->ecc_mode;
++	ecc->config.deccon = nb->ecc_deccon;
++	ecc->config.sectors = sectors;
++	ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size;
++	ecc->config.strength = nfi->ecc_strength;
++
++	return ecc->enable(ecc);
++}
++
++static int enable_ecc_encode(struct nfi_base *nb)
++{
++	struct nfiecc *ecc = nb->ecc;
++	struct nfi *nfi = &nb->nfi;
++
++	ecc->config.op = ECC_ENCODE;
++	ecc->config.mode = nb->ecc_mode;
++	ecc->config.len = nfi->sector_size + nfi->fdm_ecc_size;
++	ecc->config.strength = nfi->ecc_strength;
++
++	return ecc->enable(ecc);
++}
++
++static void read_fdm(struct nfi_base *nb, u8 *fdm, int start_sector,
++		     int sectors)
++{
++	void *regs = nb->res.nfi_regs;
++	int j, i = start_sector;
++	u32 vall, valm;
++	u8 *buf = fdm;
++
++	for (; i < start_sector + sectors; i++) {
++		if (nb->bad_mark_swap_en)
++			buf = nb->bad_mark_ctrl.fdm_shift(&nb->nfi, fdm, i);
++
++		vall = readl(regs + NFI_FDML(i));
++		valm = readl(regs + NFI_FDMM(i));
++
++		for (j = 0; j < nb->nfi.fdm_size; j++)
++			*buf++ = (j >= 4 ? valm : vall) >> ((j & 3) << 3);
++	}
++}
++
++static void write_fdm(struct nfi_base *nb, u8 *fdm)
++{
++	struct nfi *nfi = &nb->nfi;
++	void *regs = nb->res.nfi_regs;
++	u32 vall, valm;
++	int i, j;
++	u8 *buf = fdm;
++
++	for (i = 0; i < nb->page_sectors; i++) {
++		if (nb->bad_mark_swap_en)
++			buf = nb->bad_mark_ctrl.fdm_shift(nfi, fdm, i);
++
++		vall = 0;
++		for (j = 0; j < 4; j++)
++			vall |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8);
++		writel(vall, regs + NFI_FDML(i));
++
++		valm = 0;
++		for (j = 0; j < 4; j++)
++			valm |= (j < nfi->fdm_size ? *buf++ : 0xff) << (j * 8);
++		writel(valm, regs + NFI_FDMM(i));
++	}
++}
++
++/* NOTE: pio not use auto format */
++static int pio_rx_data(struct nfi_base *nb, u8 *data, u8 *fdm,
++		       int sectors)
++{
++	struct nfiecc_status ecc_status;
++	struct nfi *nfi = &nb->nfi;
++	void *regs = nb->res.nfi_regs;
++	u32 val, bitflips = 0;
++	int len, ret, i;
++	u8 *buf;
++
++	val = readl(regs + NFI_CNFG) | CNFG_BYTE_RW;
++	writel(val, regs + NFI_CNFG);
++
++	len = nfi->sector_size + nfi->sector_spare_size;
++	len *= sectors;
++
++	for (i = 0; i < len; i++) {
++		ret = wait_io_ready(regs);
++		if (ret)
++			return ret;
++
++		nb->buf[i] = readb(regs + NFI_DATAR);
++	}
++
++	/* TODO: do error handle for autoformat setting of pio */
++	if (nb->ecc_en) {
++		for (i = 0; i < sectors; i++) {
++			buf = nb->buf + i * (nfi->sector_size +
++					     nfi->sector_spare_size);
++			ret = nb->ecc->correct_data(nb->ecc, &ecc_status,
++						    buf, i);
++			if (data)
++				memcpy(data + i * nfi->sector_size,
++				       buf, nfi->sector_size);
++			if (fdm)
++				memcpy(fdm + i * nfi->fdm_size,
++				       buf + nfi->sector_size, nfi->fdm_size);
++			if (ret) {
++				ret = nb->ecc->decode_status(nb->ecc, i, 1);
++				if (ret < 0)
++					return ret;
++
++				bitflips = max_t(int, (int)bitflips, ret);
++			}
++		}
++
++		return bitflips;
++	}
++
++	/* raw read, only data not null, and its length should be $len */
++	if (data)
++		memcpy(data, nb->buf, len);
++
++	return 0;
++}
++
++static int pio_tx_data(struct nfi_base *nb, u8 *data, u8 *fdm,
++		       int sectors)
++{
++	struct nfi *nfi = &nb->nfi;
++	void *regs = nb->res.nfi_regs;
++	u32 i, val;
++	int len, ret;
++
++	val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW;
++	writew(val, regs + NFI_CNFG);
++
++	len = nb->ecc_en ? nfi->sector_size :
++	      nfi->sector_size + nfi->sector_spare_size;
++	len *= sectors;
++
++	/* data shouldn't null,
++	 * and if ecc enable ,fdm been written in prepare process
++	 */
++	for (i = 0; i < len; i++) {
++		ret = wait_io_ready(regs);
++		if (ret)
++			return ret;
++		writeb(data[i], regs + NFI_DATAW);
++	}
++
++	return 0;
++}
++
++static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm,
++			  int sectors)
++{
++	u32 empty = readl(nb->res.nfi_regs + NFI_STA) & STA_EMP_PAGE;
++
++	if (empty) {
++		pr_info("empty page!\n");
++		return true;
++	}
++
++	return false;
++}
++
++static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data,
++		      u8 *fdm, bool read)
++{
++	void *regs = nb->res.nfi_regs;
++	u32 len = nb->nfi.sector_size * sectors;
++	bool irq_en = nb->dma_en && nb->nfi_irq_en;
++	void *dma_addr;
++	u32 val;
++	int ret;
++
++	nb->rw_sectors = sectors;
++
++	if (irq_en) {
++		nandx_event_init(nb->done);
++		writel(INTR_AHB_DONE_EN, regs + NFI_INTR_EN);
++	}
++
++	val = readw(regs + NFI_CNFG);
++	if (read)
++		val |= CNFG_READ_EN;
++	else
++		val &= ~CNFG_READ_EN;
++
++	/* as design, now, auto format enabled when ecc enabled */
++	if (nb->ecc_en) {
++		val |= CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN;
++
++		if (read)
++			ret = enable_ecc_decode(nb, sectors);
++		else
++			ret = enable_ecc_encode(nb);
++
++		if (ret) {
++			pr_info("%s: ecc enable %s fail!\n", __func__,
++			       read ? "decode" : "encode");
++			return ret;
++		}
++	} else {
++		val &= ~(CNFG_HW_ECC_EN | CNFG_AUTO_FMT_EN);
++	}
++
++	if (!read && nb->bad_mark_swap_en)
++		nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm);
++
++	if (!nb->ecc_en && read)
++		len += sectors * nb->nfi.sector_spare_size;
++
++	if (nb->dma_en) {
++		val |= CNFG_DMA_BURST_EN | CNFG_AHB;
++
++		if (read) {
++			dma_addr = (void *)(unsigned long)nandx_dma_map(
++						nb->res.dev, nb->buf,
++						(u64)len, NDMA_FROM_DEV);
++		} else {
++			memcpy(nb->buf, data, len);
++			dma_addr = (void *)(unsigned long)nandx_dma_map(
++						nb->res.dev, nb->buf,
++						(u64)len, NDMA_TO_DEV);
++		}
++
++		writel((unsigned long)dma_addr, (void *)regs + NFI_STRADDR);
++
++		nb->access_len = len;
++		nb->dma_addr = dma_addr;
++	}
++
++	if (nb->ecc_en && !read && fdm)
++		write_fdm(nb, fdm);
++
++	writew(val, regs + NFI_CNFG);
++	/* setup R/W sector number */
++	writel(sectors << CON_SEC_SHIFT, regs + NFI_CON);
++
++	return 0;
++}
++
++static void rw_trigger(struct nfi_base *nb, bool read)
++{
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	val = read ? CON_BRD : CON_BWR;
++	val |= readl(regs + NFI_CON);
++	writel(val, regs + NFI_CON);
++
++	writel(STAR_EN, regs + NFI_STRDATA);
++}
++
++static int rw_wait_done(struct nfi_base *nb, int sectors, bool read)
++{
++	void *regs = nb->res.nfi_regs;
++	bool irq_en = nb->dma_en && nb->nfi_irq_en;
++	int ret;
++	u32 val;
++
++	if (irq_en) {
++		ret = nandx_event_wait_complete(nb->done, NFI_TIMEOUT);
++		if (!ret) {
++			writew(0, regs + NFI_INTR_EN);
++			return ret;
++		}
++	}
++
++	if (read) {
++		ret = readl_poll_timeout_atomic(regs + NFI_BYTELEN, val,
++						ADDRCNTR_SEC(val) >=
++						(u32)sectors,
++						2, NFI_TIMEOUT);
++		/* HW issue: if not wait ahb done, need polling bus busy */
++		if (!ret && !irq_en)
++			ret = readl_poll_timeout_atomic(regs + NFI_MASTER_STA,
++							val,
++							!(val &
++							  MASTER_BUS_BUSY),
++							2, NFI_TIMEOUT);
++	} else {
++		ret = readl_poll_timeout_atomic(regs + NFI_ADDRCNTR, val,
++						ADDRCNTR_SEC(val) >=
++						(u32)sectors,
++						2, NFI_TIMEOUT);
++	}
++
++	if (ret) {
++		pr_info("do page %s timeout\n", read ? "read" : "write");
++		return ret;
++	}
++
++	if (read && nb->ecc_en) {
++		ret = nb->ecc->wait_done(nb->ecc);
++		if (ret)
++			return ret;
++
++		return nb->ecc->decode_status(nb->ecc, 0, sectors);
++	}
++
++	return 0;
++}
++
++static int rw_data(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors,
++		   bool read)
++{
++	if (read && nb->dma_en && nb->ecc_en && fdm)
++		read_fdm(nb, fdm, 0, sectors);
++
++	if (!nb->dma_en) {
++		if (read)
++			return pio_rx_data(nb, data, fdm, sectors);
++
++		return pio_tx_data(nb, data, fdm, sectors);
++	}
++
++	return 0;
++}
++
++static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm,
++			bool read)
++{
++	int data_len = 0;
++	bool is_empty;
++
++	if (nb->dma_en) {
++		if (read) {
++			nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr,
++					(u64)nb->access_len, NDMA_FROM_DEV);
++
++			if (data) {
++				data_len = nb->rw_sectors * nb->nfi.sector_size;
++				memcpy(data, nb->buf, data_len);
++			}
++
++			if (fdm)
++				memcpy(fdm, nb->buf + data_len,
++				       nb->access_len - data_len);
++
++			if (nb->read_status == -ENANDREAD) {
++				is_empty = nb->is_page_empty(nb, data, fdm,
++							nb->rw_sectors);
++				if (is_empty)
++					nb->read_status = 0;
++			}
++		} else {
++			nandx_dma_unmap(nb->res.dev, nb->buf, nb->dma_addr,
++					(u64)nb->access_len, NDMA_TO_DEV);
++		}
++	}
++
++	/* whether it's reading or writing, we all check if nee swap
++	 * for write, we need to restore data
++	 */
++	if (nb->bad_mark_swap_en)
++		nb->bad_mark_ctrl.bad_mark_swap(&nb->nfi, data, fdm);
++
++	if (nb->ecc_en)
++		nb->ecc->disable(nb->ecc);
++
++	writel(0, nb->res.nfi_regs + NFI_CNFG);
++	writel(0, nb->res.nfi_regs + NFI_CON);
++}
++
++static int nfi_read_sectors(struct nfi *nfi, u8 *data, u8 *fdm,
++			    int sectors)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	int bitflips = 0, ret;
++
++	pr_debug("%s: read page#%d\n", __func__, nb->row);
++	pr_debug("%s: data address 0x%x, fdm address 0x%x, sectors 0x%x\n",
++		 __func__, (u32)((unsigned long)data),
++		 (u32)((unsigned long)fdm), sectors);
++
++	nb->read_status = 0;
++
++	ret = nb->rw_prepare(nb, sectors, data, fdm, true);
++	if (ret)
++		return ret;
++
++	nb->rw_trigger(nb, true);
++
++	if (nb->dma_en) {
++		ret = nb->rw_wait_done(nb, sectors, true);
++		if (ret > 0)
++			bitflips = ret;
++		else if (ret == -ENANDREAD)
++			nb->read_status = -ENANDREAD;
++		else if (ret < 0)
++			goto complete;
++
++	}
++
++	ret = nb->rw_data(nb, data, fdm, sectors, true);
++	if (ret > 0)
++		ret = max_t(int, ret, bitflips);
++
++complete:
++	nb->rw_complete(nb, data, fdm, true);
++
++	if (nb->read_status == -ENANDREAD)
++		return -ENANDREAD;
++
++	return ret;
++}
++
++int nfi_write_page(struct nfi *nfi, u8 *data, u8 *fdm)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	u32 sectors = div_down(nb->format.page_size, nfi->sector_size);
++	int ret;
++
++	pr_debug("%s: data address 0x%x, fdm address 0x%x\n",
++		 __func__, (int)((unsigned long)data),
++		 (int)((unsigned long)fdm));
++
++	ret = nb->rw_prepare(nb, sectors, data, fdm, false);
++	if (ret)
++		return ret;
++
++	nb->rw_trigger(nb, false);
++
++	ret = nb->rw_data(nb, data, fdm, sectors, false);
++	if (ret)
++		return ret;
++
++	ret = nb->rw_wait_done(nb, sectors, false);
++
++	nb->rw_complete(nb, data, fdm, false);
++
++	return ret;
++}
++
++static int nfi_rw_bytes(struct nfi *nfi, u8 *data, int count, bool read)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	int i, ret;
++	u32 val;
++
++	for (i = 0; i < count; i++) {
++		val = readl(regs + NFI_STA) & NFI_FSM_MASK;
++		if (val != NFI_FSM_CUSTDATA) {
++			val = readw(regs + NFI_CNFG) | CNFG_BYTE_RW;
++			if (read)
++				val |= CNFG_READ_EN;
++			writew(val, regs + NFI_CNFG);
++
++			val = div_up(count, nfi->sector_size);
++			val = (val << CON_SEC_SHIFT) | CON_BRD | CON_BWR;
++			writel(val, regs + NFI_CON);
++
++			writew(STAR_EN, regs + NFI_STRDATA);
++		}
++
++		ret = wait_io_ready(regs);
++		if (ret)
++			return ret;
++
++		if (read)
++			data[i] = readb(regs + NFI_DATAR);
++		else
++			writeb(data[i], regs + NFI_DATAW);
++	}
++
++	writel(0, nb->res.nfi_regs + NFI_CNFG);
++
++	return 0;
++}
++
++static int nfi_read_bytes(struct nfi *nfi, u8 *data, int count)
++{
++	return nfi_rw_bytes(nfi, data, count, true);
++}
++
++static int nfi_write_bytes(struct nfi *nfi, u8 *data, int count)
++{
++	return nfi_rw_bytes(nfi, data, count, false);
++}
++
++/* As register map says, only when flash macro is idle,
++ * sw reset or nand interface change can be issued
++ */
++static inline int wait_flash_macro_idle(void *regs)
++{
++	u32 val;
++
++	return readl_poll_timeout_atomic(regs + NFI_STA, val,
++					 val & FLASH_MACRO_IDLE, 2,
++					 NFI_TIMEOUT);
++}
++
++#define ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt) \
++	((tpoecs) << 28 | (tprecs) << 22 | (tc2r) << 16 | \
++	 (tw2r) << 12 | (twh) << 8 | (twst) << 4 | (trlt))
++
++static int nfi_set_sdr_timing(struct nfi *nfi, void *timing, u8 type)
++{
++	struct nand_sdr_timing *sdr = (struct nand_sdr_timing *) timing;
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	u32 tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt, tstrobe;
++	u32 rate, val;
++	int ret;
++
++	ret = wait_flash_macro_idle(regs);
++	if (ret)
++		return ret;
++
++	/* turn clock rate into KHZ */
++	rate = nb->res.clock_1x / 1000;
++
++	tpoecs = max_t(u16, sdr->tALH, sdr->tCLH);
++	tpoecs = div_up(tpoecs * rate, 1000000);
++	tpoecs &= 0xf;
++
++	tprecs = max_t(u16, sdr->tCLS, sdr->tALS);
++	tprecs = div_up(tprecs * rate, 1000000);
++	tprecs &= 0x3f;
++
++	/* tc2r is in unit of 2T */
++	tc2r = div_up(sdr->tCR * rate, 1000000);
++	tc2r = div_down(tc2r, 2);
++	tc2r &= 0x3f;
++
++	tw2r = div_up(sdr->tWHR * rate, 1000000);
++	tw2r = div_down(tw2r, 2);
++	tw2r &= 0xf;
++
++	twh = max_t(u16, sdr->tREH, sdr->tWH);
++	twh = div_up(twh * rate, 1000000) - 1;
++	twh &= 0xf;
++
++	twst = div_up(sdr->tWP * rate, 1000000) - 1;
++	twst &= 0xf;
++
++	trlt = div_up(sdr->tRP * rate, 1000000) - 1;
++	trlt &= 0xf;
++
++	/* If tREA is bigger than tRP, setup strobe sel here */
++	if ((trlt + 1) * 1000000 / rate < sdr->tREA) {
++		tstrobe = sdr->tREA - (trlt + 1) * 1000000 / rate;
++		tstrobe = div_up(tstrobe * rate, 1000000);
++		val = readl(regs + NFI_DEBUG_CON1);
++		val &= ~STROBE_MASK;
++		val |= tstrobe << STROBE_SHIFT;
++		writel(val, regs + NFI_DEBUG_CON1);
++	}
++
++	/*
++	 * ACCON: access timing control register
++	 * -------------------------------------
++	 * 31:28: tpoecs, minimum required time for CS post pulling down after
++	 *        accessing the device
++	 * 27:22: tprecs, minimum required time for CS pre pulling down before
++	 *        accessing the device
++	 * 21:16: tc2r, minimum required time from NCEB low to NREB low
++	 * 15:12: tw2r, minimum required time from NWEB high to NREB low.
++	 * 11:08: twh, write enable hold time
++	 * 07:04: twst, write wait states
++	 * 03:00: trlt, read wait states
++	 */
++	val = ACCTIMING(tpoecs, tprecs, tc2r, tw2r, twh, twst, trlt);
++	pr_info("acctiming: 0x%x\n", val);
++	writel(val, regs + NFI_ACCCON);
++
++	/* set NAND type */
++	writel(NAND_TYPE_ASYNC, regs + NFI_NAND_TYPE_CNFG);
++
++	return ret;
++}
++
++static int nfi_set_timing(struct nfi *nfi, void *timing, int type)
++{
++	switch (type) {
++	case NAND_TIMING_SDR:
++		return nfi_set_sdr_timing(nfi, timing, type);
++
++	/* NOTE: for mlc/tlc */
++	case NAND_TIMING_SYNC_DDR:
++	case NAND_TIMING_TOGGLE_DDR:
++	case NAND_TIMING_NVDDR2:
++	default:
++		return -EINVAL;
++	}
++
++	return 0;
++}
++
++static void set_nfi_funcs(struct nfi *nfi)
++{
++	nfi->select_chip = nfi_select_chip;
++	nfi->set_format = nfi_set_format;
++	nfi->nfi_ctrl = nfi_ctrl;
++	nfi->set_timing = nfi_set_timing;
++
++	nfi->reset = nfi_reset;
++	nfi->send_cmd = nfi_send_cmd;
++	nfi->send_addr = nfi_send_addr;
++	nfi->trigger = nfi_trigger;
++
++	nfi->write_page = nfi_write_page;
++	nfi->write_bytes = nfi_write_bytes;
++	nfi->read_sectors = nfi_read_sectors;
++	nfi->read_bytes = nfi_read_bytes;
++
++	nfi->wait_ready = nfi_wait_ready;
++
++	nfi->enable_randomizer = nfi_enable_randomizer;
++	nfi->disable_randomizer = nfi_disable_randomizer;
++}
++
++static struct nfi_caps nfi_caps_mt7622 = {
++	.max_fdm_size = 8,
++	.fdm_ecc_size = 1,
++	.ecc_parity_bits = 13,
++	.spare_size = spare_size_mt7622,
++	.spare_size_num = 4,
++};
++
++static struct nfi_caps *nfi_get_match_data(enum mtk_ic_version ic)
++{
++	/* NOTE: add other IC's data */
++	return &nfi_caps_mt7622;
++}
++
++static void set_nfi_base_params(struct nfi_base *nb)
++{
++	nb->ecc_en = false;
++	nb->dma_en = false;
++	nb->nfi_irq_en = false;
++	nb->ecc_irq_en = false;
++	nb->page_irq_en = false;
++	nb->ecc_clk_en = false;
++	nb->randomize_en = false;
++	nb->custom_sector_en = false;
++	nb->bad_mark_swap_en = false;
++
++	nb->op_mode = CNFG_CUSTOM_MODE;
++	nb->ecc_deccon = ECC_DEC_CORRECT;
++	nb->ecc_mode = ECC_NFI_MODE;
++
++	nb->done = nandx_event_create();
++	nb->caps = nfi_get_match_data(nb->res.ic_ver);
++
++	nb->set_op_mode = set_op_mode;
++	nb->is_page_empty = is_page_empty;
++
++	nb->rw_prepare = rw_prepare;
++	nb->rw_trigger = rw_trigger;
++	nb->rw_wait_done = rw_wait_done;
++	nb->rw_data = rw_data;
++	nb->rw_complete = rw_complete;
++}
++
++struct nfi *__weak nfi_extend_init(struct nfi_base *nb)
++{
++	return &nb->nfi;
++}
++
++void __weak nfi_extend_exit(struct nfi_base *nb)
++{
++	mem_free(nb);
++}
++
++struct nfi *nfi_init(struct nfi_resource *res)
++{
++	struct nfiecc_resource ecc_res;
++	struct nfi_base *nb;
++	struct nfiecc *ecc;
++	struct nfi *nfi;
++	int ret;
++
++	nb = mem_alloc(1, sizeof(struct nfi_base));
++	if (!nb) {
++		pr_info("nfi alloc memory fail @%s.\n", __func__);
++		return NULL;
++	}
++
++	nb->res = *res;
++
++	ret = nandx_irq_register(res->dev, res->nfi_irq_id, nfi_irq_handler,
++				 "mtk_nand", nb);
++	if (ret) {
++		pr_info("nfi irq register failed!\n");
++		goto error;
++	}
++
++	/* fill ecc paras and init ecc */
++	ecc_res.ic_ver = nb->res.ic_ver;
++	ecc_res.dev = nb->res.dev;
++	ecc_res.irq_id = nb->res.ecc_irq_id;
++	ecc_res.regs = nb->res.ecc_regs;
++	ecc = nfiecc_init(&ecc_res);
++	if (!ecc) {
++		pr_info("nfiecc init fail.\n");
++		return NULL;
++	}
++
++	nb->ecc = ecc;
++
++	set_nfi_base_params(nb);
++	set_nfi_funcs(&nb->nfi);
++
++	/* Assign a temp sector size for reading ID & para page.
++	 * We may assign new value later.
++	 */
++	nb->nfi.sector_size = 512;
++
++	/* give a default timing, and as discuss
++	 * this is the only thing what we need do for nfi init
++	 * if need do more, then we can add a function
++	 */
++	writel(0x30C77FFF, nb->res.nfi_regs + NFI_ACCCON);
++
++	nfi = nfi_extend_init(nb);
++	if (nfi)
++		return nfi;
++
++error:
++	mem_free(nb);
++	return NULL;
++}
++
++void nfi_exit(struct nfi *nfi)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++
++	nandx_event_destroy(nb->done);
++	nfiecc_exit(nb->ecc);
++#if !NANDX_BULK_IO_USE_DRAM
++	mem_free(nb->buf);
++#endif
++	nfi_extend_exit(nb);
++}
++
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_base.h b/drivers/mtd/nandx/core/nfi/nfi_base.h
+new file mode 100644
+index 0000000000..ae894eaa31
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_base.h
+@@ -0,0 +1,95 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFI_BASE_H__
++#define __NFI_BASE_H__
++
++#define NFI_TIMEOUT             1000000
++
++enum randomizer_op {
++	RAND_ENCODE,
++	RAND_DECODE
++};
++
++struct bad_mark_ctrl {
++	void (*bad_mark_swap)(struct nfi *nfi, u8 *buf, u8 *fdm);
++	u8 *(*fdm_shift)(struct nfi *nfi, u8 *fdm, int sector);
++	u32 sector;
++	u32 position;
++};
++
++struct nfi_caps {
++	u8 max_fdm_size;
++	u8 fdm_ecc_size;
++	u8 ecc_parity_bits;
++	const int *spare_size;
++	u32 spare_size_num;
++};
++
++struct nfi_base {
++	struct nfi nfi;
++	struct nfi_resource res;
++	struct nfiecc *ecc;
++	struct nfi_format format;
++	struct nfi_caps *caps;
++	struct bad_mark_ctrl bad_mark_ctrl;
++
++	/* page_size + spare_size */
++	u8 *buf;
++
++	/* used for spi nand */
++	u8 cmd_mode;
++	u32 op_mode;
++
++	int page_sectors;
++
++	void *done;
++
++	/* for read/write */
++	int col;
++	int row;
++	int access_len;
++	int rw_sectors;
++	void *dma_addr;
++	int read_status;
++
++	bool dma_en;
++	bool nfi_irq_en;
++	bool page_irq_en;
++	bool auto_format;
++	bool ecc_en;
++	bool ecc_irq_en;
++	bool ecc_clk_en;
++	bool randomize_en;
++	bool custom_sector_en;
++	bool bad_mark_swap_en;
++
++	enum nfiecc_deccon ecc_deccon;
++	enum nfiecc_mode ecc_mode;
++
++	void (*set_op_mode)(void *regs, u32 mode);
++	bool (*is_page_empty)(struct nfi_base *nb, u8 *data, u8 *fdm,
++			      int sectors);
++
++	int (*rw_prepare)(struct nfi_base *nb, int sectors, u8 *data, u8 *fdm,
++			  bool read);
++	void (*rw_trigger)(struct nfi_base *nb, bool read);
++	int (*rw_wait_done)(struct nfi_base *nb, int sectors, bool read);
++	int (*rw_data)(struct nfi_base *nb, u8 *data, u8 *fdm, int sectors,
++		       bool read);
++	void (*rw_complete)(struct nfi_base *nb, u8 *data, u8 *fdm, bool read);
++};
++
++static inline struct nfi_base *nfi_to_base(struct nfi *nfi)
++{
++	return container_of(nfi, struct nfi_base, nfi);
++}
++
++struct nfi *nfi_extend_init(struct nfi_base *nb);
++void nfi_extend_exit(struct nfi_base *nb);
++
++#endif /* __NFI_BASE_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_regs.h b/drivers/mtd/nandx/core/nfi/nfi_regs.h
+new file mode 100644
+index 0000000000..ba4868acc8
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_regs.h
+@@ -0,0 +1,114 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFI_REGS_H__
++#define __NFI_REGS_H__
++
++#define NFI_CNFG                0x000
++#define         CNFG_AHB                BIT(0)
++#define         CNFG_READ_EN            BIT(1)
++#define         CNFG_DMA_BURST_EN       BIT(2)
++#define         CNFG_RESEED_SEC_EN      BIT(4)
++#define         CNFG_RAND_SEL           BIT(5)
++#define         CNFG_BYTE_RW            BIT(6)
++#define         CNFG_HW_ECC_EN          BIT(8)
++#define         CNFG_AUTO_FMT_EN        BIT(9)
++#define         CNFG_RAND_MASK          GENMASK(5, 4)
++#define         CNFG_OP_MODE_MASK       GENMASK(14, 12)
++#define         CNFG_IDLE_MOD           0
++#define         CNFG_READ_MODE          (1 << 12)
++#define         CNFG_SINGLE_READ_MODE   (2 << 12)
++#define         CNFG_PROGRAM_MODE       (3 << 12)
++#define         CNFG_ERASE_MODE         (4 << 12)
++#define         CNFG_RESET_MODE         (5 << 12)
++#define         CNFG_CUSTOM_MODE        (6 << 12)
++#define NFI_PAGEFMT             0x004
++#define         PAGEFMT_SPARE_SHIFT     4
++#define         PAGEFMT_FDM_ECC_SHIFT   12
++#define         PAGEFMT_FDM_SHIFT       8
++#define         PAGEFMT_SEC_SEL_512     BIT(2)
++#define         PAGEFMT_512_2K          0
++#define         PAGEFMT_2K_4K           1
++#define         PAGEFMT_4K_8K           2
++#define         PAGEFMT_8K_16K          3
++#define NFI_CON                 0x008
++#define         CON_FIFO_FLUSH          BIT(0)
++#define         CON_NFI_RST             BIT(1)
++#define         CON_BRD                 BIT(8)
++#define         CON_BWR                 BIT(9)
++#define         CON_SEC_SHIFT           12
++#define NFI_ACCCON              0x00c
++#define NFI_INTR_EN             0x010
++#define         INTR_BUSY_RETURN_EN     BIT(4)
++#define         INTR_AHB_DONE_EN        BIT(6)
++#define NFI_INTR_STA            0x014
++#define NFI_CMD                 0x020
++#define NFI_ADDRNOB             0x030
++#define         ROW_SHIFT               4
++#define NFI_COLADDR             0x034
++#define NFI_ROWADDR             0x038
++#define NFI_STRDATA             0x040
++#define         STAR_EN                 1
++#define         STAR_DE                 0
++#define NFI_CNRNB               0x044
++#define NFI_DATAW               0x050
++#define NFI_DATAR               0x054
++#define NFI_PIO_DIRDY           0x058
++#define         PIO_DI_RDY              1
++#define NFI_STA                 0x060
++#define         STA_CMD                 BIT(0)
++#define         STA_ADDR                BIT(1)
++#define         FLASH_MACRO_IDLE        BIT(5)
++#define         STA_BUSY                BIT(8)
++#define         STA_BUSY2READY          BIT(9)
++#define         STA_EMP_PAGE            BIT(12)
++#define         NFI_FSM_CUSTDATA        (0xe << 16)
++#define         NFI_FSM_MASK            GENMASK(19, 16)
++#define         NAND_FSM_MASK           GENMASK(29, 23)
++#define NFI_ADDRCNTR            0x070
++#define         CNTR_VALID_MASK         GENMASK(16, 0)
++#define         CNTR_MASK               GENMASK(15, 12)
++#define         ADDRCNTR_SEC_SHIFT      12
++#define         ADDRCNTR_SEC(val) \
++	(((val) & CNTR_MASK) >> ADDRCNTR_SEC_SHIFT)
++#define NFI_STRADDR             0x080
++#define NFI_BYTELEN             0x084
++#define NFI_CSEL                0x090
++#define NFI_FDML(x)             (0x0a0 + (x) * 8)
++#define NFI_FDMM(x)             (0x0a4 + (x) * 8)
++#define NFI_DEBUG_CON1          0x220
++#define         STROBE_MASK             GENMASK(4, 3)
++#define         STROBE_SHIFT            3
++#define         ECC_CLK_EN              BIT(11)
++#define         AUTOC_SRAM_MODE         BIT(12)
++#define         BYPASS_MASTER_EN        BIT(15)
++#define NFI_MASTER_STA          0x224
++#define         MASTER_BUS_BUSY         0x3
++#define NFI_SECCUS_SIZE         0x22c
++#define         SECCUS_SIZE_EN          BIT(17)
++#define NFI_RANDOM_CNFG         0x238
++#define         RAN_ENCODE_EN           BIT(0)
++#define         ENCODE_SEED_SHIFT       1
++#define         RAN_DECODE_EN           BIT(16)
++#define         DECODE_SEED_SHIFT       17
++#define         RAN_SEED_MASK           0x7fff
++#define NFI_EMPTY_THRESH        0x23c
++#define NFI_NAND_TYPE_CNFG      0x240
++#define         NAND_TYPE_ASYNC         0
++#define         NAND_TYPE_TOGGLE        1
++#define         NAND_TYPE_SYNC          2
++#define NFI_ACCCON1             0x244
++#define NFI_DELAY_CTRL          0x248
++#define NFI_TLC_RD_WHR2         0x300
++#define         TLC_RD_WHR2_EN          BIT(12)
++#define         TLC_RD_WHR2_MASK        GENMASK(11, 0)
++#define SNF_SNF_CNFG            0x55c
++#define         SPI_MODE_EN             1
++#define         SPI_MODE_DIS            0
++
++#endif /* __NFI_REGS_H__ */
++
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi.c b/drivers/mtd/nandx/core/nfi/nfi_spi.c
+new file mode 100644
+index 0000000000..67cd0aaad9
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_spi.c
+@@ -0,0 +1,689 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "../nfi.h"
++#include "nfiecc.h"
++#include "nfi_regs.h"
++#include "nfi_base.h"
++#include "nfi_spi_regs.h"
++#include "nfi_spi.h"
++
++#define NFI_CMD_DUMMY_RD 0x00
++#define NFI_CMD_DUMMY_WR 0x80
++
++static struct nfi_spi_delay spi_delay[SPI_NAND_MAX_DELAY] = {
++	/*
++	 * tCLK_SAM_DLY, tCLK_OUT_DLY, tCS_DLY, tWR_EN_DLY,
++	 * tIO_IN_DLY[4], tIO_OUT_DLY[4], tREAD_LATCH_LATENCY
++	 */
++	{0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
++	{21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
++	{63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 0},
++	{0, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1},
++	{21, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1},
++	{63, 0, 0, 0, {0, 0, 0, 0}, {0, 0, 0, 0}, 1}
++};
++
++static inline struct nfi_spi *base_to_snfi(struct nfi_base *nb)
++{
++	return container_of(nb, struct nfi_spi, base);
++}
++
++static void snfi_mac_enable(struct nfi_base *nb)
++{
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	val = readl(regs + SNF_MAC_CTL);
++	val &= ~MAC_XIO_SEL;
++	val |= SF_MAC_EN;
++
++	writel(val, regs + SNF_MAC_CTL);
++}
++
++static void snfi_mac_disable(struct nfi_base *nb)
++{
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	val = readl(regs + SNF_MAC_CTL);
++	val &= ~(SF_TRIG | SF_MAC_EN);
++	writel(val, regs + SNF_MAC_CTL);
++}
++
++static int snfi_mac_trigger(struct nfi_base *nb)
++{
++	void *regs = nb->res.nfi_regs;
++	int ret;
++	u32 val;
++
++	val = readl(regs + SNF_MAC_CTL);
++	val |= SF_TRIG;
++	writel(val, regs + SNF_MAC_CTL);
++
++	ret = readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val,
++					val & WIP_READY, 10,
++					NFI_TIMEOUT);
++	if (ret) {
++		pr_info("polling wip ready for read timeout\n");
++		return ret;
++	}
++
++	return readl_poll_timeout_atomic(regs + SNF_MAC_CTL, val,
++					 !(val & WIP), 10,
++					 NFI_TIMEOUT);
++}
++
++static int snfi_mac_op(struct nfi_base *nb)
++{
++	int ret;
++
++	snfi_mac_enable(nb);
++	ret = snfi_mac_trigger(nb);
++	snfi_mac_disable(nb);
++
++	return ret;
++}
++
++static void snfi_write_mac(struct nfi_spi *nfi_spi, u8 *data, int count)
++{
++	struct nandx_split32 split = {0};
++	u32 reg_offset = round_down(nfi_spi->tx_count, 4);
++	void *regs = nfi_spi->base.res.nfi_regs;
++	u32 data_offset = 0, i, val;
++	u8 *p_val = (u8 *)(&val);
++
++	nandx_split(&split, nfi_spi->tx_count, count, val, 4);
++
++	if (split.head_len) {
++		val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
++
++		for (i = 0; i < split.head_len; i++)
++			p_val[split.head + i] = data[i];
++
++		writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
++	}
++
++	if (split.body_len) {
++		reg_offset = split.body;
++		data_offset = split.head_len;
++
++		for (i = 0; i < split.body_len; i++) {
++			p_val[i & 3] = data[data_offset + i];
++
++			if ((i & 3) == 3) {
++				writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
++				reg_offset += 4;
++			}
++		}
++	}
++
++	if (split.tail_len) {
++		reg_offset = split.tail;
++		data_offset += split.body_len;
++
++		for (i = 0; i < split.tail_len; i++) {
++			p_val[i] = data[data_offset + i];
++
++			if (i == split.tail_len - 1)
++				writel(val, regs + SPI_GPRAM_ADDR + reg_offset);
++		}
++	}
++}
++
++static void snfi_read_mac(struct nfi_spi *nfi_spi, u8 *data, int count)
++{
++	void *regs = nfi_spi->base.res.nfi_regs;
++	u32 reg_offset = round_down(nfi_spi->tx_count, 4);
++	struct nandx_split32 split = {0};
++	u32 data_offset = 0, i, val;
++	u8 *p_val = (u8 *)&val;
++
++	nandx_split(&split, nfi_spi->tx_count, count, val, 4);
++
++	if (split.head_len) {
++		val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
++
++		for (i = 0; i < split.head_len; i++)
++			data[data_offset + i] = p_val[split.head + i];
++	}
++
++	if (split.body_len) {
++		reg_offset = split.body;
++		data_offset = split.head_len;
++
++		for (i = 0; i < split.body_len; i++) {
++			if ((i & 3) == 0) {
++				val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
++				reg_offset += 4;
++			}
++
++			data[data_offset + i] = p_val[i % 4];
++		}
++	}
++
++	if (split.tail_len) {
++		reg_offset = split.tail;
++		data_offset += split.body_len;
++		val = readl(regs + SPI_GPRAM_ADDR + reg_offset);
++
++		for (i = 0; i < split.tail_len; i++)
++			data[data_offset + i] = p_val[i];
++	}
++}
++
++static int snfi_send_command(struct nfi *nfi, short cmd)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++
++	if (cmd == -1)
++		return 0;
++
++	if (nfi_spi->snfi_mode == SNFI_MAC_MODE) {
++		snfi_write_mac(nfi_spi, (u8 *)&cmd, 1);
++		nfi_spi->tx_count++;
++		return 0;
++	}
++
++	nfi_spi->cmd[nfi_spi->cur_cmd_idx++] = cmd;
++	return 0;
++}
++
++static int snfi_send_address(struct nfi *nfi, int col, int row,
++			     int col_cycle,
++			     int row_cycle)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	u32 addr, cycle, temp;
++
++	nb->col = col;
++	nb->row = row;
++
++	if (nfi_spi->snfi_mode == SNFI_MAC_MODE) {
++		addr = row;
++		cycle = row_cycle;
++
++		if (!row_cycle) {
++			addr = col;
++			cycle = col_cycle;
++		}
++
++		temp = nandx_cpu_to_be32(addr) >> ((4 - cycle) << 3);
++		snfi_write_mac(nfi_spi, (u8 *)&temp, cycle);
++		nfi_spi->tx_count += cycle;
++	}  else {
++		nfi_spi->row_addr[nfi_spi->cur_addr_idx++] = row;
++		nfi_spi->col_addr[nfi_spi->cur_addr_idx++] = col;
++	}
++
++	return 0;
++}
++
++static int snfi_trigger(struct nfi *nfi)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++
++	writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
++	writel(0, regs + SNF_MAC_INL);
++
++	nfi_spi->tx_count = 0;
++	nfi_spi->cur_cmd_idx = 0;
++	nfi_spi->cur_addr_idx = 0;
++
++	return snfi_mac_op(nb);
++}
++
++static int snfi_select_chip(struct nfi *nfi, int cs)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	val = readl(regs + SNF_MISC_CTL);
++
++	if (cs == 0) {
++		val &= ~SF2CS_SEL;
++		val &= ~SF2CS_EN;
++	} else if (cs == 1) {
++		val |= SF2CS_SEL;
++		val |= SF2CS_EN;
++	} else {
++		return -EIO;
++	}
++
++	writel(val, regs + SNF_MISC_CTL);
++
++	return 0;
++}
++
++static int snfi_set_delay(struct nfi_base *nb, u8 delay_mode)
++{
++	void *regs = nb->res.nfi_regs;
++	struct nfi_spi_delay *delay;
++	u32 val;
++
++	if (delay_mode < 0 || delay_mode > SPI_NAND_MAX_DELAY)
++		return -EINVAL;
++
++	delay = &spi_delay[delay_mode];
++
++	val = delay->tIO_OUT_DLY[0] | delay->tIO_OUT_DLY[1] << 8 |
++	      delay->tIO_OUT_DLY[2] << 16 |
++	      delay->tIO_OUT_DLY[3] << 24;
++	writel(val, regs + SNF_DLY_CTL1);
++
++	val = delay->tIO_IN_DLY[0] | (delay->tIO_IN_DLY[1] << 8) |
++	      delay->tIO_IN_DLY[2] << 16 |
++	      delay->tIO_IN_DLY[3] << 24;
++	writel(val, regs + SNF_DLY_CTL2);
++
++	val = delay->tCLK_SAM_DLY | delay->tCLK_OUT_DLY << 8 |
++	      delay->tCS_DLY << 16 |
++	      delay->tWR_EN_DLY << 24;
++	writel(val, regs + SNF_DLY_CTL3);
++
++	writel(delay->tCS_DLY, regs + SNF_DLY_CTL4);
++
++	val = readl(regs + SNF_MISC_CTL);
++	val |= (delay->tREAD_LATCH_LATENCY) <<
++	       LATCH_LAT_SHIFT;
++	writel(val, regs + SNF_MISC_CTL);
++
++	return 0;
++}
++
++static int snfi_set_timing(struct nfi *nfi, void *timing, int type)
++{
++	/* Nothing need to do. */
++	return 0;
++}
++
++static int snfi_wait_ready(struct nfi *nfi, int type, u32 timeout)
++{
++	/* Nothing need to do. */
++	return 0;
++}
++
++static int snfi_ctrl(struct nfi *nfi, int cmd, void *args)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	int ret = 0;
++
++	if (!args)
++		return -EINVAL;
++
++	switch (cmd) {
++	case NFI_CTRL_DMA:
++		nb->dma_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_NFI_IRQ:
++		nb->nfi_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_IRQ:
++		nb->ecc_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_PAGE_IRQ:
++		nb->page_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC:
++		nb->ecc_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_BAD_MARK_SWAP:
++		nb->bad_mark_swap_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_CLOCK:
++		nb->ecc_clk_en = *(bool *)args;
++		break;
++
++	case SNFI_CTRL_OP_MODE:
++		nfi_spi->snfi_mode = *(u8 *)args;
++		break;
++
++	case SNFI_CTRL_RX_MODE:
++		nfi_spi->read_cache_mode = *(u8 *)args;
++		break;
++
++	case SNFI_CTRL_TX_MODE:
++		nfi_spi->write_cache_mode = *(u8 *)args;
++		break;
++
++	case SNFI_CTRL_DELAY_MODE:
++		ret = snfi_set_delay(nb, *(u8 *)args);
++		break;
++
++	default:
++		pr_info("operation not support.\n");
++		ret = -EOPNOTSUPP;
++		break;
++	}
++
++	return ret;
++}
++
++static int snfi_read_bytes(struct nfi *nfi, u8 *data, int count)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++	int ret;
++
++	writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
++	writel(count, regs + SNF_MAC_INL);
++
++	ret = snfi_mac_op(nb);
++	if (ret)
++		return ret;
++
++	snfi_read_mac(nfi_spi, data, count);
++
++	nfi_spi->tx_count = 0;
++
++	return 0;
++}
++
++static int snfi_write_bytes(struct nfi *nfi, u8 *data, int count)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++
++	snfi_write_mac(nfi_spi, data, count);
++	nfi_spi->tx_count += count;
++
++	writel(0, regs + SNF_MAC_INL);
++	writel(nfi_spi->tx_count, regs + SNF_MAC_OUTL);
++
++	nfi_spi->tx_count = 0;
++
++	return snfi_mac_op(nb);
++}
++
++static int snfi_reset(struct nfi *nfi)
++{
++	struct nfi_base *nb = nfi_to_base(nfi);
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++	int ret;
++
++	ret = nfi_spi->parent->nfi.reset(nfi);
++	if (ret)
++		return ret;
++
++	val = readl(regs + SNF_MISC_CTL);
++	val |= SW_RST;
++	writel(val, regs + SNF_MISC_CTL);
++
++	ret = readx_poll_timeout_atomic(readw, regs + SNF_STA_CTL1, val,
++					!(val & SPI_STATE), 50,
++					NFI_TIMEOUT);
++	if (ret) {
++		pr_info("spi state active in reset [0x%x] = 0x%x\n",
++			SNF_STA_CTL1, val);
++		return ret;
++	}
++
++	val = readl(regs + SNF_MISC_CTL);
++	val &= ~SW_RST;
++	writel(val, regs + SNF_MISC_CTL);
++
++	return 0;
++}
++
++static int snfi_config_for_write(struct nfi_base *nb, int count)
++{
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	nb->set_op_mode(regs, CNFG_CUSTOM_MODE);
++
++	val = readl(regs + SNF_MISC_CTL);
++
++	if (nfi_spi->write_cache_mode == SNFI_TX_114)
++		val |= PG_LOAD_X4_EN;
++
++	if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
++		val |= PG_LOAD_CUSTOM_EN;
++
++	writel(val, regs + SNF_MISC_CTL);
++
++	val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size);
++	writel(val << PG_LOAD_SHIFT, regs + SNF_MISC_CTL2);
++
++	val = readl(regs + SNF_PG_CTL1);
++
++	if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
++		val |= nfi_spi->cmd[0] << PG_LOAD_CMD_SHIFT;
++	else {
++		val |= nfi_spi->cmd[0] | nfi_spi->cmd[1] << PG_LOAD_CMD_SHIFT |
++		       nfi_spi->cmd[2] << PG_EXE_CMD_SHIFT;
++
++		writel(nfi_spi->row_addr[1], regs + SNF_PG_CTL3);
++		writel(nfi_spi->cmd[3] << GF_CMD_SHIFT | nfi_spi->col_addr[2] <<
++		       GF_ADDR_SHIFT, regs + SNF_GF_CTL1);
++	}
++
++	writel(val, regs + SNF_PG_CTL1);
++	writel(nfi_spi->col_addr[1], regs + SNF_PG_CTL2);
++
++	writel(NFI_CMD_DUMMY_WR, regs + NFI_CMD);
++
++	return 0;
++}
++
++static int snfi_config_for_read(struct nfi_base *nb, int count)
++{
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++	int ret = 0;
++
++	nb->set_op_mode(regs, CNFG_CUSTOM_MODE);
++
++	val = readl(regs + SNF_MISC_CTL);
++	val &= ~DARA_READ_MODE_MASK;
++
++	switch (nfi_spi->read_cache_mode) {
++
++	case SNFI_RX_111:
++		break;
++
++	case SNFI_RX_112:
++		val |= X2_DATA_MODE << READ_MODE_SHIFT;
++		break;
++
++	case SNFI_RX_114:
++		val |= X4_DATA_MODE << READ_MODE_SHIFT;
++		break;
++
++	case SNFI_RX_122:
++		val |= DUAL_IO_MODE << READ_MODE_SHIFT;
++		break;
++
++	case SNFI_RX_144:
++		val |= QUAD_IO_MODE << READ_MODE_SHIFT;
++		break;
++
++	default:
++		pr_info("Not support this read operarion: %d!\n",
++		       nfi_spi->read_cache_mode);
++		ret = -EINVAL;
++		break;
++	}
++
++	if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE)
++		val |= DATARD_CUSTOM_EN;
++
++	writel(val, regs + SNF_MISC_CTL);
++
++	val = count * (nb->nfi.sector_size + nb->nfi.sector_spare_size);
++	writel(val, regs + SNF_MISC_CTL2);
++
++	val = readl(regs + SNF_RD_CTL2);
++
++	if (nfi_spi->snfi_mode == SNFI_CUSTOM_MODE) {
++		val |= nfi_spi->cmd[0];
++		writel(nfi_spi->col_addr[1], regs + SNF_RD_CTL3);
++	} else {
++		val |= nfi_spi->cmd[2];
++		writel(nfi_spi->cmd[0] << PAGE_READ_CMD_SHIFT |
++		       nfi_spi->row_addr[0], regs + SNF_RD_CTL1);
++		writel(nfi_spi->cmd[1] << GF_CMD_SHIFT |
++		       nfi_spi->col_addr[1] << GF_ADDR_SHIFT,
++		       regs + SNF_GF_CTL1);
++		writel(nfi_spi->col_addr[2], regs + SNF_RD_CTL3);
++	}
++
++	writel(val, regs + SNF_RD_CTL2);
++
++	writel(NFI_CMD_DUMMY_RD, regs + NFI_CMD);
++
++	return ret;
++}
++
++static bool is_page_empty(struct nfi_base *nb, u8 *data, u8 *fdm,
++			  int sectors)
++{
++	u32 *data32 = (u32 *)data;
++	u32 *fdm32 = (u32 *)fdm;
++	u32 i, count = 0;
++
++	for (i = 0; i < nb->format.page_size >> 2; i++) {
++		if (data32[i] != 0xffff) {
++			count += zero_popcount(data32[i]);
++			if (count > 10) {
++				pr_info("%s %d %d count:%d\n",
++					__func__, __LINE__, i, count);
++				return false;
++			}
++		}
++	}
++
++	if (fdm) {
++		for (i = 0; i < (nb->nfi.fdm_size * sectors >> 2); i++)
++		if (fdm32[i] != 0xffff) {
++			count += zero_popcount(fdm32[i]);
++			if (count > 10) {
++				pr_info("%s %d %d count:%d\n",
++					__func__, __LINE__, i, count);
++				return false;
++			}
++		}
++	}
++
++	return true;
++}
++
++static int rw_prepare(struct nfi_base *nb, int sectors, u8 *data,
++		      u8 *fdm,
++		      bool read)
++{
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	int ret;
++
++	ret = nfi_spi->parent->rw_prepare(nb, sectors, data, fdm, read);
++	if (ret)
++		return ret;
++
++	if (read)
++		ret = snfi_config_for_read(nb, sectors);
++	else
++		ret = snfi_config_for_write(nb, sectors);
++
++	return ret;
++}
++
++static void rw_complete(struct nfi_base *nb, u8 *data, u8 *fdm,
++			bool read)
++{
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++	void *regs = nb->res.nfi_regs;
++	u32 val;
++
++	nfi_spi->parent->rw_complete(nb, data, fdm, read);
++
++	val = readl(regs + SNF_MISC_CTL);
++
++	if (read)
++		val &= ~DATARD_CUSTOM_EN;
++	else
++		val &= ~PG_LOAD_CUSTOM_EN;
++
++	writel(val, regs + SNF_MISC_CTL);
++
++	nfi_spi->tx_count = 0;
++	nfi_spi->cur_cmd_idx = 0;
++	nfi_spi->cur_addr_idx = 0;
++}
++
++static void set_nfi_base_funcs(struct nfi_base *nb)
++{
++	nb->nfi.reset = snfi_reset;
++	nb->nfi.set_timing = snfi_set_timing;
++	nb->nfi.wait_ready = snfi_wait_ready;
++
++	nb->nfi.send_cmd = snfi_send_command;
++	nb->nfi.send_addr = snfi_send_address;
++	nb->nfi.trigger = snfi_trigger;
++	nb->nfi.nfi_ctrl = snfi_ctrl;
++	nb->nfi.select_chip = snfi_select_chip;
++
++	nb->nfi.read_bytes = snfi_read_bytes;
++	nb->nfi.write_bytes = snfi_write_bytes;
++
++	nb->rw_prepare = rw_prepare;
++	nb->rw_complete = rw_complete;
++	nb->is_page_empty = is_page_empty;
++
++}
++
++struct nfi *nfi_extend_init(struct nfi_base *nb)
++{
++	struct nfi_spi *nfi_spi;
++
++	nfi_spi = mem_alloc(1, sizeof(struct nfi_spi));
++	if (!nfi_spi) {
++		pr_info("snfi alloc memory fail @%s.\n", __func__);
++		return NULL;
++	}
++
++	memcpy(&nfi_spi->base, nb, sizeof(struct nfi_base));
++	nfi_spi->parent = nb;
++
++	nfi_spi->read_cache_mode = SNFI_RX_114;
++	nfi_spi->write_cache_mode = SNFI_TX_114;
++
++	set_nfi_base_funcs(&nfi_spi->base);
++
++	/* Change nfi to spi mode */
++	writel(SPI_MODE, nb->res.nfi_regs + SNF_SNF_CNFG);
++
++	return &(nfi_spi->base.nfi);
++}
++
++void nfi_extend_exit(struct nfi_base *nb)
++{
++	struct nfi_spi *nfi_spi = base_to_snfi(nb);
++
++	mem_free(nfi_spi->parent);
++	mem_free(nfi_spi);
++}
++
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi.h b/drivers/mtd/nandx/core/nfi/nfi_spi.h
+new file mode 100644
+index 0000000000..a52255663a
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_spi.h
+@@ -0,0 +1,44 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFI_SPI_H__
++#define __NFI_SPI_H__
++
++#define SPI_NAND_MAX_DELAY      6
++#define SPI_NAND_MAX_OP         4
++
++/*TODO - add comments */
++struct nfi_spi_delay {
++	u8 tCLK_SAM_DLY;
++	u8 tCLK_OUT_DLY;
++	u8 tCS_DLY;
++	u8 tWR_EN_DLY;
++	u8 tIO_IN_DLY[4];
++	u8 tIO_OUT_DLY[4];
++	u8 tREAD_LATCH_LATENCY;
++};
++
++/* SPI Nand structure */
++struct nfi_spi {
++	struct nfi_base base;
++	struct nfi_base *parent;
++
++	u8 snfi_mode;
++	u8 tx_count;
++
++	u8 cmd[SPI_NAND_MAX_OP];
++	u8 cur_cmd_idx;
++
++	u32 row_addr[SPI_NAND_MAX_OP];
++	u32 col_addr[SPI_NAND_MAX_OP];
++	u8 cur_addr_idx;
++
++	u8 read_cache_mode;
++	u8 write_cache_mode;
++};
++
++#endif /* __NFI_SPI_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h b/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+new file mode 100644
+index 0000000000..77adf46782
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfi_spi_regs.h
+@@ -0,0 +1,64 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFI_SPI_REGS_H__
++#define __NFI_SPI_REGS_H__
++
++#define SNF_MAC_CTL             0x500
++#define         WIP                     BIT(0)
++#define         WIP_READY               BIT(1)
++#define         SF_TRIG                 BIT(2)
++#define         SF_MAC_EN               BIT(3)
++#define         MAC_XIO_SEL             BIT(4)
++#define SNF_MAC_OUTL            0x504
++#define SNF_MAC_INL             0x508
++#define SNF_RD_CTL1             0x50c
++#define         PAGE_READ_CMD_SHIFT     24
++#define SNF_RD_CTL2             0x510
++#define SNF_RD_CTL3             0x514
++#define SNF_GF_CTL1             0x518
++#define         GF_ADDR_SHIFT           16
++#define         GF_CMD_SHIFT            24
++#define SNF_GF_CTL3             0x520
++#define SNF_PG_CTL1             0x524
++#define         PG_EXE_CMD_SHIFT        16
++#define         PG_LOAD_CMD_SHIFT       8
++#define SNF_PG_CTL2             0x528
++#define SNF_PG_CTL3             0x52c
++#define SNF_ER_CTL              0x530
++#define SNF_ER_CTL2             0x534
++#define SNF_MISC_CTL            0x538
++#define         SW_RST                  BIT(28)
++#define         PG_LOAD_X4_EN           BIT(20)
++#define         X2_DATA_MODE            1
++#define         X4_DATA_MODE            2
++#define         DUAL_IO_MODE            5
++#define         QUAD_IO_MODE            6
++#define         READ_MODE_SHIFT         16
++#define         LATCH_LAT_SHIFT         8
++#define         LATCH_LAT_MASK          GENMASK(9, 8)
++#define         DARA_READ_MODE_MASK     GENMASK(18, 16)
++#define         SF2CS_SEL               BIT(13)
++#define         SF2CS_EN                BIT(12)
++#define         PG_LOAD_CUSTOM_EN       BIT(7)
++#define         DATARD_CUSTOM_EN        BIT(6)
++#define SNF_MISC_CTL2           0x53c
++#define         PG_LOAD_SHIFT           16
++#define SNF_DLY_CTL1            0x540
++#define SNF_DLY_CTL2            0x544
++#define SNF_DLY_CTL3            0x548
++#define SNF_DLY_CTL4            0x54c
++#define SNF_STA_CTL1            0x550
++#define         SPI_STATE               GENMASK(3, 0)
++#define SNF_STA_CTL2            0x554
++#define SNF_STA_CTL3            0x558
++#define SNF_SNF_CNFG            0x55c
++#define         SPI_MODE                BIT(0)
++#define SNF_DEBUG_SEL           0x560
++#define SPI_GPRAM_ADDR          0x800
++
++#endif /* __NFI_SPI_REGS_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi/nfiecc.c b/drivers/mtd/nandx/core/nfi/nfiecc.c
+new file mode 100644
+index 0000000000..14246fbc3e
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfiecc.c
+@@ -0,0 +1,510 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "nfiecc_regs.h"
++#include "nfiecc.h"
++
++#define NFIECC_IDLE_REG(op) \
++	((op) == ECC_ENCODE ? NFIECC_ENCIDLE : NFIECC_DECIDLE)
++#define         IDLE_MASK       1
++#define NFIECC_CTL_REG(op) \
++	((op) == ECC_ENCODE ? NFIECC_ENCCON : NFIECC_DECCON)
++#define NFIECC_IRQ_REG(op) \
++	((op) == ECC_ENCODE ? NFIECC_ENCIRQEN : NFIECC_DECIRQEN)
++#define NFIECC_ADDR(op) \
++	((op) == ECC_ENCODE ? NFIECC_ENCDIADDR : NFIECC_DECDIADDR)
++
++#define ECC_TIMEOUT     500000
++
++/* ecc strength that each IP supports */
++static const int ecc_strength_mt7622[] = {
++	4, 6, 8, 10, 12, 14, 16
++};
++
++static int nfiecc_irq_handler(void *data)
++{
++	struct nfiecc *ecc = data;
++	void *regs = ecc->res.regs;
++	u32 status;
++
++	status = readl(regs + NFIECC_DECIRQSTA) & DEC_IRQSTA_GEN;
++	if (status) {
++		status = readl(regs + NFIECC_DECDONE);
++		if (!(status & ecc->config.sectors))
++			return NAND_IRQ_NONE;
++
++		/*
++		 * Clear decode IRQ status once again to ensure that
++		 * there will be no extra IRQ.
++		 */
++		readl(regs + NFIECC_DECIRQSTA);
++		ecc->config.sectors = 0;
++		nandx_event_complete(ecc->done);
++	} else {
++		status = readl(regs + NFIECC_ENCIRQSTA) & ENC_IRQSTA_GEN;
++		if (!status)
++			return NAND_IRQ_NONE;
++
++		nandx_event_complete(ecc->done);
++	}
++
++	return NAND_IRQ_HANDLED;
++}
++
++static inline int nfiecc_wait_idle(struct nfiecc *ecc)
++{
++	int op = ecc->config.op;
++	int ret, val;
++
++	ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_IDLE_REG(op),
++					val, val & IDLE_MASK,
++					10, ECC_TIMEOUT);
++	if (ret)
++		pr_info("%s not idle\n",
++			op == ECC_ENCODE ? "encoder" : "decoder");
++
++	return ret;
++}
++
++static int nfiecc_wait_encode_done(struct nfiecc *ecc)
++{
++	int ret, val;
++
++	if (ecc->ecc_irq_en) {
++		/* poll one time to avoid missing irq event */
++		ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA,
++						val, val & ENC_FSM_IDLE, 1, 1);
++		if (!ret)
++			return 0;
++
++		/* irq done, if not, we can go on to poll status for a while */
++		ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT);
++		if (ret)
++			return 0;
++	}
++
++	ret = readl_poll_timeout_atomic(ecc->res.regs + NFIECC_ENCSTA,
++					val, val & ENC_FSM_IDLE,
++					10, ECC_TIMEOUT);
++	if (ret)
++		pr_info("encode timeout\n");
++
++	return ret;
++
++}
++
++static int nfiecc_wait_decode_done(struct nfiecc *ecc)
++{
++	u32 secbit = BIT(ecc->config.sectors - 1);
++	void *regs = ecc->res.regs;
++	int ret, val;
++
++	if (ecc->ecc_irq_en) {
++		ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE,
++						val, val & secbit, 1, 1);
++		if (!ret)
++			return 0;
++
++		ret = nandx_event_wait_complete(ecc->done, ECC_TIMEOUT);
++		if (ret)
++			return 0;
++	}
++
++	ret = readl_poll_timeout_atomic(regs + NFIECC_DECDONE,
++					val, val & secbit,
++					10, ECC_TIMEOUT);
++	if (ret) {
++		pr_info("decode timeout\n");
++		return ret;
++	}
++
++	/* decode done does not stands for ecc all work done.
++	 * we need check syn, bma, chien, autoc all idle.
++	 * just check it when ECC_DECCNFG[13:12] is 3,
++	 * which means auto correct.
++	 */
++	ret = readl_poll_timeout_atomic(regs + NFIECC_DECFSM,
++					val, (val & FSM_MASK) == FSM_IDLE,
++					10, ECC_TIMEOUT);
++	if (ret)
++		pr_info("decode fsm(0x%x) is not idle\n",
++		       readl(regs + NFIECC_DECFSM));
++
++	return ret;
++}
++
++static int nfiecc_wait_done(struct nfiecc *ecc)
++{
++	if (ecc->config.op == ECC_ENCODE)
++		return nfiecc_wait_encode_done(ecc);
++
++	return nfiecc_wait_decode_done(ecc);
++}
++
++static void nfiecc_encode_config(struct nfiecc *ecc, u32 ecc_idx)
++{
++	struct nfiecc_config *config = &ecc->config;
++	u32 val;
++
++	val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift);
++
++	if (config->mode == ECC_DMA_MODE)
++		val |= ENC_BURST_EN;
++
++	val |= (config->len << 3) << ENCCNFG_MS_SHIFT;
++	writel(val, ecc->res.regs + NFIECC_ENCCNFG);
++}
++
++static void nfiecc_decode_config(struct nfiecc *ecc, u32 ecc_idx)
++{
++	struct nfiecc_config *config = &ecc->config;
++	u32 dec_sz = (config->len << 3) +
++		     config->strength * ecc->caps->parity_bits;
++	u32 val;
++
++	val = ecc_idx | (config->mode << ecc->caps->ecc_mode_shift);
++
++	if (config->mode == ECC_DMA_MODE)
++		val |= DEC_BURST_EN;
++
++	val |= (dec_sz << DECCNFG_MS_SHIFT) |
++	       (config->deccon << DEC_CON_SHIFT);
++	val |= DEC_EMPTY_EN;
++	writel(val, ecc->res.regs + NFIECC_DECCNFG);
++}
++
++static void nfiecc_config(struct nfiecc *ecc)
++{
++	u32 idx;
++
++	for (idx = 0; idx < ecc->caps->ecc_strength_num; idx++) {
++		if (ecc->config.strength == ecc->caps->ecc_strength[idx])
++			break;
++	}
++
++	if (ecc->config.op == ECC_ENCODE)
++		nfiecc_encode_config(ecc, idx);
++	else
++		nfiecc_decode_config(ecc, idx);
++}
++
++static int nfiecc_enable(struct nfiecc *ecc)
++{
++	enum nfiecc_operation op = ecc->config.op;
++	void *regs = ecc->res.regs;
++
++	nfiecc_config(ecc);
++
++	writel(ECC_OP_EN, regs + NFIECC_CTL_REG(op));
++
++	if (ecc->ecc_irq_en) {
++		writel(ECC_IRQEN, regs + NFIECC_IRQ_REG(op));
++
++		if (ecc->page_irq_en)
++			writel(ECC_IRQEN | ECC_PG_IRQ_SEL,
++			       regs + NFIECC_IRQ_REG(op));
++
++		nandx_event_init(ecc->done);
++	}
++
++	return 0;
++}
++
++static int nfiecc_disable(struct nfiecc *ecc)
++{
++	enum nfiecc_operation op = ecc->config.op;
++	void *regs = ecc->res.regs;
++
++	nfiecc_wait_idle(ecc);
++
++	writel(0, regs + NFIECC_IRQ_REG(op));
++	writel(~ECC_OP_EN, regs + NFIECC_CTL_REG(op));
++
++	return 0;
++}
++
++static int nfiecc_correct_data(struct nfiecc *ecc,
++			       struct nfiecc_status *status,
++			       u8 *data, u32 sector)
++{
++	u32 err, offset, i;
++	u32 loc, byteloc, bitloc;
++
++	status->corrected = 0;
++	status->failed = 0;
++
++	offset = (sector >> 2);
++	err = readl(ecc->res.regs + NFIECC_DECENUM(offset));
++	err >>= (sector % 4) * 8;
++	err &= ecc->caps->err_mask;
++
++	if (err == ecc->caps->err_mask) {
++		status->failed++;
++		return -ENANDREAD;
++	}
++
++	status->corrected += err;
++	status->bitflips = max_t(u32, status->bitflips, err);
++
++	for (i = 0; i < err; i++) {
++		loc = readl(ecc->res.regs + NFIECC_DECEL(i >> 1));
++		loc >>= ((i & 0x1) << 4);
++		byteloc = loc >> 3;
++		bitloc = loc & 0x7;
++		data[byteloc] ^= (1 << bitloc);
++	}
++
++	return 0;
++}
++
++static int nfiecc_fill_data(struct nfiecc *ecc, u8 *data)
++{
++	struct nfiecc_config *config = &ecc->config;
++	void *regs = ecc->res.regs;
++	int size, ret, i;
++	u32 val;
++
++	if (config->mode == ECC_DMA_MODE) {
++		if ((unsigned long)config->dma_addr & 0x3)
++			pr_info("encode address is not 4B aligned: 0x%x\n",
++			       (u32)(unsigned long)config->dma_addr);
++
++		writel((unsigned long)config->dma_addr,
++		       regs + NFIECC_ADDR(config->op));
++	} else if (config->mode == ECC_PIO_MODE) {
++		if (config->op == ECC_ENCODE) {
++			size = (config->len + 3) >> 2;
++		} else {
++			size = config->strength * ecc->caps->parity_bits;
++			size = (size + 7) >> 3;
++			size += config->len;
++			size >>= 2;
++		}
++
++		for (i = 0; i < size; i++) {
++			ret = readl_poll_timeout_atomic(regs + NFIECC_PIO_DIRDY,
++							val, val & PIO_DI_RDY,
++							10, ECC_TIMEOUT);
++			if (ret)
++				return ret;
++
++			writel(*((u32 *)data + i), regs + NFIECC_PIO_DI);
++		}
++	}
++
++	return 0;
++}
++
++static int nfiecc_encode(struct nfiecc *ecc, u8 *data)
++{
++	struct nfiecc_config *config = &ecc->config;
++	u32 len, i, val = 0;
++	u8 *p;
++	int ret;
++
++	/* Under NFI mode, nothing need to do */
++	if (config->mode == ECC_NFI_MODE)
++		return 0;
++
++	ret = nfiecc_fill_data(ecc, data);
++	if (ret)
++		return ret;
++
++	ret = nfiecc_wait_encode_done(ecc);
++	if (ret)
++		return ret;
++
++	ret = nfiecc_wait_idle(ecc);
++	if (ret)
++		return ret;
++
++	/* Program ECC bytes to OOB: per sector oob = FDM + ECC + SPARE */
++	len = (config->strength * ecc->caps->parity_bits + 7) >> 3;
++	p = data + config->len;
++
++	/* Write the parity bytes generated by the ECC back to the OOB region */
++	for (i = 0; i < len; i++) {
++		if ((i % 4) == 0)
++			val = readl(ecc->res.regs + NFIECC_ENCPAR(i / 4));
++
++		p[i] = (val >> ((i % 4) * 8)) & 0xff;
++	}
++
++	return 0;
++}
++
++static int nfiecc_decode(struct nfiecc *ecc, u8 *data)
++{
++	int ret;
++
++	/* Under NFI mode, nothing need to do */
++	if (ecc->config.mode == ECC_NFI_MODE)
++		return 0;
++
++	ret = nfiecc_fill_data(ecc, data);
++	if (ret)
++		return ret;
++
++	return nfiecc_wait_decode_done(ecc);
++}
++
++static int nfiecc_decode_status(struct nfiecc *ecc, u32 start_sector,
++				u32 sectors)
++{
++	void *regs = ecc->res.regs;
++	u32 i, val = 0, err;
++	u32 bitflips = 0;
++
++	for (i = start_sector; i < start_sector + sectors; i++) {
++		if ((i % 4) == 0)
++			val = readl(regs + NFIECC_DECENUM(i / 4));
++
++		err = val >> ((i % 4) * 5);
++		err &= ecc->caps->err_mask;
++
++		if (err == ecc->caps->err_mask)
++			pr_err("sector %d is uncorrect\n", i);
++
++		bitflips = max_t(u32, bitflips, err);
++	}
++
++	if (bitflips == ecc->caps->err_mask)
++		return -ENANDREAD;
++
++	if (bitflips)
++		pr_info("bitflips %d is corrected\n", bitflips);
++
++	return bitflips;
++}
++
++static int nfiecc_adjust_strength(struct nfiecc *ecc, int strength)
++{
++	struct nfiecc_caps *caps = ecc->caps;
++	int i, count = caps->ecc_strength_num;
++
++	if (strength >= caps->ecc_strength[count - 1])
++		return caps->ecc_strength[count - 1];
++
++	if (strength < caps->ecc_strength[0])
++		return -EINVAL;
++
++	for (i = 1; i < count; i++) {
++		if (strength < caps->ecc_strength[i])
++			return caps->ecc_strength[i - 1];
++	}
++
++	return -EINVAL;
++}
++
++static int nfiecc_ctrl(struct nfiecc *ecc, int cmd, void *args)
++{
++	int ret = 0;
++
++	switch (cmd) {
++	case NFI_CTRL_ECC_IRQ:
++		ecc->ecc_irq_en = *(bool *)args;
++		break;
++
++	case NFI_CTRL_ECC_PAGE_IRQ:
++		ecc->page_irq_en = *(bool *)args;
++		break;
++
++	default:
++		pr_info("invalid arguments.\n");
++		ret = -EINVAL;
++		break;
++	}
++
++	return ret;
++}
++
++static int nfiecc_hw_init(struct nfiecc *ecc)
++{
++	int ret;
++
++	ret = nfiecc_wait_idle(ecc);
++	if (ret)
++		return ret;
++
++	writel(~ECC_OP_EN, ecc->res.regs + NFIECC_ENCCON);
++
++	ret = nfiecc_wait_idle(ecc);
++	if (ret)
++		return ret;
++
++	writel(~ECC_OP_EN, ecc->res.regs + NFIECC_DECCON);
++
++	return 0;
++}
++
++static struct nfiecc_caps nfiecc_caps_mt7622 = {
++	.err_mask = 0x1f,
++	.ecc_mode_shift = 4,
++	.parity_bits = 13,
++	.ecc_strength = ecc_strength_mt7622,
++	.ecc_strength_num = 7,
++};
++
++static struct nfiecc_caps *nfiecc_get_match_data(enum mtk_ic_version ic)
++{
++	/* NOTE: add other IC's data */
++	return &nfiecc_caps_mt7622;
++}
++
++struct nfiecc *nfiecc_init(struct nfiecc_resource *res)
++{
++	struct nfiecc *ecc;
++	int ret;
++
++	ecc = mem_alloc(1, sizeof(struct nfiecc));
++	if (!ecc)
++		return NULL;
++
++	ecc->res = *res;
++
++	ret = nandx_irq_register(res->dev, res->irq_id, nfiecc_irq_handler,
++				 "mtk-ecc", ecc);
++	if (ret) {
++		pr_info("ecc irq register failed!\n");
++		goto error;
++	}
++
++	ecc->ecc_irq_en = false;
++	ecc->page_irq_en = false;
++	ecc->done = nandx_event_create();
++	ecc->caps = nfiecc_get_match_data(res->ic_ver);
++
++	ecc->adjust_strength = nfiecc_adjust_strength;
++	ecc->enable = nfiecc_enable;
++	ecc->disable = nfiecc_disable;
++	ecc->decode = nfiecc_decode;
++	ecc->encode = nfiecc_encode;
++	ecc->wait_done = nfiecc_wait_done;
++	ecc->decode_status = nfiecc_decode_status;
++	ecc->correct_data = nfiecc_correct_data;
++	ecc->nfiecc_ctrl = nfiecc_ctrl;
++
++	ret = nfiecc_hw_init(ecc);
++	if (ret)
++		return NULL;
++
++	return ecc;
++
++error:
++	mem_free(ecc);
++
++	return NULL;
++}
++
++void nfiecc_exit(struct nfiecc *ecc)
++{
++	nandx_event_destroy(ecc->done);
++	mem_free(ecc);
++}
++
+diff --git a/drivers/mtd/nandx/core/nfi/nfiecc.h b/drivers/mtd/nandx/core/nfi/nfiecc.h
+new file mode 100644
+index 0000000000..b02a5c3534
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfiecc.h
+@@ -0,0 +1,90 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFIECC_H__
++#define __NFIECC_H__
++
++enum nfiecc_mode {
++	ECC_DMA_MODE,
++	ECC_NFI_MODE,
++	ECC_PIO_MODE
++};
++
++enum nfiecc_operation {
++	ECC_ENCODE,
++	ECC_DECODE
++};
++
++enum nfiecc_deccon {
++	ECC_DEC_FER = 1,
++	ECC_DEC_LOCATE = 2,
++	ECC_DEC_CORRECT = 3
++};
++
++struct nfiecc_resource {
++	int ic_ver;
++	void *dev;
++	void *regs;
++	int irq_id;
++
++};
++
++struct nfiecc_status {
++	u32 corrected;
++	u32 failed;
++	u32 bitflips;
++};
++
++struct nfiecc_caps {
++	u32 err_mask;
++	u32 ecc_mode_shift;
++	u32 parity_bits;
++	const int *ecc_strength;
++	u32 ecc_strength_num;
++};
++
++struct nfiecc_config {
++	enum nfiecc_operation op;
++	enum nfiecc_mode mode;
++	enum nfiecc_deccon deccon;
++
++	void *dma_addr; /* DMA use only */
++	u32 strength;
++	u32 sectors;
++	u32 len;
++};
++
++struct nfiecc {
++	struct nfiecc_resource res;
++	struct nfiecc_config config;
++	struct nfiecc_caps *caps;
++
++	bool ecc_irq_en;
++	bool page_irq_en;
++
++	void *done;
++
++	int (*adjust_strength)(struct nfiecc *ecc, int strength);
++	int (*enable)(struct nfiecc *ecc);
++	int (*disable)(struct nfiecc *ecc);
++
++	int (*decode)(struct nfiecc *ecc, u8 *data);
++	int (*encode)(struct nfiecc *ecc, u8 *data);
++
++	int (*decode_status)(struct nfiecc *ecc, u32 start_sector, u32 sectors);
++	int (*correct_data)(struct nfiecc *ecc,
++			    struct nfiecc_status *status,
++			    u8 *data, u32 sector);
++	int (*wait_done)(struct nfiecc *ecc);
++
++	int (*nfiecc_ctrl)(struct nfiecc *ecc, int cmd, void *args);
++};
++
++struct nfiecc *nfiecc_init(struct nfiecc_resource *res);
++void nfiecc_exit(struct nfiecc *ecc);
++
++#endif /* __NFIECC_H__ */
+diff --git a/drivers/mtd/nandx/core/nfi/nfiecc_regs.h b/drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+new file mode 100644
+index 0000000000..96564cf872
+--- /dev/null
++++ b/drivers/mtd/nandx/core/nfi/nfiecc_regs.h
+@@ -0,0 +1,51 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NFIECC_REGS_H__
++#define __NFIECC_REGS_H__
++
++#define NFIECC_ENCCON           0x000
++/* NFIECC_DECCON has same bit define */
++#define         ECC_OP_EN               BIT(0)
++#define NFIECC_ENCCNFG          0x004
++#define         ENCCNFG_MS_SHIFT        16
++#define         ENC_BURST_EN            BIT(8)
++#define NFIECC_ENCDIADDR        0x008
++#define NFIECC_ENCIDLE          0x00c
++#define NFIECC_ENCSTA           0x02c
++#define         ENC_FSM_IDLE            1
++#define NFIECC_ENCIRQEN         0x030
++/* NFIECC_DECIRQEN has same bit define */
++#define         ECC_IRQEN               BIT(0)
++#define         ECC_PG_IRQ_SEL          BIT(1)
++#define NFIECC_ENCIRQSTA        0x034
++#define         ENC_IRQSTA_GEN          BIT(0)
++#define NFIECC_PIO_DIRDY        0x080
++#define         PIO_DI_RDY              BIT(0)
++#define NFIECC_PIO_DI           0x084
++#define NFIECC_DECCON           0x100
++#define NFIECC_DECCNFG          0x104
++#define         DEC_BURST_EN            BIT(8)
++#define         DEC_EMPTY_EN            BIT(31)
++#define         DEC_CON_SHIFT           12
++#define         DECCNFG_MS_SHIFT        16
++#define NFIECC_DECDIADDR        0x108
++#define NFIECC_DECIDLE          0x10c
++#define NFIECC_DECENUM(x)       (0x114 + (x) * 4)
++#define NFIECC_DECDONE          0x11c
++#define NFIECC_DECIRQEN         0x140
++#define NFIECC_DECIRQSTA        0x144
++#define         DEC_IRQSTA_GEN          BIT(0)
++#define NFIECC_DECFSM           0x14c
++#define         FSM_MASK                0x7f0f0f0f
++#define         FSM_IDLE                0x01010101
++#define NFIECC_BYPASS           0x20c
++#define         NFIECC_BYPASS_EN        BIT(0)
++#define NFIECC_ENCPAR(x)        (0x010 + (x) * 4)
++#define NFIECC_DECEL(x)         (0x120 + (x) * 4)
++
++#endif /* __NFIECC_REGS_H__ */
+diff --git a/drivers/mtd/nandx/driver/Nandx.mk b/drivers/mtd/nandx/driver/Nandx.mk
+new file mode 100644
+index 0000000000..3fb93d37c5
+--- /dev/null
++++ b/drivers/mtd/nandx/driver/Nandx.mk
+@@ -0,0 +1,18 @@
++#
++# Copyright (C) 2017 MediaTek Inc.
++# Licensed under either
++#     BSD Licence, (see NOTICE for more details)
++#     GNU General Public License, version 2.0, (see NOTICE for more details)
++#
++
++nandx-$(NANDX_SIMULATOR_SUPPORT) += simulator/driver.c
++
++nandx-$(NANDX_CTP_SUPPORT) += ctp/ts_nand.c
++nandx-$(NANDX_CTP_SUPPORT) += ctp/nand_test.c
++nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nand_test.h
++
++nandx-$(NANDX_BBT_SUPPORT) += bbt/bbt.c
++nandx-$(NANDX_BROM_SUPPORT) += brom/driver.c
++nandx-$(NANDX_KERNEL_SUPPORT) += kernel/driver.c
++nandx-$(NANDX_LK_SUPPORT) += lk/driver.c
++nandx-$(NANDX_UBOOT_SUPPORT) += uboot/driver.c
+diff --git a/drivers/mtd/nandx/driver/bbt/bbt.c b/drivers/mtd/nandx/driver/bbt/bbt.c
+new file mode 100644
+index 0000000000..c9d4823e09
+--- /dev/null
++++ b/drivers/mtd/nandx/driver/bbt/bbt.c
+@@ -0,0 +1,408 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include "nandx_util.h"
++#include "nandx_core.h"
++#include "bbt.h"
++
++/* Not support: multi-chip */
++static u8 main_bbt_pattern[] = {'B', 'b', 't', '0' };
++static u8 mirror_bbt_pattern[] = {'1', 't', 'b', 'B' };
++
++static struct bbt_manager g_bbt_manager = {
++	{	{{main_bbt_pattern, 4}, 0, BBT_INVALID_ADDR},
++		{{mirror_bbt_pattern, 4}, 0, BBT_INVALID_ADDR}
++	},
++	NAND_BBT_SCAN_MAXBLOCKS, NULL
++};
++
++static inline void set_bbt_mark(u8 *bbt, int block, u8 mark)
++{
++	int index, offset;
++
++	index = GET_ENTRY(block);
++	offset = GET_POSITION(block);
++
++	bbt[index] &= ~(BBT_ENTRY_MASK << offset);
++	bbt[index] |= (mark & BBT_ENTRY_MASK) << offset;
++	pr_info("%s %d block:%d, bbt[%d]:0x%x, offset:%d, mark:%d\n",
++		__func__, __LINE__, block, index, bbt[index], offset, mark);
++}
++
++static inline u8 get_bbt_mark(u8 *bbt, int block)
++{
++	int offset = GET_POSITION(block);
++	int index = GET_ENTRY(block);
++	u8 value = bbt[index];
++
++	return (value >> offset) & BBT_ENTRY_MASK;
++}
++
++static void mark_nand_bad(struct nandx_info *nand, int block)
++{
++	u8 *buf;
++
++	buf = mem_alloc(1, nand->page_size + nand->oob_size);
++	if (!buf) {
++		pr_info("%s, %d, memory alloc fail, pagesize:%d, oobsize:%d\n",
++		       __func__, __LINE__, nand->page_size, nand->oob_size);
++		return;
++	}
++	memset(buf, 0, nand->page_size + nand->oob_size);
++	nandx_erase(block * nand->block_size, nand->block_size);
++	nandx_write(buf, buf + nand->page_size, block * nand->block_size,
++		    nand->page_size);
++	mem_free(buf);
++}
++
++static inline bool is_bbt_data(u8 *buf, struct bbt_pattern *pattern)
++{
++	int i;
++
++	for (i = 0; i < pattern->len; i++) {
++		if (buf[i] != pattern->data[i])
++			return false;
++	}
++
++	return true;
++}
++
++static u64 get_bbt_address(struct nandx_info *nand, u8 *bbt,
++			   u64 mirror_addr,
++			   int max_blocks)
++{
++	u64 addr, end_addr;
++	u8 mark;
++
++	addr = nand->total_size;
++	end_addr = nand->total_size - nand->block_size * max_blocks;
++
++	while (addr > end_addr) {
++		addr -= nand->block_size;
++		mark = get_bbt_mark(bbt, div_down(addr, nand->block_size));
++
++		if (mark == BBT_BLOCK_WORN || mark == BBT_BLOCK_FACTORY_BAD)
++			continue;
++		if (addr != mirror_addr)
++			return addr;
++	}
++
++	return BBT_INVALID_ADDR;
++}
++
++static int read_bbt(struct bbt_desc *desc, u8 *bbt, u32 len)
++{
++	int ret;
++
++	ret = nandx_read(bbt, NULL, desc->bbt_addr + desc->pattern.len + 1,
++			 len);
++	if (ret < 0)
++		pr_info("nand_bbt: error reading BBT page, ret:-%x\n", ret);
++
++	return ret;
++}
++
++static void create_bbt(struct nandx_info *nand, u8 *bbt)
++{
++	u32 offset = 0, block = 0;
++
++	do {
++		if (nandx_is_bad_block(offset)) {
++			pr_info("Create bbt at bad block:%d\n", block);
++			set_bbt_mark(bbt, block, BBT_BLOCK_FACTORY_BAD);
++		}
++		block++;
++		offset += nand->block_size;
++	} while (offset < nand->total_size);
++}
++
++static int search_bbt(struct nandx_info *nand, struct bbt_desc *desc,
++		      int max_blocks)
++{
++	u64 addr, end_addr;
++	u8 *buf;
++	int ret;
++
++	buf = mem_alloc(1, nand->page_size);
++	if (!buf) {
++		pr_info("%s, %d, mem alloc fail!!! len:%d\n",
++		       __func__, __LINE__, nand->page_size);
++		return -ENOMEM;
++	}
++
++	addr = nand->total_size;
++	end_addr = nand->total_size - max_blocks * nand->block_size;
++	while (addr > end_addr) {
++		addr -= nand->block_size;
++
++		nandx_read(buf, NULL, addr, nand->page_size);
++
++		if (is_bbt_data(buf, &desc->pattern)) {
++			desc->bbt_addr = addr;
++			desc->version = buf[desc->pattern.len];
++			pr_info("BBT is found at addr 0x%llx, version %d\n",
++				desc->bbt_addr, desc->version);
++			ret = 0;
++			break;
++		}
++		ret = -EFAULT;
++	}
++
++	mem_free(buf);
++	return ret;
++}
++
++static int save_bbt(struct nandx_info *nand, struct bbt_desc *desc,
++		    u8 *bbt)
++{
++	u32 page_size_mask, total_block;
++	int write_len;
++	u8 *buf;
++	int ret;
++
++	ret = nandx_erase(desc->bbt_addr, nand->block_size);
++	if (ret) {
++		pr_info("erase addr 0x%llx fail !!!, ret %d\n",
++			desc->bbt_addr, ret);
++		return ret;
++	}
++
++	total_block = div_down(nand->total_size, nand->block_size);
++	write_len = GET_BBT_LENGTH(total_block) + desc->pattern.len + 1;
++	page_size_mask = nand->page_size - 1;
++	write_len = (write_len + page_size_mask) & (~page_size_mask);
++
++	buf = (u8 *)mem_alloc(1, write_len);
++	if (!buf) {
++		pr_info("%s, %d, mem alloc fail!!! len:%d\n",
++		       __func__, __LINE__, write_len);
++		return -ENOMEM;
++	}
++	memset(buf, 0xFF, write_len);
++
++	memcpy(buf, desc->pattern.data, desc->pattern.len);
++	buf[desc->pattern.len] = desc->version;
++
++	memcpy(buf + desc->pattern.len + 1, bbt, GET_BBT_LENGTH(total_block));
++
++	ret = nandx_write(buf, NULL, desc->bbt_addr, write_len);
++
++	if (ret)
++		pr_info("nandx_write fail(%d), offset:0x%llx, len(%d)\n",
++		       ret, desc->bbt_addr, write_len);
++	mem_free(buf);
++
++	return ret;
++}
++
++static int write_bbt(struct nandx_info *nand, struct bbt_desc *main,
++		     struct bbt_desc *mirror, u8 *bbt, int max_blocks)
++{
++	int block;
++	int ret;
++
++	do {
++		if (main->bbt_addr == BBT_INVALID_ADDR) {
++			main->bbt_addr = get_bbt_address(nand, bbt,
++					 mirror->bbt_addr, max_blocks);
++			if (main->bbt_addr == BBT_INVALID_ADDR)
++				return -ENOSPC;
++		}
++
++		ret = save_bbt(nand, main, bbt);
++		if (!ret)
++			break;
++
++		block = div_down(main->bbt_addr, nand->block_size);
++		set_bbt_mark(bbt, block, BBT_BLOCK_WORN);
++		main->version++;
++		mark_nand_bad(nand, block);
++		main->bbt_addr = BBT_INVALID_ADDR;
++	} while (1);
++
++	return 0;
++}
++
++static void mark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks)
++{
++	int total_block;
++	int block;
++	u8 mark;
++
++	total_block = div_down(nand->total_size, nand->block_size);
++	block = total_block - bbt_blocks;
++
++	while (bbt_blocks) {
++		mark = get_bbt_mark(bbt, block);
++		if (mark == BBT_BLOCK_GOOD)
++			set_bbt_mark(bbt, block, BBT_BLOCK_RESERVED);
++		block++;
++		bbt_blocks--;
++	}
++}
++
++static void unmark_bbt_region(struct nandx_info *nand, u8 *bbt, int bbt_blocks)
++{
++	int total_block;
++	int block;
++	u8 mark;
++
++	total_block = div_down(nand->total_size, nand->block_size);
++	block = total_block - bbt_blocks;
++
++	while (bbt_blocks) {
++		mark = get_bbt_mark(bbt, block);
++		if (mark == BBT_BLOCK_RESERVED)
++			set_bbt_mark(bbt, block, BBT_BLOCK_GOOD);
++		block++;
++		bbt_blocks--;
++	}
++}
++
++static int update_bbt(struct nandx_info *nand, struct bbt_desc *desc,
++		      u8 *bbt,
++		      int max_blocks)
++{
++	int ret = 0, i;
++
++	/* The reserved info is not stored in NAND*/
++	unmark_bbt_region(nand, bbt, max_blocks);
++
++	desc[0].version++;
++	for (i = 0; i < 2; i++) {
++		if (i > 0)
++			desc[i].version = desc[i - 1].version;
++
++		ret = write_bbt(nand, &desc[i], &desc[1 - i], bbt, max_blocks);
++		if (ret)
++			break;
++	}
++	mark_bbt_region(nand, bbt, max_blocks);
++
++	return ret;
++}
++
++int scan_bbt(struct nandx_info *nand)
++{
++	struct bbt_manager *manager = &g_bbt_manager;
++	struct bbt_desc *pdesc;
++	int total_block, len, i;
++	int valid_desc = 0;
++	int ret = 0;
++	u8 *bbt;
++
++	total_block = div_down(nand->total_size, nand->block_size);
++	len = GET_BBT_LENGTH(total_block);
++
++	if (!manager->bbt) {
++		manager->bbt = (u8 *)mem_alloc(1, len);
++		if (!manager->bbt) {
++			pr_info("%s, %d, mem alloc fail!!! len:%d\n",
++			       __func__, __LINE__, len);
++			return -ENOMEM;
++		}
++	}
++	bbt = manager->bbt;
++	memset(bbt, 0xFF, len);
++
++	/* scan bbt */
++	for (i = 0; i < 2; i++) {
++		pdesc = &manager->desc[i];
++		pdesc->bbt_addr = BBT_INVALID_ADDR;
++		pdesc->version = 0;
++		ret = search_bbt(nand, pdesc, manager->max_blocks);
++		if (!ret && (pdesc->bbt_addr != BBT_INVALID_ADDR))
++			valid_desc += 1 << i;
++	}
++
++	pdesc = &manager->desc[0];
++	if ((valid_desc == 0x3) && (pdesc[0].version != pdesc[1].version))
++		valid_desc = (pdesc[0].version > pdesc[1].version) ? 1 : 2;
++
++	/* read bbt */
++	for (i = 0; i < 2; i++) {
++		if (!(valid_desc & (1 << i)))
++			continue;
++		ret = read_bbt(&pdesc[i], bbt, len);
++		if (ret) {
++			pdesc->bbt_addr = BBT_INVALID_ADDR;
++			pdesc->version = 0;
++			valid_desc &= ~(1 << i);
++		}
++		/* If two BBT version is same, only need to read the first bbt*/
++		if ((valid_desc == 0x3) &&
++		    (pdesc[0].version == pdesc[1].version))
++			break;
++	}
++
++	if (!valid_desc) {
++		create_bbt(nand, bbt);
++		pdesc[0].version = 1;
++		pdesc[1].version = 1;
++	}
++
++	pdesc[0].version = max_t(u8, pdesc[0].version, pdesc[1].version);
++	pdesc[1].version = pdesc[0].version;
++
++	for (i = 0; i < 2; i++) {
++		if (valid_desc & (1 << i))
++			continue;
++
++		ret = write_bbt(nand, &pdesc[i], &pdesc[1 - i], bbt,
++				manager->max_blocks);
++		if (ret) {
++			pr_info("write bbt(%d) fail, ret:%d\n", i, ret);
++			manager->bbt = NULL;
++			return ret;
++		}
++	}
++
++	/* Prevent the bbt regions from erasing / writing */
++	mark_bbt_region(nand, manager->bbt, manager->max_blocks);
++
++	for (i = 0; i < total_block; i++) {
++		if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_WORN)
++			pr_info("Checked WORN bad blk: %d\n", i);
++		else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_FACTORY_BAD)
++			pr_info("Checked Factory bad blk: %d\n", i);
++		else if (get_bbt_mark(manager->bbt, i) == BBT_BLOCK_RESERVED)
++			pr_info("Checked Reserved blk: %d\n", i);
++		else if (get_bbt_mark(manager->bbt, i) != BBT_BLOCK_GOOD)
++			pr_info("Checked unknown blk: %d\n", i);
++	}
++
++	return 0;
++}
++
++int bbt_mark_bad(struct nandx_info *nand, off_t offset)
++{
++	struct bbt_manager *manager = &g_bbt_manager;
++	int block = div_down(offset, nand->block_size);
++	int ret = 0;
++
++	mark_nand_bad(nand, block);
++
++#if 0
++	set_bbt_mark(manager->bbt, block, BBT_BLOCK_WORN);
++
++	/* Update flash-based bad block table */
++	ret = update_bbt(nand, manager->desc, manager->bbt,
++			 manager->max_blocks);
++#endif
++	pr_info("block %d, update result %d.\n", block, ret);
++
++	return ret;
++}
++
++int bbt_is_bad(struct nandx_info *nand, off_t offset)
++{
++	int block;
++
++	block = div_down(offset, nand->block_size);
++
++	return get_bbt_mark(g_bbt_manager.bbt, block) != BBT_BLOCK_GOOD;
++}
+diff --git a/drivers/mtd/nandx/driver/uboot/driver.c b/drivers/mtd/nandx/driver/uboot/driver.c
+new file mode 100644
+index 0000000000..7bd3342452
+--- /dev/null
++++ b/drivers/mtd/nandx/driver/uboot/driver.c
+@@ -0,0 +1,574 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#include <common.h>
++#include <linux/io.h>
++#include <dm.h>
++#include <clk.h>
++#include <nand.h>
++#include <linux/iopoll.h>
++#include <linux/delay.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include "nandx_core.h"
++#include "nandx_util.h"
++#include "bbt.h"
++
++typedef int (*func_nandx_operation)(u8 *, u8 *, u64, size_t);
++
++struct nandx_clk {
++	struct clk *nfi_clk;
++	struct clk *ecc_clk;
++	struct clk *snfi_clk;
++	struct clk *snfi_clk_sel;
++	struct clk *snfi_parent_50m;
++};
++
++struct nandx_nfc {
++	struct nandx_info info;
++	struct nandx_clk clk;
++	struct nfi_resource *res;
++
++	struct nand_chip *nand;
++	spinlock_t lock;
++};
++
++/* Default flash layout for MTK nand controller
++ * 64Bytes oob format.
++ */
++static struct nand_ecclayout eccoob = {
++	.eccbytes = 42,
++	.eccpos = {
++		17, 18, 19, 20, 21, 22, 23, 24, 25,
++		26, 27, 28, 29, 30, 31, 32, 33, 34,
++		35, 36, 37, 38, 39, 40, 41
++	},
++	.oobavail = 16,
++	.oobfree = {
++			{
++			.offset = 0,
++			.length = 16,
++			},
++	}
++};
++
++static struct nandx_nfc *mtd_to_nfc(struct mtd_info *mtd)
++{
++	struct nand_chip *nand = mtd_to_nand(mtd);
++
++	return (struct nandx_nfc *)nand_get_controller_data(nand);
++}
++
++static int nandx_enable_clk(struct nandx_clk *clk)
++{
++	int ret;
++
++	ret = clk_enable(clk->nfi_clk);
++	if (ret) {
++		pr_info("failed to enable nfi clk\n");
++		return ret;
++	}
++
++	ret = clk_enable(clk->ecc_clk);
++	if (ret) {
++		pr_info("failed to enable ecc clk\n");
++		goto disable_nfi_clk;
++	}
++
++	ret = clk_enable(clk->snfi_clk);
++	if (ret) {
++		pr_info("failed to enable snfi clk\n");
++		goto disable_ecc_clk;
++	}
++
++	ret = clk_enable(clk->snfi_clk_sel);
++	if (ret) {
++		pr_info("failed to enable snfi clk sel\n");
++		goto disable_snfi_clk;
++	}
++
++	ret = clk_set_parent(clk->snfi_clk_sel, clk->snfi_parent_50m);
++	if (ret) {
++		pr_info("failed to set snfi parent 50MHz\n");
++		goto disable_snfi_clk;
++	}
++
++	return 0;
++
++disable_snfi_clk:
++	clk_disable(clk->snfi_clk);
++disable_ecc_clk:
++	clk_disable(clk->ecc_clk);
++disable_nfi_clk:
++	clk_disable(clk->nfi_clk);
++
++	return ret;
++}
++
++static void nandx_disable_clk(struct nandx_clk *clk)
++{
++	clk_disable(clk->ecc_clk);
++	clk_disable(clk->nfi_clk);
++	clk_disable(clk->snfi_clk);
++}
++
++static int mtk_nfc_ooblayout_free(struct mtd_info *mtd, int section,
++				  struct mtd_oob_region *oob_region)
++{
++	struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
++	u32 eccsteps;
++
++	eccsteps = div_down(mtd->writesize, mtd->ecc_step_size);
++
++	if (section >= eccsteps)
++		return -EINVAL;
++
++	oob_region->length = nfc->info.fdm_reg_size - nfc->info.fdm_ecc_size;
++	oob_region->offset = section * nfc->info.fdm_reg_size
++		+ nfc->info.fdm_ecc_size;
++
++	return 0;
++}
++
++static int mtk_nfc_ooblayout_ecc(struct mtd_info *mtd, int section,
++				 struct mtd_oob_region *oob_region)
++{
++	struct nandx_nfc *nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
++	u32 eccsteps;
++
++	if (section)
++		return -EINVAL;
++
++	eccsteps = div_down(mtd->writesize, mtd->ecc_step_size);
++	oob_region->offset = nfc->info.fdm_reg_size * eccsteps;
++	oob_region->length = mtd->oobsize - oob_region->offset;
++
++	return 0;
++}
++
++static const struct mtd_ooblayout_ops mtk_nfc_ooblayout_ops = {
++	.rfree = mtk_nfc_ooblayout_free,
++	.ecc = mtk_nfc_ooblayout_ecc,
++};
++
++struct nfc_compatible {
++	enum mtk_ic_version ic_ver;
++
++	u32 clock_1x;
++	u32 *clock_2x;
++	int clock_2x_num;
++
++	int min_oob_req;
++};
++
++static const struct nfc_compatible nfc_compats_mt7622 = {
++	.ic_ver = NANDX_MT7622,
++	.clock_1x = 26000000,
++	.clock_2x = NULL,
++	.clock_2x_num = 8,
++	.min_oob_req = 1,
++};
++
++static const struct udevice_id ic_of_match[] = {
++	{.compatible = "mediatek,mt7622-nfc", .data = &nfc_compats_mt7622},
++	{}
++};
++
++static int nand_operation(struct mtd_info *mtd, loff_t addr, size_t len,
++	      size_t *retlen, uint8_t *data, uint8_t *oob, bool read)
++{
++	struct nandx_split64 split = {0};
++	func_nandx_operation operation;
++	u64 block_oobs, val, align;
++	uint8_t *databuf, *oobbuf;
++	struct nandx_nfc *nfc;
++	bool readoob;
++	int ret = 0;
++
++	nfc = (struct nandx_nfc *)nand_get_controller_data;
++	spin_lock(&nfc->lock);
++
++	databuf = data;
++	oobbuf = oob;
++
++	readoob = data ? false : true;
++	block_oobs = div_up(mtd->erasesize, mtd->writesize) * mtd->oobavail;
++	align = readoob ? block_oobs : mtd->erasesize;
++
++	operation = read ? nandx_read : nandx_write;
++
++	nandx_split(&split, addr, len, val, align);
++
++	if (split.head_len) {
++		ret = operation((u8 *) databuf, oobbuf, addr, split.head_len);
++
++		if (databuf)
++			databuf += split.head_len;
++
++		if (oobbuf)
++			oobbuf += split.head_len;
++
++		addr += split.head_len;
++		*retlen += split.head_len;
++	}
++
++	if (split.body_len) {
++		while (div_up(split.body_len, align)) {
++			ret = operation((u8 *) databuf, oobbuf, addr, align);
++
++			if (databuf) {
++				databuf += mtd->erasesize;
++				split.body_len -= mtd->erasesize;
++				*retlen += mtd->erasesize;
++			}
++
++			if (oobbuf) {
++				oobbuf += block_oobs;
++				split.body_len -= block_oobs;
++				*retlen += block_oobs;
++			}
++
++			addr += mtd->erasesize;
++		}
++
++	}
++
++	if (split.tail_len) {
++		ret = operation((u8 *) databuf, oobbuf, addr, split.tail_len);
++		*retlen += split.tail_len;
++	}
++
++	spin_unlock(&nfc->lock);
++
++	return ret;
++}
++
++static int mtk_nand_read(struct mtd_info *mtd, loff_t from, size_t len,
++	      size_t *retlen, u_char *buf)
++{
++	return nand_operation(mtd, from, len, retlen, buf, NULL, true);
++}
++
++static int mtk_nand_write(struct mtd_info *mtd, loff_t to, size_t len,
++	       size_t *retlen, const u_char *buf)
++{
++	return nand_operation(mtd, to, len, retlen, (uint8_t *)buf,
++		NULL, false);
++}
++
++int mtk_nand_read_oob(struct mtd_info *mtd, loff_t from, struct mtd_oob_ops *ops)
++{
++	size_t retlen;
++
++	return nand_operation(mtd, from, ops->ooblen, &retlen, NULL,
++		ops->oobbuf, true);
++}
++
++int mtk_nand_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
++{
++	size_t retlen;
++
++	return nand_operation(mtd, to, ops->ooblen, &retlen, NULL,
++		ops->oobbuf, false);
++}
++
++static int mtk_nand_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++	struct nandx_nfc *nfc;
++	u64 erase_len, erase_addr;
++	u32 block_size;
++	int ret = 0;
++
++	nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
++	block_size = nfc->info.block_size;
++	erase_len = instr->len;
++	erase_addr = instr->addr;
++	spin_lock(&nfc->lock);
++	instr->state = MTD_ERASING;
++
++	while (erase_len) {
++		if (mtk_nand_is_bad(mtd, erase_addr)) {
++			pr_info("block(0x%llx) is bad, not erase\n",
++				erase_addr);
++			instr->state = MTD_ERASE_FAILED;
++			goto erase_exit;
++		} else {
++			ret = nandx_erase(erase_addr, block_size);
++			if (ret < 0) {
++				instr->state = MTD_ERASE_FAILED;
++				goto erase_exit;
++				pr_info("erase fail at blk %llu, ret:%d\n",
++					erase_addr, ret);
++			}
++		}
++		erase_addr += block_size;
++		erase_len -= block_size;
++	}
++
++	instr->state = MTD_ERASE_DONE;
++
++erase_exit:
++	ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;
++
++	spin_unlock(&nfc->lock);
++	/* Do mtd call back function */
++	if (!ret)
++		mtd_erase_callback(instr);
++
++	return ret;
++}
++
++int mtk_nand_is_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nandx_nfc *nfc;
++	int ret;
++
++	nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
++	spin_lock(&nfc->lock);
++
++	/*ret = bbt_is_bad(&nfc->info, ofs);*/
++	ret = nandx_is_bad_block(ofs);
++	spin_unlock(&nfc->lock);
++
++	if (ret) {
++		pr_info("nand block 0x%x is bad, ret %d!\n", ofs, ret);
++		return 1;
++	} else {
++		return 0;
++	}
++}
++
++int mtk_nand_mark_bad(struct mtd_info *mtd, loff_t ofs)
++{
++	struct nandx_nfc *nfc;
++	int ret;
++
++	nfc = (struct nandx_nfc *)mtd_to_nfc(mtd);
++	spin_lock(&nfc->lock);
++	pr_info("%s, %d\n", __func__, __LINE__);
++	ret = bbt_mark_bad(&nfc->info, ofs);
++
++	spin_unlock(&nfc->lock);
++
++	return ret;
++}
++
++void mtk_nand_sync(struct mtd_info *mtd)
++{
++	nandx_sync();
++}
++
++static struct mtd_info *mtd_info_create(struct udevice *pdev,
++		struct nandx_nfc *nfc, struct nand_chip *nand)
++{
++	struct mtd_info *mtd = nand_to_mtd(nand);
++	int ret;
++
++	nand_set_controller_data(nand, nfc);
++
++	nand->flash_node = dev_of_offset(pdev);
++	nand->ecc.layout = &eccoob;
++
++	ret = nandx_ioctl(CORE_CTRL_NAND_INFO, &nfc->info);
++	if (ret) {
++		pr_info("fail to get nand info (%d)!\n", ret);
++		mem_free(mtd);
++		return NULL;
++	}
++
++	mtd->owner = THIS_MODULE;
++
++	mtd->name = "MTK-SNand";
++	mtd->writesize = nfc->info.page_size;
++	mtd->erasesize = nfc->info.block_size;
++	mtd->oobsize = nfc->info.oob_size;
++	mtd->size = nfc->info.total_size;
++	mtd->type = MTD_NANDFLASH;
++	mtd->flags = MTD_CAP_NANDFLASH;
++	mtd->_erase = mtk_nand_erase;
++	mtd->_read = mtk_nand_read;
++	mtd->_write = mtk_nand_write;
++	mtd->_read_oob = mtk_nand_read_oob;
++	mtd->_write_oob = mtk_nand_write_oob;
++	mtd->_sync = mtk_nand_sync;
++	mtd->_lock = NULL;
++	mtd->_unlock = NULL;
++	mtd->_block_isbad = mtk_nand_is_bad;
++	mtd->_block_markbad = mtk_nand_mark_bad;
++	mtd->writebufsize = mtd->writesize;
++
++	mtd_set_ooblayout(mtd, &mtk_nfc_ooblayout_ops);
++
++	mtd->ecc_strength = nfc->info.ecc_strength;
++	mtd->ecc_step_size = nfc->info.sector_size;
++
++	if (!mtd->bitflip_threshold)
++		mtd->bitflip_threshold = mtd->ecc_strength;
++
++	return mtd;
++}
++
++int board_nand_init(struct nand_chip *nand)
++{
++	struct udevice *dev;
++	struct mtd_info *mtd;
++	struct nandx_nfc *nfc;
++	int arg = 1;
++	int ret;
++
++	ret = uclass_get_device_by_driver(UCLASS_MTD,
++					  DM_GET_DRIVER(mtk_snand_drv),
++					  &dev);
++	if (ret) {
++		pr_err("Failed to get mtk_nand_drv. (error %d)\n", ret);
++		return ret;
++	}
++
++	nfc = dev_get_priv(dev);
++
++	ret = nandx_enable_clk(&nfc->clk);
++	if (ret) {
++		pr_err("failed to enable nfi clk (error %d)\n", ret);
++		return ret;
++	}
++
++	ret = nandx_init(nfc->res);
++	if (ret) {
++		pr_err("nandx init error (%d)!\n", ret);
++		goto disable_clk;
++	}
++
++	arg = 1;
++	nandx_ioctl(NFI_CTRL_DMA, &arg);
++	nandx_ioctl(NFI_CTRL_ECC, &arg);
++
++#ifdef NANDX_UNIT_TEST
++	nandx_unit_test(0x780000, 0x800);
++#endif
++
++	mtd = mtd_info_create(dev, nfc, nand);
++	if (!mtd) {
++		ret = -ENOMEM;
++		goto disable_clk;
++	}
++
++	spin_lock_init(&nfc->lock);
++#if 0
++	ret = scan_bbt(&nfc->info);
++	if (ret) {
++		pr_info("bbt init error (%d)!\n", ret);
++		goto disable_clk;
++	}
++#endif
++	return ret;
++
++disable_clk:
++	nandx_disable_clk(&nfc->clk);
++
++	return ret;
++}
++
++static int mtk_snand_ofdata_to_platdata(struct udevice *dev)
++{
++	struct nandx_nfc *nfc = dev_get_priv(dev);
++	struct nfc_compatible *compat;
++	struct nfi_resource *res;
++
++	int ret = 0;
++
++	res = mem_alloc(1, sizeof(struct nfi_resource));
++	if (!res)
++		return -ENOMEM;
++
++	nfc->res = res;
++
++	res->nfi_regs = (void *)dev_read_addr_index(dev, 0);
++	res->ecc_regs = (void *)dev_read_addr_index(dev, 1);
++	pr_debug("mtk snand nfi_regs:0x%x ecc_regs:0x%x\n",
++		res->nfi_regs, res->ecc_regs);
++
++	compat = (struct nfc_compatible *)dev_get_driver_data(dev);
++
++	res->ic_ver = (enum mtk_ic_version)(compat->ic_ver);
++	res->clock_1x = compat->clock_1x;
++	res->clock_2x = compat->clock_2x;
++	res->clock_2x_num = compat->clock_2x_num;
++
++	memset(&nfc->clk, 0, sizeof(struct nandx_clk));
++	nfc->clk.nfi_clk =
++	    kmalloc(sizeof(*nfc->clk.nfi_clk), GFP_KERNEL);
++	nfc->clk.ecc_clk =
++	    kmalloc(sizeof(*nfc->clk.ecc_clk), GFP_KERNEL);
++	nfc->clk.snfi_clk=
++	    kmalloc(sizeof(*nfc->clk.snfi_clk), GFP_KERNEL);
++	nfc->clk.snfi_clk_sel =
++	    kmalloc(sizeof(*nfc->clk.snfi_clk_sel), GFP_KERNEL);
++	nfc->clk.snfi_parent_50m =
++	    kmalloc(sizeof(*nfc->clk.snfi_parent_50m), GFP_KERNEL);
++
++	if (!nfc->clk.nfi_clk || !nfc->clk.ecc_clk || !nfc->clk.snfi_clk ||
++		!nfc->clk.snfi_clk_sel || !nfc->clk.snfi_parent_50m) {
++		ret = -ENOMEM;
++		goto err;
++	}
++
++	ret = clk_get_by_name(dev, "nfi_clk", nfc->clk.nfi_clk);
++	if (IS_ERR(nfc->clk.nfi_clk)) {
++		ret = PTR_ERR(nfc->clk.nfi_clk);
++		goto err;
++	}
++
++	ret = clk_get_by_name(dev, "ecc_clk", nfc->clk.ecc_clk);
++	if (IS_ERR(nfc->clk.ecc_clk)) {
++		ret = PTR_ERR(nfc->clk.ecc_clk);
++		goto err;
++	}
++
++	ret = clk_get_by_name(dev, "snfi_clk", nfc->clk.snfi_clk);
++	if (IS_ERR(nfc->clk.snfi_clk)) {
++		ret = PTR_ERR(nfc->clk.snfi_clk);
++		goto err;
++	}
++
++	ret = clk_get_by_name(dev, "spinfi_sel", nfc->clk.snfi_clk_sel);
++	if (IS_ERR(nfc->clk.snfi_clk_sel)) {
++		ret = PTR_ERR(nfc->clk.snfi_clk_sel);
++		goto err;
++	}
++
++	ret = clk_get_by_name(dev, "spinfi_parent_50m", nfc->clk.snfi_parent_50m);
++	if (IS_ERR(nfc->clk.snfi_parent_50m))
++		pr_info("spinfi parent 50MHz is not configed\n");
++
++	return 0;
++err:
++	if (nfc->clk.nfi_clk)
++		kfree(nfc->clk.nfi_clk);
++	if (nfc->clk.snfi_clk)
++		kfree(nfc->clk.snfi_clk);
++	if (nfc->clk.ecc_clk)
++		kfree(nfc->clk.ecc_clk);
++	if (nfc->clk.snfi_clk_sel)
++		kfree(nfc->clk.snfi_clk_sel);
++	if (nfc->clk.snfi_parent_50m)
++		kfree(nfc->clk.snfi_parent_50m);
++
++	return ret;
++}
++
++U_BOOT_DRIVER(mtk_snand_drv) = {
++	.name = "mtk_snand",
++	.id = UCLASS_MTD,
++	.of_match = ic_of_match,
++	.ofdata_to_platdata = mtk_snand_ofdata_to_platdata,
++	.priv_auto_alloc_size = sizeof(struct nandx_nfc),
++};
++
++MODULE_LICENSE("GPL v2");
++MODULE_DESCRIPTION("MTK Nand Flash Controller Driver");
++MODULE_AUTHOR("MediaTek");
+diff --git a/drivers/mtd/nandx/include/Nandx.mk b/drivers/mtd/nandx/include/Nandx.mk
+new file mode 100644
+index 0000000000..667402790e
+--- /dev/null
++++ b/drivers/mtd/nandx/include/Nandx.mk
+@@ -0,0 +1,16 @@
++#
++# Copyright (C) 2017 MediaTek Inc.
++# Licensed under either
++#     BSD Licence, (see NOTICE for more details)
++#     GNU General Public License, version 2.0, (see NOTICE for more details)
++#
++
++nandx-header-y += internal/nandx_core.h
++nandx-header-y += internal/nandx_errno.h
++nandx-header-y += internal/nandx_util.h
++nandx-header-$(NANDX_BBT_SUPPORT) += internal/bbt.h
++nandx-header-$(NANDX_SIMULATOR_SUPPORT) += simulator/nandx_os.h
++nandx-header-$(NANDX_CTP_SUPPORT) += ctp/nandx_os.h
++nandx-header-$(NANDX_LK_SUPPORT) += lk/nandx_os.h
++nandx-header-$(NANDX_KERNEL_SUPPORT) += kernel/nandx_os.h
++nandx-header-$(NANDX_UBOOT_SUPPORT) += uboot/nandx_os.h
+diff --git a/drivers/mtd/nandx/include/internal/bbt.h b/drivers/mtd/nandx/include/internal/bbt.h
+new file mode 100644
+index 0000000000..4676def1f5
+--- /dev/null
++++ b/drivers/mtd/nandx/include/internal/bbt.h
+@@ -0,0 +1,62 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __BBT_H__
++#define __BBT_H__
++
++#define BBT_BLOCK_GOOD      0x03
++#define BBT_BLOCK_WORN      0x02
++#define BBT_BLOCK_RESERVED      0x01
++#define BBT_BLOCK_FACTORY_BAD   0x00
++
++#define BBT_INVALID_ADDR 0
++/* The maximum number of blocks to scan for a bbt */
++#define NAND_BBT_SCAN_MAXBLOCKS 4
++#define NAND_BBT_USE_FLASH  0x00020000
++#define NAND_BBT_NO_OOB     0x00040000
++
++/* Search good / bad pattern on the first and the second page */
++#define NAND_BBT_SCAN2NDPAGE    0x00008000
++/* Search good / bad pattern on the last page of the eraseblock */
++#define NAND_BBT_SCANLASTPAGE   0x00010000
++
++#define NAND_DRAM_BUF_DATABUF_ADDR  (NAND_BUF_ADDR)
++
++struct bbt_pattern {
++	u8 *data;
++	int len;
++};
++
++struct bbt_desc {
++	struct bbt_pattern pattern;
++	u8 version;
++	u64 bbt_addr;/*0: invalid value; otherwise, valid value*/
++};
++
++struct bbt_manager {
++	/* main bbt descriptor and mirror descriptor */
++	struct bbt_desc desc[2];/* 0: main bbt; 1: mirror bbt */
++	int max_blocks;
++	u8 *bbt;
++};
++
++#define BBT_ENTRY_MASK      0x03
++#define BBT_ENTRY_SHIFT     2
++
++#define GET_BBT_LENGTH(blocks) (blocks >> 2)
++#define GET_ENTRY(block) ((block) >> BBT_ENTRY_SHIFT)
++#define GET_POSITION(block) (((block) & BBT_ENTRY_MASK) * 2)
++#define GET_MARK_VALUE(block, mark) \
++	(((mark) & BBT_ENTRY_MASK) << GET_POSITION(block))
++
++int scan_bbt(struct nandx_info *nand);
++
++int bbt_mark_bad(struct nandx_info *nand, off_t offset);
++
++int bbt_is_bad(struct nandx_info *nand, off_t offset);
++
++#endif /*__BBT_H__*/
+diff --git a/drivers/mtd/nandx/include/internal/nandx_core.h b/drivers/mtd/nandx/include/internal/nandx_core.h
+new file mode 100644
+index 0000000000..09aff72224
+--- /dev/null
++++ b/drivers/mtd/nandx/include/internal/nandx_core.h
+@@ -0,0 +1,250 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NANDX_CORE_H__
++#define __NANDX_CORE_H__
++
++/**
++ * mtk_ic_version - indicates specifical IC, IP need this to load some info
++ */
++enum mtk_ic_version {
++	NANDX_MT7622,
++};
++
++/**
++ * nandx_ioctl_cmd - operations supported by nandx
++ *
++ * @NFI_CTRL_DMA dma enable or not
++ * @NFI_CTRL_NFI_MODE customer/read/program/erase...
++ * @NFI_CTRL_ECC ecc enable or not
++ * @NFI_CTRL_ECC_MODE nfi/dma/pio
++ * @CHIP_CTRL_DRIVE_STRENGTH enum chip_ctrl_drive_strength
++ */
++enum nandx_ctrl_cmd {
++	CORE_CTRL_NAND_INFO,
++
++	NFI_CTRL_DMA,
++	NFI_CTRL_NFI_MODE,
++	NFI_CTRL_AUTOFORMAT,
++	NFI_CTRL_NFI_IRQ,
++	NFI_CTRL_PAGE_IRQ,
++	NFI_CTRL_RANDOMIZE,
++	NFI_CTRL_BAD_MARK_SWAP,
++
++	NFI_CTRL_ECC,
++	NFI_CTRL_ECC_MODE,
++	NFI_CTRL_ECC_CLOCK,
++	NFI_CTRL_ECC_IRQ,
++	NFI_CTRL_ECC_PAGE_IRQ,
++	NFI_CTRL_ECC_DECODE_MODE,
++
++	SNFI_CTRL_OP_MODE,
++	SNFI_CTRL_RX_MODE,
++	SNFI_CTRL_TX_MODE,
++	SNFI_CTRL_DELAY_MODE,
++
++	CHIP_CTRL_OPS_CACHE,
++	CHIP_CTRL_OPS_MULTI,
++	CHIP_CTRL_PSLC_MODE,
++	CHIP_CTRL_DRIVE_STRENGTH,
++	CHIP_CTRL_DDR_MODE,
++	CHIP_CTRL_ONDIE_ECC,
++	CHIP_CTRL_TIMING_MODE
++};
++
++enum snfi_ctrl_op_mode {
++	SNFI_CUSTOM_MODE,
++	SNFI_AUTO_MODE,
++	SNFI_MAC_MODE
++};
++
++enum snfi_ctrl_rx_mode {
++	SNFI_RX_111,
++	SNFI_RX_112,
++	SNFI_RX_114,
++	SNFI_RX_122,
++	SNFI_RX_144
++};
++
++enum snfi_ctrl_tx_mode {
++	SNFI_TX_111,
++	SNFI_TX_114,
++};
++
++enum chip_ctrl_drive_strength {
++	CHIP_DRIVE_NORMAL,
++	CHIP_DRIVE_HIGH,
++	CHIP_DRIVE_MIDDLE,
++	CHIP_DRIVE_LOW
++};
++
++enum chip_ctrl_timing_mode {
++	CHIP_TIMING_MODE0,
++	CHIP_TIMING_MODE1,
++	CHIP_TIMING_MODE2,
++	CHIP_TIMING_MODE3,
++	CHIP_TIMING_MODE4,
++	CHIP_TIMING_MODE5,
++};
++
++/**
++ * nandx_info - basic information
++ */
++struct nandx_info {
++	u32 max_io_count;
++	u32 min_write_pages;
++	u32 plane_num;
++	u32 oob_size;
++	u32 page_parity_size;
++	u32 page_size;
++	u32 block_size;
++	u64 total_size;
++	u32 fdm_reg_size;
++	u32 fdm_ecc_size;
++	u32 ecc_strength;
++	u32 sector_size;
++};
++
++/**
++ * nfi_resource - the resource needed by nfi & ecc to do initialization
++ */
++struct nfi_resource {
++	int ic_ver;
++	void *dev;
++
++	void *ecc_regs;
++	int ecc_irq_id;
++
++	void *nfi_regs;
++	int nfi_irq_id;
++
++	u32 clock_1x;
++	u32 *clock_2x;
++	int clock_2x_num;
++
++	int min_oob_req;
++};
++
++/**
++ * nandx_init - init all related modules below
++ *
++ * @res: basic resource of the project
++ *
++ * return 0 if init success, otherwise return negative error code
++ */
++int nandx_init(struct nfi_resource *res);
++
++/**
++ * nandx_exit - release resource those that obtained in init flow
++ */
++void nandx_exit(void);
++
++/**
++ * nandx_read - read data from nand this function can read data and related
++ *   oob from specifical address
++ *   if do multi_ops, set one operation per time, and call nandx_sync at last
++ *   in multi mode, not support page partial read
++ *   oob not support partial read
++ *
++ * @data: buf to receive data from nand
++ * @oob: buf to receive oob data from nand which related to data page
++ *   length of @oob should oob size aligned, oob not support partial read
++ * @offset: offset address on the whole flash
++ * @len: the length of @data that need to read
++ *
++ * if read success return 0, otherwise return negative error code
++ */
++int nandx_read(u8 *data, u8 *oob, u64 offset, size_t len);
++
++/**
++ * nandx_write -  write data to nand
++ *   this function can write data and related oob to specifical address
++ *   if do multi_ops, set one operation per time, and call nandx_sync at last
++ *
++ * @data: source data to be written to nand,
++ *   for multi operation, the length of @data should be page size aliged
++ * @oob: source oob which related to data page to be written to nand,
++ *   length of @oob should oob size aligned
++ * @offset: offset address on the whole flash, the value should be start address
++ *   of a page
++ * @len: the length of @data that need to write,
++ *   for multi operation, the len should be page size aliged
++ *
++ * if write success return 0, otherwise return negative error code
++ * if return value > 0, it indicates that how many pages still need to write,
++ * and data has not been written to nand
++ * please call nandx_sync after pages alligned $nandx_info.min_write_pages
++ */
++int nandx_write(u8 *data, u8 *oob, u64 offset, size_t len);
++
++/**
++ * nandx_erase - erase an area of nand
++ *   if do multi_ops, set one operation per time, and call nandx_sync at last
++ *
++ * @offset: offset address on the flash
++ * @len: erase length which should be block size aligned
++ *
++ * if erase success return 0, otherwise return negative error code
++ */
++int nandx_erase(u64 offset, size_t len);
++
++/**
++ * nandx_sync - sync all operations to nand
++ *   when do multi_ops, this function will be called at last operation
++ *   when write data, if number of pages not alligned
++ *   by $nandx_info.min_write_pages, this interface could be called to do
++ *   force write, 0xff will be padded to blanked pages.
++ */
++int nandx_sync(void);
++
++/**
++ * nandx_is_bad_block - check if the block is bad
++ *   only check the flag that marked by the flash vendor
++ *
++ * @offset: offset address on the whole flash
++ *
++ * return true if the block is bad, otherwise return false
++ */
++bool nandx_is_bad_block(u64 offset);
++
++/**
++ * nandx_ioctl - set/get property of nand chip
++ *
++ * @cmd: parameter that defined in enum nandx_ioctl_cmd
++ * @arg: operate parameter
++ *
++ * return 0 if operate success, otherwise return negative error code
++ */
++int nandx_ioctl(int cmd, void *arg);
++
++/**
++ * nandx_suspend - suspend nand, and store some data
++ *
++ * return 0 if suspend success, otherwise return negative error code
++ */
++int nandx_suspend(void);
++
++/**
++ * nandx_resume - resume nand, and replay some data
++ *
++ * return 0 if resume success, otherwise return negative error code
++ */
++int nandx_resume(void);
++
++#ifdef NANDX_UNIT_TEST
++/**
++ * nandx_unit_test - unit test
++ *
++ * @offset: offset address on the whole flash
++ * @len: should be not larger than a block size, we only test a block per time
++ *
++ * return 0 if test success, otherwise return negative error code
++ */
++int nandx_unit_test(u64 offset, size_t len);
++#endif
++
++#endif /* __NANDX_CORE_H__ */
+diff --git a/drivers/mtd/nandx/include/internal/nandx_errno.h b/drivers/mtd/nandx/include/internal/nandx_errno.h
+new file mode 100644
+index 0000000000..51fb299c03
+--- /dev/null
++++ b/drivers/mtd/nandx/include/internal/nandx_errno.h
+@@ -0,0 +1,40 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NANDX_ERRNO_H__
++#define __NANDX_ERRNO_H__
++
++#ifndef EIO
++#define EIO             5       /* I/O error */
++#define ENOMEM          12      /* Out of memory */
++#define EFAULT          14      /* Bad address */
++#define EBUSY           16      /* Device or resource busy */
++#define ENODEV          19      /* No such device */
++#define EINVAL          22      /* Invalid argument */
++#define ENOSPC          28      /* No space left on device */
++/* Operation not supported on transport endpoint */
++#define EOPNOTSUPP      95
++#define ETIMEDOUT       110     /* Connection timed out */
++#endif
++
++#define ENANDFLIPS      1024    /* Too many bitflips, uncorrected */
++#define ENANDREAD       1025    /* Read fail, can't correct */
++#define ENANDWRITE      1026    /* Write fail */
++#define ENANDERASE      1027    /* Erase fail */
++#define ENANDBAD        1028    /* Bad block */
++#define ENANDWP         1029
++
++#define IS_NAND_ERR(err)        ((err) >= -ENANDBAD && (err) <= -ENANDFLIPS)
++
++#ifndef MAX_ERRNO
++#define MAX_ERRNO       4096
++#define ERR_PTR(errno)  ((void *)((long)errno))
++#define PTR_ERR(ptr)    ((long)(ptr))
++#define IS_ERR(ptr)     ((unsigned long)(ptr) > (unsigned long)-MAX_ERRNO)
++#endif
++
++#endif /* __NANDX_ERRNO_H__ */
+diff --git a/drivers/mtd/nandx/include/internal/nandx_util.h b/drivers/mtd/nandx/include/internal/nandx_util.h
+new file mode 100644
+index 0000000000..1990b000ee
+--- /dev/null
++++ b/drivers/mtd/nandx/include/internal/nandx_util.h
+@@ -0,0 +1,221 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NANDX_UTIL_H__
++#define __NANDX_UTIL_H__
++
++typedef unsigned char u8;
++typedef unsigned short u16;
++typedef unsigned int u32;
++typedef unsigned long long u64;
++
++enum nand_irq_return {
++	NAND_IRQ_NONE,
++	NAND_IRQ_HANDLED,
++};
++
++enum nand_dma_operation {
++	NDMA_FROM_DEV,
++	NDMA_TO_DEV,
++};
++
++
++/*
++ * Compatible function
++ * used for preloader/lk/kernel environment
++ */
++#include "nandx_os.h"
++#include "nandx_errno.h"
++
++#ifndef BIT
++#define BIT(a)                  (1 << (a))
++#endif
++
++#ifndef min_t
++#define min_t(type, x, y) ({                    \
++	type __min1 = (x);                      \
++	type __min2 = (y);                      \
++	__min1 < __min2 ? __min1 : __min2; })
++
++#define max_t(type, x, y) ({                    \
++	type __max1 = (x);                      \
++	type __max2 = (y);                      \
++	__max1 > __max2 ? __max1 : __max2; })
++#endif
++
++#ifndef GENMASK
++#define GENMASK(h, l) \
++	(((~0UL) << (l)) & (~0UL >> ((sizeof(unsigned long) * 8) - 1 - (h))))
++#endif
++
++#ifndef __weak
++#define __weak __attribute__((__weak__))
++#endif
++
++#ifndef __packed
++#define __packed __attribute__((__packed__))
++#endif
++
++#ifndef KB
++#define KB(x)   ((x) << 10)
++#define MB(x)   (KB(x) << 10)
++#define GB(x)   (MB(x) << 10)
++#endif
++
++#ifndef offsetof
++#define offsetof(type, member) ((size_t)&((type *)0)->member)
++#endif
++
++#ifndef NULL
++#define NULL (void *)0
++#endif
++static inline u32 nandx_popcount(u32 x)
++{
++	x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
++	x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
++	x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
++	x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
++	x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
++
++	return x;
++}
++
++#ifndef zero_popcount
++#define zero_popcount(x) (32 - nandx_popcount(x))
++#endif
++
++#ifndef do_div
++#define do_div(n, base) \
++	({ \
++		u32 __base = (base); \
++		u32 __rem; \
++		__rem = ((u64)(n)) % __base; \
++		(n) = ((u64)(n)) / __base; \
++		__rem; \
++	})
++#endif
++
++#define div_up(x, y) \
++	({ \
++		u64 __temp = ((x) + (y) - 1); \
++		do_div(__temp, (y)); \
++		__temp; \
++	})
++
++#define div_down(x, y) \
++	({ \
++		u64 __temp = (x); \
++		do_div(__temp, (y)); \
++		__temp; \
++	})
++
++#define div_round_up(x, y)      (div_up(x, y) * (y))
++#define div_round_down(x, y)    (div_down(x, y) * (y))
++
++#define reminder(x, y) \
++	({ \
++		u64 __temp = (x); \
++		do_div(__temp, (y)); \
++	})
++
++#ifndef round_up
++#define round_up(x, y)          ((((x) - 1) | ((y) - 1)) + 1)
++#define round_down(x, y)        ((x) & ~((y) - 1))
++#endif
++
++#ifndef readx_poll_timeout_atomic
++#define readx_poll_timeout_atomic(op, addr, val, cond, delay_us, timeout_us) \
++	({ \
++		u64 end = get_current_time_us() + timeout_us; \
++		for (;;) { \
++			u64 now = get_current_time_us(); \
++			(val) = op(addr); \
++			if (cond) \
++				break; \
++			if (now > end) { \
++				(val) = op(addr); \
++				break; \
++			} \
++		} \
++		(cond) ? 0 : -ETIMEDOUT; \
++	})
++
++#define readl_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readl, addr, val, cond, delay_us, timeout_us)
++#define readw_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readw, addr, val, cond, delay_us, timeout_us)
++#define readb_poll_timeout_atomic(addr, val, cond, delay_us, timeout_us) \
++	readx_poll_timeout_atomic(readb, addr, val, cond, delay_us, timeout_us)
++#endif
++
++struct nandx_split64 {
++	u64 head;
++	size_t head_len;
++	u64 body;
++	size_t body_len;
++	u64 tail;
++	size_t tail_len;
++};
++
++struct nandx_split32 {
++	u32 head;
++	u32 head_len;
++	u32 body;
++	u32 body_len;
++	u32 tail;
++	u32 tail_len;
++};
++
++#define nandx_split(split, offset, len, val, align) \
++	do { \
++		(split)->head = (offset); \
++		(val) = div_round_down((offset), (align)); \
++		(val) = (align) - ((offset) - (val)); \
++		if ((val) == (align)) \
++			(split)->head_len = 0; \
++		else if ((val) > (len)) \
++			(split)->head_len = len; \
++		else \
++			(split)->head_len = val; \
++		(split)->body = (offset) + (split)->head_len; \
++		(split)->body_len = div_round_down((len) - \
++						   (split)->head_len,\
++						   (align)); \
++		(split)->tail = (split)->body + (split)->body_len; \
++		(split)->tail_len = (len) - (split)->head_len - \
++				    (split)->body_len; \
++	} while (0)
++
++#ifndef container_of
++#define container_of(ptr, type, member) \
++	({const __typeof__(((type *)0)->member) * __mptr = (ptr); \
++		(type *)((char *)__mptr - offsetof(type, member)); })
++#endif
++
++static inline u32 nandx_cpu_to_be32(u32 val)
++{
++	u32 temp = 1;
++	u8 *p_temp = (u8 *)&temp;
++
++	if (*p_temp)
++		return ((val & 0xff) << 24) | ((val & 0xff00) << 8) |
++		       ((val >> 8) & 0xff00) | ((val >> 24) & 0xff);
++
++	return val;
++}
++
++static inline void nandx_set_bits32(unsigned long addr, u32 mask,
++				    u32 val)
++{
++	u32 temp = readl((void *)addr);
++
++	temp &= ~(mask);
++	temp |= val;
++	writel(temp, (void *)addr);
++}
++
++#endif /* __NANDX_UTIL_H__ */
+diff --git a/drivers/mtd/nandx/include/uboot/nandx_os.h b/drivers/mtd/nandx/include/uboot/nandx_os.h
+new file mode 100644
+index 0000000000..8ea53378bf
+--- /dev/null
++++ b/drivers/mtd/nandx/include/uboot/nandx_os.h
+@@ -0,0 +1,78 @@
++/*
++ * Copyright (C) 2017 MediaTek Inc.
++ * Licensed under either
++ *     BSD Licence, (see NOTICE for more details)
++ *     GNU General Public License, version 2.0, (see NOTICE for more details)
++ */
++
++#ifndef __NANDX_OS_H__
++#define __NANDX_OS_H__
++
++#include <common.h>
++#include <dm.h>
++#include <clk.h>
++#include <asm/dma-mapping.h>
++#include <linux/io.h>
++#include <linux/err.h>
++#include <linux/errno.h>
++#include <linux/bitops.h>
++#include <linux/kernel.h>
++#include <linux/compiler-gcc.h>
++
++#define NANDX_BULK_IO_USE_DRAM 0
++
++#define nandx_event_create()     NULL
++#define nandx_event_destroy(event)
++#define nandx_event_complete(event)
++#define nandx_event_init(event)
++#define nandx_event_wait_complete(event, timeout)        true
++
++#define nandx_irq_register(dev, irq, irq_handler, name, data)	NULL
++
++static inline void *mem_alloc(u32 count, u32 size)
++{
++	return kmalloc(count * size, GFP_KERNEL | __GFP_ZERO);
++}
++
++static inline void mem_free(void *mem)
++{
++	kfree(mem);
++}
++
++static inline u64 get_current_time_us(void)
++{
++	return timer_get_us();
++}
++
++static inline u32 nandx_dma_map(void *dev, void *buf, u64 len,
++				enum nand_dma_operation op)
++{
++	unsigned long addr = (unsigned long)buf;
++	u64 size;
++
++	size = ALIGN(len, ARCH_DMA_MINALIGN);
++
++	if (op == NDMA_FROM_DEV)
++		invalidate_dcache_range(addr, addr + size);
++	else
++		flush_dcache_range(addr, addr + size);
++
++	return addr;
++}
++
++static inline void nandx_dma_unmap(void *dev, void *buf, void *addr,
++				   u64 len, enum nand_dma_operation op)
++{
++	u64 size;
++
++	size = ALIGN(len, ARCH_DMA_MINALIGN);
++
++	if (op != NDMA_FROM_DEV)
++		invalidate_dcache_range((unsigned long)addr, addr + size);
++	else
++		flush_dcache_range((unsigned long)addr, addr + size);
++
++	return addr;
++}
++
++#endif /* __NANDX_OS_H__ */
+diff --git a/include/configs/mt7622.h b/include/configs/mt7622.h
+index dfd506ed24..6d0c956484 100644
+--- a/include/configs/mt7622.h
++++ b/include/configs/mt7622.h
+@@ -11,6 +11,31 @@
+ 
+ #include <linux/sizes.h>
+ 
++/* SPI Nand */
++#if defined(CONFIG_MTD_RAW_NAND)
++#define CONFIG_SYS_MAX_NAND_DEVICE 1
++#define CONFIG_SYS_NAND_BASE		0x1100d000
++
++#define ENV_BOOT_READ_IMAGE \
++	"boot_rd_img=" \
++	"nand read 0x4007ff28 0x380000 0x1400000" \
++	";iminfo 0x4007ff28 \0"
++
++#define ENV_BOOT_WRITE_IMAGE \
++	"boot_wr_img=" \
++	"nand write 0x4007ff28 0x380000 0x1400000" \
++	";iminfo 0x4007ff28 \0"
++
++#define ENV_BOOT_CMD \
++	"mtk_boot=run boot_rd_img;bootm;\0"
++
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	ENV_BOOT_READ_IMAGE \
++	ENV_BOOT_CMD \
++	"bootcmd=run mtk_boot;\0"
++
++#endif
++
+ #define CONFIG_SYS_MAXARGS		8
+ #define CONFIG_SYS_BOOTM_LEN		SZ_64M
+ #define CONFIG_SYS_CBSIZE		SZ_1K
+-- 
+2.17.1
+
diff --git a/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch b/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch
new file mode 100644
index 0000000..2c021e1
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/003-mt7622-uboot-add-dts-and-config-for-spi-nand.patch
@@ -0,0 +1,64 @@
+From b1b3c3d2ce62872c8dec4a7d645af6b3c565e094 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Mon, 20 Apr 2020 17:11:32 +0800
+Subject: [PATCH 2/3] mt7622 uboot: add dts and config for spi nand
+
+This patch add dts and config for mt7622 spi nand
+
+Signed-off-by: Xiangsheng Hou <xiangsheng.hou@mediatek.com>
+---
+ arch/arm/dts/mt7622-rfb.dts |  6 ++++++
+ arch/arm/dts/mt7622.dtsi    | 20 ++++++++++++++++++++
+ 2 files changed, 26 insertions(+)
+
+diff --git a/arch/arm/dts/mt7622-rfb.dts b/arch/arm/dts/mt7622-rfb.dts
+index f05c3fe14d..05502bddec 100644
+--- a/arch/arm/dts/mt7622-rfb.dts
++++ b/arch/arm/dts/mt7622-rfb.dts
+@@ -143,6 +143,12 @@
+ 	};
+ };
+ 
++&nandc {
++	pinctrl-names = "default";
++	pinctrl-0 = <&snfi_pins>;
++	status = "okay";
++};
++
+ &uart0 {
+ 	pinctrl-names = "default";
+ 	pinctrl-0 = <&uart0_pins>;
+diff --git a/arch/arm/dts/mt7622.dtsi b/arch/arm/dts/mt7622.dtsi
+index 1e8ec9b48b..63fdb63d4a 100644
+--- a/arch/arm/dts/mt7622.dtsi
++++ b/arch/arm/dts/mt7622.dtsi
+@@ -52,6 +52,26 @@
+ 		#size-cells = <0>;
+ 	};
+ 
++	nandc: nfi@1100d000 {
++		compatible = "mediatek,mt7622-nfc";
++		reg = <0x1100d000 0x1000>,
++		      <0x1100e000 0x1000>;
++		interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_LOW>,
++			     <GIC_SPI 95 IRQ_TYPE_LEVEL_LOW>;
++		clocks = <&pericfg CLK_PERI_NFI_PD>,
++			 <&pericfg CLK_PERI_NFIECC_PD>,
++			 <&pericfg CLK_PERI_SNFI_PD>,
++			 <&topckgen CLK_TOP_NFI_INFRA_SEL>,
++			 <&topckgen CLK_TOP_UNIVPLL2_D8>;
++		clock-names = "nfi_clk",
++			      "ecc_clk",
++			      "snfi_clk",
++			      "spinfi_sel",
++			      "spinfi_parent_50m";
++		nand-ecc-mode = "hw";
++		status = "disabled";
++	};
++
+ 	timer {
+ 		compatible = "arm,armv8-timer";
+ 		interrupt-parent = <&gic>;
+-- 
+2.17.1
+
diff --git a/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch b/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch
new file mode 100644
index 0000000..cb56496
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/004-configs-enable-mtd-and-mtk_spi_nand-in-defconfig.patch
@@ -0,0 +1,39 @@
+From e5745143a2984cf44fbfc0b3aedb49e57873f109 Mon Sep 17 00:00:00 2001
+From: Sam Shih <sam.shih@mediatek.com>
+Date: Mon, 20 Apr 2020 17:17:04 +0800
+Subject: [PATCH 3/3] configs: enable mtd and mtk_spi_nand in defconfig
+
+This patch enable mtk and mtk_spi_nand in mt7622_rfb defconfig
+
+Signed-off-by: Sam Shih <sam.shih@mediatek.com>
+---
+ configs/mt7622_rfb_defconfig | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/configs/mt7622_rfb_defconfig b/configs/mt7622_rfb_defconfig
+index 1ce6ebdfeb..816126267b 100644
+--- a/configs/mt7622_rfb_defconfig
++++ b/configs/mt7622_rfb_defconfig
+@@ -13,6 +13,7 @@ CONFIG_DEFAULT_FDT_FILE="mt7622-rfb"
+ CONFIG_SYS_PROMPT="MT7622> "
+ CONFIG_CMD_BOOTMENU=y
+ CONFIG_CMD_MMC=y
++CONFIG_CMD_NAND=y
+ CONFIG_CMD_PCI=y
+ CONFIG_CMD_SF_TEST=y
+ CONFIG_CMD_PING=y
+ CONFIG_CMD_SMC=y
+@@ -25,6 +26,10 @@ CONFIG_CLK=y
+ CONFIG_DM_MMC=y
+ CONFIG_MMC_HS200_SUPPORT=y
+ CONFIG_MMC_MTK=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_MTK_SPI_NAND=y
++CONFIG_MTD_RAW_NAND=y
+ CONFIG_DM_SPI_FLASH=y
+ CONFIG_SPI_FLASH_EON=y
+ CONFIG_SPI_FLASH_GIGADEVICE=y
+-- 
+2.17.1
+
diff --git a/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch b/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch
new file mode 100644
index 0000000..cc7ed89
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/005-update-bpir2-defconfig.patch
@@ -0,0 +1,17 @@
+diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig
+index 6b9fbd7e22..fb2a004803 100644
+--- a/configs/mt7623n_bpir2_defconfig
++++ b/configs/mt7623n_bpir2_defconfig
+@@ -52,3 +52,13 @@ CONFIG_TIMER=y
+ CONFIG_WDT_MTK=y
+ CONFIG_LZMA=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_OF_LIBFDT_OVERLAY=y
++#enables savenenv-command
++CONFIG_ENV_IS_IN_FAT=y
++CONFIG_ENV_FAT_INTERFACE="mmc"
++CONFIG_ENV_FAT_DEVICE_AND_PART=":2"
++CONFIG_ENV_FAT_FILE="uboot.env"
++CONFIG_CMD_ASKENV=y
++CONFIG_ENV_SIZE=0x2000
++CONFIG_CMD_SETEXPR=y
diff --git a/package/boot/uboot-mediatek/patches/010-no-binman.patch b/package/boot/uboot-mediatek/patches/010-no-binman.patch
new file mode 100644
index 0000000..a2680e5
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/010-no-binman.patch
@@ -0,0 +1,23 @@
+--- a/Makefile	2020-10-13 13:39:06.471438591 +0800
++++ b/Makefile	2020-10-13 13:39:39.190798462 +0800
+@@ -1725,6 +1725,10 @@
+ 
+ ifeq ($(CONFIG_SPL),y)
+ spl/u-boot-spl-mtk.bin: spl/u-boot-spl
++OBJCOPYFLAGS_u-boot-mtk.bin = -I binary -O binary \
++			--pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
++u-boot-mtk.bin: u-boot.img spl/u-boot-spl-mtk.bin FORCE
++	$(call if_changed,pad_cat)
+ else
+ MKIMAGEFLAGS_u-boot-mtk.bin = -T mtk_image \
+ 	-a $(CONFIG_SYS_TEXT_BASE) -e $(CONFIG_SYS_TEXT_BASE) \
+--- a/arch/arm/mach-mediatek/Kconfig
++++ b/arch/arm/mach-mediatek/Kconfig
+@@ -36,7 +36,6 @@ config TARGET_MT7629
+ 	bool "MediaTek MT7629 SoC"
+ 	select CPU_V7A
+ 	select SPL
+-	select BINMAN
+ 	help
+ 	  The MediaTek MT7629 is a ARM-based SoC with a dual-core Cortex-A7
+ 	  including DDR3, crypto engine, 3x3 11n/ac Wi-Fi, Gigabit Ethernet,
diff --git a/package/boot/uboot-mediatek/patches/010-update-u7623-defconfig.patch b/package/boot/uboot-mediatek/patches/010-update-u7623-defconfig.patch
new file mode 100644
index 0000000..ec189f8
--- /dev/null
+++ b/package/boot/uboot-mediatek/patches/010-update-u7623-defconfig.patch
@@ -0,0 +1,17 @@
+diff --git a/configs/mt7623n_bpir2_defconfig b/configs/mt7623n_bpir2_defconfig
+index 6b9fbd7e22..fb2a004803 100644
+--- a/configs/mt7623a_unielec_u7623_02_defconfig
++++ b/configs/mt7623a_unielec_u7623_02_defconfig
+@@ -52,3 +52,12 @@ CONFIG_TIMER=y
+ CONFIG_MTK_TIMER=y
+ CONFIG_WDT_MTK=y
+ CONFIG_LZMA=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_OF_LIBFDT_OVERLAY=y
++#enables savenenv-command
++CONFIG_ENV_IS_IN_FAT=y
++CONFIG_ENV_FAT_INTERFACE="mmc"
++CONFIG_ENV_FAT_DEVICE_AND_PART="0:2"
++CONFIG_ENV_FAT_FILE="uboot.env"
++CONFIG_CMD_ASKENV=y
++CONFIG_CMD_SETEXPR=y
diff --git a/package/boot/uboot-mmp/Makefile b/package/boot/uboot-mmp/Makefile
new file mode 100755
index 0000000..cbc1258
--- /dev/null
+++ b/package/boot/uboot-mmp/Makefile
@@ -0,0 +1,149 @@
+#
+# Copyright (C) 2012 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+
+PKG_NAME:=u-boot
+PKG_VERSION:=2014
+PKG_RELEASE:=1
+
+USE_SOURCE_DIR:=$(MRVLDIR)/uboot
+PKG_SOURCE_SUBDIR:=$(PKG_NAME)-$(PKG_VERSION)
+PKG_BUILD_DIR:=$(BUILD_DIR)/$(PKG_NAME)-$(BUILD_VARIANT)/$(PKG_NAME)-$(PKG_VERSION)
+
+include $(INCLUDE_DIR)/package.mk
+
+define uboot/Default
+  TITLE:=U-Boot for Marvell MMP SOC
+  CONFIG:=
+  IMAGE:=
+endef
+
+define uboot/falcon_p401
+  TITLE:=U-Boot for ASR 1803 profile 401
+  DEPS:=@TARGET_mmp_asr1803_FALCON401
+endef
+
+define uboot/falcon_p403
+  TITLE:=U-Boot for ASR 1803 profile 403
+  DEPS:=@TARGET_mmp_asr1803_FALCON403
+endef
+
+define uboot/fact_p301
+  TITLE:=U-Boot for ASR 1806 profile 301
+  DEPS:=@TARGET_mmp_asr1806_FACT301
+endef
+
+define uboot/fact_p306
+  TITLE:=U-Boot for ASR 1806 profile 306
+  DEPS:=@TARGET_mmp_asr1806_FACT306
+endef
+
+define uboot/kagu_p801
+  TITLE:=U-Boot for ASR 1828 profile 801
+  DEPS:=@TARGET_mmp_asr1828_KAGU801
+endef
+
+define uboot/kstr_p901
+  TITLE:=U-Boot for ASR 1901 profile 901
+  DEPS:=@TARGET_mmp_asr1901_KSTR901
+endef
+
+define uboot/kstrz_p906
+  TITLE:=U-Boot for ASR 1906 profile 906
+  DEPS:=@TARGET_mmp_asr1906_KSTRZ906
+endef
+
+define uboot/lapw_p501
+  TITLE:=U-Boot for ASR 1903 profile 501
+  DEPS:=@TARGET_mmp_asr1903_LAPW501
+endef
+
+define uboot/lapw_p503
+  TITLE:=U-Boot for ASR 1903 profile 503
+  DEPS:=@TARGET_mmp_asr1903_LAPW503
+endef
+
+UBOOTS:=falcon_p401 falcon_p403 kagu_p801 kstr_p901 \
+	fact_p301 fact_p306 kstrz_p906 lapw_p501 lapw_p503
+
+define Package/uboot/template
+define Package/uboot-mmp-$(1)
+  SECTION:=boot
+  CATEGORY:=Boot Loaders
+  DEPENDS:=$(3)
+  TITLE:=$(2)
+  URL:=http://www.denx.de/wiki/U-Boot
+  VARIANT:=$(1)
+endef
+endef
+
+define BuildUBootPackage
+	$(eval $(uboot/Default))
+	$(eval $(uboot/$(1)))
+	DEPS:=$(uboot/$(1)/DEPS)
+	$(call Package/uboot/template,$(1),$(TITLE),$(DEPS))
+endef
+
+ifdef BUILD_VARIANT
+$(eval $(call uboot/$(BUILD_VARIANT)))
+UBOOT_CONFIG:=$(if $(CONFIG),$(CONFIG),$(BUILD_VARIANT))
+UBOOT_IMAGE:=$(if $(IMAGE),$(IMAGE),openwrt-$(BOARD)-$(BUILD_VARIANT)-u-boot.bin)
+endif
+
+define Build/Configure
+	@if [ -d $(PKG_BUILD_DIR) ]; then \
+		$(MAKE) CONFIG_SECURE_DM=$(CONFIG_SECURE_DM) CONFIG_SECURE_IMA=$(CONFIG_SECURE_IMA) \
+			CONFIG_HARDWARE_AES_ENGINE=$(CONFIG_HARDWARE_AES_ENGINE) CONFIG_SECURE_DM_CRYPT=$(CONFIG_SECURE_DM_CRYPT) \
+			-C $(PKG_BUILD_DIR) \
+			distclean \
+			CROSS_COMPILE=$(TARGET_CROSS); \
+	fi
+	$(MAKE) CONFIG_SECURE_DM=$(CONFIG_SECURE_DM) CONFIG_SECURE_IMA=$(CONFIG_SECURE_IMA) \
+		CONFIG_HARDWARE_AES_ENGINE=$(CONFIG_HARDWARE_AES_ENGINE) CONFIG_SECURE_DM_CRYPT=$(CONFIG_SECURE_DM_CRYPT) \
+		-C $(PKG_BUILD_DIR) $(UBOOT_CONFIG) \
+		CROSS_COMPILE=$(TARGET_CROSS)
+endef
+
+define Build/Compile
+	$(MAKE) CONFIG_SECURE_DM=$(CONFIG_SECURE_DM) CONFIG_SECURE_IMA=$(CONFIG_SECURE_IMA) \
+		CONFIG_HARDWARE_AES_ENGINE=$(CONFIG_HARDWARE_AES_ENGINE) CONFIG_SECURE_DM_CRYPT=$(CONFIG_SECURE_DM_CRYPT) \
+		-C $(PKG_BUILD_DIR) \
+		u-boot.bin \
+		CROSS_COMPILE=$(TARGET_CROSS)
+endef
+
+define Build/Clean
+	@if [ -d $(PKG_BUILD_DIR) ]; then \
+		$(MAKE) CONFIG_SECURE_DM=$(CONFIG_SECURE_DM) CONFIG_SECURE_IMA=$(CONFIG_SECURE_IMA) \
+			CONFIG_HARDWARE_AES_ENGINE=$(CONFIG_HARDWARE_AES_ENGINE) CONFIG_SECURE_DM_CRYPT=$(CONFIG_SECURE_DM_CRYPT) \
+			-C $(PKG_BUILD_DIR) \
+			distclean \
+			CROSS_COMPILE=$(TARGET_CROSS); \
+	fi
+endef
+
+define Package/uboot/install/default
+	$(INSTALL_DIR) $(BIN_DIR)
+	$(CP) $(PKG_BUILD_DIR)/u-boot.bin \
+		$(BIN_DIR)/openwrt-$(BOARD)-$(ARCH_PACKAGES)-u-boot.bin
+endef
+
+define Package/uboot/install/template
+define Package/uboot-mmp-$(1)/install
+	$(call Package/uboot/install/default)
+endef
+endef
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call Package/uboot/install/template,$(u))) \
+)
+
+$(foreach u,$(UBOOTS), \
+	$(eval $(call BuildUBootPackage,$(u))) \
+	$(eval $(call BuildPackage,uboot-mmp-$(u))) \
+)
diff --git a/package/boot/uboot-mvebu/Makefile b/package/boot/uboot-mvebu/Makefile
new file mode 100644
index 0000000..37e93d1
--- /dev/null
+++ b/package/boot/uboot-mvebu/Makefile
@@ -0,0 +1,74 @@
+#
+# Copyright (C) 2016 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)/kernel.mk
+
+PKG_VERSION:=2021.01
+PKG_RELEASE:=1
+
+PKG_HASH:=b407e1510a74e863b8b5cb42a24625344f0e0c2fc7582d8c866bd899367d0454
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=mvebu
+  HIDDEN:=1
+endef
+
+define U-Boot/clearfog
+  NAME:=SolidRun ClearFog A1
+  BUILD_DEVICES:=solidrun_clearfog-base-a1 solidrun_clearfog-pro-a1
+  BUILD_SUBTARGET:=cortexa9
+  UBOOT_IMAGE:=u-boot-spl.kwb
+endef
+
+define U-Boot/helios4
+  NAME:=Kobol Helios 4
+  BUILD_DEVICES:=kobol_helios4
+  BUILD_SUBTARGET:=cortexa9
+  UBOOT_IMAGE:=u-boot-spl.kwb
+endef
+
+define U-Boot/espressobin
+  NAME:=Marvell ESPRESSObin
+  BUILD_SUBTARGET:=cortexa53
+  UBOOT_CONFIG:=mvebu_espressobin-88f3720
+endef
+
+define U-Boot/uDPU
+  NAME:=Methode uDPU
+  BUILD_SUBTARGET:=cortexa53
+endef
+
+UBOOT_TARGETS:= \
+	clearfog \
+	helios4 \
+	espressobin \
+	uDPU
+
+Build/Exports:=$(Host/Exports)
+
+define Build/Configure
+	# enable additional options beyond <device>_defconfig
+	echo CONFIG_CMD_SETEXPR=y >> $(PKG_BUILD_DIR)/configs/$(UBOOT_CONFIG)_defconfig
+
+	$(call Build/Configure/U-Boot)
+endef
+
+define Package/u-boot/install
+	$(if $(findstring cortexa53,$(BUILD_SUBTARGET)),,$(Package/u-boot/install/default))
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-mvebu/patches/210-link-libcrypto-static.patch b/package/boot/uboot-mvebu/patches/210-link-libcrypto-static.patch
new file mode 100644
index 0000000..eb0b05e
--- /dev/null
+++ b/package/boot/uboot-mvebu/patches/210-link-libcrypto-static.patch
@@ -0,0 +1,14 @@
+OpenWrt links the libressl statically against mkimage, make sure all the 
+needed dependencies are added too.
+
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -158,7 +158,7 @@ ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CON
+ HOSTCFLAGS_kwbimage.o += \
+ 	$(shell pkg-config --cflags libssl libcrypto 2> /dev/null || echo "")
+ HOSTLDLIBS_mkimage += \
+-	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
++	$(shell pkg-config --libs --static libssl libcrypto 2> /dev/null || echo "-lssl -lpthread -lcrypto")
+ 
+ # OS X deprecate openssl in favour of CommonCrypto, supress deprecation
+ # warnings on those systems
diff --git a/package/boot/uboot-mxs/Makefile b/package/boot/uboot-mxs/Makefile
new file mode 100644
index 0000000..2a202dc
--- /dev/null
+++ b/package/boot/uboot-mxs/Makefile
@@ -0,0 +1,48 @@
+#
+# Copyright (C) 2013-2016 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)/kernel.mk
+
+PKG_VERSION:=2020.04
+PKG_RELEASE:=1
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=mxs
+  UBOOT_IMAGE:=u-boot.sb
+  DEFAULT:=y
+  HIDDEN:=1
+endef
+
+define U-Boot/mx23_olinuxino
+  NAME:=Olinuxino i.MX233
+endef
+
+define U-Boot/duckbill
+  NAME:=I2SE Duckbill
+endef
+
+UBOOT_TARGETS := \
+	mx23_olinuxino \
+	duckbill
+
+UBOOT_MAKE_FLAGS += $(UBOOT_IMAGE)
+
+Build/Exports:=$(Host/Exports)
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-$(UBOOT_IMAGE)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-mxs/patches/001-add-i2se-duckbill.patch b/package/boot/uboot-mxs/patches/001-add-i2se-duckbill.patch
new file mode 100644
index 0000000..50702cb
--- /dev/null
+++ b/package/boot/uboot-mxs/patches/001-add-i2se-duckbill.patch
@@ -0,0 +1,705 @@
+From 83ee930c18b068c9a16b66c01aaa5d6e06570152 Mon Sep 17 00:00:00 2001
+From: Michael Heimpold <mhei@heimpold.de>
+Date: Sun, 19 Apr 2020 02:46:46 +0200
+Subject: [PATCH] arm: mxs: add support for I2SE's Duckbill boards
+
+The Duckbill devices are small, pen-drive sized boards based on
+NXP's i.MX28 SoC. While the initial variants (Duckbill series) were
+equipped with a micro SD card slot only, the latest generation
+(Duckbill 2 series) have an additional internal eMMC onboard.
+
+Both device generations consist of four "family members":
+
+- Duckbill/Duckbill 2: generic board, intended to be used as
+  baseboard for custom designs and/or as development board
+
+- Duckbill EnOcean/Duckbill 2 EnOcean: come with an EnOcean
+  daugther board equipped with the popular TCM310 module
+
+- Duckbill 485/Duckbill 2 485: as the name implies, these
+  devices are intended to be used as Ethernet - RS485 converters
+
+- Duckbill SPI/Duckbill 2 SPI: not sold separately, but used
+  in I2SE's development kits for Green PHY HomePlug Powerline
+  communication
+
+Signed-off-by: Michael Heimpold <mhei@heimpold.de>
+Signed-off-by: Stefan Wahren <stefan.wahren@i2se.com>
+---
+ arch/arm/mach-imx/mxs/Kconfig   |   5 +
+ board/i2se/duckbill/Kconfig     |  15 +++
+ board/i2se/duckbill/MAINTAINERS |   6 +
+ board/i2se/duckbill/Makefile    |  10 ++
+ board/i2se/duckbill/duckbill.c  | 189 ++++++++++++++++++++++++++++++++
+ board/i2se/duckbill/iomux.c     | 157 ++++++++++++++++++++++++++
+ configs/duckbill_defconfig      |  43 ++++++++
+ include/configs/duckbill.h      | 172 +++++++++++++++++++++++++++++
+ 8 files changed, 597 insertions(+)
+ create mode 100644 board/i2se/duckbill/Kconfig
+ create mode 100644 board/i2se/duckbill/MAINTAINERS
+ create mode 100644 board/i2se/duckbill/Makefile
+ create mode 100644 board/i2se/duckbill/duckbill.c
+ create mode 100644 board/i2se/duckbill/iomux.c
+ create mode 100644 configs/duckbill_defconfig
+ create mode 100644 include/configs/duckbill.h
+
+diff --git a/arch/arm/mach-imx/mxs/Kconfig b/arch/arm/mach-imx/mxs/Kconfig
+index b90d7b6e41..e7d8bc6792 100644
+--- a/arch/arm/mach-imx/mxs/Kconfig
++++ b/arch/arm/mach-imx/mxs/Kconfig
+@@ -50,6 +50,10 @@ config TARGET_APX4DEVKIT
+ config TARGET_BG0900
+ 	bool "Support bg0900"
+ 
++config TARGET_DUCKBILL
++	bool "Support duckbill"
++	select BOARD_EARLY_INIT_F
++
+ config TARGET_MX28EVK
+ 	bool "Support mx28evk"
+ 	select BOARD_EARLY_INIT_F
+@@ -70,6 +74,7 @@ config SYS_SOC
+ 
+ source "board/bluegiga/apx4devkit/Kconfig"
+ source "board/freescale/mx28evk/Kconfig"
++source "board/i2se/duckbill/Kconfig"
+ source "board/liebherr/xea/Kconfig"
+ source "board/ppcag/bg0900/Kconfig"
+ source "board/schulercontrol/sc_sps_1/Kconfig"
+diff --git a/board/i2se/duckbill/Kconfig b/board/i2se/duckbill/Kconfig
+new file mode 100644
+index 0000000000..98c1e4689f
+--- /dev/null
++++ b/board/i2se/duckbill/Kconfig
+@@ -0,0 +1,15 @@
++if TARGET_DUCKBILL
++
++config SYS_BOARD
++	default "duckbill"
++
++config SYS_VENDOR
++	default "i2se"
++
++config SYS_SOC
++	default "mxs"
++
++config SYS_CONFIG_NAME
++	default "duckbill"
++
++endif
+diff --git a/board/i2se/duckbill/MAINTAINERS b/board/i2se/duckbill/MAINTAINERS
+new file mode 100644
+index 0000000000..5496baa330
+--- /dev/null
++++ b/board/i2se/duckbill/MAINTAINERS
+@@ -0,0 +1,6 @@
++I2SE DUCKBILL BOARD
++M:	Michael Heimpold <mhei@heimpold.de>
++S:	Maintained
++F:	board/i2se/duckbill/
++F:	include/configs/duckbill.h
++F:	configs/duckbill_defconfig
+diff --git a/board/i2se/duckbill/Makefile b/board/i2se/duckbill/Makefile
+new file mode 100644
+index 0000000000..11bac98e4c
+--- /dev/null
++++ b/board/i2se/duckbill/Makefile
+@@ -0,0 +1,10 @@
++# SPDX-License-Identifier: GPL-2.0+
++#
++# (C) Copyright 2014-2020
++# Michael Heimpold, mhei@heimpold.de.
++
++ifndef	CONFIG_SPL_BUILD
++obj-y	:= duckbill.o
++else
++obj-y	:= iomux.o
++endif
+diff --git a/board/i2se/duckbill/duckbill.c b/board/i2se/duckbill/duckbill.c
+new file mode 100644
+index 0000000000..93defc6c28
+--- /dev/null
++++ b/board/i2se/duckbill/duckbill.c
+@@ -0,0 +1,189 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * I2SE Duckbill board
++ *
++ * Copyright (C) 2014-2020 Michael Heimpold <mhei@heimpold.de>
++ */
++
++#include <common.h>
++#include <asm/gpio.h>
++#include <asm/io.h>
++#include <asm/arch/imx-regs.h>
++#include <asm/arch/iomux-mx28.h>
++#include <asm/arch/clock.h>
++#include <asm/arch/sys_proto.h>
++#include <asm/setup.h>
++#include <fdt_support.h>
++#include <linux/mii.h>
++#include <miiphy.h>
++#include <netdev.h>
++#include <errno.h>
++#include <fuse.h>
++
++DECLARE_GLOBAL_DATA_PTR;
++
++static u32 system_rev;
++static u32 serialno;
++
++/*
++ * Functions
++ */
++int board_early_init_f(void)
++{
++	/* IO0 clock at 480MHz */
++	mxs_set_ioclk(MXC_IOCLK0, 480000);
++	/* IO1 clock at 480MHz */
++	mxs_set_ioclk(MXC_IOCLK1, 480000);
++
++	/* SSP0 clock at 96MHz */
++	mxs_set_sspclk(MXC_SSPCLK0, 96000, 0);
++
++	return 0;
++}
++
++int dram_init(void)
++{
++	return mxs_dram_init();
++}
++
++int board_init(void)
++{
++	/* Adress of boot parameters */
++	gd->bd->bi_boot_params = PHYS_SDRAM_1 + 0x100;
++
++	return 0;
++}
++
++#ifdef CONFIG_CMD_MMC
++int board_mmc_init(bd_t *bis)
++{
++	return mxsmmc_initialize(bis, 0, NULL, NULL);
++}
++#endif
++
++#ifdef CONFIG_CMD_NET
++int board_eth_init(bd_t *bis)
++{
++	unsigned int reset_gpio;
++	int ret;
++
++	ret = cpu_eth_init(bis);
++
++	if (system_rev == 1)
++		reset_gpio = MX28_PAD_SSP0_DATA7__GPIO_2_7;
++	else
++		reset_gpio = MX28_PAD_GPMI_ALE__GPIO_0_26;
++
++	/* Reset PHY */
++	gpio_request(reset_gpio, "enet0_phy_rst");
++	gpio_direction_output(reset_gpio, 0);
++	udelay(200);
++	gpio_set_value(reset_gpio, 1);
++
++	/* give PHY some time to get out of the reset */
++	udelay(10000);
++
++	ret = fecmxc_initialize_multi(bis, 0, 0, MXS_ENET0_BASE);
++	if (ret) {
++		puts("FEC MXS: Unable to init FEC\n");
++		return ret;
++	}
++
++	return ret;
++}
++
++void mx28_adjust_mac(int dev_id, unsigned char *mac)
++{
++	mac[0] = 0x00;
++	mac[1] = 0x01;
++	mac[2] = 0x87;
++}
++#endif
++
++#ifdef CONFIG_OF_BOARD_SETUP
++int ft_board_setup(void *blob, bd_t *bd)
++{
++	uint8_t enetaddr[6];
++	u32 mac = 0;
++
++#ifdef CONFIG_MXS_OCOTP
++	/* only Duckbill SPI has a MAC for the QCA7k */
++	fuse_read(0, 1, &mac);
++#endif
++
++	if (mac != 0) {
++		enetaddr[0] = 0x00;
++		enetaddr[1] = 0x01;
++		enetaddr[2] = 0x87;
++		enetaddr[3] = (mac >> 16) & 0xff;
++		enetaddr[4] = (mac >>  8) & 0xff;
++		enetaddr[5] =  mac        & 0xff;
++
++		fdt_find_and_setprop(blob, "spi1/ethernet@0",
++		                     "local-mac-address", enetaddr, 6, 1);
++	}
++
++	return 0;
++}
++#endif
++
++#ifdef CONFIG_REVISION_TAG
++u32 get_board_rev(void)
++{
++	return system_rev;
++}
++#endif
++
++#ifdef CONFIG_SERIAL_TAG
++void get_board_serial(struct tag_serialnr *serialnr)
++{
++	serialnr->low = serialno;
++	serialnr->high = 0;
++}
++#endif
++
++int misc_init_r(void)
++{
++	unsigned int led_red_gpio;
++	char *s;
++
++	/* Board revision detection */
++	gpio_request(MX28_PAD_LCD_D17__GPIO_1_17, "board_revision");
++	gpio_direction_input(MX28_PAD_LCD_D17__GPIO_1_17);
++
++	/* MX28_PAD_LCD_D17__GPIO_1_17: v1 = pull-down, v2 = pull-up */
++	system_rev =
++		gpio_get_value(MX28_PAD_LCD_D17__GPIO_1_17);
++	system_rev += 1;
++
++	/* guess DT blob if not set in environment */
++	if (!env_get("fdt_file")) {
++		if (system_rev == 1)
++			env_set("fdt_file", "imx28-duckbill.dtb");
++		else
++			env_set("fdt_file", "imx28-duckbill-2.dtb");
++	}
++
++	/* enable red LED to indicate a running bootloader */
++	if (system_rev == 1)
++		led_red_gpio = MX28_PAD_AUART1_RX__GPIO_3_4;
++	else
++		led_red_gpio = MX28_PAD_SAIF0_LRCLK__GPIO_3_21;
++	gpio_request(led_red_gpio, "led_red");
++	gpio_direction_output(led_red_gpio, 1);
++
++	if (system_rev == 1)
++		puts("Board: I2SE Duckbill\n");
++	else
++		puts("Board: I2SE Duckbill 2\n");
++
++	serialno = env_get_ulong("serial#", 10, 0);
++	s = env_get("serial#");
++	if (s && s[0]) {
++		puts("Serial: ");
++		puts(s);
++		putc('\n');
++	}
++
++	return 0;
++}
+diff --git a/board/i2se/duckbill/iomux.c b/board/i2se/duckbill/iomux.c
+new file mode 100644
+index 0000000000..c6cc211181
+--- /dev/null
++++ b/board/i2se/duckbill/iomux.c
+@@ -0,0 +1,157 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * I2SE Duckbill IOMUX setup
++ *
++ * Copyright (C) 2013-2020 Michael Heimpold <mhei@heimpold.de>
++ */
++
++#include <common.h>
++#include <config.h>
++#include <asm/io.h>
++#include <asm/gpio.h>
++#include <asm/arch/iomux-mx28.h>
++#include <asm/arch/imx-regs.h>
++#include <asm/arch/sys_proto.h>
++
++#define	MUX_CONFIG_SSP0	(MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP)
++#define	MUX_CONFIG_ENET	(MXS_PAD_3V3 | MXS_PAD_8MA | MXS_PAD_PULLUP)
++#define	MUX_CONFIG_EMI	(MXS_PAD_3V3 | MXS_PAD_12MA | MXS_PAD_NOPULL)
++
++/* For all revisions */
++const iomux_cfg_t iomux_setup[] = {
++	/* DUART */
++	MX28_PAD_PWM0__DUART_RX,
++	MX28_PAD_PWM1__DUART_TX,
++
++	/* eMMC (v2) or SD card (v1) */
++	MX28_PAD_SSP0_DATA0__SSP0_D0 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA1__SSP0_D1 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA2__SSP0_D2 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA3__SSP0_D3 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_CMD__SSP0_CMD | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DETECT__SSP0_CARD_DETECT |
++		(MXS_PAD_8MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
++	MX28_PAD_SSP0_SCK__SSP0_SCK |
++		(MXS_PAD_12MA | MXS_PAD_3V3 | MXS_PAD_NOPULL),
++
++	/* Ethernet */
++	MX28_PAD_ENET0_MDC__ENET0_MDC | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_MDIO__ENET0_MDIO | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_RX_EN__ENET0_RX_EN | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_TX_EN__ENET0_TX_EN | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_RXD0__ENET0_RXD0 | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_RXD1__ENET0_RXD1 | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_TXD0__ENET0_TXD0 | MUX_CONFIG_ENET,
++	MX28_PAD_ENET0_TXD1__ENET0_TXD1 | MUX_CONFIG_ENET,
++	MX28_PAD_ENET_CLK__CLKCTRL_ENET | MUX_CONFIG_ENET,
++
++	/* EMI */
++	MX28_PAD_EMI_D00__EMI_DATA0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D01__EMI_DATA1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D02__EMI_DATA2 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D03__EMI_DATA3 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D04__EMI_DATA4 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D05__EMI_DATA5 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D06__EMI_DATA6 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D07__EMI_DATA7 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D08__EMI_DATA8 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D09__EMI_DATA9 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D10__EMI_DATA10 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D11__EMI_DATA11 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D12__EMI_DATA12 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D13__EMI_DATA13 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D14__EMI_DATA14 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_D15__EMI_DATA15 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_ODT0__EMI_ODT0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DQM0__EMI_DQM0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_ODT1__EMI_ODT1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DQM1__EMI_DQM1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DDR_OPEN_FB__EMI_DDR_OPEN_FEEDBACK | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_CLK__EMI_CLK | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DQS0__EMI_DQS0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DQS1__EMI_DQS1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_DDR_OPEN__EMI_DDR_OPEN | MUX_CONFIG_EMI,
++
++	MX28_PAD_EMI_A00__EMI_ADDR0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A01__EMI_ADDR1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A02__EMI_ADDR2 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A03__EMI_ADDR3 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A04__EMI_ADDR4 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A05__EMI_ADDR5 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A06__EMI_ADDR6 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A07__EMI_ADDR7 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A08__EMI_ADDR8 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A09__EMI_ADDR9 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A10__EMI_ADDR10 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A11__EMI_ADDR11 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A12__EMI_ADDR12 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A13__EMI_ADDR13 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_A14__EMI_ADDR14 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_BA0__EMI_BA0 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_BA1__EMI_BA1 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_BA2__EMI_BA2 | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_CASN__EMI_CASN | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_RASN__EMI_RASN | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_WEN__EMI_WEN | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_CE0N__EMI_CE0N | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_CE1N__EMI_CE1N | MUX_CONFIG_EMI,
++	MX28_PAD_EMI_CKE__EMI_CKE | MUX_CONFIG_EMI,
++
++	/* Revision pin(s) */
++	MX28_PAD_LCD_D17__GPIO_1_17,
++};
++
++/* For revision 1 only */
++const iomux_cfg_t iomux_setup_v1[] = {
++	/* PHY reset */
++	MX28_PAD_SSP0_DATA7__GPIO_2_7 |
++		(MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
++
++	/* LEDs */
++	MX28_PAD_AUART1_RX__GPIO_3_4,
++	MX28_PAD_AUART1_TX__GPIO_3_5,
++};
++
++/* For revision 2 only */
++const iomux_cfg_t iomux_setup_v2[] = {
++	/* eMMC (v2) */
++	MX28_PAD_SSP0_DATA4__SSP0_D4 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA5__SSP0_D5 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA6__SSP0_D6 | MUX_CONFIG_SSP0,
++	MX28_PAD_SSP0_DATA7__SSP0_D7 | MUX_CONFIG_SSP0,
++
++	/* PHY reset */
++	MX28_PAD_GPMI_ALE__GPIO_0_26 |
++		(MXS_PAD_4MA | MXS_PAD_3V3 | MXS_PAD_PULLUP),
++
++	/* LEDs */
++	MX28_PAD_SAIF0_LRCLK__GPIO_3_21,
++	MX28_PAD_SAIF0_MCLK__GPIO_3_20,
++};
++
++#define HW_DRAM_CTL29	(0x74 >> 2)
++#define CS_MAP		0xf
++#define COLUMN_SIZE	0x2
++#define ADDR_PINS	0x1
++#define APREBIT		0xa
++
++#define HW_DRAM_CTL29_CONFIG	(CS_MAP << 24 | COLUMN_SIZE << 16 | \
++					ADDR_PINS << 8 | APREBIT)
++
++void mxs_adjust_memory_params(uint32_t *dram_vals)
++{
++	dram_vals[HW_DRAM_CTL29] = HW_DRAM_CTL29_CONFIG;
++}
++
++void board_init_ll(const uint32_t arg, const uint32_t *resptr)
++{
++	mxs_common_spl_init(arg, resptr, iomux_setup, ARRAY_SIZE(iomux_setup));
++
++	gpio_request(MX28_PAD_LCD_D17__GPIO_1_17, "board_revision");
++	gpio_direction_input(MX28_PAD_LCD_D17__GPIO_1_17);
++
++	if (gpio_get_value(MX28_PAD_LCD_D17__GPIO_1_17))
++		mxs_iomux_setup_multiple_pads(iomux_setup_v2, ARRAY_SIZE(iomux_setup_v2));
++	else
++		mxs_iomux_setup_multiple_pads(iomux_setup_v1, ARRAY_SIZE(iomux_setup_v1));
++}
+diff --git a/configs/duckbill_defconfig b/configs/duckbill_defconfig
+new file mode 100644
+index 0000000000..b2d7fbcf77
+--- /dev/null
++++ b/configs/duckbill_defconfig
+@@ -0,0 +1,43 @@
++CONFIG_ARM=y
++CONFIG_ARCH_MX28=y
++CONFIG_SYS_TEXT_BASE=0x40002000
++CONFIG_SPL_GPIO_SUPPORT=y
++CONFIG_SPL_LIBCOMMON_SUPPORT=y
++CONFIG_SPL_LIBGENERIC_SUPPORT=y
++CONFIG_TARGET_DUCKBILL=y
++CONFIG_SPL_SERIAL_SUPPORT=y
++CONFIG_ENV_SIZE=0x20000
++CONFIG_ENV_OFFSET=0x20000
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_SPL=y
++CONFIG_SPL_TEXT_BASE=0x00001000
++CONFIG_BOOTDELAY=1
++CONFIG_SYS_CONSOLE_IS_IN_ENV=y
++CONFIG_VERSION_VARIABLE=y
++# CONFIG_DISPLAY_BOARDINFO is not set
++CONFIG_ARCH_MISC_INIT=y
++# CONFIG_SPL_FRAMEWORK is not set
++CONFIG_HUSH_PARSER=y
++CONFIG_CMD_BOOTZ=y
++# CONFIG_CMD_ELF is not set
++CONFIG_CMD_UNZIP=y
++CONFIG_CMD_FUSE=y
++CONFIG_CMD_GPIO=y
++CONFIG_CMD_MMC=y
++CONFIG_CMD_MMC_SWRITE=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_EXT4=y
++CONFIG_CMD_EXT4_WRITE=y
++CONFIG_CMD_FS_GENERIC=y
++CONFIG_DOS_PARTITION=y
++CONFIG_ENV_IS_IN_MMC=y
++CONFIG_SYS_REDUNDAND_ENVIRONMENT=y
++CONFIG_ENV_OFFSET_REDUND=0x40000
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_MXS_GPIO=y
++CONFIG_MMC_MXS=y
++CONFIG_MII=y
++CONFIG_CONS_INDEX=0
++CONFIG_OF_LIBFDT=y
+diff --git a/include/configs/duckbill.h b/include/configs/duckbill.h
+new file mode 100644
+index 0000000000..565d8c58b7
+--- /dev/null
++++ b/include/configs/duckbill.h
+@@ -0,0 +1,172 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2014-2020 Michael Heimpold <mhei@heimpold.de>
++ *
++ */
++#ifndef __CONFIGS_DUCKBILL_H__
++#define __CONFIGS_DUCKBILL_H__
++
++/* System configurations */
++#define CONFIG_MACH_TYPE	MACH_TYPE_DUCKBILL
++
++#define CONFIG_MISC_INIT_R
++
++#define CONFIG_SYS_MXS_VDD5V_ONLY
++
++/* Memory configuration */
++#define PHYS_SDRAM_1			0x40000000	/* Base address */
++#define PHYS_SDRAM_1_SIZE		0x40000000	/* Max 1 GB RAM */
++#define CONFIG_SYS_SDRAM_BASE		PHYS_SDRAM_1
++
++/* Environment is in MMC */
++#define CONFIG_ENV_OVERWRITE
++#define CONFIG_SYS_MMC_ENV_DEV		0
++
++/* FEC Ethernet on SoC */
++#ifdef CONFIG_CMD_NET
++#define CONFIG_FEC_MXC
++#define CONFIG_MX28_FEC_MAC_IN_OCOTP
++#define CONFIG_FEC_MXC_MDIO_BASE	MXS_ENET0_BASE
++#endif
++
++#define CONFIG_IPADDR		192.168.1.10
++#define CONFIG_SERVERIP		192.168.1.1
++#define CONFIG_NETMASK		255.255.255.0
++#define CONFIG_GATEWAYIP	192.168.1.254
++
++/* Boot Linux */
++#define CONFIG_BOOTDELAY	1
++#define CONFIG_BOOTFILE		"zImage"
++#define CONFIG_LOADADDR		0x42000000
++#define CONFIG_SYS_LOAD_ADDR	CONFIG_LOADADDR
++#define CONFIG_REVISION_TAG
++#define CONFIG_SERIAL_TAG
++#define CONFIG_OF_BOARD_SETUP
++#define CONFIG_BOOT_RETRY_TIME		120	/* retry autoboot after 120 seconds */
++#define CONFIG_AUTOBOOT_KEYED
++#define CONFIG_AUTOBOOT_PROMPT		"Autobooting in %d seconds, " \
++					"press <c> to stop\n"
++#define CONFIG_AUTOBOOT_DELAY_STR	"\x63"	/* allows retry after retry time */
++#define CONFIG_AUTOBOOT_STOP_STR	" "	/* stop autoboot with <Space> */
++#define CONFIG_RESET_TO_RETRY			/* reset board to retry booting */
++
++/* Extra Environment */
++#define CONFIG_EXTRA_ENV_SETTINGS \
++	"mmc_part2_offset=1000\0" \
++	"mmc_part3_offset=19000\0" \
++	"update_openwrt_firmware_filename=openwrt-mxs-root.ext4\0" \
++	"update_openwrt_firmware=" \
++		"if mmc rescan; then " \
++			"if tftp ${update_openwrt_firmware_filename}; then " \
++				"setexpr fw_sz ${filesize} + 1ff; " \
++				"setexpr fw_sz ${fw_sz} / 200; " \
++				"mmc write ${loadaddr} ${mmc_part2_offset} ${fw_sz}; " \
++				"mmc write ${loadaddr} ${mmc_part3_offset} ${fw_sz}; " \
++			"fi; " \
++		"fi\0" \
++	"update_fw_filename_prefix=emmc.img.\0" \
++	"update_fw_filename_suffix=.gz\0" \
++	"update_fw_parts=0x6\0" \
++	"update_fw_fsize_uncompressed=4000000\0" \
++	"gzwrite_wbuf=100000\0" \
++	"update_emmc_firmware=" \
++		"setexpr i ${update_fw_parts}; setexpr error 0; " \
++		"while itest ${i} -gt 0; do " \
++			"echo Transfering firmware image part ${i} of ${update_fw_parts}; " \
++			"if itest ${i} -le f; then " \
++				"setenv j 0${i}; " \
++			"else " \
++				"setenv j ${i}; " \
++			"fi; " \
++			"if tftp ${loadaddr} ${update_fw_basedir}${update_fw_filename_prefix}${j}${update_fw_filename_suffix}; then " \
++				"setexpr k ${i} - 1; " \
++				"setexpr offset ${update_fw_fsize_uncompressed} * ${k}; " \
++				"if gzwrite mmc ${mmcdev} ${loadaddr} ${filesize} ${gzwrite_wbuf} ${offset}; then " \
++					"setexpr i ${i} - 1; " \
++				"else " \
++					"setexpr i 0; " \
++					"setexpr error 1; " \
++				"fi; " \
++			"else " \
++				"setexpr i 0; " \
++				"setexpr error 1; " \
++			"fi; " \
++		"done; setenv i; setenv j; setenv k; setenv fsize; setenv filesize; setenv offset; " \
++		"if test ${error} -eq 1; then " \
++			"echo Firmware Update FAILED; " \
++		"else " \
++			"echo Firmware Update OK; " \
++		"fi; setenv error\0" \
++	"image=zImage\0" \
++	"console=ttyAMA0\0" \
++	"fdt_addr=0x41000000\0" \
++	"boot_fdt=try\0" \
++	"ip_dyn=yes\0" \
++	"bootsys=1\0" \
++	"mmcdev=0\0" \
++	"mmcpart=2\0" \
++	"mmcroot=/dev/mmcblk0p2\0" \
++	"mmcargs=setenv bootargs console=${console},${baudrate} " \
++		"root=${mmcroot} " \
++		"rootwait bootsys=${bootsys} panic=1 ${extraargs}\0" \
++	"loadimage=load mmc ${mmcdev}:${mmcpart} ${loadaddr} /boot/${image}\0" \
++	"loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdt_addr} /boot/${fdt_file}\0" \
++	"mmcboot=echo Booting from mmc ...; " \
++		"setexpr mmcpart 1 + ${bootsys}; " \
++		"setenv mmcroot /dev/mmcblk0p${mmcpart}; " \
++		"run mmcargs; " \
++		"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
++			"if run loadfdt; then " \
++				"bootz ${loadaddr} - ${fdt_addr}; " \
++			"else " \
++				"if test ${boot_fdt} = try; then " \
++					"bootz; " \
++				"else " \
++					"echo WARN: Cannot load the DT; " \
++				"fi; " \
++			"fi; " \
++		"else " \
++			"bootz; " \
++		"fi\0" \
++	"nfsroot=/\0" \
++	"netargs=setenv bootargs console=${console},${baudrate} " \
++		"root=/dev/nfs " \
++		"ip=dhcp nfsroot=${serverip}:${nfsroot},v3,tcp ${extraargs}\0" \
++	"netboot=echo Booting from net ...; " \
++		"run netargs; "	\
++		"if test ${ip_dyn} = yes; then " \
++			"setenv get_cmd dhcp; " \
++		"else " \
++			"setenv get_cmd tftp; " \
++		"fi; " \
++		"${get_cmd} ${image}; " \
++		"if test ${boot_fdt} = yes || test ${boot_fdt} = try; then " \
++			"if ${get_cmd} ${fdt_addr} ${fdt_file}; then " \
++				"bootz ${loadaddr} - ${fdt_addr}; " \
++			"else " \
++				"if test ${boot_fdt} = try; then " \
++					"bootz; " \
++				"else " \
++					"echo WARN: Cannot load the DT; " \
++				"fi;" \
++			"fi; " \
++		"else " \
++			"bootz; " \
++		"fi\0"
++
++#define CONFIG_BOOTCOMMAND \
++	"mmc dev ${mmcdev}; " \
++	"if mmc rescan; then " \
++		"if run loadimage; then " \
++			"run mmcboot; " \
++		"else " \
++			"run netboot; " \
++		"fi; " \
++	"else " \
++		"run netboot; " \
++	"fi"
++
++/* The rest of the configuration is shared */
++#include <configs/mxs.h>
++
++#endif /* __CONFIGS_DUCKBILL_H__ */
+-- 
+2.17.1
+
diff --git a/package/boot/uboot-mxs/patches/210-link-libcrypto-static.patch b/package/boot/uboot-mxs/patches/210-link-libcrypto-static.patch
new file mode 100644
index 0000000..022e798
--- /dev/null
+++ b/package/boot/uboot-mxs/patches/210-link-libcrypto-static.patch
@@ -0,0 +1,14 @@
+OpenWrt links the libressl statically against mkimage, make sure all the 
+needed dependencies are added too.
+
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -147,7 +147,7 @@ endif
+ # MXSImage needs LibSSL
+ ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),)
+ HOSTLOADLIBES_mkimage += \
+-	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
++	$(shell pkg-config --libs --static libssl libcrypto 2> /dev/null || echo "-lssl -lpthread -lcrypto")
+ 
+ # OS X deprecate openssl in favour of CommonCrypto, supress deprecation
+ # warnings on those systems
diff --git a/package/boot/uboot-omap/Makefile b/package/boot/uboot-omap/Makefile
new file mode 100644
index 0000000..f66b8d5
--- /dev/null
+++ b/package/boot/uboot-omap/Makefile
@@ -0,0 +1,58 @@
+#
+# Copyright (C) 2012-2013 OpenWrt.org
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2020.04
+PKG_RELEASE:=1
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=omap
+  UBOOT_IMAGE:=u-boot.img MLO
+endef
+
+define U-Boot/omap4_panda
+  NAME:=Pandaboard
+  BUILD_DEVICES:=ti_omap4-panda
+endef
+
+define U-Boot/am335x_evm
+  NAME:=AM335x EVM
+  BUILD_DEVICES:=ti_am335x-evm ti_am335x-bone-black
+endef
+
+define U-Boot/omap3_overo
+  NAME:=Gumstix Overo
+endef
+
+define U-Boot/omap3_beagle
+  NAME:=BeagleBoard
+  BUILD_DEVICES:=ti_omap3-beagle
+endef
+
+UBOOT_TARGETS:=omap4_panda am335x_evm omap3_overo omap3_beagle
+
+define Build/InstallDev
+	$(foreach device,$(BUILD_DEVICES), \
+		$(INSTALL_DIR) $(STAGING_DIR_IMAGE)/$(device)
+	)
+	$(foreach device,$(BUILD_DEVICES), \
+		$(CP) $(patsubst %,$(PKG_BUILD_DIR)/%,$(UBOOT_IMAGE)) $(STAGING_DIR_IMAGE)/$(device)/
+	)
+	$(foreach device,$(BUILD_DEVICES), \
+		mkimage -C none -A arm -T script -d ./files/boot.scr.txt \
+			$(STAGING_DIR_IMAGE)/$(device)/boot.scr
+	)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-omap/files/boot.scr.txt b/package/boot/uboot-omap/files/boot.scr.txt
new file mode 100644
index 0000000..a97684b
--- /dev/null
+++ b/package/boot/uboot-omap/files/boot.scr.txt
@@ -0,0 +1,9 @@
+if test -z "${devnum}"; then
+	setenv devnum 0
+fi
+
+setenv bootargs console=${console} root=/dev/mmcblk${devnum}p2 rootwait
+
+load mmc ${devnum}:1 ${loadaddr} /zImage \
+&& load mmc ${devnum}:1 ${fdtaddr} /dtbs/${fdtfile} \
+&& bootz ${loadaddr} - ${fdtaddr}
diff --git a/package/boot/uboot-oxnas/Makefile b/package/boot/uboot-oxnas/Makefile
new file mode 100644
index 0000000..daa266e
--- /dev/null
+++ b/package/boot/uboot-oxnas/Makefile
@@ -0,0 +1,36 @@
+#
+# Copyright (C) 2012 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)/kernel.mk
+
+PKG_VERSION:=2014.10
+PKG_RELEASE:=1
+
+PKG_HASH:=d3b132a7a9b3f3182b7aad71c2dfbd4fc15bea83e12c76134eb3ffefc07d1c71
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=oxnas
+  BUILD_DEVICES:=Default
+  HIDDEN:=y
+endef
+
+define U-Boot/ox820
+  NAME:=Oxford/PLX NAS7820
+endef
+
+UBOOT_TARGETS:=ox820
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/u-boot.bin $(STAGING_DIR_IMAGE)/u-boot.bin
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-oxnas/patches/010-capacity-is-unsigned.patch b/package/boot/uboot-oxnas/patches/010-capacity-is-unsigned.patch
new file mode 100644
index 0000000..443b5e2
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/010-capacity-is-unsigned.patch
@@ -0,0 +1,37 @@
+From df9fb90120423c4c55b66a5dc09af23f605a406b Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Mon, 1 Dec 2014 21:37:25 +0100
+Subject: [PATCH] disk/part.c: use unsigned format when printing capacity
+To: u-boot@lists.denx.de
+
+Large disks otherwise produce highly unplausible output such as
+        Capacity: 1907729.0 MB = 1863.0 GB (-387938128 x 512)
+
+As supposedly all size-related decimals are unsigned, use unsigned
+format in printf statement, resulting in a correct capacity being
+displayed:
+        Capacity: 1907729.0 MB = 1863.0 GB (3907029168 x 512)
+
+Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+---
+ disk/part.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/disk/part.c
++++ b/disk/part.c
+@@ -229,13 +229,13 @@ void dev_print (block_dev_desc_t *dev_de
+ 			printf ("            Supports 48-bit addressing\n");
+ #endif
+ #if defined(CONFIG_SYS_64BIT_LBA)
+-		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%Ld x %ld)\n",
++		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%Lu x %lu)\n",
+ 			mb_quot, mb_rem,
+ 			gb_quot, gb_rem,
+ 			lba,
+ 			dev_desc->blksz);
+ #else
+-		printf ("            Capacity: %ld.%ld MB = %ld.%ld GB (%ld x %ld)\n",
++		printf ("            Capacity: %lu.%lu MB = %lu.%lu GB (%lu x %lu)\n",
+ 			mb_quot, mb_rem,
+ 			gb_quot, gb_rem,
+ 			(ulong)lba,
diff --git a/package/boot/uboot-oxnas/patches/020-socfpgaimage_portability.patch b/package/boot/uboot-oxnas/patches/020-socfpgaimage_portability.patch
new file mode 100644
index 0000000..e273c27
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/020-socfpgaimage_portability.patch
@@ -0,0 +1,52 @@
+--- a/tools/socfpgaimage.c
++++ b/tools/socfpgaimage.c
+@@ -74,12 +74,12 @@ static uint16_t hdr_checksum(struct socf
+ static void build_header(uint8_t *buf, uint8_t version, uint8_t flags,
+ 			 uint16_t length_bytes)
+ {
+-	header.validation = htole32(VALIDATION_WORD);
++	header.validation = cpu_to_le32(VALIDATION_WORD);
+ 	header.version = version;
+ 	header.flags = flags;
+-	header.length_u32 = htole16(length_bytes/4);
++	header.length_u32 = cpu_to_le16(length_bytes/4);
+ 	header.zero = 0;
+-	header.checksum = htole16(hdr_checksum(&header));
++	header.checksum = cpu_to_le16(hdr_checksum(&header));
+ 
+ 	memcpy(buf, &header, sizeof(header));
+ }
+@@ -92,12 +92,12 @@ static int verify_header(const uint8_t *
+ {
+ 	memcpy(&header, buf, sizeof(header));
+ 
+-	if (le32toh(header.validation) != VALIDATION_WORD)
++	if (le32_to_cpu(header.validation) != VALIDATION_WORD)
+ 		return -1;
+-	if (le16toh(header.checksum) != hdr_checksum(&header))
++	if (le16_to_cpu(header.checksum) != hdr_checksum(&header))
+ 		return -1;
+ 
+-	return le16toh(header.length_u32) * 4;
++	return le16_to_cpu(header.length_u32) * 4;
+ }
+ 
+ /* Sign the buffer and return the signed buffer size */
+@@ -116,7 +116,7 @@ static int sign_buffer(uint8_t *buf,
+ 	/* Calculate and apply the CRC */
+ 	calc_crc = ~pbl_crc32(0, (char *)buf, len);
+ 
+-	*((uint32_t *)(buf + len)) = htole32(calc_crc);
++	*((uint32_t *)(buf + len)) = cpu_to_le32(calc_crc);
+ 
+ 	if (!pad_64k)
+ 		return len + 4;
+@@ -150,7 +150,7 @@ static int verify_buffer(const uint8_t *
+ 
+ 	calc_crc = ~pbl_crc32(0, (const char *)buf, len);
+ 
+-	buf_crc = le32toh(*((uint32_t *)(buf + len)));
++	buf_crc = le32_to_cpu(*((uint32_t *)(buf + len)));
+ 
+ 	if (buf_crc != calc_crc) {
+ 		fprintf(stderr, "CRC32 does not match (%08x != %08x)\n",
diff --git a/package/boot/uboot-oxnas/patches/150-spl-block.patch b/package/boot/uboot-oxnas/patches/150-spl-block.patch
new file mode 100644
index 0000000..5d76084
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/150-spl-block.patch
@@ -0,0 +1,54 @@
+--- a/common/spl/Makefile
++++ b/common/spl/Makefile
+@@ -19,4 +19,5 @@ obj-$(CONFIG_SPL_MMC_SUPPORT) += spl_mmc
+ obj-$(CONFIG_SPL_USB_SUPPORT) += spl_usb.o
+ obj-$(CONFIG_SPL_FAT_SUPPORT) += spl_fat.o
+ obj-$(CONFIG_SPL_SATA_SUPPORT) += spl_sata.o
++obj-$(CONFIG_SPL_BLOCK_SUPPORT) += spl_block.o
+ endif
+--- a/common/spl/spl.c
++++ b/common/spl/spl.c
+@@ -191,6 +191,14 @@ void board_init_r(gd_t *dummy1, ulong du
+ 		spl_spi_load_image();
+ 		break;
+ #endif
++#ifdef CONFIG_SPL_BLOCK_SUPPORT
++	case BOOT_DEVICE_BLOCK:
++	{
++		extern void spl_block_load_image(void);
++		spl_block_load_image();
++		break;
++	}
++#endif
+ #ifdef CONFIG_SPL_ETH_SUPPORT
+ 	case BOOT_DEVICE_CPGMAC:
+ #ifdef CONFIG_SPL_ETH_DEVICE
+--- a/common/cmd_nvedit.c
++++ b/common/cmd_nvedit.c
+@@ -49,6 +49,7 @@ DECLARE_GLOBAL_DATA_PTR;
+ 	!defined(CONFIG_ENV_IS_IN_SPI_FLASH)	&& \
+ 	!defined(CONFIG_ENV_IS_IN_REMOTE)	&& \
+ 	!defined(CONFIG_ENV_IS_IN_UBI)		&& \
++	!defined(CONFIG_ENV_IS_IN_EXT4)		&& \
+ 	!defined(CONFIG_ENV_IS_NOWHERE)
+ # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|ONENAND|\
+ SPI_FLASH|NVRAM|MMC|FAT|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE
+--- a/common/Makefile
++++ b/common/Makefile
+@@ -63,6 +63,7 @@ obj-$(CONFIG_ENV_IS_IN_ONENAND) += env_o
+ obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
+ obj-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o
+ obj-$(CONFIG_ENV_IS_IN_UBI) += env_ubi.o
++obj-$(CONFIG_ENV_IS_IN_EXT4) += env_ext4.o
+ obj-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
+ 
+ # command
+@@ -213,6 +214,8 @@ obj-$(CONFIG_UPDATE_TFTP) += update.o
+ obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
+ obj-$(CONFIG_CMD_DFU) += cmd_dfu.o
+ obj-$(CONFIG_CMD_GPT) += cmd_gpt.o
++else
++obj-$(CONFIG_SPL_BLOCK_SUPPORT) += cmd_ide.o
+ endif
+ 
+ ifdef CONFIG_SPL_BUILD
diff --git a/package/boot/uboot-oxnas/patches/200-icplus-phy.patch b/package/boot/uboot-oxnas/patches/200-icplus-phy.patch
new file mode 100644
index 0000000..b378331
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/200-icplus-phy.patch
@@ -0,0 +1,142 @@
+From e719404ee1241af679a51879eaad291bc27e4817 Mon Sep 17 00:00:00 2001
+From: Daniel Golle <daniel@makrotopia.org>
+Date: Tue, 2 Dec 2014 14:46:05 +0100
+Subject: [PATCH] net/phy: add back icplus driver
+
+IC+ phy driver was removed due to the lack of users some time ago.
+Add it back, so we can use it.
+---
+ drivers/net/phy/Makefile |  1 +
+ drivers/net/phy/icplus.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/net/phy/phy.c    |  3 ++
+ 3 files changed, 84 insertions(+)
+ create mode 100644 drivers/net/phy/icplus.c
+
+--- a/drivers/net/phy/Makefile
++++ b/drivers/net/phy/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_PHY_ATHEROS) += atheros.o
+ obj-$(CONFIG_PHY_BROADCOM) += broadcom.o
+ obj-$(CONFIG_PHY_DAVICOM) += davicom.o
+ obj-$(CONFIG_PHY_ET1011C) += et1011c.o
++obj-$(CONFIG_PHY_ICPLUS) += icplus.o
+ obj-$(CONFIG_PHY_LXT) += lxt.o
+ obj-$(CONFIG_PHY_MARVELL) += marvell.o
+ obj-$(CONFIG_PHY_MICREL) += micrel.o
+--- /dev/null
++++ b/drivers/net/phy/icplus.c
+@@ -0,0 +1,93 @@
++/*
++ * ICPlus PHY drivers
++ *
++ * SPDX-License-Identifier:	GPL-2.0+
++ *
++ * Copyright (c) 2007 Freescale Semiconductor, Inc.
++ */
++#include <phy.h>
++
++/* IP101A/G - IP1001 */
++#define IP10XX_SPEC_CTRL_STATUS         16      /* Spec. Control Register */
++#define IP1001_SPEC_CTRL_STATUS_2       20      /* IP1001 Spec. Control Reg 2 */
++#define IP1001_PHASE_SEL_MASK           3       /* IP1001 RX/TXPHASE_SEL */
++#define IP1001_APS_ON                   11      /* IP1001 APS Mode  bit */
++#define IP101A_G_APS_ON                 2       /* IP101A/G APS Mode bit */
++#define IP101A_G_IRQ_CONF_STATUS        0x11    /* Conf Info IRQ & Status Reg */
++#define IP101A_G_IRQ_PIN_USED           (1<<15) /* INTR pin used */
++#define IP101A_G_IRQ_DEFAULT            IP101A_G_IRQ_PIN_USED
++#define IP1001LF_DRIVE_MASK     (15 << 5)
++#define IP1001LF_RXCLKDRIVE_HI  (2  << 5)
++#define IP1001LF_RXDDRIVE_HI    (2  << 7)
++#define IP1001LF_RXCLKDRIVE_M   (1  << 5)
++#define IP1001LF_RXDDRIVE_M     (1  << 7)
++#define IP1001LF_RXCLKDRIVE_L   (0  << 5)
++#define IP1001LF_RXDDRIVE_L     (0  << 7)
++#define IP1001LF_RXCLKDRIVE_VL  (3  << 5)
++#define IP1001LF_RXDDRIVE_VL    (3  << 7)
++
++static int ip1001_config(struct phy_device *phydev)
++{
++	int c;
++
++	/* Enable Auto Power Saving mode */
++	c = phy_read(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2);
++	if (c < 0)
++		return c;
++	c |= IP1001_APS_ON;
++	c = phy_write(phydev, MDIO_DEVAD_NONE, IP1001_SPEC_CTRL_STATUS_2, c);
++	if (c < 0)
++		return c;
++
++	/* INTR pin used: speed/link/duplex will cause an interrupt */
++	c = phy_write(phydev, MDIO_DEVAD_NONE, IP101A_G_IRQ_CONF_STATUS,
++		      IP101A_G_IRQ_DEFAULT);
++	if (c < 0)
++		return c;
++
++	if (phydev->interface == PHY_INTERFACE_MODE_RGMII) {
++		/*
++		 * Additional delay (2ns) used to adjust RX clock phase
++		 * at RGMII interface
++		 */
++		c = phy_read(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS);
++		if (c < 0)
++			return c;
++
++		c |= IP1001_PHASE_SEL_MASK;
++		/* adjust digtial drive strength */
++		c &= ~IP1001LF_DRIVE_MASK;
++		c |=  IP1001LF_RXCLKDRIVE_M;
++		c |=  IP1001LF_RXDDRIVE_M;
++		c = phy_write(phydev, MDIO_DEVAD_NONE, IP10XX_SPEC_CTRL_STATUS,
++			      c);
++		if (c < 0)
++			return c;
++	}
++
++	return 0;
++}
++
++static int ip1001_startup(struct phy_device *phydev)
++{
++	genphy_update_link(phydev);
++	genphy_parse_link(phydev);
++
++	return 0;
++}
++static struct phy_driver IP1001_driver = {
++	.name = "ICPlus IP1001",
++	.uid = 0x02430d90,
++	.mask = 0x0ffffff0,
++	.features = PHY_GBIT_FEATURES,
++	.config = &ip1001_config,
++	.startup = &ip1001_startup,
++	.shutdown = &genphy_shutdown,
++};
++
++int phy_icplus_init(void)
++{
++	phy_register(&IP1001_driver);
++
++	return 0;
++}
+--- a/drivers/net/phy/phy.c
++++ b/drivers/net/phy/phy.c
+@@ -454,6 +454,9 @@ int phy_init(void)
+ #ifdef CONFIG_PHY_ET1011C
+ 	phy_et1011c_init();
+ #endif
++#ifdef CONFIG_PHY_ICPLUS
++	phy_icplus_init();
++#endif
+ #ifdef CONFIG_PHY_LXT
+ 	phy_lxt_init();
+ #endif
+--- a/include/phy.h
++++ b/include/phy.h
+@@ -225,6 +225,7 @@ int phy_atheros_init(void);
+ int phy_broadcom_init(void);
+ int phy_davicom_init(void);
+ int phy_et1011c_init(void);
++int phy_icplus_init(void);
+ int phy_lxt_init(void);
+ int phy_marvell_init(void);
+ int phy_micrel_init(void);
diff --git a/package/boot/uboot-oxnas/patches/300-oxnas-target.patch b/package/boot/uboot-oxnas/patches/300-oxnas-target.patch
new file mode 100644
index 0000000..e677bd2
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/300-oxnas-target.patch
@@ -0,0 +1,101 @@
+--- a/arch/arm/include/asm/mach-types.h
++++ b/arch/arm/include/asm/mach-types.h
+@@ -212,6 +212,7 @@ extern unsigned int __machine_arch_type;
+ #define MACH_TYPE_EDB9307A             1128
+ #define MACH_TYPE_OMAP_3430SDP         1138
+ #define MACH_TYPE_VSTMS                1140
++#define MACH_TYPE_OXNAS                1152
+ #define MACH_TYPE_MICRO9M              1169
+ #define MACH_TYPE_BUG                  1179
+ #define MACH_TYPE_AT91SAM9263EK        1202
+--- a/drivers/block/Makefile
++++ b/drivers/block/Makefile
+@@ -21,3 +21,4 @@ obj-$(CONFIG_IDE_SIL680) += sil680.o
+ obj-$(CONFIG_SANDBOX) += sandbox.o
+ obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
+ obj-$(CONFIG_SYSTEMACE) += systemace.o
++obj-$(CONFIG_IDE_PLX) += plxsata_ide.o
+--- a/drivers/usb/host/Makefile
++++ b/drivers/usb/host/Makefile
+@@ -33,6 +33,7 @@ obj-$(CONFIG_USB_EHCI_MX6) += ehci-mx6.o
+ obj-$(CONFIG_USB_EHCI_OMAP) += ehci-omap.o
+ obj-$(CONFIG_USB_EHCI_PPC4XX) += ehci-ppc4xx.o
+ obj-$(CONFIG_USB_EHCI_MARVELL) += ehci-marvell.o
++obj-$(CONFIG_USB_EHCI_OXNAS) += ehci-oxnas.o
+ obj-$(CONFIG_USB_EHCI_PCI) += ehci-pci.o
+ obj-$(CONFIG_USB_EHCI_SPEAR) += ehci-spear.o
+ obj-$(CONFIG_USB_EHCI_SUNXI) += ehci-sunxi.o
+--- a/tools/.gitignore
++++ b/tools/.gitignore
+@@ -9,6 +9,7 @@
+ /mkenvimage
+ /mkimage
+ /mkexynosspl
++/mkox820crc
+ /mpc86x_clk
+ /mxsboot
+ /mksunxiboot
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -143,6 +143,12 @@ hostprogs-$(CONFIG_KIRKWOOD) += kwboot
+ hostprogs-y += proftool
+ hostprogs-$(CONFIG_STATIC_RELA) += relocate-rela
+ 
++
++hostprogs-$(CONFIG_OX820) += mkox820crc$(SFX)
++
++mkox820crc$(SFX)-objs := mkox820crc.o lib/crc32.o
++
++
+ # We build some files with extra pedantic flags to try to minimize things
+ # that won't build on some weird host compiler -- though there are lots of
+ # exceptions for files that aren't complaint.
+--- a/drivers/serial/ns16550.c
++++ b/drivers/serial/ns16550.c
+@@ -118,6 +118,14 @@ int ns16550_calc_divisor(NS16550_t port,
+ 	}
+ 	port->osc_12m_sel = 0;			/* clear if previsouly set */
+ #endif
++#ifdef CONFIG_OX820
++	{
++		/* with additional 3 bit fractional */
++		u32 div = (CONFIG_SYS_NS16550_CLK + baudrate) / (baudrate * 2);
++		port->reg9 = (div & 7) << 5;
++		return (div >> 3);
++	}
++#endif
+ 
+ 	return DIV_ROUND_CLOSEST(clock, mode_x_div * baudrate);
+ }
+--- a/scripts/Makefile.spl
++++ b/scripts/Makefile.spl
+@@ -202,6 +202,9 @@ OBJCOPYFLAGS_$(SPL_BIN).bin = $(SPL_OBJC
+ 
+ $(obj)/$(SPL_BIN).bin: $(obj)/$(SPL_BIN) FORCE
+ 	$(call if_changed,objcopy)
++ifdef CONFIG_OX820
++	$(OBJTREE)/tools/mkox820crc $@
++endif
+ 
+ LDFLAGS_$(SPL_BIN) += -T u-boot-spl.lds $(LDFLAGS_FINAL)
+ ifneq ($(CONFIG_SPL_TEXT_BASE),)
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -488,6 +488,9 @@ config TARGET_BALLOON3
+ config TARGET_H2200
+ 	bool "Support h2200"
+ 
++config TARGET_OX820
++	bool "Support ox820"
++
+ config TARGET_PALMLD
+ 	bool "Support palmld"
+ 
+@@ -650,6 +653,7 @@ source "board/logicpd/imx27lite/Kconfig"
+ source "board/logicpd/imx31_litekit/Kconfig"
+ source "board/mpl/vcma9/Kconfig"
+ source "board/olimex/mx23_olinuxino/Kconfig"
++source "board/ox820/Kconfig"
+ source "board/palmld/Kconfig"
+ source "board/palmtc/Kconfig"
+ source "board/palmtreo680/Kconfig"
diff --git a/package/boot/uboot-oxnas/patches/400-gcc-5-compiler.patch b/package/boot/uboot-oxnas/patches/400-gcc-5-compiler.patch
new file mode 100644
index 0000000..8724927
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/400-gcc-5-compiler.patch
@@ -0,0 +1,87 @@
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 7 Feb 2015 21:52:40 +0000 (+0100)
+Subject: Add linux/compiler-gcc5.h to fix builds with gcc5
+X-Git-Tag: v2015.04-rc2~31
+X-Git-Url: http://git.denx.de/?p=u-boot.git;a=commitdiff_plain;h=478b02f1a7043b673565075ea5016376f3293b23
+
+Add linux/compiler-gcc5.h to fix builds with gcc5
+
+Add linux/compiler-gcc5/h from the kernel sources at:
+
+commit 5631b8fba640a4ab2f8a954f63a603fa34eda96b
+Author: Steven Noonan <steven@uplinklabs.net>
+Date:   Sat Oct 25 15:09:42 2014 -0700
+
+    compiler/gcc4+: Remove inaccurate comment about 'asm goto' miscompiles
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+
+--- /dev/null
++++ b/include/linux/compiler-gcc5.h
+@@ -0,0 +1,65 @@
++#ifndef __LINUX_COMPILER_H
++#error "Please don't include <linux/compiler-gcc5.h> directly, include <linux/compiler.h> instead."
++#endif
++
++#define __used				__attribute__((__used__))
++#define __must_check			__attribute__((warn_unused_result))
++#define __compiler_offsetof(a, b)	__builtin_offsetof(a, b)
++
++/* Mark functions as cold. gcc will assume any path leading to a call
++   to them will be unlikely.  This means a lot of manual unlikely()s
++   are unnecessary now for any paths leading to the usual suspects
++   like BUG(), printk(), panic() etc. [but let's keep them for now for
++   older compilers]
++
++   Early snapshots of gcc 4.3 don't support this and we can't detect this
++   in the preprocessor, but we can live with this because they're unreleased.
++   Maketime probing would be overkill here.
++
++   gcc also has a __attribute__((__hot__)) to move hot functions into
++   a special section, but I don't see any sense in this right now in
++   the kernel context */
++#define __cold			__attribute__((__cold__))
++
++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
++
++#ifndef __CHECKER__
++# define __compiletime_warning(message) __attribute__((warning(message)))
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* __CHECKER__ */
++
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased.  Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++
++/* Mark a function definition as prohibited from being cloned. */
++#define __noclone	__attribute__((__noclone__))
++
++/*
++ * Tell the optimizer that something else uses this function or variable.
++ */
++#define __visible __attribute__((externally_visible))
++
++/*
++ * GCC 'asm goto' miscompiles certain code sequences:
++ *
++ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
++ *
++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
++ *
++ * (asm goto is automatically volatile - the naming reflects this.)
++ */
++#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
++
++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#define __HAVE_BUILTIN_BSWAP16__
++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
diff --git a/package/boot/uboot-oxnas/patches/410-gcc-6-compiler.patch b/package/boot/uboot-oxnas/patches/410-gcc-6-compiler.patch
new file mode 100644
index 0000000..00d0657
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/410-gcc-6-compiler.patch
@@ -0,0 +1,306 @@
+From: Hans de Goede <hdegoede@redhat.com>
+Date: Sat, 7 Feb 2015 21:52:40 +0000 (+0100)
+Subject: Add linux/compiler-gcc6.h to fix builds with gcc6
+X-Git-Tag: v2015.04-rc2~31
+X-Git-Url: http://git.denx.de/?p=u-boot.git;a=commitdiff_plain;h=478b02f1a7043b673565075ea5016376f3293b23
+
+Add linux/compiler-gcc6.h to fix builds with gcc6
+
+Add linux/compiler-gcc6/h from the kernel sources at:
+
+commit 5631b8fba640a4ab2f8a954f63a603fa34eda96b
+Author: Steven Noonan <steven@uplinklabs.net>
+Date:   Sat Oct 25 15:09:42 2014 -0700
+
+    compiler/gcc4+: Remove inaccurate comment about 'asm goto' miscompiles
+
+Signed-off-by: Hans de Goede <hdegoede@redhat.com>
+---
+
+--- /dev/null
++++ b/include/linux/compiler-gcc6.h
+@@ -0,0 +1,284 @@
++#ifndef __LINUX_COMPILER_H
++#error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
++#endif
++
++/*
++ * Common definitions for all gcc versions go here.
++ */
++#define GCC_VERSION (__GNUC__ * 10000		\
++		     + __GNUC_MINOR__ * 100	\
++		     + __GNUC_PATCHLEVEL__)
++
++/* Optimization barrier */
++
++/* The "volatile" is due to gcc bugs */
++#define barrier() __asm__ __volatile__("": : :"memory")
++/*
++ * This version is i.e. to prevent dead stores elimination on @ptr
++ * where gcc and llvm may behave differently when otherwise using
++ * normal barrier(): while gcc behavior gets along with a normal
++ * barrier(), llvm needs an explicit input variable to be assumed
++ * clobbered. The issue is as follows: while the inline asm might
++ * access any memory it wants, the compiler could have fit all of
++ * @ptr into memory registers instead, and since @ptr never escaped
++ * from that, it proofed that the inline asm wasn't touching any of
++ * it. This version works well with both compilers, i.e. we're telling
++ * the compiler that the inline asm absolutely may see the contents
++ * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495
++ */
++#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
++
++/*
++ * This macro obfuscates arithmetic on a variable address so that gcc
++ * shouldn't recognize the original var, and make assumptions about it.
++ *
++ * This is needed because the C standard makes it undefined to do
++ * pointer arithmetic on "objects" outside their boundaries and the
++ * gcc optimizers assume this is the case. In particular they
++ * assume such arithmetic does not wrap.
++ *
++ * A miscompilation has been observed because of this on PPC.
++ * To work around it we hide the relationship of the pointer and the object
++ * using this macro.
++ *
++ * Versions of the ppc64 compiler before 4.1 had a bug where use of
++ * RELOC_HIDE could trash r30. The bug can be worked around by changing
++ * the inline assembly constraint from =g to =r, in this particular
++ * case either is valid.
++ */
++#define RELOC_HIDE(ptr, off)						\
++({									\
++	unsigned long __ptr;						\
++	__asm__ ("" : "=r"(__ptr) : "0"(ptr));				\
++	(typeof(ptr)) (__ptr + (off));					\
++})
++
++/* Make the optimizer believe the variable can be manipulated arbitrarily. */
++#define OPTIMIZER_HIDE_VAR(var)						\
++	__asm__ ("" : "=r" (var) : "0" (var))
++
++#ifdef __CHECKER__
++#define __must_be_array(a)	0
++#else
++/* &a[0] degrades to a pointer: a different type from an array */
++#define __must_be_array(a)	BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
++#endif
++
++/*
++ * Force always-inline if the user requests it so via the .config,
++ * or if gcc is too old:
++ */
++#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
++    !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
++#define inline		inline		__attribute__((always_inline)) notrace
++#define __inline__	__inline__	__attribute__((always_inline)) notrace
++#define __inline	__inline	__attribute__((always_inline)) notrace
++#else
++/* A lot of inline functions can cause havoc with function tracing */
++#define inline		inline		notrace
++#define __inline__	__inline__	notrace
++#define __inline	__inline	notrace
++#endif
++
++#define __always_inline	inline __attribute__((always_inline))
++#define  noinline	__attribute__((noinline))
++
++#define __deprecated	__attribute__((deprecated))
++#define __packed	__attribute__((packed))
++#define __weak		__attribute__((weak))
++#define __alias(symbol)	__attribute__((alias(#symbol)))
++
++/*
++ * it doesn't make sense on ARM (currently the only user of __naked)
++ * to trace naked functions because then mcount is called without
++ * stack and frame pointer being set up and there is no chance to
++ * restore the lr register to the value before mcount was called.
++ *
++ * The asm() bodies of naked functions often depend on standard calling
++ * conventions, therefore they must be noinline and noclone.
++ *
++ * GCC 4.[56] currently fail to enforce this, so we must do so ourselves.
++ * See GCC PR44290.
++ */
++#define __naked		__attribute__((naked)) noinline __noclone notrace
++
++#define __noreturn	__attribute__((noreturn))
++
++/*
++ * From the GCC manual:
++ *
++ * Many functions have no effects except the return value and their
++ * return value depends only on the parameters and/or global
++ * variables.  Such a function can be subject to common subexpression
++ * elimination and loop optimization just as an arithmetic operator
++ * would be.
++ * [...]
++ */
++#define __pure			__attribute__((pure))
++#define __aligned(x)		__attribute__((aligned(x)))
++#define __printf(a, b)		__attribute__((format(printf, a, b)))
++#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
++#define __attribute_const__	__attribute__((__const__))
++#define __maybe_unused		__attribute__((unused))
++#define __always_unused		__attribute__((unused))
++
++/* gcc version specific checks */
++
++#if GCC_VERSION < 30200
++# error Sorry, your compiler is too old - please upgrade it.
++#endif
++
++#if GCC_VERSION < 30300
++# define __used			__attribute__((__unused__))
++#else
++# define __used			__attribute__((__used__))
++#endif
++
++#ifdef CONFIG_GCOV_KERNEL
++# if GCC_VERSION < 30400
++#   error "GCOV profiling support for gcc versions below 3.4 not included"
++# endif /* __GNUC_MINOR__ */
++#endif /* CONFIG_GCOV_KERNEL */
++
++#if GCC_VERSION >= 30400
++#define __must_check		__attribute__((warn_unused_result))
++#define __malloc		__attribute__((__malloc__))
++#endif
++
++#if GCC_VERSION >= 40000
++
++/* GCC 4.1.[01] miscompiles __weak */
++#ifdef __KERNEL__
++# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
++#  error Your version of gcc miscompiles the __weak directive
++# endif
++#endif
++
++#define __used			__attribute__((__used__))
++#define __compiler_offsetof(a, b)					\
++	__builtin_offsetof(a, b)
++
++#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
++# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
++#endif
++
++#if GCC_VERSION >= 40300
++/* Mark functions as cold. gcc will assume any path leading to a call
++ * to them will be unlikely.  This means a lot of manual unlikely()s
++ * are unnecessary now for any paths leading to the usual suspects
++ * like BUG(), printk(), panic() etc. [but let's keep them for now for
++ * older compilers]
++ *
++ * Early snapshots of gcc 4.3 don't support this and we can't detect this
++ * in the preprocessor, but we can live with this because they're unreleased.
++ * Maketime probing would be overkill here.
++ *
++ * gcc also has a __attribute__((__hot__)) to move hot functions into
++ * a special section, but I don't see any sense in this right now in
++ * the kernel context
++ */
++#define __cold			__attribute__((__cold__))
++
++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
++
++#ifndef __CHECKER__
++# define __compiletime_warning(message) __attribute__((warning(message)))
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* __CHECKER__ */
++#endif /* GCC_VERSION >= 40300 */
++
++#if GCC_VERSION >= 40500
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased.  Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++
++/* Mark a function definition as prohibited from being cloned. */
++#define __noclone	__attribute__((__noclone__, __optimize__("no-tracer")))
++
++#endif /* GCC_VERSION >= 40500 */
++
++#if GCC_VERSION >= 40600
++/*
++ * When used with Link Time Optimization, gcc can optimize away C functions or
++ * variables which are referenced only from assembly code.  __visible tells the
++ * optimizer that something else uses this function or variable, thus preventing
++ * this.
++ */
++#define __visible	__attribute__((externally_visible))
++#endif
++
++
++#if GCC_VERSION >= 40900 && !defined(__CHECKER__)
++/*
++ * __assume_aligned(n, k): Tell the optimizer that the returned
++ * pointer can be assumed to be k modulo n. The second argument is
++ * optional (default 0), so we use a variadic macro to make the
++ * shorthand.
++ *
++ * Beware: Do not apply this to functions which may return
++ * ERR_PTRs. Also, it is probably unwise to apply it to functions
++ * returning extra information in the low bits (but in that case the
++ * compiler should see some alignment anyway, when the return value is
++ * massaged by 'flags = ptr & 3; ptr &= ~3;').
++ */
++#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))
++#endif
++
++/*
++ * GCC 'asm goto' miscompiles certain code sequences:
++ *
++ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
++ *
++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
++ *
++ * (asm goto is automatically volatile - the naming reflects this.)
++ */
++#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
++
++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
++#if GCC_VERSION >= 40400
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#endif
++#if GCC_VERSION >= 40800
++#define __HAVE_BUILTIN_BSWAP16__
++#endif
++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
++
++#if GCC_VERSION >= 50000
++#define KASAN_ABI_VERSION 4
++#elif GCC_VERSION >= 40902
++#define KASAN_ABI_VERSION 3
++#endif
++
++#if GCC_VERSION >= 40902
++/*
++ * Tell the compiler that address safety instrumentation (KASAN)
++ * should not be applied to that function.
++ * Conflicts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ */
++#define __no_sanitize_address __attribute__((no_sanitize_address))
++#endif
++
++#endif	/* gcc version >= 40000 specific checks */
++
++#if !defined(__noclone)
++#define __noclone	/* not needed */
++#endif
++
++#if !defined(__no_sanitize_address)
++#define __no_sanitize_address
++#endif
++
++/*
++ * A trick to suppress uninitialized variable warning without generating any
++ * code
++ */
++#define uninitialized_var(x) x = x
diff --git a/package/boot/uboot-oxnas/patches/420-gcc-7-compiler.patch b/package/boot/uboot-oxnas/patches/420-gcc-7-compiler.patch
new file mode 100644
index 0000000..0951629
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/420-gcc-7-compiler.patch
@@ -0,0 +1,287 @@
+--- /dev/null
++++ b/include/linux/compiler-gcc7.h
+@@ -0,0 +1,284 @@
++#ifndef __LINUX_COMPILER_H
++#error "Please don't include <linux/compiler-gcc.h> directly, include <linux/compiler.h> instead."
++#endif
++
++/*
++ * Common definitions for all gcc versions go here.
++ */
++#define GCC_VERSION (__GNUC__ * 10000		\
++		     + __GNUC_MINOR__ * 100	\
++		     + __GNUC_PATCHLEVEL__)
++
++/* Optimization barrier */
++
++/* The "volatile" is due to gcc bugs */
++#define barrier() __asm__ __volatile__("": : :"memory")
++/*
++ * This version is i.e. to prevent dead stores elimination on @ptr
++ * where gcc and llvm may behave differently when otherwise using
++ * normal barrier(): while gcc behavior gets along with a normal
++ * barrier(), llvm needs an explicit input variable to be assumed
++ * clobbered. The issue is as follows: while the inline asm might
++ * access any memory it wants, the compiler could have fit all of
++ * @ptr into memory registers instead, and since @ptr never escaped
++ * from that, it proofed that the inline asm wasn't touching any of
++ * it. This version works well with both compilers, i.e. we're telling
++ * the compiler that the inline asm absolutely may see the contents
++ * of @ptr. See also: https://llvm.org/bugs/show_bug.cgi?id=15495
++ */
++#define barrier_data(ptr) __asm__ __volatile__("": :"r"(ptr) :"memory")
++
++/*
++ * This macro obfuscates arithmetic on a variable address so that gcc
++ * shouldn't recognize the original var, and make assumptions about it.
++ *
++ * This is needed because the C standard makes it undefined to do
++ * pointer arithmetic on "objects" outside their boundaries and the
++ * gcc optimizers assume this is the case. In particular they
++ * assume such arithmetic does not wrap.
++ *
++ * A miscompilation has been observed because of this on PPC.
++ * To work around it we hide the relationship of the pointer and the object
++ * using this macro.
++ *
++ * Versions of the ppc64 compiler before 4.1 had a bug where use of
++ * RELOC_HIDE could trash r30. The bug can be worked around by changing
++ * the inline assembly constraint from =g to =r, in this particular
++ * case either is valid.
++ */
++#define RELOC_HIDE(ptr, off)						\
++({									\
++	unsigned long __ptr;						\
++	__asm__ ("" : "=r"(__ptr) : "0"(ptr));				\
++	(typeof(ptr)) (__ptr + (off));					\
++})
++
++/* Make the optimizer believe the variable can be manipulated arbitrarily. */
++#define OPTIMIZER_HIDE_VAR(var)						\
++	__asm__ ("" : "=r" (var) : "0" (var))
++
++#ifdef __CHECKER__
++#define __must_be_array(a)	0
++#else
++/* &a[0] degrades to a pointer: a different type from an array */
++#define __must_be_array(a)	BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
++#endif
++
++/*
++ * Force always-inline if the user requests it so via the .config,
++ * or if gcc is too old:
++ */
++#if !defined(CONFIG_ARCH_SUPPORTS_OPTIMIZED_INLINING) ||		\
++    !defined(CONFIG_OPTIMIZE_INLINING) || (__GNUC__ < 4)
++#define inline		inline		__attribute__((always_inline)) notrace
++#define __inline__	__inline__	__attribute__((always_inline)) notrace
++#define __inline	__inline	__attribute__((always_inline)) notrace
++#else
++/* A lot of inline functions can cause havoc with function tracing */
++#define inline		inline		notrace
++#define __inline__	__inline__	notrace
++#define __inline	__inline	notrace
++#endif
++
++#define __always_inline	inline __attribute__((always_inline))
++#define  noinline	__attribute__((noinline))
++
++#define __deprecated	__attribute__((deprecated))
++#define __packed	__attribute__((packed))
++#define __weak		__attribute__((weak))
++#define __alias(symbol)	__attribute__((alias(#symbol)))
++
++/*
++ * it doesn't make sense on ARM (currently the only user of __naked)
++ * to trace naked functions because then mcount is called without
++ * stack and frame pointer being set up and there is no chance to
++ * restore the lr register to the value before mcount was called.
++ *
++ * The asm() bodies of naked functions often depend on standard calling
++ * conventions, therefore they must be noinline and noclone.
++ *
++ * GCC 4.[56] currently fail to enforce this, so we must do so ourselves.
++ * See GCC PR44290.
++ */
++#define __naked		__attribute__((naked)) noinline __noclone notrace
++
++#define __noreturn	__attribute__((noreturn))
++
++/*
++ * From the GCC manual:
++ *
++ * Many functions have no effects except the return value and their
++ * return value depends only on the parameters and/or global
++ * variables.  Such a function can be subject to common subexpression
++ * elimination and loop optimization just as an arithmetic operator
++ * would be.
++ * [...]
++ */
++#define __pure			__attribute__((pure))
++#define __aligned(x)		__attribute__((aligned(x)))
++#define __printf(a, b)		__attribute__((format(printf, a, b)))
++#define __scanf(a, b)		__attribute__((format(scanf, a, b)))
++#define __attribute_const__	__attribute__((__const__))
++#define __maybe_unused		__attribute__((unused))
++#define __always_unused		__attribute__((unused))
++
++/* gcc version specific checks */
++
++#if GCC_VERSION < 30200
++# error Sorry, your compiler is too old - please upgrade it.
++#endif
++
++#if GCC_VERSION < 30300
++# define __used			__attribute__((__unused__))
++#else
++# define __used			__attribute__((__used__))
++#endif
++
++#ifdef CONFIG_GCOV_KERNEL
++# if GCC_VERSION < 30400
++#   error "GCOV profiling support for gcc versions below 3.4 not included"
++# endif /* __GNUC_MINOR__ */
++#endif /* CONFIG_GCOV_KERNEL */
++
++#if GCC_VERSION >= 30400
++#define __must_check		__attribute__((warn_unused_result))
++#define __malloc		__attribute__((__malloc__))
++#endif
++
++#if GCC_VERSION >= 40000
++
++/* GCC 4.1.[01] miscompiles __weak */
++#ifdef __KERNEL__
++# if GCC_VERSION >= 40100 &&  GCC_VERSION <= 40101
++#  error Your version of gcc miscompiles the __weak directive
++# endif
++#endif
++
++#define __used			__attribute__((__used__))
++#define __compiler_offsetof(a, b)					\
++	__builtin_offsetof(a, b)
++
++#if GCC_VERSION >= 40100 && GCC_VERSION < 40600
++# define __compiletime_object_size(obj) __builtin_object_size(obj, 0)
++#endif
++
++#if GCC_VERSION >= 40300
++/* Mark functions as cold. gcc will assume any path leading to a call
++ * to them will be unlikely.  This means a lot of manual unlikely()s
++ * are unnecessary now for any paths leading to the usual suspects
++ * like BUG(), printk(), panic() etc. [but let's keep them for now for
++ * older compilers]
++ *
++ * Early snapshots of gcc 4.3 don't support this and we can't detect this
++ * in the preprocessor, but we can live with this because they're unreleased.
++ * Maketime probing would be overkill here.
++ *
++ * gcc also has a __attribute__((__hot__)) to move hot functions into
++ * a special section, but I don't see any sense in this right now in
++ * the kernel context
++ */
++#define __cold			__attribute__((__cold__))
++
++#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
++
++#ifndef __CHECKER__
++# define __compiletime_warning(message) __attribute__((warning(message)))
++# define __compiletime_error(message) __attribute__((error(message)))
++#endif /* __CHECKER__ */
++#endif /* GCC_VERSION >= 40300 */
++
++#if GCC_VERSION >= 40500
++/*
++ * Mark a position in code as unreachable.  This can be used to
++ * suppress control flow warnings after asm blocks that transfer
++ * control elsewhere.
++ *
++ * Early snapshots of gcc 4.5 don't support this and we can't detect
++ * this in the preprocessor, but we can live with this because they're
++ * unreleased.  Really, we need to have autoconf for the kernel.
++ */
++#define unreachable() __builtin_unreachable()
++
++/* Mark a function definition as prohibited from being cloned. */
++#define __noclone	__attribute__((__noclone__, __optimize__("no-tracer")))
++
++#endif /* GCC_VERSION >= 40500 */
++
++#if GCC_VERSION >= 40600
++/*
++ * When used with Link Time Optimization, gcc can optimize away C functions or
++ * variables which are referenced only from assembly code.  __visible tells the
++ * optimizer that something else uses this function or variable, thus preventing
++ * this.
++ */
++#define __visible	__attribute__((externally_visible))
++#endif
++
++
++#if GCC_VERSION >= 40900 && !defined(__CHECKER__)
++/*
++ * __assume_aligned(n, k): Tell the optimizer that the returned
++ * pointer can be assumed to be k modulo n. The second argument is
++ * optional (default 0), so we use a variadic macro to make the
++ * shorthand.
++ *
++ * Beware: Do not apply this to functions which may return
++ * ERR_PTRs. Also, it is probably unwise to apply it to functions
++ * returning extra information in the low bits (but in that case the
++ * compiler should see some alignment anyway, when the return value is
++ * massaged by 'flags = ptr & 3; ptr &= ~3;').
++ */
++#define __assume_aligned(a, ...) __attribute__((__assume_aligned__(a, ## __VA_ARGS__)))
++#endif
++
++/*
++ * GCC 'asm goto' miscompiles certain code sequences:
++ *
++ *   http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
++ *
++ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
++ *
++ * (asm goto is automatically volatile - the naming reflects this.)
++ */
++#define asm_volatile_goto(x...)	do { asm goto(x); asm (""); } while (0)
++
++#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
++#if GCC_VERSION >= 40400
++#define __HAVE_BUILTIN_BSWAP32__
++#define __HAVE_BUILTIN_BSWAP64__
++#endif
++#if GCC_VERSION >= 40800
++#define __HAVE_BUILTIN_BSWAP16__
++#endif
++#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
++
++#if GCC_VERSION >= 50000
++#define KASAN_ABI_VERSION 4
++#elif GCC_VERSION >= 40902
++#define KASAN_ABI_VERSION 3
++#endif
++
++#if GCC_VERSION >= 40902
++/*
++ * Tell the compiler that address safety instrumentation (KASAN)
++ * should not be applied to that function.
++ * Conflicts with inlining: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67368
++ */
++#define __no_sanitize_address __attribute__((no_sanitize_address))
++#endif
++
++#endif	/* gcc version >= 40000 specific checks */
++
++#if !defined(__noclone)
++#define __noclone	/* not needed */
++#endif
++
++#if !defined(__no_sanitize_address)
++#define __no_sanitize_address
++#endif
++
++/*
++ * A trick to suppress uninitialized variable warning without generating any
++ * code
++ */
++#define uninitialized_var(x) x = x
diff --git a/package/boot/uboot-oxnas/patches/800-fix-bootm-assertion.patch b/package/boot/uboot-oxnas/patches/800-fix-bootm-assertion.patch
new file mode 100644
index 0000000..957c492
--- /dev/null
+++ b/package/boot/uboot-oxnas/patches/800-fix-bootm-assertion.patch
@@ -0,0 +1,11 @@
+--- a/common/cmd_bootm.c
++++ b/common/cmd_bootm.c
+@@ -77,7 +77,7 @@ static int do_bootm_subcommand(cmd_tbl_t
+ 		return CMD_RET_USAGE;
+ 	}
+ 
+-	if (state != BOOTM_STATE_START && images.state >= state) {
++	if (!(state & BOOTM_STATE_START) && images.state >= state) {
+ 		printf("Trying to execute a command out of order\n");
+ 		return CMD_RET_USAGE;
+ 	}
diff --git a/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/Makefile b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/Makefile
new file mode 100644
index 0000000..4c32f5c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/Makefile
@@ -0,0 +1,13 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	+= reset.o
+obj-y	+= timer.o
+obj-y	+= clock.o
+obj-y	+= pinmux.o
diff --git a/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/clock.c b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/clock.c
new file mode 100644
index 0000000..8974ca0
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/clock.c
@@ -0,0 +1,97 @@
+#include <common.h>
+#include <asm/arch/sysctl.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/clock.h>
+
+typedef struct {
+	unsigned short mhz;
+	unsigned char refdiv;
+	unsigned char outdiv;
+	unsigned int fbdiv;
+	unsigned short bwadj;
+	unsigned short sfreq;
+	unsigned int sslope;
+} PLL_CONFIG;
+
+const PLL_CONFIG C_PLL_CONFIG[] = {
+	{ 500, 1, 2, 3932160, 119, 208, 189 }, //  500 MHz
+	{ 525, 2, 1, 4128768, 125, 139, 297 }, //  525 MHz
+	{ 550, 2, 1, 4325376, 131, 139, 311 }, //  550 MHz
+	{ 575, 2, 1, 4521984, 137, 139, 326 }, //  575 MHz
+	{ 600, 2, 1, 4718592, 143, 138, 339 }, //  600 MHz
+	{ 625, 1, 1, 3276800, 99, 208, 157 }, //  625 MHz
+	{ 650, 1, 1, 3407872, 103, 208, 164 }, //  650 MHz
+	{ 675, 1, 1, 3538944, 107, 208, 170 }, //  675 MHz
+	{ 700, 0, 0, 917504, 27, 416, 22 }, //  700 MHz
+	{ 725, 1, 1, 3801088, 115, 208, 182 }, //  725 MHz
+	{ 750, 0, 0, 983040, 29, 416, 23 }, //  750 MHz
+	{ 775, 3, 0, 4063232, 123, 104, 390 }, //  775 MHz
+	{ 800, 3, 0, 4194304, 127, 104, 403 }, //  800 MHz
+	{ 825, 3, 0, 4325376, 131, 104, 415 }, //  825 MHz
+	{ 850, 2, 0, 3342336, 101, 139, 241 }, //  850 MHz
+	{ 875, 2, 0, 3440640, 104, 139, 248 }, //  875 MHz
+	{ 900, 2, 0, 3538944, 107, 139, 255 }, //  900 MHz
+	{ 925, 2, 0, 3637248, 110, 139, 262 }, //  925 MHz
+	{ 950, 2, 0, 3735552, 113, 139, 269 }, //  950 MHz
+	{ 975, 2, 0, 3833856, 116, 139, 276 }, //  975 MHz
+	{ 1000, 2, 0, 3932160, 119, 139, 283 }, // 1000 MHz
+};
+
+#define PLL_BYPASS (1<<1)
+#define SAT_ENABLE (1<<3)
+
+#define PLL_OUTDIV_SHIFT	4
+#define PLL_REFDIV_SHIFT	8
+#define PLL_BWADJ_SHIFT		16
+
+#define PLL_LOW_FREQ	500
+#define PLL_FREQ_STEP	25
+static void plla_configure(int outdiv, int refdiv, int fbdiv, int bwadj,
+                           int sfreq, int sslope)
+{
+	setbits_le32(SYS_CTRL_PLLA_CTRL0, PLL_BYPASS);
+	udelay(10);
+	reset_block(SYS_CTRL_RST_PLLA, 1);
+	udelay(10);
+
+	writel((refdiv << PLL_REFDIV_SHIFT) | (outdiv << PLL_OUTDIV_SHIFT) |
+	       SAT_ENABLE | PLL_BYPASS,
+	       SYS_CTRL_PLLA_CTRL0);
+
+	writel(fbdiv, SYS_CTRL_PLLA_CTRL1);
+	writel((bwadj << PLL_BWADJ_SHIFT) | sfreq, SYS_CTRL_PLLA_CTRL2);
+	writel(sslope, SYS_CTRL_PLLA_CTRL3);
+
+	udelay(10); // 5us delay required (from TCI datasheet), use 10us
+
+	reset_block(SYS_CTRL_RST_PLLA, 0);
+
+	udelay(100); // Delay for PLL to lock
+
+	printf("  plla_ctrl0 : %08x\n", readl(SYS_CTRL_PLLA_CTRL0));
+	printf("  plla_ctrl1 : %08x\n", readl(SYS_CTRL_PLLA_CTRL1));
+	printf("  plla_ctrl2 : %08x\n", readl(SYS_CTRL_PLLA_CTRL2));
+	printf("  plla_ctrl3 : %08x\n", readl(SYS_CTRL_PLLA_CTRL3));
+
+	clrbits_le32(SYS_CTRL_PLLA_CTRL0, PLL_BYPASS); // Take PLL out of bypass
+	puts("\nPLLA Set\n");
+}
+
+int plla_set_config(int mhz)
+{
+	int index = (mhz - PLL_LOW_FREQ) / PLL_FREQ_STEP;
+	const PLL_CONFIG *cfg;
+
+	if (index < 0 || index > ARRAY_SIZE(C_PLL_CONFIG)) {
+		debug("Freq %d MHz out of range, default to lowest\n", mhz);
+		index = 0;
+	}
+	cfg = &C_PLL_CONFIG[index];
+
+	printf("Attempting to set PLLA to %d MHz ...\n", (unsigned) cfg->mhz);
+	plla_configure(cfg->outdiv, cfg->refdiv, cfg->fbdiv, cfg->bwadj,
+	               cfg->sfreq, cfg->sslope);
+
+	return cfg->mhz;
+}
+
diff --git a/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/pinmux.c b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/pinmux.c
new file mode 100644
index 0000000..a6f5e9a
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/pinmux.c
@@ -0,0 +1,43 @@
+#include <common.h>
+#include <asm/arch/pinmux.h>
+
+void pinmux_set(int bank, int pin, int func)
+{
+	u32 reg;
+	u32 base;
+	/* TODO: check parameters */
+
+	if (bank == PINMUX_BANK_MFA)
+		base = SYS_CONTROL_BASE;
+	else
+		base = SEC_CONTROL_BASE;
+
+	clrbits_le32(base + PINMUX_SECONDARY_SEL, BIT(pin));
+	clrbits_le32(base + PINMUX_TERTIARY_SEL, BIT(pin));
+	clrbits_le32(base + PINMUX_QUATERNARY_SEL, BIT(pin));
+	clrbits_le32(base + PINMUX_DEBUG_SEL, BIT(pin));
+	clrbits_le32(base + PINMUX_ALTERNATIVE_SEL, BIT(pin));
+
+	switch (func) {
+	case PINMUX_GPIO:
+	default:
+		return;
+		break;
+	case PINMUX_2:
+		reg = base + PINMUX_SECONDARY_SEL;
+		break;
+	case PINMUX_3:
+		reg = base + PINMUX_TERTIARY_SEL;
+		break;
+	case PINMUX_4:
+		reg = base + PINMUX_QUATERNARY_SEL;
+		break;
+	case PINMUX_DEBUG:
+		reg = base + PINMUX_DEBUG_SEL;
+		break;
+	case PINMUX_ALT:
+		reg = base + PINMUX_ALTERNATIVE_SEL;
+		break;
+	}
+	setbits_le32(reg, BIT(pin));
+}
diff --git a/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/reset.c b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/reset.c
new file mode 100644
index 0000000..276c912
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/reset.c
@@ -0,0 +1,91 @@
+#include <common.h>
+#include <asm/arch/sysctl.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/clock.h>
+
+void reset_cpu(ulong addr)
+{
+	u32 value;
+
+	// Assert reset to cores as per power on defaults
+	// Don't touch the DDR interface as things will come to an impromptu stop
+	// NB Possibly should be asserting reset for PLLB, but there are timing
+	//    concerns here according to the docs
+
+	value =
+		BIT(SYS_CTRL_RST_COPRO     ) |
+		BIT(SYS_CTRL_RST_USBHS     ) |
+		BIT(SYS_CTRL_RST_USBHSPHYA ) |
+		BIT(SYS_CTRL_RST_MACA      ) |
+		BIT(SYS_CTRL_RST_PCIEA     ) |
+		BIT(SYS_CTRL_RST_SGDMA     ) |
+		BIT(SYS_CTRL_RST_CIPHER    ) |
+		BIT(SYS_CTRL_RST_SATA      ) |
+		BIT(SYS_CTRL_RST_SATA_LINK ) |
+		BIT(SYS_CTRL_RST_SATA_PHY  ) |
+		BIT(SYS_CTRL_RST_PCIEPHY   ) |
+		BIT(SYS_CTRL_RST_STATIC    ) |
+		BIT(SYS_CTRL_RST_UART1     ) |
+		BIT(SYS_CTRL_RST_UART2     ) |
+		BIT(SYS_CTRL_RST_MISC      ) |
+		BIT(SYS_CTRL_RST_I2S       ) |
+		BIT(SYS_CTRL_RST_SD        ) |
+		BIT(SYS_CTRL_RST_MACB      ) |
+		BIT(SYS_CTRL_RST_PCIEB     ) |
+		BIT(SYS_CTRL_RST_VIDEO     ) |
+		BIT(SYS_CTRL_RST_USBHSPHYB ) |
+		BIT(SYS_CTRL_RST_USBDEV    );
+
+	writel(value, SYS_CTRL_RST_SET_CTRL);
+
+	// Release reset to cores as per power on defaults
+	writel(BIT(SYS_CTRL_RST_GPIO), SYS_CTRL_RST_CLR_CTRL);
+
+	// Disable clocks to cores as per power-on defaults - must leave DDR
+	// related clocks enabled otherwise we'll stop rather abruptly.
+	value =
+		BIT(SYS_CTRL_CLK_COPRO) 	|
+		BIT(SYS_CTRL_CLK_DMA)   	|
+		BIT(SYS_CTRL_CLK_CIPHER)	|
+		BIT(SYS_CTRL_CLK_SD)  		|
+		BIT(SYS_CTRL_CLK_SATA)  	|
+		BIT(SYS_CTRL_CLK_I2S)   	|
+		BIT(SYS_CTRL_CLK_USBHS) 	|
+		BIT(SYS_CTRL_CLK_MAC)   	|
+		BIT(SYS_CTRL_CLK_PCIEA)   	|
+		BIT(SYS_CTRL_CLK_STATIC)	|
+		BIT(SYS_CTRL_CLK_MACB)		|
+		BIT(SYS_CTRL_CLK_PCIEB)		|
+		BIT(SYS_CTRL_CLK_REF600)	|
+		BIT(SYS_CTRL_CLK_USBDEV);
+
+	writel(value, SYS_CTRL_CLK_CLR_CTRL);
+
+	// Enable clocks to cores as per power-on defaults
+
+	// Set sys-control pin mux'ing as per power-on defaults
+
+	writel(0, SYS_CONTROL_BASE + PINMUX_SECONDARY_SEL);
+	writel(0, SYS_CONTROL_BASE + PINMUX_TERTIARY_SEL);
+	writel(0, SYS_CONTROL_BASE + PINMUX_QUATERNARY_SEL);
+	writel(0, SYS_CONTROL_BASE + PINMUX_DEBUG_SEL);
+	writel(0, SYS_CONTROL_BASE + PINMUX_ALTERNATIVE_SEL);
+	writel(0, SYS_CONTROL_BASE + PINMUX_PULLUP_SEL);
+
+	writel(0, SEC_CONTROL_BASE + PINMUX_SECONDARY_SEL);
+	writel(0, SEC_CONTROL_BASE + PINMUX_TERTIARY_SEL);
+	writel(0, SEC_CONTROL_BASE + PINMUX_QUATERNARY_SEL);
+	writel(0, SEC_CONTROL_BASE + PINMUX_DEBUG_SEL);
+	writel(0, SEC_CONTROL_BASE + PINMUX_ALTERNATIVE_SEL);
+	writel(0, SEC_CONTROL_BASE + PINMUX_PULLUP_SEL);
+
+	// No need to save any state, as the ROM loader can determine whether reset
+	// is due to power cycling or programatic action, just hit the (self-
+	// clearing) CPU reset bit of the block reset register
+	value =
+		BIT(SYS_CTRL_RST_SCU) |
+		BIT(SYS_CTRL_RST_ARM0) |
+		BIT(SYS_CTRL_RST_ARM1);
+
+	writel(value, SYS_CTRL_RST_SET_CTRL);
+}
diff --git a/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/timer.c b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/timer.c
new file mode 100644
index 0000000..5e876080
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/cpu/arm1136/nas782x/timer.c
@@ -0,0 +1,129 @@
+/*
+ * (C) Copyright 2004
+ * Texas Instruments
+ * Richard Woodruff <r-woodruff2@ti.com>
+ *
+ * (C) Copyright 2002
+ * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
+ * Marius Groeger <mgroeger@sysgo.de>
+ * Alex Zuepke <azu@sysgo.de>
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#define TIMER_CLOCK	(CONFIG_SYS_CLK_FREQ / (1 << (CONFIG_TIMER_PRESCALE * 4)))
+#define TIMER_LOAD_VAL 0xFFFFFF
+
+/* macro to read the 32 bit timer */
+#define READ_TIMER	(TIMER_LOAD_VAL - readl(CONFIG_SYS_TIMERBASE + TIMER_CURR)) \
+			/ (TIMER_CLOCK / CONFIG_SYS_HZ)
+
+#define READ_TIMER_HW	(TIMER_LOAD_VAL - readl(CONFIG_SYS_TIMERBASE + TIMER_CURR))
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int timer_init (void)
+{
+	int32_t val;
+
+	/* Start the counter ticking up */
+	writel(TIMER_LOAD_VAL, CONFIG_SYS_TIMERBASE + TIMER_LOAD);	/* reload value on overflow*/
+
+	val = (CONFIG_TIMER_PRESCALE << TIMER_PRESCALE_SHIFT) |
+			(TIMER_MODE_PERIODIC << TIMER_MODE_SHIFT) |
+			(TIMER_ENABLE << TIMER_ENABLE_SHIFT);		/* mask to enable timer*/
+	writel(val, CONFIG_SYS_TIMERBASE + TIMER_CTRL);	/* start timer */
+
+	/* reset time */
+	gd->arch.lastinc = READ_TIMER;	/* capture current incrementer value */
+	gd->arch.tbl = 0;		/* start "advancing" time stamp */
+
+	return(0);
+}
+/*
+ * timer without interrupts
+ */
+ulong get_timer (ulong base)
+{
+	return get_timer_masked () - base;
+}
+
+/* delay x useconds AND preserve advance timestamp value */
+void __udelay (unsigned long usec)
+{
+	ulong tmo, tmp;
+
+	if (usec > 100000) {		/* if "big" number, spread normalization to seconds */
+		tmo = usec / 1000;	/* start to normalize for usec to ticks per sec */
+		tmo *= CONFIG_SYS_HZ;	/* find number of "ticks" to wait to achieve target */
+		tmo /= 1000;		/* finish normalize. */
+
+		tmp = get_timer (0);		/* get current timestamp */
+		while (get_timer (tmp) < tmo)/* loop till event */
+			/*NOP*/;
+	} else {			/* else small number, convert to hw ticks */
+		tmo = usec * (TIMER_CLOCK / 1000) / 1000;
+		/* timeout is no more than 0.1s, and the hw timer will roll over at most once */
+		tmp = READ_TIMER_HW;
+		while (((READ_TIMER_HW -tmp) & TIMER_LOAD_VAL) < tmo)/* loop till event */
+			/*NOP*/;
+	}
+}
+
+ulong get_timer_masked (void)
+{
+	ulong now = READ_TIMER;		/* current tick value */
+
+	if (now >= gd->arch.lastinc) {		/* normal mode (non roll) */
+		/* move stamp fordward with absoulte diff ticks */
+		gd->arch.tbl += (now - gd->arch.lastinc);
+	} else {
+		/* we have rollover of incrementer */
+		gd->arch.tbl += ((TIMER_LOAD_VAL / (TIMER_CLOCK / CONFIG_SYS_HZ))
+				 - gd->arch.lastinc) + now;
+	}
+	gd->arch.lastinc = now;
+	return gd->arch.tbl;
+}
+
+
+/*
+ * This function is derived from PowerPC code (read timebase as long long).
+ * On ARM it just returns the timer value.
+ */
+unsigned long long get_ticks(void)
+{
+	return get_timer(0);
+}
+/*
+ * This function is derived from PowerPC code (timebase clock frequency).
+ * On ARM it returns the number of timer ticks per second.
+ */
+ulong get_tbclk (void)
+{
+	ulong tbclk;
+	tbclk = CONFIG_SYS_HZ;
+	return tbclk;
+}
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/clock.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/clock.h
new file mode 100644
index 0000000..da7dd1c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/clock.h
@@ -0,0 +1,84 @@
+#ifndef _NAS782X_CLOCK_H
+#define _NAS782X_CLOCK_H
+
+#include <asm/arch/sysctl.h>
+#include <asm/arch/cpu.h>
+
+/* bit numbers of clock control register */
+#define SYS_CTRL_CLK_COPRO  0
+#define SYS_CTRL_CLK_DMA    1
+#define SYS_CTRL_CLK_CIPHER 2
+#define SYS_CTRL_CLK_SD     3
+#define SYS_CTRL_CLK_SATA   4
+#define SYS_CTRL_CLK_I2S    5
+#define SYS_CTRL_CLK_USBHS  6
+#define SYS_CTRL_CLK_MACA   7
+#define SYS_CTRL_CLK_MAC   SYS_CTRL_CLK_MACA
+#define SYS_CTRL_CLK_PCIEA  8
+#define SYS_CTRL_CLK_STATIC 9
+#define SYS_CTRL_CLK_MACB   10
+#define SYS_CTRL_CLK_PCIEB  11
+#define SYS_CTRL_CLK_REF600 12
+#define SYS_CTRL_CLK_USBDEV 13
+#define SYS_CTRL_CLK_DDR    14
+#define SYS_CTRL_CLK_DDRPHY 15
+#define SYS_CTRL_CLK_DDRCK  16
+
+/* bit numbers of reset control register */
+#define SYS_CTRL_RST_SCU          0
+#define SYS_CTRL_RST_COPRO        1
+#define SYS_CTRL_RST_ARM0         2
+#define SYS_CTRL_RST_ARM1         3
+#define SYS_CTRL_RST_USBHS        4
+#define SYS_CTRL_RST_USBHSPHYA    5
+#define SYS_CTRL_RST_MACA         6
+#define SYS_CTRL_RST_MAC	SYS_CTRL_RST_MACA
+#define SYS_CTRL_RST_PCIEA        7
+#define SYS_CTRL_RST_SGDMA        8
+#define SYS_CTRL_RST_CIPHER       9
+#define SYS_CTRL_RST_DDR          10
+#define SYS_CTRL_RST_SATA         11
+#define SYS_CTRL_RST_SATA_LINK    12
+#define SYS_CTRL_RST_SATA_PHY     13
+#define SYS_CTRL_RST_PCIEPHY      14
+#define SYS_CTRL_RST_STATIC       15
+#define SYS_CTRL_RST_GPIO         16
+#define SYS_CTRL_RST_UART1        17
+#define SYS_CTRL_RST_UART2        18
+#define SYS_CTRL_RST_MISC         19
+#define SYS_CTRL_RST_I2S          20
+#define SYS_CTRL_RST_SD           21
+#define SYS_CTRL_RST_MACB         22
+#define SYS_CTRL_RST_PCIEB        23
+#define SYS_CTRL_RST_VIDEO        24
+#define SYS_CTRL_RST_DDR_PHY      25
+#define SYS_CTRL_RST_USBHSPHYB    26
+#define SYS_CTRL_RST_USBDEV       27
+#define SYS_CTRL_RST_ARMDBG       29
+#define SYS_CTRL_RST_PLLA         30
+#define SYS_CTRL_RST_PLLB         31
+
+static inline void reset_block(int block, int reset)
+{
+	u32 reg;
+	if (reset)
+		reg = SYS_CTRL_RST_SET_CTRL;
+	else
+		reg = SYS_CTRL_RST_CLR_CTRL;
+
+	writel(BIT(block), reg);
+}
+
+static inline void enable_clock(int block)
+{
+	writel(BIT(block), SYS_CTRL_CLK_SET_CTRL);
+}
+
+static inline void disable_clock(int block)
+{
+	writel(BIT(block), SYS_CTRL_CLK_CLR_CTRL);
+}
+
+int plla_set_config(int idx);
+
+#endif /* _NAS782X_CLOCK_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/cpu.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/cpu.h
new file mode 100644
index 0000000..11e803c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/cpu.h
@@ -0,0 +1,26 @@
+#ifndef _NAS782X_CPU_H
+#define _NAS782X_CPU_H
+
+#if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__))
+#include <asm/types.h>
+#include <asm/io.h>
+#endif /* !(__KERNEL_STRICT_NAMES || __ASSEMBLY__) */
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/timer.h>
+
+#ifndef __KERNEL_STRICT_NAMES
+#ifndef __ASSEMBLY__
+
+#define BIT(x)                  (1 << (x))
+
+/* fix "implicit declaration of function" warnning */
+void *memalign(size_t alignment, size_t bytes);
+void free(void* mem);
+void *malloc(size_t bytes);
+void *calloc(size_t n, size_t elem_size);
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL_STRICT_NAMES */
+
+#endif /* _NAS782X_CPU_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/hardware.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/hardware.h
new file mode 100644
index 0000000..f26b17f
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/hardware.h
@@ -0,0 +1,30 @@
+#ifndef _NAS782X_HARDWARE_H
+#define _NAS782X_HARDWARE_H
+
+/* Core addresses */
+#define USB_HOST_BASE		0x40200000
+#define MACA_BASE		0x40400000
+#define MACB_BASE		0x40800000
+#define MAC_BASE		MACA_BASE
+#define STATIC_CS0_BASE		0x41000000
+#define STATIC_CS1_BASE		0x41400000
+#define STATIC_CONTROL_BASE	0x41C00000
+#define SATA_DATA_BASE		0x42000000 /* non-functional, DMA just needs an address */
+#define GPIO_1_BASE		0x44000000
+#define GPIO_2_BASE		0x44100000
+#define UART_1_BASE		0x44200000
+#define UART_2_BASE		0x44300000
+#define SYS_CONTROL_BASE	0x44e00000
+#define SEC_CONTROL_BASE	0x44f00000
+#define RPSA_BASE		0x44400000
+#define RPSC_BASE		0x44500000
+#define DDR_BASE		0x44700000
+
+#define SATA_BASE		0x45900000
+#define SATA_0_REGS_BASE	0x45900000
+#define SATA_1_REGS_BASE	0x45910000
+#define SATA_DMA_REGS_BASE	0x459a0000
+#define SATA_SGDMA_REGS_BASE	0x459b0000
+#define SATA_HOST_REGS_BASE	0x459e0000
+
+#endif /* _NAS782X_HARDWARE_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/pinmux.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/pinmux.h
new file mode 100644
index 0000000..810ba5c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/pinmux.h
@@ -0,0 +1,46 @@
+#ifndef _NAS782X_PINMUX_H
+#define _NAS782X_PINMUX_H
+
+#include <asm/arch/cpu.h>
+
+#define PINMUX_GPIO		0
+#define PINMUX_2		1
+#define PINMUX_3		2
+#define PINMUX_4		3
+#define PINMUX_DEBUG		4
+#define PINMUX_ALT		5
+
+#define PINMUX_BANK_MFA		0
+#define PINMUX_BANK_MFB		1
+
+/* System control multi-function pin function selection */
+#define PINMUX_SECONDARY_SEL		0x14
+#define PINMUX_TERTIARY_SEL		0x8c
+#define PINMUX_QUATERNARY_SEL		0x94
+#define PINMUX_DEBUG_SEL		0x9c
+#define PINMUX_ALTERNATIVE_SEL		0xa4
+#define PINMUX_PULLUP_SEL		0xac
+
+#define PINMUX_UARTA_SIN		PINMUX_ALT
+#define PINMUX_UARTA_SOUT		PINMUX_ALT
+
+#define PINMUX_STATIC_DATA0		PINMUX_2
+#define PINMUX_STATIC_DATA1		PINMUX_2
+#define PINMUX_STATIC_DATA2		PINMUX_2
+#define PINMUX_STATIC_DATA3		PINMUX_2
+#define PINMUX_STATIC_DATA4		PINMUX_2
+#define PINMUX_STATIC_DATA5		PINMUX_2
+#define PINMUX_STATIC_DATA6		PINMUX_2
+#define PINMUX_STATIC_DATA7		PINMUX_2
+#define PINMUX_STATIC_NWE		PINMUX_2
+#define PINMUX_STATIC_NOE		PINMUX_2
+#define PINMUX_STATIC_NCS		PINMUX_2
+#define PINMUX_STATIC_ADDR18		PINMUX_2
+#define PINMUX_STATIC_ADDR19		PINMUX_2
+
+#define PINMUX_MACA_MDC			PINMUX_2
+#define PINMUX_MACA_MDIO		PINMUX_2
+
+extern void pinmux_set(int bank, int pin, int func);
+
+#endif /* _NAS782X_PINMUX_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/spl.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/spl.h
new file mode 100644
index 0000000..f73afda
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/spl.h
@@ -0,0 +1,6 @@
+#ifndef _NAS782X_SPL_H
+#define _NAS782X_SPL_H
+
+#include <asm/arch/cpu.h>
+
+#endif /* _NAS782X_SPL_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/sysctl.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/sysctl.h
new file mode 100644
index 0000000..3867e45
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/sysctl.h
@@ -0,0 +1,125 @@
+#ifndef _NAS782X_SYSCTL_H
+#define _NAS782X_SYSCTL_H
+
+#if !(defined(__KERNEL_STRICT_NAMES) || defined(__ASSEMBLY__))
+#include <asm/types.h>
+#endif /* !(__KERNEL_STRICT_NAMES || __ASSEMBLY__) */
+
+#include <asm/arch/hardware.h>
+
+/**
+ * System block reset and clock control
+ */
+#define SYS_CTRL_PCI_STAT		(SYS_CONTROL_BASE + 0x20)
+#define SYS_CTRL_CLK_SET_CTRL		(SYS_CONTROL_BASE + 0x2C)
+#define SYS_CTRL_CLK_CLR_CTRL		(SYS_CONTROL_BASE + 0x30)
+#define SYS_CTRL_RST_SET_CTRL		(SYS_CONTROL_BASE + 0x34)
+#define SYS_CTRL_RST_CLR_CTRL		(SYS_CONTROL_BASE + 0x38)
+#define SYS_CTRL_PLLSYS_CTRL		(SYS_CONTROL_BASE + 0x48)
+#define SYS_CTRL_PLLSYS_KEY_CTRL	(SYS_CONTROL_BASE + 0x6C)
+#define SYS_CTRL_GMAC_CTRL		(SYS_CONTROL_BASE + 0x78)
+
+/* Scratch registers */
+#define SYS_CTRL_SCRATCHWORD0		(SYS_CONTROL_BASE + 0xc4)
+#define SYS_CTRL_SCRATCHWORD1		(SYS_CONTROL_BASE + 0xc8)
+#define SYS_CTRL_SCRATCHWORD2		(SYS_CONTROL_BASE + 0xcc)
+#define SYS_CTRL_SCRATCHWORD3		(SYS_CONTROL_BASE + 0xd0)
+
+#define SYS_CTRL_PLLA_CTRL0		(SYS_CONTROL_BASE + 0x1F0)
+#define SYS_CTRL_PLLA_CTRL1		(SYS_CONTROL_BASE + 0x1F4)
+#define SYS_CTRL_PLLA_CTRL2		(SYS_CONTROL_BASE + 0x1F8)
+#define SYS_CTRL_PLLA_CTRL3		(SYS_CONTROL_BASE + 0x1FC)
+
+#define SYS_CTRL_GMAC_AUTOSPEED		3
+#define SYS_CTRL_GMAC_RGMII		2
+#define SYS_CTRL_GMAC_SIMPLE_MUX	1
+#define SYS_CTRL_GMAC_CKEN_GTX		0
+
+#define SYS_CTRL_CKCTRL_CTRL_ADDR	(SYS_CONTROL_BASE + 0x64)
+
+#define SYS_CTRL_CKCTRL_PCI_DIV_BIT	0
+#define SYS_CTRL_CKCTRL_SLOW_BIT	8
+
+
+#define SYS_CTRL_USBHSMPH_CTRL		(SYS_CONTROL_BASE + 0x40)
+#define SYS_CTRL_USBHSMPH_STAT		(SYS_CONTROL_BASE + 0x44)
+#define SYS_CTRL_REF300_DIV		(SYS_CONTROL_BASE + 0xF8)
+#define SYS_CTRL_USBHSPHY_CTRL		(SYS_CONTROL_BASE + 0x84)
+#define SYS_CTRL_USB_CTRL		(SYS_CONTROL_BASE + 0x90)
+
+/* System control multi-function pin function selection */
+#define SYS_CTRL_SECONDARY_SEL		(SYS_CONTROL_BASE + 0x14)
+#define SYS_CTRL_TERTIARY_SEL		(SYS_CONTROL_BASE + 0x8c)
+#define SYS_CTRL_QUATERNARY_SEL		(SYS_CONTROL_BASE + 0x94)
+#define SYS_CTRL_DEBUG_SEL		(SYS_CONTROL_BASE + 0x9c)
+#define SYS_CTRL_ALTERNATIVE_SEL	(SYS_CONTROL_BASE + 0xa4)
+#define SYS_CTRL_PULLUP_SEL		(SYS_CONTROL_BASE + 0xac)
+
+/* Secure control multi-function pin function selection */
+#define SEC_CTRL_SECONDARY_SEL		(SEC_CONTROL_BASE + 0x14)
+#define SEC_CTRL_TERTIARY_SEL		(SEC_CONTROL_BASE + 0x8c)
+#define SEC_CTRL_QUATERNARY_SEL		(SEC_CONTROL_BASE + 0x94)
+#define SEC_CTRL_DEBUG_SEL		(SEC_CONTROL_BASE + 0x9c)
+#define SEC_CTRL_ALTERNATIVE_SEL	(SEC_CONTROL_BASE + 0xa4)
+#define SEC_CTRL_PULLUP_SEL		(SEC_CONTROL_BASE + 0xac)
+
+#define SEC_CTRL_COPRO_CTRL		(SEC_CONTROL_BASE + 0x68)
+#define SEC_CTRL_SECURE_CTRL		(SEC_CONTROL_BASE + 0x98)
+#define SEC_CTRL_LEON_DEBUG		(SEC_CONTROL_BASE + 0xF0)
+#define SEC_CTRL_PLLB_DIV_CTRL		(SEC_CONTROL_BASE + 0xF8)
+#define SEC_CTRL_PLLB_CTRL0		(SEC_CONTROL_BASE + 0x1F0)
+#define SEC_CTRL_PLLB_CTRL1		(SEC_CONTROL_BASE + 0x1F4)
+#define SEC_CTRL_PLLB_CTRL8		(SEC_CONTROL_BASE + 0x1F4)
+
+#define REF300_DIV_INT_SHIFT		8
+#define REF300_DIV_FRAC_SHIFT		0
+#define REF300_DIV_INT(val)		((val) << REF300_DIV_INT_SHIFT)
+#define REF300_DIV_FRAC(val)		((val) << REF300_DIV_FRAC_SHIFT)
+
+#define USBHSPHY_SUSPENDM_MANUAL_ENABLE		16
+#define USBHSPHY_SUSPENDM_MANUAL_STATE		15
+#define USBHSPHY_ATE_ESET			14
+#define USBHSPHY_TEST_DIN			6
+#define USBHSPHY_TEST_ADD			2
+#define USBHSPHY_TEST_DOUT_SEL			1
+#define USBHSPHY_TEST_CLK			0
+
+#define USB_CTRL_USBAPHY_CKSEL_SHIFT	5
+#define USB_CLK_XTAL0_XTAL1		(0 << USB_CTRL_USBAPHY_CKSEL_SHIFT)
+#define USB_CLK_XTAL0			(1 << USB_CTRL_USBAPHY_CKSEL_SHIFT)
+#define USB_CLK_INTERNAL		(2 << USB_CTRL_USBAPHY_CKSEL_SHIFT)
+
+#define USBAMUX_DEVICE			BIT(4)
+
+#define USBPHY_REFCLKDIV_SHIFT		2
+#define USB_PHY_REF_12MHZ		(0 << USBPHY_REFCLKDIV_SHIFT)
+#define USB_PHY_REF_24MHZ		(1 << USBPHY_REFCLKDIV_SHIFT)
+#define USB_PHY_REF_48MHZ		(2 << USBPHY_REFCLKDIV_SHIFT)
+
+#define USB_CTRL_USB_CKO_SEL_BIT	0
+
+#define USB_INT_CLK_XTAL 		0
+#define USB_INT_CLK_REF300		2
+#define USB_INT_CLK_PLLB		3
+
+#define SYS_CTRL_GMAC_AUTOSPEED		3
+#define SYS_CTRL_GMAC_RGMII		2
+#define SYS_CTRL_GMAC_SIMPLE_MUX	1
+#define SYS_CTRL_GMAC_CKEN_GTX		0
+
+
+#define PLLB_ENSAT			3
+#define PLLB_OUTDIV			4
+#define PLLB_REFDIV			8
+#define PLLB_DIV_INT_SHIFT		8
+#define PLLB_DIV_FRAC_SHIFT		0
+#define PLLB_DIV_INT(val)		((val) << PLLB_DIV_INT_SHIFT)
+#define PLLB_DIV_FRAC(val)		((val) << PLLB_DIV_FRAC_SHIFT)
+
+#ifndef __KERNEL_STRICT_NAMES
+#ifndef __ASSEMBLY__
+
+#endif /* __ASSEMBLY__ */
+#endif /* __KERNEL_STRICT_NAMES */
+
+#endif /* _NAS782X_SYSCTL_H */
diff --git a/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/timer.h b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/timer.h
new file mode 100644
index 0000000..ea4d71e
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/arch/arm/include/asm/arch-nas782x/timer.h
@@ -0,0 +1,23 @@
+#ifndef _NAS782X_TIMER_H
+#define _NAS782X_TIMER_H
+
+#define TIMER1_BASE		(RPSA_BASE + 0x200)
+#define TIMER2_BASE		(RPSA_BASE + 0x220)
+
+#define TIMER_LOAD		0
+#define TIMER_CURR		4
+#define TIMER_CTRL		8
+#define	TIMER_INTR		0x0C
+
+#define TIMER_PRESCALE_SHIFT		2
+#define TIMER_PRESCALE_1		0
+#define TIMER_PRESCALE_16		1
+#define TIMER_PRESCALE_256		2
+#define TIMER_MODE_SHIFT		6
+#define TIMER_MODE_FREE_RUNNING		0
+#define TIMER_MODE_PERIODIC		1
+#define TIMER_ENABLE_SHIFT		7
+#define TIMER_DISABLE			0
+#define TIMER_ENABLE			1
+
+#endif /* _NAS782X_TIMER_H */
diff --git a/package/boot/uboot-oxnas/src/board/ox820/Kconfig b/package/boot/uboot-oxnas/src/board/ox820/Kconfig
new file mode 100644
index 0000000..8f631aa
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_OX820
+
+config SYS_CPU
+	default "arm1136"
+
+config SYS_SOC
+	default "nas782x"
+
+config SYS_BOARD
+	default "ox820"
+
+config SYS_CONFIG_NAME
+	default "ox820"
+
+endif
diff --git a/package/boot/uboot-oxnas/src/board/ox820/MAINTAINERS b/package/boot/uboot-oxnas/src/board/ox820/MAINTAINERS
new file mode 100644
index 0000000..a86ba26
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/MAINTAINERS
@@ -0,0 +1,6 @@
+SHEEVAPLUG BOARD
+M:	Daniel Golle <daniel@makrotopia.org>
+S:	Maintained
+F:	board/ox820/
+F:	include/configs/ox820.h
+F:	configs/ox820_defconfig
diff --git a/package/boot/uboot-oxnas/src/board/ox820/Makefile b/package/boot/uboot-oxnas/src/board/ox820/Makefile
new file mode 100644
index 0000000..445fc4c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/Makefile
@@ -0,0 +1,15 @@
+#
+# (C) Copyright 2000-2006
+# Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+#
+# (C) Copyright 2008-2009 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += ox820.o
+obj-y += lowlevel_init.o
+
+obj-$(CONFIG_SPL_BUILD) += spl_start.o
+obj-$(CONFIG_SPL_BUILD) += ddr.o
+
diff --git a/package/boot/uboot-oxnas/src/board/ox820/ddr.c b/package/boot/uboot-oxnas/src/board/ox820/ddr.c
new file mode 100644
index 0000000..a665722
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/ddr.c
@@ -0,0 +1,477 @@
+/*******************************************************************
+ *
+ * File:            ddr_oxsemi.c
+ *
+ * Description:     Declarations for DDR routines and data objects
+ *
+ * Author:          Julien Margetts
+ *
+ * Copyright:       Oxford Semiconductor Ltd, 2009
+ */
+#include <common.h>
+#include <asm/arch/clock.h>
+
+#include "ddr.h"
+
+typedef unsigned int UINT;
+
+// DDR TIMING PARAMETERS
+typedef struct {
+	unsigned int holdoff_cmd_A;
+	unsigned int holdoff_cmd_ARW;
+	unsigned int holdoff_cmd_N;
+	unsigned int holdoff_cmd_LM;
+	unsigned int holdoff_cmd_R;
+	unsigned int holdoff_cmd_W;
+	unsigned int holdoff_cmd_PC;
+	unsigned int holdoff_cmd_RF;
+	unsigned int holdoff_bank_R;
+	unsigned int holdoff_bank_W;
+	unsigned int holdoff_dir_RW;
+	unsigned int holdoff_dir_WR;
+	unsigned int holdoff_FAW;
+	unsigned int latency_CAS;
+	unsigned int latency_WL;
+	unsigned int recovery_WR;
+	unsigned int width_update;
+	unsigned int odt_offset;
+	unsigned int odt_drive_all;
+	unsigned int use_fixed_re;
+	unsigned int delay_wr_to_re;
+	unsigned int wr_slave_ratio;
+	unsigned int rd_slave_ratio0;
+	unsigned int rd_slave_ratio1;
+} T_DDR_TIMING_PARAMETERS;
+
+// DDR CONFIG PARAMETERS
+
+typedef struct {
+	unsigned int ddr_mode;
+	unsigned int width;
+	unsigned int blocs;
+	unsigned int banks8;
+	unsigned int rams;
+	unsigned int asize;
+	unsigned int speed;
+	unsigned int cmd_mode_wr_cl_bl;
+} T_DDR_CONFIG_PARAMETERS;
+
+//cmd_mode_wr_cl_bl
+//when SDR : cmd_mode_wr_cl_bl = 0x80200002 + (latency_CAS_RAM * 16) + (recovery_WR - 1) * 512; -- Sets write rec XX, CL=XX; BL=8
+//else       cmd_mode_wr_cl_bl = 0x80200003 + (latency_CAS_RAM * 16) + (recovery_WR - 1) * 512; -- Sets write rec XX, CL=XX; BL=8
+
+//                                                            cmd_                    bank_ dir_     lat_  rec_ width_ odt_   odt_ fix delay     ratio
+//                                                                A                                F  C         update offset all  re  re_to_we  w  r0  r1
+//                                                                R     L        P  R        R  W  A  A  W  W
+//Timing Parameters                                            A  W  N  M  R  W  C  F  R  W  W  R  W  S  L  R
+static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25E_CL5_1GB = { 4, 5, 0, 2, 4, 4,
+	5, 51, 23, 24, 9, 11, 18, 5, 4, 6, 3, 2, 0, 1, 2, 75, 56, 56 }; //elida device.
+static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25E_CL5_2GB = { 4, 5, 0, 2, 4, 4,
+	5, 79, 22, 24, 9, 11, 20, 5, 4, 6, 3, 2, 0, 1, 2, 75, 56, 56 };
+static const T_DDR_TIMING_PARAMETERS C_TP_DDR2_25_CL6_1GB = { 4, 5, 0, 2, 4, 4,
+	4, 51, 22, 26, 10, 12, 18, 6, 5, 6, 3, 2, 0, 1, 2, 75, 56, 56 }; // 400MHz, Speedgrade 25 timings (1Gb parts)
+
+//                                                          D     B  B  R  A   S
+//                                                          D  W  L  K  A  S   P
+//Config Parameters                                         R  D  C  8  M  Z   D CMD_MODE
+//static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25E_CL5  = { 2,16, 1, 0, 1, 32,25,0x80200A53}; // 64 MByte
+static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25E_CL5 = { 2, 16, 1, 1, 1, 64,
+	25, 0x80200A53 }; // 128 MByte
+static const T_DDR_CONFIG_PARAMETERS C_CP_DDR2_25_CL6 = { 2, 16, 1, 1, 1, 128,
+	25, 0x80200A63 }; // 256 MByte
+
+static void ddr_phy_poll_until_locked(void)
+{
+	volatile UINT reg_tmp = 0;
+	volatile UINT locked = 0;
+
+	//Extra read to put in delay before starting to poll...
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2;      // read
+
+	//POLL C_DDR_PHY2_REG register until clock and flock
+	//!!! Ideally have a timeout on this.
+	while (locked == 0) {
+		reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2;      // read
+
+		//locked when bits 30 and 31 are set
+		if (reg_tmp & 0xC0000000) {
+			locked = 1;
+		}
+	}
+}
+
+static void ddr_poll_until_not_busy(void)
+{
+	volatile UINT reg_tmp = 0;
+	volatile UINT busy = 1;
+
+	//Extra read to put in delay before starting to poll...
+	reg_tmp = *(volatile UINT *) C_DDR_STAT_REG;      // read
+
+	//POLL DDR_STAT register until no longer busy
+	//!!! Ideally have a timeout on this.
+	while (busy == 1) {
+		reg_tmp = *(volatile UINT *) C_DDR_STAT_REG;      // read
+
+		//when bit 31 is clear - core is no longer busy
+		if ((reg_tmp & 0x80000000) == 0x00000000) {
+			busy = 0;
+		}
+	}
+}
+
+static void ddr_issue_command(int commmand)
+{
+	*(volatile UINT *) C_DDR_CMD_REG = commmand;
+	ddr_poll_until_not_busy();
+}
+
+static void ddr_timing_initialisation(
+	const T_DDR_TIMING_PARAMETERS *ddr_timing_parameters)
+{
+	volatile UINT reg_tmp = 0;
+	/* update the DDR controller registers for timing parameters */
+	reg_tmp = (ddr_timing_parameters->holdoff_cmd_A << 0);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_ARW << 4);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_N << 8);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_LM << 12);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_R << 16);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_W << 20);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_cmd_PC << 24);
+	*(volatile UINT *) C_DDR_REG_TIMING0 = reg_tmp;
+
+	reg_tmp = (ddr_timing_parameters->holdoff_cmd_RF << 0);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_bank_R << 8);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_bank_W << 16);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_dir_RW << 24);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_dir_WR << 28);
+	*(volatile UINT *) C_DDR_REG_TIMING1 = reg_tmp;
+
+	reg_tmp = (ddr_timing_parameters->latency_CAS << 0);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->latency_WL << 4);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->holdoff_FAW << 8);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->width_update << 16);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->odt_offset << 21);
+	reg_tmp = reg_tmp + (ddr_timing_parameters->odt_drive_all << 24);
+
+	*(volatile UINT *) C_DDR_REG_TIMING2 = reg_tmp;
+
+	/* Program the timing parameters in the PHY too */
+	reg_tmp = (ddr_timing_parameters->use_fixed_re << 16)
+			| (ddr_timing_parameters->delay_wr_to_re << 8)
+			| (ddr_timing_parameters->latency_WL << 4)
+			| (ddr_timing_parameters->latency_CAS << 0);
+
+	*(volatile UINT *) C_DDR_REG_PHY_TIMING = reg_tmp;
+
+	reg_tmp = ddr_timing_parameters->wr_slave_ratio;
+
+	*(volatile UINT *) C_DDR_REG_PHY_WR_RATIO = reg_tmp;
+
+	reg_tmp = ddr_timing_parameters->rd_slave_ratio0;
+	reg_tmp += ddr_timing_parameters->rd_slave_ratio1 << 8;
+
+	*(volatile UINT *) C_DDR_REG_PHY_RD_RATIO = reg_tmp;
+
+}
+
+static void ddr_normal_initialisation(
+	const T_DDR_CONFIG_PARAMETERS *ddr_config_parameters, int mhz)
+{
+	int i;
+	volatile UINT tmp = 0;
+	volatile UINT reg_tmp = 0;
+	volatile UINT emr_cmd = 0;
+	UINT refresh;
+
+	//Total size of memory in Mbits...
+	tmp = ddr_config_parameters->rams * ddr_config_parameters->asize
+		* ddr_config_parameters->width;
+	//Deduce value to program into DDR_CFG register...
+	switch (tmp) {
+	case 16:
+		reg_tmp = 0x00020000 * 1;
+		break;
+	case 32:
+		reg_tmp = 0x00020000 * 2;
+		break;
+	case 64:
+		reg_tmp = 0x00020000 * 3;
+		break;
+	case 128:
+		reg_tmp = 0x00020000 * 4;
+		break;
+	case 256:
+		reg_tmp = 0x00020000 * 5;
+		break;
+	case 512:
+		reg_tmp = 0x00020000 * 6;
+		break;
+	case 1024:
+		reg_tmp = 0x00020000 * 7;
+		break;
+	case 2048:
+		reg_tmp = 0x00020000 * 8;
+		break;
+	default:
+		reg_tmp = 0; //forces sims not to work if badly configured
+	}
+
+	//Memory width
+	tmp = ddr_config_parameters->rams * ddr_config_parameters->width;
+	switch (tmp) {
+	case 8:
+		reg_tmp = reg_tmp + 0x00400000;
+		break;
+	case 16:
+		reg_tmp = reg_tmp + 0x00200000;
+		break;
+	case 32:
+		reg_tmp = reg_tmp + 0x00000000;
+		break;
+	default:
+		reg_tmp = 0; //forces sims not to work if badly configured
+	}
+
+	//Setup DDR Mode
+	switch (ddr_config_parameters->ddr_mode) {
+	case 0:
+		reg_tmp = reg_tmp + 0x00000000;
+		break;   //SDR
+	case 1:
+		reg_tmp = reg_tmp + 0x40000000;
+		break;   //DDR
+	case 2:
+		reg_tmp = reg_tmp + 0x80000000;
+		break;   //DDR2
+	default:
+		reg_tmp = 0; //forces sims not to work if badly configured
+	}
+
+	//Setup Banks
+	if (ddr_config_parameters->banks8 == 1) {
+		reg_tmp = reg_tmp + 0x00800000;
+	}
+
+	//Program DDR_CFG register...
+	*(volatile UINT *) C_DDR_CFG_REG = reg_tmp;
+
+	//Configure PHY0 reg - se_mode is bit 1,
+	//needs to be 1 for DDR (single_ended drive)
+	switch (ddr_config_parameters->ddr_mode) {
+	case 0:
+		reg_tmp = 2 + (0 << 4);
+		break;   //SDR
+	case 1:
+		reg_tmp = 2 + (4 << 4);
+		break;   //DDR
+	case 2:
+		reg_tmp = 0 + (4 << 4);
+		break;   //DDR2
+	default:
+		reg_tmp = 0;
+	}
+
+	//Program DDR_PHY0 register...
+	*(volatile UINT *) C_DDR_REG_PHY0 = reg_tmp;
+
+	//Read DDR_PHY* registers to exercise paths for vcd
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY3;
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2;
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY1;
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY0;
+
+	//Start up sequences - Different dependant on DDR mode
+	switch (ddr_config_parameters->ddr_mode) {
+	case 2:   //DDR2
+		//Start-up sequence: follows procedure described in Micron datasheet.
+		//start up DDR PHY DLL
+		reg_tmp = 0x00022828;       // dll on, start point and inc = h28
+		*(volatile UINT *) C_DDR_REG_PHY2 = reg_tmp;
+
+		reg_tmp = 0x00032828; // start on, dll on, start point and inc = h28
+		*(volatile UINT *) C_DDR_REG_PHY2 = reg_tmp;
+
+		ddr_phy_poll_until_locked();
+
+		udelay(200);   //200us
+
+		//Startup SDRAM...
+		//!!! Software: CK should be running for 200us before wake-up
+		ddr_issue_command( C_CMD_WAKE_UP);
+		ddr_issue_command( C_CMD_NOP);
+		ddr_issue_command( C_CMD_PRECHARGE_ALL);
+		ddr_issue_command( C_CMD_DDR2_EMR2);
+		ddr_issue_command( C_CMD_DDR2_EMR3);
+
+		emr_cmd = C_CMD_DDR2_EMR1 + C_CMD_ODT_75 + C_CMD_REDUCED_DRIVE
+			+ C_CMD_ENABLE_DLL;
+
+		ddr_issue_command(emr_cmd);
+		//Sets CL=3; BL=8 but also reset DLL to trigger a DLL initialisation...
+		udelay(1);   //1us
+		ddr_issue_command(
+			ddr_config_parameters->cmd_mode_wr_cl_bl
+			+ C_CMD_RESET_DLL);
+		udelay(1);   //1us
+
+		//!!! Software: Wait 200 CK cycles before...
+		//for(i=1; i<=2; i++) {
+		ddr_issue_command(C_CMD_PRECHARGE_ALL);
+		// !!! Software: Wait here at least 8 CK cycles
+		//}
+		//need a wait here to ensure PHY DLL lock before the refresh is issued
+		udelay(1);   //1us
+		for (i = 1; i <= 2; i++) {
+			ddr_issue_command( C_CMD_AUTO_REFRESH);
+			//!!! Software: Wait here at least 8 CK cycles to satify tRFC
+			udelay(1);   //1us
+		}
+		//As before but without 'RESET_DLL' bit set...
+		ddr_issue_command(ddr_config_parameters->cmd_mode_wr_cl_bl);
+		udelay(1);   //1us
+		// OCD commands
+		ddr_issue_command(emr_cmd + C_CMD_MODE_DDR2_OCD_DFLT);
+		ddr_issue_command(emr_cmd + C_CMD_MODE_DDR2_OCD_EXIT);
+		break;
+
+	default:
+		break;  //Do nothing
+	}
+
+	//Enable auto-refresh
+
+	// 8192 Refreshes required every 64ms, so maximum refresh period is 7.8125 us
+	// We have a 400 MHz DDR clock (2.5ns period) so max period is 3125 cycles
+	// Our core now does 8 refreshes in a go, so we multiply this period by 8
+
+	refresh = (64000 * mhz) / 8192; // Refresh period in clocks
+
+	reg_tmp = *(volatile UINT *) C_DDR_CFG_REG;      // read
+#ifdef BURST_REFRESH_ENABLE
+	reg_tmp |= C_CFG_REFRESH_ENABLE | (refresh * 8);
+	reg_tmp |= C_CFG_BURST_REFRESH_ENABLE;
+#else
+	reg_tmp |= C_CFG_REFRESH_ENABLE | (refresh * 1);
+	reg_tmp &= ~C_CFG_BURST_REFRESH_ENABLE;
+#endif
+	*(volatile UINT *) C_DDR_CFG_REG = reg_tmp;
+
+	//Verify register contents
+	reg_tmp = *(volatile UINT *) C_DDR_REG_PHY2;      // read
+	//printf("Warning XXXXXXXXXXXXXXXXXXXXXX - get bad read data from C_DDR_PHY2_REG, though it looks OK on bus XXXXXXXXXXXXXXXXXX");
+	//TBD   Check_data (read_data,  dll_reg, "Error: bad C_DDR_PHY2_REG read", tb_pass);
+	reg_tmp = *(volatile UINT *) C_DDR_CFG_REG;      // read
+	//TBD   Check_data (read_data,  cfg_reg, "Error: bad DDR_CFG read", tb_pass);
+
+	//disable optimised wrapping
+	if (ddr_config_parameters->ddr_mode == 2) {
+		reg_tmp = 0xFFFF0000;
+		*(volatile UINT *) C_DDR_REG_IGNORE = reg_tmp;
+	}
+
+	//enable midbuffer followon
+	reg_tmp = *(volatile UINT *) C_DDR_ARB_REG;      // read
+	reg_tmp = 0xFFFF0000 | reg_tmp;
+	*(volatile UINT *) C_DDR_ARB_REG = reg_tmp;
+
+	// Enable write behind coherency checking for all clients
+
+	reg_tmp = 0xFFFF0000;
+	*(volatile UINT *) C_DDR_AHB4_REG = reg_tmp;
+
+	//Wait for 200 clock cycles for SDRAM DLL to lock...
+	udelay(1);   //1us
+}
+
+// Function used to Setup DDR core
+
+void ddr_setup(int mhz)
+{
+	static const T_DDR_TIMING_PARAMETERS *ddr_timing_parameters =
+		&C_TP_DDR2_25_CL6_1GB;
+	static const T_DDR_CONFIG_PARAMETERS *ddr_config_parameters =
+		&C_CP_DDR2_25_CL6;
+
+	//Bring core out of Reset
+	*(volatile UINT *) C_DDR_BLKEN_REG = C_BLKEN_DDR_ON;
+
+	//DDR TIMING INITIALISTION
+	ddr_timing_initialisation(ddr_timing_parameters);
+
+	//DDR NORMAL INITIALISATION
+	ddr_normal_initialisation(ddr_config_parameters, mhz);
+
+	// route all writes through one client
+	*(volatile UINT *) C_DDR_TRANSACTION_ROUTING = (0
+		<< DDR_ROUTE_CPU0_INSTR_SHIFT)
+		| (1 << DDR_ROUTE_CPU0_RDDATA_SHIFT)
+		| (3 << DDR_ROUTE_CPU0_WRDATA_SHIFT)
+		| (2 << DDR_ROUTE_CPU1_INSTR_SHIFT)
+		| (3 << DDR_ROUTE_CPU1_RDDATA_SHIFT)
+		| (3 << DDR_ROUTE_CPU1_WRDATA_SHIFT);
+
+	//Bring all clients out of reset
+	*(volatile UINT *) C_DDR_BLKEN_REG = C_BLKEN_DDR_ON + 0x0000FFFF;
+
+}
+
+void set_ddr_timing(unsigned int w, unsigned int i)
+{
+	unsigned int reg;
+	unsigned int wnow = 16;
+	unsigned int inow = 32;
+
+	/* reset all timing controls to known value (31) */
+	writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST, DDR_PHY_TIMING);
+	writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST | DDR_PHY_TIMING_CK,
+	       DDR_PHY_TIMING);
+	writel(DDR_PHY_TIMING_W_RST | DDR_PHY_TIMING_I_RST, DDR_PHY_TIMING);
+
+	/* step up or down read delay to the requested value */
+	while (wnow != w) {
+		if (wnow < w) {
+			reg = DDR_PHY_TIMING_INC;
+			wnow++;
+		} else {
+			reg = 0;
+			wnow--;
+		}
+		writel(DDR_PHY_TIMING_W_CE | reg, DDR_PHY_TIMING);
+		writel(DDR_PHY_TIMING_CK | DDR_PHY_TIMING_W_CE | reg,
+		       DDR_PHY_TIMING);
+		writel(DDR_PHY_TIMING_W_CE | reg, DDR_PHY_TIMING);
+	}
+
+	/* now write delay */
+	while (inow != i) {
+		if (inow < i) {
+			reg = DDR_PHY_TIMING_INC;
+			inow++;
+		} else {
+			reg = 0;
+			inow--;
+		}
+		writel(DDR_PHY_TIMING_I_CE | reg, DDR_PHY_TIMING);
+		writel(DDR_PHY_TIMING_CK | DDR_PHY_TIMING_I_CE | reg,
+		       DDR_PHY_TIMING);
+		writel(DDR_PHY_TIMING_I_CE | reg, DDR_PHY_TIMING);
+	}
+}
+
+//Function used to Setup SDRAM in DDR/SDR mode
+void init_ddr(int mhz)
+{
+	/* start clocks */
+	enable_clock(SYS_CTRL_CLK_DDRPHY);
+	enable_clock(SYS_CTRL_CLK_DDR);
+	enable_clock(SYS_CTRL_CLK_DDRCK);
+
+	/* bring phy and core out of reset */
+	reset_block(SYS_CTRL_RST_DDR_PHY, 0);
+	reset_block(SYS_CTRL_RST_DDR, 0);
+
+	/* DDR runs at half the speed of the CPU */
+	ddr_setup(mhz >> 1);
+	return;
+}
diff --git a/package/boot/uboot-oxnas/src/board/ox820/ddr.h b/package/boot/uboot-oxnas/src/board/ox820/ddr.h
new file mode 100644
index 0000000..a3c1990
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/ddr.h
@@ -0,0 +1,148 @@
+/*******************************************************************
+*
+* File:			ddr_oxsemi.h
+*
+* Description:		Declarations for DDR routines and data objects
+*
+* Author:		Julien Margetts
+*
+* Copyright:		Oxford Semiconductor Ltd, 2009
+*/
+
+void ddr_oxsemi_setup(int mhz);
+
+/* define to refresh in bursts of 8 */
+#define BURST_REFRESH_ENABLE
+
+#define DDR_BASE			0x44700000
+
+#define C_DDR_CFG_REG			(DDR_BASE + 0x00)
+#define C_CFG_DDR			0x80000000
+#define C_CFG_SDR			0x00000000
+#define C_CFG_WIDTH8			0x00200000
+#define C_CFG_WIDTH16			0x00100000
+#define C_CFG_WIDTH32			0x00000000
+#define C_CFG_SIZE_FACTOR		0x00020000
+#define C_CFG_REFRESH_ENABLE		0x00010000
+#define C_CFG_BURST_REFRESH_ENABLE	0x01000000
+#define C_CFG_SIZE(x)			(x << 17)
+#define CFG_SIZE_2MB			1
+#define CFG_SIZE_4MB			2
+#define CFG_SIZE_8MB			3
+#define CFG_SIZE_16MB			4
+#define CFG_SIZE_32MB			5
+#define CFG_SIZE_64MB			6
+#define CFG_SIZE_128MB			7
+
+#define C_DDR_BLKEN_REG			(DDR_BASE + 0x04)
+#define C_BLKEN_DDR_ON			0x80000000
+
+#define C_DDR_STAT_REG			(DDR_BASE + 0x08)
+
+#define C_DDR_CMD_REG			(DDR_BASE + 0x0C)
+#define C_CMD_SEND_COMMAND		(1UL << 31) | (1 << 21) // RAS/CAS/WE/CS all low(active), CKE High, indicates
+#define C_CMD_WAKE_UP			0x80FC0000 // Asserts CKE
+#define C_CMD_MODE_SDR			0x80200022 // Sets CL=2 BL=4
+#define C_CMD_MODE_DDR			0x80200063 // Sets CL=2.5 BL=8
+#define C_CMD_RESET_DLL			0x00000100 // A8=1 Use in conjunction with C_CMD_MODE_DDR
+#define C_CMD_PRECHARGE_ALL		0x80280400
+#define C_CMD_AUTO_REFRESH		0x80240000
+#define C_CMD_SELF_REFRESH		0x80040000 // As AUTO-REFRESH but with CKE low
+#define C_CMD_NOP			0x803C0000 // NOP just to insert guaranteed delay
+#define C_CMD_DDR2_EMR1			0x80210000 // Load extended mode register 1 with zeros (for init), CKE still set
+//#define C_CMD_DDR2_EMR1		0x80210400 // Load extended mode register 1 with zeros (for init), CKE still set
+#define C_CMD_ENABLE_DLL		0x00000000 // Values used in conjuction with C_CMD_DDR2_EMR1
+#define C_CMD_DISABLE_DLL		0x00000001
+#define C_CMD_REDUCED_DRIVE		0x00000002
+#define C_CMD_ODT_DISABLED		0x00000000
+#define C_CMD_ODT_50			0x00000044
+#define C_CMD_ODT_75			0x00000004
+#define C_CMD_ODT_150			0x00000040
+#define C_CMD_MODE_DDR2_OCD_DFLT	0x00000380
+#define C_CMD_MODE_DDR2_OCD_EXIT	0x00000000
+
+#define C_CMD_DDR2_EMR2			0x80220000 // Load extended mode register 2 with zeros (for init), CKE still set
+#define C_CMD_DDR2_EMR3			0x80230000 // Load extended mode register 3 with zeros (for init), CKE still set
+
+#define C_DDR_AHB_REG			(DDR_BASE + 0x10)
+#define C_AHB_NO_RCACHES		0xFFFF0000
+#define C_AHB_FLUSH_ALL_RCACHES		0x0000FFFF
+#define C_AHB_FLUSH_AHB0_RCACHE		0x00000001
+#define C_AHB_FLUSH_AHB1_RCACHE		0x00000002
+
+#define C_DDR_DLL_REG			(DDR_BASE + 0x14)
+#define C_DLL_DISABLED			0x00000000
+#define C_DLL_MANUAL			0x80000000
+#define C_DLL_AUTO_OFFSET		0xA0000000
+#define C_DLL_AUTO_IN_REFRESH		0xC0000000
+#define C_DLL_AUTOMATIC			0xE0000000
+
+#define C_DDR_MON_REG			(DDR_BASE + 0x18)
+#define C_MON_ALL			0x00000010
+#define C_MON_CLIENT			0x00000000
+
+#define C_DDR_DIAG_REG			(DDR_BASE + 0x1C)
+#define C_DDR_DIAG2_REG			(DDR_BASE + 0x20)
+
+#define C_DDR_IOC_REG			(DDR_BASE + 0x24)
+#define C_DDR_IOC_PWR_DWN		(1 << 10)
+#define C_DDR_IOC_SEL_SSTL		(1 << 9)
+#define C_DDR_IOC_CK_DRIVE(x)		((x) << 6)
+#define C_DDR_IOC_DQ_DRIVE(x)		((x) << 3)
+#define C_DDR_IOC_XX_DRIVE(x)		((x) << 0)
+
+#define C_DDR_ARB_REG			(DDR_BASE + 0x28)
+#define C_DDR_ARB_MIDBUF		(1 << 4)
+#define C_DDR_ARB_LRUBANK		(1 << 3)
+#define C_DDR_ARB_REQAGE		(1 << 2)
+#define C_DDR_ARB_DATDIR		(1 << 1)
+#define C_DDR_ARB_DATDIR_NC		(1 << 0)
+
+#define C_TOP_ADDRESS_BIT_TEST		22
+#define C_MEM_BASE			C_SDRAM_BASE
+
+#define C_MEM_TEST_BASE			0
+#define C_MEM_TEST_LEN			1920
+#define C_MAX_RAND_ACCESS_LEN		16
+
+#define C_DDR_REG_IGNORE		(DDR_BASE + 0x2C)
+#define C_DDR_AHB4_REG			(DDR_BASE + 0x44)
+
+#define C_DDR_REG_TIMING0		(DDR_BASE + 0x34)
+#define C_DDR_REG_TIMING1		(DDR_BASE + 0x38)
+#define C_DDR_REG_TIMING2		(DDR_BASE + 0x3C)
+
+#define C_DDR_REG_PHY0			(DDR_BASE + 0x48)
+#define C_DDR_REG_PHY1			(DDR_BASE + 0x4C)
+#define C_DDR_REG_PHY2			(DDR_BASE + 0x50)
+#define C_DDR_REG_PHY3			(DDR_BASE + 0x54)
+
+#define C_DDR_REG_GENERIC		(DDR_BASE + 0x60)
+
+#define C_OXSEMI_DDRC_SIGNATURE		0x054415AA
+
+#define DDR_PHY_BASE			(DDR_BASE + 0x80000)
+#define DDR_PHY_TIMING			(DDR_PHY_BASE + 0x48)
+#define DDR_PHY_TIMING_CK		(1 << 12)
+#define DDR_PHY_TIMING_INC		(1 << 13)
+#define DDR_PHY_TIMING_W_CE		(1 << 14)
+#define DDR_PHY_TIMING_W_RST		(1 << 15)
+#define DDR_PHY_TIMING_I_CE		(1 << 16)
+#define DDR_PHY_TIMING_I_RST		(1 << 17)
+
+#define C_DDR_REG_PHY_TIMING		(DDR_PHY_BASE + 0x50)
+#define C_DDR_REG_PHY_WR_RATIO		(DDR_PHY_BASE + 0x74)
+#define C_DDR_REG_PHY_RD_RATIO		(DDR_PHY_BASE + 0x78)
+
+#define C_DDR_TRANSACTION_ROUTING	(DDR_PHY_BASE + 0xC8)
+#define DDR_ROUTE_CPU0_INSTR_SHIFT	0
+#define DDR_ROUTE_CPU0_RDDATA_SHIFT	4
+#define DDR_ROUTE_CPU0_WRDATA_SHIFT	6
+#define DDR_ROUTE_CPU1_INSTR_SHIFT	8
+#define DDR_ROUTE_CPU1_RDDATA_SHIFT	12
+#define DDR_ROUTE_CPU1_WRDATA_SHIFT	14
+
+unsigned int ddrc_signature(void);
+void set_ddr_timing(unsigned int w, unsigned int i);
+int pause(unsigned int us);
+void set_ddr_sel(int val);
diff --git a/package/boot/uboot-oxnas/src/board/ox820/lowlevel_init.S b/package/boot/uboot-oxnas/src/board/ox820/lowlevel_init.S
new file mode 100644
index 0000000..3328b7a
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/lowlevel_init.S
@@ -0,0 +1,20 @@
+#include <config.h>
+#ifndef CONFIG_SPL_BUILD
+
+.globl lowlevel_init
+lowlevel_init:
+	/*
+	 * Copy exception table to relocated address in internal SRAM
+	 */
+	ldr	r0, src		/* Address of exception table in flash */
+	ldr	r1, dest	/* Relocated address of exception table */
+	ldmia	r0!, {r3-r10}	/* Copy exception table and jump values from */
+	stmia	r1!, {r3-r10}	/* FLASH to relocated address */
+	ldmia	r0!, {r3-r10}
+	stmia	r1!, {r3-r10}
+	mov	pc, lr
+
+src:	.word CONFIG_SYS_TEXT_BASE
+dest:	.word CONFIG_SRAM_BASE
+
+#endif
\ No newline at end of file
diff --git a/package/boot/uboot-oxnas/src/board/ox820/ox820.c b/package/boot/uboot-oxnas/src/board/ox820/ox820.c
new file mode 100644
index 0000000..f93cc9c
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/ox820.c
@@ -0,0 +1,374 @@
+#include <common.h>
+#include <spl.h>
+#include <phy.h>
+#include <netdev.h>
+#include <ide.h>
+#include <nand.h>
+#include <asm/arch/spl.h>
+#include <asm/arch/pinmux.h>
+#include <asm/arch/clock.h>
+#include <asm/arch/sysctl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_SPL_BUILD
+
+#ifdef DEBUG
+#define DILIGENCE (1048576/4)
+static int test_memory(u32 memory)
+{
+	volatile u32 *read;
+	volatile u32 *write;
+	const u32 INIT_PATTERN = 0xAA55AA55;
+	const u32 INC_PATTERN = 0x01030507;
+	u32 pattern;
+	int check;
+	int i;
+
+	check = 0;
+	read = write = (volatile u32 *) memory;
+	pattern = INIT_PATTERN;
+	for (i = 0; i < DILIGENCE; i++) {
+		*write++ = pattern;
+		pattern += INC_PATTERN;
+	}
+	puts("testing\n");
+	pattern = INIT_PATTERN;
+	for (i = 0; i < DILIGENCE; i++) {
+		check += (pattern == *read++) ? 1 : 0;
+		pattern += INC_PATTERN;
+	}
+	return (check == DILIGENCE) ? 0 : -1;
+}
+#endif
+
+void uart_init(void)
+{
+	/* Reset UART1 */
+	reset_block(SYS_CTRL_RST_UART1, 1);
+	udelay(100);
+	reset_block(SYS_CTRL_RST_UART1, 0);
+	udelay(100);
+
+	/* Setup pin mux'ing for UART1 */
+	pinmux_set(PINMUX_BANK_MFA, 30, PINMUX_UARTA_SIN);
+	pinmux_set(PINMUX_BANK_MFA, 31, PINMUX_UARTA_SOUT);
+}
+
+extern void init_ddr(int mhz);
+
+void board_inithw(void)
+{
+	int plla_freq;
+#ifdef DEBUG
+	int i;
+#endif	/* DEBUG */
+
+	timer_init();
+	uart_init();
+	preloader_console_init();
+
+	plla_freq = plla_set_config(CONFIG_PLLA_FREQ_MHZ);
+	init_ddr(plla_freq);
+
+#ifdef DEBUG
+	if(test_memory(CONFIG_SYS_SDRAM_BASE)) {
+		puts("memory test failed\n");
+	} else {
+		puts("memory test done\n");
+	}
+#endif /* DEBUG */
+#ifdef CONFIG_SPL_BSS_DRAM_START
+	extern char __bss_dram_start[];
+	extern char __bss_dram_end[];
+	memset(&__bss_dram_start, 0, __bss_dram_end - __bss_dram_start);
+#endif
+}
+
+void board_init_f(ulong dummy)
+{
+	/* Set the stack pointer. */
+	asm volatile("mov sp, %0\n" : : "r"(CONFIG_SPL_STACK));
+
+	/* Clear the BSS. */
+	memset(__bss_start, 0, __bss_end - __bss_start);
+
+	/* Set global data pointer. */
+	gd = &gdata;
+
+	board_inithw();
+
+	board_init_r(NULL, 0);
+}
+
+u32 spl_boot_device(void)
+{
+	return CONFIG_SPL_BOOT_DEVICE;
+}
+
+#ifdef CONFIG_SPL_BLOCK_SUPPORT
+void spl_block_device_init(void)
+{
+	ide_init();
+}
+#endif
+
+#ifdef CONFIG_SPL_OS_BOOT
+int spl_start_uboot(void)
+{
+        /* break into full u-boot on 'c' */
+        return (serial_tstc() && serial_getc() == 'c');
+}
+#endif
+
+void spl_display_print(void)
+{
+	/* print a hint, so that we will not use the wrong SPL by mistake */
+	puts("  Boot device: " BOOT_DEVICE_TYPE "\n" );
+}
+
+void lowlevel_init(void)
+{
+}
+
+#ifdef USE_DL_PREFIX
+/* quick and dirty memory allocation */
+static ulong next_mem = CONFIG_SPL_MALLOC_START;
+
+void *memalign(size_t alignment, size_t bytes)
+{
+	ulong mem = ALIGN(next_mem, alignment);
+
+	next_mem = mem + bytes;
+
+	if (next_mem > CONFIG_SYS_SDRAM_BASE + CONFIG_MIN_SDRAM_SIZE) {
+		printf("spl: out of memory\n");
+		hang();
+	}
+
+	return (void *)mem;
+}
+
+void free(void* mem)
+{
+}
+#endif
+
+#endif /* CONFIG_SPL_BUILD */
+
+int board_early_init_f(void)
+{
+	return 0;
+}
+
+#define STATIC_CTL_BANK0		(STATIC_CONTROL_BASE + 4)
+#define STATIC_READ_CYCLE_SHIFT		0
+#define STATIC_DELAYED_OE		(1 << 7)
+#define STATIC_WRITE_CYCLE_SHIFT	8
+#define STATIC_WRITE_PULSE_SHIFT	16
+#define STATIC_WRITE_BURST_EN		(1 << 23)
+#define STATIC_TURN_AROUND_SHIFT	24
+#define STATIC_BUFFER_PRESENT		(1 << 28)
+#define STATIC_READ_BURST_EN		(1 << 29)
+#define STATIC_BUS_WIDTH8		(0 << 30)
+#define STATIC_BUS_WIDTH16		(1 << 30)
+#define STATIC_BUS_WIDTH32		(2 << 30)
+
+void nand_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *this = mtd->priv;
+	unsigned long nandaddr = (unsigned long) this->IO_ADDR_W;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		nandaddr &= ~(BIT(NAND_ALE_ADDR_PIN) | BIT(NAND_CLE_ADDR_PIN));
+		if (ctrl & NAND_CLE)
+			nandaddr |= BIT(NAND_CLE_ADDR_PIN);
+		else if (ctrl & NAND_ALE)
+			nandaddr |= BIT(NAND_ALE_ADDR_PIN);
+		this->IO_ADDR_W = (void __iomem *) nandaddr;
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, (void __iomem *) nandaddr);
+}
+
+#if defined(CONFIG_SPL_BUILD) && defined(CONFIG_BOOT_FROM_NAND)
+
+int nand_dev_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *chip = mtd->priv;
+
+	udelay(chip->chip_delay);
+
+	return 1;
+}
+
+void nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+	int i;
+	struct nand_chip *chip = mtd->priv;
+
+	for (i = 0; i < len; i++)
+		buf[i] = readb(chip->IO_ADDR_R);
+}
+
+void nand_dev_reset(struct nand_chip *chip)
+{
+	writeb(NAND_CMD_RESET, chip->IO_ADDR_W + BIT(NAND_CLE_ADDR_PIN));
+	udelay(chip->chip_delay);
+	writeb(NAND_CMD_STATUS, chip->IO_ADDR_W + BIT(NAND_CLE_ADDR_PIN));
+	while (!(readb(chip->IO_ADDR_R) & NAND_STATUS_READY)) {
+		;
+	}
+}
+
+#else
+
+#define nand_dev_reset(chip)	/* framework will reset the chip anyway */
+#define nand_read_buf		NULL /* framework will provide a default one */
+#define nand_dev_ready		NULL /* dev_ready is optional */
+
+#endif
+
+int board_nand_init(struct nand_chip *chip)
+{
+	/* Block reset Static core */
+	reset_block(SYS_CTRL_RST_STATIC, 1);
+	reset_block(SYS_CTRL_RST_STATIC, 0);
+
+	/* Enable clock to Static core */
+	enable_clock(SYS_CTRL_CLK_STATIC);
+
+	/* enable flash support on static bus.
+	 * Enable static bus onto GPIOs, only CS0 */
+	pinmux_set(PINMUX_BANK_MFA, 12, PINMUX_STATIC_DATA0);
+	pinmux_set(PINMUX_BANK_MFA, 13, PINMUX_STATIC_DATA1);
+	pinmux_set(PINMUX_BANK_MFA, 14, PINMUX_STATIC_DATA2);
+	pinmux_set(PINMUX_BANK_MFA, 15, PINMUX_STATIC_DATA3);
+	pinmux_set(PINMUX_BANK_MFA, 16, PINMUX_STATIC_DATA4);
+	pinmux_set(PINMUX_BANK_MFA, 17, PINMUX_STATIC_DATA5);
+	pinmux_set(PINMUX_BANK_MFA, 18, PINMUX_STATIC_DATA6);
+	pinmux_set(PINMUX_BANK_MFA, 19, PINMUX_STATIC_DATA7);
+
+	pinmux_set(PINMUX_BANK_MFA, 20, PINMUX_STATIC_NWE);
+	pinmux_set(PINMUX_BANK_MFA, 21, PINMUX_STATIC_NOE);
+	pinmux_set(PINMUX_BANK_MFA, 22, PINMUX_STATIC_NCS);
+	pinmux_set(PINMUX_BANK_MFA, 23, PINMUX_STATIC_ADDR18);
+	pinmux_set(PINMUX_BANK_MFA, 24, PINMUX_STATIC_ADDR19);
+
+	/* Setup the static bus CS0 to access FLASH */
+
+	writel((0x3f << STATIC_READ_CYCLE_SHIFT)
+			| (0x3f << STATIC_WRITE_CYCLE_SHIFT)
+			| (0x1f << STATIC_WRITE_PULSE_SHIFT)
+			| (0x03 << STATIC_TURN_AROUND_SHIFT) |
+			STATIC_BUS_WIDTH16,
+		STATIC_CTL_BANK0);
+
+	chip->cmd_ctrl = nand_hwcontrol;
+	chip->ecc.mode = NAND_ECC_SOFT;
+	chip->chip_delay = 30;
+	chip->dev_ready = nand_dev_ready;
+	chip->read_buf = nand_read_buf;
+
+	nand_dev_reset(chip);
+
+	return 0;
+}
+
+int board_init(void)
+{
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
+	gd->bd->bi_arch_number = MACH_TYPE_OXNAS;
+
+	/* assume uart is already initialized by SPL */
+
+#if defined(CONFIG_START_IDE)
+	puts("IDE:   ");
+	ide_init();
+#endif
+
+	return 0;
+}
+
+/* copied from board/evb64260/sdram_init.c */
+/*
+ * Check memory range for valid RAM. A simple memory test determines
+ * the actually available RAM size between addresses `base' and
+ * `base + maxsize'. Some (not all) hardware errors are detected:
+ * - short between address lines
+ * - short between data lines
+ */
+static long int dram_size (long int *base, long int maxsize)
+{
+	volatile long int *addr, *b = base;
+	long int cnt, val, save1, save2;
+
+#define STARTVAL (CONFIG_MIN_SDRAM_SIZE / 2)	/* start test at half size */
+	for (cnt = STARTVAL / sizeof (long); cnt < maxsize / sizeof (long);
+	     cnt <<= 1) {
+		addr = base + cnt;	/* pointer arith! */
+
+		save1 = *addr;	/* save contents of addr */
+		save2 = *b;	/* save contents of base */
+
+		*addr = cnt;	/* write cnt to addr */
+		*b = 0;		/* put null at base */
+
+		/* check at base address */
+		if ((*b) != 0) {
+			*addr = save1;	/* restore *addr */
+			*b = save2;	/* restore *b */
+			return (0);
+		}
+		val = *addr;	/* read *addr */
+
+		*addr = save1;
+		*b = save2;
+
+		if (val != cnt) {
+			/* fix boundary condition.. STARTVAL means zero */
+			if (cnt == STARTVAL / sizeof (long))
+				cnt = 0;
+			return (cnt * sizeof (long));
+		}
+	}
+	return maxsize;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = dram_size((long int *)CONFIG_SYS_SDRAM_BASE,
+					CONFIG_MAX_SDRAM_SIZE);
+	return 0;
+}
+
+int board_eth_init(bd_t *bis)
+{
+	u32 value;
+
+	/* set the pin multiplexers to enable talking to Ethernent Phys */
+	pinmux_set(PINMUX_BANK_MFA, 3, PINMUX_MACA_MDC);
+	pinmux_set(PINMUX_BANK_MFA, 4, PINMUX_MACA_MDIO);
+
+	// Ensure the MAC block is properly reset
+	reset_block(SYS_CTRL_RST_MAC, 1);
+	udelay(10);
+	reset_block(SYS_CTRL_RST_MAC, 0);
+
+	// Enable the clock to the MAC block
+	enable_clock(SYS_CTRL_CLK_MAC);
+
+	value = readl(SYS_CTRL_GMAC_CTRL);
+	/* Use simple mux for 25/125 Mhz clock switching */
+	value |= BIT(SYS_CTRL_GMAC_SIMPLE_MUX);
+	/* Enable GMII_GTXCLK to follow GMII_REFCLK - required for gigabit PHY */
+	value |= BIT(SYS_CTRL_GMAC_CKEN_GTX);
+	/* set auto tx speed */
+	value |= BIT(SYS_CTRL_GMAC_AUTOSPEED);
+
+	writel(value, SYS_CTRL_GMAC_CTRL);
+
+	return designware_initialize(MAC_BASE, PHY_INTERFACE_MODE_RGMII);
+}
+
diff --git a/package/boot/uboot-oxnas/src/board/ox820/spl_start.S b/package/boot/uboot-oxnas/src/board/ox820/spl_start.S
new file mode 100644
index 0000000..2eab3f5
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/spl_start.S
@@ -0,0 +1,21 @@
+.section .init
+.globl _spl_start
+_spl_start:
+	b	_start
+	b	_start+0x4
+	b	_start+0x8
+	b	_start+0xc
+	b	_start+0x10
+	b	_start+0x14
+	b	_start+0x18
+	b	_start+0x1c
+	.space	0x30 - (. - _spl_start)
+	.ascii	"BOOT"		/* 0x30 signature*/
+	.word	0x50		/* 0x34 header size itself */
+	.word	0		/* 0x38 */
+	.word	0x5000f000	/* boot report location */
+	.word	_start		/* 0x40 */
+
+main_crc_size:	.word	code_size	/* 0x44 filled by linker */
+main_crc:	.word	0		/* 0x48 fill later */
+header_crc:	.word	0		/* 0x4C header crc*/
diff --git a/package/boot/uboot-oxnas/src/board/ox820/u-boot-spl.lds b/package/boot/uboot-oxnas/src/board/ox820/u-boot-spl.lds
new file mode 100644
index 0000000..a8d90df
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/board/ox820/u-boot-spl.lds
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 Marek Vasut <marek.vasut@gmail.com>
+ * on behalf of DENX Software Engineering GmbH
+ *
+ * January 2004 - Changed to support H4 device
+ * Copyright (c) 2004-2008 Texas Instruments
+ *
+ * (C) Copyright 2002
+ * Gary Jennejohn, DENX Software Engineering, <garyj@denx.de>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+
+MEMORY
+{
+	 sram (rwx) : ORIGIN = CONFIG_SPL_TEXT_BASE, LENGTH = CONFIG_SPL_MAX_SIZE
+	 dram : ORIGIN = CONFIG_SPL_BSS_DRAM_START, LENGTH = CONFIG_SPL_BSS_DRAM_SIZE
+}
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+ENTRY(_spl_start)
+SECTIONS
+{
+	.text.0	:
+	{
+		*(.init*)
+	}
+
+
+	/* Start of the rest of the SPL */
+	code_start = . ;
+
+	.text.1	:
+	{
+		*(.text*)
+	}
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) }
+
+	. = ALIGN(4);
+	.data : {
+		*(.data*)
+	}
+
+	. = ALIGN(4);
+
+	__image_copy_end = .;
+	code_size = . - code_start;
+
+	.rel.dyn : {
+		__rel_dyn_start = .;
+		*(.rel*)
+		__rel_dyn_end = .;
+	}
+
+	. = ALIGN(0x800);
+
+	_end = .;
+
+	.bss.sram __rel_dyn_start (OVERLAY) : {
+		__bss_start = .;
+		*(.bss.stdio_devices)
+		*(.bss.serial_current)
+		 . = ALIGN(4);
+		__bss_end = .;
+	}
+
+	.bss : {
+		__bss_dram_start = .;
+		*(.bss*)
+		__bss_dram_end = .;
+	} > dram
+
+	/DISCARD/ : { *(.bss*) }
+	/DISCARD/ : { *(.dynsym) }
+	/DISCARD/ : { *(.dynstr*) }
+	/DISCARD/ : { *(.dynsym*) }
+	/DISCARD/ : { *(.dynamic*) }
+	/DISCARD/ : { *(.hash*) }
+	/DISCARD/ : { *(.plt*) }
+	/DISCARD/ : { *(.interp*) }
+	/DISCARD/ : { *(.gnu*) }
+}
diff --git a/package/boot/uboot-oxnas/src/common/env_ext4.c b/package/boot/uboot-oxnas/src/common/env_ext4.c
new file mode 100644
index 0000000..e98d94d
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/common/env_ext4.c
@@ -0,0 +1,116 @@
+/*
+ * (c) Copyright 2011 by Tigris Elektronik GmbH
+ *
+ * Author:
+ *  Maximilian Schwerin <mvs@tigris.de>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <search.h>
+#include <errno.h>
+#include <ext4fs.h>
+
+char *env_name_spec = "EXT4";
+
+env_t *env_ptr;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int env_init(void)
+{
+	/* use default */
+	gd->env_addr = (ulong)&default_environment[0];
+	gd->env_valid = 1;
+
+	return 0;
+}
+
+#ifdef CONFIG_CMD_SAVEENV
+int saveenv(void)
+{
+	env_t	env_new;
+	ssize_t	len;
+	char	*res;
+	block_dev_desc_t *dev_desc = NULL;
+	int dev = EXT4_ENV_DEVICE;
+	int part = EXT4_ENV_PART;
+	int err;
+
+	res = (char *)&env_new.data;
+	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
+	if (len < 0) {
+		error("Cannot export environment: errno = %d\n", errno);
+		return 1;
+	}
+
+	dev_desc = get_dev(EXT4_ENV_INTERFACE, dev);
+	if (dev_desc == NULL) {
+		printf("Failed to find %s%d\n",
+			EXT4_ENV_INTERFACE, dev);
+		return 1;
+	}
+
+	err = ext4_register_device(dev_desc, part);
+	if (err) {
+		printf("Failed to register %s%d:%d\n",
+			EXT4_ENV_INTERFACE, dev, part);
+		return 1;
+	}
+
+	env_new.crc = crc32(0, env_new.data, ENV_SIZE);
+	err = ext4fs_write(EXT4_ENV_FILE, (void *)&env_new, sizeof(env_t));
+	ext4fs_close();
+	if (err == -1) {
+		printf("\n** Unable to write \"%s\" from %s%d:%d **\n",
+			EXT4_ENV_FILE, EXT4_ENV_INTERFACE, dev, part);
+		return 1;
+	}
+
+	puts("done\n");
+	return 0;
+}
+#endif /* CONFIG_CMD_SAVEENV */
+
+void env_relocate_spec(void)
+{
+	char buf[CONFIG_ENV_SIZE];
+	block_dev_desc_t *dev_desc = NULL;
+	int dev = EXT4_ENV_DEVICE;
+	int part = EXT4_ENV_PART;
+	int err;
+
+	dev_desc = get_dev(EXT4_ENV_INTERFACE, dev);
+	if (dev_desc == NULL) {
+		printf("Failed to find %s%d\n",
+			EXT4_ENV_INTERFACE, dev);
+		set_default_env(NULL);
+		return;
+	}
+
+	err = ext4_register_device(dev_desc, part);
+	if (err) {
+		printf("Failed to register %s%d:%d\n",
+			EXT4_ENV_INTERFACE, dev, part);
+		set_default_env(NULL);
+		return;
+	}
+
+	err = ext4_read_file(EXT4_ENV_FILE, (uchar *)&buf, 0, CONFIG_ENV_SIZE);
+	ext4fs_close();
+
+	if (err == -1) {
+		printf("\n** Unable to read \"%s\" from %s%d:%d **\n",
+			EXT4_ENV_FILE, EXT4_ENV_INTERFACE, dev, part);
+		set_default_env(NULL);
+		return;
+	}
+
+	env_import(buf, 1);
+}
diff --git a/package/boot/uboot-oxnas/src/common/spl/spl_block.c b/package/boot/uboot-oxnas/src/common/spl/spl_block.c
new file mode 100644
index 0000000..f16413a
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/common/spl/spl_block.c
@@ -0,0 +1,236 @@
+/*
+ * (C) Copyright 2013
+ *
+ * Ma Haijun <mahaijuns@gmail.com>
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <spl.h>
+#include <asm/u-boot.h>
+#include <asm/utils.h>
+#include <version.h>
+#include <part.h>
+#include <fat.h>
+#include <ext4fs.h>
+
+/* should be implemented by board */
+extern void spl_block_device_init(void);
+
+block_dev_desc_t * spl_get_block_device(void)
+{
+	block_dev_desc_t * device;
+
+	spl_block_device_init();
+
+	device = get_dev(CONFIG_SPL_BLOCKDEV_INTERFACE, CONFIG_SPL_BLOCKDEV_ID);
+	if (!device) {
+		printf("blk device %s%d not exists\n",
+			CONFIG_SPL_BLOCKDEV_INTERFACE,
+			CONFIG_SPL_BLOCKDEV_ID);
+		hang();
+	}
+
+	return device;
+}
+
+#ifdef CONFIG_SPL_FAT_SUPPORT
+static int block_load_image_fat(const char *filename)
+{
+	int err;
+	struct image_header *header;
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+						sizeof(struct image_header));
+
+	err = file_fat_read(filename, header, sizeof(struct image_header));
+	if (err <= 0)
+		goto end;
+
+	spl_parse_image_header(header);
+
+	err = file_fat_read(filename, (u8 *)spl_image.load_addr, 0);
+
+end:
+	if (err <= 0)
+		printf("spl: error reading image %s, err - %d\n",
+		       filename, err);
+
+	return (err <= 0);
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+static int block_load_image_fat_os(void)
+{
+	int err;
+
+	err = file_fat_read(CONFIG_SPL_FAT_LOAD_ARGS_NAME,
+			    (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0);
+	if (err <= 0) {
+		return -1;
+	}
+
+	return block_load_image_fat(CONFIG_SPL_FAT_LOAD_KERNEL_NAME);
+}
+#endif
+
+void spl_block_load_image(void)
+{
+	int err;
+	block_dev_desc_t * device;
+
+	device = spl_get_block_device();
+	err = fat_register_device(device, CONFIG_BLOCKDEV_FAT_BOOT_PARTITION);
+	if (err) {
+		printf("spl: fat register err - %d\n", err);
+		hang();
+	}
+#ifdef CONFIG_SPL_OS_BOOT
+	if (spl_start_uboot() || block_load_image_fat_os())
+#endif
+	{
+		err = block_load_image_fat(CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME);
+		if (err)
+			hang();
+	}
+}
+#elif defined(CONFIG_SPL_EXT4_SUPPORT) /* end CONFIG_SPL_FAT_SUPPORT */
+static int block_load_image_ext4(const char *filename)
+{
+	int err;
+	struct image_header *header;
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+						sizeof(struct image_header));
+
+	err = ext4_read_file(filename, header, 0, sizeof(struct image_header));
+	if (err <= 0)
+		goto end;
+
+	spl_parse_image_header(header);
+
+	err = ext4_read_file(filename, (u8 *)spl_image.load_addr, 0, 0);
+
+end:
+	return (err <= 0);
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+static int block_load_image_ext4_os(void)
+{
+	int err;
+
+	err = ext4_read_file(CONFIG_SPL_EXT4_LOAD_ARGS_NAME,
+			    (void *)CONFIG_SYS_SPL_ARGS_ADDR, 0, 0);
+	if (err <= 0) {
+		return -1;
+	}
+
+	return block_load_image_ext4(CONFIG_SPL_EXT4_LOAD_KERNEL_NAME);
+}
+#endif
+
+void spl_block_load_image(void)
+{
+	int err;
+	block_dev_desc_t * device;
+
+	device = spl_get_block_device();
+	err = ext4_register_device(device, CONFIG_BLOCKDEV_EXT4_BOOT_PARTITION);
+	if (err) {
+		hang();
+	}
+#ifdef CONFIG_SPL_OS_BOOT
+	if (spl_start_uboot() || block_load_image_ext4_os())
+#endif
+	{
+		err = block_load_image_ext4(CONFIG_SPL_EXT4_LOAD_PAYLOAD_NAME);
+		if (err)
+			hang();
+	}
+}
+#else /* end CONFIG_SPL_EXT4_SUPPORT */
+static int block_load_image_raw(block_dev_desc_t * device, lbaint_t sector)
+{
+	int n;
+	u32 image_size_sectors;
+	struct image_header *header;
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+						sizeof(struct image_header));
+
+	/* read image header to find the image size & load address */
+	n = device->block_read(device->dev, sector, 1, header);
+
+	if (n != 1) {
+		printf("spl: blk read err\n");
+		return 1;
+	}
+
+	spl_parse_image_header(header);
+
+	/* convert size to sectors - round up */
+	image_size_sectors = (spl_image.size + 512 - 1) / 512;
+	n = device->block_read(device->dev, sector, image_size_sectors,
+					(void *)spl_image.load_addr);
+
+	if (n != image_size_sectors) {
+		printf("spl: blk read err\n");
+		return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SPL_OS_BOOT
+static int block_load_image_raw_os(block_dev_desc_t * device)
+{
+	int n;
+
+	n = device->block_read(device->dev, CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTOR,
+					CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTORS,
+					(u32 *)CONFIG_SYS_SPL_ARGS_ADDR);
+	/* flush cache after read */
+	flush_cache(addr, CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTORS * 512);
+
+	if (n != CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTORS) {
+		printf("args blk read error\n");
+		return -1;
+	}
+
+	return block_load_image_raw(device, CONFIG_SYS_BLOCK_RAW_MODE_KERNEL_SECTOR);
+}
+#endif
+
+void spl_block_load_image(void)
+{
+	int err;
+	block_dev_desc_t * device;
+
+	device = spl_get_block_device();
+#ifdef CONFIG_SPL_OS_BOOT
+	if (spl_start_uboot() || block_load_image_raw_os(device))
+#endif
+	{
+		err = block_load_image_raw(device,
+					 CONFIG_SYS_BLOCK_RAW_MODE_U_BOOT_SECTOR);
+		if (err)
+			hang();
+	}
+}
+#endif /* CONFIG_SPL_FAT_SUPPORT */
diff --git a/package/boot/uboot-oxnas/src/configs/ox820_defconfig b/package/boot/uboot-oxnas/src/configs/ox820_defconfig
new file mode 100644
index 0000000..48a16d0
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/configs/ox820_defconfig
@@ -0,0 +1,3 @@
+CONFIG_ARM=y
+CONFIG_OX820=y
+CONFIG_TARGET_OX820=y
diff --git a/package/boot/uboot-oxnas/src/drivers/block/plxsata_ide.c b/package/boot/uboot-oxnas/src/drivers/block/plxsata_ide.c
new file mode 100644
index 0000000..7e0e78f
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/drivers/block/plxsata_ide.c
@@ -0,0 +1,1170 @@
+/*
+ * (C) Copyright 2005
+ * Oxford Semiconductor Ltd
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston,`
+ * MA 02111-1307 USA
+ */
+#include <common.h>
+#include <asm/arch/clock.h>
+
+/**
+ * SATA related definitions
+ */
+#define ATA_PORT_CTL        0
+#define ATA_PORT_FEATURE    1
+#define ATA_PORT_NSECT      2
+#define ATA_PORT_LBAL       3
+#define ATA_PORT_LBAM       4
+#define ATA_PORT_LBAH       5
+#define ATA_PORT_DEVICE     6
+#define ATA_PORT_COMMAND    7
+
+/* The offsets to the SATA registers */
+#define SATA_ORB1_OFF           0
+#define SATA_ORB2_OFF           1
+#define SATA_ORB3_OFF           2
+#define SATA_ORB4_OFF           3
+#define SATA_ORB5_OFF           4
+
+#define SATA_FIS_ACCESS         11
+#define SATA_INT_STATUS_OFF     12  /* Read only */
+#define SATA_INT_CLR_OFF        12  /* Write only */
+#define SATA_INT_ENABLE_OFF     13  /* Read only */
+#define SATA_INT_ENABLE_SET_OFF 13  /* Write only */
+#define SATA_INT_ENABLE_CLR_OFF 14  /* Write only */
+#define SATA_VERSION_OFF        15
+#define SATA_CONTROL_OFF        23
+#define SATA_COMMAND_OFF        24
+#define SATA_PORT_CONTROL_OFF   25
+#define SATA_DRIVE_CONTROL_OFF  26
+
+/* The offsets to the link registers that are access in an asynchronous manner */
+#define SATA_LINK_DATA     28
+#define SATA_LINK_RD_ADDR  29
+#define SATA_LINK_WR_ADDR  30
+#define SATA_LINK_CONTROL  31
+
+/* SATA interrupt status register fields */
+#define SATA_INT_STATUS_EOC_RAW_BIT     ( 0 + 16)
+#define SATA_INT_STATUS_ERROR_BIT       ( 2 + 16)
+#define SATA_INT_STATUS_EOADT_RAW_BIT   ( 1 + 16)
+
+/* SATA core command register commands */
+#define SATA_CMD_WRITE_TO_ORB_REGS              2
+#define SATA_CMD_WRITE_TO_ORB_REGS_NO_COMMAND   4
+
+#define SATA_CMD_BUSY_BIT 7
+
+#define SATA_SCTL_CLR_ERR 0x00000316UL
+
+#define SATA_LBAL_BIT    0
+#define SATA_LBAM_BIT    8
+#define SATA_LBAH_BIT    16
+#define SATA_HOB_LBAH_BIT 24
+#define SATA_DEVICE_BIT  24
+#define SATA_NSECT_BIT   0
+#define SATA_HOB_NSECT_BIT   8
+#define SATA_LBA32_BIT       0
+#define SATA_LBA40_BIT       8
+#define SATA_FEATURE_BIT 16
+#define SATA_COMMAND_BIT 24
+#define SATA_CTL_BIT     24
+
+/* ATA status (7) register field definitions */
+#define ATA_STATUS_BSY_BIT     7
+#define ATA_STATUS_DRDY_BIT    6
+#define ATA_STATUS_DF_BIT      5
+#define ATA_STATUS_DRQ_BIT     3
+#define ATA_STATUS_ERR_BIT     0
+
+/* ATA device (6) register field definitions */
+#define ATA_DEVICE_FIXED_MASK 0xA0
+#define ATA_DEVICE_DRV_BIT 4
+#define ATA_DEVICE_DRV_NUM_BITS 1
+#define ATA_DEVICE_LBA_BIT 6
+
+/* ATA Command register initiated commands */
+#define ATA_CMD_INIT    0x91
+#define ATA_CMD_IDENT   0xEC
+
+#define SATA_STD_ASYNC_REGS_OFF 0x20
+#define SATA_SCR_STATUS      0
+#define SATA_SCR_ERROR       1
+#define SATA_SCR_CONTROL     2
+#define SATA_SCR_ACTIVE      3
+#define SATA_SCR_NOTIFICAION 4
+
+#define SATA_BURST_BUF_FORCE_EOT_BIT        0
+#define SATA_BURST_BUF_DATA_INJ_ENABLE_BIT  1
+#define SATA_BURST_BUF_DIR_BIT              2
+#define SATA_BURST_BUF_DATA_INJ_END_BIT     3
+#define SATA_BURST_BUF_FIFO_DIS_BIT         4
+#define SATA_BURST_BUF_DIS_DREQ_BIT         5
+#define SATA_BURST_BUF_DREQ_BIT             6
+
+#define SATA_OPCODE_MASK 0x3
+
+#define SATA_DMA_CHANNEL 0
+
+#define DMA_CTRL_STATUS      (0x0)
+#define DMA_BASE_SRC_ADR     (0x4)
+#define DMA_BASE_DST_ADR     (0x8)
+#define DMA_BYTE_CNT         (0xC)
+#define DMA_CURRENT_SRC_ADR  (0x10)
+#define DMA_CURRENT_DST_ADR  (0x14)
+#define DMA_CURRENT_BYTE_CNT (0x18)
+#define DMA_INTR_ID          (0x1C)
+#define DMA_INTR_CLEAR_REG   (DMA_CURRENT_SRC_ADR)
+
+#define DMA_CALC_REG_ADR(channel, register) ((volatile u32*)(DMA_BASE + ((channel) << 5) + (register)))
+
+#define DMA_CTRL_STATUS_FAIR_SHARE_ARB            (1 << 0)
+#define DMA_CTRL_STATUS_IN_PROGRESS               (1 << 1)
+#define DMA_CTRL_STATUS_SRC_DREQ_MASK             (0x0000003C)
+#define DMA_CTRL_STATUS_SRC_DREQ_SHIFT            (2)
+#define DMA_CTRL_STATUS_DEST_DREQ_MASK            (0x000003C0)
+#define DMA_CTRL_STATUS_DEST_DREQ_SHIFT           (6)
+#define DMA_CTRL_STATUS_INTR                      (1 << 10)
+#define DMA_CTRL_STATUS_NXT_FREE                  (1 << 11)
+#define DMA_CTRL_STATUS_RESET                     (1 << 12)
+#define DMA_CTRL_STATUS_DIR_MASK                  (0x00006000)
+#define DMA_CTRL_STATUS_DIR_SHIFT                 (13)
+#define DMA_CTRL_STATUS_SRC_ADR_MODE              (1 << 15)
+#define DMA_CTRL_STATUS_DEST_ADR_MODE             (1 << 16)
+#define DMA_CTRL_STATUS_TRANSFER_MODE_A           (1 << 17)
+#define DMA_CTRL_STATUS_TRANSFER_MODE_B           (1 << 18)
+#define DMA_CTRL_STATUS_SRC_WIDTH_MASK            (0x00380000)
+#define DMA_CTRL_STATUS_SRC_WIDTH_SHIFT           (19)
+#define DMA_CTRL_STATUS_DEST_WIDTH_MASK           (0x01C00000)
+#define DMA_CTRL_STATUS_DEST_WIDTH_SHIFT          (22)
+#define DMA_CTRL_STATUS_PAUSE                     (1 << 25)
+#define DMA_CTRL_STATUS_INTERRUPT_ENABLE          (1 << 26)
+#define DMA_CTRL_STATUS_SOURCE_ADDRESS_FIXED      (1 << 27)
+#define DMA_CTRL_STATUS_DESTINATION_ADDRESS_FIXED (1 << 28)
+#define DMA_CTRL_STATUS_STARVE_LOW_PRIORITY       (1 << 29)
+#define DMA_CTRL_STATUS_INTR_CLEAR_ENABLE         (1 << 30)
+
+#define DMA_BYTE_CNT_MASK        ((1 << 21) - 1)
+#define DMA_BYTE_CNT_WR_EOT_MASK (1 << 30)
+#define DMA_BYTE_CNT_RD_EOT_MASK (1 << 31)
+#define DMA_BYTE_CNT_BURST_MASK  (1 << 28)
+
+#define MAKE_FIELD(value, num_bits, bit_num) (((value) & ((1 << (num_bits)) - 1)) << (bit_num))
+
+typedef enum oxnas_dma_mode {
+	OXNAS_DMA_MODE_FIXED, OXNAS_DMA_MODE_INC
+} oxnas_dma_mode_t;
+
+typedef enum oxnas_dma_direction {
+	OXNAS_DMA_TO_DEVICE, OXNAS_DMA_FROM_DEVICE
+} oxnas_dma_direction_t;
+
+/* The available buses to which the DMA controller is attached */
+typedef enum oxnas_dma_transfer_bus {
+	OXNAS_DMA_SIDE_A, OXNAS_DMA_SIDE_B
+} oxnas_dma_transfer_bus_t;
+
+/* Direction of data flow between the DMA controller's pair of interfaces */
+typedef enum oxnas_dma_transfer_direction {
+	OXNAS_DMA_A_TO_A, OXNAS_DMA_B_TO_A, OXNAS_DMA_A_TO_B, OXNAS_DMA_B_TO_B
+} oxnas_dma_transfer_direction_t;
+
+/* The available data widths */
+typedef enum oxnas_dma_transfer_width {
+	OXNAS_DMA_TRANSFER_WIDTH_8BITS,
+	OXNAS_DMA_TRANSFER_WIDTH_16BITS,
+	OXNAS_DMA_TRANSFER_WIDTH_32BITS
+} oxnas_dma_transfer_width_t;
+
+/* The mode of the DMA transfer */
+typedef enum oxnas_dma_transfer_mode {
+	OXNAS_DMA_TRANSFER_MODE_SINGLE, OXNAS_DMA_TRANSFER_MODE_BURST
+} oxnas_dma_transfer_mode_t;
+
+/* The available transfer targets */
+typedef enum oxnas_dma_dreq {
+	OXNAS_DMA_DREQ_SATA = 0, OXNAS_DMA_DREQ_MEMORY = 15
+} oxnas_dma_dreq_t;
+
+typedef struct oxnas_dma_device_settings {
+	unsigned long address_;
+	unsigned fifo_size_; // Chained transfers must take account of FIFO offset at end of previous transfer
+	unsigned char dreq_;
+	unsigned read_eot_ :1;
+	unsigned read_final_eot_ :1;
+	unsigned write_eot_ :1;
+	unsigned write_final_eot_ :1;
+	unsigned bus_ :1;
+	unsigned width_ :2;
+	unsigned transfer_mode_ :1;
+	unsigned address_mode_ :1;
+	unsigned address_really_fixed_ :1;
+} oxnas_dma_device_settings_t;
+
+static const int MAX_NO_ERROR_LOOPS = 100000; /* 1 second in units of 10uS */
+static const int MAX_DMA_XFER_LOOPS = 300000; /* 30 seconds in units of 100uS */
+static const int MAX_DMA_ABORT_LOOPS = 10000; /* 0.1 second in units of 10uS */
+static const int MAX_SRC_READ_LOOPS = 10000; /* 0.1 second in units of 10uS */
+static const int MAX_SRC_WRITE_LOOPS = 10000; /* 0.1 second in units of 10uS */
+static const int MAX_NOT_BUSY_LOOPS = 10000; /* 1 second in units of 100uS */
+
+/* The internal SATA drive on which we should attempt to find partitions */
+static volatile u32* sata_regs_base[2] = { (volatile u32*) SATA_0_REGS_BASE,
+		(volatile u32*) SATA_1_REGS_BASE,
+
+};
+static u32 wr_sata_orb1[2] = { 0, 0 };
+static u32 wr_sata_orb2[2] = { 0, 0 };
+static u32 wr_sata_orb3[2] = { 0, 0 };
+static u32 wr_sata_orb4[2] = { 0, 0 };
+
+#ifdef CONFIG_LBA48
+/* need keeping a record of NSECT LBAL LBAM LBAH ide_outb values for lba48 support */
+#define OUT_HISTORY_BASE	ATA_PORT_NSECT
+#define OUT_HISTORY_MAX		ATA_PORT_LBAH
+static unsigned char out_history[2][OUT_HISTORY_MAX - OUT_HISTORY_BASE + 1] = {};
+#endif
+
+static oxnas_dma_device_settings_t oxnas_sata_dma_settings = { .address_ =
+	SATA_DATA_BASE, .fifo_size_ = 16, .dreq_ = OXNAS_DMA_DREQ_SATA,
+		.read_eot_ = 0, .read_final_eot_ = 1, .write_eot_ = 0,
+		.write_final_eot_ = 1, .bus_ = OXNAS_DMA_SIDE_B, .width_ =
+			OXNAS_DMA_TRANSFER_WIDTH_32BITS, .transfer_mode_ =
+			OXNAS_DMA_TRANSFER_MODE_BURST, .address_mode_ =
+			OXNAS_DMA_MODE_FIXED, .address_really_fixed_ = 0 };
+
+oxnas_dma_device_settings_t oxnas_ram_dma_settings = { .address_ = 0,
+		.fifo_size_ = 0, .dreq_ = OXNAS_DMA_DREQ_MEMORY, .read_eot_ = 1,
+		.read_final_eot_ = 1, .write_eot_ = 1, .write_final_eot_ = 1,
+		.bus_ = OXNAS_DMA_SIDE_A, .width_ =
+			OXNAS_DMA_TRANSFER_WIDTH_32BITS, .transfer_mode_ =
+			OXNAS_DMA_TRANSFER_MODE_BURST, .address_mode_ =
+			OXNAS_DMA_MODE_FIXED, .address_really_fixed_ = 1 };
+
+static void xfer_wr_shadow_to_orbs(int device)
+{
+	*(sata_regs_base[device] + SATA_ORB1_OFF) = wr_sata_orb1[device];
+	*(sata_regs_base[device] + SATA_ORB2_OFF) = wr_sata_orb2[device];
+	*(sata_regs_base[device] + SATA_ORB3_OFF) = wr_sata_orb3[device];
+	*(sata_regs_base[device] + SATA_ORB4_OFF) = wr_sata_orb4[device];
+}
+
+static inline void device_select(int device)
+{
+	/* master/slave has no meaning to SATA core */
+}
+
+static int disk_present[CONFIG_SYS_IDE_MAXDEVICE];
+
+#include <ata.h>
+
+unsigned char ide_inb(int device, int port)
+{
+	unsigned char val = 0;
+
+	/* Only permit accesses to disks found to be present during ide_preinit() */
+	if (!disk_present[device]) {
+		return ATA_STAT_FAULT;
+	}
+
+	device_select(device);
+
+	switch (port) {
+	case ATA_PORT_CTL:
+		val = (*(sata_regs_base[device] + SATA_ORB4_OFF)
+			& (0xFFUL << SATA_CTL_BIT)) >> SATA_CTL_BIT;
+		break;
+	case ATA_PORT_FEATURE:
+		val = (*(sata_regs_base[device] + SATA_ORB2_OFF)
+			& (0xFFUL << SATA_FEATURE_BIT)) >> SATA_FEATURE_BIT;
+		break;
+	case ATA_PORT_NSECT:
+		val = (*(sata_regs_base[device] + SATA_ORB2_OFF)
+			& (0xFFUL << SATA_NSECT_BIT)) >> SATA_NSECT_BIT;
+		break;
+	case ATA_PORT_LBAL:
+		val = (*(sata_regs_base[device] + SATA_ORB3_OFF)
+			& (0xFFUL << SATA_LBAL_BIT)) >> SATA_LBAL_BIT;
+		break;
+	case ATA_PORT_LBAM:
+		val = (*(sata_regs_base[device] + SATA_ORB3_OFF)
+			& (0xFFUL << SATA_LBAM_BIT)) >> SATA_LBAM_BIT;
+		break;
+	case ATA_PORT_LBAH:
+		val = (*(sata_regs_base[device] + SATA_ORB3_OFF)
+			& (0xFFUL << SATA_LBAH_BIT)) >> SATA_LBAH_BIT;
+		break;
+	case ATA_PORT_DEVICE:
+		val = (*(sata_regs_base[device] + SATA_ORB3_OFF)
+			& (0xFFUL << SATA_HOB_LBAH_BIT)) >> SATA_HOB_LBAH_BIT;
+		val |= (*(sata_regs_base[device] + SATA_ORB1_OFF)
+			& (0xFFUL << SATA_DEVICE_BIT)) >> SATA_DEVICE_BIT;
+		break;
+	case ATA_PORT_COMMAND:
+		val = (*(sata_regs_base[device] + SATA_ORB2_OFF)
+			& (0xFFUL << SATA_COMMAND_BIT)) >> SATA_COMMAND_BIT;
+		val |= ATA_STAT_DRQ;
+		break;
+	default:
+		printf("ide_inb() Unknown port = %d\n", port);
+		break;
+	}
+
+	//    printf("inb: %d:%01x => %02x\n", device, port, val);
+
+	return val;
+}
+
+/**
+ * Possible that ATA status will not become no-error, so must have timeout
+ * @returns An int which is zero on error
+ */
+static inline int wait_no_error(int device)
+{
+	int status = 0;
+
+	/* Check for ATA core error */
+	if (*(sata_regs_base[device] + SATA_INT_STATUS_OFF)
+		& (1 << SATA_INT_STATUS_ERROR_BIT)) {
+		printf("wait_no_error() SATA core flagged error\n");
+	} else {
+		int loops = MAX_NO_ERROR_LOOPS;
+		do {
+			/* Check for ATA device error */
+			if (!(ide_inb(device, ATA_PORT_COMMAND)
+				& (1 << ATA_STATUS_ERR_BIT))) {
+				status = 1;
+				break;
+			}
+			udelay(10);
+		} while (--loops);
+
+		if (!loops) {
+			printf("wait_no_error() Timed out of wait for SATA no-error condition\n");
+		}
+	}
+
+	return status;
+}
+
+/**
+ * Expect SATA command to always finish, perhaps with error
+ * @returns An int which is zero on error
+ */
+static inline int wait_sata_command_not_busy(int device)
+{
+	/* Wait for data to be available */
+	int status = 0;
+	int loops = MAX_NOT_BUSY_LOOPS;
+	do {
+		if (!(*(sata_regs_base[device] + SATA_COMMAND_OFF)
+			& (1 << SATA_CMD_BUSY_BIT))) {
+			status = 1;
+			break;
+		}
+		udelay(100);
+	} while (--loops);
+
+	if (!loops) {
+		printf("wait_sata_command_not_busy() Timed out of wait for SATA command to finish\n");
+	}
+
+	return status;
+}
+
+void ide_outb(int device, int port, unsigned char val)
+{
+	typedef enum send_method {
+		SEND_NONE, SEND_SIMPLE, SEND_CMD, SEND_CTL,
+	} send_method_t;
+
+	/* Only permit accesses to disks found to be present during ide_preinit() */
+	if (!disk_present[device]) {
+		return;
+	}
+
+	//    printf("outb: %d:%01x <= %02x\n", device, port, val);
+
+	device_select(device);
+
+#ifdef CONFIG_LBA48
+	if (port >= OUT_HISTORY_BASE && port <= OUT_HISTORY_MAX) {
+		out_history[0][port - OUT_HISTORY_BASE] =
+			out_history[1][port - OUT_HISTORY_BASE];
+		out_history[1][port - OUT_HISTORY_BASE] = val;
+	}
+#endif
+	send_method_t send_regs = SEND_NONE;
+	switch (port) {
+	case ATA_PORT_CTL:
+		wr_sata_orb4[device] &= ~(0xFFUL << SATA_CTL_BIT);
+		wr_sata_orb4[device] |= (val << SATA_CTL_BIT);
+		send_regs = SEND_CTL;
+		break;
+	case ATA_PORT_FEATURE:
+		wr_sata_orb2[device] &= ~(0xFFUL << SATA_FEATURE_BIT);
+		wr_sata_orb2[device] |= (val << SATA_FEATURE_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_NSECT:
+		wr_sata_orb2[device] &= ~(0xFFUL << SATA_NSECT_BIT);
+		wr_sata_orb2[device] |= (val << SATA_NSECT_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_LBAL:
+		wr_sata_orb3[device] &= ~(0xFFUL << SATA_LBAL_BIT);
+		wr_sata_orb3[device] |= (val << SATA_LBAL_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_LBAM:
+		wr_sata_orb3[device] &= ~(0xFFUL << SATA_LBAM_BIT);
+		wr_sata_orb3[device] |= (val << SATA_LBAM_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_LBAH:
+		wr_sata_orb3[device] &= ~(0xFFUL << SATA_LBAH_BIT);
+		wr_sata_orb3[device] |= (val << SATA_LBAH_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_DEVICE:
+		wr_sata_orb1[device] &= ~(0xFFUL << SATA_DEVICE_BIT);
+		wr_sata_orb1[device] |= (val << SATA_DEVICE_BIT);
+		send_regs = SEND_SIMPLE;
+		break;
+	case ATA_PORT_COMMAND:
+		wr_sata_orb2[device] &= ~(0xFFUL << SATA_COMMAND_BIT);
+		wr_sata_orb2[device] |= (val << SATA_COMMAND_BIT);
+		send_regs = SEND_CMD;
+#ifdef CONFIG_LBA48
+		if (val == ATA_CMD_READ_EXT || val == ATA_CMD_WRITE_EXT)
+		{
+			/* fill high bytes of LBA48 && NSECT */
+			wr_sata_orb2[device] &= ~(0xFFUL << SATA_HOB_NSECT_BIT);
+			wr_sata_orb2[device] |=
+				(out_history[0][ATA_PORT_NSECT - OUT_HISTORY_BASE] << SATA_HOB_NSECT_BIT);
+
+			wr_sata_orb3[device] &= ~(0xFFUL << SATA_HOB_LBAH_BIT);
+			wr_sata_orb3[device] |=
+				(out_history[0][ATA_PORT_LBAL - OUT_HISTORY_BASE] << SATA_HOB_LBAH_BIT);
+
+			wr_sata_orb4[device] &= ~(0xFFUL << SATA_LBA32_BIT);
+			wr_sata_orb4[device] |=
+				(out_history[0][ATA_PORT_LBAM - OUT_HISTORY_BASE] << SATA_LBA32_BIT);
+
+			wr_sata_orb4[device] &= ~(0xFFUL << SATA_LBA40_BIT);
+			wr_sata_orb4[device] |=
+				(out_history[0][ATA_PORT_LBAH - OUT_HISTORY_BASE] << SATA_LBA40_BIT);
+		}
+#endif
+		break;
+	default:
+		printf("ide_outb() Unknown port = %d\n", port);
+	}
+
+	u32 command;
+	switch (send_regs) {
+	case SEND_CMD:
+		wait_sata_command_not_busy(device);
+		command = *(sata_regs_base[device] + SATA_COMMAND_OFF);
+		command &= ~SATA_OPCODE_MASK;
+		command |= SATA_CMD_WRITE_TO_ORB_REGS;
+		xfer_wr_shadow_to_orbs(device);
+		wait_sata_command_not_busy(device);
+		*(sata_regs_base[device] + SATA_COMMAND_OFF) = command;
+		if (!wait_no_error(device)) {
+			printf("ide_outb() Wait for ATA no-error timed-out\n");
+		}
+		break;
+	case SEND_CTL:
+		wait_sata_command_not_busy(device);
+		command = *(sata_regs_base[device] + SATA_COMMAND_OFF);
+		command &= ~SATA_OPCODE_MASK;
+		command |= SATA_CMD_WRITE_TO_ORB_REGS_NO_COMMAND;
+		xfer_wr_shadow_to_orbs(device);
+		wait_sata_command_not_busy(device);
+		*(sata_regs_base[device] + SATA_COMMAND_OFF) = command;
+		if (!wait_no_error(device)) {
+			printf("ide_outb() Wait for ATA no-error timed-out\n");
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static u32 encode_start(u32 ctrl_status)
+{
+	return ctrl_status & ~DMA_CTRL_STATUS_PAUSE;
+}
+
+/* start a paused DMA transfer in channel 0 of the SATA DMA core */
+static void dma_start(void)
+{
+	unsigned int reg;
+	reg = readl(SATA_DMA_REGS_BASE + DMA_CTRL_STATUS);
+	reg = encode_start(reg);
+	writel(reg, SATA_DMA_REGS_BASE + DMA_CTRL_STATUS);
+}
+
+static unsigned long encode_control_status(
+	oxnas_dma_device_settings_t* src_settings,
+	oxnas_dma_device_settings_t* dst_settings)
+{
+	unsigned long ctrl_status;
+	oxnas_dma_transfer_direction_t direction;
+
+	ctrl_status = DMA_CTRL_STATUS_PAUSE;                           // Paused
+	ctrl_status |= DMA_CTRL_STATUS_FAIR_SHARE_ARB;          // High priority
+	ctrl_status |= (src_settings->dreq_ << DMA_CTRL_STATUS_SRC_DREQ_SHIFT); // Dreq
+	ctrl_status |= (dst_settings->dreq_ << DMA_CTRL_STATUS_DEST_DREQ_SHIFT); // Dreq
+	ctrl_status &= ~DMA_CTRL_STATUS_RESET;                         // !RESET
+
+	// Use new interrupt clearing register
+	ctrl_status |= DMA_CTRL_STATUS_INTR_CLEAR_ENABLE;
+
+	// Setup the transfer direction and burst/single mode for the two DMA busses
+	if (src_settings->bus_ == OXNAS_DMA_SIDE_A) {
+		// Set the burst/single mode for bus A based on src device's settings
+		if (src_settings->transfer_mode_
+			== OXNAS_DMA_TRANSFER_MODE_BURST) {
+			ctrl_status |= DMA_CTRL_STATUS_TRANSFER_MODE_A;
+		} else {
+			ctrl_status &= ~DMA_CTRL_STATUS_TRANSFER_MODE_A;
+		}
+
+		if (dst_settings->bus_ == OXNAS_DMA_SIDE_A) {
+			direction = OXNAS_DMA_A_TO_A;
+		} else {
+			direction = OXNAS_DMA_A_TO_B;
+
+			// Set the burst/single mode for bus B based on dst device's settings
+			if (dst_settings->transfer_mode_
+				== OXNAS_DMA_TRANSFER_MODE_BURST) {
+				ctrl_status |= DMA_CTRL_STATUS_TRANSFER_MODE_B;
+			} else {
+				ctrl_status &= ~DMA_CTRL_STATUS_TRANSFER_MODE_B;
+			}
+		}
+	} else {
+		// Set the burst/single mode for bus B based on src device's settings
+		if (src_settings->transfer_mode_
+			== OXNAS_DMA_TRANSFER_MODE_BURST) {
+			ctrl_status |= DMA_CTRL_STATUS_TRANSFER_MODE_B;
+		} else {
+			ctrl_status &= ~DMA_CTRL_STATUS_TRANSFER_MODE_B;
+		}
+
+		if (dst_settings->bus_ == OXNAS_DMA_SIDE_A) {
+			direction = OXNAS_DMA_B_TO_A;
+
+			// Set the burst/single mode for bus A based on dst device's settings
+			if (dst_settings->transfer_mode_
+				== OXNAS_DMA_TRANSFER_MODE_BURST) {
+				ctrl_status |= DMA_CTRL_STATUS_TRANSFER_MODE_A;
+			} else {
+				ctrl_status &= ~DMA_CTRL_STATUS_TRANSFER_MODE_A;
+			}
+		} else {
+			direction = OXNAS_DMA_B_TO_B;
+		}
+	}
+	ctrl_status |= (direction << DMA_CTRL_STATUS_DIR_SHIFT);
+
+	// Setup source address mode fixed or increment
+	if (src_settings->address_mode_ == OXNAS_DMA_MODE_FIXED) {
+		// Fixed address
+		ctrl_status &= ~(DMA_CTRL_STATUS_SRC_ADR_MODE);
+
+		// Set up whether fixed address is _really_ fixed
+		if (src_settings->address_really_fixed_) {
+			ctrl_status |= DMA_CTRL_STATUS_SOURCE_ADDRESS_FIXED;
+		} else {
+			ctrl_status &= ~DMA_CTRL_STATUS_SOURCE_ADDRESS_FIXED;
+		}
+	} else {
+		// Incrementing address
+		ctrl_status |= DMA_CTRL_STATUS_SRC_ADR_MODE;
+		ctrl_status &= ~DMA_CTRL_STATUS_SOURCE_ADDRESS_FIXED;
+	}
+
+	// Setup destination address mode fixed or increment
+	if (dst_settings->address_mode_ == OXNAS_DMA_MODE_FIXED) {
+		// Fixed address
+		ctrl_status &= ~(DMA_CTRL_STATUS_DEST_ADR_MODE);
+
+		// Set up whether fixed address is _really_ fixed
+		if (dst_settings->address_really_fixed_) {
+			ctrl_status |=
+				DMA_CTRL_STATUS_DESTINATION_ADDRESS_FIXED;
+		} else {
+			ctrl_status &=
+				~DMA_CTRL_STATUS_DESTINATION_ADDRESS_FIXED;
+		}
+	} else {
+		// Incrementing address
+		ctrl_status |= DMA_CTRL_STATUS_DEST_ADR_MODE;
+		ctrl_status &= ~DMA_CTRL_STATUS_DESTINATION_ADDRESS_FIXED;
+	}
+
+	// Set up the width of the transfers on the DMA buses
+	ctrl_status |=
+		(src_settings->width_ << DMA_CTRL_STATUS_SRC_WIDTH_SHIFT);
+	ctrl_status |=
+		(dst_settings->width_ << DMA_CTRL_STATUS_DEST_WIDTH_SHIFT);
+
+	// Setup the priority arbitration scheme
+	ctrl_status &= ~DMA_CTRL_STATUS_STARVE_LOW_PRIORITY; // !Starve low priority
+
+	return ctrl_status;
+}
+
+static u32 encode_final_eot(oxnas_dma_device_settings_t* src_settings,
+				oxnas_dma_device_settings_t* dst_settings,
+				unsigned long length)
+{
+	// Write the length, with EOT configuration for a final transfer
+	unsigned long encoded = length;
+	if (dst_settings->write_final_eot_) {
+		encoded |= DMA_BYTE_CNT_WR_EOT_MASK;
+	} else {
+		encoded &= ~DMA_BYTE_CNT_WR_EOT_MASK;
+	}
+	if (src_settings->read_final_eot_) {
+		encoded |= DMA_BYTE_CNT_RD_EOT_MASK;
+	} else {
+		encoded &= ~DMA_BYTE_CNT_RD_EOT_MASK;
+	}
+	/*    if((src_settings->transfer_mode_) ||
+	 (src_settings->transfer_mode_)) {
+	 encoded |= DMA_BYTE_CNT_BURST_MASK;
+	 } else {
+	 encoded &= ~DMA_BYTE_CNT_BURST_MASK;
+	 }*/
+	return encoded;
+}
+
+static void dma_start_write(const ulong* buffer, int num_bytes)
+{
+	// Assemble complete memory settings
+	oxnas_dma_device_settings_t mem_settings = oxnas_ram_dma_settings;
+	mem_settings.address_ = (unsigned long) buffer;
+	mem_settings.address_mode_ = OXNAS_DMA_MODE_INC;
+
+	writel(encode_control_status(&mem_settings, &oxnas_sata_dma_settings),
+		SATA_DMA_REGS_BASE + DMA_CTRL_STATUS);
+	writel(mem_settings.address_, SATA_DMA_REGS_BASE + DMA_BASE_SRC_ADR);
+	writel(oxnas_sata_dma_settings.address_,
+		SATA_DMA_REGS_BASE + DMA_BASE_DST_ADR);
+	writel(encode_final_eot(&mem_settings, &oxnas_sata_dma_settings,
+				num_bytes),
+		SATA_DMA_REGS_BASE + DMA_BYTE_CNT);
+
+	dma_start();
+}
+
+static void dma_start_read(ulong* buffer, int num_bytes)
+{
+	// Assemble complete memory settings
+	oxnas_dma_device_settings_t mem_settings = oxnas_ram_dma_settings;
+	mem_settings.address_ = (unsigned long) buffer;
+	mem_settings.address_mode_ = OXNAS_DMA_MODE_INC;
+
+	writel(encode_control_status(&oxnas_sata_dma_settings, &mem_settings),
+		SATA_DMA_REGS_BASE + DMA_CTRL_STATUS);
+	writel(oxnas_sata_dma_settings.address_,
+		SATA_DMA_REGS_BASE + DMA_BASE_SRC_ADR);
+	writel(mem_settings.address_, SATA_DMA_REGS_BASE + DMA_BASE_DST_ADR);
+	writel(encode_final_eot(&oxnas_sata_dma_settings, &mem_settings,
+				num_bytes),
+		SATA_DMA_REGS_BASE + DMA_BYTE_CNT);
+
+	dma_start();
+}
+
+static inline int dma_busy(void)
+{
+	return readl(SATA_DMA_REGS_BASE + DMA_CTRL_STATUS)
+		& DMA_CTRL_STATUS_IN_PROGRESS;
+}
+
+static int wait_dma_not_busy(int device)
+{
+	unsigned int cleanup_required = 0;
+
+	/* Poll for DMA completion */
+	int loops = MAX_DMA_XFER_LOOPS;
+	do {
+		if (!dma_busy()) {
+			break;
+		}
+		udelay(100);
+	} while (--loops);
+
+	if (!loops) {
+		printf("wait_dma_not_busy() Timed out of wait for DMA not busy\n");
+		cleanup_required = 1;
+	}
+
+	if (cleanup_required) {
+		/* Abort DMA to make sure it has finished. */
+		unsigned int ctrl_status = readl(
+			SATA_DMA_CHANNEL + DMA_CTRL_STATUS);
+		ctrl_status |= DMA_CTRL_STATUS_RESET;
+		writel(ctrl_status, SATA_DMA_CHANNEL + DMA_CTRL_STATUS);
+
+		// Wait for the channel to become idle - should be quick as should
+		// finish after the next AHB single or burst transfer
+		loops = MAX_DMA_ABORT_LOOPS;
+		do {
+			if (!dma_busy()) {
+				break;
+			}
+			udelay(10);
+		} while (--loops);
+
+		if (!loops) {
+			printf("wait_dma_not_busy() Timed out of wait for DMA channel abort\n");
+		} else {
+			/* Successfully cleanup the DMA channel */
+			cleanup_required = 0;
+		}
+
+		// Deassert reset for the channel
+		ctrl_status = readl(SATA_DMA_CHANNEL + DMA_CTRL_STATUS);
+		ctrl_status &= ~DMA_CTRL_STATUS_RESET;
+		writel(ctrl_status, SATA_DMA_CHANNEL + DMA_CTRL_STATUS);
+	}
+
+	return !cleanup_required;
+}
+
+/**
+ * Possible that ATA status will not become not-busy, so must have timeout
+ */
+static unsigned int wait_not_busy(int device, unsigned long timeout_secs)
+{
+	int busy = 1;
+	unsigned long loops = (timeout_secs * 1000) / 50;
+	do {
+		// Test the ATA status register BUSY flag
+		if (!((*(sata_regs_base[device] + SATA_ORB2_OFF)
+			>> SATA_COMMAND_BIT) & (1UL << ATA_STATUS_BSY_BIT))) {
+			/* Not busy, so stop polling */
+			busy = 0;
+			break;
+		}
+
+		// Wait for 50mS before sampling ATA status register again
+		udelay(50000);
+	} while (--loops);
+
+	return busy;
+}
+
+void ide_output_data(int device, const ulong *sect_buf, int words)
+{
+	/* Only permit accesses to disks found to be present during ide_preinit() */
+	if (!disk_present[device]) {
+		return;
+	}
+
+	/* Select the required internal SATA drive */
+	device_select(device);
+
+	/* Start the DMA channel sending data from the passed buffer to the SATA core */
+	dma_start_write(sect_buf, words << 2);
+
+	/* Don't know why we need this delay, but without it the wait for DMA not
+	 busy times soemtimes out, e.g. when saving environment to second disk */
+	udelay(1000);
+
+	/* Wait for DMA to finish */
+	if (!wait_dma_not_busy(device)) {
+		printf("Timed out of wait for DMA channel for SATA device %d to have in-progress clear\n",
+			device);
+	}
+
+	/* Sata core should finish after DMA */
+	if (wait_not_busy(device, 30)) {
+		printf("Timed out of wait for SATA device %d to have BUSY clear\n",
+			device);
+	}
+	if (!wait_no_error(device)) {
+		printf("oxnas_sata_output_data() Wait for ATA no-error timed-out\n");
+	}
+}
+
+
+#define SATA_DM_DBG1			(SATA_HOST_REGS_BASE + 0)
+#define SATA_DATACOUNT_PORT0		(SATA_HOST_REGS_BASE + 0x10)
+#define SATA_DATACOUNT_PORT1		(SATA_HOST_REGS_BASE + 0x14)
+#define SATA_DATA_MUX_RAM0		(SATA_HOST_REGS_BASE + 0x8000)
+#define SATA_DATA_MUX_RAM1		(SATA_HOST_REGS_BASE + 0xA000)
+/* Sata core debug1 register bits */
+#define SATA_CORE_PORT0_DATA_DIR_BIT	20
+#define SATA_CORE_PORT1_DATA_DIR_BIT	21
+#define SATA_CORE_PORT0_DATA_DIR	(1 << SATA_CORE_PORT0_DATA_DIR_BIT)
+#define SATA_CORE_PORT1_DATA_DIR	(1 << SATA_CORE_PORT1_DATA_DIR_BIT)
+
+/**
+ * Ref bug-6320
+ *
+ * This code is a work around for a DMA hardware bug that will repeat the
+ * penultimate 8-bytes on some reads. This code will check that the amount
+ * of data transferred is a multiple of 512 bytes, if not the in it will
+ * fetch the correct data from a buffer in the SATA core and copy it into
+ * memory.
+ *
+ */
+static void sata_bug_6320_workaround(int port, ulong *candidate)
+{
+	int is_read;
+	int quads_transferred;
+	int remainder;
+	int sector_quads_remaining;
+
+	/* Only want to apply fix to reads */
+	is_read = !(*((unsigned long*) SATA_DM_DBG1)
+		& (port ? SATA_CORE_PORT1_DATA_DIR : SATA_CORE_PORT0_DATA_DIR));
+
+	/* Check for an incomplete transfer, i.e. not a multiple of 512 bytes
+	 transferred (datacount_port register counts quads transferred) */
+	quads_transferred = *((unsigned long*) (
+		port ? SATA_DATACOUNT_PORT1 : SATA_DATACOUNT_PORT0));
+
+	remainder = quads_transferred & 0x7f;
+	sector_quads_remaining = remainder ? (0x80 - remainder) : 0;
+
+	if (is_read && (sector_quads_remaining == 2)) {
+		debug("SATA read fixup, only transfered %d quads, "
+			"sector_quads_remaining %d, port %d\n",
+			quads_transferred, sector_quads_remaining, port);
+
+		int total_len = ATA_SECT_SIZE;
+		ulong *sata_data_ptr = (void*) (
+			port ? SATA_DATA_MUX_RAM1 : SATA_DATA_MUX_RAM0)
+			+ ((total_len - 8) % 2048);
+
+		*candidate = *sata_data_ptr;
+		*(candidate + 1) = *(sata_data_ptr + 1);
+	}
+}
+
+
+void ide_input_data(int device, ulong *sect_buf, int words)
+{
+	/* Only permit accesses to disks found to be present during ide_preinit() */
+	if (!disk_present[device]) {
+		return;
+	}
+
+	/* Select the required internal SATA drive */
+	device_select(device);
+
+	/* Start the DMA channel receiving data from the SATA core into the passed buffer */
+	dma_start_read(sect_buf, words << 2);
+
+	/* Sata core should finish before DMA */
+	if (wait_not_busy(device, 30)) {
+		printf("Timed out of wait for SATA device %d to have BUSY clear\n",
+			device);
+	}
+	if (!wait_no_error(device)) {
+		printf("oxnas_sata_output_data() Wait for ATA no-error timed-out\n");
+	}
+
+	/* Wait for DMA to finish */
+	if (!wait_dma_not_busy(device)) {
+		printf("Timed out of wait for DMA channel for SATA device %d to have in-progress clear\n",
+			device);
+	}
+
+	if (words == ATA_SECTORWORDS)
+		sata_bug_6320_workaround(device, sect_buf + words - 2);
+}
+
+static u32 scr_read(int device, unsigned int sc_reg)
+{
+	/* Setup adr of required register. std regs start eight into async region */
+	*(sata_regs_base[device] + SATA_LINK_RD_ADDR) = sc_reg
+		* 4+ SATA_STD_ASYNC_REGS_OFF;
+
+	/* Wait for data to be available */
+	int loops = MAX_SRC_READ_LOOPS;
+	do {
+		if (*(sata_regs_base[device] + SATA_LINK_CONTROL) & 1UL) {
+			break;
+		}
+		udelay(10);
+	} while (--loops);
+
+	if (!loops) {
+		printf("scr_read() Timed out of wait for read completion\n");
+	}
+
+	/* Read the data from the async register */
+	return *(sata_regs_base[device] + SATA_LINK_DATA);
+}
+
+static void scr_write(int device, unsigned int sc_reg, u32 val)
+{
+	/* Setup the data for the write */
+	*(sata_regs_base[device] + SATA_LINK_DATA) = val;
+
+	/* Setup adr of required register. std regs start eight into async region */
+	*(sata_regs_base[device] + SATA_LINK_WR_ADDR) = sc_reg
+		* 4+ SATA_STD_ASYNC_REGS_OFF;
+
+	/* Wait for data to be written */
+	int loops = MAX_SRC_WRITE_LOOPS;
+	do {
+		if (*(sata_regs_base[device] + SATA_LINK_CONTROL) & 1UL) {
+			break;
+		}
+		udelay(10);
+	} while (--loops);
+
+	if (!loops) {
+		printf("scr_write() Timed out of wait for write completion\n");
+	}
+}
+extern void workaround5458(void);
+
+#define PHY_LOOP_COUNT  25  /* Wait for upto 5 seconds for PHY to be found */
+#define LOS_AND_TX_LVL   0x2988
+#define TX_ATTEN         0x55629
+
+static int phy_reset(int device)
+{
+	int phy_status = 0;
+	int loops = 0;
+
+	scr_write(device, (0x60 - SATA_STD_ASYNC_REGS_OFF) / 4, LOS_AND_TX_LVL);
+	scr_write(device, (0x70 - SATA_STD_ASYNC_REGS_OFF) / 4, TX_ATTEN);
+
+	/* limit it to Gen-1 SATA (1.5G) */
+	scr_write(device, SATA_SCR_CONTROL, 0x311); /* Issue phy wake & core reset */
+	scr_read(device, SATA_SCR_STATUS); /* Dummy read; flush */
+	udelay(1000);
+	scr_write(device, SATA_SCR_CONTROL, 0x310); /* Issue phy wake & clear core reset */
+
+	/* Wait for upto 5 seconds for PHY to become ready */
+	do {
+		udelay(200000);
+		if ((scr_read(device, SATA_SCR_STATUS) & 0xf) == 3) {
+			scr_write(device, SATA_SCR_ERROR, ~0);
+			phy_status = 1;
+			break;
+		}
+		//printf("No SATA PHY found status:0x%x\n", scr_read(device, SATA_SCR_STATUS));
+	} while (++loops < PHY_LOOP_COUNT);
+
+	if (phy_status) {
+		udelay(500000); /* wait half a second */
+	}
+
+	return phy_status;
+}
+
+#define FIS_LOOP_COUNT  25  /* Wait for upto 5 seconds for FIS to be received */
+static int wait_FIS(int device)
+{
+	int status = 0;
+	int loops = 0;
+
+	do {
+		udelay(200000);
+		if (ide_inb(device, ATA_PORT_NSECT) > 0) {
+			status = 1;
+			break;
+		}
+	} while (++loops < FIS_LOOP_COUNT);
+
+	return status;
+}
+
+
+#define SATA_PHY_ASIC_STAT  (0x44900000)
+#define SATA_PHY_ASIC_DATA  (0x44900004)
+
+/**
+ * initialise functions and macros for ASIC implementation
+ */
+#define PH_GAIN         2
+#define FR_GAIN         3
+#define PH_GAIN_OFFSET  6
+#define FR_GAIN_OFFSET  8
+#define PH_GAIN_MASK  (0x3 << PH_GAIN_OFFSET)
+#define FR_GAIN_MASK  (0x3 << FR_GAIN_OFFSET)
+#define USE_INT_SETTING  (1<<5)
+
+#define CR_READ_ENABLE  (1<<16)
+#define CR_WRITE_ENABLE (1<<17)
+#define CR_CAP_DATA     (1<<18)
+
+static void wait_cr_ack(void)
+{
+	while ((readl(SATA_PHY_ASIC_STAT) >> 16) & 0x1f)
+		/* wait for an ack bit to be set */;
+}
+
+static unsigned short read_cr(unsigned short address)
+{
+	writel(address, SATA_PHY_ASIC_STAT);
+	wait_cr_ack();
+	writel(CR_READ_ENABLE, SATA_PHY_ASIC_DATA);
+	wait_cr_ack();
+	return readl(SATA_PHY_ASIC_STAT);
+}
+
+static void write_cr(unsigned short data, unsigned short address)
+{
+	writel(address, SATA_PHY_ASIC_STAT);
+	wait_cr_ack();
+	writel((data | CR_CAP_DATA), SATA_PHY_ASIC_DATA);
+	wait_cr_ack();
+	writel(CR_WRITE_ENABLE, SATA_PHY_ASIC_DATA);
+	wait_cr_ack();
+	return;
+}
+
+void workaround5458(void)
+{
+	unsigned i;
+
+	for (i = 0; i < 2; i++) {
+		unsigned short rx_control = read_cr(0x201d + (i << 8));
+		rx_control &= ~(PH_GAIN_MASK | FR_GAIN_MASK);
+		rx_control |= PH_GAIN << PH_GAIN_OFFSET;
+		rx_control |= FR_GAIN << FR_GAIN_OFFSET;
+		rx_control |= USE_INT_SETTING;
+		write_cr(rx_control, 0x201d + (i << 8));
+	}
+}
+
+int ide_preinit(void)
+{
+	int num_disks_found = 0;
+
+	/* Initialise records of which disks are present to all present */
+	int i;
+	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; i++) {
+		disk_present[i] = 1;
+	}
+
+	/* Block reset SATA and DMA cores */
+	reset_block(SYS_CTRL_RST_SATA, 1);
+	reset_block(SYS_CTRL_RST_SATA_LINK, 1);
+	reset_block(SYS_CTRL_RST_SATA_PHY, 1);
+	reset_block(SYS_CTRL_RST_SGDMA, 1);
+
+	/* Enable clocks to SATA and DMA cores */
+	enable_clock(SYS_CTRL_CLK_SATA);
+	enable_clock(SYS_CTRL_CLK_DMA);
+
+	udelay(5000);
+	reset_block(SYS_CTRL_RST_SATA_PHY, 0);
+	udelay(50);
+	reset_block(SYS_CTRL_RST_SATA, 0);
+	reset_block(SYS_CTRL_RST_SATA_LINK, 0);
+	udelay(50);
+	reset_block(SYS_CTRL_RST_SGDMA, 0);
+	udelay(100);
+	/* Apply the Synopsis SATA PHY workarounds */
+	workaround5458();
+	udelay(10000);
+
+	/* disable and clear core interrupts */
+	*((unsigned long*) SATA_HOST_REGS_BASE + SATA_INT_ENABLE_CLR_OFF) =
+		~0UL;
+	*((unsigned long*) SATA_HOST_REGS_BASE + SATA_INT_CLR_OFF) = ~0UL;
+
+	int device;
+	for (device = 0; device < CONFIG_SYS_IDE_MAXDEVICE; device++) {
+		int found = 0;
+		int retries = 1;
+
+		/* Disable SATA interrupts */
+		*(sata_regs_base[device] + SATA_INT_ENABLE_CLR_OFF) = ~0UL;
+
+		/* Clear any pending SATA interrupts */
+		*(sata_regs_base[device] + SATA_INT_CLR_OFF) = ~0UL;
+
+		do {
+			/* clear sector count register for FIS detection */
+			ide_outb(device, ATA_PORT_NSECT, 0);
+
+			/* Get the PHY working */
+			if (!phy_reset(device)) {
+				printf("SATA PHY not ready for device %d\n",
+					device);
+				break;
+			}
+
+			if (!wait_FIS(device)) {
+				printf("No FIS received from device %d\n",
+					device);
+			} else {
+				if ((scr_read(device, SATA_SCR_STATUS) & 0xf)
+					== 0x3) {
+					if (wait_not_busy(device, 30)) {
+						printf("Timed out of wait for SATA device %d to have BUSY clear\n",
+							device);
+					} else {
+						++num_disks_found;
+						found = 1;
+					}
+				} else {
+					printf("No SATA device %d found, PHY status = 0x%08x\n",
+						device,
+						scr_read(
+							device,
+							SATA_SCR_STATUS));
+				}
+				break;
+			}
+		} while (retries--);
+
+		/* Record whether disk is present, so won't attempt to access it later */
+		disk_present[device] = found;
+	}
+
+	/* post disk detection clean-up */
+	for (device = 0; device < CONFIG_SYS_IDE_MAXDEVICE; device++) {
+		if (disk_present[device]) {
+			/* set as ata-5 (28-bit) */
+			*(sata_regs_base[device] + SATA_DRIVE_CONTROL_OFF) =
+				0UL;
+
+			/* clear phy/link errors */
+			scr_write(device, SATA_SCR_ERROR, ~0);
+
+			/* clear host errors */
+			*(sata_regs_base[device] + SATA_CONTROL_OFF) |=
+				SATA_SCTL_CLR_ERR;
+
+			/* clear interrupt register as this clears the error bit in the IDE
+			 status register */
+			*(sata_regs_base[device] + SATA_INT_CLR_OFF) = ~0UL;
+		}
+	}
+
+	return !num_disks_found;
+}
+
diff --git a/package/boot/uboot-oxnas/src/drivers/usb/host/ehci-oxnas.c b/package/boot/uboot-oxnas/src/drivers/usb/host/ehci-oxnas.c
new file mode 100644
index 0000000..6ab05c5
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/drivers/usb/host/ehci-oxnas.c
@@ -0,0 +1,105 @@
+/*
+ * drivers/usb/host/ehci-oxnas.c
+ *
+ * Tzachi Perelstein <tzachi@marvell.com>
+ *
+ * This file is licensed under  the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+#include <common.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sysctl.h>
+#include <asm/arch/clock.h>
+
+#include "ehci.h"
+
+static struct ehci_hcor *ghcor;
+
+static int start_oxnas_usb_ehci(void)
+{
+#ifdef CONFIG_USB_PLLB_CLK
+	reset_block(SYS_CTRL_RST_PLLB, 0);
+	enable_clock(SYS_CTRL_CLK_REF600);
+
+	writel((1 << PLLB_ENSAT) | (1 << PLLB_OUTDIV) | (2 << PLLB_REFDIV),
+			SEC_CTRL_PLLB_CTRL0);
+	/* 600MHz pllb divider for 12MHz */
+	writel(PLLB_DIV_INT(50) | PLLB_DIV_FRAC(0), SEC_CTRL_PLLB_DIV_CTRL);
+#else
+	/* ref 300 divider for 12MHz */
+	writel(REF300_DIV_INT(25) | REF300_DIV_FRAC(0), SYS_CTRL_REF300_DIV);
+#endif
+
+	/* Ensure the USB block is properly reset */
+	reset_block(SYS_CTRL_RST_USBHS, 1);
+	reset_block(SYS_CTRL_RST_USBHS, 0);
+
+	reset_block(SYS_CTRL_RST_USBHSPHYA, 1);
+	reset_block(SYS_CTRL_RST_USBHSPHYA, 0);
+
+	reset_block(SYS_CTRL_RST_USBHSPHYB, 1);
+	reset_block(SYS_CTRL_RST_USBHSPHYB, 0);
+
+	/* Force the high speed clock to be generated all the time, via serial
+	 programming of the USB HS PHY */
+	writel((2UL << USBHSPHY_TEST_ADD) |
+		   (0xe0UL << USBHSPHY_TEST_DIN), SYS_CTRL_USBHSPHY_CTRL);
+
+	writel((1UL << USBHSPHY_TEST_CLK) |
+		   (2UL << USBHSPHY_TEST_ADD) |
+		   (0xe0UL << USBHSPHY_TEST_DIN), SYS_CTRL_USBHSPHY_CTRL);
+
+	writel((0xfUL << USBHSPHY_TEST_ADD) |
+		   (0xaaUL << USBHSPHY_TEST_DIN), SYS_CTRL_USBHSPHY_CTRL);
+
+	writel((1UL << USBHSPHY_TEST_CLK) |
+		   (0xfUL << USBHSPHY_TEST_ADD) |
+		   (0xaaUL << USBHSPHY_TEST_DIN), SYS_CTRL_USBHSPHY_CTRL);
+
+#ifdef CONFIG_USB_PLLB_CLK /* use pllb clock */
+		writel(USB_CLK_INTERNAL | USB_INT_CLK_PLLB, SYS_CTRL_USB_CTRL);
+#else /* use ref300 derived clock */
+		writel(USB_CLK_INTERNAL | USB_INT_CLK_REF300, SYS_CTRL_USB_CTRL);
+#endif
+	/* Enable the clock to the USB block */
+	enable_clock(SYS_CTRL_CLK_USBHS);
+
+	return 0;
+}
+int ehci_hcd_init(int index, enum usb_init_type init, struct ehci_hccr **hccr,
+		  struct ehci_hcor **hcor)
+{
+	start_oxnas_usb_ehci();
+	*hccr = (struct ehci_hccr *)(USB_HOST_BASE + 0x100);
+	*hcor = (struct ehci_hcor *)((uint32_t)*hccr +
+			HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase)));
+	ghcor = *hcor;
+	return 0;
+}
+
+int ehci_hcd_stop(int index)
+{
+	reset_block(SYS_CTRL_RST_USBHS, 1);
+	disable_clock(SYS_CTRL_CLK_USBHS);
+	return 0;
+}
+
+extern void __ehci_set_usbmode(int index);
+void ehci_set_usbmode(int index)
+{
+	#define  or_txttfill_tuning	_reserved_1_[0]
+	u32 tmp;
+
+	__ehci_set_usbmode(index);
+
+	tmp = ehci_readl(&ghcor->or_txfilltuning);
+	tmp &= ~0x00ff0000;
+	tmp |= 0x003f0000; /* set burst pre load count to 0x40 (63 * 4 bytes)  */
+	tmp |= 0x16; /* set sheduler overhead to 22 * 1.267us (HS) or 22 * 6.33us (FS/LS)*/
+	ehci_writel(&ghcor->or_txfilltuning, tmp);
+
+	tmp = ehci_readl(&ghcor->or_txttfill_tuning);
+	tmp |= 0x2; /* set sheduler overhead to 2 * 6.333us */
+	ehci_writel(&ghcor->or_txttfill_tuning, tmp);
+}
diff --git a/package/boot/uboot-oxnas/src/include/configs/ox820.h b/package/boot/uboot-oxnas/src/include/configs/ox820.h
new file mode 100644
index 0000000..9b6522b
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/include/configs/ox820.h
@@ -0,0 +1,384 @@
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+/* High Level Configuration Options */
+#define CONFIG_ARM1136
+#define CONFIG_OX820
+#define CONFIG_SYS_GENERIC_BOARD
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#include <asm/arch/cpu.h>	/* get chip and board defs */
+
+/* make cmd_ide.c quiet when compile */
+#define __io
+
+/*#define CONFIG_ARCH_CPU_INIT*/
+/*#define CONFIG_DISPLAY_CPUINFO*/
+/*#define CONFIG_DISPLAY_BOARDINFO*/
+/*#define CONFIG_BOARD_EARLY_INIT_F*/
+/*#define CONFIG_SKIP_LOWLEVEL_INIT*/
+
+/* mem */
+#define CONFIG_SYS_SDRAM_BASE		0x60000000
+#define CONFIG_NR_DRAM_BANKS		1
+#define CONFIG_MIN_SDRAM_SIZE		(128 * 1024 * 1024)	/* 128 MB */
+#define CONFIG_MAX_SDRAM_SIZE		(512 * 1024 * 1024)	/* 512 MB */
+#define CONFIG_SRAM_BASE		0x50000000
+#define CONFIG_SRAM_SIZE		(64 * 1024)
+
+/* need do dma so better keep dcache off */
+#define CONFIG_SYS_DCACHE_OFF
+
+/* clock */
+#define CONFIG_PLLA_FREQ_MHZ		800
+#define CONFIG_RPSCLK			6250000
+#define CONFIG_SYS_HZ			1000
+#define CONFIG_SYS_CLK_FREQ		CONFIG_RPSCLK
+#define CONFIG_SYS_TIMERBASE		TIMER1_BASE
+#define CONFIG_TIMER_PRESCALE		TIMER_PRESCALE_16
+
+/* serial */
+#define CONFIG_SYS_NS16550
+#define CONFIG_SYS_NS16550_SERIAL
+#define CONFIG_SYS_NS16550_CLK		CONFIG_RPSCLK
+#define CONFIG_SYS_NS16550_REG_SIZE	1
+#define CONFIG_BAUDRATE			115200
+#define CONFIG_SYS_NS16550_COM1		UART_1_BASE
+#define CONFIG_CONS_INDEX		1
+
+/* ide */
+#define CONFIG_SYS_ATA_BASE_ADDR	0
+#define CONFIG_SYS_ATA_DATA_OFFSET	0
+#define CONFIG_SYS_ATA_REG_OFFSET	0
+#define CONFIG_SYS_ATA_ALT_OFFSET	0
+#define CONFIG_IDE_PLX
+#define CONFIG_SYS_IDE_MAXDEVICE	2
+#define CONFIG_SYS_IDE_MAXBUS		1
+#define CONFIG_IDE_PREINIT
+#define CONFIG_LBA48
+
+/* nand */
+#define CONFIG_NAND
+#define CONFIG_SYS_MAX_NAND_DEVICE	1
+#define CONFIG_SYS_NAND_BASE		STATIC_CS0_BASE
+#define NAND_CLE_ADDR_PIN		19
+#define NAND_ALE_ADDR_PIN		18
+#define MTDPARTS_DEFAULT		"mtdparts=41000000.nand:" \
+						"14m(boot)," \
+                                                "-(ubi)"
+#define MTDIDS_DEFAULT			"nand0=41000000.nand"
+#define UBIPART_DEFAULT			"ubi"
+
+/* net */
+#define CONFIG_DESIGNWARE_ETH
+#define CONFIG_DW_ALTDESCRIPTOR
+#define CONFIG_MII
+#define CONFIG_CMD_MII
+#define CONFIG_PHYLIB
+#define CONFIG_PHY_REALTEK
+#define CONFIG_PHY_ICPLUS
+
+/* spl */
+#ifdef CONFIG_SPL_BUILD
+#define USE_DL_PREFIX	/* rename malloc free etc, so we can override them */
+#endif
+
+#if defined(CONFIG_BOOT_FROM_NAND) || defined(CONFIG_BOOT_FROM_SATA)
+#define CONFIG_SPL
+#define CONFIG_SPL_FRAMEWORK
+#define CONFIG_SPL_LIBCOMMON_SUPPORT
+#define CONFIG_SPL_SERIAL_SUPPORT
+#define CONFIG_SPL_LIBGENERIC_SUPPORT
+#define CONFIG_SPL_TEXT_BASE			0x50000000
+#define CONFIG_SPL_STACK			(CONFIG_SRAM_BASE + (48 * 1024))
+#define CONFIG_SPL_DISPLAY_PRINT
+#define CONFIG_SPL_BSS_DRAM_START			0x65000000
+#define CONFIG_SPL_BSS_DRAM_SIZE			0x01000000
+#define CONFIG_SPL_MALLOC_START				0x66000000
+#endif
+
+#if defined(CONFIG_BOOT_FROM_NAND)
+#define CONFIG_SPL_NAND_SUPPORT
+#define BOOT_DEVICE_TYPE			"NAND"
+#define BOOT_DEVICE_NAND			0xfeedbacc
+#define CONFIG_SPL_BOOT_DEVICE			BOOT_DEVICE_NAND
+#define CONFIG_SPL_NAND_SIMPLE
+#define CONFIG_SPL_NAND_ECC
+#define CONFIG_SPL_NAND_SOFTECC
+#define CONFIG_SYS_NAND_ECCSIZE			512
+#define CONFIG_SYS_NAND_ECCBYTES		6
+#define CONFIG_SYS_NAND_ECCPOS			{40, 41, 42, 43, 44, 45, 46, 47, \
+						48, 49, 50, 51, 52, 53, 54, 55, \
+						56, 57, 58, 59, 60, 61, 62, 63}
+#define CONFIG_SYS_NAND_PAGE_SIZE		2048
+#define CONFIG_SYS_NAND_OOBSIZE			64
+#define CONFIG_SYS_NAND_BLOCK_SIZE		(128 * 1024)
+#define CONFIG_SYS_NAND_BAD_BLOCK_POS		0
+/* pages per erase block */
+#define CONFIG_SYS_NAND_PAGE_COUNT		(CONFIG_SYS_NAND_BLOCK_SIZE / CONFIG_SYS_NAND_PAGE_SIZE)
+/* nand spl use 1 erase block, and use bit to byte encode for reliability */
+#define CONFIG_SPL_MAX_SIZE			(128 * 1024 / 8)
+#define CONFIG_SYS_NAND_U_BOOT_OFFS		0x00040000
+/* spl kernel load is not enabled */
+#define CONFIG_SYS_NAND_SPL_KERNEL_OFFS		0x00200000
+#define CONFIG_CMD_SPL_NAND_OFS			0
+#define CONFIG_CMD_SPL_WRITE_SIZE		1024
+#define CONFIG_SYS_SPL_ARGS_ADDR		(CONFIG_SYS_SDRAM_BASE + 0x100)
+/* CONFIG_BOOT_FROM_NAND end */
+
+#elif defined(CONFIG_BOOT_FROM_SATA)
+#define CONFIG_SPL_BLOCK_SUPPORT
+#define BOOT_DEVICE_TYPE				"SATA"
+#define BOOT_DEVICE_BLOCK				860202
+#define CONFIG_SPL_BOOT_DEVICE				BOOT_DEVICE_BLOCK
+#define CONFIG_SPL_MAX_SIZE				(36 * 1024)
+#define CONFIG_SPL_LIBDISK_SUPPORT
+#define CONFIG_SPL_BLOCKDEV_INTERFACE			"ide"
+#define CONFIG_SPL_BLOCKDEV_ID				0
+
+#ifdef CONFIG_BOOT_FROM_FAT /* u-boot in fat partition */
+
+#define CONFIG_SPL_FAT_SUPPORT
+
+#define CONFIG_BLOCKDEV_FAT_BOOT_PARTITION		1 /* first partition */
+#define CONFIG_SPL_FAT_LOAD_PAYLOAD_NAME		"u-boot.img" /* u-boot file name */
+/* enable U-Boot Falcon Mode */
+#define CONFIG_CMD_SPL
+#define CONFIG_SPL_OS_BOOT
+#define CONFIG_SPL_FAT_LOAD_ARGS_NAME			"bootargs.bin" /* boot parameters */
+#define CONFIG_SPL_FAT_LOAD_KERNEL_NAME			"falcon.img" /* kernel */
+#define CONFIG_SYS_SPL_ARGS_ADDR			(CONFIG_SYS_SDRAM_BASE + 0x100)
+
+#elif CONFIG_BOOT_FROM_EXT4
+
+#define CONFIG_SPL_EXT4_SUPPORT
+#define CONFIG_BLOCKDEV_EXT4_BOOT_PARTITION		1 /* first partition */
+#define CONFIG_SPL_EXT4_LOAD_PAYLOAD_NAME		"/boot/u-boot.img" /* u-boot file name */
+/* enable U-Boot Falcon Mode */
+#define CONFIG_CMD_SPL
+#define CONFIG_SPL_OS_BOOT
+#define CONFIG_SPL_EXT4_LOAD_ARGS_NAME			"/boot/bootargs.bin" /* boot parameters */
+#define CONFIG_SPL_EXT4_LOAD_KERNEL_NAME		"/boot/falcon.img" /* kernel */
+#define CONFIG_SYS_SPL_ARGS_ADDR			(CONFIG_SYS_SDRAM_BASE + 0x100)
+
+#else /* u-boot in raw sectors */
+
+#define CONFIG_SYS_BLOCK_RAW_MODE_U_BOOT_SECTOR		1024
+/* spl kernel load is not enabled */
+#define CONFIG_SYS_BLOCK_RAW_MODE_KERNEL_SECTOR		4096
+#define CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTOR		0
+#define CONFIG_SYS_BLOCK_RAW_MODE_ARGS_SECTORS		(1024 / 512)
+#define CONFIG_SYS_SPL_ARGS_ADDR			(CONFIG_SYS_SDRAM_BASE + 0x100)
+
+#endif /* CONFIG_BOOT_FROM_FAT */
+/* CONFIG_BOOT_FROM_SATA end */
+
+#else
+/* generic, no spl support */
+#endif
+
+/* boot */
+#define CONFIG_IDENT_STRING		" for OXNAS"
+#define CONFIG_MACH_TYPE		MACH_TYPE_OXNAS
+#ifndef CONFIG_SPL_BUILD
+/* Enable devicetree support */
+#define CONFIG_OF_LIBFDT
+#endif
+#define CONFIG_SETUP_MEMORY_TAGS
+#define CONFIG_CMDLINE_TAG
+#define CONFIG_INITRD_TAG
+#define CONFIG_BOOTDELAY		1
+#define CONFIG_ZERO_BOOTDELAY_CHECK
+#define CONFIG_DEFAULT_CONSOLE_PARM	"console=ttyS0,115200n8 earlyprintk=serial"
+/* Boot Argument Buffer Size */
+#define CONFIG_SYS_BARGSIZE		CONFIG_SYS_CBSIZE
+/* memtest works on */
+#define CONFIG_SYS_LOAD_ADDR		(CONFIG_SYS_SDRAM_BASE)
+#define CONFIG_SYS_AUTOLOAD		"no"
+
+#define CONFIG_DEFAULT_CONSOLE		CONFIG_DEFAULT_CONSOLE_PARM "\0"
+#define CONFIG_BOOTARGS			CONFIG_DEFAULT_CONSOLE_PARM
+#define CONFIG_BOOTCOMMAND		"run nandboot"
+#define CONFIG_BOOT_RETRY_TIME		-1
+#define CONFIG_RESET_TO_RETRY		60
+
+#define CONFIG_NETCONSOLE
+#define CONFIG_IPADDR			192.168.50.100
+#define CONFIG_SERVERIP			192.168.50.59
+
+/* A sane default configuration...
+ * When booting without a valid environment in ubi, first to loading and booting
+ * the kernel image directly above U-Boot, maybe both were loaded there by
+ * another bootloader.
+ * Also use that same offset (0x90000) to load the rescue image later on (by
+ * adding it onto the flash address where U-Boot is supposed to be stored by
+ * the legacy loader, 0x440000, resulting in offset 0x4d0000 on the flash).
+ * When coming up with a valid environment in ubi, first try to load the
+ * kernel from a ubi volume kernel, if that fails, fallback to the rescue
+ * image stored in boot partition. As a last resort try booting via
+ * DHCP/TFTP.
+ * In case there is no valid environment, first probe for a uimage in ram left
+ * behind by the first bootloader on a tftp boot.
+ * If that fails, switch to normal boot order and save environment.
+ * The loader is supposed to be written to flash at offset 0x440000 and loaded to
+ * RAM at 0x64000000
+ */
+#define CONFIG_EXTRA_ENV_SETTINGS	\
+	"load_kernel_ubi=ubi readvol 0x62000000 kernel;\0" \
+	"load_kernel_rescue=nand read 0x62000000 0x4e0000 0x400000;\0" \
+	"load_kernel_dhcp=dhcp 0x62000000 oxnas-rescue.bin;\0" \
+	"boot_kernel=bootm 0x62000000;\0" \
+	"boot_ubi=run load_kernel_ubi && run boot_kernel;\0" \
+	"boot_rescue=run load_kernel_rescue && run boot_kernel;\0" \
+	"boot_dhcp=run load_kernel_dhcp && run boot_kernel;\0" \
+	"normalboot=run boot_ubi; run boot_rescue; run boot_dhcp;\0" \
+	"firstboot=bootm 0x640a0000; setenv bootcmd run normalboot; " \
+	"setenv firstboot; saveenv; run bootcmd; \0" \
+	"bootcmd=run firstboot; \0" \
+	"console=" CONFIG_DEFAULT_CONSOLE \
+	"bootargs=" CONFIG_BOOTARGS "\0" \
+	"mtdids=" MTDIDS_DEFAULT "\0" \
+	"mtdparts=" MTDPARTS_DEFAULT "\0" \
+
+/* env */
+#if defined(CONFIG_BOOT_FROM_NAND)
+#define CONFIG_ENV_IS_IN_NAND
+#define CONFIG_ENV_OFFSET		0x000C0000
+#define CONFIG_ENV_SIZE			0x00020000
+#define CONFIG_ENV_OFFSET_REDUND	0x00100000
+#define CONFIG_ENV_SIZE_REDUND		0x00020000
+#define CONFIG_ENV_RANGE		(CONFIG_ENV_SIZE * 2)
+/* CONFIG_BOOT_FROM_NAND end */
+
+#elif defined(CONFIG_BOOT_FROM_SATA)
+#ifdef CONFIG_BOOT_FROM_EXT4
+#define CONFIG_ENV_IS_IN_EXT4
+#define CONFIG_START_IDE
+#define EXT4_ENV_INTERFACE 		"ide"
+#define EXT4_ENV_DEVICE			0
+#define EXT4_ENV_PART			1
+#define EXT4_ENV_FILE			"/boot/u-boot.env"
+#define CONFIG_ENV_SIZE			(16 * 1024)
+#else
+#define CONFIG_ENV_IS_IN_FAT
+#define CONFIG_START_IDE
+#define FAT_ENV_INTERFACE 		"ide"
+#define FAT_ENV_DEVICE			0
+#define FAT_ENV_PART			1
+#define FAT_ENV_FILE			"u-boot.env"
+#define CONFIG_ENV_SIZE			(16 * 1024)
+#endif
+/* CONFIG_BOOT_FROM_SATA end */
+#elif defined(CONFIG_BOOT_FROM_SATA)
+
+#else
+/* generic */
+#define CONFIG_ENV_IS_IN_UBI		1
+#define CONFIG_ENV_UBI_PART		UBIPART_DEFAULT
+#define CONFIG_ENV_UBI_VOLUME		"ubootenv"
+#define CONFIG_ENV_UBI_VOLUME_REDUND	"ubootenv2"
+#define CONFIG_ENV_SIZE			(16 * 1024)
+#endif
+
+/* allow to overwrite serial and ethaddr */
+#define CONFIG_ENV_OVERWRITE
+
+#define CONFIG_SYS_MONITOR_LEN		(512 * 1024)
+#define CONFIG_SYS_TEXT_BASE		0x64000000
+#define CONFIG_SYS_INIT_SP_ADDR		0x65000000
+/* Size of malloc() pool */
+#define CONFIG_SYS_MALLOC_LEN		(1 * 1024 * 1024)
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_LONGHELP		/* undef to save memory */
+#define CONFIG_SYS_HUSH_PARSER		/* use "hush" command parser	*/
+#define CONFIG_SYS_PROMPT		"OX820 # "
+#define CONFIG_SYS_CBSIZE		1024	/* Console I/O Buffer Size*/
+#define CONFIG_SYS_PBSIZE		1024	/* Print Buffer Size */
+#define CONFIG_SYS_MAXARGS		32	/* max number of command args */
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+
+/* usb */
+#define CONFIG_USB_MAX_CONTROLLER_COUNT	1
+#define CONFIG_USB_EHCI
+#define CONFIG_EHCI_IS_TDI
+/* #define CONFIG_USB_EHCI_TXFIFO_THRESH	0x3F */
+#define CONFIG_USB_PLLB_CLK
+#define CONFIG_USB_EHCI_OXNAS
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_USB_STORAGE
+#endif
+#define CONFIG_CMD_USB
+
+/* cmds */
+#define CONFIG_SYS_NO_FLASH
+#include <config_cmd_default.h>
+
+#define CONFIG_CMD_SAVEENV
+#define CONFIG_CMD_ASKENV
+#define CONFIG_CMD_GREPENV
+#define CONFIG_CMD_ENV_FLAGS
+
+#define CONFIG_CMD_NET
+#define CONFIG_CMD_DHCP
+#define CONFIG_CMD_NFS
+#define CONFIG_CMD_PING
+#define CONFIG_CMD_PXE
+
+#define CONFIG_CMD_NAND
+#define CONFIG_CMD_MTDPARTS
+#define CONFIG_CMD_UBI
+#define CONFIG_CMD_UBIFS
+
+#define CONFIG_CMD_IDE
+#define CONFIG_CMD_FAT
+#define CONFIG_FAT_WRITE
+#define CONFIG_CMD_EXT2
+#define CONFIG_CMD_EXT4
+#ifndef CONFIG_SPL_BUILD
+#define CONFIG_CMD_EXT4_WRITE
+#endif
+
+#define CONFIG_CMD_ZIP
+#define CONFIG_CMD_UNZIP
+#define CONFIG_CMD_TIME
+#define CONFIG_CMD_SETEXPR
+#define CONFIG_CMD_MD5SUM
+#define CONFIG_CMD_HASH
+#define CONFIG_CMD_INI
+#define CONFIG_CMD_GETTIME
+#define CONFIG_CMD_BOOTMENU
+#define CONFIG_CMD_ELF
+#define CONFIG_CMD_BOOTZ
+
+#define CONFIG_DOS_PARTITION
+#define CONFIG_EFI_PARTITION
+
+/* for CONFIG_CMD_MTDPARTS */
+#define CONFIG_MTD_DEVICE
+/* for CONFIG_CMD_UBI */
+#define CONFIG_MTD_PARTITIONS
+/* for CONFIG_CMD_UBI */
+#define CONFIG_RBTREE
+
+/* optional, for CONFIG_CMD_BOOTM & required by CONFIG_CMD_UBIFS */
+#define CONFIG_LZO
+#define CONFIG_LZMA
+#define CONFIG_BZIP2
+
+/* for CONFIG_CMD_ZIP */
+#define CONFIG_GZIP_COMPRESSED
+/* for CONFIG_CMD_MD5SUM */
+#define CONFIG_MD5
+#define CONFIG_MD5SUM_VERIFY
+/* enable CONFIG_CMD_HASH's verification feature */
+#define CONFIG_HASH_VERIFY
+#define CONFIG_REGEX
+/* for CONFIG_CMD_BOOTMENU & CONFIG_CMD_PXE */
+#define CONFIG_MENU
+
+/* for new FIT uImage format generated in OpenWrt */
+#define CONFIG_FIT
+
+#endif	/* __CONFIG_H */
diff --git a/package/boot/uboot-oxnas/src/tools/mkox820crc.c b/package/boot/uboot-oxnas/src/tools/mkox820crc.c
new file mode 100644
index 0000000..8737062
--- /dev/null
+++ b/package/boot/uboot-oxnas/src/tools/mkox820crc.c
@@ -0,0 +1,126 @@
+/* J J Larworthy 27 September 2006 */
+
+/* file to read the boot sector of a dis and the loaded image and report
+ * if the boot rom would accept the data as intact and suitable for use
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/errno.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+extern uint32_t crc32(uint32_t, const unsigned char *, unsigned int);
+
+#define NUMBER_VECTORS   12
+struct {
+	unsigned int start_vector[NUMBER_VECTORS];
+	char code[4];
+	unsigned int header_length;
+	unsigned int reserved[3];
+	unsigned int length;
+	unsigned int img_CRC;
+	unsigned int CRC;
+} img_header;
+
+void print_usage(void)
+{
+	printf("update_header file.bin\n");
+}
+
+void print_header(void)
+{
+	int i;
+
+	printf("vectors in header\n");
+	for (i = 0; i < NUMBER_VECTORS; i++) {
+		printf("%d:0x%08x\n", i, img_header.start_vector[i]);
+	}
+	printf("length:%8x\nimg_CRC:0x%08x\nHeader CRC:0x%08x\n",
+		img_header.length, img_header.img_CRC, img_header.CRC);
+}
+
+int main(int argc, char **argv)
+{
+	int in_file;
+	int status;
+	int unsigned crc;
+	int file_length;
+	int len;
+
+	struct stat file_stat;
+
+	void *executable;
+
+	in_file = open(argv[1], O_RDWR);
+
+	if (in_file < 0) {
+		printf("failed to open file:%s\n", argv[optind]);
+		return -ENOENT;
+	}
+
+	status = fstat(in_file, &file_stat);
+
+	/* read header and obtain size of image */
+	status = read(in_file, &img_header, sizeof(img_header));
+
+	file_length = file_stat.st_size - sizeof(img_header);
+
+	if (img_header.length != file_length) {
+		printf("size in header:%d, size of file: %d\n",
+			img_header.length, file_length);
+	}
+	img_header.length = file_length;
+
+	/* read working image and CRC */
+	executable = malloc(file_length);
+
+	status = read(in_file, executable, file_length);
+
+	if (status != file_length) {
+		printf("Failed to load image\n");
+		free(executable);
+		return -ENOENT;
+	}
+
+	/* verify image CRC */
+	crc = crc32(0, (const unsigned char *) executable, img_header.length);
+
+	if (crc != img_header.img_CRC) {
+		printf("New Image CRC:0x%08x, hdr:0x%08x\n", crc,
+			img_header.img_CRC);
+		img_header.img_CRC = crc;
+	}
+	memcpy(img_header.code, "BOOT", 4);
+	img_header.header_length = sizeof(img_header);
+
+	/* check header CRC */
+	crc = crc32(0, (const unsigned char *) &img_header,
+			sizeof(img_header) - sizeof(unsigned int));
+	if (crc != img_header.CRC) {
+		printf("New header CRC - crc:0x%08x hdr:0x%08x\n", crc,
+			img_header.CRC);
+		img_header.CRC = crc;
+	}
+
+	/* re-write the file */
+	status = lseek(in_file, 0, SEEK_SET);
+	if (status != 0) {
+		printf("failed to rewind\n");
+		free(executable);
+		return 1;
+	}
+	len = write(in_file, &img_header, sizeof(img_header));
+	assert(len == sizeof(img_header));
+	len = write(in_file, executable, file_length);
+	assert(len == file_length);
+	close(in_file);
+	free(executable);
+
+	return 0;
+}
diff --git a/package/boot/uboot-ramips/Makefile b/package/boot/uboot-ramips/Makefile
new file mode 100644
index 0000000..5229f5c
--- /dev/null
+++ b/package/boot/uboot-ramips/Makefile
@@ -0,0 +1,34 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2020.04
+PKG_RELEASE:=1
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=ramips
+  UBOOT_IMAGE:=u-boot.bin
+endef
+
+define U-Boot/ravpower_rp-wd009
+  BUILD_DEVICES:=ravpower_rp-wd009
+  BUILD_SUBTARGET:=mt76x8
+  NAME:=RAVPower RP-WD009
+  UBOOT_CONFIG:=ravpower-rp-wd009-ram
+endef
+
+UBOOT_TARGETS := \
+	ravpower_rp-wd009
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(INSTALL_BIN) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(VARIANT)-$(UBOOT_IMAGE)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch b/package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch
new file mode 100644
index 0000000..1833a62
--- /dev/null
+++ b/package/boot/uboot-ramips/patches/0001-add-support-for-RAVPower-RP-WD009.patch
@@ -0,0 +1,290 @@
+From 593db38363297247df731566c2aa307a5d795005 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Thu, 18 Jun 2020 00:13:11 +0200
+Subject: [PATCH] add support for RAVPower RP-WD009
+
+---
+ arch/mips/dts/Makefile                  |  3 +-
+ arch/mips/dts/ravpower-rp-wd009.dts     | 50 +++++++++++++++++++++
+ arch/mips/mach-mtmips/Kconfig           |  9 ++++
+ board/ravpower/rp-wd009/Kconfig         | 12 +++++
+ board/ravpower/rp-wd009/Makefile        |  3 ++
+ board/ravpower/rp-wd009/board.c         | 16 +++++++
+ configs/ravpower-rp-wd009-ram_defconfig | 59 +++++++++++++++++++++++++
+ include/configs/ravpower-rp-wd009.h     | 48 ++++++++++++++++++++
+ 8 files changed, 199 insertions(+), 1 deletion(-)
+ create mode 100644 arch/mips/dts/ravpower-rp-wd009.dts
+ create mode 100644 board/ravpower/rp-wd009/Kconfig
+ create mode 100644 board/ravpower/rp-wd009/Makefile
+ create mode 100644 board/ravpower/rp-wd009/board.c
+ create mode 100644 configs/ravpower-rp-wd009-ram_defconfig
+ create mode 100644 include/configs/ravpower-rp-wd009.h
+
+diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
+index c9d75596f2..23868ae1d2 100644
+--- a/arch/mips/dts/Makefile
++++ b/arch/mips/dts/Makefile
+@@ -2,7 +2,8 @@
+ 
+ dtb-$(CONFIG_ARCH_MTMIPS) += \
+ 	gardena-smart-gateway-mt7688.dtb \
+-	linkit-smart-7688.dtb
++	linkit-smart-7688.dtb \
++	ravpower-rp-wd009.dtb
+ dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
+ dtb-$(CONFIG_TARGET_AP143) += ap143.dtb
+ dtb-$(CONFIG_TARGET_AP152) += ap152.dtb
+diff --git a/arch/mips/dts/ravpower-rp-wd009.dts b/arch/mips/dts/ravpower-rp-wd009.dts
+new file mode 100644
+index 0000000000..b271d5bfbc
+--- /dev/null
++++ b/arch/mips/dts/ravpower-rp-wd009.dts
+@@ -0,0 +1,50 @@
++// SPDX-License-Identifier: GPL-2.0
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++/dts-v1/;
++
++#include "mt7628a.dtsi"
++#include <dt-bindings/gpio/gpio.h>
++
++/ {
++	compatible = "ravpower,rp-wd009", "ralink,mt7628a-soc";
++	model = "RAVPower RP-WD009";
++
++	aliases {
++		serial0 = &uart0;
++		spi0 = &spi0;
++	};
++
++	memory@0 {
++		device_type = "memory";
++		reg = <0x0 0x4000000>;
++	};
++
++	chosen {
++		stdout-path = "serial0:115200n8";
++	};
++};
++
++&uart0 {
++	status = "okay";
++};
++
++&spi0 {
++	status = "okay";
++	num-cs = <2>;
++
++	spi-flash@0 {
++		#address-cells = <1>;
++		#size-cells = <1>;
++		compatible = "jedec,spi-nor";
++		spi-max-frequency = <40000000>;
++		reg = <0>;
++	};
++};
++
++&eth {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ephy_router_mode>;
++};
+diff --git a/arch/mips/mach-mtmips/Kconfig b/arch/mips/mach-mtmips/Kconfig
+index c8dcf19c0d..85ac8878ab 100644
+--- a/arch/mips/mach-mtmips/Kconfig
++++ b/arch/mips/mach-mtmips/Kconfig
+@@ -32,6 +32,14 @@ config BOARD_GARDENA_SMART_GATEWAY_MT7688
+ 	  GARDENA smart Gateway boards have a MT7688 SoC with 128 MiB of RAM
+ 	  and 8 MiB of flash (SPI NOR) and additional SPI NAND storage.
+ 
++config BOARD_RAVPOWER_RP_WD009
++	bool "RAVPower RP-WD009"
++	depends on SOC_MT7628
++	select BOARD_LATE_INIT
++	select SUPPORTS_BOOT_RAM
++	help
++	  RAVPower RP-WD009
++
+ config BOARD_LINKIT_SMART_7688
+ 	bool "LinkIt Smart 7688"
+ 	depends on SOC_MT7628
+@@ -133,6 +141,7 @@ config SUPPORTS_BOOT_RAM
+ 	bool
+ 
+ source "board/gardena/smart-gateway-mt7688/Kconfig"
++source "board/ravpower/rp-wd009/Kconfig"
+ source "board/seeed/linkit-smart-7688/Kconfig"
+ 
+ endmenu
+diff --git a/board/ravpower/rp-wd009/Kconfig b/board/ravpower/rp-wd009/Kconfig
+new file mode 100644
+index 0000000000..111f8e4478
+--- /dev/null
++++ b/board/ravpower/rp-wd009/Kconfig
+@@ -0,0 +1,12 @@
++if BOARD_RAVPOWER_RP_WD009
++
++config SYS_BOARD
++	default "rp-wd009"
++
++config SYS_VENDOR
++	default "ravpower"
++
++config SYS_CONFIG_NAME
++	default "ravpower-rp-wd009"
++
++endif
+diff --git a/board/ravpower/rp-wd009/Makefile b/board/ravpower/rp-wd009/Makefile
+new file mode 100644
+index 0000000000..70cd7a8e56
+--- /dev/null
++++ b/board/ravpower/rp-wd009/Makefile
+@@ -0,0 +1,3 @@
++# SPDX-License-Identifier: GPL-2.0+
++
++obj-y += board.o
+diff --git a/board/ravpower/rp-wd009/board.c b/board/ravpower/rp-wd009/board.c
+new file mode 100644
+index 0000000000..eabcf85735
+--- /dev/null
++++ b/board/ravpower/rp-wd009/board.c
+@@ -0,0 +1,16 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++
++int board_early_init_f(void)
++{
++	return 0;
++}
++
++
++int board_late_init(void)
++{
++	return 0;
++}
+diff --git a/configs/ravpower-rp-wd009-ram_defconfig b/configs/ravpower-rp-wd009-ram_defconfig
+new file mode 100644
+index 0000000000..08cbf40638
+--- /dev/null
++++ b/configs/ravpower-rp-wd009-ram_defconfig
+@@ -0,0 +1,59 @@
++CONFIG_MIPS=y
++CONFIG_SYS_TEXT_BASE=0x80010000
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_ARCH_MTMIPS=y
++CONFIG_MIPS_BOOT_FDT=y
++CONFIG_LEGACY_IMAGE_FORMAT=y
++CONFIG_OF_STDOUT_VIA_ALIAS=y
++CONFIG_USE_BOOTCOMMAND=y
++CONFIG_BOOTCOMMAND="sf probe && mtd read firmware 82000000 && bootm 82000000"
++CONFIG_USE_PREBOOT=y
++CONFIG_SYS_CONSOLE_INFO_QUIET=y
++CONFIG_VERSION_VARIABLE=y
++CONFIG_BOARD_RAVPOWER_RP_WD009=y
++CONFIG_BOARD_EARLY_INIT_F=y
++CONFIG_HUSH_PARSER=y
++CONFIG_CMD_LICENSE=y
++# CONFIG_CMD_ELF is not set
++# CONFIG_CMD_XIMG is not set
++CONFIG_CMD_MEMINFO=y
++# CONFIG_CMD_FLASH is not set
++CONFIG_CMD_GPIO=y
++# CONFIG_CMD_LOADS is not set
++CONFIG_CMD_MTD=y
++CONFIG_CMD_SPI=y
++CONFIG_CMD_WDT=y
++CONFIG_CMD_DHCP=y
++CONFIG_CMD_MII=y
++CONFIG_CMD_PING=y
++CONFIG_CMD_TIME=y
++CONFIG_CMD_UUID=y
++CONFIG_CMD_MTDPARTS=y
++CONFIG_MTDIDS_DEFAULT="nor0=spi0.0"
++CONFIG_MTDPARTS_DEFAULT="spi0.0:192k(factory-uboot),64k(config),64k(factory),1536k(loader),64k(params),64k(user_backup),64k(user),14272k(firmware),64k(mode)"
++CONFIG_DEFAULT_DEVICE_TREE="ravpower-rp-wd009"
++CONFIG_NET_RANDOM_ETHADDR=y
++# CONFIG_DM_DEVICE_REMOVE is not set
++CONFIG_HAVE_BLOCK_DEVICE=y
++CONFIG_LED=y
++CONFIG_LED_BLINK=y
++CONFIG_LED_GPIO=y
++CONFIG_MTD=y
++CONFIG_DM_MTD=y
++CONFIG_SPI_FLASH_GIGADEVICE=y
++CONFIG_SPI_FLASH_MACRONIX=y
++CONFIG_SPI_FLASH_SPANSION=y
++CONFIG_SPI_FLASH_STMICRO=y
++CONFIG_SPI_FLASH_WINBOND=y
++CONFIG_SPI_FLASH_XMC=y
++CONFIG_SPI_FLASH_MTD=y
++CONFIG_MTD_UBI_BEB_LIMIT=22
++CONFIG_MT7628_ETH=y
++CONFIG_PHY=y
++CONFIG_SPI=y
++CONFIG_MT7621_SPI=y
++CONFIG_SYSRESET_SYSCON=y
++CONFIG_WDT=y
++CONFIG_WDT_MT7621=y
++CONFIG_LZMA=y
++CONFIG_BAUDRATE=57600
+diff --git a/include/configs/ravpower-rp-wd009.h b/include/configs/ravpower-rp-wd009.h
+new file mode 100644
+index 0000000000..bb4145197c
+--- /dev/null
++++ b/include/configs/ravpower-rp-wd009.h
+@@ -0,0 +1,48 @@
++/* SPDX-License-Identifier: GPL-2.0+ */
++/*
++ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
++ */
++
++#ifndef __CONFIG_RAVPOWER_RP_WD009_H
++#define __CONFIG_RAVPOWER_RP_WD009_H
++
++/* CPU */
++#define CONFIG_SYS_MIPS_TIMER_FREQ	290000000
++
++/* RAM */
++#define CONFIG_SYS_SDRAM_BASE		0x80000000
++
++#define CONFIG_SYS_LOAD_ADDR		CONFIG_SYS_SDRAM_BASE + 0x100000
++
++#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
++
++#ifdef CONFIG_BOOT_RAM
++#define CONFIG_SKIP_LOWLEVEL_INIT
++#endif
++
++/* UART */
++#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
++					  230400, 460800, 921600 }
++
++/* RAM */
++#define CONFIG_SYS_MEMTEST_START	0x80100000
++#define CONFIG_SYS_MEMTEST_END		0x80400000
++
++/* Memory usage */
++#define CONFIG_SYS_MAXARGS		64
++#define CONFIG_SYS_MALLOC_LEN		(16 * 1024 * 1024)
++#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
++#define CONFIG_SYS_CBSIZE		512
++
++/* U-Boot */
++#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
++
++/* Environment settings */
++
++/*
++ * Environment is right behind U-Boot in flash. Make sure U-Boot
++ * doesn't grow into the environment area.
++ */
++#define CONFIG_BOARD_SIZE_LIMIT		CONFIG_ENV_OFFSET
++
++#endif /* __CONFIG_RAVPOWER_RP_WD009_H */
+-- 
+2.27.0
+
diff --git a/package/boot/uboot-rockchip/Makefile b/package/boot/uboot-rockchip/Makefile
new file mode 100644
index 0000000..393e8c3
--- /dev/null
+++ b/package/boot/uboot-rockchip/Makefile
@@ -0,0 +1,95 @@
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2021.01
+PKG_RELEASE:=1
+
+PKG_HASH:=b407e1510a74e863b8b5cb42a24625344f0e0c2fc7582d8c866bd899367d0454
+
+PKG_MAINTAINER:=Tobias Maedel <openwrt@tbspace.de>
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=rockchip
+  UENV:=default
+  HIDDEN:=1
+endef
+
+
+# RK3328 boards
+
+define U-Boot/nanopi-r2s-rk3328
+  BUILD_SUBTARGET:=armv8
+  NAME:=NanoPi R2S
+  BUILD_DEVICES:= \
+    friendlyarm_nanopi-r2s
+  DEPENDS:=+PACKAGE_u-boot-nanopi-r2s-rk3328:arm-trusted-firmware-rockchip
+  PKG_BUILD_DEPENDS:=arm-trusted-firmware-rockchip
+  ATF:=rk3328_bl31.elf
+  OF_PLATDATA:=$(1)
+endef
+
+
+# RK3399 boards
+
+define U-Boot/rock-pi-4-rk3399
+  BUILD_SUBTARGET:=armv8
+  NAME:=Rock Pi 4
+  BUILD_DEVICES:= \
+    radxa_rock-pi-4
+  DEPENDS:=+PACKAGE_u-boot-rock-pi-4-rk3399:arm-trusted-firmware-rockchip
+  PKG_BUILD_DEPENDS:=arm-trusted-firmware-rockchip
+  ATF:=rk3399_bl31.elf
+endef
+
+define U-Boot/rockpro64-rk3399
+  BUILD_SUBTARGET:=armv8
+  NAME:=RockPro64
+  BUILD_DEVICES:= \
+    pine64_rockpro64
+  DEPENDS:=+PACKAGE_u-boot-rockpro64-rk3399:arm-trusted-firmware-rockchip
+  PKG_BUILD_DEPENDS:=arm-trusted-firmware-rockchip
+  ATF:=rk3399_bl31.elf
+endef
+
+UBOOT_TARGETS := \
+  rock-pi-4-rk3399 \
+  rockpro64-rk3399 \
+  nanopi-r2s-rk3328
+
+UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes
+
+UBOOT_MAKE_FLAGS += \
+  BL31=$(STAGING_DIR_IMAGE)/$(ATF)
+
+define Build/Configure
+	$(call Build/Configure/U-Boot)
+
+ifneq ($(OF_PLATDATA),)
+	mkdir -p $(PKG_BUILD_DIR)/tpl/dts
+	mkdir -p $(PKG_BUILD_DIR)/include/generated
+
+	$(CP) $(PKG_BUILD_DIR)/of-platdata/$(OF_PLATDATA)/dt-platdata.c $(PKG_BUILD_DIR)/tpl/dts/dt-platdata.c
+	$(CP) $(PKG_BUILD_DIR)/of-platdata/$(OF_PLATDATA)/dt-structs-gen.h $(PKG_BUILD_DIR)/include/generated/dt-structs-gen.h
+endif
+
+	$(SED) 's#CONFIG_MKIMAGE_DTC_PATH=.*#CONFIG_MKIMAGE_DTC_PATH="$(PKG_BUILD_DIR)/scripts/dtc/dtc"#g' $(PKG_BUILD_DIR)/.config
+	echo 'CONFIG_IDENT_STRING=" OpenWrt"' >> $(PKG_BUILD_DIR)/.config
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/idbloader.img $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-idbloader.img
+	$(CP) $(PKG_BUILD_DIR)/u-boot.itb $(STAGING_DIR_IMAGE)/$(BUILD_VARIANT)-u-boot.itb
+endef
+
+define Package/u-boot/install/default
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-rockchip/patches/001-scripts-remove-dependency-on-swig.patch b/package/boot/uboot-rockchip/patches/001-scripts-remove-dependency-on-swig.patch
new file mode 100644
index 0000000..0505589
--- /dev/null
+++ b/package/boot/uboot-rockchip/patches/001-scripts-remove-dependency-on-swig.patch
@@ -0,0 +1,24 @@
+From b137ca16b54c67d76714ea5a0138741959b0dc29 Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Mon, 13 Jul 2020 23:37:37 +0200
+Subject: [PATCH] scripts: remove dependency on swig
+
+Don't build the libfdt tool, as it has a dependency on swig (which
+OpenWrt does not ship).
+
+This requires more hacks, as of-platdata generation does not work
+without it.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ scripts/dtc/Makefile | 2 --
+ 1 file changed, 2 deletions(-)
+
+--- a/scripts/dtc/Makefile
++++ b/scripts/dtc/Makefile
+@@ -18,5 +18,3 @@ HOSTCFLAGS_dtc-parser.tab.o := -I$(src)
+ # dependencies on generated files need to be listed explicitly
+ $(obj)/dtc-lexer.lex.o: $(obj)/dtc-parser.tab.h
+ 
+-# Added for U-Boot
+-subdir-$(CONFIG_PYLIBFDT) += pylibfdt
diff --git a/package/boot/uboot-rockchip/patches/002-spl-remove-dtoc-of-pdata-generation.patch b/package/boot/uboot-rockchip/patches/002-spl-remove-dtoc-of-pdata-generation.patch
new file mode 100644
index 0000000..bd40110
--- /dev/null
+++ b/package/boot/uboot-rockchip/patches/002-spl-remove-dtoc-of-pdata-generation.patch
@@ -0,0 +1,32 @@
+From 55273cf6079ddd3b006da69f0113c2c66c03f17e Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Tue, 14 Jul 2020 22:44:22 +0200
+Subject: [PATCH] spl: remove dtoc of-pdata generation
+
+Remove the dtoc of-pdata generation. This generation is dependant on
+libpython-dev. As OpenWrt does not ship with this dependency, use
+pre-generated pdata files and remove the generation from the
+build-process.
+
+This only affects RK3328 boards.
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ scripts/Makefile.spl | 6 ------
+ 1 file changed, 6 deletions(-)
+
+--- a/scripts/Makefile.spl
++++ b/scripts/Makefile.spl
+@@ -321,12 +321,6 @@ PHONY += dts_dir
+ dts_dir:
+ 	$(shell [ -d $(obj)/dts ] || mkdir -p $(obj)/dts)
+ 
+-include/generated/dt-structs-gen.h: $(obj)/$(SPL_BIN).dtb dts_dir FORCE
+-	$(call if_changed,dtoch)
+-
+-$(obj)/dts/dt-platdata.c: $(obj)/$(SPL_BIN).dtb dts_dir FORCE
+-	$(call if_changed,dtocc)
+-
+ ifdef CONFIG_SAMSUNG
+ ifdef CONFIG_VAR_SIZE_SPL
+ VAR_SIZE_PARAM = --vs
diff --git a/package/boot/uboot-rockchip/patches/100-rockchip-rk3328-Add-support-for-FriendlyARM-NanoPi-R.patch b/package/boot/uboot-rockchip/patches/100-rockchip-rk3328-Add-support-for-FriendlyARM-NanoPi-R.patch
new file mode 100644
index 0000000..60416a6
--- /dev/null
+++ b/package/boot/uboot-rockchip/patches/100-rockchip-rk3328-Add-support-for-FriendlyARM-NanoPi-R.patch
@@ -0,0 +1,571 @@
+From 4189a8db90ca7edc16cf9509576ca2e74f028c1c Mon Sep 17 00:00:00 2001
+From: David Bauer <mail@david-bauer.net>
+Date: Thu, 7 Jan 2021 00:05:46 +0100
+Subject: [PATCH] rockchip: rk3328: Add support for FriendlyARM NanoPi R2S
+
+This adds support for the NanoPi R2S from FriendlyArm.
+
+Rockchip RK3328 SoC
+1GB DDR4 RAM
+Gigabit Ethernet (WAN)
+Gigabit Ethernet (USB3) (LAN)
+USB 2.0 Host Port
+MicroSD slot
+Reset button
+WAN - LAN - SYS LED
+
+Signed-off-by: David Bauer <mail@david-bauer.net>
+---
+ arch/arm/dts/Makefile                      |   1 +
+ arch/arm/dts/rk3328-nanopi-r2s-u-boot.dtsi |  40 +++
+ arch/arm/dts/rk3328-nanopi-r2s.dts         | 370 +++++++++++++++++++++
+ board/rockchip/evb_rk3328/MAINTAINERS      |   7 +
+ configs/nanopi-r2s-rk3328_defconfig        |  98 ++++++
+ 5 files changed, 516 insertions(+)
+ create mode 100644 arch/arm/dts/rk3328-nanopi-r2s-u-boot.dtsi
+ create mode 100644 arch/arm/dts/rk3328-nanopi-r2s.dts
+ create mode 100644 configs/nanopi-r2s-rk3328_defconfig
+
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -110,6 +110,7 @@ dtb-$(CONFIG_ROCKCHIP_RK3308) += \
+ 
+ dtb-$(CONFIG_ROCKCHIP_RK3328) += \
+ 	rk3328-evb.dtb \
++	rk3328-nanopi-r2s.dtb \
+ 	rk3328-roc-cc.dtb \
+ 	rk3328-rock64.dtb \
+ 	rk3328-rock-pi-e.dtb
+--- /dev/null
++++ b/arch/arm/dts/rk3328-nanopi-r2s-u-boot.dtsi
+@@ -0,0 +1,40 @@
++// SPDX-License-Identifier: GPL-2.0+
++/*
++ * (C) Copyright 2018-2019 Rockchip Electronics Co., Ltd
++ * (C) Copyright 2020 David Bauer
++ */
++
++#include "rk3328-u-boot.dtsi"
++#include "rk3328-sdram-ddr4-666.dtsi"
++/ {
++	chosen {
++		u-boot,spl-boot-order = "same-as-spl", &sdmmc, &emmc;
++	};
++};
++
++&gpio0 {
++	u-boot,dm-spl;
++};
++
++&pinctrl {
++	u-boot,dm-spl;
++};
++
++&sdmmc0m1_gpio {
++	u-boot,dm-spl;
++};
++
++&pcfg_pull_up_4ma {
++	u-boot,dm-spl;
++};
++
++/* Need this and all the pinctrl/gpio stuff above to set pinmux */
++&vcc_sd {
++	u-boot,dm-spl;
++};
++
++&gmac2io {
++	snps,reset-gpio = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
++	snps,reset-active-low;
++	snps,reset-delays-us = <0 10000 50000>;
++};
+--- /dev/null
++++ b/arch/arm/dts/rk3328-nanopi-r2s.dts
+@@ -0,0 +1,370 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (c) 2020 David Bauer <mail@david-bauer.net>
++ */
++
++/dts-v1/;
++
++#include <dt-bindings/input/input.h>
++#include <dt-bindings/gpio/gpio.h>
++#include "rk3328.dtsi"
++
++/ {
++	model = "FriendlyElec NanoPi R2S";
++	compatible = "friendlyarm,nanopi-r2s", "rockchip,rk3328";
++
++	chosen {
++		stdout-path = "serial2:1500000n8";
++	};
++
++	gmac_clk: gmac-clock {
++		compatible = "fixed-clock";
++		clock-frequency = <125000000>;
++		clock-output-names = "gmac_clkin";
++		#clock-cells = <0>;
++	};
++
++	keys {
++		compatible = "gpio-keys";
++		pinctrl-0 = <&reset_button_pin>;
++		pinctrl-names = "default";
++
++		reset {
++			label = "reset";
++			gpios = <&gpio0 RK_PA0 GPIO_ACTIVE_LOW>;
++			linux,code = <KEY_RESTART>;
++			debounce-interval = <50>;
++		};
++	};
++
++	leds {
++		compatible = "gpio-leds";
++		pinctrl-0 = <&lan_led_pin>,  <&sys_led_pin>, <&wan_led_pin>;
++		pinctrl-names = "default";
++
++		lan_led: led-0 {
++			gpios = <&gpio2 RK_PB7 GPIO_ACTIVE_HIGH>;
++			label = "nanopi-r2s:green:lan";
++		};
++
++		sys_led: led-1 {
++			gpios = <&gpio0 RK_PA2 GPIO_ACTIVE_HIGH>;
++			label = "nanopi-r2s:red:sys";
++		};
++
++		wan_led: led-2 {
++			gpios = <&gpio2 RK_PC2 GPIO_ACTIVE_HIGH>;
++			label = "nanopi-r2s:green:wan";
++		};
++	};
++
++	vcc_io_sdio: sdmmcio-regulator {
++		compatible = "regulator-gpio";
++		enable-active-high;
++		gpios = <&gpio1 RK_PD4 GPIO_ACTIVE_HIGH>;
++		pinctrl-0 = <&sdio_vcc_pin>;
++		pinctrl-names = "default";
++		regulator-name = "vcc_io_sdio";
++		regulator-always-on;
++		regulator-min-microvolt = <1800000>;
++		regulator-max-microvolt = <3300000>;
++		regulator-settling-time-us = <5000>;
++		regulator-type = "voltage";
++		startup-delay-us = <2000>;
++		states = <1800000 0x1
++			  3300000 0x0>;
++		vin-supply = <&vcc_io_33>;
++	};
++
++	vcc_sd: sdmmc-regulator {
++		compatible = "regulator-fixed";
++		gpio = <&gpio0 RK_PD6 GPIO_ACTIVE_LOW>;
++		pinctrl-0 = <&sdmmc0m1_gpio>;
++		pinctrl-names = "default";
++		regulator-name = "vcc_sd";
++		regulator-boot-on;
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		vin-supply = <&vcc_io_33>;
++	};
++
++	vdd_5v: vdd-5v {
++		compatible = "regulator-fixed";
++		regulator-name = "vdd_5v";
++		regulator-always-on;
++		regulator-boot-on;
++		regulator-min-microvolt = <5000000>;
++		regulator-max-microvolt = <5000000>;
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu1 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu2 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&cpu3 {
++	cpu-supply = <&vdd_arm>;
++};
++
++&gmac2io {
++	assigned-clocks = <&cru SCLK_MAC2IO>, <&cru SCLK_MAC2IO_EXT>;
++	assigned-clock-parents = <&gmac_clk>, <&gmac_clk>;
++	clock_in_out = "input";
++	phy-handle = <&rtl8211e>;
++	phy-mode = "rgmii";
++	phy-supply = <&vcc_io_33>;
++	pinctrl-0 = <&rgmiim1_pins>;
++	pinctrl-names = "default";
++	rx_delay = <0x18>;
++	snps,aal;
++	tx_delay = <0x24>;
++	status = "okay";
++
++	mdio {
++		compatible = "snps,dwmac-mdio";
++		#address-cells = <1>;
++		#size-cells = <0>;
++
++		rtl8211e: ethernet-phy@1 {
++			compatible = "ethernet-phy-id001c.c915",
++				     "ethernet-phy-ieee802.3-c22";
++			reg = <1>;
++			pinctrl-0 = <&eth_phy_reset_pin>;
++			pinctrl-names = "default";
++			reset-assert-us = <10000>;
++			reset-deassert-us = <50000>;
++			reset-gpios = <&gpio1 RK_PC2 GPIO_ACTIVE_LOW>;
++		};
++	};
++};
++
++&i2c1 {
++	status = "okay";
++
++	rk805: pmic@18 {
++		compatible = "rockchip,rk805";
++		reg = <0x18>;
++		interrupt-parent = <&gpio1>;
++		interrupts = <24 IRQ_TYPE_LEVEL_LOW>;
++		#clock-cells = <1>;
++		clock-output-names = "xin32k", "rk805-clkout2";
++		gpio-controller;
++		#gpio-cells = <2>;
++		pinctrl-0 = <&pmic_int_l>;
++		pinctrl-names = "default";
++		rockchip,system-power-controller;
++		wakeup-source;
++
++		vcc1-supply = <&vdd_5v>;
++		vcc2-supply = <&vdd_5v>;
++		vcc3-supply = <&vdd_5v>;
++		vcc4-supply = <&vdd_5v>;
++		vcc5-supply = <&vcc_io_33>;
++		vcc6-supply = <&vdd_5v>;
++
++		regulators {
++			vdd_log: DCDC_REG1 {
++				regulator-name = "vdd_log";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <712500>;
++				regulator-max-microvolt = <1450000>;
++				regulator-ramp-delay = <12500>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1000000>;
++				};
++			};
++
++			vdd_arm: DCDC_REG2 {
++				regulator-name = "vdd_arm";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <712500>;
++				regulator-max-microvolt = <1450000>;
++				regulator-ramp-delay = <12500>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <950000>;
++				};
++			};
++
++			vcc_ddr: DCDC_REG3 {
++				regulator-name = "vcc_ddr";
++				regulator-always-on;
++				regulator-boot-on;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++				};
++			};
++
++			vcc_io_33: DCDC_REG4 {
++				regulator-name = "vcc_io_33";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <3300000>;
++				};
++			};
++
++			vcc_18: LDO_REG1 {
++				regulator-name = "vcc_18";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <1800000>;
++				regulator-max-microvolt = <1800000>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1800000>;
++				};
++			};
++
++			vcc18_emmc: LDO_REG2 {
++				regulator-name = "vcc18_emmc";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <1800000>;
++				regulator-max-microvolt = <1800000>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1800000>;
++				};
++			};
++
++			vdd_10: LDO_REG3 {
++				regulator-name = "vdd_10";
++				regulator-always-on;
++				regulator-boot-on;
++				regulator-min-microvolt = <1000000>;
++				regulator-max-microvolt = <1000000>;
++
++				regulator-state-mem {
++					regulator-on-in-suspend;
++					regulator-suspend-microvolt = <1000000>;
++				};
++			};
++		};
++	};
++};
++
++&io_domains {
++	pmuio-supply = <&vcc_io_33>;
++	vccio1-supply = <&vcc_io_33>;
++	vccio2-supply = <&vcc18_emmc>;
++	vccio3-supply = <&vcc_io_sdio>;
++	vccio4-supply = <&vcc_18>;
++	vccio5-supply = <&vcc_io_33>;
++	vccio6-supply = <&vcc_io_33>;
++	status = "okay";
++};
++
++&pinctrl {
++	button {
++		reset_button_pin: reset-button-pin {
++			rockchip,pins = <0 RK_PA0 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++	};
++
++	ethernet-phy {
++		eth_phy_reset_pin: eth-phy-reset-pin {
++			rockchip,pins = <1 RK_PC2 RK_FUNC_GPIO &pcfg_pull_down>;
++		};
++	};
++
++	leds {
++		lan_led_pin: lan-led-pin {
++			rockchip,pins = <2 RK_PB7 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++
++		sys_led_pin: sys-led-pin {
++			rockchip,pins = <0 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++
++		wan_led_pin: wan-led-pin {
++			rockchip,pins = <2 RK_PC2 RK_FUNC_GPIO &pcfg_pull_none>;
++		};
++	};
++
++	pmic {
++		pmic_int_l: pmic-int-l {
++			rockchip,pins = <1 RK_PD0 RK_FUNC_GPIO &pcfg_pull_up>;
++		};
++	};
++
++	sd {
++		sdio_vcc_pin: sdio-vcc-pin {
++			rockchip,pins = <1 RK_PD4 RK_FUNC_GPIO &pcfg_pull_up>;
++		};
++	};
++};
++
++&pwm2 {
++	status = "okay";
++};
++
++&sdmmc {
++	bus-width = <4>;
++	cap-sd-highspeed;
++	disable-wp;
++	pinctrl-0 = <&sdmmc0_clk>, <&sdmmc0_cmd>, <&sdmmc0_dectn>, <&sdmmc0_bus4>;
++	pinctrl-names = "default";
++	sd-uhs-sdr12;
++	sd-uhs-sdr25;
++	sd-uhs-sdr50;
++	sd-uhs-sdr104;
++	vmmc-supply = <&vcc_sd>;
++	vqmmc-supply = <&vcc_io_sdio>;
++	status = "okay";
++};
++
++&tsadc {
++	rockchip,hw-tshut-mode = <0>;
++	rockchip,hw-tshut-polarity = <0>;
++	status = "okay";
++};
++
++&u2phy {
++	status = "okay";
++};
++
++&u2phy_host {
++	status = "okay";
++};
++
++&u2phy_otg {
++	status = "okay";
++};
++
++&uart2 {
++	status = "okay";
++};
++
++&usb20_otg {
++	status = "okay";
++	dr_mode = "host";
++};
++
++&usb_host0_ehci {
++	status = "okay";
++};
++
++&usb_host0_ohci {
++	status = "okay";
++};
+--- a/board/rockchip/evb_rk3328/MAINTAINERS
++++ b/board/rockchip/evb_rk3328/MAINTAINERS
+@@ -5,6 +5,13 @@ F:      board/rockchip/evb_rk3328
+ F:      include/configs/evb_rk3328.h
+ F:      configs/evb-rk3328_defconfig
+ 
++NANOPI-R2S-RK3328
++M:      David Bauer <mail@david-bauer.net>
++S:      Maintained
++F:      configs/nanopi-r2s-rk3328_defconfig
++F:      arch/arm/dts/rk3328-nanopi-r2s-u-boot.dtsi
++F:      arch/arm/dts/rk3328-nanopi-r2s.dts
++
+ ROC-RK3328-CC
+ M:      Loic Devulder <ldevulder@suse.com>
+ M:      Chen-Yu Tsai <wens@csie.org>
+--- /dev/null
++++ b/configs/nanopi-r2s-rk3328_defconfig
+@@ -0,0 +1,98 @@
++CONFIG_ARM=y
++CONFIG_ARCH_ROCKCHIP=y
++CONFIG_SYS_TEXT_BASE=0x00200000
++CONFIG_SPL_GPIO_SUPPORT=y
++CONFIG_ENV_OFFSET=0x3F8000
++CONFIG_ROCKCHIP_RK3328=y
++CONFIG_TPL_ROCKCHIP_COMMON_BOARD=y
++CONFIG_TPL_LIBCOMMON_SUPPORT=y
++CONFIG_TPL_LIBGENERIC_SUPPORT=y
++CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
++CONFIG_SPL_STACK_R_ADDR=0x600000
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_DEBUG_UART_BASE=0xFF130000
++CONFIG_DEBUG_UART_CLOCK=24000000
++CONFIG_SYSINFO=y
++CONFIG_DEBUG_UART=y
++CONFIG_TPL_SYS_MALLOC_F_LEN=0x800
++# CONFIG_ANDROID_BOOT_IMAGE is not set
++CONFIG_FIT=y
++CONFIG_FIT_VERBOSE=y
++CONFIG_SPL_LOAD_FIT=y
++CONFIG_DEFAULT_FDT_FILE="rockchip/rk3328-nanopi-r2s.dtb"
++CONFIG_MISC_INIT_R=y
++# CONFIG_DISPLAY_CPUINFO is not set
++CONFIG_DISPLAY_BOARDINFO_LATE=y
++# CONFIG_SPL_RAW_IMAGE_SUPPORT is not set
++CONFIG_TPL_SYS_MALLOC_SIMPLE=y
++CONFIG_SPL_STACK_R=y
++CONFIG_SPL_I2C_SUPPORT=y
++CONFIG_SPL_POWER_SUPPORT=y
++CONFIG_SPL_ATF=y
++CONFIG_SPL_ATF_NO_PLATFORM_PARAM=y
++CONFIG_CMD_BOOTZ=y
++CONFIG_CMD_GPT=y
++CONFIG_CMD_MMC=y
++CONFIG_CMD_USB=y
++# CONFIG_CMD_SETEXPR is not set
++CONFIG_CMD_TIME=y
++CONFIG_SPL_OF_CONTROL=y
++CONFIG_TPL_OF_CONTROL=y
++CONFIG_DEFAULT_DEVICE_TREE="rk3328-nanopi-r2s"
++CONFIG_OF_SPL_REMOVE_PROPS="clock-names interrupt-parent assigned-clocks assigned-clock-rates assigned-clock-parents"
++CONFIG_TPL_OF_PLATDATA=y
++CONFIG_ENV_IS_IN_MMC=y
++CONFIG_SYS_RELOC_GD_ENV_ADDR=y
++CONFIG_NET_RANDOM_ETHADDR=y
++CONFIG_TPL_DM=y
++CONFIG_REGMAP=y
++CONFIG_SPL_REGMAP=y
++CONFIG_TPL_REGMAP=y
++CONFIG_SYSCON=y
++CONFIG_SPL_SYSCON=y
++CONFIG_TPL_SYSCON=y
++CONFIG_CLK=y
++CONFIG_SPL_CLK=y
++CONFIG_FASTBOOT_BUF_ADDR=0x800800
++CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
++CONFIG_ROCKCHIP_GPIO=y
++CONFIG_SYS_I2C_ROCKCHIP=y
++CONFIG_MMC_DW=y
++CONFIG_MMC_DW_ROCKCHIP=y
++CONFIG_SF_DEFAULT_SPEED=20000000
++CONFIG_DM_ETH=y
++CONFIG_ETH_DESIGNWARE=y
++CONFIG_GMAC_ROCKCHIP=y
++CONFIG_PINCTRL=y
++CONFIG_SPL_PINCTRL=y
++CONFIG_DM_PMIC=y
++CONFIG_PMIC_RK8XX=y
++CONFIG_SPL_DM_REGULATOR=y
++CONFIG_REGULATOR_PWM=y
++CONFIG_DM_REGULATOR_FIXED=y
++CONFIG_SPL_DM_REGULATOR_FIXED=y
++CONFIG_REGULATOR_RK8XX=y
++CONFIG_PWM_ROCKCHIP=y
++CONFIG_RAM=y
++CONFIG_SPL_RAM=y
++CONFIG_TPL_RAM=y
++CONFIG_DM_RESET=y
++CONFIG_BAUDRATE=1500000
++CONFIG_DEBUG_UART_SHIFT=2
++CONFIG_SYSRESET=y
++# CONFIG_TPL_SYSRESET is not set
++CONFIG_USB=y
++CONFIG_USB_XHCI_HCD=y
++CONFIG_USB_XHCI_DWC3=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_GENERIC=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_USB_OHCI_GENERIC=y
++CONFIG_USB_DWC2=y
++CONFIG_USB_DWC3=y
++# CONFIG_USB_DWC3_GADGET is not set
++CONFIG_USB_GADGET=y
++CONFIG_USB_GADGET_DWC2_OTG=y
++CONFIG_SPL_TINY_MEMSET=y
++CONFIG_TPL_TINY_MEMSET=y
++CONFIG_ERRNO_STR=y
diff --git a/package/boot/uboot-rockchip/patches/101-rock64pro-disable-CONFIG_USE_PREBOOT.patch b/package/boot/uboot-rockchip/patches/101-rock64pro-disable-CONFIG_USE_PREBOOT.patch
new file mode 100644
index 0000000..f630818
--- /dev/null
+++ b/package/boot/uboot-rockchip/patches/101-rock64pro-disable-CONFIG_USE_PREBOOT.patch
@@ -0,0 +1,27 @@
+From 2114d68b3c755ec8043ae9e43ac8e9753e0cec84 Mon Sep 17 00:00:00 2001
+From: Marty Jones <mj8263788@gmail.com>
+Date: Sun, 17 Jan 2021 15:26:09 -0500
+Subject: [PATCH] rockpro64: disable CONFIG_USE_PREBOOT
+
+On commit https://github.com/u-boot/u-boot/commit/f81f9f0ebac596bae7f27db095f4f0272b606cc3
+CONFIG_USE_PREBOOT was enabled on the RockPro64.
+
+When the board is booting, U-Boot hangs as soon as it disables the USB
+controller. This is a workaround until a final solution is deployed
+upstream.
+
+Signed-off-by: Marty Jones <mj8263788@gmail.com>
+---
+ configs/rockpro64-rk3399_defconfig | 1 -
+ 1 file changed, 1 deletion(-)
+
+--- a/configs/rockpro64-rk3399_defconfig
++++ b/configs/rockpro64-rk3399_defconfig
+@@ -12,7 +12,6 @@ CONFIG_SPL_SPI_FLASH_SUPPORT=y
+ CONFIG_SPL_SPI_SUPPORT=y
+ CONFIG_DEFAULT_DEVICE_TREE="rk3399-rockpro64"
+ CONFIG_DEBUG_UART=y
+-CONFIG_USE_PREBOOT=y
+ CONFIG_DEFAULT_FDT_FILE="rockchip/rk3399-rockpro64.dtb"
+ CONFIG_DISPLAY_BOARDINFO_LATE=y
+ CONFIG_MISC_INIT_R=y
diff --git a/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-platdata.c b/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-platdata.c
new file mode 100644
index 0000000..17e1e30
--- /dev/null
+++ b/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-platdata.c
@@ -0,0 +1,174 @@
+/*
+ * DO NOT MODIFY
+ *
+ * This file was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+/* Allow use of U_BOOT_DEVICE() in this file */
+#define DT_PLATDATA_C
+
+#include <common.h>
+#include <dm.h>
+#include <dt-structs.h>
+
+/* Node /clock-controller@ff440000 index 0 */
+static struct dtd_rockchip_rk3328_cru dtv_clock_controller_at_ff440000 = {
+	.reg			= {0xff440000, 0x1000},
+	.rockchip_grf		= 0x3a,
+};
+U_BOOT_DEVICE(clock_controller_at_ff440000) = {
+	.name		= "rockchip_rk3328_cru",
+	.platdata	= &dtv_clock_controller_at_ff440000,
+	.platdata_size	= sizeof(dtv_clock_controller_at_ff440000),
+	.parent_idx	= -1,
+};
+
+/* Node /dmc index 1 */
+static struct dtd_rockchip_rk3328_dmc dtv_dmc = {
+	.reg			= {0xff400000, 0x1000, 0xff780000, 0x3000, 0xff100000, 0x1000, 0xff440000, 0x1000,
+		0xff720000, 0x1000, 0xff798000, 0x1000},
+	.rockchip_sdram_params	= {0x1, 0xa, 0x2, 0x1, 0x0, 0x0, 0x11, 0x0,
+		0x11, 0x0, 0x0, 0x94291288, 0x0, 0x27, 0x462, 0x15,
+		0x242, 0xff, 0x14d, 0x0, 0x1, 0x0, 0x0, 0x0,
+		0x43049010, 0x64, 0x28003b, 0xd0, 0x20053, 0xd4, 0x220000, 0xd8,
+		0x100, 0xdc, 0x40000, 0xe0, 0x0, 0xe4, 0x110000, 0xe8,
+		0x420, 0xec, 0x400, 0xf4, 0xf011f, 0x100, 0x9060b06, 0x104,
+		0x20209, 0x108, 0x505040a, 0x10c, 0x40400c, 0x110, 0x5030206, 0x114,
+		0x3030202, 0x120, 0x3030b03, 0x124, 0x20208, 0x180, 0x1000040, 0x184,
+		0x0, 0x190, 0x7030003, 0x198, 0x5001100, 0x1a0, 0xc0400003, 0x240,
+		0x6000604, 0x244, 0x201, 0x250, 0xf00, 0x490, 0x1, 0xffffffff,
+		0xffffffff, 0xffffffff, 0xffffffff, 0x4, 0xc, 0x28, 0xa, 0x2c,
+		0x0, 0x30, 0x9, 0xffffffff, 0xffffffff, 0x77, 0x88, 0x79,
+		0x79, 0x87, 0x97, 0x87, 0x78, 0x77, 0x78, 0x87,
+		0x88, 0x87, 0x87, 0x77, 0x78, 0x78, 0x78, 0x78,
+		0x78, 0x78, 0x78, 0x78, 0x78, 0x69, 0x9, 0x77,
+		0x78, 0x77, 0x78, 0x77, 0x78, 0x77, 0x78, 0x77,
+		0x79, 0x9, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+		0x78, 0x78, 0x78, 0x69, 0x9, 0x77, 0x78, 0x77,
+		0x77, 0x77, 0x77, 0x77, 0x77, 0x77, 0x79, 0x9,
+		0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
+		0x78, 0x69, 0x9, 0x77, 0x78, 0x77, 0x78, 0x77,
+		0x78, 0x77, 0x78, 0x77, 0x79, 0x9, 0x78, 0x78,
+		0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x69,
+		0x9, 0x77, 0x78, 0x77, 0x77, 0x77, 0x77, 0x77,
+		0x77, 0x77, 0x79, 0x9},
+};
+U_BOOT_DEVICE(dmc) = {
+	.name		= "rockchip_rk3328_dmc",
+	.platdata	= &dtv_dmc,
+	.platdata_size	= sizeof(dtv_dmc),
+	.parent_idx	= -1,
+};
+
+/* Node /pinctrl/gpio0@ff210000 index 2 */
+static struct dtd_rockchip_gpio_bank dtv_gpio0_at_ff210000 = {
+	.clocks			= {
+			{0, {200}},},
+	.gpio_controller	= true,
+	.interrupt_controller	= true,
+	.interrupts		= {0x0, 0x33, 0x4},
+	.reg			= {0xff210000, 0x100},
+};
+U_BOOT_DEVICE(gpio0_at_ff210000) = {
+	.name		= "rockchip_gpio_bank",
+	.platdata	= &dtv_gpio0_at_ff210000,
+	.platdata_size	= sizeof(dtv_gpio0_at_ff210000),
+	.parent_idx	= 4,
+};
+
+/* Node /mmc@ff500000 index 3 */
+static struct dtd_rockchip_rk3288_dw_mshc dtv_mmc_at_ff500000 = {
+	.bus_width		= 0x4,
+	.cap_sd_highspeed	= true,
+	.clocks			= {
+			{0, {317}},
+			{0, {33}},
+			{0, {74}},
+			{0, {78}},},
+	.disable_wp		= true,
+	.fifo_depth		= 0x100,
+	.interrupts		= {0x0, 0xc, 0x4},
+	.max_frequency		= 0x8f0d180,
+	.pinctrl_0		= {0x47, 0x48, 0x49, 0x4a},
+	.pinctrl_names		= "default",
+	.reg			= {0xff500000, 0x4000},
+	.sd_uhs_sdr104		= true,
+	.sd_uhs_sdr12		= true,
+	.sd_uhs_sdr25		= true,
+	.sd_uhs_sdr50		= true,
+	.u_boot_spl_fifo_mode	= true,
+	.vmmc_supply		= 0x4b,
+	.vqmmc_supply		= 0x1e,
+};
+U_BOOT_DEVICE(mmc_at_ff500000) = {
+	.name		= "rockchip_rk3288_dw_mshc",
+	.platdata	= &dtv_mmc_at_ff500000,
+	.platdata_size	= sizeof(dtv_mmc_at_ff500000),
+	.parent_idx	= -1,
+};
+
+/* Node /pinctrl index 4 */
+static struct dtd_rockchip_rk3328_pinctrl dtv_pinctrl = {
+	.ranges			= true,
+	.rockchip_grf		= 0x3a,
+};
+U_BOOT_DEVICE(pinctrl) = {
+	.name		= "rockchip_rk3328_pinctrl",
+	.platdata	= &dtv_pinctrl,
+	.platdata_size	= sizeof(dtv_pinctrl),
+	.parent_idx	= -1,
+};
+
+/* Node /sdmmc-regulator index 5 */
+static struct dtd_regulator_fixed dtv_sdmmc_regulator = {
+	.gpio			= {0x61, 0x1e, 0x1},
+	.pinctrl_0		= 0x67,
+	.pinctrl_names		= "default",
+	.regulator_boot_on	= true,
+	.regulator_max_microvolt = 0x325aa0,
+	.regulator_min_microvolt = 0x325aa0,
+	.regulator_name		= "vcc_sd",
+	.vin_supply		= 0x1c,
+};
+U_BOOT_DEVICE(sdmmc_regulator) = {
+	.name		= "regulator_fixed",
+	.platdata	= &dtv_sdmmc_regulator,
+	.platdata_size	= sizeof(dtv_sdmmc_regulator),
+	.parent_idx	= -1,
+};
+
+/* Node /serial@ff130000 index 6 */
+static struct dtd_ns16550_serial dtv_serial_at_ff130000 = {
+	.clock_frequency	= 0x16e3600,
+	.clocks			= {
+			{0, {40}},
+			{0, {212}},},
+	.dma_names		= {"tx", "rx"},
+	.dmas			= {0x10, 0x6, 0x10, 0x7},
+	.interrupts		= {0x0, 0x39, 0x4},
+	.pinctrl_0		= 0x26,
+	.pinctrl_names		= "default",
+	.reg			= {0xff130000, 0x100},
+	.reg_io_width		= 0x4,
+	.reg_shift		= 0x2,
+};
+U_BOOT_DEVICE(serial_at_ff130000) = {
+	.name		= "ns16550_serial",
+	.platdata	= &dtv_serial_at_ff130000,
+	.platdata_size	= sizeof(dtv_serial_at_ff130000),
+	.parent_idx	= -1,
+};
+
+/* Node /syscon@ff100000 index 7 */
+static struct dtd_rockchip_rk3328_grf dtv_syscon_at_ff100000 = {
+	.reg			= {0xff100000, 0x1000},
+};
+U_BOOT_DEVICE(syscon_at_ff100000) = {
+	.name		= "rockchip_rk3328_grf",
+	.platdata	= &dtv_syscon_at_ff100000,
+	.platdata_size	= sizeof(dtv_syscon_at_ff100000),
+	.parent_idx	= -1,
+};
+
+void dm_populate_phandle_data(void) {
+}
diff --git a/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-structs-gen.h b/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-structs-gen.h
new file mode 100644
index 0000000..847b121
--- /dev/null
+++ b/package/boot/uboot-rockchip/src/of-platdata/nanopi-r2s-rk3328/dt-structs-gen.h
@@ -0,0 +1,71 @@
+/*
+ * DO NOT MODIFY
+ *
+ * This file was generated by dtoc from a .dtb (device tree binary) file.
+ */
+
+#include <stdbool.h>
+#include <linux/libfdt.h>
+struct dtd_ns16550_serial {
+	fdt32_t		clock_frequency;
+	struct phandle_1_arg clocks[2];
+	const char *	dma_names[2];
+	fdt32_t		dmas[4];
+	fdt32_t		interrupts[3];
+	fdt32_t		pinctrl_0;
+	const char *	pinctrl_names;
+	fdt64_t		reg[2];
+	fdt32_t		reg_io_width;
+	fdt32_t		reg_shift;
+};
+struct dtd_regulator_fixed {
+	fdt32_t		gpio[3];
+	fdt32_t		pinctrl_0;
+	const char *	pinctrl_names;
+	bool		regulator_boot_on;
+	fdt32_t		regulator_max_microvolt;
+	fdt32_t		regulator_min_microvolt;
+	const char *	regulator_name;
+	fdt32_t		vin_supply;
+};
+struct dtd_rockchip_gpio_bank {
+	struct phandle_1_arg clocks[1];
+	bool		gpio_controller;
+	bool		interrupt_controller;
+	fdt32_t		interrupts[3];
+	fdt64_t		reg[2];
+};
+struct dtd_rockchip_rk3288_dw_mshc {
+	fdt32_t		bus_width;
+	bool		cap_sd_highspeed;
+	struct phandle_1_arg clocks[4];
+	bool		disable_wp;
+	fdt32_t		fifo_depth;
+	fdt32_t		interrupts[3];
+	fdt32_t		max_frequency;
+	fdt32_t		pinctrl_0[4];
+	const char *	pinctrl_names;
+	fdt64_t		reg[2];
+	bool		sd_uhs_sdr104;
+	bool		sd_uhs_sdr12;
+	bool		sd_uhs_sdr25;
+	bool		sd_uhs_sdr50;
+	bool		u_boot_spl_fifo_mode;
+	fdt32_t		vmmc_supply;
+	fdt32_t		vqmmc_supply;
+};
+struct dtd_rockchip_rk3328_cru {
+	fdt64_t		reg[2];
+	fdt32_t		rockchip_grf;
+};
+struct dtd_rockchip_rk3328_dmc {
+	fdt64_t		reg[12];
+	fdt32_t		rockchip_sdram_params[196];
+};
+struct dtd_rockchip_rk3328_grf {
+	fdt64_t		reg[2];
+};
+struct dtd_rockchip_rk3328_pinctrl {
+	bool		ranges;
+	fdt32_t		rockchip_grf;
+};
diff --git a/package/boot/uboot-sunxi/Makefile b/package/boot/uboot-sunxi/Makefile
new file mode 100644
index 0000000..3814733
--- /dev/null
+++ b/package/boot/uboot-sunxi/Makefile
@@ -0,0 +1,364 @@
+#
+# Copyright (C) 2013-2016 OpenWrt.org
+# Copyright (C) 2017 Yousong Zhou
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+
+include $(TOPDIR)/rules.mk
+include $(INCLUDE_DIR)/kernel.mk
+
+PKG_VERSION:=2020.04
+
+PKG_HASH:=fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+PKG_MAINTAINER:=Zoltan HERPAI <wigyori@uid0.hu>
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=sunxi
+  UBOOT_IMAGE:=u-boot-sunxi-with-spl.bin
+  UENV:=default
+  HIDDEN:=1
+endef
+
+define U-Boot/a64-olinuxino
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Olimex A64-OLinuXino
+  BUILD_DEVICES:=olimex_a64-olinuxino
+  DEPENDS:=+PACKAGE_u-boot-olimex_a64-olinuxino:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/a64-olinuxino-emmc
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Olimex A64-OLinuXino eMMC
+  BUILD_DEVICES:=olimex_a64-olinuxino-emmc
+  DEPENDS:=+PACKAGE_u-boot-olimex_a64-olinuxino-emmc:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/A10-OLinuXino-Lime
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=A10 OLinuXino LIME
+  BUILD_DEVICES:=olimex_a10-olinuxino-lime
+endef
+
+define U-Boot/A13-OLinuXino
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=A13 OlinuXino
+  BUILD_DEVICES:=olimex_a13-olinuxino
+endef
+
+define U-Boot/A20-OLinuXino-Lime
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=A20 OLinuXino LIME
+  BUILD_DEVICES:=olimex_a20-olinuxino-lime
+endef
+
+define U-Boot/A20-OLinuXino-Lime2
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=A20 OLinuXino LIME2
+  BUILD_DEVICES:=olimex_a20-olinuxino-lime2
+endef
+
+define U-Boot/A20-OLinuXino-Lime2-eMMC
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=A20 OLinuXino LIME2 eMMC
+  BUILD_DEVICES:=olimex_a20-olinuxino-lime2-emmc
+endef
+
+define U-Boot/A20-OLinuXino_MICRO
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=A20 OLinuXino MICRO
+  BUILD_DEVICES:=olimex_a20-olinuxino-micro
+endef
+
+define U-Boot/Bananapi
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Bananapi
+  BUILD_DEVICES:=lemaker_bananapi
+endef
+
+define U-Boot/Bananapro
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Bananapro
+  BUILD_DEVICES:=lemaker_bananapro
+endef
+
+define U-Boot/Cubieboard
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=Cubieboard
+  BUILD_DEVICES:=cubietech_a10-cubieboard
+endef
+
+define U-Boot/Cubieboard2
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Cubieboard2
+  BUILD_DEVICES:=cubietech_cubieboard2
+endef
+
+define U-Boot/Cubietruck
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Cubietruck
+  BUILD_DEVICES:=cubietech_cubietruck
+endef
+
+define U-Boot/Hummingbird_A31
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Hummingbird A31 board
+endef
+
+define U-Boot/Marsboard_A10
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=Marsboard
+  BUILD_DEVICES:=marsboard_a10-marsboard
+endef
+
+define U-Boot/Mele_M9
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Mele M9 (A31)
+  BUILD_DEVICES:=mele_m9
+endef
+
+define U-Boot/OLIMEX_A13_SOM
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=Olimex A13 SOM
+  BUILD_DEVICES:=olimex_a13-olimex-som
+endef
+
+define U-Boot/Linksprite_pcDuino
+  BUILD_SUBTARGET:=cortexa8
+  NAME:=Linksprite pcDuino
+  BUILD_DEVICES:=linksprite_a10-pcduino
+endef
+
+define U-Boot/Linksprite_pcDuino3
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Linksprite pcDuino3
+  BUILD_DEVICES:=linksprite_pcduino3
+endef
+
+define U-Boot/Linksprite_pcDuino3_Nano
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Linksprite pcDuino3 Nano
+  BUILD_DEVICES:=linksprite_pcduino3-nano
+endef
+
+define U-Boot/Lamobo_R1
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Lamobo R1
+  BUILD_DEVICES:=lamobo_lamobo-r1
+endef
+
+define U-Boot/nanopi_m1_plus
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=NanoPi M1 Plus (H3)
+  BUILD_DEVICES:=friendlyarm_nanopi-m1-plus
+endef
+
+define U-Boot/zeropi
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=ZeroPi (H3)
+  BUILD_DEVICES:=friendlyarm_zeropi
+endef
+
+define U-Boot/nanopi_neo_air
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=U-Boot for NanoPi NEO Air (H3)
+  BUILD_DEVICES:=friendlyarm_nanopi-neo-air
+endef
+
+define U-Boot/nanopi_neo
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=U-Boot for NanoPi NEO (H3)
+  BUILD_DEVICES:=friendlyarm_nanopi-neo
+endef
+
+define U-Boot/nanopi_r1
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=U-Boot for NanoPi R1 (H3)
+  BUILD_DEVICES:=friendlyarm_nanopi-r1
+endef
+
+define U-Boot/orangepi_r1
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi R1 (H2+)
+  BUILD_DEVICES:=xunlong_orangepi-r1
+endef
+
+define U-Boot/orangepi_zero
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi Zero (H2+)
+  BUILD_DEVICES:=xunlong_orangepi-zero
+endef
+
+define U-Boot/orangepi_one
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi One (H3)
+  BUILD_DEVICES:=xunlong_orangepi-one
+endef
+
+define U-Boot/orangepi_pc
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi PC (H3)
+  BUILD_DEVICES:=xunlong_orangepi-pc
+endef
+
+define U-Boot/orangepi_pc_plus
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi PC Plus (H3)
+  BUILD_DEVICES:=xunlong_orangepi-pc-plus
+endef
+
+define U-Boot/orangepi_plus
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi Plus (H3)
+  BUILD_DEVICES:=xunlong_orangepi-plus
+endef
+
+define U-Boot/orangepi_2
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Orange Pi 2 (H3)
+  BUILD_DEVICES:=xunlong_orangepi-2
+endef
+
+define U-Boot/pangolin
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Theobroma A31-yQ7 devboard
+  UENV:=pangolin
+endef
+
+define U-Boot/libretech_all_h3_cc_h5
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Libre Computer ALL-H3-CC H5
+  BUILD_DEVICES:=libretech_all-h3-cc-h5
+  DEPENDS:=+PACKAGE_u-boot-libretech_all_h3_cc_h5:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/nanopi_neo_plus2
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=NanoPi NEO Plus2 (H5)
+  BUILD_DEVICES:=friendlyarm_nanopi-neo-plus2
+  DEPENDS:=+PACKAGE_u-boot-nanopi_neo_plus2:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/nanopi_neo2
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=NanoPi NEO2 (H5)
+  BUILD_DEVICES:=friendlyarm_nanopi-neo2
+  DEPENDS:=+PACKAGE_u-boot-nanopi_neo2:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/pine64_plus
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Pine64 Plus A64
+  BUILD_DEVICES:=pine64_pine64-plus
+  DEPENDS:=+PACKAGE_u-boot-pine64_plus:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/bananapi_m2_plus_h3
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Bananapi M2 Plus H3
+  BUILD_DEVICES:=sinovoip_bananapi-m2-plus
+endef
+
+define U-Boot/sopine_baseboard
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Sopine Baseboard
+  BUILD_DEVICES:=pine64_sopine-baseboard
+  DEPENDS:=+PACKAGE_u-boot-sopine_baseboard:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+
+define U-Boot/orangepi_zero_plus
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Xunlong Orange Pi Zero Plus
+  BUILD_DEVICES:=xunlong_orangepi-zero-plus
+  DEPENDS:=+PACKAGE_u-boot-orangepi_zero_plus:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/orangepi_pc2
+  BUILD_SUBTARGET:=cortexa53
+  NAME:=Xunlong Orange Pi PC2
+  BUILD_DEVICES:=xunlong_orangepi-pc2
+  DEPENDS:=+PACKAGE_u-boot-orangepi_pc2:arm-trusted-firmware-sunxi
+  UENV:=a64
+endef
+
+define U-Boot/Bananapi_M2_Ultra
+  BUILD_SUBTARGET:=cortexa7
+  NAME:=Bananapi M2 Ultra
+  BUILD_DEVICES:=sinovoip_bananapi-m2-ultra
+endef
+
+UBOOT_TARGETS := \
+	a64-olinuxino \
+	a64-olinuxino-emmc \
+	A10-OLinuXino-Lime \
+	A13-OLinuXino \
+	A20-OLinuXino-Lime \
+	A20-OLinuXino-Lime2 \
+	A20-OLinuXino-Lime2-eMMC \
+	A20-OLinuXino_MICRO \
+	bananapi_m2_plus_h3 \
+	Bananapi \
+	Bananapi_M2_Ultra \
+	Bananapro \
+	Cubieboard \
+	Cubieboard2 \
+	Cubietruck \
+	Hummingbird_A31 \
+	Marsboard_A10 \
+	Mele_M9 \
+	OLIMEX_A13_SOM \
+	Linksprite_pcDuino \
+	Linksprite_pcDuino3 \
+	Linksprite_pcDuino3_Nano \
+	Lamobo_R1 \
+	nanopi_m1_plus \
+	zeropi \
+	nanopi_neo \
+	nanopi_neo_air \
+	nanopi_neo_plus2 \
+	nanopi_neo2 \
+	nanopi_r1 \
+	orangepi_zero \
+	orangepi_r1 \
+	orangepi_one \
+	orangepi_pc \
+	orangepi_pc_plus \
+	orangepi_plus \
+	orangepi_2 \
+	orangepi_pc2 \
+	pangolin \
+	pine64_plus \
+	sopine_baseboard \
+	orangepi_zero_plus \
+	libretech_all_h3_cc_h5
+
+UBOOT_CONFIGURE_VARS += USE_PRIVATE_LIBGCC=yes
+
+UBOOT_MAKE_FLAGS += \
+	BL31=$(STAGING_DIR_IMAGE)/bl31.bin
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/$(UBOOT_IMAGE) $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-u-boot-with-spl.bin
+	mkimage -C none -A arm -T script -d uEnv-$(UENV).txt \
+		$(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-boot.scr
+endef
+
+define Package/u-boot/install/default
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch b/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch
new file mode 100644
index 0000000..c19f378
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/002-add-olimex-a13-som.patch
@@ -0,0 +1,20 @@
+--- /dev/null
++++ b/configs/OLIMEX_A13_SOM_defconfig
+@@ -0,0 +1,17 @@
++CONFIG_SPL=y
++CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_MACH_SUN5I=y
++CONFIG_DRAM_CLK=408
++CONFIG_DRAM_ZQ=123
++CONFIG_DRAM_EMR1=0
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++# CONFIG_CMD_FPGA is not set
++CONFIG_DM_SERIAL=y
++CONFIG_USB=y
++CONFIG_DM_USB=y
++CONFIG_SYS_NS16550=y
++CONFIG_SUNXI_NO_PMIC=y
++CONFIG_USB_EHCI_HCD=y
diff --git a/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch b/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch
new file mode 100644
index 0000000..29969a7
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/003-add-theobroma-a31-pangolin.patch
@@ -0,0 +1,375 @@
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -455,6 +455,7 @@ dtb-$(CONFIG_MACH_SUN6I) += \
+ 	sun6i-a31-m9.dtb \
+ 	sun6i-a31-mele-a1000g-quad.dtb \
+ 	sun6i-a31-mixtile-loftq.dtb \
++	sun6i-a31-pangolin.dtb \
+ 	sun6i-a31s-colorfly-e708-q1.dtb \
+ 	sun6i-a31s-cs908.dtb \
+ 	sun6i-a31s-inet-q972.dtb \
+--- a/arch/arm/dts/sun6i-a31.dtsi
++++ b/arch/arm/dts/sun6i-a31.dtsi
+@@ -641,6 +641,11 @@
+ 				function = "lcd0";
+ 			};
+ 
++			i2c3_pins_a: i2c3@0 {
++				allwinner,pins = "PB5", "PB6";
++				allwinner,function = "i2c3";
++			};
++
+ 			mmc0_pins_a: mmc0@0 {
+ 				pins = "PF0", "PF1", "PF2",
+ 						 "PF3", "PF4", "PF5";
+--- /dev/null
++++ b/arch/arm/dts/sun6i-a31-pangolin.dts
+@@ -0,0 +1,292 @@
++/*
++ * Copyright 2015, Theobroma Systems Design und Consulting GmbH
++ *
++ * This file is dual-licensed: you can use it either under the terms
++ * of the GPL or the X11 license, at your option. Note that this dual
++ * licensing only applies to this file, and not this project as a
++ * whole.
++ *
++ *  a) This file is free software; you can redistribute it and/or
++ *     modify it under the terms of the GNU General Public License as
++ *     published by the Free Software Foundation; either version 2 of the
++ *     License, or (at your option) any later version.
++ *
++ *     This file 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.
++ *
++ * Or, alternatively,
++ *
++ *  b) Permission is hereby granted, free of charge, to any person
++ *     obtaining a copy of this software and associated documentation
++ *     files (the "Software"), to deal in the Software without
++ *     restriction, including without limitation the rights to use,
++ *     copy, modify, merge, publish, distribute, sublicense, and/or
++ *     sell copies of the Software, and to permit persons to whom the
++ *     Software is furnished to do so, subject to the following
++ *     conditions:
++ *
++ *     The above copyright notice and this permission notice shall be
++ *     included in all copies or substantial portions of the Software.
++ *
++ *     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++ *     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
++ *     OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++ *     NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
++ *     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
++ *     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ *     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
++ *     OTHER DEALINGS IN THE SOFTWARE.
++ */
++
++/dts-v1/;
++#include "sun6i-a31.dtsi"
++#include "sunxi-common-regulators.dtsi"
++
++#include <dt-bindings/gpio/gpio.h>
++#include <dt-bindings/pinctrl/sun4i-a10.h>
++
++/ {
++	model = "Theobroma Systems A31 Pangolin";
++	compatible = "tsd,a31-pangolin", "allwinner,sun6i-a31";
++
++	aliases {
++		serial0 = &uart0;
++		serial2 = &uart2;
++		spi0 = &spi0;
++		spi1 = &spi1;
++		spi2 = &spi2;
++		spi3 = &spi3;
++	};
++
++	chosen {
++		stdout-path = "serial2:115200n8";
++	};
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&ohci2 {
++	status = "okay";
++};
++
++&gmac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&gmac_pins_rgmii_a>;
++	phy = <&phy1>;
++	phy-mode = "rgmii";
++	snps,reset-gpio = <&pio 0 7 GPIO_ACTIVE_LOW>;
++	snps,reset-active-low;
++	snps,reset-delays-us = <0 10000 30000>;
++	status = "okay";
++
++	phy1: ethernet-phy@4 {
++		reg = <4>;
++	};
++};
++
++&i2c0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c0_pins_a>;
++	status = "okay";
++};
++
++&i2c1 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c1_pins_a>;
++	status = "okay";
++};
++
++&i2c2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c2_pins_a>;
++	status = "okay";
++};
++
++&i2c3 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&i2c3_pins_a>;
++	status = "okay";
++
++	rtc_twi: rtc@6f {
++	 compatible = "isil,isl1208";
++	 reg = <0x6f>;
++	};
++	fan: fan@18 {
++		compatible = "ti,amc6821";
++		reg = <0x18>;
++		cooling-min-state = <0>;
++		cooling-max-state = <9>;
++		#cooling-cells = <2>;
++	};
++};
++
++&spi0 {
++	status = "okay";
++
++	flash: flash@0 {
++		compatible = "spansion,m25p40";
++		spi-max-frequency = <16000000>;
++		spi-cpol;
++		spi-cpha;
++	};
++};
++
++&spi1 {
++	status = "okay";
++};
++
++&ir {
++	pinctrl-names = "default";
++	pinctrl-0 = <&ir_pins_a>;
++	status = "okay";
++};
++
++&mmc0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_pangolin>;
++	vmmc-supply = <&reg_vcc3v0>;
++	bus-width = <4>;
++	cd-gpios = <&pio 2 19 GPIO_ACTIVE_LOW>; /* PC19 */
++	status = "okay";
++};
++
++&mmc0_pins_a {
++	/* external pull-ups missing for some pins */
++	allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++};
++
++&mmc2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc2_pins_a>;
++	vmmc-supply = <&reg_vcc3v0>;
++	bus-width = <8>;
++	non-removable;
++	status = "okay";
++};
++
++&pio {
++	mmc0_cd_pin_pangolin: mmc0_cd_pin@0 {
++		allwinner,pins = "PC19";
++		allwinner,function = "gpio_in";
++		allwinner,drive = <SUN4I_PINCTRL_10_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_PULL_UP>;
++	};
++
++	leds_pins_pangolin: led_pins@0 {
++		allwinner,pins = "PH7", "PC16";
++		allwinner,function = "gpio_out";
++		allwinner,drive = <SUN4I_PINCTRL_20_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++
++	mmc2_pins_a: mmc2@0 {
++		allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11",
++				"PC12","PC13","PC14","PC15";
++		allwinner,function = "mmc2";
++		allwinner,drive = <SUN4I_PINCTRL_30_MA>;
++		allwinner,pull = <SUN4I_PINCTRL_NO_PULL>;
++	};
++};
++
++&p2wi {
++	status = "okay";
++
++	axp221: pmic@68 {
++		compatible = "x-powers,axp221";
++		reg = <0x68>;
++		interrupt-parent = <&nmi_intc>;
++		interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-controller;
++		#interrupt-cells = <1>;
++		dcdc1-supply = <&vcc_3v0>;
++		dcdc5-supply = <&vcc_dram>;
++
++		regulators {
++			x-powers,dcdc-freq = <3000>;
++
++			vcc_3v0: dcdc1 {
++				regulator-always-on;
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-name = "vcc-3v0";
++			};
++
++			vdd_cpu: dcdc2 {
++				regulator-always-on;
++				regulator-min-microvolt = <700000>;
++				regulator-max-microvolt = <1320000>;
++				regulator-name = "vdd-cpu";
++			};
++
++			vdd_gpu: dcdc3 {
++				regulator-always-on;
++				regulator-min-microvolt = <700000>;
++				regulator-max-microvolt = <1320000>;
++				regulator-name = "vdd-gpu";
++			};
++
++			vdd_sys_dll: dcdc4 {
++				regulator-always-on;
++				regulator-min-microvolt = <1100000>;
++				regulator-max-microvolt = <1100000>;
++				regulator-name = "vdd-sys-dll";
++			};
++
++			vcc_dram: dcdc5 {
++				regulator-always-on;
++				regulator-min-microvolt = <1500000>;
++				regulator-max-microvolt = <1500000>;
++				regulator-name = "vcc-dram";
++			};
++
++			vcc_wifi: aldo1 {
++				regulator-min-microvolt = <3300000>;
++				regulator-max-microvolt = <3300000>;
++				regulator-name = "vcc_wifi";
++			};
++
++			avcc: aldo3 {
++				regulator-always-on;
++				regulator-min-microvolt = <3000000>;
++				regulator-max-microvolt = <3000000>;
++				regulator-name = "avcc";
++			};
++		};
++	};
++};
++
++&uart0 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&uart0_pins_a>;
++	status = "okay";
++};
++
++&usb1_vbus_pin_a {
++	allwinner,pins = "PD23";
++};
++
++&reg_usb1_vbus {
++	gpio = <&pio 3 23 GPIO_ACTIVE_HIGH>; /* PD 23 */
++	status = "okay";
++};
++
++&usbphy {
++	status = "okay";
++	usb1_vbus-supply = <&reg_usb1_vbus>;
++};
+--- /dev/null
++++ b/configs/pangolin_defconfig
+@@ -0,0 +1,36 @@
++CONFIG_SUNXI_PANGOLIN=y
++CONFIG_SPL=y
++CONFIG_SYS_EXTRA_OPTIONS="USB_EHCI,SUNXI_GMAC,RGMII"
++CONFIG_DEFAULT_DEVICE_TREE="sun6i-a31-pangolin"
++CONFIG_VIDEO_VGA_VIA_LCD=y
++CONFIG_VIDEO_VGA_EXTERNAL_DAC_EN="PH25"
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_MACH_SUN6I=y
++CONFIG_DRAM_CHANNELS=1
++CONFIG_DRAM_CLK=360
++CONFIG_DRAM_ZQ=70
++CONFIG_AXP_DCDC1_VOLT=3300
++CONFIG_AXP_ALDO1_VOLT=0
++CONFIG_AXP_ALDO2_VOLT=1800
++CONFIG_AXP_ALDO3_VOLT=3000
++CONFIG_AXP_DLDO4_VOLT=3300
++CONFIG_AXP_ELDO1_VOLT=1200
++CONFIG_AXP_ELDO2_VOLT=2500
++CONFIG_AXP_ELDO3_VOLT=3300
++CONFIG_MMC_SUNXI_SLOT_EXTRA=2
++CONFIG_CONS_INDEX=3
++# Vbus gpio for usb1
++CONFIG_USB1_VBUS_PIN=""
++# No Vbus gpio for usb2
++CONFIG_USB2_VBUS_PIN=""
++CONFIG_USB=y
++CONFIG_DM_USB=y
++CONFIG_USB_EHCI=y
++CONFIG_USB_KEYBOARD=y
++CONFIG_DM_ETH=y
++CONFIG_CMD_IMLS=n
++CONFIG_ETH_DESIGNWARE=y
++CONFIG_DM_SPI=y
++CONFIG_DM_SPI_FLASH=y
++CONFIG_SUNXI_SPI=y
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -896,6 +896,14 @@ config VIDEO_LCD_PANEL_I2C_SCL
+ 	Set the SCL pin for the LCD i2c interface. This takes a string in the
+ 	format understood by sunxi_name_to_gpio, e.g. PH1 for pin 1 of port H.
+ 
++choice
++	prompt "Sunxi Board Variant"
++	optional
++
++config SUNXI_PANGOLIN
++	bool "Theobroma A31 uQ7 Board"
++
++endchoice
+ 
+ # Note only one of these may be selected at a time! But hidden choices are
+ # not supported by Kconfig
diff --git a/package/boot/uboot-sunxi/patches/062-A20-improve-gmac-upload.patch b/package/boot/uboot-sunxi/patches/062-A20-improve-gmac-upload.patch
new file mode 100644
index 0000000..b805bbd
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/062-A20-improve-gmac-upload.patch
@@ -0,0 +1,12 @@
+  GNU nano 2.7.4                                                    File: 062-A20-improve-gmac-upload.patch
+
+--- a/configs/A20-OLinuXino-Lime2_defconfig
++++ b/configs/A20-OLinuXino-Lime2_defconfig
+@@ -22,6 +22,7 @@ CONFIG_ETH_DESIGNWARE=y
+ CONFIG_RGMII=y
+ CONFIG_MII=y
+ CONFIG_SUN7I_GMAC=y
++CONFIG_GMAC_TX_DELAY=1
+ CONFIG_AXP_ALDO3_VOLT=2800
+ CONFIG_AXP_ALDO3_VOLT_SLOPE_08=y
+ CONFIG_AXP_ALDO3_INRUSH_QUIRK=y
diff --git a/package/boot/uboot-sunxi/patches/063-fix-lime2-revK-add-micrel-PHY.patch b/package/boot/uboot-sunxi/patches/063-fix-lime2-revK-add-micrel-PHY.patch
new file mode 100644
index 0000000..e1ed58e
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/063-fix-lime2-revK-add-micrel-PHY.patch
@@ -0,0 +1,44 @@
+--- a/configs/A20-OLinuXino-Lime2-eMMC_defconfig
++++ b/configs/A20-OLinuXino-Lime2-eMMC_defconfig
+@@ -8,6 +8,8 @@ CONFIG_MMC_SUNXI_SLOT_EXTRA=2
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
++CONFIG_PHY_MICREL=y
++CONFIG_PHY_MICREL_KSZ90X1=y
+ CONFIG_SATAPWR="PC3"
+ CONFIG_SPL_SPI_SUNXI=y
+ CONFIG_AHCI=y
+--- a/configs/A20-OLinuXino-Lime2_defconfig
++++ b/configs/A20-OLinuXino-Lime2_defconfig
+@@ -7,6 +7,8 @@ CONFIG_MMC0_CD_PIN="PH1"
+ CONFIG_USB0_VBUS_PIN="PC17"
+ CONFIG_USB0_VBUS_DET="PH5"
+ CONFIG_I2C1_ENABLE=y
++CONFIG_PHY_MICREL=y
++CONFIG_PHY_MICREL_KSZ90X1=y
+ CONFIG_SATAPWR="PC3"
+ CONFIG_AHCI=y
+ # CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+--- a/drivers/net/phy/micrel_ksz90x1.c
++++ b/drivers/net/phy/micrel_ksz90x1.c
+@@ -14,6 +14,8 @@
+ #include <errno.h>
+ #include <micrel.h>
+ #include <phy.h>
++#include <asm/io.h>
++#include <asm/arch/clock.h>
+ 
+ /*
+  * KSZ9021 - KSZ9031 common
+@@ -344,6 +346,10 @@ static int ksz9031_phy_extwrite(struct p
+ static int ksz9031_config(struct phy_device *phydev)
+ {
+ 	int ret;
++	struct sunxi_ccm_reg *const ccm =
++		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
++
++	setbits_le32(&ccm->gmac_clk_cfg, CCM_GMAC_CTRL_TX_CLK_DELAY(4));
+ 
+ 	ret = ksz9031_of_config(phydev);
+ 	if (ret)
diff --git a/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch b/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch
new file mode 100644
index 0000000..f2a2b5e
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/091-sun6i-sync-PLL1-multdiv-with-Boot1.patch
@@ -0,0 +1,32 @@
+From a58eb20fb80f478038243e9e0f30f6984725e265 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 6 Jan 2015 15:47:18 +0100
+Subject: sun6i: Sync PLL1 multipliers/dividers with Boot1
+
+This change syncs up the multipliers and dividers used to initialize
+PLL1 (i.e. the fast clock driving the ARM cores) with the values used
+in Allwinner's Boot1 on sun6i.
+
+More specifically, the following settings are now used:
+ * up to 768MHz:  mul=2, div=2 (was: mul=1, div=1)
+ * up to 1152MHz: mul=3, div=2 (unchanged)
+ * above 1152MHz: mul=4, div=2 (was: mul=2, div=1)
+
+--- a/arch/arm/mach-sunxi/clock_sun6i.c
++++ b/arch/arm/mach-sunxi/clock_sun6i.c
+@@ -112,11 +112,12 @@ void clock_set_pll1(unsigned int clk)
+ 	struct sunxi_ccm_reg * const ccm =
+ 		(struct sunxi_ccm_reg *)SUNXI_CCM_BASE;
+ 	const int p = 0;
+-	int k = 1;
+-	int m = 1;
++	int k = 2;
++	int m = 2;
+ 
+ 	if (clk > 1152000000) {
+-		k = 2;
++		k = 4;
++		m = 2;
+ 	} else if (clk > 768000000) {
+ 		k = 4;
+ 		m = 2;
diff --git a/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch b/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch
new file mode 100644
index 0000000..b62209e
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/093-sun6i-fix-PLL-LDO-voltselect.patch
@@ -0,0 +1,69 @@
+From b2b385df5095fff80b4655142f58a2a6801e6c80 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 6 Jan 2015 21:26:44 +0100
+Subject: sun6i: Fix and document PLL LDO voltage selection
+
+The PRCM_PLL_CTRL_LDO_OUT_L and PRCM_PLL_CTRL_LDO_OUT_H macros had
+their meaning reversed. This is fixed by this change-set. With this
+changed, the PRCM_PLL_CTRL_LDO_OUT_L(1370) now becomes self-evident
+as setting the voltage to 1.37v (which it had done all along, even
+though stating a different target voltage).
+
+After changing the PLL LDO setting, it will take a little while for
+the voltage output to settle. A sdelay()-based loop waits the same
+order of magnitude as Boot1.
+
+Furthermore, a bit of documentation is added to clarify that the
+required setting for the PLL LDO is 1.37v as per the A31 manual.
+
+--- a/arch/arm/mach-sunxi/clock_sun6i.c
++++ b/arch/arm/mach-sunxi/clock_sun6i.c
+@@ -25,13 +25,26 @@ void clock_init_safe(void)
+ 	struct sunxi_prcm_reg * const prcm =
+ 		(struct sunxi_prcm_reg *)SUNXI_PRCM_BASE;
+ 
+-	/* Set PLL ldo voltage without this PLL6 does not work properly */
++	/* Set PLL ldo voltage without this PLL6 does not work properly.
++	 *
++	 * As the A31 manual states, that "before enable PLL, PLLVDD
++	 * LDO should be set to 1.37v", we need to configure this to 2.5v
++	 * in the "PLL Input Power Select" (0 << 15) and (7 << 16).
++	 */
+ 	clrsetbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK,
+ 			PRCM_PLL_CTRL_LDO_KEY);
+ 	clrsetbits_le32(&prcm->pll_ctrl1, ~PRCM_PLL_CTRL_LDO_KEY_MASK,
+ 		PRCM_PLL_CTRL_LDO_DIGITAL_EN | PRCM_PLL_CTRL_LDO_ANALOG_EN |
+-		PRCM_PLL_CTRL_EXT_OSC_EN | PRCM_PLL_CTRL_LDO_OUT_L(1140));
++		PRCM_PLL_CTRL_EXT_OSC_EN | PRCM_PLL_CTRL_LDO_OUT_L(1370));
+ 	clrbits_le32(&prcm->pll_ctrl1, PRCM_PLL_CTRL_LDO_KEY_MASK);
++
++	/* Give the PLL LDO voltage setting some time to take hold.
++	 * Notes:
++	 *   1) We need to use sdelay() as the timers aren't set up yet.
++	 *   2) The 100k iterations come from Boot1, which spin's for 100k
++	 *      iterations through a loop.
++	 */
++	sdelay(100000);
+ #endif
+ 
+ #if defined(CONFIG_MACH_SUN8I_R40) || defined(CONFIG_MACH_SUN50I)
+--- a/arch/arm/include/asm/arch-sunxi/prcm.h
++++ b/arch/arm/include/asm/arch-sunxi/prcm.h
+@@ -110,13 +110,13 @@
+ #define PRCM_PLL_CTRL_LDO_OUT_MASK \
+ 	__PRCM_PLL_CTRL_LDO_OUT(0x7)
+ /* When using the low voltage 20 mV steps, and high voltage 30 mV steps */
+-#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
+-	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
+ #define PRCM_PLL_CTRL_LDO_OUT_H(n) \
++	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1000) / 20) & 0x7)
++#define PRCM_PLL_CTRL_LDO_OUT_L(n) \
+ 	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) - 1160) / 30) & 0x7)
+-#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
+-	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
+ #define PRCM_PLL_CTRL_LDO_OUT_HV(n) \
++	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 20) + 1000)
++#define PRCM_PLL_CTRL_LDO_OUT_LV(n) \
+ 	__PRCM_PLL_CTRL_VDD_LDO_OUT((((n) & 0x7) * 30) + 1160)
+ #define PRCM_PLL_CTRL_LDO_KEY (0xa7 << 24)
+ #define PRCM_PLL_CTRL_LDO_KEY_MASK (0xff << 24)
diff --git a/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch b/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch
new file mode 100644
index 0000000..a7afa51
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/100-sun6i-alternate-on-UART2.patch
@@ -0,0 +1,16 @@
+From d7311b6e7cdd1fc0e92665188e650934718cb2b1 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:52:01 +0200
+Subject: sun6i: define alternate-function for UART2 on GPG
+
+
+--- a/arch/arm/include/asm/arch-sunxi/gpio.h
++++ b/arch/arm/include/asm/arch-sunxi/gpio.h
+@@ -190,6 +190,7 @@ enum sunxi_gpio_number {
+ #define SUN6I_GPG_SDC1		2
+ #define SUN8I_GPG_SDC1		2
+ #define SUN6I_GPG_TWI3		2
++#define SUN6I_GPG_UART2         2
+ #define SUN5I_GPG_UART1		4
+ 
+ #define SUN6I_GPH_PWM		2
diff --git a/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch b/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch
new file mode 100644
index 0000000..823c156
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/101-sun6i-support-console-on-UART2.patch
@@ -0,0 +1,30 @@
+From c058dfb69136d62f88ae8b121104bdb7ce2df03f Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:53:11 +0200
+Subject: ARM: sun6i: Support console on UART2 (GPG6/GPG7)
+
+
+--- a/arch/arm/mach-sunxi/board.c
++++ b/arch/arm/mach-sunxi/board.c
+@@ -129,6 +129,10 @@ static int gpio_init(void)
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPG(3), SUN5I_GPG_UART1);
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPG(4), SUN5I_GPG_UART1);
+ 	sunxi_gpio_set_pull(SUNXI_GPG(4), SUNXI_GPIO_PULL_UP);
++#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN6I)
++	sunxi_gpio_set_cfgpin(SUNXI_GPG(6), SUN6I_GPG_UART2);
++	sunxi_gpio_set_cfgpin(SUNXI_GPG(7), SUN6I_GPG_UART2);
++	sunxi_gpio_set_pull(SUNXI_GPG(7), SUNXI_GPIO_PULL_UP);
+ #elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I)
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPB(0), SUN8I_GPB_UART2);
+ 	sunxi_gpio_set_cfgpin(SUNXI_GPB(1), SUN8I_GPB_UART2);
+--- a/include/configs/sunxi-common.h
++++ b/include/configs/sunxi-common.h
+@@ -244,6 +244,8 @@ extern int soft_i2c_gpio_scl;
+ #endif
+ #elif CONFIG_CONS_INDEX == 2 && defined(CONFIG_MACH_SUN5I)
+ #define OF_STDOUT_PATH		"/soc@01c00000/serial@01c28400:115200"
++#elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN6I)
++#define OF_STDOUT_PATH          "/soc@01c00000/serial@01c28800:115200"
+ #elif CONFIG_CONS_INDEX == 3 && defined(CONFIG_MACH_SUN8I)
+ #define OF_STDOUT_PATH		"/soc@01c00000/serial@01c28800:115200"
+ #elif CONFIG_CONS_INDEX == 5 && defined(CONFIG_MACH_SUN8I)
diff --git a/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch b/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch
new file mode 100644
index 0000000..b85e2af
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/102-sunxi-make_CONS_INDEX-configurable.patch
@@ -0,0 +1,23 @@
+From 78d5fab8e345b1273ec8c22d06f1a1d27670b518 Mon Sep 17 00:00:00 2001
+From: Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
+Date: Tue, 16 Jun 2015 10:59:38 +0200
+Subject: ARM: sunxi: Make CONS_INDEX configurable
+
+
+--- a/arch/arm/mach-sunxi/Kconfig
++++ b/arch/arm/mach-sunxi/Kconfig
+@@ -559,6 +559,14 @@ config SYS_BOARD
+ config SYS_SOC
+ 	default "sunxi"
+ 
++config CONS_INDEX
++        int "UART used for console"
++        range 1 5
++        default 1
++        ---help---
++        Defines the UART port used for serial output. It starts at 1 so UART0 is 1,
++        UART1 is 2 and so on.
++
+ config UART0_PORT_F
+ 	bool "UART0 on MicroSD breakout board"
+ 	default n
diff --git a/package/boot/uboot-sunxi/patches/200-mkimage-check-environment-for-dtc-binary-location.patch b/package/boot/uboot-sunxi/patches/200-mkimage-check-environment-for-dtc-binary-location.patch
new file mode 100644
index 0000000..482aa1a
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/200-mkimage-check-environment-for-dtc-binary-location.patch
@@ -0,0 +1,35 @@
+From 637800493945ffed2f454756300437a4ec86e3b1 Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Wed, 19 Jul 2017 22:23:15 +0200
+Subject: mkimage: check environment for dtc binary location
+
+Currently mkimage assumes the dtc binary is in the path and fails
+otherwise. This patch makes it check the DTC environment variable first
+for the dtc binary and then fall back to the default path. This makes
+it possible to call the u-boot build with make DTC=... and build a fit
+image with the dtc binary not being the the default path.
+
+Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
+Cc: Simon Glass <sjg@chromium.org>
+---
+ tools/fit_image.c | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+--- a/tools/fit_image.c
++++ b/tools/fit_image.c
+@@ -726,9 +726,14 @@ static int fit_handle_file(struct image_
+ 		}
+ 		*cmd = '\0';
+ 	} else if (params->datafile) {
++		const char* dtc = getenv("DTC");
++
++		if (!dtc)
++			dtc = MKIMAGE_DTC;
++
+ 		/* dtc -I dts -O dtb -p 500 -o tmpfile datafile */
+ 		snprintf(cmd, sizeof(cmd), "%s %s -o \"%s\" \"%s\"",
+-			 MKIMAGE_DTC, params->dtc, tmpfile, params->datafile);
++			 dtc, params->dtc, tmpfile, params->datafile);
+ 		debug("Trying to execute \"%s\"\n", cmd);
+ 	} else {
+ 		snprintf(cmd, sizeof(cmd), "cp \"%s\" \"%s\"",
diff --git a/package/boot/uboot-sunxi/patches/210-sunxi-deactivate-binman.patch b/package/boot/uboot-sunxi/patches/210-sunxi-deactivate-binman.patch
new file mode 100644
index 0000000..5efebbd
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/210-sunxi-deactivate-binman.patch
@@ -0,0 +1,37 @@
+From def280c4792262a368c8861312dc6b376181021f Mon Sep 17 00:00:00 2001
+From: Hauke Mehrtens <hauke@hauke-m.de>
+Date: Mon, 1 Jan 2018 23:10:56 +0100
+Subject: sunxi: deactivate binman
+
+Use the old way to generate the images instead of binman.
+binman needs python with swig to avoid this host tool dependency use the
+old way of generating images.
+---
+ Makefile | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+--- a/Makefile
++++ b/Makefile
+@@ -1555,8 +1555,10 @@ endif
+ 
+ ifneq ($(CONFIG_ARCH_SUNXI),)
+ ifeq ($(CONFIG_ARM64),)
+-u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img u-boot.dtb FORCE
+-	$(call if_changed,binman)
++OBJCOPYFLAGS_u-boot-sunxi-with-spl.bin = -I binary -O binary \
++				--pad-to=$(CONFIG_SPL_PAD_TO) --gap-fill=0xff
++u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.img FORCE
++	$(call if_changed,pad_cat)
+ else
+ u-boot-sunxi-with-spl.bin: spl/sunxi-spl.bin u-boot.itb FORCE
+ 	$(call if_changed,cat)
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -962,7 +962,6 @@ config ARCH_SOCFPGA
+ 
+ config ARCH_SUNXI
+ 	bool "Support sunxi (Allwinner) SoCs"
+-	select BINMAN
+ 	select CMD_GPIO
+ 	select CMD_MMC if MMC
+ 	select CMD_USB if DISTRO_DEFAULTS
diff --git a/package/boot/uboot-sunxi/patches/230-disable-axp209-on-a13-olinuxino.diff b/package/boot/uboot-sunxi/patches/230-disable-axp209-on-a13-olinuxino.diff
new file mode 100644
index 0000000..b846cbf
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/230-disable-axp209-on-a13-olinuxino.diff
@@ -0,0 +1,19 @@
+--- a/configs/A13-OLinuXino_defconfig
++++ b/configs/A13-OLinuXino_defconfig
+@@ -7,7 +7,6 @@ CONFIG_DRAM_EMR1=0
+ CONFIG_MMC0_CD_PIN="PG0"
+ CONFIG_USB0_VBUS_DET="PG1"
+ CONFIG_USB1_VBUS_PIN="PG11"
+-CONFIG_AXP_GPIO=y
+ # CONFIG_VIDEO_HDMI is not set
+ CONFIG_VIDEO_VGA_VIA_LCD=y
+ CONFIG_VIDEO_VGA_VIA_LCD_FORCE_SYNC_ACTIVE_HIGH=y
+@@ -21,7 +20,7 @@ CONFIG_CMD_USB_MASS_STORAGE=y
+ CONFIG_DEFAULT_DEVICE_TREE="sun5i-a13-olinuxino"
+ CONFIG_DFU_RAM=y
+ CONFIG_FASTBOOT_CMD_OEM_FORMAT=y
+-CONFIG_AXP_ALDO3_VOLT=3300
++CONFIG_SUNXI_NO_PMIC=y
+ CONFIG_CONS_INDEX=2
+ CONFIG_USB_EHCI_HCD=y
+ CONFIG_USB_OHCI_HCD=y
diff --git a/package/boot/uboot-sunxi/patches/250-sun8i-h3-zeropi-add-device-tree.patch b/package/boot/uboot-sunxi/patches/250-sun8i-h3-zeropi-add-device-tree.patch
new file mode 100644
index 0000000..4250e4e
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/250-sun8i-h3-zeropi-add-device-tree.patch
@@ -0,0 +1,81 @@
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -539,7 +539,8 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \
+ 	sun8i-h3-orangepi-plus.dtb \
+ 	sun8i-h3-orangepi-plus2e.dtb \
+ 	sun8i-h3-orangepi-zero-plus2.dtb \
+-	sun8i-h3-rervision-dvk.dtb
++	sun8i-h3-rervision-dvk.dtb \
++	sun8i-h3-zeropi.dtb
+ dtb-$(CONFIG_MACH_SUN8I_R40) += \
+ 	sun8i-r40-bananapi-m2-ultra.dtb \
+ 	sun8i-v40-bananapi-m2-berry.dtb
+--- /dev/null
++++ b/arch/arm/dts/sun8i-h3-zeropi.dts
+@@ -0,0 +1,66 @@
++// SPDX-License-Identifier: GPL-2.0-or-later OR MIT
++
++#include "sun8i-h3-nanopi.dtsi"
++
++/ {
++	model = "FriendlyElec ZeroPi";
++	compatible = "friendlyarm,zeropi", "allwinner,sun8i-h3";
++
++	aliases {
++		ethernet0 = &emac;
++	};
++
++	reg_gmac_3v3: gmac-3v3 {
++		compatible = "regulator-fixed";
++		pinctrl-names = "default";
++		pinctrl-0 = <&gmac_power_pin_nanopi>;
++		regulator-name = "gmac-3v3";
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		startup-delay-us = <100000>;
++		enable-active-high;
++		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
++	};
++};
++
++&ehci0 {
++	status = "okay";
++};
++
++&ohci0 {
++	status = "okay";
++};
++
++&pio {
++	gmac_power_pin_nanopi: gmac_power_pin@0 {
++		pins = "PD6";
++		function = "gpio_out";
++	};
++};
++
++&external_mdio {
++	ext_rgmii_phy: ethernet-phy@1 {
++		compatible = "ethernet-phy-ieee802.3-c22";
++		reg = <7>;
++	};
++};
++
++&emac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&emac_rgmii_pins>;
++	phy-supply = <&reg_gmac_3v3>;
++	phy-handle = <&ext_rgmii_phy>;
++	phy-mode = "rgmii";
++
++	allwinner,leds-active-low;
++	status = "okay";
++};
++
++&usb_otg {
++	status = "okay";
++	dr_mode = "peripheral";
++};
++
++&usbphy {
++	usb0_id_det-gpios = <&pio 6 12 GPIO_ACTIVE_HIGH>; /* PG12 */
++};
diff --git a/package/boot/uboot-sunxi/patches/251-sun8i-h3-zeropi-add-defconfig.patch b/package/boot/uboot-sunxi/patches/251-sun8i-h3-zeropi-add-defconfig.patch
new file mode 100644
index 0000000..76e3332
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/251-sun8i-h3-zeropi-add-defconfig.patch
@@ -0,0 +1,24 @@
+--- /dev/null
++++ b/configs/zeropi_defconfig
+@@ -0,0 +1,21 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_MACH_SUN8I_H3=y
++CONFIG_DRAM_CLK=408
++CONFIG_DRAM_ZQ=3881979
++CONFIG_DRAM_ODT_EN=y
++CONFIG_MACPWR="PD6"
++# CONFIG_VIDEO_DE2 is not set
++CONFIG_NR_DRAM_BANKS=1
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-zeropi"
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_CONSOLE_MUX=y
++CONFIG_SPL=y
++CONFIG_SYS_CLK_FREQ=480000000
++# CONFIG_CMD_IMLS is not set
++# CONFIG_CMD_FLASH is not set
++# CONFIG_CMD_FPGA is not set
++CONFIG_SUN8I_EMAC=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
diff --git a/package/boot/uboot-sunxi/patches/252-sunxi-h3-add-support-for-nanopi-r1.patch b/package/boot/uboot-sunxi/patches/252-sunxi-h3-add-support-for-nanopi-r1.patch
new file mode 100644
index 0000000..0db7be5
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/252-sunxi-h3-add-support-for-nanopi-r1.patch
@@ -0,0 +1,198 @@
+From 0e8043aff1aae95d1f7b7422b91b57d9569860d3 Mon Sep 17 00:00:00 2001
+From: Jayantajit Gogoi <jayanta.gogoi525@gmail.com>
+Date: Mon, 12 Oct 2020 18:39:53 +0000
+Subject: [PATCH] sunxi: add support for FriendlyARM NanoPi R1
+
+Signed-off-by: Jayantajit Gogoi <jayanta.gogoi525@gmail.com>
+---
+ arch/arm/dts/Makefile               |   1 +
+ arch/arm/dts/sun8i-h3-nanopi-r1.dts | 146 ++++++++++++++++++++++++++++
+ configs/nanopi_r1_defconfig         |  22 +++++
+ 3 files changed, 169 insertions(+)
+ create mode 100644 arch/arm/dts/sun8i-h3-nanopi-r1.dts
+ create mode 100644 configs/nanopi_r1_defconfig
+
+--- a/arch/arm/dts/Makefile
++++ b/arch/arm/dts/Makefile
+@@ -531,6 +531,7 @@ dtb-$(CONFIG_MACH_SUN8I_H3) += \
+ 	sun8i-h3-nanopi-m1-plus.dtb \
+ 	sun8i-h3-nanopi-neo.dtb \
+ 	sun8i-h3-nanopi-neo-air.dtb \
++	sun8i-h3-nanopi-r1.dtb \
+ 	sun8i-h3-orangepi-2.dtb \
+ 	sun8i-h3-orangepi-lite.dtb \
+ 	sun8i-h3-orangepi-one.dtb \
+--- /dev/null
++++ b/arch/arm/dts/sun8i-h3-nanopi-r1.dts
+@@ -0,0 +1,146 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright (C) 2019 Igor Pecovnik <igor@armbian.com>
++ * Copyright (C) 2020 Jayantajit Gogoi <jayanta.gogoi525@gmail.com>
++ */
++
++/* NanoPi R1 is based on the NanoPi-H3 design from FriendlyARM */
++#include "sun8i-h3-nanopi.dtsi"
++
++/ {
++	model = "FriendlyARM NanoPi R1";
++	compatible = "friendlyarm,nanopi-r1", "allwinner,sun8i-h3";
++
++	reg_gmac_3v3: gmac-3v3 {
++		compatible = "regulator-fixed";
++		regulator-name = "gmac-3v3";
++		regulator-min-microvolt = <3300000>;
++		regulator-max-microvolt = <3300000>;
++		startup-delay-us = <100000>;
++		enable-active-high;
++		gpio = <&pio 3 6 GPIO_ACTIVE_HIGH>;
++	};
++
++	vdd_cpux: gpio-regulator {
++		compatible = "regulator-gpio";
++		pinctrl-names = "default";
++		regulator-name = "vdd-cpux";
++		regulator-type = "voltage";
++		regulator-boot-on;
++		regulator-always-on;
++		regulator-min-microvolt = <1100000>;
++		regulator-max-microvolt = <1300000>;
++		regulator-ramp-delay = <50>;
++		gpios = <&r_pio 0 6 GPIO_ACTIVE_HIGH>;
++		gpios-states = <0x1>;
++		states = <1100000 0x0
++			  1300000 0x1>;
++	};
++
++	wifi_pwrseq: wifi_pwrseq {
++		compatible = "mmc-pwrseq-simple";
++		pinctrl-names = "default";
++		reset-gpios = <&r_pio 0 7 GPIO_ACTIVE_LOW>;
++	};
++
++	leds {
++		/delete-node/ pwr;
++		status {
++			label = "nanopi:red:status";
++			gpios = <&pio 0 10 GPIO_ACTIVE_HIGH>;
++			linux,default-trigger = "heartbeat";
++		};
++
++		wan {
++			label = "nanopi:green:wan";
++			gpios = <&pio 6 11 GPIO_ACTIVE_HIGH>;
++		};
++
++		lan {
++			label = "nanopi:green:lan";
++			gpios = <&pio 0 9 GPIO_ACTIVE_HIGH>;
++		};
++	};
++
++	r_gpio_keys {
++		pinctrl-names = "default";
++		pinctrl-0 = <&sw_r_npi>;
++
++		/delete-node/ k1;
++		reset {
++			label = "reset";
++			linux,code = <KEY_RESTART>;
++			gpios = <&r_pio 0 3 GPIO_ACTIVE_LOW>;
++		};
++	};
++};
++
++&cpu0 {
++	cpu-supply = <&vdd_cpux>;
++};
++
++&ehci1 {
++	status = "okay";
++};
++
++&ehci2 {
++	status = "okay";
++};
++
++&emac {
++	pinctrl-names = "default";
++	pinctrl-0 = <&emac_rgmii_pins>;
++	phy-supply = <&reg_gmac_3v3>;
++	phy-handle = <&ext_rgmii_phy>;
++	phy-mode = "rgmii";
++	status = "okay";
++};
++
++&external_mdio {
++	ext_rgmii_phy: ethernet-phy@1 {
++		compatible = "ethernet-phy-ieee802.3-c22";
++		reg = <7>;
++	};
++};
++
++&mmc1 {
++	vmmc-supply = <&reg_vcc3v3>;
++	vqmmc-supply = <&reg_vcc3v3>;
++	mmc-pwrseq = <&wifi_pwrseq>;
++	bus-width = <4>;
++	non-removable;
++	status = "okay";
++
++	sdio_wifi: sdio_wifi@1 {
++		reg = <1>;
++		compatible = "brcm,bcm4329-fmac";
++		interrupt-parent = <&pio>;
++		interrupts = <6 10 IRQ_TYPE_LEVEL_LOW>;
++		interrupt-names = "host-wake";
++	};
++};
++
++&mmc2 {
++	pinctrl-names = "default";
++	pinctrl-0 = <&mmc2_8bit_pins>;
++	vmmc-supply = <&reg_vcc3v3>;
++	vqmmc-supply = <&reg_vcc3v3>;
++	bus-width = <8>;
++	non-removable;
++	status = "okay";
++};
++
++&ohci1 {
++	status = "okay";
++};
++
++&ohci2 {
++	status = "okay";
++};
++
++&r_pio {
++	sw_r_npi: key_pins {
++		pins = "PL3";
++		function = "gpio_in";
++	};
++};
+--- /dev/null
++++ b/configs/nanopi_r1_defconfig
+@@ -0,0 +1,22 @@
++CONFIG_ARM=y
++CONFIG_ARCH_SUNXI=y
++CONFIG_SPL=y
++CONFIG_MACH_SUN8I_H3=y
++CONFIG_DRAM_CLK=408
++CONFIG_DRAM_ZQ=3881979
++CONFIG_DRAM_ODT_EN=y
++CONFIG_MACPWR="PD6"
++# CONFIG_VIDEO_DE2 is not set
++CONFIG_NR_DRAM_BANKS=1
++# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
++CONFIG_CONSOLE_MUX=y
++CONFIG_SYS_CLK_FREQ=480000000
++# CONFIG_CMD_FLASH is not set
++# CONFIG_SPL_DOS_PARTITION is not set
++# CONFIG_SPL_EFI_PARTITION is not set
++CONFIG_DEFAULT_DEVICE_TREE="sun8i-h3-nanopi-r1"
++CONFIG_SUN8I_EMAC=y
++CONFIG_USB_EHCI_HCD=y
++CONFIG_USB_OHCI_HCD=y
++CONFIG_SYS_USB_EVENT_POLL_VIA_INT_QUEUE=y
++CONFIG_MMC_SUNXI_SLOT_EXTRA=2
diff --git a/package/boot/uboot-sunxi/patches/260-add-missing-type-u64.patch b/package/boot/uboot-sunxi/patches/260-add-missing-type-u64.patch
new file mode 100644
index 0000000..a6204c7
--- /dev/null
+++ b/package/boot/uboot-sunxi/patches/260-add-missing-type-u64.patch
@@ -0,0 +1,10 @@
+--- a/include/linux/types.h
++++ b/include/linux/types.h
+@@ -1,6 +1,7 @@
+ #ifndef _LINUX_TYPES_H
+ #define _LINUX_TYPES_H
+ 
++typedef unsigned long long __u64;
+ #include <linux/posix_types.h>
+ #include <asm/types.h>
+ #include <stdbool.h>
diff --git a/package/boot/uboot-sunxi/uEnv-a64.txt b/package/boot/uboot-sunxi/uEnv-a64.txt
new file mode 100644
index 0000000..a47ebda
--- /dev/null
+++ b/package/boot/uboot-sunxi/uEnv-a64.txt
@@ -0,0 +1,7 @@
+setenv mmc_rootpart 2
+part uuid mmc ${mmc_bootdev}:${mmc_rootpart} uuid
+setenv loadkernel fatload mmc \$mmc_bootdev \$kernel_addr_r uImage
+setenv loaddtb fatload mmc \$mmc_bootdev \$fdt_addr_r dtb
+setenv bootargs console=ttyS0,115200 earlyprintk root=PARTUUID=${uuid} rootwait earlycon=uart,mmio32,0x01c28000
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& booti \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-sunxi/uEnv-default.txt b/package/boot/uboot-sunxi/uEnv-default.txt
new file mode 100644
index 0000000..e024954
--- /dev/null
+++ b/package/boot/uboot-sunxi/uEnv-default.txt
@@ -0,0 +1,6 @@
+setenv fdt_high ffffffff
+setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
+setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
+setenv bootargs console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-sunxi/uEnv-pangolin.txt b/package/boot/uboot-sunxi/uEnv-pangolin.txt
new file mode 100644
index 0000000..9c4fa11
--- /dev/null
+++ b/package/boot/uboot-sunxi/uEnv-pangolin.txt
@@ -0,0 +1,6 @@
+setenv fdt_high ffffffff
+setenv loadkernel fatload mmc 0 \$kernel_addr_r uImage
+setenv loaddtb fatload mmc 0 \$fdt_addr_r dtb
+setenv bootargs console=ttyS2,115200 earlyprintk root=/dev/mmcblk0p2 rootwait
+setenv uenvcmd run loadkernel \&\& run loaddtb \&\& bootm \$kernel_addr_r - \$fdt_addr_r
+run uenvcmd
diff --git a/package/boot/uboot-tegra/Makefile b/package/boot/uboot-tegra/Makefile
new file mode 100644
index 0000000..a3d6690
--- /dev/null
+++ b/package/boot/uboot-tegra/Makefile
@@ -0,0 +1,64 @@
+#
+# Copyright (C) 2017-2019 Tomasz Maciej Nowak <tmn505@gmail.com>
+#
+# This is free software, licensed under the GNU General Public License v2.
+# See /LICENSE for more information.
+#
+include $(TOPDIR)/rules.mk
+
+PKG_VERSION := 2020.04
+PKG_RELEASE := 1
+
+PKG_HASH := fe732aaf037d9cc3c0909bad8362af366ae964bbdac6913a34081ff4ad565372
+
+PKG_MAINTAINER := Tomasz Maciej Nowak <tmn505@gmail.com>
+
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+
+define U-Boot/Default
+  BUILD_TARGET := tegra
+  HIDDEN := y
+endef
+
+define U-Boot/trimslice
+  NAME := CompuLab TrimSlice
+  BUILD_DEVICES := compulab_trimslice
+  UBOOT_IMAGE := trimslice-mmc.img trimslice-spi.img
+  SOC := tegra20
+  VENDOR := compulab
+endef
+
+UBOOT_TARGETS := trimslice
+
+define Build/bct-image
+	$(CP) $(PKG_BUILD_DIR)/u-boot-dtb-tegra.bin $(PKG_BUILD_DIR)/u-boot.bin
+	$(foreach bct,$(basename $(UBOOT_IMAGE)), \
+		cd $(PKG_BUILD_DIR); \
+		cbootimage -s $(SOC) -gbct \
+			$(STAGING_DIR_HOST)/share/cbootimage-configs/$(SOC)/$(VENDOR)/$(VARIANT)/$(bct).bct.cfg \
+			$(bct).bct; \
+		cbootimage -s $(SOC) \
+			$(STAGING_DIR_HOST)/share/cbootimage-configs/$(SOC)/$(VENDOR)/$(VARIANT)/$(bct).img.cfg \
+			$(PKG_BUILD_DIR)/$(bct).img; \
+		rm -f $(bct).bct; \
+	)
+endef
+
+define Build/Configure
+	sed '/select BINMAN/d' -i $(PKG_BUILD_DIR)/arch/arm/mach-tegra/Kconfig
+	$(call Build/Configure/U-Boot)
+endef
+
+define Build/Compile
+	$(call Build/Compile/U-Boot)
+	$(call Build/bct-image)
+endef
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(foreach img,$(UBOOT_IMAGE), \
+		$(CP) $(PKG_BUILD_DIR)/$(img) $(STAGING_DIR_IMAGE)/;)
+endef
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-zynq/Makefile b/package/boot/uboot-zynq/Makefile
new file mode 100644
index 0000000..b6b1dc8
--- /dev/null
+++ b/package/boot/uboot-zynq/Makefile
@@ -0,0 +1,65 @@
+#
+# 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
+
+PKG_VERSION:=2019.07
+
+PKG_HASH:=bff4fa77e8da17521c030ca4c5b947a056c1b1be4d3e6ee8637020b8d50251d0
+
+include $(INCLUDE_DIR)/kernel.mk
+include $(INCLUDE_DIR)/u-boot.mk
+include $(INCLUDE_DIR)/package.mk
+include $(INCLUDE_DIR)/host-build.mk
+
+define U-Boot/Default
+  BUILD_TARGET:=zynq
+  UBOOT_IMAGE:=spl/boot.bin u-boot.img
+  UBOOT_CONFIG:=zynq_$(1)
+  UENV:=default
+  HIDDEN:=1
+endef
+
+define U-Boot/zc702
+  NAME:=Xilinx ZC702 Dev Board
+  BUILD_DEVICES:=xlnx_zynq-zc702
+endef
+
+define U-Boot/zed
+  NAME:=Avnet Digilent ZedBoard Dev Board
+  BUILD_DEVICES:=avnet_zynq-zed
+endef
+
+define U-Boot/zybo
+  NAME:=Digilent Zybo Dev Board
+  BUILD_DEVICES:=digilent_zynq-zybo
+endef
+
+define U-Boot/zybo_z7
+  NAME:=Digilent Zybo Z7 board
+  BUILD_DEVICES:=digilent_zynq-zybo-z7
+endef
+
+UBOOT_TARGETS := \
+	zc702 \
+	zed \
+	zybo \
+	zybo_z7
+
+define Build/InstallDev
+	$(INSTALL_DIR) $(STAGING_DIR_IMAGE)
+	$(CP) $(PKG_BUILD_DIR)/spl/boot.bin $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-boot.bin
+	$(CP) $(PKG_BUILD_DIR)/u-boot.img $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-u-boot.img
+	$(CP) ./files/uEnv-$(UENV).txt $(STAGING_DIR_IMAGE)/$(BUILD_DEVICES)-uEnv.txt
+endef
+
+define Package/u-boot/install/default
+endef
+
+Build/Exports:=$(Host/Exports)
+
+$(eval $(call BuildPackage/U-Boot))
diff --git a/package/boot/uboot-zynq/files/uEnv-default.txt b/package/boot/uboot-zynq/files/uEnv-default.txt
new file mode 100644
index 0000000..5030b07
--- /dev/null
+++ b/package/boot/uboot-zynq/files/uEnv-default.txt
@@ -0,0 +1 @@
+bootargs=console=ttyPS0,115200n8 root=/dev/mmcblk0p2 rootwait earlyprintk
diff --git a/package/boot/uboot-zynq/patches/010-fix_dtc_compilation_on_host_gcc10.patch b/package/boot/uboot-zynq/patches/010-fix_dtc_compilation_on_host_gcc10.patch
new file mode 100644
index 0000000..a4080e4
--- /dev/null
+++ b/package/boot/uboot-zynq/patches/010-fix_dtc_compilation_on_host_gcc10.patch
@@ -0,0 +1,48 @@
+From e33a814e772cdc36436c8c188d8c42d019fda639 Mon Sep 17 00:00:00 2001
+From: Dirk Mueller <dmueller@suse.com>
+Date: Tue, 14 Jan 2020 18:53:41 +0100
+Subject: [PATCH] scripts/dtc: Remove redundant YYLOC global declaration
+
+gcc 10 will default to -fno-common, which causes this error at link
+time:
+
+  (.text+0x0): multiple definition of `yylloc'; dtc-lexer.lex.o (symbol from plugin):(.text+0x0): first defined here
+
+This is because both dtc-lexer as well as dtc-parser define the same
+global symbol yyloc. Before with -fcommon those were merged into one
+defintion. The proper solution would be to to mark this as "extern",
+however that leads to:
+
+  dtc-lexer.l:26:16: error: redundant redeclaration of 'yylloc' [-Werror=redundant-decls]
+   26 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+In file included from dtc-lexer.l:24:
+dtc-parser.tab.h:127:16: note: previous declaration of 'yylloc' was here
+  127 | extern YYLTYPE yylloc;
+      |                ^~~~~~
+cc1: all warnings being treated as errors
+
+which means the declaration is completely redundant and can just be
+dropped.
+
+Signed-off-by: Dirk Mueller <dmueller@suse.com>
+Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
+[robh: cherry-pick from upstream]
+Cc: stable@vger.kernel.org
+Signed-off-by: Rob Herring <robh@kernel.org>
+---
+ scripts/dtc/dtc-lexer.l | 1 -
+ 1 file changed, 1 deletion(-)
+
+diff --git a/scripts/dtc/dtc-lexer.l b/scripts/dtc/dtc-lexer.l
+index 5c6c3fd557d7f..b3b7270300de5 100644
+--- a/scripts/dtc/dtc-lexer.l
++++ b/scripts/dtc/dtc-lexer.l
+@@ -38,7 +38,6 @@ LINECOMMENT	"//".*\n
+ #include "srcpos.h"
+ #include "dtc-parser.tab.h"
+ 
+-YYLTYPE yylloc;
+ extern bool treesource_error;
+ 
+ /* CAUTION: this will stop working if we ever use yyless() or yyunput() */
diff --git a/package/boot/uboot-zynq/patches/110-zybo-z7-read-mac-address-from-SPI-flash-memory.patch b/package/boot/uboot-zynq/patches/110-zybo-z7-read-mac-address-from-SPI-flash-memory.patch
new file mode 100644
index 0000000..00dce9a
--- /dev/null
+++ b/package/boot/uboot-zynq/patches/110-zybo-z7-read-mac-address-from-SPI-flash-memory.patch
@@ -0,0 +1,103 @@
+From 67db0da72eb7ed87ebaaeb8a26891cb2cf916500 Mon Sep 17 00:00:00 2001
+From: Luis Araneda <luaraneda@gmail.com>
+Date: Sun, 21 Jul 2019 23:24:12 -0400
+Subject: [U-Boot] [PATCH] arm: zynq: read mac address from SPI flash memory
+
+Implement a method for reading the MAC address from an
+SPI flash memory.
+In particular, this method is used by the Zybo Z7 board
+to read the MAC address from the OTP region in the SPI NOR
+memory
+
+Signed-off-by: Luis Araneda <luaraneda@gmail.com>
+---
+As of 2019-08-18, this patch has not been accepted by upstream U-Boot.
+Keep this patch until an alternative is accepted by upstream.
+---
+ board/xilinx/common/board.c    | 28 ++++++++++++++++++++++++++++
+ configs/zynq_zybo_z7_defconfig |  3 +++
+ drivers/misc/Kconfig           | 17 +++++++++++++++++
+ 3 files changed, 48 insertions(+)
+
+--- a/board/xilinx/common/board.c
++++ b/board/xilinx/common/board.c
+@@ -6,7 +6,10 @@
+ 
+ #include <common.h>
+ #include <dm/uclass.h>
++#include <dm/device.h>
++#include <dm/device-internal.h>
+ #include <i2c.h>
++#include <spi_flash.h>
+ 
+ int zynq_board_read_rom_ethaddr(unsigned char *ethaddr)
+ {
+@@ -34,5 +37,30 @@ int zynq_board_read_rom_ethaddr(unsigned
+ 		debug("%s: I2C EEPROM MAC %pM\n", __func__, ethaddr);
+ #endif
+ 
++#if defined(CONFIG_MAC_ADDR_IN_SPI_FLASH)
++	struct spi_flash *flash;
++	struct udevice *dev;
++
++	ret = spi_flash_probe_bus_cs(CONFIG_SF_DEFAULT_BUS,
++				     CONFIG_SF_DEFAULT_CS,
++				     0, 0, &dev);
++	if (ret) {
++		printf("SPI(bus:%u cs:%u) probe failed\n",
++		       CONFIG_SF_DEFAULT_BUS,
++		       CONFIG_SF_DEFAULT_CS);
++		return 0;
++	}
++
++	flash = dev_get_uclass_priv(dev);
++	flash->read_opcode = CONFIG_MAC_ADDR_SPI_FLASH_READ_CMD;
++
++	if (spi_flash_read_dm(dev,
++			      CONFIG_MAC_ADDR_SPI_FLASH_DATA_OFFSET,
++			      6, ethaddr))
++		printf("SPI MAC address read failed\n");
++
++	device_remove(dev, DM_REMOVE_NORMAL);
++#endif
++
+ 	return ret;
+ }
+--- a/configs/zynq_zybo_z7_defconfig
++++ b/configs/zynq_zybo_z7_defconfig
+@@ -42,6 +42,9 @@ CONFIG_DFU_RAM=y
+ CONFIG_FPGA_XILINX=y
+ CONFIG_FPGA_ZYNQPL=y
+ CONFIG_DM_GPIO=y
++CONFIG_MAC_ADDR_IN_SPI_FLASH=y
++CONFIG_MAC_ADDR_SPI_FLASH_READ_CMD=0x4b
++CONFIG_MAC_ADDR_SPI_FLASH_DATA_OFFSET=0x20
+ CONFIG_MMC_SDHCI=y
+ CONFIG_MMC_SDHCI_ZYNQ=y
+ CONFIG_SPI_FLASH=y
+--- a/drivers/misc/Kconfig
++++ b/drivers/misc/Kconfig
+@@ -366,6 +366,23 @@ config SYS_I2C_EEPROM_ADDR_OVERFLOW
+ 
+ endif
+ 
++config MAC_ADDR_IN_SPI_FLASH
++	bool "MAC address in SPI flash"
++	help
++	  Read MAC address from an SPI flash memory
++
++if MAC_ADDR_IN_SPI_FLASH
++
++config MAC_ADDR_SPI_FLASH_READ_CMD
++	hex "Read command for the SPI flash memory"
++	default 0
++
++config MAC_ADDR_SPI_FLASH_DATA_OFFSET
++	hex "Offset of MAC data in SPI flash memory"
++	default 0
++
++endif
++
+ config GDSYS_RXAUI_CTRL
+ 	bool "Enable gdsys RXAUI control driver"
+ 	depends on MISC
diff --git a/package/boot/uboot-zynq/patches/210-link-libcrypto-static.patch b/package/boot/uboot-zynq/patches/210-link-libcrypto-static.patch
new file mode 100644
index 0000000..d2e7bf1
--- /dev/null
+++ b/package/boot/uboot-zynq/patches/210-link-libcrypto-static.patch
@@ -0,0 +1,14 @@
+OpenWrt links the libressl statically against mkimage, make sure all the 
+needed dependencies are added too.
+
+--- a/tools/Makefile
++++ b/tools/Makefile
+@@ -151,7 +151,7 @@ ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CON
+ HOSTCFLAGS_kwbimage.o += \
+ 	$(shell pkg-config --cflags libssl libcrypto 2> /dev/null || echo "")
+ HOSTLOADLIBES_mkimage += \
+-	$(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto")
++	$(shell pkg-config --libs --static libssl libcrypto 2> /dev/null || echo "-lssl -lpthread -lcrypto")
+ 
+ # OS X deprecate openssl in favour of CommonCrypto, supress deprecation
+ # warnings on those systems