Sorry, pls ping Thanks, Arseniy
On 08.01.2024 21:33, Arseniy Krasnov wrote: > Sorry, pls ping > > Thanks, Arseniy > > On 20.12.2023 22:36, Arseniy Krasnov wrote: >> Add access to OTP region. It supports info, dump, write and lock >> operations. >> >> Signed-off-by: Arseniy Krasnov <avkras...@salutedevices.com> >> --- >> Changelog: >> v1 -> v2: >> * Remove warning that OTP can't be erased after write. >> >> cmd/Kconfig | 1 + >> cmd/mtd.c | 224 ++++++++++++++++++++++++++++++++++++++++++++++++++++ >> 2 files changed, 225 insertions(+) >> >> diff --git a/cmd/Kconfig b/cmd/Kconfig >> index 90e4ef93e0..c47523a03b 100644 >> --- a/cmd/Kconfig >> +++ b/cmd/Kconfig >> @@ -1354,6 +1354,7 @@ config CMD_MTD >> bool "mtd" >> depends on MTD >> select MTD_PARTITIONS >> + select HEXDUMP >> help >> MTD commands support. >> >> diff --git a/cmd/mtd.c b/cmd/mtd.c >> index eb6e2d6892..1ab69b108b 100644 >> --- a/cmd/mtd.c >> +++ b/cmd/mtd.c >> @@ -11,6 +11,7 @@ >> #include <command.h> >> #include <common.h> >> #include <console.h> >> +#include <hexdump.h> >> #include <malloc.h> >> #include <mapmem.h> >> #include <mtd.h> >> @@ -202,6 +203,219 @@ static bool mtd_oob_write_is_empty(struct mtd_oob_ops >> *op) >> return true; >> } >> >> +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, %lu 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%zx\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; >> +} >> + >> static int do_mtd_list(struct cmd_tbl *cmdtp, int flag, int argc, >> char *const argv[]) >> { >> @@ -552,6 +766,10 @@ static char mtd_help_text[] = >> "\n" >> "Specific functions:\n" >> "mtd bad <name>\n" >> + "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" >> "\n" >> "With:\n" >> "\t<name>: NAND partition/chip name (or corresponding DM device name or >> OF path)\n" >> @@ -562,11 +780,17 @@ static char mtd_help_text[] = >> "\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" >> + "\t<hex string>: hex string without '0x' and spaces. Example: >> ABCD1234\n" >> + "\t[u|f]: user or factory OTP region\n" >> "\n" >> "The .dontskipff option forces writing empty pages, don't use it if >> unsure.\n"; >> #endif >> >> U_BOOT_CMD_WITH_SUBCMDS(mtd, "MTD utils", mtd_help_text, >> + 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), >> U_BOOT_SUBCMD_MKENT(list, 1, 1, do_mtd_list), >> U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io, >> mtd_name_complete),