+ if (retval != ERROR_OK)
+ break;
+ }
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
+
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+ /* restore all FLASH pages as non-secure */
+ int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE);
+ if (retval3 != ERROR_OK)
+ return retval3;
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ return retval2;
+}
+
+static int stm32l4_protect_same_bank(struct flash_bank *bank, enum stm32_bank_id bank_id, int set,
+ unsigned int first, unsigned int last)
+{
+ unsigned int i;
+
+ /* check if the desired protection is already configured */
+ for (i = first; i <= last; i++) {
+ if (bank->sectors[i].is_protected != set)
+ break;
+ else if (i == last) {
+ LOG_INFO("The specified sectors are already %s", set ? "protected" : "unprotected");
+ return ERROR_OK;
+ }
+ }
+
+ /* all sectors from first to last (or part of them) could have different
+ * protection other than the requested */
+ unsigned int n_wrp;
+ struct stm32l4_wrp wrpxy[4];
+
+ int ret = stm32l4_get_all_wrpxy(bank, bank_id, wrpxy, &n_wrp);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* use bitmap and range helpers to optimize the WRP usage */
+ DECLARE_BITMAP(pages, bank->num_sectors);
+ bitmap_zero(pages, bank->num_sectors);
+
+ for (i = 0; i < n_wrp; i++) {
+ if (wrpxy[i].used) {
+ for (int p = wrpxy[i].first; p <= wrpxy[i].last; p++)
+ set_bit(p, pages);
+ }
+ }
+
+ /* we have at most 'n_wrp' WRP areas
+ * add one range if the user is trying to protect a fifth range */
+ struct range ranges[n_wrp + 1];
+ unsigned int ranges_count = 0;
+
+ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count);
+
+ /* pretty-print the currently protected ranges */
+ if (ranges_count > 0) {
+ char *ranges_str = range_print_alloc(ranges, ranges_count);
+ LOG_DEBUG("current protected areas: %s", ranges_str);
+ free(ranges_str);
+ } else
+ LOG_DEBUG("current protected areas: none");
+
+ if (set) { /* flash protect */
+ for (i = first; i <= last; i++)
+ set_bit(i, pages);
+ } else { /* flash unprotect */
+ for (i = first; i <= last; i++)
+ clear_bit(i, pages);
+ }
+
+ /* check the ranges_count after the user request */
+ bitmap_to_ranges(pages, bank->num_sectors, ranges, &ranges_count);
+
+ /* pretty-print the requested areas for protection */
+ if (ranges_count > 0) {
+ char *ranges_str = range_print_alloc(ranges, ranges_count);
+ LOG_DEBUG("requested areas for protection: %s", ranges_str);
+ free(ranges_str);
+ } else
+ LOG_DEBUG("requested areas for protection: none");
+
+ if (ranges_count > n_wrp) {
+ LOG_ERROR("cannot set the requested protection "
+ "(only %u write protection areas are available)" , n_wrp);
+ return ERROR_FAIL;
+ }
+
+ /* re-init all WRPxy as disabled (first > last)*/
+ for (i = 0; i < n_wrp; i++) {
+ wrpxy[i].first = wrpxy[i].offset + 1;
+ wrpxy[i].last = wrpxy[i].offset;
+ }
+
+ /* then configure WRPxy areas */
+ for (i = 0; i < ranges_count; i++) {
+ wrpxy[i].first = ranges[i].start;
+ wrpxy[i].last = ranges[i].end;
+ }
+
+ /* finally write WRPxy registers */
+ return stm32l4_write_all_wrpxy(bank, wrpxy, n_wrp);
+}
+
+static int stm32l4_protect(struct flash_bank *bank, int set, unsigned int first, unsigned 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;
+ }
+
+ /* refresh the sectors' protection */
+ int ret = stm32l4_protect_check(bank);
+ if (ret != ERROR_OK)
+ return ret;
+
+ /* the requested sectors could be located into bank1 and/or bank2 */
+ if (last < stm32l4_info->bank1_sectors) {
+ return stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, last);
+ } else if (first >= stm32l4_info->bank1_sectors) {
+ return stm32l4_protect_same_bank(bank, STM32_BANK2, set, first, last);
+ } else {
+ ret = stm32l4_protect_same_bank(bank, STM32_BANK1, set, first, stm32l4_info->bank1_sectors - 1);
+ if (ret != ERROR_OK)
+ return ret;
+
+ return stm32l4_protect_same_bank(bank, STM32_BANK2, set, stm32l4_info->bank1_sectors, last);
+ }
+}
+
+/* count is the size divided by stm32l4_info->data_width */
+static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ struct working_area *write_algorithm;
+ struct working_area *source;
+ uint32_t address = bank->base + offset;
+ struct reg_param reg_params[5];
+ struct armv7m_algorithm armv7m_info;
+ int retval = ERROR_OK;
+
+ static const uint8_t stm32l4_flash_write_code[] = {
+#include "../../../contrib/loaders/flash/stm32/stm32l4x.inc"
+ };
+
+ if (target_alloc_working_area(target, sizeof(stm32l4_flash_write_code),
+ &write_algorithm) != ERROR_OK) {
+ LOG_WARNING("no working area available, can't do block memory writes");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ retval = target_write_buffer(target, write_algorithm->address,
+ sizeof(stm32l4_flash_write_code),
+ stm32l4_flash_write_code);
+ if (retval != ERROR_OK) {
+ target_free_working_area(target, write_algorithm);
+ return retval;
+ }
+
+ /* 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 + extra_size, &source) != ERROR_OK) {
+ LOG_ERROR("allocating working area failed");
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+
+ armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
+ armv7m_info.core_mode = ARM_MODE_THREAD;
+
+ /* contrib/loaders/flash/stm32/stm32l4x.c:write() arguments */
+ init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* stm32l4_work_area ptr , status (out) */
+ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */
+ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */
+ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (of stm32l4_info->data_width) */
+
+ 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);
+
+ /* write algo stack pointer */
+ init_reg_param(®_params[4], "sp", 32, PARAM_OUT);
+ 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 + 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;
+ 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");
+
+ if (error != 0) {
+ LOG_ERROR("flash write failed = %08" PRIx32, error);
+ /* Clear but report errors */
+ stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_SR_INDEX, error);
+ retval = ERROR_FAIL;
+ }
+ }
+
+ target_free_working_area(target, source);
+ target_free_working_area(target, write_algorithm);
+
+ destroy_reg_param(®_params[0]);
+ destroy_reg_param(®_params[1]);
+ destroy_reg_param(®_params[2]);
+ destroy_reg_param(®_params[3]);
+ destroy_reg_param(®_params[4]);
+
+ return retval;
+}
+
+/* count is the size divided by stm32l4_info->data_width */
+static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ struct target *target = bank->target;
+ uint32_t address = bank->base + offset;
+ int retval = ERROR_OK;
+
+ /* wait for BSY bit */
+ retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* set PG in FLASH_CR */
+ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, FLASH_PG);
+ if (retval != ERROR_OK)
+ return retval;
+
+
+ /* write directly to flash memory */
+ const uint8_t *src = buffer;
+ const uint32_t data_width_in_words = stm32l4_info->data_width / 4;
+ while (count--) {
+ retval = target_write_memory(target, address, 4, data_width_in_words, src);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* wait for BSY bit */
+ retval = stm32l4_wait_status_busy(bank, FLASH_WRITE_TIMEOUT);
+ if (retval != ERROR_OK)
+ return retval;
+
+ src += stm32l4_info->data_width;
+ address += stm32l4_info->data_width;
+ }
+
+ /* reset PG in FLASH_CR */
+ retval = stm32l4_write_flash_reg_by_index(bank, STM32_FLASH_CR_INDEX, 0);
+ if (retval != ERROR_OK)
+ return retval;
+
+ return retval;
+}
+
+static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ 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;
+ }
+
+ /* ensure that stm32l4_info->data_width is 'at least' a multiple of dword */
+ assert(stm32l4_info->data_width % 8 == 0);
+
+ /* The flash write must be aligned to the 'stm32l4_info->data_width' boundary.
+ * The flash infrastructure ensures it, do just a security check */
+ assert(offset % stm32l4_info->data_width == 0);
+ assert(count % stm32l4_info->data_width == 0);
+
+ /* STM32G4xxx Cat. 3 devices may have gaps between banks, check whether
+ * data to be written does not go into a gap:
+ * suppose buffer is fully contained in bank from sector 0 to sector
+ * num->sectors - 1 and sectors are ordered according to offset
+ */
+ struct flash_sector *head = &bank->sectors[0];
+ struct flash_sector *tail = &bank->sectors[bank->num_sectors - 1];
+
+ while ((head < tail) && (offset >= (head + 1)->offset)) {
+ /* buffer does not intersect head nor gap behind head */
+ head++;
+ }
+
+ while ((head < tail) && (offset + count <= (tail - 1)->offset + (tail - 1)->size)) {
+ /* buffer does not intersect tail nor gap before tail */
+ --tail;
+ }
+
+ LOG_DEBUG("data: 0x%08" PRIx32 " - 0x%08" PRIx32 ", sectors: 0x%08" PRIx32 " - 0x%08" PRIx32,
+ offset, offset + count - 1, head->offset, tail->offset + tail->size - 1);
+
+ /* Now check that there is no gap from head to tail, this should work
+ * even for multiple or non-symmetric gaps
+ */
+ while (head < tail) {
+ if (head->offset + head->size != (head + 1)->offset) {
+ LOG_ERROR("write into gap from " TARGET_ADDR_FMT " to " TARGET_ADDR_FMT,
+ bank->base + head->offset + head->size,
+ bank->base + (head + 1)->offset - 1);
+ retval = ERROR_FLASH_DST_OUT_OF_BANK;
+ }
+ head++;
+ }
+
+ if (retval != ERROR_OK)
+ return retval;
+
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+ /* set all FLASH pages as secure */
+ retval = stm32l4_set_secbb(bank, FLASH_SECBB_SECURE);
+ if (retval != ERROR_OK) {
+ /* restore all FLASH pages as non-secure */
+ stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE); /* ignore the return value */
+ return retval;
+ }
+ }
+
+ retval = stm32l4_unlock_reg(bank);
+ if (retval != ERROR_OK)
+ goto err_lock;
+
+
+ /* 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,
+ * and the workarea need to be in non-secure RAM */
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5))
+ LOG_WARNING("RDP = 0x55, the work-area should be in non-secure RAM (check SAU partitioning)");
+
+ /* first try to write using the loader, for better performance */
+ retval = stm32l4_write_block(bank, buffer, offset,
+ count / stm32l4_info->data_width);
+
+ /* if resources are not available write without a loader */
+ if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) {
+ LOG_WARNING("falling back to programming without a flash loader (slower)");
+ retval = stm32l4_write_block_without_loader(bank, buffer, offset,
+ count / stm32l4_info->data_width);
+ }
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg_by_index(bank, stm32l4_get_flash_cr_with_lock_index(bank), FLASH_LOCK);
+
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+ /* restore all FLASH pages as non-secure */
+ int retval3 = stm32l4_set_secbb(bank, FLASH_SECBB_NON_SECURE);
+ if (retval3 != ERROR_OK)
+ return retval3;
+ }
+
+ if (retval != ERROR_OK) {
+ LOG_ERROR("block write failed");
+ return retval;
+ }
+ return retval2;
+}
+
+static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
+{
+ int retval = ERROR_OK;
+ struct target *target = bank->target;
+
+ /* try reading possible IDCODE registers, in the following order */
+ uint32_t dbgmcu_idcode[] = {DBGMCU_IDCODE_L4_G4, DBGMCU_IDCODE_G0, DBGMCU_IDCODE_L5};
+
+ for (unsigned int i = 0; i < ARRAY_SIZE(dbgmcu_idcode); i++) {
+ retval = target_read_u32(target, dbgmcu_idcode[i], id);
+ if ((retval == ERROR_OK) && ((*id & 0xfff) != 0) && ((*id & 0xfff) != 0xfff))
+ return ERROR_OK;
+ }
+
+ /* Workaround for STM32WL5x devices:
+ * DBGMCU_IDCODE cannot be read using CPU1 (Cortex-M0+) at AP1,
+ * to solve this read the UID64 (IEEE 64-bit unique device ID register) */
+
+ struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+ if (!armv7m) {
+ LOG_ERROR("Flash requires Cortex-M target");
+ return ERROR_TARGET_INVALID;
+ }
+
+ /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
+ * Using HLA adapters armv7m.debug_ap is null, and checking ap_num triggers a segfault */
+ if (cortex_m_get_partno_safe(target) == CORTEX_M0P_PARTNO &&
+ armv7m->debug_ap && armv7m->debug_ap->ap_num == 1) {
+ uint32_t uid64_ids;
+
+ /* UID64 is contains
+ * - Bits 63:32 : DEVNUM (unique device number, different for each individual device)
+ * - Bits 31:08 : STID (company ID) = 0x0080E1
+ * - Bits 07:00 : DEVID (device ID) = 0x15
+ *
+ * read only the fixed values {STID,DEVID} from UID64_IDS to identify the device as STM32WLx
+ */
+ retval = target_read_u32(target, UID64_IDS, &uid64_ids);
+ if (retval == ERROR_OK && uid64_ids == UID64_IDS_STM32WL) {
+ /* force the DEV_ID to DEVID_STM32WLE_WL5XX and the REV_ID to unknown */
+ *id = DEVID_STM32WLE_WL5XX;
+ return ERROR_OK;
+ }
+ }
+
+ LOG_ERROR("can't get the device id");
+ return (retval == ERROR_OK) ? ERROR_FAIL : retval;
+}
+
+static const char *get_stm32l4_rev_str(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ const struct stm32l4_part_info *part_info = stm32l4_info->part_info;
+ assert(part_info);
+
+ const uint16_t rev_id = stm32l4_info->idcode >> 16;
+ for (unsigned int i = 0; i < part_info->num_revs; i++) {
+ if (rev_id == part_info->revs[i].rev)
+ return part_info->revs[i].str;
+ }
+ return "'unknown'";
+}
+
+static const char *get_stm32l4_bank_type_str(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ assert(stm32l4_info->part_info);
+ return stm32l4_is_otp(bank) ? "OTP" :
+ stm32l4_info->dual_bank_mode ? "Flash dual" :
+ "Flash single";
+}
+
+static int stm32l4_probe(struct flash_bank *bank)
+{
+ struct target *target = bank->target;
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ const struct stm32l4_part_info *part_info;
+ uint16_t flash_size_kb = 0xffff;
+
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_TARGET_NOT_EXAMINED;
+ }
+
+ struct armv7m_common *armv7m = target_to_armv7m_safe(target);
+ if (!armv7m) {
+ LOG_ERROR("Flash requires Cortex-M target");
+ return ERROR_TARGET_INVALID;
+ }
+
+ stm32l4_info->probed = false;
+
+ /* read stm32 device id registers */
+ int retval = stm32l4_read_idcode(bank, &stm32l4_info->idcode);
+ if (retval != ERROR_OK)
+ return retval;
+
+ const uint32_t device_id = stm32l4_info->idcode & 0xFFF;
+
+ for (unsigned int n = 0; n < ARRAY_SIZE(stm32l4_parts); n++) {
+ if (device_id == stm32l4_parts[n].id) {
+ stm32l4_info->part_info = &stm32l4_parts[n];
+ break;
+ }
+ }
+
+ if (!stm32l4_info->part_info) {
+ LOG_WARNING("Cannot identify target as an %s family device.", device_families);
+ return ERROR_FAIL;
+ }
+
+ part_info = stm32l4_info->part_info;
+ const char *rev_str = get_stm32l4_rev_str(bank);
+ const uint16_t rev_id = stm32l4_info->idcode >> 16;
+
+ LOG_INFO("device idcode = 0x%08" PRIx32 " (%s - Rev %s : 0x%04x)",
+ stm32l4_info->idcode, part_info->device_str, rev_str, rev_id);
+
+ stm32l4_info->flash_regs_base = stm32l4_info->part_info->flash_regs_base;
+ stm32l4_info->data_width = (part_info->flags & F_QUAD_WORD_PROG) ? 16 : 8;
+ stm32l4_info->cr_bker_mask = FLASH_BKER;
+ stm32l4_info->sr_bsy_mask = FLASH_BSY;
+
+ /* Set flash write alignment boundaries.
+ * Ask the flash infrastructure to ensure required alignment */
+ bank->write_start_alignment = stm32l4_info->data_width;
+ bank->write_end_alignment = stm32l4_info->data_width;
+
+ /* Initialize the flash registers layout */
+ if (part_info->flags & F_HAS_L5_FLASH_REGS)
+ stm32l4_info->flash_regs = stm32l5_ns_flash_regs;
+ else
+ stm32l4_info->flash_regs = stm32l4_flash_regs;
+
+ /* read flash option register */
+ retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &stm32l4_info->optr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ stm32l4_sync_rdp_tzen(bank);
+
+ /* for devices with TrustZone, use flash secure registers when TZEN=1 and RDP is LEVEL_0 */
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0)) {
+ if (part_info->flags & F_HAS_L5_FLASH_REGS) {
+ stm32l4_info->flash_regs_base |= STM32L5_REGS_SEC_OFFSET;
+ stm32l4_info->flash_regs = stm32l5_s_flash_regs;
+ } else {
+ LOG_ERROR("BUG: device supported incomplete");
+ return ERROR_NOT_IMPLEMENTED;
+ }
+ }
+
+ if (part_info->flags & F_HAS_TZ)
+ LOG_INFO("TZEN = %d : TrustZone %s by option bytes",
+ stm32l4_info->tzen,
+ stm32l4_info->tzen ? "enabled" : "disabled");
+
+ LOG_INFO("RDP level %s (0x%02X)",
+ stm32l4_info->rdp == RDP_LEVEL_0 ? "0" : stm32l4_info->rdp == RDP_LEVEL_0_5 ? "0.5" : "1",
+ stm32l4_info->rdp);
+
+ 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);
+
+ /* OTP memory is considered as one sector */
+ free(bank->sectors);
+ 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 && bank->base != STM32_FLASH_S_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);
+
+ /* failed reading flash size or flash size invalid (early silicon),
+ * default to max target family */
+ if (retval != ERROR_OK || flash_size_kb == 0xffff || flash_size_kb == 0
+ || flash_size_kb > part_info->max_flash_size_kb) {
+ LOG_WARNING("STM32 flash size failed, probe inaccurate - assuming %dk flash",
+ part_info->max_flash_size_kb);
+ flash_size_kb = part_info->max_flash_size_kb;
+ }
+
+ /* if the user sets the size manually then ignore the probed value
+ * this allows us to work around devices that have a invalid flash size register value */
+ if (stm32l4_info->user_bank_size) {
+ LOG_WARNING("overriding size register by configured bank size - MAY CAUSE TROUBLE");
+ flash_size_kb = stm32l4_info->user_bank_size / 1024;
+ }
+
+ LOG_INFO("flash size = %d KiB", flash_size_kb);
+
+ /* did we assign a flash size? */
+ assert((flash_size_kb != 0xffff) && flash_size_kb);
+
+ const bool is_max_flash_size = flash_size_kb == stm32l4_info->part_info->max_flash_size_kb;
+
+ stm32l4_info->bank1_sectors = 0;
+ stm32l4_info->hole_sectors = 0;
+
+ int num_pages = 0;
+ int page_size_kb = 0;
+
+ stm32l4_info->dual_bank_mode = false;
+
+ switch (device_id) {
+ case DEVID_STM32L47_L48XX:
+ case DEVID_STM32L49_L4AXX:
+ /* if flash size is max (1M) the device is always dual bank
+ * STM32L47/L48xx: has variants with 512K
+ * STM32L49/L4Axx: has variants with 512 and 256
+ * for these variants:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank without gap
+ * note: the page size is invariant
+ */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+
+ /* check DUAL_BANK option bit if the flash is less than 1M */
+ if (is_max_flash_size || (stm32l4_info->optr & FLASH_L4_DUAL_BANK)) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case DEVID_STM32L43_L44XX:
+ case DEVID_STM32G05_G06XX:
+ case DEVID_STM32G07_G08XX:
+ case DEVID_STM32L45_L46XX:
+ case DEVID_STM32L41_L42XX:
+ case DEVID_STM32G03_G04XX:
+ case DEVID_STM32G43_G44XX:
+ case DEVID_STM32G49_G4AXX:
+ case DEVID_STM32WB1XX:
+ /* single bank flash */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ case DEVID_STM32G0B_G0CXX:
+ /* single/dual bank depending on DUAL_BANK option bit */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ stm32l4_info->cr_bker_mask = FLASH_BKER_G0;
+
+ /* check DUAL_BANK bit */
+ if (stm32l4_info->optr & FLASH_G0_DUAL_BANK) {
+ stm32l4_info->sr_bsy_mask = FLASH_BSY | FLASH_BSY2;
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case DEVID_STM32G47_G48XX:
+ /* STM32G47/8 can be single/dual bank:
+ * if DUAL_BANK = 0 -> single bank
+ * else -> dual bank WITH gap
+ */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ if (stm32l4_info->optr & FLASH_G4_DUAL_BANK) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+
+ /* for devices with trimmed flash, there is a gap between both banks */
+ stm32l4_info->hole_sectors =
+ (part_info->max_flash_size_kb - flash_size_kb) / (2 * page_size_kb);
+ }
+ break;
+ case DEVID_STM32L4R_L4SXX:
+ case DEVID_STM32L4P_L4QXX:
+ /* STM32L4R/S can be single/dual bank:
+ * if size = 2M check DBANK bit
+ * if size = 1M check DB1M bit
+ * STM32L4P/Q can be single/dual bank
+ * if size = 1M check DBANK bit
+ * if size = 512K check DB512K bit (same as DB1M bit)
+ */
+ page_size_kb = 8;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L4R_DBANK)) ||
+ (!is_max_flash_size && (stm32l4_info->optr & FLASH_LRR_DB1M))) {
+ stm32l4_info->dual_bank_mode = true;
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case DEVID_STM32L55_L56XX:
+ /* STM32L55/L56xx can be single/dual bank:
+ * if size = 512K check DBANK bit
+ * if size = 256K check DB256K bit
+ *
+ * default page size is 4kb, if DBANK = 1, the page size is 2kb.
+ */
+
+ page_size_kb = (stm32l4_info->optr & FLASH_L5_DBANK) ? 2 : 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+
+ if ((is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DBANK)) ||
+ (!is_max_flash_size && (stm32l4_info->optr & FLASH_L5_DB256))) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case DEVID_STM32U57_U58XX:
+ /* if flash size is max (2M) the device is always dual bank
+ * otherwise check DUALBANK
+ */
+ page_size_kb = 8;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ if (is_max_flash_size || (stm32l4_info->optr & FLASH_U5_DUALBANK)) {
+ stm32l4_info->dual_bank_mode = true;
+ stm32l4_info->bank1_sectors = num_pages / 2;
+ }
+ break;
+ case DEVID_STM32WB5XX:
+ case DEVID_STM32WB3XX:
+ /* single bank flash */
+ page_size_kb = 4;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+ break;
+ case DEVID_STM32WLE_WL5XX:
+ /* single bank flash */
+ page_size_kb = 2;
+ num_pages = flash_size_kb / page_size_kb;
+ stm32l4_info->bank1_sectors = num_pages;
+
+ /* CPU2 (Cortex-M0+) is supported only with non-hla adapters because it is on AP1.
+ * Using HLA adapters armv7m->debug_ap is null, and checking ap_num triggers a segfault */
+ if (armv7m->debug_ap && armv7m->debug_ap->ap_num == 1)
+ stm32l4_info->flash_regs = stm32wl_cpu2_flash_regs;
+ break;
+ default:
+ LOG_ERROR("unsupported device");
+ return ERROR_FAIL;
+ }
+
+ /* ensure that at least there is 1 flash sector / page */
+ if (num_pages == 0) {
+ if (stm32l4_info->user_bank_size)
+ LOG_ERROR("The specified flash size is less than page size");
+
+ LOG_ERROR("Flash pages count cannot be zero");
+ return ERROR_FAIL;
+ }
+
+ LOG_INFO("flash mode : %s-bank", stm32l4_info->dual_bank_mode ? "dual" : "single");
+
+ const int gap_size_kb = stm32l4_info->hole_sectors * page_size_kb;
+
+ if (gap_size_kb != 0) {
+ LOG_INFO("gap detected from 0x%08x to 0x%08x",
+ STM32_FLASH_BANK_BASE + stm32l4_info->bank1_sectors
+ * page_size_kb * 1024,
+ STM32_FLASH_BANK_BASE + (stm32l4_info->bank1_sectors
+ * page_size_kb + gap_size_kb) * 1024 - 1);
+ }
+
+ /* number of significant bits in WRPxxR differs per device,
+ * always right adjusted, on some devices non-implemented
+ * bits read as '0', on others as '1' ...
+ * notably G4 Cat. 2 implement only 6 bits, contradicting the RM
+ */
+
+ /* use *max_flash_size* instead of actual size as the trimmed versions
+ * certainly use the same number of bits
+ */
+ uint32_t max_pages = stm32l4_info->part_info->max_flash_size_kb / page_size_kb;
+
+ /* 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);
+ assert((stm32l4_info->wrpxxr_mask & 0xFFFF0000) == 0);
+ LOG_DEBUG("WRPxxR mask 0x%04" PRIx16, (uint16_t)stm32l4_info->wrpxxr_mask);
+
+ free(bank->sectors);
+
+ bank->size = (flash_size_kb + gap_size_kb) * 1024;
+ bank->num_sectors = num_pages;
+ bank->sectors = malloc(sizeof(struct flash_sector) * bank->num_sectors);
+ if (!bank->sectors) {
+ LOG_ERROR("failed to allocate bank sectors");
+ return ERROR_FAIL;
+ }
+
+ for (unsigned int i = 0; i < bank->num_sectors; i++) {
+ bank->sectors[i].offset = i * page_size_kb * 1024;
+ /* in dual bank configuration, if there is a gap between banks
+ * we fix up the sector offset to consider this gap */
+ if (i >= stm32l4_info->bank1_sectors && stm32l4_info->hole_sectors)
+ bank->sectors[i].offset += gap_size_kb * 1024;
+ bank->sectors[i].size = page_size_kb * 1024;
+ bank->sectors[i].is_erased = -1;
+ bank->sectors[i].is_protected = 1;
+ }
+
+ stm32l4_info->probed = true;
+ return ERROR_OK;
+}
+
+static int stm32l4_auto_probe(struct flash_bank *bank)
+{
+ struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
+ if (stm32l4_info->probed) {
+ uint32_t optr_cur;
+
+ /* save flash_regs_base */
+ uint32_t saved_flash_regs_base = stm32l4_info->flash_regs_base;
+
+ /* for devices with TrustZone, use NS flash registers to read OPTR */
+ if (stm32l4_info->part_info->flags & F_HAS_L5_FLASH_REGS)
+ stm32l4_info->flash_regs_base &= ~STM32L5_REGS_SEC_OFFSET;
+
+ /* read flash option register and re-probe if optr value is changed */
+ int retval = stm32l4_read_flash_reg_by_index(bank, STM32_FLASH_OPTR_INDEX, &optr_cur);
+
+ /* restore saved flash_regs_base */
+ stm32l4_info->flash_regs_base = saved_flash_regs_base;
+