Add supprt for STM32L4 flash driver

No loader yet, but we can erase!
pull/321/head
Dave Vandervies 2015-07-19 22:58:43 -04:00
rodzic 67fd44b837
commit ab464492f7
1 zmienionych plików z 103 dodań i 11 usunięć

Wyświetl plik

@ -63,6 +63,28 @@
#define FLASH_L1_FPRG 10 #define FLASH_L1_FPRG 10
#define FLASH_L1_PROG 3 #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 //STM32L0x flash register base and offsets
//same as 32L1 above //same as 32L1 above
// RM0090 - DM00031020.pdf // RM0090 - DM00031020.pdf
@ -156,6 +178,8 @@ static inline uint32_t read_flash_cr(stlink_t *sl) {
(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_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))
res = stlink_read_debug32(sl, FLASH_F4_CR); 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 else
res = stlink_read_debug32(sl, FLASH_CR); res = stlink_read_debug32(sl, FLASH_CR);
#if DEBUG_FLASH #if DEBUG_FLASH
@ -166,12 +190,16 @@ static inline uint32_t read_flash_cr(stlink_t *sl) {
static inline unsigned int is_flash_locked(stlink_t *sl) { static inline unsigned int is_flash_locked(stlink_t *sl) {
/* return non zero for true */ /* 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) || 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_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))
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 else
return read_flash_cr(sl) & (1 << FLASH_CR_LOCK); return cr & (1 << FLASH_CR_LOCK);
} }
static void unlock_flash(stlink_t *sl) { static void unlock_flash(stlink_t *sl) {
@ -185,6 +213,9 @@ static void unlock_flash(stlink_t *sl) {
(sl->chip_id == STM32_CHIPID_F446)) { (sl->chip_id == STM32_CHIPID_F446)) {
stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY1); stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY1);
stlink_write_debug32(sl, FLASH_F4_KEYR, FLASH_KEY2); 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 { } else {
stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY1); stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY1);
stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2); stlink_write_debug32(sl, FLASH_KEYR, FLASH_KEY2);
@ -212,6 +243,9 @@ static void lock_flash(stlink_t *sl) {
(sl->chip_id == STM32_CHIPID_F446)) { (sl->chip_id == STM32_CHIPID_F446)) {
const uint32_t n = read_flash_cr(sl) | (1 << FLASH_F4_CR_LOCK); const uint32_t n = read_flash_cr(sl) | (1 << FLASH_F4_CR_LOCK);
stlink_write_debug32(sl, FLASH_F4_CR, n); 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 { } else {
/* write to 1 only. reset by hw at unlock sequence */ /* write to 1 only. reset by hw at unlock sequence */
const uint32_t n = read_flash_cr(sl) | (1 << FLASH_CR_LOCK); const uint32_t n = read_flash_cr(sl) | (1 << FLASH_CR_LOCK);
@ -227,6 +261,10 @@ static void set_flash_cr_pg(stlink_t *sl) {
uint32_t x = read_flash_cr(sl); uint32_t x = read_flash_cr(sl);
x |= (1 << FLASH_CR_PG); x |= (1 << FLASH_CR_PG);
stlink_write_debug32(sl, FLASH_F4_CR, x); 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 { } else {
const uint32_t n = 1 << FLASH_CR_PG; const uint32_t n = 1 << FLASH_CR_PG;
stlink_write_debug32(sl, FLASH_CR, n); stlink_write_debug32(sl, FLASH_CR, n);
@ -244,8 +282,14 @@ static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) {
} }
static void set_flash_cr_per(stlink_t *sl) { static void set_flash_cr_per(stlink_t *sl) {
const uint32_t n = 1 << FLASH_CR_PER; if (sl->chip_id == STM32_CHIPID_L4) {
stlink_write_debug32(sl, FLASH_CR, n); 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) { static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) {
@ -259,6 +303,11 @@ static void set_flash_cr_mer(stlink_t *sl) {
(sl->chip_id == STM32_CHIPID_F446)) (sl->chip_id == STM32_CHIPID_F446))
stlink_write_debug32(sl, FLASH_F4_CR, stlink_write_debug32(sl, FLASH_F4_CR,
stlink_read_debug32(sl, FLASH_F4_CR) | (1 << FLASH_CR_MER)); 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 else
stlink_write_debug32(sl, FLASH_CR, stlink_write_debug32(sl, FLASH_CR,
stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_MER)); stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_MER));
@ -282,6 +331,10 @@ static void set_flash_cr_strt(stlink_t *sl) {
uint32_t x = read_flash_cr(sl); uint32_t x = read_flash_cr(sl);
x |= (1 << FLASH_F4_CR_STRT); x |= (1 << FLASH_F4_CR_STRT);
stlink_write_debug32(sl, FLASH_F4_CR, x); 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 { } else {
stlink_write_debug32(sl, FLASH_CR, stlink_write_debug32(sl, FLASH_CR,
stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_STRT) ); stlink_read_debug32(sl, FLASH_CR) | (1 << FLASH_CR_STRT) );
@ -298,6 +351,8 @@ static inline uint32_t read_flash_sr(stlink_t *sl) {
(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_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))
res = stlink_read_debug32(sl, FLASH_F4_SR); 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 else
res = stlink_read_debug32(sl, FLASH_SR); res = stlink_read_debug32(sl, FLASH_SR);
//fprintf(stdout, "SR:0x%x\n", *(uint32_t*) sl->q_buf); //fprintf(stdout, "SR:0x%x\n", *(uint32_t*) sl->q_buf);
@ -309,6 +364,8 @@ static inline unsigned int is_flash_busy(stlink_t *sl) {
(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_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))
return read_flash_sr(sl) & (1 << FLASH_F4_SR_BSY); 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 else
return read_flash_sr(sl) & (1 << FLASH_SR_BSY); return read_flash_sr(sl) & (1 << FLASH_SR_BSY);
} }
@ -375,6 +432,17 @@ static inline void write_flash_cr_snb(stlink_t *sl, uint32_t n) {
stlink_write_debug32(sl, FLASH_F4_CR, x); 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... // Delegates to the backends...
void stlink_close(stlink_t *sl) { void stlink_close(stlink_t *sl) {
@ -1036,6 +1104,23 @@ uint32_t calculate_F4_sectornum(uint32_t flashaddr){
} }
// 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){ 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) || 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_F4_LP) || (sl->chip_id == STM32_CHIPID_F4_HD) || (sl->chip_id == STM32_CHIPID_F411RE) ||
@ -1061,7 +1146,7 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
{ {
if ((sl->chip_id == STM32_CHIPID_F2) || (sl->chip_id == STM32_CHIPID_F4) || (sl->chip_id == STM32_CHIPID_F4_DE) || 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_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 for ongoing op to finish */
wait_flash_busy(sl); wait_flash_busy(sl);
@ -1069,15 +1154,22 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr)
unlock_flash_if(sl); unlock_flash_if(sl);
/* select the page to erase */ /* select the page to erase */
// calculate the actual page from the address if (sl->chip_id == STM32_CHIPID_L4) {
uint32_t sector=calculate_F4_sectornum(flashaddr); // 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);
//the SNB values for flash sectors in the second bank do not directly follow the values for the first bank on 2mb devices... fprintf(stderr, "EraseFlash - Sector:0x%x Size:0x%x\n", sector, stlink_calculate_pagesize(sl, flashaddr));
if (sector >= 12) sector += 4;
write_flash_cr_snb(sl, sector); //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);
}
/* start erase operation */ /* start erase operation */
set_flash_cr_strt(sl); set_flash_cr_strt(sl);