This is an automated email from Gerrit.

"zapb <d...@zapb.de>" just uploaded a new patch set to Gerrit, which you can 
find at https://review.openocd.org/c/openocd/+/8999

-- gerrit

commit c2b1f727942870d158f58ed9b188bedfb43ff5f8
Author: Marc Schink <d...@zapb.de>
Date:   Sun Jul 13 14:00:50 2025 +0000

    flash/nor/stm32lx: Add 'option_{write,read}' functions
    
    Add functions to read and write the option bytes, inspired by the
    stm32l4x driver.
    
    Tested on STM32L072CZ, including regression tests for 'stm32lx (un)lock'.
    
    Change-Id: I73298e1a668b3f604cbe558422495719832644e8
    Signed-off-by: Marc Schink <d...@zapb.de>

diff --git a/doc/openocd.texi b/doc/openocd.texi
index fb4664f3db..22095d4b27 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -8256,6 +8256,40 @@ Level is 2 which can't be unlocked at all).
 The @var{num} parameter is a value shown by @command{flash banks}.
 @end deffn
 
+@deffn {Command} {stm32lx option_read} num reg_offset
+Reads an option byte register from the device.
+The @var{num} parameter is a value shown by @command{flash banks}, 
@var{reg_offset} is the register offset of the option byte to read.
+
+For example to read the FLASH_OPTR register:
+@example
+stm32lx option_read 0 0x0
+# Option Register (for STM32L0): 0xaa
+@end example
+
+The above example will read out the first 16-bit of the FLASH_OPTR register 
which contains the RDP and WPRMOD value.
+@end deffn
+
+@deffn {Command} {stm324x option_write} num reg_offset value [reg_mask]
+Write an option byte register of the device.
+The @var{num} parameter is a value shown by @command{flash banks}, 
@var{reg_offset} is the register offset of the option byte to write.
+@var{value} is the 16-bit value that is written into the register.
+The complementary value for the option byte register is calculated 
automatically.
+@var{reg_mask} is the mask to apply when writing the register (only bits with 
a '1' will be touched).
+
+@emph{Note:} To modify an entire 32-bit option byte register, two individual 
write operations are necessary.
+
+For example, to modify the first 16-bit of the FLASH_OPTR register use the 
following command:
+
+@example
+stm32lx option_write 0 0x00 0x100 0x100
+@end example
+
+The above example sets bit 8 (WPRMOD) on the FLASH_OPTR option byte register 
which enables PCROP.
+Due to the applied mask, all other bits are not changed.
+
+@emph{Note:} To apply the option bytes change immediately, use 
@command{stm32lx option_load}.
+@end deffn
+
 @deffn {Command} {stm32lx option_load} num
 Forces a re-load of the option byte registers.
 This command will cause a system reset of the device.
diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c
index bf283239c0..69e66e6c67 100644
--- a/src/flash/nor/stm32lx.c
+++ b/src/flash/nor/stm32lx.c
@@ -17,6 +17,7 @@
 
 #include "imp.h"
 #include <helper/binarybuffer.h>
+#include <helper/align.h>
 #include <target/algorithm.h>
 #include <target/armv7m.h>
 #include <target/cortex_m.h>
@@ -82,8 +83,8 @@
 /* option bytes */
 #define OPTION_BYTES_ADDRESS 0x1FF80000
 
-#define OPTION_BYTE_0_PR1 0xFFFF0000
-#define OPTION_BYTE_0_PR0 0xFF5500AA
+#define OPTION_BYTE_0_PR1 0x0000
+#define OPTION_BYTE_0_PR0 0x00AA
 
 static int stm32lx_unlock_program_memory(struct flash_bank *bank);
 static int stm32lx_lock_program_memory(struct flash_bank *bank);
