@@ -1732,8 +1732,13 @@ M: Heiko Schocher <hs@denx.de>
S: Maintained
T: git https://source.denx.de/u-boot/custodians/u-boot-ubi.git
F: drivers/mtd/ubi/
+UFETCH
+M: Caleb Connolly <caleb.connolly@linaro.org>
+S: Maintained
+F: cmd/ufetch.c
+
UFS
M: Neil Armstrong <neil.armstrong@linaro.org>
M: Bhupesh Sharma <bhupesh.linux@gmail.com>
M: Neha Malcom Francis <n-francis@ti.com>
@@ -175,8 +175,15 @@ config CMD_CPU
number of CPUs, type (e.g. manufacturer, architecture, product or
internal name) and clock frequency. Other information may be
available depending on the CPU driver.
+config CMD_UFETCH
+ bool "U-Boot fetch"
+ depends on BLK
+ help
+ Fetch utility for U-Boot (akin to neofetch). Prints information
+ about U-Boot and the board it is running on in a pleasing format.
+
config CMD_FWU_METADATA
bool "fwu metadata read"
depends on FWU_MULTI_BANK_UPDATE
help
@@ -52,8 +52,9 @@ obj-$(CONFIG_CMD_CONSOLE) += console.o
obj-$(CONFIG_CMD_CPU) += cpu.o
obj-$(CONFIG_CMD_DATE) += date.o
obj-$(CONFIG_CMD_DEMO) += demo.o
obj-$(CONFIG_CMD_DM) += dm.o
+obj-$(CONFIG_CMD_UFETCH) += ufetch.o
obj-$(CONFIG_CMD_SOUND) += sound.o
ifdef CONFIG_POST
obj-$(CONFIG_CMD_DIAG) += diag.o
endif
new file mode 100644
@@ -0,0 +1,229 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Small "fetch" utility for U-Boot */
+
+#ifdef CONFIG_ARM64
+#include <asm/system.h>
+#endif
+#include <dm/device.h>
+#include <dm/uclass-internal.h>
+#include <display_options.h>
+#include <mmc.h>
+#include <time.h>
+#include <asm/global_data.h>
+#include <cli.h>
+#include <command.h>
+#include <dm/ofnode.h>
+#include <env.h>
+#include <rand.h>
+#include <vsprintf.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <version.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define LINE_WIDTH 40
+#define BLUE "\033[38;5;4m"
+#define YELLOW "\033[38;5;11m"
+#define BOLD "\033[1m"
+#define RESET "\033[0m"
+static const char * const logo_lines[] = {
+ BLUE BOLD " ......::...... ",
+ BLUE BOLD " ...::::::::::::::::::... ",
+ BLUE BOLD " ..::::::::::::::::::::::::::.. ",
+ BLUE BOLD " .::::.:::::::::::::::...::::.::::. ",
+ BLUE BOLD " .::::::::::::::::::::..::::::::::::::. ",
+ BLUE BOLD " .::.:::::::::::::::::::" YELLOW "=*%#*" BLUE "::::::::::.::. ",
+ BLUE BOLD " .:::::::::::::::::....." YELLOW "*%%*-" BLUE ":....::::::::::. ",
+ BLUE BOLD " .:.:::...:::::::::.:-" YELLOW "===##*---==-" BLUE "::::::::::.:. ",
+ BLUE BOLD " .::::..::::........" YELLOW "-***#****###****-" BLUE "...::::::.:. ",
+ BLUE BOLD " ::.:.-" YELLOW "+***+=" BLUE "::-" YELLOW "=+**#%%%%%%%%%%%%###*= " BLUE "-::...::::. ",
+ BLUE BOLD ".:.::-" YELLOW "*****###%%%%%%%%%%%%%%%%%%%%%%%%%%#*=" BLUE ":..:::: ",
+ BLUE BOLD ".::" YELLOW "##" BLUE ":" YELLOW "***#%%%%%%#####%%%%%%%####%%%%%####%%%*" BLUE "-.::. ",
+ BLUE BOLD ":.:" YELLOW "#%" BLUE "::" YELLOW "*%%%%%%%#*****##%%%#*****##%%##*****#%%+" BLUE ".::.",
+ BLUE BOLD ".::" YELLOW "**==#%%%%%%%##****#%%%%##****#%%%%#****###%%" BLUE ":.. ",
+ BLUE BOLD "..:" YELLOW "#%" BLUE "::" YELLOW "*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#%%%%%+ " BLUE ".:.",
+ BLUE BOLD " ::" YELLOW "##" BLUE ":" YELLOW "+**#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%* " BLUE "-.:: ",
+ BLUE BOLD " ..::-" YELLOW "#****#%#%%%%%%%%%%%%%%%%%%%%%%%%%%#*=" BLUE "-..::. ",
+ BLUE BOLD " ...:=" YELLOW "*****=" BLUE "::-" YELLOW "=+**###%%%%%%%%###**+= " BLUE "--:...::: ",
+ BLUE BOLD " .::.::--:........::::::--::::::......::::::. ",
+ BLUE BOLD " .::.....::::::::::...........:::::::::.::. ",
+ BLUE BOLD " .::::::::::::::::::::::::::::::::::::. ",
+ BLUE BOLD " .::::.::::::::::::::::::::::.::::. ",
+ BLUE BOLD " ..::::::::::::::::::::::::::.. ",
+ BLUE BOLD " ...::::::::::::::::::... ",
+ BLUE BOLD " ......::...... ",
+};
+
+enum output_lines {
+ FIRST,
+ SECOND,
+ KERNEL,
+ SYSINFO,
+ HOST,
+ UPTIME,
+ IP,
+ CMDS,
+ CONSOLES,
+ FEATURES,
+ RELOCATION,
+ CORES,
+ MEMORY,
+ STORAGE,
+
+ /* Up to 10 storage devices... Should be enough for anyone right? */
+ _LAST_LINE = (STORAGE + 10),
+#define LAST_LINE (_LAST_LINE - 1UL)
+};
+
+/*
+ * TODO/ideas:
+ * - Refactor to not use a for loop
+ * - Handle multiple network interfaces
+ * - Include stats about number of bound/probed devices
+ * - Show U-Boot's size and malloc usage, fdt size, etc.
+ */
+
+
+static int do_ufetch(struct cmd_tbl *cmdtp, int flag, int argc,
+ char *const argv[])
+{
+ int num_lines = max(LAST_LINE + 1, ARRAY_SIZE(logo_lines));
+ const char *model, *compatible;
+ char *ipaddr;
+ int n_cmds, n_cpus = 0, ret, compatlen;
+ size_t size;
+ ofnode np;
+ struct udevice *dev;
+ struct blk_desc *desc;
+ bool skip_ascii = false;
+
+ if (argc > 1 && strcmp(argv[1], "-n") == 0) {
+ skip_ascii = true;
+ num_lines = LAST_LINE;
+ }
+
+ for (int line = 0; line < num_lines; line++) {
+ if (!skip_ascii) {
+ if (line < ARRAY_SIZE(logo_lines))
+ printf("%s ", logo_lines[line]);
+ else
+ printf("%*c ", LINE_WIDTH, ' ');
+ }
+ switch (line) {
+ case FIRST:
+ compatible = ofnode_read_string(ofnode_root(), "compatible");
+ if (!compatible)
+ compatible = "unknown";
+ printf(RESET "%s\n", compatible);
+ compatlen = strlen(compatible);
+ break;
+ case SECOND:
+ for (int j = 0; j < compatlen; j++)
+ putc('-');
+ putc('\n');
+ break;
+ case KERNEL:
+ printf("Kernel:" RESET " %s\n", U_BOOT_VERSION);
+ break;
+ case SYSINFO:
+ printf("Config:" RESET " %s_defconfig\n", CONFIG_SYS_CONFIG_NAME);
+ break;
+ case HOST:
+ model = ofnode_read_string(ofnode_root(), "model");
+ if (model)
+ printf("Host:" RESET " %s\n", model);
+ break;
+ case UPTIME:
+ printf("Uptime:" RESET " %ld seconds\n", get_timer(0) / 1000);
+ break;
+ case IP:
+ ipaddr = env_get("ipaddr");
+ if (!ipaddr)
+ ipaddr = "none";
+ printf("IP Address:" RESET " %s", ipaddr);
+ ipaddr = env_get("ipv6addr");
+ if (ipaddr)
+ printf(", %s\n", ipaddr);
+ else
+ putc('\n');
+ break;
+ case CMDS:
+ n_cmds = ll_entry_count(struct cmd_tbl, cmd);
+ printf("Commands:" RESET " %d (help)\n", n_cmds);
+ break;
+ case CONSOLES:
+ printf("Consoles:" RESET " %s", env_get("stdout"));
+ if (gd->baudrate)
+ printf(" (%d baud)", gd->baudrate);
+ putc('\n');
+ break;
+ case FEATURES:
+ printf("Features:" RESET " ");
+ if (IS_ENABLED(CONFIG_NET))
+ printf("Net");
+ if (IS_ENABLED(CONFIG_EFI_LOADER))
+ printf(", EFI");
+ if (IS_ENABLED(CONFIG_CMD_CAT))
+ printf(", cat :3");
+#ifdef CONFIG_ARM64
+ switch (current_el()) {
+ case 2:
+ printf(", VMs");
+ break;
+ case 3:
+ printf(", full control!");
+ break;
+ }
+#endif
+ printf("\n");
+ break;
+ case RELOCATION:
+ if (gd->flags & GD_FLG_SKIP_RELOC)
+ printf("Relocated:" RESET " no\n");
+ else
+ printf("Relocated:" RESET " to %#011lx\n", gd->relocaddr);
+ break;
+ case CORES:
+ ofnode_for_each_subnode(np, ofnode_path("/cpus")) {
+ if (ofnode_name_eq(np, "cpu"))
+ n_cpus++;
+ }
+ printf("CPU:" RESET " %d (1 in use)\n", n_cpus);
+ break;
+ case MEMORY:
+ for (int j = 0; j < CONFIG_NR_DRAM_BANKS && gd->bd->bi_dram[j].size; j++)
+ size += gd->bd->bi_dram[j].size;
+ printf("Memory:" RESET " ");
+ print_size(size, "\n");
+ break;
+ case STORAGE:
+ default:
+ ret = uclass_find_device_by_seq(UCLASS_BLK, line - STORAGE, &dev);
+ if (!ret && dev) {
+ desc = dev_get_uclass_plat(dev);
+ size = desc->lba * desc->blksz;
+ printf("%4s %d: " RESET, blk_get_uclass_name(desc->uclass_id),
+ desc->lun);
+ if (size)
+ print_size(size, "");
+ else
+ printf("No media");
+ } else if (ret == -ENODEV && (skip_ascii || line > ARRAY_SIZE(logo_lines))) {
+ break;
+ }
+ printf("\n");
+ }
+ }
+
+ printf(RESET "\n\n");
+
+ return 0;
+}
+
+U_BOOT_CMD(ufetch, 2, 1, do_ufetch,
+ "U-Boot fetch utility",
+ "Print information about your device.\n"
+ " -n Don't print the ASCII logo"
+);
@@ -50,8 +50,9 @@ CONFIG_LOG_DEFAULT_LEVEL=6
CONFIG_LOGF_FUNC=y
CONFIG_DISPLAY_BOARDINFO_LATE=y
CONFIG_STACKPROTECTOR=y
CONFIG_CMD_CPU=y
+CONFIG_CMD_UFETCH=y
CONFIG_CMD_LICENSE=y
CONFIG_CMD_SMBIOS=y
CONFIG_CMD_BOOTM_PRE_LOAD=y
CONFIG_CMD_BOOTZ=y