Merge tag 'u-boot-imx-20190101' of git://www.denx.de/git/u-boot-imx

imx for 2019.01

- introduce support for i.MX8M
- fix size limit for Vhybrid / pico boards
- several board fixes
- w1 driver for MX2x / MX5x
diff --git a/.travis.yml b/.travis.yml
index fe2dfce..321fd79 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -336,6 +336,10 @@
     - name: "Check for configs without MAINTAINERS entry"
       script:
         - if [ `./tools/genboardscfg.py -f 2>&1 | wc -l` -ne 0 ]; then exit 1; fi
+    # Ensure host tools build
+    - name: "Build tools-only"
+      script:
+        - make tools-only_config tools-only -j$(nproc)
 
     # test/py
     - name: "test/py sandbox"
diff --git a/Kconfig b/Kconfig
index ee7ee30..aff7b2e 100644
--- a/Kconfig
+++ b/Kconfig
@@ -126,6 +126,7 @@
 config SYS_MALLOC_F
 	bool "Enable malloc() pool before relocation"
 	default y if DM
+
 	help
 	  Before relocation, memory is very limited on many platforms. Still,
 	  we can provide a small malloc() pool if needed. Driver model in
@@ -136,6 +137,7 @@
 	hex "Size of malloc() pool before relocation"
 	depends on SYS_MALLOC_F
 	default 0x1000 if AM33XX
+	default 0x2800 if SANDBOX
 	default 0x400
 	help
 	  Before relocation, memory is very limited on many platforms. Still,
diff --git a/MAINTAINERS b/MAINTAINERS
index 0cec39c..ae82501 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -512,6 +512,24 @@
 T:	git git://git.denx.de/u-boot-mips.git
 F:	arch/mips/
 
+MIPS MSCC
+M:	Gregory CLEMENT <gregory.clement@bootlin.com>
+M:	Lars Povlsen <lars.povlsen@microchip.com>
+M:	Horatiu Vultur <horatiu.vultur@microchip.com>
+S:	Maintained
+F:	arch/mips/mach-mscc/
+F:	arch/mips/dts/luton*
+F:	arch/mips/dts/mscc*
+F:	arch/mips/dts/ocelot*
+F:	board/mscc/
+F:	configs/mscc*
+F:	include/configs/vcoreiii.h
+
+MIPS JZ4780
+M:	Ezequiel Garcia <ezequiel@collabora.com>
+S:	Maintained
+F:	arch/mips/mach-jz47xx/
+
 MMC
 M:	Jaehoon Chung <jh80.chung@samsung.com>
 S:	Maintained
@@ -719,5 +737,6 @@
 Q:	http://patchwork.ozlabs.org/project/uboot/list/
 S:	Maintained
 T:	git git://git.denx.de/u-boot.git
+F:	configs/tools-only_defconfig
 F:	*
 F:	*/
diff --git a/Makefile b/Makefile
index fe41a5f..ed8647b 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 VERSION = 2019
 PATCHLEVEL = 01
 SUBLEVEL =
-EXTRAVERSION = -rc1
+EXTRAVERSION = -rc2
 NAME =
 
 # *DOCUMENTATION*
@@ -724,8 +724,7 @@
 libs-y += env/
 libs-$(CONFIG_API) += api/
 libs-$(CONFIG_HAS_POST) += post/
-libs-y += test/
-libs-y += test/dm/
+libs-$(CONFIG_UNIT_TEST) += test/ test/dm/
 libs-$(CONFIG_UT_ENV) += test/env/
 libs-$(CONFIG_UT_OVERLAY) += test/overlay/
 
@@ -913,47 +912,47 @@
 
 all:		$(ALL-y) cfg
 ifeq ($(CONFIG_DM_I2C_COMPAT)$(CONFIG_SANDBOX),y)
-	@echo "===================== WARNING ======================"
-	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
-	@echo "(possibly in a subsequent patch in your series)"
-	@echo "before sending patches to the mailing list."
-	@echo "===================================================="
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
+	@echo >&2 "(possibly in a subsequent patch in your series)"
+	@echo >&2 "before sending patches to the mailing list."
+	@echo >&2 "===================================================="
 endif
 ifeq ($(CONFIG_MMC),y)
 ifneq ($(CONFIG_DM_MMC)$(CONFIG_OF_CONTROL)$(CONFIG_BLK),yyy)
-	@echo "===================== WARNING ======================"
-	@echo "This board does not use CONFIG_DM_MMC. Please update"
-	@echo "the board to use CONFIG_DM_MMC before the v2019.04 release."
-	@echo "Failure to update by the deadline may result in board removal."
-	@echo "See doc/driver-model/MIGRATION.txt for more info."
-	@echo "===================================================="
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "This board does not use CONFIG_DM_MMC. Please update"
+	@echo >&2 "the board to use CONFIG_DM_MMC before the v2019.04 release."
+	@echo >&2 "Failure to update by the deadline may result in board removal."
+	@echo >&2 "See doc/driver-model/MIGRATION.txt for more info."
+	@echo >&2 "===================================================="
 endif
 endif
 ifeq ($(CONFIG_USB),y)
 ifneq ($(CONFIG_DM_USB)$(CONFIG_OF_CONTROL)$(CONFIG_BLK),yyy)
-	@echo "===================== WARNING ======================"
-	@echo "This board does not use CONFIG_DM_USB. Please update"
-	@echo "the board to use CONFIG_DM_USB before the v2019.07 release."
-	@echo "Failure to update by the deadline may result in board removal."
-	@echo "See doc/driver-model/MIGRATION.txt for more info."
-	@echo "===================================================="
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "This board does not use CONFIG_DM_USB. Please update"
+	@echo >&2 "the board to use CONFIG_DM_USB before the v2019.07 release."
+	@echo >&2 "Failure to update by the deadline may result in board removal."
+	@echo >&2 "See doc/driver-model/MIGRATION.txt for more info."
+	@echo >&2 "===================================================="
 endif
 endif
 ifeq ($(CONFIG_LIBATA)$(CONFIG_DM_SCSI)$(CONFIG_MVSATA_IDE),y)
-	@echo "===================== WARNING ======================"
-	@echo "This board does not use CONFIG_DM_SCSI. Please update"
-	@echo "the storage controller to use CONFIG_DM_SCSI before the v2019.07 release."
-	@echo "Failure to update by the deadline may result in board removal."
-	@echo "See doc/driver-model/MIGRATION.txt for more info."
-	@echo "===================================================="
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "This board does not use CONFIG_DM_SCSI. Please update"
+	@echo >&2 "the storage controller to use CONFIG_DM_SCSI before the v2019.07 release."
+	@echo >&2 "Failure to update by the deadline may result in board removal."
+	@echo >&2 "See doc/driver-model/MIGRATION.txt for more info."
+	@echo >&2 "===================================================="
 endif
 ifeq ($(CONFIG_OF_EMBED),y)
-	@echo "===================== WARNING ======================"
-	@echo "CONFIG_OF_EMBED is enabled. This option should only"
-	@echo "be used for debugging purposes. Please use"
-	@echo "CONFIG_OF_SEPARATE for boards in mainline."
-	@echo "See doc/README.fdt-control for more info."
-	@echo "===================================================="
+	@echo >&2 "===================== WARNING ======================"
+	@echo >&2 "CONFIG_OF_EMBED is enabled. This option should only"
+	@echo >&2 "be used for debugging purposes. Please use"
+	@echo >&2 "CONFIG_OF_SEPARATE for boards in mainline."
+	@echo >&2 "See doc/README.fdt-control for more info."
+	@echo >&2 "===================================================="
 endif
 	@# Check that this build does not use CONFIG options that we do not
 	@# know about unless they are in Kconfig. All the existing CONFIG
diff --git a/api/api_storage.c b/api/api_storage.c
index 8aeeda2..2b90c18 100644
--- a/api/api_storage.c
+++ b/api/api_storage.c
@@ -99,6 +99,7 @@
 {
 	struct blk_desc *dd;
 	int found = 0;
+	int found_last = 0;
 	int i = 0;
 
 	/* Wasn't configured for this type, return 0 directly */
@@ -111,9 +112,13 @@
 			if (di->cookie ==
 			    (void *)blk_get_dev(specs[type].name, i)) {
 				i += 1;
+				found_last = 1;
 				break;
 			}
 		}
+
+		if (!found_last)
+			i = 0;
 	}
 
 	for (; i < specs[type].max_dev; i++) {
diff --git a/arch/Kconfig b/arch/Kconfig
index 947070f..35e2712 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -116,6 +116,7 @@
 	imply VIRTIO_SANDBOX
 	imply VIRTIO_BLK
 	imply VIRTIO_NET
+	imply DM_SOUND
 
 config SH
 	bool "SuperH architecture"
diff --git a/arch/arm/dts/Makefile b/arch/arm/dts/Makefile
index ad494ec..dda4e59 100644
--- a/arch/arm/dts/Makefile
+++ b/arch/arm/dts/Makefile
@@ -53,6 +53,7 @@
 	rk3399-puma-ddr1600.dtb \
 	rk3399-puma-ddr1866.dtb \
 	rk3399-rock960.dtb \
+	rv1108-elgin-r1.dtb \
 	rv1108-evb.dtb
 dtb-$(CONFIG_ARCH_MESON) += \
 	meson-gxbb-nanopi-k2.dtb \
diff --git a/arch/arm/dts/am4372-generic-u-boot.dtsi b/arch/arm/dts/am4372-generic-u-boot.dtsi
index d485679..6ba5c16 100644
--- a/arch/arm/dts/am4372-generic-u-boot.dtsi
+++ b/arch/arm/dts/am4372-generic-u-boot.dtsi
@@ -3,6 +3,8 @@
  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  */
 
+#include "am4372-u-boot.dtsi"
+
 /{
 	ocp {
 		u-boot,dm-pre-reloc;
diff --git a/arch/arm/dts/am4372-u-boot.dtsi b/arch/arm/dts/am4372-u-boot.dtsi
new file mode 100644
index 0000000..99922ca
--- /dev/null
+++ b/arch/arm/dts/am4372-u-boot.dtsi
@@ -0,0 +1,40 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+&am43xx_control_usb2phy1 {
+	compatible = "ti,control-phy-usb2-am437", "syscon";
+};
+
+&am43xx_control_usb2phy2 {
+	compatible = "ti,control-phy-usb2-am437", "syscon";
+};
+
+&ocp2scp0 {
+	compatible = "ti,am437x-ocp2scp", "ti,omap-ocp2scp", "simple-bus";
+};
+
+&ocp2scp1 {
+	compatible = "ti,am437x-ocp2scp", "ti,omap-ocp2scp", "simple-bus";
+};
+
+&dwc3_1 {
+	u-boot,dm-spl;
+};
+
+&usb1 {
+	u-boot,dm-spl;
+};
+
+&usb2_phy1 {
+	u-boot,dm-spl;
+};
+
+&am43xx_control_usb2phy1 {
+	u-boot,dm-spl;
+};
+
+&ocp2scp0 {
+	u-boot,dm-spl;
+};
diff --git a/arch/arm/dts/am437x-gp-evm-u-boot.dtsi b/arch/arm/dts/am437x-gp-evm-u-boot.dtsi
index 03a1c1d..d950d32 100644
--- a/arch/arm/dts/am437x-gp-evm-u-boot.dtsi
+++ b/arch/arm/dts/am437x-gp-evm-u-boot.dtsi
@@ -7,6 +7,8 @@
  * Based on "dra7.dtsi"
  */
 
+#include "am4372-u-boot.dtsi"
+
 /{
 	ocp {
 		u-boot,dm-spl;
diff --git a/arch/arm/dts/am437x-idk-evm-u-boot.dtsi b/arch/arm/dts/am437x-idk-evm-u-boot.dtsi
index 0a3d79a..3aa9195 100644
--- a/arch/arm/dts/am437x-idk-evm-u-boot.dtsi
+++ b/arch/arm/dts/am437x-idk-evm-u-boot.dtsi
@@ -3,6 +3,8 @@
  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  */
 
+#include "am4372-u-boot.dtsi"
+
 /{
 	ocp {
 		u-boot,dm-spl;
diff --git a/arch/arm/dts/am437x-sk-evm-u-boot.dtsi b/arch/arm/dts/am437x-sk-evm-u-boot.dtsi
index 0a3d79a..3aa9195 100644
--- a/arch/arm/dts/am437x-sk-evm-u-boot.dtsi
+++ b/arch/arm/dts/am437x-sk-evm-u-boot.dtsi
@@ -3,6 +3,8 @@
  * Copyright (C) 2018 Texas Instruments Incorporated - http://www.ti.com/
  */
 
+#include "am4372-u-boot.dtsi"
+
 /{
 	ocp {
 		u-boot,dm-spl;
diff --git a/arch/arm/dts/exynos5250-smdk5250.dts b/arch/arm/dts/exynos5250-smdk5250.dts
index 8b69544..e542a79 100644
--- a/arch/arm/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/dts/exynos5250-smdk5250.dts
@@ -60,9 +60,26 @@
 	};
 
 	i2c@12C70000 {
-		soundcodec@1a {
+		wm8994: soundcodec@1a {
 			reg = <0x1a>;
-			compatible = "wolfson,wm8994-codec";
+			u-boot,i2c-offset-len = <2>;
+			compatible = "wolfson,wm8994";
+			#sound-dai-cells = <1>;
+		};
+	};
+
+	sound {
+		compatible = "google,smdk5250-audio-wm8994";
+
+		samsung,model = "SMDK5250-I2S-WM8994";
+		samsung,audio-codec = <&wm8994>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&wm8994 0>;
 		};
 	};
 
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index 29c13c1..7587dc0 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -40,7 +40,6 @@
 		mmc3 = "/mmc@12230000";
 		serial0 = "/serial@12C30000";
 		console = "/serial@12C30000";
-		i2s = "/sound@3830000";
 	};
 
         memory {
@@ -88,7 +87,7 @@
 
 		ro-boot {
 			label = "u-boot";
-			reg = <0x6000 0x9a000>;
+			reg = <0x6000 0xb0000>;
 			read-only;
 			type = "blob boot,dtb";
 			required;
@@ -214,9 +213,10 @@
 			};
 		};
 
-		soundcodec@22 {
-			reg = <0x22>;
-			compatible = "maxim,max98095-codec";
+		max98095: codec@11 {
+			compatible = "maxim,max98095";
+			reg = <0x11>;
+			#sound-dai-cells = <1>;
 		};
 	};
 
@@ -273,9 +273,20 @@
 		};
 	};
 
-	sound@3830000 {
-		samsung,codec-type = "max98095";
+	sound {
+		compatible = "google,snow-audio-max98095";
+
+		samsung,model = "Snow-I2S-MAX98095";
+		samsung,audio-codec = <&max98095>;
 		codec-enable-gpio = <&gpx1 7 GPIO_ACTIVE_HIGH>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98095 0>;
+		};
 	};
 
 	sound@12d60000 {
diff --git a/arch/arm/dts/exynos5250-spring.dts b/arch/arm/dts/exynos5250-spring.dts
index 7633d36..191e12a 100644
--- a/arch/arm/dts/exynos5250-spring.dts
+++ b/arch/arm/dts/exynos5250-spring.dts
@@ -34,7 +34,6 @@
 		mmc0 = "/mmc@12200000";
 		serial0 = "/serial@12C30000";
 		console = "/serial@12C30000";
-		i2s = "/sound@3830000";
 	};
 
 	memory {
@@ -639,10 +638,27 @@
 		};
 	};
 
-	soundcodec@20 {
-		reg = <0x20>;
-		compatible = "maxim,max98088-codec";
+	max98095: soundcodec@10 {
+		reg = <0x10>;
+		compatible = "maxim,max98095";
+		#sound-dai-cells = <1>;
 	};
+
+	sound {
+		compatible = "google,spring-audio-max98095";
+
+		samsung,model = "Spring-I2S-MAX98095";
+		samsung,audio-codec = <&max98095>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98095 0>;
+		};
+	};
+
 };
 
 #include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/dts/exynos5250.dtsi b/arch/arm/dts/exynos5250.dtsi
index 502c687..66c5b6d 100644
--- a/arch/arm/dts/exynos5250.dtsi
+++ b/arch/arm/dts/exynos5250.dtsi
@@ -78,9 +78,12 @@
 		#size-cells = <0>;
 	};
 
-	sound@3830000 {
-		compatible = "samsung,exynos-sound";
-		reg = <0x3830000 0x50>;
+	i2s0: i2s@3830000 {
+		compatible = "samsung,s5pv210-i2s";
+		reg = <0x03830000 0x100>;
+		samsung,idma-addr = <0x03000000>;
+		#clock-cells = <1>;
+		#sound-dai-cells = <1>;
 		samsung,i2s-epll-clock-frequency = <192000000>;
 		samsung,i2s-sampling-rate = <48000>;
 		samsung,i2s-bits-per-sample = <16>;
@@ -90,9 +93,11 @@
 		samsung,i2s-id = <0>;
 	};
 
-	sound@12d60000 {
-		compatible = "samsung,exynos-sound";
+	i2s1: i2s@12d60000 {
+		compatible = "samsung,s5pv210-i2s";
 		reg = <0x12d60000 0x20>;
+		#clock-cells = <1>;
+		#sound-dai-cells = <1>;
 		samsung,i2s-epll-clock-frequency = <192000000>;
 		samsung,i2s-sampling-rate = <48000>;
 		samsung,i2s-bits-per-sample = <16>;
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index c86f9d9..4a96a18 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -67,12 +67,28 @@
 		};
 	};
 
+	sound {
+		compatible = "google,peach-audio-max98090";
+
+		samsung,model = "PEACH-I2S-MAX98090";
+		samsung,audio-codec = <&max98090>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98090 0>;
+		};
+	};
+
 	i2c@12CD0000 { /* i2c7 */
 		clock-frequency = <100000>;
-	       soundcodec@20 {
-	              reg = <0x20>;
-	              compatible = "maxim,max98090-codec";
-	       };
+		max98090: soundcodec@10 {
+			reg = <0x10>;
+			compatible = "maxim,max98090";
+			#sound-dai-cells = <1>;
+		};
 
 		edp-lvds-bridge@48 {
 			compatible = "parade,ps8625";
diff --git a/arch/arm/dts/exynos5420-smdk5420.dts b/arch/arm/dts/exynos5420-smdk5420.dts
index cab5ddb..7a5da67 100644
--- a/arch/arm/dts/exynos5420-smdk5420.dts
+++ b/arch/arm/dts/exynos5420-smdk5420.dts
@@ -82,9 +82,26 @@
 	};
 
 	i2c@12C70000 {
-		soundcodec@1a {
+		wm8994: soundcodec@1a {
 			reg = <0x1a>;
-			compatible = "wolfson,wm8994-codec";
+			u-boot,i2c-offset-len = <2>;
+			compatible = "wolfson,wm8994";
+			#sound-dai-cells = <1>;
+		};
+	};
+
+	sound {
+		compatible = "samsung,smdk5420-audio-wm8994";
+
+		samsung,model = "Snow-I2S-MAX98095";
+		samsung,audio-codec = <&wm8994>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&wm8994 0>;
 		};
 	};
 
diff --git a/arch/arm/dts/exynos54xx.dtsi b/arch/arm/dts/exynos54xx.dtsi
index 09bef56..221da8b 100644
--- a/arch/arm/dts/exynos54xx.dtsi
+++ b/arch/arm/dts/exynos54xx.dtsi
@@ -104,6 +104,20 @@
 		interrupts = <0 203 0>;
 	};
 
+	i2s0: i2s@3830000 {
+		compatible = "samsung,s5pv210-i2s";
+		reg = <0x03830000 0x100>;
+		#sound-dai-cells = <1>;
+		samsung,idma-addr = <0x03000000>;
+		samsung,i2s-epll-clock-frequency = <192000000>;
+		samsung,i2s-sampling-rate = <48000>;
+		samsung,i2s-bits-per-sample = <16>;
+		samsung,i2s-channels = <2>;
+		samsung,i2s-lr-clk-framesize = <256>;
+		samsung,i2s-bit-clk-framesize = <32>;
+		samsung,i2s-id = <0>;
+	};
+
 	mmc@12200000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index 7498519..63c0b18 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -79,12 +79,28 @@
 		};
 	};
 
+	sound {
+		compatible = "google,peach-audio-max98090";
+
+		samsung,model = "PEACH-I2S-MAX98090";
+		samsung,audio-codec = <&max98090>;
+
+		cpu {
+			sound-dai = <&i2s0 0>;
+		};
+
+		codec {
+			sound-dai = <&max98090 0>;
+		};
+	};
+
 	i2c@12CD0000 { /* i2c7 */
 		clock-frequency = <100000>;
-	       soundcodec@20 {
-	              reg = <0x20>;
-	              compatible = "maxim,max98090-codec";
-	       };
+		max98090: soundcodec@10 {
+			reg = <0x10>;
+			compatible = "maxim,max98090";
+			#sound-dai-cells = <1>;
+		};
 	};
 
         sound@3830000 {
diff --git a/arch/arm/dts/hi3798cv200-u-boot.dtsi b/arch/arm/dts/hi3798cv200-u-boot.dtsi
index 709ae1c..7844c52 100644
--- a/arch/arm/dts/hi3798cv200-u-boot.dtsi
+++ b/arch/arm/dts/hi3798cv200-u-boot.dtsi
@@ -17,12 +17,6 @@
 };
 
 &uart0 {
-	status = "disabled";
+	clock = <75000000>;
+	status = "okay";
 };
-
-/{
-	chosen {
-		stdout-path = "";
-	};
-};
-
diff --git a/arch/arm/dts/keystone-k2g-evm.dts b/arch/arm/dts/keystone-k2g-evm.dts
index ad746c7..6c9de25 100644
--- a/arch/arm/dts/keystone-k2g-evm.dts
+++ b/arch/arm/dts/keystone-k2g-evm.dts
@@ -33,6 +33,34 @@
 	};
 };
 
+&keystone_usb0 {
+	status = "okay";
+};
+
+&usb0_phy {
+	status = "okay";
+	compatible = "nop-phy";
+};
+
+&usb0 {
+	dr_mode = "host";
+	status = "okay";
+};
+
+&keystone_usb1 {
+	status = "okay";
+};
+
+&usb1_phy {
+	compatible = "nop-phy";
+	status = "okay";
+};
+
+&usb1 {
+	dr_mode = "peripheral";
+	status = "okay";
+};
+
 &gbe0 {
 	phy-handle = <&ethphy0>;
 };
diff --git a/arch/arm/dts/keystone-k2g.dtsi b/arch/arm/dts/keystone-k2g.dtsi
index bbbb987..ede7118 100644
--- a/arch/arm/dts/keystone-k2g.dtsi
+++ b/arch/arm/dts/keystone-k2g.dtsi
@@ -201,5 +201,61 @@
 			status = "disabled";
 			clock-names = "fck";
 		};
+
+		usb0_phy: usb-phy@0 {
+			compatible = "usb-nop-xceiv";
+			status = "disabled";
+		};
+
+		keystone_usb0: keystone-dwc3@2680000 {
+			compatible = "ti,keystone-dwc3";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x2680000 0x10000>;
+			interrupts = <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>;
+			ranges;
+			dma-coherent;
+			dma-ranges;
+			status = "disabled";
+			/*power-domains = <&k2g_pds 0x0016>;*/
+
+			usb0: usb@2690000 {
+				compatible = "snps,dwc3";
+				reg = <0x2690000 0x10000>;
+				interrupts = <GIC_SPI 128 IRQ_TYPE_EDGE_RISING>;
+				maximum-speed = "high-speed";
+				dr_mode = "otg";
+				/*usb-phy = <&usb0_phy>;*/
+				status = "disabled";
+			};
+		};
+
+		usb1_phy: usb-phy@1 {
+			compatible = "usb-nop-xceiv";
+			status = "disabled";
+		};
+
+		keystone_usb1: keystone-dwc3@2580000 {
+			compatible = "ti,keystone-dwc3";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			reg = <0x2580000 0x10000>;
+			interrupts = <GIC_SPI 144 IRQ_TYPE_EDGE_RISING>;
+			ranges;
+			dma-coherent;
+			dma-ranges;
+			status = "disabled";
+			/*power-domains = <&k2g_pds 0x0017>;*/
+
+			usb1: usb@2590000 {
+				compatible = "snps,dwc3";
+				reg = <0x2590000 0x10000>;
+				interrupts = <GIC_SPI 144 IRQ_TYPE_EDGE_RISING>;
+				maximum-speed = "high-speed";
+				dr_mode = "otg";
+				/*usb-phy = <&usb1_phy>;*/
+				status = "disabled";
+			};
+		};
 	};
 };
diff --git a/arch/arm/dts/meson-axg-s400-u-boot.dtsi b/arch/arm/dts/meson-axg-s400-u-boot.dtsi
new file mode 100644
index 0000000..c46eb3f
--- /dev/null
+++ b/arch/arm/dts/meson-axg-s400-u-boot.dtsi
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2017 Amlogic, Inc. All rights reserved.
+ */
+
+/* wifi module */
+&sd_emmc_b {
+	status = "disabled";
+};
+
+/* emmc storage */
+&sd_emmc_c {
+	status = "okay";
+};
diff --git a/arch/arm/dts/rk3288-evb.dtsi b/arch/arm/dts/rk3288-evb.dtsi
index ce75bd5..04902c0 100644
--- a/arch/arm/dts/rk3288-evb.dtsi
+++ b/arch/arm/dts/rk3288-evb.dtsi
@@ -150,8 +150,6 @@
 	num-slots = <1>;
 	pinctrl-names = "default";
 	pinctrl-0 = <&emmc_clk>, <&emmc_cmd>, <&emmc_pwr>, <&emmc_bus8>;
-	vmmc-supply = <&vcc_io>;
-	vqmmc-supply = <&vcc_flash>;
 	status = "okay";
 };
 
diff --git a/arch/arm/dts/rk3399-puma.dtsi b/arch/arm/dts/rk3399-puma.dtsi
index ba9bb4c..9a61fbb 100644
--- a/arch/arm/dts/rk3399-puma.dtsi
+++ b/arch/arm/dts/rk3399-puma.dtsi
@@ -95,6 +95,8 @@
 		regulator-name = "usbhub_enable";
 		enable-active-low;
 		gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&host_vbus_drv>;
 		regulator-boot-on;
 		regulator-min-microvolt = <3300000>;
 		regulator-max-microvolt = <3300000>;
@@ -146,16 +148,6 @@
 		regulator-always-on;
 	};
 
-	vcc5v0_host: vcc5v0-host-regulator {
-		compatible = "regulator-fixed";
-		enable-active-low;
-		gpio = <&gpio4 RK_PA3 GPIO_ACTIVE_HIGH>;
-		pinctrl-names = "default";
-		pinctrl-0 = <&host_vbus_drv>;
-		regulator-name = "vcc5v0_host";
-		regulator-always-on;
-	};
-
 	vcc5v0_sys: vcc5v0-sys {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc5v0_sys";
diff --git a/arch/arm/dts/rv1108-elgin-r1.dts b/arch/arm/dts/rv1108-elgin-r1.dts
new file mode 100644
index 0000000..32b9594
--- /dev/null
+++ b/arch/arm/dts/rv1108-elgin-r1.dts
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ */
+
+/dts-v1/;
+
+#include "rv1108.dtsi"
+
+/ {
+	model = "Elgin RV1108 R1 board";
+	compatible = "elgin,rv1108-elgin", "rockchip,rv1108";
+
+	memory@60000000 {
+		device_type = "memory";
+		reg = <0x60000000 0x08000000>;
+	};
+
+	chosen {
+		stdout-path = "serial2:1500000n8";
+	};
+};
+
+&emmc {
+	pinctrl-names = "default";
+	pinctrl-0 = <&emmc_clk &emmc_cmd &emmc_bus8>;
+	bus-width = <8>;
+	cap-mmc-highspeed;
+	disable-wp;
+	non-removable;
+	status = "okay";
+};
+
+&u2phy {
+	status = "okay";
+
+	u2phy_otg: otg-port {
+		status = "okay";
+	};
+};
+
+&uart2 {
+	status = "okay";
+};
+
+&usb20_otg {
+	status = "okay";
+};
diff --git a/arch/arm/dts/uniphier-ld11.dtsi b/arch/arm/dts/uniphier-ld11.dtsi
index d63b56e..31ba52b 100644
--- a/arch/arm/dts/uniphier-ld11.dtsi
+++ b/arch/arm/dts/uniphier-ld11.dtsi
@@ -116,6 +116,28 @@
 		#size-cells = <1>;
 		ranges = <0 0 0 0xffffffff>;
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi1: spi@54006100 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006100 0x100>;
+			interrupts = <0 216 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi1>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -432,6 +454,8 @@
 				 <&mio_clk 12>;
 			resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>,
 				 <&mio_rst 12>;
+			phy-names = "usb";
+			phys = <&usb_phy0>;
 			has-transaction-translator;
 		};
 
@@ -446,6 +470,8 @@
 				 <&mio_clk 13>;
 			resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>,
 				 <&mio_rst 13>;
+			phy-names = "usb";
+			phys = <&usb_phy1>;
 			has-transaction-translator;
 		};
 
@@ -460,6 +486,8 @@
 				 <&mio_clk 14>;
 			resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 10>,
 				 <&mio_rst 14>;
+			phy-names = "usb";
+			phys = <&usb_phy2>;
 			has-transaction-translator;
 		};
 
@@ -488,6 +516,27 @@
 			pinctrl: pinctrl {
 				compatible = "socionext,uniphier-ld11-pinctrl";
 			};
+
+			usb-phy {
+				compatible = "socionext,uniphier-ld11-usb2-phy";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				usb_phy0: phy@0 {
+					reg = <0>;
+					#phy-cells = <0>;
+				};
+
+				usb_phy1: phy@1 {
+					reg = <1>;
+					#phy-cells = <0>;
+				};
+
+				usb_phy2: phy@2 {
+					reg = <2>;
+					#phy-cells = <0>;
+				};
+			};
 		};
 
 		soc-glue@5f900000 {
@@ -571,7 +620,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-ld20-global.dts b/arch/arm/dts/uniphier-ld20-global.dts
index 1a5e7c2..9ca692e 100644
--- a/arch/arm/dts/uniphier-ld20-global.dts
+++ b/arch/arm/dts/uniphier-ld20-global.dts
@@ -145,6 +145,10 @@
 	};
 };
 
+&usb {
+	status = "okay";
+};
+
 &nand {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-ld20-ref.dts b/arch/arm/dts/uniphier-ld20-ref.dts
index 440c2e6..406244a 100644
--- a/arch/arm/dts/uniphier-ld20-ref.dts
+++ b/arch/arm/dts/uniphier-ld20-ref.dts
@@ -75,3 +75,7 @@
 		drive-strength = <9>;
 	};
 };
+
+&usb {
+	status = "okay";
+};
diff --git a/arch/arm/dts/uniphier-ld20.dtsi b/arch/arm/dts/uniphier-ld20.dtsi
index 9970497..b9ed613 100644
--- a/arch/arm/dts/uniphier-ld20.dtsi
+++ b/arch/arm/dts/uniphier-ld20.dtsi
@@ -224,6 +224,50 @@
 		#size-cells = <1>;
 		ranges = <0 0 0 0xffffffff>;
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi1: spi@54006100 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006100 0x100>;
+			interrupts = <0 216 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi1>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi2: spi@54006200 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006200 0x100>;
+			interrupts = <0 229 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi2>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi3: spi@54006300 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006300 0x100>;
+			interrupts = <0 230 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi3>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -567,6 +611,50 @@
 			efuse@200 {
 				compatible = "socionext,uniphier-efuse";
 				reg = <0x200 0x68>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				/* USB cells */
+				usb_rterm0: trim@54,4 {
+					reg = <0x54 1>;
+					bits = <4 2>;
+				};
+				usb_rterm1: trim@55,4 {
+					reg = <0x55 1>;
+					bits = <4 2>;
+				};
+				usb_rterm2: trim@58,4 {
+					reg = <0x58 1>;
+					bits = <4 2>;
+				};
+				usb_rterm3: trim@59,4 {
+					reg = <0x59 1>;
+					bits = <4 2>;
+				};
+				usb_sel_t0: trim@54,0 {
+					reg = <0x54 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t1: trim@55,0 {
+					reg = <0x55 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t2: trim@58,0 {
+					reg = <0x58 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t3: trim@59,0 {
+					reg = <0x59 1>;
+					bits = <0 4>;
+				};
+				usb_hs_i0: trim@56,0 {
+					reg = <0x56 1>;
+					bits = <0 4>;
+				};
+				usb_hs_i2: trim@5a,0 {
+					reg = <0x5a 1>;
+					bits = <0 4>;
+				};
 			};
 		};
 
@@ -634,6 +722,157 @@
 			};
 		};
 
+		_usb: usb@65a00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65a00000 0xcd00>;
+			interrupt-names = "host";
+			interrupts = <0 134 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb1>,
+				    <&pinctrl_usb2>, <&pinctrl_usb3>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 14>, <&sys_clk 14>, <&sys_clk 14>;
+			resets = <&usb_rst 15>;
+			phys = <&usb_hsphy0>, <&usb_hsphy1>,
+			       <&usb_hsphy2>, <&usb_hsphy3>,
+			       <&usb_ssphy0>, <&usb_ssphy1>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65b00000 {
+			compatible = "socionext,uniphier-ld20-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65b00000 0x400>;
+
+			usb_rst: reset@0 {
+				compatible = "socionext,uniphier-ld20-usb3-reset";
+				reg = <0x0 0x4>;
+				#reset-cells = <1>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb_vbus0: regulator@100 {
+				compatible = "socionext,uniphier-ld20-usb3-regulator";
+				reg = <0x100 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb_vbus1: regulator@110 {
+				compatible = "socionext,uniphier-ld20-usb3-regulator";
+				reg = <0x110 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb_vbus2: regulator@120 {
+				compatible = "socionext,uniphier-ld20-usb3-regulator";
+				reg = <0x120 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb_vbus3: regulator@130 {
+				compatible = "socionext,uniphier-ld20-usb3-regulator";
+				reg = <0x130 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb_hsphy0: hs-phy@200 {
+				compatible = "socionext,uniphier-ld20-usb3-hsphy";
+				reg = <0x200 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 16>;
+				vbus-supply = <&usb_vbus0>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm0>, <&usb_sel_t0>,
+					      <&usb_hs_i0>;
+			};
+
+			usb_hsphy1: hs-phy@210 {
+				compatible = "socionext,uniphier-ld20-usb3-hsphy";
+				reg = <0x210 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 16>;
+				vbus-supply = <&usb_vbus1>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm1>, <&usb_sel_t1>,
+					      <&usb_hs_i0>;
+			};
+
+			usb_hsphy2: hs-phy@220 {
+				compatible = "socionext,uniphier-ld20-usb3-hsphy";
+				reg = <0x220 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 17>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 17>;
+				vbus-supply = <&usb_vbus2>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm2>, <&usb_sel_t2>,
+					      <&usb_hs_i2>;
+			};
+
+			usb_hsphy3: hs-phy@230 {
+				compatible = "socionext,uniphier-ld20-usb3-hsphy";
+				reg = <0x230 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 17>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 17>;
+				vbus-supply = <&usb_vbus3>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm3>, <&usb_sel_t3>,
+					      <&usb_hs_i2>;
+			};
+
+			usb_ssphy0: ss-phy@300 {
+				compatible = "socionext,uniphier-ld20-usb3-ssphy";
+				reg = <0x300 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 18>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 18>;
+				vbus-supply = <&usb_vbus0>;
+			};
+
+			usb_ssphy1: ss-phy@310 {
+				compatible = "socionext,uniphier-ld20-usb3-ssphy";
+				reg = <0x310 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 19>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 19>;
+				vbus-supply = <&usb_vbus1>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb: usb@65b00000 {
 			compatible = "socionext,uniphier-ld20-dwc3";
 			reg = <0x65b00000 0x1000>;
@@ -660,7 +899,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-ld4.dtsi b/arch/arm/dts/uniphier-ld4.dtsi
index f505f64..b73d594 100644
--- a/arch/arm/dts/uniphier-ld4.dtsi
+++ b/arch/arm/dts/uniphier-ld4.dtsi
@@ -63,6 +63,17 @@
 			cache-level = <2>;
 		};
 
+		spi: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -381,7 +392,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand2cs>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-pinctrl.dtsi b/arch/arm/dts/uniphier-pinctrl.dtsi
index aeb47b0..1fee5ff 100644
--- a/arch/arm/dts/uniphier-pinctrl.dtsi
+++ b/arch/arm/dts/uniphier-pinctrl.dtsi
@@ -131,6 +131,26 @@
 		function = "sd1";
 	};
 
+	pinctrl_spi0: spi0 {
+		groups = "spi0";
+		function = "spi0";
+	};
+
+	pinctrl_spi1: spi1 {
+		groups = "spi1";
+		function = "spi1";
+	};
+
+	pinctrl_spi2: spi2 {
+		groups = "spi2";
+		function = "spi2";
+	};
+
+	pinctrl_spi3: spi3 {
+		groups = "spi3";
+		function = "spi3";
+	};
+
 	pinctrl_system_bus: system-bus {
 		groups = "system_bus", "system_bus_cs1";
 		function = "system_bus";
diff --git a/arch/arm/dts/uniphier-pro4-ace.dts b/arch/arm/dts/uniphier-pro4-ace.dts
index bff90c2..ce8ea7b 100644
--- a/arch/arm/dts/uniphier-pro4-ace.dts
+++ b/arch/arm/dts/uniphier-pro4-ace.dts
@@ -73,11 +73,11 @@
 	status = "okay";
 };
 
-&usb0 {
+&usb2 {
 	status = "okay";
 };
 
-&usb1 {
+&usb3 {
 	status = "okay";
 };
 
@@ -92,10 +92,10 @@
 	};
 };
 
-&usb2 {
+&usb0 {
 	status = "okay";
 };
 
-&usb3 {
+&usb1 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-pro4-sanji.dts b/arch/arm/dts/uniphier-pro4-sanji.dts
index 7f5b957..686dd3a 100644
--- a/arch/arm/dts/uniphier-pro4-sanji.dts
+++ b/arch/arm/dts/uniphier-pro4-sanji.dts
@@ -68,11 +68,11 @@
 	status = "okay";
 };
 
-&usb0 {
+&usb2 {
 	status = "okay";
 };
 
-&usb1 {
+&usb3 {
 	status = "okay";
 };
 
@@ -87,10 +87,10 @@
 	};
 };
 
-&usb2 {
+&usb0 {
 	status = "okay";
 };
 
-&usb3 {
+&usb1 {
 	status = "okay";
 };
diff --git a/arch/arm/dts/uniphier-pro4.dtsi b/arch/arm/dts/uniphier-pro4.dtsi
index 8974844..ef34208 100644
--- a/arch/arm/dts/uniphier-pro4.dtsi
+++ b/arch/arm/dts/uniphier-pro4.dtsi
@@ -71,6 +71,17 @@
 			cache-level = <2>;
 		};
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -317,6 +328,8 @@
 				 <&mio_clk 12>;
 			resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 8>,
 				 <&mio_rst 12>;
+			phy-names = "usb";
+			phys = <&usb_phy0>;
 			has-transaction-translator;
 		};
 
@@ -331,6 +344,8 @@
 				 <&mio_clk 13>;
 			resets = <&sys_rst 8>, <&mio_rst 7>, <&mio_rst 9>,
 				 <&mio_rst 13>;
+			phy-names = "usb";
+			phys = <&usb_phy1>;
 			has-transaction-translator;
 		};
 
@@ -342,6 +357,34 @@
 			pinctrl: pinctrl {
 				compatible = "socionext,uniphier-pro4-pinctrl";
 			};
+
+			usb-phy {
+				compatible = "socionext,uniphier-pro4-usb2-phy";
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				usb_phy0: phy@0 {
+					reg = <0>;
+					#phy-cells = <0>;
+				};
+
+				usb_phy1: phy@1 {
+					reg = <1>;
+					#phy-cells = <0>;
+				};
+
+				usb_phy2: phy@2 {
+					reg = <2>;
+					#phy-cells = <0>;
+					vbus-supply = <&usb0_vbus>;
+				};
+
+				usb_phy3: phy@3 {
+					reg = <3>;
+					#phy-cells = <0>;
+					vbus-supply = <&usb1_vbus>;
+				};
+			};
 		};
 
 		soc-glue@5f900000 {
@@ -434,6 +477,60 @@
 			};
 		};
 
+		_usb0: usb@65a00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65a00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 134 4>, <0 135 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb0>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 12>, <&sys_clk 12>, <&sys_clk 12>;
+			resets = <&usb0_rst 4>;
+			phys = <&usb_phy2>, <&usb0_ssphy>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65b00000 {
+			compatible = "socionext,uniphier-pro4-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65b00000 0x100>;
+
+			usb0_vbus: regulator@0 {
+				compatible = "socionext,uniphier-pro4-usb3-regulator";
+				reg = <0 0x10>;
+				clock-names = "gio", "link";
+				clocks = <&sys_clk 12>, <&sys_clk 14>;
+				reset-names = "gio", "link";
+				resets = <&sys_rst 12>, <&sys_rst 14>;
+			};
+
+			usb0_ssphy: ss-phy@10 {
+				compatible = "socionext,uniphier-pro4-usb3-ssphy";
+				reg = <0x10 0x10>;
+				#phy-cells = <0>;
+				clock-names = "gio", "link";
+				clocks = <&sys_clk 12>, <&sys_clk 14>;
+				reset-names = "gio", "link";
+				resets = <&sys_rst 12>, <&sys_rst 14>;
+				vbus-supply = <&usb0_vbus>;
+			};
+
+			usb0_rst: reset@40 {
+				compatible = "socionext,uniphier-pro4-usb3-reset";
+				reg = <0x40 0x4>;
+				#reset-cells = <1>;
+				clock-names = "gio", "link";
+				clocks = <&sys_clk 12>, <&sys_clk 14>;
+				reset-names = "gio", "link";
+				resets = <&sys_rst 12>, <&sys_rst 14>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb0: usb@65b00000 {
 			compatible = "socionext,uniphier-pro4-dwc3";
 			status = "disabled";
@@ -452,6 +549,49 @@
 			};
 		};
 
+		_usb1: usb@65c00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65c00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 137 4>, <0 138 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb1>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 12>, <&sys_clk 12>, <&sys_clk 12>;
+			resets = <&usb1_rst 4>;
+			phys = <&usb_phy3>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65d00000 {
+			compatible = "socionext,uniphier-pro4-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65d00000 0x100>;
+
+			usb1_vbus: regulator@0 {
+				compatible = "socionext,uniphier-pro4-usb3-regulator";
+				reg = <0 0x10>;
+				clock-names = "gio", "link";
+				clocks = <&sys_clk 12>, <&sys_clk 15>;
+				reset-names = "gio", "link";
+				resets = <&sys_rst 12>, <&sys_rst 15>;
+			};
+
+			usb1_rst: reset@40 {
+				compatible = "socionext,uniphier-pro4-usb3-reset";
+				reg = <0x40 0x4>;
+				#reset-cells = <1>;
+				clock-names = "gio", "link";
+				clocks = <&sys_clk 12>, <&sys_clk 15>;
+				reset-names = "gio", "link";
+				resets = <&sys_rst 12>, <&sys_rst 15>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb1: usb@65d00000 {
 			compatible = "socionext,uniphier-pro4-dwc3";
 			status = "disabled";
@@ -478,7 +618,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-pro5.dtsi b/arch/arm/dts/uniphier-pro5.dtsi
index 6e0ea79..9cad79d 100644
--- a/arch/arm/dts/uniphier-pro5.dtsi
+++ b/arch/arm/dts/uniphier-pro5.dtsi
@@ -156,6 +156,28 @@
 			cache-level = <3>;
 		};
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi1: spi@54006100 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006100 0x100>;
+			interrupts = <0 216 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi1>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -475,7 +497,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand2cs>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 
diff --git a/arch/arm/dts/uniphier-pxs2.dtsi b/arch/arm/dts/uniphier-pxs2.dtsi
index 63c1c2c..fa25ffd 100644
--- a/arch/arm/dts/uniphier-pxs2.dtsi
+++ b/arch/arm/dts/uniphier-pxs2.dtsi
@@ -167,6 +167,28 @@
 			cache-level = <2>;
 		};
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi1: spi@54006100 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006100 0x100>;
+			interrupts = <0 216 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi1>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -557,6 +579,103 @@
 			};
 		};
 
+		_usb0: usb@65a00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65a00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 134 4>, <0 135 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb2>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 14>, <&sys_clk 14>, <&sys_clk 14>;
+			resets = <&usb0_rst 15>;
+			phys = <&usb0_hsphy0>, <&usb0_hsphy1>,
+			       <&usb0_ssphy0>, <&usb0_ssphy1>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65b00000 {
+			compatible = "socionext,uniphier-pxs2-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65b00000 0x400>;
+
+			usb0_rst: reset@0 {
+				compatible = "socionext,uniphier-pxs2-usb3-reset";
+				reg = <0x0 0x4>;
+				#reset-cells = <1>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb0_vbus0: regulator@100 {
+				compatible = "socionext,uniphier-pxs2-usb3-regulator";
+				reg = <0x100 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb0_vbus1: regulator@110 {
+				compatible = "socionext,uniphier-pxs2-usb3-regulator";
+				reg = <0x110 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 14>;
+				reset-names = "link";
+				resets = <&sys_rst 14>;
+			};
+
+			usb0_hsphy0: hs-phy@200 {
+				compatible = "socionext,uniphier-pxs2-usb3-hsphy";
+				reg = <0x200 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 16>;
+				vbus-supply = <&usb0_vbus0>;
+			};
+
+			usb0_hsphy1: hs-phy@210 {
+				compatible = "socionext,uniphier-pxs2-usb3-hsphy";
+				reg = <0x210 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 16>;
+				vbus-supply = <&usb0_vbus1>;
+			};
+
+			usb0_ssphy0: ss-phy@300 {
+				compatible = "socionext,uniphier-pxs2-usb3-ssphy";
+				reg = <0x300 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 17>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 17>;
+				vbus-supply = <&usb0_vbus0>;
+			};
+
+			usb0_ssphy1: ss-phy@310 {
+				compatible = "socionext,uniphier-pxs2-usb3-ssphy";
+				reg = <0x310 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 14>, <&sys_clk 18>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 14>, <&sys_rst 18>;
+				vbus-supply = <&usb0_vbus1>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb0: usb@65b00000 {
 			compatible = "socionext,uniphier-pxs2-dwc3";
 			status = "disabled";
@@ -575,6 +694,91 @@
 			};
 		};
 
+		_usb1: usb@65c00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65c00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 137 4>, <0 138 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb1>, <&pinctrl_usb3>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 15>, <&sys_clk 15>, <&sys_clk 15>;
+			resets = <&usb1_rst 15>;
+			phys = <&usb1_hsphy0>, <&usb1_hsphy1>, <&usb1_ssphy0>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65d00000 {
+			compatible = "socionext,uniphier-pxs2-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65d00000 0x400>;
+
+			usb1_rst: reset@0 {
+				compatible = "socionext,uniphier-pxs2-usb3-reset";
+				reg = <0x0 0x4>;
+				#reset-cells = <1>;
+				clock-names = "link";
+				clocks = <&sys_clk 15>;
+				reset-names = "link";
+				resets = <&sys_rst 15>;
+			};
+
+			usb1_vbus0: regulator@100 {
+				compatible = "socionext,uniphier-pxs2-usb3-regulator";
+				reg = <0x100 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 15>;
+				reset-names = "link";
+				resets = <&sys_rst 15>;
+			};
+
+			usb1_vbus1: regulator@110 {
+				compatible = "socionext,uniphier-pxs2-usb3-regulator";
+				reg = <0x110 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 15>;
+				reset-names = "link";
+				resets = <&sys_rst 15>;
+			};
+
+			usb1_hsphy0: hs-phy@200 {
+				compatible = "socionext,uniphier-pxs2-usb3-hsphy";
+				reg = <0x200 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 15>, <&sys_clk 20>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 15>, <&sys_rst 20>;
+				vbus-supply = <&usb1_vbus0>;
+			};
+
+			usb1_hsphy1: hs-phy@210 {
+				compatible = "socionext,uniphier-pxs2-usb3-hsphy";
+				reg = <0x210 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 15>, <&sys_clk 20>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 15>, <&sys_rst 20>;
+				vbus-supply = <&usb1_vbus1>;
+			};
+
+			usb1_ssphy0: ss-phy@300 {
+				compatible = "socionext,uniphier-pxs2-usb3-ssphy";
+				reg = <0x300 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 15>, <&sys_clk 21>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 15>, <&sys_rst 21>;
+				vbus-supply = <&usb1_vbus0>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb1: usb@65d00000 {
 			compatible = "socionext,uniphier-pxs2-dwc3";
 			status = "disabled";
@@ -601,7 +805,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand2cs>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-pxs3.dtsi b/arch/arm/dts/uniphier-pxs3.dtsi
index daf7453..f629c6a 100644
--- a/arch/arm/dts/uniphier-pxs3.dtsi
+++ b/arch/arm/dts/uniphier-pxs3.dtsi
@@ -144,6 +144,28 @@
 		#size-cells = <1>;
 		ranges = <0 0 0 0xffffffff>;
 
+		spi0: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
+		spi1: spi@54006100 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006100 0x100>;
+			interrupts = <0 216 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi1>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -384,6 +406,50 @@
 			efuse@200 {
 				compatible = "socionext,uniphier-efuse";
 				reg = <0x200 0x68>;
+				#address-cells = <1>;
+				#size-cells = <1>;
+
+				/* USB cells */
+				usb_rterm0: trim@54,4 {
+					reg = <0x54 1>;
+					bits = <4 2>;
+				};
+				usb_rterm1: trim@55,4 {
+					reg = <0x55 1>;
+					bits = <4 2>;
+				};
+				usb_rterm2: trim@58,4 {
+					reg = <0x58 1>;
+					bits = <4 2>;
+				};
+				usb_rterm3: trim@59,4 {
+					reg = <0x59 1>;
+					bits = <4 2>;
+				};
+				usb_sel_t0: trim@54,0 {
+					reg = <0x54 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t1: trim@55,0 {
+					reg = <0x55 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t2: trim@58,0 {
+					reg = <0x58 1>;
+					bits = <0 4>;
+				};
+				usb_sel_t3: trim@59,0 {
+					reg = <0x59 1>;
+					bits = <0 4>;
+				};
+				usb_hs_i0: trim@56,0 {
+					reg = <0x56 1>;
+					bits = <0 4>;
+				};
+				usb_hs_i2: trim@5a,0 {
+					reg = <0x5a 1>;
+					bits = <0 4>;
+				};
 			};
 		};
 
@@ -465,6 +531,109 @@
 			};
 		};
 
+		_usb0: usb@65a00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65a00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 134 4>, <0 135 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb0>, <&pinctrl_usb2>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 12>, <&sys_clk 12>, <&sys_clk 12>;
+			resets = <&usb0_rst 15>;
+			phys = <&usb0_hsphy0>, <&usb0_hsphy1>,
+			       <&usb0_ssphy0>, <&usb0_ssphy1>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65b00000 {
+			compatible = "socionext,uniphier-pxs3-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65b00000 0x400>;
+
+			usb0_rst: reset@0 {
+				compatible = "socionext,uniphier-pxs3-usb3-reset";
+				reg = <0x0 0x4>;
+				#reset-cells = <1>;
+				clock-names = "link";
+				clocks = <&sys_clk 12>;
+				reset-names = "link";
+				resets = <&sys_rst 12>;
+			};
+
+			usb0_vbus0: regulator@100 {
+				compatible = "socionext,uniphier-pxs3-usb3-regulator";
+				reg = <0x100 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 12>;
+				reset-names = "link";
+				resets = <&sys_rst 12>;
+			};
+
+			usb0_vbus1: regulator@110 {
+				compatible = "socionext,uniphier-pxs3-usb3-regulator";
+				reg = <0x110 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 12>;
+				reset-names = "link";
+				resets = <&sys_rst 12>;
+			};
+
+			usb0_hsphy0: hs-phy@200 {
+				compatible = "socionext,uniphier-pxs3-usb3-hsphy";
+				reg = <0x200 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 12>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 12>, <&sys_rst 16>;
+				vbus-supply = <&usb0_vbus0>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm0>, <&usb_sel_t0>,
+					      <&usb_hs_i0>;
+			};
+
+			usb0_hsphy1: hs-phy@210 {
+				compatible = "socionext,uniphier-pxs3-usb3-hsphy";
+				reg = <0x210 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 12>, <&sys_clk 16>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 12>, <&sys_rst 16>;
+				vbus-supply = <&usb0_vbus1>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm1>, <&usb_sel_t1>,
+					      <&usb_hs_i0>;
+			};
+
+			usb0_ssphy0: ss-phy@300 {
+				compatible = "socionext,uniphier-pxs3-usb3-ssphy";
+				reg = <0x300 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 12>, <&sys_clk 17>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 12>, <&sys_rst 17>;
+				vbus-supply = <&usb0_vbus0>;
+			};
+
+			usb0_ssphy1: ss-phy@310 {
+				compatible = "socionext,uniphier-pxs3-usb3-ssphy";
+				reg = <0x310 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy";
+				clocks = <&sys_clk 12>, <&sys_clk 18>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 12>, <&sys_rst 18>;
+				vbus-supply = <&usb0_vbus1>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb0: usb@65b00000 {
 			compatible = "socionext,uniphier-pxs3-dwc3";
 			status = "disabled";
@@ -483,6 +652,101 @@
 			};
 		};
 
+		_usb1: usb@65c00000 {
+			compatible = "socionext,uniphier-dwc3", "snps,dwc3";
+			status = "disabled";
+			reg = <0x65c00000 0xcd00>;
+			interrupt-names = "host", "peripheral";
+			interrupts = <0 137 4>, <0 138 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_usb1>, <&pinctrl_usb3>;
+			clock-names = "ref", "bus_early", "suspend";
+			clocks = <&sys_clk 13>, <&sys_clk 13>, <&sys_clk 13>;
+			resets = <&usb1_rst 15>;
+			phys = <&usb1_hsphy0>, <&usb1_hsphy1>,
+			       <&usb1_ssphy0>;
+			dr_mode = "host";
+		};
+
+		usb-glue@65d00000 {
+			compatible = "socionext,uniphier-pxs3-dwc3-glue",
+				     "simple-mfd";
+			#address-cells = <1>;
+			#size-cells = <1>;
+			ranges = <0 0x65d00000 0x400>;
+
+			usb1_rst: reset@0 {
+				compatible = "socionext,uniphier-pxs3-usb3-reset";
+				reg = <0x0 0x4>;
+				#reset-cells = <1>;
+				clock-names = "link";
+				clocks = <&sys_clk 13>;
+				reset-names = "link";
+				resets = <&sys_rst 13>;
+			};
+
+			usb1_vbus0: regulator@100 {
+				compatible = "socionext,uniphier-pxs3-usb3-regulator";
+				reg = <0x100 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 13>;
+				reset-names = "link";
+				resets = <&sys_rst 13>;
+			};
+
+			usb1_vbus1: regulator@110 {
+				compatible = "socionext,uniphier-pxs3-usb3-regulator";
+				reg = <0x110 0x10>;
+				clock-names = "link";
+				clocks = <&sys_clk 13>;
+				reset-names = "link";
+				resets = <&sys_rst 13>;
+			};
+
+			usb1_hsphy0: hs-phy@200 {
+				compatible = "socionext,uniphier-pxs3-usb3-hsphy";
+				reg = <0x200 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy", "phy-ext";
+				clocks = <&sys_clk 13>, <&sys_clk 20>,
+					 <&sys_clk 14>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 13>, <&sys_rst 20>;
+				vbus-supply = <&usb1_vbus0>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm2>, <&usb_sel_t2>,
+					      <&usb_hs_i2>;
+			};
+
+			usb1_hsphy1: hs-phy@210 {
+				compatible = "socionext,uniphier-pxs3-usb3-hsphy";
+				reg = <0x210 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy", "phy-ext";
+				clocks = <&sys_clk 13>, <&sys_clk 20>,
+					 <&sys_clk 14>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 13>, <&sys_rst 20>;
+				vbus-supply = <&usb1_vbus1>;
+				nvmem-cell-names = "rterm", "sel_t", "hs_i";
+				nvmem-cells = <&usb_rterm3>, <&usb_sel_t3>,
+					      <&usb_hs_i2>;
+			};
+
+			usb1_ssphy0: ss-phy@300 {
+				compatible = "socionext,uniphier-pxs3-usb3-ssphy";
+				reg = <0x300 0x10>;
+				#phy-cells = <0>;
+				clock-names = "link", "phy", "phy-ext";
+				clocks = <&sys_clk 13>, <&sys_clk 21>,
+					 <&sys_clk 14>;
+				reset-names = "link", "phy";
+				resets = <&sys_rst 13>, <&sys_rst 21>;
+				vbus-supply = <&usb1_vbus0>;
+			};
+		};
+
+		/* FIXME: U-Boot own node */
 		usb1: usb@65d00000 {
 			compatible = "socionext,uniphier-pxs3-dwc3";
 			status = "disabled";
@@ -509,7 +773,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/dts/uniphier-sld8.dtsi b/arch/arm/dts/uniphier-sld8.dtsi
index 437265b..f7fcf6b 100644
--- a/arch/arm/dts/uniphier-sld8.dtsi
+++ b/arch/arm/dts/uniphier-sld8.dtsi
@@ -63,6 +63,17 @@
 			cache-level = <2>;
 		};
 
+		spi: spi@54006000 {
+			compatible = "socionext,uniphier-scssi";
+			status = "disabled";
+			reg = <0x54006000 0x100>;
+			interrupts = <0 39 4>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_spi0>;
+			clocks = <&peri_clk 11>;
+			resets = <&peri_rst 11>;
+		};
+
 		serial0: serial@54006800 {
 			compatible = "socionext,uniphier-uart";
 			status = "disabled";
@@ -385,7 +396,8 @@
 			interrupts = <0 65 4>;
 			pinctrl-names = "default";
 			pinctrl-0 = <&pinctrl_nand2cs>;
-			clocks = <&sys_clk 2>;
+			clock-names = "nand", "nand_x", "ecc";
+			clocks = <&sys_clk 2>, <&sys_clk 3>, <&sys_clk 3>;
 			resets = <&sys_rst 2>;
 		};
 	};
diff --git a/arch/arm/include/asm/omap_musb.h b/arch/arm/include/asm/omap_musb.h
index 875f100..b40ea00 100644
--- a/arch/arm/include/asm/omap_musb.h
+++ b/arch/arm/include/asm/omap_musb.h
@@ -7,6 +7,7 @@
 
 #ifndef __ASM_ARM_OMAP_MUSB_H
 #define __ASM_ARM_OMAP_MUSB_H
+#include <linux/usb/musb.h>
 
 extern struct musb_platform_ops musb_dsps_ops;
 extern const struct musb_platform_ops am35x_ops;
@@ -21,4 +22,11 @@
 };
 
 enum musb_interface    {MUSB_INTERFACE_ULPI, MUSB_INTERFACE_UTMI};
+
+struct ti_musb_platdata {
+	void *base;
+	void *ctrl_mod_base;
+	struct musb_hdrc_platform_data plat;
+};
+
 #endif /* __ASM_ARM_OMAP_MUSB_H */
diff --git a/arch/arm/mach-exynos/clock.c b/arch/arm/mach-exynos/clock.c
index 6a3cd44..73aa4cd 100644
--- a/arch/arm/mach-exynos/clock.c
+++ b/arch/arm/mach-exynos/clock.c
@@ -345,7 +345,7 @@
 	int i;
 	struct clk_bit_info *info;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422())
+	if (proid_is_exynos542x())
 		info = exynos542x_bit_info;
 	else
 		info = exynos5_bit_info;
@@ -557,7 +557,7 @@
 unsigned long clock_get_periph_rate(int peripheral)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos542x_get_periph_rate(peripheral);
 		return exynos5_get_periph_rate(peripheral);
 	} else {
@@ -1317,6 +1317,19 @@
 	return 0;
 }
 
+static int exynos5420_set_i2s_clk_source(void)
+{
+	struct exynos5420_clock *clk =
+		(struct exynos5420_clock *)samsung_get_base_clock();
+
+	setbits_le32(&clk->src_top6, EXYNOS5420_CLK_SRC_MOUT_EPLL);
+	clrsetbits_le32(&clk->src_mau, EXYNOS5420_AUDIO0_SEL_MASK,
+			(EXYNOS5420_CLK_SRC_SCLK_EPLL));
+	setbits_le32(EXYNOS5_AUDIOSS_BASE, 1 << 0);
+
+	return 0;
+}
+
 int exynos5_set_i2s_clk_source(unsigned int i2s_id)
 {
 	struct exynos5_clock *clk =
@@ -1575,7 +1588,7 @@
 unsigned long get_pll_clk(int pllreg)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos542x_get_pll_clk(pllreg);
 		return exynos5_get_pll_clk(pllreg);
 	} else if (cpu_is_exynos4()) {
@@ -1691,7 +1704,7 @@
 		div -= 1;
 
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			exynos5420_set_mmc_clk(dev_index, div);
 		else
 			exynos5_set_mmc_clk(dev_index, div);
@@ -1739,7 +1752,7 @@
 int set_spi_clk(int periph_id, unsigned int rate)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_set_spi_clk(periph_id, rate);
 		return exynos5_set_spi_clk(periph_id, rate);
 	}
@@ -1758,8 +1771,12 @@
 
 int set_i2s_clk_source(unsigned int i2s_id)
 {
-	if (cpu_is_exynos5())
-		return exynos5_set_i2s_clk_source(i2s_id);
+	if (cpu_is_exynos5()) {
+		if (proid_is_exynos542x())
+			return exynos5420_set_i2s_clk_source();
+		else
+			return exynos5_set_i2s_clk_source(i2s_id);
+	}
 
 	return 0;
 }
diff --git a/arch/arm/mach-exynos/clock_init_exynos5.c b/arch/arm/mach-exynos/clock_init_exynos5.c
index e63ef64..1cb8d39 100644
--- a/arch/arm/mach-exynos/clock_init_exynos5.c
+++ b/arch/arm/mach-exynos/clock_init_exynos5.c
@@ -968,7 +968,7 @@
 
 void system_clock_init(void)
 {
-	if (proid_is_exynos5420() || proid_is_exynos5422())
+	if (proid_is_exynos542x())
 		exynos5420_system_clock_init();
 	else
 		exynos5250_system_clock_init();
diff --git a/arch/arm/mach-exynos/common_setup.h b/arch/arm/mach-exynos/common_setup.h
index 2829fb2..4e3702b 100644
--- a/arch/arm/mach-exynos/common_setup.h
+++ b/arch/arm/mach-exynos/common_setup.h
@@ -78,7 +78,7 @@
 		CACHE_TAG_RAM_LATENCY_2_CYCLES |
 		CACHE_DATA_RAM_LATENCY_2_CYCLES;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422()) {
+	if (proid_is_exynos542x()) {
 		val |= CACHE_ECC_AND_PARITY |
 			CACHE_TAG_RAM_LATENCY_3_CYCLES |
 			CACHE_DATA_RAM_LATENCY_3_CYCLES;
@@ -97,7 +97,7 @@
 {
 	uint32_t val;
 
-	if (proid_is_exynos5420() || proid_is_exynos5422()) {
+	if (proid_is_exynos542x()) {
 		mrc_l2_aux_ctlr(val);
 		val |= CACHE_ENABLE_FORCE_L2_LOGIC |
 			CACHE_DISABLE_CLEAN_EVICT;
diff --git a/arch/arm/mach-exynos/include/mach/clock.h b/arch/arm/mach-exynos/include/mach/clock.h
index edf62bd..e4c706a 100644
--- a/arch/arm/mach-exynos/include/mach/clock.h
+++ b/arch/arm/mach-exynos/include/mach/clock.h
@@ -1370,10 +1370,13 @@
 #define AUDIO_1_RATIO_MASK		0x0f
 
 #define AUDIO0_SEL_MASK			0xf
+#define EXYNOS5420_AUDIO0_SEL_MASK	(0x3 << 28)
 #define AUDIO1_SEL_MASK			0xf
 
 #define CLK_SRC_SCLK_EPLL		0x7
+#define EXYNOS5420_CLK_SRC_SCLK_EPLL	(0x6 << 28)
 #define CLK_SRC_MOUT_EPLL		(1<<12)
+#define EXYNOS5420_CLK_SRC_MOUT_EPLL	BIT(20)
 #define AUDIO_CLKMUX_ASS		(1<<0)
 
 /* CON0 bit-fields */
diff --git a/arch/arm/mach-exynos/include/mach/cpu.h b/arch/arm/mach-exynos/include/mach/cpu.h
index aeb3755..766edee 100644
--- a/arch/arm/mach-exynos/include/mach/cpu.h
+++ b/arch/arm/mach-exynos/include/mach/cpu.h
@@ -268,6 +268,8 @@
 IS_EXYNOS_TYPE(exynos5420, 0x5420)
 IS_EXYNOS_TYPE(exynos5422, 0x5422)
 
+#define proid_is_exynos542x() (proid_is_exynos5420() || proid_is_exynos5422())
+
 #define SAMSUNG_BASE(device, base)				\
 static inline unsigned long __attribute__((no_instrument_function)) \
 	samsung_get_base_##device(void) \
@@ -277,7 +279,7 @@
 			return EXYNOS4X12_##base;		\
 		return EXYNOS4_##base;				\
 	} else if (cpu_is_exynos5()) {				\
-		if (proid_is_exynos5420() || proid_is_exynos5422())	\
+		if (proid_is_exynos542x())			\
 			return EXYNOS5420_##base;		\
 		return EXYNOS5_##base;				\
 	}							\
diff --git a/arch/arm/mach-exynos/include/mach/gpio.h b/arch/arm/mach-exynos/include/mach/gpio.h
index 272e00b..f9975d7 100644
--- a/arch/arm/mach-exynos/include/mach/gpio.h
+++ b/arch/arm/mach-exynos/include/mach/gpio.h
@@ -1397,7 +1397,7 @@
 static inline struct gpio_info *get_gpio_data(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_gpio_data;
 		else
 			return exynos5_gpio_data;
@@ -1414,7 +1414,7 @@
 static inline unsigned int get_bank_num(void)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return EXYNOS5420_GPIO_NUM_PARTS;
 		else
 			return EXYNOS5_GPIO_NUM_PARTS;
diff --git a/arch/arm/mach-exynos/pinmux.c b/arch/arm/mach-exynos/pinmux.c
index f6743ca..b24f1bb 100644
--- a/arch/arm/mach-exynos/pinmux.c
+++ b/arch/arm/mach-exynos/pinmux.c
@@ -378,6 +378,20 @@
 	}
 }
 
+static void exynos5420_i2s_config(int peripheral)
+{
+	int i;
+
+	switch (peripheral) {
+	case PERIPH_ID_I2S0:
+		for (i = 0; i < 5; i++)
+			gpio_cfg_pin(EXYNOS5420_GPIO_Z0 + i,
+				     S5P_GPIO_FUNC(0x02));
+		break;
+	}
+}
+
+
 void exynos5_spi_config(int peripheral)
 {
 	int cfg = 0, pin = 0, i;
@@ -550,6 +564,9 @@
 	case PERIPH_ID_I2C10:
 		exynos5420_i2c_config(peripheral);
 		break;
+	case PERIPH_ID_I2S0:
+		exynos5420_i2s_config(peripheral);
+		break;
 	case PERIPH_ID_PWM0:
 		gpio_cfg_pin(EXYNOS5420_GPIO_B20, S5P_GPIO_FUNC(2));
 		break;
@@ -863,7 +880,7 @@
 int exynos_pinmux_config(int peripheral, int flags)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			return exynos5420_pinmux_config(peripheral, flags);
 		else if (proid_is_exynos5250())
 			return exynos5_pinmux_config(peripheral, flags);
diff --git a/arch/arm/mach-exynos/power.c b/arch/arm/mach-exynos/power.c
index 63c410a..f2a6c00 100644
--- a/arch/arm/mach-exynos/power.c
+++ b/arch/arm/mach-exynos/power.c
@@ -124,7 +124,7 @@
 void set_usbdrd_phy_ctrl(unsigned int enable)
 {
 	if (cpu_is_exynos5()) {
-		if (proid_is_exynos5420() || proid_is_exynos5422())
+		if (proid_is_exynos542x())
 			exynos5420_set_usbdev_phy_ctrl(enable);
 		else
 			exynos5_set_usbdrd_phy_ctrl(enable);
diff --git a/arch/arm/mach-k3/config.mk b/arch/arm/mach-k3/config.mk
index 7fc0b3f..be00d79 100644
--- a/arch/arm/mach-k3/config.mk
+++ b/arch/arm/mach-k3/config.mk
@@ -37,7 +37,7 @@
 ifeq ($(CONFIG_SYS_K3_KEY), "")
 KEY=u-boot-spl-eckey.pem
 else
-KEY=$(patsubst "%",%,$(CONFIG_SYS_K3_KEY))
+KEY=$(patsubst "%",$(srctree)/%,$(CONFIG_SYS_K3_KEY))
 endif
 
 u-boot-spl-eckey.pem: FORCE
diff --git a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
index 90dd4ea..3375796 100644
--- a/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
+++ b/arch/arm/mach-mediatek/mt7629/lowlevel_init.S
@@ -5,6 +5,14 @@
 
 #include <linux/linkage.h>
 
+#define WAIT_CODE_SRAM_BASE	0x0010ff00
+
+#define SLAVE_JUMP_REG		0x10202034
+#define SLAVE1_MAGIC_REG	0x10202038
+#define SLAVE1_MAGIC_NUM	0x534c4131
+
+#define GIC_CPU_BASE		0x10320000
+
 ENTRY(lowlevel_init)
 
 #ifndef CONFIG_SPL_BUILD
@@ -28,6 +36,7 @@
 	mrc	p15, 0, r0, c0, c0, 5
 	ands	r1, r0, #0x40000000
 	bne	go			@ Go if UP
+	/* read slave CPU number */
 	ands	r0, r0, #0x0f
 	beq	go			@ Go if core0 on primary core tile
 	b	secondary
@@ -37,14 +46,41 @@
 	mov	pc, lr
 
 secondary:
-	/* read slave CPU number into r0 firstly */
-	mrc	p15, 0, r0, c0, c0, 5
-	and	r0, r0, #0x0f
+	/* enable GIC as cores will be waken up by IPI */
+	ldr	r2, =GIC_CPU_BASE
+	mov	r1, #0xf0
+	str	r1, [r2, #4]
+	mov	r1, #1
+	str	r1, [r2, #0]
 
-loop:
-	dsb
-	isb
-	wfi				@Zzz...
-	b	loop
+	ldr	r1, [r2]
+	orr	r1, #1
+	str	r1, [r2]
+
+	/* copy wait code into SRAM */
+	ldr	r0, =slave_cpu_wait
+	ldm	r0, {r1 - r8}		@ slave_cpu_wait has eight insns
+	ldr	r0, =WAIT_CODE_SRAM_BASE
+	stm	r0, {r1 - r8}
+
+	/* pass args to slave_cpu_wait */
+	ldr	r0, =SLAVE1_MAGIC_REG
+	ldr	r1, =SLAVE1_MAGIC_NUM
+
+	/* jump to wait code in SRAM */
+	ldr	pc, =WAIT_CODE_SRAM_BASE
+
 #endif
 ENDPROC(lowlevel_init)
+
+/* This function will be copied into SRAM */
+ENTRY(slave_cpu_wait)
+	wfi
+	ldr	r2, [r0]
+	cmp	r2, r1
+	bne	slave_cpu_wait
+	movw	r0, #:lower16:SLAVE_JUMP_REG
+	movt	r0, #:upper16:SLAVE_JUMP_REG
+	ldr	r1, [r0]
+	mov	pc, r1
+ENDPROC(slave_cpu_wait)
diff --git a/arch/arm/mach-mvebu/cpu.c b/arch/arm/mach-mvebu/cpu.c
index aa1be8e..919d05c 100644
--- a/arch/arm/mach-mvebu/cpu.c
+++ b/arch/arm/mach-mvebu/cpu.c
@@ -283,10 +283,8 @@
  * and sets the correct windows sizes and base addresses accordingly.
  *
  * These values are set in the scratch registers by the Marvell
- * DDR3 training code, which is executed by the BootROM before the
- * main payload (U-Boot) is executed. This training code is currently
- * only available in the Marvell U-Boot version. It needs to be
- * ported to mainline U-Boot SPL at some point.
+ * DDR3 training code, which is executed by the SPL before the
+ * main payload (U-Boot) is executed.
  */
 static void update_sdram_window_sizes(void)
 {
diff --git a/arch/arm/mach-omap2/am33xx/board.c b/arch/arm/mach-omap2/am33xx/board.c
index 2fc364d..62158a9 100644
--- a/arch/arm/mach-omap2/am33xx/board.c
+++ b/arch/arm/mach-omap2/am33xx/board.c
@@ -174,7 +174,55 @@
 /* AM33XX has two MUSB controllers which can be host or gadget */
 #if (defined(CONFIG_USB_MUSB_GADGET) || defined(CONFIG_USB_MUSB_HOST)) && \
 	(defined(CONFIG_AM335X_USB0) || defined(CONFIG_AM335X_USB1)) && \
-	(!defined(CONFIG_DM_USB))
+	(!CONFIG_IS_ENABLED(DM_USB) || !CONFIG_IS_ENABLED(OF_CONTROL)) && \
+	(!defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_MUSB_NEW_SUPPORT))
+
+static struct musb_hdrc_config musb_config = {
+	.multipoint     = 1,
+	.dyn_fifo       = 1,
+	.num_eps        = 16,
+	.ram_bits       = 12,
+};
+
+#if CONFIG_IS_ENABLED(DM_USB) && !CONFIG_IS_ENABLED(OF_CONTROL)
+static struct ti_musb_platdata usb0 = {
+	.base = (void *)USB0_OTG_BASE,
+	.ctrl_mod_base = &((struct ctrl_dev *)CTRL_DEVICE_BASE)->usb_ctrl0,
+	.plat = {
+		.config         = &musb_config,
+		.power          = 50,
+		.platform_ops	= &musb_dsps_ops,
+		},
+};
+
+static struct ti_musb_platdata usb1 = {
+	.base = (void *)USB1_OTG_BASE,
+	.ctrl_mod_base = &((struct ctrl_dev *)CTRL_DEVICE_BASE)->usb_ctrl1,
+	.plat = {
+		.config         = &musb_config,
+		.power          = 50,
+		.platform_ops	= &musb_dsps_ops,
+		},
+};
+
+U_BOOT_DEVICES(am33xx_usbs) = {
+#if CONFIG_AM335X_USB0_MODE == MUSB_PERIPHERAL
+	{ "ti-musb-peripheral", &usb0 },
+#elif CONFIG_AM335X_USB0_MODE == MUSB_HOST
+	{ "ti-musb-host", &usb0 },
+#endif
+#if CONFIG_AM335X_USB1_MODE == MUSB_PERIPHERAL
+	{ "ti-musb-peripheral", &usb1 },
+#elif CONFIG_AM335X_USB1_MODE == MUSB_HOST
+	{ "ti-musb-host", &usb1 },
+#endif
+};
+
+int arch_misc_init(void)
+{
+	return 0;
+}
+#else
 static struct ctrl_dev *cdev = (struct ctrl_dev *)CTRL_DEVICE_BASE;
 
 /* USB 2.0 PHY Control */
@@ -193,13 +241,6 @@
 	}
 }
 
-static struct musb_hdrc_config musb_config = {
-	.multipoint     = 1,
-	.dyn_fifo       = 1,
-	.num_eps        = 16,
-	.ram_bits       = 12,
-};
-
 #ifdef CONFIG_AM335X_USB0
 static void am33xx_otg0_set_phy_power(struct udevice *dev, u8 on)
 {
@@ -250,6 +291,7 @@
 #endif
 	return 0;
 }
+#endif
 
 #else	/* CONFIG_USB_MUSB_* && CONFIG_AM335X_USB* && !CONFIG_DM_USB */
 
diff --git a/arch/arm/mach-omap2/omap3/Kconfig b/arch/arm/mach-omap2/omap3/Kconfig
index e0d02fb..0286b0d 100644
--- a/arch/arm/mach-omap2/omap3/Kconfig
+++ b/arch/arm/mach-omap2/omap3/Kconfig
@@ -3,18 +3,23 @@
 # We only enable the clocks for the GPIO banks that a given board requies.
 config OMAP3_GPIO_2
 	bool
+	default y if CMD_GPIO
 
 config OMAP3_GPIO_3
 	bool
+	default y if CMD_GPIO
 
 config OMAP3_GPIO_4
 	bool
+	default y if CMD_GPIO
 
 config OMAP3_GPIO_5
 	bool
+	default y if CMD_GPIO
 
 config OMAP3_GPIO_6
 	bool
+	default y if CMD_GPIO
 
 choice
 	prompt "OMAP3 board select"
diff --git a/arch/arm/mach-omap2/omap3/clock.c b/arch/arm/mach-omap2/omap3/clock.c
index 9a03bfa..cb9e91e 100644
--- a/arch/arm/mach-omap2/omap3/clock.c
+++ b/arch/arm/mach-omap2/omap3/clock.c
@@ -750,23 +750,23 @@
 	setbits_le32(&prcm_base->iclken_per, 0x00000800);
 #endif
 
-#if (CONFIG_IS_ENABLED(OMAP3_GPIO_2) || CONFIG_IS_ENABLED(CMD_GPIO))
+#if defined(CONFIG_OMAP3_GPIO_2)
 	setbits_le32(&prcm_base->fclken_per, 0x00002000);
 	setbits_le32(&prcm_base->iclken_per, 0x00002000);
 #endif
-#if (CONFIG_IS_ENABLED(OMAP3_GPIO_3) || CONFIG_IS_ENABLED(CMD_GPIO))
+#if defined(CONFIG_OMAP3_GPIO_3)
 	setbits_le32(&prcm_base->fclken_per, 0x00004000);
 	setbits_le32(&prcm_base->iclken_per, 0x00004000);
 #endif
-#if (CONFIG_IS_ENABLED(OMAP3_GPIO_4) || CONFIG_IS_ENABLED(CMD_GPIO))
+#if defined(CONFIG_OMAP3_GPIO_4)
 	setbits_le32(&prcm_base->fclken_per, 0x00008000);
 	setbits_le32(&prcm_base->iclken_per, 0x00008000);
 #endif
-#if (CONFIG_IS_ENABLED(OMAP3_GPIO_5) || CONFIG_IS_ENABLED(CMD_GPIO))
+#if defined(CONFIG_OMAP3_GPIO_5)
 	setbits_le32(&prcm_base->fclken_per, 0x00010000);
 	setbits_le32(&prcm_base->iclken_per, 0x00010000);
 #endif
-#if (CONFIG_IS_ENABLED(OMAP3_GPIO_6) || CONFIG_IS_ENABLED(CMD_GPIO))
+#if defined(CONFIG_OMAP3_GPIO_6)
 	setbits_le32(&prcm_base->fclken_per, 0x00020000);
 	setbits_le32(&prcm_base->iclken_per, 0x00020000);
 #endif
diff --git a/arch/arm/mach-rockchip/rv1108/Kconfig b/arch/arm/mach-rockchip/rv1108/Kconfig
index e6cba66..8883aea 100644
--- a/arch/arm/mach-rockchip/rv1108/Kconfig
+++ b/arch/arm/mach-rockchip/rv1108/Kconfig
@@ -17,6 +17,11 @@
 	   * 10/100 Mbps Ethernet
 	   * camera interface compatible with imx323 / ov2710 / ov4689
 
+config TARGET_ELGIN_RV1108
+	bool "ELGIN_RV1108"
+	help
+	  RV1108 ELGIN is a board based on the Rockchip RV1108.
+
 config SYS_SOC
 	default "rockchip"
 
@@ -24,5 +29,6 @@
 	default 0x400
 
 source board/rockchip/evb_rv1108/Kconfig
+source board/elgin/elgin_rv1108/Kconfig
 
 endif
diff --git a/arch/arm/mach-socfpga/Kconfig b/arch/arm/mach-socfpga/Kconfig
index 06f8527..5e87371 100644
--- a/arch/arm/mach-socfpga/Kconfig
+++ b/arch/arm/mach-socfpga/Kconfig
@@ -35,6 +35,7 @@
 	select ARMV8_MULTIENTRY
 	select ARMV8_SET_SMPEN
 	select ARMV8_SPIN_TABLE
+	select FPGA_STRATIX10
 
 choice
 	prompt "Altera SOCFPGA board select"
diff --git a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
index 81a609d..ae728a5 100644
--- a/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
+++ b/arch/arm/mach-socfpga/include/mach/mailbox_s10.h
@@ -107,6 +107,12 @@
 #define RECONFIG_STATUS_PIN_STATUS			2
 #define RECONFIG_STATUS_SOFTFUNC_STATUS			3
 
+/* Macros for specifying number of arguments in mailbox command */
+#define MBOX_NUM_ARGS(n, b)				(((n) & 0xFF) << (b))
+#define MBOX_DIRECT_COUNT(n)				MBOX_NUM_ARGS((n), 0)
+#define MBOX_ARG_DESC_COUNT(n)				MBOX_NUM_ARGS((n), 8)
+#define MBOX_RESP_DESC_COUNT(n)				MBOX_NUM_ARGS((n), 16)
+
 #define MBOX_CFGSTAT_STATE_IDLE				0x00000000
 #define MBOX_CFGSTAT_STATE_CONFIG			0x10000000
 #define MBOX_CFGSTAT_STATE_FAILACK			0x08000000
@@ -140,5 +146,6 @@
 #endif
 
 int mbox_reset_cold(void);
-
+int mbox_get_fpga_config_status(u32 cmd);
+int mbox_get_fpga_config_status_psci(u32 cmd);
 #endif /* _MAILBOX_S10_H_ */
diff --git a/arch/arm/mach-socfpga/include/mach/misc.h b/arch/arm/mach-socfpga/include/mach/misc.h
index 2660992..86d5d2b 100644
--- a/arch/arm/mach-socfpga/include/mach/misc.h
+++ b/arch/arm/mach-socfpga/include/mach/misc.h
@@ -18,9 +18,9 @@
 extern struct bsel bsel_str[];
 
 #ifdef CONFIG_FPGA
-void socfpga_fpga_add(void);
+void socfpga_fpga_add(void *fpga_desc);
 #else
-static inline void socfpga_fpga_add(void) {}
+inline void socfpga_fpga_add(void *fpga_desc) {}
 #endif
 
 #ifdef CONFIG_TARGET_SOCFPGA_GEN5
diff --git a/arch/arm/mach-socfpga/mailbox_s10.c b/arch/arm/mach-socfpga/mailbox_s10.c
index 0d906c3..3c33223 100644
--- a/arch/arm/mach-socfpga/mailbox_s10.c
+++ b/arch/arm/mach-socfpga/mailbox_s10.c
@@ -342,6 +342,54 @@
 	return 0;
 }
 
+/* Accepted commands: CONFIG_STATUS or RECONFIG_STATUS */
+static __always_inline int mbox_get_fpga_config_status_common(u32 cmd)
+{
+	u32 reconfig_status_resp_len;
+	u32 reconfig_status_resp[RECONFIG_STATUS_RESPONSE_LEN];
+	int ret;
+
+	reconfig_status_resp_len = RECONFIG_STATUS_RESPONSE_LEN;
+	ret = mbox_send_cmd_common(MBOX_ID_UBOOT, cmd,
+				   MBOX_CMD_DIRECT, 0, NULL, 0,
+				   &reconfig_status_resp_len,
+				   reconfig_status_resp);
+
+	if (ret)
+		return ret;
+
+	/* Check for any error */
+	ret = reconfig_status_resp[RECONFIG_STATUS_STATE];
+	if (ret && ret != MBOX_CFGSTAT_STATE_CONFIG)
+		return ret;
+
+	/* Make sure nStatus is not 0 */
+	ret = reconfig_status_resp[RECONFIG_STATUS_PIN_STATUS];
+	if (!(ret & RCF_PIN_STATUS_NSTATUS))
+		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+
+	ret = reconfig_status_resp[RECONFIG_STATUS_SOFTFUNC_STATUS];
+	if (ret & RCF_SOFTFUNC_STATUS_SEU_ERROR)
+		return MBOX_CFGSTAT_STATE_ERROR_HARDWARE;
+
+	if ((ret & RCF_SOFTFUNC_STATUS_CONF_DONE) &&
+	    (ret & RCF_SOFTFUNC_STATUS_INIT_DONE) &&
+	    !reconfig_status_resp[RECONFIG_STATUS_STATE])
+		return 0;	/* configuration success */
+
+	return MBOX_CFGSTAT_STATE_CONFIG;
+}
+
+int mbox_get_fpga_config_status(u32 cmd)
+{
+	return mbox_get_fpga_config_status_common(cmd);
+}
+
+int __secure mbox_get_fpga_config_status_psci(u32 cmd)
+{
+	return mbox_get_fpga_config_status_common(cmd);
+}
+
 int mbox_send_cmd(u8 id, u32 cmd, u8 is_indirect, u32 len, u32 *arg,
 		  u8 urgent, u32 *resp_buf_len, u32 *resp_buf)
 {
diff --git a/arch/arm/mach-socfpga/misc.c b/arch/arm/mach-socfpga/misc.c
index a4f6d5c..78fbe28 100644
--- a/arch/arm/mach-socfpga/misc.c
+++ b/arch/arm/mach-socfpga/misc.c
@@ -88,33 +88,11 @@
 #endif
 
 #ifdef CONFIG_FPGA
-/*
- * FPGA programming support for SoC FPGA Cyclone V
- */
-static Altera_desc altera_fpga[] = {
-	{
-		/* Family */
-		Altera_SoCFPGA,
-		/* Interface type */
-		fast_passive_parallel,
-		/* No limitation as additional data will be ignored */
-		-1,
-		/* No device function table */
-		NULL,
-		/* Base interface address specified in driver */
-		NULL,
-		/* No cookie implementation */
-		0
-	},
-};
-
 /* add device descriptor to FPGA device table */
-void socfpga_fpga_add(void)
+void socfpga_fpga_add(void *fpga_desc)
 {
-	int i;
 	fpga_init();
-	for (i = 0; i < ARRAY_SIZE(altera_fpga); i++)
-		fpga_add(fpga_altera, &altera_fpga[i]);
+	fpga_add(fpga_altera, fpga_desc);
 }
 #endif
 
diff --git a/arch/arm/mach-socfpga/misc_arria10.c b/arch/arm/mach-socfpga/misc_arria10.c
index f347ae8..63b8c75 100644
--- a/arch/arm/mach-socfpga/misc_arria10.c
+++ b/arch/arm/mach-socfpga/misc_arria10.c
@@ -30,6 +30,27 @@
 
 static struct socfpga_system_manager *sysmgr_regs =
 	(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
+
+/*
+ * FPGA programming support for SoC FPGA Arria 10
+ */
+static Altera_desc altera_fpga[] = {
+	{
+		/* Family */
+		Altera_SoCFPGA,
+		/* Interface type */
+		fast_passive_parallel,
+		/* No limitation as additional data will be ignored */
+		-1,
+		/* No device function table */
+		NULL,
+		/* Base interface address specified in driver */
+		NULL,
+		/* No cookie implementation */
+		0
+	},
+};
+
 #if defined(CONFIG_SPL_BUILD)
 static struct pl310_regs *const pl310 =
 	(struct pl310_regs *)CONFIG_SYS_PL310_BASE;
@@ -73,7 +94,7 @@
 int arch_early_init_r(void)
 {
 	/* Add device descriptor to FPGA device table */
-	socfpga_fpga_add();
+	socfpga_fpga_add(&altera_fpga[0]);
 
 	return 0;
 }
diff --git a/arch/arm/mach-socfpga/misc_gen5.c b/arch/arm/mach-socfpga/misc_gen5.c
index 5fa4093..04f237d 100644
--- a/arch/arm/mach-socfpga/misc_gen5.c
+++ b/arch/arm/mach-socfpga/misc_gen5.c
@@ -35,6 +35,26 @@
 	(struct scu_registers *)SOCFPGA_MPUSCU_ADDRESS;
 
 /*
+ * FPGA programming support for SoC FPGA Cyclone V
+ */
+static Altera_desc altera_fpga[] = {
+	{
+		/* Family */
+		Altera_SoCFPGA,
+		/* Interface type */
+		fast_passive_parallel,
+		/* No limitation as additional data will be ignored */
+		-1,
+		/* No device function table */
+		NULL,
+		/* Base interface address specified in driver */
+		NULL,
+		/* No cookie implementation */
+		0
+	},
+};
+
+/*
  * DesignWare Ethernet initialization
  */
 #ifdef CONFIG_ETH_DESIGNWARE
@@ -221,7 +241,7 @@
 	socfpga_sdram_remap_zero();
 
 	/* Add device descriptor to FPGA device table */
-	socfpga_fpga_add();
+	socfpga_fpga_add(&altera_fpga[0]);
 
 #ifdef CONFIG_DESIGNWARE_SPI
 	/* Get Designware SPI controller out of reset */
diff --git a/arch/arm/mach-socfpga/misc_s10.c b/arch/arm/mach-socfpga/misc_s10.c
index e599362..113eace 100644
--- a/arch/arm/mach-socfpga/misc_s10.c
+++ b/arch/arm/mach-socfpga/misc_s10.c
@@ -25,6 +25,26 @@
 	(struct socfpga_system_manager *)SOCFPGA_SYSMGR_ADDRESS;
 
 /*
+ * FPGA programming support for SoC FPGA Stratix 10
+ */
+static Altera_desc altera_fpga[] = {
+	{
+		/* Family */
+		Intel_FPGA_Stratix10,
+		/* Interface type */
+		secure_device_manager_mailbox,
+		/* No limitation as additional data will be ignored */
+		-1,
+		/* No device function table */
+		NULL,
+		/* Base interface address specified in driver */
+		NULL,
+		/* No cookie implementation */
+		0
+	},
+};
+
+/*
  * DesignWare Ethernet initialization
  */
 #ifdef CONFIG_ETH_DESIGNWARE
@@ -125,6 +145,8 @@
 
 int arch_early_init_r(void)
 {
+	socfpga_fpga_add(&altera_fpga[0]);
+
 	return 0;
 }
 
diff --git a/arch/arm/mach-uniphier/board_late_init.c b/arch/arm/mach-uniphier/board_late_init.c
index 1b871c6..972dbe8 100644
--- a/arch/arm/mach-uniphier/board_late_init.c
+++ b/arch/arm/mach-uniphier/board_late_init.c
@@ -66,20 +66,20 @@
 	switch (uniphier_boot_device_raw()) {
 	case BOOT_DEVICE_MMC1:
 		printf("eMMC Boot");
-		env_set("bootcmd", "run bootcmd_mmc0; run distro_bootcmd");
+		env_set("bootdev", "emmc");
 		break;
 	case BOOT_DEVICE_NAND:
 		printf("NAND Boot");
-		env_set("bootcmd", "run bootcmd_ubifs0; run distro_bootcmd");
+		env_set("bootdev", "nand");
 		nand_denali_wp_disable();
 		break;
 	case BOOT_DEVICE_NOR:
 		printf("NOR Boot");
-		env_set("bootcmd", "run tftpboot; run distro_bootcmd");
+		env_set("bootdev", "nor");
 		break;
 	case BOOT_DEVICE_USB:
 		printf("USB Boot");
-		env_set("bootcmd", "run bootcmd_usb0; run distro_bootcmd");
+		env_set("bootdev", "usb");
 		break;
 	default:
 		printf("Unknown");
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 1b1b1d7..194f4f3 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -59,6 +59,11 @@
 	select OF_CONTROL
 	imply CMD_DM
 
+config ARCH_MSCC
+	bool "Support MSCC VCore-III"
+	select OF_CONTROL
+	select DM
+
 config ARCH_BMIPS
 	bool "Support BMIPS SoCs"
 	select CLK
@@ -79,7 +84,7 @@
 	select DM_SERIAL
 	imply DM_SPI
 	imply DM_SPI_FLASH
-	select ARCH_MISC_INIT if WATCHDOG
+	select ARCH_MISC_INIT
 	select MIPS_TUNE_24KC
 	select OF_CONTROL
 	select ROM_EXCEPTION_VECTORS
@@ -88,6 +93,12 @@
 	select SUPPORTS_LITTLE_ENDIAN
 	select SYSRESET
 
+config ARCH_JZ47XX
+	bool "Support Ingenic JZ47xx"
+	select SUPPORT_SPL
+	select OF_CONTROL
+	select DM
+
 config MACH_PIC32
 	bool "Support Microchip PIC32"
 	select DM
@@ -138,7 +149,9 @@
 source "board/micronas/vct/Kconfig"
 source "board/qemu-mips/Kconfig"
 source "arch/mips/mach-ath79/Kconfig"
+source "arch/mips/mach-mscc/Kconfig"
 source "arch/mips/mach-bmips/Kconfig"
+source "arch/mips/mach-jz47xx/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
 source "arch/mips/mach-mt7620/Kconfig"
 
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index 802244a..029d290 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -13,8 +13,10 @@
 
 machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_ARCH_BMIPS) += bmips
+machine-$(CONFIG_ARCH_JZ47XX) += jz47xx
 machine-$(CONFIG_MACH_PIC32) += pic32
 machine-$(CONFIG_ARCH_MT7620) += mt7620
+machine-$(CONFIG_ARCH_MSCC) += mscc
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
 libs-y += $(machdirs)
diff --git a/arch/mips/cpu/cpu.c b/arch/mips/cpu/cpu.c
index 5c56ab0..a403ff7 100644
--- a/arch/mips/cpu/cpu.c
+++ b/arch/mips/cpu/cpu.c
@@ -28,16 +28,6 @@
 }
 #endif
 
-void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0, u32 low1)
-{
-	write_c0_entrylo0(low0);
-	write_c0_pagemask(pagemask);
-	write_c0_entrylo1(low1);
-	write_c0_entryhi(hi);
-	write_c0_index(index);
-	tlb_write_indexed();
-}
-
 int arch_cpu_init(void)
 {
 	mips_cache_probe();
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index b447141..647d2bf 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -16,6 +16,7 @@
 dtb-$(CONFIG_BOARD_NETGEAR_DGND3700V2) += netgear,dgnd3700v2.dtb
 dtb-$(CONFIG_BOARD_SAGEM_FAST1704) += sagem,f@st1704.dtb
 dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb
+dtb-$(CONFIG_TARGET_JZ4780_CI20) += ci20.dtb
 
 targets += $(dtb-y)
 
diff --git a/arch/mips/dts/ar933x.dtsi b/arch/mips/dts/ar933x.dtsi
index 85fb14b..3735432 100644
--- a/arch/mips/dts/ar933x.dtsi
+++ b/arch/mips/dts/ar933x.dtsi
@@ -3,7 +3,6 @@
  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
  */
 
-#include <dt-bindings/interrupt-controller/irq.h>
 #include "skeleton.dtsi"
 
 / {
@@ -68,7 +67,6 @@
 			uart0: uart@18020000 {
 				compatible = "qca,ar9330-uart";
 				reg = <0x18020000 0x20>;
-				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
 
 				status = "disabled";
 			};
@@ -103,7 +101,6 @@
 		spi0: spi@1f000000 {
 			compatible = "qca,ar7100-spi";
 			reg = <0x1f000000 0x10>;
-			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
 
 			status = "disabled";
 
diff --git a/arch/mips/dts/brcm,bcm6318.dtsi b/arch/mips/dts/brcm,bcm6318.dtsi
index f75988b..d678dab 100644
--- a/arch/mips/dts/brcm,bcm6318.dtsi
+++ b/arch/mips/dts/brcm,bcm6318.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6318-clock.h>
+#include <dt-bindings/dma/bcm6318-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/power-domain/bcm6318-power-domain.h>
 #include <dt-bindings/reset/bcm6318-reset.h>
@@ -54,6 +55,12 @@
 			reg = <0x10000004 0x4>;
 			#clock-cells = <1>;
 		};
+
+		ubus_clk: ubus-clk {
+			compatible = "brcm,bcm6345-clk";
+			reg = <0x10000008 0x4>;
+			#clock-cells = <1>;
+		};
 	};
 
 	ubus {
@@ -182,5 +189,36 @@
 
 			status = "disabled";
 		};
+
+		enet: ethernet@10080000 {
+			compatible = "brcm,bcm6368-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x10080000 0x8000>;
+			clocks = <&periph_clk BCM6318_CLK_ROBOSW250>,
+				 <&periph_clk BCM6318_CLK_ROBOSW025>,
+				 <&ubus_clk BCM6318_UCLK_ROBOSW>;
+			resets = <&periph_rst BCM6318_RST_ENETSW>,
+				 <&periph_rst BCM6318_RST_EPHY>;
+			dmas = <&iudma BCM6318_DMA_ENETSW_RX>,
+			       <&iudma BCM6318_DMA_ENETSW_TX>;
+			dma-names = "rx",
+				    "tx";
+			brcm,num-ports = <5>;
+
+			status = "disabled";
+		};
+
+		iudma: dma-controller@10088000 {
+			compatible = "brcm,bcm6368-iudma";
+			reg = <0x10088000 0x80>,
+			      <0x10088200 0x80>,
+			      <0x10088400 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm63268.dtsi b/arch/mips/dts/brcm,bcm63268.dtsi
index 62c440e..f8a72ef 100644
--- a/arch/mips/dts/brcm,bcm63268.dtsi
+++ b/arch/mips/dts/brcm,bcm63268.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm63268-clock.h>
+#include <dt-bindings/dma/bcm63268-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/power-domain/bcm63268-power-domain.h>
 #include <dt-bindings/reset/bcm63268-reset.h>
@@ -217,5 +218,42 @@
 			reg = <0x10003000 0x894>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller@1000d800 {
+			compatible = "brcm,bcm6368-iudma";
+			reg = <0x1000d800 0x80>,
+			      <0x1000da00 0x80>,
+			      <0x1000dc00 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+		};
+
+		enet: ethernet@10700000 {
+			compatible = "brcm,bcm6368-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x10700000 0x10000>;
+			clocks = <&periph_clk BCM63268_CLK_GMAC>,
+				 <&periph_clk BCM63268_CLK_ROBOSW>,
+				 <&periph_clk BCM63268_CLK_ROBOSW250>,
+				 <&timer_clk BCM63268_TCLK_EPHY1>,
+				 <&timer_clk BCM63268_TCLK_EPHY2>,
+				 <&timer_clk BCM63268_TCLK_EPHY3>,
+				 <&timer_clk BCM63268_TCLK_GPHY>;
+			resets = <&periph_rst BCM63268_RST_ENETSW>,
+				 <&periph_rst BCM63268_RST_EPHY>,
+				 <&periph_rst BCM63268_RST_GPHY>;
+			dmas = <&iudma BCM63268_DMA_ENETSW_RX>,
+			       <&iudma BCM63268_DMA_ENETSW_TX>;
+			dma-names = "rx",
+				    "tx";
+			brcm,rgmii-override;
+			brcm,rgmii-timing;
+
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6328.dtsi b/arch/mips/dts/brcm,bcm6328.dtsi
index e00a295..50beed4 100644
--- a/arch/mips/dts/brcm,bcm6328.dtsi
+++ b/arch/mips/dts/brcm,bcm6328.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6328-clock.h>
+#include <dt-bindings/dma/bcm6328-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/power-domain/bcm6328-power-domain.h>
 #include <dt-bindings/reset/bcm6328-reset.h>
@@ -187,5 +188,34 @@
 			reg = <0x10003000 0x864>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller@1000d800 {
+			compatible = "brcm,bcm6368-iudma";
+			reg = <0x1000d800 0x80>,
+			      <0x1000da00 0x80>,
+			      <0x1000dc00 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+		};
+
+		enet: ethernet@10e00000 {
+			compatible = "brcm,bcm6368-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x10e00000 0x10000>;
+			clocks = <&periph_clk BCM6328_CLK_ROBOSW>;
+			resets = <&periph_rst BCM6328_RST_ENETSW>,
+				 <&periph_rst BCM6328_RST_EPHY>;
+			dmas = <&iudma BCM6328_DMA_ENETSW_RX>,
+			       <&iudma BCM6328_DMA_ENETSW_TX>;
+			dma-names = "rx",
+				    "tx";
+			brcm,num-ports = <5>;
+
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6338.dtsi b/arch/mips/dts/brcm,bcm6338.dtsi
index bbd58cf..c547e94 100644
--- a/arch/mips/dts/brcm,bcm6338.dtsi
+++ b/arch/mips/dts/brcm,bcm6338.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6338-clock.h>
+#include <dt-bindings/dma/bcm6338-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6338-reset.h>
 #include "skeleton.dtsi"
@@ -130,5 +131,33 @@
 			reg = <0xfffe3100 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller@fffe2400 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe2400 0x1c>,
+			      <0xfffe2500 0x60>,
+			      <0xfffe2600 0x60>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <6>;
+			resets = <&periph_rst BCM6338_RST_DMAMEM>;
+		};
+
+		enet: ethernet@fffe2800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe2800 0x2dc>;
+			clocks = <&periph_clk BCM6338_CLK_ENET>;
+			resets = <&periph_rst BCM6338_RST_ENET>;
+			dmas = <&iudma BCM6338_DMA_ENET_RX>,
+			       <&iudma BCM6338_DMA_ENET_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6348.dtsi b/arch/mips/dts/brcm,bcm6348.dtsi
index cc80bbc..79e7bd8 100644
--- a/arch/mips/dts/brcm,bcm6348.dtsi
+++ b/arch/mips/dts/brcm,bcm6348.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6348-clock.h>
+#include <dt-bindings/dma/bcm6348-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6348-reset.h>
 #include "skeleton.dtsi"
@@ -159,5 +160,46 @@
 			reg = <0xfffe2300 0x38>;
 			u-boot,dm-pre-reloc;
 		};
+
+		enet0: ethernet@fffe6000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6000 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET0_RX>,
+			       <&iudma BCM6348_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet@fffe6800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe6800 0x2dc>;
+			dmas = <&iudma BCM6348_DMA_ENET1_RX>,
+			       <&iudma BCM6348_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		iudma: dma-controller@fffe7000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe7000 0x1c>,
+			      <0xfffe7100 0x40>,
+			      <0xfffe7200 0x40>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <4>;
+			clocks = <&periph_clk BCM6348_CLK_ENET>;
+			resets = <&periph_rst BCM6348_RST_ENET>,
+				 <&periph_rst BCM6348_RST_DMAMEM>;
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6358.dtsi b/arch/mips/dts/brcm,bcm6358.dtsi
index 0617b46..5e9c9ad 100644
--- a/arch/mips/dts/brcm,bcm6358.dtsi
+++ b/arch/mips/dts/brcm,bcm6358.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6358-clock.h>
+#include <dt-bindings/dma/bcm6358-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6358-reset.h>
 #include "skeleton.dtsi"
@@ -190,5 +191,50 @@
 
 			status = "disabled";
 		};
+
+		enet0: ethernet@fffe4000 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4000 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET0>;
+			dmas = <&iudma BCM6358_DMA_ENET0_RX>,
+			       <&iudma BCM6358_DMA_ENET0_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		enet1: ethernet@fffe4800 {
+			compatible = "brcm,bcm6348-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0xfffe4800 0x2dc>;
+			clocks = <&periph_clk BCM6358_CLK_ENET1>;
+			dmas = <&iudma BCM6358_DMA_ENET1_RX>,
+			       <&iudma BCM6358_DMA_ENET1_TX>;
+			dma-names = "rx",
+				    "tx";
+
+			status = "disabled";
+		};
+
+		iudma: dma-controller@fffe5000 {
+			compatible = "brcm,bcm6348-iudma";
+			reg = <0xfffe5000 0x24>,
+			      <0xfffe5100 0x80>,
+			      <0xfffe5200 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+			clocks = <&periph_clk BCM6358_CLK_EMUSB>,
+				 <&periph_clk BCM6358_CLK_USBSU>,
+				 <&periph_clk BCM6358_CLK_EPHY>;
+			resets = <&periph_rst BCM6358_RST_ENET>,
+				 <&periph_rst BCM6358_RST_EPHY>;
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6362.dtsi b/arch/mips/dts/brcm,bcm6362.dtsi
index 3047b82..c77b80a 100644
--- a/arch/mips/dts/brcm,bcm6362.dtsi
+++ b/arch/mips/dts/brcm,bcm6362.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6362-clock.h>
+#include <dt-bindings/dma/bcm6362-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/power-domain/bcm6362-power-domain.h>
 #include <dt-bindings/reset/bcm6362-reset.h>
@@ -211,5 +212,36 @@
 			reg = <0x10003000 0x864>;
 			u-boot,dm-pre-reloc;
 		};
+
+		iudma: dma-controller@1000d800 {
+			compatible = "brcm,bcm6368-iudma";
+			reg = <0x1000d800 0x80>,
+			      <0x1000da00 0x80>,
+			      <0x1000dc00 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+		};
+
+		enet: ethernet@10e00000 {
+			compatible = "brcm,bcm6368-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x10e00000 0x10000>;
+			clocks = <&periph_clk BCM6362_CLK_SWPKT_USB>,
+				 <&periph_clk BCM6362_CLK_SWPKT_SAR>,
+				 <&periph_clk BCM6362_CLK_ROBOSW>;
+			resets = <&periph_rst BCM6362_RST_ENETSW>,
+				 <&periph_rst BCM6362_RST_EPHY>;
+			dmas = <&iudma BCM6362_DMA_ENETSW_RX>,
+			       <&iudma BCM6362_DMA_ENETSW_TX>;
+			dma-names = "rx",
+				    "tx";
+			brcm,num-ports = <6>;
+
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/mips/dts/brcm,bcm6368.dtsi b/arch/mips/dts/brcm,bcm6368.dtsi
index 65d769a..89590d6 100644
--- a/arch/mips/dts/brcm,bcm6368.dtsi
+++ b/arch/mips/dts/brcm,bcm6368.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/bcm6368-clock.h>
+#include <dt-bindings/dma/bcm6368-dma.h>
 #include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/reset/bcm6368-reset.h>
 #include "skeleton.dtsi"
@@ -192,5 +193,36 @@
 
 			status = "disabled";
 		};
+
+		iudma: dma-controller@10006800 {
+			compatible = "brcm,bcm6368-iudma";
+			reg = <0x10006800 0x80>,
+			      <0x10006a00 0x80>,
+			      <0x10006c00 0x80>;
+			reg-names = "dma",
+				    "dma-channels",
+				    "dma-sram";
+			#dma-cells = <1>;
+			dma-channels = <8>;
+		};
+
+		enet: ethernet@10f00000 {
+			compatible = "brcm,bcm6368-enet";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x10f00000 0x10000>;
+			clocks = <&periph_clk BCM6368_CLK_SWPKT_USB>,
+				 <&periph_clk BCM6368_CLK_SWPKT_SAR>,
+				 <&periph_clk BCM6368_CLK_ROBOSW>;
+			resets = <&periph_rst BCM6368_RST_SWITCH>,
+				 <&periph_rst BCM6368_RST_EPHY>;
+			dmas = <&iudma BCM6368_DMA_ENETSW_RX>,
+			       <&iudma BCM6368_DMA_ENETSW_TX>;
+			dma-names = "rx",
+				    "tx";
+			brcm,num-ports = <6>;
+
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/mips/dts/ci20.dts b/arch/mips/dts/ci20.dts
new file mode 100644
index 0000000..8d6417a
--- /dev/null
+++ b/arch/mips/dts/ci20.dts
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/dts-v1/;
+
+#include "jz4780.dtsi"
+
+/ {
+	compatible = "img,ci20", "ingenic,jz4780";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial3 = &uart3;
+		serial4 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial4:115200n8";
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x0 0x10000000
+		       0x30000000 0x30000000>;
+	};
+};
+
+&ext {
+	clock-frequency = <48000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&uart1 {
+	status = "okay";
+};
+
+&uart3 {
+	status = "okay";
+};
+
+&uart4 {
+	status = "okay";
+};
+
+&nemc {
+	status = "okay";
+
+	nandc: nand-controller@1 {
+		compatible = "ingenic,jz4780-nand";
+		reg = <1 0 0x1000000>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		ingenic,bch-controller = <&bch>;
+
+		ingenic,nemc-tAS = <10>;
+		ingenic,nemc-tAH = <5>;
+		ingenic,nemc-tBP = <10>;
+		ingenic,nemc-tAW = <15>;
+		ingenic,nemc-tSTRV = <100>;
+
+		nand@1 {
+			reg = <1>;
+
+			nand-ecc-step-size = <1024>;
+			nand-ecc-strength = <24>;
+			nand-ecc-mode = "hw";
+			nand-on-flash-bbt;
+
+			partitions {
+				compatible = "fixed-partitions";
+				#address-cells = <2>;
+				#size-cells = <2>;
+
+				partition@0 {
+					label = "u-boot-spl";
+					reg = <0x0 0x0 0x0 0x800000>;
+				};
+
+				partition@0x800000 {
+					label = "u-boot";
+					reg = <0x0 0x800000 0x0 0x200000>;
+				};
+
+				partition@0xa00000 {
+					label = "u-boot-env";
+					reg = <0x0 0xa00000 0x0 0x200000>;
+				};
+
+				partition@0xc00000 {
+					label = "boot";
+					reg = <0x0 0xc00000 0x0 0x4000000>;
+				};
+
+				partition@0x8c00000 {
+					label = "system";
+					reg = <0x0 0x4c00000 0x1 0xfb400000>;
+				};
+			};
+		};
+	};
+};
+
+&bch {
+	status = "okay";
+};
+
+&mmc0 {
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	status = "okay";
+};
+
+&mmc1 {
+	bus-width = <4>;
+	max-frequency = <50000000>;
+	status = "okay";
+};
diff --git a/arch/mips/dts/comtrend,ar-5315u.dts b/arch/mips/dts/comtrend,ar-5315u.dts
index 4557018..eb60aaa 100644
--- a/arch/mips/dts/comtrend,ar-5315u.dts
+++ b/arch/mips/dts/comtrend,ar-5315u.dts
@@ -24,6 +24,38 @@
 	status = "okay";
 };
 
+&enet {
+	status = "okay";
+
+	port@0 {
+		compatible = "brcm,enetsw-port";
+		reg = <0>;
+		label = "fe4";
+		brcm,phy-id = <1>;
+	};
+
+	port@1 {
+		compatible = "brcm,enetsw-port";
+		reg = <1>;
+		label = "fe3";
+		brcm,phy-id = <2>;
+	};
+
+	port@2 {
+		compatible = "brcm,enetsw-port";
+		reg = <2>;
+		label = "fe2";
+		brcm,phy-id = <3>;
+	};
+
+	port@3 {
+		compatible = "brcm,enetsw-port";
+		reg = <3>;
+		label = "fe1";
+		brcm,phy-id = <4>;
+	};
+};
+
 &leds {
 	status = "okay";
 
diff --git a/arch/mips/dts/comtrend,ar-5387un.dts b/arch/mips/dts/comtrend,ar-5387un.dts
index e993b5c..03e3851 100644
--- a/arch/mips/dts/comtrend,ar-5387un.dts
+++ b/arch/mips/dts/comtrend,ar-5387un.dts
@@ -24,6 +24,38 @@
 	status = "okay";
 };
 
+&enet {
+	status = "okay";
+
+	port@0 {
+		compatible = "brcm,enetsw-port";
+		reg = <0>;
+		label = "fe1";
+		brcm,phy-id = <1>;
+	};
+
+	port@1 {
+		compatible = "brcm,enetsw-port";
+		reg = <1>;
+		label = "fe2";
+		brcm,phy-id = <2>;
+	};
+
+	port@2 {
+		compatible = "brcm,enetsw-port";
+		reg = <2>;
+		label = "fe3";
+		brcm,phy-id = <3>;
+	};
+
+	port@3 {
+		compatible = "brcm,enetsw-port";
+		reg = <3>;
+		label = "fe4";
+		brcm,phy-id = <4>;
+	};
+};
+
 &leds {
 	status = "okay";
 
diff --git a/arch/mips/dts/comtrend,ct-5361.dts b/arch/mips/dts/comtrend,ct-5361.dts
index 25747ca..f6b8a94 100644
--- a/arch/mips/dts/comtrend,ct-5361.dts
+++ b/arch/mips/dts/comtrend,ct-5361.dts
@@ -34,6 +34,18 @@
 	};
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/arch/mips/dts/comtrend,vr-3032u.dts b/arch/mips/dts/comtrend,vr-3032u.dts
index 8c6a4a1..512cb52 100644
--- a/arch/mips/dts/comtrend,vr-3032u.dts
+++ b/arch/mips/dts/comtrend,vr-3032u.dts
@@ -24,6 +24,38 @@
 	status = "okay";
 };
 
+&enet {
+	status = "okay";
+
+	port@0 {
+		compatible = "brcm,enetsw-port";
+		reg = <0>;
+		label = "fe2";
+		brcm,phy-id = <1>;
+	};
+
+	port@1 {
+		compatible = "brcm,enetsw-port";
+		reg = <1>;
+		label = "fe3";
+		brcm,phy-id = <2>;
+	};
+
+	port@2 {
+		compatible = "brcm,enetsw-port";
+		reg = <2>;
+		label = "fe4";
+		brcm,phy-id = <3>;
+	};
+
+	port@3 {
+		compatible = "brcm,enetsw-port";
+		reg = <3>;
+		label = "fe1";
+		brcm,phy-id = <4>;
+	};
+};
+
 &leds {
 	status = "okay";
 	brcm,serial-leds;
diff --git a/arch/mips/dts/comtrend,wap-5813n.dts b/arch/mips/dts/comtrend,wap-5813n.dts
index bd41dab..7e835b2 100644
--- a/arch/mips/dts/comtrend,wap-5813n.dts
+++ b/arch/mips/dts/comtrend,wap-5813n.dts
@@ -54,6 +54,20 @@
 	status = "okay";
 };
 
+&enet {
+	status = "okay";
+
+	port@4 {
+		compatible = "brcm,enetsw-port";
+		reg = <4>;
+		label = "rgmii";
+		brcm,phy-id = <0xff>;
+		speed = <1000>;
+		full-duplex;
+		bypass-link;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/arch/mips/dts/huawei,hg556a.dts b/arch/mips/dts/huawei,hg556a.dts
index 60455c2..6a7fc1d 100644
--- a/arch/mips/dts/huawei,hg556a.dts
+++ b/arch/mips/dts/huawei,hg556a.dts
@@ -93,6 +93,18 @@
 	status = "okay";
 };
 
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/arch/mips/dts/jz4780.dtsi b/arch/mips/dts/jz4780.dtsi
new file mode 100644
index 0000000..f62a7a9
--- /dev/null
+++ b/arch/mips/dts/jz4780.dtsi
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <dt-bindings/clock/jz4780-cgu.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "ingenic,jz4780";
+
+	cpuintc: interrupt-controller {
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+		compatible = "mti,cpu-interrupt-controller";
+	};
+
+	intc: interrupt-controller@10001000 {
+		compatible = "ingenic,jz4780-intc";
+		reg = <0x10001000 0x50>;
+
+		interrupt-controller;
+		#interrupt-cells = <1>;
+
+		interrupt-parent = <&cpuintc>;
+		interrupts = <2>;
+	};
+
+	ext: ext {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+	};
+
+	rtc: rtc {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <32768>;
+	};
+
+	cgu: jz4780-cgu@10000000 {
+		compatible = "ingenic,jz4780-cgu";
+		reg = <0x10000000 0x100>;
+
+		clocks = <&ext>, <&rtc>;
+		clock-names = "ext", "rtc";
+
+		#clock-cells = <1>;
+	};
+
+	mmc0: mmc@13450000 {
+		compatible = "ingenic,jz4780-mmc";
+		reg = <0x13450000 0x1000>;
+
+		status = "disabled";
+
+		clocks = <&cgu JZ4780_CLK_MSC0>;
+		clock-names = "mmc";
+	};
+
+	mmc1: mmc@13460000 {
+		compatible = "ingenic,jz4780-mmc";
+		reg = <0x13460000 0x1000>;
+
+		clocks = <&cgu JZ4780_CLK_MSC1>;
+		clock-names = "mmc";
+
+		status = "disabled";
+	};
+
+	uart0: serial@10030000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10030000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <51>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART0>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart1: serial@10031000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10031000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <50>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART1>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart2: serial@10032000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10032000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <49>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART2>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart3: serial@10033000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10033000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <48>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART3>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	uart4: serial@10034000 {
+		compatible = "ingenic,jz4780-uart";
+		reg = <0x10034000 0x100>;
+		reg-shift = <2>;
+
+		interrupt-parent = <&intc>;
+		interrupts = <34>;
+
+		clocks = <&ext>, <&cgu JZ4780_CLK_UART4>;
+		clock-names = "baud", "module";
+
+		status = "disabled";
+	};
+
+	nemc: nemc@13410000 {
+		compatible = "ingenic,jz4780-nemc";
+		reg = <0x13410000 0x10000>;
+		#address-cells = <2>;
+		#size-cells = <1>;
+		ranges = <1 0 0x1b000000 0x1000000
+			  2 0 0x1a000000 0x1000000
+			  3 0 0x19000000 0x1000000
+			  4 0 0x18000000 0x1000000
+			  5 0 0x17000000 0x1000000
+			  6 0 0x16000000 0x1000000>;
+
+		clocks = <&cgu JZ4780_CLK_NEMC>;
+
+		status = "disabled";
+	};
+
+	bch: bch@134d0000 {
+		compatible = "ingenic,jz4780-bch";
+		reg = <0x134d0000 0x10000>;
+
+		clocks = <&cgu JZ4780_CLK_BCH>;
+
+		status = "disabled";
+	};
+};
diff --git a/arch/mips/dts/luton_pcb091.dts b/arch/mips/dts/luton_pcb091.dts
new file mode 100644
index 0000000..74f9274
--- /dev/null
+++ b/arch/mips/dts/luton_pcb091.dts
@@ -0,0 +1,36 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+/dts-v1/;
+#include "mscc,luton.dtsi"
+
+/ {
+	model = "Luton10 PCB091 Reference Board";
+	compatible = "mscc,luton-pcb091", "mscc,luton";
+
+	aliases {
+		serial0 = &uart0;
+		spi0 = &spi0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	status = "okay";
+	spi-flash@0 {
+		compatible = "spi-flash";
+		spi-max-frequency = <18000000>; /* input clock */
+		reg = <0>; /* CS0 */
+		spi-cs-high;
+	};
+};
+
diff --git a/arch/mips/dts/mscc,luton.dtsi b/arch/mips/dts/mscc,luton.dtsi
new file mode 100644
index 0000000..6a4ad2a
--- /dev/null
+++ b/arch/mips/dts/mscc,luton.dtsi
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "mscc,luton";
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			compatible = "mips,mips24KEc";
+			device_type = "cpu";
+			reg = <0>;
+		};
+	};
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	ahb_clk: ahb-clk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <208333333>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0x60000000 0x10200000>;
+
+		uart0: serial@10100000 {
+			pinctrl-0 = <&uart_pins>;
+			pinctrl-names = "default";
+
+			compatible = "ns16550a";
+			reg = <0x10100000 0x20>;
+			clocks = <&ahb_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+
+			status = "disabled";
+		};
+
+		gpio: pinctrl@70068 {
+			compatible = "mscc,luton-pinctrl";
+			reg = <0x70068 0x68>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&gpio 0 0 32>;
+
+			uart_pins: uart-pins {
+				pins = "GPIO_30", "GPIO_31";
+				function = "uart";
+			};
+
+		};
+
+		gpio_spi_bitbang: gpio@10000064 {
+			compatible = "mscc,spi-bitbang-gpio";
+			reg = <0x10000064 0x4>;
+			gpio-controller;
+			#gpio-cells = <2>;
+
+		};
+
+		spi0: spi-bitbang {
+			compatible = "spi-gpio";
+			status = "okay";
+			gpio-sck = <&gpio_spi_bitbang 6 0>;
+			gpio-miso = <&gpio_spi_bitbang 0 0>;
+			gpio-mosi = <&gpio_spi_bitbang 5 0>;
+			cs-gpios = <&gpio_spi_bitbang 1 0>;
+			num-chipselects = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/mscc,ocelot.dtsi b/arch/mips/dts/mscc,ocelot.dtsi
new file mode 100644
index 0000000..87b4736
--- /dev/null
+++ b/arch/mips/dts/mscc,ocelot.dtsi
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "mscc,ocelot";
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			compatible = "mips,mips24KEc";
+			device_type = "cpu";
+			clocks = <&cpu_clk>;
+			reg = <0>;
+		};
+	};
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	cpuintc: interrupt-controller@0 {
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+		compatible = "mti,cpu-interrupt-controller";
+	};
+
+	cpu_clk: cpu-clock {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <500000000>;
+	};
+
+	ahb_clk: ahb-clk {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+		clock-frequency = <250000000>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0 0x70000000 0x2000000>;
+
+		interrupt-parent = <&intc>;
+
+		cpu_ctrl: syscon@0 {
+			compatible = "mscc,ocelot-cpu-syscon", "syscon";
+			reg = <0x0 0x2c>;
+		};
+
+		intc: interrupt-controller@70 {
+			compatible = "mscc,ocelot-icpu-intr";
+			reg = <0x70 0x70>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+			interrupt-parent = <&cpuintc>;
+			interrupts = <2>;
+		};
+
+		uart0: serial@100000 {
+			pinctrl-0 = <&uart_pins>;
+			pinctrl-names = "default";
+			compatible = "ns16550a";
+			reg = <0x100000 0x20>;
+			interrupts = <6>;
+			clocks = <&ahb_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+
+			status = "disabled";
+		};
+
+		uart2: serial@100800 {
+			pinctrl-0 = <&uart2_pins>;
+			pinctrl-names = "default";
+			compatible = "ns16550a";
+			reg = <0x100800 0x20>;
+			interrupts = <7>;
+			clocks = <&ahb_clk>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+
+			status = "disabled";
+		};
+
+		spi0: spi-master@101000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "snps,dw-apb-ssi";
+			reg = <0x101000 0x40>;
+			num-chipselect = <4>;
+			bus-num = <0>;
+			reg-io-width = <4>;
+			reg-shift = <2>;
+			spi-max-frequency = <18000000>; /* input clock */
+			clocks = <&ahb_clk>;
+
+			status = "disabled";
+		};
+
+		reset@1070008 {
+			compatible = "mscc,ocelot-chip-reset";
+			reg = <0x1070008 0x4>;
+		};
+
+		gpio: pinctrl@1070034 {
+			compatible = "mscc,ocelot-pinctrl";
+			reg = <0x1070034 0x68>;
+			gpio-controller;
+			#gpio-cells = <2>;
+			gpio-ranges = <&gpio 0 0 22>;
+
+			uart_pins: uart-pins {
+				pins = "GPIO_6", "GPIO_7";
+				function = "uart";
+			};
+
+			uart2_pins: uart2-pins {
+				pins = "GPIO_12", "GPIO_13";
+				function = "uart2";
+			};
+
+			spi_cs1_pin: spi-cs1-pin {
+				pins = "GPIO_8";
+				function = "si";
+			};
+
+			spi_cs2_pin: spi-cs2-pin {
+				pins = "GPIO_9";
+				function = "si";
+			};
+
+			spi_cs3_pin: spi-cs3-pin {
+				pins = "GPIO_16";
+				function = "si";
+			};
+
+			spi_cs4_pin: spi-cs4-pin {
+				pins = "GPIO_17";
+				function = "si";
+			};
+		};
+	};
+};
diff --git a/arch/mips/dts/mscc,ocelot_pcb.dtsi b/arch/mips/dts/mscc,ocelot_pcb.dtsi
new file mode 100644
index 0000000..90725d3
--- /dev/null
+++ b/arch/mips/dts/mscc,ocelot_pcb.dtsi
@@ -0,0 +1,42 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+/dts-v1/;
+#include "mscc,ocelot.dtsi"
+
+/ {
+	compatible = "mscc,ocelot";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	status = "okay";
+	pinctrl-0 = <&spi_cs1_pin>;
+	pinctrl-names = "default";
+
+	spi-flash@0 {
+		compatible = "spi-flash";
+		spi-max-frequency = <18000000>; /* input clock */
+		reg = <0>; /* CS0 */
+	};
+
+	spi-nand@1 {
+		compatible = "spi-nand";
+		spi-max-frequency = <18000000>; /* input clock */
+		reg = <1>; /* CS1 */
+	};
+};
diff --git a/arch/mips/dts/netgear,dgnd3700v2.dts b/arch/mips/dts/netgear,dgnd3700v2.dts
index 322d156..2b72491 100644
--- a/arch/mips/dts/netgear,dgnd3700v2.dts
+++ b/arch/mips/dts/netgear,dgnd3700v2.dts
@@ -43,6 +43,20 @@
 	status = "okay";
 };
 
+&enet {
+	status = "okay";
+
+	port@4 {
+		compatible = "brcm,enetsw-port";
+		reg = <4>;
+		label = "rgmii";
+		brcm,phy-id = <0xff>;
+		speed = <1000>;
+		full-duplex;
+		bypass-link;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/arch/mips/dts/nexys4ddr.dts b/arch/mips/dts/nexys4ddr.dts
index e254ab1..6de8584 100644
--- a/arch/mips/dts/nexys4ddr.dts
+++ b/arch/mips/dts/nexys4ddr.dts
@@ -40,7 +40,6 @@
 			#address-cells = <1>;
 			#size-cells = <0>;
 			phy0: phy@1 {
-				compatible = <0x0007c0f0 0xfffffff0>;
 				device_type = "ethernet-phy";
 				reg = <1>;
 			} ;
diff --git a/arch/mips/dts/ocelot_pcb120.dts b/arch/mips/dts/ocelot_pcb120.dts
new file mode 100644
index 0000000..47d305a
--- /dev/null
+++ b/arch/mips/dts/ocelot_pcb120.dts
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+/dts-v1/;
+#include "mscc,ocelot_pcb.dtsi"
+
+/ {
+	model = "Ocelot PCB120 Reference Board";
+	compatible = "mscc,ocelot-pcb120", "mscc,ocelot";
+};
diff --git a/arch/mips/dts/ocelot_pcb123.dts b/arch/mips/dts/ocelot_pcb123.dts
new file mode 100644
index 0000000..17d8d32
--- /dev/null
+++ b/arch/mips/dts/ocelot_pcb123.dts
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+/dts-v1/;
+#include "mscc,ocelot_pcb.dtsi"
+
+/ {
+	model = "Ocelot PCB123 Reference Board";
+	compatible = "mscc,ocelot-pcb123", "mscc,ocelot";
+};
diff --git a/arch/mips/dts/qca953x.dtsi b/arch/mips/dts/qca953x.dtsi
index 599e809..ba29ea2 100644
--- a/arch/mips/dts/qca953x.dtsi
+++ b/arch/mips/dts/qca953x.dtsi
@@ -3,7 +3,6 @@
  * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
  */
 
-#include <dt-bindings/interrupt-controller/irq.h>
 #include "skeleton.dtsi"
 
 / {
@@ -63,7 +62,6 @@
 				reg = <0x18020000 0x20>;
 				reg-shift = <2>;
 				clock-frequency = <25000000>;
-				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
 
 				status = "disabled";
 			};
@@ -72,7 +70,6 @@
 		spi0: spi@1f000000 {
 			compatible = "qca,ar7100-spi";
 			reg = <0x1f000000 0x10>;
-			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
 
 			status = "disabled";
 
diff --git a/arch/mips/dts/sagem,f@st1704.dts b/arch/mips/dts/sagem,f@st1704.dts
index 5300f8b..ec6846d 100644
--- a/arch/mips/dts/sagem,f@st1704.dts
+++ b/arch/mips/dts/sagem,f@st1704.dts
@@ -39,6 +39,18 @@
 	};
 };
 
+&enet {
+	status = "okay";
+	phy = <&enetphy>;
+	phy-mode = "mii";
+
+	enetphy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio {
 	status = "okay";
 };
diff --git a/arch/mips/dts/sfr,nb4-ser.dts b/arch/mips/dts/sfr,nb4-ser.dts
index bdc6f8a..dfbc414 100644
--- a/arch/mips/dts/sfr,nb4-ser.dts
+++ b/arch/mips/dts/sfr,nb4-ser.dts
@@ -53,6 +53,30 @@
 	status = "okay";
 };
 
+&enet0 {
+	status = "okay";
+	phy = <&enet0phy>;
+	phy-mode = "internal";
+
+	enet0phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
+&enet1 {
+	status = "okay";
+	phy = <&enet1phy>;
+	phy-mode = "mii";
+
+	enet1phy: fixed-link {
+		reg = <1>;
+		speed = <100>;
+		full-duplex;
+	};
+};
+
 &gpio0 {
 	status = "okay";
 };
diff --git a/arch/mips/include/asm/cacheops.h b/arch/mips/include/asm/cacheops.h
index 3161875..98b67cc 100644
--- a/arch/mips/include/asm/cacheops.h
+++ b/arch/mips/include/asm/cacheops.h
@@ -19,6 +19,25 @@
 #endif
 }
 
+#define MIPS32_WHICH_ICACHE                    0x0
+#define MIPS32_FETCH_AND_LOCK                  0x7
+
+#define ICACHE_LOAD_LOCK (MIPS32_WHICH_ICACHE | (MIPS32_FETCH_AND_LOCK << 2))
+
+/* Prefetch and lock instructions into cache */
+static inline void icache_lock(void *func, size_t len)
+{
+	int i, lines = ((len - 1) / ARCH_DMA_MINALIGN) + 1;
+
+	for (i = 0; i < lines; i++) {
+		asm volatile (" cache %0, %1(%2)"
+			      : /* No Output */
+			      : "I" ICACHE_LOAD_LOCK,
+				"n" (i * ARCH_DMA_MINALIGN),
+				"r" (func)
+			      : /* No Clobbers */);
+	}
+}
 #endif /* !__ASSEMBLY__ */
 
 /*
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 48fa1f1..f80311e 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -1013,9 +1013,7 @@
 #define __read_64bit_c0_split(source, sel)				\
 ({									\
 	unsigned long long __val;					\
-	unsigned long __flags;						\
 									\
-	local_irq_save(__flags);					\
 	if (sel == 0)							\
 		__asm__ __volatile__(					\
 			".set\tmips64\n\t"				\
@@ -1034,16 +1032,12 @@
 			"dsra\t%L0, %L0, 32\n\t"			\
 			".set\tmips0"					\
 			: "=r" (__val));				\
-	local_irq_restore(__flags);					\
 									\
 	__val;								\
 })
 
 #define __write_64bit_c0_split(source, sel, val)			\
 do {									\
-	unsigned long __flags;						\
-									\
-	local_irq_save(__flags);					\
 	if (sel == 0)							\
 		__asm__ __volatile__(					\
 			".set\tmips64\n\t"				\
@@ -1064,7 +1058,6 @@
 			"dmtc0\t%L0, " #source ", " #sel "\n\t"		\
 			".set\tmips0"					\
 			: : "r" (val));					\
-	local_irq_restore(__flags);					\
 } while (0)
 
 #define __readx_32bit_c0_register(source)				\
@@ -2005,6 +1998,17 @@
 	return read_c0_ebase() & 0x3ff;
 }
 
+static inline void write_one_tlb(int index, u32 pagemask, u32 hi, u32 low0,
+				 u32 low1)
+{
+	write_c0_entrylo0(low0);
+	write_c0_pagemask(pagemask);
+	write_c0_entrylo1(low1);
+	write_c0_entryhi(hi);
+	write_c0_index(index);
+	tlb_write_indexed();
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_MIPSREGS_H */
diff --git a/arch/mips/include/asm/spl.h b/arch/mips/include/asm/spl.h
new file mode 100644
index 0000000..0a847ed
--- /dev/null
+++ b/arch/mips/include/asm/spl.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2012
+ * Texas Instruments, <www.ti.com>
+ */
+#ifndef	_ASM_SPL_H_
+#define	_ASM_SPL_H_
+
+enum {
+	BOOT_DEVICE_RAM,
+	BOOT_DEVICE_MMC1,
+	BOOT_DEVICE_MMC2,
+	BOOT_DEVICE_MMC2_2,
+	BOOT_DEVICE_NAND,
+	BOOT_DEVICE_ONENAND,
+	BOOT_DEVICE_NOR,
+	BOOT_DEVICE_UART,
+	BOOT_DEVICE_SPI,
+	BOOT_DEVICE_USB,
+	BOOT_DEVICE_SATA,
+	BOOT_DEVICE_I2C,
+	BOOT_DEVICE_BOARD,
+	BOOT_DEVICE_DFU,
+	BOOT_DEVICE_XIP,
+	BOOT_DEVICE_BOOTROM,
+	BOOT_DEVICE_NONE
+};
+
+#ifndef CONFIG_DM
+extern gd_t gdata;
+#endif
+
+#endif
diff --git a/arch/mips/mach-jz47xx/Kconfig b/arch/mips/mach-jz47xx/Kconfig
new file mode 100644
index 0000000..dcaac01
--- /dev/null
+++ b/arch/mips/mach-jz47xx/Kconfig
@@ -0,0 +1,26 @@
+menu "Ingenic JZ47xx platforms"
+	depends on ARCH_JZ47XX
+
+config SYS_SOC
+	default "jz47xx"
+
+config SOC_JZ4780
+	bool
+	select SUPPORTS_LITTLE_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	help
+	  Support for Ingenic JZ4780 family SoCs.
+
+choice
+	prompt "Board select"
+
+config TARGET_JZ4780_CI20
+	bool "Creator CI20 Reference Board"
+	select SOC_JZ4780
+
+endchoice
+
+source "board/imgtec/ci20/Kconfig"
+
+endmenu
diff --git a/arch/mips/mach-jz47xx/Makefile b/arch/mips/mach-jz47xx/Makefile
new file mode 100644
index 0000000..dbb8229
--- /dev/null
+++ b/arch/mips/mach-jz47xx/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+extra-$(CONFIG_SPL_BUILD)	:= start.o
+
+obj-$(CONFIG_SOC_JZ4780)	+= jz4780/
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780.h b/arch/mips/mach-jz47xx/include/mach/jz4780.h
new file mode 100644
index 0000000..4422e50
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780.h
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * JZ4780 definitions
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#ifndef __JZ4780_H__
+#define __JZ4780_H__
+
+/* AHB0 BUS Devices */
+#define DDRC_BASE	0xb3010000
+
+/* AHB2 BUS Devices */
+#define NEMC_BASE	0xb3410000
+#define BCH_BASE	0xb34d0000
+
+/* APB BUS Devices */
+#define CPM_BASE	0xb0000000
+#define TCU_BASE	0xb0002000
+#define WDT_BASE	0xb0002000
+#define GPIO_BASE	0xb0010000
+#define UART0_BASE	0xb0030000
+#define UART1_BASE	0xb0031000
+#define UART2_BASE	0xb0032000
+#define UART3_BASE	0xb0033000
+#define MSC0_BASE	0xb3450000
+#define MSC1_BASE	0xb3460000
+#define MSC2_BASE	0xb3470000
+
+/*
+ * GPIO
+ */
+/* n = 0,1,2,3,4,5 */
+#define GPIO_PXPIN(n)	(0x00 + (n) * 0x100)
+#define GPIO_PXINT(n)	(0x10 + (n) * 0x100)
+#define GPIO_PXINTS(n)	(0x14 + (n) * 0x100)
+#define GPIO_PXINTC(n)	(0x18 + (n) * 0x100)
+#define GPIO_PXMASK(n)	(0x20 + (n) * 0x100)
+#define GPIO_PXMASKS(n)	(0x24 + (n) * 0x100)
+#define GPIO_PXMASKC(n)	(0x28 + (n) * 0x100)
+#define GPIO_PXPAT1(n)	(0x30 + (n) * 0x100)
+#define GPIO_PXPAT1S(n)	(0x34 + (n) * 0x100)
+#define GPIO_PXPAT1C(n)	(0x38 + (n) * 0x100)
+#define GPIO_PXPAT0(n)	(0x40 + (n) * 0x100)
+#define GPIO_PXPAT0S(n)	(0x44 + (n) * 0x100)
+#define GPIO_PXPAT0C(n)	(0x48 + (n) * 0x100)
+#define GPIO_PXFLG(n)	(0x50 + (n) * 0x100)
+#define GPIO_PXFLGC(n)	(0x54 + (n) * 0x100)
+#define GPIO_PXOEN(n)	(0x60 + (n) * 0x100)
+#define GPIO_PXOENS(n)	(0x64 + (n) * 0x100)
+#define GPIO_PXOENC(n)	(0x68 + (n) * 0x100)
+#define GPIO_PXPEN(n)	(0x70 + (n) * 0x100)
+#define GPIO_PXPENS(n)	(0x74 + (n) * 0x100)
+#define GPIO_PXPENC(n)	(0x78 + (n) * 0x100)
+#define GPIO_PXDS(n)	(0x80 + (n) * 0x100)
+#define GPIO_PXDSS(n)	(0x84 + (n) * 0x100)
+#define GPIO_PXDSC(n)	(0x88 + (n) * 0x100)
+
+/* PLL setup */
+#define JZ4780_SYS_EXTAL	48000000
+#define JZ4780_SYS_MEM_SPEED	(CONFIG_SYS_MHZ * 1000000)
+#define JZ4780_SYS_MEM_DIV	3
+#define JZ4780_SYS_AUDIO_SPEED	(768 * 1000000)
+
+#define JZ4780_APLL_M	1
+#define JZ4780_APLL_N	1
+#define JZ4780_APLL_OD	1
+
+#define JZ4780_MPLL_M	(JZ4780_SYS_MEM_SPEED / JZ4780_SYS_EXTAL * 2)
+#define JZ4780_MPLL_N	2
+#define JZ4780_MPLL_OD	1
+
+#define JZ4780_EPLL_M	(JZ4780_SYS_AUDIO_SPEED * 2 / JZ4780_SYS_EXTAL)
+#define JZ4780_EPLL_N	1
+#define JZ4780_EPLL_OD	2
+
+#define JZ4780_VPLL_M	((888 * 1000000) * 2 / JZ4780_SYS_EXTAL)
+#define JZ4780_VPLL_N	1
+#define JZ4780_VPLL_OD	2
+
+#ifndef __ASSEMBLY__
+
+u32 sdram_size(int bank);
+
+const u32 jz4780_clk_get_efuse_clk(void);
+void jz4780_clk_ungate_ethernet(void);
+void jz4780_clk_ungate_mmc(void);
+void jz4780_clk_ungate_uart(const unsigned int uart);
+
+void jz4780_efuse_read(size_t addr, size_t count, u8 *buf);
+void jz4780_efuse_init(u32 ahb2_rate);
+
+void jz4780_tcu_wdt_start(void);
+
+#ifdef CONFIG_SPL_BUILD
+int jz_mmc_init(void __iomem *base);
+#endif
+
+#endif /* __ASSEMBLY__ */
+
+#endif	/* __JZ4780_H__ */
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h b/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h
new file mode 100644
index 0000000..92d431b
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780_dram.h
@@ -0,0 +1,456 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * JZ4780 DDR initialization - parameters definitions
+ *
+ * Copyright (c) 2015 Imagination Technologies
+ * Author: Matt Redfearn <matt.redfearn.com>
+ */
+
+#ifndef __JZ4780_DRAM_H__
+#define __JZ4780_DRAM_H__
+
+/*
+ * DDR
+ */
+#define DDRC_ST				0x0
+#define DDRC_CFG			0x4
+#define DDRC_CTRL			0x8
+#define DDRC_LMR			0xc
+#define DDRC_REFCNT			0x18
+#define DDRC_DQS			0x1c
+#define DDRC_DQS_ADJ			0x20
+#define DDRC_MMAP0			0x24
+#define DDRC_MMAP1			0x28
+#define DDRC_MDELAY			0x2c
+#define DDRC_CKEL			0x30
+#define DDRC_PMEMCTRL0			0x54
+#define DDRC_PMEMCTRL1			0x50
+#define DDRC_PMEMCTRL2			0x58
+#define DDRC_PMEMCTRL3			0x5c
+
+#define DDRC_TIMING(n)			(0x60 + 4 * (n))
+#define DDRC_REMMAP(n)			(0x9c + 4 * (n))
+
+/*
+ * DDR PHY
+ */
+#define DDR_MEM_PHY_BASE		0x20000000
+#define DDR_PHY_OFFSET			0x1000
+
+#define DDRP_PIR			0x4
+#define DDRP_PGCR			0x8
+#define DDRP_PGSR			0xc
+
+#define DDRP_PTR0			0x18
+#define DDRP_PTR1			0x1c
+#define DDRP_PTR2			0x20
+
+#define DDRP_ACIOCR			0x24
+#define DDRP_DXCCR			0x28
+#define DDRP_DSGCR			0x2c
+#define DDRP_DCR			0x30
+
+#define DDRP_DTPR0			0x34
+#define DDRP_DTPR1			0x38
+#define DDRP_DTPR2			0x3c
+#define DDRP_MR0			0x40
+#define DDRP_MR1			0x44
+#define DDRP_MR2			0x48
+#define DDRP_MR3			0x4c
+
+#define DDRP_ODTCR			0x50
+#define DDRP_DTAR			0x54
+#define DDRP_DTDR0			0x58
+#define DDRP_DTDR1			0x5c
+
+#define DDRP_DCUAR			0xc0
+#define DDRP_DCUDR			0xc4
+#define DDRP_DCURR			0xc8
+#define DDRP_DCULR			0xcc
+#define DDRP_DCUGCR			0xd0
+#define DDRP_DCUTPR			0xd4
+#define DDRP_DCUSR0			0xd8
+#define DDRP_DCUSR1			0xdc
+
+#define DDRP_ZQXCR0(n)			(0x180 + ((n) * 0x10))
+#define DDRP_ZQXCR1(n)			(0x184 + ((n) * 0x10))
+#define DDRP_ZQXSR0(n)			(0x188 + ((n) * 0x10))
+#define DDRP_ZQXSR1(n)			(0x18c + ((n) * 0x10))
+
+#define DDRP_DXGCR(n)			(0x1c0 + ((n) * 0x40))
+#define DDRP_DXGSR0(n)			(0x1c4 + ((n) * 0x40))
+#define DDRP_DXGSR1(n)			(0x1c8 + ((n) * 0x40))
+#define DDRP_DXDQSTR(n)			(0x1d4 + ((n) * 0x40))
+
+/* DDRC Status Register */
+#define DDRC_ST_ENDIAN			BIT(7)
+#define DDRC_ST_DPDN			BIT(5)
+#define DDRC_ST_PDN			BIT(4)
+#define DDRC_ST_AREF			BIT(3)
+#define DDRC_ST_SREF			BIT(2)
+#define DDRC_ST_CKE1			BIT(1)
+#define DDRC_ST_CKE0			BIT(0)
+
+/* DDRC Configure Register */
+#define DDRC_CFG_ROW1_BIT		27
+#define DDRC_CFG_ROW1_MASK		(0x7 << DDRC_CFG_ROW1_BIT)
+#define DDRC_CFG_COL1_BIT		24
+#define DDRC_CFG_COL1_MASK		(0x7 << DDRC_CFG_COL1_BIT)
+#define DDRC_CFG_BA1			BIT(23)
+#define DDRC_CFG_IMBA			BIT(22)
+#define DDRC_CFG_BL_8			BIT(21)
+
+#define DDRC_CFG_TYPE_BIT		17
+#define DDRC_CFG_TYPE_MASK		(0x7 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR1		(2 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_MDDR		(3 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR2		(4 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_LPDDR2		(5 << DDRC_CFG_TYPE_BIT)
+#define DDRC_CFG_TYPE_DDR3		(6 << DDRC_CFG_TYPE_BIT)
+
+#define DDRC_CFG_ODT_EN			BIT(16)
+
+#define DDRC_CFG_MPRT			BIT(15)
+
+#define DDRC_CFG_ROW_BIT		11
+#define DDRC_CFG_ROW_MASK		(0x7 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_12			(0 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_13			(1 << DDRC_CFG_ROW_BIT)
+#define DDRC_CFG_ROW_14			(2 << DDRC_CFG_ROW_BIT)
+
+#define DDRC_CFG_COL_BIT		8
+#define DDRC_CFG_COL_MASK		(0x7 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_8			(0 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_9			(1 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_10			(2 << DDRC_CFG_COL_BIT)
+#define DDRC_CFG_COL_11			(3 << DDRC_CFG_COL_BIT)
+
+#define DDRC_CFG_CS1EN			BIT(7)
+#define DDRC_CFG_CS0EN			BIT(6)
+#define DDRC_CFG_CL_BIT			2
+#define DDRC_CFG_CL_MASK		(0xf << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_3			(0 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_4			(1 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_5			(2 << DDRC_CFG_CL_BIT)
+#define DDRC_CFG_CL_6			(3 << DDRC_CFG_CL_BIT)
+
+#define DDRC_CFG_BA			BIT(1)
+#define DDRC_CFG_DW			BIT(0)
+
+/* DDRC Control Register */
+#define DDRC_CTRL_DFI_RST		BIT(23)
+#define DDRC_CTRL_DLL_RST		BIT(22)
+#define DDRC_CTRL_CTL_RST		BIT(21)
+#define DDRC_CTRL_CFG_RST		BIT(20)
+#define DDRC_CTRL_ACTPD			BIT(15)
+#define DDRC_CTRL_PDT_BIT		12
+#define DDRC_CTRL_PDT_MASK		(0x7 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_DIS		(0 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_8			(1 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_16		(2 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_32		(3 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_64		(4 << DDRC_CTRL_PDT_BIT)
+#define DDRC_CTRL_PDT_128		(5 << DDRC_CTRL_PDT_BIT)
+
+#define DDRC_CTRL_PRET_BIT		8
+#define DDRC_CTRL_PRET_MASK		(0x7 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_DIS		(0 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_8		(1 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_16		(2 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_32		(3 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_64		(4 << DDRC_CTRL_PRET_BIT)
+#define DDRC_CTRL_PRET_128		(5 << DDRC_CTRL_PRET_BIT)
+
+#define DDRC_CTRL_DPD			BIT(6)
+#define DDRC_CTRL_SR			BIT(5)
+#define DDRC_CTRL_UNALIGN		BIT(4)
+#define DDRC_CTRL_ALH			BIT(3)
+#define DDRC_CTRL_RDC			BIT(2)
+#define DDRC_CTRL_CKE			BIT(1)
+#define DDRC_CTRL_RESET			BIT(0)
+
+/* DDRC Load-Mode-Register */
+#define DDRC_LMR_DDR_ADDR_BIT		16
+#define DDRC_LMR_DDR_ADDR_MASK		(0x3fff << DDRC_LMR_DDR_ADDR_BIT)
+
+#define DDRC_LMR_BA_BIT			8
+#define DDRC_LMR_BA_MASK		(0x7 << DDRC_LMR_BA_BIT)
+/* For DDR2 */
+#define DDRC_LMR_BA_MRS			(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS1		(1 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS2		(2 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_EMRS3		(3 << DDRC_LMR_BA_BIT)
+/* For mobile DDR */
+#define DDRC_LMR_BA_M_MRS		(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_M_EMRS		(2 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_M_SR		(1 << DDRC_LMR_BA_BIT)
+/* For Normal DDR1 */
+#define DDRC_LMR_BA_N_MRS		(0 << DDRC_LMR_BA_BIT)
+#define DDRC_LMR_BA_N_EMRS		(1 << DDRC_LMR_BA_BIT)
+
+#define DDRC_LMR_CMD_BIT		4
+#define DDRC_LMR_CMD_MASK		(0x3 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_PREC		(0 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_AUREF		(1 << DDRC_LMR_CMD_BIT)
+#define DDRC_LMR_CMD_LMR		(2 << DDRC_LMR_CMD_BIT)
+
+#define DDRC_LMR_START			BIT(0)
+
+/* DDRC Timing Config Register 1 */
+#define DDRC_TIMING1_TRTP_BIT		24
+#define DDRC_TIMING1_TRTP_MASK		(0x3f << DDRC_TIMING1_TRTP_BIT)
+#define DDRC_TIMING1_TWTR_BIT		16
+#define DDRC_TIMING1_TWTR_MASK		(0x3f << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_1		(0 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_2		(1 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_3		(2 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWTR_4		(3 << DDRC_TIMING1_TWTR_BIT)
+#define DDRC_TIMING1_TWR_BIT		8
+#define DDRC_TIMING1_TWR_MASK		(0x3f << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_1		(0 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_2		(1 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_3		(2 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_4		(3 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_5		(4 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWR_6		(5 << DDRC_TIMING1_TWR_BIT)
+#define DDRC_TIMING1_TWL_BIT		0
+#define DDRC_TIMING1_TWL_MASK		(0x3f << DDRC_TIMING1_TWL_BIT)
+
+/* DDRC Timing Config Register 2 */
+#define DDRC_TIMING2_TCCD_BIT		24
+#define DDRC_TIMING2_TCCD_MASK		(0x3f << DDRC_TIMING2_TCCD_BIT)
+#define DDRC_TIMING2_TRAS_BIT		16
+#define DDRC_TIMING2_TRAS_MASK		(0x3f << DDRC_TIMING2_TRAS_BIT)
+#define DDRC_TIMING2_TRCD_BIT		8
+#define DDRC_TIMING2_TRCD_MASK		(0x3f << DDRC_TIMING2_TRCD_BIT)
+#define DDRC_TIMING2_TRL_BIT		0
+#define DDRC_TIMING2_TRL_MASK		(0x3f << DDRC_TIMING2_TRL_BIT)
+
+/* DDRC Timing Config Register 3 */
+#define DDRC_TIMING3_ONUM		27
+#define DDRC_TIMING3_TCKSRE_BIT		24
+#define DDRC_TIMING3_TCKSRE_MASK	(0x3f << DDRC_TIMING3_TCKSRE_BIT)
+#define DDRC_TIMING3_TRP_BIT		16
+#define DDRC_TIMING3_TRP_MASK		(0x3f << DDRC_TIMING3_TRP_BIT)
+#define DDRC_TIMING3_TRRD_BIT		8
+#define DDRC_TIMING3_TRRD_MASK		(0x3f << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_DISABLE	(0 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_2		(1 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_3		(2 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRRD_4		(3 << DDRC_TIMING3_TRRD_BIT)
+#define DDRC_TIMING3_TRC_BIT		0
+#define DDRC_TIMING3_TRC_MASK		(0x3f << DDRC_TIMING3_TRC_BIT)
+
+/* DDRC Timing Config Register 4 */
+#define DDRC_TIMING4_TRFC_BIT		24
+#define DDRC_TIMING4_TRFC_MASK		(0x3f << DDRC_TIMING4_TRFC_BIT)
+#define DDRC_TIMING4_TEXTRW_BIT		21
+#define DDRC_TIMING4_TEXTRW_MASK	(0x7 << DDRC_TIMING4_TEXTRW_BIT)
+#define DDRC_TIMING4_TRWCOV_BIT		19
+#define DDRC_TIMING4_TRWCOV_MASK	(0x3 << DDRC_TIMING4_TRWCOV_BIT)
+#define DDRC_TIMING4_TCKE_BIT		16
+#define DDRC_TIMING4_TCKE_MASK		(0x7 << DDRC_TIMING4_TCKE_BIT)
+#define DDRC_TIMING4_TMINSR_BIT		8
+#define DDRC_TIMING4_TMINSR_MASK	(0xf << DDRC_TIMING4_TMINSR_BIT)
+#define DDRC_TIMING4_TXP_BIT		4
+#define DDRC_TIMING4_TXP_MASK		(0x7 << DDRC_TIMING4_TXP_BIT)
+#define DDRC_TIMING4_TMRD_BIT		0
+#define DDRC_TIMING4_TMRD_MASK		(0x3 << DDRC_TIMING4_TMRD_BIT)
+
+/* DDRC Timing Config Register 5 */
+#define DDRC_TIMING5_TCTLUPD_BIT	24
+#define DDRC_TIMING4_TCTLUPD_MASK	(0x3f << DDRC_TIMING5_TCTLUDP_BIT)
+#define DDRC_TIMING5_TRTW_BIT		16
+#define DDRC_TIMING5_TRTW_MASK		(0x3f << DDRC_TIMING5_TRTW_BIT)
+#define DDRC_TIMING5_TRDLAT_BIT		8
+#define DDRC_TIMING5_TRDLAT_MASK	(0x3f << DDRC_TIMING5_TRDLAT_BIT)
+#define DDRC_TIMING5_TWDLAT_BIT		0
+#define DDRC_TIMING5_TWDLAT_MASK	(0x3f << DDRC_TIMING5_TWDLAT_BIT)
+
+/* DDRC Timing Config Register 6 */
+#define DDRC_TIMING6_TXSRD_BIT		24
+#define DDRC_TIMING6_TXSRD_MASK		(0x3f << DDRC_TIMING6_TXSRD_BIT)
+#define DDRC_TIMING6_TFAW_BIT		16
+#define DDRC_TIMING6_TFAW_MASK		(0x3f << DDRC_TIMING6_TFAW_BIT)
+#define DDRC_TIMING6_TCFGW_BIT		8
+#define DDRC_TIMING6_TCFGW_MASK		(0x3f << DDRC_TIMING6_TCFGW_BIT)
+#define DDRC_TIMING6_TCFGR_BIT		0
+#define DDRC_TIMING6_TCFGR_MASK		(0x3f << DDRC_TIMING6_TCFGR_BIT)
+
+/* DDRC  Auto-Refresh Counter */
+#define DDRC_REFCNT_CON_BIT		16
+#define DDRC_REFCNT_CON_MASK		(0xff << DDRC_REFCNT_CON_BIT)
+#define DDRC_REFCNT_CNT_BIT		8
+#define DDRC_REFCNT_CNT_MASK		(0xff << DDRC_REFCNT_CNT_BIT)
+#define DDRC_REFCNT_CLKDIV_BIT		1
+#define DDRC_REFCNT_CLKDIV_MASK		(0x7 << DDRC_REFCNT_CLKDIV_BIT)
+#define DDRC_REFCNT_REF_EN		BIT(0)
+
+/* DDRC DQS Delay Control Register */
+#define DDRC_DQS_ERROR			BIT(29)
+#define DDRC_DQS_READY			BIT(28)
+#define DDRC_DQS_AUTO			BIT(23)
+#define DDRC_DQS_DET			BIT(24)
+#define DDRC_DQS_SRDET			BIT(25)
+#define DDRC_DQS_CLKD_BIT		16
+#define DDRC_DQS_CLKD_MASK		(0x3f << DDRC_DQS_CLKD_BIT)
+#define DDRC_DQS_WDQS_BIT		8
+#define DDRC_DQS_WDQS_MASK		(0x3f << DDRC_DQS_WDQS_BIT)
+#define DDRC_DQS_RDQS_BIT		0
+#define DDRC_DQS_RDQS_MASK		(0x3f << DDRC_DQS_RDQS_BIT)
+
+/* DDRC DQS Delay Adjust Register */
+#define DDRC_DQS_ADJWDQS_BIT		8
+#define DDRC_DQS_ADJWDQS_MASK		(0x1f << DDRC_DQS_ADJWDQS_BIT)
+#define DDRC_DQS_ADJRDQS_BIT		0
+#define DDRC_DQS_ADJRDQS_MASK		(0x1f << DDRC_DQS_ADJRDQS_BIT)
+
+/* DDRC Memory Map Config Register */
+#define DDRC_MMAP_BASE_BIT		8
+#define DDRC_MMAP_BASE_MASK		(0xff << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP_MASK_BIT		0
+#define DDRC_MMAP_MASK_MASK		(0xff << DDRC_MMAP_MASK_BIT)
+
+#define DDRC_MMAP0_BASE			(0x20 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_64M		(0x24 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_128M		(0x28 << DDRC_MMAP_BASE_BIT)
+#define DDRC_MMAP1_BASE_256M		(0x30 << DDRC_MMAP_BASE_BIT)
+
+#define DDRC_MMAP_MASK_64_64		(0xfc << DDRC_MMAP_MASK_BIT)
+#define DDRC_MMAP_MASK_128_128		(0xf8 << DDRC_MMAP_MASK_BIT)
+#define DDRC_MMAP_MASK_256_256		(0xf0 << DDRC_MMAP_MASK_BIT)
+
+/* DDRP PHY Initialization Register */
+#define DDRP_PIR_INIT			BIT(0)
+#define DDRP_PIR_DLLSRST		BIT(1)
+#define DDRP_PIR_DLLLOCK		BIT(2)
+#define DDRP_PIR_ZCAL			BIT(3)
+#define DDRP_PIR_ITMSRST		BIT(4)
+#define DDRP_PIR_DRAMRST		BIT(5)
+#define DDRP_PIR_DRAMINT		BIT(6)
+#define DDRP_PIR_QSTRN			BIT(7)
+#define DDRP_PIR_EYETRN			BIT(8)
+#define DDRP_PIR_DLLBYP			BIT(17)
+/* DDRP PHY General Configurate Register */
+#define DDRP_PGCR_ITMDMD		BIT(0)
+#define DDRP_PGCR_DQSCFG		BIT(1)
+#define DDRP_PGCR_DFTCMP		BIT(2)
+#define DDRP_PGCR_DFTLMT_BIT		3
+#define DDRP_PGCR_DTOSEL_BIT		5
+#define DDRP_PGCR_CKEN_BIT		9
+#define DDRP_PGCR_CKDV_BIT		12
+#define DDRP_PGCR_CKINV			BIT(14)
+#define DDRP_PGCR_RANKEN_BIT		18
+#define DDRP_PGCR_ZCKSEL_32		(2 << 22)
+#define DDRP_PGCR_PDDISDX		BIT(24)
+/* DDRP PHY General Status Register */
+#define DDRP_PGSR_IDONE			BIT(0)
+#define DDRP_PGSR_DLDONE		BIT(1)
+#define DDRP_PGSR_ZCDONE		BIT(2)
+#define DDRP_PGSR_DIDONE		BIT(3)
+#define DDRP_PGSR_DTDONE		BIT(4)
+#define DDRP_PGSR_DTERR			BIT(5)
+#define DDRP_PGSR_DTIERR		BIT(6)
+#define DDRP_PGSR_DFTEERR		BIT(7)
+/* DDRP DRAM Configuration Register */
+#define DDRP_DCR_TYPE_BIT		0
+#define DDRP_DCR_TYPE_MASK		(0x7 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_MDDR		(0 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR		(1 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR2		(2 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_DDR3		(3 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_TYPE_LPDDR2		(4 << DDRP_DCR_TYPE_BIT)
+#define DDRP_DCR_DDR8BNK_BIT		3
+#define DDRP_DCR_DDR8BNK_MASK		(1 << DDRP_DCR_DDR8BNK_BIT)
+#define DDRP_DCR_DDR8BNK		(1 << DDRP_DCR_DDR8BNK_BIT)
+#define DDRP_DCR_DDR8BNK_DIS		(0 << DDRP_DCR_DDR8BNK_BIT)
+
+#define DRP_DTRP1_RTODT			BIT(11)
+
+#define DDRP_DXGCR_DXEN			BIT(0)
+
+#define DDRP_ZQXCR_ZDEN_BIT		28
+#define DDRP_ZQXCR_ZDEN			(1 << DDRP_ZQXCR_ZDEN_BIT)
+#define DDRP_ZQXCR_PULLUP_IMPE_BIT	5
+#define DDRP_ZQXCR_PULLDOWN_IMPE_BIT	0
+
+/* DDR3 Mode Register Set */
+#define DDR3_MR0_BL_BIT			0
+#define DDR3_MR0_BL_MASK		(3 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_8			(0 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_fly			(1 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BL_4			(2 << DDR3_MR0_BL_BIT)
+#define DDR3_MR0_BT_BIT			3
+#define DDR3_MR0_BT_MASK		(1 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_BT_SEQ			(0 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_BT_INTER		(1 << DDR3_MR0_BT_BIT)
+#define DDR3_MR0_WR_BIT			9
+
+#define DDR3_MR1_DLL_DISABLE		1
+#define DDR3_MR1_DIC_6			(0 << 5 | 0 << 1)
+#define DDR3_MR1_DIC_7			(0 << 5 | BIT(1))
+#define DDR3_MR1_RTT_DIS		(0 << 9 | 0 << 6 | 0 << 2)
+#define DDR3_MR1_RTT_4			(0 << 9 | 0 << 6 | BIT(2))
+#define DDR3_MR1_RTT_2			(0 << 9 | BIT(6) | 0 << 2)
+#define DDR3_MR1_RTT_6			(0 << 9 | BIT(6) | BIT(2))
+#define DDR3_MR1_RTT_12			(BIT(9) | 0 << 6 | 0 << 2)
+#define DDR3_MR1_RTT_8			(BIT(9) | 0 << 6 | BIT(2))
+
+#define DDR3_MR2_CWL_BIT		3
+
+/* Parameters common to all RAM devices used */
+
+/* Chip Select */
+/* CSEN : whether a ddr chip exists 0 - un-used, 1 - used */
+#define DDR_CS0EN	1
+/* CSEN : whether a ddr chip exists 0 - un-used, 1 - used */
+#define DDR_CS1EN	0
+
+/* ROW : 12 to 18 row address, 1G only 512MB */
+#define DDR_ROW		15
+/* COL :  8 to 14 column address */
+#define DDR_COL		10
+/* Banks each chip: 0-4bank, 1-8bank */
+#define DDR_BANK8	1
+/* 0 - 16-bit data width, 1 - 32-bit data width */
+#define DDR_DW32	1
+
+/* Refresh period: 64ms / 32768 = 1.95 us , 2 ^ 15 = 32768 */
+#define DDR_tREFI	7800
+/* Clock Divider */
+#define DDR_CLK_DIV	1
+
+/* DDR3 Burst length: 0 - 8 burst, 2 - 4 burst , 1 - 4 or 8 (on the fly) */
+#define DDR_BL		8
+
+/* CAS latency: 5 to 14, tCK */
+#define DDR_CL		6
+/* DDR3 only: CAS Write Latency, 5 to 8 */
+#define DDR_tCWL	(DDR_CL - 1)
+
+/* Structure representing per-RAM type configuration */
+
+struct jz4780_ddr_config {
+	u32	timing[6];	/* Timing1..6 register value */
+
+	/* DDR PHY control */
+	u16	mr0;	/* Mode Register 0 */
+	u16	mr1;	/* Mode Register 1 */
+
+	u32	ptr0;	/* PHY Timing Register 0 */
+	u32	ptr1;	/* PHY Timing Register 1 */
+	u32	ptr2;	/* PHY Timing Register 1 */
+
+	u32	dtpr0;	/* DRAM Timing Parameters Register 0 */
+	u32	dtpr1;	/* DRAM Timing Parameters Register 1 */
+	u32	dtpr2;	/* DRAM Timing Parameters Register 2 */
+
+	u8	pullup;	/* PHY pullup impedance */
+	u8	pulldn;	/* PHY pulldown impedance */
+};
+
+void pll_init(void);
+void sdram_init(void);
+
+#endif	/* __JZ4780_DRAM_H__ */
+
diff --git a/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h b/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h
new file mode 100644
index 0000000..37f0892
--- /dev/null
+++ b/arch/mips/mach-jz47xx/include/mach/jz4780_gpio.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef __JZ4780_GPIO_H__
+#define __JZ4780_GPIO_H__
+
+#define JZ_GPIO(bank, pin) ((32 * (bank)) + (pin))
+
+int jz47xx_gpio_get_value(unsigned int gpio);
+void jz47xx_gpio_direction_input(unsigned int gpio);
+void jz47xx_gpio_direction_output(unsigned int gpio, int value);
+
+#endif
diff --git a/arch/mips/mach-jz47xx/jz4780/Makefile b/arch/mips/mach-jz47xx/jz4780/Makefile
new file mode 100644
index 0000000..5b3c354
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y := gpio.o jz4780.o pll.o reset.o sdram.o timer.o
diff --git a/arch/mips/mach-jz47xx/jz4780/TODO b/arch/mips/mach-jz47xx/jz4780/TODO
new file mode 100644
index 0000000..99ad622
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/TODO
@@ -0,0 +1,4 @@
+- dm gpio driver
+- ethernet driver for the dm9000
+- reduce the hundreds of definitions of register addresses to the ones really needed in assembly or SPL.
+- define the remaining register base addresses as physical addresses and establish a mapping with ioremap_nocache()
diff --git a/arch/mips/mach-jz47xx/jz4780/gpio.c b/arch/mips/mach-jz47xx/jz4780/gpio.c
new file mode 100644
index 0000000..cee2328
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/gpio.c
@@ -0,0 +1,39 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+int jz47xx_gpio_get_value(unsigned int gpio)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	return readl(gpio_regs + GPIO_PXPIN(port)) & BIT(pin);
+}
+
+void jz47xx_gpio_direction_input(unsigned int gpio)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXPAT1S(port));
+}
+
+void jz47xx_gpio_direction_output(unsigned int gpio, int value)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int port = gpio / 32;
+	int pin = gpio % 32;
+
+	writel(BIT(pin), gpio_regs + GPIO_PXINTC(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXMASKS(port));
+	writel(BIT(pin), gpio_regs + GPIO_PXPAT1C(port));
+	writel(BIT(pin), gpio_regs +
+			 (value ? GPIO_PXPAT0S(port) : GPIO_PXPAT0C(port)));
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/jz4780.c b/arch/mips/mach-jz47xx/jz4780/jz4780.c
new file mode 100644
index 0000000..dbd328c
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/jz4780.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <asm/sections.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+#include <mmc.h>
+#include <spl.h>
+
+#ifdef CONFIG_SPL_BUILD
+/* Pointer to the global data structure for SPL */
+DECLARE_GLOBAL_DATA_PTR;
+gd_t gdata __attribute__ ((section(".bss")));
+
+void board_init_f(ulong dummy)
+{
+	typedef void __noreturn (*image_entry_noargs_t)(void);
+	struct mmc *mmc;
+	unsigned long count;
+	struct image_header *header;
+	int ret;
+
+	/* Set global data pointer */
+	gd = &gdata;
+
+	timer_init();
+	pll_init();
+	sdram_init();
+	enable_caches();
+
+	/* Clear the BSS */
+	memset(__bss_start, 0, (char *)&__bss_end - __bss_start);
+
+	gd->flags |= GD_FLG_SPL_INIT;
+
+	ret = mmc_initialize(NULL);
+	if (ret)
+		hang();
+
+	mmc = find_mmc_device(BOOT_DEVICE_MMC1);
+	if (ret)
+		hang();
+
+	ret = mmc_init(mmc);
+	if (ret)
+		hang();
+
+	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
+					 sizeof(struct image_header));
+
+	count = blk_dread(mmc_get_blk_desc(mmc),
+			  CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR,
+		0x800, header);
+	if (count == 0)
+		hang();
+
+	image_entry_noargs_t image_entry =
+		(image_entry_noargs_t)CONFIG_SYS_TEXT_BASE;
+
+	image_entry();
+
+	hang();
+}
+#endif /* CONFIG_SPL_BUILD */
+
+ulong board_get_usable_ram_top(ulong total_size)
+{
+	return CONFIG_SYS_SDRAM_BASE + (256 * 1024 * 1024);
+}
+
+int print_cpuinfo(void)
+{
+	printf("CPU:   Ingenic JZ4780\n");
+	return 0;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/pll.c b/arch/mips/mach-jz47xx/jz4780/pll.c
new file mode 100644
index 0000000..9a46198
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/pll.c
@@ -0,0 +1,530 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 PLL setup
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+#define CPM_CPCCR		0x00
+#define CPM_LCR			0x04
+#define CPM_RSR			0x08
+#define CPM_CPPCR		0x0c
+#define CPM_CPAPCR		0x10
+#define CPM_CPMPCR		0x14
+#define CPM_CPEPCR		0x18
+#define CPM_CPVPCR		0x1c
+#define CPM_CLKGR0		0x20
+#define CPM_OPCR		0x24
+#define CPM_CLKGR1		0x28
+#define CPM_DDCDR		0x2c
+#define CPM_VPUCDR		0x30
+#define CPM_CPSPR		0x34
+#define CPM_CPSPPR		0x38
+#define CPM_USBPCR		0x3c
+#define CPM_USBRDT		0x40
+#define CPM_USBVBFIL		0x44
+#define CPM_USBPCR1		0x48
+#define CPM_USBCDR		0x50
+#define CPM_LPCDR		0x54
+#define CPM_I2SCDR		0x60
+#define CPM_LPCDR1		0x64
+#define CPM_MSCCDR		0x68
+#define CPM_UHCCDR		0x6c
+#define CPM_SSICDR		0x74
+#define CPM_CIMCDR		0x7c
+#define CPM_PCMCDR		0x84
+#define CPM_GPUCDR		0x88
+#define CPM_HDMICDR		0x8c
+#define CPM_I2S1CDR		0xa0
+#define CPM_MSCCDR1		0xa4
+#define CPM_MSCCDR2		0xa8
+#define CPM_BCHCDR		0xac
+#define CPM_SPCR0		0xb8
+#define CPM_SPCR1		0xbc
+#define CPM_CPCSR		0xd4
+#define CPM_PSWCST(n)		((0x4 * (n)) + 0x90)
+
+/* Clock control register */
+#define CPM_CPCCR_SEL_SRC_BIT		30
+#define CPM_CPCCR_SEL_SRC_MASK		(0x3 << CPM_CPCCR_SEL_SRC_BIT)
+#define CPM_SRC_SEL_STOP		0
+#define CPM_SRC_SEL_APLL		1
+#define CPM_SRC_SEL_EXCLK		2
+#define CPM_SRC_SEL_RTCLK		3
+#define CPM_CPCCR_SEL_CPLL_BIT		28
+#define CPM_CPCCR_SEL_CPLL_MASK		(0x3 << CPM_CPCCR_SEL_CPLL_BIT)
+#define CPM_CPCCR_SEL_H0PLL_BIT		26
+#define CPM_CPCCR_SEL_H0PLL_MASK	(0x3 << CPM_CPCCR_SEL_H0PLL_BIT)
+#define CPM_CPCCR_SEL_H2PLL_BIT		24
+#define CPM_CPCCR_SEL_H2PLL_MASK	(0x3 << CPM_CPCCR_SEL_H2PLL_BIT)
+#define CPM_PLL_SEL_STOP		0
+#define CPM_PLL_SEL_SRC			1
+#define CPM_PLL_SEL_MPLL		2
+#define CPM_PLL_SEL_EPLL		3
+#define CPM_CPCCR_CE_CPU		(0x1 << 22)
+#define CPM_CPCCR_CE_AHB0		(0x1 << 21)
+#define CPM_CPCCR_CE_AHB2		(0x1 << 20)
+#define CPM_CPCCR_PDIV_BIT		16
+#define CPM_CPCCR_PDIV_MASK		(0xf << CPM_CPCCR_PDIV_BIT)
+#define CPM_CPCCR_H2DIV_BIT		12
+#define CPM_CPCCR_H2DIV_MASK		(0xf << CPM_CPCCR_H2DIV_BIT)
+#define CPM_CPCCR_H0DIV_BIT		8
+#define CPM_CPCCR_H0DIV_MASK		(0x0f << CPM_CPCCR_H0DIV_BIT)
+#define CPM_CPCCR_L2DIV_BIT		4
+#define CPM_CPCCR_L2DIV_MASK		(0x0f << CPM_CPCCR_L2DIV_BIT)
+#define CPM_CPCCR_CDIV_BIT		0
+#define CPM_CPCCR_CDIV_MASK		(0x0f << CPM_CPCCR_CDIV_BIT)
+
+/* Clock Status register */
+#define CPM_CPCSR_H2DIV_BUSY		BIT(2)
+#define CPM_CPCSR_H0DIV_BUSY		BIT(1)
+#define CPM_CPCSR_CDIV_BUSY		BIT(0)
+
+/* PLL control register */
+#define CPM_CPPCR_PLLST_BIT		0
+#define CPM_CPPCR_PLLST_MASK		(0xff << CPM_CPPCR_PLLST_BIT)
+
+/* XPLL control register */
+#define CPM_CPXPCR_XPLLM_BIT		19
+#define CPM_CPXPCR_XPLLM_MASK		(0x1fff << CPM_CPXPCR_XPLLM_BIT)
+#define CPM_CPXPCR_XPLLN_BIT		13
+#define CPM_CPXPCR_XPLLN_MASK		(0x3f << CPM_CPXPCR_XPLLN_BIT)
+#define CPM_CPXPCR_XPLLOD_BIT		9
+#define CPM_CPXPCR_XPLLOD_MASK		(0xf << CPM_CPXPCR_XPLLOD_BIT)
+#define CPM_CPXPCR_XLOCK		BIT(6)
+#define CPM_CPXPCR_XPLL_ON		BIT(4)
+#define CPM_CPXPCR_XF_MODE		BIT(3)
+#define CPM_CPXPCR_XPLLBP		BIT(1)
+#define CPM_CPXPCR_XPLLEN		BIT(0)
+
+/* CPM scratch protected register */
+#define CPM_CPSPPR_BIT			0
+#define CPM_CPSPPR_MASK			(0xffff << CPM_CPSPPR_BIT)
+
+/* USB parameter control register */
+#define CPM_USBPCR_USB_MODE		BIT(31)  /* 1: OTG, 0: UDC*/
+#define CPM_USBPCR_AVLD_REG		BIT(30)
+#define CPM_USBPCR_IDPULLUP_MASK_BIT	28
+#define CPM_USBPCR_IDPULLUP_MASK_MASK	(0x02 << IDPULLUP_MASK_BIT)
+#define CPM_USBPCR_INCR_MASK		BIT(27)
+#define CPM_USBPCR_CLK12_EN		BIT(26)
+#define CPM_USBPCR_COMMONONN		BIT(25)
+#define CPM_USBPCR_VBUSVLDEXT		BIT(24)
+#define CPM_USBPCR_VBUSVLDEXTSEL	BIT(23)
+#define CPM_USBPCR_POR			BIT(22)
+#define CPM_USBPCR_SIDDQ		BIT(21)
+#define CPM_USBPCR_OTG_DISABLE		BIT(20)
+#define CPM_USBPCR_COMPDISTUNE_BIT	17
+#define CPM_USBPCR_COMPDISTUNE_MASK	(0x07 << COMPDISTUNE_BIT)
+#define CPM_USBPCR_OTGTUNE_BIT		14
+#define CPM_USBPCR_OTGTUNE_MASK		(0x07 << OTGTUNE_BIT)
+#define CPM_USBPCR_SQRXTUNE_BIT		11
+#define CPM_USBPCR_SQRXTUNE_MASK	(0x7x << SQRXTUNE_BIT)
+#define CPM_USBPCR_TXFSLSTUNE_BIT	7
+#define CPM_USBPCR_TXFSLSTUNE_MASK	(0x0f << TXFSLSTUNE_BIT)
+#define CPM_USBPCR_TXPREEMPHTUNE	BIT(6)
+#define CPM_USBPCR_TXRISETUNE_BIT	4
+#define CPM_USBPCR_TXRISETUNE_MASK	(0x03 << TXRISETUNE_BIT)
+#define CPM_USBPCR_TXVREFTUNE_BIT	0
+#define CPM_USBPCR_TXVREFTUNE_MASK	(0x0f << TXVREFTUNE_BIT)
+
+/* DDR memory clock divider register */
+#define CPM_DDRCDR_DCS_BIT		30
+#define CPM_DDRCDR_DCS_MASK		(0x3 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_STOP		(0x0 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_SRC		(0x1 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_DCS_MPLL		(0x2 << CPM_DDRCDR_DCS_BIT)
+#define CPM_DDRCDR_CE_DDR		BIT(29)
+#define CPM_DDRCDR_DDR_BUSY		BIT(28)
+#define CPM_DDRCDR_DDR_STOP		BIT(27)
+#define CPM_DDRCDR_DDRDIV_BIT		0
+#define CPM_DDRCDR_DDRDIV_MASK		(0xf << CPM_DDRCDR_DDRDIV_BIT)
+
+/* USB reset detect timer register */
+#define CPM_USBRDT_VBFIL_LD_EN		BIT(25)
+#define CPM_USBRDT_IDDIG_EN		BIT(24)
+#define CPM_USBRDT_IDDIG_REG		BIT(23)
+#define CPM_USBRDT_USBRDT_BIT		0
+#define CPM_USBRDT_USBRDT_MASK		(0x7fffff << CPM_USBRDT_USBRDT_BIT)
+
+/* USB OTG PHY clock divider register */
+#define CPM_USBCDR_UCS			BIT(31)
+#define CPM_USBCDR_UPCS			BIT(30)
+#define CPM_USBCDR_CEUSB		BIT(29)
+#define CPM_USBCDR_USB_BUSY		BIT(28)
+#define CPM_USBCDR_OTGDIV_BIT		0
+#define CPM_USBCDR_OTGDIV_MASK		(0xff << CPM_USBCDR_OTGDIV_BIT)
+
+/* I2S device clock divider register */
+#define CPM_I2SCDR_I2CS			BIT(31)
+#define CPM_I2SCDR_I2PCS		BIT(30)
+#define CPM_I2SCDR_I2SDIV_BIT		0
+#define CPM_I2SCDR_I2SDIV_MASK		(0x1ff << CPM_I2SCDR_I2SDIV_BIT)
+
+/* LCD0 pix clock divider register */
+#define CPM_LPCDR_LPCS_BIT		30
+#define CPM_LPCDR_LPCS_MASK		(0x3 << CPM_LPCDR_LPCS_BIT)
+#define CPM_LPCDR_CELCD			BIT(28)
+#define CPM_LPCDR_LCD_BUSY		BIT(27)
+#define CPM_LPCDR_LCD_STOP		BIT(26)
+#define CPM_LPCDR_PIXDIV_BIT		0
+#define CPM_LPCDR_PIXDIV_MASK		(0xff << CPM_LPCDR_PIXDIV_BIT)
+
+/* MSC clock divider register */
+#define CPM_MSCCDR_MPCS_BIT		30
+#define CPM_MSCCDR_MPCS_MASK		(3 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_STOP		(0x0 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_SRC		(0x1 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_MPCS_MPLL		(0x2 << CPM_MSCCDR_MPCS_BIT)
+#define CPM_MSCCDR_CE			BIT(29)
+#define CPM_MSCCDR_MSC_BUSY		BIT(28)
+#define CPM_MSCCDR_MSC_STOP		BIT(27)
+#define CPM_MSCCDR_MSC_CLK0_SEL		BIT(15)
+#define CPM_MSCCDR_MSCDIV_BIT		0
+#define CPM_MSCCDR_MSCDIV_MASK		(0xff << CPM_MSCCDR_MSCDIV_BIT)
+
+/* UHC 48M clock divider register */
+#define CPM_UHCCDR_UHCS_BIT		30
+#define CPM_UHCCDR_UHCS_MASK		(0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_SRC		(0x0 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_MPLL		(0x1 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_EPLL		(0x2 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_UHCS_OTG		(0x3 << CPM_UHCCDR_UHCS_BIT)
+#define CPM_UHCCDR_CE_UHC		BIT(29)
+#define CPM_UHCCDR_UHC_BUSY		BIT(28)
+#define CPM_UHCCDR_UHC_STOP		BIT(27)
+#define CPM_UHCCDR_UHCDIV_BIT		0
+#define CPM_UHCCDR_UHCDIV_MASK		(0xff << CPM_UHCCDR_UHCDIV_BIT)
+
+/* SSI clock divider register */
+#define CPM_SSICDR_SCS			BIT(31)
+#define CPM_SSICDR_SSIDIV_BIT		0
+#define CPM_SSICDR_SSIDIV_MASK		(0x3f << CPM_SSICDR_SSIDIV_BIT)
+
+/* CIM MCLK clock divider register */
+#define CPM_CIMCDR_CIMDIV_BIT		0
+#define CPM_CIMCDR_CIMDIV_MASK		(0xff << CPM_CIMCDR_CIMDIV_BIT)
+
+/* GPS clock divider register */
+#define CPM_GPSCDR_GPCS			BIT(31)
+#define CPM_GPSCDR_GPSDIV_BIT		0
+#define CPM_GSPCDR_GPSDIV_MASK		(0xf << CPM_GPSCDR_GPSDIV_BIT)
+
+/* PCM device clock divider register */
+#define CPM_PCMCDR_PCMS			BIT(31)
+#define CPM_PCMCDR_PCMPCS		BIT(30)
+#define CPM_PCMCDR_PCMDIV_BIT		0
+#define CPM_PCMCDR_PCMDIV_MASK		(0x1ff << CPM_PCMCDR_PCMDIV_BIT)
+
+/* GPU clock divider register */
+#define CPM_GPUCDR_GPCS			BIT(31)
+#define CPM_GPUCDR_GPUDIV_BIT		0
+#define CPM_GPUCDR_GPUDIV_MASK		(0x7 << CPM_GPUCDR_GPUDIV_BIT)
+
+/* HDMI clock divider register */
+#define CPM_HDMICDR_HPCS_BIT		30
+#define CPM_HDMICDR_HPCS_MASK		(0x3 << CPM_HDMICDR_HPCS_BIT)
+#define CPM_HDMICDR_CEHDMI		BIT(29)
+#define CPM_HDMICDR_HDMI_BUSY		BIT(28)
+#define CPM_HDMICDR_HDMI_STOP		BIT(26)
+#define CPM_HDMICDR_HDMIDIV_BIT		0
+#define CPM_HDMICDR_HDMIDIV_MASK	(0xff << CPM_HDMICDR_HDMIDIV_BIT)
+
+/* Low Power Control Register */
+#define CPM_LCR_PD_SCPU			BIT(31)
+#define CPM_LCR_PD_VPU			BIT(30)
+#define CPM_LCR_PD_GPU			BIT(29)
+#define CPM_LCR_PD_GPS			BIT(28)
+#define CPM_LCR_SCPUS			BIT(27)
+#define CPM_LCR_VPUS			BIT(26)
+#define CPM_LCR_GPUS			BIT(25)
+#define CPM_LCR_GPSS			BIT(24)
+#define CPM_LCR_GPU_IDLE		BIT(20)
+#define CPM_LCR_PST_BIT			8
+#define CPM_LCR_PST_MASK		(0xfff << CPM_LCR_PST_BIT)
+#define CPM_LCR_DOZE_DUTY_BIT		3
+#define CPM_LCR_DOZE_DUTY_MASK		(0x1f << CPM_LCR_DOZE_DUTY_BIT)
+#define CPM_LCR_DOZE_ON			BIT(2)
+#define CPM_LCR_LPM_BIT			0
+#define CPM_LCR_LPM_MASK		(0x3 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_IDLE		(0x0 << CPM_LCR_LPM_BIT)
+#define CPM_LCR_LPM_SLEEP		(0x1 << CPM_LCR_LPM_BIT)
+
+/* Clock Gate Register0 */
+#define CPM_CLKGR0_DDR1			BIT(31)
+#define CPM_CLKGR0_DDR0			BIT(30)
+#define CPM_CLKGR0_IPU			BIT(29)
+#define CPM_CLKGR0_LCD1			BIT(28)
+#define CPM_CLKGR0_LCD			BIT(27)
+#define CPM_CLKGR0_CIM			BIT(26)
+#define CPM_CLKGR0_I2C2			BIT(25)
+#define CPM_CLKGR0_UHC			BIT(24)
+#define CPM_CLKGR0_MAC			BIT(23)
+#define CPM_CLKGR0_GPS			BIT(22)
+#define CPM_CLKGR0_PDMAC		BIT(21)
+#define CPM_CLKGR0_SSI2			BIT(20)
+#define CPM_CLKGR0_SSI1			BIT(19)
+#define CPM_CLKGR0_UART3		BIT(18)
+#define CPM_CLKGR0_UART2		BIT(17)
+#define CPM_CLKGR0_UART1		BIT(16)
+#define CPM_CLKGR0_UART0		BIT(15)
+#define CPM_CLKGR0_SADC			BIT(14)
+#define CPM_CLKGR0_KBC			BIT(13)
+#define CPM_CLKGR0_MSC2			BIT(12)
+#define CPM_CLKGR0_MSC1			BIT(11)
+#define CPM_CLKGR0_OWI			BIT(10)
+#define CPM_CLKGR0_TSSI			BIT(9)
+#define CPM_CLKGR0_AIC			BIT(8)
+#define CPM_CLKGR0_SCC			BIT(7)
+#define CPM_CLKGR0_I2C1			BIT(6)
+#define CPM_CLKGR0_I2C0			BIT(5)
+#define CPM_CLKGR0_SSI0			BIT(4)
+#define CPM_CLKGR0_MSC0			BIT(3)
+#define CPM_CLKGR0_OTG			BIT(2)
+#define CPM_CLKGR0_BCH			BIT(1)
+#define CPM_CLKGR0_NEMC			BIT(0)
+
+/* Clock Gate Register1 */
+#define CPM_CLKGR1_P1			BIT(15)
+#define CPM_CLKGR1_X2D			BIT(14)
+#define CPM_CLKGR1_DES			BIT(13)
+#define CPM_CLKGR1_I2C4			BIT(12)
+#define CPM_CLKGR1_AHB			BIT(11)
+#define CPM_CLKGR1_UART4		BIT(10)
+#define CPM_CLKGR1_HDMI			BIT(9)
+#define CPM_CLKGR1_OTG1			BIT(8)
+#define CPM_CLKGR1_GPVLC		BIT(7)
+#define CPM_CLKGR1_AIC1			BIT(6)
+#define CPM_CLKGR1_COMPRES		BIT(5)
+#define CPM_CLKGR1_GPU			BIT(4)
+#define CPM_CLKGR1_PCM			BIT(3)
+#define CPM_CLKGR1_VPU			BIT(2)
+#define CPM_CLKGR1_TSSI1		BIT(1)
+#define CPM_CLKGR1_I2C3			BIT(0)
+
+/* Oscillator and Power Control Register */
+#define CPM_OPCR_O1ST_BIT		8
+#define CPM_OPCR_O1ST_MASK		(0xff << CPM_OPCR_O1ST_BIT)
+#define CPM_OPCR_SPENDN			BIT(7)
+#define CPM_OPCR_GPSEN			BIT(6)
+#define CPM_OPCR_SPENDH			BIT(5)
+#define CPM_OPCR_O1SE			BIT(4)
+#define CPM_OPCR_ERCS			BIT(2) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+#define CPM_OPCR_USBM			BIT(0) /* 0: select EXCLK/512 clock, 1: RTCLK clock */
+
+/* Reset Status Register */
+#define CPM_RSR_P0R			BIT(2)
+#define CPM_RSR_WR			BIT(1)
+#define CPM_RSR_PR			BIT(0)
+
+/* BCH clock divider register */
+#define CPM_BCHCDR_BPCS_BIT		30
+#define CPM_BCHCDR_BPCS_MASK		(0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_STOP		(0X0 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_SRC_CLK		(0x1 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_MPLL		(0x2 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_BPCS_EPLL		(0x3 << CPM_BCHCDR_BPCS_BIT)
+#define CPM_BCHCDR_CE_BCH		BIT(29)
+#define CPM_BCHCDR_BCH_BUSY		BIT(28)
+#define CPM_BCHCDR_BCH_STOP		BIT(27)
+#define CPM_BCHCDR_BCHCDR_BIT		0
+#define CPM_BCHCDR_BCHCDR_MASK		(0x7 << CPM_BCHCDR_BCHCDR_BIT)
+
+/* CPM scratch pad protected register(CPSPPR) */
+#define CPSPPR_CPSPR_WRITABLE		0x00005a5a
+#define RECOVERY_SIGNATURE		0x1a1a	/* means "RECY" */
+#define RECOVERY_SIGNATURE_SEC		0x800	/* means "RECY" */
+
+#define REBOOT_SIGNATURE		0x3535	/* means reboot */
+
+/* XPLL control register */
+#define XLOCK		(1 << 6)
+#define XPLL_ON		(1 << 4)
+#define XF_MODE		(1 << 3)
+#define XPLLBP		(1 << 1)
+#define XPLLEN		(1 << 0)
+
+enum PLLS {
+	EXTCLK = 0,
+	APLL,
+	MPLL,
+	EPLL,
+	VPLL,
+};
+
+#define M_N_OD(m, n, od)		\
+		((((m) - 1) << 19) | (((n) - 1) << 13) | (((od) - 1) << 9))
+
+struct cgu_pll_select {
+	u8	reg;
+	u8	pll;
+	u8	pll_shift;
+};
+
+static void pll_init_one(int pll, int m, int n, int od)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	void __iomem *pll_reg = cpm_regs + CPM_CPAPCR + ((pll - 1) * 4);
+
+	setbits_le32(pll_reg, M_N_OD(m, n, od) | XPLLEN);
+
+	/* FIXME */
+	while (!(readl(pll_reg) & XPLL_ON))
+		;
+}
+
+static void cpu_mux_select(int pll)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 clk_ctrl;
+	unsigned int selectplls[] = {
+		CPM_PLL_SEL_STOP,
+		CPM_PLL_SEL_SRC,
+		CPM_PLL_SEL_MPLL,
+		CPM_PLL_SEL_EPLL
+	};
+
+	/* Init CPU, L2CACHE, AHB0, AHB2, APB clock */
+	clk_ctrl = CPM_CPCCR_CE_CPU | CPM_CPCCR_CE_AHB0 | CPM_CPCCR_CE_AHB2 |
+			((6 - 1) << CPM_CPCCR_H2DIV_BIT) |
+			((3 - 1) << CPM_CPCCR_H0DIV_BIT) |
+			((2 - 1) << CPM_CPCCR_L2DIV_BIT) |
+			((1 - 1) << CPM_CPCCR_CDIV_BIT);
+
+	if (CONFIG_SYS_MHZ >= 1000)
+		clk_ctrl |= (12 - 1) << CPM_CPCCR_PDIV_BIT;
+	else
+		clk_ctrl |= (6 - 1) << CPM_CPCCR_PDIV_BIT;
+
+	clrsetbits_le32(cpm_regs + CPM_CPCCR, 0x00ffffff, clk_ctrl);
+
+	while (readl(cpm_regs + CPM_CPCSR) & (CPM_CPCSR_CDIV_BUSY |
+	       CPM_CPCSR_H0DIV_BUSY | CPM_CPCSR_H2DIV_BUSY))
+		;
+
+	clk_ctrl = (selectplls[pll] << CPM_CPCCR_SEL_CPLL_BIT) |
+		   (selectplls[MPLL] << CPM_CPCCR_SEL_H0PLL_BIT) |
+		   (selectplls[MPLL] << CPM_CPCCR_SEL_H2PLL_BIT);
+	if (pll == APLL)
+		clk_ctrl |= CPM_PLL_SEL_SRC << CPM_CPCCR_SEL_SRC_BIT;
+	else
+		clk_ctrl |= CPM_SRC_SEL_EXCLK << CPM_CPCCR_SEL_SRC_BIT;
+
+	clrsetbits_le32(cpm_regs + CPM_CPCCR, 0xff << 24, clk_ctrl);
+}
+
+static void ddr_mux_select(int pll)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	int selectplls[] = { CPM_DDRCDR_DCS_STOP,
+			     CPM_DDRCDR_DCS_SRC,
+			     CPM_DDRCDR_DCS_MPLL};
+
+	writel(selectplls[pll] | CPM_DDRCDR_CE_DDR | (JZ4780_SYS_MEM_DIV - 1),
+	       cpm_regs + CPM_DDCDR);
+
+	while (readl(cpm_regs + CPM_DDCDR) & CPM_DDRCDR_DDR_BUSY)
+		;
+
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_DDR0);
+
+	mdelay(200);
+}
+
+static void cgu_mux_init(struct cgu_pll_select *cgu, unsigned int num)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	unsigned int selectplls[] = {0, 1, 2, 3, 2, 6};
+	int i;
+
+	for (i = 0; i < num; i++)
+		writel(selectplls[cgu[i].pll] << cgu[i].pll_shift,
+		       cpm_regs + cgu[i].reg);
+}
+
+void pll_init(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	struct cgu_pll_select cgu_mux[] = {
+		{ CPM_MSCCDR,  MPLL, 30 },
+		{ CPM_LPCDR,   VPLL, 30 },
+		{ CPM_LPCDR1,  VPLL, 30 },
+		{ CPM_GPUCDR,  MPLL, 30 },
+		{ CPM_HDMICDR, VPLL, 30 },
+		{ CPM_I2SCDR,  EPLL, 30 },
+		{ CPM_BCHCDR,  MPLL, 30 },
+		{ CPM_VPUCDR,  0x1,  30 },
+		{ CPM_UHCCDR,  0x3,  30 },
+		{ CPM_CIMCDR,  0x1,  31 },
+		{ CPM_PCMCDR,  0x5,  29 },
+		{ CPM_SSICDR,  0x3,  30 },
+	};
+
+	/* PLL stable time set to default -- 1ms */
+	clrsetbits_le32(cpm_regs + CPM_CPPCR, 0xfffff, (16 << 8) | 0x20);
+
+	pll_init_one(APLL, JZ4780_APLL_M, JZ4780_APLL_N, JZ4780_APLL_OD);
+	pll_init_one(MPLL, JZ4780_MPLL_M, JZ4780_MPLL_N, JZ4780_MPLL_OD);
+	pll_init_one(VPLL, JZ4780_VPLL_M, JZ4780_VPLL_N, JZ4780_VPLL_OD);
+	pll_init_one(EPLL, JZ4780_EPLL_M, JZ4780_EPLL_N, JZ4780_EPLL_OD);
+
+	cpu_mux_select(MPLL);
+	ddr_mux_select(MPLL);
+	cgu_mux_init(cgu_mux, ARRAY_SIZE(cgu_mux));
+}
+
+const u32 jz4780_clk_get_efuse_clk(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 cpccr = readl(cpm_regs + CPM_CPCCR);
+	u32 ahb2_div = ((cpccr & CPM_CPCCR_H2DIV_MASK) >>
+			CPM_CPCCR_H2DIV_BIT) + 1;
+	return JZ4780_SYS_MEM_SPEED / ahb2_div;
+}
+
+void jz4780_clk_ungate_ethernet(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_MAC);
+	clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_NEMC);
+}
+
+void jz4780_clk_ungate_mmc(void)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 msc_cdr = JZ4780_SYS_MEM_SPEED / 24000000 / 2 - 1;
+
+	msc_cdr |= CPM_MSCCDR_MPCS_MPLL | CPM_MSCCDR_CE;
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR);
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR1);
+	writel(msc_cdr, cpm_regs + CPM_MSCCDR2);
+
+	/* The wait_for_bit() won't fit, thus unbounded loop here. */
+	while (readl(cpm_regs + CPM_MSCCDR1) & CPM_MSCCDR_MSC_BUSY)
+		;
+}
+
+void jz4780_clk_ungate_uart(const unsigned int uart)
+{
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+
+	if (uart == 0)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART0);
+	else if (uart == 1)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART1);
+	else if (uart == 2)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART2);
+	else if (uart == 3)
+		clrbits_le32(cpm_regs + CPM_CLKGR0, CPM_CLKGR0_UART3);
+	else if (uart == 4)
+		clrbits_le32(cpm_regs + CPM_CLKGR1, CPM_CLKGR1_UART4);
+	else
+		printf("%s[%i]: Invalid UART %d\n", __func__, __LINE__, uart);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/reset.c b/arch/mips/mach-jz47xx/jz4780/reset.c
new file mode 100644
index 0000000..73af347
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/reset.c
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 common routines
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+
+/* WDT */
+#define WDT_TDR		0x00
+#define WDT_TCER	0x04
+#define WDT_TCNT	0x08
+#define WDT_TCSR	0x0C
+
+/* Register definition */
+#define WDT_TCSR_PRESCALE_BIT	3
+#define WDT_TCSR_PRESCALE_MASK	(0x7 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE1	(0x0 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE4	(0x1 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE16	(0x2 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE64	(0x3 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE256	(0x4 << WDT_TCSR_PRESCALE_BIT)
+  #define WDT_TCSR_PRESCALE1024	(0x5 << WDT_TCSR_PRESCALE_BIT)
+#define WDT_TCSR_EXT_EN		BIT(2)
+#define WDT_TCSR_RTC_EN		BIT(1)
+#define WDT_TCSR_PCK_EN		BIT(0)
+
+#define WDT_TCER_TCEN		BIT(0)
+
+void _machine_restart(void)
+{
+	void __iomem *wdt_regs = (void __iomem *)WDT_BASE;
+
+	/* EXTAL as the timer clock input. */
+	writew(WDT_TCSR_PRESCALE1 | WDT_TCSR_EXT_EN, wdt_regs + WDT_TCSR);
+
+	/* Reset the WDT counter and timeout. */
+	writew(0, wdt_regs + WDT_TCNT);
+	writew(0, wdt_regs + WDT_TDR);
+
+	jz4780_tcu_wdt_start();
+
+	/* WDT start */
+	writeb(WDT_TCER_TCEN, wdt_regs + WDT_TCER);
+
+	for (;;)
+		;
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/sdram.c b/arch/mips/mach-jz47xx/jz4780/sdram.c
new file mode 100644
index 0000000..5b25c8d
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/sdram.c
@@ -0,0 +1,270 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 DDR initialization
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ *
+ * Based on spl/common/{jz4780_ddr,jz_ddr3_init}.c from X-Boot
+ * Copyright (c) 2006-2013 Ingenic Semiconductor
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+
+static const u32 get_mem_clk(void)
+{
+	const u32 mpll_out = ((u64)JZ4780_SYS_EXTAL * JZ4780_MPLL_M) /
+			     (JZ4780_MPLL_N * JZ4780_MPLL_OD);
+	return mpll_out / JZ4780_SYS_MEM_DIV;
+}
+
+u32 sdram_size(int cs)
+{
+	u32 dw = DDR_DW32 ? 4 : 2;
+	u32 banks = DDR_BANK8 ? 8 : 4;
+	u32 size = 0;
+
+	if ((cs == 0) && DDR_CS0EN) {
+		size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+		if (DDR_CS1EN && (size > 0x20000000))
+			size = 0x20000000;
+	} else if ((cs == 1) && DDR_CS1EN) {
+		size = (1 << (DDR_ROW + DDR_COL)) * dw * banks;
+	}
+
+	return size;
+}
+
+static void ddr_cfg_init(void)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	u32 ddrc_cfg, tmp;
+
+	tmp = DDR_CL;
+	if (tmp)
+		tmp--;
+	if (tmp > 4)
+		tmp = 4;
+
+	ddrc_cfg = DDRC_CFG_TYPE_DDR3 | DDRC_CFG_IMBA |
+		   DDR_DW32 | DDRC_CFG_MPRT | ((tmp | 0x8) << 2) |
+		   ((DDR_ROW - 12) << 11) | ((DDR_COL - 8) << 8) |
+		   (DDR_CS0EN << 6) | (DDR_BANK8 << 1) |
+		   ((DDR_ROW - 12) << 27) | ((DDR_COL - 8) << 24) |
+		   (DDR_CS1EN << 7) | (DDR_BANK8 << 23);
+
+	if (DDR_BL > 4)
+		ddrc_cfg |= BIT(21);
+
+	writel(ddrc_cfg, ddr_ctl_regs + DDRC_CFG);
+}
+
+static void ddr_phy_init(const struct jz4780_ddr_config *ddr_config)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+	unsigned int count = 0, i;
+	u32 reg, mask;
+
+	writel(DDRP_DCR_TYPE_DDR3 | (DDR_BANK8 << 3), ddr_phy_regs + DDRP_DCR);
+
+	writel(ddr_config->mr0, ddr_phy_regs + DDRP_MR0);
+	writel(ddr_config->mr1, ddr_phy_regs + DDRP_MR1);
+	writel(0, ddr_phy_regs + DDRP_ODTCR);
+	writel(0, ddr_phy_regs + DDRP_MR2);
+
+	writel(ddr_config->ptr0, ddr_phy_regs + DDRP_PTR0);
+	writel(ddr_config->ptr1, ddr_phy_regs + DDRP_PTR1);
+	writel(ddr_config->ptr2, ddr_phy_regs + DDRP_PTR2);
+
+	writel(ddr_config->dtpr0, ddr_phy_regs + DDRP_DTPR0);
+	writel(ddr_config->dtpr1, ddr_phy_regs + DDRP_DTPR1);
+	writel(ddr_config->dtpr2, ddr_phy_regs + DDRP_DTPR2);
+
+	writel(DDRP_PGCR_DQSCFG | (7 << DDRP_PGCR_CKEN_BIT) |
+	       (2 << DDRP_PGCR_CKDV_BIT) |
+	       (DDR_CS0EN | (DDR_CS1EN << 1)) << DDRP_PGCR_RANKEN_BIT |
+	       DDRP_PGCR_ZCKSEL_32 | DDRP_PGCR_PDDISDX,
+	       ddr_phy_regs + DDRP_PGCR);
+
+	for (i = 0; i < 8; i++)
+		clrbits_le32(ddr_phy_regs + DDRP_DXGCR(i), 0x3 << 9);
+
+	count = 0;
+	mask = DDRP_PGSR_IDONE | DDRP_PGSR_DLDONE | DDRP_PGSR_ZCDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if ((reg == mask) || (reg == 0x1f))
+			break;
+		if (count++ == 10000)
+			hang();
+	}
+
+	/* DQS extension and early set to 1 */
+	clrsetbits_le32(ddr_phy_regs + DDRP_DSGCR, 0x7E << 4, 0x12 << 4);
+
+	/* 500 pull up and 500 pull down */
+	clrsetbits_le32(ddr_phy_regs + DDRP_DXCCR, 0xFF << 4, 0xC4 << 4);
+
+	/* Initialise phy */
+	writel(DDRP_PIR_INIT | DDRP_PIR_DRAMINT | DDRP_PIR_DRAMRST,
+	       ddr_phy_regs + DDRP_PIR);
+
+	count = 0;
+	mask |= DDRP_PGSR_DIDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if ((reg == mask) || (reg == 0x1f))
+			break;
+		if (count++ == 20000)
+			hang();
+	}
+
+	writel(DDRP_PIR_INIT | DDRP_PIR_QSTRN, ddr_phy_regs + DDRP_PIR);
+
+	count = 0;
+	mask |= DDRP_PGSR_DTDONE;
+	for (;;) {
+		reg = readl(ddr_phy_regs + DDRP_PGSR);
+		if (reg == mask)
+			break;
+		if (count++ != 50000)
+			continue;
+		reg &= DDRP_PGSR_DTDONE | DDRP_PGSR_DTERR | DDRP_PGSR_DTIERR;
+		if (reg)
+			hang();
+		count = 0;
+	}
+
+	/* Override impedance */
+	clrsetbits_le32(ddr_phy_regs + DDRP_ZQXCR0(0), 0x3ff,
+		((ddr_config->pullup & 0x1f) << DDRP_ZQXCR_PULLUP_IMPE_BIT) |
+		((ddr_config->pulldn & 0x1f) << DDRP_ZQXCR_PULLDOWN_IMPE_BIT) |
+		DDRP_ZQXCR_ZDEN);
+}
+
+#define JZBIT(bit) ((bit % 4) * 8)
+#define JZMASK(bit) (0x1f << JZBIT(bit))
+
+static void remap_swap(int a, int b)
+{
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	u32 remmap[2], tmp[2];
+
+	remmap[0] = readl(ddr_ctl_regs + DDRC_REMMAP(a / 4));
+	remmap[1] = readl(ddr_ctl_regs + DDRC_REMMAP(b / 4));
+
+	tmp[0] = (remmap[0] & JZMASK(a)) >> JZBIT(a);
+	tmp[1] = (remmap[1] & JZMASK(b)) >> JZBIT(b);
+
+	remmap[0] &= ~JZMASK(a);
+	remmap[1] &= ~JZMASK(b);
+
+	writel(remmap[0] | (tmp[1] << JZBIT(a)),
+	       ddr_ctl_regs + DDRC_REMMAP(a / 4));
+	writel(remmap[1] | (tmp[0] << JZBIT(b)),
+	       ddr_ctl_regs + DDRC_REMMAP(b / 4));
+}
+
+static void mem_remap(void)
+{
+	u32 start = (DDR_ROW + DDR_COL + (DDR_DW32 ? 4 : 2) / 2) - 12;
+	u32 num = DDR_BANK8 ? 3 : 2;
+
+	if (DDR_CS0EN && DDR_CS1EN)
+		num++;
+
+	for (; num > 0; num--)
+		remap_swap(0 + num - 1, start + num - 1);
+}
+
+/* Fetch DRAM config from board file */
+__weak const struct jz4780_ddr_config *jz4780_get_ddr_config(void)
+{
+	return NULL;
+}
+
+void sdram_init(void)
+{
+	const struct jz4780_ddr_config *ddr_config = jz4780_get_ddr_config();
+	void __iomem *ddr_ctl_regs = (void __iomem *)DDRC_BASE;
+	void __iomem *ddr_phy_regs = ddr_ctl_regs + DDR_PHY_OFFSET;
+	void __iomem *cpm_regs = (void __iomem *)CPM_BASE;
+	u32 mem_clk, tmp, i;
+	u32 mem_base0, mem_base1;
+	u32 mem_mask0, mem_mask1;
+	u32 mem_size0, mem_size1;
+
+	if (!ddr_config)
+		hang();
+
+	/* Reset DLL in DDR PHY */
+	writel(0x3, cpm_regs + 0xd0);
+	mdelay(400);
+	writel(0x1, cpm_regs + 0xd0);
+	mdelay(400);
+
+	/* Enter reset */
+	writel(0xf << 20, ddr_ctl_regs + DDRC_CTRL);
+
+	mem_clk = get_mem_clk();
+
+	tmp = 1000000000 / mem_clk;
+	if (1000000000 % mem_clk)
+		tmp++;
+	tmp = DDR_tREFI / tmp;
+	tmp = tmp / (16 * (1 << DDR_CLK_DIV)) - 1;
+	if (tmp > 0xff)
+		tmp = 0xff;
+	if (tmp < 1)
+		tmp = 1;
+
+	writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+	writel(0x150000, ddr_phy_regs + DDRP_DTAR);
+	ddr_phy_init(ddr_config);
+
+	writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+	writel(0x0, ddr_ctl_regs + DDRC_CTRL);
+
+	ddr_cfg_init();
+
+	for (i = 0; i < 6; i++)
+		writel(ddr_config->timing[i], ddr_ctl_regs + DDRC_TIMING(i));
+
+	mem_size0 = sdram_size(0);
+	mem_size1 = sdram_size(1);
+
+	if (!mem_size1 && mem_size0 > 0x20000000) {
+		mem_base0 = 0x0;
+		mem_mask0 = ~(((mem_size0 * 2) >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+	} else {
+		mem_base0 = (DDR_MEM_PHY_BASE >> 24) & 0xff;
+		mem_mask0 = ~((mem_size0 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+	}
+
+	if (mem_size1) {
+		mem_mask1 = ~((mem_size1 >> 24) - 1) & DDRC_MMAP_MASK_MASK;
+		mem_base1 = ((DDR_MEM_PHY_BASE + mem_size0) >> 24) & 0xff;
+	} else {
+		mem_mask1 = 0;
+		mem_base1 = 0xff;
+	}
+
+	writel(mem_base0 << DDRC_MMAP_BASE_BIT | mem_mask0,
+	       ddr_ctl_regs + DDRC_MMAP0);
+	writel(mem_base1 << DDRC_MMAP_BASE_BIT | mem_mask1,
+	       ddr_ctl_regs + DDRC_MMAP1);
+	writel(DDRC_CTRL_CKE | DDRC_CTRL_ALH, ddr_ctl_regs + DDRC_CTRL);
+	writel((DDR_CLK_DIV << 1) | DDRC_REFCNT_REF_EN |
+	       (tmp << DDRC_REFCNT_CON_BIT),
+	       ddr_ctl_regs + DDRC_REFCNT);
+	writel((1 << 15) | (4 << 12) | (1 << 11) | (1 << 8) | (0 << 6) |
+	       (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1),
+	       ddr_ctl_regs + DDRC_CTRL);
+	mem_remap();
+	clrbits_le32(ddr_ctl_regs + DDRC_ST, 0x40);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/timer.c b/arch/mips/mach-jz47xx/jz4780/timer.c
new file mode 100644
index 0000000..a689b9d
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/timer.c
@@ -0,0 +1,239 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 timer
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <config.h>
+#include <common.h>
+#include <div64.h>
+#include <asm/io.h>
+#include <asm/mipsregs.h>
+#include <mach/jz4780.h>
+
+#define TCU_TSR		0x1C	/* Timer Stop Register */
+#define TCU_TSSR	0x2C	/* Timer Stop Set Register */
+#define TCU_TSCR	0x3C	/* Timer Stop Clear Register */
+#define TCU_TER		0x10	/* Timer Counter Enable Register */
+#define TCU_TESR	0x14	/* Timer Counter Enable Set Register */
+#define TCU_TECR	0x18	/* Timer Counter Enable Clear Register */
+#define TCU_TFR		0x20	/* Timer Flag Register */
+#define TCU_TFSR	0x24	/* Timer Flag Set Register */
+#define TCU_TFCR	0x28	/* Timer Flag Clear Register */
+#define TCU_TMR		0x30	/* Timer Mask Register */
+#define TCU_TMSR	0x34	/* Timer Mask Set Register */
+#define TCU_TMCR	0x38	/* Timer Mask Clear Register */
+/* n = 0,1,2,3,4,5 */
+#define TCU_TDFR(n)	(0x40 + (n) * 0x10)	/* Timer Data Full Reg */
+#define TCU_TDHR(n)	(0x44 + (n) * 0x10)	/* Timer Data Half Reg */
+#define TCU_TCNT(n)	(0x48 + (n) * 0x10)	/* Timer Counter Reg */
+#define TCU_TCSR(n)	(0x4C + (n) * 0x10)	/* Timer Control Reg */
+
+#define TCU_OSTCNTL	0xe4
+#define TCU_OSTCNTH	0xe8
+#define TCU_OSTCSR	0xec
+#define TCU_OSTCNTHBUF	0xfc
+
+/* Register definitions */
+#define TCU_TCSR_PWM_SD		BIT(9)
+#define TCU_TCSR_PWM_INITL_HIGH	BIT(8)
+#define TCU_TCSR_PWM_EN		BIT(7)
+#define TCU_TCSR_PRESCALE_BIT	3
+#define TCU_TCSR_PRESCALE_MASK	(0x7 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1	(0x0 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE4	(0x1 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE16	(0x2 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE64	(0x3 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE256	(0x4 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_PRESCALE1024	(0x5 << TCU_TCSR_PRESCALE_BIT)
+#define TCU_TCSR_EXT_EN		BIT(2)
+#define TCU_TCSR_RTC_EN		BIT(1)
+#define TCU_TCSR_PCK_EN		BIT(0)
+
+#define TCU_TER_TCEN5		BIT(5)
+#define TCU_TER_TCEN4		BIT(4)
+#define TCU_TER_TCEN3		BIT(3)
+#define TCU_TER_TCEN2		BIT(2)
+#define TCU_TER_TCEN1		BIT(1)
+#define TCU_TER_TCEN0		BIT(0)
+
+#define TCU_TESR_TCST5		BIT(5)
+#define TCU_TESR_TCST4		BIT(4)
+#define TCU_TESR_TCST3		BIT(3)
+#define TCU_TESR_TCST2		BIT(2)
+#define TCU_TESR_TCST1		BIT(1)
+#define TCU_TESR_TCST0		BIT(0)
+
+#define TCU_TECR_TCCL5		BIT(5)
+#define TCU_TECR_TCCL4		BIT(4)
+#define TCU_TECR_TCCL3		BIT(3)
+#define TCU_TECR_TCCL2		BIT(2)
+#define TCU_TECR_TCCL1		BIT(1)
+#define TCU_TECR_TCCL0		BIT(0)
+
+#define TCU_TFR_HFLAG5		BIT(21)
+#define TCU_TFR_HFLAG4		BIT(20)
+#define TCU_TFR_HFLAG3		BIT(19)
+#define TCU_TFR_HFLAG2		BIT(18)
+#define TCU_TFR_HFLAG1		BIT(17)
+#define TCU_TFR_HFLAG0		BIT(16)
+#define TCU_TFR_FFLAG5		BIT(5)
+#define TCU_TFR_FFLAG4		BIT(4)
+#define TCU_TFR_FFLAG3		BIT(3)
+#define TCU_TFR_FFLAG2		BIT(2)
+#define TCU_TFR_FFLAG1		BIT(1)
+#define TCU_TFR_FFLAG0		BIT(0)
+
+#define TCU_TFSR_HFLAG5		BIT(21)
+#define TCU_TFSR_HFLAG4		BIT(20)
+#define TCU_TFSR_HFLAG3		BIT(19)
+#define TCU_TFSR_HFLAG2		BIT(18)
+#define TCU_TFSR_HFLAG1		BIT(17)
+#define TCU_TFSR_HFLAG0		BIT(16)
+#define TCU_TFSR_FFLAG5		BIT(5)
+#define TCU_TFSR_FFLAG4		BIT(4)
+#define TCU_TFSR_FFLAG3		BIT(3)
+#define TCU_TFSR_FFLAG2		BIT(2)
+#define TCU_TFSR_FFLAG1		BIT(1)
+#define TCU_TFSR_FFLAG0		BIT(0)
+
+#define TCU_TFCR_HFLAG5		BIT(21)
+#define TCU_TFCR_HFLAG4		BIT(20)
+#define TCU_TFCR_HFLAG3		BIT(19)
+#define TCU_TFCR_HFLAG2		BIT(18)
+#define TCU_TFCR_HFLAG1		BIT(17)
+#define TCU_TFCR_HFLAG0		BIT(16)
+#define TCU_TFCR_FFLAG5		BIT(5)
+#define TCU_TFCR_FFLAG4		BIT(4)
+#define TCU_TFCR_FFLAG3		BIT(3)
+#define TCU_TFCR_FFLAG2		BIT(2)
+#define TCU_TFCR_FFLAG1		BIT(1)
+#define TCU_TFCR_FFLAG0		BIT(0)
+
+#define TCU_TMR_HMASK5		BIT(21)
+#define TCU_TMR_HMASK4		BIT(20)
+#define TCU_TMR_HMASK3		BIT(19)
+#define TCU_TMR_HMASK2		BIT(18)
+#define TCU_TMR_HMASK1		BIT(17)
+#define TCU_TMR_HMASK0		BIT(16)
+#define TCU_TMR_FMASK5		BIT(5)
+#define TCU_TMR_FMASK4		BIT(4)
+#define TCU_TMR_FMASK3		BIT(3)
+#define TCU_TMR_FMASK2		BIT(2)
+#define TCU_TMR_FMASK1		BIT(1)
+#define TCU_TMR_FMASK0		BIT(0)
+
+#define TCU_TMSR_HMST5		BIT(21)
+#define TCU_TMSR_HMST4		BIT(20)
+#define TCU_TMSR_HMST3		BIT(19)
+#define TCU_TMSR_HMST2		BIT(18)
+#define TCU_TMSR_HMST1		BIT(17)
+#define TCU_TMSR_HMST0		BIT(16)
+#define TCU_TMSR_FMST5		BIT(5)
+#define TCU_TMSR_FMST4		BIT(4)
+#define TCU_TMSR_FMST3		BIT(3)
+#define TCU_TMSR_FMST2		BIT(2)
+#define TCU_TMSR_FMST1		BIT(1)
+#define TCU_TMSR_FMST0		BIT(0)
+
+#define TCU_TMCR_HMCL5		BIT(21)
+#define TCU_TMCR_HMCL4		BIT(20)
+#define TCU_TMCR_HMCL3		BIT(19)
+#define TCU_TMCR_HMCL2		BIT(18)
+#define TCU_TMCR_HMCL1		BIT(17)
+#define TCU_TMCR_HMCL0		BIT(16)
+#define TCU_TMCR_FMCL5		BIT(5)
+#define TCU_TMCR_FMCL4		BIT(4)
+#define TCU_TMCR_FMCL3		BIT(3)
+#define TCU_TMCR_FMCL2		BIT(2)
+#define TCU_TMCR_FMCL1		BIT(1)
+#define TCU_TMCR_FMCL0		BIT(0)
+
+#define TCU_TSR_WDTS		BIT(16)
+#define TCU_TSR_STOP5		BIT(5)
+#define TCU_TSR_STOP4		BIT(4)
+#define TCU_TSR_STOP3		BIT(3)
+#define TCU_TSR_STOP2		BIT(2)
+#define TCU_TSR_STOP1		BIT(1)
+#define TCU_TSR_STOP0		BIT(0)
+
+#define TCU_TSSR_WDTSS		BIT(16)
+#define TCU_TSSR_STPS5		BIT(5)
+#define TCU_TSSR_STPS4		BIT(4)
+#define TCU_TSSR_STPS3		BIT(3)
+#define TCU_TSSR_STPS2		BIT(2)
+#define TCU_TSSR_STPS1		BIT(1)
+#define TCU_TSSR_STPS0		BIT(0)
+
+#define TCU_TSSR_WDTSC		BIT(16)
+#define TCU_TSSR_STPC5		BIT(5)
+#define TCU_TSSR_STPC4		BIT(4)
+#define TCU_TSSR_STPC3		BIT(3)
+#define TCU_TSSR_STPC2		BIT(2)
+#define TCU_TSSR_STPC1		BIT(1)
+#define TCU_TSSR_STPC0		BIT(0)
+
+#define TER_OSTEN		BIT(15)
+
+#define OSTCSR_CNT_MD		BIT(15)
+#define OSTCSR_SD		BIT(9)
+#define OSTCSR_PRESCALE_16	(0x2 << 3)
+#define OSTCSR_EXT_EN		BIT(2)
+
+int timer_init(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+
+	writel(OSTCSR_SD, regs + TCU_OSTCSR);
+	reset_timer();
+	writel(OSTCSR_CNT_MD | OSTCSR_EXT_EN | OSTCSR_PRESCALE_16,
+	       regs + TCU_OSTCSR);
+	writew(TER_OSTEN, regs + TCU_TESR);
+	return 0;
+}
+
+void reset_timer(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+
+	writel(0, regs + TCU_OSTCNTH);
+	writel(0, regs + TCU_OSTCNTL);
+}
+
+static u64 get_timer64(void)
+{
+	void __iomem *regs = (void __iomem *)TCU_BASE;
+	u32 low = readl(regs + TCU_OSTCNTL);
+	u32 high = readl(regs + TCU_OSTCNTHBUF);
+
+	return ((u64)high << 32) | low;
+}
+
+ulong get_timer(ulong base)
+{
+	return lldiv(get_timer64(), 3000) - base;
+}
+
+void __udelay(unsigned long usec)
+{
+	/* OST count increments at 3MHz */
+	u64 end = get_timer64() + ((u64)usec * 3);
+
+	while (get_timer64() < end)
+		;
+}
+
+unsigned long long get_ticks(void)
+{
+	return get_timer64();
+}
+
+void jz4780_tcu_wdt_start(void)
+{
+	void __iomem *tcu_regs = (void __iomem *)TCU_BASE;
+
+	/* Enable WDT clock */
+	writel(TCU_TSSR_WDTSC, tcu_regs + TCU_TSCR);
+}
diff --git a/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
new file mode 100644
index 0000000..347cabc
--- /dev/null
+++ b/arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds
@@ -0,0 +1,50 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+MEMORY { .sram : ORIGIN = CONFIG_SPL_TEXT_BASE,\
+		LENGTH = CONFIG_SPL_MAX_SIZE }
+MEMORY { .sdram : ORIGIN = CONFIG_SPL_BSS_START_ADDR, \
+		LENGTH = CONFIG_SPL_BSS_MAX_SIZE }
+
+OUTPUT_ARCH(mips)
+ENTRY(_start)
+SECTIONS
+{
+	.text :
+	{
+		__image_copy_start = .;
+		arch/mips/mach-jz47xx/start.o	(.text*)
+		*(.text*)
+	} >.sram
+
+	. = ALIGN(4);
+	.rodata : { *(SORT_BY_ALIGNMENT(.rodata*)) } >.sram
+
+	. = ALIGN(4);
+	.data : { *(SORT_BY_ALIGNMENT(.data*)) } >.sram
+
+	. = ALIGN(4);
+	__image_copy_end = .;
+
+	.bss : {
+		. = ALIGN(4);
+		__bss_start = .;
+		*(.sbss.*)
+		*(.bss.*)
+		*(COMMON)
+		. = ALIGN(4);
+		__bss_end = .;
+	} >.sdram
+
+	/DISCARD/ : {
+		*(.dynbss)
+		*(.dynstr)
+		*(.dynamic)
+		*(.interp)
+		*(.hash)
+		*(.gnu.*)
+		*(.plt)
+		*(.got.plt)
+		*(.rel.plt)
+		*(.rel.dyn)
+	}
+}
diff --git a/arch/mips/mach-jz47xx/start.S b/arch/mips/mach-jz47xx/start.S
new file mode 100644
index 0000000..760d021
--- /dev/null
+++ b/arch/mips/mach-jz47xx/start.S
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Startup Code for MIPS32 XBURST CPU-core
+ *
+ *  Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
+ */
+
+#include <config.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/cacheops.h>
+#include <asm/cache.h>
+#include <mach/jz4780.h>
+
+	.set noreorder
+
+	.globl _start
+	.text
+_start:
+#ifdef CONFIG_SPL_BUILD
+
+	/* magic value ("MSPL") */
+	.word 0x4d53504c
+
+	/* Invalidate BTB */
+	mfc0	t0, CP0_CONFIG, 7
+	nop
+	ori	t0, 2
+	mtc0	t0, CP0_CONFIG, 7
+	nop
+
+	/*
+	 * CU0=UM=EXL=IE=0, BEV=ERL=1, IP2~7=1
+	 */
+	li	t0, 0x0040FC04
+	mtc0	t0, CP0_STATUS
+
+	/* CAUSE register */
+	/* IV=1, use the specical interrupt vector (0x200) */
+	li	t1, 0x00800000
+	mtc0	t1, CP0_CAUSE
+
+#ifdef CONFIG_SOC_JZ4780
+	/* enable bridge radical mode */
+	la	t0, CPM_BASE
+	lw	t1, 0x24(t0)
+	ori	t1, t1, 0x22
+	sw	t1, 0x24(t0)
+#endif
+
+	/* Set up stack */
+	li	sp, CONFIG_SPL_STACK
+
+	b		board_init_f
+	 nop
+
+#ifdef CONFIG_SOC_JZ4780
+
+	.globl enable_caches
+	.ent enable_caches
+enable_caches:
+	mtc0	zero, CP0_TAGLO
+	mtc0	zero, CP0_TAGHI
+
+	li	t0, KSEG0
+	addu	t1, t0, CONFIG_SYS_DCACHE_SIZE
+1:
+	cache	INDEX_STORE_TAG_D, 0(t0)
+	bne	t0, t1, 1b
+	addiu	t0, t0, CONFIG_SYS_CACHELINE_SIZE
+
+	li	t0, KSEG0
+	addu	t1, t0, CONFIG_SYS_ICACHE_SIZE
+2:
+	cache	INDEX_STORE_TAG_I, 0(t0)
+	bne	t0, t1, 2b
+	addiu	t0, t0, CONFIG_SYS_CACHELINE_SIZE
+
+	/* Invalidate BTB */
+	mfc0	t0, CP0_CONFIG, 7
+	nop
+	ori	t0, 2
+	mtc0	t0, CP0_CONFIG, 7
+	nop
+
+	/* Enable caches */
+	li	t0, CONF_CM_CACHABLE_NONCOHERENT
+	mtc0	t0, CP0_CONFIG
+	nop
+
+	jr	ra
+	 nop
+
+	.end enable_caches
+
+#endif /* CONFIG_SOC_JZ4780 */
+#endif /* !CONFIG_SPL_BUILD */
diff --git a/arch/mips/mach-mscc/Kconfig b/arch/mips/mach-mscc/Kconfig
new file mode 100644
index 0000000..0e35b77
--- /dev/null
+++ b/arch/mips/mach-mscc/Kconfig
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+menu "MSCC VCore-III platforms"
+	depends on ARCH_MSCC
+
+config SOC_VCOREIII
+	select MIPS_TUNE_24KC
+	select ROM_EXCEPTION_VECTORS
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select SUPPORTS_LITTLE_ENDIAN
+	bool
+
+config SYS_SOC
+	default "mscc"
+
+config SOC_OCELOT
+	bool
+	select SOC_VCOREIII
+	help
+	  This supports MSCC Ocelot family of SOCs.
+
+config SOC_LUTON
+	bool
+	select SOC_VCOREIII
+	help
+	  This supports MSCC Luton family of SOCs.
+
+config SYS_CONFIG_NAME
+	default "vcoreiii"
+
+choice
+	prompt "Board select"
+
+config TARGET_OCELOT_PCB120
+	bool "MSCC PCB120 Reference Board (aka VSC5635EV)"
+	select SOC_OCELOT
+	help
+	  When selected, CONFIG_DEFAULT_DEVICE_TREE should be set to
+	  ocelot_pcb120
+
+config TARGET_OCELOT_PCB123
+	bool "MSCC PCB123 Reference Board (aka VSC7514EV))"
+	select SOC_OCELOT
+	help
+	  When selected, CONFIG_DEFAULT_DEVICE_TREE should be set to
+	  ocelot_pcb123
+
+config TARGET_LUTON_PCB091
+	bool "MSCC PCB091 Reference Board"
+	select SOC_LUTON
+	select MSCC_BITBANG_SPI_GPIO
+	help
+	  When selected, CONFIG_DEFAULT_DEVICE_TREE should be set to
+	  luton_pcb091
+endchoice
+
+choice
+	prompt "DDR type"
+
+config DDRTYPE_H5TQ4G63MFR
+	bool "Hynix H5TQ4G63MFR-PBC (4Gbit, DDR3-800, 256Mbitx16)"
+
+config DDRTYPE_MT41K256M16
+	bool "Micron MT41K256M16 (4Gbit, DDR3L-800, 256Mbitx16)"
+
+config DDRTYPE_H5TQ1G63BFA
+	bool "Hynix H5TQ1G63BFA (1Gbit DDR3, x16)"
+
+config DDRTYPE_MT41J128M16HA
+	bool "Micron MT41J128M16HA-15E:D (2Gbit DDR3, x16)"
+
+config DDRTYPE_MT41K128M16JT
+	bool "Micron MT41K128M16JT-125 (2Gbit DDR3L, 128Mbitx16)"
+
+config DDRTYPE_MT47H128M8HQ
+	bool "Micron MT47H128M8-3 (1Gbit, DDR-533@CL4 @ 4.80ns 16Mbisx8x8)"
+
+endchoice
+
+source "board/mscc/ocelot/Kconfig"
+
+source "board/mscc/luton/Kconfig"
+
+endmenu
diff --git a/arch/mips/mach-mscc/Makefile b/arch/mips/mach-mscc/Makefile
new file mode 100644
index 0000000..6c60f26
--- /dev/null
+++ b/arch/mips/mach-mscc/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+CFLAGS_cpu.o += -finline-limit=64000
+
+obj-y += cpu.o dram.o reset.o lowlevel_init.o
+obj-$(CONFIG_SOC_LUTON) += lowlevel_init_luton.o
diff --git a/arch/mips/mach-mscc/cpu.c b/arch/mips/mach-mscc/cpu.c
new file mode 100644
index 0000000..5be8ff6
--- /dev/null
+++ b/arch/mips/mach-mscc/cpu.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+
+#include <mach/tlb.h>
+#include <mach/ddr.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#if CONFIG_SYS_SDRAM_SIZE <= SZ_64M
+#define MSCC_RAM_TLB_SIZE   SZ_64M
+#define MSCC_ATTRIB2   MMU_REGIO_INVAL
+#elif CONFIG_SYS_SDRAM_SIZE <= SZ_128M
+#define MSCC_RAM_TLB_SIZE   SZ_64M
+#define MSCC_ATTRIB2   MMU_REGIO_RW
+#elif CONFIG_SYS_SDRAM_SIZE <= SZ_256M
+#define MSCC_RAM_TLB_SIZE   SZ_256M
+#define MSCC_ATTRIB2   MMU_REGIO_INVAL
+#elif CONFIG_SYS_SDRAM_SIZE <= SZ_512M
+#define MSCC_RAM_TLB_SIZE   SZ_256M
+#define MSCC_ATTRIB2   MMU_REGIO_RW
+#else
+#define MSCC_RAM_TLB_SIZE   SZ_512M
+#define MSCC_ATTRIB2   MMU_REGIO_RW
+#endif
+
+/* NOTE: lowlevel_init() function does not have access to the
+ * stack. Thus, all called functions must be inlined, and (any) local
+ * variables must be kept in registers.
+ */
+void vcoreiii_tlb_init(void)
+{
+	register int tlbix = 0;
+
+	/*
+	 * Unlike most of the MIPS based SoCs, the IO register address
+	 * are not in KSEG0. The mainline linux kernel built in legacy
+	 * mode needs to access some of the registers very early in
+	 * the boot and make the assumption that the bootloader has
+	 * already configured them, so we have to match this
+	 * expectation.
+	 */
+	create_tlb(tlbix++, MSCC_IO_ORIGIN1_OFFSET, SZ_16M, MMU_REGIO_RW,
+		   MMU_REGIO_RW);
+#ifdef CONFIG_SOC_LUTON
+	create_tlb(tlbix++, MSCC_IO_ORIGIN2_OFFSET, SZ_16M, MMU_REGIO_RW,
+		   MMU_REGIO_RW);
+#endif
+
+#if  CONFIG_SYS_TEXT_BASE == MSCC_FLASH_TO
+	/*
+	 * If U-Boot is located in NOR then we want to be able to use
+	 * the data cache in order to boot in a decent duration
+	 */
+	create_tlb(tlbix++, MSCC_FLASH_TO, SZ_16M, MMU_REGIO_RO_C,
+		   MMU_REGIO_RO_C);
+	create_tlb(tlbix++, MSCC_FLASH_TO + SZ_32M, SZ_16M, MMU_REGIO_RO_C,
+		   MMU_REGIO_RO_C);
+
+	/*
+	 * Using cache for RAM also helps to improve boot time. Thanks
+	 * to this the time to relocate U-Boot in RAM went from 2.092
+	 * secs to 0.104 secs.
+	 */
+	create_tlb(tlbix++, MSCC_DDR_TO, MSCC_RAM_TLB_SIZE, MMU_REGIO_RW,
+		   MSCC_ATTRIB2);
+
+	/* Enable caches by clearing the bit ERL, which is set on reset */
+	write_c0_status(read_c0_status() & ~BIT(2));
+#endif /* CONFIG_SYS_TEXT_BASE */
+}
+
+int mach_cpu_init(void)
+{
+	/* Speed up NOR flash access */
+#ifdef CONFIG_SOC_LUTON
+	writel(ICPU_PI_MST_CFG_TRISTATE_CTRL +
+	       ICPU_PI_MST_CFG_CLK_DIV(4), BASE_CFG + ICPU_PI_MST_CFG);
+
+	writel(ICPU_SPI_MST_CFG_FAST_READ_ENA +
+	       ICPU_SPI_MST_CFG_CS_DESELECT_TIME(0x19) +
+	       ICPU_SPI_MST_CFG_CLK_DIV(9), BASE_CFG + ICPU_SPI_MST_CFG);
+#else
+	writel(ICPU_SPI_MST_CFG_CS_DESELECT_TIME(0x19) +
+	       ICPU_SPI_MST_CFG_CLK_DIV(9), BASE_CFG + ICPU_SPI_MST_CFG);
+	/*
+	 * Legacy and mainline linux kernel expect that the
+	 * interruption map was set as it was done by redboot.
+	 */
+	writel(~0, BASE_CFG + ICPU_DST_INTR_MAP(0));
+	writel(0, BASE_CFG + ICPU_DST_INTR_MAP(1));
+	writel(0, BASE_CFG + ICPU_DST_INTR_MAP(2));
+	writel(0, BASE_CFG + ICPU_DST_INTR_MAP(3));
+#endif
+	return 0;
+}
diff --git a/arch/mips/mach-mscc/dram.c b/arch/mips/mach-mscc/dram.c
new file mode 100644
index 0000000..309007c
--- /dev/null
+++ b/arch/mips/mach-mscc/dram.c
@@ -0,0 +1,73 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+
+#include <asm/io.h>
+#include <asm/types.h>
+
+#include <mach/tlb.h>
+#include <mach/ddr.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static inline int vcoreiii_train_bytelane(void)
+{
+	int ret;
+
+	ret = hal_vcoreiii_train_bytelane(0);
+
+#ifdef CONFIG_SOC_OCELOT
+	if (ret)
+		return ret;
+	ret = hal_vcoreiii_train_bytelane(1);
+#endif
+
+	return ret;
+}
+
+int vcoreiii_ddr_init(void)
+{
+	int res;
+
+	if (!(readl(BASE_CFG + ICPU_MEMCTRL_STAT)
+	      & ICPU_MEMCTRL_STAT_INIT_DONE)) {
+		hal_vcoreiii_init_memctl();
+		hal_vcoreiii_wait_memctl();
+		if (hal_vcoreiii_init_dqs() || vcoreiii_train_bytelane())
+			hal_vcoreiii_ddr_failed();
+	}
+#if (CONFIG_SYS_TEXT_BASE != 0x20000000)
+	res = dram_check();
+	if (res == 0)
+		hal_vcoreiii_ddr_verified();
+	else
+		hal_vcoreiii_ddr_failed();
+
+	/* Clear boot-mode and read-back to activate/verify */
+	clrbits_le32(BASE_CFG + ICPU_GENERAL_CTRL,
+		     ICPU_GENERAL_CTRL_BOOT_MODE_ENA);
+	readl(BASE_CFG + ICPU_GENERAL_CTRL);
+#else
+	res = 0;
+#endif
+	return res;
+}
+
+int print_cpuinfo(void)
+{
+	printf("MSCC VCore-III MIPS 24Kec\n");
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	while (vcoreiii_ddr_init())
+		;
+
+	gd->ram_size = CONFIG_SYS_SDRAM_SIZE;
+	return 0;
+}
diff --git a/arch/mips/mach-mscc/include/ioremap.h b/arch/mips/mach-mscc/include/ioremap.h
new file mode 100644
index 0000000..9024364
--- /dev/null
+++ b/arch/mips/mach-mscc/include/ioremap.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef __ASM_MACH_MSCC_IOREMAP_H
+#define __ASM_MACH_MSCC_IOREMAP_H
+
+#include <linux/types.h>
+#include <mach/common.h>
+
+/*
+ * Allow physical addresses to be fixed up to help peripherals located
+ * outside the low 32-bit range -- generic pass-through version.
+ */
+static inline phys_addr_t fixup_bigphys_addr(phys_addr_t phys_addr,
+					     phys_addr_t size)
+{
+	return phys_addr;
+}
+
+static inline int is_vcoreiii_internal_registers(phys_addr_t offset)
+{
+	if ((offset >= MSCC_IO_ORIGIN1_OFFSET &&
+	     offset < (MSCC_IO_ORIGIN1_OFFSET + MSCC_IO_ORIGIN1_SIZE)) ||
+	    (offset >= MSCC_IO_ORIGIN2_OFFSET &&
+	     offset < (MSCC_IO_ORIGIN2_OFFSET + MSCC_IO_ORIGIN2_SIZE)))
+		return 1;
+
+	return 0;
+}
+
+static inline void __iomem *plat_ioremap(phys_addr_t offset, unsigned long size,
+					 unsigned long flags)
+{
+	if (is_vcoreiii_internal_registers(offset))
+		return (void __iomem *)offset;
+
+	return NULL;
+}
+
+static inline int plat_iounmap(const volatile void __iomem *addr)
+{
+	return is_vcoreiii_internal_registers((unsigned long)addr);
+}
+
+#define _page_cachable_default	_CACHE_CACHABLE_NONCOHERENT
+
+#endif				/* __ASM_MACH_MSCC_IOREMAP_H */
diff --git a/arch/mips/mach-mscc/include/mach/common.h b/arch/mips/mach-mscc/include/mach/common.h
new file mode 100644
index 0000000..931ecd7
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/common.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef __ASM_MACH_COMMON_H
+#define __ASM_MACH_COMMON_H
+
+#if defined(CONFIG_SOC_OCELOT)
+#include <mach/ocelot/ocelot.h>
+#include <mach/ocelot/ocelot_devcpu_gcb.h>
+#include <mach/ocelot/ocelot_icpu_cfg.h>
+#elif defined(CONFIG_SOC_LUTON)
+#include <mach/luton/luton.h>
+#include <mach/luton/luton_devcpu_gcb.h>
+#include <mach/luton/luton_icpu_cfg.h>
+#else
+#error Unsupported platform
+#endif
+
+#define MSCC_DDR_TO	0x20000000	/* DDR RAM base offset */
+#define MSCC_MEMCTL1_TO	0x40000000	/* SPI/PI base offset */
+#define MSCC_MEMCTL2_TO	0x50000000	/* SPI/PI base offset */
+#define MSCC_FLASH_TO	MSCC_MEMCTL1_TO	/* Flash base offset */
+
+#define VCOREIII_TIMER_DIVIDER 25	/* Clock tick ~ 0.1 us */
+
+#endif				/* __ASM_MACH_COMMON_H */
diff --git a/arch/mips/mach-mscc/include/mach/ddr.h b/arch/mips/mach-mscc/include/mach/ddr.h
new file mode 100644
index 0000000..f445e63
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/ddr.h
@@ -0,0 +1,814 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef __ASM_MACH_DDR_H
+#define __ASM_MACH_DDR_H
+
+#include <asm/cacheops.h>
+#include <asm/io.h>
+#include <asm/reboot.h>
+#include <mach/common.h>
+
+#define MIPS_VCOREIII_MEMORY_DDR3
+#define MIPS_VCOREIII_DDR_SIZE CONFIG_SYS_SDRAM_SIZE
+
+#if defined(CONFIG_DDRTYPE_H5TQ1G63BFA)	/* Serval1 Refboard */
+
+/* Hynix H5TQ1G63BFA (1Gbit DDR3, x16) @ 3.20ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     13
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            2437
+#define VC3_MPAR_tRAS_min         12
+#define VC3_MPAR_CL               6
+#define VC3_MPAR_tWTR             4
+#define VC3_MPAR_tRC              16
+#define VC3_MPR_tFAW             16
+#define VC3_MPAR_tRP              5
+#define VC3_MPAR_tRRD             4
+#define VC3_MPAR_tRCD             5
+#define VC3_MPAR_tMRD             4
+#define VC3_MPAR_tRFC             35
+#define VC3_MPAR_CWL              5
+#define VC3_MPAR_tXPR             38
+#define VC3_MPAR_tMOD             12
+#define VC3_MPAR_tDLLK            512
+#define VC3_MPAR_tWR              5
+
+#elif defined(CONFIG_DDRTYPE_MT41J128M16HA)	/* Validation board */
+
+/* Micron MT41J128M16HA-15E:D (2Gbit DDR3, x16) @ 3.20ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     14
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            2437
+#define VC3_MPAR_tRAS_min         12
+#define VC3_MPAR_CL               5
+#define VC3_MPAR_tWTR             4
+#define VC3_MPAR_tRC              16
+#define VC3_MPAR_tFAW             16
+#define VC3_MPAR_tRP              5
+#define VC3_MPAR_tRRD             4
+#define VC3_MPAR_tRCD             5
+#define VC3_MPAR_tMRD             4
+#define VC3_MPAR_tRFC             50
+#define VC3_MPAR_CWL              5
+#define VC3_MPAR_tXPR             54
+#define VC3_MPAR_tMOD             12
+#define VC3_MPAR_tDLLK            512
+#define VC3_MPAR_tWR              5
+
+#elif defined(CONFIG_DDRTYPE_MT41K256M16)	/* JR2 Validation board */
+
+/* Micron MT41K256M16 (4Gbit, DDR3L-800, 256Mbitx16) @ 3.20ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     15
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            2437
+#define VC3_MPAR_tRAS_min         12
+#define VC3_MPAR_CL               5
+#define VC3_MPAR_tWTR             4
+#define VC3_MPAR_tRC              16
+#define VC3_MPAR_tFAW             16
+#define VC3_MPAR_tRP              5
+#define VC3_MPAR_tRRD             4
+#define VC3_MPAR_tRCD             5
+#define VC3_MPAR_tMRD             4
+#define VC3_MPAR_tRFC             82
+#define VC3_MPAR_CWL              5
+#define VC3_MPAR_tXPR             85
+#define VC3_MPAR_tMOD             12
+#define VC3_MPAR_tDLLK            512
+#define VC3_MPAR_tWR              5
+
+#elif defined(CONFIG_DDRTYPE_H5TQ4G63MFR)	/* JR2 Reference board */
+
+/* Hynix H5TQ4G63MFR-PBC (4Gbit, DDR3-800, 256Mbitx16) - 2kb pages @ 3.20ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     15
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            2437
+#define VC3_MPAR_tRAS_min         12
+#define VC3_MPAR_CL               6
+#define VC3_MPAR_tWTR             4
+#define VC3_MPAR_tRC              17
+#define VC3_MPAR_tFAW             16
+#define VC3_MPAR_tRP              5
+#define VC3_MPAR_tRRD             4
+#define VC3_MPAR_tRCD             5
+#define VC3_MPAR_tMRD             4
+#define VC3_MPAR_tRFC             82
+#define VC3_MPAR_CWL              5
+#define VC3_MPAR_tXPR             85
+#define VC3_MPAR_tMOD             12
+#define VC3_MPAR_tDLLK            512
+#define VC3_MPAR_tWR              5
+
+#elif defined(CONFIG_DDRTYPE_MT41K128M16JT)
+
+/* Micron Micron MT41K128M16JT-125 (2Gbit DDR3L, 128Mbitx16) @ 3.20ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     14
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            2437
+#define VC3_MPAR_tRAS_min         12
+#define VC3_MPAR_CL               6
+#define VC3_MPAR_tWTR             4
+#define VC3_MPAR_tRC              16
+#define VC3_MPAR_tFAW             16
+#define VC3_MPAR_tRP              5
+#define VC3_MPAR_tRRD             4
+#define VC3_MPAR_tRCD             5
+#define VC3_MPAR_tMRD             4
+#define VC3_MPAR_tRFC             82
+#define VC3_MPAR_CWL              5
+#define VC3_MPAR_tXPR             85
+#define VC3_MPAR_tMOD             12
+#define VC3_MPAR_tDLLK            512
+#define VC3_MPAR_tWR              5
+
+#elif defined(CONFIG_DDRTYPE_MT47H128M8HQ)	/* Luton10/26 Refboards */
+
+/* Micron 1Gb MT47H128M8-3 16Meg x 8 x 8 banks, DDR-533@CL4 @ 4.80ns */
+#define VC3_MPAR_bank_addr_cnt    3
+#define VC3_MPAR_row_addr_cnt     14
+#define VC3_MPAR_col_addr_cnt     10
+#define VC3_MPAR_tREFI            1625
+#define VC3_MPAR_tRAS_min         9
+#define VC3_MPAR_CL               4
+#define VC3_MPAR_tWTR             2
+#define VC3_MPAR_tRC              12
+#define VC3_MPAR_tFAW             8
+#define VC3_MPAR_tRP              4
+#define VC3_MPAR_tRRD             2
+#define VC3_MPAR_tRCD             4
+
+#define VC3_MPAR_tRPA             4
+#define VC3_MPAR_tRP              4
+
+#define VC3_MPAR_tMRD             2
+#define VC3_MPAR_tRFC             27
+
+#define VC3_MPAR__400_ns_dly      84
+
+#define VC3_MPAR_tWR              4
+#undef MIPS_VCOREIII_MEMORY_DDR3
+#else
+
+#error Unknown DDR system configuration - please add!
+
+#endif
+
+#ifdef CONFIG_SOC_OCELOT
+#define MIPS_VCOREIII_MEMORY_16BIT 1
+#endif
+
+#define MIPS_VCOREIII_MEMORY_SSTL_ODT 7
+#define MIPS_VCOREIII_MEMORY_SSTL_DRIVE 7
+#define VCOREIII_DDR_DQS_MODE_CALIBRATE
+
+#ifdef MIPS_VCOREIII_MEMORY_16BIT
+#define VC3_MPAR_16BIT       1
+#else
+#define VC3_MPAR_16BIT       0
+#endif
+
+#ifdef MIPS_VCOREIII_MEMORY_DDR3
+#define VC3_MPAR_DDR3_MODE    1	/* DDR3 */
+#define VC3_MPAR_BURST_LENGTH 8	/* Always 8 (1) for DDR3 */
+#ifdef MIPS_VCOREIII_MEMORY_16BIT
+#define VC3_MPAR_BURST_SIZE   1	/* Always 1 for DDR3/16bit */
+#else
+#define VC3_MPAR_BURST_SIZE   0
+#endif
+#else
+#define VC3_MPAR_DDR3_MODE    0	/* DDR2 */
+#ifdef MIPS_VCOREIII_MEMORY_16BIT
+#define VC3_MPAR_BURST_LENGTH 4	/* in DDR2 16-bit mode, use burstlen 4 */
+#else
+#define VC3_MPAR_BURST_LENGTH 8	/* For 8-bit IF we must run burst-8 */
+#endif
+#define VC3_MPAR_BURST_SIZE   0	/* Always 0 for DDR2 */
+#endif
+
+#define VC3_MPAR_RL VC3_MPAR_CL
+#if !defined(MIPS_VCOREIII_MEMORY_DDR3)
+#define VC3_MPAR_WL (VC3_MPAR_RL - 1)
+#define VC3_MPAR_MD VC3_MPAR_tMRD
+#define VC3_MPAR_ID VC3_MPAR__400_ns_dly
+#define VC3_MPAR_SD VC3_MPAR_tXSRD
+#define VC3_MPAR_OW (VC3_MPAR_WL - 2)
+#define VC3_MPAR_OR (VC3_MPAR_WL - 3)
+#define VC3_MPAR_RP (VC3_MPAR_bank_addr_cnt < 3 ? VC3_MPAR_tRP : VC3_MPAR_tRPA)
+#define VC3_MPAR_FAW (VC3_MPAR_bank_addr_cnt < 3 ? 1 : VC3_MPAR_tFAW)
+#define VC3_MPAR_BL (VC3_MPAR_BURST_LENGTH == 4 ? 2 : 4)
+#define MSCC_MEMPARM_MR0 \
+	(VC3_MPAR_BURST_LENGTH == 8 ? 3 : 2) | (VC3_MPAR_CL << 4) | \
+	((VC3_MPAR_tWR - 1) << 9)
+/* DLL-on, Full-OD, AL=0, RTT=off, nDQS-on, RDQS-off, out-en */
+#define MSCC_MEMPARM_MR1 0x382
+#define MSCC_MEMPARM_MR2 0
+#define MSCC_MEMPARM_MR3 0
+#else
+#define VC3_MPAR_WL VC3_MPAR_CWL
+#define VC3_MPAR_MD VC3_MPAR_tMOD
+#define VC3_MPAR_ID VC3_MPAR_tXPR
+#define VC3_MPAR_SD VC3_MPAR_tDLLK
+#define VC3_MPAR_OW 2
+#define VC3_MPAR_OR 2
+#define VC3_MPAR_RP VC3_MPAR_tRP
+#define VC3_MPAR_FAW VC3_MPAR_tFAW
+#define VC3_MPAR_BL 4
+#define MSCC_MEMPARM_MR0 ((VC3_MPAR_RL - 4) << 4) | ((VC3_MPAR_tWR - 4) << 9)
+/* ODT_RTT: “0x0040” for 120ohm, and “0x0004” for 60ohm. */
+#define MSCC_MEMPARM_MR1 0x0040
+#define MSCC_MEMPARM_MR2 ((VC3_MPAR_WL - 5) << 3)
+#define MSCC_MEMPARM_MR3 0
+#endif				/* MIPS_VCOREIII_MEMORY_DDR3 */
+
+#define MSCC_MEMPARM_MEMCFG                                             \
+	((MIPS_VCOREIII_DDR_SIZE > SZ_512M) ?				\
+	 ICPU_MEMCTRL_CFG_DDR_512MBYTE_PLUS : 0) |			\
+	(VC3_MPAR_16BIT ? ICPU_MEMCTRL_CFG_DDR_WIDTH : 0) |		\
+	(VC3_MPAR_DDR3_MODE ? ICPU_MEMCTRL_CFG_DDR_MODE : 0) |		\
+	(VC3_MPAR_BURST_SIZE ? ICPU_MEMCTRL_CFG_BURST_SIZE : 0) |	\
+	(VC3_MPAR_BURST_LENGTH == 8 ? ICPU_MEMCTRL_CFG_BURST_LEN : 0) | \
+	(VC3_MPAR_bank_addr_cnt == 3 ? ICPU_MEMCTRL_CFG_BANK_CNT : 0) | \
+	ICPU_MEMCTRL_CFG_MSB_ROW_ADDR(VC3_MPAR_row_addr_cnt - 1) |	\
+	ICPU_MEMCTRL_CFG_MSB_COL_ADDR(VC3_MPAR_col_addr_cnt - 1)
+
+#ifdef CONFIG_SOC_OCELOT
+#define MSCC_MEMPARM_PERIOD					\
+	ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF(8) |		\
+	ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD(VC3_MPAR_tREFI)
+
+#define MSCC_MEMPARM_TIMING0                                            \
+	ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY(VC3_MPAR_RL + VC3_MPAR_BL + 1 - \
+					  VC3_MPAR_WL) |		\
+	ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY(VC3_MPAR_BL - 1) |	\
+	ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY(VC3_MPAR_BL) |		\
+	ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY(VC3_MPAR_tRAS_min - 1) |	\
+	ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY(VC3_MPAR_WL +		\
+					     VC3_MPAR_BL +		\
+					     VC3_MPAR_tWR - 1) |	\
+	ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY(VC3_MPAR_BL - 1) |		\
+		ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY(VC3_MPAR_WL - 1) |	\
+	ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY(VC3_MPAR_RL - 3)
+
+#define MSCC_MEMPARM_TIMING1                                            \
+	ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY(VC3_MPAR_tRC - 1) | \
+	ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY(VC3_MPAR_FAW - 1) |		\
+	ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY(VC3_MPAR_RP - 1) |	\
+	ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY(VC3_MPAR_tRRD - 1) |	\
+	ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY(VC3_MPAR_tRCD - 1) |	\
+	ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY(VC3_MPAR_WL +			\
+					  VC3_MPAR_BL +			\
+					  VC3_MPAR_tWTR - 1)
+
+#define MSCC_MEMPARM_TIMING2					\
+	ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY(VC3_MPAR_RP - 1) |	\
+	ICPU_MEMCTRL_TIMING2_MDSET_DLY(VC3_MPAR_MD - 1) |		\
+	ICPU_MEMCTRL_TIMING2_REF_DLY(VC3_MPAR_tRFC - 1) |		\
+	ICPU_MEMCTRL_TIMING2_INIT_DLY(VC3_MPAR_ID - 1)
+
+#define MSCC_MEMPARM_TIMING3						\
+	ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY(VC3_MPAR_WL +	\
+						    VC3_MPAR_tWTR - 1) |\
+	ICPU_MEMCTRL_TIMING3_ODT_RD_DLY(VC3_MPAR_OR - 1) |		\
+	ICPU_MEMCTRL_TIMING3_ODT_WR_DLY(VC3_MPAR_OW - 1) |		\
+	ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY(VC3_MPAR_RL - 3)
+
+#else
+#define MSCC_MEMPARM_PERIOD					\
+	ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF(1) |		\
+	ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD(VC3_MPAR_tREFI)
+
+#define MSCC_MEMPARM_TIMING0                                            \
+	ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY(VC3_MPAR_tRAS_min - 1) |	\
+	ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY(VC3_MPAR_CL +		\
+					     (VC3_MPAR_BURST_LENGTH == 8 ? 2 : 0) + \
+					     VC3_MPAR_tWR) |		\
+	ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY(VC3_MPAR_BURST_LENGTH == 8 ? 3 : 1) | \
+	ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY(VC3_MPAR_CL - 3) |		\
+	ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY(VC3_MPAR_CL - 3)
+
+#define MSCC_MEMPARM_TIMING1                                            \
+	ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY(VC3_MPAR_tRC - 1) | \
+	ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY(VC3_MPAR_tFAW - 1) |		\
+	ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY(VC3_MPAR_tRP - 1) |	\
+	ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY(VC3_MPAR_tRRD - 1) |	\
+	ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY(VC3_MPAR_tRCD - 1) |	\
+	ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY(VC3_MPAR_CL +			\
+					  (VC3_MPAR_BURST_LENGTH == 8 ? 2 : 0) + \
+					  VC3_MPAR_tWTR)
+#define MSCC_MEMPARM_TIMING2                                            \
+	ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY(VC3_MPAR_tRPA - 1) |		\
+	ICPU_MEMCTRL_TIMING2_MDSET_DLY(VC3_MPAR_tMRD - 1) |		\
+	ICPU_MEMCTRL_TIMING2_REF_DLY(VC3_MPAR_tRFC - 1) |		\
+	ICPU_MEMCTRL_TIMING2_FOUR_HUNDRED_NS_DLY(VC3_MPAR__400_ns_dly)
+
+#define MSCC_MEMPARM_TIMING3						\
+	ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY(VC3_MPAR_CL - 1) |	\
+	ICPU_MEMCTRL_TIMING3_ODT_WR_DLY(VC3_MPAR_CL - 1) |		\
+	ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY(VC3_MPAR_CL - 1)
+
+#endif
+
+enum {
+	DDR_TRAIN_OK,
+	DDR_TRAIN_CONTINUE,
+	DDR_TRAIN_ERROR,
+};
+
+/*
+ * We actually have very few 'pause' possibilities apart from
+ * these assembly nops (at this very early stage).
+ */
+#define PAUSE() asm volatile("nop; nop; nop; nop; nop; nop; nop; nop")
+
+/* NB: Assumes inlining as no stack is available! */
+static inline void set_dly(u32 bytelane, u32 dly)
+{
+	register u32 r = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+
+	r &= ~ICPU_MEMCTRL_DQS_DLY_DQS_DLY_M;
+	r |= ICPU_MEMCTRL_DQS_DLY_DQS_DLY(dly);
+	writel(r, BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+}
+
+static inline bool incr_dly(u32 bytelane)
+{
+	register u32 r = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+
+	if (ICPU_MEMCTRL_DQS_DLY_DQS_DLY(r) < 31) {
+		writel(r + 1, BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+		return true;
+	}
+
+	return false;
+}
+
+static inline bool adjust_dly(int adjust)
+{
+	register u32 r = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(0));
+
+	if (ICPU_MEMCTRL_DQS_DLY_DQS_DLY(r) < 31) {
+		writel(r + adjust, BASE_CFG + ICPU_MEMCTRL_DQS_DLY(0));
+		return true;
+	}
+
+	return false;
+}
+
+/* NB: Assumes inlining as no stack is available! */
+static inline void center_dly(u32 bytelane, u32 start)
+{
+	register u32 r = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane)) - start;
+
+	writel(start + (r >> 1), BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+}
+
+static inline void memphy_soft_reset(void)
+{
+	setbits_le32(BASE_CFG + ICPU_MEMPHY_CFG, ICPU_MEMPHY_CFG_PHY_FIFO_RST);
+	PAUSE();
+	clrbits_le32(BASE_CFG + ICPU_MEMPHY_CFG, ICPU_MEMPHY_CFG_PHY_FIFO_RST);
+	PAUSE();
+}
+
+#ifdef CONFIG_SOC_OCELOT
+static u8 training_data[] = { 0xfe, 0x11, 0x33, 0x55, 0x77, 0x99, 0xbb, 0xdd };
+
+static inline void sleep_100ns(u32 val)
+{
+	/* Set the timer tick generator to 100 ns */
+	writel(VCOREIII_TIMER_DIVIDER - 1, BASE_CFG + ICPU_TIMER_TICK_DIV);
+
+	/* Set the timer value */
+	writel(val, BASE_CFG + ICPU_TIMER_VALUE(0));
+
+	/* Enable timer 0 for one-shot */
+	writel(ICPU_TIMER_CTRL_ONE_SHOT_ENA | ICPU_TIMER_CTRL_TIMER_ENA,
+	       BASE_CFG + ICPU_TIMER_CTRL(0));
+
+	/* Wait for timer 0 to reach 0 */
+	while (readl(BASE_CFG + ICPU_TIMER_VALUE(0)) != 0)
+		;
+}
+
+static inline void hal_vcoreiii_ddr_reset_assert(void)
+{
+	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
+	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_CLR);
+	sleep_100ns(10000);
+}
+
+static inline void hal_vcoreiii_ddr_reset_release(void)
+{
+	/* DDR has reset pin on GPIO 19 toggle Low-High to release */
+	setbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+	writel(BIT(19), BASE_DEVCPU_GCB + PERF_GPIO_OUT_SET);
+	sleep_100ns(10000);
+}
+
+/*
+ * DDR memory sanity checking failed, tally and do hard reset
+ *
+ * NB: Assumes inlining as no stack is available!
+ */
+static inline void hal_vcoreiii_ddr_failed(void)
+{
+	register u32 reset;
+
+	writel(readl(BASE_CFG + ICPU_GPR(6)) + 1, BASE_CFG + ICPU_GPR(6));
+
+	clrbits_le32(BASE_DEVCPU_GCB + PERF_GPIO_OE, BIT(19));
+
+	/* We have to execute the reset function from cache. Indeed,
+	 * the reboot workaround in _machine_restart() will change the
+	 * SPI NOR into SW bitbang.
+	 *
+	 * This will render the CPU unable to execute directly from
+	 * the NOR, which is why the reset instructions are prefetched
+	 * into the I-cache.
+	 *
+	 * When failing the DDR initialization we are executing from
+	 * NOR.
+	 *
+	 * The last instruction in _machine_restart() will reset the
+	 * MIPS CPU (and the cache), and the CPU will start executing
+	 * from the reset vector.
+	 */
+	reset = KSEG0ADDR(_machine_restart);
+	icache_lock((void *)reset, 128);
+	asm volatile ("jr %0"::"r" (reset));
+
+	panic("DDR init failed\n");
+}
+
+/*
+ * DDR memory sanity checking done, possibly enable ECC.
+ *
+ * NB: Assumes inlining as no stack is available!
+ */
+static inline void hal_vcoreiii_ddr_verified(void)
+{
+#ifdef MIPS_VCOREIII_MEMORY_ECC
+	/* Finally, enable ECC */
+	register u32 val = readl(BASE_CFG + ICPU_MEMCTRL_CFG);
+
+	val |= ICPU_MEMCTRL_CFG_DDR_ECC_ERR_ENA;
+	val &= ~ICPU_MEMCTRL_CFG_BURST_SIZE;
+
+	writel(val, BASE_CFG + ICPU_MEMCTRL_CFG);
+#endif
+
+	/* Reset Status register - sticky bits */
+	writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT), BASE_CFG + ICPU_MEMCTRL_STAT);
+}
+
+/* NB: Assumes inlining as no stack is available! */
+static inline int look_for(u32 bytelane)
+{
+	register u32 i;
+
+	/* Reset FIFO in case any previous access failed */
+	for (i = 0; i < sizeof(training_data); i++) {
+		register u32 byte;
+
+		memphy_soft_reset();
+		/* Reset sticky bits */
+		writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT),
+		       BASE_CFG + ICPU_MEMCTRL_STAT);
+		/* Read data */
+		byte = __raw_readb((void __iomem *)MSCC_DDR_TO + bytelane +
+				   (i * 4));
+
+		/*
+		 * Prevent the compiler reordering the instruction so
+		 * the read of RAM happens after the check of the
+		 * errors.
+		 */
+		rmb();
+		if (readl(BASE_CFG + ICPU_MEMCTRL_STAT) &
+		    (ICPU_MEMCTRL_STAT_RDATA_MASKED |
+		     ICPU_MEMCTRL_STAT_RDATA_DUMMY)) {
+			/* Noise on the line */
+			goto read_error;
+		}
+		/* If mismatch, increment DQS - if possible */
+		if (byte != training_data[i]) {
+ read_error:
+			if (!incr_dly(bytelane))
+				return DDR_TRAIN_ERROR;
+			return DDR_TRAIN_CONTINUE;
+		}
+	}
+	return DDR_TRAIN_OK;
+}
+
+/* NB: Assumes inlining as no stack is available! */
+static inline int look_past(u32 bytelane)
+{
+	register u32 i;
+
+	/* Reset FIFO in case any previous access failed */
+	for (i = 0; i < sizeof(training_data); i++) {
+		register u32 byte;
+
+		memphy_soft_reset();
+		/* Ack sticky bits */
+		writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT),
+		       BASE_CFG + ICPU_MEMCTRL_STAT);
+		byte = __raw_readb((void __iomem *)MSCC_DDR_TO + bytelane +
+				   (i * 4));
+		/*
+		 * Prevent the compiler reordering the instruction so
+		 * the read of RAM happens after the check of the
+		 * errors.
+		 */
+		rmb();
+		if (readl(BASE_CFG + ICPU_MEMCTRL_STAT) &
+		    (ICPU_MEMCTRL_STAT_RDATA_MASKED |
+		     ICPU_MEMCTRL_STAT_RDATA_DUMMY)) {
+			/* Noise on the line */
+			goto read_error;
+		}
+		/* Bail out when we see first mismatch */
+		if (byte != training_data[i]) {
+ read_error:
+			return DDR_TRAIN_OK;
+		}
+	}
+	/* All data compares OK, increase DQS and retry */
+	if (!incr_dly(bytelane))
+		return DDR_TRAIN_ERROR;
+
+	return DDR_TRAIN_CONTINUE;
+}
+
+static inline int hal_vcoreiii_train_bytelane(u32 bytelane)
+{
+	register int res;
+	register u32 dqs_s;
+
+	set_dly(bytelane, 0);	/* Start training at DQS=0 */
+	while ((res = look_for(bytelane)) == DDR_TRAIN_CONTINUE)
+		;
+	if (res != DDR_TRAIN_OK)
+		return res;
+
+	dqs_s = readl(BASE_CFG + ICPU_MEMCTRL_DQS_DLY(bytelane));
+	while ((res = look_past(bytelane)) == DDR_TRAIN_CONTINUE)
+		;
+	if (res != DDR_TRAIN_OK)
+		return res;
+	/* Reset FIFO - for good measure */
+	memphy_soft_reset();
+	/* Adjust to center [dqs_s;cur] */
+	center_dly(bytelane, dqs_s);
+	return DDR_TRAIN_OK;
+}
+
+/* This algorithm is converted from the TCL training algorithm used
+ * during silicon simulation.
+ * NB: Assumes inlining as no stack is available!
+ */
+static inline int hal_vcoreiii_init_dqs(void)
+{
+#define MAX_DQS 32
+	register u32 i, j;
+
+	for (i = 0; i < MAX_DQS; i++) {
+		set_dly(0, i);	/* Byte-lane 0 */
+		for (j = 0; j < MAX_DQS; j++) {
+			__maybe_unused register u32  byte;
+
+			set_dly(1, j);	/* Byte-lane 1 */
+			/* Reset FIFO in case any previous access failed */
+			memphy_soft_reset();
+			writel(readl(BASE_CFG + ICPU_MEMCTRL_STAT),
+			       BASE_CFG + ICPU_MEMCTRL_STAT);
+			byte = __raw_readb((void __iomem *)MSCC_DDR_TO);
+			byte = __raw_readb((void __iomem *)(MSCC_DDR_TO + 1));
+			if (!(readl(BASE_CFG + ICPU_MEMCTRL_STAT) &
+			    (ICPU_MEMCTRL_STAT_RDATA_MASKED |
+			     ICPU_MEMCTRL_STAT_RDATA_DUMMY)))
+				return 0;
+		}
+	}
+	return -1;
+}
+
+static inline int dram_check(void)
+{
+	register u32 i;
+
+	for (i = 0; i < 8; i++) {
+		__raw_writel(~i, (void __iomem *)(MSCC_DDR_TO + (i * 4)));
+		if (__raw_readl((void __iomem *)(MSCC_DDR_TO + (i * 4))) != ~i)
+			return 1;
+	}
+	return 0;
+}
+#else				/* Luton */
+
+static inline void sleep_100ns(u32 val)
+{
+}
+
+static inline void hal_vcoreiii_ddr_reset_assert(void)
+{
+	setbits_le32(BASE_CFG + ICPU_MEMPHY_CFG, ICPU_MEMPHY_CFG_PHY_RST);
+	setbits_le32(BASE_CFG + ICPU_RESET, ICPU_RESET_MEM_RST_FORCE);
+}
+
+static inline void hal_vcoreiii_ddr_reset_release(void)
+{
+}
+
+static inline void hal_vcoreiii_ddr_failed(void)
+{
+	register u32 memphy_cfg = readl(BASE_CFG + ICPU_MEMPHY_CFG);
+
+	/* Do a fifo reset and start over */
+	writel(memphy_cfg | ICPU_MEMPHY_CFG_PHY_FIFO_RST,
+	       BASE_CFG + ICPU_MEMPHY_CFG);
+	writel(memphy_cfg & ~ICPU_MEMPHY_CFG_PHY_FIFO_RST,
+	       BASE_CFG + ICPU_MEMPHY_CFG);
+	writel(memphy_cfg | ICPU_MEMPHY_CFG_PHY_FIFO_RST,
+	       BASE_CFG + ICPU_MEMPHY_CFG);
+}
+
+static inline void hal_vcoreiii_ddr_verified(void)
+{
+}
+
+static inline int look_for(u32 data)
+{
+	register u32 byte = __raw_readb((void __iomem *)MSCC_DDR_TO);
+
+	if (data != byte) {
+		if (!incr_dly(0))
+			return DDR_TRAIN_ERROR;
+		return DDR_TRAIN_CONTINUE;
+	}
+
+	return DDR_TRAIN_OK;
+}
+
+/* This algorithm is converted from the TCL training algorithm used
+ * during silicon simulation.
+ * NB: Assumes inlining as no stack is available!
+ */
+static inline int hal_vcoreiii_train_bytelane(u32 bytelane)
+{
+	register int res;
+
+	set_dly(bytelane, 0);	/* Start training at DQS=0 */
+	while ((res = look_for(0xff)) == DDR_TRAIN_CONTINUE)
+		;
+	if (res != DDR_TRAIN_OK)
+		return res;
+
+	set_dly(bytelane, 0);	/* Start training at DQS=0 */
+	while ((res = look_for(0x00)) == DDR_TRAIN_CONTINUE)
+
+		;
+
+	if (res != DDR_TRAIN_OK)
+		return res;
+
+	adjust_dly(-3);
+
+	return DDR_TRAIN_OK;
+}
+
+static inline int hal_vcoreiii_init_dqs(void)
+{
+	return 0;
+}
+
+static inline int dram_check(void)
+{
+	register u32 i;
+
+	for (i = 0; i < 8; i++) {
+		__raw_writel(~i, (void __iomem *)(MSCC_DDR_TO + (i * 4)));
+
+		if (__raw_readl((void __iomem *)(MSCC_DDR_TO + (i * 4))) != ~i)
+			return 1;
+	}
+
+	return 0;
+}
+#endif
+
+/*
+ * NB: Called *early* to init memory controller - assumes inlining as
+ * no stack is available!
+ */
+static inline void hal_vcoreiii_init_memctl(void)
+{
+	/* Ensure DDR is in reset */
+	hal_vcoreiii_ddr_reset_assert();
+
+	/* Wait maybe not needed, but ... */
+	PAUSE();
+
+	/* Drop sys ctl memory controller forced reset */
+	clrbits_le32(BASE_CFG + ICPU_RESET, ICPU_RESET_MEM_RST_FORCE);
+
+	PAUSE();
+
+	/* Drop Reset, enable SSTL */
+	writel(ICPU_MEMPHY_CFG_PHY_SSTL_ENA, BASE_CFG + ICPU_MEMPHY_CFG);
+	PAUSE();
+
+	/* Start the automatic SSTL output and ODT drive-strength calibration */
+	writel(ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT(MIPS_VCOREIII_MEMORY_SSTL_ODT) |
+	       /* drive strength */
+	       ICPU_MEMPHY_ZCAL_ZCAL_PROG(MIPS_VCOREIII_MEMORY_SSTL_DRIVE) |
+	       /* Start calibration process */
+	       ICPU_MEMPHY_ZCAL_ZCAL_ENA, BASE_CFG + ICPU_MEMPHY_ZCAL);
+
+	/* Wait for ZCAL to clear */
+	while (readl(BASE_CFG + ICPU_MEMPHY_ZCAL) & ICPU_MEMPHY_ZCAL_ZCAL_ENA)
+		;
+#ifdef CONFIG_SOC_OCELOT
+	/* Check no ZCAL_ERR */
+	if (readl(BASE_CFG + ICPU_MEMPHY_ZCAL_STAT)
+	    & ICPU_MEMPHY_ZCAL_STAT_ZCAL_ERR)
+		hal_vcoreiii_ddr_failed();
+#endif
+	/* Drive CL, CK, ODT */
+	setbits_le32(BASE_CFG + ICPU_MEMPHY_CFG, ICPU_MEMPHY_CFG_PHY_ODT_OE |
+		     ICPU_MEMPHY_CFG_PHY_CK_OE | ICPU_MEMPHY_CFG_PHY_CL_OE);
+
+	/* Initialize memory controller */
+	writel(MSCC_MEMPARM_MEMCFG, BASE_CFG + ICPU_MEMCTRL_CFG);
+	writel(MSCC_MEMPARM_PERIOD, BASE_CFG + ICPU_MEMCTRL_REF_PERIOD);
+
+#ifdef CONFIG_SOC_OCELOT
+	writel(MSCC_MEMPARM_TIMING0, BASE_CFG + ICPU_MEMCTRL_TIMING0);
+#else /* Luton */
+	clrbits_le32(BASE_CFG + ICPU_MEMCTRL_TIMING0, ((1 << 20) - 1));
+	setbits_le32(BASE_CFG + ICPU_MEMCTRL_TIMING0, MSCC_MEMPARM_TIMING0);
+#endif
+
+	writel(MSCC_MEMPARM_TIMING1, BASE_CFG + ICPU_MEMCTRL_TIMING1);
+	writel(MSCC_MEMPARM_TIMING2, BASE_CFG + ICPU_MEMCTRL_TIMING2);
+	writel(MSCC_MEMPARM_TIMING3, BASE_CFG + ICPU_MEMCTRL_TIMING3);
+	writel(MSCC_MEMPARM_MR0, BASE_CFG + ICPU_MEMCTRL_MR0_VAL);
+	writel(MSCC_MEMPARM_MR1, BASE_CFG + ICPU_MEMCTRL_MR1_VAL);
+	writel(MSCC_MEMPARM_MR2, BASE_CFG + ICPU_MEMCTRL_MR2_VAL);
+	writel(MSCC_MEMPARM_MR3, BASE_CFG + ICPU_MEMCTRL_MR3_VAL);
+
+#ifdef CONFIG_SOC_OCELOT
+	/* Termination setup - enable ODT */
+	writel(ICPU_MEMCTRL_TERMRES_CTRL_LOCAL_ODT_RD_ENA |
+	       /* Assert ODT0 for any write */
+	       ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA(3),
+	       BASE_CFG + ICPU_MEMCTRL_TERMRES_CTRL);
+
+	/* Release Reset from DDR */
+	hal_vcoreiii_ddr_reset_release();
+
+	writel(readl(BASE_CFG + ICPU_GPR(7)) + 1, BASE_CFG + ICPU_GPR(7));
+#else				/* Luton */
+	/* Termination setup - disable ODT */
+	writel(0, BASE_CFG + ICPU_MEMCTRL_TERMRES_CTRL);
+
+#endif
+}
+
+static inline void hal_vcoreiii_wait_memctl(void)
+{
+	/* Now, rip it! */
+	writel(ICPU_MEMCTRL_CTRL_INITIALIZE, BASE_CFG + ICPU_MEMCTRL_CTRL);
+
+	while (!(readl(BASE_CFG + ICPU_MEMCTRL_STAT)
+		 & ICPU_MEMCTRL_STAT_INIT_DONE))
+		;
+
+	/* Settle...? */
+	sleep_100ns(10000);
+#ifdef CONFIG_SOC_OCELOT
+	/* Establish data contents in DDR RAM for training */
+
+	__raw_writel(0xcacafefe, ((void __iomem *)MSCC_DDR_TO));
+	__raw_writel(0x22221111, ((void __iomem *)MSCC_DDR_TO + 0x4));
+	__raw_writel(0x44443333, ((void __iomem *)MSCC_DDR_TO + 0x8));
+	__raw_writel(0x66665555, ((void __iomem *)MSCC_DDR_TO + 0xC));
+	__raw_writel(0x88887777, ((void __iomem *)MSCC_DDR_TO + 0x10));
+	__raw_writel(0xaaaa9999, ((void __iomem *)MSCC_DDR_TO + 0x14));
+	__raw_writel(0xccccbbbb, ((void __iomem *)MSCC_DDR_TO + 0x18));
+	__raw_writel(0xeeeedddd, ((void __iomem *)MSCC_DDR_TO + 0x1C));
+#else
+	__raw_writel(0xff, ((void __iomem *)MSCC_DDR_TO));
+#endif
+}
+#endif				/* __ASM_MACH_DDR_H */
diff --git a/arch/mips/mach-mscc/include/mach/luton/luton.h b/arch/mips/mach-mscc/include/mach/luton/luton.h
new file mode 100644
index 0000000..19f02ed
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/luton/luton.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_H_
+#define _MSCC_OCELOT_H_
+
+#include <linux/bitops.h>
+#include <dm.h>
+
+/*
+ * Target offset base(s)
+ */
+#define MSCC_IO_ORIGIN1_OFFSET 0x60000000
+#define MSCC_IO_ORIGIN1_SIZE   0x01000000
+#define MSCC_IO_ORIGIN2_OFFSET 0x70000000
+#define MSCC_IO_ORIGIN2_SIZE   0x00200000
+#define BASE_CFG        ((void __iomem *)0x70000000)
+#define BASE_DEVCPU_GCB ((void __iomem *)0x60070000)
+
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/luton/luton_devcpu_gcb.h b/arch/mips/mach-mscc/include/mach/luton/luton_devcpu_gcb.h
new file mode 100644
index 0000000..8c0b612
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/luton/luton_devcpu_gcb.h
@@ -0,0 +1,14 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_DEVCPU_GCB_H_
+#define _MSCC_OCELOT_DEVCPU_GCB_H_
+
+#define PERF_SOFT_RST                                     0x90
+
+#define PERF_SOFT_RST_SOFT_SWC_RST                        BIT(1)
+#define PERF_SOFT_RST_SOFT_CHIP_RST                       BIT(0)
+
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/luton/luton_icpu_cfg.h b/arch/mips/mach-mscc/include/mach/luton/luton_icpu_cfg.h
new file mode 100644
index 0000000..9233f03
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/luton/luton_icpu_cfg.h
@@ -0,0 +1,245 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_ICPU_CFG_H_
+#define _MSCC_OCELOT_ICPU_CFG_H_
+
+#define ICPU_GPR(x) (0x4 * (x))
+#define ICPU_GPR_RSZ                                      0x4
+
+#define ICPU_RESET                                        0x20
+
+#define ICPU_RESET_CORE_RST_CPU_ONLY                      BIT(3)
+#define ICPU_RESET_CORE_RST_PROTECT                       BIT(2)
+#define ICPU_RESET_CORE_RST_FORCE                         BIT(1)
+#define ICPU_RESET_MEM_RST_FORCE                          BIT(0)
+
+#define ICPU_GENERAL_CTRL                                 0x24
+
+#define ICPU_GENERAL_CTRL_SWC_CLEAR_IF                    BIT(6)
+#define ICPU_GENERAL_CTRL_CPU_BUSIF_SLEEP_DIS             BIT(5)
+#define ICPU_GENERAL_CTRL_CPU_BUSIF_WERR_ENA              BIT(4)
+#define ICPU_GENERAL_CTRL_IF_MASTER_DIS                   BIT(3)
+#define ICPU_GENERAL_CTRL_IF_MASTER_SPI_ENA               BIT(2)
+#define ICPU_GENERAL_CTRL_IF_MASTER_PI_ENA                BIT(1)
+
+#define ICPU_GENERAL_CTRL_BOOT_MODE_ENA                   BIT(0)
+
+#define ICPU_PI_MST_CFG                                   0x2c
+
+#define ICPU_PI_MST_CFG_ATE_MODE_DIS                      BIT(7)
+#define ICPU_PI_MST_CFG_CLK_POL                           BIT(6)
+#define ICPU_PI_MST_CFG_TRISTATE_CTRL                     BIT(5)
+#define ICPU_PI_MST_CFG_CLK_DIV(x)                        ((x) & GENMASK(4, 0))
+#define ICPU_PI_MST_CFG_CLK_DIV_M                         GENMASK(4, 0)
+
+#define ICPU_SPI_MST_CFG                                  0x50
+
+#define ICPU_SPI_MST_CFG_FAST_READ_ENA                    BIT(10)
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME(x)              (((x) << 5) & GENMASK(9, 5))
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME_M               GENMASK(9, 5)
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME_X(x)            (((x) & GENMASK(9, 5)) >> 5)
+#define ICPU_SPI_MST_CFG_CLK_DIV(x)                       ((x) & GENMASK(4, 0))
+#define ICPU_SPI_MST_CFG_CLK_DIV_M                        GENMASK(4, 0)
+
+#define ICPU_SW_MODE                                      0x64
+
+#define ICPU_SW_MODE_SW_PIN_CTRL_MODE                     BIT(13)
+#define ICPU_SW_MODE_SW_SPI_SCK                           BIT(12)
+#define ICPU_SW_MODE_SW_SPI_SCK_OE                        BIT(11)
+#define ICPU_SW_MODE_SW_SPI_SDO                           BIT(10)
+#define ICPU_SW_MODE_SW_SPI_SDO_OE                        BIT(9)
+#define ICPU_SW_MODE_SW_SPI_CS(x)                         (((x) << 5) & GENMASK(8, 5))
+#define ICPU_SW_MODE_SW_SPI_CS_M                          GENMASK(8, 5)
+#define ICPU_SW_MODE_SW_SPI_CS_X(x)                       (((x) & GENMASK(8, 5)) >> 5)
+#define ICPU_SW_MODE_SW_SPI_CS_OE(x)                      (((x) << 1) & GENMASK(4, 1))
+#define ICPU_SW_MODE_SW_SPI_CS_OE_M                       GENMASK(4, 1)
+#define ICPU_SW_MODE_SW_SPI_CS_OE_X(x)                    (((x) & GENMASK(4, 1)) >> 1)
+#define ICPU_SW_MODE_SW_SPI_SDI                           BIT(0)
+
+#define ICPU_INTR_ENA                                     0x88
+
+#define ICPU_INTR_IRQ0_ENA                                0x98
+#define ICPU_INTR_IRQ0_ENA_IRQ0_ENA                       BIT(0)
+
+#define ICPU_MEMCTRL_CTRL                                 0x234
+
+#define ICPU_MEMCTRL_CTRL_PWR_DOWN                        BIT(3)
+#define ICPU_MEMCTRL_CTRL_MDSET                           BIT(2)
+#define ICPU_MEMCTRL_CTRL_STALL_REF_ENA                   BIT(1)
+#define ICPU_MEMCTRL_CTRL_INITIALIZE                      BIT(0)
+
+#define ICPU_MEMCTRL_CFG                                  0x238
+
+#define ICPU_MEMCTRL_CFG_DDR_512MBYTE_PLUS                BIT(16)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_ERR_ENA                  BIT(15)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_COR_ENA                  BIT(14)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_ENA                      BIT(13)
+#define ICPU_MEMCTRL_CFG_DDR_WIDTH                        BIT(12)
+#define ICPU_MEMCTRL_CFG_DDR_MODE                         BIT(11)
+#define ICPU_MEMCTRL_CFG_BURST_SIZE                       BIT(10)
+#define ICPU_MEMCTRL_CFG_BURST_LEN                        BIT(9)
+#define ICPU_MEMCTRL_CFG_BANK_CNT                         BIT(8)
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR(x)                  (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR_M                   GENMASK(7, 4)
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR_X(x)                (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_CFG_MSB_COL_ADDR(x)                  ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_CFG_MSB_COL_ADDR_M                   GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_STAT                                 0x23C
+
+#define ICPU_MEMCTRL_STAT_RDATA_MASKED                    BIT(5)
+#define ICPU_MEMCTRL_STAT_RDATA_DUMMY                     BIT(4)
+#define ICPU_MEMCTRL_STAT_RDATA_ECC_ERR                   BIT(3)
+#define ICPU_MEMCTRL_STAT_RDATA_ECC_COR                   BIT(2)
+#define ICPU_MEMCTRL_STAT_PWR_DOWN_ACK                    BIT(1)
+#define ICPU_MEMCTRL_STAT_INIT_DONE                       BIT(0)
+
+#define ICPU_MEMCTRL_REF_PERIOD                           0x240
+
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF(x)           (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF_M            GENMASK(19, 16)
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF_X(x)         (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD(x)             ((x) & GENMASK(15, 0))
+#define ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD_M              GENMASK(15, 0)
+
+#define ICPU_MEMCTRL_TIMING0                              0x248
+
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY(x)              (((x) << 28) & GENMASK(31, 28))
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY_M               GENMASK(31, 28)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY_X(x)            (((x) & GENMASK(31, 28)) >> 28)
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY(x)          (((x) << 24) & GENMASK(27, 24))
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY_M           GENMASK(27, 24)
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY_X(x)        (((x) & GENMASK(27, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY(x)          (((x) << 20) & GENMASK(23, 20))
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY_M           GENMASK(23, 20)
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY_X(x)        (((x) & GENMASK(23, 20)) >> 20)
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY(x)          (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY_M           GENMASK(19, 16)
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY_X(x)        (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY(x)           (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY_M            GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY_X(x)         (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY(x)           (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY_M            GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY_X(x)         (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY(x)           (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY_M            GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY_X(x)         (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY(x)           ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY_M            GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_TIMING1                              0x24c
+
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY(x)  (((x) << 24) & GENMASK(31, 24))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY_M   GENMASK(31, 24)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY_X(x) (((x) & GENMASK(31, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY(x)             (((x) << 16) & GENMASK(23, 16))
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY_M              GENMASK(23, 16)
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY_X(x)           (((x) & GENMASK(23, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY(x)          (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY_M           GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY_X(x)        (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY(x)            (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY_M             GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY_X(x)          (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY(x)            (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY_M             GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY_X(x)          (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY(x)              ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY_M               GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_TIMING2                              0x250
+
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY(x)             (((x) << 28) & GENMASK(31, 28))
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY_M              GENMASK(31, 28)
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY_X(x)           (((x) & GENMASK(31, 28)) >> 28)
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY(x)                 (((x) << 24) & GENMASK(27, 24))
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY_M                  GENMASK(27, 24)
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY_X(x)               (((x) & GENMASK(27, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING2_REF_DLY(x)                   (((x) << 16) & GENMASK(23, 16))
+#define ICPU_MEMCTRL_TIMING2_REF_DLY_M                    GENMASK(23, 16)
+#define ICPU_MEMCTRL_TIMING2_REF_DLY_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING2_FOUR_HUNDRED_NS_DLY(x)       ((x) & GENMASK(15, 0))
+#define ICPU_MEMCTRL_TIMING2_FOUR_HUNDRED_NS_DLY_M        GENMASK(15, 0)
+
+#define ICPU_MEMCTRL_TIMING3                              0x254
+
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY(x)                   (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY_M                    GENMASK(19, 16)
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY_X(x)                 (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY(x)                (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY_M                 GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY_X(x)              (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY(x)                (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY_M                 GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY_X(x)              (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY(x)          (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY_M           GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY_X(x)        (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY(x)    ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY_M     GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_MR0_VAL                              0x258
+
+#define ICPU_MEMCTRL_MR1_VAL                              0x25c
+
+#define ICPU_MEMCTRL_MR2_VAL                              0x260
+
+#define ICPU_MEMCTRL_MR3_VAL                              0x264
+
+#define ICPU_MEMCTRL_TERMRES_CTRL                         0x268
+
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_EXT              BIT(11)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA(x)           (((x) << 7) & GENMASK(10, 7))
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA_M            GENMASK(10, 7)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA_X(x)         (((x) & GENMASK(10, 7)) >> 7)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_EXT              BIT(6)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA(x)           (((x) << 2) & GENMASK(5, 2))
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA_M            GENMASK(5, 2)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA_X(x)         (((x) & GENMASK(5, 2)) >> 2)
+#define ICPU_MEMCTRL_TERMRES_CTRL_LOCAL_ODT_RD_EXT        BIT(1)
+#define ICPU_MEMCTRL_TERMRES_CTRL_LOCAL_ODT_RD_ENA        BIT(0)
+
+#define ICPU_MEMCTRL_DQS_DLY(x) (0x270)
+
+#define ICPU_MEMCTRL_DQS_DLY_TRAIN_DQ_ENA                 BIT(11)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1(x)              (((x) << 8) & GENMASK(10, 8))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1_M               GENMASK(10, 8)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1_X(x)            (((x) & GENMASK(10, 8)) >> 8)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0(x)              (((x) << 5) & GENMASK(7, 5))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0_M               GENMASK(7, 5)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0_X(x)            (((x) & GENMASK(7, 5)) >> 5)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY(x)                   ((x) & GENMASK(4, 0))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_M                    GENMASK(4, 0)
+
+#define ICPU_MEMPHY_CFG                                   0x278
+
+#define ICPU_MEMPHY_CFG_PHY_FLUSH_DIS                     BIT(10)
+#define ICPU_MEMPHY_CFG_PHY_RD_ADJ_DIS                    BIT(9)
+#define ICPU_MEMPHY_CFG_PHY_DQS_EXT                       BIT(8)
+#define ICPU_MEMPHY_CFG_PHY_FIFO_RST                      BIT(7)
+#define ICPU_MEMPHY_CFG_PHY_DLL_BL_RST                    BIT(6)
+#define ICPU_MEMPHY_CFG_PHY_DLL_CL_RST                    BIT(5)
+#define ICPU_MEMPHY_CFG_PHY_ODT_OE                        BIT(4)
+#define ICPU_MEMPHY_CFG_PHY_CK_OE                         BIT(3)
+#define ICPU_MEMPHY_CFG_PHY_CL_OE                         BIT(2)
+#define ICPU_MEMPHY_CFG_PHY_SSTL_ENA                      BIT(1)
+#define ICPU_MEMPHY_CFG_PHY_RST                           BIT(0)
+#define ICPU_MEMPHY_DQ_DLY_TRM                            0x180
+#define ICPU_MEMPHY_DQ_DLY_TRM_RSZ                        0x4
+
+#define ICPU_MEMPHY_ZCAL                                  0x294
+
+#define ICPU_MEMPHY_ZCAL_ZCAL_CLK_SEL                     BIT(9)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT(x)                 (((x) << 5) & GENMASK(8, 5))
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT_M                  GENMASK(8, 5)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT_X(x)               (((x) & GENMASK(8, 5)) >> 5)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG(x)                     (((x) << 1) & GENMASK(4, 1))
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_M                      GENMASK(4, 1)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_X(x)                   (((x) & GENMASK(4, 1)) >> 1)
+#define ICPU_MEMPHY_ZCAL_ZCAL_ENA                         BIT(0)
+
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/ocelot/ocelot.h b/arch/mips/mach-mscc/include/mach/ocelot/ocelot.h
new file mode 100644
index 0000000..2cb2135
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/ocelot/ocelot.h
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Microsemi Ocelot Switch driver
+ *
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_H_
+#define _MSCC_OCELOT_H_
+
+#include <linux/bitops.h>
+#include <dm.h>
+
+/*
+ * Target offset base(s)
+ */
+#define MSCC_IO_ORIGIN1_OFFSET 0x70000000
+#define MSCC_IO_ORIGIN1_SIZE   0x00200000
+#define MSCC_IO_ORIGIN2_OFFSET 0x71000000
+#define MSCC_IO_ORIGIN2_SIZE   0x01000000
+#define BASE_CFG        ((void __iomem *)0x70000000)
+#define BASE_DEVCPU_GCB ((void __iomem *)0x71070000)
+
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h
new file mode 100644
index 0000000..f8aa97b
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_devcpu_gcb.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_DEVCPU_GCB_H_
+#define _MSCC_OCELOT_DEVCPU_GCB_H_
+
+#define PERF_SOFT_RST                                     0x8
+
+#define PERF_SOFT_RST_SOFT_NON_CFG_RST                    BIT(2)
+#define PERF_SOFT_RST_SOFT_SWC_RST                        BIT(1)
+#define PERF_SOFT_RST_SOFT_CHIP_RST                       BIT(0)
+
+#define PERF_GPIO_OUT_SET                                 0x34
+
+#define PERF_GPIO_OUT_CLR                                 0x38
+
+#define PERF_GPIO_OE                                      0x44
+
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/ocelot/ocelot_icpu_cfg.h b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_icpu_cfg.h
new file mode 100644
index 0000000..04cf70b
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/ocelot/ocelot_icpu_cfg.h
@@ -0,0 +1,274 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef _MSCC_OCELOT_ICPU_CFG_H_
+#define _MSCC_OCELOT_ICPU_CFG_H_
+
+#define ICPU_GPR(x) (0x4 * (x))
+#define ICPU_GPR_RSZ                                      0x4
+
+#define ICPU_RESET                                        0x20
+
+#define ICPU_RESET_CORE_RST_CPU_ONLY                      BIT(3)
+#define ICPU_RESET_CORE_RST_PROTECT                       BIT(2)
+#define ICPU_RESET_CORE_RST_FORCE                         BIT(1)
+#define ICPU_RESET_MEM_RST_FORCE                          BIT(0)
+
+#define ICPU_GENERAL_CTRL                                 0x24
+
+#define ICPU_GENERAL_CTRL_CPU_BUSIF_SLEEP_DIS             BIT(14)
+#define ICPU_GENERAL_CTRL_CPU_BUSIF_WERR_ENA              BIT(13)
+#define ICPU_GENERAL_CTRL_CPU_8051_IROM_ENA               BIT(12)
+#define ICPU_GENERAL_CTRL_CPU_MIPS_DIS                    BIT(11)
+#define ICPU_GENERAL_CTRL_IF_MIIM_SLV_ADDR_SEL            BIT(10)
+#define ICPU_GENERAL_CTRL_IF_MIIM_SLV_ENA                 BIT(9)
+#define ICPU_GENERAL_CTRL_IF_PI_SLV_DONEPOL               BIT(8)
+#define ICPU_GENERAL_CTRL_IF_PI_MST_ENA                   BIT(7)
+#define ICPU_GENERAL_CTRL_IF_PI_SLV_ENA                   BIT(6)
+#define ICPU_GENERAL_CTRL_IF_SI_OWNER(x)                  (((x) << 4) & GENMASK(5, 4))
+#define ICPU_GENERAL_CTRL_IF_SI_OWNER_M                   GENMASK(5, 4)
+#define ICPU_GENERAL_CTRL_IF_SI_OWNER_X(x)                (((x) & GENMASK(5, 4)) >> 4)
+#define ICPU_GENERAL_CTRL_SSI_MST_CONTENTION              BIT(3)
+#define ICPU_GENERAL_CTRL_CPU_BE_ENA                      BIT(2)
+#define ICPU_GENERAL_CTRL_CPU_DIS                         BIT(1)
+#define ICPU_GENERAL_CTRL_BOOT_MODE_ENA                   BIT(0)
+#define ICPU_SPI_MST_CFG                                  0x3c
+
+#define ICPU_SPI_MST_CFG_A32B_ENA                         BIT(11)
+#define ICPU_SPI_MST_CFG_FAST_READ_ENA                    BIT(10)
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME(x)              (((x) << 5) & GENMASK(9, 5))
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME_M               GENMASK(9, 5)
+#define ICPU_SPI_MST_CFG_CS_DESELECT_TIME_X(x)            (((x) & GENMASK(9, 5)) >> 5)
+#define ICPU_SPI_MST_CFG_CLK_DIV(x)                       ((x) & GENMASK(4, 0))
+#define ICPU_SPI_MST_CFG_CLK_DIV_M                        GENMASK(4, 0)
+
+#define ICPU_SW_MODE                                      0x50
+
+#define ICPU_SW_MODE_SW_PIN_CTRL_MODE                     BIT(13)
+#define ICPU_SW_MODE_SW_SPI_SCK                           BIT(12)
+#define ICPU_SW_MODE_SW_SPI_SCK_OE                        BIT(11)
+#define ICPU_SW_MODE_SW_SPI_SDO                           BIT(10)
+#define ICPU_SW_MODE_SW_SPI_SDO_OE                        BIT(9)
+#define ICPU_SW_MODE_SW_SPI_CS(x)                         (((x) << 5) & GENMASK(8, 5))
+#define ICPU_SW_MODE_SW_SPI_CS_M                          GENMASK(8, 5)
+#define ICPU_SW_MODE_SW_SPI_CS_X(x)                       (((x) & GENMASK(8, 5)) >> 5)
+#define ICPU_SW_MODE_SW_SPI_CS_OE(x)                      (((x) << 1) & GENMASK(4, 1))
+#define ICPU_SW_MODE_SW_SPI_CS_OE_M                       GENMASK(4, 1)
+#define ICPU_SW_MODE_SW_SPI_CS_OE_X(x)                    (((x) & GENMASK(4, 1)) >> 1)
+#define ICPU_SW_MODE_SW_SPI_SDI                           BIT(0)
+
+#define ICPU_INTR_ENA					  0x88
+
+#define ICPU_DST_INTR_MAP(x)  (0x98 + 0x4 * (x))
+#define ICPU_DST_INTR_MAP_RSZ                             0x4
+
+#define ICPU_DST_INTR_IDENT                               0xa8
+#define ICPU_DST_INTR_IDENT_RSZ                           0x4
+
+#define ICPU_TIMER_TICK_DIV                               0xe8
+#define ICPU_TIMER_VALUE(x) (0xec + 0x4 * (x))
+
+#define ICPU_TIMER_CTRL(x) (0x104 + 0x4 * (x))
+#define ICPU_TIMER_CTRL_MAX_FREQ_ENA			  BIT(3)
+#define ICPU_TIMER_CTRL_ONE_SHOT_ENA			  BIT(2)
+#define ICPU_TIMER_CTRL_TIMER_ENA			  BIT(1)
+#define ICPU_TIMER_CTRL_FORCE_RELOAD			  BIT(0)
+
+#define ICPU_MEMCTRL_CTRL                                 0x110
+#define ICPU_MEMCTRL_CTRL_PWR_DOWN                        BIT(3)
+#define ICPU_MEMCTRL_CTRL_MDSET                           BIT(2)
+#define ICPU_MEMCTRL_CTRL_STALL_REF_ENA                   BIT(1)
+#define ICPU_MEMCTRL_CTRL_INITIALIZE                      BIT(0)
+
+#define ICPU_MEMCTRL_CFG                                  0x114
+
+#define ICPU_MEMCTRL_CFG_DDR_512MBYTE_PLUS                BIT(16)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_ERR_ENA                  BIT(15)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_COR_ENA                  BIT(14)
+#define ICPU_MEMCTRL_CFG_DDR_ECC_ENA                      BIT(13)
+#define ICPU_MEMCTRL_CFG_DDR_WIDTH                        BIT(12)
+#define ICPU_MEMCTRL_CFG_DDR_MODE                         BIT(11)
+#define ICPU_MEMCTRL_CFG_BURST_SIZE                       BIT(10)
+#define ICPU_MEMCTRL_CFG_BURST_LEN                        BIT(9)
+#define ICPU_MEMCTRL_CFG_BANK_CNT                         BIT(8)
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR(x)                  (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR_M                   GENMASK(7, 4)
+#define ICPU_MEMCTRL_CFG_MSB_ROW_ADDR_X(x)                (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_CFG_MSB_COL_ADDR(x)                  ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_CFG_MSB_COL_ADDR_M                   GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_STAT                                 0x118
+
+#define ICPU_MEMCTRL_STAT_RDATA_MASKED                    BIT(5)
+#define ICPU_MEMCTRL_STAT_RDATA_DUMMY                     BIT(4)
+#define ICPU_MEMCTRL_STAT_RDATA_ECC_ERR                   BIT(3)
+#define ICPU_MEMCTRL_STAT_RDATA_ECC_COR                   BIT(2)
+#define ICPU_MEMCTRL_STAT_PWR_DOWN_ACK                    BIT(1)
+#define ICPU_MEMCTRL_STAT_INIT_DONE                       BIT(0)
+
+#define ICPU_MEMCTRL_REF_PERIOD                           0x11c
+
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF(x)           (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF_M            GENMASK(19, 16)
+#define ICPU_MEMCTRL_REF_PERIOD_MAX_PEND_REF_X(x)         (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD(x)             ((x) & GENMASK(15, 0))
+#define ICPU_MEMCTRL_REF_PERIOD_REF_PERIOD_M              GENMASK(15, 0)
+
+#define ICPU_MEMCTRL_TIMING0                              0x124
+
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY(x)              (((x) << 28) & GENMASK(31, 28))
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY_M               GENMASK(31, 28)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_WR_DLY_X(x)            (((x) & GENMASK(31, 28)) >> 28)
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY(x)          (((x) << 24) & GENMASK(27, 24))
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY_M           GENMASK(27, 24)
+#define ICPU_MEMCTRL_TIMING0_WR_CS_CHANGE_DLY_X(x)        (((x) & GENMASK(27, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY(x)          (((x) << 20) & GENMASK(23, 20))
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY_M           GENMASK(23, 20)
+#define ICPU_MEMCTRL_TIMING0_RD_CS_CHANGE_DLY_X(x)        (((x) & GENMASK(23, 20)) >> 20)
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY(x)          (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY_M           GENMASK(19, 16)
+#define ICPU_MEMCTRL_TIMING0_RAS_TO_PRECH_DLY_X(x)        (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY(x)           (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY_M            GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING0_WR_TO_PRECH_DLY_X(x)         (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY(x)           (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY_M            GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING0_RD_TO_PRECH_DLY_X(x)         (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY(x)           (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY_M            GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING0_WR_DATA_XFR_DLY_X(x)         (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY(x)           ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING0_RD_DATA_XFR_DLY_M            GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_TIMING1                              0x128
+
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY(x)  (((x) << 24) & GENMASK(31, 24))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY_M   GENMASK(31, 24)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_SAME_BANK_DLY_X(x) (((x) & GENMASK(31, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY(x)             (((x) << 16) & GENMASK(23, 16))
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY_M              GENMASK(23, 16)
+#define ICPU_MEMCTRL_TIMING1_BANK8_FAW_DLY_X(x)           (((x) & GENMASK(23, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY(x)          (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY_M           GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING1_PRECH_TO_RAS_DLY_X(x)        (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY(x)            (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY_M             GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_RAS_DLY_X(x)          (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY(x)            (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY_M             GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING1_RAS_TO_CAS_DLY_X(x)          (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY(x)              ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING1_WR_TO_RD_DLY_M               GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_TIMING2                              0x12c
+
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY(x)             (((x) << 28) & GENMASK(31, 28))
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY_M              GENMASK(31, 28)
+#define ICPU_MEMCTRL_TIMING2_PRECH_ALL_DLY_X(x)           (((x) & GENMASK(31, 28)) >> 28)
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY(x)                 (((x) << 24) & GENMASK(27, 24))
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY_M                  GENMASK(27, 24)
+#define ICPU_MEMCTRL_TIMING2_MDSET_DLY_X(x)               (((x) & GENMASK(27, 24)) >> 24)
+#define ICPU_MEMCTRL_TIMING2_REF_DLY(x)                   (((x) << 16) & GENMASK(23, 16))
+#define ICPU_MEMCTRL_TIMING2_REF_DLY_M                    GENMASK(23, 16)
+#define ICPU_MEMCTRL_TIMING2_REF_DLY_X(x)                 (((x) & GENMASK(23, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING2_INIT_DLY(x)                  ((x) & GENMASK(15, 0))
+#define ICPU_MEMCTRL_TIMING2_INIT_DLY_M                   GENMASK(15, 0)
+
+#define ICPU_MEMCTRL_TIMING3                              0x130
+
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY(x)                   (((x) << 16) & GENMASK(19, 16))
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY_M                    GENMASK(19, 16)
+#define ICPU_MEMCTRL_TIMING3_RMW_DLY_X(x)                 (((x) & GENMASK(19, 16)) >> 16)
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY(x)                (((x) << 12) & GENMASK(15, 12))
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY_M                 GENMASK(15, 12)
+#define ICPU_MEMCTRL_TIMING3_ODT_RD_DLY_X(x)              (((x) & GENMASK(15, 12)) >> 12)
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY(x)                (((x) << 8) & GENMASK(11, 8))
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY_M                 GENMASK(11, 8)
+#define ICPU_MEMCTRL_TIMING3_ODT_WR_DLY_X(x)              (((x) & GENMASK(11, 8)) >> 8)
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY(x)          (((x) << 4) & GENMASK(7, 4))
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY_M           GENMASK(7, 4)
+#define ICPU_MEMCTRL_TIMING3_LOCAL_ODT_RD_DLY_X(x)        (((x) & GENMASK(7, 4)) >> 4)
+#define ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY(x)    ((x) & GENMASK(3, 0))
+#define ICPU_MEMCTRL_TIMING3_WR_TO_RD_CS_CHANGE_DLY_M     GENMASK(3, 0)
+
+#define ICPU_MEMCTRL_MR0_VAL                              0x138
+
+#define ICPU_MEMCTRL_MR1_VAL                              0x13c
+
+#define ICPU_MEMCTRL_MR2_VAL                              0x140
+
+#define ICPU_MEMCTRL_MR3_VAL                              0x144
+
+#define ICPU_MEMCTRL_TERMRES_CTRL                         0x148
+
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_EXT              BIT(11)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA(x)           (((x) << 7) & GENMASK(10, 7))
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA_M            GENMASK(10, 7)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_RD_ENA_X(x)         (((x) & GENMASK(10, 7)) >> 7)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_EXT              BIT(6)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA(x)           (((x) << 2) & GENMASK(5, 2))
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA_M            GENMASK(5, 2)
+#define ICPU_MEMCTRL_TERMRES_CTRL_ODT_WR_ENA_X(x)         (((x) & GENMASK(5, 2)) >> 2)
+#define ICPU_MEMCTRL_TERMRES_CTRL_LOCAL_ODT_RD_EXT        BIT(1)
+#define ICPU_MEMCTRL_TERMRES_CTRL_LOCAL_ODT_RD_ENA        BIT(0)
+
+#define ICPU_MEMCTRL_DQS_DLY(x) (0x150 + 0x4 * (x))
+#define ICPU_MEMCTRL_DQS_DLY_RSZ                          0x4
+
+#define ICPU_MEMCTRL_DQS_DLY_TRAIN_DQ_ENA                 BIT(11)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1(x)              (((x) << 8) & GENMASK(10, 8))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1_M               GENMASK(10, 8)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM1_X(x)            (((x) & GENMASK(10, 8)) >> 8)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0(x)              (((x) << 5) & GENMASK(7, 5))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0_M               GENMASK(7, 5)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_TRM0_X(x)            (((x) & GENMASK(7, 5)) >> 5)
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY(x)                   ((x) & GENMASK(4, 0))
+#define ICPU_MEMCTRL_DQS_DLY_DQS_DLY_M                    GENMASK(4, 0)
+
+#define ICPU_MEMPHY_CFG                                   0x160
+
+#define ICPU_MEMPHY_CFG_PHY_FLUSH_DIS                     BIT(10)
+#define ICPU_MEMPHY_CFG_PHY_RD_ADJ_DIS                    BIT(9)
+#define ICPU_MEMPHY_CFG_PHY_DQS_EXT                       BIT(8)
+#define ICPU_MEMPHY_CFG_PHY_FIFO_RST                      BIT(7)
+#define ICPU_MEMPHY_CFG_PHY_DLL_BL_RST                    BIT(6)
+#define ICPU_MEMPHY_CFG_PHY_DLL_CL_RST                    BIT(5)
+#define ICPU_MEMPHY_CFG_PHY_ODT_OE                        BIT(4)
+#define ICPU_MEMPHY_CFG_PHY_CK_OE                         BIT(3)
+#define ICPU_MEMPHY_CFG_PHY_CL_OE                         BIT(2)
+#define ICPU_MEMPHY_CFG_PHY_SSTL_ENA                      BIT(1)
+#define ICPU_MEMPHY_CFG_PHY_RST                           BIT(0)
+
+#define ICPU_MEMPHY_ZCAL                                  0x188
+
+#define ICPU_MEMPHY_ZCAL_ZCAL_CLK_SEL                     BIT(9)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT(x)                 (((x) << 5) & GENMASK(8, 5))
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT_M                  GENMASK(8, 5)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_ODT_X(x)               (((x) & GENMASK(8, 5)) >> 5)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG(x)                     (((x) << 1) & GENMASK(4, 1))
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_M                      GENMASK(4, 1)
+#define ICPU_MEMPHY_ZCAL_ZCAL_PROG_X(x)                   (((x) & GENMASK(4, 1)) >> 1)
+#define ICPU_MEMPHY_ZCAL_ZCAL_ENA                         BIT(0)
+
+#define ICPU_MEMPHY_ZCAL_STAT                             0x18c
+
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_ZCTRL(x)               (((x) << 12) & GENMASK(31, 12))
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_ZCTRL_M                GENMASK(31, 12)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_ZCTRL_X(x)             (((x) & GENMASK(31, 12)) >> 12)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPU(x)          (((x) << 8) & GENMASK(9, 8))
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPU_M           GENMASK(9, 8)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPU_X(x)        (((x) & GENMASK(9, 8)) >> 8)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPD(x)          (((x) << 6) & GENMASK(7, 6))
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPD_M           GENMASK(7, 6)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_ODTPD_X(x)        (((x) & GENMASK(7, 6)) >> 6)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PU(x)             (((x) << 4) & GENMASK(5, 4))
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PU_M              GENMASK(5, 4)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PU_X(x)           (((x) & GENMASK(5, 4)) >> 4)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PD(x)             (((x) << 2) & GENMASK(3, 2))
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PD_M              GENMASK(3, 2)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_STAT_PD_X(x)           (((x) & GENMASK(3, 2)) >> 2)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_ERR                    BIT(1)
+#define ICPU_MEMPHY_ZCAL_STAT_ZCAL_DONE                   BIT(0)
+#endif
diff --git a/arch/mips/mach-mscc/include/mach/tlb.h b/arch/mips/mach-mscc/include/mach/tlb.h
new file mode 100644
index 0000000..fdb554f
--- /dev/null
+++ b/arch/mips/mach-mscc/include/mach/tlb.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef __ASM_MACH_TLB_H
+#define __ASM_MACH_TLB_H
+
+#include <asm/mipsregs.h>
+#include <mach/common.h>
+#include <linux/sizes.h>
+
+#define TLB_HI_MASK      0xffffe000
+#define TLB_LO_MASK      0x3fffffff	/* Masks off Fill bits */
+#define TLB_LO_SHIFT     6	/* PFN Start bit */
+
+#define PAGEMASK_SHIFT   13
+
+#define MMU_PAGE_CACHED   (3 << 3)	/* C(5:3) Cache Coherency Attributes */
+#define MMU_PAGE_UNCACHED (2 << 3)	/* C(5:3) Cache Coherency Attributes */
+#define MMU_PAGE_DIRTY    BIT(2)	/* = Writeable */
+#define MMU_PAGE_VALID    BIT(1)
+#define MMU_PAGE_GLOBAL   BIT(0)
+#define MMU_REGIO_RO_C    (MMU_PAGE_CACHED | MMU_PAGE_VALID | MMU_PAGE_GLOBAL)
+#define MMU_REGIO_RO      (MMU_PAGE_UNCACHED | MMU_PAGE_VALID | MMU_PAGE_GLOBAL)
+#define MMU_REGIO_RW      (MMU_PAGE_DIRTY | MMU_REGIO_RO)
+#define MMU_REGIO_INVAL   (MMU_PAGE_GLOBAL)
+
+#define TLB_COUNT_MASK	  GENMASK(5, 0)
+#define TLB_COUNT_OFF	  25
+
+static inline u32 get_tlb_count(void)
+{
+	register u32 config1;
+
+	config1 = read_c0_config1();
+	config1 >>= TLB_COUNT_OFF;
+	config1 &= TLB_COUNT_MASK;
+
+	return 1 + config1;
+}
+
+static inline void create_tlb(int index, u32 offset, u32 size, u32 tlb_attrib1,
+			      u32 tlb_attrib2)
+{
+	register u32 tlb_mask, tlb_lo0, tlb_lo1;
+
+	tlb_mask = ((size >> 12) - 1) << PAGEMASK_SHIFT;
+	tlb_lo0 = tlb_attrib1 | (offset >> TLB_LO_SHIFT);
+	tlb_lo1 = tlb_attrib2 | ((offset + size) >> TLB_LO_SHIFT);
+
+	write_one_tlb(index, tlb_mask, offset & TLB_HI_MASK,
+		      tlb_lo0 & TLB_LO_MASK, tlb_lo1 & TLB_LO_MASK);
+}
+#endif				/* __ASM_MACH_TLB_H */
diff --git a/arch/mips/mach-mscc/lowlevel_init.S b/arch/mips/mach-mscc/lowlevel_init.S
new file mode 100644
index 0000000..dfbe067
--- /dev/null
+++ b/arch/mips/mach-mscc/lowlevel_init.S
@@ -0,0 +1,30 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+    .set noreorder
+    .extern     vcoreiii_tlb_init
+#ifdef CONFIG_SOC_LUTON
+    .extern     pll_init
+#endif
+
+LEAF(lowlevel_init)
+	/*
+	 * As we have no stack yet, we can assume the restricted
+	 * luxury of the sX-registers without saving them
+	 */
+	move	s0,ra
+
+	jal	vcoreiii_tlb_init
+	 nop
+#ifdef CONFIG_SOC_LUTON
+	jal	pll_init
+	 nop
+#endif
+	jr	s0
+	 nop
+	END(lowlevel_init)
diff --git a/arch/mips/mach-mscc/lowlevel_init_luton.S b/arch/mips/mach-mscc/lowlevel_init_luton.S
new file mode 100644
index 0000000..8a528fa
--- /dev/null
+++ b/arch/mips/mach-mscc/lowlevel_init_luton.S
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+
+#define BASE_MACRO      0x600a0000
+#define REG_OFFSET(t, o) (t + (o*4))
+#define REG_MACRO(x) REG_OFFSET(BASE_MACRO, x)
+#define BIT(nr)			(1 << (nr))
+
+#define MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0 REG_MACRO(6)
+#define MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0_LOCK_STATUS BIT(0)
+#define MACRO_CTRL_PLL5G_CFG_PLL5G_CFG2 REG_MACRO(2)
+#define MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0 REG_MACRO(0)
+#define MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0_CPU_CLK_DIV (0x3F << 6)
+#define MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0_CPU_CLK_DIV_ENC(x) (x << 6)
+
+    .set noreorder
+LEAF(pll_init)
+	/* Make sure PLL is locked */
+	lw	v0, MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0
+	andi	v1, v0, MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0_LOCK_STATUS
+	bne	v1, zero, 1f
+	 nop
+
+	/* Black magic from frontend */
+	li	v1, 0x00610400
+	sw	v1, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG2
+
+	li	v1, 0x00610c00
+	sw	v1, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG2
+
+	li	v1, 0x00610800
+	sw	v1, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG2
+
+	li	v1, 0x00610000
+	sw	v1, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG2
+
+	/* Wait for lock */
+2:	lw	v0, MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0
+	andi	v1, v0, MACRO_CTRL_PLL5G_STATUS_PLL5G_STATUS0_LOCK_STATUS
+	/* Keep looping if zero (no lock bit yet) */
+	beq	v1, zero, 2b
+	 nop
+
+	/* Setup PLL CPU clock divider for 416MHz */
+1:	lw	v0, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0
+
+	/* Keep reserved bits */
+	li	v1, ~MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0_CPU_CLK_DIV
+	and	v0, v0, v1
+
+	/* Set code 6 ~ 416.66 MHz */
+	ori	v0, v0, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0_CPU_CLK_DIV_ENC(6)
+
+	sw	v0, MACRO_CTRL_PLL5G_CFG_PLL5G_CFG0
+	jr      ra
+	 nop
+	END(pll_init)
diff --git a/arch/mips/mach-mscc/reset.c b/arch/mips/mach-mscc/reset.c
new file mode 100644
index 0000000..390bbd0
--- /dev/null
+++ b/arch/mips/mach-mscc/reset.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+
+#include <asm/sections.h>
+#include <asm/io.h>
+
+#include <asm/reboot.h>
+
+void _machine_restart(void)
+{
+	register u32 resetbits = PERF_SOFT_RST_SOFT_CHIP_RST;
+	(void)readl(BASE_DEVCPU_GCB + PERF_SOFT_RST);
+
+	/* Make sure VCore is NOT protected from reset */
+	clrbits_le32(BASE_CFG + ICPU_RESET, ICPU_RESET_CORE_RST_PROTECT);
+
+	/* Change to SPI bitbang for SPI reset workaround... */
+	writel(ICPU_SW_MODE_SW_SPI_CS_OE(1) | ICPU_SW_MODE_SW_SPI_CS(1) |
+	       ICPU_SW_MODE_SW_PIN_CTRL_MODE, BASE_CFG + ICPU_SW_MODE);
+
+	/* Do the global reset */
+	writel(resetbits, BASE_DEVCPU_GCB + PERF_SOFT_RST);
+
+	while (1)
+		; /* NOP */
+}
diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mt7620/cpu.c
index 87cc973..9e0ca71 100644
--- a/arch/mips/mach-mt7620/cpu.c
+++ b/arch/mips/mach-mt7620/cpu.c
@@ -89,9 +89,21 @@
 		wdt_reset(watchdog_dev);
 	}
 }
+#endif
 
 int arch_misc_init(void)
 {
+	/*
+	 * It has been noticed, that sometimes the d-cache is not in a
+	 * "clean-state" when U-Boot is running on MT7688. This was
+	 * detected when using the ethernet driver (which uses d-cache)
+	 * and a TFTP command does not complete. Flushing the complete
+	 * d-cache (again?) here seems to fix this issue.
+	 */
+	flush_dcache_range(gd->bd->bi_memstart,
+			   gd->bd->bi_memstart + gd->ram_size - 1);
+
+#ifdef CONFIG_WATCHDOG
 	/* Init watchdog */
 	if (uclass_get_device_by_seq(UCLASS_WDT, 0, &watchdog_dev)) {
 		debug("Watchdog: Not found by seq!\n");
@@ -103,7 +115,7 @@
 
 	wdt_start(watchdog_dev, 60000, 0);	/* 60 seconds */
 	printf("Watchdog: Started\n");
+#endif
 
 	return 0;
 }
-#endif
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 732a357..c45e4d7 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -22,6 +22,7 @@
 
 # platform-specific options below
 source "arch/riscv/cpu/ax25/Kconfig"
+source "arch/riscv/cpu/qemu/Kconfig"
 
 # architecture-specific options below
 
@@ -44,6 +45,40 @@
 
 endchoice
 
+choice
+	prompt "Code Model"
+	default CMODEL_MEDLOW
+
+config CMODEL_MEDLOW
+	bool "medium low code model"
+	help
+	  U-Boot and its statically defined symbols must lie within a single 2 GiB
+	  address range and must lie between absolute addresses -2 GiB and +2 GiB.
+
+config CMODEL_MEDANY
+	bool "medium any code model"
+	help
+	  U-Boot and its statically defined symbols must be within any single 2 GiB
+	  address range.
+
+endchoice
+
+choice
+	prompt "Run Mode"
+	default RISCV_MMODE
+
+config RISCV_MMODE
+	bool "Machine"
+	help
+	  Choose this option to build U-Boot for RISC-V M-Mode.
+
+config RISCV_SMODE
+	bool "Supervisor"
+	help
+	  Choose this option to build U-Boot for RISC-V S-Mode.
+
+endchoice
+
 config RISCV_ISA_C
 	bool "Emit compressed instructions"
 	default y
@@ -55,15 +90,30 @@
 config RISCV_ISA_A
 	def_bool y
 
-config RISCV_SMODE
-	bool "Run in S-Mode"
-	help
-	  Enable this option to build U-Boot for RISC-V S-Mode
-
 config 32BIT
 	bool
 
 config 64BIT
 	bool
 
+config SIFIVE_CLINT
+	bool
+	depends on RISCV_MMODE
+	select REGMAP
+	select SYSCON
+	help
+	  The SiFive CLINT block holds memory-mapped control and status registers
+	  associated with software and timer interrupts.
+
+config RISCV_RDTIME
+	bool
+	default y if RISCV_SMODE
+	help
+	  The provides the riscv_get_time() API that is implemented using the
+	  standard rdtime instruction. This is the case for S-mode U-Boot, and
+	  is useful for processors that support rdtime in M-mode too.
+
+config SYS_MALLOC_F_LEN
+	default 0x1000
+
 endmenu
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile
index 55d7c65..0b80eb8 100644
--- a/arch/riscv/Makefile
+++ b/arch/riscv/Makefile
@@ -17,8 +17,15 @@
 ifeq ($(CONFIG_RISCV_ISA_C),y)
 	ARCH_C = c
 endif
+ifeq ($(CONFIG_CMODEL_MEDLOW),y)
+	CMODEL = medlow
+endif
+ifeq ($(CONFIG_CMODEL_MEDANY),y)
+	CMODEL = medany
+endif
 
-ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C) -mabi=$(ABI)
+ARCH_FLAGS = -march=$(ARCH_BASE)$(ARCH_A)$(ARCH_C) -mabi=$(ABI) \
+	     -mcmodel=$(CMODEL)
 
 PLATFORM_CPPFLAGS	+= $(ARCH_FLAGS)
 CFLAGS_EFI		+= $(ARCH_FLAGS)
diff --git a/arch/riscv/cpu/Makefile b/arch/riscv/cpu/Makefile
index 2cc6757..6bf6f91 100644
--- a/arch/riscv/cpu/Makefile
+++ b/arch/riscv/cpu/Makefile
@@ -4,4 +4,4 @@
 
 extra-y = start.o
 
-obj-y += cpu.o
+obj-y += cpu.o mtrap.o
diff --git a/arch/riscv/cpu/ax25/Kconfig b/arch/riscv/cpu/ax25/Kconfig
index 6c7022f..e9dbca2 100644
--- a/arch/riscv/cpu/ax25/Kconfig
+++ b/arch/riscv/cpu/ax25/Kconfig
@@ -1,7 +1,14 @@
 config RISCV_NDS
-	bool "AndeStar V5 ISA support"
-	default n
+	bool
 	help
-		Say Y here if you plan to run U-Boot on AndeStar v5
-		platforms and use some specific features which are
-		provided by Andes Technology AndeStar V5 Families.
+	  Run U-Boot on AndeStar V5 platforms and use some specific features
+	  which are provided by Andes Technology AndeStar V5 families.
+
+if RISCV_NDS
+
+config RISCV_NDS_CACHE
+	bool "AndeStar V5 families specific cache support"
+	help
+	  Provide Andes Technology AndeStar V5 families specific cache support.
+
+endif
diff --git a/arch/riscv/cpu/ax25/cache.c b/arch/riscv/cpu/ax25/cache.c
index 6600ac2..8d6ae17 100644
--- a/arch/riscv/cpu/ax25/cache.c
+++ b/arch/riscv/cpu/ax25/cache.c
@@ -9,7 +9,7 @@
 void icache_enable(void)
 {
 #ifndef CONFIG_SYS_ICACHE_OFF
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"csrr t1, mcache_ctl\n\t"
 		"ori t0, t1, 0x1\n\t"
@@ -22,7 +22,7 @@
 void icache_disable(void)
 {
 #ifndef CONFIG_SYS_ICACHE_OFF
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"fence.i\n\t"
 		"csrr t1, mcache_ctl\n\t"
@@ -36,7 +36,7 @@
 void dcache_enable(void)
 {
 #ifndef CONFIG_SYS_DCACHE_OFF
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"csrr t1, mcache_ctl\n\t"
 		"ori t0, t1, 0x2\n\t"
@@ -49,7 +49,7 @@
 void dcache_disable(void)
 {
 #ifndef CONFIG_SYS_DCACHE_OFF
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"fence\n\t"
 		"csrr t1, mcache_ctl\n\t"
@@ -64,7 +64,7 @@
 {
 	int ret = 0;
 
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"csrr t1, mcache_ctl\n\t"
 		"andi	%0, t1, 0x01\n\t"
@@ -81,7 +81,7 @@
 {
 	int ret = 0;
 
-#ifdef CONFIG_RISCV_NDS
+#ifdef CONFIG_RISCV_NDS_CACHE
 	asm volatile (
 		"csrr t1, mcache_ctl\n\t"
 		"andi	%0, t1, 0x02\n\t"
diff --git a/arch/riscv/cpu/cpu.c b/arch/riscv/cpu/cpu.c
index d9f820c..e662140 100644
--- a/arch/riscv/cpu/cpu.c
+++ b/arch/riscv/cpu/cpu.c
@@ -4,7 +4,12 @@
  */
 
 #include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <log.h>
 #include <asm/csr.h>
+#include <asm/encoding.h>
+#include <dm/uclass-internal.h>
 
 /*
  * prior_stage_fdt_address must be stored in the data section since it is used
@@ -12,44 +17,79 @@
  */
 phys_addr_t prior_stage_fdt_address __attribute__((section(".data")));
 
-enum {
-	ISA_INVALID = 0,
-	ISA_32BIT,
-	ISA_64BIT,
-	ISA_128BIT
-};
-
-static const char * const isa_bits[] = {
-	[ISA_INVALID] = NULL,
-	[ISA_32BIT]   = "32",
-	[ISA_64BIT]   = "64",
-	[ISA_128BIT]  = "128"
-};
-
 static inline bool supports_extension(char ext)
 {
+#ifdef CONFIG_CPU
+	struct udevice *dev;
+	char desc[32];
+
+	uclass_find_first_device(UCLASS_CPU, &dev);
+	if (!dev) {
+		debug("unable to find the RISC-V cpu device\n");
+		return false;
+	}
+	if (!cpu_get_desc(dev, desc, sizeof(desc))) {
+		/* skip the first 4 characters (rv32|rv64) */
+		if (strchr(desc + 4, ext))
+			return true;
+	}
+
+	return false;
+#else  /* !CONFIG_CPU */
+#ifdef CONFIG_RISCV_MMODE
 	return csr_read(misa) & (1 << (ext - 'a'));
+#else  /* !CONFIG_RISCV_MMODE */
+#warning "There is no way to determine the available extensions in S-mode."
+#warning "Please convert your board to use the RISC-V CPU driver."
+	return false;
+#endif /* CONFIG_RISCV_MMODE */
+#endif /* CONFIG_CPU */
 }
 
-int print_cpuinfo(void)
+static int riscv_cpu_probe(void)
 {
-	char name[32];
-	char *s = name;
-	int bit;
+#ifdef CONFIG_CPU
+	int ret;
 
-	s += sprintf(name, "rv");
-	bit = csr_read(misa) >> (sizeof(long) * 8 - 2);
-	s += sprintf(s, isa_bits[bit]);
-
-	supports_extension('i') ? *s++ = 'i' : 'r';
-	supports_extension('m') ? *s++ = 'm' : 'i';
-	supports_extension('a') ? *s++ = 'a' : 's';
-	supports_extension('f') ? *s++ = 'f' : 'c';
-	supports_extension('d') ? *s++ = 'd' : '-';
-	supports_extension('c') ? *s++ = 'c' : 'v';
-	*s++ = '\0';
-
-	printf("CPU:   %s\n", name);
+	/* probe cpus so that RISC-V timer can be bound */
+	ret = cpu_probe_all();
+	if (ret)
+		return log_msg_ret("RISC-V cpus probe failed\n", ret);
+#endif
 
 	return 0;
 }
+
+int arch_cpu_init_dm(void)
+{
+	int ret;
+
+	ret = riscv_cpu_probe();
+	if (ret)
+		return ret;
+
+	/* Enable FPU */
+	if (supports_extension('d') || supports_extension('f')) {
+		csr_set(MODE_PREFIX(status), MSTATUS_FS);
+		csr_write(fcsr, 0);
+	}
+
+	if (CONFIG_IS_ENABLED(RISCV_MMODE)) {
+		/*
+		 * Enable perf counters for cycle, time,
+		 * and instret counters only
+		 */
+		csr_write(mcounteren, GENMASK(2, 0));
+
+		/* Disable paging */
+		if (supports_extension('s'))
+			csr_write(satp, 0);
+	}
+
+	return 0;
+}
+
+int arch_early_init_r(void)
+{
+	return riscv_cpu_probe();
+}
diff --git a/arch/riscv/cpu/mtrap.S b/arch/riscv/cpu/mtrap.S
new file mode 100644
index 0000000..407ecfa
--- /dev/null
+++ b/arch/riscv/cpu/mtrap.S
@@ -0,0 +1,103 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * M-mode Trap Handler Code for RISC-V Core
+ *
+ * Copyright (c) 2017 Microsemi Corporation.
+ * Copyright (c) 2017 Padmarao Begari <Padmarao.Begari@microsemi.com>
+ *
+ * Copyright (C) 2017 Andes Technology Corporation
+ * Rick Chen, Andes Technology Corporation <rick@andestech.com>
+ *
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <asm/encoding.h>
+
+#ifdef CONFIG_32BIT
+#define LREG		lw
+#define SREG		sw
+#define REGBYTES	4
+#else
+#define LREG		ld
+#define SREG		sd
+#define REGBYTES	8
+#endif
+
+	.text
+
+	/* trap entry */
+	.align 2
+	.global trap_entry
+trap_entry:
+	addi sp, sp, -32 * REGBYTES
+	SREG x1,   1 * REGBYTES(sp)
+	SREG x2,   2 * REGBYTES(sp)
+	SREG x3,   3 * REGBYTES(sp)
+	SREG x4,   4 * REGBYTES(sp)
+	SREG x5,   5 * REGBYTES(sp)
+	SREG x6,   6 * REGBYTES(sp)
+	SREG x7,   7 * REGBYTES(sp)
+	SREG x8,   8 * REGBYTES(sp)
+	SREG x9,   9 * REGBYTES(sp)
+	SREG x10, 10 * REGBYTES(sp)
+	SREG x11, 11 * REGBYTES(sp)
+	SREG x12, 12 * REGBYTES(sp)
+	SREG x13, 13 * REGBYTES(sp)
+	SREG x14, 14 * REGBYTES(sp)
+	SREG x15, 15 * REGBYTES(sp)
+	SREG x16, 16 * REGBYTES(sp)
+	SREG x17, 17 * REGBYTES(sp)
+	SREG x18, 18 * REGBYTES(sp)
+	SREG x19, 19 * REGBYTES(sp)
+	SREG x20, 20 * REGBYTES(sp)
+	SREG x21, 21 * REGBYTES(sp)
+	SREG x22, 22 * REGBYTES(sp)
+	SREG x23, 23 * REGBYTES(sp)
+	SREG x24, 24 * REGBYTES(sp)
+	SREG x25, 25 * REGBYTES(sp)
+	SREG x26, 26 * REGBYTES(sp)
+	SREG x27, 27 * REGBYTES(sp)
+	SREG x28, 28 * REGBYTES(sp)
+	SREG x29, 29 * REGBYTES(sp)
+	SREG x30, 30 * REGBYTES(sp)
+	SREG x31, 31 * REGBYTES(sp)
+	csrr a0, MODE_PREFIX(cause)
+	csrr a1, MODE_PREFIX(epc)
+	mv a2, sp
+	jal handle_trap
+	csrw MODE_PREFIX(epc), a0
+
+	LREG x1,   1 * REGBYTES(sp)
+	LREG x3,   3 * REGBYTES(sp)
+	LREG x4,   4 * REGBYTES(sp)
+	LREG x5,   5 * REGBYTES(sp)
+	LREG x6,   6 * REGBYTES(sp)
+	LREG x7,   7 * REGBYTES(sp)
+	LREG x8,   8 * REGBYTES(sp)
+	LREG x9,   9 * REGBYTES(sp)
+	LREG x10, 10 * REGBYTES(sp)
+	LREG x11, 11 * REGBYTES(sp)
+	LREG x12, 12 * REGBYTES(sp)
+	LREG x13, 13 * REGBYTES(sp)
+	LREG x14, 14 * REGBYTES(sp)
+	LREG x15, 15 * REGBYTES(sp)
+	LREG x16, 16 * REGBYTES(sp)
+	LREG x17, 17 * REGBYTES(sp)
+	LREG x18, 18 * REGBYTES(sp)
+	LREG x19, 19 * REGBYTES(sp)
+	LREG x20, 20 * REGBYTES(sp)
+	LREG x21, 21 * REGBYTES(sp)
+	LREG x22, 22 * REGBYTES(sp)
+	LREG x23, 23 * REGBYTES(sp)
+	LREG x24, 24 * REGBYTES(sp)
+	LREG x25, 25 * REGBYTES(sp)
+	LREG x26, 26 * REGBYTES(sp)
+	LREG x27, 27 * REGBYTES(sp)
+	LREG x28, 28 * REGBYTES(sp)
+	LREG x29, 29 * REGBYTES(sp)
+	LREG x30, 30 * REGBYTES(sp)
+	LREG x31, 31 * REGBYTES(sp)
+	LREG x2,   2 * REGBYTES(sp)
+	addi sp, sp, 32 * REGBYTES
+	MODE_PREFIX(ret)
diff --git a/arch/riscv/cpu/qemu/Kconfig b/arch/riscv/cpu/qemu/Kconfig
new file mode 100644
index 0000000..f48751e
--- /dev/null
+++ b/arch/riscv/cpu/qemu/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0+
+#
+# Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+
+config QEMU_RISCV
+	bool
+	select ARCH_EARLY_INIT_R
+	imply CPU
+	imply CPU_RISCV
+	imply RISCV_TIMER
+	imply SIFIVE_CLINT if RISCV_MMODE
+	imply CMD_CPU
diff --git a/arch/riscv/cpu/qemu/cpu.c b/arch/riscv/cpu/qemu/cpu.c
index 25d97d0..ad2950c 100644
--- a/arch/riscv/cpu/qemu/cpu.c
+++ b/arch/riscv/cpu/qemu/cpu.c
@@ -4,6 +4,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 
 /*
  * cleanup_before_linux() is called just before we call linux
@@ -19,3 +20,16 @@
 
 	return 0;
 }
+
+/* To enumerate devices on the /soc/ node, create a "simple-bus" driver */
+static const struct udevice_id riscv_virtio_soc_ids[] = {
+	{ .compatible = "riscv-virtio-soc" },
+	{ }
+};
+
+U_BOOT_DRIVER(riscv_virtio_soc) = {
+	.name = "riscv_virtio_soc",
+	.id = UCLASS_SIMPLE_BUS,
+	.of_match = riscv_virtio_soc_ids,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/riscv/cpu/start.S b/arch/riscv/cpu/start.S
index 64246a4..81ea52b 100644
--- a/arch/riscv/cpu/start.S
+++ b/arch/riscv/cpu/start.S
@@ -14,6 +14,7 @@
 #include <common.h>
 #include <elf.h>
 #include <asm/encoding.h>
+#include <generated/asm-offsets.h>
 
 #ifdef CONFIG_32BIT
 #define LREG			lw
@@ -70,6 +71,9 @@
 
 	jal	board_init_f_init_reserve
 
+	/* save the boot hart id to global_data */
+	SREG	s0, GD_BOOT_HART(gp)
+
 	mv	a0, zero		/* a0 <-- boot_flags = 0 */
 	la	t5, board_init_f
 	jr	t5			/* jump to board_init_f() */
@@ -198,92 +202,3 @@
  * jump to it ...
  */
 	jr	t4			/* jump to board_init_r() */
-
-/*
- * trap entry
- */
-.align 2
-trap_entry:
-	addi	sp, sp, -32*REGBYTES
-	SREG	x1, 1*REGBYTES(sp)
-	SREG	x2, 2*REGBYTES(sp)
-	SREG	x3, 3*REGBYTES(sp)
-	SREG	x4, 4*REGBYTES(sp)
-	SREG	x5, 5*REGBYTES(sp)
-	SREG	x6, 6*REGBYTES(sp)
-	SREG	x7, 7*REGBYTES(sp)
-	SREG	x8, 8*REGBYTES(sp)
-	SREG	x9, 9*REGBYTES(sp)
-	SREG	x10, 10*REGBYTES(sp)
-	SREG	x11, 11*REGBYTES(sp)
-	SREG	x12, 12*REGBYTES(sp)
-	SREG	x13, 13*REGBYTES(sp)
-	SREG	x14, 14*REGBYTES(sp)
-	SREG	x15, 15*REGBYTES(sp)
-	SREG	x16, 16*REGBYTES(sp)
-	SREG	x17, 17*REGBYTES(sp)
-	SREG	x18, 18*REGBYTES(sp)
-	SREG	x19, 19*REGBYTES(sp)
-	SREG	x20, 20*REGBYTES(sp)
-	SREG	x21, 21*REGBYTES(sp)
-	SREG	x22, 22*REGBYTES(sp)
-	SREG	x23, 23*REGBYTES(sp)
-	SREG	x24, 24*REGBYTES(sp)
-	SREG	x25, 25*REGBYTES(sp)
-	SREG	x26, 26*REGBYTES(sp)
-	SREG	x27, 27*REGBYTES(sp)
-	SREG	x28, 28*REGBYTES(sp)
-	SREG	x29, 29*REGBYTES(sp)
-	SREG	x30, 30*REGBYTES(sp)
-	SREG	x31, 31*REGBYTES(sp)
-	csrr	a0, MODE_PREFIX(cause)
-	csrr	a1, MODE_PREFIX(epc)
-	mv	a2, sp
-	jal	handle_trap
-	csrw	MODE_PREFIX(epc), a0
-
-#ifdef CONFIG_RISCV_SMODE
-/*
- * Remain in S-mode after sret
- */
-	li	t0, SSTATUS_SPP
-#else
-/*
- * Remain in M-mode after mret
- */
-	li	t0, MSTATUS_MPP
-#endif
-	csrs	MODE_PREFIX(status), t0
-	LREG	x1, 1*REGBYTES(sp)
-	LREG	x2, 2*REGBYTES(sp)
-	LREG	x3, 3*REGBYTES(sp)
-	LREG	x4, 4*REGBYTES(sp)
-	LREG	x5, 5*REGBYTES(sp)
-	LREG	x6, 6*REGBYTES(sp)
-	LREG	x7, 7*REGBYTES(sp)
-	LREG	x8, 8*REGBYTES(sp)
-	LREG	x9, 9*REGBYTES(sp)
-	LREG	x10, 10*REGBYTES(sp)
-	LREG	x11, 11*REGBYTES(sp)
-	LREG	x12, 12*REGBYTES(sp)
-	LREG	x13, 13*REGBYTES(sp)
-	LREG	x14, 14*REGBYTES(sp)
-	LREG	x15, 15*REGBYTES(sp)
-	LREG	x16, 16*REGBYTES(sp)
-	LREG	x17, 17*REGBYTES(sp)
-	LREG	x18, 18*REGBYTES(sp)
-	LREG	x19, 19*REGBYTES(sp)
-	LREG	x20, 20*REGBYTES(sp)
-	LREG	x21, 21*REGBYTES(sp)
-	LREG	x22, 22*REGBYTES(sp)
-	LREG	x23, 23*REGBYTES(sp)
-	LREG	x24, 24*REGBYTES(sp)
-	LREG	x25, 25*REGBYTES(sp)
-	LREG	x26, 26*REGBYTES(sp)
-	LREG	x27, 27*REGBYTES(sp)
-	LREG	x28, 28*REGBYTES(sp)
-	LREG	x29, 29*REGBYTES(sp)
-	LREG	x30, 30*REGBYTES(sp)
-	LREG	x31, 31*REGBYTES(sp)
-	addi	sp, sp, 32*REGBYTES
-	MODE_PREFIX(ret)
diff --git a/arch/riscv/dts/ae350.dts b/arch/riscv/dts/ae350.dts
deleted file mode 100644
index e48c298..0000000
--- a/arch/riscv/dts/ae350.dts
+++ /dev/null
@@ -1,229 +0,0 @@
-/dts-v1/;
-
-/ {
-	#address-cells = <2>;
-	#size-cells = <2>;
-	compatible = "andestech,ax25";
-	model = "andestech,ax25";
-
-	aliases {
-		uart0 = &serial0;
-		spi0 = &spi;
-	};
-
-	chosen {
-		bootargs = "console=ttyS0,38400n8  debug loglevel=7";
-		stdout-path = "uart0:38400n8";
-	};
-
-	cpus {
-		#address-cells = <1>;
-		#size-cells = <0>;
-		timebase-frequency = <60000000>;
-		CPU0: cpu@0 {
-			device_type = "cpu";
-			reg = <0>;
-			status = "okay";
-			compatible = "riscv";
-			riscv,isa = "rv64imafdc";
-			mmu-type = "riscv,sv39";
-			clock-frequency = <60000000>;
-			d-cache-size = <0x8000>;
-			d-cache-line-size = <32>;
-			CPU0_intc: interrupt-controller {
-				#interrupt-cells = <1>;
-				interrupt-controller;
-				compatible = "riscv,cpu-intc";
-			};
-		};
-	};
-
-	memory@0 {
-		device_type = "memory";
-		reg = <0x0 0x00000000 0x0 0x40000000>;
-	};
-
-	soc {
-		#address-cells = <2>;
-		#size-cells = <2>;
-		compatible = "andestech,riscv-ae350-soc";
-		ranges;
-
-	plic0: interrupt-controller@e4000000 {
-		compatible = "riscv,plic0";
-		#address-cells = <2>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0x0 0xe4000000 0x0 0x2000000>;
-		riscv,ndev=<71>;
-		interrupts-extended = <&CPU0_intc 11 &CPU0_intc 9>;
-	};
-
-	plic1: interrupt-controller@e6400000 {
-		compatible = "riscv,plic1";
-		#address-cells = <2>;
-		#interrupt-cells = <2>;
-		interrupt-controller;
-		reg = <0x0 0xe6400000 0x0 0x400000>;
-		riscv,ndev=<1>;
-		interrupts-extended = <&CPU0_intc 3>;
-	};
-
-	plmt0@e6000000 {
-		compatible = "riscv,plmt0";
-			interrupts-extended = <&CPU0_intc 7>;
-			reg = <0x0 0xe6000000 0x0 0x100000>;
-		};
-	};
-
-	spiclk: virt_100mhz {
-		#clock-cells = <0>;
-		compatible = "fixed-clock";
-		clock-frequency = <100000000>;
-	};
-
-	timer0: timer@f0400000 {
-		compatible = "andestech,atcpit100";
-		reg = <0x0 0xf0400000 0x0 0x1000>;
-		clock-frequency = <60000000>;
-		interrupts = <3 4>;
-		interrupt-parent = <&plic0>;
-	};
-
-	serial0: serial@f0300000 {
-		compatible = "andestech,uart16550", "ns16550a";
-		reg = <0x0 0xf0300000 0x0 0x1000>;
-		interrupts = <9 4>;
-		clock-frequency = <19660800>;
-		reg-shift = <2>;
-		reg-offset = <32>;
-		no-loopback-test = <1>;
-		interrupt-parent = <&plic0>;
-	};
-
-	mac0: mac@e0100000 {
-		compatible = "andestech,atmac100";
-		reg = <0x0 0xe0100000 0x0 0x1000>;
-		interrupts = <19 4>;
-		interrupt-parent = <&plic0>;
-	};
-
-	mmc0: mmc@f0e00000 {
-		compatible = "andestech,atfsdc010";
-		max-frequency = <100000000>;
-		clock-freq-min-max = <400000 100000000>;
-		fifo-depth = <0x10>;
-		reg = <0x0 0xf0e00000 0x0 0x1000>;
-		interrupts = <18 4>;
-		cap-sd-highspeed;
-		interrupt-parent = <&plic0>;
-	};
-
-	dma0: dma@f0c00000 {
-		compatible = "andestech,atcdmac300";
-		reg = <0x0 0xf0c00000 0x0 0x1000>;
-		interrupts = <10 4 64 4 65 4 66 4 67 4 68 4 69 4 70 4 71 4>;
-		dma-channels = <8>;
-		interrupt-parent = <&plic0>;
-	};
-
-	lcd0: lcd@e0200000 {
-		compatible = "andestech,atflcdc100";
-		reg = <0x0 0xe0200000 0x0 0x1000>;
-		interrupts = <20 4>;
-		interrupt-parent = <&plic0>;
-	};
-
-	smc0: smc@e0400000 {
-		compatible = "andestech,atfsmc020";
-		reg = <0x0 0xe0400000 0x0 0x1000>;
-	};
-
-	snd0: snd@f0d00000 {
-		compatible = "andestech,atfac97";
-		reg = <0x0 0xf0d00000 0x0 0x1000>;
-		interrupts = <17 4>;
-		interrupt-parent = <&plic0>;
-	};
-
-	virtio_mmio@fe007000 {
-		interrupts = <0x17 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe007000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe006000 {
-		interrupts = <0x16 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe006000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe005000 {
-		interrupts = <0x15 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe005000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe004000 {
-		interrupts = <0x14 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe004000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe003000 {
-		interrupts = <0x13 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe003000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe002000 {
-		interrupts = <0x12 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe002000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe001000 {
-		interrupts = <0x11 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe001000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	virtio_mmio@fe000000 {
-		interrupts = <0x10 0x4>;
-		interrupt-parent = <0x2>;
-		reg = <0x0 0xfe000000 0x0 0x1000>;
-		compatible = "virtio,mmio";
-	};
-
-	nor@0,0 {
-		compatible = "cfi-flash";
-		reg = <0x0 0x88000000 0x0 0x1000>;
-		bank-width = <2>;
-		device-width = <1>;
-	};
-
-	spi: spi@f0b00000 {
-		compatible = "andestech,atcspi200";
-		reg = <0x0 0xf0b00000 0x0 0x1000>;
-		#address-cells = <1>;
-		#size-cells = <0>;
-		num-cs = <1>;
-		clocks = <&spiclk>;
-		interrupts = <4 4>;
-		interrupt-parent = <&plic0>;
-		flash@0 {
-			compatible = "spi-flash";
-			spi-max-frequency = <50000000>;
-			reg = <0>;
-			spi-cpol;
-			spi-cpha;
-		};
-	};
-};
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 29624fd..86136f5 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -61,10 +61,12 @@
 
 #ifndef __ASSEMBLY__
 
+#define xcsr(csr)	#csr
+
 #define csr_swap(csr, val)					\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrrw %0, " #csr ", %1"		\
+	__asm__ __volatile__ ("csrrw %0, " xcsr(csr) ", %1"	\
 			      : "=r" (__v) : "rK" (__v)		\
 			      : "memory");			\
 	__v;							\
@@ -73,7 +75,7 @@
 #define csr_read(csr)						\
 ({								\
 	register unsigned long __v;				\
-	__asm__ __volatile__ ("csrr %0, " #csr			\
+	__asm__ __volatile__ ("csrr %0, " xcsr(csr)		\
 			      : "=r" (__v) :			\
 			      : "memory");			\
 	__v;							\
@@ -82,7 +84,7 @@
 #define csr_write(csr, val)					\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrw " #csr ", %0"		\
+	__asm__ __volatile__ ("csrw " xcsr(csr) ", %0"		\
 			      : : "rK" (__v)			\
 			      : "memory");			\
 })
@@ -90,7 +92,7 @@
 #define csr_read_set(csr, val)					\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrrs %0, " #csr ", %1"		\
+	__asm__ __volatile__ ("csrrs %0, " xcsr(csr) ", %1"	\
 			      : "=r" (__v) : "rK" (__v)		\
 			      : "memory");			\
 	__v;							\
@@ -99,7 +101,7 @@
 #define csr_set(csr, val)					\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrs " #csr ", %0"		\
+	__asm__ __volatile__ ("csrs " xcsr(csr) ", %0"		\
 			      : : "rK" (__v)			\
 			      : "memory");			\
 })
@@ -107,7 +109,7 @@
 #define csr_read_clear(csr, val)				\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrrc %0, " #csr ", %1"		\
+	__asm__ __volatile__ ("csrrc %0, " xcsr(csr) ", %1"	\
 			      : "=r" (__v) : "rK" (__v)		\
 			      : "memory");			\
 	__v;							\
@@ -116,7 +118,7 @@
 #define csr_clear(csr, val)					\
 ({								\
 	unsigned long __v = (unsigned long)(val);		\
-	__asm__ __volatile__ ("csrc " #csr ", %0"		\
+	__asm__ __volatile__ ("csrc " xcsr(csr) ", %0"		\
 			      : : "rK" (__v)			\
 			      : "memory");			\
 })
diff --git a/arch/riscv/include/asm/encoding.h b/arch/riscv/include/asm/encoding.h
index 97cf906..772668c 100644
--- a/arch/riscv/include/asm/encoding.h
+++ b/arch/riscv/include/asm/encoding.h
@@ -85,6 +85,21 @@
 #define IRQ_COP		12
 #define IRQ_HOST	13
 
+#define CAUSE_MISALIGNED_FETCH		0
+#define CAUSE_FETCH_ACCESS		1
+#define CAUSE_ILLEGAL_INSTRUCTION	2
+#define CAUSE_BREAKPOINT		3
+#define CAUSE_MISALIGNED_LOAD		4
+#define CAUSE_LOAD_ACCESS		5
+#define CAUSE_MISALIGNED_STORE		6
+#define CAUSE_STORE_ACCESS		7
+#define CAUSE_USER_ECALL		8
+#define CAUSE_SUPERVISOR_ECALL		9
+#define CAUSE_MACHINE_ECALL		11
+#define CAUSE_FETCH_PAGE_FAULT		12
+#define CAUSE_LOAD_PAGE_FAULT		13
+#define CAUSE_STORE_PAGE_FAULT		15
+
 #define DEFAULT_RSTVEC		0x00001000
 #define DEFAULT_NMIVEC		0x00001004
 #define DEFAULT_MTVEC		0x00001010
@@ -152,6 +167,227 @@
 #define RISCV_PGSHIFT 12
 #define RISCV_PGSIZE BIT(RISCV_PGSHIFT)
 
+/* CSR numbers */
+#define CSR_FFLAGS		0x1
+#define CSR_FRM			0x2
+#define CSR_FCSR		0x3
+
+#define CSR_SSTATUS		0x100
+#define CSR_SEDELEG		0x102
+#define CSR_SIDELEG		0x103
+#define CSR_SIE			0x104
+#define CSR_STVEC		0x105
+#define CSR_SCOUNTEREN		0x106
+#define CSR_SSCRATCH		0x140
+#define CSR_SEPC		0x141
+#define CSR_SCAUSE		0x142
+#define CSR_STVAL		0x143
+#define CSR_SIP			0x144
+#define CSR_SATP		0x180
+
+#define CSR_MSTATUS		0x300
+#define CSR_MISA		0x301
+#define CSR_MEDELEG		0x302
+#define CSR_MIDELEG		0x303
+#define CSR_MIE			0x304
+#define CSR_MTVEC		0x305
+#define CSR_MCOUNTEREN		0x306
+#define CSR_MHPMEVENT3		0x323
+#define CSR_MHPMEVENT4		0x324
+#define CSR_MHPMEVENT5		0x325
+#define CSR_MHPMEVENT6		0x326
+#define CSR_MHPMEVENT7		0x327
+#define CSR_MHPMEVENT8		0x328
+#define CSR_MHPMEVENT9		0x329
+#define CSR_MHPMEVENT10		0x32a
+#define CSR_MHPMEVENT11		0x32b
+#define CSR_MHPMEVENT12		0x32c
+#define CSR_MHPMEVENT13		0x32d
+#define CSR_MHPMEVENT14		0x32e
+#define CSR_MHPMEVENT15		0x32f
+#define CSR_MHPMEVENT16		0x330
+#define CSR_MHPMEVENT17		0x331
+#define CSR_MHPMEVENT18		0x332
+#define CSR_MHPMEVENT19		0x333
+#define CSR_MHPMEVENT20		0x334
+#define CSR_MHPMEVENT21		0x335
+#define CSR_MHPMEVENT22		0x336
+#define CSR_MHPMEVENT23		0x337
+#define CSR_MHPMEVENT24		0x338
+#define CSR_MHPMEVENT25		0x339
+#define CSR_MHPMEVENT26		0x33a
+#define CSR_MHPMEVENT27		0x33b
+#define CSR_MHPMEVENT28		0x33c
+#define CSR_MHPMEVENT29		0x33d
+#define CSR_MHPMEVENT30		0x33e
+#define CSR_MHPMEVENT31		0x33f
+#define CSR_MSCRATCH		0x340
+#define CSR_MEPC		0x341
+#define CSR_MCAUSE		0x342
+#define CSR_MTVAL		0x343
+#define CSR_MIP			0x344
+#define CSR_PMPCFG0		0x3a0
+#define CSR_PMPCFG1		0x3a1
+#define CSR_PMPCFG2		0x3a2
+#define CSR_PMPCFG3		0x3a3
+#define CSR_PMPADDR0		0x3b0
+#define CSR_PMPADDR1		0x3b1
+#define CSR_PMPADDR2		0x3b2
+#define CSR_PMPADDR3		0x3b3
+#define CSR_PMPADDR4		0x3b4
+#define CSR_PMPADDR5		0x3b5
+#define CSR_PMPADDR6		0x3b6
+#define CSR_PMPADDR7		0x3b7
+#define CSR_PMPADDR8		0x3b8
+#define CSR_PMPADDR9		0x3b9
+#define CSR_PMPADDR10		0x3ba
+#define CSR_PMPADDR11		0x3bb
+#define CSR_PMPADDR12		0x3bc
+#define CSR_PMPADDR13		0x3bd
+#define CSR_PMPADDR14		0x3be
+#define CSR_PMPADDR15		0x3bf
+
+#define CSR_TSELECT		0x7a0
+#define CSR_TDATA1		0x7a1
+#define CSR_TDATA2		0x7a2
+#define CSR_TDATA3		0x7a3
+#define CSR_DCSR		0x7b0
+#define CSR_DPC			0x7b1
+#define CSR_DSCRATCH		0x7b2
+
+#define CSR_MCYCLE		0xb00
+#define CSR_MINSTRET		0xb02
+#define CSR_MHPMCOUNTER3	0xb03
+#define CSR_MHPMCOUNTER4	0xb04
+#define CSR_MHPMCOUNTER5	0xb05
+#define CSR_MHPMCOUNTER6	0xb06
+#define CSR_MHPMCOUNTER7	0xb07
+#define CSR_MHPMCOUNTER8	0xb08
+#define CSR_MHPMCOUNTER9	0xb09
+#define CSR_MHPMCOUNTER10	0xb0a
+#define CSR_MHPMCOUNTER11	0xb0b
+#define CSR_MHPMCOUNTER12	0xb0c
+#define CSR_MHPMCOUNTER13	0xb0d
+#define CSR_MHPMCOUNTER14	0xb0e
+#define CSR_MHPMCOUNTER15	0xb0f
+#define CSR_MHPMCOUNTER16	0xb10
+#define CSR_MHPMCOUNTER17	0xb11
+#define CSR_MHPMCOUNTER18	0xb12
+#define CSR_MHPMCOUNTER19	0xb13
+#define CSR_MHPMCOUNTER20	0xb14
+#define CSR_MHPMCOUNTER21	0xb15
+#define CSR_MHPMCOUNTER22	0xb16
+#define CSR_MHPMCOUNTER23	0xb17
+#define CSR_MHPMCOUNTER24	0xb18
+#define CSR_MHPMCOUNTER25	0xb19
+#define CSR_MHPMCOUNTER26	0xb1a
+#define CSR_MHPMCOUNTER27	0xb1b
+#define CSR_MHPMCOUNTER28	0xb1c
+#define CSR_MHPMCOUNTER29	0xb1d
+#define CSR_MHPMCOUNTER30	0xb1e
+#define CSR_MHPMCOUNTER31	0xb1f
+#define CSR_MCYCLEH		0xb80
+#define CSR_MINSTRETH		0xb82
+#define CSR_MHPMCOUNTER3H	0xb83
+#define CSR_MHPMCOUNTER4H	0xb84
+#define CSR_MHPMCOUNTER5H	0xb85
+#define CSR_MHPMCOUNTER6H	0xb86
+#define CSR_MHPMCOUNTER7H	0xb87
+#define CSR_MHPMCOUNTER8H	0xb88
+#define CSR_MHPMCOUNTER9H	0xb89
+#define CSR_MHPMCOUNTER10H	0xb8a
+#define CSR_MHPMCOUNTER11H	0xb8b
+#define CSR_MHPMCOUNTER12H	0xb8c
+#define CSR_MHPMCOUNTER13H	0xb8d
+#define CSR_MHPMCOUNTER14H	0xb8e
+#define CSR_MHPMCOUNTER15H	0xb8f
+#define CSR_MHPMCOUNTER16H	0xb90
+#define CSR_MHPMCOUNTER17H	0xb91
+#define CSR_MHPMCOUNTER18H	0xb92
+#define CSR_MHPMCOUNTER19H	0xb93
+#define CSR_MHPMCOUNTER20H	0xb94
+#define CSR_MHPMCOUNTER21H	0xb95
+#define CSR_MHPMCOUNTER22H	0xb96
+#define CSR_MHPMCOUNTER23H	0xb97
+#define CSR_MHPMCOUNTER24H	0xb98
+#define CSR_MHPMCOUNTER25H	0xb99
+#define CSR_MHPMCOUNTER26H	0xb9a
+#define CSR_MHPMCOUNTER27H	0xb9b
+#define CSR_MHPMCOUNTER28H	0xb9c
+#define CSR_MHPMCOUNTER29H	0xb9d
+#define CSR_MHPMCOUNTER30H	0xb9e
+#define CSR_MHPMCOUNTER31H	0xb9f
+
+#define CSR_CYCLE		0xc00
+#define CSR_TIME		0xc01
+#define CSR_INSTRET		0xc02
+#define CSR_HPMCOUNTER3		0xc03
+#define CSR_HPMCOUNTER4		0xc04
+#define CSR_HPMCOUNTER5		0xc05
+#define CSR_HPMCOUNTER6		0xc06
+#define CSR_HPMCOUNTER7		0xc07
+#define CSR_HPMCOUNTER8		0xc08
+#define CSR_HPMCOUNTER9		0xc09
+#define CSR_HPMCOUNTER10	0xc0a
+#define CSR_HPMCOUNTER11	0xc0b
+#define CSR_HPMCOUNTER12	0xc0c
+#define CSR_HPMCOUNTER13	0xc0d
+#define CSR_HPMCOUNTER14	0xc0e
+#define CSR_HPMCOUNTER15	0xc0f
+#define CSR_HPMCOUNTER16	0xc10
+#define CSR_HPMCOUNTER17	0xc11
+#define CSR_HPMCOUNTER18	0xc12
+#define CSR_HPMCOUNTER19	0xc13
+#define CSR_HPMCOUNTER20	0xc14
+#define CSR_HPMCOUNTER21	0xc15
+#define CSR_HPMCOUNTER22	0xc16
+#define CSR_HPMCOUNTER23	0xc17
+#define CSR_HPMCOUNTER24	0xc18
+#define CSR_HPMCOUNTER25	0xc19
+#define CSR_HPMCOUNTER26	0xc1a
+#define CSR_HPMCOUNTER27	0xc1b
+#define CSR_HPMCOUNTER28	0xc1c
+#define CSR_HPMCOUNTER29	0xc1d
+#define CSR_HPMCOUNTER30	0xc1e
+#define CSR_HPMCOUNTER31	0xc1f
+#define CSR_CYCLEH		0xc80
+#define CSR_TIMEH		0xc81
+#define CSR_INSTRETH		0xc82
+#define CSR_HPMCOUNTER3H	0xc83
+#define CSR_HPMCOUNTER4H	0xc84
+#define CSR_HPMCOUNTER5H	0xc85
+#define CSR_HPMCOUNTER6H	0xc86
+#define CSR_HPMCOUNTER7H	0xc87
+#define CSR_HPMCOUNTER8H	0xc88
+#define CSR_HPMCOUNTER9H	0xc89
+#define CSR_HPMCOUNTER10H	0xc8a
+#define CSR_HPMCOUNTER11H	0xc8b
+#define CSR_HPMCOUNTER12H	0xc8c
+#define CSR_HPMCOUNTER13H	0xc8d
+#define CSR_HPMCOUNTER14H	0xc8e
+#define CSR_HPMCOUNTER15H	0xc8f
+#define CSR_HPMCOUNTER16H	0xc90
+#define CSR_HPMCOUNTER17H	0xc91
+#define CSR_HPMCOUNTER18H	0xc92
+#define CSR_HPMCOUNTER19H	0xc93
+#define CSR_HPMCOUNTER20H	0xc94
+#define CSR_HPMCOUNTER21H	0xc95
+#define CSR_HPMCOUNTER22H	0xc96
+#define CSR_HPMCOUNTER23H	0xc97
+#define CSR_HPMCOUNTER24H	0xc98
+#define CSR_HPMCOUNTER25H	0xc99
+#define CSR_HPMCOUNTER26H	0xc9a
+#define CSR_HPMCOUNTER27H	0xc9b
+#define CSR_HPMCOUNTER28H	0xc9c
+#define CSR_HPMCOUNTER29H	0xc9d
+#define CSR_HPMCOUNTER30H	0xc9e
+#define CSR_HPMCOUNTER31H	0xc9f
+
+#define CSR_MVENDORID		0xf11
+#define CSR_MARCHID		0xf12
+#define CSR_MIMPID		0xf13
+#define CSR_MHARTID		0xf14
+
 #endif /* __riscv */
 
 #endif /* RISCV_CSR_ENCODING_H */
diff --git a/arch/riscv/include/asm/global_data.h b/arch/riscv/include/asm/global_data.h
index 4d5d623..a3a342c 100644
--- a/arch/riscv/include/asm/global_data.h
+++ b/arch/riscv/include/asm/global_data.h
@@ -12,6 +12,10 @@
 
 /* Architecture-specific global data */
 struct arch_global_data {
+	long boot_hart;		/* boot hart id */
+#ifdef CONFIG_SIFIVE_CLINT
+	void __iomem *clint;	/* clint base address */
+#endif
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/riscv/include/asm/syscon.h b/arch/riscv/include/asm/syscon.h
new file mode 100644
index 0000000..d311ee6
--- /dev/null
+++ b/arch/riscv/include/asm/syscon.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#ifndef _ASM_SYSCON_H
+#define _ASM_SYSCON_H
+
+/*
+ * System controllers in a RISC-V system
+ *
+ * So far only SiFive's Core Local Interruptor (CLINT) is defined.
+ */
+enum {
+	RISCV_NONE,
+	RISCV_SYSCON_CLINT,	/* Core Local Interruptor (CLINT) */
+};
+
+#endif /* _ASM_SYSCON_H */
diff --git a/arch/riscv/lib/Makefile b/arch/riscv/lib/Makefile
index b58db89..edfa616 100644
--- a/arch/riscv/lib/Makefile
+++ b/arch/riscv/lib/Makefile
@@ -9,6 +9,8 @@
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_GO) += boot.o
 obj-y	+= cache.o
+obj-$(CONFIG_RISCV_RDTIME) += rdtime.o
+obj-$(CONFIG_SIFIVE_CLINT) += sifive_clint.o
 obj-y	+= interrupts.o
 obj-y	+= reset.o
 obj-y   += setjmp.o
diff --git a/arch/riscv/lib/asm-offsets.c b/arch/riscv/lib/asm-offsets.c
new file mode 100644
index 0000000..e0b71f5
--- /dev/null
+++ b/arch/riscv/lib/asm-offsets.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * From arch/x86/lib/asm-offsets.c
+ *
+ * This program is used to generate definitions needed by
+ * assembly language modules.
+ */
+
+#include <common.h>
+#include <linux/kbuild.h>
+
+int main(void)
+{
+	DEFINE(GD_BOOT_HART, offsetof(gd_t, arch.boot_hart));
+
+	return 0;
+}
diff --git a/arch/riscv/lib/bootm.c b/arch/riscv/lib/bootm.c
index 124aeef..f36b870 100644
--- a/arch/riscv/lib/bootm.c
+++ b/arch/riscv/lib/bootm.c
@@ -86,14 +86,14 @@
 
 	bootstage_mark(BOOTSTAGE_ID_RUN_OS);
 
-	debug("## Transferring control to Linux (at address %08lx) ...\n",
+	debug("## Transferring control to kernel (at address %08lx) ...\n",
 	      (ulong)kernel);
 
 	announce_and_cleanup(fake);
 
 	if (!fake) {
 		if (IMAGE_ENABLE_OF_LIBFDT && images->ft_len)
-			kernel(csr_read(mhartid), images->ft_addr);
+			kernel(gd->arch.boot_hart, images->ft_addr);
 	}
 }
 
@@ -118,3 +118,9 @@
 	boot_jump_linux(images, flag);
 	return 0;
 }
+
+int do_bootm_vxworks(int flag, int argc, char * const argv[],
+		     bootm_headers_t *images)
+{
+	return do_bootm_linux(flag, argc, argv, images);
+}
diff --git a/arch/riscv/lib/interrupts.c b/arch/riscv/lib/interrupts.c
index 3aff006..e185933 100644
--- a/arch/riscv/lib/interrupts.c
+++ b/arch/riscv/lib/interrupts.c
@@ -12,7 +12,36 @@
 #include <asm/system.h>
 #include <asm/encoding.h>
 
-static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs);
+static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)
+{
+	static const char * const exception_code[] = {
+		"Instruction address misaligned",
+		"Instruction access fault",
+		"Illegal instruction",
+		"Breakpoint",
+		"Load address misaligned",
+		"Load access fault",
+		"Store/AMO address misaligned",
+		"Store/AMO access fault",
+		"Environment call from U-mode",
+		"Environment call from S-mode",
+		"Reserved",
+		"Environment call from M-mode",
+		"Instruction page fault",
+		"Load page fault",
+		"Reserved",
+		"Store/AMO page fault",
+	};
+
+	if (code < ARRAY_SIZE(exception_code)) {
+		printf("exception code: %ld , %s , epc %lx , ra %lx\n",
+		       code, exception_code[code], epc, regs->ra);
+	} else {
+		printf("Reserved\n");
+	}
+
+	hang();
+}
 
 int interrupt_init(void)
 {
@@ -72,34 +101,3 @@
 __attribute__((weak)) void timer_interrupt(struct pt_regs *regs)
 {
 }
-
-static void _exit_trap(ulong code, ulong epc, struct pt_regs *regs)
-{
-	static const char * const exception_code[] = {
-		"Instruction address misaligned",
-		"Instruction access fault",
-		"Illegal instruction",
-		"Breakpoint",
-		"Load address misaligned",
-		"Load access fault",
-		"Store/AMO address misaligned",
-		"Store/AMO access fault",
-		"Environment call from U-mode",
-		"Environment call from S-mode",
-		"Reserved",
-		"Environment call from M-mode",
-		"Instruction page fault",
-		"Load page fault",
-		"Reserved",
-		"Store/AMO page fault",
-	};
-
-	if (code < ARRAY_SIZE(exception_code)) {
-		printf("exception code: %ld , %s , epc %lx , ra %lx\n",
-		       code, exception_code[code], epc, regs->ra);
-	} else {
-		printf("Reserved\n");
-	}
-
-	hang();
-}
diff --git a/arch/riscv/lib/rdtime.c b/arch/riscv/lib/rdtime.c
new file mode 100644
index 0000000..e128d7f
--- /dev/null
+++ b/arch/riscv/lib/rdtime.c
@@ -0,0 +1,38 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Anup Patel <anup@brainfault.org>
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * The riscv_get_time() API implementation that is using the
+ * standard rdtime instruction.
+ */
+
+#include <common.h>
+
+/* Implement the API required by RISC-V timer driver */
+int riscv_get_time(u64 *time)
+{
+#ifdef CONFIG_64BIT
+	u64 n;
+
+	__asm__ __volatile__ (
+		"rdtime %0"
+		: "=r" (n));
+
+	*time = n;
+#else
+	u32 lo, hi, tmp;
+
+	__asm__ __volatile__ (
+		"1:\n"
+		"rdtimeh %0\n"
+		"rdtime %1\n"
+		"rdtimeh %2\n"
+		"bne %0, %2, 1b"
+		: "=&r" (hi), "=&r" (lo), "=&r" (tmp));
+
+	*time = ((u64)hi << 32) | lo;
+#endif
+
+	return 0;
+}
diff --git a/arch/riscv/lib/sifive_clint.c b/arch/riscv/lib/sifive_clint.c
new file mode 100644
index 0000000..d24e0d5
--- /dev/null
+++ b/arch/riscv/lib/sifive_clint.c
@@ -0,0 +1,84 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * U-Boot syscon driver for SiFive's Core Local Interruptor (CLINT).
+ * The CLINT block holds memory-mapped control and status registers
+ * associated with software and timer interrupts.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <asm/io.h>
+#include <asm/syscon.h>
+
+/* MSIP registers */
+#define MSIP_REG(base, hart)		((ulong)(base) + (hart) * 4)
+/* mtime compare register */
+#define MTIMECMP_REG(base, hart)	((ulong)(base) + 0x4000 + (hart) * 8)
+/* mtime register */
+#define MTIME_REG(base)			((ulong)(base) + 0xbff8)
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define CLINT_BASE_GET(void)						\
+	do {								\
+		long *ret;						\
+									\
+		if (!gd->arch.clint) {					\
+			ret = syscon_get_first_range(RISCV_SYSCON_CLINT); \
+			if (IS_ERR(ret))				\
+				return PTR_ERR(ret);			\
+			gd->arch.clint = ret;				\
+		}							\
+	} while (0)
+
+int riscv_get_time(u64 *time)
+{
+	CLINT_BASE_GET();
+
+	*time = readq((void __iomem *)MTIME_REG(gd->arch.clint));
+
+	return 0;
+}
+
+int riscv_set_timecmp(int hart, u64 cmp)
+{
+	CLINT_BASE_GET();
+
+	writeq(cmp, (void __iomem *)MTIMECMP_REG(gd->arch.clint, hart));
+
+	return 0;
+}
+
+int riscv_send_ipi(int hart)
+{
+	CLINT_BASE_GET();
+
+	writel(1, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+
+	return 0;
+}
+
+int riscv_clear_ipi(int hart)
+{
+	CLINT_BASE_GET();
+
+	writel(0, (void __iomem *)MSIP_REG(gd->arch.clint, hart));
+
+	return 0;
+}
+
+static const struct udevice_id sifive_clint_ids[] = {
+	{ .compatible = "riscv,clint0", .data = RISCV_SYSCON_CLINT },
+	{ }
+};
+
+U_BOOT_DRIVER(sifive_clint) = {
+	.name		= "sifive_clint",
+	.id		= UCLASS_SYSCON,
+	.of_match	= sifive_clint_ids,
+	.flags		= DM_FLAG_PRE_RELOC,
+};
diff --git a/arch/sandbox/cpu/sdl.c b/arch/sandbox/cpu/sdl.c
index c7a8d94..f668f53 100644
--- a/arch/sandbox/cpu/sdl.c
+++ b/arch/sandbox/cpu/sdl.c
@@ -4,13 +4,24 @@
  */
 
 #include <errno.h>
+#include <unistd.h>
 #include <linux/input.h>
 #include <SDL/SDL.h>
-#include <sound.h>
 #include <asm/state.h>
 
-enum {
-	SAMPLE_RATE	= 22050,
+/**
+ * struct buf_info - a data buffer holding audio data
+ *
+ * @pos:	Current position playing in audio buffer
+ * @size:	Size of data in audio buffer (0=empty)
+ * @alloced:	Allocated size of audio buffer (max size it can hold)
+ * @data:	Audio data
+ */
+struct buf_info {
+	uint pos;
+	uint size;
+	uint alloced;
+	uint8_t *data;
 };
 
 static struct sdl_info {
@@ -20,12 +31,12 @@
 	int depth;
 	int pitch;
 	uint frequency;
-	uint audio_pos;
-	uint audio_size;
 	uint sample_rate;
-	uint8_t *audio_data;
 	bool audio_active;
 	bool inited;
+	int cur_buf;
+	struct buf_info buf[2];
+	bool running;
 } sdl;
 
 static void sandbox_sdl_poll_events(void)
@@ -243,24 +254,37 @@
 
 void sandbox_sdl_fill_audio(void *udata, Uint8 *stream, int len)
 {
+	struct buf_info *buf;
 	int avail;
+	int i;
 
-	avail = sdl.audio_size - sdl.audio_pos;
-	if (avail < len)
-		len = avail;
+	for (i = 0; i < 2; i++) {
+		buf = &sdl.buf[sdl.cur_buf];
+		avail = buf->size - buf->pos;
+		if (avail <= 0) {
+			sdl.cur_buf = 1 - sdl.cur_buf;
+			continue;
+		}
+		if (avail > len)
+			avail = len;
 
-	SDL_MixAudio(stream, sdl.audio_data + sdl.audio_pos, len,
-		     SDL_MIX_MAXVOLUME);
-	sdl.audio_pos += len;
+		SDL_MixAudio(stream, buf->data + buf->pos, avail,
+			     SDL_MIX_MAXVOLUME);
+		buf->pos += avail;
+		len -= avail;
 
-	/* Loop if we are at the end */
-	if (sdl.audio_pos == sdl.audio_size)
-		sdl.audio_pos = 0;
+		/* Move to next buffer if we are at the end */
+		if (buf->pos == buf->size)
+			buf->size = 0;
+		else
+			break;
+	}
 }
 
-int sandbox_sdl_sound_init(void)
+int sandbox_sdl_sound_init(int rate, int channels)
 {
 	SDL_AudioSpec wanted;
+	int i;
 
 	if (sandbox_sdl_ensure_init())
 		return -1;
@@ -269,20 +293,27 @@
 		return 0;
 
 	/* Set the audio format */
-	wanted.freq = SAMPLE_RATE;
+	wanted.freq = rate;
 	wanted.format = AUDIO_S16;
-	wanted.channels = 1;    /* 1 = mono, 2 = stereo */
+	wanted.channels = channels;
 	wanted.samples = 1024;  /* Good low-latency value for callback */
 	wanted.callback = sandbox_sdl_fill_audio;
 	wanted.userdata = NULL;
 
-	sdl.audio_size = sizeof(uint16_t) * wanted.freq;
-	sdl.audio_data = malloc(sdl.audio_size);
-	if (!sdl.audio_data) {
-		printf("%s: Out of memory\n", __func__);
-		return -1;
+	for (i = 0; i < 2; i++) {
+		struct buf_info *buf = &sdl.buf[i];
+
+		buf->alloced = sizeof(uint16_t) * wanted.freq * wanted.channels;
+		buf->data = malloc(buf->alloced);
+		if (!buf->data) {
+			printf("%s: Out of memory\n", __func__);
+			if (i == 1)
+				free(sdl.buf[0].data);
+			return -1;
+		}
+		buf->pos = 0;
+		buf->size = 0;
 	}
-	sdl.audio_pos = 0;
 
 	if (SDL_InitSubSystem(SDL_INIT_AUDIO) < 0) {
 		printf("Unable to initialize SDL audio: %s\n", SDL_GetError());
@@ -296,33 +327,50 @@
 	}
 	sdl.audio_active = true;
 	sdl.sample_rate = wanted.freq;
+	sdl.cur_buf = 0;
+	sdl.running = 0;
 
 	return 0;
 
 err:
-	free(sdl.audio_data);
+	for (i = 0; i < 2; i++)
+		free(sdl.buf[i].data);
 	return -1;
 }
 
-int sandbox_sdl_sound_start(uint frequency)
+int sandbox_sdl_sound_play(const void *data, uint size)
 {
+	struct buf_info *buf;
+
 	if (!sdl.audio_active)
-		return -1;
-	sdl.frequency = frequency;
-	sound_create_square_wave(sdl.sample_rate,
-				 (unsigned short *)sdl.audio_data,
-				 sdl.audio_size, frequency);
-	sdl.audio_pos = 0;
-	SDL_PauseAudio(0);
+		return 0;
+
+	buf = &sdl.buf[0];
+	if (buf->size)
+		buf = &sdl.buf[1];
+	while (buf->size)
+		usleep(1000);
+
+	if (size > buf->alloced)
+		return -E2BIG;
+
+	memcpy(buf->data, data, size);
+	buf->size = size;
+	buf->pos = 0;
+	if (!sdl.running) {
+		SDL_PauseAudio(0);
+		sdl.running = 1;
+	}
 
 	return 0;
 }
 
 int sandbox_sdl_sound_stop(void)
 {
-	if (!sdl.audio_active)
-		return -1;
-	SDL_PauseAudio(1);
+	if (sdl.running) {
+		SDL_PauseAudio(1);
+		sdl.running = 0;
+	}
 
 	return 0;
 }
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index ce3c88c..ae3189e 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -18,6 +18,11 @@
 		stdout-path = "/serial";
 	};
 
+	audio: audio-codec {
+		compatible = "sandbox,audio-codec";
+		#sound-dai-cells = <1>;
+	};
+
 	cros_ec: cros-ec {
 		reg = <0 0>;
 		u-boot,dm-pre-reloc;
@@ -127,6 +132,11 @@
 		};
 	};
 
+	i2s: i2s {
+		compatible = "sandbox,i2s";
+		#sound-dai-cells = <1>;
+	};
+
 	lcd {
 		u-boot,dm-pre-reloc;
 		compatible = "sandbox,lcd-sdl";
@@ -190,6 +200,17 @@
 		compatible = "sandbox,reset";
 	};
 
+	sound {
+		compatible = "sandbox,sound";
+		cpu {
+			sound-dai = <&i2s 0>;
+		};
+
+		codec {
+			sound-dai = <&audio 0>;
+		};
+	};
+
 	spi@0 {
 		u-boot,dm-pre-reloc;
 		#address-cells = <1>;
diff --git a/arch/sandbox/dts/test.dts b/arch/sandbox/dts/test.dts
index 6b1c269..3790b4c 100644
--- a/arch/sandbox/dts/test.dts
+++ b/arch/sandbox/dts/test.dts
@@ -42,6 +42,11 @@
 		osd0 = "/osd";
 	};
 
+	audio: audio-codec {
+		compatible = "sandbox,audio-codec";
+		#sound-dai-cells = <1>;
+	};
+
 	cros_ec: cros-ec {
 		reg = <0 0>;
 		compatible = "google,cros-ec-sandbox";
@@ -82,6 +87,8 @@
 		test2-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 6 1 3 2 1>,
 			<&gpio_b 7 2 3 2 1>, <&gpio_b 8 4 3 2 1>,
 			<&gpio_b 9 0xc 3 2 1>;
+		int-value = <1234>;
+		uint-value = <(-1234)>;
 	};
 
 	junk {
@@ -373,6 +380,11 @@
 		u-boot,dm-pre-reloc;
 	};
 
+	i2s: i2s {
+		compatible = "sandbox,i2s";
+		#sound-dai-cells = <1>;
+	};
+
 	misc-test {
 		compatible = "sandbox,misc_sandbox";
 	};
@@ -528,6 +540,17 @@
 		compatible = "sandbox,smem";
 	};
 
+	sound {
+		compatible = "sandbox,sound";
+		cpu {
+			sound-dai = <&i2s 0>;
+		};
+
+		codec {
+			sound-dai = <&audio 0>;
+		};
+	};
+
 	spi@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/sandbox/include/asm/sdl.h b/arch/sandbox/include/asm/sdl.h
index 1c4380c..1027b59 100644
--- a/arch/sandbox/include/asm/sdl.h
+++ b/arch/sandbox/include/asm/sdl.h
@@ -54,12 +54,12 @@
 int sandbox_sdl_key_pressed(int keycode);
 
 /**
- * sandbox_sdl_sound_start() - start playing a sound
+ * sandbox_sdl_sound_play() - Play a sound
  *
- * @frequency:	Frequency of sounds in Hertz
- * @return 0 if OK, -ENODEV if no sound is available
+ * @data:	Data to play (typically 16-bit)
+ * @count:	Number of bytes in data
  */
-int sandbox_sdl_sound_start(uint frequency);
+int sandbox_sdl_sound_play(const void *data, uint count);
 
 /**
  * sandbox_sdl_sound_stop() - stop playing a sound
@@ -71,9 +71,11 @@
 /**
  * sandbox_sdl_sound_init() - set up the sound system
  *
+ * @rate:	Sample rate to use
+ * @channels:	Number of channels to use (1=mono, 2=stereo)
  * @return 0 if OK, -ENODEV if no sound is available
  */
-int sandbox_sdl_sound_init(void);
+int sandbox_sdl_sound_init(int rate, int channels);
 
 #else
 static inline int sandbox_sdl_init_display(int width, int height,
@@ -102,12 +104,17 @@
 	return -ENODEV;
 }
 
+int sandbox_sdl_sound_play(const void *data, uint count)
+{
+	return -ENODEV;
+}
+
 static inline int sandbox_sdl_sound_stop(void)
 {
 	return -ENODEV;
 }
 
-static inline int sandbox_sdl_sound_init(void)
+int sandbox_sdl_sound_init(int rate, int channels)
 {
 	return -ENODEV;
 }
diff --git a/arch/sandbox/include/asm/sound.h b/arch/sandbox/include/asm/sound.h
deleted file mode 100644
index a6015b0..0000000
--- a/arch/sandbox/include/asm/sound.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2013 Google, Inc
- */
-
-#ifndef __SANDBOX_SOUND_H
-#define __SANDBOX_SOUND_H
-
-int sound_play(unsigned int msec, unsigned int frequency);
-
-int sound_init(const void *blob);
-
-#endif
diff --git a/arch/sandbox/include/asm/test.h b/arch/sandbox/include/asm/test.h
index 5e81839..74f9618 100644
--- a/arch/sandbox/include/asm/test.h
+++ b/arch/sandbox/include/asm/test.h
@@ -121,4 +121,44 @@
  */
 void sandbox_sf_set_block_protect(struct udevice *dev, int bp_mask);
 
+/**
+ * sandbox_get_codec_params() - Read back codec parameters
+ *
+ * This reads back the parameters set by audio_codec_set_params() for the
+ * sandbox audio driver. Arguments are as for that function.
+ */
+void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
+			      int *mclk_freqp, int *bits_per_samplep,
+			      uint *channelsp);
+
+/**
+ * sandbox_get_i2s_sum() - Read back the sum of the audio data so far
+ *
+ * This data is provided to the sandbox driver by the I2S tx_data() method.
+ *
+ * @dev: Device to check
+ * @return sum of audio data
+ */
+int sandbox_get_i2s_sum(struct udevice *dev);
+
+/**
+ * sandbox_get_setup_called() - Returns the number of times setup(*) was called
+ *
+ * This is used in the sound test
+ *
+ * @dev: Device to check
+ * @return call count for the setup() method
+ */
+int sandbox_get_setup_called(struct udevice *dev);
+
+/**
+ * sandbox_get_sound_sum() - Read back the sum of the sound data so far
+ *
+ * This data is provided to the sandbox driver by the sound play() method.
+ *
+ * @dev: Device to check
+ * @return sum of audio data
+ */
+int sandbox_get_sound_sum(struct udevice *dev);
+
 #endif
diff --git a/board/AndesTech/ax25-ae350/Kconfig b/board/AndesTech/ax25-ae350/Kconfig
index bb69ea3..44cb302 100644
--- a/board/AndesTech/ax25-ae350/Kconfig
+++ b/board/AndesTech/ax25-ae350/Kconfig
@@ -21,4 +21,8 @@
 config ENV_OFFSET
 	default 0x140000 if ENV_IS_IN_SPI_FLASH
 
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+	select RISCV_NDS
+
 endif
diff --git a/board/AndesTech/ax25-ae350/MAINTAINERS b/board/AndesTech/ax25-ae350/MAINTAINERS
index d87446e..b0a99e4 100644
--- a/board/AndesTech/ax25-ae350/MAINTAINERS
+++ b/board/AndesTech/ax25-ae350/MAINTAINERS
@@ -3,6 +3,5 @@
 S:	Maintained
 F:	board/AndesTech/ax25-ae350/
 F:	include/configs/ax25-ae350.h
-F:	configs/a25-ae350_32_defconfig
-F:	configs/ax25-ae350_64_defconfig
-F:	configs/ax25-ae350_defconfig
+F:	configs/ae350_rv32_defconfig
+F:	configs/ae350_rv64_defconfig
diff --git a/board/elgin/elgin_rv1108/Kconfig b/board/elgin/elgin_rv1108/Kconfig
new file mode 100644
index 0000000..be92431
--- /dev/null
+++ b/board/elgin/elgin_rv1108/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_ELGIN_RV1108
+
+config SYS_BOARD
+	default "elgin_rv1108"
+
+config SYS_VENDOR
+	default "elgin"
+
+config SYS_CONFIG_NAME
+	default "elgin_rv1108"
+
+config BOARD_SPECIFIC_OPTIONS # dummy
+	def_bool y
+
+endif
diff --git a/board/elgin/elgin_rv1108/MAINTAINERS b/board/elgin/elgin_rv1108/MAINTAINERS
new file mode 100644
index 0000000..7747490
--- /dev/null
+++ b/board/elgin/elgin_rv1108/MAINTAINERS
@@ -0,0 +1,6 @@
+ELGIN-RV1108
+M:      Otavio Salvador <otavio@ossystems.com.br>
+S:      Maintained
+F:      board/elgin/elgin_rv1108
+F:      include/configs/elgin_rv1108.h
+F:      configs/elgin-rv1108_defconfig
diff --git a/board/elgin/elgin_rv1108/Makefile b/board/elgin/elgin_rv1108/Makefile
new file mode 100644
index 0000000..3822180
--- /dev/null
+++ b/board/elgin/elgin_rv1108/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2016 Rockchip Electronics Co., Ltd
+#
+# SPDX-License-Identifier:     GPL-2.0+
+#
+
+obj-y	+= elgin_rv1108.o
diff --git a/board/elgin/elgin_rv1108/elgin_rv1108.c b/board/elgin/elgin_rv1108/elgin_rv1108.c
new file mode 100644
index 0000000..3abc514
--- /dev/null
+++ b/board/elgin/elgin_rv1108/elgin_rv1108.c
@@ -0,0 +1,74 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C)Copyright 2016 Rockchip Electronics Co., Ltd
+ * Authors: Andy Yan <andy.yan@rock-chips.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <fdtdec.h>
+#include <asm/arch/grf_rv1108.h>
+#include <asm/arch/hardware.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int mach_cpu_init(void)
+{
+	int node;
+	struct rv1108_grf *grf;
+	enum {
+		GPIO3C3_SHIFT           = 6,
+		GPIO3C3_MASK            = 3 << GPIO3C3_SHIFT,
+
+		GPIO3C2_SHIFT           = 4,
+		GPIO3C2_MASK            = 3 << GPIO3C2_SHIFT,
+
+		GPIO2D2_SHIFT		= 4,
+		GPIO2D2_MASK		= 3 << GPIO2D2_SHIFT,
+		GPIO2D2_GPIO            = 0,
+		GPIO2D2_UART2_SOUT_M0,
+
+		GPIO2D1_SHIFT		= 2,
+		GPIO2D1_MASK		= 3 << GPIO2D1_SHIFT,
+		GPIO2D1_GPIO            = 0,
+		GPIO2D1_UART2_SIN_M0,
+	};
+
+	node = fdt_node_offset_by_compatible(gd->fdt_blob, -1, "rockchip,rv1108-grf");
+	grf = (struct rv1108_grf *)fdtdec_get_addr(gd->fdt_blob, node, "reg");
+
+	/* Elgin board use UART2 m0 for debug*/
+	rk_clrsetreg(&grf->gpio2d_iomux,
+		     GPIO2D2_MASK | GPIO2D1_MASK,
+		     GPIO2D2_UART2_SOUT_M0 << GPIO2D2_SHIFT |
+		     GPIO2D1_UART2_SIN_M0 << GPIO2D1_SHIFT);
+	rk_clrreg(&grf->gpio3c_iomux, GPIO3C3_MASK | GPIO3C2_MASK);
+
+	return 0;
+}
+
+#define MODEM_ENABLE_GPIO 111
+
+int board_init(void)
+{
+	gpio_request(MODEM_ENABLE_GPIO, "modem_enable");
+	gpio_direction_output(MODEM_ENABLE_GPIO, 0);
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = 0x8000000;
+
+	return 0;
+}
+
+int dram_init_banksize(void)
+{
+	gd->bd->bi_dram[0].start = 0x60000000;
+	gd->bd->bi_dram[0].size = 0x8000000;
+
+	return 0;
+}
diff --git a/board/emulation/qemu-riscv/Kconfig b/board/emulation/qemu-riscv/Kconfig
index 56bb533..0d865ac 100644
--- a/board/emulation/qemu-riscv/Kconfig
+++ b/board/emulation/qemu-riscv/Kconfig
@@ -18,6 +18,7 @@
 
 config BOARD_SPECIFIC_OPTIONS # dummy
 	def_bool y
+	select QEMU_RISCV
 	imply SYS_NS16550
 	imply VIRTIO_MMIO
 	imply VIRTIO_NET
@@ -32,5 +33,6 @@
 	imply CMD_FAT
 	imply BOARD_LATE_INIT
 	imply OF_BOARD_SETUP
+	imply SIFIVE_SERIAL
 
 endif
diff --git a/board/hisilicon/poplar/MAINTAINERS b/board/hisilicon/poplar/MAINTAINERS
index 0cc01c8..622e5cb 100644
--- a/board/hisilicon/poplar/MAINTAINERS
+++ b/board/hisilicon/poplar/MAINTAINERS
@@ -1,5 +1,6 @@
 Poplar BOARD
 M:     Jorge Ramirez-Ortiz <jorge.ramirez-ortiz@linaro.org>
+M:     Shawn Guo <shawn.guo@linaro.org>
 S:     Maintained
 F:     board/hisilicon/poplar
 F:     include/configs/poplar.h
diff --git a/board/hisilicon/poplar/poplar.c b/board/hisilicon/poplar/poplar.c
index 9e8eac7..8adc750 100644
--- a/board/hisilicon/poplar/poplar.c
+++ b/board/hisilicon/poplar/poplar.c
@@ -35,6 +35,7 @@
 
 struct mm_region *mem_map = poplar_mem_map;
 
+#if !CONFIG_IS_ENABLED(OF_CONTROL)
 static const struct pl01x_serial_platdata serial_platdata = {
 	.base = REG_BASE_UART0,
 	.type = TYPE_PL010,
@@ -45,6 +46,7 @@
 	.name = "serial_pl01x",
 	.platdata = &serial_platdata,
 };
+#endif
 
 int checkboard(void)
 {
diff --git a/board/imgtec/ci20/Kconfig b/board/imgtec/ci20/Kconfig
new file mode 100644
index 0000000..82bf65d
--- /dev/null
+++ b/board/imgtec/ci20/Kconfig
@@ -0,0 +1,15 @@
+if TARGET_JZ4780_CI20
+
+config SYS_BOARD
+	default "ci20"
+
+config SYS_VENDOR
+	default "imgtec"
+
+config SYS_CONFIG_NAME
+	default "ci20"
+
+config SYS_TEXT_BASE
+	default 0x80000000
+
+endif
diff --git a/board/imgtec/ci20/MAINTAINERS b/board/imgtec/ci20/MAINTAINERS
new file mode 100644
index 0000000..dca6bf3
--- /dev/null
+++ b/board/imgtec/ci20/MAINTAINERS
@@ -0,0 +1,6 @@
+Creator CI20 BOARD
+M:      Ezequiel Garcia <ezequiel@collabora.com>
+S:      Maintained
+F:      board/imgtec/ci20/
+F:      include/configs/ci20.h
+F:      configs/ci20_mmc_defconfig
diff --git a/board/imgtec/ci20/Makefile b/board/imgtec/ci20/Makefile
new file mode 100644
index 0000000..7843b46
--- /dev/null
+++ b/board/imgtec/ci20/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y := ci20.o
diff --git a/board/imgtec/ci20/README b/board/imgtec/ci20/README
new file mode 100644
index 0000000..07d89d7
--- /dev/null
+++ b/board/imgtec/ci20/README
@@ -0,0 +1,10 @@
+CI20 U-Boot
+
+Installation to an SD card:
+  Repartition your card with an MBR such that the first partition starts at an
+  offset of no less than 270KB. Then install U-Boot SPL & the full U-Boot image
+  to the card like so:
+
+    dd if=spl/u-boot-spl.bin of=/dev/sdX obs=512 seek=1
+    dd if=u-boot-dtb.img of=/dev/sdX obs=1K seek=14
+    sync
diff --git a/board/imgtec/ci20/ci20.c b/board/imgtec/ci20/ci20.c
new file mode 100644
index 0000000..9811ef5
--- /dev/null
+++ b/board/imgtec/ci20/ci20.c
@@ -0,0 +1,362 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * CI20 setup code
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <common.h>
+#include <environment.h>
+#include <net.h>
+#include <netdev.h>
+#include <asm/io.h>
+#include <asm/gpio.h>
+#include <mach/jz4780.h>
+#include <mach/jz4780_dram.h>
+#include <mach/jz4780_gpio.h>
+
+struct ci20_otp {
+	u32	serial_number;
+	u32	date;
+	u8	manufacturer[2];
+	u8	mac[6];
+} __packed;
+
+static void ci20_mux_mmc(void)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+
+	/* setup MSC1 pins */
+	writel(0x30f00000, gpio_regs + GPIO_PXINTC(4));
+	writel(0x30f00000, gpio_regs + GPIO_PXMASKC(4));
+	writel(0x30f00000, gpio_regs + GPIO_PXPAT1C(4));
+	writel(0x30f00000, gpio_regs + GPIO_PXPAT0C(4));
+	writel(0x30f00000, gpio_regs + GPIO_PXPENC(4));
+	jz4780_clk_ungate_mmc();
+}
+
+#ifndef CONFIG_SPL_BUILD
+
+static void ci20_mux_eth(void)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+
+#ifdef CONFIG_NAND
+	/* setup pins (some already setup for NAND) */
+	writel(0x04030000, gpio_regs + GPIO_PXINTC(0));
+	writel(0x04030000, gpio_regs + GPIO_PXMASKC(0));
+	writel(0x04030000, gpio_regs + GPIO_PXPAT1C(0));
+	writel(0x04030000, gpio_regs + GPIO_PXPAT0C(0));
+	writel(0x04030000, gpio_regs + GPIO_PXPENS(0));
+#else
+	/* setup pins (as above +NAND CS +RD/WE +SDx +SAx) */
+	writel(0x0dff00ff, gpio_regs + GPIO_PXINTC(0));
+	writel(0x0dff00ff, gpio_regs + GPIO_PXMASKC(0));
+	writel(0x0dff00ff, gpio_regs + GPIO_PXPAT1C(0));
+	writel(0x0dff00ff, gpio_regs + GPIO_PXPAT0C(0));
+	writel(0x0dff00ff, gpio_regs + GPIO_PXPENS(0));
+	writel(0x00000003, gpio_regs + GPIO_PXINTC(1));
+	writel(0x00000003, gpio_regs + GPIO_PXMASKC(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPAT1C(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPAT0C(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPENS(1));
+#endif
+}
+
+static void ci20_mux_jtag(void)
+{
+#ifdef CONFIG_JTAG
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+
+	/* enable JTAG */
+	writel(3 << 30, gpio_regs + GPIO_PXINTC(0));
+	writel(3 << 30, gpio_regs + GPIO_PXMASKC(0));
+	writel(3 << 30, gpio_regs + GPIO_PXPAT1C(0));
+	writel(3 << 30, gpio_regs + GPIO_PXPAT0C(0));
+#endif
+}
+
+static void ci20_mux_nand(void)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+
+	/* setup pins */
+	writel(0x002c00ff, gpio_regs + GPIO_PXINTC(0));
+	writel(0x002c00ff, gpio_regs + GPIO_PXMASKC(0));
+	writel(0x002c00ff, gpio_regs + GPIO_PXPAT1C(0));
+	writel(0x002c00ff, gpio_regs + GPIO_PXPAT0C(0));
+	writel(0x002c00ff, gpio_regs + GPIO_PXPENS(0));
+	writel(0x00000003, gpio_regs + GPIO_PXINTC(1));
+	writel(0x00000003, gpio_regs + GPIO_PXMASKC(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPAT1C(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPAT0C(1));
+	writel(0x00000003, gpio_regs + GPIO_PXPENS(1));
+
+	/* FRB0_N */
+	jz47xx_gpio_direction_input(JZ_GPIO(0, 20));
+	writel(20, gpio_regs + GPIO_PXPENS(0));
+
+	/* disable write protect */
+	jz47xx_gpio_direction_output(JZ_GPIO(5, 22), 1);
+}
+
+static void ci20_mux_uart(void)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+
+	/* UART0 */
+	writel(0x9, gpio_regs + GPIO_PXINTC(5));
+	writel(0x9, gpio_regs + GPIO_PXMASKC(5));
+	writel(0x9, gpio_regs + GPIO_PXPAT1C(5));
+	writel(0x9, gpio_regs + GPIO_PXPAT0C(5));
+	writel(0x9, gpio_regs + GPIO_PXPENC(5));
+	jz4780_clk_ungate_uart(0);
+
+	/* UART 1 and 2 */
+	jz4780_clk_ungate_uart(1);
+	jz4780_clk_ungate_uart(2);
+
+#ifndef CONFIG_JTAG
+	/* UART3 */
+	writel(1 << 12, gpio_regs + GPIO_PXINTC(3));
+	writel(1 << 12, gpio_regs + GPIO_PXMASKS(3));
+	writel(1 << 12, gpio_regs + GPIO_PXPAT1S(3));
+	writel(1 << 12, gpio_regs + GPIO_PXPAT0C(3));
+	writel(3 << 30, gpio_regs + GPIO_PXINTC(0));
+	writel(3 << 30, gpio_regs + GPIO_PXMASKC(0));
+	writel(3 << 30, gpio_regs + GPIO_PXPAT1C(0));
+	writel(1 << 30, gpio_regs + GPIO_PXPAT0C(0));
+	writel(1 << 31, gpio_regs + GPIO_PXPAT0S(0));
+	jz4780_clk_ungate_uart(3);
+#endif
+
+	/* UART4 */
+	writel(0x100400, gpio_regs + GPIO_PXINTC(2));
+	writel(0x100400, gpio_regs + GPIO_PXMASKC(2));
+	writel(0x100400, gpio_regs + GPIO_PXPAT1S(2));
+	writel(0x100400, gpio_regs + GPIO_PXPAT0C(2));
+	writel(0x100400, gpio_regs + GPIO_PXPENC(2));
+	jz4780_clk_ungate_uart(4);
+}
+
+int board_early_init_f(void)
+{
+	ci20_mux_jtag();
+	ci20_mux_uart();
+
+	ci20_mux_eth();
+	ci20_mux_mmc();
+	ci20_mux_nand();
+
+	/* SYS_POWER_IND high (LED blue, VBUS off) */
+	jz47xx_gpio_direction_output(JZ_GPIO(5, 15), 0);
+
+	/* LEDs off */
+	jz47xx_gpio_direction_output(JZ_GPIO(2, 0), 0);
+	jz47xx_gpio_direction_output(JZ_GPIO(2, 1), 0);
+	jz47xx_gpio_direction_output(JZ_GPIO(2, 2), 0);
+	jz47xx_gpio_direction_output(JZ_GPIO(2, 3), 0);
+
+	return 0;
+}
+
+int misc_init_r(void)
+{
+	const u32 efuse_clk = jz4780_clk_get_efuse_clk();
+	struct ci20_otp otp;
+	char manufacturer[3];
+
+	/* Read the board OTP data */
+	jz4780_efuse_init(efuse_clk);
+	jz4780_efuse_read(0x18, 16, (u8 *)&otp);
+
+	/* Set MAC address */
+	if (!is_valid_ethaddr(otp.mac)) {
+		/* no MAC assigned, generate one from the unique chip ID */
+		jz4780_efuse_read(0x8, 4, &otp.mac[0]);
+		jz4780_efuse_read(0x12, 2, &otp.mac[4]);
+		otp.mac[0] = (otp.mac[0] | 0x02) & ~0x01;
+	}
+	eth_env_set_enetaddr("ethaddr", otp.mac);
+
+	/* Put other board information into the environment */
+	env_set_ulong("serial#", otp.serial_number);
+	env_set_ulong("board_date", otp.date);
+	manufacturer[0] = otp.manufacturer[0];
+	manufacturer[1] = otp.manufacturer[1];
+	manufacturer[2] = 0;
+	env_set("board_mfr", manufacturer);
+
+	return 0;
+}
+
+#ifdef CONFIG_DRIVER_DM9000
+int board_eth_init(bd_t *bis)
+{
+	/* Enable clock */
+	jz4780_clk_ungate_ethernet();
+
+	/* Enable power (PB25) */
+	jz47xx_gpio_direction_output(JZ_GPIO(1, 25), 1);
+
+	/* Reset (PF12) */
+	mdelay(10);
+	jz47xx_gpio_direction_output(JZ_GPIO(5, 12), 0);
+	mdelay(10);
+	jz47xx_gpio_direction_output(JZ_GPIO(5, 12), 1);
+	mdelay(10);
+
+	return dm9000_initialize(bis);
+}
+#endif /* CONFIG_DRIVER_DM9000 */
+#endif
+
+static u8 ci20_revision(void)
+{
+	void __iomem *gpio_regs = (void __iomem *)GPIO_BASE;
+	int val;
+
+	jz47xx_gpio_direction_input(JZ_GPIO(2, 18));
+	jz47xx_gpio_direction_input(JZ_GPIO(2, 19));
+
+	/* Enable pullups */
+	writel(BIT(18) | BIT(19), gpio_regs + GPIO_PXPENC(2));
+
+	/* Read PC18/19 for version */
+	val = (!!jz47xx_gpio_get_value(JZ_GPIO(2, 18))) |
+	     ((!!jz47xx_gpio_get_value(JZ_GPIO(2, 19))) << 1);
+
+	if (val == 3)	/* Rev 1 boards had no pulldowns - giving 3 */
+		return 1;
+	if (val == 1)	/* Rev 2 boards pulldown port C bit 18 giving 1 */
+		return 2;
+
+	return 0;
+}
+
+int dram_init(void)
+{
+	gd->ram_size = sdram_size(0) + sdram_size(1);
+	return 0;
+}
+
+/* U-Boot common routines */
+int checkboard(void)
+{
+	printf("Board: Creator CI20 (rev.%d)\n", ci20_revision());
+	return 0;
+}
+
+#ifdef CONFIG_SPL_BUILD
+
+#if defined(CONFIG_SPL_MMC_SUPPORT)
+int board_mmc_init(bd_t *bd)
+{
+	ci20_mux_mmc();
+	return jz_mmc_init((void __iomem *)MSC0_BASE);
+}
+#endif
+
+static const struct jz4780_ddr_config K4B2G0846Q_48_config = {
+	.timing = {
+		(4 << DDRC_TIMING1_TRTP_BIT) | (13 << DDRC_TIMING1_TWTR_BIT) |
+		(6 << DDRC_TIMING1_TWR_BIT) | (5 << DDRC_TIMING1_TWL_BIT),
+
+		(4 << DDRC_TIMING2_TCCD_BIT) | (15 << DDRC_TIMING2_TRAS_BIT) |
+		(6 << DDRC_TIMING2_TRCD_BIT) | (6 << DDRC_TIMING2_TRL_BIT),
+
+		(4 << DDRC_TIMING3_ONUM) | (7 << DDRC_TIMING3_TCKSRE_BIT) |
+		(6 << DDRC_TIMING3_TRP_BIT) | (4 << DDRC_TIMING3_TRRD_BIT) |
+		(21 << DDRC_TIMING3_TRC_BIT),
+
+		(31 << DDRC_TIMING4_TRFC_BIT) | (1 << DDRC_TIMING4_TRWCOV_BIT) |
+		(4 << DDRC_TIMING4_TCKE_BIT) | (9 << DDRC_TIMING4_TMINSR_BIT) |
+		(8 << DDRC_TIMING4_TXP_BIT) | (3 << DDRC_TIMING4_TMRD_BIT),
+
+		(8 << DDRC_TIMING5_TRTW_BIT) | (4 << DDRC_TIMING5_TRDLAT_BIT) |
+		(4 << DDRC_TIMING5_TWDLAT_BIT),
+
+		(25 << DDRC_TIMING6_TXSRD_BIT) | (12 << DDRC_TIMING6_TFAW_BIT) |
+		(2 << DDRC_TIMING6_TCFGW_BIT) | (2 << DDRC_TIMING6_TCFGR_BIT),
+	},
+
+	/* PHY */
+	/* Mode Register 0 */
+	.mr0 = 0x420,
+#ifdef SDRAM_DISABLE_DLL
+	.mr1 = (DDR3_MR1_DIC_7 | DDR3_MR1_RTT_DIS | DDR3_MR1_DLL_DISABLE),
+#else
+	.mr1 = (DDR3_MR1_DIC_7 | DDR3_MR1_RTT_DIS),
+#endif
+
+	.ptr0 = 0x002000d4,
+	.ptr1 = 0x02230d40,
+	.ptr2 = 0x04013880,
+
+	.dtpr0 = 0x2a8f6690,
+	.dtpr1 = 0x00400860,
+	.dtpr2 = 0x10042a00,
+
+	.pullup = 0x0b,
+	.pulldn = 0x0b,
+};
+
+static const struct jz4780_ddr_config H5TQ2G83CFR_48_config = {
+	.timing = {
+		(4 << DDRC_TIMING1_TRTP_BIT) | (13 << DDRC_TIMING1_TWTR_BIT) |
+		(6 << DDRC_TIMING1_TWR_BIT) | (5 << DDRC_TIMING1_TWL_BIT),
+
+		(4 << DDRC_TIMING2_TCCD_BIT) | (16 << DDRC_TIMING2_TRAS_BIT) |
+		(6 << DDRC_TIMING2_TRCD_BIT) | (6 << DDRC_TIMING2_TRL_BIT),
+
+		(4 << DDRC_TIMING3_ONUM) | (7 << DDRC_TIMING3_TCKSRE_BIT) |
+		(6 << DDRC_TIMING3_TRP_BIT) | (4 << DDRC_TIMING3_TRRD_BIT) |
+		(22 << DDRC_TIMING3_TRC_BIT),
+
+		(42 << DDRC_TIMING4_TRFC_BIT) | (1 << DDRC_TIMING4_TRWCOV_BIT) |
+		(4 << DDRC_TIMING4_TCKE_BIT) | (7 << DDRC_TIMING4_TMINSR_BIT) |
+		(3 << DDRC_TIMING4_TXP_BIT) | (3 << DDRC_TIMING4_TMRD_BIT),
+
+		(8 << DDRC_TIMING5_TRTW_BIT) | (4 << DDRC_TIMING5_TRDLAT_BIT) |
+		(4 << DDRC_TIMING5_TWDLAT_BIT),
+
+		(25 << DDRC_TIMING6_TXSRD_BIT) | (20 << DDRC_TIMING6_TFAW_BIT) |
+		(2 << DDRC_TIMING6_TCFGW_BIT) | (2 << DDRC_TIMING6_TCFGR_BIT),
+	},
+
+	/* PHY */
+	/* Mode Register 0 */
+	.mr0 = 0x420,
+#ifdef SDRAM_DISABLE_DLL
+	.mr1 = (DDR3_MR1_DIC_7 | DDR3_MR1_RTT_DIS | DDR3_MR1_DLL_DISABLE),
+#else
+	.mr1 = (DDR3_MR1_DIC_7 | DDR3_MR1_RTT_DIS),
+#endif
+
+	.ptr0 = 0x002000d4,
+	.ptr1 = 0x02d30d40,
+	.ptr2 = 0x04013880,
+
+	.dtpr0 = 0x2c906690,
+	.dtpr1 = 0x005608a0,
+	.dtpr2 = 0x10042a00,
+
+	.pullup = 0x0e,
+	.pulldn = 0x0e,
+};
+
+#if (CONFIG_SYS_MHZ != 1200)
+#error No DDR configuration for CPU speed
+#endif
+
+const struct jz4780_ddr_config *jz4780_get_ddr_config(void)
+{
+	const int board_revision = ci20_revision();
+
+	if (board_revision == 2)
+		return &K4B2G0846Q_48_config;
+	else /* Fall back to H5TQ2G83CFR RAM */
+		return &H5TQ2G83CFR_48_config;
+}
+#endif
diff --git a/board/mscc/luton/Kconfig b/board/mscc/luton/Kconfig
new file mode 100644
index 0000000..e119980
--- /dev/null
+++ b/board/mscc/luton/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+if SOC_LUTON
+
+config SYS_VENDOR
+	default "mscc"
+
+config SYS_BOARD
+	default "luton"
+
+config SYS_CONFIG_NAME
+	default "luton"
+
+endif
diff --git a/board/mscc/luton/Makefile b/board/mscc/luton/Makefile
new file mode 100644
index 0000000..b27f7c7
--- /dev/null
+++ b/board/mscc/luton/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+obj-$(CONFIG_SOC_LUTON)	:= luton.o
diff --git a/board/mscc/luton/luton.c b/board/mscc/luton/luton.c
new file mode 100644
index 0000000..41fc6d5
--- /dev/null
+++ b/board/mscc/luton/luton.c
@@ -0,0 +1,28 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#define MSCC_GPIO_ALT0		0x88
+#define MSCC_GPIO_ALT1		0x8C
+
+DECLARE_GLOBAL_DATA_PTR;
+
+void board_debug_uart_init(void)
+{
+	/* too early for the pinctrl driver, so configure the UART pins here */
+	setbits_le32(BASE_DEVCPU_GCB + MSCC_GPIO_ALT0, BIT(30) | BIT(31));
+}
+
+int board_early_init_r(void)
+{
+	/* Prepare SPI controller to be used in master mode */
+	writel(0, BASE_CFG + ICPU_SW_MODE);
+
+	/* Address of boot parameters */
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
+	return 0;
+}
diff --git a/board/mscc/ocelot/Kconfig b/board/mscc/ocelot/Kconfig
new file mode 100644
index 0000000..9ddc088
--- /dev/null
+++ b/board/mscc/ocelot/Kconfig
@@ -0,0 +1,14 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+config SYS_VENDOR
+	default "mscc"
+
+if SOC_OCELOT
+
+config SYS_BOARD
+	default "ocelot"
+
+config SYS_CONFIG_NAME
+	default "ocelot"
+
+endif
diff --git a/board/mscc/ocelot/Makefile b/board/mscc/ocelot/Makefile
new file mode 100644
index 0000000..9f28c81
--- /dev/null
+++ b/board/mscc/ocelot/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+obj-$(CONFIG_SOC_OCELOT)	:= ocelot.o
+
diff --git a/board/mscc/ocelot/ocelot.c b/board/mscc/ocelot/ocelot.c
new file mode 100644
index 0000000..d521a61
--- /dev/null
+++ b/board/mscc/ocelot/ocelot.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <environment.h>
+#include <spi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define MSCC_GPIO_ALT0		0x54
+#define MSCC_GPIO_ALT1		0x58
+
+void external_cs_manage(struct udevice *dev, bool enable)
+{
+	u32 cs = spi_chip_select(dev);
+	/* IF_SI0_OWNER, select the owner of the SI interface
+	 * Encoding: 0: SI Slave
+	 *           1: SI Boot Master
+	 *           2: SI Master Controller
+	 */
+	if (!enable) {
+		writel(ICPU_SW_MODE_SW_PIN_CTRL_MODE |
+		       ICPU_SW_MODE_SW_SPI_CS(BIT(cs)), BASE_CFG + ICPU_SW_MODE);
+		clrsetbits_le32(BASE_CFG + ICPU_GENERAL_CTRL,
+				ICPU_GENERAL_CTRL_IF_SI_OWNER_M,
+				ICPU_GENERAL_CTRL_IF_SI_OWNER(2));
+	} else {
+		writel(0, BASE_CFG + ICPU_SW_MODE);
+		clrsetbits_le32(BASE_CFG + ICPU_GENERAL_CTRL,
+				ICPU_GENERAL_CTRL_IF_SI_OWNER_M,
+				ICPU_GENERAL_CTRL_IF_SI_OWNER(1));
+	}
+}
+
+void board_debug_uart_init(void)
+{
+	/* too early for the pinctrl driver, so configure the UART pins here */
+	setbits_le32(BASE_DEVCPU_GCB + MSCC_GPIO_ALT0, BIT(6) | BIT(7));
+	clrbits_le32(BASE_DEVCPU_GCB + MSCC_GPIO_ALT1, BIT(6) | BIT(7));
+}
+
+int board_early_init_r(void)
+{
+	/* Prepare SPI controller to be used in master mode */
+	writel(0, BASE_CFG + ICPU_SW_MODE);
+	clrsetbits_le32(BASE_CFG + ICPU_GENERAL_CTRL,
+			ICPU_GENERAL_CTRL_IF_SI_OWNER_M,
+			ICPU_GENERAL_CTRL_IF_SI_OWNER(2));
+
+	/* Address of boot parameters */
+	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE;
+	return 0;
+}
diff --git a/board/ti/am43xx/board.c b/board/ti/am43xx/board.c
index 31bc0f4..536c5b8 100644
--- a/board/ti/am43xx/board.c
+++ b/board/ti/am43xx/board.c
@@ -705,6 +705,19 @@
 }
 
 #ifdef CONFIG_BOARD_LATE_INIT
+#if CONFIG_IS_ENABLED(DM_USB) && CONFIG_IS_ENABLED(OF_CONTROL)
+static int device_okay(const char *path)
+{
+	int node;
+
+	node = fdt_path_offset(gd->fdt_blob, path);
+	if (node < 0)
+		return 0;
+
+	return fdtdec_get_is_enabled(gd->fdt_blob, node);
+}
+#endif
+
 int board_late_init(void)
 {
 #ifdef CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG
@@ -717,10 +730,18 @@
 	if (get_device_type() == HS_DEVICE)
 		env_set("boot_fit", "1");
 #endif
+
+#if CONFIG_IS_ENABLED(DM_USB) && CONFIG_IS_ENABLED(OF_CONTROL)
+	if (device_okay("/ocp/omap_dwc3@48380000"))
+		enable_usb_clocks(0);
+	if (device_okay("/ocp/omap_dwc3@483c0000"))
+		enable_usb_clocks(1);
+#endif
 	return 0;
 }
 #endif
 
+#if !CONFIG_IS_ENABLED(DM_USB_GADGET)
 #ifdef CONFIG_USB_DWC3
 static struct dwc3_device usb_otg_ss1 = {
 	.maximum_speed = USB_SPEED_HIGH,
@@ -823,6 +844,7 @@
 	return 0;
 }
 #endif /* defined(CONFIG_USB_DWC3) || defined(CONFIG_USB_XHCI_OMAP) */
+#endif /* !CONFIG_IS_ENABLED(DM_USB_GADGET) */
 
 #ifdef CONFIG_DRIVER_TI_CPSW
 
diff --git a/board/ti/ks2_evm/board.c b/board/ti/ks2_evm/board.c
index 3e06800..eed62e9 100644
--- a/board/ti/ks2_evm/board.c
+++ b/board/ti/ks2_evm/board.c
@@ -66,6 +66,18 @@
 
 int board_init(void)
 {
+#if CONFIG_IS_ENABLED(DM_USB)
+	int rc = psc_enable_module(KS2_LPSC_USB);
+
+	if (rc)
+		puts("Cannot enable USB0 module");
+#ifdef KS2_LPSC_USB_1
+	rc = psc_enable_module(KS2_LPSC_USB_1);
+	if (rc)
+		puts("Cannot enable USB1 module");
+#endif
+#endif
+
 	gd->bd->bi_boot_params = CONFIG_SYS_SDRAM_BASE + 0x100;
 
 	return 0;
diff --git a/cmd/Makefile b/cmd/Makefile
index 4998643..15ae4d2 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -40,6 +40,7 @@
 obj-$(CONFIG_DATAFLASH_MMC_SELECT) += dataflash_mmc_mux.o
 obj-$(CONFIG_CMD_DATE) += date.o
 obj-$(CONFIG_CMD_DEMO) += demo.o
+obj-$(CONFIG_CMD_DM) += dm.o
 obj-$(CONFIG_CMD_SOUND) += sound.o
 ifdef CONFIG_POST
 obj-$(CONFIG_CMD_DIAG) += diag.o
diff --git a/cmd/cbfs.c b/cmd/cbfs.c
index ece790e..c118a95 100644
--- a/cmd/cbfs.c
+++ b/cmd/cbfs.c
@@ -112,12 +112,21 @@
 		printf(" %8d", file_cbfs_size(file));
 
 		switch (type) {
+		case CBFS_TYPE_BOOTBLOCK:
+			type_name = "bootblock";
+			break;
+		case CBFS_TYPE_CBFSHEADER:
+			type_name = "cbfs header";
+			break;
 		case CBFS_TYPE_STAGE:
 			type_name = "stage";
 			break;
 		case CBFS_TYPE_PAYLOAD:
 			type_name = "payload";
 			break;
+		case CBFS_TYPE_FIT:
+			type_name = "fit";
+			break;
 		case CBFS_TYPE_OPTIONROM:
 			type_name = "option rom";
 			break;
@@ -136,10 +145,31 @@
 		case CBFS_TYPE_MICROCODE:
 			type_name = "microcode";
 			break;
-		case CBFS_COMPONENT_CMOS_DEFAULT:
+		case CBFS_TYPE_FSP:
+			type_name = "fsp";
+			break;
+		case CBFS_TYPE_MRC:
+			type_name = "mrc";
+			break;
+		case CBFS_TYPE_MMA:
+			type_name = "mma";
+			break;
+		case CBFS_TYPE_EFI:
+			type_name = "efi";
+			break;
+		case CBFS_TYPE_STRUCT:
+			type_name = "struct";
+			break;
+		case CBFS_TYPE_CMOS_DEFAULT:
 			type_name = "cmos default";
 			break;
-		case CBFS_COMPONENT_CMOS_LAYOUT:
+		case CBFS_TYPE_SPD:
+			type_name = "spd";
+			break;
+		case CBFS_TYPE_MRC_CACHE:
+			type_name = "mrc cache";
+			break;
+		case CBFS_TYPE_CMOS_LAYOUT:
 			type_name = "cmos layout";
 			break;
 		case -1:
diff --git a/test/dm/cmd_dm.c b/cmd/dm.c
similarity index 100%
rename from test/dm/cmd_dm.c
rename to cmd/dm.c
diff --git a/cmd/sound.c b/cmd/sound.c
index d1cbc14..638f29d 100644
--- a/cmd/sound.c
+++ b/cmd/sound.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
 #include <fdtdec.h>
 #include <sound.h>
 
@@ -14,11 +15,14 @@
 /* Initilaise sound subsystem */
 static int do_init(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
+	struct udevice *dev;
 	int ret;
 
-	ret = sound_init(gd->fdt_blob);
+	ret = uclass_first_device_err(UCLASS_SOUND, &dev);
+	if (!ret)
+		ret = sound_setup(dev);
 	if (ret) {
-		printf("Initialise Audio driver failed\n");
+		printf("Initialise Audio driver failed (ret=%d)\n", ret);
 		return CMD_RET_FAILURE;
 	}
 
@@ -28,6 +32,7 @@
 /* play sound from buffer */
 static int do_play(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
+	struct udevice *dev;
 	int ret = 0;
 	int msec = 1000;
 	int freq = 400;
@@ -37,9 +42,11 @@
 	if (argc > 2)
 		freq = simple_strtoul(argv[2], NULL, 10);
 
-	ret = sound_play(msec, freq);
+	ret = uclass_first_device_err(UCLASS_SOUND, &dev);
+	if (!ret)
+		ret = sound_beep(dev, msec, freq);
 	if (ret) {
-		printf("play failed");
+		printf("Sound device failed to play (err=%d)\n", ret);
 		return CMD_RET_FAILURE;
 	}
 
diff --git a/common/Makefile b/common/Makefile
index 65d89dc..0de60b3 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -74,9 +74,12 @@
 obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
 obj-$(CONFIG_SPL_NET_SUPPORT) += miiphyutil.o
 obj-$(CONFIG_$(SPL_TPL_)OF_LIBFDT) += fdt_support.o
+
 ifdef CONFIG_SPL_USB_HOST_SUPPORT
 obj-$(CONFIG_SPL_USB_SUPPORT) += usb.o usb_hub.o
 obj-$(CONFIG_USB_STORAGE) += usb_storage.o
+else
+obj-$(CONFIG_USB_MUSB_HOST) += usb.o
 endif
 endif # CONFIG_SPL_BUILD
 
diff --git a/common/bootm_os.c b/common/bootm_os.c
index f302135..855c471 100644
--- a/common/bootm_os.c
+++ b/common/bootm_os.c
@@ -260,7 +260,7 @@
 #if defined(CONFIG_BOOTM_VXWORKS) && \
 	(defined(CONFIG_PPC) || defined(CONFIG_ARM))
 
-void do_bootvx_fdt(bootm_headers_t *images)
+static void do_bootvx_fdt(bootm_headers_t *images)
 {
 #if defined(CONFIG_OF_LIBFDT)
 	int ret;
@@ -317,8 +317,8 @@
 	puts("## vxWorks terminated\n");
 }
 
-static int do_bootm_vxworks(int flag, int argc, char * const argv[],
-			     bootm_headers_t *images)
+int do_bootm_vxworks(int flag, int argc, char * const argv[],
+		     bootm_headers_t *images)
 {
 	if (flag != BOOTM_STATE_OS_GO)
 		return 0;
@@ -482,7 +482,7 @@
 	[IH_OS_PLAN9] = do_bootm_plan9,
 #endif
 #if defined(CONFIG_BOOTM_VXWORKS) && \
-	(defined(CONFIG_PPC) || defined(CONFIG_ARM))
+	(defined(CONFIG_PPC) || defined(CONFIG_ARM) || defined(CONFIG_RISCV))
 	[IH_OS_VXWORKS] = do_bootm_vxworks,
 #endif
 #if defined(CONFIG_CMD_ELF)
diff --git a/common/spl/spl_net.c b/common/spl/spl_net.c
index b6967ff..c91ad2b 100644
--- a/common/spl/spl_net.c
+++ b/common/spl/spl_net.c
@@ -85,7 +85,9 @@
 			   struct spl_boot_device *bootdev)
 {
 	bootdev->boot_device_name = "usb_ether";
-
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+	usb_ether_init();
+#endif
 	return spl_net_load_image(spl_image, bootdev);
 }
 SPL_LOAD_IMAGE_METHOD("USB eth", 0, BOOT_DEVICE_USBETH, spl_net_load_image_usb);
diff --git a/configs/a25-ae350_32_defconfig b/configs/ae350_rv32_defconfig
similarity index 100%
rename from configs/a25-ae350_32_defconfig
rename to configs/ae350_rv32_defconfig
diff --git a/configs/ax25-ae350_64_defconfig b/configs/ae350_rv64_defconfig
similarity index 100%
rename from configs/ax25-ae350_64_defconfig
rename to configs/ae350_rv64_defconfig
diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig
index d625599..be04424 100644
--- a/configs/am335x_boneblack_vboot_defconfig
+++ b/configs/am335x_boneblack_vboot_defconfig
@@ -13,7 +13,11 @@
 CONFIG_ARCH_MISC_INIT=y
 CONFIG_SPL_MUSB_NEW_SUPPORT=y
 # CONFIG_SPL_NAND_SUPPORT is not set
+CONFIG_SPL_NET_SUPPORT=y
+CONFIG_SPL_NET_VCI_STRING="AM33xx U-Boot SPL"
 CONFIG_SPL_OS_BOOT=y
+CONFIG_SPL_USB_GADGET_SUPPORT=y
+CONFIG_SPL_USB_ETHER=y
 CONFIG_AUTOBOOT_KEYED=y
 CONFIG_AUTOBOOT_PROMPT="Press SPACE to abort autoboot in %d seconds\n"
 CONFIG_AUTOBOOT_DELAY_STR="d"
@@ -31,6 +35,7 @@
 CONFIG_DFU_RAM=y
 CONFIG_USB_FUNCTION_FASTBOOT=y
 CONFIG_DM_I2C=y
+CONFIG_MISC=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_SPI_FLASH=y
@@ -44,8 +49,13 @@
 CONFIG_TIMER=y
 CONFIG_OMAP_TIMER=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_SPL_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_SPL_DM_USB_GADGET=y
 CONFIG_USB_MUSB_HOST=y
 CONFIG_USB_MUSB_GADGET=y
+CONFIG_USB_MUSB_TI=y
 CONFIG_USB_MUSB_DSPS=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
diff --git a/configs/am43xx_evm_defconfig b/configs/am43xx_evm_defconfig
index 7601263..9bbda43 100644
--- a/configs/am43xx_evm_defconfig
+++ b/configs/am43xx_evm_defconfig
@@ -3,6 +3,7 @@
 CONFIG_TI_COMMON_CMD_OPTIONS=y
 CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_AM43XX=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
 CONFIG_SPL=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_SPL_LOAD_FIT=y
@@ -12,7 +13,11 @@
 # CONFIG_MISC_INIT_R is not set
 CONFIG_VERSION_VARIABLE=y
 CONFIG_SPL_MTD_SUPPORT=y
+CONFIG_SPL_NET_SUPPORT=y
+CONFIG_SPL_NET_VCI_STRING="AM43xx U-Boot SPL"
 CONFIG_SPL_OS_BOOT=y
+CONFIG_SPL_USB_GADGET_SUPPORT=y
+CONFIG_SPL_USB_ETHER=y
 CONFIG_CMD_SPL=y
 CONFIG_CMD_SPL_NAND_OFS=0x00100000
 CONFIG_CMD_SPL_WRITE_SIZE=0x40000
@@ -27,11 +32,16 @@
 CONFIG_OF_LIST="am437x-gp-evm am437x-sk-evm am43x-epos-evm am437x-idk-evm"
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
 CONFIG_DM=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
 # CONFIG_BLK is not set
 CONFIG_DFU_MMC=y
 CONFIG_DFU_RAM=y
 CONFIG_DFU_SF=y
 CONFIG_DM_GPIO=y
+CONFIG_MISC=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_NAND=y
@@ -40,17 +50,25 @@
 CONFIG_DRIVER_TI_CPSW=y
 CONFIG_PHY_GIGE=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_SPL_PHY=y
+CONFIG_OMAP_USB2_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SPI=y
 CONFIG_TI_QSPI=y
 CONFIG_TIMER=y
 CONFIG_OMAP_TIMER=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_SPL_DM_USB=y
+CONFIG_DM_USB_GADGET=y
+CONFIG_SPL_DM_USB_GADGET=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_DWC3=y
 CONFIG_USB_DWC3_GADGET=y
 CONFIG_USB_DWC3_OMAP=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_DWC3_PHY_OMAP=y
 CONFIG_OMAP_USB_PHY=y
 CONFIG_USB_STORAGE=y
@@ -59,3 +77,4 @@
 CONFIG_USB_GADGET_VENDOR_NUM=0x0403
 CONFIG_USB_GADGET_PRODUCT_NUM=0xbd00
 CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_USB_ETHER=y
diff --git a/configs/ci20_mmc_defconfig b/configs/ci20_mmc_defconfig
new file mode 100644
index 0000000..c1b1c3f
--- /dev/null
+++ b/configs/ci20_mmc_defconfig
@@ -0,0 +1,48 @@
+CONFIG_MIPS=y
+CONFIG_SPL_LDSCRIPT="arch/mips/mach-jz47xx/jz4780/u-boot-spl.lds"
+CONFIG_SYS_TEXT_BASE=0x80010000
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL=y
+CONFIG_ARCH_JZ47XX=y
+CONFIG_NR_DRAM_BANKS=1
+CONFIG_FIT=y
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS4,115200 rw rootwait root=/dev/mmcblk0p1"
+CONFIG_USE_BOOTCOMMAND=y
+CONFIG_BOOTCOMMAND="ext4load mmc 0:1 0x88000000 /boot/uImage; bootm 0x88000000"
+CONFIG_MISC_INIT_R=y
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_BOARD_EARLY_INIT_F=y
+# CONFIG_SPL_BANNER_PRINT is not set
+# CONFIG_TPL_BANNER_PRINT is not set
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_DM=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+# CONFIG_SPL_DOS_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="ci20"
+CONFIG_ENV_IS_IN_MMC=y
+# CONFIG_DM_WARN is not set
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_JZ4780_EFUSE=y
+CONFIG_MMC=y
+CONFIG_MMC_BROKEN_CD=y
+CONFIG_DM_MMC=y
+# CONFIG_MMC_HW_PARTITIONING is not set
+CONFIG_MMC_IO_VOLTAGE=y
+CONFIG_MMC_UHS_SUPPORT=y
+CONFIG_MMC_HS400_SUPPORT=y
+# CONFIG_MMC_VERBOSE is not set
+CONFIG_SPL_MMC_TINY=y
+CONFIG_JZ47XX_MMC=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_USE_TINY_PRINTF=y
+CONFIG_SPL_TINY_MEMSET=y
+CONFIG_LZO=y
diff --git a/configs/comtrend_ar5315u_ram_defconfig b/configs/comtrend_ar5315u_ram_defconfig
index d9ef52e..1b8e4e4 100644
--- a/configs/comtrend_ar5315u_ram_defconfig
+++ b/configs/comtrend_ar5315u_ram_defconfig
@@ -28,11 +28,14 @@
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="comtrend,ar-5315u"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_LED=y
 CONFIG_LED_BCM6328=y
@@ -41,6 +44,8 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6368_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6318_USBH_PHY=y
 CONFIG_BCM6328_POWER_DOMAIN=y
diff --git a/configs/comtrend_ar5387un_ram_defconfig b/configs/comtrend_ar5387un_ram_defconfig
index f129870..5ba401a 100644
--- a/configs/comtrend_ar5387un_ram_defconfig
+++ b/configs/comtrend_ar5387un_ram_defconfig
@@ -28,11 +28,14 @@
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="comtrend,ar-5387un"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_LED=y
 CONFIG_LED_BCM6328=y
@@ -41,6 +44,8 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_MACRONIX=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6368_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6368_USBH_PHY=y
 CONFIG_POWER_DOMAIN=y
diff --git a/configs/comtrend_ct5361_ram_defconfig b/configs/comtrend_ct5361_ram_defconfig
index 82f2070..6297e78 100644
--- a/configs/comtrend_ct5361_ram_defconfig
+++ b/configs/comtrend_ct5361_ram_defconfig
@@ -25,11 +25,14 @@
 CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="comtrend,ct-5361"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@
 CONFIG_CFI_FLASH=y
 CONFIG_SYS_FLASH_PROTECTION=y
 CONFIG_SYS_FLASH_CFI=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6348_USBH_PHY=y
 CONFIG_DM_RESET=y
diff --git a/configs/comtrend_vr3032u_ram_defconfig b/configs/comtrend_vr3032u_ram_defconfig
index 1689eec..47f5399 100644
--- a/configs/comtrend_vr3032u_ram_defconfig
+++ b/configs/comtrend_vr3032u_ram_defconfig
@@ -26,15 +26,20 @@
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="comtrend,vr-3032u"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_LED=y
 CONFIG_LED_BCM6328=y
 CONFIG_LED_BLINK=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6368_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6368_USBH_PHY=y
 CONFIG_POWER_DOMAIN=y
diff --git a/configs/comtrend_wap5813n_ram_defconfig b/configs/comtrend_wap5813n_ram_defconfig
index 987e4c3..fd5107b 100644
--- a/configs/comtrend_wap5813n_ram_defconfig
+++ b/configs/comtrend_wap5813n_ram_defconfig
@@ -25,11 +25,14 @@
 CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="comtrend,wap-5813n"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@
 CONFIG_CFI_FLASH=y
 CONFIG_SYS_FLASH_PROTECTION=y
 CONFIG_SYS_FLASH_CFI=y
+CONFIG_DM_ETH=y
+CONFIG_PHY_GIGE=y
+CONFIG_BCM6368_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6368_USBH_PHY=y
 CONFIG_DM_RESET=y
diff --git a/configs/db-88f6820-amc_defconfig b/configs/db-88f6820-amc_defconfig
index dd58198..9068a58 100644
--- a/configs/db-88f6820-amc_defconfig
+++ b/configs/db-88f6820-amc_defconfig
@@ -43,6 +43,9 @@
 CONFIG_DEFAULT_DEVICE_TREE="armada-385-amc"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_SPL_OF_TRANSLATE=y
+CONFIG_BLK=y
+# CONFIG_SPL_BLK is not set
+# CONFIG_BLOCK_CACHE is not set
 CONFIG_DM_I2C=y
 CONFIG_SYS_I2C_MVTWSI=y
 # CONFIG_MMC is not set
diff --git a/configs/edison_defconfig b/configs/edison_defconfig
index eb9f9a0..234dbac 100644
--- a/configs/edison_defconfig
+++ b/configs/edison_defconfig
@@ -18,7 +18,6 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_MMC=y
 CONFIG_CMD_PART=y
-# CONFIG_CMD_PCI is not set
 # CONFIG_CMD_NFS is not set
 CONFIG_CMD_TIMER=y
 CONFIG_CMD_HASH=y
diff --git a/configs/elgin-rv1108_defconfig b/configs/elgin-rv1108_defconfig
new file mode 100644
index 0000000..40fbd6b
--- /dev/null
+++ b/configs/elgin-rv1108_defconfig
@@ -0,0 +1,58 @@
+CONFIG_ARM=y
+CONFIG_ARCH_ROCKCHIP=y
+CONFIG_SYS_TEXT_BASE=0x60000000
+CONFIG_ROCKCHIP_RV1108=y
+CONFIG_TARGET_ELGIN_RV1108=y
+CONFIG_DEBUG_UART_BASE=0x10210000
+CONFIG_DEBUG_UART_CLOCK=24000000
+CONFIG_DEBUG_UART=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_USE_BOOTCOMMAND is not set
+CONFIG_DEFAULT_FDT_FILE="rv1108-elgin-r1.dtb"
+# CONFIG_DISPLAY_CPUINFO is not set
+CONFIG_DISPLAY_BOARDINFO_LATE=y
+CONFIG_CMD_GPIO=y
+CONFIG_RANDOM_UUID=y
+CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
+# CONFIG_CMD_SETEXPR is not set
+CONFIG_CMD_CACHE=y
+CONFIG_CMD_TIME=y
+CONFIG_DEFAULT_DEVICE_TREE="rv1108-elgin-r1"
+CONFIG_ENV_IS_IN_MMC=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_CLK=y
+CONFIG_FASTBOOT_BUF_ADDR=0x62000000
+CONFIG_FASTBOOT_BUF_SIZE=0x08000000
+CONFIG_FASTBOOT_FLASH=y
+CONFIG_FASTBOOT_FLASH_MMC_DEV=0
+CONFIG_ROCKCHIP_GPIO=y
+CONFIG_SYS_I2C_ROCKCHIP=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_ROCKCHIP=y
+CONFIG_DM_ETH=y
+CONFIG_ETH_DESIGNWARE=y
+CONFIG_GMAC_ROCKCHIP=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_ROCKCHIP_RV1108=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_BAUDRATE=1500000
+# CONFIG_SPL_SERIAL_PRESENT is not set
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SYSRESET=y
+CONFIG_USB=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_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="Rockchip"
+CONFIG_USB_GADGET_VENDOR_NUM=0x2207
+CONFIG_USB_GADGET_PRODUCT_NUM=0x110a
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_ERRNO_STR=y
diff --git a/configs/gardena-smart-gateway-mt7688-ram_defconfig b/configs/gardena-smart-gateway-mt7688-ram_defconfig
index 05e7cf9..ae8bf29 100644
--- a/configs/gardena-smart-gateway-mt7688-ram_defconfig
+++ b/configs/gardena-smart-gateway-mt7688-ram_defconfig
@@ -36,7 +36,6 @@
 CONFIG_MTDIDS_DEFAULT="spi-nand0=gd5f,nor0=spi0.0"
 CONFIG_MTDPARTS_DEFAULT="spi0.0:640k(uboot),64k(uboot_env0),64k(uboot_env1),64k(factory),-(unused);gd5f:-(nand)"
 CONFIG_CMD_UBI=y
-CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/gardena-smart-gateway-mt7688_defconfig b/configs/gardena-smart-gateway-mt7688_defconfig
index a08d1db..b7024e3 100644
--- a/configs/gardena-smart-gateway-mt7688_defconfig
+++ b/configs/gardena-smart-gateway-mt7688_defconfig
@@ -39,7 +39,6 @@
 CONFIG_MTDIDS_DEFAULT="spi-nand0=gd5f,nor0=spi0.0"
 CONFIG_MTDPARTS_DEFAULT="spi0.0:640k(uboot),64k(uboot_env0),64k(uboot_env1),64k(factory),-(unused);gd5f:-(nand)"
 CONFIG_CMD_UBI=y
-CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/huawei_hg556a_ram_defconfig b/configs/huawei_hg556a_ram_defconfig
index 6bb14ba..d4e6144 100644
--- a/configs/huawei_hg556a_ram_defconfig
+++ b/configs/huawei_hg556a_ram_defconfig
@@ -25,11 +25,14 @@
 CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="huawei,hg556a"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@
 CONFIG_CFI_FLASH=y
 CONFIG_SYS_FLASH_PROTECTION=y
 CONFIG_SYS_FLASH_CFI=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
diff --git a/configs/k2e_evm_defconfig b/configs/k2e_evm_defconfig
index 67b1f30..03a1ceb 100644
--- a/configs/k2e_evm_defconfig
+++ b/configs/k2e_evm_defconfig
@@ -37,6 +37,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -47,13 +48,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/k2e_hs_evm_defconfig b/configs/k2e_hs_evm_defconfig
index 1abda84..bb7b314 100644
--- a/configs/k2e_hs_evm_defconfig
+++ b/configs/k2e_hs_evm_defconfig
@@ -30,6 +30,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -40,13 +41,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/k2g_evm_defconfig b/configs/k2g_evm_defconfig
index bc4b92b..8a07039 100644
--- a/configs/k2g_evm_defconfig
+++ b/configs/k2g_evm_defconfig
@@ -35,7 +35,9 @@
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
 CONFIG_DM=y
 # CONFIG_BLK is not set
+CONFIG_DFU_MMC=y
 CONFIG_SYS_I2C_DAVINCI=y
+CONFIG_MISC=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_NAND=y
@@ -50,6 +52,8 @@
 CONFIG_PHY_MICREL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
 CONFIG_REMOTEPROC_TI_POWER=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
@@ -57,7 +61,15 @@
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_USB_FUNCTION_SDP=y
diff --git a/configs/k2g_hs_evm_defconfig b/configs/k2g_hs_evm_defconfig
index 66d8220..5f91f11 100644
--- a/configs/k2g_hs_evm_defconfig
+++ b/configs/k2g_hs_evm_defconfig
@@ -28,7 +28,9 @@
 CONFIG_ENV_VARS_UBOOT_RUNTIME_CONFIG=y
 CONFIG_DM=y
 # CONFIG_BLK is not set
+CONFIG_DFU_MMC=y
 CONFIG_SYS_I2C_DAVINCI=y
+CONFIG_MISC=y
 CONFIG_DM_MMC=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_NAND=y
@@ -43,6 +45,8 @@
 CONFIG_PHY_MICREL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
 CONFIG_REMOTEPROC_TI_POWER=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
@@ -50,7 +54,15 @@
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_DM_USB_GADGET=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GADGET=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DOWNLOAD=y
+CONFIG_USB_FUNCTION_SDP=y
diff --git a/configs/k2hk_evm_defconfig b/configs/k2hk_evm_defconfig
index f66d922..700fafd 100644
--- a/configs/k2hk_evm_defconfig
+++ b/configs/k2hk_evm_defconfig
@@ -37,6 +37,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -47,13 +48,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/k2hk_hs_evm_defconfig b/configs/k2hk_hs_evm_defconfig
index dd91a51..a6caccc 100644
--- a/configs/k2hk_hs_evm_defconfig
+++ b/configs/k2hk_hs_evm_defconfig
@@ -30,6 +30,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -40,13 +41,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/k2l_evm_defconfig b/configs/k2l_evm_defconfig
index 4f04caa..cb63808 100644
--- a/configs/k2l_evm_defconfig
+++ b/configs/k2l_evm_defconfig
@@ -37,6 +37,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -47,13 +48,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/k2l_hs_evm_defconfig b/configs/k2l_hs_evm_defconfig
index 9ce23de..4ce7801 100644
--- a/configs/k2l_hs_evm_defconfig
+++ b/configs/k2l_hs_evm_defconfig
@@ -29,6 +29,7 @@
 CONFIG_DM=y
 CONFIG_SYS_I2C_DAVINCI=y
 CONFIG_TI_AEMIF=y
+CONFIG_MISC=y
 # CONFIG_MMC is not set
 CONFIG_NAND=y
 CONFIG_NAND_DAVINCI=y
@@ -39,13 +40,19 @@
 CONFIG_PHY_MARVELL=y
 CONFIG_DM_ETH=y
 CONFIG_MII=y
+CONFIG_PHY=y
+CONFIG_NOP_PHY=y
+CONFIG_KEYSTONE_USB_PHY=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
 CONFIG_DAVINCI_SPI=y
 CONFIG_USB=y
+CONFIG_DM_USB=y
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
+CONFIG_USB_DWC3=y
+CONFIG_USB_DWC3_GENERIC=y
 CONFIG_USB_STORAGE=y
 CONFIG_DRIVER_TI_KEYSTONE_NET=y
diff --git a/configs/linkit-smart-7688-ram_defconfig b/configs/linkit-smart-7688-ram_defconfig
index 2d20e9e..2d3ab7e 100644
--- a/configs/linkit-smart-7688-ram_defconfig
+++ b/configs/linkit-smart-7688-ram_defconfig
@@ -26,7 +26,6 @@
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
-CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/linkit-smart-7688_defconfig b/configs/linkit-smart-7688_defconfig
index 5add29f..ad34aaf 100644
--- a/configs/linkit-smart-7688_defconfig
+++ b/configs/linkit-smart-7688_defconfig
@@ -30,7 +30,6 @@
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
 CONFIG_CMD_TIME=y
-CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
 CONFIG_NET_RANDOM_ETHADDR=y
diff --git a/configs/mscc_luton_defconfig b/configs/mscc_luton_defconfig
new file mode 100644
index 0000000..d7476c4
--- /dev/null
+++ b/configs/mscc_luton_defconfig
@@ -0,0 +1,64 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x40000000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0x70100000
+CONFIG_DEBUG_UART_CLOCK=208333333
+CONFIG_ARCH_MSCC=y
+CONFIG_TARGET_LUTON_PCB091=y
+CONFIG_DDRTYPE_MT47H128M8HQ=y
+CONFIG_SYS_LITTLE_ENDIAN=y
+CONFIG_MIPS_BOOT_FDT=y
+CONFIG_DEBUG_UART=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200"
+CONFIG_LOGLEVEL=7
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_SYS_PROMPT="pcb091 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MEMTEST=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_DHCP=y
+# CONFIG_NET_TFTP_VARS is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:512k(UBoot),256k(Env),256k(conf),6m@1m(linux)"
+# CONFIG_ISO_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="luton_pcb091"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=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_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_SOFT_SPI=y
+CONFIG_LZMA=y
diff --git a/configs/mscc_ocelot_defconfig b/configs/mscc_ocelot_defconfig
new file mode 100644
index 0000000..5fa74db
--- /dev/null
+++ b/configs/mscc_ocelot_defconfig
@@ -0,0 +1,67 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x40000000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0x70100000
+CONFIG_DEBUG_UART_CLOCK=250000000
+CONFIG_ARCH_MSCC=y
+CONFIG_TARGET_OCELOT_PCB123=y
+CONFIG_SYS_LITTLE_ENDIAN=y
+CONFIG_DEBUG_UART=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200"
+CONFIG_LOGLEVEL=7
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_SYS_PROMPT="pcb123 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MEMTEST=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_DHCP=y
+# CONFIG_NET_TFTP_VARS is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:512k(UBoot),256k(Env),256k(conf),15m(linux),15m(linux.bk)"
+CONFIG_CMD_UBI=y
+# CONFIG_CMD_UBIFS is not set
+# CONFIG_ISO_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="ocelot_pcb123"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_DEBUG_UART_ANNOUNCE=y
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_DESIGNWARE_SPI=y
+CONFIG_LZMA=y
diff --git a/configs/mscc_ocelot_pcb120_defconfig b/configs/mscc_ocelot_pcb120_defconfig
new file mode 100644
index 0000000..c5a9f96
--- /dev/null
+++ b/configs/mscc_ocelot_pcb120_defconfig
@@ -0,0 +1,60 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x40000000
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_ARCH_MSCC=y
+CONFIG_SYS_LITTLE_ENDIAN=y
+CONFIG_FIT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200"
+CONFIG_LOGLEVEL=7
+CONFIG_DISPLAY_CPUINFO=y
+CONFIG_SYS_PROMPT="pcb120 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_MEMTEST=y
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_MTD=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_DHCP=y
+# CONFIG_NET_TFTP_VARS is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_CMD_PING=y
+CONFIG_CMD_MTDPARTS=y
+CONFIG_MTDIDS_DEFAULT="nor0=spi_flash"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi_flash:512k(UBoot),256k(Env),256k(conf),15m(linux),15m(linux.bk)"
+CONFIG_CMD_UBI=y
+# CONFIG_CMD_UBIFS is not set
+# CONFIG_ISO_PARTITION is not set
+CONFIG_DEFAULT_DEVICE_TREE="ocelot_pcb120"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_MTD=y
+CONFIG_MTD_SPI_NAND=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_DM_ETH=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_DM_SERIAL=y
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_DESIGNWARE_SPI=y
+CONFIG_LZMA=y
diff --git a/configs/netgear_dgnd3700v2_ram_defconfig b/configs/netgear_dgnd3700v2_ram_defconfig
index 1abc869..0f3914f 100644
--- a/configs/netgear_dgnd3700v2_ram_defconfig
+++ b/configs/netgear_dgnd3700v2_ram_defconfig
@@ -27,17 +27,23 @@
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
-# CONFIG_CMD_NET is not set
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="netgear,dgnd3700v2"
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
 CONFIG_LED_BCM6328=y
 CONFIG_LED_BLINK=y
 CONFIG_LED_GPIO=y
+CONFIG_DM_ETH=y
+CONFIG_PHY_GIGE=y
+CONFIG_BCM6368_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6368_USBH_PHY=y
 CONFIG_POWER_DOMAIN=y
diff --git a/configs/peach-pi_defconfig b/configs/peach-pi_defconfig
index 338eae2..14c835c 100644
--- a/configs/peach-pi_defconfig
+++ b/configs/peach-pi_defconfig
@@ -21,6 +21,7 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_TPM=y
@@ -28,7 +29,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5800-peach-pi"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
@@ -52,6 +52,7 @@
 CONFIG_SOUND=y
 CONFIG_I2S=y
 CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98090=y
 CONFIG_SOUND_MAX98095=y
 CONFIG_SOUND_WM8994=y
 CONFIG_EXYNOS_SPI=y
diff --git a/configs/peach-pit_defconfig b/configs/peach-pit_defconfig
index 933c823..9a3a115 100644
--- a/configs/peach-pit_defconfig
+++ b/configs/peach-pit_defconfig
@@ -20,6 +20,7 @@
 # CONFIG_CMD_SETEXPR is not set
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_TIME=y
+CONFIG_CMD_SOUND=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_TPM=y
@@ -27,7 +28,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5420-peach-pit"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_TUNNEL=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
@@ -51,6 +51,7 @@
 CONFIG_SOUND=y
 CONFIG_I2S=y
 CONFIG_I2S_SAMSUNG=y
+CONFIG_SOUND_MAX98090=y
 CONFIG_SOUND_MAX98095=y
 CONFIG_SOUND_WM8994=y
 CONFIG_EXYNOS_SPI=y
diff --git a/configs/sagem_f@st1704_ram_defconfig b/configs/sagem_f@st1704_ram_defconfig
index 91a9663..8c36f5d 100644
--- a/configs/sagem_f@st1704_ram_defconfig
+++ b/configs/sagem_f@st1704_ram_defconfig
@@ -27,11 +27,14 @@
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_SF=y
 CONFIG_CMD_SPI=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="sagem,f@st1704"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -40,6 +43,9 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_DM_RESET=y
 CONFIG_RESET_BCM6345=y
 # CONFIG_SPL_SERIAL_PRESENT is not set
diff --git a/configs/sandbox64_defconfig b/configs/sandbox64_defconfig
index e6680d9..aede145 100644
--- a/configs/sandbox64_defconfig
+++ b/configs/sandbox64_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_SANDBOX64=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 5b65c61..1e7d41d 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DEBUG_UART=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
diff --git a/configs/sandbox_flattree_defconfig b/configs/sandbox_flattree_defconfig
index 756b839..4f3757c 100644
--- a/configs/sandbox_flattree_defconfig
+++ b/configs/sandbox_flattree_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_FIT=y
diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig
index e71e2d3..6c7d08e 100644
--- a/configs/sandbox_noblk_defconfig
+++ b/configs/sandbox_noblk_defconfig
@@ -1,5 +1,4 @@
 CONFIG_SYS_TEXT_BASE=0
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_NR_DRAM_BANKS=1
 CONFIG_FIT=y
diff --git a/configs/sandbox_spl_defconfig b/configs/sandbox_spl_defconfig
index 452a2ef..2f83812 100644
--- a/configs/sandbox_spl_defconfig
+++ b/configs/sandbox_spl_defconfig
@@ -1,7 +1,6 @@
 CONFIG_SYS_TEXT_BASE=0
 CONFIG_SPL_LIBCOMMON_SUPPORT=y
 CONFIG_SPL_LIBGENERIC_SUPPORT=y
-CONFIG_SYS_MALLOC_F_LEN=0x2000
 CONFIG_SPL_SERIAL_SUPPORT=y
 CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
 CONFIG_SPL=y
diff --git a/configs/sfr_nb4-ser_ram_defconfig b/configs/sfr_nb4-ser_ram_defconfig
index 12adfb0..3962287 100644
--- a/configs/sfr_nb4-ser_ram_defconfig
+++ b/configs/sfr_nb4-ser_ram_defconfig
@@ -26,11 +26,14 @@
 CONFIG_CMD_MEMINFO=y
 # CONFIG_CMD_LOADS is not set
 CONFIG_CMD_USB=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
 # CONFIG_CMD_MISC is not set
 CONFIG_OF_EMBED=y
 CONFIG_DEFAULT_DEVICE_TREE="sfr,nb4-ser"
-# CONFIG_NET is not set
+CONFIG_NET_RANDOM_ETHADDR=y
 # CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_BCM6348_IUDMA=y
 CONFIG_DM_GPIO=y
 CONFIG_BCM6345_GPIO=y
 CONFIG_LED=y
@@ -42,6 +45,9 @@
 CONFIG_CFI_FLASH=y
 CONFIG_SYS_FLASH_PROTECTION=y
 CONFIG_SYS_FLASH_CFI=y
+CONFIG_PHY_FIXED=y
+CONFIG_DM_ETH=y
+CONFIG_BCM6348_ETH=y
 CONFIG_PHY=y
 CONFIG_BCM6358_USBH_PHY=y
 CONFIG_DM_RESET=y
diff --git a/configs/smdk5250_defconfig b/configs/smdk5250_defconfig
index 161454b..21018d8 100644
--- a/configs/smdk5250_defconfig
+++ b/configs/smdk5250_defconfig
@@ -30,7 +30,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-smdk5250"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_S5P=y
diff --git a/configs/smdk5420_defconfig b/configs/smdk5420_defconfig
index 433e9a8..4e45589 100644
--- a/configs/smdk5420_defconfig
+++ b/configs/smdk5420_defconfig
@@ -25,7 +25,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5420-smdk5420"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_MMC_DW=y
 CONFIG_MMC_SDHCI=y
 CONFIG_MMC_SDHCI_S5P=y
diff --git a/configs/snow_defconfig b/configs/snow_defconfig
index 2108009..e0c1bf8 100644
--- a/configs/snow_defconfig
+++ b/configs/snow_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-snow"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
diff --git a/configs/spring_defconfig b/configs/spring_defconfig
index ca17998..c089517 100644
--- a/configs/spring_defconfig
+++ b/configs/spring_defconfig
@@ -34,7 +34,6 @@
 CONFIG_CMD_EXT4_WRITE=y
 CONFIG_DEFAULT_DEVICE_TREE="exynos5250-spring"
 CONFIG_ENV_IS_IN_SPI_FLASH=y
-CONFIG_DM_I2C_COMPAT=y
 CONFIG_I2C_CROS_EC_LDO=y
 CONFIG_I2C_MUX=y
 CONFIG_I2C_ARB_GPIO_CHALLENGE=y
diff --git a/configs/tools-only_defconfig b/configs/tools-only_defconfig
new file mode 100644
index 0000000..fb06076
--- /dev/null
+++ b/configs/tools-only_defconfig
@@ -0,0 +1,24 @@
+CONFIG_SYS_TEXT_BASE=0
+CONFIG_ANDROID_BOOT_IMAGE=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_BOOTM is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_DATE is not set
+CONFIG_OF_CONTROL=y
+CONFIG_OF_HOSTFILE=y
+CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+# CONFIG_UDP_FUNCTION_FASTBOOT is not set
+CONFIG_SANDBOX_GPIO=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_PCI=y
+CONFIG_DM_PCI=y
+CONFIG_PCI_SANDBOX=y
+CONFIG_DM_RTC=y
+CONFIG_SOUND=y
+CONFIG_SYSRESET=y
+# CONFIG_VIRTIO_MMIO is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_SANDBOX is not set
+# CONFIG_EFI_LOADER is not set
diff --git a/configs/uniphier_ld4_sld8_defconfig b/configs/uniphier_ld4_sld8_defconfig
index 6b9e22a..98a0017 100644
--- a/configs/uniphier_ld4_sld8_defconfig
+++ b/configs/uniphier_ld4_sld8_defconfig
@@ -9,6 +9,7 @@
 CONFIG_MICRO_SUPPORT_CARD=y
 CONFIG_NR_DRAM_BANKS=3
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_BOOTCOMMAND="run ${bootdev}script; run ${bootdev}boot"
 CONFIG_LOGLEVEL=6
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_SPL_NOR_SUPPORT=y
diff --git a/configs/uniphier_v7_defconfig b/configs/uniphier_v7_defconfig
index 4c06f27..bba8e18 100644
--- a/configs/uniphier_v7_defconfig
+++ b/configs/uniphier_v7_defconfig
@@ -8,6 +8,7 @@
 CONFIG_MICRO_SUPPORT_CARD=y
 CONFIG_NR_DRAM_BANKS=3
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_BOOTCOMMAND="run ${bootdev}script; run ${bootdev}boot"
 CONFIG_LOGLEVEL=6
 CONFIG_SPL_NAND_SUPPORT=y
 CONFIG_SPL_NOR_SUPPORT=y
diff --git a/configs/uniphier_v8_defconfig b/configs/uniphier_v8_defconfig
index f8f9bdf..df6c511 100644
--- a/configs/uniphier_v8_defconfig
+++ b/configs/uniphier_v8_defconfig
@@ -7,6 +7,7 @@
 CONFIG_MICRO_SUPPORT_CARD=y
 CONFIG_NR_DRAM_BANKS=3
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
+CONFIG_BOOTCOMMAND="run ${bootdev}script; run ${bootdev}boot"
 CONFIG_LOGLEVEL=6
 CONFIG_CMD_CONFIG=y
 CONFIG_CMD_IMLS=y
diff --git a/doc/README.ae350 b/doc/README.ae350
index fe75b80..189a6b7 100644
--- a/doc/README.ae350
+++ b/doc/README.ae350
@@ -25,7 +25,7 @@
 
 build:
 1. Prepare the toolchains and make sure the $PATH to toolchains is correct.
-2. Use `make ax25-ae350_defconfig` in u-boot root to build the image.
+2. Use `make ae350_rv[32|64]_defconfig` in u-boot root to build the image for 32 or 64 bit.
 
 Verification
 ====================
diff --git a/doc/README.commands b/doc/README.commands
index 1d29c4d..0ccadae 100644
--- a/doc/README.commands
+++ b/doc/README.commands
@@ -28,6 +28,42 @@
 		entering the command arguments to complete the entry. Command
 		completion is only available if CONFIG_AUTO_COMPLETE is defined.
 
+Sub-command definition
+----------------------
+
+Likewise an array of cmd_tbl_t holding sub-commands can be created using either
+of the following macros:
+
+* U_BOOT_CMD_MKENT(name, maxargs, repeatable, command, "usage", "help")
+* U_BOOT_CMD_MKENTCOMPLETE(name, maxargs, repeatable, command, "usage, "help",
+  comp)
+
+This table has to be evaluated in the command function of the main command, e.g.
+
+    static cmd_tbl_t cmd_sub[] = {
+        U_BOOT_CMD_MKENT(foo, CONFIG_SYS_MAXARGS, 1, do_foo, "", ""),
+        U_BOOT_CMD_MKENT(bar, CONFIG_SYS_MAXARGS, 1, do_bar, "", ""),
+    };
+
+    static int do_cmd(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+    {
+        cmd_tbl_t *cp;
+
+        if (argc < 2)
+                return CMD_RET_USAGE;
+
+        /* drop sub-command argument */
+        argc--;
+        argv++;
+
+        cp = find_cmd_tbl(argv[0], cmd_ut_sub, ARRAY_SIZE(cmd_sub));
+
+        if (cp)
+            return cp->cmd(cmdtp, flag, argc, argv);
+
+        return CMD_RET_USAGE;
+    }
+
 Command function
 ----------------
 
diff --git a/drivers/Makefile b/drivers/Makefile
index c3c0615..8c53e05 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -48,6 +48,7 @@
 obj-$(CONFIG_SPL_USB_ETHER) += net/phy/
 obj-$(CONFIG_SPL_MUSB_NEW_SUPPORT) += usb/musb-new/
 obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += usb/gadget/
+obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += usb/common/
 obj-$(CONFIG_SPL_USB_GADGET_SUPPORT) += usb/gadget/udc/
 obj-$(CONFIG_SPL_DFU_SUPPORT) += dfu/
 obj-$(CONFIG_SPL_WATCHDOG_SUPPORT) += watchdog/
diff --git a/drivers/clk/uniphier/clk-uniphier-sys.c b/drivers/clk/uniphier/clk-uniphier-sys.c
index 9e087b6..487b43e 100644
--- a/drivers/clk/uniphier/clk-uniphier-sys.c
+++ b/drivers/clk/uniphier/clk-uniphier-sys.c
@@ -6,13 +6,12 @@
 
 #include "clk-uniphier.h"
 
-/* Denali driver requires clk_x rate (clk: 50MHz, clk_x & ecc_clk: 200MHz) */
 #define UNIPHIER_LD4_SYS_CLK_NAND(_id)					\
-	UNIPHIER_CLK_RATE(128, 200000000),				\
+	UNIPHIER_CLK_RATE(128, 50000000),				\
 	UNIPHIER_CLK_GATE((_id), 128, 0x2104, 2)
 
 #define UNIPHIER_LD11_SYS_CLK_NAND(_id)					\
-	UNIPHIER_CLK_RATE(128, 200000000),				\
+	UNIPHIER_CLK_RATE(128, 50000000),				\
 	UNIPHIER_CLK_GATE((_id), 128, 0x210c, 0)
 
 const struct uniphier_clk_data uniphier_pxs2_sys_clk_data[] = {
@@ -20,6 +19,7 @@
     defined(CONFIG_ARCH_UNIPHIER_PRO4) || defined(CONFIG_ARCH_UNIPHIER_PRO5) ||\
     defined(CONFIG_ARCH_UNIPHIER_PXS2) || defined(CONFIG_ARCH_UNIPHIER_LD6B)
 	UNIPHIER_LD4_SYS_CLK_NAND(2),
+	UNIPHIER_CLK_RATE(3, 200000000),
 	UNIPHIER_CLK_GATE_SIMPLE(6, 0x2104, 12),	/* ether (Pro4, PXs2) */
 	UNIPHIER_CLK_GATE_SIMPLE(7, 0x2104, 5),		/* ether-gb (Pro4) */
 	UNIPHIER_CLK_GATE_SIMPLE(8, 0x2104, 10),	/* stdmac */
@@ -36,6 +36,7 @@
 const struct uniphier_clk_data uniphier_ld20_sys_clk_data[] = {
 #if defined(CONFIG_ARCH_UNIPHIER_LD11) || defined(CONFIG_ARCH_UNIPHIER_LD20)
 	UNIPHIER_LD11_SYS_CLK_NAND(2),
+	UNIPHIER_CLK_RATE(3, 200000000),
 	UNIPHIER_CLK_GATE_SIMPLE(6, 0x210c, 6),		/* ether */
 	UNIPHIER_CLK_GATE_SIMPLE(8, 0x210c, 8),		/* stdmac */
 	UNIPHIER_CLK_GATE_SIMPLE(14, 0x210c, 14),	/* usb30 (LD20) */
@@ -48,6 +49,7 @@
 const struct uniphier_clk_data uniphier_pxs3_sys_clk_data[] = {
 #if defined(CONFIG_ARCH_UNIPHIER_PXS3)
 	UNIPHIER_LD11_SYS_CLK_NAND(2),
+	UNIPHIER_CLK_RATE(3, 200000000),
 	UNIPHIER_CLK_GATE_SIMPLE(6, 0x210c, 9),		/* ether0 */
 	UNIPHIER_CLK_GATE_SIMPLE(7, 0x210c, 10),	/* ether1 */
 	UNIPHIER_CLK_GATE_SIMPLE(12, 0x210c, 4),	/* usb30 (gio0) */
diff --git a/drivers/core/read.c b/drivers/core/read.c
index cdd78be..3c46b36 100644
--- a/drivers/core/read.c
+++ b/drivers/core/read.c
@@ -21,6 +21,29 @@
 	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
 }
 
+int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp)
+{
+	return ofnode_read_u32(dev_ofnode(dev), propname, (u32 *)outp);
+}
+
+int dev_read_s32_default(struct udevice *dev, const char *propname, int def)
+{
+	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
+}
+
+int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp)
+{
+	u32 val;
+	int ret;
+
+	ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+	if (ret)
+		return ret;
+	*outp = val;
+
+	return 0;
+}
+
 const char *dev_read_string(struct udevice *dev, const char *propname)
 {
 	return ofnode_read_string(dev_ofnode(dev), propname);
diff --git a/drivers/core/syscon-uclass.c b/drivers/core/syscon-uclass.c
index 661cf61..3cf9dd9 100644
--- a/drivers/core/syscon-uclass.c
+++ b/drivers/core/syscon-uclass.c
@@ -146,52 +146,31 @@
  * The syscon node can be bound to another driver, but still works
  * as a syscon provider.
  */
-static LIST_HEAD(syscon_list);
-
-struct syscon {
-	ofnode node;
-	struct regmap *regmap;
-	struct list_head list;
-};
-
-static struct syscon *of_syscon_register(ofnode node)
+struct regmap *syscon_node_to_regmap(ofnode node)
 {
-	struct syscon *syscon;
+	struct udevice *dev, *parent;
 	int ret;
 
+	if (!uclass_get_device_by_ofnode(UCLASS_SYSCON, node, &dev))
+		return syscon_get_regmap(dev);
+
 	if (!ofnode_device_is_compatible(node, "syscon"))
 		return ERR_PTR(-EINVAL);
 
-	syscon = malloc(sizeof(*syscon));
-	if (!syscon)
-		return ERR_PTR(-ENOMEM);
+	/* bound to driver with same ofnode or to root if not found */
+	if (device_find_global_by_ofnode(node, &parent))
+		parent = dm_root();
 
-	ret = regmap_init_mem(node, &syscon->regmap);
-	if (ret) {
-		free(syscon);
+	/* force bound to syscon class */
+	ret = device_bind_driver_to_node(parent, "syscon",
+					 ofnode_get_name(node),
+					 node, &dev);
+	if (ret)
 		return ERR_PTR(ret);
-	}
 
-	list_add_tail(&syscon->list, &syscon_list);
+	ret = device_probe(dev);
+	if (ret)
+		return ERR_PTR(ret);
 
-	return syscon;
-}
-
-struct regmap *syscon_node_to_regmap(ofnode node)
-{
-	struct syscon *entry, *syscon = NULL;
-
-	list_for_each_entry(entry, &syscon_list, list)
-		if (ofnode_equal(entry->node, node)) {
-			syscon = entry;
-			break;
-		}
-
-	if (!syscon)
-		syscon = of_syscon_register(node);
-
-	if (IS_ERR(syscon))
-		return ERR_CAST(syscon);
-
-	return syscon->regmap;
+	return syscon_get_regmap(dev);
 }
diff --git a/drivers/cpu/Kconfig b/drivers/cpu/Kconfig
index d405200..3d5729f 100644
--- a/drivers/cpu/Kconfig
+++ b/drivers/cpu/Kconfig
@@ -13,3 +13,9 @@
 	select CLK_MPC83XX
 	help
 	  Support CPU cores for SoCs of the MPC83xx series.
+
+config CPU_RISCV
+	bool "Enable RISC-V CPU driver"
+	depends on CPU && RISCV
+	help
+	  Support CPU cores for RISC-V architecture.
diff --git a/drivers/cpu/Makefile b/drivers/cpu/Makefile
index 858b037..be0300c 100644
--- a/drivers/cpu/Makefile
+++ b/drivers/cpu/Makefile
@@ -8,4 +8,5 @@
 
 obj-$(CONFIG_ARCH_BMIPS) += bmips_cpu.o
 obj-$(CONFIG_CPU_MPC83XX) += mpc83xx_cpu.o
+obj-$(CONFIG_CPU_RISCV) += riscv_cpu.o
 obj-$(CONFIG_SANDBOX) += cpu_sandbox.o
diff --git a/drivers/cpu/riscv_cpu.c b/drivers/cpu/riscv_cpu.c
new file mode 100644
index 0000000..5e15df5
--- /dev/null
+++ b/drivers/cpu/riscv_cpu.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ */
+
+#include <common.h>
+#include <cpu.h>
+#include <dm.h>
+#include <errno.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+static int riscv_cpu_get_desc(struct udevice *dev, char *buf, int size)
+{
+	const char *isa;
+
+	isa = dev_read_string(dev, "riscv,isa");
+	if (size < (strlen(isa) + 1))
+		return -ENOSPC;
+
+	strcpy(buf, isa);
+
+	return 0;
+}
+
+static int riscv_cpu_get_info(struct udevice *dev, struct cpu_info *info)
+{
+	const char *mmu;
+
+	dev_read_u32(dev, "clock-frequency", (u32 *)&info->cpu_freq);
+
+	mmu = dev_read_string(dev, "mmu-type");
+	if (!mmu)
+		info->features |= BIT(CPU_FEAT_MMU);
+
+	return 0;
+}
+
+static int riscv_cpu_get_count(struct udevice *dev)
+{
+	ofnode node;
+	int num = 0;
+
+	ofnode_for_each_subnode(node, dev_ofnode(dev->parent)) {
+		const char *device_type;
+
+		device_type = ofnode_read_string(node, "device_type");
+		if (!device_type)
+			continue;
+		if (strcmp(device_type, "cpu") == 0)
+			num++;
+	}
+
+	return num;
+}
+
+static int riscv_cpu_bind(struct udevice *dev)
+{
+	struct cpu_platdata *plat = dev_get_parent_platdata(dev);
+	struct driver *drv;
+	int ret;
+
+	/* save the hart id */
+	plat->cpu_id = dev_read_addr(dev);
+
+	/* first examine the property in current cpu node */
+	ret = dev_read_u32(dev, "timebase-frequency", &plat->timebase_freq);
+	/* if not found, then look at the parent /cpus node */
+	if (ret)
+		dev_read_u32(dev->parent, "timebase-frequency",
+			     &plat->timebase_freq);
+
+	/*
+	 * Bind riscv-timer driver on hart 0
+	 *
+	 * We only instantiate one timer device which is enough for U-Boot.
+	 * Pass the "timebase-frequency" value as the driver data for the
+	 * timer device.
+	 *
+	 * Return value is not checked since it's possible that the timer
+	 * driver is not included.
+	 */
+	if (!plat->cpu_id && plat->timebase_freq) {
+		drv = lists_driver_lookup_name("riscv_timer");
+		if (!drv) {
+			debug("Cannot find the timer driver, not included?\n");
+			return 0;
+		}
+
+		device_bind_with_driver_data(dev, drv, "riscv_timer",
+					     plat->timebase_freq, ofnode_null(),
+					     NULL);
+	}
+
+	return 0;
+}
+
+static const struct cpu_ops riscv_cpu_ops = {
+	.get_desc	= riscv_cpu_get_desc,
+	.get_info	= riscv_cpu_get_info,
+	.get_count	= riscv_cpu_get_count,
+};
+
+static const struct udevice_id riscv_cpu_ids[] = {
+	{ .compatible = "riscv" },
+	{ }
+};
+
+U_BOOT_DRIVER(riscv_cpu) = {
+	.name = "riscv_cpu",
+	.id = UCLASS_CPU,
+	.of_match = riscv_cpu_ids,
+	.bind = riscv_cpu_bind,
+	.ops = &riscv_cpu_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 8a4162e..1820676 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -26,6 +26,15 @@
 	  Enable support for a test DMA uclass implementation. It stimulates
 	  DMA transfer by simple copying data between channels.
 
+config BCM6348_IUDMA
+	bool "BCM6348 IUDMA driver"
+	depends on ARCH_BMIPS
+	select DMA_CHANNELS
+	help
+	  Enable the BCM6348 IUDMA driver.
+	  This driver support data transfer from devices to
+	  memory and from memory to devices.
+
 config TI_EDMA3
 	bool "TI EDMA3 driver"
 	help
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index aff31f9..b5f9147 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -7,6 +7,7 @@
 
 obj-$(CONFIG_FSLDMAFEC) += MCD_tasksInit.o MCD_dmaApi.o MCD_tasks.o
 obj-$(CONFIG_APBH_DMA) += apbh_dma.o
+obj-$(CONFIG_BCM6348_IUDMA) += bcm6348-iudma.o
 obj-$(CONFIG_FSL_DMA) += fsl_dma.o
 obj-$(CONFIG_SANDBOX_DMA) += sandbox-dma-test.o
 obj-$(CONFIG_TI_KSNAV) += keystone_nav.o keystone_nav_cfg.o
diff --git a/drivers/dma/bcm6348-iudma.c b/drivers/dma/bcm6348-iudma.c
new file mode 100644
index 0000000..1d3c192
--- /dev/null
+++ b/drivers/dma/bcm6348-iudma.c
@@ -0,0 +1,642 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/dma/bcm63xx-iudma.c:
+ *	Copyright (C) 2015 Simon Arlott <simon@fire.lp0.eu>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/shared/opensource/include/bcm963xx/63268_map_part.h:
+ *	Copyright (C) 2000-2010 Broadcom Corporation
+ *
+ * Derived from bcm963xx_4.12L.06B_consumer/bcmdrivers/opensource/net/enet/impl4/bcmenet.c:
+ *	Copyright (C) 2010 Broadcom Corporation
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma-uclass.h>
+#include <memalign.h>
+#include <reset.h>
+#include <asm/io.h>
+
+#define DMA_RX_DESC	6
+#define DMA_TX_DESC	1
+
+/* DMA Channels */
+#define DMA_CHAN_FLOWC(x)		((x) >> 1)
+#define DMA_CHAN_MAX			16
+#define DMA_CHAN_SIZE			0x10
+#define DMA_CHAN_TOUT			500
+
+/* DMA Global Configuration register */
+#define DMA_CFG_REG			0x00
+#define  DMA_CFG_ENABLE_SHIFT		0
+#define  DMA_CFG_ENABLE_MASK		(1 << DMA_CFG_ENABLE_SHIFT)
+#define  DMA_CFG_FLOWC_ENABLE(x)	BIT(DMA_CHAN_FLOWC(x) + 1)
+#define  DMA_CFG_NCHANS_SHIFT		24
+#define  DMA_CFG_NCHANS_MASK		(0xf << DMA_CFG_NCHANS_SHIFT)
+
+/* DMA Global Flow Control registers */
+#define DMA_FLOWC_THR_LO_REG(x)		(0x04 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_THR_HI_REG(x)		(0x08 + DMA_CHAN_FLOWC(x) * 0x0c)
+#define DMA_FLOWC_ALLOC_REG(x)		(0x0c + DMA_CHAN_FLOWC(x) * 0x0c)
+#define  DMA_FLOWC_ALLOC_FORCE_SHIFT	31
+#define  DMA_FLOWC_ALLOC_FORCE_MASK	(1 << DMA_FLOWC_ALLOC_FORCE_SHIFT)
+
+/* DMA Global Reset register */
+#define DMA_RST_REG			0x34
+#define  DMA_RST_CHAN_SHIFT		0
+#define  DMA_RST_CHAN_MASK(x)		(1 << x)
+
+/* DMA Channel Configuration register */
+#define DMAC_CFG_REG(x)			(DMA_CHAN_SIZE * (x) + 0x00)
+#define  DMAC_CFG_ENABLE_SHIFT		0
+#define  DMAC_CFG_ENABLE_MASK		(1 << DMAC_CFG_ENABLE_SHIFT)
+#define  DMAC_CFG_PKT_HALT_SHIFT	1
+#define  DMAC_CFG_PKT_HALT_MASK		(1 << DMAC_CFG_PKT_HALT_SHIFT)
+#define  DMAC_CFG_BRST_HALT_SHIFT	2
+#define  DMAC_CFG_BRST_HALT_MASK	(1 << DMAC_CFG_BRST_HALT_SHIFT)
+
+/* DMA Channel Max Burst Length register */
+#define DMAC_BURST_REG(x)		(DMA_CHAN_SIZE * (x) + 0x0c)
+
+/* DMA SRAM Descriptor Ring Start register */
+#define DMAS_RSTART_REG(x)		(DMA_CHAN_SIZE * (x) + 0x00)
+
+/* DMA SRAM State/Bytes done/ring offset register */
+#define DMAS_STATE_DATA_REG(x)		(DMA_CHAN_SIZE * (x) + 0x04)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_LEN_STATUS_REG(x)	(DMA_CHAN_SIZE * (x) + 0x08)
+
+/* DMA SRAM Buffer Descriptor status and length register */
+#define DMAS_DESC_BASE_BUFPTR_REG(x)	(DMA_CHAN_SIZE * (x) + 0x0c)
+
+/* DMA Descriptor Status */
+#define DMAD_ST_CRC_SHIFT		8
+#define DMAD_ST_CRC_MASK		(1 << DMAD_ST_CRC_SHIFT)
+#define DMAD_ST_WRAP_SHIFT		12
+#define DMAD_ST_WRAP_MASK		(1 << DMAD_ST_WRAP_SHIFT)
+#define DMAD_ST_SOP_SHIFT		13
+#define DMAD_ST_SOP_MASK		(1 << DMAD_ST_SOP_SHIFT)
+#define DMAD_ST_EOP_SHIFT		14
+#define DMAD_ST_EOP_MASK		(1 << DMAD_ST_EOP_SHIFT)
+#define DMAD_ST_OWN_SHIFT		15
+#define DMAD_ST_OWN_MASK		(1 << DMAD_ST_OWN_SHIFT)
+
+#define DMAD6348_ST_OV_ERR_SHIFT	0
+#define DMAD6348_ST_OV_ERR_MASK		(1 << DMAD6348_ST_OV_ERR_SHIFT)
+#define DMAD6348_ST_CRC_ERR_SHIFT	1
+#define DMAD6348_ST_CRC_ERR_MASK	(1 << DMAD6348_ST_CRC_ERR_SHIFT)
+#define DMAD6348_ST_RX_ERR_SHIFT	2
+#define DMAD6348_ST_RX_ERR_MASK		(1 << DMAD6348_ST_RX_ERR_SHIFT)
+#define DMAD6348_ST_OS_ERR_SHIFT	4
+#define DMAD6348_ST_OS_ERR_MASK		(1 << DMAD6348_ST_OS_ERR_SHIFT)
+#define DMAD6348_ST_UN_ERR_SHIFT	9
+#define DMAD6348_ST_UN_ERR_MASK		(1 << DMAD6348_ST_UN_ERR_SHIFT)
+
+struct bcm6348_dma_desc {
+	uint16_t length;
+	uint16_t status;
+	uint32_t address;
+};
+
+struct bcm6348_chan_priv {
+	void __iomem *dma_ring;
+	uint8_t dma_ring_size;
+	uint8_t desc_id;
+	uint8_t desc_cnt;
+	bool *busy_desc;
+	bool running;
+};
+
+struct bcm6348_iudma_hw {
+	uint16_t err_mask;
+};
+
+struct bcm6348_iudma_priv {
+	const struct bcm6348_iudma_hw *hw;
+	void __iomem *base;
+	void __iomem *chan;
+	void __iomem *sram;
+	struct bcm6348_chan_priv **ch_priv;
+	uint8_t n_channels;
+};
+
+static inline bool bcm6348_iudma_chan_is_rx(uint8_t ch)
+{
+	return !(ch & 1);
+}
+
+static inline void bcm6348_iudma_fdc(void *ptr, ulong size)
+{
+	ulong start = (ulong) ptr;
+
+	flush_dcache_range(start, start + size);
+}
+
+static inline void bcm6348_iudma_idc(void *ptr, ulong size)
+{
+	ulong start = (ulong) ptr;
+
+	invalidate_dcache_range(start, start + size);
+}
+
+static void bcm6348_iudma_chan_stop(struct bcm6348_iudma_priv *priv,
+				    uint8_t ch)
+{
+	unsigned int timeout = DMA_CHAN_TOUT;
+
+	do {
+		uint32_t cfg, halt;
+
+		if (timeout > DMA_CHAN_TOUT / 2)
+			halt = DMAC_CFG_PKT_HALT_MASK;
+		else
+			halt = DMAC_CFG_BRST_HALT_MASK;
+
+		/* try to stop dma channel */
+		writel_be(halt, priv->chan + DMAC_CFG_REG(ch));
+		mb();
+
+		/* check if channel was stopped */
+		cfg = readl_be(priv->chan + DMAC_CFG_REG(ch));
+		if (!(cfg & DMAC_CFG_ENABLE_MASK))
+			break;
+
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		pr_err("unable to stop channel %u\n", ch);
+
+	/* reset dma channel */
+	setbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+	mb();
+	clrbits_be32(priv->base + DMA_RST_REG, DMA_RST_CHAN_MASK(ch));
+}
+
+static int bcm6348_iudma_disable(struct dma *dma)
+{
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+
+	/* stop dma channel */
+	bcm6348_iudma_chan_stop(priv, dma->id);
+
+	/* dma flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		writel_be(DMA_FLOWC_ALLOC_FORCE_MASK,
+			  DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* init channel config */
+	ch_priv->running = false;
+	ch_priv->desc_id = 0;
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->desc_cnt = 0;
+	else
+		ch_priv->desc_cnt = ch_priv->dma_ring_size;
+
+	return 0;
+}
+
+static int bcm6348_iudma_enable(struct dma *dma)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
+	uint8_t i;
+
+	/* dma ring init */
+	for (i = 0; i < ch_priv->desc_cnt; i++) {
+		if (bcm6348_iudma_chan_is_rx(dma->id)) {
+			ch_priv->busy_desc[i] = false;
+			dma_desc->status |= DMAD_ST_OWN_MASK;
+		} else {
+			dma_desc->status = 0;
+			dma_desc->length = 0;
+			dma_desc->address = 0;
+		}
+
+		if (i == ch_priv->desc_cnt - 1)
+			dma_desc->status |= DMAD_ST_WRAP_MASK;
+
+		dma_desc++;
+	}
+
+	/* init to first descriptor */
+	ch_priv->desc_id = 0;
+
+	/* force cache writeback */
+	bcm6348_iudma_fdc(ch_priv->dma_ring,
+			  sizeof(*dma_desc) * ch_priv->desc_cnt);
+
+	/* clear sram */
+	writel_be(0, priv->sram + DMAS_STATE_DATA_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_LEN_STATUS_REG(dma->id));
+	writel_be(0, priv->sram + DMAS_DESC_BASE_BUFPTR_REG(dma->id));
+
+	/* set dma ring start */
+	writel_be(virt_to_phys(ch_priv->dma_ring),
+		  priv->sram + DMAS_RSTART_REG(dma->id));
+
+	/* set flow control */
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		u32 val;
+
+		setbits_be32(priv->base + DMA_CFG_REG,
+			     DMA_CFG_FLOWC_ENABLE(dma->id));
+
+		val = ch_priv->desc_cnt / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_LO_REG(dma->id));
+
+		val = (ch_priv->desc_cnt * 2) / 3;
+		writel_be(val, priv->base + DMA_FLOWC_THR_HI_REG(dma->id));
+
+		writel_be(0, priv->base + DMA_FLOWC_ALLOC_REG(dma->id));
+	}
+
+	/* set dma max burst */
+	writel_be(ch_priv->desc_cnt,
+		  priv->chan + DMAC_BURST_REG(dma->id));
+
+	/* kick rx dma channel */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		setbits_be32(priv->chan + DMAC_CFG_REG(dma->id),
+			     DMAC_CFG_ENABLE_MASK);
+
+	/* channel is now enabled */
+	ch_priv->running = true;
+
+	return 0;
+}
+
+static int bcm6348_iudma_request(struct dma *dma)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv;
+
+	/* check if channel is valid */
+	if (dma->id >= priv->n_channels)
+		return -ENODEV;
+
+	/* alloc channel private data */
+	priv->ch_priv[dma->id] = calloc(1, sizeof(struct bcm6348_chan_priv));
+	if (!priv->ch_priv[dma->id])
+		return -ENOMEM;
+	ch_priv = priv->ch_priv[dma->id];
+
+	/* alloc dma ring */
+	if (bcm6348_iudma_chan_is_rx(dma->id))
+		ch_priv->dma_ring_size = DMA_RX_DESC;
+	else
+		ch_priv->dma_ring_size = DMA_TX_DESC;
+
+	ch_priv->dma_ring =
+		malloc_cache_aligned(sizeof(struct bcm6348_dma_desc) *
+				     ch_priv->dma_ring_size);
+	if (!ch_priv->dma_ring)
+		return -ENOMEM;
+
+	/* init channel config */
+	ch_priv->running = false;
+	ch_priv->desc_id = 0;
+	if (bcm6348_iudma_chan_is_rx(dma->id)) {
+		ch_priv->desc_cnt = 0;
+		ch_priv->busy_desc = calloc(ch_priv->desc_cnt, sizeof(bool));
+	} else {
+		ch_priv->desc_cnt = ch_priv->dma_ring_size;
+		ch_priv->busy_desc = NULL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_iudma_receive(struct dma *dma, void **dst, void *metadata)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	const struct bcm6348_iudma_hw *hw = priv->hw;
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc = dma_desc = ch_priv->dma_ring;
+	int ret;
+
+	/* get dma ring descriptor address */
+	dma_desc += ch_priv->desc_id;
+
+	/* invalidate cache data */
+	bcm6348_iudma_idc(dma_desc, sizeof(*dma_desc));
+
+	/* check dma own */
+	if (dma_desc->status & DMAD_ST_OWN_MASK)
+		return -EAGAIN;
+
+	/* check pkt */
+	if (!(dma_desc->status & DMAD_ST_EOP_MASK) ||
+	    !(dma_desc->status & DMAD_ST_SOP_MASK) ||
+	    (dma_desc->status & hw->err_mask)) {
+		pr_err("invalid pkt received (ch=%ld desc=%u) (st=%04x)\n",
+		       dma->id, ch_priv->desc_id, dma_desc->status);
+		ret = -EAGAIN;
+	} else {
+		/* set dma buffer address */
+		*dst = phys_to_virt(dma_desc->address);
+
+		/* invalidate cache data */
+		bcm6348_iudma_idc(*dst, dma_desc->length);
+
+		/* return packet length */
+		ret = dma_desc->length;
+	}
+
+	/* busy dma descriptor */
+	ch_priv->busy_desc[ch_priv->desc_id] = true;
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->desc_cnt;
+
+	return ret;
+}
+
+static int bcm6348_iudma_send(struct dma *dma, void *src, size_t len,
+			      void *metadata)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc;
+	uint16_t status;
+
+	/* flush cache */
+	bcm6348_iudma_fdc(src, len);
+
+	/* get dma ring descriptor address */
+	dma_desc = ch_priv->dma_ring;
+	dma_desc += ch_priv->desc_id;
+
+	/* config dma descriptor */
+	status = (DMAD_ST_OWN_MASK |
+		  DMAD_ST_EOP_MASK |
+		  DMAD_ST_CRC_MASK |
+		  DMAD_ST_SOP_MASK);
+	if (ch_priv->desc_id == ch_priv->desc_cnt - 1)
+		status |= DMAD_ST_WRAP_MASK;
+
+	/* set dma descriptor */
+	dma_desc->address = virt_to_phys(src);
+	dma_desc->length = len;
+	dma_desc->status = status;
+
+	/* flush cache */
+	bcm6348_iudma_fdc(dma_desc, sizeof(*dma_desc));
+
+	/* kick tx dma channel */
+	setbits_be32(priv->chan + DMAC_CFG_REG(dma->id), DMAC_CFG_ENABLE_MASK);
+
+	/* poll dma status */
+	do {
+		/* invalidate cache */
+		bcm6348_iudma_idc(dma_desc, sizeof(*dma_desc));
+
+		if (!(dma_desc->status & DMAD_ST_OWN_MASK))
+			break;
+	} while(1);
+
+	/* increment dma descriptor */
+	ch_priv->desc_id = (ch_priv->desc_id + 1) % ch_priv->desc_cnt;
+
+	return 0;
+}
+
+static int bcm6348_iudma_free_rcv_buf(struct dma *dma, void *dst, size_t size)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
+	uint16_t status;
+	uint8_t i;
+	u32 cfg;
+
+	/* get dirty dma descriptor */
+	for (i = 0; i < ch_priv->desc_cnt; i++) {
+		if (phys_to_virt(dma_desc->address) == dst)
+			break;
+
+		dma_desc++;
+	}
+
+	/* dma descriptor not found */
+	if (i == ch_priv->desc_cnt) {
+		pr_err("dirty dma descriptor not found\n");
+		return -ENOENT;
+	}
+
+	/* invalidate cache */
+	bcm6348_iudma_idc(ch_priv->dma_ring,
+			  sizeof(*dma_desc) * ch_priv->desc_cnt);
+
+	/* free dma descriptor */
+	ch_priv->busy_desc[i] = false;
+
+	status = DMAD_ST_OWN_MASK;
+	if (i == ch_priv->desc_cnt - 1)
+		status |= DMAD_ST_WRAP_MASK;
+
+	dma_desc->status |= status;
+	dma_desc->length = PKTSIZE_ALIGN;
+
+	/* tell dma we allocated one buffer */
+	writel_be(1, DMA_FLOWC_ALLOC_REG(dma->id));
+
+	/* flush cache */
+	bcm6348_iudma_fdc(ch_priv->dma_ring,
+			  sizeof(*dma_desc) * ch_priv->desc_cnt);
+
+	/* kick rx dma channel if disabled */
+	cfg = readl_be(priv->chan + DMAC_CFG_REG(dma->id));
+	if (!(cfg & DMAC_CFG_ENABLE_MASK))
+		setbits_be32(priv->chan + DMAC_CFG_REG(dma->id),
+			     DMAC_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+static int bcm6348_iudma_add_rcv_buf(struct dma *dma, void *dst, size_t size)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+	struct bcm6348_dma_desc *dma_desc = ch_priv->dma_ring;
+
+	/* no more dma descriptors available */
+	if (ch_priv->desc_cnt == ch_priv->dma_ring_size) {
+		pr_err("max number of buffers reached\n");
+		return -EINVAL;
+	}
+
+	/* get next dma descriptor */
+	dma_desc += ch_priv->desc_cnt;
+
+	/* init dma descriptor */
+	dma_desc->address = virt_to_phys(dst);
+	dma_desc->length = size;
+	dma_desc->status = 0;
+
+	/* flush cache */
+	bcm6348_iudma_fdc(dma_desc, sizeof(*dma_desc));
+
+	/* increment dma descriptors */
+	ch_priv->desc_cnt++;
+
+	return 0;
+}
+
+static int bcm6348_iudma_prepare_rcv_buf(struct dma *dma, void *dst,
+					 size_t size)
+{
+	const struct bcm6348_iudma_priv *priv = dev_get_priv(dma->dev);
+	struct bcm6348_chan_priv *ch_priv = priv->ch_priv[dma->id];
+
+	/* only add new rx buffers if channel isn't running */
+	if (ch_priv->running)
+		return bcm6348_iudma_free_rcv_buf(dma, dst, size);
+	else
+		return bcm6348_iudma_add_rcv_buf(dma, dst, size);
+}
+
+static const struct dma_ops bcm6348_iudma_ops = {
+	.disable = bcm6348_iudma_disable,
+	.enable = bcm6348_iudma_enable,
+	.prepare_rcv_buf = bcm6348_iudma_prepare_rcv_buf,
+	.request = bcm6348_iudma_request,
+	.receive = bcm6348_iudma_receive,
+	.send = bcm6348_iudma_send,
+};
+
+static const struct bcm6348_iudma_hw bcm6348_hw = {
+	.err_mask = (DMAD6348_ST_OV_ERR_MASK |
+		     DMAD6348_ST_CRC_ERR_MASK |
+		     DMAD6348_ST_RX_ERR_MASK |
+		     DMAD6348_ST_OS_ERR_MASK |
+		     DMAD6348_ST_UN_ERR_MASK),
+};
+
+static const struct bcm6348_iudma_hw bcm6368_hw = {
+	.err_mask = 0,
+};
+
+static const struct udevice_id bcm6348_iudma_ids[] = {
+	{
+		.compatible = "brcm,bcm6348-iudma",
+		.data = (ulong)&bcm6348_hw,
+	}, {
+		.compatible = "brcm,bcm6368-iudma",
+		.data = (ulong)&bcm6368_hw,
+	}, { /* sentinel */ }
+};
+
+static int bcm6348_iudma_probe(struct udevice *dev)
+{
+	struct dma_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct bcm6348_iudma_priv *priv = dev_get_priv(dev);
+	const struct bcm6348_iudma_hw *hw =
+		(const struct bcm6348_iudma_hw *)dev_get_driver_data(dev);
+	uint8_t ch;
+	int i;
+
+	uc_priv->supported = (DMA_SUPPORTS_DEV_TO_MEM |
+			      DMA_SUPPORTS_MEM_TO_DEV);
+	priv->hw = hw;
+
+	/* dma global base address */
+	priv->base = dev_remap_addr_name(dev, "dma");
+	if (!priv->base)
+		return -EINVAL;
+
+	/* dma channels base address */
+	priv->chan = dev_remap_addr_name(dev, "dma-channels");
+	if (!priv->chan)
+		return -EINVAL;
+
+	/* dma sram base address */
+	priv->sram = dev_remap_addr_name(dev, "dma-sram");
+	if (!priv->sram)
+		return -EINVAL;
+
+	/* get number of channels */
+	priv->n_channels = dev_read_u32_default(dev, "dma-channels", 8);
+	if (priv->n_channels > DMA_CHAN_MAX)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+
+		ret = clk_enable(&clk);
+		if (ret < 0) {
+			pr_err("error enabling clock %d\n", i);
+			return ret;
+		}
+
+		ret = clk_free(&clk);
+		if (ret < 0) {
+			pr_err("error freeing clock %d\n", i);
+			return ret;
+		}
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+
+		ret = reset_deassert(&reset);
+		if (ret < 0) {
+			pr_err("error deasserting reset %d\n", i);
+			return ret;
+		}
+
+		ret = reset_free(&reset);
+		if (ret < 0) {
+			pr_err("error freeing reset %d\n", i);
+			return ret;
+		}
+	}
+
+	/* disable dma controller */
+	clrbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	/* alloc channel private data pointers */
+	priv->ch_priv = calloc(priv->n_channels,
+			       sizeof(struct bcm6348_chan_priv*));
+	if (!priv->ch_priv)
+		return -ENOMEM;
+
+	/* stop dma channels */
+	for (ch = 0; ch < priv->n_channels; ch++)
+		bcm6348_iudma_chan_stop(priv, ch);
+
+	/* enable dma controller */
+	setbits_be32(priv->base + DMA_CFG_REG, DMA_CFG_ENABLE_MASK);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_iudma) = {
+	.name = "bcm6348_iudma",
+	.id = UCLASS_DMA,
+	.of_match = bcm6348_iudma_ids,
+	.ops = &bcm6348_iudma_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6348_iudma_priv),
+	.probe = bcm6348_iudma_probe,
+};
diff --git a/drivers/fpga/Kconfig b/drivers/fpga/Kconfig
index 50e9019..8f59193 100644
--- a/drivers/fpga/Kconfig
+++ b/drivers/fpga/Kconfig
@@ -31,6 +31,17 @@
 	  Enable FPGA driver for loading bitstream in BIT and BIN format
 	  on Altera Cyclone II device.
 
+config FPGA_STRATIX10
+	bool "Enable Altera FPGA driver for Stratix 10"
+	depends on TARGET_SOCFPGA_STRATIX10
+	select FPGA_ALTERA
+	help
+	  Say Y here to enable the Altera Stratix 10 FPGA specific driver
+
+	  This provides common functionality for Altera Stratix 10 devices.
+	  Enable FPGA driver for writing bitstream into Altera Stratix10
+	  device.
+
 config FPGA_XILINX
 	bool "Enable Xilinx FPGA drivers"
 	select FPGA
diff --git a/drivers/fpga/Makefile b/drivers/fpga/Makefile
index 97d7d5d..5a778c1 100644
--- a/drivers/fpga/Makefile
+++ b/drivers/fpga/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_FPGA_CYCLON2) += cyclon2.o
 obj-$(CONFIG_FPGA_STRATIX_II) += stratixII.o
 obj-$(CONFIG_FPGA_STRATIX_V) += stratixv.o
+obj-$(CONFIG_FPGA_STRATIX10) += stratix10.o
 obj-$(CONFIG_FPGA_SOCFPGA) += socfpga.o
 obj-$(CONFIG_TARGET_SOCFPGA_GEN5) += socfpga_gen5.o
 obj-$(CONFIG_TARGET_SOCFPGA_ARRIA10) += socfpga_arria10.o
diff --git a/drivers/fpga/altera.c b/drivers/fpga/altera.c
index 9605554..7c8f518 100644
--- a/drivers/fpga/altera.c
+++ b/drivers/fpga/altera.c
@@ -39,6 +39,9 @@
 #if defined(CONFIG_FPGA_STRATIX_V)
 	{ Altera_StratixV, "StratixV", stratixv_load, NULL, NULL },
 #endif
+#if defined(CONFIG_FPGA_STRATIX10)
+	{ Intel_FPGA_Stratix10, "Stratix10", stratix10_load, NULL, NULL },
+#endif
 #if defined(CONFIG_FPGA_SOCFPGA)
 	{ Altera_SoCFPGA, "SoC FPGA", socfpga_load, NULL, NULL },
 #endif
@@ -154,6 +157,9 @@
 	case fast_passive_parallel_security:
 		printf("Fast Passive Parallel with Security (FPPS)\n");
 		break;
+	case secure_device_manager_mailbox:
+		puts("Secure Device Manager (SDM) Mailbox\n");
+		break;
 		/* Add new interface types here */
 	default:
 		printf("Unsupported interface type, %d\n", desc->iface);
diff --git a/drivers/fpga/stratix10.c b/drivers/fpga/stratix10.c
new file mode 100644
index 0000000..aae0521
--- /dev/null
+++ b/drivers/fpga/stratix10.c
@@ -0,0 +1,288 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ */
+
+#include <common.h>
+#include <altera.h>
+#include <asm/arch/mailbox_s10.h>
+
+#define RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS		60000
+#define RECONFIG_STATUS_INTERVAL_DELAY_US		1000000
+
+static const struct mbox_cfgstat_state {
+	int			err_no;
+	const char		*error_name;
+} mbox_cfgstat_state[] = {
+	{MBOX_CFGSTAT_STATE_IDLE, "FPGA in idle mode."},
+	{MBOX_CFGSTAT_STATE_CONFIG, "FPGA in config mode."},
+	{MBOX_CFGSTAT_STATE_FAILACK, "Acknowledgment failed!"},
+	{MBOX_CFGSTAT_STATE_ERROR_INVALID, "Invalid bitstream!"},
+	{MBOX_CFGSTAT_STATE_ERROR_CORRUPT, "Corrupted bitstream!"},
+	{MBOX_CFGSTAT_STATE_ERROR_AUTH, "Authentication failed!"},
+	{MBOX_CFGSTAT_STATE_ERROR_CORE_IO, "I/O error!"},
+	{MBOX_CFGSTAT_STATE_ERROR_HARDWARE, "Hardware error!"},
+	{MBOX_CFGSTAT_STATE_ERROR_FAKE, "Fake error!"},
+	{MBOX_CFGSTAT_STATE_ERROR_BOOT_INFO, "Error in boot info!"},
+	{MBOX_CFGSTAT_STATE_ERROR_QSPI_ERROR, "Error in QSPI!"},
+	{MBOX_RESP_ERROR, "Mailbox general error!"},
+	{-ETIMEDOUT, "I/O timeout error"},
+	{-1, "Unknown error!"}
+};
+
+#define MBOX_CFGSTAT_MAX ARRAY_SIZE(mbox_cfgstat_state)
+
+static const char *mbox_cfgstat_to_str(int err)
+{
+	int i;
+
+	for (i = 0; i < MBOX_CFGSTAT_MAX - 1; i++) {
+		if (mbox_cfgstat_state[i].err_no == err)
+			return mbox_cfgstat_state[i].error_name;
+	}
+
+	return mbox_cfgstat_state[MBOX_CFGSTAT_MAX - 1].error_name;
+}
+
+/*
+ * Add the ongoing transaction's command ID into pending list and return
+ * the command ID for next transfer.
+ */
+static u8 add_transfer(u32 *xfer_pending_list, size_t list_size, u8 id)
+{
+	int i;
+
+	for (i = 0; i < list_size; i++) {
+		if (xfer_pending_list[i])
+			continue;
+		xfer_pending_list[i] = id;
+		debug("ID(%d) added to transaction pending list\n", id);
+		/*
+		 * Increment command ID for next transaction.
+		 * Valid command ID (4 bits) is from 1 to 15.
+		 */
+		id = (id % 15) + 1;
+		break;
+	}
+
+	return id;
+}
+
+/*
+ * Check whether response ID match the command ID in the transfer
+ * pending list. If a match is found in the transfer pending list,
+ * it clears the transfer pending list and return the matched
+ * command ID.
+ */
+static int get_and_clr_transfer(u32 *xfer_pending_list, size_t list_size,
+				u8 id)
+{
+	int i;
+
+	for (i = 0; i < list_size; i++) {
+		if (id != xfer_pending_list[i])
+			continue;
+		xfer_pending_list[i] = 0;
+		return id;
+	}
+
+	return 0;
+}
+
+/*
+ * Polling the FPGA configuration status.
+ * Return 0 for success, non-zero for error.
+ */
+static int reconfig_status_polling_resp(void)
+{
+	int ret;
+	unsigned long start = get_timer(0);
+
+	while (1) {
+		ret = mbox_get_fpga_config_status(MBOX_RECONFIG_STATUS);
+		if (!ret)
+			return 0;	/* configuration success */
+
+		if (ret != MBOX_CFGSTAT_STATE_CONFIG)
+			return ret;
+
+		if (get_timer(start) > RECONFIG_STATUS_POLL_RESP_TIMEOUT_MS)
+			break;	/* time out */
+
+		puts(".");
+		udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+	}
+
+	return -ETIMEDOUT;
+}
+
+static u32 get_resp_hdr(u32 *r_index, u32 *w_index, u32 *resp_count,
+			u32 *resp_buf, u32 buf_size, u32 client_id)
+{
+	u32 buf[MBOX_RESP_BUFFER_SIZE];
+	u32 mbox_hdr;
+	u32 resp_len;
+	u32 hdr_len;
+	u32 i;
+
+	if (*resp_count < buf_size) {
+		u32 rcv_len_max = buf_size - *resp_count;
+
+		if (rcv_len_max > MBOX_RESP_BUFFER_SIZE)
+			rcv_len_max = MBOX_RESP_BUFFER_SIZE;
+		resp_len = mbox_rcv_resp(buf, rcv_len_max);
+
+		for (i = 0; i < resp_len; i++) {
+			resp_buf[(*w_index)++] = buf[i];
+			*w_index %= buf_size;
+			(*resp_count)++;
+		}
+	}
+
+	/* No response in buffer */
+	if (*resp_count == 0)
+		return 0;
+
+	mbox_hdr = resp_buf[*r_index];
+
+	hdr_len = MBOX_RESP_LEN_GET(mbox_hdr);
+
+	/* Insufficient header length to return a mailbox header */
+	if ((*resp_count - 1) < hdr_len)
+		return 0;
+
+	*r_index += (hdr_len + 1);
+	*r_index %= buf_size;
+	*resp_count -= (hdr_len + 1);
+
+	/* Make sure response belongs to us */
+	if (MBOX_RESP_CLIENT_GET(mbox_hdr) != client_id)
+		return 0;
+
+	return mbox_hdr;
+}
+
+/* Send bit stream data to SDM via RECONFIG_DATA mailbox command */
+static int send_reconfig_data(const void *rbf_data, size_t rbf_size,
+			      u32 xfer_max, u32 buf_size_max)
+{
+	u32 response_buffer[MBOX_RESP_BUFFER_SIZE];
+	u32 xfer_pending[MBOX_RESP_BUFFER_SIZE];
+	u32 resp_rindex = 0;
+	u32 resp_windex = 0;
+	u32 resp_count = 0;
+	u32 xfer_count = 0;
+	u8 resp_err = 0;
+	u8 cmd_id = 1;
+	u32 args[3];
+	int ret;
+
+	debug("SDM xfer_max = %d\n", xfer_max);
+	debug("SDM buf_size_max = %x\n\n", buf_size_max);
+
+	memset(xfer_pending, 0, sizeof(xfer_pending));
+
+	while (rbf_size || xfer_count) {
+		if (!resp_err && rbf_size && xfer_count < xfer_max) {
+			args[0] = MBOX_ARG_DESC_COUNT(1);
+			args[1] = (u64)rbf_data;
+			if (rbf_size >= buf_size_max) {
+				args[2] = buf_size_max;
+				rbf_size -= buf_size_max;
+				rbf_data += buf_size_max;
+			} else {
+				args[2] = (u64)rbf_size;
+				rbf_size = 0;
+			}
+
+			ret = mbox_send_cmd_only(cmd_id, MBOX_RECONFIG_DATA,
+						 MBOX_CMD_INDIRECT, 3, args);
+			if (ret) {
+				resp_err = 1;
+			} else {
+				xfer_count++;
+				cmd_id = add_transfer(xfer_pending,
+						      MBOX_RESP_BUFFER_SIZE,
+						      cmd_id);
+			}
+			puts(".");
+		} else {
+			u32 resp_hdr = get_resp_hdr(&resp_rindex, &resp_windex,
+						    &resp_count,
+						    response_buffer,
+						    MBOX_RESP_BUFFER_SIZE,
+						    MBOX_CLIENT_ID_UBOOT);
+
+			/*
+			 * If no valid response header found or
+			 * non-zero length from RECONFIG_DATA
+			 */
+			if (!resp_hdr || MBOX_RESP_LEN_GET(resp_hdr))
+				continue;
+
+			/* Check for response's status */
+			if (!resp_err) {
+				ret = MBOX_RESP_ERR_GET(resp_hdr);
+				debug("Response error code: %08x\n", ret);
+				/* Error in response */
+				if (ret)
+					resp_err = 1;
+			}
+
+			ret = get_and_clr_transfer(xfer_pending,
+						   MBOX_RESP_BUFFER_SIZE,
+						   MBOX_RESP_ID_GET(resp_hdr));
+			if (ret) {
+				/* Claim and reuse the ID */
+				cmd_id = (u8)ret;
+				xfer_count--;
+			}
+
+			if (resp_err && !xfer_count)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+/*
+ * This is the interface used by FPGA driver.
+ * Return 0 for success, non-zero for error.
+ */
+int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size)
+{
+	int ret;
+	u32 resp_len = 2;
+	u32 resp_buf[2];
+
+	debug("Sending MBOX_RECONFIG...\n");
+	ret = mbox_send_cmd(MBOX_ID_UBOOT, MBOX_RECONFIG, MBOX_CMD_DIRECT, 0,
+			    NULL, 0, &resp_len, resp_buf);
+	if (ret) {
+		puts("Failure in RECONFIG mailbox command!\n");
+		return ret;
+	}
+
+	ret = send_reconfig_data(rbf_data, rbf_size, resp_buf[0], resp_buf[1]);
+	if (ret) {
+		printf("RECONFIG_DATA error: %08x, %s\n", ret,
+		       mbox_cfgstat_to_str(ret));
+		return ret;
+	}
+
+	/* Make sure we don't send MBOX_RECONFIG_STATUS too fast */
+	udelay(RECONFIG_STATUS_INTERVAL_DELAY_US);
+
+	debug("Polling with MBOX_RECONFIG_STATUS...\n");
+	ret = reconfig_status_polling_resp();
+	if (ret) {
+		printf("RECONFIG_STATUS Error: %08x, %s\n", ret,
+		       mbox_cfgstat_to_str(ret));
+		return ret;
+	}
+
+	puts("FPGA reconfiguration OK!\n");
+
+	return ret;
+}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 35344e5..c8c6c60 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -99,6 +99,13 @@
 	help
 	  Support for the LPC32XX GPIO driver.
 
+config MSCC_BITBANG_SPI_GPIO
+	bool "Microsemi bitbang spi GPIO driver"
+	depends on DM_GPIO && SOC_VCOREIII
+	help
+	  Support controlling the GPIO used for SPI bitbang by software. Can
+	  be used by the VCoreIII SoCs, but it was mainly useful for Luton.
+
 config MSM_GPIO
 	bool "Qualcomm GPIO driver"
 	depends on DM_GPIO
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 7ed9a4e..61feda1 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -59,3 +59,4 @@
 obj-$(CONFIG_$(SPL_)PCF8575_GPIO)	+= pcf8575_gpio.o
 obj-$(CONFIG_PM8916_GPIO)	+= pm8916_gpio.o
 obj-$(CONFIG_MT7621_GPIO)	+= mt7621_gpio.o
+obj-$(CONFIG_MSCC_BITBANG_SPI_GPIO)	+= gpio-mscc-bitbang-spi.o
diff --git a/drivers/gpio/gpio-mscc-bitbang-spi.c b/drivers/gpio/gpio-mscc-bitbang-spi.c
new file mode 100644
index 0000000..b675f90
--- /dev/null
+++ b/drivers/gpio/gpio-mscc-bitbang-spi.c
@@ -0,0 +1,122 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs pinctrl driver
+ *
+ * Author: <gregory.clement@bootlin.com>
+ * License: Dual MIT/GPL
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <asm-generic/gpio.h>
+#include <asm/io.h>
+#include <dm.h>
+#include <errno.h>
+
+enum {
+	SDI,
+	CS0,
+	CS1,
+	CS2,
+	CS3,
+	SDO,
+	SCK
+};
+
+static const int pinmap[] = { 0, 5, 6, 7, 8, 10, 12 };
+
+#define SW_SPI_CSn_OE	 0x1E	/* bits 1 to 4 */
+#define SW_SPI_CS0_OE	 BIT(1)
+#define SW_SPI_SDO_OE	 BIT(9)
+#define SW_SPI_SCK_OE	 BIT(11)
+#define SW_PIN_CTRL_MODE BIT(13)
+
+struct mscc_bb_spi_gpio {
+	void __iomem *regs;
+	u32 cache_val;
+};
+
+static int mscc_bb_spi_gpio_set(struct udevice *dev, unsigned oft, int val)
+{
+	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
+
+	if (val)
+		gpio->cache_val |= BIT(pinmap[oft]);
+	else
+		gpio->cache_val &= ~BIT(pinmap[oft]);
+
+	writel(gpio->cache_val, gpio->regs);
+
+	return 0;
+}
+
+static int mscc_bb_spi_gpio_direction_output(struct udevice *dev, unsigned oft,
+					     int val)
+{
+	if (oft == 0) {
+		pr_err("SW_SPI_DSI can't be used as output\n");
+		return -ENOTSUPP;
+	}
+
+	mscc_bb_spi_gpio_set(dev, oft, val);
+
+	return 0;
+}
+
+static int mscc_bb_spi_gpio_direction_input(struct udevice *dev, unsigned oft)
+{
+	return 0;
+}
+
+static int mscc_bb_spi_gpio_get(struct udevice *dev, unsigned int oft)
+{
+	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
+	u32 val = readl(gpio->regs);
+
+	return !!(val & BIT(pinmap[oft]));
+}
+
+static const struct dm_gpio_ops mscc_bb_spi_gpio_ops = {
+	.direction_output	= mscc_bb_spi_gpio_direction_output,
+	.direction_input	= mscc_bb_spi_gpio_direction_input,
+	.set_value		= mscc_bb_spi_gpio_set,
+	.get_value		= mscc_bb_spi_gpio_get,
+};
+
+static int mscc_bb_spi_gpio_probe(struct udevice *dev)
+{
+	struct mscc_bb_spi_gpio *gpio = dev_get_priv(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	gpio->regs = dev_remap_addr(dev);
+	if (!gpio->regs)
+		return -EINVAL;
+
+	uc_priv->bank_name = dev->name;
+	uc_priv->gpio_count = ARRAY_SIZE(pinmap);
+	/*
+	 * Enable software mode to control the SPI pin, enables the
+	 * output mode for most of the pin and initialize the cache
+	 * value in the same time
+	 */
+
+	gpio->cache_val = SW_PIN_CTRL_MODE | SW_SPI_SCK_OE | SW_SPI_SDO_OE |
+	    SW_SPI_CS0_OE;
+	writel(gpio->cache_val, gpio->regs);
+
+	return 0;
+}
+
+static const struct udevice_id mscc_bb_spi_gpio_ids[] = {
+	{.compatible = "mscc,spi-bitbang-gpio"},
+	{}
+};
+
+U_BOOT_DRIVER(gpio_mscc_bb_spi) = {
+	.name	= "gpio-mscc-spi-bitbang",
+	.id	= UCLASS_GPIO,
+	.ops	= &mscc_bb_spi_gpio_ops,
+	.probe	= mscc_bb_spi_gpio_probe,
+	.of_match = of_match_ptr(mscc_bb_spi_gpio_ids),
+	.priv_auto_alloc_size = sizeof(struct mscc_bb_spi_gpio),
+};
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index 48febc4..704c8dd 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -120,6 +120,12 @@
 	  Security Monitor can be transitioned on any security failures,
 	  like software violations or hardware security violations.
 
+config JZ4780_EFUSE
+	bool "Ingenic JZ4780 eFUSE support"
+	depends on ARCH_JZ47XX
+	help
+	  This selects support for the eFUSE on Ingenic JZ4780 SoCs.
+
 config MXC_OCOTP
 	bool "Enable MXC OCOTP Driver"
 	help
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index 302d441..6bdf505 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -62,3 +62,4 @@
 obj-$(CONFIG_TWL4030_LED) += twl4030_led.o
 obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress_config.o
 obj-$(CONFIG_WINBOND_W83627) += winbond_w83627.o
+obj-$(CONFIG_JZ4780_EFUSE) += jz4780_efuse.o
diff --git a/drivers/misc/jz4780_efuse.c b/drivers/misc/jz4780_efuse.c
new file mode 100644
index 0000000..bc3dc93
--- /dev/null
+++ b/drivers/misc/jz4780_efuse.c
@@ -0,0 +1,103 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4780 EFUSE driver
+ *
+ * Copyright (c) 2014 Imagination Technologies
+ * Author: Alex Smith <alex.smith@imgtec.com>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <errno.h>
+#include <mach/jz4780.h>
+#include <wait_bit.h>
+
+#define EFUSE_EFUCTRL			0xd0
+#define EFUSE_EFUCFG			0xd4
+#define EFUSE_EFUSTATE			0xd8
+#define EFUSE_EFUDATA(n)		(0xdc + ((n) * 4))
+
+#define EFUSE_EFUCTRL_RD_EN		BIT(0)
+#define EFUSE_EFUCTRL_LEN_BIT		16
+#define EFUSE_EFUCTRL_LEN_MASK		0x1f
+#define EFUSE_EFUCTRL_ADDR_BIT		21
+#define EFUSE_EFUCTRL_ADDR_MASK		0x1ff
+#define EFUSE_EFUCTRL_CS		BIT(30)
+
+#define EFUSE_EFUCFG_RD_STROBE_BIT	16
+#define EFUSE_EFUCFG_RD_STROBE_MASK	0xf
+#define EFUSE_EFUCFG_RD_ADJ_BIT		20
+#define EFUSE_EFUCFG_RD_ADJ_MASK	0xf
+
+#define EFUSE_EFUSTATE_RD_DONE		BIT(0)
+
+static void jz4780_efuse_read_chunk(size_t addr, size_t count, u8 *buf)
+{
+	void __iomem *regs = (void __iomem *)NEMC_BASE;
+	size_t i;
+	u32 val;
+	int ret;
+
+	val = EFUSE_EFUCTRL_RD_EN |
+		((count - 1) << EFUSE_EFUCTRL_LEN_BIT) |
+		(addr << EFUSE_EFUCTRL_ADDR_BIT) |
+		((addr > 0x200) ? EFUSE_EFUCTRL_CS : 0);
+	writel(val, regs + EFUSE_EFUCTRL);
+
+	ret = wait_for_bit_le32(regs + EFUSE_EFUSTATE,
+				EFUSE_EFUSTATE_RD_DONE, true, 10000, false);
+	if (ret)
+		return;
+
+	if ((count % 4) == 0) {
+		for (i = 0; i < count / 4; i++) {
+			val = readl(regs + EFUSE_EFUDATA(i));
+			put_unaligned(val, (u32 *)(buf + (i * 4)));
+		}
+	} else {
+		val = readl(regs + EFUSE_EFUDATA(0));
+		if (count > 2)
+			buf[2] = (val >> 16) & 0xff;
+		if (count > 1)
+			buf[1] = (val >> 8) & 0xff;
+		buf[0] = val & 0xff;
+	}
+}
+
+static inline int jz4780_efuse_chunk_size(size_t count)
+{
+	if (count >= 32)
+		return 32;
+	else if ((count / 4) > 0)
+		return (count / 4) * 4;
+	else
+		return count % 4;
+}
+
+void jz4780_efuse_read(size_t addr, size_t count, u8 *buf)
+{
+	size_t chunk;
+
+	while (count > 0) {
+		chunk = jz4780_efuse_chunk_size(count);
+		jz4780_efuse_read_chunk(addr, chunk, buf);
+		addr += chunk;
+		buf += chunk;
+		count -= chunk;
+	}
+}
+
+void jz4780_efuse_init(u32 ahb2_rate)
+{
+	void __iomem *regs = (void __iomem *)NEMC_BASE;
+	u32 rd_adj, rd_strobe, tmp;
+
+	rd_adj = (((6500 * (ahb2_rate / 1000000)) / 1000000) + 0xf) / 2;
+	tmp = (((35000 * (ahb2_rate / 1000000)) / 1000000) - 4) - rd_adj;
+	rd_strobe = ((tmp + 0xf) / 2 < 7) ? 7 : (tmp + 0xf) / 2;
+
+	tmp = (rd_adj << EFUSE_EFUCFG_RD_ADJ_BIT) |
+	      (rd_strobe << EFUSE_EFUCFG_RD_STROBE_BIT);
+	writel(tmp, regs + EFUSE_EFUCFG);
+}
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index fbd1396..496b2cb 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -332,6 +332,12 @@
 
 	  If unsure, say N.
 
+config JZ47XX_MMC
+	bool "Ingenic JZ47xx SD/MMC Host Controller support"
+	depends on ARCH_JZ47XX
+	help
+	  This selects support for the SD Card Controller on Ingenic JZ47xx SoCs.
+
 config MMC_SANDBOX
 	bool "Sandbox MMC support"
 	depends on SANDBOX
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 801a26d..7892c46 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -40,6 +40,7 @@
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
 obj-$(CONFIG_STM32_SDMMC2) += stm32_sdmmc2.o
+obj-$(CONFIG_JZ47XX_MMC) += jz_mmc.o
 
 # SDHCI
 obj-$(CONFIG_MMC_SDHCI)			+= sdhci.o
diff --git a/drivers/mmc/jz_mmc.c b/drivers/mmc/jz_mmc.c
new file mode 100644
index 0000000..3132c3e
--- /dev/null
+++ b/drivers/mmc/jz_mmc.c
@@ -0,0 +1,488 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Ingenic JZ MMC driver
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <mmc.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+#include <errno.h>
+#include <mach/jz4780.h>
+#include <wait_bit.h>
+
+/* Registers */
+#define MSC_STRPCL			0x000
+#define MSC_STAT			0x004
+#define MSC_CLKRT			0x008
+#define MSC_CMDAT			0x00c
+#define MSC_RESTO			0x010
+#define MSC_RDTO			0x014
+#define MSC_BLKLEN			0x018
+#define MSC_NOB				0x01c
+#define MSC_SNOB			0x020
+#define MSC_IMASK			0x024
+#define MSC_IREG			0x028
+#define MSC_CMD				0x02c
+#define MSC_ARG				0x030
+#define MSC_RES				0x034
+#define MSC_RXFIFO			0x038
+#define MSC_TXFIFO			0x03c
+#define MSC_LPM				0x040
+#define MSC_DMAC			0x044
+#define MSC_DMANDA			0x048
+#define MSC_DMADA			0x04c
+#define MSC_DMALEN			0x050
+#define MSC_DMACMD			0x054
+#define MSC_CTRL2			0x058
+#define MSC_RTCNT			0x05c
+#define MSC_DBG				0x0fc
+
+/* MSC Clock and Control Register (MSC_STRPCL) */
+#define MSC_STRPCL_EXIT_MULTIPLE	BIT(7)
+#define MSC_STRPCL_EXIT_TRANSFER	BIT(6)
+#define MSC_STRPCL_START_READWAIT	BIT(5)
+#define MSC_STRPCL_STOP_READWAIT	BIT(4)
+#define MSC_STRPCL_RESET		BIT(3)
+#define MSC_STRPCL_START_OP		BIT(2)
+#define MSC_STRPCL_CLOCK_CONTROL_STOP	BIT(0)
+#define MSC_STRPCL_CLOCK_CONTROL_START	BIT(1)
+
+/* MSC Status Register (MSC_STAT) */
+#define MSC_STAT_AUTO_CMD_DONE		BIT(31)
+#define MSC_STAT_IS_RESETTING		BIT(15)
+#define MSC_STAT_SDIO_INT_ACTIVE	BIT(14)
+#define MSC_STAT_PRG_DONE		BIT(13)
+#define MSC_STAT_DATA_TRAN_DONE		BIT(12)
+#define MSC_STAT_END_CMD_RES		BIT(11)
+#define MSC_STAT_DATA_FIFO_AFULL	BIT(10)
+#define MSC_STAT_IS_READWAIT		BIT(9)
+#define MSC_STAT_CLK_EN			BIT(8)
+#define MSC_STAT_DATA_FIFO_FULL		BIT(7)
+#define MSC_STAT_DATA_FIFO_EMPTY	BIT(6)
+#define MSC_STAT_CRC_RES_ERR		BIT(5)
+#define MSC_STAT_CRC_READ_ERROR		BIT(4)
+#define MSC_STAT_CRC_WRITE_ERROR	BIT(2)
+#define MSC_STAT_CRC_WRITE_ERROR_NOSTS	BIT(4)
+#define MSC_STAT_TIME_OUT_RES		BIT(1)
+#define MSC_STAT_TIME_OUT_READ		BIT(0)
+
+/* MSC Bus Clock Control Register (MSC_CLKRT) */
+#define MSC_CLKRT_CLK_RATE_MASK		0x7
+
+/* MSC Command Sequence Control Register (MSC_CMDAT) */
+#define MSC_CMDAT_IO_ABORT		BIT(11)
+#define MSC_CMDAT_BUS_WIDTH_1BIT	(0x0 << 9)
+#define MSC_CMDAT_BUS_WIDTH_4BIT	(0x2 << 9)
+#define MSC_CMDAT_DMA_EN		BIT(8)
+#define MSC_CMDAT_INIT			BIT(7)
+#define MSC_CMDAT_BUSY			BIT(6)
+#define MSC_CMDAT_STREAM_BLOCK		BIT(5)
+#define MSC_CMDAT_WRITE			BIT(4)
+#define MSC_CMDAT_DATA_EN		BIT(3)
+#define MSC_CMDAT_RESPONSE_MASK		(0x7 << 0)
+#define MSC_CMDAT_RESPONSE_NONE		(0x0 << 0) /* No response */
+#define MSC_CMDAT_RESPONSE_R1		(0x1 << 0) /* Format R1 and R1b */
+#define MSC_CMDAT_RESPONSE_R2		(0x2 << 0) /* Format R2 */
+#define MSC_CMDAT_RESPONSE_R3		(0x3 << 0) /* Format R3 */
+#define MSC_CMDAT_RESPONSE_R4		(0x4 << 0) /* Format R4 */
+#define MSC_CMDAT_RESPONSE_R5		(0x5 << 0) /* Format R5 */
+#define MSC_CMDAT_RESPONSE_R6		(0x6 << 0) /* Format R6 */
+
+/* MSC Interrupts Mask Register (MSC_IMASK) */
+#define MSC_IMASK_TIME_OUT_RES		BIT(9)
+#define MSC_IMASK_TIME_OUT_READ		BIT(8)
+#define MSC_IMASK_SDIO			BIT(7)
+#define MSC_IMASK_TXFIFO_WR_REQ		BIT(6)
+#define MSC_IMASK_RXFIFO_RD_REQ		BIT(5)
+#define MSC_IMASK_END_CMD_RES		BIT(2)
+#define MSC_IMASK_PRG_DONE		BIT(1)
+#define MSC_IMASK_DATA_TRAN_DONE	BIT(0)
+
+/* MSC Interrupts Status Register (MSC_IREG) */
+#define MSC_IREG_TIME_OUT_RES		BIT(9)
+#define MSC_IREG_TIME_OUT_READ		BIT(8)
+#define MSC_IREG_SDIO			BIT(7)
+#define MSC_IREG_TXFIFO_WR_REQ		BIT(6)
+#define MSC_IREG_RXFIFO_RD_REQ		BIT(5)
+#define MSC_IREG_END_CMD_RES		BIT(2)
+#define MSC_IREG_PRG_DONE		BIT(1)
+#define MSC_IREG_DATA_TRAN_DONE		BIT(0)
+
+struct jz_mmc_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+struct jz_mmc_priv {
+	void __iomem		*regs;
+	u32			flags;
+/* priv flags */
+#define JZ_MMC_BUS_WIDTH_MASK	0x3
+#define JZ_MMC_BUS_WIDTH_1	0x0
+#define JZ_MMC_BUS_WIDTH_4	0x2
+#define JZ_MMC_BUS_WIDTH_8	0x3
+#define JZ_MMC_SENT_INIT	BIT(2)
+};
+
+static int jz_mmc_clock_rate(void)
+{
+	return 24000000;
+}
+
+static int jz_mmc_send_cmd(struct mmc *mmc, struct jz_mmc_priv *priv,
+			   struct mmc_cmd *cmd, struct mmc_data *data)
+{
+	u32 stat, mask, cmdat = 0;
+	int i, ret;
+
+	/* stop the clock */
+	writel(MSC_STRPCL_CLOCK_CONTROL_STOP, priv->regs + MSC_STRPCL);
+	ret = wait_for_bit_le32(priv->regs + MSC_STAT,
+				MSC_STAT_CLK_EN, false, 10000, false);
+	if (ret)
+		return ret;
+
+	writel(0, priv->regs + MSC_DMAC);
+
+	/* setup command */
+	writel(cmd->cmdidx, priv->regs + MSC_CMD);
+	writel(cmd->cmdarg, priv->regs + MSC_ARG);
+
+	if (data) {
+		/* setup data */
+		cmdat |= MSC_CMDAT_DATA_EN;
+		if (data->flags & MMC_DATA_WRITE)
+			cmdat |= MSC_CMDAT_WRITE;
+
+		writel(data->blocks, priv->regs + MSC_NOB);
+		writel(data->blocksize, priv->regs + MSC_BLKLEN);
+	} else {
+		writel(0, priv->regs + MSC_NOB);
+		writel(0, priv->regs + MSC_BLKLEN);
+	}
+
+	/* setup response */
+	switch (cmd->resp_type) {
+	case MMC_RSP_NONE:
+		break;
+	case MMC_RSP_R1:
+	case MMC_RSP_R1b:
+		cmdat |= MSC_CMDAT_RESPONSE_R1;
+		break;
+	case MMC_RSP_R2:
+		cmdat |= MSC_CMDAT_RESPONSE_R2;
+		break;
+	case MMC_RSP_R3:
+		cmdat |= MSC_CMDAT_RESPONSE_R3;
+		break;
+	default:
+		break;
+	}
+
+	if (cmd->resp_type & MMC_RSP_BUSY)
+		cmdat |= MSC_CMDAT_BUSY;
+
+	/* set init for the first command only */
+	if (!(priv->flags & JZ_MMC_SENT_INIT)) {
+		cmdat |= MSC_CMDAT_INIT;
+		priv->flags |= JZ_MMC_SENT_INIT;
+	}
+
+	cmdat |= (priv->flags & JZ_MMC_BUS_WIDTH_MASK) << 9;
+
+	/* write the data setup */
+	writel(cmdat, priv->regs + MSC_CMDAT);
+
+	/* unmask interrupts */
+	mask = 0xffffffff & ~(MSC_IMASK_END_CMD_RES | MSC_IMASK_TIME_OUT_RES);
+	if (data) {
+		mask &= ~MSC_IMASK_DATA_TRAN_DONE;
+		if (data->flags & MMC_DATA_WRITE) {
+			mask &= ~MSC_IMASK_TXFIFO_WR_REQ;
+		} else {
+			mask &= ~(MSC_IMASK_RXFIFO_RD_REQ |
+				  MSC_IMASK_TIME_OUT_READ);
+		}
+	}
+	writel(mask, priv->regs + MSC_IMASK);
+
+	/* clear interrupts */
+	writel(0xffffffff, priv->regs + MSC_IREG);
+
+	/* start the command (& the clock) */
+	writel(MSC_STRPCL_START_OP | MSC_STRPCL_CLOCK_CONTROL_START,
+	       priv->regs + MSC_STRPCL);
+
+	/* wait for completion */
+	for (i = 0; i < 100; i++) {
+		stat = readl(priv->regs + MSC_IREG);
+		stat &= MSC_IREG_END_CMD_RES | MSC_IREG_TIME_OUT_RES;
+		if (stat)
+			break;
+		mdelay(1);
+	}
+	writel(stat, priv->regs + MSC_IREG);
+	if (stat & MSC_IREG_TIME_OUT_RES)
+		return -ETIMEDOUT;
+
+	if (cmd->resp_type & MMC_RSP_PRESENT) {
+		/* read the response */
+		if (cmd->resp_type & MMC_RSP_136) {
+			u16 a, b, c, i;
+
+			a = readw(priv->regs + MSC_RES);
+			for (i = 0; i < 4; i++) {
+				b = readw(priv->regs + MSC_RES);
+				c = readw(priv->regs + MSC_RES);
+				cmd->response[i] =
+					(a << 24) | (b << 8) | (c >> 8);
+				a = c;
+			}
+		} else {
+			cmd->response[0] = readw(priv->regs + MSC_RES) << 24;
+			cmd->response[0] |= readw(priv->regs + MSC_RES) << 8;
+			cmd->response[0] |= readw(priv->regs + MSC_RES) & 0xff;
+		}
+	}
+
+	if (data && (data->flags & MMC_DATA_WRITE)) {
+		/* write the data */
+		int sz = DIV_ROUND_UP(data->blocks * data->blocksize, 4);
+		const void *buf = data->src;
+
+		while (sz--) {
+			u32 val = get_unaligned_le32(buf);
+
+			wait_for_bit_le32(priv->regs + MSC_IREG,
+					  MSC_IREG_TXFIFO_WR_REQ,
+					  true, 10000, false);
+			writel(val, priv->regs + MSC_TXFIFO);
+			buf += 4;
+		}
+	} else if (data && (data->flags & MMC_DATA_READ)) {
+		/* read the data */
+		int sz = data->blocks * data->blocksize;
+		void *buf = data->dest;
+
+		do {
+			stat = readl(priv->regs + MSC_STAT);
+
+			if (stat & MSC_STAT_TIME_OUT_READ)
+				return -ETIMEDOUT;
+			if (stat & MSC_STAT_CRC_READ_ERROR)
+				return -EINVAL;
+			if (stat & MSC_STAT_DATA_FIFO_EMPTY) {
+				udelay(10);
+				continue;
+			}
+			do {
+				u32 val = readl(priv->regs + MSC_RXFIFO);
+
+				if (sz == 1)
+					*(u8 *)buf = (u8)val;
+				else if (sz == 2)
+					put_unaligned_le16(val, buf);
+				else if (sz >= 4)
+					put_unaligned_le32(val, buf);
+				buf += 4;
+				sz -= 4;
+				stat = readl(priv->regs + MSC_STAT);
+			} while (!(stat & MSC_STAT_DATA_FIFO_EMPTY));
+		} while (!(stat & MSC_STAT_DATA_TRAN_DONE));
+	}
+
+	return 0;
+}
+
+static int jz_mmc_set_ios(struct mmc *mmc, struct jz_mmc_priv *priv)
+{
+	u32 real_rate = jz_mmc_clock_rate();
+	u8 clk_div = 0;
+
+	/* calculate clock divide */
+	while ((real_rate > mmc->clock) && (clk_div < 7)) {
+		real_rate >>= 1;
+		clk_div++;
+	}
+	writel(clk_div & MSC_CLKRT_CLK_RATE_MASK, priv->regs + MSC_CLKRT);
+
+	/* set the bus width for the next command */
+	priv->flags &= ~JZ_MMC_BUS_WIDTH_MASK;
+	if (mmc->bus_width == 8)
+		priv->flags |= JZ_MMC_BUS_WIDTH_8;
+	else if (mmc->bus_width == 4)
+		priv->flags |= JZ_MMC_BUS_WIDTH_4;
+	else
+		priv->flags |= JZ_MMC_BUS_WIDTH_1;
+
+	return 0;
+}
+
+static int jz_mmc_core_init(struct mmc *mmc)
+{
+	struct jz_mmc_priv *priv = mmc->priv;
+	int ret;
+
+	/* Reset */
+	writel(MSC_STRPCL_RESET, priv->regs + MSC_STRPCL);
+	ret = wait_for_bit_le32(priv->regs + MSC_STAT,
+				MSC_STAT_IS_RESETTING, false, 10000, false);
+	if (ret)
+		return ret;
+
+	/* Maximum timeouts */
+	writel(0xffff, priv->regs + MSC_RESTO);
+	writel(0xffffffff, priv->regs + MSC_RDTO);
+
+	/* Enable low power mode */
+	writel(0x1, priv->regs + MSC_LPM);
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(DM_MMC)
+
+static int jz_mmc_legacy_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+				  struct mmc_data *data)
+{
+	struct jz_mmc_priv *priv = mmc->priv;
+
+	return jz_mmc_send_cmd(mmc, priv, cmd, data);
+}
+
+static int jz_mmc_legacy_set_ios(struct mmc *mmc)
+{
+	struct jz_mmc_priv *priv = mmc->priv;
+
+	return jz_mmc_set_ios(mmc, priv);
+};
+
+static const struct mmc_ops jz_msc_ops = {
+	.send_cmd	= jz_mmc_legacy_send_cmd,
+	.set_ios	= jz_mmc_legacy_set_ios,
+	.init		= jz_mmc_core_init,
+};
+
+static struct jz_mmc_priv jz_mmc_priv_static;
+static struct jz_mmc_plat jz_mmc_plat_static = {
+	.cfg = {
+		.name = "MSC",
+		.ops = &jz_msc_ops,
+
+		.voltages = MMC_VDD_27_28 | MMC_VDD_28_29 | MMC_VDD_29_30 |
+			    MMC_VDD_30_31 | MMC_VDD_31_32 | MMC_VDD_32_33 |
+			    MMC_VDD_33_34 | MMC_VDD_34_35 | MMC_VDD_35_36,
+		.host_caps = MMC_MODE_4BIT | MMC_MODE_HS_52MHz | MMC_MODE_HS,
+
+		.f_min = 375000,
+		.f_max = 48000000,
+		.b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT,
+	},
+};
+
+int jz_mmc_init(void __iomem *base)
+{
+	struct mmc *mmc;
+
+	jz_mmc_priv_static.regs = base;
+
+	mmc = mmc_create(&jz_mmc_plat_static.cfg, &jz_mmc_priv_static);
+
+	return mmc ? 0 : -ENODEV;
+}
+
+#else /* CONFIG_DM_MMC */
+
+#include <dm.h>
+DECLARE_GLOBAL_DATA_PTR;
+
+static int jz_mmc_dm_send_cmd(struct udevice *dev, struct mmc_cmd *cmd,
+			      struct mmc_data *data)
+{
+	struct jz_mmc_priv *priv = dev_get_priv(dev);
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+	return jz_mmc_send_cmd(mmc, priv, cmd, data);
+}
+
+static int jz_mmc_dm_set_ios(struct udevice *dev)
+{
+	struct jz_mmc_priv *priv = dev_get_priv(dev);
+	struct mmc *mmc = mmc_get_mmc_dev(dev);
+
+	return jz_mmc_set_ios(mmc, priv);
+};
+
+static const struct dm_mmc_ops jz_msc_ops = {
+	.send_cmd	= jz_mmc_dm_send_cmd,
+	.set_ios	= jz_mmc_dm_set_ios,
+};
+
+static int jz_mmc_ofdata_to_platdata(struct udevice *dev)
+{
+	struct jz_mmc_priv *priv = dev_get_priv(dev);
+	struct jz_mmc_plat *plat = dev_get_platdata(dev);
+	struct mmc_config *cfg;
+	int ret;
+
+	priv->regs = map_physmem(devfdt_get_addr(dev), 0x100, MAP_NOCACHE);
+	cfg = &plat->cfg;
+
+	cfg->name = "MSC";
+	cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS;
+
+	ret = mmc_of_parse(dev, cfg);
+	if (ret < 0) {
+		dev_err(dev, "failed to parse host caps\n");
+		return ret;
+	}
+
+	cfg->f_min = 400000;
+	cfg->f_max = 52000000;
+
+	cfg->voltages = MMC_VDD_32_33 | MMC_VDD_33_34 | MMC_VDD_165_195;
+	cfg->b_max = CONFIG_SYS_MMC_MAX_BLK_COUNT;
+
+	return 0;
+}
+
+static int jz_mmc_bind(struct udevice *dev)
+{
+	struct jz_mmc_plat *plat = dev_get_platdata(dev);
+
+	return mmc_bind(dev, &plat->mmc, &plat->cfg);
+}
+
+static int jz_mmc_probe(struct udevice *dev)
+{
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(dev);
+	struct jz_mmc_priv *priv = dev_get_priv(dev);
+	struct jz_mmc_plat *plat = dev_get_platdata(dev);
+
+	plat->mmc.priv = priv;
+	upriv->mmc = &plat->mmc;
+	return jz_mmc_core_init(&plat->mmc);
+}
+
+static const struct udevice_id jz_mmc_ids[] = {
+	{ .compatible = "ingenic,jz4780-mmc" },
+	{ }
+};
+
+U_BOOT_DRIVER(jz_mmc_drv) = {
+	.name			= "jz_mmc",
+	.id			= UCLASS_MMC,
+	.of_match		= jz_mmc_ids,
+	.ofdata_to_platdata	= jz_mmc_ofdata_to_platdata,
+	.bind			= jz_mmc_bind,
+	.probe			= jz_mmc_probe,
+	.priv_auto_alloc_size	= sizeof(struct jz_mmc_priv),
+	.platdata_auto_alloc_size = sizeof(struct jz_mmc_plat),
+	.ops			= &jz_msc_ops,
+};
+#endif /* CONFIG_DM_MMC */
diff --git a/drivers/mtd/nand/raw/denali.c b/drivers/mtd/nand/raw/denali.c
index d1cac06..e0eb133 100644
--- a/drivers/mtd/nand/raw/denali.c
+++ b/drivers/mtd/nand/raw/denali.c
@@ -69,14 +69,6 @@
 #define DENALI_INVALID_BANK	-1
 #define DENALI_NR_BANKS		4
 
-/*
- * The bus interface clock, clk_x, is phase aligned with the core clock.  The
- * clk_x is an integral multiple N of the core clk.  The value N is configured
- * at IP delivery time, and its available value is 4, 5, or 6.  We need to align
- * to the largest value to make it work with any possible configuration.
- */
-#define DENALI_CLK_X_MULT	6
-
 static inline struct denali_nand_info *mtd_to_denali(struct mtd_info *mtd)
 {
 	return container_of(mtd_to_nand(mtd), struct denali_nand_info, nand);
@@ -595,6 +587,12 @@
 	}
 
 	iowrite32(DMA_ENABLE__FLAG, denali->reg + DMA_ENABLE);
+	/*
+	 * The ->setup_dma() hook kicks DMA by using the data/command
+	 * interface, which belongs to a different AXI port from the
+	 * register interface.  Read back the register to avoid a race.
+	 */
+	ioread32(denali->reg + DMA_ENABLE);
 
 	denali_reset_irq(denali);
 	denali->setup_dma(denali, dma_addr, page, write);
@@ -946,7 +944,7 @@
 {
 	struct denali_nand_info *denali = mtd_to_denali(mtd);
 	const struct nand_sdr_timings *timings;
-	unsigned long t_clk;
+	unsigned long t_x, mult_x;
 	int acc_clks, re_2_we, re_2_re, we_2_re, addr_2_data;
 	int rdwr_en_lo, rdwr_en_hi, rdwr_en_lo_hi, cs_setup;
 	int addr_2_data_mask;
@@ -957,15 +955,24 @@
 		return PTR_ERR(timings);
 
 	/* clk_x period in picoseconds */
-	t_clk = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
-	if (!t_clk)
+	t_x = DIV_ROUND_DOWN_ULL(1000000000000ULL, denali->clk_x_rate);
+	if (!t_x)
+		return -EINVAL;
+
+	/*
+	 * The bus interface clock, clk_x, is phase aligned with the core clock.
+	 * The clk_x is an integral multiple N of the core clk.  The value N is
+	 * configured at IP delivery time, and its available value is 4, 5, 6.
+	 */
+	mult_x = DIV_ROUND_CLOSEST_ULL(denali->clk_x_rate, denali->clk_rate);
+	if (mult_x < 4 || mult_x > 6)
 		return -EINVAL;
 
 	if (chipnr == NAND_DATA_IFACE_CHECK_ONLY)
 		return 0;
 
 	/* tREA -> ACC_CLKS */
-	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_clk);
+	acc_clks = DIV_ROUND_UP(timings->tREA_max, t_x);
 	acc_clks = min_t(int, acc_clks, ACC_CLKS__VALUE);
 
 	tmp = ioread32(denali->reg + ACC_CLKS);
@@ -974,7 +981,7 @@
 	iowrite32(tmp, denali->reg + ACC_CLKS);
 
 	/* tRWH -> RE_2_WE */
-	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_clk);
+	re_2_we = DIV_ROUND_UP(timings->tRHW_min, t_x);
 	re_2_we = min_t(int, re_2_we, RE_2_WE__VALUE);
 
 	tmp = ioread32(denali->reg + RE_2_WE);
@@ -983,7 +990,7 @@
 	iowrite32(tmp, denali->reg + RE_2_WE);
 
 	/* tRHZ -> RE_2_RE */
-	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_clk);
+	re_2_re = DIV_ROUND_UP(timings->tRHZ_max, t_x);
 	re_2_re = min_t(int, re_2_re, RE_2_RE__VALUE);
 
 	tmp = ioread32(denali->reg + RE_2_RE);
@@ -997,8 +1004,7 @@
 	 * With WE_2_RE properly set, the Denali controller automatically takes
 	 * care of the delay; the driver need not set NAND_WAIT_TCCS.
 	 */
-	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min),
-			       t_clk);
+	we_2_re = DIV_ROUND_UP(max(timings->tCCS_min, timings->tWHR_min), t_x);
 	we_2_re = min_t(int, we_2_re, TWHR2_AND_WE_2_RE__WE_2_RE);
 
 	tmp = ioread32(denali->reg + TWHR2_AND_WE_2_RE);
@@ -1013,7 +1019,7 @@
 	if (denali->revision < 0x0501)
 		addr_2_data_mask >>= 1;
 
-	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_clk);
+	addr_2_data = DIV_ROUND_UP(timings->tADL_min, t_x);
 	addr_2_data = min_t(int, addr_2_data, addr_2_data_mask);
 
 	tmp = ioread32(denali->reg + TCWAW_AND_ADDR_2_DATA);
@@ -1023,7 +1029,7 @@
 
 	/* tREH, tWH -> RDWR_EN_HI_CNT */
 	rdwr_en_hi = DIV_ROUND_UP(max(timings->tREH_min, timings->tWH_min),
-				  t_clk);
+				  t_x);
 	rdwr_en_hi = min_t(int, rdwr_en_hi, RDWR_EN_HI_CNT__VALUE);
 
 	tmp = ioread32(denali->reg + RDWR_EN_HI_CNT);
@@ -1032,11 +1038,10 @@
 	iowrite32(tmp, denali->reg + RDWR_EN_HI_CNT);
 
 	/* tRP, tWP -> RDWR_EN_LO_CNT */
-	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min),
-				  t_clk);
+	rdwr_en_lo = DIV_ROUND_UP(max(timings->tRP_min, timings->tWP_min), t_x);
 	rdwr_en_lo_hi = DIV_ROUND_UP(max(timings->tRC_min, timings->tWC_min),
-				     t_clk);
-	rdwr_en_lo_hi = max(rdwr_en_lo_hi, DENALI_CLK_X_MULT);
+				     t_x);
+	rdwr_en_lo_hi = max_t(int, rdwr_en_lo_hi, mult_x);
 	rdwr_en_lo = max(rdwr_en_lo, rdwr_en_lo_hi - rdwr_en_hi);
 	rdwr_en_lo = min_t(int, rdwr_en_lo, RDWR_EN_LO_CNT__VALUE);
 
@@ -1046,8 +1051,8 @@
 	iowrite32(tmp, denali->reg + RDWR_EN_LO_CNT);
 
 	/* tCS, tCEA -> CS_SETUP_CNT */
-	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_clk) - rdwr_en_lo,
-			(int)DIV_ROUND_UP(timings->tCEA_max, t_clk) - acc_clks,
+	cs_setup = max3((int)DIV_ROUND_UP(timings->tCS_min, t_x) - rdwr_en_lo,
+			(int)DIV_ROUND_UP(timings->tCEA_max, t_x) - acc_clks,
 			0);
 	cs_setup = min_t(int, cs_setup, CS_SETUP_CNT__VALUE);
 
diff --git a/drivers/mtd/nand/raw/denali.h b/drivers/mtd/nand/raw/denali.h
index 9b797be..019deda 100644
--- a/drivers/mtd/nand/raw/denali.h
+++ b/drivers/mtd/nand/raw/denali.h
@@ -292,6 +292,7 @@
 
 struct denali_nand_info {
 	struct nand_chip nand;
+	unsigned long clk_rate;		/* core clock rate */
 	unsigned long clk_x_rate;	/* bus interface clock rate */
 	int active_bank;		/* currently selected bank */
 	struct udevice *dev;
diff --git a/drivers/mtd/nand/raw/denali_dt.c b/drivers/mtd/nand/raw/denali_dt.c
index 65a7797..d384b97 100644
--- a/drivers/mtd/nand/raw/denali_dt.c
+++ b/drivers/mtd/nand/raw/denali_dt.c
@@ -62,7 +62,7 @@
 {
 	struct denali_nand_info *denali = dev_get_priv(dev);
 	const struct denali_dt_data *data;
-	struct clk clk;
+	struct clk clk, clk_x, clk_ecc;
 	struct resource res;
 	int ret;
 
@@ -87,15 +87,49 @@
 
 	denali->host = devm_ioremap(dev, res.start, resource_size(&res));
 
-	ret = clk_get_by_index(dev, 0, &clk);
+	ret = clk_get_by_name(dev, "nand", &clk);
+	if (ret)
+		ret = clk_get_by_index(dev, 0, &clk);
 	if (ret)
 		return ret;
 
+	ret = clk_get_by_name(dev, "nand_x", &clk_x);
+	if (ret)
+		clk_x.dev = NULL;
+
+	ret = clk_get_by_name(dev, "ecc", &clk_ecc);
+	if (ret)
+		clk_ecc.dev = NULL;
+
 	ret = clk_enable(&clk);
 	if (ret)
 		return ret;
 
-	denali->clk_x_rate = clk_get_rate(&clk);
+	if (clk_x.dev) {
+		ret = clk_enable(&clk_x);
+		if (ret)
+			return ret;
+	}
+
+	if (clk_ecc.dev) {
+		ret = clk_enable(&clk_ecc);
+		if (ret)
+			return ret;
+	}
+
+	if (clk_x.dev) {
+		denali->clk_rate = clk_get_rate(&clk);
+		denali->clk_x_rate = clk_get_rate(&clk_x);
+	} else {
+		/*
+		 * Hardcode the clock rates for the backward compatibility.
+		 * This works for both SOCFPGA and UniPhier.
+		 */
+		dev_notice(dev,
+			   "necessary clock is missing. default clock rates are used.\n");
+		denali->clk_rate = 50000000;
+		denali->clk_x_rate = 200000000;
+	}
 
 	return denali_init(denali);
 }
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 8fb365f..7044c6a 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -72,6 +72,24 @@
 	  by the BCM_SF2_ETH driver.
 	  Say Y to any bcmcygnus based platforms.
 
+config BCM6348_ETH
+	bool "BCM6348 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select DMA_CHANNELS
+	select MII
+	select PHYLIB
+	help
+	  This driver supports the BCM6348 Ethernet MAC.
+
+config BCM6368_ETH
+	bool "BCM6368 EMAC support"
+	depends on DM_ETH && ARCH_BMIPS
+	select DMA
+	select MII
+	help
+	  This driver supports the BCM6368 Ethernet MAC.
+
 config DWC_ETH_QOS
 	bool "Synopsys DWC Ethernet QOS device support"
 	depends on DM_ETH
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 99056aa..0dbfa03 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -6,6 +6,8 @@
 obj-$(CONFIG_ALTERA_TSE) += altera_tse.o
 obj-$(CONFIG_AG7XXX) += ag7xxx.o
 obj-$(CONFIG_ARMADA100_FEC) += armada100_fec.o
+obj-$(CONFIG_BCM6348_ETH) += bcm6348-eth.o
+obj-$(CONFIG_BCM6368_ETH) += bcm6368-eth.o
 obj-$(CONFIG_DRIVER_AT91EMAC) += at91_emac.o
 obj-$(CONFIG_DRIVER_AX88180) += ax88180.o
 obj-$(CONFIG_BCM_SF2_ETH) += bcm-sf2-eth.o
diff --git a/drivers/net/bcm6348-eth.c b/drivers/net/bcm6348-eth.c
new file mode 100644
index 0000000..7100e68
--- /dev/null
+++ b/drivers/net/bcm6348-eth.c
@@ -0,0 +1,537 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <phy.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_RX_DESC			PKTBUFSRX
+#define ETH_MAX_MTU_SIZE		1518
+#define ETH_TIMEOUT			100
+#define ETH_TX_WATERMARK		32
+
+/* ETH Receiver Configuration register */
+#define ETH_RXCFG_REG			0x00
+#define ETH_RXCFG_ENFLOW_SHIFT		5
+#define ETH_RXCFG_ENFLOW_MASK		(1 << ETH_RXCFG_ENFLOW_SHIFT)
+
+/* ETH Receive Maximum Length register */
+#define ETH_RXMAXLEN_REG		0x04
+#define ETH_RXMAXLEN_SHIFT		0
+#define ETH_RXMAXLEN_MASK		(0x7ff << ETH_RXMAXLEN_SHIFT)
+
+/* ETH Transmit Maximum Length register */
+#define ETH_TXMAXLEN_REG		0x08
+#define ETH_TXMAXLEN_SHIFT		0
+#define ETH_TXMAXLEN_MASK		(0x7ff << ETH_TXMAXLEN_SHIFT)
+
+/* MII Status/Control register */
+#define MII_SC_REG			0x10
+#define MII_SC_MDCFREQDIV_SHIFT		0
+#define MII_SC_MDCFREQDIV_MASK		(0x7f << MII_SC_MDCFREQDIV_SHIFT)
+#define MII_SC_PREAMBLE_EN_SHIFT	7
+#define MII_SC_PREAMBLE_EN_MASK		(1 << MII_SC_PREAMBLE_EN_SHIFT)
+
+/* MII Data register */
+#define MII_DAT_REG			0x14
+#define MII_DAT_DATA_SHIFT		0
+#define MII_DAT_DATA_MASK		(0xffff << MII_DAT_DATA_SHIFT)
+#define MII_DAT_TA_SHIFT		16
+#define MII_DAT_TA_MASK			(0x3 << MII_DAT_TA_SHIFT)
+#define MII_DAT_REG_SHIFT		18
+#define MII_DAT_REG_MASK		(0x1f << MII_DAT_REG_SHIFT)
+#define MII_DAT_PHY_SHIFT		23
+#define MII_DAT_PHY_MASK		(0x1f << MII_DAT_PHY_SHIFT)
+#define MII_DAT_OP_SHIFT		28
+#define MII_DAT_OP_WRITE		(0x5 << MII_DAT_OP_SHIFT)
+#define MII_DAT_OP_READ			(0x6 << MII_DAT_OP_SHIFT)
+
+/* ETH Interrupts Mask register */
+#define ETH_IRMASK_REG			0x18
+
+/* ETH Interrupts register */
+#define ETH_IR_REG			0x1c
+#define ETH_IR_MII_SHIFT		0
+#define ETH_IR_MII_MASK			(1 << ETH_IR_MII_SHIFT)
+
+/* ETH Control register */
+#define ETH_CTL_REG			0x2c
+#define ETH_CTL_ENABLE_SHIFT		0
+#define ETH_CTL_ENABLE_MASK		(1 << ETH_CTL_ENABLE_SHIFT)
+#define ETH_CTL_DISABLE_SHIFT		1
+#define ETH_CTL_DISABLE_MASK		(1 << ETH_CTL_DISABLE_SHIFT)
+#define ETH_CTL_RESET_SHIFT		2
+#define ETH_CTL_RESET_MASK		(1 << ETH_CTL_RESET_SHIFT)
+#define ETH_CTL_EPHY_SHIFT		3
+#define ETH_CTL_EPHY_MASK		(1 << ETH_CTL_EPHY_SHIFT)
+
+/* ETH Transmit Control register */
+#define ETH_TXCTL_REG			0x30
+#define ETH_TXCTL_FD_SHIFT		0
+#define ETH_TXCTL_FD_MASK		(1 << ETH_TXCTL_FD_SHIFT)
+
+/* ETH Transmit Watermask register */
+#define ETH_TXWMARK_REG			0x34
+#define ETH_TXWMARK_WM_SHIFT		0
+#define ETH_TXWMARK_WM_MASK		(0x3f << ETH_TXWMARK_WM_SHIFT)
+
+/* MIB Control register */
+#define MIB_CTL_REG			0x38
+#define MIB_CTL_RDCLEAR_SHIFT		0
+#define MIB_CTL_RDCLEAR_MASK		(1 << MIB_CTL_RDCLEAR_SHIFT)
+
+/* ETH Perfect Match registers */
+#define ETH_PM_CNT			4
+#define ETH_PML_REG(x)			(0x58 + (x) * 0x8)
+#define ETH_PMH_REG(x)			(0x5c + (x) * 0x8)
+#define ETH_PMH_VALID_SHIFT		16
+#define ETH_PMH_VALID_MASK		(1 << ETH_PMH_VALID_SHIFT)
+
+/* MIB Counters registers */
+#define MIB_REG_CNT			55
+#define MIB_REG(x)			(0x200 + (x) * 4)
+
+/* ETH data */
+struct bcm6348_eth_priv {
+	void __iomem *base;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* PHY */
+	int phy_id;
+	struct phy_device *phy_dev;
+};
+
+static void bcm6348_eth_mac_disable(struct bcm6348_eth_priv *priv)
+{
+	/* disable emac */
+	clrsetbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK,
+			ETH_CTL_DISABLE_MASK);
+
+	/* wait until emac is disabled */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_DISABLE_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("%s: error disabling emac\n", __func__);
+}
+
+static void bcm6348_eth_mac_enable(struct bcm6348_eth_priv *priv)
+{
+	setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_ENABLE_MASK);
+}
+
+static void bcm6348_eth_mac_reset(struct bcm6348_eth_priv *priv)
+{
+	/* reset emac */
+	writel_be(ETH_CTL_RESET_MASK, priv->base + ETH_CTL_REG);
+	wmb();
+
+	/* wait until emac is reset */
+	if (wait_for_bit_be32(priv->base + ETH_CTL_REG,
+			      ETH_CTL_RESET_MASK, false,
+			      ETH_TIMEOUT, false))
+		pr_err("%s: error resetting emac\n", __func__);
+}
+
+static int bcm6348_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_prepare_rcv_buf(&priv->rx_dma, packet, len);
+}
+
+static int bcm6348_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_receive(&priv->rx_dma, (void**)packetp, NULL);
+}
+
+static int bcm6348_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_send(&priv->tx_dma, packet, length, NULL);
+}
+
+static int bcm6348_eth_adjust_link(struct udevice *dev,
+				   struct phy_device *phydev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* mac duplex parameters */
+	if (phydev->duplex)
+		setbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+	else
+		clrbits_be32(priv->base + ETH_TXCTL_REG, ETH_TXCTL_FD_MASK);
+
+	/* rx flow control (pause frame handling) */
+	if (phydev->pause)
+		setbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+	else
+		clrbits_be32(priv->base + ETH_RXCFG_REG,
+			     ETH_RXCFG_ENFLOW_MASK);
+
+	return 0;
+}
+
+static int bcm6348_eth_start(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	int ret, i;
+
+	/* prepare rx dma buffers */
+	for (i = 0; i < ETH_RX_DESC; i++) {
+		ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i],
+					  PKTSIZE_ALIGN);
+		if (ret < 0)
+			break;
+	}
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	ret = phy_startup(priv->phy_dev);
+	if (ret) {
+		pr_err("%s: could not initialize phy\n", __func__);
+		return ret;
+	}
+
+	if (!priv->phy_dev->link) {
+		pr_err("%s: no phy link\n", __func__);
+		return -EIO;
+	}
+
+	bcm6348_eth_adjust_link(dev, priv->phy_dev);
+
+	/* zero mib counters */
+	for (i = 0; i < MIB_REG_CNT; i++)
+		writel_be(0, MIB_REG(i));
+
+	/* enable rx flow control */
+	setbits_be32(priv->base + ETH_RXCFG_REG, ETH_RXCFG_ENFLOW_MASK);
+
+	/* set max rx/tx length */
+	writel_be((ETH_MAX_MTU_SIZE << ETH_RXMAXLEN_SHIFT) &
+		  ETH_RXMAXLEN_MASK, priv->base + ETH_RXMAXLEN_REG);
+	writel_be((ETH_MAX_MTU_SIZE << ETH_TXMAXLEN_SHIFT) &
+		  ETH_TXMAXLEN_MASK, priv->base + ETH_TXMAXLEN_REG);
+
+	/* set correct transmit fifo watermark */
+	writel_be((ETH_TX_WATERMARK << ETH_TXWMARK_WM_SHIFT) &
+		  ETH_TXWMARK_WM_MASK, priv->base + ETH_TXWMARK_REG);
+
+	/* enable emac */
+	bcm6348_eth_mac_enable(priv);
+
+	/* clear interrupts */
+	writel_be(0, priv->base + ETH_IRMASK_REG);
+
+	return 0;
+}
+
+static void bcm6348_eth_stop(struct udevice *dev)
+{
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+}
+
+static int bcm6348_eth_write_hwaddr(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	bool running = false;
+
+	/* check if emac is running */
+	if (readl_be(priv->base + ETH_CTL_REG) & ETH_CTL_ENABLE_MASK)
+		running = true;
+
+	/* disable emac */
+	if (running)
+		bcm6348_eth_mac_disable(priv);
+
+	/* set mac address */
+	writel_be((pdata->enetaddr[2] << 24) | (pdata->enetaddr[3]) << 16 |
+		  (pdata->enetaddr[4]) << 8 | (pdata->enetaddr[5]),
+		  priv->base + ETH_PML_REG(0));
+	writel_be((pdata->enetaddr[1]) | (pdata->enetaddr[0] << 8) |
+		  ETH_PMH_VALID_MASK, priv->base + ETH_PMH_REG(0));
+
+	/* enable emac */
+	if (running)
+		bcm6348_eth_mac_enable(priv);
+
+	return 0;
+}
+
+static const struct eth_ops bcm6348_eth_ops = {
+	.free_pkt = bcm6348_eth_free_pkt,
+	.recv = bcm6348_eth_recv,
+	.send = bcm6348_eth_send,
+	.start = bcm6348_eth_start,
+	.stop = bcm6348_eth_stop,
+	.write_hwaddr = bcm6348_eth_write_hwaddr,
+};
+
+static const struct udevice_id bcm6348_eth_ids[] = {
+	{ .compatible = "brcm,bcm6348-enet", },
+	{ /* sentinel */ }
+};
+
+static int bcm6348_mdio_op(void __iomem *base, uint32_t data)
+{
+	/* make sure mii interrupt status is cleared */
+	writel_be(ETH_IR_MII_MASK, base + ETH_IR_REG);
+
+	/* issue mii op */
+	writel_be(data, base + MII_DAT_REG);
+
+	/* wait until emac is disabled */
+	return wait_for_bit_be32(base + ETH_IR_REG,
+				 ETH_IR_MII_MASK, true,
+				 ETH_TIMEOUT, false);
+}
+
+static int bcm6348_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+			     int reg)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_READ;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	val = readl_be(base + MII_DAT_REG) & MII_DAT_DATA_MASK;
+	val >>= MII_DAT_DATA_SHIFT;
+
+	return val;
+}
+
+static int bcm6348_mdio_write(struct mii_dev *bus, int addr, int dev_addr,
+			      int reg, u16 value)
+{
+	void __iomem *base = bus->priv;
+	uint32_t val;
+
+	val = MII_DAT_OP_WRITE;
+	val |= (reg << MII_DAT_REG_SHIFT) & MII_DAT_REG_MASK;
+	val |= (0x2 << MII_DAT_TA_SHIFT) & MII_DAT_TA_MASK;
+	val |= (addr << MII_DAT_PHY_SHIFT) & MII_DAT_PHY_MASK;
+	val |= (value << MII_DAT_DATA_SHIFT) & MII_DAT_DATA_MASK;
+
+	if (bcm6348_mdio_op(base, val)) {
+		pr_err("%s: timeout\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int bcm6348_mdio_init(const char *name, void __iomem *base)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6348_mdio_read;
+	bus->write = bcm6348_mdio_write;
+	bus->priv = base;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6348_phy_init(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct mii_dev *bus;
+
+	/* get mii bus */
+	bus = miiphy_get_dev_by_name(dev->name);
+
+	/* phy connect */
+	priv->phy_dev = phy_connect(bus, priv->phy_id, dev,
+				    pdata->phy_interface);
+	if (!priv->phy_dev) {
+		pr_err("%s: no phy device\n", __func__);
+		return -ENODEV;
+	}
+
+	priv->phy_dev->supported = (SUPPORTED_10baseT_Half |
+				    SUPPORTED_10baseT_Full |
+				    SUPPORTED_100baseT_Half |
+				    SUPPORTED_100baseT_Full |
+				    SUPPORTED_Autoneg |
+				    SUPPORTED_Pause |
+				    SUPPORTED_MII);
+	priv->phy_dev->advertising = priv->phy_dev->supported;
+
+	/* phy config */
+	phy_config(priv->phy_dev);
+
+	return 0;
+}
+
+static int bcm6348_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6348_eth_priv *priv = dev_get_priv(dev);
+	struct ofnode_phandle_args phy;
+	const char *phy_mode;
+	int ret, i;
+
+	/* get base address */
+	priv->base = dev_remap_addr(dev);
+	if (!priv->base)
+		return -EINVAL;
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* get phy mode */
+	pdata->phy_interface = PHY_INTERFACE_MODE_NONE;
+	phy_mode = dev_read_string(dev, "phy-mode");
+	if (phy_mode)
+		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_NONE)
+		return -ENODEV;
+
+	/* get phy */
+	if (dev_read_phandle_with_args(dev, "phy", NULL, 0, 0, &phy))
+		return -ENOENT;
+	priv->phy_id = ofnode_read_u32_default(phy.node, "reg", -1);
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+
+		ret = clk_enable(&clk);
+		if (ret < 0) {
+			pr_err("%s: error enabling clock %d\n", __func__, i);
+			return ret;
+		}
+
+		ret = clk_free(&clk);
+		if (ret < 0) {
+			pr_err("%s: error freeing clock %d\n", __func__, i);
+			return ret;
+		}
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+
+		ret = reset_deassert(&reset);
+		if (ret < 0) {
+			pr_err("%s: error deasserting reset %d\n", __func__, i);
+			return ret;
+		}
+
+		ret = reset_free(&reset);
+		if (ret < 0) {
+			pr_err("%s: error freeing reset %d\n", __func__, i);
+			return ret;
+		}
+	}
+
+	/* disable emac */
+	bcm6348_eth_mac_disable(priv);
+
+	/* reset emac */
+	bcm6348_eth_mac_reset(priv);
+
+	/* select correct mii interface */
+	if (pdata->phy_interface == PHY_INTERFACE_MODE_INTERNAL)
+		clrbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+	else
+		setbits_be32(priv->base + ETH_CTL_REG, ETH_CTL_EPHY_MASK);
+
+	/* turn on mdc clock */
+	writel_be((0x1f << MII_SC_MDCFREQDIV_SHIFT) |
+		  MII_SC_PREAMBLE_EN_MASK, priv->base + MII_SC_REG);
+
+	/* set mib counters to not clear when read */
+	clrbits_be32(priv->base + MIB_CTL_REG, MIB_CTL_RDCLEAR_MASK);
+
+	/* initialize perfect match registers */
+	for (i = 0; i < ETH_PM_CNT; i++) {
+		writel_be(0, priv->base + ETH_PML_REG(i));
+		writel_be(0, priv->base + ETH_PMH_REG(i));
+	}
+
+	/* init mii bus */
+	ret = bcm6348_mdio_init(dev->name, priv->base);
+	if (ret)
+		return ret;
+
+	/* init phy */
+	ret = bcm6348_phy_init(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6348_eth) = {
+	.name = "bcm6348_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6348_eth_ids,
+	.ops = &bcm6348_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6348_eth_priv),
+	.probe = bcm6348_eth_probe,
+};
diff --git a/drivers/net/bcm6368-eth.c b/drivers/net/bcm6368-eth.c
new file mode 100644
index 0000000..a31efba
--- /dev/null
+++ b/drivers/net/bcm6368-eth.c
@@ -0,0 +1,625 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c:
+ *	Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <dma.h>
+#include <miiphy.h>
+#include <net.h>
+#include <reset.h>
+#include <wait_bit.h>
+#include <asm/io.h>
+
+#define ETH_PORT_STR			"brcm,enetsw-port"
+
+#define ETH_RX_DESC			PKTBUFSRX
+#define ETH_ZLEN			60
+#define ETH_TIMEOUT			100
+
+#define ETH_MAX_PORT			8
+#define ETH_RGMII_PORT0			4
+
+/* Port traffic control */
+#define ETH_PTCTRL_REG(x)		(0x0 + (x))
+#define ETH_PTCTRL_RXDIS_SHIFT		0
+#define ETH_PTCTRL_RXDIS_MASK		(1 << ETH_PTCTRL_RXDIS_SHIFT)
+#define ETH_PTCTRL_TXDIS_SHIFT		1
+#define ETH_PTCTRL_TXDIS_MASK		(1 << ETH_PTCTRL_TXDIS_SHIFT)
+
+/* Switch mode register */
+#define ETH_SWMODE_REG			0xb
+#define ETH_SWMODE_FWD_EN_SHIFT		1
+#define ETH_SWMODE_FWD_EN_MASK		(1 << ETH_SWMODE_FWD_EN_SHIFT)
+
+/* IMP override Register */
+#define ETH_IMPOV_REG			0xe
+#define ETH_IMPOV_LINKUP_SHIFT		0
+#define ETH_IMPOV_LINKUP_MASK		(1 << ETH_IMPOV_LINKUP_SHIFT)
+#define ETH_IMPOV_FDX_SHIFT		1
+#define ETH_IMPOV_FDX_MASK		(1 << ETH_IMPOV_FDX_SHIFT)
+#define ETH_IMPOV_100_SHIFT		2
+#define ETH_IMPOV_100_MASK		(1 << ETH_IMPOV_100_SHIFT)
+#define ETH_IMPOV_1000_SHIFT		3
+#define ETH_IMPOV_1000_MASK		(1 << ETH_IMPOV_1000_SHIFT)
+#define ETH_IMPOV_RXFLOW_SHIFT		4
+#define ETH_IMPOV_RXFLOW_MASK		(1 << ETH_IMPOV_RXFLOW_SHIFT)
+#define ETH_IMPOV_TXFLOW_SHIFT		5
+#define ETH_IMPOV_TXFLOW_MASK		(1 << ETH_IMPOV_TXFLOW_SHIFT)
+#define ETH_IMPOV_FORCE_SHIFT		7
+#define ETH_IMPOV_FORCE_MASK		(1 << ETH_IMPOV_FORCE_SHIFT)
+
+/* Port override Register */
+#define ETH_PORTOV_REG(x)		(0x58 + (x))
+#define ETH_PORTOV_LINKUP_SHIFT		0
+#define ETH_PORTOV_LINKUP_MASK		(1 << ETH_PORTOV_LINKUP_SHIFT)
+#define ETH_PORTOV_FDX_SHIFT		1
+#define ETH_PORTOV_FDX_MASK		(1 << ETH_PORTOV_FDX_SHIFT)
+#define ETH_PORTOV_100_SHIFT		2
+#define ETH_PORTOV_100_MASK		(1 << ETH_PORTOV_100_SHIFT)
+#define ETH_PORTOV_1000_SHIFT		3
+#define ETH_PORTOV_1000_MASK		(1 << ETH_PORTOV_1000_SHIFT)
+#define ETH_PORTOV_RXFLOW_SHIFT		4
+#define ETH_PORTOV_RXFLOW_MASK		(1 << ETH_PORTOV_RXFLOW_SHIFT)
+#define ETH_PORTOV_TXFLOW_SHIFT		5
+#define ETH_PORTOV_TXFLOW_MASK		(1 << ETH_PORTOV_TXFLOW_SHIFT)
+#define ETH_PORTOV_ENABLE_SHIFT		6
+#define ETH_PORTOV_ENABLE_MASK		(1 << ETH_PORTOV_ENABLE_SHIFT)
+
+/* Port RGMII control register */
+#define ETH_RGMII_CTRL_REG(x)		(0x60 + (x))
+#define ETH_RGMII_CTRL_GMII_CLK_EN	(1 << 7)
+#define ETH_RGMII_CTRL_MII_OVERRIDE_EN	(1 << 6)
+#define ETH_RGMII_CTRL_MII_MODE_MASK	(3 << 4)
+#define ETH_RGMII_CTRL_RGMII_MODE	(0 << 4)
+#define ETH_RGMII_CTRL_MII_MODE		(1 << 4)
+#define ETH_RGMII_CTRL_RVMII_MODE	(2 << 4)
+#define ETH_RGMII_CTRL_TIMING_SEL_EN	(1 << 0)
+
+/* Port RGMII timing register */
+#define ENETSW_RGMII_TIMING_REG(x)	(0x68 + (x))
+
+/* MDIO control register */
+#define MII_SC_REG			0xb0
+#define MII_SC_EXT_SHIFT		16
+#define MII_SC_EXT_MASK			(1 << MII_SC_EXT_SHIFT)
+#define MII_SC_REG_SHIFT		20
+#define MII_SC_PHYID_SHIFT		25
+#define MII_SC_RD_SHIFT			30
+#define MII_SC_RD_MASK			(1 << MII_SC_RD_SHIFT)
+#define MII_SC_WR_SHIFT			31
+#define MII_SC_WR_MASK			(1 << MII_SC_WR_SHIFT)
+
+/* MDIO data register */
+#define MII_DAT_REG			0xb4
+
+/* Global Management Configuration Register */
+#define ETH_GMCR_REG			0x200
+#define ETH_GMCR_RST_MIB_SHIFT		0
+#define ETH_GMCR_RST_MIB_MASK		(1 << ETH_GMCR_RST_MIB_SHIFT)
+
+/* Jumbo control register port mask register */
+#define ETH_JMBCTL_PORT_REG		0x4004
+
+/* Jumbo control mib good frame register */
+#define ETH_JMBCTL_MAXSIZE_REG		0x4008
+
+/* ETH port data */
+struct bcm_enetsw_port {
+	bool used;
+	const char *name;
+	/* Config */
+	bool bypass_link;
+	int force_speed;
+	bool force_duplex_full;
+	/* PHY */
+	int phy_id;
+};
+
+/* ETH data */
+struct bcm6368_eth_priv {
+	void __iomem *base;
+	/* DMA */
+	struct dma rx_dma;
+	struct dma tx_dma;
+	/* Ports */
+	uint8_t num_ports;
+	struct bcm_enetsw_port used_ports[ETH_MAX_PORT];
+	int sw_port_link[ETH_MAX_PORT];
+	bool rgmii_override;
+	bool rgmii_timing;
+	/* PHY */
+	int phy_id;
+};
+
+static inline bool bcm_enet_port_is_rgmii(int portid)
+{
+	return portid >= ETH_RGMII_PORT0;
+}
+
+static int bcm6368_mdio_read(struct bcm6368_eth_priv *priv, uint8_t ext,
+			     int phy_id, int reg)
+{
+	uint32_t val;
+
+	writel_be(0, priv->base + MII_SC_REG);
+
+	val = MII_SC_RD_MASK |
+	      (phy_id << MII_SC_PHYID_SHIFT) |
+	      (reg << MII_SC_REG_SHIFT);
+
+	if (ext)
+		val |= MII_SC_EXT_MASK;
+
+	writel_be(val, priv->base + MII_SC_REG);
+	udelay(50);
+
+	return readw_be(priv->base + MII_DAT_REG);
+}
+
+static int bcm6368_mdio_write(struct bcm6368_eth_priv *priv, uint8_t ext,
+			      int phy_id, int reg, u16 data)
+{
+	uint32_t val;
+
+	writel_be(0, priv->base + MII_SC_REG);
+
+	val = MII_SC_WR_MASK |
+	      (phy_id << MII_SC_PHYID_SHIFT) |
+	      (reg << MII_SC_REG_SHIFT);
+
+	if (ext)
+		val |= MII_SC_EXT_MASK;
+
+	val |= data;
+
+	writel_be(val, priv->base + MII_SC_REG);
+	udelay(50);
+
+	return 0;
+}
+
+static int bcm6368_eth_free_pkt(struct udevice *dev, uchar *packet, int len)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_prepare_rcv_buf(&priv->rx_dma, packet, len);
+}
+
+static int bcm6368_eth_recv(struct udevice *dev, int flags, uchar **packetp)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+
+	return dma_receive(&priv->rx_dma, (void**)packetp, NULL);
+}
+
+static int bcm6368_eth_send(struct udevice *dev, void *packet, int length)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+
+	/* pad packets smaller than ETH_ZLEN */
+	if (length < ETH_ZLEN) {
+		memset(packet + length, 0, ETH_ZLEN - length);
+		length = ETH_ZLEN;
+	}
+
+	return dma_send(&priv->tx_dma, packet, length, NULL);
+}
+
+static int bcm6368_eth_adjust_link(struct udevice *dev)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+	unsigned int i;
+
+	for (i = 0; i < priv->num_ports; i++) {
+		struct bcm_enetsw_port *port;
+		int val, j, up, adv, lpa, speed, duplex, media;
+		int external_phy = bcm_enet_port_is_rgmii(i);
+		u8 override;
+
+		port = &priv->used_ports[i];
+		if (!port->used)
+			continue;
+
+		if (port->bypass_link)
+			continue;
+
+		/* dummy read to clear */
+		for (j = 0; j < 2; j++)
+			val = bcm6368_mdio_read(priv, external_phy,
+						port->phy_id, MII_BMSR);
+
+		if (val == 0xffff)
+			continue;
+
+		up = (val & BMSR_LSTATUS) ? 1 : 0;
+		if (!(up ^ priv->sw_port_link[i]))
+			continue;
+
+		priv->sw_port_link[i] = up;
+
+		/* link changed */
+		if (!up) {
+			dev_info(&priv->pdev->dev, "link DOWN on %s\n",
+				 port->name);
+			writeb_be(ETH_PORTOV_ENABLE_MASK,
+				  priv->base + ETH_PORTOV_REG(i));
+			writeb_be(ETH_PTCTRL_RXDIS_MASK |
+				  ETH_PTCTRL_TXDIS_MASK,
+				  priv->base + ETH_PTCTRL_REG(i));
+			continue;
+		}
+
+		adv = bcm6368_mdio_read(priv, external_phy,
+					port->phy_id, MII_ADVERTISE);
+
+		lpa = bcm6368_mdio_read(priv, external_phy, port->phy_id,
+					MII_LPA);
+
+		/* figure out media and duplex from advertise and LPA values */
+		media = mii_nway_result(lpa & adv);
+		duplex = (media & ADVERTISE_FULL) ? 1 : 0;
+
+		if (media & (ADVERTISE_100FULL | ADVERTISE_100HALF))
+			speed = 100;
+		else
+			speed = 10;
+
+		if (val & BMSR_ESTATEN) {
+			adv = bcm6368_mdio_read(priv, external_phy,
+						port->phy_id, MII_CTRL1000);
+
+			lpa = bcm6368_mdio_read(priv, external_phy,
+						port->phy_id, MII_STAT1000);
+
+			if ((adv & (ADVERTISE_1000FULL | ADVERTISE_1000HALF)) &&
+			    (lpa & (LPA_1000FULL | LPA_1000HALF))) {
+				speed = 1000;
+				duplex = (lpa & LPA_1000FULL);
+			}
+		}
+
+		pr_alert("link UP on %s, %dMbps, %s-duplex\n",
+			 port->name, speed, duplex ? "full" : "half");
+
+		override = ETH_PORTOV_ENABLE_MASK |
+			   ETH_PORTOV_LINKUP_MASK;
+
+		if (speed == 1000)
+			override |= ETH_PORTOV_1000_MASK;
+		else if (speed == 100)
+			override |= ETH_PORTOV_100_MASK;
+		if (duplex)
+			override |= ETH_PORTOV_FDX_MASK;
+
+		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
+		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
+	}
+
+	return 0;
+}
+
+static int bcm6368_eth_start(struct udevice *dev)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+	uint8_t i;
+
+	/* prepare rx dma buffers */
+	for (i = 0; i < ETH_RX_DESC; i++) {
+		int ret = dma_prepare_rcv_buf(&priv->rx_dma, net_rx_packets[i],
+					      PKTSIZE_ALIGN);
+		if (ret < 0)
+			break;
+	}
+
+	/* enable dma rx channel */
+	dma_enable(&priv->rx_dma);
+
+	/* enable dma tx channel */
+	dma_enable(&priv->tx_dma);
+
+	/* apply override config for bypass_link ports here. */
+	for (i = 0; i < priv->num_ports; i++) {
+		struct bcm_enetsw_port *port;
+		u8 override;
+
+		port = &priv->used_ports[i];
+		if (!port->used)
+			continue;
+
+		if (!port->bypass_link)
+			continue;
+
+		override = ETH_PORTOV_ENABLE_MASK |
+			   ETH_PORTOV_LINKUP_MASK;
+
+		switch (port->force_speed) {
+		case 1000:
+			override |= ETH_PORTOV_1000_MASK;
+			break;
+		case 100:
+			override |= ETH_PORTOV_100_MASK;
+			break;
+		case 10:
+			break;
+		default:
+			pr_warn("%s: invalid forced speed on port %s\n",
+				__func__, port->name);
+			break;
+		}
+
+		if (port->force_duplex_full)
+			override |= ETH_PORTOV_FDX_MASK;
+
+		writeb_be(override, priv->base + ETH_PORTOV_REG(i));
+		writeb_be(0, priv->base + ETH_PTCTRL_REG(i));
+	}
+
+	bcm6368_eth_adjust_link(dev);
+
+	return 0;
+}
+
+static void bcm6368_eth_stop(struct udevice *dev)
+{
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+
+	/* disable dma rx channel */
+	dma_disable(&priv->rx_dma);
+
+	/* disable dma tx channel */
+	dma_disable(&priv->tx_dma);
+}
+
+static const struct eth_ops bcm6368_eth_ops = {
+	.free_pkt = bcm6368_eth_free_pkt,
+	.recv = bcm6368_eth_recv,
+	.send = bcm6368_eth_send,
+	.start = bcm6368_eth_start,
+	.stop = bcm6368_eth_stop,
+};
+
+static const struct udevice_id bcm6368_eth_ids[] = {
+	{ .compatible = "brcm,bcm6368-enet", },
+	{ /* sentinel */ }
+};
+
+static bool bcm6368_phy_is_external(struct bcm6368_eth_priv *priv, int phy_id)
+{
+	uint8_t i;
+
+	for (i = 0; i < priv->num_ports; ++i) {
+		if (!priv->used_ports[i].used)
+			continue;
+		if (priv->used_ports[i].phy_id == phy_id)
+			return bcm_enet_port_is_rgmii(i);
+	}
+
+	return true;
+}
+
+static int bcm6368_mii_mdio_read(struct mii_dev *bus, int addr, int devaddr,
+				 int reg)
+{
+	struct bcm6368_eth_priv *priv = bus->priv;
+	bool ext = bcm6368_phy_is_external(priv, addr);
+
+	return bcm6368_mdio_read(priv, ext, addr, reg);
+}
+
+static int bcm6368_mii_mdio_write(struct mii_dev *bus, int addr, int devaddr,
+				  int reg, u16 data)
+{
+	struct bcm6368_eth_priv *priv = bus->priv;
+	bool ext = bcm6368_phy_is_external(priv, addr);
+
+	return bcm6368_mdio_write(priv, ext, addr, reg, data);
+}
+
+static int bcm6368_mdio_init(const char *name, struct bcm6368_eth_priv *priv)
+{
+	struct mii_dev *bus;
+
+	bus = mdio_alloc();
+	if (!bus) {
+		pr_err("%s: failed to allocate MDIO bus\n", __func__);
+		return -ENOMEM;
+	}
+
+	bus->read = bcm6368_mii_mdio_read;
+	bus->write = bcm6368_mii_mdio_write;
+	bus->priv = priv;
+	snprintf(bus->name, sizeof(bus->name), "%s", name);
+
+	return mdio_register(bus);
+}
+
+static int bcm6368_eth_probe(struct udevice *dev)
+{
+	struct eth_pdata *pdata = dev_get_platdata(dev);
+	struct bcm6368_eth_priv *priv = dev_get_priv(dev);
+	int num_ports, ret, i;
+	uint32_t val;
+	ofnode node;
+
+	/* get base address */
+	priv->base = dev_remap_addr(dev);
+	if (!priv->base)
+		return -EINVAL;
+	pdata->iobase = (phys_addr_t) priv->base;
+
+	/* get number of ports */
+	num_ports = dev_read_u32_default(dev, "brcm,num-ports", ETH_MAX_PORT);
+	if (!num_ports || num_ports > ETH_MAX_PORT)
+		return -EINVAL;
+
+	/* get dma channels */
+	ret = dma_get_by_name(dev, "tx", &priv->tx_dma);
+	if (ret)
+		return -EINVAL;
+
+	ret = dma_get_by_name(dev, "rx", &priv->rx_dma);
+	if (ret)
+		return -EINVAL;
+
+	/* try to enable clocks */
+	for (i = 0; ; i++) {
+		struct clk clk;
+		int ret;
+
+		ret = clk_get_by_index(dev, i, &clk);
+		if (ret < 0)
+			break;
+
+		ret = clk_enable(&clk);
+		if (ret < 0) {
+			pr_err("%s: error enabling clock %d\n", __func__, i);
+			return ret;
+		}
+
+		ret = clk_free(&clk);
+		if (ret < 0) {
+			pr_err("%s: error freeing clock %d\n", __func__, i);
+			return ret;
+		}
+	}
+
+	/* try to perform resets */
+	for (i = 0; ; i++) {
+		struct reset_ctl reset;
+		int ret;
+
+		ret = reset_get_by_index(dev, i, &reset);
+		if (ret < 0)
+			break;
+
+		ret = reset_deassert(&reset);
+		if (ret < 0) {
+			pr_err("%s: error deasserting reset %d\n", __func__, i);
+			return ret;
+		}
+
+		ret = reset_free(&reset);
+		if (ret < 0) {
+			pr_err("%s: error freeing reset %d\n", __func__, i);
+			return ret;
+		}
+	}
+
+	/* set priv data */
+	priv->num_ports = num_ports;
+	if (dev_read_bool(dev, "brcm,rgmii-override"))
+		priv->rgmii_override = true;
+	if (dev_read_bool(dev, "brcm,rgmii-timing"))
+		priv->rgmii_timing = true;
+
+	/* get ports */
+	dev_for_each_subnode(node, dev) {
+		const char *comp;
+		const char *label;
+		unsigned int p;
+		int phy_id;
+		int speed;
+
+		comp = ofnode_read_string(node, "compatible");
+		if (!comp || memcmp(comp, ETH_PORT_STR, sizeof(ETH_PORT_STR)))
+			continue;
+
+		p = ofnode_read_u32_default(node, "reg", ETH_MAX_PORT);
+		if (p >= num_ports)
+			return -EINVAL;
+
+		label = ofnode_read_string(node, "label");
+		if (!label) {
+			debug("%s: node %s has no label\n", __func__,
+			      ofnode_get_name(node));
+			return -EINVAL;
+		}
+
+		phy_id = ofnode_read_u32_default(node, "brcm,phy-id", -1);
+
+		priv->used_ports[p].used = true;
+		priv->used_ports[p].name = label;
+		priv->used_ports[p].phy_id = phy_id;
+
+		if (ofnode_read_bool(node, "full-duplex"))
+			priv->used_ports[p].force_duplex_full = true;
+		if (ofnode_read_bool(node, "bypass-link"))
+			priv->used_ports[p].bypass_link = true;
+		speed = ofnode_read_u32_default(node, "speed", 0);
+		if (speed)
+			priv->used_ports[p].force_speed = speed;
+	}
+
+	/* init mii bus */
+	ret = bcm6368_mdio_init(dev->name, priv);
+	if (ret)
+		return ret;
+
+	/* disable all ports */
+	for (i = 0; i < priv->num_ports; i++) {
+		writeb_be(ETH_PORTOV_ENABLE_MASK,
+			      priv->base + ETH_PORTOV_REG(i));
+		writeb_be(ETH_PTCTRL_RXDIS_MASK |
+			      ETH_PTCTRL_TXDIS_MASK,
+			      priv->base + ETH_PTCTRL_REG(i));
+
+		priv->sw_port_link[i] = 0;
+	}
+
+	/* enable external ports */
+	for (i = ETH_RGMII_PORT0; i < priv->num_ports; i++) {
+		u8 rgmii_ctrl;
+
+		if (!priv->used_ports[i].used)
+			continue;
+
+		rgmii_ctrl = readb_be(priv->base + ETH_RGMII_CTRL_REG(i));
+		rgmii_ctrl |= ETH_RGMII_CTRL_GMII_CLK_EN;
+		if (priv->rgmii_override)
+			rgmii_ctrl |= ETH_RGMII_CTRL_MII_OVERRIDE_EN;
+		if (priv->rgmii_timing)
+			rgmii_ctrl |= ETH_RGMII_CTRL_TIMING_SEL_EN;
+		writeb_be(rgmii_ctrl, priv->base + ETH_RGMII_CTRL_REG(i));
+	}
+
+	/* reset mib */
+	val = readb_be(priv->base + ETH_GMCR_REG);
+	val |= ETH_GMCR_RST_MIB_MASK;
+	writeb_be(val, priv->base + ETH_GMCR_REG);
+	mdelay(1);
+	val &= ~ETH_GMCR_RST_MIB_MASK;
+	writeb_be(val, priv->base + ETH_GMCR_REG);
+	mdelay(1);
+
+	/* force CPU port state */
+	val = readb_be(priv->base + ETH_IMPOV_REG);
+	val |= ETH_IMPOV_FORCE_MASK | ETH_IMPOV_LINKUP_MASK;
+	writeb_be(val, priv->base + ETH_IMPOV_REG);
+
+	/* enable switch forward engine */
+	val = readb_be(priv->base + ETH_SWMODE_REG);
+	val |= ETH_SWMODE_FWD_EN_MASK;
+	writeb_be(val, priv->base + ETH_SWMODE_REG);
+
+	/* enable jumbo on all ports */
+	writel_be(0x1ff, priv->base + ETH_JMBCTL_PORT_REG);
+	writew_be(9728, priv->base + ETH_JMBCTL_MAXSIZE_REG);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(bcm6368_eth) = {
+	.name = "bcm6368_eth",
+	.id = UCLASS_ETH,
+	.of_match = bcm6368_eth_ids,
+	.ops = &bcm6368_eth_ops,
+	.platdata_auto_alloc_size = sizeof(struct eth_pdata),
+	.priv_auto_alloc_size = sizeof(struct bcm6368_eth_priv),
+	.probe = bcm6368_eth_probe,
+};
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index e837eb7..cda4caa 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -656,7 +656,8 @@
 
 	phy_probe(dev);
 
-	bus->phymap[addr] = dev;
+	if (addr >= 0 && addr < PHY_MAX_ADDR)
+		bus->phymap[addr] = dev;
 
 	return dev;
 }
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 3921e39..825ee7c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -164,4 +164,14 @@
 
 	  This PHY is found on OMAP devices supporting USB2.
 
+
+config KEYSTONE_USB_PHY
+	bool "Support TI Keystone USB PHY"
+	depends on PHY
+	depends on ARCH_KEYSTONE
+	help
+	  Support for the USB PHY found on some Keystone (k2) processors
+
+	  This PHY is found on some Keystone (K2) devices supporting USB.
+
 endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 53dd5bd..099551d 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -18,3 +18,4 @@
 obj-$(CONFIG_MESON_GXL_USB_PHY) += meson-gxl-usb2.o meson-gxl-usb3.o
 obj-$(CONFIG_MSM8916_USB_PHY) += msm8916-usbh-phy.o
 obj-$(CONFIG_OMAP_USB2_PHY) += omap-usb2-phy.o
+obj-$(CONFIG_KEYSTONE_USB_PHY) += keystone-usb-phy.o
diff --git a/drivers/phy/keystone-usb-phy.c b/drivers/phy/keystone-usb-phy.c
new file mode 100644
index 0000000..e8146ca
--- /dev/null
+++ b/drivers/phy/keystone-usb-phy.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2017 Texas Instruments Incorporated - http://www.ti.com/
+ * Written by Jean-Jacques Hiblot  <jjhiblot@ti.com>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <dm/device.h>
+#include <generic-phy.h>
+#include <asm/io.h>
+
+/* USB PHY control register offsets */
+#define USB_PHY_CTL_UTMI		0x0000
+#define USB_PHY_CTL_PIPE		0x0004
+#define USB_PHY_CTL_PARAM_1		0x0008
+#define USB_PHY_CTL_PARAM_2		0x000c
+#define USB_PHY_CTL_CLOCK		0x0010
+#define USB_PHY_CTL_PLL			0x0014
+
+#define PHY_OTG_VBUSVLDECTSEL		BIT(16)
+#define PHY_REF_SSP_EN			BIT(29)
+
+struct keystone_usb_phy {
+	void __iomem *reg;
+};
+
+static int keystone_usb_init(struct phy *phy)
+{
+	u32 val;
+	struct udevice *dev = phy->dev;
+	struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+	/*
+	 * VBUSVLDEXTSEL has a default value of 1 in BootCfg but shouldn't.
+	 * It should always be cleared because our USB PHY has an onchip VBUS
+	 * analog comparator.
+	 */
+	val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+	/* quit selecting the vbusvldextsel by default! */
+	val &= ~PHY_OTG_VBUSVLDECTSEL;
+	writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+	return 0;
+}
+
+static int keystone_usb_power_on(struct phy *phy)
+{
+	u32 val;
+	struct udevice *dev = phy->dev;
+	struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+	val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+	val |= PHY_REF_SSP_EN;
+	writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+	return 0;
+}
+
+static int keystone_usb_power_off(struct phy *phy)
+{
+	u32 val;
+	struct udevice *dev = phy->dev;
+	struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+	val = readl(keystone->reg + USB_PHY_CTL_CLOCK);
+	val &= ~PHY_REF_SSP_EN;
+	writel(val, keystone->reg + USB_PHY_CTL_CLOCK);
+
+	return 0;
+}
+
+static int keystone_usb_exit(struct phy *phy)
+{
+	return 0;
+}
+
+static int keystone_usb_phy_probe(struct udevice *dev)
+{
+	struct keystone_usb_phy *keystone = dev_get_priv(dev);
+
+	keystone->reg = dev_remap_addr_index(dev, 0);
+	if (!keystone->reg) {
+		pr_err("unable to remap usb phy\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static const struct udevice_id keystone_usb_phy_ids[] = {
+	{ .compatible = "ti,keystone-usbphy" },
+	{ }
+};
+
+static struct phy_ops keystone_usb_phy_ops = {
+	.init = keystone_usb_init,
+	.power_on = keystone_usb_power_on,
+	.power_off = keystone_usb_power_off,
+	.exit = keystone_usb_exit,
+};
+
+U_BOOT_DRIVER(keystone_usb_phy) = {
+	.name	= "keystone_usb_phy",
+	.id	= UCLASS_PHY,
+	.of_match = keystone_usb_phy_ids,
+	.ops = &keystone_usb_phy_ops,
+	.probe = keystone_usb_phy_probe,
+	.priv_auto_alloc_size = sizeof(struct keystone_usb_phy),
+};
diff --git a/drivers/phy/omap-usb2-phy.c b/drivers/phy/omap-usb2-phy.c
index fd20e8c..be3bb0d 100644
--- a/drivers/phy/omap-usb2-phy.c
+++ b/drivers/phy/omap-usb2-phy.c
@@ -19,6 +19,11 @@
 #define OMAP_DEV_PHY_PD		BIT(0)
 #define OMAP_USB2_PHY_PD	BIT(28)
 
+#define AM437X_USB2_PHY_PD		BIT(0)
+#define AM437X_USB2_OTG_PD		BIT(1)
+#define AM437X_USB2_OTGVDET_EN		BIT(19)
+#define AM437X_USB2_OTGSESSEND_EN	BIT(20)
+
 #define USB2PHY_DISCON_BYP_LATCH	BIT(31)
 #define USB2PHY_ANA_CONFIG1		(0x4c)
 
@@ -60,6 +65,15 @@
 	.power_off = OMAP_USB2_PHY_PD,
 };
 
+static const struct usb_phy_data am437x_usb2_data = {
+	.label = "am437x_usb2",
+	.flags =  0,
+	.mask = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD |
+		AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+	.power_on = AM437X_USB2_OTGVDET_EN | AM437X_USB2_OTGSESSEND_EN,
+	.power_off = AM437X_USB2_PHY_PD | AM437X_USB2_OTG_PD,
+};
+
 static const struct udevice_id omap_usb2_id_table[] = {
 	{
 		.compatible = "ti,omap5-usb2",
@@ -73,6 +87,10 @@
 		.compatible = "ti,dra7x-usb2-phy2",
 		.data = (ulong)&dra7x_usb2_phy2_data,
 	},
+	{
+		.compatible = "ti,am437x-usb2",
+		.data = (ulong)&am437x_usb2_data,
+	},
 	{},
 };
 
@@ -170,20 +188,25 @@
 	}
 
 	regmap = syscon_regmap_lookup_by_phandle(dev, "syscon-phy-power");
-	if (IS_ERR(regmap)) {
-		printf("can't get regmap (err %ld)\n", PTR_ERR(regmap));
-		return PTR_ERR(regmap);
+	if (!IS_ERR(regmap)) {
+		priv->pwr_regmap = regmap;
+		rc =  dev_read_u32_array(dev, "syscon-phy-power", tmp, 2);
+		if (rc) {
+			printf("couldn't get power reg. offset (err %d)\n", rc);
+			return rc;
+		}
+		priv->pwr_reg_offset = tmp[1];
+		return 0;
 	}
-	priv->pwr_regmap = regmap;
-
-	rc =  dev_read_u32_array(dev, "syscon-phy-power", tmp, 2);
-	if (rc) {
-		printf("couldn't get power reg. offset (err %d)\n", rc);
-		return rc;
+	regmap = syscon_regmap_lookup_by_phandle(dev, "ctrl-module");
+	if (!IS_ERR(regmap)) {
+		priv->pwr_regmap = regmap;
+		priv->pwr_reg_offset = 0;
+		return 0;
 	}
-	priv->pwr_reg_offset = tmp[1];
 
-	return 0;
+	printf("can't get regmap (err %ld)\n", PTR_ERR(regmap));
+	return PTR_ERR(regmap);
 }
 
 U_BOOT_DRIVER(omap_usb2_phy) = {
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 7e6fad3..1dbe2b1 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -306,6 +306,7 @@
 source "drivers/pinctrl/renesas/Kconfig"
 source "drivers/pinctrl/uniphier/Kconfig"
 source "drivers/pinctrl/exynos/Kconfig"
+source "drivers/pinctrl/mscc/Kconfig"
 source "drivers/pinctrl/mvebu/Kconfig"
 source "drivers/pinctrl/broadcom/Kconfig"
 
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 293bad3..66d36b9 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -17,6 +17,7 @@
 obj-$(CONFIG_PINCTRL_EXYNOS)	+= exynos/
 obj-$(CONFIG_PINCTRL_MESON)	+= meson/
 obj-$(CONFIG_PINCTRL_MTK)	+= mediatek/
+obj-$(CONFIG_PINCTRL_MSCC)	+= mscc/
 obj-$(CONFIG_ARCH_MVEBU)	+= mvebu/
 obj-$(CONFIG_PINCTRL_SINGLE)	+= pinctrl-single.o
 obj-$(CONFIG_PINCTRL_STI)	+= pinctrl-sti.o
diff --git a/drivers/pinctrl/mscc/Kconfig b/drivers/pinctrl/mscc/Kconfig
new file mode 100644
index 0000000..cfc6c06
--- /dev/null
+++ b/drivers/pinctrl/mscc/Kconfig
@@ -0,0 +1,22 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+config PINCTRL_MSCC
+	bool
+
+config PINCTRL_MSCC_OCELOT
+	depends on SOC_OCELOT && PINCTRL_FULL && OF_CONTROL
+	select PINCTRL_MSCC
+	default y
+	bool "Microsemi ocelot family pin control driver"
+	help
+	   Support pin multiplexing and pin configuration control on
+	   Microsemi ocelot SoCs.
+
+config PINCTRL_MSCC_LUTON
+	depends on SOC_LUTON && PINCTRL_FULL && OF_CONTROL
+	select PINCTRL_MSCC
+	default y
+	bool "Microsemi luton family pin control driver"
+	help
+	   Support pin multiplexing and pin configuration control on
+	   Microsemi luton SoCs.
diff --git a/drivers/pinctrl/mscc/Makefile b/drivers/pinctrl/mscc/Makefile
new file mode 100644
index 0000000..6910671
--- /dev/null
+++ b/drivers/pinctrl/mscc/Makefile
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+obj-y += mscc-common.o
+obj-$(CONFIG_PINCTRL_MSCC_OCELOT) += pinctrl-ocelot.o
+obj-$(CONFIG_PINCTRL_MSCC_LUTON) += pinctrl-luton.o
diff --git a/drivers/pinctrl/mscc/mscc-common.c b/drivers/pinctrl/mscc/mscc-common.c
new file mode 100644
index 0000000..d74b8a6
--- /dev/null
+++ b/drivers/pinctrl/mscc/mscc-common.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs pinctrl driver
+ *
+ * Author: <alexandre.belloni@free-electrons.com>
+ * Author: <gregory.clement@bootlin.com>
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#include <asm/gpio.h>
+#include <asm/system.h>
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/io.h>
+#include "mscc-common.h"
+
+#define MSCC_GPIO_OUT_SET	0x0
+#define MSCC_GPIO_OUT_CLR	0x4
+#define MSCC_GPIO_OUT		0x8
+#define MSCC_GPIO_IN		0xc
+#define MSCC_GPIO_OE		0x10
+#define MSCC_GPIO_INTR		0x14
+#define MSCC_GPIO_INTR_ENA	0x18
+#define MSCC_GPIO_INTR_IDENT	0x1c
+#define MSCC_GPIO_ALT0		0x20
+#define MSCC_GPIO_ALT1		0x24
+
+static int mscc_get_functions_count(struct udevice *dev)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev);
+
+	return info->num_func;
+}
+
+static const char *mscc_get_function_name(struct udevice *dev,
+					  unsigned int function)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev);
+
+	return info->function_names[function];
+}
+
+static int mscc_pin_function_idx(unsigned int pin, unsigned int function,
+				 const struct mscc_pin_data *mscc_pins)
+{
+	struct mscc_pin_caps *p = mscc_pins[pin].drv_data;
+	int i;
+
+	for (i = 0; i < MSCC_FUNC_PER_PIN; i++) {
+		if (function == p->functions[i])
+			return i;
+	}
+
+	return -1;
+}
+
+static int mscc_pinmux_set_mux(struct udevice *dev,
+			       unsigned int pin_selector, unsigned int selector)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev);
+	struct mscc_pin_caps *pin = info->mscc_pins[pin_selector].drv_data;
+	int f;
+
+	f = mscc_pin_function_idx(pin_selector, selector, info->mscc_pins);
+	if (f < 0)
+		return -EINVAL;
+	/*
+	 * f is encoded on two bits.
+	 * bit 0 of f goes in BIT(pin) of ALT0, bit 1 of f goes in BIT(pin) of
+	 * ALT1
+	 * This is racy because both registers can't be updated at the same time
+	 * but it doesn't matter much for now.
+	 */
+	if (f & BIT(0))
+		setbits_le32(info->regs + MSCC_GPIO_ALT0, BIT(pin->pin));
+	else
+		clrbits_le32(info->regs + MSCC_GPIO_ALT0, BIT(pin->pin));
+
+	if (f & BIT(1))
+		setbits_le32(info->regs + MSCC_GPIO_ALT1, BIT(pin->pin - 1));
+	else
+		clrbits_le32(info->regs + MSCC_GPIO_ALT1, BIT(pin->pin - 1));
+
+	return 0;
+}
+
+static int mscc_pctl_get_groups_count(struct udevice *dev)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev);
+
+	return info->num_pins;
+}
+
+static const char *mscc_pctl_get_group_name(struct udevice *dev,
+					    unsigned int group)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev);
+
+	return info->mscc_pins[group].name;
+}
+
+static int mscc_create_group_func_map(struct udevice *dev,
+				      struct mscc_pinctrl *info)
+{
+	u16 pins[info->num_pins];
+	int f, npins, i;
+
+	for (f = 0; f < info->num_func; f++) {
+		for (npins = 0, i = 0; i < info->num_pins; i++) {
+			if (mscc_pin_function_idx(i, f, info->mscc_pins) >= 0)
+				pins[npins++] = i;
+		}
+
+		info->func[f].ngroups = npins;
+		info->func[f].groups = devm_kzalloc(dev, npins *
+						    sizeof(char *), GFP_KERNEL);
+		if (!info->func[f].groups)
+			return -ENOMEM;
+
+		for (i = 0; i < npins; i++)
+			info->func[f].groups[i] = info->mscc_pins[pins[i]].name;
+	}
+
+	return 0;
+}
+
+static int mscc_pinctrl_register(struct udevice *dev, struct mscc_pinctrl *info)
+{
+	int ret;
+
+	ret = mscc_create_group_func_map(dev, info);
+	if (ret) {
+		dev_err(dev, "Unable to create group func map.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int mscc_gpio_get(struct udevice *dev, unsigned int offset)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int val;
+
+	val = readl(info->regs + MSCC_GPIO_IN);
+
+	return !!(val & BIT(offset));
+}
+
+static int mscc_gpio_set(struct udevice *dev, unsigned int offset, int value)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev->parent);
+
+	if (value)
+		writel(BIT(offset), info->regs + MSCC_GPIO_OUT_SET);
+	else
+		writel(BIT(offset), info->regs + MSCC_GPIO_OUT_CLR);
+
+	return 0;
+}
+
+static int mscc_gpio_get_direction(struct udevice *dev, unsigned int offset)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev->parent);
+	unsigned int val;
+
+	val = readl(info->regs + MSCC_GPIO_OE);
+
+	return (val & BIT(offset)) ? GPIOF_OUTPUT : GPIOF_INPUT;
+}
+
+static int mscc_gpio_direction_input(struct udevice *dev, unsigned int offset)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev->parent);
+
+	clrbits_le32(info->regs + MSCC_GPIO_OE, BIT(offset));
+
+	return 0;
+}
+
+static int mscc_gpio_direction_output(struct udevice *dev,
+				      unsigned int offset, int value)
+{
+	struct mscc_pinctrl *info = dev_get_priv(dev->parent);
+
+	setbits_le32(info->regs + MSCC_GPIO_OE, BIT(offset));
+
+	return mscc_gpio_set(dev, offset, value);
+}
+
+const struct dm_gpio_ops mscc_gpio_ops = {
+	.set_value = mscc_gpio_set,
+	.get_value = mscc_gpio_get,
+	.get_function = mscc_gpio_get_direction,
+	.direction_input = mscc_gpio_direction_input,
+	.direction_output = mscc_gpio_direction_output,
+};
+
+const struct pinctrl_ops mscc_pinctrl_ops = {
+	.get_pins_count = mscc_pctl_get_groups_count,
+	.get_pin_name = mscc_pctl_get_group_name,
+	.get_functions_count = mscc_get_functions_count,
+	.get_function_name = mscc_get_function_name,
+	.pinmux_set = mscc_pinmux_set_mux,
+	.set_state = pinctrl_generic_set_state,
+};
+
+int mscc_pinctrl_probe(struct udevice *dev, int num_func,
+		       const struct mscc_pin_data *mscc_pins, int num_pins,
+		       char *const *function_names)
+{
+	struct mscc_pinctrl *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->regs = dev_remap_addr(dev);
+	if (!priv->regs)
+		return -EINVAL;
+
+	priv->func = devm_kzalloc(dev, num_func * sizeof(struct mscc_pmx_func),
+				  GFP_KERNEL);
+	priv->num_func = num_func;
+	priv->mscc_pins = mscc_pins;
+	priv->num_pins = num_pins;
+	priv->function_names = function_names;
+	ret = mscc_pinctrl_register(dev, priv);
+
+	return ret;
+}
diff --git a/drivers/pinctrl/mscc/mscc-common.h b/drivers/pinctrl/mscc/mscc-common.h
new file mode 100644
index 0000000..b0001db
--- /dev/null
+++ b/drivers/pinctrl/mscc/mscc-common.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR MIT) */
+/*
+ * Microsemi SoCs pinctrl driver
+ *
+ * Author: <alexandre.belloni@free-electrons.com>
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#define MSCC_FUNC_PER_PIN	4
+
+struct mscc_pin_caps {
+	unsigned int pin;
+	unsigned char functions[MSCC_FUNC_PER_PIN];
+};
+
+struct mscc_pin_data {
+	const char *name;
+	struct mscc_pin_caps *drv_data;
+};
+
+#define MSCC_P(p, f0, f1, f2)						\
+static struct mscc_pin_caps mscc_pin_##p = {				\
+	.pin = p,							\
+	.functions = {							\
+			FUNC_GPIO, FUNC_##f0, FUNC_##f1, FUNC_##f2,	\
+	},								\
+}
+
+struct mscc_pmx_func {
+	const char **groups;
+	unsigned int ngroups;
+};
+
+struct mscc_pinctrl {
+	struct udevice *dev;
+	struct pinctrl_dev *pctl;
+	void __iomem *regs;
+	struct mscc_pmx_func *func;
+	int num_func;
+	const struct mscc_pin_data *mscc_pins;
+	int num_pins;
+	char * const *function_names;
+};
+
+int mscc_pinctrl_probe(struct udevice *dev, int num_func,
+		       const struct mscc_pin_data *mscc_pins, int num_pins,
+		       char * const *function_names);
+const struct pinctrl_ops mscc_pinctrl_ops;
+
+const struct dm_gpio_ops mscc_gpio_ops;
diff --git a/drivers/pinctrl/mscc/pinctrl-luton.c b/drivers/pinctrl/mscc/pinctrl-luton.c
new file mode 100644
index 0000000..7166588
--- /dev/null
+++ b/drivers/pinctrl/mscc/pinctrl-luton.c
@@ -0,0 +1,172 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs pinctrl driver
+ *
+ * Author: <gregory.clement@bootlin.com>
+ * License: Dual MIT/GPL
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/io.h>
+#include <asm/gpio.h>
+#include <asm/system.h>
+#include "mscc-common.h"
+
+enum {
+	FUNC_NONE,
+	FUNC_GPIO,
+	FUNC_SIO,
+	FUNC_TACHO,
+	FUNC_TWI,
+	FUNC_PHY_LED,
+	FUNC_EXT_IRQ,
+	FUNC_SFP,
+	FUNC_SI,
+	FUNC_PWM,
+	FUNC_UART,
+	FUNC_MAX
+};
+
+static char * const luton_function_names[] = {
+	[FUNC_NONE]		= "none",
+	[FUNC_GPIO]		= "gpio",
+	[FUNC_SIO]		= "sio",
+	[FUNC_TACHO]		= "tacho",
+	[FUNC_TWI]		= "twi",
+	[FUNC_PHY_LED]		= "phy_led",
+	[FUNC_EXT_IRQ]		= "ext_irq",
+	[FUNC_SFP]		= "sfp",
+	[FUNC_SI]		= "si",
+	[FUNC_PWM]		= "pwm",
+	[FUNC_UART]		= "uart",
+};
+
+MSCC_P(0,  SIO,       NONE,      NONE);
+MSCC_P(1,  SIO,       NONE,      NONE);
+MSCC_P(2,  SIO,       NONE,      NONE);
+MSCC_P(3,  SIO,       NONE,      NONE);
+MSCC_P(4,  TACHO,     NONE,      NONE);
+MSCC_P(5,  TWI,       PHY_LED,   NONE);
+MSCC_P(6,  TWI,       PHY_LED,   NONE);
+MSCC_P(7,  NONE,      PHY_LED,   NONE);
+MSCC_P(8,  EXT_IRQ,   PHY_LED,   NONE);
+MSCC_P(9,  EXT_IRQ,   PHY_LED,   NONE);
+MSCC_P(10, SFP,       PHY_LED,   NONE);
+MSCC_P(11, SFP,       PHY_LED,   NONE);
+MSCC_P(12, SFP,       PHY_LED,   NONE);
+MSCC_P(13, SFP,       PHY_LED,   NONE);
+MSCC_P(14, SI,        PHY_LED,   NONE);
+MSCC_P(15, SI,        PHY_LED,   NONE);
+MSCC_P(16, SI,        PHY_LED,   NONE);
+MSCC_P(17, SFP,       PHY_LED,   NONE);
+MSCC_P(18, SFP,       PHY_LED,   NONE);
+MSCC_P(19, SFP,       PHY_LED,   NONE);
+MSCC_P(20, SFP,       PHY_LED,   NONE);
+MSCC_P(21, SFP,       PHY_LED,   NONE);
+MSCC_P(22, SFP,       PHY_LED,   NONE);
+MSCC_P(23, SFP,       PHY_LED,   NONE);
+MSCC_P(24, SFP,       PHY_LED,   NONE);
+MSCC_P(25, SFP,       PHY_LED,   NONE);
+MSCC_P(26, SFP,       PHY_LED,   NONE);
+MSCC_P(27, SFP,       PHY_LED,   NONE);
+MSCC_P(28, SFP,       PHY_LED,   NONE);
+MSCC_P(29, PWM,       NONE,      NONE);
+MSCC_P(30, UART,      NONE,      NONE);
+MSCC_P(31, UART,      NONE,      NONE);
+
+#define LUTON_PIN(n) {						\
+	.name = "GPIO_"#n,					\
+	.drv_data = &mscc_pin_##n				\
+}
+
+static const struct mscc_pin_data luton_pins[] = {
+	LUTON_PIN(0),
+	LUTON_PIN(1),
+	LUTON_PIN(2),
+	LUTON_PIN(3),
+	LUTON_PIN(4),
+	LUTON_PIN(5),
+	LUTON_PIN(6),
+	LUTON_PIN(7),
+	LUTON_PIN(8),
+	LUTON_PIN(9),
+	LUTON_PIN(10),
+	LUTON_PIN(11),
+	LUTON_PIN(12),
+	LUTON_PIN(13),
+	LUTON_PIN(14),
+	LUTON_PIN(15),
+	LUTON_PIN(16),
+	LUTON_PIN(17),
+	LUTON_PIN(18),
+	LUTON_PIN(19),
+	LUTON_PIN(20),
+	LUTON_PIN(21),
+	LUTON_PIN(22),
+	LUTON_PIN(23),
+	LUTON_PIN(24),
+	LUTON_PIN(25),
+	LUTON_PIN(26),
+	LUTON_PIN(27),
+	LUTON_PIN(28),
+	LUTON_PIN(29),
+	LUTON_PIN(30),
+	LUTON_PIN(31),
+};
+
+static int luton_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv;
+
+	uc_priv = dev_get_uclass_priv(dev);
+	uc_priv->bank_name = "luton-gpio";
+	uc_priv->gpio_count = ARRAY_SIZE(luton_pins);
+
+	return 0;
+}
+
+static struct driver luton_gpio_driver = {
+	.name	= "luton-gpio",
+	.id	= UCLASS_GPIO,
+	.probe	= luton_gpio_probe,
+	.ops	= &mscc_gpio_ops,
+};
+
+int luton_pinctrl_probe(struct udevice *dev)
+{
+	int ret;
+
+	ret = mscc_pinctrl_probe(dev, FUNC_MAX, luton_pins,
+				 ARRAY_SIZE(luton_pins), luton_function_names);
+
+	if (ret)
+		return ret;
+
+	ret = device_bind(dev, &luton_gpio_driver, "luton-gpio", NULL,
+			  dev_of_offset(dev), NULL);
+
+	return 0;
+}
+
+static const struct udevice_id luton_pinctrl_of_match[] = {
+	{.compatible = "mscc,luton-pinctrl"},
+	{},
+};
+
+U_BOOT_DRIVER(luton_pinctrl) = {
+	.name = "luton-pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = of_match_ptr(luton_pinctrl_of_match),
+	.probe = luton_pinctrl_probe,
+	.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
+	.ops = &mscc_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/mscc/pinctrl-ocelot.c b/drivers/pinctrl/mscc/pinctrl-ocelot.c
new file mode 100644
index 0000000..10f9b90
--- /dev/null
+++ b/drivers/pinctrl/mscc/pinctrl-ocelot.c
@@ -0,0 +1,188 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Microsemi SoCs pinctrl driver
+ *
+ * Author: <alexandre.belloni@free-electrons.com>
+ * Author: <gregory.clement@bootlin.com>
+ * License: Dual MIT/GPL
+ * Copyright (c) 2017 Microsemi Corporation
+ */
+
+#include <asm/gpio.h>
+#include <asm/system.h>
+#include <common.h>
+#include <config.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/pinctrl.h>
+#include <dm/root.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <linux/io.h>
+#include "mscc-common.h"
+
+enum {
+	FUNC_NONE,
+	FUNC_GPIO,
+	FUNC_IRQ0_IN,
+	FUNC_IRQ0_OUT,
+	FUNC_IRQ1_IN,
+	FUNC_IRQ1_OUT,
+	FUNC_MIIM1,
+	FUNC_PCI_WAKE,
+	FUNC_PTP0,
+	FUNC_PTP1,
+	FUNC_PTP2,
+	FUNC_PTP3,
+	FUNC_PWM,
+	FUNC_RECO_CLK0,
+	FUNC_RECO_CLK1,
+	FUNC_SFP0,
+	FUNC_SFP1,
+	FUNC_SFP2,
+	FUNC_SFP3,
+	FUNC_SFP4,
+	FUNC_SFP5,
+	FUNC_SG0,
+	FUNC_SI,
+	FUNC_TACHO,
+	FUNC_TWI,
+	FUNC_TWI_SCL_M,
+	FUNC_UART,
+	FUNC_UART2,
+	FUNC_MAX
+};
+
+static char * const ocelot_function_names[] = {
+	[FUNC_NONE]		= "none",
+	[FUNC_GPIO]		= "gpio",
+	[FUNC_IRQ0_IN]		= "irq0_in",
+	[FUNC_IRQ0_OUT]		= "irq0_out",
+	[FUNC_IRQ1_IN]		= "irq1_in",
+	[FUNC_IRQ1_OUT]		= "irq1_out",
+	[FUNC_MIIM1]		= "miim1",
+	[FUNC_PCI_WAKE]		= "pci_wake",
+	[FUNC_PTP0]		= "ptp0",
+	[FUNC_PTP1]		= "ptp1",
+	[FUNC_PTP2]		= "ptp2",
+	[FUNC_PTP3]		= "ptp3",
+	[FUNC_PWM]		= "pwm",
+	[FUNC_RECO_CLK0]	= "reco_clk0",
+	[FUNC_RECO_CLK1]	= "reco_clk1",
+	[FUNC_SFP0]		= "sfp0",
+	[FUNC_SFP1]		= "sfp1",
+	[FUNC_SFP2]		= "sfp2",
+	[FUNC_SFP3]		= "sfp3",
+	[FUNC_SFP4]		= "sfp4",
+	[FUNC_SFP5]		= "sfp5",
+	[FUNC_SG0]		= "sg0",
+	[FUNC_SI]		= "si",
+	[FUNC_TACHO]		= "tacho",
+	[FUNC_TWI]		= "twi",
+	[FUNC_TWI_SCL_M]	= "twi_scl_m",
+	[FUNC_UART]		= "uart",
+	[FUNC_UART2]		= "uart2",
+};
+
+MSCC_P(0,  SG0,       NONE,      NONE);
+MSCC_P(1,  SG0,       NONE,      NONE);
+MSCC_P(2,  SG0,       NONE,      NONE);
+MSCC_P(3,  SG0,       NONE,      NONE);
+MSCC_P(4,  IRQ0_IN,   IRQ0_OUT,  TWI);
+MSCC_P(5,  IRQ1_IN,   IRQ1_OUT,  PCI_WAKE);
+MSCC_P(6,  UART,      TWI_SCL_M, NONE);
+MSCC_P(7,  UART,      TWI_SCL_M, NONE);
+MSCC_P(8,  SI,        TWI_SCL_M, IRQ0_OUT);
+MSCC_P(9,  SI,        TWI_SCL_M, IRQ1_OUT);
+MSCC_P(10, PTP2,      TWI_SCL_M, SFP0);
+MSCC_P(11, PTP3,      TWI_SCL_M, SFP1);
+MSCC_P(12, UART2,     TWI_SCL_M, SFP2);
+MSCC_P(13, UART2,     TWI_SCL_M, SFP3);
+MSCC_P(14, MIIM1,     TWI_SCL_M, SFP4);
+MSCC_P(15, MIIM1,     TWI_SCL_M, SFP5);
+MSCC_P(16, TWI,       NONE,      SI);
+MSCC_P(17, TWI,       TWI_SCL_M, SI);
+MSCC_P(18, PTP0,      TWI_SCL_M, NONE);
+MSCC_P(19, PTP1,      TWI_SCL_M, NONE);
+MSCC_P(20, RECO_CLK0, TACHO,     NONE);
+MSCC_P(21, RECO_CLK1, PWM,       NONE);
+
+#define OCELOT_PIN(n) {						\
+	.name = "GPIO_"#n,					\
+	.drv_data = &mscc_pin_##n				\
+}
+
+static const struct mscc_pin_data ocelot_pins[] = {
+	OCELOT_PIN(0),
+	OCELOT_PIN(1),
+	OCELOT_PIN(2),
+	OCELOT_PIN(3),
+	OCELOT_PIN(4),
+	OCELOT_PIN(5),
+	OCELOT_PIN(6),
+	OCELOT_PIN(7),
+	OCELOT_PIN(8),
+	OCELOT_PIN(9),
+	OCELOT_PIN(10),
+	OCELOT_PIN(11),
+	OCELOT_PIN(12),
+	OCELOT_PIN(13),
+	OCELOT_PIN(14),
+	OCELOT_PIN(15),
+	OCELOT_PIN(16),
+	OCELOT_PIN(17),
+	OCELOT_PIN(18),
+	OCELOT_PIN(19),
+	OCELOT_PIN(20),
+	OCELOT_PIN(21),
+};
+
+static int ocelot_gpio_probe(struct udevice *dev)
+{
+	struct gpio_dev_priv *uc_priv;
+
+	uc_priv = dev_get_uclass_priv(dev);
+	uc_priv->bank_name = "ocelot-gpio";
+	uc_priv->gpio_count = ARRAY_SIZE(ocelot_pins);
+
+	return 0;
+}
+
+static struct driver ocelot_gpio_driver = {
+	.name	= "ocelot-gpio",
+	.id	= UCLASS_GPIO,
+	.probe	= ocelot_gpio_probe,
+	.ops	= &mscc_gpio_ops,
+};
+
+int ocelot_pinctrl_probe(struct udevice *dev)
+{
+	int ret;
+
+	ret = mscc_pinctrl_probe(dev, FUNC_MAX, ocelot_pins,
+				 ARRAY_SIZE(ocelot_pins),
+				 ocelot_function_names);
+
+	if (ret)
+		return ret;
+
+	ret = device_bind(dev, &ocelot_gpio_driver, "ocelot-gpio", NULL,
+			  dev_of_offset(dev), NULL);
+
+	return ret;
+}
+
+static const struct udevice_id ocelot_pinctrl_of_match[] = {
+	{.compatible = "mscc,ocelot-pinctrl"},
+	{},
+};
+
+U_BOOT_DRIVER(ocelot_pinctrl) = {
+	.name = "ocelot-pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = of_match_ptr(ocelot_pinctrl_of_match),
+	.probe = ocelot_pinctrl_probe,
+	.priv_auto_alloc_size = sizeof(struct mscc_pinctrl),
+	.ops = &mscc_pinctrl_ops,
+};
diff --git a/drivers/pinctrl/pinctrl-uclass.c b/drivers/pinctrl/pinctrl-uclass.c
index 6db0445..29c910c 100644
--- a/drivers/pinctrl/pinctrl-uclass.c
+++ b/drivers/pinctrl/pinctrl-uclass.c
@@ -117,9 +117,9 @@
 	int ret;
 
 	dev_for_each_subnode(node, dev) {
-		if (pre_reloc_only &&
-		    !ofnode_pre_reloc(node))
+		if (pre_reloc_only ^ ofnode_pre_reloc(node))
 			continue;
+
 		/*
 		 * If this node has "compatible" property, this is not
 		 * a pin configuration node, but a normal device. skip.
diff --git a/drivers/power/regulator/regulator-uclass.c b/drivers/power/regulator/regulator-uclass.c
index 4511625..39e4627 100644
--- a/drivers/power/regulator/regulator-uclass.c
+++ b/drivers/power/regulator/regulator-uclass.c
@@ -113,7 +113,7 @@
 
 	uc_pdata = dev_get_uclass_platdata(dev);
 	if (!enable && uc_pdata->always_on)
-		return -EACCES;
+		return 0;
 
 	return ops->set_enable(dev, enable);
 }
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index 6252dd8..b7ff296 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -343,6 +343,13 @@
 	  start up driver model. The driver will be available until the real
 	  driver model serial is running.
 
+config DEBUG_UART_SIFIVE
+	bool "SiFive UART"
+	help
+	  Select this to enable a debug UART using the serial_sifive driver. You
+	  will need to provide parameters to make this work. The driver will
+	  be available until the real driver-model serial is running.
+
 config DEBUG_UART_STM32
 	bool "STMicroelectronics STM32"
 	depends on STM32_SERIAL
@@ -679,6 +686,12 @@
 	  If you have a machine based on a Marvell XScale PXA2xx CPU you
 	  can enable its onboard serial ports by enabling this option.
 
+config SIFIVE_SERIAL
+	bool "SiFive UART support"
+	depends on DM_SERIAL
+	help
+	  This driver supports the SiFive UART. If unsure say N.
+
 config STI_ASC_SERIAL
 	bool "STMicroelectronics on-chip UART"
 	depends on DM_SERIAL && ARCH_STI
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index 2f8d065..06ee306 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -67,6 +67,7 @@
 obj-$(CONFIG_OWL_SERIAL) += serial_owl.o
 obj-$(CONFIG_OMAP_SERIAL) += serial_omap.o
 obj-$(CONFIG_MTK_SERIAL) += serial_mtk.o
+obj-$(CONFIG_SIFIVE_SERIAL) += serial_sifive.o
 
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_USB_TTY) += usbtty.o
diff --git a/drivers/serial/serial_sifive.c b/drivers/serial/serial_sifive.c
new file mode 100644
index 0000000..341728a
--- /dev/null
+++ b/drivers/serial/serial_sifive.c
@@ -0,0 +1,215 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Anup Patel <anup@brainfault.org>
+ */
+
+#include <clk.h>
+#include <common.h>
+#include <debug_uart.h>
+#include <dm.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <watchdog.h>
+#include <asm/io.h>
+#include <linux/compiler.h>
+#include <serial.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define UART_TXFIFO_FULL	0x80000000
+#define UART_RXFIFO_EMPTY	0x80000000
+#define UART_RXFIFO_DATA	0x000000ff
+#define UART_TXCTRL_TXEN	0x1
+#define UART_RXCTRL_RXEN	0x1
+
+struct uart_sifive {
+	u32 txfifo;
+	u32 rxfifo;
+	u32 txctrl;
+	u32 rxctrl;
+	u32 ie;
+	u32 ip;
+	u32 div;
+};
+
+struct sifive_uart_platdata {
+	unsigned int clock;
+	int saved_input_char;
+	struct uart_sifive *regs;
+};
+
+/* Set up the baud rate in gd struct */
+static void _sifive_serial_setbrg(struct uart_sifive *regs,
+				  unsigned long clock, unsigned long baud)
+{
+	writel((u32)((clock / baud) - 1), &regs->div);
+}
+
+static void _sifive_serial_init(struct uart_sifive *regs)
+{
+	writel(UART_TXCTRL_TXEN, &regs->txctrl);
+	writel(UART_RXCTRL_RXEN, &regs->rxctrl);
+	writel(0, &regs->ie);
+}
+
+static int _sifive_serial_putc(struct uart_sifive *regs, const char c)
+{
+	if (readl(&regs->txfifo) & UART_TXFIFO_FULL)
+		return -EAGAIN;
+
+	writel(c, &regs->txfifo);
+
+	return 0;
+}
+
+static int _sifive_serial_getc(struct uart_sifive *regs)
+{
+	int ch = readl(&regs->rxfifo);
+
+	if (ch & UART_RXFIFO_EMPTY)
+		return -EAGAIN;
+	ch &= UART_RXFIFO_DATA;
+
+	return (!ch) ? -EAGAIN : ch;
+}
+
+static int sifive_serial_setbrg(struct udevice *dev, int baudrate)
+{
+	int err;
+	struct clk clk;
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+	err = clk_get_by_index(dev, 0, &clk);
+	if (!err) {
+		err = clk_get_rate(&clk);
+		if (!IS_ERR_VALUE(err))
+			platdata->clock = err;
+	} else if (err != -ENOENT && err != -ENODEV && err != -ENOSYS) {
+		debug("SiFive UART failed to get clock\n");
+		return err;
+	}
+
+	if (!platdata->clock)
+		platdata->clock = dev_read_u32_default(dev, "clock-frequency", 0);
+	if (!platdata->clock) {
+		debug("SiFive UART clock not defined\n");
+		return -EINVAL;
+	}
+
+	_sifive_serial_setbrg(platdata->regs, platdata->clock, baudrate);
+
+	return 0;
+}
+
+static int sifive_serial_probe(struct udevice *dev)
+{
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+	/* No need to reinitialize the UART after relocation */
+	if (gd->flags & GD_FLG_RELOC)
+		return 0;
+
+	platdata->saved_input_char = 0;
+	_sifive_serial_init(platdata->regs);
+
+	return 0;
+}
+
+static int sifive_serial_getc(struct udevice *dev)
+{
+	int c;
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+	struct uart_sifive *regs = platdata->regs;
+
+	if (platdata->saved_input_char > 0) {
+		c = platdata->saved_input_char;
+		platdata->saved_input_char = 0;
+		return c;
+	}
+
+	while ((c = _sifive_serial_getc(regs)) == -EAGAIN) ;
+
+	return c;
+}
+
+static int sifive_serial_putc(struct udevice *dev, const char ch)
+{
+	int rc;
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+	while ((rc = _sifive_serial_putc(platdata->regs, ch)) == -EAGAIN) ;
+
+	return rc;
+}
+
+static int sifive_serial_pending(struct udevice *dev, bool input)
+{
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+	struct uart_sifive *regs = platdata->regs;
+
+	if (input) {
+		if (platdata->saved_input_char > 0)
+			return 1;
+		platdata->saved_input_char = _sifive_serial_getc(regs);
+		return (platdata->saved_input_char > 0) ? 1 : 0;
+	} else {
+		return !!(readl(&regs->txfifo) & UART_TXFIFO_FULL);
+	}
+}
+
+static int sifive_serial_ofdata_to_platdata(struct udevice *dev)
+{
+	struct sifive_uart_platdata *platdata = dev_get_platdata(dev);
+
+	platdata->regs = (struct uart_sifive *)dev_read_addr(dev);
+	if (IS_ERR(platdata->regs))
+		return PTR_ERR(platdata->regs);
+
+	return 0;
+}
+
+static const struct dm_serial_ops sifive_serial_ops = {
+	.putc = sifive_serial_putc,
+	.getc = sifive_serial_getc,
+	.pending = sifive_serial_pending,
+	.setbrg = sifive_serial_setbrg,
+};
+
+static const struct udevice_id sifive_serial_ids[] = {
+	{ .compatible = "sifive,uart0" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_sifive) = {
+	.name	= "serial_sifive",
+	.id	= UCLASS_SERIAL,
+	.of_match = sifive_serial_ids,
+	.ofdata_to_platdata = sifive_serial_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct sifive_uart_platdata),
+	.probe = sifive_serial_probe,
+	.ops	= &sifive_serial_ops,
+};
+
+#ifdef CONFIG_DEBUG_UART_SIFIVE
+static inline void _debug_uart_init(void)
+{
+	struct uart_sifive *regs =
+			(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
+
+	_sifive_serial_setbrg(regs, CONFIG_DEBUG_UART_CLOCK,
+			      CONFIG_BAUDRATE);
+	_sifive_serial_init(regs);
+}
+
+static inline void _debug_uart_putc(int ch)
+{
+	struct uart_sifive *regs =
+			(struct uart_sifive *)CONFIG_DEBUG_UART_BASE;
+
+	while (_sifive_serial_putc(regs, ch) == -EAGAIN)
+		WATCHDOG_RESET();
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/serial/serial_stm32.c b/drivers/serial/serial_stm32.c
index 31b43ee..e31c87b 100644
--- a/drivers/serial/serial_stm32.c
+++ b/drivers/serial/serial_stm32.c
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <clk.h>
 #include <dm.h>
+#include <reset.h>
 #include <serial.h>
 #include <watchdog.h>
 #include <asm/io.h>
@@ -171,6 +172,7 @@
 {
 	struct stm32x7_serial_platdata *plat = dev_get_platdata(dev);
 	struct clk clk;
+	struct reset_ctl reset;
 	int ret;
 
 	plat->uart_info = (struct stm32_uart_info *)dev_get_driver_data(dev);
@@ -185,6 +187,13 @@
 		return ret;
 	}
 
+	ret = reset_get_by_index(dev, 0, &reset);
+	if (!ret) {
+		reset_assert(&reset);
+		udelay(2);
+		reset_deassert(&reset);
+	}
+
 	plat->clock_rate = clk_get_rate(&clk);
 	if (plat->clock_rate < 0) {
 		clk_disable(&clk);
diff --git a/drivers/sound/Kconfig b/drivers/sound/Kconfig
index 5de86c0..c0d97cc 100644
--- a/drivers/sound/Kconfig
+++ b/drivers/sound/Kconfig
@@ -31,6 +31,14 @@
 	  option provides an implementation for sound_init() and
 	  sound_play().
 
+config SOUND_MAX98090
+	bool "Support Maxim max98090 audio codec"
+	depends on I2S_SAMSUNG
+	help
+	  Enable the max98090 audio codec. This is connected via I2S for
+	  audio data and I2C for codec control. At present it only works
+	  with the Samsung I2S driver.
+
 config SOUND_MAX98095
 	bool "Support Maxim max98095 audio codec"
 	depends on I2S_SAMSUNG
diff --git a/drivers/sound/Makefile b/drivers/sound/Makefile
index 696c5ae..1de4346 100644
--- a/drivers/sound/Makefile
+++ b/drivers/sound/Makefile
@@ -4,8 +4,12 @@
 # R. Chandrasekar <rcsekar@samsung.com>
 
 obj-$(CONFIG_SOUND)	+= sound.o
-obj-$(CONFIG_I2S)	+= sound-i2s.o
+obj-$(CONFIG_SOUND)	+= codec-uclass.o
+obj-$(CONFIG_SOUND)	+= i2s-uclass.o
+obj-$(CONFIG_SOUND)	+= sound-uclass.o
 obj-$(CONFIG_I2S_SAMSUNG)	+= samsung-i2s.o
 obj-$(CONFIG_SOUND_SANDBOX)	+= sandbox.o
+obj-$(CONFIG_I2S_SAMSUNG)	+= samsung_sound.o
 obj-$(CONFIG_SOUND_WM8994)	+= wm8994.o
-obj-$(CONFIG_SOUND_MAX98095)	+= max98095.o
+obj-$(CONFIG_SOUND_MAX98090)	+= max98090.o maxim_codec.o
+obj-$(CONFIG_SOUND_MAX98095)	+= max98095.o maxim_codec.o
diff --git a/drivers/sound/codec-uclass.c b/drivers/sound/codec-uclass.c
new file mode 100644
index 0000000..1ec77ac
--- /dev/null
+++ b/drivers/sound/codec-uclass.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <audio_codec.h>
+
+int audio_codec_set_params(struct udevice *dev, int interface, int rate,
+			   int mclk_freq, int bits_per_sample, uint channels)
+{
+	struct audio_codec_ops *ops = audio_codec_get_ops(dev);
+
+	if (!ops->set_params)
+		return -ENOSYS;
+
+	return ops->set_params(dev, interface, rate, mclk_freq, bits_per_sample,
+			       channels);
+}
+
+UCLASS_DRIVER(audio_codec) = {
+	.id		= UCLASS_AUDIO_CODEC,
+	.name		= "audio-codec",
+};
diff --git a/drivers/sound/i2s-uclass.c b/drivers/sound/i2s-uclass.c
new file mode 100644
index 0000000..b741e39
--- /dev/null
+++ b/drivers/sound/i2s-uclass.c
@@ -0,0 +1,25 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+
+int i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+	struct i2s_ops *ops = i2s_get_ops(dev);
+
+	if (!ops->tx_data)
+		return -ENOSYS;
+
+	return ops->tx_data(dev, data, data_size);
+}
+
+UCLASS_DRIVER(i2s) = {
+	.id		= UCLASS_I2S,
+	.name		= "i2s",
+	.per_device_auto_alloc_size	= sizeof(struct i2s_uc_priv),
+};
diff --git a/drivers/sound/max98090.c b/drivers/sound/max98090.c
new file mode 100644
index 0000000..346ff5f
--- /dev/null
+++ b/drivers/sound/max98090.c
@@ -0,0 +1,377 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * max98090.c -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <div64.h>
+#include <dm.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+#include "max98090.h"
+
+/*
+ * Sets hw params for max98090
+ *
+ * @priv: max98090 information pointer
+ * @rate: Sampling rate
+ * @bits_per_sample: Bits per sample
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_hw_params(struct maxim_priv *priv, unsigned int rate,
+		       unsigned int bits_per_sample)
+{
+	int error;
+	unsigned char value;
+
+	switch (bits_per_sample) {
+	case 16:
+		maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+		error = maxim_bic_or(priv, M98090_REG_INTERFACE_FORMAT,
+				     M98090_WS_MASK, 0);
+		maxim_i2c_read(priv, M98090_REG_INTERFACE_FORMAT, &value);
+		break;
+	default:
+		debug("%s: Illegal bits per sample %d.\n",
+		      __func__, bits_per_sample);
+		return -1;
+	}
+
+	/* Update filter mode */
+	if (rate < 240000)
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_MODE_MASK, 0);
+	else
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_MODE_MASK, M98090_MODE_MASK);
+
+	/* Update sample rate mode */
+	if (rate < 50000)
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_DHF_MASK, 0);
+	else
+		error |= maxim_bic_or(priv, M98090_REG_FILTER_CONFIG,
+				      M98090_DHF_MASK, M98090_DHF_MASK);
+
+	if (error < 0) {
+		debug("%s: Error setting hardware params.\n", __func__);
+		return -EIO;
+	}
+	priv->rate = rate;
+
+	return 0;
+}
+
+/*
+ * Configures Audio interface system clock for the given frequency
+ *
+ * @priv: max98090 information
+ * @freq: Sampling frequency in Hz
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_sysclk(struct maxim_priv *priv, unsigned int freq)
+{
+	int error = 0;
+
+	/* Requested clock frequency is already setup */
+	if (freq == priv->sysclk)
+		return 0;
+
+	/* Setup clocks for slave mode, and using the PLL
+	 * PSCLK = 0x01 (when master clk is 10MHz to 20MHz)
+	 *	0x02 (when master clk is 20MHz to 40MHz)..
+	 *	0x03 (when master clk is 40MHz to 60MHz)..
+	 */
+	if (freq >= 10000000 && freq < 20000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV1);
+	} else if (freq >= 20000000 && freq < 40000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV2);
+	} else if (freq >= 40000000 && freq < 60000000) {
+		error = maxim_i2c_write(priv, M98090_REG_SYSTEM_CLOCK,
+					M98090_PSCLK_DIV4);
+	} else {
+		debug("%s: Invalid master clock frequency\n", __func__);
+		return -1;
+	}
+
+	debug("%s: Clock at %uHz\n", __func__, freq);
+
+	if (error < 0)
+		return -1;
+
+	priv->sysclk = freq;
+
+	return 0;
+}
+
+/*
+ * Sets Max98090 I2S format
+ *
+ * @priv: max98090 information
+ * @fmt: i2S format - supports a subset of the options defined in i2s.h.
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_set_fmt(struct maxim_priv *priv, int fmt)
+{
+	u8 regval = 0;
+	int error = 0;
+
+	if (fmt == priv->fmt)
+		return 0;
+
+	priv->fmt = fmt;
+
+	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+	case SND_SOC_DAIFMT_CBS_CFS:
+		/* Set to slave mode PLL - MAS mode off */
+		error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB,
+					 0x00);
+		error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB,
+					 0x00);
+		error |= maxim_bic_or(priv, M98090_REG_CLOCK_MODE,
+				      M98090_USE_M1_MASK, 0);
+		break;
+	case SND_SOC_DAIFMT_CBM_CFM:
+		/* Set to master mode */
+		debug("Master mode not supported\n");
+		break;
+	case SND_SOC_DAIFMT_CBS_CFM:
+	case SND_SOC_DAIFMT_CBM_CFS:
+	default:
+		debug("%s: Clock mode unsupported\n", __func__);
+		return -EINVAL;
+	}
+
+	error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, regval);
+
+	regval = 0;
+	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+	case SND_SOC_DAIFMT_I2S:
+		regval |= M98090_DLY_MASK;
+		break;
+	case SND_SOC_DAIFMT_LEFT_J:
+		break;
+	case SND_SOC_DAIFMT_RIGHT_J:
+		regval |= M98090_RJ_MASK;
+		break;
+	case SND_SOC_DAIFMT_DSP_A:
+		/* Not supported mode */
+	default:
+		debug("%s: Unrecognized format.\n", __func__);
+		return -EINVAL;
+	}
+
+	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+	case SND_SOC_DAIFMT_NB_NF:
+		break;
+	case SND_SOC_DAIFMT_NB_IF:
+		regval |= M98090_WCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_NF:
+		regval |= M98090_BCI_MASK;
+		break;
+	case SND_SOC_DAIFMT_IB_IF:
+		regval |= M98090_BCI_MASK | M98090_WCI_MASK;
+		break;
+	default:
+		debug("%s: Unrecognized inversion settings.\n", __func__);
+		return -EINVAL;
+	}
+
+	error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, regval);
+
+	if (error < 0) {
+		debug("%s: Error setting i2s format.\n", __func__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * resets the audio codec
+ *
+ * @priv: max98090 information
+ * @return -EIO for error, 0 for success.
+ */
+static int max98090_reset(struct maxim_priv *priv)
+{
+	int ret;
+
+	/*
+	 * Gracefully reset the DSP core and the codec hardware in a proper
+	 * sequence.
+	 */
+	ret = maxim_i2c_write(priv, M98090_REG_SOFTWARE_RESET,
+			      M98090_SWRESET_MASK);
+	if (ret != 0) {
+		debug("%s: Failed to reset DSP: %d\n", __func__, ret);
+		return ret;
+	}
+	mdelay(20);
+
+	return 0;
+}
+
+/*
+ * Initialise max98090 codec device
+ *
+ * @priv: max98090 information
+ *
+ * @return -EIO for error, 0 for success.
+ */
+int max98090_device_init(struct maxim_priv *priv)
+{
+	unsigned char id;
+	int error = 0;
+
+	/* Enable codec clock */
+	set_xclkout();
+
+	/* reset the codec, the DSP core, and disable all interrupts */
+	error = max98090_reset(priv);
+	if (error != 0) {
+		debug("Reset\n");
+		return error;
+	}
+
+	/* initialize private data */
+	priv->sysclk = -1U;
+	priv->rate = -1U;
+	priv->fmt = -1U;
+
+	error = maxim_i2c_read(priv, M98090_REG_REVISION_ID, &id);
+	if (error < 0) {
+		debug("%s: Failure reading hardware revision: %d\n",
+		      __func__, id);
+		return -EIO;
+	}
+	debug("%s: Hardware revision: %d\n", __func__, id);
+
+	return 0;
+}
+
+static int max98090_setup_interface(struct maxim_priv *priv)
+{
+	unsigned char id;
+	int error;
+
+	/* Reading interrupt status to clear them */
+	error = maxim_i2c_read(priv, M98090_REG_DEVICE_STATUS, &id);
+
+	error |= maxim_i2c_write(priv, M98090_REG_DAC_CONTROL,
+				 M98090_DACHP_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_BIAS_CONTROL,
+				 M98090_VCM_MODE_MASK);
+
+	error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_MIXER, 0x1);
+	error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_MIXER, 0x2);
+
+	error |= maxim_i2c_write(priv, M98090_REG_LEFT_SPK_VOLUME, 0x25);
+	error |= maxim_i2c_write(priv, M98090_REG_RIGHT_SPK_VOLUME, 0x25);
+
+	error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_MSB, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_CLOCK_RATIO_NI_LSB, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_MASTER_MODE, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_INTERFACE_FORMAT, 0x0);
+	error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+				 M98090_SDIEN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_DEVICE_SHUTDOWN,
+				 M98090_SHDNN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_OUTPUT_ENABLE,
+				 M98090_HPREN_MASK | M98090_HPLEN_MASK |
+				 M98090_SPREN_MASK | M98090_SPLEN_MASK |
+				 M98090_DAREN_MASK | M98090_DALEN_MASK);
+	error |= maxim_i2c_write(priv, M98090_REG_IO_CONFIGURATION,
+				 M98090_SDOEN_MASK | M98090_SDIEN_MASK);
+
+	if (error < 0)
+		return -EIO;
+
+	return 0;
+}
+
+static int max98090_do_init(struct maxim_priv *priv, int sampling_rate,
+			    int mclk_freq, int bits_per_sample)
+{
+	int ret = 0;
+
+	ret = max98090_setup_interface(priv);
+	if (ret < 0) {
+		debug("%s: max98090 setup interface failed\n", __func__);
+		return ret;
+	}
+
+	ret = max98090_set_sysclk(priv, mclk_freq);
+	if (ret < 0) {
+		debug("%s: max98090 codec set sys clock failed\n", __func__);
+		return ret;
+	}
+
+	ret = max98090_hw_params(priv, sampling_rate, bits_per_sample);
+
+	if (ret == 0) {
+		ret = max98090_set_fmt(priv, SND_SOC_DAIFMT_I2S |
+				       SND_SOC_DAIFMT_NB_NF |
+				       SND_SOC_DAIFMT_CBS_CFS);
+	}
+
+	return ret;
+}
+
+static int max98090_set_params(struct udevice *dev, int interface, int rate,
+			       int mclk_freq, int bits_per_sample,
+			       uint channels)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+
+	return max98090_do_init(priv, rate, mclk_freq, bits_per_sample);
+}
+
+static int max98090_probe(struct udevice *dev)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	priv->dev = dev;
+	ret = max98090_device_init(priv);
+	if (ret < 0) {
+		debug("%s: max98090 codec chip init failed\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct audio_codec_ops max98090_ops = {
+	.set_params	= max98090_set_params,
+};
+
+static const struct udevice_id max98090_ids[] = {
+	{ .compatible = "maxim,max98090" },
+	{ }
+};
+
+U_BOOT_DRIVER(max98090) = {
+	.name		= "max98090",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= max98090_ids,
+	.probe		= max98090_probe,
+	.ops		= &max98090_ops,
+	.priv_auto_alloc_size	= sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98090.h b/drivers/sound/max98090.h
new file mode 100644
index 0000000..3a6983b
--- /dev/null
+++ b/drivers/sound/max98090.h
@@ -0,0 +1,663 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * max98090.h -- MAX98090 ALSA SoC Audio driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#ifndef _MAX98090_H
+#define _MAX98090_H
+
+#include "maxim_codec.h"
+
+/* MAX98090 Registers Definition */
+
+#define M98090_REG_SOFTWARE_RESET               0x00
+#define M98090_REG_DEVICE_STATUS                0x01
+
+#define M98090_REG_QUICK_SAMPLE_RATE            0x05
+#define M98090_REG_DAI_INTERFACE                0x06
+#define M98090_REG_DAC_PATH                     0x07
+
+#define M98090_REG_MIC_BIAS_VOLTAGE		0x12
+#define M98090_REG_DIGITAL_MIC_ENABLE		0x13
+#define M98090_REG_DIGITAL_MIC_CONFIG		0x14
+#define M98090_REG_SYSTEM_CLOCK			0x1B
+#define M98090_REG_CLOCK_RATIO_NI_MSB		0x1D
+#define M98090_REG_CLOCK_MODE			0x1C
+#define M98090_REG_CLOCK_RATIO_NI_LSB		0x1E
+
+#define M98090_REG_MASTER_MODE			0x21
+#define M98090_REG_INTERFACE_FORMAT		0x22
+#define M98090_REG_IO_CONFIGURATION             0x25
+#define M98090_REG_FILTER_CONFIG                0x26
+
+#define M98090_REG_LEFT_HP_MIXER                0x29
+#define M98090_REG_RIGHT_HP_MIXER               0x2a
+#define M98090_REG_HP_CONTROL                   0x2b
+#define M98090_REG_LEFT_HP_VOLUME               0x2c
+#define M98090_REG_RIGHT_HP_VOLUME              0x2d
+#define M98090_REG_LEFT_SPK_MIXER               0x2e
+#define M98090_REG_RIGHT_SPK_MIXER              0x2f
+#define M98090_REG_SPK_CONTROL                  0x30
+#define M98090_REG_LEFT_SPK_VOLUME              0x31
+#define M98090_REG_RIGHT_SPK_VOLUME             0x32
+
+#define M98090_REG_RCV_LOUTL_CONTROL            0x38
+#define M98090_REG_RCV_LOUTL_VOLUME             0x39
+#define M98090_REG_LOUTR_MIXER                  0x3a
+#define M98090_REG_LOUTR_CONTROL                0x3b
+#define M98090_REG_LOUTR_VOLUME                 0x3c
+#define M98090_REG_JACK_DETECT                  0x3d
+#define M98090_REG_INPUT_ENABLE                 0x3e
+#define M98090_REG_OUTPUT_ENABLE                0x3f
+#define M98090_REG_LEVEL_CONTROL                0x40
+#define M98090_REG_DSP_FILTER_ENABLE            0x41
+#define M98090_REG_BIAS_CONTROL                 0x42
+#define M98090_REG_DAC_CONTROL                  0x43
+#define M98090_REG_ADC_CONTROL                  0x44
+#define M98090_REG_DEVICE_SHUTDOWN              0x45
+
+#define M98090_REG_REVISION_ID                  0xff
+
+#define M98090_REG_CNT				(0xff + 1)
+#define M98090_REG_MAX_CACHed			0x45
+
+/* MAX98090 Registers Bit Fields */
+
+/*
+ * M98090_REG_SOFTWARE_RESET		0x00
+ */
+#define M98090_SWRESET_MASK             BIT(7)
+
+/*
+ * M98090_REG_QUICK_SAMPLE_RATE		0x05
+ */
+#define M98090_SR_96K_MASK              BIT(5)
+#define M98090_SR_96K_SHIFT             5
+#define M98090_SR_96K_WIDTH             1
+#define M98090_SR_32K_MASK              BIT(4)
+#define M98090_SR_32K_SHIFT             4
+#define M98090_SR_32K_WIDTH             1
+#define M98090_SR_48K_MASK              BIT(3)
+#define M98090_SR_48K_SHIFT             3
+#define M98090_SR_48K_WIDTH             1
+#define M98090_SR_44K1_MASK             BIT(2)
+#define M98090_SR_44K1_SHIFT            2
+#define M98090_SR_44K1_WIDTH            1
+#define M98090_SR_16K_MASK              BIT(1)
+#define M98090_SR_16K_SHIFT             1
+#define M98090_SR_16K_WIDTH             1
+#define M98090_SR_8K_MASK               BIT(0)
+#define M98090_SR_8K_SHIFT              0
+#define M98090_SR_8K_WIDTH              1
+#define M98090_SR_MASK                  0x3F
+#define M98090_SR_ALL_SHIFT             0
+#define M98090_SR_ALL_WIDTH             8
+#define M98090_SR_ALL_NUM               BIT(M98090_SR_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAI_INTERFACE		0x06
+ */
+#define M98090_RJ_M_MASK                BIT(5)
+#define M98090_RJ_M_SHIFT               5
+#define M98090_RJ_M_WIDTH               1
+#define M98090_RJ_S_MASK                BIT(4)
+#define M98090_RJ_S_SHIFT               4
+#define M98090_RJ_S_WIDTH               1
+#define M98090_LJ_M_MASK                BIT(3)
+#define M98090_LJ_M_SHIFT               3
+#define M98090_LJ_M_WIDTH               1
+#define M98090_LJ_S_MASK                BIT(2)
+#define M98090_LJ_S_SHIFT               2
+#define M98090_LJ_S_WIDTH               1
+#define M98090_I2S_M_MASK               BIT(1)
+#define M98090_I2S_M_SHIFT              1
+#define M98090_I2S_M_WIDTH              1
+#define M98090_I2S_S_MASK               BIT(0)
+#define M98090_I2S_S_SHIFT              0
+#define M98090_I2S_S_WIDTH              1
+#define M98090_DAI_ALL_SHIFT            0
+#define M98090_DAI_ALL_WIDTH            8
+#define M98090_DAI_ALL_NUM              BIT(M98090_DAI_ALL_WIDTH)
+
+/*
+ * M98090_REG_DAC_PATH			0x07
+ */
+#define M98090_DIG2_HP_MASK             BIT(7)
+#define M98090_DIG2_HP_SHIFT            7
+#define M98090_DIG2_HP_WIDTH            1
+#define M98090_DIG2_EAR_MASK            BIT(6)
+#define M98090_DIG2_EAR_SHIFT           6
+#define M98090_DIG2_EAR_WIDTH           1
+#define M98090_DIG2_SPK_MASK            BIT(5)
+#define M98090_DIG2_SPK_SHIFT           5
+#define M98090_DIG2_SPK_WIDTH           1
+#define M98090_DIG2_LOUT_MASK           BIT(4)
+#define M98090_DIG2_LOUT_SHIFT          4
+#define M98090_DIG2_LOUT_WIDTH          1
+#define M98090_DIG2_ALL_SHIFT           0
+#define M98090_DIG2_ALL_WIDTH           8
+#define M98090_DIG2_ALL_NUM             BIT(M98090_DIG2_ALL_WIDTH)
+
+/*
+ * M98090_REG_MIC_BIAS_VOLTAGE		0x12
+ */
+#define M98090_MBVSEL_MASK              (3 << 0)
+#define M98090_MBVSEL_SHIFT             0
+#define M98090_MBVSEL_WIDTH             2
+#define M98090_MBVSEL_2V8               (3 << 0)
+#define M98090_MBVSEL_2V55              (2 << 0)
+#define M98090_MBVSEL_2V4               BIT(0)
+#define M98090_MBVSEL_2V2               (0 << 0)
+
+/*
+ * M98090_REG_DIGITAL_MIC_ENABLE	0x13
+ */
+#define M98090_MICCLK_MASK		(7 << 4)
+#define M98090_MICCLK_SHIFT		4
+#define M98090_MICCLK_WIDTH		3
+#define M98090_DIGMIC4_MASK		BIT(3)
+#define M98090_DIGMIC4_SHIFT		3
+#define M98090_DIGMIC4_WIDTH		1
+#define M98090_DIGMIC4_NUM		BIT(M98090_DIGMIC4_WIDTH)
+#define M98090_DIGMIC3_MASK		BIT(2)
+#define M98090_DIGMIC3_SHIFT		2
+#define M98090_DIGMIC3_WIDTH		1
+#define M98090_DIGMIC3_NUM		BIT(M98090_DIGMIC3_WIDTH)
+#define M98090_DIGMICR_MASK		BIT(1)
+#define M98090_DIGMICR_SHIFT		1
+#define M98090_DIGMICR_WIDTH		1
+#define M98090_DIGMICR_NUM		BIT(M98090_DIGMICR_WIDTH)
+#define M98090_DIGMICL_MASK		BIT(0)
+#define M98090_DIGMICL_SHIFT		0
+#define M98090_DIGMICL_WIDTH		1
+#define M98090_DIGMICL_NUM		BIT(M98090_DIGMICL_WIDTH)
+
+/*
+ * M98090_REG_DIGITAL_MIC_CONFIG	0x14
+ */
+#define M98090_DMIC_COMP_MASK		(15 << 4)
+#define M98090_DMIC_COMP_SHIFT		4
+#define M98090_DMIC_COMP_WIDTH		4
+#define M98090_DMIC_COMP_NUM		BIT(M98090_DMIC_COMP_WIDTH)
+#define M98090_DMIC_FREQ_MASK		(3 << 0)
+#define M98090_DMIC_FREQ_SHIFT		0
+#define M98090_DMIC_FREQ_WIDTH		2
+
+/*
+ * M98090_REG_CLOCK_MODE		0x1B
+ */
+#define M98090_PSCLK_MASK               (3 << 4)
+#define M98090_PSCLK_SHIFT              4
+#define M98090_PSCLK_WIDTH              2
+#define M98090_PSCLK_DISABLED           (0 << 4)
+#define M98090_PSCLK_DIV1               BIT(4)
+#define M98090_PSCLK_DIV2               (2 << 4)
+#define M98090_PSCLK_DIV4               (3 << 4)
+
+/*
+ * M98090_REG_INTERFACE_FORMAT		0x22
+ */
+#define M98090_RJ_MASK			BIT(5)
+#define M98090_RJ_SHIFT			5
+#define M98090_RJ_WIDTH			1
+#define M98090_WCI_MASK			BIT(4)
+#define M98090_WCI_SHIFT		4
+#define M98090_WCI_WIDTH		1
+#define M98090_BCI_MASK			BIT(3)
+#define M98090_BCI_SHIFT		3
+#define M98090_BCI_WIDTH		1
+#define M98090_DLY_MASK			BIT(2)
+#define M98090_DLY_SHIFT		2
+#define M98090_DLY_WIDTH		1
+#define M98090_WS_MASK			(3 << 0)
+#define M98090_WS_SHIFT			0
+#define M98090_WS_WIDTH			2
+#define M98090_WS_NUM			BIT(M98090_WS_WIDTH)
+
+/* M98090_REG_IO_CONFIGURATION	0x25 */
+#define M98090_LTEN_MASK                BIT(5)
+#define M98090_LTEN_SHIFT               5
+#define M98090_LTEN_WIDTH               1
+#define M98090_LTEN_NUM                 BIT(M98090_LTEN_WIDTH)
+#define M98090_LBEN_MASK                BIT(4)
+#define M98090_LBEN_SHIFT               4
+#define M98090_LBEN_WIDTH               1
+#define M98090_LBEN_NUM                 BIT(M98090_LBEN_WIDTH)
+#define M98090_DMONO_MASK               BIT(3)
+#define M98090_DMONO_SHIFT              3
+#define M98090_DMONO_WIDTH              1
+#define M98090_DMONO_NUM                BIT(M98090_DMONO_WIDTH)
+#define M98090_HIZOFF_MASK              BIT(2)
+#define M98090_HIZOFF_SHIFT             2
+#define M98090_HIZOFF_WIDTH             1
+#define M98090_HIZOFF_NUM               BIT(M98090_HIZOFF_WIDTH)
+#define M98090_SDOEN_MASK               BIT(1)
+#define M98090_SDOEN_SHIFT              1
+#define M98090_SDOEN_WIDTH              1
+#define M98090_SDOEN_NUM                BIT(M98090_SDOEN_WIDTH)
+#define M98090_SDIEN_MASK               BIT(0)
+#define M98090_SDIEN_SHIFT              0
+#define M98090_SDIEN_WIDTH              1
+#define M98090_SDIEN_NUM                BIT(M98090_SDIEN_WIDTH)
+
+/*
+ * M98090_REG_FILTER_CONFIG		0x26
+ */
+#define M98090_MODE_MASK                BIT(7)
+#define M98090_MODE_SHIFT               7
+#define M98090_MODE_WIDTH               1
+#define M98090_AHPF_MASK                BIT(6)
+#define M98090_AHPF_SHIFT               6
+#define M98090_AHPF_WIDTH               1
+#define M98090_AHPF_NUM                 BIT(M98090_AHPF_WIDTH)
+#define M98090_DHPF_MASK                BIT(5)
+#define M98090_DHPF_SHIFT               5
+#define M98090_DHPF_WIDTH               1
+#define M98090_DHPF_NUM                 BIT(M98090_DHPF_WIDTH)
+#define M98090_DHF_MASK                 BIT(4)
+#define M98090_DHF_SHIFT                4
+#define M98090_DHF_WIDTH                1
+#define M98090_FLT_DMIC34MODE_MASK      BIT(3)
+#define M98090_FLT_DMIC34MODE_SHIFT     3
+#define M98090_FLT_DMIC34MODE_WIDTH     1
+#define M98090_FLT_DMIC34HPF_MASK       BIT(2)
+#define M98090_FLT_DMIC34HPF_SHIFT      2
+#define M98090_FLT_DMIC34HPF_WIDTH      1
+#define M98090_FLT_DMIC34HPF_NUM        BIT(M98090_FLT_DMIC34HPF_WIDTH)
+
+/*
+ * M98090_REG_CLOCK_MODE
+ */
+#define M98090_FREQ_MASK		(15 << 4)
+#define M98090_FREQ_SHIFT		4
+#define M98090_FREQ_WIDTH		4
+#define M98090_USE_M1_MASK		BIT(0)
+#define M98090_USE_M1_SHIFT		0
+#define M98090_USE_M1_WIDTH		1
+#define M98090_USE_M1_NUM		BIT(M98090_USE_M1_WIDTH)
+
+/*
+ * M98090_REG_LEFT_HP_MIXER		0x29
+ */
+#define M98090_MIXHPL_MIC2_MASK         BIT(5)
+#define M98090_MIXHPL_MIC2_SHIFT        5
+#define M98090_MIXHPL_MIC2_WIDTH        1
+#define M98090_MIXHPL_MIC1_MASK         BIT(4)
+#define M98090_MIXHPL_MIC1_SHIFT        4
+#define M98090_MIXHPL_MIC1_WIDTH        1
+#define M98090_MIXHPL_LINEB_MASK        BIT(3)
+#define M98090_MIXHPL_LINEB_SHIFT       3
+#define M98090_MIXHPL_LINEB_WIDTH       1
+#define M98090_MIXHPL_LINEA_MASK        BIT(2)
+#define M98090_MIXHPL_LINEA_SHIFT       2
+#define M98090_MIXHPL_LINEA_WIDTH       1
+#define M98090_MIXHPL_DACR_MASK         BIT(1)
+#define M98090_MIXHPL_DACR_SHIFT        1
+#define M98090_MIXHPL_DACR_WIDTH        1
+#define M98090_MIXHPL_DACL_MASK         BIT(0)
+#define M98090_MIXHPL_DACL_SHIFT        0
+#define M98090_MIXHPL_DACL_WIDTH        1
+#define M98090_MIXHPL_MASK              (63 << 0)
+#define M98090_MIXHPL_SHIFT             0
+#define M98090_MIXHPL_WIDTH             6
+
+/*
+ * M98090_REG_RIGHT_HP_MIXER		0x2A
+ */
+#define M98090_MIXHPR_MIC2_MASK         BIT(5)
+#define M98090_MIXHPR_MIC2_SHIFT        5
+#define M98090_MIXHPR_MIC2_WIDTH        1
+#define M98090_MIXHPR_MIC1_MASK         BIT(4)
+#define M98090_MIXHPR_MIC1_SHIFT        4
+#define M98090_MIXHPR_MIC1_WIDTH        1
+#define M98090_MIXHPR_LINEB_MASK        BIT(3)
+#define M98090_MIXHPR_LINEB_SHIFT       3
+#define M98090_MIXHPR_LINEB_WIDTH       1
+#define M98090_MIXHPR_LINEA_MASK        BIT(2)
+#define M98090_MIXHPR_LINEA_SHIFT       2
+#define M98090_MIXHPR_LINEA_WIDTH       1
+#define M98090_MIXHPR_DACR_MASK         BIT(1)
+#define M98090_MIXHPR_DACR_SHIFT        1
+#define M98090_MIXHPR_DACR_WIDTH        1
+#define M98090_MIXHPR_DACL_MASK         BIT(0)
+#define M98090_MIXHPR_DACL_SHIFT        0
+#define M98090_MIXHPR_DACL_WIDTH        1
+#define M98090_MIXHPR_MASK              (63 << 0)
+#define M98090_MIXHPR_SHIFT             0
+#define M98090_MIXHPR_WIDTH             6
+
+/*
+ * M98090_REG_LEFT_HP_VOLUME		0x2C
+ */
+#define M98090_HPLM_MASK                BIT(7)
+#define M98090_HPLM_SHIFT               7
+#define M98090_HPLM_WIDTH               1
+#define M98090_HPVOLL_MASK              (31 << 0)
+#define M98090_HPVOLL_SHIFT             0
+#define M98090_HPVOLL_WIDTH             5
+#define M98090_HPVOLL_NUM               BIT(M98090_HPVOLL_WIDTH)
+
+/*
+ * M98090_REG_RIGHT_HP_VOLUME	0x2D
+ */
+#define M98090_HPRM_MASK                BIT(7)
+#define M98090_HPRM_SHIFT               7
+#define M98090_HPRM_WIDTH               1
+#define M98090_HPVOLR_MASK              (31 << 0)
+#define M98090_HPVOLR_SHIFT             0
+#define M98090_HPVOLR_WIDTH             5
+#define M98090_HPVOLR_NUM               BIT(M98090_HPVOLR_WIDTH)
+
+/*
+ * M98090_REG_LEFT_SPK_MIXER		0x2E
+ */
+#define M98090_MIXSPL_MIC2_MASK         BIT(5)
+#define M98090_MIXSPL_MIC2_SHIFT        5
+#define M98090_MIXSPL_MIC2_WIDTH        1
+#define M98090_MIXSPL_MIC1_MASK         BIT(4)
+#define M98090_MIXSPL_MIC1_SHIFT        4
+#define M98090_MIXSPL_MIC1_WIDTH        1
+#define M98090_MIXSPL_LINEB_MASK        BIT(3)
+#define M98090_MIXSPL_LINEB_SHIFT       3
+#define M98090_MIXSPL_LINEB_WIDTH       1
+#define M98090_MIXSPL_LINEA_MASK        BIT(2)
+#define M98090_MIXSPL_LINEA_SHIFT       2
+#define M98090_MIXSPL_LINEA_WIDTH       1
+#define M98090_MIXSPL_DACR_MASK         BIT(1)
+#define M98090_MIXSPL_DACR_SHIFT        1
+#define M98090_MIXSPL_DACR_WIDTH        1
+#define M98090_MIXSPL_DACL_MASK         BIT(0)
+#define M98090_MIXSPL_DACL_SHIFT        0
+#define M98090_MIXSPL_DACL_WIDTH        1
+#define M98090_MIXSPL_MASK              (63 << 0)
+#define M98090_MIXSPL_SHIFT             0
+#define M98090_MIXSPL_WIDTH             6
+#define M98090_MIXSPR_DACR_MASK         BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT        1
+#define M98090_MIXSPR_DACR_WIDTH        1
+
+/*
+ * M98090_REG_RIGHT_SPK_MIXER		0x2F
+ */
+#define M98090_SPK_SLAVE_MASK           BIT(6)
+#define M98090_SPK_SLAVE_SHIFT          6
+#define M98090_SPK_SLAVE_WIDTH          1
+#define M98090_MIXSPR_MIC2_MASK         BIT(5)
+#define M98090_MIXSPR_MIC2_SHIFT        5
+#define M98090_MIXSPR_MIC2_WIDTH        1
+#define M98090_MIXSPR_MIC1_MASK         BIT(4)
+#define M98090_MIXSPR_MIC1_SHIFT        4
+#define M98090_MIXSPR_MIC1_WIDTH        1
+#define M98090_MIXSPR_LINEB_MASK        BIT(3)
+#define M98090_MIXSPR_LINEB_SHIFT       3
+#define M98090_MIXSPR_LINEB_WIDTH       1
+#define M98090_MIXSPR_LINEA_MASK        BIT(2)
+#define M98090_MIXSPR_LINEA_SHIFT       2
+#define M98090_MIXSPR_LINEA_WIDTH       1
+#define M98090_MIXSPR_DACR_MASK         BIT(1)
+#define M98090_MIXSPR_DACR_SHIFT        1
+#define M98090_MIXSPR_DACR_WIDTH        1
+#define M98090_MIXSPR_DACL_MASK         BIT(0)
+#define M98090_MIXSPR_DACL_SHIFT        0
+#define M98090_MIXSPR_DACL_WIDTH        1
+#define M98090_MIXSPR_MASK              (63 << 0)
+#define M98090_MIXSPR_SHIFT             0
+#define M98090_MIXSPR_WIDTH             6
+
+/*
+ * M98090_REG_LEFT_SPK_VOLUME		0x31
+ */
+#define M98090_SPLM_MASK                BIT(7)
+#define M98090_SPLM_SHIFT               7
+#define M98090_SPLM_WIDTH               1
+#define M98090_SPVOLL_MASK              (63 << 0)
+#define M98090_SPVOLL_SHIFT             0
+#define M98090_SPVOLL_WIDTH             6
+#define M98090_SPVOLL_NUM               40
+
+/*
+ * M98090_REG_RIGHT_SPK_VOLUME		0x32
+ */
+#define M98090_SPRM_MASK                BIT(7)
+#define M98090_SPRM_SHIFT               7
+#define M98090_SPRM_WIDTH               1
+#define M98090_SPVOLR_MASK              (63 << 0)
+#define M98090_SPVOLR_SHIFT             0
+#define M98090_SPVOLR_WIDTH             6
+#define M98090_SPVOLR_NUM               40
+
+/*
+ * M98090_REG_RCV_LOUTL_MIXER		0x37
+ */
+#define M98090_MIXRCVL_MIC2_MASK        BIT(5)
+#define M98090_MIXRCVL_MIC2_SHIFT       5
+#define M98090_MIXRCVL_MIC2_WIDTH       1
+#define M98090_MIXRCVL_MIC1_MASK        BIT(4)
+#define M98090_MIXRCVL_MIC1_SHIFT       4
+#define M98090_MIXRCVL_MIC1_WIDTH       1
+#define M98090_MIXRCVL_LINEB_MASK       BIT(3)
+#define M98090_MIXRCVL_LINEB_SHIFT      3
+#define M98090_MIXRCVL_LINEB_WIDTH      1
+#define M98090_MIXRCVL_LINEA_MASK       BIT(2)
+#define M98090_MIXRCVL_LINEA_SHIFT      2
+#define M98090_MIXRCVL_LINEA_WIDTH      1
+#define M98090_MIXRCVL_DACR_MASK        BIT(1)
+#define M98090_MIXRCVL_DACR_SHIFT       1
+#define M98090_MIXRCVL_DACR_WIDTH       1
+#define M98090_MIXRCVL_DACL_MASK        BIT(0)
+#define M98090_MIXRCVL_DACL_SHIFT       0
+#define M98090_MIXRCVL_DACL_WIDTH       1
+#define M98090_MIXRCVL_MASK             (63 << 0)
+#define M98090_MIXRCVL_SHIFT            0
+#define M98090_MIXRCVL_WIDTH            6
+
+/*
+ * M98090_REG_RCV_LOUTL_CONTROL		0x38
+ */
+#define M98090_MIXRCVLG_MASK            (3 << 0)
+#define M98090_MIXRCVLG_SHIFT           0
+#define M98090_MIXRCVLG_WIDTH           2
+#define M98090_MIXRCVLG_NUM             BIT(M98090_MIXRCVLG_WIDTH)
+
+/*
+ * M98090_REG_RCV_LOUTL_VOLUME		0x39
+ */
+#define M98090_RCVLM_MASK               BIT(7)
+#define M98090_RCVLM_SHIFT              7
+#define M98090_RCVLM_WIDTH              1
+#define M98090_RCVLVOL_MASK             (31 << 0)
+#define M98090_RCVLVOL_SHIFT            0
+#define M98090_RCVLVOL_WIDTH            5
+#define M98090_RCVLVOL_NUM              BIT(M98090_RCVLVOL_WIDTH)
+
+/*
+ * M98090_REG_LOUTR_MIXER		0x3A
+ */
+#define M98090_LINMOD_MASK              BIT(7)
+#define M98090_LINMOD_SHIFT             7
+#define M98090_LINMOD_WIDTH             1
+#define M98090_MIXRCVR_MIC2_MASK        BIT(5)
+#define M98090_MIXRCVR_MIC2_SHIFT       5
+#define M98090_MIXRCVR_MIC2_WIDTH       1
+#define M98090_MIXRCVR_MIC1_MASK        BIT(4)
+#define M98090_MIXRCVR_MIC1_SHIFT       4
+#define M98090_MIXRCVR_MIC1_WIDTH       1
+#define M98090_MIXRCVR_LINEB_MASK       BIT(3)
+#define M98090_MIXRCVR_LINEB_SHIFT      3
+#define M98090_MIXRCVR_LINEB_WIDTH      1
+#define M98090_MIXRCVR_LINEA_MASK       BIT(2)
+#define M98090_MIXRCVR_LINEA_SHIFT      2
+#define M98090_MIXRCVR_LINEA_WIDTH      1
+#define M98090_MIXRCVR_DACR_MASK        BIT(1)
+#define M98090_MIXRCVR_DACR_SHIFT       1
+#define M98090_MIXRCVR_DACR_WIDTH       1
+#define M98090_MIXRCVR_DACL_MASK        BIT(0)
+#define M98090_MIXRCVR_DACL_SHIFT       0
+#define M98090_MIXRCVR_DACL_WIDTH       1
+#define M98090_MIXRCVR_MASK             (63 << 0)
+#define M98090_MIXRCVR_SHIFT            0
+#define M98090_MIXRCVR_WIDTH            6
+
+/*
+ * M98090_REG_LOUTR_VOLUME		0x3C
+ */
+#define M98090_RCVRM_MASK               BIT(7)
+#define M98090_RCVRM_SHIFT              7
+#define M98090_RCVRM_WIDTH              1
+#define M98090_RCVRVOL_MASK             (31 << 0)
+#define M98090_RCVRVOL_SHIFT            0
+#define M98090_RCVRVOL_WIDTH            5
+#define M98090_RCVRVOL_NUM              BIT(M98090_RCVRVOL_WIDTH)
+
+/*
+ * M98090_REG_JACK_DETECT		0x3D
+ */
+#define M98090_JDETEN_MASK              BIT(7)
+#define M98090_JDETEN_SHIFT             7
+#define M98090_JDETEN_WIDTH             1
+#define M98090_JDWK_MASK                BIT(6)
+#define M98090_JDWK_SHIFT               6
+#define M98090_JDWK_WIDTH               1
+#define M98090_JDEB_MASK                (3 << 0)
+#define M98090_JDEB_SHIFT               0
+#define M98090_JDEB_WIDTH               2
+#define M98090_JDEB_25MS                (0 << 0)
+#define M98090_JDEB_50MS                BIT(0)
+#define M98090_JDEB_100MS               (2 << 0)
+#define M98090_JDEB_200MS               (3 << 0)
+
+/*
+ * M98090_REG_INPUT_ENABLE		0x3E
+ */
+#define M98090_MBEN_MASK                BIT(4)
+#define M98090_MBEN_SHIFT               4
+#define M98090_MBEN_WIDTH               1
+#define M98090_LINEAEN_MASK             BIT(3)
+#define M98090_LINEAEN_SHIFT            3
+#define M98090_LINEAEN_WIDTH            1
+#define M98090_LINEBEN_MASK             BIT(2)
+#define M98090_LINEBEN_SHIFT            2
+#define M98090_LINEBEN_WIDTH            1
+#define M98090_ADREN_MASK               BIT(1)
+#define M98090_ADREN_SHIFT              1
+#define M98090_ADREN_WIDTH              1
+#define M98090_ADLEN_MASK               BIT(0)
+#define M98090_ADLEN_SHIFT              0
+#define M98090_ADLEN_WIDTH              1
+
+/*
+ * M98090_REG_OUTPUT_ENABLE		0x3F
+ */
+#define M98090_HPREN_MASK               BIT(7)
+#define M98090_HPREN_SHIFT              7
+#define M98090_HPREN_WIDTH              1
+#define M98090_HPLEN_MASK               BIT(6)
+#define M98090_HPLEN_SHIFT              6
+#define M98090_HPLEN_WIDTH              1
+#define M98090_SPREN_MASK               BIT(5)
+#define M98090_SPREN_SHIFT              5
+#define M98090_SPREN_WIDTH              1
+#define M98090_SPLEN_MASK               BIT(4)
+#define M98090_SPLEN_SHIFT              4
+#define M98090_SPLEN_WIDTH              1
+#define M98090_RCVLEN_MASK              BIT(3)
+#define M98090_RCVLEN_SHIFT             3
+#define M98090_RCVLEN_WIDTH             1
+#define M98090_RCVREN_MASK              BIT(2)
+#define M98090_RCVREN_SHIFT             2
+#define M98090_RCVREN_WIDTH             1
+#define M98090_DAREN_MASK               BIT(1)
+#define M98090_DAREN_SHIFT              1
+#define M98090_DAREN_WIDTH              1
+#define M98090_DALEN_MASK               BIT(0)
+#define M98090_DALEN_SHIFT              0
+#define M98090_DALEN_WIDTH              1
+
+/*
+ * M98090_REG_LEVEL_CONTROL		0x40
+ */
+#define M98090_ZDENN_MASK               BIT(2)
+#define M98090_ZDENN_SHIFT              2
+#define M98090_ZDENN_WIDTH              1
+#define M98090_ZDENN_NUM                BIT(M98090_ZDENN_WIDTH)
+#define M98090_VS2ENN_MASK              BIT(1)
+#define M98090_VS2ENN_SHIFT             1
+#define M98090_VS2ENN_WIDTH             1
+#define M98090_VS2ENN_NUM               BIT(M98090_VS2ENN_WIDTH)
+#define M98090_VSENN_MASK               BIT(0)
+#define M98090_VSENN_SHIFT              0
+#define M98090_VSENN_WIDTH              1
+#define M98090_VSENN_NUM                BIT(M98090_VSENN_WIDTH)
+
+/*
+ * M98090_REG_BIAS_CONTROL		0x42
+ */
+#define M98090_VCM_MODE_MASK            BIT(0)
+#define M98090_VCM_MODE_SHIFT           0
+#define M98090_VCM_MODE_WIDTH           1
+#define M98090_VCM_MODE_NUM             BIT(M98090_VCM_MODE_WIDTH)
+
+/*
+ * M98090_REG_DAC_CONTROL		0x43
+ */
+#define M98090_PERFMODE_MASK            BIT(1)
+#define M98090_PERFMODE_SHIFT           1
+#define M98090_PERFMODE_WIDTH           1
+#define M98090_PERFMODE_NUM             BIT(M98090_PERFMODE_WIDTH)
+#define M98090_DACHP_MASK               BIT(0)
+#define M98090_DACHP_SHIFT              0
+#define M98090_DACHP_WIDTH              1
+#define M98090_DACHP_NUM                BIT(M98090_DACHP_WIDTH)
+
+/*
+ * M98090_REG_ADC_CONTROL		0x44
+ */
+#define M98090_OSR128_MASK              BIT(2)
+#define M98090_OSR128_SHIFT             2
+#define M98090_OSR128_WIDTH             1
+#define M98090_ADCDITHER_MASK           BIT(1)
+#define M98090_ADCDITHER_SHIFT          1
+#define M98090_ADCDITHER_WIDTH          1
+#define M98090_ADCDITHER_NUM            BIT(M98090_ADCDITHER_WIDTH)
+#define M98090_ADCHP_MASK               BIT(0)
+#define M98090_ADCHP_SHIFT              0
+#define M98090_ADCHP_WIDTH              1
+#define M98090_ADCHP_NUM                BIT(M98090_ADCHP_WIDTH)
+
+/*
+ * M98090_REG_DEVICE_SHUTDOWN		0x45
+ */
+#define M98090_SHDNN_MASK               BIT(7)
+#define M98090_SHDNN_SHIFT              7
+#define M98090_SHDNN_WIDTH              1
+
+/*
+ * M98090_REG_REVISION_ID		0xFF
+ */
+#define M98090_REVID_MASK               (255 << 0)
+#define M98090_REVID_SHIFT              0
+#define M98090_REVID_WIDTH              8
+#define M98090_REVID_NUM                BIT(M98090_REVID_WIDTH)
+
+/* function prototype */
+
+/*
+ * initialise max98090 sound codec device for the given configuration
+ *
+ * @param blob			FDT node for codec values
+ * @param sampling_rate		Sampling rate (Hz)
+ * @param mclk_freq		MCLK Frequency (Hz)
+ * @param bits_per_sample	bits per Sample (must be 16 or 24)
+ *
+ * @returns -1 for error and 0 Success.
+ */
+int max98090_init(const void *blob, int sampling_rate, int mclk_freq,
+		  int bits_per_sample);
+int max98090_set_sysclk(struct maxim_priv *max98090, uint freq);
+int max98090_hw_params(struct maxim_priv *max98090, uint rate,
+		       uint bits_per_sample);
+int max98090_device_init(struct maxim_priv *max98090);
+int max98090_set_fmt(struct maxim_priv *max98090, int fmt);
+#endif
diff --git a/drivers/sound/max98095.c b/drivers/sound/max98095.c
index 7c37bd0..99c0e99 100644
--- a/drivers/sound/max98095.c
+++ b/drivers/sound/max98095.c
@@ -1,113 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
 /*
  * max98095.c -- MAX98095 ALSA SoC Audio driver
  *
  * Copyright 2011 Maxim Integrated Products
  *
- * Modified for uboot by R. Chandrasekar (rcsekar@samsung.com)
- *
- * 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.
+ * Modified for U-Boot by R. Chandrasekar (rcsekar@samsung.com)
  */
 
 #include <common.h>
-#include <asm/arch/clk.h>
-#include <asm/arch/cpu.h>
-#include <asm/arch/power.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
-#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
 #include "i2s.h"
 #include "max98095.h"
 
-enum max98095_type {
-	MAX98095,
-};
-
-struct max98095_priv {
-	enum max98095_type devtype;
-	unsigned int sysclk;
-	unsigned int rate;
-	unsigned int fmt;
-};
-
-static struct sound_codec_info g_codec_info;
-struct max98095_priv g_max98095_info;
-unsigned int g_max98095_i2c_dev_addr;
-
 /* Index 0 is reserved. */
 int rate_table[] = {0, 8000, 11025, 16000, 22050, 24000, 32000, 44100, 48000,
 		88200, 96000};
 
 /*
- * Writes value to a device register through i2c
- *
- * @param reg	reg number to be write
- * @param data	data to be writen to the above registor
- *
- * @return	int value 1 for change, 0 for no change or negative error code.
- */
-static int max98095_i2c_write(unsigned int reg, unsigned char data)
-{
-	debug("%s: Write Addr : 0x%02X, Data :  0x%02X\n",
-	      __func__, reg, data);
-	return i2c_write(g_max98095_i2c_dev_addr, reg, 1, &data, 1);
-}
-
-/*
- * Read a value from a device register through i2c
- *
- * @param reg	reg number to be read
- * @param data	address of read data to be stored
- *
- * @return	int value 0 for success, -1 in case of error.
- */
-static unsigned int max98095_i2c_read(unsigned int reg, unsigned char *data)
-{
-	int ret;
-
-	ret = i2c_read(g_max98095_i2c_dev_addr, reg, 1, data, 1);
-	if (ret != 0) {
-		debug("%s: Error while reading register %#04x\n",
-		      __func__, reg);
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * update device register bits through i2c
- *
- * @param reg	codec register
- * @param mask	register mask
- * @param value	new value
- *
- * @return int value 0 for success, non-zero error code.
- */
-static int max98095_update_bits(unsigned int reg, unsigned char mask,
-				unsigned char value)
-{
-	int change, ret = 0;
-	unsigned char old, new;
-
-	if (max98095_i2c_read(reg, &old) != 0)
-		return -1;
-	new = (old & ~mask) | (value & mask);
-	change  = (old != new) ? 1 : 0;
-	if (change)
-		ret = max98095_i2c_write(reg, new);
-	if (ret < 0)
-		return ret;
-
-	return change;
-}
-
-/*
  * codec mclk clock divider coefficients based on sampling rate
  *
  * @param rate sampling rate
@@ -127,19 +46,19 @@
 	}
 	*value = 1;
 
-	return -1;
+	return -EINVAL;
 }
 
 /*
  * Sets hw params for max98095
  *
- * @param max98095	max98095 information pointer
+ * @param priv		max98095 information pointer
  * @param rate		Sampling rate
  * @param bits_per_sample	Bits per sample
  *
- * @return -1 for error  and 0  Success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_hw_params(struct max98095_priv *max98095,
+static int max98095_hw_params(struct maxim_priv *priv,
 			      enum en_max_audio_interface aif_id,
 			      unsigned int rate, unsigned int bits_per_sample)
 {
@@ -161,40 +80,39 @@
 
 	switch (bits_per_sample) {
 	case 16:
-		error = max98095_update_bits(M98095_DAI_FORMAT,
-					     M98095_DAI_WS, 0);
+		error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS, 0);
 		break;
 	case 24:
-		error = max98095_update_bits(M98095_DAI_FORMAT,
-					     M98095_DAI_WS, M98095_DAI_WS);
+		error = maxim_bic_or(priv, M98095_DAI_FORMAT, M98095_DAI_WS,
+				     M98095_DAI_WS);
 		break;
 	default:
 		debug("%s: Illegal bits per sample %d.\n",
 		      __func__, bits_per_sample);
-		return -1;
+		return -EINVAL;
 	}
 
 	if (rate_value(rate, &regval)) {
 		debug("%s: Failed to set sample rate to %d.\n",
 		      __func__, rate);
-		return -1;
+		return -EINVAL;
 	}
-	max98095->rate = rate;
+	priv->rate = rate;
 
-	error |= max98095_update_bits(M98095_DAI_CLKMODE,
-				      M98095_CLKMODE_MASK, regval);
+	error |= maxim_bic_or(priv, M98095_DAI_CLKMODE, M98095_CLKMODE_MASK,
+				 regval);
 
 	/* Update sample rate mode */
 	if (rate < 50000)
-		error |= max98095_update_bits(M98095_DAI_FILTERS,
-					      M98095_DAI_DHF, 0);
+		error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+					 M98095_DAI_DHF, 0);
 	else
-		error |= max98095_update_bits(M98095_DAI_FILTERS,
-					      M98095_DAI_DHF, M98095_DAI_DHF);
+		error |= maxim_bic_or(priv, M98095_DAI_FILTERS,
+					 M98095_DAI_DHF, M98095_DAI_DHF);
 
 	if (error < 0) {
 		debug("%s: Error setting hardware params.\n", __func__);
-		return -1;
+		return -EIO;
 	}
 
 	return 0;
@@ -203,18 +121,17 @@
 /*
  * Configures Audio interface system clock for the given frequency
  *
- * @param max98095	max98095 information
+ * @param priv		max98095 information
  * @param freq		Sampling frequency in Hz
  *
- * @return -1 for error and 0 success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_set_sysclk(struct max98095_priv *max98095,
-			       unsigned int freq)
+static int max98095_set_sysclk(struct maxim_priv *priv, unsigned int freq)
 {
 	int error = 0;
 
 	/* Requested clock frequency is already setup */
-	if (freq == max98095->sysclk)
+	if (freq == priv->sysclk)
 		return 0;
 
 	/* Setup clocks for slave mode, and using the PLL
@@ -223,35 +140,35 @@
 	 *	0x03 (when master clk is 40MHz to 60MHz)..
 	 */
 	if ((freq >= 10000000) && (freq < 20000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x10);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x10);
 	} else if ((freq >= 20000000) && (freq < 40000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x20);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x20);
 	} else if ((freq >= 40000000) && (freq < 60000000)) {
-		error = max98095_i2c_write(M98095_026_SYS_CLK, 0x30);
+		error = maxim_i2c_write(priv, M98095_026_SYS_CLK, 0x30);
 	} else {
 		debug("%s: Invalid master clock frequency\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	debug("%s: Clock at %uHz\n", __func__, freq);
 
 	if (error < 0)
-		return -1;
+		return -EIO;
 
-	max98095->sysclk = freq;
+	priv->sysclk = freq;
 	return 0;
 }
 
 /*
  * Sets Max98095 I2S format
  *
- * @param max98095	max98095 information
+ * @param priv		max98095 information
  * @param fmt		i2S format - supports a subset of the options defined
  *			in i2s.h.
  *
- * @return -1 for error and 0  Success.
+ * @return	0 for success or negative error code.
  */
-static int max98095_set_fmt(struct max98095_priv *max98095, int fmt,
+static int max98095_set_fmt(struct maxim_priv *priv, int fmt,
 			    enum en_max_audio_interface aif_id)
 {
 	u8 regval = 0;
@@ -261,10 +178,10 @@
 	unsigned short M98095_DAI_FORMAT;
 	unsigned short M98095_DAI_CLOCK;
 
-	if (fmt == max98095->fmt)
+	if (fmt == priv->fmt)
 		return 0;
 
-	max98095->fmt = fmt;
+	priv->fmt = fmt;
 
 	if (aif_id == AIF1) {
 		M98095_DAI_CLKCFG_HI = M98095_028_DAI1_CLKCFG_HI;
@@ -281,10 +198,8 @@
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
 	case SND_SOC_DAIFMT_CBS_CFS:
 		/* Slave mode PLL */
-		error |= max98095_i2c_write(M98095_DAI_CLKCFG_HI,
-					0x80);
-		error |= max98095_i2c_write(M98095_DAI_CLKCFG_LO,
-					0x00);
+		error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_HI, 0x80);
+		error |= maxim_i2c_write(priv, M98095_DAI_CLKCFG_LO, 0x00);
 		break;
 	case SND_SOC_DAIFMT_CBM_CFM:
 		/* Set to master mode */
@@ -294,7 +209,7 @@
 	case SND_SOC_DAIFMT_CBM_CFS:
 	default:
 		debug("%s: Clock mode unsupported\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -305,7 +220,7 @@
 		break;
 	default:
 		debug("%s: Unrecognized format.\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
@@ -322,20 +237,18 @@
 		break;
 	default:
 		debug("%s: Unrecognized inversion settings.\n", __func__);
-		return -1;
+		return -EINVAL;
 	}
 
-	error |= max98095_update_bits(M98095_DAI_FORMAT,
-				      M98095_DAI_MAS | M98095_DAI_DLY |
-				      M98095_DAI_BCI | M98095_DAI_WCI,
-				      regval);
+	error |= maxim_bic_or(priv, M98095_DAI_FORMAT,
+				 M98095_DAI_MAS | M98095_DAI_DLY |
+				 M98095_DAI_BCI | M98095_DAI_WCI, regval);
 
-	error |= max98095_i2c_write(M98095_DAI_CLOCK,
-				    M98095_DAI_BSEL64);
+	error |= maxim_i2c_write(priv, M98095_DAI_CLOCK, M98095_DAI_BSEL64);
 
 	if (error < 0) {
 		debug("%s: Error setting i2s format.\n", __func__);
-		return -1;
+		return -EIO;
 	}
 
 	return 0;
@@ -344,9 +257,10 @@
 /*
  * resets the audio codec
  *
- * @return -1 for error and 0 success.
+ * @param priv	Private data for driver
+ * @return	0 for success or negative error code.
  */
-static int max98095_reset(void)
+static int max98095_reset(struct maxim_priv *priv)
 {
 	int i, ret;
 
@@ -354,13 +268,13 @@
 	 * Gracefully reset the DSP core and the codec hardware in a proper
 	 * sequence.
 	 */
-	ret = max98095_i2c_write(M98095_00F_HOST_CFG, 0);
+	ret = maxim_i2c_write(priv, M98095_00F_HOST_CFG, 0);
 	if (ret != 0) {
 		debug("%s: Failed to reset DSP: %d\n", __func__, ret);
 		return ret;
 	}
 
-	ret = max98095_i2c_write(M98095_097_PWR_SYS, 0);
+	ret = maxim_i2c_write(priv, M98095_097_PWR_SYS, 0);
 	if (ret != 0) {
 		debug("%s: Failed to reset codec: %d\n", __func__, ret);
 		return ret;
@@ -371,7 +285,7 @@
 	 * reset hardware control register.
 	 */
 	for (i = M98095_010_HOST_INT_CFG; i < M98095_REG_MAX_CACHED; i++) {
-		ret = max98095_i2c_write(i, 0);
+		ret = maxim_i2c_write(priv, i, 0);
 		if (ret < 0) {
 			debug("%s: Failed to reset: %d\n", __func__, ret);
 			return ret;
@@ -384,132 +298,128 @@
 /*
  * Intialise max98095 codec device
  *
- * @param max98095	max98095 information
- *
- * @returns -1 for error  and 0 Success.
+ * @param priv		max98095 information
+ * @return	0 for success or negative error code.
  */
-static int max98095_device_init(struct max98095_priv *max98095,
-				enum en_max_audio_interface aif_id)
+static int max98095_device_init(struct maxim_priv *priv)
 {
 	unsigned char id;
-	int error = 0;
+	int ret;
+
+	/* Enable codec clock */
+	set_xclkout();
 
 	/* reset the codec, the DSP core, and disable all interrupts */
-	error = max98095_reset();
-	if (error != 0) {
+	ret = max98095_reset(priv);
+	if (ret != 0) {
 		debug("Reset\n");
-		return error;
+		return ret;
 	}
 
 	/* initialize private data */
-	max98095->sysclk = -1U;
-	max98095->rate = -1U;
-	max98095->fmt = -1U;
+	priv->sysclk = -1U;
+	priv->rate = -1U;
+	priv->fmt = -1U;
 
-	error = max98095_i2c_read(M98095_0FF_REV_ID, &id);
-	if (error < 0) {
+	ret = maxim_i2c_read(priv, M98095_0FF_REV_ID, &id);
+	if (ret < 0) {
 		debug("%s: Failure reading hardware revision: %d\n",
 		      __func__, id);
-		goto err_access;
+		return ret;
 	}
 	debug("%s: Hardware revision: %c\n", __func__, (id - 0x40) + 'A');
 
-	error |= max98095_i2c_write(M98095_097_PWR_SYS, M98095_PWRSV);
+	return 0;
+}
+
+static int max98095_setup_interface(struct maxim_priv *priv,
+				    enum en_max_audio_interface aif_id)
+{
+	int error;
+
+	error = maxim_i2c_write(priv, M98095_097_PWR_SYS, M98095_PWRSV);
 
 	/*
 	 * initialize registers to hardware default configuring audio
 	 * interface2 to DAC
 	 */
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+		error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
 					    M98095_DAI1L_TO_DACL |
 					    M98095_DAI1R_TO_DACR);
 	else
-		error |= max98095_i2c_write(M98095_048_MIX_DAC_LR,
+		error |= maxim_i2c_write(priv, M98095_048_MIX_DAC_LR,
 					    M98095_DAI2M_TO_DACL |
 					    M98095_DAI2M_TO_DACR);
 
-	error |= max98095_i2c_write(M98095_092_PWR_EN_OUT,
+	error |= maxim_i2c_write(priv, M98095_092_PWR_EN_OUT,
 				    M98095_SPK_SPREADSPECTRUM);
-	error |= max98095_i2c_write(M98095_04E_CFG_HP, M98095_HPNORMAL);
+	error |= maxim_i2c_write(priv, M98095_04E_CFG_HP, M98095_HPNORMAL);
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_02C_DAI1_IOCFG,
+		error |= maxim_i2c_write(priv, M98095_02C_DAI1_IOCFG,
 					    M98095_S1NORMAL | M98095_SDATA);
 	else
-		error |= max98095_i2c_write(M98095_036_DAI2_IOCFG,
+		error |= maxim_i2c_write(priv, M98095_036_DAI2_IOCFG,
 					    M98095_S2NORMAL | M98095_SDATA);
 
 	/* take the codec out of the shut down */
-	error |= max98095_update_bits(M98095_097_PWR_SYS, M98095_SHDNRUN,
-				      M98095_SHDNRUN);
-	/* route DACL and DACR output to HO and Spekers */
-	error |= max98095_i2c_write(M98095_050_MIX_SPK_LEFT, 0x01); /* DACL */
-	error |= max98095_i2c_write(M98095_051_MIX_SPK_RIGHT, 0x01);/* DACR */
-	error |= max98095_i2c_write(M98095_04C_MIX_HP_LEFT, 0x01);  /* DACL */
-	error |= max98095_i2c_write(M98095_04D_MIX_HP_RIGHT, 0x01); /* DACR */
+	error |= maxim_bic_or(priv, M98095_097_PWR_SYS, M98095_SHDNRUN,
+				 M98095_SHDNRUN);
+	/*
+	 * route DACL and DACR output to HO and Speakers
+	 * Ordering: DACL, DACR, DACL, DACR
+	 */
+	error |= maxim_i2c_write(priv, M98095_050_MIX_SPK_LEFT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_051_MIX_SPK_RIGHT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_04C_MIX_HP_LEFT, 0x01);
+	error |= maxim_i2c_write(priv, M98095_04D_MIX_HP_RIGHT, 0x01);
 
 	/* power Enable */
-	error |= max98095_i2c_write(M98095_091_PWR_EN_OUT, 0xF3);
+	error |= maxim_i2c_write(priv, M98095_091_PWR_EN_OUT, 0xF3);
 
 	/* set Volume */
-	error |= max98095_i2c_write(M98095_064_LVL_HP_L, 15);
-	error |= max98095_i2c_write(M98095_065_LVL_HP_R, 15);
-	error |= max98095_i2c_write(M98095_067_LVL_SPK_L, 16);
-	error |= max98095_i2c_write(M98095_068_LVL_SPK_R, 16);
+	error |= maxim_i2c_write(priv, M98095_064_LVL_HP_L, 15);
+	error |= maxim_i2c_write(priv, M98095_065_LVL_HP_R, 15);
+	error |= maxim_i2c_write(priv, M98095_067_LVL_SPK_L, 16);
+	error |= maxim_i2c_write(priv, M98095_068_LVL_SPK_R, 16);
 
 	/* Enable DAIs */
-	error |= max98095_i2c_write(M98095_093_BIAS_CTRL, 0x30);
+	error |= maxim_i2c_write(priv, M98095_093_BIAS_CTRL, 0x30);
 	if (aif_id == AIF1)
-		error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x01);
+		error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x01);
 	else
-		error |= max98095_i2c_write(M98095_096_PWR_DAC_CK, 0x07);
+		error |= maxim_i2c_write(priv, M98095_096_PWR_DAC_CK, 0x07);
 
-err_access:
 	if (error < 0)
-		return -1;
+		return -EIO;
 
 	return 0;
 }
 
-static int max98095_do_init(struct sound_codec_info *pcodec_info,
+static int max98095_do_init(struct maxim_priv *priv,
 			    enum en_max_audio_interface aif_id,
 			    int sampling_rate, int mclk_freq,
 			    int bits_per_sample)
 {
 	int ret = 0;
 
-	/* Enable codec clock */
-	set_xclkout();
-
-	/* shift the device address by 1 for 7 bit addressing */
-	g_max98095_i2c_dev_addr = pcodec_info->i2c_dev_addr >> 1;
-
-	if (pcodec_info->codec_type == CODEC_MAX_98095) {
-		g_max98095_info.devtype = MAX98095;
-	} else {
-		debug("%s: Codec id [%d] not defined\n", __func__,
-		      pcodec_info->codec_type);
-		return -1;
-	}
-
-	ret = max98095_device_init(&g_max98095_info, aif_id);
+	ret = max98095_setup_interface(priv, aif_id);
 	if (ret < 0) {
-		debug("%s: max98095 codec chip init failed\n", __func__);
+		debug("%s: max98095 setup interface failed\n", __func__);
 		return ret;
 	}
 
-	ret = max98095_set_sysclk(&g_max98095_info, mclk_freq);
+	ret = max98095_set_sysclk(priv, mclk_freq);
 	if (ret < 0) {
 		debug("%s: max98095 codec set sys clock failed\n", __func__);
 		return ret;
 	}
 
-	ret = max98095_hw_params(&g_max98095_info, aif_id, sampling_rate,
+	ret = max98095_hw_params(priv, aif_id, sampling_rate,
 				 bits_per_sample);
 
 	if (ret == 0) {
-		ret = max98095_set_fmt(&g_max98095_info,
-				       SND_SOC_DAIFMT_I2S |
+		ret = max98095_set_fmt(priv, SND_SOC_DAIFMT_I2S |
 				       SND_SOC_DAIFMT_NB_NF |
 				       SND_SOC_DAIFMT_CBS_CFS,
 				       aif_id);
@@ -518,76 +428,45 @@
 	return ret;
 }
 
-static int get_max98095_codec_values(struct sound_codec_info *pcodec_info,
-				const void *blob)
+static int max98095_set_params(struct udevice *dev, int interface, int rate,
+			       int mclk_freq, int bits_per_sample,
+			       uint channels)
 {
-	int error = 0;
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-	enum fdt_compat_id compat;
-	int node;
-	int parent;
+	struct maxim_priv *priv = dev_get_priv(dev);
 
-	/* Get the node from FDT for codec */
-	node = fdtdec_next_compatible(blob, 0, COMPAT_MAXIM_98095_CODEC);
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for codec in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
+	return max98095_do_init(priv, interface, rate, mclk_freq,
+				bits_per_sample);
+}
 
-	parent = fdt_parent_offset(blob, node);
-	if (parent < 0) {
-		debug("%s: Cannot find node parent\n", __func__);
-		return -1;
-	}
+static int max98095_probe(struct udevice *dev)
+{
+	struct maxim_priv *priv = dev_get_priv(dev);
+	int ret;
 
-	compat = fdtdec_lookup(blob, parent);
-	switch (compat) {
-	case COMPAT_SAMSUNG_S3C2440_I2C:
-		pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
-		error |= pcodec_info->i2c_bus;
-		debug("i2c bus = %d\n", pcodec_info->i2c_bus);
-		pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
-							"reg", 0);
-		error |= pcodec_info->i2c_dev_addr;
-		debug("i2c dev addr = %x\n", pcodec_info->i2c_dev_addr);
-		break;
-	default:
-		debug("%s: Unknown compat id %d\n", __func__, compat);
-		return -1;
-	}
-#else
-	pcodec_info->i2c_bus = AUDIO_I2C_BUS;
-	pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
-	debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-#endif
-	pcodec_info->codec_type = CODEC_MAX_98095;
-	if (error == -1) {
-		debug("fail to get max98095 codec node properties\n");
-		return -1;
+	priv->dev = dev;
+	ret = max98095_device_init(priv);
+	if (ret < 0) {
+		debug("%s: max98095 codec chip init failed\n", __func__);
+		return ret;
 	}
 
 	return 0;
 }
 
-/* max98095 Device Initialisation */
-int max98095_init(const void *blob, enum en_max_audio_interface aif_id,
-		  int sampling_rate, int mclk_freq,
-		  int bits_per_sample)
-{
-	int ret;
-	int old_bus = i2c_get_bus_num();
-	struct sound_codec_info *pcodec_info = &g_codec_info;
+static const struct audio_codec_ops max98095_ops = {
+	.set_params	= max98095_set_params,
+};
 
-	if (get_max98095_codec_values(pcodec_info, blob) < 0) {
-		debug("FDT Codec values failed\n");
-		return -1;
-	}
+static const struct udevice_id max98095_ids[] = {
+	{ .compatible = "maxim,max98095" },
+	{ }
+};
 
-	i2c_set_bus_num(pcodec_info->i2c_bus);
-	ret = max98095_do_init(pcodec_info, aif_id, sampling_rate, mclk_freq,
-			       bits_per_sample);
-	i2c_set_bus_num(old_bus);
-
-	return ret;
-}
+U_BOOT_DRIVER(max98095) = {
+	.name		= "max98095",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= max98095_ids,
+	.probe		= max98095_probe,
+	.ops		= &max98095_ops,
+	.priv_auto_alloc_size	= sizeof(struct maxim_priv),
+};
diff --git a/drivers/sound/max98095.h b/drivers/sound/max98095.h
index 44b1e3a..1521f3f 100644
--- a/drivers/sound/max98095.h
+++ b/drivers/sound/max98095.h
@@ -1,19 +1,18 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
 /*
  * max98095.h -- MAX98095 ALSA SoC Audio driver
  *
  * Copyright 2011 Maxim Integrated Products
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
  */
 
 #ifndef _MAX98095_H
 #define _MAX98095_H
 
+#include "maxim_codec.h"
+
 /*  Available audio interface ports in wm8994 codec */
 enum en_max_audio_interface {
-	AIF1 = 1,
+	AIF1,
 	AIF2,
 };
 
diff --git a/drivers/sound/maxim_codec.c b/drivers/sound/maxim_codec.c
new file mode 100644
index 0000000..dcaf081
--- /dev/null
+++ b/drivers/sound/maxim_codec.c
@@ -0,0 +1,87 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * maxim_codec.c -- MAXIM CODEC Common driver
+ *
+ * Copyright 2011 Maxim Integrated Products
+ */
+
+#include <common.h>
+#include <div64.h>
+#include <i2c.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/power.h>
+#include "maxim_codec.h"
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be write
+ * @param data	data to be writen to the above registor
+ *
+ * @return	int value 1 for change, 0 for no change or negative error code.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+		    unsigned char data)
+{
+	debug("%s: Write Addr : 0x%02X, Data :  0x%02X\n",
+	      __func__, reg, data);
+	return dm_i2c_write(priv->dev, reg, &data, 1);
+}
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be read
+ * @param data	address of read data to be stored
+ *
+ * @return	int value 0 for success, -1 in case of error.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+			    unsigned char *data)
+{
+	int ret;
+
+	return dm_i2c_read(priv->dev, reg, data, 1);
+	if (ret != 0) {
+		debug("%s: Error while reading register %#04x\n",
+		      __func__, reg);
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * update device register bits through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	codec register
+ * @param mask	register mask
+ * @param value	new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+		 unsigned char value)
+{
+	int change, ret = 0;
+	unsigned char old, new;
+
+	if (maxim_i2c_read(priv, reg, &old) != 0)
+		return -1;
+	new = (old & ~mask) | (value & mask);
+	change  = (old != new) ? 1 : 0;
+	if (change)
+		ret = maxim_i2c_write(priv, reg, new);
+	if (ret < 0)
+		return ret;
+
+	return change;
+}
diff --git a/drivers/sound/maxim_codec.h b/drivers/sound/maxim_codec.h
new file mode 100644
index 0000000..a3128e0
--- /dev/null
+++ b/drivers/sound/maxim_codec.h
@@ -0,0 +1,67 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * maxim_codec.h -- MAXIM codec common interface file
+ *
+ * Copyright (C) 2013 Samsung Electronics
+ * D Krishna Mohan <krishna.md@samsung.com>
+ */
+
+#ifndef __MAXIM_COMMON_H__
+#define __MAXIM_COMMON_H__
+
+enum maxim_codec_type {
+	MAX98095,
+	MAX98090,
+};
+
+struct maxim_priv {
+	enum maxim_codec_type devtype;
+	unsigned int sysclk;
+	unsigned int rate;
+	unsigned int fmt;
+	struct udevice *dev;
+};
+
+#define MAXIM_AUDIO_I2C_BUS		7
+#define MAXIM_AUDIO_I2C_REG_98095	0x22
+
+#define MAXIM_AUDIO_I2C_REG		MAXIM_AUDIO_I2C_REG_98095
+
+/*
+ * Writes value to a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be write
+ * @param data	data to be writen to the above registor
+ *
+ * @return	int value 1 for change, 0 for no change or negative error code.
+ */
+int maxim_i2c_write(struct maxim_priv *priv, unsigned int reg,
+		    unsigned char data);
+
+/*
+ * Read a value from a device register through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	reg number to be read
+ * @param data	address of read data to be stored
+ *
+ * @return	int value 0 for success, -1 in case of error.
+ */
+unsigned int maxim_i2c_read(struct maxim_priv *priv, unsigned int reg,
+			    unsigned char *data);
+
+/*
+ * update device register bits through i2c
+ *
+ * @param priv	Private data for driver
+ * @param reg	codec register
+ * @param mask	register mask
+ * @param value	new value
+ *
+ * @return int value 0 for success, non-zero error code.
+ */
+int maxim_bic_or(struct maxim_priv *priv, unsigned int reg, unsigned char mask,
+		 unsigned char value);
+
+#endif /* __MAXIM_COMMON_H__ */
diff --git a/drivers/sound/samsung-i2s.c b/drivers/sound/samsung-i2s.c
index f39abf5..c19e08e 100644
--- a/drivers/sound/samsung-i2s.c
+++ b/drivers/sound/samsung-i2s.c
@@ -4,13 +4,14 @@
  * R. Chandrasekar <rcsekar@samsung.com>
  */
 
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
 #include <asm/arch/clk.h>
 #include <asm/arch/pinmux.h>
 #include <asm/arch/i2s-regs.h>
 #include <asm/io.h>
-#include <common.h>
-#include <sound.h>
-#include <i2s.h>
 
 #define FIC_TX2COUNT(x)		(((x) >>  24) & 0xf)
 #define FIC_TX1COUNT(x)		(((x) >>  16) & 0xf)
@@ -111,7 +112,7 @@
  * @param flush		Tx fifo flush command (0x00 - do not flush
  *				0x80 - flush tx fifo)
  */
-void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
+static void i2s_fifo(struct i2s_reg *i2s_reg, unsigned int flush)
 {
 	/* Flush the FIFO */
 	setbits_le32(&i2s_reg->fic, flush);
@@ -126,7 +127,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
+static int i2s_set_sysclk_dir(struct i2s_reg *i2s_reg, int dir)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 
@@ -148,7 +149,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
+static int i2s_set_fmt(struct i2s_reg *i2s_reg, unsigned int fmt)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 	unsigned int tmp = 0;
@@ -170,7 +171,7 @@
 	default:
 		debug("%s: Invalid format priority [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_FORMAT_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	/*
@@ -189,7 +190,7 @@
 	default:
 		debug("%s: Invalid clock ploarity input [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_INV_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
@@ -201,13 +202,13 @@
 		ret = i2s_set_sysclk_dir(i2s_reg, SND_SOC_CLOCK_OUT);
 		if (ret != 0) {
 			debug("%s:set i2s clock direction failed\n", __func__);
-			return -1;
+			return ret;
 		}
 		break;
 	default:
 		debug("%s: Invalid master selection [0x%x]\n", __func__,
 		      (fmt & SND_SOC_DAIFMT_MASTER_MASK));
-		return -1;
+		return -ERANGE;
 	}
 
 	mod &= ~(MOD_SDF_MASK | MOD_LR_RLOW | MOD_SLAVE);
@@ -225,7 +226,7 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
+static int i2s_set_samplesize(struct i2s_reg *i2s_reg, unsigned int blc)
 {
 	unsigned int mod = readl(&i2s_reg->mod);
 
@@ -248,43 +249,43 @@
 	default:
 		debug("%s: Invalid sample size input [0x%x]\n",
 		      __func__, blc);
-		return -1;
+		return -ERANGE;
 	}
 	writel(mod, &i2s_reg->mod);
 
 	return 0;
 }
 
-int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned int *data,
-				unsigned long data_size)
+int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+			 uint data_size)
 {
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+	u32 *ptr;
 	int i;
 	int start;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
 
 	if (data_size < FIFO_LENGTH) {
 		debug("%s : Invalid data size\n", __func__);
-		return -1; /* invalid pcm data size */
+		return -ENODATA; /* invalid pcm data size */
 	}
 
 	/* fill the tx buffer before stating the tx transmit */
-	for (i = 0; i < FIFO_LENGTH; i++)
-		writel(*data++, &i2s_reg->txd);
+	for (i = 0, ptr = data; i < FIFO_LENGTH; i++)
+		writel(*ptr++, &i2s_reg->txd);
 
-	data_size -= FIFO_LENGTH;
+	data_size -= sizeof(*ptr) * FIFO_LENGTH;
 	i2s_txctrl(i2s_reg, I2S_TX_ON);
 
 	while (data_size > 0) {
 		start = get_timer(0);
 		if (!(CON_TXFIFO_FULL & (readl(&i2s_reg->con)))) {
-			writel(*data++, &i2s_reg->txd);
-			data_size--;
+			writel(*ptr++, &i2s_reg->txd);
+			data_size -= sizeof(*ptr);
 		} else {
 			if (get_timer(start) > TIMEOUT_I2S_TX) {
 				i2s_txctrl(i2s_reg, I2S_TX_OFF);
 				debug("%s: I2S Transfer Timeout\n", __func__);
-				return -1;
+				return -ETIMEDOUT;
 			}
 		}
 	}
@@ -293,11 +294,11 @@
 	return 0;
 }
 
-int i2s_tx_init(struct i2stx_info *pi2s_tx)
+int i2s_tx_init(struct i2s_uc_priv *pi2s_tx)
 {
 	int ret;
-	struct i2s_reg *i2s_reg =
-				(struct i2s_reg *)pi2s_tx->base_address;
+	struct i2s_reg *i2s_reg = (struct i2s_reg *)pi2s_tx->base_address;
+
 	if (pi2s_tx->id == 0) {
 		/* Initialize GPIO for I2S-0 */
 		exynos_pinmux_config(PERIPH_ID_I2S0, 0);
@@ -312,20 +313,20 @@
 		ret = set_epll_clk(pi2s_tx->audio_pll_clk);
 	} else {
 		debug("%s: unsupported i2s-%d bus\n", __func__, pi2s_tx->id);
-		return -1;
+		return -ERANGE;
 	}
 
-	if (ret != 0) {
+	if (ret) {
 		debug("%s: epll clock set rate failed\n", __func__);
-		return -1;
+		return ret;
 	}
 
 	/* Select Clk Source for Audio 0 or 1 */
 	ret = set_i2s_clk_source(pi2s_tx->id);
-	if (ret == -1) {
+	if (ret) {
 		debug("%s: unsupported clock for i2s-%d\n", __func__,
 		      pi2s_tx->id);
-		return -1;
+		return ret;
 	}
 
 	if (pi2s_tx->id == 0) {
@@ -341,21 +342,21 @@
 				(pi2s_tx->samplingrate * (pi2s_tx->rfs)),
 				pi2s_tx->id);
 	}
-	if (ret == -1) {
+	if (ret) {
 		debug("%s: unsupported prescalar for i2s-%d\n", __func__,
 		      pi2s_tx->id);
-		return -1;
+		return ret;
 	}
 
 	/* Configure I2s format */
-	ret = i2s_set_fmt(i2s_reg, (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
-			  SND_SOC_DAIFMT_CBM_CFM));
+	ret = i2s_set_fmt(i2s_reg, SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			  SND_SOC_DAIFMT_CBM_CFM);
 	if (ret == 0) {
 		i2s_set_lr_framesize(i2s_reg, pi2s_tx->rfs);
 		ret = i2s_set_samplesize(i2s_reg, pi2s_tx->bitspersample);
 		if (ret != 0) {
 			debug("%s:set sample rate failed\n", __func__);
-			return -1;
+			return ret;
 		}
 
 		i2s_set_bitclk_framesize(i2s_reg, pi2s_tx->bfs);
@@ -368,3 +369,87 @@
 
 	return ret;
 }
+
+static int samsung_i2s_tx_data(struct udevice *dev, void *data, uint data_size)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_transfer_tx_data(priv, data, data_size);
+}
+
+static int samsung_i2s_probe(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_init(priv);
+}
+
+static int samsung_i2s_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2s_uc_priv *priv = dev_get_uclass_priv(dev);
+	ulong base;
+
+	/*
+	 * Get the pre-defined sound specific values from FDT.
+	 * All of these are expected to be correct otherwise
+	 * wrong register values in i2s setup parameters
+	 * may result in no sound play.
+	 */
+	base = dev_read_addr(dev);
+	if (base == FDT_ADDR_T_NONE) {
+		debug("%s: Missing  i2s base\n", __func__);
+		return -EINVAL;
+	}
+	priv->base_address = base;
+
+	if (dev_read_u32u(dev, "samsung,i2s-epll-clock-frequency",
+			  &priv->audio_pll_clk))
+		goto err;
+	debug("audio_pll_clk = %d\n", priv->audio_pll_clk);
+	if (dev_read_u32u(dev, "samsung,i2s-sampling-rate",
+			  &priv->samplingrate))
+		goto err;
+	debug("samplingrate = %d\n", priv->samplingrate);
+	if (dev_read_u32u(dev, "samsung,i2s-bits-per-sample",
+			  &priv->bitspersample))
+		goto err;
+	debug("bitspersample = %d\n", priv->bitspersample);
+	if (dev_read_u32u(dev, "samsung,i2s-channels", &priv->channels))
+		goto err;
+	debug("channels = %d\n", priv->channels);
+	if (dev_read_u32u(dev, "samsung,i2s-lr-clk-framesize", &priv->rfs))
+		goto err;
+	debug("rfs = %d\n", priv->rfs);
+	if (dev_read_u32u(dev, "samsung,i2s-bit-clk-framesize", &priv->bfs))
+		goto err;
+	debug("bfs = %d\n", priv->bfs);
+
+	if (dev_read_u32u(dev, "samsung,i2s-id", &priv->id))
+		goto err;
+	debug("id = %d\n", priv->id);
+
+	return 0;
+
+err:
+	debug("fail to get sound i2s node properties\n");
+
+	return -EINVAL;
+}
+
+static const struct i2s_ops samsung_i2s_ops = {
+	.tx_data	= samsung_i2s_tx_data,
+};
+
+static const struct udevice_id samsung_i2s_ids[] = {
+	{ .compatible = "samsung,s5pv210-i2s" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_i2s) = {
+	.name		= "samsung_i2s",
+	.id		= UCLASS_I2S,
+	.of_match	= samsung_i2s_ids,
+	.probe		= samsung_i2s_probe,
+	.ofdata_to_platdata	= samsung_i2s_ofdata_to_platdata,
+	.ops		= &samsung_i2s_ops,
+};
diff --git a/drivers/sound/samsung_sound.c b/drivers/sound/samsung_sound.c
new file mode 100644
index 0000000..1d711c8
--- /dev/null
+++ b/drivers/sound/samsung_sound.c
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google, LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+#include <asm/gpio.h>
+
+static int samsung_sound_setup(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct i2s_uc_priv *i2c_priv = dev_get_uclass_priv(uc_priv->i2s);
+	int ret;
+
+	if (uc_priv->setup_done)
+		return -EALREADY;
+	ret = audio_codec_set_params(uc_priv->codec, i2c_priv->id,
+				     i2c_priv->samplingrate,
+				     i2c_priv->samplingrate * i2c_priv->rfs,
+				     i2c_priv->bitspersample,
+				     i2c_priv->channels);
+	if (ret)
+		return ret;
+	uc_priv->setup_done = true;
+
+	return 0;
+}
+
+static int samsung_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int samsung_sound_probe(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct ofnode_phandle_args args;
+	struct gpio_desc en_gpio;
+	ofnode node;
+	int ret;
+
+	ret = gpio_request_by_name(dev, "codec-enable-gpio", 0, &en_gpio,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+
+	/* Turn on the GPIO which connects to the codec's "enable" line. */
+	if (!ret)
+		gpio_set_pull(gpio_get_number(&en_gpio), S5P_GPIO_PULL_NONE);
+
+	ret = uclass_get_device_by_phandle(UCLASS_AUDIO_CODEC, dev,
+					   "samsung,audio-codec",
+					   &uc_priv->codec);
+	if (ret) {
+		debug("Failed to probe audio codec\n");
+		return ret;
+	}
+	node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+	if (ret) {
+		debug("Cannot find i2s: %d\n", ret);
+		return ret;
+	}
+	debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+	      uc_priv->codec->name, uc_priv->i2s->name);
+
+	return 0;
+}
+
+static const struct sound_ops samsung_sound_ops = {
+	.setup	= samsung_sound_setup,
+	.play	= samsung_sound_play,
+};
+
+static const struct udevice_id samsung_sound_ids[] = {
+	{ .compatible = "google,snow-audio-max98095" },
+	{ .compatible = "google,spring-audio-max98095" },
+	{ .compatible = "samsung,smdk5420-audio-wm8994" },
+	{ .compatible = "google,peach-audio-max98090" },
+	{ }
+};
+
+U_BOOT_DRIVER(samsung_sound) = {
+	.name		= "samsung_sound",
+	.id		= UCLASS_SOUND,
+	.of_match	= samsung_sound_ids,
+	.probe		= samsung_sound_probe,
+	.ops		= &samsung_sound_ops,
+};
diff --git a/drivers/sound/sandbox.c b/drivers/sound/sandbox.c
index 94eff54..b0b07f3 100644
--- a/drivers/sound/sandbox.c
+++ b/drivers/sound/sandbox.c
@@ -4,19 +4,185 @@
  */
 
 #include <common.h>
-#include <asm/sound.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
 #include <asm/sdl.h>
 
-int sound_play(uint32_t msec, uint32_t frequency)
+struct sandbox_codec_priv {
+	int interface;
+	int rate;
+	int mclk_freq;
+	int bits_per_sample;
+	uint channels;
+};
+
+struct sandbox_i2s_priv {
+	int sum;	/* Use to sum the provided audio data */
+};
+
+struct sandbox_sound_priv {
+	int setup_called;
+	int sum;	/* Use to sum the provided audio data */
+};
+
+void sandbox_get_codec_params(struct udevice *dev, int *interfacep, int *ratep,
+			      int *mclk_freqp, int *bits_per_samplep,
+			      uint *channelsp)
 {
-	sandbox_sdl_sound_start(frequency);
-	mdelay(msec);
-	sandbox_sdl_sound_stop();
+	struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+	*interfacep = priv->interface;
+	*ratep = priv->rate;
+	*mclk_freqp = priv->mclk_freq;
+	*bits_per_samplep = priv->bits_per_sample;
+	*channelsp = priv->channels;
+}
+
+int sandbox_get_i2s_sum(struct udevice *dev)
+{
+	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+
+	return priv->sum;
+}
+
+int sandbox_get_setup_called(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	return priv->setup_called;
+}
+
+int sandbox_get_sound_sum(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	return priv->sum;
+}
+
+static int sandbox_codec_set_params(struct udevice *dev, int interface,
+				    int rate, int mclk_freq,
+				    int bits_per_sample, uint channels)
+{
+	struct sandbox_codec_priv *priv = dev_get_priv(dev);
+
+	priv->interface = interface;
+	priv->rate = rate;
+	priv->mclk_freq = mclk_freq;
+	priv->bits_per_sample = bits_per_sample;
+	priv->channels = channels;
 
 	return 0;
 }
 
-int sound_init(const void *blob)
+static int sandbox_i2s_tx_data(struct udevice *dev, void *data,
+			       uint data_size)
 {
-	return sandbox_sdl_sound_init();
+	struct sandbox_i2s_priv *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < data_size; i++)
+		priv->sum += ((uint8_t *)data)[i];
+
+	return sandbox_sdl_sound_play(data, data_size);
 }
+
+static int sandbox_i2s_probe(struct udevice *dev)
+{
+	struct i2s_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	/* Use hard-coded values here */
+	uc_priv->rfs = 256;
+	uc_priv->bfs = 32;
+	uc_priv->audio_pll_clk = 192000000;
+	uc_priv->samplingrate = 48000;
+	uc_priv->bitspersample = 16;
+	uc_priv->channels = 2;
+	uc_priv->id = 1;
+
+	/* Ignore any error here - we'll just have no sound */
+	sandbox_sdl_sound_init(uc_priv->samplingrate, uc_priv->channels);
+
+	return 0;
+}
+
+static int sandbox_sound_setup(struct udevice *dev)
+{
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+
+	priv->setup_called++;
+
+	return 0;
+}
+
+static int sandbox_sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct sandbox_sound_priv *priv = dev_get_priv(dev);
+	int i;
+
+	for (i = 0; i < data_size; i++)
+		priv->sum += ((uint8_t *)data)[i];
+
+	return i2s_tx_data(uc_priv->i2s, data, data_size);
+}
+
+static int sandbox_sound_probe(struct udevice *dev)
+{
+	return sound_find_codec_i2s(dev);
+}
+
+static const struct audio_codec_ops sandbox_codec_ops = {
+	.set_params	= sandbox_codec_set_params,
+};
+
+static const struct udevice_id sandbox_codec_ids[] = {
+	{ .compatible = "sandbox,audio-codec" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_codec) = {
+	.name		= "sandbox_codec",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= sandbox_codec_ids,
+	.ops		= &sandbox_codec_ops,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_codec_priv),
+};
+
+static const struct i2s_ops sandbox_i2s_ops = {
+	.tx_data	= sandbox_i2s_tx_data,
+};
+
+static const struct udevice_id sandbox_i2s_ids[] = {
+	{ .compatible = "sandbox,i2s" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_i2s) = {
+	.name		= "sandbox_i2s",
+	.id		= UCLASS_I2S,
+	.of_match	= sandbox_i2s_ids,
+	.ops		= &sandbox_i2s_ops,
+	.probe		= sandbox_i2s_probe,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_i2s_priv),
+};
+
+static const struct sound_ops sandbox_sound_ops = {
+	.setup	= sandbox_sound_setup,
+	.play	= sandbox_sound_play,
+};
+
+static const struct udevice_id sandbox_sound_ids[] = {
+	{ .compatible = "sandbox,sound" },
+	{ }
+};
+
+U_BOOT_DRIVER(sandbox_sound) = {
+	.name		= "sandbox_sound",
+	.id		= UCLASS_SOUND,
+	.of_match	= sandbox_sound_ids,
+	.ops		= &sandbox_sound_ops,
+	.priv_auto_alloc_size	= sizeof(struct sandbox_sound_priv),
+	.probe		= sandbox_sound_probe,
+};
diff --git a/drivers/sound/sound-i2s.c b/drivers/sound/sound-i2s.c
deleted file mode 100644
index f0f0b79..0000000
--- a/drivers/sound/sound-i2s.c
+++ /dev/null
@@ -1,208 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright (C) 2012 Samsung Electronics
- * R. Chandrasekar <rcsekar@samsung.com>
- */
-
-#include <malloc.h>
-#include <common.h>
-#include <asm/io.h>
-#include <linux/libfdt.h>
-#include <fdtdec.h>
-#include <i2c.h>
-#include <i2s.h>
-#include <sound.h>
-#include <asm/arch/sound.h>
-#include "wm8994.h"
-#include "max98095.h"
-
-/* defines */
-#define SOUND_400_HZ 400
-#define SOUND_BITS_IN_BYTE 8
-
-static struct i2stx_info g_i2stx_pri;
-
-/*
- * get_sound_i2s_values gets values for i2s parameters
- *
- * @param i2stx_info	i2s transmitter transfer param structure
- * @param blob		FDT blob if enabled else NULL
- */
-static int get_sound_i2s_values(struct i2stx_info *i2s, const void *blob)
-{
-	int node;
-	int error = 0;
-	int base;
-
-	node = fdt_path_offset(blob, "i2s");
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for sound in device tree\n");
-		return -1;
-	}
-
-	/*
-	 * Get the pre-defined sound specific values from FDT.
-	 * All of these are expected to be correct otherwise
-	 * wrong register values in i2s setup parameters
-	 * may result in no sound play.
-	 */
-	base = fdtdec_get_addr(blob, node, "reg");
-	if (base == FDT_ADDR_T_NONE) {
-		debug("%s: Missing  i2s base\n", __func__);
-		return -1;
-	}
-	i2s->base_address = base;
-
-	i2s->audio_pll_clk = fdtdec_get_int(blob,
-				node, "samsung,i2s-epll-clock-frequency", -1);
-	error |= i2s->audio_pll_clk;
-	debug("audio_pll_clk = %d\n", i2s->audio_pll_clk);
-	i2s->samplingrate = fdtdec_get_int(blob,
-				node, "samsung,i2s-sampling-rate", -1);
-	error |= i2s->samplingrate;
-	debug("samplingrate = %d\n", i2s->samplingrate);
-	i2s->bitspersample = fdtdec_get_int(blob,
-				node, "samsung,i2s-bits-per-sample", -1);
-	error |= i2s->bitspersample;
-	debug("bitspersample = %d\n", i2s->bitspersample);
-	i2s->channels = fdtdec_get_int(blob,
-			node, "samsung,i2s-channels", -1);
-	error |= i2s->channels;
-	debug("channels = %d\n", i2s->channels);
-	i2s->rfs = fdtdec_get_int(blob,
-				node, "samsung,i2s-lr-clk-framesize", -1);
-	error |= i2s->rfs;
-	debug("rfs = %d\n", i2s->rfs);
-	i2s->bfs = fdtdec_get_int(blob,
-				node, "samsung,i2s-bit-clk-framesize", -1);
-	error |= i2s->bfs;
-	debug("bfs = %d\n", i2s->bfs);
-
-	i2s->id = fdtdec_get_int(blob, node, "samsung,i2s-id", -1);
-	error |= i2s->id;
-	debug("id = %d\n", i2s->id);
-
-	if (error == -1) {
-		debug("fail to get sound i2s node properties\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/*
- * Init codec
- *
- * @param blob          FDT blob
- * @param pi2s_tx	i2s parameters required by codec
- * @return              int value, 0 for success
- */
-static int codec_init(const void *blob, struct i2stx_info *pi2s_tx)
-{
-	int ret;
-	const char *codectype;
-	int node;
-
-	/* Get the node from FDT for sound */
-	node = fdt_path_offset(blob, "i2s");
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for sound in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
-
-	/*
-	 * Get the pre-defined sound codec specific values from FDT.
-	 * All of these are expected to be correct otherwise sound
-	 * can not be played
-	 */
-	codectype = fdt_getprop(blob, node, "samsung,codec-type", NULL);
-	debug("device = %s\n", codectype);
-	if (!strcmp(codectype, "wm8994")) {
-		/* Check the codec type and initialise the same */
-		ret = wm8994_init(blob, pi2s_tx->id + 1,
-				  pi2s_tx->samplingrate,
-				  (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
-				  pi2s_tx->bitspersample, pi2s_tx->channels);
-	} else if (!strcmp(codectype, "max98095")) {
-		ret = max98095_init(blob, pi2s_tx->id + 1,
-				    pi2s_tx->samplingrate,
-				    (pi2s_tx->samplingrate * (pi2s_tx->rfs)),
-				    pi2s_tx->bitspersample);
-	} else {
-		debug("%s: Unknown codec type %s\n", __func__, codectype);
-		return -1;
-	}
-
-	if (ret) {
-		debug("%s: Codec init failed\n", __func__);
-		return -1;
-	}
-
-	return 0;
-}
-
-int sound_init(const void *blob)
-{
-	int ret;
-	struct i2stx_info *pi2s_tx = &g_i2stx_pri;
-
-	/* Get the I2S Values */
-	if (get_sound_i2s_values(pi2s_tx, blob) < 0) {
-		debug(" FDT I2S values failed\n");
-		return -1;
-	}
-
-	if (codec_init(blob, pi2s_tx) < 0) {
-		debug(" Codec init failed\n");
-		return -1;
-	}
-
-	ret = i2s_tx_init(pi2s_tx);
-	if (ret) {
-		debug("%s: Failed to init i2c transmit: ret=%d\n", __func__,
-		      ret);
-		return ret;
-	}
-
-
-	return ret;
-}
-
-int sound_play(uint32_t msec, uint32_t frequency)
-{
-	unsigned int *data;
-	unsigned long data_size;
-	unsigned int ret = 0;
-
-	/*Buffer length computation */
-	data_size = g_i2stx_pri.samplingrate * g_i2stx_pri.channels;
-	data_size *= (g_i2stx_pri.bitspersample / SOUND_BITS_IN_BYTE);
-	data = malloc(data_size);
-
-	if (data == NULL) {
-		debug("%s: malloc failed\n", __func__);
-		return -1;
-	}
-
-	sound_create_square_wave(g_i2stx_pri.samplingrate,
-				 (unsigned short *)data,
-				 data_size / sizeof(unsigned short),
-				 frequency);
-
-	while (msec >= 1000) {
-		ret = i2s_transfer_tx_data(&g_i2stx_pri, data,
-					   (data_size / sizeof(int)));
-		msec -= 1000;
-	}
-	if (msec) {
-		unsigned long size =
-			(data_size * msec) / (sizeof(int) * 1000);
-
-		ret = i2s_transfer_tx_data(&g_i2stx_pri, data, size);
-	}
-
-	free(data);
-
-	return ret;
-}
diff --git a/drivers/sound/sound-uclass.c b/drivers/sound/sound-uclass.c
new file mode 100644
index 0000000..2b83626
--- /dev/null
+++ b/drivers/sound/sound-uclass.c
@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <sound.h>
+
+#define SOUND_BITS_IN_BYTE 8
+
+int sound_setup(struct udevice *dev)
+{
+	struct sound_ops *ops = sound_get_ops(dev);
+
+	if (!ops->setup)
+		return -ENOSYS;
+
+	return ops->setup(dev);
+}
+
+int sound_play(struct udevice *dev, void *data, uint data_size)
+{
+	struct sound_ops *ops = sound_get_ops(dev);
+
+	if (!ops->play)
+		return -ENOSYS;
+
+	return ops->play(dev, data, data_size);
+}
+
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct i2s_uc_priv *i2s_uc_priv = dev_get_uclass_priv(uc_priv->i2s);
+	unsigned short *data;
+	uint data_size;
+	int ret;
+
+	ret = sound_setup(dev);
+	if (ret && ret != -EALREADY)
+		return ret;
+
+	/* Buffer length computation */
+	data_size = i2s_uc_priv->samplingrate * i2s_uc_priv->channels;
+	data_size *= (i2s_uc_priv->bitspersample / SOUND_BITS_IN_BYTE);
+	data = malloc(data_size);
+	if (!data) {
+		debug("%s: malloc failed\n", __func__);
+		return -ENOMEM;
+	}
+
+	sound_create_square_wave(i2s_uc_priv->samplingrate, data, data_size,
+				 frequency_hz, i2s_uc_priv->channels);
+
+	while (msecs >= 1000) {
+		ret = sound_play(dev, data, data_size);
+		msecs -= 1000;
+	}
+	if (msecs) {
+		unsigned long size =
+			(data_size * msecs) / (sizeof(int) * 1000);
+
+		ret = sound_play(dev, data, size);
+	}
+
+	free(data);
+
+	return ret;
+}
+
+int sound_find_codec_i2s(struct udevice *dev)
+{
+	struct sound_uc_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct ofnode_phandle_args args;
+	ofnode node;
+	int ret;
+
+	/* First the codec */
+	node = ofnode_find_subnode(dev_ofnode(dev), "codec");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_AUDIO_CODEC, args.node,
+					  &uc_priv->codec);
+	if (ret) {
+		debug("Cannot find codec: %d\n", ret);
+		return ret;
+	}
+
+	/* Now the i2s */
+	node = ofnode_find_subnode(dev_ofnode(dev), "cpu");
+	if (!ofnode_valid(node)) {
+		debug("Failed to find /cpu subnode\n");
+		return -EINVAL;
+	}
+	ret = ofnode_parse_phandle_with_args(node, "sound-dai",
+					     "#sound-dai-cells", 0, 0, &args);
+	if (ret) {
+		debug("Cannot find phandle: %d\n", ret);
+		return ret;
+	}
+	ret = uclass_get_device_by_ofnode(UCLASS_I2S, args.node, &uc_priv->i2s);
+	if (ret) {
+		debug("Cannot find i2s: %d\n", ret);
+		return ret;
+	}
+	debug("Probed sound '%s' with codec '%s' and i2s '%s'\n", dev->name,
+	      uc_priv->codec->name, uc_priv->i2s->name);
+
+	return 0;
+}
+
+UCLASS_DRIVER(sound) = {
+	.id		= UCLASS_SOUND,
+	.name		= "sound",
+	.per_device_auto_alloc_size	= sizeof(struct sound_uc_priv),
+};
diff --git a/drivers/sound/sound.c b/drivers/sound/sound.c
index 4f0ad0d..dd3f9db 100644
--- a/drivers/sound/sound.c
+++ b/drivers/sound/sound.c
@@ -8,7 +8,7 @@
 #include <sound.h>
 
 void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
-			      uint freq)
+			      uint freq, uint channels)
 {
 	const unsigned short amplitude = 16000; /* between 1 and 32767 */
 	const int period = freq ? sample_rate / freq : 0;
@@ -21,14 +21,17 @@
 		size--;
 
 	while (size) {
-		int i;
+		int i, j;
+
 		for (i = 0; size && i < half; i++) {
 			size -= 2;
-			*data++ = amplitude;
+			for (j = 0; j < channels; j++)
+				*data++ = amplitude;
 		}
 		for (i = 0; size && i < period - half; i++) {
 			size -= 2;
-			*data++ = -amplitude;
+			for (j = 0; j < channels; j++)
+				*data++ = -amplitude;
 		}
 	}
 }
diff --git a/drivers/sound/wm8994.c b/drivers/sound/wm8994.c
index aaaa324..b290c4e 100644
--- a/drivers/sound/wm8994.c
+++ b/drivers/sound/wm8994.c
@@ -4,15 +4,17 @@
  * R. Chandrasekar <rcsekar@samsung.com>
  */
 #include <common.h>
-#include <asm/arch/clk.h>
-#include <asm/arch/cpu.h>
-#include <asm/gpio.h>
-#include <asm/io.h>
+#include <audio_codec.h>
+#include <dm.h>
 #include <div64.h>
 #include <fdtdec.h>
 #include <i2c.h>
 #include <i2s.h>
 #include <sound.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <asm/arch/clk.h>
+#include <asm/arch/cpu.h>
 #include <asm/arch/sound.h>
 #include "wm8994.h"
 #include "wm8994_registers.h"
@@ -38,6 +40,7 @@
 	int mclk[WM8994_MAX_AIF];	/* master clock frequency in Hz */
 	int aifclk[WM8994_MAX_AIF];	/* audio interface clock in Hz   */
 	struct wm8994_fll_config fll[2]; /* fll config to configure fll */
+	struct udevice *dev;
 };
 
 /* wm 8994 supported sampling rate values */
@@ -60,29 +63,17 @@
 	640, 880, 960, 1280, 1760, 1920
 };
 
-static struct wm8994_priv g_wm8994_info;
-static unsigned char g_wm8994_i2c_dev_addr;
-static struct sound_codec_info g_codec_info;
-
-/*
- * Initialise I2C for wm 8994
- *
- * @param bus no	i2c bus number in which wm8994 is connected
- */
-static void wm8994_i2c_init(int bus_no)
-{
-	i2c_set_bus_num(bus_no);
-}
-
 /*
  * Writes value to a device register through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	reg number to be write
  * @param data	data to be writen to the above registor
  *
  * @return	int value 1 for change, 0 for no change or negative error code.
  */
-static int wm8994_i2c_write(unsigned int reg, unsigned short data)
+static int wm8994_i2c_write(struct wm8994_priv *priv, unsigned int reg,
+			    unsigned short data)
 {
 	unsigned char val[2];
 
@@ -90,23 +81,25 @@
 	val[1] = (unsigned char)(data & 0xff);
 	debug("Write Addr : 0x%04X, Data :  0x%04X\n", reg, data);
 
-	return i2c_write(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+	return dm_i2c_write(priv->dev, reg, val, 2);
 }
 
 /*
  * Read a value from a device register through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	reg number to be read
  * @param data	address of read data to be stored
  *
  * @return	int value 0 for success, -1 in case of error.
  */
-static unsigned int  wm8994_i2c_read(unsigned int reg , unsigned short *data)
+static unsigned int wm8994_i2c_read(struct wm8994_priv *priv, unsigned int reg,
+				    unsigned short *data)
 {
 	unsigned char val[2];
 	int ret;
 
-	ret = i2c_read(g_wm8994_i2c_dev_addr, reg, 2, val, 2);
+	ret = dm_i2c_read(priv->dev, reg, val, 1);
 	if (ret != 0) {
 		debug("%s: Error while reading register %#04x\n",
 		      __func__, reg);
@@ -123,6 +116,7 @@
 /*
  * update device register bits through i2c
  *
+ * @param priv	Private data for driver
  * @param reg	codec register
  * @param mask	register mask
  * @param value	new value
@@ -130,18 +124,18 @@
  * @return int value 1 if change in the register value,
  * 0 for no change or negative error code.
  */
-static int wm8994_update_bits(unsigned int reg, unsigned short mask,
-						unsigned short value)
+static int wm8994_bic_or(struct wm8994_priv *priv, unsigned int reg,
+			 unsigned short mask, unsigned short value)
 {
 	int change , ret = 0;
 	unsigned short old, new;
 
-	if (wm8994_i2c_read(reg, &old) != 0)
+	if (wm8994_i2c_read(priv, reg, &old) != 0)
 		return -1;
 	new = (old & ~mask) | (value & mask);
 	change  = (old != new) ? 1 : 0;
 	if (change)
-		ret = wm8994_i2c_write(reg, new);
+		ret = wm8994_i2c_write(priv, reg, new);
 	if (ret < 0)
 		return ret;
 
@@ -151,12 +145,13 @@
 /*
  * Sets i2s set format
  *
+ * @param priv		wm8994 information
  * @param aif_id	Interface ID
  * @param fmt		i2S format
  *
  * @return -1 for error and 0  Success.
  */
-int wm8994_set_fmt(int aif_id, unsigned int fmt)
+static int wm8994_set_fmt(struct wm8994_priv *priv, int aif_id, uint fmt)
 {
 	int ms_reg;
 	int aif_reg;
@@ -254,12 +249,13 @@
 		return -1;
 	}
 
-	error = wm8994_update_bits(aif_reg, WM8994_AIF1_BCLK_INV |
-			WM8994_AIF1_LRCLK_INV_MASK | WM8994_AIF1_FMT_MASK, aif);
+	error = wm8994_bic_or(priv, aif_reg, WM8994_AIF1_BCLK_INV |
+			      WM8994_AIF1_LRCLK_INV_MASK |
+			       WM8994_AIF1_FMT_MASK, aif);
 
-	error |= wm8994_update_bits(ms_reg, WM8994_AIF1_MSTR_MASK, ms);
-	error |= wm8994_update_bits(aif_clk, WM8994_AIF1CLK_ENA_MASK,
-						WM8994_AIF1CLK_ENA);
+	error |= wm8994_bic_or(priv, ms_reg, WM8994_AIF1_MSTR_MASK, ms);
+	error |= wm8994_bic_or(priv, aif_clk, WM8994_AIF1CLK_ENA_MASK,
+			       WM8994_AIF1CLK_ENA);
 	if (error < 0) {
 		debug("%s: codec register access error\n", __func__);
 		return -1;
@@ -271,7 +267,7 @@
 /*
  * Sets hw params FOR WM8994
  *
- * @param wm8994		wm8994 information pointer
+ * @param priv			wm8994 information pointer
  * @param aif_id		Audio interface ID
  * @param sampling_rate		Sampling rate
  * @param bits_per_sample	Bits per sample
@@ -279,9 +275,9 @@
  *
  * @return -1 for error  and 0  Success.
  */
-static int wm8994_hw_params(struct wm8994_priv *wm8994, int aif_id,
-		unsigned int sampling_rate, unsigned int bits_per_sample,
-		unsigned int channels)
+static int wm8994_hw_params(struct wm8994_priv *priv, int aif_id,
+			    uint sampling_rate, uint bits_per_sample,
+			    uint channels)
 {
 	int aif1_reg;
 	int aif2_reg;
@@ -349,12 +345,10 @@
 
 	/* AIFCLK/fs ratio; look for a close match in either direction */
 	best = 0;
-	best_val = abs((fs_ratios[0] * sampling_rate)
-						- wm8994->aifclk[id]);
+	best_val = abs((fs_ratios[0] * sampling_rate) - priv->aifclk[id]);
 
 	for (i = 1; i < ARRAY_SIZE(fs_ratios); i++) {
-		cur_val = abs((fs_ratios[i] * sampling_rate)
-					- wm8994->aifclk[id]);
+		cur_val = abs(fs_ratios[i] * sampling_rate - priv->aifclk[id]);
 		if (cur_val >= best_val)
 			continue;
 		best = i;
@@ -371,7 +365,7 @@
 	 */
 	best = 0;
 	for (i = 0; i < ARRAY_SIZE(bclk_divs); i++) {
-		cur_val = (wm8994->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
+		cur_val = (priv->aifclk[id] * 10 / bclk_divs[i]) - bclk_rate;
 		if (cur_val < 0) /* BCLK table is sorted */
 			break;
 		best = i;
@@ -383,10 +377,10 @@
 		return -1;
 	}
 
-	bclk_rate = wm8994->aifclk[id] * 10 / bclk_divs[best];
+	bclk_rate = priv->aifclk[id] * 10 / bclk_divs[best];
 	bclk |= best << WM8994_AIF1_BCLK_DIV_SHIFT;
 
-	if (wm8994_i2c_read(aif1_reg, &reg_data) != 0) {
+	if (wm8994_i2c_read(priv, aif1_reg, &reg_data) != 0) {
 		debug("%s: AIF1 register read Failed\n", __func__);
 		return -1;
 	}
@@ -394,16 +388,17 @@
 	if ((channels == 1) && ((reg_data & 0x18) == 0x18))
 		aif2 |= WM8994_AIF1_MONO;
 
-	if (wm8994->aifclk[id] == 0) {
+	if (priv->aifclk[id] == 0) {
 		debug("%s:Audio interface clock not set\n", __func__);
 		return -1;
 	}
 
-	ret = wm8994_update_bits(aif1_reg, WM8994_AIF1_WL_MASK, aif1);
-	ret |= wm8994_update_bits(aif2_reg, WM8994_AIF1_MONO, aif2);
-	ret |= wm8994_update_bits(bclk_reg, WM8994_AIF1_BCLK_DIV_MASK, bclk);
-	ret |= wm8994_update_bits(rate_reg, WM8994_AIF1_SR_MASK |
-				WM8994_AIF1CLK_RATE_MASK, rate_val);
+	ret = wm8994_bic_or(priv, aif1_reg, WM8994_AIF1_WL_MASK, aif1);
+	ret |= wm8994_bic_or(priv, aif2_reg, WM8994_AIF1_MONO, aif2);
+	ret |= wm8994_bic_or(priv, bclk_reg, WM8994_AIF1_BCLK_DIV_MASK,
+				  bclk);
+	ret |= wm8994_bic_or(priv, rate_reg, WM8994_AIF1_SR_MASK |
+				  WM8994_AIF1CLK_RATE_MASK, rate_val);
 
 	debug("rate vale = %x , bclk val= %x\n", rate_val, bclk);
 
@@ -418,12 +413,12 @@
 /*
  * Configures Audio interface Clock
  *
- * @param wm8994	wm8994 information pointer
+ * @param priv		wm8994 information pointer
  * @param aif		Audio Interface ID
  *
  * @return -1 for error  and 0  Success.
  */
-static int configure_aif_clock(struct wm8994_priv *wm8994, int aif)
+static int configure_aif_clock(struct wm8994_priv *priv, int aif)
 {
 	int rate;
 	int reg1 = 0;
@@ -436,30 +431,30 @@
 	else
 		offset = 0;
 
-	switch (wm8994->sysclk[aif-1]) {
+	switch (priv->sysclk[aif - 1]) {
 	case WM8994_SYSCLK_MCLK1:
 		reg1 |= SEL_MCLK1;
-		rate = wm8994->mclk[0];
+		rate = priv->mclk[0];
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		reg1 |= SEL_MCLK2;
-		rate = wm8994->mclk[1];
+		rate = priv->mclk[1];
 		break;
 
 	case WM8994_SYSCLK_FLL1:
 		reg1 |= SEL_FLL1;
-		rate = wm8994->fll[0].out;
+		rate = priv->fll[0].out;
 		break;
 
 	case WM8994_SYSCLK_FLL2:
 		reg1 |= SEL_FLL2;
-		rate = wm8994->fll[1].out;
+		rate = priv->fll[1].out;
 		break;
 
 	default:
 		debug("%s: Invalid input clock selection [%d]\n",
-		      __func__, wm8994->sysclk[aif-1]);
+		      __func__, priv->sysclk[aif - 1]);
 		return -1;
 	}
 
@@ -469,18 +464,18 @@
 		reg1 |= WM8994_AIF1CLK_DIV;
 	}
 
-	wm8994->aifclk[aif-1] = rate;
+	priv->aifclk[aif - 1] = rate;
 
-	ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_1 + offset,
-				WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
-				reg1);
+	ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_1 + offset,
+			    WM8994_AIF1CLK_SRC_MASK | WM8994_AIF1CLK_DIV,
+			    reg1);
 
 	if (aif == WM8994_AIF1)
-		ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
 			WM8994_AIF1DSPCLK_ENA_MASK | WM8994_SYSDSPCLK_ENA_MASK,
 			WM8994_AIF1DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
 	else if (aif == WM8994_AIF2)
-		ret |= wm8994_update_bits(WM8994_CLOCKING_1,
+		ret |= wm8994_bic_or(priv, WM8994_CLOCKING_1,
 			WM8994_SYSCLK_SRC | WM8994_AIF2DSPCLK_ENA_MASK |
 			WM8994_SYSDSPCLK_ENA_MASK, WM8994_SYSCLK_SRC |
 			WM8994_AIF2DSPCLK_ENA | WM8994_SYSDSPCLK_ENA);
@@ -496,33 +491,33 @@
 /*
  * Configures Audio interface  for the given frequency
  *
- * @param wm8994	wm8994 information
+ * @param priv		wm8994 information
  * @param aif_id	Audio Interface
  * @param clk_id	Input Clock ID
  * @param freq		Sampling frequency in Hz
  *
  * @return -1 for error and 0 success.
  */
-static int wm8994_set_sysclk(struct wm8994_priv *wm8994, int aif_id,
-				int clk_id, unsigned int freq)
+static int wm8994_set_sysclk(struct wm8994_priv *priv, int aif_id, int clk_id,
+			     unsigned int freq)
 {
 	int i;
 	int ret = 0;
 
-	wm8994->sysclk[aif_id - 1] = clk_id;
+	priv->sysclk[aif_id - 1] = clk_id;
 
 	switch (clk_id) {
 	case WM8994_SYSCLK_MCLK1:
-		wm8994->mclk[0] = freq;
+		priv->mclk[0] = freq;
 		if (aif_id == 2) {
-			ret = wm8994_update_bits(WM8994_AIF1_CLOCKING_2 ,
-			WM8994_AIF2DAC_DIV_MASK , 0);
+			ret = wm8994_bic_or(priv, WM8994_AIF1_CLOCKING_2,
+					    WM8994_AIF2DAC_DIV_MASK, 0);
 		}
 		break;
 
 	case WM8994_SYSCLK_MCLK2:
 		/* TODO: Set GPIO AF */
-		wm8994->mclk[1] = freq;
+		priv->mclk[1] = freq;
 		break;
 
 	case WM8994_SYSCLK_FLL1:
@@ -543,13 +538,14 @@
 				      __func__);
 				return -1;
 			}
-			ret = wm8994_update_bits(WM8994_CLOCKING_2,
+			ret = wm8994_bic_or(priv, WM8994_CLOCKING_2,
 					    WM8994_OPCLK_DIV_MASK, i);
-			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
-					    WM8994_OPCLK_ENA, WM8994_OPCLK_ENA);
+			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+					     WM8994_OPCLK_ENA,
+					     WM8994_OPCLK_ENA);
 		} else {
-			ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_2,
-					    WM8994_OPCLK_ENA, 0);
+			ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_2,
+					     WM8994_OPCLK_ENA, 0);
 		}
 
 	default:
@@ -558,7 +554,7 @@
 		return -1;
 	}
 
-	ret |= configure_aif_clock(wm8994, aif_id);
+	ret |= configure_aif_clock(priv, aif_id);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -571,37 +567,38 @@
 /*
  * Initializes Volume for AIF2 to HP path
  *
+ * @param priv		wm8994 information
  * @returns -1 for error  and 0 Success.
  *
  */
-static int wm8994_init_volume_aif2_dac1(void)
+static int wm8994_init_volume_aif2_dac1(struct wm8994_priv *priv)
 {
 	int ret;
 
 	/* Unmute AIF2DAC */
-	ret = wm8994_update_bits(WM8994_AIF2_DAC_FILTERS_1,
-			WM8994_AIF2DAC_MUTE_MASK, 0);
+	ret = wm8994_bic_or(priv, WM8994_AIF2_DAC_FILTERS_1,
+			    WM8994_AIF2DAC_MUTE_MASK, 0);
 
 
-	ret |= wm8994_update_bits(WM8994_AIF2_DAC_LEFT_VOLUME,
-			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
-			WM8994_AIF2DAC_VU | 0xff);
+	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_LEFT_VOLUME,
+			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACL_VOL_MASK,
+			     WM8994_AIF2DAC_VU | 0xff);
 
-	ret |= wm8994_update_bits(WM8994_AIF2_DAC_RIGHT_VOLUME,
-			WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
-			WM8994_AIF2DAC_VU | 0xff);
+	ret |= wm8994_bic_or(priv, WM8994_AIF2_DAC_RIGHT_VOLUME,
+			     WM8994_AIF2DAC_VU_MASK | WM8994_AIF2DACR_VOL_MASK,
+			     WM8994_AIF2DAC_VU | 0xff);
 
 
-	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
-			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
-			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 	/* Head Phone Volume */
-	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
-	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -614,26 +611,27 @@
 /*
  * Initializes Volume for AIF1 to HP path
  *
+ * @param priv		wm8994 information
  * @returns -1 for error  and 0 Success.
  *
  */
-static int wm8994_init_volume_aif1_dac1(void)
+static int wm8994_init_volume_aif1_dac1(struct wm8994_priv *priv)
 {
 	int ret = 0;
 
 	/* Unmute AIF1DAC */
-	ret |= wm8994_i2c_write(WM8994_AIF1_DAC_FILTERS_1, 0x0000);
+	ret |= wm8994_i2c_write(priv, WM8994_AIF1_DAC_FILTERS_1, 0x0000);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_LEFT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
-			WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1L_VOL_MASK |
+			     WM8994_DAC1L_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 
-	ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_VOLUME,
-			WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
-			WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
+	ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_VOLUME,
+			     WM8994_DAC1_VU_MASK | WM8994_DAC1R_VOL_MASK |
+			     WM8994_DAC1R_MUTE_MASK, WM8994_DAC1_VU | 0xc0);
 	/* Head Phone Volume */
-	ret |= wm8994_i2c_write(WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
-	ret |= wm8994_i2c_write(WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_LEFT_OUTPUT_VOLUME, 0x12D);
+	ret |= wm8994_i2c_write(priv, WM8994_RIGHT_OUTPUT_VOLUME, 0x12D);
 
 	if (ret < 0) {
 		debug("%s: codec register access error\n", __func__);
@@ -646,93 +644,99 @@
 /*
  * Intialise wm8994 codec device
  *
- * @param wm8994	wm8994 information
+ * @param priv		wm8994 information
  *
  * @returns -1 for error  and 0 Success.
  */
-static int wm8994_device_init(struct wm8994_priv *wm8994,
-			      enum en_audio_interface aif_id)
+static int wm8994_device_init(struct wm8994_priv *priv)
 {
 	const char *devname;
 	unsigned short reg_data;
 	int ret;
 
-	wm8994_i2c_write(WM8994_SOFTWARE_RESET, WM8994_SW_RESET);/* Reset */
+	wm8994_i2c_write(priv, WM8994_SOFTWARE_RESET, WM8994_SW_RESET);
 
-	ret = wm8994_i2c_read(WM8994_SOFTWARE_RESET, &reg_data);
+	ret = wm8994_i2c_read(priv, WM8994_SOFTWARE_RESET, &reg_data);
 	if (ret < 0) {
 		debug("Failed to read ID register\n");
-		goto err;
+		return ret;
 	}
 
 	if (reg_data == WM8994_ID) {
 		devname = "WM8994";
-		debug("Device registered as type %d\n", wm8994->type);
-		wm8994->type = WM8994;
+		debug("Device registered as type %d\n", priv->type);
+		priv->type = WM8994;
 	} else {
 		debug("Device is not a WM8994, ID is %x\n", ret);
-		ret = -1;
-		goto err;
+		return -ENXIO;
 	}
 
-	ret = wm8994_i2c_read(WM8994_CHIP_REVISION, &reg_data);
+	ret = wm8994_i2c_read(priv, WM8994_CHIP_REVISION, &reg_data);
 	if (ret < 0) {
 		debug("Failed to read revision register: %d\n", ret);
-		goto err;
+		return ret;
 	}
-	wm8994->revision = reg_data;
-	debug("%s revision %c\n", devname, 'A' + wm8994->revision);
+	priv->revision = reg_data;
+	debug("%s revision %c\n", devname, 'A' + priv->revision);
+
+	return 0;
+}
+
+static int wm8994_setup_interface(struct wm8994_priv *priv,
+				  enum en_audio_interface aif_id)
+{
+	int ret;
 
 	/* VMID Selection */
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-			WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
+	ret = wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			    WM8994_VMID_SEL_MASK | WM8994_BIAS_ENA_MASK, 0x3);
 
 	/* Charge Pump Enable */
-	ret |= wm8994_update_bits(WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
-					WM8994_CP_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_CHARGE_PUMP_1, WM8994_CP_ENA_MASK,
+			     WM8994_CP_ENA);
 
 	/* Head Phone Power Enable */
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-			WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			     WM8994_HPOUT1L_ENA_MASK, WM8994_HPOUT1L_ENA);
 
-	ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_1,
-				WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
+	ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_1,
+			     WM8994_HPOUT1R_ENA_MASK, WM8994_HPOUT1R_ENA);
 
 	if (aif_id == WM8994_AIF1) {
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_2,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_2,
 					WM8994_TSHUT_ENA | WM8994_MIXINL_ENA |
 					WM8994_MIXINR_ENA | WM8994_IN2L_ENA |
 					WM8994_IN2R_ENA);
 
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_4,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_4,
 					WM8994_ADCL_ENA | WM8994_ADCR_ENA |
 					WM8994_AIF1ADC1R_ENA |
 					WM8994_AIF1ADC1L_ENA);
 
 		/* Power enable for AIF1 and DAC1 */
-		ret |= wm8994_i2c_write(WM8994_POWER_MANAGEMENT_5,
+		ret |= wm8994_i2c_write(priv, WM8994_POWER_MANAGEMENT_5,
 					WM8994_AIF1DACL_ENA |
 					WM8994_AIF1DACR_ENA |
 					WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
 	} else if (aif_id == WM8994_AIF2) {
 		/* Power enable for AIF2 and DAC1 */
-		ret |= wm8994_update_bits(WM8994_POWER_MANAGEMENT_5,
+		ret |= wm8994_bic_or(priv, WM8994_POWER_MANAGEMENT_5,
 			WM8994_AIF2DACL_ENA_MASK | WM8994_AIF2DACR_ENA_MASK |
 			WM8994_DAC1L_ENA_MASK | WM8994_DAC1R_ENA_MASK,
 			WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA |
 			WM8994_DAC1L_ENA | WM8994_DAC1R_ENA);
 	}
 	/* Head Phone Initialisation */
-	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
 		WM8994_HPOUT1L_DLY_MASK | WM8994_HPOUT1R_DLY_MASK,
 		WM8994_HPOUT1L_DLY | WM8994_HPOUT1R_DLY);
 
-	ret |= wm8994_update_bits(WM8994_DC_SERVO_1,
+	ret |= wm8994_bic_or(priv, WM8994_DC_SERVO_1,
 			WM8994_DCS_ENA_CHAN_0_MASK |
 			WM8994_DCS_ENA_CHAN_1_MASK , WM8994_DCS_ENA_CHAN_0 |
 			WM8994_DCS_ENA_CHAN_1);
 
-	ret |= wm8994_update_bits(WM8994_ANALOGUE_HP_1,
+	ret |= wm8994_bic_or(priv, WM8994_ANALOGUE_HP_1,
 			WM8994_HPOUT1L_DLY_MASK |
 			WM8994_HPOUT1R_DLY_MASK | WM8994_HPOUT1L_OUTP_MASK |
 			WM8994_HPOUT1R_OUTP_MASK |
@@ -743,172 +747,130 @@
 			WM8994_HPOUT1R_RMV_SHORT);
 
 	/* MIXER Config DAC1 to HP */
-	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_1,
-			WM8994_DAC1L_TO_HPOUT1L_MASK, WM8994_DAC1L_TO_HPOUT1L);
+	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_1,
+			     WM8994_DAC1L_TO_HPOUT1L_MASK,
+			     WM8994_DAC1L_TO_HPOUT1L);
 
-	ret |= wm8994_update_bits(WM8994_OUTPUT_MIXER_2,
-			WM8994_DAC1R_TO_HPOUT1R_MASK, WM8994_DAC1R_TO_HPOUT1R);
+	ret |= wm8994_bic_or(priv, WM8994_OUTPUT_MIXER_2,
+			     WM8994_DAC1R_TO_HPOUT1R_MASK,
+			     WM8994_DAC1R_TO_HPOUT1R);
 
 	if (aif_id == WM8994_AIF1) {
 		/* Routing AIF1 to DAC1 */
-		ret |= wm8994_i2c_write(WM8994_DAC1_LEFT_MIXER_ROUTING,
-				WM8994_AIF1DAC1L_TO_DAC1L);
+		ret |= wm8994_i2c_write(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
+					WM8994_AIF1DAC1L_TO_DAC1L);
 
-		ret |= wm8994_i2c_write(WM8994_DAC1_RIGHT_MIXER_ROUTING,
+		ret |= wm8994_i2c_write(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
 					WM8994_AIF1DAC1R_TO_DAC1R);
 
 		/* GPIO Settings for AIF1 */
-		ret |=  wm8994_i2c_write(WM8994_GPIO_1, WM8994_GPIO_DIR_OUTPUT
-					 | WM8994_GPIO_FUNCTION_I2S_CLK
-					 | WM8994_GPIO_INPUT_DEBOUNCE);
+		ret |=  wm8994_i2c_write(priv, WM8994_GPIO_1,
+					 WM8994_GPIO_DIR_OUTPUT |
+					 WM8994_GPIO_FUNCTION_I2S_CLK |
+					 WM8994_GPIO_INPUT_DEBOUNCE);
 
-		ret |= wm8994_init_volume_aif1_dac1();
+		ret |= wm8994_init_volume_aif1_dac1(priv);
 	} else if (aif_id == WM8994_AIF2) {
 		/* Routing AIF2 to DAC1 */
-		ret |= wm8994_update_bits(WM8994_DAC1_LEFT_MIXER_ROUTING,
-				WM8994_AIF2DACL_TO_DAC1L_MASK,
-				WM8994_AIF2DACL_TO_DAC1L);
+		ret |= wm8994_bic_or(priv, WM8994_DAC1_LEFT_MIXER_ROUTING,
+				     WM8994_AIF2DACL_TO_DAC1L_MASK,
+				     WM8994_AIF2DACL_TO_DAC1L);
 
-		ret |= wm8994_update_bits(WM8994_DAC1_RIGHT_MIXER_ROUTING,
-				WM8994_AIF2DACR_TO_DAC1R_MASK,
-				WM8994_AIF2DACR_TO_DAC1R);
+		ret |= wm8994_bic_or(priv, WM8994_DAC1_RIGHT_MIXER_ROUTING,
+				     WM8994_AIF2DACR_TO_DAC1R_MASK,
+				     WM8994_AIF2DACR_TO_DAC1R);
 
 		/* GPIO Settings for AIF2 */
 		/* B CLK */
-		ret |= wm8994_update_bits(WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK ,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_3, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
 		/* LR CLK */
-		ret |= wm8994_update_bits(WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_4, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
 		/* DATA */
-		ret |= wm8994_update_bits(WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
-					WM8994_GPIO_FUNCTION_MASK,
-					WM8994_GPIO_DIR_OUTPUT);
+		ret |= wm8994_bic_or(priv, WM8994_GPIO_5, WM8994_GPIO_DIR_MASK |
+				     WM8994_GPIO_FUNCTION_MASK,
+				     WM8994_GPIO_DIR_OUTPUT);
 
-		ret |= wm8994_init_volume_aif2_dac1();
+		ret |= wm8994_init_volume_aif2_dac1(priv);
 	}
 
 	if (ret < 0)
 		goto err;
 
-	debug("%s: Codec chip init ok\n", __func__);
+	debug("%s: Codec chip setup ok\n", __func__);
 	return 0;
 err:
-	debug("%s: Codec chip init error\n", __func__);
+	debug("%s: Codec chip setup error\n", __func__);
 	return -1;
 }
 
-/*
- * Gets fdt values for wm8994 config parameters
- *
- * @param pcodec_info	codec information structure
- * @param blob		FDT blob
- * @return		int value, 0 for success
- */
-static int get_codec_values(struct sound_codec_info *pcodec_info,
-			const void *blob)
+static int _wm8994_init(struct wm8994_priv *priv,
+			enum en_audio_interface aif_id, int sampling_rate,
+			int mclk_freq, int bits_per_sample,
+			unsigned int channels)
 {
-	int error = 0;
-#if CONFIG_IS_ENABLED(OF_CONTROL)
-	enum fdt_compat_id compat;
-	int node;
-	int parent;
+	int ret;
 
-	/* Get the node from FDT for codec */
-	node = fdtdec_next_compatible(blob, 0, COMPAT_WOLFSON_WM8994_CODEC);
-	if (node <= 0) {
-		debug("EXYNOS_SOUND: No node for codec in device tree\n");
-		debug("node = %d\n", node);
-		return -1;
-	}
-
-	parent = fdt_parent_offset(blob, node);
-	if (parent < 0) {
-		debug("%s: Cannot find node parent\n", __func__);
-		return -1;
-	}
-
-	compat = fdtdec_lookup(blob, parent);
-	switch (compat) {
-	case COMPAT_SAMSUNG_S3C2440_I2C:
-		pcodec_info->i2c_bus = i2c_get_bus_num_fdt(parent);
-		error |= pcodec_info->i2c_bus;
-		debug("i2c bus = %d\n", pcodec_info->i2c_bus);
-		pcodec_info->i2c_dev_addr = fdtdec_get_int(blob, node,
-							"reg", 0);
-		error |= pcodec_info->i2c_dev_addr;
-		debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-		break;
-	default:
-		debug("%s: Unknown compat id %d\n", __func__, compat);
-		return -1;
-	}
-#else
-	pcodec_info->i2c_bus = AUDIO_I2C_BUS;
-	pcodec_info->i2c_dev_addr = AUDIO_I2C_REG;
-	debug("i2c dev addr = %d\n", pcodec_info->i2c_dev_addr);
-#endif
-
-	pcodec_info->codec_type = CODEC_WM_8994;
-
-	if (error == -1) {
-		debug("fail to get wm8994 codec node properties\n");
-		return -1;
-	}
-
-	return 0;
-}
-
-/* WM8994 Device Initialisation */
-int wm8994_init(const void *blob, enum en_audio_interface aif_id,
-			int sampling_rate, int mclk_freq,
-			int bits_per_sample, unsigned int channels)
-{
-	int ret = 0;
-	struct sound_codec_info *pcodec_info = &g_codec_info;
-
-	/* Get the codec Values */
-	if (get_codec_values(pcodec_info, blob) < 0) {
-		debug("FDT Codec values failed\n");
-		return -1;
-	}
-
-	/* shift the device address by 1 for 7 bit addressing */
-	g_wm8994_i2c_dev_addr = pcodec_info->i2c_dev_addr;
-	wm8994_i2c_init(pcodec_info->i2c_bus);
-
-	if (pcodec_info->codec_type == CODEC_WM_8994) {
-		g_wm8994_info.type = WM8994;
-	} else {
-		debug("%s: Codec id [%d] not defined\n", __func__,
-		      pcodec_info->codec_type);
-		return -1;
-	}
-
-	ret = wm8994_device_init(&g_wm8994_info, aif_id);
+	ret = wm8994_setup_interface(priv, aif_id);
 	if (ret < 0) {
 		debug("%s: wm8994 codec chip init failed\n", __func__);
 		return ret;
 	}
 
-	ret =  wm8994_set_sysclk(&g_wm8994_info, aif_id, WM8994_SYSCLK_MCLK1,
-							mclk_freq);
+	ret = wm8994_set_sysclk(priv, aif_id, WM8994_SYSCLK_MCLK1, mclk_freq);
 	if (ret < 0) {
 		debug("%s: wm8994 codec set sys clock failed\n", __func__);
 		return ret;
 	}
 
-	ret = wm8994_hw_params(&g_wm8994_info, aif_id, sampling_rate,
-						bits_per_sample, channels);
+	ret = wm8994_hw_params(priv, aif_id, sampling_rate, bits_per_sample,
+			       channels);
 
 	if (ret == 0) {
-		ret = wm8994_set_fmt(aif_id, SND_SOC_DAIFMT_I2S |
-						SND_SOC_DAIFMT_NB_NF |
-						SND_SOC_DAIFMT_CBS_CFS);
+		ret = wm8994_set_fmt(priv, aif_id, SND_SOC_DAIFMT_I2S |
+				     SND_SOC_DAIFMT_NB_NF |
+				     SND_SOC_DAIFMT_CBS_CFS);
 	}
+
 	return ret;
 }
+
+static int wm8994_set_params(struct udevice *dev, int interface, int rate,
+			     int mclk_freq, int bits_per_sample, uint channels)
+{
+	struct wm8994_priv *priv = dev_get_priv(dev);
+
+	return _wm8994_init(priv, interface, rate, mclk_freq, bits_per_sample,
+			    channels);
+}
+
+static int wm8994_probe(struct udevice *dev)
+{
+	struct wm8994_priv *priv = dev_get_priv(dev);
+
+	priv->dev = dev;
+	return wm8994_device_init(priv);
+}
+
+static const struct audio_codec_ops wm8994_ops = {
+	.set_params	= wm8994_set_params,
+};
+
+static const struct udevice_id wm8994_ids[] = {
+	{ .compatible = "wolfson,wm8994" },
+	{ }
+};
+
+U_BOOT_DRIVER(wm8994) = {
+	.name		= "wm8994",
+	.id		= UCLASS_AUDIO_CODEC,
+	.of_match	= wm8994_ids,
+	.probe		= wm8994_probe,
+	.ops		= &wm8994_ops,
+	.priv_auto_alloc_size	= sizeof(struct wm8994_priv),
+};
diff --git a/drivers/sound/wm8994.h b/drivers/sound/wm8994.h
index ef2878f..e36e626 100644
--- a/drivers/sound/wm8994.h
+++ b/drivers/sound/wm8994.h
@@ -15,7 +15,7 @@
 
 /*  Avilable audi interface ports in wm8994 codec */
 enum en_audio_interface {
-	 WM8994_AIF1 = 1,
+	 WM8994_AIF1,
 	 WM8994_AIF2,
 	 WM8994_AIF3
 };
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 5cca414..02d9376 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -369,7 +369,13 @@
 	return 0;
 }
 
-static void external_cs_manage(struct udevice *dev, bool on)
+/*
+ * We define external_cs_manage function as 'weak' as some targets
+ * (like MSCC Ocelot) don't control the external CS pin using a GPIO
+ * controller. These SoCs use specific registers to control by
+ * software the SPI pins (and especially the CS).
+ */
+__weak void external_cs_manage(struct udevice *dev, bool on)
 {
 #if defined(CONFIG_DM_GPIO) && !defined(CONFIG_SPL_BUILD)
 	struct dw_spi_priv *priv = dev_get_priv(dev->parent);
diff --git a/drivers/tee/optee/supplicant.c b/drivers/tee/optee/supplicant.c
index b1ea65b..c5726ec 100644
--- a/drivers/tee/optee/supplicant.c
+++ b/drivers/tee/optee/supplicant.c
@@ -82,8 +82,8 @@
 		cmd_shm_free(arg);
 		break;
 	case OPTEE_MSG_RPC_CMD_FS:
-		debug("OPTEE_MSG_RPC_CMD_FS not implemented\n");
-		arg->ret = TEE_ERROR_NOT_IMPLEMENTED;
+		debug("REE FS storage isn't available\n");
+		arg->ret = TEE_ERROR_STORAGE_NOT_AVAILABLE;
 		break;
 	case OPTEE_MSG_RPC_CMD_RPMB:
 		optee_suppl_cmd_rpmb(dev, arg);
diff --git a/drivers/timer/Kconfig b/drivers/timer/Kconfig
index b0e6f32..df37a79 100644
--- a/drivers/timer/Kconfig
+++ b/drivers/timer/Kconfig
@@ -126,6 +126,13 @@
 	help
 	  Select this to enable an timer for Omap devices.
 
+config RISCV_TIMER
+	bool "RISC-V timer support"
+	depends on TIMER && RISCV
+	help
+	  Select this to enable support for the timer as defined
+	  by the RISC-V privileged architecture spec.
+
 config ROCKCHIP_TIMER
 	bool "Rockchip timer support"
 	depends on TIMER
diff --git a/drivers/timer/Makefile b/drivers/timer/Makefile
index c4fbab2..d0bf218 100644
--- a/drivers/timer/Makefile
+++ b/drivers/timer/Makefile
@@ -13,6 +13,7 @@
 obj-$(CONFIG_DESIGNWARE_APB_TIMER)	+= dw-apb-timer.o
 obj-$(CONFIG_MPC83XX_TIMER) += mpc83xx_timer.o
 obj-$(CONFIG_OMAP_TIMER)	+= omap-timer.o
+obj-$(CONFIG_RISCV_TIMER) += riscv_timer.o
 obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
 obj-$(CONFIG_SANDBOX_TIMER)	+= sandbox_timer.o
 obj-$(CONFIG_STI_TIMER)		+= sti-timer.o
diff --git a/drivers/timer/riscv_timer.c b/drivers/timer/riscv_timer.c
new file mode 100644
index 0000000..9f9f070
--- /dev/null
+++ b/drivers/timer/riscv_timer.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018, Bin Meng <bmeng.cn@gmail.com>
+ *
+ * RISC-V privileged architecture defined generic timer driver
+ *
+ * This driver relies on RISC-V platform codes to provide the essential API
+ * riscv_get_time() which is supposed to return the timer counter as defined
+ * by the RISC-V privileged architecture spec.
+ *
+ * This driver can be used in both M-mode and S-mode U-Boot.
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <timer.h>
+#include <asm/io.h>
+
+/**
+ * riscv_get_time() - get the timer counter
+ *
+ * Platform codes should provide this API in order to make this driver function.
+ *
+ * @time:	the 64-bit timer count  as defined by the RISC-V privileged
+ *		architecture spec.
+ * @return:	0 on success, -ve on error.
+ */
+extern int riscv_get_time(u64 *time);
+
+static int riscv_timer_get_count(struct udevice *dev, u64 *count)
+{
+	return riscv_get_time(count);
+}
+
+static int riscv_timer_probe(struct udevice *dev)
+{
+	struct timer_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+
+	/* clock frequency was passed from the cpu driver as driver data */
+	uc_priv->clock_rate = dev->driver_data;
+
+	return 0;
+}
+
+static const struct timer_ops riscv_timer_ops = {
+	.get_count = riscv_timer_get_count,
+};
+
+U_BOOT_DRIVER(riscv_timer) = {
+	.name = "riscv_timer",
+	.id = UCLASS_TIMER,
+	.probe = riscv_timer_probe,
+	.ops = &riscv_timer_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 98f8343..3b53bf2 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -49,7 +49,7 @@
 
 config SPL_DM_USB
 	bool "Enable driver model for USB in SPL"
-	depends on DM_USB
+	depends on SPL_DM && DM_USB
 	default y
 
 config DM_USB_GADGET
diff --git a/drivers/usb/dwc3/dwc3-generic.c b/drivers/usb/dwc3/dwc3-generic.c
index bc6bba1..3e6c494 100644
--- a/drivers/usb/dwc3/dwc3-generic.c
+++ b/drivers/usb/dwc3/dwc3-generic.c
@@ -342,7 +342,9 @@
 
 static const struct udevice_id dwc3_glue_ids[] = {
 	{ .compatible = "xlnx,zynqmp-dwc3" },
+	{ .compatible = "ti,keystone-dwc3"},
 	{ .compatible = "ti,dwc3", .data = (ulong)&ti_ops },
+	{ .compatible = "ti,am437x-dwc3", .data = (ulong)&ti_ops },
 	{ }
 };
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index e340cb2..085f7b8 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -16,7 +16,6 @@
 #include <common.h>
 #include <malloc.h>
 #include <asm/dma-mapping.h>
-#include <usb/lin_gadget_compat.h>
 #include <linux/bug.h>
 #include <linux/list.h>
 
diff --git a/drivers/usb/dwc3/ti_usb_phy.c b/drivers/usb/dwc3/ti_usb_phy.c
index d168e86..e7ea12c 100644
--- a/drivers/usb/dwc3/ti_usb_phy.c
+++ b/drivers/usb/dwc3/ti_usb_phy.c
@@ -19,7 +19,6 @@
 #include <common.h>
 #include <malloc.h>
 #include <ti-usb-phy-uboot.h>
-#include <usb/lin_gadget_compat.h>
 #include <linux/ioport.h>
 #include <asm/io.h>
 #include <asm/arch/sys_proto.h>
diff --git a/drivers/usb/eth/r8152.c b/drivers/usb/eth/r8152.c
index 941158a..e5f73e3 100644
--- a/drivers/usb/eth/r8152.c
+++ b/drivers/usb/eth/r8152.c
@@ -10,7 +10,6 @@
 #include <malloc.h>
 #include <memalign.h>
 #include <usb.h>
-#include <usb/lin_gadget_compat.h>
 #include <linux/mii.h>
 #include <linux/bitops.h>
 #include "usb_ether.h"
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 39ea870..2a6626b 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -24,7 +24,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/at91_udc.h>
 #include <malloc.h>
-#include <usb/lin_gadget_compat.h>
 
 #include "at91_udc.h"
 
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index c9d4833..dffa511 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -16,7 +16,6 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/atmel_usba_udc.h>
 #include <malloc.h>
-#include <usb/lin_gadget_compat.h>
 
 #include "atmel_usba_udc.h"
 
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 5106cc5..c7e7623 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -735,8 +735,21 @@
 		case USB_DT_DEVICE:
 			cdev->desc.bNumConfigurations =
 				count_configs(cdev, USB_DT_DEVICE);
-			cdev->desc.bMaxPacketSize0 =
-				cdev->gadget->ep0->maxpacket;
+
+			/*
+			 * If the speed is Super speed, then the supported
+			 * max packet size is 512 and it should be sent as
+			 * exponent of 2. So, 9(2^9=512) should be filled in
+			 * bMaxPacketSize0. Also fill USB version as 3.0
+			 * if speed is Super speed.
+			 */
+			if (cdev->gadget->speed == USB_SPEED_SUPER) {
+				cdev->desc.bMaxPacketSize0 = 9;
+				cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+			} else {
+				cdev->desc.bMaxPacketSize0 =
+					cdev->gadget->ep0->maxpacket;
+			}
 			value = min(w_length, (u16) sizeof cdev->desc);
 			memcpy(req->buf, &cdev->desc, value);
 			break;
diff --git a/drivers/usb/gadget/dwc2_udc_otg.c b/drivers/usb/gadget/dwc2_udc_otg.c
index e3edd10..3c7ad03 100644
--- a/drivers/usb/gadget/dwc2_udc_otg.c
+++ b/drivers/usb/gadget/dwc2_udc_otg.c
@@ -33,7 +33,6 @@
 
 #include "dwc2_udc_otg_regs.h"
 #include "dwc2_udc_otg_priv.h"
-#include <usb/lin_gadget_compat.h>
 
 /***********************************************************/
 
diff --git a/drivers/usb/gadget/dwc2_udc_otg_phy.c b/drivers/usb/gadget/dwc2_udc_otg_phy.c
index 47aa78a..c4338af 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_phy.c
+++ b/drivers/usb/gadget/dwc2_udc_otg_phy.c
@@ -33,7 +33,6 @@
 
 #include "dwc2_udc_otg_regs.h"
 #include "dwc2_udc_otg_priv.h"
-#include <usb/lin_gadget_compat.h>
 
 #include <usb/dwc2_udc.h>
 
diff --git a/drivers/usb/gadget/dwc2_udc_otg_priv.h b/drivers/usb/gadget/dwc2_udc_otg_priv.h
index b64e222..aaa9018 100644
--- a/drivers/usb/gadget/dwc2_udc_otg_priv.h
+++ b/drivers/usb/gadget/dwc2_udc_otg_priv.h
@@ -12,7 +12,6 @@
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 #include <linux/list.h>
-#include <usb/lin_gadget_compat.h>
 #include <usb/dwc2_udc.h>
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index a3101af..45c7b58 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -256,7 +256,7 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/gadget.h>
 #include <linux/usb/composite.h>
-#include <usb/lin_gadget_compat.h>
+#include <linux/bitmap.h>
 #include <g_dnl.h>
 
 /*------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/f_sdp.c b/drivers/usb/gadget/f_sdp.c
index 00a9f88..ae97ab2 100644
--- a/drivers/usb/gadget/f_sdp.c
+++ b/drivers/usb/gadget/f_sdp.c
@@ -100,6 +100,7 @@
 	enum sdp_state			state;
 	enum sdp_state			next_state;
 	u32				dnl_address;
+	u32				dnl_bytes;
 	u32				dnl_bytes_remaining;
 	u32				jmp_address;
 	bool				always_send_status;
@@ -276,6 +277,7 @@
 		sdp->state = SDP_STATE_RX_FILE_DATA;
 		sdp->dnl_address = be32_to_cpu(cmd->addr);
 		sdp->dnl_bytes_remaining = be32_to_cpu(cmd->cnt);
+		sdp->dnl_bytes = sdp->dnl_bytes_remaining;
 		sdp->next_state = SDP_STATE_IDLE;
 
 		printf("Downloading file of size %d to 0x%08x... ",
@@ -355,6 +357,9 @@
 	if (sdp->dnl_bytes_remaining)
 		return;
 
+#ifndef CONFIG_SPL_BUILD
+	env_set_hex("filesize", sdp->dnl_bytes);
+#endif
 	printf("done\n");
 
 	switch (sdp->state) {
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index 44092df..09c0a30 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -29,7 +29,6 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <usb/lin_gadget_compat.h>
 #include <asm/arch/pxa-regs.h>
 
 #include "pxa25x_udc.h"
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 285c20a..948683a 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -50,7 +50,6 @@
 obj-$(CONFIG_USB_XHCI_DWC3_OF_SIMPLE) += dwc3-of-simple.o
 obj-$(CONFIG_USB_XHCI_ROCKCHIP) += xhci-rockchip.o
 obj-$(CONFIG_USB_XHCI_ZYNQMP) += xhci-zynqmp.o
-obj-$(CONFIG_USB_XHCI_KEYSTONE) += xhci-keystone.o
 obj-$(CONFIG_USB_XHCI_EXYNOS) += xhci-exynos5.o
 obj-$(CONFIG_USB_XHCI_FSL) += xhci-fsl.o
 obj-$(CONFIG_USB_XHCI_MVEBU) += xhci-mvebu.o
diff --git a/drivers/usb/host/xhci-keystone.c b/drivers/usb/host/xhci-keystone.c
deleted file mode 100644
index 200b3f0..0000000
--- a/drivers/usb/host/xhci-keystone.c
+++ /dev/null
@@ -1,240 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * USB 3.0 DRD Controller
- *
- * (C) Copyright 2012-2014
- *     Texas Instruments Incorporated, <www.ti.com>
- */
-
-#include <common.h>
-#include <watchdog.h>
-#include <usb.h>
-#include <asm/arch/psc_defs.h>
-#include <asm/io.h>
-#include <linux/usb/dwc3.h>
-#include <asm/arch/xhci-keystone.h>
-#include <linux/errno.h>
-#include <linux/list.h>
-#include "xhci.h"
-
-struct kdwc3_irq_regs {
-	u32 revision;	/* 0x000 */
-	u32 rsvd0[3];
-	u32 sysconfig;	/* 0x010 */
-	u32 rsvd1[1];
-	u32 irq_eoi;
-	u32 rsvd2[1];
-	struct {
-		u32 raw_status;
-		u32 status;
-		u32 enable_set;
-		u32 enable_clr;
-	} irqs[16];
-};
-
-struct keystone_xhci {
-	struct xhci_hccr *hcd;
-	struct dwc3 *dwc3_reg;
-	struct xhci_hcor *hcor;
-	struct kdwc3_irq_regs *usbss;
-	struct keystone_xhci_phy *phy;
-};
-
-struct keystone_xhci keystone;
-
-static void keystone_xhci_phy_set(struct keystone_xhci_phy *phy)
-{
-	u32 val;
-
-	/*
-	 * VBUSVLDEXTSEL has a default value of 1 in BootCfg but shouldn't.
-	 * It should always be cleared because our USB PHY has an onchip VBUS
-	 * analog comparator.
-	 */
-	val = readl(&phy->phy_clock);
-	/* quit selecting the vbusvldextsel by default! */
-	val &= ~USB3_PHY_OTG_VBUSVLDECTSEL;
-	writel(val, &phy->phy_clock);
-}
-
-static void keystone_xhci_phy_unset(struct keystone_xhci_phy *phy)
-{
-	u32 val;
-
-	/* Disable the PHY REFCLK clock gate */
-	val = readl(&phy->phy_clock);
-	val &= ~USB3_PHY_REF_SSP_EN;
-	writel(val, &phy->phy_clock);
-}
-
-static int keystone_xhci_core_init(struct dwc3 *dwc3_reg)
-{
-	int ret;
-
-	ret = dwc3_core_init(dwc3_reg);
-	if (ret) {
-		debug("failed to initialize core\n");
-		return -EINVAL;
-	}
-
-	/* We are hard-coding DWC3 core to Host Mode */
-	dwc3_set_mode(dwc3_reg, DWC3_GCTL_PRTCAP_HOST);
-
-	return 0;
-}
-
-int xhci_hcd_init(int index,
-		  struct xhci_hccr **ret_hccr, struct xhci_hcor **ret_hcor)
-{
-	u32 val;
-	int ret;
-	struct xhci_hccr *hcd;
-	struct xhci_hcor *hcor;
-	struct kdwc3_irq_regs *usbss;
-	struct keystone_xhci_phy *phy;
-
-	usbss = (struct kdwc3_irq_regs *)CONFIG_USB_SS_BASE;
-	phy = (struct keystone_xhci_phy *)CONFIG_DEV_USB_PHY_BASE;
-
-	/* Enable the PHY REFCLK clock gate with phy_ref_ssp_en = 1 */
-	val = readl(&(phy->phy_clock));
-	val |= USB3_PHY_REF_SSP_EN;
-	writel(val, &phy->phy_clock);
-
-	mdelay(100);
-
-	/* Release USB from reset */
-	ret = psc_enable_module(KS2_LPSC_USB);
-	if (ret) {
-		puts("Cannot enable USB module");
-		return -1;
-	}
-
-	mdelay(100);
-
-	/* Initialize usb phy */
-	keystone_xhci_phy_set(phy);
-
-	/* soft reset usbss */
-	writel(1, &usbss->sysconfig);
-	while (readl(&usbss->sysconfig) & 1)
-		;
-
-	val = readl(&usbss->revision);
-	debug("usbss revision %x\n", val);
-
-	/* Initialize usb core */
-	hcd = (struct xhci_hccr *)CONFIG_USB_HOST_XHCI_BASE;
-	keystone.dwc3_reg = (struct dwc3 *)(CONFIG_USB_HOST_XHCI_BASE +
-					    DWC3_REG_OFFSET);
-
-	keystone_xhci_core_init(keystone.dwc3_reg);
-
-	/* set register addresses */
-	hcor = (struct xhci_hcor *)((uint32_t)hcd +
-		HC_LENGTH(readl(&hcd->cr_capbase)));
-
-	debug("Keystone2-xhci: init hccr %08x and hcor %08x hc_length %d\n",
-	      (u32)hcd, (u32)hcor,
-	      (u32)HC_LENGTH(xhci_readl(&hcd->cr_capbase)));
-
-	keystone.usbss = usbss;
-	keystone.phy = phy;
-	keystone.hcd = hcd;
-	keystone.hcor = hcor;
-
-	*ret_hccr = hcd;
-	*ret_hcor = hcor;
-
-	return 0;
-}
-
-static int keystone_xhci_phy_suspend(void)
-{
-	int loop_cnt = 0;
-	struct xhci_hcor *hcor;
-	uint32_t *portsc_1 = NULL;
-	uint32_t *portsc_2 = NULL;
-	u32 val, usb2_pls, usb3_pls, event_q;
-	struct dwc3 *dwc3_reg = keystone.dwc3_reg;
-
-	/* set register addresses */
-	hcor = keystone.hcor;
-
-	/* Bypass Scrambling and Set Shorter Training sequence for simulation */
-	val = DWC3_GCTL_PWRDNSCALE(0x4b0) | DWC3_GCTL_PRTCAPDIR(0x2);
-	writel(val, &dwc3_reg->g_ctl);
-
-	/* GUSB2PHYCFG */
-	val = readl(&dwc3_reg->g_usb2phycfg[0]);
-
-	/* assert bit 6 (SusPhy) */
-	val |= DWC3_GUSB2PHYCFG_SUSPHY;
-	writel(val, &dwc3_reg->g_usb2phycfg[0]);
-
-	/* GUSB3PIPECTL */
-	val = readl(&dwc3_reg->g_usb3pipectl[0]);
-
-	/*
-	 * assert bit 29 to allow PHY to go to suspend when idle
-	 * and cause the USB3 SS PHY to enter suspend mode
-	 */
-	val |= (BIT(29) | DWC3_GUSB3PIPECTL_SUSPHY);
-	writel(val, &dwc3_reg->g_usb3pipectl[0]);
-
-	/*
-	 * Steps necessary to allow controller to suspend even when
-	 * VBUS is HIGH:
-	 * - Init DCFG[2:0] (DevSpd) to: 1=FS
-	 * - Init GEVNTADR0 to point to an eventQ
-	 * - Init GEVNTSIZ0 to 0x0100 to specify the size of the eventQ
-	 * - Init DCTL::Run_nStop = 1
-	 */
-	writel(0x00020001, &dwc3_reg->d_cfg);
-	/* TODO: local2global( (Uint32) eventQ )? */
-	writel((u32)&event_q, &dwc3_reg->g_evnt_buf[0].g_evntadrlo);
-	writel(0, &dwc3_reg->g_evnt_buf[0].g_evntadrhi);
-	writel(0x4, &dwc3_reg->g_evnt_buf[0].g_evntsiz);
-	/* Run */
-	writel(DWC3_DCTL_RUN_STOP, &dwc3_reg->d_ctl);
-
-	mdelay(100);
-
-	/* Wait for USB2 & USB3 PORTSC::PortLinkState to indicate suspend */
-	portsc_1 = (uint32_t *)(&hcor->portregs[0].or_portsc);
-	portsc_2 = (uint32_t *)(&hcor->portregs[1].or_portsc);
-	usb2_pls = 0;
-	usb3_pls = 0;
-	do {
-		++loop_cnt;
-		usb2_pls = (readl(portsc_1) & PORT_PLS_MASK) >> 5;
-		usb3_pls = (readl(portsc_2) & PORT_PLS_MASK) >> 5;
-	} while (((usb2_pls != 0x4) || (usb3_pls != 0x4)) && loop_cnt < 1000);
-
-	if (usb2_pls != 0x4 || usb3_pls != 0x4) {
-		debug("USB suspend failed - PLS USB2=%02x, USB3=%02x\n",
-		      usb2_pls, usb3_pls);
-		return -1;
-	}
-
-	debug("USB2 and USB3 PLS - Disabled, loop_cnt=%d\n", loop_cnt);
-	return 0;
-}
-
-void xhci_hcd_stop(int index)
-{
-	/* Disable USB */
-	if (keystone_xhci_phy_suspend())
-		return;
-
-	if (psc_disable_module(KS2_LPSC_USB)) {
-		debug("PSC disable module USB failed!\n");
-		return;
-	}
-
-	/* Disable PHY */
-	keystone_xhci_phy_unset(keystone.phy);
-
-/*	memset(&keystone, 0, sizeof(struct keystone_xhci)); */
-	debug("xhci_hcd_stop OK.\n");
-}
diff --git a/drivers/usb/musb-new/am35x.c b/drivers/usb/musb-new/am35x.c
index 251b4e9..bda099c 100644
--- a/drivers/usb/musb-new/am35x.c
+++ b/drivers/usb/musb-new/am35x.c
@@ -406,7 +406,7 @@
 	musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK);
 
 	/* Start the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 1);
 
 	msleep(5);
@@ -437,7 +437,7 @@
 #endif
 
 	/* Shutdown the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 0);
 
 #ifndef __UBOOT__
@@ -628,7 +628,7 @@
 	struct omap_musb_board_data *data = plat->board_data;
 
 	/* Shutdown the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 0);
 
 	clk_disable(glue->phy_clk);
@@ -645,7 +645,7 @@
 	int			ret;
 
 	/* Start the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 1);
 
 	ret = clk_enable(glue->phy_clk);
diff --git a/drivers/usb/musb-new/musb_dsps.c b/drivers/usb/musb-new/musb_dsps.c
index 9b814f4..0c794b3 100644
--- a/drivers/usb/musb-new/musb_dsps.c
+++ b/drivers/usb/musb-new/musb_dsps.c
@@ -450,7 +450,7 @@
 	dsps_writel(reg_base, wrp->control, (1 << wrp->reset));
 
 	/* Start the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 1);
 
 	musb->isr = dsps_interrupt;
@@ -491,7 +491,7 @@
 #endif
 
 	/* Shutdown the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 0);
 
 #ifndef __UBOOT__
@@ -691,7 +691,7 @@
 	struct omap_musb_board_data *data = plat->board_data;
 
 	/* Shutdown the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 0);
 
 	return 0;
@@ -703,7 +703,7 @@
 	struct omap_musb_board_data *data = plat->board_data;
 
 	/* Start the on-chip PHY and its PLL. */
-	if (data->set_phy_power)
+	if (data && data->set_phy_power)
 		data->set_phy_power(data->dev, 1);
 
 	return 0;
diff --git a/drivers/usb/musb-new/musb_gadget.c b/drivers/usb/musb-new/musb_gadget.c
index 8b6cec1..b35d33f 100644
--- a/drivers/usb/musb-new/musb_gadget.c
+++ b/drivers/usb/musb-new/musb_gadget.c
@@ -1775,6 +1775,14 @@
 		struct usb_gadget_driver *driver);
 static int musb_gadget_stop(struct usb_gadget *g,
 		struct usb_gadget_driver *driver);
+#else
+static int musb_gadget_stop(struct usb_gadget *g)
+{
+	struct musb	*musb = gadget_to_musb(g);
+
+	musb_stop(musb);
+	return 0;
+}
 #endif
 
 static const struct usb_gadget_ops musb_gadget_operations = {
@@ -1787,6 +1795,9 @@
 #ifndef __UBOOT__
 	.udc_start		= musb_gadget_start,
 	.udc_stop		= musb_gadget_stop,
+#else
+	.udc_start		= musb_gadget_start,
+	.udc_stop		= musb_gadget_stop,
 #endif
 };
 
diff --git a/drivers/usb/musb-new/musb_uboot.c b/drivers/usb/musb-new/musb_uboot.c
index d40772b..9c8cc6e 100644
--- a/drivers/usb/musb-new/musb_uboot.c
+++ b/drivers/usb/musb-new/musb_uboot.c
@@ -367,7 +367,7 @@
 #endif /* CONFIG_IS_ENABLED(DM_USB) */
 #endif /* CONFIG_USB_MUSB_HOST */
 
-#ifdef CONFIG_USB_MUSB_GADGET
+#if defined(CONFIG_USB_MUSB_GADGET) && !CONFIG_IS_ENABLED(DM_USB_GADGET)
 static struct musb *gadget;
 
 int usb_gadget_handle_interrupts(int index)
@@ -430,7 +430,7 @@
 		musbp = &musb_host.host;
 		break;
 #endif
-#ifdef CONFIG_USB_MUSB_GADGET
+#if defined(CONFIG_USB_MUSB_GADGET) && !CONFIG_IS_ENABLED(DM_USB_GADGET)
 	case MUSB_PERIPHERAL:
 		musbp = &gadget;
 		break;
diff --git a/drivers/usb/musb-new/sunxi.c b/drivers/usb/musb-new/sunxi.c
index d7170a3..f542a18 100644
--- a/drivers/usb/musb-new/sunxi.c
+++ b/drivers/usb/musb-new/sunxi.c
@@ -435,11 +435,14 @@
 {
 	struct sunxi_glue *glue = dev_get_priv(dev);
 	struct musb_host_data *host = &glue->mdata;
-	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
 	struct musb_hdrc_platform_data pdata;
 	void *base = dev_read_addr_ptr(dev);
 	int ret;
 
+#ifdef CONFIG_USB_MUSB_HOST
+	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
+#endif
+
 	if (!base)
 		return -EINVAL;
 
@@ -459,7 +462,6 @@
 		return ret;
 	}
 
-	priv->desc_before_addr = true;
 
 	memset(&pdata, 0, sizeof(pdata));
 	pdata.power = 250;
@@ -467,6 +469,8 @@
 	pdata.config = glue->cfg->config;
 
 #ifdef CONFIG_USB_MUSB_HOST
+	priv->desc_before_addr = true;
+
 	pdata.mode = MUSB_HOST;
 	host->host = musb_init_controller(&pdata, &glue->dev, base);
 	if (!host->host)
diff --git a/drivers/usb/musb-new/ti-musb.c b/drivers/usb/musb-new/ti-musb.c
index ee09607..20ca273 100644
--- a/drivers/usb/musb-new/ti-musb.c
+++ b/drivers/usb/musb-new/ti-musb.c
@@ -20,22 +20,33 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 #if CONFIG_IS_ENABLED(DM_USB)
-
 /* USB 2.0 PHY Control */
 #define CM_PHY_PWRDN			(1 << 0)
 #define CM_PHY_OTG_PWRDN		(1 << 1)
 #define OTGVDET_EN			(1 << 19)
 #define OTGSESSENDEN			(1 << 20)
 
+#define AM335X_USB0_CTRL	0x0
 #define AM335X_USB1_CTRL	0x8
 
-struct ti_musb_platdata {
-	void *base;
-	void *ctrl_mod_base;
-	struct musb_hdrc_platform_data plat;
-	struct musb_hdrc_config musb_config;
-	struct omap_musb_board_data otg_board_data;
-};
+static void ti_musb_set_phy_power(struct udevice *dev, u8 on)
+{
+	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
+
+	if (!platdata->ctrl_mod_base)
+		return;
+
+	if (on) {
+		clrsetbits_le32(platdata->ctrl_mod_base,
+				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN,
+				OTGVDET_EN | OTGSESSENDEN);
+	} else {
+		clrsetbits_le32(platdata->ctrl_mod_base, 0,
+				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN);
+	}
+}
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
 
 static int ti_musb_get_usb_index(int node)
 {
@@ -64,20 +75,6 @@
 	return -ENOENT;
 }
 
-static void ti_musb_set_phy_power(struct udevice *dev, u8 on)
-{
-	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
-
-	if (on) {
-		clrsetbits_le32(platdata->ctrl_mod_base,
-				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN,
-				OTGVDET_EN | OTGSESSENDEN);
-	} else {
-		clrsetbits_le32(platdata->ctrl_mod_base, 0,
-				CM_PHY_PWRDN | CM_PHY_OTG_PWRDN);
-	}
-}
-
 static int ti_musb_ofdata_to_platdata(struct udevice *dev)
 {
 	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
@@ -86,6 +83,7 @@
 	int phys;
 	int ctrl_mod;
 	int usb_index;
+	struct musb_hdrc_config *musb_config;
 
 	platdata->base = (void *)devfdt_get_addr_index(dev, 1);
 
@@ -96,38 +94,41 @@
 	switch (usb_index) {
 	case 1:
 		platdata->ctrl_mod_base += AM335X_USB1_CTRL;
+		break;
 	case 0:
+		platdata->ctrl_mod_base += AM335X_USB0_CTRL;
+		break;
 	default:
 		break;
 	}
 
-	platdata->musb_config.multipoint = fdtdec_get_int(fdt, node,
-							  "mentor,multipoint",
-							  -1);
-	if (platdata->musb_config.multipoint < 0) {
+	musb_config = malloc(sizeof(struct musb_hdrc_config));
+	memset(musb_config, 0, sizeof(struct musb_hdrc_config));
+
+	musb_config->multipoint = fdtdec_get_int(fdt, node,
+						 "mentor,multipoint", -1);
+	if (musb_config->multipoint < 0) {
 		pr_err("MUSB multipoint DT entry missing\n");
 		return -ENOENT;
 	}
 
-	platdata->musb_config.dyn_fifo = 1;
+	musb_config->dyn_fifo = 1;
 
-	platdata->musb_config.num_eps = fdtdec_get_int(fdt, node,
-						       "mentor,num-eps", -1);
-	if (platdata->musb_config.num_eps < 0) {
+	musb_config->num_eps = fdtdec_get_int(fdt, node, "mentor,num-eps",
+					      -1);
+	if (musb_config->num_eps < 0) {
 		pr_err("MUSB num-eps DT entry missing\n");
 		return -ENOENT;
 	}
 
-	platdata->musb_config.ram_bits = fdtdec_get_int(fdt, node,
-							"mentor,ram-bits", -1);
-	if (platdata->musb_config.ram_bits < 0) {
+	musb_config->ram_bits = fdtdec_get_int(fdt, node, "mentor,ram-bits",
+					       -1);
+	if (musb_config->ram_bits < 0) {
 		pr_err("MUSB ram-bits DT entry missing\n");
 		return -ENOENT;
 	}
 
-	platdata->otg_board_data.set_phy_power = ti_musb_set_phy_power;
-	platdata->otg_board_data.dev = dev;
-	platdata->plat.config = &platdata->musb_config;
+	platdata->plat.config = musb_config;
 
 	platdata->plat.power = fdtdec_get_int(fdt, node, "mentor,power", -1);
 	if (platdata->plat.power < 0) {
@@ -136,29 +137,27 @@
 	}
 
 	platdata->plat.platform_ops = &musb_dsps_ops;
-	platdata->plat.board_data = &platdata->otg_board_data;
 
 	return 0;
 }
+#endif
 
 static int ti_musb_host_probe(struct udevice *dev)
 {
 	struct musb_host_data *host = dev_get_priv(dev);
 	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
 	struct usb_bus_priv *priv = dev_get_uclass_priv(dev);
-	struct omap_musb_board_data *otg_board_data;
 	int ret;
 
 	priv->desc_before_addr = true;
 
-	otg_board_data = &platdata->otg_board_data;
-
 	host->host = musb_init_controller(&platdata->plat,
-					  (struct device *)otg_board_data,
+					  NULL,
 					  platdata->base);
 	if (!host->host)
 		return -EIO;
 
+	ti_musb_set_phy_power(dev, 1);
 	ret = musb_lowlevel_init(host);
 
 	return ret;
@@ -169,10 +168,12 @@
 	struct musb_host_data *host = dev_get_priv(dev);
 
 	musb_stop(host->host);
+	ti_musb_set_phy_power(dev, 0);
 
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(OF_CONTROL)
 static int ti_musb_host_ofdata_to_platdata(struct udevice *dev)
 {
 	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
@@ -190,11 +191,14 @@
 
 	return 0;
 }
+#endif
 
 U_BOOT_DRIVER(ti_musb_host) = {
 	.name	= "ti-musb-host",
 	.id	= UCLASS_USB,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
 	.ofdata_to_platdata = ti_musb_host_ofdata_to_platdata,
+#endif
 	.probe = ti_musb_host_probe,
 	.remove = ti_musb_host_remove,
 	.ops	= &musb_usb_ops,
@@ -202,6 +206,82 @@
 	.priv_auto_alloc_size = sizeof(struct musb_host_data),
 };
 
+#if CONFIG_IS_ENABLED(DM_USB_GADGET)
+struct ti_musb_peripheral {
+	struct musb *periph;
+};
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+static int ti_musb_peripheral_ofdata_to_platdata(struct udevice *dev)
+{
+	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(dev);
+	int ret;
+
+	ret = ti_musb_ofdata_to_platdata(dev);
+	if (ret) {
+		pr_err("platdata dt parse error\n");
+		return ret;
+	}
+	platdata->plat.mode = MUSB_PERIPHERAL;
+
+	return 0;
+}
+#endif
+
+int dm_usb_gadget_handle_interrupts(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+
+	priv->periph->isr(0, priv->periph);
+
+	return 0;
+}
+
+static int ti_musb_peripheral_probe(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+	struct ti_musb_platdata *platdata = dev_get_platdata(dev);
+	int ret;
+
+	priv->periph = musb_init_controller(&platdata->plat,
+					    NULL,
+					    platdata->base);
+	if (!priv->periph)
+		return -EIO;
+
+	ti_musb_set_phy_power(dev, 1);
+	musb_gadget_setup(priv->periph);
+	return usb_add_gadget_udc((struct device *)dev, &priv->periph->g);
+}
+
+static int ti_musb_peripheral_remove(struct udevice *dev)
+{
+	struct ti_musb_peripheral *priv = dev_get_priv(dev);
+
+	usb_del_gadget_udc(&priv->periph->g);
+	ti_musb_set_phy_power(dev, 0);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(ti_musb_peripheral) = {
+	.name	= "ti-musb-peripheral",
+	.id	= UCLASS_USB_GADGET_GENERIC,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.ofdata_to_platdata = ti_musb_peripheral_ofdata_to_platdata,
+#endif
+	.probe = ti_musb_peripheral_probe,
+	.remove = ti_musb_peripheral_remove,
+	.ops	= &musb_usb_ops,
+	.platdata_auto_alloc_size = sizeof(struct ti_musb_platdata),
+	.priv_auto_alloc_size = sizeof(struct ti_musb_peripheral),
+	.flags = DM_FLAG_PRE_RELOC,
+};
+#endif
+
+#if CONFIG_IS_ENABLED(OF_CONTROL)
 static int ti_musb_wrapper_bind(struct udevice *parent)
 {
 	const void *fdt = gd->fdt_blob;
@@ -222,15 +302,23 @@
 		switch (dr_mode) {
 		case USB_DR_MODE_PERIPHERAL:
 			/* Bind MUSB device */
+			ret = device_bind_driver_to_node(parent,
+							 "ti-musb-peripheral",
+							 name,
+							 offset_to_ofnode(node),
+							 &dev);
+			if (ret)
+				pr_err("musb - not able to bind usb peripheral node\n");
 			break;
 		case USB_DR_MODE_HOST:
 			/* Bind MUSB host */
-			ret = device_bind_driver_to_node(parent, "ti-musb-host",
-					name, offset_to_ofnode(node), &dev);
-			if (ret) {
+			ret = device_bind_driver_to_node(parent,
+							 "ti-musb-host",
+							 name,
+							 offset_to_ofnode(node),
+							 &dev);
+			if (ret)
 				pr_err("musb - not able to bind usb host node\n");
-				return ret;
-			}
 			break;
 		default:
 			break;
@@ -250,5 +338,6 @@
 	.of_match = ti_musb_ids,
 	.bind = ti_musb_wrapper_bind,
 };
+#endif /* CONFIG_IS_ENABLED(OF_CONTROL) */
 
 #endif /* CONFIG_IS_ENABLED(DM_USB) */
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index dd42f69..2508b6e 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -11,17 +11,10 @@
 config USB_MUSB_UDC
 	bool "Legacy USB Device Controller"
 
-config USB_DAVINCI
-	bool "Legacy MUSB DaVinci"
-	
 config USB_OMAP3
 	bool "Legacy MUSB OMAP3 / OMAP4"
 	depends on ARCH_OMAP2PLUS
 
-config USB_DA8XX
-	bool "Legacy MUSB DA8xx/OMAP-L1x"
-	depends on ARCH_DAVINCI
-
 config USB_AM35X
 	bool"Legacy MUSB AM35x"
 	depends on ARCH_OMAP2PLUS && !USB_OMAP3
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index bdb3cd8..744f2cf 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -5,7 +5,5 @@
 
 obj-$(CONFIG_USB_MUSB_HCD) += musb_hcd.o musb_core.o
 obj-$(CONFIG_USB_MUSB_UDC) += musb_udc.o musb_core.o
-obj-$(CONFIG_USB_DAVINCI) += davinci.o
 obj-$(CONFIG_USB_OMAP3) += omap3.o
-obj-$(CONFIG_USB_DA8XX) += da8xx.o
 obj-$(CONFIG_USB_AM35X) += am35x.o
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
deleted file mode 100644
index a652a7c..0000000
--- a/drivers/usb/musb/da8xx.c
+++ /dev/null
@@ -1,127 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * da8xx.c - TI's DA8xx platform specific usb wrapper functions.
- *
- * Author: Ajay Kumar Gupta <ajay.gupta@ti.com>
- *
- * Based on drivers/usb/musb/davinci.c
- *
- * Copyright (C) 2009 Texas Instruments Incorporated
- */
-#include <common.h>
-
-#include "musb_core.h"
-#include <asm/arch/da8xx-usb.h>
-
-/* MUSB platform configuration */
-struct musb_config musb_cfg = {
-	.regs		= (struct musb_regs *)DA8XX_USB_OTG_CORE_BASE,
-	.timeout	= DA8XX_USB_OTG_TIMEOUT,
-	.musb_speed	= 0,
-};
-
-/*
- * This function enables VBUS by driving the GPIO Bank4 Pin 15 high.
- */
-static void enable_vbus(void)
-{
-	u32 value;
-
-	/* configure GPIO bank4 pin 15 in output direction */
-	value = readl(&davinci_gpio_bank45->dir);
-	writel((value & (~DA8XX_USB_VBUS_GPIO)), &davinci_gpio_bank45->dir);
-
-	/* set GPIO bank4 pin 15 high to drive VBUS */
-	value = readl(&davinci_gpio_bank45->set_data);
-	writel((value | DA8XX_USB_VBUS_GPIO), &davinci_gpio_bank45->set_data);
-}
-
-/*
- * Enable the usb0 phy. This initialization procedure is explained in
- * the DA8xx USB user guide document.
- */
-static u8 phy_on(void)
-{
-	u32 timeout;
-	u32 cfgchip2;
-
-	cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2);
-
-	cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN |
-		      CFGCHIP2_OTGMODE | CFGCHIP2_REFFREQ);
-	cfgchip2 |= CFGCHIP2_SESENDEN | CFGCHIP2_VBDTCTEN | CFGCHIP2_PHY_PLLON |
-		    CFGCHIP2_REFFREQ_24MHZ;
-
-	writel(cfgchip2, &davinci_syscfg_regs->cfgchip2);
-
-	/* wait until the usb phy pll locks */
-	timeout = musb_cfg.timeout;
-	while (timeout--)
-		if (readl(&davinci_syscfg_regs->cfgchip2) & CFGCHIP2_PHYCLKGD)
-			return 1;
-
-	/* USB phy was not turned on */
-	return 0;
-}
-
-/*
- * Disable the usb phy
- */
-static void phy_off(void)
-{
-	u32 cfgchip2;
-
-	/*
-	 * Power down the on-chip PHY.
-	 */
-	cfgchip2 = readl(&davinci_syscfg_regs->cfgchip2);
-	cfgchip2 &= ~CFGCHIP2_PHY_PLLON;
-	cfgchip2 |= CFGCHIP2_PHYPWRDN | CFGCHIP2_OTGPWRDN;
-	writel(cfgchip2, &davinci_syscfg_regs->cfgchip2);
-}
-
-/*
- * This function performs DA8xx platform specific initialization for usb0.
- */
-int musb_platform_init(void)
-{
-	u32  revision;
-
-	/* enable psc for usb2.0 */
-	lpsc_on(33);
-
-	/* enable usb vbus */
-	enable_vbus();
-
-	/* reset the controller */
-	writel(0x1, &da8xx_usb_regs->control);
-	udelay(5000);
-
-	/* start the on-chip usb phy and its pll */
-	if (phy_on() == 0)
-		return -1;
-
-	/* Returns zero if e.g. not clocked */
-	revision = readl(&da8xx_usb_regs->revision);
-	if (revision == 0)
-		return -1;
-
-	/* Disable all interrupts */
-	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
-		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_set);
-	return 0;
-}
-
-/*
- * This function performs DA8xx platform specific deinitialization for usb0.
- */
-void musb_platform_deinit(void)
-{
-	/* Turn of the phy */
-	phy_off();
-
-	/* flush any interrupts */
-	writel((DA8XX_USB_USBINT_MASK | DA8XX_USB_TXINT_MASK |
-		DA8XX_USB_RXINT_MASK), &da8xx_usb_regs->intmsk_clr);
-	writel(0, &da8xx_usb_regs->eoi);
-}
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
deleted file mode 100644
index 46cdb5a..0000000
--- a/drivers/usb/musb/davinci.c
+++ /dev/null
@@ -1,123 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * TI's Davinci platform specific USB wrapper functions.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#include <common.h>
-#include <asm/io.h>
-#include "davinci.h"
-#include <asm/arch/hardware.h>
-
-#if !defined(CONFIG_DV_USBPHY_CTL)
-#define CONFIG_DV_USBPHY_CTL (USBPHY_SESNDEN | USBPHY_VBDTCTEN)
-#endif
-
-/* MUSB platform configuration */
-struct musb_config musb_cfg = {
-	.regs		= (struct musb_regs *)MENTOR_USB0_BASE,
-	.timeout	= DAVINCI_USB_TIMEOUT,
-	.musb_speed	= 0,
-};
-
-/* MUSB module register overlay */
-struct davinci_usb_regs *dregs;
-
-/*
- * Enable the USB phy
- */
-static u8 phy_on(void)
-{
-	u32 timeout;
-#ifdef DAVINCI_DM365EVM
-	u32 val;
-#endif
-	/* Wait until the USB phy is turned on */
-#ifdef DAVINCI_DM365EVM
-	writel(USBPHY_PHY24MHZ | USBPHY_SESNDEN |
-			USBPHY_VBDTCTEN, USBPHY_CTL_PADDR);
-#else
-	writel(CONFIG_DV_USBPHY_CTL, USBPHY_CTL_PADDR);
-#endif
-	timeout = musb_cfg.timeout;
-
-#ifdef DAVINCI_DM365EVM
-	/* Set the ownership of GIO33 to USB */
-	val = readl(PINMUX4);
-	val &= ~(PINMUX4_USBDRVBUS_BITCLEAR);
-	val |= PINMUX4_USBDRVBUS_BITSET;
-	writel(val, PINMUX4);
-#endif
-	while (timeout--)
-		if (readl(USBPHY_CTL_PADDR) & USBPHY_PHYCLKGD)
-			return 1;
-
-	/* USB phy was not turned on */
-	return 0;
-}
-
-/*
- * Disable the USB phy
- */
-static void phy_off(void)
-{
-	/* powerdown the on-chip PHY and its oscillator */
-	writel(USBPHY_OSCPDWN | USBPHY_PHYPDWN, USBPHY_CTL_PADDR);
-}
-
-void __enable_vbus(void)
-{
-	/*
-	 *  nothing to do, vbus is handled through the cpu.
-	 *  Define this function in board code, if it is
-	 *  different on your board.
-	 */
-}
-void  enable_vbus(void)
-	__attribute__((weak, alias("__enable_vbus")));
-
-/*
- * This function performs Davinci platform specific initialization for usb0.
- */
-int musb_platform_init(void)
-{
-	u32  revision;
-
-	/* enable USB VBUS */
-	enable_vbus();
-
-	/* start the on-chip USB phy and its pll */
-	if (!phy_on())
-		return -1;
-
-	/* reset the controller */
-	dregs = (struct davinci_usb_regs *)DAVINCI_USB0_BASE;
-	writel(1, &dregs->ctrlr);
-	udelay(5000);
-
-	/* Returns zero if e.g. not clocked */
-	revision = readl(&dregs->version);
-	if (!revision)
-		return -1;
-
-	/* Disable all interrupts */
-	writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_RXINT_MASK |
-			DAVINCI_USB_TXINT_MASK , &dregs->intmsksetr);
-	return 0;
-}
-
-/*
- * This function performs Davinci platform specific deinitialization for usb0.
- */
-void musb_platform_deinit(void)
-{
-	/* Turn of the phy */
-	phy_off();
-
-	/* flush any interrupts */
-	writel(DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK |
-			DAVINCI_USB_RXINT_MASK , &dregs->intclrr);
-}
diff --git a/drivers/usb/musb/davinci.h b/drivers/usb/musb/davinci.h
deleted file mode 100644
index 29bb08c..0000000
--- a/drivers/usb/musb/davinci.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * TI's Davinci platform specific USB wrapper functions.
- *
- * Copyright (c) 2008 Texas Instruments
- *
- * Author: Thomas Abraham t-abraham@ti.com, Texas Instruments
- */
-
-#ifndef __DAVINCI_USB_H__
-#define __DAVINCI_USB_H__
-
-#include <asm/arch/hardware.h>
-#include "musb_core.h"
-
-/* Base address of DAVINCI usb0 wrapper */
-#define DAVINCI_USB0_BASE 0x01C64000
-
-/* Base address of DAVINCI musb core */
-#define MENTOR_USB0_BASE (DAVINCI_USB0_BASE+0x400)
-
-/*
- * Davinci platform USB wrapper register overlay. Note: Only the required
- * registers are included in this structure. It can be expanded as required.
- */
-struct davinci_usb_regs {
-	u32	version;
-	u32	ctrlr;
-	u32	reserved[0x20];
-	u32	intclrr;
-	u32 	intmskr;
-	u32 	intmsksetr;
-};
-
-#define DAVINCI_USB_TX_ENDPTS_MASK	0x1f /* ep0 + 4 tx */
-#define DAVINCI_USB_RX_ENDPTS_MASK	0x1e /* 4 rx */
-#define DAVINCI_USB_USBINT_SHIFT	16
-#define DAVINCI_USB_TXINT_SHIFT 	0
-#define DAVINCI_USB_RXINT_SHIFT 	8
-#define DAVINCI_INTR_DRVVBUS		0x0100
-
-#define DAVINCI_USB_USBINT_MASK 	0x01ff0000	/* 8 Mentor, DRVVBUS */
-#define DAVINCI_USB_TXINT_MASK \
-		(DAVINCI_USB_TX_ENDPTS_MASK << DAVINCI_USB_TXINT_SHIFT)
-#define DAVINCI_USB_RXINT_MASK \
-		(DAVINCI_USB_RX_ENDPTS_MASK << DAVINCI_USB_RXINT_SHIFT)
-#define MGC_BUSCTL_OFFSET(_bEnd, _bOffset) \
-		(0x80 + (8*(_bEnd)) + (_bOffset))
-
-/* Integrated highspeed/otg PHY */
-#define USBPHY_CTL_PADDR	(DAVINCI_SYSTEM_MODULE_BASE + 0x34)
-#define USBPHY_PHY24MHZ 	(1 << 13)
-#define USBPHY_PHYCLKGD 	(1 << 8)
-#define USBPHY_SESNDEN		(1 << 7)	/* v(sess_end) comparator */
-#define USBPHY_VBDTCTEN 	(1 << 6)	/* v(bus) comparator */
-#define USBPHY_PHYPLLON 	(1 << 4)	/* override pll suspend */
-#define USBPHY_CLKO1SEL 	(1 << 3)
-#define USBPHY_OSCPDWN		(1 << 2)
-#define USBPHY_PHYPDWN		(1 << 0)
-
-/* Timeout for Davinci USB module */
-#define DAVINCI_USB_TIMEOUT 0x3FFFFFF
-
-/* IO Expander I2C address and VBUS enable mask */
-#define IOEXP_I2C_ADDR 0x3A
-#define IOEXP_VBUSEN_MASK 1
-
-/* extern functions */
-extern void lpsc_on(unsigned int id);
-extern int i2c_write(uchar chip, uint addr, int alen, uchar *buffer, int len);
-extern int i2c_read(uchar chip, uint addr, int alen, uchar *buffer, int len);
-extern void enable_vbus(void);
-#endif	/* __DAVINCI_USB_H__ */
diff --git a/drivers/usb/musb/musb_udc.c b/drivers/usb/musb/musb_udc.c
index f1d6d85..7620114 100644
--- a/drivers/usb/musb/musb_udc.c
+++ b/drivers/usb/musb/musb_udc.c
@@ -46,8 +46,6 @@
 #include "omap3.h"
 #elif defined(CONFIG_USB_AM35X)
 #include "am35x.h"
-#elif defined(CONFIG_USB_DAVINCI)
-#include "davinci.h"
 #endif
 
 /* Define MUSB_DEBUG for debugging */
diff --git a/fs/cbfs/cbfs.c b/fs/cbfs/cbfs.c
index 0dce639..7b2513c 100644
--- a/fs/cbfs/cbfs.c
+++ b/fs/cbfs/cbfs.c
@@ -96,8 +96,7 @@
 		}
 
 		swap_file_header(&header, fileHeader);
-		if (header.offset < sizeof(struct cbfs_fileheader) ||
-		    header.offset > header.len) {
+		if (header.offset < sizeof(struct cbfs_fileheader)) {
 			file_cbfs_result = CBFS_BAD_FILE;
 			return -1;
 		}
@@ -190,8 +189,8 @@
 
 	start_of_rom = (u8 *)(end_of_rom + 1 - cbfs_header.rom_size);
 
-	file_cbfs_fill_cache(start_of_rom + cbfs_header.offset,
-			     cbfs_header.rom_size, cbfs_header.align);
+	file_cbfs_fill_cache(start_of_rom, cbfs_header.rom_size,
+			     cbfs_header.align);
 	if (file_cbfs_result == CBFS_SUCCESS)
 		initialized = 1;
 }
diff --git a/include/altera.h b/include/altera.h
index ead5d3d..22d55cf 100644
--- a/include/altera.h
+++ b/include/altera.h
@@ -39,6 +39,8 @@
 	fast_passive_parallel,
 	/* fast passive parallel with security (FPPS) */
 	fast_passive_parallel_security,
+	/* secure device manager (SDM) mailbox */
+	secure_device_manager_mailbox,
 	/* insert all new types before this */
 	max_altera_iface_type,
 };
@@ -54,6 +56,8 @@
 	Altera_StratixII,
 	/* StratixV Family */
 	Altera_StratixV,
+	/* Stratix10 Family */
+	Intel_FPGA_Stratix10,
 	/* SoCFPGA Family */
 	Altera_SoCFPGA,
 
@@ -116,4 +120,8 @@
 int stratixv_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size);
 #endif
 
+#ifdef CONFIG_FPGA_STRATIX10
+int stratix10_load(Altera_desc *desc, const void *rbf_data, size_t rbf_size);
+#endif
+
 #endif /* _ALTERA_H_ */
diff --git a/include/audio_codec.h b/include/audio_codec.h
new file mode 100644
index 0000000..2587099
--- /dev/null
+++ b/include/audio_codec.h
@@ -0,0 +1,48 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __AUDIO_CODEC_H__
+#define __AUDIO_CODEC_H__
+
+/*
+ * An audio codec turns digital data into sound with various parameters to
+ * control its operation.
+ */
+
+/* Operations for sound */
+struct audio_codec_ops {
+	/**
+	 * set_params() - Set audio codec parameters
+	 *
+	 * @dev: Sound device
+	 * @inteface: Interface number to use on codec
+	 * @rate: Sampling rate in Hz
+	 * @mclk_freq: Codec clock frequency in Hz
+	 * @bits_per_sample: Must be 16 or 24
+	 * @channels: Number of channels to use (1=mono, 2=stereo)
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*set_params)(struct udevice *dev, int interface, int rate,
+			  int mclk_freq, int bits_per_sample, uint channels);
+};
+
+#define audio_codec_get_ops(dev) ((struct audio_codec_ops *)(dev)->driver->ops)
+
+/**
+ * audio_codec_set_params() - Set audio codec parameters
+ *
+ * @dev: Sound device
+ * @inteface: Interface number to use on codec
+ * @rate: Sampling rate in Hz
+ * @mclk_freq: Codec clock frequency in Hz
+ * @bits_per_sample: Must be 16 or 24
+ * @channels: Number of channels to use (1=mono, 2=stereo)
+ * @return 0 if OK, -ve on error
+ */
+int audio_codec_set_params(struct udevice *dev, int interface, int rate,
+			   int mclk_freq, int bits_per_sample, uint channels);
+
+#endif  /* __AUDIO_CODEC_H__ */
diff --git a/include/bootm.h b/include/bootm.h
index 0501414..dbd6f49 100644
--- a/include/bootm.h
+++ b/include/bootm.h
@@ -35,6 +35,8 @@
 			bootm_headers_t *images);
 
 extern boot_os_fn do_bootm_linux;
+extern boot_os_fn do_bootm_vxworks;
+
 int do_bootelf(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 void lynxkdi_boot(image_header_t *hdr);
 
diff --git a/include/cbfs.h b/include/cbfs.h
index 1b88ec0..bd1bf75 100644
--- a/include/cbfs.h
+++ b/include/cbfs.h
@@ -18,16 +18,26 @@
 };
 
 enum cbfs_filetype {
+	CBFS_TYPE_BOOTBLOCK = 0x01,
+	CBFS_TYPE_CBFSHEADER = 0x02,
 	CBFS_TYPE_STAGE = 0x10,
 	CBFS_TYPE_PAYLOAD = 0x20,
+	CBFS_TYPE_FIT = 0x21,
 	CBFS_TYPE_OPTIONROM = 0x30,
 	CBFS_TYPE_BOOTSPLASH = 0x40,
 	CBFS_TYPE_RAW = 0x50,
 	CBFS_TYPE_VSA = 0x51,
 	CBFS_TYPE_MBI = 0x52,
 	CBFS_TYPE_MICROCODE = 0x53,
-	CBFS_COMPONENT_CMOS_DEFAULT = 0xaa,
-	CBFS_COMPONENT_CMOS_LAYOUT = 0x01aa
+	CBFS_TYPE_FSP = 0x60,
+	CBFS_TYPE_MRC = 0x61,
+	CBFS_TYPE_MMA = 0x62,
+	CBFS_TYPE_EFI = 0x63,
+	CBFS_TYPE_STRUCT = 0x70,
+	CBFS_TYPE_CMOS_DEFAULT = 0xaa,
+	CBFS_TYPE_SPD = 0xab,
+	CBFS_TYPE_MRC_CACHE = 0xac,
+	CBFS_TYPE_CMOS_LAYOUT = 0x01aa
 };
 
 struct cbfs_header {
diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
index 5d5b09b..3bd96b9 100644
--- a/include/configs/am335x_evm.h
+++ b/include/configs/am335x_evm.h
@@ -253,7 +253,6 @@
 #ifdef CONFIG_SPL_BUILD
 #undef CONFIG_DM_MMC
 #undef CONFIG_TIMER
-#undef CONFIG_DM_USB
 #endif
 
 #if defined(CONFIG_SPL_BUILD) && defined(CONFIG_SPL_USB_ETHER)
diff --git a/include/configs/bmips_common.h b/include/configs/bmips_common.h
index 39ca2e0..788f4af 100644
--- a/include/configs/bmips_common.h
+++ b/include/configs/bmips_common.h
@@ -6,6 +6,10 @@
 #ifndef __CONFIG_BMIPS_COMMON_H
 #define __CONFIG_BMIPS_COMMON_H
 
+/* ETH */
+#define CONFIG_PHY_RESET_DELAY		20
+#define CONFIG_SYS_RX_ETH_BUFFER	6
+
 /* UART */
 #define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
 					  230400, 500000, 1500000 }
@@ -16,7 +20,7 @@
 
 /* Memory usage */
 #define CONFIG_SYS_MAXARGS		24
-#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(2 * 1024 * 1024)
 #define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
 #define CONFIG_SYS_CBSIZE		512
 
diff --git a/include/configs/ci20.h b/include/configs/ci20.h
new file mode 100644
index 0000000..9a36213
--- /dev/null
+++ b/include/configs/ci20.h
@@ -0,0 +1,72 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * CI20 configuration
+ *
+ * Copyright (c) 2013 Imagination Technologies
+ * Author: Paul Burton <paul.burton@imgtec.com>
+ */
+
+#ifndef __CONFIG_CI20_H__
+#define __CONFIG_CI20_H__
+
+#define CONFIG_SKIP_LOWLEVEL_INIT
+
+/* Ingenic JZ4780 clock configuration. */
+#define CONFIG_SYS_HZ			1000
+#define CONFIG_SYS_MHZ			1200
+#define CONFIG_SYS_MIPS_TIMER_FREQ	(CONFIG_SYS_MHZ * 1000000)
+
+/* Memory configuration */
+#define CONFIG_SYS_MONITOR_LEN		(512 * 1024)
+#define CONFIG_SYS_MALLOC_LEN		(64 * 1024 * 1024)
+#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
+
+#define CONFIG_SYS_SDRAM_BASE		0x80000000 /* cached (KSEG0) address */
+#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+#define CONFIG_SYS_LOAD_ADDR		0x81000000
+#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
+#define CONFIG_SYS_MEMTEST_START	0x80000000
+#define CONFIG_SYS_MEMTEST_END		0x88000000
+
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+/* NS16550-ish UARTs */
+#define CONFIG_SYS_NS16550_CLK		48000000
+#define CONFIG_SYS_CONSOLE_IS_IN_ENV
+
+/* Ethernet: davicom DM9000 */
+#define CONFIG_DRIVER_DM9000		1
+#define CONFIG_DM9000_BASE		0xb6000000
+#define DM9000_IO			CONFIG_DM9000_BASE
+#define DM9000_DATA			(CONFIG_DM9000_BASE + 2)
+
+/* Environment */
+#define CONFIG_SYS_MMC_ENV_DEV		0
+#define CONFIG_ENV_SIZE			(32 << 10)
+#define CONFIG_ENV_OFFSET		((14 + 512) << 10)
+#define CONFIG_ENV_OVERWRITE
+
+/* Command line configuration. */
+#define CONFIG_SYS_CBSIZE	1024		/* Console I/O buffer size */
+#define CONFIG_SYS_MAXARGS	32		/* Max number of command args */
+#define CONFIG_SYS_BARGSIZE	CONFIG_SYS_CBSIZE
+						/* Boot argument buffer size */
+#define CONFIG_VERSION_VARIABLE			/* U-BOOT version */
+
+/* Miscellaneous configuration options */
+#define CONFIG_SYS_BOOTM_LEN		(64 << 20)
+
+/* SPL */
+#define CONFIG_SPL_STACK		0xf4008000 /* only max. 2KB spare! */
+
+#define CONFIG_SPL_TEXT_BASE		0xf4000a00
+#define CONFIG_SPL_MAX_SIZE		((14 * 1024) - 0xa00)
+
+#define CONFIG_SPL_BSS_START_ADDR	0xf4004000
+#define CONFIG_SPL_BSS_MAX_SIZE		0x00002000 /* 512KB, arbitrary */
+
+#define CONFIG_SPL_START_S_PATH		"arch/mips/mach-jz47xx"
+
+#define CONFIG_SYS_MMCSD_RAW_MODE_U_BOOT_SECTOR	0x1c	/* 14 KiB offset */
+
+#endif /* __CONFIG_CI20_H__ */
diff --git a/include/configs/edison.h b/include/configs/edison.h
index 86c584d..a6155ba 100644
--- a/include/configs/edison.h
+++ b/include/configs/edison.h
@@ -8,13 +8,6 @@
 
 #include <asm/ibmpc.h>
 
-/* ACPI */
-
-/* Boot */
-#define CONFIG_BOOTCOMMAND "run bootcmd"
-
-/* DISK Partition support */
-
 /* Miscellaneous configurable options */
 
 #define CONFIG_SYS_CBSIZE	2048
@@ -43,9 +36,6 @@
 #define CONFIG_ENV_OFFSET_REDUND		(6 * 1024 * 1024)
 #define CONFIG_SUPPORT_EMMC_BOOT
 
-/* PCI */
-#define CONFIG_CMD_PCI
-
 /* RTC */
 #define CONFIG_SYS_ISA_IO_BASE_ADDRESS	0
 
diff --git a/include/configs/elgin_rv1108.h b/include/configs/elgin_rv1108.h
new file mode 100644
index 0000000..aa6c4b0
--- /dev/null
+++ b/include/configs/elgin_rv1108.h
@@ -0,0 +1,13 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2016 Rockchip Electronics Co., Ltd
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#include <configs/rv1108_common.h>
+
+#define CONFIG_SYS_MMC_ENV_DEV	0
+
+#endif
diff --git a/include/configs/helios4.h b/include/configs/helios4.h
index 3157225..4e98f19 100644
--- a/include/configs/helios4.h
+++ b/include/configs/helios4.h
@@ -118,7 +118,7 @@
 #define CONFIG_SPL_SPI_FLASH_SUPPORT
 #define CONFIG_SPL_SPI_LOAD
 #define CONFIG_SPL_SPI_SUPPORT
-#define CONFIG_SYS_SPI_U_BOOT_OFFS	0x20000
+#define CONFIG_SYS_SPI_U_BOOT_OFFS	0x30000
 #define CONFIG_SYS_U_BOOT_OFFS		CONFIG_SYS_SPI_U_BOOT_OFFS
 #endif
 
diff --git a/include/configs/mt7623.h b/include/configs/mt7623.h
index 68da920..ba76350 100644
--- a/include/configs/mt7623.h
+++ b/include/configs/mt7623.h
@@ -46,7 +46,7 @@
 /* DRAM */
 #define CONFIG_SYS_SDRAM_BASE		0x80000000
 
-/* This is neede for kernel booting */
+/* This is needed for kernel booting */
 #define FDT_HIGH			"fdt_high=0xac000000\0"
 
 /* Extra environment variables */
diff --git a/include/configs/omap3_igep00x0.h b/include/configs/omap3_igep00x0.h
index b9d6569..775374c 100644
--- a/include/configs/omap3_igep00x0.h
+++ b/include/configs/omap3_igep00x0.h
@@ -20,10 +20,6 @@
 
 #define CONFIG_REVISION_TAG		1
 
-/* GPIO banks */
-#define CONFIG_OMAP3_GPIO_2		/* GPIO32..63   is in GPIO bank 2 */
-#define CONFIG_OMAP3_GPIO_4		/* GPIO96..127  is in GPIO bank 4 */
-
 /* TPS65950 */
 #define PBIASLITEVMODE1			(1 << 8)
 
diff --git a/include/configs/ti_armv7_keystone2.h b/include/configs/ti_armv7_keystone2.h
index 5e504f6..0c7d664 100644
--- a/include/configs/ti_armv7_keystone2.h
+++ b/include/configs/ti_armv7_keystone2.h
@@ -169,12 +169,16 @@
 #define CONFIG_SYS_NAND_MAX_CHIPS		1
 #define CONFIG_SYS_NAND_NO_SUBPAGE_WRITE
 
-/* USB Configuration */
-#define CONFIG_USB_XHCI_KEYSTONE
-#define CONFIG_USB_SS_BASE			KS2_USB_SS_BASE
-#define CONFIG_USB_HOST_XHCI_BASE		KS2_USB_HOST_XHCI_BASE
-#define CONFIG_DEV_USB_PHY_BASE			KS2_DEV_USB_PHY_BASE
-#define CONFIG_USB_PHY_CFG_BASE			KS2_USB_PHY_CFG_BASE
+#define DFU_ALT_INFO_MMC \
+	"dfu_alt_info_mmc=" \
+	"MLO fat 0 1;" \
+	"u-boot.img fat 0 1;" \
+	"uEnv.txt fat 0 1\0"
+
+/* DFU settings */
+#define DFUARGS \
+	"dfu_bufsiz=0x10000\0" \
+	DFU_ALT_INFO_MMC \
 
 /* U-Boot general configuration */
 #define CONFIG_MX_CYCLIC
@@ -214,6 +218,7 @@
 #define CONFIG_EXTRA_ENV_SETTINGS					\
 	DEFAULT_LINUX_BOOT_ENV						\
 	CONFIG_EXTRA_ENV_KS2_BOARD_SETTINGS				\
+	DFUARGS								\
 	"bootdir=/boot\0" \
 	"tftp_root=/\0"							\
 	"nfs_root=/export\0"						\
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index 70f8712..95d6452 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -124,6 +124,8 @@
 	"third_image=u-boot.bin\0"
 #endif
 
+#define CONFIG_PREBOOT			"env exist ${bootdev}preboot && run ${bootdev}preboot"
+
 #define CONFIG_ROOTPATH			"/nfs/root/path"
 #define CONFIG_NFSBOOTCOMMAND						\
 	"setenv bootargs $bootargs root=/dev/nfs rw "			\
@@ -169,8 +171,32 @@
 #define	CONFIG_EXTRA_ENV_SETTINGS				\
 	"netdev=eth0\0"						\
 	"initrd_high=0xffffffffffffffff\0"			\
+	"script=boot.scr\0" \
 	"scriptaddr=0x85000000\0"				\
 	"nor_base=0x42000000\0"					\
+	"emmcboot=mmcsetn && run bootcmd_mmc${mmc_first_dev}\0" \
+	"nandboot=run bootcmd_ubifs0\0" \
+	"norboot=run tftpboot\0" \
+	"usbboot=run bootcmd_usb0\0" \
+	"emmcscript=setenv devtype mmc && " \
+		"mmcsetn && " \
+		"setenv devnum ${mmc_first_dev} && " \
+		"run loadscript_fat\0" \
+	"nandscript=echo Running ${script} from ubi ... && " \
+		"ubi part UBI && " \
+		"ubifsmount ubi0:boot && " \
+		"ubifsload ${loadaddr} ${script} && " \
+		"source\0" \
+	"norscript=echo Running ${script} from tftp ... && " \
+		"tftpboot ${script} &&" \
+		"source\0" \
+	"usbscript=usb start && " \
+		"setenv devtype usb && " \
+		"setenv devnum 0 && " \
+		"run loadscript_fat\0" \
+	"loadscript_fat=echo Running ${script} from ${devtype}${devnum} ... && " \
+		"load ${devtype} ${devnum}:1 ${loadaddr} ${script} && " \
+		"source\0" \
 	"sramupdate=setexpr tmp_addr $nor_base + 0x50000 &&"	\
 		"tftpboot $tmp_addr $second_image && " \
 		"setexpr tmp_addr $nor_base + 0x70000 && " \
diff --git a/include/configs/vcoreiii.h b/include/configs/vcoreiii.h
new file mode 100644
index 0000000..df89cda
--- /dev/null
+++ b/include/configs/vcoreiii.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: (GPL-2.0+ OR MIT) */
+/*
+ * Copyright (c) 2018 Microsemi Corporation
+ */
+
+#ifndef __VCOREIII_H
+#define __VCOREIII_H
+
+#include <linux/sizes.h>
+
+/* Onboard devices */
+
+#define CONFIG_SYS_MALLOC_LEN		0x100000
+#define CONFIG_SYS_LOAD_ADDR		0x00100000
+#define CONFIG_SYS_INIT_SP_OFFSET       0x400000
+
+#define CPU_CLOCK_RATE			500000000 /* Clock for the MIPS core */
+#ifdef CONFIG_SOC_LUTON
+#define CONFIG_SYS_MIPS_TIMER_FREQ	208333333
+#else
+#define CONFIG_SYS_MIPS_TIMER_FREQ	(CPU_CLOCK_RATE / 2)
+#endif
+#define CONFIG_SYS_NS16550_CLK		CONFIG_SYS_MIPS_TIMER_FREQ
+
+#if defined(CONFIG_ENV_IS_IN_SPI_FLASH) && !defined(CONFIG_ENV_OFFSET)
+#define CONFIG_ENV_OFFSET		(1024 * 1024)
+#define CONFIG_ENV_SIZE			(256 * 1024)
+#define CONFIG_ENV_SECT_SIZE		(256 * 1024)
+
+#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#define CONFIG_ENV_SIZE_REDUND		CONFIG_ENV_SIZE
+#define CONFIG_ENV_OFFSET_REDUND      (CONFIG_ENV_OFFSET + CONFIG_ENV_SECT_SIZE)
+
+#define CONFIG_ENV_SPI_MAX_HZ		0 /* This force to read from DT */
+#define CONFIG_ENV_SPI_MODE		0 /* This force to read from DT */
+#endif
+
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+#if defined(CONFIG_DDRTYPE_H5TQ1G63BFA) || defined(CONFIG_DDRTYPE_MT47H128M8HQ)
+#define CONFIG_SYS_SDRAM_SIZE		(128 * SZ_1M)
+#elif defined(CONFIG_DDRTYPE_MT41J128M16HA) || defined(CONFIG_DDRTYPE_MT41K128M16JT)
+#define CONFIG_SYS_SDRAM_SIZE		(256 * SZ_1M)
+#elif defined(CONFIG_DDRTYPE_H5TQ4G63MFR) || defined(CONFIG_DDRTYPE_MT41K256M16)
+#define CONFIG_SYS_SDRAM_SIZE		(512 * SZ_1M)
+#else
+#error Unknown DDR size - please add!
+#endif
+
+#define CONFIG_CONS_INDEX		1
+
+#define CONFIG_SYS_MEMTEST_START	CONFIG_SYS_SDRAM_BASE
+#define CONFIG_SYS_MEMTEST_END		(CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_SDRAM_SIZE - SZ_1M)
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_BOARD_EARLY_INIT_R
+#if defined(CONFIG_MTDIDS_DEFAULT) && defined(CONFIG_MTDPARTS_DEFAULT)
+#define VCOREIII_DEFAULT_MTD_ENV		    \
+	"mtdparts="CONFIG_MTDPARTS_DEFAULT"\0"	    \
+	"mtdids="CONFIG_MTDIDS_DEFAULT"\0"
+#else
+#define VCOREIII_DEFAULT_MTD_ENV    /* Go away */
+#endif
+
+#define CONFIG_SYS_BOOTM_LEN      (16 << 20)      /* Increase max gunzip size */
+
+#define CONFIG_EXTRA_ENV_SETTINGS					\
+	VCOREIII_DEFAULT_MTD_ENV					\
+	"loadaddr=0x81000000\0"						\
+	"spi_image_off=0x00100000\0"					\
+	"console=ttyS0,115200\0"					\
+	"setup=setenv bootargs console=${console} ${mtdparts}"		\
+	"${bootargs_extra}\0"						\
+	"spiboot=run setup; sf probe; sf read ${loadaddr}"		\
+	"${spi_image_off} 0x600000; bootm ${loadaddr}\0"		\
+	"ubootfile=u-boot.bin\0"					\
+	"update=sf probe;mtdparts;dhcp ${loadaddr} ${ubootfile};"	\
+	"sf erase UBoot 0x100000;"					\
+	"sf write ${loadaddr} UBoot  ${filesize}\0"			\
+	"bootcmd=run spiboot\0"						\
+	""
+#endif				/* __VCOREIII_H */
diff --git a/include/cpu.h b/include/cpu.h
index 367c5f4..28dd48f 100644
--- a/include/cpu.h
+++ b/include/cpu.h
@@ -14,6 +14,8 @@
  * @device_id:     Driver-defined device identifier
  * @family:        DMTF CPU Family identifier
  * @id:            DMTF CPU Processor identifier
+ * @timebase_freq: the current frequency at which the cpu timer timebase
+ *		   registers are updated (in Hz)
  *
  * This can be accessed with dev_get_parent_platdata() for any UCLASS_CPU
  * device.
@@ -24,6 +26,7 @@
 	ulong device_id;
 	u16 family;
 	u32 id[2];
+	u32 timebase_freq;
 };
 
 /* CPU features - mostly just a placeholder for now */
diff --git a/include/dm/read.h b/include/dm/read.h
index efcbee1..389e30e 100644
--- a/include/dm/read.h
+++ b/include/dm/read.h
@@ -65,6 +65,38 @@
 int dev_read_u32_default(struct udevice *dev, const char *propname, int def);
 
 /**
+ * dev_read_s32() - read a signed 32-bit integer from a device's DT property
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @outp:	place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int dev_read_s32(struct udevice *dev, const char *propname, s32 *outp);
+
+/**
+ * dev_read_s32_default() - read a signed 32-bit int from a device's DT property
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @def:	default value to return if the property has no value
+ * @return property value, or @def if not found
+ */
+int dev_read_s32_default(struct udevice *dev, const char *propname, int def);
+
+/**
+ * dev_read_u32u() - read a 32-bit integer from a device's DT property
+ *
+ * This version uses a standard uint type.
+ *
+ * @dev:	device to read DT property from
+ * @propname:	name of the property to read from
+ * @outp:	place to put value (if found)
+ * @return 0 if OK, -ve on error
+ */
+int dev_read_u32u(struct udevice *dev, const char *propname, uint *outp);
+
+/**
  * dev_read_string() - Read a string from a device's DT property
  *
  * @dev:	device to read DT property from
@@ -492,6 +524,32 @@
 	return ofnode_read_u32_default(dev_ofnode(dev), propname, def);
 }
 
+static inline int dev_read_s32(struct udevice *dev,
+			       const char *propname, s32 *outp)
+{
+	return ofnode_read_s32(dev_ofnode(dev), propname, outp);
+}
+
+static inline int dev_read_s32_default(struct udevice *dev,
+				       const char *propname, int def)
+{
+	return ofnode_read_s32_default(dev_ofnode(dev), propname, def);
+}
+
+static inline int dev_read_u32u(struct udevice *dev,
+				const char *propname, uint *outp)
+{
+	u32 val;
+	int ret;
+
+	ret = ofnode_read_u32(dev_ofnode(dev), propname, &val);
+	if (ret)
+		return ret;
+	*outp = val;
+
+	return 0;
+}
+
 static inline const char *dev_read_string(struct udevice *dev,
 					  const char *propname)
 {
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index e960e48..f3bafb3 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -29,6 +29,7 @@
 	/* U-Boot uclasses start here - in alphabetical order */
 	UCLASS_ADC,		/* Analog-to-digital converter */
 	UCLASS_AHCI,		/* SATA disk controller */
+	UCLASS_AUDIO_CODEC,	/* Audio codec with control and data path */
 	UCLASS_AXI,		/* AXI bus */
 	UCLASS_BLK,		/* Block device */
 	UCLASS_BOARD,		/* Device information from hardware */
@@ -48,6 +49,7 @@
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
 	UCLASS_I2C_GENERIC,	/* Generic I2C device */
 	UCLASS_I2C_MUX,		/* I2C multiplexer */
+	UCLASS_I2S,		/* I2S bus */
 	UCLASS_IDE,		/* IDE device */
 	UCLASS_IRQ,		/* Interrupt controller */
 	UCLASS_KEYBOARD,	/* Keyboard input device */
@@ -82,6 +84,7 @@
 	UCLASS_SERIAL,		/* Serial UART */
 	UCLASS_SIMPLE_BUS,	/* Bus with child devices */
 	UCLASS_SMEM,		/* Shared memory interface */
+	UCLASS_SOUND,		/* Playing simple sounds */
 	UCLASS_SPI,		/* SPI bus */
 	UCLASS_SPI_FLASH,	/* SPI flash */
 	UCLASS_SPI_GENERIC,	/* Generic SPI flash target */
diff --git a/include/dt-bindings/clock/bcm6318-clock.h b/include/dt-bindings/clock/bcm6318-clock.h
index d5e13c5..3f10448 100644
--- a/include/dt-bindings/clock/bcm6318-clock.h
+++ b/include/dt-bindings/clock/bcm6318-clock.h
@@ -33,4 +33,15 @@
 #define BCM6318_CLK_AFE		29
 #define BCM6318_CLK_QPROC	30
 
+#define BCM6318_UCLK_ADSL	0
+#define BCM6318_UCLK_ARB	1
+#define BCM6318_UCLK_MIPS	2
+#define BCM6318_UCLK_PCIE	3
+#define BCM6318_UCLK_PERIPH	4
+#define BCM6318_UCLK_PHYMIPS	5
+#define BCM6318_UCLK_ROBOSW	6
+#define BCM6318_UCLK_SAR	7
+#define BCM6318_UCLK_SDR	8
+#define BCM6318_UCLK_USB	9
+
 #endif /* __DT_BINDINGS_CLOCK_BCM6318_H */
diff --git a/include/dt-bindings/clock/jz4780-cgu.h b/include/dt-bindings/clock/jz4780-cgu.h
new file mode 100644
index 0000000..73214c5
--- /dev/null
+++ b/include/dt-bindings/clock/jz4780-cgu.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * This header provides clock numbers for the ingenic,jz4780-cgu DT binding.
+ *
+ * They are roughly ordered as:
+ *   - external clocks
+ *   - PLLs
+ *   - muxes/dividers in the order they appear in the jz4780 programmers manual
+ *   - gates in order of their bit in the CLKGR* registers
+ */
+
+#ifndef __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+#define __DT_BINDINGS_CLOCK_JZ4780_CGU_H__
+
+#define JZ4780_CLK_EXCLK	0
+#define JZ4780_CLK_RTCLK	1
+#define JZ4780_CLK_APLL		2
+#define JZ4780_CLK_MPLL		3
+#define JZ4780_CLK_EPLL		4
+#define JZ4780_CLK_VPLL		5
+#define JZ4780_CLK_OTGPHY	6
+#define JZ4780_CLK_SCLKA	7
+#define JZ4780_CLK_CPUMUX	8
+#define JZ4780_CLK_CPU		9
+#define JZ4780_CLK_L2CACHE	10
+#define JZ4780_CLK_AHB0		11
+#define JZ4780_CLK_AHB2PMUX	12
+#define JZ4780_CLK_AHB2		13
+#define JZ4780_CLK_PCLK		14
+#define JZ4780_CLK_DDR		15
+#define JZ4780_CLK_VPU		16
+#define JZ4780_CLK_I2SPLL	17
+#define JZ4780_CLK_I2S		18
+#define JZ4780_CLK_LCD0PIXCLK	19
+#define JZ4780_CLK_LCD1PIXCLK	20
+#define JZ4780_CLK_MSCMUX	21
+#define JZ4780_CLK_MSC0		22
+#define JZ4780_CLK_MSC1		23
+#define JZ4780_CLK_MSC2		24
+#define JZ4780_CLK_UHC		25
+#define JZ4780_CLK_SSIPLL	26
+#define JZ4780_CLK_SSI		27
+#define JZ4780_CLK_CIMMCLK	28
+#define JZ4780_CLK_PCMPLL	29
+#define JZ4780_CLK_PCM		30
+#define JZ4780_CLK_GPU		31
+#define JZ4780_CLK_HDMI		32
+#define JZ4780_CLK_BCH		33
+#define JZ4780_CLK_NEMC		34
+#define JZ4780_CLK_OTG0		35
+#define JZ4780_CLK_SSI0		36
+#define JZ4780_CLK_SMB0		37
+#define JZ4780_CLK_SMB1		38
+#define JZ4780_CLK_SCC		39
+#define JZ4780_CLK_AIC		40
+#define JZ4780_CLK_TSSI0	41
+#define JZ4780_CLK_OWI		42
+#define JZ4780_CLK_KBC		43
+#define JZ4780_CLK_SADC		44
+#define JZ4780_CLK_UART0	45
+#define JZ4780_CLK_UART1	46
+#define JZ4780_CLK_UART2	47
+#define JZ4780_CLK_UART3	48
+#define JZ4780_CLK_SSI1		49
+#define JZ4780_CLK_SSI2		50
+#define JZ4780_CLK_PDMA		51
+#define JZ4780_CLK_GPS		52
+#define JZ4780_CLK_MAC		53
+#define JZ4780_CLK_SMB2		54
+#define JZ4780_CLK_CIM		55
+#define JZ4780_CLK_LCD		56
+#define JZ4780_CLK_TVE		57
+#define JZ4780_CLK_IPU		58
+#define JZ4780_CLK_DDR0		59
+#define JZ4780_CLK_DDR1		60
+#define JZ4780_CLK_SMB3		61
+#define JZ4780_CLK_TSSI1	62
+#define JZ4780_CLK_COMPRESS	63
+#define JZ4780_CLK_AIC1		64
+#define JZ4780_CLK_GPVLC	65
+#define JZ4780_CLK_OTG1		66
+#define JZ4780_CLK_UART4	67
+#define JZ4780_CLK_AHBMON	68
+#define JZ4780_CLK_SMB4		69
+#define JZ4780_CLK_DES		70
+#define JZ4780_CLK_X2D		71
+#define JZ4780_CLK_CORE1	72
+
+#endif /* __DT_BINDINGS_CLOCK_JZ4780_CGU_H__ */
diff --git a/include/dt-bindings/dma/bcm6318-dma.h b/include/dt-bindings/dma/bcm6318-dma.h
new file mode 100644
index 0000000..ad7c5ac
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6318-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6318_H
+#define __DT_BINDINGS_DMA_BCM6318_H
+
+#define BCM6318_DMA_ENETSW_RX	0
+#define BCM6318_DMA_ENETSW_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6318_H */
diff --git a/include/dt-bindings/dma/bcm63268-dma.h b/include/dt-bindings/dma/bcm63268-dma.h
new file mode 100644
index 0000000..7d02711
--- /dev/null
+++ b/include/dt-bindings/dma/bcm63268-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM63268_H
+#define __DT_BINDINGS_DMA_BCM63268_H
+
+#define BCM63268_DMA_ENETSW_RX	0
+#define BCM63268_DMA_ENETSW_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM63268_H */
diff --git a/include/dt-bindings/dma/bcm6328-dma.h b/include/dt-bindings/dma/bcm6328-dma.h
new file mode 100644
index 0000000..7494df2
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6328-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6328_H
+#define __DT_BINDINGS_DMA_BCM6328_H
+
+#define BCM6328_DMA_ENETSW_RX	0
+#define BCM6328_DMA_ENETSW_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6328_H */
diff --git a/include/dt-bindings/dma/bcm6338-dma.h b/include/dt-bindings/dma/bcm6338-dma.h
new file mode 100644
index 0000000..f2e0b20
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6338-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6338_H
+#define __DT_BINDINGS_DMA_BCM6338_H
+
+#define BCM6338_DMA_ENET_RX	0
+#define BCM6338_DMA_ENET_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6338_H */
diff --git a/include/dt-bindings/dma/bcm6348-dma.h b/include/dt-bindings/dma/bcm6348-dma.h
new file mode 100644
index 0000000..36c2ffd
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6348-dma.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6348_H
+#define __DT_BINDINGS_DMA_BCM6348_H
+
+#define BCM6348_DMA_ENET0_RX	0
+#define BCM6348_DMA_ENET0_TX	1
+#define BCM6348_DMA_ENET1_RX	2
+#define BCM6348_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6348_H */
diff --git a/include/dt-bindings/dma/bcm6358-dma.h b/include/dt-bindings/dma/bcm6358-dma.h
new file mode 100644
index 0000000..3118b9d
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6358-dma.h
@@ -0,0 +1,16 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6358_H
+#define __DT_BINDINGS_DMA_BCM6358_H
+
+#define BCM6358_DMA_ENET0_RX	0
+#define BCM6358_DMA_ENET0_TX	1
+#define BCM6358_DMA_ENET1_RX	2
+#define BCM6358_DMA_ENET1_TX	3
+
+#endif /* __DT_BINDINGS_DMA_BCM6358_H */
diff --git a/include/dt-bindings/dma/bcm6362-dma.h b/include/dt-bindings/dma/bcm6362-dma.h
new file mode 100644
index 0000000..1e62236
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6362-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6362_H
+#define __DT_BINDINGS_DMA_BCM6362_H
+
+#define BCM6362_DMA_ENETSW_RX	0
+#define BCM6362_DMA_ENETSW_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6362_H */
diff --git a/include/dt-bindings/dma/bcm6368-dma.h b/include/dt-bindings/dma/bcm6368-dma.h
new file mode 100644
index 0000000..36c6caa
--- /dev/null
+++ b/include/dt-bindings/dma/bcm6368-dma.h
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Álvaro Fernández Rojas <noltari@gmail.com>
+ *
+ * Derived from linux/drivers/net/ethernet/broadcom/bcm63xx_enet.c
+ */
+
+#ifndef __DT_BINDINGS_DMA_BCM6368_H
+#define __DT_BINDINGS_DMA_BCM6368_H
+
+#define BCM6368_DMA_ENETSW_RX	0
+#define BCM6368_DMA_ENETSW_TX	1
+
+#endif /* __DT_BINDINGS_DMA_BCM6368_H */
diff --git a/include/environment/ti/boot.h b/include/environment/ti/boot.h
index 5891009..86ff6d3 100644
--- a/include/environment/ti/boot.h
+++ b/include/environment/ti/boot.h
@@ -41,7 +41,7 @@
 	"name=crypto,size=16K,uuid=${uuid_gpt_crypto};" \
 	"name=recovery,size=40M,uuid=${uuid_gpt_recovery};" \
 	"name=boot,size=10M,uuid=${uuid_gpt_boot};" \
-	"name=system,size=768M,uuid=${uuid_gpt_system};" \
+	"name=system,size=1024M,uuid=${uuid_gpt_system};" \
 	"name=vendor,size=256M,uuid=${uuid_gpt_vendor};" \
 	"name=cache,size=256M,uuid=${uuid_gpt_cache};" \
 	"name=ipu1,size=1M,uuid=${uuid_gpt_ipu1};" \
diff --git a/include/i2s.h b/include/i2s.h
index e6d45ec..28f6184 100644
--- a/include/i2s.h
+++ b/include/i2s.h
@@ -76,7 +76,7 @@
 };
 
 /* This structure stores the i2s related information */
-struct i2stx_info {
+struct i2s_uc_priv {
 	unsigned int rfs;		/* LR clock frame size */
 	unsigned int bfs;		/* Bit slock frame size */
 	unsigned int audio_pll_clk;	/* Audio pll frequency in Hz */
@@ -87,17 +87,41 @@
 	unsigned int id;		/* I2S controller id */
 };
 
+/* Operations for i2s devices */
+struct i2s_ops {
+	/**
+	 * tx_data() - Transmit audio data
+	 *
+	 * @dev: I2C device
+	 * @data: Data buffer to play
+	 * @data_size: Size of data buffer in bytes
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*tx_data)(struct udevice *dev, void *data, uint data_size);
+};
+
+#define i2s_get_ops(dev)	((struct i2s_ops *)(dev)->driver->ops)
+
+/**
+ * i2s_tx_data() - Transmit audio data
+ *
+ * @dev: I2C device
+ * @data: Data buffer to play
+ * @data_size: Size of data buffer in bytes
+ * @return 0 if OK, -ve on error
+ */
+int i2s_tx_data(struct udevice *dev, void *data, uint data_size);
+
 /*
  * Sends the given data through i2s tx
  *
  * @param pi2s_tx	pointer of i2s transmitter parameter structure.
  * @param data		address of the data buffer
- * @param data_size	array size of the int buffer (total size / size of int)
- *
+ * @param data_size	size of the data (in bytes)
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_transfer_tx_data(struct i2stx_info *pi2s_tx, unsigned *data,
-				unsigned long data_size);
+int i2s_transfer_tx_data(struct i2s_uc_priv *pi2s_tx, void *data,
+			 uint data_size);
 
 /*
  * Initialise i2s transmiter
@@ -106,6 +130,6 @@
  *
  * @return		int value 0 for success, -1 in case of error
  */
-int i2s_tx_init(struct i2stx_info *pi2s_tx);
+int i2s_tx_init(struct i2s_uc_priv *pi2s_tx);
 
 #endif /* __I2S_H__ */
diff --git a/include/image.h b/include/image.h
index 7ce9670..765ffec 100644
--- a/include/image.h
+++ b/include/image.h
@@ -126,7 +126,8 @@
  * Operating System Codes
  *
  * The following are exposed to uImage header.
- * Do not change values for backward compatibility.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
  */
 enum {
 	IH_OS_INVALID		= 0,	/* Invalid OS	*/
@@ -164,7 +165,8 @@
  * CPU Architecture Codes (supported by Linux)
  *
  * The following are exposed to uImage header.
- * Do not change values for backward compatibility.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
  */
 enum {
 	IH_ARCH_INVALID		= 0,	/* Invalid CPU	*/
@@ -237,7 +239,8 @@
  *	as command interpreter (=> Shell Scripts).
  *
  * The following are exposed to uImage header.
- * Do not change values for backward compatibility.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
  */
 
 enum {
@@ -252,7 +255,6 @@
 	IH_TYPE_FLATDT,			/* Binary Flat Device Tree Blob	*/
 	IH_TYPE_KWBIMAGE,		/* Kirkwood Boot Image		*/
 	IH_TYPE_IMXIMAGE,		/* Freescale IMXBoot Image	*/
-	IH_TYPE_IMX8IMAGE,		/* Freescale IMX8Boot Image	*/
 	IH_TYPE_UBLIMAGE,		/* Davinci UBL Image		*/
 	IH_TYPE_OMAPIMAGE,		/* TI OMAP Config Header Image	*/
 	IH_TYPE_AISIMAGE,		/* TI Davinci AIS Image		*/
@@ -279,8 +281,9 @@
 	IH_TYPE_PMMC,            /* TI Power Management Micro-Controller Firmware */
 	IH_TYPE_STM32IMAGE,		/* STMicroelectronics STM32 Image */
 	IH_TYPE_SOCFPGAIMAGE_V1,	/* Altera SOCFPGA A10 Preloader	*/
-	IH_TYPE_IMX8MIMAGE,		/* Freescale IMX8MBoot Image	*/
 	IH_TYPE_MTKIMAGE,		/* MediaTek BootROM loadable Image */
+	IH_TYPE_IMX8MIMAGE,		/* Freescale IMX8MBoot Image	*/
+	IH_TYPE_IMX8IMAGE,		/* Freescale IMX8Boot Image	*/
 
 	IH_TYPE_COUNT,			/* Number of image types */
 };
@@ -289,7 +292,8 @@
  * Compression Types
  *
  * The following are exposed to uImage header.
- * Do not change values for backward compatibility.
+ * New IDs *MUST* be appended at the end of the list and *NEVER*
+ * inserted for backward compatibility.
  */
 enum {
 	IH_COMP_NONE		= 0,	/*  No	 Compression Used	*/
diff --git a/include/linux/bitmap.h b/include/linux/bitmap.h
new file mode 100644
index 0000000..4a54ae0
--- /dev/null
+++ b/include/linux/bitmap.h
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0+
+#ifndef __LINUX_BITMAP_H
+#define __LINUX_BITMAP_H
+
+#include <asm/types.h>
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#define small_const_nbits(nbits) \
+	(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
+
+static inline void bitmap_zero(unsigned long *dst, int nbits)
+{
+	if (small_const_nbits(nbits)) {
+		*dst = 0UL;
+	} else {
+		int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
+
+		memset(dst, 0, len);
+	}
+}
+
+#endif /* __LINUX_BITMAP_H */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index bd88483..a85c15d 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -102,6 +102,18 @@
 		(((__x) - ((__d) / 2)) / (__d));	\
 }							\
 )
+/*
+ * Same as above but for u64 dividends. divisor must be a 32-bit
+ * number.
+ */
+#define DIV_ROUND_CLOSEST_ULL(x, divisor)(		\
+{							\
+	typeof(divisor) __d = divisor;			\
+	unsigned long long _tmp = (x) + (__d) / 2;	\
+	do_div(_tmp, __d);				\
+	_tmp;						\
+}							\
+)
 
 /*
  * Multiplies an integer by a fraction, while avoiding unnecessary
diff --git a/include/linux/types.h b/include/linux/types.h
index 1f3cd63..cc6f7cb 100644
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -158,4 +158,7 @@
 	char			f_fpack[6];
 };
 
+#define DECLARE_BITMAP(name, bits) \
+	unsigned long name[BITS_TO_LONGS(bits)]
+
 #endif /* _LINUX_TYPES_H */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 30c464c..a49a66f 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -24,7 +24,7 @@
 #include <common.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
-#include <usb/lin_gadget_compat.h>
+#include <linux/bitmap.h>
 
 /*
  * USB function drivers should return USB_GADGET_DELAYED_STATUS if they
diff --git a/include/sound.h b/include/sound.h
index 77bfe6a..b7959cc 100644
--- a/include/sound.h
+++ b/include/sound.h
@@ -8,14 +8,6 @@
 #define __SOUND_H__
 
 /* sound codec enum */
-enum en_sound_codec {
-	CODEC_WM_8994,
-	CODEC_WM_8995,
-	CODEC_MAX_98095,
-	CODEC_MAX
-};
-
-/* sound codec enum */
 enum sound_compat {
 	AUDIO_COMPAT_SPI,
 	AUDIO_COMPAT_I2C,
@@ -25,33 +17,81 @@
 struct sound_codec_info {
 	int i2c_bus;
 	int i2c_dev_addr;
-	enum en_sound_codec codec_type;
 };
 
-/*
+/**
+ * struct sound_uc_priv - private uclass information about each sound device
+ *
+ * This is used to line the codec and i2s together
+ *
+ * @codec: Codec that is used for this sound device
+ * @i2s: I2S bus that is used for this sound device
+ * @setup_done: true if setup() has been called
+ */
+struct sound_uc_priv {
+	struct udevice *codec;
+	struct udevice *i2s;
+	int setup_done;
+};
+
+/**
  * Generates square wave sound data for 1 second
  *
- * @param sample_rate   Sample rate in Hz
- * @param data          data buffer pointer
- * @param size          size of the buffer
- * @param freq          frequency of the wave
+ * @sample_rate: Sample rate in Hz
+ * @data: data buffer pointer
+ * @size: size of the buffer in bytes
+ * @freq: frequency of the wave
+ * @channels: Number of channels to use
  */
 void sound_create_square_wave(uint sample_rate, unsigned short *data, int size,
-			      uint freq);
+			      uint freq, uint channels);
 
 /*
- * Initialises audio sub system
- * @param blob	Pointer of device tree node or NULL if none.
- * @return	int value 0 for success, -1 for error
+ * The sound uclass brings together a data transport (currently only I2C) and a
+ * codec (currently connected over I2C).
  */
-int sound_init(const void *blob);
 
-/*
- * plays the pcm data buffer in pcm_data.h through i2s1 to make the
- * sine wave sound
+/* Operations for sound */
+struct sound_ops {
+	/**
+	 * setup() - Set up to play a sound
+	 */
+	int (*setup)(struct udevice *dev);
+
+	/**
+	 * play() - Play a beep
+	 *
+	 * @dev: Sound device
+	 * @data: Data buffer to play
+	 * @data_size: Size of data buffer in bytes
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*play)(struct udevice *dev, void *data, uint data_size);
+};
+
+#define sound_get_ops(dev)	((struct sound_ops *)(dev)->driver->ops)
+
+/**
+ * setup() - Set up to play a sound
+ */
+int sound_setup(struct udevice *dev);
+
+/**
+ * play() - Play a beep
  *
- * @return	int 0 for success, -1 for error
+ * @dev: Sound device
+ * @msecs: Duration of beep in milliseconds
+ * @frequency_hz: Frequency of the beep in Hertz
+ * @return 0 if OK, -ve on error
  */
-int sound_play(uint32_t msec, uint32_t frequency);
+int sound_beep(struct udevice *dev, int msecs, int frequency_hz);
+
+/**
+ * sound_find_codec_i2s() - Called by sound drivers to locate codec and i2s
+ *
+ * This finds the audio codec and i2s devices and puts them in the uclass's
+ * private data for this device.
+ */
+int sound_find_codec_i2s(struct udevice *dev);
 
 #endif  /* __SOUND__H__ */
diff --git a/include/tee.h b/include/tee.h
index 98b1c9c..edd9f9b 100644
--- a/include/tee.h
+++ b/include/tee.h
@@ -34,6 +34,7 @@
  * struct tee_version_data::gen_caps
  */
 #define TEE_SUCCESS			0x00000000
+#define TEE_ERROR_STORAGE_NOT_AVAILABLE	0xf0100003
 #define TEE_ERROR_GENERIC		0xffff0000
 #define TEE_ERROR_BAD_PARAMETERS	0xffff0006
 #define TEE_ERROR_ITEM_NOT_FOUND	0xffff0008
diff --git a/include/usb/lin_gadget_compat.h b/include/usb/lin_gadget_compat.h
deleted file mode 100644
index e5dba47..0000000
--- a/include/usb/lin_gadget_compat.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright (c) 2011 Samsung Electronics
- * Lukasz Majewski <l.majewski@samsung.com>
- *
- * This is a Linux kernel compatibility layer for USB Gadget
- */
-
-#ifndef __LIN_COMPAT_H__
-#define __LIN_COMPAT_H__
-
-#include <linux/bitops.h>
-#include <linux/compat.h>
-
-/* common */
-#define DECLARE_BITMAP(name, bits) \
-	unsigned long name[BITS_TO_LONGS(bits)]
-
-#define small_const_nbits(nbits) \
-	(__builtin_constant_p(nbits) && (nbits) <= BITS_PER_LONG)
-
-static inline void bitmap_zero(unsigned long *dst, int nbits)
-{
-	if (small_const_nbits(nbits))
-		*dst = 0UL;
-	else {
-		int len = BITS_TO_LONGS(nbits) * sizeof(unsigned long);
-		memset(dst, 0, len);
-	}
-}
-
-#define dma_cache_maint(addr, size, mode) cache_flush()
-void cache_flush(void);
-
-#endif /* __LIN_COMPAT_H__ */
diff --git a/include/vxworks.h b/include/vxworks.h
index 60c0efa..1a29509 100644
--- a/include/vxworks.h
+++ b/include/vxworks.h
@@ -83,6 +83,5 @@
 int do_bootvx(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 void boot_prep_vxworks(bootm_headers_t *images);
 void boot_jump_vxworks(bootm_headers_t *images);
-void do_bootvx_fdt(bootm_headers_t *images);
 
 #endif
diff --git a/lib/crc32.c b/lib/crc32.c
index 71e27df..eee21f8 100644
--- a/lib/crc32.c
+++ b/lib/crc32.c
@@ -65,7 +65,8 @@
   int n, k;
   uLong poly;		/* polynomial exclusive-or pattern */
   /* terms of polynomial defining this crc (except x^32): */
-  static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26};
+  static Byte __efi_runtime_data p[] = {
+		0, 1, 2, 4, 5, 7, 8, 10, 11, 12, 16, 22, 23, 26};
 
   /* make exclusive-or pattern from polynomial (0xedb88320L) */
   poly = 0L;
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 95844ef..fff93f0 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -436,14 +436,42 @@
 			uint32_t descriptor_version,
 			struct efi_mem_desc *virtmap)
 {
-	ulong runtime_start = (ulong)&__efi_runtime_start &
-			      ~(ulong)EFI_PAGE_MASK;
 	int n = memory_map_size / descriptor_size;
 	int i;
+	int rt_code_sections = 0;
 
 	EFI_ENTRY("%lx %lx %x %p", memory_map_size, descriptor_size,
 		  descriptor_version, virtmap);
 
+	/*
+	 * TODO:
+	 * Further down we are cheating. While really we should implement
+	 * SetVirtualAddressMap() events and ConvertPointer() to allow
+	 * dynamically loaded drivers to expose runtime services, we don't
+	 * today.
+	 *
+	 * So let's ensure we see exactly one single runtime section, as
+	 * that is the built-in one. If we see more (or less), someone must
+	 * have tried adding or removing to that which we don't support yet.
+	 * In that case, let's better fail rather than expose broken runtime
+	 * services.
+	 */
+	for (i = 0; i < n; i++) {
+		struct efi_mem_desc *map = (void*)virtmap +
+					   (descriptor_size * i);
+
+		if (map->type == EFI_RUNTIME_SERVICES_CODE)
+			rt_code_sections++;
+	}
+
+	if (rt_code_sections != 1) {
+		/*
+		 * We expose exactly one single runtime code section, so
+		 * something is definitely going wrong.
+		 */
+		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	}
+
 	/* Rebind mmio pointers */
 	for (i = 0; i < n; i++) {
 		struct efi_mem_desc *map = (void*)virtmap +
@@ -483,7 +511,7 @@
 		map = (void*)virtmap + (descriptor_size * i);
 		if (map->type == EFI_RUNTIME_SERVICES_CODE) {
 			ulong new_offset = map->virtual_start -
-					   (runtime_start - gd->relocaddr);
+					   map->physical_start + gd->relocaddr;
 
 			efi_runtime_relocate(new_offset, map);
 			/* Once we're virtual, we can no longer handle
diff --git a/lib/efi_selftest/efi_selftest_block_device.c b/lib/efi_selftest/efi_selftest_block_device.c
index d4e4fac..f038da9 100644
--- a/lib/efi_selftest/efi_selftest_block_device.c
+++ b/lib/efi_selftest/efi_selftest_block_device.c
@@ -445,11 +445,6 @@
 		efi_st_error("Failed to write file\n");
 		return EFI_ST_FAILURE;
 	}
-	ret = file->close(file);
-	if (ret != EFI_SUCCESS) {
-		efi_st_error("Failed to close file\n");
-		return EFI_ST_FAILURE;
-	}
 	ret = file->getpos(file, &pos);
 	if (ret != EFI_SUCCESS) {
 		efi_st_error("GetPosition failed\n");
@@ -460,6 +455,11 @@
 			     (unsigned int)pos);
 		return EFI_ST_FAILURE;
 	}
+	ret = file->close(file);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Failed to close file\n");
+		return EFI_ST_FAILURE;
+	}
 
 	/* Verify file */
 	boottime->set_mem(buf, sizeof(buf), 0);
diff --git a/lib/hashtable.c b/lib/hashtable.c
index 1c48692..93028ed 100644
--- a/lib/hashtable.c
+++ b/lib/hashtable.c
@@ -662,7 +662,7 @@
 			return (-1);
 		}
 	} else {
-		size = totlen;
+		size = totlen + 1;
 	}
 
 	/* Check if the user provided a buffer */
diff --git a/scripts/check-config.sh b/scripts/check-config.sh
index 4848ca6..583f7d0 100755
--- a/scripts/check-config.sh
+++ b/scripts/check-config.sh
@@ -17,6 +17,15 @@
 set -e
 set -u
 
+PROG_NAME="${0##*/}"
+
+usage() {
+	echo "$PROG_NAME <path to u-boot.cfg> <path to whitelist file> <source dir>"
+	exit 1
+}
+
+[ $# -ge 3 ] || usage
+
 path="$1"
 whitelist="$2"
 srctree="$3"
diff --git a/test/dm/Makefile b/test/dm/Makefile
index 2c9081e..7dc80be 100644
--- a/test/dm/Makefile
+++ b/test/dm/Makefile
@@ -2,7 +2,6 @@
 #
 # Copyright (c) 2013 Google, Inc
 
-obj-$(CONFIG_CMD_DM) += cmd_dm.o
 obj-$(CONFIG_UT_DM) += bus.o
 obj-$(CONFIG_UT_DM) += test-driver.o
 obj-$(CONFIG_UT_DM) += test-fdt.o
@@ -13,6 +12,7 @@
 # subsystem you must add sandbox tests here.
 obj-$(CONFIG_UT_DM) += core.o
 ifneq ($(CONFIG_SANDBOX),)
+obj-$(CONFIG_SOUND) += audio.o
 obj-$(CONFIG_BLK) += blk.o
 obj-$(CONFIG_BOARD) += board.o
 obj-$(CONFIG_CLK) += clk.o
@@ -21,6 +21,7 @@
 obj-$(CONFIG_DM_GPIO) += gpio.o
 obj-$(CONFIG_DM_HWSPINLOCK) += hwspinlock.o
 obj-$(CONFIG_DM_I2C) += i2c.o
+obj-$(CONFIG_SOUND) += i2s.o
 obj-$(CONFIG_LED) += led.o
 obj-$(CONFIG_DM_MAILBOX) += mailbox.o
 obj-$(CONFIG_DM_MMC) += mmc.o
@@ -53,6 +54,7 @@
 obj-$(CONFIG_MISC) += misc.o
 obj-$(CONFIG_DM_SERIAL) += serial.o
 obj-$(CONFIG_CPU) += cpu.o
+obj-$(CONFIG_SOUND) += sound.o
 obj-$(CONFIG_TEE) += tee.o
 obj-$(CONFIG_VIRTIO_SANDBOX) += virtio.o
 obj-$(CONFIG_DMA) += dma.o
diff --git a/test/dm/audio.c b/test/dm/audio.c
new file mode 100644
index 0000000..77c3a36
--- /dev/null
+++ b/test/dm/audio.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <audio_codec.h>
+#include <dm.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the audio codec uclass */
+static int dm_test_audio(struct unit_test_state *uts)
+{
+	int interface, rate, mclk_freq, bits_per_sample;
+	struct udevice *dev;
+	uint channels;
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_AUDIO_CODEC, &dev));
+	ut_assertok(audio_codec_set_params(dev, 1, 2, 3, 4, 5));
+	sandbox_get_codec_params(dev, &interface, &rate, &mclk_freq,
+				 &bits_per_sample, &channels);
+	ut_asserteq(1, interface);
+	ut_asserteq(2, rate);
+	ut_asserteq(3, mclk_freq);
+	ut_asserteq(4, bits_per_sample);
+	ut_asserteq(5, channels);
+
+	return 0;
+}
+DM_TEST(dm_test_audio, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/i2s.c b/test/dm/i2s.c
new file mode 100644
index 0000000..49ebc35
--- /dev/null
+++ b/test/dm/i2s.c
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <i2s.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the i2s codec uclass */
+static int dm_test_i2s(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u8 data[3];
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_I2S, &dev));
+	data[0] = 1;
+	data[1] = 4;
+	data[2] = 6;
+	ut_assertok(i2s_tx_data(dev, data, ARRAY_SIZE(data)));
+	ut_asserteq(11, sandbox_get_i2s_sum(dev));
+	ut_assertok(i2s_tx_data(dev, data, 1));
+	ut_asserteq(12, sandbox_get_i2s_sum(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_i2s, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/sound.c b/test/dm/sound.c
new file mode 100644
index 0000000..7d0b36e
--- /dev/null
+++ b/test/dm/sound.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sound.h>
+#include <dm/test.h>
+#include <test/ut.h>
+#include <asm/test.h>
+
+/* Basic test of the sound codec uclass */
+static int dm_test_sound(struct unit_test_state *uts)
+{
+	struct sound_uc_priv *uc_priv;
+	struct udevice *dev;
+
+	/* check probe success */
+	ut_assertok(uclass_first_device_err(UCLASS_SOUND, &dev));
+	uc_priv = dev_get_uclass_priv(dev);
+	ut_asserteq_str("audio-codec", uc_priv->codec->name);
+	ut_asserteq_str("i2s", uc_priv->i2s->name);
+	ut_asserteq(0, sandbox_get_setup_called(dev));
+
+	ut_assertok(sound_beep(dev, 1, 100));
+	ut_asserteq(4560, sandbox_get_sound_sum(dev));
+	ut_assertok(sound_beep(dev, 1, 100));
+	ut_asserteq(9120, sandbox_get_sound_sum(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_sound, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index 96d2528..984b80c 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -736,3 +736,38 @@
 	return 0;
 }
 DM_TEST(dm_test_first_child, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test integer functions in dm_read_...() */
+static int dm_test_read_int(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	u32 val32;
+	s32 sval;
+	uint val;
+
+	ut_assertok(uclass_first_device_err(UCLASS_TEST_FDT, &dev));
+	ut_asserteq_str("a-test", dev->name);
+	ut_assertok(dev_read_u32(dev, "int-value", &val32));
+	ut_asserteq(1234, val32);
+
+	ut_asserteq(-EINVAL, dev_read_u32(dev, "missing", &val32));
+	ut_asserteq(6, dev_read_u32_default(dev, "missing", 6));
+
+	ut_asserteq(1234, dev_read_u32_default(dev, "int-value", 6));
+	ut_asserteq(1234, val32);
+
+	ut_asserteq(-EINVAL, dev_read_s32(dev, "missing", &sval));
+	ut_asserteq(6, dev_read_s32_default(dev, "missing", 6));
+
+	ut_asserteq(-1234, dev_read_s32_default(dev, "uint-value", 6));
+	ut_assertok(dev_read_s32(dev, "uint-value", &sval));
+	ut_asserteq(-1234, sval);
+
+	val = 0;
+	ut_asserteq(-EINVAL, dev_read_u32u(dev, "missing", &val));
+	ut_assertok(dev_read_u32u(dev, "uint-value", &val));
+	ut_asserteq(-1234, val);
+
+	return 0;
+}
+DM_TEST(dm_test_read_int, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/overlay/Kconfig b/test/overlay/Kconfig
index 13c8542..a4f1544 100644
--- a/test/overlay/Kconfig
+++ b/test/overlay/Kconfig
@@ -1,11 +1,10 @@
 config UT_OVERLAY
 	bool "Enable Device Tree Overlays Unit Tests"
-	depends on OF_LIBFDT_OVERLAY
-	depends on UNIT_TEST
+	depends on UNIT_TEST && OF_CONTROL
+	default y
+	select OF_LIBFDT_OVERLAY
 	help
 	  This enables the 'ut overlay' command which runs a series of unit
 	  tests on the fdt overlay code.
 	  If all is well then all tests pass although there will be a few
 	  messages printed along the way.
-	  Be warned that it requires an out-of-tree dtc compiler with patches
-	  to support the DT overlays, otherwise it will fail.
diff --git a/tools/Makefile b/tools/Makefile
index 9a72480..081383d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -127,7 +127,7 @@
 fit_check_sign-objs   := $(dumpimage-mkimage-objs) fit_check_sign.o
 file2include-objs := file2include.o
 
-ifneq ($(CONFIG_MX23)$(CONFIG_MX28),)
+ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),)
 # Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
 # the mxsimage support within tools/mxsimage.c .
 HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS
diff --git a/tools/mtk_image.c b/tools/mtk_image.c
index 2706d2d..2ca5194 100644
--- a/tools/mtk_image.c
+++ b/tools/mtk_image.c
@@ -322,7 +322,7 @@
 				lk = val;
 
 			if (!strcmp(key, "lkname"))
-				strncpy(lk_name, val, sizeof(lk_name));
+				snprintf(lk_name, sizeof(lk_name), "%s", val);
 		}
 
 		if (next)
@@ -656,7 +656,7 @@
 		bootname = SDMMC_BOOT_NAME;
 
 	/* Generic device header */
-	strncpy(hdr->boot.name, bootname, sizeof(hdr->boot.name));
+	snprintf(hdr->boot.name, sizeof(hdr->boot.name), "%s", bootname);
 	hdr->boot.version = cpu_to_le32(1);
 	hdr->boot.size = cpu_to_le32(sizeof(hdr->boot));