diff options
| author | Tom Rini <[email protected]> | 2024-04-14 12:26:42 -0600 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2024-04-14 15:55:14 -0600 |
| commit | 57cb92de7a9d01be1ce72af003651efc80ac67e2 (patch) | |
| tree | eae708f156dfe7002c03cfbd4c87bacf188a8d90 /cmd | |
| parent | 266603d8c39cf4d194e2cfe8d86d870590e150e0 (diff) | |
| parent | 248fc16055858c2028a381bb59e12354c4ae19ea (diff) | |
Merge tag 'u-boot-nand-20240414' of https://source.denx.de/u-boot/custodians/u-boot-nand-flash
The first patch is by Weizhao Ouyang and avoids sf probe crashes.
The second patch is by Arseniy Krasnov and adds basic support for Amlogic
Meson NAND controller on AXG.
The following four patches are by Alexander Dahl and apply some fixes to
drivers/mtd/nand/raw/ and port some changes applied in Linux.
The following patch is by Bruce Suen and adds support for XTX SPINAND.
Finally, the last patch is again by Arseniy Krasnov and adds access to
OTP region, supporting info, dump, write and lock operations.
Diffstat (limited to 'cmd')
| -rw-r--r-- | cmd/Kconfig | 7 | ||||
| -rw-r--r-- | cmd/mtd.c | 234 | ||||
| -rw-r--r-- | cmd/sf.c | 5 |
3 files changed, 244 insertions, 2 deletions
diff --git a/cmd/Kconfig b/cmd/Kconfig index f9f271616d3..8eeb99eea5e 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -1361,6 +1361,13 @@ config CMD_MTD help MTD commands support. +config CMD_MTD_OTP + bool "mtd otp" + depends on CMD_MTD + select HEXDUMP + help + MTD commands for OTP access. + config CMD_MUX bool "mux" depends on MULTIPLEXER diff --git a/cmd/mtd.c b/cmd/mtd.c index 9083a6840ac..9189f45cabd 100644 --- a/cmd/mtd.c +++ b/cmd/mtd.c @@ -11,6 +11,9 @@ #include <command.h> #include <common.h> #include <console.h> +#if CONFIG_IS_ENABLED(CMD_MTD_OTP) +#include <hexdump.h> +#endif #include <malloc.h> #include <mapmem.h> #include <mtd.h> @@ -202,6 +205,221 @@ static bool mtd_oob_write_is_empty(struct mtd_oob_ops *op) return true; } +#if CONFIG_IS_ENABLED(CMD_MTD_OTP) +static int do_mtd_otp_read(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mtd_info *mtd; + size_t retlen; + off_t from; + size_t len; + bool user; + int ret; + u8 *buf; + + if (argc != 5) + return CMD_RET_USAGE; + + if (!strcmp(argv[2], "u")) + user = true; + else if (!strcmp(argv[2], "f")) + user = false; + else + return CMD_RET_USAGE; + + mtd = get_mtd_by_name(argv[1]); + if (IS_ERR_OR_NULL(mtd)) + return CMD_RET_FAILURE; + + from = simple_strtoul(argv[3], NULL, 0); + len = simple_strtoul(argv[4], NULL, 0); + + ret = CMD_RET_FAILURE; + + buf = malloc(len); + if (!buf) + goto put_mtd; + + printf("Reading %s OTP from 0x%lx, %zu bytes\n", + user ? "user" : "factory", from, len); + + if (user) + ret = mtd_read_user_prot_reg(mtd, from, len, &retlen, buf); + else + ret = mtd_read_fact_prot_reg(mtd, from, len, &retlen, buf); + if (ret) { + free(buf); + pr_err("OTP read failed: %d\n", ret); + ret = CMD_RET_FAILURE; + goto put_mtd; + } + + if (retlen != len) + pr_err("OTP read returns %zu, but %zu expected\n", + retlen, len); + + print_hex_dump("", 0, 16, 1, buf, retlen, true); + + free(buf); + + ret = CMD_RET_SUCCESS; + +put_mtd: + put_mtd_device(mtd); + + return ret; +} + +static int do_mtd_otp_lock(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mtd_info *mtd; + off_t from; + size_t len; + int ret; + + if (argc != 4) + return CMD_RET_USAGE; + + mtd = get_mtd_by_name(argv[1]); + if (IS_ERR_OR_NULL(mtd)) + return CMD_RET_FAILURE; + + from = simple_strtoul(argv[2], NULL, 0); + len = simple_strtoul(argv[3], NULL, 0); + + ret = mtd_lock_user_prot_reg(mtd, from, len); + if (ret) { + pr_err("OTP lock failed: %d\n", ret); + ret = CMD_RET_FAILURE; + goto put_mtd; + } + + ret = CMD_RET_SUCCESS; + +put_mtd: + put_mtd_device(mtd); + + return ret; +} + +static int do_mtd_otp_write(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct mtd_info *mtd; + size_t retlen; + size_t binlen; + u8 *binbuf; + off_t from; + int ret; + + if (argc != 4) + return CMD_RET_USAGE; + + mtd = get_mtd_by_name(argv[1]); + if (IS_ERR_OR_NULL(mtd)) + return CMD_RET_FAILURE; + + from = simple_strtoul(argv[2], NULL, 0); + binlen = strlen(argv[3]) / 2; + + ret = CMD_RET_FAILURE; + binbuf = malloc(binlen); + if (!binbuf) + goto put_mtd; + + hex2bin(binbuf, argv[3], binlen); + + printf("Will write:\n"); + + print_hex_dump("", 0, 16, 1, binbuf, binlen, true); + + printf("to 0x%lx\n", from); + + printf("Continue (y/n)?\n"); + + if (confirm_yesno() != 1) { + pr_err("OTP write canceled\n"); + ret = CMD_RET_SUCCESS; + goto put_mtd; + } + + ret = mtd_write_user_prot_reg(mtd, from, binlen, &retlen, binbuf); + if (ret) { + pr_err("OTP write failed: %d\n", ret); + ret = CMD_RET_FAILURE; + goto put_mtd; + } + + if (retlen != binlen) + pr_err("OTP write returns %zu, but %zu expected\n", + retlen, binlen); + + ret = CMD_RET_SUCCESS; + +put_mtd: + free(binbuf); + put_mtd_device(mtd); + + return ret; +} + +static int do_mtd_otp_info(struct cmd_tbl *cmdtp, int flag, int argc, + char *const argv[]) +{ + struct otp_info otp_info; + struct mtd_info *mtd; + size_t retlen; + bool user; + int ret; + + if (argc != 3) + return CMD_RET_USAGE; + + if (!strcmp(argv[2], "u")) + user = true; + else if (!strcmp(argv[2], "f")) + user = false; + else + return CMD_RET_USAGE; + + mtd = get_mtd_by_name(argv[1]); + if (IS_ERR_OR_NULL(mtd)) + return CMD_RET_FAILURE; + + if (user) + ret = mtd_get_user_prot_info(mtd, sizeof(otp_info), &retlen, + &otp_info); + else + ret = mtd_get_fact_prot_info(mtd, sizeof(otp_info), &retlen, + &otp_info); + if (ret) { + pr_err("OTP info failed: %d\n", ret); + ret = CMD_RET_FAILURE; + goto put_mtd; + } + + if (retlen != sizeof(otp_info)) { + pr_err("OTP info returns %zu, but %zu expected\n", + retlen, sizeof(otp_info)); + ret = CMD_RET_FAILURE; + goto put_mtd; + } + + printf("%s OTP region info:\n", user ? "User" : "Factory"); + printf("\tstart: %u\n", otp_info.start); + printf("\tlength: %u\n", otp_info.length); + printf("\tlocked: %u\n", otp_info.locked); + + ret = CMD_RET_SUCCESS; + +put_mtd: + put_mtd_device(mtd); + + return ret; +} +#endif + static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]) { @@ -551,6 +769,12 @@ U_BOOT_LONGHELP(mtd, "\n" "Specific functions:\n" "mtd bad <name>\n" +#if CONFIG_IS_ENABLED(CMD_MTD_OTP) + "mtd otpread <name> [u|f] <off> <size>\n" + "mtd otpwrite <name> <off> <hex string>\n" + "mtd otplock <name> <off> <size>\n" + "mtd otpinfo <name> [u|f]\n" +#endif "\n" "With:\n" "\t<name>: NAND partition/chip name (or corresponding DM device name or OF path)\n" @@ -561,10 +785,20 @@ U_BOOT_LONGHELP(mtd, "\t<size>: length of the operation in bytes (default: the entire device)\n" "\t\t* must be a multiple of a block for erase\n" "\t\t* must be a multiple of a page otherwise (special case: default is a page with dump)\n" +#if CONFIG_IS_ENABLED(CMD_MTD_OTP) + "\t<hex string>: hex string without '0x' and spaces. Example: ABCD1234\n" + "\t[u|f]: user or factory OTP region\n" +#endif "\n" "The .dontskipff option forces writing empty pages, don't use it if unsure.\n"); U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text, +#if CONFIG_IS_ENABLED(CMD_MTD_OTP) + U_BOOT_SUBCMD_MKENT(otpread, 5, 1, do_mtd_otp_read), + U_BOOT_SUBCMD_MKENT(otpwrite, 4, 1, do_mtd_otp_write), + U_BOOT_SUBCMD_MKENT(otplock, 4, 1, do_mtd_otp_lock), + U_BOOT_SUBCMD_MKENT(otpinfo, 3, 1, do_mtd_otp_info), +#endif U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list), U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io, mtd_name_complete), @@ -135,8 +135,9 @@ static int do_spi_flash_probe(int argc, char *const argv[]) } flash = NULL; if (use_dt) { - spi_flash_probe_bus_cs(bus, cs, &new); - flash = dev_get_uclass_priv(new); + ret = spi_flash_probe_bus_cs(bus, cs, &new); + if (!ret) + flash = dev_get_uclass_priv(new); } else { flash = spi_flash_probe(bus, cs, speed, mode); } |
