Merge tag 'fsl-qoriq-for-v2018.11-rc1' of git://git.denx.de/u-boot-fsl-qoriq

Switch to driver model for eSDHC on Layerscape SoCs including LS1021A,
LS1043A, LS1046A, LS1088A, LS2088A.
Switch to driver model for SATA on LS1021A and LS1043A.
Add support for LS1012AFRWY rev C board.
Enable SMMU for LS1043A.
diff --git a/MAINTAINERS b/MAINTAINERS
index 64fb41e..ea21d59 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -383,12 +383,16 @@
 F:	doc/README.uefi
 F:	doc/README.iscsi
 F:	Documentation/efi.rst
+F:	include/capitalization.h
+F:	include/cp1250.h
+F:	include/cp437.h
 F:	include/efi*
 F:	include/pe.h
 F:	include/asm-generic/pe.h
 F:	lib/charset.c
 F:	lib/efi*/
 F:	test/py/tests/test_efi*
+F:	test/unicode_ut.c
 F:	cmd/bootefi.c
 F:	tools/file2include.c
 
diff --git a/Makefile b/Makefile
index e38966e..3561fb0 100644
--- a/Makefile
+++ b/Makefile
@@ -372,7 +372,7 @@
 KBUILD_CFLAGS   := -Wall -Wstrict-prototypes \
 		   -Wno-format-security \
 		   -fno-builtin -ffreestanding $(CSTD_FLAG)
-KBUILD_CFLAGS	+= -fshort-wchar
+KBUILD_CFLAGS	+= -fshort-wchar -fno-strict-aliasing
 KBUILD_AFLAGS   := -D__ASSEMBLY__
 
 # Don't generate position independent code
diff --git a/README b/README
index 09822a3..f7ed7ea 100644
--- a/README
+++ b/README
@@ -528,25 +528,6 @@
 		pointer. This is needed for the temporary stack before
 		relocation.
 
-		CONFIG_SYS_MIPS_CACHE_MODE
-
-		Cache operation mode for the MIPS CPU.
-		See also arch/mips/include/asm/mipsregs.h.
-		Possible values are:
-			CONF_CM_CACHABLE_NO_WA
-			CONF_CM_CACHABLE_WA
-			CONF_CM_UNCACHED
-			CONF_CM_CACHABLE_NONCOHERENT
-			CONF_CM_CACHABLE_CE
-			CONF_CM_CACHABLE_COW
-			CONF_CM_CACHABLE_CUW
-			CONF_CM_CACHABLE_ACCELERATED
-
-		CONFIG_SYS_XWAY_EBU_BOOTCFG
-
-		Special option for Lantiq XWAY SoCs for booting from NOR flash.
-		See also arch/mips/cpu/mips32/start.S.
-
 		CONFIG_XWAY_SWAP_BYTES
 
 		Enable compilation of tools/xway-swap-bytes needed for Lantiq
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0f8dd32..ccf2a84 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -747,6 +747,8 @@
 	select OF_CONTROL
 	select PL01X_SERIAL
 	imply CMD_DM
+	imply DM_RTC
+	imply RTC_PL031
 
 config ARCH_RMOBILE
 	bool "Renesas ARM SoCs"
@@ -861,7 +863,6 @@
 config ARCH_ZYNQ
 	bool "Xilinx Zynq based platform"
 	select BOARD_EARLY_INIT_F if WDT
-	select BOARD_LATE_INIT
 	select CLK
 	select CLK_ZYNQ
 	select CPU_V7A
@@ -881,6 +882,7 @@
 	select SPL_SEPARATE_BSS if SPL
 	select SUPPORT_SPL
 	imply ARCH_EARLY_INIT_R
+	imply BOARD_LATE_INIT
 	imply CMD_CLK
 	imply CMD_DM
 	imply CMD_SPL
@@ -898,7 +900,6 @@
 config ARCH_ZYNQMP
 	bool "Xilinx ZynqMP based platform"
 	select ARM64
-	select BOARD_LATE_INIT
 	select CLK
 	select DM
 	select DM_SERIAL
@@ -907,6 +908,7 @@
 	select SPL_BOARD_INIT if SPL
 	select SPL_CLK if SPL
 	select SUPPORT_SPL
+	imply BOARD_LATE_INIT
 	imply CMD_DM
 	imply FAT_WRITE
 
diff --git a/arch/arm/cpu/arm926ejs/spear/cpu.c b/arch/arm/cpu/arm926ejs/spear/cpu.c
index 88a40c6..51c4a73 100644
--- a/arch/arm/cpu/arm926ejs/spear/cpu.c
+++ b/arch/arm/cpu/arm926ejs/spear/cpu.c
@@ -52,6 +52,9 @@
 #if defined(CONFIG_SPEAR_GPIO)
 	periph1_clken |= MISC_GPIO3ENB | MISC_GPIO4ENB;
 #endif
+#if defined(CONFIG_PL022_SPI)
+	periph1_clken |= MISC_SSP1ENB | MISC_SSP2ENB | MISC_SSP3ENB;
+#endif
 
 	writel(periph1_clken, &misc_p->periph1_clken);
 
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
index 052e070..be00bd5 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/cpu.c
@@ -835,7 +835,7 @@
 	return 0;
 }
 
-#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER)
 void efi_add_known_memory(void)
 {
 	int i;
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
index fc9de73..c9c2c3f 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fdt.c
@@ -135,7 +135,7 @@
 
 	fdt_add_mem_rsv(blob, (uintptr_t)&secondary_boot_code,
 			*boot_code_size);
-#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER)
 	efi_add_memory_map((uintptr_t)&secondary_boot_code,
 			   ALIGN(*boot_code_size, EFI_PAGE_SIZE) >> EFI_PAGE_SHIFT,
 			   EFI_RESERVED_MEMORY_TYPE, false);
diff --git a/arch/arm/cpu/armv8/zynqmp/cpu.c b/arch/arm/cpu/armv8/zynqmp/cpu.c
index 1279dc8..43ba739 100644
--- a/arch/arm/cpu/armv8/zynqmp/cpu.c
+++ b/arch/arm/cpu/armv8/zynqmp/cpu.c
@@ -171,38 +171,28 @@
 	return regs.regs[0];
 }
 
-#define ZYNQMP_SIP_SVC_GET_API_VERSION		0xC2000001
-
-#define ZYNQMP_PM_VERSION_MAJOR		1
-#define ZYNQMP_PM_VERSION_MINOR		0
-#define ZYNQMP_PM_VERSION_MAJOR_SHIFT	16
-#define ZYNQMP_PM_VERSION_MINOR_MASK	0xFFFF
-
-#define ZYNQMP_PM_VERSION	\
-	((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \
-				 ZYNQMP_PM_VERSION_MINOR)
-
 #if defined(CONFIG_CLK_ZYNQMP)
-void zynqmp_pmufw_version(void)
+unsigned int zynqmp_pmufw_version(void)
 {
 	int ret;
 	u32 ret_payload[PAYLOAD_ARG_CNT];
-	u32 pm_api_version;
+	static u32 pm_api_version = ZYNQMP_PM_VERSION_INVALID;
 
-	ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0,
-			 ret_payload);
-	pm_api_version = ret_payload[1];
+	/*
+	 * Get PMU version only once and later
+	 * just return stored values instead of
+	 * asking PMUFW again.
+	 */
+	if (pm_api_version == ZYNQMP_PM_VERSION_INVALID) {
+		ret = invoke_smc(ZYNQMP_SIP_SVC_GET_API_VERSION, 0, 0, 0, 0,
+				 ret_payload);
+		pm_api_version = ret_payload[1];
 
-	if (ret)
-		panic("PMUFW is not found - Please load it!\n");
-
-	printf("PMUFW:\tv%d.%d\n",
-	       pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
-	       pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK);
+		if (ret)
+			panic("PMUFW is not found - Please load it!\n");
+	}
 
-	if (pm_api_version < ZYNQMP_PM_VERSION)
-		panic("PMUFW version error. Expected: v%d.%d\n",
-		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
+	return pm_api_version;
 }
 #endif
 
diff --git a/arch/arm/dts/am3517-evm-u-boot.dtsi b/arch/arm/dts/am3517-evm-u-boot.dtsi
index c02beaa..59df819 100644
--- a/arch/arm/dts/am3517-evm-u-boot.dtsi
+++ b/arch/arm/dts/am3517-evm-u-boot.dtsi
@@ -10,10 +10,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/at91-sama5d27_som1_ek.dts b/arch/arm/dts/at91-sama5d27_som1_ek.dts
index 5e62d4a..4cd6db6 100644
--- a/arch/arm/dts/at91-sama5d27_som1_ek.dts
+++ b/arch/arm/dts/at91-sama5d27_som1_ek.dts
@@ -54,6 +54,18 @@
 		stdout-path = &uart1;
 	};
 
+	onewire_tm: onewire {
+		gpios = <&pioA 17 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire_tm_default>;
+		status = "okay";
+
+		w1_eeprom: w1_eeprom@0 {
+			compatible = "maxim,ds24b33";
+			status = "okay";
+		};
+	};
+
 	ahb {
 		usb1: ohci@00400000 {
 			num-ports = <3>;
@@ -208,6 +220,11 @@
 						pinmux = <PIN_PA31__GPIO>;
 						bias-disable;
 					};
+
+					pinctrl_onewire_tm_default: onewire_tm_default {
+						pinmux = <PIN_PA17__GPIO>;
+						bias-pull-up;
+					};
 				};
 			};
 		};
diff --git a/arch/arm/dts/at91-sama5d2_ptc_ek.dts b/arch/arm/dts/at91-sama5d2_ptc_ek.dts
index ab5ab21..068a117 100644
--- a/arch/arm/dts/at91-sama5d2_ptc_ek.dts
+++ b/arch/arm/dts/at91-sama5d2_ptc_ek.dts
@@ -56,6 +56,18 @@
 		stdout-path = &uart0;
 	};
 
+	onewire_tm: onewire {
+		gpios = <&pioA PIN_PB31 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire_tm_default>;
+		status = "okay";
+
+		w1_eeprom: w1_eeprom@0 {
+			compatible = "maxim,ds24b33";
+			status = "okay";
+		};
+	};
+
 	ahb {
 		usb0: gadget@00300000 {
 			atmel,vbus-gpio = <&pioA PIN_PA27 GPIO_ACTIVE_HIGH>;
@@ -208,6 +220,11 @@
 						pinmux = <PIN_PB11__GPIO>;
 						bias-disable;
 					};
+
+					pinctrl_onewire_tm_default: onewire_tm_default {
+						pinmux = <PIN_PB31__GPIO>;
+						bias-pull-up;
+					};
 				};
 			};
 		};
diff --git a/arch/arm/dts/at91-sama5d2_xplained.dts b/arch/arm/dts/at91-sama5d2_xplained.dts
index 01326a1..33064b3 100644
--- a/arch/arm/dts/at91-sama5d2_xplained.dts
+++ b/arch/arm/dts/at91-sama5d2_xplained.dts
@@ -11,6 +11,18 @@
 		stdout-path = &uart1;
 	};
 
+	onewire_tm: onewire {
+		gpios = <&pioA PIN_PB0 0>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire_tm_default>;
+		status = "okay";
+
+		w1_eeprom: w1_eeprom@0 {
+			compatible = "maxim,ds24b33";
+			status = "okay";
+		};
+	};
+
 	ahb {
 		usb1: ohci@00400000 {
 			num-ports = <3>;
@@ -270,6 +282,11 @@
 						pinmux = <PIN_PA31__GPIO>;
 						bias-disable;
 					};
+
+					pinctrl_onewire_tm_default: onewire_tm_default {
+						pinmux = <PIN_PB0__GPIO>;
+						bias-pull-up;
+					};
 				};
 			};
 		};
diff --git a/arch/arm/dts/at91-sama5d3_xplained.dts b/arch/arm/dts/at91-sama5d3_xplained.dts
index 6959710..20fba5f 100644
--- a/arch/arm/dts/at91-sama5d3_xplained.dts
+++ b/arch/arm/dts/at91-sama5d3_xplained.dts
@@ -36,6 +36,18 @@
 		};
 	};
 
+	onewire_tm: onewire {
+		gpios = <&pioE 23 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire_tm_default>;
+		status = "okay";
+
+		w1_eeprom: w1_eeprom@0 {
+			compatible = "maxim,ds24b33";
+			status = "okay";
+		};
+	};
+
 	ahb {
 		apb {
 			mmc0: mmc@f0000000 {
@@ -243,6 +255,11 @@
 						atmel,pins =
 							<AT91_PIOE 9 AT91_PERIPH_GPIO AT91_PINCTRL_DEGLITCH>;	/* PE9, conflicts with A9 */
 					};
+
+					pinctrl_onewire_tm_default: onewire_tm_default {
+						atmel,pins =
+							<AT91_PIOE 23 AT91_PERIPH_GPIO AT91_PINCTRL_NONE>;
+					};
 				};
 			};
 		};
diff --git a/arch/arm/dts/at91-sama5d4_xplained.dts b/arch/arm/dts/at91-sama5d4_xplained.dts
index ea35dc2..58a0e60 100644
--- a/arch/arm/dts/at91-sama5d4_xplained.dts
+++ b/arch/arm/dts/at91-sama5d4_xplained.dts
@@ -58,6 +58,18 @@
 		stdout-path = &usart3;
 	};
 
+	onewire_tm: onewire {
+		gpios = <&pioE 15 GPIO_ACTIVE_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire_tm_default>;
+		status = "okay";
+
+		w1_eeprom: w1_eeprom@0 {
+			compatible = "maxim,ds24b33";
+			status = "okay";
+		};
+	};
+
 	memory {
 		reg = <0x20000000 0x20000000>;
 	};
@@ -199,6 +211,10 @@
 						atmel,pins =
 							<AT91_PIOE 1 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP_DEGLITCH>;
 					};
+					pinctrl_onewire_tm_default: onewire_tm_default {
+						atmel,pins =
+							<AT91_PIOE 15 AT91_PERIPH_GPIO AT91_PINCTRL_PULL_UP>;
+					};
 				};
 			};
 		};
diff --git a/arch/arm/dts/omap3-beagle-u-boot.dtsi b/arch/arm/dts/omap3-beagle-u-boot.dtsi
index 094f955..41beaf0 100644
--- a/arch/arm/dts/omap3-beagle-u-boot.dtsi
+++ b/arch/arm/dts/omap3-beagle-u-boot.dtsi
@@ -11,10 +11,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi b/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi
index 094f955..41beaf0 100644
--- a/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi
+++ b/arch/arm/dts/omap3-beagle-xm-ab-u-boot.dtsi
@@ -11,10 +11,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi b/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi
index 094f955..41beaf0 100644
--- a/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi
+++ b/arch/arm/dts/omap3-beagle-xm-u-boot.dtsi
@@ -11,10 +11,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi b/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi
index b09ce0e..de41131 100644
--- a/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi
+++ b/arch/arm/dts/omap3-evm-37xx-u-boot.dtsi
@@ -11,10 +11,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/omap3-evm-u-boot.dtsi b/arch/arm/dts/omap3-evm-u-boot.dtsi
index b09ce0e..de41131 100644
--- a/arch/arm/dts/omap3-evm-u-boot.dtsi
+++ b/arch/arm/dts/omap3-evm-u-boot.dtsi
@@ -11,10 +11,6 @@
 	};
 };
 
-&mmc1 {
-	cd-inverted;
-};
-
 &uart1 {
 	reg-shift = <2>;
 };
diff --git a/arch/arm/dts/sama5d2.dtsi b/arch/arm/dts/sama5d2.dtsi
index 6645a55..830251a 100644
--- a/arch/arm/dts/sama5d2.dtsi
+++ b/arch/arm/dts/sama5d2.dtsi
@@ -769,4 +769,9 @@
 			};
 		};
 	};
+
+	onewire_tm: onewire {
+		compatible = "w1-gpio";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/dts/sama5d3.dtsi b/arch/arm/dts/sama5d3.dtsi
index ba707b0..7db66c5 100644
--- a/arch/arm/dts/sama5d3.dtsi
+++ b/arch/arm/dts/sama5d3.dtsi
@@ -1534,4 +1534,9 @@
 			};
 		};
 	};
+
+	onewire_tm: onewire {
+		compatible = "w1-gpio";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/dts/sama5d4.dtsi b/arch/arm/dts/sama5d4.dtsi
index 8072b8a..8875d7b 100644
--- a/arch/arm/dts/sama5d4.dtsi
+++ b/arch/arm/dts/sama5d4.dtsi
@@ -1913,4 +1913,9 @@
 			};
 		};
 	};
+
+	onewire_tm: onewire {
+		compatible = "w1-gpio";
+		status = "disabled";
+	};
 };
diff --git a/arch/arm/dts/stm32mp157-pinctrl.dtsi b/arch/arm/dts/stm32mp157-pinctrl.dtsi
index c69c397..85da592 100644
--- a/arch/arm/dts/stm32mp157-pinctrl.dtsi
+++ b/arch/arm/dts/stm32mp157-pinctrl.dtsi
@@ -321,6 +321,12 @@
 					bias-disable;
 				};
 			};
+
+			usbotg_hs_pins_a: usbotg_hs-0 {
+				pins {
+					pinmux = <STM32_PINMUX('A', 10, ANALOG)>; /* OTG_ID */
+				};
+			};
 		};
 
 		pinctrl_z: pin-controller-z@54004000 {
diff --git a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi
index 2f4de3a..30b1734 100644
--- a/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi
+++ b/arch/arm/dts/stm32mp157c-ev1-u-boot.dtsi
@@ -25,6 +25,10 @@
 	regulator-always-on;
 };
 
+&usbotg_hs {
+	g-tx-fifo-size = <576>;
+};
+
 /* SPL part **************************************/
 &qspi {
 	u-boot,dm-spl;
@@ -60,3 +64,4 @@
 &flash0 {
 	u-boot,dm-spl;
 };
+
diff --git a/arch/arm/dts/stm32mp157c-ev1.dts b/arch/arm/dts/stm32mp157c-ev1.dts
index d6934f7..902a42b 100644
--- a/arch/arm/dts/stm32mp157c-ev1.dts
+++ b/arch/arm/dts/stm32mp157c-ev1.dts
@@ -96,6 +96,21 @@
 	};
 };
 
+&usbh_ehci {
+	phys = <&usbphyc_port0>;
+	phy-names = "usb";
+	vbus-supply = <&vbus_sw>;
+	status = "okay";
+};
+
+&usbotg_hs {
+	pinctrl-names = "default";
+	pinctrl-0 = <&usbotg_hs_pins_a>;
+	phys = <&usbphyc_port1 0>;
+	phy-names = "usb2-phy";
+	status = "okay";
+};
+
 &usbphyc {
 	status = "okay";
 };
diff --git a/arch/arm/dts/stm32mp157c.dtsi b/arch/arm/dts/stm32mp157c.dtsi
index cdf2946..33c5981 100644
--- a/arch/arm/dts/stm32mp157c.dtsi
+++ b/arch/arm/dts/stm32mp157c.dtsi
@@ -106,6 +106,26 @@
 		};
 	};
 
+	pm_domain {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "st,stm32mp157c-pd";
+
+		pd_core_ret: core-ret-power-domain@1 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+			#power-domain-cells = <0>;
+			label = "CORE-RETENTION";
+
+			pd_core: core-power-domain@2 {
+				reg = <2>;
+				#power-domain-cells = <0>;
+				label = "CORE";
+			};
+		};
+	};
+
 	soc {
 		compatible = "simple-bus";
 		#address-cells = <1>;
@@ -654,6 +674,22 @@
 			status = "disabled";
 		};
 
+		usbotg_hs: usb-otg@49000000 {
+			compatible = "st,stm32mp1-hsotg", "snps,dwc2";
+			reg = <0x49000000 0x10000>;
+			clocks = <&rcc USBO_K>;
+			clock-names = "otg";
+			resets = <&rcc USBO_R>;
+			reset-names = "dwc2";
+			interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+			g-rx-fifo-size = <256>;
+			g-np-tx-fifo-size = <32>;
+			g-tx-fifo-size = <128 128 64 64 64 64 32 32>;
+			dr_mode = "otg";
+			power-domains = <&pd_core>;
+			status = "disabled";
+		};
+
 		rcc: rcc@50000000 {
 			compatible = "st,stm32mp1-rcc", "syscon";
 			reg = <0x50000000 0x1000>;
diff --git a/arch/arm/include/asm/arch-omap3/mmc_host_def.h b/arch/arm/include/asm/arch-omap3/mmc_host_def.h
index 9f2896c..39a7cba 100644
--- a/arch/arm/include/asm/arch-omap3/mmc_host_def.h
+++ b/arch/arm/include/asm/arch-omap3/mmc_host_def.h
@@ -51,6 +51,7 @@
 #define PBIASLITEPWRDNZ0		(1 << 1)
 #define PBIASSPEEDCTRL0			(1 << 2)
 #define PBIASLITEPWRDNZ1		(1 << 9)
+#define PBIASLITEVMODE1			(1 << 8)
 #define PBIASLITEVMODE0			(1 << 0)
 
 #define CTLPROGIO1SPEEDCTRL		(1 << 20)
diff --git a/arch/arm/include/asm/arch-spear/spr_misc.h b/arch/arm/include/asm/arch-spear/spr_misc.h
index 65063fc..0171119 100644
--- a/arch/arm/include/asm/arch-spear/spr_misc.h
+++ b/arch/arm/include/asm/arch-spear/spr_misc.h
@@ -146,11 +146,13 @@
 #define MISC_SMIENB			0x00200000
 #define MISC_GPIO3ENB			0x00040000
 #define MISC_GPT3ENB			0x00010000
+#define MISC_SSP3ENB			0x00004000
 #define MISC_GPIO4ENB			0x00002000
 #define MISC_GPT2ENB			0x00000800
 #define MISC_FSMCENB			0x00000200
 #define MISC_I2CENB			0x00000080
-#define MISC_SSP2ENB			0x00000070
+#define MISC_SSP2ENB			0x00000040
+#define MISC_SSP1ENB			0x00000020
 #define MISC_UART0ENB			0x00000008
 
 /*   PERIPH_CLK_CFG   */
diff --git a/arch/arm/include/asm/arch-zynqmp/sys_proto.h b/arch/arm/include/asm/arch-zynqmp/sys_proto.h
index 773b930..9fa44d0 100644
--- a/arch/arm/include/asm/arch-zynqmp/sys_proto.h
+++ b/arch/arm/include/asm/arch-zynqmp/sys_proto.h
@@ -21,6 +21,21 @@
 
 #define ZYNQMP_FPGA_AUTH_DDR	1
 
+#define ZYNQMP_SIP_SVC_GET_API_VERSION		0xC2000001
+
+#define ZYNQMP_PM_VERSION_MAJOR		1
+#define ZYNQMP_PM_VERSION_MINOR		0
+#define ZYNQMP_PM_VERSION_MAJOR_SHIFT	16
+#define ZYNQMP_PM_VERSION_MINOR_MASK	0xFFFF
+
+#define ZYNQMP_PM_VERSION	\
+	((ZYNQMP_PM_VERSION_MAJOR << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | \
+				 ZYNQMP_PM_VERSION_MINOR)
+
+#define ZYNQMP_PM_VERSION_INVALID	~0
+
+#define PMUFW_V1_0	((1 << ZYNQMP_PM_VERSION_MAJOR_SHIFT) | 0)
+
 enum {
 	IDCODE,
 	VERSION,
@@ -44,7 +59,7 @@
 
 void handoff_setup(void);
 
-void zynqmp_pmufw_version(void);
+unsigned int zynqmp_pmufw_version(void);
 int zynqmp_mmio_write(const u32 address, const u32 mask, const u32 value);
 int zynqmp_mmio_read(const u32 address, u32 *value);
 int invoke_smc(u32 pm_api_id, u32 arg0, u32 arg1, u32 arg2, u32 arg3,
diff --git a/arch/arm/include/asm/atomic.h b/arch/arm/include/asm/atomic.h
index 171f4d9..5822b0a 100644
--- a/arch/arm/include/asm/atomic.h
+++ b/arch/arm/include/asm/atomic.h
@@ -20,152 +20,8 @@
 #error SMP not supported
 #endif
 
-typedef struct { volatile int counter; } atomic_t;
-#if BITS_PER_LONG == 32
-typedef struct { volatile long long counter; } atomic64_t;
-#else /* BIT_PER_LONG == 32 */
-typedef struct { volatile long counter; } atomic64_t;
-#endif
-
-#define ATOMIC_INIT(i)	{ (i) }
-
-#ifdef __KERNEL__
 #include <asm/proc-armv/system.h>
-
-#define atomic_read(v)	((v)->counter)
-#define atomic_set(v, i)	(((v)->counter) = (i))
-#define atomic64_read(v)	atomic_read(v)
-#define atomic64_set(v, i)	atomic_set(v, i)
-
-static inline void atomic_add(int i, volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter += i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_sub(int i, volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter -= i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_inc(volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter += 1;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_dec(volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter -= 1;
-	local_irq_restore(flags);
-}
-
-static inline int atomic_dec_and_test(volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-	int val;
-
-	local_irq_save(flags);
-	val = v->counter;
-	v->counter = val -= 1;
-	local_irq_restore(flags);
-
-	return val == 0;
-}
-
-static inline int atomic_add_negative(int i, volatile atomic_t *v)
-{
-	unsigned long flags = 0;
-	int val;
-
-	local_irq_save(flags);
-	val = v->counter;
-	v->counter = val += i;
-	local_irq_restore(flags);
-
-	return val < 0;
-}
-
-static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	*addr &= ~mask;
-	local_irq_restore(flags);
-}
-
-#if BITS_PER_LONG == 32
-
-static inline void atomic64_add(long long i, volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter += i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic64_sub(long long i, volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter -= i;
-	local_irq_restore(flags);
-}
-
-#else /* BIT_PER_LONG == 32 */
-
-static inline void atomic64_add(long i, volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter += i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic64_sub(long i, volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter -= i;
-	local_irq_restore(flags);
-}
-#endif
-
-static inline void atomic64_inc(volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter += 1;
-	local_irq_restore(flags);
-}
-
-static inline void atomic64_dec(volatile atomic64_t *v)
-{
-	unsigned long flags = 0;
-
-	local_irq_save(flags);
-	v->counter -= 1;
-	local_irq_restore(flags);
-}
+#include <asm-generic/atomic.h>
 
 /* Atomic operations are already serializing on ARM */
 #define smp_mb__before_atomic_dec()	barrier()
@@ -174,4 +30,3 @@
 #define smp_mb__after_atomic_inc()	barrier()
 
 #endif
-#endif
diff --git a/arch/arm/include/asm/omap_mmc.h b/arch/arm/include/asm/omap_mmc.h
index 42ce8dc..6d31cc4 100644
--- a/arch/arm/include/asm/omap_mmc.h
+++ b/arch/arm/include/asm/omap_mmc.h
@@ -68,7 +68,6 @@
 	struct mmc_config cfg;
 	struct hsmmc *base_addr;
 	struct mmc *mmc;
-	bool cd_inverted;
 	u32 controller_flags;
 	const char *hw_rev;
 };
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 69856c8..a6329dc 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -151,6 +151,7 @@
 	bool "SAMA5D2 PTC EK board"
 	select BOARD_EARLY_INIT_F
 	select SAMA5D2
+	select BOARD_LATE_INIT
 
 config TARGET_SAMA5D2_XPLAINED
 	bool "SAMA5D2 Xplained board"
@@ -177,6 +178,7 @@
 	select BOARD_EARLY_INIT_F
 	select SAMA5D3
 	select SUPPORT_SPL
+	select BOARD_LATE_INIT
 
 config TARGET_SAMA5D3XEK
 	bool "SAMA5D3X-EK board"
diff --git a/arch/arm/mach-davinci/da850_lowlevel.c b/arch/arm/mach-davinci/da850_lowlevel.c
index 95dc93a..822e0dc 100644
--- a/arch/arm/mach-davinci/da850_lowlevel.c
+++ b/arch/arm/mach-davinci/da850_lowlevel.c
@@ -288,10 +288,10 @@
 	/* GPIO setup */
 	board_gpio_init();
 
-
+#if !CONFIG_IS_ENABLED(DM_SERIAL)
 	NS16550_init((NS16550_t)(CONFIG_SYS_NS16550_COM1),
 			CONFIG_SYS_NS16550_CLK / 16 / CONFIG_BAUDRATE);
-
+#endif
 	/*
 	 * Fix Power and Emulation Management Register
 	 * see sprufw3a.pdf page 37 Table 24
diff --git a/arch/arm/mach-tegra/board2.c b/arch/arm/mach-tegra/board2.c
index 421a71b..12257a4 100644
--- a/arch/arm/mach-tegra/board2.c
+++ b/arch/arm/mach-tegra/board2.c
@@ -6,6 +6,7 @@
 
 #include <common.h>
 #include <dm.h>
+#include <efi_loader.h>
 #include <errno.h>
 #include <ns16550.h>
 #include <usb.h>
@@ -210,6 +211,19 @@
 
 int board_late_init(void)
 {
+#if CONFIG_IS_ENABLED(EFI_LOADER)
+	if (gd->bd->bi_dram[1].start) {
+		/*
+		 * Only bank 0 is below board_get_usable_ram_top(), so all of
+		 * bank 1 is not mapped by the U-Boot MMU configuration, and so
+		 * we must prevent EFI from using it.
+		 */
+		efi_add_memory_map(gd->bd->bi_dram[1].start,
+				   gd->bd->bi_dram[1].size >> EFI_PAGE_SHIFT,
+				   EFI_BOOT_SERVICES_DATA, false);
+	}
+#endif
+
 #if defined(CONFIG_TEGRA_SUPPORT_NON_SECURE)
 	if (tegra_cpu_is_non_secure()) {
 		printf("CPU is in NS mode\n");
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 6e5e0ff..071dea0 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -28,6 +28,7 @@
 	select DM_SERIAL
 	select DYNAMIC_IO_PORT_BASE
 	select MIPS_CM
+	select MIPS_INSERT_BOOT_CONFIG
 	select MIPS_L1_CACHE_SHIFT_6
 	select MIPS_L2_CACHE
 	select OF_CONTROL
@@ -68,6 +69,22 @@
 	select SYSRESET
 	imply CMD_DM
 
+config ARCH_MT7620
+	bool "Support MT7620/7688 SoCs"
+	imply CMD_DM
+	select DISPLAY_CPUINFO
+	select DM
+	select DM_SERIAL
+	imply DM_SPI
+	imply DM_SPI_FLASH
+	select MIPS_TUNE_24KC
+	select OF_CONTROL
+	select ROM_EXCEPTION_VECTORS
+	select SUPPORTS_CPU_MIPS32_R1
+	select SUPPORTS_CPU_MIPS32_R2
+	select SUPPORTS_LITTLE_ENDIAN
+	select SYSRESET
+
 config MACH_PIC32
 	bool "Support Microchip PIC32"
 	select DM
@@ -120,6 +137,7 @@
 source "arch/mips/mach-ath79/Kconfig"
 source "arch/mips/mach-bmips/Kconfig"
 source "arch/mips/mach-pic32/Kconfig"
+source "arch/mips/mach-mt7620/Kconfig"
 
 if MIPS
 
@@ -218,6 +236,18 @@
 	  the GCRs occupy a region of the physical address space which is
 	  otherwise unused, or at minimum that software doesn't need to access.
 
+config MIPS_CACHE_INDEX_BASE
+	hex "Index base address for cache initialisation"
+	default 0x80000000 if CPU_MIPS32
+	default 0xffffffff80000000 if CPU_MIPS64
+	help
+	  This is the base address for a memory block, which is used for
+	  initialising the cache lines. This is also the base address of a memory
+	  block which is used for loading and filling cache lines when
+	  SYS_MIPS_CACHE_INIT_RAM_LOAD is selected.
+	  Normally this is CKSEG0. If the MIPS system needs to move this block
+	  to some SRAM or ScratchPad RAM, adapt this option accordingly.
+
 endmenu
 
 menu "OS boot interface"
@@ -390,6 +420,28 @@
 	  wish U-Boot to configure it or make use of it to retrieve system
 	  information such as cache configuration.
 
+config MIPS_INSERT_BOOT_CONFIG
+	bool
+	default n
+	help
+	  Enable this to insert some board-specific boot configuration in
+	  the U-Boot binary at offset 0x10.
+
+config MIPS_BOOT_CONFIG_WORD0
+	hex
+	depends on MIPS_INSERT_BOOT_CONFIG
+	default 0x420 if TARGET_MALTA
+	default 0x0
+	help
+	  Value which is inserted as boot config word 0.
+
+config MIPS_BOOT_CONFIG_WORD1
+	hex
+	depends on MIPS_INSERT_BOOT_CONFIG
+	default 0x0
+	help
+	  Value which is inserted as boot config word 1.
+
 endif
 
 endmenu
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
index a36f5f1..802244a 100644
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -14,6 +14,7 @@
 machine-$(CONFIG_ARCH_ATH79) += ath79
 machine-$(CONFIG_ARCH_BMIPS) += bmips
 machine-$(CONFIG_MACH_PIC32) += pic32
+machine-$(CONFIG_ARCH_MT7620) += mt7620
 
 machdirs := $(patsubst %,arch/mips/mach-%/,$(machine-y))
 libs-y += $(machdirs)
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index 6ca0916..1d21b23 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -84,25 +84,14 @@
 	b	reset
 	 mtc0	zero, CP0_COUNT	# clear cp0 count for most accurate boot timing
 
-#if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG)
+#if defined(CONFIG_MIPS_INSERT_BOOT_CONFIG)
 	/*
-	 * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to
-	 * access external NOR flashes. If the board boots from NOR flash the
-	 * internal BootROM does a blind read at address 0xB0000010 to read the
-	 * initial configuration for that EBU in order to access the flash
-	 * device with correct parameters. This config option is board-specific.
+	 * Store some board-specific boot configuration. This is used by some
+	 * MIPS systems like Malta.
 	 */
 	.org 0x10
-	.word CONFIG_SYS_XWAY_EBU_BOOTCFG
-	.word 0x0
-#endif
-#if defined(CONFIG_MALTA)
-	/*
-	 * Linux expects the Board ID here.
-	 */
-	.org 0x10
-	.word 0x00000420	# 0x420 (Malta Board with CoreLV)
-	.word 0x00000000
+	.word CONFIG_MIPS_BOOT_CONFIG_WORD0
+	.word CONFIG_MIPS_BOOT_CONFIG_WORD1
 #endif
 
 #if defined(CONFIG_ROM_EXCEPTION_VECTORS)
diff --git a/arch/mips/dts/brcm,bcm6838.dtsi b/arch/mips/dts/brcm,bcm6838.dtsi
index d365d0f..1018f9e 100644
--- a/arch/mips/dts/brcm,bcm6838.dtsi
+++ b/arch/mips/dts/brcm,bcm6838.dtsi
@@ -55,6 +55,18 @@
 			u-boot,dm-pre-reloc;
 		};
 
+		gpio_test_port: syscon@14e00294 {
+			compatible = "syscon";
+			reg = <0x14e00294 0x1c>;
+		};
+
+		pinctrl: pinctrl {
+			compatible = "brcm,bcm6838-pinctrl";
+			regmap = <&gpio_test_port>;
+			brcm,pins-count = <74>;
+			brcm,functions-count = <8>;
+		};
+
 		uart0: serial@14e00500 {
 			compatible = "brcm,bcm6345-uart";
 			reg = <0x14e00500 0x18>;
diff --git a/arch/mips/dts/gardena-smart-gateway-mt7688.dts b/arch/mips/dts/gardena-smart-gateway-mt7688.dts
new file mode 100644
index 0000000..ee99c3d
--- /dev/null
+++ b/arch/mips/dts/gardena-smart-gateway-mt7688.dts
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+/dts-v1/;
+
+#include "mt7628a.dtsi"
+
+/ {
+	compatible = "gardena,smart-gateway-mt7688", "ralink,mt7628a-soc";
+	model = "Gardena smart-Gateway-MT7688";
+
+	aliases {
+		serial0 = &uart0;
+		spi0 = &spi0;
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x08000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,57600";
+		stdout-path = &uart0;
+	};
+};
+
+&uart0 {
+	status = "okay";
+	clock-frequency = <40000000>;
+};
+
+&spi0 {
+	status = "okay";
+	num-cs = <2>;
+
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash", "jedec,spi-nor";
+		spi-max-frequency = <40000000>;
+		reg = <0>;
+	};
+
+	spi-nand@1 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-nand";
+		spi-max-frequency = <40000000>;
+		reg = <1>;
+	};
+};
diff --git a/arch/mips/dts/linkit-smart-7688.dts b/arch/mips/dts/linkit-smart-7688.dts
new file mode 100644
index 0000000..df4bf90
--- /dev/null
+++ b/arch/mips/dts/linkit-smart-7688.dts
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+/dts-v1/;
+
+#include "mt7628a.dtsi"
+
+/ {
+	compatible = "seeed,linkit-smart-7688", "ralink,mt7628a-soc";
+	model = "LinkIt-Smart-7688";
+
+	aliases {
+		serial0 = &uart2;
+		spi0 = &spi0;
+	};
+
+	memory@0 {
+		device_type = "memory";
+		reg = <0x0 0x08000000>;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,57600";
+		stdout-path = &uart2;
+	};
+};
+
+&uart2 {
+	status = "okay";
+	clock-frequency = <40000000>;
+};
+
+&spi0 {
+	status = "okay";
+	num-cs = <2>;
+
+	spi-flash@0 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		compatible = "spi-flash", "jedec,spi-nor";
+		spi-max-frequency = <25000000>;
+		reg = <0>;
+	};
+};
diff --git a/arch/mips/dts/mt7628a.dtsi b/arch/mips/dts/mt7628a.dtsi
new file mode 100644
index 0000000..c14259b
--- /dev/null
+++ b/arch/mips/dts/mt7628a.dtsi
@@ -0,0 +1,144 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/ {
+	#address-cells = <1>;
+	#size-cells = <1>;
+	compatible = "ralink,mt7628a-soc";
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		cpu@0 {
+			compatible = "mti,mips24KEc";
+			device_type = "cpu";
+			reg = <0>;
+		};
+	};
+
+	resetc: reset-controller {
+		compatible = "ralink,rt2880-reset";
+		#reset-cells = <1>;
+	};
+
+	cpuintc: interrupt-controller {
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+		interrupt-controller;
+		compatible = "mti,cpu-interrupt-controller";
+	};
+
+	palmbus@10000000 {
+		compatible = "palmbus", "simple-bus";
+		reg = <0x10000000 0x200000>;
+		ranges = <0x0 0x10000000 0x1FFFFF>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		sysc: system-controller@0 {
+			compatible = "ralink,mt7620a-sysc", "syscon";
+			reg = <0x0 0x100>;
+		};
+
+		syscon-reboot {
+			compatible = "syscon-reboot";
+			regmap = <&sysc>;
+			offset = <0x34>;
+			mask = <0x1>;
+		};
+
+		intc: interrupt-controller@200 {
+			compatible = "ralink,rt2880-intc";
+			reg = <0x200 0x100>;
+
+			interrupt-controller;
+			#interrupt-cells = <1>;
+
+			resets = <&resetc 9>;
+			reset-names = "intc";
+
+			interrupt-parent = <&cpuintc>;
+			interrupts = <2>;
+
+			ralink,intc-registers = <0x9c 0xa0
+						 0x6c 0xa4
+						 0x80 0x78>;
+		};
+
+		memory-controller@300 {
+			compatible = "ralink,mt7620a-memc";
+			reg = <0x300 0x100>;
+		};
+
+		spi0: spi@b00 {
+			compatible = "ralink,mt7621-spi";
+			reg = <0xb00 0x40>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			clock-frequency = <200000000>;
+		};
+
+		uart0: uartlite@c00 {
+			compatible = "ns16550a";
+			reg = <0xc00 0x100>;
+
+			resets = <&resetc 12>;
+			reset-names = "uart0";
+
+			interrupt-parent = <&intc>;
+			interrupts = <20>;
+
+			reg-shift = <2>;
+		};
+
+		uart1: uart1@d00 {
+			compatible = "ns16550a";
+			reg = <0xd00 0x100>;
+
+			resets = <&resetc 19>;
+			reset-names = "uart1";
+
+			interrupt-parent = <&intc>;
+			interrupts = <21>;
+
+			reg-shift = <2>;
+		};
+
+		uart2: uart2@e00 {
+			compatible = "ns16550a";
+			reg = <0xe00 0x100>;
+
+			resets = <&resetc 20>;
+			reset-names = "uart2";
+
+			interrupt-parent = <&intc>;
+			interrupts = <22>;
+
+			reg-shift = <2>;
+		};
+	};
+
+	usb_phy: usb-phy@10120000 {
+		compatible = "mediatek,mt7628-usbphy";
+		reg = <0x10120000 0x1000>;
+
+		#phy-cells = <0>;
+
+		ralink,sysctl = <&sysc>;
+		resets = <&resetc 22 &resetc 25>;
+		reset-names = "host", "device";
+	};
+
+	ehci@101c0000 {
+		compatible = "generic-ehci";
+		reg = <0x101c0000 0x1000>;
+
+		phys = <&usb_phy>;
+		phy-names = "usb";
+
+		interrupt-parent = <&intc>;
+		interrupts = <18>;
+	};
+};
diff --git a/arch/mips/include/asm/atomic.h b/arch/mips/include/asm/atomic.h
new file mode 100644
index 0000000..c4f08b7
--- /dev/null
+++ b/arch/mips/include/asm/atomic.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2016 Cadence Design Systems Inc.
+ */
+
+#ifndef _MIPS_ATOMIC_H
+#define _MIPS_ATOMIC_H
+
+#include <asm/system.h>
+#include <asm-generic/atomic.h>
+
+#endif
diff --git a/arch/mips/lib/cache.c b/arch/mips/lib/cache.c
index 1d14fc4..d56fd1e 100644
--- a/arch/mips/lib/cache.c
+++ b/arch/mips/lib/cache.c
@@ -175,3 +175,23 @@
 	/* ensure cache ops complete before any further memory accesses */
 	sync();
 }
+
+int dcache_status(void)
+{
+	unsigned int cca = read_c0_config() & CONF_CM_CMASK;
+	return cca != CONF_CM_UNCACHED;
+}
+
+void dcache_enable(void)
+{
+	puts("Not supported!\n");
+}
+
+void dcache_disable(void)
+{
+	/* change CCA to uncached */
+	change_c0_config(CONF_CM_CMASK, CONF_CM_UNCACHED);
+
+	/* ensure the pipeline doesn't contain now-invalid instructions */
+	instruction_hazard_barrier();
+}
diff --git a/arch/mips/lib/cache_init.S b/arch/mips/lib/cache_init.S
index b209f23..cfad1d9 100644
--- a/arch/mips/lib/cache_init.S
+++ b/arch/mips/lib/cache_init.S
@@ -14,12 +14,6 @@
 #include <asm/cacheops.h>
 #include <asm/cm.h>
 
-#ifndef CONFIG_SYS_MIPS_CACHE_MODE
-#define CONFIG_SYS_MIPS_CACHE_MODE CONF_CM_CACHABLE_NONCOHERENT
-#endif
-
-#define INDEX_BASE	CKSEG0
-
 	.macro	f_fill64 dst, offset, val
 	LONG_S	\val, (\offset +  0 * LONGSIZE)(\dst)
 	LONG_S	\val, (\offset +  1 * LONGSIZE)(\dst)
@@ -84,6 +78,7 @@
 10:
 	.set	pop
 	.endm
+
 /*
  * mips_cache_reset - low level initialisation of the primary caches
  *
@@ -255,7 +250,7 @@
 	/*
 	 * Now clear that much memory starting from zero.
 	 */
-	PTR_LI		a0, CKSEG1
+	PTR_LI		a0, CKSEG1ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	PTR_ADDU	a1, a0, v0
 2:	PTR_ADDIU	a0, 64
 	f_fill64	a0, -64, zero
@@ -271,7 +266,7 @@
 	bnez		R_L2_BYPASSED, l1_init
 
 l2_init:
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	PTR_ADDU	t1, t0, R_L2_SIZE
 1:	cache		INDEX_STORE_TAG_SD, 0(t0)
 	PTR_ADDU	t0, t0, R_L2_LINE
@@ -307,48 +302,50 @@
 	 * Initialize the I-cache first,
 	 */
 	blez		R_IC_SIZE, 1f
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	PTR_ADDU	t1, t0, R_IC_SIZE
 	/* clear tag to invalidate */
 	cache_loop	t0, t1, R_IC_LINE, INDEX_STORE_TAG_I
 #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
 	/* fill once, so data field parity is correct */
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	cache_loop	t0, t1, R_IC_LINE, FILL
 	/* invalidate again - prudent but not strictly neccessary */
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	cache_loop	t0, t1, R_IC_LINE, INDEX_STORE_TAG_I
 #endif
-
-	/* Enable use of the I-cache by setting Config.K0 */
 	sync
-	mfc0		t0, CP0_CONFIG
-	li		t1, CONFIG_SYS_MIPS_CACHE_MODE
-#if __mips_isa_rev >= 2
-	ins		t0, t1, 0, 3
-#else
-	ori		t0, t0, CONF_CM_CMASK
-	xori		t0, t0, CONF_CM_CMASK
+
+	/*
+	 * Enable use of the I-cache by setting Config.K0. The code for this
+	 * must be executed from KSEG1. Jump from KSEG0 to KSEG1 to do this.
+	 * Jump back to KSEG0 after caches are enabled and insert an
+	 * instruction hazard barrier.
+	 */
+	PTR_LA		t0, change_k0_cca
+	li		t1, CPHYSADDR(~0)
+	and		t0, t0, t1
+	PTR_LI		t1, CKSEG1
 	or		t0, t0, t1
-#endif
-	mtc0		t0, CP0_CONFIG
+	li		a0, CONF_CM_CACHABLE_NONCOHERENT
+	jalr.hb		t0
 
 	/*
 	 * then initialize D-cache.
 	 */
 1:	blez		R_DC_SIZE, 3f
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	PTR_ADDU	t1, t0, R_DC_SIZE
 	/* clear all tags */
 	cache_loop	t0, t1, R_DC_LINE, INDEX_STORE_TAG_D
 #ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
 	/* load from each line (in cached space) */
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 2:	LONG_L		zero, 0(t0)
 	PTR_ADDU	t0, R_DC_LINE
 	bne		t0, t1, 2b
 	/* clear all tags */
-	PTR_LI		t0, INDEX_BASE
+	PTR_LI		t0, CKSEG0ADDR(CONFIG_MIPS_CACHE_INDEX_BASE)
 	cache_loop	t0, t1, R_DC_LINE, INDEX_STORE_TAG_D
 #endif
 3:
@@ -391,16 +388,9 @@
 	beqz		t0, 2f
 
 	/* Change Config.K0 to a coherent CCA */
-	mfc0		t0, CP0_CONFIG
-	li		t1, CONF_CM_CACHABLE_COW
-#if __mips_isa_rev >= 2
-	ins		t0, t1, 0, 3
-#else
-	ori		t0, t0, CONF_CM_CMASK
-	xori		t0, t0, CONF_CM_CMASK
-	or		t0, t0, t1
-#endif
-	mtc0		t0, CP0_CONFIG
+	PTR_LA		t0, change_k0_cca
+	li		a0, CONF_CM_CACHABLE_COW
+	jalr		t0
 
 	/*
 	 * Join the coherent domain such that the caches of this core are kept
@@ -421,51 +411,19 @@
 return:
 	/* Ensure all cache operations complete before returning */
 	sync
-	jr	ra
+	jr	R_RETURN
 	END(mips_cache_reset)
 
-/*
- * dcache_status - get cache status
- *
- * RETURNS: 0 - cache disabled; 1 - cache enabled
- *
- */
-LEAF(dcache_status)
-	mfc0	t0, CP0_CONFIG
-	li	t1, CONF_CM_UNCACHED
-	andi	t0, t0, CONF_CM_CMASK
-	move	v0, zero
-	beq	t0, t1, 2f
-	li	v0, 1
-2:	jr	ra
-	END(dcache_status)
-
-/*
- * dcache_disable - disable cache
- *
- * RETURNS: N/A
- *
- */
-LEAF(dcache_disable)
-	mfc0	t0, CP0_CONFIG
-	li	t1, -8
-	and	t0, t0, t1
-	ori	t0, t0, CONF_CM_UNCACHED
-	mtc0	t0, CP0_CONFIG
-	jr	ra
-	END(dcache_disable)
+LEAF(change_k0_cca)
+	mfc0		t0, CP0_CONFIG
+#if __mips_isa_rev >= 2
+	ins		t0, a0, 0, 3
+#else
+	xor		a0, a0, t0
+	andi		a0, a0, CONF_CM_CMASK
+	xor		a0, a0, t0
+#endif
+	mtc0		a0, CP0_CONFIG
 
-/*
- * dcache_enable - enable cache
- *
- * RETURNS: N/A
- *
- */
-LEAF(dcache_enable)
-	mfc0	t0, CP0_CONFIG
-	ori	t0, CONF_CM_CMASK
-	xori	t0, CONF_CM_CMASK
-	ori	t0, CONFIG_SYS_MIPS_CACHE_MODE
-	mtc0	t0, CP0_CONFIG
-	jr	ra
-	END(dcache_enable)
+	jr.hb		ra
+	END(change_k0_cca)
diff --git a/arch/mips/mach-mt7620/Kconfig b/arch/mips/mach-mt7620/Kconfig
new file mode 100644
index 0000000..13a7bd2
--- /dev/null
+++ b/arch/mips/mach-mt7620/Kconfig
@@ -0,0 +1,135 @@
+menu "MediaTek MIPS platforms"
+	depends on ARCH_MT7620
+
+config SYS_MALLOC_F_LEN
+	default 0x1000
+
+config SYS_SOC
+	default "mt7620" if SOC_MT7620
+
+choice
+	prompt "MediaTek MIPS SoC select"
+
+config SOC_MT7620
+	bool "MT7620/8"
+	select MIPS_L1_CACHE_SHIFT_5
+	help
+	  This supports MediaTek MIPS MT7620 family.
+
+endchoice
+
+choice
+	prompt "Board select"
+
+config BOARD_GARDENA_SMART_GATEWAY_MT7688
+	bool "Gardena Smart Gateway"
+	depends on SOC_MT7620
+	select SUPPORTS_BOOT_RAM
+	help
+	  Gardena Smart Gateway boards have a MT7688 SoC with 128 MiB of RAM
+	  and 8 MiB of flash (SPI NOR) and additional SPI NAND storage.
+
+config BOARD_LINKIT_SMART_7688
+	bool "LinkIt Smart 7688"
+	depends on SOC_MT7620
+	select SUPPORTS_BOOT_RAM
+	help
+	  Seeed LinkIt Smart 7688 boards have a MT7688 SoC with 128 MiB of RAM
+	  and 32 MiB of flash (SPI).
+	  Between its different peripherals there's an integrated switch with 4
+	  ethernet ports, 1 USB port, 1 UART, GPIO buttons and LEDs, and
+	  a MT7688 (PCIe).
+
+endchoice
+
+choice
+	prompt "Boot mode"
+
+config BOOT_RAM
+	bool "RAM boot"
+	depends on SUPPORTS_BOOT_RAM
+	help
+	  This builds an image that is linked to a RAM address. It can be used
+	  for booting from CFE via TFTP using an ELF image, but it can also be
+	  booted from RAM by other bootloaders using a BIN image.
+
+config BOOT_ROM
+	bool "ROM boot"
+	depends on SUPPORTS_BOOT_RAM
+	help
+	  This builds an image that is linked to a ROM address. It can be
+	  used as main bootloader image which is programmed onto the onboard
+	  flash storage (SPI NOR).
+
+endchoice
+
+choice
+	prompt "DDR2 size"
+
+config ONBOARD_DDR2_SIZE_256MBIT
+	bool "256MBit (32MByte) total size"
+	depends on BOOT_ROM
+	help
+	  Use 256MBit (32MByte) of DDR total size
+
+config ONBOARD_DDR2_SIZE_512MBIT
+	bool "512MBit (64MByte) total size"
+	depends on BOOT_ROM
+	help
+	  Use 512MBit (64MByte) of DDR total size
+
+config ONBOARD_DDR2_SIZE_1024MBIT
+	bool "1024MBit (128MByte) total size"
+	depends on BOOT_ROM
+	help
+	  Use 1024MBit (128MByte) of DDR total size
+
+config ONBOARD_DDR2_SIZE_2048MBIT
+	bool "2048MBit (256MByte) total size"
+	depends on BOOT_ROM
+	help
+	  Use 2048MBit (256MByte) of DDR total size
+
+endchoice
+
+choice
+	prompt "DDR2 chip width"
+
+config ONBOARD_DDR2_CHIP_WIDTH_8BIT
+	bool "8bit DDR chip width"
+	depends on BOOT_ROM
+	help
+	  Use DDR chips with 8bit width
+
+config ONBOARD_DDR2_CHIP_WIDTH_16BIT
+	bool "16bit DDR chip width"
+	depends on BOOT_ROM
+	help
+	  Use DDR chips with 16bit width
+
+endchoice
+
+choice
+	prompt "DDR2 bus width"
+
+config ONBOARD_DDR2_BUS_WIDTH_16BIT
+	bool "16bit DDR bus width"
+	depends on BOOT_ROM
+	help
+	  Use 16bit DDR bus width
+
+config ONBOARD_DDR2_BUS_WIDTH_32BIT
+	bool "32bit DDR bus width"
+	depends on BOOT_ROM
+	help
+	  Use 32bit DDR bus width
+
+endchoice
+
+config SUPPORTS_BOOT_RAM
+	bool
+
+source "board/gardena/smart-gateway-mt7688/Kconfig"
+source "board/seeed/linkit-smart-7688/Kconfig"
+
+endmenu
diff --git a/arch/mips/mach-mt7620/Makefile b/arch/mips/mach-mt7620/Makefile
new file mode 100644
index 0000000..1f3e65e
--- /dev/null
+++ b/arch/mips/mach-mt7620/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += cpu.o
+
+ifndef CONFIG_SKIP_LOWLEVEL_INIT
+obj-y += ddr_calibrate.o
+obj-y += lowlevel_init.o
+endif
diff --git a/arch/mips/mach-mt7620/cpu.c b/arch/mips/mach-mt7620/cpu.c
new file mode 100644
index 0000000..457f09f
--- /dev/null
+++ b/arch/mips/mach-mt7620/cpu.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <ram.h>
+#include <asm/io.h>
+#include <linux/io.h>
+#include <linux/sizes.h>
+#include "mt76xx.h"
+
+#define STR_LEN			6
+
+#ifdef CONFIG_BOOT_ROM
+int mach_cpu_init(void)
+{
+	ddr_calibrate();
+
+	return 0;
+}
+#endif
+
+int dram_init(void)
+{
+	gd->ram_size = get_ram_size((void *)CONFIG_SYS_SDRAM_BASE, SZ_256M);
+
+	return 0;
+}
+
+int print_cpuinfo(void)
+{
+	static const char * const boot_str[] = { "PLL (3-Byte SPI Addr)",
+						 "PLL (4-Byte SPI Addr)",
+						 "XTAL (3-Byte SPI Addr)",
+						 "XTAL (4-Byte SPI Addr)" };
+	const void *blob = gd->fdt_blob;
+	void __iomem *sysc_base;
+	char buf[STR_LEN + 1];
+	fdt_addr_t base;
+	fdt_size_t size;
+	char *str;
+	int node;
+	u32 val;
+
+	/* Get system controller base address */
+	node = fdt_node_offset_by_compatible(blob, -1, "ralink,mt7620a-sysc");
+	if (node < 0)
+		return -FDT_ERR_NOTFOUND;
+
+	base = fdtdec_get_addr_size_auto_noparent(blob, node, "reg",
+						  0, &size, true);
+	if (base == FDT_ADDR_T_NONE)
+		return -EINVAL;
+
+	sysc_base = ioremap_nocache(base, size);
+
+	str = (char *)sysc_base + MT76XX_CHIPID_OFFS;
+	snprintf(buf, STR_LEN + 1, "%s", str);
+	val = readl(sysc_base + MT76XX_CHIP_REV_ID_OFFS);
+	printf("CPU:   %-*s Rev %ld.%ld - ", STR_LEN, buf,
+	       (val & GENMASK(11, 8)) >> 8, val & GENMASK(3, 0));
+
+	val = (readl(sysc_base + MT76XX_SYSCFG0_OFFS) & GENMASK(3, 1)) >> 1;
+	printf("Boot from %s\n", boot_str[val]);
+
+	return 0;
+}
diff --git a/arch/mips/mach-mt7620/ddr_calibrate.c b/arch/mips/mach-mt7620/ddr_calibrate.c
new file mode 100644
index 0000000..75763c4
--- /dev/null
+++ b/arch/mips/mach-mt7620/ddr_calibrate.c
@@ -0,0 +1,308 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ *
+ * This code is mostly based on the code extracted from this MediaTek
+ * github repository:
+ *
+ * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
+ *
+ * I was not able to find a specific license or other developers
+ * copyrights here, so I can't add them here.
+ *
+ * Most functions in this file are copied from the MediaTek U-Boot
+ * repository. Without any documentation, it was impossible to really
+ * implement this differently. So its mostly a cleaned-up version of
+ * the original code, with only support for the MT7628 / MT7688 SoC.
+ */
+
+#include <common.h>
+#include <linux/io.h>
+#include <asm/cacheops.h>
+#include <asm/io.h>
+#include "mt76xx.h"
+
+#define NUM_OF_CACHELINE	128
+#define MIN_START		6
+#define MIN_FINE_START		0xf
+#define MAX_START		7
+#define MAX_FINE_START		0x0
+
+#define CPU_FRAC_DIV		1
+
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
+#define DRAM_BUTTOM 0x02000000
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
+#define DRAM_BUTTOM 0x04000000
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
+#define DRAM_BUTTOM 0x08000000
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
+#define DRAM_BUTTOM 0x10000000
+#endif
+
+static inline void cal_memcpy(void *src, void *dst, u32 size)
+{
+	u8 *psrc = (u8 *)src;
+	u8 *pdst = (u8 *)dst;
+	int i;
+
+	for (i = 0; i < size; i++, psrc++, pdst++)
+		*pdst = *psrc;
+}
+
+static inline void cal_memset(void *src, u8 pat, u32 size)
+{
+	u8 *psrc = (u8 *)src;
+	int i;
+
+	for (i = 0; i < size; i++, psrc++)
+		*psrc = pat;
+}
+
+#define pref_op(hint, addr)						\
+	__asm__ __volatile__(						\
+		".set	push\n"						\
+		".set	noreorder\n"					\
+		"pref	%0, %1\n"					\
+		".set	pop\n"						\
+		:							\
+		: "i" (hint), "R" (*(u8 *)(addr)))
+
+static inline void cal_patgen(u32 start_addr, u32 size, u32 bias)
+{
+	u32 *addr = (u32 *)start_addr;
+	int i;
+
+	for (i = 0; i < size; i++)
+		addr[i] = start_addr + i + bias;
+}
+
+static inline int test_loop(int k, int dqs, u32 test_dqs, u32 *coarse_dqs,
+			    u32 offs, u32 pat, u32 val)
+{
+	u32 nc_addr;
+	u32 *c_addr;
+	int i;
+
+	for (nc_addr = 0xa0000000;
+	     nc_addr < (0xa0000000 + DRAM_BUTTOM - NUM_OF_CACHELINE * 32);
+	     nc_addr += (DRAM_BUTTOM >> 6) + offs) {
+		writel(0x00007474, (void *)MT76XX_MEMCTRL_BASE + 0x64);
+		wmb();		/* Make sure store if finished */
+
+		c_addr = (u32 *)(nc_addr & 0xdfffffff);
+		cal_memset(((u8 *)c_addr), 0x1F, NUM_OF_CACHELINE * 32);
+		cal_patgen(nc_addr, NUM_OF_CACHELINE * 8, pat);
+
+		if (dqs > 0)
+			writel(0x00000074 |
+			       (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 12) |
+			       (((k == 0) ? val : test_dqs) << 8),
+			       (void *)MT76XX_MEMCTRL_BASE + 0x64);
+		else
+			writel(0x00007400 |
+			       (((k == 1) ? coarse_dqs[dqs] : test_dqs) << 4) |
+			       (((k == 0) ? val : test_dqs) << 0),
+			       (void *)MT76XX_MEMCTRL_BASE + 0x64);
+		wmb();		/* Make sure store if finished */
+
+		invalidate_dcache_range((u32)c_addr,
+					(u32)c_addr +
+					NUM_OF_CACHELINE * 32);
+		wmb();		/* Make sure store if finished */
+
+		for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
+			if (i % 8 == 0)
+				pref_op(0, &c_addr[i]);
+		}
+
+		for (i = 0; i < NUM_OF_CACHELINE * 8; i++) {
+			if (c_addr[i] != nc_addr + i + pat)
+				return -1;
+		}
+	}
+
+	return 0;
+}
+
+void ddr_calibrate(void)
+{
+	u32 min_coarse_dqs[2];
+	u32 max_coarse_dqs[2];
+	u32 min_fine_dqs[2];
+	u32 max_fine_dqs[2];
+	u32 coarse_dqs[2];
+	u32 fine_dqs[2];
+	int reg = 0, ddr_cfg2_reg;
+	int flag;
+	int i, k;
+	int dqs = 0;
+	u32 min_coarse_dqs_bnd, min_fine_dqs_bnd, coarse_dqs_dll, fine_dqs_dll;
+	u32 val;
+	u32 fdiv = 0, frac = 0;
+
+	/* Setup clock to run at full speed */
+	val = readl((void *)MT76XX_DYN_CFG0_REG);
+	fdiv = (u32)((val >> 8) & 0x0F);
+	if (CPU_FRAC_DIV < 1 || CPU_FRAC_DIV > 10)
+		frac = val & 0x0f;
+	else
+		frac = CPU_FRAC_DIV;
+
+	while (frac < fdiv) {
+		val = readl((void *)MT76XX_DYN_CFG0_REG);
+		fdiv = (val >> 8) & 0x0f;
+		fdiv--;
+		val &= ~(0x0f << 8);
+		val |= (fdiv << 8);
+		writel(val, (void *)MT76XX_DYN_CFG0_REG);
+		udelay(500);
+		val = readl((void *)MT76XX_DYN_CFG0_REG);
+		fdiv = (val >> 8) & 0x0f;
+	}
+
+	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
+	ddr_cfg2_reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x48);
+	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x48,
+		     (0x3 << 28) | (0x3 << 26));
+
+	min_coarse_dqs[0] = MIN_START;
+	min_coarse_dqs[1] = MIN_START;
+	min_fine_dqs[0] = MIN_FINE_START;
+	min_fine_dqs[1] = MIN_FINE_START;
+	max_coarse_dqs[0] = MAX_START;
+	max_coarse_dqs[1] = MAX_START;
+	max_fine_dqs[0] = MAX_FINE_START;
+	max_fine_dqs[1] = MAX_FINE_START;
+	dqs = 0;
+
+	/* Add by KP, DQS MIN boundary */
+	reg = readl((void *)MT76XX_MEMCTRL_BASE + 0x20);
+	coarse_dqs_dll = (reg & 0xf00) >> 8;
+	fine_dqs_dll = (reg & 0xf0) >> 4;
+	if (coarse_dqs_dll <= 8)
+		min_coarse_dqs_bnd = 8 - coarse_dqs_dll;
+	else
+		min_coarse_dqs_bnd = 0;
+
+	if (fine_dqs_dll <= 8)
+		min_fine_dqs_bnd = 8 - fine_dqs_dll;
+	else
+		min_fine_dqs_bnd = 0;
+	/* DQS MIN boundary */
+
+DQS_CAL:
+
+	for (k = 0; k < 2; k++) {
+		u32 test_dqs;
+
+		if (k == 0)
+			test_dqs = MAX_START;
+		else
+			test_dqs = MAX_FINE_START;
+
+		do {
+			flag = test_loop(k, dqs, test_dqs, max_coarse_dqs,
+					 0x400, 0x3, 0xf);
+			if (flag == -1)
+				break;
+
+			test_dqs++;
+		} while (test_dqs <= 0xf);
+
+		if (k == 0) {
+			max_coarse_dqs[dqs] = test_dqs;
+		} else {
+			test_dqs--;
+
+			if (test_dqs == MAX_FINE_START - 1) {
+				max_coarse_dqs[dqs]--;
+				max_fine_dqs[dqs] = 0xf;
+			} else {
+				max_fine_dqs[dqs] = test_dqs;
+			}
+		}
+	}
+
+	for (k = 0; k < 2; k++) {
+		u32 test_dqs;
+
+		if (k == 0)
+			test_dqs = MIN_START;
+		else
+			test_dqs = MIN_FINE_START;
+
+		do {
+			flag = test_loop(k, dqs, test_dqs, min_coarse_dqs,
+					 0x480, 0x1, 0x0);
+			if (k == 0) {
+				if (flag == -1 ||
+				    test_dqs == min_coarse_dqs_bnd)
+					break;
+
+				test_dqs--;
+
+				if (test_dqs < min_coarse_dqs_bnd)
+					break;
+			} else {
+				if (flag == -1) {
+					test_dqs++;
+					break;
+				} else if (test_dqs == min_fine_dqs_bnd) {
+					break;
+				}
+
+				test_dqs--;
+
+				if (test_dqs < min_fine_dqs_bnd)
+					break;
+			}
+		} while (test_dqs >= 0);
+
+		if (k == 0) {
+			min_coarse_dqs[dqs] = test_dqs;
+		} else {
+			if (test_dqs == MIN_FINE_START + 1) {
+				min_coarse_dqs[dqs]++;
+				min_fine_dqs[dqs] = 0x0;
+			} else {
+				min_fine_dqs[dqs] = test_dqs;
+			}
+		}
+	}
+
+	if (dqs == 0) {
+		dqs = 1;
+		goto DQS_CAL;
+	}
+
+	for (i = 0; i < 2; i++) {
+		u32 temp;
+
+		coarse_dqs[i] = (max_coarse_dqs[i] + min_coarse_dqs[i]) >> 1;
+		temp =
+		    (((max_coarse_dqs[i] + min_coarse_dqs[i]) % 2) * 4) +
+		    ((max_fine_dqs[i] + min_fine_dqs[i]) >> 1);
+		if (temp >= 0x10) {
+			coarse_dqs[i]++;
+			fine_dqs[i] = (temp - 0x10) + 0x8;
+		} else {
+			fine_dqs[i] = temp;
+		}
+	}
+	reg = (coarse_dqs[1] << 12) | (fine_dqs[1] << 8) |
+		(coarse_dqs[0] << 4) | fine_dqs[0];
+
+	clrbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
+	writel(reg, (void *)MT76XX_MEMCTRL_BASE + 0x64);
+	writel(ddr_cfg2_reg, (void *)MT76XX_MEMCTRL_BASE + 0x48);
+	setbits_le32((void *)MT76XX_MEMCTRL_BASE + 0x10, BIT(4));
+
+	for (i = 0; i < 2; i++)
+		debug("[%02X%02X%02X%02X]", min_coarse_dqs[i],
+		      min_fine_dqs[i], max_coarse_dqs[i], max_fine_dqs[i]);
+	debug("\nDDR Calibration DQS reg = %08X\n", reg);
+}
diff --git a/arch/mips/mach-mt7620/lowlevel_init.S b/arch/mips/mach-mt7620/lowlevel_init.S
new file mode 100644
index 0000000..1a50f160
--- /dev/null
+++ b/arch/mips/mach-mt7620/lowlevel_init.S
@@ -0,0 +1,322 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (c) 2018 Stefan Roese <sr@denx.de>
+ *
+ * This code is mostly based on the code extracted from this MediaTek
+ * github repository:
+ *
+ * https://github.com/MediaTek-Labs/linkit-smart-uboot.git
+ *
+ * I was not able to find a specific license or other developers
+ * copyrights here, so I can't add them here.
+ */
+
+#include <config.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/asm.h>
+#include "mt76xx.h"
+
+#ifndef BIT
+#define BIT(nr)			(1 << (nr))
+#endif
+
+#define DELAY_USEC(us)		((us) / 100)
+
+#define DDR_CFG1_CHIP_WIDTH_MASK (0x3 << 16)
+#define DDR_CFG1_BUS_WIDTH_MASK	(0x3 << 12)
+
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_256MBIT)
+#define DDR_CFG1_SIZE_VAL	0x222e2323
+#define DDR_CFG4_SIZE_VAL	7
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_512MBIT)
+#define DDR_CFG1_SIZE_VAL	0x22322323
+#define DDR_CFG4_SIZE_VAL	9
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_1024MBIT)
+#define DDR_CFG1_SIZE_VAL	0x22362323
+#define DDR_CFG4_SIZE_VAL	9
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_SIZE_2048MBIT)
+#define DDR_CFG1_SIZE_VAL	0x223a2323
+#define DDR_CFG4_SIZE_VAL	9
+#endif
+
+#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_8BIT)
+#define DDR_CFG1_CHIP_WIDTH_VAL	(0x1 << 16)
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT)
+#define DDR_CFG1_CHIP_WIDTH_VAL	(0x2 << 16)
+#endif
+
+#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_16BIT)
+#define DDR_CFG1_BUS_WIDTH_VAL	(0x2 << 12)
+#endif
+#if defined(CONFIG_ONBOARD_DDR2_BUS_WIDTH_32BIT)
+#define DDR_CFG1_BUS_WIDTH_VAL	(0x3 << 12)
+#endif
+
+	.set noreorder
+
+LEAF(lowlevel_init)
+
+	/* Load base addresses as physical addresses for later usage */
+	li	s0, CKSEG1ADDR(MT76XX_SYSCTL_BASE)
+	li	s1, CKSEG1ADDR(MT76XX_MEMCTRL_BASE)
+	li	s2, CKSEG1ADDR(MT76XX_RGCTRL_BASE)
+
+	/* polling CPLL is ready */
+	li	t1, DELAY_USEC(1000000)
+	la	t5, MT76XX_ROM_STATUS_REG
+1:
+	lw	t2, 0(t5)
+	andi	t2, t2, 0x1
+	bnez	t2, CPLL_READY
+	subu	t1, t1, 1
+	bgtz	t1, 1b
+	nop
+	la      t0, MT76XX_CLKCFG0_REG
+	lw      t3, 0(t0)
+	ori	t3, t3, 0x1
+	sw	t3, 0(t0)
+	b	CPLL_DONE
+	nop
+CPLL_READY:
+	la	t0, MT76XX_CLKCFG0_REG
+	lw	t1, 0(t0)
+	li	t2, ~0x0c
+	and	t1, t1, t2
+	ori	t1, t1, 0xc
+	sw	t1, 0(t0)
+	la	t0, MT76XX_DYN_CFG0_REG
+	lw	t3, 0(t0)
+	li	t5, ~((0x0f << 8) | (0x0f << 0))
+	and	t3, t3, t5
+	li	t5, (10 << 8) | (1 << 0)
+	or	t3, t3, t5
+	sw	t3, 0(t0)
+	la	t0, MT76XX_CLKCFG0_REG
+	lw	t3, 0(t0)
+	li	t4, ~0x0F
+	and     t3, t3, t4
+	ori	t3, t3, 0xc
+	sw	t3, 0(t0)
+	lw	t3, 0(t0)
+	ori	t3, t3, 0x08
+	sw	t3, 0(t0)
+
+CPLL_DONE:
+	/*
+	 * SDR and DDR initialization: delay 200us
+	 */
+	li	t0, DELAY_USEC(200 + 40)
+	li	t1, 0x1
+1:
+	sub	t0, t0, t1
+	bnez	t0, 1b
+	nop
+
+	/* set DRAM IO PAD for MT7628IC */
+	/* DDR LDO Enable  */
+	lw	t4, 0x100(s2)
+	li	t2, BIT(31)
+	or	t4, t4, t2
+	sw	t4, 0x100(s2)
+	lw	t4, 0x10c(s2)
+	j	LDO_1P8V
+	nop
+LDO_1P8V:
+	li	t2, ~BIT(6)
+	and	t4, t4, t2
+	sw	t4, 0x10c(s2)
+	j	DDRLDO_SOFT_START
+LDO_2P5V:
+	/* suppose external DDR1 LDO 2.5V */
+	li	t2, BIT(6)
+	or	t4, t4, t2
+	sw	t4, 0x10c(s2)
+
+DDRLDO_SOFT_START:
+	lw	t2, 0x10c(s2)
+	li	t3, BIT(16)
+	or	t2, t2, t3
+	sw	t2, 0x10c(s2)
+	li	t3, DELAY_USEC(250*50)
+LDO_DELAY:
+	subu	t3, t3, 1
+	bnez	t3, LDO_DELAY
+	nop
+
+	lw	t2, 0x10c(s2)
+	li	t3, BIT(18)
+	or	t2, t2, t3
+	sw	t2, 0x10c(s2)
+
+SET_RG_BUCK_FPWM:
+	lw	t2, 0x104(s2)
+	ori	t2, t2, BIT(10)
+	sw	t2, 0x104(s2)
+
+DDR_PAD_CFG:
+	/* clean CLK PAD */
+	lw	t2, 0x704(s2)
+	li	t8, 0xfffff0f0
+	and	t2, t2, t8
+	/* clean CMD PAD */
+	lw	t3, 0x70c(s2)
+	li	t8, 0xfffff0f0
+	and	t3, t3, t8
+	/* clean DQ IPAD */
+	lw	t4, 0x710(s2)
+	li	t8, 0xfffff8ff
+	and	t4, t4, t8
+	/* clean DQ OPAD */
+	lw	t5, 0x714(s2)
+	li	t8, 0xfffff0f0
+	and	t5, t5, t8
+	/* clean DQS IPAD */
+	lw	t6, 0x718(s2)
+	li	t8, 0xfffff8ff
+	and	t6, t6, t8
+	/* clean DQS OPAD */
+	lw	t7, 0x71c(s2)
+	li	t8, 0xfffff0f0
+	and	t7, t7, t8
+
+	lw	t9, 0xc(s0)
+	srl	t9, t9, 16
+	andi	t9, t9, 0x1
+	bnez	t9, MT7628_AN_DDR1_PAD
+MT7628_KN_PAD:
+	li	t8, 0x00000303
+	or	t2, t2, t8
+	or	t3, t3, t8
+	or	t5, t5, t8
+	or	t7, t7, t8
+	li	t8, 0x00000000
+	or	t4, t4, t8
+	or	t6, t6, t8
+	j	SET_PAD_CFG
+MT7628_AN_DDR1_PAD:
+	lw	t1, 0x10(s0)
+	andi	t1, t1, 0x1
+	beqz	t1, MT7628_AN_DDR2_PAD
+	li	t8, 0x00000c0c
+	or	t2, t2, t8
+	li	t8, 0x00000202
+	or	t3, t3, t8
+	li	t8, 0x00000707
+	or	t5, t5, t8
+	li	t8, 0x00000c0c
+	or	t7, t7, t8
+	li	t8, 0x00000000
+	or	t4, t4, t8
+	or	t6, t6, t8
+	j	SET_PAD_CFG
+MT7628_AN_DDR2_PAD:
+	li	t8, 0x00000c0c
+	or	t2, t2, t8
+	li	t8, 0x00000202
+	or	t3, t3, t8
+	li	t8, 0x00000404
+	or	t5, t5, t8
+	li	t8, 0x00000c0c
+	or	t7, t7, t8
+	li	t8, 0x00000000		/* ODT off */
+	or	t4, t4, t8
+	or	t6, t6, t8
+
+SET_PAD_CFG:
+	sw	t2, 0x704(s2)
+	sw	t3, 0x70c(s2)
+	sw	t4, 0x710(s2)
+	sw	t5, 0x714(s2)
+	sw	t6, 0x718(s2)
+	sw	t7, 0x71c(s2)
+
+	/*
+	 * DDR initialization: reset pin to 0
+	 */
+	lw	t2, 0x34(s0)
+	and	t2, ~BIT(10)
+	sw	t2, 0x34(s0)
+	nop
+
+	/*
+	 * DDR initialization: wait til reg DDR_CFG1 bit 21 equal to 1 (ready)
+	 */
+DDR_READY:
+	li	t1, DDR_CFG1_REG
+	lw	t0, 0(t1)
+	nop
+	and	t2, t0, BIT(21)
+	beqz	t2, DDR_READY
+	nop
+
+	/*
+	 * DDR initialization
+	 *
+	 * Only DDR2 supported right now. DDR2 support can be added, once
+	 * boards using it will get added to mainline U-Boot.
+	 */
+	li	t1, DDR_CFG2_REG
+	lw	t0, 0(t1)
+	nop
+	and	t0, ~BIT(30)
+	and	t0, ~(7 << 4)
+	or	t0, (4 << 4)
+	or	t0, BIT(30)
+	or	t0, BIT(11)
+	sw	t0, 0(t1)
+	nop
+
+	li	t1, DDR_CFG3_REG
+	lw	t2, 0(t1)
+	/* Disable ODT; reference board ok, ev board fail */
+	and	t2, ~BIT(6)
+	or	t2, BIT(2)
+	li	t0, DDR_CFG4_REG
+	lw	t1, 0(t0)
+	li	t2, ~(0x01f | 0x0f0)
+	and	t1, t1, t2
+	ori	t1, t1, DDR_CFG4_SIZE_VAL
+	sw	t1, 0(t0)
+	nop
+
+	/*
+	 * DDR initialization: config size and width on reg DDR_CFG1
+	 */
+	li	t6, DDR_CFG1_SIZE_VAL
+
+	and	t6, ~DDR_CFG1_CHIP_WIDTH_MASK
+	or	t6, DDR_CFG1_CHIP_WIDTH_VAL
+
+	/* CONFIG DDR_CFG1[13:12] about TOTAL WIDTH */
+	and	t6, ~DDR_CFG1_BUS_WIDTH_MASK
+	or	t6, DDR_CFG1_BUS_WIDTH_VAL
+
+	li	t5, DDR_CFG1_REG
+	sw	t6, 0(t5)
+	nop
+
+	/*
+	 * DDR: enable self auto refresh for power saving
+	 * enable it by default for both RAM and ROM version (for CoC)
+	 */
+	lw	t1, 0x14(s1)
+	nop
+	and	t1, 0xff000000
+	or	t1, 0x01
+	sw	t1, 0x14(s1)
+	nop
+	lw	t1, 0x10(s1)
+	nop
+	or	t1, 0x10
+	sw	t1, 0x10(s1)
+	nop
+
+	jr	ra
+	nop
+	END(lowlevel_init)
diff --git a/arch/mips/mach-mt7620/mt76xx.h b/arch/mips/mach-mt7620/mt76xx.h
new file mode 100644
index 0000000..17473ea
--- /dev/null
+++ b/arch/mips/mach-mt7620/mt76xx.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#ifndef __MT76XX_H
+#define __MT76XX_H
+
+#define MT76XX_SYSCTL_BASE	0x10000000
+
+#define MT76XX_CHIPID_OFFS	0x00
+#define MT76XX_CHIP_REV_ID_OFFS	0x0c
+#define MT76XX_SYSCFG0_OFFS	0x10
+
+#define MT76XX_MEMCTRL_BASE	(MT76XX_SYSCTL_BASE + 0x0300)
+#define MT76XX_RGCTRL_BASE	(MT76XX_SYSCTL_BASE + 0x1000)
+
+#define MT76XX_ROM_STATUS_REG	(MT76XX_SYSCTL_BASE + 0x0028)
+#define MT76XX_CLKCFG0_REG	(MT76XX_SYSCTL_BASE + 0x002c)
+#define MT76XX_DYN_CFG0_REG	(MT76XX_SYSCTL_BASE + 0x0440)
+
+#define DDR_CFG1_REG		(MT76XX_MEMCTRL_BASE + 0x44)
+#define DDR_CFG2_REG		(MT76XX_MEMCTRL_BASE + 0x48)
+#define DDR_CFG3_REG		(MT76XX_MEMCTRL_BASE + 0x4c)
+#define DDR_CFG4_REG		(MT76XX_MEMCTRL_BASE + 0x50)
+
+#ifndef __ASSEMBLY__
+/* Prototypes */
+void ddr_calibrate(void);
+#endif
+
+#endif
diff --git a/arch/nds32/config.mk b/arch/nds32/config.mk
index cb3d8b3..c5520fd 100644
--- a/arch/nds32/config.mk
+++ b/arch/nds32/config.mk
@@ -15,7 +15,7 @@
 CONFIG_STANDALONE_LOAD_ADDR = 0x300000 \
 			      -T $(srctree)/examples/standalone/nds32.lds
 
-PLATFORM_RELFLAGS	+= -fno-strict-aliasing -fno-common -mrelax
+PLATFORM_RELFLAGS	+= -fno-common -mrelax
 PLATFORM_RELFLAGS	+= -gdwarf-2
 PLATFORM_CPPFLAGS	+= -D__nds32__ -G0 -ffixed-10 -fpie
 
diff --git a/arch/riscv/config.mk b/arch/riscv/config.mk
index 219e666..c0b3858 100644
--- a/arch/riscv/config.mk
+++ b/arch/riscv/config.mk
@@ -31,7 +31,7 @@
 			      -T $(srctree)/examples/standalone/riscv.lds
 
 PLATFORM_CPPFLAGS	+= -ffixed-gp -fpic
-PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -gdwarf-2 -ffunction-sections
+PLATFORM_RELFLAGS += -fno-common -gdwarf-2 -ffunction-sections
 LDFLAGS_u-boot += --gc-sections -static -pie
 
 EFI_CRT0		:= crt0_riscv_efi.o
diff --git a/arch/sandbox/cpu/cpu.c b/arch/sandbox/cpu/cpu.c
index cde0b05..6098945 100644
--- a/arch/sandbox/cpu/cpu.c
+++ b/arch/sandbox/cpu/cpu.c
@@ -57,14 +57,104 @@
 	return 0;
 }
 
+/**
+ * is_in_sandbox_mem() - Checks if a pointer is within sandbox's emulated DRAM
+ *
+ * This provides a way to check if a pointer is owned by sandbox (and is within
+ * its RAM) or not. Sometimes pointers come from a test which conceptually runs
+ * output sandbox, potentially with direct access to the C-library malloc()
+ * function, or the sandbox stack (which is not actually within the emulated
+ * DRAM.
+ *
+ * Such pointers obviously cannot be mapped into sandbox's DRAM, so we must
+ * detect them an process them separately, by recording a mapping to a tag,
+ * which we can use to map back to the pointer later.
+ *
+ * @ptr: Pointer to check
+ * @return true if this is within sandbox emulated DRAM, false if not
+ */
+static bool is_in_sandbox_mem(const void *ptr)
+{
+	return (const uint8_t *)ptr >= gd->arch.ram_buf &&
+		(const uint8_t *)ptr < gd->arch.ram_buf + gd->ram_size;
+}
+
+/**
+ * phys_to_virt() - Converts a sandbox RAM address to a pointer
+ *
+ * Sandbox uses U-Boot addresses from 0 to the size of DRAM. These index into
+ * the emulated DRAM buffer used by sandbox. This function converts such an
+ * address to a pointer into this buffer, which can be used to access the
+ * memory.
+ *
+ * If the address is outside this range, it is assumed to be a tag
+ */
 void *phys_to_virt(phys_addr_t paddr)
 {
-	return (void *)(gd->arch.ram_buf + paddr);
+	struct sandbox_mapmem_entry *mentry;
+	struct sandbox_state *state;
+
+	/* If the address is within emulated DRAM, calculate the value */
+	if (paddr < gd->ram_size)
+		return (void *)(gd->arch.ram_buf + paddr);
+
+	/*
+	 * Otherwise search out list of tags for the correct pointer previously
+	 * created by map_to_sysmem()
+	 */
+	state = state_get_current();
+	list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
+		if (mentry->tag == paddr) {
+			printf("%s: Used map from %lx to %p\n", __func__,
+			       (ulong)paddr, mentry->ptr);
+			return mentry->ptr;
+		}
+	}
+
+	printf("%s: Cannot map sandbox address %lx (SDRAM from 0 to %lx)\n",
+	       __func__, (ulong)paddr, (ulong)gd->ram_size);
+	os_abort();
+
+	/* Not reached */
+	return NULL;
 }
 
-phys_addr_t virt_to_phys(void *vaddr)
+struct sandbox_mapmem_entry *find_tag(const void *ptr)
 {
-	return (phys_addr_t)((uint8_t *)vaddr - gd->arch.ram_buf);
+	struct sandbox_mapmem_entry *mentry;
+	struct sandbox_state *state = state_get_current();
+
+	list_for_each_entry(mentry, &state->mapmem_head, sibling_node) {
+		if (mentry->ptr == ptr) {
+			debug("%s: Used map from %p to %lx\n", __func__, ptr,
+			      mentry->tag);
+			return mentry;
+		}
+	}
+	return NULL;
+}
+
+phys_addr_t virt_to_phys(void *ptr)
+{
+	struct sandbox_mapmem_entry *mentry;
+
+	/*
+	 * If it is in emulated RAM, don't bother looking for a tag. Just
+	 * calculate the pointer using the provides offset into the RAM buffer.
+	 */
+	if (is_in_sandbox_mem(ptr))
+		return (phys_addr_t)((uint8_t *)ptr - gd->arch.ram_buf);
+
+	mentry = find_tag(ptr);
+	if (!mentry) {
+		/* Abort so that gdb can be used here */
+		printf("%s: Cannot map sandbox address %p (SDRAM from 0 to %lx)\n",
+		       __func__, ptr, (ulong)gd->ram_size);
+		os_abort();
+	}
+	printf("%s: Used map from %p to %lx\n", __func__, ptr, mentry->tag);
+
+	return mentry->tag;
 }
 
 void *map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
@@ -87,24 +177,57 @@
 	return phys_to_virt(paddr);
 }
 
-void unmap_physmem(const void *vaddr, unsigned long flags)
+void unmap_physmem(const void *ptr, unsigned long flags)
 {
 #ifdef CONFIG_PCI
 	if (map_dev) {
-		pci_unmap_physmem(vaddr, map_len, map_dev);
+		pci_unmap_physmem(ptr, map_len, map_dev);
 		map_dev = NULL;
 	}
 #endif
 }
 
-void sandbox_set_enable_pci_map(int enable)
+phys_addr_t map_to_sysmem(const void *ptr)
 {
-	enable_pci_map = enable;
+	struct sandbox_mapmem_entry *mentry;
+
+	/*
+	 * If it is in emulated RAM, don't bother creating a tag. Just return
+	 * the offset into the RAM buffer.
+	 */
+	if (is_in_sandbox_mem(ptr))
+		return (u8 *)ptr - gd->arch.ram_buf;
+
+	/*
+	 * See if there is an existing tag with this pointer. If not, set up a
+	 * new one.
+	 */
+	mentry = find_tag(ptr);
+	if (!mentry) {
+		struct sandbox_state *state = state_get_current();
+
+		mentry = malloc(sizeof(*mentry));
+		if (!mentry) {
+			printf("%s: Error: Out of memory\n", __func__);
+			os_exit(ENOMEM);
+		}
+		mentry->tag = state->next_tag++;
+		mentry->ptr = (void *)ptr;
+		list_add_tail(&mentry->sibling_node, &state->mapmem_head);
+		debug("%s: Added map from %p to %lx\n", __func__, ptr,
+		      (ulong)mentry->tag);
+	}
+
+	/*
+	 * Return the tag as the address to use. A later call to map_sysmem()
+	 * will return ptr
+	 */
+	return mentry->tag;
 }
 
-phys_addr_t map_to_sysmem(const void *ptr)
+void sandbox_set_enable_pci_map(int enable)
 {
-	return (u8 *)ptr - gd->arch.ram_buf;
+	enable_pci_map = enable;
 }
 
 void flush_dcache_range(unsigned long start, unsigned long stop)
@@ -165,15 +288,3 @@
 
 	return (count - base_count) / 1000;
 }
-
-int setjmp(jmp_buf jmp)
-{
-	return os_setjmp((ulong *)jmp, sizeof(*jmp));
-}
-
-void longjmp(jmp_buf jmp, int ret)
-{
-	os_longjmp((ulong *)jmp, ret);
-	while (1)
-		;
-}
diff --git a/arch/sandbox/cpu/os.c b/arch/sandbox/cpu/os.c
index 5839932..9fbcb9e 100644
--- a/arch/sandbox/cpu/os.c
+++ b/arch/sandbox/cpu/os.c
@@ -143,14 +143,16 @@
 void *os_malloc(size_t length)
 {
 	struct os_mem_hdr *hdr;
+	int page_size = getpagesize();
 
-	hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE,
+	hdr = mmap(NULL, length + page_size,
+		   PROT_READ | PROT_WRITE | PROT_EXEC,
 		   MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
 	if (hdr == MAP_FAILED)
 		return NULL;
 	hdr->length = length;
 
-	return hdr + 1;
+	return (void *)hdr + page_size;
 }
 
 void os_free(void *ptr)
@@ -630,24 +632,7 @@
 	rt->tm_isdst = tm->tm_isdst;
 }
 
-int os_setjmp(ulong *jmp, int size)
-{
-	jmp_buf dummy;
-
-	/*
-	 * We cannot rely on the struct name that jmp_buf uses, so use a
-	 * local variable here
-	 */
-	if (size < sizeof(dummy)) {
-		printf("setjmp: jmpbuf is too small (%d bytes, need %d)\n",
-		       size, sizeof(jmp_buf));
-		return -ENOSPC;
-	}
-
-	return setjmp((struct __jmp_buf_tag *)jmp);
-}
-
-void os_longjmp(ulong *jmp, int ret)
+void os_abort(void)
 {
-	longjmp((struct __jmp_buf_tag *)jmp, ret);
+	abort();
 }
diff --git a/arch/sandbox/cpu/state.c b/arch/sandbox/cpu/state.c
index cc50819..04a11fe 100644
--- a/arch/sandbox/cpu/state.c
+++ b/arch/sandbox/cpu/state.c
@@ -359,6 +359,14 @@
 
 	memset(&state->wdt, '\0', sizeof(state->wdt));
 	memset(state->spi, '\0', sizeof(state->spi));
+
+	/*
+	 * Set up the memory tag list. Use the top of emulated SDRAM for the
+	 * first tag number, since that address offset is outside the legal
+	 * range, and can be assumed to be a tag.
+	 */
+	INIT_LIST_HEAD(&state->mapmem_head);
+	state->next_tag = state->ram_size;
 }
 
 int state_init(void)
diff --git a/arch/sandbox/dts/sandbox.dts b/arch/sandbox/dts/sandbox.dts
index 6ac37f1..1aa0f8e 100644
--- a/arch/sandbox/dts/sandbox.dts
+++ b/arch/sandbox/dts/sandbox.dts
@@ -153,6 +153,7 @@
 
 	pinctrl {
 		compatible = "sandbox,pinctrl";
+		status = "okay";
 
 		pinctrl_i2c0: i2c0 {
 			groups = "i2c";
@@ -164,6 +165,12 @@
 			groups = "serial_a";
 			function = "serial";
 		};
+
+		pinctrl_onewire0: onewire0 {
+			groups = "w1";
+			function = "w1";
+			bias-pull-up;
+		};
 	};
 
 	reset@1 {
@@ -322,6 +329,19 @@
 			reg = <0x0 0x400>;
 		};
 	};
+
+	onewire0: onewire {
+		compatible = "w1-gpio";
+		gpios = <&gpio_a 8>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_onewire0>;
+		status = "okay";
+
+		sandbox_eeprom0: sandbox_eeprom@0 {
+			compatible = "sandbox,w1-eeprom";
+			status = "okay";
+		};
+	};
 };
 
 #include "cros-ec-keyboard.dtsi"
diff --git a/arch/sandbox/include/asm/setjmp.h b/arch/sandbox/include/asm/setjmp.h
index 1fe37c9..001c7ea 100644
--- a/arch/sandbox/include/asm/setjmp.h
+++ b/arch/sandbox/include/asm/setjmp.h
@@ -24,6 +24,11 @@
 
 typedef struct jmp_buf_data jmp_buf[1];
 
+/*
+ * We have to directly link with the system versions of
+ * setjmp/longjmp, because setjmp must not return as otherwise
+ * the stack may become invalid.
+ */
 int setjmp(jmp_buf jmp);
 __noreturn void longjmp(jmp_buf jmp, int ret);
 
diff --git a/arch/sandbox/include/asm/state.h b/arch/sandbox/include/asm/state.h
index 7ed4b51..a612ce8 100644
--- a/arch/sandbox/include/asm/state.h
+++ b/arch/sandbox/include/asm/state.h
@@ -9,6 +9,7 @@
 #include <config.h>
 #include <sysreset.h>
 #include <stdbool.h>
+#include <linux/list.h>
 #include <linux/stringify.h>
 
 /**
@@ -45,6 +46,23 @@
 	bool running;
 };
 
+/**
+ * struct sandbox_mapmem_entry - maps pointers to/from U-Boot addresses
+ *
+ * When map_to_sysmem() is called with an address outside sandbox's emulated
+ * RAM, a record is created with a tag that can be used to reference that
+ * pointer. When map_sysmem() is called later with that tag, the pointer will
+ * be returned, just as it would for a normal sandbox address.
+ *
+ * @tag: Address tag (a value which U-Boot uses to refer to the address)
+ * @ptr: Associated pointer for that tag
+ */
+struct sandbox_mapmem_entry {
+	ulong tag;
+	void *ptr;
+	struct list_head sibling_node;
+};
+
 /* The complete state of the test system */
 struct sandbox_state {
 	const char *cmd;		/* Command to execute */
@@ -78,6 +96,9 @@
 
 	/* Information about Watchdog */
 	struct sandbox_wdt_info wdt;
+
+	ulong next_tag;			/* Next address tag to allocate */
+	struct list_head mapmem_head;	/* struct sandbox_mapmem_entry */
 };
 
 /* Minimum space we guarantee in the state FDT when calling read/write*/
diff --git a/arch/x86/config.mk b/arch/x86/config.mk
index 5b04feb..cc94071 100644
--- a/arch/x86/config.mk
+++ b/arch/x86/config.mk
@@ -5,7 +5,6 @@
 
 CONFIG_STANDALONE_LOAD_ADDR ?= 0x40000
 
-PLATFORM_CPPFLAGS += -fno-strict-aliasing
 PLATFORM_CPPFLAGS += -fomit-frame-pointer
 PF_CPPFLAGS_X86   := $(call cc-option, -fno-toplevel-reorder, \
 		     $(call cc-option, -fno-unit-at-a-time))
diff --git a/arch/x86/lib/e820.c b/arch/x86/lib/e820.c
index 8b34f67..d6ae2c4 100644
--- a/arch/x86/lib/e820.c
+++ b/arch/x86/lib/e820.c
@@ -36,7 +36,7 @@
 	return 4;
 }
 
-#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER)
 void efi_add_known_memory(void)
 {
 	struct e820_entry e820[E820MAX];
@@ -72,4 +72,4 @@
 		efi_add_memory_map(start, pages, type, false);
 	}
 }
-#endif /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
+#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
diff --git a/arch/xtensa/include/asm/atomic.h b/arch/xtensa/include/asm/atomic.h
index 42b32f5..4e3ad56 100644
--- a/arch/xtensa/include/asm/atomic.h
+++ b/arch/xtensa/include/asm/atomic.h
@@ -7,48 +7,6 @@
 #define _XTENSA_ATOMIC_H
 
 #include <asm/system.h>
-
-typedef struct { volatile int counter; } atomic_t;
-
-#define ATOMIC_INIT(i)	{ (i) }
-
-#define atomic_read(v)		((v)->counter)
-#define atomic_set(v, i)	((v)->counter = (i))
-
-static inline void atomic_add(int i, atomic_t *v)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	v->counter += i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_sub(int i, atomic_t *v)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	v->counter -= i;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_inc(atomic_t *v)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	++v->counter;
-	local_irq_restore(flags);
-}
-
-static inline void atomic_dec(atomic_t *v)
-{
-	unsigned long flags;
-
-	local_irq_save(flags);
-	--v->counter;
-	local_irq_restore(flags);
-}
+#include <asm-generic/atomic.h>
 
 #endif
diff --git a/board/atmel/common/board.c b/board/atmel/common/board.c
index 650eb22..8f9b5e1 100644
--- a/board/atmel/common/board.c
+++ b/board/atmel/common/board.c
@@ -5,7 +5,64 @@
  */
 
 #include <common.h>
+#include <w1.h>
+#include <w1-eeprom.h>
+#include <dm/device-internal.h>
+
+#define AT91_PDA_EEPROM_ID_OFFSET		15
+#define AT91_PDA_EEPROM_ID_LENGTH		5
+#define AT91_PDA_EEPROM_DEFAULT_BUS		0
 
 void dummy(void)
 {
 }
+
+#if defined CONFIG_W1
+void at91_pda_detect(void)
+{
+	struct udevice *bus, *dev;
+	u8 buf[AT91_PDA_EEPROM_ID_LENGTH + 1] = {0};
+	int ret;
+	int pda = 0;
+
+	ret = w1_get_bus(AT91_PDA_EEPROM_DEFAULT_BUS, &bus);
+	if (ret)
+		return;
+
+	for (device_find_first_child(bus, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		ret = device_probe(dev);
+		if (ret) {
+			continue;
+		} else {
+			ret = w1_eeprom_read_buf(dev, AT91_PDA_EEPROM_ID_OFFSET,
+						 (u8 *)buf, AT91_PDA_EEPROM_ID_LENGTH);
+			if (ret)
+				return;
+			break;
+		}
+	}
+	pda = simple_strtoul((const char *)buf, NULL, 10);
+
+	switch (pda) {
+	case 7000:
+		if (buf[4] == 'B')
+			printf("PDA TM7000B detected\n");
+		else
+			printf("PDA TM7000 detected\n");
+		break;
+	case 4300:
+		printf("PDA TM4300 detected\n");
+		break;
+	case 5000:
+		printf("PDA TM5000 detected\n");
+		break;
+	}
+	env_set("pda", (const char *)buf);
+}
+#else
+void at91_pda_detect(void)
+{
+}
+#endif
diff --git a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c
index d5ddf8d..8363434 100644
--- a/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c
+++ b/board/atmel/sama5d27_som1_ek/sama5d27_som1_ek.c
@@ -15,6 +15,8 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/sama5d2.h>
 
+extern void at91_pda_detect(void);
+
 DECLARE_GLOBAL_DATA_PTR;
 
 static void board_usb_hw_init(void)
@@ -28,6 +30,7 @@
 #ifdef CONFIG_DM_VIDEO
 	at91_video_show_board_info();
 #endif
+	at91_pda_detect();
 	return 0;
 }
 #endif
diff --git a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c
index 789841e..17e08fa 100644
--- a/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c
+++ b/board/atmel/sama5d2_ptc_ek/sama5d2_ptc_ek.c
@@ -20,6 +20,8 @@
 #include <asm/arch/sama5d2.h>
 #include <asm/arch/sama5d2_smc.h>
 
+extern void at91_pda_detect(void);
+
 DECLARE_GLOBAL_DATA_PTR;
 
 #ifdef CONFIG_NAND_ATMEL
@@ -65,6 +67,14 @@
 }
 #endif
 
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+	at91_pda_detect();
+	return 0;
+}
+#endif
+
 static void board_usb_hw_init(void)
 {
 	atmel_pio4_set_pio_output(AT91_PIO_PORTB, 12, ATMEL_PIO_PUEN_MASK);
diff --git a/board/atmel/sama5d2_xplained/sama5d2_xplained.c b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
index 592b4d8..fccd80e 100644
--- a/board/atmel/sama5d2_xplained/sama5d2_xplained.c
+++ b/board/atmel/sama5d2_xplained/sama5d2_xplained.c
@@ -15,6 +15,8 @@
 #include <asm/arch/gpio.h>
 #include <asm/arch/sama5d2.h>
 
+extern void at91_pda_detect(void);
+
 DECLARE_GLOBAL_DATA_PTR;
 
 static void board_usb_hw_init(void)
@@ -28,6 +30,7 @@
 #ifdef CONFIG_DM_VIDEO
 	at91_video_show_board_info();
 #endif
+	at91_pda_detect();
 	return 0;
 }
 #endif
diff --git a/board/atmel/sama5d3_xplained/sama5d3_xplained.c b/board/atmel/sama5d3_xplained/sama5d3_xplained.c
index c47f638..289f8d8 100644
--- a/board/atmel/sama5d3_xplained/sama5d3_xplained.c
+++ b/board/atmel/sama5d3_xplained/sama5d3_xplained.c
@@ -18,6 +18,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+extern void at91_pda_detect(void);
+
 #ifdef CONFIG_NAND_ATMEL
 void sama5d3_xplained_nand_hw_init(void)
 {
@@ -72,6 +74,14 @@
 }
 #endif
 
+#ifdef CONFIG_BOARD_LATE_INIT
+int board_late_init(void)
+{
+	at91_pda_detect();
+	return 0;
+}
+#endif
+
 #ifdef CONFIG_BOARD_EARLY_INIT_F
 int board_early_init_f(void)
 {
diff --git a/board/atmel/sama5d4_xplained/sama5d4_xplained.c b/board/atmel/sama5d4_xplained/sama5d4_xplained.c
index 526c6c7..4da6489 100644
--- a/board/atmel/sama5d4_xplained/sama5d4_xplained.c
+++ b/board/atmel/sama5d4_xplained/sama5d4_xplained.c
@@ -17,6 +17,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+extern void at91_pda_detect(void);
+
 #ifdef CONFIG_NAND_ATMEL
 static void sama5d4_xplained_nand_hw_init(void)
 {
@@ -71,6 +73,7 @@
 #ifdef CONFIG_BOARD_LATE_INIT
 int board_late_init(void)
 {
+	at91_pda_detect();
 #ifdef CONFIG_DM_VIDEO
 	at91_video_show_board_info();
 #endif
diff --git a/board/gardena/smart-gateway-mt7688/Kconfig b/board/gardena/smart-gateway-mt7688/Kconfig
new file mode 100644
index 0000000..3653f8a
--- /dev/null
+++ b/board/gardena/smart-gateway-mt7688/Kconfig
@@ -0,0 +1,12 @@
+if BOARD_GARDENA_SMART_GATEWAY_MT7688
+
+config SYS_BOARD
+	default "smart-gateway-mt7688"
+
+config SYS_VENDOR
+	default "gardena"
+
+config SYS_CONFIG_NAME
+	default "gardena-smart-gateway-mt7688"
+
+endif
diff --git a/board/gardena/smart-gateway-mt7688/MAINTAINERS b/board/gardena/smart-gateway-mt7688/MAINTAINERS
new file mode 100644
index 0000000..bbb491c
--- /dev/null
+++ b/board/gardena/smart-gateway-mt7688/MAINTAINERS
@@ -0,0 +1,8 @@
+GARDENA_SMART_GATEWAY_MT7688 BOARD
+M:	Stefan Roese <sr@denx.de>
+S:	Maintained
+F:	board/gardena/smart-gateway-mt7688
+F:	include/configs/gardena-smart-gateway-mt7688.h
+F:	configs/gardena-smart-gateway-mt7688_defconfig
+F:	configs/gardena-smart-gateway-mt7688-ram_defconfig
+F:	arch/mips/dts/gardena-smart-gateway-mt7688.dts
diff --git a/board/gardena/smart-gateway-mt7688/Makefile b/board/gardena/smart-gateway-mt7688/Makefile
new file mode 100644
index 0000000..70cd7a8
--- /dev/null
+++ b/board/gardena/smart-gateway-mt7688/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += board.o
diff --git a/board/gardena/smart-gateway-mt7688/board.c b/board/gardena/smart-gateway-mt7688/board.c
new file mode 100644
index 0000000..5ff546f
--- /dev/null
+++ b/board/gardena/smart-gateway-mt7688/board.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+int board_early_init_f(void)
+{
+	/*
+	 * Nothing to be done here for this board (no UART setup etc)
+	 * right now. We might need some pin muxing, so lets keep this
+	 * function for now.
+	 */
+	return 0;
+}
diff --git a/board/logicpd/omap3som/omap3logic.c b/board/logicpd/omap3som/omap3logic.c
index 620423b..48d8869 100644
--- a/board/logicpd/omap3som/omap3logic.c
+++ b/board/logicpd/omap3som/omap3logic.c
@@ -331,13 +331,6 @@
 #endif
 
 #if defined(CONFIG_MMC)
-int board_mmc_init(bd_t *bis)
-{
-	return omap_mmc_init(0, 0, 0, -1, -1);
-}
-#endif
-
-#if defined(CONFIG_MMC)
 void board_mmc_power_init(void)
 {
 	twl4030_power_mmc_init(0);
diff --git a/board/logicpd/omap3som/omap3logic.h b/board/logicpd/omap3som/omap3logic.h
index a5601f7..aeb26b9 100644
--- a/board/logicpd/omap3som/omap3logic.h
+++ b/board/logicpd/omap3som/omap3logic.h
@@ -131,145 +131,18 @@
 	MUX_VAL(CP(GPMC_WAIT2), (IEN  | PTU | EN  | M4)); /*GPIO_64*/
 	MUX_VAL(CP(GPMC_WAIT3), (IEN  | PTU | EN  | M0)); /*GPMC_WAIT3*/
 
-	MUX_VAL(CP(CAM_HS), (IEN  | PTU | EN  | M0)); /*CAM_HS */
-	MUX_VAL(CP(CAM_VS), (IEN  | PTU | EN  | M0)); /*CAM_VS */
-	MUX_VAL(CP(CAM_XCLKA), (IDIS | PTD | DIS | M0)); /*CAM_XCLKA*/
-	MUX_VAL(CP(CAM_PCLK), (IEN  | PTU | EN  | M0)); /*CAM_PCLK*/
-	MUX_VAL(CP(CAM_FLD), (IDIS | PTD | DIS | M4)); /*GPIO_98*/
-	MUX_VAL(CP(CAM_D0), (IEN  | PTD | DIS | M0)); /*CAM_D0*/
-	MUX_VAL(CP(CAM_D1), (IEN  | PTD | DIS | M0)); /*CAM_D1*/
-	MUX_VAL(CP(CAM_D2), (IEN  | PTD | DIS | M0)); /*CAM_D2*/
-	MUX_VAL(CP(CAM_D3), (IEN  | PTD | DIS | M0)); /*CAM_D3*/
-	MUX_VAL(CP(CAM_D4), (IEN  | PTD | DIS | M0)); /*CAM_D4*/
-	MUX_VAL(CP(CAM_D5), (IEN  | PTD | DIS | M0)); /*CAM_D5*/
-	MUX_VAL(CP(CAM_D6), (IEN  | PTD | DIS | M0)); /*CAM_D6*/
-	MUX_VAL(CP(CAM_D7), (IEN  | PTD | DIS | M0)); /*CAM_D7*/
-	MUX_VAL(CP(CAM_D8), (IEN  | PTD | DIS | M0)); /*CAM_D8*/
-	MUX_VAL(CP(CAM_D9), (IEN  | PTD | DIS | M0)); /*CAM_D9*/
-	MUX_VAL(CP(CAM_D10), (IEN  | PTD | DIS | M0)); /*CAM_D10*/
-	MUX_VAL(CP(CAM_D11), (IEN  | PTD | DIS | M0)); /*CAM_D11*/
-	MUX_VAL(CP(CAM_XCLKB), (IDIS | PTD | DIS | M0)); /*CAM_XCLKB*/
-	MUX_VAL(CP(CAM_WEN), (IEN  | PTD | DIS | M4)); /*GPIO_167*/
-	MUX_VAL(CP(CAM_STROBE), (IDIS | PTD | DIS | M0)); /*CAM_STROBE*/
-
-	MUX_VAL(CP(CSI2_DX0), (IEN  | PTD | DIS | M0)); /*CSI2_DX0*/
-	MUX_VAL(CP(CSI2_DY0), (IEN  | PTD | DIS | M0)); /*CSI2_DY0*/
-	MUX_VAL(CP(CSI2_DX1), (IEN  | PTD | DIS | M0)); /*CSI2_DX1*/
-	MUX_VAL(CP(CSI2_DY1), (IEN  | PTD | DIS | M0)); /*CSI2_DY1*/
-
-	MUX_VAL(CP(MCBSP2_FSX), (IEN  | PTD | DIS | M0)); /*McBSP2_FSX*/
-	MUX_VAL(CP(MCBSP2_CLKX), (IEN  | PTD | DIS | M0)); /*McBSP2_CLKX*/
-	MUX_VAL(CP(MCBSP2_DR), (IEN  | PTD | DIS | M0)); /*McBSP2_DR*/
-	MUX_VAL(CP(MCBSP2_DX), (IDIS | PTD | DIS | M0)); /*McBSP2_DX*/
-
 	MUX_VAL(CP(MMC1_CLK), (IDIS | PTU | EN  | M0)); /*MMC1_CLK*/
 	MUX_VAL(CP(MMC1_CMD), (IEN  | PTU | EN  | M0)); /*MMC1_CMD*/
 	MUX_VAL(CP(MMC1_DAT0), (IEN  | PTU | EN  | M0)); /*MMC1_DAT0*/
 	MUX_VAL(CP(MMC1_DAT1), (IEN  | PTU | EN  | M0)); /*MMC1_DAT1*/
 	MUX_VAL(CP(MMC1_DAT2), (IEN  | PTU | EN  | M0)); /*MMC1_DAT2*/
 	MUX_VAL(CP(MMC1_DAT3), (IEN  | PTU | EN  | M0)); /*MMC1_DAT3*/
-	MUX_VAL(CP(MMC1_DAT4), (IEN  | PTU | EN  | M0)); /*MMC1_DAT4*/
-	MUX_VAL(CP(MMC1_DAT5), (IEN  | PTU | EN  | M0)); /*MMC1_DAT5*/
-	MUX_VAL(CP(MMC1_DAT6), (IEN  | PTU | EN  | M0)); /*MMC1_DAT6*/
-	MUX_VAL(CP(MMC1_DAT7), (IEN  | PTU | EN  | M0)); /*MMC1_DAT7*/
-
-	MUX_VAL(CP(MMC2_CLK),  (IEN  | PTD | DIS | M0)); /*MMC2_CLK*/
-	MUX_VAL(CP(MMC2_CMD),  (IEN  | PTU | EN  | M0)); /*MMC2_CMD*/
-	MUX_VAL(CP(MMC2_DAT0), (IEN  | PTU | EN  | M0)); /*MMC2_DAT0*/
-	MUX_VAL(CP(MMC2_DAT1), (IEN  | PTU | EN  | M0)); /*MMC2_DAT1*/
-	MUX_VAL(CP(MMC2_DAT2), (IEN  | PTU | EN  | M0)); /*MMC2_DAT2*/
-	MUX_VAL(CP(MMC2_DAT3), (IEN  | PTU | EN  | M0)); /*MMC2_DAT3*/
-	MUX_VAL(CP(MMC2_DAT4), (IDIS | PTD | DIS | M0)); /*MMC2_DAT4*/
-	MUX_VAL(CP(MMC2_DAT5), (IDIS | PTD | DIS | M0)); /*MMC2_DAT5*/
-	MUX_VAL(CP(MMC2_DAT6), (IDIS | PTD | DIS | M0)); /*MMC2_DAT6 */
-	MUX_VAL(CP(MMC2_DAT7), (IEN  | PTU | EN  | M0)); /*MMC2_DAT7*/
-
-	MUX_VAL(CP(MCBSP3_DX), (IDIS | PTD | DIS | M0)); /*McBSP3_DX*/
-	MUX_VAL(CP(MCBSP3_DR), (IEN  | PTD | DIS | M0)); /*McBSP3_DR*/
-	MUX_VAL(CP(MCBSP3_CLKX), (IEN  | PTD | DIS | M0)); /*McBSP3_CLKX*/
-	MUX_VAL(CP(MCBSP3_FSX), (IEN  | PTD | DIS | M0)); /*McBSP3_FSX*/
-
-	MUX_VAL(CP(UART2_CTS), (IEN  | PTU | EN  | M0)); /*UART2_CTS*/
-	MUX_VAL(CP(UART2_RTS), (IDIS | PTD | DIS | M0)); /*UART2_RTS*/
-	MUX_VAL(CP(UART2_TX), (IDIS | PTD | DIS | M0)); /*UART2_TX*/
-	MUX_VAL(CP(UART2_RX), (IEN  | PTD | DIS | M0)); /*UART2_RX*/
 
 	MUX_VAL(CP(UART1_TX), (IDIS | PTD | DIS | M0)); /*UART1_TX*/
 	MUX_VAL(CP(UART1_RTS), (IDIS | PTD | DIS | M0)); /*UART1_RTS*/
 	MUX_VAL(CP(UART1_CTS), (IEN  | PTU | DIS | M0)); /*UART1_CTS*/
 	MUX_VAL(CP(UART1_RX), (IEN  | PTD | DIS | M0)); /*UART1_RX*/
 
-	MUX_VAL(CP(MCBSP4_CLKX), (IDIS | PTD | DIS | M4)); /*GPIO_152*/
-	MUX_VAL(CP(MCBSP4_DR), (IDIS | PTD | DIS | M4)); /*GPIO_153*/
-
-	MUX_VAL(CP(MCBSP1_CLKR), (IEN  | PTD | DIS | M0)); /*MCBSP1_CLKR*/
-	MUX_VAL(CP(MCBSP1_FSR), (IDIS | PTU | EN  | M0)); /*MCBSP1_FSR*/
-	MUX_VAL(CP(MCBSP1_DX), (IDIS | PTD | DIS | M0)); /*MCBSP1_DX*/
-	MUX_VAL(CP(MCBSP1_DR), (IEN  | PTD | DIS | M0)); /*MCBSP1_DR*/
-	MUX_VAL(CP(MCBSP_CLKS), (IEN  | PTU | DIS | M0)); /*MCBSP_CLKS*/
-	MUX_VAL(CP(MCBSP1_FSX), (IEN  | PTD | DIS | M0)); /*MCBSP1_FSX*/
-	MUX_VAL(CP(MCBSP1_CLKX), (IEN  | PTD | DIS | M0)); /*MCBSP1_CLKX*/
-
-	MUX_VAL(CP(UART3_CTS_RCTX), (IEN  | PTD | EN  | M0)); /*UART3_CTS_*/
-	MUX_VAL(CP(UART3_RTS_SD),  (IDIS | PTD | DIS | M0)); /*UART3_RTS_SD */
-	MUX_VAL(CP(UART3_RX_IRRX), (IEN  | PTD | DIS | M0)); /*UART3_RX_IRRX*/
-	MUX_VAL(CP(UART3_TX_IRTX), (IDIS | PTD | DIS | M0)); /*UART3_TX_IRTX*/
-
-	MUX_VAL(CP(HSUSB0_CLK), (IEN  | PTD | DIS | M0)); /*HSUSB0_CLK*/
-	MUX_VAL(CP(HSUSB0_STP), (IDIS | PTU | EN  | M0)); /*HSUSB0_STP*/
-	MUX_VAL(CP(HSUSB0_DIR), (IEN  | PTD | DIS | M0)); /*HSUSB0_DIR*/
-	MUX_VAL(CP(HSUSB0_NXT), (IEN  | PTD | DIS | M0)); /*HSUSB0_NXT*/
-	MUX_VAL(CP(HSUSB0_DATA0), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA0*/
-	MUX_VAL(CP(HSUSB0_DATA1), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA1*/
-	MUX_VAL(CP(HSUSB0_DATA2), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA2*/
-	MUX_VAL(CP(HSUSB0_DATA3), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA3*/
-	MUX_VAL(CP(HSUSB0_DATA4), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA4*/
-	MUX_VAL(CP(HSUSB0_DATA5), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA5*/
-	MUX_VAL(CP(HSUSB0_DATA6), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA6*/
-	MUX_VAL(CP(HSUSB0_DATA7), (IEN  | PTD | DIS | M0)); /*HSUSB0_DATA7*/
-
-	MUX_VAL(CP(I2C1_SCL), (IEN  | EN  | M0)); /*I2C1_SCL*/
-	MUX_VAL(CP(I2C1_SDA), (IEN  | EN  | M0)); /*I2C1_SDA*/
-
-	MUX_VAL(CP(I2C2_SCL), (IEN  | EN  | M0)); /*I2C2_SCL*/
-	MUX_VAL(CP(I2C2_SDA), (IEN  | EN  | M0)); /*I2C2_SDA*/
-
-	MUX_VAL(CP(I2C3_SCL), (IEN  | EN  | M0)); /*I2C3_SCL*/
-	MUX_VAL(CP(I2C3_SDA), (IEN  | EN  | M0)); /*I2C3_SDA*/
-
-	MUX_VAL(CP(I2C4_SCL), (IEN  | EN  | M0)); /*I2C4_SCL*/
-	MUX_VAL(CP(I2C4_SDA), (IEN  | EN  | M0)); /*I2C4_SDA*/
-
-	MUX_VAL(CP(HDQ_SIO), (IEN  | PTU | EN  | M0)); /*HDQ_SIO*/
-
-	MUX_VAL(CP(MCSPI1_CLK), (IEN  | PTD | DIS | M0)); /*McSPI1_CLK*/
-	MUX_VAL(CP(MCSPI1_SIMO), (IEN  | PTD | DIS | M0)); /*McSPI1_SIMO  */
-	MUX_VAL(CP(MCSPI1_SOMI), (IEN  | PTD | DIS | M0)); /*McSPI1_SOMI  */
-	MUX_VAL(CP(MCSPI1_CS0), (IEN  | PTD | EN  | M0)); /*McSPI1_CS0*/
-	MUX_VAL(CP(MCSPI1_CS1), (IEN  | PTD | EN  | M4)); /*GPIO_175*/
-	MUX_VAL(CP(MCSPI1_CS2), (IEN  | PTU | DIS | M4)); /*GPIO_176*/
-	MUX_VAL(CP(MCSPI1_CS3), (IEN  | PTD | EN  | M0)); /*McSPI1_CS3*/
-
-	MUX_VAL(CP(MCSPI2_CLK), (IEN  | PTD | DIS | M0)); /*McSPI2_CLK*/
-	MUX_VAL(CP(MCSPI2_SIMO), (IEN  | PTD | DIS | M0)); /*McSPI2_SIMO*/
-	MUX_VAL(CP(MCSPI2_SOMI), (IEN  | PTD | DIS | M0)); /*McSPI2_SOMI*/
-	MUX_VAL(CP(MCSPI2_CS0),  (IEN  | PTD | EN  | M0)); /*McSPI2_CS0*/
-	MUX_VAL(CP(MCSPI2_CS1),  (IEN  | PTD | EN  | M0)); /*McSPI2_CS1*/
-
-	MUX_VAL(CP(SYS_32K), (IEN  | PTD | DIS | M0)); /*SYS_32K*/
-	MUX_VAL(CP(SYS_CLKREQ), (IEN  | PTD | DIS | M0)); /*SYS_CLKREQ*/
-	MUX_VAL(CP(SYS_NIRQ), (IEN  | PTU | EN  | M0)); /*SYS_nIRQ*/
-	MUX_VAL(CP(SYS_BOOT0), (IEN  | PTD | DIS | M4)); /*GPIO_2*/
-	MUX_VAL(CP(SYS_BOOT1), (IEN  | PTD | DIS | M4)); /*GPIO_3 */
-	MUX_VAL(CP(SYS_BOOT2), (IEN  | PTD | DIS | M4)); /*GPIO_4*/
-	MUX_VAL(CP(SYS_BOOT3), (IEN  | PTD | DIS | M4)); /*GPIO_5*/
-	MUX_VAL(CP(SYS_BOOT4), (IEN  | PTD | DIS | M4)); /*GPIO_6*/
-	MUX_VAL(CP(SYS_BOOT5), (IEN  | PTD | DIS | M4)); /*GPIO_7*/
-
-	MUX_VAL(CP(SYS_OFF_MODE), (IEN  | PTD | DIS | M0)); /*SYS_OFF_MODE*/
-	MUX_VAL(CP(SYS_CLKOUT1), (IEN  | PTD | DIS | M0)); /*SYS_CLKOUT1*/
-	MUX_VAL(CP(SYS_CLKOUT2), (IEN  | PTU | EN  | M0)); /*SYS_CLKOUT2*/
-
 	MUX_VAL(CP(JTAG_TCK), (IEN  | PTD | DIS | M0)); /*JTAG_TCK*/
 	MUX_VAL(CP(JTAG_TMS), (IEN  | PTD | DIS | M0)); /*JTAG_TMS*/
 	MUX_VAL(CP(JTAG_TDI), (IEN  | PTD | DIS | M0)); /*JTAG_TDI*/
diff --git a/board/seeed/linkit-smart-7688/Kconfig b/board/seeed/linkit-smart-7688/Kconfig
new file mode 100644
index 0000000..a9d6328
--- /dev/null
+++ b/board/seeed/linkit-smart-7688/Kconfig
@@ -0,0 +1,12 @@
+if BOARD_LINKIT_SMART_7688
+
+config SYS_BOARD
+	default "linkit-smart-7688"
+
+config SYS_VENDOR
+	default "seeed"
+
+config SYS_CONFIG_NAME
+	default "linkit-smart-7688"
+
+endif
diff --git a/board/seeed/linkit-smart-7688/MAINTAINERS b/board/seeed/linkit-smart-7688/MAINTAINERS
new file mode 100644
index 0000000..c3bbad4
--- /dev/null
+++ b/board/seeed/linkit-smart-7688/MAINTAINERS
@@ -0,0 +1,8 @@
+LINKIT_SMART_7688 BOARD
+M:	Stefan Roese <sr@denx.de>
+S:	Maintained
+F:	board/seeed/linkit-smart-7688
+F:	include/configs/linkit-smart-7688.h
+F:	configs/linkit-smart-7688_defconfig
+F:	configs/linkit-smart-7688_ram_defconfig
+F:	arch/mips/dts/linkit-smart-7688.dts
diff --git a/board/seeed/linkit-smart-7688/Makefile b/board/seeed/linkit-smart-7688/Makefile
new file mode 100644
index 0000000..70cd7a8
--- /dev/null
+++ b/board/seeed/linkit-smart-7688/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0+
+
+obj-y += board.o
diff --git a/board/seeed/linkit-smart-7688/board.c b/board/seeed/linkit-smart-7688/board.c
new file mode 100644
index 0000000..a28abc0
--- /dev/null
+++ b/board/seeed/linkit-smart-7688/board.c
@@ -0,0 +1,26 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#define MT76XX_GPIO1_MODE	0xb0000060
+
+void board_debug_uart_init(void)
+{
+	/* Select UART2 mode instead of GPIO mode (default) */
+	clrbits_le32((void __iomem *)MT76XX_GPIO1_MODE, GENMASK(27, 26));
+}
+
+int board_early_init_f(void)
+{
+	/*
+	 * The pin muxing of UART2 also needs to be done, if debug uart
+	 * is not enabled. So we need to call this function here as well.
+	 */
+	board_debug_uart_init();
+
+	return 0;
+}
diff --git a/board/st/stm32mp1/stm32mp1.c b/board/st/stm32mp1/stm32mp1.c
index bfc8ab6..54feca0 100644
--- a/board/st/stm32mp1/stm32mp1.c
+++ b/board/st/stm32mp1/stm32mp1.c
@@ -5,13 +5,181 @@
 #include <config.h>
 #include <common.h>
 #include <led.h>
+#include <clk.h>
+#include <dm.h>
+#include <generic-phy.h>
+#include <phy.h>
+#include <reset.h>
+#include <usb.h>
 #include <asm/arch/stm32.h>
+#include <asm/io.h>
+#include <power/regulator.h>
+#include <usb/dwc2_udc.h>
 
 /*
  * Get a global data pointer
  */
 DECLARE_GLOBAL_DATA_PTR;
 
+#define STM32MP_GUSBCFG 0x40002407
+
+#define STM32MP_GGPIO 0x38
+#define STM32MP_GGPIO_VBUS_SENSING BIT(21)
+
+static struct dwc2_plat_otg_data stm32mp_otg_data = {
+	.usb_gusbcfg = STM32MP_GUSBCFG,
+};
+
+static struct reset_ctl usbotg_reset;
+
+int board_usb_init(int index, enum usb_init_type init)
+{
+	struct fdtdec_phandle_args args;
+	struct udevice *dev;
+	const void *blob = gd->fdt_blob;
+	struct clk clk;
+	struct phy phy;
+	int node;
+	int phy_provider;
+	int ret;
+
+	/* find the usb otg node */
+	node = fdt_node_offset_by_compatible(blob, -1, "snps,dwc2");
+	if (node < 0) {
+		debug("Not found usb_otg device\n");
+		return -ENODEV;
+	}
+
+	if (!fdtdec_get_is_enabled(blob, node)) {
+		debug("stm32 usbotg is disabled in the device tree\n");
+		return -ENODEV;
+	}
+
+	/* Enable clock */
+	ret = fdtdec_parse_phandle_with_args(blob, node, "clocks",
+					     "#clock-cells", 0, 0, &args);
+	if (ret) {
+		debug("usbotg has no clocks defined in the device tree\n");
+		return ret;
+	}
+
+	ret = uclass_get_device_by_of_offset(UCLASS_CLK, args.node, &dev);
+	if (ret)
+		return ret;
+
+	if (args.args_count != 1) {
+		debug("Can't find clock ID in the device tree\n");
+		return -ENODATA;
+	}
+
+	clk.dev = dev;
+	clk.id = args.args[0];
+
+	ret = clk_enable(&clk);
+	if (ret) {
+		debug("Failed to enable usbotg clock\n");
+		return ret;
+	}
+
+	/* Reset */
+	ret = fdtdec_parse_phandle_with_args(blob, node, "resets",
+					     "#reset-cells", 0, 0, &args);
+	if (ret) {
+		debug("usbotg has no resets defined in the device tree\n");
+		goto clk_err;
+	}
+
+	ret = uclass_get_device_by_of_offset(UCLASS_RESET, args.node, &dev);
+	if (ret || args.args_count != 1)
+		goto clk_err;
+
+	usbotg_reset.dev = dev;
+	usbotg_reset.id = args.args[0];
+
+	reset_assert(&usbotg_reset);
+	udelay(2);
+	reset_deassert(&usbotg_reset);
+
+	/* Get USB PHY */
+	ret = fdtdec_parse_phandle_with_args(blob, node, "phys",
+					     "#phy-cells", 0, 0, &args);
+	if (!ret) {
+		phy_provider = fdt_parent_offset(blob, args.node);
+		ret = uclass_get_device_by_of_offset(UCLASS_PHY,
+						     phy_provider, &dev);
+		if (ret)
+			goto clk_err;
+
+		phy.dev = dev;
+		phy.id = fdtdec_get_uint(blob, args.node, "reg", -1);
+
+		ret = generic_phy_power_on(&phy);
+		if (ret) {
+			debug("unable to power on the phy\n");
+			goto clk_err;
+		}
+
+		ret = generic_phy_init(&phy);
+		if (ret) {
+			debug("failed to init usb phy\n");
+			goto phy_power_err;
+		}
+	}
+
+	/* Parse and store data needed for gadget */
+	stm32mp_otg_data.regs_otg = fdtdec_get_addr(blob, node, "reg");
+	if (stm32mp_otg_data.regs_otg == FDT_ADDR_T_NONE) {
+		debug("usbotg: can't get base address\n");
+		ret = -ENODATA;
+		goto phy_init_err;
+	}
+
+	stm32mp_otg_data.rx_fifo_sz = fdtdec_get_int(blob, node,
+						     "g-rx-fifo-size", 0);
+	stm32mp_otg_data.np_tx_fifo_sz = fdtdec_get_int(blob, node,
+							"g-np-tx-fifo-size", 0);
+	stm32mp_otg_data.tx_fifo_sz = fdtdec_get_int(blob, node,
+						     "g-tx-fifo-size", 0);
+	/* Enable voltage level detector */
+	if (!(fdtdec_parse_phandle_with_args(blob, node, "usb33d-supply",
+					     NULL, 0, 0, &args))) {
+		if (!uclass_get_device_by_of_offset(UCLASS_REGULATOR,
+						    args.node, &dev)) {
+			ret = regulator_set_enable(dev, true);
+			if (ret) {
+				debug("Failed to enable usb33d\n");
+				goto phy_init_err;
+			}
+		}
+	}
+		/* Enable vbus sensing */
+	setbits_le32(stm32mp_otg_data.regs_otg + STM32MP_GGPIO,
+		     STM32MP_GGPIO_VBUS_SENSING);
+
+	return dwc2_udc_probe(&stm32mp_otg_data);
+
+phy_init_err:
+	generic_phy_exit(&phy);
+
+phy_power_err:
+	generic_phy_power_off(&phy);
+
+clk_err:
+	clk_disable(&clk);
+
+	return ret;
+}
+
+int board_usb_cleanup(int index, enum usb_init_type init)
+{
+	/* Reset usbotg */
+	reset_assert(&usbotg_reset);
+	udelay(2);
+	reset_deassert(&usbotg_reset);
+
+	return 0;
+}
+
 int board_late_init(void)
 {
 	return 0;
diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c
index a359d20..1384525 100644
--- a/board/ti/am335x/board.c
+++ b/board/ti/am335x/board.c
@@ -608,6 +608,84 @@
 };
 #endif
 
+#if defined(CONFIG_OF_BOARD_SETUP) && defined(CONFIG_OF_CONTROL) && \
+	defined(CONFIG_DM_ETH) && defined(CONFIG_DRIVER_TI_CPSW)
+
+#define MAX_CPSW_SLAVES	2
+
+/* At the moment, we do not want to stop booting for any failures here */
+int ft_board_setup(void *fdt, bd_t *bd)
+{
+	const char *slave_path, *enet_name;
+	int enetnode, slavenode, phynode;
+	struct udevice *ethdev;
+	char alias[16];
+	u32 phy_id[2];
+	int phy_addr;
+	int i, ret;
+
+	/* phy address fixup needed only on beagle bone family */
+	if (!board_is_beaglebonex())
+		goto done;
+
+	for (i = 0; i < MAX_CPSW_SLAVES; i++) {
+		sprintf(alias, "ethernet%d", i);
+
+		slave_path = fdt_get_alias(fdt, alias);
+		if (!slave_path)
+			continue;
+
+		slavenode = fdt_path_offset(fdt, slave_path);
+		if (slavenode < 0)
+			continue;
+
+		enetnode = fdt_parent_offset(fdt, slavenode);
+		enet_name = fdt_get_name(fdt, enetnode, NULL);
+
+		ethdev = eth_get_dev_by_name(enet_name);
+		if (!ethdev)
+			continue;
+
+		phy_addr = cpsw_get_slave_phy_addr(ethdev, i);
+
+		/* check for phy_id as well as phy-handle properties */
+		ret = fdtdec_get_int_array_count(fdt, slavenode, "phy_id",
+						 phy_id, 2);
+		if (ret == 2) {
+			if (phy_id[1] != phy_addr) {
+				printf("fixing up phy_id for %s, old: %d, new: %d\n",
+				       alias, phy_id[1], phy_addr);
+
+				phy_id[0] = cpu_to_fdt32(phy_id[0]);
+				phy_id[1] = cpu_to_fdt32(phy_addr);
+				do_fixup_by_path(fdt, slave_path, "phy_id",
+						 phy_id, sizeof(phy_id), 0);
+			}
+		} else {
+			phynode = fdtdec_lookup_phandle(fdt, slavenode,
+							"phy-handle");
+			if (phynode < 0)
+				continue;
+
+			ret = fdtdec_get_int(fdt, phynode, "reg", -ENOENT);
+			if (ret < 0)
+				continue;
+
+			if (ret != phy_addr) {
+				printf("fixing up phy-handle for %s, old: %d, new: %d\n",
+				       alias, ret, phy_addr);
+
+				fdt_setprop_u32(fdt, phynode, "reg",
+						cpu_to_fdt32(phy_addr));
+			}
+		}
+	}
+
+done:
+	return 0;
+}
+#endif
+
 /*
  * Basic board specific setup.  Pinmux has been handled already.
  */
diff --git a/board/xilinx/zynqmp/zynqmp.c b/board/xilinx/zynqmp/zynqmp.c
index 89fac6b..af91cde 100644
--- a/board/xilinx/zynqmp/zynqmp.c
+++ b/board/xilinx/zynqmp/zynqmp.c
@@ -281,7 +281,16 @@
 {
 	int ret = 0;
 #if !defined(CONFIG_SPL_BUILD) && defined(CONFIG_CLK_ZYNQMP)
-	zynqmp_pmufw_version();
+	u32 pm_api_version;
+
+	pm_api_version = zynqmp_pmufw_version();
+	printf("PMUFW:\tv%d.%d\n",
+	       pm_api_version >> ZYNQMP_PM_VERSION_MAJOR_SHIFT,
+	       pm_api_version & ZYNQMP_PM_VERSION_MINOR_MASK);
+
+	if (pm_api_version < ZYNQMP_PM_VERSION)
+		panic("PMUFW version error. Expected: v%d.%d\n",
+		      ZYNQMP_PM_VERSION_MAJOR, ZYNQMP_PM_VERSION_MINOR);
 #endif
 
 #if defined(CONFIG_ZYNQMP_PSU_INIT_ENABLED)
diff --git a/cmd/Kconfig b/cmd/Kconfig
index 13d4c99..ae697fc 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -304,11 +304,6 @@
 	help
 	  Extract a part of a multi-image.
 
-config CMD_POWEROFF
-	bool "poweroff"
-	help
-	  Poweroff/Shutdown the system
-
 config CMD_SPL
 	bool "spl export - Export boot information for Falcon boot"
 	depends on SPL
@@ -832,6 +827,13 @@
 	help
 	  I2C support.
 
+config CMD_W1
+	depends on W1
+	default y if W1
+	bool "w1 - Support for Dallas 1-Wire protocol"
+	help
+	  Dallas 1-wire protocol support
+
 config CMD_LOADB
 	bool "loadb"
 	default y
@@ -937,6 +939,11 @@
 	  about 1990. These devices are typically removable memory or network
 	  cards using a standard 68-pin connector.
 
+config CMD_POWEROFF
+	bool "poweroff"
+	help
+	  Poweroff/Shutdown the system
+
 config CMD_READ
 	bool "read - Read binary data from a partition"
 	help
@@ -1338,6 +1345,12 @@
 	help
 	  Enable the "icache" and "dcache" commands
 
+config CMD_CONITRACE
+	bool "conitrace - trace console input codes"
+	help
+	  Enable the 'conitrace' command which displays the codes received
+	  from the console input as hexadecimal numbers.
+
 config CMD_DISPLAY
 	bool "Enable the 'display' command, for character displays"
 	help
diff --git a/cmd/Makefile b/cmd/Makefile
index a61fab6..9e311a7 100644
--- a/cmd/Makefile
+++ b/cmd/Makefile
@@ -34,6 +34,7 @@
 obj-$(CONFIG_CMD_CBFS) += cbfs.o
 obj-$(CONFIG_CMD_CLK) += clk.o
 obj-$(CONFIG_CMD_CONFIG) += config.o
+obj-$(CONFIG_CMD_CONITRACE) += conitrace.o
 obj-$(CONFIG_CMD_CONSOLE) += console.o
 obj-$(CONFIG_CMD_CPU) += cpu.o
 obj-$(CONFIG_DATAFLASH_MMC_SELECT) += dataflash_mmc_mux.o
@@ -145,6 +146,7 @@
 obj-$(CONFIG_CMD_XIMG) += ximg.o
 obj-$(CONFIG_CMD_YAFFS2) += yaffs2.o
 obj-$(CONFIG_CMD_SPL) += spl.o
+obj-$(CONFIG_CMD_W1) += w1.o
 obj-$(CONFIG_CMD_ZIP) += zip.o
 obj-$(CONFIG_CMD_ZFS) += zfs.o
 
diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index b60c151..82d755c 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -49,6 +49,11 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
+	/* Initialize root node */
+	ret = efi_root_node_register();
+	if (ret != EFI_SUCCESS)
+		goto out;
+
 	/* Initialize EFI driver uclass */
 	ret = efi_driver_init();
 	if (ret != EFI_SUCCESS)
@@ -116,32 +121,47 @@
 {
 	size_t size;
 	const char *env = env_get(env_var);
+	u16 *pos;
 
 	loaded_image_info->load_options = NULL;
 	loaded_image_info->load_options_size = 0;
 	if (!env)
 		return;
-	size = strlen(env) + 1;
+	size = utf8_utf16_strlen(env) + 1;
 	loaded_image_info->load_options = calloc(size, sizeof(u16));
 	if (!loaded_image_info->load_options) {
 		printf("ERROR: Out of memory\n");
 		return;
 	}
-	utf8_to_utf16(loaded_image_info->load_options, (u8 *)env, size);
+	pos = loaded_image_info->load_options;
+	utf8_utf16_strcpy(&pos, env);
 	loaded_image_info->load_options_size = size * 2;
 }
 
-static void *copy_fdt(void *fdt)
+/**
+ * copy_fdt() - Copy the device tree to a new location available to EFI
+ *
+ * The FDT is relocated into a suitable location within the EFI memory map.
+ * An additional 12KB is added to the space in case the device tree needs to be
+ * expanded later with fdt_open_into().
+ *
+ * @fdt_addr: On entry, address of start of FDT. On exit, address of relocated
+ *	FDT start
+ * @fdt_sizep: Returns new size of FDT, including
+ * @return new relocated address of FDT
+ */
+static efi_status_t copy_fdt(ulong *fdt_addrp, ulong *fdt_sizep)
 {
-	u64 fdt_size = fdt_totalsize(fdt);
 	unsigned long fdt_ram_start = -1L, fdt_pages;
+	efi_status_t ret = 0;
+	void *fdt, *new_fdt;
 	u64 new_fdt_addr;
-	void *new_fdt;
+	uint fdt_size;
 	int i;
 
-        for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
-                u64 ram_start = gd->bd->bi_dram[i].start;
-                u64 ram_size = gd->bd->bi_dram[i].size;
+	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
+		u64 ram_start = gd->bd->bi_dram[i].start;
+		u64 ram_size = gd->bd->bi_dram[i].size;
 
 		if (!ram_size)
 			continue;
@@ -154,30 +174,37 @@
 	 * Give us at least 4KB of breathing room in case the device tree needs
 	 * to be expanded later. Round up to the nearest EFI page boundary.
 	 */
-	fdt_size += 4096;
+	fdt = map_sysmem(*fdt_addrp, 0);
+	fdt_size = fdt_totalsize(fdt);
+	fdt_size += 4096 * 3;
 	fdt_size = ALIGN(fdt_size + EFI_PAGE_SIZE - 1, EFI_PAGE_SIZE);
 	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
 
-	/* Safe fdt location is at 128MB */
-	new_fdt_addr = fdt_ram_start + (128 * 1024 * 1024) + fdt_size;
-	if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
-			       EFI_RUNTIME_SERVICES_DATA, fdt_pages,
-			       &new_fdt_addr) != EFI_SUCCESS) {
+	/* Safe fdt location is at 127MB */
+	new_fdt_addr = fdt_ram_start + (127 * 1024 * 1024) + fdt_size;
+	ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
+				 EFI_RUNTIME_SERVICES_DATA, fdt_pages,
+				 &new_fdt_addr);
+	if (ret != EFI_SUCCESS) {
 		/* If we can't put it there, put it somewhere */
 		new_fdt_addr = (ulong)memalign(EFI_PAGE_SIZE, fdt_size);
-		if (efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
-				       EFI_RUNTIME_SERVICES_DATA, fdt_pages,
-				       &new_fdt_addr) != EFI_SUCCESS) {
+		ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
+					 EFI_RUNTIME_SERVICES_DATA, fdt_pages,
+					 &new_fdt_addr);
+		if (ret != EFI_SUCCESS) {
 			printf("ERROR: Failed to reserve space for FDT\n");
-			return NULL;
+			goto done;
 		}
 	}
 
-	new_fdt = (void*)(ulong)new_fdt_addr;
+	new_fdt = map_sysmem(new_fdt_addr, fdt_size);
 	memcpy(new_fdt, fdt, fdt_totalsize(fdt));
 	fdt_set_totalsize(new_fdt, fdt_size);
 
-	return new_fdt;
+	*fdt_addrp = new_fdt_addr;
+	*fdt_sizep = fdt_size;
+done:
+	return ret;
 }
 
 static efi_status_t efi_do_enter(
@@ -250,22 +277,27 @@
 	}
 }
 
-static efi_status_t efi_install_fdt(void *fdt)
+static efi_status_t efi_install_fdt(ulong fdt_addr)
 {
 	bootm_headers_t img = { 0 };
-	ulong fdt_pages, fdt_size, fdt_start, fdt_end;
+	ulong fdt_pages, fdt_size, fdt_start;
 	efi_status_t ret;
+	void *fdt;
 
+	fdt = map_sysmem(fdt_addr, 0);
 	if (fdt_check_header(fdt)) {
 		printf("ERROR: invalid device tree\n");
 		return EFI_INVALID_PARAMETER;
 	}
 
 	/* Prepare fdt for payload */
-	fdt = copy_fdt(fdt);
-	if (!fdt)
-		return EFI_OUT_OF_RESOURCES;
+	ret = copy_fdt(&fdt_addr, &fdt_size);
+	if (ret)
+		return ret;
 
+	unmap_sysmem(fdt);
+	fdt = map_sysmem(fdt_addr, 0);
+	fdt_size = fdt_totalsize(fdt);
 	if (image_setup_libfdt(&img, fdt, 0, NULL)) {
 		printf("ERROR: failed to process device tree\n");
 		return EFI_LOAD_ERROR;
@@ -279,30 +311,35 @@
 		return EFI_OUT_OF_RESOURCES;
 
 	/* And reserve the space in the memory map */
-	fdt_start = ((ulong)fdt) & ~EFI_PAGE_MASK;
-	fdt_end = ((ulong)fdt) + fdt_totalsize(fdt);
-	fdt_size = (fdt_end - fdt_start) + EFI_PAGE_MASK;
+	fdt_start = fdt_addr;
 	fdt_pages = fdt_size >> EFI_PAGE_SHIFT;
-	/* Give a bootloader the chance to modify the device tree */
-	fdt_pages += 2;
+
 	ret = efi_add_memory_map(fdt_start, fdt_pages,
 				 EFI_BOOT_SERVICES_DATA, true);
+
 	return ret;
 }
 
-/*
- * Load an EFI payload into a newly allocated piece of memory, register all
- * EFI objects it would want to access and jump to it.
+/**
+ * do_bootefi_exec() - execute EFI binary
+ *
+ * @efi:		address of the binary
+ * @device_path:	path of the device from which the binary was loaded
+ * @image_path:		device path of the binary
+ * Return:		status code
+ *
+ * Load the EFI binary into a newly assigned memory unwinding the relocation
+ * information, install the loaded image protocol, and call the binary.
  */
 static efi_status_t do_bootefi_exec(void *efi,
 				    struct efi_device_path *device_path,
 				    struct efi_device_path *image_path)
 {
-	struct efi_loaded_image loaded_image_info = {};
-	struct efi_object loaded_image_info_obj = {};
-	struct efi_object mem_obj = {};
+	efi_handle_t mem_handle = NULL;
 	struct efi_device_path *memdp = NULL;
 	efi_status_t ret;
+	struct efi_loaded_image_obj *image_handle = NULL;
+	struct efi_loaded_image *loaded_image_info = NULL;
 
 	EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
 				     struct efi_system_table *st);
@@ -310,16 +347,21 @@
 	/*
 	 * Special case for efi payload not loaded from disk, such as
 	 * 'bootefi hello' or for example payload loaded directly into
-	 * memory via jtag/etc:
+	 * memory via jtag, etc:
 	 */
 	if (!device_path && !image_path) {
 		printf("WARNING: using memory device/image path, this may confuse some payloads!\n");
 		/* actual addresses filled in after efi_load_pe() */
 		memdp = efi_dp_from_mem(0, 0, 0);
 		device_path = image_path = memdp;
-		efi_add_handle(&mem_obj);
-
-		ret = efi_add_protocol(mem_obj.handle, &efi_guid_device_path,
+		/*
+		 * Grub expects that the device path of the loaded image is
+		 * installed on a handle.
+		 */
+		ret = efi_create_handle(&mem_handle);
+		if (ret != EFI_SUCCESS)
+			goto exit;
+		ret = efi_add_protocol(mem_handle, &efi_guid_device_path,
 				       device_path);
 		if (ret != EFI_SUCCESS)
 			goto exit;
@@ -327,8 +369,10 @@
 		assert(device_path && image_path);
 	}
 
-	efi_setup_loaded_image(&loaded_image_info, &loaded_image_info_obj,
-			       device_path, image_path);
+	ret = efi_setup_loaded_image(device_path, image_path, &image_handle,
+				     &loaded_image_info);
+	if (ret != EFI_SUCCESS)
+		goto exit;
 
 	/*
 	 * gd lives in a fixed register which may get clobbered while we execute
@@ -337,9 +381,9 @@
 	efi_save_gd();
 
 	/* Transfer environment variable bootargs as load options */
-	set_load_options(&loaded_image_info, "bootargs");
+	set_load_options(loaded_image_info, "bootargs");
 	/* Load the EFI payload */
-	entry = efi_load_pe(efi, &loaded_image_info);
+	entry = efi_load_pe(image_handle, efi, loaded_image_info);
 	if (!entry) {
 		ret = EFI_LOAD_ERROR;
 		goto exit;
@@ -347,10 +391,10 @@
 
 	if (memdp) {
 		struct efi_device_path_memory *mdp = (void *)memdp;
-		mdp->memory_type = loaded_image_info.image_code_type;
-		mdp->start_address = (uintptr_t)loaded_image_info.image_base;
+		mdp->memory_type = loaded_image_info->image_code_type;
+		mdp->start_address = (uintptr_t)loaded_image_info->image_base;
 		mdp->end_address = mdp->start_address +
-				loaded_image_info.image_size;
+				loaded_image_info->image_size;
 	}
 
 	/* we don't support much: */
@@ -360,8 +404,8 @@
 	/* Call our payload! */
 	debug("%s:%d Jumping to 0x%lx\n", __func__, __LINE__, (long)entry);
 
-	if (setjmp(&loaded_image_info.exit_jmp)) {
-		ret = loaded_image_info.exit_status;
+	if (setjmp(&image_handle->exit_jmp)) {
+		ret = image_handle->exit_status;
 		goto exit;
 	}
 
@@ -373,7 +417,7 @@
 
 		/* Move into EL2 and keep running there */
 		armv8_switch_to_el2((ulong)entry,
-				    (ulong)&loaded_image_info_obj.handle,
+				    (ulong)image_handle,
 				    (ulong)&systab, 0, (ulong)efi_run_in_el2,
 				    ES_TO_AARCH64);
 
@@ -390,7 +434,7 @@
 		secure_ram_addr(_do_nonsec_entry)(
 					efi_run_in_hyp,
 					(uintptr_t)entry,
-					(uintptr_t)loaded_image_info_obj.handle,
+					(uintptr_t)image_handle,
 					(uintptr_t)&systab);
 
 		/* Should never reach here, efi exits with longjmp */
@@ -398,13 +442,14 @@
 	}
 #endif
 
-	ret = efi_do_enter(loaded_image_info_obj.handle, &systab, entry);
+	ret = efi_do_enter(image_handle, &systab, entry);
 
 exit:
 	/* image has returned, loaded-image obj goes *poof*: */
-	list_del(&loaded_image_info_obj.link);
-	if (mem_obj.handle)
-		list_del(&mem_obj.link);
+	if (image_handle)
+		efi_delete_handle(&image_handle->parent);
+	if (mem_handle)
+		efi_delete_handle(mem_handle);
 
 	return ret;
 }
@@ -443,7 +488,6 @@
 	char *saddr;
 	efi_status_t r;
 	unsigned long fdt_addr;
-	void *fdt;
 
 	/* Allow unaligned memory access */
 	allow_unaligned();
@@ -464,8 +508,7 @@
 		if (!fdt_addr && *argv[2] != '0')
 			return CMD_RET_USAGE;
 		/* Install device tree */
-		fdt = map_sysmem(fdt_addr, 0);
-		r = efi_install_fdt(fdt);
+		r = efi_install_fdt(fdt_addr);
 		if (r != EFI_SUCCESS) {
 			printf("ERROR: failed to install device tree\n");
 			return CMD_RET_FAILURE;
@@ -489,8 +532,8 @@
 #endif
 #ifdef CONFIG_CMD_BOOTEFI_SELFTEST
 	if (!strcmp(argv[1], "selftest")) {
-		struct efi_loaded_image loaded_image_info = {};
-		struct efi_object loaded_image_info_obj = {};
+		struct efi_loaded_image_obj *image_handle;
+		struct efi_loaded_image *loaded_image_info;
 
 		/* Construct a dummy device path. */
 		bootefi_device_path = efi_dp_from_mem(EFI_RESERVED_MEMORY_TYPE,
@@ -498,9 +541,12 @@
 						      (uintptr_t)&efi_selftest);
 		bootefi_image_path = efi_dp_from_file(NULL, 0, "\\selftest");
 
-		efi_setup_loaded_image(&loaded_image_info,
-				       &loaded_image_info_obj,
-				       bootefi_device_path, bootefi_image_path);
+		r = efi_setup_loaded_image(bootefi_device_path,
+					   bootefi_image_path, &image_handle,
+					   &loaded_image_info);
+		if (r != EFI_SUCCESS)
+			return CMD_RET_FAILURE;
+
 		/*
 		 * gd lives in a fixed register which may get clobbered while we
 		 * execute the payload. So save it here and restore it on every
@@ -508,12 +554,12 @@
 		 */
 		efi_save_gd();
 		/* Transfer environment variable efi_selftest as load options */
-		set_load_options(&loaded_image_info, "efi_selftest");
+		set_load_options(loaded_image_info, "efi_selftest");
 		/* Execute the test */
-		r = efi_selftest(loaded_image_info_obj.handle, &systab);
+		r = efi_selftest(image_handle, &systab);
 		efi_restore_gd();
-		free(loaded_image_info.load_options);
-		list_del(&loaded_image_info_obj.link);
+		free(loaded_image_info->load_options);
+		efi_delete_handle(&image_handle->parent);
 		return r != EFI_SUCCESS;
 	} else
 #endif
@@ -575,6 +621,13 @@
 	char filename[32] = { 0 }; /* dp->str is u16[32] long */
 	char *s;
 
+	/* efi_set_bootdev is typically called repeatedly, recover memory */
+	efi_free_pool(bootefi_device_path);
+	efi_free_pool(bootefi_image_path);
+	/* If blk_get_device_part_str fails, avoid duplicate free. */
+	bootefi_device_path = NULL;
+	bootefi_image_path = NULL;
+
 	if (strcmp(dev, "Net")) {
 		struct blk_desc *desc;
 		disk_partition_t fs_partition;
diff --git a/cmd/conitrace.c b/cmd/conitrace.c
new file mode 100644
index 0000000..85c5422
--- /dev/null
+++ b/cmd/conitrace.c
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * The 'conitrace' command prints the codes received from the console input as
+ * hexadecimal numbers.
+ *
+ * Copyright (c) 2018, Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+#include <common.h>
+#include <command.h>
+
+static int do_conitrace(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	bool first = true;
+
+	printf("Waiting for your input\n");
+	printf("To terminate type 'x'\n");
+
+	/* Empty input buffer */
+	while (tstc())
+		getc();
+
+	for (;;) {
+		int c = getc();
+
+		if (first && (c == 'x' || c == 'X'))
+			break;
+
+		printf("%02x ", c);
+		first = false;
+
+		/* 1 ms delay - serves to detect separate keystrokes */
+		udelay(1000);
+		if (!tstc()) {
+			printf("\n");
+			first = true;
+		}
+	}
+
+	return CMD_RET_SUCCESS;
+}
+
+#ifdef CONFIG_SYS_LONGHELP
+static char conitrace_help_text[] = "";
+#endif
+
+U_BOOT_CMD_COMPLETE(
+	conitrace, 2, 0, do_conitrace,
+	"trace console input",
+	conitrace_help_text, NULL
+);
diff --git a/cmd/fat.c b/cmd/fat.c
index 03de5d1..4b9a7ea 100644
--- a/cmd/fat.c
+++ b/cmd/fat.c
@@ -104,6 +104,7 @@
 	int ret;
 	unsigned long addr;
 	unsigned long count;
+	long offset;
 	struct blk_desc *dev_desc = NULL;
 	disk_partition_t info;
 	int dev = 0;
@@ -126,9 +127,11 @@
 	}
 	addr = simple_strtoul(argv[3], NULL, 16);
 	count = (argc <= 5) ? 0 : simple_strtoul(argv[5], NULL, 16);
+	/* offset should be a hex, but "-1" is allowed */
+	offset = (argc <= 6) ? 0 : simple_strtol(argv[6], NULL, 16);
 
 	buf = map_sysmem(addr, count);
-	ret = file_fat_write(argv[4], buf, 0, count, &size);
+	ret = file_fat_write(argv[4], buf, offset, count, &size);
 	unmap_sysmem(buf);
 	if (ret < 0) {
 		printf("\n** Unable to write \"%s\" from %s %d:%d **\n",
@@ -142,10 +145,35 @@
 }
 
 U_BOOT_CMD(
-	fatwrite,	6,	0,	do_fat_fswrite,
+	fatwrite,	7,	0,	do_fat_fswrite,
 	"write file into a dos filesystem",
-	"<interface> <dev[:part]> <addr> <filename> [<bytes>]\n"
+	"<interface> <dev[:part]> <addr> <filename> [<bytes> [<offset>]]\n"
 	"    - write file 'filename' from the address 'addr' in RAM\n"
 	"      to 'dev' on 'interface'"
 );
+
+static int do_fat_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	return do_rm(cmdtp, flag, argc, argv, FS_TYPE_FAT);
+}
+
+U_BOOT_CMD(
+	fatrm,	4,	1,	do_fat_rm,
+	"delete a file",
+	"<interface> [<dev[:part]>] <filename>\n"
+	"    - delete a file from 'dev' on 'interface'"
+);
+
+static int do_fat_mkdir(cmd_tbl_t *cmdtp, int flag, int argc,
+			char * const argv[])
+{
+	return do_mkdir(cmdtp, flag, argc, argv, FS_TYPE_FAT);
+}
+
+U_BOOT_CMD(
+	fatmkdir,	4,	1,	do_fat_mkdir,
+	"create a directory",
+	"<interface> [<dev[:part]>] <directory>\n"
+	"    - create a directory in 'dev' on 'interface'"
+);
 #endif
diff --git a/cmd/ubi.c b/cmd/ubi.c
index 913f0f7..0fa7553 100644
--- a/cmd/ubi.c
+++ b/cmd/ubi.c
@@ -47,8 +47,7 @@
 static struct selected_dev ubi_dev;
 
 #ifdef CONFIG_CMD_UBIFS
-int ubifs_is_mounted(void);
-void cmd_ubifs_umount(void);
+#include <ubifs_uboot.h>
 #endif
 
 static void display_volume_info(struct ubi_device *ubi)
diff --git a/cmd/ubifs.c b/cmd/ubifs.c
index 11bab7a..e4000b7 100644
--- a/cmd/ubifs.c
+++ b/cmd/ubifs.c
@@ -19,16 +19,10 @@
 static int ubifs_initialized;
 static int ubifs_mounted;
 
-static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc,
-				char * const argv[])
+int cmd_ubifs_mount(char *vol_name)
 {
-	char *vol_name;
 	int ret;
 
-	if (argc != 2)
-		return CMD_RET_USAGE;
-
-	vol_name = argv[1];
 	debug("Using volume %s\n", vol_name);
 
 	if (ubifs_initialized == 0) {
@@ -42,19 +36,38 @@
 
 	ubifs_mounted = 1;
 
-	return 0;
+	return ret;
 }
+static int do_ubifs_mount(cmd_tbl_t *cmdtp, int flag, int argc,
+				char * const argv[])
+{
+	char *vol_name;
+
+	if (argc != 2)
+		return CMD_RET_USAGE;
+
+	vol_name = argv[1];
+
+	return cmd_ubifs_mount(vol_name);
+}
 
 int ubifs_is_mounted(void)
 {
 	return ubifs_mounted;
 }
 
-void cmd_ubifs_umount(void)
+int cmd_ubifs_umount(void)
 {
+	if (ubifs_initialized == 0) {
+		printf("No UBIFS volume mounted!\n");
+		return -1;
+	}
+
 	uboot_ubifs_umount();
 	ubifs_mounted = 0;
 	ubifs_initialized = 0;
+
+	return 0;
 }
 
 static int do_ubifs_umount(cmd_tbl_t *cmdtp, int flag, int argc,
@@ -63,14 +76,7 @@
 	if (argc != 1)
 		return CMD_RET_USAGE;
 
-	if (ubifs_initialized == 0) {
-		printf("No UBIFS volume mounted!\n");
-		return -1;
-	}
-
-	cmd_ubifs_umount();
-
-	return 0;
+	return cmd_ubifs_umount();
 }
 
 static int do_ubifs_ls(cmd_tbl_t *cmdtp, int flag, int argc,
diff --git a/cmd/w1.c b/cmd/w1.c
new file mode 100644
index 0000000..9c95fcf
--- /dev/null
+++ b/cmd/w1.c
@@ -0,0 +1,126 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ *
+ * (C) Copyright 2018
+ * Microchip Technology, Inc.
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ */
+#include <common.h>
+#include <command.h>
+#include <w1.h>
+#include <w1-eeprom.h>
+#include <dm/device-internal.h>
+
+static int w1_bus(void)
+{
+	struct udevice *bus, *dev;
+	int ret;
+
+	ret = w1_get_bus(0, &bus);
+	if (ret) {
+		printf("one wire interface not found\n");
+		return CMD_RET_FAILURE;
+	}
+	printf("Bus %d:\t%s", bus->seq, bus->name);
+	if (device_active(bus))
+		printf("  (active)");
+	printf("\n");
+
+	for (device_find_first_child(bus, &dev);
+	     dev;
+	     device_find_next_child(&dev)) {
+		ret = device_probe(dev);
+
+		printf("\t%s (%d) uclass %s : ", dev->name, dev->seq,
+		       dev->uclass->uc_drv->name);
+
+		if (ret)
+			printf("device error\n");
+		else
+			printf("family 0x%x\n", w1_get_device_family(dev));
+	}
+	return CMD_RET_SUCCESS;
+}
+
+static int w1_read(int argc, char *const argv[])
+{
+	int bus_n = 0, dev_n = 0, offset = 0, len = 512;
+	int i;
+	struct udevice *bus, *dev;
+	int ret;
+	u8 buf[512];
+
+	if (argc > 2)
+		bus_n = simple_strtoul(argv[2], NULL, 10);
+
+	if (argc > 3)
+		dev_n = simple_strtoul(argv[3], NULL, 10);
+
+	if (argc > 4)
+		offset = simple_strtoul(argv[4], NULL, 10);
+
+	if (argc > 5)
+		len = simple_strtoul(argv[5], NULL, 10);
+
+	if (len > 512) {
+		printf("len needs to be <= 512\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = w1_get_bus(bus_n, &bus);
+	if (ret) {
+		printf("one wire interface not found\n");
+		return CMD_RET_FAILURE;
+	}
+
+	for (device_find_first_child(bus, &dev), i = 0;
+	   dev && i <= dev_n;
+	   device_find_next_child(&dev), i++) {
+		ret = device_probe(dev);
+		if (!ret && i == dev_n)
+			break;
+	}
+
+	if (i != dev_n || ret || !dev) {
+		printf("invalid dev\n");
+		return CMD_RET_FAILURE;
+	}
+
+	if (strcmp(dev->uclass->uc_drv->name, "w1_eeprom")) {
+		printf("the device present on the interface is of unknown device class\n");
+		return CMD_RET_FAILURE;
+	}
+
+	ret = w1_eeprom_read_buf(dev, offset, (u8 *)buf, len);
+	if (ret) {
+		printf("error reading device %s\n", dev->name);
+		return CMD_RET_FAILURE;
+	}
+
+	for (i = 0; i < len; i++)
+		printf("%x", buf[i]);
+	printf("\n");
+
+	return CMD_RET_SUCCESS;
+}
+
+int do_w1(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[])
+{
+	if (argc < 2)
+		return CMD_RET_USAGE;
+
+	if (!strcmp(argv[1], "bus"))
+		return w1_bus();
+
+	if (!strcmp(argv[1], "read"))
+		return w1_read(argc, argv);
+
+	return CMD_RET_SUCCESS;
+}
+
+U_BOOT_CMD(w1, 6, 0, do_w1,
+	   "onewire interface utility commands",
+	   "bus - show onewire bus info (all)\n"
+	   "w1 read [<bus> [<dev> [offset [length]]]]"
+	   "    - read from onewire device 'dev' on onewire bus 'bus'"
+	   " starting from offset 'offset' and length 'length'\n"
+	   "      defaults: bus 0, dev 0, offset 0, length 512 bytes.");
diff --git a/common/Kconfig b/common/Kconfig
index 3030da4..41f27a1 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -259,6 +259,11 @@
 	  The buffer is allocated immediately after the malloc() region is
 	  ready.
 
+config DISABLE_CONSOLE
+	bool "Add functionality to disable console completely"
+	help
+		Disable console (in & out).
+
 config IDENT_STRING
 	string "Board specific string to be added to uboot version string"
 	help
@@ -557,7 +562,7 @@
 	  next reset.
 
 config BOARD_LATE_INIT
-	bool
+	bool "Execute Board late init"
 	help
 	  Sometimes board require some initialization code that might
 	  require once the actual init done, example saving board specific env,
diff --git a/common/bootm.c b/common/bootm.c
index e517d9f..8bf84eb 100644
--- a/common/bootm.c
+++ b/common/bootm.c
@@ -262,7 +262,7 @@
 		puts("Could not find a valid device tree\n");
 		return 1;
 	}
-	set_working_fdt_addr((ulong)images.ft_addr);
+	set_working_fdt_addr(map_to_sysmem(images.ft_addr));
 #endif
 
 #if IMAGE_ENABLE_FIT
diff --git a/common/image-fdt.c b/common/image-fdt.c
index 9b41f16..95748f0 100644
--- a/common/image-fdt.c
+++ b/common/image-fdt.c
@@ -193,7 +193,7 @@
 	*of_flat_tree = of_start;
 	*of_size = of_len;
 
-	set_working_fdt_addr((ulong)*of_flat_tree);
+	set_working_fdt_addr(map_to_sysmem(*of_flat_tree));
 	return 0;
 
 error:
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 19508c7..038f2b0 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -127,6 +127,11 @@
 	/* Nothing to do! */
 }
 
+__weak struct image_header *spl_get_load_buffer(ssize_t offset, size_t size)
+{
+	return (struct image_header *)(CONFIG_SYS_TEXT_BASE + offset);
+}
+
 void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
 {
 	ulong u_boot_pos = binman_sym(ulong, u_boot_any, image_pos);
diff --git a/common/spl/spl_ext.c b/common/spl/spl_ext.c
index fd30a61..fe05223 100644
--- a/common/spl/spl_ext.c
+++ b/common/spl/spl_ext.c
@@ -16,8 +16,7 @@
 	loff_t filelen, actlen;
 	disk_partition_t part_info = {};
 
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
-						sizeof(struct image_header));
+	header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
 
 	if (part_get_info(block_dev, partition, &part_info)) {
 		printf("spl: no partition table found\n");
diff --git a/common/spl/spl_fat.c b/common/spl/spl_fat.c
index 0403016..163e540 100644
--- a/common/spl/spl_fat.c
+++ b/common/spl/spl_fat.c
@@ -63,8 +63,7 @@
 	if (err)
 		goto end;
 
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
-						sizeof(struct image_header));
+	header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));
 
 	err = file_fat_read(filename, header, sizeof(struct image_header));
 	if (err <= 0)
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 9eabb1c..cb0cc52 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -257,10 +257,7 @@
 	board_fit_image_post_process(&src, &length);
 #endif
 
-	if (IS_ENABLED(CONFIG_SPL_OS_BOOT)	&&
-	    IS_ENABLED(CONFIG_SPL_GZIP)		&&
-	    image_comp == IH_COMP_GZIP		&&
-	    type == IH_TYPE_KERNEL) {
+	if (IS_ENABLED(CONFIG_SPL_GZIP) && image_comp == IH_COMP_GZIP) {
 		size = length;
 		if (gunzip((void *)load_addr, CONFIG_SYS_BOOTM_LEN,
 			   src, &size)) {
@@ -357,7 +354,7 @@
 	struct spl_image_info image_info;
 	int node = -1;
 	int images, ret;
-	int base_offset, align_len = ARCH_DMA_MINALIGN - 1;
+	int base_offset, hsize, align_len = ARCH_DMA_MINALIGN - 1;
 	int index = 0;
 
 	/*
@@ -386,8 +383,8 @@
 	 * For FIT with data embedded, data is loaded as part of FIT image.
 	 * For FIT with external data, data is not loaded in this step.
 	 */
-	fit = (void *)((CONFIG_SYS_TEXT_BASE - size - info->bl_len -
-			align_len) & ~align_len);
+	hsize = (size + info->bl_len + align_len) & ~align_len;
+	fit = spl_get_load_buffer(-hsize, hsize);
 	sectors = get_aligned_image_size(info, size, 0);
 	count = info->read(info, sector, sectors, fit);
 	debug("fit read sector %lx, sectors=%d, dst=%p, count=%lu\n",
diff --git a/common/spl/spl_mmc.c b/common/spl/spl_mmc.c
index 0b2f059..75c4159 100644
--- a/common/spl/spl_mmc.c
+++ b/common/spl/spl_mmc.c
@@ -55,13 +55,13 @@
 {
 	unsigned long count;
 	struct image_header *header;
+	struct blk_desc *bd = mmc_get_blk_desc(mmc);
 	int ret = 0;
 
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE -
-					 sizeof(struct image_header));
+	header = spl_get_load_buffer(-sizeof(*header), bd->blksz);
 
 	/* read image header to find the image size & load address */
-	count = blk_dread(mmc_get_blk_desc(mmc), sector, 1, header);
+	count = blk_dread(bd, sector, 1, header);
 	debug("hdr read sector %lx, count=%lu\n", sector, count);
 	if (count == 0) {
 		ret = -EIO;
diff --git a/common/spl/spl_nand.c b/common/spl/spl_nand.c
index 2722fd3..6eb190f 100644
--- a/common/spl/spl_nand.c
+++ b/common/spl/spl_nand.c
@@ -83,8 +83,8 @@
 #endif
 	nand_init();
 
-	/*use CONFIG_SYS_TEXT_BASE as temporary storage area */
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+	header = spl_get_load_buffer(0, sizeof(*header));
+
 #ifdef CONFIG_SPL_OS_BOOT
 	if (!spl_start_uboot()) {
 		/*
diff --git a/common/spl/spl_onenand.c b/common/spl/spl_onenand.c
index d323339..ee30f32 100644
--- a/common/spl/spl_onenand.c
+++ b/common/spl/spl_onenand.c
@@ -21,8 +21,7 @@
 
 	debug("spl: onenand\n");
 
-	/*use CONFIG_SYS_TEXT_BASE as temporary storage area */
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+	header = spl_get_load_buffer(0, CONFIG_SYS_ONENAND_PAGE_SIZE);
 	/* Load u-boot */
 	onenand_spl_load_image(CONFIG_SYS_ONENAND_U_BOOT_OFFS,
 		CONFIG_SYS_ONENAND_PAGE_SIZE, (void *)header);
diff --git a/common/spl/spl_ram.c b/common/spl/spl_ram.c
index e594bea..619b39a 100644
--- a/common/spl/spl_ram.c
+++ b/common/spl/spl_ram.c
@@ -63,8 +63,9 @@
 			 * No binman support or no information. For now, fix it
 			 * to the address pointed to by U-Boot.
 			 */
-			u_boot_pos = CONFIG_SYS_TEXT_BASE -
-					sizeof(struct image_header);
+			header = spl_get_load_buffer(-sizeof(*header),
+						     sizeof(*header));
+
 		}
 		header = (struct image_header *)map_sysmem(u_boot_pos, 0);
 
diff --git a/common/spl/spl_spi.c b/common/spl/spl_spi.c
index ba60a3a..e10cf01 100644
--- a/common/spl/spl_spi.c
+++ b/common/spl/spl_spi.c
@@ -88,8 +88,7 @@
 		return -ENODEV;
 	}
 
-	/* use CONFIG_SYS_TEXT_BASE as temporary storage area */
-	header = (struct image_header *)(CONFIG_SYS_TEXT_BASE);
+	header = spl_get_load_buffer(-sizeof(*header), 0x40);
 
 #if CONFIG_IS_ENABLED(OF_CONTROL) && !CONFIG_IS_ENABLED(OF_PLATDATA)
 	payload_offs = fdtdec_get_config_int(gd->fdt_blob,
diff --git a/common/spl/spl_ubi.c b/common/spl/spl_ubi.c
index a7939e9..67e5fad 100644
--- a/common/spl/spl_ubi.c
+++ b/common/spl/spl_ubi.c
@@ -61,8 +61,7 @@
 		puts("Loading Linux failed, falling back to U-Boot.\n");
 	}
 #endif
-	header = (struct image_header *)
-		(CONFIG_SYS_TEXT_BASE - sizeof(struct image_header));
+	header = spl_get_load_buffer(-sizeof(*header), sizeof(header));
 	volumes[0].vol_id = CONFIG_SPL_UBI_LOAD_MONITOR_ID;
 	volumes[0].load_addr = (void *)header;
 
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index 291d569..2fc2184 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -5,6 +5,7 @@
 CONFIG_SPL=y
 CONFIG_DISTRO_DEFAULTS=y
 CONFIG_SPL_LOAD_FIT=y
+CONFIG_OF_BOARD_SETUP=y
 CONFIG_BOOTCOMMAND="if test ${boot_fit} -eq 1; then run update_to_fit; fi; run findfdt; run init_console; run envboot; run distro_bootcmd"
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_VERSION_VARIABLE=y
diff --git a/configs/am3517_evm_defconfig b/configs/am3517_evm_defconfig
index 96491f3..e334030 100644
--- a/configs/am3517_evm_defconfig
+++ b/configs/am3517_evm_defconfig
@@ -38,6 +38,7 @@
 CONFIG_SPL_OF_PLATDATA=y
 # CONFIG_ENV_IS_IN_FAT is not set
 CONFIG_ENV_IS_IN_NAND=y
+CONFIG_DM_PCA953X=y
 CONFIG_MMC_OMAP_HS=y
 CONFIG_NAND=y
 CONFIG_SYS_NAND_BUSWIDTH_16BIT=y
@@ -47,6 +48,8 @@
 CONFIG_MII=y
 CONFIG_DRIVER_TI_EMAC=y
 # CONFIG_TWL4030_POWER is not set
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
 CONFIG_CONS_INDEX=3
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
diff --git a/configs/bcm968380gerg_ram_defconfig b/configs/bcm968380gerg_ram_defconfig
index 4943c8a..8b2b318 100644
--- a/configs/bcm968380gerg_ram_defconfig
+++ b/configs/bcm968380gerg_ram_defconfig
@@ -39,6 +39,7 @@
 # CONFIG_SPI_FLASH_USE_4K_SECTORS is not set
 CONFIG_PHY=y
 CONFIG_BCM6368_USBH_PHY=y
+CONFIG_PINCTRL=y
 CONFIG_POWER_DOMAIN=y
 CONFIG_BCM6328_POWER_DOMAIN=y
 CONFIG_DM_RESET=y
diff --git a/configs/da850evm_defconfig b/configs/da850evm_defconfig
index c30f396..6dc70dd 100644
--- a/configs/da850evm_defconfig
+++ b/configs/da850evm_defconfig
@@ -24,6 +24,7 @@
 CONFIG_SYS_PROMPT="U-Boot > "
 CONFIG_CRC32_VERIFY=y
 # CONFIG_CMD_EEPROM is not set
+CONFIG_CMD_DM=y
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_GPT is not set
 # CONFIG_CMD_PART is not set
@@ -50,6 +51,8 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
 CONFIG_SPI_FLASH_MTD=y
 CONFIG_MII=y
 CONFIG_DRIVER_TI_EMAC=y
diff --git a/configs/da850evm_direct_nor_defconfig b/configs/da850evm_direct_nor_defconfig
index 4039d0ee..8ea522a 100644
--- a/configs/da850evm_direct_nor_defconfig
+++ b/configs/da850evm_direct_nor_defconfig
@@ -5,7 +5,6 @@
 CONFIG_DA850_LOWLEVEL=y
 CONFIG_TI_COMMON_CMD_OPTIONS=y
 CONFIG_NR_DRAM_BANKS=1
-# CONFIG_SYS_MALLOC_F is not set
 CONFIG_SYS_EXTRA_OPTIONS="USE_NOR,DIRECT_NOR_BOOT"
 CONFIG_BOOTDELAY=3
 CONFIG_USE_BOOTARGS=y
@@ -21,6 +20,7 @@
 CONFIG_CMD_IMLS=y
 CONFIG_CRC32_VERIFY=y
 # CONFIG_CMD_EEPROM is not set
+CONFIG_CMD_DM=y
 # CONFIG_CMD_GPIO is not set
 # CONFIG_CMD_GPT is not set
 # CONFIG_CMD_MMC is not set
@@ -48,8 +48,12 @@
 CONFIG_SPI_FLASH=y
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
 CONFIG_MII=y
 CONFIG_DRIVER_TI_EMAC=y
+CONFIG_SPECIFY_CONSOLE_INDEX=y
+CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
 CONFIG_DM_SPI=y
diff --git a/configs/da850evm_nand_defconfig b/configs/da850evm_nand_defconfig
index 11d6a2b..d13d832 100644
--- a/configs/da850evm_nand_defconfig
+++ b/configs/da850evm_nand_defconfig
@@ -24,6 +24,7 @@
 CONFIG_SYS_PROMPT="U-Boot > "
 CONFIG_CRC32_VERIFY=y
 # CONFIG_CMD_EEPROM is not set
+CONFIG_CMD_DM=y
 # CONFIG_CMD_FLASH is not set
 # CONFIG_CMD_GPT is not set
 CONFIG_CMD_NAND=y
@@ -51,6 +52,8 @@
 CONFIG_SPI_FLASH_STMICRO=y
 CONFIG_SPI_FLASH_WINBOND=y
 CONFIG_SPI_FLASH_MTD=y
+CONFIG_PINCTRL=y
+CONFIG_PINCTRL_SINGLE=y
 CONFIG_DM_SERIAL=y
 CONFIG_SYS_NS16550=y
 CONFIG_SPI=y
diff --git a/configs/gardena-smart-gateway-mt7688-ram_defconfig b/configs/gardena-smart-gateway-mt7688-ram_defconfig
new file mode 100644
index 0000000..0e2f158
--- /dev/null
+++ b/configs/gardena-smart-gateway-mt7688-ram_defconfig
@@ -0,0 +1,55 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x80010000
+CONFIG_ARCH_MT7620=y
+# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set
+# CONFIG_MIPS_BOOT_ENV_LEGACY is not set
+CONFIG_MIPS_BOOT_FDT=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_MEMINFO=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_NET is not set
+CONFIG_CMD_TIME=y
+CONFIG_MTDIDS_DEFAULT="spi-nand0=spi-nand0"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:-(ubi)"
+CONFIG_CMD_UBI=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_HAVE_BLOCK_DEVICE=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_MTD=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_RAM=y
+CONFIG_DM_RESET=y
+CONFIG_BAUDRATE=57600
+# CONFIG_SPL_SERIAL_PRESENT is not set
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_SYSRESET_SYSCON=y
diff --git a/configs/gardena-smart-gateway-mt7688_defconfig b/configs/gardena-smart-gateway-mt7688_defconfig
new file mode 100644
index 0000000..1213227
--- /dev/null
+++ b/configs/gardena-smart-gateway-mt7688_defconfig
@@ -0,0 +1,58 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x9c000000
+CONFIG_ARCH_MT7620=y
+CONFIG_BOOT_ROM=y
+CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
+CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y
+# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set
+# CONFIG_MIPS_BOOT_ENV_LEGACY is not set
+CONFIG_MIPS_BOOT_FDT=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_MEMINFO=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_NET is not set
+CONFIG_CMD_TIME=y
+CONFIG_MTDIDS_DEFAULT="spi-nand0=spi-nand0"
+CONFIG_MTDPARTS_DEFAULT="mtdparts=spi-nand0:-(ubi)"
+CONFIG_CMD_UBI=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="gardena-smart-gateway-mt7688"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_HAVE_BLOCK_DEVICE=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_MTD=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_RAM=y
+CONFIG_DM_RESET=y
+CONFIG_BAUDRATE=57600
+# CONFIG_SPL_SERIAL_PRESENT is not set
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_SYSRESET_SYSCON=y
diff --git a/configs/linkit-smart-7688-ram_defconfig b/configs/linkit-smart-7688-ram_defconfig
new file mode 100644
index 0000000..77cd1c1
--- /dev/null
+++ b/configs/linkit-smart-7688-ram_defconfig
@@ -0,0 +1,51 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x80010000
+CONFIG_ARCH_MT7620=y
+# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set
+# CONFIG_MIPS_BOOT_ENV_LEGACY is not set
+CONFIG_MIPS_BOOT_FDT=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+CONFIG_CMD_MEMINFO=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_NET is not set
+CONFIG_CMD_TIME=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_HAVE_BLOCK_DEVICE=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_RAM=y
+CONFIG_DM_RESET=y
+CONFIG_BAUDRATE=57600
+# CONFIG_SPL_SERIAL_PRESENT is not set
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_SYSRESET_SYSCON=y
diff --git a/configs/linkit-smart-7688_defconfig b/configs/linkit-smart-7688_defconfig
new file mode 100644
index 0000000..62cdda1
--- /dev/null
+++ b/configs/linkit-smart-7688_defconfig
@@ -0,0 +1,55 @@
+CONFIG_MIPS=y
+CONFIG_SYS_TEXT_BASE=0x9c000000
+CONFIG_ARCH_MT7620=y
+CONFIG_BOOT_ROM=y
+CONFIG_ONBOARD_DDR2_SIZE_1024MBIT=y
+CONFIG_ONBOARD_DDR2_CHIP_WIDTH_16BIT=y
+# CONFIG_MIPS_BOOT_CMDLINE_LEGACY is not set
+# CONFIG_MIPS_BOOT_ENV_LEGACY is not set
+CONFIG_MIPS_BOOT_FDT=y
+CONFIG_NR_DRAM_BANKS=1
+# CONFIG_SYS_MALLOC_CLEAR_ON_INIT is not set
+CONFIG_OF_STDOUT_VIA_ALIAS=y
+CONFIG_SYS_CONSOLE_INFO_QUIET=y
+CONFIG_BOARD_EARLY_INIT_F=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_CPU=y
+CONFIG_CMD_LICENSE=y
+# CONFIG_CMD_BOOTD is not set
+# CONFIG_CMD_ELF is not set
+# CONFIG_CMD_XIMG is not set
+# CONFIG_CMD_CRC32 is not set
+CONFIG_CMD_MEMINFO=y
+# CONFIG_CMD_FLASH is not set
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_SF=y
+CONFIG_CMD_SPI=y
+# CONFIG_CMD_NET is not set
+CONFIG_CMD_TIME=y
+CONFIG_OF_EMBED=y
+CONFIG_DEFAULT_DEVICE_TREE="linkit-smart-7688"
+CONFIG_ENV_IS_IN_SPI_FLASH=y
+# CONFIG_DM_DEVICE_REMOVE is not set
+CONFIG_HAVE_BLOCK_DEVICE=y
+CONFIG_CLK=y
+CONFIG_CPU=y
+CONFIG_DM_GPIO=y
+CONFIG_LED=y
+CONFIG_LED_BLINK=y
+CONFIG_LED_GPIO=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_GIGADEVICE=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_SPANSION=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_WINBOND=y
+CONFIG_SPI_FLASH_MTD=y
+CONFIG_PHY=y
+CONFIG_POWER_DOMAIN=y
+CONFIG_RAM=y
+CONFIG_DM_RESET=y
+CONFIG_BAUDRATE=57600
+# CONFIG_SPL_SERIAL_PRESENT is not set
+CONFIG_SYS_NS16550=y
+CONFIG_SPI=y
+CONFIG_SYSRESET_SYSCON=y
diff --git a/configs/qemu_arm64_defconfig b/configs/qemu_arm64_defconfig
index 2df35a8..7fd726f 100644
--- a/configs/qemu_arm64_defconfig
+++ b/configs/qemu_arm64_defconfig
@@ -8,6 +8,7 @@
 CONFIG_NR_DRAM_BANKS=1
 # CONFIG_DISPLAY_CPUINFO is not set
 # CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_DATE=y
diff --git a/configs/qemu_arm_defconfig b/configs/qemu_arm_defconfig
index 2865599..fbceaf3 100644
--- a/configs/qemu_arm_defconfig
+++ b/configs/qemu_arm_defconfig
@@ -8,6 +8,7 @@
 CONFIG_NR_DRAM_BANKS=1
 # CONFIG_DISPLAY_CPUINFO is not set
 # CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 CONFIG_CMD_PCI=y
 CONFIG_CMD_USB=y
 CONFIG_CMD_DATE=y
diff --git a/configs/sama5d27_som1_ek_mmc1_defconfig b/configs/sama5d27_som1_ek_mmc1_defconfig
new file mode 100644
index 0000000..0ac2445
--- /dev/null
+++ b/configs/sama5d27_som1_ek_mmc1_defconfig
@@ -0,0 +1,91 @@
+CONFIG_ARM=y
+CONFIG_ARCH_AT91=y
+CONFIG_SYS_TEXT_BASE=0x23f00000
+CONFIG_TARGET_SAMA5D27_SOM1_EK=y
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_SPL=y
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xf8020000
+CONFIG_DEBUG_UART_CLOCK=82000000
+CONFIG_SPL_FAT_SUPPORT=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d27_som1_ek"
+CONFIG_DEBUG_UART=y
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_FIT=y
+CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2"
+CONFIG_SD_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk1p2 rw rootwait"
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_I2C=y
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-parent dmas dma-names"
+CONFIG_ENV_IS_IN_FAT=y
+CONFIG_ENV_FAT_DEVICE_AND_PART="1"
+CONFIG_DM=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_CLK_AT91=y
+CONFIG_AT91_UTMI=y
+CONFIG_AT91_H32MX=y
+CONFIG_AT91_GENERIC_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_ATMEL_PIO4=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_AT91=y
+CONFIG_I2C_EEPROM=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ATMEL=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_SPI_FLASH_MACRONIX=y
+CONFIG_SPI_FLASH_STMICRO=y
+CONFIG_SPI_FLASH_SST=y
+CONFIG_DM_ETH=y
+CONFIG_MACB=y
+CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
+CONFIG_PINCTRL_AT91PIO4=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_ATMEL=y
+CONFIG_DEBUG_UART_ANNOUNCE=y
+CONFIG_ATMEL_USART=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_TIMER=y
+CONFIG_SPL_TIMER=y
+CONFIG_ATMEL_PIT_TIMER=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_DM_VIDEO=y
+CONFIG_ATMEL_HLCD=y
diff --git a/configs/sama5d27_som1_ek_mmc_defconfig b/configs/sama5d27_som1_ek_mmc_defconfig
index 56c7252..fbde79c 100644
--- a/configs/sama5d27_som1_ek_mmc_defconfig
+++ b/configs/sama5d27_som1_ek_mmc_defconfig
@@ -22,6 +22,8 @@
 CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2"
 CONFIG_SD_BOOT=y
 CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait"
 CONFIG_MISC_INIT_R=y
 # CONFIG_DISPLAY_BOARDINFO is not set
 CONFIG_SPL_SEPARATE_BSS=y
@@ -88,3 +90,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d2_ptc_ek_mmc_defconfig b/configs/sama5d2_ptc_ek_mmc_defconfig
index 42f0c95..60df0f0 100644
--- a/configs/sama5d2_ptc_ek_mmc_defconfig
+++ b/configs/sama5d2_ptc_ek_mmc_defconfig
@@ -63,3 +63,8 @@
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d2_ptc_ek_nandflash_defconfig b/configs/sama5d2_ptc_ek_nandflash_defconfig
index c4b3085..4e39406 100644
--- a/configs/sama5d2_ptc_ek_nandflash_defconfig
+++ b/configs/sama5d2_ptc_ek_nandflash_defconfig
@@ -62,3 +62,8 @@
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d2_xplained_emmc_defconfig b/configs/sama5d2_xplained_emmc_defconfig
new file mode 100644
index 0000000..ca5d4f4
--- /dev/null
+++ b/configs/sama5d2_xplained_emmc_defconfig
@@ -0,0 +1,88 @@
+CONFIG_ARM=y
+CONFIG_ARCH_AT91=y
+CONFIG_SYS_TEXT_BASE=0x26f00000
+CONFIG_TARGET_SAMA5D2_XPLAINED=y
+CONFIG_SPL_GPIO_SUPPORT=y
+CONFIG_SPL_LIBCOMMON_SUPPORT=y
+CONFIG_SPL_LIBGENERIC_SUPPORT=y
+CONFIG_SYS_MALLOC_F_LEN=0x2000
+CONFIG_SPL_MMC_SUPPORT=y
+CONFIG_SPL_SERIAL_SUPPORT=y
+CONFIG_SPL_DRIVERS_MISC_SUPPORT=y
+CONFIG_SPL=y
+CONFIG_DEBUG_UART_BOARD_INIT=y
+CONFIG_DEBUG_UART_BASE=0xf8020000
+CONFIG_DEBUG_UART_CLOCK=83000000
+CONFIG_SPL_FAT_SUPPORT=y
+CONFIG_SPL_LIBDISK_SUPPORT=y
+CONFIG_DEFAULT_DEVICE_TREE="at91-sama5d2_xplained"
+CONFIG_DEBUG_UART=y
+CONFIG_ENV_VARS_UBOOT_CONFIG=y
+CONFIG_FIT=y
+CONFIG_SYS_EXTRA_OPTIONS="SAMA5D2,SYS_USE_MMC"
+CONFIG_SD_BOOT=y
+CONFIG_BOOTDELAY=3
+CONFIG_USE_BOOTARGS=y
+CONFIG_BOOTARGS="console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait"
+# CONFIG_DISPLAY_BOARDINFO is not set
+CONFIG_SPL_SEPARATE_BSS=y
+CONFIG_HUSH_PARSER=y
+CONFIG_CMD_BOOTZ=y
+# CONFIG_CMD_IMI is not set
+# CONFIG_CMD_FLASH is not set
+CONFIG_CMD_I2C=y
+# CONFIG_CMD_LOADS is not set
+CONFIG_CMD_MMC=y
+CONFIG_CMD_SF=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_DHCP=y
+CONFIG_CMD_PING=y
+CONFIG_CMD_EXT4=y
+CONFIG_CMD_FAT=y
+CONFIG_OF_CONTROL=y
+CONFIG_SPL_OF_CONTROL=y
+CONFIG_OF_SPL_REMOVE_PROPS="interrupts interrupt-parent dmas dma-names"
+CONFIG_ENV_IS_IN_FAT=y
+CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
+CONFIG_DM=y
+CONFIG_SPL_DM=y
+CONFIG_SPL_DM_SEQ_ALIAS=y
+CONFIG_CLK=y
+CONFIG_SPL_CLK=y
+CONFIG_CLK_AT91=y
+CONFIG_AT91_UTMI=y
+CONFIG_AT91_H32MX=y
+CONFIG_AT91_GENERIC_CLK=y
+CONFIG_DM_GPIO=y
+CONFIG_ATMEL_PIO4=y
+CONFIG_DM_I2C=y
+CONFIG_SYS_I2C_AT91=y
+CONFIG_I2C_EEPROM=y
+CONFIG_DM_MMC=y
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SDHCI_ATMEL=y
+CONFIG_DM_SPI_FLASH=y
+CONFIG_SPI_FLASH=y
+CONFIG_SPI_FLASH_ATMEL=y
+CONFIG_DM_ETH=y
+CONFIG_MACB=y
+CONFIG_PINCTRL=y
+CONFIG_SPL_PINCTRL=y
+CONFIG_PINCTRL_AT91PIO4=y
+CONFIG_DM_SERIAL=y
+CONFIG_DEBUG_UART_ATMEL=y
+CONFIG_DEBUG_UART_ANNOUNCE=y
+CONFIG_ATMEL_USART=y
+CONFIG_SPI=y
+CONFIG_DM_SPI=y
+CONFIG_TIMER=y
+CONFIG_SPL_TIMER=y
+CONFIG_ATMEL_PIT_TIMER=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_ATMEL_USBA=y
+CONFIG_DM_VIDEO=y
+CONFIG_ATMEL_HLCD=y
diff --git a/configs/sama5d2_xplained_mmc_defconfig b/configs/sama5d2_xplained_mmc_defconfig
index 77dc82c..f8748f8 100644
--- a/configs/sama5d2_xplained_mmc_defconfig
+++ b/configs/sama5d2_xplained_mmc_defconfig
@@ -88,3 +88,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d2_xplained_spiflash_defconfig b/configs/sama5d2_xplained_spiflash_defconfig
index fc9ec9c..efe7176 100644
--- a/configs/sama5d2_xplained_spiflash_defconfig
+++ b/configs/sama5d2_xplained_spiflash_defconfig
@@ -85,3 +85,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d3_xplained_mmc_defconfig b/configs/sama5d3_xplained_mmc_defconfig
index 7f2d276..154cdc2 100644
--- a/configs/sama5d3_xplained_mmc_defconfig
+++ b/configs/sama5d3_xplained_mmc_defconfig
@@ -76,3 +76,8 @@
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d3_xplained_nandflash_defconfig b/configs/sama5d3_xplained_nandflash_defconfig
index ac8435e..3bf93de 100644
--- a/configs/sama5d3_xplained_nandflash_defconfig
+++ b/configs/sama5d3_xplained_nandflash_defconfig
@@ -72,4 +72,9 @@
 CONFIG_DM_USB=y
 CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_STORAGE=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
 CONFIG_FAT_WRITE=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d4_xplained_mmc_defconfig b/configs/sama5d4_xplained_mmc_defconfig
index 89393a9..f60b6b5 100644
--- a/configs/sama5d4_xplained_mmc_defconfig
+++ b/configs/sama5d4_xplained_mmc_defconfig
@@ -84,3 +84,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d4_xplained_nandflash_defconfig b/configs/sama5d4_xplained_nandflash_defconfig
index 5387966..3524dbf 100644
--- a/configs/sama5d4_xplained_nandflash_defconfig
+++ b/configs/sama5d4_xplained_nandflash_defconfig
@@ -80,3 +80,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sama5d4_xplained_spiflash_defconfig b/configs/sama5d4_xplained_spiflash_defconfig
index 39c86ec..3f519cd 100644
--- a/configs/sama5d4_xplained_spiflash_defconfig
+++ b/configs/sama5d4_xplained_spiflash_defconfig
@@ -84,3 +84,8 @@
 CONFIG_USB_GADGET_ATMEL_USBA=y
 CONFIG_DM_VIDEO=y
 CONFIG_ATMEL_HLCD=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_DS24XXX=y
+CONFIG_OF_LIBFDT_OVERLAY=y
diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index ca12118..fb71998 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -23,6 +23,7 @@
 CONFIG_CMD_CPU=y
 CONFIG_CMD_LICENSE=y
 CONFIG_CMD_BOOTZ=y
+CONFIG_CMD_BOOTEFI_SELFTEST=y
 # CONFIG_CMD_ELF is not set
 CONFIG_CMD_ASKENV=y
 CONFIG_CMD_GREPENV=y
@@ -191,6 +192,10 @@
 CONFIG_CONSOLE_TRUETYPE=y
 CONFIG_CONSOLE_TRUETYPE_CANTORAONE=y
 CONFIG_VIDEO_SANDBOX_SDL=y
+CONFIG_W1=y
+CONFIG_W1_GPIO=y
+CONFIG_W1_EEPROM=y
+CONFIG_W1_EEPROM_SANDBOX=y
 CONFIG_WDT=y
 CONFIG_WDT_SANDBOX=y
 CONFIG_FS_CBFS=y
diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig
index e134a66..3bf7538 100644
--- a/configs/stm32mp15_basic_defconfig
+++ b/configs/stm32mp15_basic_defconfig
@@ -24,6 +24,8 @@
 CONFIG_CMD_GPT=y
 CONFIG_CMD_I2C=y
 CONFIG_CMD_MMC=y
+CONFIG_CMD_USB=y
+CONFIG_CMD_USB_MASS_STORAGE=y
 CONFIG_CMD_PMIC=y
 CONFIG_CMD_REGULATOR=y
 CONFIG_CMD_EXT4_WRITE=y
@@ -36,6 +38,8 @@
 CONFIG_LED_GPIO=y
 CONFIG_DM_MMC=y
 CONFIG_STM32_SDMMC2=y
+CONFIG_PHY=y
+CONFIG_PHY_STM32_USBPHYC=y
 # CONFIG_PINCTRL_FULL is not set
 # CONFIG_SPL_PINCTRL_FULL is not set
 CONFIG_DM_PMIC=y
@@ -47,3 +51,15 @@
 CONFIG_DM_REGULATOR_STPMU1=y
 CONFIG_SERIAL_RX_BUFFER=y
 CONFIG_STM32_SERIAL=y
+CONFIG_USB=y
+CONFIG_DM_USB=y
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_GENERIC=y
+CONFIG_USB_DWC2=y
+CONFIG_USB_STORAGE=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_MANUFACTURER="STMicroelectronics"
+CONFIG_USB_GADGET_VENDOR_NUM=0x0483
+CONFIG_USB_GADGET_PRODUCT_NUM=0x5720
+CONFIG_USB_GADGET_DWC2_OTG=y
+CONFIG_USB_GADGET_DOWNLOAD=y
diff --git a/configs/vf610twr_defconfig b/configs/vf610twr_defconfig
index 59066a3..3f38c88 100644
--- a/configs/vf610twr_defconfig
+++ b/configs/vf610twr_defconfig
@@ -39,3 +39,4 @@
 CONFIG_MII=y
 CONFIG_DM_SERIAL=y
 CONFIG_FSL_LPUART=y
+# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
diff --git a/configs/vf610twr_nand_defconfig b/configs/vf610twr_nand_defconfig
index 5b269fd..d6e318f 100644
--- a/configs/vf610twr_nand_defconfig
+++ b/configs/vf610twr_nand_defconfig
@@ -39,3 +39,4 @@
 CONFIG_MII=y
 CONFIG_DM_SERIAL=y
 CONFIG_FSL_LPUART=y
+# CONFIG_EFI_UNICODE_CAPITALIZATION is not set
diff --git a/configs/xilinx_zynqmp_mini_emmc0_defconfig b/configs/xilinx_zynqmp_mini_emmc0_defconfig
index 19bb708..c0ec79c 100644
--- a/configs/xilinx_zynqmp_mini_emmc0_defconfig
+++ b/configs/xilinx_zynqmp_mini_emmc0_defconfig
@@ -9,6 +9,7 @@
 CONFIG_FIT=y
 CONFIG_BOOTDELAY=-1
 CONFIG_SUPPORT_RAW_INITRD=y
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
diff --git a/configs/xilinx_zynqmp_mini_emmc1_defconfig b/configs/xilinx_zynqmp_mini_emmc1_defconfig
index 041bd0c..c1f5e64 100644
--- a/configs/xilinx_zynqmp_mini_emmc1_defconfig
+++ b/configs/xilinx_zynqmp_mini_emmc1_defconfig
@@ -9,6 +9,7 @@
 CONFIG_FIT=y
 CONFIG_BOOTDELAY=-1
 CONFIG_SUPPORT_RAW_INITRD=y
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
diff --git a/configs/xilinx_zynqmp_mini_nand_defconfig b/configs/xilinx_zynqmp_mini_nand_defconfig
index d597e09..e119ec1 100644
--- a/configs/xilinx_zynqmp_mini_nand_defconfig
+++ b/configs/xilinx_zynqmp_mini_nand_defconfig
@@ -9,6 +9,7 @@
 CONFIG_FIT=y
 CONFIG_BOOTDELAY=-1
 CONFIG_SUPPORT_RAW_INITRD=y
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_BOARD_EARLY_INIT_R=y
 # CONFIG_CMDLINE_EDITING is not set
diff --git a/configs/xilinx_zynqmp_mini_qspi_defconfig b/configs/xilinx_zynqmp_mini_qspi_defconfig
index d557139..9fcc7c2 100644
--- a/configs/xilinx_zynqmp_mini_qspi_defconfig
+++ b/configs/xilinx_zynqmp_mini_qspi_defconfig
@@ -9,6 +9,7 @@
 CONFIG_NR_DRAM_BANKS=1
 # CONFIG_IMAGE_FORMAT_LEGACY is not set
 CONFIG_BOOTDELAY=-1
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 # CONFIG_CMDLINE_EDITING is not set
 # CONFIG_AUTO_COMPLETE is not set
diff --git a/configs/zynq_cse_nand_defconfig b/configs/zynq_cse_nand_defconfig
index ae5a696..44ad5bd 100644
--- a/configs/zynq_cse_nand_defconfig
+++ b/configs/zynq_cse_nand_defconfig
@@ -6,6 +6,7 @@
 CONFIG_SPL=y
 CONFIG_SPL_STACK_R_ADDR=0x200000
 CONFIG_SYS_MALLOC_LEN=0x1000
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_SPL_STACK_R=y
 CONFIG_SYS_PROMPT="Zynq> "
diff --git a/configs/zynq_cse_nor_defconfig b/configs/zynq_cse_nor_defconfig
index ce50852..1f81c0b 100644
--- a/configs/zynq_cse_nor_defconfig
+++ b/configs/zynq_cse_nor_defconfig
@@ -7,6 +7,7 @@
 CONFIG_SPL_STACK_R_ADDR=0x200000
 CONFIG_SYS_MALLOC_LEN=0x1000
 CONFIG_BOOTDELAY=-1
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 CONFIG_SPL_STACK_R=y
 CONFIG_SYS_PROMPT="Zynq> "
diff --git a/configs/zynq_cse_qspi_defconfig b/configs/zynq_cse_qspi_defconfig
index 02f1a25..2e1e34d 100644
--- a/configs/zynq_cse_qspi_defconfig
+++ b/configs/zynq_cse_qspi_defconfig
@@ -15,6 +15,7 @@
 # CONFIG_ARCH_FIXUP_FDT_MEMORY is not set
 CONFIG_BOOTDELAY=-1
 # CONFIG_USE_BOOTCOMMAND is not set
+# CONFIG_BOARD_LATE_INIT is not set
 # CONFIG_DISPLAY_CPUINFO is not set
 # CONFIG_ARCH_EARLY_INIT_R is not set
 CONFIG_SPL_STACK_R=y
diff --git a/configs/zynq_zybo_defconfig b/configs/zynq_zybo_defconfig
index 46a8f5a..8293171 100644
--- a/configs/zynq_zybo_defconfig
+++ b/configs/zynq_zybo_defconfig
@@ -72,3 +72,4 @@
 CONFIG_CI_UDC=y
 CONFIG_USB_GADGET_DOWNLOAD=y
 CONFIG_USB_FUNCTION_THOR=y
+CONFIG_DISPLAY=y
diff --git a/doc/device-tree-bindings/chosen.txt b/doc/device-tree-bindings/chosen.txt
index da7b4e6..86c533a 100644
--- a/doc/device-tree-bindings/chosen.txt
+++ b/doc/device-tree-bindings/chosen.txt
@@ -83,3 +83,24 @@
 
 You should not define this property yourself in the device-tree, as it
 may be overwritten without warning.
+
+firmware-loader property
+------------------------
+Multiple file system firmware loader nodes could be defined in device trees for
+multiple storage type and their default partition, then a property
+"firmware-loader" can be used to pass default firmware loader
+node(default storage type) to the firmware loader driver.
+
+Example
+-------
+/ {
+	chosen {
+		firmware-loader = &fs_loader0;
+	};
+
+	fs_loader0: fs-loader@0 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		phandlepart = <&mmc 1>;
+	};
+};
diff --git a/doc/device-tree-bindings/misc/fs_loader.txt b/doc/device-tree-bindings/misc/fs_loader.txt
new file mode 100644
index 0000000..884fbf4
--- /dev/null
+++ b/doc/device-tree-bindings/misc/fs_loader.txt
@@ -0,0 +1,48 @@
+* File system firmware loader
+
+Required properties:
+--------------------
+
+- compatible: should contain "u-boot,fs-loader"
+- phandlepart: which block storage device and partition the image loading from,
+	       this property is required for mmc, usb and sata. This is unsigned
+	       32-bit array. For example phandlepart=<&mmc_0 1>, meaning use
+	       that MMC0 node pointer, partition 1.
+- mdtpart: which partition of ubi the image loading from, this property is
+	   required for ubi and mounting.
+- ubivol: which volume of ubi the image loading from, this property is required
+	  for ubi and mounting.
+
+Example of storage device and partition search set for mmc, usb, sata and
+ubi in device tree source as shown in below:
+
+	Example of storage type and device partition search set for mmc, usb,
+	sata and ubi as shown in below:
+	Example for mmc:
+	fs_loader0: fs-loader@0 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		phandlepart = <&mmc_0 1>;
+	};
+
+	Example for usb:
+	fs_loader1: fs-loader@1 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		phandlepart = <&usb0 1>;
+	};
+
+	Example for sata:
+	fs_loader2: fs-loader@2 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		phandlepart = <&sata0 1>;
+	};
+
+	Example for ubi:
+	fs_loader3: fs-loader@3 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		mtdpart = "UBI",
+		ubivol = "ubi0";
+	};
diff --git a/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt b/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt
new file mode 100644
index 0000000..2034f05
--- /dev/null
+++ b/doc/device-tree-bindings/pinctrl/bcm6838-pinctrl.txt
@@ -0,0 +1,35 @@
+* broadcom bcm6838 pinctrl
+
+Required properties for the pinctrl driver:
+- compatible:	   "brcm,bcm6838-pinctrl"
+- regmap: 		   specify the gpio test port syscon
+- brcm,pins-count:      the number of pin
+- brcm,functions-count: the number of function
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices.
+
+Example:
+
+		gpio_test_port: syscon@14e00294 {
+			compatible = "syscon";
+			reg = <0x14e00294 0x1c>;
+		};
+
+		pinctrl: pinctrl {
+			compatible = "brcm,bcm6838-pinctrl";
+			regmap = <&gpio_test_port>;
+			brcm,pins-count = <74>;
+			brcm,functions-count = <8>;
+
+			usb0: usb0 {
+				usb0_pwrflt {
+					pins = "69";
+					function = "1";
+				};
+				usb0_pwron {
+					pins = "70";
+					function = "1";
+				};
+			};
+		};
diff --git a/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt b/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt
new file mode 100644
index 0000000..2e91be9
--- /dev/null
+++ b/doc/device-tree-bindings/w1-eeprom/ds24xxx.txt
@@ -0,0 +1,37 @@
+Maxim DS24 families driver device binding - one wire protocol EEPROMS from Maxim
+=======================
+
+This memory needs to be connected to a onewire bus, as a child node.
+The bus will read the device serial number and match this node with a found
+device on the bus
+Also check doc/device-tree-bindings/w1 for onewire bus drivers
+
+Driver:
+- drivers/w1-eeprom/ds24xxx.c
+
+Software ds24xxx device-tree node properties:
+Required:
+* compatible = "maxim,ds24b33"
+or
+* compatible = "maxim,ds2431"
+Further memories can be added.
+
+Optional:
+* none
+
+Example:
+	eeprom1: eeprom@0 {
+		compatible = "maxim,ds24xxx";
+	}
+
+Example with parent bus:
+
+onewire_tm: onewire {
+		compatible = "w1-gpio";
+		gpios = <&pioA 32 0>;
+
+		eeprom1: eeprom@0 {
+			compatible = "maxim,ds24xxx";
+		}
+};
+
diff --git a/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt b/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt
new file mode 100644
index 0000000..82bb589
--- /dev/null
+++ b/doc/device-tree-bindings/w1-eeprom/eep_sandbox.txt
@@ -0,0 +1,34 @@
+Onewire EEPROM sandbox driver device binding - one wire protocol sandbox EEPROM
+=======================
+
+This memory needs to be connected to a onewire bus, as a child node.
+The bus will read the device serial number and match this node with a found
+device on the bus
+Also check doc/device-tree-bindings/w1 for onewire bus drivers
+
+Driver:
+- drivers/w1-eeprom/eep_sandbox.c
+
+Software ds24xxx device-tree node properties:
+Required:
+* compatible = "sandbox,w1-eeprom"
+
+Optional:
+* none
+
+Example:
+	eeprom1: eeprom@0 {
+		compatible = "sandbox,w1-eeprom";
+	}
+
+Example with parent bus:
+
+onewire_tm: onewire {
+		compatible = "w1-gpio";
+		gpios = <&gpio_a 8>;
+
+		eeprom1: eeprom@0 {
+			compatible = "sandbox,w1-eeprom";
+		}
+};
+
diff --git a/doc/device-tree-bindings/w1/w1-gpio.txt b/doc/device-tree-bindings/w1/w1-gpio.txt
new file mode 100644
index 0000000..5a58244
--- /dev/null
+++ b/doc/device-tree-bindings/w1/w1-gpio.txt
@@ -0,0 +1,40 @@
+W1 gpio device binding - one wire protocol over bitbanged gpio
+=======================
+
+
+Child nodes are required in device tree. The driver will detect
+the devices serial number and then search in the child nodes in the device tree
+for the proper node and try to match it with the device.
+
+Also check doc/device-tree-bindings/w1-eeprom for possible child nodes drivers
+
+Driver:
+- drivers/w1/w1-gpio.c
+
+Software w1 device-tree node properties:
+Required:
+* compatible = "w1-gpio";
+* gpios = <...>;
+	This is the gpio used for one wire protocol, using bitbanging
+
+Optional:
+* none
+
+Example:
+
+onewire_tm: onewire {
+		compatible = "w1-gpio";
+		gpios = <&pioA 32 0>;
+};
+
+Example with child:
+
+onewire_tm: onewire {
+		compatible = "w1-gpio";
+		gpios = <&pioA 32 0>;
+
+		eeprom1: eeprom@0 {
+			compatible = "maxim,ds24xxx";
+		}
+};
+
diff --git a/doc/driver-model/README.txt b/doc/driver-model/README.txt
index d6fa5c4..e949ff6 100644
--- a/doc/driver-model/README.txt
+++ b/doc/driver-model/README.txt
@@ -449,6 +449,15 @@
 root driver is at device tree offset 0 (the root node, '/'), and its
 children are the children of the root node.
 
+In order for a device tree to be valid, the content must be correct with
+respect to either device tree specification
+(https://www.devicetree.org/specifications/) or the device tree bindings that
+are found in the doc/device-tree-bindings directory.  When not U-Boot specific
+the bindings in this directory tend to come from the Linux Kernel.  As such
+certain design decisions may have been made already for us in terms of how
+specific devices are described and bound.  In most circumstances we wish to
+retain compatibility without additional changes being made to the device tree
+source files.
 
 Declaring Uclasses
 ------------------
diff --git a/doc/driver-model/fs_firmware_loader.txt b/doc/driver-model/fs_firmware_loader.txt
new file mode 100644
index 0000000..290915a
--- /dev/null
+++ b/doc/driver-model/fs_firmware_loader.txt
@@ -0,0 +1,133 @@
+# Copyright (C) 2018 Intel Corporation <www.intel.com>
+#
+# SPDX-License-Identifier:    GPL-2.0
+
+Introduction
+============
+
+This is file system firmware loader for U-Boot framework, which has very close
+to some Linux Firmware API. For the details of Linux Firmware API, you can refer
+to https://01.org/linuxgraphics/gfx-docs/drm/driver-api/firmware/index.html.
+
+File system firmware loader can be used to load whatever(firmware, image,
+and binary) from the storage device in file system format into target location
+such as memory, then consumer driver such as FPGA driver can program FPGA image
+from the target location into FPGA.
+
+To enable firmware loader, CONFIG_FS_LOADER need to be set at
+<board_name>_defconfig such as "CONFIG_FS_LOADER=y".
+
+Firmware Loader API core features
+---------------------------------
+
+Firmware storage device described in device tree source
+-------------------------------------------------------
+	For passing data like storage device phandle and partition where the
+	firmware loading from to the firmware loader driver, those data could be
+	defined in fs-loader node as shown in below:
+
+	Example for block device:
+	fs_loader0: fs-loader@0 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		phandlepart = <&mmc 1>;
+	};
+
+	<&mmc 1> means block storage device pointer and its partition.
+
+	Above example is a description for block storage, but for UBI storage
+	device, it can be described in FDT as shown in below:
+
+	Example for ubi:
+	fs_loader1: fs-loader@1 {
+		u-boot,dm-pre-reloc;
+		compatible = "u-boot,fs-loader";
+		mtdpart = "UBI",
+		ubivol = "ubi0";
+	};
+
+	Then, firmware_loader property would be set with the path of fs_loader
+	node under /chosen node such as:
+	/{
+		chosen {
+			firmware_loader = &fs_loader0;
+		};
+	};
+
+	However, this driver is also designed to support U-boot environment
+	variables, so all these data from FDT can be overwritten
+	through the U-boot environment variable during run time.
+	For examples:
+	"storage_interface" - Storage interface, it can be "mmc", "usb", "sata"
+						  or "ubi".
+	"fw_dev_part" - Block device number and its partition, it can be "0:1".
+	"fw_ubi_mtdpart" - UBI device mtd partition, it can be "UBI".
+	"fw_ubi_volume" - UBI volume, it can be "ubi0".
+
+	When above environment variables are set, environment values would be
+	used instead of data from FDT.
+	The benefit of this design allows user to change storage attribute data
+	at run time through U-boot console and saving the setting as default
+	environment values in the storage for the next power cycle, so no
+	compilation is required for both driver and FDT.
+
+File system firmware Loader API
+-------------------------------
+
+int request_firmware_into_buf(struct device_platdata *plat,
+				 const char *name,
+				 void *buf, size_t size, u32 offset,
+				 struct firmware **firmwarep)
+--------------------------------------------------------------------
+Load firmware into a previously allocated buffer
+
+Parameters:
+
+1. struct device_platdata *plat
+	Platform data such as storage and partition firmware loading from
+
+2. const char *name
+	name of firmware file
+
+3. void *buf
+	address of buffer to load firmware into
+
+4. size_t size
+	size of buffer
+
+5. u32 offset
+	offset of a file for start reading into buffer
+
+6. struct firmware **firmwarep
+	pointer to firmware image
+
+return:
+	size of total read
+	-ve when error
+
+Description:
+	The firmware is loaded directly into the buffer pointed to by buf and
+	the @firmwarep data member is pointed at buf
+
+Note: Memory would be allocated for firmware image, hence user should
+	  free() *firmwarep and *firmwarep->priv structs after usage of
+	  request_firmware_into_buf(), otherwise it will always leak memory
+	  while subsequent calls of request_firmware_into_buf() with the same
+	  *firmwarep argument. Those arguments can be free through calling API
+	  below release_firmware();
+
+Example of creating firmware loader instance and calling
+request_firmware_into_buf API:
+	if (uclass_get_device(UCLASS_FS_FIRMWARE_LOADER, 0, &dev)) {
+		request_firmware_into_buf(dev->plat, filename, buffer_location,
+					 buffer_size, offset_ofreading, &fw);
+	}
+
+void release_firmware(struct firmware *firmware)
+------------------------------------------------
+Release the resource associated with a firmware image
+
+Parameters:
+
+1. struct firmware *firmware
+	Firmware resource to release
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 884a945..9ac90c4 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -108,6 +108,10 @@
 
 source "drivers/video/Kconfig"
 
+source "drivers/w1/Kconfig"
+
+source "drivers/w1-eeprom/Kconfig"
+
 source "drivers/watchdog/Kconfig"
 
 config PHYS_TO_BUS
diff --git a/drivers/Makefile b/drivers/Makefile
index 23ea609..1d5905f 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -105,6 +105,8 @@
 obj-y += soc/
 obj-y += thermal/
 obj-y += axi/
+obj-$(CONFIG_W1) += w1/
+obj-$(CONFIG_W1_EEPROM) += w1-eeprom/
 
 obj-$(CONFIG_MACH_PIC32) += ddr/microchip/
 endif
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index c35912b..5fafb63 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -230,8 +230,10 @@
 	debug("cap 0x%x  port_map 0x%x  n_ports %d\n",
 	      uc_priv->cap, uc_priv->port_map, uc_priv->n_ports);
 
+#if !defined(CONFIG_DM_SCSI)
 	if (uc_priv->n_ports > CONFIG_SYS_SCSI_MAX_SCSI_ID)
 		uc_priv->n_ports = CONFIG_SYS_SCSI_MAX_SCSI_ID;
+#endif
 
 	for (i = 0; i < uc_priv->n_ports; i++) {
 		if (!(port_map & (1 << i)))
@@ -980,7 +982,7 @@
 
 	linkmap = uc_priv->link_port_map;
 
-	for (i = 0; i < CONFIG_SYS_SCSI_MAX_SCSI_ID; i++) {
+	for (i = 0; i < uc_priv->n_ports; i++) {
 		if (((linkmap >> i) & 0x01)) {
 			if (ahci_port_start(uc_priv, (u8) i)) {
 				printf("Can not start port %d\n", i);
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
index 9e0c823..facf527 100644
--- a/drivers/block/blk-uclass.c
+++ b/drivers/block/blk-uclass.c
@@ -132,6 +132,29 @@
 }
 
 /**
+ * blk_get_by_device() - Get the block device descriptor for the given device
+ * @dev:	Instance of a storage device
+ *
+ * Return: With block device descriptor on success , NULL if there is no such
+ *	   block device.
+ */
+struct blk_desc *blk_get_by_device(struct udevice *dev)
+{
+	struct udevice *child_dev, *next;
+
+	device_foreach_child_safe(child_dev, next, dev) {
+		if (device_get_uclass_id(child_dev) != UCLASS_BLK)
+			continue;
+
+		return dev_get_uclass_platdata(child_dev);
+	}
+
+	debug("%s: No block device found\n", __func__);
+
+	return NULL;
+}
+
+/**
  * get_desc() - Get the block device descriptor for the given device number
  *
  * @if_type:	Interface type
diff --git a/drivers/fpga/zynqmppl.c b/drivers/fpga/zynqmppl.c
index 03ffa8c..c095d5e 100644
--- a/drivers/fpga/zynqmppl.c
+++ b/drivers/fpga/zynqmppl.c
@@ -150,7 +150,8 @@
 			new_buf[i] = load_word(&buf[i], swap);
 
 		buf = new_buf;
-	} else if (swap != SWAP_DONE) {
+	} else if ((swap != SWAP_DONE) &&
+		   (zynqmp_pmufw_version() <= PMUFW_V1_0)) {
 		/* For bitstream which are aligned */
 		u32 *new_buf = (u32 *)buf;
 
@@ -196,27 +197,41 @@
 		     bitstream_type bstype)
 {
 	ALLOC_CACHE_ALIGN_BUFFER(u32, bsizeptr, 1);
-	u32 swap;
+	u32 swap = 0;
 	ulong bin_buf;
 	int ret;
 	u32 buf_lo, buf_hi;
 	u32 ret_payload[PAYLOAD_ARG_CNT];
+	bool xilfpga_old = false;
 
-	if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap))
-		return FPGA_FAIL;
+	if (zynqmp_pmufw_version() <= PMUFW_V1_0) {
+		puts("WARN: PMUFW v1.0 or less is detected\n");
+		puts("WARN: Not all bitstream formats are supported\n");
+		puts("WARN: Please upgrade PMUFW\n");
+		xilfpga_old = true;
+		if (zynqmp_validate_bitstream(desc, buf, bsize, bsize, &swap))
+			return FPGA_FAIL;
+		bsizeptr = (u32 *)&bsize;
+		flush_dcache_range((ulong)bsizeptr,
+				   (ulong)bsizeptr + sizeof(size_t));
+		bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
+	}
 
 	bin_buf = zynqmp_align_dma_buffer((u32 *)buf, bsize, swap);
-	bsizeptr = (u32 *)&bsize;
 
 	debug("%s called!\n", __func__);
 	flush_dcache_range(bin_buf, bin_buf + bsize);
-	flush_dcache_range((ulong)bsizeptr, (ulong)bsizeptr + sizeof(size_t));
 
 	buf_lo = (u32)bin_buf;
 	buf_hi = upper_32_bits(bin_buf);
-	bstype |= BIT(ZYNQMP_FPGA_BIT_NS);
-	ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi,
-			 (u32)(uintptr_t)bsizeptr, bstype, ret_payload);
+
+	if (xilfpga_old)
+		ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi,
+				 (u32)(uintptr_t)bsizeptr, bstype, ret_payload);
+	else
+		ret = invoke_smc(ZYNQMP_SIP_SVC_PM_FPGA_LOAD, buf_lo, buf_hi,
+				 (u32)bsize, 0, ret_payload);
+
 	if (ret)
 		debug("PL FPGA LOAD fail\n");
 
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index bfa5c91..b0fb73f 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -295,4 +295,13 @@
 	help
 	  Support for serdes found on MPC83xx SoCs.
 
+config FS_LOADER
+	bool "Enable loader driver for file system"
+	help
+	  This is file system generic loader which can be used to load
+	  the file image from the storage into target such as memory.
+
+	  The consumer driver would then use this loader to program whatever,
+	  ie. the FPGA device.
+
 endmenu
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index da4666f..acf24c4 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -56,3 +56,4 @@
 obj-$(CONFIG_GDSYS_IOEP) += gdsys_ioep.o
 obj-$(CONFIG_GDSYS_RXAUI_CTRL) += gdsys_rxaui_ctrl.o
 obj-$(CONFIG_MPC83XX_SERDES) += mpc83xx_serdes.o
+obj-$(CONFIG_FS_LOADER) += fs_loader.o
diff --git a/drivers/misc/fs_loader.c b/drivers/misc/fs_loader.c
new file mode 100644
index 0000000..5fe642b
--- /dev/null
+++ b/drivers/misc/fs_loader.c
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+#include <common.h>
+#include <dm.h>
+#include <errno.h>
+#include <blk.h>
+#include <fs.h>
+#include <fs_loader.h>
+#include <linux/string.h>
+#include <mapmem.h>
+#include <malloc.h>
+#include <spl.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+struct firmware_priv {
+	const char *name;	/* Filename */
+	u32 offset;		/* Offset of reading a file */
+};
+
+#ifdef CONFIG_CMD_UBIFS
+static int mount_ubifs(char *mtdpart, char *ubivol)
+{
+	int ret = ubi_part(mtdpart, NULL);
+
+	if (ret) {
+		debug("Cannot find mtd partition %s\n", mtdpart);
+		return ret;
+	}
+
+	return cmd_ubifs_mount(ubivol);
+}
+
+static int umount_ubifs(void)
+{
+	return cmd_ubifs_umount();
+}
+#else
+static int mount_ubifs(char *mtdpart, char *ubivol)
+{
+	debug("Error: Cannot load image: no UBIFS support\n");
+	return -ENOSYS;
+}
+#endif
+
+static int select_fs_dev(struct device_platdata *plat)
+{
+	int ret;
+
+	if (plat->phandlepart.phandle) {
+		ofnode node;
+
+		node = ofnode_get_by_phandle(plat->phandlepart.phandle);
+
+		int of_offset = ofnode_to_offset(node);
+
+		struct udevice *dev;
+
+		ret = device_get_global_by_of_offset(of_offset, &dev);
+		if (!ret) {
+			struct blk_desc *desc = blk_get_by_device(dev);
+			if (desc) {
+				ret = fs_set_blk_dev_with_part(desc,
+					plat->phandlepart.partition);
+			} else {
+				debug("%s: No device found\n", __func__);
+				return -ENODEV;
+			}
+		}
+	} else if (plat->mtdpart && plat->ubivol) {
+		ret = mount_ubifs(plat->mtdpart, plat->ubivol);
+		if (ret)
+			return ret;
+
+		ret = fs_set_blk_dev("ubi", NULL, FS_TYPE_UBIFS);
+	} else {
+		debug("Error: unsupported storage device.\n");
+		return -ENODEV;
+	}
+
+	if (ret)
+		debug("Error: could not access storage.\n");
+
+	return ret;
+}
+
+/**
+ * _request_firmware_prepare - Prepare firmware struct.
+ *
+ * @name: Name of firmware file.
+ * @dbuf: Address of buffer to load firmware into.
+ * @size: Size of buffer.
+ * @offset: Offset of a file for start reading into buffer.
+ * @firmwarep: Pointer to pointer to firmware image.
+ *
+ * Return: Negative value if fail, 0 for successful.
+ */
+static int _request_firmware_prepare(const char *name, void *dbuf,
+				    size_t size, u32 offset,
+				    struct firmware **firmwarep)
+{
+	if (!name || name[0] == '\0')
+		return -EINVAL;
+
+	/* No memory allocation is required if *firmwarep is allocated */
+	if (!(*firmwarep)) {
+		(*firmwarep) = calloc(1, sizeof(struct firmware));
+		if (!(*firmwarep))
+			return -ENOMEM;
+
+		(*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv));
+		if (!(*firmwarep)->priv) {
+			free(*firmwarep);
+			return -ENOMEM;
+		}
+	} else if (!(*firmwarep)->priv) {
+		(*firmwarep)->priv = calloc(1, sizeof(struct firmware_priv));
+		if (!(*firmwarep)->priv) {
+			free(*firmwarep);
+			return -ENOMEM;
+		}
+	}
+
+	((struct firmware_priv *)((*firmwarep)->priv))->name = name;
+	((struct firmware_priv *)((*firmwarep)->priv))->offset = offset;
+	(*firmwarep)->data = dbuf;
+	(*firmwarep)->size = size;
+
+	return 0;
+}
+
+/**
+ * release_firmware - Release the resource associated with a firmware image
+ * @firmware: Firmware resource to release
+ */
+void release_firmware(struct firmware *firmware)
+{
+	if (firmware) {
+		if (firmware->priv) {
+			free(firmware->priv);
+			firmware->priv = NULL;
+		}
+		free(firmware);
+	}
+}
+
+/**
+ * fw_get_filesystem_firmware - load firmware into an allocated buffer.
+ * @plat: Platform data such as storage and partition firmware loading from.
+ * @firmware: pointer to firmware image.
+ *
+ * Return: Size of total read, negative value when error.
+ */
+static int fw_get_filesystem_firmware(struct device_platdata *plat,
+				     struct firmware *firmware)
+{
+	struct firmware_priv *fw_priv = NULL;
+	loff_t actread;
+	char *storage_interface, *dev_part, *ubi_mtdpart, *ubi_volume;
+	int ret;
+
+	storage_interface = env_get("storage_interface");
+	dev_part = env_get("fw_dev_part");
+	ubi_mtdpart = env_get("fw_ubi_mtdpart");
+	ubi_volume = env_get("fw_ubi_volume");
+
+	if (storage_interface && dev_part) {
+		ret = fs_set_blk_dev(storage_interface, dev_part, FS_TYPE_ANY);
+	} else if (storage_interface && ubi_mtdpart && ubi_volume) {
+		ret = mount_ubifs(ubi_mtdpart, ubi_volume);
+		if (ret)
+			return ret;
+
+		if (!strcmp("ubi", storage_interface))
+			ret = fs_set_blk_dev(storage_interface, NULL,
+				FS_TYPE_UBIFS);
+		else
+			ret = -ENODEV;
+	} else {
+		ret = select_fs_dev(plat);
+	}
+
+	if (ret)
+		goto out;
+
+	fw_priv = firmware->priv;
+
+	ret = fs_read(fw_priv->name, (ulong)map_to_sysmem(firmware->data),
+			fw_priv->offset, firmware->size, &actread);
+	if (ret) {
+		debug("Error: %d Failed to read %s from flash %lld != %d.\n",
+		      ret, fw_priv->name, actread, firmware->size);
+	} else {
+		ret = actread;
+	}
+
+out:
+#ifdef CONFIG_CMD_UBIFS
+	umount_ubifs();
+#endif
+	return ret;
+}
+
+/**
+ * request_firmware_into_buf - Load firmware into a previously allocated buffer.
+ * @plat: Platform data such as storage and partition firmware loading from.
+ * @name: Name of firmware file.
+ * @buf: Address of buffer to load firmware into.
+ * @size: Size of buffer.
+ * @offset: Offset of a file for start reading into buffer.
+ * @firmwarep: Pointer to firmware image.
+ *
+ * The firmware is loaded directly into the buffer pointed to by @buf and
+ * the @firmwarep data member is pointed at @buf.
+ *
+ * Return: Size of total read, negative value when error.
+ */
+int request_firmware_into_buf(struct device_platdata *plat,
+			      const char *name,
+			      void *buf, size_t size, u32 offset,
+			      struct firmware **firmwarep)
+{
+	int ret;
+
+	if (!plat)
+		return -EINVAL;
+
+	ret = _request_firmware_prepare(name, buf, size, offset, firmwarep);
+	if (ret < 0) /* error */
+		return ret;
+
+	ret = fw_get_filesystem_firmware(plat, *firmwarep);
+
+	return ret;
+}
+
+static int fs_loader_ofdata_to_platdata(struct udevice *dev)
+{
+	const char *fs_loader_path;
+	u32 phandlepart[2];
+
+	fs_loader_path = ofnode_get_chosen_prop("firmware-loader");
+
+	if (fs_loader_path) {
+		ofnode fs_loader_node;
+
+		fs_loader_node = ofnode_path(fs_loader_path);
+		if (ofnode_valid(fs_loader_node)) {
+			struct device_platdata *plat;
+			plat = dev->platdata;
+
+			if (!ofnode_read_u32_array(fs_loader_node,
+						  "phandlepart",
+						  phandlepart, 2)) {
+				plat->phandlepart.phandle = phandlepart[0];
+				plat->phandlepart.partition = phandlepart[1];
+			}
+
+			plat->mtdpart = (char *)ofnode_read_string(
+					 fs_loader_node, "mtdpart");
+
+			plat->ubivol = (char *)ofnode_read_string(
+					 fs_loader_node, "ubivol");
+		}
+	}
+
+	return 0;
+}
+
+static int fs_loader_probe(struct udevice *dev)
+{
+	return 0;
+};
+
+static const struct udevice_id fs_loader_ids[] = {
+	{ .compatible = "u-boot,fs-loader"},
+	{ }
+};
+
+U_BOOT_DRIVER(fs_loader) = {
+	.name			= "fs-loader",
+	.id			= UCLASS_FS_FIRMWARE_LOADER,
+	.of_match		= fs_loader_ids,
+	.probe			= fs_loader_probe,
+	.ofdata_to_platdata	= fs_loader_ofdata_to_platdata,
+	.platdata_auto_alloc_size	= sizeof(struct device_platdata),
+};
+
+UCLASS_DRIVER(fs_loader) = {
+	.id		= UCLASS_FS_FIRMWARE_LOADER,
+	.name		= "fs-loader",
+};
diff --git a/drivers/mmc/omap_hsmmc.c b/drivers/mmc/omap_hsmmc.c
index 4d171f45..ec853d0 100644
--- a/drivers/mmc/omap_hsmmc.c
+++ b/drivers/mmc/omap_hsmmc.c
@@ -83,7 +83,6 @@
 #if CONFIG_IS_ENABLED(DM_MMC)
 	struct gpio_desc cd_gpio;	/* Change Detect GPIO */
 	struct gpio_desc wp_gpio;	/* Write Protect GPIO */
-	bool cd_inverted;
 #else
 	int cd_gpio;
 	int wp_gpio;
@@ -216,6 +215,10 @@
 	/* for cairo board, we need to set up 1.8 Volt bias level on MMC1 */
 	pbias_lite &= ~PBIASLITEVMODE0;
 #endif
+#ifdef CONFIG_TARGET_OMAP3_LOGIC
+	/* For Logic PD board, 1.8V bias to go enable gpio127 for mmc_cd */
+	pbias_lite &= ~PBIASLITEVMODE1;
+#endif
 #ifdef CONFIG_MMC_OMAP36XX_PINS
 	if (get_cpu_family() == CPU_OMAP36XX) {
 		/* Disable extended drain IO before changing PBIAS */
@@ -1364,17 +1367,15 @@
 #if CONFIG_IS_ENABLED(DM_MMC)
 static int omap_hsmmc_getcd(struct udevice *dev)
 {
-	struct omap_hsmmc_data *priv = dev_get_priv(dev);
 	int value = -1;
 #if CONFIG_IS_ENABLED(DM_GPIO)
+	struct omap_hsmmc_data *priv = dev_get_priv(dev);
 	value = dm_gpio_get_value(&priv->cd_gpio);
 #endif
 	/* if no CD return as 1 */
 	if (value < 0)
 		return 1;
 
-	if (priv->cd_inverted)
-		return !value;
 	return value;
 }
 
@@ -1856,10 +1857,6 @@
 	}
 #endif
 
-#ifdef OMAP_HSMMC_USE_GPIO
-	plat->cd_inverted = fdtdec_get_bool(fdt, node, "cd-inverted");
-#endif
-
 	return 0;
 }
 #endif
@@ -1888,9 +1885,6 @@
 	priv->base_addr = plat->base_addr;
 	priv->controller_flags = plat->controller_flags;
 	priv->hw_rev = plat->hw_rev;
-#ifdef OMAP_HSMMC_USE_GPIO
-	priv->cd_inverted = plat->cd_inverted;
-#endif
 
 #ifdef CONFIG_BLK
 	mmc = plat->mmc;
diff --git a/drivers/net/cpsw.c b/drivers/net/cpsw.c
index c31695e..8e2a48c 100644
--- a/drivers/net/cpsw.c
+++ b/drivers/net/cpsw.c
@@ -1008,6 +1008,25 @@
 	return 1;
 }
 
+static void cpsw_phy_addr_update(struct cpsw_priv *priv)
+{
+	struct cpsw_platform_data *data = &priv->data;
+	u16 alive = mdio_regs->alive & GENMASK(15, 0);
+	int active = data->active_slave;
+	int new_addr = ffs(alive) - 1;
+
+	/*
+	 * If there is only one phy alive and its address does not match
+	 * that of active slave, then phy address can safely be updated.
+	 */
+	if (hweight16(alive) == 1 &&
+	    data->slave_data[active].phy_addr != new_addr) {
+		printf("Updated phy address for CPSW#%d, old: %d, new: %d\n",
+		       active, data->slave_data[active].phy_addr, new_addr);
+		data->slave_data[active].phy_addr = new_addr;
+	}
+}
+
 int _cpsw_register(struct cpsw_priv *priv)
 {
 	struct cpsw_slave	*slave;
@@ -1034,6 +1053,9 @@
 	}
 
 	cpsw_mdio_init(priv->dev->name, data->mdio_base, data->mdio_div);
+
+	cpsw_phy_addr_update(priv);
+
 	priv->bus = miiphy_get_dev_by_name(priv->dev->name);
 	for_active_slave(slave, priv)
 		cpsw_phy_init(priv, slave);
@@ -1458,6 +1480,13 @@
 	return 0;
 }
 
+int cpsw_get_slave_phy_addr(struct udevice *dev, int slave)
+{
+	struct cpsw_priv *priv = dev_get_priv(dev);
+	struct cpsw_platform_data *data = &priv->data;
+
+	return data->slave_data[slave].phy_addr;
+}
 
 static const struct udevice_id cpsw_eth_ids[] = {
 	{ .compatible = "ti,cpsw" },
diff --git a/drivers/net/zynq_gem.c b/drivers/net/zynq_gem.c
index 68d1c2f..e22d048 100644
--- a/drivers/net/zynq_gem.c
+++ b/drivers/net/zynq_gem.c
@@ -699,14 +699,17 @@
 	/* Hardcode for now */
 	priv->phyaddr = -1;
 
-	if (dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
-				       &phandle_args)) {
-		debug("phy-handle does not exist %s\n", dev->name);
-		return -ENOENT;
+	if (!dev_read_phandle_with_args(dev, "phy-handle", NULL, 0, 0,
+					&phandle_args)) {
+		debug("phy-handle does exist %s\n", dev->name);
+		priv->phyaddr = ofnode_read_u32_default(phandle_args.node,
+							"reg", -1);
+		priv->phy_of_node = phandle_args.node;
+		priv->max_speed = ofnode_read_u32_default(phandle_args.node,
+							  "max-speed",
+							  SPEED_1000);
 	}
 
-	priv->phyaddr = ofnode_read_u32_default(phandle_args.node, "reg", -1);
-	priv->phy_of_node = phandle_args.node;
 	phy_mode = dev_read_prop(dev, "phy-mode", NULL);
 	if (phy_mode)
 		pdata->phy_interface = phy_get_interface_by_name(phy_mode);
@@ -716,7 +719,6 @@
 	}
 	priv->interface = pdata->phy_interface;
 
-	priv->max_speed = dev_read_u32_default(dev, "max-speed", SPEED_1000);
 	priv->int_pcs = dev_read_bool(dev, "is-internal-pcspma");
 
 	printf("ZYNQ GEM: %lx, phyaddr %x, interface %s\n", (ulong)priv->iobase,
diff --git a/drivers/pinctrl/broadcom/Kconfig b/drivers/pinctrl/broadcom/Kconfig
index 4056782..b01b725 100644
--- a/drivers/pinctrl/broadcom/Kconfig
+++ b/drivers/pinctrl/broadcom/Kconfig
@@ -5,3 +5,11 @@
 	help
 	   Support pin multiplexing and pin configuration control on
 	   Broadcom's 283x family of SoCs.
+
+config PINCTRL_BCM6838
+	depends on ARCH_BMIPS && PINCTRL_FULL && OF_CONTROL
+	default y
+	bool "Broadcom 6838 family pin control driver"
+	help
+	   Support pin multiplexing and pin configuration control on
+	   Broadcom's 6838 family of SoCs.
diff --git a/drivers/pinctrl/broadcom/Makefile b/drivers/pinctrl/broadcom/Makefile
index 99c7c23..f94f3ce 100644
--- a/drivers/pinctrl/broadcom/Makefile
+++ b/drivers/pinctrl/broadcom/Makefile
@@ -5,3 +5,4 @@
 # https://spdx.org/licenses
 
 obj-$(CONFIG_PINCTRL_BCM283X) += pinctrl-bcm283x.o
+obj-$(CONFIG_PINCTRL_BCM6838) += pinctrl-bcm6838.o
diff --git a/drivers/pinctrl/broadcom/pinctrl-bcm6838.c b/drivers/pinctrl/broadcom/pinctrl-bcm6838.c
new file mode 100644
index 0000000..48c0b6b
--- /dev/null
+++ b/drivers/pinctrl/broadcom/pinctrl-bcm6838.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <common.h>
+#include <dm.h>
+#include <regmap.h>
+#include <syscon.h>
+#include <dm/pinctrl.h>
+
+#define BCM6838_CMD_LOAD_MUX            0x21
+
+#define BCM6838_FUNC_OFFS               12
+#define BCM6838_FUNC_MASK               (0x37 << BCM6838_FUNC_OFFS)
+#define BCM6838_PIN_OFFS                 0
+#define BCM6838_PIN_MASK                (0xfff << BCM6838_PIN_OFFS)
+
+#define BCM6838_MAX_PIN_NAME_LEN         8
+static char bcm6838_pin_name[BCM6838_MAX_PIN_NAME_LEN];
+
+#define BCM6838_MAX_FUNC_NAME_LEN        8
+static char bcm6838_func_name[BCM6838_MAX_FUNC_NAME_LEN];
+
+struct bcm6838_test_port_hw {
+	unsigned long port_blk_data1;
+	unsigned long port_blk_data2;
+	unsigned long port_command;
+};
+
+static const struct bcm6838_test_port_hw bcm6838_hw = {
+	.port_blk_data1 = 0x10,
+	.port_blk_data2 = 0x14,
+	.port_command   = 0x18
+};
+
+struct bcm6838_pinctrl_priv {
+	const struct bcm6838_test_port_hw *hw;
+	struct regmap *regmap;
+	u32 pins_count;
+	u32 functions_count;
+};
+
+int bcm6838_pinctrl_get_pins_count(struct udevice *dev)
+{
+	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->pins_count;
+}
+
+const char *bcm6838_pinctrl_get_pin_name(struct udevice *dev,
+					 unsigned int selector)
+{
+	snprintf(bcm6838_pin_name, BCM6838_MAX_PIN_NAME_LEN, "%u", selector);
+	return bcm6838_pin_name;
+}
+
+int bcm6838_pinctrl_get_functions_count(struct udevice *dev)
+{
+	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
+
+	return priv->functions_count;
+}
+
+const char *bcm6838_pinctrl_get_function_name(struct udevice *dev,
+					      unsigned int selector)
+{
+	snprintf(bcm6838_func_name, BCM6838_MAX_FUNC_NAME_LEN, "%u", selector);
+	return bcm6838_func_name;
+}
+
+int bcm6838_pinctrl_pinmux_set(struct udevice *dev,
+			       unsigned int pin_selector,
+			       unsigned int func_selector)
+{
+	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct bcm6838_test_port_hw *hw = priv->hw;
+	unsigned int data;
+
+	regmap_write(priv->regmap, hw->port_blk_data1, 0);
+	data = (func_selector << BCM6838_FUNC_OFFS) & BCM6838_FUNC_MASK;
+	data |= (pin_selector << BCM6838_PIN_OFFS) & BCM6838_PIN_MASK;
+	regmap_write(priv->regmap, hw->port_blk_data2, data);
+	regmap_write(priv->regmap, hw->port_command, BCM6838_CMD_LOAD_MUX);
+
+	return 0;
+}
+
+int bcm6838_pinctrl_probe(struct udevice *dev)
+{
+	struct bcm6838_pinctrl_priv *priv = dev_get_priv(dev);
+	const struct bcm6838_test_port_hw *hw =
+		(const struct bcm6838_test_port_hw *)dev_get_driver_data(dev);
+	int err;
+	u32 phandle;
+	ofnode node;
+
+	err = ofnode_read_u32(dev_ofnode(dev), "regmap", &phandle);
+	if (err) {
+		dev_err(dev, "%s: unable to read regmap\n", __func__);
+		goto out;
+	}
+
+	node = ofnode_get_by_phandle(phandle);
+	if (!ofnode_valid(node)) {
+		dev_err(dev, "%s: unable to find node\n", __func__);
+		err = -EINVAL;
+		goto out;
+	}
+
+	priv->regmap = syscon_node_to_regmap(node);
+	if (!priv->regmap) {
+		dev_err(dev, "%s: unable to find regmap\n", __func__);
+		err = -ENODEV;
+		goto out;
+	}
+
+	err = ofnode_read_u32(dev_ofnode(dev), "brcm,pins-count",
+			      &priv->pins_count);
+	if (err) {
+		dev_err(dev, "%s: unable to read brcm,pins-count\n",
+			__func__);
+		goto out;
+	}
+
+	err = ofnode_read_u32(dev_ofnode(dev), "brcm,functions-count",
+			      &priv->functions_count);
+	if (err) {
+		dev_err(dev, "%s: unable to read brcm,functions-count\n",
+			__func__);
+		goto out;
+	}
+
+	priv->hw = hw;
+
+ out:
+	return err;
+}
+
+const struct pinctrl_ops bcm6838_pinctrl_ops = {
+	.set_state = pinctrl_generic_set_state,
+	.get_pins_count = bcm6838_pinctrl_get_pins_count,
+	.get_pin_name = bcm6838_pinctrl_get_pin_name,
+	.get_functions_count = bcm6838_pinctrl_get_functions_count,
+	.get_function_name = bcm6838_pinctrl_get_function_name,
+	.pinmux_set = bcm6838_pinctrl_pinmux_set,
+};
+
+static const struct udevice_id bcm6838_pinctrl_match[] = {
+	{
+		.compatible = "brcm,bcm6838-pinctrl",
+		.data = (ulong)&bcm6838_hw,
+	},
+	{ /* sentinel */ }
+};
+
+U_BOOT_DRIVER(bcm6838_pinctrl) = {
+	.name = "bcm6838_pinctrl",
+	.id = UCLASS_PINCTRL,
+	.of_match = bcm6838_pinctrl_match,
+	.ops = &bcm6838_pinctrl_ops,
+	.priv_auto_alloc_size = sizeof(struct bcm6838_pinctrl_priv),
+	.probe = bcm6838_pinctrl_probe,
+};
diff --git a/drivers/pinctrl/pinctrl-sandbox.c b/drivers/pinctrl/pinctrl-sandbox.c
index 468fa2a..755ac08 100644
--- a/drivers/pinctrl/pinctrl-sandbox.c
+++ b/drivers/pinctrl/pinctrl-sandbox.c
@@ -14,6 +14,7 @@
 	"SDA",
 	"TX",
 	"RX",
+	"W1"
 };
 
 static const char * const sandbox_groups[] = {
@@ -21,12 +22,14 @@
 	"serial_a",
 	"serial_b",
 	"spi",
+	"w1",
 };
 
 static const char * const sandbox_functions[] = {
 	"i2c",
 	"serial",
 	"spi",
+	"w1",
 };
 
 static const struct pinconf_param sandbox_conf_params[] = {
diff --git a/drivers/rtc/pl031.c b/drivers/rtc/pl031.c
index 8955805..8bf04f2 100644
--- a/drivers/rtc/pl031.c
+++ b/drivers/rtc/pl031.c
@@ -8,13 +8,11 @@
 
 #include <common.h>
 #include <command.h>
+#include <dm.h>
+#include <errno.h>
 #include <rtc.h>
-
-#if defined(CONFIG_CMD_DATE)
-
-#ifndef CONFIG_SYS_RTC_PL031_BASE
-#error CONFIG_SYS_RTC_PL031_BASE is not defined!
-#endif
+#include <asm/io.h>
+#include <asm/types.h>
 
 /*
  * Register definitions
@@ -30,78 +28,114 @@
 
 #define RTC_CR_START	(1 << 0)
 
-#define	RTC_WRITE_REG(addr, val) \
-			(*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)) = (val))
-#define	RTC_READ_REG(addr)	\
-			(*(volatile unsigned int *)(CONFIG_SYS_RTC_PL031_BASE + (addr)))
+struct pl031_platdata {
+	phys_addr_t base;
+};
 
-static int pl031_initted = 0;
+static inline u32 pl031_read_reg(struct udevice *dev, int reg)
+{
+	struct pl031_platdata *pdata = dev_get_platdata(dev);
 
-/* Enable RTC Start in Control register*/
-void rtc_init(void)
+	return readl(pdata->base + reg);
+}
+
+static inline u32 pl031_write_reg(struct udevice *dev, int reg, u32 value)
 {
-	RTC_WRITE_REG(RTC_CR, RTC_CR_START);
+	struct pl031_platdata *pdata = dev_get_platdata(dev);
 
-	pl031_initted = 1;
+	return writel(value, pdata->base + reg);
 }
 
 /*
- * Reset the RTC. We set the date back to 1970-01-01.
+ * Probe RTC device
+ */
+static int pl031_probe(struct udevice *dev)
+{
+	/* Enable RTC Start in Control register*/
+	pl031_write_reg(dev, RTC_CR, RTC_CR_START);
+
+	return 0;
+}
+
+/*
+ * Get the current time from the RTC
  */
-void rtc_reset(void)
+static int pl031_get(struct udevice *dev, struct rtc_time *tm)
 {
-	RTC_WRITE_REG(RTC_LR, 0x00);
-	if(!pl031_initted)
-		rtc_init();
+	unsigned long tim;
+
+	if (!tm)
+		return -EINVAL;
+
+	tim = pl031_read_reg(dev, RTC_DR);
+
+	rtc_to_tm(tim, tm);
+
+	debug("Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+	      tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+	      tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+	return 0;
 }
 
 /*
  * Set the RTC
-*/
-int rtc_set(struct rtc_time *tmp)
+ */
+static int pl031_set(struct udevice *dev, const struct rtc_time *tm)
 {
 	unsigned long tim;
 
-	if(!pl031_initted)
-		rtc_init();
+	if (!tm)
+		return -EINVAL;
 
-	if (tmp == NULL) {
-		puts("Error setting the date/time\n");
-		return -1;
-	}
+	debug("Set DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
+	      tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_wday,
+	      tm->tm_hour, tm->tm_min, tm->tm_sec);
 
 	/* Calculate number of seconds this incoming time represents */
-	tim = rtc_mktime(tmp);
+	tim = rtc_mktime(tm);
 
-	RTC_WRITE_REG(RTC_LR, tim);
+	pl031_write_reg(dev, RTC_LR, tim);
 
-	return -1;
+	return 0;
 }
 
 /*
- * Get the current time from the RTC
+ * Reset the RTC. We set the date back to 1970-01-01.
  */
-int rtc_get(struct rtc_time *tmp)
+static int pl031_reset(struct udevice *dev)
 {
-	ulong tim;
+	pl031_write_reg(dev, RTC_LR, 0);
 
-	if(!pl031_initted)
-		rtc_init();
+	return 0;
+}
 
-	if (tmp == NULL) {
-		puts("Error getting the date/time\n");
-		return -1;
-	}
+static const struct rtc_ops pl031_ops = {
+	.get = pl031_get,
+	.set = pl031_set,
+	.reset = pl031_reset,
+};
 
-	tim = RTC_READ_REG(RTC_DR);
+static const struct udevice_id pl031_ids[] = {
+	{ .compatible = "arm,pl031" },
+	{ }
+};
 
-	rtc_to_tm(tim, tmp);
+static int pl031_ofdata_to_platdata(struct udevice *dev)
+{
+	struct pl031_platdata *pdata = dev_get_platdata(dev);
 
-	debug ( "Get DATE: %4d-%02d-%02d (wday=%d)  TIME: %2d:%02d:%02d\n",
-		tmp->tm_year, tmp->tm_mon, tmp->tm_mday, tmp->tm_wday,
-		tmp->tm_hour, tmp->tm_min, tmp->tm_sec);
+	pdata->base = dev_read_addr(dev);
 
 	return 0;
 }
 
-#endif
+U_BOOT_DRIVER(rtc_pl031) = {
+	.name	= "rtc-pl031",
+	.id	= UCLASS_RTC,
+	.of_match = pl031_ids,
+	.probe	= pl031_probe,
+	.ofdata_to_platdata = pl031_ofdata_to_platdata,
+	.platdata_auto_alloc_size = sizeof(struct pl031_platdata),
+	.ops	= &pl031_ops,
+};
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 399dfd6..1b54d18 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -17,7 +17,7 @@
 
 /* Information about the efi console */
 struct serial_efi_priv {
-	struct efi_simple_input_interface *con_in;
+	struct efi_simple_text_input_protocol *con_in;
 	struct efi_simple_text_output_protocol *con_out;
 	struct efi_input_key key;
 	bool have_key;
diff --git a/drivers/serial/serial_omap.c b/drivers/serial/serial_omap.c
index d8a047b..af3c755 100644
--- a/drivers/serial/serial_omap.c
+++ b/drivers/serial/serial_omap.c
@@ -104,6 +104,7 @@
 	{ .compatible = "ti,am3352-uart", },
 	{ .compatible = "ti,am4372-uart", },
 	{ .compatible = "ti,dra742-uart", },
+	{ .compatible = "ti,am654-uart", },
 	{}
 };
 #endif /* OF_CONTROL && !OF_PLATDATA */
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index dcd719f..7d4d47d 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -125,6 +125,14 @@
 	  to access the SPI NOR flash, MMC-over-SPI on platforms based on
 	  Microchip PIC32 family devices.
 
+config PL022_SPI
+	bool "ARM AMBA PL022 SSP controller driver"
+	depends on ARM
+	help
+	  This selects the ARM(R) AMBA(R) PrimeCell PL022 SSP
+	  controller. If you have an embedded system with an AMBA(R)
+	  bus and a PL022 controller, say Y or M here.
+
 config RENESAS_RPC_SPI
 	bool "Renesas RPC SPI driver"
 	depends on RCAR_GEN3
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 728e30c..6679987 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -38,6 +38,7 @@
 obj-$(CONFIG_ATCSPI200_SPI) += atcspi200_spi.o
 obj-$(CONFIG_OMAP3_SPI) += omap3_spi.o
 obj-$(CONFIG_PIC32_SPI) += pic32_spi.o
+obj-$(CONFIG_PL022_SPI) += pl022_spi.o
 obj-$(CONFIG_RENESAS_RPC_SPI) += renesas_rpc_spi.o
 obj-$(CONFIG_ROCKCHIP_SPI) += rk_spi.o
 obj-$(CONFIG_SANDBOX_SPI) += sandbox_spi.o
diff --git a/drivers/spi/pl022_spi.c b/drivers/spi/pl022_spi.c
new file mode 100644
index 0000000..86b71d2
--- /dev/null
+++ b/drivers/spi/pl022_spi.c
@@ -0,0 +1,338 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2012
+ * Armando Visconti, ST Microelectronics, armando.visconti@st.com.
+ *
+ * (C) Copyright 2018
+ * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com
+ *
+ * Driver for ARM PL022 SPI Controller.
+ */
+
+#include <asm/io.h>
+#include <clk.h>
+#include <common.h>
+#include <dm.h>
+#include <dm/platform_data/pl022_spi.h>
+#include <fdtdec.h>
+#include <linux/bitops.h>
+#include <linux/bug.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <spi.h>
+
+#define SSP_CR0		0x000
+#define SSP_CR1		0x004
+#define SSP_DR		0x008
+#define SSP_SR		0x00C
+#define SSP_CPSR	0x010
+#define SSP_IMSC	0x014
+#define SSP_RIS		0x018
+#define SSP_MIS		0x01C
+#define SSP_ICR		0x020
+#define SSP_DMACR	0x024
+#define SSP_CSR		0x030 /* vendor extension */
+#define SSP_ITCR	0x080
+#define SSP_ITIP	0x084
+#define SSP_ITOP	0x088
+#define SSP_TDR		0x08C
+
+#define SSP_PID0	0xFE0
+#define SSP_PID1	0xFE4
+#define SSP_PID2	0xFE8
+#define SSP_PID3	0xFEC
+
+#define SSP_CID0	0xFF0
+#define SSP_CID1	0xFF4
+#define SSP_CID2	0xFF8
+#define SSP_CID3	0xFFC
+
+/* SSP Control Register 0  - SSP_CR0 */
+#define SSP_CR0_SPO		(0x1 << 6)
+#define SSP_CR0_SPH		(0x1 << 7)
+#define SSP_CR0_BIT_MODE(x)	((x) - 1)
+#define SSP_SCR_MIN		(0x00)
+#define SSP_SCR_MAX		(0xFF)
+#define SSP_SCR_SHFT		8
+#define DFLT_CLKRATE		2
+
+/* SSP Control Register 1  - SSP_CR1 */
+#define SSP_CR1_MASK_SSE	(0x1 << 1)
+
+#define SSP_CPSR_MIN		(0x02)
+#define SSP_CPSR_MAX		(0xFE)
+#define DFLT_PRESCALE		(0x40)
+
+/* SSP Status Register - SSP_SR */
+#define SSP_SR_MASK_TFE		(0x1 << 0) /* Transmit FIFO empty */
+#define SSP_SR_MASK_TNF		(0x1 << 1) /* Transmit FIFO not full */
+#define SSP_SR_MASK_RNE		(0x1 << 2) /* Receive FIFO not empty */
+#define SSP_SR_MASK_RFF		(0x1 << 3) /* Receive FIFO full */
+#define SSP_SR_MASK_BSY		(0x1 << 4) /* Busy Flag */
+
+struct pl022_spi_slave {
+	void *base;
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct clk clk;
+#else
+	unsigned int freq;
+#endif
+};
+
+/*
+ * ARM PL022 exists in different 'flavors'.
+ * This drivers currently support the standard variant (0x00041022), that has a
+ * 16bit wide and 8 locations deep TX/RX FIFO.
+ */
+static int pl022_is_supported(struct pl022_spi_slave *ps)
+{
+	/* PL022 version is 0x00041022 */
+	if ((readw(ps->base + SSP_PID0) == 0x22) &&
+	    (readw(ps->base + SSP_PID1) == 0x10) &&
+	    ((readw(ps->base + SSP_PID2) & 0xf) == 0x04) &&
+	    (readw(ps->base + SSP_PID3) == 0x00))
+		return 1;
+
+	return 0;
+}
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static int pl022_spi_ofdata_to_platdata(struct udevice *bus)
+{
+	struct pl022_spi_pdata *plat = bus->platdata;
+	const void *fdt = gd->fdt_blob;
+	int node = dev_of_offset(bus);
+
+	plat->addr = fdtdec_get_addr_size(fdt, node, "reg", &plat->size);
+
+	return clk_get_by_index(bus, 0, &plat->clk);
+}
+#endif
+
+static int pl022_spi_probe(struct udevice *bus)
+{
+	struct pl022_spi_pdata *plat = dev_get_platdata(bus);
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+
+	ps->base = ioremap(plat->addr, plat->size);
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	ps->clk = plat->clk;
+#else
+	ps->freq = plat->freq;
+#endif
+
+	/* Check the PL022 version */
+	if (!pl022_is_supported(ps))
+		return -ENOTSUPP;
+
+	/* 8 bits per word, high polarity and default clock rate */
+	writew(SSP_CR0_BIT_MODE(8), ps->base + SSP_CR0);
+	writew(DFLT_PRESCALE, ps->base + SSP_CPSR);
+
+	return 0;
+}
+
+static void flush(struct pl022_spi_slave *ps)
+{
+	do {
+		while (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE)
+			readw(ps->base + SSP_DR);
+	} while (readw(ps->base + SSP_SR) & SSP_SR_MASK_BSY);
+}
+
+static int pl022_spi_claim_bus(struct udevice *dev)
+{
+	struct udevice *bus = dev->parent;
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+	u16 reg;
+
+	/* Enable the SPI hardware */
+	reg = readw(ps->base + SSP_CR1);
+	reg |= SSP_CR1_MASK_SSE;
+	writew(reg, ps->base + SSP_CR1);
+
+	flush(ps);
+
+	return 0;
+}
+
+static int pl022_spi_release_bus(struct udevice *dev)
+{
+	struct udevice *bus = dev->parent;
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+	u16 reg;
+
+	flush(ps);
+
+	/* Disable the SPI hardware */
+	reg = readw(ps->base + SSP_CR1);
+	reg &= ~SSP_CR1_MASK_SSE;
+	writew(reg, ps->base + SSP_CR1);
+
+	return 0;
+}
+
+static int pl022_spi_xfer(struct udevice *dev, unsigned int bitlen,
+			  const void *dout, void *din, unsigned long flags)
+{
+	struct udevice *bus = dev->parent;
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+	u32		len_tx = 0, len_rx = 0, len;
+	u32		ret = 0;
+	const u8	*txp = dout;
+	u8		*rxp = din, value;
+
+	if (bitlen == 0)
+		/* Finish any previously submitted transfers */
+		return 0;
+
+	/*
+	 * TODO: The controller can do non-multiple-of-8 bit
+	 * transfers, but this driver currently doesn't support it.
+	 *
+	 * It's also not clear how such transfers are supposed to be
+	 * represented as a stream of bytes...this is a limitation of
+	 * the current SPI interface.
+	 */
+	if (bitlen % 8) {
+		/* Errors always terminate an ongoing transfer */
+		flags |= SPI_XFER_END;
+		return -1;
+	}
+
+	len = bitlen / 8;
+
+	while (len_tx < len) {
+		if (readw(ps->base + SSP_SR) & SSP_SR_MASK_TNF) {
+			value = txp ? *txp++ : 0;
+			writew(value, ps->base + SSP_DR);
+			len_tx++;
+		}
+
+		if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) {
+			value = readw(ps->base + SSP_DR);
+			if (rxp)
+				*rxp++ = value;
+			len_rx++;
+		}
+	}
+
+	while (len_rx < len_tx) {
+		if (readw(ps->base + SSP_SR) & SSP_SR_MASK_RNE) {
+			value = readw(ps->base + SSP_DR);
+			if (rxp)
+				*rxp++ = value;
+			len_rx++;
+		}
+	}
+
+	return ret;
+}
+
+static inline u32 spi_rate(u32 rate, u16 cpsdvsr, u16 scr)
+{
+	return rate / (cpsdvsr * (1 + scr));
+}
+
+static int pl022_spi_set_speed(struct udevice *bus, uint speed)
+{
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+	u16 scr = SSP_SCR_MIN, cr0 = 0, cpsr = SSP_CPSR_MIN, best_scr = scr,
+	    best_cpsr = cpsr;
+	u32 min, max, best_freq = 0, tmp;
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	u32 rate = clk_get_rate(&ps->clk);
+#else
+	u32 rate = ps->freq;
+#endif
+	bool found = false;
+
+	max = spi_rate(rate, SSP_CPSR_MIN, SSP_SCR_MIN);
+	min = spi_rate(rate, SSP_CPSR_MAX, SSP_SCR_MAX);
+
+	if (speed > max || speed < min) {
+		pr_err("Tried to set speed to %dHz but min=%d and max=%d\n",
+		       speed, min, max);
+		return -EINVAL;
+	}
+
+	while (cpsr <= SSP_CPSR_MAX && !found) {
+		while (scr <= SSP_SCR_MAX) {
+			tmp = spi_rate(rate, cpsr, scr);
+
+			if (abs(speed - tmp) < abs(speed - best_freq)) {
+				best_freq = tmp;
+				best_cpsr = cpsr;
+				best_scr = scr;
+
+				if (tmp == speed) {
+					found = true;
+					break;
+				}
+			}
+
+			scr++;
+		}
+		cpsr += 2;
+		scr = SSP_SCR_MIN;
+	}
+
+	writew(best_cpsr, ps->base + SSP_CPSR);
+	cr0 = readw(ps->base + SSP_CR0);
+	writew(cr0 | (best_scr << SSP_SCR_SHFT), ps->base + SSP_CR0);
+
+	return 0;
+}
+
+static int pl022_spi_set_mode(struct udevice *bus, uint mode)
+{
+	struct pl022_spi_slave *ps = dev_get_priv(bus);
+	u16 reg;
+
+	reg = readw(ps->base + SSP_CR0);
+	reg &= ~(SSP_CR0_SPH | SSP_CR0_SPO);
+	if (mode & SPI_CPHA)
+		reg |= SSP_CR0_SPH;
+	if (mode & SPI_CPOL)
+		reg |= SSP_CR0_SPO;
+	writew(reg, ps->base + SSP_CR0);
+
+	return 0;
+}
+
+static int pl022_cs_info(struct udevice *bus, uint cs,
+			 struct spi_cs_info *info)
+{
+	return 0;
+}
+
+static const struct dm_spi_ops pl022_spi_ops = {
+	.claim_bus      = pl022_spi_claim_bus,
+	.release_bus    = pl022_spi_release_bus,
+	.xfer           = pl022_spi_xfer,
+	.set_speed      = pl022_spi_set_speed,
+	.set_mode       = pl022_spi_set_mode,
+	.cs_info        = pl022_cs_info,
+};
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+static const struct udevice_id pl022_spi_ids[] = {
+	{ .compatible = "arm,pl022-spi" },
+	{ }
+};
+#endif
+
+U_BOOT_DRIVER(pl022_spi) = {
+	.name   = "pl022_spi",
+	.id     = UCLASS_SPI,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.of_match = pl022_spi_ids,
+#endif
+	.ops    = &pl022_spi_ops,
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	.ofdata_to_platdata = pl022_spi_ofdata_to_platdata,
+#endif
+	.platdata_auto_alloc_size = sizeof(struct pl022_spi_pdata),
+	.priv_auto_alloc_size = sizeof(struct pl022_spi_slave),
+	.probe  = pl022_spi_probe,
+};
diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c
index f1d3ad3..0c36a5d 100644
--- a/drivers/video/vidconsole-uclass.c
+++ b/drivers/video/vidconsole-uclass.c
@@ -213,6 +213,14 @@
 		s++;    /* ; */
 		s = parsenum(s, &col);
 
+		/*
+		 * Ensure we stay in the bounds of the screen.
+		 */
+		if (row >= priv->rows)
+			row = priv->rows - 1;
+		if (col >= priv->cols)
+			col = priv->cols - 1;
+
 		priv->ycur = row * priv->y_charsize;
 		priv->xcur_frac = priv->xstart_frac +
 			VID_TO_POS(col * priv->x_charsize);
diff --git a/drivers/w1-eeprom/Kconfig b/drivers/w1-eeprom/Kconfig
new file mode 100644
index 0000000..4b7f3c4
--- /dev/null
+++ b/drivers/w1-eeprom/Kconfig
@@ -0,0 +1,29 @@
+#
+# EEPROM subsystem configuration
+#
+
+menu "1-wire EEPROM support"
+
+config W1_EEPROM
+	bool "Enable support for EEPROMs on 1wire interface"
+	depends on DM
+	help
+	  Support for the EEPROMs connected on 1-wire Dallas protocol interface
+
+if W1_EEPROM
+
+config W1_EEPROM_DS24XXX
+	bool "Enable Maxim DS24 families EEPROM support"
+	depends on W1
+	help
+	  Maxim DS24 EEPROMs 1-Wire EEPROM support
+
+config W1_EEPROM_SANDBOX
+	bool "Enable sandbox onewire EEPROM driver"
+	depends on W1
+	help
+	  Sandbox driver for a onewire EEPROM memory
+
+endif
+
+endmenu
diff --git a/drivers/w1-eeprom/Makefile b/drivers/w1-eeprom/Makefile
new file mode 100644
index 0000000..03cc4c8
--- /dev/null
+++ b/drivers/w1-eeprom/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_W1_EEPROM) += w1-eeprom-uclass.o
+
+obj-$(CONFIG_W1_EEPROM_DS24XXX) += ds24xxx.o
+
+obj-$(CONFIG_W1_EEPROM_SANDBOX) += eep_sandbox.o
diff --git a/drivers/w1-eeprom/ds24xxx.c b/drivers/w1-eeprom/ds24xxx.c
new file mode 100644
index 0000000..56186e5
--- /dev/null
+++ b/drivers/w1-eeprom/ds24xxx.c
@@ -0,0 +1,55 @@
+// SPDX-License-Identifier:	GPL-2.0+
+/*
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <w1-eeprom.h>
+#include <w1.h>
+
+#define W1_F2D_READ_EEPROM	0xf0
+
+static int ds24xxx_read_buf(struct udevice *dev, unsigned int offset,
+			    u8 *buf, unsigned int count)
+{
+	w1_reset_select(dev);
+
+	w1_write_byte(dev, W1_F2D_READ_EEPROM);
+	w1_write_byte(dev, offset & 0xff);
+	w1_write_byte(dev, offset >> 8);
+
+	return w1_read_buf(dev, buf, count);
+}
+
+static int ds24xxx_probe(struct udevice *dev)
+{
+	struct w1_device *w1;
+
+	w1 = dev_get_platdata(dev);
+	w1->id = 0;
+	return 0;
+}
+
+static const struct w1_eeprom_ops ds24xxx_ops = {
+	.read_buf	= ds24xxx_read_buf,
+};
+
+static const struct udevice_id ds24xxx_id[] = {
+	{ .compatible = "maxim,ds24b33", .data = W1_FAMILY_DS24B33 },
+	{ .compatible = "maxim,ds2431", .data = W1_FAMILY_DS2431 },
+	{ },
+};
+
+U_BOOT_DRIVER(ds24xxx) = {
+	.name		= "ds24xxx",
+	.id		= UCLASS_W1_EEPROM,
+	.of_match	= ds24xxx_id,
+	.ops		= &ds24xxx_ops,
+	.probe		= ds24xxx_probe,
+};
diff --git a/drivers/w1-eeprom/eep_sandbox.c b/drivers/w1-eeprom/eep_sandbox.c
new file mode 100644
index 0000000..27c7f9f
--- /dev/null
+++ b/drivers/w1-eeprom/eep_sandbox.c
@@ -0,0 +1,61 @@
+/* SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ */
+
+#include <common.h>
+#include <linux/err.h>
+#include <dm.h>
+#include <w1-eeprom.h>
+#include <w1.h>
+
+#define W1_F2D_READ_EEPROM      0xf0
+
+#define EEP_SANDBOX_SAMPLE_MEM "this is a sample EEPROM memory string."
+
+static int eep_sandbox_read_buf(struct udevice *dev, unsigned int offset,
+				u8 *buf, unsigned int count)
+{
+	/* do not allow to copy more than our maximum sample string */
+	if (offset + count < strlen(EEP_SANDBOX_SAMPLE_MEM)) {
+		offset = 0;
+		count = strlen(EEP_SANDBOX_SAMPLE_MEM);
+	}
+	strncpy((char *)buf, EEP_SANDBOX_SAMPLE_MEM, count);
+
+	/*
+	 * in case the w1 subsystem uses some different kind of sandbox testing,
+	 * like randomized gpio values , we take the buffer from there
+	 */
+
+	w1_reset_select(dev);
+
+	w1_write_byte(dev, W1_F2D_READ_EEPROM);
+	w1_write_byte(dev, offset & 0xff);
+	w1_write_byte(dev, offset >> 8);
+
+	w1_read_buf(dev, buf, count);
+
+	/*
+	 * even if read buf from w1 fails, return success as we hardcoded
+	 * the buffer.
+	 */
+	return 0;
+}
+
+static const struct w1_eeprom_ops eep_sandbox_ops = {
+	.read_buf	= eep_sandbox_read_buf,
+};
+
+static const struct udevice_id eep_sandbox_id[] = {
+	{ .compatible = "sandbox,w1-eeprom", .data = W1_FAMILY_EEP_SANDBOX },
+	{ },
+};
+
+U_BOOT_DRIVER(eep_sandbox) = {
+	.name		= "eep_sandbox",
+	.id		= UCLASS_W1_EEPROM,
+	.of_match	= eep_sandbox_id,
+	.ops		= &eep_sandbox_ops,
+};
diff --git a/drivers/w1-eeprom/w1-eeprom-uclass.c b/drivers/w1-eeprom/w1-eeprom-uclass.c
new file mode 100644
index 0000000..7b05793
--- /dev/null
+++ b/drivers/w1-eeprom/w1-eeprom-uclass.c
@@ -0,0 +1,116 @@
+// SPDX-License-Identifier:	GPL-2.0+
+/*
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co.
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <w1.h>
+#include <w1-eeprom.h>
+
+#include <dm/device-internal.h>
+
+int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
+		       u8 *buf, unsigned int count)
+{
+	const struct w1_eeprom_ops *ops = device_get_ops(dev);
+	u64 id = 0;
+	int ret;
+
+	if (!ops->read_buf)
+		return -ENOSYS;
+
+	ret = w1_eeprom_get_id(dev, &id);
+	if (ret)
+		return ret;
+	if (!id)
+		return -ENODEV;
+
+	return ops->read_buf(dev, offset, buf, count);
+}
+
+int w1_eeprom_register_new_device(u64 id)
+{
+	u8 family = id & 0xff;
+	int ret;
+	struct udevice *dev;
+
+	for (ret = uclass_first_device(UCLASS_W1_EEPROM, &dev);
+	     !ret && dev;
+	     uclass_next_device(&dev)) {
+		if (ret || !dev) {
+			debug("cannot find w1 eeprom dev\n");
+			return ret;
+		}
+		if (dev_get_driver_data(dev) == family) {
+			struct w1_device *w1;
+
+			w1 = dev_get_parent_platdata(dev);
+			if (w1->id) /* device already in use */
+				continue;
+			w1->id = id;
+			debug("%s: Match found: %s:%s %llx\n", __func__,
+			      dev->name, dev->driver->name, id);
+			return 0;
+		}
+	}
+
+	debug("%s: No matches found: error %d\n", __func__, ret);
+
+	return ret;
+}
+
+int w1_eeprom_get_id(struct udevice *dev, u64 *id)
+{
+	struct w1_device *w1 = dev_get_parent_platdata(dev);
+
+	if (!w1)
+		return -ENODEV;
+	*id = w1->id;
+
+	return 0;
+}
+
+UCLASS_DRIVER(w1_eeprom) = {
+	.name		= "w1_eeprom",
+	.id		= UCLASS_W1_EEPROM,
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.post_bind	= dm_scan_fdt_dev,
+#endif
+};
+
+int w1_eeprom_dm_init(void)
+{
+	struct udevice *dev;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_W1_EEPROM, &uc);
+	if (ret) {
+		debug("W1_EEPROM uclass not available\n");
+		return ret;
+	}
+
+	uclass_foreach_dev(dev, uc) {
+		ret = device_probe(dev);
+		if (ret == -ENODEV) {	/* No such device. */
+			debug("W1_EEPROM not available.\n");
+			continue;
+		}
+
+		if (ret) {		/* Other error. */
+			printf("W1_EEPROM probe failed, error %d\n", ret);
+			continue;
+		}
+	}
+
+	return 0;
+}
diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
new file mode 100644
index 0000000..d6e0457
--- /dev/null
+++ b/drivers/w1/Kconfig
@@ -0,0 +1,25 @@
+#
+# W1 subsystem configuration
+#
+
+menu "1-Wire support"
+
+config W1
+	bool "Enable 1-wire controllers support"
+	default no
+	depends on DM
+	help
+	  Support for the Dallas 1-Wire bus.
+
+if W1
+
+config W1_GPIO
+	bool "Enable 1-wire GPIO bitbanging"
+	default no
+	depends on DM_GPIO
+	help
+	  Emulate a 1-wire bus using a GPIO.
+
+endif
+
+endmenu
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile
new file mode 100644
index 0000000..7fd8697
--- /dev/null
+++ b/drivers/w1/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_W1) += w1-uclass.o
+
+obj-$(CONFIG_W1_GPIO) += w1-gpio.o
diff --git a/drivers/w1/w1-gpio.c b/drivers/w1/w1-gpio.c
new file mode 100644
index 0000000..5e5d6b3
--- /dev/null
+++ b/drivers/w1/w1-gpio.c
@@ -0,0 +1,176 @@
+/* SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <w1.h>
+
+#include <asm/gpio.h>
+
+#define W1_TIMING_A	6
+#define W1_TIMING_B	64
+#define W1_TIMING_C	60
+#define W1_TIMING_D	10
+#define W1_TIMING_E	9
+#define W1_TIMING_F	55
+#define W1_TIMING_G	0
+#define W1_TIMING_H	480
+#define W1_TIMING_I	70
+#define W1_TIMING_J	410
+
+struct w1_gpio_pdata {
+	struct gpio_desc	gpio;
+	u64			search_id;
+};
+
+static bool w1_gpio_read_bit(struct udevice *dev)
+{
+	struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+	int val;
+
+	dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
+	udelay(W1_TIMING_A);
+
+	dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
+	udelay(W1_TIMING_E);
+
+	val = dm_gpio_get_value(&pdata->gpio);
+	if (val < 0)
+		debug("error in retrieving GPIO value");
+	udelay(W1_TIMING_F);
+
+	return val;
+}
+
+static u8 w1_gpio_read_byte(struct udevice *dev)
+{
+	int i;
+	u8 ret = 0;
+
+	for (i = 0; i < 8; ++i)
+		ret |= (w1_gpio_read_bit(dev) ? 1 : 0) << i;
+
+	return ret;
+}
+
+static void w1_gpio_write_bit(struct udevice *dev, bool bit)
+{
+	struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+
+	dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
+
+	bit ? udelay(W1_TIMING_A) : udelay(W1_TIMING_C);
+
+	dm_gpio_set_value(&pdata->gpio, 1);
+
+	bit ? udelay(W1_TIMING_B) : udelay(W1_TIMING_D);
+}
+
+static void w1_gpio_write_byte(struct udevice *dev, u8 byte)
+{
+	int i;
+
+	for (i = 0; i < 8; ++i)
+		w1_gpio_write_bit(dev, (byte >> i) & 0x1);
+}
+
+static bool w1_gpio_reset(struct udevice *dev)
+{
+	struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+	int val;
+
+	/* initiate the reset pulse. first we must pull the bus to low */
+	dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+	udelay(W1_TIMING_G);
+
+	dm_gpio_set_value(&pdata->gpio, 0);
+	/* wait for the specified time with the bus kept low */
+	udelay(W1_TIMING_H);
+
+	/* now we must read the presence pulse */
+	dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
+	udelay(W1_TIMING_I);
+
+	val = dm_gpio_get_value(&pdata->gpio);
+	if (val < 0)
+		debug("error in retrieving GPIO value");
+
+	/* if nobody pulled the bus down , it means nobody is on the bus */
+	if (val != 0)
+		return 1;
+	/* we have the bus pulled down, let's wait for the specified presence time */
+	udelay(W1_TIMING_J);
+
+	/* read again, the other end should leave the bus free */
+	val = dm_gpio_get_value(&pdata->gpio);
+	if (val < 0)
+		debug("error in retrieving GPIO value");
+
+	/* bus is not going up again, so we have an error */
+	if (val != 1)
+		return 1;
+
+	/* all good, presence detected */
+	return 0;
+}
+
+static u8 w1_gpio_triplet(struct udevice *dev, bool bdir)
+{
+	u8 id_bit   = w1_gpio_read_bit(dev);
+	u8 comp_bit = w1_gpio_read_bit(dev);
+	u8 retval;
+
+	if (id_bit && comp_bit)
+		return 0x03;  /* error */
+
+	if (!id_bit && !comp_bit) {
+		/* Both bits are valid, take the direction given */
+		retval = bdir ? 0x04 : 0;
+	} else {
+		/* Only one bit is valid, take that direction */
+		bdir = id_bit;
+		retval = id_bit ? 0x05 : 0x02;
+	}
+
+	w1_gpio_write_bit(dev, bdir);
+	return retval;
+}
+
+static const struct w1_ops w1_gpio_ops = {
+	.read_byte	= w1_gpio_read_byte,
+	.reset		= w1_gpio_reset,
+	.triplet	= w1_gpio_triplet,
+	.write_byte	= w1_gpio_write_byte,
+};
+
+static int w1_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+	struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+	int ret;
+
+	ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0);
+	if (ret < 0)
+		printf("Error claiming GPIO %d\n", ret);
+
+	return ret;
+};
+
+static const struct udevice_id w1_gpio_id[] = {
+	{ "w1-gpio", 0 },
+	{ },
+};
+
+U_BOOT_DRIVER(w1_gpio_drv) = {
+	.id				= UCLASS_W1,
+	.name				= "w1_gpio_drv",
+	.of_match			= w1_gpio_id,
+	.ofdata_to_platdata		= w1_gpio_ofdata_to_platdata,
+	.ops				= &w1_gpio_ops,
+	.platdata_auto_alloc_size	= sizeof(struct w1_gpio_pdata),
+};
diff --git a/drivers/w1/w1-uclass.c b/drivers/w1/w1-uclass.c
new file mode 100644
index 0000000..aecf7fe
--- /dev/null
+++ b/drivers/w1/w1-uclass.c
@@ -0,0 +1,240 @@
+// SPDX-License-Identifier:	GPL-2.0+
+/*
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co.
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ * Eugen Hristev <eugen.hristev@microchip.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <w1.h>
+#include <w1-eeprom.h>
+
+#include <dm/device-internal.h>
+
+#define W1_MATCH_ROM	0x55
+#define W1_SKIP_ROM	0xcc
+#define W1_SEARCH	0xf0
+
+struct w1_bus {
+	u64	search_id;
+};
+
+static int w1_enumerate(struct udevice *bus)
+{
+	const struct w1_ops *ops = device_get_ops(bus);
+	struct w1_bus *w1 = dev_get_uclass_priv(bus);
+	u64 last_rn, rn = w1->search_id, tmp64;
+	bool last_device = false;
+	int search_bit, desc_bit = 64;
+	int last_zero = -1;
+	u8 triplet_ret = 0;
+	int i;
+
+	if (!ops->reset || !ops->write_byte || !ops->triplet)
+		return -ENOSYS;
+
+	while (!last_device) {
+		last_rn = rn;
+		rn = 0;
+
+		/*
+		 * Reset bus and all 1-wire device state machines
+		 * so they can respond to our requests.
+		 *
+		 * Return 0 - device(s) present, 1 - no devices present.
+		 */
+		if (ops->reset(bus)) {
+			debug("%s: No devices present on the wire.\n",
+			      __func__);
+			break;
+		}
+
+		/* Start the search */
+		ops->write_byte(bus, W1_SEARCH);
+		for (i = 0; i < 64; ++i) {
+			/* Determine the direction/search bit */
+			if (i == desc_bit)
+				/* took the 0 path last time, so take the 1 path */
+				search_bit = 1;
+			else if (i > desc_bit)
+				/* take the 0 path on the next branch */
+				search_bit = 0;
+			else
+				search_bit = ((last_rn >> i) & 0x1);
+
+			/* Read two bits and write one bit */
+			triplet_ret = ops->triplet(bus, search_bit);
+
+			/* quit if no device responded */
+			if ((triplet_ret & 0x03) == 0x03)
+				break;
+
+			/* If both directions were valid, and we took the 0 path... */
+			if (triplet_ret == 0)
+				last_zero = i;
+
+			/* extract the direction taken & update the device number */
+			tmp64 = (triplet_ret >> 2);
+			rn |= (tmp64 << i);
+		}
+
+		/* last device or error, aborting here */
+		if ((triplet_ret & 0x03) == 0x03)
+			last_device = true;
+
+		if ((triplet_ret & 0x03) != 0x03) {
+			if (desc_bit == last_zero || last_zero < 0) {
+				last_device = 1;
+				w1->search_id = 0;
+			} else {
+				w1->search_id = rn;
+			}
+			desc_bit = last_zero;
+
+			debug("%s: Detected new device 0x%llx (family 0x%x)\n",
+			      bus->name, rn, (u8)(rn & 0xff));
+
+			/* attempt to register as w1-eeprom device */
+			w1_eeprom_register_new_device(rn);
+		}
+	}
+
+	return 0;
+}
+
+int w1_get_bus(int busnum, struct udevice **busp)
+{
+	int ret, i = 0;
+
+	struct udevice *dev;
+
+	for (ret = uclass_first_device(UCLASS_W1, &dev);
+	     !ret;
+	     uclass_next_device(&dev), i++) {
+		if (ret) {
+			debug("Cannot find w1 bus %d\n", busnum);
+			return ret;
+		}
+		if (i == busnum) {
+			*busp = dev;
+			return 0;
+		}
+	}
+	return ret;
+}
+
+u8 w1_get_device_family(struct udevice *dev)
+{
+	struct w1_device *w1 = dev_get_parent_platdata(dev);
+
+	return w1->id & 0xff;
+}
+
+int w1_reset_select(struct udevice *dev)
+{
+	struct w1_device *w1 = dev_get_parent_platdata(dev);
+	struct udevice *bus = dev_get_parent(dev);
+	const struct w1_ops *ops = device_get_ops(bus);
+	int i;
+
+	if (!ops->reset || !ops->write_byte)
+		return -ENOSYS;
+
+	ops->reset(bus);
+
+	ops->write_byte(bus, W1_MATCH_ROM);
+
+	for (i = 0; i < sizeof(w1->id); i++)
+		ops->write_byte(bus, (w1->id >> (i * 8)) & 0xff);
+
+	return 0;
+}
+
+int w1_read_byte(struct udevice *dev)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	const struct w1_ops *ops = device_get_ops(bus);
+
+	if (!ops->read_byte)
+		return -ENOSYS;
+
+	return ops->read_byte(bus);
+}
+
+int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count)
+{
+	int i, ret;
+
+	for (i = 0; i < count; i++) {
+		ret = w1_read_byte(dev);
+		if (ret < 0)
+			return ret;
+
+		buf[i] = ret & 0xff;
+	}
+
+	return 0;
+}
+
+int w1_write_byte(struct udevice *dev, u8 byte)
+{
+	struct udevice *bus = dev_get_parent(dev);
+	const struct w1_ops *ops = device_get_ops(bus);
+
+	if (!ops->write_byte)
+		return -ENOSYS;
+
+	ops->write_byte(bus, byte);
+
+	return 0;
+}
+
+static int w1_post_probe(struct udevice *bus)
+{
+	w1_enumerate(bus);
+
+	return 0;
+}
+
+int w1_init(void)
+{
+	struct udevice *bus;
+	struct uclass *uc;
+	int ret;
+
+	ret = uclass_get(UCLASS_W1, &uc);
+	if (ret)
+		return ret;
+
+	uclass_foreach_dev(bus, uc) {
+		ret = device_probe(bus);
+		if (ret == -ENODEV) {	/* No such device. */
+			printf("W1 controller not available.\n");
+			continue;
+		}
+
+		if (ret) {		/* Other error. */
+			printf("W1 controller probe failed.\n");
+			continue;
+		}
+	}
+	return 0;
+}
+
+UCLASS_DRIVER(w1) = {
+	.name		= "w1",
+	.id		= UCLASS_W1,
+	.flags		= DM_UC_FLAG_SEQ_ALIAS,
+	.per_device_auto_alloc_size	= sizeof(struct w1_bus),
+	.post_probe	= w1_post_probe,
+#if CONFIG_IS_ENABLED(OF_CONTROL)
+	.post_bind	= dm_scan_fdt_dev,
+#endif
+	.per_child_platdata_auto_alloc_size     = sizeof(struct w1_device),
+};
diff --git a/fs/fat/fat.c b/fs/fat/fat.c
index 4b722fc..b08949d 100644
--- a/fs/fat/fat.c
+++ b/fs/fat/fat.c
@@ -260,7 +260,7 @@
 	if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
 
-		printf("FAT: Misaligned buffer address (%p)\n", buffer);
+		debug("FAT: Misaligned buffer address (%p)\n", buffer);
 
 		while (size >= mydata->sect_size) {
 			ret = disk_read(startsect++, 1, tmpbuf);
@@ -465,15 +465,6 @@
 }
 
 /*
- * TODO these should go away once fat_write is reworked to use the
- * directory iterator
- */
-__u8 get_dentfromdir_block[MAX_CLUSTSIZE]
-	__aligned(ARCH_DMA_MINALIGN);
-__u8 do_fat_read_at_block[MAX_CLUSTSIZE]
-	__aligned(ARCH_DMA_MINALIGN);
-
-/*
  * Read boot sector and volume info from a FAT filesystem
  */
 static int
@@ -558,10 +549,17 @@
 
 	if (mydata->fatsize == 32) {
 		mydata->fatlength = bs.fat32_length;
+		mydata->total_sect = bs.total_sect;
 	} else {
 		mydata->fatlength = bs.fat_length;
+		mydata->total_sect = (bs.sectors[1] << 8) + bs.sectors[0];
+		if (!mydata->total_sect)
+			mydata->total_sect = bs.total_sect;
 	}
+	if (!mydata->total_sect) /* unlikely */
+		mydata->total_sect = (u32)cur_part_info.size;
 
+	mydata->fats = bs.fats;
 	mydata->fat_sect = bs.reserved;
 
 	mydata->rootdir_sect = mydata->fat_sect + mydata->fatlength * bs.fats;
@@ -633,7 +631,9 @@
 
 typedef struct {
 	fsdata    *fsdata;        /* filesystem parameters */
+	unsigned   start_clust;   /* first cluster */
 	unsigned   clust;         /* current cluster */
+	unsigned   next_clust;    /* next cluster if remaining == 0 */
 	int        last_cluster;  /* set once we've read last cluster */
 	int        is_root;       /* is iterator at root directory */
 	int        remaining;     /* remaining dent's in current cluster */
@@ -664,7 +664,9 @@
 		return -ENXIO;
 
 	itr->fsdata = fsdata;
+	itr->start_clust = 0;
 	itr->clust = fsdata->root_cluster;
+	itr->next_clust = fsdata->root_cluster;
 	itr->dent = NULL;
 	itr->remaining = 0;
 	itr->last_cluster = 0;
@@ -698,11 +700,14 @@
 	assert(fat_itr_isdir(parent));
 
 	itr->fsdata = parent->fsdata;
+	itr->start_clust = clustnum;
 	if (clustnum > 0) {
 		itr->clust = clustnum;
+		itr->next_clust = clustnum;
 		itr->is_root = 0;
 	} else {
 		itr->clust = parent->fsdata->root_cluster;
+		itr->next_clust = parent->fsdata->root_cluster;
 		itr->is_root = 1;
 	}
 	itr->dent = NULL;
@@ -720,7 +725,7 @@
 	if (itr->last_cluster)
 		return NULL;
 
-	sect = clust_to_sect(itr->fsdata, itr->clust);
+	sect = clust_to_sect(itr->fsdata, itr->next_clust);
 
 	debug("FAT read(sect=%d), clust_size=%d, DIRENTSPERBLOCK=%zd\n",
 	      sect, itr->fsdata->clust_size, DIRENTSPERBLOCK);
@@ -741,18 +746,19 @@
 		return NULL;
 	}
 
+	itr->clust = itr->next_clust;
 	if (itr->is_root && itr->fsdata->fatsize != 32) {
-		itr->clust++;
-		sect = clust_to_sect(itr->fsdata, itr->clust);
+		itr->next_clust++;
+		sect = clust_to_sect(itr->fsdata, itr->next_clust);
 		if (sect - itr->fsdata->rootdir_sect >=
 		    itr->fsdata->rootdir_size) {
-			debug("cursect: 0x%x\n", itr->clust);
+			debug("nextclust: 0x%x\n", itr->next_clust);
 			itr->last_cluster = 1;
 		}
 	} else {
-		itr->clust = get_fatent(itr->fsdata, itr->clust);
-		if (CHECK_CLUST(itr->clust, itr->fsdata->fatsize)) {
-			debug("cursect: 0x%x\n", itr->clust);
+		itr->next_clust = get_fatent(itr->fsdata, itr->next_clust);
+		if (CHECK_CLUST(itr->next_clust, itr->fsdata->fatsize)) {
+			debug("nextclust: 0x%x\n", itr->next_clust);
 			itr->last_cluster = 1;
 		}
 	}
@@ -768,8 +774,11 @@
 			itr->fsdata->clust_size;
 
 		/* have we reached the last cluster? */
-		if (!dent)
+		if (!dent) {
+			/* a sign for no more entries left */
+			itr->dent = NULL;
 			return NULL;
+		}
 
 		itr->remaining = nbytes / sizeof(dir_entry) - 1;
 		itr->dent = dent;
@@ -924,6 +933,28 @@
 	while (next[0] && !ISDIRDELIM(next[0]))
 		next++;
 
+	if (itr->is_root) {
+		/* root dir doesn't have "." nor ".." */
+		if ((((next - path) == 1) && !strncmp(path, ".", 1)) ||
+		    (((next - path) == 2) && !strncmp(path, "..", 2))) {
+			/* point back to itself */
+			itr->clust = itr->fsdata->root_cluster;
+			itr->next_clust = itr->fsdata->root_cluster;
+			itr->dent = NULL;
+			itr->remaining = 0;
+			itr->last_cluster = 0;
+
+			if (next[0] == 0) {
+				if (type & TYPE_DIR)
+					return 0;
+				else
+					return -ENOENT;
+			}
+
+			return fat_itr_resolve(itr, next, type);
+		}
+	}
+
 	while (fat_itr_next(itr)) {
 		int match = 0;
 		unsigned n = max(strlen(itr->name), (size_t)(next - path));
diff --git a/fs/fat/fat_write.c b/fs/fat/fat_write.c
index 27e0ff6..fc211e7 100644
--- a/fs/fat/fat_write.c
+++ b/fs/fat/fat_write.c
@@ -99,7 +99,6 @@
 	debug("ext : %s\n", dirent->ext);
 }
 
-static __u8 num_of_fats;
 /*
  * Write fat buffer into block device
  */
@@ -128,7 +127,7 @@
 		return -1;
 	}
 
-	if (num_of_fats == 2) {
+	if (mydata->fats == 2) {
 		/* Update corresponding second FAT blocks */
 		startblock += mydata->fatlength;
 		if (disk_write(startblock, getsize, bufptr) < 0) {
@@ -210,15 +209,14 @@
 	return 1;
 }
 
-static int is_next_clust(fsdata *mydata, dir_entry *dentptr);
-static void flush_dir_table(fsdata *mydata, dir_entry **dentptr);
+static int flush_dir_table(fat_itr *itr);
 
 /*
  * Fill dir_slot entries with appropriate name, id, and attr
- * The real directory entry is returned by 'dentptr'
+ * 'itr' will point to a next entry
  */
-static void
-fill_dir_slot(fsdata *mydata, dir_entry **dentptr, const char *l_name)
+static int
+fill_dir_slot(fat_itr *itr, const char *l_name)
 {
 	__u8 temp_dir_slot_buffer[MAX_LFN_SLOT * sizeof(dir_slot)];
 	dir_slot *slotptr = (dir_slot *)temp_dir_slot_buffer;
@@ -226,7 +224,7 @@
 	int idx = 0, ret;
 
 	/* Get short file name checksum value */
-	checksum = mkcksum((*dentptr)->name, (*dentptr)->ext);
+	checksum = mkcksum(itr->dent->name, itr->dent->ext);
 
 	do {
 		memset(slotptr, 0x00, sizeof(dir_slot));
@@ -241,120 +239,21 @@
 	slotptr->id |= LAST_LONG_ENTRY_MASK;
 
 	while (counter >= 1) {
-		if (is_next_clust(mydata, *dentptr)) {
-			/* A new cluster is allocated for directory table */
-			flush_dir_table(mydata, dentptr);
-		}
-		memcpy(*dentptr, slotptr, sizeof(dir_slot));
-		(*dentptr)++;
+		memcpy(itr->dent, slotptr, sizeof(dir_slot));
 		slotptr--;
 		counter--;
-	}
-
-	if (is_next_clust(mydata, *dentptr)) {
-		/* A new cluster is allocated for directory table */
-		flush_dir_table(mydata, dentptr);
-	}
-}
-
-static __u32 dir_curclust;
-
-/*
- * Extract the full long filename starting at 'retdent' (which is really
- * a slot) into 'l_name'. If successful also copy the real directory entry
- * into 'retdent'
- * If additional adjacent cluster for directory entries is read into memory,
- * then 'get_contents_vfatname_block' is copied into 'get_dentfromdir_block' and
- * the location of the real directory entry is returned by 'retdent'
- * Return 0 on success, -1 otherwise.
- */
-static int
-get_long_file_name(fsdata *mydata, int curclust, __u8 *cluster,
-	      dir_entry **retdent, char *l_name)
-{
-	dir_entry *realdent;
-	dir_slot *slotptr = (dir_slot *)(*retdent);
-	dir_slot *slotptr2 = NULL;
-	__u8 *buflimit = cluster + mydata->sect_size * ((curclust == 0) ?
-							PREFETCH_BLOCKS :
-							mydata->clust_size);
-	__u8 counter = (slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff;
-	int idx = 0, cur_position = 0;
-
-	if (counter > VFAT_MAXSEQ) {
-		debug("Error: VFAT name is too long\n");
-		return -1;
-	}
-
-	while ((__u8 *)slotptr < buflimit) {
-		if (counter == 0)
-			break;
-		if (((slotptr->id & ~LAST_LONG_ENTRY_MASK) & 0xff) != counter)
-			return -1;
-		slotptr++;
-		counter--;
-	}
-
-	if ((__u8 *)slotptr >= buflimit) {
-		if (curclust == 0)
-			return -1;
-		curclust = get_fatent(mydata, dir_curclust);
-		if (CHECK_CLUST(curclust, mydata->fatsize)) {
-			debug("curclust: 0x%x\n", curclust);
-			printf("Invalid FAT entry\n");
-			return -1;
-		}
-
-		dir_curclust = curclust;
-
-		if (get_cluster(mydata, curclust, get_contents_vfatname_block,
-				mydata->clust_size * mydata->sect_size) != 0) {
-			debug("Error: reading directory block\n");
-			return -1;
-		}
-
-		slotptr2 = (dir_slot *)get_contents_vfatname_block;
-		while (counter > 0) {
-			if (((slotptr2->id & ~LAST_LONG_ENTRY_MASK)
-			    & 0xff) != counter)
+		if (!fat_itr_next(itr))
+			if (!itr->dent && !itr->is_root && flush_dir_table(itr))
 				return -1;
-			slotptr2++;
-			counter--;
-		}
-
-		/* Save the real directory entry */
-		realdent = (dir_entry *)slotptr2;
-		while ((__u8 *)slotptr2 > get_contents_vfatname_block) {
-			slotptr2--;
-			slot2str(slotptr2, l_name, &idx);
-		}
-	} else {
-		/* Save the real directory entry */
-		realdent = (dir_entry *)slotptr;
 	}
 
-	do {
-		slotptr--;
-		if (slot2str(slotptr, l_name, &idx))
-			break;
-	} while (!(slotptr->id & LAST_LONG_ENTRY_MASK));
-
-	l_name[idx] = '\0';
-	if (*l_name == DELETED_FLAG)
-		*l_name = '\0';
-	else if (*l_name == aRING)
-		*l_name = DELETED_FLAG;
-	downcase(l_name, INT_MAX);
-
-	/* Return the real directory entry */
-	*retdent = realdent;
-
-	if (slotptr2) {
-		memcpy(get_dentfromdir_block, get_contents_vfatname_block,
-			mydata->clust_size * mydata->sect_size);
-		cur_position = (__u8 *)realdent - get_contents_vfatname_block;
-		*retdent = (dir_entry *) &get_dentfromdir_block[cur_position];
-	}
+	if (!itr->dent && !itr->is_root)
+		/*
+		 * don't care return value here because we have already
+		 * finished completing an entry with name, only ending up
+		 * no more entry left
+		 */
+		flush_dir_table(itr);
 
 	return 0;
 }
@@ -510,7 +409,7 @@
 	if ((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1)) {
 		ALLOC_CACHE_ALIGN_BUFFER(__u8, tmpbuf, mydata->sect_size);
 
-		printf("FAT: Misaligned buffer address (%p)\n", buffer);
+		debug("FAT: Misaligned buffer address (%p)\n", buffer);
 
 		while (size >= mydata->sect_size) {
 			memcpy(tmpbuf, buffer, mydata->sect_size);
@@ -551,6 +450,121 @@
 	return 0;
 }
 
+static __u8 tmpbuf_cluster[MAX_CLUSTSIZE] __aligned(ARCH_DMA_MINALIGN);
+
+/*
+ * Read and modify data on existing and consecutive cluster blocks
+ */
+static int
+get_set_cluster(fsdata *mydata, __u32 clustnum, loff_t pos, __u8 *buffer,
+		loff_t size, loff_t *gotsize)
+{
+	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
+	__u32 startsect;
+	loff_t wsize;
+	int clustcount, i, ret;
+
+	*gotsize = 0;
+	if (!size)
+		return 0;
+
+	assert(pos < bytesperclust);
+	startsect = clust_to_sect(mydata, clustnum);
+
+	debug("clustnum: %d, startsect: %d, pos: %lld\n",
+	      clustnum, startsect, pos);
+
+	/* partial write at beginning */
+	if (pos) {
+		wsize = min(bytesperclust - pos, size);
+		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
+		if (ret != mydata->clust_size) {
+			debug("Error reading data (got %d)\n", ret);
+			return -1;
+		}
+
+		memcpy(tmpbuf_cluster + pos, buffer, wsize);
+		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
+		if (ret != mydata->clust_size) {
+			debug("Error writing data (got %d)\n", ret);
+			return -1;
+		}
+
+		size -= wsize;
+		buffer += wsize;
+		*gotsize += wsize;
+
+		startsect += mydata->clust_size;
+
+		if (!size)
+			return 0;
+	}
+
+	/* full-cluster write */
+	if (size >= bytesperclust) {
+		clustcount = lldiv(size, bytesperclust);
+
+		if (!((unsigned long)buffer & (ARCH_DMA_MINALIGN - 1))) {
+			wsize = clustcount * bytesperclust;
+			ret = disk_write(startsect,
+					 clustcount * mydata->clust_size,
+					 buffer);
+			if (ret != clustcount * mydata->clust_size) {
+				debug("Error writing data (got %d)\n", ret);
+				return -1;
+			}
+
+			size -= wsize;
+			buffer += wsize;
+			*gotsize += wsize;
+
+			startsect += clustcount * mydata->clust_size;
+		} else {
+			for (i = 0; i < clustcount; i++) {
+				memcpy(tmpbuf_cluster, buffer, bytesperclust);
+				ret = disk_write(startsect,
+						 mydata->clust_size,
+						 tmpbuf_cluster);
+				if (ret != mydata->clust_size) {
+					debug("Error writing data (got %d)\n",
+					      ret);
+					return -1;
+				}
+
+				size -= bytesperclust;
+				buffer += bytesperclust;
+				*gotsize += bytesperclust;
+
+				startsect += mydata->clust_size;
+			}
+		}
+	}
+
+	/* partial write at end */
+	if (size) {
+		wsize = size;
+		ret = disk_read(startsect, mydata->clust_size, tmpbuf_cluster);
+		if (ret != mydata->clust_size) {
+			debug("Error reading data (got %d)\n", ret);
+			return -1;
+		}
+		memcpy(tmpbuf_cluster, buffer, wsize);
+		ret = disk_write(startsect, mydata->clust_size, tmpbuf_cluster);
+		if (ret != mydata->clust_size) {
+			debug("Error writing data (got %d)\n", ret);
+			return -1;
+		}
+
+		size -= wsize;
+		buffer += wsize;
+		*gotsize += wsize;
+	}
+
+	assert(!size);
+
+	return 0;
+}
+
 /*
  * Find the first empty cluster
  */
@@ -569,20 +583,20 @@
 }
 
 /*
- * Write directory entries in 'get_dentfromdir_block' to block device
+ * Write directory entries in itr's buffer to block device
  */
-static void flush_dir_table(fsdata *mydata, dir_entry **dentptr)
+static int flush_dir_table(fat_itr *itr)
 {
+	fsdata *mydata = itr->fsdata;
 	int dir_newclust = 0;
+	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
 
-	if (set_cluster(mydata, dir_curclust,
-		    get_dentfromdir_block,
-		    mydata->clust_size * mydata->sect_size) != 0) {
-		printf("error: wrinting directory entry\n");
-		return;
+	if (set_cluster(mydata, itr->clust, itr->block, bytesperclust) != 0) {
+		printf("error: writing directory entry\n");
+		return -1;
 	}
 	dir_newclust = find_empty_cluster(mydata);
-	set_fatent_value(mydata, dir_curclust, dir_newclust);
+	set_fatent_value(mydata, itr->clust, dir_newclust);
 	if (mydata->fatsize == 32)
 		set_fatent_value(mydata, dir_newclust, 0xffffff8);
 	else if (mydata->fatsize == 16)
@@ -590,15 +604,19 @@
 	else if (mydata->fatsize == 12)
 		set_fatent_value(mydata, dir_newclust, 0xff8);
 
-	dir_curclust = dir_newclust;
+	itr->clust = dir_newclust;
+	itr->next_clust = dir_newclust;
 
 	if (flush_dirty_fat_buffer(mydata) < 0)
-		return;
+		return -1;
 
-	memset(get_dentfromdir_block, 0x00,
-		mydata->clust_size * mydata->sect_size);
+	memset(itr->block, 0x00, bytesperclust);
 
-	*dentptr = (dir_entry *) get_dentfromdir_block;
+	itr->dent = (dir_entry *)itr->block;
+	itr->last_cluster = 1;
+	itr->remaining = bytesperclust / sizeof(dir_entry) - 1;
+
+	return 0;
 }
 
 /*
@@ -626,37 +644,212 @@
 }
 
 /*
+ * Set start cluster in directory entry
+ */
+static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
+			      __u32 start_cluster)
+{
+	if (mydata->fatsize == 32)
+		dentptr->starthi =
+			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
+	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
+}
+
+/*
+ * Check whether adding a file makes the file system to
+ * exceed the size of the block device
+ * Return -1 when overflow occurs, otherwise return 0
+ */
+static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
+{
+	__u32 startsect, sect_num, offset;
+
+	if (clustnum > 0)
+		startsect = clust_to_sect(mydata, clustnum);
+	else
+		startsect = mydata->rootdir_sect;
+
+	sect_num = div_u64_rem(size, mydata->sect_size, &offset);
+
+	if (offset != 0)
+		sect_num++;
+
+	if (startsect + sect_num > total_sector)
+		return -1;
+	return 0;
+}
+
+/*
  * Write at most 'maxsize' bytes from 'buffer' into
  * the file associated with 'dentptr'
  * Update the number of bytes written in *gotsize and return 0
  * or return -1 on fatal errors.
  */
 static int
-set_contents(fsdata *mydata, dir_entry *dentptr, __u8 *buffer,
-	      loff_t maxsize, loff_t *gotsize)
+set_contents(fsdata *mydata, dir_entry *dentptr, loff_t pos, __u8 *buffer,
+	     loff_t maxsize, loff_t *gotsize)
 {
-	loff_t filesize = FAT2CPU32(dentptr->size);
+	loff_t filesize;
 	unsigned int bytesperclust = mydata->clust_size * mydata->sect_size;
 	__u32 curclust = START(dentptr);
 	__u32 endclust = 0, newclust = 0;
-	loff_t actsize;
+	loff_t cur_pos, offset, actsize, wsize;
 
 	*gotsize = 0;
-	debug("Filesize: %llu bytes\n", filesize);
-
-	if (maxsize > 0 && filesize > maxsize)
-		filesize = maxsize;
+	filesize = pos + maxsize;
 
 	debug("%llu bytes\n", filesize);
 
+	if (!filesize) {
+		if (!curclust)
+			return 0;
+		if (!CHECK_CLUST(curclust, mydata->fatsize) ||
+		    IS_LAST_CLUST(curclust, mydata->fatsize)) {
+			clear_fatent(mydata, curclust);
+			set_start_cluster(mydata, dentptr, 0);
+			return 0;
+		}
+		debug("curclust: 0x%x\n", curclust);
+		debug("Invalid FAT entry\n");
+		return -1;
+	}
+
 	if (!curclust) {
-		if (filesize) {
-			debug("error: nonempty clusterless file!\n");
+		assert(pos == 0);
+		goto set_clusters;
+	}
+
+	/* go to cluster at pos */
+	cur_pos = bytesperclust;
+	while (1) {
+		if (pos <= cur_pos)
+			break;
+		if (IS_LAST_CLUST(curclust, mydata->fatsize))
+			break;
+
+		newclust = get_fatent(mydata, curclust);
+		if (!IS_LAST_CLUST(newclust, mydata->fatsize) &&
+		    CHECK_CLUST(newclust, mydata->fatsize)) {
+			debug("curclust: 0x%x\n", curclust);
+			debug("Invalid FAT entry\n");
+			return -1;
+		}
+
+		cur_pos += bytesperclust;
+		curclust = newclust;
+	}
+	if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
+		assert(pos == cur_pos);
+		goto set_clusters;
+	}
+
+	assert(pos < cur_pos);
+	cur_pos -= bytesperclust;
+
+	/* overwrite */
+	assert(IS_LAST_CLUST(curclust, mydata->fatsize) ||
+	       !CHECK_CLUST(curclust, mydata->fatsize));
+
+	while (1) {
+		/* search for allocated consecutive clusters */
+		actsize = bytesperclust;
+		endclust = curclust;
+		while (1) {
+			if (filesize <= (cur_pos + actsize))
+				break;
+
+			newclust = get_fatent(mydata, endclust);
+
+			if (IS_LAST_CLUST(newclust, mydata->fatsize))
+				break;
+			if (CHECK_CLUST(newclust, mydata->fatsize)) {
+				debug("curclust: 0x%x\n", curclust);
+				debug("Invalid FAT entry\n");
+				return -1;
+			}
+
+			actsize += bytesperclust;
+			endclust = newclust;
+		}
+
+		/* overwrite to <curclust..endclust> */
+		if (pos < cur_pos)
+			offset = 0;
+		else
+			offset = pos - cur_pos;
+		wsize = min(cur_pos + actsize, filesize) - pos;
+		if (get_set_cluster(mydata, curclust, offset,
+				    buffer, wsize, &actsize)) {
+			printf("Error get-and-setting cluster\n");
 			return -1;
 		}
+		buffer += wsize;
+		*gotsize += wsize;
+		cur_pos += offset + wsize;
+
+		if (filesize <= cur_pos)
+			break;
+
+		/* CHECK: newclust = get_fatent(mydata, endclust); */
+
+		if (IS_LAST_CLUST(newclust, mydata->fatsize))
+			/* no more clusters */
+			break;
+
+		curclust = newclust;
+	}
+
+	if (filesize <= cur_pos) {
+		/* no more write */
+		newclust = get_fatent(mydata, endclust);
+		if (!IS_LAST_CLUST(newclust, mydata->fatsize)) {
+			/* truncate the rest */
+			clear_fatent(mydata, newclust);
+
+			/* Mark end of file in FAT */
+			if (mydata->fatsize == 12)
+				newclust = 0xfff;
+			else if (mydata->fatsize == 16)
+				newclust = 0xffff;
+			else if (mydata->fatsize == 32)
+				newclust = 0xfffffff;
+			set_fatent_value(mydata, endclust, newclust);
+		}
+
 		return 0;
 	}
 
+	curclust = endclust;
+	filesize -= cur_pos;
+	assert(!(cur_pos % bytesperclust));
+
+set_clusters:
+	/* allocate and write */
+	assert(!pos);
+
+	/* Assure that curclust is valid */
+	if (!curclust) {
+		curclust = find_empty_cluster(mydata);
+		set_start_cluster(mydata, dentptr, curclust);
+	} else {
+		newclust = get_fatent(mydata, curclust);
+
+		if (IS_LAST_CLUST(newclust, mydata->fatsize)) {
+			newclust = determine_fatent(mydata, curclust);
+			set_fatent_value(mydata, curclust, newclust);
+			curclust = newclust;
+		} else {
+			debug("error: something wrong\n");
+			return -1;
+		}
+	}
+
+	/* TODO: already partially written */
+	if (check_overflow(mydata, curclust, filesize)) {
+		printf("Error: no space left: %llu\n", filesize);
+		return -1;
+	}
+
 	actsize = bytesperclust;
 	endclust = curclust;
 	do {
@@ -665,6 +858,7 @@
 			newclust = determine_fatent(mydata, endclust);
 
 			if ((newclust - 1) != endclust)
+				/* write to <curclust..endclust> */
 				goto getit;
 
 			if (CHECK_CLUST(newclust, mydata->fatsize)) {
@@ -711,18 +905,8 @@
 		actsize = bytesperclust;
 		curclust = endclust = newclust;
 	} while (1);
-}
 
-/*
- * Set start cluster in directory entry
- */
-static void set_start_cluster(const fsdata *mydata, dir_entry *dentptr,
-				__u32 start_cluster)
-{
-	if (mydata->fatsize == 32)
-		dentptr->starthi =
-			cpu_to_le16((start_cluster & 0xffff0000) >> 16);
-	dentptr->start = cpu_to_le16(start_cluster & 0xffff);
+	return 0;
 }
 
 /*
@@ -740,334 +924,512 @@
 }
 
 /*
- * Check whether adding a file makes the file system to
- * exceed the size of the block device
- * Return -1 when overflow occurs, otherwise return 0
+ * Find a directory entry based on filename or start cluster number
+ * If the directory entry is not found,
+ * the new position for writing a directory entry will be returned
  */
-static int check_overflow(fsdata *mydata, __u32 clustnum, loff_t size)
+static dir_entry *find_directory_entry(fat_itr *itr, char *filename)
 {
-	__u32 startsect, sect_num, offset;
+	int match = 0;
 
-	if (clustnum > 0) {
-		startsect = clust_to_sect(mydata, clustnum);
-	} else {
-		startsect = mydata->rootdir_sect;
+	while (fat_itr_next(itr)) {
+		/* check both long and short name: */
+		if (!strcasecmp(filename, itr->name))
+			match = 1;
+		else if (itr->name != itr->s_name &&
+			 !strcasecmp(filename, itr->s_name))
+			match = 1;
+
+		if (!match)
+			continue;
+
+		if (itr->dent->name[0] == '\0')
+			return NULL;
+		else
+			return itr->dent;
 	}
 
-	sect_num = div_u64_rem(size, mydata->sect_size, &offset);
+	if (!itr->dent && !itr->is_root && flush_dir_table(itr))
+		/* indicate that allocating dent failed */
+		itr->dent = NULL;
 
-	if (offset != 0)
-		sect_num++;
+	return NULL;
+}
 
-	if (startsect + sect_num > total_sector)
-		return -1;
+static int split_filename(char *filename, char **dirname, char **basename)
+{
+	char *p, *last_slash, *last_slash_cont;
+
+again:
+	p = filename;
+	last_slash = NULL;
+	last_slash_cont = NULL;
+	while (*p) {
+		if (ISDIRDELIM(*p)) {
+			last_slash = p;
+			last_slash_cont = p;
+			/* continuous slashes */
+			while (ISDIRDELIM(*p))
+				last_slash_cont = p++;
+			if (!*p)
+				break;
+		}
+		p++;
+	}
+
+	if (last_slash) {
+		if (last_slash_cont == (filename + strlen(filename) - 1)) {
+			/* remove trailing slashes */
+			*last_slash = '\0';
+			goto again;
+		}
+
+		if (last_slash == filename) {
+			/* avoid ""(null) directory */
+			*dirname = "/";
+		} else {
+			*last_slash = '\0';
+			*dirname = filename;
+		}
+
+		*last_slash_cont = '\0';
+		*basename = last_slash_cont + 1;
+	} else {
+		*dirname = "/"; /* root by default */
+		*basename = filename;
+	}
+
 	return 0;
 }
 
-/*
- * Check if adding several entries exceed one cluster boundary
- */
-static int is_next_clust(fsdata *mydata, dir_entry *dentptr)
+static int normalize_longname(char *l_filename, const char *filename)
 {
-	int cur_position;
+	const char *p, legal[] = "!#$%&\'()-.@^`_{}~";
+	char c;
+	int name_len;
 
-	cur_position = (__u8 *)dentptr - get_dentfromdir_block;
+	/* Check that the filename is valid */
+	for (p = filename; p < filename + strlen(filename); p++) {
+		c = *p;
 
-	if (cur_position >= mydata->clust_size * mydata->sect_size)
-		return 1;
-	else
-		return 0;
+		if (('0' <= c) && (c <= '9'))
+			continue;
+		if (('A' <= c) && (c <= 'Z'))
+			continue;
+		if (('a' <= c) && (c <= 'z'))
+			continue;
+		if (strchr(legal, c))
+			continue;
+		/* extended code */
+		if ((0x80 <= c) && (c <= 0xff))
+			continue;
+
+		return -1;
+	}
+
+	/* Normalize it */
+	name_len = strlen(filename);
+	if (name_len >= VFAT_MAXLEN_BYTES)
+		/* should return an error? */
+		name_len = VFAT_MAXLEN_BYTES - 1;
+
+	memcpy(l_filename, filename, name_len);
+	l_filename[name_len] = 0; /* terminate the string */
+	downcase(l_filename, INT_MAX);
+
+	return 0;
 }
 
-static dir_entry *empty_dentptr;
-/*
- * Find a directory entry based on filename or start cluster number
- * If the directory entry is not found,
- * the new position for writing a directory entry will be returned
- */
-static dir_entry *find_directory_entry(fsdata *mydata, int startsect,
-	char *filename, dir_entry *retdent, __u32 start)
+int file_fat_write_at(const char *filename, loff_t pos, void *buffer,
+		      loff_t size, loff_t *actwrite)
 {
-	__u32 curclust = sect_to_clust(mydata, startsect);
+	dir_entry *retdent;
+	fsdata datablock = { .fatbuf = NULL, };
+	fsdata *mydata = &datablock;
+	fat_itr *itr = NULL;
+	int ret = -1;
+	char *filename_copy, *parent, *basename;
+	char l_filename[VFAT_MAXLEN_BYTES];
 
-	debug("get_dentfromdir: %s\n", filename);
+	debug("writing %s\n", filename);
 
-	while (1) {
-		dir_entry *dentptr;
+	filename_copy = strdup(filename);
+	if (!filename_copy)
+		return -ENOMEM;
 
-		int i;
+	split_filename(filename_copy, &parent, &basename);
+	if (!strlen(basename)) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
-		if (get_cluster(mydata, curclust, get_dentfromdir_block,
-			    mydata->clust_size * mydata->sect_size) != 0) {
-			printf("Error: reading directory block\n");
-			return NULL;
-		}
+	filename = basename;
+	if (normalize_longname(l_filename, filename)) {
+		printf("FAT: illegal filename (%s)\n", filename);
+		ret = -EINVAL;
+		goto exit;
+	}
 
-		dentptr = (dir_entry *)get_dentfromdir_block;
+	itr = malloc_cache_aligned(sizeof(fat_itr));
+	if (!itr) {
+		ret = -ENOMEM;
+		goto exit;
+	}
 
-		dir_curclust = curclust;
+	ret = fat_itr_root(itr, &datablock);
+	if (ret)
+		goto exit;
 
-		for (i = 0; i < DIRENTSPERCLUST; i++) {
-			char s_name[14], l_name[VFAT_MAXLEN_BYTES];
+	total_sector = datablock.total_sect;
 
-			l_name[0] = '\0';
-			if (dentptr->name[0] == DELETED_FLAG) {
-				dentptr++;
-				if (is_next_clust(mydata, dentptr))
-					break;
-				continue;
-			}
-			if ((dentptr->attr & ATTR_VOLUME)) {
-				if ((dentptr->attr & ATTR_VFAT) &&
-				    (dentptr->name[0] & LAST_LONG_ENTRY_MASK)) {
-					get_long_file_name(mydata, curclust,
-						     get_dentfromdir_block,
-						     &dentptr, l_name);
-					debug("vfatname: |%s|\n", l_name);
-				} else {
-					/* Volume label or VFAT entry */
-					dentptr++;
-					if (is_next_clust(mydata, dentptr))
-						break;
-					continue;
-				}
-			}
-			if (dentptr->name[0] == 0) {
-				debug("Dentname == NULL - %d\n", i);
-				empty_dentptr = dentptr;
-				return NULL;
-			}
+	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
+	if (ret) {
+		printf("%s: doesn't exist (%d)\n", parent, ret);
+		goto exit;
+	}
 
-			get_name(dentptr, s_name);
+	retdent = find_directory_entry(itr, l_filename);
 
-			if (strncasecmp(filename, s_name, sizeof(s_name)) &&
-			    strncasecmp(filename, l_name, sizeof(l_name))) {
-				debug("Mismatch: |%s|%s|\n",
-					s_name, l_name);
-				dentptr++;
-				if (is_next_clust(mydata, dentptr))
-					break;
-				continue;
-			}
+	if (retdent) {
+		if (fat_itr_isdir(itr)) {
+			ret = -EISDIR;
+			goto exit;
+		}
 
-			memcpy(retdent, dentptr, sizeof(dir_entry));
+		/* A file exists */
+		if (pos == -1)
+			/* Append to the end */
+			pos = FAT2CPU32(retdent->size);
+		if (pos > retdent->size) {
+			/* No hole allowed */
+			ret = -EINVAL;
+			goto exit;
+		}
 
-			debug("DentName: %s", s_name);
-			debug(", start: 0x%x", START(dentptr));
-			debug(", size:  0x%x %s\n",
-			      FAT2CPU32(dentptr->size),
-			      (dentptr->attr & ATTR_DIR) ?
-			      "(DIR)" : "");
+		/* Update file size in a directory entry */
+		retdent->size = cpu_to_le32(pos + size);
+	} else {
+		/* Create a new file */
 
-			return dentptr;
+		if (itr->is_root) {
+			/* root dir cannot have "." or ".." */
+			if (!strcmp(l_filename, ".") ||
+			    !strcmp(l_filename, "..")) {
+				ret = -EINVAL;
+				goto exit;
+			}
 		}
 
-		/*
-		 * In FAT16/12, the root dir is locate before data area, shows
-		 * in following:
-		 * -------------------------------------------------------------
-		 * | Boot | FAT1 & 2 | Root dir | Data (start from cluster #2) |
-		 * -------------------------------------------------------------
-		 *
-		 * As a result if curclust is in Root dir, it is a negative
-		 * number or 0, 1.
-		 *
-		 */
-		if (mydata->fatsize != 32 && (int)curclust <= 1) {
-			/* Current clust is in root dir, set to next clust */
-			curclust++;
-			if ((int)curclust <= 1)
-				continue;	/* continue to find */
-
-			/* Reach the end of root dir */
-			empty_dentptr = dentptr;
-			return NULL;
+		if (!itr->dent) {
+			printf("Error: allocating new dir entry\n");
+			ret = -EIO;
+			goto exit;
 		}
 
-		curclust = get_fatent(mydata, dir_curclust);
-		if (IS_LAST_CLUST(curclust, mydata->fatsize)) {
-			empty_dentptr = dentptr;
-			return NULL;
+		if (pos) {
+			/* No hole allowed */
+			ret = -EINVAL;
+			goto exit;
 		}
-		if (CHECK_CLUST(curclust, mydata->fatsize)) {
-			debug("curclust: 0x%x\n", curclust);
-			debug("Invalid FAT entry\n");
-			return NULL;
+
+		memset(itr->dent, 0, sizeof(*itr->dent));
+
+		/* Set short name to set alias checksum field in dir_slot */
+		set_name(itr->dent, filename);
+		if (fill_dir_slot(itr, filename)) {
+			ret = -EIO;
+			goto exit;
 		}
+
+		/* Set attribute as archive for regular file */
+		fill_dentry(itr->fsdata, itr->dent, filename, 0, size, 0x20);
+
+		retdent = itr->dent;
 	}
 
-	return NULL;
+	ret = set_contents(mydata, retdent, pos, buffer, size, actwrite);
+	if (ret < 0) {
+		printf("Error: writing contents\n");
+		ret = -EIO;
+		goto exit;
+	}
+	debug("attempt to write 0x%llx bytes\n", *actwrite);
+
+	/* Flush fat buffer */
+	ret = flush_dirty_fat_buffer(mydata);
+	if (ret) {
+		printf("Error: flush fat buffer\n");
+		ret = -EIO;
+		goto exit;
+	}
+
+	/* Write directory table to device */
+	ret = set_cluster(mydata, itr->clust, itr->block,
+			  mydata->clust_size * mydata->sect_size);
+	if (ret) {
+		printf("Error: writing directory entry\n");
+		ret = -EIO;
+	}
+
+exit:
+	free(filename_copy);
+	free(mydata->fatbuf);
+	free(itr);
+	return ret;
 }
 
-static int do_fat_write(const char *filename, void *buffer, loff_t size,
-			loff_t *actwrite)
+int file_fat_write(const char *filename, void *buffer, loff_t offset,
+		   loff_t maxsize, loff_t *actwrite)
 {
-	dir_entry *dentptr, *retdent;
-	__u32 startsect;
-	__u32 start_cluster;
-	boot_sector bs;
-	volume_info volinfo;
-	fsdata datablock;
-	fsdata *mydata = &datablock;
-	int cursect, i;
-	int ret = -1, name_len;
-	char l_filename[VFAT_MAXLEN_BYTES];
-	char bad[2] = " ";
-	const char illegal[] = "<>:\"/\\|?*";
+	return file_fat_write_at(filename, offset, buffer, maxsize, actwrite);
+}
 
-	*actwrite = size;
-	dir_curclust = 0;
+static int fat_dir_entries(fat_itr *itr)
+{
+	fat_itr *dirs;
+	fsdata fsdata = { .fatbuf = NULL, }, *mydata = &fsdata;
+						/* for FATBUFSIZE */
+	int count;
 
-	if (read_bootsectandvi(&bs, &volinfo, &mydata->fatsize)) {
-		debug("error: reading boot sector\n");
-		return -1;
+	dirs = malloc_cache_aligned(sizeof(fat_itr));
+	if (!dirs) {
+		debug("Error: allocating memory\n");
+		count = -ENOMEM;
+		goto exit;
 	}
 
-	total_sector = bs.total_sect;
-	if (total_sector == 0)
-		total_sector = (int)cur_part_info.size; /* cast of lbaint_t */
+	/* duplicate fsdata */
+	fat_itr_child(dirs, itr);
+	fsdata = *dirs->fsdata;
 
-	if (mydata->fatsize == 32)
-		mydata->fatlength = bs.fat32_length;
-	else
-		mydata->fatlength = bs.fat_length;
+	/* allocate local fat buffer */
+	fsdata.fatbuf = malloc_cache_aligned(FATBUFSIZE);
+	if (!fsdata.fatbuf) {
+		debug("Error: allocating memory\n");
+		count = -ENOMEM;
+		goto exit;
+	}
+	fsdata.fatbufnum = -1;
+	dirs->fsdata = &fsdata;
+
+	for (count = 0; fat_itr_next(dirs); count++)
+		;
 
-	mydata->fat_sect = bs.reserved;
+exit:
+	free(fsdata.fatbuf);
+	free(dirs);
+	return count;
+}
 
-	cursect = mydata->rootdir_sect
-		= mydata->fat_sect + mydata->fatlength * bs.fats;
-	num_of_fats = bs.fats;
+static int delete_dentry(fat_itr *itr)
+{
+	fsdata *mydata = itr->fsdata;
+	dir_entry *dentptr = itr->dent;
 
-	mydata->sect_size = (bs.sector_size[1] << 8) + bs.sector_size[0];
-	mydata->clust_size = bs.cluster_size;
+	/* free cluster blocks */
+	clear_fatent(mydata, START(dentptr));
+	if (flush_dirty_fat_buffer(mydata) < 0) {
+		printf("Error: flush fat buffer\n");
+		return -EIO;
+	}
 
-	if (mydata->fatsize == 32) {
-		mydata->data_begin = mydata->rootdir_sect -
-					(mydata->clust_size * 2);
-	} else {
-		int rootdir_size;
+	/*
+	 * update a directory entry
+	 * TODO:
+	 *  - long file name support
+	 *  - find and mark the "new" first invalid entry as name[0]=0x00
+	 */
+	memset(dentptr, 0, sizeof(*dentptr));
+	dentptr->name[0] = 0xe5;
 
-		rootdir_size = ((bs.dir_entries[1]  * (int)256 +
-				 bs.dir_entries[0]) *
-				 sizeof(dir_entry)) /
-				 mydata->sect_size;
-		mydata->data_begin = mydata->rootdir_sect +
-					rootdir_size -
-					(mydata->clust_size * 2);
+	if (set_cluster(mydata, itr->clust, itr->block,
+			mydata->clust_size * mydata->sect_size) != 0) {
+		printf("error: writing directory entry\n");
+		return -EIO;
 	}
 
-	mydata->fatbufnum = -1;
-	mydata->fat_dirty = 0;
-	mydata->fatbuf = memalign(ARCH_DMA_MINALIGN, FATBUFSIZE);
-	if (mydata->fatbuf == NULL) {
-		debug("Error: allocating memory\n");
-		return -1;
+	return 0;
+}
+
+int fat_unlink(const char *filename)
+{
+	fsdata fsdata = { .fatbuf = NULL, };
+	fat_itr *itr = NULL;
+	int n_entries, ret;
+	char *filename_copy, *dirname, *basename;
+
+	filename_copy = strdup(filename);
+	split_filename(filename_copy, &dirname, &basename);
+
+	if (!strcmp(dirname, "/") && !strcmp(basename, "")) {
+		printf("Error: cannot remove root\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+	itr = malloc_cache_aligned(sizeof(fat_itr));
+	if (!itr) {
+		printf("Error: allocating memory\n");
+		return -ENOMEM;
+	}
+
+	ret = fat_itr_root(itr, &fsdata);
+	if (ret)
+		goto exit;
+
+	total_sector = fsdata.total_sect;
+
+	ret = fat_itr_resolve(itr, dirname, TYPE_DIR);
+	if (ret) {
+		printf("%s: doesn't exist (%d)\n", dirname, ret);
+		ret = -ENOENT;
+		goto exit;
 	}
 
-	if (disk_read(cursect,
-		(mydata->fatsize == 32) ?
-		(mydata->clust_size) :
-		PREFETCH_BLOCKS, do_fat_read_at_block) < 0) {
-		debug("Error: reading rootdir block\n");
+	if (!find_directory_entry(itr, basename)) {
+		printf("%s: doesn't exist\n", basename);
+		ret = -ENOENT;
 		goto exit;
 	}
-	dentptr = (dir_entry *) do_fat_read_at_block;
 
-	/* Strip leading (back-)slashes */
-	while ISDIRDELIM(*filename)
-		++filename;
-	/* Check that the filename is valid */
-	for (i = 0; i < strlen(illegal); ++i) {
-		*bad = illegal[i];
-		if (strstr(filename, bad)) {
-			printf("FAT: illegal filename (%s)\n", filename);
-			return -1;
+	if (fat_itr_isdir(itr)) {
+		n_entries = fat_dir_entries(itr);
+		if (n_entries < 0) {
+			ret = n_entries;
+			goto exit;
+		}
+		if (n_entries > 2) {
+			printf("Error: directory is not empty: %d\n",
+			       n_entries);
+			ret = -EINVAL;
+			goto exit;
 		}
 	}
 
-	name_len = strlen(filename);
-	if (name_len >= VFAT_MAXLEN_BYTES)
-		name_len = VFAT_MAXLEN_BYTES - 1;
+	ret = delete_dentry(itr);
 
-	memcpy(l_filename, filename, name_len);
-	l_filename[name_len] = 0; /* terminate the string */
-	downcase(l_filename, INT_MAX);
+exit:
+	free(fsdata.fatbuf);
+	free(itr);
+	free(filename_copy);
 
-	startsect = mydata->rootdir_sect;
-	retdent = find_directory_entry(mydata, startsect,
-				l_filename, dentptr, 0);
-	if (retdent) {
-		/* Update file size and start_cluster in a directory entry */
-		retdent->size = cpu_to_le32(size);
-		start_cluster = START(retdent);
+	return ret;
+}
 
-		if (start_cluster) {
-			if (size) {
-				ret = check_overflow(mydata, start_cluster,
-							size);
-				if (ret) {
-					printf("Error: %llu overflow\n", size);
-					goto exit;
-				}
-			}
+int fat_mkdir(const char *new_dirname)
+{
+	dir_entry *retdent;
+	fsdata datablock = { .fatbuf = NULL, };
+	fsdata *mydata = &datablock;
+	fat_itr *itr = NULL;
+	char *dirname_copy, *parent, *dirname;
+	char l_dirname[VFAT_MAXLEN_BYTES];
+	int ret = -1;
+	loff_t actwrite;
+	unsigned int bytesperclust;
+	dir_entry *dotdent = NULL;
 
-			ret = clear_fatent(mydata, start_cluster);
-			if (ret) {
-				printf("Error: clearing FAT entries\n");
-				goto exit;
-			}
+	dirname_copy = strdup(new_dirname);
+	if (!dirname_copy)
+		goto exit;
 
-			if (!size)
-				set_start_cluster(mydata, retdent, 0);
-		} else if (size) {
-			ret = start_cluster = find_empty_cluster(mydata);
-			if (ret < 0) {
-				printf("Error: finding empty cluster\n");
-				goto exit;
-			}
+	split_filename(dirname_copy, &parent, &dirname);
+	if (!strlen(dirname)) {
+		ret = -EINVAL;
+		goto exit;
+	}
 
-			ret = check_overflow(mydata, start_cluster, size);
-			if (ret) {
-				printf("Error: %llu overflow\n", size);
-				goto exit;
-			}
+	if (normalize_longname(l_dirname, dirname)) {
+		printf("FAT: illegal filename (%s)\n", dirname);
+		ret = -EINVAL;
+		goto exit;
+	}
 
-			set_start_cluster(mydata, retdent, start_cluster);
-		}
-	} else {
-		/* Set short name to set alias checksum field in dir_slot */
-		set_name(empty_dentptr, filename);
-		fill_dir_slot(mydata, &empty_dentptr, filename);
+	itr = malloc_cache_aligned(sizeof(fat_itr));
+	if (!itr) {
+		ret = -ENOMEM;
+		goto exit;
+	}
 
-		if (size) {
-			ret = start_cluster = find_empty_cluster(mydata);
-			if (ret < 0) {
-				printf("Error: finding empty cluster\n");
-				goto exit;
-			}
+	ret = fat_itr_root(itr, &datablock);
+	if (ret)
+		goto exit;
+
+	total_sector = datablock.total_sect;
+
+	ret = fat_itr_resolve(itr, parent, TYPE_DIR);
+	if (ret) {
+		printf("%s: doesn't exist (%d)\n", parent, ret);
+		goto exit;
+	}
+
+	retdent = find_directory_entry(itr, l_dirname);
 
-			ret = check_overflow(mydata, start_cluster, size);
-			if (ret) {
-				printf("Error: %llu overflow\n", size);
+	if (retdent) {
+		printf("%s: already exists\n", l_dirname);
+		ret = -EEXIST;
+		goto exit;
+	} else {
+		if (itr->is_root) {
+			/* root dir cannot have "." or ".." */
+			if (!strcmp(l_dirname, ".") ||
+			    !strcmp(l_dirname, "..")) {
+				ret = -EINVAL;
 				goto exit;
 			}
-		} else {
-			start_cluster = 0;
 		}
 
+		if (!itr->dent) {
+			printf("Error: allocating new dir entry\n");
+			ret = -EIO;
+			goto exit;
+		}
+
+		memset(itr->dent, 0, sizeof(*itr->dent));
+
-		/* Set attribute as archieve for regular file */
-		fill_dentry(mydata, empty_dentptr, filename,
-			start_cluster, size, 0x20);
+		/* Set short name to set alias checksum field in dir_slot */
+		set_name(itr->dent, dirname);
+		fill_dir_slot(itr, dirname);
+
+		/* Set attribute as archive for regular file */
+		fill_dentry(itr->fsdata, itr->dent, dirname, 0, 0,
+			    ATTR_DIR | ATTR_ARCH);
 
-		retdent = empty_dentptr;
+		retdent = itr->dent;
 	}
 
+	/* Default entries */
+	bytesperclust = mydata->clust_size * mydata->sect_size;
+	dotdent = malloc_cache_aligned(bytesperclust);
+	if (!dotdent) {
+		ret = -ENOMEM;
+		goto exit;
+	}
+	memset(dotdent, 0, bytesperclust);
+
+	memcpy(dotdent[0].name, ".       ", 8);
+	memcpy(dotdent[0].ext, "   ", 3);
+	dotdent[0].attr = ATTR_DIR | ATTR_ARCH;
+
+	memcpy(dotdent[1].name, "..      ", 8);
+	memcpy(dotdent[1].ext, "   ", 3);
+	dotdent[1].attr = ATTR_DIR | ATTR_ARCH;
+	set_start_cluster(mydata, &dotdent[1], itr->start_clust);
+
-	ret = set_contents(mydata, retdent, buffer, size, actwrite);
+	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
+			   bytesperclust, &actwrite);
 	if (ret < 0) {
 		printf("Error: writing contents\n");
 		goto exit;
 	}
-	debug("attempt to write 0x%llx bytes\n", *actwrite);
+	/* Write twice for "." */
+	set_start_cluster(mydata, &dotdent[0], START(retdent));
+	ret = set_contents(mydata, retdent, 0, (__u8 *)dotdent,
+			   bytesperclust, &actwrite);
+	if (ret < 0) {
+		printf("Error: writing contents\n");
+		goto exit;
+	}
 
 	/* Flush fat buffer */
 	ret = flush_dirty_fat_buffer(mydata);
@@ -1077,24 +1439,15 @@
 	}
 
 	/* Write directory table to device */
-	ret = set_cluster(mydata, dir_curclust, get_dentfromdir_block,
-			mydata->clust_size * mydata->sect_size);
+	ret = set_cluster(mydata, itr->clust, itr->block,
+			  mydata->clust_size * mydata->sect_size);
 	if (ret)
 		printf("Error: writing directory entry\n");
 
 exit:
+	free(dirname_copy);
 	free(mydata->fatbuf);
+	free(itr);
+	free(dotdent);
 	return ret;
 }
-
-int file_fat_write(const char *filename, void *buffer, loff_t offset,
-		   loff_t maxsize, loff_t *actwrite)
-{
-	if (offset != 0) {
-		printf("Error: non zero offset is currently not supported.\n");
-		return -1;
-	}
-
-	printf("writing %s\n", filename);
-	return do_fat_write(filename, buffer, maxsize, actwrite);
-}
diff --git a/fs/fs.c b/fs/fs.c
index cb68e81..adae98d 100644
--- a/fs/fs.c
+++ b/fs/fs.c
@@ -105,6 +105,16 @@
 	return -EACCES;
 }
 
+static inline int fs_unlink_unsupported(const char *filename)
+{
+	return -1;
+}
+
+static inline int fs_mkdir_unsupported(const char *dirname)
+{
+	return -1;
+}
+
 struct fstype_info {
 	int fstype;
 	char *name;
@@ -142,6 +152,8 @@
 	int (*readdir)(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
 	/* see fs_closedir() */
 	void (*closedir)(struct fs_dir_stream *dirs);
+	int (*unlink)(const char *filename);
+	int (*mkdir)(const char *dirname);
 };
 
 static struct fstype_info fstypes[] = {
@@ -158,8 +170,12 @@
 		.read = fat_read_file,
 #ifdef CONFIG_FAT_WRITE
 		.write = file_fat_write,
+		.unlink = fat_unlink,
+		.mkdir = fat_mkdir,
 #else
 		.write = fs_write_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 #endif
 		.uuid = fs_uuid_unsupported,
 		.opendir = fat_opendir,
@@ -185,6 +201,8 @@
 #endif
 		.uuid = ext4fs_uuid,
 		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 	},
 #endif
 #ifdef CONFIG_SANDBOX
@@ -201,6 +219,8 @@
 		.write = fs_write_sandbox,
 		.uuid = fs_uuid_unsupported,
 		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 	},
 #endif
 #ifdef CONFIG_CMD_UBIFS
@@ -217,6 +237,8 @@
 		.write = fs_write_unsupported,
 		.uuid = fs_uuid_unsupported,
 		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 	},
 #endif
 #ifdef CONFIG_FS_BTRFS
@@ -233,6 +255,8 @@
 		.write = fs_write_unsupported,
 		.uuid = btrfs_uuid,
 		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 	},
 #endif
 	{
@@ -248,6 +272,8 @@
 		.write = fs_write_unsupported,
 		.uuid = fs_uuid_unsupported,
 		.opendir = fs_opendir_unsupported,
+		.unlink = fs_unlink_unsupported,
+		.mkdir = fs_mkdir_unsupported,
 	},
 };
 
@@ -497,6 +523,33 @@
 	fs_close();
 }
 
+int fs_unlink(const char *filename)
+{
+	int ret;
+
+	struct fstype_info *info = fs_get_info(fs_type);
+
+	ret = info->unlink(filename);
+
+	fs_type = FS_TYPE_ANY;
+	fs_close();
+
+	return ret;
+}
+
+int fs_mkdir(const char *dirname)
+{
+	int ret;
+
+	struct fstype_info *info = fs_get_info(fs_type);
+
+	ret = info->mkdir(dirname);
+
+	fs_type = FS_TYPE_ANY;
+	fs_close();
+
+	return ret;
+}
 
 int do_size(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 		int fstype)
@@ -700,3 +753,37 @@
 	return CMD_RET_SUCCESS;
 }
 
+int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+	  int fstype)
+{
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (fs_set_blk_dev(argv[1], argv[2], fstype))
+		return 1;
+
+	if (fs_unlink(argv[3]))
+		return 1;
+
+	return 0;
+}
+
+int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+	     int fstype)
+{
+	int ret;
+
+	if (argc != 4)
+		return CMD_RET_USAGE;
+
+	if (fs_set_blk_dev(argv[1], argv[2], fstype))
+		return 1;
+
+	ret = fs_mkdir(argv[3]);
+	if (ret) {
+		printf("** Unable to create a directory \"%s\" **\n", argv[3]);
+		return 1;
+	}
+
+	return 0;
+}
diff --git a/include/asm-generic/atomic.h b/include/asm-generic/atomic.h
new file mode 100644
index 0000000..94d0747
--- /dev/null
+++ b/include/asm-generic/atomic.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+#ifndef _ASM_GENERIC_ATOMIC_H
+#define _ASM_GENERIC_ATOMIC_H
+
+typedef struct { volatile int counter; } atomic_t;
+#if BITS_PER_LONG == 32
+typedef struct { volatile long long counter; } atomic64_t;
+#else /* BIT_PER_LONG == 32 */
+typedef struct { volatile long counter; } atomic64_t;
+#endif
+
+#define ATOMIC_INIT(i)	{ (i) }
+
+#define atomic_read(v)		((v)->counter)
+#define atomic_set(v, i)	((v)->counter = (i))
+#define atomic64_read(v)	atomic_read(v)
+#define atomic64_set(v, i)	atomic_set(v, i)
+
+static inline void atomic_add(int i, atomic_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter += i;
+	local_irq_restore(flags);
+}
+
+static inline void atomic_sub(int i, atomic_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter -= i;
+	local_irq_restore(flags);
+}
+
+static inline void atomic_inc(atomic_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	++v->counter;
+	local_irq_restore(flags);
+}
+
+static inline void atomic_dec(atomic_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	--v->counter;
+	local_irq_restore(flags);
+}
+
+static inline int atomic_dec_and_test(volatile atomic_t *v)
+{
+	unsigned long flags = 0;
+	int val;
+
+	local_irq_save(flags);
+	val = v->counter;
+	v->counter = val -= 1;
+	local_irq_restore(flags);
+
+	return val == 0;
+}
+
+static inline int atomic_add_negative(int i, volatile atomic_t *v)
+{
+	unsigned long flags = 0;
+	int val;
+
+	local_irq_save(flags);
+	val = v->counter;
+	v->counter = val += i;
+	local_irq_restore(flags);
+
+	return val < 0;
+}
+
+static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	*addr &= ~mask;
+	local_irq_restore(flags);
+}
+
+#if BITS_PER_LONG == 32
+
+static inline void atomic64_add(long long i, volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter += i;
+	local_irq_restore(flags);
+}
+
+static inline void atomic64_sub(long long i, volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter -= i;
+	local_irq_restore(flags);
+}
+
+#else /* BIT_PER_LONG == 32 */
+
+static inline void atomic64_add(long i, volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter += i;
+	local_irq_restore(flags);
+}
+
+static inline void atomic64_sub(long i, volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter -= i;
+	local_irq_restore(flags);
+}
+#endif
+
+static inline void atomic64_inc(volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter += 1;
+	local_irq_restore(flags);
+}
+
+static inline void atomic64_dec(volatile atomic64_t *v)
+{
+	unsigned long flags = 0;
+
+	local_irq_save(flags);
+	v->counter -= 1;
+	local_irq_restore(flags);
+}
+
+#endif
diff --git a/include/blk.h b/include/blk.h
index 86f6d50..6af2196 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -406,6 +406,15 @@
  */
 int blk_get_from_parent(struct udevice *parent, struct udevice **devp);
 
+/**
+ * blk_get_by_device() - Get the block device descriptor for the given device
+ * @dev:	Instance of a storage device
+ *
+ * Return: With block device descriptor on success , NULL if there is no such
+ *	   block device.
+ */
+struct blk_desc *blk_get_by_device(struct udevice *dev);
+
 #else
 #include <errno.h>
 /*
diff --git a/include/capitalization.h b/include/capitalization.h
new file mode 100644
index 0000000..9d7e8d2
--- /dev/null
+++ b/include/capitalization.h
@@ -0,0 +1,2028 @@
+/* SPDX-License-Identifier: Unicode-DFS-2016 */
+/*
+ * Capitalization tables
+ */
+
+struct capitalization_table {
+	u16 upper;
+	u16 lower;
+};
+
+/*
+ * Correspondence table for small and capital Unicode letters in the range of
+ * 0x0000 - 0xffff based on http://www.unicode.org/Public/UCA/11.0.0/allkeys.txt
+ */
+#define UNICODE_CAPITALIZATION_TABLE { \
+	{ 0x0531, /* ARMENIAN CAPITAL LETTER AYB */ \
+	  0x0561, /* ARMENIAN SMALL LETTER AYB */ }, \
+	{ 0x0532, /* ARMENIAN CAPITAL LETTER BEN */ \
+	  0x0562, /* ARMENIAN SMALL LETTER BEN */ }, \
+	{ 0x053E, /* ARMENIAN CAPITAL LETTER CA */ \
+	  0x056E, /* ARMENIAN SMALL LETTER CA */ }, \
+	{ 0x0549, /* ARMENIAN CAPITAL LETTER CHA */ \
+	  0x0579, /* ARMENIAN SMALL LETTER CHA */ }, \
+	{ 0x0543, /* ARMENIAN CAPITAL LETTER CHEH */ \
+	  0x0573, /* ARMENIAN SMALL LETTER CHEH */ }, \
+	{ 0x0551, /* ARMENIAN CAPITAL LETTER CO */ \
+	  0x0581, /* ARMENIAN SMALL LETTER CO */ }, \
+	{ 0x0534, /* ARMENIAN CAPITAL LETTER DA */ \
+	  0x0564, /* ARMENIAN SMALL LETTER DA */ }, \
+	{ 0x0535, /* ARMENIAN CAPITAL LETTER ECH */ \
+	  0x0565, /* ARMENIAN SMALL LETTER ECH */ }, \
+	{ 0x0537, /* ARMENIAN CAPITAL LETTER EH */ \
+	  0x0567, /* ARMENIAN SMALL LETTER EH */ }, \
+	{ 0x0538, /* ARMENIAN CAPITAL LETTER ET */ \
+	  0x0568, /* ARMENIAN SMALL LETTER ET */ }, \
+	{ 0x0556, /* ARMENIAN CAPITAL LETTER FEH */ \
+	  0x0586, /* ARMENIAN SMALL LETTER FEH */ }, \
+	{ 0x0542, /* ARMENIAN CAPITAL LETTER GHAD */ \
+	  0x0572, /* ARMENIAN SMALL LETTER GHAD */ }, \
+	{ 0x0533, /* ARMENIAN CAPITAL LETTER GIM */ \
+	  0x0563, /* ARMENIAN SMALL LETTER GIM */ }, \
+	{ 0x0540, /* ARMENIAN CAPITAL LETTER HO */ \
+	  0x0570, /* ARMENIAN SMALL LETTER HO */ }, \
+	{ 0x053B, /* ARMENIAN CAPITAL LETTER INI */ \
+	  0x056B, /* ARMENIAN SMALL LETTER INI */ }, \
+	{ 0x0541, /* ARMENIAN CAPITAL LETTER JA */ \
+	  0x0571, /* ARMENIAN SMALL LETTER JA */ }, \
+	{ 0x054B, /* ARMENIAN CAPITAL LETTER JHEH */ \
+	  0x057B, /* ARMENIAN SMALL LETTER JHEH */ }, \
+	{ 0x0554, /* ARMENIAN CAPITAL LETTER KEH */ \
+	  0x0584, /* ARMENIAN SMALL LETTER KEH */ }, \
+	{ 0x053F, /* ARMENIAN CAPITAL LETTER KEN */ \
+	  0x056F, /* ARMENIAN SMALL LETTER KEN */ }, \
+	{ 0x053C, /* ARMENIAN CAPITAL LETTER LIWN */ \
+	  0x056C, /* ARMENIAN SMALL LETTER LIWN */ }, \
+	{ 0x0544, /* ARMENIAN CAPITAL LETTER MEN */ \
+	  0x0574, /* ARMENIAN SMALL LETTER MEN */ }, \
+	{ 0x0546, /* ARMENIAN CAPITAL LETTER NOW */ \
+	  0x0576, /* ARMENIAN SMALL LETTER NOW */ }, \
+	{ 0x0555, /* ARMENIAN CAPITAL LETTER OH */ \
+	  0x0585, /* ARMENIAN SMALL LETTER OH */ }, \
+	{ 0x054A, /* ARMENIAN CAPITAL LETTER PEH */ \
+	  0x057A, /* ARMENIAN SMALL LETTER PEH */ }, \
+	{ 0x0553, /* ARMENIAN CAPITAL LETTER PIWR */ \
+	  0x0583, /* ARMENIAN SMALL LETTER PIWR */ }, \
+	{ 0x054C, /* ARMENIAN CAPITAL LETTER RA */ \
+	  0x057C, /* ARMENIAN SMALL LETTER RA */ }, \
+	{ 0x0550, /* ARMENIAN CAPITAL LETTER REH */ \
+	  0x0580, /* ARMENIAN SMALL LETTER REH */ }, \
+	{ 0x054D, /* ARMENIAN CAPITAL LETTER SEH */ \
+	  0x057D, /* ARMENIAN SMALL LETTER SEH */ }, \
+	{ 0x0547, /* ARMENIAN CAPITAL LETTER SHA */ \
+	  0x0577, /* ARMENIAN SMALL LETTER SHA */ }, \
+	{ 0x054F, /* ARMENIAN CAPITAL LETTER TIWN */ \
+	  0x057F, /* ARMENIAN SMALL LETTER TIWN */ }, \
+	{ 0x0539, /* ARMENIAN CAPITAL LETTER TO */ \
+	  0x0569, /* ARMENIAN SMALL LETTER TO */ }, \
+	{ 0x054E, /* ARMENIAN CAPITAL LETTER VEW */ \
+	  0x057E, /* ARMENIAN SMALL LETTER VEW */ }, \
+	{ 0x0548, /* ARMENIAN CAPITAL LETTER VO */ \
+	  0x0578, /* ARMENIAN SMALL LETTER VO */ }, \
+	{ 0x053D, /* ARMENIAN CAPITAL LETTER XEH */ \
+	  0x056D, /* ARMENIAN SMALL LETTER XEH */ }, \
+	{ 0x0545, /* ARMENIAN CAPITAL LETTER YI */ \
+	  0x0575, /* ARMENIAN SMALL LETTER YI */ }, \
+	{ 0x0552, /* ARMENIAN CAPITAL LETTER YIWN */ \
+	  0x0582, /* ARMENIAN SMALL LETTER YIWN */ }, \
+	{ 0x0536, /* ARMENIAN CAPITAL LETTER ZA */ \
+	  0x0566, /* ARMENIAN SMALL LETTER ZA */ }, \
+	{ 0x053A, /* ARMENIAN CAPITAL LETTER ZHE */ \
+	  0x056A, /* ARMENIAN SMALL LETTER ZHE */ }, \
+	{ 0x24B6, /* CIRCLED LATIN CAPITAL LETTER A */ \
+	  0x24D0, /* CIRCLED LATIN SMALL LETTER A */ }, \
+	{ 0x24B7, /* CIRCLED LATIN CAPITAL LETTER B */ \
+	  0x24D1, /* CIRCLED LATIN SMALL LETTER B */ }, \
+	{ 0x24B8, /* CIRCLED LATIN CAPITAL LETTER C */ \
+	  0x24D2, /* CIRCLED LATIN SMALL LETTER C */ }, \
+	{ 0x24B9, /* CIRCLED LATIN CAPITAL LETTER D */ \
+	  0x24D3, /* CIRCLED LATIN SMALL LETTER D */ }, \
+	{ 0x24BA, /* CIRCLED LATIN CAPITAL LETTER E */ \
+	  0x24D4, /* CIRCLED LATIN SMALL LETTER E */ }, \
+	{ 0x24BB, /* CIRCLED LATIN CAPITAL LETTER F */ \
+	  0x24D5, /* CIRCLED LATIN SMALL LETTER F */ }, \
+	{ 0x24BC, /* CIRCLED LATIN CAPITAL LETTER G */ \
+	  0x24D6, /* CIRCLED LATIN SMALL LETTER G */ }, \
+	{ 0x24BD, /* CIRCLED LATIN CAPITAL LETTER H */ \
+	  0x24D7, /* CIRCLED LATIN SMALL LETTER H */ }, \
+	{ 0x24BE, /* CIRCLED LATIN CAPITAL LETTER I */ \
+	  0x24D8, /* CIRCLED LATIN SMALL LETTER I */ }, \
+	{ 0x24BF, /* CIRCLED LATIN CAPITAL LETTER J */ \
+	  0x24D9, /* CIRCLED LATIN SMALL LETTER J */ }, \
+	{ 0x24C0, /* CIRCLED LATIN CAPITAL LETTER K */ \
+	  0x24DA, /* CIRCLED LATIN SMALL LETTER K */ }, \
+	{ 0x24C1, /* CIRCLED LATIN CAPITAL LETTER L */ \
+	  0x24DB, /* CIRCLED LATIN SMALL LETTER L */ }, \
+	{ 0x24C2, /* CIRCLED LATIN CAPITAL LETTER M */ \
+	  0x24DC, /* CIRCLED LATIN SMALL LETTER M */ }, \
+	{ 0x24C3, /* CIRCLED LATIN CAPITAL LETTER N */ \
+	  0x24DD, /* CIRCLED LATIN SMALL LETTER N */ }, \
+	{ 0x24C4, /* CIRCLED LATIN CAPITAL LETTER O */ \
+	  0x24DE, /* CIRCLED LATIN SMALL LETTER O */ }, \
+	{ 0x24C5, /* CIRCLED LATIN CAPITAL LETTER P */ \
+	  0x24DF, /* CIRCLED LATIN SMALL LETTER P */ }, \
+	{ 0x24C6, /* CIRCLED LATIN CAPITAL LETTER Q */ \
+	  0x24E0, /* CIRCLED LATIN SMALL LETTER Q */ }, \
+	{ 0x24C7, /* CIRCLED LATIN CAPITAL LETTER R */ \
+	  0x24E1, /* CIRCLED LATIN SMALL LETTER R */ }, \
+	{ 0x24C8, /* CIRCLED LATIN CAPITAL LETTER S */ \
+	  0x24E2, /* CIRCLED LATIN SMALL LETTER S */ }, \
+	{ 0x24C9, /* CIRCLED LATIN CAPITAL LETTER T */ \
+	  0x24E3, /* CIRCLED LATIN SMALL LETTER T */ }, \
+	{ 0x24CA, /* CIRCLED LATIN CAPITAL LETTER U */ \
+	  0x24E4, /* CIRCLED LATIN SMALL LETTER U */ }, \
+	{ 0x24CB, /* CIRCLED LATIN CAPITAL LETTER V */ \
+	  0x24E5, /* CIRCLED LATIN SMALL LETTER V */ }, \
+	{ 0x24CC, /* CIRCLED LATIN CAPITAL LETTER W */ \
+	  0x24E6, /* CIRCLED LATIN SMALL LETTER W */ }, \
+	{ 0x24CD, /* CIRCLED LATIN CAPITAL LETTER X */ \
+	  0x24E7, /* CIRCLED LATIN SMALL LETTER X */ }, \
+	{ 0x24CE, /* CIRCLED LATIN CAPITAL LETTER Y */ \
+	  0x24E8, /* CIRCLED LATIN SMALL LETTER Y */ }, \
+	{ 0x24CF, /* CIRCLED LATIN CAPITAL LETTER Z */ \
+	  0x24E9, /* CIRCLED LATIN SMALL LETTER Z */ }, \
+	{ 0x2CC8, /* COPTIC CAPITAL LETTER AKHMIMIC KHEI */ \
+	  0x2CC9, /* COPTIC SMALL LETTER AKHMIMIC KHEI */ }, \
+	{ 0x2C80, /* COPTIC CAPITAL LETTER ALFA */ \
+	  0x2C81, /* COPTIC SMALL LETTER ALFA */ }, \
+	{ 0x2CF2, /* COPTIC CAPITAL LETTER BOHAIRIC KHEI */ \
+	  0x2CF3, /* COPTIC SMALL LETTER BOHAIRIC KHEI */ }, \
+	{ 0x2CC2, /* COPTIC CAPITAL LETTER CROSSED SHEI */ \
+	  0x2CC3, /* COPTIC SMALL LETTER CROSSED SHEI */ }, \
+	{ 0x2CB6, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE */ \
+	  0x2CB7, /* COPTIC SMALL LETTER CRYPTOGRAMMIC EIE */ }, \
+	{ 0x2CED, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC GANGIA */ \
+	  0x2CEE, /* COPTIC SMALL LETTER CRYPTOGRAMMIC GANGIA */ }, \
+	{ 0x2CBC, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI */ \
+	  0x2CBD, /* COPTIC SMALL LETTER CRYPTOGRAMMIC NI */ }, \
+	{ 0x2CEB, /* COPTIC CAPITAL LETTER CRYPTOGRAMMIC SHEI */ \
+	  0x2CEC, /* COPTIC SMALL LETTER CRYPTOGRAMMIC SHEI */ }, \
+	{ 0x2C86, /* COPTIC CAPITAL LETTER DALDA */ \
+	  0x2C87, /* COPTIC SMALL LETTER DALDA */ }, \
+	{ 0x03EE, /* COPTIC CAPITAL LETTER DEI */ \
+	  0x03EF, /* COPTIC SMALL LETTER DEI */ }, \
+	{ 0x2CB2, /* COPTIC CAPITAL LETTER DIALECT-P ALEF */ \
+	  0x2CB3, /* COPTIC SMALL LETTER DIALECT-P ALEF */ }, \
+	{ 0x2CCA, /* COPTIC CAPITAL LETTER DIALECT-P HORI */ \
+	  0x2CCB, /* COPTIC SMALL LETTER DIALECT-P HORI */ }, \
+	{ 0x2CB8, /* COPTIC CAPITAL LETTER DIALECT-P KAPA */ \
+	  0x2CB9, /* COPTIC SMALL LETTER DIALECT-P KAPA */ }, \
+	{ 0x2CBA, /* COPTIC CAPITAL LETTER DIALECT-P NI */ \
+	  0x2CBB, /* COPTIC SMALL LETTER DIALECT-P NI */ }, \
+	{ 0x2C88, /* COPTIC CAPITAL LETTER EIE */ \
+	  0x2C89, /* COPTIC SMALL LETTER EIE */ }, \
+	{ 0x03E4, /* COPTIC CAPITAL LETTER FEI */ \
+	  0x03E5, /* COPTIC SMALL LETTER FEI */ }, \
+	{ 0x2CAA, /* COPTIC CAPITAL LETTER FI */ \
+	  0x2CAB, /* COPTIC SMALL LETTER FI */ }, \
+	{ 0x2C84, /* COPTIC CAPITAL LETTER GAMMA */ \
+	  0x2C85, /* COPTIC SMALL LETTER GAMMA */ }, \
+	{ 0x03EA, /* COPTIC CAPITAL LETTER GANGIA */ \
+	  0x03EB, /* COPTIC SMALL LETTER GANGIA */ }, \
+	{ 0x2C8E, /* COPTIC CAPITAL LETTER HATE */ \
+	  0x2C8F, /* COPTIC SMALL LETTER HATE */ }, \
+	{ 0x03E8, /* COPTIC CAPITAL LETTER HORI */ \
+	  0x03E9, /* COPTIC SMALL LETTER HORI */ }, \
+	{ 0x2C92, /* COPTIC CAPITAL LETTER IAUDA */ \
+	  0x2C93, /* COPTIC SMALL LETTER IAUDA */ }, \
+	{ 0x2C94, /* COPTIC CAPITAL LETTER KAPA */ \
+	  0x2C95, /* COPTIC SMALL LETTER KAPA */ }, \
+	{ 0x03E6, /* COPTIC CAPITAL LETTER KHEI */ \
+	  0x03E7, /* COPTIC SMALL LETTER KHEI */ }, \
+	{ 0x2CAC, /* COPTIC CAPITAL LETTER KHI */ \
+	  0x2CAD, /* COPTIC SMALL LETTER KHI */ }, \
+	{ 0x2C9C, /* COPTIC CAPITAL LETTER KSI */ \
+	  0x2C9D, /* COPTIC SMALL LETTER KSI */ }, \
+	{ 0x2C96, /* COPTIC CAPITAL LETTER LAULA */ \
+	  0x2C97, /* COPTIC SMALL LETTER LAULA */ }, \
+	{ 0x2CD0, /* COPTIC CAPITAL LETTER L-SHAPED HA */ \
+	  0x2CD1, /* COPTIC SMALL LETTER L-SHAPED HA */ }, \
+	{ 0x2C98, /* COPTIC CAPITAL LETTER MI */ \
+	  0x2C99, /* COPTIC SMALL LETTER MI */ }, \
+	{ 0x2C9A, /* COPTIC CAPITAL LETTER NI */ \
+	  0x2C9B, /* COPTIC SMALL LETTER NI */ }, \
+	{ 0x2C9E, /* COPTIC CAPITAL LETTER O */ \
+	  0x2C9F, /* COPTIC SMALL LETTER O */ }, \
+	{ 0x2CB4, /* COPTIC CAPITAL LETTER OLD COPTIC AIN */ \
+	  0x2CB5, /* COPTIC SMALL LETTER OLD COPTIC AIN */ }, \
+	{ 0x2CD8, /* COPTIC CAPITAL LETTER OLD COPTIC DJA */ \
+	  0x2CD9, /* COPTIC SMALL LETTER OLD COPTIC DJA */ }, \
+	{ 0x2CC6, /* COPTIC CAPITAL LETTER OLD COPTIC ESH */ \
+	  0x2CC7, /* COPTIC SMALL LETTER OLD COPTIC ESH */ }, \
+	{ 0x2CD6, /* COPTIC CAPITAL LETTER OLD COPTIC GANGIA */ \
+	  0x2CD7, /* COPTIC SMALL LETTER OLD COPTIC GANGIA */ }, \
+	{ 0x2CCE, /* COPTIC CAPITAL LETTER OLD COPTIC HA */ \
+	  0x2CCF, /* COPTIC SMALL LETTER OLD COPTIC HA */ }, \
+	{ 0x2CD4, /* COPTIC CAPITAL LETTER OLD COPTIC HAT */ \
+	  0x2CD5, /* COPTIC SMALL LETTER OLD COPTIC HAT */ }, \
+	{ 0x2CD2, /* COPTIC CAPITAL LETTER OLD COPTIC HEI */ \
+	  0x2CD3, /* COPTIC SMALL LETTER OLD COPTIC HEI */ }, \
+	{ 0x2CCC, /* COPTIC CAPITAL LETTER OLD COPTIC HORI */ \
+	  0x2CCD, /* COPTIC SMALL LETTER OLD COPTIC HORI */ }, \
+	{ 0x2CBE, /* COPTIC CAPITAL LETTER OLD COPTIC OOU */ \
+	  0x2CBF, /* COPTIC SMALL LETTER OLD COPTIC OOU */ }, \
+	{ 0x2CC4, /* COPTIC CAPITAL LETTER OLD COPTIC SHEI */ \
+	  0x2CC5, /* COPTIC SMALL LETTER OLD COPTIC SHEI */ }, \
+	{ 0x2CDA, /* COPTIC CAPITAL LETTER OLD COPTIC SHIMA */ \
+	  0x2CDB, /* COPTIC SMALL LETTER OLD COPTIC SHIMA */ }, \
+	{ 0x2CDE, /* COPTIC CAPITAL LETTER OLD NUBIAN NGI */ \
+	  0x2CDF, /* COPTIC SMALL LETTER OLD NUBIAN NGI */ }, \
+	{ 0x2CE0, /* COPTIC CAPITAL LETTER OLD NUBIAN NYI */ \
+	  0x2CE1, /* COPTIC SMALL LETTER OLD NUBIAN NYI */ }, \
+	{ 0x2CDC, /* COPTIC CAPITAL LETTER OLD NUBIAN SHIMA */ \
+	  0x2CDD, /* COPTIC SMALL LETTER OLD NUBIAN SHIMA */ }, \
+	{ 0x2CE2, /* COPTIC CAPITAL LETTER OLD NUBIAN WAU */ \
+	  0x2CE3, /* COPTIC SMALL LETTER OLD NUBIAN WAU */ }, \
+	{ 0x2CB0, /* COPTIC CAPITAL LETTER OOU */ \
+	  0x2CB1, /* COPTIC SMALL LETTER OOU */ }, \
+	{ 0x2CA0, /* COPTIC CAPITAL LETTER PI */ \
+	  0x2CA1, /* COPTIC SMALL LETTER PI */ }, \
+	{ 0x2CAE, /* COPTIC CAPITAL LETTER PSI */ \
+	  0x2CAF, /* COPTIC SMALL LETTER PSI */ }, \
+	{ 0x2CA2, /* COPTIC CAPITAL LETTER RO */ \
+	  0x2CA3, /* COPTIC SMALL LETTER RO */ }, \
+	{ 0x2CC0, /* COPTIC CAPITAL LETTER SAMPI */ \
+	  0x2CC1, /* COPTIC SMALL LETTER SAMPI */ }, \
+	{ 0x03E2, /* COPTIC CAPITAL LETTER SHEI */ \
+	  0x03E3, /* COPTIC SMALL LETTER SHEI */ }, \
+	{ 0x03EC, /* COPTIC CAPITAL LETTER SHIMA */ \
+	  0x03ED, /* COPTIC SMALL LETTER SHIMA */ }, \
+	{ 0x2CA4, /* COPTIC CAPITAL LETTER SIMA */ \
+	  0x2CA5, /* COPTIC SMALL LETTER SIMA */ }, \
+	{ 0x2C8A, /* COPTIC CAPITAL LETTER SOU */ \
+	  0x2C8B, /* COPTIC SMALL LETTER SOU */ }, \
+	{ 0x2CA6, /* COPTIC CAPITAL LETTER TAU */ \
+	  0x2CA7, /* COPTIC SMALL LETTER TAU */ }, \
+	{ 0x2C90, /* COPTIC CAPITAL LETTER THETHE */ \
+	  0x2C91, /* COPTIC SMALL LETTER THETHE */ }, \
+	{ 0x2CA8, /* COPTIC CAPITAL LETTER UA */ \
+	  0x2CA9, /* COPTIC SMALL LETTER UA */ }, \
+	{ 0x2C82, /* COPTIC CAPITAL LETTER VIDA */ \
+	  0x2C83, /* COPTIC SMALL LETTER VIDA */ }, \
+	{ 0x2C8C, /* COPTIC CAPITAL LETTER ZATA */ \
+	  0x2C8D, /* COPTIC SMALL LETTER ZATA */ }, \
+	{ 0x0410, /* CYRILLIC CAPITAL LETTER A */ \
+	  0x0430, /* CYRILLIC SMALL LETTER A */ }, \
+	{ 0x04D0, /* CYRILLIC CAPITAL LETTER A WITH BREVE */ \
+	  0x04D1, /* CYRILLIC SMALL LETTER A WITH BREVE */ }, \
+	{ 0x04D2, /* CYRILLIC CAPITAL LETTER A WITH DIAERESIS */ \
+	  0x04D3, /* CYRILLIC SMALL LETTER A WITH DIAERESIS */ }, \
+	{ 0x04BC, /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE */ \
+	  0x04BD, /* CYRILLIC SMALL LETTER ABKHASIAN CHE */ }, \
+	{ 0x04BE, /* CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER */ \
+	  0x04BF, /* CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER */ }, \
+	{ 0x04E0, /* CYRILLIC CAPITAL LETTER ABKHASIAN DZE */ \
+	  0x04E1, /* CYRILLIC SMALL LETTER ABKHASIAN DZE */ }, \
+	{ 0x04A8, /* CYRILLIC CAPITAL LETTER ABKHASIAN HA */ \
+	  0x04A9, /* CYRILLIC SMALL LETTER ABKHASIAN HA */ }, \
+	{ 0x051E, /* CYRILLIC CAPITAL LETTER ALEUT KA */ \
+	  0x051F, /* CYRILLIC SMALL LETTER ALEUT KA */ }, \
+	{ 0x04E8, /* CYRILLIC CAPITAL LETTER BARRED O */ \
+	  0x04E9, /* CYRILLIC SMALL LETTER BARRED O */ }, \
+	{ 0x04EA, /* CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS */ \
+	  0x04EB, /* CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS */ }, \
+	{ 0x04A0, /* CYRILLIC CAPITAL LETTER BASHKIR KA */ \
+	  0x04A1, /* CYRILLIC SMALL LETTER BASHKIR KA */ }, \
+	{ 0x0411, /* CYRILLIC CAPITAL LETTER BE */ \
+	  0x0431, /* CYRILLIC SMALL LETTER BE */ }, \
+	{ 0x046A, /* CYRILLIC CAPITAL LETTER BIG YUS */ \
+	  0x046B, /* CYRILLIC SMALL LETTER BIG YUS */ }, \
+	{ 0xA66A, /* CYRILLIC CAPITAL LETTER BINOCULAR O */ \
+	  0xA66B, /* CYRILLIC SMALL LETTER BINOCULAR O */ }, \
+	{ 0xA65A, /* CYRILLIC CAPITAL LETTER BLENDED YUS */ \
+	  0xA65B, /* CYRILLIC SMALL LETTER BLENDED YUS */ }, \
+	{ 0xA64C, /* CYRILLIC CAPITAL LETTER BROAD OMEGA */ \
+	  0xA64D, /* CYRILLIC SMALL LETTER BROAD OMEGA */ }, \
+	{ 0x0406, /* CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I */ \
+	  0x0456, /* CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I */ }, \
+	{ 0xA686, /* CYRILLIC CAPITAL LETTER CCHE */ \
+	  0xA687, /* CYRILLIC SMALL LETTER CCHE */ }, \
+	{ 0x0427, /* CYRILLIC CAPITAL LETTER CHE */ \
+	  0x0447, /* CYRILLIC SMALL LETTER CHE */ }, \
+	{ 0x04B6, /* CYRILLIC CAPITAL LETTER CHE WITH DESCENDER */ \
+	  0x04B7, /* CYRILLIC SMALL LETTER CHE WITH DESCENDER */ }, \
+	{ 0x04F4, /* CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS */ \
+	  0x04F5, /* CYRILLIC SMALL LETTER CHE WITH DIAERESIS */ }, \
+	{ 0x04B8, /* CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE */ \
+	  0x04B9, /* CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE */ }, \
+	{ 0xA658, /* CYRILLIC CAPITAL LETTER CLOSED LITTLE YUS */ \
+	  0xA659, /* CYRILLIC SMALL LETTER CLOSED LITTLE YUS */ }, \
+	{ 0xA69A, /* CYRILLIC CAPITAL LETTER CROSSED O */ \
+	  0xA69B, /* CYRILLIC SMALL LETTER CROSSED O */ }, \
+	{ 0x052C, /* CYRILLIC CAPITAL LETTER DCHE */ \
+	  0x052D, /* CYRILLIC SMALL LETTER DCHE */ }, \
+	{ 0x0414, /* CYRILLIC CAPITAL LETTER DE */ \
+	  0x0434, /* CYRILLIC SMALL LETTER DE */ }, \
+	{ 0x0402, /* CYRILLIC CAPITAL LETTER DJE */ \
+	  0x0452, /* CYRILLIC SMALL LETTER DJE */ }, \
+	{ 0xA648, /* CYRILLIC CAPITAL LETTER DJERV */ \
+	  0xA649, /* CYRILLIC SMALL LETTER DJERV */ }, \
+	{ 0xA66C, /* CYRILLIC CAPITAL LETTER DOUBLE MONOCULAR O */ \
+	  0xA66D, /* CYRILLIC SMALL LETTER DOUBLE MONOCULAR O */ }, \
+	{ 0xA698, /* CYRILLIC CAPITAL LETTER DOUBLE O */ \
+	  0xA699, /* CYRILLIC SMALL LETTER DOUBLE O */ }, \
+	{ 0xA680, /* CYRILLIC CAPITAL LETTER DWE */ \
+	  0xA681, /* CYRILLIC SMALL LETTER DWE */ }, \
+	{ 0x0405, /* CYRILLIC CAPITAL LETTER DZE */ \
+	  0x0455, /* CYRILLIC SMALL LETTER DZE */ }, \
+	{ 0xA642, /* CYRILLIC CAPITAL LETTER DZELO */ \
+	  0xA643, /* CYRILLIC SMALL LETTER DZELO */ }, \
+	{ 0x040F, /* CYRILLIC CAPITAL LETTER DZHE */ \
+	  0x045F, /* CYRILLIC SMALL LETTER DZHE */ }, \
+	{ 0xA682, /* CYRILLIC CAPITAL LETTER DZWE */ \
+	  0xA683, /* CYRILLIC SMALL LETTER DZWE */ }, \
+	{ 0xA688, /* CYRILLIC CAPITAL LETTER DZZE */ \
+	  0xA689, /* CYRILLIC SMALL LETTER DZZE */ }, \
+	{ 0x052A, /* CYRILLIC CAPITAL LETTER DZZHE */ \
+	  0x052B, /* CYRILLIC SMALL LETTER DZZHE */ }, \
+	{ 0x042D, /* CYRILLIC CAPITAL LETTER E */ \
+	  0x044D, /* CYRILLIC SMALL LETTER E */ }, \
+	{ 0x04EC, /* CYRILLIC CAPITAL LETTER E WITH DIAERESIS */ \
+	  0x04ED, /* CYRILLIC SMALL LETTER E WITH DIAERESIS */ }, \
+	{ 0x0424, /* CYRILLIC CAPITAL LETTER EF */ \
+	  0x0444, /* CYRILLIC SMALL LETTER EF */ }, \
+	{ 0x041B, /* CYRILLIC CAPITAL LETTER EL */ \
+	  0x043B, /* CYRILLIC SMALL LETTER EL */ }, \
+	{ 0x052E, /* CYRILLIC CAPITAL LETTER EL WITH DESCENDER */ \
+	  0x052F, /* CYRILLIC SMALL LETTER EL WITH DESCENDER */ }, \
+	{ 0x0512, /* CYRILLIC CAPITAL LETTER EL WITH HOOK */ \
+	  0x0513, /* CYRILLIC SMALL LETTER EL WITH HOOK */ }, \
+	{ 0x0520, /* CYRILLIC CAPITAL LETTER EL WITH MIDDLE HOOK */ \
+	  0x0521, /* CYRILLIC SMALL LETTER EL WITH MIDDLE HOOK */ }, \
+	{ 0x04C5, /* CYRILLIC CAPITAL LETTER EL WITH TAIL */ \
+	  0x04C6, /* CYRILLIC SMALL LETTER EL WITH TAIL */ }, \
+	{ 0x041C, /* CYRILLIC CAPITAL LETTER EM */ \
+	  0x043C, /* CYRILLIC SMALL LETTER EM */ }, \
+	{ 0x04CD, /* CYRILLIC CAPITAL LETTER EM WITH TAIL */ \
+	  0x04CE, /* CYRILLIC SMALL LETTER EM WITH TAIL */ }, \
+	{ 0x041D, /* CYRILLIC CAPITAL LETTER EN */ \
+	  0x043D, /* CYRILLIC SMALL LETTER EN */ }, \
+	{ 0x04A2, /* CYRILLIC CAPITAL LETTER EN WITH DESCENDER */ \
+	  0x04A3, /* CYRILLIC SMALL LETTER EN WITH DESCENDER */ }, \
+	{ 0x04C7, /* CYRILLIC CAPITAL LETTER EN WITH HOOK */ \
+	  0x04C8, /* CYRILLIC SMALL LETTER EN WITH HOOK */ }, \
+	{ 0x0528, /* CYRILLIC CAPITAL LETTER EN WITH LEFT HOOK */ \
+	  0x0529, /* CYRILLIC SMALL LETTER EN WITH LEFT HOOK */ }, \
+	{ 0x0522, /* CYRILLIC CAPITAL LETTER EN WITH MIDDLE HOOK */ \
+	  0x0523, /* CYRILLIC SMALL LETTER EN WITH MIDDLE HOOK */ }, \
+	{ 0x04C9, /* CYRILLIC CAPITAL LETTER EN WITH TAIL */ \
+	  0x04CA, /* CYRILLIC SMALL LETTER EN WITH TAIL */ }, \
+	{ 0x0420, /* CYRILLIC CAPITAL LETTER ER */ \
+	  0x0440, /* CYRILLIC SMALL LETTER ER */ }, \
+	{ 0x048E, /* CYRILLIC CAPITAL LETTER ER WITH TICK */ \
+	  0x048F, /* CYRILLIC SMALL LETTER ER WITH TICK */ }, \
+	{ 0x0421, /* CYRILLIC CAPITAL LETTER ES */ \
+	  0x0441, /* CYRILLIC SMALL LETTER ES */ }, \
+	{ 0x04AA, /* CYRILLIC CAPITAL LETTER ES WITH DESCENDER */ \
+	  0x04AB, /* CYRILLIC SMALL LETTER ES WITH DESCENDER */ }, \
+	{ 0x0472, /* CYRILLIC CAPITAL LETTER FITA */ \
+	  0x0473, /* CYRILLIC SMALL LETTER FITA */ }, \
+	{ 0x0413, /* CYRILLIC CAPITAL LETTER GHE */ \
+	  0x0433, /* CYRILLIC SMALL LETTER GHE */ }, \
+	{ 0x04F6, /* CYRILLIC CAPITAL LETTER GHE WITH DESCENDER */ \
+	  0x04F7, /* CYRILLIC SMALL LETTER GHE WITH DESCENDER */ }, \
+	{ 0x0494, /* CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK */ \
+	  0x0495, /* CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK */ }, \
+	{ 0x0492, /* CYRILLIC CAPITAL LETTER GHE WITH STROKE */ \
+	  0x0493, /* CYRILLIC SMALL LETTER GHE WITH STROKE */ }, \
+	{ 0x04FA, /* CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK */ \
+	  0x04FB, /* CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK */ }, \
+	{ 0x0490, /* CYRILLIC CAPITAL LETTER GHE WITH UPTURN */ \
+	  0x0491, /* CYRILLIC SMALL LETTER GHE WITH UPTURN */ }, \
+	{ 0x0403, /* CYRILLIC CAPITAL LETTER GJE */ \
+	  0x0453, /* CYRILLIC SMALL LETTER GJE */ }, \
+	{ 0x0425, /* CYRILLIC CAPITAL LETTER HA */ \
+	  0x0445, /* CYRILLIC SMALL LETTER HA */ }, \
+	{ 0x04B2, /* CYRILLIC CAPITAL LETTER HA WITH DESCENDER */ \
+	  0x04B3, /* CYRILLIC SMALL LETTER HA WITH DESCENDER */ }, \
+	{ 0x04FC, /* CYRILLIC CAPITAL LETTER HA WITH HOOK */ \
+	  0x04FD, /* CYRILLIC SMALL LETTER HA WITH HOOK */ }, \
+	{ 0x04FE, /* CYRILLIC CAPITAL LETTER HA WITH STROKE */ \
+	  0x04FF, /* CYRILLIC SMALL LETTER HA WITH STROKE */ }, \
+	{ 0x042A, /* CYRILLIC CAPITAL LETTER HARD SIGN */ \
+	  0x044A, /* CYRILLIC SMALL LETTER HARD SIGN */ }, \
+	{ 0xA694, /* CYRILLIC CAPITAL LETTER HWE */ \
+	  0xA695, /* CYRILLIC SMALL LETTER HWE */ }, \
+	{ 0x0418, /* CYRILLIC CAPITAL LETTER I */ \
+	  0x0438, /* CYRILLIC SMALL LETTER I */ }, \
+	{ 0x04E4, /* CYRILLIC CAPITAL LETTER I WITH DIAERESIS */ \
+	  0x04E5, /* CYRILLIC SMALL LETTER I WITH DIAERESIS */ }, \
+	{ 0x040D, /* CYRILLIC CAPITAL LETTER I WITH GRAVE */ \
+	  0x045D, /* CYRILLIC SMALL LETTER I WITH GRAVE */ }, \
+	{ 0x04E2, /* CYRILLIC CAPITAL LETTER I WITH MACRON */ \
+	  0x04E3, /* CYRILLIC SMALL LETTER I WITH MACRON */ }, \
+	{ 0x0415, /* CYRILLIC CAPITAL LETTER IE */ \
+	  0x0435, /* CYRILLIC SMALL LETTER IE */ }, \
+	{ 0x04D6, /* CYRILLIC CAPITAL LETTER IE WITH BREVE */ \
+	  0x04D7, /* CYRILLIC SMALL LETTER IE WITH BREVE */ }, \
+	{ 0x0400, /* CYRILLIC CAPITAL LETTER IE WITH GRAVE */ \
+	  0x0450, /* CYRILLIC SMALL LETTER IE WITH GRAVE */ }, \
+	{ 0x0401, /* CYRILLIC CAPITAL LETTER IO */ \
+	  0x0451, /* CYRILLIC SMALL LETTER IO */ }, \
+	{ 0xA646, /* CYRILLIC CAPITAL LETTER IOTA */ \
+	  0xA647, /* CYRILLIC SMALL LETTER IOTA */ }, \
+	{ 0xA656, /* CYRILLIC CAPITAL LETTER IOTIFIED A */ \
+	  0xA657, /* CYRILLIC SMALL LETTER IOTIFIED A */ }, \
+	{ 0x046C, /* CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS */ \
+	  0x046D, /* CYRILLIC SMALL LETTER IOTIFIED BIG YUS */ }, \
+	{ 0xA65C, /* CYRILLIC CAPITAL LETTER IOTIFIED CLOSED LITTLE YUS */ \
+	  0xA65D, /* CYRILLIC SMALL LETTER IOTIFIED CLOSED LITTLE YUS */ }, \
+	{ 0x0464, /* CYRILLIC CAPITAL LETTER IOTIFIED E */ \
+	  0x0465, /* CYRILLIC SMALL LETTER IOTIFIED E */ }, \
+	{ 0x0468, /* CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS */ \
+	  0x0469, /* CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS */ }, \
+	{ 0xA652, /* CYRILLIC CAPITAL LETTER IOTIFIED YAT */ \
+	  0xA653, /* CYRILLIC SMALL LETTER IOTIFIED YAT */ }, \
+	{ 0x0474, /* CYRILLIC CAPITAL LETTER IZHITSA */ \
+	  0x0475, /* CYRILLIC SMALL LETTER IZHITSA */ }, \
+	{ 0x0476, /* CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */ \
+	  0x0477, /* CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT */ }, \
+	{ 0x0408, /* CYRILLIC CAPITAL LETTER JE */ \
+	  0x0458, /* CYRILLIC SMALL LETTER JE */ }, \
+	{ 0x041A, /* CYRILLIC CAPITAL LETTER KA */ \
+	  0x043A, /* CYRILLIC SMALL LETTER KA */ }, \
+	{ 0x049A, /* CYRILLIC CAPITAL LETTER KA WITH DESCENDER */ \
+	  0x049B, /* CYRILLIC SMALL LETTER KA WITH DESCENDER */ }, \
+	{ 0x04C3, /* CYRILLIC CAPITAL LETTER KA WITH HOOK */ \
+	  0x04C4, /* CYRILLIC SMALL LETTER KA WITH HOOK */ }, \
+	{ 0x049E, /* CYRILLIC CAPITAL LETTER KA WITH STROKE */ \
+	  0x049F, /* CYRILLIC SMALL LETTER KA WITH STROKE */ }, \
+	{ 0x049C, /* CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE */ \
+	  0x049D, /* CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE */ }, \
+	{ 0x04CB, /* CYRILLIC CAPITAL LETTER KHAKASSIAN CHE */ \
+	  0x04CC, /* CYRILLIC SMALL LETTER KHAKASSIAN CHE */ }, \
+	{ 0x040C, /* CYRILLIC CAPITAL LETTER KJE */ \
+	  0x045C, /* CYRILLIC SMALL LETTER KJE */ }, \
+	{ 0x0500, /* CYRILLIC CAPITAL LETTER KOMI DE */ \
+	  0x0501, /* CYRILLIC SMALL LETTER KOMI DE */ }, \
+	{ 0x0502, /* CYRILLIC CAPITAL LETTER KOMI DJE */ \
+	  0x0503, /* CYRILLIC SMALL LETTER KOMI DJE */ }, \
+	{ 0x0506, /* CYRILLIC CAPITAL LETTER KOMI DZJE */ \
+	  0x0507, /* CYRILLIC SMALL LETTER KOMI DZJE */ }, \
+	{ 0x0508, /* CYRILLIC CAPITAL LETTER KOMI LJE */ \
+	  0x0509, /* CYRILLIC SMALL LETTER KOMI LJE */ }, \
+	{ 0x050A, /* CYRILLIC CAPITAL LETTER KOMI NJE */ \
+	  0x050B, /* CYRILLIC SMALL LETTER KOMI NJE */ }, \
+	{ 0x050C, /* CYRILLIC CAPITAL LETTER KOMI SJE */ \
+	  0x050D, /* CYRILLIC SMALL LETTER KOMI SJE */ }, \
+	{ 0x050E, /* CYRILLIC CAPITAL LETTER KOMI TJE */ \
+	  0x050F, /* CYRILLIC SMALL LETTER KOMI TJE */ }, \
+	{ 0x0504, /* CYRILLIC CAPITAL LETTER KOMI ZJE */ \
+	  0x0505, /* CYRILLIC SMALL LETTER KOMI ZJE */ }, \
+	{ 0x0480, /* CYRILLIC CAPITAL LETTER KOPPA */ \
+	  0x0481, /* CYRILLIC SMALL LETTER KOPPA */ }, \
+	{ 0x046E, /* CYRILLIC CAPITAL LETTER KSI */ \
+	  0x046F, /* CYRILLIC SMALL LETTER KSI */ }, \
+	{ 0x0514, /* CYRILLIC CAPITAL LETTER LHA */ \
+	  0x0515, /* CYRILLIC SMALL LETTER LHA */ }, \
+	{ 0x0466, /* CYRILLIC CAPITAL LETTER LITTLE YUS */ \
+	  0x0467, /* CYRILLIC SMALL LETTER LITTLE YUS */ }, \
+	{ 0x0409, /* CYRILLIC CAPITAL LETTER LJE */ \
+	  0x0459, /* CYRILLIC SMALL LETTER LJE */ }, \
+	{ 0xA668, /* CYRILLIC CAPITAL LETTER MONOCULAR O */ \
+	  0xA669, /* CYRILLIC SMALL LETTER MONOCULAR O */ }, \
+	{ 0xA64A, /* CYRILLIC CAPITAL LETTER MONOGRAPH UK */ \
+	  0xA64B, /* CYRILLIC SMALL LETTER MONOGRAPH UK */ }, \
+	{ 0xA64E, /* CYRILLIC CAPITAL LETTER NEUTRAL YER */ \
+	  0xA64F, /* CYRILLIC SMALL LETTER NEUTRAL YER */ }, \
+	{ 0x040A, /* CYRILLIC CAPITAL LETTER NJE */ \
+	  0x045A, /* CYRILLIC SMALL LETTER NJE */ }, \
+	{ 0x041E, /* CYRILLIC CAPITAL LETTER O */ \
+	  0x043E, /* CYRILLIC SMALL LETTER O */ }, \
+	{ 0x04E6, /* CYRILLIC CAPITAL LETTER O WITH DIAERESIS */ \
+	  0x04E7, /* CYRILLIC SMALL LETTER O WITH DIAERESIS */ }, \
+	{ 0x0460, /* CYRILLIC CAPITAL LETTER OMEGA */ \
+	  0x0461, /* CYRILLIC SMALL LETTER OMEGA */ }, \
+	{ 0x047C, /* CYRILLIC CAPITAL LETTER OMEGA WITH TITLO */ \
+	  0x047D, /* CYRILLIC SMALL LETTER OMEGA WITH TITLO */ }, \
+	{ 0x047E, /* CYRILLIC CAPITAL LETTER OT */ \
+	  0x047F, /* CYRILLIC SMALL LETTER OT */ }, \
+	{ 0x041F, /* CYRILLIC CAPITAL LETTER PE */ \
+	  0x043F, /* CYRILLIC SMALL LETTER PE */ }, \
+	{ 0x0524, /* CYRILLIC CAPITAL LETTER PE WITH DESCENDER */ \
+	  0x0525, /* CYRILLIC SMALL LETTER PE WITH DESCENDER */ }, \
+	{ 0x04A6, /* CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK */ \
+	  0x04A7, /* CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK */ }, \
+	{ 0x0470, /* CYRILLIC CAPITAL LETTER PSI */ \
+	  0x0471, /* CYRILLIC SMALL LETTER PSI */ }, \
+	{ 0x051A, /* CYRILLIC CAPITAL LETTER QA */ \
+	  0x051B, /* CYRILLIC SMALL LETTER QA */ }, \
+	{ 0xA644, /* CYRILLIC CAPITAL LETTER REVERSED DZE */ \
+	  0xA645, /* CYRILLIC SMALL LETTER REVERSED DZE */ }, \
+	{ 0xA660, /* CYRILLIC CAPITAL LETTER REVERSED TSE */ \
+	  0xA661, /* CYRILLIC SMALL LETTER REVERSED TSE */ }, \
+	{ 0xA654, /* CYRILLIC CAPITAL LETTER REVERSED YU */ \
+	  0xA655, /* CYRILLIC SMALL LETTER REVERSED YU */ }, \
+	{ 0x0510, /* CYRILLIC CAPITAL LETTER REVERSED ZE */ \
+	  0x0511, /* CYRILLIC SMALL LETTER REVERSED ZE */ }, \
+	{ 0x0516, /* CYRILLIC CAPITAL LETTER RHA */ \
+	  0x0517, /* CYRILLIC SMALL LETTER RHA */ }, \
+	{ 0x047A, /* CYRILLIC CAPITAL LETTER ROUND OMEGA */ \
+	  0x047B, /* CYRILLIC SMALL LETTER ROUND OMEGA */ }, \
+	{ 0x04D8, /* CYRILLIC CAPITAL LETTER SCHWA */ \
+	  0x04D9, /* CYRILLIC SMALL LETTER SCHWA */ }, \
+	{ 0x04DA, /* CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS */ \
+	  0x04DB, /* CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS */ }, \
+	{ 0x048C, /* CYRILLIC CAPITAL LETTER SEMISOFT SIGN */ \
+	  0x048D, /* CYRILLIC SMALL LETTER SEMISOFT SIGN */ }, \
+	{ 0x0428, /* CYRILLIC CAPITAL LETTER SHA */ \
+	  0x0448, /* CYRILLIC SMALL LETTER SHA */ }, \
+	{ 0x0429, /* CYRILLIC CAPITAL LETTER SHCHA */ \
+	  0x0449, /* CYRILLIC SMALL LETTER SHCHA */ }, \
+	{ 0x04BA, /* CYRILLIC CAPITAL LETTER SHHA */ \
+	  0x04BB, /* CYRILLIC SMALL LETTER SHHA */ }, \
+	{ 0x0526, /* CYRILLIC CAPITAL LETTER SHHA WITH DESCENDER */ \
+	  0x0527, /* CYRILLIC SMALL LETTER SHHA WITH DESCENDER */ }, \
+	{ 0x048A, /* CYRILLIC CAPITAL LETTER SHORT I WITH TAIL */ \
+	  0x048B, /* CYRILLIC SMALL LETTER SHORT I WITH TAIL */ }, \
+	{ 0x040E, /* CYRILLIC CAPITAL LETTER SHORT U */ \
+	  0x045E, /* CYRILLIC SMALL LETTER SHORT U */ }, \
+	{ 0xA696, /* CYRILLIC CAPITAL LETTER SHWE */ \
+	  0xA697, /* CYRILLIC SMALL LETTER SHWE */ }, \
+	{ 0xA662, /* CYRILLIC CAPITAL LETTER SOFT DE */ \
+	  0xA663, /* CYRILLIC SMALL LETTER SOFT DE */ }, \
+	{ 0xA664, /* CYRILLIC CAPITAL LETTER SOFT EL */ \
+	  0xA665, /* CYRILLIC SMALL LETTER SOFT EL */ }, \
+	{ 0xA666, /* CYRILLIC CAPITAL LETTER SOFT EM */ \
+	  0xA667, /* CYRILLIC SMALL LETTER SOFT EM */ }, \
+	{ 0x042C, /* CYRILLIC CAPITAL LETTER SOFT SIGN */ \
+	  0x044C, /* CYRILLIC SMALL LETTER SOFT SIGN */ }, \
+	{ 0x04AE, /* CYRILLIC CAPITAL LETTER STRAIGHT U */ \
+	  0x04AF, /* CYRILLIC SMALL LETTER STRAIGHT U */ }, \
+	{ 0x04B0, /* CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE */ \
+	  0x04B1, /* CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE */ }, \
+	{ 0xA692, /* CYRILLIC CAPITAL LETTER TCHE */ \
+	  0xA693, /* CYRILLIC SMALL LETTER TCHE */ }, \
+	{ 0x0422, /* CYRILLIC CAPITAL LETTER TE */ \
+	  0x0442, /* CYRILLIC SMALL LETTER TE */ }, \
+	{ 0x04AC, /* CYRILLIC CAPITAL LETTER TE WITH DESCENDER */ \
+	  0x04AD, /* CYRILLIC SMALL LETTER TE WITH DESCENDER */ }, \
+	{ 0xA68A, /* CYRILLIC CAPITAL LETTER TE WITH MIDDLE HOOK */ \
+	  0xA68B, /* CYRILLIC SMALL LETTER TE WITH MIDDLE HOOK */ }, \
+	{ 0x0426, /* CYRILLIC CAPITAL LETTER TSE */ \
+	  0x0446, /* CYRILLIC SMALL LETTER TSE */ }, \
+	{ 0x040B, /* CYRILLIC CAPITAL LETTER TSHE */ \
+	  0x045B, /* CYRILLIC SMALL LETTER TSHE */ }, \
+	{ 0xA690, /* CYRILLIC CAPITAL LETTER TSSE */ \
+	  0xA691, /* CYRILLIC SMALL LETTER TSSE */ }, \
+	{ 0xA68E, /* CYRILLIC CAPITAL LETTER TSWE */ \
+	  0xA68F, /* CYRILLIC SMALL LETTER TSWE */ }, \
+	{ 0xA68C, /* CYRILLIC CAPITAL LETTER TWE */ \
+	  0xA68D, /* CYRILLIC SMALL LETTER TWE */ }, \
+	{ 0x0423, /* CYRILLIC CAPITAL LETTER U */ \
+	  0x0443, /* CYRILLIC SMALL LETTER U */ }, \
+	{ 0x04F0, /* CYRILLIC CAPITAL LETTER U WITH DIAERESIS */ \
+	  0x04F1, /* CYRILLIC SMALL LETTER U WITH DIAERESIS */ }, \
+	{ 0x04F2, /* CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE */ \
+	  0x04F3, /* CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE */ }, \
+	{ 0x04EE, /* CYRILLIC CAPITAL LETTER U WITH MACRON */ \
+	  0x04EF, /* CYRILLIC SMALL LETTER U WITH MACRON */ }, \
+	{ 0x0478, /* CYRILLIC CAPITAL LETTER UK */ \
+	  0x0479, /* CYRILLIC SMALL LETTER UK */ }, \
+	{ 0x0404, /* CYRILLIC CAPITAL LETTER UKRAINIAN IE */ \
+	  0x0454, /* CYRILLIC SMALL LETTER UKRAINIAN IE */ }, \
+	{ 0x0412, /* CYRILLIC CAPITAL LETTER VE */ \
+	  0x0432, /* CYRILLIC SMALL LETTER VE */ }, \
+	{ 0x051C, /* CYRILLIC CAPITAL LETTER WE */ \
+	  0x051D, /* CYRILLIC SMALL LETTER WE */ }, \
+	{ 0x042F, /* CYRILLIC CAPITAL LETTER YA */ \
+	  0x044F, /* CYRILLIC SMALL LETTER YA */ }, \
+	{ 0x0518, /* CYRILLIC CAPITAL LETTER YAE */ \
+	  0x0519, /* CYRILLIC SMALL LETTER YAE */ }, \
+	{ 0x0462, /* CYRILLIC CAPITAL LETTER YAT */ \
+	  0x0463, /* CYRILLIC SMALL LETTER YAT */ }, \
+	{ 0x042B, /* CYRILLIC CAPITAL LETTER YERU */ \
+	  0x044B, /* CYRILLIC SMALL LETTER YERU */ }, \
+	{ 0xA650, /* CYRILLIC CAPITAL LETTER YERU WITH BACK YER */ \
+	  0xA651, /* CYRILLIC SMALL LETTER YERU WITH BACK YER */ }, \
+	{ 0x04F8, /* CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS */ \
+	  0x04F9, /* CYRILLIC SMALL LETTER YERU WITH DIAERESIS */ }, \
+	{ 0x0407, /* CYRILLIC CAPITAL LETTER YI */ \
+	  0x0457, /* CYRILLIC SMALL LETTER YI */ }, \
+	{ 0xA65E, /* CYRILLIC CAPITAL LETTER YN */ \
+	  0xA65F, /* CYRILLIC SMALL LETTER YN */ }, \
+	{ 0x042E, /* CYRILLIC CAPITAL LETTER YU */ \
+	  0x044E, /* CYRILLIC SMALL LETTER YU */ }, \
+	{ 0x0417, /* CYRILLIC CAPITAL LETTER ZE */ \
+	  0x0437, /* CYRILLIC SMALL LETTER ZE */ }, \
+	{ 0x0498, /* CYRILLIC CAPITAL LETTER ZE WITH DESCENDER */ \
+	  0x0499, /* CYRILLIC SMALL LETTER ZE WITH DESCENDER */ }, \
+	{ 0x04DE, /* CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS */ \
+	  0x04DF, /* CYRILLIC SMALL LETTER ZE WITH DIAERESIS */ }, \
+	{ 0xA640, /* CYRILLIC CAPITAL LETTER ZEMLYA */ \
+	  0xA641, /* CYRILLIC SMALL LETTER ZEMLYA */ }, \
+	{ 0x0416, /* CYRILLIC CAPITAL LETTER ZHE */ \
+	  0x0436, /* CYRILLIC SMALL LETTER ZHE */ }, \
+	{ 0x04C1, /* CYRILLIC CAPITAL LETTER ZHE WITH BREVE */ \
+	  0x04C2, /* CYRILLIC SMALL LETTER ZHE WITH BREVE */ }, \
+	{ 0x0496, /* CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER */ \
+	  0x0497, /* CYRILLIC SMALL LETTER ZHE WITH DESCENDER */ }, \
+	{ 0x04DC, /* CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS */ \
+	  0x04DD, /* CYRILLIC SMALL LETTER ZHE WITH DIAERESIS */ }, \
+	{ 0xA684, /* CYRILLIC CAPITAL LETTER ZHWE */ \
+	  0xA685, /* CYRILLIC SMALL LETTER ZHWE */ }, \
+	{ 0xFF21, /* FULLWIDTH LATIN CAPITAL LETTER A */ \
+	  0xFF41, /* FULLWIDTH LATIN SMALL LETTER A */ }, \
+	{ 0xFF22, /* FULLWIDTH LATIN CAPITAL LETTER B */ \
+	  0xFF42, /* FULLWIDTH LATIN SMALL LETTER B */ }, \
+	{ 0xFF23, /* FULLWIDTH LATIN CAPITAL LETTER C */ \
+	  0xFF43, /* FULLWIDTH LATIN SMALL LETTER C */ }, \
+	{ 0xFF24, /* FULLWIDTH LATIN CAPITAL LETTER D */ \
+	  0xFF44, /* FULLWIDTH LATIN SMALL LETTER D */ }, \
+	{ 0xFF25, /* FULLWIDTH LATIN CAPITAL LETTER E */ \
+	  0xFF45, /* FULLWIDTH LATIN SMALL LETTER E */ }, \
+	{ 0xFF26, /* FULLWIDTH LATIN CAPITAL LETTER F */ \
+	  0xFF46, /* FULLWIDTH LATIN SMALL LETTER F */ }, \
+	{ 0xFF27, /* FULLWIDTH LATIN CAPITAL LETTER G */ \
+	  0xFF47, /* FULLWIDTH LATIN SMALL LETTER G */ }, \
+	{ 0xFF28, /* FULLWIDTH LATIN CAPITAL LETTER H */ \
+	  0xFF48, /* FULLWIDTH LATIN SMALL LETTER H */ }, \
+	{ 0xFF29, /* FULLWIDTH LATIN CAPITAL LETTER I */ \
+	  0xFF49, /* FULLWIDTH LATIN SMALL LETTER I */ }, \
+	{ 0xFF2A, /* FULLWIDTH LATIN CAPITAL LETTER J */ \
+	  0xFF4A, /* FULLWIDTH LATIN SMALL LETTER J */ }, \
+	{ 0xFF2B, /* FULLWIDTH LATIN CAPITAL LETTER K */ \
+	  0xFF4B, /* FULLWIDTH LATIN SMALL LETTER K */ }, \
+	{ 0xFF2C, /* FULLWIDTH LATIN CAPITAL LETTER L */ \
+	  0xFF4C, /* FULLWIDTH LATIN SMALL LETTER L */ }, \
+	{ 0xFF2D, /* FULLWIDTH LATIN CAPITAL LETTER M */ \
+	  0xFF4D, /* FULLWIDTH LATIN SMALL LETTER M */ }, \
+	{ 0xFF2E, /* FULLWIDTH LATIN CAPITAL LETTER N */ \
+	  0xFF4E, /* FULLWIDTH LATIN SMALL LETTER N */ }, \
+	{ 0xFF2F, /* FULLWIDTH LATIN CAPITAL LETTER O */ \
+	  0xFF4F, /* FULLWIDTH LATIN SMALL LETTER O */ }, \
+	{ 0xFF30, /* FULLWIDTH LATIN CAPITAL LETTER P */ \
+	  0xFF50, /* FULLWIDTH LATIN SMALL LETTER P */ }, \
+	{ 0xFF31, /* FULLWIDTH LATIN CAPITAL LETTER Q */ \
+	  0xFF51, /* FULLWIDTH LATIN SMALL LETTER Q */ }, \
+	{ 0xFF32, /* FULLWIDTH LATIN CAPITAL LETTER R */ \
+	  0xFF52, /* FULLWIDTH LATIN SMALL LETTER R */ }, \
+	{ 0xFF33, /* FULLWIDTH LATIN CAPITAL LETTER S */ \
+	  0xFF53, /* FULLWIDTH LATIN SMALL LETTER S */ }, \
+	{ 0xFF34, /* FULLWIDTH LATIN CAPITAL LETTER T */ \
+	  0xFF54, /* FULLWIDTH LATIN SMALL LETTER T */ }, \
+	{ 0xFF35, /* FULLWIDTH LATIN CAPITAL LETTER U */ \
+	  0xFF55, /* FULLWIDTH LATIN SMALL LETTER U */ }, \
+	{ 0xFF36, /* FULLWIDTH LATIN CAPITAL LETTER V */ \
+	  0xFF56, /* FULLWIDTH LATIN SMALL LETTER V */ }, \
+	{ 0xFF37, /* FULLWIDTH LATIN CAPITAL LETTER W */ \
+	  0xFF57, /* FULLWIDTH LATIN SMALL LETTER W */ }, \
+	{ 0xFF38, /* FULLWIDTH LATIN CAPITAL LETTER X */ \
+	  0xFF58, /* FULLWIDTH LATIN SMALL LETTER X */ }, \
+	{ 0xFF39, /* FULLWIDTH LATIN CAPITAL LETTER Y */ \
+	  0xFF59, /* FULLWIDTH LATIN SMALL LETTER Y */ }, \
+	{ 0xFF3A, /* FULLWIDTH LATIN CAPITAL LETTER Z */ \
+	  0xFF5A, /* FULLWIDTH LATIN SMALL LETTER Z */ }, \
+	{ 0x10CD, /* GEORGIAN CAPITAL LETTER AEN */ \
+	  0x2D2D, /* GEORGIAN SMALL LETTER AEN */ }, \
+	{ 0x10A0, /* GEORGIAN CAPITAL LETTER AN */ \
+	  0x2D00, /* GEORGIAN SMALL LETTER AN */ }, \
+	{ 0x10A1, /* GEORGIAN CAPITAL LETTER BAN */ \
+	  0x2D01, /* GEORGIAN SMALL LETTER BAN */ }, \
+	{ 0x10BA, /* GEORGIAN CAPITAL LETTER CAN */ \
+	  0x2D1A, /* GEORGIAN SMALL LETTER CAN */ }, \
+	{ 0x10BD, /* GEORGIAN CAPITAL LETTER CHAR */ \
+	  0x2D1D, /* GEORGIAN SMALL LETTER CHAR */ }, \
+	{ 0x10B9, /* GEORGIAN CAPITAL LETTER CHIN */ \
+	  0x2D19, /* GEORGIAN SMALL LETTER CHIN */ }, \
+	{ 0x10BC, /* GEORGIAN CAPITAL LETTER CIL */ \
+	  0x2D1C, /* GEORGIAN SMALL LETTER CIL */ }, \
+	{ 0x10A3, /* GEORGIAN CAPITAL LETTER DON */ \
+	  0x2D03, /* GEORGIAN SMALL LETTER DON */ }, \
+	{ 0x10A4, /* GEORGIAN CAPITAL LETTER EN */ \
+	  0x2D04, /* GEORGIAN SMALL LETTER EN */ }, \
+	{ 0x10A2, /* GEORGIAN CAPITAL LETTER GAN */ \
+	  0x2D02, /* GEORGIAN SMALL LETTER GAN */ }, \
+	{ 0x10B6, /* GEORGIAN CAPITAL LETTER GHAN */ \
+	  0x2D16, /* GEORGIAN SMALL LETTER GHAN */ }, \
+	{ 0x10C0, /* GEORGIAN CAPITAL LETTER HAE */ \
+	  0x2D20, /* GEORGIAN SMALL LETTER HAE */ }, \
+	{ 0x10C4, /* GEORGIAN CAPITAL LETTER HAR */ \
+	  0x2D24, /* GEORGIAN SMALL LETTER HAR */ }, \
+	{ 0x10C1, /* GEORGIAN CAPITAL LETTER HE */ \
+	  0x2D21, /* GEORGIAN SMALL LETTER HE */ }, \
+	{ 0x10C2, /* GEORGIAN CAPITAL LETTER HIE */ \
+	  0x2D22, /* GEORGIAN SMALL LETTER HIE */ }, \
+	{ 0x10C5, /* GEORGIAN CAPITAL LETTER HOE */ \
+	  0x2D25, /* GEORGIAN SMALL LETTER HOE */ }, \
+	{ 0x10A8, /* GEORGIAN CAPITAL LETTER IN */ \
+	  0x2D08, /* GEORGIAN SMALL LETTER IN */ }, \
+	{ 0x10BF, /* GEORGIAN CAPITAL LETTER JHAN */ \
+	  0x2D1F, /* GEORGIAN SMALL LETTER JHAN */ }, \
+	{ 0x10BB, /* GEORGIAN CAPITAL LETTER JIL */ \
+	  0x2D1B, /* GEORGIAN SMALL LETTER JIL */ }, \
+	{ 0x10A9, /* GEORGIAN CAPITAL LETTER KAN */ \
+	  0x2D09, /* GEORGIAN SMALL LETTER KAN */ }, \
+	{ 0x10B5, /* GEORGIAN CAPITAL LETTER KHAR */ \
+	  0x2D15, /* GEORGIAN SMALL LETTER KHAR */ }, \
+	{ 0x10AA, /* GEORGIAN CAPITAL LETTER LAS */ \
+	  0x2D0A, /* GEORGIAN SMALL LETTER LAS */ }, \
+	{ 0x10AB, /* GEORGIAN CAPITAL LETTER MAN */ \
+	  0x2D0B, /* GEORGIAN SMALL LETTER MAN */ }, \
+	{ 0x10AC, /* GEORGIAN CAPITAL LETTER NAR */ \
+	  0x2D0C, /* GEORGIAN SMALL LETTER NAR */ }, \
+	{ 0x10AD, /* GEORGIAN CAPITAL LETTER ON */ \
+	  0x2D0D, /* GEORGIAN SMALL LETTER ON */ }, \
+	{ 0x10AE, /* GEORGIAN CAPITAL LETTER PAR */ \
+	  0x2D0E, /* GEORGIAN SMALL LETTER PAR */ }, \
+	{ 0x10B4, /* GEORGIAN CAPITAL LETTER PHAR */ \
+	  0x2D14, /* GEORGIAN SMALL LETTER PHAR */ }, \
+	{ 0x10B7, /* GEORGIAN CAPITAL LETTER QAR */ \
+	  0x2D17, /* GEORGIAN SMALL LETTER QAR */ }, \
+	{ 0x10B0, /* GEORGIAN CAPITAL LETTER RAE */ \
+	  0x2D10, /* GEORGIAN SMALL LETTER RAE */ }, \
+	{ 0x10B1, /* GEORGIAN CAPITAL LETTER SAN */ \
+	  0x2D11, /* GEORGIAN SMALL LETTER SAN */ }, \
+	{ 0x10B8, /* GEORGIAN CAPITAL LETTER SHIN */ \
+	  0x2D18, /* GEORGIAN SMALL LETTER SHIN */ }, \
+	{ 0x10A7, /* GEORGIAN CAPITAL LETTER TAN */ \
+	  0x2D07, /* GEORGIAN SMALL LETTER TAN */ }, \
+	{ 0x10B2, /* GEORGIAN CAPITAL LETTER TAR */ \
+	  0x2D12, /* GEORGIAN SMALL LETTER TAR */ }, \
+	{ 0x10B3, /* GEORGIAN CAPITAL LETTER UN */ \
+	  0x2D13, /* GEORGIAN SMALL LETTER UN */ }, \
+	{ 0x10A5, /* GEORGIAN CAPITAL LETTER VIN */ \
+	  0x2D05, /* GEORGIAN SMALL LETTER VIN */ }, \
+	{ 0x10C3, /* GEORGIAN CAPITAL LETTER WE */ \
+	  0x2D23, /* GEORGIAN SMALL LETTER WE */ }, \
+	{ 0x10BE, /* GEORGIAN CAPITAL LETTER XAN */ \
+	  0x2D1E, /* GEORGIAN SMALL LETTER XAN */ }, \
+	{ 0x10C7, /* GEORGIAN CAPITAL LETTER YN */ \
+	  0x2D27, /* GEORGIAN SMALL LETTER YN */ }, \
+	{ 0x10A6, /* GEORGIAN CAPITAL LETTER ZEN */ \
+	  0x2D06, /* GEORGIAN SMALL LETTER ZEN */ }, \
+	{ 0x10AF, /* GEORGIAN CAPITAL LETTER ZHAR */ \
+	  0x2D0F, /* GEORGIAN SMALL LETTER ZHAR */ }, \
+	{ 0x2C00, /* GLAGOLITIC CAPITAL LETTER AZU */ \
+	  0x2C30, /* GLAGOLITIC SMALL LETTER AZU */ }, \
+	{ 0x2C28, /* GLAGOLITIC CAPITAL LETTER BIG YUS */ \
+	  0x2C58, /* GLAGOLITIC SMALL LETTER BIG YUS */ }, \
+	{ 0x2C01, /* GLAGOLITIC CAPITAL LETTER BUKY */ \
+	  0x2C31, /* GLAGOLITIC SMALL LETTER BUKY */ }, \
+	{ 0x2C1D, /* GLAGOLITIC CAPITAL LETTER CHRIVI */ \
+	  0x2C4D, /* GLAGOLITIC SMALL LETTER CHRIVI */ }, \
+	{ 0x2C0C, /* GLAGOLITIC CAPITAL LETTER DJERVI */ \
+	  0x2C3C, /* GLAGOLITIC SMALL LETTER DJERVI */ }, \
+	{ 0x2C04, /* GLAGOLITIC CAPITAL LETTER DOBRO */ \
+	  0x2C34, /* GLAGOLITIC SMALL LETTER DOBRO */ }, \
+	{ 0x2C07, /* GLAGOLITIC CAPITAL LETTER DZELO */ \
+	  0x2C37, /* GLAGOLITIC SMALL LETTER DZELO */ }, \
+	{ 0x2C2A, /* GLAGOLITIC CAPITAL LETTER FITA */ \
+	  0x2C5A, /* GLAGOLITIC SMALL LETTER FITA */ }, \
+	{ 0x2C17, /* GLAGOLITIC CAPITAL LETTER FRITU */ \
+	  0x2C47, /* GLAGOLITIC SMALL LETTER FRITU */ }, \
+	{ 0x2C03, /* GLAGOLITIC CAPITAL LETTER GLAGOLI */ \
+	  0x2C33, /* GLAGOLITIC SMALL LETTER GLAGOLI */ }, \
+	{ 0x2C18, /* GLAGOLITIC CAPITAL LETTER HERU */ \
+	  0x2C48, /* GLAGOLITIC SMALL LETTER HERU */ }, \
+	{ 0x2C0B, /* GLAGOLITIC CAPITAL LETTER I */ \
+	  0x2C3B, /* GLAGOLITIC SMALL LETTER I */ }, \
+	{ 0x2C0A, /* GLAGOLITIC CAPITAL LETTER INITIAL IZHE */ \
+	  0x2C3A, /* GLAGOLITIC SMALL LETTER INITIAL IZHE */ }, \
+	{ 0x2C29, /* GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS */ \
+	  0x2C59, /* GLAGOLITIC SMALL LETTER IOTATED BIG YUS */ }, \
+	{ 0x2C27, /* GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS */ \
+	  0x2C57, /* GLAGOLITIC SMALL LETTER IOTATED SMALL YUS */ }, \
+	{ 0x2C09, /* GLAGOLITIC CAPITAL LETTER IZHE */ \
+	  0x2C39, /* GLAGOLITIC SMALL LETTER IZHE */ }, \
+	{ 0x2C2B, /* GLAGOLITIC CAPITAL LETTER IZHITSA */ \
+	  0x2C5B, /* GLAGOLITIC SMALL LETTER IZHITSA */ }, \
+	{ 0x2C0D, /* GLAGOLITIC CAPITAL LETTER KAKO */ \
+	  0x2C3D, /* GLAGOLITIC SMALL LETTER KAKO */ }, \
+	{ 0x2C2E, /* GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE */ \
+	  0x2C5E, /* GLAGOLITIC SMALL LETTER LATINATE MYSLITE */ }, \
+	{ 0x2C0E, /* GLAGOLITIC CAPITAL LETTER LJUDIJE */ \
+	  0x2C3E, /* GLAGOLITIC SMALL LETTER LJUDIJE */ }, \
+	{ 0x2C0F, /* GLAGOLITIC CAPITAL LETTER MYSLITE */ \
+	  0x2C3F, /* GLAGOLITIC SMALL LETTER MYSLITE */ }, \
+	{ 0x2C10, /* GLAGOLITIC CAPITAL LETTER NASHI */ \
+	  0x2C40, /* GLAGOLITIC SMALL LETTER NASHI */ }, \
+	{ 0x2C11, /* GLAGOLITIC CAPITAL LETTER ONU */ \
+	  0x2C41, /* GLAGOLITIC SMALL LETTER ONU */ }, \
+	{ 0x2C19, /* GLAGOLITIC CAPITAL LETTER OTU */ \
+	  0x2C49, /* GLAGOLITIC SMALL LETTER OTU */ }, \
+	{ 0x2C1A, /* GLAGOLITIC CAPITAL LETTER PE */ \
+	  0x2C4A, /* GLAGOLITIC SMALL LETTER PE */ }, \
+	{ 0x2C12, /* GLAGOLITIC CAPITAL LETTER POKOJI */ \
+	  0x2C42, /* GLAGOLITIC SMALL LETTER POKOJI */ }, \
+	{ 0x2C13, /* GLAGOLITIC CAPITAL LETTER RITSI */ \
+	  0x2C43, /* GLAGOLITIC SMALL LETTER RITSI */ }, \
+	{ 0x2C1E, /* GLAGOLITIC CAPITAL LETTER SHA */ \
+	  0x2C4E, /* GLAGOLITIC SMALL LETTER SHA */ }, \
+	{ 0x2C1B, /* GLAGOLITIC CAPITAL LETTER SHTA */ \
+	  0x2C4B, /* GLAGOLITIC SMALL LETTER SHTA */ }, \
+	{ 0x2C2C, /* GLAGOLITIC CAPITAL LETTER SHTAPIC */ \
+	  0x2C5C, /* GLAGOLITIC SMALL LETTER SHTAPIC */ }, \
+	{ 0x2C14, /* GLAGOLITIC CAPITAL LETTER SLOVO */ \
+	  0x2C44, /* GLAGOLITIC SMALL LETTER SLOVO */ }, \
+	{ 0x2C24, /* GLAGOLITIC CAPITAL LETTER SMALL YUS */ \
+	  0x2C54, /* GLAGOLITIC SMALL LETTER SMALL YUS */ }, \
+	{ 0x2C25, /* GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL */ \
+	  0x2C55, /* GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL */ }, \
+	{ 0x2C22, /* GLAGOLITIC CAPITAL LETTER SPIDERY HA */ \
+	  0x2C52, /* GLAGOLITIC SMALL LETTER SPIDERY HA */ }, \
+	{ 0x2C2D, /* GLAGOLITIC CAPITAL LETTER TROKUTASTI A */ \
+	  0x2C5D, /* GLAGOLITIC SMALL LETTER TROKUTASTI A */ }, \
+	{ 0x2C1C, /* GLAGOLITIC CAPITAL LETTER TSI */ \
+	  0x2C4C, /* GLAGOLITIC SMALL LETTER TSI */ }, \
+	{ 0x2C15, /* GLAGOLITIC CAPITAL LETTER TVRIDO */ \
+	  0x2C45, /* GLAGOLITIC SMALL LETTER TVRIDO */ }, \
+	{ 0x2C16, /* GLAGOLITIC CAPITAL LETTER UKU */ \
+	  0x2C46, /* GLAGOLITIC SMALL LETTER UKU */ }, \
+	{ 0x2C02, /* GLAGOLITIC CAPITAL LETTER VEDE */ \
+	  0x2C32, /* GLAGOLITIC SMALL LETTER VEDE */ }, \
+	{ 0x2C21, /* GLAGOLITIC CAPITAL LETTER YATI */ \
+	  0x2C51, /* GLAGOLITIC SMALL LETTER YATI */ }, \
+	{ 0x2C20, /* GLAGOLITIC CAPITAL LETTER YERI */ \
+	  0x2C50, /* GLAGOLITIC SMALL LETTER YERI */ }, \
+	{ 0x2C1F, /* GLAGOLITIC CAPITAL LETTER YERU */ \
+	  0x2C4F, /* GLAGOLITIC SMALL LETTER YERU */ }, \
+	{ 0x2C05, /* GLAGOLITIC CAPITAL LETTER YESTU */ \
+	  0x2C35, /* GLAGOLITIC SMALL LETTER YESTU */ }, \
+	{ 0x2C26, /* GLAGOLITIC CAPITAL LETTER YO */ \
+	  0x2C56, /* GLAGOLITIC SMALL LETTER YO */ }, \
+	{ 0x2C23, /* GLAGOLITIC CAPITAL LETTER YU */ \
+	  0x2C53, /* GLAGOLITIC SMALL LETTER YU */ }, \
+	{ 0x2C08, /* GLAGOLITIC CAPITAL LETTER ZEMLJA */ \
+	  0x2C38, /* GLAGOLITIC SMALL LETTER ZEMLJA */ }, \
+	{ 0x2C06, /* GLAGOLITIC CAPITAL LETTER ZHIVETE */ \
+	  0x2C36, /* GLAGOLITIC SMALL LETTER ZHIVETE */ }, \
+	{ 0x0391, /* GREEK CAPITAL LETTER ALPHA */ \
+	  0x03B1, /* GREEK SMALL LETTER ALPHA */ }, \
+	{ 0x1F09, /* GREEK CAPITAL LETTER ALPHA WITH DASIA */ \
+	  0x1F01, /* GREEK SMALL LETTER ALPHA WITH DASIA */ }, \
+	{ 0x1F0D, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA */ \
+	  0x1F05, /* GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA */ }, \
+	{ 0x1F0F, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI */ \
+	  0x1F07, /* GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI */ }, \
+	{ 0x1F0B, /* GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA */ \
+	  0x1F03, /* GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA */ }, \
+	{ 0x1FB9, /* GREEK CAPITAL LETTER ALPHA WITH MACRON */ \
+	  0x1FB1, /* GREEK SMALL LETTER ALPHA WITH MACRON */ }, \
+	{ 0x1FBB, /* GREEK CAPITAL LETTER ALPHA WITH OXIA */ \
+	  0x1F71, /* GREEK SMALL LETTER ALPHA WITH OXIA */ }, \
+	{ 0x1F08, /* GREEK CAPITAL LETTER ALPHA WITH PSILI */ \
+	  0x1F00, /* GREEK SMALL LETTER ALPHA WITH PSILI */ }, \
+	{ 0x1F0C, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA */ \
+	  0x1F04, /* GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA */ }, \
+	{ 0x1F0E, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI */ \
+	  0x1F06, /* GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI */ }, \
+	{ 0x1F0A, /* GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA */ \
+	  0x1F02, /* GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA */ }, \
+	{ 0x0386, /* GREEK CAPITAL LETTER ALPHA WITH TONOS */ \
+	  0x03AC, /* GREEK SMALL LETTER ALPHA WITH TONOS */ }, \
+	{ 0x1FBA, /* GREEK CAPITAL LETTER ALPHA WITH VARIA */ \
+	  0x1F70, /* GREEK SMALL LETTER ALPHA WITH VARIA */ }, \
+	{ 0x1FB8, /* GREEK CAPITAL LETTER ALPHA WITH VRACHY */ \
+	  0x1FB0, /* GREEK SMALL LETTER ALPHA WITH VRACHY */ }, \
+	{ 0x0372, /* GREEK CAPITAL LETTER ARCHAIC SAMPI */ \
+	  0x0373, /* GREEK SMALL LETTER ARCHAIC SAMPI */ }, \
+	{ 0x0392, /* GREEK CAPITAL LETTER BETA */ \
+	  0x03B2, /* GREEK SMALL LETTER BETA */ }, \
+	{ 0x03A7, /* GREEK CAPITAL LETTER CHI */ \
+	  0x03C7, /* GREEK SMALL LETTER CHI */ }, \
+	{ 0x0394, /* GREEK CAPITAL LETTER DELTA */ \
+	  0x03B4, /* GREEK SMALL LETTER DELTA */ }, \
+	{ 0x0395, /* GREEK CAPITAL LETTER EPSILON */ \
+	  0x03B5, /* GREEK SMALL LETTER EPSILON */ }, \
+	{ 0x1F19, /* GREEK CAPITAL LETTER EPSILON WITH DASIA */ \
+	  0x1F11, /* GREEK SMALL LETTER EPSILON WITH DASIA */ }, \
+	{ 0x1F1D, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA */ \
+	  0x1F15, /* GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA */ }, \
+	{ 0x1F1B, /* GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA */ \
+	  0x1F13, /* GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA */ }, \
+	{ 0x1FC9, /* GREEK CAPITAL LETTER EPSILON WITH OXIA */ \
+	  0x1F73, /* GREEK SMALL LETTER EPSILON WITH OXIA */ }, \
+	{ 0x1F18, /* GREEK CAPITAL LETTER EPSILON WITH PSILI */ \
+	  0x1F10, /* GREEK SMALL LETTER EPSILON WITH PSILI */ }, \
+	{ 0x1F1C, /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA */ \
+	  0x1F14, /* GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA */ }, \
+	{ 0x1F1A, /* GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA */ \
+	  0x1F12, /* GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA */ }, \
+	{ 0x0388, /* GREEK CAPITAL LETTER EPSILON WITH TONOS */ \
+	  0x03AD, /* GREEK SMALL LETTER EPSILON WITH TONOS */ }, \
+	{ 0x1FC8, /* GREEK CAPITAL LETTER EPSILON WITH VARIA */ \
+	  0x1F72, /* GREEK SMALL LETTER EPSILON WITH VARIA */ }, \
+	{ 0x0397, /* GREEK CAPITAL LETTER ETA */ \
+	  0x03B7, /* GREEK SMALL LETTER ETA */ }, \
+	{ 0x1F29, /* GREEK CAPITAL LETTER ETA WITH DASIA */ \
+	  0x1F21, /* GREEK SMALL LETTER ETA WITH DASIA */ }, \
+	{ 0x1F2D, /* GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA */ \
+	  0x1F25, /* GREEK SMALL LETTER ETA WITH DASIA AND OXIA */ }, \
+	{ 0x1F2F, /* GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI */ \
+	  0x1F27, /* GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI */ }, \
+	{ 0x1F2B, /* GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA */ \
+	  0x1F23, /* GREEK SMALL LETTER ETA WITH DASIA AND VARIA */ }, \
+	{ 0x1FCB, /* GREEK CAPITAL LETTER ETA WITH OXIA */ \
+	  0x1F75, /* GREEK SMALL LETTER ETA WITH OXIA */ }, \
+	{ 0x1F28, /* GREEK CAPITAL LETTER ETA WITH PSILI */ \
+	  0x1F20, /* GREEK SMALL LETTER ETA WITH PSILI */ }, \
+	{ 0x1F2C, /* GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA */ \
+	  0x1F24, /* GREEK SMALL LETTER ETA WITH PSILI AND OXIA */ }, \
+	{ 0x1F2E, /* GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI */ \
+	  0x1F26, /* GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI */ }, \
+	{ 0x1F2A, /* GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA */ \
+	  0x1F22, /* GREEK SMALL LETTER ETA WITH PSILI AND VARIA */ }, \
+	{ 0x0389, /* GREEK CAPITAL LETTER ETA WITH TONOS */ \
+	  0x03AE, /* GREEK SMALL LETTER ETA WITH TONOS */ }, \
+	{ 0x1FCA, /* GREEK CAPITAL LETTER ETA WITH VARIA */ \
+	  0x1F74, /* GREEK SMALL LETTER ETA WITH VARIA */ }, \
+	{ 0x0393, /* GREEK CAPITAL LETTER GAMMA */ \
+	  0x03B3, /* GREEK SMALL LETTER GAMMA */ }, \
+	{ 0x0370, /* GREEK CAPITAL LETTER HETA */ \
+	  0x0371, /* GREEK SMALL LETTER HETA */ }, \
+	{ 0x0399, /* GREEK CAPITAL LETTER IOTA */ \
+	  0x03B9, /* GREEK SMALL LETTER IOTA */ }, \
+	{ 0x1F39, /* GREEK CAPITAL LETTER IOTA WITH DASIA */ \
+	  0x1F31, /* GREEK SMALL LETTER IOTA WITH DASIA */ }, \
+	{ 0x1F3D, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA */ \
+	  0x1F35, /* GREEK SMALL LETTER IOTA WITH DASIA AND OXIA */ }, \
+	{ 0x1F3F, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI */ \
+	  0x1F37, /* GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI */ }, \
+	{ 0x1F3B, /* GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA */ \
+	  0x1F33, /* GREEK SMALL LETTER IOTA WITH DASIA AND VARIA */ }, \
+	{ 0x03AA, /* GREEK CAPITAL LETTER IOTA WITH DIALYTIKA */ \
+	  0x03CA, /* GREEK SMALL LETTER IOTA WITH DIALYTIKA */ }, \
+	{ 0x1FD9, /* GREEK CAPITAL LETTER IOTA WITH MACRON */ \
+	  0x1FD1, /* GREEK SMALL LETTER IOTA WITH MACRON */ }, \
+	{ 0x1FDB, /* GREEK CAPITAL LETTER IOTA WITH OXIA */ \
+	  0x1F77, /* GREEK SMALL LETTER IOTA WITH OXIA */ }, \
+	{ 0x1F38, /* GREEK CAPITAL LETTER IOTA WITH PSILI */ \
+	  0x1F30, /* GREEK SMALL LETTER IOTA WITH PSILI */ }, \
+	{ 0x1F3C, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA */ \
+	  0x1F34, /* GREEK SMALL LETTER IOTA WITH PSILI AND OXIA */ }, \
+	{ 0x1F3E, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI */ \
+	  0x1F36, /* GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI */ }, \
+	{ 0x1F3A, /* GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA */ \
+	  0x1F32, /* GREEK SMALL LETTER IOTA WITH PSILI AND VARIA */ }, \
+	{ 0x038A, /* GREEK CAPITAL LETTER IOTA WITH TONOS */ \
+	  0x03AF, /* GREEK SMALL LETTER IOTA WITH TONOS */ }, \
+	{ 0x1FDA, /* GREEK CAPITAL LETTER IOTA WITH VARIA */ \
+	  0x1F76, /* GREEK SMALL LETTER IOTA WITH VARIA */ }, \
+	{ 0x1FD8, /* GREEK CAPITAL LETTER IOTA WITH VRACHY */ \
+	  0x1FD0, /* GREEK SMALL LETTER IOTA WITH VRACHY */ }, \
+	{ 0x039A, /* GREEK CAPITAL LETTER KAPPA */ \
+	  0x03BA, /* GREEK SMALL LETTER KAPPA */ }, \
+	{ 0x039B, /* GREEK CAPITAL LETTER LAMDA */ \
+	  0x03BB, /* GREEK SMALL LETTER LAMDA */ }, \
+	{ 0x039C, /* GREEK CAPITAL LETTER MU */ \
+	  0x03BC, /* GREEK SMALL LETTER MU */ }, \
+	{ 0x039D, /* GREEK CAPITAL LETTER NU */ \
+	  0x03BD, /* GREEK SMALL LETTER NU */ }, \
+	{ 0x03A9, /* GREEK CAPITAL LETTER OMEGA */ \
+	  0x03C9, /* GREEK SMALL LETTER OMEGA */ }, \
+	{ 0x1F69, /* GREEK CAPITAL LETTER OMEGA WITH DASIA */ \
+	  0x1F61, /* GREEK SMALL LETTER OMEGA WITH DASIA */ }, \
+	{ 0x1F6D, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA */ \
+	  0x1F65, /* GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA */ }, \
+	{ 0x1F6F, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI */ \
+	  0x1F67, /* GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI */ }, \
+	{ 0x1F6B, /* GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA */ \
+	  0x1F63, /* GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA */ }, \
+	{ 0x1FFB, /* GREEK CAPITAL LETTER OMEGA WITH OXIA */ \
+	  0x1F7D, /* GREEK SMALL LETTER OMEGA WITH OXIA */ }, \
+	{ 0x1F68, /* GREEK CAPITAL LETTER OMEGA WITH PSILI */ \
+	  0x1F60, /* GREEK SMALL LETTER OMEGA WITH PSILI */ }, \
+	{ 0x1F6C, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA */ \
+	  0x1F64, /* GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA */ }, \
+	{ 0x1F6E, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI */ \
+	  0x1F66, /* GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI */ }, \
+	{ 0x1F6A, /* GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA */ \
+	  0x1F62, /* GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA */ }, \
+	{ 0x038F, /* GREEK CAPITAL LETTER OMEGA WITH TONOS */ \
+	  0x03CE, /* GREEK SMALL LETTER OMEGA WITH TONOS */ }, \
+	{ 0x1FFA, /* GREEK CAPITAL LETTER OMEGA WITH VARIA */ \
+	  0x1F7C, /* GREEK SMALL LETTER OMEGA WITH VARIA */ }, \
+	{ 0x039F, /* GREEK CAPITAL LETTER OMICRON */ \
+	  0x03BF, /* GREEK SMALL LETTER OMICRON */ }, \
+	{ 0x1F49, /* GREEK CAPITAL LETTER OMICRON WITH DASIA */ \
+	  0x1F41, /* GREEK SMALL LETTER OMICRON WITH DASIA */ }, \
+	{ 0x1F4D, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA */ \
+	  0x1F45, /* GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA */ }, \
+	{ 0x1F4B, /* GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA */ \
+	  0x1F43, /* GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA */ }, \
+	{ 0x1FF9, /* GREEK CAPITAL LETTER OMICRON WITH OXIA */ \
+	  0x1F79, /* GREEK SMALL LETTER OMICRON WITH OXIA */ }, \
+	{ 0x1F48, /* GREEK CAPITAL LETTER OMICRON WITH PSILI */ \
+	  0x1F40, /* GREEK SMALL LETTER OMICRON WITH PSILI */ }, \
+	{ 0x1F4C, /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA */ \
+	  0x1F44, /* GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA */ }, \
+	{ 0x1F4A, /* GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA */ \
+	  0x1F42, /* GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA */ }, \
+	{ 0x038C, /* GREEK CAPITAL LETTER OMICRON WITH TONOS */ \
+	  0x03CC, /* GREEK SMALL LETTER OMICRON WITH TONOS */ }, \
+	{ 0x1FF8, /* GREEK CAPITAL LETTER OMICRON WITH VARIA */ \
+	  0x1F78, /* GREEK SMALL LETTER OMICRON WITH VARIA */ }, \
+	{ 0x0376, /* GREEK CAPITAL LETTER PAMPHYLIAN DIGAMMA */ \
+	  0x0377, /* GREEK SMALL LETTER PAMPHYLIAN DIGAMMA */ }, \
+	{ 0x03A6, /* GREEK CAPITAL LETTER PHI */ \
+	  0x03C6, /* GREEK SMALL LETTER PHI */ }, \
+	{ 0x03A0, /* GREEK CAPITAL LETTER PI */ \
+	  0x03C0, /* GREEK SMALL LETTER PI */ }, \
+	{ 0x03A8, /* GREEK CAPITAL LETTER PSI */ \
+	  0x03C8, /* GREEK SMALL LETTER PSI */ }, \
+	{ 0x03A1, /* GREEK CAPITAL LETTER RHO */ \
+	  0x03C1, /* GREEK SMALL LETTER RHO */ }, \
+	{ 0x1FEC, /* GREEK CAPITAL LETTER RHO WITH DASIA */ \
+	  0x1FE5, /* GREEK SMALL LETTER RHO WITH DASIA */ }, \
+	{ 0x03FA, /* GREEK CAPITAL LETTER SAN */ \
+	  0x03FB, /* GREEK SMALL LETTER SAN */ }, \
+	{ 0x03F7, /* GREEK CAPITAL LETTER SHO */ \
+	  0x03F8, /* GREEK SMALL LETTER SHO */ }, \
+	{ 0x03A3, /* GREEK CAPITAL LETTER SIGMA */ \
+	  0x03C3, /* GREEK SMALL LETTER SIGMA */ }, \
+	{ 0x03A4, /* GREEK CAPITAL LETTER TAU */ \
+	  0x03C4, /* GREEK SMALL LETTER TAU */ }, \
+	{ 0x0398, /* GREEK CAPITAL LETTER THETA */ \
+	  0x03B8, /* GREEK SMALL LETTER THETA */ }, \
+	{ 0x03A5, /* GREEK CAPITAL LETTER UPSILON */ \
+	  0x03C5, /* GREEK SMALL LETTER UPSILON */ }, \
+	{ 0x1F59, /* GREEK CAPITAL LETTER UPSILON WITH DASIA */ \
+	  0x1F51, /* GREEK SMALL LETTER UPSILON WITH DASIA */ }, \
+	{ 0x1F5D, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA */ \
+	  0x1F55, /* GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA */ }, \
+	{ 0x1F5F, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI */ \
+	  0x1F57, /* GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI */ }, \
+	{ 0x1F5B, /* GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA */ \
+	  0x1F53, /* GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA */ }, \
+	{ 0x03AB, /* GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA */ \
+	  0x03CB, /* GREEK SMALL LETTER UPSILON WITH DIALYTIKA */ }, \
+	{ 0x1FE9, /* GREEK CAPITAL LETTER UPSILON WITH MACRON */ \
+	  0x1FE1, /* GREEK SMALL LETTER UPSILON WITH MACRON */ }, \
+	{ 0x1FEB, /* GREEK CAPITAL LETTER UPSILON WITH OXIA */ \
+	  0x1F7B, /* GREEK SMALL LETTER UPSILON WITH OXIA */ }, \
+	{ 0x038E, /* GREEK CAPITAL LETTER UPSILON WITH TONOS */ \
+	  0x03CD, /* GREEK SMALL LETTER UPSILON WITH TONOS */ }, \
+	{ 0x1FEA, /* GREEK CAPITAL LETTER UPSILON WITH VARIA */ \
+	  0x1F7A, /* GREEK SMALL LETTER UPSILON WITH VARIA */ }, \
+	{ 0x1FE8, /* GREEK CAPITAL LETTER UPSILON WITH VRACHY */ \
+	  0x1FE0, /* GREEK SMALL LETTER UPSILON WITH VRACHY */ }, \
+	{ 0x039E, /* GREEK CAPITAL LETTER XI */ \
+	  0x03BE, /* GREEK SMALL LETTER XI */ }, \
+	{ 0x0396, /* GREEK CAPITAL LETTER ZETA */ \
+	  0x03B6, /* GREEK SMALL LETTER ZETA */ }, \
+	{ 0x0041, /* LATIN CAPITAL LETTER A */ \
+	  0x0061, /* LATIN SMALL LETTER A */ }, \
+	{ 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */ \
+	  0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */ }, \
+	{ 0x0102, /* LATIN CAPITAL LETTER A WITH BREVE */ \
+	  0x0103, /* LATIN SMALL LETTER A WITH BREVE */ }, \
+	{ 0x1EAE, /* LATIN CAPITAL LETTER A WITH BREVE AND ACUTE */ \
+	  0x1EAF, /* LATIN SMALL LETTER A WITH BREVE AND ACUTE */ }, \
+	{ 0x1EB6, /* LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW */ \
+	  0x1EB7, /* LATIN SMALL LETTER A WITH BREVE AND DOT BELOW */ }, \
+	{ 0x1EB0, /* LATIN CAPITAL LETTER A WITH BREVE AND GRAVE */ \
+	  0x1EB1, /* LATIN SMALL LETTER A WITH BREVE AND GRAVE */ }, \
+	{ 0x1EB2, /* LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE */ \
+	  0x1EB3, /* LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE */ }, \
+	{ 0x1EB4, /* LATIN CAPITAL LETTER A WITH BREVE AND TILDE */ \
+	  0x1EB5, /* LATIN SMALL LETTER A WITH BREVE AND TILDE */ }, \
+	{ 0x01CD, /* LATIN CAPITAL LETTER A WITH CARON */ \
+	  0x01CE, /* LATIN SMALL LETTER A WITH CARON */ }, \
+	{ 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ \
+	  0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ }, \
+	{ 0x1EA4, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE */ \
+	  0x1EA5, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE */ }, \
+	{ 0x1EAC, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ \
+	  0x1EAD, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW */ }, \
+	{ 0x1EA6, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE */ \
+	  0x1EA7, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE */ }, \
+	{ 0x1EA8, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ \
+	  0x1EA9, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE */ }, \
+	{ 0x1EAA, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE */ \
+	  0x1EAB, /* LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE */ }, \
+	{ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \
+	  0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \
+	{ 0x01DE, /* LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON */ \
+	  0x01DF, /* LATIN SMALL LETTER A WITH DIAERESIS AND MACRON */ }, \
+	{ 0x0226, /* LATIN CAPITAL LETTER A WITH DOT ABOVE */ \
+	  0x0227, /* LATIN SMALL LETTER A WITH DOT ABOVE */ }, \
+	{ 0x01E0, /* LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON */ \
+	  0x01E1, /* LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON */ }, \
+	{ 0x1EA0, /* LATIN CAPITAL LETTER A WITH DOT BELOW */ \
+	  0x1EA1, /* LATIN SMALL LETTER A WITH DOT BELOW */ }, \
+	{ 0x0200, /* LATIN CAPITAL LETTER A WITH DOUBLE GRAVE */ \
+	  0x0201, /* LATIN SMALL LETTER A WITH DOUBLE GRAVE */ }, \
+	{ 0x00C0, /* LATIN CAPITAL LETTER A WITH GRAVE */ \
+	  0x00E0, /* LATIN SMALL LETTER A WITH GRAVE */ }, \
+	{ 0x1EA2, /* LATIN CAPITAL LETTER A WITH HOOK ABOVE */ \
+	  0x1EA3, /* LATIN SMALL LETTER A WITH HOOK ABOVE */ }, \
+	{ 0x0202, /* LATIN CAPITAL LETTER A WITH INVERTED BREVE */ \
+	  0x0203, /* LATIN SMALL LETTER A WITH INVERTED BREVE */ }, \
+	{ 0x0100, /* LATIN CAPITAL LETTER A WITH MACRON */ \
+	  0x0101, /* LATIN SMALL LETTER A WITH MACRON */ }, \
+	{ 0x0104, /* LATIN CAPITAL LETTER A WITH OGONEK */ \
+	  0x0105, /* LATIN SMALL LETTER A WITH OGONEK */ }, \
+	{ 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ \
+	  0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */ }, \
+	{ 0x01FA, /* LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE */ \
+	  0x01FB, /* LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE */ }, \
+	{ 0x1E00, /* LATIN CAPITAL LETTER A WITH RING BELOW */ \
+	  0x1E01, /* LATIN SMALL LETTER A WITH RING BELOW */ }, \
+	{ 0x023A, /* LATIN CAPITAL LETTER A WITH STROKE */ \
+	  0x2C65, /* LATIN SMALL LETTER A WITH STROKE */ }, \
+	{ 0x00C3, /* LATIN CAPITAL LETTER A WITH TILDE */ \
+	  0x00E3, /* LATIN SMALL LETTER A WITH TILDE */ }, \
+	{ 0xA732, /* LATIN CAPITAL LETTER AA */ \
+	  0xA733, /* LATIN SMALL LETTER AA */ }, \
+	{ 0x00C6, /* LATIN CAPITAL LETTER AE */ \
+	  0x00E6, /* LATIN SMALL LETTER AE */ }, \
+	{ 0x01FC, /* LATIN CAPITAL LETTER AE WITH ACUTE */ \
+	  0x01FD, /* LATIN SMALL LETTER AE WITH ACUTE */ }, \
+	{ 0x01E2, /* LATIN CAPITAL LETTER AE WITH MACRON */ \
+	  0x01E3, /* LATIN SMALL LETTER AE WITH MACRON */ }, \
+	{ 0x2C6D, /* LATIN CAPITAL LETTER ALPHA */ \
+	  0x0251, /* LATIN SMALL LETTER ALPHA */ }, \
+	{ 0xA734, /* LATIN CAPITAL LETTER AO */ \
+	  0xA735, /* LATIN SMALL LETTER AO */ }, \
+	{ 0xA736, /* LATIN CAPITAL LETTER AU */ \
+	  0xA737, /* LATIN SMALL LETTER AU */ }, \
+	{ 0xA738, /* LATIN CAPITAL LETTER AV */ \
+	  0xA739, /* LATIN SMALL LETTER AV */ }, \
+	{ 0xA73A, /* LATIN CAPITAL LETTER AV WITH HORIZONTAL BAR */ \
+	  0xA73B, /* LATIN SMALL LETTER AV WITH HORIZONTAL BAR */ }, \
+	{ 0xA73C, /* LATIN CAPITAL LETTER AY */ \
+	  0xA73D, /* LATIN SMALL LETTER AY */ }, \
+	{ 0x0042, /* LATIN CAPITAL LETTER B */ \
+	  0x0062, /* LATIN SMALL LETTER B */ }, \
+	{ 0x1E02, /* LATIN CAPITAL LETTER B WITH DOT ABOVE */ \
+	  0x1E03, /* LATIN SMALL LETTER B WITH DOT ABOVE */ }, \
+	{ 0x1E04, /* LATIN CAPITAL LETTER B WITH DOT BELOW */ \
+	  0x1E05, /* LATIN SMALL LETTER B WITH DOT BELOW */ }, \
+	{ 0xA796, /* LATIN CAPITAL LETTER B WITH FLOURISH */ \
+	  0xA797, /* LATIN SMALL LETTER B WITH FLOURISH */ }, \
+	{ 0x0181, /* LATIN CAPITAL LETTER B WITH HOOK */ \
+	  0x0253, /* LATIN SMALL LETTER B WITH HOOK */ }, \
+	{ 0x1E06, /* LATIN CAPITAL LETTER B WITH LINE BELOW */ \
+	  0x1E07, /* LATIN SMALL LETTER B WITH LINE BELOW */ }, \
+	{ 0x0243, /* LATIN CAPITAL LETTER B WITH STROKE */ \
+	  0x0180, /* LATIN SMALL LETTER B WITH STROKE */ }, \
+	{ 0x0182, /* LATIN CAPITAL LETTER B WITH TOPBAR */ \
+	  0x0183, /* LATIN SMALL LETTER B WITH TOPBAR */ }, \
+	{ 0xA7B4, /* LATIN CAPITAL LETTER BETA */ \
+	  0xA7B5, /* LATIN SMALL LETTER BETA */ }, \
+	{ 0xA746, /* LATIN CAPITAL LETTER BROKEN L */ \
+	  0xA747, /* LATIN SMALL LETTER BROKEN L */ }, \
+	{ 0x0043, /* LATIN CAPITAL LETTER C */ \
+	  0x0063, /* LATIN SMALL LETTER C */ }, \
+	{ 0x0106, /* LATIN CAPITAL LETTER C WITH ACUTE */ \
+	  0x0107, /* LATIN SMALL LETTER C WITH ACUTE */ }, \
+	{ 0xA792, /* LATIN CAPITAL LETTER C WITH BAR */ \
+	  0xA793, /* LATIN SMALL LETTER C WITH BAR */ }, \
+	{ 0x010C, /* LATIN CAPITAL LETTER C WITH CARON */ \
+	  0x010D, /* LATIN SMALL LETTER C WITH CARON */ }, \
+	{ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \
+	  0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \
+	{ 0x1E08, /* LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE */ \
+	  0x1E09, /* LATIN SMALL LETTER C WITH CEDILLA AND ACUTE */ }, \
+	{ 0x0108, /* LATIN CAPITAL LETTER C WITH CIRCUMFLEX */ \
+	  0x0109, /* LATIN SMALL LETTER C WITH CIRCUMFLEX */ }, \
+	{ 0x010A, /* LATIN CAPITAL LETTER C WITH DOT ABOVE */ \
+	  0x010B, /* LATIN SMALL LETTER C WITH DOT ABOVE */ }, \
+	{ 0x0187, /* LATIN CAPITAL LETTER C WITH HOOK */ \
+	  0x0188, /* LATIN SMALL LETTER C WITH HOOK */ }, \
+	{ 0x023B, /* LATIN CAPITAL LETTER C WITH STROKE */ \
+	  0x023C, /* LATIN SMALL LETTER C WITH STROKE */ }, \
+	{ 0xA7B3, /* LATIN CAPITAL LETTER CHI */ \
+	  0xAB53, /* LATIN SMALL LETTER CHI */ }, \
+	{ 0xA76E, /* LATIN CAPITAL LETTER CON */ \
+	  0xA76F, /* LATIN SMALL LETTER CON */ }, \
+	{ 0xA72C, /* LATIN CAPITAL LETTER CUATRILLO */ \
+	  0xA72D, /* LATIN SMALL LETTER CUATRILLO */ }, \
+	{ 0xA72E, /* LATIN CAPITAL LETTER CUATRILLO WITH COMMA */ \
+	  0xA72F, /* LATIN SMALL LETTER CUATRILLO WITH COMMA */ }, \
+	{ 0x0044, /* LATIN CAPITAL LETTER D */ \
+	  0x0064, /* LATIN SMALL LETTER D */ }, \
+	{ 0x010E, /* LATIN CAPITAL LETTER D WITH CARON */ \
+	  0x010F, /* LATIN SMALL LETTER D WITH CARON */ }, \
+	{ 0x1E10, /* LATIN CAPITAL LETTER D WITH CEDILLA */ \
+	  0x1E11, /* LATIN SMALL LETTER D WITH CEDILLA */ }, \
+	{ 0x1E12, /* LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW */ \
+	  0x1E13, /* LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW */ }, \
+	{ 0x1E0A, /* LATIN CAPITAL LETTER D WITH DOT ABOVE */ \
+	  0x1E0B, /* LATIN SMALL LETTER D WITH DOT ABOVE */ }, \
+	{ 0x1E0C, /* LATIN CAPITAL LETTER D WITH DOT BELOW */ \
+	  0x1E0D, /* LATIN SMALL LETTER D WITH DOT BELOW */ }, \
+	{ 0x018A, /* LATIN CAPITAL LETTER D WITH HOOK */ \
+	  0x0257, /* LATIN SMALL LETTER D WITH HOOK */ }, \
+	{ 0x1E0E, /* LATIN CAPITAL LETTER D WITH LINE BELOW */ \
+	  0x1E0F, /* LATIN SMALL LETTER D WITH LINE BELOW */ }, \
+	{ 0x0110, /* LATIN CAPITAL LETTER D WITH STROKE */ \
+	  0x0111, /* LATIN SMALL LETTER D WITH STROKE */ }, \
+	{ 0x018B, /* LATIN CAPITAL LETTER D WITH TOPBAR */ \
+	  0x018C, /* LATIN SMALL LETTER D WITH TOPBAR */ }, \
+	{ 0x01F1, /* LATIN CAPITAL LETTER DZ */ \
+	  0x01F3, /* LATIN SMALL LETTER DZ */ }, \
+	{ 0x01C4, /* LATIN CAPITAL LETTER DZ WITH CARON */ \
+	  0x01C6, /* LATIN SMALL LETTER DZ WITH CARON */ }, \
+	{ 0x0045, /* LATIN CAPITAL LETTER E */ \
+	  0x0065, /* LATIN SMALL LETTER E */ }, \
+	{ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \
+	  0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \
+	{ 0x0114, /* LATIN CAPITAL LETTER E WITH BREVE */ \
+	  0x0115, /* LATIN SMALL LETTER E WITH BREVE */ }, \
+	{ 0x011A, /* LATIN CAPITAL LETTER E WITH CARON */ \
+	  0x011B, /* LATIN SMALL LETTER E WITH CARON */ }, \
+	{ 0x0228, /* LATIN CAPITAL LETTER E WITH CEDILLA */ \
+	  0x0229, /* LATIN SMALL LETTER E WITH CEDILLA */ }, \
+	{ 0x1E1C, /* LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE */ \
+	  0x1E1D, /* LATIN SMALL LETTER E WITH CEDILLA AND BREVE */ }, \
+	{ 0x00CA, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX */ \
+	  0x00EA, /* LATIN SMALL LETTER E WITH CIRCUMFLEX */ }, \
+	{ 0x1EBE, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE */ \
+	  0x1EBF, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE */ }, \
+	{ 0x1EC6, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ \
+	  0x1EC7, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW */ }, \
+	{ 0x1EC0, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE */ \
+	  0x1EC1, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE */ }, \
+	{ 0x1EC2, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ \
+	  0x1EC3, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE */ }, \
+	{ 0x1EC4, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE */ \
+	  0x1EC5, /* LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE */ }, \
+	{ 0x1E18, /* LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW */ \
+	  0x1E19, /* LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW */ }, \
+	{ 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ \
+	  0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */ }, \
+	{ 0x0116, /* LATIN CAPITAL LETTER E WITH DOT ABOVE */ \
+	  0x0117, /* LATIN SMALL LETTER E WITH DOT ABOVE */ }, \
+	{ 0x1EB8, /* LATIN CAPITAL LETTER E WITH DOT BELOW */ \
+	  0x1EB9, /* LATIN SMALL LETTER E WITH DOT BELOW */ }, \
+	{ 0x0204, /* LATIN CAPITAL LETTER E WITH DOUBLE GRAVE */ \
+	  0x0205, /* LATIN SMALL LETTER E WITH DOUBLE GRAVE */ }, \
+	{ 0x00C8, /* LATIN CAPITAL LETTER E WITH GRAVE */ \
+	  0x00E8, /* LATIN SMALL LETTER E WITH GRAVE */ }, \
+	{ 0x1EBA, /* LATIN CAPITAL LETTER E WITH HOOK ABOVE */ \
+	  0x1EBB, /* LATIN SMALL LETTER E WITH HOOK ABOVE */ }, \
+	{ 0x0206, /* LATIN CAPITAL LETTER E WITH INVERTED BREVE */ \
+	  0x0207, /* LATIN SMALL LETTER E WITH INVERTED BREVE */ }, \
+	{ 0x0112, /* LATIN CAPITAL LETTER E WITH MACRON */ \
+	  0x0113, /* LATIN SMALL LETTER E WITH MACRON */ }, \
+	{ 0x1E16, /* LATIN CAPITAL LETTER E WITH MACRON AND ACUTE */ \
+	  0x1E17, /* LATIN SMALL LETTER E WITH MACRON AND ACUTE */ }, \
+	{ 0x1E14, /* LATIN CAPITAL LETTER E WITH MACRON AND GRAVE */ \
+	  0x1E15, /* LATIN SMALL LETTER E WITH MACRON AND GRAVE */ }, \
+	{ 0x0118, /* LATIN CAPITAL LETTER E WITH OGONEK */ \
+	  0x0119, /* LATIN SMALL LETTER E WITH OGONEK */ }, \
+	{ 0x0246, /* LATIN CAPITAL LETTER E WITH STROKE */ \
+	  0x0247, /* LATIN SMALL LETTER E WITH STROKE */ }, \
+	{ 0x1EBC, /* LATIN CAPITAL LETTER E WITH TILDE */ \
+	  0x1EBD, /* LATIN SMALL LETTER E WITH TILDE */ }, \
+	{ 0x1E1A, /* LATIN CAPITAL LETTER E WITH TILDE BELOW */ \
+	  0x1E1B, /* LATIN SMALL LETTER E WITH TILDE BELOW */ }, \
+	{ 0xA724, /* LATIN CAPITAL LETTER EGYPTOLOGICAL AIN */ \
+	  0xA725, /* LATIN SMALL LETTER EGYPTOLOGICAL AIN */ }, \
+	{ 0xA722, /* LATIN CAPITAL LETTER EGYPTOLOGICAL ALEF */ \
+	  0xA723, /* LATIN SMALL LETTER EGYPTOLOGICAL ALEF */ }, \
+	{ 0x014A, /* LATIN CAPITAL LETTER ENG */ \
+	  0x014B, /* LATIN SMALL LETTER ENG */ }, \
+	{ 0x01A9, /* LATIN CAPITAL LETTER ESH */ \
+	  0x0283, /* LATIN SMALL LETTER ESH */ }, \
+	{ 0xA76A, /* LATIN CAPITAL LETTER ET */ \
+	  0xA76B, /* LATIN SMALL LETTER ET */ }, \
+	{ 0x00D0, /* LATIN CAPITAL LETTER ETH */ \
+	  0x00F0, /* LATIN SMALL LETTER ETH */ }, \
+	{ 0x01B7, /* LATIN CAPITAL LETTER EZH */ \
+	  0x0292, /* LATIN SMALL LETTER EZH */ }, \
+	{ 0x01B8, /* LATIN CAPITAL LETTER EZH REVERSED */ \
+	  0x01B9, /* LATIN SMALL LETTER EZH REVERSED */ }, \
+	{ 0x01EE, /* LATIN CAPITAL LETTER EZH WITH CARON */ \
+	  0x01EF, /* LATIN SMALL LETTER EZH WITH CARON */ }, \
+	{ 0x0046, /* LATIN CAPITAL LETTER F */ \
+	  0x0066, /* LATIN SMALL LETTER F */ }, \
+	{ 0x1E1E, /* LATIN CAPITAL LETTER F WITH DOT ABOVE */ \
+	  0x1E1F, /* LATIN SMALL LETTER F WITH DOT ABOVE */ }, \
+	{ 0x0191, /* LATIN CAPITAL LETTER F WITH HOOK */ \
+	  0x0192, /* LATIN SMALL LETTER F WITH HOOK */ }, \
+	{ 0xA798, /* LATIN CAPITAL LETTER F WITH STROKE */ \
+	  0xA799, /* LATIN SMALL LETTER F WITH STROKE */ }, \
+	{ 0x0047, /* LATIN CAPITAL LETTER G */ \
+	  0x0067, /* LATIN SMALL LETTER G */ }, \
+	{ 0x01F4, /* LATIN CAPITAL LETTER G WITH ACUTE */ \
+	  0x01F5, /* LATIN SMALL LETTER G WITH ACUTE */ }, \
+	{ 0x011E, /* LATIN CAPITAL LETTER G WITH BREVE */ \
+	  0x011F, /* LATIN SMALL LETTER G WITH BREVE */ }, \
+	{ 0x01E6, /* LATIN CAPITAL LETTER G WITH CARON */ \
+	  0x01E7, /* LATIN SMALL LETTER G WITH CARON */ }, \
+	{ 0x0122, /* LATIN CAPITAL LETTER G WITH CEDILLA */ \
+	  0x0123, /* LATIN SMALL LETTER G WITH CEDILLA */ }, \
+	{ 0x011C, /* LATIN CAPITAL LETTER G WITH CIRCUMFLEX */ \
+	  0x011D, /* LATIN SMALL LETTER G WITH CIRCUMFLEX */ }, \
+	{ 0x0120, /* LATIN CAPITAL LETTER G WITH DOT ABOVE */ \
+	  0x0121, /* LATIN SMALL LETTER G WITH DOT ABOVE */ }, \
+	{ 0x0193, /* LATIN CAPITAL LETTER G WITH HOOK */ \
+	  0x0260, /* LATIN SMALL LETTER G WITH HOOK */ }, \
+	{ 0x1E20, /* LATIN CAPITAL LETTER G WITH MACRON */ \
+	  0x1E21, /* LATIN SMALL LETTER G WITH MACRON */ }, \
+	{ 0xA7A0, /* LATIN CAPITAL LETTER G WITH OBLIQUE STROKE */ \
+	  0xA7A1, /* LATIN SMALL LETTER G WITH OBLIQUE STROKE */ }, \
+	{ 0x01E4, /* LATIN CAPITAL LETTER G WITH STROKE */ \
+	  0x01E5, /* LATIN SMALL LETTER G WITH STROKE */ }, \
+	{ 0x0194, /* LATIN CAPITAL LETTER GAMMA */ \
+	  0x0263, /* LATIN SMALL LETTER GAMMA */ }, \
+	{ 0x0241, /* LATIN CAPITAL LETTER GLOTTAL STOP */ \
+	  0x0242, /* LATIN SMALL LETTER GLOTTAL STOP */ }, \
+	{ 0x0048, /* LATIN CAPITAL LETTER H */ \
+	  0x0068, /* LATIN SMALL LETTER H */ }, \
+	{ 0x1E2A, /* LATIN CAPITAL LETTER H WITH BREVE BELOW */ \
+	  0x1E2B, /* LATIN SMALL LETTER H WITH BREVE BELOW */ }, \
+	{ 0x021E, /* LATIN CAPITAL LETTER H WITH CARON */ \
+	  0x021F, /* LATIN SMALL LETTER H WITH CARON */ }, \
+	{ 0x1E28, /* LATIN CAPITAL LETTER H WITH CEDILLA */ \
+	  0x1E29, /* LATIN SMALL LETTER H WITH CEDILLA */ }, \
+	{ 0x0124, /* LATIN CAPITAL LETTER H WITH CIRCUMFLEX */ \
+	  0x0125, /* LATIN SMALL LETTER H WITH CIRCUMFLEX */ }, \
+	{ 0x2C67, /* LATIN CAPITAL LETTER H WITH DESCENDER */ \
+	  0x2C68, /* LATIN SMALL LETTER H WITH DESCENDER */ }, \
+	{ 0x1E26, /* LATIN CAPITAL LETTER H WITH DIAERESIS */ \
+	  0x1E27, /* LATIN SMALL LETTER H WITH DIAERESIS */ }, \
+	{ 0x1E22, /* LATIN CAPITAL LETTER H WITH DOT ABOVE */ \
+	  0x1E23, /* LATIN SMALL LETTER H WITH DOT ABOVE */ }, \
+	{ 0x1E24, /* LATIN CAPITAL LETTER H WITH DOT BELOW */ \
+	  0x1E25, /* LATIN SMALL LETTER H WITH DOT BELOW */ }, \
+	{ 0xA7AA, /* LATIN CAPITAL LETTER H WITH HOOK */ \
+	  0x0266, /* LATIN SMALL LETTER H WITH HOOK */ }, \
+	{ 0x0126, /* LATIN CAPITAL LETTER H WITH STROKE */ \
+	  0x0127, /* LATIN SMALL LETTER H WITH STROKE */ }, \
+	{ 0x2C75, /* LATIN CAPITAL LETTER HALF H */ \
+	  0x2C76, /* LATIN SMALL LETTER HALF H */ }, \
+	{ 0xA726, /* LATIN CAPITAL LETTER HENG */ \
+	  0xA727, /* LATIN SMALL LETTER HENG */ }, \
+	{ 0x0049, /* LATIN CAPITAL LETTER I */ \
+	  0x0069, /* LATIN SMALL LETTER I */ }, \
+	{ 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */ \
+	  0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */ }, \
+	{ 0x012C, /* LATIN CAPITAL LETTER I WITH BREVE */ \
+	  0x012D, /* LATIN SMALL LETTER I WITH BREVE */ }, \
+	{ 0x01CF, /* LATIN CAPITAL LETTER I WITH CARON */ \
+	  0x01D0, /* LATIN SMALL LETTER I WITH CARON */ }, \
+	{ 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ \
+	  0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ }, \
+	{ 0x00CF, /* LATIN CAPITAL LETTER I WITH DIAERESIS */ \
+	  0x00EF, /* LATIN SMALL LETTER I WITH DIAERESIS */ }, \
+	{ 0x1E2E, /* LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE */ \
+	  0x1E2F, /* LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE */ }, \
+	{ 0x1ECA, /* LATIN CAPITAL LETTER I WITH DOT BELOW */ \
+	  0x1ECB, /* LATIN SMALL LETTER I WITH DOT BELOW */ }, \
+	{ 0x0208, /* LATIN CAPITAL LETTER I WITH DOUBLE GRAVE */ \
+	  0x0209, /* LATIN SMALL LETTER I WITH DOUBLE GRAVE */ }, \
+	{ 0x00CC, /* LATIN CAPITAL LETTER I WITH GRAVE */ \
+	  0x00EC, /* LATIN SMALL LETTER I WITH GRAVE */ }, \
+	{ 0x1EC8, /* LATIN CAPITAL LETTER I WITH HOOK ABOVE */ \
+	  0x1EC9, /* LATIN SMALL LETTER I WITH HOOK ABOVE */ }, \
+	{ 0x020A, /* LATIN CAPITAL LETTER I WITH INVERTED BREVE */ \
+	  0x020B, /* LATIN SMALL LETTER I WITH INVERTED BREVE */ }, \
+	{ 0x012A, /* LATIN CAPITAL LETTER I WITH MACRON */ \
+	  0x012B, /* LATIN SMALL LETTER I WITH MACRON */ }, \
+	{ 0x012E, /* LATIN CAPITAL LETTER I WITH OGONEK */ \
+	  0x012F, /* LATIN SMALL LETTER I WITH OGONEK */ }, \
+	{ 0x0197, /* LATIN CAPITAL LETTER I WITH STROKE */ \
+	  0x0268, /* LATIN SMALL LETTER I WITH STROKE */ }, \
+	{ 0x0128, /* LATIN CAPITAL LETTER I WITH TILDE */ \
+	  0x0129, /* LATIN SMALL LETTER I WITH TILDE */ }, \
+	{ 0x1E2C, /* LATIN CAPITAL LETTER I WITH TILDE BELOW */ \
+	  0x1E2D, /* LATIN SMALL LETTER I WITH TILDE BELOW */ }, \
+	{ 0xA779, /* LATIN CAPITAL LETTER INSULAR D */ \
+	  0xA77A, /* LATIN SMALL LETTER INSULAR D */ }, \
+	{ 0xA77B, /* LATIN CAPITAL LETTER INSULAR F */ \
+	  0xA77C, /* LATIN SMALL LETTER INSULAR F */ }, \
+	{ 0xA77D, /* LATIN CAPITAL LETTER INSULAR G */ \
+	  0x1D79, /* LATIN SMALL LETTER INSULAR G */ }, \
+	{ 0xA782, /* LATIN CAPITAL LETTER INSULAR R */ \
+	  0xA783, /* LATIN SMALL LETTER INSULAR R */ }, \
+	{ 0xA784, /* LATIN CAPITAL LETTER INSULAR S */ \
+	  0xA785, /* LATIN SMALL LETTER INSULAR S */ }, \
+	{ 0xA786, /* LATIN CAPITAL LETTER INSULAR T */ \
+	  0xA787, /* LATIN SMALL LETTER INSULAR T */ }, \
+	{ 0x0196, /* LATIN CAPITAL LETTER IOTA */ \
+	  0x0269, /* LATIN SMALL LETTER IOTA */ }, \
+	{ 0xA76C, /* LATIN CAPITAL LETTER IS */ \
+	  0xA76D, /* LATIN SMALL LETTER IS */ }, \
+	{ 0x004A, /* LATIN CAPITAL LETTER J */ \
+	  0x006A, /* LATIN SMALL LETTER J */ }, \
+	{ 0x0134, /* LATIN CAPITAL LETTER J WITH CIRCUMFLEX */ \
+	  0x0135, /* LATIN SMALL LETTER J WITH CIRCUMFLEX */ }, \
+	{ 0xA7B2, /* LATIN CAPITAL LETTER J WITH CROSSED-TAIL */ \
+	  0x029D, /* LATIN SMALL LETTER J WITH CROSSED-TAIL */ }, \
+	{ 0x0248, /* LATIN CAPITAL LETTER J WITH STROKE */ \
+	  0x0249, /* LATIN SMALL LETTER J WITH STROKE */ }, \
+	{ 0x004B, /* LATIN CAPITAL LETTER K */ \
+	  0x006B, /* LATIN SMALL LETTER K */ }, \
+	{ 0x1E30, /* LATIN CAPITAL LETTER K WITH ACUTE */ \
+	  0x1E31, /* LATIN SMALL LETTER K WITH ACUTE */ }, \
+	{ 0x01E8, /* LATIN CAPITAL LETTER K WITH CARON */ \
+	  0x01E9, /* LATIN SMALL LETTER K WITH CARON */ }, \
+	{ 0x0136, /* LATIN CAPITAL LETTER K WITH CEDILLA */ \
+	  0x0137, /* LATIN SMALL LETTER K WITH CEDILLA */ }, \
+	{ 0x2C69, /* LATIN CAPITAL LETTER K WITH DESCENDER */ \
+	  0x2C6A, /* LATIN SMALL LETTER K WITH DESCENDER */ }, \
+	{ 0xA742, /* LATIN CAPITAL LETTER K WITH DIAGONAL STROKE */ \
+	  0xA743, /* LATIN SMALL LETTER K WITH DIAGONAL STROKE */ }, \
+	{ 0x1E32, /* LATIN CAPITAL LETTER K WITH DOT BELOW */ \
+	  0x1E33, /* LATIN SMALL LETTER K WITH DOT BELOW */ }, \
+	{ 0x0198, /* LATIN CAPITAL LETTER K WITH HOOK */ \
+	  0x0199, /* LATIN SMALL LETTER K WITH HOOK */ }, \
+	{ 0x1E34, /* LATIN CAPITAL LETTER K WITH LINE BELOW */ \
+	  0x1E35, /* LATIN SMALL LETTER K WITH LINE BELOW */ }, \
+	{ 0xA7A2, /* LATIN CAPITAL LETTER K WITH OBLIQUE STROKE */ \
+	  0xA7A3, /* LATIN SMALL LETTER K WITH OBLIQUE STROKE */ }, \
+	{ 0xA740, /* LATIN CAPITAL LETTER K WITH STROKE */ \
+	  0xA741, /* LATIN SMALL LETTER K WITH STROKE */ }, \
+	{ 0xA744, /* LATIN CAPITAL LETTER K WITH STROKE AND DIAGONAL STROKE */ \
+	  0xA745, /* LATIN SMALL LETTER K WITH STROKE AND DIAGONAL STROKE */ }, \
+	{ 0x004C, /* LATIN CAPITAL LETTER L */ \
+	  0x006C, /* LATIN SMALL LETTER L */ }, \
+	{ 0x0139, /* LATIN CAPITAL LETTER L WITH ACUTE */ \
+	  0x013A, /* LATIN SMALL LETTER L WITH ACUTE */ }, \
+	{ 0x023D, /* LATIN CAPITAL LETTER L WITH BAR */ \
+	  0x019A, /* LATIN SMALL LETTER L WITH BAR */ }, \
+	{ 0xA7AD, /* LATIN CAPITAL LETTER L WITH BELT */ \
+	  0x026C, /* LATIN SMALL LETTER L WITH BELT */ }, \
+	{ 0x013D, /* LATIN CAPITAL LETTER L WITH CARON */ \
+	  0x013E, /* LATIN SMALL LETTER L WITH CARON */ }, \
+	{ 0x013B, /* LATIN CAPITAL LETTER L WITH CEDILLA */ \
+	  0x013C, /* LATIN SMALL LETTER L WITH CEDILLA */ }, \
+	{ 0x1E3C, /* LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW */ \
+	  0x1E3D, /* LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW */ }, \
+	{ 0x1E36, /* LATIN CAPITAL LETTER L WITH DOT BELOW */ \
+	  0x1E37, /* LATIN SMALL LETTER L WITH DOT BELOW */ }, \
+	{ 0x1E38, /* LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON */ \
+	  0x1E39, /* LATIN SMALL LETTER L WITH DOT BELOW AND MACRON */ }, \
+	{ 0x2C60, /* LATIN CAPITAL LETTER L WITH DOUBLE BAR */ \
+	  0x2C61, /* LATIN SMALL LETTER L WITH DOUBLE BAR */ }, \
+	{ 0xA748, /* LATIN CAPITAL LETTER L WITH HIGH STROKE */ \
+	  0xA749, /* LATIN SMALL LETTER L WITH HIGH STROKE */ }, \
+	{ 0x1E3A, /* LATIN CAPITAL LETTER L WITH LINE BELOW */ \
+	  0x1E3B, /* LATIN SMALL LETTER L WITH LINE BELOW */ }, \
+	{ 0x013F, /* LATIN CAPITAL LETTER L WITH MIDDLE DOT */ \
+	  0x0140, /* LATIN SMALL LETTER L WITH MIDDLE DOT */ }, \
+	{ 0x2C62, /* LATIN CAPITAL LETTER L WITH MIDDLE TILDE */ \
+	  0x026B, /* LATIN SMALL LETTER L WITH MIDDLE TILDE */ }, \
+	{ 0x0141, /* LATIN CAPITAL LETTER L WITH STROKE */ \
+	  0x0142, /* LATIN SMALL LETTER L WITH STROKE */ }, \
+	{ 0x01C7, /* LATIN CAPITAL LETTER LJ */ \
+	  0x01C9, /* LATIN SMALL LETTER LJ */ }, \
+	{ 0x004D, /* LATIN CAPITAL LETTER M */ \
+	  0x006D, /* LATIN SMALL LETTER M */ }, \
+	{ 0x1E3E, /* LATIN CAPITAL LETTER M WITH ACUTE */ \
+	  0x1E3F, /* LATIN SMALL LETTER M WITH ACUTE */ }, \
+	{ 0x1E40, /* LATIN CAPITAL LETTER M WITH DOT ABOVE */ \
+	  0x1E41, /* LATIN SMALL LETTER M WITH DOT ABOVE */ }, \
+	{ 0x1E42, /* LATIN CAPITAL LETTER M WITH DOT BELOW */ \
+	  0x1E43, /* LATIN SMALL LETTER M WITH DOT BELOW */ }, \
+	{ 0x2C6E, /* LATIN CAPITAL LETTER M WITH HOOK */ \
+	  0x0271, /* LATIN SMALL LETTER M WITH HOOK */ }, \
+	{ 0x1EFA, /* LATIN CAPITAL LETTER MIDDLE-WELSH LL */ \
+	  0x1EFB, /* LATIN SMALL LETTER MIDDLE-WELSH LL */ }, \
+	{ 0x1EFC, /* LATIN CAPITAL LETTER MIDDLE-WELSH V */ \
+	  0x1EFD, /* LATIN SMALL LETTER MIDDLE-WELSH V */ }, \
+	{ 0x004E, /* LATIN CAPITAL LETTER N */ \
+	  0x006E, /* LATIN SMALL LETTER N */ }, \
+	{ 0x0143, /* LATIN CAPITAL LETTER N WITH ACUTE */ \
+	  0x0144, /* LATIN SMALL LETTER N WITH ACUTE */ }, \
+	{ 0x0147, /* LATIN CAPITAL LETTER N WITH CARON */ \
+	  0x0148, /* LATIN SMALL LETTER N WITH CARON */ }, \
+	{ 0x0145, /* LATIN CAPITAL LETTER N WITH CEDILLA */ \
+	  0x0146, /* LATIN SMALL LETTER N WITH CEDILLA */ }, \
+	{ 0x1E4A, /* LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW */ \
+	  0x1E4B, /* LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW */ }, \
+	{ 0xA790, /* LATIN CAPITAL LETTER N WITH DESCENDER */ \
+	  0xA791, /* LATIN SMALL LETTER N WITH DESCENDER */ }, \
+	{ 0x1E44, /* LATIN CAPITAL LETTER N WITH DOT ABOVE */ \
+	  0x1E45, /* LATIN SMALL LETTER N WITH DOT ABOVE */ }, \
+	{ 0x1E46, /* LATIN CAPITAL LETTER N WITH DOT BELOW */ \
+	  0x1E47, /* LATIN SMALL LETTER N WITH DOT BELOW */ }, \
+	{ 0x01F8, /* LATIN CAPITAL LETTER N WITH GRAVE */ \
+	  0x01F9, /* LATIN SMALL LETTER N WITH GRAVE */ }, \
+	{ 0x019D, /* LATIN CAPITAL LETTER N WITH LEFT HOOK */ \
+	  0x0272, /* LATIN SMALL LETTER N WITH LEFT HOOK */ }, \
+	{ 0x1E48, /* LATIN CAPITAL LETTER N WITH LINE BELOW */ \
+	  0x1E49, /* LATIN SMALL LETTER N WITH LINE BELOW */ }, \
+	{ 0x0220, /* LATIN CAPITAL LETTER N WITH LONG RIGHT LEG */ \
+	  0x019E, /* LATIN SMALL LETTER N WITH LONG RIGHT LEG */ }, \
+	{ 0xA7A4, /* LATIN CAPITAL LETTER N WITH OBLIQUE STROKE */ \
+	  0xA7A5, /* LATIN SMALL LETTER N WITH OBLIQUE STROKE */ }, \
+	{ 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */ \
+	  0x00F1, /* LATIN SMALL LETTER N WITH TILDE */ }, \
+	{ 0x01CA, /* LATIN CAPITAL LETTER NJ */ \
+	  0x01CC, /* LATIN SMALL LETTER NJ */ }, \
+	{ 0x004F, /* LATIN CAPITAL LETTER O */ \
+	  0x006F, /* LATIN SMALL LETTER O */ }, \
+	{ 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */ \
+	  0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */ }, \
+	{ 0x014E, /* LATIN CAPITAL LETTER O WITH BREVE */ \
+	  0x014F, /* LATIN SMALL LETTER O WITH BREVE */ }, \
+	{ 0x01D1, /* LATIN CAPITAL LETTER O WITH CARON */ \
+	  0x01D2, /* LATIN SMALL LETTER O WITH CARON */ }, \
+	{ 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ \
+	  0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ }, \
+	{ 0x1ED0, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE */ \
+	  0x1ED1, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE */ }, \
+	{ 0x1ED8, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ \
+	  0x1ED9, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW */ }, \
+	{ 0x1ED2, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE */ \
+	  0x1ED3, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE */ }, \
+	{ 0x1ED4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ \
+	  0x1ED5, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE */ }, \
+	{ 0x1ED6, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE */ \
+	  0x1ED7, /* LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE */ }, \
+	{ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \
+	  0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \
+	{ 0x022A, /* LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON */ \
+	  0x022B, /* LATIN SMALL LETTER O WITH DIAERESIS AND MACRON */ }, \
+	{ 0x022E, /* LATIN CAPITAL LETTER O WITH DOT ABOVE */ \
+	  0x022F, /* LATIN SMALL LETTER O WITH DOT ABOVE */ }, \
+	{ 0x0230, /* LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON */ \
+	  0x0231, /* LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON */ }, \
+	{ 0x1ECC, /* LATIN CAPITAL LETTER O WITH DOT BELOW */ \
+	  0x1ECD, /* LATIN SMALL LETTER O WITH DOT BELOW */ }, \
+	{ 0x0150, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ \
+	  0x0151, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ }, \
+	{ 0x020C, /* LATIN CAPITAL LETTER O WITH DOUBLE GRAVE */ \
+	  0x020D, /* LATIN SMALL LETTER O WITH DOUBLE GRAVE */ }, \
+	{ 0x00D2, /* LATIN CAPITAL LETTER O WITH GRAVE */ \
+	  0x00F2, /* LATIN SMALL LETTER O WITH GRAVE */ }, \
+	{ 0x1ECE, /* LATIN CAPITAL LETTER O WITH HOOK ABOVE */ \
+	  0x1ECF, /* LATIN SMALL LETTER O WITH HOOK ABOVE */ }, \
+	{ 0x01A0, /* LATIN CAPITAL LETTER O WITH HORN */ \
+	  0x01A1, /* LATIN SMALL LETTER O WITH HORN */ }, \
+	{ 0x1EDA, /* LATIN CAPITAL LETTER O WITH HORN AND ACUTE */ \
+	  0x1EDB, /* LATIN SMALL LETTER O WITH HORN AND ACUTE */ }, \
+	{ 0x1EE2, /* LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW */ \
+	  0x1EE3, /* LATIN SMALL LETTER O WITH HORN AND DOT BELOW */ }, \
+	{ 0x1EDC, /* LATIN CAPITAL LETTER O WITH HORN AND GRAVE */ \
+	  0x1EDD, /* LATIN SMALL LETTER O WITH HORN AND GRAVE */ }, \
+	{ 0x1EDE, /* LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE */ \
+	  0x1EDF, /* LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE */ }, \
+	{ 0x1EE0, /* LATIN CAPITAL LETTER O WITH HORN AND TILDE */ \
+	  0x1EE1, /* LATIN SMALL LETTER O WITH HORN AND TILDE */ }, \
+	{ 0x020E, /* LATIN CAPITAL LETTER O WITH INVERTED BREVE */ \
+	  0x020F, /* LATIN SMALL LETTER O WITH INVERTED BREVE */ }, \
+	{ 0xA74A, /* LATIN CAPITAL LETTER O WITH LONG STROKE OVERLAY */ \
+	  0xA74B, /* LATIN SMALL LETTER O WITH LONG STROKE OVERLAY */ }, \
+	{ 0xA74C, /* LATIN CAPITAL LETTER O WITH LOOP */ \
+	  0xA74D, /* LATIN SMALL LETTER O WITH LOOP */ }, \
+	{ 0x014C, /* LATIN CAPITAL LETTER O WITH MACRON */ \
+	  0x014D, /* LATIN SMALL LETTER O WITH MACRON */ }, \
+	{ 0x1E52, /* LATIN CAPITAL LETTER O WITH MACRON AND ACUTE */ \
+	  0x1E53, /* LATIN SMALL LETTER O WITH MACRON AND ACUTE */ }, \
+	{ 0x1E50, /* LATIN CAPITAL LETTER O WITH MACRON AND GRAVE */ \
+	  0x1E51, /* LATIN SMALL LETTER O WITH MACRON AND GRAVE */ }, \
+	{ 0x01EA, /* LATIN CAPITAL LETTER O WITH OGONEK */ \
+	  0x01EB, /* LATIN SMALL LETTER O WITH OGONEK */ }, \
+	{ 0x01EC, /* LATIN CAPITAL LETTER O WITH OGONEK AND MACRON */ \
+	  0x01ED, /* LATIN SMALL LETTER O WITH OGONEK AND MACRON */ }, \
+	{ 0x00D8, /* LATIN CAPITAL LETTER O WITH STROKE */ \
+	  0x00F8, /* LATIN SMALL LETTER O WITH STROKE */ }, \
+	{ 0x01FE, /* LATIN CAPITAL LETTER O WITH STROKE AND ACUTE */ \
+	  0x01FF, /* LATIN SMALL LETTER O WITH STROKE AND ACUTE */ }, \
+	{ 0x00D5, /* LATIN CAPITAL LETTER O WITH TILDE */ \
+	  0x00F5, /* LATIN SMALL LETTER O WITH TILDE */ }, \
+	{ 0x1E4C, /* LATIN CAPITAL LETTER O WITH TILDE AND ACUTE */ \
+	  0x1E4D, /* LATIN SMALL LETTER O WITH TILDE AND ACUTE */ }, \
+	{ 0x1E4E, /* LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS */ \
+	  0x1E4F, /* LATIN SMALL LETTER O WITH TILDE AND DIAERESIS */ }, \
+	{ 0x022C, /* LATIN CAPITAL LETTER O WITH TILDE AND MACRON */ \
+	  0x022D, /* LATIN SMALL LETTER O WITH TILDE AND MACRON */ }, \
+	{ 0x01A2, /* LATIN CAPITAL LETTER OI */ \
+	  0x01A3, /* LATIN SMALL LETTER OI */ }, \
+	{ 0xA7B6, /* LATIN CAPITAL LETTER OMEGA */ \
+	  0xA7B7, /* LATIN SMALL LETTER OMEGA */ }, \
+	{ 0xA74E, /* LATIN CAPITAL LETTER OO */ \
+	  0xA74F, /* LATIN SMALL LETTER OO */ }, \
+	{ 0x0190, /* LATIN CAPITAL LETTER OPEN E */ \
+	  0x025B, /* LATIN SMALL LETTER OPEN E */ }, \
+	{ 0x0186, /* LATIN CAPITAL LETTER OPEN O */ \
+	  0x0254, /* LATIN SMALL LETTER OPEN O */ }, \
+	{ 0x0222, /* LATIN CAPITAL LETTER OU */ \
+	  0x0223, /* LATIN SMALL LETTER OU */ }, \
+	{ 0x0050, /* LATIN CAPITAL LETTER P */ \
+	  0x0070, /* LATIN SMALL LETTER P */ }, \
+	{ 0x1E54, /* LATIN CAPITAL LETTER P WITH ACUTE */ \
+	  0x1E55, /* LATIN SMALL LETTER P WITH ACUTE */ }, \
+	{ 0x1E56, /* LATIN CAPITAL LETTER P WITH DOT ABOVE */ \
+	  0x1E57, /* LATIN SMALL LETTER P WITH DOT ABOVE */ }, \
+	{ 0xA752, /* LATIN CAPITAL LETTER P WITH FLOURISH */ \
+	  0xA753, /* LATIN SMALL LETTER P WITH FLOURISH */ }, \
+	{ 0x01A4, /* LATIN CAPITAL LETTER P WITH HOOK */ \
+	  0x01A5, /* LATIN SMALL LETTER P WITH HOOK */ }, \
+	{ 0xA754, /* LATIN CAPITAL LETTER P WITH SQUIRREL TAIL */ \
+	  0xA755, /* LATIN SMALL LETTER P WITH SQUIRREL TAIL */ }, \
+	{ 0x2C63, /* LATIN CAPITAL LETTER P WITH STROKE */ \
+	  0x1D7D, /* LATIN SMALL LETTER P WITH STROKE */ }, \
+	{ 0xA750, /* LATIN CAPITAL LETTER P WITH STROKE THROUGH DESCENDER */ \
+	  0xA751, /* LATIN SMALL LETTER P WITH STROKE THROUGH DESCENDER */ }, \
+	{ 0x0051, /* LATIN CAPITAL LETTER Q */ \
+	  0x0071, /* LATIN SMALL LETTER Q */ }, \
+	{ 0xA758, /* LATIN CAPITAL LETTER Q WITH DIAGONAL STROKE */ \
+	  0xA759, /* LATIN SMALL LETTER Q WITH DIAGONAL STROKE */ }, \
+	{ 0xA756, /* LATIN CAPITAL LETTER Q WITH STROKE THROUGH DESCENDER */ \
+	  0xA757, /* LATIN SMALL LETTER Q WITH STROKE THROUGH DESCENDER */ }, \
+	{ 0x0052, /* LATIN CAPITAL LETTER R */ \
+	  0x0072, /* LATIN SMALL LETTER R */ }, \
+	{ 0xA75A, /* LATIN CAPITAL LETTER R ROTUNDA */ \
+	  0xA75B, /* LATIN SMALL LETTER R ROTUNDA */ }, \
+	{ 0x0154, /* LATIN CAPITAL LETTER R WITH ACUTE */ \
+	  0x0155, /* LATIN SMALL LETTER R WITH ACUTE */ }, \
+	{ 0x0158, /* LATIN CAPITAL LETTER R WITH CARON */ \
+	  0x0159, /* LATIN SMALL LETTER R WITH CARON */ }, \
+	{ 0x0156, /* LATIN CAPITAL LETTER R WITH CEDILLA */ \
+	  0x0157, /* LATIN SMALL LETTER R WITH CEDILLA */ }, \
+	{ 0x1E58, /* LATIN CAPITAL LETTER R WITH DOT ABOVE */ \
+	  0x1E59, /* LATIN SMALL LETTER R WITH DOT ABOVE */ }, \
+	{ 0x1E5A, /* LATIN CAPITAL LETTER R WITH DOT BELOW */ \
+	  0x1E5B, /* LATIN SMALL LETTER R WITH DOT BELOW */ }, \
+	{ 0x1E5C, /* LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON */ \
+	  0x1E5D, /* LATIN SMALL LETTER R WITH DOT BELOW AND MACRON */ }, \
+	{ 0x0210, /* LATIN CAPITAL LETTER R WITH DOUBLE GRAVE */ \
+	  0x0211, /* LATIN SMALL LETTER R WITH DOUBLE GRAVE */ }, \
+	{ 0x0212, /* LATIN CAPITAL LETTER R WITH INVERTED BREVE */ \
+	  0x0213, /* LATIN SMALL LETTER R WITH INVERTED BREVE */ }, \
+	{ 0x1E5E, /* LATIN CAPITAL LETTER R WITH LINE BELOW */ \
+	  0x1E5F, /* LATIN SMALL LETTER R WITH LINE BELOW */ }, \
+	{ 0xA7A6, /* LATIN CAPITAL LETTER R WITH OBLIQUE STROKE */ \
+	  0xA7A7, /* LATIN SMALL LETTER R WITH OBLIQUE STROKE */ }, \
+	{ 0x024C, /* LATIN CAPITAL LETTER R WITH STROKE */ \
+	  0x024D, /* LATIN SMALL LETTER R WITH STROKE */ }, \
+	{ 0x2C64, /* LATIN CAPITAL LETTER R WITH TAIL */ \
+	  0x027D, /* LATIN SMALL LETTER R WITH TAIL */ }, \
+	{ 0xA73E, /* LATIN CAPITAL LETTER REVERSED C WITH DOT */ \
+	  0xA73F, /* LATIN SMALL LETTER REVERSED C WITH DOT */ }, \
+	{ 0x018E, /* LATIN CAPITAL LETTER REVERSED E */ \
+	  0x0258, /* LATIN SMALL LETTER REVERSED E */ }, \
+	{ 0xA7AB, /* LATIN CAPITAL LETTER REVERSED OPEN E */ \
+	  0x025C, /* LATIN SMALL LETTER REVERSED OPEN E */ }, \
+	{ 0xA75C, /* LATIN CAPITAL LETTER RUM ROTUNDA */ \
+	  0xA75D, /* LATIN SMALL LETTER RUM ROTUNDA */ }, \
+	{ 0x0053, /* LATIN CAPITAL LETTER S */ \
+	  0x0073, /* LATIN SMALL LETTER S */ }, \
+	{ 0x015A, /* LATIN CAPITAL LETTER S WITH ACUTE */ \
+	  0x015B, /* LATIN SMALL LETTER S WITH ACUTE */ }, \
+	{ 0x1E64, /* LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE */ \
+	  0x1E65, /* LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE */ }, \
+	{ 0x0160, /* LATIN CAPITAL LETTER S WITH CARON */ \
+	  0x0161, /* LATIN SMALL LETTER S WITH CARON */ }, \
+	{ 0x1E66, /* LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE */ \
+	  0x1E67, /* LATIN SMALL LETTER S WITH CARON AND DOT ABOVE */ }, \
+	{ 0x015E, /* LATIN CAPITAL LETTER S WITH CEDILLA */ \
+	  0x015F, /* LATIN SMALL LETTER S WITH CEDILLA */ }, \
+	{ 0x015C, /* LATIN CAPITAL LETTER S WITH CIRCUMFLEX */ \
+	  0x015D, /* LATIN SMALL LETTER S WITH CIRCUMFLEX */ }, \
+	{ 0x0218, /* LATIN CAPITAL LETTER S WITH COMMA BELOW */ \
+	  0x0219, /* LATIN SMALL LETTER S WITH COMMA BELOW */ }, \
+	{ 0x1E60, /* LATIN CAPITAL LETTER S WITH DOT ABOVE */ \
+	  0x1E61, /* LATIN SMALL LETTER S WITH DOT ABOVE */ }, \
+	{ 0x1E62, /* LATIN CAPITAL LETTER S WITH DOT BELOW */ \
+	  0x1E63, /* LATIN SMALL LETTER S WITH DOT BELOW */ }, \
+	{ 0x1E68, /* LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE */ \
+	  0x1E69, /* LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE */ }, \
+	{ 0xA7A8, /* LATIN CAPITAL LETTER S WITH OBLIQUE STROKE */ \
+	  0xA7A9, /* LATIN SMALL LETTER S WITH OBLIQUE STROKE */ }, \
+	{ 0x2C7E, /* LATIN CAPITAL LETTER S WITH SWASH TAIL */ \
+	  0x023F, /* LATIN SMALL LETTER S WITH SWASH TAIL */ }, \
+	{ 0xA78B, /* LATIN CAPITAL LETTER SALTILLO */ \
+	  0xA78C, /* LATIN SMALL LETTER SALTILLO */ }, \
+	{ 0x018F, /* LATIN CAPITAL LETTER SCHWA */ \
+	  0x0259, /* LATIN SMALL LETTER SCHWA */ }, \
+	{ 0xA7AC, /* LATIN CAPITAL LETTER SCRIPT G */ \
+	  0x0261, /* LATIN SMALL LETTER SCRIPT G */ }, \
+	{ 0x1E9E, /* LATIN CAPITAL LETTER SHARP S */ \
+	  0x00DF, /* LATIN SMALL LETTER SHARP S */ }, \
+	{ 0x0054, /* LATIN CAPITAL LETTER T */ \
+	  0x0074, /* LATIN SMALL LETTER T */ }, \
+	{ 0x0164, /* LATIN CAPITAL LETTER T WITH CARON */ \
+	  0x0165, /* LATIN SMALL LETTER T WITH CARON */ }, \
+	{ 0x0162, /* LATIN CAPITAL LETTER T WITH CEDILLA */ \
+	  0x0163, /* LATIN SMALL LETTER T WITH CEDILLA */ }, \
+	{ 0x1E70, /* LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW */ \
+	  0x1E71, /* LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW */ }, \
+	{ 0x021A, /* LATIN CAPITAL LETTER T WITH COMMA BELOW */ \
+	  0x021B, /* LATIN SMALL LETTER T WITH COMMA BELOW */ }, \
+	{ 0x023E, /* LATIN CAPITAL LETTER T WITH DIAGONAL STROKE */ \
+	  0x2C66, /* LATIN SMALL LETTER T WITH DIAGONAL STROKE */ }, \
+	{ 0x1E6A, /* LATIN CAPITAL LETTER T WITH DOT ABOVE */ \
+	  0x1E6B, /* LATIN SMALL LETTER T WITH DOT ABOVE */ }, \
+	{ 0x1E6C, /* LATIN CAPITAL LETTER T WITH DOT BELOW */ \
+	  0x1E6D, /* LATIN SMALL LETTER T WITH DOT BELOW */ }, \
+	{ 0x01AC, /* LATIN CAPITAL LETTER T WITH HOOK */ \
+	  0x01AD, /* LATIN SMALL LETTER T WITH HOOK */ }, \
+	{ 0x1E6E, /* LATIN CAPITAL LETTER T WITH LINE BELOW */ \
+	  0x1E6F, /* LATIN SMALL LETTER T WITH LINE BELOW */ }, \
+	{ 0x01AE, /* LATIN CAPITAL LETTER T WITH RETROFLEX HOOK */ \
+	  0x0288, /* LATIN SMALL LETTER T WITH RETROFLEX HOOK */ }, \
+	{ 0x0166, /* LATIN CAPITAL LETTER T WITH STROKE */ \
+	  0x0167, /* LATIN SMALL LETTER T WITH STROKE */ }, \
+	{ 0x00DE, /* LATIN CAPITAL LETTER THORN */ \
+	  0x00FE, /* LATIN SMALL LETTER THORN */ }, \
+	{ 0xA764, /* LATIN CAPITAL LETTER THORN WITH STROKE */ \
+	  0xA765, /* LATIN SMALL LETTER THORN WITH STROKE */ }, \
+	{ 0xA766, /* LATIN CAPITAL LETTER THORN WITH STROKE THROUGH DESCENDER */ \
+	  0xA767, /* LATIN SMALL LETTER THORN WITH STROKE THROUGH DESCENDER */ }, \
+	{ 0x01BC, /* LATIN CAPITAL LETTER TONE FIVE */ \
+	  0x01BD, /* LATIN SMALL LETTER TONE FIVE */ }, \
+	{ 0x0184, /* LATIN CAPITAL LETTER TONE SIX */ \
+	  0x0185, /* LATIN SMALL LETTER TONE SIX */ }, \
+	{ 0x01A7, /* LATIN CAPITAL LETTER TONE TWO */ \
+	  0x01A8, /* LATIN SMALL LETTER TONE TWO */ }, \
+	{ 0xA72A, /* LATIN CAPITAL LETTER TRESILLO */ \
+	  0xA72B, /* LATIN SMALL LETTER TRESILLO */ }, \
+	{ 0x2C6F, /* LATIN CAPITAL LETTER TURNED A */ \
+	  0x0250, /* LATIN SMALL LETTER TURNED A */ }, \
+	{ 0x2C70, /* LATIN CAPITAL LETTER TURNED ALPHA */ \
+	  0x0252, /* LATIN SMALL LETTER TURNED ALPHA */ }, \
+	{ 0xA78D, /* LATIN CAPITAL LETTER TURNED H */ \
+	  0x0265, /* LATIN SMALL LETTER TURNED H */ }, \
+	{ 0xA77E, /* LATIN CAPITAL LETTER TURNED INSULAR G */ \
+	  0xA77F, /* LATIN SMALL LETTER TURNED INSULAR G */ }, \
+	{ 0xA7B0, /* LATIN CAPITAL LETTER TURNED K */ \
+	  0x029E, /* LATIN SMALL LETTER TURNED K */ }, \
+	{ 0xA780, /* LATIN CAPITAL LETTER TURNED L */ \
+	  0xA781, /* LATIN SMALL LETTER TURNED L */ }, \
+	{ 0x019C, /* LATIN CAPITAL LETTER TURNED M */ \
+	  0x026F, /* LATIN SMALL LETTER TURNED M */ }, \
+	{ 0xA7B1, /* LATIN CAPITAL LETTER TURNED T */ \
+	  0x0287, /* LATIN SMALL LETTER TURNED T */ }, \
+	{ 0x0245, /* LATIN CAPITAL LETTER TURNED V */ \
+	  0x028C, /* LATIN SMALL LETTER TURNED V */ }, \
+	{ 0xA728, /* LATIN CAPITAL LETTER TZ */ \
+	  0xA729, /* LATIN SMALL LETTER TZ */ }, \
+	{ 0x0055, /* LATIN CAPITAL LETTER U */ \
+	  0x0075, /* LATIN SMALL LETTER U */ }, \
+	{ 0x0244, /* LATIN CAPITAL LETTER U BAR */ \
+	  0x0289, /* LATIN SMALL LETTER U BAR */ }, \
+	{ 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */ \
+	  0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */ }, \
+	{ 0x016C, /* LATIN CAPITAL LETTER U WITH BREVE */ \
+	  0x016D, /* LATIN SMALL LETTER U WITH BREVE */ }, \
+	{ 0x01D3, /* LATIN CAPITAL LETTER U WITH CARON */ \
+	  0x01D4, /* LATIN SMALL LETTER U WITH CARON */ }, \
+	{ 0x00DB, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX */ \
+	  0x00FB, /* LATIN SMALL LETTER U WITH CIRCUMFLEX */ }, \
+	{ 0x1E76, /* LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW */ \
+	  0x1E77, /* LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW */ }, \
+	{ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \
+	  0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \
+	{ 0x01D7, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE */ \
+	  0x01D8, /* LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE */ }, \
+	{ 0x01D9, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON */ \
+	  0x01DA, /* LATIN SMALL LETTER U WITH DIAERESIS AND CARON */ }, \
+	{ 0x01DB, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE */ \
+	  0x01DC, /* LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE */ }, \
+	{ 0x01D5, /* LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON */ \
+	  0x01D6, /* LATIN SMALL LETTER U WITH DIAERESIS AND MACRON */ }, \
+	{ 0x1E72, /* LATIN CAPITAL LETTER U WITH DIAERESIS BELOW */ \
+	  0x1E73, /* LATIN SMALL LETTER U WITH DIAERESIS BELOW */ }, \
+	{ 0x1EE4, /* LATIN CAPITAL LETTER U WITH DOT BELOW */ \
+	  0x1EE5, /* LATIN SMALL LETTER U WITH DOT BELOW */ }, \
+	{ 0x0170, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ \
+	  0x0171, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ }, \
+	{ 0x0214, /* LATIN CAPITAL LETTER U WITH DOUBLE GRAVE */ \
+	  0x0215, /* LATIN SMALL LETTER U WITH DOUBLE GRAVE */ }, \
+	{ 0x00D9, /* LATIN CAPITAL LETTER U WITH GRAVE */ \
+	  0x00F9, /* LATIN SMALL LETTER U WITH GRAVE */ }, \
+	{ 0x1EE6, /* LATIN CAPITAL LETTER U WITH HOOK ABOVE */ \
+	  0x1EE7, /* LATIN SMALL LETTER U WITH HOOK ABOVE */ }, \
+	{ 0x01AF, /* LATIN CAPITAL LETTER U WITH HORN */ \
+	  0x01B0, /* LATIN SMALL LETTER U WITH HORN */ }, \
+	{ 0x1EE8, /* LATIN CAPITAL LETTER U WITH HORN AND ACUTE */ \
+	  0x1EE9, /* LATIN SMALL LETTER U WITH HORN AND ACUTE */ }, \
+	{ 0x1EF0, /* LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW */ \
+	  0x1EF1, /* LATIN SMALL LETTER U WITH HORN AND DOT BELOW */ }, \
+	{ 0x1EEA, /* LATIN CAPITAL LETTER U WITH HORN AND GRAVE */ \
+	  0x1EEB, /* LATIN SMALL LETTER U WITH HORN AND GRAVE */ }, \
+	{ 0x1EEC, /* LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE */ \
+	  0x1EED, /* LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE */ }, \
+	{ 0x1EEE, /* LATIN CAPITAL LETTER U WITH HORN AND TILDE */ \
+	  0x1EEF, /* LATIN SMALL LETTER U WITH HORN AND TILDE */ }, \
+	{ 0x0216, /* LATIN CAPITAL LETTER U WITH INVERTED BREVE */ \
+	  0x0217, /* LATIN SMALL LETTER U WITH INVERTED BREVE */ }, \
+	{ 0x016A, /* LATIN CAPITAL LETTER U WITH MACRON */ \
+	  0x016B, /* LATIN SMALL LETTER U WITH MACRON */ }, \
+	{ 0x1E7A, /* LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS */ \
+	  0x1E7B, /* LATIN SMALL LETTER U WITH MACRON AND DIAERESIS */ }, \
+	{ 0x0172, /* LATIN CAPITAL LETTER U WITH OGONEK */ \
+	  0x0173, /* LATIN SMALL LETTER U WITH OGONEK */ }, \
+	{ 0x016E, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ \
+	  0x016F, /* LATIN SMALL LETTER U WITH RING ABOVE */ }, \
+	{ 0xA7B8, /* LATIN CAPITAL LETTER U WITH STROKE */ \
+	  0xA7B9, /* LATIN SMALL LETTER U WITH STROKE */ }, \
+	{ 0x0168, /* LATIN CAPITAL LETTER U WITH TILDE */ \
+	  0x0169, /* LATIN SMALL LETTER U WITH TILDE */ }, \
+	{ 0x1E78, /* LATIN CAPITAL LETTER U WITH TILDE AND ACUTE */ \
+	  0x1E79, /* LATIN SMALL LETTER U WITH TILDE AND ACUTE */ }, \
+	{ 0x1E74, /* LATIN CAPITAL LETTER U WITH TILDE BELOW */ \
+	  0x1E75, /* LATIN SMALL LETTER U WITH TILDE BELOW */ }, \
+	{ 0x01B1, /* LATIN CAPITAL LETTER UPSILON */ \
+	  0x028A, /* LATIN SMALL LETTER UPSILON */ }, \
+	{ 0x0056, /* LATIN CAPITAL LETTER V */ \
+	  0x0076, /* LATIN SMALL LETTER V */ }, \
+	{ 0xA75E, /* LATIN CAPITAL LETTER V WITH DIAGONAL STROKE */ \
+	  0xA75F, /* LATIN SMALL LETTER V WITH DIAGONAL STROKE */ }, \
+	{ 0x1E7E, /* LATIN CAPITAL LETTER V WITH DOT BELOW */ \
+	  0x1E7F, /* LATIN SMALL LETTER V WITH DOT BELOW */ }, \
+	{ 0x01B2, /* LATIN CAPITAL LETTER V WITH HOOK */ \
+	  0x028B, /* LATIN SMALL LETTER V WITH HOOK */ }, \
+	{ 0x1E7C, /* LATIN CAPITAL LETTER V WITH TILDE */ \
+	  0x1E7D, /* LATIN SMALL LETTER V WITH TILDE */ }, \
+	{ 0xA768, /* LATIN CAPITAL LETTER VEND */ \
+	  0xA769, /* LATIN SMALL LETTER VEND */ }, \
+	{ 0xA762, /* LATIN CAPITAL LETTER VISIGOTHIC Z */ \
+	  0xA763, /* LATIN SMALL LETTER VISIGOTHIC Z */ }, \
+	{ 0xA79A, /* LATIN CAPITAL LETTER VOLAPUK AE */ \
+	  0xA79B, /* LATIN SMALL LETTER VOLAPUK AE */ }, \
+	{ 0xA79C, /* LATIN CAPITAL LETTER VOLAPUK OE */ \
+	  0xA79D, /* LATIN SMALL LETTER VOLAPUK OE */ }, \
+	{ 0xA79E, /* LATIN CAPITAL LETTER VOLAPUK UE */ \
+	  0xA79F, /* LATIN SMALL LETTER VOLAPUK UE */ }, \
+	{ 0xA760, /* LATIN CAPITAL LETTER VY */ \
+	  0xA761, /* LATIN SMALL LETTER VY */ }, \
+	{ 0x0057, /* LATIN CAPITAL LETTER W */ \
+	  0x0077, /* LATIN SMALL LETTER W */ }, \
+	{ 0x1E82, /* LATIN CAPITAL LETTER W WITH ACUTE */ \
+	  0x1E83, /* LATIN SMALL LETTER W WITH ACUTE */ }, \
+	{ 0x0174, /* LATIN CAPITAL LETTER W WITH CIRCUMFLEX */ \
+	  0x0175, /* LATIN SMALL LETTER W WITH CIRCUMFLEX */ }, \
+	{ 0x1E84, /* LATIN CAPITAL LETTER W WITH DIAERESIS */ \
+	  0x1E85, /* LATIN SMALL LETTER W WITH DIAERESIS */ }, \
+	{ 0x1E86, /* LATIN CAPITAL LETTER W WITH DOT ABOVE */ \
+	  0x1E87, /* LATIN SMALL LETTER W WITH DOT ABOVE */ }, \
+	{ 0x1E88, /* LATIN CAPITAL LETTER W WITH DOT BELOW */ \
+	  0x1E89, /* LATIN SMALL LETTER W WITH DOT BELOW */ }, \
+	{ 0x1E80, /* LATIN CAPITAL LETTER W WITH GRAVE */ \
+	  0x1E81, /* LATIN SMALL LETTER W WITH GRAVE */ }, \
+	{ 0x2C72, /* LATIN CAPITAL LETTER W WITH HOOK */ \
+	  0x2C73, /* LATIN SMALL LETTER W WITH HOOK */ }, \
+	{ 0x0058, /* LATIN CAPITAL LETTER X */ \
+	  0x0078, /* LATIN SMALL LETTER X */ }, \
+	{ 0x1E8C, /* LATIN CAPITAL LETTER X WITH DIAERESIS */ \
+	  0x1E8D, /* LATIN SMALL LETTER X WITH DIAERESIS */ }, \
+	{ 0x1E8A, /* LATIN CAPITAL LETTER X WITH DOT ABOVE */ \
+	  0x1E8B, /* LATIN SMALL LETTER X WITH DOT ABOVE */ }, \
+	{ 0x0059, /* LATIN CAPITAL LETTER Y */ \
+	  0x0079, /* LATIN SMALL LETTER Y */ }, \
+	{ 0x00DD, /* LATIN CAPITAL LETTER Y WITH ACUTE */ \
+	  0x00FD, /* LATIN SMALL LETTER Y WITH ACUTE */ }, \
+	{ 0x0176, /* LATIN CAPITAL LETTER Y WITH CIRCUMFLEX */ \
+	  0x0177, /* LATIN SMALL LETTER Y WITH CIRCUMFLEX */ }, \
+	{ 0x0178, /* LATIN CAPITAL LETTER Y WITH DIAERESIS */ \
+	  0x00FF, /* LATIN SMALL LETTER Y WITH DIAERESIS */ }, \
+	{ 0x1E8E, /* LATIN CAPITAL LETTER Y WITH DOT ABOVE */ \
+	  0x1E8F, /* LATIN SMALL LETTER Y WITH DOT ABOVE */ }, \
+	{ 0x1EF4, /* LATIN CAPITAL LETTER Y WITH DOT BELOW */ \
+	  0x1EF5, /* LATIN SMALL LETTER Y WITH DOT BELOW */ }, \
+	{ 0x1EF2, /* LATIN CAPITAL LETTER Y WITH GRAVE */ \
+	  0x1EF3, /* LATIN SMALL LETTER Y WITH GRAVE */ }, \
+	{ 0x01B3, /* LATIN CAPITAL LETTER Y WITH HOOK */ \
+	  0x01B4, /* LATIN SMALL LETTER Y WITH HOOK */ }, \
+	{ 0x1EF6, /* LATIN CAPITAL LETTER Y WITH HOOK ABOVE */ \
+	  0x1EF7, /* LATIN SMALL LETTER Y WITH HOOK ABOVE */ }, \
+	{ 0x1EFE, /* LATIN CAPITAL LETTER Y WITH LOOP */ \
+	  0x1EFF, /* LATIN SMALL LETTER Y WITH LOOP */ }, \
+	{ 0x0232, /* LATIN CAPITAL LETTER Y WITH MACRON */ \
+	  0x0233, /* LATIN SMALL LETTER Y WITH MACRON */ }, \
+	{ 0x024E, /* LATIN CAPITAL LETTER Y WITH STROKE */ \
+	  0x024F, /* LATIN SMALL LETTER Y WITH STROKE */ }, \
+	{ 0x1EF8, /* LATIN CAPITAL LETTER Y WITH TILDE */ \
+	  0x1EF9, /* LATIN SMALL LETTER Y WITH TILDE */ }, \
+	{ 0x021C, /* LATIN CAPITAL LETTER YOGH */ \
+	  0x021D, /* LATIN SMALL LETTER YOGH */ }, \
+	{ 0x005A, /* LATIN CAPITAL LETTER Z */ \
+	  0x007A, /* LATIN SMALL LETTER Z */ }, \
+	{ 0x0179, /* LATIN CAPITAL LETTER Z WITH ACUTE */ \
+	  0x017A, /* LATIN SMALL LETTER Z WITH ACUTE */ }, \
+	{ 0x017D, /* LATIN CAPITAL LETTER Z WITH CARON */ \
+	  0x017E, /* LATIN SMALL LETTER Z WITH CARON */ }, \
+	{ 0x1E90, /* LATIN CAPITAL LETTER Z WITH CIRCUMFLEX */ \
+	  0x1E91, /* LATIN SMALL LETTER Z WITH CIRCUMFLEX */ }, \
+	{ 0x2C6B, /* LATIN CAPITAL LETTER Z WITH DESCENDER */ \
+	  0x2C6C, /* LATIN SMALL LETTER Z WITH DESCENDER */ }, \
+	{ 0x017B, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ \
+	  0x017C, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ }, \
+	{ 0x1E92, /* LATIN CAPITAL LETTER Z WITH DOT BELOW */ \
+	  0x1E93, /* LATIN SMALL LETTER Z WITH DOT BELOW */ }, \
+	{ 0x0224, /* LATIN CAPITAL LETTER Z WITH HOOK */ \
+	  0x0225, /* LATIN SMALL LETTER Z WITH HOOK */ }, \
+	{ 0x1E94, /* LATIN CAPITAL LETTER Z WITH LINE BELOW */ \
+	  0x1E95, /* LATIN SMALL LETTER Z WITH LINE BELOW */ }, \
+	{ 0x01B5, /* LATIN CAPITAL LETTER Z WITH STROKE */ \
+	  0x01B6, /* LATIN SMALL LETTER Z WITH STROKE */ }, \
+	{ 0x2C7F, /* LATIN CAPITAL LETTER Z WITH SWASH TAIL */ \
+	  0x0240, /* LATIN SMALL LETTER Z WITH SWASH TAIL */ }, \
+	{ 0x0000, /* END OF LIST CAPITAL LETTERS */ \
+	  0x0000, /* END OF LIST SMALL LETTERS */ }, \
+}
+
+/*
+ * Correspondence table for small and capital letters of codepage 437.
+ * Letters A-Z are handled in code.
+ */
+#define CP437_CAPITALIZATION_TABLE { \
+	{ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \
+	  0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \
+	{ 0x00C5, /* LATIN CAPITAL LETTER A WITH RING ABOVE */ \
+	  0x00E5, /* LATIN SMALL LETTER A WITH RING ABOVE */ }, \
+	{ 0x00C6, /* LATIN CAPITAL LETTER AE */ \
+	  0x00E6, /* LATIN SMALL LETTER AE */ }, \
+	{ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \
+	  0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \
+	{ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \
+	  0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \
+	{ 0x00D1, /* LATIN CAPITAL LETTER N WITH TILDE */ \
+	  0x00F1, /* LATIN SMALL LETTER N WITH TILDE */ }, \
+	{ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \
+	  0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \
+	{ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \
+	  0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \
+	{ 0x03A3, /* GREEK CAPITAL LETTER SIGMA */ \
+	  0x03C3, /* GREEK SMALL LETTER SIGMA */ }, \
+	{ 0x03A6, /* GREEK CAPITAL LETTER PHI */ \
+	  0x03C6, /* GREEK SMALL LETTER PHI */ }, \
+	{ 0x0000, 0x0000, }, \
+}
+
+/*
+ * Correspondence table for small and capital letters of codepage 1250.
+ * Letters A-Z are handled in code.
+ */
+#define CP1250_CAPITALIZATION_TABLE { \
+	{ 0x00C1, /* LATIN CAPITAL LETTER A WITH ACUTE */ \
+	  0x00E1, /* LATIN SMALL LETTER A WITH ACUTE */ }, \
+	{ 0x00C2, /* LATIN CAPITAL LETTER A WITH CIRCUMFLEX */ \
+	  0x00E2, /* LATIN SMALL LETTER A WITH CIRCUMFLEX */ }, \
+	{ 0x00C4, /* LATIN CAPITAL LETTER A WITH DIAERESIS */ \
+	  0x00E4, /* LATIN SMALL LETTER A WITH DIAERESIS */ }, \
+	{ 0x00C7, /* LATIN CAPITAL LETTER C WITH CEDILLA */ \
+	  0x00E7, /* LATIN SMALL LETTER C WITH CEDILLA */ }, \
+	{ 0x00C9, /* LATIN CAPITAL LETTER E WITH ACUTE */ \
+	  0x00E9, /* LATIN SMALL LETTER E WITH ACUTE */ }, \
+	{ 0x00CB, /* LATIN CAPITAL LETTER E WITH DIAERESIS */ \
+	  0x00EB, /* LATIN SMALL LETTER E WITH DIAERESIS */ }, \
+	{ 0x00CD, /* LATIN CAPITAL LETTER I WITH ACUTE */ \
+	  0x00ED, /* LATIN SMALL LETTER I WITH ACUTE */ }, \
+	{ 0x00CE, /* LATIN CAPITAL LETTER I WITH CIRCUMFLEX */ \
+	  0x00EE, /* LATIN SMALL LETTER I WITH CIRCUMFLEX */ }, \
+	{ 0x00D3, /* LATIN CAPITAL LETTER O WITH ACUTE */ \
+	  0x00F3, /* LATIN SMALL LETTER O WITH ACUTE */ }, \
+	{ 0x00D4, /* LATIN CAPITAL LETTER O WITH CIRCUMFLEX */ \
+	  0x00F4, /* LATIN SMALL LETTER O WITH CIRCUMFLEX */ }, \
+	{ 0x00D6, /* LATIN CAPITAL LETTER O WITH DIAERESIS */ \
+	  0x00F6, /* LATIN SMALL LETTER O WITH DIAERESIS */ }, \
+	{ 0x00DA, /* LATIN CAPITAL LETTER U WITH ACUTE */ \
+	  0x00FA, /* LATIN SMALL LETTER U WITH ACUTE */ }, \
+	{ 0x00DC, /* LATIN CAPITAL LETTER U WITH DIAERESIS */ \
+	  0x00FC, /* LATIN SMALL LETTER U WITH DIAERESIS */ }, \
+	{ 0x00DD, /* LATIN CAPITAL LETTER Y WITH ACUTE */ \
+	  0x00FD, /* LATIN SMALL LETTER Y WITH ACUTE */ }, \
+	{ 0x0102, /* LATIN CAPITAL LETTER A WITH BREVE */ \
+	  0x0103, /* LATIN SMALL LETTER A WITH BREVE */ }, \
+	{ 0x0104, /* LATIN CAPITAL LETTER A WITH OGONEK */ \
+	  0x0105, /* LATIN SMALL LETTER A WITH OGONEK */ }, \
+	{ 0x0106, /* LATIN CAPITAL LETTER C WITH ACUTE */ \
+	  0x0107, /* LATIN SMALL LETTER C WITH ACUTE */ }, \
+	{ 0x010C, /* LATIN CAPITAL LETTER C WITH CARON */ \
+	  0x010D, /* LATIN SMALL LETTER C WITH CARON */ }, \
+	{ 0x010E, /* LATIN CAPITAL LETTER D WITH CARON */ \
+	  0x010F, /* LATIN SMALL LETTER D WITH CARON */ }, \
+	{ 0x0110, /* LATIN CAPITAL LETTER D WITH STROKE */ \
+	  0x0111, /* LATIN SMALL LETTER D WITH STROKE */ }, \
+	{ 0x0118, /* LATIN CAPITAL LETTER E WITH OGONEK */ \
+	  0x0119, /* LATIN SMALL LETTER E WITH OGONEK */ }, \
+	{ 0x011A, /* LATIN CAPITAL LETTER E WITH CARON */ \
+	  0x011B, /* LATIN SMALL LETTER E WITH CARON */ }, \
+	{ 0x0139, /* LATIN CAPITAL LETTER L WITH ACUTE */ \
+	  0x013A, /* LATIN SMALL LETTER L WITH ACUTE */ }, \
+	{ 0x013D, /* LATIN CAPITAL LETTER L WITH CARON */ \
+	  0x013E, /* LATIN SMALL LETTER L WITH CARON */ }, \
+	{ 0x0141, /* LATIN CAPITAL LETTER L WITH STROKE */ \
+	  0x0142, /* LATIN SMALL LETTER L WITH STROKE */ }, \
+	{ 0x0143, /* LATIN CAPITAL LETTER N WITH ACUTE */ \
+	  0x0144, /* LATIN SMALL LETTER N WITH ACUTE */ }, \
+	{ 0x0147, /* LATIN CAPITAL LETTER N WITH CARON */ \
+	  0x0148, /* LATIN SMALL LETTER N WITH CARON */ }, \
+	{ 0x0150, /* LATIN CAPITAL LETTER O WITH DOUBLE ACUTE */ \
+	  0x0151, /* LATIN SMALL LETTER O WITH DOUBLE ACUTE */ }, \
+	{ 0x0154, /* LATIN CAPITAL LETTER R WITH ACUTE */ \
+	  0x0155, /* LATIN SMALL LETTER R WITH ACUTE */ }, \
+	{ 0x0158, /* LATIN CAPITAL LETTER R WITH CARON */ \
+	  0x0159, /* LATIN SMALL LETTER R WITH CARON */ }, \
+	{ 0x015A, /* LATIN CAPITAL LETTER S WITH ACUTE */ \
+	  0x015B, /* LATIN SMALL LETTER S WITH ACUTE */ }, \
+	{ 0x015E, /* LATIN CAPITAL LETTER S WITH CEDILLA */ \
+	  0x015F, /* LATIN SMALL LETTER S WITH CEDILLA */ }, \
+	{ 0x0160, /* LATIN CAPITAL LETTER S WITH CARON */ \
+	  0x0161, /* LATIN SMALL LETTER S WITH CARON */ }, \
+	{ 0x0162, /* LATIN CAPITAL LETTER T WITH CEDILLA */ \
+	  0x0163, /* LATIN SMALL LETTER T WITH CEDILLA */ }, \
+	{ 0x0164, /* LATIN CAPITAL LETTER T WITH CARON */ \
+	  0x0165, /* LATIN SMALL LETTER T WITH CARON */ }, \
+	{ 0x016E, /* LATIN CAPITAL LETTER U WITH RING ABOVE */ \
+	  0x016F, /* LATIN SMALL LETTER U WITH RING ABOVE */ }, \
+	{ 0x0170, /* LATIN CAPITAL LETTER U WITH DOUBLE ACUTE */ \
+	  0x0171, /* LATIN SMALL LETTER U WITH DOUBLE ACUTE */ }, \
+	{ 0x0179, /* LATIN CAPITAL LETTER Z WITH ACUTE */ \
+	  0x017A, /* LATIN SMALL LETTER Z WITH ACUTE */ }, \
+	{ 0x017B, /* LATIN CAPITAL LETTER Z WITH DOT ABOVE */ \
+	  0x017C, /* LATIN SMALL LETTER Z WITH DOT ABOVE */ }, \
+	{ 0x017D, /* LATIN CAPITAL LETTER Z WITH CARON */ \
+	  0x017E, /* LATIN SMALL LETTER Z WITH CARON */ }, \
+	{ 0x0000, 0x0000, }, \
+}
diff --git a/include/charset.h b/include/charset.h
index 11832cb..4d45e24 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -8,46 +8,190 @@
 #ifndef __CHARSET_H_
 #define __CHARSET_H_
 
+#include <linux/kernel.h>
 #include <linux/types.h>
 
 #define MAX_UTF8_PER_UTF16 3
 
 /**
- * utf16_strlen() - Get the length of an utf16 string
+ * console_read_unicode() - read Unicode code point from console
  *
- * Returns the number of 16 bit characters in an utf16 string, not
- * including the terminating NULL character.
+ * @code:	pointer to store Unicode code point
+ * Return:	0 = success
+ */
+int console_read_unicode(s32 *code);
+
+/**
+ * utf8_get() - get next UTF-8 code point from buffer
+ *
+ * @src:		pointer to current byte, updated to point to next byte
+ * Return:		code point, or 0 for end of string, or -1 if no legal
+ *			code point is found. In case of an error src points to
+ *			the incorrect byte.
+ */
+s32 utf8_get(const char **src);
+
+/**
+ * utf8_put() - write UTF-8 code point to buffer
+ *
+ * @code:		code point
+ * @dst:		pointer to destination buffer, updated to next position
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf8_put(s32 code, char **dst);
+
+/**
+ * utf8_utf16_strnlen() - length of a truncated utf-8 string after conversion
+ *			  to utf-16
+ *
+ * @src:		utf-8 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in bytes after conversion to utf-16 without the
+ *			trailing \0. If an invalid UTF-8 sequence is hit one
+ *			word will be reserved for a replacement character.
+ */
+size_t utf8_utf16_strnlen(const char *src, size_t count);
+
+/**
+ * utf8_utf16_strlen() - length of a utf-8 string after conversion to utf-16
+ *
+ * @src:		utf-8 string
+ * Return:		length in bytes after conversion to utf-16 without the
+ *			trailing \0. -1 if the utf-8 string is not valid.
+ */
+#define utf8_utf16_strlen(a) utf8_utf16_strnlen((a), SIZE_MAX)
+
+/**
+ * utf8_utf16_strncpy() - copy utf-8 string to utf-16 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * @count:		maximum number of code points to copy
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count);
+
+/**
+ * utf8_utf16_strcpy() - copy utf-8 string to utf-16 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * Return:		-1 if the input parameters are invalid
+ */
+#define utf8_utf16_strcpy(d, s) utf8_utf16_strncpy((d), (s), SIZE_MAX)
+
+/**
+ * utf16_get() - get next UTF-16 code point from buffer
+ *
+ * @src:		pointer to current word, updated to point to next word
+ * Return:		code point, or 0 for end of string, or -1 if no legal
+ *			code point is found. In case of an error src points to
+ *			the incorrect word.
+ */
+s32 utf16_get(const u16 **src);
+
+/**
+ * utf16_put() - write UTF-16 code point to buffer
+ *
+ * @code:		code point
+ * @dst:		pointer to destination buffer, updated to next position
+ * Return:		-1 if the input parameters are invalid
+ */
+int utf16_put(s32 code, u16 **dst);
+
+/**
+ * utf16_strnlen() - length of a truncated utf-16 string
  *
- * @in     the string to measure
- * @return the string length
+ * @src:		utf-16 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in code points. If an invalid UTF-16 sequence is
+ *			hit one position will be reserved for a replacement
+ *			character.
  */
-size_t utf16_strlen(const uint16_t *in);
+size_t utf16_strnlen(const u16 *src, size_t count);
 
 /**
- * utf16_strnlen() - Get the length of a fixed-size utf16 string.
+ * utf16_utf8_strnlen() - length of a truncated utf-16 string after conversion
+ *			  to utf-8
  *
- * Returns the number of 16 bit characters in an utf16 string,
- * not including the terminating NULL character, but at most
- * 'count' number of characters.  In doing this, utf16_strnlen()
- * looks at only the first 'count' characters.
+ * @src:		utf-16 string
+ * @count:		maximum number of code points to convert
+ * Return:		length in bytes after conversion to utf-8 without the
+ *			trailing \0. If an invalid UTF-16 sequence is hit one
+ *			byte will be reserved for a replacement character.
+ */
+size_t utf16_utf8_strnlen(const u16 *src, size_t count);
+
+/**
+ * utf16_utf8_strlen() - length of a utf-16 string after conversion to utf-8
  *
- * @in     the string to measure
- * @count  the maximum number of characters to count
- * @return the string length, up to a maximum of 'count'
+ * @src:		utf-16 string
+ * Return:		length in bytes after conversion to utf-8 without the
+ *			trailing \0. -1 if the utf-16 string is not valid.
  */
-size_t utf16_strnlen(const uint16_t *in, size_t count);
+#define utf16_utf8_strlen(a) utf16_utf8_strnlen((a), SIZE_MAX)
 
 /**
- * utf16_strcpy() - UTF16 equivalent of strcpy()
+ * utf16_utf8_strncpy() - copy utf-16 string to utf-8 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * @count:		maximum number of code points to copy
+ * Return:		-1 if the input parameters are invalid
  */
-uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src);
+int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count);
 
 /**
- * utf16_strdup() - UTF16 equivalent of strdup()
+ * utf16_utf8_strcpy() - copy utf-16 string to utf-8 string
+ *
+ * @dst:		destination buffer
+ * @src:		source buffer
+ * Return:		-1 if the input parameters are invalid
  */
-uint16_t *utf16_strdup(const uint16_t *s);
+#define utf16_utf8_strcpy(d, s) utf16_utf8_strncpy((d), (s), SIZE_MAX)
 
 /**
+ * utf_to_lower() - convert a Unicode letter to lower case
+ *
+ * @code:		letter to convert
+ * Return:		lower case letter or unchanged letter
+ */
+s32 utf_to_lower(const s32 code);
+
+/**
+ * utf_to_upper() - convert a Unicode letter to upper case
+ *
+ * @code:		letter to convert
+ * Return:		upper case letter or unchanged letter
+ */
+s32 utf_to_upper(const s32 code);
+
+/**
+ * u16_strlen - count non-zero words
+ *
+ * This function matches wsclen() if the -fshort-wchar compiler flag is set.
+ * In the EFI context we explicitly need a function handling u16 strings.
+ *
+ * @in:			null terminated u16 string
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
+ */
+size_t u16_strlen(const u16 *in);
+
+/**
+ * u16_strlen - count non-zero words
+ *
+ * This function matches wscnlen_s() if the -fshort-wchar compiler flag is set.
+ * In the EFI context we explicitly need a function handling u16 strings.
+ *
+ * @in:			null terminated u16 string
+ * @count:		maximum number of words to count
+ * ReturnValue:		number of non-zero words.
+ *			This is not the number of utf-16 letters!
+ */
+size_t u16_strnlen(const u16 *in, size_t count);
+
+/**
  * utf16_to_utf8() - Convert an utf16 string to utf8
  *
  * Converts 'size' characters of the utf16 string 'src' to utf8
@@ -63,17 +207,4 @@
  */
 uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size);
 
-/**
- * utf8_to_utf16() - Convert an utf8 string to utf16
- *
- * Converts up to 'size' characters of the utf16 string 'src' to utf8
- * written to the 'dest' buffer. Stops at 0x00.
- *
- * @dest   the destination buffer to write the utf8 characters
- * @src    the source utf16 string
- * @size   maximum number of utf16 characters to convert
- * @return the pointer to the first unwritten byte in 'dest'
- */
-uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size);
-
 #endif /* __CHARSET_H_ */
diff --git a/include/config_distro_bootcmd.h b/include/config_distro_bootcmd.h
index d672e8e..373fee7 100644
--- a/include/config_distro_bootcmd.h
+++ b/include/config_distro_bootcmd.h
@@ -245,22 +245,26 @@
 #if defined(CONFIG_CMD_DHCP)
 #if defined(CONFIG_EFI_LOADER)
 /* http://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xml */
-#if defined(CONFIG_ARM64)
+#if defined(CONFIG_ARM64) || defined(__aarch64__)
 #define BOOTENV_EFI_PXE_ARCH "0xb"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00011:UNDI:003000"
-#elif defined(CONFIG_ARM)
+#elif defined(CONFIG_ARM) || defined(__arm__)
 #define BOOTENV_EFI_PXE_ARCH "0xa"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00010:UNDI:003000"
-#elif defined(CONFIG_X86)
-/* Always assume we're running 64bit */
+#elif defined(CONFIG_X86) || defined(__x86_64__)
 #define BOOTENV_EFI_PXE_ARCH "0x7"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00007:UNDI:003000"
-#elif defined(CONFIG_CPU_RISCV_32)
+#elif defined(__i386__)
+#define BOOTENV_EFI_PXE_ARCH "0x6"
+#define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00006:UNDI:003000"
+#elif defined(CONFIG_CPU_RISCV_32) || ((defined(__riscv) && __riscv_xlen == 32))
 #define BOOTENV_EFI_PXE_ARCH "0x19"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00025:UNDI:003000"
-#elif defined(CONFIG_CPU_RISCV_64)
+#elif defined(CONFIG_CPU_RISCV_64) || ((defined(__riscv) && __riscv_xlen == 64))
 #define BOOTENV_EFI_PXE_ARCH "0x1b"
 #define BOOTENV_EFI_PXE_VCI "PXEClient:Arch:00027:UNDI:003000"
+#elif defined(CONFIG_SANDBOX)
+# error "sandbox EFI support is only supported on ARM and x86"
 #else
 #error Please specify an EFI client identifier
 #endif
diff --git a/include/configs/MPC8544DS.h b/include/configs/MPC8544DS.h
index 2568e95..d825f0f 100644
--- a/include/configs/MPC8544DS.h
+++ b/include/configs/MPC8544DS.h
@@ -280,8 +280,7 @@
 #define CONFIG_SYS_SCSI_MAX_SCSI_ID	4
 #define CONFIG_SYS_SCSI_MAX_LUN	1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_SYS_SCSI_MAXDEVICE	CONFIG_SYS_SCSI_MAX_DEVICE
-#endif /* SCSCI */
+#endif /* CONFIG_SCSI_AHCI */
 
 #endif	/* CONFIG_PCI */
 
diff --git a/include/configs/MPC8572DS.h b/include/configs/MPC8572DS.h
index 8c92c3f..dd081e8 100644
--- a/include/configs/MPC8572DS.h
+++ b/include/configs/MPC8572DS.h
@@ -464,7 +464,6 @@
 #define CONFIG_SYS_SCSI_MAX_SCSI_ID	4
 #define CONFIG_SYS_SCSI_MAX_LUN	1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_SYS_SCSI_MAXDEVICE	CONFIG_SYS_SCSI_MAX_DEVICE
 #endif /* SCSI */
 
 #endif	/* CONFIG_PCI */
diff --git a/include/configs/MPC8610HPCD.h b/include/configs/MPC8610HPCD.h
index cfb7135..02fd864 100644
--- a/include/configs/MPC8610HPCD.h
+++ b/include/configs/MPC8610HPCD.h
@@ -278,7 +278,6 @@
 #define CONFIG_SYS_SCSI_MAX_SCSI_ID	4
 #define CONFIG_SYS_SCSI_MAX_LUN	1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_SYS_SCSI_MAXDEVICE	CONFIG_SYS_SCSI_MAX_DEVICE
 #endif
 
 #endif	/* CONFIG_PCI */
diff --git a/include/configs/MPC8641HPCN.h b/include/configs/MPC8641HPCN.h
index 68bc710..bc69efb 100644
--- a/include/configs/MPC8641HPCN.h
+++ b/include/configs/MPC8641HPCN.h
@@ -373,7 +373,6 @@
 #define CONFIG_SYS_SCSI_MAX_SCSI_ID	4
 #define CONFIG_SYS_SCSI_MAX_LUN	1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_SYS_SCSI_MAXDEVICE	CONFIG_SYS_SCSI_MAX_DEVICE
 #endif
 
 #endif	/* CONFIG_PCI */
diff --git a/include/configs/da850evm.h b/include/configs/da850evm.h
index 14a6b9e..319f6aa 100644
--- a/include/configs/da850evm.h
+++ b/include/configs/da850evm.h
@@ -116,7 +116,7 @@
  * Serial Driver info
  */
 
-#if defined(CONFIG_SPL_BUILD) || defined(CONFIG_DIRECT_NOR_BOOT)
+#if !CONFIG_IS_ENABLED(DM_SERIAL)
 #define CONFIG_SYS_NS16550_SERIAL
 #define CONFIG_SYS_NS16550_REG_SIZE	-4	/* NS16550 register size */
 #define CONFIG_SYS_NS16550_COM1	DAVINCI_UART2_BASE /* Base address of UART2 */
diff --git a/include/configs/dra7xx_evm.h b/include/configs/dra7xx_evm.h
index fcaf3a1..d8d6d2f 100644
--- a/include/configs/dra7xx_evm.h
+++ b/include/configs/dra7xx_evm.h
@@ -113,10 +113,6 @@
 
 /* SATA */
 #define CONFIG_SCSI_AHCI_PLAT
-#define CONFIG_SYS_SCSI_MAX_SCSI_ID	1
-#define CONFIG_SYS_SCSI_MAX_LUN		1
-#define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
-						CONFIG_SYS_SCSI_MAX_LUN)
 
 /* NAND support */
 #ifdef CONFIG_NAND
diff --git a/include/configs/gardena-smart-gateway-mt7688.h b/include/configs/gardena-smart-gateway-mt7688.h
new file mode 100644
index 0000000..0184147
--- /dev/null
+++ b/include/configs/gardena-smart-gateway-mt7688.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#ifndef __CONFIG_GARDENA_SMART_GATEWAY_H
+#define __CONFIG_GARDENA_SMART_GATEWAY_H
+
+/* CPU */
+#define CONFIG_SYS_MIPS_TIMER_FREQ	200000000
+
+/* RAM */
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+
+#define CONFIG_SYS_LOAD_ADDR		CONFIG_SYS_SDRAM_BASE + 0x100000
+
+#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+
+#ifdef CONFIG_BOOT_RAM
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+
+/* UART */
+#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
+					  230400, 500000, 1500000 }
+
+/* RAM */
+#define CONFIG_SYS_MEMTEST_START	0x80100000
+#define CONFIG_SYS_MEMTEST_END		0x80400000
+
+/* Memory usage */
+#define CONFIG_SYS_MAXARGS		64
+#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
+#define CONFIG_SYS_CBSIZE		512
+
+/* U-Boot */
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+/* Environment settings */
+#define CONFIG_ENV_OFFSET		0x80000
+#define CONFIG_ENV_SIZE			(64 << 10)
+#define CONFIG_ENV_SECT_SIZE		(64 << 10)
+#define CONFIG_SYS_REDUNDAND_ENVIRONMENT
+#define CONFIG_ENV_OFFSET_REDUND	(CONFIG_ENV_OFFSET + \
+						CONFIG_ENV_SECT_SIZE)
+#define CONFIG_ENV_SIZE_REDUND		CONFIG_ENV_SIZE
+
+/*
+ * Environment is right behind U-Boot in flash. Make sure U-Boot
+ * doesn't grow into the environment area.
+ */
+#define CONFIG_BOARD_SIZE_LIMIT		CONFIG_ENV_OFFSET
+
+#endif /* __CONFIG_GARDENA_SMART_GATEWAY_H */
diff --git a/include/configs/imgtec_xilfpga.h b/include/configs/imgtec_xilfpga.h
index 29b23fa..8e2d723 100644
--- a/include/configs/imgtec_xilfpga.h
+++ b/include/configs/imgtec_xilfpga.h
@@ -19,9 +19,6 @@
 /* CPU Timer rate */
 #define CONFIG_SYS_MIPS_TIMER_FREQ	50000000
 
-/* Cache Configuration */
-#define CONFIG_SYS_MIPS_CACHE_MODE	CONF_CM_CACHABLE_NONCOHERENT
-
 /*----------------------------------------------------------------------
  * Memory Layout
  */
diff --git a/include/configs/linkit-smart-7688.h b/include/configs/linkit-smart-7688.h
new file mode 100644
index 0000000..78efa23
--- /dev/null
+++ b/include/configs/linkit-smart-7688.h
@@ -0,0 +1,51 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * Copyright (C) 2018 Stefan Roese <sr@denx.de>
+ */
+
+#ifndef __CONFIG_LINKIT_SMART_7688_H
+#define __CONFIG_LINKIT_SMART_7688_H
+
+/* CPU */
+#define CONFIG_SYS_MIPS_TIMER_FREQ	200000000
+
+/* RAM */
+#define CONFIG_SYS_SDRAM_BASE		0x80000000
+
+#define CONFIG_SYS_LOAD_ADDR		CONFIG_SYS_SDRAM_BASE + 0x100000
+
+#define CONFIG_SYS_INIT_SP_OFFSET	0x400000
+
+#ifdef CONFIG_BOOT_RAM
+#define CONFIG_SKIP_LOWLEVEL_INIT
+#endif
+
+/* UART */
+#define CONFIG_SYS_BAUDRATE_TABLE	{ 9600, 19200, 38400, 57600, 115200, \
+					  230400, 500000, 1500000 }
+
+/* RAM */
+#define CONFIG_SYS_MEMTEST_START	0x80100000
+#define CONFIG_SYS_MEMTEST_END		0x80400000
+
+/* Memory usage */
+#define CONFIG_SYS_MAXARGS		64
+#define CONFIG_SYS_MALLOC_LEN		(1024 * 1024)
+#define CONFIG_SYS_BOOTPARAMS_LEN	(128 * 1024)
+#define CONFIG_SYS_CBSIZE		512
+
+/* U-Boot */
+#define CONFIG_SYS_MONITOR_BASE		CONFIG_SYS_TEXT_BASE
+
+/* Environment settings */
+#define CONFIG_ENV_OFFSET		0x40000
+#define CONFIG_ENV_SIZE			(16 << 10)
+#define CONFIG_ENV_SECT_SIZE		(64 << 10)
+
+/*
+ * Environment is right behind U-Boot in flash. Make sure U-Boot
+ * doesn't grow into the environment area.
+ */
+#define CONFIG_BOARD_SIZE_LIMIT		CONFIG_ENV_OFFSET
+
+#endif /* __CONFIG_LINKIT_SMART_7688_H */
diff --git a/include/configs/pic32mzdask.h b/include/configs/pic32mzdask.h
index 3749577..d3ab557 100644
--- a/include/configs/pic32mzdask.h
+++ b/include/configs/pic32mzdask.h
@@ -16,9 +16,6 @@
 /* CPU Timer rate */
 #define CONFIG_SYS_MIPS_TIMER_FREQ	100000000
 
-/* Cache Configuration */
-#define CONFIG_SYS_MIPS_CACHE_MODE	CONF_CM_CACHABLE_NONCOHERENT
-
 /*----------------------------------------------------------------------
  * Memory Layout
  */
diff --git a/include/configs/qemu-arm.h b/include/configs/qemu-arm.h
index 66729b7..fedc466 100644
--- a/include/configs/qemu-arm.h
+++ b/include/configs/qemu-arm.h
@@ -20,12 +20,6 @@
 /* For timer, QEMU emulates an ARMv7/ARMv8 architected timer */
 #define CONFIG_SYS_HZ                       1000
 
-/* For block devices, QEMU emulates an ICH9 AHCI controller over PCI */
-#define CONFIG_SYS_SCSI_MAX_SCSI_ID 6
-
-/* QEMU emulates the ARM AMBA PL031 RTC */
-#define CONFIG_SYS_RTC_PL031_BASE	0x09010000
-
 /* Environment options */
 #define CONFIG_ENV_SIZE				SZ_64K
 
diff --git a/include/configs/sama5d27_som1_ek.h b/include/configs/sama5d27_som1_ek.h
index 6192328..7c7479b 100644
--- a/include/configs/sama5d27_som1_ek.h
+++ b/include/configs/sama5d27_som1_ek.h
@@ -36,17 +36,11 @@
 #undef CONFIG_BOOTCOMMAND
 #ifdef CONFIG_SD_BOOT
 /* u-boot env in sd/mmc card */
-#define FAT_ENV_INTERFACE	"mmc"
-#define FAT_ENV_DEVICE_AND_PART	"0"
-#define FAT_ENV_FILE		"uboot.env"
 #define CONFIG_ENV_SIZE		0x4000
 /* bootstrap + u-boot + env in sd card */
-#define CONFIG_BOOTCOMMAND	"fatload mmc 0:1 0x21000000 at91-sama5d27_som1_ek.dtb; " \
-				"fatload mmc 0:1 0x22000000 zImage; " \
+#define CONFIG_BOOTCOMMAND	"fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x21000000 at91-sama5d27_som1_ek.dtb; " \
+				"fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x22000000 zImage; " \
 				"bootz 0x22000000 - 0x21000000"
-#undef CONFIG_BOOTARGS
-#define CONFIG_BOOTARGS \
-	"console=ttyS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait"
 #endif
 
 #ifdef CONFIG_QSPI_BOOT
diff --git a/include/configs/sama5d2_xplained.h b/include/configs/sama5d2_xplained.h
index 92f7f0d..2cec1c7 100644
--- a/include/configs/sama5d2_xplained.h
+++ b/include/configs/sama5d2_xplained.h
@@ -36,8 +36,8 @@
 /* bootstrap + u-boot + env in sd card */
 #undef CONFIG_BOOTCOMMAND
 
-#define CONFIG_BOOTCOMMAND	"fatload mmc 1:1 0x21000000 at91-sama5d2_xplained.dtb; " \
-				"fatload mmc 1:1 0x22000000 zImage; " \
+#define CONFIG_BOOTCOMMAND	"fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x21000000 at91-sama5d2_xplained.dtb; " \
+				"fatload mmc " CONFIG_ENV_FAT_DEVICE_AND_PART " 0x22000000 zImage; " \
 				"bootz 0x22000000 - 0x21000000"
 
 #elif CONFIG_SPI_BOOT
diff --git a/include/configs/sbc8641d.h b/include/configs/sbc8641d.h
index c509822..d777e7a 100644
--- a/include/configs/sbc8641d.h
+++ b/include/configs/sbc8641d.h
@@ -298,7 +298,6 @@
 #define CONFIG_SYS_SCSI_MAX_SCSI_ID	4
 #define CONFIG_SYS_SCSI_MAX_LUN	1
 #define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * CONFIG_SYS_SCSI_MAX_LUN)
-#define CONFIG_SYS_SCSI_MAXDEVICE	CONFIG_SYS_SCSI_MAX_DEVICE
 #endif
 
 #endif	/* CONFIG_PCI */
diff --git a/include/configs/x86-common.h b/include/configs/x86-common.h
index 78c382d..4180b25 100644
--- a/include/configs/x86-common.h
+++ b/include/configs/x86-common.h
@@ -28,10 +28,6 @@
 #define CONFIG_LBA48
 #define CONFIG_SYS_64BIT_LBA
 
-#define CONFIG_SYS_SCSI_MAX_SCSI_ID	2
-#define CONFIG_SYS_SCSI_MAX_LUN		1
-#define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
-					 CONFIG_SYS_SCSI_MAX_LUN)
 #endif
 
 /* Generic TPM interfaced through LPC bus */
diff --git a/include/configs/xilinx_zynqmp.h b/include/configs/xilinx_zynqmp.h
index a65e8fe..0ab3261 100644
--- a/include/configs/xilinx_zynqmp.h
+++ b/include/configs/xilinx_zynqmp.h
@@ -122,13 +122,6 @@
 # define CONFIG_SYS_EEPROM_SIZE			(64 * 1024)
 #endif
 
-#ifdef CONFIG_SATA_CEVA
-#define CONFIG_SYS_SCSI_MAX_SCSI_ID	2
-#define CONFIG_SYS_SCSI_MAX_LUN		1
-#define CONFIG_SYS_SCSI_MAX_DEVICE	(CONFIG_SYS_SCSI_MAX_SCSI_ID * \
-					 CONFIG_SYS_SCSI_MAX_LUN)
-#endif
-
 #define CONFIG_SYS_BOOTM_LEN	(60 * 1024 * 1024)
 
 #define CONFIG_CLOCKS
diff --git a/include/configs/xilinx_zynqmp_mini.h b/include/configs/xilinx_zynqmp_mini.h
index 1387d39..00ca3d4 100644
--- a/include/configs/xilinx_zynqmp_mini.h
+++ b/include/configs/xilinx_zynqmp_mini.h
@@ -24,7 +24,6 @@
 #undef CONFIG_BOOTM_NETBSD
 #undef CONFIG_BOOTM_VXWORKS
 #undef CONFIG_BOOTM_LINUX
-#undef CONFIG_BOARD_LATE_INIT
 
 /* BOOTP options */
 #undef CONFIG_BOOTP_BOOTFILESIZE
diff --git a/include/configs/zynq-common.h b/include/configs/zynq-common.h
index 526fe05..f99c2cb 100644
--- a/include/configs/zynq-common.h
+++ b/include/configs/zynq-common.h
@@ -127,8 +127,6 @@
 /* Boot configuration */
 #define CONFIG_SYS_LOAD_ADDR		0 /* default? */
 
-/* Distro boot enablement */
-
 #ifdef CONFIG_SPL_BUILD
 #define BOOTENV
 #else
@@ -244,10 +242,6 @@
 
 #define CONFIG_SYS_LDSCRIPT  "arch/arm/mach-zynq/u-boot.lds"
 
-/* Commands */
-
-/* SPL part */
-
 /* MMC support */
 #ifdef CONFIG_MMC_SDHCI_ZYNQ
 #define CONFIG_SYS_MMCSD_FS_BOOT_PARTITION     1
@@ -279,8 +273,6 @@
 					CONFIG_SYS_SPI_ARGS_SIZE)
 #endif
 
-/* for booting directly linux */
-
 /* SP location before relocation, must use scratch RAM */
 #define CONFIG_SPL_TEXT_BASE	0x0
 
diff --git a/include/configs/zynq_cse.h b/include/configs/zynq_cse.h
index c4587a1..e7a4d41 100644
--- a/include/configs/zynq_cse.h
+++ b/include/configs/zynq_cse.h
@@ -17,7 +17,6 @@
 
 /* Undef unneeded configs */
 #undef CONFIG_EXTRA_ENV_SETTINGS
-#undef CONFIG_BOARD_LATE_INIT
 #undef CONFIG_ZLIB
 #undef CONFIG_GZIP
 
diff --git a/include/configs/zynq_zybo.h b/include/configs/zynq_zybo.h
index 547ecb6..7d00b41 100644
--- a/include/configs/zynq_zybo.h
+++ b/include/configs/zynq_zybo.h
@@ -12,8 +12,6 @@
 
 #define CONFIG_SYS_I2C_EEPROM_ADDR_LEN	1
 #define CONFIG_ZYNQ_GEM_EEPROM_ADDR	0x50
-#define CONFIG_DISPLAY
-#define CONFIG_I2C_EDID
 
 #include <configs/zynq-common.h>
 
diff --git a/include/cp1250.h b/include/cp1250.h
new file mode 100644
index 0000000..adacf8a
--- /dev/null
+++ b/include/cp1250.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Constant CP1250 contains the Unicode code points for characters 0x80 - 0xff
+ * of the code page 1250.
+ */
+#define CP1250 { \
+	0x20ac, 0x0000, 0x201a, 0x0000, \
+	0x201e, 0x2026, 0x2020, 0x2021, \
+	0x0000, 0x2030, 0x0160, 0x2039, \
+	0x015a, 0x0164, 0x017d, 0x0179, \
+	0x0000, 0x2018, 0x2019, 0x201c, \
+	0x201d, 0x2022, 0x2013, 0x2014, \
+	0x0000, 0x2122, 0x0161, 0x203a, \
+	0x015b, 0x0165, 0x017e, 0x017a, \
+	0x00a0, 0x02c7, 0x02d8, 0x0141, \
+	0x00a4, 0x0104, 0x00a6, 0x00a7, \
+	0x00a8, 0x00a9, 0x015e, 0x00ab, \
+	0x00ac, 0x00ad, 0x00ae, 0x017b, \
+	0x00b0, 0x00b1, 0x02db, 0x0142, \
+	0x00b4, 0x00b5, 0x00b6, 0x00b7, \
+	0x00b8, 0x0105, 0x015f, 0x00bb, \
+	0x013d, 0x02dd, 0x013e, 0x017c, \
+	0x0154, 0x00c1, 0x00c2, 0x0102, \
+	0x00c4, 0x0139, 0x0106, 0x00c7, \
+	0x010c, 0x00c9, 0x0118, 0x00cb, \
+	0x011a, 0x00cd, 0x00ce, 0x010e, \
+	0x0110, 0x0143, 0x0147, 0x00d3, \
+	0x00d4, 0x0150, 0x00d6, 0x00d7, \
+	0x0158, 0x016e, 0x00da, 0x0170, \
+	0x00dc, 0x00dd, 0x0162, 0x00df, \
+	0x0155, 0x00e1, 0x00e2, 0x0103, \
+	0x00e4, 0x013a, 0x0107, 0x00e7, \
+	0x010d, 0x00e9, 0x0119, 0x00eb, \
+	0x011b, 0x00ed, 0x00ee, 0x010f, \
+	0x0111, 0x0144, 0x0148, 0x00f3, \
+	0x00f4, 0x0151, 0x00f6, 0x00f7, \
+	0x0159, 0x016f, 0x00fa, 0x0171, \
+	0x00fc, 0x00fd, 0x0163, 0x02d9, \
+}
diff --git a/include/cp437.h b/include/cp437.h
new file mode 100644
index 0000000..0b2b971
--- /dev/null
+++ b/include/cp437.h
@@ -0,0 +1,40 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+
+/*
+ * Constant CP437 contains the Unicode code points for characters 0x80 - 0xff
+ * of the code page 437.
+ */
+#define CP437 { \
+	0x00c7, 0x00fc, 0x00e9, 0x00e2, \
+	0x00e4, 0x00e0, 0x00e5, 0x00e7, \
+	0x00ea, 0x00eb, 0x00e8, 0x00ef, \
+	0x00ee, 0x00ec, 0x00c4, 0x00c5, \
+	0x00c9, 0x00e6, 0x00c6, 0x00f4, \
+	0x00f6, 0x00f2, 0x00fb, 0x00f9, \
+	0x00ff, 0x00d6, 0x00dc, 0x00a2, \
+	0x00a3, 0x00a5, 0x20a7, 0x0192, \
+	0x00e1, 0x00ed, 0x00f3, 0x00fa, \
+	0x00f1, 0x00d1, 0x00aa, 0x00ba, \
+	0x00bf, 0x2310, 0x00ac, 0x00bd, \
+	0x00bc, 0x00a1, 0x00ab, 0x00bb, \
+	0x2591, 0x2592, 0x2593, 0x2502, \
+	0x2524, 0x2561, 0x2562, 0x2556, \
+	0x2555, 0x2563, 0x2551, 0x2557, \
+	0x255d, 0x255c, 0x255b, 0x2510, \
+	0x2514, 0x2534, 0x252c, 0x251c, \
+	0x2500, 0x253c, 0x255e, 0x255f, \
+	0x255a, 0x2554, 0x2569, 0x2566, \
+	0x2560, 0x2550, 0x256c, 0x2567, \
+	0x2568, 0x2564, 0x2565, 0x2559, \
+	0x2558, 0x2552, 0x2553, 0x256b, \
+	0x256a, 0x2518, 0x250c, 0x2588, \
+	0x2584, 0x258c, 0x2590, 0x2580, \
+	0x03b1, 0x00df, 0x0393, 0x03c0, \
+	0x03a3, 0x03c3, 0x00b5, 0x03c4, \
+	0x03a6, 0x0398, 0x03a9, 0x03b4, \
+	0x221e, 0x03c6, 0x03b5, 0x2229, \
+	0x2261, 0x00b1, 0x2265, 0x2264, \
+	0x2320, 0x2321, 0x00f7, 0x2248, \
+	0x00b0, 0x2219, 0x00b7, 0x221a, \
+	0x207f, 0x00b2, 0x25a0, 0x00a0, \
+}
diff --git a/include/cpsw.h b/include/cpsw.h
index f135e7b..9f8ce88 100644
--- a/include/cpsw.h
+++ b/include/cpsw.h
@@ -54,5 +54,6 @@
 
 int cpsw_register(struct cpsw_platform_data *data);
 int ti_cm_get_macid(struct udevice *dev, int slave, u8 *mac_addr);
+int cpsw_get_slave_phy_addr(struct udevice *dev, int slave);
 
 #endif /* _CPSW_H_  */
diff --git a/include/dm/platform_data/pl022_spi.h b/include/dm/platform_data/pl022_spi.h
new file mode 100644
index 0000000..77fe6da
--- /dev/null
+++ b/include/dm/platform_data/pl022_spi.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * (C) Copyright 2018
+ * Quentin Schulz, Bootlin, quentin.schulz@bootlin.com
+ *
+ * Structure for use with U_BOOT_DEVICE for pl022 SPI devices or to use
+ * in ofdata_to_platdata.
+ */
+
+#ifndef __PL022_SPI_H__
+#define __PL022_SPI_H__
+
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+#include <clk.h>
+#endif
+#include <fdtdec.h>
+
+struct pl022_spi_pdata {
+	fdt_addr_t addr;
+	fdt_size_t size;
+#if !CONFIG_IS_ENABLED(OF_PLATDATA)
+	struct clk clk;
+#else
+	unsigned int freq;
+#endif
+};
+
+#endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 7027ea0..e6fc3ab 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -37,6 +37,7 @@
 	UCLASS_DMA,		/* Direct Memory Access */
 	UCLASS_EFI,		/* EFI managed devices */
 	UCLASS_ETH,		/* Ethernet device */
+	UCLASS_FS_FIRMWARE_LOADER,		/* Generic loader */
 	UCLASS_GPIO,		/* Bank of general-purpose I/O pins */
 	UCLASS_FIRMWARE,	/* Firmware */
 	UCLASS_I2C,		/* I2C bus */
@@ -92,6 +93,8 @@
 	UCLASS_VIDEO,		/* Video or LCD device */
 	UCLASS_VIDEO_BRIDGE,	/* Video bridge, e.g. DisplayPort to LVDS */
 	UCLASS_VIDEO_CONSOLE,	/* Text console driver for video device */
+	UCLASS_W1,		/* Dallas 1-Wire bus */
+	UCLASS_W1_EEPROM,	/* one-wire EEPROMs */
 	UCLASS_WDT,		/* Watchdot Timer driver */
 
 	UCLASS_COUNT,
diff --git a/include/efi.h b/include/efi.h
index e1854ec..b1deb60 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Extensible Firmware Interface
  * Based on 'Extensible Firmware Interface Specification' version 0.9,
diff --git a/include/efi_api.h b/include/efi_api.h
index ebf2a3b..bea19a5 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 */
 /*
  * Extensible Firmware Interface
  * Based on 'Extensible Firmware Interface Specification' version 0.9,
@@ -31,6 +32,7 @@
 	EFI_TIMER_RELATIVE = 2
 };
 
+#define efi_intn_t ssize_t
 #define efi_uintn_t size_t
 typedef uint16_t *efi_string_t;
 
@@ -294,8 +296,7 @@
 	EFI_GUID(0xeb9d2d31, 0x2d88, 0x11d3,  \
 		 0x9a, 0x16, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d)
 
-struct efi_configuration_table
-{
+struct efi_configuration_table {
 	efi_guid_t guid;
 	void *table;
 };
@@ -307,7 +308,7 @@
 	u16 *fw_vendor;   /* physical addr of wchar_t vendor string */
 	u32 fw_revision;
 	efi_handle_t con_in_handle;
-	struct efi_simple_input_interface *con_in;
+	struct efi_simple_text_input_protocol *con_in;
 	efi_handle_t con_out_handle;
 	struct efi_simple_text_output_protocol *con_out;
 	efi_handle_t stderr_handle;
@@ -338,19 +339,11 @@
 	unsigned int image_code_type;
 	unsigned int image_data_type;
 	unsigned long unload;
-
-	/* Below are efi loader private fields */
-#ifdef CONFIG_EFI_LOADER
-	void *reloc_base;
-	aligned_u64 reloc_size;
-	efi_status_t exit_status;
-	struct jmp_buf_data exit_jmp;
-#endif
 };
 
 #define DEVICE_PATH_GUID \
 	EFI_GUID(0x09576e91, 0x6d3f, 0x11d2, \
-		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b )
+		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
 #define DEVICE_PATH_TYPE_END			0x7f
 #  define DEVICE_PATH_SUB_TYPE_INSTANCE_END	0x01
@@ -475,8 +468,7 @@
 	EFI_GUID(0x964e5b21, 0x6459, 0x11d2, \
 		 0x8e, 0x39, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
-struct efi_block_io_media
-{
+struct efi_block_io_media {
 	u32 media_id;
 	char removable_media;
 	char media_present;
@@ -521,7 +513,6 @@
 	bool cursor_visible;
 };
 
-
 #define EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID \
 	EFI_GUID(0x387477c2, 0x69c7, 0x11d2, \
 		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
@@ -588,20 +579,76 @@
 	struct simple_text_output_mode *mode;
 };
 
+#define EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID \
+	EFI_GUID(0xdd9e7534, 0x7762, 0x4698, \
+		 0x8c, 0x14, 0xf5, 0x85, 0x17, 0xa6, 0x25, 0xaa)
+
 struct efi_input_key {
 	u16 scan_code;
 	s16 unicode_char;
 };
 
+#define EFI_SHIFT_STATE_INVALID		0x00000000
+#define EFI_RIGHT_SHIFT_PRESSED		0x00000001
+#define EFI_LEFT_SHIFT_PRESSED		0x00000002
+#define EFI_RIGHT_CONTROL_PRESSED	0x00000004
+#define EFI_LEFT_CONTROL_PRESSED	0x00000008
+#define EFI_RIGHT_ALT_PRESSED		0x00000010
+#define EFI_LEFT_ALT_PRESSED		0x00000020
+#define EFI_RIGHT_LOGO_PRESSED		0x00000040
+#define EFI_LEFT_LOGO_PRESSED		0x00000080
+#define EFI_MENU_KEY_PRESSED		0x00000100
+#define EFI_SYS_REQ_PRESSED		0x00000200
+#define EFI_SHIFT_STATE_VALID		0x80000000
+
+#define EFI_TOGGLE_STATE_INVALID	0x00
+#define EFI_SCROLL_LOCK_ACTIVE		0x01
+#define EFI_NUM_LOCK_ACTIVE		0x02
+#define EFI_CAPS_LOCK_ACTIVE		0x04
+#define EFI_KEY_STATE_EXPOSED		0x40
+#define EFI_TOGGLE_STATE_VALID		0x80
+
+struct efi_key_state {
+	u32 key_shift_state;
+	u8 key_toggle_state;
+};
+
+struct efi_key_data {
+	struct efi_input_key key;
+	struct efi_key_state key_state;
+};
+
+struct efi_simple_text_input_ex_protocol {
+	efi_status_t (EFIAPI *reset) (
+		struct efi_simple_text_input_ex_protocol *this,
+		bool extended_verification);
+	efi_status_t (EFIAPI *read_key_stroke_ex) (
+		struct efi_simple_text_input_ex_protocol *this,
+		struct efi_key_data *key_data);
+	struct efi_event *wait_for_key_ex;
+	efi_status_t (EFIAPI *set_state) (
+		struct efi_simple_text_input_ex_protocol *this,
+		u8 key_toggle_state);
+	efi_status_t (EFIAPI *register_key_notify) (
+		struct efi_simple_text_input_ex_protocol *this,
+		struct efi_key_data *key_data,
+		efi_status_t (EFIAPI *key_notify_function)(
+			struct efi_key_data *key_data),
+		void **notify_handle);
+	efi_status_t (EFIAPI *unregister_key_notify) (
+		struct efi_simple_text_input_ex_protocol *this,
+		void *notification_handle);
+};
+
 #define EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID \
 	EFI_GUID(0x387477c1, 0x69c7, 0x11d2, \
 		 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
 
-struct efi_simple_input_interface {
-	efi_status_t(EFIAPI *reset)(struct efi_simple_input_interface *this,
-			bool ExtendedVerification);
+struct efi_simple_text_input_protocol {
+	efi_status_t(EFIAPI *reset)(struct efi_simple_text_input_protocol *this,
+				    bool extended_verification);
 	efi_status_t(EFIAPI *read_key_stroke)(
-			struct efi_simple_input_interface *this,
+			struct efi_simple_text_input_protocol *this,
 			struct efi_input_key *key);
 	struct efi_event *wait_for_key;
 };
@@ -610,8 +657,7 @@
 	EFI_GUID(0x8b843e20, 0x8132, 0x4852, \
 		 0x90, 0xcc, 0x55, 0x1a, 0x4e, 0x4a, 0x7f, 0x1c)
 
-struct efi_device_path_to_text_protocol
-{
+struct efi_device_path_to_text_protocol {
 	uint16_t *(EFIAPI *convert_device_node_to_text)(
 			struct efi_device_path *device_node,
 			bool display_only,
@@ -659,8 +705,7 @@
 #define EFI_GOT_BGRA8		1
 #define EFI_GOT_BITMASK		2
 
-struct efi_gop_mode_info
-{
+struct efi_gop_mode_info {
 	u32 version;
 	u32 width;
 	u32 height;
@@ -669,8 +714,7 @@
 	u32 pixels_per_scanline;
 };
 
-struct efi_gop_mode
-{
+struct efi_gop_mode {
 	u32 max_mode;
 	u32 mode;
 	struct efi_gop_mode_info *info;
@@ -691,8 +735,7 @@
 #define EFI_BLT_BUFFER_TO_VIDEO		2
 #define EFI_BLT_VIDEO_TO_VIDEO		3
 
-struct efi_gop
-{
+struct efi_gop {
 	efi_status_t (EFIAPI *query_mode)(struct efi_gop *this, u32 mode_number,
 					  efi_uintn_t *size_of_info,
 					  struct efi_gop_mode_info **info);
@@ -762,8 +805,7 @@
 /* revision of the simple network protocol */
 #define EFI_SIMPLE_NETWORK_PROTOCOL_REVISION	0x00010000
 
-struct efi_simple_network
-{
+struct efi_simple_network {
 	u64 revision;
 	efi_status_t (EFIAPI *start)(struct efi_simple_network *this);
 	efi_status_t (EFIAPI *stop)(struct efi_simple_network *this);
@@ -808,8 +850,7 @@
 	u8 packet[1472];
 };
 
-struct efi_pxe_mode
-{
+struct efi_pxe_mode {
 	u8 started;
 	u8 ipv6_available;
 	u8 ipv6_supported;
@@ -958,4 +999,24 @@
 	efi_handle_t driver_binding_handle;
 };
 
+#define EFI_UNICODE_COLLATION_PROTOCOL2_GUID \
+	EFI_GUID(0xa4c751fc, 0x23ae, 0x4c3e, \
+		 0x92, 0xe9, 0x49, 0x64, 0xcf, 0x63, 0xf3, 0x49)
+struct efi_unicode_collation_protocol {
+	efi_intn_t (EFIAPI *stri_coll)(
+		struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2);
+	bool (EFIAPI *metai_match)(struct efi_unicode_collation_protocol *this,
+				   const u16 *string, const u16 *patter);
+	void (EFIAPI *str_lwr)(struct efi_unicode_collation_protocol
+			       *this, u16 *string);
+	void (EFIAPI *str_upr)(struct efi_unicode_collation_protocol *this,
+			       u16 *string);
+	void (EFIAPI *fat_to_str)(struct efi_unicode_collation_protocol *this,
+				  efi_uintn_t fat_size, char *fat, u16 *string);
+	bool (EFIAPI *str_to_fat)(struct efi_unicode_collation_protocol *this,
+				  const u16 *string, efi_uintn_t fat_size,
+				  char *fat);
+	char *supported_languages;
+};
+
 #endif
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f162adf..34e44c6 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -13,13 +13,18 @@
 #include <efi_api.h>
 
 /* No need for efi loader support in SPL */
-#if defined(CONFIG_EFI_LOADER) && !defined(CONFIG_SPL_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER)
 
 #include <linux/list.h>
 
 /* Maximum number of configuration tables */
 #define EFI_MAX_CONFIGURATION_TABLES 16
 
+/* GUID used by the root node */
+#define U_BOOT_GUID \
+	EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
+		 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
+
 int __efi_entry_check(void);
 int __efi_exit_check(void);
 const char *__efi_nesting(void);
@@ -92,15 +97,20 @@
 extern struct efi_system_table systab;
 
 extern struct efi_simple_text_output_protocol efi_con_out;
-extern struct efi_simple_input_interface efi_con_in;
+extern struct efi_simple_text_input_protocol efi_con_in;
 extern struct efi_console_control_protocol efi_console_control;
 extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
 /* implementation of the EFI_DEVICE_PATH_UTILITIES_PROTOCOL */
 extern const struct efi_device_path_utilities_protocol
 					efi_device_path_utilities;
+/* Implementation of the EFI_UNICODE_COLLATION_PROTOCOL */
+extern const struct efi_unicode_collation_protocol
+					efi_unicode_collation_protocol;
 
 uint16_t *efi_dp_str(struct efi_device_path *dp);
 
+/* GUID of the U-Boot root node */
+extern const efi_guid_t efi_u_boot_guid;
 /* GUID of the EFI_BLOCK_IO_PROTOCOL */
 extern const efi_guid_t efi_block_io_guid;
 extern const efi_guid_t efi_global_variable_guid;
@@ -127,6 +137,8 @@
 /* GUID for file system information */
 extern const efi_guid_t efi_file_system_info_guid;
 extern const efi_guid_t efi_guid_device_path_utilities_protocol;
+/* GUID of the Unicode collation protocol */
+extern const efi_guid_t efi_guid_unicode_collation_protocol;
 
 extern unsigned int __efi_runtime_start, __efi_runtime_stop;
 extern unsigned int __efi_runtime_rel_start, __efi_runtime_rel_stop;
@@ -172,6 +184,20 @@
 };
 
 /**
+ * struct efi_loaded_image_obj - handle of a loaded image
+ */
+struct efi_loaded_image_obj {
+	/* Generic EFI object parent class data */
+	struct efi_object parent;
+	void *reloc_base;
+	aligned_u64 reloc_size;
+	efi_status_t exit_status;
+	struct jmp_buf_data exit_jmp;
+	EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
+				     struct efi_system_table *st);
+};
+
+/**
  * struct efi_event
  *
  * @link:		Link to list of all events
@@ -205,6 +231,8 @@
 /* List of all events */
 extern struct list_head efi_events;
 
+/* Called by bootefi to initialize root node */
+efi_status_t efi_root_node_register(void);
 /* Called by bootefi to initialize runtime */
 efi_status_t efi_initialize_system_table(void);
 /* Called by bootefi to make console interface available */
@@ -250,7 +278,8 @@
 /* Called from places to check whether a timer expired */
 void efi_timer_check(void);
 /* PE loader implementation */
-void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info);
+void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+		  struct efi_loaded_image *loaded_image_info);
 /* Called once to store the pristine gd pointer */
 void efi_save_gd(void);
 /* Special case handler for error/abort that just tries to dtrt to get
@@ -331,14 +360,12 @@
 /* Adds new or overrides configuration table entry to the system table */
 efi_status_t efi_install_configuration_table(const efi_guid_t *guid, void *table);
 /* Sets up a loaded image */
-efi_status_t efi_setup_loaded_image(
-			struct efi_loaded_image *info, struct efi_object *obj,
-			struct efi_device_path *device_path,
-			struct efi_device_path *file_path);
+efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
+				    struct efi_device_path *file_path,
+				    struct efi_loaded_image_obj **handle_ptr,
+				    struct efi_loaded_image **info_ptr);
 efi_status_t efi_load_image_from_path(struct efi_device_path *file_path,
 				      void **buffer);
-/* Print information about a loaded image */
-efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc);
 /* Print information about all loaded images */
 void efi_print_image_infos(void *pc);
 
@@ -397,7 +424,15 @@
 	(((_dp)->type == DEVICE_PATH_TYPE_##_type) && \
 	 ((_dp)->sub_type == DEVICE_PATH_SUB_TYPE_##_subtype))
 
-/* Convert strings from normal C strings to uEFI strings */
+/**
+ * ascii2unicode() - convert ASCII string to UTF-16 string
+ *
+ * A zero terminated ASCII string is converted to a zero terminated UTF-16
+ * string. The output buffer must be preassigned.
+ *
+ * @unicode:	preassigned output buffer for UTF-16 string
+ * @ascii:	ASCII string to be converted
+ */
 static inline void ascii2unicode(u16 *unicode, const char *ascii)
 {
 	while (*ascii)
@@ -460,7 +495,7 @@
 void *efi_bootmgr_load(struct efi_device_path **device_path,
 		       struct efi_device_path **file_path);
 
-#else /* defined(EFI_LOADER) && !defined(CONFIG_SPL_BUILD) */
+#else /* CONFIG_IS_ENABLED(EFI_LOADER) */
 
 /* Without CONFIG_EFI_LOADER we don't have a runtime section, stub it out */
 #define __efi_runtime_data
@@ -477,6 +512,6 @@
 static inline void efi_net_set_dhcp_ack(void *pkt, int len) { }
 static inline void efi_print_image_infos(void *pc) { }
 
-#endif /* CONFIG_EFI_LOADER && !CONFIG_SPL_BUILD */
+#endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
 
 #endif /* _EFI_LOADER_H */
diff --git a/include/efi_selftest.h b/include/efi_selftest.h
index d0a76d7..56beac3 100644
--- a/include/efi_selftest.h
+++ b/include/efi_selftest.h
@@ -53,7 +53,7 @@
 };
 
 extern struct efi_simple_text_output_protocol *con_out;
-extern struct efi_simple_input_interface *con_in;
+extern struct efi_simple_text_input_protocol *con_in;
 
 /*
  * Exit the boot services.
@@ -76,6 +76,22 @@
 void efi_st_printc(int color, const char *fmt, ...)
 		 __attribute__ ((format (__printf__, 2, 3)));
 
+/**
+ * efi_st_translate_char() - translate a unicode character to a string
+ *
+ * @code:	unicode character
+ * Return:	string
+ */
+u16 *efi_st_translate_char(u16 code);
+
+/**
+ * efi_st_translate_code() - translate a scan code to a human readable string
+ *
+ * @code:	unicode character
+ * Return:	string
+ */
+u16 *efi_st_translate_code(u16 code);
+
 /*
  * Compare memory.
  * We cannot use lib/string.c due to different CFLAGS values.
diff --git a/include/fat.h b/include/fat.h
index 09e1423..bc139f8 100644
--- a/include/fat.h
+++ b/include/fat.h
@@ -173,6 +173,8 @@
 	int	fatbufnum;	/* Used by get_fatent, init to -1 */
 	int	rootdir_size;	/* Size of root dir for non-FAT32 */
 	__u32	root_cluster;	/* First cluster of root dir for FAT32 */
+	u32	total_sect;	/* Number of sectors */
+	int	fats;		/* Number of FATs */
 } fsdata;
 
 static inline u32 clust_to_sect(fsdata *fsdata, u32 clust)
@@ -201,5 +203,7 @@
 int fat_opendir(const char *filename, struct fs_dir_stream **dirsp);
 int fat_readdir(struct fs_dir_stream *dirs, struct fs_dirent **dentp);
 void fat_closedir(struct fs_dir_stream *dirs);
+int fat_unlink(const char *filename);
+int fat_mkdir(const char *dirname);
 void fat_close(void);
 #endif /* _FAT_H_ */
diff --git a/include/fs.h b/include/fs.h
index 163da10..aa3604d 100644
--- a/include/fs.h
+++ b/include/fs.h
@@ -156,6 +156,24 @@
 void fs_closedir(struct fs_dir_stream *dirs);
 
 /*
+ * fs_unlink - delete a file or directory
+ *
+ * If a given name is a directory, it will be deleted only if it's empty
+ *
+ * @filename: Name of file or directory to delete
+ * @return 0 on success, -1 on error conditions
+ */
+int fs_unlink(const char *filename);
+
+/*
+ * fs_mkdir - Create a directory
+ *
+ * @filename: Name of directory to create
+ * @return 0 on success, -1 on error conditions
+ */
+int fs_mkdir(const char *filename);
+
+/*
  * Common implementation for various filesystem commands, optionally limited
  * to a specific filesystem type via the fstype parameter.
  */
@@ -169,6 +187,10 @@
 		int fstype);
 int do_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
 		int fstype);
+int do_rm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+		int fstype);
+int do_mkdir(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
+		int fstype);
 
 /*
  * Determine the UUID of the specified filesystem and print it. Optionally it is
diff --git a/include/fs_loader.h b/include/fs_loader.h
new file mode 100644
index 0000000..0be4f17
--- /dev/null
+++ b/include/fs_loader.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2018 Intel Corporation <www.intel.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0
+ */
+#ifndef _FS_LOADER_H_
+#define _FS_LOADER_H_
+
+#include <dm.h>
+
+/**
+ * struct firmware - A place for storing firmware and its attribute data.
+ *
+ * This holds information about a firmware and its content.
+ *
+ * @size: Size of a file
+ * @data: Buffer for file
+ * @priv: Firmware loader private fields
+ */
+struct firmware {
+	size_t size;
+	const u8 *data;
+	void *priv;
+};
+
+/**
+ * struct phandle_part - A place for storing phandle of node and its partition
+ *
+ * This holds information about a phandle of the block device, and its
+ * partition where the firmware would be loaded from.
+ *
+ * @phandle: Phandle of storage device node
+ * @partition: Partition of block device
+ */
+struct phandle_part {
+	u32 phandle;
+	u32 partition;
+};
+
+/**
+ * struct phandle_part - A place for storing all supported storage devices
+ *
+ * This holds information about all supported storage devices for driver use.
+ *
+ * @phandlepart: Attribute data for block device.
+ * @mtdpart: MTD partition for ubi partition.
+ * @ubivol: UBI volume-name for ubifsmount.
+ */
+struct device_platdata {
+	struct phandle_part phandlepart;
+	char *mtdpart;
+	char *ubivol;
+};
+
+/**
+ * release_firmware - Release the resource associated with a firmware image
+ * @firmware: Firmware resource to release
+ */
+void release_firmware(struct firmware *firmware);
+
+/**
+ * request_firmware_into_buf - Load firmware into a previously allocated buffer.
+ * @plat: Platform data such as storage and partition firmware loading from.
+ * @name: Name of firmware file.
+ * @buf: Address of buffer to load firmware into.
+ * @size: Size of buffer.
+ * @offset: Offset of a file for start reading into buffer.
+ * @firmwarep: Pointer to firmware image.
+ *
+ * The firmware is loaded directly into the buffer pointed to by @buf and
+ * the @firmwarep data member is pointed at @buf.
+ *
+ * Return: Size of total read, negative value when error.
+ */
+int request_firmware_into_buf(struct device_platdata *plat,
+			      const char *name,
+			      void *buf, size_t size, u32 offset,
+			      struct firmware **firmwarep);
+#endif
diff --git a/include/os.h b/include/os.h
index c8e0f52..5c79721 100644
--- a/include/os.h
+++ b/include/os.h
@@ -331,24 +331,7 @@
 void os_localtime(struct rtc_time *rt);
 
 /**
- * os_setjmp() - Call setjmp()
- *
- * Call the host system's setjmp() function.
- *
- * @jmp: Buffer to store current execution state
- * @size: Size of buffer
- * @return normal setjmp() value if OK, -ENOSPC if @size is too small
- */
-int os_setjmp(ulong *jmp, int size);
-
-/**
- * os_longjmp() - Call longjmp()
- *
- * Call the host system's longjmp() function.
- *
- * @jmp: Buffer where previous execution state was stored
- * @ret: Value to pass to longjmp()
+ * os_abort() - Raise SIGABRT to exit sandbox (e.g. to debugger)
  */
-void os_longjmp(ulong *jmp, int ret);
-
+void os_abort(void);
 #endif
diff --git a/include/spl.h b/include/spl.h
index 7fad62c..b42683c 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -303,4 +303,13 @@
  *                        the boot-payload
  */
 void spl_perform_fixups(struct spl_image_info *spl_image);
+
+/*
+ * spl_get_load_buffer() - get buffer for loading partial image data
+ *
+ * Returns memory area which can be populated by partial image data,
+ * ie. uImage or fitImage header.
+ */
+struct image_header *spl_get_load_buffer(ssize_t offset, size_t size);
+
 #endif
diff --git a/include/test/suites.h b/include/test/suites.h
index 071ab40..abb3a4b 100644
--- a/include/test/suites.h
+++ b/include/test/suites.h
@@ -23,10 +23,11 @@
 int cmd_ut_category(const char *name, struct unit_test *tests, int n_ents,
 		    int argc, char * const argv[]);
 
+int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
 int do_ut_dm(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_env(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_overlay(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 int do_ut_time(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
-int do_ut_compression(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]);
+int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]);
 
 #endif /* __TEST_SUITES_H__ */
diff --git a/include/ubi_uboot.h b/include/ubi_uboot.h
index 80acbcb..0770228 100644
--- a/include/ubi_uboot.h
+++ b/include/ubi_uboot.h
@@ -75,5 +75,7 @@
 extern int ubi_volume_read(char *volume, char *buf, size_t size);
 
 extern struct ubi_device *ubi_devices[];
+int cmd_ubifs_mount(char *vol_name);
+int cmd_ubifs_umount(void);
 
 #endif
diff --git a/include/w1-eeprom.h b/include/w1-eeprom.h
new file mode 100644
index 0000000..2233736
--- /dev/null
+++ b/include/w1-eeprom.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ * Copyright (c) 2018 Microchip Technology, Inc.
+ *
+ */
+
+#ifndef __W1_EEPROM_H
+#define __W1_EEPROM_H
+
+struct udevice;
+
+struct w1_eeprom_ops {
+	/*
+	 * Reads a buff from the given EEPROM memory, starting at
+	 * given offset and place the results into the given buffer.
+	 * Should read given count of bytes.
+	 * Should return 0 on success, and normal error.h on error
+	 */
+	int	(*read_buf)(struct udevice *dev, unsigned int offset,
+			    u8 *buf, unsigned int count);
+};
+
+int w1_eeprom_read_buf(struct udevice *dev, unsigned int offset,
+		       u8 *buf, unsigned int count);
+
+int w1_eeprom_dm_init(void);
+
+int w1_eeprom_register_new_device(u64 id);
+
+int w1_eeprom_get_id(struct udevice *dev, u64 *id);
+#endif
diff --git a/include/w1.h b/include/w1.h
new file mode 100644
index 0000000..399177a
--- /dev/null
+++ b/include/w1.h
@@ -0,0 +1,37 @@
+/* SPDX-License-Identifier:	GPL-2.0+
+ *
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ *
+ */
+
+#ifndef __W1_H
+#define __W1_H
+
+#include <dm.h>
+
+#define W1_FAMILY_DS24B33	0x23
+#define W1_FAMILY_DS2431	0x2d
+#define W1_FAMILY_EEP_SANDBOX	0xfe
+
+struct w1_device {
+	u64	id;
+};
+
+struct w1_ops {
+	u8	(*read_byte)(struct udevice *dev);
+	bool	(*reset)(struct udevice *dev);
+	u8	(*triplet)(struct udevice *dev, bool bdir);
+	void	(*write_byte)(struct udevice *dev, u8 byte);
+};
+
+int w1_get_bus(int busnum, struct udevice **busp);
+u8 w1_get_device_family(struct udevice *dev);
+
+int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count);
+int w1_read_byte(struct udevice *dev);
+int w1_reset_select(struct udevice *dev);
+int w1_write_buf(struct udevice *dev, u8 *buf, unsigned int count);
+int w1_write_byte(struct udevice *dev, u8 byte);
+
+#endif
diff --git a/lib/Makefile b/lib/Makefile
index 5f583ae..f169644 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -19,7 +19,12 @@
 obj-$(CONFIG_OPTEE) += optee/
 
 obj-$(CONFIG_AES) += aes.o
+
+ifndef API_BUILD
+ifneq ($(CONFIG_UT_UNICODE)$(CONFIG_EFI_LOADER),)
 obj-y += charset.o
+endif
+endif
 obj-$(CONFIG_USB_TTY) += circbuf.o
 obj-y += crc7.o
 obj-y += crc8.o
diff --git a/lib/charset.c b/lib/charset.c
index cd186a5..0cede9b 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -5,46 +5,345 @@
  *  Copyright (c) 2017 Rob Clark
  */
 
+#include <common.h>
 #include <charset.h>
+#include <capitalization.h>
 #include <malloc.h>
 
-/*
- * utf8/utf16 conversion mostly lifted from grub
+static struct capitalization_table capitalization_table[] =
+#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
+	UNICODE_CAPITALIZATION_TABLE;
+#elif CONFIG_FAT_DEFAULT_CODEPAGE == 1250
+	CP1250_CAPITALIZATION_TABLE;
+#else
+	CP437_CAPITALIZATION_TABLE;
+#endif
+
+/**
+ * get_code() - read Unicode code point from UTF-8 stream
+ *
+ * @read_u8:	- stream reader
+ * @src:	- string buffer passed to stream reader, optional
+ * Return:	- Unicode code point
  */
+static int get_code(u8 (*read_u8)(void *data), void *data)
+{
+	s32 ch = 0;
 
-size_t utf16_strlen(const uint16_t *in)
+	ch = read_u8(data);
+	if (!ch)
+		return 0;
+	if (ch >= 0xc2 && ch <= 0xf4) {
+		int code = 0;
+
+		if (ch >= 0xe0) {
+			if (ch >= 0xf0) {
+				/* 0xf0 - 0xf4 */
+				ch &= 0x07;
+				code = ch << 18;
+				ch = read_u8(data);
+				if (ch < 0x80 || ch > 0xbf)
+					goto error;
+				ch &= 0x3f;
+			} else {
+				/* 0xe0 - 0xef */
+				ch &= 0x0f;
+			}
+			code += ch << 12;
+			if ((code >= 0xD800 && code <= 0xDFFF) ||
+			    code >= 0x110000)
+				goto error;
+			ch = read_u8(data);
+			if (ch < 0x80 || ch > 0xbf)
+				goto error;
+		}
+		/* 0xc0 - 0xdf or continuation byte (0x80 - 0xbf) */
+		ch &= 0x3f;
+		code += ch << 6;
+		ch = read_u8(data);
+		if (ch < 0x80 || ch > 0xbf)
+			goto error;
+		ch &= 0x3f;
+		ch += code;
+	} else if (ch >= 0x80) {
+		goto error;
+	}
+	return ch;
+error:
+	return '?';
+}
+
+/**
+ * read_string() - read byte from character string
+ *
+ * @data:	- pointer to string
+ * Return:	- byte read
+ *
+ * The string pointer is incremented if it does not point to '\0'.
+ */
+static u8 read_string(void *data)
+
 {
-	size_t i;
-	for (i = 0; in[i]; i++);
-	return i;
+	const char **src = (const char **)data;
+	u8 c;
+
+	if (!src || !*src || !**src)
+		return 0;
+	c = **src;
+	++*src;
+	return c;
 }
 
-size_t utf16_strnlen(const uint16_t *in, size_t count)
+/**
+ * read_console() - read byte from console
+ *
+ * @src		- not used, needed to match interface
+ * Return:	- byte read
+ */
+static u8 read_console(void *data)
 {
-	size_t i;
-	for (i = 0; count-- && in[i]; i++);
-	return i;
+	return getc();
 }
 
-uint16_t *utf16_strcpy(uint16_t *dest, const uint16_t *src)
+int console_read_unicode(s32 *code)
 {
-	uint16_t *tmp = dest;
+	if (!tstc()) {
+		/* No input available */
+		return 1;
+	}
 
-	while ((*dest++ = *src++) != '\0')
-		/* nothing */;
-	return tmp;
+	/* Read Unicode code */
+	*code = get_code(read_console, NULL);
+	return 0;
+}
 
+s32 utf8_get(const char **src)
+{
+	return get_code(read_string, src);
 }
 
-uint16_t *utf16_strdup(const uint16_t *s)
+int utf8_put(s32 code, char **dst)
 {
-	uint16_t *new;
-	if (!s || !(new = malloc((utf16_strlen(s) + 1) * 2)))
-		return NULL;
-	utf16_strcpy(new, s);
-	return new;
+	if (!dst || !*dst)
+		return -1;
+	if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
+		return -1;
+	if (code <= 0x007F) {
+		**dst = code;
+	} else {
+		if (code <= 0x07FF) {
+			**dst = code >> 6 | 0xC0;
+		} else {
+			if (code < 0x10000) {
+				**dst = code >> 12 | 0xE0;
+			} else {
+				**dst = code >> 18 | 0xF0;
+				++*dst;
+				**dst = (code >> 12 & 0x3F) | 0x80;
+			}
+			++*dst;
+			**dst = (code >> 6 & 0x3F) | 0x80;
+		}
+		++*dst;
+		**dst = (code & 0x3F) | 0x80;
+	}
+	++*dst;
+	return 0;
+}
+
+size_t utf8_utf16_strnlen(const char *src, size_t count)
+{
+	size_t len = 0;
+
+	for (; *src && count; --count)  {
+		s32 code = utf8_get(&src);
+
+		if (!code)
+			break;
+		if (code < 0) {
+			/* Reserve space for a replacement character */
+			len += 1;
+		} else if (code < 0x10000) {
+			len += 1;
+		} else {
+			len += 2;
+		}
+	}
+	return len;
+}
+
+int utf8_utf16_strncpy(u16 **dst, const char *src, size_t count)
+{
+	if (!src || !dst || !*dst)
+		return -1;
+
+	for (; count && *src; --count) {
+		s32 code = utf8_get(&src);
+
+		if (code < 0)
+			code = '?';
+		utf16_put(code, dst);
+	}
+	**dst = 0;
+	return 0;
+}
+
+s32 utf16_get(const u16 **src)
+{
+	s32 code, code2;
+
+	if (!src || !*src)
+		return -1;
+	if (!**src)
+		return 0;
+	code = **src;
+	++*src;
+	if (code >= 0xDC00 && code <= 0xDFFF)
+		return -1;
+	if (code >= 0xD800 && code <= 0xDBFF) {
+		if (!**src)
+			return -1;
+		code &= 0x3ff;
+		code <<= 10;
+		code += 0x10000;
+		code2 = **src;
+		++*src;
+		if (code2 <= 0xDC00 || code2 >= 0xDFFF)
+			return -1;
+		code2 &= 0x3ff;
+		code += code2;
+	}
+	return code;
+}
+
+int utf16_put(s32 code, u16 **dst)
+{
+	if (!dst || !*dst)
+		return -1;
+	if ((code >= 0xD800 && code <= 0xDFFF) || code >= 0x110000)
+		return -1;
+	if (code < 0x10000) {
+		**dst = code;
+	} else {
+		code -= 0x10000;
+		**dst = code >> 10 | 0xD800;
+		++*dst;
+		**dst = (code & 0x3ff) | 0xDC00;
+	}
+	++*dst;
+	return 0;
+}
+
+size_t utf16_strnlen(const u16 *src, size_t count)
+{
+	size_t len = 0;
+
+	for (; *src && count; --count)  {
+		s32 code = utf16_get(&src);
+
+		if (!code)
+			break;
+		/*
+		 * In case of an illegal sequence still reserve space for a
+		 * replacement character.
+		 */
+		++len;
+	}
+	return len;
 }
 
+size_t utf16_utf8_strnlen(const u16 *src, size_t count)
+{
+	size_t len = 0;
+
+	for (; *src && count; --count)  {
+		s32 code = utf16_get(&src);
+
+		if (!code)
+			break;
+		if (code < 0)
+			/* Reserve space for a replacement character */
+			len += 1;
+		else if (code < 0x80)
+			len += 1;
+		else if (code < 0x800)
+			len += 2;
+		else if (code < 0x10000)
+			len += 3;
+		else
+			len += 4;
+	}
+	return len;
+}
+
+int utf16_utf8_strncpy(char **dst, const u16 *src, size_t count)
+{
+	if (!src || !dst || !*dst)
+		return -1;
+
+	for (; count && *src; --count) {
+		s32 code = utf16_get(&src);
+
+		if (code < 0)
+			code = '?';
+		utf8_put(code, dst);
+	}
+	**dst = 0;
+	return 0;
+}
+
+s32 utf_to_lower(const s32 code)
+{
+	struct capitalization_table *pos = capitalization_table;
+	s32 ret = code;
+
+	if (code <= 0x7f) {
+		if (code >= 'A' && code <= 'Z')
+			ret += 0x20;
+		return ret;
+	}
+	for (; pos->upper; ++pos) {
+		if (pos->upper == code) {
+			ret = pos->lower;
+			break;
+		}
+	}
+	return ret;
+}
+
+s32 utf_to_upper(const s32 code)
+{
+	struct capitalization_table *pos = capitalization_table;
+	s32 ret = code;
+
+	if (code <= 0x7f) {
+		if (code >= 'a' && code <= 'z')
+			ret -= 0x20;
+		return ret;
+	}
+	for (; pos->lower; ++pos) {
+		if (pos->lower == code) {
+			ret = pos->upper;
+			break;
+		}
+	}
+	return ret;
+}
+
+size_t u16_strlen(const u16 *in)
+{
+	size_t i;
+	for (i = 0; in[i]; i++);
+	return i;
+}
+
+size_t u16_strnlen(const u16 *in, size_t count)
+{
+	size_t i;
+	for (i = 0; count-- && in[i]; i++);
+	return i;
+}
+
 /* Convert UTF-16 to UTF-8.  */
 uint8_t *utf16_to_utf8(uint8_t *dest, const uint16_t *src, size_t size)
 {
@@ -95,61 +394,5 @@
 		}
 	}
 
-	return dest;
-}
-
-uint16_t *utf8_to_utf16(uint16_t *dest, const uint8_t *src, size_t size)
-{
-	while (size--) {
-		int extension_bytes;
-		uint32_t code;
-
-		extension_bytes = 0;
-		if (*src <= 0x7f) {
-			code = *src++;
-			/* Exit on zero byte */
-			if (!code)
-				size = 0;
-		} else if (*src <= 0xbf) {
-			/* Illegal code */
-			code = '?';
-		} else if (*src <= 0xdf) {
-			code = *src++ & 0x1f;
-			extension_bytes = 1;
-		} else if (*src <= 0xef) {
-			code = *src++ & 0x0f;
-			extension_bytes = 2;
-		} else if (*src <= 0xf7) {
-			code = *src++ & 0x07;
-			extension_bytes = 3;
-		} else {
-			/* Illegal code */
-			code = '?';
-		}
-
-		for (; extension_bytes && size; --size, --extension_bytes) {
-			if ((*src & 0xc0) == 0x80) {
-				code <<= 6;
-				code |= *src++ & 0x3f;
-			} else {
-				/* Illegal code */
-				code = '?';
-				++src;
-				--size;
-				break;
-			}
-		}
-
-		if (code < 0x10000) {
-			*dest++ = code;
-		} else {
-			/*
-			 * Simplified expression for
-			 * (((code - 0x10000) >> 10) & 0x3ff) | 0xd800
-			 */
-			*dest++ = (code >> 10) + 0xd7c0;
-			*dest++ = (code & 0x3ff) | 0xdc00;
-		}
-	}
 	return dest;
 }
diff --git a/lib/efi_driver/efi_uclass.c b/lib/efi_driver/efi_uclass.c
index b484aba..bb86ffd 100644
--- a/lib/efi_driver/efi_uclass.c
+++ b/lib/efi_driver/efi_uclass.c
@@ -19,11 +19,13 @@
 
 #include <efi_driver.h>
 
-/*
- * Check node type. We do not support partitions as controller handles.
+/**
+ * check_node_type() - check node type
  *
- * @handle	handle to be checked
- * @return	status code
+ * We do not support partitions as controller handles.
+ *
+ * @handle:	handle to be checked
+ * Return:	status code
  */
 static efi_status_t check_node_type(efi_handle_t handle)
 {
@@ -44,13 +46,13 @@
 	return ret;
 }
 
-/*
- * Check if the driver supports the controller.
+/**
+ * efi_uc_supported() - check if the driver supports the controller
  *
- * @this			driver binding protocol
- * @controller_handle		handle of the controller
- * @remaining_device_path	path specifying the child controller
- * @return			status code
+ * @this:			driver binding protocol
+ * @controller_handle:		handle of the controller
+ * @remaining_device_path:	path specifying the child controller
+ * Return:			status code
  */
 static efi_status_t EFIAPI efi_uc_supported(
 		struct efi_driver_binding_protocol *this,
@@ -92,13 +94,13 @@
 	return EFI_EXIT(ret);
 }
 
-/*
- * Create child controllers and attach driver.
+/**
+ * efi_uc_start() - create child controllers and attach driver
  *
- * @this			driver binding protocol
- * @controller_handle		handle of the controller
- * @remaining_device_path	path specifying the child controller
- * @return			status code
+ * @this:			driver binding protocol
+ * @controller_handle:		handle of the controller
+ * @remaining_device_path:	path specifying the child controller
+ * Return:			status code
  */
 static efi_status_t EFIAPI efi_uc_start(
 		struct efi_driver_binding_protocol *this,
@@ -146,12 +148,13 @@
 	return EFI_EXIT(ret);
 }
 
-/*
- * Remove a single child controller from the parent controller.
+/**
+ * disconnect_child() - remove a single child controller from the parent
+ *			controller
  *
- * @controller_handle	parent controller
- * @child_handle	child controller
- * @return		status code
+ * @controller_handle:	parent controller
+ * @child_handle:	child controller
+ * Return:		status code
  */
 static efi_status_t disconnect_child(efi_handle_t controller_handle,
 				     efi_handle_t child_handle)
@@ -176,14 +179,14 @@
 	return ret;
 }
 
-/*
- * Remove child controllers and disconnect the controller.
+/**
+ * efi_uc_stop() - Remove child controllers and disconnect the controller
  *
- * @this			driver binding protocol
- * @controller_handle		handle of the controller
- * @number_of_children		number of child controllers to remove
- * @child_handle_buffer		handles of the child controllers to remove
- * @return			status code
+ * @this:			driver binding protocol
+ * @controller_handle:		handle of the controller
+ * @number_of_children:		number of child controllers to remove
+ * @child_handle_buffer:	handles of the child controllers to remove
+ * Return:			status code
  */
 static efi_status_t EFIAPI efi_uc_stop(
 		struct efi_driver_binding_protocol *this,
@@ -241,6 +244,12 @@
 	return EFI_EXIT(ret);
 }
 
+/**
+ * efi_add_driver() - add driver
+ *
+ * @drv:		driver to add
+ * Return:		status code
+ */
 static efi_status_t efi_add_driver(struct driver *drv)
 {
 	efi_status_t ret;
@@ -280,11 +289,12 @@
 	return ret;
 }
 
-/*
- * Initialize the EFI drivers.
- * Called by board_init_r().
+/**
+ * efi_driver_init() - initialize the EFI drivers
+ *
+ * Called by efi_init_obj_list().
  *
- * @return	0 = success, any other value will stop further execution
+ * Return:	0 = success, any other value will stop further execution
  */
 efi_status_t efi_driver_init(void)
 {
@@ -309,12 +319,24 @@
 	return ret;
 }
 
+/**
+ * efi_uc_init() - initialize the EFI uclass
+ *
+ * @class:	the EFI uclass
+ * Return:	0 = success
+ */
 static int efi_uc_init(struct uclass *class)
 {
 	printf("EFI: Initializing UCLASS_EFI\n");
 	return 0;
 }
 
+/**
+ * efi_uc_destroy() - destroy the EFI uclass
+ *
+ * @class:	the EFI uclass
+ * Return:	0 = success
+ */
 static int efi_uc_destroy(struct uclass *class)
 {
 	printf("Destroying  UCLASS_EFI\n");
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index ce6a09f..b921ea8 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -1,6 +1,6 @@
 config EFI_LOADER
 	bool "Support running EFI Applications in U-Boot"
-	depends on (ARM || X86 || RISCV) && OF_LIBFDT
+	depends on (ARM || X86 || RISCV || SANDBOX) && OF_LIBFDT
 	# We need EFI_STUB_64BIT to be set on x86_64 with EFI_STUB
 	depends on !EFI_STUB || !X86_64 || EFI_STUB_64BIT
 	# We need EFI_STUB_32BIT to be set on x86_32 with EFI_STUB
@@ -15,6 +15,16 @@
 	  interfaces to a loaded EFI application, enabling it to reuse U-Boot's
 	  device drivers.
 
+config EFI_UNICODE_CAPITALIZATION
+	bool "Support Unicode capitalization"
+	depends on EFI_LOADER
+	default y
+	help
+	  Select this option to enable correct handling of the capitalization of
+	  Unicode codepoints in the range 0x0000-0xffff. If this option is not
+	  set, only the the correct handling of the letters of the codepage
+	  used by the FAT file system is ensured.
+
 config EFI_LOADER_BOUNCE_BUFFER
 	bool "EFI Applications use bounce buffers for DMA operations"
 	depends on EFI_LOADER && ARM64
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 1ffbf52..6703435 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -17,9 +17,19 @@
 endif
 
 obj-$(CONFIG_CMD_BOOTEFI_HELLO) += helloworld_efi.o
-obj-y += efi_image_loader.o efi_boottime.o efi_runtime.o efi_console.o
-obj-y += efi_memory.o efi_device_path_to_text.o efi_device_path.o
-obj-y += efi_device_path_utilities.o efi_file.o efi_variable.o efi_bootmgr.o
+obj-y += efi_bootmgr.o
+obj-y += efi_boottime.o
+obj-y += efi_console.o
+obj-y += efi_device_path.o
+obj-y += efi_device_path_to_text.o
+obj-y += efi_device_path_utilities.o
+obj-y += efi_file.o
+obj-y += efi_image_loader.o
+obj-y += efi_memory.o
+obj-y += efi_root_node.o
+obj-y += efi_runtime.o
+obj-y += efi_unicode_collation.o
+obj-y += efi_variable.o
 obj-y += efi_watchdog.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
diff --git a/lib/efi_loader/efi_bootmgr.c b/lib/efi_loader/efi_bootmgr.c
index 853358a..0c5764d 100644
--- a/lib/efi_loader/efi_bootmgr.c
+++ b/lib/efi_loader/efi_bootmgr.c
@@ -60,7 +60,7 @@
 	ptr += sizeof(u16);
 
 	lo->label = ptr;
-	ptr += (utf16_strlen(lo->label) + 1) * 2;
+	ptr += (u16_strlen(lo->label) + 1) * 2;
 
 	lo->file_path = ptr;
 	ptr += lo->file_path_length;
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index ca61e1a..97eb19c 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -26,14 +26,6 @@
 /* List of all events */
 LIST_HEAD(efi_events);
 
-/*
- * If we're running on nasty systems (32bit ARM booting into non-EFI Linux)
- * we need to do trickery with caches. Since we don't want to break the EFI
- * aware boot path, only apply hacks when loading exiting directly (breaking
- * direct Linux EFI booting along the way - oh well).
- */
-static bool efi_is_direct_boot = true;
-
 #ifdef CONFIG_ARM
 /*
  * The "gd" pointer lives in a register on ARM and AArch64 that we declare
@@ -105,8 +97,8 @@
 
 /*
  * Special case handler for error/abort that just forces things back to u-boot
- * world so we can dump out an abort msg, without any care about returning back
- * to UEFI world.
+ * world so we can dump out an abort message, without any care about returning
+ * back to UEFI world.
  */
 void efi_restore_gd(void)
 {
@@ -183,7 +175,7 @@
  * is_valid_tpl() - check if the task priority level is valid
  *
  * @tpl:		TPL level to check
- * ReturnValue:		status code
+ * Return:		status code
  */
 efi_status_t is_valid_tpl(efi_uintn_t tpl)
 {
@@ -626,7 +618,7 @@
 	evt->notify_function = notify_function;
 	evt->notify_context = notify_context;
 	evt->group = group;
-	/* Disable timers on bootup */
+	/* Disable timers on boot up */
 	evt->trigger_next = -1ULL;
 	evt->is_queued = false;
 	evt->is_signaled = false;
@@ -732,7 +724,7 @@
  * efi_set_timer() - set the trigger time for a timer event or stop the event
  * @event:        event for which the timer is set
  * @type:         type of the timer
- * @trigger_time: trigger period in multiples of 100ns
+ * @trigger_time: trigger period in multiples of 100 ns
  *
  * This is the function for internal usage in U-Boot. For the API function
  * implementing the SetTimer service see efi_set_timer_ext.
@@ -747,8 +739,8 @@
 		return EFI_INVALID_PARAMETER;
 
 	/*
-	 * The parameter defines a multiple of 100ns.
-	 * We use multiples of 1000ns. So divide by 10.
+	 * The parameter defines a multiple of 100 ns.
+	 * We use multiples of 1000 ns. So divide by 10.
 	 */
 	do_div(trigger_time, 10);
 
@@ -774,7 +766,7 @@
  *                       event
  * @event:        event for which the timer is set
  * @type:         type of the timer
- * @trigger_time: trigger period in multiples of 100ns
+ * @trigger_time: trigger period in multiples of 100 ns
  *
  * This function implements the SetTimer service.
  *
@@ -1061,7 +1053,7 @@
 /**
  * efi_get_drivers() - get all drivers associated to a controller
  * @efiobj:               handle of the controller
- * @protocol:             protocol guid (optional)
+ * @protocol:             protocol GUID (optional)
  * @number_of_drivers:    number of child controllers
  * @driver_handle_buffer: handles of the the drivers
  *
@@ -1126,7 +1118,7 @@
 /**
  * efi_disconnect_all_drivers() - disconnect all drivers from a controller
  * @efiobj:       handle of the controller
- * @protocol:     protocol guid (optional)
+ * @protocol:     protocol GUID (optional)
  * @child_handle: handle of the child to destroy
  *
  * This function implements the DisconnectController service.
@@ -1408,7 +1400,7 @@
 	if (!guid)
 		return EFI_INVALID_PARAMETER;
 
-	/* Check for guid override */
+	/* Check for GUID override */
 	for (i = 0; i < systab.nr_tables; i++) {
 		if (!guidcmp(guid, &systab.tables[i].guid)) {
 			if (table)
@@ -1432,7 +1424,7 @@
 	systab.nr_tables = i + 1;
 
 out:
-	/* systab.nr_tables may have changed. So we need to update the crc32 */
+	/* systab.nr_tables may have changed. So we need to update the CRC32 */
 	efi_update_table_header_crc32(&systab.hdr);
 
 	/* Notify that the configuration table was changed */
@@ -1478,20 +1470,35 @@
  *
  * Return: status code
  */
-efi_status_t efi_setup_loaded_image(
-			struct efi_loaded_image *info, struct efi_object *obj,
-			struct efi_device_path *device_path,
-			struct efi_device_path *file_path)
+efi_status_t efi_setup_loaded_image(struct efi_device_path *device_path,
+				    struct efi_device_path *file_path,
+				    struct efi_loaded_image_obj **handle_ptr,
+				    struct efi_loaded_image **info_ptr)
 {
 	efi_status_t ret;
+	struct efi_loaded_image *info;
+	struct efi_loaded_image_obj *obj;
+
+	info = calloc(1, sizeof(*info));
+	if (!info)
+		return EFI_OUT_OF_RESOURCES;
+	obj = calloc(1, sizeof(*obj));
+	if (!obj) {
+		free(info);
+		return EFI_OUT_OF_RESOURCES;
+	}
 
 	/* Add internal object to object list */
-	efi_add_handle(obj);
-	/* efi_exit() assumes that the handle points to the info */
-	obj->handle = info;
+	efi_add_handle(&obj->parent);
+
+	if (info_ptr)
+		*info_ptr = info;
+	if (handle_ptr)
+		*handle_ptr = obj;
 
 	info->revision =  EFI_LOADED_IMAGE_PROTOCOL_REVISION;
 	info->file_path = file_path;
+	info->system_table = &systab;
 
 	if (device_path) {
 		info->device_handle = efi_dp_find_obj(device_path, NULL);
@@ -1499,8 +1506,8 @@
 		 * When asking for the device path interface, return
 		 * bootefi_device_path
 		 */
-		ret = efi_add_protocol(obj->handle, &efi_guid_device_path,
-				       device_path);
+		ret = efi_add_protocol(obj->parent.handle,
+				       &efi_guid_device_path, device_path);
 		if (ret != EFI_SUCCESS)
 			goto failure;
 	}
@@ -1509,22 +1516,11 @@
 	 * When asking for the loaded_image interface, just
 	 * return handle which points to loaded_image_info
 	 */
-	ret = efi_add_protocol(obj->handle, &efi_guid_loaded_image, info);
+	ret = efi_add_protocol(obj->parent.handle,
+			       &efi_guid_loaded_image, info);
 	if (ret != EFI_SUCCESS)
 		goto failure;
 
-	ret = efi_add_protocol(obj->handle,
-			       &efi_guid_device_path_to_text_protocol,
-			       (void *)&efi_device_path_to_text);
-	if (ret != EFI_SUCCESS)
-		goto failure;
-
-	ret = efi_add_protocol(obj->handle,
-			       &efi_guid_device_path_utilities_protocol,
-			       (void *)&efi_device_path_utilities);
-	if (ret != EFI_SUCCESS)
-		goto failure;
-
 	return ret;
 failure:
 	printf("ERROR: Failure to install protocols for loaded image\n");
@@ -1604,7 +1600,8 @@
 					  efi_handle_t *image_handle)
 {
 	struct efi_loaded_image *info;
-	struct efi_object *obj;
+	struct efi_loaded_image_obj **image_obj =
+		(struct efi_loaded_image_obj **)image_handle;
 	efi_status_t ret;
 
 	EFI_ENTRY("%d, %p, %pD, %p, %zd, %p", boot_policy, parent_image,
@@ -1620,18 +1617,6 @@
 		goto error;
 	}
 
-	info = calloc(1, sizeof(*info));
-	if (!info) {
-		ret = EFI_OUT_OF_RESOURCES;
-		goto error;
-	}
-	obj = calloc(1, sizeof(*obj));
-	if (!obj) {
-		free(info);
-		ret = EFI_OUT_OF_RESOURCES;
-		goto error;
-	}
-
 	if (!source_buffer) {
 		struct efi_device_path *dp, *fp;
 
@@ -1643,35 +1628,35 @@
 		 * file parts:
 		 */
 		efi_dp_split_file_path(file_path, &dp, &fp);
-		ret = efi_setup_loaded_image(info, obj, dp, fp);
+		ret = efi_setup_loaded_image(dp, fp, image_obj, &info);
 		if (ret != EFI_SUCCESS)
 			goto failure;
 	} else {
-		/* In this case, file_path is the "device" path, ie.
+		/* In this case, file_path is the "device" path, i.e.
 		 * something like a HARDWARE_DEVICE:MEMORY_MAPPED
 		 */
-		ret = efi_setup_loaded_image(info, obj, file_path, NULL);
+		ret = efi_setup_loaded_image(file_path, NULL, image_obj, &info);
 		if (ret != EFI_SUCCESS)
-			goto failure;
+			goto error;
 	}
-	info->reserved = efi_load_pe(source_buffer, info);
-	if (!info->reserved) {
+	(*image_obj)->entry = efi_load_pe(*image_obj, source_buffer, info);
+	if (!(*image_obj)->entry) {
 		ret = EFI_UNSUPPORTED;
 		goto failure;
 	}
 	info->system_table = &systab;
 	info->parent_handle = parent_image;
-	*image_handle = obj->handle;
 	return EFI_EXIT(EFI_SUCCESS);
 failure:
+	efi_delete_handle(*image_handle);
+	*image_handle = NULL;
 	free(info);
-	efi_delete_handle(obj);
 error:
 	return EFI_EXIT(ret);
 }
 
 /**
- * efi_start_image() - dall the entry point of an image
+ * efi_start_image() - call the entry point of an image
  * @image_handle:   handle of the image
  * @exit_data_size: size of the buffer
  * @exit_data:      buffer to receive the exit data of the called image
@@ -1687,18 +1672,14 @@
 					   unsigned long *exit_data_size,
 					   s16 **exit_data)
 {
-	EFIAPI efi_status_t (*entry)(efi_handle_t image_handle,
-				     struct efi_system_table *st);
-	struct efi_loaded_image *info = image_handle;
+	struct efi_loaded_image_obj *image_obj =
+		(struct efi_loaded_image_obj *)image_handle;
 	efi_status_t ret;
 
 	EFI_ENTRY("%p, %p, %p", image_handle, exit_data_size, exit_data);
-	entry = info->reserved;
-
-	efi_is_direct_boot = false;
 
 	/* call the image! */
-	if (setjmp(&info->exit_jmp)) {
+	if (setjmp(&image_obj->exit_jmp)) {
 		/*
 		 * We called the entry point of the child image with EFI_CALL
 		 * in the lines below. The child image called the Exit() boot
@@ -1721,16 +1702,16 @@
 		assert(__efi_entry_check());
 		debug("%sEFI: %lu returned by started image\n",
 		      __efi_nesting_dec(),
-		      (unsigned long)((uintptr_t)info->exit_status &
+		      (unsigned long)((uintptr_t)image_obj->exit_status &
 				      ~EFI_ERROR_MASK));
-		return EFI_EXIT(info->exit_status);
+		return EFI_EXIT(image_obj->exit_status);
 	}
 
-	ret = EFI_CALL(entry(image_handle, &systab));
+	ret = EFI_CALL(image_obj->entry(image_handle, &systab));
 
 	/*
 	 * Usually UEFI applications call Exit() instead of returning.
-	 * But because the world doesn not consist of ponies and unicorns,
+	 * But because the world doesn't consist of ponies and unicorns,
 	 * we're happy to emulate that behavior on behalf of a payload
 	 * that forgot.
 	 */
@@ -1757,17 +1738,11 @@
 				    int16_t *exit_data)
 {
 	/*
-	 * We require that the handle points to the original loaded
-	 * image protocol interface.
-	 *
-	 * For getting the longjmp address this is safer than locating
-	 * the protocol because the protocol may have been reinstalled
-	 * pointing to another memory location.
-	 *
 	 * TODO: We should call the unload procedure of the loaded
 	 *	 image protocol.
 	 */
-	struct efi_loaded_image *loaded_image_info = (void *)image_handle;
+	struct efi_loaded_image_obj *image_obj =
+		(struct efi_loaded_image_obj *)image_handle;
 
 	EFI_ENTRY("%p, %ld, %ld, %p", image_handle, exit_status,
 		  exit_data_size, exit_data);
@@ -1781,8 +1756,8 @@
 	 */
 	efi_restore_gd();
 
-	loaded_image_info->exit_status = exit_status;
-	longjmp(&loaded_image_info->exit_jmp, 1);
+	image_obj->exit_status = exit_status;
+	longjmp(&image_obj->exit_jmp, 1);
 
 	panic("EFI application exited");
 }
@@ -1811,21 +1786,6 @@
 }
 
 /**
- * efi_exit_caches() - fix up caches for EFI payloads if necessary
- */
-static void efi_exit_caches(void)
-{
-#if defined(CONFIG_ARM) && !defined(CONFIG_ARM64)
-	/*
-	 * Grub on 32bit ARM needs to have caches disabled before jumping into
-	 * a zImage, but does not know of all cache layers. Give it a hand.
-	 */
-	if (efi_is_direct_boot)
-		cleanup_before_linux();
-#endif
-}
-
-/**
  * efi_exit_boot_services() - stop all boot services
  * @image_handle: handle of the loaded image
  * @map_key:      key of the memory map
@@ -1874,17 +1834,14 @@
 		}
 	}
 
-	/* TODO Should persist EFI variables here */
+	/* TODO: Should persist EFI variables here */
 
 	board_quiesce_devices();
 
-	/* Fix up caches for EFI payloads if necessary */
-	efi_exit_caches();
-
 	/* This stops all lingering devices */
 	bootm_disable_interrupts();
 
-	/* Disable boottime services */
+	/* Disable boot time services */
 	systab.con_in_handle = NULL;
 	systab.con_in = NULL;
 	systab.con_out_handle = NULL;
@@ -2118,7 +2075,7 @@
 		++*protocol_buffer_count;
 	}
 
-	/* Copy guids */
+	/* Copy GUIDs */
 	if (*protocol_buffer_count) {
 		size_t j = 0;
 
@@ -2709,7 +2666,7 @@
  * efi_connect_single_controller() - connect a single driver to a controller
  * @controller_handle:   controller
  * @driver_image_handle: driver
- * @remain_device_path:  remainting path
+ * @remain_device_path:  remaining path
  *
  * Return: status code
  */
@@ -2790,7 +2747,7 @@
  * details.
  *
  * First all driver binding protocol handles are tried for binding drivers.
- * Afterwards all handles that have openened a protocol of the controller
+ * Afterwards all handles that have opened a protocol of the controller
  * with EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER are connected to drivers.
  *
  * Return: status code
@@ -3123,7 +3080,7 @@
 /**
  * efi_initialize_system_table() - Initialize system table
  *
- * Return Value:        status code
+ * Return:	status code
  */
 efi_status_t efi_initialize_system_table(void)
 {
@@ -3135,7 +3092,7 @@
 				sizeof(struct efi_configuration_table),
 				(void **)&systab.tables);
 
-	/* Set crc32 field in table headers */
+	/* Set CRC32 field in table headers */
 	efi_update_table_header_crc32(&systab.hdr);
 	efi_update_table_header_crc32(&efi_runtime_services.hdr);
 	efi_update_table_header_crc32(&efi_boot_services.hdr);
diff --git a/lib/efi_loader/efi_console.c b/lib/efi_loader/efi_console.c
index b487288..7ecdbb1 100644
--- a/lib/efi_loader/efi_console.c
+++ b/lib/efi_loader/efi_console.c
@@ -42,10 +42,12 @@
 	},
 };
 
-const efi_guid_t efi_guid_text_output_protocol =
-			EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
+const efi_guid_t efi_guid_text_input_ex_protocol =
+			EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
 const efi_guid_t efi_guid_text_input_protocol =
 			EFI_SIMPLE_TEXT_INPUT_PROTOCOL_GUID;
+const efi_guid_t efi_guid_text_output_protocol =
+			EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL_GUID;
 
 #define cESC '\x1b'
 #define ESC "\x1b"
@@ -111,23 +113,28 @@
 {
 	struct simple_text_output_mode *con = &efi_con_mode;
 	struct cout_mode *mode = &efi_cout_modes[con->mode];
-
-	EFI_ENTRY("%p, %p", this, string);
-
-	unsigned int n16 = utf16_strlen(string);
-	char buf[MAX_UTF8_PER_UTF16 * n16 + 1];
+	char *buf, *pos;
 	u16 *p;
+	efi_status_t ret = EFI_SUCCESS;
 
-	*utf16_to_utf8((u8 *)buf, string, n16) = '\0';
+	EFI_ENTRY("%p, %p", this, string);
 
+	buf = malloc(utf16_utf8_strlen(string) + 1);
+	if (!buf) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+	pos = buf;
+	utf16_utf8_strcpy(&pos, string);
 	fputs(stdout, buf);
+	free(buf);
 
 	/*
 	 * Update the cursor position.
 	 *
 	 * The UEFI spec provides advance rules for U+0000, U+0008, U+000A,
 	 * and U000D. All other characters, including control characters
-	 * U+0007 (bel) and U+0009 (tab), have to increase the column by one.
+	 * U+0007 (BEL) and U+0009 (TAB), have to increase the column by one.
 	 */
 	for (p = string; *p; ++p) {
 		switch (*p) {
@@ -158,7 +165,8 @@
 		con->cursor_row = min(con->cursor_row, (s32)mode->rows - 1);
 	}
 
-	return EFI_EXIT(EFI_SUCCESS);
+out:
+	return EFI_EXIT(ret);
 }
 
 static efi_status_t EFIAPI efi_cout_test_string(
@@ -177,32 +185,56 @@
 	return (mode->rows == rows) && (mode->columns == cols);
 }
 
+/**
+ * query_console_serial() - query console size
+ *
+ * @rows	pointer to return number of rows
+ * @columns	pointer to return number of columns
+ * Returns	0 on success
+ */
 static int query_console_serial(int *rows, int *cols)
 {
-	/* Ask the terminal about its size */
-	int n[3];
+	int ret = 0;
+	int n[2];
 	u64 timeout;
 
 	/* Empty input buffer */
 	while (tstc())
 		getc();
 
-	printf(ESC"[18t");
+	/*
+	 * Not all terminals understand CSI [18t for querying the console size.
+	 * We should adhere to escape sequences documented in the console_codes
+	 * manpage and the ECMA-48 standard.
+	 *
+	 * So here we follow a different approach. We position the cursor to the
+	 * bottom right and query its position. Before leaving the function we
+	 * restore the original cursor position.
+	 */
+	printf(ESC "7"		/* Save cursor position */
+	       ESC "[r"		/* Set scrolling region to full window */
+	       ESC "[999;999H"	/* Move to bottom right corner */
+	       ESC "[6n");	/* Query cursor position */
 
-	/* Check if we have a terminal that understands */
+	/* Allow up to one second for a response */
 	timeout = timer_get_us() + 1000000;
 	while (!tstc())
-		if (timer_get_us() > timeout)
-			return -1;
-
-	/* Read {depth,rows,cols} */
-	if (term_read_reply(n, 3, 't'))
-		return -1;
+		if (timer_get_us() > timeout) {
+			ret = -1;
+			goto out;
+		}
 
-	*cols = n[2];
-	*rows = n[1];
+	/* Read {rows,cols} */
+	if (term_read_reply(n, 2, 'R')) {
+		ret = 1;
+		goto out;
+	}
 
-	return 0;
+	*cols = n[1];
+	*rows = n[0];
+out:
+	printf(ESC "8");	/* Restore cursor position */
+	return ret;
 }
 
 /*
@@ -298,8 +330,8 @@
 	{ 36, 46 },     /* 3: cyan */
 	{ 31, 41 },     /* 4: red */
 	{ 35, 45 },     /* 5: magenta */
-	{ 33, 43 },     /* 6: brown, map to yellow as edk2 does*/
-	{ 37, 47 },     /* 7: light grey, map to white */
+	{ 33, 43 },     /* 6: brown, map to yellow as EDK2 does*/
+	{ 37, 47 },     /* 7: light gray, map to white */
 };
 
 /* See EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute(). */
@@ -351,13 +383,31 @@
 			struct efi_simple_text_output_protocol *this,
 			unsigned long column, unsigned long row)
 {
+	efi_status_t ret = EFI_SUCCESS;
+	struct simple_text_output_mode *con = &efi_con_mode;
+	struct cout_mode *mode = &efi_cout_modes[con->mode];
+
 	EFI_ENTRY("%p, %ld, %ld", this, column, row);
 
-	printf(ESC"[%d;%df", (int)row, (int)column);
+	/* Check parameters */
+	if (!this) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+	if (row >= mode->rows || column >= mode->columns) {
+		ret = EFI_UNSUPPORTED;
+		goto out;
+	}
+
+	/*
+	 * Set cursor position by sending CSI H.
+	 * EFI origin is [0, 0], terminal origin is [1, 1].
+	 */
+	printf(ESC "[%d;%dH", (int)row + 1, (int)column + 1);
 	efi_con_mode.cursor_column = column;
 	efi_con_mode.cursor_row = row;
-
-	return EFI_EXIT(EFI_SUCCESS);
+out:
+	return EFI_EXIT(ret);
 }
 
 static efi_status_t EFIAPI efi_cout_enable_cursor(
@@ -384,29 +434,58 @@
 	.mode = (void*)&efi_con_mode,
 };
 
-static efi_status_t EFIAPI efi_cin_reset(
-			struct efi_simple_input_interface *this,
-			bool extended_verification)
-{
-	EFI_ENTRY("%p, %d", this, extended_verification);
+/**
+ * struct efi_cin_notify_function - registered console input notify function
+ *
+ * @link:	link to list
+ * @data:	key to notify
+ * @function:	function to call
+ */
+struct efi_cin_notify_function {
+	struct list_head link;
+	struct efi_key_data key;
+	efi_status_t (EFIAPI *function)
+		(struct efi_key_data *key_data);
+};
 
-	/* Empty input buffer */
-	while (tstc())
-		getc();
+static bool key_available;
+static struct efi_key_data next_key;
+static LIST_HEAD(cin_notify_functions);
 
-	return EFI_EXIT(EFI_SUCCESS);
+/**
+ * set_shift_mask() - set shift mask
+ *
+ * @mod:	Xterm shift mask
+ */
+void set_shift_mask(int mod, struct efi_key_state *key_state)
+{
+	key_state->key_shift_state = EFI_SHIFT_STATE_VALID;
+	if (mod) {
+		--mod;
+		if (mod & 1)
+			key_state->key_shift_state |= EFI_LEFT_SHIFT_PRESSED;
+		if (mod & 2)
+			key_state->key_shift_state |= EFI_LEFT_ALT_PRESSED;
+		if (mod & 4)
+			key_state->key_shift_state |= EFI_LEFT_CONTROL_PRESSED;
+		if (mod & 8)
+			key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
+	} else {
+		key_state->key_shift_state |= EFI_LEFT_LOGO_PRESSED;
+	}
 }
 
-/*
- * Analyze modifiers (shift, alt, ctrl) for function keys.
+/**
+ * analyze_modifiers() - analyze modifiers (shift, alt, ctrl) for function keys
+ *
  * This gets called when we have already parsed CSI.
  *
  * @modifiers:  bitmask (shift, alt, ctrl)
  * @return:	the unmodified code
  */
-static char skip_modifiers(int *modifiers)
+static int analyze_modifiers(struct efi_key_state *key_state)
 {
-	char c, mod = 0, ret = 0;
+	int c, mod = 0, ret = 0;
 
 	c = getc();
 
@@ -430,37 +509,38 @@
 		}
 	}
 out:
-	if (mod)
-		--mod;
-	if (modifiers)
-		*modifiers = mod;
+	set_shift_mask(mod, key_state);
 	if (!ret)
 		ret = c;
 	return ret;
 }
 
-static efi_status_t EFIAPI efi_cin_read_key_stroke(
-			struct efi_simple_input_interface *this,
-			struct efi_input_key *key)
+/**
+ * efi_cin_read_key() - read a key from the console input
+ *
+ * @key:	- key received
+ * Return:	- status code
+ */
+static efi_status_t efi_cin_read_key(struct efi_key_data *key)
 {
 	struct efi_input_key pressed_key = {
 		.scan_code = 0,
 		.unicode_char = 0,
 	};
-	char ch;
+	s32 ch;
 
-	EFI_ENTRY("%p, %p", this, key);
+	if (console_read_unicode(&ch))
+		return EFI_NOT_READY;
 
-	/* We don't do interrupts, so check for timers cooperatively */
-	efi_timer_check();
+	key->key_state.key_shift_state = EFI_SHIFT_STATE_INVALID;
+	key->key_state.key_toggle_state = EFI_TOGGLE_STATE_INVALID;
 
-	if (!tstc()) {
-		/* No key pressed */
-		return EFI_EXIT(EFI_NOT_READY);
-	}
+	/* We do not support multi-word codes */
+	if (ch >= 0x10000)
+		ch = '?';
 
-	ch = getc();
-	if (ch == cESC) {
+	switch (ch) {
+	case 0x1b:
 		/*
 		 * Xterm Control Sequences
 		 * https://www.xfree86.org/4.8.0/ctlseqs.html
@@ -472,14 +552,13 @@
 			break;
 		case 'O': /* F1 - F4 */
 			ch = getc();
-			/* skip modifiers */
-			if (ch <= '9')
+			/* consider modifiers */
+			if (ch < 'P') {
+				set_shift_mask(ch - '0', &key->key_state);
 				ch = getc();
+			}
 			pressed_key.scan_code = ch - 'P' + 11;
 			break;
-		case 'a'...'z':
-			ch = ch - 'a';
-			break;
 		case '[':
 			ch = getc();
 			switch (ch) {
@@ -493,7 +572,7 @@
 				pressed_key.scan_code = 5;
 				break;
 			case '1':
-				ch = skip_modifiers(NULL);
+				ch = analyze_modifiers(&key->key_state);
 				switch (ch) {
 				case '1'...'5': /* F1 - F5 */
 					pressed_key.scan_code = ch - '1' + 11;
@@ -513,7 +592,7 @@
 				}
 				break;
 			case '2':
-				ch = skip_modifiers(NULL);
+				ch = analyze_modifiers(&key->key_state);
 				switch (ch) {
 				case '0'...'1': /* F9 - F10 */
 					pressed_key.scan_code = ch - '0' + 19;
@@ -528,31 +607,406 @@
 				break;
 			case '3': /* DEL */
 				pressed_key.scan_code = 8;
-				skip_modifiers(NULL);
+				analyze_modifiers(&key->key_state);
 				break;
 			case '5': /* PG UP */
 				pressed_key.scan_code = 9;
-				skip_modifiers(NULL);
+				analyze_modifiers(&key->key_state);
 				break;
 			case '6': /* PG DOWN */
 				pressed_key.scan_code = 10;
-				skip_modifiers(NULL);
+				analyze_modifiers(&key->key_state);
 				break;
-			}
+			} /* [ */
 			break;
+		default:
+			/* ALT key */
+			set_shift_mask(3, &key->key_state);
 		}
-	} else if (ch == 0x7f) {
+		break;
+	case 0x7f:
 		/* Backspace */
 		ch = 0x08;
 	}
-	if (!pressed_key.scan_code)
+	if (pressed_key.scan_code) {
+		key->key_state.key_shift_state |= EFI_SHIFT_STATE_VALID;
+	} else {
 		pressed_key.unicode_char = ch;
-	*key = pressed_key;
 
-	return EFI_EXIT(EFI_SUCCESS);
+		/*
+		 * Assume left control key for control characters typically
+		 * entered using the control key.
+		 */
+		if (ch >= 0x01 && ch <= 0x1f) {
+			key->key_state.key_shift_state |=
+					EFI_SHIFT_STATE_VALID;
+			switch (ch) {
+			case 0x01 ... 0x07:
+			case 0x0b ... 0x0c:
+			case 0x0e ... 0x1f:
+				key->key_state.key_shift_state |=
+						EFI_LEFT_CONTROL_PRESSED;
+			}
+		}
+	}
+	key->key = pressed_key;
+
+	return EFI_SUCCESS;
+}
+
+/**
+ * efi_cin_notify() - notify registered functions
+ */
+static void efi_cin_notify(void)
+{
+	struct efi_cin_notify_function *item;
+
+	list_for_each_entry(item, &cin_notify_functions, link) {
+		bool match = true;
+
+		/* We do not support toggle states */
+		if (item->key.key.unicode_char || item->key.key.scan_code) {
+			if (item->key.key.unicode_char !=
+			    next_key.key.unicode_char ||
+			    item->key.key.scan_code != next_key.key.scan_code)
+				match = false;
+		}
+		if (item->key.key_state.key_shift_state &&
+		    item->key.key_state.key_shift_state !=
+		    next_key.key_state.key_shift_state)
+			match = false;
+
+		if (match)
+			/* We don't bother about the return code */
+			EFI_CALL(item->function(&next_key));
+	}
+}
+
+/**
+ * efi_cin_check() - check if keyboard input is available
+ */
+static void efi_cin_check(void)
+{
+	efi_status_t ret;
+
+	if (key_available) {
+		efi_signal_event(efi_con_in.wait_for_key, true);
+		return;
+	}
+
+	if (tstc()) {
+		ret = efi_cin_read_key(&next_key);
+		if (ret == EFI_SUCCESS) {
+			key_available = true;
+
+			/* Notify registered functions */
+			efi_cin_notify();
+
+			/* Queue the wait for key event */
+			if (key_available)
+				efi_signal_event(efi_con_in.wait_for_key, true);
+		}
+	}
+}
+
+/**
+ * efi_cin_empty_buffer() - empty input buffer
+ */
+static void efi_cin_empty_buffer(void)
+{
+	while (tstc())
+		getc();
+	key_available = false;
+}
+
+/**
+ * efi_cin_reset_ex() - reset console input
+ *
+ * @this:			- the extended simple text input protocol
+ * @extended_verification:	- extended verification
+ *
+ * This function implements the reset service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * Return: old value of the task priority level
+ */
+static efi_status_t EFIAPI efi_cin_reset_ex(
+		struct efi_simple_text_input_ex_protocol *this,
+		bool extended_verification)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %d", this, extended_verification);
+
+	/* Check parameters */
+	if (!this) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	efi_cin_empty_buffer();
+out:
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_read_key_stroke_ex() - read key stroke
+ *
+ * @this:	instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_data:	key read from console
+ * Return:	status code
+ *
+ * This function implements the ReadKeyStrokeEx service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_read_key_stroke_ex(
+		struct efi_simple_text_input_ex_protocol *this,
+		struct efi_key_data *key_data)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p", this, key_data);
+
+	/* Check parameters */
+	if (!this || !key_data) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+
+	/* Enable console input after ExitBootServices */
+	efi_cin_check();
+
+	if (!key_available) {
+		ret = EFI_NOT_READY;
+		goto out;
+	}
+	*key_data = next_key;
+	key_available = false;
+	efi_con_in.wait_for_key->is_signaled = false;
+out:
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_set_state() - set toggle key state
+ *
+ * @this:		instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_toggle_state:	key toggle state
+ * Return:		status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_set_state(
+		struct efi_simple_text_input_ex_protocol *this,
+		u8 key_toggle_state)
+{
+	EFI_ENTRY("%p, %u", this, key_toggle_state);
+	/*
+	 * U-Boot supports multiple console input sources like serial and
+	 * net console for which a key toggle state cannot be set at all.
+	 *
+	 * According to the UEFI specification it is allowable to not implement
+	 * this service.
+	 */
+	return EFI_EXIT(EFI_UNSUPPORTED);
+}
+
+/**
+ * efi_cin_register_key_notify() - register key notification function
+ *
+ * @this:			instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key_data:			key to be notified
+ * @key_notify_function:	function to be called if the key is pressed
+ * @notify_handle:		handle for unregistering the notification
+ * Return:			status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_register_key_notify(
+		struct efi_simple_text_input_ex_protocol *this,
+		struct efi_key_data *key_data,
+		efi_status_t (EFIAPI *key_notify_function)(
+			struct efi_key_data *key_data),
+		void **notify_handle)
+{
+	efi_status_t ret = EFI_SUCCESS;
+	struct efi_cin_notify_function *notify_function;
+
+	EFI_ENTRY("%p, %p, %p, %p",
+		  this, key_data, key_notify_function, notify_handle);
+
+	/* Check parameters */
+	if (!this || !key_data || !key_notify_function || !notify_handle) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	EFI_PRINT("u+%04x, sc %04x, sh %08x, tg %02x\n",
+		  key_data->key.unicode_char,
+	       key_data->key.scan_code,
+	       key_data->key_state.key_shift_state,
+	       key_data->key_state.key_toggle_state);
+
+	notify_function = calloc(1, sizeof(struct efi_cin_notify_function));
+	if (!notify_function) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+	notify_function->key = *key_data;
+	notify_function->function = key_notify_function;
+	list_add_tail(&notify_function->link, &cin_notify_functions);
+	*notify_handle = notify_function;
+out:
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_unregister_key_notify() - unregister key notification function
+ *
+ * @this:			instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @notification_handle:	handle received when registering
+ * Return:			status code
+ *
+ * This function implements the SetState service of the
+ * EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_unregister_key_notify(
+		struct efi_simple_text_input_ex_protocol *this,
+		void *notification_handle)
+{
+	efi_status_t ret = EFI_INVALID_PARAMETER;
+	struct efi_cin_notify_function *item, *notify_function =
+			notification_handle;
+
+	EFI_ENTRY("%p, %p", this, notification_handle);
+
+	/* Check parameters */
+	if (!this || !notification_handle)
+		goto out;
+
+	list_for_each_entry(item, &cin_notify_functions, link) {
+		if (item == notify_function) {
+			ret = EFI_SUCCESS;
+			break;
+		}
+	}
+	if (ret != EFI_SUCCESS)
+		goto out;
+
+	/* Remove the notify function */
+	list_del(&notify_function->link);
+	free(notify_function);
+out:
+	return EFI_EXIT(ret);
 }
 
-struct efi_simple_input_interface efi_con_in = {
+
+/**
+ * efi_cin_reset() - drain the input buffer
+ *
+ * @this:			instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @extended_verification:	allow for exhaustive verification
+ * Return:			status code
+ *
+ * This function implements the Reset service of the
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_reset
+			(struct efi_simple_text_input_protocol *this,
+			 bool extended_verification)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %d", this, extended_verification);
+
+	/* Check parameters */
+	if (!this) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	efi_cin_empty_buffer();
+out:
+	return EFI_EXIT(ret);
+}
+
+/**
+ * efi_cin_read_key_stroke() - read key stroke
+ *
+ * @this:	instance of the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ * @key:	key read from console
+ * Return:	status code
+ *
+ * This function implements the ReadKeyStroke service of the
+ * EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ */
+static efi_status_t EFIAPI efi_cin_read_key_stroke
+			(struct efi_simple_text_input_protocol *this,
+			 struct efi_input_key *key)
+{
+	efi_status_t ret = EFI_SUCCESS;
+
+	EFI_ENTRY("%p, %p", this, key);
+
+	/* Check parameters */
+	if (!this || !key) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+
+	/* We don't do interrupts, so check for timers cooperatively */
+	efi_timer_check();
+
+	/* Enable console input after ExitBootServices */
+	efi_cin_check();
+
+	if (!key_available) {
+		ret = EFI_NOT_READY;
+		goto out;
+	}
+	*key = next_key.key;
+	key_available = false;
+	efi_con_in.wait_for_key->is_signaled = false;
+out:
+	return EFI_EXIT(ret);
+}
+
+static struct efi_simple_text_input_ex_protocol efi_con_in_ex = {
+	.reset = efi_cin_reset_ex,
+	.read_key_stroke_ex = efi_cin_read_key_stroke_ex,
+	.wait_for_key_ex = NULL,
+	.set_state = efi_cin_set_state,
+	.register_key_notify = efi_cin_register_key_notify,
+	.unregister_key_notify = efi_cin_unregister_key_notify,
+};
+
+struct efi_simple_text_input_protocol efi_con_in = {
 	.reset = efi_cin_reset,
 	.read_key_stroke = efi_cin_read_key_stroke,
 	.wait_for_key = NULL,
@@ -560,31 +1014,38 @@
 
 static struct efi_event *console_timer_event;
 
-static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
-{
-}
-
 /*
- * Notification function of the console timer event.
+ * efi_console_timer_notify() - notify the console timer event
  *
- * event:	console timer event
- * context:	not used
+ * @event:	console timer event
+ * @context:	not used
  */
 static void EFIAPI efi_console_timer_notify(struct efi_event *event,
 					    void *context)
 {
 	EFI_ENTRY("%p, %p", event, context);
+	efi_cin_check();
+	EFI_EXIT(EFI_SUCCESS);
+}
 
-	/* Check if input is available */
-	if (tstc()) {
-		/* Queue the wait for key event */
-		efi_con_in.wait_for_key->is_signaled = true;
-		efi_signal_event(efi_con_in.wait_for_key, true);
-	}
+/**
+ * efi_key_notify() - notify the wait for key event
+ *
+ * @event:	wait for key event
+ * @context:	not used
+ */
+static void EFIAPI efi_key_notify(struct efi_event *event, void *context)
+{
+	EFI_ENTRY("%p, %p", event, context);
+	efi_cin_check();
 	EFI_EXIT(EFI_SUCCESS);
 }
 
-/* This gets called from do_bootefi_exec(). */
+/**
+ * efi_console_register() - install the console protocols
+ *
+ * This function is called from do_bootefi_exec().
+ */
 int efi_console_register(void)
 {
 	efi_status_t r;
@@ -598,17 +1059,27 @@
 	r = efi_create_handle((efi_handle_t *)&efi_console_output_obj);
 	if (r != EFI_SUCCESS)
 		goto out_of_memory;
+
 	r = efi_add_protocol(efi_console_output_obj->handle,
 			     &efi_guid_text_output_protocol, &efi_con_out);
 	if (r != EFI_SUCCESS)
 		goto out_of_memory;
+	systab.con_out_handle = efi_console_output_obj->handle;
+	systab.stderr_handle = efi_console_output_obj->handle;
+
 	r = efi_create_handle((efi_handle_t *)&efi_console_input_obj);
 	if (r != EFI_SUCCESS)
 		goto out_of_memory;
+
 	r = efi_add_protocol(efi_console_input_obj->handle,
 			     &efi_guid_text_input_protocol, &efi_con_in);
 	if (r != EFI_SUCCESS)
 		goto out_of_memory;
+	systab.con_in_handle = efi_console_input_obj->handle;
+	r = efi_add_protocol(efi_console_input_obj->handle,
+			     &efi_guid_text_input_ex_protocol, &efi_con_in_ex);
+	if (r != EFI_SUCCESS)
+		goto out_of_memory;
 
 	/* Create console events */
 	r = efi_create_event(EVT_NOTIFY_WAIT, TPL_CALLBACK, efi_key_notify,
@@ -617,6 +1088,7 @@
 		printf("ERROR: Failed to register WaitForKey event\n");
 		return r;
 	}
+	efi_con_in_ex.wait_for_key_ex = efi_con_in.wait_for_key;
 	r = efi_create_event(EVT_TIMER | EVT_NOTIFY_SIGNAL, TPL_CALLBACK,
 			     efi_console_timer_notify, NULL, NULL,
 			     &console_timer_event);
@@ -630,6 +1102,6 @@
 		printf("ERROR: Failed to set console timer\n");
 	return r;
 out_of_memory:
-	printf("ERROR: Out of meemory\n");
+	printf("ERROR: Out of memory\n");
 	return r;
 }
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index 9d776a6..5a61a1c 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -22,10 +22,6 @@
 	.length   = sizeof(END),
 };
 
-#define U_BOOT_GUID \
-	EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
-		 0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
-
 /* template ROOT node: */
 static const struct efi_device_path_vendor ROOT = {
 	.dp = {
diff --git a/lib/efi_loader/efi_device_path_to_text.c b/lib/efi_loader/efi_device_path_to_text.c
index ca8037d..0082236 100644
--- a/lib/efi_loader/efi_device_path_to_text.c
+++ b/lib/efi_loader/efi_device_path_to_text.c
@@ -17,6 +17,15 @@
 const efi_guid_t efi_guid_device_path_to_text_protocol =
 		EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
 
+/**
+ * efi_str_to_u16() - convert ASCII string to UTF-16
+ *
+ * A u16 buffer is allocated from pool. The ASCII string is copied to the u16
+ * buffer.
+ *
+ * @str:	ASCII string
+ * Return:	UTF-16 string. NULL if out of memory.
+ */
 static u16 *efi_str_to_u16(char *str)
 {
 	efi_uintn_t len;
@@ -29,7 +38,6 @@
 	if (ret != EFI_SUCCESS)
 		return NULL;
 	ascii2unicode(out, str);
-	out[len - 1] = 0;
 	return out;
 }
 
diff --git a/lib/efi_loader/efi_file.c b/lib/efi_loader/efi_file.c
index e6a15bc..0753a36 100644
--- a/lib/efi_loader/efi_file.c
+++ b/lib/efi_loader/efi_file.c
@@ -9,6 +9,7 @@
 #include <charset.h>
 #include <efi_loader.h>
 #include <malloc.h>
+#include <mapmem.h>
 #include <fs.h>
 
 /* GUID for file system information */
@@ -126,11 +127,22 @@
 	return 0;
 }
 
-/* NOTE: despite what you would expect, 'file_name' is actually a path.
- * With windoze style backlashes, ofc.
+/**
+ * file_open() - open a file handle
+ *
+ * @fs:			file system
+ * @parent:		directory relative to which the file is to be opened
+ * @file_name:		path of the file to be opened. '\', '.', or '..' may
+ *			be used as modifiers. A leading backslash indicates an
+ *			absolute path.
+ * @mode:		bit mask indicating the access mode (read, write,
+ *			create)
+ * @attributes:		attributes for newly created file
+ * Returns:		handle to the opened file or NULL
  */
 static struct efi_file_handle *file_open(struct file_system *fs,
-		struct file_handle *parent, s16 *file_name, u64 mode)
+		struct file_handle *parent, s16 *file_name, u64 mode,
+		u64 attributes)
 {
 	struct file_handle *fh;
 	char f0[MAX_UTF8_PER_UTF16] = {0};
@@ -139,7 +151,7 @@
 
 	if (file_name) {
 		utf16_to_utf8((u8 *)f0, (u16 *)file_name, 1);
-		flen = utf16_strlen((u16 *)file_name);
+		flen = u16_strlen((u16 *)file_name);
 	}
 
 	/* we could have a parent, but also an absolute path: */
@@ -173,7 +185,12 @@
 		if (set_blk_dev(fh))
 			goto error;
 
-		if (!((mode & EFI_FILE_MODE_CREATE) || fs_exists(fh->path)))
+		if ((mode & EFI_FILE_MODE_CREATE) &&
+		    (attributes & EFI_FILE_DIRECTORY)) {
+			if (fs_mkdir(fh->path))
+				goto error;
+		} else if (!((mode & EFI_FILE_MODE_CREATE) ||
+			     fs_exists(fh->path)))
 			goto error;
 
 		/* figure out if file is a directory: */
@@ -195,15 +212,46 @@
 		s16 *file_name, u64 open_mode, u64 attributes)
 {
 	struct file_handle *fh = to_fh(file);
+	efi_status_t ret;
 
 	EFI_ENTRY("%p, %p, \"%ls\", %llx, %llu", file, new_handle, file_name,
 		  open_mode, attributes);
 
-	*new_handle = file_open(fh->fs, fh, file_name, open_mode);
-	if (!*new_handle)
-		return EFI_EXIT(EFI_NOT_FOUND);
+	/* Check parameters */
+	if (!file || !new_handle || !file_name) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+	if (open_mode != EFI_FILE_MODE_READ &&
+	    open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE) &&
+	    open_mode != (EFI_FILE_MODE_READ | EFI_FILE_MODE_WRITE |
+			 EFI_FILE_MODE_CREATE)) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
+	/*
+	 * The UEFI spec requires that attributes are only set in create mode.
+	 * The SCT does not care about this and sets EFI_FILE_DIRECTORY in
+	 * read mode. EDK2 does not check that attributes are zero if not in
+	 * create mode.
+	 *
+	 * So here we only check attributes in create mode and do not check
+	 * that they are zero otherwise.
+	 */
+	if ((open_mode & EFI_FILE_MODE_CREATE) &&
+	    (attributes & (EFI_FILE_READ_ONLY | ~EFI_FILE_VALID_ATTR))) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
 
-	return EFI_EXIT(EFI_SUCCESS);
+	/* Open file */
+	*new_handle = file_open(fh->fs, fh, file_name, open_mode, attributes);
+	if (*new_handle)
+		ret = EFI_SUCCESS;
+	else
+		ret = EFI_NOT_FOUND;
+out:
+	return EFI_EXIT(ret);
 }
 
 static efi_status_t file_close(struct file_handle *fh)
@@ -223,9 +271,21 @@
 static efi_status_t EFIAPI efi_file_delete(struct efi_file_handle *file)
 {
 	struct file_handle *fh = to_fh(file);
+	efi_status_t ret = EFI_SUCCESS;
+
 	EFI_ENTRY("%p", file);
+
+	if (set_blk_dev(fh)) {
+		ret = EFI_DEVICE_ERROR;
+		goto error;
+	}
+
+	if (fs_unlink(fh->path))
+		ret = EFI_DEVICE_ERROR;
 	file_close(fh);
-	return EFI_EXIT(EFI_WARN_DELETE_FAILURE);
+
+error:
+	return EFI_EXIT(ret);
 }
 
 static efi_status_t file_read(struct file_handle *fh, u64 *buffer_size,
@@ -233,7 +293,7 @@
 {
 	loff_t actread;
 
-	if (fs_read(fh->path, (ulong)buffer, fh->offset,
+	if (fs_read(fh->path, map_to_sysmem(buffer), fh->offset,
 		    *buffer_size, &actread))
 		return EFI_DEVICE_ERROR;
 
@@ -363,7 +423,7 @@
 		goto error;
 	}
 
-	if (fs_write(fh->path, (ulong)buffer, fh->offset, *buffer_size,
+	if (fs_write(fh->path, map_to_sysmem(buffer), fh->offset, *buffer_size,
 		     &actwrite)) {
 		ret = EFI_DEVICE_ERROR;
 		goto error;
@@ -438,7 +498,7 @@
 	struct file_handle *fh = to_fh(file);
 	efi_status_t ret = EFI_SUCCESS;
 
-	EFI_ENTRY("%p, %p, %p, %p", file, info_type, buffer_size, buffer);
+	EFI_ENTRY("%p, %pUl, %p, %p", file, info_type, buffer_size, buffer);
 
 	if (!guidcmp(info_type, &efi_file_info_guid)) {
 		struct efi_file_info *info = buffer;
@@ -598,7 +658,7 @@
 
 	EFI_ENTRY("%p, %p", this, root);
 
-	*root = file_open(fs, NULL, NULL, 0);
+	*root = file_open(fs, NULL, NULL, 0, 0);
 
 	return EFI_EXIT(EFI_SUCCESS);
 }
diff --git a/lib/efi_loader/efi_image_loader.c b/lib/efi_loader/efi_image_loader.c
index fdf40a6..a18ce0a 100644
--- a/lib/efi_loader/efi_image_loader.c
+++ b/lib/efi_loader/efi_image_loader.c
@@ -48,20 +48,21 @@
  * If the program counter is located within the image the offset to the base
  * address is shown.
  *
+ * @obj:	EFI object
  * @image:	loaded image
  * @pc:		program counter (use NULL to suppress offset output)
  * @return:	status code
  */
-efi_status_t efi_print_image_info(struct efi_loaded_image *image, void *pc)
+static efi_status_t efi_print_image_info(struct efi_loaded_image_obj *obj,
+					 struct efi_loaded_image *image,
+					 void *pc)
 {
-	if (!image)
-		return EFI_INVALID_PARAMETER;
 	printf("UEFI image");
 	printf(" [0x%p:0x%p]",
-	       image->reloc_base, image->reloc_base + image->reloc_size - 1);
-	if (pc && pc >= image->reloc_base &&
-	    pc < image->reloc_base + image->reloc_size)
-		printf(" pc=0x%zx", pc - image->reloc_base);
+	       obj->reloc_base, obj->reloc_base + obj->reloc_size - 1);
+	if (pc && pc >= obj->reloc_base &&
+	    pc < obj->reloc_base + obj->reloc_size)
+		printf(" pc=0x%zx", pc - obj->reloc_base);
 	if (image->file_path)
 		printf(" '%pD'", image->file_path);
 	printf("\n");
@@ -82,6 +83,7 @@
 		list_for_each_entry(handler, &efiobj->protocols, link) {
 			if (!guidcmp(handler->guid, &efi_guid_loaded_image)) {
 				efi_print_image_info(
+					(struct efi_loaded_image_obj *)efiobj,
 					handler->protocol_interface, pc);
 			}
 		}
@@ -196,7 +198,8 @@
  * piece of memory. On successful load it then returns the entry point for
  * the binary. Otherwise NULL.
  */
-void *efi_load_pe(void *efi, struct efi_loaded_image *loaded_image_info)
+void *efi_load_pe(struct efi_loaded_image_obj *handle, void *efi,
+		  struct efi_loaded_image *loaded_image_info)
 {
 	IMAGE_NT_HEADERS32 *nt;
 	IMAGE_DOS_HEADER *dos;
@@ -314,8 +317,8 @@
 	/* Populate the loaded image interface bits */
 	loaded_image_info->image_base = efi;
 	loaded_image_info->image_size = image_size;
-	loaded_image_info->reloc_base = efi_reloc;
-	loaded_image_info->reloc_size = virt_size;
+	handle->reloc_base = efi_reloc;
+	handle->reloc_size = virt_size;
 
 	return entry;
 }
diff --git a/lib/efi_loader/efi_memory.c b/lib/efi_loader/efi_memory.c
index 0ac4ff5..5bd4f4d 100644
--- a/lib/efi_loader/efi_memory.c
+++ b/lib/efi_loader/efi_memory.c
@@ -65,9 +65,54 @@
 		return -1;
 }
 
+static uint64_t desc_get_end(struct efi_mem_desc *desc)
+{
+	return desc->physical_start + (desc->num_pages << EFI_PAGE_SHIFT);
+}
+
 static void efi_mem_sort(void)
 {
+	struct list_head *lhandle;
+	struct efi_mem_list *prevmem = NULL;
+	bool merge_again = true;
+
 	list_sort(NULL, &efi_mem, efi_mem_cmp);
+
+	/* Now merge entries that can be merged */
+	while (merge_again) {
+		merge_again = false;
+		list_for_each(lhandle, &efi_mem) {
+			struct efi_mem_list *lmem;
+			struct efi_mem_desc *prev = &prevmem->desc;
+			struct efi_mem_desc *cur;
+			uint64_t pages;
+
+			lmem = list_entry(lhandle, struct efi_mem_list, link);
+			if (!prevmem) {
+				prevmem = lmem;
+				continue;
+			}
+
+			cur = &lmem->desc;
+
+			if ((desc_get_end(cur) == prev->physical_start) &&
+			    (prev->type == cur->type) &&
+			    (prev->attribute == cur->attribute)) {
+				/* There is an existing map before, reuse it */
+				pages = cur->num_pages;
+				prev->num_pages += pages;
+				prev->physical_start -= pages << EFI_PAGE_SHIFT;
+				prev->virtual_start -= pages << EFI_PAGE_SHIFT;
+				list_del(&lmem->link);
+				free(lmem);
+
+				merge_again = true;
+				break;
+			}
+
+			prevmem = lmem;
+		}
+	}
 }
 
 /** efi_mem_carve_out - unmap memory region
@@ -303,7 +348,7 @@
 	switch (type) {
 	case EFI_ALLOCATE_ANY_PAGES:
 		/* Any page */
-		addr = efi_find_free_memory(len, gd->start_addr_sp);
+		addr = efi_find_free_memory(len, -1ULL);
 		if (!addr) {
 			r = EFI_NOT_FOUND;
 			break;
diff --git a/lib/efi_loader/efi_root_node.c b/lib/efi_loader/efi_root_node.c
new file mode 100644
index 0000000..b056ba3
--- /dev/null
+++ b/lib/efi_loader/efi_root_node.c
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  Root node for system services
+ *
+ *  Copyright (c) 2018 Heinrich Schuchardt
+ */
+
+#include <common.h>
+#include <malloc.h>
+#include <efi_loader.h>
+
+const efi_guid_t efi_u_boot_guid = U_BOOT_GUID;
+
+struct efi_root_dp {
+	struct efi_device_path_vendor vendor;
+	struct efi_device_path end;
+} __packed;
+
+/**
+ * efi_root_node_register() - create root node
+ *
+ * Create the root node on which we install all protocols that are
+ * not related to a loaded image or a driver.
+ *
+ * Return:	status code
+ */
+efi_status_t efi_root_node_register(void)
+{
+	efi_handle_t root;
+	efi_status_t ret;
+	struct efi_root_dp *dp;
+
+	/* Create handle */
+	ret = efi_create_handle(&root);
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	/* Install device path protocol */
+	dp = calloc(1, sizeof(*dp));
+	if (!dp)
+		return EFI_OUT_OF_RESOURCES;
+
+	/* Fill vendor node */
+	dp->vendor.dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+	dp->vendor.dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+	dp->vendor.dp.length = sizeof(struct efi_device_path_vendor);
+	dp->vendor.guid = efi_u_boot_guid;
+
+	/* Fill end node */
+	dp->end.type = DEVICE_PATH_TYPE_END;
+	dp->end.sub_type = DEVICE_PATH_SUB_TYPE_END;
+	dp->end.length = sizeof(struct efi_device_path);
+
+	/* Install device path protocol */
+	ret = efi_add_protocol(root, &efi_guid_device_path, dp);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
+	/* Install device path to text protocol */
+	ret = efi_add_protocol(root, &efi_guid_device_path_to_text_protocol,
+			       (void *)&efi_device_path_to_text);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
+	/* Install device path utilities protocol */
+	ret = efi_add_protocol(root, &efi_guid_device_path_utilities_protocol,
+			       (void *)&efi_device_path_utilities);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
+	/* Install Unicode collation protocol */
+	ret = efi_add_protocol(root, &efi_guid_unicode_collation_protocol,
+			       (void *)&efi_unicode_collation_protocol);
+	if (ret != EFI_SUCCESS)
+		goto failure;
+
+failure:
+	return ret;
+}
diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c
index 27136cb..c5fbd91 100644
--- a/lib/efi_loader/efi_runtime.c
+++ b/lib/efi_loader/efi_runtime.c
@@ -30,8 +30,9 @@
 static efi_status_t __efi_runtime EFIAPI efi_invalid_parameter(void);
 
 /*
- * TODO(sjg@chromium.org): These defines and structs should come from the elf
- * header for each arch (or a generic header) rather than being repeated here.
+ * TODO(sjg@chromium.org): These defines and structures should come from the ELF
+ * header for each architecture (or a generic header) rather than being repeated
+ * here.
  */
 #if defined(__aarch64__)
 #define R_RELATIVE	R_AARCH64_RELATIVE
@@ -79,7 +80,7 @@
 };
 
 /*
- * EFI Runtime code lives in 2 stages. In the first stage, U-Boot and an EFI
+ * EFI runtime code lives in two stages. In the first stage, U-Boot and an EFI
  * payload are running concurrently at the same time. In this mode, we can
  * handle a good number of runtime callbacks
  */
@@ -97,7 +98,7 @@
 }
 
 /**
- * efi_reset_system_boottime() - reset system at boottime
+ * efi_reset_system_boottime() - reset system at boot time
  *
  * This function implements the ResetSystem() runtime service before
  * SetVirtualAddressMap() is called.
@@ -144,7 +145,7 @@
 }
 
 /**
- * efi_get_time_boottime() - get current time at boottime
+ * efi_get_time_boottime() - get current time at boot time
  *
  * This function implements the GetTime runtime service before
  * SetVirtualAddressMap() is called.
@@ -335,7 +336,7 @@
 		*p = newaddr;
 	}
 
-	/* Update crc32 */
+	/* Update CRC32 */
 	efi_update_table_header_crc32(&efi_runtime_services.hdr);
 }
 
@@ -489,7 +490,7 @@
  * available at runtime.
  *
  * @mmio_ptr:		address of the memory-mapped IO region
- * @len:		size of thememory-mapped IO region
+ * @len:		size of the memory-mapped IO region
  * Returns:		status code
  */
 efi_status_t efi_add_runtime_mmio(void *mmio_ptr, u64 len)
@@ -607,7 +608,7 @@
  *
  * @capsule_header_array:	pointer to array of virtual pointers
  * @capsule_count:		number of pointers in capsule_header_array
- * @capsule_size:		maximum capsule size
+ * @maximum_capsule_size:	maximum capsule size
  * @reset_type:			type of reset needed for capsule update
  * Returns:			status code
  */
diff --git a/lib/efi_loader/efi_unicode_collation.c b/lib/efi_loader/efi_unicode_collation.c
new file mode 100644
index 0000000..7f3ea3c
--- /dev/null
+++ b/lib/efi_loader/efi_unicode_collation.c
@@ -0,0 +1,329 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * EFI Unicode collation protocol
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <cp1250.h>
+#include <cp437.h>
+#include <efi_loader.h>
+
+/* Characters that may not be used in file names */
+static const char illegal[] = "<>:\"/\\|?*";
+
+/*
+ * EDK2 assumes codepage 1250 when creating FAT 8.3 file names.
+ * Linux defaults to codepage 437 for FAT 8.3 file names.
+ */
+#if CONFIG_FAT_DEFAULT_CODEPAGE == 1250
+/* Unicode code points for code page 1250 characters 0x80 - 0xff */
+static const u16 codepage[] = CP1250;
+#else
+/* Unicode code points for code page 437 characters 0x80 - 0xff */
+static const u16 codepage[] = CP437;
+#endif
+
+/* GUID of the EFI_UNICODE_COLLATION_PROTOCOL */
+const efi_guid_t efi_guid_unicode_collation_protocol =
+	EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
+
+/**
+ * efi_stri_coll() - compare utf-16 strings case-insenitively
+ *
+ * @this:	unicode collation protocol instance
+ * @s1:		first string
+ * @s2:		second string
+ *
+ * This function implements the StriColl() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ *
+ * See the Unified Extensible Firmware Interface (UEFI) specification for
+ * details.
+ *
+ * TODO:
+ * The implementation does not follow the Unicode collation algorithm.
+ * For ASCII characters it results in the same sort order as EDK2.
+ * We could use table UNICODE_CAPITALIZATION_TABLE for better results.
+ *
+ * Return:	0: s1 == s2, > 0: s1 > s2, < 0: s1 < s2
+ */
+static efi_intn_t EFIAPI efi_stri_coll(
+		struct efi_unicode_collation_protocol *this, u16 *s1, u16 *s2)
+{
+	s32 c1, c2;
+	efi_intn_t ret = 0;
+
+	EFI_ENTRY("%p, %ls, %ls", this, s1, s2);
+	for (; *s1 | *s2; ++s1, ++s2) {
+		c1 = utf_to_upper(*s1);
+		c2 = utf_to_upper(*s2);
+		if (c1 < c2) {
+			ret = -1;
+			goto out;
+		} else if (c1 > c2) {
+			ret = 1;
+			goto out;
+		}
+	}
+out:
+	EFI_EXIT(EFI_SUCCESS);
+	return ret;
+}
+
+/**
+ * metai_match() - compare utf-16 string with a pattern string case-insenitively
+ *
+ * @s:		string to compare
+ * @p:		pattern string
+ *
+ * The pattern string may use these:
+ *	- * matches >= 0 characters
+ *	- ? matches 1 character
+ *	- [<char1><char2>...<charN>] match any character in the set
+ *	- [<char1>-<char2>] matches any character in the range
+ *
+ * This function is called my efi_metai_match().
+ *
+ * For '*' pattern searches this function calls itself recursively.
+ * Performance-wise this is suboptimal, especially for multiple '*' wildcards.
+ * But it results in simple code.
+ *
+ * Return:	true if the string is matched.
+ */
+static bool metai_match(const u16 *s, const u16 *p)
+{
+	u16 first;
+
+	for (; *s && *p; ++s, ++p) {
+		switch (*p) {
+		case '*':
+			/* Match 0 or more characters */
+			++p;
+			for (;; ++s) {
+				if (metai_match(s, p))
+					return true;
+				if (!*s)
+					return false;
+			}
+		case '?':
+			/* Match any one character */
+			break;
+		case '[':
+			/* Match any character in the set */
+			++p;
+			first = *p;
+			if (first == ']')
+				/* Empty set */
+				return false;
+			++p;
+			if (*p == '-') {
+				/* Range */
+				++p;
+				if (*s < first || *s > *p)
+					return false;
+				++p;
+				if (*p != ']')
+					return false;
+			} else {
+				/* Set */
+				bool hit = false;
+
+				if (*s == first)
+					hit = true;
+				for (; *p && *p != ']'; ++p) {
+					if (*p == *s)
+						hit = true;
+				}
+				if (!hit || *p != ']')
+					return false;
+			}
+			break;
+		default:
+			/* Match one character */
+			if (*p != *s)
+				return false;
+		}
+	}
+	if (!*p && !*s)
+		return true;
+	return false;
+}
+
+/**
+ * efi_metai_match() - compare utf-16 string with a pattern string
+ *		       case-insenitively
+ *
+ * @this:	unicode collation protocol instance
+ * @s:		string to compare
+ * @p:		pattern string
+ *
+ * The pattern string may use these:
+ *	- * matches >= 0 characters
+ *	- ? matches 1 character
+ *	- [<char1><char2>...<charN>] match any character in the set
+ *	- [<char1>-<char2>] matches any character in the range
+ *
+ * This function implements the MetaMatch() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ *
+ * Return:	true if the string is matched.
+ */
+static bool EFIAPI efi_metai_match(struct efi_unicode_collation_protocol *this,
+				   const u16 *string, const u16 *pattern)
+{
+	bool ret;
+
+	EFI_ENTRY("%p, %ls, %ls", this, string, pattern);
+	ret =  metai_match(string, pattern);
+	EFI_EXIT(EFI_SUCCESS);
+	return ret;
+}
+
+/**
+ * efi_str_lwr() - convert to lower case
+ *
+ * @this:	unicode collation protocol instance
+ * @string:	string to convert
+ * @p:		pattern string
+ *
+ * The conversion is done in place. As long as upper and lower letters use the
+ * same number of words this does not pose a problem.
+ *
+ * This function implements the StrLwr() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ */
+static void EFIAPI efi_str_lwr(struct efi_unicode_collation_protocol *this,
+			       u16 *string)
+{
+	EFI_ENTRY("%p, %ls", this, string);
+	for (; *string; ++string)
+		*string = utf_to_lower(*string);
+	EFI_EXIT(EFI_SUCCESS);
+}
+
+/**
+ * efi_str_upr() - convert to upper case
+ *
+ * @this:	unicode collation protocol instance
+ * @string:	string to convert
+ * @p:		pattern string
+ *
+ * The conversion is done in place. As long as upper and lower letters use the
+ * same number of words this does not pose a problem.
+ *
+ * This function implements the StrUpr() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ */
+static void EFIAPI efi_str_upr(struct efi_unicode_collation_protocol *this,
+			       u16 *string)
+{
+	EFI_ENTRY("%p, %ls", this, string);
+	for (; *string; ++string)
+		*string = utf_to_upper(*string);
+	EFI_EXIT(EFI_SUCCESS);
+}
+
+/**
+ * efi_fat_to_str() - convert an 8.3 file name from an OEM codepage to Unicode
+ *
+ * @this:	unicode collation protocol instance
+ * @fat_size:	size of the string to convert
+ * @fat:	string to convert
+ * @string:	converted string
+ *
+ * This function implements the FatToStr() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ */
+static void EFIAPI efi_fat_to_str(struct efi_unicode_collation_protocol *this,
+				  efi_uintn_t fat_size, char *fat, u16 *string)
+{
+	efi_uintn_t i;
+	u16 c;
+
+	EFI_ENTRY("%p, %zu, %s, %p", this, fat_size, fat, string);
+	for (i = 0; i < fat_size; ++i) {
+		c = (unsigned char)fat[i];
+		if (c > 0x80)
+			c = codepage[i - 0x80];
+		string[i] = c;
+		if (!c)
+			break;
+	}
+	string[i] = 0;
+	EFI_EXIT(EFI_SUCCESS);
+}
+
+/**
+ * efi_fat_to_str() - convert a utf-16 string to legal characters for a FAT
+ *                    file name in an OEM code page
+ *
+ * @this:	unicode collation protocol instance
+ * @string:	Unicode string to convert
+ * @fat_size:	size of the target buffer
+ * @fat:	converted string
+ *
+ * This function implements the StrToFat() service of the
+ * EFI_UNICODE_COLLATION_PROTOCOL.
+ *
+ * Return:	true if an illegal character was substituted by '_'.
+ */
+static bool EFIAPI efi_str_to_fat(struct efi_unicode_collation_protocol *this,
+				  const u16 *string, efi_uintn_t fat_size,
+				  char *fat)
+{
+	efi_uintn_t i;
+	s32 c;
+	bool ret = false;
+
+	EFI_ENTRY("%p, %ls, %zu, %p", this, string, fat_size, fat);
+	for (i = 0; i < fat_size;) {
+		c = utf16_get(&string);
+		switch (c) {
+		/* Ignore period and space */
+		case '.':
+		case ' ':
+			continue;
+		case 0:
+			break;
+		}
+		c = utf_to_upper(c);
+		if (c >= 0x80) {
+			int j;
+
+			/* Look for codepage translation */
+			for (j = 0; j < 0x80; ++j) {
+				if (c == codepage[j]) {
+					c = j + 0x80;
+					break;
+				}
+			}
+			if (j >= 0x80) {
+				c = '_';
+				ret = true;
+			}
+		} else if (c && (c < 0x20 || strchr(illegal, c))) {
+			c = '_';
+			ret = true;
+		}
+
+		fat[i] = c;
+		if (!c)
+			break;
+		++i;
+	}
+	EFI_EXIT(EFI_SUCCESS);
+	return ret;
+}
+
+const struct efi_unicode_collation_protocol efi_unicode_collation_protocol = {
+	.stri_coll = efi_stri_coll,
+	.metai_match = efi_metai_match,
+	.str_lwr = efi_str_lwr,
+	.str_upr = efi_str_upr,
+	.fat_to_str = efi_fat_to_str,
+	.str_to_fat = efi_str_to_fat,
+	.supported_languages = "en",
+};
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 90b6372..a1313fa 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -44,10 +44,7 @@
  * converted to utf16?
  */
 
-#define MAX_VAR_NAME 31
-#define MAX_NATIVE_VAR_NAME \
-	(strlen("efi_xxxxxxxx-xxxx-xxxx-xxxxxxxxxxxxxxxx_") + \
-		(MAX_VAR_NAME * MAX_UTF8_PER_UTF16))
+#define PREFIX_LEN (strlen("efi_xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx_"))
 
 static int hex(int ch)
 {
@@ -101,18 +98,20 @@
 	return hexstr;
 }
 
-static efi_status_t efi_to_native(char *native, u16 *variable_name,
+static efi_status_t efi_to_native(char **native, const u16 *variable_name,
 				  efi_guid_t *vendor)
 {
 	size_t len;
+	char *pos;
 
-	len = utf16_strlen((u16 *)variable_name);
-	if (len >= MAX_VAR_NAME)
-		return EFI_DEVICE_ERROR;
+	len = PREFIX_LEN + utf16_utf8_strlen(variable_name) + 1;
+	*native = malloc(len);
+	if (!*native)
+		return EFI_OUT_OF_RESOURCES;
 
-	native += sprintf(native, "efi_%pUl_", vendor);
-	native  = (char *)utf16_to_utf8((u8 *)native, (u16 *)variable_name, len);
-	*native = '\0';
+	pos = *native;
+	pos += sprintf(pos, "efi_%pUl_", vendor);
+	utf16_utf8_strcpy(&pos, variable_name);
 
 	return EFI_SUCCESS;
 }
@@ -168,7 +167,7 @@
 				     u32 *attributes, efi_uintn_t *data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name;
 	efi_status_t ret;
 	unsigned long in_size;
 	const char *val, *s;
@@ -180,13 +179,14 @@
 	if (!variable_name || !vendor || !data_size)
 		return EFI_EXIT(EFI_INVALID_PARAMETER);
 
-	ret = efi_to_native(native_name, variable_name, vendor);
+	ret = efi_to_native(&native_name, variable_name, vendor);
 	if (ret)
 		return EFI_EXIT(ret);
 
 	debug("%s: get '%s'\n", __func__, native_name);
 
 	val = env_get(native_name);
+	free(native_name);
 	if (!val)
 		return EFI_EXIT(EFI_NOT_FOUND);
 
@@ -256,35 +256,41 @@
 				     u32 attributes, efi_uintn_t data_size,
 				     void *data)
 {
-	char native_name[MAX_NATIVE_VAR_NAME + 1];
+	char *native_name = NULL, *val = NULL, *s;
 	efi_status_t ret = EFI_SUCCESS;
-	char *val, *s;
 	u32 attr;
 
 	EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
 		  data_size, data);
 
-	if (!variable_name || !vendor)
-		return EFI_EXIT(EFI_INVALID_PARAMETER);
+	if (!variable_name || !vendor) {
+		ret = EFI_INVALID_PARAMETER;
+		goto out;
+	}
 
-	ret = efi_to_native(native_name, variable_name, vendor);
+	ret = efi_to_native(&native_name, variable_name, vendor);
 	if (ret)
-		return EFI_EXIT(ret);
+		goto out;
 
 #define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
 
 	if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
 		/* delete the variable: */
 		env_set(native_name, NULL);
-		return EFI_EXIT(EFI_SUCCESS);
+		ret = EFI_SUCCESS;
+		goto out;
 	}
 
 	val = env_get(native_name);
 	if (val) {
 		parse_attr(val, &attr);
 
-		if (attr & READ_ONLY)
-			return EFI_EXIT(EFI_WRITE_PROTECTED);
+		if (attr & READ_ONLY) {
+			/* We should not free val */
+			val = NULL;
+			ret = EFI_WRITE_PROTECTED;
+			goto out;
+		}
 	}
 
 	val = malloc(2 * data_size + strlen("{ro,run,boot}(blob)") + 1);
@@ -320,6 +326,8 @@
 	if (env_set(native_name, val))
 		ret = EFI_DEVICE_ERROR;
 
+out:
+	free(native_name);
 	free(val);
 
 	return EFI_EXIT(ret);
diff --git a/lib/efi_selftest/Kconfig b/lib/efi_selftest/Kconfig
index 59f9f36..b526967 100644
--- a/lib/efi_selftest/Kconfig
+++ b/lib/efi_selftest/Kconfig
@@ -1,6 +1,6 @@
 config CMD_BOOTEFI_SELFTEST
 	bool "Allow booting an EFI efi_selftest"
-	depends on CMD_BOOTEFI
+	depends on CMD_BOOTEFI && !SANDBOX
 	imply FAT
 	imply FAT_WRITE
 	help
diff --git a/lib/efi_selftest/Makefile b/lib/efi_selftest/Makefile
index 590f90b..2f55d9d 100644
--- a/lib/efi_selftest/Makefile
+++ b/lib/efi_selftest/Makefile
@@ -24,12 +24,15 @@
 efi_selftest_exitbootservices.o \
 efi_selftest_fdt.o \
 efi_selftest_gop.o \
+efi_selftest_loaded_image.o \
 efi_selftest_manageprotocols.o \
 efi_selftest_rtc.o \
 efi_selftest_snp.o \
 efi_selftest_textinput.o \
+efi_selftest_textinputex.o \
 efi_selftest_textoutput.o \
 efi_selftest_tpl.o \
+efi_selftest_unicode_collation.o \
 efi_selftest_util.o \
 efi_selftest_variables.o \
 efi_selftest_watchdog.o
diff --git a/lib/efi_selftest/efi_selftest_console.c b/lib/efi_selftest/efi_selftest_console.c
index eb139c1..42f51b6 100644
--- a/lib/efi_selftest/efi_selftest_console.c
+++ b/lib/efi_selftest/efi_selftest_console.c
@@ -9,7 +9,7 @@
 #include <vsprintf.h>
 
 struct efi_simple_text_output_protocol *con_out;
-struct efi_simple_input_interface *con_in;
+struct efi_simple_text_input_protocol *con_in;
 
 /*
  * Print a MAC address to an u16 string
diff --git a/lib/efi_selftest/efi_selftest_loaded_image.c b/lib/efi_selftest/efi_selftest_loaded_image.c
new file mode 100644
index 0000000..f9b54ae
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_loaded_image.c
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_loaded_image
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * This unit test checks the Loaded Image Protocol.
+ */
+
+#include <efi_selftest.h>
+
+static efi_guid_t loaded_image_protocol_guid =
+	EFI_GUID(0x5b1b31a1, 0x9562, 0x11d2,
+		 0x8e, 0x3f, 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b);
+static struct efi_boot_services *boottime;
+efi_handle_t image_handle;
+
+/*
+ * Setup unit test.
+ *
+ * @handle:	handle of the loaded image
+ * @systable:	system table
+ */
+static int setup(const efi_handle_t img_handle,
+		 const struct efi_system_table *systable)
+{
+	boottime = systable->boottime;
+	image_handle = img_handle;
+
+	return EFI_ST_SUCCESS;
+}
+
+/*
+ * Execute unit test.
+ *
+ * Verify that the loaded image protocol is installed on the image handle.
+ * Verify that the loaded image protocol points to the system table.
+ */
+static int execute(void)
+{
+	efi_status_t ret;
+	efi_uintn_t i, protocol_buffer_count = 0;
+	efi_guid_t **protocol_buffer = NULL;
+	bool found = false;
+	struct efi_loaded_image *loaded_image_protocol;
+
+	/*
+	 * Get the GUIDs of all protocols installed on the handle.
+	 */
+	ret = boottime->protocols_per_handle(image_handle, &protocol_buffer,
+					     &protocol_buffer_count);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("ProtocolsPerHandle failed\n");
+		return EFI_ST_FAILURE;
+	}
+	if (!protocol_buffer_count | !protocol_buffer) {
+		efi_st_error("ProtocolsPerHandle returned no protocol\n");
+		return EFI_ST_FAILURE;
+	}
+	efi_st_printf("%u protocols installed on image handle\n",
+		      (unsigned int)protocol_buffer_count);
+	for (i = 0; i < protocol_buffer_count; ++i) {
+		if (efi_st_memcmp(protocol_buffer[i],
+				  &loaded_image_protocol_guid,
+				  sizeof(efi_guid_t)))
+			found = true;
+	}
+	if (!found) {
+		efi_st_printf("LoadedImageProtocol not found\n");
+		return EFI_ST_FAILURE;
+	}
+	ret = boottime->free_pool(protocol_buffer);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("FreePool failed\n");
+		return EFI_ST_FAILURE;
+	}
+
+	/*
+	 * Open the loaded image protocol.
+	 */
+	ret = boottime->open_protocol(image_handle, &loaded_image_protocol_guid,
+				      (void **)&loaded_image_protocol, NULL,
+				      NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("OpenProtocol failed\n");
+		return EFI_ST_FAILURE;
+	}
+	if (loaded_image_protocol->revision !=
+	    EFI_LOADED_IMAGE_PROTOCOL_REVISION) {
+		efi_st_printf("Incorrect revision\n");
+		return EFI_ST_FAILURE;
+	}
+	if (!loaded_image_protocol->system_table ||
+	    loaded_image_protocol->system_table->hdr.signature !=
+	    EFI_SYSTEM_TABLE_SIGNATURE) {
+		efi_st_printf("System table reference missing\n");
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(loadedimage) = {
+	.name = "loaded image",
+	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+	.setup = setup,
+	.execute = execute,
+};
diff --git a/lib/efi_selftest/efi_selftest_manageprotocols.c b/lib/efi_selftest/efi_selftest_manageprotocols.c
index 44b8da3..b09e4cd 100644
--- a/lib/efi_selftest/efi_selftest_manageprotocols.c
+++ b/lib/efi_selftest/efi_selftest_manageprotocols.c
@@ -179,7 +179,12 @@
 		efi_st_error("LocateHandleBuffer failed to locate new handle\n");
 		return EFI_ST_FAILURE;
 	}
-	boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
+	/* Release buffer */
+	ret = boottime->free_pool(buffer);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("FreePool failed\n");
+		return EFI_ST_FAILURE;
+	}
 
 	/*
 	 * Test error handling in UninstallMultipleProtocols
@@ -221,6 +226,7 @@
 		efi_st_error("LocateHandleBuffer failed to locate new handle\n");
 		return EFI_ST_FAILURE;
 	}
+	/* Clear the buffer, we are reusing it it the next step. */
 	boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
 
 	/*
@@ -248,7 +254,12 @@
 		efi_st_error("LocateHandle failed to locate new handles\n");
 		return EFI_ST_FAILURE;
 	}
-	boottime->set_mem(buffer, sizeof(efi_handle_t) * buffer_size, 0);
+	/* Release buffer */
+	ret = boottime->free_pool(buffer);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("FreePool failed\n");
+		return EFI_ST_FAILURE;
+	}
 
 	/*
 	 * Test LocateProtocol
@@ -319,6 +330,12 @@
 		efi_st_error("Failed to get protocols per handle\n");
 		return EFI_ST_FAILURE;
 	}
+	/* Release buffer */
+	ret = boottime->free_pool(prot_buffer);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("FreePool failed\n");
+		return EFI_ST_FAILURE;
+	}
 
 	/*
 	 * Uninstall remaining protocols
diff --git a/lib/efi_selftest/efi_selftest_textinput.c b/lib/efi_selftest/efi_selftest_textinput.c
index 7aa84de..164fbff 100644
--- a/lib/efi_selftest/efi_selftest_textinput.c
+++ b/lib/efi_selftest/efi_selftest_textinput.c
@@ -14,113 +14,8 @@
 
 #include <efi_selftest.h>
 
-struct translate {
-	u16 code;
-	u16 *text;
-};
-
 static struct efi_boot_services *boottime;
 
-static struct translate control_characters[] = {
-	{0, L"Null"},
-	{8, L"BS"},
-	{9, L"TAB"},
-	{10, L"LF"},
-	{13, L"CR"},
-	{0, NULL},
-};
-
-static u16 ch[] = L"' '";
-static u16 unknown[] = L"unknown";
-
-static struct translate scan_codes[] = {
-	{0x00, L"Null"},
-	{0x01, L"Up"},
-	{0x02, L"Down"},
-	{0x03, L"Right"},
-	{0x04, L"Left"},
-	{0x05, L"Home"},
-	{0x06, L"End"},
-	{0x07, L"Insert"},
-	{0x08, L"Delete"},
-	{0x09, L"Page Up"},
-	{0x0a, L"Page Down"},
-	{0x0b, L"FN 1"},
-	{0x0c, L"FN 2"},
-	{0x0d, L"FN 3"},
-	{0x0e, L"FN 4"},
-	{0x0f, L"FN 5"},
-	{0x10, L"FN 6"},
-	{0x11, L"FN 7"},
-	{0x12, L"FN 8"},
-	{0x13, L"FN 9"},
-	{0x14, L"FN 10"},
-	{0x15, L"FN 11"},
-	{0x16, L"FN 12"},
-	{0x17, L"Escape"},
-	{0x68, L"FN 13"},
-	{0x69, L"FN 14"},
-	{0x6a, L"FN 15"},
-	{0x6b, L"FN 16"},
-	{0x6c, L"FN 17"},
-	{0x6d, L"FN 18"},
-	{0x6e, L"FN 19"},
-	{0x6f, L"FN 20"},
-	{0x70, L"FN 21"},
-	{0x71, L"FN 22"},
-	{0x72, L"FN 23"},
-	{0x73, L"FN 24"},
-	{0x7f, L"Mute"},
-	{0x80, L"Volume Up"},
-	{0x81, L"Volume Down"},
-	{0x100, L"Brightness Up"},
-	{0x101, L"Brightness Down"},
-	{0x102, L"Suspend"},
-	{0x103, L"Hibernate"},
-	{0x104, L"Toggle Display"},
-	{0x105, L"Recovery"},
-	{0x106, L"Reject"},
-	{0x0, NULL},
-};
-
-/*
- * Translate a unicode character to a string.
- *
- * @code	unicode character
- * @return	string
- */
-static u16 *translate_char(u16 code)
-{
-	struct translate *tr;
-
-	if (code >= ' ') {
-		ch[1] = code;
-		return ch;
-	}
-	for (tr = control_characters; tr->text; ++tr) {
-		if (tr->code == code)
-			return tr->text;
-	}
-	return unknown;
-}
-
-/*
- * Translate a scan code to a human readable string.
- *
- * @code	unicode character
- * @return	string
- */
-static u16 *translate_code(u16 code)
-{
-	struct translate *tr;
-
-	for (tr = scan_codes; tr->text; ++tr) {
-		if (tr->code == code)
-			return tr->text;
-	}
-	return unknown;
-}
-
 /*
  * Setup unit test.
  *
@@ -145,24 +40,45 @@
 {
 	struct efi_input_key input_key = {0};
 	efi_status_t ret;
+	efi_uintn_t index;
+
+	/* Drain the console input */
+	ret = con_in->reset(con_in, true);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Reset failed\n");
+		return EFI_ST_FAILURE;
+	}
+	ret = con_in->read_key_stroke(con_in, &input_key);
+	if (ret != EFI_NOT_READY) {
+		efi_st_error("Empty buffer not reported\n");
+		return EFI_ST_FAILURE;
+	}
 
 	efi_st_printf("Waiting for your input\n");
 	efi_st_printf("To terminate type 'x'\n");
 
 	for (;;) {
 		/* Wait for next key */
-		do {
-			ret = con_in->read_key_stroke(con_in, &input_key);
-		} while (ret == EFI_NOT_READY);
+		ret = boottime->wait_for_event(1, &con_in->wait_for_key,
+					       &index);
+		if (ret != EFI_ST_SUCCESS) {
+			efi_st_error("WaitForEvent failed\n");
+			return EFI_ST_FAILURE;
+		}
+		ret = con_in->read_key_stroke(con_in, &input_key);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("ReadKeyStroke failed\n");
+			return EFI_ST_FAILURE;
+		}
 
 		/* Allow 5 minutes until time out */
 		boottime->set_watchdog_timer(300, 0, 0, NULL);
 
 		efi_st_printf("Unicode char %u (%ps), scan code %u (%ps)\n",
 			      (unsigned int)input_key.unicode_char,
-			      translate_char(input_key.unicode_char),
+			      efi_st_translate_char(input_key.unicode_char),
 			      (unsigned int)input_key.scan_code,
-			      translate_code(input_key.scan_code));
+			      efi_st_translate_code(input_key.scan_code));
 
 		switch (input_key.unicode_char) {
 		case 'x':
diff --git a/lib/efi_selftest/efi_selftest_textinputex.c b/lib/efi_selftest/efi_selftest_textinputex.c
new file mode 100644
index 0000000..de44224
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_textinputex.c
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_textinput
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Provides a unit test for the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+ * The unicode character and the scan code are printed for text
+ * input. To run the test:
+ *
+ *	setenv efi_selftest extended text input
+ *	bootefi selftest
+ */
+
+#include <efi_selftest.h>
+
+static const efi_guid_t text_input_ex_protocol_guid =
+		EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
+
+static struct efi_simple_text_input_ex_protocol *con_in_ex;
+
+static struct efi_boot_services *boottime;
+
+static void *efi_key_notify_handle;
+static bool efi_running;
+
+/**
+ * efi_key_notify_function() - key notification function
+ *
+ * This function is called when the registered key is hit.
+ *
+ * @key_data:		next key
+ * Return:		status code
+ */
+static efi_status_t EFIAPI efi_key_notify_function
+				(struct efi_key_data *key_data)
+{
+	efi_running = false;
+
+	return EFI_SUCCESS;
+}
+
+/*
+ * Setup unit test.
+ *
+ * @handle:	handle of the loaded image
+ * @systable:	system table
+ * @return:	EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+		 const struct efi_system_table *systable)
+{
+	efi_status_t ret;
+	struct efi_key_data key_data = {
+		.key = {
+			.scan_code = 0,
+			.unicode_char = 0x18
+		},
+		.key_state = {
+			.key_shift_state = EFI_SHIFT_STATE_VALID |
+					   EFI_LEFT_CONTROL_PRESSED,
+			.key_toggle_state = EFI_TOGGLE_STATE_INVALID,
+		},
+	};
+
+	boottime = systable->boottime;
+
+	ret = boottime->locate_protocol(&text_input_ex_protocol_guid, NULL,
+					(void **)&con_in_ex);
+	if (ret != EFI_SUCCESS) {
+		con_in_ex = NULL;
+		efi_st_error
+			("Extended text input protocol is not available.\n");
+		return EFI_ST_FAILURE;
+	}
+
+	ret = con_in_ex->register_key_notify(con_in_ex, &key_data,
+					     efi_key_notify_function,
+					     &efi_key_notify_handle);
+	if (ret != EFI_SUCCESS) {
+		efi_key_notify_handle = NULL;
+		efi_st_error
+			("Notify function could not be registered.\n");
+		return EFI_ST_FAILURE;
+	}
+	efi_running = true;
+
+	return EFI_ST_SUCCESS;
+}
+
+/*
+ * Tear down unit test.
+ *
+ * Unregister notify function.
+ *
+ * @return:	EFI_ST_SUCCESS for success
+ */
+static int teardown(void)
+{
+	efi_status_t ret;
+
+	ret = con_in_ex->unregister_key_notify
+			(con_in_ex, efi_key_notify_handle);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error
+			("Notify function could not be registered.\n");
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+/*
+ * Execute unit test.
+ *
+ * @return:	EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+	struct efi_key_data input_key = { {0, 0}, {0, 0} };
+	efi_status_t ret;
+	efi_uintn_t index;
+
+	if (!con_in_ex) {
+		efi_st_printf("Setup failed\n");
+		return EFI_ST_FAILURE;
+	}
+
+	/* Drain the console input */
+	ret = con_in_ex->reset(con_in_ex, true);
+	if (ret != EFI_SUCCESS) {
+		efi_st_error("Reset failed\n");
+		return EFI_ST_FAILURE;
+	}
+	ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
+	if (ret != EFI_NOT_READY) {
+		efi_st_error("Empty buffer not reported\n");
+		return EFI_ST_FAILURE;
+	}
+
+	efi_st_printf("Waiting for your input\n");
+	efi_st_printf("To terminate type 'CTRL+x'\n");
+
+	while (efi_running) {
+		/* Wait for next key */
+		ret = boottime->wait_for_event(1, &con_in_ex->wait_for_key_ex,
+					       &index);
+		if (ret != EFI_ST_SUCCESS) {
+			efi_st_error("WaitForEvent failed\n");
+			return EFI_ST_FAILURE;
+		}
+		ret = con_in_ex->read_key_stroke_ex(con_in_ex, &input_key);
+		if (ret != EFI_SUCCESS) {
+			efi_st_error("ReadKeyStroke failed\n");
+			return EFI_ST_FAILURE;
+		}
+
+		/* Allow 5 minutes until time out */
+		boottime->set_watchdog_timer(300, 0, 0, NULL);
+
+		efi_st_printf("Unicode char %u (%ps), scan code %u (",
+			      (unsigned int)input_key.key.unicode_char,
+			      efi_st_translate_char(input_key.key.unicode_char),
+			      (unsigned int)input_key.key.scan_code);
+		if (input_key.key_state.key_shift_state &
+		    EFI_SHIFT_STATE_VALID) {
+			if (input_key.key_state.key_shift_state &
+			    (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED))
+				efi_st_printf("SHIFT+");
+			if (input_key.key_state.key_shift_state &
+			    (EFI_LEFT_ALT_PRESSED | EFI_RIGHT_ALT_PRESSED))
+				efi_st_printf("ALT+");
+			if (input_key.key_state.key_shift_state &
+			    (EFI_LEFT_CONTROL_PRESSED |
+			     EFI_RIGHT_CONTROL_PRESSED))
+				efi_st_printf("CTRL+");
+			if (input_key.key_state.key_shift_state &
+			    (EFI_LEFT_LOGO_PRESSED | EFI_RIGHT_LOGO_PRESSED))
+				efi_st_printf("META+");
+			if (input_key.key_state.key_shift_state ==
+			    EFI_SHIFT_STATE_VALID)
+				efi_st_printf("+");
+		}
+
+		efi_st_printf("%ps)\n",
+			      efi_st_translate_code(input_key.key.scan_code));
+
+	}
+	return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(textinputex) = {
+	.name = "extended text input",
+	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+	.setup = setup,
+	.execute = execute,
+	.teardown = teardown,
+	.on_request = true,
+};
diff --git a/lib/efi_selftest/efi_selftest_unicode_collation.c b/lib/efi_selftest/efi_selftest_unicode_collation.c
new file mode 100644
index 0000000..9765bd3
--- /dev/null
+++ b/lib/efi_selftest/efi_selftest_unicode_collation.c
@@ -0,0 +1,260 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * efi_selftest_unicode_collation
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ *
+ * Test unicode collation protocol.
+ */
+
+#include <efi_selftest.h>
+
+static const efi_guid_t unicode_collation_protocol_guid =
+	EFI_UNICODE_COLLATION_PROTOCOL2_GUID;
+
+static struct efi_boot_services *boottime;
+
+static struct efi_unicode_collation_protocol *unicode_collation_protocol;
+
+/**
+ * setup() - setup unit test.
+ *
+ * @handle:	handle of the loaded image
+ * @systable:	system table
+ * ReturnValue:	EFI_ST_SUCCESS for success
+ */
+static int setup(const efi_handle_t handle,
+		 const struct efi_system_table *systable)
+{
+	efi_status_t ret;
+
+	boottime = systable->boottime;
+
+	ret = boottime->locate_protocol(&unicode_collation_protocol_guid, NULL,
+					(void **)&unicode_collation_protocol);
+	if (ret != EFI_SUCCESS) {
+		unicode_collation_protocol = NULL;
+		efi_st_error("Unicode collation protocol is not available.\n");
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_stri_coll(void)
+{
+	efi_intn_t ret;
+	u16 c1[] = L"first";
+	u16 c2[] = L"FIRST";
+	u16 c3[] = L"second";
+
+	ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
+						    c1, c2);
+	if (ret) {
+		efi_st_error(
+			"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c2, ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
+						    c1, c3);
+	if (ret >= 0) {
+		efi_st_error(
+			"stri_coll(\"%ps\", \"%ps\") = %zu\n", c1, c3, ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->stri_coll(unicode_collation_protocol,
+						    c3, c1);
+	if (ret <= 0) {
+		efi_st_error(
+			"stri_coll(\"%ps\", \"%ps\") = %zu\n", c3, c1, ret);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_metai_match(void)
+{
+	bool ret;
+	const u16 c[] = L"Das U-Boot";
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"*");
+	if (!ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da[rstu] U-Boot");
+	if (!ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da[q-v] U-Boot");
+	if (!ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da? U-Boot");
+	if (!ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"D*Bo*t");
+	if (!ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da[xyz] U-Boot");
+	if (ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da[a-d] U-Boot");
+	if (ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"Da?? U-Boot");
+	if (ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	ret = unicode_collation_protocol->metai_match(
+		unicode_collation_protocol, c, L"D*Bo*tt");
+	if (ret) {
+		efi_st_error("metai_match returned %u\n", ret);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_str_lwr(void)
+{
+	u16 c[] = L"U-Boot";
+
+	unicode_collation_protocol->str_lwr(unicode_collation_protocol, c);
+	if (efi_st_strcmp_16_8(c, "u-boot")) {
+		efi_st_error("str_lwr returned \"%ps\"\n", c);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_str_upr(void)
+{
+	u16 c[] = L"U-Boot";
+
+	unicode_collation_protocol->str_upr(unicode_collation_protocol, c);
+	if (efi_st_strcmp_16_8(c, "U-BOOT")) {
+		efi_st_error("str_lwr returned \"%ps\"\n", c);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_fat_to_str(void)
+{
+	u16 str[16];
+
+	boottime->set_mem(str, sizeof(str), 0);
+	unicode_collation_protocol->fat_to_str(unicode_collation_protocol, 6,
+					       "U-BOOT", str);
+	if (efi_st_strcmp_16_8(str, "U-BOOT")) {
+		efi_st_error("fat_to_str returned \"%ps\"\n", str);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+static int test_str_to_fat(void)
+{
+	char fat[16];
+	bool ret;
+
+	boottime->set_mem(fat, sizeof(fat), 0);
+	ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol,
+						     L"U -Boo.t", 6, fat);
+	if (ret || efi_st_strcmp_16_8(L"U-BOOT", fat)) {
+		efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat);
+		return EFI_ST_FAILURE;
+	}
+
+	boottime->set_mem(fat, 16, 0);
+	ret = unicode_collation_protocol->str_to_fat(unicode_collation_protocol,
+						     L"U\\Boot", 6, fat);
+	if (!ret || efi_st_strcmp_16_8(L"U_BOOT", fat)) {
+		efi_st_error("str_to_fat returned %u, \"%s\"\n", ret, fat);
+		return EFI_ST_FAILURE;
+	}
+
+	return EFI_ST_SUCCESS;
+}
+
+/**
+ * execute() - Execute unit test.
+ *
+ * ReturnValue:	EFI_ST_SUCCESS for success
+ */
+static int execute(void)
+{
+	int ret;
+
+	if (!unicode_collation_protocol) {
+		efi_st_printf("Unicode collation protocol missing\n");
+		return EFI_ST_FAILURE;
+	}
+
+	ret = test_stri_coll();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	ret = test_metai_match();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	ret = test_str_lwr();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	ret = test_str_upr();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	ret = test_fat_to_str();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	ret = test_str_to_fat();
+	if (ret != EFI_ST_SUCCESS)
+		return ret;
+
+	return EFI_ST_SUCCESS;
+}
+
+EFI_UNIT_TEST(unicoll) = {
+	.name = "unicode collation",
+	.phase = EFI_EXECUTE_BEFORE_BOOTTIME_EXIT,
+	.execute = execute,
+	.setup = setup,
+};
diff --git a/lib/efi_selftest/efi_selftest_util.c b/lib/efi_selftest/efi_selftest_util.c
index 87a04f8..96a964c 100644
--- a/lib/efi_selftest/efi_selftest_util.c
+++ b/lib/efi_selftest/efi_selftest_util.c
@@ -9,6 +9,99 @@
 
 #include <efi_selftest.h>
 
+struct efi_st_translate {
+	u16 code;
+	u16 *text;
+};
+
+static struct efi_st_translate efi_st_control_characters[] = {
+	{0, L"Null"},
+	{8, L"BS"},
+	{9, L"TAB"},
+	{10, L"LF"},
+	{13, L"CR"},
+	{0, NULL},
+};
+
+static u16 efi_st_ch[] = L"' '";
+static u16 efi_st_unknown[] = L"unknown";
+
+static struct efi_st_translate efi_st_scan_codes[] = {
+	{0x00, L"Null"},
+	{0x01, L"Up"},
+	{0x02, L"Down"},
+	{0x03, L"Right"},
+	{0x04, L"Left"},
+	{0x05, L"Home"},
+	{0x06, L"End"},
+	{0x07, L"Insert"},
+	{0x08, L"Delete"},
+	{0x09, L"Page Up"},
+	{0x0a, L"Page Down"},
+	{0x0b, L"FN 1"},
+	{0x0c, L"FN 2"},
+	{0x0d, L"FN 3"},
+	{0x0e, L"FN 4"},
+	{0x0f, L"FN 5"},
+	{0x10, L"FN 6"},
+	{0x11, L"FN 7"},
+	{0x12, L"FN 8"},
+	{0x13, L"FN 9"},
+	{0x14, L"FN 10"},
+	{0x15, L"FN 11"},
+	{0x16, L"FN 12"},
+	{0x17, L"Escape"},
+	{0x68, L"FN 13"},
+	{0x69, L"FN 14"},
+	{0x6a, L"FN 15"},
+	{0x6b, L"FN 16"},
+	{0x6c, L"FN 17"},
+	{0x6d, L"FN 18"},
+	{0x6e, L"FN 19"},
+	{0x6f, L"FN 20"},
+	{0x70, L"FN 21"},
+	{0x71, L"FN 22"},
+	{0x72, L"FN 23"},
+	{0x73, L"FN 24"},
+	{0x7f, L"Mute"},
+	{0x80, L"Volume Up"},
+	{0x81, L"Volume Down"},
+	{0x100, L"Brightness Up"},
+	{0x101, L"Brightness Down"},
+	{0x102, L"Suspend"},
+	{0x103, L"Hibernate"},
+	{0x104, L"Toggle Display"},
+	{0x105, L"Recovery"},
+	{0x106, L"Reject"},
+	{0x0, NULL},
+};
+
+u16 *efi_st_translate_char(u16 code)
+{
+	struct efi_st_translate *tr;
+
+	if (code >= ' ') {
+		efi_st_ch[1] = code;
+		return efi_st_ch;
+	}
+	for (tr = efi_st_control_characters; tr->text; ++tr) {
+		if (tr->code == code)
+			return tr->text;
+	}
+	return efi_st_unknown;
+}
+
+u16 *efi_st_translate_code(u16 code)
+{
+	struct efi_st_translate *tr;
+
+	for (tr = efi_st_scan_codes; tr->text; ++tr) {
+		if (tr->code == code)
+			return tr->text;
+	}
+	return efi_st_unknown;
+}
+
 int efi_st_memcmp(const void *buf1, const void *buf2, size_t length)
 {
 	const u8 *pos1 = buf1;
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index 914fbd3..4213441 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -274,28 +274,23 @@
 	return buf;
 }
 
+/* U-Boot uses UTF-16 strings in the EFI context only. */
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 static char *string16(char *buf, char *end, u16 *s, int field_width,
 		int precision, int flags)
 {
 	u16 *str = s ? s : L"<NULL>";
-	int utf16_len = utf16_strnlen(str, precision);
-	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
-	int utf8_len, i;
-
-	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
+	ssize_t len = utf16_strnlen(str, precision);
 
 	if (!(flags & LEFT))
-		while (utf8_len < field_width--)
+		for (; len < field_width; --field_width)
 			ADDCH(buf, ' ');
-	for (i = 0; i < utf8_len; ++i)
-		ADDCH(buf, utf8[i]);
-	while (utf8_len < field_width--)
+	utf16_utf8_strncpy(&buf, str, len);
+	for (; len < field_width; --field_width)
 		ADDCH(buf, ' ');
 	return buf;
 }
 
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
 static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 				int precision, int flags)
 {
@@ -450,8 +445,8 @@
 #endif
 
 	switch (*fmt) {
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+/* Device paths only exist in the EFI context. */
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 	case 'D':
 		return device_path_string(buf, end, ptr, field_width,
 					  precision, flags);
@@ -612,10 +607,14 @@
 			continue;
 
 		case 's':
-			if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
+/* U-Boot uses UTF-16 strings in the EFI context only. */
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
+			if (qualifier == 'l') {
 				str = string16(str, end, va_arg(args, u16 *),
 					       field_width, precision, flags);
-			} else {
+			} else
+#endif
+			{
 				str = string(str, end, va_arg(args, char *),
 					     field_width, precision, flags);
 			}
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index cf97b64..96d3f75 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -366,7 +366,6 @@
 CONFIG_DIALOG_POWER
 CONFIG_DIMM_SLOTS_PER_CTLR
 CONFIG_DIRECT_NOR_BOOT
-CONFIG_DISABLE_CONSOLE
 CONFIG_DISCONTIGMEM
 CONFIG_DISCOVER_PHY
 CONFIG_DISPLAY_AER_xxxx
@@ -3424,7 +3423,6 @@
 CONFIG_SYS_MFD
 CONFIG_SYS_MHZ
 CONFIG_SYS_MII_MODE
-CONFIG_SYS_MIPS_CACHE_MODE
 CONFIG_SYS_MIPS_TIMER_FREQ
 CONFIG_SYS_MMCSD_FS_BOOT_PARTITION
 CONFIG_SYS_MMCSD_RAW_MODE_ARGS_SECTOR
@@ -4070,7 +4068,6 @@
 CONFIG_SYS_RTC_BUS_NUM
 CONFIG_SYS_RTC_CNT
 CONFIG_SYS_RTC_OSCILLATOR
-CONFIG_SYS_RTC_PL031_BASE
 CONFIG_SYS_RTC_REG_BASE_ADDR
 CONFIG_SYS_RTC_SETUP
 CONFIG_SYS_RV3029_TCR
@@ -4101,7 +4098,6 @@
 CONFIG_SYS_SCCR_USBMPHCM
 CONFIG_SYS_SCR
 CONFIG_SYS_SCRATCH_VA
-CONFIG_SYS_SCSI_MAXDEVICE
 CONFIG_SYS_SCSI_MAX_DEVICE
 CONFIG_SYS_SCSI_MAX_LUN
 CONFIG_SYS_SCSI_MAX_SCSI_ID
@@ -4421,7 +4417,6 @@
 CONFIG_SYS_XHCI_USB2_ADDR
 CONFIG_SYS_XHCI_USB3_ADDR
 CONFIG_SYS_XIMG_LEN
-CONFIG_SYS_XWAY_EBU_BOOTCFG
 CONFIG_SYS_ZYNQ_QSPI_WAIT
 CONFIG_SYS_ZYNQ_SPI_WAIT
 CONFIG_SYS_i2C_FSL
diff --git a/test/Kconfig b/test/Kconfig
index 3643761..de16d17 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -15,6 +15,14 @@
 	  problems. But if you are having problems with udelay() and the like,
 	  this is a good place to start.
 
+config UT_UNICODE
+	bool "Unit tests for Unicode functions"
+	depends on UNIT_TEST
+	default y
+	help
+	  Enables the 'ut unicode' command which tests that the functions for
+	  manipulating Unicode strings work correctly.
+
 source "test/dm/Kconfig"
 source "test/env/Kconfig"
 source "test/overlay/Kconfig"
diff --git a/test/Makefile b/test/Makefile
index 1092011..a5f52fd 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -8,4 +8,5 @@
 obj-$(CONFIG_SANDBOX) += compression.o
 obj-$(CONFIG_SANDBOX) += print_ut.o
 obj-$(CONFIG_UT_TIME) += time_ut.o
+obj-$(CONFIG_UT_UNICODE) += unicode_ut.o
 obj-$(CONFIG_$(SPL_)LOG) += log/
diff --git a/test/cmd_ut.c b/test/cmd_ut.c
index 934a5a9..b7e01a4 100644
--- a/test/cmd_ut.c
+++ b/test/cmd_ut.c
@@ -49,6 +49,9 @@
 #ifdef CONFIG_UT_TIME
 	U_BOOT_CMD_MKENT(time, CONFIG_SYS_MAXARGS, 1, do_ut_time, "", ""),
 #endif
+#if CONFIG_IS_ENABLED(UT_UNICODE) && !defined(API_BUILD)
+	U_BOOT_CMD_MKENT(unicode, CONFIG_SYS_MAXARGS, 1, do_ut_unicode, "", ""),
+#endif
 #ifdef CONFIG_SANDBOX
 	U_BOOT_CMD_MKENT(compression, CONFIG_SYS_MAXARGS, 1, do_ut_compression,
 			 "", ""),
@@ -93,6 +96,9 @@
 #ifdef CONFIG_SYS_LONGHELP
 static char ut_help_text[] =
 	"all - execute all enabled tests\n"
+#ifdef CONFIG_SANDBOX
+	"ut compression - Test compressors and bootm decompression\n"
+#endif
 #ifdef CONFIG_UT_DM
 	"ut dm [test-name]\n"
 #endif
@@ -105,11 +111,12 @@
 #ifdef CONFIG_UT_TIME
 	"ut time - Very basic test of time functions\n"
 #endif
-#ifdef CONFIG_SANDBOX
-	"ut compression - Test compressors and bootm decompression\n"
+#if defined(CONFIG_UT_UNICODE) && \
+	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+	"ut unicode [test-name] - test Unicode functions\n"
 #endif
 	;
-#endif
+#endif /* CONFIG_SYS_LONGHELP */
 
 U_BOOT_CMD(
 	ut, CONFIG_SYS_MAXARGS, 1, do_ut,
diff --git a/test/fs/fs-test.sh b/test/fs/fs-test.sh
index 9482239..86308cf 100755
--- a/test/fs/fs-test.sh
+++ b/test/fs/fs-test.sh
@@ -7,18 +7,20 @@
 # It currently tests the fs/sb and native commands for ext4 and fat partitions
 # Expected results are as follows:
 # EXT4 tests:
-# fs-test.sb.ext4.out: Summary: PASS: 24 FAIL: 0
-# fs-test.ext4.out: Summary: PASS: 24 FAIL: 0
-# fs-test.fs.ext4.out: Summary: PASS: 24 FAIL: 0
+# fs-test.sb.ext4	Summary: PASS: 24 FAIL: 0
+# fs-test.nonfs.ext4	Summary: PASS: 24 FAIL: 0
+# fs-test.fs.ext4	Summary: PASS: 24 FAIL: 0
 # FAT16 tests:
-# fs-test.sb.fat16.out: Summary: PASS: 24 FAIL: 0
-# fs-test.fat16.out: Summary: PASS: 20 FAIL: 4
-# fs-test.fs.fat16.out: Summary: PASS: 20 FAIL: 4
+# fs-test.sb.fat16	Summary: PASS: 24 FAIL: 0
+# fs-test.nonfs.fat16	Summary: PASS: 24 FAIL: 0
+# fs-test.fs.fat16	Summary: PASS: 24 FAIL: 0
 # FAT32 tests:
-# fs-test.sb.fat32.out: Summary: PASS: 24 FAIL: 0
-# fs-test.fat32.out: Summary: PASS: 20 FAIL: 4
-# fs-test.fs.fat32.out: Summary: PASS: 20 FAIL: 4
-# Total Summary: TOTAL PASS: 200 TOTAL FAIL: 16
+# fs-test.sb.fat32	Summary: PASS: 24 FAIL: 0
+# fs-test.nonfs.fat32	Summary: PASS: 24 FAIL: 0
+# fs-test.fs.fat32	Summary: PASS: 24 FAIL: 0
+# --------------------------------------------
+# Total Summary: TOTAL PASS: 216 TOTAL FAIL: 0
+# --------------------------------------------
 
 # pre-requisite binaries list.
 PREREQ_BINS="md5sum mkfs mount umount dd fallocate mkdir"
@@ -522,7 +524,7 @@
 		"TC11: 1MB write to $3.w - content verified"
 
 	# Check lookup of 'dot' directory
-	grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write file'
+	grep -A4 "Test Case 12 " "$1" | grep -q 'Unable to write'
 	pass_fail "TC12: 1MB write to . - write denied"
 
 	# Check directory traversal
diff --git a/test/print_ut.c b/test/print_ut.c
index fb46db8..f0f1d60 100644
--- a/test/print_ut.c
+++ b/test/print_ut.c
@@ -6,8 +6,7 @@
 #define DEBUG
 
 #include <common.h>
-#if defined(CONFIG_EFI_LOADER) && \
-	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 #include <efi_api.h>
 #endif
 #include <display_options.h>
@@ -19,8 +18,7 @@
 /* Test efi_loader specific printing */
 static void efi_ut_print(void)
 {
-#if defined(CONFIG_EFI_LOADER) && \
-    !defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 	char str[10];
 	u8 buf[sizeof(struct efi_device_path_sd_mmc_path) +
 	       sizeof(struct efi_device_path)];
diff --git a/test/py/tests/test_efi_selftest.py b/test/py/tests/test_efi_selftest.py
index 747d52d..e0833ff 100644
--- a/test/py/tests/test_efi_selftest.py
+++ b/test/py/tests/test_efi_selftest.py
@@ -16,7 +16,7 @@
 	u_boot_console.run_command(cmd='bootefi selftest', wait_for_prompt=False)
 	m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
 	if m != 0:
-		raise Exception('Failures occured during the EFI selftest')
+		raise Exception('Failures occurred during the EFI selftest')
 	u_boot_console.run_command(cmd='', wait_for_echo=False, wait_for_prompt=False);
 	m = u_boot_console.p.expect(['resetting', 'U-Boot'])
 	if m != 0:
@@ -48,3 +48,152 @@
 	if m != 0:
 		raise Exception('Reset failed in \'watchdog reboot\' test')
 	u_boot_console.restart_uboot();
+
+@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
+def test_efi_selftest_text_input(u_boot_console):
+	"""Test the EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+
+	:param u_boot_console: U-Boot console
+
+	This function calls the text input EFI selftest.
+	"""
+	u_boot_console.run_command(cmd='setenv efi_selftest text input')
+	output = u_boot_console.run_command(cmd='bootefi selftest',
+					    wait_for_prompt=False)
+	m = u_boot_console.p.expect(['To terminate type \'x\''])
+	if m != 0:
+		raise Exception('No prompt for \'text input\' test')
+	u_boot_console.drain_console()
+	u_boot_console.p.timeout = 500
+	# EOT
+	u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 4 \(unknown\), scan code 0 \(Null\)'])
+	if m != 0:
+		raise Exception('EOT failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# BS
+	u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 8 \(BS\), scan code 0 \(Null\)'])
+	if m != 0:
+		raise Exception('BS failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# TAB
+	u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 9 \(TAB\), scan code 0 \(Null\)'])
+	if m != 0:
+		raise Exception('BS failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# a
+	u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
+				   wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
+	if m != 0:
+		raise Exception('\'a\' failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# UP escape sequence
+	u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 0 \(Null\), scan code 1 \(Up\)'])
+	if m != 0:
+		raise Exception('UP failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# Euro sign
+	u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
+	if m != 0:
+		raise Exception('Euro sign failed in \'text input\' test')
+	u_boot_console.drain_console()
+	u_boot_console.run_command(cmd='x', wait_for_echo=False, send_nl=False,
+				   wait_for_prompt=False)
+	m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
+	if m != 0:
+		raise Exception('Failures occurred during the EFI selftest')
+	u_boot_console.restart_uboot();
+
+@pytest.mark.buildconfigspec('cmd_bootefi_selftest')
+def test_efi_selftest_text_input_ex(u_boot_console):
+	"""Test the EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
+
+	:param u_boot_console: U-Boot console
+
+	This function calls the extended text input EFI selftest.
+	"""
+	u_boot_console.run_command(cmd='setenv efi_selftest extended text input')
+	output = u_boot_console.run_command(cmd='bootefi selftest',
+					    wait_for_prompt=False)
+	m = u_boot_console.p.expect(['To terminate type \'CTRL\+x\''])
+	if m != 0:
+		raise Exception('No prompt for \'text input\' test')
+	u_boot_console.drain_console()
+	u_boot_console.p.timeout = 500
+	# EOT
+	u_boot_console.run_command(cmd=chr(4), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 4 \(unknown\), scan code 0 \(CTRL\+Null\)'])
+	if m != 0:
+		raise Exception('EOT failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# BS
+	u_boot_console.run_command(cmd=chr(8), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 8 \(BS\), scan code 0 \(\+Null\)'])
+	if m != 0:
+		raise Exception('BS failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# TAB
+	u_boot_console.run_command(cmd=chr(9), wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 9 \(TAB\), scan code 0 \(\+Null\)'])
+	if m != 0:
+		raise Exception('TAB failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# a
+	u_boot_console.run_command(cmd='a', wait_for_echo=False, send_nl=False,
+				   wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 97 \(\'a\'\), scan code 0 \(Null\)'])
+	if m != 0:
+		raise Exception('\'a\' failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# UP escape sequence
+	u_boot_console.run_command(cmd=chr(27) + '[A', wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 0 \(Null\), scan code 1 \(\+Up\)'])
+	if m != 0:
+		raise Exception('UP failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# Euro sign
+	u_boot_console.run_command(cmd='\xe2\x82\xac', wait_for_echo=False,
+				   send_nl=False, wait_for_prompt=False)
+	m = u_boot_console.p.expect(['Unicode char 8364 \(\''])
+	if m != 0:
+		raise Exception('Euro sign failed in \'text input\' test')
+	u_boot_console.drain_console()
+	# SHIFT+ALT+FN 5
+	u_boot_console.run_command(cmd='\x1b\x5b\x31\x35\x3b\x34\x7e',
+				   wait_for_echo=False, send_nl=False,
+				   wait_for_prompt=False)
+	m = u_boot_console.p.expect(
+		['Unicode char 0 \(Null\), scan code 15 \(SHIFT\+ALT\+FN 5\)'])
+	if m != 0:
+		raise Exception('SHIFT+ALT+FN 5 failed in \'text input\' test')
+	u_boot_console.drain_console()
+	u_boot_console.run_command(cmd=chr(24), wait_for_echo=False, send_nl=False,
+				   wait_for_prompt=False)
+	m = u_boot_console.p.expect(['Summary: 0 failures', 'Press any key'])
+	if m != 0:
+		raise Exception('Failures occurred during the EFI selftest')
+	u_boot_console.restart_uboot();
diff --git a/test/py/tests/test_fs/conftest.py b/test/py/tests/test_fs/conftest.py
new file mode 100644
index 0000000..6404b31
--- /dev/null
+++ b/test/py/tests/test_fs/conftest.py
@@ -0,0 +1,392 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+
+import os
+import os.path
+import pytest
+import re
+from subprocess import call, check_call, check_output, CalledProcessError
+from fstest_defs import *
+
+supported_fs_basic = ['fat16', 'fat32', 'ext4']
+supported_fs_ext = ['fat16', 'fat32']
+supported_fs_mkdir = ['fat16', 'fat32']
+supported_fs_unlink = ['fat16', 'fat32']
+
+#
+# Filesystem test specific setup
+#
+def pytest_addoption(parser):
+    parser.addoption('--fs-type', action='append', default=None,
+        help='Targeting Filesystem Types')
+
+def pytest_configure(config):
+    global supported_fs_basic
+    global supported_fs_ext
+    global supported_fs_mkdir
+    global supported_fs_unlink
+
+    def intersect(listA, listB):
+        return  [x for x in listA if x in listB]
+
+    supported_fs = config.getoption('fs_type')
+    if supported_fs:
+        print("*** FS TYPE modified: %s" % supported_fs)
+        supported_fs_basic =  intersect(supported_fs, supported_fs_basic)
+        supported_fs_ext =  intersect(supported_fs, supported_fs_ext)
+        supported_fs_mkdir =  intersect(supported_fs, supported_fs_mkdir)
+        supported_fs_unlink =  intersect(supported_fs, supported_fs_unlink)
+
+def pytest_generate_tests(metafunc):
+    if 'fs_obj_basic' in metafunc.fixturenames:
+        metafunc.parametrize('fs_obj_basic', supported_fs_basic,
+            indirect=True, scope='module')
+    if 'fs_obj_ext' in metafunc.fixturenames:
+        metafunc.parametrize('fs_obj_ext', supported_fs_ext,
+            indirect=True, scope='module')
+    if 'fs_obj_mkdir' in metafunc.fixturenames:
+        metafunc.parametrize('fs_obj_mkdir', supported_fs_mkdir,
+            indirect=True, scope='module')
+    if 'fs_obj_unlink' in metafunc.fixturenames:
+        metafunc.parametrize('fs_obj_unlink', supported_fs_unlink,
+            indirect=True, scope='module')
+
+#
+# Helper functions
+#
+def fstype_to_ubname(fs_type):
+    if re.match('fat', fs_type):
+        return 'fat'
+    else:
+        return fs_type
+
+def check_ubconfig(config, fs_type):
+    if not config.buildconfig.get('config_cmd_%s' % fs_type, None):
+        pytest.skip('.config feature "CMD_%s" not enabled' % fs_type.upper())
+    if not config.buildconfig.get('config_%s_write' % fs_type, None):
+        pytest.skip('.config feature "%s_WRITE" not enabled'
+        % fs_type.upper())
+
+def mk_fs(config, fs_type, size, id):
+    fs_img = '%s.%s.img' % (id, fs_type)
+    fs_img = config.persistent_data_dir + '/' + fs_img
+
+    if fs_type == 'fat16':
+        mkfs_opt = '-F 16'
+    elif fs_type == 'fat32':
+        mkfs_opt = '-F 32'
+    else:
+        mkfs_opt = ''
+
+    if re.match('fat', fs_type):
+        fs_lnxtype = 'vfat'
+    else:
+        fs_lnxtype = fs_type
+
+    count = (size + 1048576 - 1) / 1048576
+
+    try:
+        check_call('rm -f %s' % fs_img, shell=True)
+        check_call('dd if=/dev/zero of=%s bs=1M count=%d'
+            % (fs_img, count), shell=True)
+        check_call('mkfs.%s %s %s'
+            % (fs_lnxtype, mkfs_opt, fs_img), shell=True)
+        return fs_img
+    except CalledProcessError:
+        call('rm -f %s' % fs_img, shell=True)
+        raise
+
+# from test/py/conftest.py
+def tool_is_in_path(tool):
+    for path in os.environ["PATH"].split(os.pathsep):
+        fn = os.path.join(path, tool)
+        if os.path.isfile(fn) and os.access(fn, os.X_OK):
+            return True
+    return False
+
+fuse_mounted = False
+
+def mount_fs(fs_type, device, mount_point):
+    global fuse_mounted
+
+    fuse_mounted = False
+    try:
+        if tool_is_in_path('guestmount'):
+            fuse_mounted = True
+            check_call('guestmount -a %s -m /dev/sda %s'
+                % (device, mount_point), shell=True)
+        else:
+            mount_opt = "loop,rw"
+            if re.match('fat', fs_type):
+                mount_opt += ",umask=0000"
+
+            check_call('sudo mount -o %s %s %s'
+                % (mount_opt, device, mount_point), shell=True)
+
+            # may not be effective for some file systems
+            check_call('sudo chmod a+rw %s' % mount_point, shell=True)
+    except CalledProcessError:
+        raise
+
+def umount_fs(fs_type, mount_point):
+    if fuse_mounted:
+        call('sync')
+        call('guestunmount %s' % mount_point, shell=True)
+    else:
+        call('sudo umount %s' % mount_point, shell=True)
+
+#
+# Fixture for basic fs test
+#     derived from test/fs/fs-test.sh
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_basic(request, u_boot_config):
+    fs_type = request.param
+    fs_img = ''
+
+    fs_ubtype = fstype_to_ubname(fs_type)
+    check_ubconfig(u_boot_config, fs_ubtype)
+
+    mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+    small_file = mount_dir + '/' + SMALL_FILE
+    big_file = mount_dir + '/' + BIG_FILE
+
+    try:
+
+        # 3GiB volume
+        fs_img = mk_fs(u_boot_config, fs_type, 0xc0000000, '3GB')
+
+        # Mount the image so we can populate it.
+        check_call('mkdir -p %s' % mount_dir, shell=True)
+        mount_fs(fs_type, fs_img, mount_dir)
+
+        # Create a subdirectory.
+        check_call('mkdir %s/SUBDIR' % mount_dir, shell=True)
+
+        # Create big file in this image.
+        # Note that we work only on the start 1MB, couple MBs in the 2GB range
+        # and the last 1 MB of the huge 2.5GB file.
+        # So, just put random values only in those areas.
+        check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+	    % big_file, shell=True)
+        check_call('dd if=/dev/urandom of=%s bs=1M count=2 seek=2047'
+            % big_file, shell=True)
+        check_call('dd if=/dev/urandom of=%s bs=1M count=1 seek=2499'
+            % big_file, shell=True)
+
+        # Create a small file in this image.
+        check_call('dd if=/dev/urandom of=%s bs=1M count=1'
+	    % small_file, shell=True)
+
+        # Delete the small file copies which possibly are written as part of a
+        # previous test.
+        # check_call('rm -f "%s.w"' % MB1, shell=True)
+        # check_call('rm -f "%s.w2"' % MB1, shell=True)
+
+        # Generate the md5sums of reads that we will test against small file
+        out = check_output(
+            'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+	    % small_file, shell=True)
+        md5val = [ out.split()[0] ]
+
+        # Generate the md5sums of reads that we will test against big file
+        # One from beginning of file.
+        out = check_output(
+            'dd if=%s bs=1M skip=0 count=1 2> /dev/null | md5sum'
+	    % big_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # One from end of file.
+        out = check_output(
+            'dd if=%s bs=1M skip=2499 count=1 2> /dev/null | md5sum'
+	    % big_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # One from the last 1MB chunk of 2GB
+        out = check_output(
+            'dd if=%s bs=1M skip=2047 count=1 2> /dev/null | md5sum'
+	    % big_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # One from the start 1MB chunk from 2GB
+        out = check_output(
+            'dd if=%s bs=1M skip=2048 count=1 2> /dev/null | md5sum'
+	    % big_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # One 1MB chunk crossing the 2GB boundary
+        out = check_output(
+            'dd if=%s bs=512K skip=4095 count=2 2> /dev/null | md5sum'
+	    % big_file, shell=True)
+        md5val.append(out.split()[0])
+
+        umount_fs(fs_type, mount_dir)
+    except CalledProcessError:
+        pytest.skip('Setup failed for filesystem: ' + fs_type)
+        return
+    else:
+        yield [fs_ubtype, fs_img, md5val]
+    finally:
+        umount_fs(fs_type, mount_dir)
+        call('rmdir %s' % mount_dir, shell=True)
+        if fs_img:
+            call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for extended fs test
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_ext(request, u_boot_config):
+    fs_type = request.param
+    fs_img = ''
+
+    fs_ubtype = fstype_to_ubname(fs_type)
+    check_ubconfig(u_boot_config, fs_ubtype)
+
+    mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+    min_file = mount_dir + '/' + MIN_FILE
+    tmp_file = mount_dir + '/tmpfile'
+
+    try:
+
+        # 128MiB volume
+        fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+
+        # Mount the image so we can populate it.
+        check_call('mkdir -p %s' % mount_dir, shell=True)
+        mount_fs(fs_type, fs_img, mount_dir)
+
+        # Create a test directory
+        check_call('mkdir %s/dir1' % mount_dir, shell=True)
+
+        # Create a small file and calculate md5
+        check_call('dd if=/dev/urandom of=%s bs=1K count=20'
+            % min_file, shell=True)
+        out = check_output(
+            'dd if=%s bs=1K 2> /dev/null | md5sum'
+            % min_file, shell=True)
+        md5val = [ out.split()[0] ]
+
+        # Calculate md5sum of Test Case 4
+        check_call('dd if=%s of=%s bs=1K count=20'
+            % (min_file, tmp_file), shell=True)
+        check_call('dd if=%s of=%s bs=1K seek=5 count=20'
+            % (min_file, tmp_file), shell=True)
+        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+            % tmp_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # Calculate md5sum of Test Case 5
+        check_call('dd if=%s of=%s bs=1K count=20'
+            % (min_file, tmp_file), shell=True)
+        check_call('dd if=%s of=%s bs=1K seek=5 count=5'
+            % (min_file, tmp_file), shell=True)
+        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+            % tmp_file, shell=True)
+        md5val.append(out.split()[0])
+
+        # Calculate md5sum of Test Case 7
+        check_call('dd if=%s of=%s bs=1K count=20'
+            % (min_file, tmp_file), shell=True)
+        check_call('dd if=%s of=%s bs=1K seek=20 count=20'
+            % (min_file, tmp_file), shell=True)
+        out = check_output('dd if=%s bs=1K 2> /dev/null | md5sum'
+            % tmp_file, shell=True)
+        md5val.append(out.split()[0])
+
+        check_call('rm %s' % tmp_file, shell=True)
+        umount_fs(fs_type, mount_dir)
+    except CalledProcessError:
+        pytest.skip('Setup failed for filesystem: ' + fs_type)
+        return
+    else:
+        yield [fs_ubtype, fs_img, md5val]
+    finally:
+        umount_fs(fs_type, mount_dir)
+        call('rmdir %s' % mount_dir, shell=True)
+        if fs_img:
+            call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for mkdir test
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_mkdir(request, u_boot_config):
+    fs_type = request.param
+    fs_img = ''
+
+    fs_ubtype = fstype_to_ubname(fs_type)
+    check_ubconfig(u_boot_config, fs_ubtype)
+
+    try:
+        # 128MiB volume
+        fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+    except:
+        pytest.skip('Setup failed for filesystem: ' + fs_type)
+    else:
+        yield [fs_ubtype, fs_img]
+    finally:
+        if fs_img:
+            call('rm -f %s' % fs_img, shell=True)
+
+#
+# Fixture for unlink test
+#
+# NOTE: yield_fixture was deprecated since pytest-3.0
+@pytest.yield_fixture()
+def fs_obj_unlink(request, u_boot_config):
+    fs_type = request.param
+    fs_img = ''
+
+    fs_ubtype = fstype_to_ubname(fs_type)
+    check_ubconfig(u_boot_config, fs_ubtype)
+
+    mount_dir = u_boot_config.persistent_data_dir + '/mnt'
+
+    try:
+
+        # 128MiB volume
+        fs_img = mk_fs(u_boot_config, fs_type, 0x8000000, '128MB')
+
+        # Mount the image so we can populate it.
+        check_call('mkdir -p %s' % mount_dir, shell=True)
+        mount_fs(fs_type, fs_img, mount_dir)
+
+        # Test Case 1 & 3
+        check_call('mkdir %s/dir1' % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir1/file1 bs=1K count=1'
+                                    % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir1/file2 bs=1K count=1'
+                                    % mount_dir, shell=True)
+
+        # Test Case 2
+        check_call('mkdir %s/dir2' % mount_dir, shell=True)
+	for i in range(0, 20):
+	    check_call('mkdir %s/dir2/0123456789abcdef%02x'
+                                    % (mount_dir, i), shell=True)
+
+        # Test Case 4
+        check_call('mkdir %s/dir4' % mount_dir, shell=True)
+
+        # Test Case 5, 6 & 7
+        check_call('mkdir %s/dir5' % mount_dir, shell=True)
+        check_call('dd if=/dev/urandom of=%s/dir5/file1 bs=1K count=1'
+                                    % mount_dir, shell=True)
+
+        umount_fs(fs_type, mount_dir)
+    except CalledProcessError:
+        pytest.skip('Setup failed for filesystem: ' + fs_type)
+        return
+    else:
+        yield [fs_ubtype, fs_img]
+    finally:
+        umount_fs(fs_type, mount_dir)
+        call('rmdir %s' % mount_dir, shell=True)
+        if fs_img:
+            call('rm -f %s' % fs_img, shell=True)
diff --git a/test/py/tests/test_fs/fstest_defs.py b/test/py/tests/test_fs/fstest_defs.py
new file mode 100644
index 0000000..5f10756
--- /dev/null
+++ b/test/py/tests/test_fs/fstest_defs.py
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier:      GPL-2.0+
+
+# $MIN_FILE is the name of the 20KB file in the file system image
+MIN_FILE='testfile'
+
+# $SMALL_FILE is the name of the 1MB file in the file system image
+SMALL_FILE='1MB.file'
+
+# $BIG_FILE is the name of the 2.5GB file in the file system image
+BIG_FILE='2.5GB.file'
+
+ADDR=0x01000008
+LENGTH=0x00100000
diff --git a/test/py/tests/test_fs/test_basic.py b/test/py/tests/test_fs/test_basic.py
new file mode 100644
index 0000000..c067cc9
--- /dev/null
+++ b/test/py/tests/test_fs/test_basic.py
@@ -0,0 +1,287 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:Basic Test
+
+"""
+This test verifies basic read/write operation on file system.
+"""
+
+import pytest
+import re
+from fstest_defs import *
+
+@pytest.mark.boardspec('sandbox')
+class TestFsBasic(object):
+    def test_fs1(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 1 - ls command, listing a root directory and invalid directory
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 1a - ls'):
+            # Test Case 1 - ls
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sls host 0:0' % fs_type])
+            assert(re.search('2621440000 *%s' % BIG_FILE, ''.join(output)))
+            assert(re.search('1048576 *%s' % SMALL_FILE, ''.join(output)))
+
+        with u_boot_console.log.section('Test Case 1b - ls (invalid dir)'):
+            # In addition, test with a nonexistent directory to see if we crash.
+            output = u_boot_console.run_command(
+                '%sls host 0:0 invalid_d' % fs_type)
+            if fs_type == 'ext4':
+                assert('Can not find directory' in output)
+            else:
+                assert('' == output)
+
+    def test_fs2(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 2 - size command for a small file
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 2a - size (small)'):
+            # 1MB is 0x0010 0000
+            # Test Case 2a - size of small file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%ssize host 0:0 /%s' % (fs_type, SMALL_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+        with u_boot_console.log.section('Test Case 2b - size (/../<file>)'):
+            # Test Case 2b - size of small file via a path using '..'
+            output = u_boot_console.run_command_list([
+                '%ssize host 0:0 /SUBDIR/../%s' % (fs_type, SMALL_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+    def test_fs3(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 3 - size command for a large file
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 3 - size (large)'):
+            # 2.5GB (1024*1024*2500) is 0x9C40 0000
+            # Test Case 3 - size of big file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%ssize host 0:0 /%s' % (fs_type, BIG_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=9c400000' in ''.join(output))
+
+    def test_fs4(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 4 - load a small file, 1MB
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 4 - load (small)'):
+            # Test Case 4a - Read full 1MB of small file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 4b - Read full 1MB of small file
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
+
+    def test_fs5(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 5 - load, reading first 1MB of 3GB file
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 5 - load (first 1MB)'):
+            # Test Case 5a - First 1MB of big file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s %x 0x0' % (fs_type, ADDR, BIG_FILE, LENGTH),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 5b - First 1MB of big file
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[1] in ''.join(output))
+
+    def test_fs6(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 6 - load, reading last 1MB of 3GB file
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 6 - load (last 1MB)'):
+            # fails for ext as no offset support
+            # Test Case 6a - Last 1MB of big file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s %x 0x9c300000'
+                    % (fs_type, ADDR, BIG_FILE, LENGTH),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 6b - Last 1MB of big file
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[2] in ''.join(output))
+
+    def test_fs7(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 7 - load, 1MB from the last 1MB in 2GB
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 7 - load (last 1MB in 2GB)'):
+            # fails for ext as no offset support
+            # Test Case 7a - One from the last 1MB chunk of 2GB
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s %x 0x7ff00000'
+                    % (fs_type, ADDR, BIG_FILE, LENGTH),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 7b - One from the last 1MB chunk of 2GB
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[3] in ''.join(output))
+
+    def test_fs8(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 8 - load, reading first 1MB in 2GB
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 8 - load (first 1MB in 2GB)'):
+            # fails for ext as no offset support
+            # Test Case 8a - One from the start 1MB chunk from 2GB
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s %x 0x80000000'
+                    % (fs_type, ADDR, BIG_FILE, LENGTH),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 8b - One from the start 1MB chunk from 2GB
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[4] in ''.join(output))
+
+    def test_fs9(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 9 - load, 1MB crossing 2GB boundary
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 9 - load (crossing 2GB boundary)'):
+            # fails for ext as no offset support
+            # Test Case 9a - One 1MB chunk crossing the 2GB boundary
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s %x 0x7ff80000'
+                    % (fs_type, ADDR, BIG_FILE, LENGTH),
+                'printenv filesize'])
+            assert('filesize=100000' in ''.join(output))
+
+            # Test Case 9b - One 1MB chunk crossing the 2GB boundary
+            output = u_boot_console.run_command_list([
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[5] in ''.join(output))
+
+    def test_fs10(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 10 - load, reading beyond file end'):
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 10 - load (beyond file end)'):
+            # Generic failure case
+            # Test Case 10 - 2MB chunk from the last 1MB of big file
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s 0x00200000 0x9c300000'
+                    % (fs_type, ADDR, BIG_FILE),
+                'printenv filesize',
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+        assert('filesize=100000' in ''.join(output))
+
+    def test_fs11(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 11 - write'
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 11 - write'):
+            # Read 1MB from small file
+            # Write it back to test the writes
+            # Test Case 11a - Check that the write succeeded
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+                '%swrite host 0:0 %x /%s.w $filesize'
+                    % (fs_type, ADDR, SMALL_FILE)])
+            assert('1048576 bytes written' in ''.join(output))
+
+            # Test Case 11b - Check md5 of written to is same
+            # as the one read from
+            output = u_boot_console.run_command_list([
+                '%sload host 0:0 %x /%s.w' % (fs_type, ADDR, SMALL_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
+
+    def test_fs12(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 12 - write to "." directory
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 12 - write (".")'):
+            # Next test case checks writing a file whose dirent
+            # is the first in the block, which is always true for "."
+            # The write should fail, but the lookup should work
+            # Test Case 12 - Check directory traversal
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%swrite host 0:0 %x /. 0x10' % (fs_type, ADDR)])
+            assert('Unable to write' in ''.join(output))
+
+    def test_fs13(self, u_boot_console, fs_obj_basic):
+        """
+        Test Case 13 - write to a file with "/./<filename>"
+        """
+        fs_type,fs_img,md5val = fs_obj_basic
+        with u_boot_console.log.section('Test Case 13 - write  ("./<file>")'):
+            # Read 1MB from small file
+            # Write it via "same directory", i.e. "." dirent
+            # Test Case 13a - Check directory traversal
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, SMALL_FILE),
+                '%swrite host 0:0 %x /./%s2 $filesize'
+                    % (fs_type, ADDR, SMALL_FILE)])
+            assert('1048576 bytes written' in ''.join(output))
+
+            # Test Case 13b - Check md5 of written to is same
+            # as the one read from
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /./%s2' % (fs_type, ADDR, SMALL_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
+
+            # Test Case 13c - Check md5 of written to is same
+            # as the one read from
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /%s2' % (fs_type, ADDR, SMALL_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
diff --git a/test/py/tests/test_fs/test_ext.py b/test/py/tests/test_fs/test_ext.py
new file mode 100644
index 0000000..38217d0
--- /dev/null
+++ b/test/py/tests/test_fs/test_ext.py
@@ -0,0 +1,224 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:Exntented Test
+
+"""
+This test verifies extended write operation on file system.
+"""
+
+import pytest
+import re
+from fstest_defs import *
+
+@pytest.mark.boardspec('sandbox')
+class TestFsExt(object):
+    def test_fs_ext1(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 1 - write a file with absolute path
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 1 - write with abs path'):
+            # Test Case 1a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w1 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            assert('20480 bytes written' in ''.join(output))
+
+            # Test Case 1b - Check md5 of file content
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /dir1/%s.w1' % (fs_type, ADDR, MIN_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
+
+    def test_fs_ext2(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 2 - write to a file with relative path
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 2 - write with rel path'):
+            # Test Case 2a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x dir1/%s.w2 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            assert('20480 bytes written' in ''.join(output))
+
+            # Test Case 2b - Check md5 of file content
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x dir1/%s.w2' % (fs_type, ADDR, MIN_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[0] in ''.join(output))
+
+    def test_fs_ext3(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 3 - write to a file with invalid path
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 3 - write with invalid path'):
+            # Test Case 3 - Check if command expectedly failed
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/none/%s.w3 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            assert('Unable to write "/dir1/none/' in ''.join(output))
+
+    def test_fs_ext4(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 4 - write at non-zero offset, enlarging file size
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 4 - write at non-zero offset, enlarging file size'):
+            # Test Case 4a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w4 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            output = u_boot_console.run_command(
+                '%swrite host 0:0 %x /dir1/%s.w4 $filesize 0x1400'
+                    % (fs_type, ADDR, MIN_FILE))
+            assert('20480 bytes written' in output)
+
+            # Test Case 4b - Check size of written file
+            output = u_boot_console.run_command_list([
+                '%ssize host 0:0 /dir1/%s.w4' % (fs_type, MIN_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=6400' in ''.join(output))
+
+            # Test Case 4c - Check md5 of file content
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /dir1/%s.w4' % (fs_type, ADDR, MIN_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[1] in ''.join(output))
+
+    def test_fs_ext5(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 5 - write at non-zero offset, shrinking file size
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 5 - write at non-zero offset, shrinking file size'):
+            # Test Case 5a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w5 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            output = u_boot_console.run_command(
+                '%swrite host 0:0 %x /dir1/%s.w5 0x1400 0x1400'
+                    % (fs_type, ADDR, MIN_FILE))
+            assert('5120 bytes written' in output)
+
+            # Test Case 5b - Check size of written file
+            output = u_boot_console.run_command_list([
+                '%ssize host 0:0 /dir1/%s.w5' % (fs_type, MIN_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=2800' in ''.join(output))
+
+            # Test Case 5c - Check md5 of file content
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /dir1/%s.w5' % (fs_type, ADDR, MIN_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[2] in ''.join(output))
+
+    def test_fs_ext6(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 6 - write nothing at the start, truncating to zero
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 6 - write nothing at the start, truncating to zero'):
+            # Test Case 6a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w6 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            output = u_boot_console.run_command(
+                '%swrite host 0:0 %x /dir1/%s.w6 0 0'
+                    % (fs_type, ADDR, MIN_FILE))
+            assert('0 bytes written' in output)
+
+            # Test Case 6b - Check size of written file
+            output = u_boot_console.run_command_list([
+                '%ssize host 0:0 /dir1/%s.w6' % (fs_type, MIN_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=0' in ''.join(output))
+
+    def test_fs_ext7(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 7 - write at the end (append)
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 7 - write at the end (append)'):
+            # Test Case 7a - Check if command successfully returned
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w7 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            output = u_boot_console.run_command(
+                '%swrite host 0:0 %x /dir1/%s.w7 $filesize $filesize'
+                    % (fs_type, ADDR, MIN_FILE))
+            assert('20480 bytes written' in output)
+
+            # Test Case 7b - Check size of written file
+            output = u_boot_console.run_command_list([
+                '%ssize host 0:0 /dir1/%s.w7' % (fs_type, MIN_FILE),
+                'printenv filesize',
+                'setenv filesize'])
+            assert('filesize=a000' in ''.join(output))
+
+            # Test Case 7c - Check md5 of file content
+            output = u_boot_console.run_command_list([
+                'mw.b %x 00 100' % ADDR,
+                '%sload host 0:0 %x /dir1/%s.w7' % (fs_type, ADDR, MIN_FILE),
+                'md5sum %x $filesize' % ADDR,
+                'setenv filesize'])
+            assert(md5val[3] in ''.join(output))
+
+    def test_fs_ext8(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 8 - write at offset beyond the end of file
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 8 - write beyond the end'):
+            # Test Case 8a - Check if command expectedly failed
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w8 $filesize'
+                    % (fs_type, ADDR, MIN_FILE)])
+            output = u_boot_console.run_command(
+                '%swrite host 0:0 %x /dir1/%s.w8 0x1400 %x'
+                    % (fs_type, ADDR, MIN_FILE, 0x100000 + 0x1400))
+            assert('Unable to write "/dir1' in output)
+
+    def test_fs_ext9(self, u_boot_console, fs_obj_ext):
+        """
+        Test Case 9 - write to a non-existing file at non-zero offset
+        """
+        fs_type,fs_img,md5val = fs_obj_ext
+        with u_boot_console.log.section('Test Case 9 - write to non-existing file with non-zero offset'):
+            # Test Case 9a - Check if command expectedly failed
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%sload host 0:0 %x /%s' % (fs_type, ADDR, MIN_FILE),
+                '%swrite host 0:0 %x /dir1/%s.w9 0x1400 0x1400'
+                    % (fs_type, ADDR, MIN_FILE)])
+            assert('Unable to write "/dir1' in ''.join(output))
diff --git a/test/py/tests/test_fs/test_mkdir.py b/test/py/tests/test_fs/test_mkdir.py
new file mode 100644
index 0000000..d9da97b
--- /dev/null
+++ b/test/py/tests/test_fs/test_mkdir.py
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:mkdir Test
+
+"""
+This test verifies mkdir operation on file system.
+"""
+
+import pytest
+
+@pytest.mark.boardspec('sandbox')
+class TestMkdir(object):
+    def test_mkdir1(self, u_boot_console, fs_obj_mkdir):
+        """
+        Test Case 1 - create a directory under a root
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 1 - mkdir'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 dir1' % fs_type,
+                '%sls host 0:0 /' % fs_type])
+            assert('dir1/' in ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir1' % fs_type)
+            assert('./'   in output)
+            assert('../'  in output)
+
+    def test_mkdir2(self, u_boot_console, fs_obj_mkdir):
+        """
+        Test Case 2 - create a directory under a sub-directory
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 2 - mkdir (sub-sub directory)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 dir1/dir2' % fs_type,
+                '%sls host 0:0 dir1' % fs_type])
+            assert('dir2/' in ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir1/dir2' % fs_type)
+            assert('./'   in output)
+            assert('../'  in output)
+
+    def test_mkdir3(self, u_boot_console, fs_obj_mkdir):
+        """
+        Test Case 3 - trying to create a directory with a non-existing
+        path should fail
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 3 - mkdir (non-existing path)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 none/dir3' % fs_type])
+            assert('Unable to create a directory' in ''.join(output))
+
+    def test_mkdir4(self, u_boot_console, fs_obj_mkdir):
+        """
+        Test Case 4 - trying to create "." should fail
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 4 - mkdir (".")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 .' % fs_type])
+            assert('Unable to create a directory' in ''.join(output))
+
+    def test_mkdir5(self, u_boot_console, fs_obj_mkdir):
+        """
+        Test Case 5 - trying to create ".." should fail
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 5 - mkdir ("..")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 ..' % fs_type])
+            assert('Unable to create a directory' in ''.join(output))
+
+    def test_mkdir6(self, u_boot_console, fs_obj_mkdir):
+        """
+        'Test Case 6 - create as many directories as amount of directory
+        entries goes beyond a cluster size)'
+        """
+        fs_type,fs_img = fs_obj_mkdir
+        with u_boot_console.log.section('Test Case 6 - mkdir (create many)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%smkdir host 0:0 dir6' % fs_type,
+                '%sls host 0:0 /' % fs_type])
+            assert('dir6/' in ''.join(output))
+
+            for i in range(0, 20):
+                output = u_boot_console.run_command(
+                    '%smkdir host 0:0 dir6/0123456789abcdef%02x'
+                    % (fs_type, i))
+            output = u_boot_console.run_command('%sls host 0:0 dir6' % fs_type)
+            assert('0123456789abcdef00/'  in output)
+            assert('0123456789abcdef13/'  in output)
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir6/0123456789abcdef13/.' % fs_type)
+            assert('./'   in output)
+            assert('../'  in output)
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir6/0123456789abcdef13/..' % fs_type)
+            assert('0123456789abcdef00/'  in output)
+            assert('0123456789abcdef13/'  in output)
diff --git a/test/py/tests/test_fs/test_unlink.py b/test/py/tests/test_fs/test_unlink.py
new file mode 100644
index 0000000..69c1a6e
--- /dev/null
+++ b/test/py/tests/test_fs/test_unlink.py
@@ -0,0 +1,109 @@
+# SPDX-License-Identifier:      GPL-2.0+
+# Copyright (c) 2018, Linaro Limited
+# Author: Takahiro Akashi <takahiro.akashi@linaro.org>
+#
+# U-Boot File System:unlink Test
+
+"""
+This test verifies unlink operation (deleting a file or a directory)
+on file system.
+"""
+
+import pytest
+
+@pytest.mark.boardspec('sandbox')
+class TestUnlink(object):
+    def test_unlink1(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 1 - delete a file
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 1 - unlink (file)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir1/file1' % fs_type,
+                '%sls host 0:0 dir1/file1' % fs_type])
+            assert('' == ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir1/' % fs_type)
+            assert(not 'file1' in output)
+            assert('file2' in output)
+
+    def test_unlink2(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 2 - delete many files
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 2 - unlink (many)'):
+            output = u_boot_console.run_command('host bind 0 %s' % fs_img)
+
+            for i in range(0, 20):
+                output = u_boot_console.run_command_list([
+                    '%srm host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i),
+                    '%sls host 0:0 dir2/0123456789abcdef%02x' % (fs_type, i)])
+                assert('' == ''.join(output))
+
+            output = u_boot_console.run_command(
+                '%sls host 0:0 dir2' % fs_type)
+            assert('0 file(s), 2 dir(s)' in output)
+
+    def test_unlink3(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 3 - trying to delete a non-existing file should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 3 - unlink (non-existing)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir1/nofile' % fs_type])
+            assert('nofile: doesn\'t exist' in ''.join(output))
+
+    def test_unlink4(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 4 - delete an empty directory
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 4 - unlink (directory)'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir4' % fs_type])
+            assert('' == ''.join(output))
+
+        output = u_boot_console.run_command(
+            '%sls host 0:0 /' % fs_type)
+        assert(not 'dir4' in output)
+
+    def test_unlink5(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 5 - trying to deleting a non-empty directory ".."
+        should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 5 - unlink ("non-empty directory")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5' % fs_type])
+            assert('directory is not empty' in ''.join(output))
+
+    def test_unlink6(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 6 - trying to deleting a "." should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 6 - unlink (".")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5/.' % fs_type])
+            assert('directory is not empty' in ''.join(output))
+
+    def test_unlink7(self, u_boot_console, fs_obj_unlink):
+        """
+        Test Case 7 - trying to deleting a ".." should fail
+        """
+        fs_type,fs_img = fs_obj_unlink
+        with u_boot_console.log.section('Test Case 7 - unlink ("..")'):
+            output = u_boot_console.run_command_list([
+                'host bind 0 %s' % fs_img,
+                '%srm host 0:0 dir5/..' % fs_type])
+            assert('directory is not empty' in ''.join(output))
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
new file mode 100644
index 0000000..b115d18
--- /dev/null
+++ b/test/unicode_ut.c
@@ -0,0 +1,543 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Unit tests for Unicode functions
+ *
+ * Copyright (c) 2018 Heinrich Schuchardt <xypron.glpk@gmx.de>
+ */
+
+#include <common.h>
+#include <charset.h>
+#include <command.h>
+#include <errno.h>
+#include <test/test.h>
+#include <test/suites.h>
+#include <test/ut.h>
+
+/* Linker list entry for a Unicode test */
+#define UNICODE_TEST(_name) UNIT_TEST(_name, 0, unicode_test)
+
+/* Constants c1-c4 and d1-d4 encode the same letters */
+
+/* Six characters translating to one utf-8 byte each. */
+static const u16 c1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
+/* One character translating to two utf-8 bytes */
+static const u16 c2[] = {0x6b, 0x61, 0x66, 0x62, 0xe1, 0x74, 0x75, 0x72, 0x00};
+/* Three characters translating to three utf-8 bytes each */
+static const u16 c3[] = {0x6f5c, 0x6c34, 0x8266, 0x00};
+/* Three letters translating to four utf-8 bytes each */
+static const u16 c4[] = {0xd801, 0xdc8d, 0xd801, 0xdc96, 0xd801, 0xdc87,
+			 0x0000};
+
+/* Illegal utf-16 strings */
+static const u16 i1[] = {0x69, 0x31, 0xdc87, 0x6c, 0x00};
+static const u16 i2[] = {0x69, 0x32, 0xd801, 0xd801, 0x6c, 0x00};
+static const u16 i3[] = {0x69, 0x33, 0xd801, 0x00};
+
+/* Six characters translating to one utf-16 word each. */
+static const char d1[] = {0x55, 0x2d, 0x42, 0x6f, 0x6f, 0x74, 0x00};
+/* Eight characters translating to one utf-16 word each */
+static const char d2[] = {0x6b, 0x61, 0x66, 0x62, 0xc3, 0xa1, 0x74, 0x75,
+			  0x72, 0x00};
+/* Three characters translating to one utf-16 word each */
+static const char d3[] = {0xe6, 0xbd, 0x9c, 0xe6, 0xb0, 0xb4, 0xe8, 0x89,
+			  0xa6, 0x00};
+/* Three letters translating to two utf-16 word each */
+static const char d4[] = {0xf0, 0x90, 0x92, 0x8d, 0xf0, 0x90, 0x92, 0x96,
+			  0xf0, 0x90, 0x92, 0x87, 0x00};
+
+/* Illegal utf-8 strings */
+static const char j1[] = {0x6a, 0x31, 0xa1, 0x6c, 0x00};
+static const char j2[] = {0x6a, 0x32, 0xc3, 0xc3, 0x6c, 0x00};
+static const char j3[] = {0x6a, 0x33, 0xf0, 0x90, 0xf0, 0x00};
+
+/* U-Boot uses UTF-16 strings in the EFI context only. */
+#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
+static int ut_string16(struct unit_test_state *uts)
+{
+	char buf[20];
+
+	/* Test length and precision */
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c2);
+	ut_asserteq(' ', buf[1]);
+	ut_assert(!strncmp(&buf[2], d2, 7));
+	ut_assert(!buf[9]);
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%8.6ls", c4);
+	ut_asserteq(' ', buf[4]);
+	ut_assert(!strncmp(&buf[5], d4, 12));
+	ut_assert(!buf[17]);
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%-8.2ls", c4);
+	ut_asserteq(' ', buf[8]);
+	ut_assert(!strncmp(buf, d4, 8));
+	ut_assert(!buf[14]);
+
+	/* Test handling of illegal utf-16 sequences */
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%ls", i1);
+	ut_asserteq_str("i1?l", buf);
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%ls", i2);
+	ut_asserteq_str("i2?l", buf);
+
+	memset(buf, 0xff, sizeof(buf));
+	sprintf(buf, "%ls", i3);
+	ut_asserteq_str("i3?", buf);
+
+	return 0;
+}
+UNICODE_TEST(ut_string16);
+#endif
+
+static int ut_utf8_get(struct unit_test_state *uts)
+{
+	const char *s;
+	s32 code;
+	int i;
+
+	/* Check characters less than 0x800 */
+	s = d2;
+	for (i = 0; i < 8; ++i) {
+		code = utf8_get((const char **)&s);
+		/* c2 is the utf-8 encoding of d2 */
+		ut_asserteq(c2[i], code);
+		if (!code)
+			break;
+	}
+	ut_asserteq_ptr(s, d2 + 9)
+
+	/* Check characters less than 0x10000 */
+	s = d3;
+	for (i = 0; i < 4; ++i) {
+		code = utf8_get((const char **)&s);
+		/* c3 is the utf-8 encoding of d3 */
+		ut_asserteq(c3[i], code);
+		if (!code)
+			break;
+	}
+	ut_asserteq_ptr(s, d3 + 9)
+
+	/* Check character greater 0xffff */
+	s = d4;
+	code = utf8_get((const char **)&s);
+	ut_asserteq(0x0001048d, code);
+	ut_asserteq_ptr(s, d4 + 4);
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_get);
+
+static int ut_utf8_put(struct unit_test_state *uts)
+{
+	char buffer[8] = { 0, };
+	char *pos;
+
+	/* Commercial at, translates to one character */
+	pos = buffer;
+	ut_assert(!utf8_put('@', &pos))
+	ut_asserteq(1, pos - buffer);
+	ut_asserteq('@', buffer[0]);
+	ut_assert(!buffer[1]);
+
+	/* Latin letter G with acute, translates to two charactes */
+	pos = buffer;
+	ut_assert(!utf8_put(0x1f4, &pos));
+	ut_asserteq(2, pos - buffer);
+	ut_asserteq_str("\xc7\xb4", buffer);
+
+	/* Tagalog letter i, translates to three characters */
+	pos = buffer;
+	ut_assert(!utf8_put(0x1701, &pos));
+	ut_asserteq(3, pos - buffer);
+	ut_asserteq_str("\xe1\x9c\x81", buffer);
+
+	/* Hamster face, translates to four characters */
+	pos = buffer;
+	ut_assert(!utf8_put(0x1f439, &pos));
+	ut_asserteq(4, pos - buffer);
+	ut_asserteq_str("\xf0\x9f\x90\xb9", buffer);
+
+	/* Illegal code */
+	pos = buffer;
+	ut_asserteq(-1, utf8_put(0xd888, &pos));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_put);
+
+static int ut_utf8_utf16_strlen(struct unit_test_state *uts)
+{
+	ut_asserteq(6, utf8_utf16_strlen(d1));
+	ut_asserteq(8, utf8_utf16_strlen(d2));
+	ut_asserteq(3, utf8_utf16_strlen(d3));
+	ut_asserteq(6, utf8_utf16_strlen(d4));
+
+	/* illegal utf-8 sequences */
+	ut_asserteq(4, utf8_utf16_strlen(j1));
+	ut_asserteq(4, utf8_utf16_strlen(j2));
+	ut_asserteq(3, utf8_utf16_strlen(j3));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_utf16_strlen);
+
+static int ut_utf8_utf16_strnlen(struct unit_test_state *uts)
+{
+	ut_asserteq(3, utf8_utf16_strnlen(d1, 3));
+	ut_asserteq(6, utf8_utf16_strnlen(d1, 13));
+	ut_asserteq(6, utf8_utf16_strnlen(d2, 6));
+	ut_asserteq(2, utf8_utf16_strnlen(d3, 2));
+	ut_asserteq(4, utf8_utf16_strnlen(d4, 2));
+	ut_asserteq(6, utf8_utf16_strnlen(d4, 3));
+
+	/* illegal utf-8 sequences */
+	ut_asserteq(4, utf8_utf16_strnlen(j1, 16));
+	ut_asserteq(4, utf8_utf16_strnlen(j2, 16));
+	ut_asserteq(3, utf8_utf16_strnlen(j3, 16));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_utf16_strnlen);
+
+/**
+ * ut_u16_strcmp() - Compare to u16 strings.
+ *
+ * @a1:		first string
+ * @a2:		second string
+ * @count:	number of u16 to compare
+ * Return:	-1 if a1 < a2, 0 if a1 == a2, 1 if a1 > a2
+ */
+static int ut_u16_strcmp(const u16 *a1, const u16 *a2, size_t count)
+{
+	for (; (*a1 || *a2) && count; ++a1, ++a2, --count) {
+		if (*a1 < *a2)
+			return -1;
+		if (*a1 > *a2)
+			return 1;
+	}
+	return 0;
+}
+
+static int ut_utf8_utf16_strcpy(struct unit_test_state *uts)
+{
+	u16 buf[16];
+	u16 *pos;
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, d1);
+	ut_asserteq(6, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, c1, SIZE_MAX));
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, d2);
+	ut_asserteq(8, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX));
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, d3);
+	ut_asserteq(3, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, c3, SIZE_MAX));
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, d4);
+	ut_asserteq(6, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX));
+
+	/* Illegal utf-8 strings */
+	pos = buf;
+	utf8_utf16_strcpy(&pos, j1);
+	ut_asserteq(4, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, L"j1?l", SIZE_MAX));
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, j2);
+	ut_asserteq(4, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, L"j2?l", SIZE_MAX));
+
+	pos = buf;
+	utf8_utf16_strcpy(&pos, j3);
+	ut_asserteq(3, pos - buf);
+	ut_assert(!ut_u16_strcmp(buf, L"j3?", SIZE_MAX));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_utf16_strcpy);
+
+int ut_utf8_utf16_strncpy(struct unit_test_state *uts)
+{
+	u16 buf[16];
+	u16 *pos;
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf8_utf16_strncpy(&pos, d1, 4);
+	ut_asserteq(4, pos - buf);
+	ut_assert(!buf[4]);
+	ut_assert(!ut_u16_strcmp(buf, c1, 4));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf8_utf16_strncpy(&pos, d2, 10);
+	ut_asserteq(8, pos - buf);
+	ut_assert(buf[4]);
+	ut_assert(!ut_u16_strcmp(buf, c2, SIZE_MAX));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf8_utf16_strncpy(&pos, d3, 2);
+	ut_asserteq(2, pos - buf);
+	ut_assert(!buf[2]);
+	ut_assert(!ut_u16_strcmp(buf, c3, 2));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf8_utf16_strncpy(&pos, d4, 2);
+	ut_asserteq(4, pos - buf);
+	ut_assert(!buf[4]);
+	ut_assert(!ut_u16_strcmp(buf, c4, 4));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf8_utf16_strncpy(&pos, d4, 10);
+	ut_asserteq(6, pos - buf);
+	ut_assert(buf[5]);
+	ut_assert(!ut_u16_strcmp(buf, c4, SIZE_MAX));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf8_utf16_strncpy);
+
+static int ut_utf16_get(struct unit_test_state *uts)
+{
+	const u16 *s;
+	s32 code;
+	int i;
+
+	/* Check characters less than 0x10000 */
+	s = c2;
+	for (i = 0; i < 9; ++i) {
+		code = utf16_get((const u16 **)&s);
+		ut_asserteq(c2[i], code);
+		if (!code)
+			break;
+	}
+	ut_asserteq_ptr(c2 + 8, s);
+
+	/* Check character greater 0xffff */
+	s = c4;
+	code = utf16_get((const u16 **)&s);
+	ut_asserteq(0x0001048d, code);
+	ut_asserteq_ptr(c4 + 2, s);
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_get);
+
+static int ut_utf16_put(struct unit_test_state *uts)
+{
+	u16 buffer[4] = { 0, };
+	u16 *pos;
+
+	/* Commercial at, translates to one word */
+	pos = buffer;
+	ut_assert(!utf16_put('@', &pos));
+	ut_asserteq(1, pos - buffer);
+	ut_asserteq((u16)'@', buffer[0]);
+	ut_assert(!buffer[1]);
+
+	/* Hamster face, translates to two words */
+	pos = buffer;
+	ut_assert(!utf16_put(0x1f439, &pos));
+	ut_asserteq(2, pos - buffer);
+	ut_asserteq((u16)0xd83d, buffer[0]);
+	ut_asserteq((u16)0xdc39, buffer[1]);
+	ut_assert(!buffer[2]);
+
+	/* Illegal code */
+	pos = buffer;
+	ut_asserteq(-1, utf16_put(0xd888, &pos));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_put);
+
+int ut_utf16_strnlen(struct unit_test_state *uts)
+{
+	ut_asserteq(3, utf16_strnlen(c1, 3));
+	ut_asserteq(6, utf16_strnlen(c1, 13));
+	ut_asserteq(6, utf16_strnlen(c2, 6));
+	ut_asserteq(2, utf16_strnlen(c3, 2));
+	ut_asserteq(2, utf16_strnlen(c4, 2));
+	ut_asserteq(3, utf16_strnlen(c4, 3));
+
+	/* illegal utf-16 word sequences */
+	ut_asserteq(4, utf16_strnlen(i1, 16));
+	ut_asserteq(4, utf16_strnlen(i2, 16));
+	ut_asserteq(3, utf16_strnlen(i3, 16));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_strnlen);
+
+int ut_utf16_utf8_strlen(struct unit_test_state *uts)
+{
+	ut_asserteq(6, utf16_utf8_strlen(c1));
+	ut_asserteq(9, utf16_utf8_strlen(c2));
+	ut_asserteq(9, utf16_utf8_strlen(c3));
+	ut_asserteq(12, utf16_utf8_strlen(c4));
+
+	/* illegal utf-16 word sequences */
+	ut_asserteq(4, utf16_utf8_strlen(i1));
+	ut_asserteq(4, utf16_utf8_strlen(i2));
+	ut_asserteq(3, utf16_utf8_strlen(i3));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_utf8_strlen);
+
+int ut_utf16_utf8_strnlen(struct unit_test_state *uts)
+{
+	ut_asserteq(3, utf16_utf8_strnlen(c1, 3));
+	ut_asserteq(6, utf16_utf8_strnlen(c1, 13));
+	ut_asserteq(7, utf16_utf8_strnlen(c2, 6));
+	ut_asserteq(6, utf16_utf8_strnlen(c3, 2));
+	ut_asserteq(8, utf16_utf8_strnlen(c4, 2));
+	ut_asserteq(12, utf16_utf8_strnlen(c4, 3));
+	return 0;
+}
+UNICODE_TEST(ut_utf16_utf8_strnlen);
+
+int ut_utf16_utf8_strcpy(struct unit_test_state *uts)
+{
+	char buf[16];
+	char *pos;
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, c1);
+	ut_asserteq(6, pos - buf);
+	ut_asserteq_str(d1, buf);
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, c2);
+	ut_asserteq(9, pos - buf);
+	ut_asserteq_str(d2, buf);
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, c3);
+	ut_asserteq(9, pos - buf);
+	ut_asserteq_str(d3, buf);
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, c4);
+	ut_asserteq(12, pos - buf);
+	ut_asserteq_str(d4, buf);
+
+	/* Illegal utf-16 strings */
+	pos = buf;
+	utf16_utf8_strcpy(&pos, i1);
+	ut_asserteq(4, pos - buf);
+	ut_asserteq_str("i1?l", buf);
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, i2);
+	ut_asserteq(4, pos - buf);
+	ut_asserteq_str("i2?l", buf);
+
+	pos = buf;
+	utf16_utf8_strcpy(&pos, i3);
+	ut_asserteq(3, pos - buf);
+	ut_asserteq_str("i3?", buf);
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_utf8_strcpy);
+
+int ut_utf16_utf8_strncpy(struct unit_test_state *uts)
+{
+	char buf[16];
+	char *pos;
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf16_utf8_strncpy(&pos, c1, 4);
+	ut_asserteq(4, pos - buf);
+	ut_assert(!buf[4]);
+	ut_assert(!strncmp(buf, d1, 4));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf16_utf8_strncpy(&pos, c2, 10);
+	ut_asserteq(9, pos - buf);
+	ut_assert(buf[4]);
+	ut_assert(!strncmp(buf, d2, SIZE_MAX));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf16_utf8_strncpy(&pos, c3, 2);
+	ut_asserteq(6, pos - buf);
+	ut_assert(!buf[6]);
+	ut_assert(!strncmp(buf, d3, 6));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf16_utf8_strncpy(&pos, c4, 2);
+	ut_asserteq(8, pos - buf);
+	ut_assert(!buf[8]);
+	ut_assert(!strncmp(buf, d4, 8));
+
+	pos = buf;
+	memset(buf, 0, sizeof(buf));
+	utf16_utf8_strncpy(&pos, c4, 10);
+	ut_asserteq(12, pos - buf);
+	ut_assert(buf[5]);
+	ut_assert(!strncmp(buf, d4, SIZE_MAX));
+
+	return 0;
+}
+UNICODE_TEST(ut_utf16_utf8_strncpy);
+
+int ut_utf_to_lower(struct unit_test_state *uts)
+{
+	ut_asserteq('@', utf_to_lower('@'));
+	ut_asserteq('a', utf_to_lower('A'));
+	ut_asserteq('z', utf_to_lower('Z'));
+	ut_asserteq('[', utf_to_lower('['));
+	ut_asserteq('m', utf_to_lower('m'));
+	/* Latin letter O with diaresis (umlaut) */
+	ut_asserteq(0x00f6, utf_to_lower(0x00d6));
+#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
+	/* Cyrillic letter I*/
+	ut_asserteq(0x0438, utf_to_lower(0x0418));
+#endif
+	return 0;
+}
+UNICODE_TEST(ut_utf_to_lower);
+
+int ut_utf_to_upper(struct unit_test_state *uts)
+{
+	ut_asserteq('`', utf_to_upper('`'));
+	ut_asserteq('A', utf_to_upper('a'));
+	ut_asserteq('Z', utf_to_upper('z'));
+	ut_asserteq('{', utf_to_upper('{'));
+	ut_asserteq('M', utf_to_upper('M'));
+	/* Latin letter O with diaresis (umlaut) */
+	ut_asserteq(0x00d6, utf_to_upper(0x00f6));
+#ifdef CONFIG_EFI_UNICODE_CAPITALIZATION
+	/* Cyrillic letter I */
+	ut_asserteq(0x0418, utf_to_upper(0x0438));
+#endif
+	return 0;
+}
+UNICODE_TEST(ut_utf_to_upper);
+
+int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
+{
+	struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);
+	const int n_ents = ll_entry_count(struct unit_test, unicode_test);
+
+	return cmd_ut_category("Unicode", tests, n_ents, argc, argv);
+}