From ab464492f7774ce5c005c026b68479c49c16fa8d Mon Sep 17 00:00:00 2001 From: Dave Vandervies Date: Sun, 19 Jul 2015 22:58:43 -0400 Subject: [PATCH] Add supprt for STM32L4 flash driver No loader yet, but we can erase! --- src/stlink-common.c | 114 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/src/stlink-common.c b/src/stlink-common.c index 343795a..07b8d67 100644 --- a/src/stlink-common.c +++ b/src/stlink-common.c @@ -63,6 +63,28 @@ #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 @@ -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_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 @@ -166,12 +190,16 @@ static inline uint32_t read_flash_cr(stlink_t *sl) { 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) { @@ -185,6 +213,9 @@ 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); @@ -212,6 +243,9 @@ static void lock_flash(stlink_t *sl) { (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); @@ -227,6 +261,10 @@ static void set_flash_cr_pg(stlink_t *sl) { 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); @@ -244,8 +282,14 @@ static void __attribute__((unused)) clear_flash_cr_pg(stlink_t *sl) { } 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) { @@ -259,6 +303,11 @@ static void set_flash_cr_mer(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)); @@ -282,6 +331,10 @@ static void set_flash_cr_strt(stlink_t *sl) { 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) ); @@ -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_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); @@ -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_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); } @@ -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); } +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) { @@ -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){ 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) || @@ -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) || (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); @@ -1069,15 +1154,22 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) 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);