diff --git a/include/stlink.h b/include/stlink.h index fedeb1bf4..d5e8270ac 100644 --- a/include/stlink.h +++ b/include/stlink.h @@ -77,6 +77,7 @@ extern "C" { STLINK_FLASH_TYPE_L4, STLINK_FLASH_TYPE_F1_XL, STLINK_FLASH_TYPE_G0, + STLINK_FLASH_TYPE_WB }; struct stlink_reg { diff --git a/include/stlink/chipid.h b/include/stlink/chipid.h index dda437ce7..a4f4be4c0 100644 --- a/include/stlink/chipid.h +++ b/include/stlink/chipid.h @@ -71,7 +71,8 @@ enum stlink_stm32_chipids { STLINK_CHIPID_STM32_F410 = 0x458, STLINK_CHIPID_STM32_F413 = 0x463, STLINK_CHIPID_STM32_L4RX = 0x470, // taken from the STM32L4R9I-DISCO board - STLINK_CHIPID_STM32_G0X1 = 0x460 + STLINK_CHIPID_STM32_G0X1 = 0x460, + STLINK_CHIPID_STM32_WB55 = 0x495 }; /** diff --git a/src/chipid.c b/src/chipid.c index 4e04f00cc..88d727377 100644 --- a/src/chipid.c +++ b/src/chipid.c @@ -518,6 +518,17 @@ static const struct stlink_chipid_params devices[] = { .bootrom_base = 0x1fff0000, .bootrom_size = 0x7800 // 30K (table 2) }, + { + // STM32WB55 (from RM0434) + .chip_id = STLINK_CHIPID_STM32_WB55, + .description = "WB55 device", + .flash_type = STLINK_FLASH_TYPE_WB, + .flash_size_reg = 0x1FFF75E0, + .flash_pagesize = 0x1000, // 4K + .sram_size = 0x40000, + .bootrom_base = 0x1fff0000, // See the memory map + .bootrom_size = 0x7000 + }, { // unknown .chip_id = STLINK_CHIPID_UNKNOWN, diff --git a/src/common.c b/src/common.c index 9bb2c2c4e..b46b6ea87 100644 --- a/src/common.c +++ b/src/common.c @@ -103,7 +103,37 @@ #define STM32G0_FLASH_CR_ERRIE 25 /* Error interrupt enable */ #define STM32G0_FLASH_CR_OBL_LAUNCH 27 /* Forces the option byte loading */ #define STM32G0_FLASH_CR_OPTLOCK 30 /* Options Lock */ -#define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock*/ +#define STM32G0_FLASH_CR_LOCK 31 /* FLASH_CR Lock */ +// GO FLASH status register +#define STM32G0_FLASH_SR_BSY 16 /* FLASH_SR Busy */ + +// WB (RM0434) +#define STM32WB_FLASH_REGS_ADDR ((uint32_t)0x58004000) +#define STM32WB_FLASH_ACR (STM32WB_FLASH_REGS_ADDR + 0x00) +#define STM32WB_FLASH_KEYR (STM32WB_FLASH_REGS_ADDR + 0x08) +#define STM32WB_FLASH_OPT_KEYR (STM32WB_FLASH_REGS_ADDR + 0x0C) +#define STM32WB_FLASH_SR (STM32WB_FLASH_REGS_ADDR + 0x10) +#define STM32WB_FLASH_CR (STM32WB_FLASH_REGS_ADDR + 0x14) +#define STM32WB_FLASH_ECCR (STM32WB_FLASH_REGS_ADDR + 0x18) +#define STM32WB_FLASH_OPTR (STM32WB_FLASH_REGS_ADDR + 0x20) +#define STM32WB_FLASH_PCROP1ASR (STM32WB_FLASH_REGS_ADDR + 0x24) +#define STM32WB_FLASH_PCROP1AER (STM32WB_FLASH_REGS_ADDR + 0x28) +#define STM32WB_FLASH_WRP1AR (STM32WB_FLASH_REGS_ADDR + 0x2C) +#define STM32WB_FLASH_WRP1BR (STM32WB_FLASH_REGS_ADDR + 0x30) +#define STM32WB_FLASH_PCROP1BSR (STM32WB_FLASH_REGS_ADDR + 0x34) +#define STM32WB_FLASH_PCROP1BER (STM32WB_FLASH_REGS_ADDR + 0x38) +#define STM32WB_FLASH_IPCCBR (STM32WB_FLASH_REGS_ADDR + 0x3C) +#define STM32WB_FLASH_C2ACR (STM32WB_FLASH_REGS_ADDR + 0x5C) +#define STM32WB_FLASH_C2SR (STM32WB_FLASH_REGS_ADDR + 0x60) +#define STM32WB_FLASH_C2CR (STM32WB_FLASH_REGS_ADDR + 0x64) +#define STM32WB_FLASH_SFR (STM32WB_FLASH_REGS_ADDR + 0x80) +#define STM32WB_FLASH_SRRVR (STM32WB_FLASH_REGS_ADDR + 0x84) + +// WB Flash control register. +#define STM32WB_FLASH_CR_STRT (16) /* FLASH_CR Start */ +#define STM32WB_FLASH_CR_LOCK (31) /* FLASH_CR Lock */ +// WB Flash status register. +#define STM32WB_FLASH_SR_BSY (16) /* FLASH_SR Busy */ //32L4 register base is at FLASH_REGS_ADDR (0x40022000) #define STM32L4_FLASH_KEYR (FLASH_REGS_ADDR + 0x08) @@ -219,6 +249,10 @@ static inline uint32_t read_flash_cr(stlink_t *sl) { reg = FLASH_F4_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) reg = STM32L4_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + reg = STM32WB_FLASH_CR; else reg = FLASH_CR; @@ -247,6 +281,10 @@ static inline unsigned int is_flash_locked(stlink_t *sl) { cr_lock_shift = FLASH_F4_CR_LOCK; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) cr_lock_shift = STM32L4_FLASH_CR_LOCK; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_lock_shift = STM32G0_FLASH_CR_LOCK; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_lock_shift = STM32WB_FLASH_CR_LOCK; else cr_lock_shift = FLASH_CR_LOCK; @@ -264,6 +302,10 @@ static void unlock_flash(stlink_t *sl) { key_reg = FLASH_F4_KEYR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) key_reg = STM32L4_FLASH_KEYR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + key_reg = STM32G0_FLASH_KEYR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + key_reg = STM32WB_FLASH_KEYR; else key_reg = FLASH_KEYR; @@ -299,6 +341,12 @@ static void lock_flash(stlink_t *sl) { } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { cr_reg = STM32L4_FLASH_CR; cr_lock_shift = STM32L4_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_lock_shift = STM32G0_FLASH_CR_LOCK; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_lock_shift = STM32WB_FLASH_CR_LOCK; } else { cr_reg = FLASH_CR; cr_lock_shift = FLASH_CR_LOCK; @@ -326,6 +374,12 @@ static void set_flash_cr_pg(stlink_t *sl) { cr_reg = STM32L4_FLASH_CR; x &= ~STM32L4_FLASH_CR_OPBITS; x |= 1 << STM32L4_FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + x |= (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + x |= (1 << FLASH_CR_PG); } else { cr_reg = FLASH_CR; x = 1 << FLASH_CR_PG; @@ -341,6 +395,10 @@ static void clear_flash_cr_pg(stlink_t *sl) { cr_reg = FLASH_F4_CR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) cr_reg = STM32L4_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; else cr_reg = FLASH_CR; @@ -349,8 +407,18 @@ static void 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); + uint32_t cr_reg, val; + + if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; + else + cr_reg = FLASH_CR; + + stlink_read_debug32(sl, cr_reg, &val); + val |= (1 << FLASH_CR_PER); + stlink_write_debug32(sl, cr_reg, val); } static void set_flash_cr2_per(stlink_t *sl) { @@ -358,9 +426,18 @@ static void set_flash_cr2_per(stlink_t *sl) { stlink_write_debug32(sl, FLASH_CR2, n); } -static void __attribute__((unused)) clear_flash_cr_per(stlink_t *sl) { +static void clear_flash_cr_per(stlink_t *sl) { + uint32_t cr_reg; + + if (sl->flash_type == STLINK_FLASH_TYPE_G0) + cr_reg = STM32G0_FLASH_CR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + cr_reg = STM32WB_FLASH_CR; + else + cr_reg = FLASH_CR; + const uint32_t n = read_flash_cr(sl) & ~(1 << FLASH_CR_PER); - stlink_write_debug32(sl, FLASH_CR, n); + stlink_write_debug32(sl, cr_reg, n); } static void set_flash_cr_mer(stlink_t *sl, bool v) { @@ -374,6 +451,14 @@ static void set_flash_cr_mer(stlink_t *sl, bool v) { cr_reg = STM32L4_FLASH_CR; cr_mer = (1 << STM32L4_FLASH_CR_MER1) | (1 << STM32L4_FLASH_CR_MER2); cr_pg = 1 << STM32L4_FLASH_CR_PG; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_mer = (1 << FLASH_CR_MER); + cr_pg = (1 << FLASH_CR_PG); } else { cr_reg = FLASH_CR; cr_mer = 1 << FLASH_CR_MER; @@ -436,6 +521,12 @@ static void set_flash_cr_strt(stlink_t *sl) { } else if (sl->flash_type == STLINK_FLASH_TYPE_L4) { cr_reg = STM32L4_FLASH_CR; cr_strt = 1 << STM32L4_FLASH_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + cr_reg = STM32G0_FLASH_CR; + cr_strt = 1 << STM32G0_FLASH_CR_STRT; + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + cr_reg = STM32WB_FLASH_CR; + cr_strt = 1 << STM32WB_FLASH_CR_STRT; } else { cr_reg = FLASH_CR; cr_strt = 1 << FLASH_CR_STRT; @@ -461,6 +552,10 @@ static inline uint32_t read_flash_sr(stlink_t *sl) { sr_reg = FLASH_F4_SR; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) sr_reg = STM32L4_FLASH_SR; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + sr_reg = STM32G0_FLASH_SR; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + sr_reg = STM32WB_FLASH_SR; else sr_reg = FLASH_SR; @@ -483,6 +578,10 @@ static inline unsigned int is_flash_busy(stlink_t *sl) { sr_busy_shift = FLASH_F4_SR_BSY; else if (sl->flash_type == STLINK_FLASH_TYPE_L4) sr_busy_shift = STM32L4_FLASH_SR_BSY; + else if (sl->flash_type == STLINK_FLASH_TYPE_G0) + sr_busy_shift = STM32G0_FLASH_SR_BSY; + else if (sl->flash_type == STLINK_FLASH_TYPE_WB) + sr_busy_shift = STM32WB_FLASH_SR_BSY; else sr_busy_shift = FLASH_SR_BSY; @@ -1646,47 +1745,39 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) stlink_read_debug32(sl, flash_regs_base + FLASH_PECR_OFF, &val); val |= (1 << 0) | (1 << 1) | (1 << 2); stlink_write_debug32(sl, flash_regs_base + FLASH_PECR_OFF, val); - } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + } else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0) { uint32_t val; - /* check if the locks are set */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ + // Wait for any ongoing Flash operation to finish. + wait_flash_busy(sl); + // Unlock Flash if necessary. + unlock_flash_if(sl); + // Set the 'enable Flash erase' bit. + set_flash_cr_per(sl); + + // Set the page to erase. + if (sl->flash_type == STLINK_FLASH_TYPE_WB) { + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); + stlink_read_debug32(sl, STM32WB_FLASH_CR, &val); + // sec 3.10.5 - PNB[7:0] is offset by 3. + val |= ((flash_page & 0xFF) << 3); + stlink_write_debug32(sl, STM32WB_FLASH_CR, val); + } else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { + uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } + // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. + val |= ((flash_page & 0x3F) << 3); + stlink_write_debug32(sl, STM32G0_FLASH_CR, val); } - /* Set PER (erase) bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x00000002; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Set the page to erase. */ - uint32_t flash_page = ((flashaddr - STM32_FLASH_BASE) / sl->flash_pgsz); - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - // sec 3.7.5 - PNB[5:0] is offset by 3. PER is 0x2. - val = ((flash_page & 0x3F) << 3) | (2); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Set the 'start' bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= (1 << 16); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); - /* Clear PER ('erase enable') bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val &= ~(0x00000002); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Re-lock the flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x80000000; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + + // Set the 'start operation' bit. + set_flash_cr_strt(sl); + // Wait for the 'busy' bit to clear. + wait_flash_busy(sl); + // Clear the 'enable page erase' bit. + clear_flash_cr_per(sl); + // Re-lock the flash. + lock_flash(sl); } else if ((sl->flash_type == STLINK_FLASH_TYPE_F0) || ((sl->flash_type == STLINK_FLASH_TYPE_F1_XL) && (flashaddr < FLASH_BANK2_START_ADDR))) { /* wait for ongoing op to finish */ wait_flash_busy(sl); @@ -1740,8 +1831,8 @@ int stlink_erase_flash_page(stlink_t *sl, stm32_addr_t flashaddr) } int stlink_erase_flash_mass(stlink_t *sl) { - /* TODO: User MER bit to mass-erase G0 series. */ - if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0) { + /* TODO: User MER bit to mass-erase G0, WB series. */ + if (sl->flash_type == STLINK_FLASH_TYPE_L0 || sl->flash_type == STLINK_FLASH_TYPE_G0 || sl->flash_type == STLINK_FLASH_TYPE_WB) { /* erase each page */ int i = 0, num_pages = (int) sl->flash_size/sl->flash_pgsz; for (i = 0; i < num_pages; i++) { @@ -2026,27 +2117,20 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t lock_flash(sl); } //STM32F4END - else if (sl->flash_type == STLINK_FLASH_TYPE_G0) { - uint32_t val; - /* Unlock flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1<<31))) { - /* disable flash write protection. */ - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0x45670123); - stlink_write_debug32(sl, STM32G0_FLASH_KEYR, 0xCDEF89AB); - /* check that the lock is no longer set. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - if ((val & (1 << 31))) { - WLOG("pecr.pelock not clear (%#x)\n", val); - return -1; - } - } - /* Set PG 'allow programming' bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x00000001; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Write all words. */ + else if (sl->flash_type == STLINK_FLASH_TYPE_WB || + sl->flash_type == STLINK_FLASH_TYPE_G0) { + fprintf(stdout, "Writing\r\n"); + fflush(stdout); + // Wait for any ongoing operations to finish. + wait_flash_busy(sl); + // Unlock flash if necessary. + unlock_flash_if(sl); + // Set PG 'allow programming' bit. + set_flash_cr_pg(sl); + // Write all words. off = 0; + fprintf(stdout, "Starting %3u page write\r\n", (unsigned int)(len/sl->flash_pgsz)); + fflush(stdout); for ( ; off < len; off += sizeof(uint32_t)) { uint32_t data; if (off > 254) @@ -2060,29 +2144,20 @@ int stlink_write_flash(stlink_t *sl, stm32_addr_t addr, uint8_t* base, uint32_t } write_uint32((unsigned char*) &data, *(uint32_t*) (base + off)); stlink_write_debug32(sl, addr + (uint32_t) off, data); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); + // Wait for 'busy' bit in FLASH_SR to clear. + wait_flash_busy(sl); } - /* Do we need a dummy write? See sec 3.3.8 of RM0444. */ - /* (Flash writes happen 2 words at a time.) */ + // (Flash writes happen 2 words at a time.) if ((off / sizeof(uint32_t)) % 2 != 0) { - /* Write a single word of zeros. */ + // Write a single word of zeros. stlink_write_debug32(sl, addr + (uint32_t) off, 0); - /* Wait for 'busy' bit in FLASH_SR to clear. */ - do { - stlink_read_debug32(sl, STM32G0_FLASH_SR, &val); - } while ((val & (1 << 16)) != 0); + // Wait for 'busy' bit in FLASH_SR to clear. + wait_flash_busy(sl); } - /* Reset PG bit. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val &= ~(0x00000001); - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); - /* Re-lock flash. */ - stlink_read_debug32(sl, STM32G0_FLASH_CR, &val); - val |= 0x80000000; - stlink_write_debug32(sl, STM32G0_FLASH_CR, val); + // Reset PG bit. + clear_flash_cr_pg(sl); + // Re-lock flash. + lock_flash(sl); } else if (sl->flash_type == STLINK_FLASH_TYPE_L0) { /* use fast word write. todo: half page. */