Merge tag 'efi-next' of https://source.denx.de/u-boot/custodians/u-boot-efi into next

Pull request of efi-next

Documentation:

* Add Sunxi board description

UEFI:

* Improvements to U-Boot running on top of UEFI
diff --git a/arch/x86/cpu/efi/payload.c b/arch/x86/cpu/efi/payload.c
index 3a9f7d7..04ce188 100644
--- a/arch/x86/cpu/efi/payload.c
+++ b/arch/x86/cpu/efi/payload.c
@@ -7,6 +7,7 @@
 #include <common.h>
 #include <cpu_func.h>
 #include <efi.h>
+#include <efi_api.h>
 #include <errno.h>
 #include <init.h>
 #include <log.h>
@@ -296,8 +297,14 @@
 void efi_show_bdinfo(void)
 {
 	struct efi_entry_systable *table = NULL;
+	struct efi_system_table *sys_table;
 	int size, ret;
 
 	ret = efi_info_get(EFIET_SYS_TABLE, (void **)&table, &size);
-	bdinfo_print_num_l("efi_table", (ulong)table);
+	if (!ret) {
+		bdinfo_print_num_l("efi_table", table->sys_table);
+		sys_table = (struct efi_system_table *)(uintptr_t)
+			table->sys_table;
+		bdinfo_print_num_l(" revision", sys_table->fw_revision);
+	}
 }
diff --git a/arch/x86/dts/Makefile b/arch/x86/dts/Makefile
index be209aa..5c8c05e 100644
--- a/arch/x86/dts/Makefile
+++ b/arch/x86/dts/Makefile
@@ -24,7 +24,7 @@
 
 targets += $(dtb-y)
 
-DTC_FLAGS += -R 4 -p 0x1000
+DTC_FLAGS += -R 4 -p $(if $(CONFIG_EFI_APP),0x8000,0x1000)
 
 PHONY += dtbs
 dtbs: $(addprefix $(obj)/, $(dtb-y))
diff --git a/arch/x86/lib/bootm.c b/arch/x86/lib/bootm.c
index 667e5e6..57cba5c 100644
--- a/arch/x86/lib/bootm.c
+++ b/arch/x86/lib/bootm.c
@@ -179,10 +179,14 @@
 		* U-Boot is setting them up that way for itself in
 		* arch/i386/cpu/cpu.c.
 		*
-		* Note that we cannot currently boot a kernel while running as
-		* an EFI application. Please use the payload option for that.
+		* Note: this is incomplete for EFI kernels!
+		*
+		* This can boot a kernel while running as an EFI application,
+		* but if the kernel requires EFI support then that support needs
+		* to be enabled first (see EFI_LOADER). Also the EFI information
+		* must enabled with setup_efi_info(). See setup_zimage() for
+		* how this is done with the stub.
 		*/
-#ifndef CONFIG_EFI_APP
 		__asm__ __volatile__ (
 		"movl $0, %%ebp\n"
 		"cli\n"
@@ -191,7 +195,6 @@
 		[boot_params] "S"(setup_base),
 		"b"(0), "D"(0)
 		);
-#endif
 	}
 
 	/* We can't get to here */
diff --git a/arch/x86/lib/zimage.c b/arch/x86/lib/zimage.c
index 7ce0222..9cc0449 100644
--- a/arch/x86/lib/zimage.c
+++ b/arch/x86/lib/zimage.c
@@ -365,11 +365,14 @@
 			strcpy(cmd_line, (char *)cmdline_force);
 		else
 			build_command_line(cmd_line, auto_boot);
-		ret = bootm_process_cmdline(cmd_line, max_size, BOOTM_CL_ALL);
-		if (ret) {
-			printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n",
-			       max_size, bootproto, ret);
-			return ret;
+		if (IS_ENABLED(CONFIG_CMD_BOOTM)) {
+			ret = bootm_process_cmdline(cmd_line, max_size,
+						    BOOTM_CL_ALL);
+			if (ret) {
+				printf("Cmdline setup failed (max_size=%x, bootproto=%x, err=%d)\n",
+				       max_size, bootproto, ret);
+				return ret;
+			}
 		}
 		printf("Kernel command line: \"");
 		puts(cmd_line);
diff --git a/common/board_r.c b/common/board_r.c
index 6d52066..760c2d0 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -841,9 +841,8 @@
 	 * TODO(sjg@chromium.org): Consider doing this for all archs, or
 	 * dropping the new_gd parameter.
 	 */
-#if CONFIG_IS_ENABLED(X86_64)
-	arch_setup_gd(new_gd);
-#endif
+	if (CONFIG_IS_ENABLED(X86_64) && !IS_ENABLED(CONFIG_EFI_APP))
+		arch_setup_gd(new_gd);
 
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
 	int i;
