Merge branch 'master' of git://git.denx.de/u-boot
diff --git a/README b/README
index d881da2..6f4c09a 100644
--- a/README
+++ b/README
@@ -1003,6 +1003,7 @@
 		CONFIG_CMD_ECHO		  echo arguments
 		CONFIG_CMD_EDITENV	  edit env variable
 		CONFIG_CMD_EEPROM	* EEPROM read/write support
+		CONFIG_CMD_EEPROM_LAYOUT* EEPROM layout aware commands
 		CONFIG_CMD_ELF		* bootelf, bootvx
 		CONFIG_CMD_ENV_CALLBACK	* display details about env callbacks
 		CONFIG_CMD_ENV_FLAGS	* display details about env flags
@@ -1066,7 +1067,7 @@
 		CONFIG_CMD_RUN		  run command in env variable
 		CONFIG_CMD_SANDBOX	* sb command to access sandbox features
 		CONFIG_CMD_SAVES	* save S record dump
-		CONFIG_CMD_SCSI		* SCSI Support
+		CONFIG_SCSI		* SCSI Support
 		CONFIG_CMD_SDRAM	* print SDRAM configuration information
 					  (requires CONFIG_CMD_I2C)
 		CONFIG_CMD_SETGETDCR	  Support for DCR Register access
@@ -1254,7 +1255,7 @@
 		CONFIG_MTD_PARTITIONS  Memory Technology Device partition table.
 
 		If IDE or SCSI support is enabled (CONFIG_CMD_IDE or
-		CONFIG_CMD_SCSI) you must configure support for at
+		CONFIG_SCSI) you must configure support for at
 		least one non-MTD partition type as well.
 
 - IDE Reset method:
diff --git a/api/api.c b/api/api.c
index 457dc36..8a1433a 100644
--- a/api/api.c
+++ b/api/api.c
@@ -52,7 +52,7 @@
 {
 	int *c;
 
-	if ((c = (int *)va_arg(ap, u_int32_t)) == NULL)
+	if ((c = (int *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*c = getc();
@@ -68,7 +68,7 @@
 {
 	int *t;
 
-	if ((t = (int *)va_arg(ap, u_int32_t)) == NULL)
+	if ((t = (int *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*t = tstc();
@@ -84,7 +84,7 @@
 {
 	char *c;
 
-	if ((c = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((c = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	putc(*c);
@@ -100,7 +100,7 @@
 {
 	char *s;
 
-	if ((s = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((s = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	puts(s);
@@ -132,7 +132,7 @@
 {
 	struct sys_info *si;
 
-	si = (struct sys_info *)va_arg(ap, u_int32_t);
+	si = (struct sys_info *)va_arg(ap, uintptr_t);
 	if (si == NULL)
 		return API_ENOMEM;
 
@@ -148,7 +148,7 @@
 {
 	unsigned long *d;
 
-	if ((d = (unsigned long *)va_arg(ap, u_int32_t)) == NULL)
+	if ((d = (unsigned long *)va_arg(ap, unsigned long)) == NULL)
 		return API_EINVAL;
 
 	udelay(*d);
@@ -164,11 +164,11 @@
 {
 	unsigned long *base, *cur;
 
-	cur = (unsigned long *)va_arg(ap, u_int32_t);
+	cur = (unsigned long *)va_arg(ap, unsigned long);
 	if (cur == NULL)
 		return API_EINVAL;
 
-	base = (unsigned long *)va_arg(ap, u_int32_t);
+	base = (unsigned long *)va_arg(ap, unsigned long);
 	if (base == NULL)
 		return API_EINVAL;
 
@@ -199,7 +199,7 @@
 	struct device_info *di;
 
 	/* arg is ptr to the device_info struct we are going to fill out */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -233,7 +233,7 @@
 	int err = 0;
 
 	/* arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -265,7 +265,7 @@
 	int err = 0;
 
 	/* arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -319,7 +319,7 @@
 	int err = 0;
 
 	/* 1. arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -329,12 +329,12 @@
 		return API_ENODEV;
 
 	/* 2. arg is ptr to buffer from where to get data to write */
-	buf = (void *)va_arg(ap, u_int32_t);
+	buf = (void *)va_arg(ap, uintptr_t);
 	if (buf == NULL)
 		return API_EINVAL;
 
 	/* 3. arg is length of buffer */
-	len = (int *)va_arg(ap, u_int32_t);
+	len = (int *)va_arg(ap, uintptr_t);
 	if (len == NULL)
 		return API_EINVAL;
 	if (*len <= 0)
@@ -387,7 +387,7 @@
 	int *len_net, *act_len_net;
 
 	/* 1. arg is ptr to the device_info struct */
-	di = (struct device_info *)va_arg(ap, u_int32_t);
+	di = (struct device_info *)va_arg(ap, uintptr_t);
 	if (di == NULL)
 		return API_EINVAL;
 
@@ -397,23 +397,23 @@
 		return API_ENODEV;
 
 	/* 2. arg is ptr to buffer from where to put the read data */
-	buf = (void *)va_arg(ap, u_int32_t);
+	buf = (void *)va_arg(ap, uintptr_t);
 	if (buf == NULL)
 		return API_EINVAL;
 
 	if (di->type & DEV_TYP_STOR) {
 		/* 3. arg - ptr to var with # of blocks to read */
-		len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+		len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
 		if (!len_stor)
 			return API_EINVAL;
 		if (*len_stor <= 0)
 			return API_EINVAL;
 
 		/* 4. arg - ptr to var with start block */
-		start = (lbastart_t *)va_arg(ap, u_int32_t);
+		start = (lbastart_t *)va_arg(ap, uintptr_t);
 
 		/* 5. arg - ptr to var where to put the len actually read */
-		act_len_stor = (lbasize_t *)va_arg(ap, u_int32_t);
+		act_len_stor = (lbasize_t *)va_arg(ap, uintptr_t);
 		if (!act_len_stor)
 			return API_EINVAL;
 
@@ -422,14 +422,14 @@
 	} else if (di->type & DEV_TYP_NET) {
 
 		/* 3. arg points to the var with length of packet to read */
-		len_net = (int *)va_arg(ap, u_int32_t);
+		len_net = (int *)va_arg(ap, uintptr_t);
 		if (!len_net)
 			return API_EINVAL;
 		if (*len_net <= 0)
 			return API_EINVAL;
 
 		/* 4. - ptr to var where to put the len actually read */
-		act_len_net = (int *)va_arg(ap, u_int32_t);
+		act_len_net = (int *)va_arg(ap, uintptr_t);
 		if (!act_len_net)
 			return API_EINVAL;
 
@@ -453,9 +453,9 @@
 {
 	char *name, **value;
 
-	if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
-	if ((value = (char **)va_arg(ap, u_int32_t)) == NULL)
+	if ((value = (char **)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	*value = getenv(name);
@@ -476,9 +476,9 @@
 {
 	char *name, *value;
 
-	if ((name = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((name = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
-	if ((value = (char *)va_arg(ap, u_int32_t)) == NULL)
+	if ((value = (char *)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	setenv(name, value);
@@ -498,9 +498,9 @@
 	int i, n;
 	char *last, **next;
 
-	last = (char *)va_arg(ap, u_int32_t);
+	last = (char *)va_arg(ap, unsigned long);
 
-	if ((next = (char **)va_arg(ap, u_int32_t)) == NULL)
+	if ((next = (char **)va_arg(ap, uintptr_t)) == NULL)
 		return API_EINVAL;
 
 	if (last == NULL)
@@ -662,14 +662,14 @@
 	}
 
 	setenv_hex("api_address", (unsigned long)sig);
-	debugf("API sig @ 0x%08x\n", sig);
+	debugf("API sig @ 0x%lX\n", (unsigned long)sig);
 	memcpy(sig->magic, API_SIG_MAGIC, 8);
 	sig->version = API_SIG_VERSION;
 	sig->syscall = &syscall;
 	sig->checksum = 0;
 	sig->checksum = crc32(0, (unsigned char *)sig,
 			      sizeof(struct api_signature));
-	debugf("syscall entry: 0x%08x\n", sig->syscall);
+	debugf("syscall entry: 0x%lX\n", (unsigned long)sig->syscall);
 }
 
 void platform_set_mr(struct sys_info *si, unsigned long start, unsigned long size,
diff --git a/api/api_storage.c b/api/api_storage.c
index 8c30c56..d425a9a 100644
--- a/api/api_storage.c
+++ b/api/api_storage.c
@@ -67,7 +67,7 @@
 	specs[ENUM_SATA].type = DEV_TYP_STOR | DT_STOR_SATA;
 	specs[ENUM_SATA].name = "sata";
 #endif
-#if defined(CONFIG_CMD_SCSI)
+#if defined(CONFIG_SCSI)
 	specs[ENUM_SCSI].max_dev = CONFIG_SYS_SCSI_MAX_DEVICE;
 	specs[ENUM_SCSI].enum_started = 0;
 	specs[ENUM_SCSI].enum_ended = 0;
diff --git a/arch/arm/cpu/armv8/start.S b/arch/arm/cpu/armv8/start.S
index c3cc819..e933021 100644
--- a/arch/arm/cpu/armv8/start.S
+++ b/arch/arm/cpu/armv8/start.S
@@ -216,7 +216,7 @@
 #endif
 #endif
 
-#ifndef CONFIG_ARMV8_MULTIENTRY
+#ifdef CONFIG_ARMV8_MULTIENTRY
 	branch_if_master x0, x1, 2f
 
 	/*
diff --git a/arch/arm/dts/exynos4210-universal_c210.dts b/arch/arm/dts/exynos4210-universal_c210.dts
index 16948c9..ad3527e 100644
--- a/arch/arm/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/dts/exynos4210-universal_c210.dts
@@ -42,11 +42,11 @@
 	};
 
 	soft-spi {
-		compatible = "u-boot,soft-spi";
-		cs-gpio = <&gpy4 3 0>;
-		sclk-gpio = <&gpy3 1 0>;
-		mosi-gpio = <&gpy3 3 0>;
-		miso-gpio = <&gpy3 0 0>;
+		compatible = "spi-gpio";
+		cs-gpios = <&gpy4 3 0>;
+		gpio-sck = <&gpy3 1 0>;
+		gpio-mosi = <&gpy3 3 0>;
+		gpio-miso = <&gpy3 0 0>;
 		spi-delay-us = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/arm/dts/tegra20-seaboard.dts b/arch/arm/dts/tegra20-seaboard.dts
index eada590..5893d2a 100644
--- a/arch/arm/dts/tegra20-seaboard.dts
+++ b/arch/arm/dts/tegra20-seaboard.dts
@@ -40,10 +40,6 @@
 				nvidia,panel = <&lcd_panel>;
 			};
 		};
-
-		dc@54240000 {
-			status = "disabled";
-		};
 	};
 
 	/* This is not used in U-Boot, but is expected to be in kernel .dts */
diff --git a/arch/arm/include/asm/arch-ls102xa/config.h b/arch/arm/include/asm/arch-ls102xa/config.h
index 267bd17..d77c04a 100644
--- a/arch/arm/include/asm/arch-ls102xa/config.h
+++ b/arch/arm/include/asm/arch-ls102xa/config.h
@@ -82,7 +82,7 @@
 /* SATA */
 #define AHCI_BASE_ADDR				(CONFIG_SYS_IMMR + 0x02200000)
 #define CONFIG_BOARD_LATE_INIT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
diff --git a/arch/m68k/cpu/mcf5227x/start.S b/arch/m68k/cpu/mcf5227x/start.S
index 23024f9..13c036f 100644
--- a/arch/m68k/cpu/mcf5227x/start.S
+++ b/arch/m68k/cpu/mcf5227x/start.S
@@ -372,14 +372,29 @@
 	move.l %d0, (%a1)
 	move.l %d0, (%a2)
 
-	/* set stackpointer to end of internal ram to get some stackspace for
-	   the first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5	/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	bsr	board_init_f_alloc_reserve
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	bsr     board_init_f_init_reserve
 
 	bsr cpu_init_f			/* run low-level CPU init code (from flash) */
+	clr.l   %sp@-
 	bsr board_init_f		/* run low-level board init code (from flash) */
 
 	/* board_init_f() does not return */
diff --git a/arch/m68k/cpu/mcf523x/start.S b/arch/m68k/cpu/mcf523x/start.S
index 1702f98..3aa4dd6 100644
--- a/arch/m68k/cpu/mcf523x/start.S
+++ b/arch/m68k/cpu/mcf523x/start.S
@@ -134,17 +134,34 @@
 	move.l %d0, (%a1)
 	move.l %d0, (%a2)
 
-	/* set stackpointer to end of internal ram to get some stackspace for the
-	   first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5	/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	move.l	#board_init_f_alloc_reserve, %a1
+	jsr	(%a1)
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	move.l	#board_init_f_init_reserve, %a1
+	jsr	(%a1)
 
 	/* run low-level CPU init code (from flash) */
 	move.l #cpu_init_f, %a1
 	jsr (%a1)
 	/* run low-level board init code (from flash) */
+	clr.l   %sp@-
 	move.l #board_init_f, %a1
 	jsr (%a1)
 
diff --git a/arch/m68k/cpu/mcf52x2/start.S b/arch/m68k/cpu/mcf52x2/start.S
index 4af691f..a048884 100644
--- a/arch/m68k/cpu/mcf52x2/start.S
+++ b/arch/m68k/cpu/mcf52x2/start.S
@@ -192,16 +192,34 @@
 	move.l %d0, (%a1)
 	move.l %d0, (%a2)
 
-	/* set stackpointer to end of internal ram to get some stackspace for the first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5		/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	move.l	#board_init_f_alloc_reserve, %a1
+	jsr (%a1)
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	move.l	#board_init_f_init_reserve, %a1
+	jsr (%a1)
 
 	/* run low-level CPU init code (from flash) */
 	move.l #cpu_init_f, %a1
 	jsr (%a1)
 	/* run low-level board init code (from flash) */
+	clr.l   %sp@-
 	move.l #board_init_f, %a1
 	jsr (%a1)
 
diff --git a/arch/m68k/cpu/mcf530x/cpu_init.c b/arch/m68k/cpu/mcf530x/cpu_init.c
index 80dc239..b09eed8 100644
--- a/arch/m68k/cpu/mcf530x/cpu_init.c
+++ b/arch/m68k/cpu/mcf530x/cpu_init.c
@@ -142,7 +142,7 @@
 	return 0;
 }
 
-void uart_port_conf(void)
+void uart_port_conf(int port)
 {
 }
 
diff --git a/arch/m68k/cpu/mcf530x/start.S b/arch/m68k/cpu/mcf530x/start.S
index 097958a..ca8bb32 100644
--- a/arch/m68k/cpu/mcf530x/start.S
+++ b/arch/m68k/cpu/mcf530x/start.S
@@ -126,21 +126,32 @@
 	move.l	%d0, (%a1)
 	move.l	%d0, (%a2)
 
-	/*
-	 * set stackpointer to internal sram end - 80
-	 * (global data struct size + some bytes)
-	 * get some stackspace for the first c-code,
-	 */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l   %sp@-
-
 	/* put relocation table address to a5 */
 	move.l #__got_start, %a5
 
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	bsr	board_init_f_alloc_reserve
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	bsr     board_init_f_init_reserve
+
 	/* run low-level CPU init code (from flash) */
 	bsr cpu_init_f
 
 	/* run low-level board init code (from flash) */
+	clr.l   %sp@-
 	bsr board_init_f
 
 	/* board_init_f() does not return */
diff --git a/arch/m68k/cpu/mcf532x/start.S b/arch/m68k/cpu/mcf532x/start.S
index 131ad6e..f25bc54 100644
--- a/arch/m68k/cpu/mcf532x/start.S
+++ b/arch/m68k/cpu/mcf532x/start.S
@@ -148,17 +148,34 @@
 	move.l %d0, (%a1)
 	move.l %d0, (%a2)
 
-	/* set stackpointer to end of internal ram to get some stackspace for the
-	   first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5	/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	move.l	#board_init_f_alloc_reserve, %a1
+	jsr	(%a1)
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	move.l	#board_init_f_init_reserve, %a1
+	jsr	(%a1)
 
 	/* run low-level CPU init code (from flash) */
 	move.l #cpu_init_f, %a1
 	jsr (%a1)
 	/* run low-level board init code (from flash) */
+	clr.l   %sp@-
 	move.l #board_init_f, %a1
 	jsr (%a1)
 
diff --git a/arch/m68k/cpu/mcf5445x/start.S b/arch/m68k/cpu/mcf5445x/start.S
index f50f147..ba38678 100644
--- a/arch/m68k/cpu/mcf5445x/start.S
+++ b/arch/m68k/cpu/mcf5445x/start.S
@@ -657,17 +657,34 @@
 	movec	%d0, %RAMBAR1
 #endif
 
-	/* set stackpointer to end of internal ram to get some stackspace for
-	   the first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5	/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	move.l	#board_init_f_alloc_reserve, %a1
+	jsr	(%a1)
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	move.l	#board_init_f_init_reserve, %a1
+	jsr	(%a1)
 
 	/* run low-level CPU init code (from flash) */
 	move.l #cpu_init_f, %a1
 	jsr (%a1)
 	/* run low-level board init code (from flash) */
+	clr.l   %sp@-
 	move.l #board_init_f, %a1
 	jsr (%a1)
 
diff --git a/arch/m68k/cpu/mcf547x_8x/start.S b/arch/m68k/cpu/mcf547x_8x/start.S
index 75de22d..9a87a0d 100644
--- a/arch/m68k/cpu/mcf547x_8x/start.S
+++ b/arch/m68k/cpu/mcf547x_8x/start.S
@@ -141,14 +141,29 @@
 	move.l %d0, (%a1)
 	move.l %d0, (%a2)
 
-	/* set stackpointer to end of internal ram to get some stackspace for the
-	   first c-code */
-	move.l	#(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_SP_OFFSET), %sp
-	clr.l %sp@-
+	/* put relocation table address to a5 */
+	move.l #__got_start, %a5
 
-	move.l #__got_start, %a5	/* put relocation table address to a5 */
+	/* setup stack initially on top of internal static ram  */
+	move.l  #(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE), %sp
+
+	/*
+	 * if configured, malloc_f arena will be reserved first,
+	 * then (and always) gd struct space will be reserved
+	 */
+	move.l	%sp, -(%sp)
+	bsr	board_init_f_alloc_reserve
+
+	/* update stack and frame-pointers */
+	move.l  %d0, %sp
+	move.l  %sp, %fp
+
+	/* initialize reserved area */
+	move.l  %d0, -(%sp)
+	bsr     board_init_f_init_reserve
 
 	jbsr cpu_init_f			/* run low-level CPU init code (from flash) */
+	clr.l   %sp@-
 	jbsr board_init_f		/* run low-level board init code (from flash) */
 
 	/* board_init_f() does not return */
diff --git a/arch/m68k/include/asm/config.h b/arch/m68k/include/asm/config.h
index e1458ac..9c4d3fb 100644
--- a/arch/m68k/include/asm/config.h
+++ b/arch/m68k/include/asm/config.h
@@ -7,8 +7,6 @@
 #ifndef _ASM_CONFIG_H_
 #define _ASM_CONFIG_H_
 
-#define CONFIG_SYS_GENERIC_GLOBAL_DATA
-
 #define CONFIG_NEEDS_MANUAL_RELOC
 
 #define CONFIG_LMB
diff --git a/arch/m68k/include/asm/fsl_i2c.h b/arch/m68k/include/asm/fsl_i2c.h
index 1b1c25e..c7d2aa3 100644
--- a/arch/m68k/include/asm/fsl_i2c.h
+++ b/arch/m68k/include/asm/fsl_i2c.h
@@ -16,7 +16,7 @@
 
 #include <asm/types.h>
 
-typedef struct fsl_i2c {
+typedef struct fsl_i2c_base {
 
 	u8 adr;		/* I2C slave address */
 	u8 res0[3];
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index fe37d1f..dc34c18 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -5,8 +5,8 @@
 	default "mips"
 
 config SYS_CPU
-	default "mips32" if CPU_MIPS32_R1 || CPU_MIPS32_R2
-	default "mips64" if CPU_MIPS64_R1 || CPU_MIPS64_R2
+	default "mips32" if CPU_MIPS32
+	default "mips64" if CPU_MIPS64
 
 choice
 	prompt "Target select"
@@ -28,6 +28,7 @@
 	select SUPPORTS_LITTLE_ENDIAN
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
+	select SUPPORTS_CPU_MIPS32_R6
 	select SWAP_IO_SPACE
 	select MIPS_L1_CACHE_SHIFT_6
 
@@ -55,6 +56,11 @@
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
 	select MIPS_TUNE_4KC
 
+config ARCH_ATH79
+	bool "Support QCA/Atheros ath79"
+	select OF_CONTROL
+	select DM
+
 config MACH_PIC32
 	bool "Support Microchip PIC32"
 	select OF_CONTROL
@@ -67,6 +73,7 @@
 source "board/micronas/vct/Kconfig"
 source "board/pb1x00/Kconfig"
 source "board/qemu-mips/Kconfig"
+source "arch/mips/mach-ath79/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
 
 if MIPS
@@ -98,7 +105,7 @@
 	depends on SUPPORTS_CPU_MIPS32_R1
 	select 32BIT
 	help
-	  Choose this option to build an U-Boot for release 1 or later of the
+	  Choose this option to build an U-Boot for release 1 through 5 of the
 	  MIPS32 architecture.
 
 config CPU_MIPS32_R2
@@ -106,7 +113,15 @@
 	depends on SUPPORTS_CPU_MIPS32_R2
 	select 32BIT
 	help
-	  Choose this option to build an U-Boot for release 2 or later of the
+	  Choose this option to build an U-Boot for release 2 through 5 of the
+	  MIPS32 architecture.
+
+config CPU_MIPS32_R6
+	bool "MIPS32 Release 6"
+	depends on SUPPORTS_CPU_MIPS32_R6
+	select 32BIT
+	help
+	  Choose this option to build an U-Boot for release 6 or later of the
 	  MIPS32 architecture.
 
 config CPU_MIPS64_R1
@@ -114,7 +129,7 @@
 	depends on SUPPORTS_CPU_MIPS64_R1
 	select 64BIT
 	help
-	  Choose this option to build a kernel for release 1 or later of the
+	  Choose this option to build a kernel for release 1 through 5 of the
 	  MIPS64 architecture.
 
 config CPU_MIPS64_R2
@@ -122,7 +137,15 @@
 	depends on SUPPORTS_CPU_MIPS64_R2
 	select 64BIT
 	help
-	  Choose this option to build a kernel for release 2 or later of the
+	  Choose this option to build a kernel for release 2 through 5 of the
+	  MIPS64 architecture.
+
+config CPU_MIPS64_R6
+	bool "MIPS64 Release 6"
+	depends on SUPPORTS_CPU_MIPS64_R6
+	select 64BIT
+	help
+	  Choose this option to build a kernel for release 6 or later of the
 	  MIPS64 architecture.
 
 endchoice
@@ -169,19 +192,25 @@
 config SUPPORTS_CPU_MIPS32_R2
 	bool
 
+config SUPPORTS_CPU_MIPS32_R6
+	bool
+
 config SUPPORTS_CPU_MIPS64_R1
 	bool
 
 config SUPPORTS_CPU_MIPS64_R2
 	bool
 
+config SUPPORTS_CPU_MIPS64_R6
+	bool
+
 config CPU_MIPS32
 	bool
-	default y if CPU_MIPS32_R1 || CPU_MIPS32_R2
+	default y if CPU_MIPS32_R1 || CPU_MIPS32_R2 || CPU_MIPS32_R6
 
 config CPU_MIPS64
 	bool
-	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2
+	default y if CPU_MIPS64_R1 || CPU_MIPS64_R2 || CPU_MIPS64_R6
 
 config MIPS_TUNE_4KC
 	bool
@@ -192,6 +221,9 @@
 config MIPS_TUNE_24KC
 	bool
 
+config MIPS_TUNE_74KC
+	bool
+
 config 32BIT
 	bool
 
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index aec5a15..655a493 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -8,6 +8,7 @@
 libs-y += arch/mips/lib/
 
 machine-$(CONFIG_SOC_AU1X00) += au1x00
+machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_MACH_PIC32) += pic32
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
@@ -18,13 +19,16 @@
 # Optimize for MIPS architectures
 arch-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,-mips32
 arch-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,-mips32r2
+arch-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,-mips32r6
 arch-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,-mips64
 arch-$(CONFIG_CPU_MIPS64_R2) += -march=mips64r2 -Wa,-mips64r2
+arch-$(CONFIG_CPU_MIPS64_R6) += -march=mips64r6 -Wa,-mips64r6
 
 # Allow extra optimization for specific CPUs/SoCs
 tune-$(CONFIG_MIPS_TUNE_4KC) += -mtune=4kc
 tune-$(CONFIG_MIPS_TUNE_14KC) += -mtune=14kc
 tune-$(CONFIG_MIPS_TUNE_24KC) += -mtune=24kc
+tune-$(CONFIG_MIPS_TUNE_74KC) += -mtune=74kc
 
 # Include default header files
 cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
diff --git a/arch/mips/cpu/cpu.c b/arch/mips/cpu/cpu.c
index 8d3b2f5..391feb3 100644
--- a/arch/mips/cpu/cpu.c
+++ b/arch/mips/cpu/cpu.c
@@ -7,7 +7,6 @@
 
 #include <common.h>
 #include <command.h>
-#include <netdev.h>
 #include <linux/compiler.h>
 #include <asm/mipsregs.h>
 #include <asm/reboot.h>
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index 1b56ca3..fc6dd66 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -164,12 +164,14 @@
 	li	t0, -16
 	PTR_LI	t1, CONFIG_SYS_INIT_SP_ADDR
 	and	sp, t1, t0		# force 16 byte alignment
-	PTR_SUB	sp, sp, GD_SIZE		# reserve space for gd
+	PTR_SUBU \
+		sp, sp, GD_SIZE		# reserve space for gd
 	and	sp, sp, t0		# force 16 byte alignment
 	move	k0, sp			# save gd pointer
 #ifdef CONFIG_SYS_MALLOC_F_LEN
 	li	t2, CONFIG_SYS_MALLOC_F_LEN
-	PTR_SUB	sp, sp, t2		# reserve space for early malloc
+	PTR_SUBU \
+		sp, sp, t2		# reserve space for early malloc
 	and	sp, sp, t0		# force 16 byte alignment
 #endif
 	move	fp, sp
@@ -179,7 +181,7 @@
 1:
 	PTR_S	zero, 0(t0)
 	blt	t0, t1, 1b
-	 PTR_ADDI t0, PTRSIZE
+	 PTR_ADDIU t0, PTRSIZE
 
 #ifdef CONFIG_SYS_MALLOC_F_LEN
 	PTR_S	sp, GD_MALLOC_BASE(k0)	# gd->malloc_base offset
@@ -237,7 +239,7 @@
 	 move	a0, s2			# a0 <-- destination address
 
 	/* Jump to where we've relocated ourselves */
-	PTR_ADDI t0, s2, in_ram - _start
+	PTR_ADDIU t0, s2, in_ram - _start
 	jr	t0
 	 nop
 
@@ -257,7 +259,7 @@
 	PTR_L	t3, -(1 * PTRSIZE)(t0)	# t3 <-- num_got_entries
 	PTR_L	t8, -(2 * PTRSIZE)(t0)	# t8 <-- _GLOBAL_OFFSET_TABLE_
 	PTR_ADD	t8, s1			# t8 now holds relocated _G_O_T_
-	PTR_ADDI t8, t8, 2 * PTRSIZE	# skipping first two entries
+	PTR_ADDIU t8, t8, 2 * PTRSIZE	# skipping first two entries
 	PTR_LI	t2, 2
 1:
 	PTR_L	t1, 0(t8)
@@ -265,16 +267,16 @@
 	 PTR_ADD t1, s1
 	PTR_S	t1, 0(t8)
 2:
-	PTR_ADDI t2, 1
+	PTR_ADDIU t2, 1
 	blt	t2, t3, 1b
-	 PTR_ADDI t8, PTRSIZE
+	 PTR_ADDIU t8, PTRSIZE
 
 	/* Update dynamic relocations */
 	PTR_L	t1, -(4 * PTRSIZE)(t0)	# t1 <-- __rel_dyn_start
 	PTR_L	t2, -(5 * PTRSIZE)(t0)	# t2 <-- __rel_dyn_end
 
 	b	2f			# skip first reserved entry
-	 PTR_ADDI t1, 2 * PTRSIZE
+	 PTR_ADDIU t1, 2 * PTRSIZE
 
 1:
 	lw	t8, -4(t1)		# t8 <-- relocation info
@@ -293,7 +295,7 @@
 
 2:
 	blt	t1, t2, 1b
-	 PTR_ADDI t1, 2 * PTRSIZE	# each rel.dyn entry is 2*PTRSIZE bytes
+	 PTR_ADDIU t1, 2 * PTRSIZE	# each rel.dyn entry is 2*PTRSIZE bytes
 
 	/*
 	 * Clear BSS
@@ -307,7 +309,7 @@
 1:
 	PTR_S	zero, 0(t1)
 	blt	t1, t2, 1b
-	 PTR_ADDI t1, PTRSIZE
+	 PTR_ADDIU t1, PTRSIZE
 
 	move	a0, s0			# a0 <-- gd
 	move	a1, s2
diff --git a/arch/mips/dts/Makefile b/arch/mips/dts/Makefile
index b513918..a94b745 100644
--- a/arch/mips/dts/Makefile
+++ b/arch/mips/dts/Makefile
@@ -2,7 +2,10 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+dtb-$(CONFIG_TARGET_AP121) += ap121.dtb
+dtb-$(CONFIG_TARGET_AP143) += ap143.dtb
 dtb-$(CONFIG_TARGET_PIC32MZDASK) += pic32mzda_sk.dtb
+dtb-$(CONFIG_BOARD_TPLINK_WDR4300) += tplink_wdr4300.dtb
 
 targets += $(dtb-y)
 
diff --git a/arch/mips/dts/ap121.dts b/arch/mips/dts/ap121.dts
new file mode 100644
index 0000000..e31f601
--- /dev/null
+++ b/arch/mips/dts/ap121.dts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ar933x.dtsi"
+
+/ {
+	model = "AP121 Reference Board";
+	compatible = "qca,ap121", "qca,ar933x";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&xtal {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x9f000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/ap143.dts b/arch/mips/dts/ap143.dts
new file mode 100644
index 0000000..f53207e
--- /dev/null
+++ b/arch/mips/dts/ap143.dts
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "qca953x.dtsi"
+
+/ {
+	model = "AP143 Reference Board";
+	compatible = "qca,ap143", "qca,qca953x";
+
+	aliases {
+		spi0 = &spi0;
+		serial0 = &uart0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&xtal {
+	clock-frequency = <25000000>;
+};
+
+&uart0 {
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x9f000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/ar933x.dtsi b/arch/mips/dts/ar933x.dtsi
new file mode 100644
index 0000000..00896b2
--- /dev/null
+++ b/arch/mips/dts/ar933x.dtsi
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,ar933x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips24Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	pinctrl {
+		u-boot,dm-pre-reloc;
+		compatible = "qca,ar933x-pinctrl";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x18040000 0x100>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ehci0: ehci@1b000100 {
+				compatible = "generic-ehci";
+				reg = <0x1b000100 0x100>;
+
+				status = "disabled";
+			};
+
+			uart0: uart@18020000 {
+				compatible = "qca,ar9330-uart";
+				reg = <0x18020000 0x20>;
+				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
+
+				status = "disabled";
+			};
+
+			gmac0: eth@0x19000000 {
+				compatible = "qca,ag7240-mac";
+				reg = <0x19000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+
+			gmac1: eth@0x1a000000 {
+				compatible = "qca,ag7240-mac";
+				reg = <0x1a000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/ar934x.dtsi b/arch/mips/dts/ar934x.dtsi
new file mode 100644
index 0000000..7a036a8
--- /dev/null
+++ b/arch/mips/dts/ar934x.dtsi
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,ar934x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips74Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ehci0: ehci@1b000100 {
+				compatible = "generic-ehci";
+				reg = <0x1b000100 0x100>;
+
+				status = "disabled";
+			};
+
+			uart0: uart@18020000 {
+				compatible = "ns16550";
+				reg = <0x18020000 0x20>;
+				reg-shift = <2>;
+
+				status = "disabled";
+			};
+
+			gmac0: eth@0x19000000 {
+				compatible = "qca,ag934x-mac";
+				reg = <0x19000000 0x200>;
+				phy = <&phy0>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy0: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+
+			gmac1: eth@0x1a000000 {
+				compatible = "qca,ag934x-mac";
+				reg = <0x1a000000 0x200>;
+				phy = <&phy1>;
+				phy-mode = "rgmii";
+
+				status = "disabled";
+
+				mdio {
+					#address-cells = <1>;
+					#size-cells = <0>;
+					phy1: ethernet-phy@0 {
+						reg = <0>;
+					};
+				};
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/qca953x.dtsi b/arch/mips/dts/qca953x.dtsi
new file mode 100644
index 0000000..870010f
--- /dev/null
+++ b/arch/mips/dts/qca953x.dtsi
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "skeleton.dtsi"
+
+/ {
+	compatible = "qca,qca953x";
+
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			device_type = "cpu";
+			compatible = "mips,mips24Kc";
+			reg = <0>;
+		};
+	};
+
+	clocks {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		xtal: xtal {
+			#clock-cells = <0>;
+			compatible = "fixed-clock";
+			clock-output-names = "xtal";
+		};
+	};
+
+	pinctrl {
+		u-boot,dm-pre-reloc;
+		compatible = "qca,qca953x-pinctrl";
+		ranges;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		reg = <0x18040000 0x100>;
+	};
+
+	ahb {
+		compatible = "simple-bus";
+		ranges;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		apb {
+			compatible = "simple-bus";
+			ranges;
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			uart0: uart@18020000 {
+				compatible = "ns16550";
+				reg = <0x18020000 0x20>;
+				reg-shift = <2>;
+				clock-frequency = <25000000>;
+				interrupts = <128 IRQ_TYPE_LEVEL_HIGH>;
+
+				status = "disabled";
+			};
+		};
+
+		spi0: spi@1f000000 {
+			compatible = "qca,ar7100-spi";
+			reg = <0x1f000000 0x10>;
+			interrupts = <129 IRQ_TYPE_LEVEL_HIGH>;
+
+			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+};
diff --git a/arch/mips/dts/tplink_wdr4300.dts b/arch/mips/dts/tplink_wdr4300.dts
new file mode 100644
index 0000000..cfda4df
--- /dev/null
+++ b/arch/mips/dts/tplink_wdr4300.dts
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+/dts-v1/;
+#include "ar934x.dtsi"
+
+/ {
+	model = "TP-Link WDR4300 Board";
+	compatible = "tplink,wdr4300", "qca,ar934x";
+
+	aliases {
+		serial0 = &uart0;
+		spi0 = &spi0;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&gmac0 {
+	phy-mode = "rgmii";
+	status = "okay";
+};
+
+&spi0 {
+	spi-max-frequency = <25000000>;
+	status = "okay";
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash";
+		memory-map = <0x1e000000 0x00800000>;
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
+
+&uart0 {
+	clock-frequency = <40000000>;
+	status = "okay";
+};
+
+&xtal {
+	clock-frequency = <40000000>;
+};
diff --git a/arch/mips/include/asm/global_data.h b/arch/mips/include/asm/global_data.h
index a1ca257..3f230b0 100644
--- a/arch/mips/include/asm/global_data.h
+++ b/arch/mips/include/asm/global_data.h
@@ -23,6 +23,12 @@
 	unsigned long tbl;
 	unsigned long lastinc;
 #endif
+#ifdef CONFIG_ARCH_ATH79
+	unsigned long id;
+	unsigned long soc;
+	unsigned long rev;
+	unsigned long ver;
+#endif
 };
 
 #include <asm-generic/global_data.h>
diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S
index 14cc2c4..08b7c3a 100644
--- a/arch/mips/lib/cache_init.S
+++ b/arch/mips/lib/cache_init.S
@@ -64,7 +64,7 @@
 	/* detect associativity */
 	srl	\sz, $1, \off + MIPS_CONF1_DA_SHF - MIPS_CONF1_DA_SHF
 	andi	\sz, \sz, (MIPS_CONF1_DA >> MIPS_CONF1_DA_SHF)
-	addi	\sz, \sz, 1
+	addiu	\sz, \sz, 1
 
 	/* sz *= line_sz */
 	mul	\sz, \sz, \line_sz
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig
new file mode 100644
index 0000000..7d483aa
--- /dev/null
+++ b/arch/mips/mach-ath79/Kconfig
@@ -0,0 +1,55 @@
+menu "QCA/Atheros 7xxx/9xxx platforms"
+	depends on ARCH_ATH79
+
+config SYS_SOC
+	default "ath79"
+
+config SOC_AR933X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_24KC
+	help
+	  This supports QCA/Atheros ar933x family SOCs.
+
+config SOC_AR934X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_74KC
+	help
+	  This supports QCA/Atheros ar934x family SOCs.
+
+config SOC_QCA953X
+	bool
+	select SUPPORTS_BIG_ENDIAN
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select MIPS_TUNE_24KC
+	help
+	  This supports QCA/Atheros qca953x family SOCs.
+
+choice
+	prompt "Board select"
+
+config TARGET_AP121
+	bool "AP121 Reference Board"
+	select SOC_AR933X
+
+config TARGET_AP143
+	bool "AP143 Reference Board"
+	select SOC_QCA953X
+
+config BOARD_TPLINK_WDR4300
+	bool "TP-Link WDR4300 Board"
+	select SOC_AR934X
+
+endchoice
+
+source "board/qca/ap121/Kconfig"
+source "board/qca/ap143/Kconfig"
+source "board/tplink/wdr4300/Kconfig"
+
+endmenu
diff --git a/arch/mips/mach-ath79/Makefile b/arch/mips/mach-ath79/Makefile
new file mode 100644
index 0000000..d7e2666
--- /dev/null
+++ b/arch/mips/mach-ath79/Makefile
@@ -0,0 +1,11 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += reset.o
+obj-y += cpu.o
+obj-y += dram.o
+
+obj-$(CONFIG_SOC_AR933X)	+= ar933x/
+obj-$(CONFIG_SOC_AR934X)	+= ar934x/
+obj-$(CONFIG_SOC_QCA953X)	+= qca953x/
diff --git a/arch/mips/mach-ath79/ar933x/Makefile b/arch/mips/mach-ath79/ar933x/Makefile
new file mode 100644
index 0000000..fd74f0c
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += clk.o
+obj-y += ddr.o
+obj-y += lowlevel_init.o
diff --git a/arch/mips/mach-ath79/ar933x/clk.c b/arch/mips/mach-ath79/ar933x/clk.c
new file mode 100644
index 0000000..9fcd496
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/clk.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 ar933x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return ar933x_get_xtal();
+}
+
+int get_clocks(void)
+{
+	void __iomem *regs;
+	u32 val, xtal, pll, div;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+	xtal = ar933x_get_xtal();
+	val = readl(regs + AR933X_PLL_CPU_CONFIG_REG);
+
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> AR933X_PLL_CPU_CONFIG_NINT_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
+			& AR933X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	val = readl(regs + AR933X_PLL_CLK_CTRL_REG);
+
+	/* CPU_CLK = PLLOUT / CPU_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
+	gd->cpu_clk = pll / div;
+
+	/* DDR_CLK = PLLOUT / DDR_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
+	gd->mem_clk = pll / div;
+
+	/* AHB_CLK = PLLOUT / AHB_POST_DIV */
+	div = ((val >> AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
+			& AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
+	gd->bus_clk = pll / div;
+
+	return 0;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	if (!gd->bus_clk)
+		get_clocks();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	if (!gd->mem_clk)
+		get_clocks();
+	return gd->mem_clk;
+}
diff --git a/arch/mips/mach-ath79/ar933x/ddr.c b/arch/mips/mach-ath79/ar933x/ddr.c
new file mode 100644
index 0000000..91452bc
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/ddr.c
@@ -0,0 +1,333 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDR_CTRL_UPD_EMR3S      BIT(5)
+#define DDR_CTRL_UPD_EMR2S      BIT(4)
+#define DDR_CTRL_PRECHARGE      BIT(3)
+#define DDR_CTRL_AUTO_REFRESH   BIT(2)
+#define DDR_CTRL_UPD_EMRS       BIT(1)
+#define DDR_CTRL_UPD_MRS        BIT(0)
+
+#define DDR_REFRESH_EN          BIT(14)
+#define DDR_REFRESH_M           0x3ff
+#define DDR_REFRESH(x)          ((x) & 0x3ff)
+#define DDR_REFRESH_VAL_25M     (DDR_REFRESH_EN | DDR_REFRESH(390))
+#define DDR_REFRESH_VAL_40M     (DDR_REFRESH_EN | DDR_REFRESH(624))
+
+#define DDR_TRAS_S              0
+#define DDR_TRAS_M              0x1f
+#define DDR_TRAS(x)             ((x) << DDR_TRAS_S)
+#define DDR_TRCD_M              0xf
+#define DDR_TRCD_S              5
+#define DDR_TRCD(x)             ((x) << DDR_TRCD_S)
+#define DDR_TRP_M               0xf
+#define DDR_TRP_S               9
+#define DDR_TRP(x)              ((x) << DDR_TRP_S)
+#define DDR_TRRD_M              0xf
+#define DDR_TRRD_S              13
+#define DDR_TRRD(x)             ((x) << DDR_TRRD_S)
+#define DDR_TRFC_M              0x7f
+#define DDR_TRFC_S              17
+#define DDR_TRFC(x)             ((x) << DDR_TRFC_S)
+#define DDR_TMRD_M              0xf
+#define DDR_TMRD_S              23
+#define DDR_TMRD(x)             ((x) << DDR_TMRD_S)
+#define DDR_CAS_L_M             0x17
+#define DDR_CAS_L_S             27
+#define DDR_CAS_L(x)            (((x) & DDR_CAS_L_M) << DDR_CAS_L_S)
+#define DDR_OPEN                BIT(30)
+#define DDR_CONF_REG_VAL        (DDR_TRAS(16) | DDR_TRCD(6) | \
+				 DDR_TRP(6) | DDR_TRRD(4) | \
+				 DDR_TRFC(30) | DDR_TMRD(15) | \
+				 DDR_CAS_L(7) | DDR_OPEN)
+
+#define DDR_BURST_LEN_S         0
+#define DDR_BURST_LEN_M         0xf
+#define DDR_BURST_LEN(x)        ((x) << DDR_BURST_LEN_S)
+#define DDR_BURST_TYPE          BIT(4)
+#define DDR_CNTL_OE_EN          BIT(5)
+#define DDR_PHASE_SEL           BIT(6)
+#define DDR_CKE                 BIT(7)
+#define DDR_TWR_S               8
+#define DDR_TWR_M               0xf
+#define DDR_TWR(x)              ((x) << DDR_TWR_S)
+#define DDR_TRTW_S              12
+#define DDR_TRTW_M              0x1f
+#define DDR_TRTW(x)             ((x) << DDR_TRTW_S)
+#define DDR_TRTP_S              17
+#define DDR_TRTP_M              0xf
+#define DDR_TRTP(x)             ((x) << DDR_TRTP_S)
+#define DDR_TWTR_S              21
+#define DDR_TWTR_M              0x1f
+#define DDR_TWTR(x)             ((x) << DDR_TWTR_S)
+#define DDR_G_OPEN_L_S          26
+#define DDR_G_OPEN_L_M          0xf
+#define DDR_G_OPEN_L(x)         ((x) << DDR_G_OPEN_L_S)
+#define DDR_HALF_WIDTH_LOW      BIT(31)
+#define DDR_CONF2_REG_VAL       (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(6) | DDR_TRTW(14) | \
+				 DDR_TRTP(8) | DDR_TWTR(14) | \
+				 DDR_G_OPEN_L(7) | DDR_HALF_WIDTH_LOW)
+
+#define DDR2_CONF_TWL_S         10
+#define DDR2_CONF_TWL_M         0xf
+#define DDR2_CONF_TWL(x)        (((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S)
+#define DDR2_CONF_ODT           BIT(9)
+#define DDR2_CONF_TFAW_S        2
+#define DDR2_CONF_TFAW_M        0x3f
+#define DDR2_CONF_TFAW(x)       (((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S)
+#define DDR2_CONF_EN            BIT(0)
+#define DDR2_CONF_VAL           (DDR2_CONF_TWL(2) | DDR2_CONF_ODT | \
+				 DDR2_CONF_TFAW(22) | DDR2_CONF_EN)
+
+#define DDR1_EXT_MODE_VAL       0x02
+#define DDR2_EXT_MODE_VAL       0x402
+#define DDR2_EXT_MODE_OCD_VAL   0x382
+#define DDR1_MODE_DLL_VAL       0x133
+#define DDR2_MODE_DLL_VAL       0x100
+#define DDR1_MODE_VAL           0x33
+#define DDR2_MODE_VAL           0xa33
+#define DDR_TAP_VAL0            0x08
+#define DDR_TAP_VAL1            0x09
+
+void ddr_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	writel(DDR_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+	writel(DDR_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+
+	val = get_bootstrap();
+	if (val & AR933X_BOOTSTRAP_DDR2) {
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX);
+
+		/* Enable DDR2 */
+		writel(DDR2_CONF_VAL, regs + AR933X_DDR_REG_DDR2_CONFIG);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Disable High Temperature Self-Refresh, Full Array */
+		writel(0x00, regs + AR933X_DDR_REG_EMR2);
+
+		/* Extended Mode Register 2 Set (EMR2S) */
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+
+		writel(0x00, regs + AR933X_DDR_REG_EMR3);
+
+		/* Extended Mode Register 3 Set (EMR3S) */
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable DLL,  Full strength, ODT Disabled */
+		writel(0x00, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Reset DLL */
+		writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Write recovery (WR) 6 clock, CAS Latency 3, Burst Length 8 */
+		writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable OCD defaults, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* OCD exit, Enable DLL, Enable /DQS, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Refresh time control */
+		if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+			writel(DDR_REFRESH_VAL_40M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+		else
+			writel(DDR_REFRESH_VAL_25M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+
+		/* DQS 0 Tap Control */
+		writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* For 16-bit DDR */
+		writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE);
+	} else {
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + AR933X_DDR_REG_TIMEOUT_MAX);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Reset DLL, Burst Length 8, CAS Latency 3 */
+		writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Forces an MRS update cycle in DDR */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Enable DLL, Full strength */
+		writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+
+		/* Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Normal DLL, Burst Length 8, CAS Latency 3 */
+		writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+
+		/* Refresh time control */
+		if (val & AR933X_BOOTSTRAP_REF_CLK_40)
+			writel(DDR_REFRESH_VAL_40M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+		else
+			writel(DDR_REFRESH_VAL_25M, regs +
+			       AR71XX_DDR_REG_REFRESH);
+
+		/* DQS 0 Tap Control */
+		writel(DDR_TAP_VAL0, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR_TAP_VAL1, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* For 16-bit DDR */
+		writel(0xff, regs + AR71XX_DDR_REG_RD_CYCLE);
+	}
+}
+
+void ddr_tap_tuning(void)
+{
+	void __iomem *regs;
+	u32 *addr_k0, *addr_k1, *addr;
+	u32 val, tap, upper, lower;
+	int i, j, dir, err, done;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	/* Init memory pattern */
+	addr = (void *)CKSEG0ADDR(0x2000);
+	for (i = 0; i < 256; i++) {
+		val = 0;
+		for (j = 0; j < 8; j++) {
+			if (i & (1 << j)) {
+				if (j % 2)
+					val |= 0xffff0000;
+				else
+					val |= 0x0000ffff;
+			}
+
+			if (j % 2) {
+				*addr++ = val;
+				val = 0;
+			}
+		}
+	}
+
+	err = 0;
+	done = 0;
+	dir = 1;
+	tap = readl(regs + AR71XX_DDR_REG_TAP_CTRL0);
+	val = tap;
+	while (!done) {
+		err = 0;
+
+		/* Update new DDR tap value */
+		writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+		writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		/* Compare DDR with cache */
+		for (i = 0; i < 2; i++) {
+			addr_k1 = (void *)CKSEG1ADDR(0x2000);
+			addr_k0 = (void *)CKSEG0ADDR(0x2000);
+			addr = (void *)CKSEG0ADDR(0x3000);
+
+			while (addr_k0 < addr) {
+				if (*addr_k1++ != *addr_k0++) {
+					err = 1;
+					break;
+				}
+			}
+
+			if (err)
+				break;
+		}
+
+		if (err) {
+			/* Save upper/lower threshold if error  */
+			if (dir) {
+				dir = 0;
+				val--;
+				upper = val;
+				val = tap;
+			} else {
+				val++;
+				lower = val;
+				done = 1;
+			}
+		} else {
+			/* Try the next value until limitation */
+			if (dir) {
+				if (val < 0x20) {
+					val++;
+				} else {
+					dir = 0;
+					upper = val;
+					val = tap;
+				}
+			} else {
+				if (!val) {
+					lower = val;
+					done = 1;
+				} else {
+					val--;
+				}
+			}
+		}
+	}
+
+	/* compute an intermediate value and write back */
+	val = (upper + lower) / 2;
+	writel(val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+	val++;
+	writel(val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+}
diff --git a/arch/mips/mach-ath79/ar933x/lowlevel_init.S b/arch/mips/mach-ath79/ar933x/lowlevel_init.S
new file mode 100644
index 0000000..1b847f5
--- /dev/null
+++ b/arch/mips/mach-ath79/ar933x/lowlevel_init.S
@@ -0,0 +1,280 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK and u-boot_mod project
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <mach/ar71xx_regs.h>
+
+#define SET_BIT(val, bit)   ((val) | (1 << (bit)))
+#define SET_PLL_PD(val)     SET_BIT(val, 30)
+#define AHB_DIV_TO_4(val)   SET_BIT(SET_BIT(val, 15), 16)
+#define PLL_BYPASS(val)     SET_BIT(val, 2)
+
+#define MK_PLL_CONF(divint, refdiv, range, outdiv) \
+     (((0x3F & divint) << 10) | \
+     ((0x1F & refdiv) << 16) | \
+     ((0x1 & range)   << 21) | \
+     ((0x7 & outdiv)  << 23) )
+
+#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \
+    (((0x3 & (cpudiv - 1)) << 5)  | \
+    ((0x3 & (ddrdiv - 1)) << 10) | \
+    ((0x3 & (ahbdiv - 1)) << 15) )
+
+/*
+ * PLL_CPU_CONFIG_VAL
+ *
+ * Bit30 is set (CPU_PLLPWD = 1 -> power down control for CPU PLL)
+ * After PLL configuration we need to clear this bit
+ *
+ * Values written into CPU PLL Configuration (CPU_PLL_CONFIG)
+ *
+ * bits 10..15  (6bit)  DIV_INT (Integer part of the DIV to CPU PLL)
+ *                      =>  32  (0x20)  VCOOUT = XTAL * DIV_INT
+ * bits 16..20  (5bit)  REFDIV  (Reference clock divider)
+ *                      =>  1   (0x1)   [Must start at values 1]
+ * bits 21      (1bit)  RANGE   (VCO frequency range of the CPU PLL)
+ *                      =>  0   (0x0)   [Doesn't impact clock values]
+ * bits 23..25  (3bit)  OUTDIV  (Ratio between VCO and PLL output)
+ *                      =>  1   (0x1)   [0 is illegal!]
+ *                              PLLOUT = VCOOUT * (1/2^OUTDIV)
+ */
+/* DIV_INT=32 (25MHz*32/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */
+#define PLL_CPU_CONFIG_VAL_40M  MK_PLL_CONF(20, 1, 0, 1)
+/* DIV_INT=20 (40MHz*20/2=400MHz), REFDIV=1, RANGE=0, OUTDIV=1 */
+#define PLL_CPU_CONFIG_VAL_25M  MK_PLL_CONF(32, 1, 0, 1)
+
+/*
+ * PLL_CLK_CONTROL_VAL
+ *
+ * In PLL_CLK_CONTROL_VAL bit 2 is set (BYPASS = 1 -> bypass PLL)
+ * After PLL configuration we need to clear this bit
+ *
+ * Values written into CPU Clock Control Register CLOCK_CONTROL
+ *
+ * bits 2       (1bit)  BYPASS (Bypass PLL. This defaults to 1 for test.
+ *                      Software must enable the CPU PLL for normal and
+ *                      then set this bit to 0)
+ * bits 5..6    (2bit)  CPU_POST_DIV    =>  0   (DEFAULT, Ratio = 1)
+ *                      CPU_CLK = PLLOUT / CPU_POST_DIV
+ * bits 10..11  (2bit)  DDR_POST_DIV    =>  0   (DEFAULT, Ratio = 1)
+ *                      DDR_CLK = PLLOUT / DDR_POST_DIV
+ * bits 15..16  (2bit)  AHB_POST_DIV    =>  1   (DEFAULT, Ratio = 2)
+ *                      AHB_CLK = PLLOUT / AHB_POST_DIV
+ *
+ */
+#define PLL_CLK_CONTROL_VAL MK_CLK_CNTL(1, 1, 2)
+
+    .text
+    .set noreorder
+
+LEAF(lowlevel_init)
+	/* These three WLAN_RESET will avoid original issue */
+	li      t3, 0x03
+1:
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	ori     t1, t1, 0x0800
+	sw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	nop
+	lw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0xfffff7ff
+	and     t1, t1, t2
+	sw      t1, AR933X_RESET_REG_RESET_MODULE(t0)
+	nop
+	addi    t3, t3, -1
+	bnez    t3, 1b
+	nop
+
+	li      t2, 0x20
+2:
+	beqz    t2, 1b
+	nop
+	addi    t2, t2, -1
+	lw      t5, AR933X_RESET_REG_BOOTSTRAP(t0)
+	andi    t1, t5, 0x10
+	bnez    t1, 2b
+	nop
+
+	li      t1, 0x02110E
+	sw      t1, AR933X_RESET_REG_BOOTSTRAP(t0)
+	nop
+
+	/* RTC Force Wake */
+	li      t0, CKSEG1ADDR(AR933X_RTC_BASE)
+	li      t1, 0x03
+	sw      t1, AR933X_RTC_REG_FORCE_WAKE(t0)
+	nop
+	nop
+
+	/* RTC Reset */
+	li      t1, 0x00
+	sw      t1, AR933X_RTC_REG_RESET(t0)
+	nop
+	nop
+
+	li      t1, 0x01
+	sw      t1, AR933X_RTC_REG_RESET(t0)
+	nop
+	nop
+
+	/* Wait for RTC in on state */
+1:
+	lw      t1, AR933X_RTC_REG_STATUS(t0)
+	andi    t1, t1, 0x02
+	beqz    t1, 1b
+	nop
+
+	/* Program ki/kd */
+	li      t0, CKSEG1ADDR(AR933X_SRIF_BASE)
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, 0x19e82f01
+	b       2f
+	nop
+1:
+	li      t1, 0x18e82f01
+2:
+	sw      t1, AR933X_SRIF_DDR_DPLL2_REG(t0)
+
+	/* Program phase shift */
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0xc07fffff
+	and     t1, t1, t2
+	li      t2, 0x800000
+	or      t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	/* in some cases, the SoC doesn't start with higher clock on AHB */
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	li      t1, AHB_DIV_TO_4(PLL_BYPASS(PLL_CLK_CONTROL_VAL))
+	sw      t1, AR933X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	/* Set SETTLE_TIME in CPU PLL */
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, 0x0352
+	b       2f
+	nop
+1:
+	li      t1, 0x0550
+2:
+	sw      t1, AR71XX_PLL_REG_SEC_CONFIG(t0)
+	nop
+
+	/* Set nint, frac, refdiv, outdiv, range according to xtal */
+0:
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_25M)
+	b       2f
+	nop
+1:
+	li      t1, SET_PLL_PD(PLL_CPU_CONFIG_VAL_40M)
+2:
+	sw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	nop
+1:
+	lw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, 0x80000000
+	and     t1, t1, t2
+	bnez    t1, 1b
+	nop
+
+	/* Put frac bit19:10 configuration */
+	li      t1, 0x1003E8
+	sw      t1, AR933X_PLL_DITHER_FRAC_REG(t0)
+	nop
+
+	/* Clear PLL power down bit in CPU PLL configuration */
+	andi    t1, t5, 0x01            # t5 BOOT_STRAP
+	bnez    t1, 1f
+	nop
+	li      t1, PLL_CPU_CONFIG_VAL_25M
+	b       2f
+	nop
+1:
+	li      t1, PLL_CPU_CONFIG_VAL_40M
+2:
+	sw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	/* Wait for PLL update -> bit 31 in CPU_PLL_CONFIG should be 0 */
+1:
+	lw      t1, AR933X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, 0x80000000
+	and     t1, t1, t2
+	bnez    t1, 1b
+	nop
+
+	/* Confirm DDR PLL lock */
+	li      t3, 100
+	li      t4, 0
+
+2:
+	addi    t4, t4, 1
+	bgt     t4, t3, 0b
+	nop
+
+	li      t3, 5
+3:
+	/* Clear do_meas */
+	li      t0, CKSEG1ADDR(AR933X_SRIF_BASE)
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0xBFFFFFFF
+	and     t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	li      t2, 10
+1:
+	subu    t2, t2, 1
+	bnez    t2, 1b
+	nop
+
+	/* Set do_meas */
+	li      t2, 0x40000000
+	or      t1, t1, t2
+	sw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	nop
+
+	/* Check meas_done */
+1:
+	lw      t1, AR933X_SRIF_DDR_DPLL4_REG(t0)
+	andi    t1, t1, 0x8
+	beqz    t1, 1b
+	nop
+
+	lw      t1, AR933X_SRIF_DDR_DPLL3_REG(t0)
+	li      t2, 0x007FFFF8
+	and     t1, t1, t2
+	srl     t1, t1, 3
+	li      t2, 0x4000
+	bgt     t1, t2, 2b
+	nop
+	addi    t3, t3, -1
+	bnez    t3, 3b
+	nop
+
+	/* clear PLL bypass (bit 2) in CPU CLOCK CONTROL register */
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	li      t1, PLL_CLK_CONTROL_VAL
+	sw      t1, AR933X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	nop
+	jr ra
+	nop
+    END(lowlevel_init)
diff --git a/arch/mips/mach-ath79/ar934x/Makefile b/arch/mips/mach-ath79/ar934x/Makefile
new file mode 100644
index 0000000..348c65b
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += cpu.o
+obj-y += clk.o
+obj-y += ddr.o
diff --git a/arch/mips/mach-ath79/ar934x/clk.c b/arch/mips/mach-ath79/ar934x/clk.c
new file mode 100644
index 0000000..9c65184
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/clk.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+#include <wait_bit.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * The math for calculating PLL:
+ *                                       NFRAC * 2^8
+ *                               NINT + -------------
+ *                XTAL [MHz]              2^(18 - 1)
+ *   PLL [MHz] = ------------ * ----------------------
+ *                  REFDIV              2^OUTDIV
+ *
+ * Unfortunatelly, there is no way to reliably compute the variables.
+ * The vendor U-Boot port contains macros for various combinations of
+ * CPU PLL / DDR PLL / AHB bus speed and there is no obvious pattern
+ * in those numbers.
+ */
+struct ar934x_pll_config {
+	u8	range;
+	u8	refdiv;
+	u8	outdiv;
+	/* Index 0 is for XTAL=25MHz , Index 1 is for XTAL=40MHz */
+	u8	nint[2];
+};
+
+struct ar934x_clock_config {
+	u16				cpu_freq;
+	u16				ddr_freq;
+	u16				ahb_freq;
+
+	struct ar934x_pll_config	cpu_pll;
+	struct ar934x_pll_config	ddr_pll;
+};
+
+static const struct ar934x_clock_config ar934x_clock_config[] = {
+	{ 300, 300, 150, { 1, 1, 1, { 24, 15 } }, { 1, 1, 1, { 24, 15 } } },
+	{ 400, 200, 200, { 1, 1, 1, { 32, 20 } }, { 1, 1, 2, { 32, 20 } } },
+	{ 400, 400, 200, { 0, 1, 1, { 32, 20 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 500, 400, 200, { 1, 1, 0, { 20, 12 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 533, 400, 200, { 1, 1, 0, { 21, 13 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 533, 500, 250, { 1, 1, 0, { 21, 13 } }, { 0, 1, 0, { 20, 12 } } },
+	{ 560, 480, 240, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 12 } } },
+	{ 566, 400, 200, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 16, 10 } } },
+	{ 566, 450, 225, { 1, 1, 0, { 22, 14 } }, { 0, 1, 1, { 36, 22 } } },
+	{ 566, 475, 237, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 19, 11 } } },
+	{ 566, 500, 250, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 20, 12 } } },
+	{ 566, 525, 262, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 21, 13 } } },
+	{ 566, 550, 275, { 1, 1, 0, { 22, 14 } }, { 1, 1, 0, { 22, 13 } } },
+	{ 600, 266, 133, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
+	{ 600, 266, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 21, 16 } } },
+	{ 600, 300, 150, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 24, 15 } } },
+	{ 600, 332, 166, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
+	{ 600, 332, 200, { 0, 1, 0, { 24, 15 } }, { 1, 1, 1, { 26, 16 } } },
+	{ 600, 400, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 1, { 32, 20 } } },
+	{ 600, 450, 200, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 18, 20 } } },
+	{ 600, 500, 250, { 0, 1, 0, { 24, 15 } }, { 1, 1, 0, { 20, 12 } } },
+	{ 600, 525, 262, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 21, 20 } } },
+	{ 600, 550, 275, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 22, 20 } } },
+	{ 600, 575, 287, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 23, 14 } } },
+	{ 600, 600, 300, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 24, 20 } } },
+	{ 600, 650, 325, { 0, 1, 0, { 24, 15 } }, { 0, 1, 0, { 26, 20 } } },
+	{ 650, 600, 300, { 0, 1, 0, { 26, 15 } }, { 0, 1, 0, { 24, 20 } } },
+	{ 700, 400, 200, { 3, 1, 0, { 28, 17 } }, { 0, 1, 1, { 32, 20 } } },
+};
+
+static void ar934x_srif_pll_cfg(void __iomem *pll_reg_base, const u32 srif_val)
+{
+	u32 reg;
+	do {
+		writel(0x10810f00, pll_reg_base + 0x4);
+		writel(srif_val, pll_reg_base + 0x0);
+		writel(0xd0810f00, pll_reg_base + 0x4);
+		writel(0x03000000, pll_reg_base + 0x8);
+		writel(0xd0800f00, pll_reg_base + 0x4);
+
+		clrbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+		setbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+
+		wait_for_bit("clk", pll_reg_base + 0xc, BIT(3), 1, 10, 0);
+
+		clrbits_be32(pll_reg_base + 0x8, BIT(30));
+		udelay(5);
+
+		/* Check if CPU SRIF PLL locked. */
+		reg = readl(pll_reg_base + 0x8);
+		reg = (reg & 0x7ffff8) >> 3;
+	} while (reg >= 0x40000);
+}
+
+void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
+{
+	void __iomem *srif_regs = map_physmem(AR934X_SRIF_BASE,
+					      AR934X_SRIF_SIZE, MAP_NOCACHE);
+	void __iomem *pll_regs = map_physmem(AR71XX_PLL_BASE,
+					     AR71XX_PLL_SIZE, MAP_NOCACHE);
+	const struct ar934x_pll_config *pll_cfg;
+	int i, pll_nint, pll_refdiv, xtal_40 = 0;
+	u32 reg, cpu_pll, cpu_srif, ddr_pll, ddr_srif;
+
+	/* Configure SRIF PLL with initial values. */
+	writel(0x13210f00, srif_regs + AR934X_SRIF_CPU_DPLL2_REG);
+	writel(0x03000000, srif_regs + AR934X_SRIF_CPU_DPLL3_REG);
+	writel(0x13210f00, srif_regs + AR934X_SRIF_DDR_DPLL2_REG);
+	writel(0x03000000, srif_regs + AR934X_SRIF_DDR_DPLL3_REG);
+	writel(0x03000000, srif_regs + 0x188); /* Undocumented reg :-) */
+
+	/* Test for 40MHz XTAL */
+	reg = get_bootstrap();
+	if (reg & AR934X_BOOTSTRAP_REF_CLK_40) {
+		xtal_40 = 1;
+		cpu_srif = 0x41c00000;
+		ddr_srif = 0x41680000;
+	} else {
+		xtal_40 = 0;
+		cpu_srif = 0x29c00000;
+		ddr_srif = 0x29680000;
+	}
+
+	/* Locate CPU/DDR PLL configuration */
+	for (i = 0; i < ARRAY_SIZE(ar934x_clock_config); i++) {
+		if (cpu_mhz != ar934x_clock_config[i].cpu_freq)
+			continue;
+		if (ddr_mhz != ar934x_clock_config[i].ddr_freq)
+			continue;
+		if (ahb_mhz != ar934x_clock_config[i].ahb_freq)
+			continue;
+
+		/* Entry found */
+		pll_cfg = &ar934x_clock_config[i].cpu_pll;
+		pll_nint = pll_cfg->nint[xtal_40];
+		pll_refdiv = pll_cfg->refdiv;
+		cpu_pll =
+			(pll_nint << AR934X_PLL_CPU_CONFIG_NINT_SHIFT) |
+			(pll_refdiv << AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) |
+			(pll_cfg->range << AR934X_PLL_CPU_CONFIG_RANGE_SHIFT) |
+			(pll_cfg->outdiv << AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT);
+
+		pll_cfg = &ar934x_clock_config[i].ddr_pll;
+		pll_nint = pll_cfg->nint[xtal_40];
+		pll_refdiv = pll_cfg->refdiv;
+		ddr_pll =
+			(pll_nint << AR934X_PLL_DDR_CONFIG_NINT_SHIFT) |
+			(pll_refdiv << AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) |
+			(pll_cfg->range << AR934X_PLL_DDR_CONFIG_RANGE_SHIFT) |
+			(pll_cfg->outdiv << AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT);
+		break;
+	}
+
+	/* PLL configuration not found, hang. */
+	if (i == ARRAY_SIZE(ar934x_clock_config))
+		hang();
+
+	/* Set PLL Bypass */
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
+	setbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
+
+	/* Configure CPU PLL */
+	writel(cpu_pll | AR934X_PLL_CPU_CONFIG_PLLPWD,
+	       pll_regs + AR934X_PLL_CPU_CONFIG_REG);
+	/* Configure DDR PLL */
+	writel(ddr_pll | AR934X_PLL_DDR_CONFIG_PLLPWD,
+	       pll_regs + AR934X_PLL_DDR_CONFIG_REG);
+	/* Configure PLL routing */
+	writel(AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS |
+	       AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS |
+	       AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS |
+	       (0 << AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) |
+	       (0 << AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) |
+	       (1 << AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) |
+	       AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL |
+	       AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL |
+	       AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL,
+	       pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
+
+	/* Configure SRIF PLLs, which is completely undocumented :-) */
+	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_CPU_DPLL1_REG, cpu_srif);
+	ar934x_srif_pll_cfg(srif_regs + AR934X_SRIF_DDR_DPLL1_REG, ddr_srif);
+
+	/* Unset PLL Bypass */
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS);
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS);
+	clrbits_be32(pll_regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG,
+		     AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS);
+
+	/* Enable PLL dithering */
+	writel((1 << AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT) |
+	       (0xf << AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT),
+	       pll_regs + AR934X_PLL_DDR_DIT_FRAC_REG);
+	writel(48 << AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT,
+	       pll_regs + AR934X_PLL_CPU_DIT_FRAC_REG);
+}
+
+static u32 ar934x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & AR934X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return ar934x_get_xtal();
+}
+
+static u32 ar934x_cpupll_to_hz(const u32 regval)
+{
+	const u32 outdiv = (regval >> AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	const u32 refdiv = (regval >> AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_REFDIV_MASK;
+	const u32 nint = (regval >> AR934X_PLL_CPU_CONFIG_NINT_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_NINT_MASK;
+	const u32 nfrac = (regval >> AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT) &
+			   AR934X_PLL_CPU_CONFIG_NFRAC_MASK;
+	const u32 xtal = ar934x_get_xtal();
+
+	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
+}
+
+static u32 ar934x_ddrpll_to_hz(const u32 regval)
+{
+	const u32 outdiv = (regval >> AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	const u32 refdiv = (regval >> AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_REFDIV_MASK;
+	const u32 nint = (regval >> AR934X_PLL_DDR_CONFIG_NINT_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_NINT_MASK;
+	const u32 nfrac = (regval >> AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT) &
+			   AR934X_PLL_DDR_CONFIG_NFRAC_MASK;
+	const u32 xtal = ar934x_get_xtal();
+
+	return (xtal * (nint + (nfrac >> 9))) / (refdiv * (1 << outdiv));
+}
+
+static void ar934x_update_clock(void)
+{
+	void __iomem *regs;
+	u32 ctrl, cpu, cpupll, ddr, ddrpll;
+	u32 cpudiv, ddrdiv, busdiv;
+	u32 cpuclk, ddrclk, busclk;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+
+	cpu = readl(regs + AR934X_PLL_CPU_CONFIG_REG);
+	ddr = readl(regs + AR934X_PLL_DDR_CONFIG_REG);
+	ctrl = readl(regs + AR934X_PLL_CPU_DDR_CLK_CTRL_REG);
+
+	cpupll = ar934x_cpupll_to_hz(cpu);
+	ddrpll = ar934x_ddrpll_to_hz(ddr);
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS)
+		cpuclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL)
+		cpuclk = cpupll;
+	else
+		cpuclk = ddrpll;
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS)
+		ddrclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+		ddrclk = ddrpll;
+	else
+		ddrclk = cpupll;
+
+	if (ctrl & AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+		busclk = ar934x_get_xtal();
+	else if (ctrl & AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL)
+		busclk = ddrpll;
+	else
+		busclk = cpupll;
+
+	cpudiv = (ctrl >> AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK;
+	ddrdiv = (ctrl >> AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK;
+	busdiv = (ctrl >> AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT) &
+		 AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK;
+
+	gd->cpu_clk = cpuclk / (cpudiv + 1);
+	gd->mem_clk = ddrclk / (ddrdiv + 1);
+	gd->bus_clk = busclk / (busdiv + 1);
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	ar934x_update_clock();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	ar934x_update_clock();
+	return gd->mem_clk;
+}
+
+int do_ar934x_showclk(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	ar934x_update_clock();
+	printf("CPU:       %8ld MHz\n", gd->cpu_clk / 1000000);
+	printf("Memory:    %8ld MHz\n", gd->mem_clk / 1000000);
+	printf("AHB:       %8ld MHz\n", gd->bus_clk / 1000000);
+	return 0;
+}
+
+U_BOOT_CMD(
+	clocks,	CONFIG_SYS_MAXARGS, 1, do_ar934x_showclk,
+	"display clocks",
+	""
+);
diff --git a/arch/mips/mach-ath79/ar934x/cpu.c b/arch/mips/mach-ath79/ar934x/cpu.c
new file mode 100644
index 0000000..8fcdf65
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/cpu.c
@@ -0,0 +1,10 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+
+/* The lowlevel_init() is not needed on AR934x */
+void lowlevel_init(void) {}
diff --git a/arch/mips/mach-ath79/ar934x/ddr.c b/arch/mips/mach-ath79/ar934x/ddr.c
new file mode 100644
index 0000000..4621d58
--- /dev/null
+++ b/arch/mips/mach-ath79/ar934x/ddr.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * Based on RAM init sequence by Piotr Dymacz <pepe2k@gmail.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum {
+	AR934X_SDRAM = 0,
+	AR934X_DDR1,
+	AR934X_DDR2,
+};
+
+struct ar934x_mem_config {
+	u32	config1;
+	u32	config2;
+	u32	mode;
+	u32	extmode;
+	u32	tap;
+};
+
+static const struct ar934x_mem_config ar934x_mem_config[] = {
+	[AR934X_SDRAM] = { 0x7fbe8cd0, 0x959f66a8, 0x33, 0, 0x1f1f },
+	[AR934X_DDR1]  = { 0x7fd48cd0, 0x99d0e6a8, 0x33, 0, 0x14 },
+	[AR934X_DDR2]  = { 0xc7d48cd0, 0x9dd0e6a8, 0x33, 0, 0x10012 },
+};
+
+void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz)
+{
+	void __iomem *ddr_regs;
+	const struct ar934x_mem_config *memcfg;
+	int memtype;
+	u32 reg, cycle, ctl;
+
+	ddr_regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			       MAP_NOCACHE);
+
+	reg = get_bootstrap();
+	if (reg & AR934X_BOOTSTRAP_SDRAM_DISABLED) {	/* DDR */
+		if (reg & AR934X_BOOTSTRAP_DDR1) {	/* DDR 1 */
+			memtype = AR934X_DDR1;
+			cycle = 0xffff;
+		} else {				/* DDR 2 */
+			memtype = AR934X_DDR2;
+			if (gd->arch.rev) {
+				ctl = BIT(6);	/* Undocumented bit :-( */
+				if (reg & BIT(3))
+					cycle = 0xff;
+				else
+					cycle = 0xffff;
+			} else {
+				/* Force DDR2/x16 configuratio on old chips. */
+				ctl = 0;
+				cycle = 0xffff;		/* DDR2 16bit */
+			}
+
+			writel(0xe59, ddr_regs + AR934X_DDR_REG_DDR2_CONFIG);
+			udelay(100);
+
+			writel(0x10, ddr_regs + AR71XX_DDR_REG_CONTROL);
+			udelay(10);
+
+			writel(0x20, ddr_regs + AR71XX_DDR_REG_CONTROL);
+			udelay(10);
+
+			writel(ctl, ddr_regs + AR934X_DDR_REG_CTL_CONF);
+			udelay(10);
+		}
+	} else {					/* SDRAM */
+		memtype = AR934X_SDRAM;
+		cycle = 0xffffffff;
+
+		writel(0x13b, ddr_regs + AR934X_DDR_REG_CTL_CONF);
+		udelay(100);
+
+		/* Undocumented register */
+		writel(0x13b, ddr_regs + 0x118);
+		udelay(100);
+	}
+
+	memcfg = &ar934x_mem_config[memtype];
+
+	writel(memcfg->config1, ddr_regs + AR71XX_DDR_REG_CONFIG);
+	udelay(100);
+
+	writel(memcfg->config2, ddr_regs + AR71XX_DDR_REG_CONFIG2);
+	udelay(100);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_MODE);
+	mdelay(1);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	if (memtype == AR934X_DDR2) {
+		writel(memcfg->mode | 0x100, ddr_regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+	}
+
+	if (memtype != AR934X_SDRAM)
+		writel(0x402, ddr_regs + AR71XX_DDR_REG_EMR);
+
+	udelay(100);
+
+	writel(0x2, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(0x8, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(memcfg->mode, ddr_regs + AR71XX_DDR_REG_MODE);
+	udelay(100);
+
+	writel(0x1, ddr_regs + AR71XX_DDR_REG_CONTROL);
+	udelay(10);
+
+	writel(0x412c /* FIXME */, ddr_regs + AR71XX_DDR_REG_REFRESH);
+	udelay(100);
+
+	writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL0);
+	writel(memcfg->tap, ddr_regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+	if (memtype != AR934X_SDRAM) {
+		if ((gd->arch.rev && (reg & BIT(3))) || !gd->arch.rev) {
+			writel(memcfg->tap,
+			       ddr_regs + AR934X_DDR_REG_TAP_CTRL2);
+			writel(memcfg->tap,
+			       ddr_regs + AR934X_DDR_REG_TAP_CTRL3);
+		}
+	}
+
+	writel(cycle, ddr_regs + AR71XX_DDR_REG_RD_CYCLE);
+	udelay(100);
+
+	writel(0x74444444, ddr_regs + AR934X_DDR_REG_BURST);
+	udelay(100);
+
+	writel(0x222, ddr_regs + AR934X_DDR_REG_BURST2);
+	udelay(100);
+
+	writel(0xfffff, ddr_regs + AR934X_DDR_REG_TIMEOUT_MAX);
+	udelay(100);
+}
+
+void ddr_tap_tuning(void)
+{
+}
diff --git a/arch/mips/mach-ath79/cpu.c b/arch/mips/mach-ath79/cpu.c
new file mode 100644
index 0000000..5756a06
--- /dev/null
+++ b/arch/mips/mach-ath79/cpu.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+
+struct ath79_soc_desc {
+	const enum ath79_soc_type soc;
+	const char *chip;
+	const int major;
+	const int minor;
+};
+
+static const struct ath79_soc_desc desc[] = {
+	{ATH79_SOC_AR7130,      "7130",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7130},
+	{ATH79_SOC_AR7141,      "7141",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7141},
+	{ATH79_SOC_AR7161,      "7161",
+	 REV_ID_MAJOR_AR71XX,   AR71XX_REV_ID_MINOR_AR7161},
+	{ATH79_SOC_AR7240,      "7240", REV_ID_MAJOR_AR7240,    0},
+	{ATH79_SOC_AR7241,      "7241", REV_ID_MAJOR_AR7241,    0},
+	{ATH79_SOC_AR7242,      "7242", REV_ID_MAJOR_AR7242,    0},
+	{ATH79_SOC_AR9130,      "9130",
+	 REV_ID_MAJOR_AR913X,   AR913X_REV_ID_MINOR_AR9130},
+	{ATH79_SOC_AR9132,      "9132",
+	 REV_ID_MAJOR_AR913X,   AR913X_REV_ID_MINOR_AR9132},
+	{ATH79_SOC_AR9330,      "9330", REV_ID_MAJOR_AR9330,    0},
+	{ATH79_SOC_AR9331,      "9331", REV_ID_MAJOR_AR9331,    0},
+	{ATH79_SOC_AR9341,      "9341", REV_ID_MAJOR_AR9341,    0},
+	{ATH79_SOC_AR9342,      "9342", REV_ID_MAJOR_AR9342,    0},
+	{ATH79_SOC_AR9344,      "9344", REV_ID_MAJOR_AR9344,    0},
+	{ATH79_SOC_QCA9533,     "9533", REV_ID_MAJOR_QCA9533,   0},
+	{ATH79_SOC_QCA9533,     "9533",
+	 REV_ID_MAJOR_QCA9533_V2,       0},
+	{ATH79_SOC_QCA9556,     "9556", REV_ID_MAJOR_QCA9556,   0},
+	{ATH79_SOC_QCA9558,     "9558", REV_ID_MAJOR_QCA9558,   0},
+	{ATH79_SOC_TP9343,      "9343", REV_ID_MAJOR_TP9343,    0},
+	{ATH79_SOC_QCA9561,     "9561", REV_ID_MAJOR_QCA9561,   0},
+};
+
+int arch_cpu_init(void)
+{
+	void __iomem *base;
+	enum ath79_soc_type soc = ATH79_SOC_UNKNOWN;
+	u32 id, major, minor = 0;
+	u32 rev = 0, ver = 1;
+	int i;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+
+	id = readl(base + AR71XX_RESET_REG_REV_ID);
+	major = id & REV_ID_MAJOR_MASK;
+	switch (major) {
+	case REV_ID_MAJOR_AR71XX:
+	case REV_ID_MAJOR_AR913X:
+		minor = id & AR71XX_REV_ID_MINOR_MASK;
+		rev = id >> AR71XX_REV_ID_REVISION_SHIFT;
+		rev &= AR71XX_REV_ID_REVISION_MASK;
+		break;
+
+	case REV_ID_MAJOR_QCA9533_V2:
+		ver = 2;
+		/* drop through */
+
+	case REV_ID_MAJOR_AR9341:
+	case REV_ID_MAJOR_AR9342:
+	case REV_ID_MAJOR_AR9344:
+	case REV_ID_MAJOR_QCA9533:
+	case REV_ID_MAJOR_QCA9556:
+	case REV_ID_MAJOR_QCA9558:
+	case REV_ID_MAJOR_TP9343:
+	case REV_ID_MAJOR_QCA9561:
+		rev = id & AR71XX_REV_ID_REVISION2_MASK;
+		break;
+	default:
+		rev = id & AR71XX_REV_ID_REVISION_MASK;
+		break;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(desc); i++) {
+		if ((desc[i].major == major) &&
+		    (desc[i].minor == minor)) {
+			soc = desc[i].soc;
+			break;
+		}
+	}
+
+	gd->arch.id = id;
+	gd->arch.soc = soc;
+	gd->arch.rev = rev;
+	gd->arch.ver = ver;
+	return 0;
+}
+
+int print_cpuinfo(void)
+{
+	enum ath79_soc_type soc = ATH79_SOC_UNKNOWN;
+	const char *chip = "????";
+	u32 id, rev, ver;
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(desc); i++) {
+		if (desc[i].soc == gd->arch.soc) {
+			chip = desc[i].chip;
+			soc = desc[i].soc;
+			break;
+		}
+	}
+
+	id = gd->arch.id;
+	rev = gd->arch.rev;
+	ver = gd->arch.ver;
+
+	switch (soc) {
+	case ATH79_SOC_QCA9533:
+	case ATH79_SOC_QCA9556:
+	case ATH79_SOC_QCA9558:
+	case ATH79_SOC_QCA9561:
+		printf("Qualcomm Atheros QCA%s ver %u rev %u\n", chip,
+		       ver, rev);
+		break;
+	case ATH79_SOC_TP9343:
+		printf("Qualcomm Atheros TP%s rev %u\n", chip, rev);
+		break;
+	case ATH79_SOC_UNKNOWN:
+		printf("ATH79: unknown SoC, id:0x%08x", id);
+		break;
+	default:
+		printf("Atheros AR%s rev %u\n", chip, rev);
+	}
+
+	return 0;
+}
diff --git a/arch/mips/mach-ath79/dram.c b/arch/mips/mach-ath79/dram.c
new file mode 100644
index 0000000..c29e98c
--- /dev/null
+++ b/arch/mips/mach-ath79/dram.c
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/sizes.h>
+#include <asm/addrspace.h>
+#include <mach/ddr.h>
+
+phys_size_t initdram(int board_type)
+{
+	ddr_tap_tuning();
+	return get_ram_size((void *)KSEG1, SZ_256M);
+}
diff --git a/arch/mips/mach-ath79/include/mach/ar71xx_regs.h b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
new file mode 100644
index 0000000..a8e51cb
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ar71xx_regs.h
@@ -0,0 +1,1263 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X SoC register definitions
+ *
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Copyright (C) 2010-2011 Jaiganesh Narayanan <jnarayanan@atheros.com>
+ * Copyright (C) 2008-2010 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_AR71XX_REGS_H
+#define __ASM_MACH_AR71XX_REGS_H
+
+#ifndef __ASSEMBLY__
+#include <linux/bitops.h>
+#else
+#ifndef BIT
+#define BIT(nr)		(1 << (nr))
+#endif
+#endif
+
+#define AR71XX_APB_BASE					0x18000000
+#define AR71XX_GE0_BASE					0x19000000
+#define AR71XX_GE0_SIZE					0x10000
+#define AR71XX_GE1_BASE					0x1a000000
+#define AR71XX_GE1_SIZE					0x10000
+#define AR71XX_EHCI_BASE				0x1b000000
+#define AR71XX_EHCI_SIZE				0x1000
+#define AR71XX_OHCI_BASE				0x1c000000
+#define AR71XX_OHCI_SIZE				0x1000
+#define AR71XX_SPI_BASE					0x1f000000
+#define AR71XX_SPI_SIZE					0x01000000
+
+#define AR71XX_DDR_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00000000)
+#define AR71XX_DDR_CTRL_SIZE				0x100
+#define AR71XX_UART_BASE \
+	(AR71XX_APB_BASE + 0x00020000)
+#define AR71XX_UART_SIZE				0x100
+#define AR71XX_USB_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00030000)
+#define AR71XX_USB_CTRL_SIZE				0x100
+#define AR71XX_GPIO_BASE \
+	(AR71XX_APB_BASE + 0x00040000)
+#define AR71XX_GPIO_SIZE				0x100
+#define AR71XX_PLL_BASE \
+	(AR71XX_APB_BASE + 0x00050000)
+#define AR71XX_PLL_SIZE					0x100
+#define AR71XX_RESET_BASE \
+	(AR71XX_APB_BASE + 0x00060000)
+#define AR71XX_RESET_SIZE				0x100
+#define AR71XX_MII_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR71XX_MII_SIZE					0x100
+
+#define AR71XX_PCI_MEM_BASE				0x10000000
+#define AR71XX_PCI_MEM_SIZE				0x07000000
+
+#define AR71XX_PCI_WIN0_OFFS				0x10000000
+#define AR71XX_PCI_WIN1_OFFS				0x11000000
+#define AR71XX_PCI_WIN2_OFFS				0x12000000
+#define AR71XX_PCI_WIN3_OFFS				0x13000000
+#define AR71XX_PCI_WIN4_OFFS				0x14000000
+#define AR71XX_PCI_WIN5_OFFS				0x15000000
+#define AR71XX_PCI_WIN6_OFFS				0x16000000
+#define AR71XX_PCI_WIN7_OFFS				0x07000000
+
+#define AR71XX_PCI_CFG_BASE \
+	(AR71XX_PCI_MEM_BASE + AR71XX_PCI_WIN7_OFFS + 0x10000)
+#define AR71XX_PCI_CFG_SIZE				0x100
+
+#define AR7240_USB_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x00030000)
+#define AR7240_USB_CTRL_SIZE				0x100
+#define AR7240_OHCI_BASE				0x1b000000
+#define AR7240_OHCI_SIZE				0x1000
+
+#define AR724X_PCI_MEM_BASE				0x10000000
+#define AR724X_PCI_MEM_SIZE				0x04000000
+
+#define AR724X_PCI_CFG_BASE				0x14000000
+#define AR724X_PCI_CFG_SIZE				0x1000
+#define AR724X_PCI_CRP_BASE \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define AR724X_PCI_CRP_SIZE				0x1000
+#define AR724X_PCI_CTRL_BASE \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define AR724X_PCI_CTRL_SIZE				0x100
+
+#define AR724X_EHCI_BASE				0x1b000000
+#define AR724X_EHCI_SIZE				0x1000
+
+#define AR913X_EHCI_BASE				0x1b000000
+#define AR913X_EHCI_SIZE				0x1000
+#define AR913X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x000C0000)
+#define AR913X_WMAC_SIZE				0x30000
+
+#define AR933X_UART_BASE \
+	(AR71XX_APB_BASE + 0x00020000)
+#define AR933X_UART_SIZE				0x14
+#define AR933X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR933X_GMAC_SIZE				0x04
+#define AR933X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define AR933X_WMAC_SIZE				0x20000
+#define AR933X_RTC_BASE \
+	(AR71XX_APB_BASE + 0x00107000)
+#define AR933X_RTC_SIZE					0x1000
+#define AR933X_EHCI_BASE				0x1b000000
+#define AR933X_EHCI_SIZE				0x1000
+#define AR933X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define AR933X_SRIF_SIZE				0x1000
+
+#define AR934X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define AR934X_GMAC_SIZE				0x14
+#define AR934X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define AR934X_WMAC_SIZE				0x20000
+#define AR934X_EHCI_BASE				0x1b000000
+#define AR934X_EHCI_SIZE				0x200
+#define AR934X_NFC_BASE					0x1b000200
+#define AR934X_NFC_SIZE					0xb8
+#define AR934X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define AR934X_SRIF_SIZE				0x1000
+
+#define QCA953X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA953X_GMAC_SIZE				0x14
+#define QCA953X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA953X_WMAC_SIZE				0x20000
+#define QCA953X_RTC_BASE \
+	(AR71XX_APB_BASE + 0x00107000)
+#define QCA953X_RTC_SIZE				0x1000
+#define QCA953X_EHCI_BASE				0x1b000000
+#define QCA953X_EHCI_SIZE				0x200
+#define QCA953X_SRIF_BASE \
+	(AR71XX_APB_BASE + 0x00116000)
+#define QCA953X_SRIF_SIZE				0x1000
+
+#define QCA953X_PCI_CFG_BASE0				0x14000000
+#define QCA953X_PCI_CTRL_BASE0 \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA953X_PCI_CRP_BASE0 \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA953X_PCI_MEM_BASE0				0x10000000
+#define QCA953X_PCI_MEM_SIZE				0x02000000
+
+#define QCA955X_PCI_MEM_BASE0				0x10000000
+#define QCA955X_PCI_MEM_BASE1				0x12000000
+#define QCA955X_PCI_MEM_SIZE				0x02000000
+#define QCA955X_PCI_CFG_BASE0				0x14000000
+#define QCA955X_PCI_CFG_BASE1				0x16000000
+#define QCA955X_PCI_CFG_SIZE				0x1000
+#define QCA955X_PCI_CRP_BASE0 \
+	(AR71XX_APB_BASE + 0x000c0000)
+#define QCA955X_PCI_CRP_BASE1 \
+	(AR71XX_APB_BASE + 0x00250000)
+#define QCA955X_PCI_CRP_SIZE				0x1000
+#define QCA955X_PCI_CTRL_BASE0 \
+	(AR71XX_APB_BASE + 0x000f0000)
+#define QCA955X_PCI_CTRL_BASE1 \
+	(AR71XX_APB_BASE + 0x00280000)
+#define QCA955X_PCI_CTRL_SIZE				0x100
+
+#define QCA955X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA955X_GMAC_SIZE				0x40
+#define QCA955X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA955X_WMAC_SIZE				0x20000
+#define QCA955X_EHCI0_BASE				0x1b000000
+#define QCA955X_EHCI1_BASE				0x1b400000
+#define QCA955X_EHCI_SIZE				0x1000
+#define QCA955X_NFC_BASE				0x1b800200
+#define QCA955X_NFC_SIZE				0xb8
+
+#define QCA956X_PCI_MEM_BASE1				0x12000000
+#define QCA956X_PCI_MEM_SIZE				0x02000000
+#define QCA956X_PCI_CFG_BASE1				0x16000000
+#define QCA956X_PCI_CFG_SIZE				0x1000
+#define QCA956X_PCI_CRP_BASE1 \
+	(AR71XX_APB_BASE + 0x00250000)
+#define QCA956X_PCI_CRP_SIZE				0x1000
+#define QCA956X_PCI_CTRL_BASE1 \
+	(AR71XX_APB_BASE + 0x00280000)
+#define QCA956X_PCI_CTRL_SIZE				0x100
+
+#define QCA956X_WMAC_BASE \
+	(AR71XX_APB_BASE + 0x00100000)
+#define QCA956X_WMAC_SIZE				0x20000
+#define QCA956X_EHCI0_BASE				0x1b000000
+#define QCA956X_EHCI1_BASE				0x1b400000
+#define QCA956X_EHCI_SIZE				0x200
+#define QCA956X_GMAC_BASE \
+	(AR71XX_APB_BASE + 0x00070000)
+#define QCA956X_GMAC_SIZE				0x64
+
+/*
+ * DDR_CTRL block
+ */
+#define AR71XX_DDR_REG_CONFIG				0x00
+#define AR71XX_DDR_REG_CONFIG2				0x04
+#define AR71XX_DDR_REG_MODE				0x08
+#define AR71XX_DDR_REG_EMR				0x0c
+#define AR71XX_DDR_REG_CONTROL				0x10
+#define AR71XX_DDR_REG_REFRESH				0x14
+#define AR71XX_DDR_REG_RD_CYCLE				0x18
+#define AR71XX_DDR_REG_TAP_CTRL0			0x1c
+#define AR71XX_DDR_REG_TAP_CTRL1			0x20
+
+#define AR71XX_DDR_REG_PCI_WIN0				0x7c
+#define AR71XX_DDR_REG_PCI_WIN1				0x80
+#define AR71XX_DDR_REG_PCI_WIN2				0x84
+#define AR71XX_DDR_REG_PCI_WIN3				0x88
+#define AR71XX_DDR_REG_PCI_WIN4				0x8c
+#define AR71XX_DDR_REG_PCI_WIN5				0x90
+#define AR71XX_DDR_REG_PCI_WIN6				0x94
+#define AR71XX_DDR_REG_PCI_WIN7				0x98
+#define AR71XX_DDR_REG_FLUSH_GE0			0x9c
+#define AR71XX_DDR_REG_FLUSH_GE1			0xa0
+#define AR71XX_DDR_REG_FLUSH_USB			0xa4
+#define AR71XX_DDR_REG_FLUSH_PCI			0xa8
+
+#define AR724X_DDR_REG_FLUSH_GE0			0x7c
+#define AR724X_DDR_REG_FLUSH_GE1			0x80
+#define AR724X_DDR_REG_FLUSH_USB			0x84
+#define AR724X_DDR_REG_FLUSH_PCIE			0x88
+
+#define AR913X_DDR_REG_FLUSH_GE0			0x7c
+#define AR913X_DDR_REG_FLUSH_GE1			0x80
+#define AR913X_DDR_REG_FLUSH_USB			0x84
+#define AR913X_DDR_REG_FLUSH_WMAC			0x88
+
+#define AR933X_DDR_REG_FLUSH_GE0			0x7c
+#define AR933X_DDR_REG_FLUSH_GE1			0x80
+#define AR933X_DDR_REG_FLUSH_USB			0x84
+#define AR933X_DDR_REG_FLUSH_WMAC			0x88
+#define AR933X_DDR_REG_DDR2_CONFIG			0x8c
+#define AR933X_DDR_REG_EMR2				0x90
+#define AR933X_DDR_REG_EMR3				0x94
+#define AR933X_DDR_REG_BURST				0x98
+#define AR933X_DDR_REG_TIMEOUT_MAX			0x9c
+#define AR933X_DDR_REG_TIMEOUT_CNT			0x9c
+#define AR933X_DDR_REG_TIMEOUT_ADDR			0x9c
+
+#define AR934X_DDR_REG_TAP_CTRL2			0x24
+#define AR934X_DDR_REG_TAP_CTRL3			0x28
+#define AR934X_DDR_REG_FLUSH_GE0			0x9c
+#define AR934X_DDR_REG_FLUSH_GE1			0xa0
+#define AR934X_DDR_REG_FLUSH_USB			0xa4
+#define AR934X_DDR_REG_FLUSH_PCIE			0xa8
+#define AR934X_DDR_REG_FLUSH_WMAC			0xac
+#define AR934X_DDR_REG_FLUSH_SRC1			0xb0
+#define AR934X_DDR_REG_FLUSH_SRC2			0xb4
+#define AR934X_DDR_REG_DDR2_CONFIG			0xb8
+#define AR934X_DDR_REG_EMR2				0xbc
+#define AR934X_DDR_REG_EMR3				0xc0
+#define AR934X_DDR_REG_BURST				0xc4
+#define AR934X_DDR_REG_BURST2				0xc8
+#define AR934X_DDR_REG_TIMEOUT_MAX			0xcc
+#define AR934X_DDR_REG_CTL_CONF				0x108
+
+#define QCA953X_DDR_REG_FLUSH_GE0			0x9c
+#define QCA953X_DDR_REG_FLUSH_GE1			0xa0
+#define QCA953X_DDR_REG_FLUSH_USB			0xa4
+#define QCA953X_DDR_REG_FLUSH_PCIE			0xa8
+#define QCA953X_DDR_REG_FLUSH_WMAC			0xac
+#define QCA953X_DDR_REG_DDR2_CONFIG			0xb8
+#define QCA953X_DDR_REG_BURST				0xc4
+#define QCA953X_DDR_REG_BURST2				0xc8
+#define QCA953X_DDR_REG_TIMEOUT_MAX			0xcc
+#define QCA953X_DDR_REG_CTL_CONF			0x108
+#define QCA953X_DDR_REG_CONFIG3				0x15c
+
+/*
+ * PLL block
+ */
+#define AR71XX_PLL_REG_CPU_CONFIG			0x00
+#define AR71XX_PLL_REG_SEC_CONFIG			0x04
+#define AR71XX_PLL_REG_ETH0_INT_CLOCK			0x10
+#define AR71XX_PLL_REG_ETH1_INT_CLOCK			0x14
+
+#define AR71XX_PLL_DIV_SHIFT				3
+#define AR71XX_PLL_DIV_MASK				0x1f
+#define AR71XX_CPU_DIV_SHIFT				16
+#define AR71XX_CPU_DIV_MASK				0x3
+#define AR71XX_DDR_DIV_SHIFT				18
+#define AR71XX_DDR_DIV_MASK				0x3
+#define AR71XX_AHB_DIV_SHIFT				20
+#define AR71XX_AHB_DIV_MASK				0x7
+
+#define AR71XX_ETH0_PLL_SHIFT				17
+#define AR71XX_ETH1_PLL_SHIFT				19
+
+#define AR724X_PLL_REG_CPU_CONFIG			0x00
+#define AR724X_PLL_REG_PCIE_CONFIG			0x18
+
+#define AR724X_PLL_DIV_SHIFT				0
+#define AR724X_PLL_DIV_MASK				0x3ff
+#define AR724X_PLL_REF_DIV_SHIFT			10
+#define AR724X_PLL_REF_DIV_MASK				0xf
+#define AR724X_AHB_DIV_SHIFT				19
+#define AR724X_AHB_DIV_MASK				0x1
+#define AR724X_DDR_DIV_SHIFT				22
+#define AR724X_DDR_DIV_MASK				0x3
+
+#define AR7242_PLL_REG_ETH0_INT_CLOCK			0x2c
+
+#define AR913X_PLL_REG_CPU_CONFIG			0x00
+#define AR913X_PLL_REG_ETH_CONFIG			0x04
+#define AR913X_PLL_REG_ETH0_INT_CLOCK			0x14
+#define AR913X_PLL_REG_ETH1_INT_CLOCK			0x18
+
+#define AR913X_PLL_DIV_SHIFT				0
+#define AR913X_PLL_DIV_MASK				0x3ff
+#define AR913X_DDR_DIV_SHIFT				22
+#define AR913X_DDR_DIV_MASK				0x3
+#define AR913X_AHB_DIV_SHIFT				19
+#define AR913X_AHB_DIV_MASK				0x1
+
+#define AR913X_ETH0_PLL_SHIFT				20
+#define AR913X_ETH1_PLL_SHIFT				22
+
+#define AR933X_PLL_CPU_CONFIG_REG			0x00
+#define AR933X_PLL_CLK_CTRL_REG				0x08
+#define AR933X_PLL_DITHER_FRAC_REG			0x10
+
+#define AR933X_PLL_CPU_CONFIG_NINT_SHIFT		10
+#define AR933X_PLL_CPU_CONFIG_NINT_MASK			0x3f
+#define AR933X_PLL_CPU_CONFIG_REFDIV_SHIFT		16
+#define AR933X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_SHIFT		23
+#define AR933X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define AR933X_PLL_CLK_CTRL_BYPASS			BIT(2)
+#define AR933X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define AR933X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x3
+#define AR933X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define AR933X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x3
+#define AR933X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define AR933X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x7
+
+#define AR934X_PLL_CPU_CONFIG_REG			0x00
+#define AR934X_PLL_DDR_CONFIG_REG			0x04
+#define AR934X_PLL_CPU_DDR_CLK_CTRL_REG			0x08
+#define AR934X_PLL_SWITCH_CLOCK_CONTROL_REG		0x24
+#define AR934X_PLL_ETH_XMII_CONTROL_REG			0x2c
+#define AR934X_PLL_DDR_DIT_FRAC_REG			0x44
+#define AR934X_PLL_CPU_DIT_FRAC_REG			0x48
+
+#define AR934X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define AR934X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define AR934X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define AR934X_PLL_CPU_CONFIG_NINT_MASK			0x3f
+#define AR934X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define AR934X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define AR934X_PLL_CPU_CONFIG_RANGE_SHIFT		17
+#define AR934X_PLL_CPU_CONFIG_RANGE_MASK		0x3
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define AR934X_PLL_CPU_CONFIG_OUTDIV_MASK		0x3
+#define AR934X_PLL_CPU_CONFIG_PLLPWD			BIT(30)
+#define AR934X_PLL_CPU_CONFIG_UPDATING			BIT(31)
+
+#define AR934X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define AR934X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define AR934X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define AR934X_PLL_DDR_CONFIG_NINT_MASK			0x3f
+#define AR934X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define AR934X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define AR934X_PLL_DDR_CONFIG_RANGE_SHIFT		21
+#define AR934X_PLL_DDR_CONFIG_RANGE_MASK		0x3
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define AR934X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+#define AR934X_PLL_DDR_CONFIG_PLLPWD			BIT(30)
+#define AR934X_PLL_DDR_CONFIG_UPDATING			BIT(31)
+
+#define AR934X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define AR934X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define AR934X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define AR934X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define AR934X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define AR934X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define AR934X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define AR934X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define AR934X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define AR934X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define AR934X_PLL_SWITCH_CLK_CTRL_MDIO_CLK_SEL		BIT(6)
+
+#define AR934X_PLL_DDR_DIT_FRAC_MAX_SHIFT		0
+#define AR934X_PLL_DDR_DIT_FRAC_MAX_MASK		0x3ff
+#define AR934X_PLL_DDR_DIT_FRAC_MIN_SHIFT		10
+#define AR934X_PLL_DDR_DIT_FRAC_MIN_MASK		0x3ff
+#define AR934X_PLL_DDR_DIT_FRAC_STEP_SHIFT		20
+#define AR934X_PLL_DDR_DIT_FRAC_STEP_MASK		0x3f
+#define AR934X_PLL_DDR_DIT_UPD_CNT_SHIFT		27
+#define AR934X_PLL_DDR_DIT_UPD_CNT_MASK			0x3f
+#define AR934X_PLL_DDR_DIT_DITHER_EN			BIT(31)
+
+#define AR934X_PLL_CPU_DIT_FRAC_MAX_SHIFT		0
+#define AR934X_PLL_CPU_DIT_FRAC_MAX_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_FRAC_MIN_SHIFT		6
+#define AR934X_PLL_CPU_DIT_FRAC_MIN_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_FRAC_STEP_SHIFT		12
+#define AR934X_PLL_CPU_DIT_FRAC_STEP_MASK		0x3f
+#define AR934X_PLL_CPU_DIT_UPD_CNT_SHIFT		18
+#define AR934X_PLL_CPU_DIT_UPD_CNT_MASK			0x3f
+#define AR934X_PLL_CPU_DIT_DITHER_EN			BIT(31)
+
+#define QCA953X_PLL_CPU_CONFIG_REG			0x00
+#define QCA953X_PLL_DDR_CONFIG_REG			0x04
+#define QCA953X_PLL_CLK_CTRL_REG			0x08
+#define QCA953X_PLL_SWITCH_CLOCK_CONTROL_REG		0x24
+#define QCA953X_PLL_ETH_XMII_CONTROL_REG		0x2c
+#define QCA953X_PLL_DDR_DIT_FRAC_REG			0x44
+#define QCA953X_PLL_CPU_DIT_FRAC_REG			0x48
+
+#define QCA953X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define QCA953X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define QCA953X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define QCA953X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA953X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA953X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define QCA953X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define QCA953X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define QCA953X_PLL_DDR_CONFIG_NINT_MASK		0x3f
+#define QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA953X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA953X_PLL_CONFIG_PWD		BIT(30)
+
+#define QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define QCA953X_PLL_CPU_DIT_FRAC_MAX_SHIFT		0
+#define QCA953X_PLL_CPU_DIT_FRAC_MAX_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_FRAC_MIN_SHIFT		6
+#define QCA953X_PLL_CPU_DIT_FRAC_MIN_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_FRAC_STEP_SHIFT		12
+#define QCA953X_PLL_CPU_DIT_FRAC_STEP_MASK		0x3f
+#define QCA953X_PLL_CPU_DIT_UPD_CNT_SHIFT		18
+#define QCA953X_PLL_CPU_DIT_UPD_CNT_MASK		0x3f
+
+#define QCA953X_PLL_DDR_DIT_FRAC_MAX_SHIFT		0
+#define QCA953X_PLL_DDR_DIT_FRAC_MAX_MASK		0x3ff
+#define QCA953X_PLL_DDR_DIT_FRAC_MIN_SHIFT		9
+#define QCA953X_PLL_DDR_DIT_FRAC_MIN_MASK		0x3ff
+#define QCA953X_PLL_DDR_DIT_FRAC_STEP_SHIFT		20
+#define QCA953X_PLL_DDR_DIT_FRAC_STEP_MASK		0x3f
+#define QCA953X_PLL_DDR_DIT_UPD_CNT_SHIFT		27
+#define QCA953X_PLL_DDR_DIT_UPD_CNT_MASK		0x3f
+
+#define QCA953X_PLL_DIT_FRAC_EN				BIT(31)
+
+#define QCA955X_PLL_CPU_CONFIG_REG			0x00
+#define QCA955X_PLL_DDR_CONFIG_REG			0x04
+#define QCA955X_PLL_CLK_CTRL_REG			0x08
+#define QCA955X_PLL_ETH_XMII_CONTROL_REG		0x28
+#define QCA955X_PLL_ETH_SGMII_CONTROL_REG		0x48
+
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_SHIFT		0
+#define QCA955X_PLL_CPU_CONFIG_NFRAC_MASK		0x3f
+#define QCA955X_PLL_CPU_CONFIG_NINT_SHIFT		6
+#define QCA955X_PLL_CPU_CONFIG_NINT_MASK		0x3f
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA955X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA955X_PLL_CPU_CONFIG_OUTDIV_MASK		0x3
+
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_SHIFT		0
+#define QCA955X_PLL_DDR_CONFIG_NFRAC_MASK		0x3ff
+#define QCA955X_PLL_DDR_CONFIG_NINT_SHIFT		10
+#define QCA955X_PLL_DDR_CONFIG_NINT_MASK		0x3f
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA955X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA955X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA955X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA955X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA955X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA955X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA955X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA955X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA955X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL		BIT(20)
+#define QCA955X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL		BIT(21)
+#define QCA955X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+#define QCA956X_PLL_CPU_CONFIG_REG			0x00
+#define QCA956X_PLL_CPU_CONFIG1_REG			0x04
+#define QCA956X_PLL_DDR_CONFIG_REG			0x08
+#define QCA956X_PLL_DDR_CONFIG1_REG			0x0c
+#define QCA956X_PLL_CLK_CTRL_REG			0x10
+
+#define QCA956X_PLL_CPU_CONFIG_REFDIV_SHIFT		12
+#define QCA956X_PLL_CPU_CONFIG_REFDIV_MASK		0x1f
+#define QCA956X_PLL_CPU_CONFIG_OUTDIV_SHIFT		19
+#define QCA956X_PLL_CPU_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_SHIFT		0
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_L_MASK		0x1f
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_SHIFT		5
+#define QCA956X_PLL_CPU_CONFIG1_NFRAC_H_MASK		0x3fff
+#define QCA956X_PLL_CPU_CONFIG1_NINT_SHIFT		18
+#define QCA956X_PLL_CPU_CONFIG1_NINT_MASK		0x1ff
+
+#define QCA956X_PLL_DDR_CONFIG_REFDIV_SHIFT		16
+#define QCA956X_PLL_DDR_CONFIG_REFDIV_MASK		0x1f
+#define QCA956X_PLL_DDR_CONFIG_OUTDIV_SHIFT		23
+#define QCA956X_PLL_DDR_CONFIG_OUTDIV_MASK		0x7
+
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_SHIFT		0
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_L_MASK		0x1f
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_SHIFT		5
+#define QCA956X_PLL_DDR_CONFIG1_NFRAC_H_MASK		0x3fff
+#define QCA956X_PLL_DDR_CONFIG1_NINT_SHIFT		18
+#define QCA956X_PLL_DDR_CONFIG1_NINT_MASK		0x1ff
+
+#define QCA956X_PLL_CLK_CTRL_CPU_PLL_BYPASS		BIT(2)
+#define QCA956X_PLL_CLK_CTRL_DDR_PLL_BYPASS		BIT(3)
+#define QCA956X_PLL_CLK_CTRL_AHB_PLL_BYPASS		BIT(4)
+#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT		5
+#define QCA956X_PLL_CLK_CTRL_CPU_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT		10
+#define QCA956X_PLL_CLK_CTRL_DDR_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT		15
+#define QCA956X_PLL_CLK_CTRL_AHB_POST_DIV_MASK		0x1f
+#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_DDRPLL	BIT(20)
+#define QCA956X_PLL_CLK_CTRL_CPU_DDRCLK_FROM_CPUPLL	BIT(21)
+#define QCA956X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL		BIT(24)
+
+/*
+ * USB_CONFIG block
+ */
+#define AR71XX_USB_CTRL_REG_FLADJ			0x00
+#define AR71XX_USB_CTRL_REG_CONFIG			0x04
+
+/*
+ * RESET block
+ */
+#define AR71XX_RESET_REG_TIMER				0x00
+#define AR71XX_RESET_REG_TIMER_RELOAD			0x04
+#define AR71XX_RESET_REG_WDOG_CTRL			0x08
+#define AR71XX_RESET_REG_WDOG				0x0c
+#define AR71XX_RESET_REG_MISC_INT_STATUS		0x10
+#define AR71XX_RESET_REG_MISC_INT_ENABLE		0x14
+#define AR71XX_RESET_REG_PCI_INT_STATUS			0x18
+#define AR71XX_RESET_REG_PCI_INT_ENABLE			0x1c
+#define AR71XX_RESET_REG_GLOBAL_INT_STATUS		0x20
+#define AR71XX_RESET_REG_RESET_MODULE			0x24
+#define AR71XX_RESET_REG_PERFC_CTRL			0x2c
+#define AR71XX_RESET_REG_PERFC0				0x30
+#define AR71XX_RESET_REG_PERFC1				0x34
+#define AR71XX_RESET_REG_REV_ID				0x90
+
+#define AR913X_RESET_REG_GLOBAL_INT_STATUS		0x18
+#define AR913X_RESET_REG_RESET_MODULE			0x1c
+#define AR913X_RESET_REG_PERF_CTRL			0x20
+#define AR913X_RESET_REG_PERFC0				0x24
+#define AR913X_RESET_REG_PERFC1				0x28
+
+#define AR724X_RESET_REG_RESET_MODULE			0x1c
+
+#define AR933X_RESET_REG_RESET_MODULE			0x1c
+#define AR933X_RESET_REG_BOOTSTRAP			0xac
+
+#define AR934X_RESET_REG_RESET_MODULE			0x1c
+#define AR934X_RESET_REG_BOOTSTRAP			0xb0
+#define AR934X_RESET_REG_PCIE_WMAC_INT_STATUS		0xac
+
+#define QCA953X_RESET_REG_RESET_MODULE			0x1c
+#define QCA953X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA953X_RESET_REG_PCIE_WMAC_INT_STATUS		0xac
+
+#define QCA955X_RESET_REG_RESET_MODULE			0x1c
+#define QCA955X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA955X_RESET_REG_EXT_INT_STATUS		0xac
+
+#define QCA956X_RESET_REG_RESET_MODULE			0x1c
+#define QCA956X_RESET_REG_BOOTSTRAP			0xb0
+#define QCA956X_RESET_REG_EXT_INT_STATUS		0xac
+
+#define MISC_INT_MIPS_SI_TIMERINT_MASK			BIT(28)
+#define MISC_INT_ETHSW					BIT(12)
+#define MISC_INT_TIMER4					BIT(10)
+#define MISC_INT_TIMER3					BIT(9)
+#define MISC_INT_TIMER2					BIT(8)
+#define MISC_INT_DMA					BIT(7)
+#define MISC_INT_OHCI					BIT(6)
+#define MISC_INT_PERFC					BIT(5)
+#define MISC_INT_WDOG					BIT(4)
+#define MISC_INT_UART					BIT(3)
+#define MISC_INT_GPIO					BIT(2)
+#define MISC_INT_ERROR					BIT(1)
+#define MISC_INT_TIMER					BIT(0)
+
+#define AR71XX_RESET_EXTERNAL				BIT(28)
+#define AR71XX_RESET_FULL_CHIP				BIT(24)
+#define AR71XX_RESET_CPU_NMI				BIT(21)
+#define AR71XX_RESET_CPU_COLD				BIT(20)
+#define AR71XX_RESET_DMA				BIT(19)
+#define AR71XX_RESET_SLIC				BIT(18)
+#define AR71XX_RESET_STEREO				BIT(17)
+#define AR71XX_RESET_DDR				BIT(16)
+#define AR71XX_RESET_GE1_MAC				BIT(13)
+#define AR71XX_RESET_GE1_PHY				BIT(12)
+#define AR71XX_RESET_USBSUS_OVERRIDE			BIT(10)
+#define AR71XX_RESET_GE0_MAC				BIT(9)
+#define AR71XX_RESET_GE0_PHY				BIT(8)
+#define AR71XX_RESET_USB_OHCI_DLL			BIT(6)
+#define AR71XX_RESET_USB_HOST				BIT(5)
+#define AR71XX_RESET_USB_PHY				BIT(4)
+#define AR71XX_RESET_PCI_BUS				BIT(1)
+#define AR71XX_RESET_PCI_CORE				BIT(0)
+
+#define AR7240_RESET_USB_HOST				BIT(5)
+#define AR7240_RESET_OHCI_DLL				BIT(3)
+
+#define AR724X_RESET_GE1_MDIO				BIT(23)
+#define AR724X_RESET_GE0_MDIO				BIT(22)
+#define AR724X_RESET_PCIE_PHY_SERIAL			BIT(10)
+#define AR724X_RESET_PCIE_PHY				BIT(7)
+#define AR724X_RESET_PCIE				BIT(6)
+#define AR724X_RESET_USB_HOST				BIT(5)
+#define AR724X_RESET_USB_PHY				BIT(4)
+#define AR724X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define AR913X_RESET_AMBA2WMAC				BIT(22)
+#define AR913X_RESET_USBSUS_OVERRIDE			BIT(10)
+#define AR913X_RESET_USB_HOST				BIT(5)
+#define AR913X_RESET_USB_PHY				BIT(4)
+
+#define AR933X_RESET_GE1_MDIO				BIT(23)
+#define AR933X_RESET_GE0_MDIO				BIT(22)
+#define AR933X_RESET_GE1_MAC				BIT(13)
+#define AR933X_RESET_WMAC				BIT(11)
+#define AR933X_RESET_GE0_MAC				BIT(9)
+#define AR933X_RESET_ETH_SWITCH				BIT(8)
+#define AR933X_RESET_USB_HOST				BIT(5)
+#define AR933X_RESET_USB_PHY				BIT(4)
+#define AR933X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define AR934X_RESET_HOST				BIT(31)
+#define AR934X_RESET_SLIC				BIT(30)
+#define AR934X_RESET_HDMA				BIT(29)
+#define AR934X_RESET_EXTERNAL				BIT(28)
+#define AR934X_RESET_RTC				BIT(27)
+#define AR934X_RESET_PCIE_EP_INT			BIT(26)
+#define AR934X_RESET_CHKSUM_ACC				BIT(25)
+#define AR934X_RESET_FULL_CHIP				BIT(24)
+#define AR934X_RESET_GE1_MDIO				BIT(23)
+#define AR934X_RESET_GE0_MDIO				BIT(22)
+#define AR934X_RESET_CPU_NMI				BIT(21)
+#define AR934X_RESET_CPU_COLD				BIT(20)
+#define AR934X_RESET_HOST_RESET_INT			BIT(19)
+#define AR934X_RESET_PCIE_EP				BIT(18)
+#define AR934X_RESET_UART1				BIT(17)
+#define AR934X_RESET_DDR				BIT(16)
+#define AR934X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define AR934X_RESET_NANDF				BIT(14)
+#define AR934X_RESET_GE1_MAC				BIT(13)
+#define AR934X_RESET_ETH_SWITCH_ANALOG			BIT(12)
+#define AR934X_RESET_USB_PHY_ANALOG			BIT(11)
+#define AR934X_RESET_HOST_DMA_INT			BIT(10)
+#define AR934X_RESET_GE0_MAC				BIT(9)
+#define AR934X_RESET_ETH_SWITCH				BIT(8)
+#define AR934X_RESET_PCIE_PHY				BIT(7)
+#define AR934X_RESET_PCIE				BIT(6)
+#define AR934X_RESET_USB_HOST				BIT(5)
+#define AR934X_RESET_USB_PHY				BIT(4)
+#define AR934X_RESET_USBSUS_OVERRIDE			BIT(3)
+#define AR934X_RESET_LUT				BIT(2)
+#define AR934X_RESET_MBOX				BIT(1)
+#define AR934X_RESET_I2S				BIT(0)
+
+#define QCA953X_RESET_USB_EXT_PWR			BIT(29)
+#define QCA953X_RESET_EXTERNAL				BIT(28)
+#define QCA953X_RESET_RTC				BIT(27)
+#define QCA953X_RESET_FULL_CHIP				BIT(24)
+#define QCA953X_RESET_GE1_MDIO				BIT(23)
+#define QCA953X_RESET_GE0_MDIO				BIT(22)
+#define QCA953X_RESET_CPU_NMI				BIT(21)
+#define QCA953X_RESET_CPU_COLD				BIT(20)
+#define QCA953X_RESET_DDR				BIT(16)
+#define QCA953X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define QCA953X_RESET_GE1_MAC				BIT(13)
+#define QCA953X_RESET_ETH_SWITCH_ANALOG			BIT(12)
+#define QCA953X_RESET_USB_PHY_ANALOG			BIT(11)
+#define QCA953X_RESET_GE0_MAC				BIT(9)
+#define QCA953X_RESET_ETH_SWITCH			BIT(8)
+#define QCA953X_RESET_PCIE_PHY				BIT(7)
+#define QCA953X_RESET_PCIE				BIT(6)
+#define QCA953X_RESET_USB_HOST				BIT(5)
+#define QCA953X_RESET_USB_PHY				BIT(4)
+#define QCA953X_RESET_USBSUS_OVERRIDE			BIT(3)
+
+#define QCA955X_RESET_HOST				BIT(31)
+#define QCA955X_RESET_SLIC				BIT(30)
+#define QCA955X_RESET_HDMA				BIT(29)
+#define QCA955X_RESET_EXTERNAL				BIT(28)
+#define QCA955X_RESET_RTC				BIT(27)
+#define QCA955X_RESET_PCIE_EP_INT			BIT(26)
+#define QCA955X_RESET_CHKSUM_ACC			BIT(25)
+#define QCA955X_RESET_FULL_CHIP				BIT(24)
+#define QCA955X_RESET_GE1_MDIO				BIT(23)
+#define QCA955X_RESET_GE0_MDIO				BIT(22)
+#define QCA955X_RESET_CPU_NMI				BIT(21)
+#define QCA955X_RESET_CPU_COLD				BIT(20)
+#define QCA955X_RESET_HOST_RESET_INT			BIT(19)
+#define QCA955X_RESET_PCIE_EP				BIT(18)
+#define QCA955X_RESET_UART1				BIT(17)
+#define QCA955X_RESET_DDR				BIT(16)
+#define QCA955X_RESET_USB_PHY_PLL_PWD_EXT		BIT(15)
+#define QCA955X_RESET_NANDF				BIT(14)
+#define QCA955X_RESET_GE1_MAC				BIT(13)
+#define QCA955X_RESET_SGMII_ANALOG			BIT(12)
+#define QCA955X_RESET_USB_PHY_ANALOG			BIT(11)
+#define QCA955X_RESET_HOST_DMA_INT			BIT(10)
+#define QCA955X_RESET_GE0_MAC				BIT(9)
+#define QCA955X_RESET_SGMII				BIT(8)
+#define QCA955X_RESET_PCIE_PHY				BIT(7)
+#define QCA955X_RESET_PCIE				BIT(6)
+#define QCA955X_RESET_USB_HOST				BIT(5)
+#define QCA955X_RESET_USB_PHY				BIT(4)
+#define QCA955X_RESET_USBSUS_OVERRIDE			BIT(3)
+#define QCA955X_RESET_LUT				BIT(2)
+#define QCA955X_RESET_MBOX				BIT(1)
+#define QCA955X_RESET_I2S				BIT(0)
+
+#define AR933X_BOOTSTRAP_MDIO_GPIO_EN			BIT(18)
+#define AR933X_BOOTSTRAP_DDR2				BIT(13)
+#define AR933X_BOOTSTRAP_EEPBUSY			BIT(4)
+#define AR933X_BOOTSTRAP_REF_CLK_40			BIT(0)
+
+#define AR934X_BOOTSTRAP_SW_OPTION8			BIT(23)
+#define AR934X_BOOTSTRAP_SW_OPTION7			BIT(22)
+#define AR934X_BOOTSTRAP_SW_OPTION6			BIT(21)
+#define AR934X_BOOTSTRAP_SW_OPTION5			BIT(20)
+#define AR934X_BOOTSTRAP_SW_OPTION4			BIT(19)
+#define AR934X_BOOTSTRAP_SW_OPTION3			BIT(18)
+#define AR934X_BOOTSTRAP_SW_OPTION2			BIT(17)
+#define AR934X_BOOTSTRAP_SW_OPTION1			BIT(16)
+#define AR934X_BOOTSTRAP_USB_MODE_DEVICE		BIT(7)
+#define AR934X_BOOTSTRAP_PCIE_RC			BIT(6)
+#define AR934X_BOOTSTRAP_EJTAG_MODE			BIT(5)
+#define AR934X_BOOTSTRAP_REF_CLK_40			BIT(4)
+#define AR934X_BOOTSTRAP_BOOT_FROM_SPI			BIT(2)
+#define AR934X_BOOTSTRAP_SDRAM_DISABLED			BIT(1)
+#define AR934X_BOOTSTRAP_DDR1				BIT(0)
+
+#define QCA953X_BOOTSTRAP_SW_OPTION2			BIT(12)
+#define QCA953X_BOOTSTRAP_SW_OPTION1			BIT(11)
+#define QCA953X_BOOTSTRAP_EJTAG_MODE			BIT(5)
+#define QCA953X_BOOTSTRAP_REF_CLK_40			BIT(4)
+#define QCA953X_BOOTSTRAP_SDRAM_DISABLED		BIT(1)
+#define QCA953X_BOOTSTRAP_DDR1				BIT(0)
+
+#define QCA955X_BOOTSTRAP_REF_CLK_40			BIT(4)
+
+#define QCA956X_BOOTSTRAP_REF_CLK_40			BIT(2)
+
+#define AR934X_PCIE_WMAC_INT_WMAC_MISC			BIT(0)
+#define AR934X_PCIE_WMAC_INT_WMAC_TX			BIT(1)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXLP			BIT(2)
+#define AR934X_PCIE_WMAC_INT_WMAC_RXHP			BIT(3)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC			BIT(4)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC0			BIT(5)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC1			BIT(6)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC2			BIT(7)
+#define AR934X_PCIE_WMAC_INT_PCIE_RC3			BIT(8)
+#define AR934X_PCIE_WMAC_INT_WMAC_ALL \
+	(AR934X_PCIE_WMAC_INT_WMAC_MISC | AR934X_PCIE_WMAC_INT_WMAC_TX | \
+	 AR934X_PCIE_WMAC_INT_WMAC_RXLP | AR934X_PCIE_WMAC_INT_WMAC_RXHP)
+
+#define AR934X_PCIE_WMAC_INT_PCIE_ALL \
+	(AR934X_PCIE_WMAC_INT_PCIE_RC | AR934X_PCIE_WMAC_INT_PCIE_RC0 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC1 | AR934X_PCIE_WMAC_INT_PCIE_RC2 | \
+	 AR934X_PCIE_WMAC_INT_PCIE_RC3)
+
+#define QCA953X_PCIE_WMAC_INT_WMAC_MISC			BIT(0)
+#define QCA953X_PCIE_WMAC_INT_WMAC_TX			BIT(1)
+#define QCA953X_PCIE_WMAC_INT_WMAC_RXLP			BIT(2)
+#define QCA953X_PCIE_WMAC_INT_WMAC_RXHP			BIT(3)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC			BIT(4)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC0			BIT(5)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC1			BIT(6)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC2			BIT(7)
+#define QCA953X_PCIE_WMAC_INT_PCIE_RC3			BIT(8)
+#define QCA953X_PCIE_WMAC_INT_WMAC_ALL \
+	(QCA953X_PCIE_WMAC_INT_WMAC_MISC | QCA953X_PCIE_WMAC_INT_WMAC_TX | \
+	 QCA953X_PCIE_WMAC_INT_WMAC_RXLP | QCA953X_PCIE_WMAC_INT_WMAC_RXHP)
+
+#define QCA953X_PCIE_WMAC_INT_PCIE_ALL \
+	(QCA953X_PCIE_WMAC_INT_PCIE_RC | QCA953X_PCIE_WMAC_INT_PCIE_RC0 | \
+	 QCA953X_PCIE_WMAC_INT_PCIE_RC1 | QCA953X_PCIE_WMAC_INT_PCIE_RC2 | \
+	 QCA953X_PCIE_WMAC_INT_PCIE_RC3)
+
+#define QCA955X_EXT_INT_WMAC_MISC			BIT(0)
+#define QCA955X_EXT_INT_WMAC_TX				BIT(1)
+#define QCA955X_EXT_INT_WMAC_RXLP			BIT(2)
+#define QCA955X_EXT_INT_WMAC_RXHP			BIT(3)
+#define QCA955X_EXT_INT_PCIE_RC1			BIT(4)
+#define QCA955X_EXT_INT_PCIE_RC1_INT0			BIT(5)
+#define QCA955X_EXT_INT_PCIE_RC1_INT1			BIT(6)
+#define QCA955X_EXT_INT_PCIE_RC1_INT2			BIT(7)
+#define QCA955X_EXT_INT_PCIE_RC1_INT3			BIT(8)
+#define QCA955X_EXT_INT_PCIE_RC2			BIT(12)
+#define QCA955X_EXT_INT_PCIE_RC2_INT0			BIT(13)
+#define QCA955X_EXT_INT_PCIE_RC2_INT1			BIT(14)
+#define QCA955X_EXT_INT_PCIE_RC2_INT2			BIT(15)
+#define QCA955X_EXT_INT_PCIE_RC2_INT3			BIT(16)
+#define QCA955X_EXT_INT_USB1				BIT(24)
+#define QCA955X_EXT_INT_USB2				BIT(28)
+
+#define QCA955X_EXT_INT_WMAC_ALL \
+	(QCA955X_EXT_INT_WMAC_MISC | QCA955X_EXT_INT_WMAC_TX | \
+	 QCA955X_EXT_INT_WMAC_RXLP | QCA955X_EXT_INT_WMAC_RXHP)
+
+#define QCA955X_EXT_INT_PCIE_RC1_ALL \
+	(QCA955X_EXT_INT_PCIE_RC1 | QCA955X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT1 | QCA955X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA955X_EXT_INT_PCIE_RC2_ALL \
+	(QCA955X_EXT_INT_PCIE_RC2 | QCA955X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT1 | QCA955X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA955X_EXT_INT_PCIE_RC2_INT3)
+
+#define QCA956X_EXT_INT_WMAC_MISC			BIT(0)
+#define QCA956X_EXT_INT_WMAC_TX				BIT(1)
+#define QCA956X_EXT_INT_WMAC_RXLP			BIT(2)
+#define QCA956X_EXT_INT_WMAC_RXHP			BIT(3)
+#define QCA956X_EXT_INT_PCIE_RC1			BIT(4)
+#define QCA956X_EXT_INT_PCIE_RC1_INT0			BIT(5)
+#define QCA956X_EXT_INT_PCIE_RC1_INT1			BIT(6)
+#define QCA956X_EXT_INT_PCIE_RC1_INT2			BIT(7)
+#define QCA956X_EXT_INT_PCIE_RC1_INT3			BIT(8)
+#define QCA956X_EXT_INT_PCIE_RC2			BIT(12)
+#define QCA956X_EXT_INT_PCIE_RC2_INT0			BIT(13)
+#define QCA956X_EXT_INT_PCIE_RC2_INT1			BIT(14)
+#define QCA956X_EXT_INT_PCIE_RC2_INT2			BIT(15)
+#define QCA956X_EXT_INT_PCIE_RC2_INT3			BIT(16)
+#define QCA956X_EXT_INT_USB1				BIT(24)
+#define QCA956X_EXT_INT_USB2				BIT(28)
+
+#define QCA956X_EXT_INT_WMAC_ALL \
+	(QCA956X_EXT_INT_WMAC_MISC | QCA956X_EXT_INT_WMAC_TX | \
+	 QCA956X_EXT_INT_WMAC_RXLP | QCA956X_EXT_INT_WMAC_RXHP)
+
+#define QCA956X_EXT_INT_PCIE_RC1_ALL \
+	(QCA956X_EXT_INT_PCIE_RC1 | QCA956X_EXT_INT_PCIE_RC1_INT0 | \
+	 QCA956X_EXT_INT_PCIE_RC1_INT1 | QCA956X_EXT_INT_PCIE_RC1_INT2 | \
+	 QCA956X_EXT_INT_PCIE_RC1_INT3)
+
+#define QCA956X_EXT_INT_PCIE_RC2_ALL \
+	(QCA956X_EXT_INT_PCIE_RC2 | QCA956X_EXT_INT_PCIE_RC2_INT0 | \
+	 QCA956X_EXT_INT_PCIE_RC2_INT1 | QCA956X_EXT_INT_PCIE_RC2_INT2 | \
+	 QCA956X_EXT_INT_PCIE_RC2_INT3)
+
+#define REV_ID_MAJOR_MASK				0xfff0
+#define REV_ID_MAJOR_AR71XX				0x00a0
+#define REV_ID_MAJOR_AR913X				0x00b0
+#define REV_ID_MAJOR_AR7240				0x00c0
+#define REV_ID_MAJOR_AR7241				0x0100
+#define REV_ID_MAJOR_AR7242				0x1100
+#define REV_ID_MAJOR_AR9330				0x0110
+#define REV_ID_MAJOR_AR9331				0x1110
+#define REV_ID_MAJOR_AR9341				0x0120
+#define REV_ID_MAJOR_AR9342				0x1120
+#define REV_ID_MAJOR_AR9344				0x2120
+#define REV_ID_MAJOR_QCA9533				0x0140
+#define REV_ID_MAJOR_QCA9533_V2				0x0160
+#define REV_ID_MAJOR_QCA9556				0x0130
+#define REV_ID_MAJOR_QCA9558				0x1130
+#define REV_ID_MAJOR_TP9343				0x0150
+#define REV_ID_MAJOR_QCA9561				0x1150
+
+#define AR71XX_REV_ID_MINOR_MASK			0x3
+#define AR71XX_REV_ID_MINOR_AR7130			0x0
+#define AR71XX_REV_ID_MINOR_AR7141			0x1
+#define AR71XX_REV_ID_MINOR_AR7161			0x2
+#define AR913X_REV_ID_MINOR_AR9130			0x0
+#define AR913X_REV_ID_MINOR_AR9132			0x1
+
+#define AR71XX_REV_ID_REVISION_MASK			0x3
+#define AR71XX_REV_ID_REVISION_SHIFT			2
+#define AR71XX_REV_ID_REVISION2_MASK			0xf
+
+/*
+ * RTC block
+ */
+#define AR933X_RTC_REG_RESET				0x40
+#define AR933X_RTC_REG_STATUS				0x44
+#define AR933X_RTC_REG_DERIVED				0x48
+#define AR933X_RTC_REG_FORCE_WAKE			0x4c
+#define AR933X_RTC_REG_INT_CAUSE			0x50
+#define AR933X_RTC_REG_CAUSE_CLR			0x50
+#define AR933X_RTC_REG_INT_ENABLE			0x54
+#define AR933X_RTC_REG_INT_MASKE			0x58
+
+#define QCA953X_RTC_REG_SYNC_RESET			0x40
+#define QCA953X_RTC_REG_SYNC_STATUS			0x44
+
+/*
+ * SPI block
+ */
+#define AR71XX_SPI_REG_FS				0x00
+#define AR71XX_SPI_REG_CTRL				0x04
+#define AR71XX_SPI_REG_IOC				0x08
+#define AR71XX_SPI_REG_RDS				0x0c
+
+#define AR71XX_SPI_FS_GPIO				BIT(0)
+
+#define AR71XX_SPI_CTRL_RD				BIT(6)
+#define AR71XX_SPI_CTRL_DIV_MASK			0x3f
+
+#define AR71XX_SPI_IOC_DO				BIT(0)
+#define AR71XX_SPI_IOC_CLK				BIT(8)
+#define AR71XX_SPI_IOC_CS(n)				BIT(16 + (n))
+#define AR71XX_SPI_IOC_CS0				AR71XX_SPI_IOC_CS(0)
+#define AR71XX_SPI_IOC_CS1				AR71XX_SPI_IOC_CS(1)
+#define AR71XX_SPI_IOC_CS2				AR71XX_SPI_IOC_CS(2)
+#define AR71XX_SPI_IOC_CS_ALL \
+	(AR71XX_SPI_IOC_CS0 | AR71XX_SPI_IOC_CS1 | AR71XX_SPI_IOC_CS2)
+
+/*
+ * GPIO block
+ */
+#define AR71XX_GPIO_REG_OE				0x00
+#define AR71XX_GPIO_REG_IN				0x04
+#define AR71XX_GPIO_REG_OUT				0x08
+#define AR71XX_GPIO_REG_SET				0x0c
+#define AR71XX_GPIO_REG_CLEAR				0x10
+#define AR71XX_GPIO_REG_INT_MODE			0x14
+#define AR71XX_GPIO_REG_INT_TYPE			0x18
+#define AR71XX_GPIO_REG_INT_POLARITY			0x1c
+#define AR71XX_GPIO_REG_INT_PENDING			0x20
+#define AR71XX_GPIO_REG_INT_ENABLE			0x24
+#define AR71XX_GPIO_REG_FUNC				0x28
+#define AR933X_GPIO_REG_FUNC				0x30
+
+#define AR934X_GPIO_REG_OUT_FUNC0			0x2c
+#define AR934X_GPIO_REG_OUT_FUNC1			0x30
+#define AR934X_GPIO_REG_OUT_FUNC2			0x34
+#define AR934X_GPIO_REG_OUT_FUNC3			0x38
+#define AR934X_GPIO_REG_OUT_FUNC4			0x3c
+#define AR934X_GPIO_REG_OUT_FUNC5			0x40
+#define AR934X_GPIO_REG_FUNC				0x6c
+
+#define QCA953X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA953X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA953X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA953X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA953X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA953X_GPIO_REG_IN_ENABLE0			0x44
+#define QCA953X_GPIO_REG_FUNC				0x6c
+
+#define QCA955X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA955X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA955X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA955X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA955X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA955X_GPIO_REG_OUT_FUNC5			0x40
+#define QCA955X_GPIO_REG_FUNC				0x6c
+
+#define QCA956X_GPIO_REG_OUT_FUNC0			0x2c
+#define QCA956X_GPIO_REG_OUT_FUNC1			0x30
+#define QCA956X_GPIO_REG_OUT_FUNC2			0x34
+#define QCA956X_GPIO_REG_OUT_FUNC3			0x38
+#define QCA956X_GPIO_REG_OUT_FUNC4			0x3c
+#define QCA956X_GPIO_REG_OUT_FUNC5			0x40
+#define QCA956X_GPIO_REG_IN_ENABLE0			0x44
+#define QCA956X_GPIO_REG_IN_ENABLE3			0x50
+#define QCA956X_GPIO_REG_FUNC				0x6c
+
+#define AR71XX_GPIO_FUNC_STEREO_EN			BIT(17)
+#define AR71XX_GPIO_FUNC_SLIC_EN			BIT(16)
+#define AR71XX_GPIO_FUNC_SPI_CS2_EN			BIT(13)
+#define AR71XX_GPIO_FUNC_SPI_CS1_EN			BIT(12)
+#define AR71XX_GPIO_FUNC_UART_EN			BIT(8)
+#define AR71XX_GPIO_FUNC_USB_OC_EN			BIT(4)
+#define AR71XX_GPIO_FUNC_USB_CLK_EN			BIT(0)
+
+#define AR724X_GPIO_FUNC_GE0_MII_CLK_EN			BIT(19)
+#define AR724X_GPIO_FUNC_SPI_EN				BIT(18)
+#define AR724X_GPIO_FUNC_SPI_CS_EN2			BIT(14)
+#define AR724X_GPIO_FUNC_SPI_CS_EN1			BIT(13)
+#define AR724X_GPIO_FUNC_CLK_OBS5_EN			BIT(12)
+#define AR724X_GPIO_FUNC_CLK_OBS4_EN			BIT(11)
+#define AR724X_GPIO_FUNC_CLK_OBS3_EN			BIT(10)
+#define AR724X_GPIO_FUNC_CLK_OBS2_EN			BIT(9)
+#define AR724X_GPIO_FUNC_CLK_OBS1_EN			BIT(8)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED4_EN		BIT(7)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED3_EN		BIT(6)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED2_EN		BIT(5)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED1_EN		BIT(4)
+#define AR724X_GPIO_FUNC_ETH_SWITCH_LED0_EN		BIT(3)
+#define AR724X_GPIO_FUNC_UART_RTS_CTS_EN		BIT(2)
+#define AR724X_GPIO_FUNC_UART_EN			BIT(1)
+#define AR724X_GPIO_FUNC_JTAG_DISABLE			BIT(0)
+
+#define AR913X_GPIO_FUNC_WMAC_LED_EN			BIT(22)
+#define AR913X_GPIO_FUNC_EXP_PORT_CS_EN			BIT(21)
+#define AR913X_GPIO_FUNC_I2S_REFCLKEN			BIT(20)
+#define AR913X_GPIO_FUNC_I2S_MCKEN			BIT(19)
+#define AR913X_GPIO_FUNC_I2S1_EN			BIT(18)
+#define AR913X_GPIO_FUNC_I2S0_EN			BIT(17)
+#define AR913X_GPIO_FUNC_SLIC_EN			BIT(16)
+#define AR913X_GPIO_FUNC_UART_RTSCTS_EN			BIT(9)
+#define AR913X_GPIO_FUNC_UART_EN			BIT(8)
+#define AR913X_GPIO_FUNC_USB_CLK_EN			BIT(4)
+
+#define AR933X_GPIO(x)					BIT(x)
+#define AR933X_GPIO_FUNC_SPDIF2TCK			BIT(31)
+#define AR933X_GPIO_FUNC_SPDIF_EN			BIT(30)
+#define AR933X_GPIO_FUNC_I2SO_22_18_EN			BIT(29)
+#define AR933X_GPIO_FUNC_I2S_MCK_EN			BIT(27)
+#define AR933X_GPIO_FUNC_I2SO_EN			BIT(26)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_DUPL		BIT(25)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_COLL		BIT(24)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED_ACT		BIT(23)
+#define AR933X_GPIO_FUNC_SPI_EN				BIT(18)
+#define AR933X_GPIO_FUNC_RES_TRUE			BIT(15)
+#define AR933X_GPIO_FUNC_SPI_CS_EN2			BIT(14)
+#define AR933X_GPIO_FUNC_SPI_CS_EN1			BIT(13)
+#define AR933X_GPIO_FUNC_XLNA_EN			BIT(12)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED4_EN		BIT(7)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED3_EN		BIT(6)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED2_EN		BIT(5)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED1_EN		BIT(4)
+#define AR933X_GPIO_FUNC_ETH_SWITCH_LED0_EN		BIT(3)
+#define AR933X_GPIO_FUNC_UART_RTS_CTS_EN		BIT(2)
+#define AR933X_GPIO_FUNC_UART_EN			BIT(1)
+#define AR933X_GPIO_FUNC_JTAG_DISABLE			BIT(0)
+
+#define AR934X_GPIO_FUNC_CLK_OBS7_EN			BIT(9)
+#define AR934X_GPIO_FUNC_CLK_OBS6_EN			BIT(8)
+#define AR934X_GPIO_FUNC_CLK_OBS5_EN			BIT(7)
+#define AR934X_GPIO_FUNC_CLK_OBS4_EN			BIT(6)
+#define AR934X_GPIO_FUNC_CLK_OBS3_EN			BIT(5)
+#define AR934X_GPIO_FUNC_CLK_OBS2_EN			BIT(4)
+#define AR934X_GPIO_FUNC_CLK_OBS1_EN			BIT(3)
+#define AR934X_GPIO_FUNC_CLK_OBS0_EN			BIT(2)
+#define AR934X_GPIO_FUNC_JTAG_DISABLE			BIT(1)
+
+#define AR934X_GPIO_OUT_GPIO				0
+#define AR934X_GPIO_OUT_SPI_CS1				7
+#define AR934X_GPIO_OUT_LED_LINK0			41
+#define AR934X_GPIO_OUT_LED_LINK1			42
+#define AR934X_GPIO_OUT_LED_LINK2			43
+#define AR934X_GPIO_OUT_LED_LINK3			44
+#define AR934X_GPIO_OUT_LED_LINK4			45
+#define AR934X_GPIO_OUT_EXT_LNA0			46
+#define AR934X_GPIO_OUT_EXT_LNA1			47
+
+#define QCA953X_GPIO(x)					BIT(x)
+#define QCA953X_GPIO_MUX_MASK(x)			(0xff << (x))
+#define QCA953X_GPIO_OUT_MUX_SPI_CS1			10
+#define QCA953X_GPIO_OUT_MUX_SPI_CS2			11
+#define QCA953X_GPIO_OUT_MUX_SPI_CS0			9
+#define QCA953X_GPIO_OUT_MUX_SPI_CLK			8
+#define QCA953X_GPIO_OUT_MUX_SPI_MOSI			12
+#define QCA953X_GPIO_OUT_MUX_UART0_SOUT			22
+#define QCA953X_GPIO_OUT_MUX_LED_LINK1			41
+#define QCA953X_GPIO_OUT_MUX_LED_LINK2			42
+#define QCA953X_GPIO_OUT_MUX_LED_LINK3			43
+#define QCA953X_GPIO_OUT_MUX_LED_LINK4			44
+#define QCA953X_GPIO_OUT_MUX_LED_LINK5			45
+
+#define QCA953X_GPIO_IN_MUX_UART0_SIN			9
+#define QCA953X_GPIO_IN_MUX_SPI_DATA_IN			8
+
+#define QCA956X_GPIO_OUT_MUX_GE0_MDO			32
+#define QCA956X_GPIO_OUT_MUX_GE0_MDC			33
+
+#define AR71XX_GPIO_COUNT				16
+#define AR7240_GPIO_COUNT				18
+#define AR7241_GPIO_COUNT				20
+#define AR913X_GPIO_COUNT				22
+#define AR933X_GPIO_COUNT				30
+#define AR934X_GPIO_COUNT				23
+#define QCA953X_GPIO_COUNT				18
+#define QCA955X_GPIO_COUNT				24
+#define QCA956X_GPIO_COUNT				23
+
+/*
+ * SRIF block
+ */
+#define AR933X_SRIF_DDR_DPLL1_REG			0x240
+#define AR933X_SRIF_DDR_DPLL2_REG			0x244
+#define AR933X_SRIF_DDR_DPLL3_REG			0x248
+#define AR933X_SRIF_DDR_DPLL4_REG			0x24c
+
+#define AR934X_SRIF_CPU_DPLL1_REG			0x1c0
+#define AR934X_SRIF_CPU_DPLL2_REG			0x1c4
+#define AR934X_SRIF_CPU_DPLL3_REG			0x1c8
+#define AR934X_SRIF_CPU_DPLL4_REG			0x1cc
+
+#define AR934X_SRIF_DDR_DPLL1_REG			0x240
+#define AR934X_SRIF_DDR_DPLL2_REG			0x244
+#define AR934X_SRIF_DDR_DPLL3_REG			0x248
+#define AR934X_SRIF_DDR_DPLL4_REG			0x24c
+
+#define AR934X_SRIF_DPLL1_REFDIV_SHIFT			27
+#define AR934X_SRIF_DPLL1_REFDIV_MASK			0x1f
+#define AR934X_SRIF_DPLL1_NINT_SHIFT			18
+#define AR934X_SRIF_DPLL1_NINT_MASK			0x1ff
+#define AR934X_SRIF_DPLL1_NFRAC_MASK			0x0003ffff
+
+#define AR934X_SRIF_DPLL2_LOCAL_PLL			BIT(30)
+#define AR934X_SRIF_DPLL2_OUTDIV_SHIFT			13
+#define AR934X_SRIF_DPLL2_OUTDIV_MASK			0x7
+
+#define QCA953X_SRIF_BB_DPLL1_REG			0x180
+#define QCA953X_SRIF_BB_DPLL2_REG			0x184
+#define QCA953X_SRIF_BB_DPLL3_REG			0x188
+
+#define QCA953X_SRIF_CPU_DPLL1_REG			0x1c0
+#define QCA953X_SRIF_CPU_DPLL2_REG			0x1c4
+#define QCA953X_SRIF_CPU_DPLL3_REG			0x1c8
+
+#define QCA953X_SRIF_DDR_DPLL1_REG			0x240
+#define QCA953X_SRIF_DDR_DPLL2_REG			0x244
+#define QCA953X_SRIF_DDR_DPLL3_REG			0x248
+
+#define QCA953X_SRIF_PCIE_DPLL1_REG			0xc00
+#define QCA953X_SRIF_PCIE_DPLL2_REG			0xc04
+#define QCA953X_SRIF_PCIE_DPLL3_REG			0xc08
+
+#define QCA953X_SRIF_PMU1_REG				0xc40
+#define QCA953X_SRIF_PMU2_REG				0xc44
+
+#define QCA953X_SRIF_DPLL1_REFDIV_SHIFT			27
+#define QCA953X_SRIF_DPLL1_REFDIV_MASK			0x1f
+
+#define QCA953X_SRIF_DPLL1_NINT_SHIFT			18
+#define QCA953X_SRIF_DPLL1_NINT_MASK			0x1ff
+#define QCA953X_SRIF_DPLL1_NFRAC_MASK			0x0003ffff
+
+#define QCA953X_SRIF_DPLL2_LOCAL_PLL			BIT(30)
+
+#define QCA953X_SRIF_DPLL2_KI_SHIFT			29
+#define QCA953X_SRIF_DPLL2_KI_MASK			0x3
+
+#define QCA953X_SRIF_DPLL2_KD_SHIFT			25
+#define QCA953X_SRIF_DPLL2_KD_MASK			0xf
+
+#define QCA953X_SRIF_DPLL2_PWD				BIT(22)
+
+#define QCA953X_SRIF_DPLL2_OUTDIV_SHIFT			13
+#define QCA953X_SRIF_DPLL2_OUTDIV_MASK			0x7
+
+/*
+ * MII_CTRL block
+ */
+#define AR71XX_MII_REG_MII0_CTRL			0x00
+#define AR71XX_MII_REG_MII1_CTRL			0x04
+
+#define AR71XX_MII_CTRL_IF_MASK				3
+#define AR71XX_MII_CTRL_SPEED_SHIFT			4
+#define AR71XX_MII_CTRL_SPEED_MASK			3
+#define AR71XX_MII_CTRL_SPEED_10			0
+#define AR71XX_MII_CTRL_SPEED_100			1
+#define AR71XX_MII_CTRL_SPEED_1000			2
+
+#define AR71XX_MII0_CTRL_IF_GMII			0
+#define AR71XX_MII0_CTRL_IF_MII				1
+#define AR71XX_MII0_CTRL_IF_RGMII			2
+#define AR71XX_MII0_CTRL_IF_RMII			3
+
+#define AR71XX_MII1_CTRL_IF_RGMII			0
+#define AR71XX_MII1_CTRL_IF_RMII			1
+
+/*
+ * AR933X GMAC interface
+ */
+#define AR933X_GMAC_REG_ETH_CFG				0x00
+
+#define AR933X_ETH_CFG_RGMII_GE0			BIT(0)
+#define AR933X_ETH_CFG_MII_GE0				BIT(1)
+#define AR933X_ETH_CFG_GMII_GE0				BIT(2)
+#define AR933X_ETH_CFG_MII_GE0_MASTER			BIT(3)
+#define AR933X_ETH_CFG_MII_GE0_SLAVE			BIT(4)
+#define AR933X_ETH_CFG_MII_GE0_ERR_EN			BIT(5)
+#define AR933X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define AR933X_ETH_CFG_SW_PHY_ADDR_SWAP			BIT(8)
+#define AR933X_ETH_CFG_RMII_GE0				BIT(9)
+#define AR933X_ETH_CFG_RMII_GE0_SPD_10			0
+#define AR933X_ETH_CFG_RMII_GE0_SPD_100			BIT(10)
+
+/*
+ * AR934X GMAC Interface
+ */
+#define AR934X_GMAC_REG_ETH_CFG				0x00
+
+#define AR934X_ETH_CFG_RGMII_GMAC0			BIT(0)
+#define AR934X_ETH_CFG_MII_GMAC0			BIT(1)
+#define AR934X_ETH_CFG_GMII_GMAC0			BIT(2)
+#define AR934X_ETH_CFG_MII_GMAC0_MASTER			BIT(3)
+#define AR934X_ETH_CFG_MII_GMAC0_SLAVE			BIT(4)
+#define AR934X_ETH_CFG_MII_GMAC0_ERR_EN			BIT(5)
+#define AR934X_ETH_CFG_SW_ONLY_MODE			BIT(6)
+#define AR934X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define AR934X_ETH_CFG_SW_APB_ACCESS			BIT(9)
+#define AR934X_ETH_CFG_RMII_GMAC0			BIT(10)
+#define AR933X_ETH_CFG_MII_CNTL_SPEED			BIT(11)
+#define AR934X_ETH_CFG_RMII_GMAC0_MASTER			BIT(12)
+#define AR933X_ETH_CFG_SW_ACC_MSB_FIRST			BIT(13)
+#define AR934X_ETH_CFG_RXD_DELAY			BIT(14)
+#define AR934X_ETH_CFG_RXD_DELAY_MASK			0x3
+#define AR934X_ETH_CFG_RXD_DELAY_SHIFT			14
+#define AR934X_ETH_CFG_RDV_DELAY			BIT(16)
+#define AR934X_ETH_CFG_RDV_DELAY_MASK			0x3
+#define AR934X_ETH_CFG_RDV_DELAY_SHIFT			16
+
+/*
+ * QCA953X GMAC Interface
+ */
+#define QCA953X_GMAC_REG_ETH_CFG			0x00
+
+#define QCA953X_ETH_CFG_SW_ONLY_MODE			BIT(6)
+#define QCA953X_ETH_CFG_SW_PHY_SWAP			BIT(7)
+#define QCA953X_ETH_CFG_SW_APB_ACCESS			BIT(9)
+#define QCA953X_ETH_CFG_SW_ACC_MSB_FIRST		BIT(13)
+
+/*
+ * QCA955X GMAC Interface
+ */
+
+#define QCA955X_GMAC_REG_ETH_CFG			0x00
+
+#define QCA955X_ETH_CFG_RGMII_EN			BIT(0)
+#define QCA955X_ETH_CFG_GE0_SGMII			BIT(6)
+
+#endif /* __ASM_AR71XX_H */
diff --git a/arch/mips/mach-ath79/include/mach/ath79.h b/arch/mips/mach-ath79/include/mach/ath79.h
new file mode 100644
index 0000000..17af082
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ath79.h
@@ -0,0 +1,149 @@
+/*
+ * Atheros AR71XX/AR724X/AR913X common definitions
+ *
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_ATH79_H
+#define __ASM_MACH_ATH79_H
+
+#include <linux/types.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum ath79_soc_type {
+	ATH79_SOC_UNKNOWN,
+	ATH79_SOC_AR7130,
+	ATH79_SOC_AR7141,
+	ATH79_SOC_AR7161,
+	ATH79_SOC_AR7240,
+	ATH79_SOC_AR7241,
+	ATH79_SOC_AR7242,
+	ATH79_SOC_AR9130,
+	ATH79_SOC_AR9132,
+	ATH79_SOC_AR9330,
+	ATH79_SOC_AR9331,
+	ATH79_SOC_AR9341,
+	ATH79_SOC_AR9342,
+	ATH79_SOC_AR9344,
+	ATH79_SOC_QCA9533,
+	ATH79_SOC_QCA9556,
+	ATH79_SOC_QCA9558,
+	ATH79_SOC_TP9343,
+	ATH79_SOC_QCA9561,
+};
+
+static inline int soc_is_ar71xx(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7130 ||
+		gd->arch.soc == ATH79_SOC_AR7141 ||
+		gd->arch.soc == ATH79_SOC_AR7161;
+}
+
+static inline int soc_is_ar724x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7240 ||
+		gd->arch.soc == ATH79_SOC_AR7241 ||
+		gd->arch.soc == ATH79_SOC_AR7242;
+}
+
+static inline int soc_is_ar7240(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7240;
+}
+
+static inline int soc_is_ar7241(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7241;
+}
+
+static inline int soc_is_ar7242(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR7242;
+}
+
+static inline int soc_is_ar913x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9130 ||
+		gd->arch.soc == ATH79_SOC_AR9132;
+}
+
+static inline int soc_is_ar933x(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9330 ||
+		gd->arch.soc == ATH79_SOC_AR9331;
+}
+
+static inline int soc_is_ar9341(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9341;
+}
+
+static inline int soc_is_ar9342(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9342;
+}
+
+static inline int soc_is_ar9344(void)
+{
+	return gd->arch.soc == ATH79_SOC_AR9344;
+}
+
+static inline int soc_is_ar934x(void)
+{
+	return soc_is_ar9341() ||
+		soc_is_ar9342() ||
+		soc_is_ar9344();
+}
+
+static inline int soc_is_qca9533(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9533;
+}
+
+static inline int soc_is_qca953x(void)
+{
+	return soc_is_qca9533();
+}
+
+static inline int soc_is_qca9556(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9556;
+}
+
+static inline int soc_is_qca9558(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9558;
+}
+
+static inline int soc_is_qca955x(void)
+{
+	return soc_is_qca9556() || soc_is_qca9558();
+}
+
+static inline int soc_is_tp9343(void)
+{
+	return gd->arch.soc == ATH79_SOC_TP9343;
+}
+
+static inline int soc_is_qca9561(void)
+{
+	return gd->arch.soc == ATH79_SOC_QCA9561;
+}
+
+static inline int soc_is_qca956x(void)
+{
+	return soc_is_tp9343() || soc_is_qca9561();
+}
+
+int ath79_eth_reset(void);
+int ath79_usb_reset(void);
+
+void ar934x_pll_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
+void ar934x_ddr_init(const u16 cpu_mhz, const u16 ddr_mhz, const u16 ahb_mhz);
+
+#endif /* __ASM_MACH_ATH79_H */
diff --git a/arch/mips/mach-ath79/include/mach/ddr.h b/arch/mips/mach-ath79/include/mach/ddr.h
new file mode 100644
index 0000000..181179a
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/ddr.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_DDR_H
+#define __ASM_MACH_DDR_H
+
+void ddr_init(void);
+void ddr_tap_tuning(void);
+
+#endif /* __ASM_MACH_DDR_H */
diff --git a/arch/mips/mach-ath79/include/mach/reset.h b/arch/mips/mach-ath79/include/mach/reset.h
new file mode 100644
index 0000000..c383bfe
--- /dev/null
+++ b/arch/mips/mach-ath79/include/mach/reset.h
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __ASM_MACH_RESET_H
+#define __ASM_MACH_RESET_H
+
+#include <linux/types.h>
+
+u32 get_bootstrap(void);
+
+#endif /* __ASM_MACH_RESET_H */
diff --git a/arch/mips/mach-ath79/qca953x/Makefile b/arch/mips/mach-ath79/qca953x/Makefile
new file mode 100644
index 0000000..fd74f0c
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/Makefile
@@ -0,0 +1,7 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y += clk.o
+obj-y += ddr.o
+obj-y += lowlevel_init.o
diff --git a/arch/mips/mach-ath79/qca953x/clk.c b/arch/mips/mach-ath79/qca953x/clk.c
new file mode 100644
index 0000000..ef0a28e
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/clk.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static u32 qca953x_get_xtal(void)
+{
+	u32 val;
+
+	val = get_bootstrap();
+	if (val & QCA953X_BOOTSTRAP_REF_CLK_40)
+		return 40000000;
+	else
+		return 25000000;
+}
+
+int get_serial_clock(void)
+{
+	return qca953x_get_xtal();
+}
+
+int get_clocks(void)
+{
+	void __iomem *regs;
+	u32 val, ctrl, xtal, pll, div;
+
+	regs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+			   MAP_NOCACHE);
+
+	xtal = qca953x_get_xtal();
+	ctrl = readl(regs + QCA953X_PLL_CLK_CTRL_REG);
+	val = readl(regs + QCA953X_PLL_CPU_CONFIG_REG);
+
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> QCA953X_PLL_CPU_CONFIG_REFDIV_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> QCA953X_PLL_CPU_CONFIG_NINT_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> QCA953X_PLL_CPU_CONFIG_OUTDIV_SHIFT)
+			& QCA953X_PLL_CPU_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	/* CPU_CLK = PLLOUT / CPU_POST_DIV */
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_CPU_POST_DIV_MASK) + 1;
+	gd->cpu_clk = pll / div;
+
+
+	val = readl(regs + QCA953X_PLL_DDR_CONFIG_REG);
+	/* VCOOUT = XTAL * DIV_INT */
+	div = (val >> QCA953X_PLL_DDR_CONFIG_REFDIV_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_REFDIV_MASK;
+	pll = xtal / div;
+
+	/* PLLOUT = VCOOUT * (1/2^OUTDIV) */
+	div = (val >> QCA953X_PLL_DDR_CONFIG_NINT_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_NINT_MASK;
+	pll *= div;
+	div = (val >> QCA953X_PLL_DDR_CONFIG_OUTDIV_SHIFT)
+			& QCA953X_PLL_DDR_CONFIG_OUTDIV_MASK;
+	if (!div)
+		div = 1;
+	pll >>= div;
+
+	/* DDR_CLK = PLLOUT / DDR_POST_DIV */
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_DDR_POST_DIV_MASK) + 1;
+	gd->mem_clk = pll / div;
+
+	div = ((ctrl >> QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_SHIFT)
+			& QCA953X_PLL_CLK_CTRL_AHB_POST_DIV_MASK) + 1;
+	if (ctrl & QCA953X_PLL_CLK_CTRL_AHBCLK_FROM_DDRPLL) {
+		/* AHB_CLK = DDR_CLK / AHB_POST_DIV */
+		gd->bus_clk = gd->mem_clk / (div + 1);
+	} else {
+		/* AHB_CLK = CPU_CLK / AHB_POST_DIV */
+		gd->bus_clk = gd->cpu_clk / (div + 1);
+	}
+
+	return 0;
+}
+
+ulong get_bus_freq(ulong dummy)
+{
+	if (!gd->bus_clk)
+		get_clocks();
+	return gd->bus_clk;
+}
+
+ulong get_ddr_freq(ulong dummy)
+{
+	if (!gd->mem_clk)
+		get_clocks();
+	return gd->mem_clk;
+}
diff --git a/arch/mips/mach-ath79/qca953x/ddr.c b/arch/mips/mach-ath79/qca953x/ddr.c
new file mode 100644
index 0000000..ac0130c
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/ddr.c
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/reset.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define DDR_CTRL_UPD_EMR3S      BIT(5)
+#define DDR_CTRL_UPD_EMR2S      BIT(4)
+#define DDR_CTRL_PRECHARGE      BIT(3)
+#define DDR_CTRL_AUTO_REFRESH   BIT(2)
+#define DDR_CTRL_UPD_EMRS       BIT(1)
+#define DDR_CTRL_UPD_MRS        BIT(0)
+
+#define DDR_REFRESH_EN          BIT(14)
+#define DDR_REFRESH_M           0x3ff
+#define DDR_REFRESH(x)          ((x) & DDR_REFRESH_M)
+#define DDR_REFRESH_VAL         (DDR_REFRESH_EN | DDR_REFRESH(312))
+
+#define DDR_TRAS_S              0
+#define DDR_TRAS_M              0x1f
+#define DDR_TRAS(x)             (((x) & DDR_TRAS_M) << DDR_TRAS_S)
+#define DDR_TRCD_M              0xf
+#define DDR_TRCD_S              5
+#define DDR_TRCD(x)             (((x) & DDR_TRCD_M) << DDR_TRCD_S)
+#define DDR_TRP_M               0xf
+#define DDR_TRP_S               9
+#define DDR_TRP(x)              (((x) & DDR_TRP_M) << DDR_TRP_S)
+#define DDR_TRRD_M              0xf
+#define DDR_TRRD_S              13
+#define DDR_TRRD(x)             (((x) & DDR_TRRD_M) << DDR_TRRD_S)
+#define DDR_TRFC_M              0x7f
+#define DDR_TRFC_S              17
+#define DDR_TRFC(x)             (((x) & DDR_TRFC_M) << DDR_TRFC_S)
+#define DDR_TMRD_M              0xf
+#define DDR_TMRD_S              23
+#define DDR_TMRD(x)             (((x) & DDR_TMRD_M) << DDR_TMRD_S)
+#define DDR_CAS_L_M             0x17
+#define DDR_CAS_L_S             27
+#define DDR_CAS_L(x)            (((x) & DDR_CAS_L_M) << DDR_CAS_L_S)
+#define DDR_OPEN                BIT(30)
+#define DDR1_CONF_REG_VAL       (DDR_TRAS(16) | DDR_TRCD(6) | \
+				 DDR_TRP(6) | DDR_TRRD(4) | \
+				 DDR_TRFC(7) | DDR_TMRD(5) | \
+				 DDR_CAS_L(7) | DDR_OPEN)
+#define DDR2_CONF_REG_VAL       (DDR_TRAS(27) | DDR_TRCD(9) | \
+				 DDR_TRP(9) | DDR_TRRD(7) | \
+				 DDR_TRFC(21) | DDR_TMRD(15) | \
+				 DDR_CAS_L(17) | DDR_OPEN)
+
+#define DDR_BURST_LEN_S         0
+#define DDR_BURST_LEN_M         0xf
+#define DDR_BURST_LEN(x)        ((x) << DDR_BURST_LEN_S)
+#define DDR_BURST_TYPE          BIT(4)
+#define DDR_CNTL_OE_EN          BIT(5)
+#define DDR_PHASE_SEL           BIT(6)
+#define DDR_CKE                 BIT(7)
+#define DDR_TWR_S               8
+#define DDR_TWR_M               0xf
+#define DDR_TWR(x)              (((x) & DDR_TWR_M) << DDR_TWR_S)
+#define DDR_TRTW_S              12
+#define DDR_TRTW_M              0x1f
+#define DDR_TRTW(x)             (((x) & DDR_TRTW_M) << DDR_TRTW_S)
+#define DDR_TRTP_S              17
+#define DDR_TRTP_M              0xf
+#define DDR_TRTP(x)             (((x) & DDR_TRTP_M) << DDR_TRTP_S)
+#define DDR_TWTR_S              21
+#define DDR_TWTR_M              0x1f
+#define DDR_TWTR(x)             (((x) & DDR_TWTR_M) << DDR_TWTR_S)
+#define DDR_G_OPEN_L_S          26
+#define DDR_G_OPEN_L_M          0xf
+#define DDR_G_OPEN_L(x)         ((x) << DDR_G_OPEN_L_S)
+#define DDR_HALF_WIDTH_LOW      BIT(31)
+#define DDR1_CONF2_REG_VAL      (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(13) | DDR_TRTW(14) | \
+				 DDR_TRTP(8) | DDR_TWTR(14) | \
+				 DDR_G_OPEN_L(6) | DDR_HALF_WIDTH_LOW)
+#define DDR2_CONF2_REG_VAL      (DDR_BURST_LEN(8) | DDR_CNTL_OE_EN | \
+				 DDR_CKE | DDR_TWR(1) | DDR_TRTW(14) | \
+				 DDR_TRTP(9) | DDR_TWTR(21) | \
+				 DDR_G_OPEN_L(8) | DDR_HALF_WIDTH_LOW)
+
+#define DDR_TWR_MSB             BIT(3)
+#define DDR_TRAS_MSB            BIT(2)
+#define DDR_TRFC_MSB_M          0x3
+#define DDR_TRFC_MSB(x)         (x)
+#define DDR1_CONF3_REG_VAL      0
+#define DDR2_CONF3_REG_VAL      (DDR_TWR_MSB | DDR_TRFC_MSB(2))
+
+#define DDR_CTL_SRAM_TSEL       BIT(30)
+#define DDR_CTL_SRAM_GE0_SYNC   BIT(20)
+#define DDR_CTL_SRAM_GE1_SYNC   BIT(19)
+#define DDR_CTL_SRAM_USB_SYNC   BIT(18)
+#define DDR_CTL_SRAM_PCIE_SYNC  BIT(17)
+#define DDR_CTL_SRAM_WMAC_SYNC  BIT(16)
+#define DDR_CTL_SRAM_MISC1_SYNC BIT(15)
+#define DDR_CTL_SRAM_MISC2_SYNC BIT(14)
+#define DDR_CTL_PAD_DDR2_SEL    BIT(6)
+#define DDR_CTL_HALF_WIDTH      BIT(1)
+#define DDR_CTL_CONFIG_VAL      (DDR_CTL_SRAM_TSEL | \
+				 DDR_CTL_SRAM_GE0_SYNC | \
+				 DDR_CTL_SRAM_GE1_SYNC | \
+				 DDR_CTL_SRAM_USB_SYNC | \
+				 DDR_CTL_SRAM_PCIE_SYNC | \
+				 DDR_CTL_SRAM_WMAC_SYNC | \
+				 DDR_CTL_HALF_WIDTH)
+
+#define DDR_BURST_GE0_MAX_BL_S  0
+#define DDR_BURST_GE0_MAX_BL_M  0xf
+#define DDR_BURST_GE0_MAX_BL(x) \
+	(((x) & DDR_BURST_GE0_MAX_BL_M) << DDR_BURST_GE0_MAX_BL_S)
+#define DDR_BURST_GE1_MAX_BL_S  4
+#define DDR_BURST_GE1_MAX_BL_M  0xf
+#define DDR_BURST_GE1_MAX_BL(x) \
+	(((x) & DDR_BURST_GE1_MAX_BL_M) << DDR_BURST_GE1_MAX_BL_S)
+#define DDR_BURST_PCIE_MAX_BL_S 8
+#define DDR_BURST_PCIE_MAX_BL_M 0xf
+#define DDR_BURST_PCIE_MAX_BL(x) \
+	(((x) & DDR_BURST_PCIE_MAX_BL_M) << DDR_BURST_PCIE_MAX_BL_S)
+#define DDR_BURST_USB_MAX_BL_S  12
+#define DDR_BURST_USB_MAX_BL_M  0xf
+#define DDR_BURST_USB_MAX_BL(x) \
+	(((x) & DDR_BURST_USB_MAX_BL_M) << DDR_BURST_USB_MAX_BL_S)
+#define DDR_BURST_CPU_MAX_BL_S  16
+#define DDR_BURST_CPU_MAX_BL_M  0xf
+#define DDR_BURST_CPU_MAX_BL(x) \
+	(((x) & DDR_BURST_CPU_MAX_BL_M) << DDR_BURST_CPU_MAX_BL_S)
+#define DDR_BURST_RD_MAX_BL_S   20
+#define DDR_BURST_RD_MAX_BL_M   0xf
+#define DDR_BURST_RD_MAX_BL(x) \
+	(((x) & DDR_BURST_RD_MAX_BL_M) << DDR_BURST_RD_MAX_BL_S)
+#define DDR_BURST_WR_MAX_BL_S   24
+#define DDR_BURST_WR_MAX_BL_M   0xf
+#define DDR_BURST_WR_MAX_BL(x) \
+	(((x) & DDR_BURST_WR_MAX_BL_M) << DDR_BURST_WR_MAX_BL_S)
+#define DDR_BURST_RWP_MASK_EN_S 28
+#define DDR_BURST_RWP_MASK_EN_M 0x3
+#define DDR_BURST_RWP_MASK_EN(x) \
+	(((x) & DDR_BURST_RWP_MASK_EN_M) << DDR_BURST_RWP_MASK_EN_S)
+#define DDR_BURST_CPU_PRI_BE    BIT(30)
+#define DDR_BURST_CPU_PRI       BIT(31)
+#define DDR_BURST_VAL           (DDR_BURST_CPU_PRI_BE | \
+				 DDR_BURST_RWP_MASK_EN(3) | \
+				 DDR_BURST_WR_MAX_BL(4) | \
+				 DDR_BURST_RD_MAX_BL(4) | \
+				 DDR_BURST_CPU_MAX_BL(4) | \
+				 DDR_BURST_USB_MAX_BL(4) | \
+				 DDR_BURST_PCIE_MAX_BL(4) | \
+				 DDR_BURST_GE1_MAX_BL(4) | \
+				 DDR_BURST_GE0_MAX_BL(4))
+
+#define DDR_BURST_WMAC_MAX_BL_S 0
+#define DDR_BURST_WMAC_MAX_BL_M 0xf
+#define DDR_BURST_WMAC_MAX_BL(x) \
+	(((x) & DDR_BURST_WMAC_MAX_BL_M) << DDR_BURST_WMAC_MAX_BL_S)
+#define DDR_BURST2_VAL          DDR_BURST_WMAC_MAX_BL(4)
+
+#define DDR2_CONF_TWL_S         10
+#define DDR2_CONF_TWL_M         0xf
+#define DDR2_CONF_TWL(x) \
+	(((x) & DDR2_CONF_TWL_M) << DDR2_CONF_TWL_S)
+#define DDR2_CONF_ODT           BIT(9)
+#define DDR2_CONF_TFAW_S        2
+#define DDR2_CONF_TFAW_M        0x3f
+#define DDR2_CONF_TFAW(x) \
+	(((x) & DDR2_CONF_TFAW_M) << DDR2_CONF_TFAW_S)
+#define DDR2_CONF_EN            BIT(0)
+#define DDR2_CONF_VAL           (DDR2_CONF_TWL(5) | \
+				 DDR2_CONF_TFAW(31) | \
+				 DDR2_CONF_ODT | \
+				 DDR2_CONF_EN)
+
+#define DDR1_EXT_MODE_VAL       0
+#define DDR2_EXT_MODE_VAL       0x402
+#define DDR2_EXT_MODE_OCD_VAL   0x782
+#define DDR1_MODE_DLL_VAL       0x133
+#define DDR2_MODE_DLL_VAL       0x143
+#define DDR1_MODE_VAL           0x33
+#define DDR2_MODE_VAL           0x43
+#define DDR1_TAP_VAL            0x20
+#define DDR2_TAP_VAL            0x10
+
+#define DDR_REG_BIST_MASK_ADDR_0        0x2c
+#define DDR_REG_BIST_MASK_ADDR_1        0x30
+#define DDR_REG_BIST_MASK_AHB_GE0_0     0x34
+#define DDR_REG_BIST_COMP_AHB_GE0_0     0x38
+#define DDR_REG_BIST_MASK_AHB_GE1_0     0x3c
+#define DDR_REG_BIST_COMP_AHB_GE1_0     0x40
+#define DDR_REG_BIST_COMP_ADDR_0        0x64
+#define DDR_REG_BIST_COMP_ADDR_1        0x68
+#define DDR_REG_BIST_MASK_AHB_GE0_1     0x6c
+#define DDR_REG_BIST_COMP_AHB_GE0_1     0x70
+#define DDR_REG_BIST_MASK_AHB_GE1_1     0x74
+#define DDR_REG_BIST_COMP_AHB_GE1_1     0x78
+#define DDR_REG_BIST                    0x11c
+#define DDR_REG_BIST_STATUS             0x120
+
+#define DDR_BIST_COMP_CNT_S     1
+#define DDR_BIST_COMP_CNT_M     0xff
+#define DDR_BIST_COMP_CNT(x) \
+	(((x) & DDR_BIST_COMP_CNT_M) << DDR_BIST_COMP_CNT_S)
+#define DDR_BIST_COMP_CNT_MASK \
+	(DDR_BIST_COMP_CNT_M << DDR_BIST_COMP_CNT_S)
+#define DDR_BIST_TEST_START     BIT(0)
+#define DDR_BIST_STATUS_DONE    BIT(0)
+
+/* 4 Row Address Bits, 4 Column Address Bits, 2 BA bits */
+#define DDR_BIST_MASK_ADDR_VAL  0xfa5de83f
+
+#define DDR_TAP_MAGIC_VAL       0xaa55aa55
+#define DDR_TAP_MAX_VAL         0x40
+
+void ddr_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+	val = get_bootstrap();
+	if (val & QCA953X_BOOTSTRAP_DDR1) {
+		writel(DDR_CTL_CONFIG_VAL, regs + QCA953X_DDR_REG_CTL_CONF);
+		udelay(10);
+
+		/* For 16-bit DDR */
+		writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE);
+		udelay(100);
+
+		/* Burst size */
+		writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST);
+		udelay(100);
+		writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2);
+		udelay(100);
+
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX);
+		udelay(100);
+
+		/* DRAM timing */
+		writel(DDR1_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+		udelay(100);
+		writel(DDR1_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+		udelay(100);
+		writel(DDR1_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* ODT disable, Full strength, Enable DLL */
+		writel(DDR1_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Reset DLL, CAS Latency 3, Burst Length 8 */
+		writel(DDR1_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Normal DLL, CAS Latency 3, Burst Length 8 */
+		writel(DDR1_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Refresh time control */
+		writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH);
+		udelay(100);
+
+		/* DQS 0 Tap Control */
+		writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR1_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1);
+	} else {
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(10);
+		writel(DDR_CTL_CONFIG_VAL | DDR_CTL_PAD_DDR2_SEL,
+		       regs + QCA953X_DDR_REG_CTL_CONF);
+		udelay(10);
+
+		/* For 16-bit DDR */
+		writel(0xffff, regs + AR71XX_DDR_REG_RD_CYCLE);
+		udelay(100);
+
+		/* Burst size */
+		writel(DDR_BURST_VAL, regs + QCA953X_DDR_REG_BURST);
+		udelay(100);
+		writel(DDR_BURST2_VAL, regs + QCA953X_DDR_REG_BURST2);
+		udelay(100);
+
+		/* AHB maximum timeout */
+		writel(0xfffff, regs + QCA953X_DDR_REG_TIMEOUT_MAX);
+		udelay(100);
+
+		/* DRAM timing */
+		writel(DDR2_CONF_REG_VAL, regs + AR71XX_DDR_REG_CONFIG);
+		udelay(100);
+		writel(DDR2_CONF2_REG_VAL, regs + AR71XX_DDR_REG_CONFIG2);
+		udelay(100);
+		writel(DDR2_CONF3_REG_VAL, regs + QCA953X_DDR_REG_CONFIG3);
+		udelay(100);
+
+		/* Enable DDR2 */
+		writel(DDR2_CONF_VAL, regs + QCA953X_DDR_REG_DDR2_CONFIG);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Update Extended Mode Register 2 Set (EMR2S) */
+		writel(DDR_CTRL_UPD_EMR2S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Update Extended Mode Register 3 Set (EMR3S) */
+		writel(DDR_CTRL_UPD_EMR3S, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* 150 ohm, Reduced strength, Enable DLL */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Reset DLL, CAS Latency 4, Burst Length 8 */
+		writel(DDR2_MODE_DLL_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Update Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Precharge All */
+		writel(DDR_CTRL_PRECHARGE, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Auto Refresh */
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+		writel(DDR_CTRL_AUTO_REFRESH, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Normal DLL, CAS Latency 4, Burst Length 8 */
+		writel(DDR2_MODE_VAL, regs + AR71XX_DDR_REG_MODE);
+		udelay(100);
+
+		/* Mode Register Set (MRS) */
+		writel(DDR_CTRL_UPD_MRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Enable OCD, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_OCD_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* OCD diable, Enable DLL, Reduced Drive Strength */
+		writel(DDR2_EXT_MODE_VAL, regs + AR71XX_DDR_REG_EMR);
+		udelay(100);
+
+		/* Update Extended Mode Register Set (EMRS) */
+		writel(DDR_CTRL_UPD_EMRS, regs + AR71XX_DDR_REG_CONTROL);
+		udelay(100);
+
+		/* Refresh time control */
+		writel(DDR_REFRESH_VAL, regs + AR71XX_DDR_REG_REFRESH);
+		udelay(100);
+
+		/* DQS 0 Tap Control */
+		writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL0);
+
+		/* DQS 1 Tap Control */
+		writel(DDR2_TAP_VAL, regs + AR71XX_DDR_REG_TAP_CTRL1);
+	}
+}
+
+void ddr_tap_tuning(void)
+{
+	void __iomem *regs;
+	u32 val, pass, tap, cnt, tap_val, last, first;
+
+	regs = map_physmem(AR71XX_DDR_CTRL_BASE, AR71XX_DDR_CTRL_SIZE,
+			   MAP_NOCACHE);
+
+	tap_val = readl(regs + AR71XX_DDR_REG_TAP_CTRL0);
+	first = DDR_TAP_MAGIC_VAL;
+	last = 0;
+	cnt = 0;
+	tap = 0;
+
+	do {
+		writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL0);
+		writel(tap, regs + AR71XX_DDR_REG_TAP_CTRL1);
+
+		writel(DDR_BIST_COMP_CNT(8), regs + DDR_REG_BIST_COMP_ADDR_1);
+		writel(DDR_BIST_MASK_ADDR_VAL, regs + DDR_REG_BIST_MASK_ADDR_0);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_1);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_0);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE1_1);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_0);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE0_1);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_0);
+		writel(0xffff, regs + DDR_REG_BIST_MASK_AHB_GE1_1);
+		writel(0xffff, regs + DDR_REG_BIST_COMP_AHB_GE0_0);
+
+		/* Start BIST test */
+		writel(DDR_BIST_TEST_START, regs + DDR_REG_BIST);
+
+		do {
+			val = readl(regs + DDR_REG_BIST_STATUS);
+		} while (!(val & DDR_BIST_STATUS_DONE));
+
+		/* Stop BIST test */
+		writel(0, regs + DDR_REG_BIST);
+
+		pass = val & DDR_BIST_COMP_CNT_MASK;
+		pass ^= DDR_BIST_COMP_CNT(8);
+		if (!pass) {
+			if (first != DDR_TAP_MAGIC_VAL) {
+				last = tap;
+			} else  {
+				first = tap;
+				last = tap;
+			}
+			cnt++;
+		}
+		tap++;
+	} while (tap < DDR_TAP_MAX_VAL);
+
+	if (cnt) {
+		tap_val = (first + last) / 2;
+		tap_val %= DDR_TAP_MAX_VAL;
+	}
+
+	writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL0);
+	writel(tap_val, regs + AR71XX_DDR_REG_TAP_CTRL1);
+}
diff --git a/arch/mips/mach-ath79/qca953x/lowlevel_init.S b/arch/mips/mach-ath79/qca953x/lowlevel_init.S
new file mode 100644
index 0000000..d7038fa
--- /dev/null
+++ b/arch/mips/mach-ath79/qca953x/lowlevel_init.S
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ * Based on Atheros LSDK/QSDK
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <config.h>
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <mach/ar71xx_regs.h>
+
+#define MK_PLL_CONF(divint, refdiv, range, outdiv) \
+     (((0x3F & divint) << 10) | \
+     ((0x1F & refdiv) << 16) | \
+     ((0x1 & range)   << 21) | \
+     ((0x7 & outdiv)  << 23) )
+
+#define MK_CLK_CNTL(cpudiv, ddrdiv, ahbdiv) \
+    (((0x3 & (cpudiv - 1)) << 5)  | \
+    ((0x3 & (ddrdiv - 1)) << 10) | \
+    ((0x3 & (ahbdiv - 1)) << 15) )
+
+#define SET_FIELD(name, v)      (((v) & QCA953X_##name##_MASK) << \
+				 QCA953X_##name##_SHIFT)
+
+#define DPLL2_KI(v)             SET_FIELD(SRIF_DPLL2_KI, v)
+#define DPLL2_KD(v)             SET_FIELD(SRIF_DPLL2_KD, v)
+#define DPLL2_PWD               QCA953X_SRIF_DPLL2_PWD
+#define MK_DPLL2(ki, kd)        (DPLL2_KI(ki) | DPLL2_KD(kd) | DPLL2_PWD)
+
+#define PLL_CPU_NFRAC(v)        SET_FIELD(PLL_CPU_CONFIG_NFRAC, v)
+#define PLL_CPU_NINT(v)         SET_FIELD(PLL_CPU_CONFIG_NINT, v)
+#define PLL_CPU_REFDIV(v)       SET_FIELD(PLL_CPU_CONFIG_REFDIV, v)
+#define PLL_CPU_OUTDIV(v)       SET_FIELD(PLL_CPU_CONFIG_OUTDIV, v)
+#define MK_PLL_CPU_CONF(frac, nint, ref, outdiv) \
+				(PLL_CPU_NFRAC(frac) | \
+				 PLL_CPU_NINT(nint) | \
+				 PLL_CPU_REFDIV(ref) | \
+				 PLL_CPU_OUTDIV(outdiv))
+
+#define PLL_DDR_NFRAC(v)        SET_FIELD(PLL_DDR_CONFIG_NFRAC, v)
+#define PLL_DDR_NINT(v)         SET_FIELD(PLL_DDR_CONFIG_NINT, v)
+#define PLL_DDR_REFDIV(v)       SET_FIELD(PLL_DDR_CONFIG_REFDIV, v)
+#define PLL_DDR_OUTDIV(v)       SET_FIELD(PLL_DDR_CONFIG_OUTDIV, v)
+#define MK_PLL_DDR_CONF(frac, nint, ref, outdiv) \
+				(PLL_DDR_NFRAC(frac) | \
+				 PLL_DDR_REFDIV(ref) | \
+				 PLL_DDR_NINT(nint) | \
+				 PLL_DDR_OUTDIV(outdiv) | \
+				 QCA953X_PLL_CONFIG_PWD)
+
+#define PLL_CPU_CONF_VAL        MK_PLL_CPU_CONF(0, 26, 1, 0)
+#define PLL_DDR_CONF_VAL        MK_PLL_DDR_CONF(0, 15, 1, 0)
+
+#define PLL_CLK_CTRL_PLL_BYPASS (QCA953X_PLL_CLK_CTRL_CPU_PLL_BYPASS | \
+				 QCA953X_PLL_CLK_CTRL_DDR_PLL_BYPASS | \
+				 QCA953X_PLL_CLK_CTRL_AHB_PLL_BYPASS)
+
+#define PLL_CLK_CTRL_CPU_DIV(v) SET_FIELD(PLL_CLK_CTRL_CPU_POST_DIV, v)
+#define PLL_CLK_CTRL_DDR_DIV(v) SET_FIELD(PLL_CLK_CTRL_DDR_POST_DIV, v)
+#define PLL_CLK_CTRL_AHB_DIV(v) SET_FIELD(PLL_CLK_CTRL_AHB_POST_DIV, v)
+#define MK_PLL_CLK_CTRL(cpu, ddr, ahb) \
+				(PLL_CLK_CTRL_CPU_DIV(cpu) | \
+				 PLL_CLK_CTRL_DDR_DIV(ddr) | \
+				 PLL_CLK_CTRL_AHB_DIV(ahb))
+#define PLL_CLK_CTRL_VAL    (MK_PLL_CLK_CTRL(0, 0, 2) | \
+			     PLL_CLK_CTRL_PLL_BYPASS | \
+			     QCA953X_PLL_CLK_CTRL_CPUCLK_FROM_CPUPLL | \
+			     QCA953X_PLL_CLK_CTRL_DDRCLK_FROM_DDRPLL)
+
+#define PLL_DDR_DIT_FRAC_MAX(v)     SET_FIELD(PLL_DDR_DIT_FRAC_MAX, v)
+#define PLL_DDR_DIT_FRAC_MIN(v)     SET_FIELD(PLL_DDR_DIT_FRAC_MIN, v)
+#define PLL_DDR_DIT_FRAC_STEP(v)    SET_FIELD(PLL_DDR_DIT_FRAC_STEP, v)
+#define PLL_DDR_DIT_UPD_CNT(v)      SET_FIELD(PLL_DDR_DIT_UPD_CNT, v)
+#define PLL_CPU_DIT_FRAC_MAX(v)     SET_FIELD(PLL_CPU_DIT_FRAC_MAX, v)
+#define PLL_CPU_DIT_FRAC_MIN(v)     SET_FIELD(PLL_CPU_DIT_FRAC_MIN, v)
+#define PLL_CPU_DIT_FRAC_STEP(v)    SET_FIELD(PLL_CPU_DIT_FRAC_STEP, v)
+#define PLL_CPU_DIT_UPD_CNT(v)      SET_FIELD(PLL_CPU_DIT_UPD_CNT, v)
+#define MK_PLL_DDR_DIT_FRAC(max, min, step, cnt) \
+				(QCA953X_PLL_DIT_FRAC_EN | \
+				 PLL_DDR_DIT_FRAC_MAX(max) | \
+				 PLL_DDR_DIT_FRAC_MIN(min) | \
+				 PLL_DDR_DIT_FRAC_STEP(step) | \
+				 PLL_DDR_DIT_UPD_CNT(cnt))
+#define MK_PLL_CPU_DIT_FRAC(max, min, step, cnt) \
+				(QCA953X_PLL_DIT_FRAC_EN | \
+				 PLL_CPU_DIT_FRAC_MAX(max) | \
+				 PLL_CPU_DIT_FRAC_MIN(min) | \
+				 PLL_CPU_DIT_FRAC_STEP(step) | \
+				 PLL_CPU_DIT_UPD_CNT(cnt))
+#define PLL_CPU_DIT_FRAC_VAL    MK_PLL_CPU_DIT_FRAC(63, 0, 1, 15)
+#define PLL_DDR_DIT_FRAC_VAL    MK_PLL_DDR_DIT_FRAC(763, 635, 1, 15)
+
+    .text
+    .set noreorder
+
+LEAF(lowlevel_init)
+	/* RTC Reset */
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0x08000000
+	or      t1, t1, t2
+	sw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	nop
+	lw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	li      t2, 0xf7ffffff
+	and     t1, t1, t2
+	sw      t1, QCA953X_RESET_REG_RESET_MODULE(t0)
+	nop
+
+	/* RTC Force Wake */
+	li      t0, CKSEG1ADDR(QCA953X_RTC_BASE)
+	li      t1, 0x01
+	sw      t1, QCA953X_RTC_REG_SYNC_RESET(t0)
+	nop
+	nop
+
+	/* Wait for RTC in on state */
+1:
+	lw      t1, QCA953X_RTC_REG_SYNC_STATUS(t0)
+	andi    t1, t1, 0x02
+	beqz    t1, 1b
+	nop
+
+	li      t0, CKSEG1ADDR(QCA953X_SRIF_BASE)
+	li      t1, MK_DPLL2(2, 16)
+	sw      t1, QCA953X_SRIF_BB_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_PCIE_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_DDR_DPLL2_REG(t0)
+	sw      t1, QCA953X_SRIF_CPU_DPLL2_REG(t0)
+
+	li      t0, CKSEG1ADDR(AR71XX_PLL_BASE)
+	lw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	ori     t1, PLL_CLK_CTRL_PLL_BYPASS
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	li      t1, PLL_CPU_CONF_VAL
+	sw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	li      t1, PLL_DDR_CONF_VAL
+	sw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	nop
+
+	li      t1, PLL_CLK_CTRL_VAL
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	li      t2, ~QCA953X_PLL_CONFIG_PWD
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_CPU_CONFIG_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	li      t2, ~QCA953X_PLL_CONFIG_PWD
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_DDR_CONFIG_REG(t0)
+	nop
+
+	lw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	li      t2, ~PLL_CLK_CTRL_PLL_BYPASS
+	and     t1, t1, t2
+	sw      t1, QCA953X_PLL_CLK_CTRL_REG(t0)
+	nop
+
+	li      t1, PLL_DDR_DIT_FRAC_VAL
+	sw      t1, QCA953X_PLL_DDR_DIT_FRAC_REG(t0)
+	nop
+
+	li      t1, PLL_CPU_DIT_FRAC_VAL
+	sw      t1, QCA953X_PLL_CPU_DIT_FRAC_REG(t0)
+	nop
+
+	li      t0, CKSEG1ADDR(AR71XX_RESET_BASE)
+	lui     t1, 0x03fc
+	sw      t1, 0xb4(t0)
+
+	nop
+	jr ra
+	 nop
+    END(lowlevel_init)
diff --git a/arch/mips/mach-ath79/reset.c b/arch/mips/mach-ath79/reset.c
new file mode 100644
index 0000000..188eccb
--- /dev/null
+++ b/arch/mips/mach-ath79/reset.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+
+void _machine_restart(void)
+{
+	void __iomem *base;
+	u32 reg = 0;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+	if (soc_is_ar71xx())
+		reg = AR71XX_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar724x())
+		reg = AR724X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar913x())
+		reg = AR913X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar933x())
+		reg = AR933X_RESET_REG_RESET_MODULE;
+	else if (soc_is_ar934x())
+		reg = AR934X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca953x())
+		reg = QCA953X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_RESET_MODULE;
+	else if (soc_is_qca956x())
+		reg = QCA956X_RESET_REG_RESET_MODULE;
+	else
+		puts("Reset register not defined for this SOC\n");
+
+	if (reg)
+		setbits_be32(base + reg, AR71XX_RESET_FULL_CHIP);
+
+	while (1)
+		/* NOP */;
+}
+
+u32 get_bootstrap(void)
+{
+	void __iomem *base;
+	u32 reg = 0;
+
+	base = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+			   MAP_NOCACHE);
+	if (soc_is_ar933x())
+		reg = AR933X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_ar934x())
+		reg = AR934X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca953x())
+		reg = QCA953X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca955x())
+		reg = QCA955X_RESET_REG_BOOTSTRAP;
+	else if (soc_is_qca956x())
+		reg = QCA956X_RESET_REG_BOOTSTRAP;
+	else
+		puts("Bootstrap register not defined for this SOC\n");
+
+	if (reg)
+		return readl(base + reg);
+
+	return 0;
+}
+
+static int eth_init_ar933x(void)
+{
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *gregs = map_physmem(AR933X_GMAC_BASE, AR933X_GMAC_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = AR933X_RESET_GE0_MAC | AR933X_RESET_GE0_MDIO |
+			 AR933X_RESET_GE1_MAC | AR933X_RESET_GE1_MDIO |
+			 AR933X_RESET_ETH_SWITCH;
+
+	/* Clear MDIO slave EN bit. */
+	clrbits_be32(rregs + AR933X_RESET_REG_BOOTSTRAP, BIT(17));
+	mdelay(10);
+
+	/* Get Atheros S26 PHY out of reset. */
+	clrsetbits_be32(pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG,
+			0x1f, 0x10);
+	mdelay(10);
+
+	setbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask);
+	mdelay(10);
+	clrbits_be32(rregs + AR933X_RESET_REG_RESET_MODULE, mask);
+	mdelay(10);
+
+	/* Configure AR93xx GMAC register. */
+	clrsetbits_be32(gregs + AR933X_GMAC_REG_ETH_CFG,
+			AR933X_ETH_CFG_MII_GE0_MASTER |
+			AR933X_ETH_CFG_MII_GE0_SLAVE,
+			AR933X_ETH_CFG_MII_GE0_SLAVE);
+	return 0;
+}
+
+static int eth_init_ar934x(void)
+{
+	void __iomem *rregs = map_physmem(AR71XX_RESET_BASE, AR71XX_RESET_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *pregs = map_physmem(AR71XX_PLL_BASE, AR71XX_PLL_SIZE,
+					  MAP_NOCACHE);
+	void __iomem *gregs = map_physmem(AR934X_GMAC_BASE, AR934X_GMAC_SIZE,
+					  MAP_NOCACHE);
+	const u32 mask = AR934X_RESET_GE0_MAC | AR934X_RESET_GE0_MDIO |
+			 AR934X_RESET_GE1_MAC | AR934X_RESET_GE1_MDIO |
+			 AR934X_RESET_ETH_SWITCH_ANALOG;
+	u32 reg;
+
+	reg = readl(rregs + AR934X_RESET_REG_BOOTSTRAP);
+	if (reg & AR934X_BOOTSTRAP_REF_CLK_40)
+		writel(0x570, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+	else
+		writel(0x271, pregs + AR934X_PLL_SWITCH_CLOCK_CONTROL_REG);
+	writel(BIT(26) | BIT(25), pregs + AR934X_PLL_ETH_XMII_CONTROL_REG);
+
+	setbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+	clrbits_be32(rregs + AR934X_RESET_REG_RESET_MODULE, mask);
+	mdelay(1);
+
+	/* Configure AR934x GMAC register. */
+	writel(AR934X_ETH_CFG_RGMII_GMAC0, gregs + AR934X_GMAC_REG_ETH_CFG);
+	return 0;
+}
+
+int ath79_eth_reset(void)
+{
+	/*
+	 * Un-reset ethernet. DM still doesn't have any notion of reset
+	 * framework, so we do it by hand here.
+	 */
+	if (soc_is_ar933x())
+		return eth_init_ar933x();
+	if (soc_is_ar934x())
+		return eth_init_ar934x();
+
+	return -EINVAL;
+}
+
+static int usb_reset_ar933x(void __iomem *reset_regs)
+{
+	/* Ungate the USB block */
+	setbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USBSUS_OVERRIDE);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USB_HOST);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR933X_RESET_REG_RESET_MODULE,
+		     AR933X_RESET_USB_PHY);
+	mdelay(1);
+
+	return 0;
+}
+
+static int usb_reset_ar934x(void __iomem *reset_regs)
+{
+	/* Ungate the USB block */
+	setbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USBSUS_OVERRIDE);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_PHY);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_PHY_ANALOG);
+	mdelay(1);
+	clrbits_be32(reset_regs + AR934X_RESET_REG_RESET_MODULE,
+		     AR934X_RESET_USB_HOST);
+	mdelay(1);
+
+	return 0;
+}
+
+int ath79_usb_reset(void)
+{
+	void __iomem *usbc_regs = map_physmem(AR71XX_USB_CTRL_BASE,
+					      AR71XX_USB_CTRL_SIZE,
+					      MAP_NOCACHE);
+	void __iomem *reset_regs = map_physmem(AR71XX_RESET_BASE,
+					       AR71XX_RESET_SIZE,
+					       MAP_NOCACHE);
+	/*
+	 * Turn on the Buff and Desc swap bits.
+	 * NOTE: This write into an undocumented register in mandatory to
+	 *       get the USB controller operational in BigEndian mode.
+	 */
+	writel(0xf0000, usbc_regs + AR71XX_USB_CTRL_REG_CONFIG);
+
+	if (soc_is_ar933x())
+		return usb_reset_ar933x(reset_regs);
+	if (soc_is_ar934x())
+		return usb_reset_ar934x(reset_regs);
+
+	return -EINVAL;
+}
diff --git a/arch/powerpc/include/asm/fsl_i2c.h b/arch/powerpc/include/asm/fsl_i2c.h
index cbbc834..d2586f9 100644
--- a/arch/powerpc/include/asm/fsl_i2c.h
+++ b/arch/powerpc/include/asm/fsl_i2c.h
@@ -16,7 +16,7 @@
 
 #include <asm/types.h>
 
-typedef struct fsl_i2c {
+typedef struct fsl_i2c_base {
 
 	u8 adr;		/* I2C slave address */
 	u8 res0[3];
@@ -68,4 +68,14 @@
 	u8 res6[0xE8];
 } fsl_i2c_t;
 
+#ifdef CONFIG_DM_I2C
+struct fsl_i2c_dev {
+	struct fsl_i2c_base __iomem *base;      /* register base */
+	u32 i2c_clk;
+	u32 index;
+	u8 slaveadd;
+	uint speed;
+};
+#endif
+
 #endif	/* _ASM_I2C_H_ */
diff --git a/arch/powerpc/include/asm/immap_85xx.h b/arch/powerpc/include/asm/immap_85xx.h
index 53ca6d9..07d2adf 100644
--- a/arch/powerpc/include/asm/immap_85xx.h
+++ b/arch/powerpc/include/asm/immap_85xx.h
@@ -120,8 +120,8 @@
 
 /* I2C Registers */
 typedef struct ccsr_i2c {
-	struct fsl_i2c	i2c[1];
-	u8	res[4096 - 1 * sizeof(struct fsl_i2c)];
+	struct fsl_i2c_base	i2c[1];
+	u8	res[4096 - 1 * sizeof(struct fsl_i2c_base)];
 } ccsr_i2c_t;
 
 #if defined(CONFIG_MPC8540) \
diff --git a/arch/powerpc/include/asm/immap_86xx.h b/arch/powerpc/include/asm/immap_86xx.h
index 177918b..b078569 100644
--- a/arch/powerpc/include/asm/immap_86xx.h
+++ b/arch/powerpc/include/asm/immap_86xx.h
@@ -92,8 +92,8 @@
 
 /* Daul I2C Registers(0x3000-0x4000) */
 typedef struct ccsr_i2c {
-	struct fsl_i2c	i2c[2];
-	u8	res[4096 - 2 * sizeof(struct fsl_i2c)];
+	struct fsl_i2c_base	i2c[2];
+	u8	res[4096 - 2 * sizeof(struct fsl_i2c_base)];
 } ccsr_i2c_t;
 
 /* DUART Registers(0x4000-0x5000) */
diff --git a/arch/sandbox/include/asm/io.h b/arch/sandbox/include/asm/io.h
index b87ee19..6919632 100644
--- a/arch/sandbox/include/asm/io.h
+++ b/arch/sandbox/include/asm/io.h
@@ -56,6 +56,21 @@
 void outw(unsigned int value, unsigned int addr);
 void outb(unsigned int value, unsigned int addr);
 
+static inline void _insw(volatile u16 *port, void *buf, int ns)
+{
+}
+
+static inline void _outsw(volatile u16 *port, const void *buf, int ns)
+{
+}
+
+#define insw(port, buf, ns)		_insw((u16 *)port, buf, ns)
+#define outsw(port, buf, ns)		_outsw((u16 *)port, buf, ns)
+
+/* For systemace.c */
+#define out16(addr, val)
+#define in16(addr)		0
+
 #include <iotrace.h>
 #include <asm/types.h>
 
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 4ef27dc..396023e 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -47,6 +47,9 @@
 
 # architecture-specific options below
 
+config AHCI
+	default y
+
 config SYS_MALLOC_F_LEN
 	default 0x800
 
diff --git a/arch/x86/cpu/broadwell/sata.c b/arch/x86/cpu/broadwell/sata.c
index dfb8486..2e47082 100644
--- a/arch/x86/cpu/broadwell/sata.c
+++ b/arch/x86/cpu/broadwell/sata.c
@@ -261,7 +261,7 @@
 
 U_BOOT_DRIVER(ahci_broadwell_drv) = {
 	.name		= "ahci_broadwell",
-	.id		= UCLASS_DISK,
+	.id		= UCLASS_AHCI,
 	.of_match	= broadwell_ahci_ids,
 	.ofdata_to_platdata	= broadwell_sata_ofdata_to_platdata,
 	.probe		= broadwell_sata_probe,
diff --git a/arch/x86/cpu/intel_common/cpu.c b/arch/x86/cpu/intel_common/cpu.c
index 93e4505..0fdef6f 100644
--- a/arch/x86/cpu/intel_common/cpu.c
+++ b/arch/x86/cpu/intel_common/cpu.c
@@ -58,7 +58,7 @@
 		return -ENODEV;
 
 	/* Cause the SATA device to do its early init */
-	uclass_first_device(UCLASS_DISK, &dev);
+	uclass_first_device(UCLASS_AHCI, &dev);
 
 	return 0;
 }
diff --git a/arch/x86/cpu/ivybridge/bd82x6x.c b/arch/x86/cpu/ivybridge/bd82x6x.c
index 4c039ac..5b58d6c 100644
--- a/arch/x86/cpu/ivybridge/bd82x6x.c
+++ b/arch/x86/cpu/ivybridge/bd82x6x.c
@@ -162,7 +162,7 @@
 		return 0;
 
 	/* Cause the SATA device to do its init */
-	uclass_first_device(UCLASS_DISK, &dev);
+	uclass_first_device(UCLASS_AHCI, &dev);
 
 	ret = syscon_get_by_driver_data(X86_SYSCON_GMA, &gma_dev);
 	if (ret)
diff --git a/arch/x86/cpu/ivybridge/sata.c b/arch/x86/cpu/ivybridge/sata.c
index c3d1057..1ce8195 100644
--- a/arch/x86/cpu/ivybridge/sata.c
+++ b/arch/x86/cpu/ivybridge/sata.c
@@ -233,7 +233,7 @@
 
 U_BOOT_DRIVER(ahci_ivybridge_drv) = {
 	.name		= "ahci_ivybridge",
-	.id		= UCLASS_DISK,
+	.id		= UCLASS_AHCI,
 	.of_match	= bd82x6x_ahci_ids,
 	.probe		= bd82x6x_sata_probe,
 };
diff --git a/board/cm5200/fwupdate.c b/board/cm5200/fwupdate.c
index 2ed90de..4740c83 100644
--- a/board/cm5200/fwupdate.c
+++ b/board/cm5200/fwupdate.c
@@ -105,7 +105,7 @@
 
 	/* Detect storage device */
 	for (devno = 0; devno < USB_MAX_STOR_DEV; devno++) {
-		stor_dev = usb_stor_get_dev(devno);
+		stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, devno);
 		if (stor_dev->type != DEV_TYPE_UNKNOWN)
 			break;
 	}
diff --git a/board/compulab/common/eeprom.c b/board/compulab/common/eeprom.c
index 6304468..b5f1aa6 100644
--- a/board/compulab/common/eeprom.c
+++ b/board/compulab/common/eeprom.c
@@ -9,6 +9,9 @@
 
 #include <common.h>
 #include <i2c.h>
+#include <eeprom_layout.h>
+#include <eeprom_field.h>
+#include <linux/kernel.h>
 #include "eeprom.h"
 
 #ifndef CONFIG_SYS_I2C_EEPROM_ADDR
@@ -181,3 +184,344 @@
 
 	return err;
 }
+
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+/**
+ * eeprom_field_print_bin_ver() - print a "version field" which contains binary
+ *				  data
+ *
+ * Treat the field data as simple binary data, and print it formatted as a
+ * version number (2 digits after decimal point).
+ * The field size must be exactly 2 bytes.
+ *
+ * Sample output:
+ *      Field Name      123.45
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_bin_ver(const struct eeprom_field *field)
+{
+	if ((field->buf[0] == 0xff) && (field->buf[1] == 0xff)) {
+		field->buf[0] = 0;
+		field->buf[1] = 0;
+	}
+
+	printf(PRINT_FIELD_SEGMENT, field->name);
+	int major = (field->buf[1] << 8 | field->buf[0]) / 100;
+	int minor = (field->buf[1] << 8 | field->buf[0]) - major * 100;
+	printf("%d.%02d\n", major, minor);
+}
+
+/**
+ * eeprom_field_update_bin_ver() - update a "version field" which contains
+ *				   binary data
+ *
+ * This function takes a version string in the form of x.y (x and y are both
+ * decimal values, y is limited to two digits), translates it to the binary
+ * form, then writes it to the field. The field size must be exactly 2 bytes.
+ *
+ * This function strictly enforces the data syntax, and will not update the
+ * field if there's any deviation from it. It also protects from overflow.
+ *
+ * @field:	an initialized field
+ * @value:	a version string
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int eeprom_field_update_bin_ver(struct eeprom_field *field, char *value)
+{
+	char *endptr;
+	char *tok = strtok(value, ".");
+	if (tok == NULL)
+		return -1;
+
+	int num = simple_strtol(tok, &endptr, 0);
+	if (*endptr != '\0')
+		return -1;
+
+	tok = strtok(NULL, "");
+	if (tok == NULL)
+		return -1;
+
+	int remainder = simple_strtol(tok, &endptr, 0);
+	if (*endptr != '\0')
+		return -1;
+
+	num = num * 100 + remainder;
+	if (num >> 16)
+		return -1;
+
+	field->buf[0] = (unsigned char)num;
+	field->buf[1] = num >> 8;
+
+	return 0;
+}
+
+char *months[12] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+
+/**
+ * eeprom_field_print_date() - print a field which contains date data
+ *
+ * Treat the field data as simple binary data, and print it formatted as a date.
+ * Sample output:
+ *      Field Name      07/Feb/2014
+ *      Field Name      56/BAD/9999
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_date(const struct eeprom_field *field)
+{
+	printf(PRINT_FIELD_SEGMENT, field->name);
+	printf("%02d/", field->buf[0]);
+	if (field->buf[1] >= 1 && field->buf[1] <= 12)
+		printf("%s", months[field->buf[1] - 1]);
+	else
+		printf("BAD");
+
+	printf("/%d\n", field->buf[3] << 8 | field->buf[2]);
+}
+
+static int validate_date(unsigned char day, unsigned char month,
+			unsigned int year)
+{
+	int days_in_february;
+
+	switch (month) {
+	case 0:
+	case 2:
+	case 4:
+	case 6:
+	case 7:
+	case 9:
+	case 11:
+		if (day > 31)
+			return -1;
+		break;
+	case 3:
+	case 5:
+	case 8:
+	case 10:
+		if (day > 30)
+			return -1;
+		break;
+	case 1:
+		days_in_february = 28;
+		if (year % 4 == 0) {
+			if (year % 100 != 0)
+				days_in_february = 29;
+			else if (year % 400 == 0)
+				days_in_february = 29;
+		}
+
+		if (day > days_in_february)
+			return -1;
+
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * eeprom_field_update_date() - update a date field which contains binary data
+ *
+ * This function takes a date string in the form of x/Mon/y (x and y are both
+ * decimal values), translates it to the binary representation, then writes it
+ * to the field.
+ *
+ * This function strictly enforces the data syntax, and will not update the
+ * field if there's any deviation from it. It also protects from overflow in the
+ * year value, and checks the validity of the date.
+ *
+ * @field:	an initialized field
+ * @value:	a date string
+ *
+ * Returns 0 on success, -1 on failure.
+ */
+int eeprom_field_update_date(struct eeprom_field *field, char *value)
+{
+	char *endptr;
+	char *tok1 = strtok(value, "/");
+	char *tok2 = strtok(NULL, "/");
+	char *tok3 = strtok(NULL, "/");
+
+	if (tok1 == NULL || tok2 == NULL || tok3 == NULL) {
+		printf("%s: syntax error\n", field->name);
+		return -1;
+	}
+
+	unsigned char day = (unsigned char)simple_strtol(tok1, &endptr, 0);
+	if (*endptr != '\0' || day == 0) {
+		printf("%s: invalid day\n", field->name);
+		return -1;
+	}
+
+	unsigned char month;
+	for (month = 1; month <= 12; month++)
+		if (!strcmp(tok2, months[month - 1]))
+			break;
+
+	unsigned int year = simple_strtol(tok3, &endptr, 0);
+	if (*endptr != '\0') {
+		printf("%s: invalid year\n", field->name);
+		return -1;
+	}
+
+	if (validate_date(day, month - 1, year)) {
+		printf("%s: invalid date\n", field->name);
+		return -1;
+	}
+
+	if (year >> 16) {
+		printf("%s: year overflow\n", field->name);
+		return -1;
+	}
+
+	field->buf[0] = day;
+	field->buf[1] = month;
+	field->buf[2] = (unsigned char)year;
+	field->buf[3] = (unsigned char)(year >> 8);
+
+	return 0;
+}
+
+#define	LAYOUT_VERSION_LEGACY 1
+#define	LAYOUT_VERSION_VER1 2
+#define	LAYOUT_VERSION_VER2 3
+#define	LAYOUT_VERSION_VER3 4
+
+extern struct eeprom_field layout_unknown[1];
+
+#define DEFINE_PRINT_UPDATE(x) eeprom_field_print_##x, eeprom_field_update_##x
+
+#ifdef CONFIG_CM_T3X
+struct eeprom_field layout_legacy[5] = {
+	{ "MAC address",          6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Board Revision",       2, NULL, DEFINE_PRINT_UPDATE(bin) },
+	{ "Serial Number",        8, NULL, DEFINE_PRINT_UPDATE(bin) },
+	{ "Board Configuration", 64, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ RESERVED_FIELDS,      176, NULL, eeprom_field_print_reserved,
+					   eeprom_field_update_ascii },
+};
+#else
+#define layout_legacy layout_unknown
+#endif
+
+#if defined(CONFIG_CM_T3X) || defined(CONFIG_CM_T3517)
+struct eeprom_field layout_v1[12] = {
+	{ "Major Revision",      2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "Minor Revision",      2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "1st MAC Address",     6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "2nd MAC Address",     6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Production Date",     4, NULL, DEFINE_PRINT_UPDATE(date) },
+	{ "Serial Number",      12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
+	{ RESERVED_FIELDS,      96, NULL, DEFINE_PRINT_UPDATE(reserved) },
+	{ "Product Name",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #1", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #2", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #3", 16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ RESERVED_FIELDS,      64, NULL, eeprom_field_print_reserved,
+					  eeprom_field_update_ascii },
+};
+#else
+#define layout_v1 layout_unknown
+#endif
+
+struct eeprom_field layout_v2[15] = {
+	{ "Major Revision",            2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "Minor Revision",            2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "1st MAC Address",           6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "2nd MAC Address",           6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Production Date",           4, NULL, DEFINE_PRINT_UPDATE(date) },
+	{ "Serial Number",            12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
+	{ "3rd MAC Address (WIFI)",    6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "4th MAC Address (Bluetooth)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Layout Version",            1, NULL, DEFINE_PRINT_UPDATE(bin) },
+	{ RESERVED_FIELDS,            83, NULL, DEFINE_PRINT_UPDATE(reserved) },
+	{ "Product Name",             16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #1",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #2",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #3",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ RESERVED_FIELDS,            64, NULL, eeprom_field_print_reserved,
+						eeprom_field_update_ascii },
+};
+
+struct eeprom_field layout_v3[16] = {
+	{ "Major Revision",            2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "Minor Revision",            2, NULL, DEFINE_PRINT_UPDATE(bin_ver) },
+	{ "1st MAC Address",           6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "2nd MAC Address",           6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Production Date",           4, NULL, DEFINE_PRINT_UPDATE(date) },
+	{ "Serial Number",            12, NULL, DEFINE_PRINT_UPDATE(bin_rev) },
+	{ "3rd MAC Address (WIFI)",    6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "4th MAC Address (Bluetooth)", 6, NULL, DEFINE_PRINT_UPDATE(mac) },
+	{ "Layout Version",            1, NULL, DEFINE_PRINT_UPDATE(bin) },
+	{ "CompuLab EEPROM ID",        3, NULL, DEFINE_PRINT_UPDATE(bin) },
+	{ RESERVED_FIELDS,            80, NULL, DEFINE_PRINT_UPDATE(reserved) },
+	{ "Product Name",             16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #1",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #2",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ "Product Options #3",       16, NULL, DEFINE_PRINT_UPDATE(ascii) },
+	{ RESERVED_FIELDS,            64, NULL, eeprom_field_print_reserved,
+						eeprom_field_update_ascii },
+};
+
+void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version)
+{
+	switch (layout->layout_version) {
+	case LAYOUT_VERSION_LEGACY:
+		layout->fields = layout_legacy;
+		layout->num_of_fields = ARRAY_SIZE(layout_legacy);
+		break;
+	case LAYOUT_VERSION_VER1:
+		layout->fields = layout_v1;
+		layout->num_of_fields = ARRAY_SIZE(layout_v1);
+		break;
+	case LAYOUT_VERSION_VER2:
+		layout->fields = layout_v2;
+		layout->num_of_fields = ARRAY_SIZE(layout_v2);
+		break;
+	case LAYOUT_VERSION_VER3:
+		layout->fields = layout_v3;
+		layout->num_of_fields = ARRAY_SIZE(layout_v3);
+		break;
+	default:
+		__eeprom_layout_assign(layout, layout_version);
+	}
+}
+
+int eeprom_parse_layout_version(char *str)
+{
+	if (!strcmp(str, "legacy"))
+		return LAYOUT_VERSION_LEGACY;
+	else if (!strcmp(str, "v1"))
+		return LAYOUT_VERSION_VER1;
+	else if (!strcmp(str, "v2"))
+		return LAYOUT_VERSION_VER2;
+	else if (!strcmp(str, "v3"))
+		return LAYOUT_VERSION_VER3;
+	else
+		return LAYOUT_VERSION_UNRECOGNIZED;
+}
+
+int eeprom_layout_detect(unsigned char *data)
+{
+	switch (data[EEPROM_LAYOUT_VER_OFFSET]) {
+	case 0xff:
+	case 0:
+		return LAYOUT_VERSION_VER1;
+	case 2:
+		return LAYOUT_VERSION_VER2;
+	case 3:
+		return LAYOUT_VERSION_VER3;
+	}
+
+	if (data[EEPROM_LAYOUT_VER_OFFSET] >= 0x20)
+		return LAYOUT_VERSION_LEGACY;
+
+	return LAYOUT_VERSION_UNRECOGNIZED;
+}
+#endif
diff --git a/board/imgtec/malta/lowlevel_init.S b/board/imgtec/malta/lowlevel_init.S
index ae09c27..534db1d 100644
--- a/board/imgtec/malta/lowlevel_init.S
+++ b/board/imgtec/malta/lowlevel_init.S
@@ -24,7 +24,6 @@
 
 	.text
 	.set noreorder
-	.set mips32
 
 	.globl	lowlevel_init
 lowlevel_init:
diff --git a/board/keymile/km83xx/km83xx_i2c.c b/board/keymile/km83xx/km83xx_i2c.c
index c961937..f0b528d 100644
--- a/board/keymile/km83xx/km83xx_i2c.c
+++ b/board/keymile/km83xx/km83xx_i2c.c
@@ -13,31 +13,33 @@
 
 static void i2c_write_start_seq(void)
 {
-	struct fsl_i2c *dev;
-	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
+	struct fsl_i2c_base *base;
+	base = (struct fsl_i2c_base *)(CONFIG_SYS_IMMR +
+			CONFIG_SYS_I2C_OFFSET);
 	udelay(DELAY_ABORT_SEQ);
-	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
+	out_8(&base->cr, (I2C_CR_MEN | I2C_CR_MSTA));
 	udelay(DELAY_ABORT_SEQ);
-	out_8(&dev->cr, (I2C_CR_MEN));
+	out_8(&base->cr, (I2C_CR_MEN));
 }
 
 int i2c_make_abort(void)
 {
-	struct fsl_i2c *dev;
-	dev = (struct fsl_i2c *) (CONFIG_SYS_IMMR + CONFIG_SYS_I2C_OFFSET);
+	struct fsl_i2c_base *base;
+	base = (struct fsl_i2c_base *)(CONFIG_SYS_IMMR +
+			CONFIG_SYS_I2C_OFFSET);
 	uchar   last;
 	int     nbr_read = 0;
 	int     i = 0;
 	int	    ret = 0;
 
 	/* wait after each operation to finsh with a delay */
-	out_8(&dev->cr, (I2C_CR_MSTA));
+	out_8(&base->cr, (I2C_CR_MSTA));
 	udelay(DELAY_ABORT_SEQ);
-	out_8(&dev->cr, (I2C_CR_MEN | I2C_CR_MSTA));
+	out_8(&base->cr, (I2C_CR_MEN | I2C_CR_MSTA));
 	udelay(DELAY_ABORT_SEQ);
-	in_8(&dev->dr);
+	in_8(&base->dr);
 	udelay(DELAY_ABORT_SEQ);
-	last = in_8(&dev->dr);
+	last = in_8(&base->dr);
 	nbr_read++;
 
 	/*
@@ -47,7 +49,7 @@
 	while (((last & 0x01) != 0x01) &&
 		(nbr_read < CONFIG_SYS_IVM_EEPROM_MAX_LEN)) {
 		udelay(DELAY_ABORT_SEQ);
-		last = in_8(&dev->dr);
+		last = in_8(&base->dr);
 		nbr_read++;
 	}
 	if ((last & 0x01) != 0x01)
@@ -56,10 +58,10 @@
 		printf("[INFO] i2c abort after %d bytes (0x%02x)\n",
 			nbr_read, last);
 	udelay(DELAY_ABORT_SEQ);
-	out_8(&dev->cr, (I2C_CR_MEN));
+	out_8(&base->cr, (I2C_CR_MEN));
 	udelay(DELAY_ABORT_SEQ);
 	/* clear status reg */
-	out_8(&dev->sr, 0);
+	out_8(&base->sr, 0);
 
 	for (i = 0; i < 5; i++)
 		i2c_write_start_seq();
diff --git a/board/mpl/pip405/README b/board/mpl/pip405/README
index e900c56..f039817 100644
--- a/board/mpl/pip405/README
+++ b/board/mpl/pip405/README
@@ -32,8 +32,8 @@
 - include/cmd_bsp.h		added PIP405 commands definitions
 - include/cmd_condefs.h		added Floppy and SCSI support
 - include/cmd_disk.h		changed to work with block device description
-- include/config_LANTEC.h	excluded CONFIG_CMD_FDC and CONFIG_CMD_SCSI
-- include/config_hymod.h	excluded CONFIG_CMD_FDC and CONFIG_CMD_SCSI
+- include/config_LANTEC.h	excluded CONFIG_CMD_FDC and CONFIG_SCSI
+- include/config_hymod.h	excluded CONFIG_CMD_FDC and CONFIG_SCSI
 - include/flash.h		added INTEL_ID_28F320C3T  0x88C488C4
 - include/i2c.h			added "defined(CONFIG_PIP405)"
 - include/image.h		added IH_OS_U_BOOT, IH_TYPE_FIRMWARE
@@ -86,7 +86,7 @@
 
 New Commands:
 -------------
-CONFIG_CMD_SCSI	SCSI Support
+CONFIG_SCSI	SCSI Support
 CONFIG_CMF_FDC	Floppy disk support
 
 IDE additions:
diff --git a/board/qca/ap121/Kconfig b/board/qca/ap121/Kconfig
new file mode 100644
index 0000000..f7e768a
--- /dev/null
+++ b/board/qca/ap121/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_AP121
+
+config SYS_VENDOR
+	default "qca"
+
+config SYS_BOARD
+	default "ap121"
+
+config SYS_CONFIG_NAME
+	default "ap121"
+
+endif
diff --git a/board/qca/ap121/MAINTAINERS b/board/qca/ap121/MAINTAINERS
new file mode 100644
index 0000000..8b02988
--- /dev/null
+++ b/board/qca/ap121/MAINTAINERS
@@ -0,0 +1,6 @@
+AP121 BOARD
+M:	Wills Wang <wills.wang@live.com>
+S:	Maintained
+F:	board/qca/ap121/
+F:	include/configs/ap121.h
+F:	configs/ap121_defconfig
diff --git a/board/qca/ap121/Makefile b/board/qca/ap121/Makefile
new file mode 100644
index 0000000..ced5432
--- /dev/null
+++ b/board/qca/ap121/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= ap121.o
diff --git a/board/qca/ap121/ap121.c b/board/qca/ap121/ap121.c
new file mode 100644
index 0000000..d6c60fe
--- /dev/null
+++ b/board/qca/ap121/ap121.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/*
+	 * GPIO9 as input, GPIO10 as output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OE);
+	val &= ~AR933X_GPIO(9);
+	val |= AR933X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OE);
+
+	/*
+	 * Enable UART, GPIO9 as UART_SI, GPIO10 as UART_SO
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_FUNC);
+	val |= AR933X_GPIO_FUNC_UART_EN | AR933X_GPIO_FUNC_RES_TRUE;
+	writel(val, regs + AR71XX_GPIO_REG_FUNC);
+}
+#endif
+
+int board_early_init_f(void)
+{
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+	ddr_init();
+	return 0;
+}
diff --git a/board/qca/ap143/Kconfig b/board/qca/ap143/Kconfig
new file mode 100644
index 0000000..4cdac0d
--- /dev/null
+++ b/board/qca/ap143/Kconfig
@@ -0,0 +1,12 @@
+if TARGET_AP143
+
+config SYS_VENDOR
+	default "qca"
+
+config SYS_BOARD
+	default "ap143"
+
+config SYS_CONFIG_NAME
+	default "ap143"
+
+endif
diff --git a/board/qca/ap143/MAINTAINERS b/board/qca/ap143/MAINTAINERS
new file mode 100644
index 0000000..11cb14f
--- /dev/null
+++ b/board/qca/ap143/MAINTAINERS
@@ -0,0 +1,6 @@
+AP143 BOARD
+M:	Wills Wang <wills.wang@live.com>
+S:	Maintained
+F:	board/qca/ap143/
+F:	include/configs/ap143.h
+F:	configs/ap143_defconfig
diff --git a/board/qca/ap143/Makefile b/board/qca/ap143/Makefile
new file mode 100644
index 0000000..00f7837
--- /dev/null
+++ b/board/qca/ap143/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= ap143.o
diff --git a/board/qca/ap143/ap143.c b/board/qca/ap143/ap143.c
new file mode 100644
index 0000000..1572472
--- /dev/null
+++ b/board/qca/ap143/ap143.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_DEBUG_UART_BOARD_INIT
+void board_debug_uart_init(void)
+{
+	void __iomem *regs;
+	u32 val;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/*
+	 * GPIO9 as input, GPIO10 as output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OE);
+	val |= QCA953X_GPIO(9);
+	val &= ~QCA953X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OE);
+
+	/*
+	 * Enable GPIO10 as UART0_SOUT
+	 */
+	val = readl(regs + QCA953X_GPIO_REG_OUT_FUNC2);
+	val &= ~QCA953X_GPIO_MUX_MASK(16);
+	val |= QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16;
+	writel(val, regs + QCA953X_GPIO_REG_OUT_FUNC2);
+
+	/*
+	 * Enable GPIO9 as UART0_SIN
+	 */
+	val = readl(regs + QCA953X_GPIO_REG_IN_ENABLE0);
+	val &= ~QCA953X_GPIO_MUX_MASK(8);
+	val |= QCA953X_GPIO_IN_MUX_UART0_SIN << 8;
+	writel(val, regs + QCA953X_GPIO_REG_IN_ENABLE0);
+
+	/*
+	 * Enable GPIO10 output
+	 */
+	val = readl(regs + AR71XX_GPIO_REG_OUT);
+	val |= QCA953X_GPIO(10);
+	writel(val, regs + AR71XX_GPIO_REG_OUT);
+}
+#endif
+
+int board_early_init_f(void)
+{
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+	ddr_init();
+	return 0;
+}
diff --git a/board/sandbox/MAINTAINERS b/board/sandbox/MAINTAINERS
index 10d88a2..f5db773 100644
--- a/board/sandbox/MAINTAINERS
+++ b/board/sandbox/MAINTAINERS
@@ -4,3 +4,10 @@
 F:	board/sandbox/
 F:	include/configs/sandbox.h
 F:	configs/sandbox_defconfig
+
+SANDBOX_NOBLK BOARD
+M:	Simon Glass <sjg@chromium.org>
+S:	Maintained
+F:	board/sandbox/
+F:	include/configs/sandbox.h
+F:	configs/sandbox_noblk_defconfig
diff --git a/board/tplink/wdr4300/Kconfig b/board/tplink/wdr4300/Kconfig
new file mode 100644
index 0000000..902abf5
--- /dev/null
+++ b/board/tplink/wdr4300/Kconfig
@@ -0,0 +1,15 @@
+if BOARD_TPLINK_WDR4300
+
+config SYS_VENDOR
+	default "tplink"
+
+config SYS_SOC
+	default "ath79"
+
+config SYS_BOARD
+	default "wdr4300"
+
+config SYS_CONFIG_NAME
+	default "tplink_wdr4300"
+
+endif
diff --git a/board/tplink/wdr4300/MAINTAINERS b/board/tplink/wdr4300/MAINTAINERS
new file mode 100644
index 0000000..db239c2
--- /dev/null
+++ b/board/tplink/wdr4300/MAINTAINERS
@@ -0,0 +1,6 @@
+TPLINK_WDR4300 BOARD
+M:	Marek Vasut <marex@denx.de>
+S:	Maintained
+F:	board/tplink/wdr4300/
+F:	include/configs/tplink_wdr4300.h
+F:	configs/tplink_wdr4300_defconfig
diff --git a/board/tplink/wdr4300/Makefile b/board/tplink/wdr4300/Makefile
new file mode 100644
index 0000000..4f0c296
--- /dev/null
+++ b/board/tplink/wdr4300/Makefile
@@ -0,0 +1,5 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-y	= wdr4300.o
diff --git a/board/tplink/wdr4300/wdr4300.c b/board/tplink/wdr4300/wdr4300.c
new file mode 100644
index 0000000..6e070fd
--- /dev/null
+++ b/board/tplink/wdr4300/wdr4300.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <mach/ath79.h>
+#include <mach/ar71xx_regs.h>
+#include <mach/ddr.h>
+#include <debug_uart.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#ifdef CONFIG_USB
+static void wdr4300_usb_start(void)
+{
+	void __iomem *gpio_regs = map_physmem(AR71XX_GPIO_BASE,
+					      AR71XX_GPIO_SIZE, MAP_NOCACHE);
+	if (!gpio_regs)
+		return;
+
+	/* Power up the USB HUB. */
+	clrbits_be32(gpio_regs + AR71XX_GPIO_REG_OE, BIT(21) | BIT(22));
+	writel(BIT(21) | BIT(22), gpio_regs + AR71XX_GPIO_REG_SET);
+	mdelay(1);
+
+	ath79_usb_reset();
+}
+#else
+static inline void wdr4300_usb_start(void) {}
+#endif
+
+#ifdef CONFIG_BOARD_EARLY_INIT_F
+int board_early_init_f(void)
+{
+	void __iomem *regs;
+
+	regs = map_physmem(AR71XX_GPIO_BASE, AR71XX_GPIO_SIZE,
+			   MAP_NOCACHE);
+
+	/* Assure JTAG is not disconnected. */
+	writel(0x40, regs + AR934X_GPIO_REG_FUNC);
+
+	/* Configure default GPIO input/output regs. */
+	writel(0x3031b, regs + AR71XX_GPIO_REG_OE);
+	writel(0x0f804, regs + AR71XX_GPIO_REG_OUT);
+
+	/* Configure pin multiplexing. */
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC0);
+	writel(0x0b0a0980, regs + AR934X_GPIO_REG_OUT_FUNC1);
+	writel(0x00180000, regs + AR934X_GPIO_REG_OUT_FUNC2);
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC3);
+	writel(0x0000004d, regs + AR934X_GPIO_REG_OUT_FUNC4);
+	writel(0x00000000, regs + AR934X_GPIO_REG_OUT_FUNC5);
+
+#ifdef CONFIG_DEBUG_UART
+	debug_uart_init();
+#endif
+
+#ifndef CONFIG_SKIP_LOWLEVEL_INIT
+	ar934x_pll_init(560, 480, 240);
+	ar934x_ddr_init(560, 480, 240);
+#endif
+
+	wdr4300_usb_start();
+	ath79_eth_reset();
+
+	return 0;
+}
+#endif
diff --git a/cmd/Makefile b/cmd/Makefile
index f95759e..e3e0c74 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -112,7 +112,7 @@
 obj-$(CONFIG_SANDBOX) += host.o
 obj-$(CONFIG_CMD_SATA) += sata.o
 obj-$(CONFIG_CMD_SF) += sf.o
-obj-$(CONFIG_CMD_SCSI) += scsi.o
+obj-$(CONFIG_SCSI) += scsi.o
 obj-$(CONFIG_CMD_SHA1SUM) += sha1sum.o
 obj-$(CONFIG_CMD_SETEXPR) += setexpr.o
 obj-$(CONFIG_CMD_SOFTSWITCH) += softswitch.o
@@ -155,12 +155,6 @@
 obj-$(CONFIG_CMD_REGULATOR) += regulator.o
 endif # !CONFIG_SPL_BUILD
 
-ifdef CONFIG_SPL_BUILD
-ifdef CONFIG_SPL_SATA_SUPPORT
-obj-$(CONFIG_CMD_SCSI) += scsi.o
-endif
-endif # CONFIG_SPL_BUILD
-
 obj-$(CONFIG_CMD_BLOB) += blob.o
 
 # core command
diff --git a/cmd/bdinfo.c b/cmd/bdinfo.c
index 8eda68b..1c4bed9 100644
--- a/cmd/bdinfo.c
+++ b/cmd/bdinfo.c
@@ -341,6 +341,8 @@
 	print_eth(0);
 	printf("ip_addr     = %s\n", getenv("ipaddr"));
 	printf("baudrate    = %u bps\n", gd->baudrate);
+	print_num("relocaddr", gd->relocaddr);
+	print_num("reloc off", gd->reloc_off);
 
 	return 0;
 }
diff --git a/cmd/disk.c b/cmd/disk.c
index 2fd1717..fcc4123 100644
--- a/cmd/disk.c
+++ b/cmd/disk.c
@@ -8,7 +8,7 @@
 #include <command.h>
 #include <part.h>
 
-#if defined(CONFIG_CMD_IDE) || defined(CONFIG_CMD_SCSI) || \
+#if defined(CONFIG_CMD_IDE) || defined(CONFIG_SCSI) || \
 	defined(CONFIG_USB_STORAGE)
 int common_diskboot(cmd_tbl_t *cmdtp, const char *intf, int argc,
 		    char *const argv[])
diff --git a/cmd/eeprom.c b/cmd/eeprom.c
index e5457ba..0a0e4a2 100644
--- a/cmd/eeprom.c
+++ b/cmd/eeprom.c
@@ -24,6 +24,7 @@
 #include <config.h>
 #include <command.h>
 #include <i2c.h>
+#include <eeprom_layout.h>
 
 #ifndef	CONFIG_SYS_I2C_SPEED
 #define	CONFIG_SYS_I2C_SPEED	50000
@@ -72,7 +73,7 @@
 #endif
 
 	/* I2C EEPROM */
-#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C_SOFT)
+#if defined(CONFIG_HARD_I2C) || defined(CONFIG_SYS_I2C)
 #if defined(CONFIG_SYS_I2C)
 	if (bus >= 0)
 		i2c_set_bus_num(bus);
@@ -207,63 +208,243 @@
 	return ret;
 }
 
-static int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+static int parse_numeric_param(char *str)
 {
-	const char *const fmt =
-		"\nEEPROM @0x%lX %s: addr %08lx  off %04lx  count %ld ... ";
-	char * const *args = &argv[2];
-	int rcode;
-	ulong dev_addr, addr, off, cnt;
-	int bus_addr;
+	char *endptr;
+	int value = simple_strtol(str, &endptr, 16);
 
-	switch (argc) {
+	return (*endptr != '\0') ? -1 : value;
+}
+
+/**
+ * parse_i2c_bus_addr - parse the i2c bus and i2c devaddr parameters
+ *
+ * @i2c_bus:	address to store the i2c bus
+ * @i2c_addr:	address to store the device i2c address
+ * @argc:	count of command line arguments left to parse
+ * @argv:	command line arguments left to parse
+ * @argc_no_bus_addr:	argc value we expect to see when bus & addr aren't given
+ *
+ * @returns:	number of arguments parsed or CMD_RET_USAGE if error
+ */
+static int parse_i2c_bus_addr(int *i2c_bus, ulong *i2c_addr, int argc,
+			      char * const argv[], int argc_no_bus_addr)
+{
+	int argc_no_bus = argc_no_bus_addr + 1;
+	int argc_bus_addr = argc_no_bus_addr + 2;
+
 #ifdef CONFIG_SYS_DEF_EEPROM_ADDR
-	case 5:
-		bus_addr = -1;
-		dev_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
-		break;
+	if (argc == argc_no_bus_addr) {
+		*i2c_bus = -1;
+		*i2c_addr = CONFIG_SYS_DEF_EEPROM_ADDR;
+
+		return 0;
+	}
 #endif
-	case 6:
-		bus_addr = -1;
-		dev_addr = simple_strtoul(*args++, NULL, 16);
-		break;
-	case 7:
-		bus_addr = simple_strtoul(*args++, NULL, 16);
-		dev_addr = simple_strtoul(*args++, NULL, 16);
-		break;
-	default:
-		return CMD_RET_USAGE;
+	if (argc == argc_no_bus) {
+		*i2c_bus = -1;
+		*i2c_addr = parse_numeric_param(argv[0]);
+
+		return 1;
 	}
 
-	addr = simple_strtoul(*args++, NULL, 16);
-	off = simple_strtoul(*args++, NULL, 16);
-	cnt = simple_strtoul(*args++, NULL, 16);
+	if (argc == argc_bus_addr) {
+		*i2c_bus = parse_numeric_param(argv[0]);
+		*i2c_addr = parse_numeric_param(argv[1]);
 
-	eeprom_init(bus_addr);
-
-	if (strcmp(argv[1], "read") == 0) {
-		printf(fmt, dev_addr, argv[1], addr, off, cnt);
-
-		rcode = eeprom_read(dev_addr, off, (uchar *)addr, cnt);
-
-		puts("done\n");
-		return rcode;
-	} else if (strcmp(argv[1], "write") == 0) {
-		printf(fmt, dev_addr, argv[1], addr, off, cnt);
-
-		rcode = eeprom_write(dev_addr, off, (uchar *)addr, cnt);
-
-		puts("done\n");
-		return rcode;
+		return 2;
 	}
 
 	return CMD_RET_USAGE;
 }
 
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+
+__weak int eeprom_parse_layout_version(char *str)
+{
+	return LAYOUT_VERSION_UNRECOGNIZED;
+}
+
+static unsigned char eeprom_buf[CONFIG_SYS_EEPROM_SIZE];
+
+#ifndef CONFIG_EEPROM_LAYOUT_HELP_STRING
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "<not defined>"
+#endif
+
+#endif
+
+enum eeprom_action {
+	EEPROM_READ,
+	EEPROM_WRITE,
+	EEPROM_PRINT,
+	EEPROM_UPDATE,
+	EEPROM_ACTION_INVALID,
+};
+
+static enum eeprom_action parse_action(char *cmd)
+{
+	if (!strncmp(cmd, "read", 4))
+		return EEPROM_READ;
+	if (!strncmp(cmd, "write", 5))
+		return EEPROM_WRITE;
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	if (!strncmp(cmd, "print", 5))
+		return EEPROM_PRINT;
+	if (!strncmp(cmd, "update", 6))
+		return EEPROM_UPDATE;
+#endif
+
+	return EEPROM_ACTION_INVALID;
+}
+
+static int eeprom_execute_command(enum eeprom_action action, int i2c_bus,
+				  ulong i2c_addr, int layout_ver, char *key,
+				  char *value, ulong addr, ulong off, ulong cnt)
+{
+	int rcode = 0;
+	const char *const fmt =
+		"\nEEPROM @0x%lX %s: addr %08lx  off %04lx  count %ld ... ";
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	struct eeprom_layout layout;
+#endif
+
+	if (action == EEPROM_ACTION_INVALID)
+		return CMD_RET_USAGE;
+
+	eeprom_init(i2c_bus);
+	if (action == EEPROM_READ) {
+		printf(fmt, i2c_addr, "read", addr, off, cnt);
+
+		rcode = eeprom_read(i2c_addr, off, (uchar *)addr, cnt);
+
+		puts("done\n");
+		return rcode;
+	} else if (action == EEPROM_WRITE) {
+		printf(fmt, i2c_addr, "write", addr, off, cnt);
+
+		rcode = eeprom_write(i2c_addr, off, (uchar *)addr, cnt);
+
+		puts("done\n");
+		return rcode;
+	}
+
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	rcode = eeprom_read(i2c_addr, 0, eeprom_buf, CONFIG_SYS_EEPROM_SIZE);
+	if (rcode < 0)
+		return rcode;
+
+	eeprom_layout_setup(&layout, eeprom_buf, CONFIG_SYS_EEPROM_SIZE,
+			    layout_ver);
+
+	if (action == EEPROM_PRINT) {
+		layout.print(&layout);
+		return 0;
+	}
+
+	layout.update(&layout, key, value);
+
+	rcode = eeprom_write(i2c_addr, 0, layout.data, CONFIG_SYS_EEPROM_SIZE);
+#endif
+
+	return rcode;
+}
+
+#define NEXT_PARAM(argc, index)	{ (argc)--; (index)++; }
+int do_eeprom(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	int layout_ver = LAYOUT_VERSION_AUTODETECT;
+	enum eeprom_action action = EEPROM_ACTION_INVALID;
+	int i2c_bus = -1, index = 0;
+	ulong i2c_addr = -1, addr = 0, cnt = 0, off = 0;
+	int ret;
+	char *field_name = "";
+	char *field_value = "";
+
+	if (argc <= 1)
+		return CMD_RET_USAGE;
+
+	NEXT_PARAM(argc, index); /* Skip program name */
+
+	action = parse_action(argv[index]);
+	NEXT_PARAM(argc, index);
+
+	if (action == EEPROM_ACTION_INVALID)
+		return CMD_RET_USAGE;
+
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	if (action == EEPROM_PRINT || action == EEPROM_UPDATE) {
+		if (!strcmp(argv[index], "-l")) {
+			NEXT_PARAM(argc, index);
+			layout_ver = eeprom_parse_layout_version(argv[index]);
+			NEXT_PARAM(argc, index);
+		}
+	}
+#endif
+
+	switch (action) {
+	case EEPROM_READ:
+	case EEPROM_WRITE:
+		ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
+					 argv + index, 3);
+		break;
+	case EEPROM_PRINT:
+		ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
+					 argv + index, 0);
+		break;
+	case EEPROM_UPDATE:
+		ret = parse_i2c_bus_addr(&i2c_bus, &i2c_addr, argc,
+					 argv + index, 2);
+		break;
+	default:
+		/* Get compiler to stop whining */
+		return CMD_RET_USAGE;
+	}
+
+	if (ret == CMD_RET_USAGE)
+		return ret;
+
+	while (ret--)
+		NEXT_PARAM(argc, index);
+
+	if (action == EEPROM_READ || action == EEPROM_WRITE) {
+		addr = parse_numeric_param(argv[index]);
+		NEXT_PARAM(argc, index);
+		off = parse_numeric_param(argv[index]);
+		NEXT_PARAM(argc, index);
+		cnt = parse_numeric_param(argv[index]);
+	}
+
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	if (action == EEPROM_UPDATE) {
+		field_name = argv[index];
+		NEXT_PARAM(argc, index);
+		field_value = argv[index];
+		NEXT_PARAM(argc, index);
+	}
+#endif
+
+	return eeprom_execute_command(action, i2c_bus, i2c_addr, layout_ver,
+				      field_name, field_value, addr, off, cnt);
+}
+
 U_BOOT_CMD(
-	eeprom,	7,	1,	do_eeprom,
+	eeprom,	8,	1,	do_eeprom,
 	"EEPROM sub-system",
 	"read  <bus> <devaddr> addr off cnt\n"
 	"eeprom write <bus> <devaddr> addr off cnt\n"
 	"       - read/write `cnt' bytes from `devaddr` EEPROM at offset `off'"
+#ifdef CONFIG_CMD_EEPROM_LAYOUT
+	"\n"
+	"eeprom print [-l <layout_version>] <bus> <devaddr>\n"
+	"       - Print layout fields and their data in human readable format\n"
+	"eeprom update [-l <layout_version>] <bus> <devaddr> field_name field_value\n"
+	"       - Update a specific eeprom field with new data.\n"
+	"         The new data must be written in the same human readable format as shown by the print command.\n"
+	"\n"
+	"LAYOUT VERSIONS\n"
+	"The -l option can be used to force the command to interpret the EEPROM data using the chosen layout.\n"
+	"If the -l option is omitted, the command will auto detect the layout based on the data in the EEPROM.\n"
+	"The values which can be provided with the -l option are:\n"
+	CONFIG_EEPROM_LAYOUT_HELP_STRING"\n"
+#endif
 )
diff --git a/cmd/ide.c b/cmd/ide.c
index c4c08c8..c942744 100644
--- a/cmd/ide.c
+++ b/cmd/ide.c
@@ -29,64 +29,9 @@
 # include <status_led.h>
 #endif
 
-#ifdef __PPC__
-# define EIEIO		__asm__ volatile ("eieio")
-# define SYNC		__asm__ volatile ("sync")
-#else
-# define EIEIO		/* nothing */
-# define SYNC		/* nothing */
-#endif
-
-/* ------------------------------------------------------------------------- */
-
 /* Current I/O Device	*/
 static int curr_device = -1;
 
-/* Current offset for IDE0 / IDE1 bus access	*/
-ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS] = {
-#if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
-	CONFIG_SYS_ATA_IDE0_OFFSET,
-#endif
-#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) && (CONFIG_SYS_IDE_MAXBUS > 1)
-	CONFIG_SYS_ATA_IDE1_OFFSET,
-#endif
-};
-
-static int ide_bus_ok[CONFIG_SYS_IDE_MAXBUS];
-
-struct blk_desc ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
-/* ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_IDE_RESET
-static void  ide_reset (void);
-#else
-#define ide_reset()	/* dummy */
-#endif
-
-static void ide_ident(struct blk_desc *dev_desc);
-static uchar ide_wait  (int dev, ulong t);
-
-#define IDE_TIME_OUT	2000	/* 2 sec timeout */
-
-#define ATAPI_TIME_OUT	7000	/* 7 sec timeout (5 sec seems to work...) */
-
-#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
-
-static void ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
-
-#ifndef CONFIG_SYS_ATA_PORT_ADDR
-#define CONFIG_SYS_ATA_PORT_ADDR(port) (port)
-#endif
-
-#ifdef CONFIG_ATAPI
-static void	atapi_inquiry(struct blk_desc *dev_desc);
-static ulong atapi_read(struct blk_desc *block_dev, lbaint_t blknr,
-			lbaint_t blkcnt, void *buffer);
-#endif
-
-
-/* ------------------------------------------------------------------------- */
-
 int do_ide(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	int rcode = 0;
@@ -106,79 +51,41 @@
 			ide_init();
 			return 0;
 		} else if (strncmp(argv[1], "inf", 3) == 0) {
-			int i;
-
-			putc('\n');
-
-			for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) {
-				if (ide_dev_desc[i].type == DEV_TYPE_UNKNOWN)
-					continue;  /* list only known devices */
-				printf("IDE device %d: ", i);
-				dev_print(&ide_dev_desc[i]);
-			}
+			blk_list_devices(IF_TYPE_IDE);
 			return 0;
 
 		} else if (strncmp(argv[1], "dev", 3) == 0) {
-			if ((curr_device < 0)
-			    || (curr_device >= CONFIG_SYS_IDE_MAXDEVICE)) {
-				puts("\nno IDE devices available\n");
-				return 1;
+			if (blk_print_device_num(IF_TYPE_IDE, curr_device)) {
+				printf("\nno IDE devices available\n");
+				return CMD_RET_FAILURE;
 			}
-			printf("\nIDE device %d: ", curr_device);
-			dev_print(&ide_dev_desc[curr_device]);
+
 			return 0;
 		} else if (strncmp(argv[1], "part", 4) == 0) {
-			int dev, ok;
-
-			for (ok = 0, dev = 0;
-			     dev < CONFIG_SYS_IDE_MAXDEVICE;
-			     ++dev) {
-				if (ide_dev_desc[dev].part_type !=
-				    PART_TYPE_UNKNOWN) {
-					++ok;
-					if (dev)
-						putc('\n');
-					part_print(&ide_dev_desc[dev]);
-				}
-			}
-			if (!ok) {
-				puts("\nno IDE devices available\n");
-				rcode++;
-			}
-			return rcode;
+			if (blk_list_part(IF_TYPE_IDE))
+				printf("\nno IDE devices available\n");
+			return 1;
 		}
 		return CMD_RET_USAGE;
 	case 3:
 		if (strncmp(argv[1], "dev", 3) == 0) {
-			int dev = (int) simple_strtoul(argv[2], NULL, 10);
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			printf("\nIDE device %d: ", dev);
-			if (dev >= CONFIG_SYS_IDE_MAXDEVICE) {
-				puts("unknown device\n");
-				return 1;
+			if (!blk_show_device(IF_TYPE_IDE, dev)) {
+				curr_device = dev;
+				printf("... is now current device\n");
+			} else {
+				return CMD_RET_FAILURE;
 			}
-			dev_print(&ide_dev_desc[dev]);
-			/*ide_print (dev); */
-
-			if (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN)
-				return 1;
-
-			curr_device = dev;
-
-			puts("... is now current device\n");
-
 			return 0;
 		} else if (strncmp(argv[1], "part", 4) == 0) {
-			int dev = (int) simple_strtoul(argv[2], NULL, 10);
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			if (ide_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
-				part_print(&ide_dev_desc[dev]);
-			} else {
-				printf("\nIDE device %d not available\n",
-				       dev);
-				rcode = 1;
+			if (blk_print_part_devnum(IF_TYPE_IDE, dev)) {
+				printf("\nIDE device %d not available\n", dev);
+				return CMD_RET_FAILURE;
 			}
-			return rcode;
+			return 1;
 		}
 
 		return CMD_RET_USAGE;
@@ -188,26 +95,22 @@
 		if (strcmp(argv[1], "read") == 0) {
 			ulong addr = simple_strtoul(argv[2], NULL, 16);
 			ulong cnt = simple_strtoul(argv[4], NULL, 16);
-			struct blk_desc *dev_desc;
 			ulong n;
 
 #ifdef CONFIG_SYS_64BIT_LBA
 			lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
 
-			printf("\nIDE read: device %d block # %lld, count %ld ... ",
-				curr_device, blk, cnt);
+			printf("\nIDE read: device %d block # %lld, count %ld...",
+			       curr_device, blk, cnt);
 #else
 			lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
 
-			printf("\nIDE read: device %d block # %ld, count %ld ... ",
-				curr_device, blk, cnt);
+			printf("\nIDE read: device %d block # %ld, count %ld...",
+			       curr_device, blk, cnt);
 #endif
 
-			dev_desc = &ide_dev_desc[curr_device];
-			n = blk_dread(dev_desc, blk, cnt, (ulong *)addr);
-			/* flush cache after read */
-			flush_cache(addr,
-				    cnt * ide_dev_desc[curr_device].blksz);
+			n = blk_read_devnum(IF_TYPE_IDE, curr_device, blk, cnt,
+					    (ulong *)addr);
 
 			printf("%ld blocks read: %s\n",
 			       n, (n == cnt) ? "OK" : "ERROR");
@@ -223,19 +126,19 @@
 #ifdef CONFIG_SYS_64BIT_LBA
 			lbaint_t blk = simple_strtoull(argv[3], NULL, 16);
 
-			printf("\nIDE write: device %d block # %lld, count %ld ... ",
-				curr_device, blk, cnt);
+			printf("\nIDE write: device %d block # %lld, count %ld...",
+			       curr_device, blk, cnt);
 #else
 			lbaint_t blk = simple_strtoul(argv[3], NULL, 16);
 
-			printf("\nIDE write: device %d block # %ld, count %ld ... ",
-				curr_device, blk, cnt);
+			printf("\nIDE write: device %d block # %ld, count %ld...",
+			       curr_device, blk, cnt);
 #endif
-			n = ide_write(&ide_dev_desc[curr_device], blk, cnt,
-				      (ulong *)addr);
+			n = blk_write_devnum(IF_TYPE_IDE, curr_device, blk, cnt,
+					     (ulong *)addr);
 
-			printf("%ld blocks written: %s\n",
-				n, (n == cnt) ? "OK" : "ERROR");
+			printf("%ld blocks written: %s\n", n,
+			       n == cnt ? "OK" : "ERROR");
 			if (n == cnt)
 				return 0;
 			else
@@ -253,1195 +156,6 @@
 	return common_diskboot(cmdtp, "ide", argc, argv);
 }
 
-/* ------------------------------------------------------------------------- */
-
-__weak void ide_led(uchar led, uchar status)
-{
-#if defined(CONFIG_IDE_LED) && defined(PER8_BASE) /* required by LED_PORT */
-	static uchar led_buffer;	/* Buffer for current LED status */
-
-	uchar *led_port = LED_PORT;
-
-	if (status)		/* switch LED on        */
-		led_buffer |= led;
-	else			/* switch LED off       */
-		led_buffer &= ~led;
-
-	*led_port = led_buffer;
-#endif
-}
-
-#ifndef CONFIG_IDE_LED	/* define LED macros, they are not used anyways */
-# define DEVICE_LED(x) 0
-# define LED_IDE1 1
-# define LED_IDE2 2
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-__weak void ide_outb(int dev, int port, unsigned char val)
-{
-	debug("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n",
-	      dev, port, val,
-	      (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
-
-#if defined(CONFIG_IDE_AHB)
-	if (port) {
-		/* write command */
-		ide_write_register(dev, port, val);
-	} else {
-		/* write data */
-		outb(val, (ATA_CURR_BASE(dev)));
-	}
-#else
-	outb(val, (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
-#endif
-}
-
-__weak unsigned char ide_inb(int dev, int port)
-{
-	uchar val;
-
-#if defined(CONFIG_IDE_AHB)
-	val = ide_read_register(dev, port);
-#else
-	val = inb((ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
-#endif
-
-	debug("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n",
-	      dev, port,
-	      (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)), val);
-	return val;
-}
-
-void ide_init(void)
-{
-	unsigned char c;
-	int i, bus;
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-	extern int ide_devices_found;	/* Initialized in check_ide_device() */
-#endif /* CONFIG_IDE_8xx_PCCARD */
-
-#ifdef CONFIG_IDE_PREINIT
-	WATCHDOG_RESET();
-
-	if (ide_preinit()) {
-		puts("ide_preinit failed\n");
-		return;
-	}
-#endif /* CONFIG_IDE_PREINIT */
-
-	WATCHDOG_RESET();
-
-	/*
-	 * Reset the IDE just to be sure.
-	 * Light LED's to show
-	 */
-	ide_led((LED_IDE1 | LED_IDE2), 1);	/* LED's on     */
-
-	/* ATAPI Drives seems to need a proper IDE Reset */
-	ide_reset();
-
-#ifdef CONFIG_IDE_INIT_POSTRESET
-	WATCHDOG_RESET();
-
-	if (ide_init_postreset()) {
-		puts("ide_preinit_postreset failed\n");
-		return;
-	}
-#endif /* CONFIG_IDE_INIT_POSTRESET */
-
-	/*
-	 * Wait for IDE to get ready.
-	 * According to spec, this can take up to 31 seconds!
-	 */
-	for (bus = 0; bus < CONFIG_SYS_IDE_MAXBUS; ++bus) {
-		int dev =
-			bus * (CONFIG_SYS_IDE_MAXDEVICE /
-			       CONFIG_SYS_IDE_MAXBUS);
-
-#ifdef CONFIG_IDE_8xx_PCCARD
-		/* Skip non-ide devices from probing */
-		if ((ide_devices_found & (1 << bus)) == 0) {
-			ide_led((LED_IDE1 | LED_IDE2), 0);	/* LED's off */
-			continue;
-		}
-#endif
-		printf("Bus %d: ", bus);
-
-		ide_bus_ok[bus] = 0;
-
-		/* Select device
-		 */
-		udelay(100000);	/* 100 ms */
-		ide_outb(dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
-		udelay(100000);	/* 100 ms */
-		i = 0;
-		do {
-			udelay(10000);	/* 10 ms */
-
-			c = ide_inb(dev, ATA_STATUS);
-			i++;
-			if (i > (ATA_RESET_TIME * 100)) {
-				puts("** Timeout **\n");
-				/* LED's off */
-				ide_led((LED_IDE1 | LED_IDE2), 0);
-				return;
-			}
-			if ((i >= 100) && ((i % 100) == 0))
-				putc('.');
-
-		} while (c & ATA_STAT_BUSY);
-
-		if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
-			puts("not available  ");
-			debug("Status = 0x%02X ", c);
-#ifndef CONFIG_ATAPI		/* ATAPI Devices do not set DRDY */
-		} else if ((c & ATA_STAT_READY) == 0) {
-			puts("not available  ");
-			debug("Status = 0x%02X ", c);
-#endif
-		} else {
-			puts("OK ");
-			ide_bus_ok[bus] = 1;
-		}
-		WATCHDOG_RESET();
-	}
-
-	putc('\n');
-
-	ide_led((LED_IDE1 | LED_IDE2), 0);	/* LED's off    */
-
-	curr_device = -1;
-	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) {
-		int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
-		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
-		ide_dev_desc[i].if_type = IF_TYPE_IDE;
-		ide_dev_desc[i].devnum = i;
-		ide_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
-		ide_dev_desc[i].blksz = 0;
-		ide_dev_desc[i].log2blksz =
-			LOG2_INVALID(typeof(ide_dev_desc[i].log2blksz));
-		ide_dev_desc[i].lba = 0;
-		ide_dev_desc[i].block_read = ide_read;
-		ide_dev_desc[i].block_write = ide_write;
-		if (!ide_bus_ok[IDE_BUS(i)])
-			continue;
-		ide_led(led, 1);	/* LED on       */
-		ide_ident(&ide_dev_desc[i]);
-		ide_led(led, 0);	/* LED off      */
-		dev_print(&ide_dev_desc[i]);
-
-		if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
-			/* initialize partition type */
-			part_init(&ide_dev_desc[i]);
-			if (curr_device < 0)
-				curr_device = i;
-		}
-	}
-	WATCHDOG_RESET();
-}
-
-/* ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *ide_get_dev(int dev)
-{
-	return (dev < CONFIG_SYS_IDE_MAXDEVICE) ? &ide_dev_desc[dev] : NULL;
-}
-#endif
-
-/* ------------------------------------------------------------------------- */
-
-/* We only need to swap data if we are running on a big endian cpu. */
-#if defined(__LITTLE_ENDIAN)
-__weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
-{
-	ide_input_data(dev, sect_buf, words);
-}
-#else
-__weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
-{
-	volatile ushort *pbuf =
-		(ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG);
-	ushort *dbuf = (ushort *) sect_buf;
-
-	debug("in input swap data base for read is %lx\n",
-	      (unsigned long) pbuf);
-
-	while (words--) {
-#ifdef __MIPS__
-		*dbuf++ = swab16p((u16 *) pbuf);
-		*dbuf++ = swab16p((u16 *) pbuf);
-#else
-		*dbuf++ = ld_le16(pbuf);
-		*dbuf++ = ld_le16(pbuf);
-#endif /* !MIPS */
-	}
-}
-#endif /* __LITTLE_ENDIAN */
-
-
-#if defined(CONFIG_IDE_SWAP_IO)
-__weak void ide_output_data(int dev, const ulong *sect_buf, int words)
-{
-	ushort *dbuf;
-	volatile ushort *pbuf;
-
-	pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG);
-	dbuf = (ushort *) sect_buf;
-	while (words--) {
-		EIEIO;
-		*pbuf = *dbuf++;
-		EIEIO;
-		*pbuf = *dbuf++;
-	}
-}
-#else  /* ! CONFIG_IDE_SWAP_IO */
-__weak void ide_output_data(int dev, const ulong *sect_buf, int words)
-{
-#if defined(CONFIG_IDE_AHB)
-	ide_write_data(dev, sect_buf, words);
-#else
-	outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
-#endif
-}
-#endif /* CONFIG_IDE_SWAP_IO */
-
-#if defined(CONFIG_IDE_SWAP_IO)
-__weak void ide_input_data(int dev, ulong *sect_buf, int words)
-{
-	ushort *dbuf;
-	volatile ushort *pbuf;
-
-	pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG);
-	dbuf = (ushort *) sect_buf;
-
-	debug("in input data base for read is %lx\n", (unsigned long) pbuf);
-
-	while (words--) {
-		EIEIO;
-		*dbuf++ = *pbuf;
-		EIEIO;
-		*dbuf++ = *pbuf;
-	}
-}
-#else  /* ! CONFIG_IDE_SWAP_IO */
-__weak void ide_input_data(int dev, ulong *sect_buf, int words)
-{
-#if defined(CONFIG_IDE_AHB)
-	ide_read_data(dev, sect_buf, words);
-#else
-	insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
-#endif
-}
-
-#endif /* CONFIG_IDE_SWAP_IO */
-
-/* -------------------------------------------------------------------------
- */
-static void ide_ident(struct blk_desc *dev_desc)
-{
-	unsigned char c;
-	hd_driveid_t iop;
-
-#ifdef CONFIG_ATAPI
-	int retries = 0;
-#endif
-	int device;
-
-	device = dev_desc->devnum;
-	printf("  Device %d: ", device);
-
-	ide_led(DEVICE_LED(device), 1);	/* LED on       */
-	/* Select device
-	 */
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	dev_desc->if_type = IF_TYPE_IDE;
-#ifdef CONFIG_ATAPI
-
-	retries = 0;
-
-	/* Warning: This will be tricky to read */
-	while (retries <= 1) {
-		/* check signature */
-		if ((ide_inb(device, ATA_SECT_CNT) == 0x01) &&
-		    (ide_inb(device, ATA_SECT_NUM) == 0x01) &&
-		    (ide_inb(device, ATA_CYL_LOW) == 0x14) &&
-		    (ide_inb(device, ATA_CYL_HIGH) == 0xEB)) {
-			/* ATAPI Signature found */
-			dev_desc->if_type = IF_TYPE_ATAPI;
-			/*
-			 * Start Ident Command
-			 */
-			ide_outb(device, ATA_COMMAND, ATAPI_CMD_IDENT);
-			/*
-			 * Wait for completion - ATAPI devices need more time
-			 * to become ready
-			 */
-			c = ide_wait(device, ATAPI_TIME_OUT);
-		} else
-#endif
-		{
-			/*
-			 * Start Ident Command
-			 */
-			ide_outb(device, ATA_COMMAND, ATA_CMD_IDENT);
-
-			/*
-			 * Wait for completion
-			 */
-			c = ide_wait(device, IDE_TIME_OUT);
-		}
-		ide_led(DEVICE_LED(device), 0);	/* LED off      */
-
-		if (((c & ATA_STAT_DRQ) == 0) ||
-		    ((c & (ATA_STAT_FAULT | ATA_STAT_ERR)) != 0)) {
-#ifdef CONFIG_ATAPI
-			{
-				/*
-				 * Need to soft reset the device
-				 * in case it's an ATAPI...
-				 */
-				debug("Retrying...\n");
-				ide_outb(device, ATA_DEV_HD,
-					 ATA_LBA | ATA_DEVICE(device));
-				udelay(100000);
-				ide_outb(device, ATA_COMMAND, 0x08);
-				udelay(500000);	/* 500 ms */
-			}
-			/*
-			 * Select device
-			 */
-			ide_outb(device, ATA_DEV_HD,
-				 ATA_LBA | ATA_DEVICE(device));
-			retries++;
-#else
-			return;
-#endif
-		}
-#ifdef CONFIG_ATAPI
-		else
-			break;
-	}			/* see above - ugly to read */
-
-	if (retries == 2)	/* Not found */
-		return;
-#endif
-
-	ide_input_swap_data(device, (ulong *)&iop, ATA_SECTORWORDS);
-
-	ident_cpy((unsigned char *) dev_desc->revision, iop.fw_rev,
-		  sizeof(dev_desc->revision));
-	ident_cpy((unsigned char *) dev_desc->vendor, iop.model,
-		  sizeof(dev_desc->vendor));
-	ident_cpy((unsigned char *) dev_desc->product, iop.serial_no,
-		  sizeof(dev_desc->product));
-#ifdef __LITTLE_ENDIAN
-	/*
-	 * firmware revision, model, and serial number have Big Endian Byte
-	 * order in Word. Convert all three to little endian.
-	 *
-	 * See CF+ and CompactFlash Specification Revision 2.0:
-	 * 6.2.1.6: Identify Drive, Table 39 for more details
-	 */
-
-	strswab(dev_desc->revision);
-	strswab(dev_desc->vendor);
-	strswab(dev_desc->product);
-#endif /* __LITTLE_ENDIAN */
-
-	if ((iop.config & 0x0080) == 0x0080)
-		dev_desc->removable = 1;
-	else
-		dev_desc->removable = 0;
-
-#ifdef CONFIG_ATAPI
-	if (dev_desc->if_type == IF_TYPE_ATAPI) {
-		atapi_inquiry(dev_desc);
-		return;
-	}
-#endif /* CONFIG_ATAPI */
-
-#ifdef __BIG_ENDIAN
-	/* swap shorts */
-	dev_desc->lba = (iop.lba_capacity << 16) | (iop.lba_capacity >> 16);
-#else  /* ! __BIG_ENDIAN */
-	/*
-	 * do not swap shorts on little endian
-	 *
-	 * See CF+ and CompactFlash Specification Revision 2.0:
-	 * 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details.
-	 */
-	dev_desc->lba = iop.lba_capacity;
-#endif /* __BIG_ENDIAN */
-
-#ifdef CONFIG_LBA48
-	if (iop.command_set_2 & 0x0400) {	/* LBA 48 support */
-		dev_desc->lba48 = 1;
-		dev_desc->lba = (unsigned long long) iop.lba48_capacity[0] |
-			((unsigned long long) iop.lba48_capacity[1] << 16) |
-			((unsigned long long) iop.lba48_capacity[2] << 32) |
-			((unsigned long long) iop.lba48_capacity[3] << 48);
-	} else {
-		dev_desc->lba48 = 0;
-	}
-#endif /* CONFIG_LBA48 */
-	/* assuming HD */
-	dev_desc->type = DEV_TYPE_HARDDISK;
-	dev_desc->blksz = ATA_BLOCKSIZE;
-	dev_desc->log2blksz = LOG2(dev_desc->blksz);
-	dev_desc->lun = 0;	/* just to fill something in... */
-
-#if 0				/* only used to test the powersaving mode,
-				 * if enabled, the drive goes after 5 sec
-				 * in standby mode */
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	c = ide_wait(device, IDE_TIME_OUT);
-	ide_outb(device, ATA_SECT_CNT, 1);
-	ide_outb(device, ATA_LBA_LOW, 0);
-	ide_outb(device, ATA_LBA_MID, 0);
-	ide_outb(device, ATA_LBA_HIGH, 0);
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	ide_outb(device, ATA_COMMAND, 0xe3);
-	udelay(50);
-	c = ide_wait(device, IDE_TIME_OUT);	/* can't take over 500 ms */
-#endif
-}
-
-
-/* ------------------------------------------------------------------------- */
-
-ulong ide_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
-	       void *buffer)
-{
-	int device = block_dev->devnum;
-	ulong n = 0;
-	unsigned char c;
-	unsigned char pwrsave = 0;	/* power save */
-
-#ifdef CONFIG_LBA48
-	unsigned char lba48 = 0;
-
-	if (blknr & 0x0000fffff0000000ULL) {
-		/* more than 28 bits used, use 48bit mode */
-		lba48 = 1;
-	}
-#endif
-	debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",
-	      device, blknr, blkcnt, (ulong) buffer);
-
-	ide_led(DEVICE_LED(device), 1);	/* LED on       */
-
-	/* Select device
-	 */
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	c = ide_wait(device, IDE_TIME_OUT);
-
-	if (c & ATA_STAT_BUSY) {
-		printf("IDE read: device %d not ready\n", device);
-		goto IDE_READ_E;
-	}
-
-	/* first check if the drive is in Powersaving mode, if yes,
-	 * increase the timeout value */
-	ide_outb(device, ATA_COMMAND, ATA_CMD_CHK_PWR);
-	udelay(50);
-
-	c = ide_wait(device, IDE_TIME_OUT);	/* can't take over 500 ms */
-
-	if (c & ATA_STAT_BUSY) {
-		printf("IDE read: device %d not ready\n", device);
-		goto IDE_READ_E;
-	}
-	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
-		printf("No Powersaving mode %X\n", c);
-	} else {
-		c = ide_inb(device, ATA_SECT_CNT);
-		debug("Powersaving %02X\n", c);
-		if (c == 0)
-			pwrsave = 1;
-	}
-
-
-	while (blkcnt-- > 0) {
-
-		c = ide_wait(device, IDE_TIME_OUT);
-
-		if (c & ATA_STAT_BUSY) {
-			printf("IDE read: device %d not ready\n", device);
-			break;
-		}
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			/* write high bits */
-			ide_outb(device, ATA_SECT_CNT, 0);
-			ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
-#ifdef CONFIG_SYS_64BIT_LBA
-			ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
-			ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
-#else
-			ide_outb(device, ATA_LBA_MID, 0);
-			ide_outb(device, ATA_LBA_HIGH, 0);
-#endif
-		}
-#endif
-		ide_outb(device, ATA_SECT_CNT, 1);
-		ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
-		ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
-		ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
-
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			ide_outb(device, ATA_DEV_HD,
-				 ATA_LBA | ATA_DEVICE(device));
-			ide_outb(device, ATA_COMMAND, ATA_CMD_READ_EXT);
-
-		} else
-#endif
-		{
-			ide_outb(device, ATA_DEV_HD, ATA_LBA |
-				 ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
-			ide_outb(device, ATA_COMMAND, ATA_CMD_READ);
-		}
-
-		udelay(50);
-
-		if (pwrsave) {
-			/* may take up to 4 sec */
-			c = ide_wait(device, IDE_SPIN_UP_TIME_OUT);
-			pwrsave = 0;
-		} else {
-			/* can't take over 500 ms */
-			c = ide_wait(device, IDE_TIME_OUT);
-		}
-
-		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
-		    ATA_STAT_DRQ) {
-			printf("Error (no IRQ) dev %d blk " LBAF ": status "
-			       "%#02x\n", device, blknr, c);
-			break;
-		}
-
-		ide_input_data(device, buffer, ATA_SECTORWORDS);
-		(void) ide_inb(device, ATA_STATUS);	/* clear IRQ */
-
-		++n;
-		++blknr;
-		buffer += ATA_BLOCKSIZE;
-	}
-IDE_READ_E:
-	ide_led(DEVICE_LED(device), 0);	/* LED off      */
-	return (n);
-}
-
-/* ------------------------------------------------------------------------- */
-
-
-ulong ide_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
-		const void *buffer)
-{
-	int device = block_dev->devnum;
-	ulong n = 0;
-	unsigned char c;
-
-#ifdef CONFIG_LBA48
-	unsigned char lba48 = 0;
-
-	if (blknr & 0x0000fffff0000000ULL) {
-		/* more than 28 bits used, use 48bit mode */
-		lba48 = 1;
-	}
-#endif
-
-	ide_led(DEVICE_LED(device), 1);	/* LED on       */
-
-	/* Select device
-	 */
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-
-	while (blkcnt-- > 0) {
-
-		c = ide_wait(device, IDE_TIME_OUT);
-
-		if (c & ATA_STAT_BUSY) {
-			printf("IDE read: device %d not ready\n", device);
-			goto WR_OUT;
-		}
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			/* write high bits */
-			ide_outb(device, ATA_SECT_CNT, 0);
-			ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
-#ifdef CONFIG_SYS_64BIT_LBA
-			ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
-			ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
-#else
-			ide_outb(device, ATA_LBA_MID, 0);
-			ide_outb(device, ATA_LBA_HIGH, 0);
-#endif
-		}
-#endif
-		ide_outb(device, ATA_SECT_CNT, 1);
-		ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
-		ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
-		ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
-
-#ifdef CONFIG_LBA48
-		if (lba48) {
-			ide_outb(device, ATA_DEV_HD,
-				 ATA_LBA | ATA_DEVICE(device));
-			ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE_EXT);
-
-		} else
-#endif
-		{
-			ide_outb(device, ATA_DEV_HD, ATA_LBA |
-				 ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
-			ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE);
-		}
-
-		udelay(50);
-
-		/* can't take over 500 ms */
-		c = ide_wait(device, IDE_TIME_OUT);
-
-		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
-		    ATA_STAT_DRQ) {
-			printf("Error (no IRQ) dev %d blk " LBAF ": status "
-				"%#02x\n", device, blknr, c);
-			goto WR_OUT;
-		}
-
-		ide_output_data(device, buffer, ATA_SECTORWORDS);
-		c = ide_inb(device, ATA_STATUS);	/* clear IRQ */
-		++n;
-		++blknr;
-		buffer += ATA_BLOCKSIZE;
-	}
-WR_OUT:
-	ide_led(DEVICE_LED(device), 0);	/* LED off      */
-	return (n);
-}
-
-/* ------------------------------------------------------------------------- */
-
-/*
- * copy src to dest, skipping leading and trailing blanks and null
- * terminate the string
- * "len" is the size of available memory including the terminating '\0'
- */
-static void ident_cpy(unsigned char *dst, unsigned char *src,
-		      unsigned int len)
-{
-	unsigned char *end, *last;
-
-	last = dst;
-	end = src + len - 1;
-
-	/* reserve space for '\0' */
-	if (len < 2)
-		goto OUT;
-
-	/* skip leading white space */
-	while ((*src) && (src < end) && (*src == ' '))
-		++src;
-
-	/* copy string, omitting trailing white space */
-	while ((*src) && (src < end)) {
-		*dst++ = *src;
-		if (*src++ != ' ')
-			last = dst;
-	}
-OUT:
-	*last = '\0';
-}
-
-/* ------------------------------------------------------------------------- */
-
-/*
- * Wait until Busy bit is off, or timeout (in ms)
- * Return last status
- */
-static uchar ide_wait(int dev, ulong t)
-{
-	ulong delay = 10 * t;	/* poll every 100 us */
-	uchar c;
-
-	while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
-		udelay(100);
-		if (delay-- == 0)
-			break;
-	}
-	return (c);
-}
-
-/* ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_IDE_RESET
-extern void ide_set_reset(int idereset);
-
-static void ide_reset(void)
-{
-	int i;
-
-	curr_device = -1;
-	for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; ++i)
-		ide_bus_ok[i] = 0;
-	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i)
-		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
-
-	ide_set_reset(1);	/* assert reset */
-
-	/* the reset signal shall be asserted for et least 25 us */
-	udelay(25);
-
-	WATCHDOG_RESET();
-
-	/* de-assert RESET signal */
-	ide_set_reset(0);
-
-	/* wait 250 ms */
-	for (i = 0; i < 250; ++i)
-		udelay(1000);
-}
-
-#endif /* CONFIG_IDE_RESET */
-
-/* ------------------------------------------------------------------------- */
-
-#if defined(CONFIG_OF_IDE_FIXUP)
-int ide_device_present(int dev)
-{
-	if (dev >= CONFIG_SYS_IDE_MAXBUS)
-		return 0;
-	return (ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1);
-}
-#endif
-/* ------------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATAPI
-/****************************************************************************
- * ATAPI Support
- */
-
-#if defined(CONFIG_IDE_SWAP_IO)
-/* since ATAPI may use commands with not 4 bytes alligned length
- * we have our own transfer functions, 2 bytes alligned */
-__weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
-{
-	ushort *dbuf;
-	volatile ushort *pbuf;
-
-	pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG);
-	dbuf = (ushort *) sect_buf;
-
-	debug("in output data shorts base for read is %lx\n",
-	      (unsigned long) pbuf);
-
-	while (shorts--) {
-		EIEIO;
-		*pbuf = *dbuf++;
-	}
-}
-
-__weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
-{
-	ushort *dbuf;
-	volatile ushort *pbuf;
-
-	pbuf = (ushort *) (ATA_CURR_BASE(dev) + ATA_DATA_REG);
-	dbuf = (ushort *) sect_buf;
-
-	debug("in input data shorts base for read is %lx\n",
-	      (unsigned long) pbuf);
-
-	while (shorts--) {
-		EIEIO;
-		*dbuf++ = *pbuf;
-	}
-}
-
-#else  /* ! CONFIG_IDE_SWAP_IO */
-__weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
-{
-	outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
-}
-
-__weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
-{
-	insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
-}
-
-#endif /* CONFIG_IDE_SWAP_IO */
-
-/*
- * Wait until (Status & mask) == res, or timeout (in ms)
- * Return last status
- * This is used since some ATAPI CD ROMs clears their Busy Bit first
- * and then they set their DRQ Bit
- */
-static uchar atapi_wait_mask(int dev, ulong t, uchar mask, uchar res)
-{
-	ulong delay = 10 * t;	/* poll every 100 us */
-	uchar c;
-
-	/* prevents to read the status before valid */
-	c = ide_inb(dev, ATA_DEV_CTL);
-
-	while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) {
-		/* break if error occurs (doesn't make sense to wait more) */
-		if ((c & ATA_STAT_ERR) == ATA_STAT_ERR)
-			break;
-		udelay(100);
-		if (delay-- == 0)
-			break;
-	}
-	return (c);
-}
-
-/*
- * issue an atapi command
- */
-unsigned char atapi_issue(int device, unsigned char *ccb, int ccblen,
-			  unsigned char *buffer, int buflen)
-{
-	unsigned char c, err, mask, res;
-	int n;
-
-	ide_led(DEVICE_LED(device), 1);	/* LED on       */
-
-	/* Select device
-	 */
-	mask = ATA_STAT_BUSY | ATA_STAT_DRQ;
-	res = 0;
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
-	if ((c & mask) != res) {
-		printf("ATAPI_ISSUE: device %d not ready status %X\n", device,
-		       c);
-		err = 0xFF;
-		goto AI_OUT;
-	}
-	/* write taskfile */
-	ide_outb(device, ATA_ERROR_REG, 0);	/* no DMA, no overlaped */
-	ide_outb(device, ATA_SECT_CNT, 0);
-	ide_outb(device, ATA_SECT_NUM, 0);
-	ide_outb(device, ATA_CYL_LOW, (unsigned char) (buflen & 0xFF));
-	ide_outb(device, ATA_CYL_HIGH,
-		 (unsigned char) ((buflen >> 8) & 0xFF));
-	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
-
-	ide_outb(device, ATA_COMMAND, ATAPI_CMD_PACKET);
-	udelay(50);
-
-	mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
-	res = ATA_STAT_DRQ;
-	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
-
-	if ((c & mask) != res) {	/* DRQ must be 1, BSY 0 */
-		printf("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",
-			device, c);
-		err = 0xFF;
-		goto AI_OUT;
-	}
-
-	/* write command block */
-	ide_output_data_shorts(device, (unsigned short *) ccb, ccblen / 2);
-
-	/* ATAPI Command written wait for completition */
-	udelay(5000);		/* device must set bsy */
-
-	mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
-	/*
-	 * if no data wait for DRQ = 0 BSY = 0
-	 * if data wait for DRQ = 1 BSY = 0
-	 */
-	res = 0;
-	if (buflen)
-		res = ATA_STAT_DRQ;
-	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
-	if ((c & mask) != res) {
-		if (c & ATA_STAT_ERR) {
-			err = (ide_inb(device, ATA_ERROR_REG)) >> 4;
-			debug("atapi_issue 1 returned sense key %X status %02X\n",
-				err, c);
-		} else {
-			printf("ATAPI_ISSUE: (no DRQ) after sending ccb (%x)  status 0x%02x\n",
-				ccb[0], c);
-			err = 0xFF;
-		}
-		goto AI_OUT;
-	}
-	n = ide_inb(device, ATA_CYL_HIGH);
-	n <<= 8;
-	n += ide_inb(device, ATA_CYL_LOW);
-	if (n > buflen) {
-		printf("ERROR, transfer bytes %d requested only %d\n", n,
-		       buflen);
-		err = 0xff;
-		goto AI_OUT;
-	}
-	if ((n == 0) && (buflen < 0)) {
-		printf("ERROR, transfer bytes %d requested %d\n", n, buflen);
-		err = 0xff;
-		goto AI_OUT;
-	}
-	if (n != buflen) {
-		debug("WARNING, transfer bytes %d not equal with requested %d\n",
-			n, buflen);
-	}
-	if (n != 0) {		/* data transfer */
-		debug("ATAPI_ISSUE: %d Bytes to transfer\n", n);
-		/* we transfer shorts */
-		n >>= 1;
-		/* ok now decide if it is an in or output */
-		if ((ide_inb(device, ATA_SECT_CNT) & 0x02) == 0) {
-			debug("Write to device\n");
-			ide_output_data_shorts(device,
-				(unsigned short *) buffer, n);
-		} else {
-			debug("Read from device @ %p shorts %d\n", buffer, n);
-			ide_input_data_shorts(device,
-				(unsigned short *) buffer, n);
-		}
-	}
-	udelay(5000);		/* seems that some CD ROMs need this... */
-	mask = ATA_STAT_BUSY | ATA_STAT_ERR;
-	res = 0;
-	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
-	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
-		err = (ide_inb(device, ATA_ERROR_REG) >> 4);
-		debug("atapi_issue 2 returned sense key %X status %X\n", err,
-		      c);
-	} else {
-		err = 0;
-	}
-AI_OUT:
-	ide_led(DEVICE_LED(device), 0);	/* LED off      */
-	return (err);
-}
-
-/*
- * sending the command to atapi_issue. If an status other than good
- * returns, an request_sense will be issued
- */
-
-#define ATAPI_DRIVE_NOT_READY	100
-#define ATAPI_UNIT_ATTN		10
-
-unsigned char atapi_issue_autoreq(int device,
-				  unsigned char *ccb,
-				  int ccblen,
-				  unsigned char *buffer, int buflen)
-{
-	unsigned char sense_data[18], sense_ccb[12];
-	unsigned char res, key, asc, ascq;
-	int notready, unitattn;
-
-	unitattn = ATAPI_UNIT_ATTN;
-	notready = ATAPI_DRIVE_NOT_READY;
-
-retry:
-	res = atapi_issue(device, ccb, ccblen, buffer, buflen);
-	if (res == 0)
-		return 0;	/* Ok */
-
-	if (res == 0xFF)
-		return 0xFF;	/* error */
-
-	debug("(auto_req)atapi_issue returned sense key %X\n", res);
-
-	memset(sense_ccb, 0, sizeof(sense_ccb));
-	memset(sense_data, 0, sizeof(sense_data));
-	sense_ccb[0] = ATAPI_CMD_REQ_SENSE;
-	sense_ccb[4] = 18;	/* allocation Length */
-
-	res = atapi_issue(device, sense_ccb, 12, sense_data, 18);
-	key = (sense_data[2] & 0xF);
-	asc = (sense_data[12]);
-	ascq = (sense_data[13]);
-
-	debug("ATAPI_CMD_REQ_SENSE returned %x\n", res);
-	debug(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
-	      sense_data[0], key, asc, ascq);
-
-	if ((key == 0))
-		return 0;	/* ok device ready */
-
-	if ((key == 6) || (asc == 0x29) || (asc == 0x28)) { /* Unit Attention */
-		if (unitattn-- > 0) {
-			udelay(200 * 1000);
-			goto retry;
-		}
-		printf("Unit Attention, tried %d\n", ATAPI_UNIT_ATTN);
-		goto error;
-	}
-	if ((asc == 0x4) && (ascq == 0x1)) {
-		/* not ready, but will be ready soon */
-		if (notready-- > 0) {
-			udelay(200 * 1000);
-			goto retry;
-		}
-		printf("Drive not ready, tried %d times\n",
-		       ATAPI_DRIVE_NOT_READY);
-		goto error;
-	}
-	if (asc == 0x3a) {
-		debug("Media not present\n");
-		goto error;
-	}
-
-	printf("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n", key, asc,
-	       ascq);
-error:
-	debug("ERROR Sense key %02X ASC %02X ASCQ %02X\n", key, asc, ascq);
-	return (0xFF);
-}
-
-
-static void atapi_inquiry(struct blk_desc *dev_desc)
-{
-	unsigned char ccb[12];	/* Command descriptor block */
-	unsigned char iobuf[64];	/* temp buf */
-	unsigned char c;
-	int device;
-
-	device = dev_desc->devnum;
-	dev_desc->type = DEV_TYPE_UNKNOWN;	/* not yet valid */
-	dev_desc->block_read = atapi_read;
-
-	memset(ccb, 0, sizeof(ccb));
-	memset(iobuf, 0, sizeof(iobuf));
-
-	ccb[0] = ATAPI_CMD_INQUIRY;
-	ccb[4] = 40;		/* allocation Legnth */
-	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 40);
-
-	debug("ATAPI_CMD_INQUIRY returned %x\n", c);
-	if (c != 0)
-		return;
-
-	/* copy device ident strings */
-	ident_cpy((unsigned char *) dev_desc->vendor, &iobuf[8], 8);
-	ident_cpy((unsigned char *) dev_desc->product, &iobuf[16], 16);
-	ident_cpy((unsigned char *) dev_desc->revision, &iobuf[32], 5);
-
-	dev_desc->lun = 0;
-	dev_desc->lba = 0;
-	dev_desc->blksz = 0;
-	dev_desc->log2blksz = LOG2_INVALID(typeof(dev_desc->log2blksz));
-	dev_desc->type = iobuf[0] & 0x1f;
-
-	if ((iobuf[1] & 0x80) == 0x80)
-		dev_desc->removable = 1;
-	else
-		dev_desc->removable = 0;
-
-	memset(ccb, 0, sizeof(ccb));
-	memset(iobuf, 0, sizeof(iobuf));
-	ccb[0] = ATAPI_CMD_START_STOP;
-	ccb[4] = 0x03;		/* start */
-
-	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 0);
-
-	debug("ATAPI_CMD_START_STOP returned %x\n", c);
-	if (c != 0)
-		return;
-
-	memset(ccb, 0, sizeof(ccb));
-	memset(iobuf, 0, sizeof(iobuf));
-	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 0);
-
-	debug("ATAPI_CMD_UNIT_TEST_READY returned %x\n", c);
-	if (c != 0)
-		return;
-
-	memset(ccb, 0, sizeof(ccb));
-	memset(iobuf, 0, sizeof(iobuf));
-	ccb[0] = ATAPI_CMD_READ_CAP;
-	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *) iobuf, 8);
-	debug("ATAPI_CMD_READ_CAP returned %x\n", c);
-	if (c != 0)
-		return;
-
-	debug("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
-	      iobuf[0], iobuf[1], iobuf[2], iobuf[3],
-	      iobuf[4], iobuf[5], iobuf[6], iobuf[7]);
-
-	dev_desc->lba = ((unsigned long) iobuf[0] << 24) +
-		((unsigned long) iobuf[1] << 16) +
-		((unsigned long) iobuf[2] << 8) + ((unsigned long) iobuf[3]);
-	dev_desc->blksz = ((unsigned long) iobuf[4] << 24) +
-		((unsigned long) iobuf[5] << 16) +
-		((unsigned long) iobuf[6] << 8) + ((unsigned long) iobuf[7]);
-	dev_desc->log2blksz = LOG2(dev_desc->blksz);
-#ifdef CONFIG_LBA48
-	/* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */
-	dev_desc->lba48 = 0;
-#endif
-	return;
-}
-
-
-/*
- * atapi_read:
- * we transfer only one block per command, since the multiple DRQ per
- * command is not yet implemented
- */
-#define ATAPI_READ_MAX_BYTES	2048	/* we read max 2kbytes */
-#define ATAPI_READ_BLOCK_SIZE	2048	/* assuming CD part */
-#define ATAPI_READ_MAX_BLOCK	(ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE)
-
-ulong atapi_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
-		 void *buffer)
-{
-	int device = block_dev->devnum;
-	ulong n = 0;
-	unsigned char ccb[12];	/* Command descriptor block */
-	ulong cnt;
-
-	debug("atapi_read dev %d start " LBAF " blocks " LBAF " buffer at %lX\n",
-	      device, blknr, blkcnt, (ulong) buffer);
-
-	do {
-		if (blkcnt > ATAPI_READ_MAX_BLOCK)
-			cnt = ATAPI_READ_MAX_BLOCK;
-		else
-			cnt = blkcnt;
-
-		ccb[0] = ATAPI_CMD_READ_12;
-		ccb[1] = 0;	/* reserved */
-		ccb[2] = (unsigned char) (blknr >> 24) & 0xFF;	/* MSB Block */
-		ccb[3] = (unsigned char) (blknr >> 16) & 0xFF;	/*  */
-		ccb[4] = (unsigned char) (blknr >> 8) & 0xFF;
-		ccb[5] = (unsigned char) blknr & 0xFF;	/* LSB Block */
-		ccb[6] = (unsigned char) (cnt >> 24) & 0xFF; /* MSB Block cnt */
-		ccb[7] = (unsigned char) (cnt >> 16) & 0xFF;
-		ccb[8] = (unsigned char) (cnt >> 8) & 0xFF;
-		ccb[9] = (unsigned char) cnt & 0xFF;	/* LSB Block */
-		ccb[10] = 0;	/* reserved */
-		ccb[11] = 0;	/* reserved */
-
-		if (atapi_issue_autoreq(device, ccb, 12,
-					(unsigned char *) buffer,
-					cnt * ATAPI_READ_BLOCK_SIZE)
-		    == 0xFF) {
-			return (n);
-		}
-		n += cnt;
-		blkcnt -= cnt;
-		blknr += cnt;
-		buffer += (cnt * ATAPI_READ_BLOCK_SIZE);
-	} while (blkcnt > 0);
-	return (n);
-}
-
-/* ------------------------------------------------------------------------- */
-
-#endif /* CONFIG_ATAPI */
-
 U_BOOT_CMD(ide, 5, 1, do_ide,
 	   "IDE sub-system",
 	   "reset - reset IDE controller\n"
diff --git a/cmd/mmc.c b/cmd/mmc.c
index c5454bf..eb4a547 100644
--- a/cmd/mmc.c
+++ b/cmd/mmc.c
@@ -314,12 +314,14 @@
 	}
 	/* Switch to the RPMB partition */
 	original_part = mmc->block_dev.hwpart;
-	if (mmc_select_hwpart(curr_device, MMC_PART_RPMB) != 0)
+	if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, MMC_PART_RPMB) !=
+	    0)
 		return CMD_RET_FAILURE;
 	ret = cp->cmd(cmdtp, flag, argc, argv);
 
 	/* Return to original partition */
-	if (mmc_select_hwpart(curr_device, original_part) != 0)
+	if (blk_select_hwpart_devnum(IF_TYPE_MMC, curr_device, original_part) !=
+	    0)
 		return CMD_RET_FAILURE;
 	return ret;
 }
@@ -346,7 +348,7 @@
 	printf("\nMMC read: dev # %d, block # %d, count %d ... ",
 	       curr_device, blk, cnt);
 
-	n = blk_dread(&mmc->block_dev, blk, cnt, addr);
+	n = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, addr);
 	/* flush cache after read */
 	flush_cache((ulong)addr, cnt * 512); /* FIXME */
 	printf("%d blocks read: %s\n", n, (n == cnt) ? "OK" : "ERROR");
@@ -378,7 +380,7 @@
 		printf("Error: card is write protected!\n");
 		return CMD_RET_FAILURE;
 	}
-	n = blk_dwrite(&mmc->block_dev, blk, cnt, addr);
+	n = blk_dwrite(mmc_get_blk_desc(mmc), blk, cnt, addr);
 	printf("%d blocks written: %s\n", n, (n == cnt) ? "OK" : "ERROR");
 
 	return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
@@ -406,7 +408,7 @@
 		printf("Error: card is write protected!\n");
 		return CMD_RET_FAILURE;
 	}
-	n = blk_derase(&mmc->block_dev, blk, cnt);
+	n = blk_derase(mmc_get_blk_desc(mmc), blk, cnt);
 	printf("%d blocks erased: %s\n", n, (n == cnt) ? "OK" : "ERROR");
 
 	return (n == cnt) ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
@@ -432,7 +434,7 @@
 	if (!mmc)
 		return CMD_RET_FAILURE;
 
-	mmc_dev = mmc_get_dev(curr_device);
+	mmc_dev = blk_get_devnum_by_type(IF_TYPE_MMC, curr_device);
 	if (mmc_dev != NULL && mmc_dev->type != DEV_TYPE_UNKNOWN) {
 		part_print(mmc_dev);
 		return CMD_RET_SUCCESS;
@@ -467,7 +469,7 @@
 	if (!mmc)
 		return CMD_RET_FAILURE;
 
-	ret = mmc_select_hwpart(dev, part);
+	ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
 	printf("switch to partitions #%d, %s\n",
 	       part, (!ret) ? "OK" : "ERROR");
 	if (ret)
@@ -478,7 +480,7 @@
 		printf("mmc%d is current device\n", curr_device);
 	else
 		printf("mmc%d(part %d) is current device\n",
-		       curr_device, mmc->block_dev.hwpart);
+		       curr_device, mmc_get_blk_desc(mmc)->hwpart);
 
 	return CMD_RET_SUCCESS;
 }
diff --git a/cmd/sata.c b/cmd/sata.c
index 8748cce..d18b523 100644
--- a/cmd/sata.c
+++ b/cmd/sata.c
@@ -16,70 +16,6 @@
 #include <sata.h>
 
 static int sata_curr_device = -1;
-struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
-
-static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start,
-				lbaint_t blkcnt, void *dst)
-{
-	return sata_read(block_dev->devnum, start, blkcnt, dst);
-}
-
-static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start,
-				 lbaint_t blkcnt, const void *buffer)
-{
-	return sata_write(block_dev->devnum, start, blkcnt, buffer);
-}
-
-int __sata_initialize(void)
-{
-	int rc;
-	int i;
-
-	for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
-		memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc));
-		sata_dev_desc[i].if_type = IF_TYPE_SATA;
-		sata_dev_desc[i].devnum = i;
-		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
-		sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
-		sata_dev_desc[i].lba = 0;
-		sata_dev_desc[i].blksz = 512;
-		sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz);
-		sata_dev_desc[i].block_read = sata_bread;
-		sata_dev_desc[i].block_write = sata_bwrite;
-
-		rc = init_sata(i);
-		if (!rc) {
-			rc = scan_sata(i);
-			if (!rc && (sata_dev_desc[i].lba > 0) &&
-				(sata_dev_desc[i].blksz > 0))
-				part_init(&sata_dev_desc[i]);
-		}
-	}
-	sata_curr_device = 0;
-	return rc;
-}
-int sata_initialize(void) __attribute__((weak,alias("__sata_initialize")));
-
-__weak int __sata_stop(void)
-{
-	int i, err = 0;
-
-	for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++)
-		err |= reset_sata(i);
-
-	if (err)
-		printf("Could not reset some SATA devices\n");
-
-	return err;
-}
-int sata_stop(void) __attribute__((weak, alias("__sata_stop")));
-
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *sata_get_dev(int dev)
-{
-	return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
-}
-#endif
 
 static int do_sata(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
@@ -105,69 +41,40 @@
 	case 1:
 		return CMD_RET_USAGE;
 	case 2:
-		if (strncmp(argv[1],"inf", 3) == 0) {
-			int i;
-			putc('\n');
-			for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; ++i) {
-				if (sata_dev_desc[i].type == DEV_TYPE_UNKNOWN)
-					continue;
-				printf ("SATA device %d: ", i);
-				dev_print(&sata_dev_desc[i]);
+		if (strncmp(argv[1], "inf", 3) == 0) {
+			blk_list_devices(IF_TYPE_SATA);
+			return 0;
+		} else if (strncmp(argv[1], "dev", 3) == 0) {
+			if (blk_print_device_num(IF_TYPE_SATA,
+						 sata_curr_device)) {
+				printf("\nno SATA devices available\n");
+				return CMD_RET_FAILURE;
 			}
 			return 0;
-		} else if (strncmp(argv[1],"dev", 3) == 0) {
-			if ((sata_curr_device < 0) || (sata_curr_device >= CONFIG_SYS_SATA_MAX_DEVICE)) {
+		} else if (strncmp(argv[1], "part", 4) == 0) {
+			if (blk_list_part(IF_TYPE_SATA))
 				puts("\nno SATA devices available\n");
-				return 1;
-			}
-			printf("\nSATA device %d: ", sata_curr_device);
-			dev_print(&sata_dev_desc[sata_curr_device]);
 			return 0;
-		} else if (strncmp(argv[1],"part",4) == 0) {
-			int dev, ok;
-
-			for (ok = 0, dev = 0; dev < CONFIG_SYS_SATA_MAX_DEVICE; ++dev) {
-				if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
-					++ok;
-					if (dev)
-						putc ('\n');
-					part_print(&sata_dev_desc[dev]);
-				}
-			}
-			if (!ok) {
-				puts("\nno SATA devices available\n");
-				rc ++;
-			}
-			return rc;
 		}
 		return CMD_RET_USAGE;
 	case 3:
 		if (strncmp(argv[1], "dev", 3) == 0) {
 			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			printf("\nSATA device %d: ", dev);
-			if (dev >= CONFIG_SYS_SATA_MAX_DEVICE) {
-				puts ("unknown device\n");
-				return 1;
+			if (!blk_show_device(IF_TYPE_SATA, dev)) {
+				sata_curr_device = dev;
+				printf("... is now current device\n");
+			} else {
+				return CMD_RET_FAILURE;
 			}
-			dev_print(&sata_dev_desc[dev]);
-
-			if (sata_dev_desc[dev].type == DEV_TYPE_UNKNOWN)
-				return 1;
-
-			sata_curr_device = dev;
-
-			puts("... is now current device\n");
-
 			return 0;
 		} else if (strncmp(argv[1], "part", 4) == 0) {
 			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 
-			if (sata_dev_desc[dev].part_type != PART_TYPE_UNKNOWN) {
-				part_print(&sata_dev_desc[dev]);
-			} else {
-				printf("\nSATA device %d not available\n", dev);
-				rc = 1;
+			if (blk_print_part_devnum(IF_TYPE_SATA, dev)) {
+				printf("\nSATA device %d not available\n",
+				       dev);
+				return CMD_RET_FAILURE;
 			}
 			return rc;
 		}
@@ -183,11 +90,8 @@
 			printf("\nSATA read: device %d block # %ld, count %ld ... ",
 				sata_curr_device, blk, cnt);
 
-			n = blk_dread(&sata_dev_desc[sata_curr_device],
-				      blk, cnt, (u32 *)addr);
-
-			/* flush cache after read */
-			flush_cache(addr, cnt * sata_dev_desc[sata_curr_device].blksz);
+			n = blk_read_devnum(IF_TYPE_SATA, sata_curr_device, blk,
+					    cnt, (ulong *)addr);
 
 			printf("%ld blocks read: %s\n",
 				n, (n==cnt) ? "OK" : "ERROR");
@@ -202,8 +106,8 @@
 			printf("\nSATA write: device %d block # %ld, count %ld ... ",
 				sata_curr_device, blk, cnt);
 
-			n = blk_dwrite(&sata_dev_desc[sata_curr_device],
-				       blk, cnt, (u32 *)addr);
+			n = blk_write_devnum(IF_TYPE_SATA, sata_curr_device,
+					     blk, cnt, (ulong *)addr);
 
 			printf("%ld blocks written: %s\n",
 				n, (n == cnt) ? "OK" : "ERROR");
diff --git a/cmd/scsi.c b/cmd/scsi.c
index 8991125..387ca1a 100644
--- a/cmd/scsi.c
+++ b/cmd/scsi.c
@@ -10,361 +10,108 @@
  */
 #include <common.h>
 #include <command.h>
-#include <inttypes.h>
-#include <asm/processor.h>
 #include <scsi.h>
-#include <image.h>
-#include <pci.h>
-
-#ifdef CONFIG_SCSI_DEV_LIST
-#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
-#else
-#ifdef CONFIG_SCSI_SYM53C8XX
-#define SCSI_VEND_ID	0x1000
-#ifndef CONFIG_SCSI_DEV_ID
-#define SCSI_DEV_ID		0x0001
-#else
-#define SCSI_DEV_ID		CONFIG_SCSI_DEV_ID
-#endif
-#elif defined CONFIG_SATA_ULI5288
-
-#define SCSI_VEND_ID 0x10b9
-#define SCSI_DEV_ID  0x5288
-
-#elif !defined(CONFIG_SCSI_AHCI_PLAT)
-#error no scsi device defined
-#endif
-#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
-#endif
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
-const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
-#endif
-static ccb tempccb;	/* temporary scsi command buffer */
-
-static unsigned char tempbuff[512]; /* temporary data buffer */
-
-static int scsi_max_devs; /* number of highest available scsi device */
 
 static int scsi_curr_dev; /* current device */
 
-static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
-
-/********************************************************************************
- *  forward declerations of some Setup Routines
- */
-void scsi_setup_test_unit_ready(ccb * pccb);
-void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks);
-void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks);
-void scsi_setup_read16(ccb * pccb, lbaint_t start, unsigned long blocks);
-
-static void scsi_setup_write_ext(ccb *pccb, lbaint_t start,
-				unsigned short blocks);
-void scsi_setup_inquiry(ccb * pccb);
-void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len);
-
-
-static int scsi_read_capacity(ccb *pccb, lbaint_t *capacity,
-			      unsigned long *blksz);
-static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
-		       lbaint_t blkcnt, void *buffer);
-static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
-			lbaint_t blkcnt, const void *buffer);
-
-
-/*********************************************************************************
- * (re)-scan the scsi bus and reports scsi device info
- * to the user if mode = 1
- */
-void scsi_scan(int mode)
-{
-	unsigned char i,perq,modi,lun;
-	lbaint_t capacity;
-	unsigned long blksz;
-	ccb* pccb=(ccb *)&tempccb;
-
-	if(mode==1) {
-		printf("scanning bus for devices...\n");
-	}
-	for(i=0;i<CONFIG_SYS_SCSI_MAX_DEVICE;i++) {
-		scsi_dev_desc[i].target=0xff;
-		scsi_dev_desc[i].lun=0xff;
-		scsi_dev_desc[i].lba=0;
-		scsi_dev_desc[i].blksz=0;
-		scsi_dev_desc[i].log2blksz =
-			LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz));
-		scsi_dev_desc[i].type=DEV_TYPE_UNKNOWN;
-		scsi_dev_desc[i].vendor[0]=0;
-		scsi_dev_desc[i].product[0]=0;
-		scsi_dev_desc[i].revision[0]=0;
-		scsi_dev_desc[i].removable = false;
-		scsi_dev_desc[i].if_type=IF_TYPE_SCSI;
-		scsi_dev_desc[i].devnum = i;
-		scsi_dev_desc[i].part_type=PART_TYPE_UNKNOWN;
-		scsi_dev_desc[i].block_read=scsi_read;
-		scsi_dev_desc[i].block_write = scsi_write;
-	}
-	scsi_max_devs=0;
-	for(i=0;i<CONFIG_SYS_SCSI_MAX_SCSI_ID;i++) {
-		pccb->target=i;
-		for(lun=0;lun<CONFIG_SYS_SCSI_MAX_LUN;lun++) {
-			pccb->lun=lun;
-			pccb->pdata=(unsigned char *)&tempbuff;
-			pccb->datalen=512;
-			scsi_setup_inquiry(pccb);
-			if (scsi_exec(pccb) != true) {
-				if(pccb->contr_stat==SCSI_SEL_TIME_OUT) {
-					debug ("Selection timeout ID %d\n",pccb->target);
-					continue; /* selection timeout => assuming no device present */
-				}
-				scsi_print_error(pccb);
-				continue;
-			}
-			perq=tempbuff[0];
-			modi=tempbuff[1];
-			if((perq & 0x1f)==0x1f) {
-				continue; /* skip unknown devices */
-			}
-			if((modi&0x80)==0x80) /* drive is removable */
-				scsi_dev_desc[scsi_max_devs].removable=true;
-			/* get info for this device */
-			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].vendor[0],
-				       &tempbuff[8], 8);
-			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].product[0],
-				       &tempbuff[16], 16);
-			scsi_ident_cpy((unsigned char *)&scsi_dev_desc[scsi_max_devs].revision[0],
-				       &tempbuff[32], 4);
-			scsi_dev_desc[scsi_max_devs].target=pccb->target;
-			scsi_dev_desc[scsi_max_devs].lun=pccb->lun;
-
-			pccb->datalen=0;
-			scsi_setup_test_unit_ready(pccb);
-			if (scsi_exec(pccb) != true) {
-				if (scsi_dev_desc[scsi_max_devs].removable == true) {
-					scsi_dev_desc[scsi_max_devs].type=perq;
-					goto removable;
-				}
-				scsi_print_error(pccb);
-				continue;
-			}
-			if (scsi_read_capacity(pccb, &capacity, &blksz)) {
-				scsi_print_error(pccb);
-				continue;
-			}
-			scsi_dev_desc[scsi_max_devs].lba=capacity;
-			scsi_dev_desc[scsi_max_devs].blksz=blksz;
-			scsi_dev_desc[scsi_max_devs].log2blksz =
-				LOG2(scsi_dev_desc[scsi_max_devs].blksz);
-			scsi_dev_desc[scsi_max_devs].type=perq;
-			part_init(&scsi_dev_desc[scsi_max_devs]);
-removable:
-			if(mode==1) {
-				printf ("  Device %d: ", scsi_max_devs);
-				dev_print(&scsi_dev_desc[scsi_max_devs]);
-			} /* if mode */
-			scsi_max_devs++;
-		} /* next LUN */
-	}
-	if(scsi_max_devs>0)
-		scsi_curr_dev=0;
-	else
-		scsi_curr_dev = -1;
-
-	printf("Found %d device(s).\n", scsi_max_devs);
-#ifndef CONFIG_SPL_BUILD
-	setenv_ulong("scsidevs", scsi_max_devs);
-#endif
-}
-
-int scsi_get_disk_count(void)
-{
-	return scsi_max_devs;
-}
-
-#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
-void scsi_init(void)
-{
-	int busdevfunc = -1;
-	int i;
-	/*
-	 * Find a device from the list, this driver will support a single
-	 * controller.
-	 */
-	for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
-		/* get PCI Device ID */
-#ifdef CONFIG_DM_PCI
-		struct udevice *dev;
-		int ret;
-
-		ret = dm_pci_find_device(scsi_device_list[i].vendor,
-					 scsi_device_list[i].device, 0, &dev);
-		if (!ret) {
-			busdevfunc = dm_pci_get_bdf(dev);
-			break;
-		}
-#else
-		busdevfunc = pci_find_device(scsi_device_list[i].vendor,
-					     scsi_device_list[i].device,
-					     0);
-#endif
-		if (busdevfunc != -1)
-			break;
-	}
-
-	if (busdevfunc == -1) {
-		printf("Error: SCSI Controller(s) ");
-		for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
-			printf("%04X:%04X ",
-			       scsi_device_list[i].vendor,
-			       scsi_device_list[i].device);
-		}
-		printf("not found\n");
-		return;
-	}
-#ifdef DEBUG
-	else {
-		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
-		       scsi_device_list[i].vendor,
-		       scsi_device_list[i].device,
-		       (busdevfunc >> 16) & 0xFF,
-		       (busdevfunc >> 11) & 0x1F,
-		       (busdevfunc >> 8) & 0x7);
-	}
-#endif
-	bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
-	scsi_low_level_init(busdevfunc);
-	scsi_scan(1);
-	bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
-}
-#endif
-
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *scsi_get_dev(int dev)
-{
-	return (dev < CONFIG_SYS_SCSI_MAX_DEVICE) ? &scsi_dev_desc[dev] : NULL;
-}
-#endif
-
-#ifndef CONFIG_SPL_BUILD
-/******************************************************************************
+/*
  * scsi boot command intepreter. Derived from diskboot
  */
-int do_scsiboot (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_scsiboot(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	return common_diskboot(cmdtp, "scsi", argc, argv);
 }
 
-/*********************************************************************************
+/*
  * scsi command intepreter
  */
-int do_scsi (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+int do_scsi(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
 	switch (argc) {
 	case 0:
 	case 1:
 		return CMD_RET_USAGE;
-
 	case 2:
-			if (strncmp(argv[1],"res",3) == 0) {
-				printf("\nReset SCSI\n");
-				scsi_bus_reset();
-				scsi_scan(1);
-				return 0;
+		if (strncmp(argv[1], "res", 3) == 0) {
+			printf("\nReset SCSI\n");
+			scsi_bus_reset();
+			scsi_scan(1);
+			return 0;
+		}
+		if (strncmp(argv[1], "inf", 3) == 0) {
+			blk_list_devices(IF_TYPE_SCSI);
+			return 0;
+		}
+		if (strncmp(argv[1], "dev", 3) == 0) {
+			if (blk_print_device_num(IF_TYPE_SCSI, scsi_curr_dev)) {
+				printf("\nno SCSI devices available\n");
+				return CMD_RET_FAILURE;
 			}
-			if (strncmp(argv[1],"inf",3) == 0) {
-				int i;
-				for (i=0; i<CONFIG_SYS_SCSI_MAX_DEVICE; ++i) {
-					if(scsi_dev_desc[i].type==DEV_TYPE_UNKNOWN)
-						continue; /* list only known devices */
-					printf ("SCSI dev. %d:  ", i);
-					dev_print(&scsi_dev_desc[i]);
-				}
-				return 0;
-			}
-			if (strncmp(argv[1],"dev",3) == 0) {
-				if ((scsi_curr_dev < 0) || (scsi_curr_dev >= CONFIG_SYS_SCSI_MAX_DEVICE)) {
-					printf("\nno SCSI devices available\n");
-					return 1;
-				}
-				printf ("\n    Device %d: ", scsi_curr_dev);
-				dev_print(&scsi_dev_desc[scsi_curr_dev]);
-				return 0;
-			}
-			if (strncmp(argv[1],"scan",4) == 0) {
-				scsi_scan(1);
-				return 0;
-			}
-			if (strncmp(argv[1],"part",4) == 0) {
-				int dev, ok;
-				for (ok=0, dev=0; dev<CONFIG_SYS_SCSI_MAX_DEVICE; ++dev) {
-					if (scsi_dev_desc[dev].type!=DEV_TYPE_UNKNOWN) {
-						ok++;
-						if (dev)
-							printf("\n");
-						debug ("print_part of %x\n",dev);
-						part_print(&scsi_dev_desc[dev]);
-					}
-				}
-				if (!ok)
-					printf("\nno SCSI devices available\n");
-				return 1;
-			}
-			return CMD_RET_USAGE;
+
+			return 0;
+		}
+		if (strncmp(argv[1], "scan", 4) == 0) {
+			scsi_scan(1);
+			return 0;
+		}
+		if (strncmp(argv[1], "part", 4) == 0) {
+			if (blk_list_part(IF_TYPE_SCSI))
+				printf("\nno SCSI devices available\n");
+			return 0;
+		}
+		return CMD_RET_USAGE;
 	case 3:
-			if (strncmp(argv[1],"dev",3) == 0) {
-				int dev = (int)simple_strtoul(argv[2], NULL, 10);
-				printf ("\nSCSI device %d: ", dev);
-				if (dev >= CONFIG_SYS_SCSI_MAX_DEVICE) {
-					printf("unknown device\n");
-					return 1;
-				}
-				printf ("\n    Device %d: ", dev);
-				dev_print(&scsi_dev_desc[dev]);
-				if(scsi_dev_desc[dev].type == DEV_TYPE_UNKNOWN) {
-					return 1;
-				}
+		if (strncmp(argv[1], "dev", 3) == 0) {
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+			if (!blk_show_device(IF_TYPE_SCSI, dev)) {
 				scsi_curr_dev = dev;
 				printf("... is now current device\n");
-				return 0;
+			} else {
+				return CMD_RET_FAILURE;
 			}
-			if (strncmp(argv[1],"part",4) == 0) {
-				int dev = (int)simple_strtoul(argv[2], NULL, 10);
-				if(scsi_dev_desc[dev].type != DEV_TYPE_UNKNOWN) {
-					part_print(&scsi_dev_desc[dev]);
-				}
-				else {
-					printf ("\nSCSI device %d not available\n", dev);
-				}
-				return 1;
+			return 0;
+		}
+		if (strncmp(argv[1], "part", 4) == 0) {
+			int dev = (int)simple_strtoul(argv[2], NULL, 10);
+
+			if (blk_print_part_devnum(IF_TYPE_SCSI, dev)) {
+				printf("\nSCSI device %d not available\n",
+				       dev);
+				return CMD_RET_FAILURE;
 			}
-			return CMD_RET_USAGE;
-    default:
-			/* at least 4 args */
-			if (strcmp(argv[1],"read") == 0) {
-				ulong addr = simple_strtoul(argv[2], NULL, 16);
-				ulong blk  = simple_strtoul(argv[3], NULL, 16);
-				ulong cnt  = simple_strtoul(argv[4], NULL, 16);
-				ulong n;
-				printf ("\nSCSI read: device %d block # %ld, count %ld ... ",
-						scsi_curr_dev, blk, cnt);
-				n = scsi_read(&scsi_dev_desc[scsi_curr_dev],
-					      blk, cnt, (ulong *)addr);
-				printf ("%ld blocks read: %s\n",n,(n==cnt) ? "OK" : "ERROR");
-				return 0;
-			} else if (strcmp(argv[1], "write") == 0) {
-				ulong addr = simple_strtoul(argv[2], NULL, 16);
-				ulong blk = simple_strtoul(argv[3], NULL, 16);
-				ulong cnt = simple_strtoul(argv[4], NULL, 16);
-				ulong n;
-				printf("\nSCSI write: device %d block # %ld, "
-				       "count %ld ... ",
-				       scsi_curr_dev, blk, cnt);
-				n = scsi_write(&scsi_dev_desc[scsi_curr_dev],
-					       blk, cnt, (ulong *)addr);
-				printf("%ld blocks written: %s\n", n,
-				       (n == cnt) ? "OK" : "ERROR");
-				return 0;
-			}
+			return 0;
+		}
+		return CMD_RET_USAGE;
+	default:
+		/* at least 4 args */
+		if (strcmp(argv[1], "read") == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong blk  = simple_strtoul(argv[3], NULL, 16);
+			ulong cnt  = simple_strtoul(argv[4], NULL, 16);
+			ulong n;
+
+			printf("\nSCSI read: device %d block # %ld, count %ld ... ",
+			       scsi_curr_dev, blk, cnt);
+			n = blk_read_devnum(IF_TYPE_SCSI, scsi_curr_dev, blk,
+					    cnt, (ulong *)addr);
+			printf("%ld blocks read: %s\n", n,
+			       n == cnt ? "OK" : "ERROR");
+			return 0;
+		} else if (strcmp(argv[1], "write") == 0) {
+			ulong addr = simple_strtoul(argv[2], NULL, 16);
+			ulong blk = simple_strtoul(argv[3], NULL, 16);
+			ulong cnt = simple_strtoul(argv[4], NULL, 16);
+			ulong n;
+
+			printf("\nSCSI write: device %d block # %ld, count %ld ... ",
+			       scsi_curr_dev, blk, cnt);
+			n = blk_write_devnum(IF_TYPE_SCSI, scsi_curr_dev, blk,
+					     cnt, (ulong *)addr);
+			printf("%ld blocks written: %s\n", n,
+			       n == cnt ? "OK" : "ERROR");
+			return 0;
+		}
 	} /* switch */
 	return CMD_RET_USAGE;
 }
@@ -388,347 +135,3 @@
 	"boot from SCSI device",
 	"loadAddr dev:part"
 );
-#endif
-
-/****************************************************************************************
- * scsi_read
- */
-
-/* almost the maximum amount of the scsi_ext command.. */
-#define SCSI_MAX_READ_BLK 0xFFFF
-#define SCSI_LBA48_READ	0xFFFFFFF
-
-static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
-		       lbaint_t blkcnt, void *buffer)
-{
-	int device = block_dev->devnum;
-	lbaint_t start, blks;
-	uintptr_t buf_addr;
-	unsigned short smallblks = 0;
-	ccb* pccb=(ccb *)&tempccb;
-	device&=0xff;
-	/* Setup  device
-	 */
-	pccb->target=scsi_dev_desc[device].target;
-	pccb->lun=scsi_dev_desc[device].lun;
-	buf_addr=(unsigned long)buffer;
-	start=blknr;
-	blks=blkcnt;
-	debug("\nscsi_read: dev %d startblk " LBAF
-	      ", blccnt " LBAF " buffer %lx\n",
-	      device, start, blks, (unsigned long)buffer);
-	do {
-		pccb->pdata=(unsigned char *)buf_addr;
-#ifdef CONFIG_SYS_64BIT_LBA
-		if (start > SCSI_LBA48_READ) {
-			unsigned long blocks;
-			blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
-			pccb->datalen = scsi_dev_desc[device].blksz * blocks;
-			scsi_setup_read16(pccb, start, blocks);
-			start += blocks;
-			blks -= blocks;
-		} else
-#endif
-		if (blks > SCSI_MAX_READ_BLK) {
-			pccb->datalen=scsi_dev_desc[device].blksz * SCSI_MAX_READ_BLK;
-			smallblks=SCSI_MAX_READ_BLK;
-			scsi_setup_read_ext(pccb,start,smallblks);
-			start+=SCSI_MAX_READ_BLK;
-			blks-=SCSI_MAX_READ_BLK;
-		}
-		else {
-			pccb->datalen=scsi_dev_desc[device].blksz * blks;
-			smallblks=(unsigned short) blks;
-			scsi_setup_read_ext(pccb,start,smallblks);
-			start+=blks;
-			blks=0;
-		}
-		debug("scsi_read_ext: startblk " LBAF
-		      ", blccnt %x buffer %" PRIXPTR "\n",
-		      start, smallblks, buf_addr);
-		if (scsi_exec(pccb) != true) {
-			scsi_print_error(pccb);
-			blkcnt-=blks;
-			break;
-		}
-		buf_addr+=pccb->datalen;
-	} while(blks!=0);
-	debug("scsi_read_ext: end startblk " LBAF
-	      ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr);
-	return(blkcnt);
-}
-
-/*******************************************************************************
- * scsi_write
- */
-
-/* Almost the maximum amount of the scsi_ext command.. */
-#define SCSI_MAX_WRITE_BLK 0xFFFF
-
-static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
-			lbaint_t blkcnt, const void *buffer)
-{
-	int device = block_dev->devnum;
-	lbaint_t start, blks;
-	uintptr_t buf_addr;
-	unsigned short smallblks;
-	ccb* pccb = (ccb *)&tempccb;
-	device &= 0xff;
-	/* Setup  device
-	 */
-	pccb->target = scsi_dev_desc[device].target;
-	pccb->lun = scsi_dev_desc[device].lun;
-	buf_addr = (unsigned long)buffer;
-	start = blknr;
-	blks = blkcnt;
-	debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
-	      __func__, device, start, blks, (unsigned long)buffer);
-	do {
-		pccb->pdata = (unsigned char *)buf_addr;
-		if (blks > SCSI_MAX_WRITE_BLK) {
-			pccb->datalen = (scsi_dev_desc[device].blksz *
-					 SCSI_MAX_WRITE_BLK);
-			smallblks = SCSI_MAX_WRITE_BLK;
-			scsi_setup_write_ext(pccb, start, smallblks);
-			start += SCSI_MAX_WRITE_BLK;
-			blks -= SCSI_MAX_WRITE_BLK;
-		} else {
-			pccb->datalen = scsi_dev_desc[device].blksz * blks;
-			smallblks = (unsigned short)blks;
-			scsi_setup_write_ext(pccb, start, smallblks);
-			start += blks;
-			blks = 0;
-		}
-		debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
-		      __func__, start, smallblks, buf_addr);
-		if (scsi_exec(pccb) != true) {
-			scsi_print_error(pccb);
-			blkcnt -= blks;
-			break;
-		}
-		buf_addr += pccb->datalen;
-	} while (blks != 0);
-	debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
-	      __func__, start, smallblks, buf_addr);
-	return blkcnt;
-}
-
-/* copy src to dest, skipping leading and trailing blanks
- * and null terminate the string
- */
-void scsi_ident_cpy (unsigned char *dest, unsigned char *src, unsigned int len)
-{
-	int start,end;
-
-	start=0;
-	while(start<len) {
-		if(src[start]!=' ')
-			break;
-		start++;
-	}
-	end=len-1;
-	while(end>start) {
-		if(src[end]!=' ')
-			break;
-		end--;
-	}
-	for( ; start<=end; start++) {
-		*dest++=src[start];
-	}
-	*dest='\0';
-}
-
-
-/* Trim trailing blanks, and NUL-terminate string
- */
-void scsi_trim_trail (unsigned char *str, unsigned int len)
-{
-	unsigned char *p = str + len - 1;
-
-	while (len-- > 0) {
-		*p-- = '\0';
-		if (*p != ' ') {
-			return;
-		}
-	}
-}
-
-int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz)
-{
-	*capacity = 0;
-
-	memset(pccb->cmd, 0, sizeof(pccb->cmd));
-	pccb->cmd[0] = SCSI_RD_CAPAC10;
-	pccb->cmd[1] = pccb->lun << 5;
-	pccb->cmdlen = 10;
-	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
-
-	pccb->datalen = 8;
-	if (scsi_exec(pccb) != true)
-		return 1;
-
-	*capacity = ((lbaint_t)pccb->pdata[0] << 24) |
-		    ((lbaint_t)pccb->pdata[1] << 16) |
-		    ((lbaint_t)pccb->pdata[2] << 8)  |
-		    ((lbaint_t)pccb->pdata[3]);
-
-	if (*capacity != 0xffffffff) {
-		/* Read capacity (10) was sufficient for this drive. */
-		*blksz = ((unsigned long)pccb->pdata[4] << 24) |
-			 ((unsigned long)pccb->pdata[5] << 16) |
-			 ((unsigned long)pccb->pdata[6] << 8)  |
-			 ((unsigned long)pccb->pdata[7]);
-		return 0;
-	}
-
-	/* Read capacity (10) was insufficient. Use read capacity (16). */
-
-	memset(pccb->cmd, 0, sizeof(pccb->cmd));
-	pccb->cmd[0] = SCSI_RD_CAPAC16;
-	pccb->cmd[1] = 0x10;
-	pccb->cmdlen = 16;
-	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
-
-	pccb->datalen = 16;
-	if (scsi_exec(pccb) != true)
-		return 1;
-
-	*capacity = ((uint64_t)pccb->pdata[0] << 56) |
-		    ((uint64_t)pccb->pdata[1] << 48) |
-		    ((uint64_t)pccb->pdata[2] << 40) |
-		    ((uint64_t)pccb->pdata[3] << 32) |
-		    ((uint64_t)pccb->pdata[4] << 24) |
-		    ((uint64_t)pccb->pdata[5] << 16) |
-		    ((uint64_t)pccb->pdata[6] << 8)  |
-		    ((uint64_t)pccb->pdata[7]);
-
-	*blksz = ((uint64_t)pccb->pdata[8]  << 56) |
-		 ((uint64_t)pccb->pdata[9]  << 48) |
-		 ((uint64_t)pccb->pdata[10] << 40) |
-		 ((uint64_t)pccb->pdata[11] << 32) |
-		 ((uint64_t)pccb->pdata[12] << 24) |
-		 ((uint64_t)pccb->pdata[13] << 16) |
-		 ((uint64_t)pccb->pdata[14] << 8)  |
-		 ((uint64_t)pccb->pdata[15]);
-
-	return 0;
-}
-
-
-/************************************************************************************
- * Some setup (fill-in) routines
- */
-void scsi_setup_test_unit_ready(ccb * pccb)
-{
-	pccb->cmd[0]=SCSI_TST_U_RDY;
-	pccb->cmd[1]=pccb->lun<<5;
-	pccb->cmd[2]=0;
-	pccb->cmd[3]=0;
-	pccb->cmd[4]=0;
-	pccb->cmd[5]=0;
-	pccb->cmdlen=6;
-	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-}
-
-#ifdef CONFIG_SYS_64BIT_LBA
-void scsi_setup_read16(ccb * pccb, lbaint_t start, unsigned long blocks)
-{
-	pccb->cmd[0] = SCSI_READ16;
-	pccb->cmd[1] = pccb->lun<<5;
-	pccb->cmd[2] = ((unsigned char) (start >> 56)) & 0xff;
-	pccb->cmd[3] = ((unsigned char) (start >> 48)) & 0xff;
-	pccb->cmd[4] = ((unsigned char) (start >> 40)) & 0xff;
-	pccb->cmd[5] = ((unsigned char) (start >> 32)) & 0xff;
-	pccb->cmd[6] = ((unsigned char) (start >> 24)) & 0xff;
-	pccb->cmd[7] = ((unsigned char) (start >> 16)) & 0xff;
-	pccb->cmd[8] = ((unsigned char) (start >> 8)) & 0xff;
-	pccb->cmd[9] = ((unsigned char) (start)) & 0xff;
-	pccb->cmd[10] = 0;
-	pccb->cmd[11] = ((unsigned char) (blocks >> 24)) & 0xff;
-	pccb->cmd[12] = ((unsigned char) (blocks >> 16)) & 0xff;
-	pccb->cmd[13] = ((unsigned char) (blocks >> 8)) & 0xff;
-	pccb->cmd[14] = (unsigned char) blocks & 0xff;
-	pccb->cmd[15] = 0;
-	pccb->cmdlen = 16;
-	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
-	debug ("scsi_setup_read16: cmd: %02X %02X "
-	       "startblk %02X%02X%02X%02X%02X%02X%02X%02X "
-	       "blccnt %02X%02X%02X%02X\n",
-		pccb->cmd[0], pccb->cmd[1],
-		pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
-		pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
-		pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
-}
-#endif
-
-void scsi_setup_read_ext(ccb * pccb, lbaint_t start, unsigned short blocks)
-{
-	pccb->cmd[0]=SCSI_READ10;
-	pccb->cmd[1]=pccb->lun<<5;
-	pccb->cmd[2]=((unsigned char) (start>>24))&0xff;
-	pccb->cmd[3]=((unsigned char) (start>>16))&0xff;
-	pccb->cmd[4]=((unsigned char) (start>>8))&0xff;
-	pccb->cmd[5]=((unsigned char) (start))&0xff;
-	pccb->cmd[6]=0;
-	pccb->cmd[7]=((unsigned char) (blocks>>8))&0xff;
-	pccb->cmd[8]=(unsigned char) blocks & 0xff;
-	pccb->cmd[6]=0;
-	pccb->cmdlen=10;
-	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-	debug ("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
-		pccb->cmd[0],pccb->cmd[1],
-		pccb->cmd[2],pccb->cmd[3],pccb->cmd[4],pccb->cmd[5],
-		pccb->cmd[7],pccb->cmd[8]);
-}
-
-void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks)
-{
-	pccb->cmd[0] = SCSI_WRITE10;
-	pccb->cmd[1] = pccb->lun << 5;
-	pccb->cmd[2] = ((unsigned char) (start>>24)) & 0xff;
-	pccb->cmd[3] = ((unsigned char) (start>>16)) & 0xff;
-	pccb->cmd[4] = ((unsigned char) (start>>8)) & 0xff;
-	pccb->cmd[5] = ((unsigned char) (start)) & 0xff;
-	pccb->cmd[6] = 0;
-	pccb->cmd[7] = ((unsigned char) (blocks>>8)) & 0xff;
-	pccb->cmd[8] = (unsigned char)blocks & 0xff;
-	pccb->cmd[9] = 0;
-	pccb->cmdlen = 10;
-	pccb->msgout[0] = SCSI_IDENTIFY;  /* NOT USED */
-	debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
-	      __func__,
-	      pccb->cmd[0], pccb->cmd[1],
-	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
-	      pccb->cmd[7], pccb->cmd[8]);
-}
-
-void scsi_setup_read6(ccb * pccb, lbaint_t start, unsigned short blocks)
-{
-	pccb->cmd[0]=SCSI_READ6;
-	pccb->cmd[1]=pccb->lun<<5 | (((unsigned char)(start>>16))&0x1f);
-	pccb->cmd[2]=((unsigned char) (start>>8))&0xff;
-	pccb->cmd[3]=((unsigned char) (start))&0xff;
-	pccb->cmd[4]=(unsigned char) blocks & 0xff;
-	pccb->cmd[5]=0;
-	pccb->cmdlen=6;
-	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-	debug ("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n",
-		pccb->cmd[0],pccb->cmd[1],
-		pccb->cmd[2],pccb->cmd[3],pccb->cmd[4]);
-}
-
-
-void scsi_setup_inquiry(ccb * pccb)
-{
-	pccb->cmd[0]=SCSI_INQUIRY;
-	pccb->cmd[1]=pccb->lun<<5;
-	pccb->cmd[2]=0;
-	pccb->cmd[3]=0;
-	if(pccb->datalen>255)
-		pccb->cmd[4]=255;
-	else
-		pccb->cmd[4]=(unsigned char)pccb->datalen;
-	pccb->cmd[5]=0;
-	pccb->cmdlen=6;
-	pccb->msgout[0]=SCSI_IDENTIFY; /* NOT USED */
-}
diff --git a/cmd/usb.c b/cmd/usb.c
index f1a7deb..b83d323 100644
--- a/cmd/usb.c
+++ b/cmd/usb.c
@@ -723,7 +723,8 @@
 		int devno, ok = 0;
 		if (argc == 2) {
 			for (devno = 0; ; ++devno) {
-				stor_dev = usb_stor_get_dev(devno);
+				stor_dev = blk_get_devnum_by_type(IF_TYPE_USB,
+								  devno);
 				if (stor_dev == NULL)
 					break;
 				if (stor_dev->type != DEV_TYPE_UNKNOWN) {
@@ -736,7 +737,7 @@
 			}
 		} else {
 			devno = simple_strtoul(argv[2], NULL, 16);
-			stor_dev = usb_stor_get_dev(devno);
+			stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, devno);
 			if (stor_dev != NULL &&
 			    stor_dev->type != DEV_TYPE_UNKNOWN) {
 				ok++;
@@ -762,7 +763,8 @@
 			unsigned long n;
 			printf("\nUSB read: device %d block # %ld, count %ld"
 				" ... ", usb_stor_curr_dev, blk, cnt);
-			stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+			stor_dev = blk_get_devnum_by_type(IF_TYPE_USB,
+							  usb_stor_curr_dev);
 			n = blk_dread(stor_dev, blk, cnt, (ulong *)addr);
 			printf("%ld blocks read: %s\n", n,
 				(n == cnt) ? "OK" : "ERROR");
@@ -783,7 +785,8 @@
 			unsigned long n;
 			printf("\nUSB write: device %d block # %ld, count %ld"
 				" ... ", usb_stor_curr_dev, blk, cnt);
-			stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+			stor_dev = blk_get_devnum_by_type(IF_TYPE_USB,
+							  usb_stor_curr_dev);
 			n = blk_dwrite(stor_dev, blk, cnt, (ulong *)addr);
 			printf("%ld blocks write: %s\n", n,
 				(n == cnt) ? "OK" : "ERROR");
@@ -796,7 +799,7 @@
 		if (argc == 3) {
 			int dev = (int)simple_strtoul(argv[2], NULL, 10);
 			printf("\nUSB device %d: ", dev);
-			stor_dev = usb_stor_get_dev(dev);
+			stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, dev);
 			if (stor_dev == NULL) {
 				printf("unknown device\n");
 				return 1;
@@ -810,7 +813,8 @@
 			return 0;
 		} else {
 			printf("\nUSB device %d: ", usb_stor_curr_dev);
-			stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+			stor_dev = blk_get_devnum_by_type(IF_TYPE_USB,
+							  usb_stor_curr_dev);
 			dev_print(stor_dev);
 			if (stor_dev->type == DEV_TYPE_UNKNOWN)
 				return 1;
diff --git a/common/Makefile b/common/Makefile
index b23f312..0562d5c 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -84,6 +84,8 @@
 obj-$(CONFIG_LCD_DT_SIMPLEFB) += lcd_simplefb.o
 obj-$(CONFIG_LYNXKDI) += lynxkdi.o
 obj-$(CONFIG_MENU) += menu.o
+obj-$(CONFIG_CMD_SATA) += sata.o
+obj-$(CONFIG_SCSI) += scsi.o
 obj-$(CONFIG_UPDATE_TFTP) += update.o
 obj-$(CONFIG_DFU_TFTP) += update.o
 obj-$(CONFIG_USB_KEYBOARD) += usb_kbd.o
@@ -112,6 +114,9 @@
 obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
 obj-$(CONFIG_ENV_IS_IN_FLASH) += env_flash.o
 endif
+ifdef CONFIG_SPL_SATA_SUPPORT
+obj-$(CONFIG_SCSI) += scsi.o
+endif
 endif
 #environment
 obj-y += env_common.o
@@ -130,6 +135,7 @@
 ifdef CONFIG_SYS_MALLOC_F_LEN
 obj-y += malloc_simple.o
 endif
+obj-$(CONFIG_CMD_IDE) += ide.o
 obj-y += image.o
 obj-$(CONFIG_ANDROID_BOOT_IMAGE) += image-android.o
 obj-$(CONFIG_$(SPL_)OF_LIBFDT) += image-fdt.o
@@ -150,6 +156,9 @@
 endif
 endif
 
+ifdef CONFIG_CMD_EEPROM_LAYOUT
+obj-y += eeprom/eeprom_field.o eeprom/eeprom_layout.o
+endif
 # We always have this since drivers/ddr/fs/interactive.c needs it
 obj-$(CONFIG_CMDLINE) += cli_simple.o
 
diff --git a/common/board_r.c b/common/board_r.c
index ad02549..d959ad3 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -620,7 +620,7 @@
 }
 #endif
 
-#if defined(CONFIG_CMD_SCSI)
+#if defined(CONFIG_SCSI)
 static int initr_scsi(void)
 {
 	puts("SCSI:  ");
@@ -923,7 +923,7 @@
 	initr_ambapp_print,
 #endif
 #endif
-#ifdef CONFIG_CMD_SCSI
+#ifdef CONFIG_SCSI
 	INIT_FUNC_WATCHDOG_RESET
 	initr_scsi,
 #endif
diff --git a/common/dlmalloc.c b/common/dlmalloc.c
index b09f524..adc680e 100644
--- a/common/dlmalloc.c
+++ b/common/dlmalloc.c
@@ -1909,6 +1909,7 @@
   * fulfill the user's request.
   */
   if (m == NULL) {
+    size_t extra, extra2;
     /*
      * Use bytes not nb, since mALLOc internally calls request2size too, and
      * each call increases the size to allocate, to account for the header.
@@ -1917,9 +1918,27 @@
     /* Aligned -> return it */
     if ((((unsigned long)(m)) % alignment) == 0)
       return m;
-    /* Otherwise, fail */
+    /*
+     * Otherwise, try again, requesting enough extra space to be able to
+     * acquire alignment.
+     */
     fREe(m);
-    m = NULL;
+    /* Add in extra bytes to match misalignment of unexpanded allocation */
+    extra = alignment - (((unsigned long)(m)) % alignment);
+    m  = (char*)(mALLOc(bytes + extra));
+    /*
+     * m might not be the same as before. Validate that the previous value of
+     * extra still works for the current value of m.
+     * If (!m), extra2=alignment so 
+     */
+    if (m) {
+      extra2 = alignment - (((unsigned long)(m)) % alignment);
+      if (extra2 > extra) {
+        fREe(m);
+        m = NULL;
+      }
+    }
+    /* Fall through to original NULL check and chunk splitting logic */
   }
 
   if (m == NULL) return NULL; /* propagate failure */
diff --git a/common/eeprom/eeprom_field.c b/common/eeprom/eeprom_field.c
new file mode 100644
index 0000000..7f095a6
--- /dev/null
+++ b/common/eeprom/eeprom_field.c
@@ -0,0 +1,250 @@
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/string.h>
+#include <eeprom_field.h>
+
+static void __eeprom_field_print_bin(const struct eeprom_field *field,
+				     char *delimiter, bool reverse)
+{
+	int i;
+	int from = reverse ? field->size - 1 : 0;
+	int to = reverse ? 0 : field->size - 1;
+
+	printf(PRINT_FIELD_SEGMENT, field->name);
+	for (i = from; i != to; reverse ? i-- : i++)
+		printf("%02x%s", field->buf[i], delimiter);
+
+	printf("%02x\n", field->buf[i]);
+}
+
+static int __eeprom_field_update_bin(struct eeprom_field *field,
+				     const char *value, bool reverse)
+{
+	int len = strlen(value);
+	int k, j, i = reverse ? len - 1 : 0;
+	unsigned char byte;
+	char *endptr;
+
+	/* each two characters in the string fit in one byte */
+	if (len > field->size * 2)
+		return -1;
+
+	memset(field->buf, 0, field->size);
+
+	/* i - string iterator, j - buf iterator */
+	for (j = 0; j < field->size; j++) {
+		byte = 0;
+		char tmp[3] = { 0, 0, 0 };
+
+		if ((reverse && i < 0) || (!reverse && i >= len))
+			break;
+
+		for (k = 0; k < 2; k++) {
+			if (reverse && i == 0) {
+				tmp[k] = value[i];
+				break;
+			}
+
+			tmp[k] = value[reverse ? i - 1 + k : i + k];
+		}
+
+		byte = simple_strtoul(tmp, &endptr, 0);
+		if (*endptr != '\0' || byte < 0)
+			return -1;
+
+		field->buf[j] = byte;
+		i = reverse ? i - 2 : i + 2;
+	}
+
+	return 0;
+}
+
+static int __eeprom_field_update_bin_delim(struct eeprom_field *field,
+					   char *value, char *delimiter)
+{
+	int count = 0;
+	int i, val;
+	const char *tmp = value;
+	char *tok;
+	char *endptr;
+
+	tmp = strstr(tmp, delimiter);
+	while (tmp != NULL) {
+		count++;
+		tmp++;
+		tmp = strstr(tmp, delimiter);
+	}
+
+	if (count > field->size)
+		return -1;
+
+	tok = strtok(value, delimiter);
+	for (i = 0; tok && i < field->size; i++) {
+		val = simple_strtoul(tok, &endptr, 0);
+		if (*endptr != '\0')
+			return -1;
+
+		/* here we assume that each tok is no more than byte long */
+		field->buf[i] = (unsigned char)val;
+		tok = strtok(NULL, delimiter);
+	}
+
+	return 0;
+}
+
+/**
+ * eeprom_field_print_bin() - print a field which contains binary data
+ *
+ * Treat the field data as simple binary data, and print it as two digit
+ * hexadecimal values.
+ * Sample output:
+ *      Field Name       0102030405060708090a
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_bin(const struct eeprom_field *field)
+{
+	__eeprom_field_print_bin(field, "", false);
+}
+
+/**
+ * eeprom_field_update_bin() - Update field with new data in binary form
+ *
+ * @field:	an initialized field
+ * @value:	a string of values (i.e. "10b234a")
+ */
+int eeprom_field_update_bin(struct eeprom_field *field, char *value)
+{
+	return __eeprom_field_update_bin(field, value, false);
+}
+
+/**
+ * eeprom_field_update_reserved() - Update reserved field with new data in
+ *				    binary form
+ *
+ * @field:	an initialized field
+ * @value:	a space delimited string of byte values (i.e. "1 02 3 0x4")
+ */
+int eeprom_field_update_reserved(struct eeprom_field *field, char *value)
+{
+	return __eeprom_field_update_bin_delim(field, value, " ");
+}
+
+/**
+ * eeprom_field_print_bin_rev() - print a field which contains binary data in
+ *				  reverse order
+ *
+ * Treat the field data as simple binary data, and print it in reverse order
+ * as two digit hexadecimal values.
+ *
+ * Data in field:
+ *                      0102030405060708090a
+ * Sample output:
+ *      Field Name      0a090807060504030201
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_bin_rev(const struct eeprom_field *field)
+{
+	__eeprom_field_print_bin(field, "", true);
+}
+
+/**
+ * eeprom_field_update_bin_rev() - Update field with new data in binary form,
+ *				   storing it in reverse
+ *
+ * This function takes a string of byte values, and stores them
+ * in the field in the reverse order. i.e. if the input string was "1234",
+ * "3412" will be written to the field.
+ *
+ * @field:	an initialized field
+ * @value:	a string of byte values
+ */
+int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value)
+{
+	return __eeprom_field_update_bin(field, value, true);
+}
+
+/**
+ * eeprom_field_print_mac_addr() - print a field which contains a mac address
+ *
+ * Treat the field data as simple binary data, and print it formatted as a MAC
+ * address.
+ * Sample output:
+ *      Field Name     01:02:03:04:05:06
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_mac(const struct eeprom_field *field)
+{
+	__eeprom_field_print_bin(field, ":", false);
+}
+
+/**
+ * eeprom_field_update_mac() - Update a mac address field which contains binary
+ *			       data
+ *
+ * @field:	an initialized field
+ * @value:	a colon delimited string of byte values (i.e. "1:02:3:ff")
+ */
+int eeprom_field_update_mac(struct eeprom_field *field, char *value)
+{
+	return __eeprom_field_update_bin_delim(field, value, ":");
+}
+
+/**
+ * eeprom_field_print_ascii() - print a field which contains ASCII data
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_ascii(const struct eeprom_field *field)
+{
+	char format[8];
+
+	sprintf(format, "%%.%ds\n", field->size);
+	printf(PRINT_FIELD_SEGMENT, field->name);
+	printf(format, field->buf);
+}
+
+/**
+ * eeprom_field_update_ascii() - Update field with new data in ASCII form
+ * @field:	an initialized field
+ * @value:	the new string data
+ *
+ * Returns 0 on success, -1 of failure (new string too long).
+ */
+int eeprom_field_update_ascii(struct eeprom_field *field, char *value)
+{
+	if (strlen(value) >= field->size) {
+		printf("%s: new data too long\n", field->name);
+		return -1;
+	}
+
+	strncpy((char *)field->buf, value, field->size - 1);
+	field->buf[field->size - 1] = '\0';
+
+	return 0;
+}
+
+/**
+ * eeprom_field_print_reserved() - print the "Reserved fields" field
+ *
+ * Print a notice that the following field_size bytes are reserved.
+ *
+ * Sample output:
+ *      Reserved fields              (64 bytes)
+ *
+ * @field:	an initialized field to print
+ */
+void eeprom_field_print_reserved(const struct eeprom_field *field)
+{
+	printf(PRINT_FIELD_SEGMENT, "Reserved fields\t");
+	printf("(%d bytes)\n", field->size);
+}
diff --git a/common/eeprom/eeprom_layout.c b/common/eeprom/eeprom_layout.c
new file mode 100644
index 0000000..c059233
--- /dev/null
+++ b/common/eeprom/eeprom_layout.c
@@ -0,0 +1,125 @@
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/kernel.h>
+#include <eeprom_layout.h>
+#include <eeprom_field.h>
+
+#define NO_LAYOUT_FIELDS	"Unknown layout. Dumping raw data\n"
+
+struct eeprom_field layout_unknown[1] = {
+	{ NO_LAYOUT_FIELDS, 256, NULL, eeprom_field_print_bin,
+				       eeprom_field_update_bin },
+};
+
+/*
+ * eeprom_layout_detect() - detect layout based on the contents of the data.
+ * @data: Pointer to the data to be analyzed.
+ *
+ * Returns: the detected layout version.
+ */
+__weak int eeprom_layout_detect(unsigned char *data)
+{
+	return LAYOUT_VERSION_UNRECOGNIZED;
+}
+
+/*
+ * __eeprom_layout_assign() - set the layout fields
+ * @layout:		A pointer to an existing struct layout.
+ * @layout_version:	The version number of the desired layout
+ */
+__weak void __eeprom_layout_assign(struct eeprom_layout *layout,
+				   int layout_version)
+{
+	layout->fields = layout_unknown;
+	layout->num_of_fields = ARRAY_SIZE(layout_unknown);
+}
+void eeprom_layout_assign(struct eeprom_layout *layout, int layout_version) \
+		__attribute__((weak, alias("__eeprom_layout_assign")));
+
+/*
+ * eeprom_layout_print() - print the layout and the data which is assigned to it
+ * @layout: A pointer to an existing struct layout.
+ */
+static void eeprom_layout_print(const struct eeprom_layout *layout)
+{
+	int i;
+	struct eeprom_field *fields = layout->fields;
+
+	for (i = 0; i < layout->num_of_fields; i++)
+		fields[i].print(&fields[i]);
+}
+
+/*
+ * eeprom_layout_update_field() - update a single field in the layout data.
+ * @layout:	A pointer to an existing struct layout.
+ * @field_name:	The name of the field to update.
+ * @new_data:	The new field data (a string. Format depends on the field)
+ *
+ * Returns: 0 on success, negative error value on failure.
+ */
+static int eeprom_layout_update_field(struct eeprom_layout *layout,
+				      char *field_name, char *new_data)
+{
+	int i, err;
+	struct eeprom_field *fields = layout->fields;
+
+	if (new_data == NULL)
+		return 0;
+
+	if (field_name == NULL)
+		return -1;
+
+	for (i = 0; i < layout->num_of_fields; i++) {
+		if (fields[i].name == RESERVED_FIELDS ||
+		    strcmp(fields[i].name, field_name))
+			continue;
+
+		err = fields[i].update(&fields[i], new_data);
+		if (err)
+			printf("Invalid data for field %s\n", field_name);
+
+		return err;
+	}
+
+	printf("No such field '%s'\n", field_name);
+
+	return -1;
+}
+
+/*
+ * eeprom_layout_setup() - setup layout struct with the layout data and
+ *			   metadata as dictated by layout_version
+ * @layout:	A pointer to an existing struct layout.
+ * @buf:	A buffer initialized with the eeprom data.
+ * @buf_size:	Size of buf in bytes.
+ * @layout version: The version number of the layout.
+ */
+void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf,
+			 unsigned int buf_size, int layout_version)
+{
+	int i;
+
+	if (layout_version == LAYOUT_VERSION_AUTODETECT)
+		layout->layout_version = eeprom_layout_detect(buf);
+	else
+		layout->layout_version = layout_version;
+
+	eeprom_layout_assign(layout, layout_version);
+	layout->data = buf;
+	for (i = 0; i < layout->num_of_fields; i++) {
+		layout->fields[i].buf = buf;
+		buf += layout->fields[i].size;
+	}
+
+	layout->data_size = buf_size;
+	layout->print = eeprom_layout_print;
+	layout->update = eeprom_layout_update_field;
+}
diff --git a/common/env_mmc.c b/common/env_mmc.c
index bdb452e..c7fef18 100644
--- a/common/env_mmc.c
+++ b/common/env_mmc.c
@@ -86,8 +86,8 @@
 	dev = 0;
 #endif
 
-	env_mmc_orig_hwpart = mmc->block_dev.hwpart;
-	ret = mmc_select_hwpart(dev, part);
+	env_mmc_orig_hwpart = mmc_get_blk_desc(mmc)->hwpart;
+	ret = blk_select_hwpart_devnum(IF_TYPE_MMC, dev, part);
 	if (ret)
 		puts("MMC partition switch failed\n");
 
@@ -119,7 +119,7 @@
 #ifdef CONFIG_SPL_BUILD
 	dev = 0;
 #endif
-	mmc_select_hwpart(dev, env_mmc_orig_hwpart);
+	blk_select_hwpart_devnum(IF_TYPE_MMC, dev, env_mmc_orig_hwpart);
 #endif
 }
 
diff --git a/common/ide.c b/common/ide.c
new file mode 100644
index 0000000..ac5b91c
--- /dev/null
+++ b/common/ide.c
@@ -0,0 +1,1231 @@
+/*
+ * (C) Copyright 2000-2011
+ * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <ata.h>
+#include <dm.h>
+#include <ide.h>
+#include <watchdog.h>
+#include <asm/io.h>
+
+#ifdef __PPC__
+# define EIEIO		__asm__ volatile ("eieio")
+# define SYNC		__asm__ volatile ("sync")
+#else
+# define EIEIO		/* nothing */
+# define SYNC		/* nothing */
+#endif
+
+/* Current offset for IDE0 / IDE1 bus access	*/
+ulong ide_bus_offset[CONFIG_SYS_IDE_MAXBUS] = {
+#if defined(CONFIG_SYS_ATA_IDE0_OFFSET)
+	CONFIG_SYS_ATA_IDE0_OFFSET,
+#endif
+#if defined(CONFIG_SYS_ATA_IDE1_OFFSET) && (CONFIG_SYS_IDE_MAXBUS > 1)
+	CONFIG_SYS_ATA_IDE1_OFFSET,
+#endif
+};
+
+static int ide_bus_ok[CONFIG_SYS_IDE_MAXBUS];
+
+struct blk_desc ide_dev_desc[CONFIG_SYS_IDE_MAXDEVICE];
+
+#define IDE_TIME_OUT	2000	/* 2 sec timeout */
+
+#define ATAPI_TIME_OUT	7000	/* 7 sec timeout (5 sec seems to work...) */
+
+#define IDE_SPIN_UP_TIME_OUT 5000 /* 5 sec spin-up timeout */
+
+#ifndef CONFIG_SYS_ATA_PORT_ADDR
+#define CONFIG_SYS_ATA_PORT_ADDR(port) (port)
+#endif
+
+#ifndef CONFIG_IDE_LED	/* define LED macros, they are not used anyways */
+# define DEVICE_LED(x) 0
+# define LED_IDE1 1
+# define LED_IDE2 2
+#endif
+
+#ifdef CONFIG_IDE_RESET
+extern void ide_set_reset(int idereset);
+
+static void ide_reset(void)
+{
+	int i;
+
+	for (i = 0; i < CONFIG_SYS_IDE_MAXBUS; ++i)
+		ide_bus_ok[i] = 0;
+	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i)
+		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+
+	ide_set_reset(1);	/* assert reset */
+
+	/* the reset signal shall be asserted for et least 25 us */
+	udelay(25);
+
+	WATCHDOG_RESET();
+
+	/* de-assert RESET signal */
+	ide_set_reset(0);
+
+	/* wait 250 ms */
+	for (i = 0; i < 250; ++i)
+		udelay(1000);
+}
+#else
+#define ide_reset()	/* dummy */
+#endif /* CONFIG_IDE_RESET */
+
+/*
+ * Wait until Busy bit is off, or timeout (in ms)
+ * Return last status
+ */
+static uchar ide_wait(int dev, ulong t)
+{
+	ulong delay = 10 * t;	/* poll every 100 us */
+	uchar c;
+
+	while ((c = ide_inb(dev, ATA_STATUS)) & ATA_STAT_BUSY) {
+		udelay(100);
+		if (delay-- == 0)
+			break;
+	}
+	return c;
+}
+
+/*
+ * copy src to dest, skipping leading and trailing blanks and null
+ * terminate the string
+ * "len" is the size of available memory including the terminating '\0'
+ */
+static void ident_cpy(unsigned char *dst, unsigned char *src,
+		      unsigned int len)
+{
+	unsigned char *end, *last;
+
+	last = dst;
+	end = src + len - 1;
+
+	/* reserve space for '\0' */
+	if (len < 2)
+		goto OUT;
+
+	/* skip leading white space */
+	while ((*src) && (src < end) && (*src == ' '))
+		++src;
+
+	/* copy string, omitting trailing white space */
+	while ((*src) && (src < end)) {
+		*dst++ = *src;
+		if (*src++ != ' ')
+			last = dst;
+	}
+OUT:
+	*last = '\0';
+}
+
+#ifdef CONFIG_ATAPI
+/****************************************************************************
+ * ATAPI Support
+ */
+
+#if defined(CONFIG_IDE_SWAP_IO)
+/* since ATAPI may use commands with not 4 bytes alligned length
+ * we have our own transfer functions, 2 bytes alligned */
+__weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort *dbuf;
+	volatile ushort *pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+
+	debug("in output data shorts base for read is %lx\n",
+	      (unsigned long) pbuf);
+
+	while (shorts--) {
+		EIEIO;
+		*pbuf = *dbuf++;
+	}
+}
+
+__weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	ushort *dbuf;
+	volatile ushort *pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+
+	debug("in input data shorts base for read is %lx\n",
+	      (unsigned long) pbuf);
+
+	while (shorts--) {
+		EIEIO;
+		*dbuf++ = *pbuf;
+	}
+}
+
+#else  /* ! CONFIG_IDE_SWAP_IO */
+__weak void ide_output_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
+}
+
+__weak void ide_input_data_shorts(int dev, ushort *sect_buf, int shorts)
+{
+	insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, shorts);
+}
+
+#endif /* CONFIG_IDE_SWAP_IO */
+
+/*
+ * Wait until (Status & mask) == res, or timeout (in ms)
+ * Return last status
+ * This is used since some ATAPI CD ROMs clears their Busy Bit first
+ * and then they set their DRQ Bit
+ */
+static uchar atapi_wait_mask(int dev, ulong t, uchar mask, uchar res)
+{
+	ulong delay = 10 * t;	/* poll every 100 us */
+	uchar c;
+
+	/* prevents to read the status before valid */
+	c = ide_inb(dev, ATA_DEV_CTL);
+
+	while (((c = ide_inb(dev, ATA_STATUS)) & mask) != res) {
+		/* break if error occurs (doesn't make sense to wait more) */
+		if ((c & ATA_STAT_ERR) == ATA_STAT_ERR)
+			break;
+		udelay(100);
+		if (delay-- == 0)
+			break;
+	}
+	return c;
+}
+
+/*
+ * issue an atapi command
+ */
+unsigned char atapi_issue(int device, unsigned char *ccb, int ccblen,
+			  unsigned char *buffer, int buflen)
+{
+	unsigned char c, err, mask, res;
+	int n;
+
+	ide_led(DEVICE_LED(device), 1);	/* LED on       */
+
+	/* Select device
+	 */
+	mask = ATA_STAT_BUSY | ATA_STAT_DRQ;
+	res = 0;
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
+	if ((c & mask) != res) {
+		printf("ATAPI_ISSUE: device %d not ready status %X\n", device,
+		       c);
+		err = 0xFF;
+		goto AI_OUT;
+	}
+	/* write taskfile */
+	ide_outb(device, ATA_ERROR_REG, 0);	/* no DMA, no overlaped */
+	ide_outb(device, ATA_SECT_CNT, 0);
+	ide_outb(device, ATA_SECT_NUM, 0);
+	ide_outb(device, ATA_CYL_LOW, (unsigned char) (buflen & 0xFF));
+	ide_outb(device, ATA_CYL_HIGH,
+		 (unsigned char) ((buflen >> 8) & 0xFF));
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+	ide_outb(device, ATA_COMMAND, ATAPI_CMD_PACKET);
+	udelay(50);
+
+	mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
+	res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
+
+	if ((c & mask) != res) {	/* DRQ must be 1, BSY 0 */
+		printf("ATAPI_ISSUE: Error (no IRQ) before sending ccb dev %d status 0x%02x\n",
+		       device, c);
+		err = 0xFF;
+		goto AI_OUT;
+	}
+
+	/* write command block */
+	ide_output_data_shorts(device, (unsigned short *)ccb, ccblen / 2);
+
+	/* ATAPI Command written wait for completition */
+	udelay(5000);		/* device must set bsy */
+
+	mask = ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR;
+	/*
+	 * if no data wait for DRQ = 0 BSY = 0
+	 * if data wait for DRQ = 1 BSY = 0
+	 */
+	res = 0;
+	if (buflen)
+		res = ATA_STAT_DRQ;
+	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
+	if ((c & mask) != res) {
+		if (c & ATA_STAT_ERR) {
+			err = (ide_inb(device, ATA_ERROR_REG)) >> 4;
+			debug("atapi_issue 1 returned sense key %X status %02X\n",
+			      err, c);
+		} else {
+			printf("ATAPI_ISSUE: (no DRQ) after sending ccb (%x)  status 0x%02x\n",
+			       ccb[0], c);
+			err = 0xFF;
+		}
+		goto AI_OUT;
+	}
+	n = ide_inb(device, ATA_CYL_HIGH);
+	n <<= 8;
+	n += ide_inb(device, ATA_CYL_LOW);
+	if (n > buflen) {
+		printf("ERROR, transfer bytes %d requested only %d\n", n,
+		       buflen);
+		err = 0xff;
+		goto AI_OUT;
+	}
+	if ((n == 0) && (buflen < 0)) {
+		printf("ERROR, transfer bytes %d requested %d\n", n, buflen);
+		err = 0xff;
+		goto AI_OUT;
+	}
+	if (n != buflen) {
+		debug("WARNING, transfer bytes %d not equal with requested %d\n",
+		      n, buflen);
+	}
+	if (n != 0) {		/* data transfer */
+		debug("ATAPI_ISSUE: %d Bytes to transfer\n", n);
+		/* we transfer shorts */
+		n >>= 1;
+		/* ok now decide if it is an in or output */
+		if ((ide_inb(device, ATA_SECT_CNT) & 0x02) == 0) {
+			debug("Write to device\n");
+			ide_output_data_shorts(device, (unsigned short *)buffer,
+					       n);
+		} else {
+			debug("Read from device @ %p shorts %d\n", buffer, n);
+			ide_input_data_shorts(device, (unsigned short *)buffer,
+					      n);
+		}
+	}
+	udelay(5000);		/* seems that some CD ROMs need this... */
+	mask = ATA_STAT_BUSY | ATA_STAT_ERR;
+	res = 0;
+	c = atapi_wait_mask(device, ATAPI_TIME_OUT, mask, res);
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		err = (ide_inb(device, ATA_ERROR_REG) >> 4);
+		debug("atapi_issue 2 returned sense key %X status %X\n", err,
+		      c);
+	} else {
+		err = 0;
+	}
+AI_OUT:
+	ide_led(DEVICE_LED(device), 0);	/* LED off      */
+	return err;
+}
+
+/*
+ * sending the command to atapi_issue. If an status other than good
+ * returns, an request_sense will be issued
+ */
+
+#define ATAPI_DRIVE_NOT_READY	100
+#define ATAPI_UNIT_ATTN		10
+
+unsigned char atapi_issue_autoreq(int device,
+				  unsigned char *ccb,
+				  int ccblen,
+				  unsigned char *buffer, int buflen)
+{
+	unsigned char sense_data[18], sense_ccb[12];
+	unsigned char res, key, asc, ascq;
+	int notready, unitattn;
+
+	unitattn = ATAPI_UNIT_ATTN;
+	notready = ATAPI_DRIVE_NOT_READY;
+
+retry:
+	res = atapi_issue(device, ccb, ccblen, buffer, buflen);
+	if (res == 0)
+		return 0;	/* Ok */
+
+	if (res == 0xFF)
+		return 0xFF;	/* error */
+
+	debug("(auto_req)atapi_issue returned sense key %X\n", res);
+
+	memset(sense_ccb, 0, sizeof(sense_ccb));
+	memset(sense_data, 0, sizeof(sense_data));
+	sense_ccb[0] = ATAPI_CMD_REQ_SENSE;
+	sense_ccb[4] = 18;	/* allocation Length */
+
+	res = atapi_issue(device, sense_ccb, 12, sense_data, 18);
+	key = (sense_data[2] & 0xF);
+	asc = (sense_data[12]);
+	ascq = (sense_data[13]);
+
+	debug("ATAPI_CMD_REQ_SENSE returned %x\n", res);
+	debug(" Sense page: %02X key %02X ASC %02X ASCQ %02X\n",
+	      sense_data[0], key, asc, ascq);
+
+	if ((key == 0))
+		return 0;	/* ok device ready */
+
+	if ((key == 6) || (asc == 0x29) || (asc == 0x28)) { /* Unit Attention */
+		if (unitattn-- > 0) {
+			udelay(200 * 1000);
+			goto retry;
+		}
+		printf("Unit Attention, tried %d\n", ATAPI_UNIT_ATTN);
+		goto error;
+	}
+	if ((asc == 0x4) && (ascq == 0x1)) {
+		/* not ready, but will be ready soon */
+		if (notready-- > 0) {
+			udelay(200 * 1000);
+			goto retry;
+		}
+		printf("Drive not ready, tried %d times\n",
+		       ATAPI_DRIVE_NOT_READY);
+		goto error;
+	}
+	if (asc == 0x3a) {
+		debug("Media not present\n");
+		goto error;
+	}
+
+	printf("ERROR: Unknown Sense key %02X ASC %02X ASCQ %02X\n", key, asc,
+	       ascq);
+error:
+	debug("ERROR Sense key %02X ASC %02X ASCQ %02X\n", key, asc, ascq);
+	return 0xFF;
+}
+
+/*
+ * atapi_read:
+ * we transfer only one block per command, since the multiple DRQ per
+ * command is not yet implemented
+ */
+#define ATAPI_READ_MAX_BYTES	2048	/* we read max 2kbytes */
+#define ATAPI_READ_BLOCK_SIZE	2048	/* assuming CD part */
+#define ATAPI_READ_MAX_BLOCK	(ATAPI_READ_MAX_BYTES/ATAPI_READ_BLOCK_SIZE)
+
+ulong atapi_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
+		 void *buffer)
+{
+	int device = block_dev->devnum;
+	ulong n = 0;
+	unsigned char ccb[12];	/* Command descriptor block */
+	ulong cnt;
+
+	debug("atapi_read dev %d start " LBAF " blocks " LBAF
+	      " buffer at %lX\n", device, blknr, blkcnt, (ulong) buffer);
+
+	do {
+		if (blkcnt > ATAPI_READ_MAX_BLOCK)
+			cnt = ATAPI_READ_MAX_BLOCK;
+		else
+			cnt = blkcnt;
+
+		ccb[0] = ATAPI_CMD_READ_12;
+		ccb[1] = 0;	/* reserved */
+		ccb[2] = (unsigned char) (blknr >> 24) & 0xFF;	/* MSB Block */
+		ccb[3] = (unsigned char) (blknr >> 16) & 0xFF;	/*  */
+		ccb[4] = (unsigned char) (blknr >> 8) & 0xFF;
+		ccb[5] = (unsigned char) blknr & 0xFF;	/* LSB Block */
+		ccb[6] = (unsigned char) (cnt >> 24) & 0xFF; /* MSB Block cnt */
+		ccb[7] = (unsigned char) (cnt >> 16) & 0xFF;
+		ccb[8] = (unsigned char) (cnt >> 8) & 0xFF;
+		ccb[9] = (unsigned char) cnt & 0xFF;	/* LSB Block */
+		ccb[10] = 0;	/* reserved */
+		ccb[11] = 0;	/* reserved */
+
+		if (atapi_issue_autoreq(device, ccb, 12,
+					(unsigned char *)buffer,
+					cnt * ATAPI_READ_BLOCK_SIZE)
+		    == 0xFF) {
+			return n;
+		}
+		n += cnt;
+		blkcnt -= cnt;
+		blknr += cnt;
+		buffer += (cnt * ATAPI_READ_BLOCK_SIZE);
+	} while (blkcnt > 0);
+	return n;
+}
+
+static void atapi_inquiry(struct blk_desc *dev_desc)
+{
+	unsigned char ccb[12];	/* Command descriptor block */
+	unsigned char iobuf[64];	/* temp buf */
+	unsigned char c;
+	int device;
+
+	device = dev_desc->devnum;
+	dev_desc->type = DEV_TYPE_UNKNOWN;	/* not yet valid */
+	dev_desc->block_read = atapi_read;
+
+	memset(ccb, 0, sizeof(ccb));
+	memset(iobuf, 0, sizeof(iobuf));
+
+	ccb[0] = ATAPI_CMD_INQUIRY;
+	ccb[4] = 40;		/* allocation Legnth */
+	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 40);
+
+	debug("ATAPI_CMD_INQUIRY returned %x\n", c);
+	if (c != 0)
+		return;
+
+	/* copy device ident strings */
+	ident_cpy((unsigned char *)dev_desc->vendor, &iobuf[8], 8);
+	ident_cpy((unsigned char *)dev_desc->product, &iobuf[16], 16);
+	ident_cpy((unsigned char *)dev_desc->revision, &iobuf[32], 5);
+
+	dev_desc->lun = 0;
+	dev_desc->lba = 0;
+	dev_desc->blksz = 0;
+	dev_desc->log2blksz = LOG2_INVALID(typeof(dev_desc->log2blksz));
+	dev_desc->type = iobuf[0] & 0x1f;
+
+	if ((iobuf[1] & 0x80) == 0x80)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+	memset(ccb, 0, sizeof(ccb));
+	memset(iobuf, 0, sizeof(iobuf));
+	ccb[0] = ATAPI_CMD_START_STOP;
+	ccb[4] = 0x03;		/* start */
+
+	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 0);
+
+	debug("ATAPI_CMD_START_STOP returned %x\n", c);
+	if (c != 0)
+		return;
+
+	memset(ccb, 0, sizeof(ccb));
+	memset(iobuf, 0, sizeof(iobuf));
+	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 0);
+
+	debug("ATAPI_CMD_UNIT_TEST_READY returned %x\n", c);
+	if (c != 0)
+		return;
+
+	memset(ccb, 0, sizeof(ccb));
+	memset(iobuf, 0, sizeof(iobuf));
+	ccb[0] = ATAPI_CMD_READ_CAP;
+	c = atapi_issue_autoreq(device, ccb, 12, (unsigned char *)iobuf, 8);
+	debug("ATAPI_CMD_READ_CAP returned %x\n", c);
+	if (c != 0)
+		return;
+
+	debug("Read Cap: LBA %02X%02X%02X%02X blksize %02X%02X%02X%02X\n",
+	      iobuf[0], iobuf[1], iobuf[2], iobuf[3],
+	      iobuf[4], iobuf[5], iobuf[6], iobuf[7]);
+
+	dev_desc->lba = ((unsigned long) iobuf[0] << 24) +
+		((unsigned long) iobuf[1] << 16) +
+		((unsigned long) iobuf[2] << 8) + ((unsigned long) iobuf[3]);
+	dev_desc->blksz = ((unsigned long) iobuf[4] << 24) +
+		((unsigned long) iobuf[5] << 16) +
+		((unsigned long) iobuf[6] << 8) + ((unsigned long) iobuf[7]);
+	dev_desc->log2blksz = LOG2(dev_desc->blksz);
+#ifdef CONFIG_LBA48
+	/* ATAPI devices cannot use 48bit addressing (ATA/ATAPI v7) */
+	dev_desc->lba48 = 0;
+#endif
+	return;
+}
+
+#endif /* CONFIG_ATAPI */
+
+static void ide_ident(struct blk_desc *dev_desc)
+{
+	unsigned char c;
+	hd_driveid_t iop;
+
+#ifdef CONFIG_ATAPI
+	int retries = 0;
+#endif
+	int device;
+
+	device = dev_desc->devnum;
+	printf("  Device %d: ", device);
+
+	ide_led(DEVICE_LED(device), 1);	/* LED on       */
+	/* Select device
+	 */
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	dev_desc->if_type = IF_TYPE_IDE;
+#ifdef CONFIG_ATAPI
+
+	retries = 0;
+
+	/* Warning: This will be tricky to read */
+	while (retries <= 1) {
+		/* check signature */
+		if ((ide_inb(device, ATA_SECT_CNT) == 0x01) &&
+		    (ide_inb(device, ATA_SECT_NUM) == 0x01) &&
+		    (ide_inb(device, ATA_CYL_LOW) == 0x14) &&
+		    (ide_inb(device, ATA_CYL_HIGH) == 0xEB)) {
+			/* ATAPI Signature found */
+			dev_desc->if_type = IF_TYPE_ATAPI;
+			/*
+			 * Start Ident Command
+			 */
+			ide_outb(device, ATA_COMMAND, ATAPI_CMD_IDENT);
+			/*
+			 * Wait for completion - ATAPI devices need more time
+			 * to become ready
+			 */
+			c = ide_wait(device, ATAPI_TIME_OUT);
+		} else
+#endif
+		{
+			/*
+			 * Start Ident Command
+			 */
+			ide_outb(device, ATA_COMMAND, ATA_CMD_IDENT);
+
+			/*
+			 * Wait for completion
+			 */
+			c = ide_wait(device, IDE_TIME_OUT);
+		}
+		ide_led(DEVICE_LED(device), 0);	/* LED off      */
+
+		if (((c & ATA_STAT_DRQ) == 0) ||
+		    ((c & (ATA_STAT_FAULT | ATA_STAT_ERR)) != 0)) {
+#ifdef CONFIG_ATAPI
+			{
+				/*
+				 * Need to soft reset the device
+				 * in case it's an ATAPI...
+				 */
+				debug("Retrying...\n");
+				ide_outb(device, ATA_DEV_HD,
+					 ATA_LBA | ATA_DEVICE(device));
+				udelay(100000);
+				ide_outb(device, ATA_COMMAND, 0x08);
+				udelay(500000);	/* 500 ms */
+			}
+			/*
+			 * Select device
+			 */
+			ide_outb(device, ATA_DEV_HD,
+				 ATA_LBA | ATA_DEVICE(device));
+			retries++;
+#else
+			return;
+#endif
+		}
+#ifdef CONFIG_ATAPI
+		else
+			break;
+	}			/* see above - ugly to read */
+
+	if (retries == 2)	/* Not found */
+		return;
+#endif
+
+	ide_input_swap_data(device, (ulong *)&iop, ATA_SECTORWORDS);
+
+	ident_cpy((unsigned char *)dev_desc->revision, iop.fw_rev,
+		  sizeof(dev_desc->revision));
+	ident_cpy((unsigned char *)dev_desc->vendor, iop.model,
+		  sizeof(dev_desc->vendor));
+	ident_cpy((unsigned char *)dev_desc->product, iop.serial_no,
+		  sizeof(dev_desc->product));
+#ifdef __LITTLE_ENDIAN
+	/*
+	 * firmware revision, model, and serial number have Big Endian Byte
+	 * order in Word. Convert all three to little endian.
+	 *
+	 * See CF+ and CompactFlash Specification Revision 2.0:
+	 * 6.2.1.6: Identify Drive, Table 39 for more details
+	 */
+
+	strswab(dev_desc->revision);
+	strswab(dev_desc->vendor);
+	strswab(dev_desc->product);
+#endif /* __LITTLE_ENDIAN */
+
+	if ((iop.config & 0x0080) == 0x0080)
+		dev_desc->removable = 1;
+	else
+		dev_desc->removable = 0;
+
+#ifdef CONFIG_ATAPI
+	if (dev_desc->if_type == IF_TYPE_ATAPI) {
+		atapi_inquiry(dev_desc);
+		return;
+	}
+#endif /* CONFIG_ATAPI */
+
+#ifdef __BIG_ENDIAN
+	/* swap shorts */
+	dev_desc->lba = (iop.lba_capacity << 16) | (iop.lba_capacity >> 16);
+#else  /* ! __BIG_ENDIAN */
+	/*
+	 * do not swap shorts on little endian
+	 *
+	 * See CF+ and CompactFlash Specification Revision 2.0:
+	 * 6.2.1.6: Identfy Drive, Table 39, Word Address 57-58 for details.
+	 */
+	dev_desc->lba = iop.lba_capacity;
+#endif /* __BIG_ENDIAN */
+
+#ifdef CONFIG_LBA48
+	if (iop.command_set_2 & 0x0400) {	/* LBA 48 support */
+		dev_desc->lba48 = 1;
+		dev_desc->lba = (unsigned long long) iop.lba48_capacity[0] |
+			((unsigned long long) iop.lba48_capacity[1] << 16) |
+			((unsigned long long) iop.lba48_capacity[2] << 32) |
+			((unsigned long long) iop.lba48_capacity[3] << 48);
+	} else {
+		dev_desc->lba48 = 0;
+	}
+#endif /* CONFIG_LBA48 */
+	/* assuming HD */
+	dev_desc->type = DEV_TYPE_HARDDISK;
+	dev_desc->blksz = ATA_BLOCKSIZE;
+	dev_desc->log2blksz = LOG2(dev_desc->blksz);
+	dev_desc->lun = 0;	/* just to fill something in... */
+
+#if 0				/* only used to test the powersaving mode,
+				 * if enabled, the drive goes after 5 sec
+				 * in standby mode */
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait(device, IDE_TIME_OUT);
+	ide_outb(device, ATA_SECT_CNT, 1);
+	ide_outb(device, ATA_LBA_LOW, 0);
+	ide_outb(device, ATA_LBA_MID, 0);
+	ide_outb(device, ATA_LBA_HIGH, 0);
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	ide_outb(device, ATA_COMMAND, 0xe3);
+	udelay(50);
+	c = ide_wait(device, IDE_TIME_OUT);	/* can't take over 500 ms */
+#endif
+}
+
+__weak void ide_led(uchar led, uchar status)
+{
+#if defined(CONFIG_IDE_LED) && defined(PER8_BASE) /* required by LED_PORT */
+	static uchar led_buffer;	/* Buffer for current LED status */
+
+	uchar *led_port = LED_PORT;
+
+	if (status)		/* switch LED on        */
+		led_buffer |= led;
+	else			/* switch LED off       */
+		led_buffer &= ~led;
+
+	*led_port = led_buffer;
+#endif
+}
+
+__weak void ide_outb(int dev, int port, unsigned char val)
+{
+	debug("ide_outb (dev= %d, port= 0x%x, val= 0x%02x) : @ 0x%08lx\n",
+	      dev, port, val,
+	      (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+
+#if defined(CONFIG_IDE_AHB)
+	if (port) {
+		/* write command */
+		ide_write_register(dev, port, val);
+	} else {
+		/* write data */
+		outb(val, (ATA_CURR_BASE(dev)));
+	}
+#else
+	outb(val, (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+#endif
+}
+
+__weak unsigned char ide_inb(int dev, int port)
+{
+	uchar val;
+
+#if defined(CONFIG_IDE_AHB)
+	val = ide_read_register(dev, port);
+#else
+	val = inb((ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)));
+#endif
+
+	debug("ide_inb (dev= %d, port= 0x%x) : @ 0x%08lx -> 0x%02x\n",
+	      dev, port,
+	      (ATA_CURR_BASE(dev) + CONFIG_SYS_ATA_PORT_ADDR(port)), val);
+	return val;
+}
+
+void ide_init(void)
+{
+	unsigned char c;
+	int i, bus;
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+	extern int ide_devices_found;	/* Initialized in check_ide_device() */
+#endif /* CONFIG_IDE_8xx_PCCARD */
+
+#ifdef CONFIG_IDE_PREINIT
+	WATCHDOG_RESET();
+
+	if (ide_preinit()) {
+		puts("ide_preinit failed\n");
+		return;
+	}
+#endif /* CONFIG_IDE_PREINIT */
+
+	WATCHDOG_RESET();
+
+	/*
+	 * Reset the IDE just to be sure.
+	 * Light LED's to show
+	 */
+	ide_led((LED_IDE1 | LED_IDE2), 1);	/* LED's on     */
+
+	/* ATAPI Drives seems to need a proper IDE Reset */
+	ide_reset();
+
+#ifdef CONFIG_IDE_INIT_POSTRESET
+	WATCHDOG_RESET();
+
+	if (ide_init_postreset()) {
+		puts("ide_preinit_postreset failed\n");
+		return;
+	}
+#endif /* CONFIG_IDE_INIT_POSTRESET */
+
+	/*
+	 * Wait for IDE to get ready.
+	 * According to spec, this can take up to 31 seconds!
+	 */
+	for (bus = 0; bus < CONFIG_SYS_IDE_MAXBUS; ++bus) {
+		int dev =
+			bus * (CONFIG_SYS_IDE_MAXDEVICE /
+			       CONFIG_SYS_IDE_MAXBUS);
+
+#ifdef CONFIG_IDE_8xx_PCCARD
+		/* Skip non-ide devices from probing */
+		if ((ide_devices_found & (1 << bus)) == 0) {
+			ide_led((LED_IDE1 | LED_IDE2), 0);	/* LED's off */
+			continue;
+		}
+#endif
+		printf("Bus %d: ", bus);
+
+		ide_bus_ok[bus] = 0;
+
+		/* Select device
+		 */
+		udelay(100000);	/* 100 ms */
+		ide_outb(dev, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(dev));
+		udelay(100000);	/* 100 ms */
+		i = 0;
+		do {
+			udelay(10000);	/* 10 ms */
+
+			c = ide_inb(dev, ATA_STATUS);
+			i++;
+			if (i > (ATA_RESET_TIME * 100)) {
+				puts("** Timeout **\n");
+				/* LED's off */
+				ide_led((LED_IDE1 | LED_IDE2), 0);
+				return;
+			}
+			if ((i >= 100) && ((i % 100) == 0))
+				putc('.');
+
+		} while (c & ATA_STAT_BUSY);
+
+		if (c & (ATA_STAT_BUSY | ATA_STAT_FAULT)) {
+			puts("not available  ");
+			debug("Status = 0x%02X ", c);
+#ifndef CONFIG_ATAPI		/* ATAPI Devices do not set DRDY */
+		} else if ((c & ATA_STAT_READY) == 0) {
+			puts("not available  ");
+			debug("Status = 0x%02X ", c);
+#endif
+		} else {
+			puts("OK ");
+			ide_bus_ok[bus] = 1;
+		}
+		WATCHDOG_RESET();
+	}
+
+	putc('\n');
+
+	ide_led((LED_IDE1 | LED_IDE2), 0);	/* LED's off    */
+
+	for (i = 0; i < CONFIG_SYS_IDE_MAXDEVICE; ++i) {
+		int led = (IDE_BUS(i) == 0) ? LED_IDE1 : LED_IDE2;
+		ide_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+		ide_dev_desc[i].if_type = IF_TYPE_IDE;
+		ide_dev_desc[i].devnum = i;
+		ide_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+		ide_dev_desc[i].blksz = 0;
+		ide_dev_desc[i].log2blksz =
+			LOG2_INVALID(typeof(ide_dev_desc[i].log2blksz));
+		ide_dev_desc[i].lba = 0;
+#ifndef CONFIG_BLK
+		ide_dev_desc[i].block_read = ide_read;
+		ide_dev_desc[i].block_write = ide_write;
+#endif
+		if (!ide_bus_ok[IDE_BUS(i)])
+			continue;
+		ide_led(led, 1);	/* LED on       */
+		ide_ident(&ide_dev_desc[i]);
+		ide_led(led, 0);	/* LED off      */
+		dev_print(&ide_dev_desc[i]);
+
+		if ((ide_dev_desc[i].lba > 0) && (ide_dev_desc[i].blksz > 0)) {
+			/* initialize partition type */
+			part_init(&ide_dev_desc[i]);
+		}
+	}
+	WATCHDOG_RESET();
+}
+
+/* We only need to swap data if we are running on a big endian cpu. */
+#if defined(__LITTLE_ENDIAN)
+__weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
+{
+	ide_input_data(dev, sect_buf, words);
+}
+#else
+__weak void ide_input_swap_data(int dev, ulong *sect_buf, int words)
+{
+	volatile ushort *pbuf =
+		(ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
+	ushort *dbuf = (ushort *)sect_buf;
+
+	debug("in input swap data base for read is %lx\n",
+	      (unsigned long) pbuf);
+
+	while (words--) {
+#ifdef __MIPS__
+		*dbuf++ = swab16p((u16 *)pbuf);
+		*dbuf++ = swab16p((u16 *)pbuf);
+#else
+		*dbuf++ = ld_le16(pbuf);
+		*dbuf++ = ld_le16(pbuf);
+#endif /* !MIPS */
+	}
+}
+#endif /* __LITTLE_ENDIAN */
+
+
+#if defined(CONFIG_IDE_SWAP_IO)
+__weak void ide_output_data(int dev, const ulong *sect_buf, int words)
+{
+	ushort *dbuf;
+	volatile ushort *pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+	while (words--) {
+		EIEIO;
+		*pbuf = *dbuf++;
+		EIEIO;
+		*pbuf = *dbuf++;
+	}
+}
+#else  /* ! CONFIG_IDE_SWAP_IO */
+__weak void ide_output_data(int dev, const ulong *sect_buf, int words)
+{
+#if defined(CONFIG_IDE_AHB)
+	ide_write_data(dev, sect_buf, words);
+#else
+	outsw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
+#endif
+}
+#endif /* CONFIG_IDE_SWAP_IO */
+
+#if defined(CONFIG_IDE_SWAP_IO)
+__weak void ide_input_data(int dev, ulong *sect_buf, int words)
+{
+	ushort *dbuf;
+	volatile ushort *pbuf;
+
+	pbuf = (ushort *)(ATA_CURR_BASE(dev) + ATA_DATA_REG);
+	dbuf = (ushort *)sect_buf;
+
+	debug("in input data base for read is %lx\n", (unsigned long) pbuf);
+
+	while (words--) {
+		EIEIO;
+		*dbuf++ = *pbuf;
+		EIEIO;
+		*dbuf++ = *pbuf;
+	}
+}
+#else  /* ! CONFIG_IDE_SWAP_IO */
+__weak void ide_input_data(int dev, ulong *sect_buf, int words)
+{
+#if defined(CONFIG_IDE_AHB)
+	ide_read_data(dev, sect_buf, words);
+#else
+	insw(ATA_CURR_BASE(dev) + ATA_DATA_REG, sect_buf, words << 1);
+#endif
+}
+
+#endif /* CONFIG_IDE_SWAP_IO */
+
+#ifdef CONFIG_BLK
+ulong ide_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+	       void *buffer)
+#else
+ulong ide_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
+	       void *buffer)
+#endif
+{
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
+	int device = block_dev->devnum;
+	ulong n = 0;
+	unsigned char c;
+	unsigned char pwrsave = 0;	/* power save */
+
+#ifdef CONFIG_LBA48
+	unsigned char lba48 = 0;
+
+	if (blknr & 0x0000fffff0000000ULL) {
+		/* more than 28 bits used, use 48bit mode */
+		lba48 = 1;
+	}
+#endif
+	debug("ide_read dev %d start " LBAF ", blocks " LBAF " buffer at %lX\n",
+	      device, blknr, blkcnt, (ulong) buffer);
+
+	ide_led(DEVICE_LED(device), 1);	/* LED on       */
+
+	/* Select device
+	 */
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+	c = ide_wait(device, IDE_TIME_OUT);
+
+	if (c & ATA_STAT_BUSY) {
+		printf("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+
+	/* first check if the drive is in Powersaving mode, if yes,
+	 * increase the timeout value */
+	ide_outb(device, ATA_COMMAND, ATA_CMD_CHK_PWR);
+	udelay(50);
+
+	c = ide_wait(device, IDE_TIME_OUT);	/* can't take over 500 ms */
+
+	if (c & ATA_STAT_BUSY) {
+		printf("IDE read: device %d not ready\n", device);
+		goto IDE_READ_E;
+	}
+	if ((c & ATA_STAT_ERR) == ATA_STAT_ERR) {
+		printf("No Powersaving mode %X\n", c);
+	} else {
+		c = ide_inb(device, ATA_SECT_CNT);
+		debug("Powersaving %02X\n", c);
+		if (c == 0)
+			pwrsave = 1;
+	}
+
+
+	while (blkcnt-- > 0) {
+		c = ide_wait(device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf("IDE read: device %d not ready\n", device);
+			break;
+		}
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			/* write high bits */
+			ide_outb(device, ATA_SECT_CNT, 0);
+			ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
+#ifdef CONFIG_SYS_64BIT_LBA
+			ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
+			ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
+#else
+			ide_outb(device, ATA_LBA_MID, 0);
+			ide_outb(device, ATA_LBA_HIGH, 0);
+#endif
+		}
+#endif
+		ide_outb(device, ATA_SECT_CNT, 1);
+		ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+		ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+		ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			ide_outb(device, ATA_DEV_HD,
+				 ATA_LBA | ATA_DEVICE(device));
+			ide_outb(device, ATA_COMMAND, ATA_CMD_READ_EXT);
+
+		} else
+#endif
+		{
+			ide_outb(device, ATA_DEV_HD, ATA_LBA |
+				 ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
+			ide_outb(device, ATA_COMMAND, ATA_CMD_READ);
+		}
+
+		udelay(50);
+
+		if (pwrsave) {
+			/* may take up to 4 sec */
+			c = ide_wait(device, IDE_SPIN_UP_TIME_OUT);
+			pwrsave = 0;
+		} else {
+			/* can't take over 500 ms */
+			c = ide_wait(device, IDE_TIME_OUT);
+		}
+
+		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
+		    ATA_STAT_DRQ) {
+			printf("Error (no IRQ) dev %d blk " LBAF
+			       ": status %#02x\n", device, blknr, c);
+			break;
+		}
+
+		ide_input_data(device, buffer, ATA_SECTORWORDS);
+		(void) ide_inb(device, ATA_STATUS);	/* clear IRQ */
+
+		++n;
+		++blknr;
+		buffer += ATA_BLOCKSIZE;
+	}
+IDE_READ_E:
+	ide_led(DEVICE_LED(device), 0);	/* LED off      */
+	return n;
+}
+
+#ifdef CONFIG_BLK
+ulong ide_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+		const void *buffer)
+#else
+ulong ide_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
+		const void *buffer)
+#endif
+{
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
+	int device = block_dev->devnum;
+	ulong n = 0;
+	unsigned char c;
+
+#ifdef CONFIG_LBA48
+	unsigned char lba48 = 0;
+
+	if (blknr & 0x0000fffff0000000ULL) {
+		/* more than 28 bits used, use 48bit mode */
+		lba48 = 1;
+	}
+#endif
+
+	ide_led(DEVICE_LED(device), 1);	/* LED on       */
+
+	/* Select device
+	 */
+	ide_outb(device, ATA_DEV_HD, ATA_LBA | ATA_DEVICE(device));
+
+	while (blkcnt-- > 0) {
+		c = ide_wait(device, IDE_TIME_OUT);
+
+		if (c & ATA_STAT_BUSY) {
+			printf("IDE read: device %d not ready\n", device);
+			goto WR_OUT;
+		}
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			/* write high bits */
+			ide_outb(device, ATA_SECT_CNT, 0);
+			ide_outb(device, ATA_LBA_LOW, (blknr >> 24) & 0xFF);
+#ifdef CONFIG_SYS_64BIT_LBA
+			ide_outb(device, ATA_LBA_MID, (blknr >> 32) & 0xFF);
+			ide_outb(device, ATA_LBA_HIGH, (blknr >> 40) & 0xFF);
+#else
+			ide_outb(device, ATA_LBA_MID, 0);
+			ide_outb(device, ATA_LBA_HIGH, 0);
+#endif
+		}
+#endif
+		ide_outb(device, ATA_SECT_CNT, 1);
+		ide_outb(device, ATA_LBA_LOW, (blknr >> 0) & 0xFF);
+		ide_outb(device, ATA_LBA_MID, (blknr >> 8) & 0xFF);
+		ide_outb(device, ATA_LBA_HIGH, (blknr >> 16) & 0xFF);
+
+#ifdef CONFIG_LBA48
+		if (lba48) {
+			ide_outb(device, ATA_DEV_HD,
+				 ATA_LBA | ATA_DEVICE(device));
+			ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE_EXT);
+
+		} else
+#endif
+		{
+			ide_outb(device, ATA_DEV_HD, ATA_LBA |
+				 ATA_DEVICE(device) | ((blknr >> 24) & 0xF));
+			ide_outb(device, ATA_COMMAND, ATA_CMD_WRITE);
+		}
+
+		udelay(50);
+
+		/* can't take over 500 ms */
+		c = ide_wait(device, IDE_TIME_OUT);
+
+		if ((c & (ATA_STAT_DRQ | ATA_STAT_BUSY | ATA_STAT_ERR)) !=
+		    ATA_STAT_DRQ) {
+			printf("Error (no IRQ) dev %d blk " LBAF
+			       ": status %#02x\n", device, blknr, c);
+			goto WR_OUT;
+		}
+
+		ide_output_data(device, buffer, ATA_SECTORWORDS);
+		c = ide_inb(device, ATA_STATUS);	/* clear IRQ */
+		++n;
+		++blknr;
+		buffer += ATA_BLOCKSIZE;
+	}
+WR_OUT:
+	ide_led(DEVICE_LED(device), 0);	/* LED off      */
+	return n;
+}
+
+#if defined(CONFIG_OF_IDE_FIXUP)
+int ide_device_present(int dev)
+{
+	if (dev >= CONFIG_SYS_IDE_MAXBUS)
+		return 0;
+	return ide_dev_desc[dev].type == DEV_TYPE_UNKNOWN ? 0 : 1;
+}
+#endif
+
+#ifdef CONFIG_BLK
+static const struct blk_ops ide_blk_ops = {
+	.read	= ide_read,
+	.write	= ide_write,
+};
+
+U_BOOT_DRIVER(ide_blk) = {
+	.name		= "ide_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &ide_blk_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(ide) = {
+	.if_typename	= "ide",
+	.if_type	= IF_TYPE_IDE,
+	.max_devs	= CONFIG_SYS_IDE_MAXDEVICE,
+	.desc		= ide_dev_desc,
+};
+#endif
diff --git a/common/image-fit.c b/common/image-fit.c
index 25f8a11..c86b7c6 100644
--- a/common/image-fit.c
+++ b/common/image-fit.c
@@ -886,9 +886,9 @@
 	ret = fdt_setprop(fit, noffset, FIT_TIMESTAMP_PROP, &t,
 				sizeof(uint32_t));
 	if (ret) {
-		printf("Can't set '%s' property for '%s' node (%s)\n",
-		       FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
-		       fdt_strerror(ret));
+		debug("Can't set '%s' property for '%s' node (%s)\n",
+		      FIT_TIMESTAMP_PROP, fit_get_name(fit, noffset, NULL),
+		      fdt_strerror(ret));
 		return ret == -FDT_ERR_NOSPACE ? -ENOSPC : -1;
 	}
 
diff --git a/common/sata.c b/common/sata.c
new file mode 100644
index 0000000..88f08c9
--- /dev/null
+++ b/common/sata.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2000-2005, DENX Software Engineering
+ *		Wolfgang Denk <wd@denx.de>
+ * Copyright (C) Procsys. All rights reserved.
+ *		Mushtaq Khan <mushtaq_k@procsys.com>
+ *			<mushtaqk_921@yahoo.co.in>
+ * Copyright (C) 2008 Freescale Semiconductor, Inc.
+ *		Dave Liu <daveliu@freescale.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <sata.h>
+
+struct blk_desc sata_dev_desc[CONFIG_SYS_SATA_MAX_DEVICE];
+
+#ifdef CONFIG_PARTITIONS
+struct blk_desc *sata_get_dev(int dev)
+{
+	return (dev < CONFIG_SYS_SATA_MAX_DEVICE) ? &sata_dev_desc[dev] : NULL;
+}
+#endif
+
+#ifdef CONFIG_BLK
+static unsigned long sata_bread(struct udevice *dev, lbaint_t start,
+				lbaint_t blkcnt, void *dst)
+{
+	return -ENOSYS;
+}
+
+static unsigned long sata_bwrite(struct udevice *dev, lbaint_t start,
+				 lbaint_t blkcnt, const void *buffer)
+{
+	return -ENOSYS;
+}
+#else
+static unsigned long sata_bread(struct blk_desc *block_dev, lbaint_t start,
+				lbaint_t blkcnt, void *dst)
+{
+	return sata_read(block_dev->devnum, start, blkcnt, dst);
+}
+
+static unsigned long sata_bwrite(struct blk_desc *block_dev, lbaint_t start,
+				 lbaint_t blkcnt, const void *buffer)
+{
+	return sata_write(block_dev->devnum, start, blkcnt, buffer);
+}
+#endif
+
+int __sata_initialize(void)
+{
+	int rc;
+	int i;
+
+	for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++) {
+		memset(&sata_dev_desc[i], 0, sizeof(struct blk_desc));
+		sata_dev_desc[i].if_type = IF_TYPE_SATA;
+		sata_dev_desc[i].devnum = i;
+		sata_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+		sata_dev_desc[i].type = DEV_TYPE_HARDDISK;
+		sata_dev_desc[i].lba = 0;
+		sata_dev_desc[i].blksz = 512;
+		sata_dev_desc[i].log2blksz = LOG2(sata_dev_desc[i].blksz);
+#ifndef CONFIG_BLK
+		sata_dev_desc[i].block_read = sata_bread;
+		sata_dev_desc[i].block_write = sata_bwrite;
+#endif
+		rc = init_sata(i);
+		if (!rc) {
+			rc = scan_sata(i);
+			if (!rc && sata_dev_desc[i].lba > 0 &&
+			    sata_dev_desc[i].blksz > 0)
+				part_init(&sata_dev_desc[i]);
+		}
+	}
+
+	return rc;
+}
+int sata_initialize(void) __attribute__((weak, alias("__sata_initialize")));
+
+__weak int __sata_stop(void)
+{
+	int i, err = 0;
+
+	for (i = 0; i < CONFIG_SYS_SATA_MAX_DEVICE; i++)
+		err |= reset_sata(i);
+
+	if (err)
+		printf("Could not reset some SATA devices\n");
+
+	return err;
+}
+int sata_stop(void) __attribute__((weak, alias("__sata_stop")));
+
+#ifdef CONFIG_BLK
+static const struct blk_ops sata_blk_ops = {
+	.read	= sata_bread,
+	.write	= sata_bwrite,
+};
+
+U_BOOT_DRIVER(sata_blk) = {
+	.name		= "sata_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &sata_blk_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(sata) = {
+	.if_typename	= "sata",
+	.if_type	= IF_TYPE_SATA,
+	.max_devs	= CONFIG_SYS_SATA_MAX_DEVICE,
+	.desc		= sata_dev_desc,
+};
+#endif
diff --git a/common/scsi.c b/common/scsi.c
new file mode 100644
index 0000000..8ac28dd
--- /dev/null
+++ b/common/scsi.c
@@ -0,0 +1,592 @@
+/*
+ * (C) Copyright 2001
+ * Denis Peter, MPL AG Switzerland
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <inttypes.h>
+#include <pci.h>
+#include <scsi.h>
+
+#ifdef CONFIG_SCSI_DEV_LIST
+#define SCSI_DEV_LIST CONFIG_SCSI_DEV_LIST
+#else
+#ifdef CONFIG_SCSI_SYM53C8XX
+#define SCSI_VEND_ID	0x1000
+#ifndef CONFIG_SCSI_DEV_ID
+#define SCSI_DEV_ID		0x0001
+#else
+#define SCSI_DEV_ID		CONFIG_SCSI_DEV_ID
+#endif
+#elif defined CONFIG_SATA_ULI5288
+
+#define SCSI_VEND_ID 0x10b9
+#define SCSI_DEV_ID  0x5288
+
+#elif !defined(CONFIG_SCSI_AHCI_PLAT)
+#error no scsi device defined
+#endif
+#define SCSI_DEV_LIST {SCSI_VEND_ID, SCSI_DEV_ID}
+#endif
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
+const struct pci_device_id scsi_device_list[] = { SCSI_DEV_LIST };
+#endif
+static ccb tempccb;	/* temporary scsi command buffer */
+
+static unsigned char tempbuff[512]; /* temporary data buffer */
+
+static int scsi_max_devs; /* number of highest available scsi device */
+
+static int scsi_curr_dev; /* current device */
+
+static struct blk_desc scsi_dev_desc[CONFIG_SYS_SCSI_MAX_DEVICE];
+
+/* almost the maximum amount of the scsi_ext command.. */
+#define SCSI_MAX_READ_BLK 0xFFFF
+#define SCSI_LBA48_READ	0xFFFFFFF
+
+#ifdef CONFIG_SYS_64BIT_LBA
+void scsi_setup_read16(ccb *pccb, lbaint_t start, unsigned long blocks)
+{
+	pccb->cmd[0] = SCSI_READ16;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = (unsigned char)(start >> 56) & 0xff;
+	pccb->cmd[3] = (unsigned char)(start >> 48) & 0xff;
+	pccb->cmd[4] = (unsigned char)(start >> 40) & 0xff;
+	pccb->cmd[5] = (unsigned char)(start >> 32) & 0xff;
+	pccb->cmd[6] = (unsigned char)(start >> 24) & 0xff;
+	pccb->cmd[7] = (unsigned char)(start >> 16) & 0xff;
+	pccb->cmd[8] = (unsigned char)(start >> 8) & 0xff;
+	pccb->cmd[9] = (unsigned char)start & 0xff;
+	pccb->cmd[10] = 0;
+	pccb->cmd[11] = (unsigned char)(blocks >> 24) & 0xff;
+	pccb->cmd[12] = (unsigned char)(blocks >> 16) & 0xff;
+	pccb->cmd[13] = (unsigned char)(blocks >> 8) & 0xff;
+	pccb->cmd[14] = (unsigned char)blocks & 0xff;
+	pccb->cmd[15] = 0;
+	pccb->cmdlen = 16;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+	debug("scsi_setup_read16: cmd: %02X %02X startblk %02X%02X%02X%02X%02X%02X%02X%02X blccnt %02X%02X%02X%02X\n",
+	      pccb->cmd[0], pccb->cmd[1],
+	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
+	      pccb->cmd[6], pccb->cmd[7], pccb->cmd[8], pccb->cmd[9],
+	      pccb->cmd[11], pccb->cmd[12], pccb->cmd[13], pccb->cmd[14]);
+}
+#endif
+
+void scsi_setup_read_ext(ccb *pccb, lbaint_t start, unsigned short blocks)
+{
+	pccb->cmd[0] = SCSI_READ10;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
+	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
+	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
+	pccb->cmd[5] = (unsigned char)start & 0xff;
+	pccb->cmd[6] = 0;
+	pccb->cmd[7] = (unsigned char)(blocks >> 8) & 0xff;
+	pccb->cmd[8] = (unsigned char)blocks & 0xff;
+	pccb->cmd[6] = 0;
+	pccb->cmdlen = 10;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+	debug("scsi_setup_read_ext: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
+	      pccb->cmd[0], pccb->cmd[1],
+	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
+	      pccb->cmd[7], pccb->cmd[8]);
+}
+
+void scsi_setup_write_ext(ccb *pccb, lbaint_t start, unsigned short blocks)
+{
+	pccb->cmd[0] = SCSI_WRITE10;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = (unsigned char)(start >> 24) & 0xff;
+	pccb->cmd[3] = (unsigned char)(start >> 16) & 0xff;
+	pccb->cmd[4] = (unsigned char)(start >> 8) & 0xff;
+	pccb->cmd[5] = (unsigned char)start & 0xff;
+	pccb->cmd[6] = 0;
+	pccb->cmd[7] = ((unsigned char)(blocks >> 8)) & 0xff;
+	pccb->cmd[8] = (unsigned char)blocks & 0xff;
+	pccb->cmd[9] = 0;
+	pccb->cmdlen = 10;
+	pccb->msgout[0] = SCSI_IDENTIFY;  /* NOT USED */
+	debug("%s: cmd: %02X %02X startblk %02X%02X%02X%02X blccnt %02X%02X\n",
+	      __func__,
+	      pccb->cmd[0], pccb->cmd[1],
+	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4], pccb->cmd[5],
+	      pccb->cmd[7], pccb->cmd[8]);
+}
+
+void scsi_setup_read6(ccb *pccb, lbaint_t start, unsigned short blocks)
+{
+	pccb->cmd[0] = SCSI_READ6;
+	pccb->cmd[1] = pccb->lun << 5 | ((unsigned char)(start >> 16) & 0x1f);
+	pccb->cmd[2] = (unsigned char)(start >> 8) & 0xff;
+	pccb->cmd[3] = (unsigned char)start & 0xff;
+	pccb->cmd[4] = (unsigned char)blocks & 0xff;
+	pccb->cmd[5] = 0;
+	pccb->cmdlen = 6;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+	debug("scsi_setup_read6: cmd: %02X %02X startblk %02X%02X blccnt %02X\n",
+	      pccb->cmd[0], pccb->cmd[1],
+	      pccb->cmd[2], pccb->cmd[3], pccb->cmd[4]);
+}
+
+
+void scsi_setup_inquiry(ccb *pccb)
+{
+	pccb->cmd[0] = SCSI_INQUIRY;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = 0;
+	pccb->cmd[3] = 0;
+	if (pccb->datalen > 255)
+		pccb->cmd[4] = 255;
+	else
+		pccb->cmd[4] = (unsigned char)pccb->datalen;
+	pccb->cmd[5] = 0;
+	pccb->cmdlen = 6;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+}
+
+#ifdef CONFIG_BLK
+static ulong scsi_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+		       void *buffer)
+#else
+static ulong scsi_read(struct blk_desc *block_dev, lbaint_t blknr,
+		       lbaint_t blkcnt, void *buffer)
+#endif
+{
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
+	int device = block_dev->devnum;
+	lbaint_t start, blks;
+	uintptr_t buf_addr;
+	unsigned short smallblks = 0;
+	ccb *pccb = (ccb *)&tempccb;
+	device &= 0xff;
+
+	/* Setup device */
+	pccb->target = scsi_dev_desc[device].target;
+	pccb->lun = scsi_dev_desc[device].lun;
+	buf_addr = (unsigned long)buffer;
+	start = blknr;
+	blks = blkcnt;
+	debug("\nscsi_read: dev %d startblk " LBAF
+	      ", blccnt " LBAF " buffer %lx\n",
+	      device, start, blks, (unsigned long)buffer);
+	do {
+		pccb->pdata = (unsigned char *)buf_addr;
+#ifdef CONFIG_SYS_64BIT_LBA
+		if (start > SCSI_LBA48_READ) {
+			unsigned long blocks;
+			blocks = min_t(lbaint_t, blks, SCSI_MAX_READ_BLK);
+			pccb->datalen = scsi_dev_desc[device].blksz * blocks;
+			scsi_setup_read16(pccb, start, blocks);
+			start += blocks;
+			blks -= blocks;
+		} else
+#endif
+		if (blks > SCSI_MAX_READ_BLK) {
+			pccb->datalen = scsi_dev_desc[device].blksz *
+				SCSI_MAX_READ_BLK;
+			smallblks = SCSI_MAX_READ_BLK;
+			scsi_setup_read_ext(pccb, start, smallblks);
+			start += SCSI_MAX_READ_BLK;
+			blks -= SCSI_MAX_READ_BLK;
+		} else {
+			pccb->datalen = scsi_dev_desc[device].blksz * blks;
+			smallblks = (unsigned short)blks;
+			scsi_setup_read_ext(pccb, start, smallblks);
+			start += blks;
+			blks = 0;
+		}
+		debug("scsi_read_ext: startblk " LBAF
+		      ", blccnt %x buffer %" PRIXPTR "\n",
+		      start, smallblks, buf_addr);
+		if (scsi_exec(pccb) != true) {
+			scsi_print_error(pccb);
+			blkcnt -= blks;
+			break;
+		}
+		buf_addr += pccb->datalen;
+	} while (blks != 0);
+	debug("scsi_read_ext: end startblk " LBAF
+	      ", blccnt %x buffer %" PRIXPTR "\n", start, smallblks, buf_addr);
+	return blkcnt;
+}
+
+/*******************************************************************************
+ * scsi_write
+ */
+
+/* Almost the maximum amount of the scsi_ext command.. */
+#define SCSI_MAX_WRITE_BLK 0xFFFF
+
+#ifdef CONFIG_BLK
+static ulong scsi_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+			const void *buffer)
+#else
+static ulong scsi_write(struct blk_desc *block_dev, lbaint_t blknr,
+			lbaint_t blkcnt, const void *buffer)
+#endif
+{
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
+	int device = block_dev->devnum;
+	lbaint_t start, blks;
+	uintptr_t buf_addr;
+	unsigned short smallblks;
+	ccb *pccb = (ccb *)&tempccb;
+
+	device &= 0xff;
+
+	/* Setup device */
+	pccb->target = scsi_dev_desc[device].target;
+	pccb->lun = scsi_dev_desc[device].lun;
+	buf_addr = (unsigned long)buffer;
+	start = blknr;
+	blks = blkcnt;
+	debug("\n%s: dev %d startblk " LBAF ", blccnt " LBAF " buffer %lx\n",
+	      __func__, device, start, blks, (unsigned long)buffer);
+	do {
+		pccb->pdata = (unsigned char *)buf_addr;
+		if (blks > SCSI_MAX_WRITE_BLK) {
+			pccb->datalen = (scsi_dev_desc[device].blksz *
+					 SCSI_MAX_WRITE_BLK);
+			smallblks = SCSI_MAX_WRITE_BLK;
+			scsi_setup_write_ext(pccb, start, smallblks);
+			start += SCSI_MAX_WRITE_BLK;
+			blks -= SCSI_MAX_WRITE_BLK;
+		} else {
+			pccb->datalen = scsi_dev_desc[device].blksz * blks;
+			smallblks = (unsigned short)blks;
+			scsi_setup_write_ext(pccb, start, smallblks);
+			start += blks;
+			blks = 0;
+		}
+		debug("%s: startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
+		      __func__, start, smallblks, buf_addr);
+		if (scsi_exec(pccb) != true) {
+			scsi_print_error(pccb);
+			blkcnt -= blks;
+			break;
+		}
+		buf_addr += pccb->datalen;
+	} while (blks != 0);
+	debug("%s: end startblk " LBAF ", blccnt %x buffer %" PRIXPTR "\n",
+	      __func__, start, smallblks, buf_addr);
+	return blkcnt;
+}
+
+int scsi_get_disk_count(void)
+{
+	return scsi_max_devs;
+}
+
+#if defined(CONFIG_PCI) && !defined(CONFIG_SCSI_AHCI_PLAT)
+void scsi_init(void)
+{
+	int busdevfunc = -1;
+	int i;
+	/*
+	 * Find a device from the list, this driver will support a single
+	 * controller.
+	 */
+	for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
+		/* get PCI Device ID */
+#ifdef CONFIG_DM_PCI
+		struct udevice *dev;
+		int ret;
+
+		ret = dm_pci_find_device(scsi_device_list[i].vendor,
+					 scsi_device_list[i].device, 0, &dev);
+		if (!ret) {
+			busdevfunc = dm_pci_get_bdf(dev);
+			break;
+		}
+#else
+		busdevfunc = pci_find_device(scsi_device_list[i].vendor,
+					     scsi_device_list[i].device,
+					     0);
+#endif
+		if (busdevfunc != -1)
+			break;
+	}
+
+	if (busdevfunc == -1) {
+		printf("Error: SCSI Controller(s) ");
+		for (i = 0; i < ARRAY_SIZE(scsi_device_list); i++) {
+			printf("%04X:%04X ",
+			       scsi_device_list[i].vendor,
+			       scsi_device_list[i].device);
+		}
+		printf("not found\n");
+		return;
+	}
+#ifdef DEBUG
+	else {
+		printf("SCSI Controller (%04X,%04X) found (%d:%d:%d)\n",
+		       scsi_device_list[i].vendor,
+		       scsi_device_list[i].device,
+		       (busdevfunc >> 16) & 0xFF,
+		       (busdevfunc >> 11) & 0x1F,
+		       (busdevfunc >> 8) & 0x7);
+	}
+#endif
+	bootstage_start(BOOTSTAGE_ID_ACCUM_SCSI, "ahci");
+	scsi_low_level_init(busdevfunc);
+	scsi_scan(1);
+	bootstage_accum(BOOTSTAGE_ID_ACCUM_SCSI);
+}
+#endif
+
+/* copy src to dest, skipping leading and trailing blanks
+ * and null terminate the string
+ */
+void scsi_ident_cpy(unsigned char *dest, unsigned char *src, unsigned int len)
+{
+	int start, end;
+
+	start = 0;
+	while (start < len) {
+		if (src[start] != ' ')
+			break;
+		start++;
+	}
+	end = len-1;
+	while (end > start) {
+		if (src[end] != ' ')
+			break;
+		end--;
+	}
+	for (; start <= end; start++)
+		*dest ++= src[start];
+	*dest = '\0';
+}
+
+
+/* Trim trailing blanks, and NUL-terminate string
+ */
+void scsi_trim_trail(unsigned char *str, unsigned int len)
+{
+	unsigned char *p = str + len - 1;
+
+	while (len-- > 0) {
+		*p-- = '\0';
+		if (*p != ' ')
+			return;
+	}
+}
+
+int scsi_read_capacity(ccb *pccb, lbaint_t *capacity, unsigned long *blksz)
+{
+	*capacity = 0;
+
+	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
+	pccb->cmd[0] = SCSI_RD_CAPAC10;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmdlen = 10;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+	pccb->datalen = 8;
+	if (scsi_exec(pccb) != true)
+		return 1;
+
+	*capacity = ((lbaint_t)pccb->pdata[0] << 24) |
+		    ((lbaint_t)pccb->pdata[1] << 16) |
+		    ((lbaint_t)pccb->pdata[2] << 8)  |
+		    ((lbaint_t)pccb->pdata[3]);
+
+	if (*capacity != 0xffffffff) {
+		/* Read capacity (10) was sufficient for this drive. */
+		*blksz = ((unsigned long)pccb->pdata[4] << 24) |
+			 ((unsigned long)pccb->pdata[5] << 16) |
+			 ((unsigned long)pccb->pdata[6] << 8)  |
+			 ((unsigned long)pccb->pdata[7]);
+		return 0;
+	}
+
+	/* Read capacity (10) was insufficient. Use read capacity (16). */
+	memset(pccb->cmd, '\0', sizeof(pccb->cmd));
+	pccb->cmd[0] = SCSI_RD_CAPAC16;
+	pccb->cmd[1] = 0x10;
+	pccb->cmdlen = 16;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+
+	pccb->datalen = 16;
+	if (scsi_exec(pccb) != true)
+		return 1;
+
+	*capacity = ((uint64_t)pccb->pdata[0] << 56) |
+		    ((uint64_t)pccb->pdata[1] << 48) |
+		    ((uint64_t)pccb->pdata[2] << 40) |
+		    ((uint64_t)pccb->pdata[3] << 32) |
+		    ((uint64_t)pccb->pdata[4] << 24) |
+		    ((uint64_t)pccb->pdata[5] << 16) |
+		    ((uint64_t)pccb->pdata[6] << 8)  |
+		    ((uint64_t)pccb->pdata[7]);
+
+	*blksz = ((uint64_t)pccb->pdata[8]  << 56) |
+		 ((uint64_t)pccb->pdata[9]  << 48) |
+		 ((uint64_t)pccb->pdata[10] << 40) |
+		 ((uint64_t)pccb->pdata[11] << 32) |
+		 ((uint64_t)pccb->pdata[12] << 24) |
+		 ((uint64_t)pccb->pdata[13] << 16) |
+		 ((uint64_t)pccb->pdata[14] << 8)  |
+		 ((uint64_t)pccb->pdata[15]);
+
+	return 0;
+}
+
+
+/*
+ * Some setup (fill-in) routines
+ */
+void scsi_setup_test_unit_ready(ccb *pccb)
+{
+	pccb->cmd[0] = SCSI_TST_U_RDY;
+	pccb->cmd[1] = pccb->lun << 5;
+	pccb->cmd[2] = 0;
+	pccb->cmd[3] = 0;
+	pccb->cmd[4] = 0;
+	pccb->cmd[5] = 0;
+	pccb->cmdlen = 6;
+	pccb->msgout[0] = SCSI_IDENTIFY; /* NOT USED */
+}
+
+/*
+ * (re)-scan the scsi bus and reports scsi device info
+ * to the user if mode = 1
+ */
+void scsi_scan(int mode)
+{
+	unsigned char i, perq, modi, lun;
+	lbaint_t capacity;
+	unsigned long blksz;
+	ccb *pccb = (ccb *)&tempccb;
+
+	if (mode == 1)
+		printf("scanning bus for devices...\n");
+	for (i = 0; i < CONFIG_SYS_SCSI_MAX_DEVICE; i++) {
+		scsi_dev_desc[i].target = 0xff;
+		scsi_dev_desc[i].lun = 0xff;
+		scsi_dev_desc[i].lba = 0;
+		scsi_dev_desc[i].blksz = 0;
+		scsi_dev_desc[i].log2blksz =
+			LOG2_INVALID(typeof(scsi_dev_desc[i].log2blksz));
+		scsi_dev_desc[i].type = DEV_TYPE_UNKNOWN;
+		scsi_dev_desc[i].vendor[0] = 0;
+		scsi_dev_desc[i].product[0] = 0;
+		scsi_dev_desc[i].revision[0] = 0;
+		scsi_dev_desc[i].removable = false;
+		scsi_dev_desc[i].if_type = IF_TYPE_SCSI;
+		scsi_dev_desc[i].devnum = i;
+		scsi_dev_desc[i].part_type = PART_TYPE_UNKNOWN;
+#ifndef CONFIG_BLK
+		scsi_dev_desc[i].block_read = scsi_read;
+		scsi_dev_desc[i].block_write = scsi_write;
+#endif
+	}
+	scsi_max_devs = 0;
+	for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
+		pccb->target = i;
+		for (lun = 0; lun < CONFIG_SYS_SCSI_MAX_LUN; lun++) {
+			pccb->lun = lun;
+			pccb->pdata = (unsigned char *)&tempbuff;
+			pccb->datalen = 512;
+			scsi_setup_inquiry(pccb);
+			if (scsi_exec(pccb) != true) {
+				if (pccb->contr_stat == SCSI_SEL_TIME_OUT) {
+					/*
+					 * selection timeout => assuming no
+					 * device present
+					 */
+					debug("Selection timeout ID %d\n",
+					      pccb->target);
+					continue;
+				}
+				scsi_print_error(pccb);
+				continue;
+			}
+			perq = tempbuff[0];
+			modi = tempbuff[1];
+			if ((perq & 0x1f) == 0x1f)
+				continue; /* skip unknown devices */
+			if ((modi & 0x80) == 0x80) /* drive is removable */
+				scsi_dev_desc[scsi_max_devs].removable = true;
+			/* get info for this device */
+			scsi_ident_cpy((unsigned char *)&scsi_dev_desc
+						[scsi_max_devs].vendor[0],
+				       &tempbuff[8], 8);
+			scsi_ident_cpy((unsigned char *)&scsi_dev_desc
+						[scsi_max_devs].product[0],
+				       &tempbuff[16], 16);
+			scsi_ident_cpy((unsigned char *)&scsi_dev_desc
+						[scsi_max_devs].revision[0],
+				       &tempbuff[32], 4);
+			scsi_dev_desc[scsi_max_devs].target = pccb->target;
+			scsi_dev_desc[scsi_max_devs].lun = pccb->lun;
+
+			pccb->datalen = 0;
+			scsi_setup_test_unit_ready(pccb);
+			if (scsi_exec(pccb) != true) {
+				if (scsi_dev_desc[scsi_max_devs].removable) {
+					scsi_dev_desc[scsi_max_devs].type =
+							perq;
+					goto removable;
+				}
+				scsi_print_error(pccb);
+				continue;
+			}
+			if (scsi_read_capacity(pccb, &capacity, &blksz)) {
+				scsi_print_error(pccb);
+				continue;
+			}
+			scsi_dev_desc[scsi_max_devs].lba = capacity;
+			scsi_dev_desc[scsi_max_devs].blksz = blksz;
+			scsi_dev_desc[scsi_max_devs].log2blksz =
+				LOG2(scsi_dev_desc[scsi_max_devs].blksz);
+			scsi_dev_desc[scsi_max_devs].type = perq;
+			part_init(&scsi_dev_desc[scsi_max_devs]);
+removable:
+			if (mode == 1) {
+				printf("  Device %d: ", scsi_max_devs);
+				dev_print(&scsi_dev_desc[scsi_max_devs]);
+			} /* if mode */
+			scsi_max_devs++;
+		} /* next LUN */
+	}
+	if (scsi_max_devs > 0)
+		scsi_curr_dev = 0;
+	else
+		scsi_curr_dev = -1;
+
+	printf("Found %d device(s).\n", scsi_max_devs);
+#ifndef CONFIG_SPL_BUILD
+	setenv_ulong("scsidevs", scsi_max_devs);
+#endif
+}
+
+#ifdef CONFIG_BLK
+static const struct blk_ops scsi_blk_ops = {
+	.read	= scsi_read,
+	.write	= scsi_write,
+};
+
+U_BOOT_DRIVER(scsi_blk) = {
+	.name		= "scsi_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &scsi_blk_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(scsi) = {
+	.if_typename	= "sata",
+	.if_type	= IF_TYPE_SCSI,
+	.max_devs	= CONFIG_SYS_SCSI_MAX_DEVICE,
+	.desc		= scsi_dev_desc,
+};
+#endif
diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c
index 338ea2f..5b0d969 100644
--- a/common/spl/spl_fat.c
+++ b/common/spl/spl_fat.c
@@ -58,7 +58,7 @@
 		goto end;
 
 	err = spl_parse_image_header(header);
-	if (err <= 0)
+	if (err)
 		goto end;
 
 	err = file_fat_read(filename, (u8 *)spl_image.load_addr, 0);
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 1a5c027..26842ba 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -39,8 +39,13 @@
 	     node >= 0;
 	     node = fdt_next_subnode(fdt, node)) {
 		name = fdt_getprop(fdt, node, "description", &len);
-		if (!name)
+		if (!name) {
+#ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
+			printf("%s: Missing FDT description in DTB\n",
+			       __func__);
+#endif
 			return -EINVAL;
+		}
 		if (board_fit_config_name_match(name))
 			continue;
 
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 360c754..5676acd 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -300,7 +300,7 @@
 			if (part == 7)
 				part = 0;
 
-			err = mmc_switch_part(0, part);
+			err = blk_dselect_hwpart(mmc_get_blk_desc(mmc), part);
 			if (err) {
 #ifdef CONFIG_SPL_LIBCOMMON_SUPPORT
 				puts("spl: mmc partition switch failed\n");
diff --git a/common/spl/spl_sata.c b/common/spl/spl_sata.c
index 1719946..9d8cc7c 100644
--- a/common/spl/spl_sata.c
+++ b/common/spl/spl_sata.c
@@ -34,7 +34,7 @@
 	} else {
 		/* try to recognize storage devices immediately */
 		scsi_scan(0);
-		stor_dev = scsi_get_dev(0);
+		stor_dev = blk_get_devnum_by_type(IF_TYPE_SCSI, 0);
 		if (!stor_dev)
 			return -ENODEV;
 	}
diff --git a/common/spl/spl_usb.c b/common/spl/spl_usb.c
index c42848e..04fa667 100644
--- a/common/spl/spl_usb.c
+++ b/common/spl/spl_usb.c
@@ -39,7 +39,7 @@
 #ifdef CONFIG_USB_STORAGE
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
-	stor_dev = usb_stor_get_dev(usb_stor_curr_dev);
+	stor_dev = blk_get_devnum_by_type(IF_TYPE_USB, usb_stor_curr_dev);
 	if (!stor_dev)
 		return -ENODEV;
 #endif
diff --git a/common/usb_storage.c b/common/usb_storage.c
index 9285c95..7e6e52d 100644
--- a/common/usb_storage.c
+++ b/common/usb_storage.c
@@ -136,23 +136,6 @@
 #endif
 void uhci_show_temp_int_td(void);
 
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *usb_stor_get_dev(int index)
-{
-#ifdef CONFIG_BLK
-	struct udevice *dev;
-	int ret;
-
-	ret = blk_get_device(IF_TYPE_USB, index, &dev);
-	if (ret)
-		return NULL;
-	return dev_get_uclass_platdata(dev);
-#else
-	return (index < usb_max_devs) ? &usb_dev_desc[index] : NULL;
-#endif
-}
-#endif
-
 static void usb_show_progress(void)
 {
 	debug(".");
@@ -217,7 +200,6 @@
 
 #ifdef CONFIG_BLK
 	struct us_data *data;
-	char dev_name[30], *str;
 	int ret;
 #else
 	int start;
@@ -240,14 +222,12 @@
 	for (lun = 0; lun <= max_lun; lun++) {
 		struct blk_desc *blkdev;
 		struct udevice *dev;
+		char str[10];
 
-		snprintf(dev_name, sizeof(dev_name), "%s.lun%d",
-			 udev->dev->name, lun);
-		str = strdup(dev_name);
-		if (!str)
-			return -ENOMEM;
-		ret = blk_create_device(udev->dev, "usb_storage_blk", str,
-				IF_TYPE_USB, usb_max_devs, 512, 0, &dev);
+		snprintf(str, sizeof(str), "lun%d", lun);
+		ret = blk_create_devicef(udev->dev, "usb_storage_blk", str,
+					 IF_TYPE_USB, usb_max_devs, 512, 0,
+					 &dev);
 		if (ret) {
 			debug("Cannot bind driver\n");
 			return ret;
@@ -1555,4 +1535,11 @@
 	.id		= UCLASS_BLK,
 	.ops		= &usb_storage_ops,
 };
+#else
+U_BOOT_LEGACY_BLK(usb) = {
+	.if_typename	= "usb",
+	.if_type	= IF_TYPE_USB,
+	.max_devs	= USB_MAX_STOR_DEV,
+	.desc		= usb_dev_desc,
+};
 #endif
diff --git a/configs/ap121_defconfig b/configs/ap121_defconfig
new file mode 100644
index 0000000..7604e2e
--- /dev/null
+++ b/configs/ap121_defconfig
@@ -0,0 +1,47 @@
+CONFIG_MIPS=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_DM_SERIAL=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_ARCH_ATH79=y
+CONFIG_DEFAULT_DEVICE_TREE="ap121"
+CONFIG_SYS_PROMPT="ap121 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_AR933X_PINCTRL=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_AR933X=y
+CONFIG_DEBUG_UART_BASE=0xb8020000
+CONFIG_DEBUG_UART_CLOCK=25000000
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_AR933X_UART=y
+CONFIG_ATH79_SPI=y
+CONFIG_USE_PRIVATE_LIBGCC=y
+CONFIG_OF_LIBFDT=y
diff --git a/configs/ap143_defconfig b/configs/ap143_defconfig
new file mode 100644
index 0000000..1aa6e5d
--- /dev/null
+++ b/configs/ap143_defconfig
@@ -0,0 +1,47 @@
+CONFIG_MIPS=y
+CONFIG_SYS_MALLOC_F_LEN=0x800
+CONFIG_DM_SERIAL=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_ARCH_ATH79=y
+CONFIG_TARGET_AP143=y
+CONFIG_DEFAULT_DEVICE_TREE="ap143"
+CONFIG_SYS_PROMPT="ap143 # "
+# CONFIG_CMD_BDI is not set
+# CONFIG_CMD_CONSOLE is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_EXPORTENV is not set
+# CONFIG_CMD_IMPORTENV is not set
+# CONFIG_CMD_EDITENV is not set
+# CONFIG_CMD_CRC32 is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_FPGA is not set
+# CONFIG_CMD_NET is not set
+# CONFIG_CMD_NFS is not set
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_BAR=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_QCA953X_PINCTRL=y
+CONFIG_DEBUG_UART=y
+CONFIG_DEBUG_UART_BASE=0xb8020000
+CONFIG_DEBUG_UART_CLOCK=25000000
+CONFIG_DEBUG_UART_SHIFT=2
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_SYS_NS16550=y
+CONFIG_ATH79_SPI=y
+CONFIG_USE_PRIVATE_LIBGCC=y
+CONFIG_OF_LIBFDT=y
diff --git a/configs/axs101_defconfig b/configs/axs101_defconfig
index 85af09e..07a6a18 100644
--- a/configs/axs101_defconfig
+++ b/configs/axs101_defconfig
@@ -18,6 +18,7 @@
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM=y
 CONFIG_CLK=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_SYS_NS16550=y
diff --git a/configs/axs103_defconfig b/configs/axs103_defconfig
index aa9bf33..01a5143 100644
--- a/configs/axs103_defconfig
+++ b/configs/axs103_defconfig
@@ -18,6 +18,7 @@
 CONFIG_NET_RANDOM_ETHADDR=y
 CONFIG_DM=y
 CONFIG_CLK=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_SYS_NS16550=y
diff --git a/configs/pico-imx6ul_defconfig b/configs/pico-imx6ul_defconfig
index cc49dc9..d46cd3b 100644
--- a/configs/pico-imx6ul_defconfig
+++ b/configs/pico-imx6ul_defconfig
@@ -2,6 +2,7 @@
 CONFIG_ARCH_MX6=y
 CONFIG_TARGET_PICO_IMX6UL=y
 CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/technexion/pico-imx6ul/imximage.cfg"
+CONFIG_HUSH_PARSER=y
 CONFIG_CMD_BOOTZ=y
 # CONFIG_CMD_IMLS is not set
 CONFIG_CMD_MEMTEST=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index afdf4a3..aec2e53 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,4 +1,5 @@
 CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_MMC=y
 CONFIG_PCI=y
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
 CONFIG_I8042_KEYB=y
@@ -97,6 +98,7 @@
 CONFIG_SPL_PWRSEQ=y
 CONFIG_RESET=y
 CONFIG_DM_MMC=y
+CONFIG_SANDBOX_MMC=y
 CONFIG_SPI_FLASH_SANDBOX=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_ATMEL=y
diff --git a/configs/sandbox_noblk_defconfig b/configs/sandbox_noblk_defconfig
new file mode 100644
index 0000000..93167c2
--- /dev/null
+++ b/configs/sandbox_noblk_defconfig
@@ -0,0 +1,168 @@
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_PCI=y
+CONFIG_DEFAULT_DEVICE_TREE="sandbox"
+CONFIG_I8042_KEYB=y
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_SPL_LOAD_FIT=y
+CONFIG_BOOTSTAGE=y
+CONFIG_BOOTSTAGE_REPORT=y
+CONFIG_BOOTSTAGE_USER_COUNT=0x20
+CONFIG_BOOTSTAGE_FDT=y
+CONFIG_BOOTSTAGE_STASH=y
+CONFIG_BOOTSTAGE_STASH_ADDR=0x0
+CONFIG_BOOTSTAGE_STASH_SIZE=0x4096
+CONFIG_CONSOLE_RECORD=y
+CONFIG_CONSOLE_RECORD_OUT_SIZE=0x1000
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+CONFIG_CMD_ASKENV=y
+CONFIG_CMD_GREPENV=y
+CONFIG_LOOPW=y
+CONFIG_CMD_MEMTEST=y
+CONFIG_CMD_MX_CYCLIC=y
+CONFIG_CMD_MEMINFO=y
+CONFIG_CMD_DEMO=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_CMD_I2C=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_REMOTEPROC=y
+CONFIG_CMD_GPIO=y
+CONFIG_CMD_TFTPPUT=y
+CONFIG_CMD_TFTPSRV=y
+CONFIG_CMD_RARP=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_MII=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_CDP=y
+CONFIG_CMD_SNTP=y
+CONFIG_CMD_DNS=y
+CONFIG_CMD_LINK_LOCAL=y
+CONFIG_CMD_TIME=y
+CONFIG_CMD_TIMER=y
+CONFIG_CMD_SOUND=y
+CONFIG_CMD_BOOTSTAGE=y
+CONFIG_CMD_PMIC=y
+CONFIG_CMD_REGULATOR=y
+CONFIG_CMD_TPM=y
+CONFIG_CMD_TPM_TEST=y
+CONFIG_CMD_EXT2=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_EXT4_WRITE=y
+CONFIG_CMD_FAT=y
+CONFIG_CMD_FS_GENERIC=y
+CONFIG_OF_CONTROL=y
+CONFIG_OF_HOSTFILE=y
+CONFIG_NETCONSOLE=y
+CONFIG_REGMAP=y
+CONFIG_SPL_REGMAP=y
+CONFIG_SYSCON=y
+CONFIG_SPL_SYSCON=y
+CONFIG_DEVRES=y
+CONFIG_DEBUG_DEVRES=y
+CONFIG_ADC=y
+CONFIG_ADC_SANDBOX=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_DEMO=y
+CONFIG_DM_DEMO_SIMPLE=y
+CONFIG_DM_DEMO_SHAPE=y
+CONFIG_PM8916_GPIO=y
+CONFIG_SANDBOX_GPIO=y
+CONFIG_DM_I2C_COMPAT=y
+CONFIG_I2C_CROS_EC_TUNNEL=y
+CONFIG_I2C_CROS_EC_LDO=y
+CONFIG_DM_I2C_GPIO=y
+CONFIG_SYS_I2C_SANDBOX=y
+CONFIG_I2C_MUX=y
+CONFIG_SPL_I2C_MUX=y
+CONFIG_I2C_ARB_GPIO_CHALLENGE=y
+CONFIG_CROS_EC_KEYB=y
+CONFIG_LED=y
+CONFIG_LED_GPIO=y
+CONFIG_CMD_CROS_EC=y
+CONFIG_CROS_EC=y
+CONFIG_CROS_EC_I2C=y
+CONFIG_CROS_EC_LPC=y
+CONFIG_CROS_EC_SANDBOX=y
+CONFIG_CROS_EC_SPI=y
+CONFIG_PWRSEQ=y
+CONFIG_SPL_PWRSEQ=y
+CONFIG_RESET=y
+CONFIG_DM_MMC=y
+CONFIG_SPI_FLASH_SANDBOX=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_DM_ETH=y
+CONFIG_DM_PCI=y
+CONFIG_DM_PCI_COMPAT=y
+CONFIG_PCI_SANDBOX=y
+CONFIG_PINCTRL=y
+CONFIG_PINCONF=y
+CONFIG_ROCKCHIP_PINCTRL=y
+CONFIG_ROCKCHIP_3036_PINCTRL=y
+CONFIG_PINCTRL_SANDBOX=y
+CONFIG_DM_PMIC=y
+CONFIG_PMIC_ACT8846=y
+CONFIG_DM_PMIC_PFUZE100=y
+CONFIG_DM_PMIC_MAX77686=y
+CONFIG_PMIC_PM8916=y
+CONFIG_PMIC_RK808=y
+CONFIG_PMIC_S2MPS11=y
+CONFIG_DM_PMIC_SANDBOX=y
+CONFIG_PMIC_S5M8767=y
+CONFIG_PMIC_TPS65090=y
+CONFIG_DM_REGULATOR=y
+CONFIG_REGULATOR_ACT8846=y
+CONFIG_DM_REGULATOR_PFUZE100=y
+CONFIG_DM_REGULATOR_MAX77686=y
+CONFIG_DM_REGULATOR_FIXED=y
+CONFIG_REGULATOR_RK808=y
+CONFIG_REGULATOR_S5M8767=y
+CONFIG_DM_REGULATOR_SANDBOX=y
+CONFIG_REGULATOR_TPS65090=y
+CONFIG_RAM=y
+CONFIG_REMOTEPROC_SANDBOX=y
+CONFIG_DM_RTC=y
+CONFIG_SANDBOX_SERIAL=y
+CONFIG_SOUND=y
+CONFIG_SOUND_SANDBOX=y
+CONFIG_SANDBOX_SPI=y
+CONFIG_SPMI=y
+CONFIG_SPMI_SANDBOX=y
+CONFIG_TIMER=y
+CONFIG_TIMER_EARLY=y
+CONFIG_SANDBOX_TIMER=y
+CONFIG_TPM_TIS_SANDBOX=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EMUL=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_KEYBOARD=y
+CONFIG_SYS_USB_EVENT_POLL=y
+CONFIG_DM_VIDEO=y
+CONFIG_CONSOLE_ROTATION=y
+CONFIG_CONSOLE_TRUETYPE=y
+CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
+CONFIG_VIDEO_SANDBOX_SDL=y
+CONFIG_CMD_DHRYSTONE=y
+CONFIG_TPM=y
+CONFIG_LZ4=y
+CONFIG_ERRNO_STR=y
+CONFIG_UNIT_TEST=y
+CONFIG_UT_TIME=y
+CONFIG_UT_DM=y
+CONFIG_UT_ENV=y
diff --git a/configs/socfpga_arria5_defconfig b/configs/socfpga_arria5_defconfig
index 9a7c091..a662e72 100644
--- a/configs/socfpga_arria5_defconfig
+++ b/configs/socfpga_arria5_defconfig
@@ -33,6 +33,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
diff --git a/configs/socfpga_cyclone5_defconfig b/configs/socfpga_cyclone5_defconfig
index ac81854..b2933f7 100644
--- a/configs/socfpga_cyclone5_defconfig
+++ b/configs/socfpga_cyclone5_defconfig
@@ -33,6 +33,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
diff --git a/configs/socfpga_de0_nano_soc_defconfig b/configs/socfpga_de0_nano_soc_defconfig
index 405d9d4..f197b6d 100644
--- a/configs/socfpga_de0_nano_soc_defconfig
+++ b/configs/socfpga_de0_nano_soc_defconfig
@@ -32,6 +32,7 @@
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/socfpga_mcvevk_defconfig b/configs/socfpga_mcvevk_defconfig
index 3615490..6624f9e 100644
--- a/configs/socfpga_mcvevk_defconfig
+++ b/configs/socfpga_mcvevk_defconfig
@@ -32,6 +32,7 @@
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_DM_ETH=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/socfpga_sockit_defconfig b/configs/socfpga_sockit_defconfig
index bdc8e6b..c6414f8 100644
--- a/configs/socfpga_sockit_defconfig
+++ b/configs/socfpga_sockit_defconfig
@@ -33,6 +33,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
diff --git a/configs/socfpga_socrates_defconfig b/configs/socfpga_socrates_defconfig
index a17e9d0..b47a560 100644
--- a/configs/socfpga_socrates_defconfig
+++ b/configs/socfpga_socrates_defconfig
@@ -34,6 +34,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
diff --git a/configs/socfpga_sr1500_defconfig b/configs/socfpga_sr1500_defconfig
index c4b215a..aab4498 100644
--- a/configs/socfpga_sr1500_defconfig
+++ b/configs/socfpga_sr1500_defconfig
@@ -32,6 +32,7 @@
 CONFIG_CMD_FS_GENERIC=y
 CONFIG_SPL_DM_SEQ_ALIAS=y
 CONFIG_DWAPB_GPIO=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_DM_MMC=y
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_BAR=y
diff --git a/configs/spear300_defconfig b/configs/spear300_defconfig
index af2f544..db3b6ea 100644
--- a/configs/spear300_defconfig
+++ b/configs/spear300_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear300_nand_defconfig b/configs/spear300_nand_defconfig
index 6c53e1f..ea4e8d7 100644
--- a/configs/spear300_nand_defconfig
+++ b/configs/spear300_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear300_usbtty_defconfig b/configs/spear300_usbtty_defconfig
index 6827701..a2b56f3 100644
--- a/configs/spear300_usbtty_defconfig
+++ b/configs/spear300_usbtty_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear300_usbtty_nand_defconfig b/configs/spear300_usbtty_nand_defconfig
index 477a226..1738489 100644
--- a/configs/spear300_usbtty_nand_defconfig
+++ b/configs/spear300_usbtty_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_defconfig b/configs/spear310_defconfig
index 0991f8e..a6064a5 100644
--- a/configs/spear310_defconfig
+++ b/configs/spear310_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_nand_defconfig b/configs/spear310_nand_defconfig
index ef30a67..85944c6 100644
--- a/configs/spear310_nand_defconfig
+++ b/configs/spear310_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_pnor_defconfig b/configs/spear310_pnor_defconfig
index 6cfe220..48efe3d 100644
--- a/configs/spear310_pnor_defconfig
+++ b/configs/spear310_pnor_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_usbtty_defconfig b/configs/spear310_usbtty_defconfig
index c0d8edf..8edbe0c 100644
--- a/configs/spear310_usbtty_defconfig
+++ b/configs/spear310_usbtty_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_usbtty_nand_defconfig b/configs/spear310_usbtty_nand_defconfig
index e9d14ce..b622f74 100644
--- a/configs/spear310_usbtty_nand_defconfig
+++ b/configs/spear310_usbtty_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear310_usbtty_pnor_defconfig b/configs/spear310_usbtty_pnor_defconfig
index 2e46e64..241a72a 100644
--- a/configs/spear310_usbtty_pnor_defconfig
+++ b/configs/spear310_usbtty_pnor_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_defconfig b/configs/spear320_defconfig
index 8dba79a..49d7c04 100644
--- a/configs/spear320_defconfig
+++ b/configs/spear320_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_nand_defconfig b/configs/spear320_nand_defconfig
index 7f33c78..70b3025 100644
--- a/configs/spear320_nand_defconfig
+++ b/configs/spear320_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_pnor_defconfig b/configs/spear320_pnor_defconfig
index f7d3725..5ced0e1 100644
--- a/configs/spear320_pnor_defconfig
+++ b/configs/spear320_pnor_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_usbtty_defconfig b/configs/spear320_usbtty_defconfig
index 9e41253..de75b17 100644
--- a/configs/spear320_usbtty_defconfig
+++ b/configs/spear320_usbtty_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_usbtty_nand_defconfig b/configs/spear320_usbtty_nand_defconfig
index e61c74e..2202d2e 100644
--- a/configs/spear320_usbtty_nand_defconfig
+++ b/configs/spear320_usbtty_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear320_usbtty_pnor_defconfig b/configs/spear320_usbtty_pnor_defconfig
index 7410093..35bb036 100644
--- a/configs/spear320_usbtty_pnor_defconfig
+++ b/configs/spear320_usbtty_pnor_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear600_defconfig b/configs/spear600_defconfig
index f0e041f..f540839 100644
--- a/configs/spear600_defconfig
+++ b/configs/spear600_defconfig
@@ -9,5 +9,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear600_nand_defconfig b/configs/spear600_nand_defconfig
index cc4067d..de416d9 100644
--- a/configs/spear600_nand_defconfig
+++ b/configs/spear600_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear600_usbtty_defconfig b/configs/spear600_usbtty_defconfig
index df21355..8b6e0d0 100644
--- a/configs/spear600_usbtty_defconfig
+++ b/configs/spear600_usbtty_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/spear600_usbtty_nand_defconfig b/configs/spear600_usbtty_nand_defconfig
index 48140aa..e8b4b0a 100644
--- a/configs/spear600_usbtty_nand_defconfig
+++ b/configs/spear600_usbtty_nand_defconfig
@@ -6,5 +6,6 @@
 CONFIG_CMD_DHCP=y
 CONFIG_CMD_MII=y
 CONFIG_CMD_PING=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
diff --git a/configs/tplink_wdr4300_defconfig b/configs/tplink_wdr4300_defconfig
new file mode 100644
index 0000000..b1af2f6
--- /dev/null
+++ b/configs/tplink_wdr4300_defconfig
@@ -0,0 +1,43 @@
+CONFIG_MIPS=y
+CONFIG_ARCH_ATH79=y
+CONFIG_BOARD_TPLINK_WDR4300=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SYS_NS16550=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEFAULT_DEVICE_TREE="tplink_wdr4300"
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_IMLS is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_FPGA is not set
+CONFIG_CMD_NET=y
+CONFIG_CMD_NFS=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_NET_RANDOM_ETHADDR=y
+CONFIG_DM_ETH=y
+CONFIG_AG7XXX=y
+CONFIG_CLK=y
+CONFIG_CMD_USB=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_STORAGE=y
+CONFIG_ATH79_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_EON=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_DATAFLASH=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
diff --git a/configs/x600_defconfig b/configs/x600_defconfig
index 1a07b9d..ace620b 100644
--- a/configs/x600_defconfig
+++ b/configs/x600_defconfig
@@ -17,6 +17,7 @@
 CONFIG_CMD_CACHE=y
 CONFIG_CMD_FAT=y
 CONFIG_CMD_FS_GENERIC=y
+CONFIG_SYS_I2C_DW=y
 CONFIG_NETDEVICES=y
 CONFIG_ETH_DESIGNWARE=y
 CONFIG_USE_TINY_PRINTF=y
diff --git a/disk/part.c b/disk/part.c
index 543cab8..6a1c02d 100644
--- a/disk/part.c
+++ b/disk/part.c
@@ -21,35 +21,6 @@
 #define PRINTF(fmt,args...)
 #endif
 
-const struct block_drvr block_drvr[] = {
-#if defined(CONFIG_CMD_IDE)
-	{ .name = "ide", .get_dev = ide_get_dev, },
-#endif
-#if defined(CONFIG_CMD_SATA)
-	{.name = "sata", .get_dev = sata_get_dev, },
-#endif
-#if defined(CONFIG_CMD_SCSI)
-	{ .name = "scsi", .get_dev = scsi_get_dev, },
-#endif
-#if defined(CONFIG_CMD_USB) && defined(CONFIG_USB_STORAGE)
-	{ .name = "usb", .get_dev = usb_stor_get_dev, },
-#endif
-#if defined(CONFIG_MMC)
-	{
-		.name = "mmc",
-		.get_dev = mmc_get_dev,
-		.select_hwpart = mmc_select_hwpart,
-	},
-#endif
-#if defined(CONFIG_SYSTEMACE)
-	{ .name = "ace", .get_dev = systemace_get_dev, },
-#endif
-#if defined(CONFIG_SANDBOX)
-	{ .name = "host", .get_dev = host_get_dev, },
-#endif
-	{ },
-};
-
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef HAVE_BLOCK_DEVICE
@@ -71,45 +42,23 @@
 
 static struct blk_desc *get_dev_hwpart(const char *ifname, int dev, int hwpart)
 {
-	const struct block_drvr *drvr = block_drvr;
-	struct blk_desc* (*reloc_get_dev)(int dev);
-	int (*select_hwpart)(int dev_num, int hwpart);
-	char *name;
+	struct blk_desc *dev_desc;
 	int ret;
 
-	if (!ifname)
+	dev_desc = blk_get_devnum_by_typename(ifname, dev);
+	if (!dev_desc) {
+		debug("%s: No device for iface '%s', dev %d\n", __func__,
+		      ifname, dev);
 		return NULL;
-
-	name = drvr->name;
-#ifdef CONFIG_NEEDS_MANUAL_RELOC
-	name += gd->reloc_off;
-#endif
-	while (drvr->name) {
-		name = drvr->name;
-		reloc_get_dev = drvr->get_dev;
-		select_hwpart = drvr->select_hwpart;
-#ifdef CONFIG_NEEDS_MANUAL_RELOC
-		name += gd->reloc_off;
-		reloc_get_dev += gd->reloc_off;
-		if (select_hwpart)
-			select_hwpart += gd->reloc_off;
-#endif
-		if (strncmp(ifname, name, strlen(name)) == 0) {
-			struct blk_desc *dev_desc = reloc_get_dev(dev);
-			if (!dev_desc)
-				return NULL;
-			if (hwpart == 0 && !select_hwpart)
-				return dev_desc;
-			if (!select_hwpart)
-				return NULL;
-			ret = select_hwpart(dev_desc->devnum, hwpart);
-			if (ret < 0)
-				return NULL;
-			return dev_desc;
-		}
-		drvr++;
 	}
-	return NULL;
+	ret = blk_dselect_hwpart(dev_desc, hwpart);
+	if (ret) {
+		debug("%s: Failed to select h/w partition: err-%d\n", __func__,
+		      ret);
+		return NULL;
+	}
+
+	return dev_desc;
 }
 
 struct blk_desc *blk_get_dev(const char *ifname, int dev)
@@ -401,7 +350,7 @@
 	if (*ep) {
 		printf("** Bad device specification %s %s **\n",
 		       ifname, dev_str);
-		dev = -1;
+		dev = -EINVAL;
 		goto cleanup;
 	}
 
@@ -410,7 +359,7 @@
 		if (*ep) {
 			printf("** Bad HW partition specification %s %s **\n",
 			    ifname, hwpart_str);
-			dev = -1;
+			dev = -EINVAL;
 			goto cleanup;
 		}
 	}
@@ -418,7 +367,7 @@
 	*dev_desc = get_dev_hwpart(ifname, dev, hwpart);
 	if (!(*dev_desc) || ((*dev_desc)->type == DEV_TYPE_UNKNOWN)) {
 		printf("** Bad device %s %s **\n", ifname, dev_hwpart_str);
-		dev = -1;
+		dev = -ENOENT;
 		goto cleanup;
 	}
 
diff --git a/doc/device-tree-bindings/serial/qca,ar9330-uart.txt b/doc/device-tree-bindings/serial/qca,ar9330-uart.txt
new file mode 100644
index 0000000..ec576a1
--- /dev/null
+++ b/doc/device-tree-bindings/serial/qca,ar9330-uart.txt
@@ -0,0 +1,24 @@
+* Qualcomm Atheros AR9330 High-Speed UART
+
+Required properties:
+
+- compatible: Must be "qca,ar9330-uart"
+
+- reg: Specifies the physical base address of the controller and
+  the length of the memory mapped region.
+
+Additional requirements:
+
+  Each UART port must have an alias correctly numbered in "aliases"
+  node.
+
+Example:
+
+	aliases {
+		serial0 = &uart0;
+	};
+
+	uart0: uart@18020000 {
+		compatible = "qca,ar9330-uart";
+		reg = <0x18020000 0x14>;
+	};
diff --git a/doc/device-tree-bindings/spi/spi-ath79.txt b/doc/device-tree-bindings/spi/spi-ath79.txt
new file mode 100644
index 0000000..3fd9d67
--- /dev/null
+++ b/doc/device-tree-bindings/spi/spi-ath79.txt
@@ -0,0 +1,19 @@
+Binding for Qualcomm Atheros AR7xxx/AR9xxx SPI controller
+
+Required properties:
+- compatible: has to be "qca,<soc-type>-spi", "qca,ar7100-spi" as fallback.
+- reg: Base address and size of the controllers memory area
+- #address-cells: <1>, as required by generic SPI binding.
+- #size-cells: <0>, also as required by generic SPI binding.
+
+Child nodes as per the generic SPI binding.
+
+Example:
+
+	spi@1f000000 {
+		compatible = "qca,ar9132-spi", "qca,ar7100-spi";
+		reg = <0x1f000000 0x10>;
+
+		#address-cells = <1>;
+		#size-cells = <0>;
+	};
diff --git a/drivers/Makefile b/drivers/Makefile
index 6900097..99dd07f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -36,6 +36,8 @@
 obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += usb/host/
 obj-$(CONFIG_OMAP_USB_PHY) += usb/phy/
 obj-$(CONFIG_SPL_SATA_SUPPORT) += block/
+obj-$(CONFIG_SPL_USB_HOST_SUPPORT) += block/
+obj-$(CONFIG_SPL_MMC_SUPPORT) += block/
 
 else
 
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index fcc9ccd..80eea84 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -9,10 +9,9 @@
 	  be partitioned into several areas, called 'partitions' in U-Boot.
 	  A filesystem can be placed in each partition.
 
-config DISK
-	bool "Support disk controllers with driver model"
+config AHCI
+	bool "Support SATA controllers with driver model"
 	depends on DM
-	default y if DM
 	help
 	  This enables a uclass for disk controllers in U-Boot. Various driver
 	  types can use this, such as AHCI/SATA. It does not provide any standard
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index a43492f..436b79f 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -7,7 +7,11 @@
 
 obj-$(CONFIG_BLK) += blk-uclass.o
 
-obj-$(CONFIG_DISK) += disk-uclass.o
+ifndef CONFIG_BLK
+obj-y += blk_legacy.o
+endif
+
+obj-$(CONFIG_AHCI) += ahci-uclass.o
 obj-$(CONFIG_SCSI_AHCI) += ahci.o
 obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
 obj-$(CONFIG_FSL_SATA) += fsl_sata.o
@@ -22,7 +26,7 @@
 obj-$(CONFIG_SATA_SIL3114) += sata_sil3114.o
 obj-$(CONFIG_SATA_SIL) += sata_sil.o
 obj-$(CONFIG_IDE_SIL680) += sil680.o
-obj-$(CONFIG_SANDBOX) += sandbox.o
+obj-$(CONFIG_SANDBOX) += sandbox.o sandbox_scsi.o sata_sandbox.o
 obj-$(CONFIG_SCSI_SYM53C8XX) += sym53c8xx.o
 obj-$(CONFIG_SYSTEMACE) += systemace.o
 obj-$(CONFIG_BLOCK_CACHE) += blkcache.o
diff --git a/drivers/block/disk-uclass.c b/drivers/block/ahci-uclass.c
similarity index 72%
rename from drivers/block/disk-uclass.c
rename to drivers/block/ahci-uclass.c
index d665b35..7b8c326 100644
--- a/drivers/block/disk-uclass.c
+++ b/drivers/block/ahci-uclass.c
@@ -8,7 +8,7 @@
 #include <common.h>
 #include <dm.h>
 
-UCLASS_DRIVER(disk) = {
-	.id		= UCLASS_DISK,
-	.name		= "disk",
+UCLASS_DRIVER(ahci) = {
+	.id		= UCLASS_AHCI,
+	.name		= "ahci",
 };
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 617db22..6ba1026 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -11,6 +11,315 @@
 #include <dm/device-internal.h>
 #include <dm/lists.h>
 
+static const char *if_typename_str[IF_TYPE_COUNT] = {
+	[IF_TYPE_IDE]		= "ide",
+	[IF_TYPE_SCSI]		= "scsi",
+	[IF_TYPE_ATAPI]		= "atapi",
+	[IF_TYPE_USB]		= "usb",
+	[IF_TYPE_DOC]		= "doc",
+	[IF_TYPE_MMC]		= "mmc",
+	[IF_TYPE_SD]		= "sd",
+	[IF_TYPE_SATA]		= "sata",
+	[IF_TYPE_HOST]		= "host",
+	[IF_TYPE_SYSTEMACE]	= "ace",
+};
+
+static enum uclass_id if_type_uclass_id[IF_TYPE_COUNT] = {
+	[IF_TYPE_IDE]		= UCLASS_INVALID,
+	[IF_TYPE_SCSI]		= UCLASS_INVALID,
+	[IF_TYPE_ATAPI]		= UCLASS_INVALID,
+	[IF_TYPE_USB]		= UCLASS_MASS_STORAGE,
+	[IF_TYPE_DOC]		= UCLASS_INVALID,
+	[IF_TYPE_MMC]		= UCLASS_MMC,
+	[IF_TYPE_SD]		= UCLASS_INVALID,
+	[IF_TYPE_SATA]		= UCLASS_AHCI,
+	[IF_TYPE_HOST]		= UCLASS_ROOT,
+	[IF_TYPE_SYSTEMACE]	= UCLASS_INVALID,
+};
+
+static enum if_type if_typename_to_iftype(const char *if_typename)
+{
+	int i;
+
+	for (i = 0; i < IF_TYPE_COUNT; i++) {
+		if (if_typename_str[i] &&
+		    !strcmp(if_typename, if_typename_str[i]))
+			return i;
+	}
+
+	return IF_TYPE_UNKNOWN;
+}
+
+static enum uclass_id if_type_to_uclass_id(enum if_type if_type)
+{
+	return if_type_uclass_id[if_type];
+}
+
+struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
+{
+	struct blk_desc *desc;
+	struct udevice *dev;
+	int ret;
+
+	ret = blk_get_device(if_type, devnum, &dev);
+	if (ret)
+		return NULL;
+	desc = dev_get_uclass_platdata(dev);
+
+	return desc;
+}
+
+/*
+ * This function is complicated with driver model. We look up the interface
+ * name in a local table. This gives us an interface type which we can match
+ * against the uclass of the block device's parent.
+ */
+struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+{
+	enum uclass_id uclass_id;
+	enum if_type if_type;
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	if_type = if_typename_to_iftype(if_typename);
+	if (if_type == IF_TYPE_UNKNOWN) {
+		debug("%s: Unknown interface type '%s'\n", __func__,
+		      if_typename);
+		return NULL;
+	}
+	uclass_id = if_type_to_uclass_id(if_type);
+	if (uclass_id == UCLASS_INVALID) {
+		debug("%s: Unknown uclass for interface type'\n",
+		      if_typename_str[if_type]);
+		return NULL;
+	}
+
+	ret = uclass_get(UCLASS_BLK, &uc);
+	if (ret)
+		return NULL;
+	uclass_foreach_dev(dev, uc) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
+		if (desc->devnum != devnum)
+			continue;
+
+		/* Find out the parent device uclass */
+		if (device_get_uclass_id(dev->parent) != uclass_id) {
+			debug("%s: parent uclass %d, this dev %d\n", __func__,
+			      device_get_uclass_id(dev->parent), uclass_id);
+			continue;
+		}
+
+		if (device_probe(dev))
+			return NULL;
+
+		debug("%s: Device desc %p\n", __func__, desc);
+		return desc;
+	}
+	debug("%s: No device found\n", __func__);
+
+	return NULL;
+}
+
+/**
+ * get_desc() - Get the block device descriptor for the given device number
+ *
+ * @if_type:	Interface type
+ * @devnum:	Device number (0 = first)
+ * @descp:	Returns block device descriptor on success
+ * @return 0 on success, -ENODEV if there is no such device and no device
+ * with a higher device number, -ENOENT if there is no such device but there
+ * is one with a higher number, or other -ve on other error.
+ */
+static int get_desc(enum if_type if_type, int devnum, struct blk_desc **descp)
+{
+	bool found_more = false;
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	*descp = NULL;
+	ret = uclass_get(UCLASS_BLK, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
+		if (desc->if_type == if_type) {
+			if (desc->devnum == devnum) {
+				ret = device_probe(dev);
+				if (ret)
+					return ret;
+
+			} else if (desc->devnum > devnum) {
+				found_more = true;
+			}
+		}
+	}
+
+	return found_more ? -ENOENT : -ENODEV;
+}
+
+int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = blk_get_device(if_type, devnum, &dev);
+	if (ret)
+		return ret;
+
+	return blk_select_hwpart(dev, hwpart);
+}
+
+int blk_list_part(enum if_type if_type)
+{
+	struct blk_desc *desc;
+	int devnum, ok;
+	int ret;
+
+	for (ok = 0, devnum = 0;; ++devnum) {
+		ret = get_desc(if_type, devnum, &desc);
+		if (ret == -ENODEV)
+			break;
+		else if (ret)
+			continue;
+		if (desc->part_type != PART_TYPE_UNKNOWN) {
+			++ok;
+			if (devnum)
+				putc('\n');
+			part_print(desc);
+		}
+	}
+	if (!ok)
+		return -ENODEV;
+
+	return 0;
+}
+
+int blk_print_part_devnum(enum if_type if_type, int devnum)
+{
+	struct blk_desc *desc;
+	int ret;
+
+	ret = get_desc(if_type, devnum, &desc);
+	if (ret)
+		return ret;
+	if (desc->type == DEV_TYPE_UNKNOWN)
+		return -ENOENT;
+	part_print(desc);
+
+	return 0;
+}
+
+void blk_list_devices(enum if_type if_type)
+{
+	struct blk_desc *desc;
+	int ret;
+	int i;
+
+	for (i = 0;; ++i) {
+		ret = get_desc(if_type, i, &desc);
+		if (ret == -ENODEV)
+			break;
+		else if (ret)
+			continue;
+		if (desc->type == DEV_TYPE_UNKNOWN)
+			continue;  /* list only known devices */
+		printf("Device %d: ", i);
+		dev_print(desc);
+	}
+}
+
+int blk_print_device_num(enum if_type if_type, int devnum)
+{
+	struct blk_desc *desc;
+	int ret;
+
+	ret = get_desc(if_type, devnum, &desc);
+	if (ret)
+		return ret;
+	printf("\nIDE device %d: ", devnum);
+	dev_print(desc);
+
+	return 0;
+}
+
+int blk_show_device(enum if_type if_type, int devnum)
+{
+	struct blk_desc *desc;
+	int ret;
+
+	printf("\nDevice %d: ", devnum);
+	ret = get_desc(if_type, devnum, &desc);
+	if (ret == -ENODEV || ret == -ENOENT) {
+		printf("unknown device\n");
+		return -ENODEV;
+	}
+	if (ret)
+		return ret;
+	dev_print(desc);
+
+	if (desc->type == DEV_TYPE_UNKNOWN)
+		return -ENOENT;
+
+	return 0;
+}
+
+ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		      lbaint_t blkcnt, void *buffer)
+{
+	struct blk_desc *desc;
+	ulong n;
+	int ret;
+
+	ret = get_desc(if_type, devnum, &desc);
+	if (ret)
+		return ret;
+	n = blk_dread(desc, start, blkcnt, buffer);
+	if (IS_ERR_VALUE(n))
+		return n;
+
+	/* flush cache after read */
+	flush_cache((ulong)buffer, blkcnt * desc->blksz);
+
+	return n;
+}
+
+ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		       lbaint_t blkcnt, const void *buffer)
+{
+	struct blk_desc *desc;
+	int ret;
+
+	ret = get_desc(if_type, devnum, &desc);
+	if (ret)
+		return ret;
+	return blk_dwrite(desc, start, blkcnt, buffer);
+}
+
+int blk_select_hwpart(struct udevice *dev, int hwpart)
+{
+	const struct blk_ops *ops = blk_get_ops(dev);
+
+	if (!ops)
+		return -ENOSYS;
+	if (!ops->select_hwpart)
+		return 0;
+
+	return ops->select_hwpart(dev, hwpart);
+}
+
+int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
+{
+	return blk_select_hwpart(desc->bdev, hwpart);
+}
+
 int blk_first_device(int if_type, struct udevice **devp)
 {
 	struct blk_desc *desc;
@@ -131,6 +440,26 @@
 	return 0;
 }
 
+int blk_find_max_devnum(enum if_type if_type)
+{
+	struct udevice *dev;
+	int max_devnum = -ENODEV;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_BLK, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+		if (desc->if_type == if_type && desc->devnum > max_devnum)
+			max_devnum = desc->devnum;
+	}
+
+	return max_devnum;
+}
+
 int blk_create_device(struct udevice *parent, const char *drv_name,
 		      const char *name, int if_type, int devnum, int blksz,
 		      lbaint_t size, struct udevice **devp)
@@ -139,6 +468,15 @@
 	struct udevice *dev;
 	int ret;
 
+	if (devnum == -1) {
+		ret = blk_find_max_devnum(if_type);
+		if (ret == -ENODEV)
+			devnum = 0;
+		else if (ret < 0)
+			return ret;
+		else
+			devnum = ret + 1;
+	}
 	ret = device_bind_driver(parent, drv_name, name, &dev);
 	if (ret)
 		return ret;
@@ -154,6 +492,29 @@
 	return 0;
 }
 
+int blk_create_devicef(struct udevice *parent, const char *drv_name,
+		       const char *name, int if_type, int devnum, int blksz,
+		       lbaint_t size, struct udevice **devp)
+{
+	char dev_name[30], *str;
+	int ret;
+
+	snprintf(dev_name, sizeof(dev_name), "%s.%s", parent->name, name);
+	str = strdup(dev_name);
+	if (!str)
+		return -ENOMEM;
+
+	ret = blk_create_device(parent, drv_name, str, if_type, devnum,
+				blksz, size, devp);
+	if (ret) {
+		free(str);
+		return ret;
+	}
+	device_set_name_alloced(*devp);
+
+	return ret;
+}
+
 int blk_unbind_all(int if_type)
 {
 	struct uclass *uc;
diff --git a/drivers/block/blk_legacy.c b/drivers/block/blk_legacy.c
new file mode 100644
index 0000000..7b90a8a
--- /dev/null
+++ b/drivers/block/blk_legacy.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/err.h>
+
+struct blk_driver *blk_driver_lookup_type(int if_type)
+{
+	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
+	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
+	struct blk_driver *entry;
+
+	for (entry = drv; entry != drv + n_ents; entry++) {
+		if (if_type == entry->if_type)
+			return entry;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+static struct blk_driver *blk_driver_lookup_typename(const char *if_typename)
+{
+	struct blk_driver *drv = ll_entry_start(struct blk_driver, blk_driver);
+	const int n_ents = ll_entry_count(struct blk_driver, blk_driver);
+	struct blk_driver *entry;
+
+	for (entry = drv; entry != drv + n_ents; entry++) {
+		if (!strcmp(if_typename, entry->if_typename))
+			return entry;
+	}
+
+	/* Not found */
+	return NULL;
+}
+
+/**
+ * get_desc() - Get the block device descriptor for the given device number
+ *
+ * @drv:	Legacy block driver
+ * @devnum:	Device number (0 = first)
+ * @descp:	Returns block device descriptor on success
+ * @return 0 on success, -ENODEV if there is no such device, -ENOSYS if the
+ * driver does not provide a way to find a device, or other -ve on other
+ * error.
+ */
+static int get_desc(struct blk_driver *drv, int devnum, struct blk_desc **descp)
+{
+	if (drv->desc) {
+		if (devnum < 0 || devnum >= drv->max_devs)
+			return -ENODEV;
+		*descp = &drv->desc[devnum];
+		return 0;
+	}
+	if (!drv->get_dev)
+		return -ENOSYS;
+
+	return drv->get_dev(devnum, descp);
+}
+
+#ifdef HAVE_BLOCK_DEVICE
+int blk_list_part(enum if_type if_type)
+{
+	struct blk_driver *drv;
+	struct blk_desc *desc;
+	int devnum, ok;
+	bool first = true;
+
+	drv = blk_driver_lookup_type(if_type);
+	if (!drv)
+		return -ENOSYS;
+	for (ok = 0, devnum = 0; devnum < drv->max_devs; ++devnum) {
+		if (get_desc(drv, devnum, &desc))
+			continue;
+		if (desc->part_type != PART_TYPE_UNKNOWN) {
+			++ok;
+			if (!first)
+				putc('\n');
+			part_print(desc);
+			first = false;
+		}
+	}
+	if (!ok)
+		return -ENODEV;
+
+	return 0;
+}
+
+int blk_print_part_devnum(enum if_type if_type, int devnum)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	if (desc->type == DEV_TYPE_UNKNOWN)
+		return -ENOENT;
+	part_print(desc);
+
+	return 0;
+}
+
+void blk_list_devices(enum if_type if_type)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int i;
+
+	if (!drv)
+		return;
+	for (i = 0; i < drv->max_devs; ++i) {
+		if (get_desc(drv, i, &desc))
+			continue;
+		if (desc->type == DEV_TYPE_UNKNOWN)
+			continue;  /* list only known devices */
+		printf("Device %d: ", i);
+		dev_print(desc);
+	}
+}
+
+int blk_print_device_num(enum if_type if_type, int devnum)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	printf("\n%s device %d: ", drv->if_typename, devnum);
+	dev_print(desc);
+
+	return 0;
+}
+
+int blk_show_device(enum if_type if_type, int devnum)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	printf("\nDevice %d: ", devnum);
+	if (devnum >= drv->max_devs) {
+		puts("unknown device\n");
+		return -ENODEV;
+	}
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	dev_print(desc);
+
+	if (desc->type == DEV_TYPE_UNKNOWN)
+		return -ENOENT;
+
+	return 0;
+}
+#endif /* HAVE_BLOCK_DEVICE */
+
+struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+
+	if (!drv)
+		return NULL;
+
+	if (get_desc(drv, devnum, &desc))
+		return NULL;
+
+	return desc;
+}
+
+int blk_dselect_hwpart(struct blk_desc *desc, int hwpart)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(desc->if_type);
+
+	if (!drv)
+		return -ENOSYS;
+	if (drv->select_hwpart)
+		return drv->select_hwpart(desc, hwpart);
+
+	return 0;
+}
+
+struct blk_desc *blk_get_devnum_by_typename(const char *if_typename, int devnum)
+{
+	struct blk_driver *drv = blk_driver_lookup_typename(if_typename);
+	struct blk_desc *desc;
+
+	if (!drv)
+		return NULL;
+
+	if (get_desc(drv, devnum, &desc))
+		return NULL;
+
+	return desc;
+}
+
+ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		      lbaint_t blkcnt, void *buffer)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	ulong n;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	n = desc->block_read(desc, start, blkcnt, buffer);
+	if (IS_ERR_VALUE(n))
+		return n;
+
+	/* flush cache after read */
+	flush_cache((ulong)buffer, blkcnt * desc->blksz);
+
+	return n;
+}
+
+ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		       lbaint_t blkcnt, const void *buffer)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	return desc->block_write(desc, start, blkcnt, buffer);
+}
+
+int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart)
+{
+	struct blk_driver *drv = blk_driver_lookup_type(if_type);
+	struct blk_desc *desc;
+	int ret;
+
+	if (!drv)
+		return -ENOSYS;
+	ret = get_desc(drv, devnum, &desc);
+	if (ret)
+		return ret;
+	return drv->select_hwpart(desc, hwpart);
+}
diff --git a/drivers/block/sandbox.c b/drivers/block/sandbox.c
index 2d340ef..ac28f83 100644
--- a/drivers/block/sandbox.c
+++ b/drivers/block/sandbox.c
@@ -17,6 +17,19 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+#ifndef CONFIG_BLK
+static struct host_block_dev host_devices[CONFIG_HOST_MAX_DEVICES];
+
+static struct host_block_dev *find_host_device(int dev)
+{
+	if (dev >= 0 && dev < CONFIG_HOST_MAX_DEVICES)
+		return &host_devices[dev];
+
+	return NULL;
+}
+#endif
+
+#ifdef CONFIG_BLK
 static unsigned long host_block_read(struct udevice *dev,
 				     unsigned long start, lbaint_t blkcnt,
 				     void *buffer)
@@ -24,6 +37,18 @@
 	struct host_block_dev *host_dev = dev_get_priv(dev);
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
 
+#else
+static unsigned long host_block_read(struct blk_desc *block_dev,
+				     unsigned long start, lbaint_t blkcnt,
+				     void *buffer)
+{
+	int dev = block_dev->devnum;
+	struct host_block_dev *host_dev = find_host_device(dev);
+
+	if (!host_dev)
+		return -1;
+#endif
+
 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
 			-1) {
 		printf("ERROR: Invalid block %lx\n", start);
@@ -35,12 +60,21 @@
 	return -1;
 }
 
+#ifdef CONFIG_BLK
 static unsigned long host_block_write(struct udevice *dev,
 				      unsigned long start, lbaint_t blkcnt,
 				      const void *buffer)
 {
 	struct host_block_dev *host_dev = dev_get_priv(dev);
 	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#else
+static unsigned long host_block_write(struct blk_desc *block_dev,
+				      unsigned long start, lbaint_t blkcnt,
+				      const void *buffer)
+{
+	int dev = block_dev->devnum;
+	struct host_block_dev *host_dev = find_host_device(dev);
+#endif
 
 	if (os_lseek(host_dev->fd, start * block_dev->blksz, OS_SEEK_SET) ==
 			-1) {
@@ -53,6 +87,7 @@
 	return -1;
 }
 
+#ifdef CONFIG_BLK
 int host_dev_bind(int devnum, char *filename)
 {
 	struct host_block_dev *host_dev;
@@ -115,9 +150,51 @@
 	free(str);
 	return ret;
 }
+#else
+int host_dev_bind(int dev, char *filename)
+{
+	struct host_block_dev *host_dev = find_host_device(dev);
+
+	if (!host_dev)
+		return -1;
+	if (host_dev->blk_dev.priv) {
+		os_close(host_dev->fd);
+		host_dev->blk_dev.priv = NULL;
+	}
+	if (host_dev->filename)
+		free(host_dev->filename);
+	if (filename && *filename) {
+		host_dev->filename = strdup(filename);
+	} else {
+		host_dev->filename = NULL;
+		return 0;
+	}
+
+	host_dev->fd = os_open(host_dev->filename, OS_O_RDWR);
+	if (host_dev->fd == -1) {
+		printf("Failed to access host backing file '%s'\n",
+		       host_dev->filename);
+		return 1;
+	}
+
+	struct blk_desc *blk_dev = &host_dev->blk_dev;
+	blk_dev->if_type = IF_TYPE_HOST;
+	blk_dev->priv = host_dev;
+	blk_dev->blksz = 512;
+	blk_dev->lba = os_lseek(host_dev->fd, 0, OS_SEEK_END) / blk_dev->blksz;
+	blk_dev->block_read = host_block_read;
+	blk_dev->block_write = host_block_write;
+	blk_dev->devnum = dev;
+	blk_dev->part_type = PART_TYPE_UNKNOWN;
+	part_init(blk_dev);
+
+	return 0;
+}
+#endif
 
 int host_get_dev_err(int devnum, struct blk_desc **blk_devp)
 {
+#ifdef CONFIG_BLK
 	struct udevice *dev;
 	int ret;
 
@@ -125,20 +202,22 @@
 	if (ret)
 		return ret;
 	*blk_devp = dev_get_uclass_platdata(dev);
+#else
+	struct host_block_dev *host_dev = find_host_device(devnum);
+
+	if (!host_dev)
+		return -ENODEV;
+
+	if (!host_dev->blk_dev.priv)
+		return -ENOENT;
+
+	*blk_devp = &host_dev->blk_dev;
+#endif
 
 	return 0;
 }
 
-struct blk_desc *host_get_dev(int dev)
-{
-	struct blk_desc *blk_dev;
-
-	if (host_get_dev_err(dev, &blk_dev))
-		return NULL;
-
-	return blk_dev;
-}
-
+#ifdef CONFIG_BLK
 static const struct blk_ops sandbox_host_blk_ops = {
 	.read	= host_block_read,
 	.write	= host_block_write,
@@ -150,3 +229,11 @@
 	.ops		= &sandbox_host_blk_ops,
 	.priv_auto_alloc_size	= sizeof(struct host_block_dev),
 };
+#else
+U_BOOT_LEGACY_BLK(sandbox_host) = {
+	.if_typename	= "host",
+	.if_type	= IF_TYPE_HOST,
+	.max_devs	= CONFIG_HOST_MAX_DEVICES,
+	.get_dev	= host_get_dev_err,
+};
+#endif
diff --git a/drivers/block/sandbox_scsi.c b/drivers/block/sandbox_scsi.c
new file mode 100644
index 0000000..ad961bd
--- /dev/null
+++ b/drivers/block/sandbox_scsi.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ * This file contains dummy implementations of SCSI functions requried so
+ * that CONFIG_SCSI can be enabled for sandbox.
+ */
+
+#include <common.h>
+#include <scsi.h>
+
+void scsi_bus_reset(void)
+{
+}
+
+void scsi_init(void)
+{
+}
+
+int scsi_exec(ccb *pccb)
+{
+	return 0;
+}
+
+void scsi_print_error(ccb *pccb)
+{
+}
diff --git a/drivers/block/sata_sandbox.c b/drivers/block/sata_sandbox.c
new file mode 100644
index 0000000..bd967d2
--- /dev/null
+++ b/drivers/block/sata_sandbox.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2015 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+int init_sata(int dev)
+{
+	return 0;
+}
+
+int reset_sata(int dev)
+{
+	return 0;
+}
+
+int scan_sata(int dev)
+{
+	return 0;
+}
+
+ulong sata_read(int dev, ulong blknr, lbaint_t blkcnt, void *buffer)
+{
+	return 0;
+}
+
+ulong sata_write(int dev, ulong blknr, lbaint_t blkcnt, const void *buffer)
+{
+	return 0;
+}
diff --git a/drivers/block/sym53c8xx.c b/drivers/block/sym53c8xx.c
index c7c40af..5daede7 100644
--- a/drivers/block/sym53c8xx.c
+++ b/drivers/block/sym53c8xx.c
@@ -33,7 +33,7 @@
 #define PRINTF(fmt,args...)
 #endif
 
-#if defined(CONFIG_CMD_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
+#if defined(CONFIG_SCSI) && defined(CONFIG_SCSI_SYM53C8XX)
 
 #undef SCSI_SINGLE_STEP
 /*
diff --git a/drivers/block/systemace.c b/drivers/block/systemace.c
index 09fe834..9392bea 100644
--- a/drivers/block/systemace.c
+++ b/drivers/block/systemace.c
@@ -27,7 +27,7 @@
 
 #include <common.h>
 #include <command.h>
-#include <systemace.h>
+#include <dm.h>
 #include <part.h>
 #include <asm/io.h>
 
@@ -69,11 +69,9 @@
 	return in16(base + off);
 }
 
-static unsigned long systemace_read(struct blk_desc *block_dev,
-				    unsigned long start, lbaint_t blkcnt,
-				    void *buffer);
-
+#ifndef CONFIG_BLK
 static struct blk_desc systemace_dev = { 0 };
+#endif
 
 static int get_cf_lock(void)
 {
@@ -104,42 +102,19 @@
 	ace_writew((val & 0xffff), 0x18);
 }
 
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *systemace_get_dev(int dev)
-{
-	/* The first time through this, the systemace_dev object is
-	   not yet initialized. In that case, fill it in. */
-	if (systemace_dev.blksz == 0) {
-		systemace_dev.if_type = IF_TYPE_UNKNOWN;
-		systemace_dev.devnum = 0;
-		systemace_dev.part_type = PART_TYPE_UNKNOWN;
-		systemace_dev.type = DEV_TYPE_HARDDISK;
-		systemace_dev.blksz = 512;
-		systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
-		systemace_dev.removable = 1;
-		systemace_dev.block_read = systemace_read;
-
-		/*
-		 * Ensure the correct bus mode (8/16 bits) gets enabled
-		 */
-		ace_writew(width == 8 ? 0 : 0x0001, 0);
-
-		part_init(&systemace_dev);
-
-	}
-
-	return &systemace_dev;
-}
-#endif
-
 /*
  * This function is called (by dereferencing the block_read pointer in
  * the dev_desc) to read blocks of data. The return value is the
  * number of blocks read. A zero return indicates an error.
  */
+#ifdef CONFIG_BLK
+static unsigned long systemace_read(struct udevice *dev, unsigned long start,
+				    lbaint_t blkcnt, void *buffer)
+#else
 static unsigned long systemace_read(struct blk_desc *block_dev,
 				    unsigned long start, lbaint_t blkcnt,
 				    void *buffer)
+#endif
 {
 	int retry;
 	unsigned blk_countdown;
@@ -257,3 +232,72 @@
 
 	return blkcnt;
 }
+
+#ifdef CONFIG_BLK
+static int systemace_bind(struct udevice *dev)
+{
+	struct blk_desc *bdesc;
+	struct udevice *bdev;
+	int ret;
+
+	ret = blk_create_devicef(dev, "systemace_blk", "blk", IF_TYPE_SYSTEMACE,
+				 -1, 512, 0, &bdev);
+	if (ret) {
+		debug("Cannot create block device\n");
+		return ret;
+	}
+	bdesc = dev_get_uclass_platdata(bdev);
+	bdesc->removable = 1;
+	bdesc->part_type = PART_TYPE_UNKNOWN;
+	bdesc->log2blksz = LOG2(bdesc->blksz);
+
+	/* Ensure the correct bus mode (8/16 bits) gets enabled */
+	ace_writew(width == 8 ? 0 : 0x0001, 0);
+
+	return 0;
+}
+
+static const struct blk_ops systemace_blk_ops = {
+	.read	= systemace_read,
+};
+
+U_BOOT_DRIVER(systemace_blk) = {
+	.name		= "systemace_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &systemace_blk_ops,
+	.bind		= systemace_bind,
+};
+#else
+static int systemace_get_dev(int dev, struct blk_desc **descp)
+{
+	/* The first time through this, the systemace_dev object is
+	   not yet initialized. In that case, fill it in. */
+	if (systemace_dev.blksz == 0) {
+		systemace_dev.if_type = IF_TYPE_UNKNOWN;
+		systemace_dev.devnum = 0;
+		systemace_dev.part_type = PART_TYPE_UNKNOWN;
+		systemace_dev.type = DEV_TYPE_HARDDISK;
+		systemace_dev.blksz = 512;
+		systemace_dev.log2blksz = LOG2(systemace_dev.blksz);
+		systemace_dev.removable = 1;
+		systemace_dev.block_read = systemace_read;
+
+		/*
+		 * Ensure the correct bus mode (8/16 bits) gets enabled
+		 */
+		ace_writew(width == 8 ? 0 : 0x0001, 0);
+
+		part_init(&systemace_dev);
+	}
+	*descp = &systemace_dev;
+
+	return 0;
+}
+
+U_BOOT_LEGACY_BLK(systemace) = {
+	.if_typename	= "ace",
+	.if_type	= IF_TYPE_SYSTEMACE,
+	.max_devs	= 1,
+	.get_dev	= systemace_get_dev,
+};
+#endif
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index e1714b2..0e56b23 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -112,6 +112,8 @@
 
 	devres_release_all(dev);
 
+	if (dev->flags & DM_NAME_ALLOCED)
+		free((char *)dev->name);
 	free(dev);
 
 	return 0;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 1322991..5c2dc70 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -657,8 +657,8 @@
 #if CONFIG_IS_ENABLED(OF_CONTROL)
 	int index;
 
-	index = fdt_find_string(gd->fdt_blob, dev->parent->of_offset,
-				"reg-names", name);
+	index = fdt_find_string(gd->fdt_blob, dev->of_offset, "reg-names",
+				name);
 	if (index < 0)
 		return index;
 
@@ -706,12 +706,18 @@
 	return list_is_last(&dev->sibling_node, &parent->child_head);
 }
 
+void device_set_name_alloced(struct udevice *dev)
+{
+	dev->flags |= DM_NAME_ALLOCED;
+}
+
 int device_set_name(struct udevice *dev, const char *name)
 {
 	name = strdup(name);
 	if (!name)
 		return -ENOMEM;
 	dev->name = name;
+	device_set_name_alloced(dev);
 
 	return 0;
 }
diff --git a/drivers/core/lists.c b/drivers/core/lists.c
index c4fc216..a72db13 100644
--- a/drivers/core/lists.c
+++ b/drivers/core/lists.c
@@ -171,6 +171,10 @@
 
 		dm_dbg("   - found match at '%s'\n", entry->name);
 		ret = device_bind(parent, entry, name, NULL, offset, &dev);
+		if (ret == -ENODEV) {
+			dm_dbg("Driver '%s' refuses to bind\n", entry->name);
+			continue;
+		}
 		if (ret) {
 			dm_warn("Error binding driver '%s': %d\n", entry->name,
 				ret);
diff --git a/drivers/ddr/marvell/a38x/ddr3_init.c b/drivers/ddr/marvell/a38x/ddr3_init.c
index ee05f57..55baad4 100644
--- a/drivers/ddr/marvell/a38x/ddr3_init.c
+++ b/drivers/ddr/marvell/a38x/ddr3_init.c
@@ -678,7 +678,7 @@
 	return (device_width == 0) ? 8 : 16;
 }
 
-float ddr3_get_device_size(u32 cs)
+static int ddr3_get_device_size(u32 cs)
 {
 	u32 device_size_low, device_size_high, device_size;
 	u32 data, cs_low_offset, cs_high_offset;
@@ -695,15 +695,15 @@
 
 	switch (device_size) {
 	case 0:
-		return 2;
+		return 2048;
 	case 2:
-		return 0.5;
+		return 512;
 	case 3:
-		return 1;
+		return 1024;
 	case 4:
-		return 4;
+		return 4096;
 	case 5:
-		return 8;
+		return 8192;
 	case 1:
 	default:
 		DEBUG_INIT_C("Error: Wrong device size of Cs: ", cs, 1);
@@ -711,13 +711,13 @@
 		 * Small value will give wrong emem size in
 		 * ddr3_calc_mem_cs_size
 		 */
-		return 0.01;
+		return 0;
 	}
 }
 
 int ddr3_calc_mem_cs_size(u32 cs, u32 *cs_size)
 {
-	float cs_mem_size;
+	int cs_mem_size;
 
 	/* Calculate in GiB */
 	cs_mem_size = ((ddr3_get_bus_width() / ddr3_get_device_width(cs)) *
@@ -731,21 +731,12 @@
 	 */
 	cs_mem_size *= DDR_CONTROLLER_BUS_WIDTH_MULTIPLIER;
 
-	if (cs_mem_size == 0.125) {
-		*cs_size = 128 << 20;
-	} else if (cs_mem_size == 0.25) {
-		*cs_size = 256 << 20;
-	} else if (cs_mem_size == 0.5) {
-		*cs_size = 512 << 20;
-	} else if (cs_mem_size == 1) {
-		*cs_size = 1 << 30;
-	} else if (cs_mem_size == 2) {
-		*cs_size = 2 << 30;
-	} else {
+	if (!cs_mem_size || (cs_mem_size == 64) || (cs_mem_size == 4096)) {
 		DEBUG_INIT_C("Error: Wrong Memory size of Cs: ", cs, 1);
 		return MV_BAD_VALUE;
 	}
 
+	*cs_size = cs_mem_size << 20;
 	return MV_OK;
 }
 
diff --git a/drivers/dfu/dfu_mmc.c b/drivers/dfu/dfu_mmc.c
index faece88..78724e4 100644
--- a/drivers/dfu/dfu_mmc.c
+++ b/drivers/dfu/dfu_mmc.c
@@ -50,8 +50,9 @@
 
 	if (dfu->data.mmc.hw_partition >= 0) {
 		part_num_bkp = mmc->block_dev.hwpart;
-		ret = mmc_select_hwpart(dfu->data.mmc.dev_num,
-					dfu->data.mmc.hw_partition);
+		ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
+					       dfu->data.mmc.dev_num,
+					       dfu->data.mmc.hw_partition);
 		if (ret)
 			return ret;
 	}
@@ -75,12 +76,16 @@
 	if (n != blk_count) {
 		error("MMC operation failed");
 		if (dfu->data.mmc.hw_partition >= 0)
-			mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
+			blk_select_hwpart_devnum(IF_TYPE_MMC,
+						 dfu->data.mmc.dev_num,
+						 part_num_bkp);
 		return -EIO;
 	}
 
 	if (dfu->data.mmc.hw_partition >= 0) {
-		ret = mmc_select_hwpart(dfu->data.mmc.dev_num, part_num_bkp);
+		ret = blk_select_hwpart_devnum(IF_TYPE_MMC,
+					       dfu->data.mmc.dev_num,
+					       part_num_bkp);
 		if (ret)
 			return ret;
 	}
diff --git a/drivers/gpio/74x164_gpio.c b/drivers/gpio/74x164_gpio.c
new file mode 100644
index 0000000..9ac10a7
--- /dev/null
+++ b/drivers/gpio/74x164_gpio.c
@@ -0,0 +1,193 @@
+/*
+ * Take drivers/gpio/gpio-74x164.c as reference.
+ *
+ * 74Hx164 - Generic serial-in/parallel-out 8-bits shift register GPIO driver
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <spi.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct gen_74x164_chip - Data for 74Hx164
+ *
+ * @oe: OE pin
+ * @nregs: number of registers
+ * @buffer: buffer for chained chips
+ */
+#define GEN_74X164_NUMBER_GPIOS 8
+
+struct gen_74x164_priv {
+	struct gpio_desc oe;
+	u32 nregs;
+	/*
+	 * Since the nregs are chained, every byte sent will make
+	 * the previous byte shift to the next register in the
+	 * chain. Thus, the first byte sent will end up in the last
+	 * register at the end of the transfer. So, to have a logical
+	 * numbering, store the bytes in reverse order.
+	 */
+	u8 *buffer;
+};
+
+static int gen_74x164_write_conf(struct udevice *dev)
+{
+	struct gen_74x164_priv *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = dm_spi_claim_bus(dev);
+	if (ret)
+		return ret;
+
+	ret = dm_spi_xfer(dev, priv->nregs * 8, priv->buffer, NULL,
+			  SPI_XFER_BEGIN | SPI_XFER_END);
+
+	dm_spi_release_bus(dev);
+
+	return ret;
+}
+
+static int gen_74x164_get_value(struct udevice *dev, unsigned offset)
+{
+	struct gen_74x164_priv *priv = dev_get_priv(dev);
+	uint bank = priv->nregs - 1 - offset / 8;
+	uint pin = offset % 8;
+
+	return (priv->buffer[bank] >> pin) & 0x1;
+}
+
+static int gen_74x164_set_value(struct udevice *dev, unsigned offset,
+				int value)
+{
+	struct gen_74x164_priv *priv = dev_get_priv(dev);
+	uint bank = priv->nregs - 1 - offset / 8;
+	uint pin = offset % 8;
+	int ret;
+
+	if (value)
+		priv->buffer[bank] |= 1 << pin;
+	else
+		priv->buffer[bank] &= ~(1 << pin);
+
+	ret = gen_74x164_write_conf(dev);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int gen_74x164_direction_input(struct udevice *dev, unsigned offset)
+{
+	return -ENOSYS;
+}
+
+static int gen_74x164_direction_output(struct udevice *dev, unsigned offset,
+				      int value)
+{
+	return gen_74x164_set_value(dev, offset, value);
+}
+
+static int gen_74x164_get_function(struct udevice *dev, unsigned offset)
+{
+	return GPIOF_OUTPUT;
+}
+
+static int gen_74x164_xlate(struct udevice *dev, struct gpio_desc *desc,
+			    struct fdtdec_phandle_args *args)
+{
+	desc->offset = args->args[0];
+	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops gen_74x164_ops = {
+	.direction_input	= gen_74x164_direction_input,
+	.direction_output	= gen_74x164_direction_output,
+	.get_value		= gen_74x164_get_value,
+	.set_value		= gen_74x164_set_value,
+	.get_function		= gen_74x164_get_function,
+	.xlate			= gen_74x164_xlate,
+};
+
+static int gen_74x164_probe(struct udevice *dev)
+{
+	struct gen_74x164_priv *priv = dev_get_priv(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	char *str, name[32];
+	int ret;
+	const void *fdt = gd->fdt_blob;
+	int node = dev->of_offset;
+
+	snprintf(name, sizeof(name), "%s_", dev->name);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+
+	/*
+	 * See Linux kernel:
+	 * Documentation/devicetree/bindings/gpio/gpio-74x164.txt
+	 */
+	priv->nregs = fdtdec_get_int(fdt, node, "registers-number", 1);
+	priv->buffer = calloc(priv->nregs, sizeof(u8));
+	if (!priv->buffer) {
+		ret = -ENOMEM;
+		goto free_str;
+	}
+
+	ret = fdtdec_get_byte_array(fdt, node, "registers-default",
+				    priv->buffer, priv->nregs);
+	if (ret)
+		dev_dbg(dev, "No registers-default property\n");
+
+	ret = gpio_request_by_name(dev, "oe-gpios", 0, &priv->oe,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret) {
+		dev_err(dev, "No oe-pins property\n");
+		goto free_buf;
+	}
+
+	uc_priv->bank_name = str;
+	uc_priv->gpio_count = priv->nregs * 8;
+
+	ret = gen_74x164_write_conf(dev);
+	if (ret)
+		goto free_buf;
+
+	dev_dbg(dev, "%s is ready\n", dev->name);
+
+	return 0;
+
+free_buf:
+	free(priv->buffer);
+free_str:
+	free(str);
+	return ret;
+}
+
+static const struct udevice_id gen_74x164_ids[] = {
+	{ .compatible = "fairchild,74hc595" },
+	{ }
+};
+
+U_BOOT_DRIVER(74x164) = {
+	.name		= "74x164",
+	.id		= UCLASS_GPIO,
+	.ops		= &gen_74x164_ops,
+	.probe		= gen_74x164_probe,
+	.priv_auto_alloc_size = sizeof(struct gen_74x164_priv),
+	.of_match	= gen_74x164_ids,
+};
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 2b4624d..93a7e8c 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -143,4 +143,34 @@
 	help
 	  Supports GPIO access on Zynq SoC.
 
+config DM_74X164
+	bool "74x164 serial-in/parallel-out 8-bits shift register"
+	depends on DM_GPIO
+	help
+	  Driver for 74x164 compatible serial-in/parallel-out 8-outputs
+	  shift registers, such as 74lv165, 74hc595.
+	  This driver can be used to provide access to more gpio outputs.
+
+config DM_PCA953X
+	bool "PCA95[357]x, PCA9698, TCA64xx, and MAX7310 I/O ports"
+	depends on DM_GPIO
+	help
+	  Say yes here to provide access to several register-oriented
+	  SMBus I/O expanders, made mostly by NXP or TI.  Compatible
+	  models include:
+
+	  4 bits:	pca9536, pca9537
+
+	  8 bits:	max7310, max7315, pca6107, pca9534, pca9538, pca9554,
+			pca9556, pca9557, pca9574, tca6408, xra1202
+
+	  16 bits:	max7312, max7313, pca9535, pca9539, pca9555, pca9575,
+			tca6416
+
+	  24 bits:	tca6424
+
+	  40 bits:	pca9505, pca9698
+
+	  Now, max 24 bits chips and PCA953X compatible chips are
+	  supported
 endmenu
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 4f071c4..ddec1ef 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -11,6 +11,9 @@
 endif
 obj-$(CONFIG_DM_GPIO)		+= gpio-uclass.o
 
+obj-$(CONFIG_DM_PCA953X)	+= pca953x_gpio.o
+obj-$(CONFIG_DM_74X164)		+= 74x164_gpio.o
+
 obj-$(CONFIG_AT91_GPIO)	+= at91_gpio.o
 obj-$(CONFIG_ATMEL_PIO4)	+= atmel_pio4.o
 obj-$(CONFIG_INTEL_ICH6_GPIO)	+= intel_ich6_gpio.o
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index b58d4e6..732b6c2 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <dt-bindings/gpio/gpio.h>
 #include <errno.h>
 #include <fdtdec.h>
 #include <malloc.h>
@@ -113,19 +114,33 @@
 	return 0;
 }
 
+int gpio_xlate_offs_flags(struct udevice *dev,
+					 struct gpio_desc *desc,
+					 struct fdtdec_phandle_args *args)
+{
+	if (args->args_count < 1)
+		return -EINVAL;
+
+	desc->offset = args->args[0];
+
+	if (args->args_count < 2)
+		return 0;
+
+	if (args->args[1] & GPIO_ACTIVE_LOW)
+		desc->flags = GPIOD_ACTIVE_LOW;
+
+	return 0;
+}
+
 static int gpio_find_and_xlate(struct gpio_desc *desc,
 			       struct fdtdec_phandle_args *args)
 {
 	struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
 
-	/* Use the first argument as the offset by default */
-	if (args->args_count > 0)
-		desc->offset = args->args[0];
+	if (ops->xlate)
+		return ops->xlate(desc->dev, desc, args);
 	else
-		desc->offset = -1;
-	desc->flags = 0;
-
-	return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
+		return gpio_xlate_offs_flags(desc->dev, desc, args);
 }
 
 int dm_gpio_request(struct gpio_desc *desc, const char *label)
@@ -605,6 +620,7 @@
 
 	desc->dev = NULL;
 	desc->offset = 0;
+	desc->flags = 0;
 	ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
 					     "#gpio-cells", 0, index, &args);
 	if (ret) {
diff --git a/drivers/gpio/intel_broadwell_gpio.c b/drivers/gpio/intel_broadwell_gpio.c
index 8cf76f9..81ce446 100644
--- a/drivers/gpio/intel_broadwell_gpio.c
+++ b/drivers/gpio/intel_broadwell_gpio.c
@@ -162,15 +162,6 @@
 	return 0;
 }
 
-static int broadwell_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
-				struct fdtdec_phandle_args *args)
-{
-	desc->offset = args->args[0];
-	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
-	return 0;
-}
-
 static const struct dm_gpio_ops gpio_broadwell_ops = {
 	.request		= broadwell_gpio_request,
 	.direction_input	= broadwell_gpio_direction_input,
@@ -178,7 +169,6 @@
 	.get_value		= broadwell_gpio_get_value,
 	.set_value		= broadwell_gpio_set_value,
 	.get_function		= broadwell_gpio_get_function,
-	.xlate			= broadwell_gpio_xlate,
 };
 
 static const struct udevice_id intel_broadwell_gpio_ids[] = {
diff --git a/drivers/gpio/omap_gpio.c b/drivers/gpio/omap_gpio.c
index 93d18e4..cd960dc 100644
--- a/drivers/gpio/omap_gpio.c
+++ b/drivers/gpio/omap_gpio.c
@@ -25,7 +25,6 @@
 #include <asm/io.h>
 #include <asm/errno.h>
 #include <malloc.h>
-#include <dt-bindings/gpio/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -277,22 +276,12 @@
 		return GPIOF_INPUT;
 }
 
-static int omap_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
-			   struct fdtdec_phandle_args *args)
-{
-	desc->offset = args->args[0];
-	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
-	return 0;
-}
-
 static const struct dm_gpio_ops gpio_omap_ops = {
 	.direction_input	= omap_gpio_direction_input,
 	.direction_output	= omap_gpio_direction_output,
 	.get_value		= omap_gpio_get_value,
 	.set_value		= omap_gpio_set_value,
 	.get_function		= omap_gpio_get_function,
-	.xlate			= omap_gpio_xlate,
 };
 
 static int omap_gpio_probe(struct udevice *dev)
diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c
new file mode 100644
index 0000000..987d10e
--- /dev/null
+++ b/drivers/gpio/pca953x_gpio.c
@@ -0,0 +1,351 @@
+/*
+ * Take linux kernel driver drivers/gpio/gpio-pca953x.c for reference.
+ *
+ * Copyright (C) 2016 Peng Fan <van.freenix@gmail.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ *
+ */
+
+/*
+ * Note:
+ * The driver's compatible table is borrowed from Linux Kernel,
+ * but now max supported gpio pins is 24 and only PCA953X_TYPE
+ * is supported. PCA957X_TYPE is not supported now.
+ * Also the Polarity Inversion feature is not supported now.
+ *
+ * TODO:
+ * 1. Support PCA957X_TYPE
+ * 2. Support max 40 gpio pins
+ * 3. Support Plolarity Inversion
+ */
+
+#include <common.h>
+#include <errno.h>
+#include <dm.h>
+#include <fdtdec.h>
+#include <i2c.h>
+#include <malloc.h>
+#include <asm/gpio.h>
+#include <asm/io.h>
+#include <dt-bindings/gpio/gpio.h>
+
+#define PCA953X_INPUT           0
+#define PCA953X_OUTPUT          1
+#define PCA953X_INVERT          2
+#define PCA953X_DIRECTION       3
+
+#define PCA_GPIO_MASK           0x00FF
+#define PCA_INT                 0x0100
+#define PCA953X_TYPE            0x1000
+#define PCA957X_TYPE            0x2000
+#define PCA_TYPE_MASK           0xF000
+#define PCA_CHIP_TYPE(x)        ((x) & PCA_TYPE_MASK)
+
+enum {
+	PCA953X_DIRECTION_IN,
+	PCA953X_DIRECTION_OUT,
+};
+
+#define MAX_BANK 3
+#define BANK_SZ 8
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/*
+ * struct pca953x_info - Data for pca953x
+ *
+ * @dev: udevice structure for the device
+ * @addr: i2c slave address
+ * @invert: Polarity inversion or not
+ * @gpio_count: the number of gpio pins that the device supports
+ * @chip_type: indicate the chip type,PCA953X or PCA957X
+ * @bank_count: the number of banks that the device supports
+ * @reg_output: array to hold the value of output registers
+ * @reg_direction: array to hold the value of direction registers
+ */
+struct pca953x_info {
+	struct udevice *dev;
+	int addr;
+	int invert;
+	int gpio_count;
+	int chip_type;
+	int bank_count;
+	u8 reg_output[MAX_BANK];
+	u8 reg_direction[MAX_BANK];
+};
+
+static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
+				int offset)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+	int off = offset / BANK_SZ;
+	int ret = 0;
+
+	ret = dm_i2c_write(dev, (reg << bank_shift) + off, &val, 1);
+	if (ret) {
+		dev_err(dev, "%s error\n", __func__);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int pca953x_read_single(struct udevice *dev, int reg, u8 *val,
+			       int offset)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	int bank_shift = fls((info->gpio_count - 1) / BANK_SZ);
+	int off = offset / BANK_SZ;
+	int ret;
+	u8 byte;
+
+	ret = dm_i2c_read(dev, (reg << bank_shift) + off, &byte, 1);
+	if (ret) {
+		dev_err(dev, "%s error\n", __func__);
+		return ret;
+	}
+
+	*val = byte;
+
+	return 0;
+}
+
+static int pca953x_read_regs(struct udevice *dev, int reg, u8 *val)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	int ret = 0;
+
+	if (info->gpio_count <= 8) {
+		ret = dm_i2c_read(dev, reg, val, 1);
+	} else if (info->gpio_count <= 16) {
+		ret = dm_i2c_read(dev, reg << 1, val, info->bank_count);
+	} else {
+		dev_err(dev, "Unsupported now\n");
+		return -EINVAL;
+	}
+
+	return ret;
+}
+
+static int pca953x_is_output(struct udevice *dev, int offset)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+
+	int bank = offset / BANK_SZ;
+	int off = offset % BANK_SZ;
+
+	/*0: output; 1: input */
+	return !(info->reg_direction[bank] & (1 << off));
+}
+
+static int pca953x_get_value(struct udevice *dev, unsigned offset)
+{
+	int ret;
+	u8 val = 0;
+
+	ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset);
+	if (ret)
+		return ret;
+
+	return (val >> offset) & 0x1;
+}
+
+static int pca953x_set_value(struct udevice *dev, unsigned offset,
+			     int value)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	int bank = offset / BANK_SZ;
+	int off = offset % BANK_SZ;
+	u8 val;
+	int ret;
+
+	if (value)
+		val = info->reg_output[bank] | (1 << off);
+	else
+		val = info->reg_output[bank] & ~(1 << off);
+
+	ret = pca953x_write_single(dev, PCA953X_OUTPUT, val, offset);
+	if (ret)
+		return ret;
+
+	info->reg_output[bank] = val;
+
+	return 0;
+}
+
+static int pca953x_set_direction(struct udevice *dev, unsigned offset, int dir)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	int bank = offset / BANK_SZ;
+	int off = offset % BANK_SZ;
+	u8 val;
+	int ret;
+
+	if (dir == PCA953X_DIRECTION_IN)
+		val = info->reg_direction[bank] | (1 << off);
+	else
+		val = info->reg_direction[bank] & ~(1 << off);
+
+	ret = pca953x_write_single(dev, PCA953X_DIRECTION, val, offset);
+	if (ret)
+		return ret;
+
+	info->reg_direction[bank] = val;
+
+	return 0;
+}
+
+static int pca953x_direction_input(struct udevice *dev, unsigned offset)
+{
+	return pca953x_set_direction(dev, offset, PCA953X_DIRECTION_IN);
+}
+
+static int pca953x_direction_output(struct udevice *dev, unsigned offset,
+				    int value)
+{
+	/* Configure output value. */
+	pca953x_set_value(dev, offset, value);
+
+	/* Configure direction as output. */
+	pca953x_set_direction(dev, offset, PCA953X_DIRECTION_OUT);
+
+	return 0;
+}
+
+static int pca953x_get_function(struct udevice *dev, unsigned offset)
+{
+	if (pca953x_is_output(dev, offset))
+		return GPIOF_OUTPUT;
+	else
+		return GPIOF_INPUT;
+}
+
+static int pca953x_xlate(struct udevice *dev, struct gpio_desc *desc,
+			 struct fdtdec_phandle_args *args)
+{
+	desc->offset = args->args[0];
+	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+	return 0;
+}
+
+static const struct dm_gpio_ops pca953x_ops = {
+	.direction_input	= pca953x_direction_input,
+	.direction_output	= pca953x_direction_output,
+	.get_value		= pca953x_get_value,
+	.set_value		= pca953x_set_value,
+	.get_function		= pca953x_get_function,
+	.xlate			= pca953x_xlate,
+};
+
+static int pca953x_probe(struct udevice *dev)
+{
+	struct pca953x_info *info = dev_get_platdata(dev);
+	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
+	char name[32], *str;
+	int addr;
+	ulong driver_data;
+	int ret;
+
+	if (!info) {
+		dev_err(dev, "platdata not ready\n");
+		return -ENOMEM;
+	}
+
+	if (!chip) {
+		dev_err(dev, "i2c not ready\n");
+		return -ENODEV;
+	}
+
+	addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", 0);
+	if (addr == 0)
+		return -ENODEV;
+
+	info->addr = addr;
+
+	driver_data = dev_get_driver_data(dev);
+
+	info->gpio_count = driver_data & PCA_GPIO_MASK;
+	if (info->gpio_count > MAX_BANK * BANK_SZ) {
+		dev_err(dev, "Max support %d pins now\n", MAX_BANK * BANK_SZ);
+		return -EINVAL;
+	}
+
+	info->chip_type = PCA_CHIP_TYPE(driver_data);
+	if (info->chip_type != PCA953X_TYPE) {
+		dev_err(dev, "Only support PCA953X chip type now.\n");
+		return -EINVAL;
+	}
+
+	info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
+
+	ret = pca953x_read_regs(dev, PCA953X_OUTPUT, info->reg_output);
+	if (ret) {
+		dev_err(dev, "Error reading output register\n");
+		return ret;
+	}
+
+	ret = pca953x_read_regs(dev, PCA953X_DIRECTION, info->reg_direction);
+	if (ret) {
+		dev_err(dev, "Error reading direction register\n");
+		return ret;
+	}
+
+	snprintf(name, sizeof(name), "gpio@%x_", info->addr);
+	str = strdup(name);
+	if (!str)
+		return -ENOMEM;
+	uc_priv->bank_name = str;
+	uc_priv->gpio_count = info->gpio_count;
+
+	dev_dbg(dev, "%s is ready\n", str);
+
+	return 0;
+}
+
+#define OF_953X(__nrgpio, __int) (ulong)(__nrgpio | PCA953X_TYPE | __int)
+#define OF_957X(__nrgpio, __int) (ulong)(__nrgpio | PCA957X_TYPE | __int)
+
+static const struct udevice_id pca953x_ids[] = {
+	{ .compatible = "nxp,pca9505", .data = OF_953X(40, PCA_INT), },
+	{ .compatible = "nxp,pca9534", .data = OF_953X(8, PCA_INT), },
+	{ .compatible = "nxp,pca9535", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9536", .data = OF_953X(4, 0), },
+	{ .compatible = "nxp,pca9537", .data = OF_953X(4, PCA_INT), },
+	{ .compatible = "nxp,pca9538", .data = OF_953X(8, PCA_INT), },
+	{ .compatible = "nxp,pca9539", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9554", .data = OF_953X(8, PCA_INT), },
+	{ .compatible = "nxp,pca9555", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9556", .data = OF_953X(8, 0), },
+	{ .compatible = "nxp,pca9557", .data = OF_953X(8, 0), },
+	{ .compatible = "nxp,pca9574", .data = OF_957X(8, PCA_INT), },
+	{ .compatible = "nxp,pca9575", .data = OF_957X(16, PCA_INT), },
+	{ .compatible = "nxp,pca9698", .data = OF_953X(40, 0), },
+
+	{ .compatible = "maxim,max7310", .data = OF_953X(8, 0), },
+	{ .compatible = "maxim,max7312", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "maxim,max7313", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "maxim,max7315", .data = OF_953X(8, PCA_INT), },
+
+	{ .compatible = "ti,pca6107", .data = OF_953X(8, PCA_INT), },
+	{ .compatible = "ti,tca6408", .data = OF_953X(8, PCA_INT), },
+	{ .compatible = "ti,tca6416", .data = OF_953X(16, PCA_INT), },
+	{ .compatible = "ti,tca6424", .data = OF_953X(24, PCA_INT), },
+
+	{ .compatible = "onsemi,pca9654", .data = OF_953X(8, PCA_INT), },
+
+	{ .compatible = "exar,xra1202", .data = OF_953X(8, 0), },
+	{ }
+};
+
+U_BOOT_DRIVER(pca953x) = {
+	.name		= "pca953x",
+	.id		= UCLASS_GPIO,
+	.ops		= &pca953x_ops,
+	.probe		= pca953x_probe,
+	.platdata_auto_alloc_size = sizeof(struct pca953x_info),
+	.of_match	= pca953x_ids,
+};
diff --git a/drivers/gpio/pic32_gpio.c b/drivers/gpio/pic32_gpio.c
index 499b4fa..7a037f3 100644
--- a/drivers/gpio/pic32_gpio.c
+++ b/drivers/gpio/pic32_gpio.c
@@ -12,7 +12,6 @@
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <linux/compat.h>
-#include <dt-bindings/gpio/gpio.h>
 #include <mach/pic32.h>
 
 DECLARE_GLOBAL_DATA_PTR;
@@ -99,14 +98,6 @@
 	return 0;
 }
 
-static int pic32_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
-			    struct fdtdec_phandle_args *args)
-{
-	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
-	return 0;
-}
-
 static int pic32_gpio_get_function(struct udevice *dev, unsigned offset)
 {
 	int ret = GPIOF_UNUSED;
@@ -131,7 +122,6 @@
 	.get_value		= pic32_gpio_get_value,
 	.set_value		= pic32_gpio_set_value,
 	.get_function		= pic32_gpio_get_function,
-	.xlate			= pic32_gpio_xlate,
 };
 
 static int pic32_gpio_probe(struct udevice *dev)
diff --git a/drivers/gpio/rk_gpio.c b/drivers/gpio/rk_gpio.c
index 40e87bd..fefe3ca 100644
--- a/drivers/gpio/rk_gpio.c
+++ b/drivers/gpio/rk_gpio.c
@@ -16,7 +16,6 @@
 #include <asm/io.h>
 #include <asm/arch/clock.h>
 #include <dm/pinctrl.h>
-#include <dt-bindings/gpio/gpio.h>
 #include <dt-bindings/clock/rk3288-cru.h>
 
 enum {
@@ -98,15 +97,6 @@
 #endif
 }
 
-static int rockchip_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
-			    struct fdtdec_phandle_args *args)
-{
-	desc->offset = args->args[0];
-	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
-	return 0;
-}
-
 static int rockchip_gpio_probe(struct udevice *dev)
 {
 	struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
@@ -135,7 +125,6 @@
 	.get_value		= rockchip_gpio_get_value,
 	.set_value		= rockchip_gpio_set_value,
 	.get_function		= rockchip_gpio_get_function,
-	.xlate			= rockchip_gpio_xlate,
 };
 
 static const struct udevice_id rockchip_gpio_ids[] = {
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 0f22b23..377fed4 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -13,7 +13,6 @@
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <dm/device-internal.h>
-#include <dt-bindings/gpio/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -276,22 +275,12 @@
 		return GPIOF_FUNC;
 }
 
-static int exynos_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
-			     struct fdtdec_phandle_args *args)
-{
-	desc->offset = args->args[0];
-	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
-
-	return 0;
-}
-
 static const struct dm_gpio_ops gpio_exynos_ops = {
 	.direction_input	= exynos_gpio_direction_input,
 	.direction_output	= exynos_gpio_direction_output,
 	.get_value		= exynos_gpio_get_value,
 	.set_value		= exynos_gpio_set_value,
 	.get_function		= exynos_gpio_get_function,
-	.xlate			= exynos_gpio_xlate,
 };
 
 static int gpio_exynos_probe(struct udevice *dev)
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 9324c6c..6e22bba 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -58,6 +58,13 @@
 	  bindings are supported.
 	  Binding info: doc/device-tree-bindings/i2c/i2c-gpio.txt
 
+config SYS_I2C_FSL
+       bool "Freescale I2C bus driver"
+       depends on DM_I2C
+       help
+	  Add support for Freescale I2C busses as used on MPC8240, MPC8245, and
+	  MPC85xx processors.
+
 config SYS_I2C_CADENCE
 	tristate "Cadence I2C Controller"
 	depends on DM_I2C && (ARCH_ZYNQ || ARM64)
@@ -65,6 +72,24 @@
 	  Say yes here to select Cadence I2C Host Controller. This controller is
 	  e.g. used by Xilinx Zynq.
 
+config SYS_I2C_DW
+	bool "Designware I2C Controller"
+	default n
+	help
+	  Say yes here to select the Designware I2C Host Controller. This
+	  controller is used in various SoCs, e.g. the ST SPEAr, Altera
+	  SoCFPGA, Synopsys ARC700 and some Intel x86 SoCs.
+
+config SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
+	bool "DW I2C Enable Status Register not supported"
+	depends on SYS_I2C_DW && (TARGET_SPEAR300 || TARGET_SPEAR310 || \
+		TARGET_SPEAR320 || TARGET_SPEAR600 || TARGET_X600)
+	default y
+	help
+	  Some versions of the Designware I2C controller do not support the
+	  enable status register. This config option can be enabled in such
+	  cases.
+
 config SYS_I2C_INTEL
 	bool "Intel I2C/SMBUS driver"
 	depends on DM_I2C
diff --git a/drivers/i2c/designware_i2c.c b/drivers/i2c/designware_i2c.c
index 0c7cd0b..e60fd0a 100644
--- a/drivers/i2c/designware_i2c.c
+++ b/drivers/i2c/designware_i2c.c
@@ -36,6 +36,14 @@
 	struct dw_scl_sda_cfg *scl_sda_cfg;
 };
 
+#ifdef CONFIG_SYS_I2C_DW_ENABLE_STATUS_UNSUPPORTED
+static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
+{
+	u32 ena = enable ? IC_ENABLE_0B : 0;
+
+	writel(ena, &i2c_base->ic_enable);
+}
+#else
 static void dw_i2c_enable(struct i2c_regs *i2c_base, bool enable)
 {
 	u32 ena = enable ? IC_ENABLE_0B : 0;
@@ -56,6 +64,7 @@
 
 	printf("timeout in %sabling I2C adapter\n", enable ? "en" : "dis");
 }
+#endif
 
 /*
  * i2c_set_bus_speed - Set the i2c speed
diff --git a/drivers/i2c/fsl_i2c.c b/drivers/i2c/fsl_i2c.c
index b56a1c2..b8cc647 100644
--- a/drivers/i2c/fsl_i2c.c
+++ b/drivers/i2c/fsl_i2c.c
@@ -12,6 +12,8 @@
 #include <i2c.h>		/* Functional interface */
 #include <asm/io.h>
 #include <asm/fsl_i2c.h>	/* HW definitions */
+#include <dm.h>
+#include <mapmem.h>
 
 /* The maximum number of microseconds we will wait until another master has
  * released the bus.  If not defined in the board header file, then use a
@@ -34,18 +36,20 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static const struct fsl_i2c *i2c_dev[4] = {
-	(struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
+#ifndef CONFIG_DM_I2C
+static const struct fsl_i2c_base *i2c_base[4] = {
+	(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C_OFFSET),
 #ifdef CONFIG_SYS_FSL_I2C2_OFFSET
-	(struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET),
+	(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C2_OFFSET),
 #endif
 #ifdef CONFIG_SYS_FSL_I2C3_OFFSET
-	(struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C3_OFFSET),
+	(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C3_OFFSET),
 #endif
 #ifdef CONFIG_SYS_FSL_I2C4_OFFSET
-	(struct fsl_i2c *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C4_OFFSET)
+	(struct fsl_i2c_base *)(CONFIG_SYS_IMMR + CONFIG_SYS_FSL_I2C4_OFFSET)
 #endif
 };
+#endif
 
 /* I2C speed map for a DFSR value of 1 */
 
@@ -104,7 +108,7 @@
 /**
  * Set the I2C bus speed for a given I2C device
  *
- * @param dev: the I2C device
+ * @param base: the I2C device registers
  * @i2c_clk: I2C bus clock frequency
  * @speed: the desired speed of the bus
  *
@@ -112,7 +116,7 @@
  *
  * The return value is the actual bus speed that is set.
  */
-static unsigned int set_i2c_bus_speed(const struct fsl_i2c *dev,
+static unsigned int set_i2c_bus_speed(const struct fsl_i2c_base *base,
 	unsigned int i2c_clk, unsigned int speed)
 {
 	unsigned short divider = min(i2c_clk / speed, (unsigned int)USHRT_MAX);
@@ -173,8 +177,8 @@
 	debug("divider:%d, est_div:%ld, DFSR:%d\n", divider, est_div, dfsr);
 	debug("FDR:0x%.2x, speed:%d\n", fdr, speed);
 #endif
-	writeb(dfsr, &dev->dfsrr);	/* set default filter */
-	writeb(fdr, &dev->fdr);		/* set bus speed */
+	writeb(dfsr, &base->dfsrr);	/* set default filter */
+	writeb(fdr, &base->fdr);	/* set bus speed */
 #else
 	unsigned int i;
 
@@ -184,7 +188,7 @@
 
 			fdr = fsl_i2c_speed_map[i].fdr;
 			speed = i2c_clk / fsl_i2c_speed_map[i].divider;
-			writeb(fdr, &dev->fdr);		/* set bus speed */
+			writeb(fdr, &base->fdr);	/* set bus speed */
 
 			break;
 		}
@@ -192,6 +196,7 @@
 	return speed;
 }
 
+#ifndef CONFIG_DM_I2C
 static unsigned int get_i2c_clock(int bus)
 {
 	if (bus)
@@ -199,8 +204,9 @@
 	else
 		return gd->arch.i2c1_clk;	/* I2C1 clock */
 }
+#endif
 
-static int fsl_i2c_fixup(const struct fsl_i2c *dev)
+static int fsl_i2c_fixup(const struct fsl_i2c_base *base)
 {
 	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
 	unsigned long long timeval = 0;
@@ -214,42 +220,42 @@
 		flags = I2C_CR_BIT6;
 #endif
 
-	writeb(I2C_CR_MEN | I2C_CR_MSTA, &dev->cr);
+	writeb(I2C_CR_MEN | I2C_CR_MSTA, &base->cr);
 
 	timeval = get_ticks();
-	while (!(readb(&dev->sr) & I2C_SR_MBB)) {
+	while (!(readb(&base->sr) & I2C_SR_MBB)) {
 		if ((get_ticks() - timeval) > timeout)
 			goto err;
 	}
 
-	if (readb(&dev->sr) & I2C_SR_MAL) {
+	if (readb(&base->sr) & I2C_SR_MAL) {
 		/* SDA is stuck low */
-		writeb(0, &dev->cr);
+		writeb(0, &base->cr);
 		udelay(100);
-		writeb(I2C_CR_MSTA | flags, &dev->cr);
-		writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &dev->cr);
+		writeb(I2C_CR_MSTA | flags, &base->cr);
+		writeb(I2C_CR_MEN | I2C_CR_MSTA | flags, &base->cr);
 	}
 
-	readb(&dev->dr);
+	readb(&base->dr);
 
 	timeval = get_ticks();
-	while (!(readb(&dev->sr) & I2C_SR_MIF)) {
+	while (!(readb(&base->sr) & I2C_SR_MIF)) {
 		if ((get_ticks() - timeval) > timeout)
 			goto err;
 	}
 	ret = 0;
 
 err:
-	writeb(I2C_CR_MEN | flags, &dev->cr);
-	writeb(0, &dev->sr);
+	writeb(I2C_CR_MEN | flags, &base->cr);
+	writeb(0, &base->sr);
 	udelay(100);
 
 	return ret;
 }
 
-static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+static void __i2c_init(const struct fsl_i2c_base *base, int speed, int
+		       slaveadd, int i2c_clk, int busnum)
 {
-	const struct fsl_i2c *dev;
 	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
 	unsigned long long timeval;
 
@@ -260,23 +266,21 @@
 	*/
 	i2c_init_board();
 #endif
-	dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
-
-	writeb(0, &dev->cr);		/* stop I2C controller */
+	writeb(0, &base->cr);		/* stop I2C controller */
 	udelay(5);			/* let it shutdown in peace */
-	set_i2c_bus_speed(dev, get_i2c_clock(adap->hwadapnr), speed);
-	writeb(slaveadd << 1, &dev->adr);/* write slave address */
-	writeb(0x0, &dev->sr);		/* clear status register */
-	writeb(I2C_CR_MEN, &dev->cr);	/* start I2C controller */
+	set_i2c_bus_speed(base, i2c_clk, speed);
+	writeb(slaveadd << 1, &base->adr);/* write slave address */
+	writeb(0x0, &base->sr);		/* clear status register */
+	writeb(I2C_CR_MEN, &base->cr);	/* start I2C controller */
 
 	timeval = get_ticks();
-	while (readb(&dev->sr) & I2C_SR_MBB) {
+	while (readb(&base->sr) & I2C_SR_MBB) {
 		if ((get_ticks() - timeval) < timeout)
 			continue;
 
-		if (fsl_i2c_fixup(dev))
+		if (fsl_i2c_fixup(base))
 			debug("i2c_init: BUS#%d failed to init\n",
-			      adap->hwadapnr);
+			      busnum);
 
 		break;
 	}
@@ -292,13 +296,12 @@
 }
 
 static int
-i2c_wait4bus(struct i2c_adapter *adap)
+i2c_wait4bus(const struct fsl_i2c_base *base)
 {
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
 	unsigned long long timeval = get_ticks();
 	const unsigned long long timeout = usec2ticks(CONFIG_I2C_MBB_TIMEOUT);
 
-	while (readb(&dev->sr) & I2C_SR_MBB) {
+	while (readb(&base->sr) & I2C_SR_MBB) {
 		if ((get_ticks() - timeval) > timeout)
 			return -1;
 	}
@@ -306,22 +309,21 @@
 	return 0;
 }
 
-static __inline__ int
-i2c_wait(struct i2c_adapter *adap, int write)
+static inline int
+i2c_wait(const struct fsl_i2c_base *base, int write)
 {
 	u32 csr;
 	unsigned long long timeval = get_ticks();
 	const unsigned long long timeout = usec2ticks(CONFIG_I2C_TIMEOUT);
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
 
 	do {
-		csr = readb(&dev->sr);
+		csr = readb(&base->sr);
 		if (!(csr & I2C_SR_MIF))
 			continue;
 		/* Read again to allow register to stabilise */
-		csr = readb(&dev->sr);
+		csr = readb(&base->sr);
 
-		writeb(0x0, &dev->sr);
+		writeb(0x0, &base->sr);
 
 		if (csr & I2C_SR_MAL) {
 			debug("i2c_wait: MAL\n");
@@ -345,203 +347,318 @@
 	return -1;
 }
 
-static __inline__ int
-i2c_write_addr(struct i2c_adapter *adap, u8 dev, u8 dir, int rsta)
+static inline int
+i2c_write_addr(const struct fsl_i2c_base *base, u8 dev, u8 dir, int rsta)
 {
-	struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
-
 	writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX
 	       | (rsta ? I2C_CR_RSTA : 0),
-	       &device->cr);
+	       &base->cr);
 
-	writeb((dev << 1) | dir, &device->dr);
+	writeb((dev << 1) | dir, &base->dr);
 
-	if (i2c_wait(adap, I2C_WRITE_BIT) < 0)
+	if (i2c_wait(base, I2C_WRITE_BIT) < 0)
 		return 0;
 
 	return 1;
 }
 
-static __inline__ int
-__i2c_write(struct i2c_adapter *adap, u8 *data, int length)
+static inline int
+__i2c_write_data(const struct fsl_i2c_base *base, u8 *data, int length)
 {
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
 	int i;
 
 	for (i = 0; i < length; i++) {
-		writeb(data[i], &dev->dr);
+		writeb(data[i], &base->dr);
 
-		if (i2c_wait(adap, I2C_WRITE_BIT) < 0)
+		if (i2c_wait(base, I2C_WRITE_BIT) < 0)
 			break;
 	}
 
 	return i;
 }
 
-static __inline__ int
-__i2c_read(struct i2c_adapter *adap, u8 *data, int length)
+static inline int
+__i2c_read_data(const struct fsl_i2c_base *base, u8 *data, int length)
 {
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
 	int i;
 
 	writeb(I2C_CR_MEN | I2C_CR_MSTA | ((length == 1) ? I2C_CR_TXAK : 0),
-	       &dev->cr);
+	       &base->cr);
 
 	/* dummy read */
-	readb(&dev->dr);
+	readb(&base->dr);
 
 	for (i = 0; i < length; i++) {
-		if (i2c_wait(adap, I2C_READ_BIT) < 0)
+		if (i2c_wait(base, I2C_READ_BIT) < 0)
 			break;
 
 		/* Generate ack on last next to last byte */
 		if (i == length - 2)
 			writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_TXAK,
-			       &dev->cr);
+			       &base->cr);
 
 		/* Do not generate stop on last byte */
 		if (i == length - 1)
 			writeb(I2C_CR_MEN | I2C_CR_MSTA | I2C_CR_MTX,
-			       &dev->cr);
+			       &base->cr);
 
-		data[i] = readb(&dev->dr);
+		data[i] = readb(&base->dr);
 	}
 
 	return i;
 }
 
 static int
-fsl_i2c_read(struct i2c_adapter *adap, u8 dev, uint addr, int alen, u8 *data,
-	     int length)
+__i2c_read(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset, int olen,
+	   u8 *data, int dlen)
 {
-	struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
-	int i = -1; /* signal error */
-	u8 *a = (u8*)&addr;
-	int len = alen * -1;
+	int ret = -1; /* signal error */
 
-	if (i2c_wait4bus(adap) < 0)
+	if (i2c_wait4bus(base) < 0)
 		return -1;
 
-	/* To handle the need of I2C devices that require to write few bytes
-	 * (more than 4 bytes of address as in the case of else part)
-	 * of data before reading, Negative equivalent of length(bytes to write)
-	 * is passed, but used the +ve part of len for writing data
+	/* Some drivers use offset lengths in excess of 4 bytes. These drivers
+	 * adhere to the following convention:
+	 * - the offset length is passed as negative (that is, the absolute
+	 *   value of olen is the actual offset length)
+	 * - the offset itself is passed in data, which is overwritten by the
+	 *   subsequent read operation
 	 */
-	if (alen < 0) {
-		/* Generate a START and send the Address and
-		 * the Tx Bytes to the slave.
-		 * "START: Address: Write bytes data[len]"
-		 * IF part supports writing any number of bytes in contrast
-		 * to the else part, which supports writing address offset
-		 * of upto 4 bytes only.
-		 * bytes that need to be written are passed in
-		 * "data", which will eventually keep the data READ,
-		 * after writing the len bytes out of it
-		 */
-		if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0)
-			i = __i2c_write(adap, data, len);
+	if (olen < 0) {
+		if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0)
+			ret = __i2c_write_data(base, data, -olen);
 
-		if (i != len)
+		if (ret != -olen)
 			return -1;
 
-		if (length && i2c_write_addr(adap, dev, I2C_READ_BIT, 1) != 0)
-			i = __i2c_read(adap, data, length);
+		if (dlen && i2c_write_addr(base, chip_addr,
+					   I2C_READ_BIT, 1) != 0)
+			ret = __i2c_read_data(base, data, dlen);
 	} else {
-		if ((!length || alen > 0) &&
-		    i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0  &&
-		    __i2c_write(adap, &a[4 - alen], alen) == alen)
-			i = 0; /* No error so far */
+		if ((!dlen || olen > 0) &&
+		    i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0  &&
+		    __i2c_write_data(base, offset, olen) == olen)
+			ret = 0; /* No error so far */
 
-		if (length &&
-		    i2c_write_addr(adap, dev, I2C_READ_BIT, alen ? 1 : 0) != 0)
-			i = __i2c_read(adap, data, length);
+		if (dlen && i2c_write_addr(base, chip_addr, I2C_READ_BIT,
+					   olen ? 1 : 0) != 0)
+			ret = __i2c_read_data(base, data, dlen);
 	}
 
-	writeb(I2C_CR_MEN, &device->cr);
+	writeb(I2C_CR_MEN, &base->cr);
 
-	if (i2c_wait4bus(adap)) /* Wait until STOP */
+	if (i2c_wait4bus(base)) /* Wait until STOP */
 		debug("i2c_read: wait4bus timed out\n");
 
-	if (i == length)
-	    return 0;
+	if (ret == dlen)
+		return 0;
 
 	return -1;
 }
 
 static int
-fsl_i2c_write(struct i2c_adapter *adap, u8 dev, uint addr, int alen,
-	      u8 *data, int length)
+__i2c_write(const struct fsl_i2c_base *base, u8 chip_addr, u8 *offset, int olen,
+	    u8 *data, int dlen)
 {
-	struct fsl_i2c *device = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
-	int i = -1; /* signal error */
-	u8 *a = (u8*)&addr;
+	int ret = -1; /* signal error */
 
-	if (i2c_wait4bus(adap) < 0)
+	if (i2c_wait4bus(base) < 0)
 		return -1;
 
-	if (i2c_write_addr(adap, dev, I2C_WRITE_BIT, 0) != 0 &&
-	    __i2c_write(adap, &a[4 - alen], alen) == alen) {
-		i = __i2c_write(adap, data, length);
+	if (i2c_write_addr(base, chip_addr, I2C_WRITE_BIT, 0) != 0 &&
+	    __i2c_write_data(base, offset, olen) == olen) {
+		ret = __i2c_write_data(base, data, dlen);
 	}
 
-	writeb(I2C_CR_MEN, &device->cr);
-	if (i2c_wait4bus(adap)) /* Wait until STOP */
+	writeb(I2C_CR_MEN, &base->cr);
+	if (i2c_wait4bus(base)) /* Wait until STOP */
 		debug("i2c_write: wait4bus timed out\n");
 
-	if (i == length)
-	    return 0;
+	if (ret == dlen)
+		return 0;
 
 	return -1;
 }
 
 static int
-fsl_i2c_probe(struct i2c_adapter *adap, uchar chip)
+__i2c_probe_chip(const struct fsl_i2c_base *base, uchar chip)
 {
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
 	/* For unknow reason the controller will ACK when
 	 * probing for a slave with the same address, so skip
 	 * it.
 	 */
-	if (chip == (readb(&dev->adr) >> 1))
+	if (chip == (readb(&base->adr) >> 1))
 		return -1;
 
-	return fsl_i2c_read(adap, chip, 0, 0, NULL, 0);
+	return __i2c_read(base, chip, 0, 0, NULL, 0);
+}
+
+static unsigned int __i2c_set_bus_speed(const struct fsl_i2c_base *base,
+			unsigned int speed, int i2c_clk)
+{
+	writeb(0, &base->cr);		/* stop controller */
+	set_i2c_bus_speed(base, i2c_clk, speed);
+	writeb(I2C_CR_MEN, &base->cr);	/* start controller */
+
+	return 0;
+}
+
+#ifndef CONFIG_DM_I2C
+static void fsl_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
+{
+	__i2c_init(i2c_base[adap->hwadapnr], speed, slaveadd,
+		   get_i2c_clock(adap->hwadapnr), adap->hwadapnr);
+}
+
+static int
+fsl_i2c_probe_chip(struct i2c_adapter *adap, uchar chip)
+{
+	return __i2c_probe_chip(i2c_base[adap->hwadapnr], chip);
+}
+
+static int
+fsl_i2c_read(struct i2c_adapter *adap, u8 chip_addr, uint offset, int olen,
+	     u8 *data, int dlen)
+{
+	u8 *o = (u8 *)&offset;
+	return __i2c_read(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
+			  olen, data, dlen);
+}
+
+static int
+fsl_i2c_write(struct i2c_adapter *adap, u8 chip_addr, uint offset, int olen,
+	      u8 *data, int dlen)
+{
+	u8 *o = (u8 *)&offset;
+	return __i2c_write(i2c_base[adap->hwadapnr], chip_addr, &o[4 - olen],
+			   olen, data, dlen);
 }
 
 static unsigned int fsl_i2c_set_bus_speed(struct i2c_adapter *adap,
-			unsigned int speed)
+					  unsigned int speed)
 {
-	struct fsl_i2c *dev = (struct fsl_i2c *)i2c_dev[adap->hwadapnr];
-
-	writeb(0, &dev->cr);		/* stop controller */
-	set_i2c_bus_speed(dev, get_i2c_clock(adap->hwadapnr), speed);
-	writeb(I2C_CR_MEN, &dev->cr);	/* start controller */
-
-	return 0;
+	return __i2c_set_bus_speed(i2c_base[adap->hwadapnr], speed,
+				   get_i2c_clock(adap->hwadapnr));
 }
 
 /*
  * Register fsl i2c adapters
  */
-U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+U_BOOT_I2C_ADAP_COMPLETE(fsl_0, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
 			 fsl_i2c_write, fsl_i2c_set_bus_speed,
 			 CONFIG_SYS_FSL_I2C_SPEED, CONFIG_SYS_FSL_I2C_SLAVE,
 			 0)
 #ifdef CONFIG_SYS_FSL_I2C2_OFFSET
-U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+U_BOOT_I2C_ADAP_COMPLETE(fsl_1, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
 			 fsl_i2c_write, fsl_i2c_set_bus_speed,
 			 CONFIG_SYS_FSL_I2C2_SPEED, CONFIG_SYS_FSL_I2C2_SLAVE,
 			 1)
 #endif
 #ifdef CONFIG_SYS_FSL_I2C3_OFFSET
-U_BOOT_I2C_ADAP_COMPLETE(fsl_2, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+U_BOOT_I2C_ADAP_COMPLETE(fsl_2, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
 			 fsl_i2c_write, fsl_i2c_set_bus_speed,
 			 CONFIG_SYS_FSL_I2C3_SPEED, CONFIG_SYS_FSL_I2C3_SLAVE,
 			 2)
 #endif
 #ifdef CONFIG_SYS_FSL_I2C4_OFFSET
-U_BOOT_I2C_ADAP_COMPLETE(fsl_3, fsl_i2c_init, fsl_i2c_probe, fsl_i2c_read,
+U_BOOT_I2C_ADAP_COMPLETE(fsl_3, fsl_i2c_init, fsl_i2c_probe_chip, fsl_i2c_read,
 			 fsl_i2c_write, fsl_i2c_set_bus_speed,
 			 CONFIG_SYS_FSL_I2C4_SPEED, CONFIG_SYS_FSL_I2C4_SLAVE,
 			 3)
 #endif
+#else /* CONFIG_DM_I2C */
+static int fsl_i2c_probe_chip(struct udevice *bus, u32 chip_addr,
+			      u32 chip_flags)
+{
+	struct fsl_i2c_dev *dev = dev_get_priv(bus);
+	return __i2c_probe_chip(dev->base, chip_addr);
+}
+
+static int fsl_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	struct fsl_i2c_dev *dev = dev_get_priv(bus);
+	return __i2c_set_bus_speed(dev->base, speed, dev->i2c_clk);
+}
+
+static int fsl_i2c_ofdata_to_platdata(struct udevice *bus)
+{
+	struct fsl_i2c_dev *dev = dev_get_priv(bus);
+	u64 reg;
+	u32 addr, size;
+
+	reg = fdtdec_get_addr(gd->fdt_blob, bus->of_offset, "reg");
+	addr = reg >> 32;
+	size = reg & 0xFFFFFFFF;
+
+	dev->base = map_sysmem(CONFIG_SYS_IMMR + addr, size);
+
+	if (!dev->base)
+		return -ENOMEM;
+
+	dev->index = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+				    "cell-index", -1);
+	dev->slaveadd = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+				       "u-boot,i2c-slave-addr", 0x7f);
+	dev->speed = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
+				    "clock-frequency", 400000);
+
+	dev->i2c_clk = dev->index ? gd->arch.i2c2_clk : gd->arch.i2c1_clk;
+
+	return 0;
+}
+
+static int fsl_i2c_probe(struct udevice *bus)
+{
+	struct fsl_i2c_dev *dev = dev_get_priv(bus);
+	__i2c_init(dev->base, dev->speed, dev->slaveadd, dev->i2c_clk,
+		   dev->index);
+	return 0;
+}
+
+static int fsl_i2c_xfer(struct udevice *bus, struct i2c_msg *msg, int nmsgs)
+{
+	struct fsl_i2c_dev *dev = dev_get_priv(bus);
+	struct i2c_msg *dmsg, *omsg, dummy;
+
+	memset(&dummy, 0, sizeof(struct i2c_msg));
+
+	/* We expect either two messages (one with an offset and one with the
+	 * actucal data) or one message (just data) */
+	if (nmsgs > 2 || nmsgs == 0) {
+		debug("%s: Only one or two messages are supported.", __func__);
+		return -1;
+	}
+
+	omsg = nmsgs == 1 ? &dummy : msg;
+	dmsg = nmsgs == 1 ? msg : msg + 1;
+
+	if (dmsg->flags & I2C_M_RD)
+		return __i2c_read(dev->base, dmsg->addr, omsg->buf, omsg->len,
+				  dmsg->buf, dmsg->len);
+	else
+		return __i2c_write(dev->base, dmsg->addr, omsg->buf, omsg->len,
+				   dmsg->buf, dmsg->len);
+}
+
+static const struct dm_i2c_ops fsl_i2c_ops = {
+	.xfer           = fsl_i2c_xfer,
+	.probe_chip     = fsl_i2c_probe_chip,
+	.set_bus_speed  = fsl_i2c_set_bus_speed,
+};
+
+static const struct udevice_id fsl_i2c_ids[] = {
+	{ .compatible = "fsl-i2c", },
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(i2c_fsl) = {
+	.name = "i2c_fsl",
+	.id = UCLASS_I2C,
+	.of_match = fsl_i2c_ids,
+	.probe = fsl_i2c_probe,
+	.ofdata_to_platdata = fsl_i2c_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct fsl_i2c_dev),
+	.ops = &fsl_i2c_ops,
+};
+
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/i2c-cdns.c b/drivers/i2c/i2c-cdns.c
index 909cea2..5642cd9 100644
--- a/drivers/i2c/i2c-cdns.c
+++ b/drivers/i2c/i2c-cdns.c
@@ -112,48 +112,10 @@
 
 struct i2c_cdns_bus {
 	int id;
+	unsigned int input_freq;
 	struct cdns_i2c_regs __iomem *regs;	/* register base */
 };
 
-
-/** cdns_i2c_probe() - Probe method
- * @dev: udevice pointer
- *
- * DM callback called when device is probed
- */
-static int cdns_i2c_probe(struct udevice *dev)
-{
-	struct i2c_cdns_bus *bus = dev_get_priv(dev);
-
-	bus->regs = (struct cdns_i2c_regs *)dev_get_addr(dev);
-	if (!bus->regs)
-		return -ENOMEM;
-
-	/* TODO: Calculate dividers based on CPU_CLK_1X */
-	/* 111MHz / ( (3 * 17) * 22 ) = ~100KHz */
-	writel((16 << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
-		(2 << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
-
-	/* Enable master mode, ack, and 7-bit addressing */
-	setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
-		CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA);
-
-	debug("%s bus %d at %p\n", __func__, dev->seq, bus->regs);
-
-	return 0;
-}
-
-static int cdns_i2c_remove(struct udevice *dev)
-{
-	struct i2c_cdns_bus *bus = dev_get_priv(dev);
-
-	debug("%s bus %d at %p\n", __func__, dev->seq, bus->regs);
-
-	unmap_sysmem(bus->regs);
-
-	return 0;
-}
-
 /* Wait for an interrupt */
 static u32 cdns_i2c_wait(struct cdns_i2c_regs *cdns_i2c, u32 mask)
 {
@@ -172,14 +134,84 @@
 	return int_status & mask;
 }
 
+#define CDNS_I2C_DIVA_MAX	4
+#define CDNS_I2C_DIVB_MAX	64
+
+static int cdns_i2c_calc_divs(unsigned long *f, unsigned long input_clk,
+		unsigned int *a, unsigned int *b)
+{
+	unsigned long fscl = *f, best_fscl = *f, actual_fscl, temp;
+	unsigned int div_a, div_b, calc_div_a = 0, calc_div_b = 0;
+	unsigned int last_error, current_error;
+
+	/* calculate (divisor_a+1) x (divisor_b+1) */
+	temp = input_clk / (22 * fscl);
+
+	/*
+	 * If the calculated value is negative or 0CDNS_I2C_DIVA_MAX,
+	 * the fscl input is out of range. Return error.
+	 */
+	if (!temp || (temp > (CDNS_I2C_DIVA_MAX * CDNS_I2C_DIVB_MAX)))
+		return -EINVAL;
+
+	last_error = -1;
+	for (div_a = 0; div_a < CDNS_I2C_DIVA_MAX; div_a++) {
+		div_b = DIV_ROUND_UP(input_clk, 22 * fscl * (div_a + 1));
+
+		if ((div_b < 1) || (div_b > CDNS_I2C_DIVB_MAX))
+			continue;
+		div_b--;
+
+		actual_fscl = input_clk / (22 * (div_a + 1) * (div_b + 1));
+
+		if (actual_fscl > fscl)
+			continue;
+
+		current_error = ((actual_fscl > fscl) ? (actual_fscl - fscl) :
+							(fscl - actual_fscl));
+
+		if (last_error > current_error) {
+			calc_div_a = div_a;
+			calc_div_b = div_b;
+			best_fscl = actual_fscl;
+			last_error = current_error;
+		}
+	}
+
+	*a = calc_div_a;
+	*b = calc_div_b;
+	*f = best_fscl;
+
+	return 0;
+}
+
 static int cdns_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
 {
-	if (speed != 100000) {
-		printf("%s, failed to set clock speed to %u\n", __func__,
-		       speed);
+	struct i2c_cdns_bus *bus = dev_get_priv(dev);
+	u32 div_a = 0, div_b = 0;
+	unsigned long speed_p = speed;
+	int ret = 0;
+
+	if (speed > 400000) {
+		debug("%s, failed to set clock speed to %u\n", __func__,
+		      speed);
 		return -EINVAL;
 	}
 
+	ret = cdns_i2c_calc_divs(&speed_p, bus->input_freq, &div_a, &div_b);
+	if (ret)
+		return ret;
+
+	debug("%s: div_a: %d, div_b: %d, input freq: %d, speed: %d/%ld\n",
+	      __func__, div_a, div_b, bus->input_freq, speed, speed_p);
+
+	writel((div_b << CDNS_I2C_CONTROL_DIV_B_SHIFT) |
+	       (div_a << CDNS_I2C_CONTROL_DIV_A_SHIFT), &bus->regs->control);
+
+	/* Enable master mode, ack, and 7-bit addressing */
+	setbits_le32(&bus->regs->control, CDNS_I2C_CONTROL_MS |
+		CDNS_I2C_CONTROL_ACKEN | CDNS_I2C_CONTROL_NEA);
+
 	return 0;
 }
 
@@ -313,6 +345,19 @@
 	return 0;
 }
 
+static int cdns_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+	struct i2c_cdns_bus *i2c_bus = dev_get_priv(dev);
+
+	i2c_bus->regs = (struct cdns_i2c_regs *)dev_get_addr(dev);
+	if (!i2c_bus->regs)
+		return -ENOMEM;
+
+	i2c_bus->input_freq = 100000000; /* TODO hardcode input freq for now */
+
+	return 0;
+}
+
 static const struct dm_i2c_ops cdns_i2c_ops = {
 	.xfer = cdns_i2c_xfer,
 	.probe_chip = cdns_i2c_probe_chip,
@@ -328,8 +373,7 @@
 	.name = "i2c-cdns",
 	.id = UCLASS_I2C,
 	.of_match = cdns_i2c_of_match,
-	.probe = cdns_i2c_probe,
-	.remove = cdns_i2c_remove,
+	.ofdata_to_platdata = cdns_i2c_ofdata_to_platdata,
 	.priv_auto_alloc_size = sizeof(struct i2c_cdns_bus),
 	.ops = &cdns_i2c_ops,
 };
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index f959d9d..48900ed 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -24,3 +24,13 @@
 	  I2C multimaster arbitration scheme using GPIOs and a challenge &
 	  response mechanism where masters have to claim the bus by asserting
 	  a GPIO.
+
+config I2C_MUX_PCA954x
+	tristate "TI PCA954x I2C Mux/switches"
+	depends on I2C_MUX
+	help
+	  If you say yes here you get support for the TI PCA954x
+	  I2C mux/switch devices. It is x width I2C multiplexer which enables to
+	  paritioning I2C bus and connect multiple devices with the same address
+	  to the same I2C controller where driver handles proper routing to
+	  target i2c device. PCA9544 and PCA9548 are supported.
diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
index 47c1240..0811add 100644
--- a/drivers/i2c/muxes/Makefile
+++ b/drivers/i2c/muxes/Makefile
@@ -5,3 +5,4 @@
 #
 obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
 obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o
+obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
new file mode 100644
index 0000000..7e0d2da
--- /dev/null
+++ b/drivers/i2c/muxes/pca954x.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2015 - 2016 Xilinx, Inc.
+ * Written by Michal Simek
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+#include <asm/gpio.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct pca954x_priv {
+	u32 addr; /* I2C mux address */
+	u32 width; /* I2C mux width - number of busses */
+};
+
+static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
+			    uint channel)
+{
+	struct pca954x_priv *priv = dev_get_priv(mux);
+	uchar byte = 0;
+
+	return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+
+static int pca954x_select(struct udevice *mux, struct udevice *bus,
+			  uint channel)
+{
+	struct pca954x_priv *priv = dev_get_priv(mux);
+	uchar byte = 1 << channel;
+
+	return dm_i2c_write(mux, priv->addr, &byte, 1);
+}
+
+static const struct i2c_mux_ops pca954x_ops = {
+	.select = pca954x_select,
+	.deselect = pca954x_deselect,
+};
+
+static const struct udevice_id pca954x_ids[] = {
+	{ .compatible = "nxp,pca9548", .data = (ulong)8 },
+	{ .compatible = "nxp,pca9544", .data = (ulong)4 },
+	{ }
+};
+
+static int pca954x_ofdata_to_platdata(struct udevice *dev)
+{
+	struct pca954x_priv *priv = dev_get_priv(dev);
+
+	priv->addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg", 0);
+	if (!priv->addr) {
+		debug("MUX not found\n");
+		return -ENODEV;
+	}
+	priv->width = dev_get_driver_data(dev);
+
+	if (!priv->width) {
+		debug("No I2C MUX width specified\n");
+		return -EINVAL;
+	}
+
+	debug("Device %s at 0x%x with width %d\n",
+	      dev->name, priv->addr, priv->width);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(pca954x) = {
+	.name = "pca954x",
+	.id = UCLASS_I2C_MUX,
+	.of_match = pca954x_ids,
+	.ops = &pca954x_ops,
+	.ofdata_to_platdata = pca954x_ofdata_to_platdata,
+	.priv_auto_alloc_size = sizeof(struct pca954x_priv),
+};
diff --git a/drivers/i2c/mvtwsi.c b/drivers/i2c/mvtwsi.c
index 221ff4f..bf44432 100644
--- a/drivers/i2c/mvtwsi.c
+++ b/drivers/i2c/mvtwsi.c
@@ -185,26 +185,17 @@
 }
 
 /*
- * These flags are ORed to any write to the control register
- * They allow global setting of TWSIEN and ACK.
- * By default none are set.
- * twsi_start() sets TWSIEN (in case the controller was disabled)
- * twsi_recv() sets ACK or resets it depending on expected status.
- */
-static u8 twsi_control_flags = MVTWSI_CONTROL_TWSIEN;
-
-/*
  * Assert the START condition, either in a single I2C transaction
  * or inside back-to-back ones (repeated starts).
  */
-static int twsi_start(struct i2c_adapter *adap, int expected_status)
+static int twsi_start(struct i2c_adapter *adap, int expected_status, u8 *flags)
 {
 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
 
 	/* globally set TWSIEN in case it was not */
-	twsi_control_flags |= MVTWSI_CONTROL_TWSIEN;
+	*flags |= MVTWSI_CONTROL_TWSIEN;
 	/* assert START */
-	writel(twsi_control_flags | MVTWSI_CONTROL_START |
+	writel(*flags | MVTWSI_CONTROL_START |
 				    MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to process START */
 	return twsi_wait(adap, expected_status);
@@ -213,14 +204,15 @@
 /*
  * Send a byte (i2c address or data).
  */
-static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status)
+static int twsi_send(struct i2c_adapter *adap, u8 byte, int expected_status,
+		     u8 *flags)
 {
 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
 
 	/* put byte in data register for sending */
 	writel(byte, &twsi->data);
 	/* clear any pending interrupt -- that'll cause sending */
-	writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+	writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to receive byte and check ACK */
 	return twsi_wait(adap, expected_status);
 }
@@ -229,18 +221,18 @@
  * Receive a byte.
  * Global mvtwsi_control_flags variable says if we should ack or nak.
  */
-static int twsi_recv(struct i2c_adapter *adap, u8 *byte)
+static int twsi_recv(struct i2c_adapter *adap, u8 *byte, u8 *flags)
 {
 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
 	int expected_status, status;
 
 	/* compute expected status based on ACK bit in global control flags */
-	if (twsi_control_flags & MVTWSI_CONTROL_ACK)
+	if (*flags & MVTWSI_CONTROL_ACK)
 		expected_status = MVTWSI_STATUS_DATA_R_ACK;
 	else
 		expected_status = MVTWSI_STATUS_DATA_R_NAK;
 	/* acknowledge *previous state* and launch receive */
-	writel(twsi_control_flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
+	writel(*flags | MVTWSI_CONTROL_CLEAR_IFLG, &twsi->control);
 	/* wait for controller to receive byte and assert ACK or NAK */
 	status = twsi_wait(adap, expected_status);
 	/* if we did receive expected byte then store it */
@@ -296,8 +288,7 @@
 static void twsi_reset(struct i2c_adapter *adap)
 {
 	struct mvtwsi_registers *twsi = twsi_get_base(adap);
-	/* ensure controller will be enabled by any twsi*() function */
-	twsi_control_flags = MVTWSI_CONTROL_TWSIEN;
+
 	/* reset controller */
 	writel(0, &twsi->soft_reset);
 	/* wait 2 ms -- this is what the Marvell LSP does */
@@ -353,7 +344,7 @@
  * Expected address status will derive from direction bit (bit 0) in addr.
  */
 static int i2c_begin(struct i2c_adapter *adap, int expected_start_status,
-		     u8 addr)
+		     u8 addr, u8 *flags)
 {
 	int status, expected_addr_status;
 
@@ -363,10 +354,11 @@
 	else /* writing */
 		expected_addr_status = MVTWSI_STATUS_ADDR_W_ACK;
 	/* assert START */
-	status = twsi_start(adap, expected_start_status);
+	status = twsi_start(adap, expected_start_status, flags);
 	/* send out the address if the start went well */
 	if (status == 0)
-		status = twsi_send(adap, addr, expected_addr_status);
+		status = twsi_send(adap, addr, expected_addr_status,
+				   flags);
 	/* return ok or status of first failure to caller */
 	return status;
 }
@@ -378,13 +370,14 @@
 static int twsi_i2c_probe(struct i2c_adapter *adap, uchar chip)
 {
 	u8 dummy_byte;
+	u8 flags = 0;
 	int status;
 
 	/* begin i2c read */
-	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1) | 1);
+	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1) | 1, &flags);
 	/* dummy read was accepted: receive byte but NAK it. */
 	if (status == 0)
-		status = twsi_recv(adap, &dummy_byte);
+		status = twsi_recv(adap, &dummy_byte, &flags);
 	/* Stop transaction */
 	twsi_stop(adap, 0);
 	/* return 0 or status of first failure */
@@ -405,27 +398,28 @@
 			int alen, uchar *data, int length)
 {
 	int status;
+	u8 flags = 0;
 
 	/* begin i2c write to send the address bytes */
-	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1));
+	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
 	/* send addr bytes */
 	while ((status == 0) && alen--)
 		status = twsi_send(adap, addr >> (8*alen),
-			MVTWSI_STATUS_DATA_W_ACK);
+			MVTWSI_STATUS_DATA_W_ACK, &flags);
 	/* begin i2c read to receive eeprom data bytes */
 	if (status == 0)
 		status = i2c_begin(adap, MVTWSI_STATUS_REPEATED_START,
-				   (chip << 1) | 1);
+				   (chip << 1) | 1, &flags);
 	/* prepare ACK if at least one byte must be received */
 	if (length > 0)
-		twsi_control_flags |= MVTWSI_CONTROL_ACK;
+		flags |= MVTWSI_CONTROL_ACK;
 	/* now receive actual bytes */
 	while ((status == 0) && length--) {
 		/* reset NAK if we if no more to read now */
 		if (length == 0)
-			twsi_control_flags &= ~MVTWSI_CONTROL_ACK;
+			flags &= ~MVTWSI_CONTROL_ACK;
 		/* read current byte */
-		status = twsi_recv(adap, data++);
+		status = twsi_recv(adap, data++, &flags);
 	}
 	/* Stop transaction */
 	status = twsi_stop(adap, status);
@@ -441,16 +435,18 @@
 			int alen, uchar *data, int length)
 {
 	int status;
+	u8 flags = 0;
 
 	/* begin i2c write to send the eeprom adress bytes then data bytes */
-	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1));
+	status = i2c_begin(adap, MVTWSI_STATUS_START, (chip << 1), &flags);
 	/* send addr bytes */
 	while ((status == 0) && alen--)
 		status = twsi_send(adap, addr >> (8*alen),
-			MVTWSI_STATUS_DATA_W_ACK);
+			MVTWSI_STATUS_DATA_W_ACK, &flags);
 	/* send data bytes */
 	while ((status == 0) && (length-- > 0))
-		status = twsi_send(adap, *(data++), MVTWSI_STATUS_DATA_W_ACK);
+		status = twsi_send(adap, *(data++), MVTWSI_STATUS_DATA_W_ACK,
+				   &flags);
 	/* Stop transaction */
 	status = twsi_stop(adap, status);
 	/* return 0 or status of first failure */
diff --git a/drivers/mmc/Kconfig b/drivers/mmc/Kconfig
index 4d3df11..c80efc3 100644
--- a/drivers/mmc/Kconfig
+++ b/drivers/mmc/Kconfig
@@ -2,7 +2,7 @@
 
 config MMC
 	bool "Enable MMC support"
-	depends on ARCH_SUNXI
+	depends on ARCH_SUNXI || SANDBOX
 	help
 	  TODO: Move all architectures to use this option
 
@@ -58,4 +58,13 @@
 	help
 	  This selects support for the SD/MMC Host Controller on UniPhier SoCs.
 
+config SANDBOX_MMC
+	bool "Sandbox MMC support"
+	depends on MMC && SANDBOX
+	help
+	  This select a dummy sandbox MMC driver. At present this does nothing
+	  other than allow sandbox to be build with MMC support. This
+	  improves build coverage for sandbox and makes it easier to detect
+	  MMC build errors with sandbox.
+
 endmenu
diff --git a/drivers/mmc/Makefile b/drivers/mmc/Makefile
index 585aaf3..3da4817 100644
--- a/drivers/mmc/Makefile
+++ b/drivers/mmc/Makefile
@@ -5,7 +5,13 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-$(CONFIG_DM_MMC) += mmc-uclass.o
+ifdef CONFIG_DM_MMC
+obj-$(CONFIG_GENERIC_MMC) += mmc-uclass.o
+endif
+
+ifndef CONFIG_BLK
+obj-$(CONFIG_GENERIC_MMC) += mmc_legacy.o
+endif
 
 obj-$(CONFIG_ARM_PL180_MMCI) += arm_pl180_mmci.o
 obj-$(CONFIG_ATMEL_SDHCI) += atmel_sdhci.o
@@ -34,7 +40,11 @@
 obj-$(CONFIG_SUPPORT_EMMC_RPMB) += rpmb.o
 obj-$(CONFIG_S3C_SDI) += s3c_sdi.o
 obj-$(CONFIG_S5P_SDHCI) += s5p_sdhci.o
+ifdef CONFIG_BLK
+ifdef CONFIG_GENERIC_MMC
 obj-$(CONFIG_SANDBOX) += sandbox_mmc.o
+endif
+endif
 obj-$(CONFIG_SDHCI) += sdhci.o
 obj-$(CONFIG_SH_MMCIF) += sh_mmcif.o
 obj-$(CONFIG_SH_SDHI) += sh_sdhi.o
diff --git a/drivers/mmc/mmc-uclass.c b/drivers/mmc/mmc-uclass.c
index 777489f..1b967d9 100644
--- a/drivers/mmc/mmc-uclass.c
+++ b/drivers/mmc/mmc-uclass.c
@@ -21,6 +21,112 @@
 	return upriv->mmc;
 }
 
+#ifdef CONFIG_BLK
+struct mmc *find_mmc_device(int dev_num)
+{
+	struct udevice *dev, *mmc_dev;
+	int ret;
+
+	ret = blk_get_device(IF_TYPE_MMC, dev_num, &dev);
+
+	if (ret) {
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+		printf("MMC Device %d not found\n", dev_num);
+#endif
+		return NULL;
+	}
+
+	mmc_dev = dev_get_parent(dev);
+
+	return mmc_get_mmc_dev(mmc_dev);
+}
+
+int get_mmc_num(void)
+{
+	return max(blk_find_max_devnum(IF_TYPE_MMC), 0);
+}
+
+int mmc_get_next_devnum(void)
+{
+	int ret;
+
+	ret = get_mmc_num();
+	if (ret < 0)
+		return ret;
+
+	return ret + 1;
+}
+
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
+{
+	struct blk_desc *desc;
+	struct udevice *dev;
+
+	device_find_first_child(mmc->dev, &dev);
+	if (!dev)
+		return NULL;
+	desc = dev_get_uclass_platdata(dev);
+
+	return desc;
+}
+
+void mmc_do_preinit(void)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_MMC, &uc);
+	if (ret)
+		return;
+	uclass_foreach_dev(dev, uc) {
+		struct mmc *m = mmc_get_mmc_dev(dev);
+
+		if (!m)
+			continue;
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+		mmc_set_preinit(m, 1);
+#endif
+		if (m->preinit)
+			mmc_start_init(m);
+	}
+}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+void print_mmc_devices(char separator)
+{
+	struct udevice *dev;
+	char *mmc_type;
+	bool first = true;
+
+	for (uclass_first_device(UCLASS_MMC, &dev);
+	     dev;
+	     uclass_next_device(&dev)) {
+		struct mmc *m = mmc_get_mmc_dev(dev);
+
+		if (!first) {
+			printf("%c", separator);
+			if (separator != '\n')
+				puts(" ");
+		}
+		if (m->has_init)
+			mmc_type = IS_SD(m) ? "SD" : "eMMC";
+		else
+			mmc_type = NULL;
+
+		printf("%s: %d", m->cfg->name, mmc_get_blk_desc(m)->devnum);
+		if (mmc_type)
+			printf(" (%s)", mmc_type);
+	}
+
+	printf("\n");
+}
+
+#else
+void print_mmc_devices(char separator) { }
+#endif
+#endif /* CONFIG_BLK */
+
 U_BOOT_DRIVER(mmc) = {
 	.name	= "mmc",
 	.id	= UCLASS_MMC,
diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c
index d3c22ab..74b3d68 100644
--- a/drivers/mmc/mmc.c
+++ b/drivers/mmc/mmc.c
@@ -21,9 +21,6 @@
 #include <div64.h>
 #include "mmc_private.h"
 
-static struct list_head mmc_devices;
-static int cur_dev_num = -1;
-
 __weak int board_mmc_getwp(struct mmc *mmc)
 {
 	return -1;
@@ -178,25 +175,6 @@
 	return mmc_send_cmd(mmc, &cmd, NULL);
 }
 
-struct mmc *find_mmc_device(int dev_num)
-{
-	struct mmc *m;
-	struct list_head *entry;
-
-	list_for_each(entry, &mmc_devices) {
-		m = list_entry(entry, struct mmc, link);
-
-		if (m->block_dev.devnum == dev_num)
-			return m;
-	}
-
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-	printf("MMC Device %d not found\n", dev_num);
-#endif
-
-	return NULL;
-}
-
 static int mmc_read_blocks(struct mmc *mmc, void *dst, lbaint_t start,
 			   lbaint_t blkcnt)
 {
@@ -238,9 +216,17 @@
 	return blkcnt;
 }
 
+#ifdef CONFIG_BLK
+static ulong mmc_bread(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+		       void *dst)
+#else
 static ulong mmc_bread(struct blk_desc *block_dev, lbaint_t start,
 		       lbaint_t blkcnt, void *dst)
+#endif
 {
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
 	int dev_num = block_dev->devnum;
 	int err;
 	lbaint_t cur, blocks_todo = blkcnt;
@@ -252,14 +238,14 @@
 	if (!mmc)
 		return 0;
 
-	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	err = blk_dselect_hwpart(block_dev, block_dev->hwpart);
 	if (err < 0)
 		return 0;
 
-	if ((start + blkcnt) > mmc->block_dev.lba) {
+	if ((start + blkcnt) > block_dev->lba) {
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
-			start + blkcnt, mmc->block_dev.lba);
+			start + blkcnt, block_dev->lba);
 #endif
 		return 0;
 	}
@@ -577,43 +563,15 @@
 		return -1;
 	}
 
-	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+	mmc_get_blk_desc(mmc)->lba = lldiv(mmc->capacity, mmc->read_bl_len);
 
 	return 0;
 }
 
-int mmc_select_hwpart(int dev_num, int hwpart)
+static int mmc_switch_part(struct mmc *mmc, unsigned int part_num)
 {
-	struct mmc *mmc = find_mmc_device(dev_num);
 	int ret;
 
-	if (!mmc)
-		return -ENODEV;
-
-	if (mmc->block_dev.hwpart == hwpart)
-		return 0;
-
-	if (mmc->part_config == MMCPART_NOAVAILABLE) {
-		printf("Card doesn't support part_switch\n");
-		return -EMEDIUMTYPE;
-	}
-
-	ret = mmc_switch_part(dev_num, hwpart);
-	if (ret)
-		return ret;
-
-	return 0;
-}
-
-
-int mmc_switch_part(int dev_num, unsigned int part_num)
-{
-	struct mmc *mmc = find_mmc_device(dev_num);
-	int ret;
-
-	if (!mmc)
-		return -1;
-
 	ret = mmc_switch(mmc, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_PART_CONF,
 			 (mmc->part_config & ~PART_ACCESS_MASK)
 			 | (part_num & PART_ACCESS_MASK));
@@ -624,12 +582,55 @@
 	 */
 	if ((ret == 0) || ((ret == -ENODEV) && (part_num == 0))) {
 		ret = mmc_set_capacity(mmc, part_num);
-		mmc->block_dev.hwpart = part_num;
+		mmc_get_blk_desc(mmc)->hwpart = part_num;
 	}
 
 	return ret;
 }
 
+#ifdef CONFIG_BLK
+static int mmc_select_hwpart(struct udevice *bdev, int hwpart)
+{
+	struct udevice *mmc_dev = dev_get_parent(bdev);
+	struct mmc *mmc = mmc_get_mmc_dev(mmc_dev);
+	struct blk_desc *desc = dev_get_uclass_platdata(bdev);
+	int ret;
+
+	if (desc->hwpart == hwpart)
+		return 0;
+
+	if (mmc->part_config == MMCPART_NOAVAILABLE)
+		return -EMEDIUMTYPE;
+
+	ret = mmc_switch_part(mmc, hwpart);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#else
+static int mmc_select_hwpartp(struct blk_desc *desc, int hwpart)
+{
+	struct mmc *mmc = find_mmc_device(desc->devnum);
+	int ret;
+
+	if (!mmc)
+		return -ENODEV;
+
+	if (mmc->block_dev.hwpart == hwpart)
+		return 0;
+
+	if (mmc->part_config == MMCPART_NOAVAILABLE)
+		return -EMEDIUMTYPE;
+
+	ret = mmc_switch_part(mmc, hwpart);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+#endif
+
 int mmc_hwpart_config(struct mmc *mmc,
 		      const struct mmc_hwpart_conf *conf,
 		      enum mmc_hwpart_conf_mode mode)
@@ -1039,6 +1040,7 @@
 	int timeout = 1000;
 	bool has_parts = false;
 	bool part_completed;
+	struct blk_desc *bdesc;
 
 #ifdef CONFIG_MMC_SPI_CRC_ON
 	if (mmc_host_is_spi(mmc)) { /* enable CRC check for spi */
@@ -1335,7 +1337,7 @@
 		mmc->wr_rel_set = ext_csd[EXT_CSD_WR_REL_SET];
 	}
 
-	err = mmc_set_capacity(mmc, mmc->block_dev.hwpart);
+	err = mmc_set_capacity(mmc, mmc_get_blk_desc(mmc)->hwpart);
 	if (err)
 		return err;
 
@@ -1475,31 +1477,32 @@
 	}
 
 	/* fill in device description */
-	mmc->block_dev.lun = 0;
-	mmc->block_dev.hwpart = 0;
-	mmc->block_dev.type = 0;
-	mmc->block_dev.blksz = mmc->read_bl_len;
-	mmc->block_dev.log2blksz = LOG2(mmc->block_dev.blksz);
-	mmc->block_dev.lba = lldiv(mmc->capacity, mmc->read_bl_len);
+	bdesc = mmc_get_blk_desc(mmc);
+	bdesc->lun = 0;
+	bdesc->hwpart = 0;
+	bdesc->type = 0;
+	bdesc->blksz = mmc->read_bl_len;
+	bdesc->log2blksz = LOG2(bdesc->blksz);
+	bdesc->lba = lldiv(mmc->capacity, mmc->read_bl_len);
 #if !defined(CONFIG_SPL_BUILD) || \
 		(defined(CONFIG_SPL_LIBCOMMON_SUPPORT) && \
 		!defined(CONFIG_USE_TINY_PRINTF))
-	sprintf(mmc->block_dev.vendor, "Man %06x Snr %04x%04x",
+	sprintf(bdesc->vendor, "Man %06x Snr %04x%04x",
 		mmc->cid[0] >> 24, (mmc->cid[2] & 0xffff),
 		(mmc->cid[3] >> 16) & 0xffff);
-	sprintf(mmc->block_dev.product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
+	sprintf(bdesc->product, "%c%c%c%c%c%c", mmc->cid[0] & 0xff,
 		(mmc->cid[1] >> 24), (mmc->cid[1] >> 16) & 0xff,
 		(mmc->cid[1] >> 8) & 0xff, mmc->cid[1] & 0xff,
 		(mmc->cid[2] >> 24) & 0xff);
-	sprintf(mmc->block_dev.revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
+	sprintf(bdesc->revision, "%d.%d", (mmc->cid[2] >> 20) & 0xf,
 		(mmc->cid[2] >> 16) & 0xf);
 #else
-	mmc->block_dev.vendor[0] = 0;
-	mmc->block_dev.product[0] = 0;
-	mmc->block_dev.revision[0] = 0;
+	bdesc->vendor[0] = 0;
+	bdesc->product[0] = 0;
+	bdesc->revision[0] = 0;
 #endif
 #if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBDISK_SUPPORT)
-	part_init(&mmc->block_dev);
+	part_init(bdesc);
 #endif
 
 	return 0;
@@ -1537,8 +1540,55 @@
 	return -1;
 }
 
+#ifdef CONFIG_BLK
+int mmc_bind(struct udevice *dev, struct mmc *mmc, const struct mmc_config *cfg)
+{
+	struct blk_desc *bdesc;
+	struct udevice *bdev;
+	int ret;
+
+	ret = blk_create_devicef(dev, "mmc_blk", "blk", IF_TYPE_MMC, -1, 512,
+				 0, &bdev);
+	if (ret) {
+		debug("Cannot create block device\n");
+		return ret;
+	}
+	bdesc = dev_get_uclass_platdata(bdev);
+	mmc->cfg = cfg;
+	mmc->priv = dev;
+
+	/* the following chunk was from mmc_register() */
+
+	/* Setup dsr related values */
+	mmc->dsr_imp = 0;
+	mmc->dsr = 0xffffffff;
+	/* Setup the universal parts of the block interface just once */
+	bdesc->removable = 1;
+
+	/* setup initial part type */
+	bdesc->part_type = mmc->cfg->part_type;
+	mmc->dev = dev;
+
+	return 0;
+}
+
+int mmc_unbind(struct udevice *dev)
+{
+	struct udevice *bdev;
+
+	device_find_first_child(dev, &bdev);
+	if (bdev) {
+		device_remove(bdev);
+		device_unbind(bdev);
+	}
+
+	return 0;
+}
+
+#else
 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv)
 {
+	struct blk_desc *bdesc;
 	struct mmc *mmc;
 
 	/* quick validation */
@@ -1559,19 +1609,17 @@
 	mmc->dsr_imp = 0;
 	mmc->dsr = 0xffffffff;
 	/* Setup the universal parts of the block interface just once */
-	mmc->block_dev.if_type = IF_TYPE_MMC;
-	mmc->block_dev.devnum = cur_dev_num++;
-	mmc->block_dev.removable = 1;
-	mmc->block_dev.block_read = mmc_bread;
-	mmc->block_dev.block_write = mmc_bwrite;
-	mmc->block_dev.block_erase = mmc_berase;
+	bdesc = mmc_get_blk_desc(mmc);
+	bdesc->if_type = IF_TYPE_MMC;
+	bdesc->removable = 1;
+	bdesc->devnum = mmc_get_next_devnum();
+	bdesc->block_read = mmc_bread;
+	bdesc->block_write = mmc_bwrite;
+	bdesc->block_erase = mmc_berase;
 
 	/* setup initial part type */
-	mmc->block_dev.part_type = mmc->cfg->part_type;
-
-	INIT_LIST_HEAD(&mmc->link);
-
-	list_add_tail(&mmc->link, &mmc_devices);
+	bdesc->part_type = mmc->cfg->part_type;
+	mmc_list_add(mmc);
 
 	return mmc;
 }
@@ -1581,15 +1629,23 @@
 	/* only freeing memory for now */
 	free(mmc);
 }
+#endif
 
-#ifdef CONFIG_PARTITIONS
-struct blk_desc *mmc_get_dev(int dev)
+#ifndef CONFIG_BLK
+static int mmc_get_dev(int dev, struct blk_desc **descp)
 {
 	struct mmc *mmc = find_mmc_device(dev);
-	if (!mmc || mmc_init(mmc))
-		return NULL;
+	int ret;
 
-	return &mmc->block_dev;
+	if (!mmc)
+		return -ENODEV;
+	ret = mmc_init(mmc);
+	if (ret)
+		return ret;
+
+	*descp = &mmc->block_dev;
+
+	return 0;
 }
 #endif
 
@@ -1636,7 +1692,7 @@
 		return err;
 
 	/* The internal partition reset to user partition(0) at every CMD0*/
-	mmc->block_dev.hwpart = 0;
+	mmc_get_blk_desc(mmc)->hwpart = 0;
 
 	/* Test for SD version 2 */
 	err = mmc_send_if_cond(mmc);
@@ -1683,7 +1739,11 @@
 {
 	int err = 0;
 	unsigned start;
+#ifdef CONFIG_DM_MMC
+	struct mmc_uclass_priv *upriv = dev_get_uclass_priv(mmc->dev);
 
+	upriv->mmc = mmc;
+#endif
 	if (mmc->has_init)
 		return 0;
 
@@ -1716,66 +1776,11 @@
 	return -1;
 }
 
-#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
-
-void print_mmc_devices(char separator)
-{
-	struct mmc *m;
-	struct list_head *entry;
-	char *mmc_type;
-
-	list_for_each(entry, &mmc_devices) {
-		m = list_entry(entry, struct mmc, link);
-
-		if (m->has_init)
-			mmc_type = IS_SD(m) ? "SD" : "eMMC";
-		else
-			mmc_type = NULL;
-
-		printf("%s: %d", m->cfg->name, m->block_dev.devnum);
-		if (mmc_type)
-			printf(" (%s)", mmc_type);
-
-		if (entry->next != &mmc_devices) {
-			printf("%c", separator);
-			if (separator != '\n')
-				puts (" ");
-		}
-	}
-
-	printf("\n");
-}
-
-#else
-void print_mmc_devices(char separator) { }
-#endif
-
-int get_mmc_num(void)
-{
-	return cur_dev_num;
-}
-
 void mmc_set_preinit(struct mmc *mmc, int preinit)
 {
 	mmc->preinit = preinit;
 }
 
-static void do_preinit(void)
-{
-	struct mmc *m;
-	struct list_head *entry;
-
-	list_for_each(entry, &mmc_devices) {
-		m = list_entry(entry, struct mmc, link);
-
-#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
-		mmc_set_preinit(m, 1);
-#endif
-		if (m->preinit)
-			mmc_start_init(m);
-	}
-}
-
 #if defined(CONFIG_DM_MMC) && defined(CONFIG_SPL_BUILD)
 static int mmc_probe(bd_t *bis)
 {
@@ -1828,9 +1833,9 @@
 		return 0;
 	initialized = 1;
 
-	INIT_LIST_HEAD (&mmc_devices);
-	cur_dev_num = 0;
-
+#ifndef CONFIG_BLK
+	mmc_list_init();
+#endif
 	ret = mmc_probe(bis);
 	if (ret)
 		return ret;
@@ -1839,7 +1844,7 @@
 	print_mmc_devices(',');
 #endif
 
-	do_preinit();
+	mmc_do_preinit();
 	return 0;
 }
 
@@ -1965,3 +1970,25 @@
 			  enable);
 }
 #endif
+
+#ifdef CONFIG_BLK
+static const struct blk_ops mmc_blk_ops = {
+	.read	= mmc_bread,
+	.write	= mmc_bwrite,
+	.select_hwpart	= mmc_select_hwpart,
+};
+
+U_BOOT_DRIVER(mmc_blk) = {
+	.name		= "mmc_blk",
+	.id		= UCLASS_BLK,
+	.ops		= &mmc_blk_ops,
+};
+#else
+U_BOOT_LEGACY_BLK(mmc) = {
+	.if_typename	= "mmc",
+	.if_type	= IF_TYPE_MMC,
+	.max_devs	= -1,
+	.get_dev	= mmc_get_dev,
+	.select_hwpart	= mmc_select_hwpartp,
+};
+#endif
diff --git a/drivers/mmc/mmc_legacy.c b/drivers/mmc/mmc_legacy.c
new file mode 100644
index 0000000..3ec649f
--- /dev/null
+++ b/drivers/mmc/mmc_legacy.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <mmc.h>
+
+static struct list_head mmc_devices;
+static int cur_dev_num = -1;
+
+struct mmc *find_mmc_device(int dev_num)
+{
+	struct mmc *m;
+	struct list_head *entry;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+		if (m->block_dev.devnum == dev_num)
+			return m;
+	}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+	printf("MMC Device %d not found\n", dev_num);
+#endif
+
+	return NULL;
+}
+
+int mmc_get_next_devnum(void)
+{
+	return cur_dev_num++;
+}
+
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc)
+{
+	return &mmc->block_dev;
+}
+
+int get_mmc_num(void)
+{
+	return cur_dev_num;
+}
+
+void mmc_do_preinit(void)
+{
+	struct mmc *m;
+	struct list_head *entry;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+#ifdef CONFIG_FSL_ESDHC_ADAPTER_IDENT
+		mmc_set_preinit(m, 1);
+#endif
+		if (m->preinit)
+			mmc_start_init(m);
+	}
+}
+
+void mmc_list_init(void)
+{
+	INIT_LIST_HEAD(&mmc_devices);
+	cur_dev_num = 0;
+}
+
+void mmc_list_add(struct mmc *mmc)
+{
+	INIT_LIST_HEAD(&mmc->link);
+
+	list_add_tail(&mmc->link, &mmc_devices);
+}
+
+#if !defined(CONFIG_SPL_BUILD) || defined(CONFIG_SPL_LIBCOMMON_SUPPORT)
+void print_mmc_devices(char separator)
+{
+	struct mmc *m;
+	struct list_head *entry;
+	char *mmc_type;
+
+	list_for_each(entry, &mmc_devices) {
+		m = list_entry(entry, struct mmc, link);
+
+		if (m->has_init)
+			mmc_type = IS_SD(m) ? "SD" : "eMMC";
+		else
+			mmc_type = NULL;
+
+		printf("%s: %d", m->cfg->name, m->block_dev.devnum);
+		if (mmc_type)
+			printf(" (%s)", mmc_type);
+
+		if (entry->next != &mmc_devices) {
+			printf("%c", separator);
+			if (separator != '\n')
+				puts(" ");
+		}
+	}
+
+	printf("\n");
+}
+
+#else
+void print_mmc_devices(char separator) { }
+#endif
diff --git a/drivers/mmc/mmc_private.h b/drivers/mmc/mmc_private.h
index d3f6bfe..27b9e5f 100644
--- a/drivers/mmc/mmc_private.h
+++ b/drivers/mmc/mmc_private.h
@@ -25,8 +25,13 @@
 unsigned long mmc_berase(struct blk_desc *block_dev, lbaint_t start,
 			 lbaint_t blkcnt);
 
-unsigned long mmc_bwrite(struct blk_desc *block_dev, lbaint_t start,
-			 lbaint_t blkcnt, const void *src);
+#ifdef CONFIG_BLK
+ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+		 const void *src);
+#else
+ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
+		 const void *src);
+#endif
 
 #else /* CONFIG_SPL_BUILD */
 
@@ -46,4 +51,28 @@
 
 #endif /* CONFIG_SPL_BUILD */
 
+/**
+ * mmc_get_next_devnum() - Get the next available MMC device number
+ *
+ * @return next available device number (0 = first), or -ve on error
+ */
+int mmc_get_next_devnum(void);
+
+/**
+ * mmc_do_preinit() - Get an MMC device ready for use
+ */
+void mmc_do_preinit(void);
+
+/**
+ * mmc_list_init() - Set up the list of MMC devices
+ */
+void mmc_list_init(void);
+
+/**
+ * mmc_list_add() - Add a new MMC device to the list of devices
+ *
+ * @mmc:	Device to add
+ */
+void mmc_list_add(struct mmc *mmc);
+
 #endif /* _MMC_PRIVATE_H_ */
diff --git a/drivers/mmc/mmc_write.c b/drivers/mmc/mmc_write.c
index 7b186f8..0f8b5c7 100644
--- a/drivers/mmc/mmc_write.c
+++ b/drivers/mmc/mmc_write.c
@@ -9,6 +9,7 @@
 
 #include <config.h>
 #include <common.h>
+#include <dm.h>
 #include <part.h>
 #include <div64.h>
 #include <linux/math64.h>
@@ -78,7 +79,8 @@
 	if (!mmc)
 		return -1;
 
-	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num,
+				       block_dev->hwpart);
 	if (err < 0)
 		return -1;
 
@@ -121,9 +123,9 @@
 	struct mmc_data data;
 	int timeout = 1000;
 
-	if ((start + blkcnt) > mmc->block_dev.lba) {
+	if ((start + blkcnt) > mmc_get_blk_desc(mmc)->lba) {
 		printf("MMC: block number 0x" LBAF " exceeds max(0x" LBAF ")\n",
-		       start + blkcnt, mmc->block_dev.lba);
+		       start + blkcnt, mmc_get_blk_desc(mmc)->lba);
 		return 0;
 	}
 
@@ -171,9 +173,17 @@
 	return blkcnt;
 }
 
+#ifdef CONFIG_BLK
+ulong mmc_bwrite(struct udevice *dev, lbaint_t start, lbaint_t blkcnt,
+		 const void *src)
+#else
 ulong mmc_bwrite(struct blk_desc *block_dev, lbaint_t start, lbaint_t blkcnt,
 		 const void *src)
+#endif
 {
+#ifdef CONFIG_BLK
+	struct blk_desc *block_dev = dev_get_uclass_platdata(dev);
+#endif
 	int dev_num = block_dev->devnum;
 	lbaint_t cur, blocks_todo = blkcnt;
 	int err;
@@ -182,7 +192,7 @@
 	if (!mmc)
 		return 0;
 
-	err = mmc_select_hwpart(dev_num, block_dev->hwpart);
+	err = blk_select_hwpart_devnum(IF_TYPE_MMC, dev_num, block_dev->hwpart);
 	if (err < 0)
 		return 0;
 
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 85a832b..be34057 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -825,6 +825,7 @@
 	gpio_request_by_name(dev, "wp-gpios", 0, &priv->wp_gpio, GPIOD_IS_IN);
 #endif
 
+	mmc->dev = dev;
 	upriv->mmc = mmc;
 
 	return 0;
diff --git a/drivers/mmc/pic32_sdhci.c b/drivers/mmc/pic32_sdhci.c
index e03d6dd..abe7429 100644
--- a/drivers/mmc/pic32_sdhci.c
+++ b/drivers/mmc/pic32_sdhci.c
@@ -41,7 +41,12 @@
 		return ret;
 	}
 
-	return add_sdhci(host, f_min_max[1], f_min_max[0]);
+	ret = add_sdhci(host, f_min_max[1], f_min_max[0]);
+	if (ret)
+		return ret;
+	host->mmc->dev = dev;
+
+	return 0;
 }
 
 static const struct udevice_id pic32_sdhci_ids[] = {
diff --git a/drivers/mmc/rockchip_dw_mmc.c b/drivers/mmc/rockchip_dw_mmc.c
index cb9e104..0a261c5 100644
--- a/drivers/mmc/rockchip_dw_mmc.c
+++ b/drivers/mmc/rockchip_dw_mmc.c
@@ -104,6 +104,7 @@
 	if (ret)
 		return ret;
 
+	host->mmc->dev = dev;
 	upriv->mmc = host->mmc;
 
 	return 0;
diff --git a/drivers/mmc/sandbox_mmc.c b/drivers/mmc/sandbox_mmc.c
index f4646a8..7da059c 100644
--- a/drivers/mmc/sandbox_mmc.c
+++ b/drivers/mmc/sandbox_mmc.c
@@ -8,18 +8,150 @@
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
+#include <fdtdec.h>
 #include <mmc.h>
 #include <asm/test.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct sandbox_mmc_plat {
+	struct mmc_config cfg;
+	struct mmc mmc;
+};
+
+/**
+ * sandbox_mmc_send_cmd() - Emulate SD commands
+ *
+ * This emulate an SD card version 2. Single-block reads result in zero data.
+ * Multiple-block reads return a test string.
+ */
+static int sandbox_mmc_send_cmd(struct mmc *mmc, struct mmc_cmd *cmd,
+				struct mmc_data *data)
+{
+	switch (cmd->cmdidx) {
+	case MMC_CMD_ALL_SEND_CID:
+		break;
+	case SD_CMD_SEND_RELATIVE_ADDR:
+		cmd->response[0] = 0 << 16; /* mmc->rca */
+	case MMC_CMD_GO_IDLE_STATE:
+		break;
+	case SD_CMD_SEND_IF_COND:
+		cmd->response[0] = 0xaa;
+		break;
+	case MMC_CMD_SEND_STATUS:
+		cmd->response[0] = MMC_STATUS_RDY_FOR_DATA;
+		break;
+	case MMC_CMD_SELECT_CARD:
+		break;
+	case MMC_CMD_SEND_CSD:
+		cmd->response[0] = 0;
+		cmd->response[1] = 10 << 16;	/* 1 << block_len */
+		break;
+	case SD_CMD_SWITCH_FUNC: {
+		u32 *resp = (u32 *)data->dest;
+
+		resp[7] = cpu_to_be32(SD_HIGHSPEED_BUSY);
+		break;
+	}
+	case MMC_CMD_READ_SINGLE_BLOCK:
+		memset(data->dest, '\0', data->blocksize);
+		break;
+	case MMC_CMD_READ_MULTIPLE_BLOCK:
+		strcpy(data->dest, "this is a test");
+		break;
+	case MMC_CMD_STOP_TRANSMISSION:
+		break;
+	case SD_CMD_APP_SEND_OP_COND:
+		cmd->response[0] = OCR_BUSY | OCR_HCS;
+		cmd->response[1] = 0;
+		cmd->response[2] = 0;
+		break;
+	case MMC_CMD_APP_CMD:
+		break;
+	case MMC_CMD_SET_BLOCKLEN:
+		debug("block len %d\n", cmd->cmdarg);
+		break;
+	case SD_CMD_APP_SEND_SCR: {
+		u32 *scr = (u32 *)data->dest;
+
+		scr[0] = cpu_to_be32(2 << 24 | 1 << 15);  /* SD version 3 */
+		break;
+	}
+	default:
+		debug("%s: Unknown command %d\n", __func__, cmd->cmdidx);
+		break;
+	}
+
+	return 0;
+}
+
+static void sandbox_mmc_set_ios(struct mmc *mmc)
+{
+}
+
+static int sandbox_mmc_init(struct mmc *mmc)
+{
+	return 0;
+}
+
+static int sandbox_mmc_getcd(struct mmc *mmc)
+{
+	return 1;
+}
+
+static const struct mmc_ops sandbox_mmc_ops = {
+	.send_cmd = sandbox_mmc_send_cmd,
+	.set_ios = sandbox_mmc_set_ios,
+	.init = sandbox_mmc_init,
+	.getcd = sandbox_mmc_getcd,
+};
+
+int sandbox_mmc_probe(struct udevice *dev)
+{
+	struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
+
+	return mmc_init(&plat->mmc);
+}
+
+int sandbox_mmc_bind(struct udevice *dev)
+{
+	struct sandbox_mmc_plat *plat = dev_get_platdata(dev);
+	struct mmc_config *cfg = &plat->cfg;
+	int ret;
+
+	cfg->name = dev->name;
+	cfg->ops = &sandbox_mmc_ops;
+	cfg->host_caps = MMC_MODE_HS_52MHz | MMC_MODE_HS | MMC_MODE_8BIT;
+	cfg->voltages = MMC_VDD_165_195 | MMC_VDD_32_33 | MMC_VDD_33_34;
+	cfg->f_min = 1000000;
+	cfg->f_max = 52000000;
+	cfg->b_max = U32_MAX;
+
+	ret = mmc_bind(dev, &plat->mmc, cfg);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+int sandbox_mmc_unbind(struct udevice *dev)
+{
+	mmc_unbind(dev);
+
+	return 0;
+}
+
 static const struct udevice_id sandbox_mmc_ids[] = {
 	{ .compatible = "sandbox,mmc" },
 	{ }
 };
 
-U_BOOT_DRIVER(warm_mmc_sandbox) = {
+U_BOOT_DRIVER(mmc_sandbox) = {
 	.name		= "mmc_sandbox",
 	.id		= UCLASS_MMC,
 	.of_match	= sandbox_mmc_ids,
+	.bind		= sandbox_mmc_bind,
+	.unbind		= sandbox_mmc_unbind,
+	.probe		= sandbox_mmc_probe,
+	.platdata_auto_alloc_size = sizeof(struct sandbox_mmc_plat),
 };
diff --git a/drivers/mmc/socfpga_dw_mmc.c b/drivers/mmc/socfpga_dw_mmc.c
index 097db81..6a0e971 100644
--- a/drivers/mmc/socfpga_dw_mmc.c
+++ b/drivers/mmc/socfpga_dw_mmc.c
@@ -108,6 +108,7 @@
 		return ret;
 
 	upriv->mmc = host->mmc;
+	host->mmc->dev = dev;
 
 	return 0;
 }
diff --git a/drivers/mmc/uniphier-sd.c b/drivers/mmc/uniphier-sd.c
index 81a80cd..4978cca 100644
--- a/drivers/mmc/uniphier-sd.c
+++ b/drivers/mmc/uniphier-sd.c
@@ -725,6 +725,7 @@
 		return -EIO;
 
 	upriv->mmc = priv->mmc;
+	priv->mmc->dev = dev;
 
 	return 0;
 }
diff --git a/drivers/mmc/zynq_sdhci.c b/drivers/mmc/zynq_sdhci.c
index b59feca..d405929 100644
--- a/drivers/mmc/zynq_sdhci.c
+++ b/drivers/mmc/zynq_sdhci.c
@@ -35,6 +35,7 @@
 		  CONFIG_ZYNQ_SDHCI_MIN_FREQ);
 
 	upriv->mmc = host->mmc;
+	host->mmc->dev = dev;
 
 	return 0;
 }
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
index c58841e..390e9e4 100644
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -28,6 +28,13 @@
 	  NOR flash to parallel flash interface. Please find details on the
 	  "Embedded Peripherals IP User Guide" of Altera.
 
+config FLASH_PIC32
+	bool "Microchip PIC32 Flash driver"
+	depends on MACH_PIC32 && MTD
+	help
+	  This enables access to Microchip PIC32 internal non-CFI flash
+	  chips through PIC32 Non-Volatile-Memory Controller.
+
 endmenu
 
 source "drivers/mtd/nand/Kconfig"
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
index 703700a..bd680a7 100644
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -19,5 +19,6 @@
 obj-$(CONFIG_FTSMC020) += ftsmc020.o
 obj-$(CONFIG_FLASH_CFI_LEGACY) += jedec_flash.o
 obj-$(CONFIG_MW_EEPROM) += mw_eeprom.o
+obj-$(CONFIG_FLASH_PIC32) += pic32_flash.o
 obj-$(CONFIG_ST_SMI) += st_smi.o
 obj-$(CONFIG_STM32_FLASH) += stm32_flash.o
diff --git a/drivers/mtd/pic32_flash.c b/drivers/mtd/pic32_flash.c
new file mode 100644
index 0000000..9166fcd
--- /dev/null
+++ b/drivers/mtd/pic32_flash.c
@@ -0,0 +1,444 @@
+/*
+ * Copyright (C) 2015
+ * Cristian Birsan <cristian.birsan@microchip.com>
+ * Purna Chandra Mandal <purna.mandal@microchip.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <fdt_support.h>
+#include <flash.h>
+#include <mach/pic32.h>
+#include <wait_bit.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/* NVM Controller registers */
+struct pic32_reg_nvm {
+	struct pic32_reg_atomic ctrl;
+	struct pic32_reg_atomic key;
+	struct pic32_reg_atomic addr;
+	struct pic32_reg_atomic data;
+};
+
+/* NVM operations */
+#define NVMOP_NOP		0
+#define NVMOP_WORD_WRITE	1
+#define NVMOP_PAGE_ERASE	4
+
+/* NVM control bits */
+#define NVM_WR			BIT(15)
+#define NVM_WREN		BIT(14)
+#define NVM_WRERR		BIT(13)
+#define NVM_LVDERR		BIT(12)
+
+/* NVM programming unlock register */
+#define LOCK_KEY		0x0
+#define UNLOCK_KEY1		0xaa996655
+#define UNLOCK_KEY2		0x556699aa
+
+/*
+ * PIC32 flash banks consist of number of pages, each page
+ * into number of rows and rows into number of words.
+ * Here we will maintain page information instead of sector.
+ */
+flash_info_t flash_info[CONFIG_SYS_MAX_FLASH_BANKS];
+static struct pic32_reg_nvm *nvm_regs_p;
+
+static inline void flash_initiate_operation(u32 nvmop)
+{
+	/* set operation */
+	writel(nvmop, &nvm_regs_p->ctrl.raw);
+
+	/* enable flash write */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.set);
+
+	/* unlock sequence */
+	writel(LOCK_KEY, &nvm_regs_p->key.raw);
+	writel(UNLOCK_KEY1, &nvm_regs_p->key.raw);
+	writel(UNLOCK_KEY2, &nvm_regs_p->key.raw);
+
+	/* initiate operation */
+	writel(NVM_WR, &nvm_regs_p->ctrl.set);
+}
+
+static int flash_wait_till_busy(const char *func, ulong timeout)
+{
+	int ret = wait_for_bit(__func__, &nvm_regs_p->ctrl.raw,
+			       NVM_WR, false, timeout, false);
+
+	return ret ? ERR_TIMOUT : ERR_OK;
+}
+
+static inline int flash_complete_operation(void)
+{
+	u32 tmp;
+
+	tmp = readl(&nvm_regs_p->ctrl.raw);
+	if (tmp & NVM_WRERR) {
+		printf("Error in Block Erase - Lock Bit may be set!\n");
+		flash_initiate_operation(NVMOP_NOP);
+		return ERR_PROTECTED;
+	}
+
+	if (tmp & NVM_LVDERR) {
+		printf("Error in Block Erase - low-vol detected!\n");
+		flash_initiate_operation(NVMOP_NOP);
+		return ERR_NOT_ERASED;
+	}
+
+	/* disable flash write or erase operation */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
+
+	return ERR_OK;
+}
+
+/*
+ * Erase flash sectors, returns:
+ * ERR_OK - OK
+ * ERR_INVAL - invalid sector arguments
+ * ERR_TIMOUT - write timeout
+ * ERR_NOT_ERASED - Flash not erased
+ * ERR_UNKNOWN_FLASH_VENDOR - incorrect flash
+ */
+int flash_erase(flash_info_t *info, int s_first, int s_last)
+{
+	ulong sect_start, sect_end, flags;
+	int prot, sect;
+	int rc;
+
+	if ((info->flash_id & FLASH_VENDMASK) != FLASH_MAN_MCHP) {
+		printf("Can't erase unknown flash type %08lx - aborted\n",
+		       info->flash_id);
+		return ERR_UNKNOWN_FLASH_VENDOR;
+	}
+
+	if ((s_first < 0) || (s_first > s_last)) {
+		printf("- no sectors to erase\n");
+		return ERR_INVAL;
+	}
+
+	prot = 0;
+	for (sect = s_first; sect <= s_last; ++sect) {
+		if (info->protect[sect])
+			prot++;
+	}
+
+	if (prot)
+		printf("- Warning: %d protected sectors will not be erased!\n",
+		       prot);
+	else
+		printf("\n");
+
+	/* erase on unprotected sectors */
+	for (sect = s_first; sect <= s_last; sect++) {
+		if (info->protect[sect])
+			continue;
+
+		/* disable interrupts */
+		flags = disable_interrupts();
+
+		/* write destination page address (physical) */
+		sect_start = CPHYSADDR(info->start[sect]);
+		writel(sect_start, &nvm_regs_p->addr.raw);
+
+		/* page erase */
+		flash_initiate_operation(NVMOP_PAGE_ERASE);
+
+		/* wait */
+		rc = flash_wait_till_busy(__func__,
+					  CONFIG_SYS_FLASH_ERASE_TOUT);
+
+		/* re-enable interrupts if necessary */
+		if (flags)
+			enable_interrupts();
+
+		if (rc != ERR_OK)
+			return rc;
+
+		rc = flash_complete_operation();
+		if (rc != ERR_OK)
+			return rc;
+
+		/*
+		 * flash content is updated but cache might contain stale
+		 * data, so invalidate dcache.
+		 */
+		sect_end = info->start[sect] + info->size / info->sector_count;
+		invalidate_dcache_range(info->start[sect], sect_end);
+	}
+
+	printf(" done\n");
+	return ERR_OK;
+}
+
+int page_erase(flash_info_t *info, int sect)
+{
+	return 0;
+}
+
+/* Write a word to flash */
+static int write_word(flash_info_t *info, ulong dest, ulong word)
+{
+	ulong flags;
+	int rc;
+
+	/* read flash to check if it is sufficiently erased */
+	if ((readl((void __iomem *)dest) & word) != word) {
+		printf("Error, Flash not erased!\n");
+		return ERR_NOT_ERASED;
+	}
+
+	/* disable interrupts */
+	flags = disable_interrupts();
+
+	/* update destination page address (physical) */
+	writel(CPHYSADDR(dest), &nvm_regs_p->addr.raw);
+	writel(word, &nvm_regs_p->data.raw);
+
+	/* word write */
+	flash_initiate_operation(NVMOP_WORD_WRITE);
+
+	/* wait for operation to complete */
+	rc = flash_wait_till_busy(__func__, CONFIG_SYS_FLASH_WRITE_TOUT);
+
+	/* re-enable interrupts if necessary */
+	if (flags)
+		enable_interrupts();
+
+	if (rc != ERR_OK)
+		return rc;
+
+	return flash_complete_operation();
+}
+
+/*
+ * Copy memory to flash, returns:
+ * ERR_OK - OK
+ * ERR_TIMOUT - write timeout
+ * ERR_NOT_ERASED - Flash not erased
+ */
+int write_buff(flash_info_t *info, uchar *src, ulong addr, ulong cnt)
+{
+	ulong dst, tmp_le, len = cnt;
+	int i, l, rc;
+	uchar *cp;
+
+	/* get lower word aligned address */
+	dst = (addr & ~3);
+
+	/* handle unaligned start bytes */
+	l = addr - dst;
+	if (l != 0) {
+		tmp_le = 0;
+		for (i = 0, cp = (uchar *)dst; i < l; ++i, ++cp)
+			tmp_le |= *cp << (i * 8);
+
+		for (; (i < 4) && (cnt > 0); ++i, ++src, --cnt, ++cp)
+			tmp_le |= *src << (i * 8);
+
+		for (; (cnt == 0) && (i < 4); ++i, ++cp)
+			tmp_le |= *cp << (i * 8);
+
+		rc = write_word(info, dst, tmp_le);
+		if (rc)
+			goto out;
+
+		dst += 4;
+	}
+
+	/* handle word aligned part */
+	while (cnt >= 4) {
+		tmp_le = src[0] | src[1] << 8 | src[2] << 16 | src[3] << 24;
+		rc = write_word(info, dst, tmp_le);
+		if (rc)
+			goto out;
+		src += 4;
+		dst += 4;
+		cnt -= 4;
+	}
+
+	if (cnt == 0) {
+		rc = ERR_OK;
+		goto out;
+	}
+
+	/* handle unaligned tail bytes */
+	tmp_le = 0;
+	for (i = 0, cp = (uchar *)dst; (i < 4) && (cnt > 0); ++i, ++cp) {
+		tmp_le |= *src++ << (i * 8);
+		--cnt;
+	}
+
+	for (; i < 4; ++i, ++cp)
+		tmp_le |= *cp << (i * 8);
+
+	rc = write_word(info, dst, tmp_le);
+out:
+	/*
+	 * flash content updated by nvm controller but CPU cache might
+	 * have stale data, so invalidate dcache.
+	 */
+	invalidate_dcache_range(addr, addr + len);
+
+	printf(" done\n");
+	return rc;
+}
+
+void flash_print_info(flash_info_t *info)
+{
+	int i;
+
+	if (info->flash_id == FLASH_UNKNOWN) {
+		printf("missing or unknown FLASH type\n");
+		return;
+	}
+
+	switch (info->flash_id & FLASH_VENDMASK) {
+	case FLASH_MAN_MCHP:
+		printf("Microchip Technology ");
+		break;
+	default:
+		printf("Unknown Vendor ");
+		break;
+	}
+
+	switch (info->flash_id & FLASH_TYPEMASK) {
+	case FLASH_MCHP100T:
+		printf("Internal (8 Mbit, 64 x 16k)\n");
+		break;
+	default:
+		printf("Unknown Chip Type\n");
+		break;
+	}
+
+	printf("  Size: %ld MB in %d Sectors\n",
+	       info->size >> 20, info->sector_count);
+
+	printf("  Sector Start Addresses:");
+	for (i = 0; i < info->sector_count; ++i) {
+		if ((i % 5) == 0)
+			printf("\n   ");
+
+		printf(" %08lX%s", info->start[i],
+		       info->protect[i] ? " (RO)" : "     ");
+	}
+	printf("\n");
+}
+
+unsigned long flash_init(void)
+{
+	unsigned long size = 0;
+	struct udevice *dev;
+	int bank;
+
+	/* probe every MTD device */
+	for (uclass_first_device(UCLASS_MTD, &dev); dev;
+	     uclass_next_device(&dev)) {
+		/* nop */
+	}
+
+	/* calc total flash size */
+	for (bank = 0; bank < CONFIG_SYS_MAX_FLASH_BANKS; ++bank)
+		size += flash_info[bank].size;
+
+	return size;
+}
+
+static void pic32_flash_bank_init(flash_info_t *info,
+				  ulong base, ulong size)
+{
+	ulong sect_size;
+	int sect;
+
+	/* device & manufacturer code */
+	info->flash_id = FLASH_MAN_MCHP | FLASH_MCHP100T;
+	info->sector_count = CONFIG_SYS_MAX_FLASH_SECT;
+	info->size = size;
+
+	/* update sector (i.e page) info */
+	sect_size = info->size / info->sector_count;
+	for (sect = 0; sect < info->sector_count; sect++) {
+		info->start[sect] = base;
+		/* protect each sector by default */
+		info->protect[sect] = 1;
+		base += sect_size;
+	}
+}
+
+static int pic32_flash_probe(struct udevice *dev)
+{
+	void *blob = (void *)gd->fdt_blob;
+	int node = dev->of_offset;
+	const char *list, *end;
+	const fdt32_t *cell;
+	unsigned long addr, size;
+	int parent, addrc, sizec;
+	flash_info_t *info;
+	int len, idx;
+
+	/*
+	 * decode regs. there are multiple reg tuples, and they need to
+	 * match with reg-names.
+	 */
+	parent = fdt_parent_offset(blob, node);
+	of_bus_default_count_cells(blob, parent, &addrc, &sizec);
+	list = fdt_getprop(blob, node, "reg-names", &len);
+	if (!list)
+		return -ENOENT;
+
+	end = list + len;
+	cell = fdt_getprop(blob, node, "reg", &len);
+	if (!cell)
+		return -ENOENT;
+
+	for (idx = 0, info = &flash_info[0]; list < end;) {
+		addr = fdt_translate_address((void *)blob, node, cell + idx);
+		size = fdt_addr_to_cpu(cell[idx + addrc]);
+		len = strlen(list);
+		if (!strncmp(list, "nvm", len)) {
+			/* NVM controller */
+			nvm_regs_p = ioremap(addr, size);
+		} else if (!strncmp(list, "bank", 4)) {
+			/* Flash bank: use kseg0 cached address */
+			pic32_flash_bank_init(info, CKSEG0ADDR(addr), size);
+			info++;
+		}
+		idx += addrc + sizec;
+		list += len + 1;
+	}
+
+	/* disable flash write/erase operations */
+	writel(NVM_WREN, &nvm_regs_p->ctrl.clr);
+
+#if (CONFIG_SYS_MONITOR_BASE >= CONFIG_SYS_FLASH_BASE)
+	/* monitor protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CONFIG_SYS_MONITOR_BASE,
+		      CONFIG_SYS_MONITOR_BASE + monitor_flash_len - 1,
+		      &flash_info[0]);
+#endif
+
+#ifdef CONFIG_ENV_IS_IN_FLASH
+	/* ENV protection ON by default */
+	flash_protect(FLAG_PROTECT_SET,
+		      CONFIG_ENV_ADDR,
+		      CONFIG_ENV_ADDR + CONFIG_ENV_SECT_SIZE - 1,
+		      &flash_info[0]);
+#endif
+	return 0;
+}
+
+static const struct udevice_id pic32_flash_ids[] = {
+	{ .compatible = "microchip,pic32mzda-flash" },
+	{}
+};
+
+U_BOOT_DRIVER(pic32_flash) = {
+	.name	= "pic32_flash",
+	.id	= UCLASS_MTD,
+	.of_match = pic32_flash_ids,
+	.probe	= pic32_flash_probe,
+};
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 4619089..4b73a0f 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -175,11 +175,7 @@
 	int bus;
 
 	for (hose = pci_get_hose_head(); hose; hose = hose->next) {
-#ifdef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
-		for (bus = hose->last_busno; bus >= hose->first_busno; bus--) {
-#else
 		for (bus = hose->first_busno; bus <= hose->last_busno; bus++) {
-#endif
 			bdf = pci_hose_find_devices(hose, bus, ids, &index);
 			if (bdf != -1)
 				return bdf;
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index 2a69bab..567b766 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -105,6 +105,24 @@
 
 if PINCTRL || SPL_PINCTRL
 
+config AR933X_PINCTRL
+	bool "QCA/Athores ar933x pin control driver"
+	depends on DM && SOC_AR933X
+	help
+	  Support pin multiplexing control on QCA/Athores ar933x SoCs.
+	  The driver is controlled by a device tree node which contains
+	  both the GPIO definitions and pin control functions for each
+	  available multiplex function.
+
+config QCA953X_PINCTRL
+	bool "QCA/Athores qca953x pin control driver"
+	depends on DM && SOC_QCA953X
+	help
+	  Support pin multiplexing control on QCA/Athores qca953x SoCs.
+	  The driver is controlled by a device tree node which contains
+	  both the GPIO definitions and pin control functions for each
+	  available multiplex function.
+
 config ROCKCHIP_PINCTRL
 	bool "Rockchip pin control driver"
 	depends on DM
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 37dc904..b99ed2f 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -6,6 +6,7 @@
 obj-$(CONFIG_$(SPL_)PINCTRL_GENERIC)	+= pinctrl-generic.o
 
 obj-y					+= nxp/
+obj-$(CONFIG_ARCH_ATH79) += ath79/
 obj-$(CONFIG_ARCH_ROCKCHIP) += rockchip/
 obj-$(CONFIG_PINCTRL_SANDBOX)	+= pinctrl-sandbox.o
 
diff --git a/drivers/pinctrl/ath79/Makefile b/drivers/pinctrl/ath79/Makefile
new file mode 100644
index 0000000..dcea10a
--- /dev/null
+++ b/drivers/pinctrl/ath79/Makefile
@@ -0,0 +1,6 @@
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_AR933X_PINCTRL) += pinctrl_ar933x.o
+obj-$(CONFIG_QCA953x_PINCTRL) += pinctrl_qca953x.o
diff --git a/drivers/pinctrl/ath79/pinctrl_ar933x.c b/drivers/pinctrl/ath79/pinctrl_ar933x.c
new file mode 100644
index 0000000..e3f64b6
--- /dev/null
+++ b/drivers/pinctrl/ath79/pinctrl_ar933x.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum periph_id {
+	PERIPH_ID_UART0,
+	PERIPH_ID_SPI0,
+	PERIPH_ID_NONE = -1,
+};
+
+struct ar933x_pinctrl_priv {
+	void __iomem *regs;
+};
+
+static void pinctrl_ar933x_spi_config(struct ar933x_pinctrl_priv *priv, int cs)
+{
+	switch (cs) {
+	case 0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				AR933X_GPIO(4), AR933X_GPIO(3) |
+				AR933X_GPIO(5) | AR933X_GPIO(2));
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
+			     AR933X_GPIO_FUNC_SPI_EN |
+			     AR933X_GPIO_FUNC_RES_TRUE);
+		break;
+	}
+}
+
+static void pinctrl_ar933x_uart_config(struct ar933x_pinctrl_priv *priv, int uart_id)
+{
+	switch (uart_id) {
+	case PERIPH_ID_UART0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				AR933X_GPIO(9), AR933X_GPIO(10));
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_FUNC,
+			     AR933X_GPIO_FUNC_UART_EN |
+			     AR933X_GPIO_FUNC_RES_TRUE);
+		break;
+	}
+}
+
+static int ar933x_pinctrl_request(struct udevice *dev, int func, int flags)
+{
+	struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
+
+	debug("%s: func=%x, flags=%x\n", __func__, func, flags);
+	switch (func) {
+	case PERIPH_ID_SPI0:
+		pinctrl_ar933x_spi_config(priv, flags);
+		break;
+	case PERIPH_ID_UART0:
+		pinctrl_ar933x_uart_config(priv, func);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int ar933x_pinctrl_get_periph_id(struct udevice *dev,
+					struct udevice *periph)
+{
+	u32 cell[2];
+	int ret;
+
+	ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
+				   "interrupts", cell, ARRAY_SIZE(cell));
+	if (ret < 0)
+		return -EINVAL;
+
+	switch (cell[0]) {
+	case 128:
+		return PERIPH_ID_UART0;
+	case 129:
+		return PERIPH_ID_SPI0;
+	}
+	return -ENOENT;
+}
+
+static int ar933x_pinctrl_set_state_simple(struct udevice *dev,
+					   struct udevice *periph)
+{
+	int func;
+
+	func = ar933x_pinctrl_get_periph_id(dev, periph);
+	if (func < 0)
+		return func;
+	return ar933x_pinctrl_request(dev, func, 0);
+}
+
+static struct pinctrl_ops ar933x_pinctrl_ops = {
+	.set_state_simple	= ar933x_pinctrl_set_state_simple,
+	.request	= ar933x_pinctrl_request,
+	.get_periph_id	= ar933x_pinctrl_get_periph_id,
+};
+
+static int ar933x_pinctrl_probe(struct udevice *dev)
+{
+	struct ar933x_pinctrl_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_GPIO_SIZE,
+				 MAP_NOCACHE);
+	return 0;
+}
+
+static const struct udevice_id ar933x_pinctrl_ids[] = {
+	{ .compatible = "qca,ar933x-pinctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_ar933x) = {
+	.name		= "pinctrl_ar933x",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= ar933x_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct ar933x_pinctrl_priv),
+	.ops		= &ar933x_pinctrl_ops,
+	.probe		= ar933x_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/ath79/pinctrl_qca953x.c b/drivers/pinctrl/ath79/pinctrl_qca953x.c
new file mode 100644
index 0000000..d02597e
--- /dev/null
+++ b/drivers/pinctrl/ath79/pinctrl_qca953x.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+enum periph_id {
+	PERIPH_ID_UART0,
+	PERIPH_ID_SPI0,
+	PERIPH_ID_NONE = -1,
+};
+
+struct qca953x_pinctrl_priv {
+	void __iomem *regs;
+};
+
+static void pinctrl_qca953x_spi_config(struct qca953x_pinctrl_priv *priv, int cs)
+{
+	switch (cs) {
+	case 0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				QCA953X_GPIO(5) | QCA953X_GPIO(6) |
+				QCA953X_GPIO(7), QCA953X_GPIO(8));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC1,
+				QCA953X_GPIO_MUX_MASK(8) |
+				QCA953X_GPIO_MUX_MASK(16) |
+				QCA953X_GPIO_MUX_MASK(24),
+				(QCA953X_GPIO_OUT_MUX_SPI_CS0 << 8) |
+				(QCA953X_GPIO_OUT_MUX_SPI_CLK << 16) |
+				(QCA953X_GPIO_OUT_MUX_SPI_MOSI << 24));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
+				QCA953X_GPIO_MUX_MASK(0),
+				QCA953X_GPIO_IN_MUX_SPI_DATA_IN);
+
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
+			     QCA953X_GPIO(8));
+		break;
+	}
+}
+
+static void pinctrl_qca953x_uart_config(struct qca953x_pinctrl_priv *priv, int uart_id)
+{
+	switch (uart_id) {
+	case PERIPH_ID_UART0:
+		clrsetbits_be32(priv->regs + AR71XX_GPIO_REG_OE,
+				QCA953X_GPIO(9), QCA953X_GPIO(10));
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_OUT_FUNC2,
+				QCA953X_GPIO_MUX_MASK(16),
+				QCA953X_GPIO_OUT_MUX_UART0_SOUT << 16);
+
+		clrsetbits_be32(priv->regs + QCA953X_GPIO_REG_IN_ENABLE0,
+				QCA953X_GPIO_MUX_MASK(8),
+				QCA953X_GPIO_IN_MUX_UART0_SIN << 8);
+
+		setbits_be32(priv->regs + AR71XX_GPIO_REG_OUT,
+			     QCA953X_GPIO(10));
+		break;
+	}
+}
+
+static int qca953x_pinctrl_request(struct udevice *dev, int func, int flags)
+{
+	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
+
+	debug("%s: func=%x, flags=%x\n", __func__, func, flags);
+	switch (func) {
+	case PERIPH_ID_SPI0:
+		pinctrl_qca953x_spi_config(priv, flags);
+		break;
+	case PERIPH_ID_UART0:
+		pinctrl_qca953x_uart_config(priv, func);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int qca953x_pinctrl_get_periph_id(struct udevice *dev,
+					struct udevice *periph)
+{
+	u32 cell[2];
+	int ret;
+
+	ret = fdtdec_get_int_array(gd->fdt_blob, periph->of_offset,
+				   "interrupts", cell, ARRAY_SIZE(cell));
+	if (ret < 0)
+		return -EINVAL;
+
+	switch (cell[0]) {
+	case 128:
+		return PERIPH_ID_UART0;
+	case 129:
+		return PERIPH_ID_SPI0;
+	}
+	return -ENOENT;
+}
+
+static int qca953x_pinctrl_set_state_simple(struct udevice *dev,
+					   struct udevice *periph)
+{
+	int func;
+
+	func = qca953x_pinctrl_get_periph_id(dev, periph);
+	if (func < 0)
+		return func;
+	return qca953x_pinctrl_request(dev, func, 0);
+}
+
+static struct pinctrl_ops qca953x_pinctrl_ops = {
+	.set_state_simple	= qca953x_pinctrl_set_state_simple,
+	.request	= qca953x_pinctrl_request,
+	.get_periph_id	= qca953x_pinctrl_get_periph_id,
+};
+
+static int qca953x_pinctrl_probe(struct udevice *dev)
+{
+	struct qca953x_pinctrl_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_GPIO_SIZE,
+				 MAP_NOCACHE);
+	return 0;
+}
+
+static const struct udevice_id qca953x_pinctrl_ids[] = {
+	{ .compatible = "qca,qca953x-pinctrl" },
+	{ }
+};
+
+U_BOOT_DRIVER(pinctrl_qca953x) = {
+	.name		= "pinctrl_qca953x",
+	.id		= UCLASS_PINCTRL,
+	.of_match	= qca953x_pinctrl_ids,
+	.priv_auto_alloc_size = sizeof(struct qca953x_pinctrl_priv),
+	.ops		= &qca953x_pinctrl_ops,
+	.probe		= qca953x_pinctrl_probe,
+};
diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig
index a9a5d47..2497ae9 100644
--- a/drivers/serial/Kconfig
+++ b/drivers/serial/Kconfig
@@ -89,6 +89,15 @@
 	  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_AR933X
+	bool "QCA/Atheros ar933x"
+	depends on AR933X_UART
+	help
+	  Select this to enable a debug UART using the ar933x uart 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_NS16550
 	bool "ns16550"
 	help
@@ -263,6 +272,15 @@
 	  Select this to enable an UART for Altera devices. Please find
 	  details on the "Embedded Peripherals IP User Guide" of Altera.
 
+config AR933X_UART
+	bool "QCA/Atheros ar933x UART support"
+	depends on DM_SERIAL && SOC_AR933X
+	help
+	  Select this to enable UART support for QCA/Atheros ar933x
+	  devices. This driver uses driver model and requires a device
+	  tree binding to operate, please refer to the document at
+	  doc/device-tree-bindings/serial/qca,ar9330-uart.txt.
+
 config FSL_LPUART
 	bool "Freescale LPUART support"
 	help
diff --git a/drivers/serial/Makefile b/drivers/serial/Makefile
index b0ac9d8..9def128 100644
--- a/drivers/serial/Makefile
+++ b/drivers/serial/Makefile
@@ -17,6 +17,7 @@
 
 obj-$(CONFIG_ALTERA_UART) += altera_uart.o
 obj-$(CONFIG_ALTERA_JTAG_UART) += altera_jtag_uart.o
+obj-$(CONFIG_AR933X_UART) += serial_ar933x.o
 obj-$(CONFIG_ARM_DCC) += arm_dcc.o
 obj-$(CONFIG_ATMEL_USART) += atmel_usart.o
 obj-$(CONFIG_EFI_APP) += serial_efi.o
diff --git a/drivers/serial/mcfuart.c b/drivers/serial/mcfuart.c
index 407354f..059cb0f 100644
--- a/drivers/serial/mcfuart.c
+++ b/drivers/serial/mcfuart.c
@@ -2,6 +2,9 @@
  * (C) Copyright 2004-2007 Freescale Semiconductor, Inc.
  * TsiChung Liew, Tsi-Chung.Liew@freescale.com.
  *
+ * Modified to add device model (DM) support
+ * (C) Copyright 2015  Angelo Dureghello <angelo@sysam.it>
+ *
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
@@ -11,9 +14,10 @@
  */
 
 #include <common.h>
+#include <dm.h>
+#include <dm/platform_data/serial_coldfire.h>
 #include <serial.h>
 #include <linux/compiler.h>
-
 #include <asm/immap.h>
 #include <asm/uart.h>
 
@@ -21,91 +25,110 @@
 
 extern void uart_port_conf(int port);
 
-static int mcf_serial_init(void)
+static int mcf_serial_init_common(uart_t *uart, int port_idx, int baudrate)
 {
-	volatile uart_t *uart;
 	u32 counter;
 
-	uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
-
-	uart_port_conf(CONFIG_SYS_UART_PORT);
+	uart_port_conf(port_idx);
 
 	/* write to SICR: SIM2 = uart mode,dcd does not affect rx */
-	uart->ucr = UART_UCR_RESET_RX;
-	uart->ucr = UART_UCR_RESET_TX;
-	uart->ucr = UART_UCR_RESET_ERROR;
-	uart->ucr = UART_UCR_RESET_MR;
+	writeb(UART_UCR_RESET_RX, &uart->ucr);
+	writeb(UART_UCR_RESET_TX, &uart->ucr);
+	writeb(UART_UCR_RESET_ERROR, &uart->ucr);
+	writeb(UART_UCR_RESET_MR, &uart->ucr);
 	__asm__("nop");
 
-	uart->uimr = 0;
+	writeb(0, &uart->uimr);
 
 	/* write to CSR: RX/TX baud rate from timers */
-	uart->ucsr = (UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK);
+	writeb(UART_UCSR_RCS_SYS_CLK | UART_UCSR_TCS_SYS_CLK, &uart->ucsr);
 
-	uart->umr = (UART_UMR_BC_8 | UART_UMR_PM_NONE);
-	uart->umr = UART_UMR_SB_STOP_BITS_1;
+	writeb(UART_UMR_BC_8 | UART_UMR_PM_NONE, &uart->umr);
+	writeb(UART_UMR_SB_STOP_BITS_1, &uart->umr);
 
 	/* Setting up BaudRate */
-	counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
-	counter = counter / gd->baudrate;
+	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
+	counter = counter / baudrate;
 
 	/* write to CTUR: divide counter upper byte */
-	uart->ubg1 = (u8) ((counter & 0xff00) >> 8);
+	writeb((u8)((counter & 0xff00) >> 8), &uart->ubg1);
 	/* write to CTLR: divide counter lower byte */
-	uart->ubg2 = (u8) (counter & 0x00ff);
+	writeb((u8)(counter & 0x00ff), &uart->ubg2);
 
-	uart->ucr = (UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED);
+	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
 
 	return (0);
 }
 
+static void mcf_serial_setbrg_common(uart_t *uart, int baudrate)
+{
+	u32 counter;
+
+	/* Setting up BaudRate */
+	counter = (u32) ((gd->bus_clk / 32) + (baudrate / 2));
+	counter = counter / baudrate;
+
+	/* write to CTUR: divide counter upper byte */
+	writeb(((counter & 0xff00) >> 8), &uart->ubg1);
+	/* write to CTLR: divide counter lower byte */
+	writeb((counter & 0x00ff), &uart->ubg2);
+
+	writeb(UART_UCR_RESET_RX, &uart->ucr);
+	writeb(UART_UCR_RESET_TX, &uart->ucr);
+
+	writeb(UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED, &uart->ucr);
+}
+
+#ifndef CONFIG_DM_SERIAL
+
+static int mcf_serial_init(void)
+{
+	uart_t *uart_base;
+	int port_idx;
+
+	uart_base = (uart_t *)CONFIG_SYS_UART_BASE;
+	port_idx = CONFIG_SYS_UART_PORT;
+
+	return mcf_serial_init_common(uart_base, port_idx, gd->baudrate);
+}
+
 static void mcf_serial_putc(const char c)
 {
-	volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
+	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
 
 	if (c == '\n')
 		serial_putc('\r');
 
 	/* Wait for last character to go. */
-	while (!(uart->usr & UART_USR_TXRDY)) ;
+	while (!(readb(&uart->usr) & UART_USR_TXRDY))
+		;
 
-	uart->utb = c;
+	writeb(c, &uart->utb);
 }
 
 static int mcf_serial_getc(void)
 {
-	volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
+	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
 
 	/* Wait for a character to arrive. */
-	while (!(uart->usr & UART_USR_RXRDY)) ;
-	return uart->urb;
-}
+	while (!(readb(&uart->usr) & UART_USR_RXRDY))
+		;
 
-static int mcf_serial_tstc(void)
-{
-	volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
-
-	return (uart->usr & UART_USR_RXRDY);
+	return readb(&uart->urb);
 }
 
 static void mcf_serial_setbrg(void)
 {
-	volatile uart_t *uart = (volatile uart_t *)(CONFIG_SYS_UART_BASE);
-	u32 counter;
+	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
 
-	/* Setting up BaudRate */
-	counter = (u32) ((gd->bus_clk / 32) + (gd->baudrate / 2));
-	counter = counter / gd->baudrate;
+	mcf_serial_setbrg_common(uart, gd->baudrate);
+}
 
-	/* write to CTUR: divide counter upper byte */
-	uart->ubg1 = ((counter & 0xff00) >> 8);
-	/* write to CTLR: divide counter lower byte */
-	uart->ubg2 = (counter & 0x00ff);
+static int mcf_serial_tstc(void)
+{
+	uart_t *uart = (uart_t *)CONFIG_SYS_UART_BASE;
 
-	uart->ucr = UART_UCR_RESET_RX;
-	uart->ucr = UART_UCR_RESET_TX;
-
-	uart->ucr = UART_UCR_RX_ENABLED | UART_UCR_TX_ENABLED;
+	return readb(&uart->usr) & UART_USR_RXRDY;
 }
 
 static struct serial_device mcf_serial_drv = {
@@ -128,3 +151,80 @@
 {
 	return &mcf_serial_drv;
 }
+
+#endif
+
+#ifdef CONFIG_DM_SERIAL
+
+static int coldfire_serial_probe(struct udevice *dev)
+{
+	struct coldfire_serial_platdata *plat = dev->platdata;
+
+	return mcf_serial_init_common((uart_t *)plat->base,
+						plat->port, plat->baudrate);
+}
+
+static int coldfire_serial_putc(struct udevice *dev, const char ch)
+{
+	struct coldfire_serial_platdata *plat = dev->platdata;
+	uart_t *uart = (uart_t *)plat->base;
+
+	/* Wait for last character to go. */
+	if (!(readb(&uart->usr) & UART_USR_TXRDY))
+		return -EAGAIN;
+
+	writeb(ch, &uart->utb);
+
+	return 0;
+}
+
+static int coldfire_serial_getc(struct udevice *dev)
+{
+	struct coldfire_serial_platdata *plat = dev->platdata;
+	uart_t *uart = (uart_t *)(plat->base);
+
+	/* Wait for a character to arrive. */
+	if (!(readb(&uart->usr) & UART_USR_RXRDY))
+		return -EAGAIN;
+
+	return readb(&uart->urb);
+}
+
+int coldfire_serial_setbrg(struct udevice *dev, int baudrate)
+{
+	struct coldfire_serial_platdata *plat = dev->platdata;
+	uart_t *uart = (uart_t *)(plat->base);
+
+	mcf_serial_setbrg_common(uart, baudrate);
+
+	return 0;
+}
+
+static int coldfire_serial_pending(struct udevice *dev, bool input)
+{
+	struct coldfire_serial_platdata *plat = dev->platdata;
+	uart_t *uart = (uart_t *)(plat->base);
+
+	if (input)
+		return readb(&uart->usr) & UART_USR_RXRDY ? 1 : 0;
+	else
+		return readb(&uart->usr) & UART_USR_TXRDY ? 0 : 1;
+
+	return 0;
+}
+
+static const struct dm_serial_ops coldfire_serial_ops = {
+	.putc = coldfire_serial_putc,
+	.pending = coldfire_serial_pending,
+	.getc = coldfire_serial_getc,
+	.setbrg = coldfire_serial_setbrg,
+};
+
+U_BOOT_DRIVER(serial_coldfire) = {
+	.name = "serial_coldfire",
+	.id = UCLASS_SERIAL,
+	.probe = coldfire_serial_probe,
+	.ops = &coldfire_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+#endif
diff --git a/drivers/serial/serial_ar933x.c b/drivers/serial/serial_ar933x.c
new file mode 100644
index 0000000..aae66dc
--- /dev/null
+++ b/drivers/serial/serial_ar933x.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <div64.h>
+#include <errno.h>
+#include <serial.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+#define AR933X_UART_DATA_REG            0x00
+#define AR933X_UART_CS_REG              0x04
+#define AR933X_UART_CLK_REG             0x08
+
+#define AR933X_UART_DATA_TX_RX_MASK     0xff
+#define AR933X_UART_DATA_RX_CSR         BIT(8)
+#define AR933X_UART_DATA_TX_CSR         BIT(9)
+#define AR933X_UART_CS_IF_MODE_S        2
+#define AR933X_UART_CS_IF_MODE_M        0x3
+#define AR933X_UART_CS_IF_MODE_DTE      1
+#define AR933X_UART_CS_IF_MODE_DCE      2
+#define AR933X_UART_CS_TX_RDY_ORIDE     BIT(7)
+#define AR933X_UART_CS_RX_RDY_ORIDE     BIT(8)
+#define AR933X_UART_CLK_STEP_M          0xffff
+#define AR933X_UART_CLK_SCALE_M         0xfff
+#define AR933X_UART_CLK_SCALE_S         16
+#define AR933X_UART_CLK_STEP_S          0
+
+struct ar933x_serial_priv {
+	void __iomem *regs;
+};
+
+/*
+ * Baudrate algorithm come from Linux/drivers/tty/serial/ar933x_uart.c
+ * baudrate = (clk / (scale + 1)) * (step * (1 / 2^17))
+ */
+static u32 ar933x_serial_get_baud(u32 clk, u32 scale, u32 step)
+{
+	u64 t;
+	u32 div;
+
+	div = (2 << 16) * (scale + 1);
+	t = clk;
+	t *= step;
+	t += (div / 2);
+	do_div(t, div);
+
+	return t;
+}
+
+static void ar933x_serial_get_scale_step(u32 clk, u32 baud,
+					 u32 *scale, u32 *step)
+{
+	u32 tscale, baudrate;
+	long min_diff;
+
+	*scale = 0;
+	*step = 0;
+
+	min_diff = baud;
+	for (tscale = 0; tscale < AR933X_UART_CLK_SCALE_M; tscale++) {
+		u64 tstep;
+		int diff;
+
+		tstep = baud * (tscale + 1);
+		tstep *= (2 << 16);
+		do_div(tstep, clk);
+
+		if (tstep > AR933X_UART_CLK_STEP_M)
+			break;
+
+		baudrate = ar933x_serial_get_baud(clk, tscale, tstep);
+		diff = abs(baudrate - baud);
+		if (diff < min_diff) {
+			min_diff = diff;
+			*scale = tscale;
+			*step = tstep;
+		}
+	}
+}
+
+static int ar933x_serial_setbrg(struct udevice *dev, int baudrate)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 val, scale, step;
+
+	val = get_serial_clock();
+	ar933x_serial_get_scale_step(val, baudrate, &scale, &step);
+
+	val  = (scale & AR933X_UART_CLK_SCALE_M)
+			<< AR933X_UART_CLK_SCALE_S;
+	val |= (step & AR933X_UART_CLK_STEP_M)
+			<< AR933X_UART_CLK_STEP_S;
+	writel(val, priv->regs + AR933X_UART_CLK_REG);
+
+	return 0;
+}
+
+static int ar933x_serial_putc(struct udevice *dev, const char c)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (!(data & AR933X_UART_DATA_TX_CSR))
+		return -EAGAIN;
+
+	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
+	writel(data, priv->regs + AR933X_UART_DATA_REG);
+
+	return 0;
+}
+
+static int ar933x_serial_getc(struct udevice *dev)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (!(data & AR933X_UART_DATA_RX_CSR))
+		return -EAGAIN;
+
+	writel(AR933X_UART_DATA_RX_CSR, priv->regs + AR933X_UART_DATA_REG);
+	return data & AR933X_UART_DATA_TX_RX_MASK;
+}
+
+static int ar933x_serial_pending(struct udevice *dev, bool input)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	u32 data;
+
+	data = readl(priv->regs + AR933X_UART_DATA_REG);
+	if (input)
+		return (data & AR933X_UART_DATA_RX_CSR) ? 1 : 0;
+	else
+		return (data & AR933X_UART_DATA_TX_CSR) ? 0 : 1;
+}
+
+static int ar933x_serial_probe(struct udevice *dev)
+{
+	struct ar933x_serial_priv *priv = dev_get_priv(dev);
+	fdt_addr_t addr;
+	u32 val;
+
+	addr = dev_get_addr(dev);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr, AR933X_UART_SIZE,
+				 MAP_NOCACHE);
+
+	/*
+	 * UART controller configuration:
+	 * - no DMA
+	 * - no interrupt
+	 * - DCE mode
+	 * - no flow control
+	 * - set RX ready oride
+	 * - set TX ready oride
+	 */
+	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
+	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
+	writel(val, priv->regs + AR933X_UART_CS_REG);
+	return 0;
+}
+
+static const struct dm_serial_ops ar933x_serial_ops = {
+	.putc = ar933x_serial_putc,
+	.pending = ar933x_serial_pending,
+	.getc = ar933x_serial_getc,
+	.setbrg = ar933x_serial_setbrg,
+};
+
+static const struct udevice_id ar933x_serial_ids[] = {
+	{ .compatible = "qca,ar9330-uart" },
+	{ }
+};
+
+U_BOOT_DRIVER(serial_ar933x) = {
+	.name   = "serial_ar933x",
+	.id = UCLASS_SERIAL,
+	.of_match = ar933x_serial_ids,
+	.priv_auto_alloc_size = sizeof(struct ar933x_serial_priv),
+	.probe = ar933x_serial_probe,
+	.ops    = &ar933x_serial_ops,
+	.flags = DM_FLAG_PRE_RELOC,
+};
+
+#ifdef CONFIG_DEBUG_UART_AR933X
+
+#include <debug_uart.h>
+
+static inline void _debug_uart_init(void)
+{
+	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
+	u32 val, scale, step;
+
+	/*
+	 * UART controller configuration:
+	 * - no DMA
+	 * - no interrupt
+	 * - DCE mode
+	 * - no flow control
+	 * - set RX ready oride
+	 * - set TX ready oride
+	 */
+	val = (AR933X_UART_CS_IF_MODE_DCE << AR933X_UART_CS_IF_MODE_S) |
+	      AR933X_UART_CS_TX_RDY_ORIDE | AR933X_UART_CS_RX_RDY_ORIDE;
+	writel(val, regs + AR933X_UART_CS_REG);
+
+	ar933x_serial_get_scale_step(CONFIG_DEBUG_UART_CLOCK,
+				     CONFIG_BAUDRATE, &scale, &step);
+
+	val  = (scale & AR933X_UART_CLK_SCALE_M)
+			<< AR933X_UART_CLK_SCALE_S;
+	val |= (step & AR933X_UART_CLK_STEP_M)
+			<< AR933X_UART_CLK_STEP_S;
+	writel(val, regs + AR933X_UART_CLK_REG);
+}
+
+static inline void _debug_uart_putc(int c)
+{
+	void __iomem *regs = (void *)CONFIG_DEBUG_UART_BASE;
+	u32 data;
+
+	do {
+		data = readl(regs + AR933X_UART_DATA_REG);
+	} while (!(data & AR933X_UART_DATA_TX_CSR));
+
+	data  = (u32)c | AR933X_UART_DATA_TX_CSR;
+	writel(data, regs + AR933X_UART_DATA_REG);
+}
+
+DEBUG_UART_FUNCS
+
+#endif
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index f0258f8..b7fd8e5 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -23,6 +23,15 @@
 	  IP core. Please find details on the "Embedded Peripherals IP
 	  User Guide" of Altera.
 
+config ATH79_SPI
+	bool "Atheros SPI driver"
+	depends on ARCH_ATH79
+	help
+	  Enable the Atheros ar7xxx/ar9xxx SoC SPI driver, it was used
+	  to access SPI NOR flash and other SPI peripherals. This driver
+	  uses driver model and requires a device tree binding to operate.
+	  please refer to doc/device-tree-bindings/spi/spi-ath79.txt.
+
 config CADENCE_QSPI
 	bool "Cadence QSPI driver"
 	help
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 3eca745..7fb2926 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -17,6 +17,7 @@
 
 obj-$(CONFIG_ALTERA_SPI) += altera_spi.o
 obj-$(CONFIG_ARMADA100_SPI) += armada100_spi.o
+obj-$(CONFIG_ATH79_SPI) += ath79_spi.o
 obj-$(CONFIG_ATMEL_DATAFLASH_SPI) += atmel_dataflash_spi.o
 obj-$(CONFIG_ATMEL_SPI) += atmel_spi.o
 obj-$(CONFIG_BFIN_SPI) += bfin_spi.o
diff --git a/drivers/spi/ath79_spi.c b/drivers/spi/ath79_spi.c
new file mode 100644
index 0000000..b18c733
--- /dev/null
+++ b/drivers/spi/ath79_spi.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <common.h>
+#include <spi.h>
+#include <dm.h>
+#include <div64.h>
+#include <errno.h>
+#include <asm/io.h>
+#include <asm/addrspace.h>
+#include <asm/types.h>
+#include <dm/pinctrl.h>
+#include <mach/ar71xx_regs.h>
+
+/* CLOCK_DIVIDER = 3 (SPI clock = 200 / 8 ~ 25 MHz) */
+#define ATH79_SPI_CLK_DIV(x)           (((x) >> 1) - 1)
+#define ATH79_SPI_RRW_DELAY_FACTOR     12000
+#define ATH79_SPI_MHZ                  (1000 * 1000)
+
+struct ath79_spi_priv {
+	void __iomem *regs;
+	u32 rrw_delay;
+};
+
+static void spi_cs_activate(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
+}
+
+static void spi_cs_deactivate(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+
+	writel(AR71XX_SPI_IOC_CS_ALL, priv->regs + AR71XX_SPI_REG_IOC);
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+}
+
+static int ath79_spi_claim_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+static int ath79_spi_release_bus(struct udevice *dev)
+{
+	return 0;
+}
+
+static int ath79_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	struct dm_spi_slave_platdata *slave = dev_get_parent_platdata(dev);
+	u8 *rx = din;
+	const u8 *tx = dout;
+	u8 curbyte, curbitlen, restbits;
+	u32 bytes = bitlen / 8;
+	u32 out, in;
+	u64 tick;
+
+	if (flags & SPI_XFER_BEGIN)
+		spi_cs_activate(dev);
+
+	restbits = (bitlen % 8);
+	if (restbits)
+		bytes++;
+
+	out = AR71XX_SPI_IOC_CS_ALL & ~(AR71XX_SPI_IOC_CS(slave->cs));
+	while (bytes > 0) {
+		bytes--;
+		curbyte = 0;
+		if (tx)
+			curbyte = *tx++;
+
+		if (restbits && !bytes) {
+			curbitlen = restbits;
+			curbyte <<= 8 - restbits;
+		} else {
+			curbitlen = 8;
+		}
+
+		for (curbyte <<= (8 - curbitlen); curbitlen; curbitlen--) {
+			if (curbyte & 0x80)
+				out |= AR71XX_SPI_IOC_DO;
+			else
+				out &= ~(AR71XX_SPI_IOC_DO);
+
+			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
+
+			/* delay for low level */
+			if (priv->rrw_delay) {
+				tick = get_ticks() + priv->rrw_delay;
+				while (get_ticks() < tick)
+					/*NOP*/;
+			}
+
+			writel(out | AR71XX_SPI_IOC_CLK,
+			       priv->regs + AR71XX_SPI_REG_IOC);
+
+			/* delay for high level */
+			if (priv->rrw_delay) {
+				tick = get_ticks() + priv->rrw_delay;
+				while (get_ticks() < tick)
+					/*NOP*/;
+			}
+
+			curbyte <<= 1;
+		}
+
+		if (!bytes)
+			writel(out, priv->regs + AR71XX_SPI_REG_IOC);
+
+		in = readl(priv->regs + AR71XX_SPI_REG_RDS);
+		if (rx) {
+			if (restbits && !bytes)
+				*rx++ = (in << (8 - restbits));
+			else
+				*rx++ = in;
+		}
+	}
+
+	if (flags & SPI_XFER_END)
+		spi_cs_deactivate(dev);
+
+	return 0;
+}
+
+
+static int ath79_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	u32 val, div = 0;
+	u64 time;
+
+	if (speed)
+		div = get_bus_freq(0) / speed;
+
+	if (div > 63)
+		div = 63;
+
+	if (div < 5)
+		div = 5;
+
+	/* calculate delay */
+	time = get_tbclk();
+	do_div(time, speed / 2);
+	val = get_bus_freq(0) / ATH79_SPI_MHZ;
+	val = ATH79_SPI_RRW_DELAY_FACTOR / val;
+	if (time > val)
+		priv->rrw_delay = time - val + 1;
+	else
+		priv->rrw_delay = 0;
+
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	clrsetbits_be32(priv->regs + AR71XX_SPI_REG_CTRL,
+			AR71XX_SPI_CTRL_DIV_MASK,
+			ATH79_SPI_CLK_DIV(div));
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+	return 0;
+}
+
+static int ath79_spi_set_mode(struct udevice *bus, uint mode)
+{
+	return 0;
+}
+
+static int ath79_spi_probe(struct udevice *bus)
+{
+	struct ath79_spi_priv *priv = dev_get_priv(bus);
+	fdt_addr_t addr;
+
+	addr = dev_get_addr(bus);
+	if (addr == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	priv->regs = map_physmem(addr,
+				 AR71XX_SPI_SIZE,
+				 MAP_NOCACHE);
+
+	/* Init SPI Hardware, disable remap, set clock */
+	writel(AR71XX_SPI_FS_GPIO, priv->regs + AR71XX_SPI_REG_FS);
+	writel(AR71XX_SPI_CTRL_RD | ATH79_SPI_CLK_DIV(8),
+	       priv->regs + AR71XX_SPI_REG_CTRL);
+	writel(0, priv->regs + AR71XX_SPI_REG_FS);
+
+	return 0;
+}
+
+static int ath79_cs_info(struct udevice *bus, uint cs,
+			   struct spi_cs_info *info)
+{
+	/* Always allow activity on CS 0/1/2 */
+	if (cs >= 3)
+		return -ENODEV;
+
+	return 0;
+}
+
+static const struct dm_spi_ops ath79_spi_ops = {
+	.claim_bus  = ath79_spi_claim_bus,
+	.release_bus    = ath79_spi_release_bus,
+	.xfer       = ath79_spi_xfer,
+	.set_speed  = ath79_spi_set_speed,
+	.set_mode   = ath79_spi_set_mode,
+	.cs_info    = ath79_cs_info,
+};
+
+static const struct udevice_id ath79_spi_ids[] = {
+	{ .compatible = "qca,ar7100-spi" },
+	{}
+};
+
+U_BOOT_DRIVER(ath79_spi) = {
+	.name   = "ath79_spi",
+	.id = UCLASS_SPI,
+	.of_match = ath79_spi_ids,
+	.ops    = &ath79_spi_ops,
+	.priv_auto_alloc_size = sizeof(struct ath79_spi_priv),
+	.probe  = ath79_spi_probe,
+};
diff --git a/drivers/spi/omap3_spi.c b/drivers/spi/omap3_spi.c
index 2fe34c9..60e9d6e 100644
--- a/drivers/spi/omap3_spi.c
+++ b/drivers/spi/omap3_spi.c
@@ -35,6 +35,12 @@
 #define OMAP3_MCSPI4_BASE	0x480BA000
 #endif
 
+#define OMAP4_MCSPI_REG_OFFSET	0x100
+
+struct omap2_mcspi_platform_config {
+	unsigned int regs_offset;
+};
+
 /* per-register bitmasks */
 #define OMAP3_MCSPI_SYSCONFIG_SMARTIDLE (2 << 3)
 #define OMAP3_MCSPI_SYSCONFIG_ENAWAKEUP BIT(2)
@@ -623,7 +629,10 @@
 	const void *blob = gd->fdt_blob;
 	int node = dev->of_offset;
 
-	priv->regs = (struct mcspi *)dev_get_addr(dev);
+	struct omap2_mcspi_platform_config* data =
+		(struct omap2_mcspi_platform_config*)dev_get_driver_data(dev);
+
+	priv->regs = (struct mcspi *)(dev_get_addr(dev) + data->regs_offset);
 	priv->pin_dir = fdtdec_get_uint(blob, node, "ti,pindir-d0-out-d1-in",
 					    MCSPI_PINDIR_D0_IN_D1_OUT);
 	priv->wordlen = SPI_DEFAULT_WORDLEN;
@@ -662,9 +671,17 @@
 	 */
 };
 
+static struct omap2_mcspi_platform_config omap2_pdata = {
+	.regs_offset = 0,
+};
+
+static struct omap2_mcspi_platform_config omap4_pdata = {
+	.regs_offset = OMAP4_MCSPI_REG_OFFSET,
+};
+
 static const struct udevice_id omap3_spi_ids[] = {
-	{ .compatible = "ti,omap2-mcspi" },
-	{ .compatible = "ti,omap4-mcspi" },
+	{ .compatible = "ti,omap2-mcspi", .data = (ulong)&omap2_pdata },
+	{ .compatible = "ti,omap4-mcspi", .data = (ulong)&omap4_pdata },
 	{ }
 };
 
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index aa4abcc..d23dc81 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -26,15 +26,20 @@
 	struct gpio_desc mosi;
 	struct gpio_desc miso;
 	int spi_delay_us;
+	int flags;
 };
 
+#define SPI_MASTER_NO_RX        BIT(0)
+#define SPI_MASTER_NO_TX        BIT(1)
+
 struct soft_spi_priv {
 	unsigned int mode;
 };
 
 static int soft_spi_scl(struct udevice *dev, int bit)
 {
-	struct soft_spi_platdata *plat = dev->platdata;
+	struct udevice *bus = dev_get_parent(dev);
+	struct soft_spi_platdata *plat = dev_get_platdata(bus);
 
 	dm_gpio_set_value(&plat->sclk, bit);
 
@@ -43,7 +48,8 @@
 
 static int soft_spi_sda(struct udevice *dev, int bit)
 {
-	struct soft_spi_platdata *plat = dev->platdata;
+	struct udevice *bus = dev_get_parent(dev);
+	struct soft_spi_platdata *plat = dev_get_platdata(bus);
 
 	dm_gpio_set_value(&plat->mosi, bit);
 
@@ -52,7 +58,8 @@
 
 static int soft_spi_cs_activate(struct udevice *dev)
 {
-	struct soft_spi_platdata *plat = dev->platdata;
+	struct udevice *bus = dev_get_parent(dev);
+	struct soft_spi_platdata *plat = dev_get_platdata(bus);
 
 	dm_gpio_set_value(&plat->cs, 0);
 	dm_gpio_set_value(&plat->sclk, 0);
@@ -63,7 +70,8 @@
 
 static int soft_spi_cs_deactivate(struct udevice *dev)
 {
-	struct soft_spi_platdata *plat = dev->platdata;
+	struct udevice *bus = dev_get_parent(dev);
+	struct soft_spi_platdata *plat = dev_get_platdata(bus);
 
 	dm_gpio_set_value(&plat->cs, 0);
 
@@ -100,8 +108,9 @@
 static int soft_spi_xfer(struct udevice *dev, unsigned int bitlen,
 			 const void *dout, void *din, unsigned long flags)
 {
-	struct soft_spi_priv *priv = dev_get_priv(dev);
-	struct soft_spi_platdata *plat = dev->platdata;
+	struct udevice *bus = dev_get_parent(dev);
+	struct soft_spi_priv *priv = dev_get_priv(bus);
+	struct soft_spi_platdata *plat = dev_get_platdata(bus);
 	uchar		tmpdin  = 0;
 	uchar		tmpdout = 0;
 	const u8	*txd = dout;
@@ -134,14 +143,16 @@
 
 		if (!cpha)
 			soft_spi_scl(dev, 0);
-		soft_spi_sda(dev, tmpdout & 0x80);
+		if ((plat->flags & SPI_MASTER_NO_TX) == 0)
+			soft_spi_sda(dev, !!(tmpdout & 0x80));
 		udelay(plat->spi_delay_us);
 		if (cpha)
 			soft_spi_scl(dev, 0);
 		else
 			soft_spi_scl(dev, 1);
 		tmpdin	<<= 1;
-		tmpdin	|= dm_gpio_get_value(&plat->miso);
+		if ((plat->flags & SPI_MASTER_NO_RX) == 0)
+			tmpdin	|= dm_gpio_get_value(&plat->miso);
 		tmpdout	<<= 1;
 		udelay(plat->spi_delay_us);
 		if (cpha)
@@ -203,24 +214,36 @@
 	struct spi_slave *slave = dev_get_parent_priv(dev);
 	struct soft_spi_platdata *plat = dev->platdata;
 	int cs_flags, clk_flags;
+	int ret;
 
 	cs_flags = (slave->mode & SPI_CS_HIGH) ? 0 : GPIOD_ACTIVE_LOW;
 	clk_flags = (slave->mode & SPI_CPOL) ? GPIOD_ACTIVE_LOW : 0;
-	if (gpio_request_by_name(dev, "cs-gpio", 0, &plat->cs,
+
+	if (gpio_request_by_name(dev, "cs-gpios", 0, &plat->cs,
 				 GPIOD_IS_OUT | cs_flags) ||
-	    gpio_request_by_name(dev, "sclk-gpio", 0, &plat->sclk,
-				 GPIOD_IS_OUT | clk_flags) ||
-	    gpio_request_by_name(dev, "mosi-gpio", 0, &plat->mosi,
-				 GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE) ||
-	    gpio_request_by_name(dev, "miso-gpio", 0, &plat->miso,
-				 GPIOD_IS_IN))
+	    gpio_request_by_name(dev, "gpio-sck", 0, &plat->sclk,
+				 GPIOD_IS_OUT | clk_flags))
+		return -EINVAL;
+
+	ret = gpio_request_by_name(dev, "gpio-mosi", 0, &plat->mosi,
+				   GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret)
+		plat->flags |= SPI_MASTER_NO_TX;
+
+	ret = gpio_request_by_name(dev, "gpio-miso", 0, &plat->miso,
+				   GPIOD_IS_IN);
+	if (ret)
+		plat->flags |= SPI_MASTER_NO_RX;
+
+	if ((plat->flags & (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX)) ==
+	    (SPI_MASTER_NO_RX | SPI_MASTER_NO_TX))
 		return -EINVAL;
 
 	return 0;
 }
 
 static const struct udevice_id soft_spi_ids[] = {
-	{ .compatible = "u-boot,soft-spi" },
+	{ .compatible = "spi-gpio" },
 	{ }
 };
 
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 5561f36..84b6786 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -45,12 +45,12 @@
 	return 0;
 }
 
-int spi_claim_bus(struct spi_slave *slave)
+int dm_spi_claim_bus(struct udevice *dev)
 {
-	struct udevice *dev = slave->dev;
 	struct udevice *bus = dev->parent;
 	struct dm_spi_ops *ops = spi_get_ops(bus);
 	struct dm_spi_bus *spi = dev_get_uclass_priv(bus);
+	struct spi_slave *slave = dev_get_parent_priv(dev);
 	int speed;
 	int ret;
 
@@ -73,9 +73,8 @@
 	return ops->claim_bus ? ops->claim_bus(dev) : 0;
 }
 
-void spi_release_bus(struct spi_slave *slave)
+void dm_spi_release_bus(struct udevice *dev)
 {
-	struct udevice *dev = slave->dev;
 	struct udevice *bus = dev->parent;
 	struct dm_spi_ops *ops = spi_get_ops(bus);
 
@@ -83,10 +82,9 @@
 		ops->release_bus(dev);
 }
 
-int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
-	     const void *dout, void *din, unsigned long flags)
+int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags)
 {
-	struct udevice *dev = slave->dev;
 	struct udevice *bus = dev->parent;
 
 	if (bus->uclass->uc_drv->id != UCLASS_SPI)
@@ -95,6 +93,22 @@
 	return spi_get_ops(bus)->xfer(dev, bitlen, dout, din, flags);
 }
 
+int spi_claim_bus(struct spi_slave *slave)
+{
+	return dm_spi_claim_bus(slave->dev);
+}
+
+void spi_release_bus(struct spi_slave *slave)
+{
+	dm_spi_release_bus(slave->dev);
+}
+
+int spi_xfer(struct spi_slave *slave, unsigned int bitlen,
+	     const void *dout, void *din, unsigned long flags)
+{
+	return dm_spi_xfer(slave->dev, bitlen, dout, din, flags);
+}
+
 static int spi_post_bind(struct udevice *dev)
 {
 	/* Scan the bus for devices */
diff --git a/drivers/usb/common/Makefile b/drivers/usb/common/Makefile
index 2f3d43d..2f46d38 100644
--- a/drivers/usb/common/Makefile
+++ b/drivers/usb/common/Makefile
@@ -3,5 +3,6 @@
 # SPDX-License-Identifier:      GPL-2.0+
 #
 
+obj-$(CONFIG_DM_USB) += common.o
 obj-$(CONFIG_USB_EHCI_FSL) += fsl-dt-fixup.o
 obj-$(CONFIG_USB_XHCI_FSL) += fsl-dt-fixup.o
diff --git a/drivers/usb/common/common.c b/drivers/usb/common/common.c
new file mode 100644
index 0000000..35c2dc1
--- /dev/null
+++ b/drivers/usb/common/common.c
@@ -0,0 +1,40 @@
+/*
+ * Provides code common for host and device side USB.
+ *
+ * (C) Copyright 2016
+ *     Texas Instruments Incorporated, <www.ti.com>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/usb/otg.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static const char *const usb_dr_modes[] = {
+	[USB_DR_MODE_UNKNOWN]		= "",
+	[USB_DR_MODE_HOST]		= "host",
+	[USB_DR_MODE_PERIPHERAL]	= "peripheral",
+	[USB_DR_MODE_OTG]		= "otg",
+};
+
+enum usb_dr_mode usb_get_dr_mode(int node)
+{
+	const void *fdt = gd->fdt_blob;
+	const char *dr_mode;
+	int i;
+
+	dr_mode = fdt_getprop(fdt, node, "dr_mode", NULL);
+	if (!dr_mode) {
+		error("usb dr_mode not found\n");
+		return USB_DR_MODE_UNKNOWN;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(usb_dr_modes); i++)
+		if (!strcmp(dr_mode, usb_dr_modes[i]))
+			return i;
+
+	return USB_DR_MODE_UNKNOWN;
+}
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index 7fd10e6..c01809e 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -620,6 +620,13 @@
 static int tegra_lcd_bind(struct udevice *dev)
 {
 	struct video_uc_platdata *plat = dev_get_uclass_platdata(dev);
+	const void *blob = gd->fdt_blob;
+	int node = dev->of_offset;
+	int rgb;
+
+	rgb = fdt_subnode_offset(blob, node, "rgb");
+	if ((rgb < 0) || !fdtdec_get_is_enabled(blob, rgb))
+		return -ENODEV;
 
 	plat->size = LCD_MAX_WIDTH * LCD_MAX_HEIGHT *
 		(1 << LCD_MAX_LOG2_BPP) / 8;
diff --git a/dts/Kconfig b/dts/Kconfig
index d585009..c56c129 100644
--- a/dts/Kconfig
+++ b/dts/Kconfig
@@ -62,6 +62,7 @@
 config OF_LIST
 	string "List of device tree files to include for DT control"
 	depends on SPL_LOAD_FIT
+	default DEFAULT_DEVICE_TREE
 	help
 	  This option specifies a list of device tree files to use for DT
 	  control. These will be packaged into a FIT. At run-time, SPL will
diff --git a/examples/api/Makefile b/examples/api/Makefile
index 4e9b8ea..6cffee7 100644
--- a/examples/api/Makefile
+++ b/examples/api/Makefile
@@ -11,8 +11,12 @@
 LOAD_ADDR = 0x1000000
 endif
 ifeq ($(ARCH),mips)
+ifdef CONFIG_64BIT
+LOAD_ADDR = 0xffffffff80200000
+else
 LOAD_ADDR = 0x80200000
 endif
+endif
 
 # Resulting ELF and binary exectuables will be named demo and demo.bin
 extra-y = demo
diff --git a/examples/api/crt0.S b/examples/api/crt0.S
index ced2c82..5a7049d 100644
--- a/examples/api/crt0.S
+++ b/examples/api/crt0.S
@@ -41,28 +41,29 @@
 	ldr	pc, [ip]
 
 #elif defined(CONFIG_MIPS)
+#include <asm/asm.h>
 	.text
 	.globl __start
 	.ent __start
 __start:
-	sw	$sp, search_hint
+	PTR_S	$sp, search_hint
 	b	main
 	.end __start
 
 	.globl syscall
 	.ent syscall
 syscall:
-	sw	$ra, return_addr
-	lw	$t9, syscall_ptr
+	PTR_S	$ra, return_addr
+	PTR_L	$t9, syscall_ptr
 	jalr	$t9
 	nop
-	lw	$ra, return_addr
+	PTR_L	$ra, return_addr
 	jr	$ra
 	nop
 	.end syscall
 
 return_addr:
-	.align 4
+	.align 8
 	.long 0
 #else
 #error No support for this arch!
@@ -70,7 +71,7 @@
 
 	.globl syscall_ptr
 syscall_ptr:
-	.align	4
+	.align	8
 	.long	0
 
 	.globl search_hint
diff --git a/examples/api/glue.c b/examples/api/glue.c
index d619518..8aabf32 100644
--- a/examples/api/glue.c
+++ b/examples/api/glue.c
@@ -77,7 +77,7 @@
 {
 	int c;
 
-	if (!syscall(API_GETC, NULL, (uint32_t)&c))
+	if (!syscall(API_GETC, NULL, &c))
 		return -1;
 
 	return c;
@@ -87,7 +87,7 @@
 {
 	int t;
 
-	if (!syscall(API_TSTC, NULL, (uint32_t)&t))
+	if (!syscall(API_TSTC, NULL, &t))
 		return -1;
 
 	return t;
@@ -95,12 +95,12 @@
 
 void ub_putc(char c)
 {
-	syscall(API_PUTC, NULL, (uint32_t)&c);
+	syscall(API_PUTC, NULL, &c);
 }
 
 void ub_puts(const char *s)
 {
-	syscall(API_PUTS, NULL, (uint32_t)s);
+	syscall(API_PUTS, NULL, s);
 }
 
 /****************************************
@@ -126,7 +126,7 @@
 	si.mr_no = UB_MAX_MR;
 	memset(&mr, 0, sizeof(mr));
 
-	if (!syscall(API_GET_SYS_INFO, &err, (u_int32_t)&si))
+	if (!syscall(API_GET_SYS_INFO, &err, &si))
 		return NULL;
 
 	return ((err) ? NULL : &si);
@@ -344,7 +344,7 @@
 {
 	char *value;
 
-	if (!syscall(API_ENV_GET, NULL, (uint32_t)name, (uint32_t)&value))
+	if (!syscall(API_ENV_GET, NULL, name, &value))
 		return NULL;
 
 	return value;
@@ -352,7 +352,7 @@
 
 void ub_env_set(const char *name, char *value)
 {
-	syscall(API_ENV_SET, NULL, (uint32_t)name, (uint32_t)value);
+	syscall(API_ENV_SET, NULL, name, value);
 }
 
 static char env_name[256];
@@ -369,7 +369,7 @@
 	 * 'name=val' string), since the API_ENUM_ENV call uses envmatch()
 	 * internally, which handles such case
 	 */
-	if (!syscall(API_ENV_ENUM, NULL, (uint32_t)last, (uint32_t)&env))
+	if (!syscall(API_ENV_ENUM, NULL, last, &env))
 		return NULL;
 
 	if (!env)
@@ -396,7 +396,7 @@
 {
 	int err = 0;
 
-	if (!syscall(API_DISPLAY_GET_INFO, &err, (uint32_t)type, (uint32_t)di))
+	if (!syscall(API_DISPLAY_GET_INFO, &err, type, di))
 		return API_ESYSC;
 
 	return err;
diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c
index 920a0a9..0d62067 100644
--- a/examples/standalone/stubs.c
+++ b/examples/standalone/stubs.c
@@ -65,6 +65,23 @@
 	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip");
 #endif
 #elif defined(CONFIG_MIPS)
+#ifdef CONFIG_CPU_MIPS64
+/*
+ * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call-
+ * clobbered register that is also used to set gp ($26). Note that the
+ * jr instruction also executes the instruction immediately following
+ * it; however, GCC/mips generates an additional `nop' after each asm
+ * statement
+ */
+#define EXPORT_FUNC(f, a, x, ...) \
+	asm volatile (			\
+"	.globl " #x "\n"		\
+#x ":\n"				\
+"	ld	$25, %0($26)\n"		\
+"	ld	$25, %1($25)\n"		\
+"	jr	$25\n"			\
+        : : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9");
+#else
 /*
  * k0 ($26) holds the pointer to the global_data; t9 ($25) is a call-
  * clobbered register that is also used to set gp ($26). Note that the
@@ -80,6 +97,7 @@
 "	lw	$25, %1($25)\n"		\
 "	jr	$25\n"			\
 	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9");
+#endif
 #elif defined(CONFIG_NIOS2)
 /*
  * gp holds the pointer to the global_data, r8 is call-clobbered
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 600a90e..826bd85 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -1254,7 +1254,7 @@
 
 #if defined(CONFIG_CMD_IDE) || \
     defined(CONFIG_CMD_SATA) || \
-    defined(CONFIG_CMD_SCSI) || \
+    defined(CONFIG_SCSI) || \
     defined(CONFIG_CMD_USB) || \
     defined(CONFIG_MMC)
 	printf("Interface:  ");
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 68b5f0b..2500c10 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -207,6 +207,16 @@
 struct fdtdec_phandle_args;
 
 /**
+ * gpio_xlate_offs_flags() - implementation for common use of dm_gpio_ops.xlate
+ *
+ * This routine sets the offset field to args[0] and the flags field to
+ * GPIOD_ACTIVE_LOW if the GPIO_ACTIVE_LOW flag is present in args[1].
+ *
+ */
+int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
+			  struct fdtdec_phandle_args *args);
+
+/**
  * struct struct dm_gpio_ops - Driver model GPIO operations
  *
  * Refer to functions above for description. These function largely copy
@@ -258,12 +268,11 @@
 	 *
 	 *   @desc->dev to @dev
 	 *   @desc->flags to 0
-	 *   @desc->offset to the value of the first argument in args, if any,
-	 *		otherwise -1 (which is invalid)
+	 *   @desc->offset to 0
 	 *
-	 * This method is optional so if the above defaults suit it can be
-	 * omitted. Typical behaviour is to set up the GPIOD_ACTIVE_LOW flag
-	 * in desc->flags.
+	 * This method is optional and defaults to gpio_xlate_offs_flags,
+	 * which will parse offset and the GPIO_ACTIVE_LOW flag in the first
+	 * two arguments.
 	 *
 	 * Note that @dev is passed in as a parameter to follow driver model
 	 * uclass conventions, even though it is already available as
diff --git a/include/ata.h b/include/ata.h
index 9d6f59c..dde377c 100644
--- a/include/ata.h
+++ b/include/ata.h
@@ -126,7 +126,7 @@
 
 #define ATA_BLOCKSIZE	512	/* bytes */
 #define ATA_BLOCKSHIFT	9	/* 2 ^ ATA_BLOCKSIZESHIFT = 512 */
-#define ATA_SECTORWORDS	(512 / sizeof(unsigned long))
+#define ATA_SECTORWORDS	(512 / sizeof(uint32_t))
 
 #ifndef ATA_RESET_TIME
 #define ATA_RESET_TIME	60	/* spec allows up to 31 seconds */
diff --git a/include/blk.h b/include/blk.h
index f624671..66a1c55 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -30,6 +30,7 @@
 	IF_TYPE_SD,
 	IF_TYPE_SATA,
 	IF_TYPE_HOST,
+	IF_TYPE_SYSTEMACE,
 
 	IF_TYPE_COUNT,			/* Number of interface types */
 };
@@ -62,6 +63,11 @@
 	char		product[20+1];	/* IDE Serial no, SCSI product */
 	char		revision[8+1];	/* firmware revision */
 #ifdef CONFIG_BLK
+	/*
+	 * For now we have a few functions which take struct blk_desc as a
+	 * parameter. This field allows them to look up the associated
+	 * device. Once these functions are removed we can drop this field.
+	 */
 	struct udevice *bdev;
 #else
 	unsigned long	(*block_read)(struct blk_desc *block_dev,
@@ -210,6 +216,25 @@
 	 */
 	unsigned long (*erase)(struct udevice *dev, lbaint_t start,
 			       lbaint_t blkcnt);
+
+	/**
+	 * select_hwpart() - select a particular hardware partition
+	 *
+	 * Some devices (e.g. MMC) can support partitioning at the hardware
+	 * level. This is quite separate from the normal idea of
+	 * software-based partitions. MMC hardware partitions must be
+	 * explicitly selected. Once selected only the region of the device
+	 * covered by that partition is accessible.
+	 *
+	 * The MMC standard provides for two boot partitions (numbered 1 and 2),
+	 * rpmb (3), and up to 4 addition general-purpose partitions (4-7).
+	 *
+	 * @desc:	Block device to update
+	 * @hwpart:	Hardware partition number to select. 0 means the raw
+	 *		device, 1 is the first partition, 2 is the second, etc.
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*select_hwpart)(struct udevice *dev, int hwpart);
 };
 
 #define blk_get_ops(dev)	((struct blk_ops *)(dev)->driver->ops)
@@ -269,7 +294,8 @@
  * @drv_name:	Driver name to use for the block device
  * @name:	Name for the device
  * @if_type:	Interface type (enum if_type_t)
- * @devnum:	Device number, specific to the interface type
+ * @devnum:	Device number, specific to the interface type, or -1 to
+ *		allocate the next available number
  * @blksz:	Block size of the device in bytes (typically 512)
  * @size:	Total size of the device in bytes
  * @devp:	the new device (which has not been probed)
@@ -279,6 +305,23 @@
 		      lbaint_t size, struct udevice **devp);
 
 /**
+ * blk_create_devicef() - Create a new named block device
+ *
+ * @parent:	Parent of the new device
+ * @drv_name:	Driver name to use for the block device
+ * @name:	Name for the device (parent name is prepended)
+ * @if_type:	Interface type (enum if_type_t)
+ * @devnum:	Device number, specific to the interface type, or -1 to
+ *		allocate the next available number
+ * @blksz:	Block size of the device in bytes (typically 512)
+ * @size:	Total size of the device in bytes
+ * @devp:	the new device (which has not been probed)
+ */
+int blk_create_devicef(struct udevice *parent, const char *drv_name,
+		       const char *name, int if_type, int devnum, int blksz,
+		       lbaint_t size, struct udevice **devp);
+
+/**
  * blk_prepare_device() - Prepare a block device for use
  *
  * This reads partition information from the device if supported.
@@ -298,6 +341,29 @@
  */
 int blk_unbind_all(int if_type);
 
+/**
+ * blk_find_max_devnum() - find the maximum device number for an interface type
+ *
+ * Finds the last allocated device number for an interface type @if_type. The
+ * next number is safe to use for a newly allocated device.
+ *
+ * @if_type:	Interface type to scan
+ * @return maximum device number found, or -ENODEV if none, or other -ve on
+ * error
+ */
+int blk_find_max_devnum(enum if_type if_type);
+
+/**
+ * blk_select_hwpart() - select a hardware partition
+ *
+ * Select a hardware partition if the device supports it (typically MMC does)
+ *
+ * @dev:	Device to update
+ * @hwpart:	Partition number to select
+ * @return 0 if OK, -ve on error
+ */
+int blk_select_hwpart(struct udevice *dev, int hwpart);
+
 #else
 #include <errno.h>
 /*
@@ -340,6 +406,201 @@
 	blkcache_invalidate(block_dev->if_type, block_dev->devnum);
 	return block_dev->block_erase(block_dev, start, blkcnt);
 }
+
+/**
+ * struct blk_driver - Driver for block interface types
+ *
+ * This provides access to the block devices for each interface type. One
+ * driver should be provided using U_BOOT_LEGACY_BLK() for each interface
+ * type that is to be supported.
+ *
+ * @if_typename:	Interface type name
+ * @if_type:		Interface type
+ * @max_devs:		Maximum number of devices supported
+ * @desc:		Pointer to list of devices for this interface type,
+ *			or NULL to use @get_dev() instead
+ */
+struct blk_driver {
+	const char *if_typename;
+	enum if_type if_type;
+	int max_devs;
+	struct blk_desc *desc;
+	/**
+	 * get_dev() - get a pointer to a block device given its number
+	 *
+	 * Each interface allocates its own devices and typically
+	 * struct blk_desc is contained with the interface's data structure.
+	 * There is no global numbering for block devices. This method allows
+	 * the device for an interface type to be obtained when @desc is NULL.
+	 *
+	 * @devnum:	Device number (0 for first device on that interface,
+	 *		1 for second, etc.
+	 * @descp:	Returns pointer to the block device on success
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*get_dev)(int devnum, struct blk_desc **descp);
+
+	/**
+	 * select_hwpart() - Select a hardware partition
+	 *
+	 * Some devices (e.g. MMC) can support partitioning at the hardware
+	 * level. This is quite separate from the normal idea of
+	 * software-based partitions. MMC hardware partitions must be
+	 * explicitly selected. Once selected only the region of the device
+	 * covered by that partition is accessible.
+	 *
+	 * The MMC standard provides for two boot partitions (numbered 1 and 2),
+	 * rpmb (3), and up to 4 addition general-purpose partitions (4-7).
+	 * Partition 0 is the main user-data partition.
+	 *
+	 * @desc:	Block device descriptor
+	 * @hwpart:	Hardware partition number to select. 0 means the main
+	 *		user-data partition, 1 is the first partition, 2 is
+	 *		the second, etc.
+	 * @return 0 if OK, other value for an error
+	 */
+	int (*select_hwpart)(struct blk_desc *desc, int hwpart);
+};
+
+/*
+ * Declare a new U-Boot legacy block driver. New drivers should use driver
+ * model (UCLASS_BLK).
+ */
+#define U_BOOT_LEGACY_BLK(__name)					\
+	ll_entry_declare(struct blk_driver, __name, blk_driver)
+
+struct blk_driver *blk_driver_lookup_type(int if_type);
+
 #endif /* !CONFIG_BLK */
 
+/**
+ * blk_get_devnum_by_typename() - Get a block device by type and number
+ *
+ * This looks through the available block devices of the given type, returning
+ * the one with the given @devnum.
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @return point to block device descriptor, or NULL if not found
+ */
+struct blk_desc *blk_get_devnum_by_type(enum if_type if_type, int devnum);
+
+/**
+ * blk_get_devnum_by_type() - Get a block device by type name, and number
+ *
+ * This looks up the block device type based on @if_typename, then calls
+ * blk_get_devnum_by_type().
+ *
+ * @if_typename:	Block device type name
+ * @devnum:		Device number
+ * @return point to block device descriptor, or NULL if not found
+ */
+struct blk_desc *blk_get_devnum_by_typename(const char *if_typename,
+					    int devnum);
+
+/**
+ * blk_dselect_hwpart() - select a hardware partition
+ *
+ * This selects a hardware partition (such as is supported by MMC). The block
+ * device size may change as this effectively points the block device to a
+ * partition at the hardware level. See the select_hwpart() method above.
+ *
+ * @desc:	Block device descriptor for the device to select
+ * @hwpart:	Partition number to select
+ * @return 0 if OK, -ve on error
+ */
+int blk_dselect_hwpart(struct blk_desc *desc, int hwpart);
+
+/**
+ * blk_list_part() - list the partitions for block devices of a given type
+ *
+ * This looks up the partition type for each block device of type @if_type,
+ * then displays a list of partitions.
+ *
+ * @if_type:	Block device type
+ * @return 0 if OK, -ENODEV if there is none of that type
+ */
+int blk_list_part(enum if_type if_type);
+
+/**
+ * blk_list_devices() - list the block devices of a given type
+ *
+ * This lists each block device of the type @if_type, showing the capacity
+ * as well as type-specific information.
+ *
+ * @if_type:	Block device type
+ */
+void blk_list_devices(enum if_type if_type);
+
+/**
+ * blk_show_device() - show information about a given block device
+ *
+ * This shows the block device capacity as well as type-specific information.
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @return 0 if OK, -ENODEV for invalid device number
+ */
+int blk_show_device(enum if_type if_type, int devnum);
+
+/**
+ * blk_print_device_num() - show information about a given block device
+ *
+ * This is similar to blk_show_device() but returns an error if the block
+ * device type is unknown.
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @return 0 if OK, -ENODEV for invalid device number, -ENOENT if the block
+ * device is not connected
+ */
+int blk_print_device_num(enum if_type if_type, int devnum);
+
+/**
+ * blk_print_part_devnum() - print the partition information for a device
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @return 0 if OK, -ENOENT if the block device is not connected, -ENOSYS if
+ * the interface type is not supported, other -ve on other error
+ */
+int blk_print_part_devnum(enum if_type if_type, int devnum);
+
+/**
+ * blk_read_devnum() - read blocks from a device
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @blkcnt:	Number of blocks to read
+ * @buffer:	Address to write data to
+ * @return number of blocks read, or -ve error number on error
+ */
+ulong blk_read_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		      lbaint_t blkcnt, void *buffer);
+
+/**
+ * blk_write_devnum() - write blocks to a device
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @blkcnt:	Number of blocks to write
+ * @buffer:	Address to read data from
+ * @return number of blocks written, or -ve error number on error
+ */
+ulong blk_write_devnum(enum if_type if_type, int devnum, lbaint_t start,
+		       lbaint_t blkcnt, const void *buffer);
+
+/**
+ * blk_select_hwpart_devnum() - select a hardware partition
+ *
+ * This is similar to blk_dselect_hwpart() but it looks up the interface and
+ * device number.
+ *
+ * @if_type:	Block device type
+ * @devnum:	Device number
+ * @hwpart:	Partition number to select
+ * @return 0 if OK, -ve on error
+ */
+int blk_select_hwpart_devnum(enum if_type if_type, int devnum, int hwpart);
+
 #endif
diff --git a/include/config_cmd_all.h b/include/config_cmd_all.h
index ed502a1..b5fd6c6 100644
--- a/include/config_cmd_all.h
+++ b/include/config_cmd_all.h
@@ -45,7 +45,7 @@
 #define CONFIG_CMD_READ		/* Read data from partition	*/
 #define CONFIG_CMD_SANDBOX	/* sb command to access sandbox features */
 #define CONFIG_CMD_SAVES	/* save S record dump		*/
-#define CONFIG_CMD_SCSI		/* SCSI Support			*/
+#define CONFIG_SCSI		/* SCSI Support			*/
 #define CONFIG_CMD_SDRAM	/* SDRAM DIMM SPD info printout */
 #define CONFIG_CMD_TERMINAL	/* built-in Serial Terminal	*/
 #define CONFIG_CMD_UBI		/* UBI Support			*/
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index 7f67344..5a8d7f2 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -165,7 +165,7 @@
 	BOOT_TARGET_DEVICES_references_SATA_without_CONFIG_CMD_SATA
 #endif
 
-#ifdef CONFIG_CMD_SCSI
+#ifdef CONFIG_SCSI
 #define BOOTENV_RUN_SCSI_INIT "run scsi_init; "
 #define BOOTENV_SET_SCSI_NEED_INIT "setenv scsi_need_init; "
 #define BOOTENV_SHARED_SCSI \
@@ -185,9 +185,9 @@
 #define BOOTENV_SET_SCSI_NEED_INIT
 #define BOOTENV_SHARED_SCSI
 #define BOOTENV_DEV_SCSI \
-	BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_CMD_SCSI
+	BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_SCSI
 #define BOOTENV_DEV_NAME_SCSI \
-	BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_CMD_SCSI
+	BOOT_TARGET_DEVICES_references_SCSI_without_CONFIG_SCSI
 #endif
 
 #ifdef CONFIG_CMD_IDE
diff --git a/include/config_fallbacks.h b/include/config_fallbacks.h
index 2666191..2ad54b7 100644
--- a/include/config_fallbacks.h
+++ b/include/config_fallbacks.h
@@ -45,7 +45,7 @@
 /* Rather than repeat this expression each time, add a define for it */
 #if defined(CONFIG_CMD_IDE) || \
 	defined(CONFIG_CMD_SATA) || \
-	defined(CONFIG_CMD_SCSI) || \
+	defined(CONFIG_SCSI) || \
 	defined(CONFIG_CMD_USB) || \
 	defined(CONFIG_CMD_PART) || \
 	defined(CONFIG_CMD_GPT) || \
diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h
index 26d92da..f3036c1 100644
--- a/include/configs/MPC8544DS.h
+++ b/include/configs/MPC8544DS.h
@@ -373,7 +373,7 @@
 
 #if defined(CONFIG_PCI)
     #define CONFIG_CMD_PCI
-    #define CONFIG_CMD_SCSI
+    #define CONFIG_SCSI
 #endif
 
 /*
diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h
index 8c4e5e2..bb7f38e 100644
--- a/include/configs/MPC8572DS.h
+++ b/include/configs/MPC8572DS.h
@@ -576,7 +576,7 @@
 
 #if defined(CONFIG_PCI)
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #endif
 
 /*
diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h
index e7f01d0..f6d45a9 100644
--- a/include/configs/MPC8610HPCD.h
+++ b/include/configs/MPC8610HPCD.h
@@ -449,7 +449,7 @@
 
 #if defined(CONFIG_PCI)
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #endif
 
 #define CONFIG_WATCHDOG			/* watchdog enabled */
diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h
index 2f94c82..9b2623c 100644
--- a/include/configs/MPC8641HPCN.h
+++ b/include/configs/MPC8641HPCN.h
@@ -354,8 +354,6 @@
 
 #define CONFIG_PCI_SCAN_SHOW		/* show pci devices on startup */
 
-#undef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
-
 #define CONFIG_PCI_PNP			/* do pci plug-and-play */
 
 #undef CONFIG_EEPRO100
@@ -612,7 +610,7 @@
 
 #if defined(CONFIG_PCI)
     #define CONFIG_CMD_PCI
-    #define CONFIG_CMD_SCSI
+    #define CONFIG_SCSI
 #endif
 
 #undef CONFIG_WATCHDOG			/* watchdog disabled */
diff --git a/include/configs/PIP405.h b/include/configs/PIP405.h
index 4bd06a4..4506d86 100644
--- a/include/configs/PIP405.h
+++ b/include/configs/PIP405.h
@@ -43,7 +43,7 @@
 #define CONFIG_CMD_EEPROM
 #define CONFIG_CMD_REGINFO
 #define CONFIG_CMD_FDC
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_CMD_DATE
 #define CONFIG_CMD_SDRAM
 #define CONFIG_CMD_SAVES
diff --git a/include/configs/am57xx_evm.h b/include/configs/am57xx_evm.h
index 32d7d4d..d53b0fd 100644
--- a/include/configs/am57xx_evm.h
+++ b/include/configs/am57xx_evm.h
@@ -75,7 +75,7 @@
 
 /* SATA */
 #define CONFIG_BOARD_LATE_INIT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
diff --git a/include/configs/ap121.h b/include/configs/ap121.h
new file mode 100644
index 0000000..2beffa4
--- /dev/null
+++ b/include/configs/ap121.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE            0x9f000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ                   1000
+#define CONFIG_SYS_MHZ                  200
+#define CONFIG_SYS_MIPS_TIMER_FREQ      (CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE          0x8000
+#define CONFIG_SYS_ICACHE_SIZE          0x10000
+#define CONFIG_SYS_CACHELINE_SIZE       32
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN           0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN       0x20000
+
+#define CONFIG_SYS_SDRAM_BASE           0x80000000
+#define CONFIG_SYS_LOAD_ADDR            0x81000000
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR        0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE        0x8000
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
+
+#define CONFIG_BAUDRATE                 115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY                3
+#define CONFIG_BOOTARGS                 "console=ttyS0,115200 " \
+					"root=/dev/mtdblock2 " \
+					"rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND              "sf probe;" \
+					"mtdparts default;" \
+					"bootm 0x9f300000"
+#define CONFIG_LZMA
+
+#define MTDIDS_DEFAULT                  "nor0=spi-flash.0"
+#define MTDPARTS_DEFAULT                "mtdparts=spi-flash.0:" \
+					"256k(u-boot),64k(u-boot-env)," \
+					"2752k(rootfs),896k(uImage)," \
+					"64k(NVRAM),64k(ART)"
+
+#define CONFIG_ENV_SPI_MAX_HZ           25000000
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_OFFSET               0x40000
+#define CONFIG_ENV_SECT_SIZE            0x10000
+#define CONFIG_ENV_SIZE                 0x10000
+
+/*
+ * Command
+ */
+#define CONFIG_CMD_MTDPARTS
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_CBSIZE               256
+#define CONFIG_SYS_MAXARGS              16
+#define CONFIG_SYS_PBSIZE               (CONFIG_SYS_CBSIZE + \
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START        0x80100000
+#define CONFIG_SYS_MEMTEST_END          0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#endif  /* __CONFIG_H */
diff --git a/include/configs/ap143.h b/include/configs/ap143.h
new file mode 100644
index 0000000..7b69e10
--- /dev/null
+++ b/include/configs/ap143.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2015-2016 Wills Wang <wills.wang@live.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE            0x9f000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ                   1000
+#define CONFIG_SYS_MHZ                  325
+#define CONFIG_SYS_MIPS_TIMER_FREQ      (CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE          0x8000
+#define CONFIG_SYS_ICACHE_SIZE          0x10000
+#define CONFIG_SYS_CACHELINE_SIZE       32
+
+#define CONFIG_SYS_MONITOR_BASE         CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN           0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN       0x20000
+
+#define CONFIG_SYS_SDRAM_BASE           0x80000000
+#define CONFIG_SYS_LOAD_ADDR            0x81000000
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR        0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE        0x2000
+#define CONFIG_SYS_INIT_SP_ADDR \
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE - 1)
+
+/*
+ * Serial Port
+ */
+#define CONFIG_SYS_NS16550_CLK          25000000
+#define CONFIG_BAUDRATE                 115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY                3
+#define CONFIG_BOOTARGS                 "console=ttyS0,115200 " \
+					"root=/dev/mtdblock2 " \
+					"rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND              "sf probe;" \
+					"mtdparts default;" \
+					"bootm 0x9f300000"
+#define CONFIG_LZMA
+
+#define MTDIDS_DEFAULT                  "nor0=spi-flash.0"
+#define MTDPARTS_DEFAULT                "mtdparts=spi-flash.0:" \
+					"256k(u-boot),64k(u-boot-env)," \
+					"2752k(rootfs),896k(uImage)," \
+					"64k(NVRAM),64k(ART)"
+
+#define CONFIG_ENV_SPI_MAX_HZ           25000000
+#define CONFIG_ENV_IS_IN_SPI_FLASH
+#define CONFIG_ENV_OFFSET               0x40000
+#define CONFIG_ENV_SECT_SIZE            0x10000
+#define CONFIG_ENV_SIZE                 0x10000
+
+/*
+ * Command
+ */
+#define CONFIG_CMD_MTDPARTS
+
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_CBSIZE               256
+#define CONFIG_SYS_MAXARGS              16
+#define CONFIG_SYS_PBSIZE               (CONFIG_SYS_CBSIZE + \
+					sizeof(CONFIG_SYS_PROMPT) + 16)
+#define CONFIG_SYS_LONGHELP
+#define CONFIG_CMDLINE_EDITING
+#define CONFIG_AUTO_COMPLETE
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START        0x80100000
+#define CONFIG_SYS_MEMTEST_END          0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#endif  /* __CONFIG_H */
diff --git a/include/configs/axs101.h b/include/configs/axs101.h
index 1bd4729..05d2d45 100644
--- a/include/configs/axs101.h
+++ b/include/configs/axs101.h
@@ -59,7 +59,6 @@
  * I2C configuration
  */
 #define CONFIG_SYS_I2C
-#define CONFIG_SYS_I2C_DW
 #define CONFIG_I2C_ENV_EEPROM_BUS	2
 #define CONFIG_SYS_I2C_SPEED		100000
 #define CONFIG_SYS_I2C_SPEED1		100000
diff --git a/include/configs/cm_fx6.h b/include/configs/cm_fx6.h
index 9a12552..1f20ec3 100644
--- a/include/configs/cm_fx6.h
+++ b/include/configs/cm_fx6.h
@@ -255,4 +255,15 @@
 #define CONFIG_VIDEO_LOGO
 #define CONFIG_VIDEO_BMP_LOGO
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "v2, v3"
+
 #endif	/* __CONFIG_CM_FX6_H */
diff --git a/include/configs/cm_t335.h b/include/configs/cm_t335.h
index c4f1d4f..6dbc9e9 100644
--- a/include/configs/cm_t335.h
+++ b/include/configs/cm_t335.h
@@ -165,6 +165,17 @@
 #define STATUS_LED_PERIOD		(CONFIG_SYS_HZ / 2)
 #define STATUS_LED_BOOT			0
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "v2, v3"
+
 #ifndef CONFIG_SPL_BUILD
 /*
  * Enable PCA9555 at I2C0-0x26.
diff --git a/include/configs/cm_t35.h b/include/configs/cm_t35.h
index 5d58116..0fb8530 100644
--- a/include/configs/cm_t35.h
+++ b/include/configs/cm_t35.h
@@ -361,4 +361,15 @@
 #define CONFIG_SYS_SPL_MALLOC_START	0x80208000
 #define CONFIG_SYS_SPL_MALLOC_SIZE	0x100000
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "legacy, v1, v2, v3"
+
 #endif /* __CONFIG_H */
diff --git a/include/configs/cm_t3517.h b/include/configs/cm_t3517.h
index 7cedb67..7c087c6 100644
--- a/include/configs/cm_t3517.h
+++ b/include/configs/cm_t3517.h
@@ -305,4 +305,15 @@
 
 #define CONFIG_OMAP3_SPI
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "v1, v2, v3"
+
 #endif /* __CONFIG_H */
diff --git a/include/configs/cm_t43.h b/include/configs/cm_t43.h
index ee818ed..c2dbd31 100644
--- a/include/configs/cm_t43.h
+++ b/include/configs/cm_t43.h
@@ -170,4 +170,15 @@
 #define CONFIG_SPL_I2C_SUPPORT
 #define CONFIG_SPL_POWER_SUPPORT
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "v2, v3"
+
 #endif	/* __CONFIG_CM_T43_H */
diff --git a/include/configs/cm_t54.h b/include/configs/cm_t54.h
index 9b13aa6..ff63d7a 100644
--- a/include/configs/cm_t54.h
+++ b/include/configs/cm_t54.h
@@ -60,7 +60,7 @@
 #define CONFIG_SPL_SATA_BOOT_DEVICE		0
 #define CONFIG_SYS_SATA_FAT_BOOT_PARTITION	1
 
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
@@ -81,6 +81,17 @@
 
 /* Enabled commands */
 
+/* EEPROM */
+#define CONFIG_CMD_EEPROM
+#define CONFIG_ENV_EEPROM_IS_ON_I2C
+#define CONFIG_SYS_I2C_EEPROM_ADDR_LEN		1
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_BITS	4
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS	5
+#define CONFIG_SYS_EEPROM_SIZE			256
+
+#define CONFIG_CMD_EEPROM_LAYOUT
+#define CONFIG_EEPROM_LAYOUT_HELP_STRING "v2, v3"
+
 /* USB Networking options */
 #define CONFIG_USB_HOST_ETHER
 #define CONFIG_USB_ETHER_SMSC95XX
diff --git a/include/configs/db-88f6820-gp.h b/include/configs/db-88f6820-gp.h
index d84dde3..3539a62 100644
--- a/include/configs/db-88f6820-gp.h
+++ b/include/configs/db-88f6820-gp.h
@@ -27,7 +27,7 @@
 #define CONFIG_SYS_NO_FLASH		/* Declare no flash (NOR/SPI) */
 #define CONFIG_CMD_ENV
 #define CONFIG_CMD_PCI
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 
 /* I2C */
 #define CONFIG_SYS_I2C
diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h
index 79b6c09..8a0cd66 100644
--- a/include/configs/dra7xx_evm.h
+++ b/include/configs/dra7xx_evm.h
@@ -230,7 +230,7 @@
 
 /* SATA */
 #define CONFIG_BOARD_LATE_INIT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
diff --git a/include/configs/efi-x86.h b/include/configs/efi-x86.h
index 6dd0b32..95e46c5 100644
--- a/include/configs/efi-x86.h
+++ b/include/configs/efi-x86.h
@@ -18,7 +18,7 @@
 #undef CONFIG_VIDEO
 #undef CONFIG_CFB_CONSOLE
 #undef CONFIG_SCSI_AHCI
-#undef CONFIG_CMD_SCSI
+#undef CONFIG_SCSI
 #undef CONFIG_INTEL_ICH6_GPIO
 #undef CONFIG_USB_EHCI_PCI
 
diff --git a/include/configs/galileo.h b/include/configs/galileo.h
index 2f1f6d4..40f7fba 100644
--- a/include/configs/galileo.h
+++ b/include/configs/galileo.h
@@ -29,7 +29,7 @@
 
 /* SATA is not supported in Quark SoC */
 #undef CONFIG_SCSI_AHCI
-#undef CONFIG_CMD_SCSI
+#undef CONFIG_SCSI
 
 /* Video is not supported in Quark SoC */
 #undef CONFIG_VIDEO
diff --git a/include/configs/highbank.h b/include/configs/highbank.h
index 3bce12b..5cefddc 100644
--- a/include/configs/highbank.h
+++ b/include/configs/highbank.h
@@ -51,7 +51,7 @@
 /*
  * Command line configuration.
  */
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 
 #define CONFIG_BOOT_RETRY_TIME		-1
 #define CONFIG_RESET_TO_RETRY
diff --git a/include/configs/ls1043aqds.h b/include/configs/ls1043aqds.h
index d71a229..af1f73d 100644
--- a/include/configs/ls1043aqds.h
+++ b/include/configs/ls1043aqds.h
@@ -108,7 +108,7 @@
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_DOS_PARTITION
 #define CONFIG_BOARD_LATE_INIT
 
diff --git a/include/configs/ls2080aqds.h b/include/configs/ls2080aqds.h
index 2d7567f..f8c9e51 100644
--- a/include/configs/ls2080aqds.h
+++ b/include/configs/ls2080aqds.h
@@ -44,7 +44,7 @@
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_DOS_PARTITION
 #define CONFIG_BOARD_LATE_INIT
 
diff --git a/include/configs/ls2080ardb.h b/include/configs/ls2080ardb.h
index 5bec509..4577919 100644
--- a/include/configs/ls2080ardb.h
+++ b/include/configs/ls2080ardb.h
@@ -62,7 +62,7 @@
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_DOS_PARTITION
 #define CONFIG_BOARD_LATE_INIT
 
diff --git a/include/configs/omap5_uevm.h b/include/configs/omap5_uevm.h
index 86cefa3..4ddc492 100644
--- a/include/configs/omap5_uevm.h
+++ b/include/configs/omap5_uevm.h
@@ -115,7 +115,7 @@
 /* Max time to hold reset on this board, see doc/README.omap-reset-time */
 #define CONFIG_OMAP_PLATFORM_RESET_TIME_MAX_USEC	16296
 
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #define CONFIG_LIBATA
 #define CONFIG_SCSI_AHCI
 #define CONFIG_SCSI_AHCI_PLAT
diff --git a/include/configs/qemu-mips.h b/include/configs/qemu-mips.h
index a7cd003..702967c 100644
--- a/include/configs/qemu-mips.h
+++ b/include/configs/qemu-mips.h
@@ -58,6 +58,10 @@
 #define CONFIG_CMD_IDE
 #define CONFIG_DOS_PARTITION
 
+#ifdef CONFIG_SYS_BIG_ENDIAN
+#define CONFIG_IDE_SWAP_IO
+#endif
+
 #define CONFIG_SYS_IDE_MAXBUS		2
 #define CONFIG_SYS_ATA_IDE0_OFFSET	0x1f0
 #define CONFIG_SYS_ATA_IDE1_OFFSET	0x170
diff --git a/include/configs/qemu-mips64.h b/include/configs/qemu-mips64.h
index 394382c..2394549 100644
--- a/include/configs/qemu-mips64.h
+++ b/include/configs/qemu-mips64.h
@@ -58,6 +58,10 @@
 #define CONFIG_CMD_IDE
 #define CONFIG_DOS_PARTITION
 
+#ifdef CONFIG_SYS_BIG_ENDIAN
+#define CONFIG_IDE_SWAP_IO
+#endif
+
 #define CONFIG_SYS_IDE_MAXBUS		2
 #define CONFIG_SYS_ATA_IDE0_OFFSET	0x1f0
 #define CONFIG_SYS_ATA_IDE1_OFFSET	0x170
diff --git a/include/configs/qemu-x86.h b/include/configs/qemu-x86.h
index b0d2ffe..476d37d 100644
--- a/include/configs/qemu-x86.h
+++ b/include/configs/qemu-x86.h
@@ -43,7 +43,7 @@
 #define CONFIG_ATAPI
 
 #undef CONFIG_SCSI_AHCI
-#undef CONFIG_CMD_SCSI
+#undef CONFIG_SCSI
 #else
 #define CONFIG_SCSI_DEV_LIST		\
 	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_AHCI}
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 9790a14..23a0c40 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -192,4 +192,29 @@
 #define CONFIG_CMD_LZMADEC
 #define CONFIG_CMD_DATE
 
+#define CONFIG_CMD_IDE
+#define CONFIG_SYS_IDE_MAXBUS		1
+#define CONFIG_SYS_ATA_IDE0_OFFSET	0
+#define CONFIG_SYS_IDE_MAXDEVICE	2
+#define CONFIG_SYS_ATA_BASE_ADDR	0x100
+#define CONFIG_SYS_ATA_DATA_OFFSET	0
+#define CONFIG_SYS_ATA_REG_OFFSET	1
+#define CONFIG_SYS_ATA_ALT_OFFSET	2
+#define CONFIG_SYS_ATA_STRIDE		4
+
+#define CONFIG_SCSI
+#define CONFIG_SCSI_AHCI_PLAT
+#define CONFIG_SYS_SCSI_MAX_DEVICE	2
+#define CONFIG_SYS_SCSI_MAX_SCSI_ID	8
+#define CONFIG_SYS_SCSI_MAX_LUN		4
+
+#define CONFIG_CMD_SATA
+#define CONFIG_SYS_SATA_MAX_DEVICE	2
+
+#define CONFIG_SYSTEMACE
+#define CONFIG_SYS_SYSTEMACE_WIDTH	16
+#define CONFIG_SYS_SYSTEMACE_BASE	0
+
+#define CONFIG_GENERIC_MMC
+
 #endif
diff --git a/include/configs/sbc8641d.h b/include/configs/sbc8641d.h
index a7c7aef..c9970f1 100644
--- a/include/configs/sbc8641d.h
+++ b/include/configs/sbc8641d.h
@@ -297,8 +297,6 @@
 
 #define CONFIG_PCI_SCAN_SHOW            /* show pci devices on startup */
 
-#undef CONFIG_SYS_SCSI_SCAN_BUS_REVERSE
-
 #define CONFIG_PCI_PNP			/* do pci plug-and-play */
 
 #undef CONFIG_EEPRO100
diff --git a/include/configs/socfpga_common.h b/include/configs/socfpga_common.h
index 4fdc09a..f657766 100644
--- a/include/configs/socfpga_common.h
+++ b/include/configs/socfpga_common.h
@@ -173,7 +173,6 @@
  * I2C support
  */
 #define CONFIG_SYS_I2C
-#define CONFIG_SYS_I2C_DW
 #define CONFIG_SYS_I2C_BUS_MAX		4
 #define CONFIG_SYS_I2C_BASE		SOCFPGA_I2C0_ADDRESS
 #define CONFIG_SYS_I2C_BASE1		SOCFPGA_I2C1_ADDRESS
diff --git a/include/configs/spear-common.h b/include/configs/spear-common.h
index c4b6234..7b2d262 100644
--- a/include/configs/spear-common.h
+++ b/include/configs/spear-common.h
@@ -35,7 +35,6 @@
 
 /* I2C driver configuration */
 #define CONFIG_SYS_I2C
-#define CONFIG_SYS_I2C_DW
 #if defined(CONFIG_SPEAR600)
 #define CONFIG_SYS_I2C_BASE			0xD0200000
 #elif defined(CONFIG_SPEAR300)
diff --git a/include/configs/sunxi-common.h b/include/configs/sunxi-common.h
index 2406115..ac2d931 100644
--- a/include/configs/sunxi-common.h
+++ b/include/configs/sunxi-common.h
@@ -125,7 +125,7 @@
 #define CONFIG_SYS_SCSI_MAX_LUN		1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
 					 CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #endif
 
 #define CONFIG_SETUP_MEMORY_TAGS
diff --git a/include/configs/theadorable.h b/include/configs/theadorable.h
index 1caa858..dda70c5 100644
--- a/include/configs/theadorable.h
+++ b/include/configs/theadorable.h
@@ -64,6 +64,7 @@
 #define PHY_ANEG_TIMEOUT	8000	/* PHY needs a longer aneg time */
 
 #define CONFIG_SYS_CONSOLE_INFO_QUIET	/* don't print console @ startup */
+#define CONFIG_ZERO_BOOTDELAY_CHECK	/* check for keypress on bootdelay==0 */
 #define CONFIG_SYS_ALT_MEMTEST
 #define CONFIG_PREBOOT
 
diff --git a/include/configs/tplink_wdr4300.h b/include/configs/tplink_wdr4300.h
new file mode 100644
index 0000000..2b9e92e
--- /dev/null
+++ b/include/configs/tplink_wdr4300.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 Marek Vasut <marex@denx.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define CONFIG_SYS_TEXT_BASE		0xa1000000
+
+#define CONFIG_DISPLAY_CPUINFO
+#define CONFIG_DISPLAY_BOARDINFO
+#define CONFIG_BOARD_EARLY_INIT_F
+
+#define CONFIG_SYS_HZ			1000
+#define CONFIG_SYS_MHZ			280
+#define CONFIG_SYS_MIPS_TIMER_FREQ	(CONFIG_SYS_MHZ * 1000000)
+
+/* Cache Configuration */
+#define CONFIG_SYS_DCACHE_SIZE		0x8000
+#define CONFIG_SYS_ICACHE_SIZE		0x10000
+#define CONFIG_SYS_CACHELINE_SIZE	32
+
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+#define CONFIG_SYS_MALLOC_LEN		0x40000
+#define CONFIG_SYS_BOOTPARAMS_LEN	0x20000
+
+#define CONFIG_SYS_SDRAM_BASE		0xa0000000
+#define CONFIG_SYS_LOAD_ADDR		0xa1000000
+#define CONFIG_LOADADDR			CONFIG_SYS_LOAD_ADDR
+
+#define CONFIG_SYS_NO_FLASH
+
+#define CONFIG_SYS_INIT_RAM_ADDR	0xbd000000
+#define CONFIG_SYS_INIT_RAM_SIZE	0x8000
+#define CONFIG_SYS_INIT_SP_ADDR		\
+	(CONFIG_SYS_INIT_RAM_ADDR + CONFIG_SYS_INIT_RAM_SIZE)
+
+/*
+ * Serial Port
+ */
+#define CONFIG_SYS_NS16550_CLK		40000000
+#define CONFIG_BAUDRATE			115200
+#define CONFIG_SYS_BAUDRATE_TABLE \
+	{9600, 19200, 38400, 57600, 115200}
+
+#define CONFIG_BOOTDELAY		3
+#define CONFIG_BOOTARGS			\
+	"console=ttyS0,115200 root=/dev/mtdblock2 rootfstype=squashfs"
+#define CONFIG_BOOTCOMMAND		\
+	"dhcp 192.168.1.1:wdr4300.fit && bootm $loadaddr"
+#define CONFIG_LZMA
+
+#define CONFIG_ENV_IS_NOWHERE
+#define CONFIG_ENV_SIZE			0x10000
+
+/*
+ * Command
+ */
+/* Miscellaneous configurable options */
+#define CONFIG_SYS_LONGHELP
+#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 */
+#define CONFIG_AUTO_COMPLETE			/* Command auto complete */
+#define CONFIG_CMDLINE_EDITING			/* Command history etc */
+#define CONFIG_SYS_HUSH_PARSER
+#define CONFIG_SYS_PROMPT_HUSH_PS2	"> "
+
+/* USB, USB storage, USB ethernet */
+#define CONFIG_EHCI_MMIO_BIG_ENDIAN
+#define CONFIG_EHCI_DESC_BIG_ENDIAN
+#define CONFIG_EHCI_IS_TDI
+
+#define CONFIG_DOS_PARTITION
+
+/*
+ * Diagnostics
+ */
+#define CONFIG_SYS_MEMTEST_START	0x80100000
+#define CONFIG_SYS_MEMTEST_END		0x83f00000
+#define CONFIG_CMD_MEMTEST
+
+#define CONFIG_USE_PRIVATE_LIBGCC
+
+#define CONFIG_CMD_MII
+#define CONFIG_PHY_GIGE
+
+#endif  /* __CONFIG_H */
diff --git a/include/configs/x600.h b/include/configs/x600.h
index d7da0b2..5fdd2be 100644
--- a/include/configs/x600.h
+++ b/include/configs/x600.h
@@ -85,7 +85,6 @@
 
 /* I2C config options */
 #define CONFIG_SYS_I2C
-#define CONFIG_SYS_I2C_DW
 #define CONFIG_SYS_I2C_BASE			0xD0200000
 #define CONFIG_SYS_I2C_SPEED			400000
 #define CONFIG_SYS_I2C_SLAVE			0x02
diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index a2822e0..b79f47b 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -100,7 +100,7 @@
 #define CONFIG_CMD_IRQ
 #define CONFIG_CMD_PCI
 #define CONFIG_CMD_GETTIME
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 
 #define CONFIG_CMD_ZBOOT
 
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h
index 060bca9..6b8e3ea 100644
--- a/include/configs/xilinx_zynqmp.h
+++ b/include/configs/xilinx_zynqmp.h
@@ -201,7 +201,7 @@
 #define CONFIG_SYS_SCSI_MAX_LUN		1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
 					 CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_CMD_SCSI
+#define CONFIG_SCSI
 #endif
 
 #define CONFIG_SYS_BOOTM_LEN	(60 * 1024 * 1024)
diff --git a/include/dm/device.h b/include/dm/device.h
index 8970fc0..e9a8ec7 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -41,6 +41,9 @@
 /* Device is bound */
 #define DM_FLAG_BOUND			(1 << 6)
 
+/* Device name is allocated and should be freed on unbind() */
+#define DM_NAME_ALLOCED			(1 << 7)
+
 /**
  * struct udevice - An instance of a driver
  *
@@ -523,6 +526,9 @@
  * this is unnecessary but for probed devices which don't get a useful name
  * this function can be helpful.
  *
+ * The name is allocated and will be freed automatically when the device is
+ * unbound.
+ *
  * @dev:	Device to update
  * @name:	New name (this string is allocated new memory and attached to
  *		the device)
@@ -532,6 +538,16 @@
 int device_set_name(struct udevice *dev, const char *name);
 
 /**
+ * device_set_name_alloced() - note that a device name is allocated
+ *
+ * This sets the DM_NAME_ALLOCED flag for the device, so that when it is
+ * unbound the name will be freed. This avoids memory leaks.
+ *
+ * @dev:	Device to update
+ */
+void device_set_name_alloced(struct udevice *dev);
+
+/**
  * device_is_on_pci_bus - Test if a device is on a PCI bus
  *
  * @dev:	device to test
diff --git a/include/dm/platform_data/serial_coldfire.h b/include/dm/platform_data/serial_coldfire.h
new file mode 100644
index 0000000..5d86456
--- /dev/null
+++ b/include/dm/platform_data/serial_coldfire.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright (c) 2015  Angelo Dureghello <angelo@sysam.it>
+ *
+ * SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#ifndef __serial_coldfire_h
+#define __serial_coldfire_h
+
+/*
+ * struct coldfire_serial_platdata - information about a coldfire port
+ *
+ * @base:               Uart port base register address
+ * @port:               Uart port index, for cpu with pinmux for uart / gpio
+ * baudrtatre:          Uart port baudrate
+ */
+struct coldfire_serial_platdata {
+	unsigned long base;
+	int port;
+	int baudrate;
+};
+
+#endif /* __serial_coldfire_h */
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index cbf9b2c..a5cf6e2 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -26,11 +26,11 @@
 
 	/* U-Boot uclasses start here - in alphabetical order */
 	UCLASS_ADC,		/* Analog-to-digital converter */
+	UCLASS_AHCI,		/* SATA disk controller */
 	UCLASS_BLK,		/* Block device */
 	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
-	UCLASS_DISK,		/* Disk controller, e.g. SATA */
 	UCLASS_DISPLAY,		/* Display (e.g. DisplayPort, HDMI) */
 	UCLASS_DMA,		/* Direct Memory Access */
 	UCLASS_RAM,		/* RAM controller */
diff --git a/include/eeprom_field.h b/include/eeprom_field.h
new file mode 100644
index 0000000..94e259f
--- /dev/null
+++ b/include/eeprom_field.h
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _FIELD_
+#define _FIELD_
+
+#define PRINT_FIELD_SEGMENT	"%-30s"
+
+struct eeprom_field {
+	char *name;
+	int size;
+	unsigned char *buf;
+
+	void (*print)(const struct eeprom_field *eeprom_field);
+	int (*update)(struct eeprom_field *eeprom_field, char *value);
+};
+
+void eeprom_field_print_bin(const struct eeprom_field *field);
+int eeprom_field_update_bin(struct eeprom_field *field, char *value);
+
+void eeprom_field_print_bin_rev(const struct eeprom_field *field);
+int eeprom_field_update_bin_rev(struct eeprom_field *field, char *value);
+
+void eeprom_field_print_mac(const struct eeprom_field *field);
+int eeprom_field_update_mac(struct eeprom_field *field, char *value);
+
+void eeprom_field_print_ascii(const struct eeprom_field *field);
+int eeprom_field_update_ascii(struct eeprom_field *field, char *value);
+
+void eeprom_field_print_reserved(const struct eeprom_field *field);
+int eeprom_field_update_reserved(struct eeprom_field *field, char *value);
+
+#endif
diff --git a/include/eeprom_layout.h b/include/eeprom_layout.h
new file mode 100644
index 0000000..459b99d
--- /dev/null
+++ b/include/eeprom_layout.h
@@ -0,0 +1,33 @@
+/*
+ * (C) Copyright 2009-2016 CompuLab, Ltd.
+ *
+ * Authors: Nikita Kiryanov <nikita@compulab.co.il>
+ *	    Igor Grinberg <grinberg@compulab.co.il>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef _LAYOUT_
+#define _LAYOUT_
+
+#define RESERVED_FIELDS			NULL
+#define LAYOUT_VERSION_UNRECOGNIZED	-1
+#define LAYOUT_VERSION_AUTODETECT	-2
+
+struct eeprom_layout {
+	struct eeprom_field *fields;
+	int num_of_fields;
+	int layout_version;
+	unsigned char *data;
+	int data_size;
+	void (*print)(const struct eeprom_layout *eeprom_layout);
+	int (*update)(struct eeprom_layout *eeprom_layout, char *field_name,
+		      char *new_data);
+};
+
+void eeprom_layout_setup(struct eeprom_layout *layout, unsigned char *buf,
+			 unsigned int buf_size, int layout_version);
+__weak void __eeprom_layout_assign(struct eeprom_layout *layout,
+				   int layout_version);
+
+#endif
diff --git a/include/flash.h b/include/flash.h
index c6321a0..2a5e13a 100644
--- a/include/flash.h
+++ b/include/flash.h
@@ -400,6 +400,9 @@
 #define FLASH_STM800DT	0x00D7		/* STM M29W800DT (1M = 64K x 16, top)	*/
 #define FLASH_STM800DB	0x005B		/* STM M29W800DB (1M = 64K x 16, bottom)*/
 
+#define FLASH_MCHP100T	0x0060		/* MCHP internal (1M = 64K x 16) */
+#define FLASH_MCHP100B	0x0061		/* MCHP internal (1M = 64K x 16) */
+
 #define FLASH_28F400_T	0x0062		/* MT  28F400B3 ID (  4M = 256K x 16 )	*/
 #define FLASH_28F400_B	0x0063		/* MT  28F400B3 ID (  4M = 256K x 16 )	*/
 
@@ -486,7 +489,7 @@
 #define FLASH_MAN_SHARP 0x00500000
 #define FLASH_MAN_ATM	0x00600000
 #define FLASH_MAN_CFI	0x01000000
-
+#define FLASH_MAN_MCHP	0x02000000	/* Microchip Technology		*/
 
 #define FLASH_TYPEMASK	0x0000FFFF	/* extract FLASH type	information	*/
 #define FLASH_VENDMASK	0xFFFF0000	/* extract FLASH vendor information	*/
diff --git a/include/ide.h b/include/ide.h
index a4e65cf..9b0a4a9 100644
--- a/include/ide.h
+++ b/include/ide.h
@@ -34,10 +34,18 @@
 
 void ide_init(void);
 struct blk_desc;
+struct udevice;
+#ifdef CONFIG_BLK
+ulong ide_read(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+	       void *buffer);
+ulong ide_write(struct udevice *dev, lbaint_t blknr, lbaint_t blkcnt,
+		const void *buffer);
+#else
 ulong ide_read(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
 	       void *buffer);
 ulong ide_write(struct blk_desc *block_dev, lbaint_t blknr, lbaint_t blkcnt,
 		const void *buffer);
+#endif
 
 #ifdef CONFIG_IDE_PREINIT
 int ide_preinit(void);
diff --git a/include/iotrace.h b/include/iotrace.h
index 9bd1f16..e4ceb61 100644
--- a/include/iotrace.h
+++ b/include/iotrace.h
@@ -31,10 +31,11 @@
 #define writew(val, addr)	iotrace_writew(val, (const void *)(addr))
 
 #undef readb
-#define readb(addr)	iotrace_readb((const void *)(addr))
+#define readb(addr)	iotrace_readb((const void *)(uintptr_t)addr)
 
 #undef writeb
-#define writeb(val, addr)	iotrace_writeb(val, (const void *)(addr))
+#define writeb(val, addr) \
+	iotrace_writeb(val, (const void *)(uintptr_t)addr)
 
 #endif
 
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 7ec5550..8f8ac6a 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -17,4 +17,13 @@
 	USB_DR_MODE_OTG,
 };
 
+/**
+ * usb_get_dr_mode() - Get dual role mode for given device
+ * @node: Node offset to the given device
+ *
+ * The function gets phy interface string from property 'dr_mode',
+ * and returns the correspondig enum usb_dr_mode
+ */
+enum usb_dr_mode usb_get_dr_mode(int node);
+
 #endif /* __LINUX_USB_OTG_H */
diff --git a/include/mmc.h b/include/mmc.h
index cdb56e7..a5c6573 100644
--- a/include/mmc.h
+++ b/include/mmc.h
@@ -344,7 +344,9 @@
 
 /* TODO struct mmc should be in mmc_private but it's hard to fix right now */
 struct mmc {
+#ifndef CONFIG_BLK
 	struct list_head link;
+#endif
 	const struct mmc_config *cfg;	/* provided configuration */
 	uint version;
 	void *priv;
@@ -376,11 +378,16 @@
 	u64 capacity_gp[4];
 	u64 enh_user_start;
 	u64 enh_user_size;
+#ifndef CONFIG_BLK
 	struct blk_desc block_dev;
+#endif
 	char op_cond_pending;	/* 1 if we are waiting on an op_cond command */
 	char init_in_progress;	/* 1 if we have done mmc_start_init() */
 	char preinit;		/* start init as early as possible */
 	int ddr_mode;
+#ifdef CONFIG_DM_MMC
+	struct udevice *dev;	/* Device for this MMC controller */
+#endif
 };
 
 struct mmc_hwpart_conf {
@@ -406,7 +413,29 @@
 
 int mmc_register(struct mmc *mmc);
 struct mmc *mmc_create(const struct mmc_config *cfg, void *priv);
+
+/**
+ * mmc_bind() - Set up a new MMC device ready for probing
+ *
+ * A child block device is bound with the IF_TYPE_MMC interface type. This
+ * allows the device to be used with CONFIG_BLK
+ *
+ * @dev:	MMC device to set up
+ * @mmc:	MMC struct
+ * @cfg:	MMC configuration
+ * @return 0 if OK, -ve on error
+ */
+int mmc_bind(struct udevice *dev, struct mmc *mmc,
+	     const struct mmc_config *cfg);
 void mmc_destroy(struct mmc *mmc);
+
+/**
+ * mmc_unbind() - Unbind a MMC device's child block device
+ *
+ * @dev:	MMC device
+ * @return 0 if OK, -ve on error
+ */
+int mmc_unbind(struct udevice *dev);
 int mmc_initialize(bd_t *bis);
 int mmc_init(struct mmc *mmc);
 int mmc_read(struct mmc *mmc, u64 src, uchar *dst, int size);
@@ -415,7 +444,6 @@
 int mmc_set_dev(int dev_num);
 void print_mmc_devices(char separator);
 int get_mmc_num(void);
-int mmc_switch_part(int dev_num, unsigned int part_num);
 int mmc_hwpart_config(struct mmc *mmc, const struct mmc_hwpart_conf *conf,
 		      enum mmc_hwpart_conf_mode mode);
 int mmc_getcd(struct mmc *mmc);
@@ -498,4 +526,12 @@
 #define CONFIG_SYS_MMC_MAX_BLK_COUNT 65535
 #endif
 
+/**
+ * mmc_get_blk_desc() - Get the block descriptor for an MMC device
+ *
+ * @mmc:	MMC device
+ * @return block device if found, else NULL
+ */
+struct blk_desc *mmc_get_blk_desc(struct mmc *mmc);
+
 #endif /* _MMC_H_ */
diff --git a/include/part.h b/include/part.h
index e3811c6..226b5be 100644
--- a/include/part.h
+++ b/include/part.h
@@ -12,7 +12,6 @@
 
 struct block_drvr {
 	char *name;
-	struct blk_desc* (*get_dev)(int dev);
 	int (*select_hwpart)(int dev_num, int hwpart);
 };
 
@@ -73,32 +72,8 @@
  *	   error occurred.
  */
 struct blk_desc *blk_get_dev(const char *ifname, int dev);
-struct blk_desc *ide_get_dev(int dev);
-struct blk_desc *sata_get_dev(int dev);
-struct blk_desc *scsi_get_dev(int dev);
-struct blk_desc *usb_stor_get_dev(int dev);
-struct blk_desc *mmc_get_dev(int dev);
 
-/**
- * mmc_select_hwpart() - Select the MMC hardware partiion on an MMC device
- *
- * MMC devices can support partitioning at the hardware level. This is quite
- * separate from the normal idea of software-based partitions. MMC hardware
- * partitions must be explicitly selected. Once selected only the region of
- * the device covered by that partition is accessible.
- *
- * The MMC standard provides for two boot partitions (numbered 1 and 2),
- * rpmb (3), and up to 4 addition general-purpose partitions (4-7).
- *
- * @dev_num:	Block device number (struct blk_desc->dev value)
- * @hwpart:	Hardware partition number to select. 0 means the raw device,
- *		1 is the first partition, 2 is the second, etc.
- * @return 0 if OK, other value for an error
- */
-int mmc_select_hwpart(int dev_num, int hwpart);
-struct blk_desc *systemace_get_dev(int dev);
 struct blk_desc *mg_disk_get_dev(int dev);
-struct blk_desc *host_get_dev(int dev);
 int host_get_dev_err(int dev, struct blk_desc **blk_devp);
 
 /* disk/part.c */
@@ -175,15 +150,7 @@
 #else
 static inline struct blk_desc *blk_get_dev(const char *ifname, int dev)
 { return NULL; }
-static inline struct blk_desc *ide_get_dev(int dev) { return NULL; }
-static inline struct blk_desc *sata_get_dev(int dev) { return NULL; }
-static inline struct blk_desc *scsi_get_dev(int dev) { return NULL; }
-static inline struct blk_desc *usb_stor_get_dev(int dev) { return NULL; }
-static inline struct blk_desc *mmc_get_dev(int dev) { return NULL; }
-static inline int mmc_select_hwpart(int dev_num, int hwpart) { return -1; }
-static inline struct blk_desc *systemace_get_dev(int dev) { return NULL; }
 static inline struct blk_desc *mg_disk_get_dev(int dev) { return NULL; }
-static inline struct blk_desc *host_get_dev(int dev) { return NULL; }
 
 static inline int part_get_info(struct blk_desc *dev_desc, int part,
 				disk_partition_t *info) { return -1; }
diff --git a/include/spi.h b/include/spi.h
index 4b88d39..ca96fa4 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -612,6 +612,58 @@
 			 struct udevice *bus, struct udevice *slave,
 			 struct udevice **emulp);
 
+/**
+ * Claim the bus and prepare it for communication with a given slave.
+ *
+ * This must be called before doing any transfers with a SPI slave. It
+ * will enable and initialize any SPI hardware as necessary, and make
+ * sure that the SCK line is in the correct idle state. It is not
+ * allowed to claim the same bus for several slaves without releasing
+ * the bus in between.
+ *
+ * @dev:	The SPI slave device
+ *
+ * Returns: 0 if the bus was claimed successfully, or a negative value
+ * if it wasn't.
+ */
+int dm_spi_claim_bus(struct udevice *dev);
+
+/**
+ * Release the SPI bus
+ *
+ * This must be called once for every call to dm_spi_claim_bus() after
+ * all transfers have finished. It may disable any SPI hardware as
+ * appropriate.
+ *
+ * @slave:	The SPI slave device
+ */
+void dm_spi_release_bus(struct udevice *dev);
+
+/**
+ * SPI transfer
+ *
+ * This writes "bitlen" bits out the SPI MOSI port and simultaneously clocks
+ * "bitlen" bits in the SPI MISO port.  That's just the way SPI works.
+ *
+ * The source of the outgoing bits is the "dout" parameter and the
+ * destination of the input bits is the "din" parameter.  Note that "dout"
+ * and "din" can point to the same memory location, in which case the
+ * input data overwrites the output data (since both are buffered by
+ * temporary variables, this is OK).
+ *
+ * dm_spi_xfer() interface:
+ * @dev:	The SPI slave device which will be sending/receiving the data.
+ * @bitlen:	How many bits to write and read.
+ * @dout:	Pointer to a string of bits to send out.  The bits are
+ *		held in a byte array and are sent MSB first.
+ * @din:	Pointer to a string of bits that will be filled in.
+ * @flags:	A bitwise combination of SPI_XFER_* flags.
+ *
+ * Returns: 0 on success, not 0 on failure
+ */
+int dm_spi_xfer(struct udevice *dev, unsigned int bitlen,
+		const void *dout, void *din, unsigned long flags);
+
 /* Access the operations for a SPI device */
 #define spi_get_ops(dev)	((struct dm_spi_ops *)(dev)->driver->ops)
 #define spi_emul_get_ops(dev)	((struct dm_spi_emul_ops *)(dev)->driver->ops)
diff --git a/include/systemace.h b/include/systemace.h
deleted file mode 100644
index 3b6ec7d..0000000
--- a/include/systemace.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __SYSTEMACE_H
-#define __SYSTEMACE_H
-/*
- * Copyright (c) 2004 Picture Elements, Inc.
- *    Stephen Williams (steve@picturel.com)
- *
- * SPDX-License-Identifier:	GPL-2.0+
- */
-
-#ifdef CONFIG_SYSTEMACE
-
-# include  <part.h>
-
-struct blk_desc *systemace_get_dev(int dev);
-
-#endif	/* CONFIG_SYSTEMACE */
-#endif	/* __SYSTEMACE_H */
diff --git a/include/usb.h b/include/usb.h
index 5adad36..02a0ccd 100644
--- a/include/usb.h
+++ b/include/usb.h
@@ -228,7 +228,6 @@
 #ifdef CONFIG_USB_STORAGE
 
 #define USB_MAX_STOR_DEV 7
-struct blk_desc *usb_stor_get_dev(int index);
 int usb_stor_scan(int mode);
 int usb_stor_info(void);
 
diff --git a/lib/efi_loader/efi_disk.c b/lib/efi_loader/efi_disk.c
index 28e5b7f..075fd34 100644
--- a/lib/efi_loader/efi_disk.c
+++ b/lib/efi_loader/efi_disk.c
@@ -7,6 +7,7 @@
  */
 
 #include <common.h>
+#include <blk.h>
 #include <efi_loader.h>
 #include <inttypes.h>
 #include <part.h>
@@ -142,7 +143,7 @@
 };
 
 static void efi_disk_add_dev(char *name,
-			     const struct block_drvr *cur_drvr,
+			     const struct blk_driver *cur_drvr,
 			     const struct blk_desc *desc,
 			     int dev_index,
 			     lbaint_t offset)
@@ -160,7 +161,7 @@
 	diskobj->parent.protocols[1].open = efi_disk_open_dp;
 	diskobj->parent.handle = diskobj;
 	diskobj->ops = block_io_disk_template;
-	diskobj->ifname = cur_drvr->name;
+	diskobj->ifname = cur_drvr->if_typename;
 	diskobj->dev_index = dev_index;
 	diskobj->offset = offset;
 
@@ -189,7 +190,7 @@
 }
 
 static int efi_disk_create_eltorito(struct blk_desc *desc,
-				    const struct block_drvr *cur_drvr,
+				    const struct blk_driver *cur_drvr,
 				    int diskid)
 {
 	int disks = 0;
@@ -202,8 +203,8 @@
 		return 0;
 
 	while (!part_get_info(desc, part, &info)) {
-		snprintf(devname, sizeof(devname), "%s%d:%d", cur_drvr->name,
-			 diskid, part);
+		snprintf(devname, sizeof(devname), "%s%d:%d",
+			 cur_drvr->if_typename, diskid, part);
 		efi_disk_add_dev(devname, cur_drvr, desc, diskid, info.start);
 		part++;
 		disks++;
@@ -222,25 +223,29 @@
  */
 int efi_disk_register(void)
 {
-	const struct block_drvr *cur_drvr;
-	int i;
+	const struct blk_driver *cur_drvr;
+	int i, if_type;
 	int disks = 0;
 
 	/* Search for all available disk devices */
-	for (cur_drvr = block_drvr; cur_drvr->name; cur_drvr++) {
-		printf("Scanning disks on %s...\n", cur_drvr->name);
+	for (if_type = 0; if_type < IF_TYPE_COUNT; if_type++) {
+		cur_drvr = blk_driver_lookup_type(if_type);
+		if (!cur_drvr)
+			continue;
+
+		printf("Scanning disks on %s...\n", cur_drvr->if_typename);
 		for (i = 0; i < 4; i++) {
 			struct blk_desc *desc;
 			char devname[32] = { 0 }; /* dp->str is u16[32] long */
 
-			desc = blk_get_dev(cur_drvr->name, i);
+			desc = blk_get_devnum_by_type(if_type, i);
 			if (!desc)
 				continue;
 			if (desc->type == DEV_TYPE_UNKNOWN)
 				continue;
 
 			snprintf(devname, sizeof(devname), "%s%d",
-				 cur_drvr->name, i);
+				 cur_drvr->if_typename, i);
 			efi_disk_add_dev(devname, cur_drvr, desc, i, 0);
 			disks++;
 
diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c
index e8e8c77..9bd0de2 100644
--- a/scripts/basic/fixdep.c
+++ b/scripts/basic/fixdep.c
@@ -296,7 +296,11 @@
 		perror(filename);
 		exit(2);
 	}
-	fstat(fd, &st);
+	if (fstat(fd, &st) < 0) {
+		fprintf(stderr, "fixdep: error fstat'ing config file: ");
+		perror(filename);
+		exit(2);
+	}
 	if (st.st_size == 0) {
 		close(fd);
 		return;
diff --git a/test/dm/blk.c b/test/dm/blk.c
index f4ea32e..012bf4c 100644
--- a/test/dm/blk.c
+++ b/test/dm/blk.c
@@ -83,12 +83,12 @@
 	ut_asserteq_ptr(usb_dev, dev_get_parent(dev));
 
 	/* Check we have one block device for each mass storage device */
-	ut_asserteq(3, count_blk_devices());
+	ut_asserteq(4, count_blk_devices());
 
 	/* Now go around again, making sure the old devices were unbound */
 	ut_assertok(usb_stop());
 	ut_assertok(usb_init());
-	ut_asserteq(3, count_blk_devices());
+	ut_asserteq(4, count_blk_devices());
 	ut_assertok(usb_stop());
 
 	return 0;
diff --git a/test/dm/mmc.c b/test/dm/mmc.c
index 0461423..5bca4b7 100644
--- a/test/dm/mmc.c
+++ b/test/dm/mmc.c
@@ -25,3 +25,22 @@
 	return 0;
 }
 DM_TEST(dm_test_mmc_base, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int dm_test_mmc_blk(struct unit_test_state *uts)
+{
+	struct udevice *dev;
+	struct blk_desc *dev_desc;
+	char cmp[1024];
+
+	ut_assertok(uclass_get_device(UCLASS_MMC, 0, &dev));
+	ut_assertok(blk_get_device_by_str("mmc", "0", &dev_desc));
+
+	/* Read a few blocks and look for the string we expect */
+	ut_asserteq(512, dev_desc->blksz);
+	memset(cmp, '\0', sizeof(cmp));
+	ut_asserteq(2, blk_dread(dev_desc, 0, 2, cmp));
+	ut_assertok(strcmp(cmp, "this is a test"));
+
+	return 0;
+}
+DM_TEST(dm_test_mmc_blk, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/tools/buildman/README b/tools/buildman/README
index 4705d26..26755c5 100644
--- a/tools/buildman/README
+++ b/tools/buildman/README
@@ -898,6 +898,48 @@
 will build commits in us-buildman that are not in upstream/master.
 
 
+Building Faster
+===============
+
+By default, buildman executes 'make mrproper' prior to building the first
+commit for each board. This causes everything to be built from scratch. If you
+trust the build system's incremental build capabilities, you can pass the -I
+flag to skip the 'make mproper' invocation, which will reduce the amount of
+work 'make' does, and hence speed up the build. This flag will speed up any
+buildman invocation, since it reduces the amount of work done on any build.
+
+One possible application of buildman is as part of a continual edit, build,
+edit, build, ... cycle; repeatedly applying buildman to the same change or
+series of changes while making small incremental modifications to the source
+each time. This provides quick feedback regarding the correctness of recent
+modifications. In this scenario, buildman's default choice of build directory
+causes more build work to be performed than strictly necessary.
+
+By default, each buildman thread uses a single directory for all builds. When a
+thread builds multiple boards, the configuration built in this directory will
+cycle through various different configurations, one per board built by the
+thread. Variations in the configuration will force a rebuild of affected source
+files when a thread switches between boards. Ideally, such buildman-induced
+rebuilds would not happen, thus allowing the build to operate as efficiently as
+the build system and source changes allow. buildman's -P flag may be used to
+enable this; -P causes each board to be built in a separate (board-specific)
+directory, thus avoiding any buildman-induced configuration changes in any
+build directory.
+
+U-Boot's build system embeds information such as a build timestamp into the
+final binary. This information varies each time U-Boot is built. This causes
+various files to be rebuilt even if no source changes are made, which in turn
+requires that the final U-Boot binary be re-linked. This unnecessary work can
+be avoided by turning off the timestamp feature. This can be achieved by
+setting the SOURCE_DATE_EPOCH environment variable to 0.
+
+Combining all of these options together yields the command-line shown below.
+This will provide the quickest possible feedback regarding the current content
+of the source tree, thus allowing rapid tested evolution of the code.
+
+    SOURCE_DATE_EPOCH=0 ./tools/buildman/buildman -I -P tegra
+
+
 Other options
 =============
 
diff --git a/tools/buildman/builder.py b/tools/buildman/builder.py
index 141bf64..8ec3551 100644
--- a/tools/buildman/builder.py
+++ b/tools/buildman/builder.py
@@ -205,7 +205,8 @@
 
     def __init__(self, toolchains, base_dir, git_dir, num_threads, num_jobs,
                  gnu_make='make', checkout=True, show_unknown=True, step=1,
-                 no_subdirs=False, full_path=False, verbose_build=False):
+                 no_subdirs=False, full_path=False, verbose_build=False,
+                 incremental=False, per_board_out_dir=False):
         """Create a new Builder object
 
         Args:
@@ -224,6 +225,10 @@
             full_path: Return the full path in CROSS_COMPILE and don't set
                 PATH
             verbose_build: Run build with V=1 and don't use 'make -s'
+            incremental: Always perform incremental builds; don't run make
+                mrproper when configuring
+            per_board_out_dir: Build in a separate persistent directory per
+                board rather than a thread-specific directory
         """
         self.toolchains = toolchains
         self.base_dir = base_dir
@@ -263,7 +268,8 @@
         self.queue = Queue.Queue()
         self.out_queue = Queue.Queue()
         for i in range(self.num_threads):
-            t = builderthread.BuilderThread(self, i)
+            t = builderthread.BuilderThread(self, i, incremental,
+                    per_board_out_dir)
             t.setDaemon(True)
             t.start()
             self.threads.append(t)
diff --git a/tools/buildman/builderthread.py b/tools/buildman/builderthread.py
index cf25bb8..c512d3b 100644
--- a/tools/buildman/builderthread.py
+++ b/tools/buildman/builderthread.py
@@ -80,11 +80,13 @@
         thread_num: Our thread number (0-n-1), used to decide on a
                 temporary directory
     """
-    def __init__(self, builder, thread_num):
+    def __init__(self, builder, thread_num, incremental, per_board_out_dir):
         """Set up a new builder thread"""
         threading.Thread.__init__(self)
         self.builder = builder
         self.thread_num = thread_num
+        self.incremental = incremental
+        self.per_board_out_dir = per_board_out_dir
 
     def Make(self, commit, brd, stage, cwd, *args, **kwargs):
         """Run 'make' on a particular commit and board.
@@ -136,7 +138,11 @@
         if self.builder.in_tree:
             out_dir = work_dir
         else:
-            out_dir = os.path.join(work_dir, 'build')
+            if self.per_board_out_dir:
+                out_rel_dir = os.path.join('..', brd.target)
+            else:
+                out_rel_dir = 'build'
+            out_dir = os.path.join(work_dir, out_rel_dir)
 
         # Check if the job was already completed last time
         done_file = self.builder.GetDoneFile(commit_upto, brd.target)
@@ -197,12 +203,12 @@
                         #
                         # Symlinks can confuse U-Boot's Makefile since
                         # we may use '..' in our path, so remove them.
-                        work_dir = os.path.realpath(work_dir)
-                        args.append('O=%s/build' % work_dir)
+                        out_dir = os.path.realpath(out_dir)
+                        args.append('O=%s' % out_dir)
                         cwd = None
                         src_dir = os.getcwd()
                     else:
-                        args.append('O=build')
+                        args.append('O=%s' % out_rel_dir)
                 if self.builder.verbose_build:
                     args.append('V=1')
                 else:
@@ -215,9 +221,11 @@
 
                 # If we need to reconfigure, do that now
                 if do_config:
-                    result = self.Make(commit, brd, 'mrproper', cwd,
-                            'mrproper', *args, env=env)
-                    config_out = result.combined
+                    config_out = ''
+                    if not self.incremental:
+                        result = self.Make(commit, brd, 'mrproper', cwd,
+                                'mrproper', *args, env=env)
+                        config_out += result.combined
                     result = self.Make(commit, brd, 'config', cwd,
                             *(args + config_args), env=env)
                     config_out += result.combined
diff --git a/tools/buildman/cmdline.py b/tools/buildman/cmdline.py
index 8341ab1..3e3bd63 100644
--- a/tools/buildman/cmdline.py
+++ b/tools/buildman/cmdline.py
@@ -49,6 +49,8 @@
     parser.add_option('-i', '--in-tree', dest='in_tree',
           action='store_true', default=False,
           help='Build in the source tree instead of a separate directory')
+    parser.add_option('-I', '--incremental', action='store_true',
+          default=False, help='Do not run make mrproper (when reconfiguring)')
     parser.add_option('-j', '--jobs', dest='jobs', type='int',
           default=None, help='Number of jobs to run at once (passed to make)')
     parser.add_option('-k', '--keep-outputs', action='store_true',
@@ -70,6 +72,8 @@
           default=False, help='Do a rough build, with limited warning resolution')
     parser.add_option('-p', '--full-path', action='store_true',
           default=False, help="Use full toolchain path in CROSS_COMPILE")
+    parser.add_option('-P', '--per-board-out-dir', action='store_true',
+          default=False, help="Use an O= (output) directory per board rather than per thread")
     parser.add_option('-s', '--summary', action='store_true',
           default=False, help='Show a build summary')
     parser.add_option('-S', '--show-sizes', action='store_true',
diff --git a/tools/buildman/control.py b/tools/buildman/control.py
index c2c54bf..aeb128a 100644
--- a/tools/buildman/control.py
+++ b/tools/buildman/control.py
@@ -250,7 +250,9 @@
             options.threads, options.jobs, gnu_make=gnu_make, checkout=True,
             show_unknown=options.show_unknown, step=options.step,
             no_subdirs=options.no_subdirs, full_path=options.full_path,
-            verbose_build=options.verbose_build)
+            verbose_build=options.verbose_build,
+            incremental=options.incremental,
+            per_board_out_dir=options.per_board_out_dir,)
     builder.force_config_on_failure = not options.quick
     if make_func:
         builder.do_make = make_func
diff --git a/tools/imagetool.c b/tools/imagetool.c
index 916ab96..08d191d 100644
--- a/tools/imagetool.c
+++ b/tools/imagetool.c
@@ -51,7 +51,8 @@
 				 * successful
 				 */
 				if ((*curr)->print_header) {
-					(*curr)->print_header(ptr);
+					if (!params->quiet)
+						(*curr)->print_header(ptr);
 				} else {
 					fprintf(stderr,
 						"%s: print_header undefined for %s\n",
diff --git a/tools/imagetool.h b/tools/imagetool.h
index 24f8f4b..a3ed0f4 100644
--- a/tools/imagetool.h
+++ b/tools/imagetool.h
@@ -73,6 +73,7 @@
 	struct content_info *content_head;	/* List of files to include */
 	struct content_info *content_tail;
 	bool external_data;	/* Store data outside the FIT */
+	bool quiet;		/* Don't output text in normal operation */
 };
 
 /*
diff --git a/tools/mkimage.c b/tools/mkimage.c
index 93d1c16..aefe22f 100644
--- a/tools/mkimage.c
+++ b/tools/mkimage.c
@@ -136,7 +136,7 @@
 	int opt;
 
 	while ((opt = getopt(argc, argv,
-			     "a:A:b:cC:d:D:e:Ef:Fk:K:ln:O:rR:sT:vVx")) != -1) {
+			     "a:A:b:cC:d:D:e:Ef:Fk:K:ln:O:rR:qsT:vVx")) != -1) {
 		switch (opt) {
 		case 'a':
 			params.addr = strtoull(optarg, &ptr, 16);
@@ -216,6 +216,9 @@
 			if (params.os < 0)
 				usage("Invalid operating system");
 			break;
+		case 'q':
+			params.quiet = 1;
+			break;
 		case 'r':
 			params.require_keys = 1;
 			break;