diff options
| author | Simona Toaca <[email protected]> | 2026-04-30 11:33:31 +0300 |
|---|---|---|
| committer | Fabio Estevam <[email protected]> | 2026-05-15 17:31:39 -0300 |
| commit | 36755f64b34add7b02be8c1845ae089bfc1b934b (patch) | |
| tree | 0b59e3641aa76322fe388fd3c1903787366cd89d | |
| parent | c9a8f673e0b8dc30bd575faae34e0b1f1e42a706 (diff) | |
arm: mach-imx: Add command to expose QB functionality
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 <[email protected]>
Signed-off-by: Ye Li <[email protected]>
Signed-off-by: Simona Toaca <[email protected]>
| -rw-r--r-- | arch/arm/mach-imx/Kconfig | 11 | ||||
| -rw-r--r-- | arch/arm/mach-imx/Makefile | 1 | ||||
| -rw-r--r-- | arch/arm/mach-imx/cmd_qb.c | 102 |
3 files changed, 114 insertions, 0 deletions
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index bb62a0cf2f6..a40baf24631 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -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 diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile index bf6820de655..43febc10460 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -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 index 00000000000..633d83d3abd --- /dev/null +++ b/arch/arm/mach-imx/cmd_qb.c @@ -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" +); |
