Sorry, please ping Thanks, Arseniy
On 11.02.2024 02:16, Arseniy Krasnov wrote: > 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 <[email protected]> >>> --- >>> 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),

