Hi Arseniy, On Tue, Mar 26, 2024 at 11:49 PM Arseniy Krasnov <avkras...@salutedevices.com> wrote: > > Add access to OTP region. It supports info, dump, write and lock > operations. Usage example: > > 'mtd otpread nand0 u 0 1024' - dump 1024 bytes of user area starting > from offset 0 of device 'nand0'. > > 'mtd otpwrite nand0 10 11223344' - write binary data 0x11, 0x22, 0x33, > 0x44 to offset 10 to user area of device 'nand0'. > > 'mtd otplock nand0 0 1024' - lock 1024 bytes of user area starting > from offset 0 of device 'nand0'. > > 'mtd otpinfo nand0 f' - show info about factory area of device 'nand0'. > > Signed-off-by: Arseniy Krasnov <avkras...@salutedevices.com> > --- > Changelog: > v1 -> v2: > * Remove warning that OTP can't be erased after write. > v2 -> v3: > * Commit message updated by adding usage. > * R-b added. > v3 -> v4: > * Fix build failure due to invalid format strings for 'printf()'. > * Rebase over latest version of cmd/mtd.c. > v4 -> v5: > * Implement commands from this patch as config option due to too big > final size of the uboot image. > * R-b removed because of patch update. > > cmd/Kconfig | 7 ++ > cmd/mtd.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 241 insertions(+) > > diff --git a/cmd/Kconfig b/cmd/Kconfig > index 7292a150f5..832098e66e 100644 > --- a/cmd/Kconfig > +++ b/cmd/Kconfig > @@ -1366,6 +1366,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 e63c011e79..c66105e373 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), > -- > 2.35.0 >
Applied to nand-next Thanks and regards Dario -- Dario Binacchi Senior Embedded Linux Developer dario.binac...@amarulasolutions.com __________________________________ Amarula Solutions SRL Via Le Canevare 30, 31100 Treviso, Veneto, IT T. +39 042 243 5310 i...@amarulasolutions.com www.amarulasolutions.com