This is an automated email from Gerrit.

Tarek BOCHKATI (tarek.bouchk...@gmail.com) just uploaded a new patch set to 
Gerrit, which you can find at http://openocd.zylin.com/5537

-- gerrit

commit 8f27a01fd5cb11f15b8db9eacdd70f91ddedfe6b
Author: Tarek BOCHKATI <tarek.bouchk...@gmail.com>
Date:   Sun Mar 22 20:31:22 2020 +0100

    stm32l4x: add OTP support for STM32 G0/G4/L4/L4+/L5/WB/WL devices
    
    this is rework of #5320 started by Andreas then abandoned.
    
    same syntax as in stm32f2x driver:
    
      enable OTP for writing
      > stm32l4x otp 1 enable
    
      write to OTP
      > flash write_bank 1 foo.bin 0
      > flash filld 0x1FFF7000 0xDeadBeafBaadF00d 1
    
      read OTP
      > mdw 0x1FFF7000 4
    
      disable OTP
      > stm32l4x otp 1 disable
    
    Change-Id: Id7d7c163b35d7a3f406dc200d7e2fc293b0675c2
    Signed-off-by: Andreas Bolsch <hyphen0br...@gmail.com>
    Signed-off-by: Tarek BOCHKATI <tarek.bouchk...@gmail.com>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index 85e3739..4fe370b 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -6900,6 +6900,17 @@ the chip identification register, and autoconfigures 
itself.
 flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
 @end example
 
+If you use OTP (One-Time Programmable) memory define it as a second bank
+as per the following example.
+@example
+flash bank $_FLASHNAME stm32l4x 0x1FFF7000 0 0 0 $_TARGETNAME
+@end example
+
+@deffn Command {stm32l4x otp} num 
(@option{enable}|@option{disable}|@option{show})
+Enables or disables OTP write commands for bank @var{num}.
+The @var{num} parameter is a value shown by @command{flash banks}.
+@end deffn
+
 Note that some devices have been found that have a flash size register that 
contains
 an invalid value, to workaround this issue you can override the probed value 
used by
 the flash driver. However, specifying a wrong value might lead to a completely
diff --git a/src/flash/nor/stm32l4x.c b/src/flash/nor/stm32l4x.c
index c964382..871abd4 100644
--- a/src/flash/nor/stm32l4x.c
+++ b/src/flash/nor/stm32l4x.c
@@ -174,6 +174,8 @@ struct stm32l4_part_info {
        const uint32_t flash_regs_base;
        const uint32_t *default_flash_regs;
        const uint32_t fsize_addr;
+       const uint32_t otp_base;
+       const uint32_t otp_size;
 };
 
 struct stm32l4_flash_bank {
@@ -186,6 +188,7 @@ struct stm32l4_flash_bank {
        uint32_t wrpxxr_mask;
        const struct stm32l4_part_info *part_info;
        const uint32_t *flash_regs;
+       bool otp_enabled;
 };
 
 /* human readable list of families this drivers supports (sorted 
alphabetically) */
@@ -262,6 +265,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x435,
@@ -273,6 +278,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x460,
@@ -284,6 +291,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x461,
@@ -295,6 +304,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x462,
@@ -306,6 +317,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x464,
@@ -317,6 +330,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x466,
@@ -328,6 +343,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x468,
@@ -339,6 +356,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x469,
@@ -350,6 +369,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x470,
@@ -361,6 +382,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x471,
@@ -372,6 +395,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x472,
@@ -383,6 +408,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x40022000,
          .default_flash_regs    = stm32l5_ns_flash_regs,
          .fsize_addr            = 0x0BFA05E0,
+         .otp_base              = 0x0BFA0000,
+         .otp_size              = 512,
        },
        {
          .id                    = 0x495,
@@ -394,6 +421,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x58004000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x496,
@@ -405,6 +434,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x58004000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
        {
          .id                    = 0x497,
@@ -416,6 +447,8 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .flash_regs_base       = 0x58004000,
          .default_flash_regs    = stm32l4_flash_regs,
          .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
        },
 };
 
@@ -427,6 +460,10 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
        if (CMD_ARGC < 6)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
+       /* check bank base address (0 is used for normal flash memory) */
+       if (bank->base == 0)
+               bank->base = STM32_FLASH_BANK_BASE;
+
        stm32l4_info = malloc(sizeof(struct stm32l4_flash_bank));
        if (!stm32l4_info)
                return ERROR_FAIL; /* Checkme: What better error to use?*/
@@ -437,11 +474,43 @@ FLASH_BANK_COMMAND_HANDLER(stm32l4_flash_bank_command)
        bank->write_start_alignment = bank->write_end_alignment = 8;
 
        stm32l4_info->probed = false;
+       stm32l4_info->otp_enabled = false;
        stm32l4_info->user_bank_size = bank->size;
 
        return ERROR_OK;
 }
 
