[PATCH v2] cmd: mtd: OTP access support

Arseniy Krasnov avkrasnov at salutedevices.com
Wed Mar 13 08:18:27 CET 2024



On 13.03.2024 09:48, Michael Nazzareno Trimarchi wrote:
> Hi
> 
> On Wed, Mar 13, 2024 at 7:43 AM Arseniy Krasnov
> <avkrasnov at salutedevices.com> wrote:
>>
>> 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 <avkrasnov at salutedevices.com>
>>>>> ---
> 
> Please extend the commit message with some example of the usage otherwise

Done in v3

Thanks, Arseniy

> 
> Reviewed-by: Michael Trimarchi <michael at amarulasolutions.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),
> 
> 
> 


More information about the U-Boot mailing list