]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
arm: mach-imx: Add command to expose QB functionality
authorSimona Toaca <simona.toaca@nxp.com>
Thu, 30 Apr 2026 08:33:31 +0000 (11:33 +0300)
committerFabio Estevam <festevam@gmail.com>
Fri, 15 May 2026 20:31:39 +0000 (17:31 -0300)
This command exposes 3 methods:
- check -> checks if the data in volatile memory is valid
   (integrity check)
- save  -> saves the data to non-volatile memory and
   erases the data in volatile memory
- erase -> erases the data in non-volatile memory

cmd_qb can be used either directly in the U-Boot console
or in an uuu script to save the QB data during flashing.
It supports specifying a different boot medium than the
current boot device for saving the data.

Signed-off-by: Viorel Suman <viorel.suman@nxp.com>
Signed-off-by: Ye Li <ye.li@nxp.com>
Signed-off-by: Simona Toaca <simona.toaca@nxp.com>
arch/arm/mach-imx/Kconfig
arch/arm/mach-imx/Makefile
arch/arm/mach-imx/cmd_qb.c [new file with mode: 0644]

index bb62a0cf2f6713ad9fd9828c5b0c554aed3b8965..a40baf246314e1af5e0bd16a64a45a0f8c144729 100644 (file)
@@ -80,6 +80,17 @@ config IMX_QB
          memory to non-volatile storage. OEI uses the saved data to
          run Quickboot flow and skip re-training the DDR PHY.
 
+config CMD_IMX_QB
+       bool "Support the 'qb' command"
+       default y
+       depends on IMX_QB
+       help
+         Enable qb command to write/erase DDR quick boot training
+         data to/from a chosen boot device. Using 'qb save/erase'
+         without arguments implies using the current boot device's
+         first bootable partition (e.g. boot0 for eMMC). For use in
+         uuu scripts, the boot device must be specified explicitly.
+
 config CMD_BMODE
        bool "Support the 'bmode' command"
        default y
index bf6820de655615c85ba91623e3e1d5ef173a64b7..43febc10460f21aef257e6f3aff625d2e1ee38f5 100644 (file)
@@ -80,6 +80,7 @@ endif
 ifneq ($(CONFIG_XPL_BUILD),y)
 obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o
 obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o
+obj-$(CONFIG_CMD_IMX_QB) += cmd_qb.o
 obj-$(CONFIG_CMD_DEKBLOB) += cmd_dek.o
 obj-$(CONFIG_CMD_NANDBCB) += cmd_nandbcb.o
 endif
diff --git a/arch/arm/mach-imx/cmd_qb.c b/arch/arm/mach-imx/cmd_qb.c
new file mode 100644 (file)
index 0000000..633d83d
--- /dev/null
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0+
+/**
+ * Copyright 2024-2026 NXP
+ */
+#include <command.h>
+#include <spl.h>
+#include <stdlib.h>
+
+#include <asm/mach-imx/boot_mode.h>
+#include <asm/mach-imx/sys_proto.h>
+#include <asm/mach-imx/qb.h>
+
+static void parse_qb_args(int argc, char * const argv[],
+                         const char **ifname, const char **dev)
+{
+       /* qb save/erase -> use boot device */
+       if (argc < 2) {
+               *ifname = "auto";
+               return;
+       }
+
+       *ifname = argv[1];
+
+       if (argc == 3)
+               *dev = argv[2];
+}
+
+static int do_qb(struct cmd_tbl *cmdtp, int flag, int argc,
+                char * const argv[], bool save)
+{
+       const char *ifname, *dev;
+
+       parse_qb_args(argc, argv, &ifname, &dev);
+
+       if (imx_qb(ifname, dev, save))
+               return CMD_RET_FAILURE;
+
+       return CMD_RET_SUCCESS;
+}
+
+static int do_qb_check(struct cmd_tbl *cmdtp, int flag,
+                      int argc, char * const argv[])
+{
+       return imx_qb_check() ? CMD_RET_SUCCESS : CMD_RET_FAILURE;
+}
+
+static int do_qb_save(struct cmd_tbl *cmdtp, int flag,
+                     int argc, char * const argv[])
+{
+       return do_qb(cmdtp, flag, argc, argv, true);
+}
+
+static int do_qb_erase(struct cmd_tbl *cmdtp, int flag,
+                      int argc, char * const argv[])
+{
+       return do_qb(cmdtp, flag, argc, argv, false);
+}
+
+static struct cmd_tbl cmd_qb[] = {
+       U_BOOT_CMD_MKENT(check, 1, 1, do_qb_check, "", ""),
+       U_BOOT_CMD_MKENT(save,  3, 1, do_qb_save,  "", ""),
+       U_BOOT_CMD_MKENT(erase, 3, 1, do_qb_erase, "", ""),
+};
+
+static int do_qbops(struct cmd_tbl *cmdtp, int flag, int argc,
+                   char *const argv[])
+{
+       struct cmd_tbl *cp;
+
+       cp = find_cmd_tbl(argv[1], cmd_qb, ARRAY_SIZE(cmd_qb));
+
+       /* Drop the qb command */
+       argc--;
+       argv++;
+
+       if (!cp) {
+               printf("qb: %s: command not found\n", argv[0] ? argv[0] : " ");
+               return CMD_RET_USAGE;
+       }
+
+       if (argc > cp->maxargs) {
+               printf("qb %s: too many arguments: %d > %d\n", cp->name,
+                      argc - 1, cp->maxargs - 1);
+               return CMD_RET_USAGE;
+       }
+
+       if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) {
+               printf("qb %s: repeat flag set but command is not repeatable\n",
+                      cp->name);
+               return CMD_RET_SUCCESS;
+       }
+
+       return cp->cmd(cmdtp, flag, argc, argv);
+}
+
+U_BOOT_CMD(
+       qb, 4, 1, do_qbops,
+       "DDR Quick Boot sub system",
+       "check - check if quick boot data is stored in mem by training flow\n"
+       "qb save [interface] [dev]  - save quick boot data in NVM => trigger quick boot flow\n"
+       "qb erase [interface] [dev] - erase quick boot data from NVM => trigger training flow\n"
+);