flash/stm32l4x: add support of STM32WB1x
[openocd.git] / src / flash / nor / stm32l4x.c
index b8635fe75ccd60de828e35757f5b5d82acc10e87..9f7d9e5e06cedbb7269702cf1271b1704ddfe4f5 100644 (file)
  *  - for STM32L4P5/Q5x
  *    In 1M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
  *    In 512K FLASH devices bit 21 (DB512K) controls Dual Bank mode.
- *
  */
 
 /* STM32WBxxx series for reference.
  *
- * RM0434 (STM32WB55)
+ * RM0434 (STM32WB55/WB35x)
  * http://www.st.com/resource/en/reference_manual/dm00318631.pdf
  *
- * RM0471 (STM32WB50)
+ * RM0471 (STM32WB50/WB30x)
  * http://www.st.com/resource/en/reference_manual/dm00622834.pdf
+ *
+ * RM0473 (STM32WB15x)
+ * http://www.st.com/resource/en/reference_manual/dm00649196.pdf
+ *
+ * RM0478 (STM32WB10x)
+ * http://www.st.com/resource/en/reference_manual/dm00689203.pdf
  */
 
 /* STM32WLxxx series for reference.
@@ -279,6 +284,10 @@ static const struct stm32l4_rev stm32_435_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x2001, "Y" },
 };
 
+static const struct stm32l4_rev stm32_456_revs[] = {
+       { 0x1000, "A" },
+};
+
 static const struct stm32l4_rev stm32_460_revs[] = {
        { 0x1000, "A/Z" } /* A and Z, no typo in RM! */, { 0x2000, "B" },
 };
@@ -331,6 +340,10 @@ static const struct stm32l4_rev stm32_482_revs[] = {
        { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x2000, "B" },
 };
 
+static const struct stm32l4_rev stm32_494_revs[] = {
+       { 0x1000, "A" }, { 0x2000, "B" },
+};
+
 static const struct stm32l4_rev stm32_495_revs[] = {
        { 0x2001, "2.1" },
 };
@@ -368,6 +381,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_base              = 0x1FFF7000,
          .otp_size              = 1024,
        },
+       {
+         .id                    = 0x456,
+         .revs                  = stm32_456_revs,
+         .num_revs              = ARRAY_SIZE(stm32_456_revs),
+         .device_str            = "STM32G05/G06xx",
+         .max_flash_size_kb     = 64,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x40022000,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
        {
          .id                    = 0x460,
          .revs                  = stm32_460_revs,
@@ -524,6 +549,18 @@ static const struct stm32l4_part_info stm32l4_parts[] = {
          .otp_base              = 0x0BFA0000,
          .otp_size              = 512,
        },
+       {
+         .id                    = 0x494,
+         .revs                  = stm32_494_revs,
+         .num_revs              = ARRAY_SIZE(stm32_494_revs),
+         .device_str            = "STM32WB1x",
+         .max_flash_size_kb     = 320,
+         .flags                 = F_NONE,
+         .flash_regs_base       = 0x58004000,
+         .fsize_addr            = 0x1FFF75E0,
+         .otp_base              = 0x1FFF7000,
+         .otp_size              = 1024,
+       },
        {
          .id                    = 0x495,
          .revs                  = stm32_495_revs,
@@ -1319,11 +1356,10 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
 {
        struct target *target = bank->target;
        struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
-       uint32_t buffer_size;
        struct working_area *write_algorithm;
        struct working_area *source;
        uint32_t address = bank->base + offset;
-       struct reg_param reg_params[6];
+       struct reg_param reg_params[5];
        struct armv7m_algorithm armv7m_info;
        int retval = ERROR_OK;
 
@@ -1345,21 +1381,23 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
                return retval;
        }
 
-       /* memory buffer, size *must* be multiple of stm32l4_info->data_width
-        * plus one dword for rp and one for wp */
-       /* FIXME, currently only STM32U5 devices do have a different data_width,
-        * but STM32U5 device flash programming does not go through this function
-        * so temporarily continue to consider the default data_width = 8 */
-       buffer_size = target_get_working_area_avail(target) & ~(2 * sizeof(uint32_t) - 1);
+       /* data_width should be multiple of double-word */
+       assert(stm32l4_info->data_width % 8 == 0);
+       const size_t extra_size = sizeof(struct stm32l4_work_area);
+       uint32_t buffer_size = target_get_working_area_avail(target) - extra_size;
+       /* buffer_size should be multiple of stm32l4_info->data_width */
+       buffer_size &= ~(stm32l4_info->data_width - 1);
+
        if (buffer_size < 256) {
                LOG_WARNING("large enough working area not available, can't do block memory writes");
+               target_free_working_area(target, write_algorithm);
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        } else if (buffer_size > 16384) {
                /* probably won't benefit from more than 16k ... */
                buffer_size = 16384;
        }
 
-       if (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
+       if (target_alloc_working_area_try(target, buffer_size + extra_size, &source) != ERROR_OK) {
                LOG_ERROR("allocating working area failed");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
@@ -1370,28 +1408,46 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);    /* buffer end */
        init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);    /* target address */
-       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* count (double word-64bit) */
-       init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);    /* flash status register */
-       init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);    /* flash control register */
+       init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);    /* count (of stm32l4_info->data_width) */
+       init_reg_param(&reg_params[4], "sp", 32, PARAM_OUT);    /* write algo stack pointer */
 
        buf_set_u32(reg_params[0].value, 0, 32, source->address);
        buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size);
        buf_set_u32(reg_params[2].value, 0, 32, address);
        buf_set_u32(reg_params[3].value, 0, 32, count);
