Merge git://git.denx.de/u-boot-dm
diff --git a/README b/README
index d881da2..94e9943 100644
--- a/README
+++ b/README
@@ -1066,7 +1066,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 +1254,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_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/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/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/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/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/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/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/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..f9b26b7 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
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/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/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_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/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/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/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/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/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/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/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/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/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/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/cm_t54.h b/include/configs/cm_t54.h
index 9b13aa6..ac6103c 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
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-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/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/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/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/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