Merge tag 'efi-2023-04-rc1-3' of https://source.denx.de/u-boot/custodians/u-boot-efi

Pull request efi-2023-04-rc1-3

Documentation:

* Improve the sl-mx8mm documenation
* Clean up README, move some section to HTML
* Man-pages for the mtime and sleep command
* Description of reducible builds
* Document dynamic event handlers

UEFI:

* Support scrolling in eficonfig command

Other:

* fix mtest on 64 bit systems
diff --git a/README b/README
index 40619ee..edce789 100644
--- a/README
+++ b/README
@@ -28,20 +28,16 @@
 Status:
 =======
 
-In general, all boards for which a configuration option exists in the
-Makefile have been tested to some extent and can be considered
+In general, all boards for which a default configuration file exists in the
+configs/ directory have been tested to some extent and can be considered
 "working". In fact, many of them are used in production systems.
 
-In case of problems see the CHANGELOG file to find out who contributed
-the specific port. In addition, there are various MAINTAINERS files
-scattered throughout the U-Boot source identifying the people or
-companies responsible for various boards and subsystems.
+In case of problems you can use
 
-Note: As of August, 2010, there is no longer a CHANGELOG file in the
-actual U-Boot source tree; however, it can be created dynamically
-from the Git log using:
+     scripts/get_maintainer.pl <path>
 
-	make CHANGELOG
+to identify the people or companies responsible for various boards and
+subsystems. Or have a look at the git log.
 
 
 Where to get help:
@@ -109,60 +105,6 @@
 	IH_OS_U_BOOT		u_boot_hush_start
 
 
-Versioning:
-===========
-
-Starting with the release in October 2008, the names of the releases
-were changed from numerical release numbers without deeper meaning
-into a time stamp based numbering. Regular releases are identified by
-names consisting of the calendar year and month of the release date.
-Additional fields (if present) indicate release candidates or bug fix
-releases in "stable" maintenance trees.
-
-Examples:
-	U-Boot v2009.11	    - Release November 2009
-	U-Boot v2009.11.1   - Release 1 in version November 2009 stable tree
-	U-Boot v2010.09-rc1 - Release candidate 1 for September 2010 release
-
-
-Directory Hierarchy:
-====================
-
-/arch			Architecture-specific files
-  /arc			Files generic to ARC architecture
-  /arm			Files generic to ARM architecture
-  /m68k			Files generic to m68k architecture
-  /microblaze		Files generic to microblaze architecture
-  /mips			Files generic to MIPS architecture
-  /nios2		Files generic to Altera NIOS2 architecture
-  /powerpc		Files generic to PowerPC architecture
-  /riscv		Files generic to RISC-V architecture
-  /sandbox		Files generic to HW-independent "sandbox"
-  /sh			Files generic to SH architecture
-  /x86			Files generic to x86 architecture
-  /xtensa		Files generic to Xtensa architecture
-/api			Machine/arch-independent API for external apps
-/board			Board-dependent files
-/boot			Support for images and booting
-/cmd			U-Boot commands functions
-/common			Misc architecture-independent functions
-/configs		Board default configuration files
-/disk			Code for disk drive partition handling
-/doc			Documentation (a mix of ReST and READMEs)
-/drivers		Device drivers
-/dts			Makefile for building internal U-Boot fdt.
-/env			Environment support
-/examples		Example code for standalone applications, etc.
-/fs			Filesystem code (cramfs, ext2, jffs2, etc.)
-/include		Header Files
-/lib			Library routines generic to all architectures
-/Licenses		Various license files
-/net			Networking code
-/post			Power On Self Test
-/scripts		Various build scripts and Makefiles
-/test			Various unit test files
-/tools			Tools to build and sign FIT images, etc.
-
 Software Configuration:
 =======================
 
@@ -189,7 +131,7 @@
 specific to be undertaken on a native platform. The sandbox is also used to
 run some of U-Boot's tests.
 
-See doc/arch/sandbox.rst for more details.
+See doc/arch/sandbox/sandbox.rst for more details.
 
 
 Board Initialisation Flow:
@@ -1717,17 +1659,6 @@
 - CONFIG_SYS_MC_RSV_MEM_ALIGN
 	Define alignment of reserved memory MC requires
 
-Reproducible builds
--------------------
-
-In order to achieve reproducible builds, timestamps used in the U-Boot build
-process have to be set to a fixed value.
-
-This is done using the SOURCE_DATE_EPOCH environment variable.
-SOURCE_DATE_EPOCH is to be set on the build host's shell, not as a configuration
-option for U-Boot or an environment variable in U-Boot.
-
-SOURCE_DATE_EPOCH should be set to a number of seconds since the epoch, in UTC.
 
 Building the Software:
 ======================
@@ -2525,35 +2456,6 @@
 	X  kermit  /usr/bin/kermit -i -l %l -s	 Y    U	   Y	   N	  N
 	Y  kermit  /usr/bin/kermit -i -l %l -r	 N    D	   Y	   N	  N
 
-
-NetBSD Notes:
-=============
-
-Starting at version 0.9.2, U-Boot supports NetBSD both as host
-(build U-Boot) and target system (boots NetBSD/mpc8xx).
-
-Building requires a cross environment; it is known to work on
-NetBSD/i386 with the cross-powerpc-netbsd-1.3 package (you will also
-need gmake since the Makefiles are not compatible with BSD make).
-Note that the cross-powerpc package does not install include files;
-attempting to build U-Boot will fail because <machine/ansi.h> is
-missing.  This file has to be installed and patched manually:
-
-	# cd /usr/pkg/cross/powerpc-netbsd/include
-	# mkdir powerpc
-	# ln -s powerpc machine
-	# cp /usr/src/sys/arch/powerpc/include/ansi.h powerpc/ansi.h
-	# ${EDIT} powerpc/ansi.h	## must remove __va_list, _BSD_VA_LIST
-
-Native builds *don't* work due to incompatibilities between native
-and U-Boot include files.
-
-Booting assumes that (the first part of) the image booted is a
-stage-2 loader which in turn loads and then invokes the kernel
-proper. Loader sources will eventually appear in the NetBSD source
-tree (probably in sys/arc/mpc8xx/stand/u-boot_stage2/); in the
-meantime, see ftp://ftp.denx.de/pub/u-boot/ppcboot_stage2.tar.gz
-
 
 Implementation Internals:
 =========================
@@ -2787,183 +2689,11 @@
 running from ROM, and because the code will have to be relocated to a
 new address in RAM.
 
-
-U-Boot Porting Guide:
-----------------------
-
-[Based on messages by Jerry Van Baren in the U-Boot-Users mailing
-list, October 2002]
-
-
-int main(int argc, char *argv[])
-{
-	sighandler_t no_more_time;
-
-	signal(SIGALRM, no_more_time);
-	alarm(PROJECT_DEADLINE - toSec (3 * WEEK));
-
-	if (available_money > available_manpower) {
-		Pay consultant to port U-Boot;
-		return 0;
-	}
-
-	Download latest U-Boot source;
-
-	Subscribe to u-boot mailing list;
-
-	if (clueless)
-		email("Hi, I am new to U-Boot, how do I get started?");
-
-	while (learning) {
-		Read the README file in the top level directory;
-		Read https://www.denx.de/wiki/bin/view/DULG/Manual;
-		Read applicable doc/README.*;
-		Read the source, Luke;
-		/* find . -name "*.[chS]" | xargs grep -i <keyword> */
-	}
-
-	if (available_money > toLocalCurrency ($2500))
-		Buy a BDI3000;
-	else
-		Add a lot of aggravation and time;
-
-	if (a similar board exists) {	/* hopefully... */
-		cp -a board/<similar> board/<myboard>
-		cp include/configs/<similar>.h include/configs/<myboard>.h
-	} else {
-		Create your own board support subdirectory;
-		Create your own board include/configs/<myboard>.h file;
-	}
-	Edit new board/<myboard> files
-	Edit new include/configs/<myboard>.h
-
-	while (!accepted) {
-		while (!running) {
-			do {
-				Add / modify source code;
-			} until (compiles);
-			Debug;
-			if (clueless)
-				email("Hi, I am having problems...");
-		}
-		Send patch file to the U-Boot email list;
-		if (reasonable critiques)
-			Incorporate improvements from email list code review;
-		else
-			Defend code as written;
-	}
-
-	return 0;
-}
 
