bool stm32f1_probe(struct target_s *target) { target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE) & 0xfff; switch(target->idcode) { case 0x410: /* Medium density */ case 0x412: /* Low denisty */ case 0x420: /* Value Line, Low-/Medium density */ target->driver = stm32f1_driver_str; target->xml_mem_map = stm32f1_xml_memory_map; target->flash_erase = stm32md_flash_erase; target->flash_write = stm32f1_flash_write; target_add_commands(target, stm32f1_cmd_list, "STM32 LD/MD"); return true; case 0x414: /* High density */ case 0x418: /* Connectivity Line */ case 0x428: /* Value Line, High Density */ target->driver = stm32hd_driver_str; target->xml_mem_map = stm32hd_xml_memory_map; target->flash_erase = stm32hd_flash_erase; target->flash_write = stm32f1_flash_write; target_add_commands(target, stm32f1_cmd_list, "STM32 HD/CL"); return true; case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ target->driver = stm32f3_driver_str; target->xml_mem_map = stm32hd_xml_memory_map; target->flash_erase = stm32hd_flash_erase; target->flash_write = stm32f1_flash_write; target_add_commands(target, stm32f1_cmd_list, "STM32F3"); return true; } target->idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE_F0) & 0xfff; switch(target->idcode) { case 0x444: /* STM32F03 */ case 0x440: /* STM32F05 */ case 0x448: /* STM32F07 */ switch(target->idcode) { case 0x444: /* STM32F03 */ target->driver = stm32f03_driver_str; break; case 0x440: /* STM32F05 */ target->driver = stm32f05_driver_str; break; case 0x448: /* STM32F07 */ target->driver = stm32f07_driver_str; break; } target->xml_mem_map = stm32f1_xml_memory_map; target->flash_erase = stm32md_flash_erase; target->flash_write = stm32f1_flash_write; target_add_commands(target, stm32f1_cmd_list, "STM32F0"); return true; } return false; }
int lmi_flash_erase(struct target_s *target, uint32_t addr, int len) { ADIv5_AP_t *ap = adiv5_target_ap(target); uint32_t tmp; addr &= 0xFFFFFC00; len &= 0xFFFFFC00; /* setup word access */ adiv5_ap_write(ap, 0x00, 0xA2000052); /* select Flash Control */ adiv5_dp_low_access(ap->dp, 1, 0, 0x04, 0x400FD000); while(len) { /* write address to FMA */ adiv5_ap_write(ap, 0x10, addr); /* Required to switch banks */ /* set ERASE bit in FMC */ adiv5_dp_low_access(ap->dp, 1, 0, 0x08, 0xA4420002); /* Read FMC to poll for ERASE bit */ adiv5_dp_low_access(ap->dp, 1, 1, 0x08, 0); do { tmp = adiv5_dp_low_access(ap->dp, 1, 1, 0x08, 0); } while (tmp & 2); len -= 0x400; addr += 0x400; } return 0; }
static bool stm32f1_option_write(target *t, uint32_t addr, uint16_t value) { ADIv5_AP_t *ap = adiv5_target_ap(t); uint16_t opt_val[8]; int i, index; index = (addr - FLASH_OBP_RDP) / 2; if ((index < 0) || (index > 7)) return false; /* Retrieve old values */ for (i = 0; i < 16; i = i +4) { uint32_t val = adiv5_ap_mem_read(ap, FLASH_OBP_RDP + i); opt_val[i/2] = val & 0xffff; opt_val[i/2 +1] = val >> 16; } if (opt_val[index] == value) return true; /* Check for erased value */ if (opt_val[index] != 0xffff) if (!(stm32f1_option_erase(t))) return false; opt_val[index] = value; /* Write changed values*/ for (i = 0; i < 8; i++) if (!(stm32f1_option_write_erased (t, FLASH_OBP_RDP + i*2,opt_val[i]))) return false; return true; }
static int stm32f1_flash_write(struct target_s *target, uint32_t dest, const uint8_t *src, int len) { ADIv5_AP_t *ap = adiv5_target_ap(target); uint32_t offset = dest % 4; uint32_t words = (offset + len + 3) / 4; uint32_t data[2 + words]; /* Construct data buffer used by stub */ data[0] = dest - offset; data[1] = words * 4; /* length must always be a multiple of 4 */ data[2] = 0xFFFFFFFF; /* pad partial words with all 1s to avoid */ data[words + 1] = 0xFFFFFFFF; /* damaging overlapping areas */ memcpy((uint8_t *)&data[2] + offset, src, len); /* Write stub and data to target ram and set PC */ target_mem_write_words(target, 0x20000000, (void*)stm32f1_flash_write_stub, 0x2C); target_mem_write_words(target, 0x2000002C, data, len + 8); target_pc_write(target, 0x20000000); if(target_check_error(target)) return -1; /* Execute the stub */ target_halt_resume(target, 0); while(!target_halt_wait(target)); /* Check for error */ if (adiv5_ap_mem_read(ap, FLASH_SR) & SR_ERROR_MASK) return -1; return 0; }
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 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_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 int stm32f4_flash_erase(struct target_s *target, uint32_t addr, int len) { ADIv5_AP_t *ap = adiv5_target_ap(target); uint16_t sr; uint32_t cr; uint32_t pagesize; addr &= 0x07FFC000; stm32f4_flash_unlock(ap); while(len) { if (addr < 0x10000) { /* Sector 0..3 */ cr = (addr >> 11); pagesize = 0x4000; } else if (addr < 0x20000) { /* Sector 4 */
bool stm32f4_probe(struct target_s *target) { uint32_t idcode; idcode = adiv5_ap_mem_read(adiv5_target_ap(target), DBGMCU_IDCODE); switch(idcode & 0xFFF) { case 0x411: /* Documented to be 0x413! This is what I read... */ case 0x413: case 0x423: /* F401 */ case 0x419: /* 427/437 */ target->driver = stm32f4_driver_str; target->xml_mem_map = stm32f4_xml_memory_map; target->flash_erase = stm32f4_flash_erase; target->flash_write = stm32f4_flash_write; target_add_commands(target, stm32f4_cmd_list, "STM32F4"); return true; } return false; }
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; }