+ destroy_reg_param(®_params[5]);
+
+ return retval;
+}
+
+/* Count is in double-words */
+static int stm32l4_write_block_without_loader(struct flash_bank *bank, const uint8_t *buffer,
+ uint32_t offset, uint32_t count)
+{
+ 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;
+ while (count--) {
+ retval = target_write_memory(target, address, 4, 2, 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 += 8;
+ address += 8;
+ }
+
+ /* 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;
+ }
+
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * The flash infrastructure ensures it, do just a security check */
+ assert(offset % 8 == 0);
+ assert(count % 8 == 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;
+
+ /**
+ * 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;
+ }
+
+ if (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,
+ * and the workarea need to be in non-secure RAM */
+ if (stm32l4_info->tzen && (stm32l4_info->rdp == RDP_LEVEL_0_5))
+ LOG_INFO("RDP level is 0.5, the work-area should reside in non-secure RAM");
+
+ retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+ }
+
+ if (!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 / 8);
+ }
+
+
+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;
+ }