+static inline bool stm32l4_is_otp(struct flash_bank *bank)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       return bank->base == stm32l4_info->part_info->otp_base;
+}
+
+static int stm32l4_otp_enable(struct flash_bank *bank, bool enable)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+
+       if (!stm32l4_is_otp(bank))
+               return ERROR_FAIL;
+
+       char *op_str = enable ? "enabled" : "disabled";
+
+       LOG_INFO("OTP memory (bank #%d) is %s%s for write commands",
+                       bank->bank_number,
+                       stm32l4_info->otp_enabled == enable ? "already " : "",
+                       op_str);
+
+       stm32l4_info->otp_enabled = enable;
+
+       return ERROR_OK;
+}
+
+static inline bool stm32l4_otp_is_enabled(struct flash_bank *bank)
+{
+       struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+       return stm32l4_info->otp_enabled;
+}
+
 static inline uint32_t stm32l4_get_flash_reg(struct flash_bank *bank, uint32_t 
reg,
        enum reg_param_type reg_param_type)
 {
@@ -664,6 +733,11 @@ static int stm32l4_erase(struct flash_bank *bank, int 
first, int last)
 
        assert((0 <= first) && (first <= last) && (last < bank->num_sectors));
 
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot erase OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        if (bank->target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
@@ -719,6 +793,11 @@ static int stm32l4_protect(struct flash_bank *bank, int 
set, int first, int last
        struct target *target = bank->target;
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
 
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot protect/unprotect OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        if (target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
@@ -853,6 +932,11 @@ static int stm32l4_write(struct flash_bank *bank, const 
uint8_t *buffer,
 {
        int retval = ERROR_OK, retval2;
 
+       if (stm32l4_is_otp(bank) && !stm32l4_otp_is_enabled(bank)) {
+               LOG_ERROR("OTP memory is disabled for write commands");
+               return ERROR_FAIL;
+       }
+
        if (bank->target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
@@ -971,6 +1055,31 @@ static int stm32l4_probe(struct flash_bank *bank)
 
        LOG_INFO("device idcode = 0x%08" PRIx32 " (%s)", stm32l4_info->idcode, 
device_info);
 
+       if (stm32l4_is_otp(bank)) {
+               bank->size = part_info->otp_size;
+
+               LOG_INFO("OTP size is %d bytes, base address is " 
TARGET_ADDR_FMT, bank->size, bank->base);
+
+               if (bank->sectors)
+                       free(bank->sectors);
+
+               /* OTP memory is considered as one sector */
+               bank->num_sectors = 1;
+               bank->sectors = alloc_block_array(0, part_info->otp_size, 1);
+
+               if (!bank->sectors) {
+                       LOG_ERROR("failed to allocate bank sectors");
+                       return ERROR_FAIL;
+               }
+
+
+               stm32l4_info->probed = true;
+               return ERROR_OK;
+       } else if (bank->base != STM32_FLASH_BANK_BASE) {
+               LOG_ERROR("invalid bank base address");
+               return ERROR_FAIL;
+       }
+
        /* get flash size from target. */
        retval = target_read_u16(target, part_info->fsize_addr, &flash_size_kb);
 
@@ -1147,7 +1256,6 @@ static int stm32l4_probe(struct flash_bank *bank)
        }
 
        bank->size = (flash_size_kb + gap_size_kb) * 1024;
-       bank->base = STM32_FLASH_BANK_BASE;
        bank->num_sectors = num_pages;
        bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
        if (bank->sectors == NULL) {
@@ -1200,6 +1308,7 @@ static int get_stm32l4_info(struct flash_bank *bank, char 
*buf, int buf_size)
                if (stm32l4_info->probed) {
                        int buf_len = strlen(buf);
                        snprintf(buf + buf_len, buf_size - buf_len, " - 
%s-bank",
+                                       stm32l4_is_otp(bank) ? "OTP" :
                                        stm32l4_info->dual_bank_mode ? "Flash 
dual" : "Flash single");
                }
 
@@ -1218,6 +1327,11 @@ static int stm32l4_mass_erase(struct flash_bank *bank)
        struct target *target = bank->target;
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
 
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot erase OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        uint32_t action = FLASH_MER1;
 
        if (stm32l4_info->part_info->has_dual_bank)
@@ -1384,6 +1498,11 @@ COMMAND_HANDLER(stm32l4_handle_lock_command)
        if (ERROR_OK != retval)
                return retval;
 
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot lock/unlock OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        target = bank->target;
 
        if (target->state != TARGET_HALTED) {
@@ -1412,6 +1531,11 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
        if (ERROR_OK != retval)
                return retval;
 
+       if (stm32l4_is_otp(bank)) {
+               LOG_ERROR("cannot lock/unlock OTP memory");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        target = bank->target;
 
        if (target->state != TARGET_HALTED) {
@@ -1427,6 +1551,33 @@ COMMAND_HANDLER(stm32l4_handle_unlock_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(stm32l4_handle_otp_command)
+{
+       if (CMD_ARGC < 2)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+       if (ERROR_OK != retval)
+               return retval;
+
+       if (!stm32l4_is_otp(bank)) {
+               command_print(CMD, "the specified bank is not an OTP memory");
+               return ERROR_FAIL;
+       }
+       if (strcmp(CMD_ARGV[1], "enable") == 0)
+               stm32l4_otp_enable(bank, true);
+       else if (strcmp(CMD_ARGV[1], "disable") == 0)
+               stm32l4_otp_enable(bank, false);
+       else if (strcmp(CMD_ARGV[1], "show") == 0)
+               command_print(CMD, "OTP memory bank #%d is %s for write 
commands.",
+                               bank->bank_number, stm32l4_otp_is_enabled(bank) 
? "enabled" : "disabled");
+       else
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       return ERROR_OK;
+}
+
 static const struct command_registration stm32l4_exec_command_handlers[] = {
        {
                .name = "lock",
@@ -1470,6 +1621,13 @@ static const struct command_registration 
stm32l4_exec_command_handlers[] = {
                .usage = "bank_id",
                .help = "Force re-load of device options (will cause device 
reset).",
        },
+       {
+               .name = "otp",
+               .handler = stm32l4_handle_otp_command,
+               .mode = COMMAND_EXEC,
+               .usage = "<bank_id> <enable|disable|show>",
+               .help = "OTP (One Time Programmable) memory write 
enable/disable",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
diff --git a/tcl/target/stm32g0x.cfg b/tcl/target/stm32g0x.cfg
index 50836ea..7df5306 100644
--- a/tcl/target/stm32g0x.cfg
+++ b/tcl/target/stm32g0x.cfg
@@ -38,8 +38,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-set _FLASHNAME $_CHIPNAME.flash
-flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp   stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
 
 # reasonable default
 adapter speed 2000
diff --git a/tcl/target/stm32g4x.cfg b/tcl/target/stm32g4x.cfg
index 9f144a0..360447b 100644
--- a/tcl/target/stm32g4x.cfg
+++ b/tcl/target/stm32g4x.cfg
@@ -47,8 +47,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-set _FLASHNAME $_CHIPNAME.flash
-flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp   stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
 
 if { [info exists QUADSPI] && $QUADSPI } {
        set a [llength [flash list]]
diff --git a/tcl/target/stm32l4x.cfg b/tcl/target/stm32l4x.cfg
index 46e6f7e..83d4afa 100644
--- a/tcl/target/stm32l4x.cfg
+++ b/tcl/target/stm32l4x.cfg
@@ -47,8 +47,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-set _FLASHNAME $_CHIPNAME.flash
-flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp   stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
 
 # Common knowledges tells JTAG speed should be <= F_CPU/6.
 # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
diff --git a/tcl/target/stm32l5x.cfg b/tcl/target/stm32l5x.cfg
index 94aa0aa..b0299aa 100644
--- a/tcl/target/stm32l5x.cfg
+++ b/tcl/target/stm32l5x.cfg
@@ -50,8 +50,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 # use non-secure RAM by default
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-# declare non-secure flash
-flash bank $_CHIPNAME.flash_ns stm32l5x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash_ns stm32l5x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp      stm32l5x 0x0BFA0000 0 0 0 $_TARGETNAME
 
 # Common knowledges tells JTAG speed should be <= F_CPU/6.
 # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
diff --git a/tcl/target/stm32wbx.cfg b/tcl/target/stm32wbx.cfg
index 90f53bb..6467667 100644
--- a/tcl/target/stm32wbx.cfg
+++ b/tcl/target/stm32wbx.cfg
@@ -46,8 +46,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-set _FLASHNAME $_CHIPNAME.flash
-flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp   stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
 
 # Common knowledges tells JTAG speed should be <= F_CPU/6.
 # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on
diff --git a/tcl/target/stm32wlx.cfg b/tcl/target/stm32wlx.cfg
index 98c9a7e..4aaa8a5 100644
--- a/tcl/target/stm32wlx.cfg
+++ b/tcl/target/stm32wlx.cfg
@@ -46,8 +46,8 @@ target create $_TARGETNAME cortex_m -endian $_ENDIAN -dap 
$_CHIPNAME.dap
 
 $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 
$_WORKAREASIZE -work-area-backup 0
 
-set _FLASHNAME $_CHIPNAME.flash
-flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.flash stm32l4x 0x08000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.otp   stm32l4x 0x1fff7000 0 0 0 $_TARGETNAME
 
 # Common knowledges tells JTAG speed should be <= F_CPU/6.
 # F_CPU after reset is MSI 4MHz, so use F_JTAG = 500 kHz to stay on

-- 


_______________________________________________
OpenOCD-devel mailing list
OpenOCD-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/openocd-devel

Reply via email to