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

Use device tree for mpc85xx with binman. Enabled for T2080QDS.
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 fa1a8dc..6869ac8 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/armv7/ls102xa/Makefile b/arch/arm/cpu/armv7/ls102xa/Makefile
index f8300c7..0c1596f 100644
--- a/arch/arm/cpu/armv7/ls102xa/Makefile
+++ b/arch/arm/cpu/armv7/ls102xa/Makefile
@@ -10,7 +10,6 @@
 obj-y	+= fsl_epu.o
 obj-y	+= soc.o
 
-obj-$(CONFIG_SCSI_AHCI_PLAT) += ls102xa_sata.o
 obj-$(CONFIG_OF_LIBFDT) += fdt.o
 obj-$(CONFIG_SYS_HAS_SERDES) += fsl_ls1_serdes.o ls102xa_serdes.o
 obj-$(CONFIG_SPL) += spl.o
diff --git a/arch/arm/cpu/armv7/ls102xa/ls102xa_psci.c b/arch/arm/cpu/armv7/ls102xa/ls102xa_psci.c
index af413f8..bb169aa 100644
--- a/arch/arm/cpu/armv7/ls102xa/ls102xa_psci.c
+++ b/arch/arm/cpu/armv7/ls102xa/ls102xa_psci.c
@@ -73,6 +73,7 @@
 	 * read, that is why we don't read it from register ippdexpcr1 itself.
 	 */
 	ippdexpcr1 = in_le32(&scfg->sparecr[7]);
+	out_be32(&rcpm->ippdexpcr1, ippdexpcr1);
 
 	if (ippdexpcr0 & RCPM_IPPDEXPCR0_ETSEC)
 		pmcintecr |= SCFG_PMCINTECR_ETSECRXG0 |
@@ -192,6 +193,9 @@
 	setbits_be32(&scfg->dpslpcr, SCFG_DPSLPCR_WDRR_EN);
 	setbits_be32(&gur->crstsr, DCFG_CRSTSR_WDRFR);
 
+	/* Disable QE */
+	setbits_be32(&gur->devdisr, CCSR_DEVDISR1_QE);
+
 	ls1_deepsleep_irq_cfg();
 
 	psci_v7_flush_dcache_all();
diff --git a/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c b/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c
deleted file mode 100644
index c9fe752..0000000
--- a/arch/arm/cpu/armv7/ls102xa/ls102xa_sata.c
+++ /dev/null
@@ -1,41 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0+
-/*
- * Copyright 2015 Freescale Semiconductor, Inc.
- */
-#include <common.h>
-#include <asm/io.h>
-#include <asm/arch/immap_ls102xa.h>
-#include <ahci.h>
-#include <scsi.h>
-
-/* port register default value */
-#define AHCI_PORT_PHY_1_CFG	0xa003fffe
-#define AHCI_PORT_PHY_2_CFG	0x28183414
-#define AHCI_PORT_PHY_3_CFG	0x0e080e06
-#define AHCI_PORT_PHY_4_CFG	0x064a080b
-#define AHCI_PORT_PHY_5_CFG	0x2aa86470
-#define AHCI_PORT_TRANS_CFG	0x08000029
-
-#define SATA_ECC_REG_ADDR	0x20220520
-#define SATA_ECC_DISABLE	0x00020000
-
-int ls1021a_sata_init(void)
-{
-	struct ccsr_ahci __iomem *ccsr_ahci = (void *)AHCI_BASE_ADDR;
-
-#ifdef CONFIG_SYS_FSL_ERRATUM_A008407
-	out_le32((void *)SATA_ECC_REG_ADDR, SATA_ECC_DISABLE);
-#endif
-
-	out_le32(&ccsr_ahci->ppcfg, AHCI_PORT_PHY_1_CFG);
-	out_le32(&ccsr_ahci->pp2c, AHCI_PORT_PHY_2_CFG);
-	out_le32(&ccsr_ahci->pp3c, AHCI_PORT_PHY_3_CFG);
-	out_le32(&ccsr_ahci->pp4c, AHCI_PORT_PHY_4_CFG);
-	out_le32(&ccsr_ahci->pp5c, AHCI_PORT_PHY_5_CFG);
-	out_le32(&ccsr_ahci->ptc, AHCI_PORT_TRANS_CFG);
-
-	ahci_init((void __iomem *)AHCI_BASE_ADDR);
-	scsi_scan(false);
-
-	return 0;
-}
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/Makefile b/arch/arm/cpu/armv8/fsl-layerscape/Makefile
index 5d6f68a..91fdbad 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/Makefile
+++ b/arch/arm/cpu/armv8/fsl-layerscape/Makefile
@@ -29,6 +29,7 @@
 ifneq ($(CONFIG_ARCH_LS1043A),)
 obj-$(CONFIG_SYS_HAS_SERDES) += ls1043a_serdes.o
 obj-$(CONFIG_ARMV8_PSCI) += ls1043a_psci.o
+obj-y += icid.o ls1043_ids.o
 endif
 
 ifneq ($(CONFIG_ARCH_LS1012A),)
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/fsl-layerscape/fsl_lsch3_speed.c b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c
index 653c6dd..bc268e2 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/fsl_lsch3_speed.c
@@ -192,6 +192,16 @@
 	return get_bus_freq(0) / CONFIG_SYS_FSL_DSPI_CLK_DIV;
 }
 
+#ifdef CONFIG_FSL_ESDHC
+int get_sdhc_freq(ulong dummy)
+{
+	if (!gd->arch.sdhc_clk)
+		get_clocks();
+
+	return gd->arch.sdhc_clk;
+}
+#endif
+
 int get_serial_clock(void)
 {
 	return get_bus_freq(0) / CONFIG_SYS_FSL_DUART_CLK_DIV;
@@ -202,6 +212,10 @@
 	switch (clk) {
 	case MXC_I2C_CLK:
 		return get_i2c_freq(0);
+#if defined(CONFIG_FSL_ESDHC)
+	case MXC_ESDHC_CLK:
+		return get_sdhc_freq(0);
+#endif
 	case MXC_DSPI_CLK:
 		return get_dspi_freq(0);
 	default:
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ls1043_ids.c b/arch/arm/cpu/armv8/fsl-layerscape/ls1043_ids.c
new file mode 100644
index 0000000..0e86494
--- /dev/null
+++ b/arch/arm/cpu/armv8/fsl-layerscape/ls1043_ids.c
@@ -0,0 +1,90 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright 2018 NXP
+ */
+
+#include <common.h>
+#include <asm/arch-fsl-layerscape/immap_lsch2.h>
+#include <asm/arch-fsl-layerscape/fsl_icid.h>
+#include <asm/arch-fsl-layerscape/fsl_portals.h>
+#include <fsl_sec.h>
+
+#ifdef CONFIG_SYS_DPAA_QBMAN
+struct qportal_info qp_info[CONFIG_SYS_QMAN_NUM_PORTALS] = {
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+	SET_QP_INFO(FSL_DPAA1_STREAM_ID_END, 0),
+};
+#endif
+
+struct icid_id_table icid_tbl[] = {
+#ifdef CONFIG_SYS_DPAA_QBMAN
+	SET_QMAN_ICID(FSL_DPAA1_STREAM_ID_START),
+	SET_BMAN_ICID(FSL_DPAA1_STREAM_ID_START + 1),
+#endif
+
+	SET_SDHC_ICID(FSL_SDHC_STREAM_ID),
+
+	SET_USB_ICID(1, "snps,dwc3", FSL_USB1_STREAM_ID),
+	SET_USB_ICID(2, "snps,dwc3", FSL_USB2_STREAM_ID),
+	SET_USB_ICID(3, "snps,dwc3", FSL_USB3_STREAM_ID),
+
+	SET_SATA_ICID("fsl,ls1043a-ahci", FSL_SATA_STREAM_ID),
+	SET_QDMA_ICID("fsl,ls1043a-qdma", FSL_QDMA_STREAM_ID),
+	SET_EDMA_ICID(FSL_EDMA_STREAM_ID),
+	SET_ETR_ICID(FSL_ETR_STREAM_ID),
+	SET_DEBUG_ICID(FSL_DEBUG_STREAM_ID),
+	SET_QE_ICID(FSL_QE_STREAM_ID),
+#ifdef CONFIG_FSL_CAAM
+	SET_SEC_QI_ICID(FSL_DPAA1_STREAM_ID_START + 2),
+	SET_SEC_JR_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 3),
+	SET_SEC_JR_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 4),
+	SET_SEC_JR_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 5),
+	SET_SEC_JR_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 6),
+	SET_SEC_RTIC_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 7),
+	SET_SEC_RTIC_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 8),
+	SET_SEC_RTIC_ICID_ENTRY(2, FSL_DPAA1_STREAM_ID_START + 9),
+	SET_SEC_RTIC_ICID_ENTRY(3, FSL_DPAA1_STREAM_ID_START + 10),
+	SET_SEC_DECO_ICID_ENTRY(0, FSL_DPAA1_STREAM_ID_START + 11),
+	SET_SEC_DECO_ICID_ENTRY(1, FSL_DPAA1_STREAM_ID_START + 12),
+#endif
+};
+
+int icid_tbl_sz = ARRAY_SIZE(icid_tbl);
+
+#ifdef CONFIG_SYS_DPAA_FMAN
+struct fman_icid_id_table fman_icid_tbl[] = {
+	/* port id, icid */
+	SET_FMAN_ICID_ENTRY(0x02, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x03, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x04, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x05, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x06, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x07, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x08, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x09, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x0a, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x0b, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x0c, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x0d, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x28, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x29, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x2a, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x2b, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x2c, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x2d, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x10, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x11, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x30, FSL_DPAA1_STREAM_ID_END),
+	SET_FMAN_ICID_ENTRY(0x31, FSL_DPAA1_STREAM_ID_END),
+};
+
+int fman_icid_tbl_sz = ARRAY_SIZE(fman_icid_tbl);
+#endif
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c
index a31c4d9..d391f93 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/ppa.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/ppa.c
@@ -99,7 +99,7 @@
 	cnt = DIV_ROUND_UP(fdt_header_len, 512);
 	debug("%s: MMC read PPA FIT header: dev # %u, block # %u, count %u\n",
 	      __func__, dev, blk, cnt);