-       buf_set_u32(reg_params[4].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
-       buf_set_u32(reg_params[5].value, 0, 32, stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
+       buf_set_u32(reg_params[4].value, 0, 32, source->address +
+                       offsetof(struct stm32l4_work_area, stack) + LDR_STACK_SIZE);
+
+       struct stm32l4_loader_params loader_extra_params;
+
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_addr,
+                       stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX));
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_cr_addr,
+                       stm32l4_get_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX));
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_word_size,
+                       stm32l4_info->data_width);
+       target_buffer_set_u32(target, (uint8_t *) &loader_extra_params.flash_sr_bsy_mask,
+                       stm32l4_info->sr_bsy_mask);
+
+       retval = target_write_buffer(target, source->address, sizeof(loader_extra_params),
+                       (uint8_t *) &loader_extra_params);
+       if (retval != ERROR_OK)
+               return retval;
 
        retval = target_run_flash_async_algorithm(target, buffer, count, stm32l4_info->data_width,
                        0, NULL,
                        ARRAY_SIZE(reg_params), reg_params,
-                       source->address, source->size,
+                       source->address + offsetof(struct stm32l4_work_area, fifo),
+                       source->size - offsetof(struct stm32l4_work_area, fifo),
                        write_algorithm->address, 0,
                        &armv7m_info);
 
        if (retval == ERROR_FLASH_OPERATION_FAILED) {
                LOG_ERROR("error executing stm32l4 flash write algorithm");
 
-               uint32_t error = buf_get_u32(reg_params[0].value, 0, 32) & FLASH_ERROR;
+               uint32_t error;
+               stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, &error);
+               error &= FLASH_ERROR;
 
                if (error & FLASH_WRPERR)
                        LOG_ERROR("flash memory write protected");
@@ -1412,7 +1468,6 @@ static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
        destroy_reg_param(&reg_params[2]);
        destroy_reg_param(&reg_params[3]);
        destroy_reg_param(&reg_params[4]);
-       destroy_reg_param(&reg_params[5]);
 
        return retval;
 }
@@ -1537,24 +1592,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
        if (retval != ERROR_OK)
                goto err_lock;
 
-       /**
-        * FIXME update the flash loader to use a custom FLASH_SR_BSY mask
-        * Workaround for STM32G0Bx/G0Cx devices in dual bank mode,
-        * as the flash loader does not use the SR_BSY2
-        */
-       bool use_flashloader = stm32l4_info->use_flashloader;
-       if ((stm32l4_info->part_info->id == 0x467) && stm32l4_info->dual_bank_mode) {
-               LOG_INFO("Couldn't use the flash loader in dual-bank mode");
-               use_flashloader = false;
-       } else if (stm32l4_info->part_info->id == 0x482) {
-               /**
-                * FIXME the current flashloader does not support writing in quad-words
-                * which is required for STM32U5 devices.
-                */
-               use_flashloader = false;
-       }
-
-       if (use_flashloader) {
+       if (stm32l4_info->use_flashloader) {
                /* For TrustZone enabled devices, when TZEN is set and RDP level is 0.5,
                 * the debug is possible only in non-secure state.
                 * Thus means the flashloader will run in non-secure mode,
@@ -1566,7 +1604,7 @@ static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
                                count / stm32l4_info->data_width);
        }
 
-       if (!use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+       if (!stm32l4_info->use_flashloader || retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
                LOG_INFO("falling back to single memory accesses");
                retval = stm32l4_write_block_without_loader(bank, buffer, offset,
                                count / stm32l4_info->data_width);
@@ -1808,12 +1846,14 @@ static int stm32l4_probe(struct flash_bank *bank)
                }
                break;
        case 0x435: /* STM32L43/L44xx */
+       case 0x456: /* STM32G05/G06xx */
        case 0x460: /* STM32G07/G08xx */
        case 0x462: /* STM32L45/L46xx */
        case 0x464: /* STM32L41/L42xx */
        case 0x466: /* STM32G03/G04xx */
        case 0x468: /* STM32G43/G44xx */
        case 0x479: /* STM32G49/G4Axx */
+       case 0x494: /* STM32WB1x */
                /* single bank flash */
                page_size_kb = 2;
                num_pages = flash_size_kb / page_size_kb;
@@ -1942,10 +1982,8 @@ static int stm32l4_probe(struct flash_bank *bank)
 
        /* use *max_flash_size* instead of actual size as the trimmed versions
         * certainly use the same number of bits
-        * max_flash_size is always power of two, so max_pages too
         */
        uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb;
-       assert(IS_PWR_OF_2(max_pages));
 
        /* in dual bank mode number of pages is doubled, but extra bit is bank selection */
        stm32l4_info->wrpxxr_mask = ((max_pages >> (stm32l4_info->dual_bank_mode ? 1 : 0)) - 1);

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)