kopia lustrzana https://github.com/stlink-org/stlink
Add supprt for STM32L4 flash driver
No loader yet, but we can erase!pull/321/head
rodzic
67fd44b837
commit
ab464492f7
|
@ -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);
|
||||||
|
|
Ładowanie…
Reference in New Issue