-	ret = mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, fitp);
+	ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, fitp);
 	if (ret != cnt) {
 		free(fitp);
 		printf("MMC/SD read of PPA FIT header at offset 0x%x failed\n",
@@ -123,7 +123,7 @@
 
 	blk = CONFIG_SYS_LS_PPA_ESBC_ADDR >> 9;
 	cnt = DIV_ROUND_UP(CONFIG_LS_PPA_ESBC_HDR_SIZE, 512);
-	ret = mmc->block_dev.block_read(&mmc->block_dev, blk, cnt, ppa_hdr_ddr);
+	ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, ppa_hdr_ddr);
 	if (ret != cnt) {
 		free(ppa_hdr_ddr);
 		printf("MMC/SD read of PPA header failed\n");
@@ -149,8 +149,7 @@
 	cnt = DIV_ROUND_UP(fw_length, 512);
 	debug("%s: MMC read PPA FIT image: dev # %u, block # %u, count %u\n",
 	      __func__, dev, blk, cnt);
-	ret = mmc->block_dev.block_read(&mmc->block_dev,
-					blk, cnt, ppa_fit_addr);
+	ret = blk_dread(mmc_get_blk_desc(mmc), blk, cnt, ppa_fit_addr);
 	if (ret != cnt) {
 		free(ppa_fit_addr);
 		printf("MMC/SD read of PPA FIT header at offset 0x%x failed\n",
diff --git a/arch/arm/cpu/armv8/fsl-layerscape/soc.c b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
index 3f15cb0..54fb074 100644
--- a/arch/arm/cpu/armv8/fsl-layerscape/soc.c
+++ b/arch/arm/cpu/armv8/fsl-layerscape/soc.c
@@ -634,7 +634,7 @@
 	erratum_a008997();
 	erratum_a009007();
 
-#ifdef CONFIG_ARCH_LS1046A
+#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
 	set_icids();
 #endif
 }
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/fsl-ls1043a-qds.dtsi b/arch/arm/dts/fsl-ls1043a-qds.dtsi
index addb9ab..3841aee 100644
--- a/arch/arm/dts/fsl-ls1043a-qds.dtsi
+++ b/arch/arm/dts/fsl-ls1043a-qds.dtsi
@@ -174,3 +174,7 @@
 &lpuart0 {
 	status = "okay";
 };
+
+&sata {
+	status = "okay";
+};
diff --git a/arch/arm/dts/fsl-ls1043a.dtsi b/arch/arm/dts/fsl-ls1043a.dtsi
index ff40122..bb70992 100644
--- a/arch/arm/dts/fsl-ls1043a.dtsi
+++ b/arch/arm/dts/fsl-ls1043a.dtsi
@@ -70,6 +70,14 @@
 			status = "disabled";
 		};
 
+		esdhc: esdhc@1560000 {
+			compatible = "fsl,esdhc";
+			reg = <0x0 0x1560000 0x0 0x10000>;
+			interrupts = <0 62 0x4>;
+			big-endian;
+			bus-width = <4>;
+		};
+
 		ifc: ifc@1530000 {
 			compatible = "fsl,ifc", "simple-bus";
 			reg = <0x0 0x1530000 0x0 0x10000>;
@@ -279,5 +287,13 @@
 			ranges = <0x81000000 0x0 0x00000000 0x50 0x00020000 0x0 0x00010000   /* downstream I/O */
 				  0x82000000 0x0 0x40000000 0x50 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
 		};
+
+		sata: sata@3200000 {
+			compatible = "fsl,ls1043a-ahci";
+			reg = <0x0 0x3200000 0x0 0x10000>;
+			interrupts = <0 69 4>;
+			clocks = <&clockgen 4 0>;
+			status = "disabled";
+		};
 	};
 };
diff --git a/arch/arm/dts/fsl-ls1046a.dtsi b/arch/arm/dts/fsl-ls1046a.dtsi
index 4acbaf7..7687d12 100644
--- a/arch/arm/dts/fsl-ls1046a.dtsi
+++ b/arch/arm/dts/fsl-ls1046a.dtsi
@@ -70,6 +70,14 @@
 			status = "disabled";
 		};
 
+		esdhc: esdhc@1560000 {
+			compatible = "fsl,esdhc";
+			reg = <0x0 0x1560000 0x0 0x10000>;
+			interrupts = <0 62 0x4>;
+			big-endian;
+			bus-width = <4>;
+		};
+
 		ifc: ifc@1530000 {
 			compatible = "fsl,ifc", "simple-bus";
 			reg = <0x0 0x1530000 0x0 0x10000>;
diff --git a/arch/arm/dts/fsl-ls1088a.dtsi b/arch/arm/dts/fsl-ls1088a.dtsi
index 077caf3..72d755a 100644
--- a/arch/arm/dts/fsl-ls1088a.dtsi
+++ b/arch/arm/dts/fsl-ls1088a.dtsi
@@ -74,6 +74,15 @@
 		reg-names = "QuadSPI", "QuadSPI-memory";
 		num-cs = <4>;
 	};
+
+	esdhc: esdhc@2140000 {
+		compatible = "fsl,esdhc";
+		reg = <0x0 0x2140000 0x0 0x10000>;
+		interrupts = <0 28 0x4>; /* Level high type */
+		little-endian;
+		bus-width = <4>;
+	};
+
 	ifc: ifc@1530000 {
 		compatible = "fsl,ifc", "simple-bus";
 		reg = <0x0 0x2240000 0x0 0x20000>;
diff --git a/arch/arm/dts/fsl-ls2080a.dtsi b/arch/arm/dts/fsl-ls2080a.dtsi
index b0f8517..2d537ae 100644
--- a/arch/arm/dts/fsl-ls2080a.dtsi
+++ b/arch/arm/dts/fsl-ls2080a.dtsi
@@ -75,6 +75,14 @@
 		num-cs = <4>;
 	};
 