-void no_more_time (int sig)
-{
-      hire_a_guru();
-}
-
-
-Coding Standards:
------------------
-
-All contributions to U-Boot should conform to the Linux kernel
-coding style; see the kernel coding style guide at
-https://www.kernel.org/doc/html/latest/process/coding-style.html, and the
-script "scripts/Lindent" in your Linux kernel source directory.
-
-Source files originating from a different project (for example the
-MTD subsystem) are generally exempt from these guidelines and are not
-reformatted to ease subsequent migration to newer versions of those
-sources.
-
-Please note that U-Boot is implemented in C (and to some small parts in
-Assembler); no C++ is used, so please do not use C++ style comments (//)
-in your code.
-
-Please also stick to the following formatting rules:
-- remove any trailing white space
-- use TAB characters for indentation and vertical alignment, not spaces
-- make sure NOT to use DOS '\r\n' line feeds
-- do not add more than 2 consecutive empty lines to source files
-- do not add trailing empty lines to source files
-
-Submissions which do not conform to the standards may be returned
-with a request to reformat the changes.
-
-
-Submitting Patches:
--------------------
-
-Since the number of patches for U-Boot is growing, we need to
-establish some rules. Submissions which do not conform to these rules
-may be rejected, even when they contain important and valuable stuff.
-
-Please see https://www.denx.de/wiki/U-Boot/Patches for details.
-
-Patches shall be sent to the u-boot mailing list <u-boot@lists.denx.de>;
-see https://lists.denx.de/listinfo/u-boot
-
-When you send a patch, please include the following information with
-it:
-
-* For bug fixes: a description of the bug and how your patch fixes
-  this bug. Please try to include a way of demonstrating that the
-  patch actually fixes something.
-
-* For new features: a description of the feature and your
-  implementation.
-
-* For major contributions, add a MAINTAINERS file with your
-  information and associated file and directory references.
-
-* When you add support for a new board, don't forget to add a
-  maintainer e-mail address to the boards.cfg file, too.
-
-* If your patch adds new configuration options, don't forget to
-  document these in the README file.
-
-* The patch itself. If you are using git (which is *strongly*
-  recommended) you can easily generate the patch using the
-  "git format-patch". If you then use "git send-email" to send it to
-  the U-Boot mailing list, you will avoid most of the common problems
-  with some other mail clients.
-
-  If you cannot use git, use "diff -purN OLD NEW". If your version of
-  diff does not support these options, then get the latest version of
-  GNU diff.
-
-  The current directory when running this command shall be the parent
-  directory of the U-Boot source tree (i. e. please make sure that
-  your patch includes sufficient directory information for the
-  affected files).
-
-  We prefer patches as plain text. MIME attachments are discouraged,
-  and compressed attachments must not be used.
-
-* If one logical set of modifications affects or creates several
-  files, all these changes shall be submitted in a SINGLE patch file.
-
-* Changesets that contain different, unrelated modifications shall be
-  submitted as SEPARATE patches, one patch per changeset.
-
-
-Notes:
-
-* Before sending the patch, run the buildman script on your patched
-  source tree and make sure that no errors or warnings are reported
-  for any of the boards.
-
-* Keep your modifications to the necessary minimum: A patch
-  containing several unrelated changes or arbitrary reformats will be
-  returned with a request to re-formatting / split it.
-
-* If you modify existing code, make sure that your new code does not
-  add to the memory footprint of the code ;-) Small is beautiful!
-  When adding new features, these should compile conditionally only
-  (using #ifdef), and the resulting code with the new feature
-  disabled must not need more memory than the old code without your
-  modification.
+Contributing
+============
 
-* Remember that there is a size limit of 100 kB per message on the
-  u-boot mailing list. Bigger patches will be moderated. If they are
-  reasonable and not too big, they will be acknowledged. But patches
-  bigger than the size limit should be avoided.
+The U-Boot projects depends on contributions from the user community.
+If you want to participate, please, have a look at the 'General'
+section of https://u-boot.readthedocs.io/en/latest/develop/index.html
+where we describe coding standards and the patch submission process.
diff --git a/cmd/eficonfig.c b/cmd/eficonfig.c
index d830e4a..47c04cf 100644
--- a/cmd/eficonfig.c
+++ b/cmd/eficonfig.c
@@ -22,9 +22,21 @@
 #include <linux/delay.h>
 
 static struct efi_simple_text_input_protocol *cin;
+const char *eficonfig_menu_desc =
+	"  Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit";
+
+static const char *eficonfig_change_boot_order_desc =
+	"  Press UP/DOWN to move, +/- to change orde\n"
+	"  Press SPACE to activate or deactivate the entry\n"
+	"  Select [Save] to complete, ESC/CTRL+C to quit";
+
+static struct efi_simple_text_output_protocol *cout;
+static int avail_row;
 
 #define EFICONFIG_DESCRIPTION_MAX 32
 #define EFICONFIG_OPTIONAL_DATA_MAX 64
+#define EFICONFIG_MENU_HEADER_ROW_NUM 3
+#define EFICONFIG_MENU_DESC_ROW_NUM 5
 
 /**
  * struct eficonfig_filepath_info - structure to be used to store file path
@@ -105,6 +117,41 @@
 };
 
 /**
+ * struct eficonfig_save_boot_order_data - structure to be used to change boot order
+ *
+ * @efi_menu:		pointer to efimenu structure
+ * @selected:		flag to indicate user selects "Save" entry
+ */
+struct eficonfig_save_boot_order_data {
+	struct efimenu *efi_menu;
+	bool selected;
+};
+
+/**
+ * struct eficonfig_menu_adjust - update start and end entry index
+ *
+ * @efi_menu:	pointer to efimenu structure
+ * @add:	flag to add or substract the index
+ */
+static void eficonfig_menu_adjust(struct efimenu *efi_menu, bool add)
+{
+	if (add)
+		++efi_menu->active;
+	else
+		--efi_menu->active;
+
+	if (add && efi_menu->end < efi_menu->active) {
+		efi_menu->start++;
+		efi_menu->end++;
+	} else if (!add && efi_menu->start > efi_menu->active) {
+		efi_menu->start--;
+		efi_menu->end--;
+	}
+}
+#define eficonfig_menu_up(_a) eficonfig_menu_adjust(_a, false)
+#define eficonfig_menu_down(_a) eficonfig_menu_adjust(_a, true)
+
+/**
  * eficonfig_print_msg() - print message
  *
  * display the message to the user, user proceeds the screen
@@ -134,23 +181,21 @@
  *
  * @data:	pointer to the data associated with each menu entry
  */
-static void eficonfig_print_entry(void *data)
+void eficonfig_print_entry(void *data)
 {
 	struct eficonfig_entry *entry = data;
-	int reverse = (entry->efi_menu->active == entry->num);
+	bool reverse = (entry->efi_menu->active == entry->num);
 
-	/* TODO: support scroll or page for many entries */
+	if (entry->efi_menu->start > entry->num || entry->efi_menu->end < entry->num)
+		return;
 
-	/*
-	 * Move cursor to line where the entry will be drawn (entry->num)
-	 * First 3 lines(menu header) + 1 empty line
-	 */
-	printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
+	printf(ANSI_CURSOR_POSITION, (entry->num - entry->efi_menu->start) +
+	       EFICONFIG_MENU_HEADER_ROW_NUM + 1, 7);
 
 	if (reverse)
 		puts(ANSI_COLOR_REVERSE);
 
-	printf("%s", entry->title);
+	printf(ANSI_CLEAR_LINE "%s", entry->title);
 
 	if (reverse)
 		puts(ANSI_COLOR_RESET);
@@ -161,7 +206,7 @@
  *
  * @m:	pointer to the menu structure
  */
-static void eficonfig_display_statusline(struct menu *m)
+void eficonfig_display_statusline(struct menu *m)
 {
 	struct eficonfig_entry *entry;
 
@@ -171,10 +216,10 @@
 	printf(ANSI_CURSOR_POSITION
 	      "\n%s\n"
 	       ANSI_CURSOR_POSITION ANSI_CLEAR_LINE ANSI_CURSOR_POSITION
-	       "  Press UP/DOWN to move, ENTER to select, ESC/CTRL+C to quit"
-	       ANSI_CLEAR_LINE_TO_END ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
-	       1, 1, entry->efi_menu->menu_header, entry->efi_menu->count + 5, 1,
-	       entry->efi_menu->count + 6, 1, entry->efi_menu->count + 7, 1);
+	       "%s"
+	       ANSI_CLEAR_LINE_TO_END,
+	       1, 1, entry->efi_menu->menu_header, avail_row + 4, 1,
+	       avail_row + 5, 1, entry->efi_menu->menu_desc);
 }
 
 /**
@@ -183,7 +228,7 @@
  * @data:	pointer to the efimenu structure
  * Return:	key string to identify the selected entry
  */
-static char *eficonfig_choice_entry(void *data)
+char *eficonfig_choice_entry(void *data)
 {
 	struct cli_ch_state s_cch, *cch = &s_cch;
 	struct list_head *pos, *n;
@@ -199,12 +244,14 @@
 		switch (key) {
 		case BKEY_UP:
 			if (efi_menu->active > 0)
-				--efi_menu->active;
+				eficonfig_menu_up(efi_menu);
+
 			/* no menu key selected, regenerate menu */
 			return NULL;
 		case BKEY_DOWN:
 			if (efi_menu->active < efi_menu->count - 1)
-				++efi_menu->active;
+				eficonfig_menu_down(efi_menu);
+
 			/* no menu key selected, regenerate menu */
 			return NULL;
 		case BKEY_SELECT:
@@ -361,9 +408,17 @@
  *
  * @efi_menu:		pointer to the efimenu structure
  * @menu_header:	pointer to the menu header string
+ * @menu_desc:		pointer to the menu description
+ * @display_statusline:	function pointer to draw statusline
+ * @item_data_print:	function pointer to draw the menu item
+ * @item_choice:	function pointer to handle the key press
  * Return:		status code
  */
-efi_status_t eficonfig_process_common(struct efimenu *efi_menu, char *menu_header)
+efi_status_t eficonfig_process_common(struct efimenu *efi_menu,
+				      char *menu_header, const char *menu_desc,
+				      void (*display_statusline)(struct menu *),
+				      void (*item_data_print)(void *),
+				      char *(*item_choice)(void *))
 {
 	struct menu *menu;
 	void *choice = NULL;
@@ -376,16 +431,19 @@
 
 	efi_menu->delay = -1;
 	efi_menu->active = 0;
+	efi_menu->start = 0;
+	efi_menu->end = avail_row - 1;
 
 	if (menu_header) {
 		efi_menu->menu_header = strdup(menu_header);
 		if (!efi_menu->menu_header)
 			return EFI_OUT_OF_RESOURCES;
 	}
+	if (menu_desc)
+		efi_menu->menu_desc = menu_desc;
 
-	menu = menu_create(NULL, 0, 1, eficonfig_display_statusline,
-			   eficonfig_print_entry, eficonfig_choice_entry,
-			   efi_menu);
+	menu = menu_create(NULL, 0, 1, display_statusline, item_data_print,
+			   item_choice, efi_menu);
 	if (!menu)
 		return EFI_INVALID_PARAMETER;
 
@@ -644,7 +702,12 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
-	ret = eficonfig_process_common(efi_menu, "  ** Select Volume **");
+	ret = eficonfig_process_common(efi_menu, "  ** Select Volume **",
+				       eficonfig_menu_desc,
+				       eficonfig_display_statusline,
+				       eficonfig_print_entry,
+				       eficonfig_choice_entry);
+
 out:
 	efi_free_pool(volume_handles);
 	list_for_each_safe(pos, n, &efi_menu->list) {
@@ -819,7 +882,11 @@
 		if (ret != EFI_SUCCESS)
 			goto err;
 
-		ret = eficonfig_process_common(efi_menu, "  ** Select File **");
+		ret = eficonfig_process_common(efi_menu, "  ** Select File **",
+					       eficonfig_menu_desc,
+					       eficonfig_display_statusline,
+					       eficonfig_print_entry,
+					       eficonfig_choice_entry);
 err:
 		EFI_CALL(f->close(f));
 		eficonfig_destroy(efi_menu);
@@ -980,7 +1047,11 @@
 	if (!efi_menu)
 		return EFI_OUT_OF_RESOURCES;
 
-	ret = eficonfig_process_common(efi_menu, "  ** Update File **");
+	ret = eficonfig_process_common(efi_menu, "  ** Update File **",
+				       eficonfig_menu_desc,
+				       eficonfig_display_statusline,
+				       eficonfig_print_entry,
+				       eficonfig_choice_entry);
 	if (ret != EFI_SUCCESS) /* User selects "Clear" or "Quit" */
 		ret = EFI_NOT_READY;
 
@@ -1326,7 +1397,12 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
+	ret = eficonfig_process_common(efi_menu, header_str,
+				       eficonfig_menu_desc,
+				       eficonfig_display_statusline,
+				       eficonfig_print_entry,
+				       eficonfig_choice_entry);
+
-	ret = eficonfig_process_common(efi_menu, header_str);
 out:
 	eficonfig_destroy(efi_menu);
 
@@ -1745,7 +1821,11 @@
 	if (ret != EFI_SUCCESS)
 		goto out;
 
-	ret = eficonfig_process_common(efi_menu, "  ** Select Boot Option **");
+	ret = eficonfig_process_common(efi_menu, "  ** Select Boot Option **",
+				       eficonfig_menu_desc,
+				       eficonfig_display_statusline,
+				       eficonfig_print_entry,
+				       eficonfig_choice_entry);
 out:
 	list_for_each_safe(pos, n, &efi_menu->list) {
 		entry = list_entry(pos, struct eficonfig_entry, list);
@@ -1810,63 +1890,48 @@
 }
 
 /**
- * eficonfig_display_change_boot_order() - display the BootOrder list
+ * eficonfig_print_change_boot_order_entry() - print the boot option entry
  *
- * @efi_menu:	pointer to the efimenu structure
- * Return:	status code
+ * @data:	pointer to the data associated with each menu entry
  */
-static void eficonfig_display_change_boot_order(struct efimenu *efi_menu)
+static void eficonfig_print_change_boot_order_entry(void *data)
 {
-	bool reverse;
-	struct list_head *pos, *n;
-	struct eficonfig_entry *entry;
-
-	printf(ANSI_CLEAR_CONSOLE ANSI_CURSOR_POSITION
-	       "\n  ** Change Boot Order **\n"
-	       ANSI_CURSOR_POSITION
-	       "  Press UP/DOWN to move, +/- to change order"
-	       ANSI_CURSOR_POSITION
-	       "  Press SPACE to activate or deactivate the entry"
-	       ANSI_CURSOR_POSITION
-	       "  Select [Save] to complete, ESC/CTRL+C to quit"
-	       ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
-	       1, 1, efi_menu->count + 5, 1, efi_menu->count + 6, 1,
-	       efi_menu->count + 7, 1,  efi_menu->count + 8, 1);
+	struct eficonfig_entry *entry = data;
+	bool reverse = (entry->efi_menu->active == entry->num);
 
-	/* draw boot option list */
-	list_for_each_safe(pos, n, &efi_menu->list) {
-		entry = list_entry(pos, struct eficonfig_entry, list);
-		reverse = (entry->num == efi_menu->active);
+	if (entry->efi_menu->start > entry->num || entry->efi_menu->end < entry->num)
+		return;
 
-		printf(ANSI_CURSOR_POSITION, entry->num + 4, 7);
+	printf(ANSI_CURSOR_POSITION ANSI_CLEAR_LINE,
+	       (entry->num - entry->efi_menu->start) + EFICONFIG_MENU_HEADER_ROW_NUM + 1, 7);
 
-		if (reverse)
-			puts(ANSI_COLOR_REVERSE);
+	if (reverse)
+		puts(ANSI_COLOR_REVERSE);
 
-		if (entry->num < efi_menu->count - 2) {
-			if (((struct eficonfig_boot_order_data *)entry->data)->active)
-				printf("[*]  ");
-			else
-				printf("[ ]  ");
-		}
+	if (entry->num < entry->efi_menu->count - 2) {
+		if (((struct eficonfig_boot_order_data *)entry->data)->active)
+			printf("[*]  ");
+		else
+			printf("[ ]  ");
+	}
 
-		printf("%s", entry->title);
+	printf("%s", entry->title);
 
-		if (reverse)
-			puts(ANSI_COLOR_RESET);
-	}
+	if (reverse)
+		puts(ANSI_COLOR_RESET);
 }
 
 /**
- * eficonfig_choice_change_boot_order() - handle the BootOrder update
+ * eficonfig_choice_change_boot_order() - user key input handler
  *
- * @efi_menu:	pointer to the efimenu structure
- * Return:	status code
+ * @data:	pointer to the menu entry
+ * Return:	key string to identify the selected entry
  */
-static efi_status_t eficonfig_choice_change_boot_order(struct efimenu *efi_menu)
+char *eficonfig_choice_change_boot_order(void *data)
 {
 	struct cli_ch_state s_cch, *cch = &s_cch;
 	struct list_head *pos, *n;
+	struct efimenu *efi_menu = data;
 	enum bootmenu_key key = BKEY_NONE;
 	struct eficonfig_entry *entry, *tmp;
 
@@ -1876,7 +1941,8 @@
 
 		switch (key) {
 		case BKEY_PLUS:
-			if (efi_menu->active > 0) {
+			if (efi_menu->active > 0 &&
+			    efi_menu->active < efi_menu->count - 2) {
 				list_for_each_safe(pos, n, &efi_menu->list) {
 					entry = list_entry(pos, struct eficonfig_entry, list);
 					if (entry->num == efi_menu->active)
@@ -1887,12 +1953,15 @@
 				tmp->num++;
 				list_del(&tmp->list);
 				list_add(&tmp->list, &entry->list);
+
+				eficonfig_menu_up(efi_menu);
 			}
-			fallthrough;
+			return NULL;
 		case BKEY_UP:
 			if (efi_menu->active > 0)
-				--efi_menu->active;
-			return EFI_NOT_READY;
+				eficonfig_menu_up(efi_menu);
+
+			return NULL;
 		case BKEY_MINUS:
 			if (efi_menu->active < efi_menu->count - 3) {
 				list_for_each_safe(pos, n, &efi_menu->list) {
@@ -1906,22 +1975,32 @@
 				list_del(&entry->list);
 				list_add(&entry->list, &tmp->list);
 
-				++efi_menu->active;
+				eficonfig_menu_down(efi_menu);
 			}
-			return EFI_NOT_READY;
+			return NULL;
 		case BKEY_DOWN:
 			if (efi_menu->active < efi_menu->count - 1)
-				++efi_menu->active;
-			return EFI_NOT_READY;
+				eficonfig_menu_down(efi_menu);
+
+			return NULL;
 		case BKEY_SELECT:
 			/* "Save" */
-			if (efi_menu->active == efi_menu->count - 2)
-				return EFI_SUCCESS;
-
+			if (efi_menu->active == efi_menu->count - 2) {
+				list_for_each_prev_safe(pos, n, &efi_menu->list) {
+					entry = list_entry(pos, struct eficonfig_entry, list);
+					if (entry->num == efi_menu->active)
+						break;
+				}
+				return entry->key;
+			}
 			/* "Quit" */
-			if (efi_menu->active == efi_menu->count - 1)
-				return EFI_ABORTED;
-
+			if (efi_menu->active == efi_menu->count - 1) {
+				entry = list_last_entry(&efi_menu->list,
+							struct eficonfig_entry,
+							list);
+				return entry->key;
+			}
+			/* Pressed key is not valid, wait next key press */
 			break;
 		case BKEY_SPACE:
 			if (efi_menu->active < efi_menu->count - 2) {
@@ -1931,21 +2010,85 @@
 						struct eficonfig_boot_order_data *data = entry->data;
 
 						data->active = !data->active;
-						return EFI_NOT_READY;
+						return NULL;
 					}
 				}
 			}
+			/* Pressed key is not valid, wait next key press */
 			break;
 		case BKEY_QUIT:
-			return EFI_ABORTED;
+			entry = list_last_entry(&efi_menu->list,
+						struct eficonfig_entry, list);
+			return entry->key;
 		default:
-			/* Pressed key is not valid, no need to regenerate the menu */
+			/* Pressed key is not valid, wait next key press */
 			break;
 		}
 	}
 }
 
 /**
+ * eficonfig_process_save_boot_order() - callback function for "Save" entry
+ *
+ * @data:	pointer to the data
+ * Return:	status code
+ */
+static efi_status_t eficonfig_process_save_boot_order(void *data)
+{
+	u32 count = 0;
+	efi_status_t ret;
+	efi_uintn_t size;
+	struct list_head *pos, *n;
+	u16 *new_bootorder;
+	struct efimenu *efi_menu;
+	struct eficonfig_entry *entry;
+	struct eficonfig_save_boot_order_data *save_data = data;
+
+	efi_menu = save_data->efi_menu;
+
+	/*
+	 * The change boot order menu always has "Save" and "Quit" entries.
+	 * !(efi_menu->count - 2) means there is no user defined boot option.
+	 */
+	if (!(efi_menu->count - 2))
+		return EFI_SUCCESS;
+
+	new_bootorder = calloc(1, (efi_menu->count - 2) * sizeof(u16));
+	if (!new_bootorder) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+
+	/* create new BootOrder */
+	count = 0;
+	list_for_each_safe(pos, n, &efi_menu->list) {
+		struct eficonfig_boot_order_data *data;
+
+		entry = list_entry(pos, struct eficonfig_entry, list);
+		/* exit the loop when iteration reaches "Save" */
+		if (!strncmp(entry->title, "Save", strlen("Save")))
+			break;
+
+		data = entry->data;
+		if (data->active)
+			new_bootorder[count++] = data->boot_index;
+	}
+
+	size = count * sizeof(u16);
+	ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
+				   EFI_VARIABLE_NON_VOLATILE |
+				   EFI_VARIABLE_BOOTSERVICE_ACCESS |
+				   EFI_VARIABLE_RUNTIME_ACCESS,
+				   size, new_bootorder, false);
+
+	save_data->selected = true;
+out:
+	free(new_bootorder);
+
+	return ret;
+}
+
+/**
  * eficonfig_add_change_boot_order_entry() - add boot order entry
  *
  * @efi_menu:	pointer to the efimenu structure
@@ -2020,6 +2163,7 @@
 	efi_status_t ret;
 	u16 *var_name16 = NULL;
 	efi_uintn_t size, buf_size;
+	struct eficonfig_save_boot_order_data *save_data;
 
 	/* list the load option in the order of BootOrder variable */
 	for (i = 0; i < num; i++) {
@@ -2070,7 +2214,17 @@
 		goto out;
 	}
 
-	ret = eficonfig_append_menu_entry(efi_menu, title, NULL, NULL);
+	save_data = malloc(sizeof(struct eficonfig_save_boot_order_data));
+	if (!save_data) {
+		ret = EFI_OUT_OF_RESOURCES;
+		goto out;
+	}
+	save_data->efi_menu = efi_menu;
+	save_data->selected = false;
+
+	ret = eficonfig_append_menu_entry(efi_menu, title,
+					  eficonfig_process_save_boot_order,
+					  save_data);
 	if (ret != EFI_SUCCESS)
 		goto out;
 
@@ -2093,7 +2247,6 @@
  */
 static efi_status_t eficonfig_process_change_boot_order(void *data)
 {
-	u32 count;
 	u16 *bootorder;
 	efi_status_t ret;
 	efi_uintn_t num, size;
@@ -2114,47 +2267,24 @@
 		goto out;
 
 	while (1) {
-		eficonfig_display_change_boot_order(efi_menu);
-
-		ret = eficonfig_choice_change_boot_order(efi_menu);
-		if (ret == EFI_SUCCESS) {
-			u16 *new_bootorder;
-
-			new_bootorder = calloc(1, (efi_menu->count - 2) * sizeof(u16));
-			if (!new_bootorder) {
-				ret = EFI_OUT_OF_RESOURCES;
-				goto out;
-			}
-
-			/* create new BootOrder  */
-			count = 0;
-			list_for_each_safe(pos, n, &efi_menu->list) {
-				struct eficonfig_boot_order_data *data;
-
+		ret = eficonfig_process_common(efi_menu,
+					       "  ** Change Boot Order **",
+					       eficonfig_change_boot_order_desc,
+					       eficonfig_display_statusline,
+					       eficonfig_print_change_boot_order_entry,
+					       eficonfig_choice_change_boot_order);
+		/* exit from the menu if user selects the "Save" entry. */
+		if (ret == EFI_SUCCESS && efi_menu->active == (efi_menu->count - 2)) {
+			list_for_each_prev_safe(pos, n, &efi_menu->list) {
 				entry = list_entry(pos, struct eficonfig_entry, list);
-				/* exit the loop when iteration reaches "Save" */
-				if (!strncmp(entry->title, "Save", strlen("Save")))
+				if (entry->num == efi_menu->active)
 					break;
-
-				data = entry->data;
-				if (data->active)
-					new_bootorder[count++] = data->boot_index;
 			}
-
-			size = count * sizeof(u16);
-			ret = efi_set_variable_int(u"BootOrder", &efi_global_variable_guid,
-						   EFI_VARIABLE_NON_VOLATILE |
-						   EFI_VARIABLE_BOOTSERVICE_ACCESS |
-						   EFI_VARIABLE_RUNTIME_ACCESS,
-						   size, new_bootorder, false);
-
-			free(new_bootorder);
-			goto out;
-		} else if (ret == EFI_NOT_READY) {
-			continue;
-		} else {
-			goto out;
+			if (((struct eficonfig_save_boot_order_data *)entry->data)->selected)
+				break;
 		}
+		if (ret != EFI_SUCCESS)
+			break;
 	}
 out:
 	free(bootorder);
@@ -2500,6 +2630,7 @@
 	efi_status_t ret = EFI_SUCCESS;
 	static bool init;
 	struct efi_handler *handler;
+	unsigned long columns, rows;
 
 	if (!init) {
 		ret = efi_search_protocol(efi_root, &efi_guid_text_input_protocol, &handler);
@@ -2510,6 +2641,23 @@
 					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
 		if (ret != EFI_SUCCESS)
 			return ret;
+		ret = efi_search_protocol(efi_root, &efi_guid_text_output_protocol, &handler);
+		if (ret != EFI_SUCCESS)
+			return ret;
+
+		ret = efi_protocol_open(handler, (void **)&cout, efi_root, NULL,
+					EFI_OPEN_PROTOCOL_GET_PROTOCOL);
+		if (ret != EFI_SUCCESS)
+			return ret;
+
+		cout->query_mode(cout, cout->mode->mode, &columns, &rows);
+		avail_row = rows - (EFICONFIG_MENU_HEADER_ROW_NUM +
+				    EFICONFIG_MENU_DESC_ROW_NUM);
+		if (avail_row <= 0) {
+			eficonfig_print_msg("Console size is too small!");
+			return EFI_INVALID_PARAMETER;
+		}
+		/* TODO: Should we check the minimum column size? */
 	}
 
 	init = true;
@@ -2567,7 +2715,12 @@
 		if (!efi_menu)
 			return CMD_RET_FAILURE;
 
-		ret = eficonfig_process_common(efi_menu, "  ** UEFI Maintenance Menu **");
+		ret = eficonfig_process_common(efi_menu,
+					       "  ** UEFI Maintenance Menu **",
+					       eficonfig_menu_desc,
+					       eficonfig_display_statusline,
+					       eficonfig_print_entry,
+					       eficonfig_choice_entry);
 		eficonfig_destroy(efi_menu);
 
 		if (ret == EFI_ABORTED)
diff --git a/cmd/eficonfig_sbkey.c b/cmd/eficonfig_sbkey.c
index ed39aab..caca274 100644
--- a/cmd/eficonfig_sbkey.c
+++ b/cmd/eficonfig_sbkey.c
@@ -410,7 +410,10 @@
 		goto out;
 
 	snprintf(buf, sizeof(buf), "  ** Show Signature Database (%ls) **", (u16 *)varname);
-	ret = eficonfig_process_common(efi_menu, buf);
+	ret = eficonfig_process_common(efi_menu, buf, eficonfig_menu_desc,
+				       eficonfig_display_statusline,
+				       eficonfig_print_entry,
+				       eficonfig_choice_entry);
 out:
 	list_for_each_safe(pos, n, &efi_menu->list) {
 		entry = list_entry(pos, struct eficonfig_entry, list);
@@ -472,7 +475,11 @@
 		efi_menu = eficonfig_create_fixed_menu(key_config_menu_items,
 						       ARRAY_SIZE(key_config_menu_items));
 
-		ret = eficonfig_process_common(efi_menu, header_str);
+		ret = eficonfig_process_common(efi_menu, header_str,
+					       eficonfig_menu_desc,
+					       eficonfig_display_statusline,
+					       eficonfig_print_entry,
+					       eficonfig_choice_entry);
 		eficonfig_destroy(efi_menu);
 
 		if (ret == EFI_ABORTED)
@@ -518,7 +525,12 @@
 			break;
 		}
 
-		ret = eficonfig_process_common(efi_menu, header_str);
+		ret = eficonfig_process_common(efi_menu, header_str,
+					       eficonfig_menu_desc,
+					       eficonfig_display_statusline,
+					       eficonfig_print_entry,
+					       eficonfig_choice_entry);
+
 		eficonfig_destroy(efi_menu);
 
 		if (ret == EFI_ABORTED)
diff --git a/cmd/mem.c b/cmd/mem.c
index 1e39348..66c2d36 100644
--- a/cmd/mem.c
+++ b/cmd/mem.c
@@ -818,8 +818,8 @@
 	 *
 	 * Returns:     0 if the test succeeds, 1 if the test fails.
 	 */
-	pattern = (vu_long) 0xaaaaaaaa;
-	anti_pattern = (vu_long) 0x55555555;
+	pattern = (vu_long)0xaaaaaaaaaaaaaaaa;
+	anti_pattern = (vu_long)0x5555555555555555;
 
 	debug("%s:%d: length = 0x%.8lx\n", __func__, __LINE__, num_words);
 	/*
@@ -970,7 +970,7 @@
 
 	max = sizeof(unsigned long) * 8;
 	for (k = 0; k < max; k++) {
-		q = 0x00000001L << k;
+		q = 1UL << k;
 		for (j = 0; j < 8; j++) {
 			schedule();
 			q = ~q;
@@ -1009,6 +1009,7 @@
 	ulong errs = 0;
 	ulong incr, length;
 	ulong val, readback;
+	const int plen = 2 * sizeof(ulong);
 
 	/* Alternate the pattern */
 	incr = 1;
@@ -1020,17 +1021,17 @@
 		 * the "negative" patterns and increment the "positive"
 		 * patterns to preserve this feature.
 		 */
-		if (pattern & 0x80000000)
+		if (pattern > (ulong)LONG_MAX)
 			pattern = -pattern;	/* complement & increment */
 		else
 			pattern = ~pattern;
 	}
 	length = (end_addr - start_addr) / sizeof(ulong);
 	end = buf + length;
-	printf("\rPattern %08lX  Writing..."
+	printf("\rPattern %0*lX  Writing..."
 		"%12s"
 		"\b\b\b\b\b\b\b\b\b\b",
-		pattern, "");
+		plen, pattern, "");
 
 	for (addr = buf, val = pattern; addr < end; addr++) {
 		schedule();
@@ -1046,10 +1047,9 @@
 		if (readback != val) {
 			ulong offset = addr - buf;
 
-			printf("\nMem error @ 0x%08X: "
-				"found %08lX, expected %08lX\n",
-				(uint)(uintptr_t)(start_addr + offset*sizeof(vu_long)),
-				readback, val);
+			printf("\nMem error @ 0x%0*lX: found %0*lX, expected %0*lX\n",
+			       plen, start_addr + offset * sizeof(vu_long),
+			       plen, readback, plen, val);
 			errs++;
 			if (ctrlc())
 				return -1;
@@ -1135,11 +1135,7 @@
 
 	unmap_sysmem((void *)buf);
 
-	if (errs == -1UL) {
-		/* Memory test was aborted - write a newline to finish off */
-		putc('\n');
-	}
-	printf("Tested %d iteration(s) with %lu errors.\n", iteration, count);
+	printf("\nTested %d iteration(s) with %lu errors.\n", iteration, count);
 
 	return errs != 0;
 }
diff --git a/doc/board/kontron/sl-mx8mm.rst b/doc/board/kontron/sl-mx8mm.rst
index f022e09..702db60 100644
--- a/doc/board/kontron/sl-mx8mm.rst
+++ b/doc/board/kontron/sl-mx8mm.rst
@@ -9,7 +9,7 @@
 The matching evaluation boards (Board-Line, BL) have two Ethernet ports,
 USB 2.0, HDMI/LVDS, SD card, CAN, RS485, RS232 and much more.
 
-The OSM-S i.MX8MM is compliant to the Open Standard Module (OSM) 1.0
+The OSM-S i.MX8MM is compliant to the Open Standard Module (OSM) 1.1
 specification, size S (https://sget.org/standards/osm).
 
 Quick Start
@@ -20,25 +20,38 @@
 - Build U-Boot
 - Boot
 
+.. note::
+
+   To build on a x86-64 host machine, you need a GNU cross toolchain for the
+   target architecture (aarch64). Check your distros package manager or
+   download and install the necessary tools (``aarch64-linux-gnu-*``) manually.
+
 Get and Build the Trusted Firmware-A (TF-A)
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
-Note: builddir is U-Boot build directory (source directory for in-tree builds)
-
 There are two sources for the TF-A. Mainline and NXP. Get the one you prefer
 (support and features might differ).
 
+.. note::
+
+   If you are using GCC 12 and you get compiler/linker errors, try to add the
+   following arguments to your make command as workaround:
+   ``CFLAGS="-Wno-array-bounds" LDFLAGS="--no-warn-rwx-segments"``
+
 **NXP's imx-atf**
 
-1. Get TF-A from: https://source.codeaurora.org/external/imx/imx-atf, branch: imx_5.4.70_2.3.0
-2. Apply the patch to select the correct UART for the console, otherwise the TF-A will lock up during boot.
-3. Build
+1. Get TF-A from: https://github.com/nxp-imx/imx-atf, branch: lf_v2.6
+2. Build
 
   .. code-block:: bash
 
-     $ make PLAT=imx8mm bl31
+     $ make PLAT=imx8mm CROSS_COMPILE=aarch64-linux-gnu- IMX_BOOT_UART_BASE="0x30880000" bl31
      $ cp build/imx8mm/release/bl31.bin $(builddir)
 
+.. note::
+
+    *builddir* is U-Boot's build directory (source directory for in-tree builds)
+
 **Mainline TF-A**
 
 1. Get TF-A from: https://git.trustedfirmware.org/TF-A/trusted-firmware-a.git/, tag: v2.4
@@ -54,10 +67,13 @@
 
 .. code-block:: bash
 
-   $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.9.bin
-   $ chmod +x firmware-imx-8.9.bin
-   $ ./firmware-imx-8.9.bin
-   $ cp firmware-imx-8.9/firmware/ddr/synopsys/lpddr4*.bin $(builddir)
+   $ wget https://www.nxp.com/lgfiles/NMG/MAD/YOCTO/firmware-imx-8.18.bin
+   $ chmod +x firmware-imx-8.18.bin
+   $ ./firmware-imx-8.18.bin
+   $ cp firmware-imx-8.18/firmware/ddr/synopsys/lpddr4_pmu_train_1d_imem.bin $(builddir)
+   $ cp firmware-imx-8.18/firmware/ddr/synopsys/lpddr4_pmu_train_1d_dmem.bin $(builddir)
+   $ cp firmware-imx-8.18/firmware/ddr/synopsys/lpddr4_pmu_train_2d_imem.bin $(builddir)
+   $ cp firmware-imx-8.18/firmware/ddr/synopsys/lpddr4_pmu_train_2d_dmem.bin $(builddir)
 
 Build U-Boot
 ^^^^^^^^^^^^
@@ -65,9 +81,9 @@
 .. code-block:: bash
 
    $ make kontron-sl-mx8mm_defconfig
-   $ make
+   $ make CROSS_COMPILE=aarch64-linux-gnu-
 
-Burn the flash.bin to SD card at an offset of 33 KiB:
+Copy the flash.bin to SD card at an offset of 33 KiB:
 
 .. code-block:: bash
 
@@ -76,7 +92,39 @@
 Boot
 ^^^^
 
+Put the SD card in the slot on the board and apply power. Check the serial
+console for output.
+
+Flash the Bootloader to SPI NOR
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+1. Determine and note the exact size of the ``flash.bin`` image in bytes (e.g.
+   by running ``ls -l flash.bin``)
+
+2. On the U-Boot CLI copy the bootloader from SD card to RAM:
+
+   .. code-block::
+
+      mmc dev 1
+      mmc read $loadaddr 0x42 0x1000
+
+3. Erase the SPI NOR flash:
+
+   .. code-block::
+
+      sf probe
+      sf erase 0x0 0x200000
+
+4. Copy the bootloader from RAM to SPI NOR. For the last parameter of the
+   command, use the size determined in step 1 in **hexadecimal notation**:
+
+   .. code-block::
+
+      sf write $loadaddr 0x400 0x13B6F0
+
+.. note::
+
-Put the SD card in the slot on the board and apply power.
+   To be able to boot from SPI NOR the OTP fuses need to be set accordingly.
 
 Further Information
 -------------------
diff --git a/doc/board/st/stm32mp1.rst b/doc/board/st/stm32mp1.rst
index 3f70634..c0b1daa 100644
--- a/doc/board/st/stm32mp1.rst
+++ b/doc/board/st/stm32mp1.rst
@@ -478,7 +478,8 @@
   +-------+--------+---------+------------------------+------------------------+
 
 And the 4th partition (Rootfs) is marked bootable with a file extlinux.conf
-following the Generic Distribution feature (doc/develop/distro.rst for use).
+following the Generic Distribution feature (see :doc:`../../develop/distro` for
+use).
 
 The size of fip or ssbl partition must be enough for the associated binary file,
 4MB and 2MB are default values.
diff --git a/doc/build/index.rst b/doc/build/index.rst
index dc9cde4..64e6649 100644
--- a/doc/build/index.rst
+++ b/doc/build/index.rst
@@ -9,6 +9,7 @@
    source
    gcc
    clang
+   reproducible
    docker
    tools
    buildman
diff --git a/doc/build/reproducible.rst b/doc/build/reproducible.rst
new file mode 100644
index 0000000..5423080
--- /dev/null
+++ b/doc/build/reproducible.rst
@@ -0,0 +1,25 @@
+Reproducible builds
+===================
+
+In order to achieve reproducible builds, timestamps used in the U-Boot build
+process have to be set to a fixed value.
+
+This is done using the SOURCE_DATE_EPOCH environment variable which specifies
+the number of seconds since 1970-01-01T00:00:00Z.
+
+Example
+-------
+
+To build the sandbox with 2023-01-01T00:00:00Z as timestamp we can use:
+
+.. code-block:: bash
+
+    make sandbox_defconfig
+    SOURCE_DATE_EPOCH=1672531200 make
+
+This date is shown when we launch U-Boot:
+
+.. code-block:: console
+
+    ./u-boot -T
+    U-Boot 2023.01 (Jan 01 2023 - 00:00:00 +0000)
diff --git a/doc/develop/directories.rst b/doc/develop/directories.rst
new file mode 100644
index 0000000..112b565
--- /dev/null
+++ b/doc/develop/directories.rst
@@ -0,0 +1,76 @@
+Directory hierarchy
+===================
+
+.. list-table::
+   :header-rows: 1
+
+   * - Directory path
+     - Usage
+   * - /arch
+     - Architecture-specific files
+   * - /arch/arc
+     - Files relating to ARC architecture
+   * - /arch/arm
+     - Files relating to ARM architecture
+   * - /arch/m68k
+     - Files relating to m68k architecture
+   * - /arch/microblaze
+     - Files relating to microblaze architecture
+   * - /arch/mips
+     - Files relating to MIPS architecture
+   * - /arch/nios2
+     - Files relating to Altera NIOS2 architecture
+   * - /arch/powerpc
+     - Files relating to PowerPC architecture
+   * - /arch/riscv
+     - Files relating to RISC-V architecture
+   * - /arch/sandbox
+     - Files relating to HW-independent "sandbox"
+   * - /arch/sh
+     - Files relating to SH architecture
+   * - /arch/x86
+     - Files relating to x86 architecture
+   * - /arch/xtensa
+     - Files relating to Xtensa architecture
+   * - /api
+     - Machine/arch-independent API for external apps
+   * - /board
+     - Board-dependent files
+   * - /boot
+     - Support for images and booting
+   * - /cmd
+     - U-Boot commands functions
+   * - /common
+     - Misc architecture-independent functions
+   * - /configs
+     - Board default configuration files
+   * - /disk
+     - Code for disk drive partition handling
+   * - /doc
+     - Documentation (a mix of ReST and READMEs)
+   * - /drivers
+     - Device drivers
+   * - /dts
+     - Makefile for building internal U-Boot fdt.
+   * - /env
+     - Environment support
+   * - /examples
+     - Example code for standalone applications, etc.
+   * - /fs
+     - Filesystem code (cramfs, ext2, jffs2, etc.)
+   * - /include
+     - Header Files
+   * - /lib
+     - Library routines relating to all architectures
+   * - /Licenses
+     - Various license files
+   * - /net
+     - Networking code
+   * - /post
+     - Power On Self Test
+   * - /scripts
+     - Various build scripts and Makefiles
+   * - /test
+     - Various unit test files
+   * - /tools
+     - Tools to build and sign FIT images, etc.
diff --git a/doc/develop/event.rst b/doc/develop/event.rst
index 6951ec9..4ff5934 100644
--- a/doc/develop/event.rst
+++ b/doc/develop/event.rst
@@ -64,3 +64,26 @@
 
     nm u-boot |grep evspy |grep list
     00000000002d6300 D _u_boot_list_2_evspy_info_2_EVT_MISC_INIT_F
+
+Logging is also available. Events use category `LOGC_EVENT`, so you can enable
+logging on that, or add `#define LOG_DEBUG` to the top of `common/event.c` to
+see events being sent.
+
+
+Dynamic events
+--------------
+
+Static events provide a way of dealing with events known at build time. In some
+cases we want to attach an event handler at runtime. For example, we may wish
+to be notified when a particular device is probed or removed.
+
+This can be handled by enabling `CONFIG_EVENT_DYNAMIC`. It is then possible to
+call `event_register()` to register a new handler for a particular event.
+
+Dynamic event handlers are called after all the static event spy handlers have
+been processed. Of course, since dynamic event handlers are created at runtime
+it is not possible to use the `event_dump.py` to see them.
+
+At present there is no way to list dynamic event handlers from the command line,
+nor to deregister a dynamic event handler. These features can be added when
+needed.
diff --git a/doc/develop/index.rst b/doc/develop/index.rst
index 79d7736..a52ad63 100644
--- a/doc/develop/index.rst
+++ b/doc/develop/index.rst
@@ -24,6 +24,7 @@
 .. toctree::
    :maxdepth: 1
 
+   directories
    bloblist
    bootstd
    ci_testing
diff --git a/doc/mkeficapsule.1 b/doc/mkeficapsule.1
index 6fb2dd0..1ca245a 100644
--- a/doc/mkeficapsule.1
+++ b/doc/mkeficapsule.1
@@ -11,22 +11,23 @@
 .RI [ options ] " " [ image-blob ] " " capsule-file
 
 .SH "DESCRIPTION"
+The
 .B mkeficapsule
-command is used to create an EFI capsule file for use with the U-Boot
-EFI capsule update.
-A capsule file may contain various type of firmware blobs which
-are to be applied to the system and must be placed in the specific
-directory on the UEFI system partition.
-An update will be automatically executed at next reboot.
+command is used to create an EFI capsule file to be used by U-Boot for firmware
+updates.
+A capsule file may contain various types of firmware blobs which are to be
+applied to the system.
+If a capsule file is placed in the /EFI/CapusuleUpdate directory of the EFI
+system partition, U-Boot will try to execute the update at the next reboot.
 
 Optionally, a capsule file can be signed with a given private key.
 In this case, the update will be authenticated by verifying the signature
 before applying.
 
-Additionally, an empty capsule file can be generated for acceptance or
-rejection of firmware images by a governing component like an Operating
-System. The empty capsules do not require an image-blob input file.
-
+Additionally, an empty capsule file can be generated to indicate the acceptance
+or rejection of firmware images by a governing component like an operating
+system.
+Empty capsules do not require an image-blob input file.
 
 .B mkeficapsule
 takes any type of image files when generating non empty capsules, including:
diff --git a/doc/usage/cmd/bdinfo.rst b/doc/usage/cmd/bdinfo.rst
index 6b3cde2..b287d0f 100644
--- a/doc/usage/cmd/bdinfo.rst
+++ b/doc/usage/cmd/bdinfo.rst
@@ -17,7 +17,7 @@
 The *bdinfo* command prints information about the board.
 
 Example
-=======
+-------
 
 ::
 
diff --git a/doc/usage/cmd/font.rst b/doc/usage/cmd/font.rst
index 6fb0823..8ba149d 100644
--- a/doc/usage/cmd/font.rst
+++ b/doc/usage/cmd/font.rst
@@ -12,33 +12,27 @@
     font select <name> [<size>]
     font size <size>
 
-
 Description
 -----------
 
 The *font* command allows selection of the font to use on the video console.
-This is available when the Truetype console is in use. This is the case when
-`CONFIG_CONSOLE_TRUETYPE` is enabled.
-
+This is available when the TrueType console is in use.
 
 font list
 ~~~~~~~~~
 
 This lists the available fonts, using the name of the font file in the build.
 
-
 font select
 ~~~~~~~~~~~
 
 This selects a new font and optionally changes the size.
 
-
 font size
 ~~~~~~~~~
 
 This changes the font size only.
 
-
 Examples
 --------
 
@@ -50,3 +44,14 @@
     => font size 40
     => font select cantoraone_regular 20
     =>
+
+Configuration
+-------------
+
+The command is only available if CONFIG_CONSOLE_TRUETYPE=y.
+
+Return value
+------------
+
+The return value $? is 0 (true) if the command completes.
+The return value is 1 (false) if the command fails.
diff --git a/doc/usage/cmd/mtest.rst b/doc/usage/cmd/mtest.rst
new file mode 100644
index 0000000..81d1f8f
--- /dev/null
+++ b/doc/usage/cmd/mtest.rst
@@ -0,0 +1,66 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2022, Heinrich Schuchardt <xypron.glpk@gmx.de>
+
+mtest command
+=============
+
+Synopsis
+--------
+
+::
+
+    mtest [start [end [pattern [iterations]]]]
+
+Description
+-----------
+
+The *mtest* command tests the random access memory. It writes long values, reads
+them back and checks for differences. The test can be interrupted with CTRL+C.
+
+The default test uses *pattern* as first value to be written and varies it
+between memory addresses.
+
+An alternative test can be selected with CONFIG_SYS_ALT_MEMTEST=y. It uses
+multiple hard coded bit patterns.
+
+With CONFIGSYS_ALT_MEMTEST_BITFLIP=y a further test is executed. It writes long
+values offset by half the size of long and checks if writing to the one address
+causes bit flips at the other address.
+
+start
+	start address of the memory range tested, defaults to
+	CONFIG_SYS_MEMTEST_START
+
+end
+	end address of the memory range tested, defaults to
+	CONFIG_SYS_MEMTEST_END. If CONFIGSYS_ALT_MEMTEST_BITFLIP=y, a value will
+	be written to this address. Otherwise it is excluded from the range.
+
+pattern
+	pattern to be written to memory. This is a 64bit value on 64bit systems
+	and a 32bit value on 32bit systems. It defaults to 0. The value is
+	ignored if CONFIG_SYS_ALT_MEMTEST=y.
+
+iterations
+	number of test repetitions. If the value is not provided the test will
+	not terminate automatically. Enter CTRL+C instead.
+
+Examples
+--------
+
+::
+
+    => mtest 1000 2000 0x55aa55aa55aa55aa 10
+    Testing 00001000 ... 00002000:
+    Pattern AA55AA55AA55AA55  Writing...  Reading...
+    Tested 16 iteration(s) with 0 errors.
+
+Configuration
+-------------
+
+The mtest command is enabled by CONFIG_CMD_MEMTEST=y.
+
+Return value
+------------
+
+The return value $? is 0 (true) if the command succeeds, 1 (false) otherwise.
diff --git a/doc/usage/cmd/sleep.rst b/doc/usage/cmd/sleep.rst
new file mode 100644
index 0000000..d19e5b3
--- /dev/null
+++ b/doc/usage/cmd/sleep.rst
@@ -0,0 +1,45 @@
+.. SPDX-License-Identifier: GPL-2.0+
+.. Copyright 2023, Heinrich Schuchardt <heinrich.schuchardt@canonical.com>
+
+sleep command
+=============
+
+Synopsis
+--------
+
+::
+
+    sleep <delay>
+
+Description
+-----------
+
+The *sleep* command waits for *delay* seconds. It can be interrupted by
+CTRL+C.
+
+delay
+   delay in seconds. The value is decimal and can be fractional.
+
+Example
+-------
+
+The current data and time is display before and after sleeping for 3.2
+seconds:
+
+::
+
+    => date; sleep 3.2; date
+    Date: 2023-01-21 (Saturday)    Time: 16:02:41
+    Date: 2023-01-21 (Saturday)    Time: 16:02:44
+    =>
+
+Configuration
+-------------
+
+The command is only available if CONFIG_CMD_SLEEP=y.
+
+Return value
+------------
+
+The return value $? is 0 (true) if the command completes.
+The return value is 1 (false) if the command is interrupted by CTRL+C.
diff --git a/doc/usage/index.rst b/doc/usage/index.rst
index 7d4a1cb..2c95471 100644
--- a/doc/usage/index.rst
+++ b/doc/usage/index.rst
@@ -63,6 +63,7 @@
    cmd/mbr
    cmd/md
    cmd/mmc
+   cmd/mtest
    cmd/part
    cmd/pause
    cmd/pinmux
@@ -76,6 +77,7 @@
    cmd/scp03
    cmd/setexpr
    cmd/size
+   cmd/sleep
    cmd/sound
    cmd/source
    cmd/temperature
diff --git a/include/efi_config.h b/include/efi_config.h
index fd69926..e5edbb5 100644
--- a/include/efi_config.h
+++ b/include/efi_config.h
@@ -9,12 +9,14 @@
 #define _EFI_CONFIG_H
 
 #include <efi_loader.h>
+#include <menu.h>
 
-#define EFICONFIG_ENTRY_NUM_MAX 99
+#define EFICONFIG_ENTRY_NUM_MAX INT_MAX
 #define EFICONFIG_VOLUME_PATH_MAX 512
 #define EFICONFIG_FILE_PATH_MAX 512
 #define EFICONFIG_FILE_PATH_BUF_SIZE (EFICONFIG_FILE_PATH_MAX * sizeof(u16))
 
+extern const char *eficonfig_menu_desc;
 typedef efi_status_t (*eficonfig_entry_func)(void *data);
 
 /**
@@ -45,14 +47,20 @@
  * @active:		active menu entry index
  * @count:		total count of menu entry
  * @menu_header:	menu header string
+ * @menu_desc:		menu description string
  * @list:		menu entry list structure
+ * @start:		top menu index to draw
+ * @end:		bottom menu index to draw
  */
 struct efimenu {
 	int delay;
 	int active;
 	int count;
 	char *menu_header;
+	const char *menu_desc;
 	struct list_head list;
+	int start;
+	int end;
 };
 
 /**
@@ -86,9 +94,16 @@
 };
 
 void eficonfig_print_msg(char *msg);
+void eficonfig_print_entry(void *data);
+void eficonfig_display_statusline(struct menu *m);
+char *eficonfig_choice_entry(void *data);
 void eficonfig_destroy(struct efimenu *efi_menu);
 efi_status_t eficonfig_process_quit(void *data);
-efi_status_t eficonfig_process_common(struct efimenu *efi_menu, char *menu_header);
+efi_status_t eficonfig_process_common(struct efimenu *efi_menu,
+				      char *menu_header, const char *menu_desc,
+				      void (*display_statusline)(struct menu *),
+				      void (*item_data_print)(void *),
+				      char *(*item_choice)(void *));
 efi_status_t eficonfig_process_select_file(void *data);
 efi_status_t eficonfig_get_unused_bootoption(u16 *buf,
 					     efi_uintn_t buf_size, u32 *index);
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f9e427f..4560b0d 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -328,6 +328,7 @@
 extern const efi_guid_t smbios_guid;
 /*GUID of console */
 extern const efi_guid_t efi_guid_text_input_protocol;
+extern const efi_guid_t efi_guid_text_output_protocol;
 
 extern char __efi_runtime_start[], __efi_runtime_stop[];
 extern char __efi_runtime_rel_start[], __efi_runtime_rel_stop[];
diff --git a/include/spl.h b/include/spl.h
index fb8c279..827bd25 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -535,7 +535,7 @@
 void __noreturn jump_to_image_linux(struct spl_image_info *spl_image);
 
 /**
- * jump_to_image_linux() - Jump to OP-TEE OS from SPL
+ * jump_to_image_optee() - Jump to OP-TEE OS from SPL
  *
  * This jumps into OP-TEE OS using the information in @spl_image.
  *
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index e65ca6a..ba28989 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1949,6 +1949,7 @@
 	efi_uintn_t buffer_size;
 	uint64_t addr, pages;
 	const efi_guid_t *guid;
+	struct efi_handler *handler;
 
 	/* In case of failure nothing is returned */
 	*buffer = NULL;
@@ -1970,11 +1971,11 @@
 	}
 	if (ret != EFI_SUCCESS)
 		return EFI_NOT_FOUND;
-	ret = EFI_CALL(efi_handle_protocol(device, guid,
-					   (void **)&load_file_protocol));
+	ret = efi_search_protocol(device, guid, &handler);
 	if (ret != EFI_SUCCESS)
 		return EFI_NOT_FOUND;
 	buffer_size = 0;
+	load_file_protocol = handler->protocol_interface;
 	ret = EFI_CALL(load_file_protocol->load_file(
 					load_file_protocol, rem, boot_policy,
 					&buffer_size, NULL));
diff --git a/lib/efi_loader/efi_esrt.c b/lib/efi_loader/efi_esrt.c
index dcc08a6..7f46d65 100644
--- a/lib/efi_loader/efi_esrt.c
+++ b/lib/efi_loader/efi_esrt.c
@@ -115,7 +115,7 @@
 	u32 size = efi_esrt_entries_to_size(num_entries);
 	efi_guid_t esrt_guid = efi_esrt_guid;
 
-	/* Reserve num_pages for ESRT */
+	/* Reserve memory for ESRT */
 	ret = efi_allocate_pool(EFI_BOOT_SERVICES_DATA, size,
 				(void **)&new_esrt);