#define FLASH_L1_FPRG 10
#define FLASH_L1_PROG 3
+//32L4 register base is at FLASH_REGS_ADDR (0x40022000)
+#define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08)
+#define STM32L4_FLASH_SR (FLASH_REGS_ADDR + 0x10)
+#define STM32L4_FLASH_CR (FLASH_REGS_ADDR + 0x14)
+#define STM32L4_FLASH_OPTR (FLASH_REGS_ADDR + 0x20)
+
+#define STM32L4_FLASH_SR_BSY 16
+#define STM32L4_FLASH_SR_ERRMASK 0x3f8 /* SR [9:3] */
+
+#define STM32L4_FLASH_CR_LOCK 31 /* Lock control register */
+#define STM32L4_FLASH_CR_PG 0 /* Program */
+#define STM32L4_FLASH_CR_PER 1 /* Page erase */
+#define STM32L4_FLASH_CR_MER1 2 /* Bank 1 erase */
+#define STM32L4_FLASH_CR_MER2 15 /* Bank 2 erase */
+#define STM32L4_FLASH_CR_STRT 16 /* Start command */
+#define STM32L4_FLASH_CR_BKER 11 /* Bank select for page erase */
+#define STM32L4_FLASH_CR_PNB 3 /* Page number (8 bits) */
+// Page is fully specified by BKER and PNB
+#define STM32L4_FLASH_CR_PAGEMASK (0x1fflu << STM32L4_FLASH_CR_PNB)
+
+#define STM32L4_FLASH_OPTR_DUALBANK 21
+
//STM32L0x flash register base and offsets
//same as 32L1 above
// RM0090 - DM00031020.pdf
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
(sl->chip_id == STM32_CHIPID_F446))
res = stlink_read_debug32(sl, FLASH_F4_CR);
+ else if (sl->chip_id == STM32_CHIPID_L4)
+ res = stlink_read_debug32(sl, STM32L4_FLASH_CR);
else
res = stlink_read_debug32(sl, FLASH_CR);
#if DEBUG_FLASH
static inline unsigned int is_flash_locked(stlink_t *sl) {
/* return non zero for true */
+ uint32_t cr = read_flash_cr(sl);
+
if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) ||
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
(sl->chip_id == STM32_CHIPID_F446))
- return read_flash_cr(sl) & (1 << FLASH_F4_CR_LOCK);
+ return cr & (1 << FLASH_F4_CR_LOCK);
+ else if (sl->chip_id == STM32_CHIPID_L4)
+ return cr & (1lu << STM32L4_FLASH_CR_LOCK);
else
- return read_flash_cr(sl) & (1 << FLASH_CR_LOCK);
+ return cr & (1 << FLASH_CR_LOCK);
}
static void unlock_flash(stlink_t *sl) {
(sl->chip_id == STM32_CHIPID_F446)) {
stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY1);
stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY2);
+ } else if (sl->chip_id == STM32_CHIPID_L4) {
+ stlink_write_debug32(sl, STM32L4_FLASH_KEYR, FLASH_KEY1);
+ stlink_write_debug32(sl, STM32L4_FLASH_KEYR, FLASH_KEY2);
} else {
stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY1);
stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2);
(sl->chip_id == STM32_CHIPID_F446)) {
const uint32_t n = read_flash_cr(sl) | (1 << FLASH_F4_CR_LOCK);
stlink_write_debug32(sl, FLASH_F4_CR, n);
+ } else if (sl->chip_id == STM32_CHIPID_L4) {
+ const uint32_t n = read_flash_cr(sl) | (1lu << STM32L4_FLASH_CR_LOCK);
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, n);
} else {
/* write to 1 only. reset by hw at unlock sequence */
const uint32_t n = read_flash_cr(sl) | (1 << FLASH_CR_LOCK);
uint32_t x = read_flash_cr(sl);
x |= (1 << FLASH_CR_PG);
stlink_write_debug32(sl, FLASH_F4_CR, x);
+ } else if (sl->chip_id == STM32_CHIPID_L4) {
+ uint32_t x = read_flash_cr(sl);
+ x |= (1 << STM32L4_FLASH_CR_PG);
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
} else {
const uint32_t n = 1 << FLASH_CR_PG;
stlink_write_debug32(sl, FLASH_CR, n);
}
static void set_flash_cr_per(stlink_t *sl) {
- const uint32_t n = 1 << FLASH_CR_PER;
- stlink_write_debug32(sl, FLASH_CR, n);
+ if (sl->chip_id == STM32_CHIPID_L4) {
+ uint32_t n = read_flash_cr(sl);
+ n |= (1lu << STM32L4_FLASH_CR_PER);
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, n);
+ } else {
+ const uint32_t n = 1 << FLASH_CR_PER;
+ stlink_write_debug32(sl, FLASH_CR, n);
+ }
}
static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
(sl->chip_id == STM32_CHIPID_F446))
stlink_write_debug32(sl, FLASH_F4_CR,
stlink_read_debug32(sl, FLASH_F4_CR) | (1 << FLASH_CR_MER));
+ else if (sl->chip_id == STM32_CHIPID_L4)
+ stlink_write_debug32(sl, STM32L4_FLASH_CR,
+ stlink_read_debug32(sl, STM32L4_FLASH_CR) |
+ (1lu << STM32L4_FLASH_CR_MER1) |
+ (1lu << STM32L4_FLASH_CR_MER2));
else
stlink_write_debug32(sl, FLASH_CR,
stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_MER));
uint32_t x = read_flash_cr(sl);
x |= (1 << FLASH_F4_CR_STRT);
stlink_write_debug32(sl, FLASH_F4_CR, x);
+ } else if (sl->chip_id == STM32_CHIPID_L4) {
+ uint32_t x = read_flash_cr(sl);
+ x |= (1lu << STM32L4_FLASH_CR_STRT);
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
} else {
stlink_write_debug32(sl, FLASH_CR,
stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_STRT) );
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
(sl->chip_id == STM32_CHIPID_F446))
res = stlink_read_debug32(sl, FLASH_F4_SR);
+ else if (sl->chip_id == STM32_CHIPID_L4)
+ res = stlink_read_debug32(sl, STM32L4_FLASH_SR);
else
res = stlink_read_debug32(sl, FLASH_SR);
//fprintf(stdout, "SR:0x%x\n", *(uint32_t*) sl->q_buf);
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
(sl->chip_id == STM32_CHIPID_F446))
return read_flash_sr(sl) & (1 << FLASH_F4_SR_BSY);
+ else if (sl->chip_id == STM32_CHIPID_L4)
+ return read_flash_sr(sl) & (1 << STM32L4_FLASH_SR_BSY);
else
return read_flash_sr(sl) & (1 << FLASH_SR_BSY);
}
stlink_write_debug32(sl, FLASH_F4_CR, x);
}
+static inline void write_flash_cr_bker_pnb(stlink_t *sl, uint32_t n) {
+ uint32_t x = read_flash_cr(sl);
+ x &=~ STM32L4_FLASH_CR_PAGEMASK;
+ x |= (n << STM32L4_FLASH_CR_PNB);
+ x |= (1lu << STM32L4_FLASH_CR_PER);
+#if DEBUG_FLASH
+ fprintf(stdout, "BKER:PNB:0x%x 0x%x\n", x, n);
+#endif
+ stlink_write_debug32(sl, STM32L4_FLASH_CR, x);
+}
+
// Delegates to the backends...
void stlink_close(stlink_t *sl) {
}
+// Returns BKER:PNB for the given page address
+uint32_t calculate_L4_page(stlink_t *sl, uint32_t flashaddr) {
+ uint32_t bker = 0;
+ uint32_t flashopt = stlink_read_debug32(sl, STM32L4_FLASH_OPTR);
+ flashaddr -= STM32_FLASH_BASE;
+ if (flashopt & (1lu << STM32L4_FLASH_OPTR_DUALBANK)) {
+ uint32_t banksize = sl->flash_size / 2;
+ if (flashaddr > banksize) {
+ flashaddr -= banksize;
+ bker = 0x100;
+ }
+ }
+ // For 1MB chips without the dual-bank option set, the page address will
+ // overflow into the BKER bit, which gives us the correct bank:page value.
+ return bker | flashaddr/sl->flash_pgsz;
+}
+
uint32_t stlink_calculate_pagesize(stlink_t *sl, uint32_t flashaddr){
if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) ||
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
{
if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) ||
(sl->chip_id == STM32_CHIPID_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
- (sl->chip_id == STM32_CHIPID_F446)) {
+ (sl->chip_id == STM32_CHIPID_F446) || (sl->chip_id == STM32_CHIPID_L4)) {
/* wait for ongoing op to finish */
wait_flash_busy(sl);
unlock_flash_if(sl);
/* select the page to erase */
- // calculate the actual page from the address
- uint32_t sector=calculate_F4_sectornum(flashaddr);
+ if (sl->chip_id == STM32_CHIPID_L4) {
+ // calculate the actual bank+page from the address
+ uint32_t page = calculate_L4_page(sl, flashaddr);
- fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
+ write_flash_cr_bker_pnb(sl, page);
+ } else {
+ // calculate the actual page from the address
+ uint32_t sector=calculate_F4_sectornum(flashaddr);
+
+ fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
- //the SNB values for flash sectors in the second bank do not directly follow the values for the first bank on 2mb devices...
- if (sector >= 12) sector += 4;
+ //the SNB values for flash sectors in the second bank do not directly follow the values for the first bank on 2mb devices...
+ if (sector >= 12) sector += 4;
- write_flash_cr_snb(sl, sector);
+ write_flash_cr_snb(sl, sector);
+ }
/* start erase operation */
set_flash_cr_strt(sl);