Merge branch 'master' of git://git.denx.de/u-boot-dm
diff --git a/Kconfig b/Kconfig
index 4157da3..fed488f 100644
--- a/Kconfig
+++ b/Kconfig
@@ -116,8 +116,9 @@
 	depends on FIT
 
 config FIT_SIGNATURE
-	bool "Enabel signature verification of FIT uImages"
+	bool "Enable signature verification of FIT uImages"
 	depends on FIT
+	select RSA
 	help
 	  This option enables signature verification of FIT uImages,
 	  using a hash signed and verified using RSA.
diff --git a/Makefile b/Makefile
index ea5ae8f..9b406c8 100644
--- a/Makefile
+++ b/Makefile
@@ -776,6 +776,13 @@
 	@echo "See doc/README.generic-board for further information"
 	@echo "===================================================="
 endif
+ifeq ($(CONFIG_DM_I2C_COMPAT),y)
+	@echo "===================== WARNING ======================"
+	@echo "This board uses CONFIG_DM_I2C_COMPAT. Please remove"
+	@echo "(possibly in a subsequent patch in your series)"
+	@echo "before sending patches to the mailing list."
+	@echo "===================================================="
+endif
 
 PHONY += dtbs
 dtbs dts/dt.dtb: checkdtc u-boot
diff --git a/README b/README
index a11e74a..a28ff13 100644
--- a/README
+++ b/README
@@ -3176,8 +3176,13 @@
 		This enables the RSA algorithm used for FIT image verification
 		in U-Boot. See doc/uImage.FIT/signature.txt for more information.
 
+		The Modular Exponentiation algorithm in RSA is implemented using
+		driver model. So CONFIG_DM needs to be enabled by default for this
+		library to function.
+
 		The signing part is build into mkimage regardless of this
-		option.
+		option. The software based modular exponentiation is built into
+		mkimage irrespective of this option.
 
 - bootcount support:
 		CONFIG_BOOTCOUNT_LIMIT
diff --git a/arch/arm/cpu/armv7/exynos/pinmux.c b/arch/arm/cpu/armv7/exynos/pinmux.c
index 94d0297..be43e22 100644
--- a/arch/arm/cpu/armv7/exynos/pinmux.c
+++ b/arch/arm/cpu/armv7/exynos/pinmux.c
@@ -266,22 +266,33 @@
 
 static void exynos5_i2c_config(int peripheral, int flags)
 {
+	int func01, func23;
+
+	 /* High-Speed I2C */
+	if (flags & PINMUX_FLAG_HS_MODE) {
+		func01 = 4;
+		func23 = 4;
+	} else {
+		func01 = 2;
+		func23 = 3;
+	}
+
 	switch (peripheral) {
 	case PERIPH_ID_I2C0:
-		gpio_cfg_pin(EXYNOS5_GPIO_B30, S5P_GPIO_FUNC(0x2));
-		gpio_cfg_pin(EXYNOS5_GPIO_B31, S5P_GPIO_FUNC(0x2));
+		gpio_cfg_pin(EXYNOS5_GPIO_B30, S5P_GPIO_FUNC(func01));
+		gpio_cfg_pin(EXYNOS5_GPIO_B31, S5P_GPIO_FUNC(func01));
 		break;
 	case PERIPH_ID_I2C1:
-		gpio_cfg_pin(EXYNOS5_GPIO_B32, S5P_GPIO_FUNC(0x2));
-		gpio_cfg_pin(EXYNOS5_GPIO_B33, S5P_GPIO_FUNC(0x2));
+		gpio_cfg_pin(EXYNOS5_GPIO_B32, S5P_GPIO_FUNC(func01));
+		gpio_cfg_pin(EXYNOS5_GPIO_B33, S5P_GPIO_FUNC(func01));
 		break;
 	case PERIPH_ID_I2C2:
-		gpio_cfg_pin(EXYNOS5_GPIO_A06, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(EXYNOS5_GPIO_A07, S5P_GPIO_FUNC(0x3));
+		gpio_cfg_pin(EXYNOS5_GPIO_A06, S5P_GPIO_FUNC(func23));
+		gpio_cfg_pin(EXYNOS5_GPIO_A07, S5P_GPIO_FUNC(func23));
 		break;
 	case PERIPH_ID_I2C3:
-		gpio_cfg_pin(EXYNOS5_GPIO_A12, S5P_GPIO_FUNC(0x3));
-		gpio_cfg_pin(EXYNOS5_GPIO_A13, S5P_GPIO_FUNC(0x3));
+		gpio_cfg_pin(EXYNOS5_GPIO_A12, S5P_GPIO_FUNC(func23));
+		gpio_cfg_pin(EXYNOS5_GPIO_A13, S5P_GPIO_FUNC(func23));
 		break;
 	case PERIPH_ID_I2C4:
 		gpio_cfg_pin(EXYNOS5_GPIO_A20, S5P_GPIO_FUNC(0x3));
diff --git a/arch/arm/cpu/tegra20-common/pmu.c b/arch/arm/cpu/tegra20-common/pmu.c
index 36a76a2..a774246 100644
--- a/arch/arm/cpu/tegra20-common/pmu.c
+++ b/arch/arm/cpu/tegra20-common/pmu.c
@@ -52,7 +52,7 @@
 		debug("%s: Cannot find DVC I2C bus\n", __func__);
 		return ret;
 	}
-	ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, &dev);
+	ret = i2c_get_chip(bus, PMI_I2C_ADDRESS, 1, &dev);
 	if (ret) {
 		debug("%s: Cannot find DVC I2C chip\n", __func__);
 		return ret;
diff --git a/arch/arm/dts/exynos4.dtsi b/arch/arm/dts/exynos4.dtsi
index 77fad48..7de227c 100644
--- a/arch/arm/dts/exynos4.dtsi
+++ b/arch/arm/dts/exynos4.dtsi
@@ -51,56 +51,64 @@
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <0 0 0>;
+		reg = <0x13860000 0x100>;
+		interrupts = <0 56 0>;
 	};
 
 	i2c@13870000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <1 1 0>;
+		reg = <0x13870000 0x100>;
+		interrupts = <1 57 0>;
 	};
 
 	i2c@13880000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <2 2 0>;
+		reg = <0x13880000 0x100>;
+		interrupts = <2 58 0>;
 	};
 
 	i2c@13890000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <3 3 0>;
+		reg = <0x13890000 0x100>;
+		interrupts = <3 59 0>;
 	};
 
 	i2c@138a0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <4 4 0>;
+		reg = <0x138a0000 0x100>;
+		interrupts = <4 60 0>;
 	};
 
 	i2c@138b0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <5 5 0>;
+		reg = <0x138b0000 0x100>;
+		interrupts = <5 61 0>;
 	};
 
 	i2c@138c0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <6 6 0>;
+		reg = <0x138c0000 0x100>;
+		interrupts = <6 62 0>;
 	};
 
 	i2c@138d0000 {
 		#address-cells = <1>;
 		#size-cells = <0>;
 		compatible = "samsung,s3c2440-i2c";
-		interrupts = <7 7 0>;
+		reg = <0x138d0000 0x100>;
+		interrupts = <7 63 0>;
 	};
 
 	sdhci@12510000 {
@@ -143,11 +151,4 @@
 		interrupts = <0 131 0>;
 	};
 
-	gpio: gpio {
-		gpio-controller;
-		#gpio-cells = <2>;
-
-		interrupt-controller;
-		#interrupt-cells = <2>;
-	};
 };
diff --git a/arch/arm/dts/exynos4210-origen.dts b/arch/arm/dts/exynos4210-origen.dts
index dd2476c..3f87761 100644
--- a/arch/arm/dts/exynos4210-origen.dts
+++ b/arch/arm/dts/exynos4210-origen.dts
@@ -36,7 +36,7 @@
 	sdhci@12530000 {
 		samsung,bus-width = <4>;
 		samsung,timing = <1 2 3>;
-		cd-gpios = <&gpio 0xA2 0>;
+		cd-gpios = <&gpk2 2 0>;
 	};
 
 	sdhci@12540000 {
diff --git a/arch/arm/dts/exynos4210-trats.dts b/arch/arm/dts/exynos4210-trats.dts
index 8c7a2c3..36d02df 100644
--- a/arch/arm/dts/exynos4210-trats.dts
+++ b/arch/arm/dts/exynos4210-trats.dts
@@ -101,7 +101,7 @@
 	sdhci@12510000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
-		pwr-gpios = <&gpio 146 0>;
+		pwr-gpios = <&gpk0 2 0>;
 	};
 
 	sdhci@12520000 {
@@ -111,7 +111,7 @@
 	sdhci@12530000 {
 		samsung,bus-width = <4>;
 		samsung,timing = <1 2 3>;
-		cd-gpios = <&gpio 284 0>;
+		cd-gpios = <&gpx3 4 0>;
 	};
 
 	sdhci@12540000 {
diff --git a/arch/arm/dts/exynos4210-universal_c210.dts b/arch/arm/dts/exynos4210-universal_c210.dts
index 808c3f7..16948c9 100644
--- a/arch/arm/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/dts/exynos4210-universal_c210.dts
@@ -24,7 +24,7 @@
 	sdhci@12510000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
-		pwr-gpios = <&gpio 146 0>;
+		pwr-gpios = <&gpk0 2 0>;
 	};
 
 	sdhci@12520000 {
@@ -34,7 +34,7 @@
 	sdhci@12530000 {
 		samsung,bus-width = <4>;
 		samsung,timing = <1 2 3>;
-		cd-gpios = <&gpio 284 0>;
+		cd-gpios = <&gpx3 4 0>;
 	};
 
 	sdhci@12540000 {
@@ -43,10 +43,10 @@
 
 	soft-spi {
 		compatible = "u-boot,soft-spi";
-		cs-gpio = <&gpio 235 0>;	/* Y43 */
-		sclk-gpio = <&gpio 225 0>;	/* Y31 */
-		mosi-gpio = <&gpio 227 0>;	/* Y33 */
-		miso-gpio = <&gpio 224 0>;	/* Y30 */
+		cs-gpio = <&gpy4 3 0>;
+		sclk-gpio = <&gpy3 1 0>;
+		mosi-gpio = <&gpy3 3 0>;
+		miso-gpio = <&gpy3 0 0>;
 		spi-delay-us = <1>;
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/arch/arm/dts/exynos4412-odroid.dts b/arch/arm/dts/exynos4412-odroid.dts
index c78efec..00a2917 100644
--- a/arch/arm/dts/exynos4412-odroid.dts
+++ b/arch/arm/dts/exynos4412-odroid.dts
@@ -16,6 +16,13 @@
 
 	aliases {
 		i2c0 = "/i2c@13860000";
+		i2c1 = "/i2c@13870000";
+		i2c2 = "/i2c@13880000";
+		i2c3 = "/i2c@13890000";
+		i2c4 = "/i2c@138a0000";
+		i2c5 = "/i2c@138b0000";
+		i2c6 = "/i2c@138c0000";
+		i2c7 = "/i2c@138d0000";
 		serial0 = "/serial@13800000";
 		console = "/serial@13810000";
 		mmc2 = "sdhci@12530000";
@@ -51,7 +58,7 @@
 	sdhci@12530000 {
 		samsung,bus-width = <4>;
 		samsung,timing = <1 2 3>;
-		cd-gpios = <&gpio 122 0>;
+		cd-gpios = <&gpk2 2 0>;
 	};
 
 	sdhci@12540000 {
diff --git a/arch/arm/dts/exynos4412-trats2.dts b/arch/arm/dts/exynos4412-trats2.dts
index 60e4515..dd238df 100644
--- a/arch/arm/dts/exynos4412-trats2.dts
+++ b/arch/arm/dts/exynos4412-trats2.dts
@@ -416,7 +416,7 @@
 	sdhci@12510000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <1 3 3>;
-		pwr-gpios = <&gpio 0x6a 0>;
+		pwr-gpios = <&gpk0 4 0>;
 		status = "disabled";
 	};
 
@@ -427,7 +427,7 @@
 	sdhci@12530000 {
 		samsung,bus-width = <4>;
 		samsung,timing = <1 2 3>;
-		cd-gpios = <&gpio 0x7a 0>;
+		cd-gpios = <&gpk2 2 0>;
 	};
 
 	sdhci@12540000 {
@@ -437,7 +437,7 @@
 	dwmmc@12550000 {
 		samsung,bus-width = <8>;
 		samsung,timing = <2 1 0>;
-		pwr-gpios = <&gpio 0x6a 0>;
+		pwr-gpios = <&gpk0 4 0>;
 		fifoth_val = <0x203f0040>;
 		bus_hz = <400000000>;
 		div = <0x3>;
diff --git a/arch/arm/dts/exynos5.dtsi b/arch/arm/dts/exynos5.dtsi
index e539068..238acb8 100644
--- a/arch/arm/dts/exynos5.dtsi
+++ b/arch/arm/dts/exynos5.dtsi
@@ -6,6 +6,7 @@
  */
 
 #include "skeleton.dtsi"
+#include <dt-bindings/gpio/gpio.h>
 
 / {
 	compatible = "samsung,exynos5";
@@ -247,7 +248,4 @@
 		u-boot,dm-pre-reloc;
 		id = <3>;
 	};
-
-	gpio: gpio {
-	};
 };
diff --git a/arch/arm/dts/exynos5250-arndale.dts b/arch/arm/dts/exynos5250-arndale.dts
index 202f2ea..21c0a21 100644
--- a/arch/arm/dts/exynos5250-arndale.dts
+++ b/arch/arm/dts/exynos5250-arndale.dts
@@ -15,6 +15,14 @@
 	compatible = "samsung,arndale", "samsung,exynos5250";
 
 	aliases {
+		i2c0 = "/i2c@12c60000";
+		i2c1 = "/i2c@12c70000";
+		i2c2 = "/i2c@12c80000";
+		i2c3 = "/i2c@12c90000";
+		i2c4 = "/i2c@12ca0000";
+		i2c5 = "/i2c@12cb0000";
+		i2c6 = "/i2c@12cc0000";
+		i2c7 = "/i2c@12cd0000";
 		serial0 = "/serial@12C20000";
 		console = "/serial@12C20000";
 	};
diff --git a/arch/arm/dts/exynos5250-smdk5250.dts b/arch/arm/dts/exynos5250-smdk5250.dts
index 8850409..9273562 100644
--- a/arch/arm/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/dts/exynos5250-smdk5250.dts
@@ -146,6 +146,6 @@
 	};
 
 	ehci@12110000 {
-		samsung,vbus-gpio = <&gpio 0x316 0>; /* X26 */
+		samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
 	};
 };
diff --git a/arch/arm/dts/exynos5250-snow.dts b/arch/arm/dts/exynos5250-snow.dts
index bac5015..7d8be69 100644
--- a/arch/arm/dts/exynos5250-snow.dts
+++ b/arch/arm/dts/exynos5250-snow.dts
@@ -44,7 +44,8 @@
 			reg = <0x1e>;
 			compatible = "google,cros-ec";
 			i2c-max-frequency = <100000>;
-			ec-interrupt = <&gpio 182 1>;
+			u-boot,i2c-offset-len = <0>;
+			ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
 		};
 
 		power-regulator@48 {
@@ -68,7 +69,7 @@
 			reg = <0>;
 			compatible = "google,cros-ec";
 			spi-max-frequency = <5000000>;
-			ec-interrupt = <&gpio 182 1>;
+			ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
 			optimise-flash-write;
 			status = "disabled";
 		};
@@ -76,7 +77,7 @@
 
 	sound@3830000 {
 		samsung,codec-type = "max98095";
-		codec-enable-gpio = <&gpio 0xb7 0>;
+		codec-enable-gpio = <&gpx1 7 GPIO_ACTIVE_HIGH>;
 	};
 
 	sound@12d60000 {
@@ -131,11 +132,11 @@
 	};
 
 	ehci@12110000 {
-		samsung,vbus-gpio = <&gpio 0xb1 0>; /* X11 */
+		samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
 	};
 
 	xhci@12000000 {
-		samsung,vbus-gpio = <&gpio 0xbf 0>; /* X27 */
+		samsung,vbus-gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
 	};
 
 	tmu@10060000 {
diff --git a/arch/arm/dts/exynos5420-peach-pit.dts b/arch/arm/dts/exynos5420-peach-pit.dts
index d1d8735..b801de9 100644
--- a/arch/arm/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/dts/exynos5420-peach-pit.dts
@@ -17,7 +17,7 @@
 		"google,peach", "samsung,exynos5420", "samsung,exynos5";
 
 	config {
-		google,bad-wake-gpios = <&gpio 0x56 0>; /* gpx0-6 */
+		google,bad-wake-gpios = <&gpx0 6 GPIO_ACTIVE_HIGH>;
 		hwid = "PIT TEST A-A 7848";
 		lazy-init = <1>;
 	};
@@ -108,7 +108,7 @@
 			spi-half-duplex;
 			spi-max-timeout-ms = <1100>;
 			spi-frame-header = <0xec>;
-			ec-interrupt = <&gpio 93 1>; /* GPX1_5 */
+			ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
 
 			/*
 			 * This describes the flash memory within the EC. Note
@@ -124,11 +124,11 @@
 	};
 
 	xhci@12000000 {
-		samsung,vbus-gpio = <&gpio 0x40 0>; /* H00 */
+		samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
 	};
 
 	xhci@12400000 {
-		samsung,vbus-gpio = <&gpio 0x41 0>; /* H01 */
+		samsung,vbus-gpio = <&gph0 1 GPIO_ACTIVE_HIGH>;
 	};
 
 	fimd@14400000 {
diff --git a/arch/arm/dts/exynos5422-odroidxu3.dts b/arch/arm/dts/exynos5422-odroidxu3.dts
index 79a7acd..8f46637 100644
--- a/arch/arm/dts/exynos5422-odroidxu3.dts
+++ b/arch/arm/dts/exynos5422-odroidxu3.dts
@@ -32,7 +32,7 @@
 	};
 
 	ehci@12110000 {
-		samsung,vbus-gpio = <&gpio 0x66 0>; /* X26 */
+		samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
 	};
 
 	serial@12C20000 {
diff --git a/arch/arm/dts/exynos5800-peach-pi.dts b/arch/arm/dts/exynos5800-peach-pi.dts
index e7c380f..e4bc100 100644
--- a/arch/arm/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/dts/exynos5800-peach-pi.dts
@@ -17,7 +17,7 @@
 		"google,peach", "samsung,exynos5800", "samsung,exynos5";
 
 	config {
-		google,bad-wake-gpios = <&gpio 0x56 0>; /* gpx0-6 */
+		google,bad-wake-gpios = <&gpx0 6 GPIO_ACTIVE_HIGH>;
 		hwid = "PIT TEST A-A 7848";
 		lazy-init = <1>;
 	};
@@ -32,7 +32,7 @@
 		mem-manuf = "samsung";
 		mem-type = "ddr3";
 		clock-frequency = <800000000>;
-		arm-frequency = <1700000000>;
+		arm-frequency = <900000000>;
 	};
 
 	tmu@10060000 {
@@ -102,7 +102,7 @@
 			spi-half-duplex;
 			spi-max-timeout-ms = <1100>;
 			spi-frame-header = <0xec>;
-			ec-interrupt = <&gpio 93 1>; /* GPX1_5 */
+			ec-interrupt = <&gpx1 5 GPIO_ACTIVE_LOW>;
 
 			/*
 			 * This describes the flash memory within the EC. Note
@@ -118,11 +118,11 @@
 	};
 
 	xhci@12000000 {
-		samsung,vbus-gpio = <&gpio 0x40 0>; /* H00 */
+		samsung,vbus-gpio = <&gph0 0 GPIO_ACTIVE_HIGH>;
 	};
 
 	xhci@12400000 {
-		samsung,vbus-gpio = <&gpio 0x41 0>; /* H01 */
+		samsung,vbus-gpio = <&gph0 1 GPIO_ACTIVE_HIGH>;
 	};
 
 	fimd@14400000 {
diff --git a/arch/arm/dts/tegra114-dalmore.dts b/arch/arm/dts/tegra114-dalmore.dts
index 81ad212..51ff266 100644
--- a/arch/arm/dts/tegra114-dalmore.dts
+++ b/arch/arm/dts/tegra114-dalmore.dts
@@ -57,7 +57,7 @@
 	};
 
 	sdhci@78000400 {
-		cd-gpios = <&gpio 170 1>; /* gpio PV2 */
+		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
 		bus-width = <4>;
 		status = "okay";
 	};
@@ -68,8 +68,7 @@
 	};
 
 	usb@7d008000 {
-		/* SPDIF_IN: USB_VBUS_EN1 */
-		nvidia,vbus-gpio = <&gpio 86 0>;
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(K, 6) GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 };
diff --git a/arch/arm/dts/tegra124-jetson-tk1.dts b/arch/arm/dts/tegra124-jetson-tk1.dts
index 51fef54..e7b66d8 100644
--- a/arch/arm/dts/tegra124-jetson-tk1.dts
+++ b/arch/arm/dts/tegra124-jetson-tk1.dts
@@ -303,8 +303,9 @@
 
 	sdhci@700b0400 {
 		status = "okay";
-		cd-gpios = <&gpio 170 1>; /* gpio PV2 */
-		power-gpios = <&gpio 136 0>; /* gpio PR0 */
+		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_LOW>;
+		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
+		wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -316,12 +317,12 @@
 	usb@7d000000 {
 		status = "okay";
 		dr_mode = "otg";
-		nvidia,vbus-gpio = <&gpio 108 0>; /* gpio PN4, USB_VBUS_EN0 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb@7d008000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio 109 0>; /* gpio PN5, USB_VBUS_EN1 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>;
 	};
 
 	regulators {
diff --git a/arch/arm/dts/tegra124-venice2.dts b/arch/arm/dts/tegra124-venice2.dts
index f7ccfc5..9e93cf9 100644
--- a/arch/arm/dts/tegra124-venice2.dts
+++ b/arch/arm/dts/tegra124-venice2.dts
@@ -72,8 +72,9 @@
 
 	sdhci@700b0400 {
 		status = "okay";
-		cd-gpios = <&gpio 170 0>; /* gpio PV2 */
-		power-gpios = <&gpio 136 0>; /* gpio PR0 */
+		cd-gpios = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(R, 0) GPIO_ACTIVE_HIGH>;
+		wp-gpios = <&gpio TEGRA_GPIO(Q, 4) GPIO_ACTIVE_LOW>;
 		bus-width = <4>;
 	};
 
@@ -85,11 +86,11 @@
 	usb@7d000000 {
 		status = "okay";
 		dr_mode = "otg";
-		nvidia,vbus-gpio = <&gpio 108 0>; /* gpio PN4, USB_VBUS_EN0 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 4) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb@7d008000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio 109 0>; /* gpio PN5, USB_VBUS_EN1 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(N, 5) GPIO_ACTIVE_HIGH>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-colibri_t20_iris.dts b/arch/arm/dts/tegra20-colibri_t20_iris.dts
index 7cf08f4..3131b92 100644
--- a/arch/arm/dts/tegra20-colibri_t20_iris.dts
+++ b/arch/arm/dts/tegra20-colibri_t20_iris.dts
@@ -22,16 +22,16 @@
 	};
 
 	usb@c5004000 {
-		nvidia,phy-reset-gpio = <&gpio 169 0>; /* PV1 */
-		nvidia,vbus-gpio = <&gpio 217 0>; /* PBB1 */
+		nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(BB, 1) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb@c5008000 {
-		nvidia,vbus-gpio = <&gpio 178 1>; /* PW2 low-active */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>;
 	};
 
 	nand-controller@70008000 {
-		nvidia,wp-gpios = <&gpio 144 0>; /* PS0 */
+		nvidia,wp-gpios = <&gpio TEGRA_GPIO(S, 0) GPIO_ACTIVE_HIGH>;
 		nvidia,width = <8>;
 		nvidia,timing = <15 100 25 80 25 10 15 10 100>;
 
@@ -43,7 +43,7 @@
 
 	sdhci@c8000600 {
 		status = "okay";
-		cd-gpios = <&gpio 23 1>; /* gpio PC7 */
+		cd-gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_LOW>;
 		bus-width = <4>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-harmony.dts b/arch/arm/dts/tegra20-harmony.dts
index 982a14c..e6e4229 100644
--- a/arch/arm/dts/tegra20-harmony.dts
+++ b/arch/arm/dts/tegra20-harmony.dts
@@ -37,7 +37,7 @@
 	};
 
 	nand-controller@70008000 {
-		nvidia,wp-gpios = <&gpio 23 0>;		/* PC7 */
+		nvidia,wp-gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_HIGH>;
 		nvidia,width = <8>;
 		nvidia,timing = <26 100 20 80 20 10 12 10 70>;
 		nand@0 {
@@ -67,22 +67,22 @@
 	};
 
 	usb@c5004000 {
-		nvidia,phy-reset-gpio = <&gpio 169 0>; /* gpio PV1 */
+		nvidia,phy-reset-gpio = <&gpio TEGRA_GPIO(V, 1) 0>;
 	};
 
 	sdhci@c8000200 {
 		status = "okay";
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 155 0>; /* gpio PT3 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(T, 3) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
 	sdhci@c8000600 {
 		status = "okay";
-		cd-gpios = <&gpio 58 1>; /* gpio PH2 */
-		wp-gpios = <&gpio 59 0>; /* gpio PH3 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		cd-gpios = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>;
 		bus-width = <8>;
 	};
 
@@ -100,10 +100,14 @@
 		vsyncx-active-high;
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 0 0>;
-		nvidia,backlight-enable-gpios = <&gpio 13 0>;	/* PB5 */
-		nvidia,lvds-shutdown-gpios = <&gpio 10 0>;	/* PB2 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */
-		nvidia,panel-vdd-gpios = <&gpio 22 0>;		/* PC6 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(B, 5)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <0 0 200 0 0>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-medcom-wide.dts b/arch/arm/dts/tegra20-medcom-wide.dts
index be2ed42..b6b57ab 100644
--- a/arch/arm/dts/tegra20-medcom-wide.dts
+++ b/arch/arm/dts/tegra20-medcom-wide.dts
@@ -73,9 +73,12 @@
 
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 0 500000>;
-		nvidia,backlight-enable-gpios = <&gpio 13 0>; /* PB5 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>; /* PW0 */
-		nvidia,lvds-shutdown-gpios = <&gpio 10 0>; /* PB2 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(B, 5)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <0 0 0 0>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-paz00.dts b/arch/arm/dts/tegra20-paz00.dts
index 9d735b5..16381c3 100644
--- a/arch/arm/dts/tegra20-paz00.dts
+++ b/arch/arm/dts/tegra20-paz00.dts
@@ -61,9 +61,9 @@
 
 	sdhci@c8000000 {
 		status = "okay";
-		cd-gpios = <&gpio 173 1>; /* gpio PV5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 169 0>; /* gpio PV1 */
+		cd-gpios = <&gpio TEGRA_GPIO(V, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(V, 1) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -86,10 +86,14 @@
 		hsync-active-high;
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 0 0>;
-		nvidia,backlight-enable-gpios = <&gpio 164 0>;	/* PU4 */
-		nvidia,lvds-shutdown-gpios = <&gpio 102 0>;	/* PM6 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */
-		nvidia,panel-vdd-gpios = <&gpio 4 0>;		/* PA4 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(U, 4)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(M, 6)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(A, 4)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <400 4 203 17 15>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-seaboard.dts b/arch/arm/dts/tegra20-seaboard.dts
index 43b9911..10f3992 100644
--- a/arch/arm/dts/tegra20-seaboard.dts
+++ b/arch/arm/dts/tegra20-seaboard.dts
@@ -65,7 +65,7 @@
 	};
 
 	nand-controller@70008000 {
-		nvidia,wp-gpios = <&gpio 59 0>;		/* PH3 */
+		nvidia,wp-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_HIGH>;
 		nvidia,width = <8>;
 		nvidia,timing = <26 100 20 80 20 10 12 10 70>;
 		nand@0 {
@@ -151,7 +151,7 @@
 	};
 
 	usb@c5000000 {
-		nvidia,vbus-gpio = <&gpio 24 0>; /* PD0 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(D, 0) GPIO_ACTIVE_HIGH>;
 		dr_mode = "otg";
 	};
 
@@ -161,9 +161,9 @@
 
 	sdhci@c8000400 {
 		status = "okay";
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -186,10 +186,14 @@
 		hsync-active-high;
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 2 0>;
-		nvidia,backlight-enable-gpios = <&gpio 28 0>;	/* PD4 */
-		nvidia,lvds-shutdown-gpios = <&gpio 10 0>;	/* PB2 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */
-		nvidia,panel-vdd-gpios = <&gpio 22 0>;		/* PC6 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(D, 4)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <400 4 203 17 15>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-tamonten.dtsi b/arch/arm/dts/tegra20-tamonten.dtsi
index f379622..78449e6 100644
--- a/arch/arm/dts/tegra20-tamonten.dtsi
+++ b/arch/arm/dts/tegra20-tamonten.dtsi
@@ -14,7 +14,8 @@
 			pll-supply = <&hdmi_pll_reg>;
 
 			nvidia,ddc-i2c-bus = <&hdmi_ddc>;
-			nvidia,hpd-gpio = <&gpio 111 0>; /* PN7 */
+			nvidia,hpd-gpio = <&gpio TEGRA_GPIO(N, 7)
+				GPIO_ACTIVE_HIGH>;
 		};
 	};
 
@@ -280,7 +281,7 @@
 	};
 
 	nand-controller@70008000 {
-		nvidia,wp-gpios = <&gpio 23 0>; /* PC7 */
+		nvidia,wp-gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_HIGH>;
 		nvidia,width = <8>;
 		nvidia,timing = <26 100 20 80 20 10 12 10 70>;
 
@@ -476,8 +477,8 @@
 	};
 
 	sdhci@c8000600 {
-		cd-gpios = <&gpio 58 1>; /* gpio PH2 */
-		wp-gpios = <&gpio 59 0>; /* gpio PH3 */
+		cd-gpios = <&gpio TEGRA_GPIO(H, 2) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 3) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 		status = "okay";
 	};
diff --git a/arch/arm/dts/tegra20-tec.dts b/arch/arm/dts/tegra20-tec.dts
index e99bd44..94ba6dc 100644
--- a/arch/arm/dts/tegra20-tec.dts
+++ b/arch/arm/dts/tegra20-tec.dts
@@ -73,9 +73,12 @@
 
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 0 500000>;
-		nvidia,backlight-enable-gpios = <&gpio 13 0>; /* PB5 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>; /* PW0 */
-		nvidia,lvds-shutdown-gpios = <&gpio 10 0>; /* PB2 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(B, 5)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <0 0 0 0>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-trimslice.dts b/arch/arm/dts/tegra20-trimslice.dts
index 1637cbd..27b118f 100644
--- a/arch/arm/dts/tegra20-trimslice.dts
+++ b/arch/arm/dts/tegra20-trimslice.dts
@@ -62,7 +62,7 @@
 	};
 
 	usb@c5000000 {
-		nvidia,vbus-gpio = <&gpio 170 0>; /* PV2 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb@c5004000 {
@@ -76,8 +76,8 @@
 
 	sdhci@c8000600 {
 		status = "okay";
-		cd-gpios = <&gpio 121 1>; /* gpio PP1 */
-		wp-gpios = <&gpio 122 0>; /* gpio PP2 */
+		cd-gpios = <&gpio TEGRA_GPIO(P, 1) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(P, 2) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -111,7 +111,7 @@
 			regulator-min-microvolt = <5000000>;
 			regulator-max-microvolt = <5000000>;
 			enable-active-high;
-			gpio = <&gpio TEGRA_GPIO(V, 2) 0>;
+			gpio = <&gpio TEGRA_GPIO(V, 2) GPIO_ACTIVE_HIGH>;
 			regulator-always-on;
 			regulator-boot-on;
 		};
diff --git a/arch/arm/dts/tegra20-ventana.dts b/arch/arm/dts/tegra20-ventana.dts
index 6812203..939e567 100644
--- a/arch/arm/dts/tegra20-ventana.dts
+++ b/arch/arm/dts/tegra20-ventana.dts
@@ -61,9 +61,9 @@
 
 	sdhci@c8000400 {
 		status = "okay";
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 57 0>; /* gpio PH1 */
-		power-gpios = <&gpio 70 0>; /* gpio PI6 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(H, 1) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(I, 6) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -86,10 +86,14 @@
 		vsync-active-high;
 		nvidia,bits-per-pixel = <16>;
 		nvidia,pwm = <&pwm 2 0>;
-		nvidia,backlight-enable-gpios = <&gpio 28 0>;	/* PD4 */
-		nvidia,lvds-shutdown-gpios = <&gpio 10 0>;	/* PB2 */
-		nvidia,backlight-vdd-gpios = <&gpio 176 0>;	/* PW0 */
-		nvidia,panel-vdd-gpios = <&gpio 22 0>;		/* PC6 */
+		nvidia,backlight-enable-gpios = <&gpio TEGRA_GPIO(D, 4)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,lvds-shutdown-gpios = <&gpio TEGRA_GPIO(B, 2)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,backlight-vdd-gpios = <&gpio TEGRA_GPIO(W, 0)
+							GPIO_ACTIVE_HIGH>;
+		nvidia,panel-vdd-gpios = <&gpio TEGRA_GPIO(C, 6)
+							GPIO_ACTIVE_HIGH>;
 		nvidia,panel-timings = <0 0 200 0 0>;
 	};
 };
diff --git a/arch/arm/dts/tegra20-whistler.dts b/arch/arm/dts/tegra20-whistler.dts
index 4fd2496..c4a28eb 100644
--- a/arch/arm/dts/tegra20-whistler.dts
+++ b/arch/arm/dts/tegra20-whistler.dts
@@ -66,7 +66,7 @@
 
 	sdhci@c8000400 {
 		status = "okay";
-		wp-gpios = <&gpio 173 0>; /* gpio PV5 */
+		wp-gpios = <&gpio TEGRA_GPIO(V, 5) GPIO_ACTIVE_HIGH>;
 		bus-width = <8>;
 	};
 
diff --git a/arch/arm/dts/tegra30-apalis.dts b/arch/arm/dts/tegra30-apalis.dts
index 5bad3e7..15db0f2 100644
--- a/arch/arm/dts/tegra30-apalis.dts
+++ b/arch/arm/dts/tegra30-apalis.dts
@@ -243,13 +243,13 @@
 	sdhci@78000000 {
 		status = "okay";
 		bus-width = <4>;
-		cd-gpios = <&gpio 229 1>; /* PCC5, SD1_CD# */
+		cd-gpios = <&gpio TEGRA_GPIO(CC, 5) GPIO_ACTIVE_HIGH>;
 	};
 
 	sdhci@78000400 {
 		status = "okay";
 		bus-width = <8>;
-		cd-gpios = <&gpio 171 1>; /* PV3, MMC1_CD# */
+		cd-gpios = <&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
 	};
 
 	sdhci@78000600 {
@@ -262,20 +262,20 @@
 	usb@7d000000 {
 		status = "okay";
 		dr_mode = "peripheral";
-		nvidia,vbus-gpio = <&gpio 157 0>;	/* PT5, USBO1_EN */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(T, 5) GPIO_ACTIVE_HIGH>;
 	};
 
 	/* EHCI instance 1: USB2_DP/N -> USBH2_DP/N */
 	usb@7d004000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio 233 0>;	/* PDD1, USBH_EN */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 1) GPIO_ACTIVE_HIGH>;
 		phy_type = "utmi";
 	};
 
 	/* EHCI instance 2: USB3_DP/N -> USBH3_DP/N */
 	usb@7d008000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio 233 0>;	/* PDD1, USBH_EN */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 1) GPIO_ACTIVE_HIGH>;
 	};
 
 	regulators {
diff --git a/arch/arm/dts/tegra30-beaver.dts b/arch/arm/dts/tegra30-beaver.dts
index 5903af6..ae83636 100644
--- a/arch/arm/dts/tegra30-beaver.dts
+++ b/arch/arm/dts/tegra30-beaver.dts
@@ -196,9 +196,9 @@
 
 	sdhci@78000000 {
 		status = "okay";
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
-		power-gpios = <&gpio 31 0>; /* gpio PD7 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(T, 3) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(D, 7) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -210,11 +210,11 @@
 	usb@7d000000 {
 		status = "okay";
 		dr_mode = "otg";
-		nvidia,vbus-gpio = <&gpio 238 0>; /* gpio DD6, PEX_L1_CLKREQ */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 6) GPIO_ACTIVE_HIGH>;
 	};
 
 	usb@7d008000 {
-		nvidia,vbus-gpio = <&gpio 236 0>; /* PDD4 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 4) GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 
diff --git a/arch/arm/dts/tegra30-cardhu.dts b/arch/arm/dts/tegra30-cardhu.dts
index e13d0fb..23ca141 100644
--- a/arch/arm/dts/tegra30-cardhu.dts
+++ b/arch/arm/dts/tegra30-cardhu.dts
@@ -185,9 +185,9 @@
 
 	sdhci@78000000 {
 		status = "okay";
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 155 0>; /* gpio PT3 */
-		power-gpios = <&gpio 31 0>; /* gpio PD7 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(T, 3) GPIO_ACTIVE_HIGH>;
+		power-gpios = <&gpio TEGRA_GPIO(D, 7) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
@@ -197,7 +197,7 @@
 	};
 
 	usb@7d008000 {
-		nvidia,vbus-gpio = <&gpio 236 0>;	/* PDD4 */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 4) GPIO_ACTIVE_HIGH>;
 		status = "okay";
 	};
 
diff --git a/arch/arm/dts/tegra30-colibri.dts b/arch/arm/dts/tegra30-colibri.dts
index 37b6abd..6cd1902 100644
--- a/arch/arm/dts/tegra30-colibri.dts
+++ b/arch/arm/dts/tegra30-colibri.dts
@@ -64,7 +64,7 @@
 	sdhci@78000200 {
 		status = "okay";
 		bus-width = <4>;
-		cd-gpios = <&gpio 23 1>; /* PC7, MMCD */
+		cd-gpios = <&gpio TEGRA_GPIO(C, 7) GPIO_ACTIVE_LOW>;
 	};
 
 	sdhci@78000600 {
@@ -83,12 +83,12 @@
 	usb@7d004000 {
 		status = "okay";
 		phy_type = "utmi";
-		nvidia,vbus-gpio = <&gpio 234 0>;	/* PDD2, VBUS_LAN */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(DD, 2) GPIO_ACTIVE_HIGH>;
 	};
 
 	/* EHCI instance 2: USB3_DP/N -> USBH_P/N */
 	usb@7d008000 {
 		status = "okay";
-		nvidia,vbus-gpio = <&gpio 178 1>;	/* PW2, USBH_PEN */
+		nvidia,vbus-gpio = <&gpio TEGRA_GPIO(W, 2) GPIO_ACTIVE_LOW>;
 	};
 };
diff --git a/arch/arm/dts/tegra30-tamonten.dtsi b/arch/arm/dts/tegra30-tamonten.dtsi
index c73afef..8eff627 100644
--- a/arch/arm/dts/tegra30-tamonten.dtsi
+++ b/arch/arm/dts/tegra30-tamonten.dtsi
@@ -55,8 +55,8 @@
 
 	/* SD slot on the base board */
 	sdhci@78000400 {
-		cd-gpios = <&gpio 69 1>; /* gpio PI5 */
-		wp-gpios = <&gpio 67 0>; /* gpio PI3 */
+		cd-gpios = <&gpio TEGRA_GPIO(I, 5) GPIO_ACTIVE_LOW>;
+		wp-gpios = <&gpio TEGRA_GPIO(I, 3) GPIO_ACTIVE_HIGH>;
 		bus-width = <4>;
 	};
 
diff --git a/arch/arm/include/asm/arch-exynos/pinmux.h b/arch/arm/include/asm/arch-exynos/pinmux.h
index 0b91ef6..d0ae757 100644
--- a/arch/arm/include/asm/arch-exynos/pinmux.h
+++ b/arch/arm/include/asm/arch-exynos/pinmux.h
@@ -23,6 +23,9 @@
 	/* Flags for SROM controller */
 	PINMUX_FLAG_BANK	= 3 << 0,       /* bank number (0-3) */
 	PINMUX_FLAG_16BIT	= 1 << 2,       /* 16-bit width */
+
+	/* Flags for I2C */
+	PINMUX_FLAG_HS_MODE	= 1 << 1,       /* I2C High Speed Mode */
 };
 
 /**
diff --git a/arch/arm/include/asm/arch-pantheon/gpio.h b/arch/arm/include/asm/arch-pantheon/gpio.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/arch/arm/include/asm/arch-pantheon/gpio.h
diff --git a/arch/arm/include/asm/arch-tegra/tegra_mmc.h b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
index 84e7b55..a20bdaa 100644
--- a/arch/arm/include/asm/arch-tegra/tegra_mmc.h
+++ b/arch/arm/include/asm/arch-tegra/tegra_mmc.h
@@ -10,6 +10,7 @@
 #define __TEGRA_MMC_H_
 
 #include <fdtdec.h>
+#include <asm/gpio.h>
 
 /* for mmc_config definition */
 #include <mmc.h>
@@ -134,9 +135,9 @@
 	int enabled;		/* 1 to enable, 0 to disable */
 	int width;		/* Bus Width, 1, 4 or 8 */
 	enum periph_id mmc_id;	/* Peripheral ID: PERIPH_ID_... */
-	struct fdt_gpio_state cd_gpio;		/* Change Detect GPIO */
-	struct fdt_gpio_state pwr_gpio;		/* Power GPIO */
-	struct fdt_gpio_state wp_gpio;		/* Write Protect GPIO */
+	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
+	struct gpio_desc pwr_gpio;	/* Power GPIO */
+	struct gpio_desc wp_gpio;	/* Write Protect GPIO */
 	unsigned int version;	/* SDHCI spec. version */
 	unsigned int clock;	/* Current clock (MHz) */
 	struct mmc_config cfg;	/* mmc configuration */
diff --git a/arch/arm/include/asm/arch-tegra20/display.h b/arch/arm/include/asm/arch-tegra20/display.h
index a04c84e..6feeda3 100644
--- a/arch/arm/include/asm/arch-tegra20/display.h
+++ b/arch/arm/include/asm/arch-tegra20/display.h
@@ -10,6 +10,7 @@
 
 #include <asm/arch/dc.h>
 #include <fdtdec.h>
+#include <asm/gpio.h>
 
 /* This holds information about a window which can be displayed */
 struct disp_ctl_win {
@@ -72,10 +73,10 @@
 	int pwm_channel;		/* PWM channel to use for backlight */
 	enum lcd_cache_t cache_type;
 
-	struct fdt_gpio_state backlight_en;	/* GPIO for backlight enable */
-	struct fdt_gpio_state lvds_shutdown;	/* GPIO for lvds shutdown */
-	struct fdt_gpio_state backlight_vdd;	/* GPIO for backlight vdd */
-	struct fdt_gpio_state panel_vdd;	/* GPIO for panel vdd */
+	struct gpio_desc backlight_en;	/* GPIO for backlight enable */
+	struct gpio_desc lvds_shutdown;	/* GPIO for lvds shutdown */
+	struct gpio_desc backlight_vdd;	/* GPIO for backlight vdd */
+	struct gpio_desc panel_vdd;	/* GPIO for panel vdd */
 	/*
 	 * Panel required timings
 	 * Timing 1: delay between panel_vdd-rise and data-rise
diff --git a/arch/arm/include/asm/arch-zynq/gpio.h b/arch/arm/include/asm/arch-zynq/gpio.h
index 2dbba75..a26ae87 100644
--- a/arch/arm/include/asm/arch-zynq/gpio.h
+++ b/arch/arm/include/asm/arch-zynq/gpio.h
@@ -7,19 +7,4 @@
 #ifndef _ZYNQ_GPIO_H
 #define _ZYNQ_GPIO_H
 
-inline int gpio_get_value(unsigned gpio)
-{
-	return 0;
-}
-
-inline int gpio_set_value(unsigned gpio, int val)
-{
-	return 0;
-}
-
-inline int gpio_request(unsigned gpio, const char *label)
-{
-	return 0;
-}
-
 #endif /* _ZYNQ_GPIO_H */
diff --git a/arch/blackfin/cpu/cpu.c b/arch/blackfin/cpu/cpu.c
index b7f1188..91aa5cc 100644
--- a/arch/blackfin/cpu/cpu.c
+++ b/arch/blackfin/cpu/cpu.c
@@ -24,6 +24,7 @@
 
 #include "cpu.h"
 #include "initcode.h"
+#include "exports.h"
 
 ulong bfin_poweron_retx;
 DECLARE_GLOBAL_DATA_PTR;
@@ -121,7 +122,7 @@
 	printf(" |-ram_size: %lx\n", gd->ram_size);
 	printf(" |-env_addr: %lx\n", gd->env_addr);
 	printf(" |-env_valid: %lx\n", gd->env_valid);
-	printf(" |-jt(%p): %p\n", gd->jt, *(gd->jt));
+	printf(" |-jt(%p): %p\n", gd->jt, gd->jt->get_version);
 	printf(" \\-bd: %p\n", gd->bd);
 	printf("   |-bi_boot_params: %lx\n", bd->bi_boot_params);
 	printf("   |-bi_memstart: %lx\n", bd->bi_memstart);
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 11748ae..4c63e4f 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -19,6 +19,7 @@
 		colour = "cyan";
 		sides = <3>;
 		character = <83>;
+		light-gpios = <&gpio_a 2>, <&gpio_b 6 0>;
 	};
 	square {
 		compatible = "demo-shape";
@@ -126,7 +127,7 @@
 			0x070b0067 0x070c0069>;
 	};
 
-	gpio_a: gpios {
+	gpio_a: gpios@0 {
 		gpio-controller;
 		compatible = "sandbox,gpio";
 		#gpio-cells = <1>;
@@ -134,6 +135,14 @@
 		num-gpios = <20>;
 	};
 
+	gpio_b: gpios@1 {
+		gpio-controller;
+		compatible = "sandbox,gpio";
+		#gpio-cells = <2>;
+		gpio-bank-name = "b";
+		num-gpios = <10>;
+	};
+
 	i2c@0 {
 		#address-cells = <1>;
 		#size-cells = <0>;
diff --git a/board/BuS/eb_cpux9k2/cpux9k2.c b/board/BuS/eb_cpux9k2/cpux9k2.c
index 5e4778e..76ad7c4 100644
--- a/board/BuS/eb_cpux9k2/cpux9k2.c
+++ b/board/BuS/eb_cpux9k2/cpux9k2.c
@@ -98,7 +98,7 @@
 				puts("Error: invalid MAC at EEPROM\n");
 		}
 	}
-	gd->jt[XF_do_reset] = (void *) do_reset;
+	gd->jt->do_reset = do_reset;
 
 #ifdef CONFIG_STATUS_LED
 	status_led_set(STATUS_LED_BOOT, STATUS_LED_BLINKING);
diff --git a/board/avionic-design/common/tamonten-ng.c b/board/avionic-design/common/tamonten-ng.c
index 86a0844..1704627 100644
--- a/board/avionic-design/common/tamonten-ng.c
+++ b/board/avionic-design/common/tamonten-ng.c
@@ -55,12 +55,12 @@
 	struct udevice *dev;
 	int ret;
 
-	ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, &dev);
+	ret = i2c_get_chip_for_busnum(4, PMU_I2C_ADDRESS, 1, &dev);
 	if (ret) {
 		debug("%s: Cannot find PMIC I2C chip\n", __func__);
 		return;
 	}
-	i2c_write(dev, reg, &data, 1);
+	dm_i2c_write(dev, reg, &data, 1);
 }
 
 /*
diff --git a/board/nvidia/cardhu/cardhu.c b/board/nvidia/cardhu/cardhu.c
index 95c4ff2..1540526 100644
--- a/board/nvidia/cardhu/cardhu.c
+++ b/board/nvidia/cardhu/cardhu.c
@@ -46,7 +46,7 @@
 	int ret;
 	int i;
 
-	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
 	if (ret) {
 		debug("%s: Cannot find PMIC I2C chip\n", __func__);
 		return;
@@ -57,7 +57,7 @@
 	reg = 0x32;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (i2c_write(dev, reg, data_buffer, 1))
+		if (dm_i2c_write(dev, reg, data_buffer, 1))
 			udelay(100);
 	}
 
@@ -66,7 +66,7 @@
 	reg = 0x67;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (i2c_write(dev, reg, data_buffer, 1))
+		if (dm_i2c_write(dev, reg, data_buffer, 1))
 			udelay(100);
 	}
 }
@@ -94,7 +94,7 @@
 	u8 addr, data[1];
 	int err;
 
-	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
 	if (err) {
 		debug("failed to find PMU bus\n");
 		return err;
@@ -104,7 +104,7 @@
 	data[0] = 0x15;
 	addr = 0x30;
 
-	err = i2c_write(dev, addr, data, 1);
+	err = dm_i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set VDD supply\n");
 		return err;
@@ -121,7 +121,7 @@
 	data[0] = 0x15;
 	addr = 0x31;
 
-	err = i2c_write(dev, addr, data, 1);
+	err = dm_i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set AVDD supply\n");
 		return err;
diff --git a/board/nvidia/dalmore/dalmore.c b/board/nvidia/dalmore/dalmore.c
index 2a73746..d7c1a69 100644
--- a/board/nvidia/dalmore/dalmore.c
+++ b/board/nvidia/dalmore/dalmore.c
@@ -55,7 +55,7 @@
 	uchar reg, data_buffer[1];
 	int ret;
 
-	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	ret = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
 	if (ret) {
 		debug("%s: Cannot find PMIC I2C chip\n", __func__);
 		return;
@@ -65,7 +65,7 @@
 	data_buffer[0] = 0x31;
 	reg = 0x61;
 
-	ret = i2c_write(dev, reg, data_buffer, 1);
+	ret = dm_i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
@@ -74,7 +74,7 @@
 	data_buffer[0] = 0x01;
 	reg = 0x60;
 
-	ret = i2c_write(dev, reg, data_buffer, 1);
+	ret = dm_i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: PMU i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
@@ -83,12 +83,12 @@
 	data_buffer[0] = 0x03;
 	reg = 0x14;
 
-	ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, &dev);
+	ret = i2c_get_chip_for_busnum(0, BAT_I2C_ADDRESS, 1, &dev);
 	if (ret) {
 		debug("%s: Cannot find charger I2C chip\n", __func__);
 		return;
 	}
-	ret = i2c_write(dev, reg, data_buffer, 1);
+	ret = dm_i2c_write(dev, reg, data_buffer, 1);
 	if (ret)
 		printf("%s: BAT i2c_write %02X<-%02X returned %d\n",
 			__func__, reg, data_buffer[0], ret);
diff --git a/board/nvidia/whistler/whistler.c b/board/nvidia/whistler/whistler.c
index 3114b20..3476f11 100644
--- a/board/nvidia/whistler/whistler.c
+++ b/board/nvidia/whistler/whistler.c
@@ -27,21 +27,21 @@
 	int ret;
 
 	/* Turn on MAX8907B LDO12 to 2.8V for J40 power */
-	ret = i2c_get_chip_for_busnum(0, 0x3c, &dev);
+	ret = i2c_get_chip_for_busnum(0, 0x3c, 1, &dev);
 	if (ret) {
 		printf("%s: Cannot find MAX8907B I2C chip\n", __func__);
 		return;
 	}
 	val = 0x29;
-	ret = i2c_write(dev, 0x46, &val, 1);
+	ret = dm_i2c_write(dev, 0x46, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x46 failed: %d\n", ret);
 	val = 0x00;
-	ret = i2c_write(dev, 0x45, &val, 1);
+	ret = dm_i2c_write(dev, 0x45, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x45 failed: %d\n", ret);
 	val = 0x1f;
-	ret = i2c_write(dev, 0x44, &val, 1);
+	ret = dm_i2c_write(dev, 0x44, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x3c 0x44 failed: %d\n", ret);
 
@@ -64,17 +64,17 @@
 	 */
 
 	/* Turn on TAC6416's GPIO 0+1 for USB1/3's VBUS */
-	ret = i2c_get_chip_for_busnum(0, 0x20, &dev);
+	ret = i2c_get_chip_for_busnum(0, 0x20, 1, &dev);
 	if (ret) {
 		printf("%s: Cannot find TAC6416 I2C chip\n", __func__);
 		return;
 	}
 	val = 0x03;
-	ret = i2c_write(dev, 2, &val, 1);
+	ret = dm_i2c_write(dev, 2, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x20 2 failed: %d\n", ret);
 	val = 0xfc;
-	ret = i2c_write(dev, 6, &val, 1);
+	ret = dm_i2c_write(dev, 6, &val, 1);
 	if (ret)
 		printf("i2c_write 0 0x20 6 failed: %d\n", ret);
 }
diff --git a/board/samsung/odroid/odroid.c b/board/samsung/odroid/odroid.c
index b7d2381..e3517f2 100644
--- a/board/samsung/odroid/odroid.c
+++ b/board/samsung/odroid/odroid.c
@@ -415,15 +415,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_SYS_I2C_INIT_BOARD
-static void board_init_i2c(void)
-{
-	/* I2C_0 */
-	if (exynos_pinmux_config(PERIPH_ID_I2C0, PINMUX_FLAG_NONE))
-		debug("I2C%d not configured\n", (I2C_0));
-}
-#endif
-
 int exynos_early_init_f(void)
 {
 	board_clock_init();
@@ -444,10 +435,7 @@
 
 int exynos_power_init(void)
 {
-#ifdef CONFIG_SYS_I2C_INIT_BOARD
-	board_init_i2c();
-#endif
-	pmic_init(I2C_0);
+	pmic_init(0);
 	pmic_init_max77686();
 
 	return 0;
diff --git a/board/toradex/apalis_t30/apalis_t30.c b/board/toradex/apalis_t30/apalis_t30.c
index 5d2c024..6244214 100644
--- a/board/toradex/apalis_t30/apalis_t30.c
+++ b/board/toradex/apalis_t30/apalis_t30.c
@@ -42,7 +42,7 @@
 	u8 addr, data[1];
 	int err;
 
-	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, &dev);
+	err = i2c_get_chip_for_busnum(0, PMU_I2C_ADDRESS, 1, &dev);
 	if (err) {
 		debug("%s: Cannot find PMIC I2C chip\n", __func__);
 		return err;
@@ -51,7 +51,7 @@
 	data[0] = 0x27;
 	addr = 0x25;
 
-	err = i2c_write(dev, addr, data, 1);
+	err = dm_i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set VDD supply\n");
 		return err;
@@ -61,7 +61,7 @@
 	data[0] = 0x0D;
 	addr = 0x24;
 
-	err = i2c_write(dev, addr, data, 1);
+	err = dm_i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to enable VDD supply\n");
 		return err;
@@ -71,7 +71,7 @@
 	data[0] = 0x0D;
 	addr = 0x35;
 
-	err = i2c_write(dev, addr, data, 1);
+	err = dm_i2c_write(dev, addr, data, 1);
 	if (err) {
 		debug("failed to set AVDD supply\n");
 		return err;
diff --git a/common/Makefile b/common/Makefile
index 94554f2..9579ab4 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -27,6 +27,8 @@
 # boards
 obj-$(CONFIG_SYS_GENERIC_BOARD) += board_f.o
 obj-$(CONFIG_SYS_GENERIC_BOARD) += board_r.o
+obj-$(CONFIG_DISPLAY_BOARDINFO) += board_info.o
+obj-$(CONFIG_DISPLAY_BOARDINFO_LATE) += board_info.o
 
 # core command
 obj-y += cmd_boot.o
diff --git a/common/board_f.c b/common/board_f.c
index 215108b..7953137 100644
--- a/common/board_f.c
+++ b/common/board_f.c
@@ -894,7 +894,7 @@
 	prt_mpc5xxx_clks,
 #endif /* CONFIG_MPC5xxx */
 #if defined(CONFIG_DISPLAY_BOARDINFO)
-	checkboard,		/* display board info */
+	show_board_info,
 #endif
 	INIT_FUNC_WATCHDOG_INIT
 #if defined(CONFIG_MISC_INIT_F)
diff --git a/common/board_info.c b/common/board_info.c
new file mode 100644
index 0000000..42d0641
--- /dev/null
+++ b/common/board_info.c
@@ -0,0 +1,35 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <libfdt.h>
+#include <linux/compiler.h>
+
+int __weak checkboard(void)
+{
+	printf("Board: Unknown\n");
+	return 0;
+}
+
+/*
+ * If the root node of the DTB has a "model" property, show it.
+ * If CONFIG_OF_CONTROL is disabled or the "model" property is missing,
+ * fall back to checkboard().
+ */
+int show_board_info(void)
+{
+#ifdef CONFIG_OF_CONTROL
+	DECLARE_GLOBAL_DATA_PTR;
+	const char *model;
+
+	model = fdt_getprop(gd->fdt_blob, 0, "model", NULL);
+
+	if (model) {
+		printf("Model: %s\n", model);
+		return 0;
+	}
+#endif
+
+	return checkboard();
+}
diff --git a/common/board_r.c b/common/board_r.c
index a301cc2..68a9448 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -476,22 +476,6 @@
 }
 #endif
 
-#ifdef CONFIG_DISPLAY_BOARDINFO_LATE
-static int show_model_r(void)
-{
-	/* Put this here so it appears on the LCD, now it is ready */
-# ifdef CONFIG_OF_CONTROL
-	const char *model;
-
-	model = (char *)fdt_getprop(gd->fdt_blob, 0, "model", NULL);
-	printf("Model: %s\n", model ? model : "<unknown>");
-# else
-	checkboard();
-# endif
-	return 0;
-}
-#endif
-
 /* enable exceptions */
 #ifdef CONFIG_ARM
 static int initr_enable_interrupts(void)
@@ -801,7 +785,7 @@
 #endif
 	console_init_r,		/* fully init console as a device */
 #ifdef CONFIG_DISPLAY_BOARDINFO_LATE
-	show_model_r,
+	show_board_info,
 #endif
 #ifdef CONFIG_ARCH_MISC_INIT
 	arch_misc_init,		/* miscellaneous arch-dependent init */
diff --git a/common/cmd_demo.c b/common/cmd_demo.c
index 652c61c..bcb34d9 100644
--- a/common/cmd_demo.c
+++ b/common/cmd_demo.c
@@ -39,6 +39,26 @@
 	return 0;
 }
 
+static int do_demo_light(cmd_tbl_t *cmdtp, int flag, int argc,
+			 char * const argv[])
+{
+	int light;
+	int ret;
+
+	if (argc) {
+		light = simple_strtoul(argv[0], NULL, 16);
+		ret = demo_set_light(demo_dev, light);
+	} else {
+		ret = demo_get_light(demo_dev);
+		if (ret >= 0) {
+			printf("Light: %x\n", ret);
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
 int do_demo_list(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
 	struct udevice *dev;
@@ -61,6 +81,7 @@
 static cmd_tbl_t demo_commands[] = {
 	U_BOOT_CMD_MKENT(list, 0, 1, do_demo_list, "", ""),
 	U_BOOT_CMD_MKENT(hello, 2, 1, do_demo_hello, "", ""),
+	U_BOOT_CMD_MKENT(light, 2, 1, do_demo_light, "", ""),
 	U_BOOT_CMD_MKENT(status, 1, 1, do_demo_status, "", ""),
 };
 
@@ -86,6 +107,10 @@
 			return cmd_process_error(cmdtp, ret);
 		argc--;
 		argv++;
+	} else {
+		demo_dev = NULL;
+		if (demo_cmd->cmd != do_demo_list)
+			return CMD_RET_USAGE;
 	}
 
 	ret = demo_cmd->cmd(demo_cmd, flag, argc, argv);
@@ -98,5 +123,7 @@
 	"Driver model (dm) demo operations",
 	"list                     List available demo devices\n"
 	"demo hello <num> [<char>]     Say hello\n"
-	"demo status <num>             Get demo device status"
+	"demo light [<num>]            Set or get the lights\n"
+	"demo status <num>             Get demo device status\n"
+	"demo list                     List available demo devices"
 );
diff --git a/common/cmd_i2c.c b/common/cmd_i2c.c
index 22db1bb..7c3ad00 100644
--- a/common/cmd_i2c.c
+++ b/common/cmd_i2c.c
@@ -83,12 +83,12 @@
 /* Display values from last command.
  * Memory modify remembered values are different from display memory.
  */
-static uchar	i2c_dp_last_chip;
+static uint	i2c_dp_last_chip;
 static uint	i2c_dp_last_addr;
 static uint	i2c_dp_last_alen;
 static uint	i2c_dp_last_length = 0x10;
 
-static uchar	i2c_mm_last_chip;
+static uint	i2c_mm_last_chip;
 static uint	i2c_mm_last_addr;
 static uint	i2c_mm_last_alen;
 
@@ -133,7 +133,7 @@
 #ifdef CONFIG_DM_I2C
 static struct udevice *i2c_cur_bus;
 
-static int i2c_set_bus_num(unsigned int busnum)
+static int cmd_i2c_set_bus_num(unsigned int busnum)
 {
 	struct udevice *bus;
 	int ret;
@@ -168,7 +168,7 @@
 	if (ret)
 		return ret;
 
-	return i2c_get_chip(bus, chip_addr, devp);
+	return i2c_get_chip(bus, chip_addr, 1, devp);
 }
 
 #endif
@@ -282,7 +282,7 @@
  */
 static int do_i2c_read ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	u_char	chip;
+	uint	chip;
 	uint	devaddr, length;
 	int alen;
 	u_char  *memaddr;
@@ -323,7 +323,7 @@
 	if (!ret && alen != -1)
 		ret = i2c_set_chip_offset_len(dev, alen);
 	if (!ret)
-		ret = i2c_read(dev, devaddr, memaddr, length);
+		ret = dm_i2c_read(dev, devaddr, memaddr, length);
 #else
 	ret = i2c_read(chip, devaddr, alen, memaddr, length);
 #endif
@@ -335,7 +335,7 @@
 
 static int do_i2c_write(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	u_char	chip;
+	uint	chip;
 	uint	devaddr, length;
 	int alen;
 	u_char  *memaddr;
@@ -381,7 +381,7 @@
 
 	while (length-- > 0) {
 #ifdef CONFIG_DM_I2C
-		ret = i2c_write(dev, devaddr++, memaddr++, 1);
+		ret = dm_i2c_write(dev, devaddr++, memaddr++, 1);
 #else
 		ret = i2c_write(chip, devaddr++, alen, memaddr++, 1);
 #endif
@@ -444,7 +444,7 @@
  */
 static int do_i2c_md ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	u_char	chip;
+	uint	chip;
 	uint	addr, length;
 	int alen;
 	int	j, nbytes, linebytes;
@@ -513,7 +513,7 @@
 		linebytes = (nbytes > DISP_LINE_LEN) ? DISP_LINE_LEN : nbytes;
 
 #ifdef CONFIG_DM_I2C
-		ret = i2c_read(dev, addr, linebuf, linebytes);
+		ret = dm_i2c_read(dev, addr, linebuf, linebytes);
 #else
 		ret = i2c_read(chip, addr, alen, linebuf, linebytes);
 #endif
@@ -563,7 +563,7 @@
  */
 static int do_i2c_mw ( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	uchar	chip;
+	uint	chip;
 	ulong	addr;
 	int	alen;
 	uchar	byte;
@@ -611,7 +611,7 @@
 
 	while (count-- > 0) {
 #ifdef CONFIG_DM_I2C
-		ret = i2c_write(dev, addr++, &byte, 1);
+		ret = dm_i2c_write(dev, addr++, &byte, 1);
 #else
 		ret = i2c_write(chip, addr++, alen, &byte, 1);
 #endif
@@ -649,7 +649,7 @@
  */
 static int do_i2c_crc (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	uchar	chip;
+	uint	chip;
 	ulong	addr;
 	int	alen;
 	int	count;
@@ -698,7 +698,7 @@
 	err = 0;
 	while (count-- > 0) {
 #ifdef CONFIG_DM_I2C
-		ret = i2c_read(dev, addr, &byte, 1);
+		ret = dm_i2c_read(dev, addr, &byte, 1);
 #else
 		ret = i2c_read(chip, addr, alen, &byte, 1);
 #endif
@@ -734,7 +734,7 @@
 static int
 mod_i2c_mem(cmd_tbl_t *cmdtp, int incrflag, int flag, int argc, char * const argv[])
 {
-	uchar	chip;
+	uint	chip;
 	ulong	addr;
 	int	alen;
 	ulong	data;
@@ -793,7 +793,7 @@
 	do {
 		printf("%08lx:", addr);
 #ifdef CONFIG_DM_I2C
-		ret = i2c_read(dev, addr, (uchar *)&data, size);
+		ret = dm_i2c_read(dev, addr, (uchar *)&data, size);
 #else
 		ret = i2c_read(chip, addr, alen, (uchar *)&data, size);
 #endif
@@ -841,8 +841,8 @@
 				 */
 				bootretry_reset_cmd_timeout();
 #ifdef CONFIG_DM_I2C
-				ret = i2c_write(dev, addr, (uchar *)&data,
-						size);
+				ret = dm_i2c_write(dev, addr, (uchar *)&data,
+						   size);
 #else
 				ret = i2c_write(chip, addr, alen,
 						(uchar *)&data, size);
@@ -917,7 +917,7 @@
 			continue;
 #endif
 #ifdef CONFIG_DM_I2C
-		ret = i2c_probe(bus, j, 0, &dev);
+		ret = dm_i2c_probe(bus, j, 0, &dev);
 #else
 		ret = i2c_probe(j);
 #endif
@@ -957,7 +957,7 @@
  */
 static int do_i2c_loop(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
 {
-	u_char	chip;
+	uint	chip;
 	int alen;
 	uint	addr;
 	uint	length;
@@ -1010,7 +1010,7 @@
 	 */
 	while (1) {
 #ifdef CONFIG_DM_I2C
-		ret = i2c_read(dev, addr, bytes, length);
+		ret = dm_i2c_read(dev, addr, bytes, length);
 #else
 		ret = i2c_read(chip, addr, alen, bytes, length);
 #endif
@@ -1085,7 +1085,7 @@
 {
 	enum { unknown, EDO, SDRAM, DDR2 } type;
 
-	u_char	chip;
+	uint	chip;
 	u_char	data[128];
 	u_char	cksum;
 	int	j;
@@ -1563,7 +1563,7 @@
 #if defined(CONFIG_I2C_EDID)
 int do_edid(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
 {
-	u_char chip;
+	uint chip;
 	struct edid1_info edid;
 	int ret;
 #ifdef CONFIG_DM_I2C
@@ -1579,7 +1579,7 @@
 #ifdef CONFIG_DM_I2C
 	ret = i2c_get_cur_bus_chip(chip, &dev);
 	if (!ret)
-		ret = i2c_read(dev, 0, (uchar *)&edid, sizeof(edid));
+		ret = dm_i2c_read(dev, 0, (uchar *)&edid, sizeof(edid));
 #else
 	ret = i2c_read(chip, 0, 1, (uchar *)&edid, sizeof(edid));
 #endif
@@ -1696,7 +1696,11 @@
 		}
 #endif
 		printf("Setting bus to %d\n", bus_no);
+#ifdef CONFIG_DM_I2C
+		ret = cmd_i2c_set_bus_num(bus_no);
+#else
 		ret = i2c_set_bus_num(bus_no);
+#endif
 		if (ret)
 			printf("Failure changing bus number (%d)\n", ret);
 	}
diff --git a/common/cmd_load.c b/common/cmd_load.c
index f6e522c..d043e6d 100644
--- a/common/cmd_load.c
+++ b/common/cmd_load.c
@@ -222,7 +222,7 @@
 		}
 
 	    /* Check for the console hangup (if any different from serial) */
-	    if (gd->jt[XF_getc] != getc) {
+	    if (gd->jt->getc != getc) {
 		if (ctrlc()) {
 		    return (-1);
 		}
diff --git a/common/console.c b/common/console.c
index fc1963b..3f25e76 100644
--- a/common/console.c
+++ b/common/console.c
@@ -125,13 +125,13 @@
 		 */
 		switch (file) {
 		case stdin:
-			gd->jt[XF_getc] = getc;
-			gd->jt[XF_tstc] = tstc;
+			gd->jt->getc = getc;
+			gd->jt->tstc = tstc;
 			break;
 		case stdout:
-			gd->jt[XF_putc] = putc;
-			gd->jt[XF_puts] = puts;
-			gd->jt[XF_printf] = printf;
+			gd->jt->putc  = putc;
+			gd->jt->puts  = puts;
+			gd->jt->printf = printf;
 			break;
 		}
 		break;
@@ -758,11 +758,11 @@
 #endif
 
 	/* set default handlers at first */
-	gd->jt[XF_getc] = serial_getc;
-	gd->jt[XF_tstc] = serial_tstc;
-	gd->jt[XF_putc] = serial_putc;
-	gd->jt[XF_puts] = serial_puts;
-	gd->jt[XF_printf] = serial_printf;
+	gd->jt->getc  = serial_getc;
+	gd->jt->tstc  = serial_tstc;
+	gd->jt->putc  = serial_putc;
+	gd->jt->puts  = serial_puts;
+	gd->jt->printf = serial_printf;
 
 	/* stdin stdout and stderr are in environment */
 	/* scan for it */
diff --git a/common/exports.c b/common/exports.c
index 88fcfc8..333107c 100644
--- a/common/exports.c
+++ b/common/exports.c
@@ -1,6 +1,7 @@
 #include <common.h>
 #include <exports.h>
 #include <spi.h>
+#include <i2c.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -13,33 +14,10 @@
 	return XF_VERSION;
 }
 
-/* Reuse _exports.h with a little trickery to avoid bitrot */
-#define EXPORT_FUNC(sym) gd->jt[XF_##sym] = (void *)sym;
-
-#if !defined(CONFIG_X86) && !defined(CONFIG_PPC)
-# define install_hdlr      dummy
-# define free_hdlr         dummy
-#else /* kludge for non-standard function naming */
-# define install_hdlr      irq_install_handler
-# define free_hdlr         irq_free_handler
-#endif
-#ifndef CONFIG_CMD_I2C
-# define i2c_write         dummy
-# define i2c_read          dummy
-#endif
-#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
-# define spi_init          dummy
-# define spi_setup_slave   dummy
-# define spi_free_slave    dummy
-#endif
-#ifndef CONFIG_CMD_SPI
-# define spi_claim_bus     dummy
-# define spi_release_bus   dummy
-# define spi_xfer          dummy
-#endif
+#define EXPORT_FUNC(f, a, x, ...)  gd->jt->x = f;
 
 void jumptable_init(void)
 {
-	gd->jt = malloc(XF_MAX * sizeof(void *));
+	gd->jt = malloc(sizeof(struct jt_funcs));
 #include <_exports.h>
 }
diff --git a/common/hash.c b/common/hash.c
index aceabc5..d154d02 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -10,17 +10,26 @@
  * SPDX-License-Identifier:	GPL-2.0+
  */
 
+#ifndef USE_HOSTCC
 #include <common.h>
 #include <command.h>
 #include <malloc.h>
 #include <hw_sha.h>
-#include <hash.h>
-#include <u-boot/sha1.h>
-#include <u-boot/sha256.h>
 #include <asm/io.h>
 #include <asm/errno.h>
+#else
+#include "mkimage.h"
+#include <time.h>
+#include <image.h>
+#endif /* !USE_HOSTCC*/
 
-#ifdef CONFIG_CMD_SHA1SUM
+#include <hash.h>
+#include <u-boot/crc.h>
+#include <u-boot/sha1.h>
+#include <u-boot/sha256.h>
+#include <u-boot/md5.h>
+
+#ifdef CONFIG_SHA1
 static int hash_init_sha1(struct hash_algo *algo, void **ctxp)
 {
 	sha1_context *ctx = malloc(sizeof(sha1_context));
@@ -125,12 +134,7 @@
 		CHUNKSZ_SHA256,
 	},
 #endif
-	/*
-	 * This is CONFIG_CMD_SHA1SUM instead of CONFIG_SHA1 since otherwise
-	 * it bloats the code for boards which use SHA1 but not the 'hash'
-	 * or 'sha1sum' commands.
-	 */
-#ifdef CONFIG_CMD_SHA1SUM
+#ifdef CONFIG_SHA1
 	{
 		"sha1",
 		SHA1_SUM_LEN,
@@ -140,7 +144,6 @@
 		hash_update_sha1,
 		hash_finish_sha1,
 	},
-#define MULTI_HASH
 #endif
 #ifdef CONFIG_SHA256
 	{
@@ -152,7 +155,6 @@
 		hash_update_sha256,
 		hash_finish_sha256,
 	},
-#define MULTI_HASH
 #endif
 	{
 		"crc32",
@@ -165,6 +167,10 @@
 	},
 };
 
+#if defined(CONFIG_SHA256) || defined(CONFIG_CMD_SHA1SUM)
+#define MULTI_HASH
+#endif
+
 #if defined(CONFIG_HASH_VERIFY) || defined(CONFIG_CMD_HASH)
 #define MULTI_HASH
 #endif
@@ -176,6 +182,40 @@
 #define multi_hash()	0
 #endif
 
+int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+		if (!strcmp(algo_name, hash_algo[i].name)) {
+			*algop = &hash_algo[i];
+			return 0;
+		}
+	}
+
+	debug("Unknown hash algorithm '%s'\n", algo_name);
+	return -EPROTONOSUPPORT;
+}
+
+int hash_progressive_lookup_algo(const char *algo_name,
+				 struct hash_algo **algop)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
+		if (!strcmp(algo_name, hash_algo[i].name)) {
+			if (hash_algo[i].hash_init) {
+				*algop = &hash_algo[i];
+				return 0;
+			}
+		}
+	}
+
+	debug("Unknown hash algorithm '%s'\n", algo_name);
+	return -EPROTONOSUPPORT;
+}
+
+#ifndef USE_HOSTCC
 /**
  * store_result: Store the resulting sum to an address or variable
  *
@@ -296,21 +336,6 @@
 	return 0;
 }
 
-int hash_lookup_algo(const char *algo_name, struct hash_algo **algop)
-{
-	int i;
-
-	for (i = 0; i < ARRAY_SIZE(hash_algo); i++) {
-		if (!strcmp(algo_name, hash_algo[i].name)) {
-			*algop = &hash_algo[i];
-			return 0;
-		}
-	}
-
-	debug("Unknown hash algorithm '%s'\n", algo_name);
-	return -EPROTONOSUPPORT;
-}
-
 void hash_show(struct hash_algo *algo, ulong addr, ulong len, uint8_t *output)
 {
 	int i;
@@ -424,3 +449,4 @@
 
 	return 0;
 }
+#endif
diff --git a/common/image-sig.c b/common/image-sig.c
index 8601eda..2c9f0cd 100644
--- a/common/image-sig.c
+++ b/common/image-sig.c
@@ -38,7 +38,7 @@
 #if IMAGE_ENABLE_SIGN
 		EVP_sha1,
 #endif
-		sha1_calculate,
+		hash_calculate,
 		padding_sha1_rsa2048,
 	},
 	{
@@ -48,7 +48,7 @@
 #if IMAGE_ENABLE_SIGN
 		EVP_sha256,
 #endif
-		sha256_calculate,
+		hash_calculate,
 		padding_sha256_rsa2048,
 	},
 	{
@@ -58,7 +58,7 @@
 #if IMAGE_ENABLE_SIGN
 		EVP_sha256,
 #endif
-		sha256_calculate,
+		hash_calculate,
 		padding_sha256_rsa4096,
 	}
 
diff --git a/configs/am335x_boneblack_vboot_defconfig b/configs/am335x_boneblack_vboot_defconfig
index 5837a0a..51bf370 100644
--- a/configs/am335x_boneblack_vboot_defconfig
+++ b/configs/am335x_boneblack_vboot_defconfig
@@ -4,3 +4,7 @@
 +S:CONFIG_TARGET_AM335X_EVM=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="am335x-boneblack"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/ids8313_defconfig b/configs/ids8313_defconfig
index 1c665aa..0950ec8 100644
--- a/configs/ids8313_defconfig
+++ b/configs/ids8313_defconfig
@@ -1,4 +1,7 @@
 CONFIG_SYS_EXTRA_OPTIONS="SYS_TEXT_BASE=0xFFF00000"
 CONFIG_PPC=y
 CONFIG_MPC83xx=y
+CONFIG_FIT=y
+CONFIG_FIT_SIGNATURE=y
 CONFIG_TARGET_IDS8313=y
+CONFIG_DM=y
diff --git a/configs/ph1_ld4_defconfig b/configs/ph1_ld4_defconfig
index 2e9dd00..86b4b15 100644
--- a/configs/ph1_ld4_defconfig
+++ b/configs/ph1_ld4_defconfig
@@ -18,6 +18,7 @@
 CONFIG_CMD_LOADS=y
 CONFIG_CMD_FLASH=y
 CONFIG_CMD_NAND=y
+CONFIG_CMD_I2C=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_ECHO=y
 CONFIG_CMD_ITEST=y
@@ -34,6 +35,7 @@
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
 CONFIG_DM_SERIAL=y
 CONFIG_UNIPHIER_SERIAL=y
+CONFIG_DM_I2C=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/ph1_pro4_defconfig b/configs/ph1_pro4_defconfig
index 5dca64b..242bcf9 100644
--- a/configs/ph1_pro4_defconfig
+++ b/configs/ph1_pro4_defconfig
@@ -18,6 +18,7 @@
 CONFIG_CMD_LOADS=y
 CONFIG_CMD_FLASH=y
 CONFIG_CMD_NAND=y
+CONFIG_CMD_I2C=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_ECHO=y
 CONFIG_CMD_ITEST=y
@@ -34,6 +35,7 @@
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
 CONFIG_DM_SERIAL=y
 CONFIG_UNIPHIER_SERIAL=y
+CONFIG_DM_I2C=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/ph1_sld8_defconfig b/configs/ph1_sld8_defconfig
index 2a6e334..8e95f17 100644
--- a/configs/ph1_sld8_defconfig
+++ b/configs/ph1_sld8_defconfig
@@ -18,6 +18,7 @@
 CONFIG_CMD_LOADS=y
 CONFIG_CMD_FLASH=y
 CONFIG_CMD_NAND=y
+CONFIG_CMD_I2C=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_ECHO=y
 CONFIG_CMD_ITEST=y
@@ -34,6 +35,7 @@
 CONFIG_NAND_DENALI_SPARE_AREA_SKIP_BYTES=8
 CONFIG_DM_SERIAL=y
 CONFIG_UNIPHIER_SERIAL=y
+CONFIG_DM_I2C=y
 CONFIG_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 47d8400..660063e 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -1,3 +1,7 @@
 CONFIG_OF_CONTROL=y
 CONFIG_OF_HOSTFILE=y
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
 CONFIG_DEFAULT_DEVICE_TREE="sandbox"
diff --git a/configs/zynq_microzed_defconfig b/configs/zynq_microzed_defconfig
index 9588849..8b985fe 100644
--- a/configs/zynq_microzed_defconfig
+++ b/configs/zynq_microzed_defconfig
@@ -3,4 +3,8 @@
 +S:CONFIG_ZYNQ=y
 +S:CONFIG_TARGET_ZYNQ_MICROZED=y
 CONFIG_OF_CONTROL=y
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-microzed"
diff --git a/configs/zynq_zc70x_defconfig b/configs/zynq_zc70x_defconfig
index cf50730..cceb321 100644
--- a/configs/zynq_zc70x_defconfig
+++ b/configs/zynq_zc70x_defconfig
@@ -4,3 +4,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZC70X=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc702"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/zynq_zc770_xm010_defconfig b/configs/zynq_zc770_xm010_defconfig
index 8bb405d..2935c0d 100644
--- a/configs/zynq_zc770_xm010_defconfig
+++ b/configs/zynq_zc770_xm010_defconfig
@@ -5,3 +5,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm010"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/zynq_zc770_xm012_defconfig b/configs/zynq_zc770_xm012_defconfig
index 0ba5da5..0401739 100644
--- a/configs/zynq_zc770_xm012_defconfig
+++ b/configs/zynq_zc770_xm012_defconfig
@@ -5,3 +5,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm012"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/zynq_zc770_xm013_defconfig b/configs/zynq_zc770_xm013_defconfig
index 13f8112..a95970a 100644
--- a/configs/zynq_zc770_xm013_defconfig
+++ b/configs/zynq_zc770_xm013_defconfig
@@ -5,3 +5,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZC770=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zc770-xm013"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/zynq_zed_defconfig b/configs/zynq_zed_defconfig
index eb057fa..0fbc41a 100644
--- a/configs/zynq_zed_defconfig
+++ b/configs/zynq_zed_defconfig
@@ -4,3 +4,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZED=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zed"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig
index 12311cd..4e66760 100644
--- a/configs/zynq_zybo_defconfig
+++ b/configs/zynq_zybo_defconfig
@@ -4,3 +4,7 @@
 +S:CONFIG_TARGET_ZYNQ_ZYBO=y
 CONFIG_OF_CONTROL=y
 CONFIG_DEFAULT_DEVICE_TREE="zynq-zybo"
+CONFIG_FIT=y
+CONFIG_FIT_VERBOSE=y
+CONFIG_FIT_SIGNATURE=y
+CONFIG_DM=y
diff --git a/doc/README.standalone b/doc/README.standalone
index e3000ef..659a12f 100644
--- a/doc/README.standalone
+++ b/doc/README.standalone
@@ -5,18 +5,18 @@
    table is allocated and initialized in the jumptable_init() routine
    (common/exports.c). Other routines may also modify the jump table,
    however. The jump table can be accessed as the 'jt' field of the
-   'global_data' structure. The slot numbers for the jump table are
+   'global_data' structure. The struct members for the jump table are
    defined in the <include/exports.h> header. E.g., to substitute the
    malloc() and free() functions that will be available to standalone
    applications, one should do the following:
 
 	DECLARE_GLOBAL_DATA_PTR;
 
-	gd->jt[XF_malloc]	= my_malloc;
-	gd->jt[XF_free]		= my_free;
+	gd->jt->malloc	= my_malloc;
+	gd->jt->free = my_free;
 
-   Note that the pointers to the functions all have 'void *' type and
-   thus the compiler cannot perform type checks on these assignments.
+   Note that the pointers to the functions are real function pointers
+   so the compiler can perform type checks on these assignments.
 
 2. The pointer to the jump table is passed to the application in a
    machine-dependent way. PowerPC, ARM, MIPS, Blackfin and Nios II
@@ -65,27 +65,46 @@
    => tftp 0x40000 hello_world.bin
    => go 0x40004
 
-5. To export some additional function foobar(), the following steps
+5. To export some additional function long foobar(int i,char c), the following steps
    should be undertaken:
 
    - Append the following line at the end of the include/_exports.h
      file:
 
-	EXPORT_FUNC(foobar)
+	EXPORT_FUNC(foobar, long, foobar, int, char)
+
+	Parameters to EXPORT_FUNC:
+	 - the first parameter is the function that is exported (default implementation)
+	 - the second parameter is the return value type
+	 - the third  parameter is the name of the member in struct jt_funcs
+	   this is also the name that the standalone application will used.
+	   the rest of the parameters are the function arguments
 
    - Add the prototype for this function to the include/exports.h
      file:
 
-	void foobar(void);
+	long foobar(int i, char c);
 
-   - Add the initialization of the jump table slot wherever
-     appropriate (most likely, to the jumptable_init() function):
+	Initialization with the default implementation is done in jumptable_init()
 
-	gd->jt[XF_foobar] = foobar;
+	You can override the default implementation using:
+
+	gd->jt->foobar = another_foobar;
+
+	The signature of another_foobar must then match the declaration of foobar.
 
    - Increase the XF_VERSION value by one in the include/exports.h
      file
 
+   - If you want to export a function which depends on a CONFIG_XXX
+	use 2 lines like this:
+	#ifdef CONFIG_FOOBAR
+		EXPORT_FUNC(foobar, long, foobar, int, char)
+	#else
+		EXPORT_FUNC(dummy, void, foobar, void)
+	#endif
+
+
 6. The code for exporting the U-Boot functions to applications is
    mostly machine-independent. The only places written in assembly
    language are stub functions that perform the jump through the jump
diff --git a/doc/device-tree-bindings/gpio/gpio-samsung.txt b/doc/device-tree-bindings/gpio/gpio-samsung.txt
new file mode 100644
index 0000000..5375625
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/gpio-samsung.txt
@@ -0,0 +1,41 @@
+Samsung Exynos4 GPIO Controller
+
+Required properties:
+- compatible: Compatible property value should be "samsung,exynos4-gpio>".
+
+- reg: Physical base address of the controller and length of memory mapped
+  region.
+
+- #gpio-cells: Should be 4. The syntax of the gpio specifier used by client nodes
+  should be the following with values derived from the SoC user manual.
+     <[phandle of the gpio controller node]
+      [pin number within the gpio controller]
+      [mux function]
+      [flags and pull up/down]
+      [drive strength]>
+
+  Values for gpio specifier:
+  - Pin number: is a value between 0 to 7.
+  - Flags and Pull Up/Down: 0 - Pull Up/Down Disabled.
+                            1 - Pull Down Enabled.
+                            3 - Pull Up Enabled.
+          Bit 16 (0x00010000) - Input is active low.
+  - Drive Strength: 0 - 1x,
+                    1 - 3x,
+                    2 - 2x,
+                    3 - 4x
+
+- gpio-controller: Specifies that the node is a gpio controller.
+- #address-cells: should be 1.
+- #size-cells: should be 1.
+
+Example:
+
+	gpa0: gpio-controller@11400000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "samsung,exynos4-gpio";
+		reg = <0x11400000 0x20>;
+		#gpio-cells = <4>;
+		gpio-controller;
+	};
diff --git a/doc/device-tree-bindings/gpio/gpio.txt b/doc/device-tree-bindings/gpio/gpio.txt
new file mode 100644
index 0000000..b9bd1d6
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/gpio.txt
@@ -0,0 +1,211 @@
+Specifying GPIO information for devices
+============================================
+
+1) gpios property
+-----------------
+
+Nodes that makes use of GPIOs should specify them using one or more
+properties, each containing a 'gpio-list':
+
+	gpio-list ::= <single-gpio> [gpio-list]
+	single-gpio ::= <gpio-phandle> <gpio-specifier>
+	gpio-phandle : phandle to gpio controller node
+	gpio-specifier : Array of #gpio-cells specifying specific gpio
+			 (controller specific)
+
+GPIO properties should be named "[<name>-]gpios", with <name> being the purpose
+of this GPIO for the device. While a non-existent <name> is considered valid
+for compatibility reasons (resolving to the "gpios" property), it is not allowed
+for new bindings.
+
+GPIO properties can contain one or more GPIO phandles, but only in exceptional
+cases should they contain more than one. If your device uses several GPIOs with
+distinct functions, reference each of them under its own property, giving it a
+meaningful name. The only case where an array of GPIOs is accepted is when
+several GPIOs serve the same function (e.g. a parallel data line).
+
+The exact purpose of each gpios property must be documented in the device tree
+binding of the device.
+
+The following example could be used to describe GPIO pins used as device enable
+and bit-banged data signals:
+
+	gpio1: gpio1 {
+		gpio-controller
+		 #gpio-cells = <2>;
+	};
+	gpio2: gpio2 {
+		gpio-controller
+		 #gpio-cells = <1>;
+	};
+	[...]
+
+	enable-gpios = <&gpio2 2>;
+	data-gpios = <&gpio1 12 0>,
+		     <&gpio1 13 0>,
+		     <&gpio1 14 0>,
+		     <&gpio1 15 0>;
+
+Note that gpio-specifier length is controller dependent.  In the
+above example, &gpio1 uses 2 cells to specify a gpio, while &gpio2
+only uses one.
+
+gpio-specifier may encode: bank, pin position inside the bank,
+whether pin is open-drain and whether pin is logically inverted.
+Exact meaning of each specifier cell is controller specific, and must
+be documented in the device tree binding for the device. Use the macros
+defined in include/dt-bindings/gpio/gpio.h whenever possible:
+
+Example of a node using GPIOs:
+
+	node {
+		enable-gpios = <&qe_pio_e 18 GPIO_ACTIVE_HIGH>;
+	};
+
+GPIO_ACTIVE_HIGH is 0, so in this example gpio-specifier is "18 0" and encodes
+GPIO pin number, and GPIO flags as accepted by the "qe_pio_e" gpio-controller.
+
+1.1) GPIO specifier best practices
+----------------------------------
+
+A gpio-specifier should contain a flag indicating the GPIO polarity; active-
+high or active-low. If it does, the follow best practices should be followed:
+
+The gpio-specifier's polarity flag should represent the physical level at the
+GPIO controller that achieves (or represents, for inputs) a logically asserted
+value at the device. The exact definition of logically asserted should be
+defined by the binding for the device. If the board inverts the signal between
+the GPIO controller and the device, then the gpio-specifier will represent the
+opposite physical level than the signal at the device's pin.
+
+When the device's signal polarity is configurable, the binding for the
+device must either:
+
+a) Define a single static polarity for the signal, with the expectation that
+any software using that binding would statically program the device to use
+that signal polarity.
+
+The static choice of polarity may be either:
+
+a1) (Preferred) Dictated by a binding-specific DT property.
+
+or:
+
+a2) Defined statically by the DT binding itself.
+
+In particular, the polarity cannot be derived from the gpio-specifier, since
+that would prevent the DT from separately representing the two orthogonal
+concepts of configurable signal polarity in the device, and possible board-
+level signal inversion.
+
+or:
+
+b) Pick a single option for device signal polarity, and document this choice
+in the binding. The gpio-specifier should represent the polarity of the signal
+(at the GPIO controller) assuming that the device is configured for this
+particular signal polarity choice. If software chooses to program the device
+to generate or receive a signal of the opposite polarity, software will be
+responsible for correctly interpreting (inverting) the GPIO signal at the GPIO
+controller.
+
+2) gpio-controller nodes
+------------------------
+
+Every GPIO controller node must contain both an empty "gpio-controller"
+property, and a #gpio-cells integer property, which indicates the number of
+cells in a gpio-specifier.
+
+Example of two SOC GPIO banks defined as gpio-controller nodes:
+
+	qe_pio_a: gpio-controller@1400 {
+		compatible = "fsl,qe-pario-bank-a", "fsl,qe-pario-bank";
+		reg = <0x1400 0x18>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+	qe_pio_e: gpio-controller@1460 {
+		compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+		#gpio-cells = <2>;
+	};
+
+2.1) gpio- and pin-controller interaction
+-----------------------------------------
+
+Some or all of the GPIOs provided by a GPIO controller may be routed to pins
+on the package via a pin controller. This allows muxing those pins between
+GPIO and other functions.
+
+It is useful to represent which GPIOs correspond to which pins on which pin
+controllers. The gpio-ranges property described below represents this, and
+contains information structures as follows:
+
+	gpio-range-list ::= <single-gpio-range> [gpio-range-list]
+	single-gpio-range ::= <numeric-gpio-range> | <named-gpio-range>
+	numeric-gpio-range ::=
+			<pinctrl-phandle> <gpio-base> <pinctrl-base> <count>
+	named-gpio-range ::= <pinctrl-phandle> <gpio-base> '<0 0>'
+	gpio-phandle : phandle to pin controller node.
+	gpio-base : Base GPIO ID in the GPIO controller
+	pinctrl-base : Base pinctrl pin ID in the pin controller
+	count : The number of GPIOs/pins in this range
+
+The "pin controller node" mentioned above must conform to the bindings
+described in ../pinctrl/pinctrl-bindings.txt.
+
+In case named gpio ranges are used (ranges with both <pinctrl-base> and
+<count> set to 0), the property gpio-ranges-group-names contains one string
+for every single-gpio-range in gpio-ranges:
+	gpiorange-names-list ::= <gpiorange-name> [gpiorange-names-list]
+	gpiorange-name : Name of the pingroup associated to the GPIO range in
+			the respective pin controller.
+
+Elements of gpiorange-names-list corresponding to numeric ranges contain
+the empty string. Elements of gpiorange-names-list corresponding to named
+ranges contain the name of a pin group defined in the respective pin
+controller. The number of pins/GPIOs in the range is the number of pins in
+that pin group.
+
+Previous versions of this binding required all pin controller nodes that
+were referenced by any gpio-ranges property to contain a property named
+#gpio-range-cells with value <3>. This requirement is now deprecated.
+However, that property may still exist in older device trees for
+compatibility reasons, and would still be required even in new device
+trees that need to be compatible with older software.
+
+Example 1:
+
+	qe_pio_e: gpio-controller@1460 {
+		#gpio-cells = <2>;
+		compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+		reg = <0x1460 0x18>;
+		gpio-controller;
+		gpio-ranges = <&pinctrl1 0 20 10>, <&pinctrl2 10 50 20>;
+	};
+
+Here, a single GPIO controller has GPIOs 0..9 routed to pin controller
+pinctrl1's pins 20..29, and GPIOs 10..19 routed to pin controller pinctrl2's
+pins 50..59.
+
+Example 2:
+
+	gpio_pio_i: gpio-controller@14B0 {
+		#gpio-cells = <2>;
+		compatible = "fsl,qe-pario-bank-e", "fsl,qe-pario-bank";
+		reg = <0x1480 0x18>;
+		gpio-controller;
+		gpio-ranges =			<&pinctrl1 0 20 10>,
+						<&pinctrl2 10 0 0>,
+						<&pinctrl1 15 0 10>,
+						<&pinctrl2 25 0 0>;
+		gpio-ranges-group-names =	"",
+						"foo",
+						"",
+						"bar";
+	};
+
+Here, three GPIO ranges are defined wrt. two pin controllers. pinctrl1 GPIO
+ranges are defined using pin numbers whereas the GPIO ranges wrt. pinctrl2
+are named "foo" and "bar".
diff --git a/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt b/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt
new file mode 100644
index 0000000..023c952
--- /dev/null
+++ b/doc/device-tree-bindings/gpio/nvidia,tegra20-gpio.txt
@@ -0,0 +1,40 @@
+NVIDIA Tegra GPIO controller
+
+Required properties:
+- compatible : "nvidia,tegra<chip>-gpio"
+- reg : Physical base address and length of the controller's registers.
+- interrupts : The interrupt outputs from the controller. For Tegra20,
+  there should be 7 interrupts specified, and for Tegra30, there should
+  be 8 interrupts specified.
+- #gpio-cells : Should be two. The first cell is the pin number and the
+  second cell is used to specify optional parameters:
+  - bit 0 specifies polarity (0 for normal, 1 for inverted)
+- gpio-controller : Marks the device node as a GPIO controller.
+- #interrupt-cells : Should be 2.
+  The first cell is the GPIO number.
+  The second cell is used to specify flags:
+    bits[3:0] trigger type and level flags:
+      1 = low-to-high edge triggered.
+      2 = high-to-low edge triggered.
+      4 = active high level-sensitive.
+      8 = active low level-sensitive.
+      Valid combinations are 1, 2, 3, 4, 8.
+- interrupt-controller : Marks the device node as an interrupt controller.
+
+Example:
+
+gpio: gpio@6000d000 {
+	compatible = "nvidia,tegra20-gpio";
+	reg = < 0x6000d000 0x1000 >;
+	interrupts = < 0 32 0x04
+		       0 33 0x04
+		       0 34 0x04
+		       0 35 0x04
+		       0 55 0x04
+		       0 87 0x04
+		       0 89 0x04 >;
+	#gpio-cells = <2>;
+	gpio-controller;
+	#interrupt-cells = <2>;
+	interrupt-controller;
+};
diff --git a/doc/device-tree-bindings/i2c/i2c.txt b/doc/device-tree-bindings/i2c/i2c.txt
new file mode 100644
index 0000000..ea918dd
--- /dev/null
+++ b/doc/device-tree-bindings/i2c/i2c.txt
@@ -0,0 +1,28 @@
+U-Boot I2C
+----------
+
+U-Boot's I2C model has the concept of an offset within a chip (I2C target
+device). The offset can be up to 4 bytes long, but is normally 1 byte,
+meaning that offsets from 0 to 255 are supported by the chip. This often
+corresponds to register numbers.
+
+Apart from the controller-specific I2C bindings, U-Boot supports a special
+property which allows the chip offset length to be selected.
+
+Optional properties:
+- u-boot,i2c-offset-len - length of chip offset in bytes. If omitted the
+    default value of 1 is used.
+
+
+Example
+-------
+
+i2c4: i2c@12ca0000 {
+	cros-ec@1e {
+		reg = <0x1e>;
+		compatible = "google,cros-ec";
+		i2c-max-frequency = <100000>;
+		u-boot,i2c-offset-len = <0>;
+		ec-interrupt = <&gpx1 6 GPIO_ACTIVE_LOW>;
+	};
+};
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index eafa825..f83264d 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -363,6 +363,10 @@
 in your ofdata_to_platdata (or probe) method to allocate the required memory,
 and you should free it in the remove method.
 
+The driver model tree is intended to mirror that of the device tree. The
+root driver is at device tree offset 0 (the root node, '/'), and its
+children are the children of the root node.
+
 
 Declaring Uclasses
 ------------------
@@ -384,12 +388,12 @@
 U-Boot numbers devices from 0 in many situations, such as in the command
 line for I2C and SPI buses, and the device names for serial ports (serial0,
 serial1, ...). Driver model supports this numbering and permits devices
-to be locating by their 'sequence'. This numbering unique identifies a
+to be locating by their 'sequence'. This numbering uniquely identifies a
 device in its uclass, so no two devices within a particular uclass can have
 the same sequence number.
 
 Sequence numbers start from 0 but gaps are permitted. For example, a board
-may have I2C buses 0, 1, 4, 5 but no 2 or 3. The choice of how devices are
+may have I2C buses 1, 4, 5 but no 0, 2 or 3. The choice of how devices are
 numbered is up to a particular board, and may be set by the SoC in some
 cases. While it might be tempting to automatically renumber the devices
 where there are gaps in the sequence, this can lead to confusion and is
@@ -399,7 +403,7 @@
 device will be automatically allocated the next available sequence number.
 
 To specify the sequence number in the device tree an alias is typically
-used.
+used. Make sure that the uclass has the DM_UC_FLAG_SEQ_ALIAS flag set.
 
 aliases {
 	serial2 = "/serial@22230000";
@@ -409,43 +413,18 @@
 ("/serial@22230000") will be given sequence number 2. Any command or driver
 which requests serial device 2 will obtain this device.
 
-Some devices represent buses where the devices on the bus are numbered or
-addressed. For example, SPI typically numbers its slaves from 0, and I2C
-uses a 7-bit address. In these cases the 'reg' property of the subnode is
-used, for example:
+More commonly you can use node references, which expand to the full path:
 
-{
-	aliases {
-		spi2 = "/spi@22300000";
-	};
+aliases {
+	serial2 = &serial_2;
+};
+...
+serial_2: serial@22230000 {
+...
+};
 
-	spi@22300000 {
-		#address-cells = <1>;
-		#size-cells = <1>;
-		spi-flash@0 {
-			reg = <0>;
-			...
-		}
-		eeprom@1 {
-			reg = <1>;
-		};
-	};
-
-In this case we have a SPI bus with two slaves at 0 and 1. The SPI bus
-itself is numbered 2. So we might access the SPI flash with:
-
-	sf probe 2:0
-
-and the eeprom with
-
-	sspi 2:1 32 ef
-
-These commands simply need to look up the 2nd device in the SPI uclass to
-find the right SPI bus. Then, they look at the children of that bus for the
-right sequence number (0 or 1 in this case).
-
-Typically the alias method is used for top-level nodes and the 'reg' method
-is used only for buses.
+The alias resolves to the same string in this case, but this version is
+easier to read.
 
 Device sequence numbers are resolved when a device is probed. Before then
 the sequence number is only a request which may or may not be honoured,
@@ -462,11 +441,18 @@
 the bus provides some sort of transport or translation that makes it
 possible to talk to the devices on the bus.
 
-Driver model provides a few useful features to help with implementing
-buses. Firstly, a bus can request that its children store some 'parent
-data' which can be used to keep track of child state. Secondly, the bus can
-define methods which are called when a child is probed or removed. This is
-similar to the methods the uclass driver provides.
+Driver model provides some useful features to help with implementing buses.
+Firstly, a bus can request that its children store some 'parent data' which
+can be used to keep track of child state. Secondly, the bus can define
+methods which are called when a child is probed or removed. This is similar
+to the methods the uclass driver provides. Thirdly, per-child platform data
+can be provided to specify things like the child's address on the bus. This
+persists across child probe()/remove() cycles.
+
+For consistency and ease of implementation, the bus uclass can specify the
+per-child platform data, so that it can be the same for all children of buses
+in that uclass. There are also uclass methods which can be called when
+children are bound and probed.
 
 Here an explanation of how a bus fits with a uclass may be useful. Consider
 a USB bus with several devices attached to it, each from a different (made
@@ -481,15 +467,23 @@
 The bus device wants to store this address and some other information such
 as the bus speed for each device.
 
-To achieve this, the bus device can use dev->parent_priv in each of its
-three children. This can be auto-allocated if the bus driver has a non-zero
-value for per_child_auto_alloc_size. If not, then the bus device can
-allocate the space itself before the child device is probed.
+To achieve this, the bus device can use dev->parent_platdata in each of its
+three children. This can be auto-allocated if the bus driver (or bus uclass)
+has a non-zero value for per_child_platdata_auto_alloc_size. If not, then
+the bus device or uclass can allocate the space itself before the child
+device is probed.
 
 Also the bus driver can define the child_pre_probe() and child_post_remove()
 methods to allow it to do some processing before the child is activated or
 after it is deactivated.
 
+Similarly the bus uclass can define the child_post_bind() method to obtain
+the per-child platform data from the device tree and set it up for the child.
+The bus uclass can also provide a child_pre_probe() method. Very often it is
+the bus uclass that controls these features, since it avoids each driver
+having to do the same processing. Of course the driver can still tweak and
+override these activities.
+
 Note that the information that controls this behaviour is in the bus's
 driver, not the child's. In fact it is possible that child has no knowledge
 that it is connected to a bus. The same child device may even be used on two
@@ -516,7 +510,8 @@
 The uclass for the device can also contain data private to that uclass.
 But note that each device on the bus may be a memeber of a different
 uclass, and this data has nothing to do with the child data for each child
-on the bus.
+on the bus. It is the bus' uclass that controls the child with respect to
+the bus.
 
 
 Driver Lifecycle
diff --git a/doc/driver-model/spi-howto.txt b/doc/driver-model/spi-howto.txt
index 719dbd5..5bc29ad 100644
--- a/doc/driver-model/spi-howto.txt
+++ b/doc/driver-model/spi-howto.txt
@@ -3,7 +3,8 @@
 
 Here is a rough step-by-step guide. It is based around converting the
 exynos SPI driver to driver model (DM) and the example code is based
-around U-Boot v2014.10-rc2 (commit be9f643).
+around U-Boot v2014.10-rc2 (commit be9f643). This has been updated for
+v2015.04.
 
 It is quite long since it includes actual code examples.
 
@@ -262,8 +263,8 @@
 	.platdata = &platdata_spi0,
 };
 
-You will unfortunately need to put the struct into a header file in this
-case so that your board file can use it.
+You will unfortunately need to put the struct definition into a header file
+in this case so that your board file can use it.
 
 
 9. Add the device private data
@@ -592,3 +593,36 @@
 
 You can use 'tools/patman/patman' to prepare, check and send patches for
 your work. See the README for details.
+
+20. A little note about SPI uclass features:
+
+The SPI uclass keeps some information about each device 'dev' on the bus:
+
+   struct dm_spi_slave_platdata - this is device_get_parent_platdata(dev)
+		This is where the chip select number is stored, along with
+		the default bus speed and mode. It is automatically read
+		from the device tree in spi_child_post_bind(). It must not
+		be changed at run-time after being set up because platform
+		data is supposed to be immutable at run-time.
+   struct spi_slave - this is device_get_parentdata(dev)
+		Already mentioned above. It holds run-time information about
+		the device.
+
+There are also some SPI uclass methods that get called behind the scenes:
+
+   spi_post_bind() - called when a new bus is bound
+		This scans the device tree for devices on the bus, and binds
+		each one. This in turn causes spi_child_post_bind() to be
+		called for each, which reads the device tree information
+		into the parent (per-child) platform data.
+   spi_child_post_bind() - called when a new child is bound
+		As mentioned above this reads the device tree information
+		into the per-child platform data
+   spi_child_pre_probe() - called before a new child is probed
+		This sets up the mode and speed in struct spi_slave by
+		copying it from the parent's platform data for this child.
+		It also sets the 'dev' pointer, needed to permit passing
+		'struct spi_slave' around the place without needing a
+		separate 'struct udevice' pointer.
+
+The above housekeeping makes it easier to write your SPI driver.
diff --git a/drivers/core/device-remove.c b/drivers/core/device-remove.c
index 8fc6b71..3a5f48d 100644
--- a/drivers/core/device-remove.c
+++ b/drivers/core/device-remove.c
@@ -88,6 +88,14 @@
 	if (ret)
 		return ret;
 
+	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+		free(dev->platdata);
+		dev->platdata = NULL;
+	}
+	if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+		free(dev->parent_platdata);
+		dev->parent_platdata = NULL;
+	}
 	ret = uclass_unbind_device(dev);
 	if (ret)
 		return ret;
@@ -111,10 +119,6 @@
 		free(dev->priv);
 		dev->priv = NULL;
 	}
-	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
-		free(dev->platdata);
-		dev->platdata = NULL;
-	}
 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
 	if (size) {
 		free(dev->uclass_priv);
@@ -122,6 +126,10 @@
 	}
 	if (dev->parent) {
 		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (!size) {
+			size = dev->parent->uclass->uc_drv->
+					per_child_auto_alloc_size;
+		}
 		if (size) {
 			free(dev->parent_priv);
 			dev->parent_priv = NULL;
diff --git a/drivers/core/device.c b/drivers/core/device.c
index 963b16f..b73d3b8 100644
--- a/drivers/core/device.c
+++ b/drivers/core/device.c
@@ -53,27 +53,47 @@
 	dev->driver = drv;
 	dev->uclass = uc;
 
-	/*
-	 * For some devices, such as a SPI or I2C bus, the 'reg' property
-	 * is a reasonable indicator of the sequence number. But if there is
-	 * an alias, we use that in preference. In any case, this is just
-	 * a 'requested' sequence, and will be resolved (and ->seq updated)
-	 * when the device is probed.
-	 */
 	dev->seq = -1;
-#ifdef CONFIG_OF_CONTROL
-	dev->req_seq = fdtdec_get_int(gd->fdt_blob, of_offset, "reg", -1);
-	if (!IS_ERR_VALUE(dev->req_seq))
-		dev->req_seq &= INT_MAX;
-	if (uc->uc_drv->name && of_offset != -1) {
-		fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name, of_offset,
-				     &dev->req_seq);
-	}
-#else
 	dev->req_seq = -1;
+#ifdef CONFIG_OF_CONTROL
+	/*
+	 * Some devices, such as a SPI bus, I2C bus and serial ports are
+	 * numbered using aliases.
+	 *
+	 * This is just a 'requested' sequence, and will be
+	 * resolved (and ->seq updated) when the device is probed.
+	 */
+	if (uc->uc_drv->flags & DM_UC_FLAG_SEQ_ALIAS) {
+		if (uc->uc_drv->name && of_offset != -1) {
+			fdtdec_get_alias_seq(gd->fdt_blob, uc->uc_drv->name,
+					     of_offset, &dev->req_seq);
+		}
+	}
 #endif
-	if (!dev->platdata && drv->platdata_auto_alloc_size)
+	if (!dev->platdata && drv->platdata_auto_alloc_size) {
 		dev->flags |= DM_FLAG_ALLOC_PDATA;
+		dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
+		if (!dev->platdata) {
+			ret = -ENOMEM;
+			goto fail_alloc1;
+		}
+	}
+	if (parent) {
+		int size = parent->driver->per_child_platdata_auto_alloc_size;
+
+		if (!size) {
+			size = parent->uclass->uc_drv->
+					per_child_platdata_auto_alloc_size;
+		}
+		if (size) {
+			dev->flags |= DM_FLAG_ALLOC_PARENT_PDATA;
+			dev->parent_platdata = calloc(1, size);
+			if (!dev->parent_platdata) {
+				ret = -ENOMEM;
+				goto fail_alloc2;
+			}
+		}
+	}
 
 	/* put dev into parent's successor list */
 	if (parent)
@@ -81,28 +101,51 @@
 
 	ret = uclass_bind_device(dev);
 	if (ret)
-		goto fail_bind;
+		goto fail_uclass_bind;
 
 	/* if we fail to bind we remove device from successors and free it */
 	if (drv->bind) {
 		ret = drv->bind(dev);
-		if (ret) {
-			if (uclass_unbind_device(dev)) {
-				dm_warn("Failed to unbind dev '%s' on error path\n",
-					dev->name);
-			}
+		if (ret)
 			goto fail_bind;
-		}
 	}
+	if (parent && parent->driver->child_post_bind) {
+		ret = parent->driver->child_post_bind(dev);
+		if (ret)
+			goto fail_child_post_bind;
+	}
+
 	if (parent)
 		dm_dbg("Bound device %s to %s\n", dev->name, parent->name);
 	*devp = dev;
 
 	return 0;
 
+fail_child_post_bind:
+	if (drv->unbind && drv->unbind(dev)) {
+		dm_warn("unbind() method failed on dev '%s' on error path\n",
+			dev->name);
+	}
+
 fail_bind:
+	if (uclass_unbind_device(dev)) {
+		dm_warn("Failed to unbind dev '%s' on error path\n",
+			dev->name);
+	}
+fail_uclass_bind:
 	list_del(&dev->sibling_node);
+	if (dev->flags & DM_FLAG_ALLOC_PARENT_PDATA) {
+		free(dev->parent_platdata);
+		dev->parent_platdata = NULL;
+	}
+fail_alloc2:
+	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
+		free(dev->platdata);
+		dev->platdata = NULL;
+	}
+fail_alloc1:
 	free(dev);
+
 	return ret;
 }
 
@@ -137,7 +180,7 @@
 	drv = dev->driver;
 	assert(drv);
 
-	/* Allocate private data and platdata if requested */
+	/* Allocate private data if requested */
 	if (drv->priv_auto_alloc_size) {
 		dev->priv = calloc(1, drv->priv_auto_alloc_size);
 		if (!dev->priv) {
@@ -146,13 +189,6 @@
 		}
 	}
 	/* Allocate private data if requested */
-	if (dev->flags & DM_FLAG_ALLOC_PDATA) {
-		dev->platdata = calloc(1, drv->platdata_auto_alloc_size);
-		if (!dev->platdata) {
-			ret = -ENOMEM;
-			goto fail;
-		}
-	}
 	size = dev->uclass->uc_drv->per_device_auto_alloc_size;
 	if (size) {
 		dev->uclass_priv = calloc(1, size);
@@ -165,6 +201,10 @@
 	/* Ensure all parents are probed */
 	if (dev->parent) {
 		size = dev->parent->driver->per_child_auto_alloc_size;
+		if (!size) {
+			size = dev->parent->uclass->uc_drv->
+					per_child_auto_alloc_size;
+		}
 		if (size) {
 			dev->parent_priv = calloc(1, size);
 			if (!dev->parent_priv) {
@@ -187,6 +227,10 @@
 	}
 	dev->seq = seq;
 
+	ret = uclass_pre_probe_child(dev);
+	if (ret)
+		goto fail;
+
 	if (dev->parent && dev->parent->driver->child_pre_probe) {
 		ret = dev->parent->driver->child_pre_probe(dev);
 		if (ret)
@@ -241,6 +285,16 @@
 	return dev->platdata;
 }
 
+void *dev_get_parent_platdata(struct udevice *dev)
+{
+	if (!dev) {
+		dm_warn("%s: null device", __func__);
+		return NULL;
+	}
+
+	return dev->parent_platdata;
+}
+
 void *dev_get_priv(struct udevice *dev)
 {
 	if (!dev) {
@@ -390,3 +444,8 @@
 {
 	return dev->of_id->data;
 }
+
+enum uclass_id device_get_uclass_id(struct udevice *dev)
+{
+	return dev->uclass->uc_drv->id;
+}
diff --git a/drivers/core/root.c b/drivers/core/root.c
index 47b3acf..73e3c72 100644
--- a/drivers/core/root.c
+++ b/drivers/core/root.c
@@ -9,6 +9,7 @@
 
 #include <common.h>
 #include <errno.h>
+#include <fdtdec.h>
 #include <malloc.h>
 #include <libfdt.h>
 #include <dm/device.h>
@@ -49,6 +50,9 @@
 	ret = device_bind_by_name(NULL, false, &root_info, &DM_ROOT_NON_CONST);
 	if (ret)
 		return ret;
+#ifdef CONFIG_OF_CONTROL
+	DM_ROOT_NON_CONST->of_offset = 0;
+#endif
 	ret = device_probe(DM_ROOT_NON_CONST);
 	if (ret)
 		return ret;
@@ -89,6 +93,10 @@
 		if (pre_reloc_only &&
 		    !fdt_getprop(blob, offset, "u-boot,dm-pre-reloc", NULL))
 			continue;
+		if (!fdtdec_get_is_enabled(blob, offset)) {
+			dm_dbg("   - ignoring disabled device\n");
+			continue;
+		}
 		err = lists_bind_fdt(parent, blob, offset, NULL);
 		if (err && !ret)
 			ret = err;
diff --git a/drivers/core/uclass.c b/drivers/core/uclass.c
index 901b06e..289a5d2 100644
--- a/drivers/core/uclass.c
+++ b/drivers/core/uclass.c
@@ -319,18 +319,29 @@
 	int ret;
 
 	uc = dev->uclass;
-
 	list_add_tail(&dev->uclass_node, &uc->dev_head);
 
+	if (dev->parent) {
+		struct uclass_driver *uc_drv = dev->parent->uclass->uc_drv;
+
+		if (uc_drv->child_post_bind) {
+			ret = uc_drv->child_post_bind(dev);
+			if (ret)
+				goto err;
+		}
+	}
 	if (uc->uc_drv->post_bind) {
 		ret = uc->uc_drv->post_bind(dev);
-		if (ret) {
-			list_del(&dev->uclass_node);
-			return ret;
-		}
+		if (ret)
+			goto err;
 	}
 
 	return 0;
+err:
+	/* There is no need to undo the parent's post_bind call */
+	list_del(&dev->uclass_node);
+
+	return ret;
 }
 
 int uclass_unbind_device(struct udevice *dev)
@@ -380,6 +391,19 @@
 	return seq;
 }
 
+int uclass_pre_probe_child(struct udevice *dev)
+{
+	struct uclass_driver *uc_drv;
+
+	if (!dev->parent)
+		return 0;
+	uc_drv = dev->parent->uclass->uc_drv;
+	if (uc_drv->child_pre_probe)
+		return uc_drv->child_pre_probe(dev);
+
+	return 0;
+}
+
 int uclass_post_probe_device(struct udevice *dev)
 {
 	struct uclass_driver *uc_drv = dev->uclass->uc_drv;
diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
index e69de29..bd26a2b 100644
--- a/drivers/crypto/Kconfig
+++ b/drivers/crypto/Kconfig
@@ -0,0 +1 @@
+source drivers/crypto/fsl/Kconfig
diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
index 7b79237..fb8c10b 100644
--- a/drivers/crypto/Makefile
+++ b/drivers/crypto/Makefile
@@ -6,4 +6,5 @@
 #
 
 obj-$(CONFIG_EXYNOS_ACE_SHA)	+= ace_sha.o
+obj-y += rsa_mod_exp/
 obj-y += fsl/
diff --git a/drivers/crypto/fsl/Kconfig b/drivers/crypto/fsl/Kconfig
new file mode 100644
index 0000000..86b2f2f
--- /dev/null
+++ b/drivers/crypto/fsl/Kconfig
@@ -0,0 +1,6 @@
+config FSL_CAAM
+	bool "Freescale Crypto Driver Support"
+	help
+	  Enables the Freescale's Cryptographic Accelerator and Assurance
+	  Module (CAAM), also known as the SEC version 4 (SEC4). The driver uses
+	  Job Ring as interface to communicate with CAAM.
diff --git a/drivers/crypto/fsl/Makefile b/drivers/crypto/fsl/Makefile
index 067d0a9..c0cf642 100644
--- a/drivers/crypto/fsl/Makefile
+++ b/drivers/crypto/fsl/Makefile
@@ -9,3 +9,4 @@
 obj-y += sec.o
 obj-$(CONFIG_FSL_CAAM) += jr.o fsl_hash.o jobdesc.o error.o
 obj-$(CONFIG_CMD_BLOB) += fsl_blob.o
+obj-$(CONFIG_RSA_FREESCALE_EXP) += fsl_rsa.o
diff --git a/drivers/crypto/fsl/fsl_rsa.c b/drivers/crypto/fsl/fsl_rsa.c
new file mode 100644
index 0000000..cf1c4c1
--- /dev/null
+++ b/drivers/crypto/fsl/fsl_rsa.c
@@ -0,0 +1,60 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <asm/types.h>
+#include <malloc.h>
+#include "jobdesc.h"
+#include "desc.h"
+#include "jr.h"
+#include "rsa_caam.h"
+#include <u-boot/rsa-mod-exp.h>
+
+int fsl_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *prop, uint8_t *out)
+{
+	uint32_t keylen;
+	struct pk_in_params pkin;
+	uint32_t desc[MAX_CAAM_DESCSIZE];
+	int ret;
+
+	/* Length in bytes */
+	keylen = prop->num_bits / 8;
+
+	pkin.a = sig;
+	pkin.a_siz = sig_len;
+	pkin.n = prop->modulus;
+	pkin.n_siz = keylen;
+	pkin.e = prop->public_exponent;
+	pkin.e_siz = prop->exp_len;
+
+	inline_cnstr_jobdesc_pkha_rsaexp(desc, &pkin, out, sig_len);
+
+	ret = run_descriptor_jr(desc);
+	if (ret) {
+		debug("%s: RSA failed to verify: %d\n", __func__, ret);
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+static const struct mod_exp_ops fsl_mod_exp_ops = {
+	.mod_exp	= fsl_mod_exp,
+};
+
+U_BOOT_DRIVER(fsl_rsa_mod_exp) = {
+	.name	= "fsl_rsa_mod_exp",
+	.id	= UCLASS_MOD_EXP,
+	.ops	= &fsl_mod_exp_ops,
+};
+
+U_BOOT_DEVICE(fsl_rsa) = {
+	.name = "fsl_rsa_mod_exp",
+};
diff --git a/drivers/crypto/fsl/jobdesc.c b/drivers/crypto/fsl/jobdesc.c
index 1386bae..cc0dced 100644
--- a/drivers/crypto/fsl/jobdesc.c
+++ b/drivers/crypto/fsl/jobdesc.c
@@ -11,6 +11,7 @@
 #include <common.h>
 #include "desc_constr.h"
 #include "jobdesc.h"
+#include "rsa_caam.h"
 
 #define KEY_BLOB_SIZE			32
 #define MAC_SIZE			16
@@ -123,3 +124,30 @@
 	append_operation(desc, OP_TYPE_CLASS1_ALG | OP_ALG_ALGSEL_RNG |
 			 OP_ALG_RNG4_SK);
 }
+
+/* Change key size to bytes form bits in calling function*/
+void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+				      struct pk_in_params *pkin, uint8_t *out,
+				      uint32_t out_siz)
+{
+	dma_addr_t dma_addr_e, dma_addr_a, dma_addr_n, dma_addr_out;
+
+	dma_addr_e = virt_to_phys((void *)pkin->e);
+	dma_addr_a = virt_to_phys((void *)pkin->a);
+	dma_addr_n = virt_to_phys((void *)pkin->n);
+	dma_addr_out = virt_to_phys((void *)out);
+
+	init_job_desc(desc, 0);
+	append_key(desc, dma_addr_e, pkin->e_siz, KEY_DEST_PKHA_E | CLASS_1);
+
+	append_fifo_load(desc, dma_addr_a,
+			 pkin->a_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_A);
+
+	append_fifo_load(desc, dma_addr_n,
+			 pkin->n_siz, LDST_CLASS_1_CCB | FIFOLD_TYPE_PK_N);
+
+	append_operation(desc, OP_TYPE_PK | OP_ALG_PK | OP_ALG_PKMODE_MOD_EXPO);
+
+	append_fifo_store(desc, dma_addr_out, out_siz,
+			  LDST_CLASS_1_CCB | FIFOST_TYPE_PKHA_B);
+}
diff --git a/drivers/crypto/fsl/jobdesc.h b/drivers/crypto/fsl/jobdesc.h
index 3cf7226..84b3edd 100644
--- a/drivers/crypto/fsl/jobdesc.h
+++ b/drivers/crypto/fsl/jobdesc.h
@@ -10,6 +10,7 @@
 
 #include <common.h>
 #include <asm/io.h>
+#include "rsa_caam.h"
 
 #define KEY_IDNFR_SZ_BYTES		16
 
@@ -26,4 +27,8 @@
 				     uint32_t out_sz);
 
 void inline_cnstr_jobdesc_rng_instantiation(uint32_t *desc);
+
+void inline_cnstr_jobdesc_pkha_rsaexp(uint32_t *desc,
+				      struct pk_in_params *pkin, uint8_t *out,
+				      uint32_t out_siz);
 #endif
diff --git a/drivers/crypto/fsl/rsa_caam.h b/drivers/crypto/fsl/rsa_caam.h
new file mode 100644
index 0000000..4ff87ef
--- /dev/null
+++ b/drivers/crypto/fsl/rsa_caam.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2014 Freescale Semiconductor, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef __RSA_CAAM_H
+#define __RSA_CAAM_H
+
+#include <common.h>
+
+/**
+ * struct pk_in_params - holder for input to PKHA block in CAAM
+ * These parameters are required to perform Modular Exponentiation
+ * using PKHA Block in CAAM
+ */
+struct pk_in_params {
+	const uint8_t *e;	/* public exponent as byte array */
+	uint32_t e_siz;		/* size of e[] in number of bytes */
+	const uint8_t *n;	/* modulus as byte array */
+	uint32_t n_siz;		/* size of n[] in number of bytes */
+	const uint8_t *a;		/* Signature as byte array */
+	uint32_t a_siz;		/* size of a[] in number of bytes */
+	uint8_t *b;		/* Result exp. modulus in number of bytes */
+	uint32_t b_siz;		/* size of b[] in number of bytes */
+};
+
+#endif
diff --git a/drivers/crypto/rsa_mod_exp/Kconfig b/drivers/crypto/rsa_mod_exp/Kconfig
new file mode 100644
index 0000000..6dcb39a
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/Kconfig
@@ -0,0 +1,5 @@
+config DM_MOD_EXP
+	bool "Enable Driver Model for RSA Modular Exponentiation"
+	depends on DM
+	help
+	  If you want to use driver model for RSA Modular Exponentiation, say Y.
diff --git a/drivers/crypto/rsa_mod_exp/Makefile b/drivers/crypto/rsa_mod_exp/Makefile
new file mode 100644
index 0000000..915b751
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/Makefile
@@ -0,0 +1,7 @@
+#
+# (C) Copyright 2014 Freescale Semiconductor, Inc.
+#
+# SPDX-License-Identifier:	GPL-2.0+
+#
+
+obj-$(CONFIG_RSA) += mod_exp_uclass.o mod_exp_sw.o
diff --git a/drivers/crypto/rsa_mod_exp/mod_exp_sw.c b/drivers/crypto/rsa_mod_exp/mod_exp_sw.c
new file mode 100644
index 0000000..dc6c064
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/mod_exp_sw.c
@@ -0,0 +1,39 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc.
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <config.h>
+#include <common.h>
+#include <dm.h>
+#include <u-boot/rsa-mod-exp.h>
+
+int mod_exp_sw(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *prop, uint8_t *out)
+{
+	int ret = 0;
+
+	ret = rsa_mod_exp_sw(sig, sig_len, prop, out);
+	if (ret) {
+		debug("%s: RSA failed to verify: %d\n", __func__, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct mod_exp_ops mod_exp_ops_sw = {
+	.mod_exp	= mod_exp_sw,
+};
+
+U_BOOT_DRIVER(mod_exp_sw) = {
+	.name	= "mod_exp_sw",
+	.id	= UCLASS_MOD_EXP,
+	.ops	= &mod_exp_ops_sw,
+};
+
+U_BOOT_DEVICE(mod_exp_sw) = {
+	.name = "mod_exp_sw",
+};
diff --git a/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c b/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
new file mode 100644
index 0000000..266f094
--- /dev/null
+++ b/drivers/crypto/rsa_mod_exp/mod_exp_uclass.c
@@ -0,0 +1,31 @@
+/*
+ * (C) Copyright 2014 Freescale Semiconductor, Inc
+ * Author: Ruchika Gupta <ruchika.gupta@freescale.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <u-boot/rsa-mod-exp.h>
+#include <errno.h>
+#include <fdtdec.h>
+#include <malloc.h>
+#include <asm/io.h>
+#include <linux/list.h>
+
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *node, uint8_t *out)
+{
+	const struct mod_exp_ops *ops = device_get_ops(dev);
+
+	if (!ops->mod_exp)
+		return -ENOSYS;
+
+	return ops->mod_exp(dev, sig, sig_len, node, out);
+}
+
+UCLASS_DRIVER(mod_exp) = {
+	.id		= UCLASS_MOD_EXP,
+	.name		= "rsa_mod_exp",
+};
diff --git a/drivers/demo/demo-shape.c b/drivers/demo/demo-shape.c
index 3fa9c59..d908736 100644
--- a/drivers/demo/demo-shape.c
+++ b/drivers/demo/demo-shape.c
@@ -11,6 +11,7 @@
 #include <malloc.h>
 #include <dm-demo.h>
 #include <asm/io.h>
+#include <asm/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -20,6 +21,8 @@
 
 struct shape_data {
 	int num_chars;	/* Number of non-space characters output so far */
+	struct gpio_desc gpio_desc[8];
+	int gpio_count;
 };
 
 /* Crazy little function to draw shapes on the console */
@@ -89,9 +92,52 @@
 	return 0;
 }
 
+static int set_light(struct udevice *dev, int light)
+{
+	struct shape_data *priv = dev_get_priv(dev);
+	struct gpio_desc *desc;
+	int ret;
+	int i;
+
+	desc = priv->gpio_desc;
+	for (i = 0; i < priv->gpio_count; i++, desc++) {
+		uint mask = 1 << i;
+
+		ret = dm_gpio_set_value(desc, light & mask);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
+static int get_light(struct udevice *dev)
+{
+	struct shape_data *priv = dev_get_priv(dev);
+	struct gpio_desc *desc;
+	uint value = 0;
+	int ret;
+	int i;
+
+	desc = priv->gpio_desc;
+	for (i = 0; i < priv->gpio_count; i++, desc++) {
+		uint mask = 1 << i;
+
+		ret = dm_gpio_get_value(desc);
+		if (ret < 0)
+			return ret;
+		if (ret)
+			value |= mask;
+	}
+
+	return value;
+}
+
 static const struct demo_ops shape_ops = {
 	.hello = shape_hello,
 	.status = shape_status,
+	.get_light = get_light,
+	.set_light = set_light,
 };
 
 static int shape_ofdata_to_platdata(struct udevice *dev)
@@ -111,6 +157,29 @@
 	return 0;
 }
 
+static int dm_shape_probe(struct udevice *dev)
+{
+	struct shape_data *priv = dev_get_priv(dev);
+	int ret;
+
+	ret = gpio_request_list_by_name(dev, "light-gpios", priv->gpio_desc,
+					ARRAY_SIZE(priv->gpio_desc),
+					GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	if (ret < 0)
+		return ret;
+	priv->gpio_count = ret;
+	debug("%s: %d GPIOs\n", __func__, priv->gpio_count);
+
+	return 0;
+}
+
+static int dm_shape_remove(struct udevice *dev)
+{
+	struct shape_data *priv = dev_get_priv(dev);
+
+	return gpio_free_list(dev, priv->gpio_desc, priv->gpio_count);
+}
+
 static const struct udevice_id demo_shape_id[] = {
 	{ "demo-shape", 0 },
 	{ },
@@ -122,6 +191,8 @@
 	.id	= UCLASS_DEMO,
 	.ofdata_to_platdata = shape_ofdata_to_platdata,
 	.ops	= &shape_ops,
+	.probe = dm_shape_probe,
+	.remove = dm_shape_remove,
 	.priv_auto_alloc_size = sizeof(struct shape_data),
 	.platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
 };
diff --git a/drivers/demo/demo-uclass.c b/drivers/demo/demo-uclass.c
index f6510d6..725f068 100644
--- a/drivers/demo/demo-uclass.c
+++ b/drivers/demo/demo-uclass.c
@@ -43,6 +43,26 @@
 	return ops->status(dev, status);
 }
 
+int demo_get_light(struct udevice *dev)
+{
+	const struct demo_ops *ops = device_get_ops(dev);
+
+	if (!ops->get_light)
+		return -ENOSYS;
+
+	return ops->get_light(dev);
+}
+
+int demo_set_light(struct udevice *dev, int light)
+{
+	const struct demo_ops *ops = device_get_ops(dev);
+
+	if (!ops->set_light)
+		return -ENOSYS;
+
+	return ops->set_light(dev, light);
+}
+
 int demo_parse_dt(struct udevice *dev)
 {
 	struct dm_demo_pdata *pdata = dev_get_platdata(dev);
diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c
index 255700a..a69bbd2 100644
--- a/drivers/gpio/gpio-uclass.c
+++ b/drivers/gpio/gpio-uclass.c
@@ -7,20 +7,25 @@
 #include <common.h>
 #include <dm.h>
 #include <errno.h>
+#include <fdtdec.h>
 #include <malloc.h>
 #include <asm/gpio.h>
 #include <linux/ctype.h>
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /**
  * gpio_to_device() - Convert global GPIO number to device, number
- * gpio:	The numeric representation of the GPIO
  *
  * Convert the GPIO number to an entry in the list of GPIOs
  * or GPIO blocks registered with the GPIO controller. Returns
  * entry on success, NULL on error.
+ *
+ * @gpio:	The numeric representation of the GPIO
+ * @desc:	Returns description (desc->flags will always be 0)
+ * @return 0 if found, -ENOENT if not found
  */
-static int gpio_to_device(unsigned int gpio, struct udevice **devp,
-			  unsigned int *offset)
+static int gpio_to_device(unsigned int gpio, struct gpio_desc *desc)
 {
 	struct gpio_dev_priv *uc_priv;
 	struct udevice *dev;
@@ -32,14 +37,15 @@
 		uc_priv = dev->uclass_priv;
 		if (gpio >= uc_priv->gpio_base &&
 		    gpio < uc_priv->gpio_base + uc_priv->gpio_count) {
-			*devp = dev;
-			*offset = gpio - uc_priv->gpio_base;
+			desc->dev = dev;
+			desc->offset = gpio - uc_priv->gpio_base;
+			desc->flags = 0;
 			return 0;
 		}
 	}
 
 	/* No such GPIO */
-	return ret ? ret : -EINVAL;
+	return ret ? ret : -ENOENT;
 }
 
 int gpio_lookup_name(const char *name, struct udevice **devp,
@@ -88,6 +94,57 @@
 	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];
+	else
+		desc->offset = -1;
+	desc->flags = 0;
+
+	return ops->xlate ? ops->xlate(desc->dev, desc, args) : 0;
+}
+
+static int dm_gpio_request(struct gpio_desc *desc, const char *label)
+{
+	struct udevice *dev = desc->dev;
+	struct gpio_dev_priv *uc_priv;
+	char *str;
+	int ret;
+
+	uc_priv = dev->uclass_priv;
+	if (uc_priv->name[desc->offset])
+		return -EBUSY;
+	str = strdup(label);
+	if (!str)
+		return -ENOMEM;
+	if (gpio_get_ops(dev)->request) {
+		ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
+		if (ret) {
+			free(str);
+			return ret;
+		}
+	}
+	uc_priv->name[desc->offset] = str;
+
+	return 0;
+}
+
+static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
+{
+	va_list args;
+	char buf[40];
+
+	va_start(args, fmt);
+	vscnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+	return dm_gpio_request(desc, buf);
+}
+
 /**
  * gpio_request() - [COMPAT] Request GPIO
  * gpio:	GPIO number
@@ -102,32 +159,14 @@
  */
 int gpio_request(unsigned gpio, const char *label)
 {
-	struct gpio_dev_priv *uc_priv;
-	unsigned int offset;
-	struct udevice *dev;
-	char *str;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
 
-	uc_priv = dev->uclass_priv;
-	if (uc_priv->name[offset])
-		return -EBUSY;
-	str = strdup(label);
-	if (!str)
-		return -ENOMEM;
-	if (gpio_get_ops(dev)->request) {
-		ret = gpio_get_ops(dev)->request(dev, offset, label);
-		if (ret) {
-			free(str);
-			return ret;
-		}
-	}
-	uc_priv->name[offset] = str;
-
-	return 0;
+	return dm_gpio_request(&desc, label);
 }
 
 /**
@@ -151,25 +190,11 @@
 	return gpio_request(gpio, buf);
 }
 
-/**
- * gpio_free() - [COMPAT] Relinquish GPIO
- * gpio:	GPIO number
- *
- * This function implements the API that's compatible with current
- * GPIO API used in U-Boot. The request is forwarded to particular
- * GPIO driver. Returns 0 on success, negative value on error.
- */
-int gpio_free(unsigned gpio)
+int _dm_gpio_free(struct udevice *dev, uint offset)
 {
 	struct gpio_dev_priv *uc_priv;
-	unsigned int offset;
-	struct udevice *dev;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
-	if (ret)
-		return ret;
-
 	uc_priv = dev->uclass_priv;
 	if (!uc_priv->name[offset])
 		return -ENXIO;
@@ -185,15 +210,35 @@
 	return 0;
 }
 
-static int check_reserved(struct udevice *dev, unsigned offset,
-			  const char *func)
+/**
+ * gpio_free() - [COMPAT] Relinquish GPIO
+ * gpio:	GPIO number
+ *
+ * This function implements the API that's compatible with current
+ * GPIO API used in U-Boot. The request is forwarded to particular
+ * GPIO driver. Returns 0 on success, negative value on error.
+ */
+int gpio_free(unsigned gpio)
 {
-	struct gpio_dev_priv *uc_priv = dev->uclass_priv;
+	struct gpio_desc desc;
+	int ret;
 
-	if (!uc_priv->name[offset]) {
+	ret = gpio_to_device(gpio, &desc);
+	if (ret)
+		return ret;
+
+	return _dm_gpio_free(desc.dev, desc.offset);
+}
+
+static int check_reserved(struct gpio_desc *desc, const char *func)
+{
+	struct gpio_dev_priv *uc_priv = desc->dev->uclass_priv;
+
+	if (!uc_priv->name[desc->offset]) {
 		printf("%s: %s: error: gpio %s%d not reserved\n",
-		       dev->name, func,
-		       uc_priv->bank_name ? uc_priv->bank_name : "", offset);
+		       desc->dev->name, func,
+		       uc_priv->bank_name ? uc_priv->bank_name : "",
+		       desc->offset);
 		return -EBUSY;
 	}
 
@@ -210,16 +255,17 @@
  */
 int gpio_direction_input(unsigned gpio)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "dir_input");
+	ret = check_reserved(&desc, "dir_input");
+	if (ret)
+		return ret;
 
-	return ret ? ret : gpio_get_ops(dev)->direction_input(dev, offset);
+	return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
 }
 
 /**
@@ -233,17 +279,81 @@
  */
 int gpio_direction_output(unsigned gpio, int value)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "dir_output");
+	ret = check_reserved(&desc, "dir_output");
+	if (ret)
+		return ret;
 
-	return ret ? ret :
-		gpio_get_ops(dev)->direction_output(dev, offset, value);
+	return gpio_get_ops(desc.dev)->direction_output(desc.dev,
+							desc.offset, value);
+}
+
+int dm_gpio_get_value(struct gpio_desc *desc)
+{
+	int value;
+	int ret;
+
+	ret = check_reserved(desc, "get_value");
+	if (ret)
+		return ret;
+
+	value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
+
+	return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
+}
+
+int dm_gpio_set_value(struct gpio_desc *desc, int value)
+{
+	int ret;
+
+	ret = check_reserved(desc, "set_value");
+	if (ret)
+		return ret;
+
+	if (desc->flags & GPIOD_ACTIVE_LOW)
+		value = !value;
+	gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
+	return 0;
+}
+
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
+{
+	struct udevice *dev = desc->dev;
+	struct dm_gpio_ops *ops = gpio_get_ops(dev);
+	int ret;
+
+	ret = check_reserved(desc, "set_dir");
+	if (ret)
+		return ret;
+
+	if (flags & GPIOD_IS_OUT) {
+		int value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
+
+		if (flags & GPIOD_ACTIVE_LOW)
+			value = !value;
+		ret = ops->direction_output(dev, desc->offset, value);
+	} else  if (flags & GPIOD_IS_IN) {
+		ret = ops->direction_input(dev, desc->offset);
+	}
+	if (ret)
+		return ret;
+	/*
+	 * Update desc->flags here, so that GPIO_ACTIVE_LOW is honoured in
+	 * futures
+	 */
+	desc->flags = flags;
+
+	return 0;
+}
+
+int dm_gpio_set_dir(struct gpio_desc *desc)
+{
+	return dm_gpio_set_dir_flags(desc, desc->flags);
 }
 
 /**
@@ -257,16 +367,14 @@
  */
 int gpio_get_value(unsigned gpio)
 {
-	unsigned int offset;
-	struct udevice *dev;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	struct gpio_desc desc;
+
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "get_value");
-
-	return ret ? ret : gpio_get_ops(dev)->get_value(dev, offset);
+	return dm_gpio_get_value(&desc);
 }
 
 /**
@@ -280,16 +388,13 @@
  */
 int gpio_set_value(unsigned gpio, int value)
 {
-	unsigned int offset;
-	struct udevice *dev;
+	struct gpio_desc desc;
 	int ret;
 
-	ret = gpio_to_device(gpio, &dev, &offset);
+	ret = gpio_to_device(gpio, &desc);
 	if (ret)
 		return ret;
-	ret = check_reserved(dev, offset, "set_value");
-
-	return ret ? ret : gpio_get_ops(dev)->set_value(dev, offset, value);
+	return dm_gpio_set_value(&desc, value);
 }
 
 const char *gpio_get_bank_info(struct udevice *dev, int *bit_count)
@@ -409,6 +514,155 @@
 	return vector;
 }
 
+static int _gpio_request_by_name_nodev(const void *blob, int node,
+				       const char *list_name, int index,
+				       struct gpio_desc *desc, int flags,
+				       bool add_index)
+{
+	struct fdtdec_phandle_args args;
+	int ret;
+
+	desc->dev = NULL;
+	desc->offset = 0;
+	ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
+					     "#gpio-cells", 0, index, &args);
+	if (ret) {
+		debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__);
+		goto err;
+	}
+
+	ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node,
+					     &desc->dev);
+	if (ret) {
+		debug("%s: uclass_get_device_by_of_offset failed\n", __func__);
+		goto err;
+	}
+	ret = gpio_find_and_xlate(desc, &args);
+	if (ret) {
+		debug("%s: gpio_find_and_xlate failed\n", __func__);
+		goto err;
+	}
+	ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
+			       fdt_get_name(blob, node, NULL),
+			       list_name, index);
+	if (ret) {
+		debug("%s: dm_gpio_requestf failed\n", __func__);
+		goto err;
+	}
+	ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
+	if (ret) {
+		debug("%s: dm_gpio_set_dir failed\n", __func__);
+		goto err;
+	}
+
+	return 0;
+err:
+	debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
+	      __func__, fdt_get_name(blob, node, NULL), list_name, index, ret);
+	return ret;
+}
+
+int gpio_request_by_name_nodev(const void *blob, int node,
+			       const char *list_name, int index,
+			       struct gpio_desc *desc, int flags)
+{
+	return _gpio_request_by_name_nodev(blob, node, list_name, index, desc,
+					   flags, index > 0);
+}
+
+int gpio_request_by_name(struct udevice *dev,  const char *list_name, int index,
+			 struct gpio_desc *desc, int flags)
+{
+	/*
+	 * This isn't ideal since we don't use dev->name in the debug()
+	 * calls in gpio_request_by_name(), but we can do this until
+	 * gpio_request_by_name_nodev() can be dropped.
+	 */
+	return gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
+					  list_name, index, desc, flags);
+}
+
+int gpio_request_list_by_name_nodev(const void *blob, int node,
+				    const char *list_name,
+				    struct gpio_desc *desc, int max_count,
+				    int flags)
+{
+	int count;
+	int ret;
+
+	for (count = 0; ; count++) {
+		if (count >= max_count) {
+			ret = -ENOSPC;
+			goto err;
+		}
+		ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
+						  &desc[count], flags, true);
+		if (ret == -ENOENT)
+			break;
+		else if (ret)
+			goto err;
+	}
+
+	/* We ran out of GPIOs in the list */
+	return count;
+
+err:
+	gpio_free_list_nodev(desc, count - 1);
+
+	return ret;
+}
+
+int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
+			      struct gpio_desc *desc, int max_count,
+			      int flags)
+{
+	/*
+	 * This isn't ideal since we don't use dev->name in the debug()
+	 * calls in gpio_request_by_name(), but we can do this until
+	 * gpio_request_list_by_name_nodev() can be dropped.
+	 */
+	return gpio_request_list_by_name_nodev(gd->fdt_blob, dev->of_offset,
+					       list_name, desc, max_count,
+					       flags);
+}
+
+int gpio_get_list_count(struct udevice *dev, const char *list_name)
+{
+	int ret;
+
+	ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
+					     list_name, "#gpio-cells", 0, -1,
+					     NULL);
+	if (ret) {
+		debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
+		      __func__, dev->name, list_name, ret);
+	}
+
+	return ret;
+}
+
+int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
+{
+	/* For now, we don't do any checking of dev */
+	return _dm_gpio_free(desc->dev, desc->offset);
+}
+
+int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
+{
+	int i;
+
+	/* For now, we don't do any checking of dev */
+	for (i = 0; i < count; i++)
+		dm_gpio_free(dev, &desc[i]);
+
+	return 0;
+}
+
+int gpio_free_list_nodev(struct gpio_desc *desc, int count)
+{
+	return gpio_free_list(NULL, desc, count);
+}
+
 /* We need to renumber the GPIOs when any driver is probed/removed */
 static int gpio_renumber(struct udevice *removed_dev)
 {
diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
index 6c41a42..0a245ba 100644
--- a/drivers/gpio/s5p_gpio.c
+++ b/drivers/gpio/s5p_gpio.c
@@ -13,6 +13,7 @@
 #include <asm/io.h>
 #include <asm/gpio.h>
 #include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -275,12 +276,22 @@
 		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)
@@ -342,7 +353,7 @@
 					plat->bank_name, plat, -1, &dev);
 		if (ret)
 			return ret;
-		dev->of_offset = parent->of_offset;
+		dev->of_offset = node;
 	}
 
 	return 0;
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index 53c80d5..d564c25 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -8,6 +8,7 @@
 #include <fdtdec.h>
 #include <malloc.h>
 #include <asm/gpio.h>
+#include <dt-bindings/gpio/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -130,12 +131,31 @@
 	return GPIOF_INPUT;
 }
 
+static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+			 struct fdtdec_phandle_args *args)
+{
+	desc->offset = args->args[0];
+	if (args->args_count < 2)
+		return 0;
+	if (args->args[1] & GPIO_ACTIVE_LOW)
+		desc->flags |= GPIOD_ACTIVE_LOW;
+	if (args->args[1] & 2)
+		desc->flags |= GPIOD_IS_IN;
+	if (args->args[1] & 4)
+		desc->flags |= GPIOD_IS_OUT;
+	if (args->args[1] & 8)
+		desc->flags |= GPIOD_IS_OUT_ACTIVE;
+
+	return 0;
+}
+
 static const struct dm_gpio_ops gpio_sandbox_ops = {
 	.direction_input	= sb_gpio_direction_input,
 	.direction_output	= sb_gpio_direction_output,
 	.get_value		= sb_gpio_get_value,
 	.set_value		= sb_gpio_set_value,
 	.get_function		= sb_gpio_get_function,
+	.xlate			= sb_gpio_xlate,
 };
 
 static int sandbox_gpio_ofdata_to_platdata(struct udevice *dev)
diff --git a/drivers/gpio/tegra_gpio.c b/drivers/gpio/tegra_gpio.c
index 88f7ef5..43928b8 100644
--- a/drivers/gpio/tegra_gpio.c
+++ b/drivers/gpio/tegra_gpio.c
@@ -21,6 +21,7 @@
 #include <asm/arch/tegra.h>
 #include <asm/gpio.h>
 #include <dm/device-internal.h>
+#include <dt-bindings/gpio/gpio.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
@@ -251,6 +252,22 @@
 		return GPIOF_INPUT;
 }
 
+static int tegra_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
+			    struct fdtdec_phandle_args *args)
+{
+	int gpio, port, ret;
+
+	gpio = args->args[0];
+	port = gpio / TEGRA_GPIOS_PER_PORT;
+	ret = device_get_child(dev, port, &desc->dev);
+	if (ret)
+		return ret;
+	desc->offset = gpio % TEGRA_GPIOS_PER_PORT;
+	desc->flags = args->args[1] & GPIO_ACTIVE_LOW ? GPIOD_ACTIVE_LOW : 0;
+
+	return 0;
+}
+
 static const struct dm_gpio_ops gpio_tegra_ops = {
 	.request		= tegra_gpio_request,
 	.direction_input	= tegra_gpio_direction_input,
@@ -258,6 +275,7 @@
 	.get_value		= tegra_gpio_get_value,
 	.set_value		= tegra_gpio_set_value,
 	.get_function		= tegra_gpio_get_function,
+	.xlate			= tegra_gpio_xlate,
 };
 
 /**
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index e69de29..202ea5d 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -0,0 +1,22 @@
+config DM_I2C
+	bool "Enable Driver Model for I2C drivers"
+	depends on DM
+	help
+	  If you want to use driver model for I2C drivers, say Y.
+	  To use legacy I2C drivers, say N.
+
+config SYS_I2C_UNIPHIER
+	bool "UniPhier I2C driver"
+	depends on ARCH_UNIPHIER && DM_I2C
+	default y
+	help
+	  Support for Panasonic UniPhier I2C controller driver.  This I2C
+	  controller is used on PH1-LD4, PH1-sLD8 or older UniPhier SoCs.
+
+config SYS_I2C_UNIPHIER_F
+	bool "UniPhier FIFO-builtin I2C driver"
+	depends on ARCH_UNIPHIER && DM_I2C
+	default y
+	help
+	  Support for Panasonic UniPhier FIFO-builtin I2C controller driver.
+	  This I2C controller is used on PH1-Pro4 or newer UniPhier SoCs.
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index 6f3c86c..774bc94 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -5,6 +5,7 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 obj-$(CONFIG_DM_I2C) += i2c-uclass.o
+obj-$(CONFIG_DM_I2C_COMPAT) += i2c-uclass-compat.o
 
 obj-$(CONFIG_SYS_I2C_ADI) += adi_i2c.o
 obj-$(CONFIG_I2C_MV) += mv_i2c.o
@@ -31,4 +32,6 @@
 obj-$(CONFIG_SYS_I2C_SH) += sh_i2c.o
 obj-$(CONFIG_SYS_I2C_SOFT) += soft_i2c.o
 obj-$(CONFIG_SYS_I2C_TEGRA) += tegra_i2c.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER) += i2c-uniphier.o
+obj-$(CONFIG_SYS_I2C_UNIPHIER_F) += i2c-uniphier-f.o
 obj-$(CONFIG_SYS_I2C_ZYNQ) += zynq_i2c.o
diff --git a/drivers/i2c/i2c-uclass-compat.c b/drivers/i2c/i2c-uclass-compat.c
new file mode 100644
index 0000000..223f238
--- /dev/null
+++ b/drivers/i2c/i2c-uclass-compat.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2014 Google, Inc
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <i2c.h>
+
+static int cur_busnum;
+
+static int i2c_compat_get_device(uint chip_addr, int alen,
+				 struct udevice **devp)
+{
+	struct dm_i2c_chip *chip;
+	int ret;
+
+	ret = i2c_get_chip_for_busnum(cur_busnum, chip_addr, alen, devp);
+	if (ret)
+		return ret;
+	chip = dev_get_parent_platdata(*devp);
+	if (chip->offset_len != alen) {
+		printf("I2C chip %x: requested alen %d does not match chip offset_len %d\n",
+		       chip_addr, alen, chip->offset_len);
+		return -EADDRNOTAVAIL;
+	}
+
+	return 0;
+}
+
+int i2c_probe(uint8_t chip_addr)
+{
+	struct udevice *bus, *dev;
+	int ret;
+
+	ret = uclass_get_device_by_seq(UCLASS_I2C, cur_busnum, &bus);
+	if (ret) {
+		debug("Cannot find I2C bus %d: err=%d\n", cur_busnum, ret);
+		return ret;
+	}
+
+	if (!bus)
+		return -ENOENT;
+
+	return dm_i2c_probe(bus, chip_addr, 0, &dev);
+}
+
+int i2c_read(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+	     int len)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = i2c_compat_get_device(chip_addr, alen, &dev);
+	if (ret)
+		return ret;
+
+	return dm_i2c_read(dev, addr, buffer, len);
+}
+
+int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+	      int len)
+{
+	struct udevice *dev;
+	int ret;
+
+	ret = i2c_compat_get_device(chip_addr, alen, &dev);
+	if (ret)
+		return ret;
+
+	return dm_i2c_write(dev, addr, buffer, len);
+}
+
+int i2c_get_bus_num_fdt(int node)
+{
+	struct udevice *bus;
+	int ret;
+
+	ret = uclass_get_device_by_of_offset(UCLASS_I2C, node, &bus);
+	if (ret)
+		return ret;
+
+	return bus->seq;
+}
+
+unsigned int i2c_get_bus_num(void)
+{
+	return cur_busnum;
+}
+
+int i2c_set_bus_num(unsigned int bus)
+{
+	cur_busnum = bus;
+
+	return 0;
+}
+
+void i2c_init(int speed, int slaveaddr)
+{
+	/* Nothing to do here - the init happens through driver model */
+}
+
+void board_i2c_init(const void *blob)
+{
+	/* Nothing to do here - the init happens through driver model */
+}
diff --git a/drivers/i2c/i2c-uclass.c b/drivers/i2c/i2c-uclass.c
index 005bf86..eafa457 100644
--- a/drivers/i2c/i2c-uclass.c
+++ b/drivers/i2c/i2c-uclass.c
@@ -50,7 +50,7 @@
 static int i2c_read_bytewise(struct udevice *dev, uint offset,
 			     uint8_t *buffer, int len)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct udevice *bus = dev_get_parent(dev);
 	struct dm_i2c_ops *ops = i2c_get_ops(bus);
 	struct i2c_msg msg[2], *ptr;
@@ -79,7 +79,7 @@
 static int i2c_write_bytewise(struct udevice *dev, uint offset,
 			     const uint8_t *buffer, int len)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct udevice *bus = dev_get_parent(dev);
 	struct dm_i2c_ops *ops = i2c_get_ops(bus);
 	struct i2c_msg msg[1];
@@ -100,9 +100,9 @@
 	return 0;
 }
 
-int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
+int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct udevice *bus = dev_get_parent(dev);
 	struct dm_i2c_ops *ops = i2c_get_ops(bus);
 	struct i2c_msg msg[2], *ptr;
@@ -130,9 +130,10 @@
 	return ops->xfer(bus, msg, msg_count);
 }
 
-int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer, int len)
+int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+		 int len)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct udevice *bus = dev_get_parent(dev);
 	struct dm_i2c_ops *ops = i2c_get_ops(bus);
 	struct i2c_msg msg[1];
@@ -219,10 +220,10 @@
 	return ops->xfer(bus, msg, 1);
 }
 
-static int i2c_bind_driver(struct udevice *bus, uint chip_addr,
+static int i2c_bind_driver(struct udevice *bus, uint chip_addr, uint offset_len,
 			   struct udevice **devp)
 {
-	struct dm_i2c_chip chip;
+	struct dm_i2c_chip *chip;
 	char name[30], *str;
 	struct udevice *dev;
 	int ret;
@@ -235,11 +236,11 @@
 		goto err_bind;
 
 	/* Tell the device what we know about it */
-	memset(&chip, '\0', sizeof(chip));
-	chip.chip_addr = chip_addr;
-	chip.offset_len = 1;	/* we assume */
-	ret = device_probe_child(dev, &chip);
-	debug("%s:  device_probe_child: ret=%d\n", __func__, ret);
+	chip = dev_get_parent_platdata(dev);
+	chip->chip_addr = chip_addr;
+	chip->offset_len = offset_len;
+	ret = device_probe(dev);
+	debug("%s:  device_probe: ret=%d\n", __func__, ret);
 	if (ret)
 		goto err_probe;
 
@@ -247,13 +248,18 @@
 	return 0;
 
 err_probe:
+	/*
+	 * If the device failed to probe, unbind it. There is nothing there
+	 * on the bus so we don't want to leave it lying around
+	 */
 	device_unbind(dev);
 err_bind:
 	free(str);
 	return ret;
 }
 
-int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp)
+int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
+		 struct udevice **devp)
 {
 	struct udevice *dev;
 
@@ -261,15 +267,9 @@
 	      bus->name, chip_addr);
 	for (device_find_first_child(bus, &dev); dev;
 			device_find_next_child(&dev)) {
-		struct dm_i2c_chip store;
-		struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+		struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 		int ret;
 
-		if (!chip) {
-			chip = &store;
-			i2c_chip_ofdata_to_platdata(gd->fdt_blob,
-						    dev->of_offset, chip);
-		}
 		if (chip->chip_addr == chip_addr) {
 			ret = device_probe(dev);
 			debug("found, ret=%d\n", ret);
@@ -280,10 +280,11 @@
 		}
 	}
 	debug("not found\n");
-	return i2c_bind_driver(bus, chip_addr, devp);
+	return i2c_bind_driver(bus, chip_addr, offset_len, devp);
 }
 
-int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp)
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
+			    struct udevice **devp)
 {
 	struct udevice *bus;
 	int ret;
@@ -293,7 +294,7 @@
 		debug("Cannot find I2C bus %d\n", busnum);
 		return ret;
 	}
-	ret = i2c_get_chip(bus, chip_addr, devp);
+	ret = i2c_get_chip(bus, chip_addr, offset_len, devp);
 	if (ret) {
 		debug("Cannot find I2C chip %02x on bus %d\n", chip_addr,
 		      busnum);
@@ -303,8 +304,8 @@
 	return 0;
 }
 
-int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
-	      struct udevice **devp)
+int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+		 struct udevice **devp)
 {
 	int ret;
 
@@ -318,7 +319,7 @@
 		return ret;
 
 	/* The chip was found, see if we have a driver, and probe it */
-	ret = i2c_get_chip(bus, chip_addr, devp);
+	ret = i2c_get_chip(bus, chip_addr, 1, devp);
 	debug("%s:  i2c_get_chip: ret=%d\n", __func__, ret);
 
 	return ret;
@@ -364,7 +365,7 @@
 int i2c_set_chip_flags(struct udevice *dev, uint flags)
 {
 	struct udevice *bus = dev->parent;
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 	struct dm_i2c_ops *ops = i2c_get_ops(bus);
 	int ret;
 
@@ -380,7 +381,7 @@
 
 int i2c_get_chip_flags(struct udevice *dev, uint *flagsp)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 
 	*flagsp = chip->flags;
 
@@ -389,7 +390,7 @@
 
 int i2c_set_chip_offset_len(struct udevice *dev, uint offset_len)
 {
-	struct dm_i2c_chip *chip = dev_get_parentdata(dev);
+	struct dm_i2c_chip *chip = dev_get_parent_platdata(dev);
 
 	if (offset_len > I2C_MAX_OFFSET_LEN)
 		return -EINVAL;
@@ -419,7 +420,8 @@
 int i2c_chip_ofdata_to_platdata(const void *blob, int node,
 				struct dm_i2c_chip *chip)
 {
-	chip->offset_len = 1;	/* default */
+	chip->offset_len = fdtdec_get_int(gd->fdt_blob, node,
+					  "u-boot,i2c-offset-len", 1);
 	chip->flags = 0;
 	chip->chip_addr = fdtdec_get_int(gd->fdt_blob, node, "reg", -1);
 	if (chip->chip_addr == -1) {
@@ -441,18 +443,31 @@
 	return i2c_set_bus_speed(dev, i2c->speed_hz);
 }
 
-int i2c_post_bind(struct udevice *dev)
+static int i2c_post_bind(struct udevice *dev)
 {
 	/* Scan the bus for devices */
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
+static int i2c_child_post_bind(struct udevice *dev)
+{
+	struct dm_i2c_chip *plat = dev_get_parent_platdata(dev);
+
+	if (dev->of_offset == -1)
+		return 0;
+
+	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+}
+
 UCLASS_DRIVER(i2c) = {
 	.id		= UCLASS_I2C,
 	.name		= "i2c",
-	.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.post_bind	= i2c_post_bind,
 	.post_probe	= i2c_post_probe,
+	.per_device_auto_alloc_size = sizeof(struct dm_i2c_bus),
+	.per_child_platdata_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.child_post_bind = i2c_child_post_bind,
 };
 
 UCLASS_DRIVER(i2c_generic) = {
diff --git a/drivers/i2c/i2c-uniphier-f.c b/drivers/i2c/i2c-uniphier-f.c
new file mode 100644
index 0000000..6707edd
--- /dev/null
+++ b/drivers/i2c/i2c-uniphier-f.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *   Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uniphier_fi2c_regs {
+	u32 cr;				/* control register */
+#define I2C_CR_MST	(1 << 3)	/* master mode */
+#define I2C_CR_STA	(1 << 2)	/* start condition */
+#define I2C_CR_STO	(1 << 1)	/* stop condition */
+#define I2C_CR_NACK	(1 << 0)	/* not ACK */
+	u32 dttx;			/* send FIFO (write-only) */
+#define dtrx		dttx		/* receive FIFO (read-only) */
+#define I2C_DTTX_CMD	(1 << 8)	/* send command (slave addr) */
+#define I2C_DTTX_RD	(1 << 0)	/* read */
+	u32 __reserved;			/* no register at offset 0x08 */
+	u32 slad;			/* slave address */
+	u32 cyc;			/* clock cycle control */
+	u32 lctl;			/* clock low period control */
+	u32 ssut;			/* restart/stop setup time control */
+	u32 dsut;			/* data setup time control */
+	u32 intr;			/* interrupt status */
+	u32 ie;				/* interrupt enable */
+	u32 ic;				/* interrupt clear */
+#define I2C_INT_TE	(1 << 9)	/* TX FIFO empty */
+#define I2C_INT_RB	(1 << 4)	/* received specified bytes */
+#define I2C_INT_NA	(1 << 2)	/* no answer */
+#define I2C_INT_AL	(1 << 1)	/* arbitration lost */
+	u32 sr;				/* status register */
+#define I2C_SR_DB	(1 << 12)	/* device busy */
+#define I2C_SR_BB	(1 << 8)	/* bus busy */
+#define I2C_SR_RFF	(1 << 3)	/* Rx FIFO full */
+#define I2C_SR_RNE	(1 << 2)	/* Rx FIFO not empty */
+#define I2C_SR_TNF	(1 << 1)	/* Tx FIFO not full */
+#define I2C_SR_TFE	(1 << 0)	/* Tx FIFO empty */
+	u32 __reserved2;		/* no register at offset 0x30 */
+	u32 rst;			/* reset control */
+#define I2C_RST_TBRST	(1 << 2)	/* clear Tx FIFO */
+#define I2C_RST_RBRST	(1 << 1)	/* clear Rx FIFO */
+#define I2C_RST_RST	(1 << 0)	/* forcible bus reset */
+	u32 bm;				/* bus monitor */
+	u32 noise;			/* noise filter control */
+	u32 tbc;			/* Tx byte count setting */
+	u32 rbc;			/* Rx byte count setting */
+	u32 tbcm;			/* Tx byte count monitor */
+	u32 rbcm;			/* Rx byte count monitor */
+	u32 brst;			/* bus reset */
+#define I2C_BRST_FOEN	(1 << 1)	/* normal operation */
+#define I2C_BRST_RSCLO	(1 << 0)	/* release SCL low fixing */
+};
+
+#define FIOCLK	50000000
+
+struct uniphier_fi2c_dev {
+	struct uniphier_fi2c_regs __iomem *regs;	/* register base */
+	unsigned long fioclk;			/* internal operation clock */
+	unsigned long timeout;			/* time out (us) */
+};
+
+static int poll_status(u32 __iomem *reg, u32 flag)
+{
+	int wait = 1000000; /* 1 sec is long enough */
+
+	while (readl(reg) & flag) {
+		if (wait-- < 0)
+			return -EREMOTEIO;
+		udelay(1);
+	}
+
+	return 0;
+}
+
+static int reset_bus(struct uniphier_fi2c_regs __iomem *regs)
+{
+	int ret;
+
+	/* bus forcible reset */
+	writel(I2C_RST_RST, &regs->rst);
+	ret = poll_status(&regs->rst, I2C_RST_RST);
+	if (ret < 0)
+		debug("error: fail to reset I2C controller\n");
+
+	return ret;
+}
+
+static int check_device_busy(struct uniphier_fi2c_regs __iomem *regs)
+{
+	int ret;
+
+	ret = poll_status(&regs->sr, I2C_SR_DB);
+	if (ret < 0) {
+		debug("error: device busy too long. reset...\n");
+		ret = reset_bus(regs);
+	}
+
+	return ret;
+}
+
+static int uniphier_fi2c_probe(struct udevice *dev)
+{
+	fdt_addr_t addr;
+	fdt_size_t size;
+	struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
+	int ret;
+
+	addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg",
+				    &size);
+
+	priv->regs = map_sysmem(addr, size);
+
+	if (!priv->regs)
+		return -ENOMEM;
+
+	priv->fioclk = FIOCLK;
+
+	/* bus forcible reset */
+	ret = reset_bus(priv->regs);
+	if (ret < 0)
+		return ret;
+
+	writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &priv->regs->brst);
+
+	return 0;
+}
+
+static int uniphier_fi2c_remove(struct udevice *dev)
+{
+	struct uniphier_fi2c_dev *priv = dev_get_priv(dev);
+
+	unmap_sysmem(priv->regs);
+
+	return 0;
+}
+
+static int wait_for_irq(struct uniphier_fi2c_dev *dev, u32 flags,
+			bool *stop)
+{
+	u32 irq;
+	unsigned long wait = dev->timeout;
+	int ret = -EREMOTEIO;
+
+	do {
+		udelay(1);
+		irq = readl(&dev->regs->intr);
+	} while (!(irq & flags) && wait--);
+
+	if (wait < 0) {
+		debug("error: time out\n");
+		return ret;
+	}
+
+	if (irq & I2C_INT_AL) {
+		debug("error: arbitration lost\n");
+		*stop = false;
+		return ret;
+	}
+
+	if (irq & I2C_INT_NA) {
+		debug("error: no answer\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static int issue_stop(struct uniphier_fi2c_dev *dev, int old_ret)
+{
+	int ret;
+
+	debug("stop condition\n");
+	writel(I2C_CR_MST | I2C_CR_STO, &dev->regs->cr);
+
+	ret = poll_status(&dev->regs->sr, I2C_SR_DB);
+	if (ret < 0)
+		debug("error: device busy after operation\n");
+
+	return old_ret ? old_ret : ret;
+}
+
+static int uniphier_fi2c_transmit(struct uniphier_fi2c_dev *dev, uint addr,
+				  uint len, const u8 *buf, bool *stop)
+{
+	int ret;
+	const u32 irq_flags = I2C_INT_TE | I2C_INT_NA | I2C_INT_AL;
+	struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+	debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+	writel(I2C_DTTX_CMD | addr << 1, &regs->dttx);
+
+	writel(irq_flags, &regs->ie);
+	writel(irq_flags, &regs->ic);
+
+	debug("start condition\n");
+	writel(I2C_CR_MST | I2C_CR_STA, &regs->cr);
+
+	ret = wait_for_irq(dev, irq_flags, stop);
+	if (ret < 0)
+		goto error;
+
+	while (len--) {
+		debug("sending %x\n", *buf);
+		writel(*buf++, &regs->dttx);
+
+		writel(irq_flags, &regs->ic);
+
+		ret = wait_for_irq(dev, irq_flags, stop);
+		if (ret < 0)
+			goto error;
+	}
+
+error:
+	writel(irq_flags, &regs->ic);
+
+	if (*stop)
+		ret = issue_stop(dev, ret);
+
+	return ret;
+}
+
+static int uniphier_fi2c_receive(struct uniphier_fi2c_dev *dev, uint addr,
+				 uint len, u8 *buf, bool *stop)
+{
+	int ret = 0;
+	const u32 irq_flags = I2C_INT_RB | I2C_INT_NA | I2C_INT_AL;
+	struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+	debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+	/*
+	 * In case 'len == 0', only the slave address should be sent
+	 * for probing, which is covered by the transmit function.
+	 */
+	if (len == 0)
+		return uniphier_fi2c_transmit(dev, addr, len, buf, stop);
+
+	writel(I2C_DTTX_CMD | I2C_DTTX_RD | addr << 1, &regs->dttx);
+
+	writel(0, &regs->rbc);
+	writel(irq_flags, &regs->ie);
+	writel(irq_flags, &regs->ic);
+
+	debug("start condition\n");
+	writel(I2C_CR_MST | I2C_CR_STA | (len == 1 ? I2C_CR_NACK : 0),
+	       &regs->cr);
+
+	while (len--) {
+		ret = wait_for_irq(dev, irq_flags, stop);
+		if (ret < 0)
+			goto error;
+
+		*buf++ = readl(&regs->dtrx);
+		debug("received %x\n", *(buf - 1));
+
+		if (len == 1)
+			writel(I2C_CR_MST | I2C_CR_NACK, &regs->cr);
+
+		writel(irq_flags, &regs->ic);
+	}
+
+error:
+	writel(irq_flags, &regs->ic);
+
+	if (*stop)
+		ret = issue_stop(dev, ret);
+
+	return ret;
+}
+
+static int uniphier_fi2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+			     int nmsgs)
+{
+	int ret;
+	struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
+	bool stop;
+
+	ret = check_device_busy(dev->regs);
+	if (ret < 0)
+		return ret;
+
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		/* If next message is read, skip the stop condition */
+		stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+		if (msg->flags & I2C_M_RD)
+			ret = uniphier_fi2c_receive(dev, msg->addr, msg->len,
+						    msg->buf, &stop);
+		else
+			ret = uniphier_fi2c_transmit(dev, msg->addr, msg->len,
+						     msg->buf, &stop);
+
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
+static int uniphier_fi2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	int ret;
+	unsigned int clk_count;
+	struct uniphier_fi2c_dev *dev = dev_get_priv(bus);
+	struct uniphier_fi2c_regs __iomem *regs = dev->regs;
+
+	/* max supported frequency is 400 kHz */
+	if (speed > 400000)
+		return -EINVAL;
+
+	ret = check_device_busy(dev->regs);
+	if (ret < 0)
+		return ret;
+
+	/* make sure the bus is idle when changing the frequency */
+	writel(I2C_BRST_RSCLO, &regs->brst);
+
+	clk_count = dev->fioclk / speed;
+
+	writel(clk_count, &regs->cyc);
+	writel(clk_count / 2, &regs->lctl);
+	writel(clk_count / 2, &regs->ssut);
+	writel(clk_count / 16, &regs->dsut);
+
+	writel(I2C_BRST_FOEN | I2C_BRST_RSCLO, &regs->brst);
+
+	/*
+	 * Theoretically, each byte can be transferred in
+	 * 1000000 * 9 / speed usec.
+	 * This time out value is long enough.
+	 */
+	dev->timeout = 100000000L / speed;
+
+	return 0;
+}
+
+static const struct dm_i2c_ops uniphier_fi2c_ops = {
+	.xfer = uniphier_fi2c_xfer,
+	.set_bus_speed = uniphier_fi2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_fi2c_of_match[] = {
+	{ .compatible = "panasonic,uniphier-fi2c" },
+	{},
+};
+
+U_BOOT_DRIVER(uniphier_fi2c) = {
+	.name = "uniphier-fi2c",
+	.id = UCLASS_I2C,
+	.of_match = uniphier_fi2c_of_match,
+	.probe = uniphier_fi2c_probe,
+	.remove = uniphier_fi2c_remove,
+	.priv_auto_alloc_size = sizeof(struct uniphier_fi2c_dev),
+	.ops = &uniphier_fi2c_ops,
+};
diff --git a/drivers/i2c/i2c-uniphier.c b/drivers/i2c/i2c-uniphier.c
new file mode 100644
index 0000000..64a9ed8
--- /dev/null
+++ b/drivers/i2c/i2c-uniphier.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2014 Panasonic Corporation
+ *   Author: Masahiro Yamada <yamada.m@jp.panasonic.com>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <linux/types.h>
+#include <asm/io.h>
+#include <asm/errno.h>
+#include <dm/device.h>
+#include <dm/root.h>
+#include <i2c.h>
+#include <fdtdec.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct uniphier_i2c_regs {
+	u32 dtrm;			/* data transmission */
+#define I2C_DTRM_STA	(1 << 10)
+#define I2C_DTRM_STO	(1 << 9)
+#define I2C_DTRM_NACK	(1 << 8)
+#define I2C_DTRM_RD	(1 << 0)
+	u32 drec;			/* data reception */
+#define I2C_DREC_STS	(1 << 12)
+#define I2C_DREC_LRB	(1 << 11)
+#define I2C_DREC_LAB	(1 << 9)
+	u32 myad;			/* slave address */
+	u32 clk;			/* clock frequency control */
+	u32 brst;			/* bus reset */
+#define I2C_BRST_FOEN	(1 << 1)
+#define I2C_BRST_BRST	(1 << 0)
+	u32 hold;			/* hold time control */
+	u32 bsts;			/* bus status monitor */
+	u32 noise;			/* noise filter control */
+	u32 setup;			/* setup time control */
+};
+
+#define IOBUS_FREQ	100000000
+
+struct uniphier_i2c_dev {
+	struct uniphier_i2c_regs __iomem *regs;	/* register base */
+	unsigned long input_clk;	/* master clock (Hz) */
+	unsigned long wait_us;		/* wait for every byte transfer (us) */
+};
+
+static int uniphier_i2c_probe(struct udevice *dev)
+{
+	fdt_addr_t addr;
+	fdt_size_t size;
+	struct uniphier_i2c_dev *priv = dev_get_priv(dev);
+
+	addr = fdtdec_get_addr_size(gd->fdt_blob, dev->of_offset, "reg", &size);
+
+	priv->regs = map_sysmem(addr, size);
+
+	if (!priv->regs)
+		return -ENOMEM;
+
+	priv->input_clk = IOBUS_FREQ;
+
+	/* deassert reset */
+	writel(0x3, &priv->regs->brst);
+
+	return 0;
+}
+
+static int uniphier_i2c_remove(struct udevice *dev)
+{
+	struct uniphier_i2c_dev *priv = dev_get_priv(dev);
+
+	unmap_sysmem(priv->regs);
+
+	return 0;
+}
+
+static int send_and_recv_byte(struct uniphier_i2c_dev *dev, u32 dtrm)
+{
+	writel(dtrm, &dev->regs->dtrm);
+
+	/*
+	 * This controller only provides interruption to inform the completion
+	 * of each byte transfer.  (No status register to poll it.)
+	 * Unfortunately, U-Boot does not have a good support of interrupt.
+	 * Wait for a while.
+	 */
+	udelay(dev->wait_us);
+
+	return readl(&dev->regs->drec);
+}
+
+static int send_byte(struct uniphier_i2c_dev *dev, u32 dtrm, bool *stop)
+{
+	int ret = 0;
+	u32 drec;
+
+	drec = send_and_recv_byte(dev, dtrm);
+
+	if (drec & I2C_DREC_LAB) {
+		debug("uniphier_i2c: bus arbitration failed\n");
+		*stop = false;
+		ret = -EREMOTEIO;
+	}
+	if (drec & I2C_DREC_LRB) {
+		debug("uniphier_i2c: slave did not return ACK\n");
+		ret = -EREMOTEIO;
+	}
+	return ret;
+}
+
+static int uniphier_i2c_transmit(struct uniphier_i2c_dev *dev, uint addr,
+				 uint len, const u8 *buf, bool *stop)
+{
+	int ret;
+
+	debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+	ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK | addr << 1, stop);
+	if (ret < 0)
+		goto fail;
+
+	while (len--) {
+		ret = send_byte(dev, I2C_DTRM_NACK | *buf++, stop);
+		if (ret < 0)
+			goto fail;
+	}
+
+fail:
+	if (*stop)
+		writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
+
+	return ret;
+}
+
+static int uniphier_i2c_receive(struct uniphier_i2c_dev *dev, uint addr,
+				uint len, u8 *buf, bool *stop)
+{
+	int ret;
+
+	debug("%s: addr = %x, len = %d\n", __func__, addr, len);
+
+	ret = send_byte(dev, I2C_DTRM_STA | I2C_DTRM_NACK |
+			I2C_DTRM_RD | addr << 1, stop);
+	if (ret < 0)
+		goto fail;
+
+	while (len--)
+		*buf++ = send_and_recv_byte(dev, len ? 0 : I2C_DTRM_NACK);
+
+fail:
+	if (*stop)
+		writel(I2C_DTRM_STO | I2C_DTRM_NACK, &dev->regs->dtrm);
+
+	return ret;
+}
+
+static int uniphier_i2c_xfer(struct udevice *bus, struct i2c_msg *msg,
+			     int nmsgs)
+{
+	int ret = 0;
+	struct uniphier_i2c_dev *dev = dev_get_priv(bus);
+	bool stop;
+
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		/* If next message is read, skip the stop condition */
+		stop = nmsgs > 1 && msg[1].flags & I2C_M_RD ? false : true;
+
+		if (msg->flags & I2C_M_RD)
+			ret = uniphier_i2c_receive(dev, msg->addr, msg->len,
+						   msg->buf, &stop);
+		else
+			ret = uniphier_i2c_transmit(dev, msg->addr, msg->len,
+						    msg->buf, &stop);
+
+		if (ret < 0)
+			break;
+	}
+
+	return ret;
+}
+
+static int uniphier_i2c_set_bus_speed(struct udevice *bus, unsigned int speed)
+{
+	struct uniphier_i2c_dev *priv = dev_get_priv(bus);
+
+	/* max supported frequency is 400 kHz */
+	if (speed > 400000)
+		return -EINVAL;
+
+	/* bus reset: make sure the bus is idle when change the frequency */
+	writel(0x1, &priv->regs->brst);
+
+	writel((priv->input_clk / speed / 2 << 16) | (priv->input_clk / speed),
+	       &priv->regs->clk);
+
+	writel(0x3, &priv->regs->brst);
+
+	/*
+	 * Theoretically, each byte can be transferred in
+	 * 1000000 * 9 / speed usec.  For safety, wait more than double.
+	 */
+	priv->wait_us = 20000000 / speed;
+
+	return 0;
+}
+
+
+static const struct dm_i2c_ops uniphier_i2c_ops = {
+	.xfer = uniphier_i2c_xfer,
+	.set_bus_speed = uniphier_i2c_set_bus_speed,
+};
+
+static const struct udevice_id uniphier_i2c_of_match[] = {
+	{ .compatible = "panasonic,uniphier-i2c" },
+	{},
+};
+
+U_BOOT_DRIVER(uniphier_i2c) = {
+	.name = "uniphier-i2c",
+	.id = UCLASS_I2C,
+	.of_match = uniphier_i2c_of_match,
+	.probe = uniphier_i2c_probe,
+	.remove = uniphier_i2c_remove,
+	.priv_auto_alloc_size = sizeof(struct uniphier_i2c_dev),
+	.ops = &uniphier_i2c_ops,
+};
diff --git a/drivers/i2c/s3c24x0_i2c.c b/drivers/i2c/s3c24x0_i2c.c
index fd328f0..0dd1abc 100644
--- a/drivers/i2c/s3c24x0_i2c.c
+++ b/drivers/i2c/s3c24x0_i2c.c
@@ -9,8 +9,9 @@
  * as they seem to have the same I2C controller inside.
  * The different address mapping is handled by the s3c24xx.h files below.
  */
-
 #include <common.h>
+#include <errno.h>
+#include <dm.h>
 #include <fdtdec.h>
 #if (defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 #include <asm/arch/clk.h>
@@ -121,13 +122,23 @@
 #define CONFIG_MAX_I2C_NUM 1
 #endif
 
+DECLARE_GLOBAL_DATA_PTR;
+
 /*
  * For SPL boot some boards need i2c before SDRAM is initialised so force
  * variables to live in SRAM
  */
+#ifdef CONFIG_SYS_I2C
 static struct s3c24x0_i2c_bus i2c_bus[CONFIG_MAX_I2C_NUM]
 			__attribute__((section(".data")));
+#endif
 
+enum exynos_i2c_type {
+	EXYNOS_I2C_STD,
+	EXYNOS_I2C_HS,
+};
+
+#ifdef CONFIG_SYS_I2C
 /**
  * Get a pointer to the given bus index
  *
@@ -147,6 +158,7 @@
 	debug("Undefined bus: %d\n", bus_idx);
 	return NULL;
 }
+#endif
 
 #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 static int GetI2CSDA(void)
@@ -251,6 +263,7 @@
 	writel(readl(&i2c->iiccon) & ~I2CCON_IRPND, &i2c->iiccon);
 }
 
+#ifdef CONFIG_SYS_I2C
 static struct s3c24x0_i2c *get_base_i2c(int bus)
 {
 #ifdef CONFIG_EXYNOS4
@@ -267,6 +280,7 @@
 	return s3c24x0_get_base_i2c();
 #endif
 }
+#endif
 
 static void i2c_ch_init(struct s3c24x0_i2c *i2c, int speed, int slaveadd)
 {
@@ -326,7 +340,7 @@
 			return 0;
 		}
 	}
-	return -1;
+	return -EINVAL;
 }
 
 static void hsi2c_ch_init(struct s3c24x0_i2c_bus *i2c_bus)
@@ -398,18 +412,20 @@
 	hsi2c_ch_init(i2c_bus);
 }
 
+#ifdef CONFIG_SYS_I2C
 static void s3c24x0_i2c_init(struct i2c_adapter *adap, int speed, int slaveadd)
 {
 	struct s3c24x0_i2c *i2c;
 	struct s3c24x0_i2c_bus *bus;
-
 #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5)
 	struct s3c24x0_gpio *gpio = s3c24x0_get_base_gpio();
 #endif
 	ulong start_time = get_timer(0);
 
-	/* By default i2c channel 0 is the current bus */
 	i2c = get_base_i2c(adap->hwadapnr);
+	bus = &i2c_bus[adap->hwadapnr];
+	if (!bus)
+		return;
 
 	/*
 	 * In case the previous transfer is still going, wait to give it a
@@ -470,12 +486,13 @@
 #endif
 	}
 #endif /* #if !(defined CONFIG_EXYNOS4 || defined CONFIG_EXYNOS5) */
+
 	i2c_ch_init(i2c, speed, slaveadd);
 
-	bus = &i2c_bus[adap->hwadapnr];
 	bus->active = true;
 	bus->regs = i2c;
 }
+#endif /* CONFIG_SYS_I2C */
 
 /*
  * Poll the appropriate bit of the fifo status register until the interface is
@@ -698,20 +715,27 @@
 	return rv;
 }
 
+#ifdef CONFIG_SYS_I2C
 static unsigned int s3c24x0_i2c_set_bus_speed(struct i2c_adapter *adap,
-					  unsigned int speed)
+					      unsigned int speed)
+#else
+static int s3c24x0_i2c_set_bus_speed(struct udevice *dev, unsigned int speed)
+#endif
 {
 	struct s3c24x0_i2c_bus *i2c_bus;
 
+#ifdef CONFIG_SYS_I2C
 	i2c_bus = get_bus(adap->hwadapnr);
 	if (!i2c_bus)
-		return -1;
-
+		return -EFAULT;
+#else
+	i2c_bus = dev_get_priv(dev);
+#endif
 	i2c_bus->clock_frequency = speed;
 
 	if (i2c_bus->is_highspeed) {
 		if (hsi2c_get_clk_details(i2c_bus))
-			return -1;
+			return -EFAULT;
 		hsi2c_ch_init(i2c_bus);
 	} else {
 		i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -721,17 +745,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_EXYNOS5
-static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
-{
-	/* This will override the speed selected in the fdt for that port */
-	debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
-	if (i2c_set_bus_speed(speed))
-		printf("i2c_init: failed to init bus %d for speed = %d\n",
-						adap->hwadapnr, speed);
-}
-#endif
-
 /*
  * cmd_type is 0 for write, 1 for read.
  *
@@ -844,15 +857,23 @@
 	return result;
 }
 
+#ifdef CONFIG_SYS_I2C
 static int s3c24x0_i2c_probe(struct i2c_adapter *adap, uchar chip)
+#else
+static int s3c24x0_i2c_probe(struct udevice *dev, uint chip, uint chip_flags)
+#endif
 {
 	struct s3c24x0_i2c_bus *i2c_bus;
 	uchar buf[1];
 	int ret;
 
+#ifdef CONFIG_SYS_I2C
 	i2c_bus = get_bus(adap->hwadapnr);
 	if (!i2c_bus)
-		return -1;
+		return -EFAULT;
+#else
+	i2c_bus = dev_get_priv(dev);
+#endif
 	buf[0] = 0;
 
 	/*
@@ -871,6 +892,7 @@
 	return ret != I2C_OK;
 }
 
+#ifdef CONFIG_SYS_I2C
 static int s3c24x0_i2c_read(struct i2c_adapter *adap, uchar chip, uint addr,
 			    int alen, uchar *buffer, int len)
 {
@@ -878,9 +900,13 @@
 	uchar xaddr[4];
 	int ret;
 
+	i2c_bus = get_bus(adap->hwadapnr);
+	if (!i2c_bus)
+		return -EFAULT;
+
 	if (alen > 4) {
 		debug("I2C read: addr len %d not supported\n", alen);
-		return 1;
+		return -EADDRNOTAVAIL;
 	}
 
 	if (alen > 0) {
@@ -906,10 +932,6 @@
 		chip |= ((addr >> (alen * 8)) &
 			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
-	i2c_bus = get_bus(adap->hwadapnr);
-	if (!i2c_bus)
-		return -1;
-
 	if (i2c_bus->is_highspeed)
 		ret = hsi2c_read(i2c_bus->hsregs, chip, &xaddr[4 - alen],
 				 alen, buffer, len);
@@ -921,7 +943,7 @@
 		if (i2c_bus->is_highspeed)
 			exynos5_i2c_reset(i2c_bus);
 		debug("I2c read failed %d\n", ret);
-		return 1;
+		return -EIO;
 	}
 	return 0;
 }
@@ -933,9 +955,13 @@
 	uchar xaddr[4];
 	int ret;
 
+	i2c_bus = get_bus(adap->hwadapnr);
+	if (!i2c_bus)
+		return -EFAULT;
+
 	if (alen > 4) {
 		debug("I2C write: addr len %d not supported\n", alen);
-		return 1;
+		return -EINVAL;
 	}
 
 	if (alen > 0) {
@@ -960,10 +986,6 @@
 		chip |= ((addr >> (alen * 8)) &
 			 CONFIG_SYS_I2C_EEPROM_ADDR_OVERFLOW);
 #endif
-	i2c_bus = get_bus(adap->hwadapnr);
-	if (!i2c_bus)
-		return -1;
-
 	if (i2c_bus->is_highspeed)
 		ret = hsi2c_write(i2c_bus->hsregs, chip, &xaddr[4 - alen],
 				  alen, buffer, len, true);
@@ -985,7 +1007,7 @@
 			 int is_highspeed)
 {
 	struct s3c24x0_i2c_bus *bus;
-	int i;
+	int i, flags;
 
 	for (i = 0; i < count; i++) {
 		int node = node_list[i];
@@ -997,12 +1019,15 @@
 		bus->active = true;
 		bus->is_highspeed = is_highspeed;
 
-		if (is_highspeed)
+		if (is_highspeed) {
+			flags = PINMUX_FLAG_HS_MODE;
 			bus->hsregs = (struct exynos5_hsi2c *)
 					fdtdec_get_addr(blob, node, "reg");
-		else
+		} else {
+			flags = 0;
 			bus->regs = (struct s3c24x0_i2c *)
 					fdtdec_get_addr(blob, node, "reg");
+		}
 
 		bus->id = pinmux_decode_periph_id(blob, node);
 		bus->clock_frequency = fdtdec_get_int(blob, node,
@@ -1010,7 +1035,7 @@
 						CONFIG_SYS_I2C_S3C24X0_SPEED);
 		bus->node = node;
 		bus->bus_num = i;
-		exynos_pinmux_config(bus->id, 0);
+		exynos_pinmux_config(PERIPH_ID_I2C0 + bus->id, flags);
 
 		/* Mark position as used */
 		node_list[i] = -1;
@@ -1033,7 +1058,6 @@
 		COMPAT_SAMSUNG_EXYNOS5_I2C, node_list,
 		CONFIG_MAX_I2C_NUM);
 	process_nodes(blob, node_list, count, 1);
-
 }
 
 int i2c_get_bus_num_fdt(int node)
@@ -1046,7 +1070,7 @@
 	}
 
 	debug("%s: Can't find any matched I2C bus\n", __func__);
-	return -1;
+	return -EINVAL;
 }
 
 int i2c_reset_port_fdt(const void *blob, int node)
@@ -1057,18 +1081,18 @@
 	bus = i2c_get_bus_num_fdt(node);
 	if (bus < 0) {
 		debug("could not get bus for node %d\n", node);
-		return -1;
+		return bus;
 	}
 
 	i2c_bus = get_bus(bus);
 	if (!i2c_bus) {
-		debug("get_bus() failed for node node %d\n", node);
-		return -1;
+		debug("get_bus() failed for node %d\n", node);
+		return -EFAULT;
 	}
 
 	if (i2c_bus->is_highspeed) {
 		if (hsi2c_get_clk_details(i2c_bus))
-			return -1;
+			return -EINVAL;
 		hsi2c_ch_init(i2c_bus);
 	} else {
 		i2c_ch_init(i2c_bus->regs, i2c_bus->clock_frequency,
@@ -1077,7 +1101,17 @@
 
 	return 0;
 }
-#endif
+#endif /* CONFIG_OF_CONTROL */
+
+#ifdef CONFIG_EXYNOS5
+static void exynos_i2c_init(struct i2c_adapter *adap, int speed, int slaveaddr)
+{
+	/* This will override the speed selected in the fdt for that port */
+	debug("i2c_init(speed=%u, slaveaddr=0x%x)\n", speed, slaveaddr);
+	if (i2c_set_bus_speed(speed))
+		error("i2c_init: failed to init bus for speed = %d", speed);
+}
+#endif /* CONFIG_EXYNOS5 */
 
 /*
  * Register s3c24x0 i2c adapters
@@ -1247,3 +1281,120 @@
 			CONFIG_SYS_I2C_S3C24X0_SPEED,
 			CONFIG_SYS_I2C_S3C24X0_SLAVE, 0)
 #endif
+#endif /* CONFIG_SYS_I2C */
+
+#ifdef CONFIG_DM_I2C
+static int i2c_write_data(struct s3c24x0_i2c_bus *i2c_bus, uchar chip,
+			  uchar *buffer, int len, bool end_with_repeated_start)
+{
+	int ret;
+
+	if (i2c_bus->is_highspeed) {
+		ret = hsi2c_write(i2c_bus->hsregs, chip, 0, 0,
+				  buffer, len, true);
+		if (ret)
+			exynos5_i2c_reset(i2c_bus);
+	} else {
+		ret = i2c_transfer(i2c_bus->regs, I2C_WRITE,
+				   chip << 1, 0, 0, buffer, len);
+	}
+
+	return ret != I2C_OK;
+}
+
+static int i2c_read_data(struct s3c24x0_i2c_bus  *i2c_bus, uchar chip,
+			 uchar *buffer, int len)
+{
+	int ret;
+
+	if (i2c_bus->is_highspeed) {
+		ret = hsi2c_read(i2c_bus->hsregs, chip, 0, 0, buffer, len);
+		if (ret)
+			exynos5_i2c_reset(i2c_bus);
+	} else {
+		ret = i2c_transfer(i2c_bus->regs, I2C_READ,
+				   chip << 1, 0, 0, buffer, len);
+	}
+
+	return ret != I2C_OK;
+}
+
+static int s3c24x0_i2c_xfer(struct udevice *dev, struct i2c_msg *msg,
+			    int nmsgs)
+{
+	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+	int ret;
+
+	for (; nmsgs > 0; nmsgs--, msg++) {
+		bool next_is_read = nmsgs > 1 && (msg[1].flags & I2C_M_RD);
+
+		if (msg->flags & I2C_M_RD) {
+			ret = i2c_read_data(i2c_bus, msg->addr, msg->buf,
+					    msg->len);
+		} else {
+			ret = i2c_write_data(i2c_bus, msg->addr, msg->buf,
+					     msg->len, next_is_read);
+		}
+		if (ret)
+			return -EREMOTEIO;
+	}
+
+	return 0;
+}
+
+static int s3c_i2c_ofdata_to_platdata(struct udevice *dev)
+{
+	const void *blob = gd->fdt_blob;
+	struct s3c24x0_i2c_bus *i2c_bus = dev_get_priv(dev);
+	int node, flags;
+
+	i2c_bus->is_highspeed = dev->of_id->data;
+	node = dev->of_offset;
+
+	if (i2c_bus->is_highspeed) {
+		flags = PINMUX_FLAG_HS_MODE;
+		i2c_bus->hsregs = (struct exynos5_hsi2c *)
+				fdtdec_get_addr(blob, node, "reg");
+	} else {
+		flags = 0;
+		i2c_bus->regs = (struct s3c24x0_i2c *)
+				fdtdec_get_addr(blob, node, "reg");
+	}
+
+	i2c_bus->id = pinmux_decode_periph_id(blob, node);
+
+	i2c_bus->clock_frequency = fdtdec_get_int(blob, node,
+						"clock-frequency",
+						CONFIG_SYS_I2C_S3C24X0_SPEED);
+	i2c_bus->node = node;
+	i2c_bus->bus_num = dev->seq;
+
+	exynos_pinmux_config(i2c_bus->id, flags);
+
+	i2c_bus->active = true;
+
+	return 0;
+}
+
+static const struct dm_i2c_ops s3c_i2c_ops = {
+	.xfer		= s3c24x0_i2c_xfer,
+	.probe_chip	= s3c24x0_i2c_probe,
+	.set_bus_speed	= s3c24x0_i2c_set_bus_speed,
+};
+
+static const struct udevice_id s3c_i2c_ids[] = {
+	{ .compatible = "samsung,s3c2440-i2c", .data = EXYNOS_I2C_STD },
+	{ .compatible = "samsung,exynos5-hsi2c", .data = EXYNOS_I2C_HS },
+	{ }
+};
+
+U_BOOT_DRIVER(i2c_s3c) = {
+	.name	= "i2c_s3c",
+	.id	= UCLASS_I2C,
+	.of_match = s3c_i2c_ids,
+	.ofdata_to_platdata = s3c_i2c_ofdata_to_platdata,
+	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
+	.priv_auto_alloc_size = sizeof(struct s3c24x0_i2c_bus),
+	.ops	= &s3c_i2c_ops,
+};
+#endif /* CONFIG_DM_I2C */
diff --git a/drivers/i2c/sandbox_i2c.c b/drivers/i2c/sandbox_i2c.c
index f0e9f51..a943aa6 100644
--- a/drivers/i2c/sandbox_i2c.c
+++ b/drivers/i2c/sandbox_i2c.c
@@ -25,24 +25,24 @@
 static int get_emul(struct udevice *dev, struct udevice **devp,
 		    struct dm_i2c_ops **opsp)
 {
-	struct dm_i2c_chip *priv;
+	struct dm_i2c_chip *plat;
 	int ret;
 
 	*devp = NULL;
 	*opsp = NULL;
-	priv = dev_get_parentdata(dev);
-	if (!priv->emul) {
+	plat = dev_get_parent_platdata(dev);
+	if (!plat->emul) {
 		ret = dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset,
 				       false);
 		if (ret)
 			return ret;
 
-		ret = device_get_child(dev, 0, &priv->emul);
+		ret = device_get_child(dev, 0, &plat->emul);
 		if (ret)
 			return ret;
 	}
-	*devp = priv->emul;
-	*opsp = i2c_get_ops(priv->emul);
+	*devp = plat->emul;
+	*opsp = i2c_get_ops(plat->emul);
 
 	return 0;
 }
@@ -60,7 +60,7 @@
 	if (msg->addr == SANDBOX_I2C_TEST_ADDR)
 		return 0;
 
-	ret = i2c_get_chip(bus, msg->addr, &dev);
+	ret = i2c_get_chip(bus, msg->addr, 1, &dev);
 	if (ret)
 		return ret;
 
@@ -82,20 +82,6 @@
 	.xfer		= sandbox_i2c_xfer,
 };
 
-static int sandbox_i2c_child_pre_probe(struct udevice *dev)
-{
-	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
-
-	/* Ignore our test address */
-	if (i2c_chip->chip_addr == SANDBOX_I2C_TEST_ADDR)
-		return 0;
-	if (dev->of_offset == -1)
-		return 0;
-
-	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
-					   i2c_chip);
-}
-
 static const struct udevice_id sandbox_i2c_ids[] = {
 	{ .compatible = "sandbox,i2c" },
 	{ }
@@ -105,7 +91,5 @@
 	.name	= "i2c_sandbox",
 	.id	= UCLASS_I2C,
 	.of_match = sandbox_i2c_ids,
-	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
-	.child_pre_probe = sandbox_i2c_child_pre_probe,
 	.ops	= &sandbox_i2c_ops,
 };
diff --git a/drivers/i2c/tegra_i2c.c b/drivers/i2c/tegra_i2c.c
index 87290c3..f414287 100644
--- a/drivers/i2c/tegra_i2c.c
+++ b/drivers/i2c/tegra_i2c.c
@@ -484,21 +484,6 @@
 	.set_bus_speed	= tegra_i2c_set_bus_speed,
 };
 
-static int tegra_i2c_child_pre_probe(struct udevice *dev)
-{
-	struct dm_i2c_chip *i2c_chip = dev_get_parentdata(dev);
-
-	if (dev->of_offset == -1)
-		return 0;
-	return i2c_chip_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
-					   i2c_chip);
-}
-
-static int tegra_i2c_ofdata_to_platdata(struct udevice *dev)
-{
-	return 0;
-}
-
 static const struct udevice_id tegra_i2c_ids[] = {
 	{ .compatible = "nvidia,tegra114-i2c", .data = TYPE_114 },
 	{ .compatible = "nvidia,tegra20-i2c", .data = TYPE_STD },
@@ -510,10 +495,7 @@
 	.name	= "i2c_tegra",
 	.id	= UCLASS_I2C,
 	.of_match = tegra_i2c_ids,
-	.ofdata_to_platdata = tegra_i2c_ofdata_to_platdata,
 	.probe	= tegra_i2c_probe,
-	.per_child_auto_alloc_size = sizeof(struct dm_i2c_chip),
-	.child_pre_probe = tegra_i2c_child_pre_probe,
 	.priv_auto_alloc_size = sizeof(struct i2c_bus),
 	.ops	= &tegra_i2c_ops,
 };
diff --git a/drivers/misc/cros_ec.c b/drivers/misc/cros_ec.c
index 9b4effb..5846e76 100644
--- a/drivers/misc/cros_ec.c
+++ b/drivers/misc/cros_ec.c
@@ -154,7 +154,9 @@
  * @param dev		CROS-EC device
  * @param dinp          Returns pointer to response data
  * @param din_len       Maximum size of response in bytes
- * @return number of bytes of response data, or <0 if error
+ * @return number of bytes of response data, or <0 if error. Note that error
+ * codes can be from errno.h or -ve EC_RES_INVALID_CHECKSUM values (and they
+ * overlap!)
  */
 static int handle_proto3_response(struct cros_ec_dev *dev,
 				  uint8_t **dinp, int din_len)
@@ -228,7 +230,7 @@
 
 #ifdef CONFIG_DM_CROS_EC
 	ops = dm_cros_ec_get_ops(dev->dev);
-	rv = ops->packet(dev->dev, out_bytes, in_bytes);
+	rv = ops->packet ? ops->packet(dev->dev, out_bytes, in_bytes) : -ENOSYS;
 #else
 	switch (dev->interface) {
 #ifdef CONFIG_CROS_EC_SPI
@@ -320,7 +322,7 @@
  *			If not NULL, it will be updated to point to the data
  *			and will always be double word aligned (64-bits)
  * @param din_len       Maximum size of response in bytes
- * @return number of bytes in response, or -1 on error
+ * @return number of bytes in response, or -ve on error
  */
 static int ec_command_inptr(struct cros_ec_dev *dev, uint8_t cmd,
 		int cmd_version, const void *dout, int dout_len, uint8_t **dinp,
@@ -387,7 +389,7 @@
  *			It not NULL, it is a place for ec_command() to copy the
  *      data to.
  * @param din_len       Maximum size of response in bytes
- * @return number of bytes in response, or -1 on error
+ * @return number of bytes in response, or -ve on error
  */
 static int ec_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
 		      const void *dout, int dout_len,
@@ -606,10 +608,10 @@
 int cros_ec_interrupt_pending(struct cros_ec_dev *dev)
 {
 	/* no interrupt support : always poll */
-	if (!fdt_gpio_isvalid(&dev->ec_int))
+	if (!dm_gpio_is_valid(&dev->ec_int))
 		return -ENOENT;
 
-	return !gpio_get_value(dev->ec_int.gpio);
+	return dm_gpio_get_value(&dev->ec_int);
 }
 
 int cros_ec_info(struct cros_ec_dev *dev, struct ec_response_mkbp_info *info)
@@ -1072,7 +1074,8 @@
 		return -1;
 	}
 
-	fdtdec_decode_gpio(blob, node, "ec-interrupt", &dev->ec_int);
+	gpio_request_by_name_nodev(blob, node, "ec-interrupt", 0, &dev->ec_int,
+				   GPIOD_IS_IN);
 	dev->optimise_flash_write = fdtdec_get_bool(blob, node,
 						    "optimise-flash-write");
 	*devp = dev;
@@ -1090,17 +1093,11 @@
 	char id[MSG_BYTES];
 
 	cdev->dev = dev;
-	fdtdec_decode_gpio(blob, node, "ec-interrupt", &cdev->ec_int);
+	gpio_request_by_name(dev, "ec-interrupt", 0, &cdev->ec_int,
+			     GPIOD_IS_IN);
 	cdev->optimise_flash_write = fdtdec_get_bool(blob, node,
 						     "optimise-flash-write");
 
-	/* we will poll the EC interrupt line */
-	fdtdec_setup_gpio(&cdev->ec_int);
-	if (fdt_gpio_isvalid(&cdev->ec_int)) {
-		gpio_request(cdev->ec_int.gpio, "cros-ec-irq");
-		gpio_direction_input(cdev->ec_int.gpio);
-	}
-
 	if (cros_ec_check_version(cdev)) {
 		debug("%s: Could not detect CROS-EC version\n", __func__);
 		return -CROS_EC_ERR_CHECK_VERSION;
@@ -1184,13 +1181,6 @@
 	}
 #endif
 
-	/* we will poll the EC interrupt line */
-	fdtdec_setup_gpio(&dev->ec_int);
-	if (fdt_gpio_isvalid(&dev->ec_int)) {
-		gpio_request(dev->ec_int.gpio, "cros-ec-irq");
-		gpio_direction_input(dev->ec_int.gpio);
-	}
-
 	if (cros_ec_check_version(dev)) {
 		debug("%s: Could not detect CROS-EC version\n", __func__);
 		return -CROS_EC_ERR_CHECK_VERSION;
diff --git a/drivers/misc/cros_ec_i2c.c b/drivers/misc/cros_ec_i2c.c
index 513cdb1..f9bc975 100644
--- a/drivers/misc/cros_ec_i2c.c
+++ b/drivers/misc/cros_ec_i2c.c
@@ -14,6 +14,7 @@
  */
 
 #include <common.h>
+#include <dm.h>
 #include <i2c.h>
 #include <cros_ec.h>
 
@@ -23,11 +24,11 @@
 #define debug_trace(fmt, b...)
 #endif
 
-int cros_ec_i2c_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
-		     const uint8_t *dout, int dout_len,
-		     uint8_t **dinp, int din_len)
+static int cros_ec_i2c_command(struct udevice *udev, uint8_t cmd,
+			       int cmd_version, const uint8_t *dout,
+			       int dout_len, uint8_t **dinp, int din_len)
 {
-	int old_bus = 0;
+	struct cros_ec_dev *dev = udev->uclass_priv;
 	/* version8, cmd8, arglen8, out8[dout_len], csum8 */
 	int out_bytes = dout_len + 4;
 	/* response8, arglen8, in8[din_len], checksum8 */
@@ -37,8 +38,6 @@
 	uint8_t *in_ptr;
 	int len, csum, ret;
 
-	old_bus = i2c_get_bus_num();
-
 	/*
 	 * Sanity-check I/O sizes given transaction overhead in internal
 	 * buffers.
@@ -86,36 +85,24 @@
 	*ptr++ = (uint8_t)
 		cros_ec_calc_checksum(dev->dout, dout_len + 3);
 
-	/* Set to the proper i2c bus */
-	if (i2c_set_bus_num(dev->bus_num)) {
-		debug("%s: Cannot change to I2C bus %d\n", __func__,
-			dev->bus_num);
-		return -1;
-	}
-
 	/* Send output data */
 	cros_ec_dump_data("out", -1, dev->dout, out_bytes);
-	ret = i2c_write(dev->addr, 0, 0, dev->dout, out_bytes);
+	ret = dm_i2c_write(udev, 0, dev->dout, out_bytes);
 	if (ret) {
-		debug("%s: Cannot complete I2C write to 0x%x\n",
-			__func__, dev->addr);
+		debug("%s: Cannot complete I2C write to %s\n", __func__,
+		      udev->name);
 		ret = -1;
 	}
 
 	if (!ret) {
-		ret = i2c_read(dev->addr, 0, 0, in_ptr, in_bytes);
+		ret = dm_i2c_read(udev, 0, in_ptr, in_bytes);
 		if (ret) {
-			debug("%s: Cannot complete I2C read from 0x%x\n",
-				__func__, dev->addr);
+			debug("%s: Cannot complete I2C read from %s\n",
+			      __func__, udev->name);
 			ret = -1;
 		}
 	}
 
-	/* Return to original bus number */
-	i2c_set_bus_num(old_bus);
-	if (ret)
-		return ret;
-
 	if (*in_ptr != EC_RES_SUCCESS) {
 		debug("%s: Received bad result code %d\n", __func__, *in_ptr);
 		return -(int)*in_ptr;
@@ -142,35 +129,24 @@
 	return din_len;
 }
 
-int cros_ec_i2c_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+static int cros_ec_probe(struct udevice *dev)
 {
-	/* Decode interface-specific FDT params */
-	dev->max_frequency = fdtdec_get_int(blob, dev->node,
-					    "i2c-max-frequency", 100000);
-	dev->bus_num = i2c_get_bus_num_fdt(dev->parent_node);
-	if (dev->bus_num == -1) {
-		debug("%s: Failed to read bus number\n", __func__);
-		return -1;
-	}
-	dev->addr = fdtdec_get_int(blob, dev->node, "reg", -1);
-	if (dev->addr == -1) {
-		debug("%s: Failed to read device address\n", __func__);
-		return -1;
-	}
-
-	return 0;
+	return cros_ec_register(dev);
 }
 
-/**
- * Initialize I2C protocol.
- *
- * @param dev		CROS_EC device
- * @param blob		Device tree blob
- * @return 0 if ok, -1 on error
- */
-int cros_ec_i2c_init(struct cros_ec_dev *dev, const void *blob)
-{
-	i2c_init(dev->max_frequency, dev->addr);
+static struct dm_cros_ec_ops cros_ec_ops = {
+	.command = cros_ec_i2c_command,
+};
 
-	return 0;
-}
+static const struct udevice_id cros_ec_ids[] = {
+	{ .compatible = "google,cros-ec" },
+	{ }
+};
+
+U_BOOT_DRIVER(cros_ec_i2c) = {
+	.name		= "cros_ec",
+	.id		= UCLASS_CROS_EC,
+	.of_match	= cros_ec_ids,
+	.probe		= cros_ec_probe,
+	.ops		= &cros_ec_ops,
+};
diff --git a/drivers/misc/cros_ec_spi.c b/drivers/misc/cros_ec_spi.c
index e6dba29..9359c56 100644
--- a/drivers/misc/cros_ec_spi.c
+++ b/drivers/misc/cros_ec_spi.c
@@ -21,14 +21,9 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
-#ifdef CONFIG_DM_CROS_EC
 int cros_ec_spi_packet(struct udevice *udev, int out_bytes, int in_bytes)
 {
 	struct cros_ec_dev *dev = udev->uclass_priv;
-#else
-int cros_ec_spi_packet(struct cros_ec_dev *dev, int out_bytes, int in_bytes)
-{
-#endif
 	struct spi_slave *slave = dev_get_parentdata(dev->dev);
 	int rv;
 
@@ -67,18 +62,11 @@
  * @param din_len	Maximum size of response in bytes
  * @return number of bytes in response, or -1 on error
  */
-#ifdef CONFIG_DM_CROS_EC
 int cros_ec_spi_command(struct udevice *udev, uint8_t cmd, int cmd_version,
 		     const uint8_t *dout, int dout_len,
 		     uint8_t **dinp, int din_len)
 {
 	struct cros_ec_dev *dev = udev->uclass_priv;
-#else
-int cros_ec_spi_command(struct cros_ec_dev *dev, uint8_t cmd, int cmd_version,
-		     const uint8_t *dout, int dout_len,
-		     uint8_t **dinp, int din_len)
-{
-#endif
 	struct spi_slave *slave = dev_get_parentdata(dev->dev);
 	int in_bytes = din_len + 4;	/* status, length, checksum, trailer */
 	uint8_t *out;
@@ -166,65 +154,12 @@
 	return len;
 }
 
-#ifndef CONFIG_DM_CROS_EC
-int cros_ec_spi_decode_fdt(struct cros_ec_dev *dev, const void *blob)
+static int cros_ec_probe(struct udevice *dev)
 {
-	/* Decode interface-specific FDT params */
-	dev->max_frequency = fdtdec_get_int(blob, dev->node,
-					    "spi-max-frequency", 500000);
-	dev->cs = fdtdec_get_int(blob, dev->node, "reg", 0);
-
-	return 0;
-}
-
-/**
- * Initialize SPI protocol.
- *
- * @param dev		CROS_EC device
- * @param blob		Device tree blob
- * @return 0 if ok, -1 on error
- */
-int cros_ec_spi_init(struct cros_ec_dev *dev, const void *blob)
-{
-	int ret;
-
-	ret = spi_setup_slave_fdt(blob, dev->node, dev->parent_node,
-				  &slave);
-	if (ret) {
-		debug("%s: Could not setup SPI slave\n", __func__);
-		return ret;
-	}
-
-	return 0;
-}
-#endif
-
-#ifdef CONFIG_DM_CROS_EC
-int cros_ec_probe(struct udevice *dev)
-{
-	struct spi_slave *slave = dev_get_parentdata(dev);
-	int ret;
-
-	/*
-	 * TODO(sjg@chromium.org)
-	 *
-	 * This is really horrible at present. It is an artifact of removing
-	 * the child_pre_probe() method for SPI. Everything here could go in
-	 * an automatic function, except that spi_get_bus_and_cs() wants to
-	 * set it up manually and call device_probe_child().
-	 *
-	 * The solution may be to re-enable the child_pre_probe() method for
-	 * SPI and have it do nothing if the child is already passed in via
-	 * device_probe_child().
-	 */
-	slave->dev = dev;
-	ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
-	if (ret)
-		return ret;
 	return cros_ec_register(dev);
 }
 
-struct dm_cros_ec_ops cros_ec_ops = {
+static struct dm_cros_ec_ops cros_ec_ops = {
 	.packet = cros_ec_spi_packet,
 	.command = cros_ec_spi_command,
 };
@@ -241,4 +176,3 @@
 	.probe		= cros_ec_probe,
 	.ops		= &cros_ec_ops,
 };
-#endif
diff --git a/drivers/mmc/s5p_sdhci.c b/drivers/mmc/s5p_sdhci.c
index a5d3487..3899372 100644
--- a/drivers/mmc/s5p_sdhci.c
+++ b/drivers/mmc/s5p_sdhci.c
@@ -102,17 +102,14 @@
 
 static int do_sdhci_init(struct sdhci_host *host)
 {
-	char str[20];
 	int dev_id, flag;
 	int err = 0;
 
 	flag = host->bus_width == 8 ? PINMUX_FLAG_8BIT_MODE : PINMUX_FLAG_NONE;
 	dev_id = host->index + PERIPH_ID_SDMMC0;
 
-	if (fdt_gpio_isvalid(&host->pwr_gpio)) {
-		sprintf(str, "sdhci%d_power", host->index & 0xf);
-		gpio_request(host->pwr_gpio.gpio, str);
-		gpio_direction_output(host->pwr_gpio.gpio, 1);
+	if (dm_gpio_is_valid(&host->pwr_gpio)) {
+		dm_gpio_set_value(&host->pwr_gpio, 1);
 		err = exynos_pinmux_config(dev_id, flag);
 		if (err) {
 			debug("MMC not configured\n");
@@ -120,11 +117,8 @@
 		}
 	}
 
-	if (fdt_gpio_isvalid(&host->cd_gpio)) {
-		sprintf(str, "sdhci%d_cd", host->index & 0xf);
-		gpio_request(host->cd_gpio.gpio, str);
-		gpio_direction_input(host->cd_gpio.gpio);
-		if (gpio_get_value(host->cd_gpio.gpio))
+	if (dm_gpio_is_valid(&host->cd_gpio)) {
+		if (dm_gpio_get_value(&host->cd_gpio))
 			return -ENODEV;
 
 		err = exynos_pinmux_config(dev_id, flag);
@@ -166,8 +160,10 @@
 	}
 	host->ioaddr = (void *)base;
 
-	fdtdec_decode_gpio(blob, node, "pwr-gpios", &host->pwr_gpio);
-	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
+	gpio_request_by_name_nodev(blob, node, "pwr-gpios", 0, &host->pwr_gpio,
+				   GPIOD_IS_OUT);
+	gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
+				   GPIOD_IS_IN);
 
 	return 0;
 }
diff --git a/drivers/mmc/tegra_mmc.c b/drivers/mmc/tegra_mmc.c
index 2bd36b0..2cd8cf1 100644
--- a/drivers/mmc/tegra_mmc.c
+++ b/drivers/mmc/tegra_mmc.c
@@ -515,8 +515,8 @@
 
 	debug("tegra_mmc_getcd called\n");
 
-	if (fdt_gpio_isvalid(&host->cd_gpio))
-		return fdtdec_get_gpio(&host->cd_gpio);
+	if (dm_gpio_is_valid(&host->cd_gpio))
+		return dm_gpio_get_value(&host->cd_gpio);
 
 	return 1;
 }
@@ -531,7 +531,6 @@
 static int do_mmc_init(int dev_index)
 {
 	struct mmc_host *host;
-	char gpusage[12]; /* "SD/MMCn PWR" or "SD/MMCn CD" */
 	struct mmc *mmc;
 
 	/* DT should have been read & host config filled in */
@@ -539,27 +538,15 @@
 	if (!host->enabled)
 		return -1;
 
-	debug(" do_mmc_init: index %d, bus width %d "
-		"pwr_gpio %d cd_gpio %d\n",
-		dev_index, host->width,
-		host->pwr_gpio.gpio, host->cd_gpio.gpio);
+	debug(" do_mmc_init: index %d, bus width %d pwr_gpio %d cd_gpio %d\n",
+	      dev_index, host->width, gpio_get_number(&host->pwr_gpio),
+	      gpio_get_number(&host->cd_gpio));
 
 	host->clock = 0;
 	clock_start_periph_pll(host->mmc_id, CLOCK_ID_PERIPH, 20000000);
 
-	if (fdt_gpio_isvalid(&host->pwr_gpio)) {
-		sprintf(gpusage, "SD/MMC%d PWR", dev_index);
-		gpio_request(host->pwr_gpio.gpio, gpusage);
-		gpio_direction_output(host->pwr_gpio.gpio, 1);
-		debug(" Power GPIO name = %s\n", host->pwr_gpio.name);
-	}
-
-	if (fdt_gpio_isvalid(&host->cd_gpio)) {
-		sprintf(gpusage, "SD/MMC%d CD", dev_index);
-		gpio_request(host->cd_gpio.gpio, gpusage);
-		gpio_direction_input(host->cd_gpio.gpio);
-		debug(" CD GPIO name = %s\n", host->cd_gpio.name);
-	}
+	if (dm_gpio_is_valid(&host->pwr_gpio))
+		dm_gpio_set_value(&host->pwr_gpio, 1);
 
 	memset(&host->cfg, 0, sizeof(host->cfg));
 
@@ -626,9 +613,12 @@
 		debug("%s: no sdmmc width found\n", __func__);
 
 	/* These GPIOs are optional */
-	fdtdec_decode_gpio(blob, node, "cd-gpios", &host->cd_gpio);
-	fdtdec_decode_gpio(blob, node, "wp-gpios", &host->wp_gpio);
-	fdtdec_decode_gpio(blob, node, "power-gpios", &host->pwr_gpio);
+	gpio_request_by_name_nodev(blob, node, "cd-gpios", 0, &host->cd_gpio,
+				   GPIOD_IS_IN);
+	gpio_request_by_name_nodev(blob, node, "wp-gpios", 0, &host->wp_gpio,
+				   GPIOD_IS_IN);
+	gpio_request_by_name_nodev(blob, node, "power-gpios", 0,
+				   &host->pwr_gpio, GPIOD_IS_OUT);
 
 	debug("%s: found controller at %p, width = %d, periph_id = %d\n",
 		__func__, host->reg, host->width, host->mmc_id);
diff --git a/drivers/mtd/nand/tegra_nand.c b/drivers/mtd/nand/tegra_nand.c
index 163cf29..b660f3b 100644
--- a/drivers/mtd/nand/tegra_nand.c
+++ b/drivers/mtd/nand/tegra_nand.c
@@ -79,7 +79,7 @@
 struct fdt_nand {
 	struct nand_ctlr *reg;
 	int enabled;		/* 1 to enable, 0 to disable */
-	struct fdt_gpio_state wp_gpio;	/* write-protect GPIO */
+	struct gpio_desc wp_gpio;	/* write-protect GPIO */
 	s32 width;		/* bit width, normally 8 */
 	u32 timing[FDT_NAND_TIMING_COUNT];
 };
@@ -945,8 +945,8 @@
 	config->reg = (struct nand_ctlr *)fdtdec_get_addr(blob, node, "reg");
 	config->enabled = fdtdec_get_is_enabled(blob, node);
 	config->width = fdtdec_get_int(blob, node, "nvidia,nand-width", 8);
-	err = fdtdec_decode_gpio(blob, node, "nvidia,wp-gpios",
-				 &config->wp_gpio);
+	err = gpio_request_by_name_nodev(blob, node, "nvidia,wp-gpios", 0,
+				 &config->wp_gpio, GPIOD_IS_OUT);
 	if (err)
 		return err;
 	err = fdtdec_get_int_array(blob, node, "nvidia,timing",
@@ -1009,8 +1009,7 @@
 	/* Adjust timing for NAND device */
 	setup_timing(config->timing, info->reg);
 
-	fdtdec_setup_gpio(&config->wp_gpio);
-	gpio_direction_output(config->wp_gpio.gpio, 1);
+	dm_gpio_set_value(&config->wp_gpio, 1);
 
 	our_mtd = &nand_info[devnum];
 	our_mtd->priv = nand;
diff --git a/drivers/mtd/spi/sandbox.c b/drivers/mtd/spi/sandbox.c
index 3024b98..d576d31 100644
--- a/drivers/mtd/spi/sandbox.c
+++ b/drivers/mtd/spi/sandbox.c
@@ -141,8 +141,10 @@
 		assert(bus->seq != -1);
 		if (bus->seq < CONFIG_SANDBOX_SPI_MAX_BUS)
 			spec = state->spi[bus->seq][cs].spec;
-		if (!spec)
-			return -ENOENT;
+		if (!spec) {
+			ret = -ENOENT;
+			goto error;
+		}
 
 		file = strchr(spec, ':');
 		if (!file) {
@@ -196,6 +198,7 @@
 	return 0;
 
  error:
+	debug("%s: Got error %d\n", __func__, ret);
 	return ret;
 }
 
@@ -587,6 +590,11 @@
 
 void sandbox_sf_unbind_emul(struct sandbox_state *state, int busnum, int cs)
 {
+	struct udevice *dev;
+
+	dev = state->spi[busnum][cs].emul;
+	device_remove(dev);
+	device_unbind(dev);
 	state->spi[busnum][cs].emul = NULL;
 }
 
diff --git a/drivers/mtd/spi/sf_probe.c b/drivers/mtd/spi/sf_probe.c
index ce9987f..4103723 100644
--- a/drivers/mtd/spi/sf_probe.c
+++ b/drivers/mtd/spi/sf_probe.c
@@ -481,11 +481,12 @@
 int spi_flash_std_probe(struct udevice *dev)
 {
 	struct spi_slave *slave = dev_get_parentdata(dev);
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 	struct spi_flash *flash;
 
 	flash = dev->uclass_priv;
 	flash->dev = dev;
-	debug("%s: slave=%p, cs=%d\n", __func__, slave, slave->cs);
+	debug("%s: slave=%p, cs=%d\n", __func__, slave, plat->cs);
 	return spi_flash_probe_slave(slave, flash);
 }
 
diff --git a/drivers/power/as3722.c b/drivers/power/as3722.c
index 4c6de79..a60bb5f 100644
--- a/drivers/power/as3722.c
+++ b/drivers/power/as3722.c
@@ -31,7 +31,7 @@
 {
 	int err;
 
-	err = i2c_read(pmic, reg, value, 1);
+	err = dm_i2c_read(pmic, reg, value, 1);
 	if (err < 0)
 		return err;
 
@@ -42,7 +42,7 @@
 {
 	int err;
 
-	err = i2c_write(pmic, reg, &value, 1);
+	err = dm_i2c_write(pmic, reg, &value, 1);
 	if (err < 0)
 		return err;
 
@@ -242,7 +242,7 @@
 	const unsigned int address = 0x40;
 	int err;
 
-	err = i2c_get_chip_for_busnum(bus, address, &pmic);
+	err = i2c_get_chip_for_busnum(bus, address, 1, &pmic);
 	if (err)
 		return err;
 	err = as3722_read_id(pmic, &id, &revision);
diff --git a/drivers/power/tps6586x.c b/drivers/power/tps6586x.c
index 29bab4c..8650983 100644
--- a/drivers/power/tps6586x.c
+++ b/drivers/power/tps6586x.c
@@ -37,7 +37,7 @@
 	int	retval = -1;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_read(tps6586x_dev, reg,  &data, 1)) {
+		if (!dm_i2c_read(tps6586x_dev, reg,  &data, 1)) {
 			retval = (int)data;
 			goto exit;
 		}
@@ -60,7 +60,7 @@
 	int	retval = -1;
 
 	for (i = 0; i < MAX_I2C_RETRY; ++i) {
-		if (!i2c_write(tps6586x_dev, reg, data, len)) {
+		if (!dm_i2c_write(tps6586x_dev, reg, data, len)) {
 			retval = 0;
 			goto exit;
 		}
diff --git a/drivers/serial/serial-uclass.c b/drivers/serial/serial-uclass.c
index d1b5777..9131a8f 100644
--- a/drivers/serial/serial-uclass.c
+++ b/drivers/serial/serial-uclass.c
@@ -297,6 +297,7 @@
 UCLASS_DRIVER(serial) = {
 	.id		= UCLASS_SERIAL,
 	.name		= "serial",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.post_probe	= serial_post_probe,
 	.pre_remove	= serial_pre_remove,
 	.per_device_auto_alloc_size = sizeof(struct serial_dev_priv),
diff --git a/drivers/spi/cadence_qspi.c b/drivers/spi/cadence_qspi.c
index 98ae3b8..a75fc46 100644
--- a/drivers/spi/cadence_qspi.c
+++ b/drivers/spi/cadence_qspi.c
@@ -340,6 +340,5 @@
 	.ofdata_to_platdata = cadence_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct cadence_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct cadence_spi_priv),
-	.per_child_auto_alloc_size = sizeof(struct spi_slave),
 	.probe = cadence_spi_probe,
 };
diff --git a/drivers/spi/designware_spi.c b/drivers/spi/designware_spi.c
index 700f616..2624844 100644
--- a/drivers/spi/designware_spi.c
+++ b/drivers/spi/designware_spi.c
@@ -421,6 +421,5 @@
 	.ofdata_to_platdata = dw_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct dw_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct dw_spi_priv),
-	.per_child_auto_alloc_size = sizeof(struct spi_slave),
 	.probe = dw_spi_probe,
 };
diff --git a/drivers/spi/exynos_spi.c b/drivers/spi/exynos_spi.c
index f078973..a46d8c1 100644
--- a/drivers/spi/exynos_spi.c
+++ b/drivers/spi/exynos_spi.c
@@ -425,6 +425,5 @@
 	.ofdata_to_platdata = exynos_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct exynos_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct exynos_spi_priv),
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.probe	= exynos_spi_probe,
 };
diff --git a/drivers/spi/sandbox_spi.c b/drivers/spi/sandbox_spi.c
index e717424..bad5660 100644
--- a/drivers/spi/sandbox_spi.c
+++ b/drivers/spi/sandbox_spi.c
@@ -160,6 +160,5 @@
 	.name	= "spi_sandbox",
 	.id	= UCLASS_SPI,
 	.of_match = sandbox_spi_ids,
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.ops	= &sandbox_spi_ops,
 };
diff --git a/drivers/spi/soft_spi.c b/drivers/spi/soft_spi.c
index 5588036..6ae45f5 100644
--- a/drivers/spi/soft_spi.c
+++ b/drivers/spi/soft_spi.c
@@ -21,10 +21,10 @@
 DECLARE_GLOBAL_DATA_PTR;
 
 struct soft_spi_platdata {
-	struct fdt_gpio_state cs;
-	struct fdt_gpio_state sclk;
-	struct fdt_gpio_state mosi;
-	struct fdt_gpio_state miso;
+	struct gpio_desc cs;
+	struct gpio_desc sclk;
+	struct gpio_desc mosi;
+	struct gpio_desc miso;
 	int spi_delay_us;
 };
 
@@ -35,9 +35,8 @@
 static int soft_spi_scl(struct udevice *dev, int bit)
 {
 	struct soft_spi_platdata *plat = dev->platdata;
-	struct soft_spi_priv *priv = dev_get_priv(dev);
 
-	gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL ? bit : !bit);
+	dm_gpio_set_value(&plat->sclk, bit);
 
 	return 0;
 }
@@ -46,7 +45,7 @@
 {
 	struct soft_spi_platdata *plat = dev->platdata;
 
-	gpio_set_value(plat->mosi.gpio, bit);
+	dm_gpio_set_value(&plat->mosi, bit);
 
 	return 0;
 }
@@ -54,11 +53,10 @@
 static int soft_spi_cs_activate(struct udevice *dev)
 {
 	struct soft_spi_platdata *plat = dev->platdata;
-	struct soft_spi_priv *priv = dev_get_priv(dev);
 
-	gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
-	gpio_set_value(plat->sclk.gpio, priv->mode & SPI_CPOL);
-	gpio_set_value(plat->cs.gpio, priv->mode & SPI_CS_HIGH);
+	dm_gpio_set_value(&plat->cs, 0);
+	dm_gpio_set_value(&plat->sclk, 0);
+	dm_gpio_set_value(&plat->cs, 1);
 
 	return 0;
 }
@@ -66,9 +64,8 @@
 static int soft_spi_cs_deactivate(struct udevice *dev)
 {
 	struct soft_spi_platdata *plat = dev->platdata;
-	struct soft_spi_priv *priv = dev_get_priv(dev);
 
-	gpio_set_value(plat->cs.gpio, !(priv->mode & SPI_CS_HIGH));
+	dm_gpio_set_value(&plat->cs, 0);
 
 	return 0;
 }
@@ -109,7 +106,6 @@
 	uchar		tmpdout = 0;
 	const u8	*txd = dout;
 	u8		*rxd = din;
-	int		cpol = priv->mode & SPI_CPOL;
 	int		cpha = priv->mode & SPI_CPHA;
 	unsigned int	j;
 
@@ -137,19 +133,19 @@
 		}
 
 		if (!cpha)
-			soft_spi_scl(dev, !cpol);
+			soft_spi_scl(dev, 0);
 		soft_spi_sda(dev, tmpdout & 0x80);
 		udelay(plat->spi_delay_us);
 		if (cpha)
-			soft_spi_scl(dev, !cpol);
+			soft_spi_scl(dev, 0);
 		else
-			soft_spi_scl(dev, cpol);
+			soft_spi_scl(dev, 1);
 		tmpdin	<<= 1;
-		tmpdin	|= gpio_get_value(plat->miso.gpio);
+		tmpdin	|= dm_gpio_get_value(&plat->miso);
 		tmpdout	<<= 1;
 		udelay(plat->spi_delay_us);
 		if (cpha)
-			soft_spi_scl(dev, cpol);
+			soft_spi_scl(dev, 1);
 	}
 	/*
 	 * If the number of bits isn't a multiple of 8, shift the last
@@ -183,14 +179,6 @@
 	return 0;
 }
 
-static int soft_spi_child_pre_probe(struct udevice *dev)
-{
-	struct spi_slave *slave = dev_get_parentdata(dev);
-
-	slave->dev = dev;
-	return spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, slave);
-}
-
 static const struct dm_spi_ops soft_spi_ops = {
 	.claim_bus	= soft_spi_claim_bus,
 	.release_bus	= soft_spi_release_bus,
@@ -205,11 +193,6 @@
 	const void *blob = gd->fdt_blob;
 	int node = dev->of_offset;
 
-	if (fdtdec_decode_gpio(blob, node, "cs-gpio", &plat->cs) ||
-	    fdtdec_decode_gpio(blob, node, "sclk-gpio", &plat->sclk) ||
-	    fdtdec_decode_gpio(blob, node, "mosi-gpio", &plat->mosi) ||
-	    fdtdec_decode_gpio(blob, node, "miso-gpio", &plat->miso))
-		return -EINVAL;
 	plat->spi_delay_us = fdtdec_get_int(blob, node, "spi-delay-us", 0);
 
 	return 0;
@@ -219,16 +202,19 @@
 {
 	struct spi_slave *slave = dev_get_parentdata(dev);
 	struct soft_spi_platdata *plat = dev->platdata;
+	int cs_flags, clk_flags;
 
-	gpio_request(plat->cs.gpio, "soft_spi_cs");
-	gpio_request(plat->sclk.gpio, "soft_spi_sclk");
-	gpio_request(plat->mosi.gpio, "soft_spi_mosi");
-	gpio_request(plat->miso.gpio, "soft_spi_miso");
-
-	gpio_direction_output(plat->sclk.gpio, slave->mode & SPI_CPOL);
-	gpio_direction_output(plat->mosi.gpio, 1);
-	gpio_direction_input(plat->miso.gpio);
-	gpio_direction_output(plat->cs.gpio, !(slave->mode & SPI_CS_HIGH));
+	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,
+				 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))
+		return -EINVAL;
 
 	return 0;
 }
@@ -246,7 +232,5 @@
 	.ofdata_to_platdata = soft_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct soft_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct soft_spi_priv),
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.probe	= soft_spi_probe,
-	.child_pre_probe	= soft_spi_child_pre_probe,
 };
diff --git a/drivers/spi/spi-uclass.c b/drivers/spi/spi-uclass.c
index 7a57bce..63a6217 100644
--- a/drivers/spi/spi-uclass.c
+++ b/drivers/spi/spi-uclass.c
@@ -98,21 +98,51 @@
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
-int spi_post_probe(struct udevice *dev)
+int spi_child_post_bind(struct udevice *dev)
 {
-	struct dm_spi_bus *spi = dev->uclass_priv;
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 
-	spi->max_hz = fdtdec_get_int(gd->fdt_blob, dev->of_offset,
+	if (dev->of_offset == -1)
+		return 0;
+
+	return spi_slave_ofdata_to_platdata(gd->fdt_blob, dev->of_offset, plat);
+}
+
+int spi_post_probe(struct udevice *bus)
+{
+	struct dm_spi_bus *spi = bus->uclass_priv;
+
+	spi->max_hz = fdtdec_get_int(gd->fdt_blob, bus->of_offset,
 				     "spi-max-frequency", 0);
 
 	return 0;
 }
 
+int spi_child_pre_probe(struct udevice *dev)
+{
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
+	struct spi_slave *slave = dev_get_parentdata(dev);
+
+	/*
+	 * This is needed because we pass struct spi_slave around the place
+	 * instead slave->dev (a struct udevice). So we have to have some
+	 * way to access the slave udevice given struct spi_slave. Once we
+	 * change the SPI API to use udevice instead of spi_slave, we can
+	 * drop this.
+	 */
+	slave->dev = dev;
+
+	slave->max_hz = plat->max_hz;
+	slave->mode = plat->mode;
+
+	return 0;
+}
+
 int spi_chip_select(struct udevice *dev)
 {
-	struct spi_slave *slave = dev_get_parentdata(dev);
+	struct dm_spi_slave_platdata *plat = dev_get_parent_platdata(dev);
 
-	return slave ? slave->cs : -ENOENT;
+	return plat ? plat->cs : -ENOENT;
 }
 
 int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp)
@@ -121,17 +151,11 @@
 
 	for (device_find_first_child(bus, &dev); dev;
 	     device_find_next_child(&dev)) {
-		struct spi_slave store;
-		struct spi_slave *slave = dev_get_parentdata(dev);
+		struct dm_spi_slave_platdata *plat;
 
-		if (!slave)  {
-			slave = &store;
-			spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
-					       slave);
-		}
-		debug("%s: slave=%p, cs=%d\n", __func__, slave,
-		      slave ? slave->cs : -1);
-		if (slave && slave->cs == cs) {
+		plat = dev_get_parent_platdata(dev);
+		debug("%s: plat=%p, cs=%d\n", __func__, plat, plat->cs);
+		if (plat->cs == cs) {
 			*devp = dev;
 			return 0;
 		}
@@ -215,7 +239,6 @@
 		       struct udevice **busp, struct spi_slave **devp)
 {
 	struct udevice *bus, *dev;
-	struct spi_slave *slave;
 	bool created = false;
 	int ret;
 
@@ -232,11 +255,17 @@
 	 * SPI flash chip - we will bind to the correct driver.
 	 */
 	if (ret == -ENODEV && drv_name) {
+		struct dm_spi_slave_platdata *plat;
+
 		debug("%s: Binding new device '%s', busnum=%d, cs=%d, driver=%s\n",
 		      __func__, dev_name, busnum, cs, drv_name);
 		ret = device_bind_driver(bus, drv_name, dev_name, &dev);
 		if (ret)
 			return ret;
+		plat = dev_get_parent_platdata(dev);
+		plat->cs = cs;
+		plat->max_hz = speed;
+		plat->mode = mode;
 		created = true;
 	} else if (ret) {
 		printf("Invalid chip select %d:%d (err=%d)\n", busnum, cs,
@@ -245,23 +274,13 @@
 	}
 
 	if (!device_active(dev)) {
-		slave = (struct spi_slave *)calloc(1,
-						   sizeof(struct spi_slave));
-		if (!slave) {
-			ret = -ENOMEM;
-			goto err;
-		}
+		struct spi_slave *slave;
 
-		ret = spi_ofdata_to_platdata(gd->fdt_blob, dev->of_offset,
-					     slave);
+		ret = device_probe(dev);
 		if (ret)
 			goto err;
-		slave->cs = cs;
+		slave = dev_get_parentdata(dev);
 		slave->dev = dev;
-		ret = device_probe_child(dev, slave);
-		free(slave);
-		if (ret)
-			goto err;
 	}
 
 	ret = spi_set_speed_mode(bus, speed, mode);
@@ -275,6 +294,8 @@
 	return 0;
 
 err:
+	debug("%s: Error path, credted=%d, device '%s'\n", __func__,
+	      created, dev->name);
 	if (created) {
 		device_remove(dev);
 		device_unbind(dev);
@@ -321,13 +342,13 @@
 	slave->dev = NULL;
 }
 
-int spi_ofdata_to_platdata(const void *blob, int node,
-			   struct spi_slave *spi)
+int spi_slave_ofdata_to_platdata(const void *blob, int node,
+				 struct dm_spi_slave_platdata *plat)
 {
 	int mode = 0;
 
-	spi->cs = fdtdec_get_int(blob, node, "reg", -1);
-	spi->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
+	plat->cs = fdtdec_get_int(blob, node, "reg", -1);
+	plat->max_hz = fdtdec_get_int(blob, node, "spi-max-frequency", 0);
 	if (fdtdec_get_bool(blob, node, "spi-cpol"))
 		mode |= SPI_CPOL;
 	if (fdtdec_get_bool(blob, node, "spi-cpha"))
@@ -336,7 +357,7 @@
 		mode |= SPI_CS_HIGH;
 	if (fdtdec_get_bool(blob, node, "spi-half-duplex"))
 		mode |= SPI_PREAMBLE;
-	spi->mode = mode;
+	plat->mode = mode;
 
 	return 0;
 }
@@ -344,9 +365,15 @@
 UCLASS_DRIVER(spi) = {
 	.id		= UCLASS_SPI,
 	.name		= "spi",
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 	.post_bind	= spi_post_bind,
 	.post_probe	= spi_post_probe,
+	.child_pre_probe = spi_child_pre_probe,
 	.per_device_auto_alloc_size = sizeof(struct dm_spi_bus),
+	.per_child_auto_alloc_size = sizeof(struct spi_slave),
+	.per_child_platdata_auto_alloc_size =
+			sizeof(struct dm_spi_slave_platdata),
+	.child_post_bind = spi_child_post_bind,
 };
 
 UCLASS_DRIVER(spi_generic) = {
diff --git a/drivers/spi/tegra114_spi.c b/drivers/spi/tegra114_spi.c
index 2d97625..53ff9ea 100644
--- a/drivers/spi/tegra114_spi.c
+++ b/drivers/spi/tegra114_spi.c
@@ -407,6 +407,5 @@
 	.ofdata_to_platdata = tegra114_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct tegra114_spi_priv),
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.probe	= tegra114_spi_probe,
 };
diff --git a/drivers/spi/tegra20_sflash.c b/drivers/spi/tegra20_sflash.c
index 7d0d0f3..78c74cd 100644
--- a/drivers/spi/tegra20_sflash.c
+++ b/drivers/spi/tegra20_sflash.c
@@ -348,6 +348,5 @@
 	.ofdata_to_platdata = tegra20_sflash_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct tegra20_sflash_priv),
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.probe	= tegra20_sflash_probe,
 };
diff --git a/drivers/spi/tegra20_slink.c b/drivers/spi/tegra20_slink.c
index 213fa5f..597d6ad 100644
--- a/drivers/spi/tegra20_slink.c
+++ b/drivers/spi/tegra20_slink.c
@@ -361,6 +361,5 @@
 	.ofdata_to_platdata = tegra30_spi_ofdata_to_platdata,
 	.platdata_auto_alloc_size = sizeof(struct tegra_spi_platdata),
 	.priv_auto_alloc_size = sizeof(struct tegra30_spi_priv),
-	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
 	.probe	= tegra30_spi_probe,
 };
diff --git a/drivers/usb/host/ehci-exynos.c b/drivers/usb/host/ehci-exynos.c
index 6fdbf57..f3c077d 100644
--- a/drivers/usb/host/ehci-exynos.c
+++ b/drivers/usb/host/ehci-exynos.c
@@ -31,7 +31,7 @@
 struct exynos_ehci {
 	struct exynos_usb_phy *usb;
 	struct ehci_hccr *hcd;
-	struct fdt_gpio_state vbus_gpio;
+	struct gpio_desc vbus_gpio;
 };
 
 static struct exynos_ehci exynos;
@@ -61,7 +61,8 @@
 	exynos->hcd = (struct ehci_hccr *)addr;
 
 	/* Vbus gpio */
-	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
+	gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
+				   &exynos->vbus_gpio, GPIOD_IS_OUT);
 
 	depth = 0;
 	node = fdtdec_next_compatible_subnode(blob, node,
@@ -236,9 +237,8 @@
 
 #ifdef CONFIG_OF_CONTROL
 	/* setup the Vbus gpio here */
-	if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
-	    !fdtdec_setup_gpio(&ctx->vbus_gpio))
-		gpio_direction_output(ctx->vbus_gpio.gpio, 1);
+	if (dm_gpio_is_valid(&ctx->vbus_gpio))
+		dm_gpio_set_value(&ctx->vbus_gpio, 1);
 #endif
 
 	setup_usb_phy(ctx->usb);
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index 5f0a98e..b5ad1e3 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -72,8 +72,8 @@
 	enum usb_init_type init_type;
 	enum dr_mode dr_mode;	/* dual role mode */
 	enum periph_id periph_id;/* peripheral id */
-	struct fdt_gpio_state vbus_gpio;	/* GPIO for vbus enable */
-	struct fdt_gpio_state phy_reset_gpio; /* GPIO to reset ULPI phy */
+	struct gpio_desc vbus_gpio;	/* GPIO for vbus enable */
+	struct gpio_desc phy_reset_gpio; /* GPIO to reset ULPI phy */
 };
 
 static struct fdt_usb port[USB_PORTS_MAX];	/* List of valid USB ports */
@@ -252,17 +252,14 @@
 		return;
 	}
 
-	if (fdt_gpio_isvalid(&config->vbus_gpio)) {
+	if (dm_gpio_is_valid(&config->vbus_gpio)) {
 		int vbus_value;
 
-		fdtdec_setup_gpio(&config->vbus_gpio);
+		vbus_value = (init == USB_INIT_HOST);
+		dm_gpio_set_value(&config->vbus_gpio, vbus_value);
 
-		vbus_value = (init == USB_INIT_HOST) ^
-			     !!(config->vbus_gpio.flags & FDT_GPIO_ACTIVE_LOW);
-		gpio_direction_output(config->vbus_gpio.gpio, vbus_value);
-
-		debug("set_up_vbus: GPIO %d %d\n", config->vbus_gpio.gpio,
-		      vbus_value);
+		debug("set_up_vbus: GPIO %d %d\n",
+		      gpio_get_number(&config->vbus_gpio), vbus_value);
 	}
 }
 
@@ -360,7 +357,7 @@
 	 * mux must be switched to actually use a_sess_vld threshold.
 	 */
 	if (config->dr_mode == DR_MODE_OTG &&
-	    fdt_gpio_isvalid(&config->vbus_gpio))
+	    dm_gpio_is_valid(&config->vbus_gpio))
 		clrsetbits_le32(&usbctlr->usb1_legacy_ctrl,
 			VBUS_SENSE_CTL_MASK,
 			VBUS_SENSE_CTL_A_SESS_VLD << VBUS_SENSE_CTL_SHIFT);
@@ -569,11 +566,10 @@
 	clock_set_pllout(CLOCK_ID_PERIPH, PLL_OUT4, CONFIG_ULPI_REF_CLK);
 
 	/* reset ULPI phy */
-	if (fdt_gpio_isvalid(&config->phy_reset_gpio)) {
-		fdtdec_setup_gpio(&config->phy_reset_gpio);
-		gpio_direction_output(config->phy_reset_gpio.gpio, 0);
+	if (dm_gpio_is_valid(&config->phy_reset_gpio)) {
+		dm_gpio_set_value(&config->phy_reset_gpio, 0);
 		mdelay(5);
-		gpio_set_value(config->phy_reset_gpio.gpio, 1);
+		dm_gpio_set_value(&config->phy_reset_gpio, 1);
 	}
 
 	/* Reset the usb controller */
@@ -685,14 +681,16 @@
 		debug("%s: Missing/invalid peripheral ID\n", __func__);
 		return -FDT_ERR_NOTFOUND;
 	}
-	fdtdec_decode_gpio(blob, node, "nvidia,vbus-gpio", &config->vbus_gpio);
-	fdtdec_decode_gpio(blob, node, "nvidia,phy-reset-gpio",
-			&config->phy_reset_gpio);
+	gpio_request_by_name_nodev(blob, node, "nvidia,vbus-gpio", 0,
+				   &config->vbus_gpio, GPIOD_IS_OUT);
+	gpio_request_by_name_nodev(blob, node, "nvidia,phy-reset-gpio", 0,
+				   &config->phy_reset_gpio, GPIOD_IS_OUT);
 	debug("enabled=%d, legacy_mode=%d, utmi=%d, ulpi=%d, periph_id=%d, "
 		"vbus=%d, phy_reset=%d, dr_mode=%d\n",
 		config->enabled, config->has_legacy_mode, config->utmi,
-		config->ulpi, config->periph_id, config->vbus_gpio.gpio,
-		config->phy_reset_gpio.gpio, config->dr_mode);
+		config->ulpi, config->periph_id,
+		gpio_get_number(&config->vbus_gpio),
+		gpio_get_number(&config->phy_reset_gpio), config->dr_mode);
 
 	return 0;
 }
diff --git a/drivers/usb/host/xhci-exynos5.c b/drivers/usb/host/xhci-exynos5.c
index b4946a3..a77c8bc 100644
--- a/drivers/usb/host/xhci-exynos5.c
+++ b/drivers/usb/host/xhci-exynos5.c
@@ -40,7 +40,7 @@
 	struct exynos_usb3_phy *usb3_phy;
 	struct xhci_hccr *hcd;
 	struct dwc3 *dwc3_reg;
-	struct fdt_gpio_state vbus_gpio;
+	struct gpio_desc vbus_gpio;
 };
 
 static struct exynos_xhci exynos;
@@ -69,7 +69,8 @@
 	exynos->hcd = (struct xhci_hccr *)addr;
 
 	/* Vbus gpio */
-	fdtdec_decode_gpio(blob, node, "samsung,vbus-gpio", &exynos->vbus_gpio);
+	gpio_request_by_name_nodev(blob, node, "samsung,vbus-gpio", 0,
+				   &exynos->vbus_gpio, GPIOD_IS_OUT);
 
 	depth = 0;
 	node = fdtdec_next_compatible_subnode(blob, node,
@@ -298,9 +299,8 @@
 
 #ifdef CONFIG_OF_CONTROL
 	/* setup the Vbus gpio here */
-	if (fdt_gpio_isvalid(&ctx->vbus_gpio) &&
-	    !fdtdec_setup_gpio(&ctx->vbus_gpio))
-		gpio_direction_output(ctx->vbus_gpio.gpio, 1);
+	if (dm_gpio_is_valid(&ctx->vbus_gpio))
+		dm_gpio_set_value(&ctx->vbus_gpio, 1);
 #endif
 
 	ret = exynos_xhci_core_init(ctx);
diff --git a/drivers/video/tegra.c b/drivers/video/tegra.c
index 57cb007..b8f3431 100644
--- a/drivers/video/tegra.c
+++ b/drivers/video/tegra.c
@@ -149,14 +149,18 @@
 					    FDT_LCD_CACHE_WRITE_BACK_FLUSH);
 
 	/* These GPIOs are all optional */
-	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-enable-gpios",
-			    &config->backlight_en);
-	fdtdec_decode_gpio(blob, display_node, "nvidia,lvds-shutdown-gpios",
-			   &config->lvds_shutdown);
-	fdtdec_decode_gpio(blob, display_node, "nvidia,backlight-vdd-gpios",
-			   &config->backlight_vdd);
-	fdtdec_decode_gpio(blob, display_node, "nvidia,panel-vdd-gpios",
-			   &config->panel_vdd);
+	gpio_request_by_name_nodev(blob, display_node,
+				   "nvidia,backlight-enable-gpios", 0,
+				   &config->backlight_en, GPIOD_IS_OUT);
+	gpio_request_by_name_nodev(blob, display_node,
+				   "nvidia,lvds-shutdown-gpios", 0,
+				   &config->lvds_shutdown, GPIOD_IS_OUT);
+	gpio_request_by_name_nodev(blob, display_node,
+				   "nvidia,backlight-vdd-gpios", 0,
+				   &config->backlight_vdd, GPIOD_IS_OUT);
+	gpio_request_by_name_nodev(blob, display_node,
+				   "nvidia,panel-vdd-gpios", 0,
+				   &config->panel_vdd, GPIOD_IS_OUT);
 
 	return fdtdec_get_int_array(blob, display_node, "nvidia,panel-timings",
 			config->panel_timings, FDT_LCD_TIMINGS);
@@ -196,36 +200,18 @@
 		 */
 
 		funcmux_select(PERIPH_ID_DISP1, FUNCMUX_DEFAULT);
-
-		fdtdec_setup_gpio(&config.panel_vdd);
-		fdtdec_setup_gpio(&config.lvds_shutdown);
-		fdtdec_setup_gpio(&config.backlight_vdd);
-		fdtdec_setup_gpio(&config.backlight_en);
-
-		/*
-		 * TODO: If fdt includes output flag we can omit this code
-		 * since fdtdec_setup_gpio will do it for us.
-		 */
-		if (fdt_gpio_isvalid(&config.panel_vdd))
-			gpio_direction_output(config.panel_vdd.gpio, 0);
-		if (fdt_gpio_isvalid(&config.lvds_shutdown))
-			gpio_direction_output(config.lvds_shutdown.gpio, 0);
-		if (fdt_gpio_isvalid(&config.backlight_vdd))
-			gpio_direction_output(config.backlight_vdd.gpio, 0);
-		if (fdt_gpio_isvalid(&config.backlight_en))
-			gpio_direction_output(config.backlight_en.gpio, 0);
 		break;
 	case STAGE_PANEL_VDD:
-		if (fdt_gpio_isvalid(&config.panel_vdd))
-			gpio_direction_output(config.panel_vdd.gpio, 1);
+		if (dm_gpio_is_valid(&config.panel_vdd))
+			dm_gpio_set_value(&config.panel_vdd, 1);
 		break;
 	case STAGE_LVDS:
-		if (fdt_gpio_isvalid(&config.lvds_shutdown))
-			gpio_set_value(config.lvds_shutdown.gpio, 1);
+		if (dm_gpio_is_valid(&config.lvds_shutdown))
+			dm_gpio_set_value(&config.lvds_shutdown, 1);
 		break;
 	case STAGE_BACKLIGHT_VDD:
-		if (fdt_gpio_isvalid(&config.backlight_vdd))
-			gpio_set_value(config.backlight_vdd.gpio, 1);
+		if (dm_gpio_is_valid(&config.backlight_vdd))
+			dm_gpio_set_value(&config.backlight_vdd, 1);
 		break;
 	case STAGE_PWM:
 		/* Enable PWM at 15/16 high, 32768 Hz with divider 1 */
@@ -235,8 +221,8 @@
 		pwm_enable(config.pwm_channel, 32768, 0xdf, 1);
 		break;
 	case STAGE_BACKLIGHT_EN:
-		if (fdt_gpio_isvalid(&config.backlight_en))
-			gpio_set_value(config.backlight_en.gpio, 1);
+		if (dm_gpio_is_valid(&config.backlight_en))
+			dm_gpio_set_value(&config.backlight_en, 1);
 		break;
 	case STAGE_DONE:
 		break;
diff --git a/examples/standalone/stubs.c b/examples/standalone/stubs.c
index 0bf690e..920a0a9 100644
--- a/examples/standalone/stubs.c
+++ b/examples/standalone/stubs.c
@@ -2,6 +2,8 @@
 #include <exports.h>
 #include <linux/compiler.h>
 
+#define FO(x) offsetof(struct jt_funcs, x)
+
 #if defined(CONFIG_X86)
 /*
  * x86 does not have a dedicated register to store the pointer to
@@ -10,23 +12,23 @@
  * from flash memory. The global_data address is passed as argv[-1]
  * to the application program.
  */
-static void **jt;
+static struct jt_funcs *jt;
 gd_t *global_data;
 
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
 "	movl	%0, %%eax\n"		\
 "	movl	jt, %%ecx\n"		\
 "	jmp	*(%%ecx, %%eax)\n"	\
-	: : "i"(XF_ ## x * sizeof(void *)) : "eax", "ecx");
+	: : "i"(FO(x)) : "eax", "ecx");
 #elif defined(CONFIG_PPC)
 /*
  * r2 holds the pointer to the global_data, r11 is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
@@ -34,33 +36,33 @@
 "	lwz	%%r11, %1(%%r11)\n"	\
 "	mtctr	%%r11\n"		\
 "	bctr\n"				\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r11");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r11");
 #elif defined(CONFIG_ARM)
 #ifdef CONFIG_ARM64
 /*
  * x18 holds the pointer to the global_data, x9 is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
 "	ldr	x9, [x18, %0]\n"		\
 "	ldr	x9, [x9, %1]\n"		\
 "	br	x9\n"		\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "x9");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "x9");
 #else
 /*
  * r9 holds the pointer to the global_data, ip is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
 "	ldr	ip, [r9, %0]\n"		\
 "	ldr	pc, [ip, %1]\n"		\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "ip");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "ip");
 #endif
 #elif defined(CONFIG_MIPS)
 /*
@@ -70,19 +72,19 @@
  * it; however, GCC/mips generates an additional `nop' after each asm
  * statement
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
 "	lw	$25, %0($26)\n"		\
 "	lw	$25, %1($25)\n"		\
 "	jr	$25\n"			\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "t9");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "t9");
 #elif defined(CONFIG_NIOS2)
 /*
  * gp holds the pointer to the global_data, r8 is call-clobbered
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
@@ -92,13 +94,13 @@
 "	ldw	r8, 0(r8)\n"		\
 "	ldw	r8, %1(r8)\n"		\
 "	jmp	r8\n"			\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "gp");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "gp");
 #elif defined(CONFIG_M68K)
 /*
  * d7 holds the pointer to the global_data, a0 is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
@@ -108,50 +110,50 @@
 "	adda.l	%1, %%a0\n"		\
 "	move.l	(%%a0), %%a0\n"		\
 "	jmp	(%%a0)\n"			\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "a0");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "a0");
 #elif defined(CONFIG_MICROBLAZE)
 /*
  * r31 holds the pointer to the global_data. r5 is a call-clobbered.
  */
-#define EXPORT_FUNC(x)				\
+#define EXPORT_FUNC(f, a, x, ...)				\
 	asm volatile (				\
 "	.globl " #x "\n"			\
 #x ":\n"					\
 "	lwi	r5, r31, %0\n"			\
 "	lwi	r5, r5, %1\n"			\
 "	bra	r5\n"				\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r5");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r5");
 #elif defined(CONFIG_BLACKFIN)
 /*
  * P3 holds the pointer to the global_data, P0 is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x)			\
+#define EXPORT_FUNC(f, a, x, ...)			\
 	asm volatile (			\
 "	.globl _" #x "\n_"		\
 #x ":\n"				\
 "	P0 = [P3 + %0]\n"		\
 "	P0 = [P0 + %1]\n"		\
 "	JUMP (P0)\n"			\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "P0");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "P0");
 #elif defined(CONFIG_AVR32)
 /*
  * r6 holds the pointer to the global_data. r8 is call clobbered.
  */
-#define EXPORT_FUNC(x)					\
+#define EXPORT_FUNC(f, a, x, ...)					\
 	asm volatile(					\
 		"	.globl\t" #x "\n"		\
 		#x ":\n"				\
 		"	ld.w	r8, r6[%0]\n"		\
 		"	ld.w	pc, r8[%1]\n"		\
 		:					\
-		: "i"(offsetof(gd_t, jt)), "i"(XF_ ##x)	\
+		: "i"(offsetof(gd_t, jt)), "i"(FO(x))	\
 		: "r8");
 #elif defined(CONFIG_SH)
 /*
  * r13 holds the pointer to the global_data. r1 is a call clobbered.
  */
-#define EXPORT_FUNC(x)					\
+#define EXPORT_FUNC(f, a, x, ...)					\
 	asm volatile (					\
 		"	.align	2\n"			\
 		"	.globl " #x "\n"		\
@@ -164,12 +166,12 @@
 		"	jmp	@r1\n"			\
 		"	nop\n"				\
 		"	nop\n"				\
-		: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r1", "r2");
+		: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r1", "r2");
 #elif defined(CONFIG_SPARC)
 /*
  * g7 holds the pointer to the global_data. g1 is call clobbered.
  */
-#define EXPORT_FUNC(x)					\
+#define EXPORT_FUNC(f, a, x, ...)					\
 	asm volatile(					\
 "	.globl\t" #x "\n"				\
 #x ":\n"						\
@@ -179,26 +181,26 @@
 "	ld [%%g1 + %1], %%g1\n"				\
 "	jmp %%g1\n"					\
 "	nop\n"						\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "g1" );
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "g1");
 #elif defined(CONFIG_NDS32)
 /*
  * r16 holds the pointer to the global_data. gp is call clobbered.
  * not support reduced register (16 GPR).
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
 "	lwi	$r16, [$gp + (%0)]\n"	\
 "	lwi	$r16, [$r16 + (%1)]\n"	\
 "	jr	$r16\n"			\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "$r16");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "$r16");
 #elif defined(CONFIG_OPENRISC)
 /*
  * r10 holds the pointer to the global_data, r13 is a call-clobbered
  * register
  */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile (			\
 "	.globl " #x "\n"		\
 #x ":\n"				\
@@ -206,12 +208,12 @@
 "	l.lwz	r13, %1(r13)\n"	\
 "	l.jr	r13\n"		\
 "	l.nop\n"				\
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r13");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r13");
 #elif defined(CONFIG_ARC)
 /*
  * r25 holds the pointer to the global_data. r10 is call clobbered.
   */
-#define EXPORT_FUNC(x) \
+#define EXPORT_FUNC(f, a, x, ...) \
 	asm volatile( \
 "	.align 4\n" \
 "	.globl " #x "\n" \
@@ -219,7 +221,7 @@
 "	ld	r10, [r25, %0]\n" \
 "	ld	r10, [r10, %1]\n" \
 "	j	[r10]\n" \
-	: : "i"(offsetof(gd_t, jt)), "i"(XF_ ## x * sizeof(void *)) : "r10");
+	: : "i"(offsetof(gd_t, jt)), "i"(FO(x)) : "r10");
 #else
 /*"	addi	$sp, $sp, -24\n"	\
 "	br	$r16\n"			\*/
diff --git a/include/_exports.h b/include/_exports.h
index 349a3c5..5944703 100644
--- a/include/_exports.h
+++ b/include/_exports.h
@@ -1,32 +1,73 @@
 /*
- * You do not need to use #ifdef around functions that may not exist
+ * You need to use #ifdef around functions that may not exist
  * in the final configuration (such as i2c).
+ * use a dummyfunction as first parameter to EXPORT_FUNC.
+ * As an example see the CONFIG_CMD_I2C section below
  */
-EXPORT_FUNC(get_version)
-EXPORT_FUNC(getc)
-EXPORT_FUNC(tstc)
-EXPORT_FUNC(putc)
-EXPORT_FUNC(puts)
-EXPORT_FUNC(printf)
-EXPORT_FUNC(install_hdlr)
-EXPORT_FUNC(free_hdlr)
-EXPORT_FUNC(malloc)
-EXPORT_FUNC(free)
-EXPORT_FUNC(udelay)
-EXPORT_FUNC(get_timer)
-EXPORT_FUNC(vprintf)
-EXPORT_FUNC(do_reset)
-EXPORT_FUNC(getenv)
-EXPORT_FUNC(setenv)
-EXPORT_FUNC(simple_strtoul)
-EXPORT_FUNC(strict_strtoul)
-EXPORT_FUNC(simple_strtol)
-EXPORT_FUNC(strcmp)
-EXPORT_FUNC(i2c_write)
-EXPORT_FUNC(i2c_read)
-EXPORT_FUNC(spi_init)
-EXPORT_FUNC(spi_setup_slave)
-EXPORT_FUNC(spi_free_slave)
-EXPORT_FUNC(spi_claim_bus)
-EXPORT_FUNC(spi_release_bus)
-EXPORT_FUNC(spi_xfer)
+#ifndef EXPORT_FUNC
+#define EXPORT_FUNC(a, b, c, ...)
+#endif
+	EXPORT_FUNC(get_version, unsigned long, get_version, void)
+	EXPORT_FUNC(getc, int, getc, void)
+	EXPORT_FUNC(tstc, int, tstc, void)
+	EXPORT_FUNC(putc, void, putc, const char)
+	EXPORT_FUNC(puts, void, puts, const char *)
+	EXPORT_FUNC(printf, int, printf, const char*, ...)
+#if defined(CONFIG_X86) || defined(CONFIG_PPC)
+	EXPORT_FUNC(irq_install_handler, void, install_hdlr,
+		    int, interrupt_handler_t, void*)
+
+	EXPORT_FUNC(irq_free_handler, void, free_hdlr, int)
+#else
+	EXPORT_FUNC(dummy, void, install_hdlr, void)
+	EXPORT_FUNC(dummy, void, free_hdlr, void)
+#endif
+	EXPORT_FUNC(malloc, void *, malloc, size_t)
+	EXPORT_FUNC(free, void, free, void *)
+	EXPORT_FUNC(udelay, void, udelay, unsigned long)
+	EXPORT_FUNC(get_timer, unsigned long, get_timer, unsigned long)
+	EXPORT_FUNC(vprintf, int, vprintf, const char *, va_list)
+	EXPORT_FUNC(do_reset, int, do_reset, cmd_tbl_t *,
+		    int , int , char * const [])
+	EXPORT_FUNC(getenv, char  *, getenv, const char*)
+	EXPORT_FUNC(setenv, int, setenv, const char *, const char *)
+	EXPORT_FUNC(simple_strtoul, unsigned long, simple_strtoul,
+		    const char *, char **, unsigned int)
+	EXPORT_FUNC(strict_strtoul, int, strict_strtoul,
+		    const char *, unsigned int , unsigned long *)
+	EXPORT_FUNC(simple_strtol, long, simple_strtol,
+		    const char *, char **, unsigned int)
+	EXPORT_FUNC(strcmp, int, strcmp, const char *cs, const char *ct)
+#if defined(CONFIG_CMD_I2C) && \
+		(!defined(CONFIG_DM_I2C) || defined(CONFIG_DM_I2C_COMPAT))
+	EXPORT_FUNC(i2c_write, int, i2c_write, uchar, uint, int , uchar * , int)
+	EXPORT_FUNC(i2c_read, int, i2c_read, uchar, uint, int , uchar * , int)
+#else
+	EXPORT_FUNC(dummy, void, i2c_write, void)
+	EXPORT_FUNC(dummy, void, i2c_read, void)
+#endif
+
+#if !defined(CONFIG_CMD_SPI) || defined(CONFIG_DM_SPI)
+	EXPORT_FUNC(dummy, void, spi_init, void)
+	EXPORT_FUNC(dummy, void, spi_setup_slave, void)
+	EXPORT_FUNC(dummy, void, spi_free_slave, void)
+#else
+	EXPORT_FUNC(spi_init, void, spi_init, void)
+	EXPORT_FUNC(spi_setup_slave, struct spi_slave *, spi_setup_slave,
+		    unsigned int, unsigned int, unsigned int, unsigned int)
+	EXPORT_FUNC(spi_free_slave, void, spi_free_slave, struct spi_slave *)
+#endif
+#ifndef CONFIG_CMD_SPI
+	EXPORT_FUNC(dummy, void, spi_claim_bus, void)
+	EXPORT_FUNC(dummy, void, spi_release_bus, void)
+	EXPORT_FUNC(dummy, void, spi_xfer, void)
+#else
+	EXPORT_FUNC(spi_claim_bus, int, spi_claim_bus, struct spi_slave *)
+	EXPORT_FUNC(spi_release_bus, void, spi_release_bus, struct spi_slave *)
+	EXPORT_FUNC(spi_xfer, int, spi_xfer, struct spi_slave *,
+		    unsigned int, const void *, void *, unsigned long)
+#endif
+	EXPORT_FUNC(ustrtoul, unsigned long, ustrtoul,
+		    const char *, char **, unsigned int)
+	EXPORT_FUNC(ustrtoull, unsigned long long, ustrtoull,
+		    const char *, char **, unsigned int)
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 3d14d5f1..6747619 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -73,7 +73,7 @@
 	const void *fdt_blob;	/* Our device tree, NULL if none */
 	void *new_fdt;		/* Relocated FDT */
 	unsigned long fdt_size;	/* Space reserved for relocated FDT */
-	void **jt;		/* jump table */
+	struct jt_funcs *jt;		/* jump table */
 	char env_buf[32];	/* buffer for getenv() before reloc. */
 #ifdef CONFIG_TRACE
 	void		*trace_buff;	/* The trace buffer */
diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
index 36a36c6..3b96b82 100644
--- a/include/asm-generic/gpio.h
+++ b/include/asm-generic/gpio.h
@@ -10,6 +10,15 @@
 /*
  * Generic GPIO API for U-Boot
  *
+ * --
+ * NB: This is deprecated. Please use the driver model functions instead:
+ *
+ *    - gpio_request_by_name()
+ *    - dm_gpio_get_value() etc.
+ *
+ * For now we need a dm_ prefix on some functions to avoid name collision.
+ * --
+ *
  * GPIOs are numbered from 0 to GPIO_COUNT-1 which value is defined
  * by the SOC/architecture.
  *
@@ -26,6 +35,7 @@
  */
 
 /**
+ * @deprecated	Please use driver model instead
  * Request a GPIO. This should be called before any of the other functions
  * are used on this GPIO.
  *
@@ -39,6 +49,7 @@
 int gpio_request(unsigned gpio, const char *label);
 
 /**
+ * @deprecated	Please use driver model instead
  * Stop using the GPIO.  This function should not alter pin configuration.
  *
  * @param gpio	GPIO number
@@ -47,6 +58,7 @@
 int gpio_free(unsigned gpio);
 
 /**
+ * @deprecated	Please use driver model instead
  * Make a GPIO an input.
  *
  * @param gpio	GPIO number
@@ -55,6 +67,7 @@
 int gpio_direction_input(unsigned gpio);
 
 /**
+ * @deprecated	Please use driver model instead
  * Make a GPIO an output, and set its value.
  *
  * @param gpio	GPIO number
@@ -64,6 +77,7 @@
 int gpio_direction_output(unsigned gpio, int value);
 
 /**
+ * @deprecated	Please use driver model instead
  * Get a GPIO's value. This will work whether the GPIO is an input
  * or an output.
  *
@@ -73,6 +87,7 @@
 int gpio_get_value(unsigned gpio);
 
 /**
+ * @deprecated	Please use driver model instead
  * Set an output GPIO's value. The GPIO must already be an output or
  * this function may have no effect.
  *
@@ -95,6 +110,34 @@
 
 struct udevice;
 
+struct gpio_desc {
+	struct udevice *dev;	/* Device, NULL for invalid GPIO */
+	unsigned long flags;
+#define GPIOD_REQUESTED		(1 << 0)	/* Requested/claimed */
+#define GPIOD_IS_OUT		(1 << 1)	/* GPIO is an output */
+#define GPIOD_IS_IN		(1 << 2)	/* GPIO is an output */
+#define GPIOD_ACTIVE_LOW	(1 << 3)	/* value has active low */
+#define GPIOD_IS_OUT_ACTIVE	(1 << 4)	/* set output active */
+
+	uint offset;		/* GPIO offset within the device */
+	/*
+	 * We could consider adding the GPIO label in here. Possibly we could
+	 * use this structure for internal GPIO information.
+	 */
+};
+
+/**
+ * dm_gpio_is_valid() - Check if a GPIO is gpio_is_valie
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @return true if valid, false if not
+ */
+static inline bool dm_gpio_is_valid(struct gpio_desc *desc)
+{
+	return desc->dev != NULL;
+}
+
 /**
  * gpio_get_status() - get the current GPIO status as a string
  *
@@ -106,6 +149,8 @@
  * which means this is GPIO bank b, offset 4, currently set to input, current
  * value 1, [x] means that it is requested and the owner is 'sdmmc_cd'
  *
+ * TODO(sjg@chromium.org): This should use struct gpio_desc
+ *
  * @dev:	Device to check
  * @offset:	Offset of device GPIO to check
  * @buf:	Place to put string
@@ -118,6 +163,8 @@
  *
  * Note this returns GPIOF_UNUSED if the GPIO is not requested.
  *
+ * TODO(sjg@chromium.org): This should use struct gpio_desc
+ *
  * @dev:	Device to check
  * @offset:	Offset of device GPIO to check
  * @namep:	If non-NULL, this is set to the nane given when the GPIO
@@ -135,6 +182,8 @@
  * Note this does not return GPIOF_UNUSED - it will always return the GPIO
  * driver's view of a pin function, even if it is not correctly set up.
  *
+ * TODO(sjg@chromium.org): This should use struct gpio_desc
+ *
  * @dev:	Device to check
  * @offset:	Offset of device GPIO to check
  * @namep:	If non-NULL, this is set to the nane given when the GPIO
@@ -155,6 +204,8 @@
 int gpio_requestf(unsigned gpio, const char *fmt, ...)
 		__attribute__ ((format (__printf__, 2, 3)));
 
+struct fdtdec_phandle_args;
+
 /**
  * struct struct dm_gpio_ops - Driver model GPIO operations
  *
@@ -198,6 +249,33 @@
 	 * @return current function - GPIOF_...
 	 */
 	int (*get_function)(struct udevice *dev, unsigned offset);
+
+	/**
+	 * xlate() - Translate phandle arguments into a GPIO description
+	 *
+	 * This function should set up the fields in desc according to the
+	 * information in the arguments. The uclass will have set up:
+	 *
+	 *   @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)
+	 *
+	 * 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.
+	 *
+	 * Note that @dev is passed in as a parameter to follow driver model
+	 * uclass conventions, even though it is already available as
+	 * desc->dev.
+	 *
+	 * @dev:	GPIO device
+	 * @desc:	Place to put GPIO description
+	 * @args:	Arguments provided in descripion
+	 * @return 0 if OK, -ve on error
+	 */
+	int (*xlate)(struct udevice *dev, struct gpio_desc *desc,
+		     struct fdtdec_phandle_args *args);
 };
 
 /**
@@ -268,4 +346,191 @@
  */
 unsigned gpio_get_values_as_int(const int *gpio_list);
 
+/**
+ * gpio_request_by_name() - Locate and request a GPIO by name
+ *
+ * This operates by looking up the given list name in the device (device
+ * tree property) and requesting the GPIO for use. The property must exist
+ * in @dev's node.
+ *
+ * Use @flags to specify whether the GPIO should be an input or output. In
+ * principle this can also come from the device tree binding but most
+ * bindings don't provide this information. Specifically, when the GPIO uclass
+ * calls the xlate() method, it can return default flags, which are then
+ * ORed with this @flags.
+ *
+ * If we find that requesting the GPIO is not always needed we could add a
+ * new function or a new GPIOD_NO_REQUEST flag.
+ *
+ * At present driver model has no reference counting so if one device
+ * requests a GPIO which subsequently is unbound, the @desc->dev pointer
+ * will be invalid. However this will only happen if the GPIO device is
+ * unbound, not if it is removed, so this seems like a reasonable limitation
+ * for now. There is no real use case for unbinding drivers in normal
+ * operation.
+ *
+ * The device tree binding is doc/device-tree-bindings/gpio/gpio.txt in
+ * generate terms and each specific device may add additional details in
+ * a binding file in the same directory.
+ *
+ * @dev:	Device requesting the GPIO
+ * @list_name:	Name of GPIO list (e.g. "board-id-gpios")
+ * @index:	Index number of the GPIO in that list use request (0=first)
+ * @desc:	Returns GPIO description information. If there is no such
+ *		GPIO, dev->dev will be NULL.
+ * @flags:	Indicates the GPIO input/output settings (GPIOD_...)
+ * @return 0 if OK, -ENOENT if the GPIO does not exist, -EINVAL if there is
+ * something wrong with the list, or other -ve for another error (e.g.
+ * -EBUSY if a GPIO was already requested)
+ */
+int gpio_request_by_name(struct udevice *dev, const char *list_name,
+			 int index, struct gpio_desc *desc, int flags);
+
+/**
+ * gpio_request_list_by_name() - Request a list of GPIOs
+ *
+ * Reads all the GPIOs from a list and requetss them. See
+ * gpio_request_by_name() for additional details. Lists should not be
+ * misused to hold unrelated or optional GPIOs. They should only be used
+ * for things like parallel data lines. A zero phandle terminates the list
+ * the list.
+ *
+ * This function will either succeed, and request all GPIOs in the list, or
+ * fail and request none (it will free already-requested GPIOs in case of
+ * an error part-way through).
+ *
+ * @dev:	Device requesting the GPIO
+ * @list_name:	Name of GPIO list (e.g. "board-id-gpios")
+ * @desc_list:	Returns a list of GPIO description information
+ * @max_count:	Maximum number of GPIOs to return (@desc_list must be at least
+ *		this big)
+ * @flags:	Indicates the GPIO input/output settings (GPIOD_...)
+ * @return number of GPIOs requested, or -ve on error
+ */
+int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
+			      struct gpio_desc *desc_list, int max_count,
+			      int flags);
+
+/**
+ * gpio_get_list_count() - Returns the number of GPIOs in a list
+ *
+ * Counts the GPIOs in a list. See gpio_request_by_name() for additional
+ * details.
+ *
+ * @dev:	Device requesting the GPIO
+ * @list_name:	Name of GPIO list (e.g. "board-id-gpios")
+ * @return number of GPIOs (0 for an empty property) or -ENOENT if the list
+ * does not exist
+ */
+int gpio_get_list_count(struct udevice *dev, const char *list_name);
+
+/**
+ * gpio_request_by_name_nodev() - request GPIOs without a device
+ *
+ * This is a version of gpio_request_list_by_name() that does not use a
+ * device. Avoid it unless the caller is not yet using driver model
+ */
+int gpio_request_by_name_nodev(const void *blob, int node,
+			       const char *list_name,
+			       int index, struct gpio_desc *desc, int flags);
+
+/**
+ * gpio_request_list_by_name_nodev() - request GPIOs without a device
+ *
+ * This is a version of gpio_request_list_by_name() that does not use a
+ * device. Avoid it unless the caller is not yet using driver model
+ */
+int gpio_request_list_by_name_nodev(const void *blob, int node,
+				    const char *list_name,
+				    struct gpio_desc *desc_list, int max_count,
+				    int flags);
+
+/**
+ * dm_gpio_free() - Free a single GPIO
+ *
+ * This frees a single GPIOs previously returned from gpio_request_by_name().
+ *
+ * @dev:	Device which requested the GPIO
+ * @desc:	GPIO to free
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc);
+
+/**
+ * gpio_free_list() - Free a list of GPIOs
+ *
+ * This frees a list of GPIOs previously returned from
+ * gpio_request_list_by_name().
+ *
+ * @dev:	Device which requested the GPIOs
+ * @desc:	List of GPIOs to free
+ * @count:	Number of GPIOs in the list
+ * @return 0 if OK, -ve on error
+ */
+int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count);
+
+/**
+ * gpio_free_list_nodev() - free GPIOs without a device
+ *
+ * This is a version of gpio_free_list() that does not use a
+ * device. Avoid it unless the caller is not yet using driver model
+ */
+int gpio_free_list_nodev(struct gpio_desc *desc, int count);
+
+/**
+ * dm_gpio_get_value() - Get the value of a GPIO
+ *
+ * This is the driver model version of the existing gpio_get_value() function
+ * and should be used instead of that.
+ *
+ * For now, these functions have a dm_ prefix since they conflict with
+ * existing names.
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @return GPIO value (0 for inactive, 1 for active) or -ve on error
+ */
+int dm_gpio_get_value(struct gpio_desc *desc);
+
+int dm_gpio_set_value(struct gpio_desc *desc, int value);
+
+/**
+ * dm_gpio_set_dir() - Set the direction for a GPIO
+ *
+ * This sets up the direction according tot the provided flags. It will do
+ * nothing unless the direction is actually specified.
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @return 0 if OK, -ve on error
+ */
+int dm_gpio_set_dir(struct gpio_desc *desc);
+
+/**
+ * dm_gpio_set_dir_flags() - Set direction using specific flags
+ *
+ * This is like dm_gpio_set_dir() except that the flags value is provided
+ * instead of being used from desc->flags. This is needed because in many
+ * cases the GPIO description does not include direction information.
+ * Note that desc->flags is updated by this function.
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @flags:	New flags to use
+ * @return 0 if OK, -ve on error, in which case desc->flags is not updated
+ */
+int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
+
+/**
+ * gpio_get_number() - Get the global GPIO number of a GPIO
+ *
+ * This should only be used for debugging or interest. It returns the nummber
+ * that should be used for gpio_get_value() etc. to access this GPIO.
+ *
+ * @desc:	GPIO description containing device, offset and flags,
+ *		previously returned by gpio_request_by_name()
+ * @return GPIO number, or -ve if not found
+ */
+int gpio_get_number(struct gpio_desc *desc);
+
 #endif	/* _ASM_GENERIC_GPIO_H_ */
diff --git a/include/common.h b/include/common.h
index 4b3e0d3..97c8f79 100644
--- a/include/common.h
+++ b/include/common.h
@@ -228,12 +228,13 @@
 extern char console_buffer[];
 
 /* arch/$(ARCH)/lib/board.c */
-void	board_init_f(ulong);
-void	board_init_r  (gd_t *, ulong) __attribute__ ((noreturn));
-int	checkboard    (void);
-int	checkflash    (void);
-int	checkdram     (void);
-int	last_stage_init(void);
+void board_init_f(ulong);
+void board_init_r(gd_t *, ulong) __attribute__ ((noreturn));
+int checkboard(void);
+int show_board_info(void);
+int checkflash(void);
+int checkdram(void);
+int last_stage_init(void);
 extern ulong monitor_flash_len;
 int mac_read_from_eeprom(void);
 extern u8 __dtb_dt_begin[];	/* embedded device tree blob */
diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
index 0004750..76ce7de 100644
--- a/include/configs/am335x_evm.h
+++ b/include/configs/am335x_evm.h
@@ -19,13 +19,11 @@
 #include <configs/ti_am335x_common.h>
 
 #ifndef CONFIG_SPL_BUILD
+#ifndef CONFIG_FIT
 # define CONFIG_FIT
+#endif
 # define CONFIG_TIMESTAMP
 # define CONFIG_LZO
-# ifdef CONFIG_ENABLE_VBOOT
-#  define CONFIG_FIT_SIGNATURE
-#  define CONFIG_RSA
-# endif
 #endif
 
 #define CONFIG_SYS_BOOTM_LEN		(16 << 20)
diff --git a/include/configs/arndale.h b/include/configs/arndale.h
index d68993b..3ad4a9b 100644
--- a/include/configs/arndale.h
+++ b/include/configs/arndale.h
@@ -51,8 +51,6 @@
 /* PMIC */
 #define CONFIG_PMIC
 #define CONFIG_POWER_I2C
-#define CONFIG_POWER_MAX77686
-
 
 #define CONFIG_PREBOOT
 
diff --git a/include/configs/exynos5-common.h b/include/configs/exynos5-common.h
index ad63f3c..0ba39a2 100644
--- a/include/configs/exynos5-common.h
+++ b/include/configs/exynos5-common.h
@@ -126,12 +126,11 @@
 #define SPI_FLASH_UBOOT_POS	(CONFIG_SEC_FW_SIZE + CONFIG_BL1_SIZE)
 
 /* I2C */
-#define CONFIG_SYS_I2C_INIT_BOARD
-#define CONFIG_SYS_I2C
+#define CONFIG_DM_I2C
+#define CONFIG_DM_I2C_COMPAT
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C_S3C24X0_SPEED	100000		/* 100 Kbps */
 #define CONFIG_SYS_I2C_S3C24X0
-#define CONFIG_I2C_MULTI_BUS
+#define CONFIG_SYS_I2C_S3C24X0_SPEED	100000		/* 100 Kbps */
 #define CONFIG_SYS_I2C_S3C24X0_SLAVE    0x0
 #define CONFIG_I2C_EDID
 
diff --git a/include/configs/exynos5250-common.h b/include/configs/exynos5250-common.h
index 6714313..ae0e5ff 100644
--- a/include/configs/exynos5250-common.h
+++ b/include/configs/exynos5250-common.h
@@ -28,9 +28,6 @@
 
 #define CONFIG_SYS_INIT_SP_ADDR	CONFIG_IRAM_STACK
 
-/* PMIC */
-#define CONFIG_POWER_MAX77686
-
 /* Sound */
 #define CONFIG_CMD_SOUND
 #ifdef CONFIG_CMD_SOUND
diff --git a/include/configs/ids8313.h b/include/configs/ids8313.h
index f084834..2384864 100644
--- a/include/configs/ids8313.h
+++ b/include/configs/ids8313.h
@@ -575,12 +575,9 @@
 
 #define CONFIG_VERSION_VARIABLE
 
-#define CONFIG_FIT
-#define CONFIG_FIT_SIGNATURE
 #define CONFIG_IMAGE_FORMAT_LEGACY
 #define CONFIG_CMD_FDT
 #define CONFIG_CMD_HASH
-#define CONFIG_RSA
 #define CONFIG_SHA1
 #define CONFIG_SHA256
 
diff --git a/include/configs/odroid.h b/include/configs/odroid.h
index 807e96b..9d5dbdc 100644
--- a/include/configs/odroid.h
+++ b/include/configs/odroid.h
@@ -177,12 +177,11 @@
 
 /* I2C */
 #define CONFIG_CMD_I2C
-#define CONFIG_SYS_I2C
+#define CONFIG_DM_I2C
+#define CONFIG_DM_I2C_COMPAT
 #define CONFIG_SYS_I2C_S3C24X0
 #define CONFIG_SYS_I2C_S3C24X0_SPEED	100000
 #define CONFIG_SYS_I2C_S3C24X0_SLAVE	0
-#define CONFIG_MAX_I2C_NUM		8
-#define CONFIG_SYS_I2C_INIT_BOARD
 
 /* POWER */
 #define CONFIG_POWER
diff --git a/include/configs/sandbox.h b/include/configs/sandbox.h
index 657f751..e9d3f32 100644
--- a/include/configs/sandbox.h
+++ b/include/configs/sandbox.h
@@ -23,7 +23,6 @@
 
 #define CONFIG_BOOTSTAGE
 #define CONFIG_BOOTSTAGE_REPORT
-#define CONFIG_DM
 #define CONFIG_CMD_DEMO
 #define CONFIG_CMD_DM
 #define CONFIG_DM_DEMO
@@ -41,9 +40,6 @@
 
 #define CONFIG_OF_LIBFDT
 #define CONFIG_LMB
-#define CONFIG_FIT
-#define CONFIG_FIT_SIGNATURE
-#define CONFIG_RSA
 #define CONFIG_CMD_FDT
 #define CONFIG_ANDROID_BOOT_IMAGE
 
diff --git a/include/configs/smdk5250.h b/include/configs/smdk5250.h
index 8395372..3b06d30 100644
--- a/include/configs/smdk5250.h
+++ b/include/configs/smdk5250.h
@@ -18,6 +18,8 @@
 
 #include <configs/exynos5250-common.h>
 
+/* PMIC */
+#define CONFIG_POWER_MAX77686
 
 #define CONFIG_BOARD_COMMON
 #define CONFIG_ARCH_EARLY_INIT_R
diff --git a/include/configs/snow.h b/include/configs/snow.h
index 7eaa586..ce6676e 100644
--- a/include/configs/snow.h
+++ b/include/configs/snow.h
@@ -22,6 +22,7 @@
 
 #define CONFIG_CROS_EC_I2C		/* Support CROS_EC over I2C */
 #define CONFIG_POWER_TPS65090_I2C
+#define CONFIG_DM_CROS_EC
 
 #define CONFIG_BOARD_COMMON
 #define CONFIG_ARCH_EARLY_INIT_R
diff --git a/include/configs/ti_am335x_common.h b/include/configs/ti_am335x_common.h
index 5ed86d9..598526b 100644
--- a/include/configs/ti_am335x_common.h
+++ b/include/configs/ti_am335x_common.h
@@ -20,7 +20,9 @@
 #define CONFIG_SPL_AM33XX_ENABLE_RTC32K_OSC
 
 #ifndef CONFIG_SPL_BUILD
+#ifndef CONFIG_DM
 # define CONFIG_DM
+#endif
 # define CONFIG_CMD_DM
 # define CONFIG_DM_GPIO
 # define CONFIG_DM_SERIAL
diff --git a/include/configs/uniphier.h b/include/configs/uniphier.h
index 5a53c50..9ad47f6 100644
--- a/include/configs/uniphier.h
+++ b/include/configs/uniphier.h
@@ -43,6 +43,9 @@
 #define CONFIG_SDRAM1_SIZE	0x10000000
 #endif
 
+#define CONFIG_I2C_EEPROM
+#define CONFIG_SYS_EEPROM_PAGE_WRITE_DELAY_MS  10
+
 /*
  * Support card address map
  */
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 2d28e89..864528a 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -276,17 +276,11 @@
 #define CONFIG_OF_LIBFDT
 
 /* FIT support */
-#define CONFIG_FIT
-#define CONFIG_FIT_VERBOSE	1 /* enable fit_format_{error,warning}() */
 #define CONFIG_IMAGE_FORMAT_LEGACY /* enable also legacy image format */
 
 /* FDT support */
 #define CONFIG_DISPLAY_BOARDINFO_LATE
 
-/* RSA support */
-#define CONFIG_FIT_SIGNATURE
-#define CONFIG_RSA
-
 /* Extend size of kernel image for uncompression */
 #define CONFIG_SYS_BOOTM_LEN	(60 * 1024 * 1024)
 
diff --git a/include/cros_ec.h b/include/cros_ec.h
index 9e13146..8457c80 100644
--- a/include/cros_ec.h
+++ b/include/cros_ec.h
@@ -13,6 +13,7 @@
 #include <ec_commands.h>
 #include <fdtdec.h>
 #include <cros_ec_message.h>
+#include <asm/gpio.h>
 
 #ifndef CONFIG_DM_CROS_EC
 /* Which interface is the device on? */
@@ -39,7 +40,7 @@
 	unsigned int bus_num;		/* Bus number (for I2C) */
 	unsigned int max_frequency;	/* Maximum interface frequency */
 #endif
-	struct fdt_gpio_state ec_int;	/* GPIO used as EC interrupt line */
+	struct gpio_desc ec_int;	/* GPIO used as EC interrupt line */
 	int protocol_version;           /* Protocol version to use */
 	int optimise_flash_write;	/* Don't write erased flash blocks */
 
diff --git a/include/dm-demo.h b/include/dm-demo.h
index a24fec6..03722d0 100644
--- a/include/dm-demo.h
+++ b/include/dm-demo.h
@@ -25,10 +25,14 @@
 struct demo_ops {
 	int (*hello)(struct udevice *dev, int ch);
 	int (*status)(struct udevice *dev, int *status);
+	int (*set_light)(struct udevice *dev, int light);
+	int (*get_light)(struct udevice *dev);
 };
 
 int demo_hello(struct udevice *dev, int ch);
 int demo_status(struct udevice *dev, int *status);
+int demo_set_light(struct udevice *dev, int light);
+int demo_get_light(struct udevice *dev);
 int demo_list(void);
 
 int demo_parse_dt(struct udevice *dev);
diff --git a/include/dm/device.h b/include/dm/device.h
index 13598a1..81afa8c 100644
--- a/include/dm/device.h
+++ b/include/dm/device.h
@@ -26,6 +26,9 @@
 /* DM should init this device prior to relocation */
 #define DM_FLAG_PRE_RELOC	(1 << 2)
 
+/* DM is responsible for allocating and freeing parent_platdata */
+#define DM_FLAG_ALLOC_PARENT_PDATA	(1 << 3)
+
 /**
  * struct udevice - An instance of a driver
  *
@@ -46,6 +49,7 @@
  * @driver: The driver used by this device
  * @name: Name of device, typically the FDT node name
  * @platdata: Configuration data for this device
+ * @parent_platdata: The parent bus's configuration data for this device
  * @of_offset: Device tree node offset for this device (- for none)
  * @of_id: Pointer to the udevice_id structure which created the device
  * @parent: Parent of this device, or NULL for the top level device
@@ -65,6 +69,7 @@
 	struct driver *driver;
 	const char *name;
 	void *platdata;
+	void *parent_platdata;
 	int of_offset;
 	const struct udevice_id *of_id;
 	struct udevice *parent;
@@ -127,6 +132,7 @@
  * @remove: Called to remove a device, i.e. de-activate it
  * @unbind: Called to unbind a device from its driver
  * @ofdata_to_platdata: Called before probe to decode device tree data
+ * @child_post_bind: Called after a new child has been bound
  * @child_pre_probe: Called before a child device is probed. The device has
  * memory allocated but it has not yet been probed.
  * @child_post_remove: Called after a child device is removed. The device
@@ -146,6 +152,9 @@
  * device_probe_child() pass it in. So far the use case for allocating it
  * is SPI, but I found that unsatisfactory. Since it is here I will leave it
  * until things are clearer.
+ * @per_child_platdata_auto_alloc_size: A bus likes to store information about
+ * its children. If non-zero this is the size of this data, to be allocated
+ * in the child's parent_platdata pointer.
  * @ops: Driver-specific operations. This is typically a list of function
  * pointers defined by the driver, to implement driver functions required by
  * the uclass.
@@ -160,11 +169,13 @@
 	int (*remove)(struct udevice *dev);
 	int (*unbind)(struct udevice *dev);
 	int (*ofdata_to_platdata)(struct udevice *dev);
+	int (*child_post_bind)(struct udevice *dev);
 	int (*child_pre_probe)(struct udevice *dev);
 	int (*child_post_remove)(struct udevice *dev);
 	int priv_auto_alloc_size;
 	int platdata_auto_alloc_size;
 	int per_child_auto_alloc_size;
+	int per_child_platdata_auto_alloc_size;
 	const void *ops;	/* driver-specific operations */
 	uint32_t flags;
 };
@@ -184,6 +195,16 @@
 void *dev_get_platdata(struct udevice *dev);
 
 /**
+ * dev_get_parent_platdata() - Get the parent platform data for a device
+ *
+ * This checks that dev is not NULL, but no other checks for now
+ *
+ * @dev		Device to check
+ * @return parent's platform data, or NULL if none
+ */
+void *dev_get_parent_platdata(struct udevice *dev);
+
+/**
  * dev_get_parentdata() - Get the parent data for a device
  *
  * The parent data is data stored in the device but owned by the parent.
@@ -224,6 +245,14 @@
  */
 ulong dev_get_of_data(struct udevice *dev);
 
+/*
+ * device_get_uclass_id() - return the uclass ID of a device
+ *
+ * @dev:	Device to check
+ * @return uclass ID for the device
+ */
+enum uclass_id device_get_uclass_id(struct udevice *dev);
+
 /**
  * device_get_child() - Get the child of a device by index
  *
diff --git a/include/dm/test.h b/include/dm/test.h
index f08c05d..707c69e 100644
--- a/include/dm/test.h
+++ b/include/dm/test.h
@@ -67,6 +67,8 @@
 struct dm_test_priv {
 	int ping_total;
 	int op_count[DM_TEST_OP_COUNT];
+	int uclass_flag;
+	int uclass_total;
 };
 
 /**
@@ -88,6 +90,7 @@
  *
  * @sum: Test value used to check parent data works correctly
  * @flag: Used to track calling of parent operations
+ * @uclass_flag: Used to track calling of parent operations by uclass
  */
 struct dm_test_parent_data {
 	int sum;
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index f17c3c2..91bb90d 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -33,6 +33,7 @@
 	UCLASS_I2C,		/* I2C bus */
 	UCLASS_I2C_GENERIC,	/* Generic I2C device */
 	UCLASS_I2C_EEPROM,	/* I2C EEPROM device */
+	UCLASS_MOD_EXP,		/* RSA Mod Exp device */
 
 	UCLASS_COUNT,
 	UCLASS_INVALID = -1,
diff --git a/include/dm/uclass-internal.h b/include/dm/uclass-internal.h
index f718f37..f2f254a 100644
--- a/include/dm/uclass-internal.h
+++ b/include/dm/uclass-internal.h
@@ -44,6 +44,17 @@
 int uclass_unbind_device(struct udevice *dev);
 
 /**
+ * uclass_pre_probe_child() - Deal with a child that is about to be probed
+ *
+ * Perform any pre-processing that is needed by the uclass before it can be
+ * probed.
+ *
+ * @dev:	Pointer to the device
+ * #return 0 on success, -ve on error
+ */
+int uclass_pre_probe_child(struct udevice *dev);
+
+/**
  * uclass_post_probe_device() - Deal with a device that has just been probed
  *
  * Perform any post-processing of a probed device that is needed by the
diff --git a/include/dm/uclass.h b/include/dm/uclass.h
index f6ec6d7..d6c40c6 100644
--- a/include/dm/uclass.h
+++ b/include/dm/uclass.h
@@ -40,6 +40,9 @@
 
 struct udevice;
 
+/* Members of this uclass sequence themselves with aliases */
+#define DM_UC_FLAG_SEQ_ALIAS			(1 << 0)
+
 /**
  * struct uclass_driver - Driver for the uclass
  *
@@ -52,6 +55,7 @@
  * @pre_unbind: Called before a device is unbound from this uclass
  * @post_probe: Called after a new device is probed
  * @pre_remove: Called before a device is removed
+ * @child_post_bind: Called after a child is bound to a device in this uclass
  * @init: Called to set up the uclass
  * @destroy: Called to destroy the uclass
  * @priv_auto_alloc_size: If non-zero this is the size of the private data
@@ -60,8 +64,16 @@
  * @per_device_auto_alloc_size: Each device can hold private data owned
  * by the uclass. If required this will be automatically allocated if this
  * value is non-zero.
+ * @per_child_auto_alloc_size: Each child device (of a parent in this
+ * uclass) can hold parent data for the device/uclass. This value is only
+ * used as a falback if this member is 0 in the driver.
+ * @per_child_platdata_auto_alloc_size: A bus likes to store information about
+ * its children. If non-zero this is the size of this data, to be allocated
+ * in the child device's parent_platdata pointer. This value is only used as
+ * a falback if this member is 0 in the driver.
  * @ops: Uclass operations, providing the consistent interface to devices
  * within the uclass.
+ * @flags: Flags for this uclass (DM_UC_...)
  */
 struct uclass_driver {
 	const char *name;
@@ -70,11 +82,16 @@
 	int (*pre_unbind)(struct udevice *dev);
 	int (*post_probe)(struct udevice *dev);
 	int (*pre_remove)(struct udevice *dev);
+	int (*child_post_bind)(struct udevice *dev);
+	int (*child_pre_probe)(struct udevice *dev);
 	int (*init)(struct uclass *class);
 	int (*destroy)(struct uclass *class);
 	int priv_auto_alloc_size;
 	int per_device_auto_alloc_size;
+	int per_child_auto_alloc_size;
+	int per_child_platdata_auto_alloc_size;
 	const void *ops;
+	uint32_t flags;
 };
 
 /* Declare a new uclass_driver */
@@ -141,6 +158,8 @@
 /**
  * uclass_first_device() - Get the first device in a uclass
  *
+ * The device returned is probed if necessary, and ready for use
+ *
  * @id: Uclass ID to look up
  * @devp: Returns pointer to the first device in that uclass, or NULL if none
  * @return 0 if OK (found or not found), -1 on error
@@ -150,6 +169,8 @@
 /**
  * uclass_next_device() - Get the next device in a uclass
  *
+ * The device returned is probed if necessary, and ready for use
+ *
  * @devp: On entry, pointer to device to lookup. On exit, returns pointer
  * to the next device in the same uclass, or NULL if none
  * @return 0 if OK (found or not found), -1 on error
diff --git a/include/exports.h b/include/exports.h
index 41d5085..205affe 100644
--- a/include/exports.h
+++ b/include/exports.h
@@ -3,6 +3,8 @@
 
 #ifndef __ASSEMBLY__
 
+struct spi_slave;
+
 /* These are declarations of exported functions available in C code */
 unsigned long get_version(void);
 int  getc(void);
@@ -10,22 +12,23 @@
 void putc(const char);
 void puts(const char*);
 int printf(const char* fmt, ...);
-void install_hdlr(int, void (*interrupt_handler_t)(void *), void*);
+void install_hdlr(int, interrupt_handler_t, void*);
 void free_hdlr(int);
 void *malloc(size_t);
 void free(void*);
 void __udelay(unsigned long);
 unsigned long get_timer(unsigned long);
 int vprintf(const char *, va_list);
-unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base);
+unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base);
 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res);
 char *getenv (const char *name);
 int setenv (const char *varname, const char *varvalue);
-long simple_strtol(const char *cp,char **endp,unsigned int base);
-int strcmp(const char * cs,const char * ct);
+long simple_strtol(const char *cp, char **endp, unsigned int base);
+int strcmp(const char *cs, const char *ct);
 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base);
 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base);
-#if defined(CONFIG_CMD_I2C)
+#if defined(CONFIG_CMD_I2C) && \
+		(!defined(CONFIG_DM_I2C) || defined(CONFIG_DM_I2C_COMPAT))
 int i2c_write (uchar, uint, int , uchar* , int);
 int i2c_read (uchar, uint, int , uchar* , int);
 #endif
@@ -34,15 +37,14 @@
 
 #endif    /* ifndef __ASSEMBLY__ */
 
-enum {
-#define EXPORT_FUNC(x) XF_ ## x ,
+struct jt_funcs {
+#define EXPORT_FUNC(impl, res, func, ...) res(*func)(__VA_ARGS__);
 #include <_exports.h>
 #undef EXPORT_FUNC
-
-	XF_MAX
 };
 
-#define XF_VERSION	6
+
+#define XF_VERSION	7
 
 #if defined(CONFIG_X86)
 extern gd_t *global_data;
diff --git a/include/fdtdec.h b/include/fdtdec.h
index 8c2bd21..231eed7 100644
--- a/include/fdtdec.h
+++ b/include/fdtdec.h
@@ -115,9 +115,6 @@
 	COMPAT_NVIDIA_TEGRA20_USB,	/* Tegra20 USB port */
 	COMPAT_NVIDIA_TEGRA30_USB,	/* Tegra30 USB port */
 	COMPAT_NVIDIA_TEGRA114_USB,	/* Tegra114 USB port */
-	COMPAT_NVIDIA_TEGRA114_I2C,	/* Tegra114 I2C w/single clock source */
-	COMPAT_NVIDIA_TEGRA20_I2C,	/* Tegra20 i2c */
-	COMPAT_NVIDIA_TEGRA20_DVC,	/* Tegra20 dvc (really just i2c) */
 	COMPAT_NVIDIA_TEGRA20_EMC,	/* Tegra20 memory controller */
 	COMPAT_NVIDIA_TEGRA20_EMC_TABLE, /* Tegra20 memory timing table */
 	COMPAT_NVIDIA_TEGRA20_KBC,	/* Tegra20 Keyboard */
@@ -127,9 +124,6 @@
 	COMPAT_NVIDIA_TEGRA124_SDMMC,	/* Tegra124 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA30_SDMMC,	/* Tegra30 SDMMC controller */
 	COMPAT_NVIDIA_TEGRA20_SDMMC,	/* Tegra20 SDMMC controller */
-	COMPAT_NVIDIA_TEGRA20_SFLASH,	/* Tegra 2 SPI flash controller */
-	COMPAT_NVIDIA_TEGRA20_SLINK,	/* Tegra 2 SPI SLINK controller */
-	COMPAT_NVIDIA_TEGRA114_SPI,	/* Tegra 114 SPI controller */
 	COMPAT_NVIDIA_TEGRA124_PCIE,	/* Tegra 124 PCIe controller */
 	COMPAT_NVIDIA_TEGRA30_PCIE,	/* Tegra 30 PCIe controller */
 	COMPAT_NVIDIA_TEGRA20_PCIE,	/* Tegra 20 PCIe controller */
@@ -140,7 +134,6 @@
 	COMPAT_SAMSUNG_S3C2440_I2C,	/* Exynos I2C Controller */
 	COMPAT_SAMSUNG_EXYNOS5_SOUND,	/* Exynos Sound */
 	COMPAT_WOLFSON_WM8994_CODEC,	/* Wolfson WM8994 Sound Codec */
-	COMPAT_SAMSUNG_EXYNOS_SPI,	/* Exynos SPI */
 	COMPAT_GOOGLE_CROS_EC,		/* Google CROS_EC Protocol */
 	COMPAT_GOOGLE_CROS_EC_KEYB,	/* Google CROS_EC Keyboard */
 	COMPAT_SAMSUNG_EXYNOS_EHCI,	/* Exynos EHCI controller */
@@ -178,38 +171,58 @@
 	COMPAT_COUNT,
 };
 
-/* GPIOs are numbered from 0 */
-enum {
-	FDT_GPIO_NONE = -1U,	/* an invalid GPIO used to end our list */
-
-	FDT_GPIO_ACTIVE_LOW = 1 << 0,	/* input is active low (else high) */
+#define MAX_PHANDLE_ARGS 16
+struct fdtdec_phandle_args {
+	int node;
+	int args_count;
+	uint32_t args[MAX_PHANDLE_ARGS];
 };
 
-/* This is the state of a GPIO pin as defined by the fdt */
-struct fdt_gpio_state {
-	const char *name;	/* name of the fdt property defining this */
-	uint gpio;		/* GPIO number, or FDT_GPIO_NONE if none */
-	u8 flags;		/* FDT_GPIO_... flags */
-};
-
-/* This tells us whether a fdt_gpio_state record is valid or not */
-#define fdt_gpio_isvalid(x) ((x)->gpio != FDT_GPIO_NONE)
-
 /**
- * Read the GPIO taking into account the polarity of the pin.
+ * fdtdec_parse_phandle_with_args() - Find a node pointed by phandle in a list
  *
- * @param gpio		pointer to the decoded gpio
- * @return value of the gpio if successful, < 0 if unsuccessful
- */
-int fdtdec_get_gpio(struct fdt_gpio_state *gpio);
-
-/**
- * Write the GPIO taking into account the polarity of the pin.
+ * This function is useful to parse lists of phandles and their arguments.
  *
- * @param gpio		pointer to the decoded gpio
- * @return 0 if successful
+ * Example:
+ *
+ * phandle1: node1 {
+ *	#list-cells = <2>;
+ * }
+ *
+ * phandle2: node2 {
+ *	#list-cells = <1>;
+ * }
+ *
+ * node3 {
+ *	list = <&phandle1 1 2 &phandle2 3>;
+ * }
+ *
+ * To get a device_node of the `node2' node you may call this:
+ * fdtdec_parse_phandle_with_args(blob, node3, "list", "#list-cells", 0, 1,
+ *				  &args);
+ *
+ * (This function is a modified version of __of_parse_phandle_with_args() from
+ * Linux 3.18)
+ *
+ * @blob:	Pointer to device tree
+ * @src_node:	Offset of device tree node containing a list
+ * @list_name:	property name that contains a list
+ * @cells_name:	property name that specifies the phandles' arguments count,
+ *		or NULL to use @cells_count
+ * @cells_count: Cell count to use if @cells_name is NULL
+ * @index:	index of a phandle to parse out
+ * @out_args:	optional pointer to output arguments structure (will be filled)
+ * @return 0 on success (with @out_args filled out if not NULL), -ENOENT if
+ *	@list_name does not exist, a phandle was not found, @cells_name
+ *	could not be found, the arguments were truncated or there were too
+ *	many arguments.
+ *
  */
-int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val);
+int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
+				   const char *list_name,
+				   const char *cells_name,
+				   int cell_count, int index,
+				   struct fdtdec_phandle_args *out_args);
 
 /**
  * Find the next numbered alias for a peripheral. This is used to enumerate
@@ -592,50 +605,6 @@
 int fdtdec_get_bool(const void *blob, int node, const char *prop_name);
 
 /**
- * Decode a single GPIOs from an FDT.
- *
- * If the property is not found, then the GPIO structure will still be
- * initialised, with gpio set to FDT_GPIO_NONE. This makes it easy to
- * provide optional GPIOs.
- *
- * @param blob		FDT blob to use
- * @param node		Node to look at
- * @param prop_name	Node property name
- * @param gpio		gpio elements to fill from FDT
- * @return 0 if ok, -FDT_ERR_NOTFOUND if the property is missing.
- */
-int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
-		struct fdt_gpio_state *gpio);
-
-/**
- * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
- * terminating item.
- *
- * @param blob         FDT blob to use
- * @param node         Node to look at
- * @param prop_name    Node property name
- * @param gpio         Array of gpio elements to fill from FDT. This will be
- *                     untouched if either 0 or an error is returned
- * @param max_count    Maximum number of elements allowed
- * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
- * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
- */
-int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
-		struct fdt_gpio_state *gpio, int max_count);
-
-/**
- * Set up a GPIO pin according to the provided gpio information. At present this
- * just requests the GPIO.
- *
- * If the gpio is FDT_GPIO_NONE, no action is taken. This makes it easy to
- * deal with optional GPIOs.
- *
- * @param gpio		GPIO info to use for set up
- * @return 0 if all ok or gpio was FDT_GPIO_NONE; -1 on error
- */
-int fdtdec_setup_gpio(struct fdt_gpio_state *gpio);
-
-/**
  * Look in the FDT for a config item with the given name and return its value
  * as a 32-bit integer. The property must have at least 4 bytes of data. The
  * value of the first cell is returned.
diff --git a/include/hash.h b/include/hash.h
index d8ec4f0..f4eb100 100644
--- a/include/hash.h
+++ b/include/hash.h
@@ -17,7 +17,6 @@
 	HASH_FLAG_ENV		= 1 << 1,	/* Allow env vars */
 };
 
-#ifndef USE_HOSTCC
 #if defined(CONFIG_SHA1SUM_VERIFY) || defined(CONFIG_CRC32_VERIFY)
 #define CONFIG_HASH_VERIFY
 #endif
@@ -77,6 +76,7 @@
 			   int size);
 };
 
+#ifndef USE_HOSTCC
 /**
  * hash_command: Process a hash command for a particular algorithm
  *
@@ -115,19 +115,6 @@
 	       uint8_t *output, int *output_size);
 
 /**
- * hash_lookup_algo() - Look up the hash_algo struct for an algorithm
- *
- * The function returns the pointer to the struct or -EPROTONOSUPPORT if the
- * algorithm is not available.
- *
- * @algo_name: Hash algorithm to look up
- * @algop: Pointer to the hash_algo struct if found
- *
- * @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm.
- */
-int hash_lookup_algo(const char *algo_name, struct hash_algo **algop);
-
-/**
  * hash_show() - Print out a hash algorithm and value
  *
  * You will get a message like this (without a newline at the end):
@@ -141,5 +128,34 @@
  */
 void hash_show(struct hash_algo *algo, ulong addr, ulong len,
 	       uint8_t *output);
+
 #endif /* !USE_HOSTCC */
+
+/**
+ * hash_lookup_algo() - Look up the hash_algo struct for an algorithm
+ *
+ * The function returns the pointer to the struct or -EPROTONOSUPPORT if the
+ * algorithm is not available.
+ *
+ * @algo_name: Hash algorithm to look up
+ * @algop: Pointer to the hash_algo struct if found
+ *
+ * @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm.
+ */
+int hash_lookup_algo(const char *algo_name, struct hash_algo **algop);
+
+/**
+ * hash_progressive_lookup_algo() - Look up hash_algo for prog. hash support
+ *
+ * The function returns the pointer to the struct or -EPROTONOSUPPORT if the
+ * algorithm is not available with progressive hash support.
+ *
+ * @algo_name: Hash algorithm to look up
+ * @algop: Pointer to the hash_algo struct if found
+ *
+ * @return 0 if ok, -EPROTONOSUPPORT for an unknown algorithm.
+ */
+int hash_progressive_lookup_algo(const char *algo_name,
+				 struct hash_algo **algop);
+
 #endif
diff --git a/include/i2c.h b/include/i2c.h
index 9c6a60c..27fe00f 100644
--- a/include/i2c.h
+++ b/include/i2c.h
@@ -39,8 +39,8 @@
  * An I2C chip is a device on the I2C bus. It sits at a particular address
  * and normally supports 7-bit or 10-bit addressing.
  *
- * To obtain this structure, use dev_get_parentdata(dev) where dev is the
- * chip to examine.
+ * To obtain this structure, use dev_get_parent_platdata(dev) where dev is
+ * the chip to examine.
  *
  * @chip_addr:	Chip address on bus
  * @offset_len: Length of offset in bytes. A single byte offset can
@@ -75,7 +75,7 @@
 };
 
 /**
- * i2c_read() - read bytes from an I2C chip
+ * dm_i2c_read() - read bytes from an I2C chip
  *
  * To obtain an I2C device (called a 'chip') given the I2C bus address you
  * can use i2c_get_chip(). To obtain a bus by bus number use
@@ -91,13 +91,12 @@
  *
  * @return 0 on success, -ve on failure
  */
-int i2c_read(struct udevice *dev, uint offset, uint8_t *buffer,
-	     int len);
+int dm_i2c_read(struct udevice *dev, uint offset, uint8_t *buffer, int len);
 
 /**
- * i2c_write() - write bytes to an I2C chip
+ * dm_i2c_write() - write bytes to an I2C chip
  *
- * See notes for i2c_read() above.
+ * See notes for dm_i2c_read() above.
  *
  * @dev:	Chip to write to
  * @offset:	Offset within chip to start writing
@@ -106,11 +105,11 @@
  *
  * @return 0 on success, -ve on failure
  */
-int i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
-	      int len);
+int dm_i2c_write(struct udevice *dev, uint offset, const uint8_t *buffer,
+		 int len);
 
 /**
- * i2c_probe() - probe a particular chip address
+ * dm_i2c_probe() - probe a particular chip address
  *
  * This can be useful to check for the existence of a chip on the bus.
  * It is typically implemented by writing the chip address to the bus
@@ -122,8 +121,8 @@
  * @devp:	Returns the device found, or NULL if none
  * @return 0 if a chip was found at that address, -ve if not
  */
-int i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
-	      struct udevice **devp);
+int dm_i2c_probe(struct udevice *bus, uint chip_addr, uint chip_flags,
+		 struct udevice **devp);
 
 /**
  * i2c_set_bus_speed() - set the speed of a bus
@@ -185,6 +184,80 @@
  */
 int i2c_deblock(struct udevice *bus);
 
+#ifdef CONFIG_DM_I2C_COMPAT
+/**
+ * i2c_probe() - Compatibility function for driver model
+ *
+ * Calls dm_i2c_probe() on the current bus
+ */
+int i2c_probe(uint8_t chip_addr);
+
+/**
+ * i2c_read() - Compatibility function for driver model
+ *
+ * Calls dm_i2c_read() with the device corresponding to @chip_addr, and offset
+ * set to @addr. @alen must match the current setting for the device.
+ */
+int i2c_read(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+	     int len);
+
+/**
+ * i2c_write() - Compatibility function for driver model
+ *
+ * Calls dm_i2c_write() with the device corresponding to @chip_addr, and offset
+ * set to @addr. @alen must match the current setting for the device.
+ */
+int i2c_write(uint8_t chip_addr, unsigned int addr, int alen, uint8_t *buffer,
+	      int len);
+
+/**
+ * i2c_get_bus_num_fdt() - Compatibility function for driver model
+ *
+ * @return the bus number associated with the given device tree node
+ */
+int i2c_get_bus_num_fdt(int node);
+
+/**
+ * i2c_get_bus_num() - Compatibility function for driver model
+ *
+ * @return the 'current' bus number
+ */
+unsigned int i2c_get_bus_num(void);
+
+/**
+ * i2c_set_bus_num() - Compatibility function for driver model
+ *
+ * Sets the 'current' bus
+ */
+int i2c_set_bus_num(unsigned int bus);
+
+static inline void I2C_SET_BUS(unsigned int bus)
+{
+	i2c_set_bus_num(bus);
+}
+
+static inline unsigned int I2C_GET_BUS(void)
+{
+	return i2c_get_bus_num();
+}
+
+/**
+ * i2c_init() - Compatibility function for driver model
+ *
+ * This function does nothing.
+ */
+void i2c_init(int speed, int slaveaddr);
+
+/**
+ * board_i2c_init() - Compatibility function for driver model
+ *
+ * @param blob  Device tree blbo
+ * @return the number of I2C bus
+ */
+void board_i2c_init(const void *blob);
+
+#endif
+
 /*
  * Not all of these flags are implemented in the U-Boot API
  */
@@ -330,10 +403,12 @@
  *
  * @bus:	Bus to examine
  * @chip_addr:	Chip address for the new device
+ * @offset_len:	Length of a register offset in bytes (normally 1)
  * @devp:	Returns pointer to new device if found or -ENODEV if not
  *		found
  */
-int i2c_get_chip(struct udevice *bus, uint chip_addr, struct udevice **devp);
+int i2c_get_chip(struct udevice *bus, uint chip_addr, uint offset_len,
+		 struct udevice **devp);
 
 /**
  * i2c_get_chip() - get a device to use to access a chip on a bus number
@@ -343,10 +418,12 @@
  *
  * @busnum:	Bus number to examine
  * @chip_addr:	Chip address for the new device
+ * @offset_len:	Length of a register offset in bytes (normally 1)
  * @devp:	Returns pointer to new device if found or -ENODEV if not
  *		found
  */
-int i2c_get_chip_for_busnum(int busnum, int chip_addr, struct udevice **devp);
+int i2c_get_chip_for_busnum(int busnum, int chip_addr, uint offset_len,
+			    struct udevice **devp);
 
 /**
  * i2c_chip_ofdata_to_platdata() - Decode standard I2C platform data
diff --git a/include/image.h b/include/image.h
index d861896..0e6af00 100644
--- a/include/image.h
+++ b/include/image.h
@@ -928,8 +928,9 @@
 #if IMAGE_ENABLE_SIGN
 	const EVP_MD *(*calculate_sign)(void);
 #endif
-	void (*calculate)(const struct image_region region[],
-			  int region_count, uint8_t *checksum);
+	int (*calculate)(const char *name,
+			 const struct image_region region[],
+			 int region_count, uint8_t *checksum);
 	const uint8_t *rsa_padding;
 };
 
diff --git a/include/sdhci.h b/include/sdhci.h
index aa4a0e9..23893b5 100644
--- a/include/sdhci.h
+++ b/include/sdhci.h
@@ -12,7 +12,7 @@
 
 #include <asm/io.h>
 #include <mmc.h>
-#include <fdtdec.h>
+#include <asm/gpio.h>
 
 /*
  * Controller registers
@@ -246,8 +246,8 @@
 	int index;
 
 	int bus_width;
-	struct fdt_gpio_state pwr_gpio;	/* Power GPIO */
-	struct fdt_gpio_state cd_gpio;		/* Card Detect GPIO */
+	struct gpio_desc pwr_gpio;	/* Power GPIO */
+	struct gpio_desc cd_gpio;		/* Card Detect GPIO */
 
 	void (*set_control_reg)(struct sdhci_host *host);
 	void (*set_clock)(int dev_index, unsigned int div);
diff --git a/include/spi.h b/include/spi.h
index ec17bd0..c58e453 100644
--- a/include/spi.h
+++ b/include/spi.h
@@ -56,20 +56,42 @@
 #define SPI_DEFAULT_WORDLEN 8
 
 #ifdef CONFIG_DM_SPI
+/* TODO(sjg@chromium.org): Remove this and use max_hz from struct spi_slave */
 struct dm_spi_bus {
 	uint max_hz;
 };
 
+/**
+ * struct dm_spi_platdata - platform data for all SPI slaves
+ *
+ * This describes a SPI slave, a child device of the SPI bus. To obtain this
+ * struct from a spi_slave, use dev_get_parent_platdata(dev) or
+ * dev_get_parent_platdata(slave->dev).
+ *
+ * This data is immuatable. Each time the device is probed, @max_hz and @mode
+ * will be copied to struct spi_slave.
+ *
+ * @cs:		Chip select number (0..n-1)
+ * @max_hz:	Maximum bus speed that this slave can tolerate
+ * @mode:	SPI mode to use for this device (see SPI mode flags)
+ */
+struct dm_spi_slave_platdata {
+	unsigned int cs;
+	uint max_hz;
+	uint mode;
+};
+
 #endif /* CONFIG_DM_SPI */
 
 /**
  * struct spi_slave - Representation of a SPI slave
  *
  * For driver model this is the per-child data used by the SPI bus. It can
- * be accessed using dev_get_parentdata() on the slave device. Each SPI
- * driver should define this child data in its U_BOOT_DRIVER() definition:
- *
- *	.per_child_auto_alloc_size	= sizeof(struct spi_slave),
+ * be accessed using dev_get_parentdata() on the slave device. The SPI uclass
+ * sets uip per_child_auto_alloc_size to sizeof(struct spi_slave), and the
+ * driver should not override it. Two platform data fields (max_hz and mode)
+ * are copied into this structure to provide an initial value. This allows
+ * them to be changed, since we should never change platform data in drivers.
  *
  * If not using driver model, drivers are expected to extend this with
  * controller-specific data.
@@ -97,8 +119,8 @@
 	uint mode;
 #else
 	unsigned int bus;
-#endif
 	unsigned int cs;
+#endif
 	u8 op_mode_rx;
 	u8 op_mode_tx;
 	unsigned int wordlen;
@@ -545,16 +567,16 @@
 int spi_find_chip_select(struct udevice *bus, int cs, struct udevice **devp);
 
 /**
- * spi_ofdata_to_platdata() - decode standard SPI platform data
+ * spi_slave_ofdata_to_platdata() - decode standard SPI platform data
  *
- * This decodes the speed and mode from a device tree node and puts it into
- * the spi_slave structure.
+ * This decodes the speed and mode for a slave from a device tree node
  *
  * @blob:	Device tree blob
  * @node:	Node offset to read from
- * @spi:	Place to put the decoded information
+ * @plat:	Place to put the decoded information
  */
-int spi_ofdata_to_platdata(const void *blob, int node, struct spi_slave *spi);
+int spi_slave_ofdata_to_platdata(const void *blob, int node,
+				 struct dm_spi_slave_platdata *plat);
 
 /**
  * spi_cs_info() - Check information on a chip select
diff --git a/include/u-boot/rsa-checksum.h b/include/u-boot/rsa-checksum.h
index c996fb3..3c69d85 100644
--- a/include/u-boot/rsa-checksum.h
+++ b/include/u-boot/rsa-checksum.h
@@ -16,9 +16,18 @@
 extern const uint8_t padding_sha256_rsa2048[];
 extern const uint8_t padding_sha1_rsa2048[];
 
-void sha256_calculate(const struct image_region region[], int region_count,
-		      uint8_t *checksum);
-void sha1_calculate(const struct image_region region[], int region_count,
-		    uint8_t *checksum);
+/**
+ * hash_calculate() - Calculate hash over the data
+ *
+ * @name:  Name of algorithm to be used for hash calculation
+ * @region: Array having info of regions over which hash needs to be calculated
+ * @region_count: Number of regions in the region array
+ * @checksum: Buffer contanining the output hash
+ *
+ * @return 0 if OK, < 0 if error
+ */
+int hash_calculate(const char *name,
+		   const struct image_region region[], int region_count,
+		   uint8_t *checksum);
 
 #endif
diff --git a/include/u-boot/rsa-mod-exp.h b/include/u-boot/rsa-mod-exp.h
new file mode 100644
index 0000000..fce445a
--- /dev/null
+++ b/include/u-boot/rsa-mod-exp.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2014, Ruchika Gupta.
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+*/
+
+#ifndef _RSA_MOD_EXP_H
+#define _RSA_MOD_EXP_H
+
+#include <errno.h>
+#include <image.h>
+
+/**
+ * struct key_prop - holder for a public key properties
+ *
+ * The struct has pointers to modulus (Typically called N),
+ * The inverse, R^2, exponent. These can be typecasted and
+ * used as byte arrays or converted to the required format
+ * as per requirement of RSA implementation.
+ */
+struct key_prop {
+	const void *rr;		/* R^2 can be treated as byte array */
+	const void *modulus;	/* modulus as byte array */
+	const void *public_exponent; /* public exponent as byte array */
+	uint32_t n0inv;		/* -1 / modulus[0] mod 2^32 */
+	int num_bits;		/* Key length in bits */
+	uint32_t exp_len;	/* Exponent length in number of uint8_t */
+};
+
+/**
+ * rsa_mod_exp_sw() - Perform RSA Modular Exponentiation in sw
+ *
+ * Operation: out[] = sig ^ exponent % modulus
+ *
+ * @sig:	RSA PKCS1.5 signature
+ * @sig_len:	Length of signature in number of bytes
+ * @node:	Node with RSA key elements like modulus, exponent, R^2, n0inv
+ * @out:	Result in form of byte array of len equal to sig_len
+ */
+int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *node, uint8_t *out);
+
+int rsa_mod_exp(struct udevice *dev, const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *node, uint8_t *out);
+
+/**
+ * struct struct mod_exp_ops - Driver model for RSA Modular Exponentiation
+ *				operations
+ *
+ * The uclass interface is implemented by all crypto devices which use
+ * driver model.
+ */
+struct mod_exp_ops {
+	/**
+	 * Perform Modular Exponentiation
+	 *
+	 * Operation: out[] = sig ^ exponent % modulus
+	 *
+	 * @dev:	RSA Device
+	 * @sig:	RSA PKCS1.5 signature
+	 * @sig_len:	Length of signature in number of bytes
+	 * @node:	Node with RSA key elements like modulus, exponent,
+	 *		R^2, n0inv
+	 * @out:	Result in form of byte array of len equal to sig_len
+	 *
+	 * This function computes exponentiation over the signature.
+	 * Returns: 0 if exponentiation is successful, or a negative value
+	 * if it wasn't.
+	 */
+	int (*mod_exp)(struct udevice *dev, const uint8_t *sig,
+			   uint32_t sig_len, struct key_prop *node,
+			   uint8_t *outp);
+};
+
+#endif
diff --git a/lib/Kconfig b/lib/Kconfig
index 8460439..a1f30a2 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -27,4 +27,6 @@
 	  get_timer() must operate in milliseconds and this option must be
 	  set to 1000.
 
+source lib/rsa/Kconfig
+
 endmenu
diff --git a/lib/fdtdec.c b/lib/fdtdec.c
index e989241..5bf8f29 100644
--- a/lib/fdtdec.c
+++ b/lib/fdtdec.c
@@ -11,8 +11,6 @@
 #include <fdtdec.h>
 #include <linux/ctype.h>
 
-#include <asm/gpio.h>
-
 DECLARE_GLOBAL_DATA_PTR;
 
 /*
@@ -26,9 +24,6 @@
 	COMPAT(NVIDIA_TEGRA20_USB, "nvidia,tegra20-ehci"),
 	COMPAT(NVIDIA_TEGRA30_USB, "nvidia,tegra30-ehci"),
 	COMPAT(NVIDIA_TEGRA114_USB, "nvidia,tegra114-ehci"),
-	COMPAT(NVIDIA_TEGRA114_I2C, "nvidia,tegra114-i2c"),
-	COMPAT(NVIDIA_TEGRA20_I2C, "nvidia,tegra20-i2c"),
-	COMPAT(NVIDIA_TEGRA20_DVC, "nvidia,tegra20-i2c-dvc"),
 	COMPAT(NVIDIA_TEGRA20_EMC, "nvidia,tegra20-emc"),
 	COMPAT(NVIDIA_TEGRA20_EMC_TABLE, "nvidia,tegra20-emc-table"),
 	COMPAT(NVIDIA_TEGRA20_KBC, "nvidia,tegra20-kbc"),
@@ -38,9 +33,6 @@
 	COMPAT(NVIDIA_TEGRA124_SDMMC, "nvidia,tegra124-sdhci"),
 	COMPAT(NVIDIA_TEGRA30_SDMMC, "nvidia,tegra30-sdhci"),
 	COMPAT(NVIDIA_TEGRA20_SDMMC, "nvidia,tegra20-sdhci"),
-	COMPAT(NVIDIA_TEGRA20_SFLASH, "nvidia,tegra20-sflash"),
-	COMPAT(NVIDIA_TEGRA20_SLINK, "nvidia,tegra20-slink"),
-	COMPAT(NVIDIA_TEGRA114_SPI, "nvidia,tegra114-spi"),
 	COMPAT(NVIDIA_TEGRA124_PCIE, "nvidia,tegra124-pcie"),
 	COMPAT(NVIDIA_TEGRA30_PCIE, "nvidia,tegra30-pcie"),
 	COMPAT(NVIDIA_TEGRA20_PCIE, "nvidia,tegra20-pcie"),
@@ -50,7 +42,6 @@
 	COMPAT(SAMSUNG_S3C2440_I2C, "samsung,s3c2440-i2c"),
 	COMPAT(SAMSUNG_EXYNOS5_SOUND, "samsung,exynos-sound"),
 	COMPAT(WOLFSON_WM8994_CODEC, "wolfson,wm8994-codec"),
-	COMPAT(SAMSUNG_EXYNOS_SPI, "samsung,exynos-spi"),
 	COMPAT(GOOGLE_CROS_EC, "google,cros-ec"),
 	COMPAT(GOOGLE_CROS_EC_KEYB, "google,cros-ec-keyb"),
 	COMPAT(SAMSUNG_EXYNOS_EHCI, "samsung,exynos-ehci"),
@@ -679,99 +670,128 @@
 	return cell != NULL;
 }
 
-/**
- * Decode a list of GPIOs from an FDT. This creates a list of GPIOs with no
- * terminating item.
- *
- * @param blob		FDT blob to use
- * @param node		Node to look at
- * @param prop_name	Node property name
- * @param gpio		Array of gpio elements to fill from FDT. This will be
- *			untouched if either 0 or an error is returned
- * @param max_count	Maximum number of elements allowed
- * @return number of GPIOs read if ok, -FDT_ERR_BADLAYOUT if max_count would
- * be exceeded, or -FDT_ERR_NOTFOUND if the property is missing.
- */
-int fdtdec_decode_gpios(const void *blob, int node, const char *prop_name,
-		struct fdt_gpio_state *gpio, int max_count)
+int fdtdec_parse_phandle_with_args(const void *blob, int src_node,
+				   const char *list_name,
+				   const char *cells_name,
+				   int cell_count, int index,
+				   struct fdtdec_phandle_args *out_args)
 {
-	const struct fdt_property *prop;
-	const u32 *cell;
-	const char *name;
-	int len, i;
+	const __be32 *list, *list_end;
+	int rc = 0, size, cur_index = 0;
+	uint32_t count = 0;
+	int node = -1;
+	int phandle;
 
-	debug("%s: %s\n", __func__, prop_name);
-	assert(max_count > 0);
-	prop = fdt_get_property(blob, node, prop_name, &len);
-	if (!prop) {
-		debug("%s: property '%s' missing\n", __func__, prop_name);
-		return -FDT_ERR_NOTFOUND;
+	/* Retrieve the phandle list property */
+	list = fdt_getprop(blob, src_node, list_name, &size);
+	if (!list)
+		return -ENOENT;
+	list_end = list + size / sizeof(*list);
+
+	/* Loop over the phandles until all the requested entry is found */
+	while (list < list_end) {
+		rc = -EINVAL;
+		count = 0;
+
+		/*
+		 * If phandle is 0, then it is an empty entry with no
+		 * arguments.  Skip forward to the next entry.
+		 */
+		phandle = be32_to_cpup(list++);
+		if (phandle) {
+			/*
+			 * Find the provider node and parse the #*-cells
+			 * property to determine the argument length.
+			 *
+			 * This is not needed if the cell count is hard-coded
+			 * (i.e. cells_name not set, but cell_count is set),
+			 * except when we're going to return the found node
+			 * below.
+			 */
+			if (cells_name || cur_index == index) {
+				node = fdt_node_offset_by_phandle(blob,
+								  phandle);
+				if (!node) {
+					debug("%s: could not find phandle\n",
+					      fdt_get_name(blob, src_node,
+							   NULL));
+					goto err;
+				}
+			}
+
+			if (cells_name) {
+				count = fdtdec_get_int(blob, node, cells_name,
+						       -1);
+				if (count == -1) {
+					debug("%s: could not get %s for %s\n",
+					      fdt_get_name(blob, src_node,
+							   NULL),
+					      cells_name,
+					      fdt_get_name(blob, node,
+							   NULL));
+					goto err;
+				}
+			} else {
+				count = cell_count;
+			}
+
+			/*
+			 * Make sure that the arguments actually fit in the
+			 * remaining property data length
+			 */
+			if (list + count > list_end) {
+				debug("%s: arguments longer than property\n",
+				      fdt_get_name(blob, src_node, NULL));
+				goto err;
+			}
+		}
+
+		/*
+		 * All of the error cases above bail out of the loop, so at
+		 * this point, the parsing is successful. If the requested
+		 * index matches, then fill the out_args structure and return,
+		 * or return -ENOENT for an empty entry.
+		 */
+		rc = -ENOENT;
+		if (cur_index == index) {
+			if (!phandle)
+				goto err;
+
+			if (out_args) {
+				int i;
+
+				if (count > MAX_PHANDLE_ARGS) {
+					debug("%s: too many arguments %d\n",
+					      fdt_get_name(blob, src_node,
+							   NULL), count);
+					count = MAX_PHANDLE_ARGS;
+				}
+				out_args->node = node;
+				out_args->args_count = count;
+				for (i = 0; i < count; i++) {
+					out_args->args[i] =
+							be32_to_cpup(list++);
+				}
+			}
+
+			/* Found it! return success */
+			return 0;
+		}
+
+		node = -1;
+		list += count;
+		cur_index++;
 	}
 
-	/* We will use the name to tag the GPIO */
-	name = fdt_string(blob, fdt32_to_cpu(prop->nameoff));
-	cell = (u32 *)prop->data;
-	len /= sizeof(u32) * 3;		/* 3 cells per GPIO record */
-	if (len > max_count) {
-		debug(" %s: too many GPIOs / cells for "
-			"property '%s'\n", __func__, prop_name);
-		return -FDT_ERR_BADLAYOUT;
-	}
-
-	/* Read out the GPIO data from the cells */
-	for (i = 0; i < len; i++, cell += 3) {
-		gpio[i].gpio = fdt32_to_cpu(cell[1]);
-		gpio[i].flags = fdt32_to_cpu(cell[2]);
-		gpio[i].name = name;
-	}
-
-	return len;
-}
-
-int fdtdec_decode_gpio(const void *blob, int node, const char *prop_name,
-		struct fdt_gpio_state *gpio)
-{
-	int err;
-
-	debug("%s: %s\n", __func__, prop_name);
-	gpio->gpio = FDT_GPIO_NONE;
-	gpio->name = NULL;
-	err = fdtdec_decode_gpios(blob, node, prop_name, gpio, 1);
-	return err == 1 ? 0 : err;
-}
-
-int fdtdec_get_gpio(struct fdt_gpio_state *gpio)
-{
-	int val;
-
-	if (!fdt_gpio_isvalid(gpio))
-		return -1;
-
-	val = gpio_get_value(gpio->gpio);
-	return gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
-}
-
-int fdtdec_set_gpio(struct fdt_gpio_state *gpio, int val)
-{
-	if (!fdt_gpio_isvalid(gpio))
-		return -1;
-
-	val = gpio->flags & FDT_GPIO_ACTIVE_LOW ? val ^ 1 : val;
-	return gpio_set_value(gpio->gpio, val);
-}
-
-int fdtdec_setup_gpio(struct fdt_gpio_state *gpio)
-{
 	/*
-	 * Return success if there is no GPIO defined. This is used for
-	 * optional GPIOs)
+	 * Result will be one of:
+	 * -ENOENT : index is for empty phandle
+	 * -EINVAL : parsing error on data
+	 * [1..n]  : Number of phandle (count mode; when index = -1)
 	 */
-	if (!fdt_gpio_isvalid(gpio))
-		return 0;
-
-	if (gpio_request(gpio->gpio, gpio->name))
-		return -1;
-	return 0;
+	rc = index < 0 ? cur_index : -ENOENT;
+ err:
+	return rc;
 }
 
 int fdtdec_get_byte_array(const void *blob, int node, const char *prop_name,
diff --git a/lib/rsa/Kconfig b/lib/rsa/Kconfig
new file mode 100644
index 0000000..1268a1b
--- /dev/null
+++ b/lib/rsa/Kconfig
@@ -0,0 +1,27 @@
+config RSA
+	bool "Use RSA Library"
+	select RSA_FREESCALE_EXP if FSL_CAAM
+	select RSA_SOFTWARE_EXP if !RSA_FREESCALE_EXP
+	help
+	  RSA support. This enables the RSA algorithm used for FIT image
+	  verification in U-Boot.
+	  See doc/uImage.FIT/signature.txt for more details.
+
+if RSA
+config RSA_SOFTWARE_EXP
+	bool "Enable driver for RSA Modular Exponentiation in software"
+	depends on DM && RSA
+	help
+	  Enables driver for modular exponentiation in software. This is a RSA
+	  algorithm used in FIT image verification. It required RSA Key as
+	  input.
+	  See doc/uImage.FIT/signature.txt for more details.
+
+config RSA_FREESCALE_EXP
+	bool "Enable RSA Modular Exponentiation with FSL crypto accelerator"
+	depends on DM && RSA && FSL_CAAM
+	help
+	Enables driver for RSA modular exponentiation using Freescale cryptographic
+	accelerator - CAAM.
+
+endif
diff --git a/lib/rsa/Makefile b/lib/rsa/Makefile
index a5a96cb6..cc25b3c 100644
--- a/lib/rsa/Makefile
+++ b/lib/rsa/Makefile
@@ -7,4 +7,4 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
-obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o
+obj-$(CONFIG_FIT_SIGNATURE) += rsa-verify.o rsa-checksum.o rsa-mod-exp.o
diff --git a/lib/rsa/rsa-checksum.c b/lib/rsa/rsa-checksum.c
index 8d8b59f..68d9d65 100644
--- a/lib/rsa/rsa-checksum.c
+++ b/lib/rsa/rsa-checksum.c
@@ -10,12 +10,13 @@
 #include <asm/byteorder.h>
 #include <asm/errno.h>
 #include <asm/unaligned.h>
+#include <hash.h>
 #else
 #include "fdt_host.h"
-#endif
-#include <u-boot/rsa.h>
 #include <u-boot/sha1.h>
 #include <u-boot/sha256.h>
+#endif
+#include <u-boot/rsa.h>
 
 /* PKCS 1.5 paddings as described in the RSA PKCS#1 v2.1 standard. */
 
@@ -136,28 +137,37 @@
 	0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20
 };
 
-void sha1_calculate(const struct image_region region[], int region_count,
-		    uint8_t *checksum)
+int hash_calculate(const char *name,
+		    const struct image_region region[],
+		    int region_count, uint8_t *checksum)
 {
-	sha1_context ctx;
+	struct hash_algo *algo;
+	int ret = 0;
+	void *ctx;
 	uint32_t i;
 	i = 0;
 
-	sha1_starts(&ctx);
-	for (i = 0; i < region_count; i++)
-		sha1_update(&ctx, region[i].data, region[i].size);
-	sha1_finish(&ctx, checksum);
-}
+	ret = hash_progressive_lookup_algo(name, &algo);
+	if (ret)
+		return ret;
 
-void sha256_calculate(const struct image_region region[], int region_count,
-		      uint8_t *checksum)
-{
-	sha256_context ctx;
-	uint32_t i;
-	i = 0;
+	ret = algo->hash_init(algo, &ctx);
+	if (ret)
+		return ret;
 
-	sha256_starts(&ctx);
-	for (i = 0; i < region_count; i++)
-		sha256_update(&ctx, region[i].data, region[i].size);
-	sha256_finish(&ctx, checksum);
+	for (i = 0; i < region_count - 1; i++) {
+		ret = algo->hash_update(algo, ctx, region[i].data,
+					region[i].size, 0);
+		if (ret)
+			return ret;
+	}
+
+	ret = algo->hash_update(algo, ctx, region[i].data, region[i].size, 1);
+	if (ret)
+		return ret;
+	ret = algo->hash_finish(algo, ctx, checksum, algo->digest_size);
+	if (ret)
+		return ret;
+
+	return 0;
 }
diff --git a/lib/rsa/rsa-mod-exp.c b/lib/rsa/rsa-mod-exp.c
new file mode 100644
index 0000000..4a6de2b
--- /dev/null
+++ b/lib/rsa/rsa-mod-exp.c
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2013, Google Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#ifndef USE_HOSTCC
+#include <common.h>
+#include <fdtdec.h>
+#include <asm/types.h>
+#include <asm/byteorder.h>
+#include <asm/errno.h>
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#else
+#include "fdt_host.h"
+#include "mkimage.h"
+#include <fdt_support.h>
+#endif
+#include <u-boot/rsa.h>
+#include <u-boot/rsa-mod-exp.h>
+
+#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
+
+#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
+#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
+
+/* Default public exponent for backward compatibility */
+#define RSA_DEFAULT_PUBEXP	65537
+
+/**
+ * subtract_modulus() - subtract modulus from the given value
+ *
+ * @key:	Key containing modulus to subtract
+ * @num:	Number to subtract modulus from, as little endian word array
+ */
+static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
+{
+	int64_t acc = 0;
+	uint i;
+
+	for (i = 0; i < key->len; i++) {
+		acc += (uint64_t)num[i] - key->modulus[i];
+		num[i] = (uint32_t)acc;
+		acc >>= 32;
+	}
+}
+
+/**
+ * greater_equal_modulus() - check if a value is >= modulus
+ *
+ * @key:	Key containing modulus to check
+ * @num:	Number to check against modulus, as little endian word array
+ * @return 0 if num < modulus, 1 if num >= modulus
+ */
+static int greater_equal_modulus(const struct rsa_public_key *key,
+				 uint32_t num[])
+{
+	int i;
+
+	for (i = (int)key->len - 1; i >= 0; i--) {
+		if (num[i] < key->modulus[i])
+			return 0;
+		if (num[i] > key->modulus[i])
+			return 1;
+	}
+
+	return 1;  /* equal */
+}
+
+/**
+ * montgomery_mul_add_step() - Perform montgomery multiply-add step
+ *
+ * Operation: montgomery result[] += a * b[] / n0inv % modulus
+ *
+ * @key:	RSA key
+ * @result:	Place to put result, as little endian word array
+ * @a:		Multiplier
+ * @b:		Multiplicand, as little endian word array
+ */
+static void montgomery_mul_add_step(const struct rsa_public_key *key,
+		uint32_t result[], const uint32_t a, const uint32_t b[])
+{
+	uint64_t acc_a, acc_b;
+	uint32_t d0;
+	uint i;
+
+	acc_a = (uint64_t)a * b[0] + result[0];
+	d0 = (uint32_t)acc_a * key->n0inv;
+	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
+	for (i = 1; i < key->len; i++) {
+		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
+		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
+				(uint32_t)acc_a;
+		result[i - 1] = (uint32_t)acc_b;
+	}
+
+	acc_a = (acc_a >> 32) + (acc_b >> 32);
+
+	result[i - 1] = (uint32_t)acc_a;
+
+	if (acc_a >> 32)
+		subtract_modulus(key, result);
+}
+
+/**
+ * montgomery_mul() - Perform montgomery mutitply
+ *
+ * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
+ *
+ * @key:	RSA key
+ * @result:	Place to put result, as little endian word array
+ * @a:		Multiplier, as little endian word array
+ * @b:		Multiplicand, as little endian word array
+ */
+static void montgomery_mul(const struct rsa_public_key *key,
+		uint32_t result[], uint32_t a[], const uint32_t b[])
+{
+	uint i;
+
+	for (i = 0; i < key->len; ++i)
+		result[i] = 0;
+	for (i = 0; i < key->len; ++i)
+		montgomery_mul_add_step(key, result, a[i], b);
+}
+
+/**
+ * num_pub_exponent_bits() - Number of bits in the public exponent
+ *
+ * @key:	RSA key
+ * @num_bits:	Storage for the number of public exponent bits
+ */
+static int num_public_exponent_bits(const struct rsa_public_key *key,
+		int *num_bits)
+{
+	uint64_t exponent;
+	int exponent_bits;
+	const uint max_bits = (sizeof(exponent) * 8);
+
+	exponent = key->exponent;
+	exponent_bits = 0;
+
+	if (!exponent) {
+		*num_bits = exponent_bits;
+		return 0;
+	}
+
+	for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
+		if (!(exponent >>= 1)) {
+			*num_bits = exponent_bits;
+			return 0;
+		}
+
+	return -EINVAL;
+}
+
+/**
+ * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
+ *
+ * @key:	RSA key
+ * @pos:	The bit position to check
+ */
+static int is_public_exponent_bit_set(const struct rsa_public_key *key,
+		int pos)
+{
+	return key->exponent & (1ULL << pos);
+}
+
+/**
+ * pow_mod() - in-place public exponentiation
+ *
+ * @key:	RSA key
+ * @inout:	Big-endian word array containing value and result
+ */
+static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
+{
+	uint32_t *result, *ptr;
+	uint i;
+	int j, k;
+
+	/* Sanity check for stack size - key->len is in 32-bit words */
+	if (key->len > RSA_MAX_KEY_BITS / 32) {
+		debug("RSA key words %u exceeds maximum %d\n", key->len,
+		      RSA_MAX_KEY_BITS / 32);
+		return -EINVAL;
+	}
+
+	uint32_t val[key->len], acc[key->len], tmp[key->len];
+	uint32_t a_scaled[key->len];
+	result = tmp;  /* Re-use location. */
+
+	/* Convert from big endian byte array to little endian word array. */
+	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
+		val[i] = get_unaligned_be32(ptr);
+
+	if (0 != num_public_exponent_bits(key, &k))
+		return -EINVAL;
+
+	if (k < 2) {
+		debug("Public exponent is too short (%d bits, minimum 2)\n",
+		      k);
+		return -EINVAL;
+	}
+
+	if (!is_public_exponent_bit_set(key, 0)) {
+		debug("LSB of RSA public exponent must be set.\n");
+		return -EINVAL;
+	}
+
+	/* the bit at e[k-1] is 1 by definition, so start with: C := M */
+	montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
+	/* retain scaled version for intermediate use */
+	memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
+
+	for (j = k - 2; j > 0; --j) {
+		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
+
+		if (is_public_exponent_bit_set(key, j)) {
+			/* acc = tmp * val / R mod n */
+			montgomery_mul(key, acc, tmp, a_scaled);
+		} else {
+			/* e[j] == 0, copy tmp back to acc for next operation */
+			memcpy(acc, tmp, key->len * sizeof(acc[0]));
+		}
+	}
+
+	/* the bit at e[0] is always 1 */
+	montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
+	montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
+	memcpy(result, acc, key->len * sizeof(result[0]));
+
+	/* Make sure result < mod; result is at most 1x mod too large. */
+	if (greater_equal_modulus(key, result))
+		subtract_modulus(key, result);
+
+	/* Convert to bigendian byte array */
+	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
+		put_unaligned_be32(result[i], ptr);
+	return 0;
+}
+
+static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
+{
+	int i;
+
+	for (i = 0; i < len; i++)
+		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
+}
+
+int rsa_mod_exp_sw(const uint8_t *sig, uint32_t sig_len,
+		struct key_prop *prop, uint8_t *out)
+{
+	struct rsa_public_key key;
+	int ret;
+
+	if (!prop) {
+		debug("%s: Skipping invalid prop", __func__);
+		return -EBADF;
+	}
+	key.n0inv = prop->n0inv;
+	key.len = prop->num_bits;
+
+	if (!prop->public_exponent)
+		key.exponent = RSA_DEFAULT_PUBEXP;
+	else
+		key.exponent =
+			fdt64_to_cpu(*((uint64_t *)(prop->public_exponent)));
+
+	if (!key.len || !prop->modulus || !prop->rr) {
+		debug("%s: Missing RSA key info", __func__);
+		return -EFAULT;
+	}
+
+	/* Sanity check for stack size */
+	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
+		debug("RSA key bits %u outside allowed range %d..%d\n",
+		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
+		return -EFAULT;
+	}
+	key.len /= sizeof(uint32_t) * 8;
+	uint32_t key1[key.len], key2[key.len];
+
+	key.modulus = key1;
+	key.rr = key2;
+	rsa_convert_big_endian(key.modulus, (uint32_t *)prop->modulus, key.len);
+	rsa_convert_big_endian(key.rr, (uint32_t *)prop->rr, key.len);
+	if (!key.modulus || !key.rr) {
+		debug("%s: Out of memory", __func__);
+		return -ENOMEM;
+	}
+
+	uint32_t buf[sig_len / sizeof(uint32_t)];
+
+	memcpy(buf, sig, sig_len);
+
+	ret = pow_mod(&key, buf);
+	if (ret)
+		return ret;
+
+	memcpy(out, buf, sig_len);
+
+	return 0;
+}
diff --git a/lib/rsa/rsa-verify.c b/lib/rsa/rsa-verify.c
index 4ef19b6..60126d2 100644
--- a/lib/rsa/rsa-verify.c
+++ b/lib/rsa/rsa-verify.c
@@ -12,246 +12,46 @@
 #include <asm/errno.h>
 #include <asm/types.h>
 #include <asm/unaligned.h>
+#include <dm.h>
 #else
 #include "fdt_host.h"
 #include "mkimage.h"
 #include <fdt_support.h>
 #endif
+#include <u-boot/rsa-mod-exp.h>
 #include <u-boot/rsa.h>
-#include <u-boot/sha1.h>
-#include <u-boot/sha256.h>
-
-#define UINT64_MULT32(v, multby)  (((uint64_t)(v)) * ((uint32_t)(multby)))
-
-#define get_unaligned_be32(a) fdt32_to_cpu(*(uint32_t *)a)
-#define put_unaligned_be32(a, b) (*(uint32_t *)(b) = cpu_to_fdt32(a))
 
 /* Default public exponent for backward compatibility */
 #define RSA_DEFAULT_PUBEXP	65537
 
 /**
- * subtract_modulus() - subtract modulus from the given value
+ * rsa_verify_key() - Verify a signature against some data using RSA Key
  *
- * @key:	Key containing modulus to subtract
- * @num:	Number to subtract modulus from, as little endian word array
+ * Verify a RSA PKCS1.5 signature against an expected hash using
+ * the RSA Key properties in prop structure.
+ *
+ * @prop:	Specifies key
+ * @sig:	Signature
+ * @sig_len:	Number of bytes in signature
+ * @hash:	Pointer to the expected hash
+ * @algo:	Checksum algo structure having information on RSA padding etc.
+ * @return 0 if verified, -ve on error
  */
-static void subtract_modulus(const struct rsa_public_key *key, uint32_t num[])
-{
-	int64_t acc = 0;
-	uint i;
-
-	for (i = 0; i < key->len; i++) {
-		acc += (uint64_t)num[i] - key->modulus[i];
-		num[i] = (uint32_t)acc;
-		acc >>= 32;
-	}
-}
-
-/**
- * greater_equal_modulus() - check if a value is >= modulus
- *
- * @key:	Key containing modulus to check
- * @num:	Number to check against modulus, as little endian word array
- * @return 0 if num < modulus, 1 if num >= modulus
- */
-static int greater_equal_modulus(const struct rsa_public_key *key,
-				 uint32_t num[])
-{
-	int i;
-
-	for (i = (int)key->len - 1; i >= 0; i--) {
-		if (num[i] < key->modulus[i])
-			return 0;
-		if (num[i] > key->modulus[i])
-			return 1;
-	}
-
-	return 1;  /* equal */
-}
-
-/**
- * montgomery_mul_add_step() - Perform montgomery multiply-add step
- *
- * Operation: montgomery result[] += a * b[] / n0inv % modulus
- *
- * @key:	RSA key
- * @result:	Place to put result, as little endian word array
- * @a:		Multiplier
- * @b:		Multiplicand, as little endian word array
- */
-static void montgomery_mul_add_step(const struct rsa_public_key *key,
-		uint32_t result[], const uint32_t a, const uint32_t b[])
-{
-	uint64_t acc_a, acc_b;
-	uint32_t d0;
-	uint i;
-
-	acc_a = (uint64_t)a * b[0] + result[0];
-	d0 = (uint32_t)acc_a * key->n0inv;
-	acc_b = (uint64_t)d0 * key->modulus[0] + (uint32_t)acc_a;
-	for (i = 1; i < key->len; i++) {
-		acc_a = (acc_a >> 32) + (uint64_t)a * b[i] + result[i];
-		acc_b = (acc_b >> 32) + (uint64_t)d0 * key->modulus[i] +
-				(uint32_t)acc_a;
-		result[i - 1] = (uint32_t)acc_b;
-	}
-
-	acc_a = (acc_a >> 32) + (acc_b >> 32);
-
-	result[i - 1] = (uint32_t)acc_a;
-
-	if (acc_a >> 32)
-		subtract_modulus(key, result);
-}
-
-/**
- * montgomery_mul() - Perform montgomery mutitply
- *
- * Operation: montgomery result[] = a[] * b[] / n0inv % modulus
- *
- * @key:	RSA key
- * @result:	Place to put result, as little endian word array
- * @a:		Multiplier, as little endian word array
- * @b:		Multiplicand, as little endian word array
- */
-static void montgomery_mul(const struct rsa_public_key *key,
-		uint32_t result[], uint32_t a[], const uint32_t b[])
-{
-	uint i;
-
-	for (i = 0; i < key->len; ++i)
-		result[i] = 0;
-	for (i = 0; i < key->len; ++i)
-		montgomery_mul_add_step(key, result, a[i], b);
-}
-
-/**
- * num_pub_exponent_bits() - Number of bits in the public exponent
- *
- * @key:	RSA key
- * @num_bits:	Storage for the number of public exponent bits
- */
-static int num_public_exponent_bits(const struct rsa_public_key *key,
-		int *num_bits)
-{
-	uint64_t exponent;
-	int exponent_bits;
-	const uint max_bits = (sizeof(exponent) * 8);
-
-	exponent = key->exponent;
-	exponent_bits = 0;
-
-	if (!exponent) {
-		*num_bits = exponent_bits;
-		return 0;
-	}
-
-	for (exponent_bits = 1; exponent_bits < max_bits + 1; ++exponent_bits)
-		if (!(exponent >>= 1)) {
-			*num_bits = exponent_bits;
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
-/**
- * is_public_exponent_bit_set() - Check if a bit in the public exponent is set
- *
- * @key:	RSA key
- * @pos:	The bit position to check
- */
-static int is_public_exponent_bit_set(const struct rsa_public_key *key,
-		int pos)
-{
-	return key->exponent & (1ULL << pos);
-}
-
-/**
- * pow_mod() - in-place public exponentiation
- *
- * @key:	RSA key
- * @inout:	Big-endian word array containing value and result
- */
-static int pow_mod(const struct rsa_public_key *key, uint32_t *inout)
-{
-	uint32_t *result, *ptr;
-	uint i;
-	int j, k;
-
-	/* Sanity check for stack size - key->len is in 32-bit words */
-	if (key->len > RSA_MAX_KEY_BITS / 32) {
-		debug("RSA key words %u exceeds maximum %d\n", key->len,
-		      RSA_MAX_KEY_BITS / 32);
-		return -EINVAL;
-	}
-
-	uint32_t val[key->len], acc[key->len], tmp[key->len];
-	uint32_t a_scaled[key->len];
-	result = tmp;  /* Re-use location. */
-
-	/* Convert from big endian byte array to little endian word array. */
-	for (i = 0, ptr = inout + key->len - 1; i < key->len; i++, ptr--)
-		val[i] = get_unaligned_be32(ptr);
-
-	if (0 != num_public_exponent_bits(key, &k))
-		return -EINVAL;
-
-	if (k < 2) {
-		debug("Public exponent is too short (%d bits, minimum 2)\n",
-		      k);
-		return -EINVAL;
-	}
-
-	if (!is_public_exponent_bit_set(key, 0)) {
-		debug("LSB of RSA public exponent must be set.\n");
-		return -EINVAL;
-	}
-
-	/* the bit at e[k-1] is 1 by definition, so start with: C := M */
-	montgomery_mul(key, acc, val, key->rr); /* acc = a * RR / R mod n */
-	/* retain scaled version for intermediate use */
-	memcpy(a_scaled, acc, key->len * sizeof(a_scaled[0]));
-
-	for (j = k - 2; j > 0; --j) {
-		montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
-
-		if (is_public_exponent_bit_set(key, j)) {
-			/* acc = tmp * val / R mod n */
-			montgomery_mul(key, acc, tmp, a_scaled);
-		} else {
-			/* e[j] == 0, copy tmp back to acc for next operation */
-			memcpy(acc, tmp, key->len * sizeof(acc[0]));
-		}
-	}
-
-	/* the bit at e[0] is always 1 */
-	montgomery_mul(key, tmp, acc, acc); /* tmp = acc^2 / R mod n */
-	montgomery_mul(key, acc, tmp, val); /* acc = tmp * a / R mod M */
-	memcpy(result, acc, key->len * sizeof(result[0]));
-
-	/* Make sure result < mod; result is at most 1x mod too large. */
-	if (greater_equal_modulus(key, result))
-		subtract_modulus(key, result);
-
-	/* Convert to bigendian byte array */
-	for (i = key->len - 1, ptr = inout; (int)i >= 0; i--, ptr++)
-		put_unaligned_be32(result[i], ptr);
-	return 0;
-}
-
-static int rsa_verify_key(const struct rsa_public_key *key, const uint8_t *sig,
+static int rsa_verify_key(struct key_prop *prop, const uint8_t *sig,
 			  const uint32_t sig_len, const uint8_t *hash,
 			  struct checksum_algo *algo)
 {
 	const uint8_t *padding;
 	int pad_len;
 	int ret;
+#if !defined(USE_HOSTCC)
+	struct udevice *mod_exp_dev;
+#endif
 
-	if (!key || !sig || !hash || !algo)
+	if (!prop || !sig || !hash || !algo)
 		return -EIO;
 
-	if (sig_len != (key->len * sizeof(uint32_t))) {
+	if (sig_len != (prop->num_bits / 8)) {
 		debug("Signature is of incorrect length %d\n", sig_len);
 		return -EINVAL;
 	}
@@ -265,13 +65,23 @@
 		return -EINVAL;
 	}
 
-	uint32_t buf[sig_len / sizeof(uint32_t)];
+	uint8_t buf[sig_len];
 
-	memcpy(buf, sig, sig_len);
+#if !defined(USE_HOSTCC)
+	ret = uclass_get_device(UCLASS_MOD_EXP, 0, &mod_exp_dev);
+	if (ret) {
+		printf("RSA: Can't find Modular Exp implementation\n");
+		return -EINVAL;
+	}
 
-	ret = pow_mod(key, buf);
-	if (ret)
+	ret = rsa_mod_exp(mod_exp_dev, sig, sig_len, prop, buf);
+#else
+	ret = rsa_mod_exp_sw(sig, sig_len, prop, buf);
+#endif
+	if (ret) {
+		debug("Error in Modular exponentation\n");
 		return ret;
+	}
 
 	padding = algo->rsa_padding;
 	pad_len = algo->pad_len - algo->checksum_len;
@@ -291,72 +101,57 @@
 	return 0;
 }
 
-static void rsa_convert_big_endian(uint32_t *dst, const uint32_t *src, int len)
-{
-	int i;
-
-	for (i = 0; i < len; i++)
-		dst[i] = fdt32_to_cpu(src[len - 1 - i]);
-}
-
+/**
+ * rsa_verify_with_keynode() - Verify a signature against some data using
+ * information in node with prperties of RSA Key like modulus, exponent etc.
+ *
+ * Parse sign-node and fill a key_prop structure with properties of the
+ * key.  Verify a RSA PKCS1.5 signature against an expected hash using
+ * the properties parsed
+ *
+ * @info:	Specifies key and FIT information
+ * @hash:	Pointer to the expected hash
+ * @sig:	Signature
+ * @sig_len:	Number of bytes in signature
+ * @node:	Node having the RSA Key properties
+ * @return 0 if verified, -ve on error
+ */
 static int rsa_verify_with_keynode(struct image_sign_info *info,
-		const void *hash, uint8_t *sig, uint sig_len, int node)
+				   const void *hash, uint8_t *sig,
+				   uint sig_len, int node)
 {
 	const void *blob = info->fdt_blob;
-	struct rsa_public_key key;
-	const void *modulus, *rr;
-	const uint64_t *public_exponent;
+	struct key_prop prop;
 	int length;
-	int ret;
+	int ret = 0;
 
 	if (node < 0) {
 		debug("%s: Skipping invalid node", __func__);
 		return -EBADF;
 	}
-	if (!fdt_getprop(blob, node, "rsa,n0-inverse", NULL)) {
-		debug("%s: Missing rsa,n0-inverse", __func__);
-		return -EFAULT;
-	}
-	key.len = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
-	key.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
-	public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
-	if (!public_exponent || length < sizeof(*public_exponent))
-		key.exponent = RSA_DEFAULT_PUBEXP;
-	else
-		key.exponent = fdt64_to_cpu(*public_exponent);
-	modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
-	rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
-	if (!key.len || !modulus || !rr) {
+
+	prop.num_bits = fdtdec_get_int(blob, node, "rsa,num-bits", 0);
+
+	prop.n0inv = fdtdec_get_int(blob, node, "rsa,n0-inverse", 0);
+
+	prop.public_exponent = fdt_getprop(blob, node, "rsa,exponent", &length);
+	if (!prop.public_exponent || length < sizeof(uint64_t))
+		prop.public_exponent = NULL;
+
+	prop.exp_len = sizeof(uint64_t);
+
+	prop.modulus = fdt_getprop(blob, node, "rsa,modulus", NULL);
+
+	prop.rr = fdt_getprop(blob, node, "rsa,r-squared", NULL);
+
+	if (!prop.num_bits || !prop.modulus) {
 		debug("%s: Missing RSA key info", __func__);
 		return -EFAULT;
 	}
 
-	/* Sanity check for stack size */
-	if (key.len > RSA_MAX_KEY_BITS || key.len < RSA_MIN_KEY_BITS) {
-		debug("RSA key bits %u outside allowed range %d..%d\n",
-		      key.len, RSA_MIN_KEY_BITS, RSA_MAX_KEY_BITS);
-		return -EFAULT;
-	}
-	key.len /= sizeof(uint32_t) * 8;
-	uint32_t key1[key.len], key2[key.len];
+	ret = rsa_verify_key(&prop, sig, sig_len, hash, info->algo->checksum);
 
-	key.modulus = key1;
-	key.rr = key2;
-	rsa_convert_big_endian(key.modulus, modulus, key.len);
-	rsa_convert_big_endian(key.rr, rr, key.len);
-	if (!key.modulus || !key.rr) {
-		debug("%s: Out of memory", __func__);
-		return -ENOMEM;
-	}
-
-	debug("key length %d\n", key.len);
-	ret = rsa_verify_key(&key, sig, sig_len, hash, info->algo->checksum);
-	if (ret) {
-		printf("%s: RSA failed to verify: %d\n", __func__, ret);
-		return ret;
-	}
-
-	return 0;
+	return ret;
 }
 
 int rsa_verify(struct image_sign_info *info,
@@ -389,7 +184,12 @@
 	}
 
 	/* Calculate checksum with checksum-algorithm */
-	info->algo->checksum->calculate(region, region_count, hash);
+	ret = info->algo->checksum->calculate(info->algo->checksum->name,
+					region, region_count, hash);
+	if (ret < 0) {
+		debug("%s: Error in checksum calculation\n", __func__);
+		return -EINVAL;
+	}
 
 	/* See if we must use a particular key */
 	if (info->required_keynode != -1) {
diff --git a/test/dm/bus.c b/test/dm/bus.c
index abbaccf..faffe6a 100644
--- a/test/dm/bus.c
+++ b/test/dm/bus.c
@@ -9,11 +9,18 @@
 #include <dm/device-internal.h>
 #include <dm/root.h>
 #include <dm/test.h>
+#include <dm/uclass-internal.h>
 #include <dm/ut.h>
 #include <dm/util.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+struct dm_test_parent_platdata {
+	int count;
+	int bind_flag;
+	int uclass_bind_flag;
+};
+
 enum {
 	FLAG_CHILD_PROBED	= 10,
 	FLAG_CHILD_REMOVED	= -7,
@@ -26,6 +33,17 @@
 	return dm_scan_fdt_node(dev, gd->fdt_blob, dev->of_offset, false);
 }
 
+static int testbus_child_post_bind(struct udevice *dev)
+{
+	struct dm_test_parent_platdata *plat;
+
+	plat = dev_get_parent_platdata(dev);
+	plat->bind_flag = 1;
+	plat->uclass_bind_flag = 2;
+
+	return 0;
+}
+
 static int testbus_child_pre_probe(struct udevice *dev)
 {
 	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
@@ -35,6 +53,15 @@
 	return 0;
 }
 
+static int testbus_child_pre_probe_uclass(struct udevice *dev)
+{
+	struct dm_test_priv *priv = dev_get_priv(dev);
+
+	priv->uclass_flag++;
+
+	return 0;
+}
+
 static int testbus_child_post_remove(struct udevice *dev)
 {
 	struct dm_test_parent_data *parent_data = dev_get_parentdata(dev);
@@ -59,9 +86,12 @@
 	.of_match	= testbus_ids,
 	.id	= UCLASS_TEST_BUS,
 	.probe	= testbus_drv_probe,
+	.child_post_bind = testbus_child_post_bind,
 	.priv_auto_alloc_size = sizeof(struct dm_test_priv),
 	.platdata_auto_alloc_size = sizeof(struct dm_test_pdata),
 	.per_child_auto_alloc_size = sizeof(struct dm_test_parent_data),
+	.per_child_platdata_auto_alloc_size =
+			sizeof(struct dm_test_parent_platdata),
 	.child_pre_probe = testbus_child_pre_probe,
 	.child_post_remove = testbus_child_post_remove,
 };
@@ -69,12 +99,14 @@
 UCLASS_DRIVER(testbus) = {
 	.name		= "testbus",
 	.id		= UCLASS_TEST_BUS,
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.child_pre_probe = testbus_child_pre_probe_uclass,
 };
 
 /* Test that we can probe for children */
 static int dm_test_bus_children(struct dm_test_state *dms)
 {
-	int num_devices = 4;
+	int num_devices = 6;
 	struct udevice *bus;
 	struct uclass *uc;
 
@@ -172,7 +204,7 @@
 	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
 /* Test that the bus can store data about each child */
-static int dm_test_bus_parent_data(struct dm_test_state *dms)
+static int test_bus_parent_data(struct dm_test_state *dms)
 {
 	struct dm_test_parent_data *parent_data;
 	struct udevice *bus, *dev;
@@ -231,9 +263,36 @@
 
 	return 0;
 }
-
+/* Test that the bus can store data about each child */
+static int dm_test_bus_parent_data(struct dm_test_state *dms)
+{
+	return test_bus_parent_data(dms);
+}
 DM_TEST(dm_test_bus_parent_data, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
 
+/* As above but the size is controlled by the uclass */
+static int dm_test_bus_parent_data_uclass(struct dm_test_state *dms)
+{
+	struct udevice *bus;
+	int size;
+	int ret;
+
+	/* Set the driver size to 0 so that the uclass size is used */
+	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
+	size = bus->driver->per_child_auto_alloc_size;
+	bus->uclass->uc_drv->per_child_auto_alloc_size = size;
+	bus->driver->per_child_auto_alloc_size = 0;
+	ret = test_bus_parent_data(dms);
+	if (ret)
+		return ret;
+	bus->uclass->uc_drv->per_child_auto_alloc_size = 0;
+	bus->driver->per_child_auto_alloc_size = size;
+
+	return 0;
+}
+DM_TEST(dm_test_bus_parent_data_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
 /* Test that the bus ops are called when a child is probed/removed */
 static int dm_test_bus_parent_ops(struct dm_test_state *dms)
 {
@@ -271,3 +330,188 @@
 	return 0;
 }
 DM_TEST(dm_test_bus_parent_ops, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+static int test_bus_parent_platdata(struct dm_test_state *dms)
+{
+	struct dm_test_parent_platdata *plat;
+	struct udevice *bus, *dev;
+	int child_count;
+
+	/* Check that the bus has no children */
+	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
+	device_find_first_child(bus, &dev);
+	ut_asserteq_ptr(NULL, dev);
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		/* Check that platform data is allocated */
+		plat = dev_get_parent_platdata(dev);
+		ut_assert(plat != NULL);
+
+		/*
+		 * Check that it is not affected by the device being
+		 * probed/removed
+		 */
+		plat->count++;
+		ut_asserteq(1, plat->count);
+		device_probe(dev);
+		device_remove(dev);
+
+		ut_asserteq_ptr(plat, dev_get_parent_platdata(dev));
+		ut_asserteq(1, plat->count);
+		ut_assertok(device_probe(dev));
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	/* Removing the bus should also have no effect (it is still bound) */
+	device_remove(bus);
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		/* Check that platform data is allocated */
+		plat = dev_get_parent_platdata(dev);
+		ut_assert(plat != NULL);
+		ut_asserteq(1, plat->count);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	/* Unbind all the children */
+	do {
+		device_find_first_child(bus, &dev);
+		if (dev)
+			device_unbind(dev);
+	} while (dev);
+
+	/* Now the child platdata should be removed and re-added */
+	device_probe(bus);
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		/* Check that platform data is allocated */
+		plat = dev_get_parent_platdata(dev);
+		ut_assert(plat != NULL);
+		ut_asserteq(0, plat->count);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	return 0;
+}
+
+/* Test that the bus can store platform data about each child */
+static int dm_test_bus_parent_platdata(struct dm_test_state *dms)
+{
+	return test_bus_parent_platdata(dms);
+}
+DM_TEST(dm_test_bus_parent_platdata, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* As above but the size is controlled by the uclass */
+static int dm_test_bus_parent_platdata_uclass(struct dm_test_state *dms)
+{
+	struct udevice *bus;
+	int size;
+	int ret;
+
+	/* Set the driver size to 0 so that the uclass size is used */
+	ut_assertok(uclass_find_device(UCLASS_TEST_BUS, 0, &bus));
+	size = bus->driver->per_child_platdata_auto_alloc_size;
+	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = size;
+	bus->driver->per_child_platdata_auto_alloc_size = 0;
+	ret = test_bus_parent_platdata(dms);
+	if (ret)
+		return ret;
+	bus->uclass->uc_drv->per_child_platdata_auto_alloc_size = 0;
+	bus->driver->per_child_platdata_auto_alloc_size = size;
+
+	return 0;
+}
+DM_TEST(dm_test_bus_parent_platdata_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that the child post_bind method is called */
+static int dm_test_bus_child_post_bind(struct dm_test_state *dms)
+{
+	struct dm_test_parent_platdata *plat;
+	struct udevice *bus, *dev;
+	int child_count;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		/* Check that platform data is allocated */
+		plat = dev_get_parent_platdata(dev);
+		ut_assert(plat != NULL);
+		ut_asserteq(1, plat->bind_flag);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_child_post_bind, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that the child post_bind method is called */
+static int dm_test_bus_child_post_bind_uclass(struct dm_test_state *dms)
+{
+	struct dm_test_parent_platdata *plat;
+	struct udevice *bus, *dev;
+	int child_count;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		/* Check that platform data is allocated */
+		plat = dev_get_parent_platdata(dev);
+		ut_assert(plat != NULL);
+		ut_asserteq(2, plat->uclass_bind_flag);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_child_post_bind_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/*
+ * Test that the bus' uclass' child_pre_probe() is called before the
+ * device's probe() method
+ */
+static int dm_test_bus_child_pre_probe_uclass(struct dm_test_state *dms)
+{
+	struct udevice *bus, *dev;
+	int child_count;
+
+	/*
+	 * See testfdt_drv_probe() which effectively checks that the uclass
+	 * flag is set before that method is called
+	 */
+	ut_assertok(uclass_get_device(UCLASS_TEST_BUS, 0, &bus));
+	for (device_find_first_child(bus, &dev), child_count = 0;
+	     dev;
+	     device_find_next_child(&dev)) {
+		struct dm_test_priv *priv = dev_get_priv(dev);
+
+		/* Check that things happened in the right order */
+		ut_asserteq_ptr(NULL, priv);
+		ut_assertok(device_probe(dev));
+
+		priv = dev_get_priv(dev);
+		ut_assert(priv != NULL);
+		ut_asserteq(1, priv->uclass_flag);
+		ut_asserteq(1, priv->uclass_total);
+		child_count++;
+	}
+	ut_asserteq(3, child_count);
+
+	return 0;
+}
+DM_TEST(dm_test_bus_child_pre_probe_uclass,
+	DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/core.c b/test/dm/core.c
index ff5c2a7..eccda09 100644
--- a/test/dm/core.c
+++ b/test/dm/core.c
@@ -598,3 +598,14 @@
 }
 
 DM_TEST(dm_test_uclass_before_ready, 0);
+
+static int dm_test_device_get_uclass_id(struct dm_test_state *dms)
+{
+	struct udevice *dev;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST, 0, &dev));
+	ut_asserteq(UCLASS_TEST, device_get_uclass_id(dev));
+
+	return 0;
+}
+DM_TEST(dm_test_device_get_uclass_id, DM_TESTF_SCAN_PDATA);
diff --git a/test/dm/gpio.c b/test/dm/gpio.c
index 94bd0d9..b29daf1 100644
--- a/test/dm/gpio.c
+++ b/test/dm/gpio.c
@@ -174,5 +174,72 @@
 
 	return 0;
 }
-
 DM_TEST(dm_test_gpio_leak, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
+
+/* Test that we can find GPIOs using phandles */
+static int dm_test_gpio_phandles(struct dm_test_state *dms)
+{
+	struct gpio_desc desc, desc_list[8], desc_list2[8];
+	struct udevice *dev, *gpio_a, *gpio_b;
+
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
+	ut_asserteq_str("a-test", dev->name);
+
+	ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0));
+	ut_assertok(uclass_get_device(UCLASS_GPIO, 1, &gpio_a));
+	ut_assertok(uclass_get_device(UCLASS_GPIO, 2, &gpio_b));
+	ut_asserteq_str("base-gpios", gpio_a->name);
+	ut_asserteq(true, !!device_active(gpio_a));
+	ut_asserteq_ptr(gpio_a, desc.dev);
+	ut_asserteq(4, desc.offset);
+	/* GPIOF_INPUT is the sandbox GPIO driver default */
+	ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 4, NULL));
+	ut_assertok(dm_gpio_free(dev, &desc));
+
+	ut_asserteq(-ENOENT, gpio_request_by_name(dev, "test-gpios", 3, &desc,
+						  0));
+	ut_asserteq_ptr(NULL, desc.dev);
+	ut_asserteq(desc.offset, 0);
+	ut_asserteq(-ENOENT, gpio_request_by_name(dev, "test-gpios", 5, &desc,
+						  0));
+
+	/* Last GPIO is ignord as it comes after <0> */
+	ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc_list,
+						 ARRAY_SIZE(desc_list), 0));
+	ut_asserteq(-EBUSY, gpio_request_list_by_name(dev, "test-gpios",
+						      desc_list2,
+						      ARRAY_SIZE(desc_list2),
+						      0));
+	ut_assertok(gpio_free_list(dev, desc_list, 3));
+	ut_asserteq(3, gpio_request_list_by_name(dev,  "test-gpios", desc_list,
+						 ARRAY_SIZE(desc_list),
+						 GPIOD_IS_OUT |
+						 GPIOD_IS_OUT_ACTIVE));
+	ut_asserteq_ptr(gpio_a, desc_list[0].dev);
+	ut_asserteq(1, desc_list[0].offset);
+	ut_asserteq_ptr(gpio_a, desc_list[1].dev);
+	ut_asserteq(4, desc_list[1].offset);
+	ut_asserteq_ptr(gpio_b, desc_list[2].dev);
+	ut_asserteq(5, desc_list[2].offset);
+	ut_asserteq(1, dm_gpio_get_value(desc_list));
+	ut_assertok(gpio_free_list(dev, desc_list, 3));
+
+	ut_asserteq(6, gpio_request_list_by_name(dev, "test2-gpios", desc_list,
+						 ARRAY_SIZE(desc_list), 0));
+	/* This was set to output previously, so still will be */
+	ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_a, 1, NULL));
+
+	/* Active low should invert the input value */
+	ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_b, 6, NULL));
+	ut_asserteq(1, dm_gpio_get_value(&desc_list[2]));
+
+	ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_b, 7, NULL));
+	ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_b, 8, NULL));
+	ut_asserteq(0, dm_gpio_get_value(&desc_list[4]));
+	ut_asserteq(GPIOF_OUTPUT, gpio_get_function(gpio_b, 9, NULL));
+	ut_asserteq(1, dm_gpio_get_value(&desc_list[5]));
+
+
+	return 0;
+}
+DM_TEST(dm_test_gpio_phandles, DM_TESTF_SCAN_PDATA | DM_TESTF_SCAN_FDT);
diff --git a/test/dm/i2c.c b/test/dm/i2c.c
index a53e28d..ef88372 100644
--- a/test/dm/i2c.c
+++ b/test/dm/i2c.c
@@ -35,8 +35,8 @@
 	 * remove the emulation and the slave device.
 	 */
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_probe(bus, chip, 0, &dev));
-	ut_asserteq(-ENODEV, i2c_probe(bus, no_chip, 0, &dev));
+	ut_assertok(dm_i2c_probe(bus, chip, 0, &dev));
+	ut_asserteq(-ENODEV, dm_i2c_probe(bus, no_chip, 0, &dev));
 	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_I2C, 1, &bus));
 
 	return 0;
@@ -49,11 +49,11 @@
 	uint8_t buf[5];
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_get_chip(bus, chip, &dev));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
-	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0AB\0", sizeof(buf)));
 
 	return 0;
@@ -66,13 +66,13 @@
 	uint8_t buf[5];
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
 	ut_assertok(i2c_set_bus_speed(bus, 100000));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(i2c_set_bus_speed(bus, 400000));
 	ut_asserteq(400000, i2c_get_bus_speed(bus));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
-	ut_asserteq(-EINVAL, i2c_write(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
+	ut_asserteq(-EINVAL, dm_i2c_write(dev, 0, buf, 5));
 
 	return 0;
 }
@@ -84,9 +84,9 @@
 	uint8_t buf[5];
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_get_chip(bus, chip, &dev));
+	ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
 	ut_assertok(i2c_set_chip_offset_len(dev, 1));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 
 	/* This is not supported by the uclass */
 	ut_asserteq(-EINVAL, i2c_set_chip_offset_len(dev, 5));
@@ -100,7 +100,7 @@
 	struct udevice *bus, *dev;
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev));
+	ut_assertok(dm_i2c_probe(bus, SANDBOX_I2C_TEST_ADDR, 0, &dev));
 
 	return 0;
 }
@@ -113,8 +113,8 @@
 	uint8_t buf[5];
 
 	ut_assertok(uclass_get_device_by_seq(UCLASS_I2C, busnum, &bus));
-	ut_assertok(i2c_get_chip(bus, chip, &dev));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(i2c_get_chip(bus, chip, 1, &dev));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
 
 	/* Tell the EEPROM to only read/write one register at a time */
@@ -123,34 +123,34 @@
 	sandbox_i2c_eeprom_set_test_mode(eeprom, SIE_TEST_MODE_SINGLE_BYTE);
 
 	/* Now we only get the first byte - the rest will be 0xff */
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
 
 	/* If we do a separate transaction for each byte, it works */
 	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0\0\0\0", sizeof(buf)));
 
 	/* This will only write A */
 	ut_assertok(i2c_set_chip_flags(dev, 0));
-	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
 
 	/* Check that the B was ignored */
 	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_RD_ADDRESS));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0A\0\0\0", sizeof(buf)));
 
 	/* Now write it again with the new flags, it should work */
 	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS));
-	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\xff\xff\xff\xff", sizeof(buf)));
 
 	ut_assertok(i2c_set_chip_flags(dev, DM_I2C_CHIP_WR_ADDRESS |
 						DM_I2C_CHIP_RD_ADDRESS));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "\0\0AB\0\0", sizeof(buf)));
 
 	/* Restore defaults */
@@ -167,45 +167,45 @@
 	struct udevice *dev;
 	uint8_t buf[5];
 
-	ut_assertok(i2c_get_chip_for_busnum(busnum, chip, &dev));
+	ut_assertok(i2c_get_chip_for_busnum(busnum, chip, 1, &dev));
 
 	/* Do a transfer so we can find the emulator */
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(uclass_first_device(UCLASS_I2C_EMUL, &eeprom));
 
 	/* Offset length 0 */
 	sandbox_i2c_eeprom_set_offset_len(eeprom, 0);
 	ut_assertok(i2c_set_chip_offset_len(dev, 0));
-	ut_assertok(i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 10 /* ignored */, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "AB\0\0\0\0", sizeof(buf)));
 
 	/* Offset length 1 */
 	sandbox_i2c_eeprom_set_offset_len(eeprom, 1);
 	ut_assertok(i2c_set_chip_offset_len(dev, 1));
-	ut_assertok(i2c_write(dev, 2, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 2, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0, buf, 5));
 	ut_assertok(memcmp(buf, "ABAB\0", sizeof(buf)));
 
 	/* Offset length 2 */
 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
 	ut_assertok(i2c_set_chip_offset_len(dev, 2));
-	ut_assertok(i2c_write(dev, 0x210, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0x210, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 0x210, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0x210, buf, 5));
 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
 
 	/* Offset length 3 */
 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
 	ut_assertok(i2c_set_chip_offset_len(dev, 2));
-	ut_assertok(i2c_write(dev, 0x410, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0x410, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 0x410, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0x410, buf, 5));
 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
 
 	/* Offset length 4 */
 	sandbox_i2c_eeprom_set_offset_len(eeprom, 2);
 	ut_assertok(i2c_set_chip_offset_len(dev, 2));
-	ut_assertok(i2c_write(dev, 0x420, (uint8_t *)"AB", 2));
-	ut_assertok(i2c_read(dev, 0x420, buf, 5));
+	ut_assertok(dm_i2c_write(dev, 0x420, (uint8_t *)"AB", 2));
+	ut_assertok(dm_i2c_read(dev, 0x420, buf, 5));
 	ut_assertok(memcmp(buf, "AB\0\0\0", sizeof(buf)));
 
 	/* Restore defaults */
diff --git a/test/dm/spi.c b/test/dm/spi.c
index 61b5b25..c7ee652 100644
--- a/test/dm/spi.c
+++ b/test/dm/spi.c
@@ -36,7 +36,6 @@
 	ut_asserteq(0, uclass_get_device_by_seq(UCLASS_SPI, busnum, &bus));
 	ut_assertok(spi_cs_info(bus, cs, &info));
 	of_offset = info.dev->of_offset;
-	sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
 	device_remove(info.dev);
 	device_unbind(info.dev);
 
@@ -45,7 +44,7 @@
 	 * reports that CS 0 is present
 	 */
 	ut_assertok(spi_cs_info(bus, cs, &info));
-	ut_asserteq_ptr(info.dev, NULL);
+	ut_asserteq_ptr(NULL, info.dev);
 
 	/* This finds nothing because we removed the device */
 	ut_asserteq(-ENODEV, spi_find_bus_and_cs(busnum, cs, &bus, &dev));
@@ -62,8 +61,9 @@
 	ut_asserteq(-ENOENT, spi_get_bus_and_cs(busnum, cs, speed, mode,
 						"spi_flash_std", "name", &bus,
 						&slave));
+	sandbox_sf_unbind_emul(state_get_current(), busnum, cs);
 	ut_assertok(spi_cs_info(bus, cs, &info));
-	ut_asserteq_ptr(info.dev, NULL);
+	ut_asserteq_ptr(NULL, info.dev);
 
 	/* Add the emulation and try again */
 	ut_assertok(sandbox_sf_bind_emul(state, busnum, cs, bus, of_offset,
diff --git a/test/dm/test-dm.sh b/test/dm/test-dm.sh
index bb99677..8ebc392 100755
--- a/test/dm/test-dm.sh
+++ b/test/dm/test-dm.sh
@@ -1,9 +1,14 @@
 #!/bin/sh
 
+die() {
+	echo $1
+	exit 1
+}
+
 NUM_CPUS=$(cat /proc/cpuinfo |grep -c processor)
 dtc -I dts -O dtb test/dm/test.dts -o test/dm/test.dtb
-make O=sandbox sandbox_config
-make O=sandbox -s -j${NUM_CPUS}
+make O=sandbox sandbox_config || die "Cannot configure U-Boot"
+make O=sandbox -s -j${NUM_CPUS} || die "Cannot build U-Boot"
 dd if=/dev/zero of=spi.bin bs=1M count=2
 ./sandbox/u-boot -d test/dm/test.dtb -c "dm test"
 rm spi.bin
diff --git a/test/dm/test-fdt.c b/test/dm/test-fdt.c
index cd2c389..b8ee959 100644
--- a/test/dm/test-fdt.c
+++ b/test/dm/test-fdt.c
@@ -51,6 +51,13 @@
 
 	priv->ping_total += DM_TEST_START_TOTAL;
 
+	/*
+	 * If this device is on a bus, the uclass_flag will be set before
+	 * calling this function. This is used by
+	 * dm_test_bus_child_pre_probe_uclass().
+	 */
+	priv->uclass_total += priv->uclass_flag;
+
 	return 0;
 }
 
@@ -89,6 +96,7 @@
 UCLASS_DRIVER(testfdt) = {
 	.name		= "testfdt",
 	.id		= UCLASS_TEST_FDT,
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
 };
 
 int dm_check_devices(struct dm_test_state *dms, int num_devices)
@@ -128,7 +136,7 @@
 /* Test that FDT-based binding works correctly */
 static int dm_test_fdt(struct dm_test_state *dms)
 {
-	const int num_devices = 4;
+	const int num_devices = 6;
 	struct udevice *dev;
 	struct uclass *uc;
 	int ret;
@@ -143,12 +151,12 @@
 	/* These are num_devices compatible root-level device tree nodes */
 	ut_asserteq(num_devices, list_count_items(&uc->dev_head));
 
-	/* Each should have no platdata / priv */
+	/* Each should have platform data but no private data */
 	for (i = 0; i < num_devices; i++) {
 		ret = uclass_find_device(UCLASS_TEST_FDT, i, &dev);
 		ut_assert(!ret);
 		ut_assert(!dev_get_priv(dev));
-		ut_assert(!dev->platdata);
+		ut_assert(dev->platdata);
 	}
 
 	ut_assertok(dm_check_devices(dms, num_devices));
@@ -184,7 +192,7 @@
 	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 3, true, &dev));
 	ut_asserteq_str("b-test", dev->name);
 
-	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 0, true, &dev));
+	ut_assertok(uclass_find_device_by_seq(UCLASS_TEST_FDT, 8, true, &dev));
 	ut_asserteq_str("a-test", dev->name);
 
 	ut_asserteq(-ENODEV, uclass_find_device_by_seq(UCLASS_TEST_FDT, 5,
@@ -220,11 +228,11 @@
 	ut_asserteq(-ENODEV, uclass_get_device_by_seq(UCLASS_TEST_FDT, 1,
 						      &dev));
 	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
-	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 1, &dev));
+	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 4, &dev));
 
 	/* But now that it is probed, we can find it */
 	ut_assertok(uclass_get_device_by_seq(UCLASS_TEST_FDT, 1, &dev));
-	ut_asserteq_str("a-test", dev->name);
+	ut_asserteq_str("f-test", dev->name);
 
 	return 0;
 }
diff --git a/test/dm/test.dts b/test/dm/test.dts
index fb0272a..84024a4 100644
--- a/test/dm/test.dts
+++ b/test/dm/test.dts
@@ -8,7 +8,15 @@
 
 	aliases {
 		console = &uart0;
+		i2c0 = "/i2c@0";
+		spi0 = "/spi@0";
 		testfdt6 = "/e-test";
+		testbus3 = "/some-bus";
+		testfdt0 = "/some-bus/c-test@0";
+		testfdt1 = "/some-bus/c-test@1";
+		testfdt3 = "/b-test";
+		testfdt5 = "/some-bus/c-test@5";
+		testfdt8 = "/a-test";
 	};
 
 	uart0: serial {
@@ -22,6 +30,11 @@
 		ping-expect = <0>;
 		ping-add = <0>;
 		u-boot,dm-pre-reloc;
+		test-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 5 0 3 2 1>,
+			<0>, <&gpio_a 12>;
+		test2-gpios = <&gpio_a 1>, <&gpio_a 4>, <&gpio_b 6 1 3 2 1>,
+			<&gpio_b 7 2 3 2 1>, <&gpio_b 8 4 3 2 1>,
+			<&gpio_b 9 0xc 3 2 1>;
 	};
 
 	junk {
@@ -81,14 +94,26 @@
 		compatible = "google,another-fdt-test";
 	};
 
+	f-test {
+		compatible = "denx,u-boot-fdt-test";
+	};
+
+	g-test {
+		compatible = "denx,u-boot-fdt-test";
+	};
+
 	gpio_a: base-gpios {
 		compatible = "sandbox,gpio";
+		gpio-controller;
+		#gpio-cells = <1>;
 		gpio-bank-name = "a";
 		num-gpios = <20>;
 	};
 
-	extra-gpios {
+	gpio_b: extra-gpios {
 		compatible = "sandbox,gpio";
+		gpio-controller;
+		#gpio-cells = <5>;
 		gpio-bank-name = "b";
 		num-gpios = <10>;
 	};
diff --git a/tools/Makefile b/tools/Makefile
index cb44456..6e1ce79 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -60,7 +60,8 @@
 LIBFDT_OBJS := $(addprefix lib/libfdt/, \
 			fdt.o fdt_ro.o fdt_rw.o fdt_strerror.o fdt_wip.o)
 RSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/rsa/, \
-					rsa-sign.o rsa-verify.o rsa-checksum.o)
+					rsa-sign.o rsa-verify.o rsa-checksum.o \
+					rsa-mod-exp.o)
 
 # common objs for dumpimage and mkimage
 dumpimage-mkimage-objs := aisimage.o \
@@ -90,6 +91,7 @@
 			socfpgaimage.o \
 			lib/sha1.o \
 			lib/sha256.o \
+			common/hash.o \
 			ublimage.o \
 			$(LIBFDT_OBJS) \
 			$(RSA_OBJS-y)