diff --git a/doc/board/allwinner/index.rst b/doc/board/allwinner/index.rst
new file mode 100644
index 0000000..7352ccd
--- /dev/null
+++ b/doc/board/allwinner/index.rst
@@ -0,0 +1,9 @@
+.. SPDX-License-Identifier: GPL-2.0+
+
+Allwinner (sunxi) boards
+========================
+
+.. toctree::
+   :maxdepth: 2
+
+   sunxi
diff --git a/doc/board/allwinner/sunxi.rst b/doc/board/allwinner/sunxi.rst
new file mode 100644
index 0000000..797222d
--- /dev/null
+++ b/doc/board/allwinner/sunxi.rst
@@ -0,0 +1,319 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright (C) 2021 Arm Ltd.
+
+Allwinner SoC based boards
+==========================
+For boards using an Allwinner ARM based SoC ("sunxi"), the U-Boot build
+system generates a single integrated image file: ``u-boot-sunxi-with-spl.bin.``
+This file can be used on SD cards, eMMC devices, SPI flash and for the
+USB-OTG based boot method (FEL). To build this file:
+
+* For 64-bit SoCs, build Trusted Firmware (TF-A, formerly known as ATF) first,
+  you will need its ``bl31.bin``. See below for more details.
+* Optionally on 64-bit SoCs, build the `crust`_ management processor firmware,
+  you will need its ``scp.bin``. See below for more details.
+* Build U-Boot::
+
+  $ export BL31=/path/to/bl31.bin		# required for 64-bit SoCs
+  $ export SCP=/path/to/scp.bin			# optional for some 64-bit SoCs
+  $ make <yourboardname>_defconfig
+  $ make
+* Transfer to an (micro)SD card (see below for more details)::
+
+  $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=8k seek=1
+* Boot and enjoy!
+
+.. note::
+  The traditional SD card location the Allwinner BootROM loads from is 8KB
+  (sector 16). This works fine with the old MBR partitioning scheme, which most
+  SD cards come formatted with. However this is in the middle of a potential
+  GPT partition table, which will become invalid in this step. Newer SoCs
+  (starting with the H3 from late 2014) also support booting from 128KB, which
+  is beyond even a GPT and thus a safer location.
+
+For more details, and alternative boot locations or installations, see below.
+
+Building Arm Trusted Firmware (TF-A)
+------------------------------------
+Boards using a 64-bit Soc (A64, H5, H6, H616, R329) require the BL31 stage of
+the `Arm Trusted Firmware-A`_ firmware. This provides the reference
+implementation of secure software for Armv8-A, offering PSCI and SMCCC
+services. Allwinner support is fully mainlined. To build bl31.bin::
+
+  $ git clone https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git
+  $ cd trusted-firmware-a
+  $ make CROSS_COMPILE=aarch64-linux-gnu- PLAT=sun50i_a64 DEBUG=1
+  $ export BL31=$(pwd)/build/sun50i_a64/debug/bl31.bin
+
+The target platform (``PLAT=``) for A64 and H5 SoCs is sun50i_a64, for the H6
+sun50i_h6, for the H616 sun50i_h616, and for the R329 sun50i_r329. Use::
+
+  $ find plat/allwinner -name platform.mk
+
+to find all supported platforms. TF-A's `docs/plat/allwinner.rst`_ contains
+more information and lists some build options.
+
+Building the Crust management processor firmware
+------------------------------------------------
+For some SoCs and boards, the integrated OpenRISC management controller can
+be used to provide power management services, foremost suspend to RAM.
+There is a community supported Open Source implementation called `crust`_,
+which runs on most SoCs featuring a management controller.
+
+This firmware part is optional, setting the SCP environment variable to
+/dev/null avoids the warning message when building without one.
+
+To build crust's scp.bin, you need an OpenRISC (or1k) cross compiler, then::
+
+  $ git clone https://github.com/crust-firmware/crust.git
+  $ cd crust
+  $ make <yourboard>_defconfig
+  $ make CROSS_COMPILE=or1k-none-elf- scp
+  $ export SCP=$(pwd)/build/scp/scp.bin
+
+Find a list of supported board configurations in the `configs/`_ directory.
+The `crust README`_ has more information about the building process, including
+information about where to get OpenRISC cross compilers.
+
+Building the U-Boot image
+-------------------------
+Find the U-Boot defconfig file for your board first. Those files live in
+the ``configs/`` directory; you can grep for the stub name of the devicetree
+file, if you know that, or for the SoC name to find the right version::
+
+    $ git grep -l MACH_SUN8I_H3 configs
+    $ git grep -l sun50i-h6-orangepi-3 configs
+
+The `linux-sunxi`_ wiki also lists the name of the defconfig file in the
+respective board page. Then use this defconfig file to create the .config
+file, and build the image::
+
+    $ make <yourboard>_defconfig
+    $ make
+
+For 64-bit boards, this requires either the BL31 environment variable to be
+set (as shown above in the TF-A build example), or it to be supplied on the
+build command line::
+
+    $ make BL31=/src/tf-a.git/build/sun50i_h616/debug/bl31.bin
+
+The same applies to the (optional) SCP firmware.
+
+The file containing everything you need is called ``u-boot-sunxi-with-spl.bin``,
+you will find it in the root folder of your U-Boot (build) tree. Except for
+raw NAND flash devices this very same file can be used for any boot source.
+It will contain the SPL image, fitted with the proper signature recognised by
+the BROM, and the required checksum. Also it will contain at least U-Boot
+proper, either wrapped in the legacy U-Boot image format, or in a FIT image.
+The board's devicetree is also included, either appended to the U-Boot proper
+image, or contained in the FIT image. If required by the SoC, this FIT file will
+also include the other firmware images.
+
+Installing U-Boot
+-----------------
+
+Installing on a (micro-) SD card
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+All Allwinner SoCs will try to find a boot image at sector 16 (8KB) of
+an SD card, connected to the first MMC controller. To transfer the generated
+image to an SD card, from any Linux device (including the board itself) with
+an (micro-)SD card reader, type::
+
+    $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/sdX bs=1k seek=8
+
+``/dev/sdx`` needs to be replaced with the block device name of the SD card
+reader. On some machines this could be ``/dev/mmcblkX``.
+Newer SoCs (starting from the H3 from 2014, and including all ARM64 SoCs),
+also look at sector 256 (128KB) for the signature (after having checked the
+8KB location). Installing the firmware there has the advantage of not
+overlapping with a GPT partition table. Simply replace the "``seek=8``" above
+with "``seek=128``".
+
+You can also use an existing (mainline) U-Boot to write to the SD card. Load
+the generated U-Boot image somewhere into DRAM (via ``ext4load``, ``fatload``,
+or ``tftpboot``), then write to MMC device 0::
+
+    => fatload mmc 0:1 $kernel_addr_r u-boot-sunxi-with-spl.bin
+    => mmc dev 0
+    => mmc write $kernel_addr_r 0x10 0x7f0
+
+To use the alternative boot location on newer SoCs::
+
+    => mmc write $kernel_addr_r 0x100 0x700
+
+Installing on eMMC (on-board flash memory)
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+Some boards have a soldered eMMC chip, some other boards have an eMMC socket
+to receive an optional eMMC module. U-Boot can be installed to those chips,
+to boot without an SD card inserted. The Boot-ROM can boot either from the
+regular user data partition, or from one of the separate eMMC boot partitions.
+U-Boot can be installed either from a running Linux instance on the device,
+from a running (mainline) U-Boot, or via an adapter for the (removable)
+eMMC module.
+
+Installing on an eMMC user data partition from Linux
+````````````````````````````````````````````````````
+If you have a running Linux instance on the device, and have somehow copied
+over the image file to that device, you can write the image directly into the
+eMMC device from there.
+Find the name of the block device file first, it is one of the
+``/dev/mmcblk<X>`` devices. eMMC devices typically also list a
+``/dev/mmcblk<X>boot0`` partition (see below), this helps you to tell it apart
+from the SD card device.
+To install onto the user data partition::
+
+    $ sudo dd if=u-boot-sunxi-with-spl.bin of=/dev/dev/mmcblkX bs=1k seek=8
+
+Similar to SD cards, the BROM in newer SoCs (H3 and above) also checks
+sector 256 of an eMMC, so you can use "``seek=128``" as well. Having a GPT
+on an eMMC device is much more likely than on an SD card, so you should
+probably stick to the alternative location, or use one of the boot partitions.
+
+Installing on an eMMC boot partition from Linux
+```````````````````````````````````````````````
+In the following examples, ``/dev/mmcblkX`` needs to be replaced with the block
+device name of the eMMC device. The eMMC device can be recognised by also
+listing the boot partitions (``/dev/mmcblkXboot0``) in ``/proc/partitions``.
+
+To allow booting from one of the eMMC boot partitions, this one needs to be
+enabled first. This only needs to be done once, as this setting is
+persistent, even though the boot partition can be disabled or changed again
+any time later::
+
+    # apt-get install mmc-utils
+    # mmc bootbus set single_hs x1 x4 /dev/mmcblkX
+    # mmc bootpart enable 1 1 /dev/mmcblkX
+
+The first "1" in the last command points to the boot partition number to be
+used, typically devices offer two boot partitions.
+
+By default Linux disables write access to the boot partitions, to prevent
+accidental overwrites. You need to disable the write protection (until the
+next reboot), then can write the U-Boot image to the *first* sector of the
+selected boot partition::
+
+    # echo 0 > /sys/block/mmcblkXboot0/force_ro
+    # dd if=u-boot-sunxi-with-spl.bin of=/dev/mmcblkXboot0 bs=1k
+
+Installing on an eMMC user data partition from U-Boot
+`````````````````````````````````````````````````````
+You can also write the generated image file to an SD card, boot the device
+from there, and burn the very same image to the eMMC device from U-Boot.
+The following commands copy the image from the SD card to the eMMC device::
+
+    => mmc dev 0
+    => mmc read $kernel_addr_r 0x10 0x7f0
+    => mmc dev 1
+    => mmc write $kernel_addr_r 0x10 0x7f0
+
+You can also copy an image from the 8K offset of an SD card to the 128K
+offset of the eMMC (or any combination), just change the "``0x10 0x7f0``" above
+to "``0x100 0x700``", respectively. Of course the image file can be loaded via
+any other loading method, including ``fatload``, ``ext4load``, ``tftpboot``.
+
+Installing on an eMMC boot partition from U-Boot
+````````````````````````````````````````````````
+The selected eMMC boot partition needs to be initially enabled first (same
+as in Linux above), you can do this from U-Boot with::
+
+    => mmc dev 1
+    => mmc bootbus 1 1 0 0
+    => mmc partconf 1 1 1 1
+
+The first "1" in both commands denotes the MMC device number. The second "1"
+in the partconf command sets the required ``BOOT_ACK`` option, the last two "1"s
+selects the active boot partition and the target for the next data access,
+respectively. So for the next "``mmc write``" command to address one of the boot
+partitions, the last number must either be "1" or "2", "0" would switch (back)
+to the normal user data partition.
+
+Then load the ``u-boot-sunxi-with-spl.bin`` image file into DRAM, either by
+reading directly from an SD card or eMMC user data partition, or from a
+file system or TFTP (see above), and transfer it to the boot partition::
+
+    => tftpboot $kernel_addr_r u-boot-sunxi-with-spl.bin
+    => mmc write $kernel_addr_r 0 0x7f0
+
+After that the device should boot from the selected boot partition, which takes
+precedence over booting from the user data partition.
+
+Installing on SPI flash
+^^^^^^^^^^^^^^^^^^^^^^^
+Some devices have a SPI NOR flash chip soldered on the board. If it is
+connected to the SPI0 pins on PortC, the BROM can also boot from there.
+Typically the SPI flash has the lowest boot priority, so SD card and eMMC
+devices will be considered first.
+
+Installing on SPI flash from Linux
+``````````````````````````````````
+If the devicetree enables and describes the SPI flash device, you can access
+the SPI flash content from Linux, using the `MTD utils`_::
+
+    # apt-get install mtd-utils
+    # mtdinfo
+    # mtd_debug erase /dev/mtdX 0 0xf0000
+    # mtd_debug write /dev/mtdX 0 0xf0000 u-boot-sunxi-with-spl.bin
+
+``/dev/mtdX`` needs to be replaced with the respective device name, as listed
+in the output of ``mtdinfo``.
+
+Installing on SPI flash from U-Boot
+```````````````````````````````````
+If SPI flash driver and command support (``CONFIG_CMD_SF``) is enabled in the
+U-Boot configuration, the image file can be installed via U-Boot as well::
+
+    => tftpboot $kernel_addr_r u-boot-sunxi-with-spl.bin
+    => sf probe
+    => sf erase 0 +0xf0000
+    => sf write $kernel_addr_r 0 $filesize
+
+Installing on SPI flash via USB in FEL mode
+```````````````````````````````````````````
+If the device is in FEL mode (see below), the SPI flash can also be written to
+with the sunxi-fel utility, via an USB(-OTG) cable from any USB host machine::
+
+    $ sunxi-fel spiflash-write 0 u-boot-sunxi-with-spl.bin
+
+Booting via the USB(-OTG) FEL mode
+----------------------------------
+If none of the boot locations checked by the BROM contains a medium or valid
+signature, the BROM will enter the so-called FEL mode, in which it will
+listen to commands from a host on the SoC's USB-OTG interface. Those commands
+allow to read from and write to arbitrary memory locations, also to start
+execution at any address, which allows to bootstrap a board solely via an
+USB cable. Some boards feature a "FEL" or "U-Boot" button, which forces
+FEL mode despite a valid boot location being present. The same can be achieved
+via a `magic binary`_ on an SD card, which allows to enter FEL mode on any
+board.
+
+To use FEL booting, let the board enter FEL mode, via any of the mentioned
+methods (no boot media, FEL button, SD card with FEL binary), then connect
+a USB cable to the board's USB OTG port. Some boards (Pine64, TV boxes) don't
+have a separate OTG port. In this case mostly one of the USB-A ports is
+connected to USB0, and can be used via a non-standard USB-A to USB-A cable.
+
+Typically there is no on-board indication of FEL mode, other than a new USB
+device appearing on the connected host computer. The USB vendor/device ID
+is 1f3a:efe8. Mostly this will identify as "sunxi SoC OTG connector in
+FEL/flashing mode", but older distributions might still report "Onda
+(unverified) V972 tablet in flashing mode".
+
+The `sunxi_fel`_ tool implements the proprietary BROM protocol, and allows to
+bootstrap U-Boot by just providing our venerable u-boot-sunxi-with-spl.bin::
+
+    $ sudo apt-get install sunxi-tools
+    $ sunxi-fel uboot u-boot-sunxi-with-spl.bin
+
+Additional binaries like a kernel, an initial ramdisk or a boot script, can
+also be uploaded via FEL, check the Wiki's `FEL page`_ for more details.
+
+.. _`Arm Trusted Firmware-A`:  https://www.trustedfirmware.org/projects/tf-a/
+.. _`docs/plat/allwinner.rst`: https://trustedfirmware-a.readthedocs.io/en/latest/plat/allwinner.html
+.. _`crust`: https://github.com/crust-firmware/crust
+.. _`configs/`: https://github.com/crust-firmware/crust/tree/master/configs
+.. _`crust README`: https://github.com/crust-firmware/crust/blob/master/README.md#building-the-firmware
+.. _`linux-sunxi`: https://linux-sunxi.org
+.. _`MTD utils`: http://www.linux-mtd.infradead.org/
+.. _`magic binary`: https://github.com/linux-sunxi/sunxi-tools/raw/master/bin/fel-sdboot.sunxi
+.. _`sunxi_fel`: https://github.com/linux-sunxi/sunxi-tools
+.. _`FEL page`: https://linux-sunxi.org/FEL/USBBoot
diff --git a/doc/board/index.rst b/doc/board/index.rst
index 13f4db8..0a02fec 100644
--- a/doc/board/index.rst
+++ b/doc/board/index.rst
@@ -9,6 +9,7 @@
    actions/index
    advantech/index
    AndesTech/index
