cmd: Update the meminfo command to show the memory map

U-Boot has a fairly rigid memory map which is normally not visible
unless debugging is enabled in board_f.c

Update the 'meminfo' command to show it. This command does not cover
arch-specific pieces but gives a good overview of where things are.

Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/cmd/Kconfig b/cmd/Kconfig
index ec2fe7a..f79fda6 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -889,6 +889,17 @@
 	help
 	  Display memory information.
 
+config CMD_MEMINFO_MAP
+	bool "- with memory map"
+	depends on CMD_MEMINFO
+	default y if SANDBOX
+	help
+	  Shows a memory map, in addition to just the DRAM size. This allows
+	  seeing where U-Boot's memory area is, at the top of DRAM, as well as
+	  detail about each piece of it.
+
+	  See doc/usage/cmd/meminfo.rst for more information.
+
 config CMD_MEMORY
 	bool "md, mm, nm, mw, cp, cmp, base, loop"
 	default y
diff --git a/cmd/meminfo.c b/cmd/meminfo.c
index bb9bcec..0e6d2f9 100644
--- a/cmd/meminfo.c
+++ b/cmd/meminfo.c
@@ -4,18 +4,67 @@
  * Written by Simon Glass <sjg@chromium.org>
  */
 
+#include <bloblist.h>
+#include <bootstage.h>
 #include <command.h>
 #include <display_options.h>
+#include <malloc.h>
+#include <mapmem.h>
 #include <asm/global_data.h>
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static void print_region(const char *name, ulong base, ulong size, ulong *uptop)
+{
+	ulong end = base + size;
+
+	printf("%-12s %8lx %8lx %8lx", name, base, size, end);
+	if (*uptop)
+		printf(" %8lx", *uptop - end);
+	putc('\n');
+	*uptop = base;
+}
+
 static int do_meminfo(struct cmd_tbl *cmdtp, int flag, int argc,
-		       char *const argv[])
+		      char *const argv[])
 {
+	ulong upto, stk_bot;
+
 	puts("DRAM:  ");
 	print_size(gd->ram_size, "\n");
 
+	if (!IS_ENABLED(CONFIG_CMD_MEMINFO_MAP))
+		return 0;
+
+	printf("\n%-12s %8s %8s %8s %8s\n", "Region", "Base", "Size", "End",
+	       "Gap");
+	printf("------------------------------------------------\n");
+	upto = 0;
+	if (IS_ENABLED(CONFIG_VIDEO))
+		print_region("video", gd_video_bottom(),
+			     gd_video_size(), &upto);
+	if (IS_ENABLED(CONFIG_TRACE))
+		print_region("trace", map_to_sysmem(gd_trace_buff()),
+			     gd_trace_size(), &upto);
+	print_region("code", gd->relocaddr, gd->mon_len, &upto);
+	print_region("malloc", map_to_sysmem((void *)mem_malloc_start),
+		     mem_malloc_end - mem_malloc_start, &upto);
+	print_region("board_info", map_to_sysmem(gd->bd),
+		     sizeof(struct bd_info), &upto);
+	print_region("global_data", map_to_sysmem((void *)gd),
+		     sizeof(struct global_data), &upto);
+	print_region("devicetree", map_to_sysmem(gd->fdt_blob),
+		     fdt_totalsize(gd->fdt_blob), &upto);
+	if (IS_ENABLED(CONFIG_BOOTSTAGE))
+		print_region("bootstage", map_to_sysmem(gd_bootstage()),
+			     bootstage_get_size(false), &upto);
+	if (IS_ENABLED(CONFIG_BLOBLIST))
+		print_region("bloblist", map_to_sysmem(gd_bloblist()),
+			     bloblist_get_total_size(), &upto);
+	stk_bot = gd->start_addr_sp - CONFIG_STACK_SIZE;
+	print_region("stack", stk_bot, CONFIG_STACK_SIZE, &upto);
+	print_region("free", gd->ram_base, stk_bot, &upto);
+
 	return 0;
 }