+	esdhc: esdhc@0 {
+		compatible = "fsl,esdhc";
+		reg = <0x0 0x2140000 0x0 0x10000>;
+		interrupts = <0 28 0x4>; /* Level high type */
+		little-endian;
+		bus-width = <4>;
+	};
+
 	usb0: usb3@3100000 {
 		compatible = "fsl,layerscape-dwc3";
 		reg = <0x0 0x3100000 0x0 0x10000>;
diff --git a/arch/arm/dts/ls1021a-qds.dtsi b/arch/arm/dts/ls1021a-qds.dtsi
index fb1af15..47c128f 100644
--- a/arch/arm/dts/ls1021a-qds.dtsi
+++ b/arch/arm/dts/ls1021a-qds.dtsi
@@ -212,3 +212,7 @@
 &uart1 {
 	status = "okay";
 };
+
+&sata {
+	status = "okay";
+};
diff --git a/arch/arm/dts/ls1021a-twr.dtsi b/arch/arm/dts/ls1021a-twr.dtsi
index 63f2079..14e0cea 100644
--- a/arch/arm/dts/ls1021a-twr.dtsi
+++ b/arch/arm/dts/ls1021a-twr.dtsi
@@ -103,3 +103,7 @@
 &uart1 {
 	status = "okay";
 };
+
+&sata {
+	status = "okay";
+};
diff --git a/arch/arm/dts/ls1021a.dtsi b/arch/arm/dts/ls1021a.dtsi
index 5b3fc6a..7670a39 100644
--- a/arch/arm/dts/ls1021a.dtsi
+++ b/arch/arm/dts/ls1021a.dtsi
@@ -96,7 +96,6 @@
 			sdhci,auto-cmd12;
 			big-endian;
 			bus-width = <4>;
-			status = "disabled";
 		};
 
 		scfg: scfg@1570000 {
@@ -404,5 +403,12 @@
 			ranges = <0x81000000 0x0 0x00000000 0x34020000 0x0 0x00010000   /* downstream I/O */
 				  0x82000000 0x0 0x38000000 0x38000000 0x0 0x08000000>; /* non-prefetchable memory */
 		};
+
+		sata: sata@3200000 {
+			compatible = "fsl,ls1021a-ahci";
+			reg = <0x3200000 0x10000>;
+			interrupts = <0 101 4>;
+			status = "disabled";
+		};
 	};
 };
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-fsl-layerscape/config.h b/arch/arm/include/asm/arch-fsl-layerscape/config.h
index 8a05148..bd4ca88 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/config.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/config.h
@@ -195,6 +195,7 @@
 /* SoC related */
 #ifdef CONFIG_ARCH_LS1043A
 #define CONFIG_SYS_FMAN_V3
+#define CONFIG_SYS_FSL_QMAN_V3
 #define CONFIG_SYS_NUM_FMAN			1
 #define CONFIG_SYS_NUM_FM1_DTSEC		7
 #define CONFIG_SYS_NUM_FM1_10GEC		1
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/fsl_icid.h b/arch/arm/include/asm/arch-fsl-layerscape/fsl_icid.h
index a70c866..a3f473f 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/fsl_icid.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/fsl_icid.h
@@ -68,6 +68,10 @@
 #define SET_DEBUG_ICID(streamid) \
 	SET_SCFG_ICID(NULL, streamid, debug_icid, 0)
 
+#define SET_QE_ICID(streamid) \
+	SET_SCFG_ICID("fsl,qe", streamid, qe_icid,\
+		QE_BASE_ADDR)
+
 #define SET_QMAN_ICID(streamid) \
 	SET_ICID_ENTRY("fsl,qman", streamid, streamid, \
 		offsetof(struct ccsr_qman, liodnr) + \
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch2.h b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch2.h
index be0a6ae..8c10526 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch2.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/immap_lsch2.h
@@ -85,6 +85,8 @@
 #define GPIO3_BASE_ADDR				(CONFIG_SYS_IMMR + 0x1320000)
 #define GPIO4_BASE_ADDR				(CONFIG_SYS_IMMR + 0x1330000)
 
+#define QE_BASE_ADDR				(CONFIG_SYS_IMMR + 0x1400000)
+
 #define LPUART_BASE				(CONFIG_SYS_IMMR + 0x01950000)
 
 #define EDMA_BASE_ADDR				(CONFIG_SYS_IMMR + 0x01c00000)
diff --git a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
index afea9b8..8d002da 100644
--- a/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
+++ b/arch/arm/include/asm/arch-fsl-layerscape/stream_id_lsch3.h
@@ -35,6 +35,9 @@
  *  -DPAA2
  *     -u-boot will allocate a range of stream IDs to be used by the Management
  *      Complex for containers and will set these values in the MC DPC image.
+ *     -u-boot will fixup the iommu-map property in the fsl-mc node in the
+ *      device tree (see Documentation/devicetree/bindings/misc/fsl,qoriq-mc.txt
+ *      for more info on the msi-map definition)
  *     -the MC is responsible for allocating and setting up 'isolation context
  *      IDs (ICIDs) based on the allocated stream IDs for all DPAA2 devices.
  *
diff --git a/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h b/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h
index 13a282f..137cd61 100644
--- a/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h
+++ b/arch/arm/include/asm/arch-ls102xa/immap_ls102xa.h
@@ -86,6 +86,8 @@
 	unsigned long freq_localbus;
 };
 
+#define CCSR_DEVDISR1_QE	0x00000001
+
 /* Device Configuration and Pin Control */
 struct ccsr_gur {
 	u32     porsr1;         /* POR status 1 */
@@ -389,33 +391,6 @@
 	u8	res_a00[0x1000-0xa00];	/* from 0xa00 to 0xfff */
 };
 
-
-
-/* AHCI (sata) register map */
-struct ccsr_ahci {
-	u32 res1[0xa4/4];	/* 0x0 - 0xa4 */
-	u32 pcfg;	/* port config */
-	u32 ppcfg;	/* port phy1 config */
-	u32 pp2c;	/* port phy2 config */
-	u32 pp3c;	/* port phy3 config */
-	u32 pp4c;	/* port phy4 config */
-	u32 pp5c;	/* port phy5 config */
-	u32 paxic;	/* port AXI config */
-	u32 axicc;	/* AXI cache control */
-	u32 axipc;	/* AXI PROT control */
-	u32 ptc;	/* port Trans Config */
-	u32 pts;	/* port Trans Status */
-	u32 plc;	/* port link config */
-	u32 plc1;	/* port link config1 */
-	u32 plc2;	/* port link config2 */
-	u32 pls;	/* port link status */
-	u32 pls1;	/* port link status1 */
-	u32 pcmdc;	/* port CMD config */
-	u32 ppcs;	/* port phy control status */
-	u32 pberr;	/* port 0/1 BIST error */
-	u32 cmds;	/* port 0/1 CMD status error */
-};
-
 #define RCPM_POWMGTCSR			0x130
 #define RCPM_POWMGTCSR_SERDES_PW	0x80000000
 #define RCPM_POWMGTCSR_LPM20_REQ	0x00100000
diff --git a/arch/arm/include/asm/arch-ls102xa/ls102xa_sata.h b/arch/arm/include/asm/arch-ls102xa/ls102xa_sata.h
deleted file mode 100644
index 3acc5af..0000000
--- a/arch/arm/include/asm/arch-ls102xa/ls102xa_sata.h
+++ /dev/null
@@ -1,10 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0+ */
-/*
- * Copyright 2015 Freescale Semiconductor, Inc.
- */
-
-#ifndef __FSL_SATA_H_
-#define __FSL_SATA_H_
-
-int ls1021a_sata_init(void);
-#endif
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/freescale/ls1012afrdm/ls1012afrdm.c b/board/freescale/ls1012afrdm/ls1012afrdm.c
index 315da8b..5db1027 100644
--- a/board/freescale/ls1012afrdm/ls1012afrdm.c
+++ b/board/freescale/ls1012afrdm/ls1012afrdm.c
@@ -24,11 +24,15 @@
 
 static inline int get_board_version(void)
 {
-	struct ccsr_gpio *pgpio = (void *)(GPIO1_BASE_ADDR);
-	int val;
+	uint32_t val;
+#ifdef CONFIG_TARGET_LS1012AFRDM
+	val = 0;
+#else
+	struct ccsr_gpio *pgpio = (void *)(GPIO2_BASE_ADDR);
 
-	val = in_be32(&pgpio->gpdat);
+	val = in_be32(&pgpio->gpdat) & BOARD_REV_MASK;/*Get GPIO2 11,12,14*/
 
+#endif
 	return val;
 }
 