+   allwinner/index
    amlogic/index
    apple/index
    atmel/index
diff --git a/doc/develop/uefi/u-boot_on_efi.rst b/doc/develop/uefi/u-boot_on_efi.rst
index 5f2f850..acad639 100644
--- a/doc/develop/uefi/u-boot_on_efi.rst
+++ b/doc/develop/uefi/u-boot_on_efi.rst
@@ -265,13 +265,11 @@
 
 - Figure out how to solve the interrupt problem
 
-- Add more drivers to the application side (e.g. block devices, USB,
-  environment access). This would mostly be an academic exercise as a strong
-  use case is not readily apparent, but it might be fun.
+- Add more drivers to the application side (e.g.USB, environment access).
 
 - Avoid turning off boot services in the stub. Instead allow U-Boot to make
   use of boot services in case it wants to. It is unclear what it might want
-  though.
+  though. It is better to use the app.
 
 Where is the code?
 ------------------
diff --git a/drivers/serial/serial_efi.c b/drivers/serial/serial_efi.c
index 33ddbd6..0067576 100644
--- a/drivers/serial/serial_efi.c
+++ b/drivers/serial/serial_efi.c
@@ -24,6 +24,9 @@
 	bool have_key;
 };
 
+/* Convert a lower-case character to its ctrl-char equivalent */
+#define CTL_CH(c)		((c) - 'a' + 1)
+
 int serial_efi_setbrg(struct udevice *dev, int baudrate)
 {
 	return 0;
@@ -49,6 +52,7 @@
 static int serial_efi_getc(struct udevice *dev)
 {
 	struct serial_efi_priv *priv = dev_get_priv(dev);
+	char conv_scan[10] = {0, 'p', 'n', 'f', 'b', 'a', 'e', 0, 8};
 	int ret, ch;
 
 	ret = serial_efi_get_key(priv);
@@ -63,8 +67,11 @@
 	 * key scan code of 8. Handle this so that backspace works correctly
 	 * in the U-Boot command line.
 	 */
-	if (!ch && priv->key.scan_code == 8)
-		ch = 8;
+	if (!ch && priv->key.scan_code < sizeof(conv_scan)) {
+		ch = conv_scan[priv->key.scan_code];
+		if (ch >= 'a')
+			ch -= 'a' - 1;
+	}
 	debug(" [%x %x %x] ", ch, priv->key.unicode_char, priv->key.scan_code);
 
 	return ch;
diff --git a/include/configs/efi-x86_app.h b/include/configs/efi-x86_app.h
index 6061a6d..33afb7c 100644
--- a/include/configs/efi-x86_app.h
+++ b/include/configs/efi-x86_app.h
@@ -10,8 +10,33 @@
 
 #undef CONFIG_TPM_TIS_BASE_ADDRESS
 
+/*
+ * Select the output device: Put an 'x' prefix before one of these to disable it
+ */
+
+/*
+ * Video output - can normally continue after exit_boot_services has been
+ * called, since output to the display does not require EFI services at that
+ * point. U-Boot sets up the console memory and does its own drawing.
+ */
 #define CONFIG_STD_DEVICES_SETTINGS	"stdin=serial\0" \
 					"stdout=vidconsole\0" \
 					"stderr=vidconsole\0"
 
+/*
+ * Serial output with no console. Run qemu with:
+ *
+ *    -display none -serial mon:stdio
+ *
+ * This will hang or fail to output on the console after exit_boot_services is
+ * called.
+ */
+#define xCONFIG_STD_DEVICES_SETTINGS	"stdin=serial\0" \
+					"stdout=serial\0" \
+					"stderr=serial\0"
+
+#undef CONFIG_BOOTCOMMAND
+
+#define CONFIG_BOOTCOMMAND "part list efi 0; fatls efi 0:1"
+
 #endif
diff --git a/include/efi.h b/include/efi.h
index 0ec5913..877a2e5 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -321,7 +321,7 @@
  * struct efi_entry_hdr - Header for a table entry
  *
  * @type:	enum eft_entry_t
- * @size	size of entry bytes excluding header and padding
+ * @size:	size of entry bytes excluding header and padding
  * @addr:	address of this entry (0 if it follows the header )
  * @link:	size of entry including header and padding
  * @spare1:	Spare space for expansion
@@ -400,15 +400,37 @@
 	return (struct efi_mem_desc *)((ulong)desc + map->desc_size);
 }
 
+/**
+ * struct efi_priv - Information about the environment provided by EFI
+ *
+ * @parent_image: image passed into the EFI app or stub
+ * @sys_table: Pointer to system table
+ * @boot: Pointer to boot-services table
+ * @run: Pointer to runtime-services table
+ *
+ * @use_pool_for_malloc: true if all allocation should go through the EFI 'pool'
+ *	methods allocate_pool() and free_pool(); false to use 'pages' methods
+ *	allocate_pages() and free_pages()
+ * @ram_base: Base address of RAM (size CONFIG_EFI_RAM_SIZE)
+ * @image_data_type: Type of the loaded image (e.g. EFI_LOADER_CODE)
+ *
+ * @info: Header of the info list, holding info collected by the stub and passed
+ *	to U-Boot
+ * @info_size: Size of the info list @info in bytes
+ * @next_hdr: Pointer to where to put the next header when adding to the list
+ */
 struct efi_priv {
 	efi_handle_t parent_image;
-	struct efi_device_path *device_path;
 	struct efi_system_table *sys_table;
 	struct efi_boot_services *boot;
 	struct efi_runtime_services *run;
+
+	/* app: */
 	bool use_pool_for_malloc;
 	unsigned long ram_base;
 	unsigned int image_data_type;
+
+	/* stub: */
 	struct efi_info_hdr *info;
 	unsigned int info_size;
 	void *next_hdr;
@@ -419,10 +441,12 @@
  *
  * @handle: handle of the controller on which this driver is installed
  * @blkio: block io protocol proxied by this driver
+ * @device_path: EFI path to the device
  */
 struct efi_media_plat {
-	efi_handle_t		handle;
-	struct efi_block_io	*blkio;
+	efi_handle_t handle;
+	struct efi_block_io *blkio;
+	struct efi_device_path *device_path;
 };
 
 /* Base address of the EFI image */
@@ -451,6 +475,27 @@
 				EFI_VARIABLE_APPEND_WRITE)
 
 /**
+ * efi_get_priv() - Get access to the EFI-private information
+ *
+ * This struct it used by both the stub and the app to record things about the
+ * EFI environment. It is not available in U-Boot proper after the stub has
+ * jumped there. Use efi_info_get() to obtain info in that case.
+ *
+ * Return: pointer to private info
+ */
+struct efi_priv *efi_get_priv(void);
+
+/**
+ * efi_set_priv() - Set up a pointer to the EFI-private information
+ *
+ * This is called in the stub and app to record the location of this
+ * information.
+ *
+ * @priv: New location of private data
+ */
+void efi_set_priv(struct efi_priv *priv);
+
+/**
  * efi_get_sys_table() - Get access to the main EFI system table
  *
  * @return pointer to EFI system table
@@ -521,6 +566,10 @@
 /**
  * efi_info_get() - get an entry from an EFI table
  *
+ * This function is called from U-Boot proper to read information set up by the
+ * EFI stub. It can only be used when running from the EFI stub, not when U-Boot
+ * is running as an app.
+ *
  * @type:	Entry type to search for
  * @datap:	Returns pointer to entry data
  * @sizep:	Returns pointer to entry size
diff --git a/include/efi_api.h b/include/efi_api.h
index 80109f0..ec9fa89 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -2035,4 +2035,19 @@
 			const u16 *package_version_name);
 };
 
+#define EFI_DISK_IO_PROTOCOL_GUID	\
+	EFI_GUID(0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, \
+		 0x00, 0xa0, 0xc9, 0x69, 0x72, 0x3b)
+
+struct efi_disk {
+	u64 revision;
+	efi_status_t (EFIAPI *read_disk)(struct efi_disk *this, u32 media_id,
+					 u64 offset, efi_uintn_t buffer_size,
+					 void *buffer);
+
+	efi_status_t (EFIAPI *write_disk)(struct efi_disk *this, u32 media_id,
+					  u64 offset, efi_uintn_t buffer_size,
+					  void *buffer);
+};
+
 #endif
diff --git a/include/init.h b/include/init.h
index f2cd46d..dcd682c 100644
--- a/include/init.h
+++ b/include/init.h
@@ -14,8 +14,11 @@
 
 #include <linux/types.h>
 
-/* Avoid using CONFIG_EFI_STUB directly as we may boot from other loaders */
-#ifdef CONFIG_EFI_STUB
+/*
+ * In case of the EFI app the UEFI firmware provides the low-level
+ * initialisation.
+ */
+#ifdef CONFIG_EFI
 #define ll_boot_init()	false
 #else
 #include <asm/global_data.h>
diff --git a/include/tee.h b/include/tee.h
index 5005149..13f6096 100644
--- a/include/tee.h
+++ b/include/tee.h
@@ -58,6 +58,7 @@
 #define TEE_SUCCESS			0x00000000
 #define TEE_ERROR_STORAGE_NOT_AVAILABLE	0xf0100003
 #define TEE_ERROR_GENERIC		0xffff0000
+#define TEE_ERROR_EXCESS_DATA		0xffff0004
 #define TEE_ERROR_BAD_PARAMETERS	0xffff0006
 #define TEE_ERROR_ITEM_NOT_FOUND	0xffff0008
 #define TEE_ERROR_NOT_IMPLEMENTED	0xffff0009
diff --git a/lib/Kconfig b/lib/Kconfig
index 10ba086..1883ac7 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -52,7 +52,7 @@
 
 config CHARSET
 	bool
-	default y if UT_UNICODE || EFI_LOADER || UFS
+	default y if UT_UNICODE || EFI_LOADER || UFS || EFI_APP
 	help
 	  Enables support for various conversions between different
 	  character sets, such as between unicode representations and
diff --git a/lib/efi/efi.c b/lib/efi/efi.c
index 69e52e4..cd6bf47 100644
--- a/lib/efi/efi.c
+++ b/lib/efi/efi.c
@@ -1,5 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0+
 /*
+ * Functions shared by the app and stub
+ *
  * Copyright (c) 2015 Google, Inc
  *
  * EFI information obtained here:
@@ -17,6 +19,33 @@
 #include <efi.h>
 #include <efi_api.h>
 
+static struct efi_priv *global_priv;
+
+struct efi_priv *efi_get_priv(void)
+{
+	return global_priv;
+}
+
+void efi_set_priv(struct efi_priv *priv)
+{
+	global_priv = priv;
+}
+
+struct efi_system_table *efi_get_sys_table(void)
+{
+	return global_priv->sys_table;
+}
+
+struct efi_boot_services *efi_get_boot(void)
+{
+	return global_priv->boot;
+}
+
+unsigned long efi_get_ram_base(void)
+{
+	return global_priv->ram_base;
+}
+
 /*
  * Global declaration of gd.
  *
diff --git a/lib/efi/efi_app.c b/lib/efi/efi_app.c
index f616656..d60f2f6 100644
--- a/lib/efi/efi_app.c
+++ b/lib/efi/efi_app.c
@@ -21,29 +21,58 @@
 #include <efi.h>
 #include <efi_api.h>
 #include <sysreset.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/root.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
-static struct efi_priv *global_priv;
-
-struct efi_system_table *efi_get_sys_table(void)
+int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
 {
-	return global_priv->sys_table;
+	return -ENOSYS;
 }
 
-struct efi_boot_services *efi_get_boot(void)
+/**
+ * efi_bind_block() - bind a new block device to an EFI device
+ *
+ * Binds a new top-level EFI_MEDIA device as well as a child block device so
+ * that the block device can be accessed in U-Boot.
+ *
+ * The device can then be accessed using 'part list efi 0', 'fat ls efi 0:1',
+ * for example, just like any other interface type.
+ *
+ * @handle: handle of the controller on which this driver is installed
+ * @blkio: block io protocol proxied by this driver
+ * @device_path: EFI device path structure for this
+ * @len: Length of @device_path in bytes
+ * @devp: Returns the bound device
+ * @return 0 if OK, -ve on error
+ */
+int efi_bind_block(efi_handle_t handle, struct efi_block_io *blkio,
+		   struct efi_device_path *device_path, int len,
+		   struct udevice **devp)
 {
-	return global_priv->boot;
-}
+	struct efi_media_plat plat;
+	struct udevice *dev;
+	char name[18];
+	int ret;
 
-unsigned long efi_get_ram_base(void)
-{
-	return global_priv->ram_base;
-}
+	plat.handle = handle;
+	plat.blkio = blkio;
+	plat.device_path = malloc(device_path->length);
+	if (!plat.device_path)
+		return log_msg_ret("path", -ENOMEM);
+	memcpy(plat.device_path, device_path, device_path->length);
+	ret = device_bind(dm_root(), DM_DRIVER_GET(efi_media), "efi_media",
+			  &plat, ofnode_null(), &dev);
+	if (ret)
+		return log_msg_ret("bind", ret);
 
-int efi_info_get(enum efi_entry_t type, void **datap, int *sizep)
-{
-	return -ENOSYS;
+	snprintf(name, sizeof(name), "efi_media_%x", dev_seq(dev));
+	device_set_name(dev, name);
+	*devp = dev;
+
+	return 0;
 }
 
 static efi_status_t setup_memory(struct efi_priv *priv)
@@ -77,13 +106,14 @@
 	ret = boot->allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
 				   priv->image_data_type, pages, &addr);
 	if (ret) {
-		printf("(using pool %lx) ", ret);
+		log_info("(using pool %lx) ", ret);
 		priv->ram_base = (ulong)efi_malloc(priv, CONFIG_EFI_RAM_SIZE,
 						   &ret);
 		if (!priv->ram_base)
 			return ret;
 		priv->use_pool_for_malloc = true;
 	} else {
+		log_info("(using allocated RAM address %lx) ", (ulong)addr);
 		priv->ram_base = addr;
 	}
 	gd->ram_size = pages << 12;
