
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 avkrasnov@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(list, 1, 1, do_mtd_list), U_BOOT_SUBCMD_MKENT_COMPLETE(read, 5, 0, do_mtd_io, mtd_name_complete),U_BOOT_SUBCMD_MKENT(otpinfo, 3, 1, do_mtd_otp_info),