* RM0394 devices have a single bank only.
*
* RM0432 devices have single and dual bank operating modes.
- * The FLASH size is 1Mbyte or 2Mbyte.
+ * - for STM32L4R/Sxx the FLASH size is 2Mbyte or 1Mbyte.
+ * - for STM32L4P/Q5x the FLASH size is 1Mbyte or 512Kbyte.
* Bank page (sector) size is 4Kbyte (dual mode) or 8Kbyte (single mode).
*
* Bank mode is controlled by two different bits in option bytes register.
- * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
- * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - for STM32L4R/Sxx
+ * In 2M FLASH devices bit 22 (DBANK) controls Dual Bank mode.
+ * In 1M FLASH devices bit 21 (DB1M) controls Dual Bank mode.
+ * - 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.
*
*/
#define FLASH_PROGERR (1 << 3) /* Programming error */
#define FLASH_OPERR (1 << 1) /* Operation error */
#define FLASH_EOP (1 << 0) /* End of operation */
-#define FLASH_ERROR (FLASH_PGSERR | FLASH_PGSERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_OPERR)
+#define FLASH_ERROR (FLASH_PGSERR | FLASH_SIZERR | FLASH_PGAERR | FLASH_WRPERR | FLASH_PROGERR | FLASH_OPERR)
/* register unlock keys */
#define KEY1 0x45670123
{ 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, { 0x100F, "W" },
};
+static const struct stm32l4_rev stm32_471_revs[] = {
+ { 0x1000, "1" },
+};
+
static const struct stm32l4_rev stm32_495_revs[] = {
{ 0x2001, "2.1" },
};
.flash_regs_base = 0x40022000,
.fsize_addr = 0x1FFF75E0,
},
+ {
+ .id = 0x471,
+ .revs = stm32_471_revs,
+ .num_revs = ARRAY_SIZE(stm32_471_revs),
+ .device_str = "STM32L4P5/L4Q5x",
+ .max_flash_size_kb = 1024,
+ .has_dual_bank = true,
+ .flash_regs_base = 0x40022000,
+ .fsize_addr = 0x1FFF75E0,
+ },
{
.id = 0x495,
.revs = stm32_495_revs,
return ERROR_FAIL; /* Checkme: What better error to use?*/
bank->driver_priv = stm32l4_info;
+ /* The flash write must be aligned to a double word (8-bytes) boundary.
+ * Ask the flash infrastructure to ensure required alignment */
+ bank->write_start_alignment = bank->write_end_alignment = 8;
+
stm32l4_info->probed = 0;
return ERROR_OK;
static int stm32l4_write_option(struct flash_bank *bank, uint32_t reg_offset, uint32_t value, uint32_t mask)
{
uint32_t optiondata;
+ int retval, retval2;
- int retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata);
+ retval = stm32l4_read_flash_reg(bank, reg_offset, &optiondata);
if (retval != ERROR_OK)
return retval;
retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_unlock_option_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
optiondata = (optiondata & ~mask) | (value & mask);
retval = stm32l4_write_flash_reg(bank, reg_offset, optiondata);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_OPTSTRT);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK | FLASH_OPTLOCK);
+
if (retval != ERROR_OK)
return retval;
- return retval;
+ return retval2;
}
static int stm32l4_protect_check(struct flash_bank *bank)
{
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
int i;
- int retval;
+ int retval, retval2;
assert(first < bank->num_sectors);
assert(last < bank->num_sectors);
retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/*
Sector Erase
erase_flags |= i << FLASH_PAGE_SHIFT;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, erase_flags);
if (retval != ERROR_OK)
- return retval;
+ break;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
if (retval != ERROR_OK)
- return retval;
+ break;
bank->sectors[i].is_erased = 1;
}
- retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ return retval2;
}
static int stm32l4_protect(struct flash_bank *bank, int set, int first, int last)
return ret;
}
-/* Count is in halfwords */
+/* Count is in double-words */
static int stm32l4_write_block(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
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 (double word-64bit) */
- init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash base */
+ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash regs base */
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 / 4);
+ buf_set_u32(reg_params[3].value, 0, 32, count);
buf_set_u32(reg_params[4].value, 0, 32, stm32l4_info->part_info->flash_regs_base);
- retval = target_run_flash_async_algorithm(target, buffer, count, 2,
+ retval = target_run_flash_async_algorithm(target, buffer, count, 8,
0, NULL,
5, reg_params,
source->address, source->size,
static int stm32l4_write(struct flash_bank *bank, const uint8_t *buffer,
uint32_t offset, uint32_t count)
{
- int retval;
+ int retval, retval2;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
- if (offset & 0x7) {
- LOG_WARNING("offset 0x%" PRIx32 " breaks required 8-byte alignment",
- offset);
- return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
- }
-
- if (count & 0x7) {
- LOG_WARNING("Padding %d bytes to keep 8-byte write size",
- count & 7);
- count = (count + 7) & ~7;
- /* This pads the write chunk with random bytes by overrunning the
- * write buffer. Padding with the erased pattern 0xff is purely
- * cosmetical, as 8-byte flash words are ECC secured and the first
- * write will program the ECC bits. A second write would need
- * to reprogramm these ECC bits.
- * But this can only be done after erase!
- */
- }
+ /* 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);
retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
+
+ retval = stm32l4_write_block(bank, buffer, offset, count / 8);
+
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
- /* Only full double words (8-byte) can be programmed*/
- retval = stm32l4_write_block(bank, buffer, offset, count / 2);
if (retval != ERROR_OK) {
- LOG_WARNING("block write failed");
+ LOG_ERROR("block write failed");
return retval;
}
-
- LOG_WARNING("block write succeeded");
- return stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+ return retval2;
}
static int stm32l4_read_idcode(struct flash_bank *bank, uint32_t *id)
stm32l4_info->bank1_sectors = num_pages;
break;
case 0x470:
+ case 0x471:
/* STM32L4R/S can be single/dual bank:
* if size = 2M check DBANK bit(22)
* if size = 1M check DB1M bit(21)
+ * STM32L4P/Q can be single/dual bank
+ * if size = 1M check DBANK bit(22)
+ * if size = 512K check DB512K bit(21)
* in single bank configuration the page size is 8K
* else (dual bank) the page size is 4K without gap between banks
*/
page_size = 8192;
num_pages = flash_size_in_kb / 8;
stm32l4_info->bank1_sectors = num_pages;
- if ((flash_size_in_kb == 2048 && (options & BIT(22))) ||
- (flash_size_in_kb == 1024 && (options & BIT(21)))) {
+ const bool use_dbank_bit = flash_size_in_kb == part_info->max_flash_size_kb;
+ if ((use_dbank_bit && (options & BIT(22))) ||
+ (!use_dbank_bit && (options & BIT(21)))) {
stm32l4_info->dual_bank_mode = true;
page_size = 4096;
num_pages = flash_size_in_kb / 4;
static int stm32l4_mass_erase(struct flash_bank *bank)
{
- int retval;
+ int retval, retval2;
struct target *target = bank->target;
struct stm32l4_flash_bank *stm32l4_info = bank->driver_priv;
retval = stm32l4_unlock_reg(bank);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
/* mass erase flash memory */
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT / 10);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
+
retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, action | FLASH_STRT);
if (retval != ERROR_OK)
- return retval;
+ goto err_lock;
retval = stm32l4_wait_status_busy(bank, FLASH_ERASE_TIMEOUT);
- if (retval != ERROR_OK)
- return retval;
- retval = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+err_lock:
+ retval2 = stm32l4_write_flash_reg(bank, STM32_FLASH_CR, FLASH_LOCK);
+
if (retval != ERROR_OK)
return retval;
- return ERROR_OK;
+ return retval2;
}
COMMAND_HANDLER(stm32l4_handle_mass_erase_command)