@@ -91,6 +121,14 @@
 	return 0;
 }
 
+/**
+ * free_memory() - Free memory used by the U-Boot app
+ *
+ * This frees memory allocated in setup_memory(), in preparation for returning
+ * to UEFI. It also zeroes the global_data pointer.
+ *
+ * @priv: Private EFI data
+ */
 static void free_memory(struct efi_priv *priv)
 {
 	struct efi_boot_services *boot = priv->boot;
@@ -106,6 +144,150 @@
 }
 
 /**
+ * devpath_is_partition() - Figure out if a device path is a partition
+ *
+ * Checks if a device path refers to a partition on some media device. This
+ * works by checking for a valid partition number in a hard-driver media device
+ * as the final component of the device path.
+ *
+ * @path:	device path
+ * Return:	true if a partition, false if not
+ *		(e.g. it might be media which contains partitions)
+ */
+static bool devpath_is_partition(const struct efi_device_path *path)
+{
+	const struct efi_device_path *p;
+	bool was_part;
+
+	for (p = path; p->type != DEVICE_PATH_TYPE_END;
+	     p = (void *)p + p->length) {
+		was_part = false;
+		if (p->type == DEVICE_PATH_TYPE_MEDIA_DEVICE &&
+		    p->sub_type == DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH) {
+			struct efi_device_path_hard_drive_path *hd =
+				(void *)path;
+
+			if (hd->partition_number)
+				was_part = true;
+		}
+	}
+
+	return was_part;
+}
+
+/**
+ * setup_block() - Find all block devices and setup EFI devices for them
+ *
+ * Partitions are ignored, since U-Boot has partition handling. Errors with
+ * particular devices produce a warning but execution continues to try to
+ * find others.
+ *
+ * Return: 0 if found, -ENOSYS if there is no boot-services table, -ENOTSUPP
+ *	if a required protocol is not supported
+ */
+static int setup_block(void)
+{
+	efi_guid_t efi_blkio_guid = EFI_BLOCK_IO_PROTOCOL_GUID;
+	efi_guid_t efi_devpath_guid = EFI_DEVICE_PATH_PROTOCOL_GUID;
+	efi_guid_t efi_pathutil_guid = EFI_DEVICE_PATH_UTILITIES_PROTOCOL_GUID;
+	efi_guid_t efi_pathtext_guid = EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
+	struct efi_boot_services *boot = efi_get_boot();
+	struct efi_device_path_utilities_protocol *util;
+	struct efi_device_path_to_text_protocol *text;
+	struct efi_device_path *path;
+	struct efi_block_io *blkio;
+	efi_uintn_t num_handles;
+	efi_handle_t *handle;
+	int ret, i;
+
+	if (!boot)
+		return log_msg_ret("sys", -ENOSYS);
+
+	/* Find all devices which support the block I/O protocol */
+	ret = boot->locate_handle_buffer(BY_PROTOCOL, &efi_blkio_guid, NULL,
+				  &num_handles, &handle);
+	if (ret)
+		return log_msg_ret("loc", -ENOTSUPP);
+	log_debug("Found %d handles:\n", (int)num_handles);
+
+	/* We need to look up the path size and convert it to text */
+	ret = boot->locate_protocol(&efi_pathutil_guid, NULL, (void **)&util);
+	if (ret)
+		return log_msg_ret("util", -ENOTSUPP);
+	ret = boot->locate_protocol(&efi_pathtext_guid, NULL, (void **)&text);
+	if (ret)
+		return log_msg_ret("text", -ENOTSUPP);
+
+	for (i = 0; i < num_handles; i++) {
+		struct udevice *dev;
+		const u16 *name;
+		bool is_part;
+		int len;
+
+		ret = boot->handle_protocol(handle[i], &efi_devpath_guid,
+					    (void **)&path);
+		if (ret) {
+			log_warning("- devpath %d failed (ret=%d)\n", i, ret);
+			continue;
+		}
+
+		ret = boot->handle_protocol(handle[i], &efi_blkio_guid,
+					    (void **)&blkio);
+		if (ret) {
+			log_warning("- blkio %d failed (ret=%d)\n", i, ret);
+			continue;
+		}
+
+		name = text->convert_device_path_to_text(path, true, false);
+		is_part = devpath_is_partition(path);
+
+		if (!is_part) {
+			len = util->get_device_path_size(path);
+			ret = efi_bind_block(handle[i], blkio, path, len, &dev);
+			if (ret) {
+				log_warning("- blkio bind %d failed (ret=%d)\n",
+					    i, ret);
+				continue;
+			}
+		} else {
+			dev = NULL;
+		}
+
+		/*
+		 * Show the device name if we created one. Otherwise indicate
+		 * that it is a partition.
+		 */
+		printf("%2d: %-12s %ls\n", i, dev ? dev->name : "<partition>",
+		       name);
+	}
+	boot->free_pool(handle);
+
+	return 0;
+}
+
+/**
+ * dm_scan_other() - Scan for UEFI devices that should be available to U-Boot
+ *
+ * This sets up block devices within U-Boot for those found in UEFI. With this,
+ * U-Boot can access those devices
+ *
+ * @pre_reloc_only: true to only bind pre-relocation devices (ignored)
+ * Returns: 0 on success, -ve on error
+ */
+int dm_scan_other(bool pre_reloc_only)
+{
+	if (gd->flags & GD_FLG_RELOC) {
+		int ret;
+
+		ret = setup_block();
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+/**
  * efi_main() - Start an EFI image
  *
  * This function is called by our EFI start-up code. It handles running
@@ -119,9 +301,12 @@
 	efi_status_t ret;
 
 	/* Set up access to EFI data structures */
-	efi_init(priv, "App", image, sys_table);
-
-	global_priv = priv;
+	ret = efi_init(priv, "App", image, sys_table);
+	if (ret) {
+		printf("Failed to set up U-Boot: err=%lx\n", ret);
+		return ret;
+	}
+	efi_set_priv(priv);
 
 	/*
 	 * Set up the EFI debug UART so that printf() works. This is
@@ -147,7 +332,7 @@
 
 static void efi_exit(void)
 {
-	struct efi_priv *priv = global_priv;
+	struct efi_priv *priv = efi_get_priv();
 
 	free_memory(priv);
 	printf("U-Boot EFI exiting\n");
diff --git a/lib/efi/efi_stub.c b/lib/efi/efi_stub.c
index b3393e4..c89ae7c 100644
--- a/lib/efi/efi_stub.c
+++ b/lib/efi/efi_stub.c
@@ -31,7 +31,6 @@
 #error "This file needs to be ported for use on architectures"
 #endif
 
-static struct efi_priv *global_priv;
 static bool use_uart;
 
 struct __packed desctab_info {
@@ -63,6 +62,8 @@
 
 void putc(const char ch)
 {
+	struct efi_priv *priv = efi_get_priv();
+
 	if (ch == '\n')
 		putc('\r');
 
@@ -73,7 +74,7 @@
 			;
 		outb(ch, (ulong)&com_port->thr);
 	} else {
-		efi_putc(global_priv, ch);
+		efi_putc(priv, ch);
 	}
 }
 
@@ -225,6 +226,22 @@
 	return cs32;
 }
 
+/**
+ * setup_info_table() - sets up a table containing information from EFI
+ *
+ * We must call exit_boot_services() before jumping out of the stub into U-Boot
+ * proper, so that U-Boot has full control of peripherals, memory, etc.
+ *
+ * Once we do this, we cannot call any boot-services functions so we must find
+ * out everything we need to before doing that.
+ *
+ * Set up a struct efi_info_hdr table which can hold various records (e.g.
+ * struct efi_entry_memmap) with information obtained from EFI.
+ *
+ * @priv: Pointer to our private information which contains the list
+ * @size: Size of the table to allocate
+ * Return: 0 if OK, non-zero on error
+ */
 static int setup_info_table(struct efi_priv *priv, int size)
 {
 	struct efi_info_hdr *info;
@@ -248,6 +265,19 @@
 	return 0;
 }
 
+/**
+ * add_entry_addr() - Add a new entry to the efi_info list
+ *
+ * This adds an entry, consisting of a tag and two lots of data. This avoids the
+ * caller having to coalesce the data first
+ *
+ * @priv: Pointer to our private information which contains the list
+ * @type: Type of the entry to add
+ * @ptr1: Pointer to first data block to add
+ * @size1: Size of first data block in bytes (can be 0)
+ * @ptr2: Pointer to second data block to add
+ * @size2: Size of second data block in bytes (can be 0)
+ */
 static void add_entry_addr(struct efi_priv *priv, enum efi_entry_t type,
 			   void *ptr1, int size1, void *ptr2, int size2)
 {
@@ -291,7 +321,7 @@
 		puts(" efi_init() failed\n");
 		return ret;
 	}
-	global_priv = priv;
+	efi_set_priv(priv);
 
 	cs32 = get_codeseg32();
 	if (cs32 < 0)
diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c
index 281f886..a2c65e3 100644
--- a/lib/efi_loader/efi_variable_tee.c
+++ b/lib/efi_loader/efi_variable_tee.c
@@ -15,7 +15,6 @@
 #include <malloc.h>
 #include <mm_communication.h>
 
-#define OPTEE_PAGE_SIZE BIT(12)
 extern struct efi_var_file __efi_runtime_data *efi_var_buf;
 static efi_uintn_t max_buffer_size;	/* comm + var + func + data */
 static efi_uintn_t max_payload_size;	/* func + data */
@@ -114,7 +113,11 @@
 	rc = tee_invoke_func(conn.tee, &arg, 2, param);
 	tee_shm_free(shm);
 	tee_close_session(conn.tee, conn.session);
-	if (rc || arg.ret != TEE_SUCCESS)
+	if (rc)
+		return EFI_DEVICE_ERROR;
+	if (arg.ret == TEE_ERROR_EXCESS_DATA)
+		log_err("Variable payload too large\n");
+	if (arg.ret != TEE_SUCCESS)
 		return EFI_DEVICE_ERROR;
 
 	switch (param[1].u.value.a) {
@@ -256,15 +259,6 @@
 	}
 	*size = var_payload->size;
 	/*
-	 * Although the max payload is configurable on StMM, we only share a
-	 * single page from OP-TEE for the non-secure buffer used to communicate
-	 * with StMM. Since OP-TEE will reject to map anything bigger than that,
-	 * make sure we are in bounds.
-	 */
-	if (*size > OPTEE_PAGE_SIZE)
-		*size = OPTEE_PAGE_SIZE - MM_COMMUNICATE_HEADER_SIZE  -
-			MM_VARIABLE_COMMUNICATE_SIZE;
-	/*
 	 * There seems to be a bug in EDK2 miscalculating the boundaries and
 	 * size checks, so deduct 2 more bytes to fulfill this requirement. Fix
 	 * it up here to ensure backwards compatibility with older versions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index e634bd7..de9f236 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -276,9 +276,8 @@
 }
 
 /* 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)
+static __maybe_unused char *string16(char *buf, char *end, u16 *s,
+				     int field_width, int precision, int flags)
 {
 	const u16 *str = s ? s : L"<NULL>";
 	ssize_t i, len = utf16_strnlen(str, precision);
@@ -317,7 +316,6 @@
 	return buf;
 }
 #endif
-#endif
 
 static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
 				int precision, int flags)
@@ -616,7 +614,8 @@
 
 		case 's':
 /* U-Boot uses UTF-16 strings in the EFI context only. */
-#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
+#if (CONFIG_IS_ENABLED(EFI_LOADER) || CONFIG_IS_ENABLED(EFI_APP)) && \
+	!defined(API_BUILD)
 			if (qualifier == 'l') {
 				str = string16(str, end, va_arg(args, u16 *),
 					       field_width, precision, flags);