flash/nor/stm32f1x: allow write fallback for flash options 06/6706/4
authorTomas Vanek <vanekt@fbl.cz>
Tue, 16 Nov 2021 16:51:09 +0000 (17:51 +0100)
committerTomas Vanek <vanekt@fbl.cz>
Wed, 13 Apr 2022 16:50:21 +0000 (16:50 +0000)
Mostly refactoring.

Rename original stm32x_write_block() to stm32x_write_block_async()
as it uses target async algo.

Introduce new stm32x_write_block() and move slow, host controlled
fallback flash write there.

The change allows stm32x_write_options() to use slow flash write fallback.

While on it rename variables where halfword count is stored.

Change-Id: I386ae15cf052b1490461ed8f7eea5b4403d466f7
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: https://review.openocd.org/c/openocd/+/6706
Tested-by: jenkins
Reviewed-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com>
src/flash/nor/stm32f1x.c

index 6972bae2de14d340bf75b6410fa2ff88ceb172e4..139f10ea81048d207841f4c11a6308b16e482355 100644 (file)
@@ -131,7 +131,7 @@ struct stm32x_flash_bank {
 static int stm32x_mass_erase(struct flash_bank *bank);
 static int stm32x_get_device_id(struct flash_bank *bank, uint32_t *device_id);
 static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
-               uint32_t address, uint32_t count);
+               uint32_t address, uint32_t hwords_count);
 
 /* flash bank stm32x <base> <size> 0 0 <target#>
  */
@@ -329,12 +329,14 @@ static int stm32x_write_options(struct flash_bank *bank)
        target_buffer_set_u16(target, opt_bytes + 12, (stm32x_info->option_bytes.protection >> 16) & 0xff);
        target_buffer_set_u16(target, opt_bytes + 14, (stm32x_info->option_bytes.protection >> 24) & 0xff);
 
+       /* Block write is preferred in favour of operation with ancient ST-Link
+        * firmwares without 16-bit memory access. See
+        * 480: flash: stm32f1x: write option bytes using the loader
+        * https://review.openocd.org/c/openocd/+/480
+        */
        retval = stm32x_write_block(bank, opt_bytes, STM32_OB_RDP, sizeof(opt_bytes) / 2);
-       if (retval != ERROR_OK) {
-               if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
-                       LOG_ERROR("working area required to erase options bytes");
+       if (retval != ERROR_OK)
                return retval;
-       }
 
        retval = target_write_u32(target, STM32_FLASH_CR_B0, FLASH_LOCK);
        if (retval != ERROR_OK)
@@ -442,8 +444,8 @@ static int stm32x_protect(struct flash_bank *bank, int set, unsigned int first,
        return stm32x_write_options(bank);
 }
 
-static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
-               uint32_t address, uint32_t count)
+static int stm32x_write_block_async(struct flash_bank *bank, const uint8_t *buffer,
+               uint32_t address, uint32_t hwords_count)
 {
        struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
        struct target *target = bank->target;
@@ -493,7 +495,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
        init_reg_param(&reg_params[4], "r4", 32, PARAM_IN_OUT); /* target address */
 
        buf_set_u32(reg_params[0].value, 0, 32, stm32x_info->register_base);
-       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, hwords_count);
        buf_set_u32(reg_params[2].value, 0, 32, source->address);
        buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size);
        buf_set_u32(reg_params[4].value, 0, 32, address);
@@ -501,7 +503,7 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
        armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
        armv7m_info.core_mode = ARM_MODE_THREAD;
 
-       retval = target_run_flash_async_algorithm(target, buffer, count, 2,
+       retval = target_run_flash_async_algorithm(target, buffer, hwords_count, 2,
                        0, NULL,
                        5, reg_params,
                        source->address, source->size,
@@ -537,6 +539,40 @@ static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer,
        return retval;
 }
 
+/** Writes a block to flash either using target algorithm
+ *  or use fallback, host controlled halfword-by-halfword access.
+ *  Flash controller must be unlocked before this call.
+ */
+static int stm32x_write_block(struct flash_bank *bank,
+               const uint8_t *buffer, uint32_t address, uint32_t hwords_count)
+{
+       struct target *target = bank->target;
+
+       /* try using a block write - on ARM architecture or... */
+       int retval = stm32x_write_block_async(bank, buffer, address, hwords_count);
+
+       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+               /* if block write failed (no sufficient working area),
+                * we use normal (slow) single halfword accesses */
+               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
+
+               while (hwords_count > 0) {
+                       retval = target_write_memory(target, address, 2, 1, buffer);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = stm32x_wait_status_busy(bank, 5);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       hwords_count--;
+                       buffer += 2;
+                       address += 2;
+               }
+       }
+       return retval;
+}
+
 static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
                uint32_t offset, uint32_t count)
 {
@@ -568,7 +604,6 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
                new_buffer[count++] = 0xff;
        }
 
-       uint32_t words_remaining = count / 2;
        int retval, retval2;
 
        /* unlock flash registers */
@@ -577,34 +612,15 @@ static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer,
                goto cleanup;
        retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_KEYR), KEY2);
        if (retval != ERROR_OK)
-               goto cleanup;
+               goto reset_pg_and_lock;
 
+       /* enable flash programming */
        retval = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_PG);
        if (retval != ERROR_OK)
-               goto cleanup;
-
-       /* try using a block write */
-       retval = stm32x_write_block(bank, buffer, bank->base + offset, words_remaining);
-
-       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
-               /* if block write failed (no sufficient working area),
-                * we use normal (slow) single halfword accesses */
-               LOG_WARNING("couldn't use block writes, falling back to single memory accesses");
-
-               while (words_remaining > 0) {
-                       retval = target_write_memory(target, bank->base + offset, 2, 1, buffer);
-                       if (retval != ERROR_OK)
-                               goto reset_pg_and_lock;
-
-                       retval = stm32x_wait_status_busy(bank, 5);
-                       if (retval != ERROR_OK)
-                               goto reset_pg_and_lock;
+               goto reset_pg_and_lock;
 
-                       words_remaining--;
-                       buffer += 2;
-                       offset += 2;
-               }
-       }
+       /* write to flash */
+       retval = stm32x_write_block(bank, buffer, bank->base + offset, count / 2);
 
 reset_pg_and_lock:
        retval2 = target_write_u32(target, stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_LOCK);

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)