static int stm32f1_flash_erase(struct target_s *target, uint32_t addr, int len, uint32_t pagesize) { ADIv5_AP_t *ap = adiv5_target_ap(target); uint16_t sr; addr &= ~(pagesize - 1); len &= ~(pagesize - 1); stm32f1_flash_unlock(ap); while(len) { /* Flash page erase instruction */ adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_PER); /* write address to FMA */ adiv5_ap_mem_write(ap, FLASH_AR, addr); /* Flash page erase start instruction */ adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER); /* Read FLASH_SR to poll for BSY bit */ while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(target)) return -1; len -= pagesize; addr += pagesize; } /* Check for error */ sr = adiv5_ap_mem_read(ap, FLASH_SR); if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) return -1; return 0; }
static void stm32f4_flash_unlock(ADIv5_AP_t *ap) { if (adiv5_ap_mem_read(ap, FLASH_CR) & FLASH_CR_LOCK) { /* Enable FPEC controller access */ adiv5_ap_mem_write(ap, FLASH_KEYR, KEY1); adiv5_ap_mem_write(ap, FLASH_KEYR, KEY2); } }
static bool stm32f1_cmd_option(target *t, int argc, char *argv[]) { uint32_t addr, val; uint32_t flash_obp_rdp_key; ADIv5_AP_t *ap = adiv5_target_ap(t); uint32_t rdprt; switch(t->idcode) { case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ case 0x440: /* STM32F0 */ flash_obp_rdp_key = FLASH_OBP_RDP_KEY_F3; break; default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY; } rdprt = (adiv5_ap_mem_read(ap, FLASH_OBR) & FLASH_OBR_RDPRT); stm32f1_flash_unlock(ap); adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY1); adiv5_ap_mem_write(ap, FLASH_OPTKEYR, KEY2); if ((argc == 2) && !strcmp(argv[1], "erase")) { stm32f1_option_erase(t); stm32f1_option_write_erased(t, FLASH_OBP_RDP, flash_obp_rdp_key); } else if (rdprt) { gdb_out("Device is Read Protected\n"); gdb_out("Use \"monitor option erase\" to unprotect, erasing device\n"); return true; } else if (argc == 3) { addr = strtol(argv[1], NULL, 0); val = strtol(argv[2], NULL, 0); stm32f1_option_write(t, addr, val); } else { gdb_out("usage: monitor option erase\n"); gdb_out("usage: monitor option <addr> <value>\n"); } if (0 && flash_obp_rdp_key == FLASH_OBP_RDP_KEY_F3) { /* Reload option bytes on F0 and F3*/ val = adiv5_ap_mem_read(ap, FLASH_CR); val |= FLASH_CR_OBL_LAUNCH; stm32f1_option_write(t, FLASH_CR, val); val &= ~FLASH_CR_OBL_LAUNCH; stm32f1_option_write(t, FLASH_CR, val); } for (int i = 0; i < 0xf; i += 4) { addr = 0x1ffff800 + i; val = adiv5_ap_mem_read(ap, addr); gdb_outf("0x%08X: 0x%04X\n", addr, val & 0xFFFF); gdb_outf("0x%08X: 0x%04X\n", addr + 2, val >> 16); } return true; }
static bool stm32f1_option_erase(target *t) { ADIv5_AP_t *ap = adiv5_target_ap(t); /* Erase option bytes instruction */ adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE); adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE); /* Read FLASH_SR to poll for BSY bit */ while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; return true; }
static bool stm32f1_cmd_erase_mass(target *t) { ADIv5_AP_t *ap = adiv5_target_ap(t); stm32f1_flash_unlock(ap); /* Flash mass erase start instruction */ adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_MER); adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER); /* Read FLASH_SR to poll for BSY bit */ while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; /* Check for error */ uint16_t sr = adiv5_ap_mem_read(ap, FLASH_SR); if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) return false; return true; }
static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value) { ADIv5_AP_t *ap = adiv5_target_ap(t); if (value == 0xffff) return true; /* Erase option bytes instruction */ adiv5_ap_mem_write(ap, FLASH_CR, FLASH_CR_OPTPG | FLASH_CR_OPTWRE); adiv5_ap_mem_write_halfword(ap, addr, value); /* Read FLASH_SR to poll for BSY bit */ while(adiv5_ap_mem_read(ap, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; return true; }
static void stm32f1_flash_unlock(ADIv5_AP_t *ap) { adiv5_ap_mem_write(ap, FLASH_KEYR, KEY1); adiv5_ap_mem_write(ap, FLASH_KEYR, KEY2); }