@@ -95,6 +96,8 @@ static int stm32lx_lock(struct flash_bank *bank);
 static int stm32lx_unlock(struct flash_bank *bank);
 static int stm32lx_mass_erase(struct flash_bank *bank);
 static int stm32lx_wait_until_bsy_clear_timeout(struct flash_bank *bank, int 
timeout);
+static int stm32lx_write_option(struct flash_bank *bank, uint32_t reg_offset,
+       uint16_t value, uint16_t mask);
 static int stm32lx_update_part_info(struct flash_bank *bank, uint16_t 
flash_size_in_kb);
 
 struct stm32lx_rev {
@@ -375,6 +378,76 @@ COMMAND_HANDLER(stm32lx_handle_option_load_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(stm32lx_handle_option_read_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 (retval != ERROR_OK)
+               return retval;
+
+       uint32_t reg_offset;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+
+       if (!IS_ALIGNED(reg_offset, 4)) {
+               command_print(CMD, "register offset must be word aligned");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint16_t value;
+       retval = target_read_u16(bank->target, OPTION_BYTES_ADDRESS + 
reg_offset,
+               &value);
+
+       if (retval != ERROR_OK) {
+               command_print(CMD, "failed to read option bytes");
+               return retval;
+       }
+
+       command_print(CMD, "0x%" PRIx16 "", value);
+
+       return retval;
+}
+
+COMMAND_HANDLER(stm32lx_handle_option_write_command)
+{
+       if (CMD_ARGC != 3 && CMD_ARGC != 4)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       struct flash_bank *bank;
+       int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       uint32_t reg_offset;
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], reg_offset);
+
+       uint16_t value;
+       COMMAND_PARSE_NUMBER(u16, CMD_ARGV[2], value);
+
+       if (!IS_ALIGNED(reg_offset, 4)) {
+               command_print(CMD, "register offset must be word aligned");
+               return ERROR_COMMAND_ARGUMENT_INVALID;
+       }
+
+       uint16_t mask = 0xffff;
+
+       if (CMD_ARGC > 3)
+               COMMAND_PARSE_NUMBER(u16, CMD_ARGV[3], mask);
+
+       retval = stm32lx_write_option(bank, reg_offset, value, mask);
+       if (retval != ERROR_OK) {
+               command_print(CMD, "failed to write option bytes");
+               return retval;
+       }
+
+       return ERROR_OK;
+}
+
 static int stm32lx_protect_check(struct flash_bank *bank)
 {
        int retval;
@@ -949,6 +1022,20 @@ static const struct command_registration 
stm32lx_exec_command_handlers[] = {
                .usage = "bank_id",
                .help = "Force re-load of device options (will cause device 
reset).",
        },
+       {
+               .name = "option_read",
+               .handler = stm32lx_handle_option_read_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id reg_offset",
+               .help = "Read & Display device option bytes.",
+       },
+       {
+               .name = "option_write",
+               .handler = stm32lx_handle_option_write_command,
+               .mode = COMMAND_EXEC,
+               .usage = "bank_id reg_offset value [mask]",
+               .help = "Write device option bit fields with provided value.",
+       },
        COMMAND_REGISTRATION_DONE
 };
 
@@ -1282,9 +1369,9 @@ static int stm32lx_obl_launch(struct flash_bank *bank)
        return tries ? ERROR_OK : ERROR_FAIL;
 }
 
-static int stm32lx_lock(struct flash_bank *bank)
+static int stm32lx_write_option(struct flash_bank *bank, uint32_t reg_offset,
+       uint16_t value, uint16_t mask)
 {
-       int retval;
        struct target *target = bank->target;
 
        if (target->state != TARGET_HALTED) {
@@ -1292,34 +1379,23 @@ static int stm32lx_lock(struct flash_bank *bank)
                return ERROR_TARGET_NOT_HALTED;
        }
 
-       retval = stm32lx_unlock_options_bytes(bank);
-       if (retval != ERROR_OK)
-               return retval;
+       uint32_t option_data;
+       int retval = target_read_u32(target, OPTION_BYTES_ADDRESS + reg_offset,
+               &option_data);
 
-       /* set the RDP protection level to 1 */
-       retval = target_write_u32(target, OPTION_BYTES_ADDRESS, 
OPTION_BYTE_0_PR1);
        if (retval != ERROR_OK)
                return retval;
 
-       return ERROR_OK;
-}
-
-static int stm32lx_unlock(struct flash_bank *bank)
-{
-       int retval;
-       struct target *target = bank->target;
-
-       if (target->state != TARGET_HALTED) {
-               LOG_ERROR("Target not halted");
-               return ERROR_TARGET_NOT_HALTED;
-       }
-
        retval = stm32lx_unlock_options_bytes(bank);
        if (retval != ERROR_OK)
                return retval;
 
-       /* set the RDP protection level to 0 */
-       retval = target_write_u32(target, OPTION_BYTES_ADDRESS, 
OPTION_BYTE_0_PR0);
+       option_data = (option_data & ~mask) | (value & mask);
+       // Calculate the complementary value for both option bytes.
+       option_data = (~(option_data & 0xffff)) << 16 | (option_data & 0xffff);
+
+       retval = target_write_u32(target, OPTION_BYTES_ADDRESS + reg_offset,
+               option_data);
        if (retval != ERROR_OK)
                return retval;
 
@@ -1330,6 +1406,19 @@ static int stm32lx_unlock(struct flash_bank *bank)
        return ERROR_OK;
 }
 
+
+static int stm32lx_lock(struct flash_bank *bank)
+{
+       // Set the RDP protection level to 1.
+       return stm32lx_write_option(bank, 0x00, OPTION_BYTE_0_PR1, 0x00ff);
+}
+
+static int stm32lx_unlock(struct flash_bank *bank)
+{
+       // Set the RDP protection level to 0.
+       return stm32lx_write_option(bank, 0x00, OPTION_BYTE_0_PR0, 0x00ff);
+}
+
 static int stm32lx_mass_erase(struct flash_bank *bank)
 {
        int retval;

-- 

Reply via email to