@@ -46,11 +50,11 @@
 	puts("Version");
 
 	switch (rev) {
-	case BOARD_REV_A:
-		puts(": RevA ");
+	case BOARD_REV_A_B:
+		puts(": RevA/B ");
 		break;
-	case BOARD_REV_B:
-		puts(": RevB ");
+	case BOARD_REV_C:
+		puts(": RevC ");
 		break;
 	default:
 		puts(": unknown");
@@ -100,7 +104,7 @@
 #ifdef CONFIG_TARGET_LS1012AFRWY
 	board_rev = get_board_version();
 
-	if (board_rev & BOARD_REV_B) {
+	if (board_rev == BOARD_REV_C) {
 		mparam.mdctl = 0x05180000;
 		gd->ram_size = SYS_SDRAM_SIZE_1024;
 	} else {
diff --git a/board/freescale/ls1021aiot/ls1021aiot.c b/board/freescale/ls1021aiot/ls1021aiot.c
index a691dab..fb05b55 100644
--- a/board/freescale/ls1021aiot/ls1021aiot.c
+++ b/board/freescale/ls1021aiot/ls1021aiot.c
@@ -11,7 +11,6 @@
 
 #include <asm/arch/ls102xa_devdis.h>
 #include <asm/arch/ls102xa_soc.h>
-#include <asm/arch/ls102xa_sata.h>
 #include <fsl_csu.h>
 #include <fsl_esdhc.h>
 #include <fsl_immap.h>
@@ -206,10 +205,6 @@
 #ifdef CONFIG_BOARD_LATE_INIT
 int board_late_init(void)
 {
-#ifdef CONFIG_SCSI_AHCI_PLAT
-	ls1021a_sata_init();
-#endif
-
 	return 0;
 }
 #endif
diff --git a/board/freescale/ls1021aqds/ls1021aqds.c b/board/freescale/ls1021aqds/ls1021aqds.c
index 6722cad..c828dac 100644
--- a/board/freescale/ls1021aqds/ls1021aqds.c
+++ b/board/freescale/ls1021aqds/ls1021aqds.c
@@ -11,7 +11,6 @@
 #include <asm/arch/fsl_serdes.h>
 #include <asm/arch/ls102xa_soc.h>
 #include <asm/arch/ls102xa_devdis.h>
-#include <asm/arch/ls102xa_sata.h>
 #include <hwconfig.h>
 #include <mmc.h>
 #include <fsl_csu.h>
@@ -362,9 +361,6 @@
 #ifdef CONFIG_BOARD_LATE_INIT
 int board_late_init(void)
 {
-#ifdef CONFIG_SCSI_AHCI_PLAT
-	ls1021a_sata_init();
-#endif
 #ifdef CONFIG_CHAIN_OF_TRUST
 	fsl_setenv_chain_of_trust();
 #endif
diff --git a/board/freescale/ls1021atwr/ls1021atwr.c b/board/freescale/ls1021atwr/ls1021atwr.c
index 863bf76..dcd6d93 100644
--- a/board/freescale/ls1021atwr/ls1021atwr.c
+++ b/board/freescale/ls1021atwr/ls1021atwr.c
@@ -11,7 +11,6 @@
 #include <asm/arch/fsl_serdes.h>
 #include <asm/arch/ls102xa_devdis.h>
 #include <asm/arch/ls102xa_soc.h>
-#include <asm/arch/ls102xa_sata.h>
 #include <hwconfig.h>
 #include <mmc.h>
 #include <fsl_csu.h>
@@ -556,9 +555,6 @@
 #ifdef CONFIG_BOARD_LATE_INIT
 int board_late_init(void)
 {
-#ifdef CONFIG_SCSI_AHCI_PLAT
-	ls1021a_sata_init();
-#endif
 #ifdef CONFIG_CHAIN_OF_TRUST
 	fsl_setenv_chain_of_trust();
 #endif
diff --git a/board/freescale/ls1043aqds/ls1043aqds.c b/board/freescale/ls1043aqds/ls1043aqds.c
index 4fba572..44cc509 100644
--- a/board/freescale/ls1043aqds/ls1043aqds.c
+++ b/board/freescale/ls1043aqds/ls1043aqds.c
@@ -14,6 +14,7 @@
 #include <asm/arch/fdt.h>
 #include <asm/arch/mmu.h>
 #include <asm/arch/soc.h>
+#include <asm/arch-fsl-layerscape/fsl_icid.h>
 #include <ahci.h>
 #include <hwconfig.h>
 #include <mmc.h>
@@ -353,6 +354,8 @@
 	fdt_fixup_board_enet(blob);
 #endif
 
+	fdt_fixup_icid(blob);
+
 	reg = QIXIS_READ(brdcfg[0]);
 	reg = (reg & QIXIS_LBMAP_MASK) >> QIXIS_LBMAP_SHIFT;
 
diff --git a/board/freescale/ls1043ardb/ls1043ardb.c b/board/freescale/ls1043ardb/ls1043ardb.c
index e7d8650..f31f0ec 100644
--- a/board/freescale/ls1043ardb/ls1043ardb.c
+++ b/board/freescale/ls1043ardb/ls1043ardb.c
@@ -9,6 +9,7 @@
 #include <asm/arch/clock.h>
 #include <asm/arch/fsl_serdes.h>
 #include <asm/arch/soc.h>
+#include <asm/arch-fsl-layerscape/fsl_icid.h>
 #include <fdt_support.h>
 #include <hwconfig.h>
 #include <ahci.h>
@@ -177,6 +178,8 @@
 	fdt_fixup_fman_ethernet(blob);
 #endif
 
+	fdt_fixup_icid(blob);
+
 	/*
 	 * qe-hdlc and usb multi-use the pins,
 	 * when set hwconfig to qe-hdlc, delete usb node.
diff --git a/board/freescale/ls1088a/ls1088a.c b/board/freescale/ls1088a/ls1088a.c
index a0dab6f..517a8ce 100644
--- a/board/freescale/ls1088a/ls1088a.c
+++ b/board/freescale/ls1088a/ls1088a.c
@@ -575,6 +575,8 @@
 
 	fdt_fixup_memory_banks(blob, base, size, CONFIG_NR_DRAM_BANKS);
 
+	fdt_fsl_mc_fixup_iommu_map_entry(blob);
+
 	fsl_fdt_fixup_flash(blob);
 
 #ifdef CONFIG_FSL_MC_ENET
diff --git a/board/freescale/ls2080a/ls2080a.c b/board/freescale/ls2080a/ls2080a.c
index 75014fd..698ae1f 100644
--- a/board/freescale/ls2080a/ls2080a.c
+++ b/board/freescale/ls2080a/ls2080a.c
@@ -127,6 +127,8 @@
 
 	fdt_fixup_memory_banks(blob, base, size, 2);
 
+	fdt_fsl_mc_fixup_iommu_map_entry(blob);
+
 #if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
 	fdt_fixup_board_enet(blob);
 #endif
diff --git a/board/freescale/ls2080aqds/ls2080aqds.c b/board/freescale/ls2080aqds/ls2080aqds.c
index c811e99..d336ef8 100644
--- a/board/freescale/ls2080aqds/ls2080aqds.c
+++ b/board/freescale/ls2080aqds/ls2080aqds.c
@@ -332,6 +332,8 @@
 
 	fdt_fixup_memory_banks(blob, base, size, 2);
 
+	fdt_fsl_mc_fixup_iommu_map_entry(blob);
+
 	fsl_fdt_fixup_dr_usb(blob, bd);
 
 #if defined(CONFIG_FSL_MC_ENET) && !defined(CONFIG_SPL_BUILD)
diff --git a/board/freescale/ls2080ardb/ls2080ardb.c b/board/freescale/ls2080ardb/ls2080ardb.c
index 46b18cf..cf91bc3 100644
--- a/board/freescale/ls2080ardb/ls2080ardb.c
+++ b/board/freescale/ls2080ardb/ls2080ardb.c
@@ -394,6 +394,8 @@
 
 	fdt_fixup_memory_banks(blob, base, size, 2);
 
+	fdt_fsl_mc_fixup_iommu_map_entry(blob);
+
 	fsl_fdt_fixup_dr_usb(blob, bd);
 
 	fsl_fdt_fixup_flash(blob);
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/ls1021atwr_nor_SECURE_BOOT_defconfig b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
index a7742b4..1d1586d 100644
--- a/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
+++ b/configs/ls1021atwr_nor_SECURE_BOOT_defconfig
@@ -50,3 +50,5 @@
 # CONFIG_VIDEO_SW_CURSOR is not set
 CONFIG_RSA=y
 CONFIG_SPL_RSA=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1021atwr_nor_defconfig b/configs/ls1021atwr_nor_defconfig
index e9224b0..c226863 100644
--- a/configs/ls1021atwr_nor_defconfig
+++ b/configs/ls1021atwr_nor_defconfig
@@ -50,3 +50,10 @@
 CONFIG_VIDEO_FSL_DCU_FB=y
 CONFIG_VIDEO=y
 # CONFIG_VIDEO_SW_CURSOR is not set
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
+CONFIG_DM_SCSI=y
+CONFIG_SATA_CEVA=y
+CONFIG_SCSI_AHCI=y
+CONFIG_SCSI=y
+CONFIG_AHCI=y
diff --git a/configs/ls1021atwr_nor_lpuart_defconfig b/configs/ls1021atwr_nor_lpuart_defconfig
index 5619d23..221755c 100644
--- a/configs/ls1021atwr_nor_lpuart_defconfig
+++ b/configs/ls1021atwr_nor_lpuart_defconfig
@@ -51,3 +51,5 @@
 CONFIG_VIDEO_FSL_DCU_FB=y
 CONFIG_VIDEO=y
 # CONFIG_VIDEO_SW_CURSOR is not set
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1021atwr_qspi_defconfig b/configs/ls1021atwr_qspi_defconfig
index af7939d..b59fdf3 100644
--- a/configs/ls1021atwr_qspi_defconfig
+++ b/configs/ls1021atwr_qspi_defconfig
@@ -57,3 +57,5 @@
 CONFIG_VIDEO_FSL_DCU_FB=y
 CONFIG_VIDEO=y
 # CONFIG_VIDEO_SW_CURSOR is not set
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1021atwr_sdcard_ifc_defconfig b/configs/ls1021atwr_sdcard_ifc_defconfig
index e5d2b28..2dfe44d 100644
--- a/configs/ls1021atwr_sdcard_ifc_defconfig
+++ b/configs/ls1021atwr_sdcard_ifc_defconfig
@@ -61,3 +61,5 @@
 CONFIG_VIDEO_FSL_DCU_FB=y
 CONFIG_VIDEO=y
 # CONFIG_VIDEO_SW_CURSOR is not set
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1021atwr_sdcard_qspi_defconfig b/configs/ls1021atwr_sdcard_qspi_defconfig
index 54813b4..94c16da 100644
--- a/configs/ls1021atwr_sdcard_qspi_defconfig
+++ b/configs/ls1021atwr_sdcard_qspi_defconfig
@@ -67,3 +67,5 @@
 CONFIG_VIDEO_FSL_DCU_FB=y
 CONFIG_VIDEO=y
 # CONFIG_VIDEO_SW_CURSOR is not set
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_defconfig b/configs/ls1043aqds_defconfig
index 493b582..fe0aeaf 100644
--- a/configs/ls1043aqds_defconfig
+++ b/configs/ls1043aqds_defconfig
@@ -47,3 +47,10 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
+CONFIG_DM_SCSI=y
+CONFIG_SATA_CEVA=y
+CONFIG_SCSI_AHCI=y
+CONFIG_SCSI=y
+CONFIG_AHCI=y
diff --git a/configs/ls1043aqds_lpuart_defconfig b/configs/ls1043aqds_lpuart_defconfig
index b91542c..2e06f6d 100644
--- a/configs/ls1043aqds_lpuart_defconfig
+++ b/configs/ls1043aqds_lpuart_defconfig
@@ -49,3 +49,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_nand_defconfig b/configs/ls1043aqds_nand_defconfig
index 779a8bf..aed30c1 100644
--- a/configs/ls1043aqds_nand_defconfig
+++ b/configs/ls1043aqds_nand_defconfig
@@ -62,3 +62,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_nor_ddr3_defconfig b/configs/ls1043aqds_nor_ddr3_defconfig
index 2d098d3..c1e86d1 100644
--- a/configs/ls1043aqds_nor_ddr3_defconfig
+++ b/configs/ls1043aqds_nor_ddr3_defconfig
@@ -48,3 +48,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_qspi_defconfig b/configs/ls1043aqds_qspi_defconfig
index 55935f2..b0a562e 100644
--- a/configs/ls1043aqds_qspi_defconfig
+++ b/configs/ls1043aqds_qspi_defconfig
@@ -46,3 +46,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_sdcard_ifc_defconfig b/configs/ls1043aqds_sdcard_ifc_defconfig
index ad18b46..b37d52d 100644
--- a/configs/ls1043aqds_sdcard_ifc_defconfig
+++ b/configs/ls1043aqds_sdcard_ifc_defconfig
@@ -62,3 +62,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043aqds_sdcard_qspi_defconfig b/configs/ls1043aqds_sdcard_qspi_defconfig
index 7aa271f..2ef5b01 100644
--- a/configs/ls1043aqds_sdcard_qspi_defconfig
+++ b/configs/ls1043aqds_sdcard_qspi_defconfig
@@ -59,3 +59,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043ardb_SECURE_BOOT_defconfig b/configs/ls1043ardb_SECURE_BOOT_defconfig
index 83a7afb..28027ff 100644
--- a/configs/ls1043ardb_SECURE_BOOT_defconfig
+++ b/configs/ls1043ardb_SECURE_BOOT_defconfig
@@ -45,3 +45,5 @@
 CONFIG_RSA=y
 CONFIG_SPL_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043ardb_defconfig b/configs/ls1043ardb_defconfig
index c72231b..df68b94 100644
--- a/configs/ls1043ardb_defconfig
+++ b/configs/ls1043ardb_defconfig
@@ -43,3 +43,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043ardb_nand_SECURE_BOOT_defconfig b/configs/ls1043ardb_nand_SECURE_BOOT_defconfig
index 64e41ec..97364b0 100644
--- a/configs/ls1043ardb_nand_SECURE_BOOT_defconfig
+++ b/configs/ls1043ardb_nand_SECURE_BOOT_defconfig
@@ -62,3 +62,5 @@
 CONFIG_USB_STORAGE=y
 CONFIG_RSA=y
 CONFIG_SPL_RSA=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043ardb_nand_defconfig b/configs/ls1043ardb_nand_defconfig
index a3d1ee8..476bb90 100644
--- a/configs/ls1043ardb_nand_defconfig
+++ b/configs/ls1043ardb_nand_defconfig
@@ -60,3 +60,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1043ardb_sdcard_defconfig b/configs/ls1043ardb_sdcard_defconfig
index b44c35d..9543800 100644
--- a/configs/ls1043ardb_sdcard_defconfig
+++ b/configs/ls1043ardb_sdcard_defconfig
@@ -58,3 +58,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_SECURE_BOOT_defconfig b/configs/ls1046aqds_SECURE_BOOT_defconfig
index 01effd9..bab8009 100644
--- a/configs/ls1046aqds_SECURE_BOOT_defconfig
+++ b/configs/ls1046aqds_SECURE_BOOT_defconfig
@@ -49,3 +49,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_RSA=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_defconfig b/configs/ls1046aqds_defconfig
index ca1703b..fad2eed 100644
--- a/configs/ls1046aqds_defconfig
+++ b/configs/ls1046aqds_defconfig
@@ -49,3 +49,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_lpuart_defconfig b/configs/ls1046aqds_lpuart_defconfig
index 9b0200d..08f2f14 100644
--- a/configs/ls1046aqds_lpuart_defconfig
+++ b/configs/ls1046aqds_lpuart_defconfig
@@ -51,3 +51,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_nand_defconfig b/configs/ls1046aqds_nand_defconfig
index b1ecedf..3d30205 100644
--- a/configs/ls1046aqds_nand_defconfig
+++ b/configs/ls1046aqds_nand_defconfig
@@ -56,3 +56,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_qspi_defconfig b/configs/ls1046aqds_qspi_defconfig
index e5495ad..56443ad 100644
--- a/configs/ls1046aqds_qspi_defconfig
+++ b/configs/ls1046aqds_qspi_defconfig
@@ -49,3 +49,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_sdcard_ifc_defconfig b/configs/ls1046aqds_sdcard_ifc_defconfig
index 7fd3e77..e9c101f 100644
--- a/configs/ls1046aqds_sdcard_ifc_defconfig
+++ b/configs/ls1046aqds_sdcard_ifc_defconfig
@@ -65,3 +65,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046aqds_sdcard_qspi_defconfig b/configs/ls1046aqds_sdcard_qspi_defconfig
index a3eea7a..021d4f9 100644
--- a/configs/ls1046aqds_sdcard_qspi_defconfig
+++ b/configs/ls1046aqds_sdcard_qspi_defconfig
@@ -64,3 +64,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046ardb_emmc_defconfig b/configs/ls1046ardb_emmc_defconfig
index e0f07b7..3968136 100644
--- a/configs/ls1046ardb_emmc_defconfig
+++ b/configs/ls1046ardb_emmc_defconfig
@@ -60,3 +60,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046ardb_qspi_SECURE_BOOT_defconfig b/configs/ls1046ardb_qspi_SECURE_BOOT_defconfig
index 6495447..c142df3 100644
--- a/configs/ls1046ardb_qspi_SECURE_BOOT_defconfig
+++ b/configs/ls1046ardb_qspi_SECURE_BOOT_defconfig
@@ -46,3 +46,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_RSA=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046ardb_qspi_defconfig b/configs/ls1046ardb_qspi_defconfig
index 5204bb5..f9660c0 100644
--- a/configs/ls1046ardb_qspi_defconfig
+++ b/configs/ls1046ardb_qspi_defconfig
@@ -46,3 +46,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1046ardb_sdcard_defconfig b/configs/ls1046ardb_sdcard_defconfig
index 07eebbf..9486e90 100644
--- a/configs/ls1046ardb_sdcard_defconfig
+++ b/configs/ls1046ardb_sdcard_defconfig
@@ -59,3 +59,5 @@
 CONFIG_USB_XHCI_HCD=y
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088aqds_defconfig b/configs/ls1088aqds_defconfig
index 1d288ab..64677f0 100644
--- a/configs/ls1088aqds_defconfig
+++ b/configs/ls1088aqds_defconfig
@@ -47,3 +47,5 @@
 CONFIG_USB_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088aqds_qspi_SECURE_BOOT_defconfig b/configs/ls1088aqds_qspi_SECURE_BOOT_defconfig
index 606c52d..7c5f696 100644
--- a/configs/ls1088aqds_qspi_SECURE_BOOT_defconfig
+++ b/configs/ls1088aqds_qspi_SECURE_BOOT_defconfig
@@ -54,3 +54,5 @@
 CONFIG_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088aqds_qspi_defconfig b/configs/ls1088aqds_qspi_defconfig
index 21f64ab..9bda1b3 100644
--- a/configs/ls1088aqds_qspi_defconfig
+++ b/configs/ls1088aqds_qspi_defconfig
@@ -52,3 +52,5 @@
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088aqds_sdcard_ifc_defconfig b/configs/ls1088aqds_sdcard_ifc_defconfig
index 09ead40..b1dc2ef 100644
--- a/configs/ls1088aqds_sdcard_ifc_defconfig
+++ b/configs/ls1088aqds_sdcard_ifc_defconfig
@@ -55,3 +55,5 @@
 CONFIG_USB_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088aqds_sdcard_qspi_defconfig b/configs/ls1088aqds_sdcard_qspi_defconfig
index fad7c7f..615fb5f 100644
--- a/configs/ls1088aqds_sdcard_qspi_defconfig
+++ b/configs/ls1088aqds_sdcard_qspi_defconfig
@@ -61,3 +61,5 @@
 CONFIG_USB_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088ardb_qspi_SECURE_BOOT_defconfig b/configs/ls1088ardb_qspi_SECURE_BOOT_defconfig
index 859ff11..f54b4a9 100644
--- a/configs/ls1088ardb_qspi_SECURE_BOOT_defconfig
+++ b/configs/ls1088ardb_qspi_SECURE_BOOT_defconfig
@@ -55,3 +55,5 @@
 CONFIG_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088ardb_qspi_defconfig b/configs/ls1088ardb_qspi_defconfig
index a42158c..1feaded 100644
--- a/configs/ls1088ardb_qspi_defconfig
+++ b/configs/ls1088ardb_qspi_defconfig
@@ -53,3 +53,5 @@
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls1088ardb_sdcard_qspi_defconfig b/configs/ls1088ardb_sdcard_qspi_defconfig
index bc53bba..4b6695d 100644
--- a/configs/ls1088ardb_sdcard_qspi_defconfig
+++ b/configs/ls1088ardb_sdcard_qspi_defconfig
@@ -62,3 +62,5 @@
 CONFIG_USB_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_USB_GADGET=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080a_emu_defconfig b/configs/ls2080a_emu_defconfig
index 1f2c052..ccccc28 100644
--- a/configs/ls2080a_emu_defconfig
+++ b/configs/ls2080a_emu_defconfig
@@ -33,3 +33,5 @@
 CONFIG_SYS_NS16550=y
 CONFIG_OF_LIBFDT=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080a_simu_defconfig b/configs/ls2080a_simu_defconfig
index a4263b7..57a568d 100644
--- a/configs/ls2080a_simu_defconfig
+++ b/configs/ls2080a_simu_defconfig
@@ -36,3 +36,5 @@
 CONFIG_SYS_NS16550=y
 CONFIG_OF_LIBFDT=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080aqds_SECURE_BOOT_defconfig b/configs/ls2080aqds_SECURE_BOOT_defconfig
index a6d6dae..b8b0431 100644
--- a/configs/ls2080aqds_SECURE_BOOT_defconfig
+++ b/configs/ls2080aqds_SECURE_BOOT_defconfig
@@ -54,3 +54,5 @@
 CONFIG_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080aqds_defconfig b/configs/ls2080aqds_defconfig
index 6ada348..3026351 100644
--- a/configs/ls2080aqds_defconfig
+++ b/configs/ls2080aqds_defconfig
@@ -53,3 +53,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080aqds_nand_defconfig b/configs/ls2080aqds_nand_defconfig
index ee986d5..8669651 100644
--- a/configs/ls2080aqds_nand_defconfig
+++ b/configs/ls2080aqds_nand_defconfig
@@ -62,3 +62,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080aqds_qspi_defconfig b/configs/ls2080aqds_qspi_defconfig
index 4dbb6dd..9980caa 100644
--- a/configs/ls2080aqds_qspi_defconfig
+++ b/configs/ls2080aqds_qspi_defconfig
@@ -53,3 +53,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080aqds_sdcard_defconfig b/configs/ls2080aqds_sdcard_defconfig
index 2259178..8bcab1e 100644
--- a/configs/ls2080aqds_sdcard_defconfig
+++ b/configs/ls2080aqds_sdcard_defconfig
@@ -60,3 +60,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080ardb_SECURE_BOOT_defconfig b/configs/ls2080ardb_SECURE_BOOT_defconfig
index 3c015e3..9d79a22 100644
--- a/configs/ls2080ardb_SECURE_BOOT_defconfig
+++ b/configs/ls2080ardb_SECURE_BOOT_defconfig
@@ -55,3 +55,5 @@
 CONFIG_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080ardb_defconfig b/configs/ls2080ardb_defconfig
index a62e09b..f3ff02c 100644
--- a/configs/ls2080ardb_defconfig
+++ b/configs/ls2080ardb_defconfig
@@ -54,3 +54,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2080ardb_nand_defconfig b/configs/ls2080ardb_nand_defconfig
index 4801f51..8af5cba 100644
--- a/configs/ls2080ardb_nand_defconfig
+++ b/configs/ls2080ardb_nand_defconfig
@@ -58,3 +58,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2088ardb_qspi_SECURE_BOOT_defconfig b/configs/ls2088ardb_qspi_SECURE_BOOT_defconfig
index 5813d29..6ae8724 100644
--- a/configs/ls2088ardb_qspi_SECURE_BOOT_defconfig
+++ b/configs/ls2088ardb_qspi_SECURE_BOOT_defconfig
@@ -53,3 +53,5 @@
 CONFIG_RSA=y
 CONFIG_RSA_SOFTWARE_EXP=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=y
diff --git a/configs/ls2088ardb_qspi_defconfig b/configs/ls2088ardb_qspi_defconfig
index 944384b..ba1f168 100644
--- a/configs/ls2088ardb_qspi_defconfig
+++ b/configs/ls2088ardb_qspi_defconfig
@@ -55,3 +55,5 @@
 CONFIG_USB_XHCI_DWC3=y
 CONFIG_USB_STORAGE=y
 CONFIG_EFI_LOADER_BOUNCE_BUFFER=y
+CONFIG_BLK=y
+CONFIG_DM_MMC=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 56536c4..9ac90c4 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -74,6 +74,8 @@
 
 source "drivers/pwm/Kconfig"
 
+source "drivers/qe/Kconfig"
+
 source "drivers/ram/Kconfig"
 
 source "drivers/remoteproc/Kconfig"
@@ -106,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/ata/sata_ceva.c b/drivers/ata/sata_ceva.c
index 047cff7..65896d1 100644
--- a/drivers/ata/sata_ceva.c
+++ b/drivers/ata/sata_ceva.c
@@ -81,13 +81,24 @@
 #define CEVA_TRANS_CFG	0x08000029
 #define CEVA_AXICC_CFG	0x3fffffff
 
+/* for ls1021a */
+#define LS1021_AHCI_VEND_AXICC 0xC0
+#define LS1021_CEVA_PHY2_CFG	0x28183414
+#define LS1021_CEVA_PHY3_CFG	0x0e080e06
+#define LS1021_CEVA_PHY4_CFG	0x064a080b
+#define LS1021_CEVA_PHY5_CFG	0x2aa86470
+
 /* ecc addr-val pair */
 #define ECC_DIS_ADDR_CH2	0x80000000
-#define ECC_DIS_VAL_CH2	0x20140520
+#define ECC_DIS_VAL_CH2		0x20140520
+#define SATA_ECC_REG_ADDR	0x20220520
+#define SATA_ECC_DISABLE	0x00020000
 
 enum ceva_soc {
 	CEVA_1V84,
 	CEVA_LS1012A,
+	CEVA_LS1021A,
+	CEVA_LS1043A,
 };
 
 struct ceva_sata_priv {
@@ -113,7 +124,20 @@
 		writel(tmp, base + AHCI_VEND_PTC);
 		break;
 
+	case CEVA_LS1021A:
+		writel(SATA_ECC_DISABLE, SATA_ECC_REG_ADDR);
+		writel(CEVA_PHY1_CFG, base + AHCI_VEND_PPCFG);
+		writel(LS1021_CEVA_PHY2_CFG, base + AHCI_VEND_PP2C);
+		writel(LS1021_CEVA_PHY3_CFG, base + AHCI_VEND_PP3C);
+		writel(LS1021_CEVA_PHY4_CFG, base + AHCI_VEND_PP4C);
+		writel(LS1021_CEVA_PHY5_CFG, base + AHCI_VEND_PP5C);
+		writel(CEVA_TRANS_CFG, base + AHCI_VEND_PTC);
+		if (priv->flag & FLAG_COHERENT)
+			writel(CEVA_AXICC_CFG, base + LS1021_AHCI_VEND_AXICC);
+		break;
+
 	case CEVA_LS1012A:
+	case CEVA_LS1043A:
 		writel(ECC_DIS_ADDR_CH2, ECC_DIS_VAL_CH2);
 		writel(CEVA_PHY1_CFG, base + AHCI_VEND_PPCFG);
 		writel(CEVA_TRANS_CFG, base + AHCI_VEND_PTC);
@@ -144,6 +168,8 @@
 static const struct udevice_id sata_ceva_ids[] = {
 	{ .compatible = "ceva,ahci-1v84", .data = CEVA_1V84 },
 	{ .compatible = "fsl,ls1012a-ahci", .data = CEVA_LS1012A },
+	{ .compatible = "fsl,ls1021a-ahci", .data = CEVA_LS1021A },
+	{ .compatible = "fsl,ls1043a-ahci", .data = CEVA_LS1043A },
 	{ }
 };
 
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/misc/fsl_portals.c b/drivers/misc/fsl_portals.c
index d313768..45eed22 100644
--- a/drivers/misc/fsl_portals.c
+++ b/drivers/misc/fsl_portals.c
@@ -49,7 +49,7 @@
 		out_be32(&qman->qcsp[i].qcsp_io_cfg, (sdest << 16) | fliodn);
 	}
 #else
-#ifdef CONFIG_ARCH_LS1046A
+#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
 	int i;
 
 	for (i = 0; i < CONFIG_SYS_QMAN_NUM_PORTALS; i++) {
@@ -197,7 +197,7 @@
 	char compat[64];
 	int compat_len;
 
-#ifdef CONFIG_ARCH_LS1046A
+#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
 	int smmu_ph = fdt_get_smmu_phandle(blob);
 #endif
 
@@ -211,7 +211,8 @@
 
 	off = fdt_node_offset_by_compatible(blob, -1, "fsl,qman-portal");
 	while (off != -FDT_ERR_NOTFOUND) {
-#if defined(CONFIG_PPC) || defined(CONFIG_ARCH_LS1046A)
+#if defined(CONFIG_PPC) || defined(CONFIG_ARCH_LS1043A) || \
+defined(CONFIG_ARCH_LS1046A)
 #ifdef CONFIG_FSL_CORENET
 		u32 liodns[2];
 #endif
@@ -226,7 +227,7 @@
 		int j;
 #endif
 
-#endif /* CONFIG_PPC || CONFIG_ARCH_LS1046A */
+#endif /* CONFIG_PPC || CONFIG_ARCH_LS1043A || CONFIG_ARCH_LS1046A */
 		err = fdt_setprop(blob, off, "compatible", compat, compat_len);
 		if (err < 0)
 			goto err;
@@ -275,7 +276,7 @@
 			goto err;
 #endif
 #else
-#ifdef CONFIG_ARCH_LS1046A
+#if defined(CONFIG_ARCH_LS1043A) || defined(CONFIG_ARCH_LS1046A)
 		if (smmu_ph >= 0) {
 			u32 icids[3];
 
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/fm/fm.c b/drivers/net/fm/fm.c
index 3327073..c5cf188 100644
--- a/drivers/net/fm/fm.c
+++ b/drivers/net/fm/fm.c
@@ -402,7 +402,7 @@
 		printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
 				dev, blk, cnt);
 		mmc_init(mmc);
-		(void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt,
+		(void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
 						addr);
 	}
 #elif defined(CONFIG_SYS_QE_FMAN_FW_IN_REMOTE)
diff --git a/drivers/net/fm/init.c b/drivers/net/fm/init.c
index 147d043..f896e80 100644
--- a/drivers/net/fm/init.c
+++ b/drivers/net/fm/init.c
@@ -328,7 +328,8 @@
 				ft_fixup_port(blob, &fm_info[i],
 					      "fsl,fman-1g-mac");
 		} else {
-			if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-tgec"))
+			if (ft_fixup_port(blob, &fm_info[i], "fsl,fman-xgec") &&
+			    ft_fixup_port(blob, &fm_info[i], "fsl,fman-tgec"))
 				ft_fixup_port(blob, &fm_info[i],
 					      "fsl,fman-10g-mac");
 		}
diff --git a/drivers/net/fsl-mc/mc.c b/drivers/net/fsl-mc/mc.c
index 940025a..d9a897d 100644
--- a/drivers/net/fsl-mc/mc.c
+++ b/drivers/net/fsl-mc/mc.c
@@ -2,6 +2,7 @@
 /*
  * Copyright 2014 Freescale Semiconductor, Inc.
  * Copyright 2017 NXP
+ * Copyright 2017-2018 NXP
  */
 #include <common.h>
 #include <errno.h>
@@ -29,6 +30,7 @@
 #define MC_BOOT_ENV_VAR		"mcinitcmd"
 
 DECLARE_GLOBAL_DATA_PTR;
+static int mc_memset_resv_ram;
 static int mc_boot_status = -1;
 static int mc_dpl_applied = -1;
 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
@@ -278,6 +280,40 @@
 				 MC_FIXUP_DPL);
 }
 
+void fdt_fsl_mc_fixup_iommu_map_entry(void *blob)
+{
+	u32 *prop;
+	u32 iommu_map[4];
+	int offset;
+	int lenp;
+
+	/* find fsl-mc node */
+	offset = fdt_path_offset(blob, "/soc/fsl-mc");
+	if (offset < 0)
+		offset = fdt_path_offset(blob, "/fsl-mc");
+	if (offset < 0) {
+		printf("%s: fsl-mc: ERR: fsl-mc node not found in DT, err %d\n",
+		       __func__, offset);
+		return;
+	}
+
+	prop = fdt_getprop_w(blob, offset, "iommu-map", &lenp);
+	if (!prop) {
+		debug("%s: fsl-mc: ERR: missing iommu-map in fsl-mc bus node\n",
+		      __func__);
+		return;
+	}
+
+	iommu_map[0] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START);
+	iommu_map[1] = *++prop;
+	iommu_map[2] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_START);
+	iommu_map[3] = cpu_to_fdt32(FSL_DPAA2_STREAM_ID_END -
+		FSL_DPAA2_STREAM_ID_START + 1);
+
+	fdt_setprop_inplace(blob, offset, "iommu-map",
+			    iommu_map, sizeof(iommu_map));
+}
+
 static int mc_fixup_dpc_mac_addr(void *blob, int dpmac_id,
 				 struct eth_device *eth_dev)
 {
@@ -810,6 +846,11 @@
 {
 	size_t mc_ram_size = mc_get_dram_block_size();
 
+	if (!mc_memset_resv_ram || (get_mc_boot_status() < 0)) {
+		mc_memset_resv_ram = 1;
+		memset((void *)gd->arch.resv_ram, 0, mc_ram_size);
+	}
+
 	return (gd->arch.resv_ram + mc_ram_size - 1) &
 		MC_RAM_BASE_ADDR_ALIGNMENT_MASK;
 }
diff --git a/drivers/net/pfe_eth/pfe_mdio.c b/drivers/net/pfe_eth/pfe_mdio.c
index b53edb7..2dde9e7 100644
--- a/drivers/net/pfe_eth/pfe_mdio.c
+++ b/drivers/net/pfe_eth/pfe_mdio.c
@@ -162,7 +162,6 @@
 	if (gem->phy_mode == PHY_INTERFACE_MODE_SGMII_2500)
 		sgmii_2500 = 1;
 
-	printf("%s %d\n", __func__, priv->gemac_port);
 
 	/* PCS configuration done with corresponding GEMAC */
 	bus.priv = gem_info[priv->gemac_port].gemac_base;
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/qe/Kconfig b/drivers/qe/Kconfig
new file mode 100644
index 0000000..49a6e32
--- /dev/null
+++ b/drivers/qe/Kconfig
@@ -0,0 +1,12 @@
+#
+# QUICC Engine Drivers
+#
+config U_QE
+	bool "Enable support for U QUICC Engine"
+	default y if (ARCH_LS1021A && !SD_BOOT && !NAND_BOOT && !QSPI_BOOT) \
+		|| (TARGET_T1024QDS) \
+		|| (TARGET_T1024RDB) \
+		|| (TARGET_T1040QDS && !NOBQFMAN) \
+		|| (TARGET_LS1043ARDB && !SPL_NO_QE && !NAND_BOOT && !QSPI_BOOT)
+	help
+	  Choose this option to add support for U QUICC Engine.
diff --git a/drivers/qe/qe.c b/drivers/qe/qe.c
index 7654df8..7010bbc 100644
--- a/drivers/qe/qe.c
+++ b/drivers/qe/qe.c
@@ -218,7 +218,7 @@
 		printf("\nMMC read: dev # %u, block # %u, count %u ...\n",
 		       dev, blk, cnt);
 		mmc_init(mmc);
-		(void)mmc->block_dev.block_read(&mmc->block_dev, blk, cnt,
+		(void)blk_dread(mmc_get_blk_desc(mmc), blk, cnt,
 						addr);
 	}
 #endif
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/T102xQDS.h b/include/configs/T102xQDS.h
index 8a38c5e..191616b 100644
--- a/include/configs/T102xQDS.h
+++ b/include/configs/T102xQDS.h
@@ -659,7 +659,6 @@
 #define CONFIG_SYS_DPAA_FMAN
 
 #define CONFIG_QE
-#define CONFIG_U_QE
 /* Default address of microcode for the Linux FMan driver */
 #if defined(CONFIG_SPIFLASH)
 /*
diff --git a/include/configs/T102xRDB.h b/include/configs/T102xRDB.h
index f7a54f7..ac5de8d 100644
--- a/include/configs/T102xRDB.h
+++ b/include/configs/T102xRDB.h
@@ -669,7 +669,6 @@
 
 #ifdef CONFIG_TARGET_T1024RDB
 #define CONFIG_QE
-#define CONFIG_U_QE
 #endif
 /* Default address of microcode for the Linux FMan driver */
 #if defined(CONFIG_SPIFLASH)
diff --git a/include/configs/T1040QDS.h b/include/configs/T1040QDS.h
index e890860..25615be 100644
--- a/include/configs/T1040QDS.h
+++ b/include/configs/T1040QDS.h
@@ -549,7 +549,6 @@
 #define CONFIG_SYS_DPAA_PME
 
 #define CONFIG_QE
-#define CONFIG_U_QE
 /* Default address of microcode for the Linux Fman driver */
 #if defined(CONFIG_SPIFLASH)
 /*
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/ls1012afrwy.h b/include/configs/ls1012afrwy.h
index 8129595..e450002 100644
--- a/include/configs/ls1012afrwy.h
+++ b/include/configs/ls1012afrwy.h
@@ -9,9 +9,9 @@
 #include "ls1012a_common.h"
 
 /* Board Rev*/
-#define BOARD_REV_A			0x0
-#define BOARD_REV_B			0x200
-
+#define BOARD_REV_A_B			0x0
+#define BOARD_REV_C			0x00080000
+#define BOARD_REV_MASK			0x001A0000
 /* DDR */
 #define CONFIG_DIMM_SLOTS_PER_CTLR	1
 #define CONFIG_CHIP_SELECTS_PER_CTRL	1
diff --git a/include/configs/ls1021aqds.h b/include/configs/ls1021aqds.h
index 994e6ca..7f7ffde 100644
--- a/include/configs/ls1021aqds.h
+++ b/include/configs/ls1021aqds.h
@@ -107,7 +107,6 @@
 
 #if !defined(CONFIG_SD_BOOT) && !defined(CONFIG_NAND_BOOT) && \
 	!defined(CONFIG_QSPI_BOOT)
-#define CONFIG_U_QE
 #define CONFIG_SYS_QE_FMAN_FW_IN_NOR
 #endif
 
diff --git a/include/configs/ls1021atwr.h b/include/configs/ls1021atwr.h
index 75b2e2f..ddd024e 100644
--- a/include/configs/ls1021atwr.h
+++ b/include/configs/ls1021atwr.h
@@ -106,7 +106,6 @@
 
 #if !defined(CONFIG_SD_BOOT) && !defined(CONFIG_NAND_BOOT) && \
 	!defined(CONFIG_QSPI_BOOT)
-#define CONFIG_U_QE
 #define CONFIG_SYS_QE_FMAN_FW_IN_NOR
 #endif
 
diff --git a/include/configs/ls1043ardb.h b/include/configs/ls1043ardb.h
index bc639e5..ffd92db 100644
--- a/include/configs/ls1043ardb.h
+++ b/include/configs/ls1043ardb.h
@@ -268,13 +268,6 @@
 #endif
 #endif
 
-/* QE */
-#ifndef SPL_NO_QE
-#if !defined(CONFIG_NAND_BOOT) && !defined(CONFIG_QSPI_BOOT)
-#define CONFIG_U_QE
-#endif
-#endif
-
 /* SATA */
 #ifndef SPL_NO_SATA
 #ifndef CONFIG_CMD_EXT2
diff --git a/include/configs/ls1088ardb.h b/include/configs/ls1088ardb.h
index eb220bf..363154a 100644
--- a/include/configs/ls1088ardb.h
+++ b/include/configs/ls1088ardb.h
@@ -455,8 +455,7 @@
 
 #define BOOT_TARGET_DEVICES(func) \
 	func(MMC, mmc, 0) \
-	func(SCSI, scsi, 0) \
-	func(DHCP, dhcp, na)
+	func(SCSI, scsi, 0)
 #include <config_distro_bootcmd.h>
 #endif
 
diff --git a/include/configs/ls2080ardb.h b/include/configs/ls2080ardb.h
index 3d53a69..05c02df 100644
--- a/include/configs/ls2080ardb.h
+++ b/include/configs/ls2080ardb.h
@@ -323,8 +323,7 @@
 #define BOOT_TARGET_DEVICES(func) \
 	func(USB, usb, 0) \
 	func(MMC, mmc, 0) \
-	func(SCSI, scsi, 0) \
-	func(DHCP, dhcp, na)
+	func(SCSI, scsi, 0)
 #include <config_distro_bootcmd.h>
 
 #ifdef CONFIG_QSPI_BOOT
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/fsl-mc/fsl_mc.h b/include/fsl-mc/fsl_mc.h
index 7f4859b..aef40d3 100644
--- a/include/fsl-mc/fsl_mc.h
+++ b/include/fsl-mc/fsl_mc.h
@@ -51,6 +51,7 @@
 	u32 reg_error[];
 };
 
+void fdt_fsl_mc_fixup_iommu_map_entry(void *blob);
 int get_mc_boot_status(void);
 int get_dpl_apply_status(void);
 #ifdef CONFIG_SYS_LS_MC_DRAM_AIOP_IMG_OFFSET
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 94953d8..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
@@ -4635,7 +4630,6 @@
 CONFIG_UTBIPAR_INIT_TBIPA
 CONFIG_U_BOOT_HDR_ADDR
 CONFIG_U_BOOT_HDR_SIZE
-CONFIG_U_QE
 CONFIG_VAL
 CONFIG_VAR_SIZE_SPL
 CONFIG_VCT_NOR
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);
+}