From: Simona Toaca <[email protected]> This command exposes 3 methods: - check -> checks if the data in volatile memory is valid - 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]> --- arch/arm/mach-imx/Kconfig | 8 ++ arch/arm/mach-imx/Makefile | 1 + arch/arm/mach-imx/cmd_qb.c | 132 ++++++++++++++++++++++++++++++++ arch/arm/mach-imx/imx9/Makefile | 4 +- 4 files changed, 144 insertions(+), 1 deletion(-) create mode 100644 arch/arm/mach-imx/cmd_qb.c diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig index e4014226582..17aad696648 100644 --- a/arch/arm/mach-imx/Kconfig +++ b/arch/arm/mach-imx/Kconfig @@ -71,6 +71,14 @@ config CSF_SIZE Define the maximum size for Command Sequence File (CSF) binary this information is used to define the image boot data. +config CMD_IMX_QB + bool "Support the 'qb' command" + default y + depends on IMX_SNPS_DDR_PHY_QB_GEN && (IMX95 || IMX94) + help + Enable qb command to write DDR quick boot training data + to boot device. + 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 0f6e737c0b9..dfa9eca43eb 100644 --- a/arch/arm/mach-imx/Makefile +++ b/arch/arm/mach-imx/Makefile @@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_BMODE) += cmd_bmode.o obj-$(CONFIG_CMD_HDMIDETECT) += cmd_hdmidet.o obj-$(CONFIG_CMD_DEKBLOB) += cmd_dek.o obj-$(CONFIG_CMD_NANDBCB) += cmd_nandbcb.o +obj-$(CONFIG_CMD_IMX_QB) += cmd_qb.o endif ifeq ($(CONFIG_XPL_BUILD),y) diff --git a/arch/arm/mach-imx/cmd_qb.c b/arch/arm/mach-imx/cmd_qb.c new file mode 100644 index 00000000000..9e4532bc84c --- /dev/null +++ b/arch/arm/mach-imx/cmd_qb.c @@ -0,0 +1,132 @@ +// 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 int get_board_boot_device(enum boot_device dev) +{ + switch (dev) { + case SD1_BOOT: + case MMC1_BOOT: + return BOOT_DEVICE_MMC1; + case SD2_BOOT: + case MMC2_BOOT: + return BOOT_DEVICE_MMC2; + case USB_BOOT: + return BOOT_DEVICE_BOARD; + case QSPI_BOOT: + return BOOT_DEVICE_SPI; + default: + return BOOT_DEVICE_NONE; + } +} + +static void parse_qb_args(int argc, char * const argv[], + int *qb_dev, int qb_bootdev) +{ + long dev = -1; + char *interface = ""; + + if (argc >= 2) { + interface = argv[1]; + } else { + /** qb save -> use boot device */ + *qb_dev = qb_bootdev; + } + + if (argc == 3) + dev = simple_strtol(argv[2], NULL, 10); + + if (!strcmp(interface, "mmc") && dev >= 0 && + dev <= (BOOT_DEVICE_MMC2_2 - BOOT_DEVICE_MMC1)) + *qb_dev = BOOT_DEVICE_MMC1 + dev; + + if (!strcmp(interface, "spi")) + *qb_dev = BOOT_DEVICE_SPI; +} + +static int do_qb(struct cmd_tbl *cmdtp, int flag, int argc, + char * const argv[], bool save) +{ + int ret = CMD_RET_FAILURE; + enum boot_device boot_dev = UNKNOWN_BOOT; + int qb_dev = BOOT_DEVICE_NONE, qb_bootdev; + + boot_dev = get_boot_device(); + qb_bootdev = get_board_boot_device(boot_dev); + + parse_qb_args(argc, argv, &qb_dev, qb_bootdev); + + ret = qb(qb_dev, qb_bootdev, save); + + return ret ? CMD_RET_FAILURE : CMD_RET_SUCCESS; +} + +static int do_qb_check(struct cmd_tbl *cmdtp, int flag, + int argc, char * const argv[]) +{ + return 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("%s cp is null\n", __func__); + return CMD_RET_USAGE; + } + + if (argc > cp->maxargs) { + printf("%s argc(%d) > cp->maxargs(%d)\n", __func__, argc, cp->maxargs); + return CMD_RET_USAGE; + } + + if (flag == CMD_FLAG_REPEAT && !cmd_is_repeatable(cp)) { + printf("%s %s repeat flag set but command is not repeatable\n", + __func__, 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 location => trigger quick boot flow\n" + "qb erase [interface] [dev] - erase quick boot data from NVM location => trigger training flow\n" +); diff --git a/arch/arm/mach-imx/imx9/Makefile b/arch/arm/mach-imx/imx9/Makefile index 3018d128a36..7dee144e0f4 100644 --- a/arch/arm/mach-imx/imx9/Makefile +++ b/arch/arm/mach-imx/imx9/Makefile @@ -15,5 +15,7 @@ obj-y += imx_bootaux.o endif ifeq ($(CONFIG_IMX_SNPS_DDR_PHY_QB_GEN),y) -obj-y += qb.o +ifneq ($(CONFIG_XPL_BUILD),y) +obj-$(CONFIG_CMD_IMX_QB) += qb.o +endif endif -- 2.43.0

