static bool kl_gen_command(target *t, uint8_t cmd, uint32_t addr, const uint8_t data[8]) { uint8_t fstat; /* clear errors unconditionally, so we can start a new operation */ target_mem_write8(t,FTFA_FSTAT,(FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)); /* Wait for CCIF to be high */ do { fstat = target_mem_read8(t, FTFA_FSTAT); } while (!(fstat & FTFA_FSTAT_CCIF)); /* Write command to FCCOB */ addr &= 0xffffff; addr |= (uint32_t)cmd << 24; target_mem_write32(t, FTFA_FCCOB_0, addr); if (data) { target_mem_write32(t, FTFA_FCCOB_1, *(uint32_t*)&data[0]); target_mem_write32(t, FTFA_FCCOB_2, *(uint32_t*)&data[4]); } /* Enable execution by clearing CCIF */ target_mem_write8(t, FTFA_FSTAT, FTFA_FSTAT_CCIF); /* Wait for execution to complete */ do { fstat = target_mem_read8(t, FTFA_FSTAT); /* Check ACCERR and FPVIOL are zero in FSTAT */ if (fstat & (FTFA_FSTAT_ACCERR | FTFA_FSTAT_FPVIOL)) return false; } while (!(fstat & FTFA_FSTAT_CCIF)); return true; }
static void cortexa_reset(target *t) { /* This mess is Xilinx Zynq specific * See Zynq-7000 TRM, Xilinx doc UG585 */ #define ZYNQ_SLCR_UNLOCK 0xf8000008 #define ZYNQ_SLCR_UNLOCK_KEY 0xdf0d #define ZYNQ_SLCR_PSS_RST_CTRL 0xf8000200 target_mem_write32(t, ZYNQ_SLCR_UNLOCK, ZYNQ_SLCR_UNLOCK_KEY); target_mem_write32(t, ZYNQ_SLCR_PSS_RST_CTRL, 1); /* Try hard reset too */ platform_srst_set_val(true); platform_srst_set_val(false); /* Spin until Xilinx reconnects us */ platform_timeout timeout; platform_timeout_set(&timeout, 1000); volatile struct exception e; do { TRY_CATCH (e, EXCEPTION_ALL) { apb_read(t, DBGDIDR); } } while (!platform_timeout_is_expired(&timeout) && e.type == EXCEPTION_ERROR); if (e.type == EXCEPTION_ERROR) raise_exception(e.type, e.msg); platform_delay(100); cortexa_attach(t); }
/** * Erase flash row by row */ static int efm32_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; /* Set WREN bit to enabel MSC write and erase functionality */ target_mem_write32(t, EFM32_MSC_WRITECTRL, 1); while (len) { /* Write address of first word in row to erase it */ target_mem_write32(t, EFM32_MSC_ADDRB, addr); target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM); /* Issue the erase command */ target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE ); /* Poll MSC Busy */ while ((target_mem_read32(t, EFM32_MSC_STATUS) & EFM32_MSC_STATUS_BUSY)) { if (target_check_error(t)) return -1; } addr += f->blocksize; len -= f->blocksize; } return 0; }
static int stm32f4_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { target *t = f->t; uint16_t sr; uint8_t sector = ((struct stm32f4_flash *)f)->base_sector + (addr - f->start)/f->blocksize; stm32f4_flash_unlock(t); while(len) { uint32_t cr = FLASH_CR_EOPIE | FLASH_CR_ERRIE | FLASH_CR_SER | (sector << 3); /* Flash page erase instruction */ target_mem_write32(t, FLASH_CR, cr); /* write address to FMA */ target_mem_write32(t, FLASH_CR, cr | FLASH_CR_STRT); /* Read FLASH_SR to poll for BSY bit */ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return -1; len -= f->blocksize; sector++; } /* Check for error */ sr = target_mem_read32(t, FLASH_SR); if(sr & SR_ERROR_MASK) return -1; return 0; }
static bool stm32l4_cmd_erase(target *t, uint32_t action) { const char spinner[] = "|/-\\"; int spinindex = 0; tc_printf(t, "Erasing flash... This may take a few seconds. "); stm32l4_flash_unlock(t); /* Flash erase action start instruction */ target_mem_write32(t, FLASH_CR, action); target_mem_write32(t, FLASH_CR, action | FLASH_CR_STRT); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { tc_printf(t, "\b%c", spinner[spinindex++ % 4]); if(target_check_error(t)) { tc_printf(t, "\n"); return false; } } tc_printf(t, "\n"); /* Check for error */ uint16_t sr = target_mem_read32(t, FLASH_SR); if (sr & FLASH_SR_ERROR_MASK) return false; return true; }
static bool stm32f4_cmd_erase_mass(target *t) { const char spinner[] = "|/-\\"; int spinindex = 0; gdb_out("Erasing flash... This may take a few seconds. "); stm32f4_flash_unlock(t); /* Flash mass erase start instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_MER); target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) { gdb_outf("\b%c", spinner[spinindex++ % 4]); if(target_check_error(t)) { gdb_out("\n"); return false; } } gdb_out("\n"); /* Check for error */ uint16_t sr = target_mem_read32(t, FLASH_SR); if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) return false; return true; }
static int nrf51_flash_write(struct target_flash *f, uint32_t dest, const void *src, size_t len) { target *t = f->t; uint32_t data[2 + len/4]; /* FIXME rewrite stub to use register args */ /* Construct data buffer used by stub */ data[0] = dest; data[1] = len; /* length must always be a multiple of 4 */ memcpy((uint8_t *)&data[2], src, len); /* Enable write */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return -1; /* Write stub and data to target ram and call stub */ target_mem_write(t, SRAM_BASE, nrf51_flash_write_stub, sizeof(nrf51_flash_write_stub)); target_mem_write(t, STUB_BUFFER_BASE, data, len + 8); cortexm_run_stub(t, SRAM_BASE, 0, 0, 0, 0); /* Return to read-only */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN); return 0; }
static int stm32f1_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint16_t sr; stm32f1_flash_unlock(t); while(len) { /* Flash page erase instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_PER); /* write address to FMA */ target_mem_write32(t, FLASH_AR, addr); /* Flash page erase start instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_PER); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return -1; len -= f->blocksize; addr += f->blocksize; } /* Check for error */ sr = target_mem_read32(t, FLASH_SR); if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) return -1; return 0; }
static void stm32f4_flash_unlock(target *t) { if (target_mem_read32(t, FLASH_CR) & FLASH_CR_LOCK) { /* Enable FPEC controller access */ target_mem_write32(t, FLASH_KEYR, KEY1); target_mem_write32(t, FLASH_KEYR, KEY2); } }
static bool stm32f1_cmd_option(target *t, int argc, char *argv[]) { uint32_t addr, val; uint32_t flash_obp_rdp_key; uint32_t rdprt; switch(t->idcode) { case 0x422: /* STM32F30x */ case 0x432: /* STM32F37x */ case 0x438: /* STM32F303x6/8 and STM32F328 */ case 0x440: /* STM32F0 */ case 0x446: /* STM32F303xD/E and STM32F398xE */ flash_obp_rdp_key = FLASH_OBP_RDP_KEY_F3; break; default: flash_obp_rdp_key = FLASH_OBP_RDP_KEY; } rdprt = target_mem_read32(t, FLASH_OBR) & FLASH_OBR_RDPRT; stm32f1_flash_unlock(t); target_mem_write32(t, FLASH_OPTKEYR, KEY1); target_mem_write32(t, 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) { tc_printf(t, "Device is Read Protected\n"); tc_printf(t, "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 { tc_printf(t, "usage: monitor option erase\n"); tc_printf(t, "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 = target_mem_read32(t, 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 = target_mem_read32(t, addr); tc_printf(t, "0x%08X: 0x%04X\n", addr, val & 0xFFFF); tc_printf(t, "0x%08X: 0x%04X\n", addr + 2, val >> 16); } return true; }
static bool stm32f1_option_erase(target *t) { /* Erase option bytes instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_OPTER | FLASH_CR_OPTWRE); target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_OPTER | FLASH_CR_OPTWRE); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; return true; }
int lmi_flash_erase(struct target_flash *f, uint32_t addr, size_t len) { target *t = f->t; while(len) { target_mem_write32(t, LMI_FLASH_FMA, addr); target_mem_write32(t, LMI_FLASH_FMC, LMI_FLASH_FMC_WRKEY | LMI_FLASH_FMC_ERASE); while (target_mem_read32(t, LMI_FLASH_FMC) & LMI_FLASH_FMC_ERASE); len -= BLOCK_SIZE; addr += BLOCK_SIZE; } return 0; }
/* Program flash */ static int msp432_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) { struct msp432_flash *mf = (struct msp432_flash *)f; target *t = f->t; /* Prepare RAM buffer in target */ target_mem_write(t, SRAM_WRITE_BUFFER, src, len); /* Unprotect sector, len is always < SECTOR_SIZE */ uint32_t old_prot = msp432_sector_unprotect(mf, dest); DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register)); /* Prepare input data */ uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA target_regs_read(t, regs); regs[0] = SRAM_WRITE_BUFFER; // Address of buffer to be flashed in R0 regs[1] = dest; // Flash address to be write to in R1 regs[2] = len; // Size of buffer to be flashed in R2 DEBUG("Writing 0x%04" PRIX32 " bytes at 0x%08" PRI_SIZET "\n", dest, len); /* Call ROM */ msp432_call_ROM(t, mf->FlashCtl_programMemory, regs); /* Restore original protection */ target_mem_write32(t, mf->flash_protect_register, old_prot); DEBUG("ROM return value: %"PRIu32"\n", regs[0]); // Result value in R0 is true for success return !regs[0]; }
/* Erase a single sector at addr calling the ROM routine*/ static bool msp432_sector_erase(struct target_flash *f, target_addr addr) { target *t = f->t; struct msp432_flash *mf = (struct msp432_flash *)f; /* Unprotect sector */ uint32_t old_prot = msp432_sector_unprotect(mf, addr); DEBUG("Flash protect: 0x%08"PRIX32"\n", target_mem_read32(t, mf->flash_protect_register)); /* Prepare input data */ uint32_t regs[t->regs_size / sizeof(uint32_t)]; // Use of VLA target_regs_read(t, regs); regs[0] = addr; // Address of sector to erase in R0 DEBUG("Erasing sector at 0x%08"PRIX32"\n", addr); /* Call ROM */ msp432_call_ROM(t, mf->FlashCtl_eraseSector, regs); // Result value in R0 is true for success DEBUG("ROM return value: %"PRIu32"\n", regs[0]); /* Restore original protection */ target_mem_write32(t, mf->flash_protect_register, old_prot); return !regs[0]; }
/** * Overloads the default cortexm reset function with a version that * removes the target from extended reset where required. */ static void samd_reset(target *t) { /** * SRST is not asserted here as it appears to reset the adiv5 * logic, meaning that subsequent adiv5_* calls PLATFORM_FATAL_ERROR. * * This is ok as normally you can just connect the debugger and go, * but if that's not possible (protection or SWCLK being used for * something else) then having SWCLK low on reset should get you * debug access (cold-plugging). TODO: Confirm this * * See the SAM D20 datasheet §12.6 Debug Operation for more * details. * * jtagtap_srst(true); * jtagtap_srst(false); */ /* Read DHCSR here to clear S_RESET_ST bit before reset */ target_mem_read32(t, CORTEXM_DHCSR); /* Request system reset from NVIC: SRST doesn't work correctly */ /* This could be VECTRESET: 0x05FA0001 (reset only core) * or SYSRESETREQ: 0x05FA0004 (system reset) */ target_mem_write32(t, CORTEXM_AIRCR, CORTEXM_AIRCR_VECTKEY | CORTEXM_AIRCR_SYSRESETREQ); /* Exit extended reset */ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) & SAMD_STATUSA_CRSTEXT) { /* Write bit to clear from extended reset */ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_CRSTEXT); } /* Poll for release from reset */ while (target_mem_read32(t, CORTEXM_DHCSR) & CORTEXM_DHCSR_S_RESET_ST); /* Reset DFSR flags */ target_mem_write32(t, CORTEXM_DFSR, CORTEXM_DFSR_RESETALL); /* Clear any target errors */ target_check_error(t); }
static bool stm32f4_option_write(target *t, uint32_t *val, int count) { target_mem_write32(t, FLASH_OPTKEYR, OPTKEY1); target_mem_write32(t, FLASH_OPTKEYR, OPTKEY2); while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return -1; /* WRITE option bytes instruction */ if (((t->idcode == ID_STM32F42X) || (t->idcode == ID_STM32F46X) || (t->idcode == ID_STM32F72X) || (t->idcode == ID_STM32F74X) || (t->idcode == ID_STM32F76X)) && (count > 1)) /* Checkme: Do we need to read old value and then set it? */ target_mem_write32(t, FLASH_OPTCR + 4, val[1]); if ((t->idcode == ID_STM32F72X) && (count > 2)) target_mem_write32(t, FLASH_OPTCR + 8, val[2]); target_mem_write32(t, FLASH_OPTCR, val[0]); target_mem_write32(t, FLASH_OPTCR, val[0] | FLASH_OPTCR_OPTSTRT); /* Read FLASH_SR to poll for BSY bit */ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; target_mem_write32(t, FLASH_OPTCR, FLASH_OPTCR_OPTLOCK); return true; }
static bool stm32f4_option_write(target *t, uint32_t value) { target_mem_write32(t, FLASH_OPTKEYR, OPTKEY1); target_mem_write32(t, FLASH_OPTKEYR, OPTKEY2); value &= ~FLASH_OPTCR_RESERVED; while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return -1; /* WRITE option bytes instruction */ target_mem_write32(t, FLASH_OPTCR, value); target_mem_write32(t, FLASH_OPTCR, value | FLASH_OPTCR_OPTSTRT); /* Read FLASH_SR to poll for BSY bit */ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; target_mem_write32(t, FLASH_OPTCR, value | FLASH_OPTCR_OPTLOCK); return true; }
/* Protect or unprotect the sector containing address */ static inline uint32_t msp432_sector_unprotect(struct msp432_flash *mf, target_addr addr) { /* Read the old protection register */ uint32_t old_mask = target_mem_read32(mf->f.t, mf->flash_protect_register); /* Find the bit representing the sector and set it to 0 */ uint32_t sec_mask = ~(1u << ((addr - mf->f.start) / SECTOR_SIZE)); /* Clear the potection bit */ sec_mask &= old_mask; target_mem_write32(mf->f.t, mf->flash_protect_register, sec_mask); return old_mask; }
static bool stm32f1_cmd_erase_mass(target *t) { stm32f1_flash_unlock(t); /* Flash mass erase start instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_MER); target_mem_write32(t, FLASH_CR, FLASH_CR_STRT | FLASH_CR_MER); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; /* Check for error */ uint16_t sr = target_mem_read32(t, FLASH_SR); if ((sr & SR_ERROR_MASK) || !(sr & SR_EOP)) return false; return true; }
static int nrf51_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; /* Enable erase */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return -1; while (len) { if (addr == NRF51_UICR) { // Special Case /* Write to the ERASE_UICR register to erase */ target_mem_write32(t, NRF51_NVMC_ERASEUICR, 0x1); } else { // Standard Flash Page /* Write address of first word in page to erase it */ target_mem_write32(t, NRF51_NVMC_ERASEPAGE, addr); } /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return -1; addr += f->blocksize; len -= f->blocksize; } /* Return to read-only */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return -1; return 0; }
static int stm32l4_flash_erase(struct target_flash *f, target_addr addr, size_t len) { target *t = f->t; uint16_t sr; uint32_t bank1_start = ((struct stm32l4_flash *)f)->bank1_start; uint32_t page; stm32l4_flash_unlock(t); page = (addr - 0x08000000) / PAGE_SIZE; while(len) { uint32_t cr; cr = FLASH_CR_PER | (page << FLASH_CR_PAGE_SHIFT ); if (addr >= bank1_start) cr |= FLASH_CR_BKER; /* Flash page erase instruction */ target_mem_write32(t, FLASH_CR, cr); /* write address to FMA */ cr |= FLASH_CR_STRT; target_mem_write32(t, FLASH_CR, cr); /* Read FLASH_SR to poll for BSY bit */ while(target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return -1; len -= PAGE_SIZE; addr += PAGE_SIZE; page++; } /* Check for error */ sr = target_mem_read32(t, FLASH_SR); if(sr & FLASH_SR_ERROR_MASK) return -1; return 0; }
/** * Overloads the default cortexm halt_resume function with a version * that removes the target from extended reset where required. * * Only required for SAM D20 _Revision B_ Silicon */ static void samd20_revB_halt_resume(target *t, bool step) { cortexm_halt_resume(t, step); /* ---- Additional ---- */ /* Exit extended reset */ if (target_mem_read32(t, SAMD_DSU_CTRLSTAT) & SAMD_STATUSA_CRSTEXT) { /* Write bit to clear from extended reset */ target_mem_write32(t, SAMD_DSU_CTRLSTAT, SAMD_STATUSA_CRSTEXT); } }
static bool stm32f1_option_write_erased(target *t, uint32_t addr, uint16_t value) { if (value == 0xffff) return true; /* Erase option bytes instruction */ target_mem_write32(t, FLASH_CR, FLASH_CR_OPTPG | FLASH_CR_OPTWRE); target_mem_write16(t, addr, value); /* Read FLASH_SR to poll for BSY bit */ while (target_mem_read32(t, FLASH_SR) & FLASH_SR_BSY) if(target_check_error(t)) return false; return true; }
static bool nrf51_cmd_erase_all(target *t) { tc_printf(t, "erase..\n"); /* Enable erase */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_EEN); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return false; /* Erase all */ target_mem_write32(t, NRF51_NVMC_ERASEALL, 1); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return false; return true; }
static int nrf51_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len) { target *t = f->t; /* Enable write */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_WEN); /* Poll for NVMC_READY */ while (target_mem_read32(t, NRF51_NVMC_READY) == 0) if(target_check_error(t)) return -1; /* Write stub and data to target ram and call stub */ target_mem_write(t, SRAM_BASE, nrf51_flash_write_stub, sizeof(nrf51_flash_write_stub)); target_mem_write(t, STUB_BUFFER_BASE, src, len); int ret = cortexm_run_stub(t, SRAM_BASE, dest, STUB_BUFFER_BASE, len, 0); /* Return to read-only */ target_mem_write32(t, NRF51_NVMC_CONFIG, NRF51_NVMC_CONFIG_REN); return ret; }
/** * Uses the MSC ERASEMAIN0 command to erase the entire flash */ static bool efm32_cmd_erase_all(target *t) { /* Set WREN bit to enabel MSC write and erase functionality */ target_mem_write32(t, EFM32_MSC_WRITECTRL, 1); /* Unlock mass erase */ target_mem_write32(t, EFM32_MSC_MASSLOCK, EFM32_MSC_MASSLOCK_LOCKKEY); /* Erase operation */ target_mem_write32(t, EFM32_MSC_WRITECMD, EFM32_MSC_WRITECMD_ERASEMAIN0); /* Poll MSC Busy */ while ((target_mem_read32(t, EFM32_MSC_STATUS) & EFM32_MSC_STATUS_BUSY)) { if (target_check_error(t)) return false; } /* Relock mass erase */ target_mem_write32(t, EFM32_MSC_MASSLOCK, 0); tc_printf(t, "Erase successful!\n"); return true; }
static int sam3x_flash_cmd(target *t, uint32_t base, uint8_t cmd, uint16_t arg) { DEBUG("%s: base = 0x%08x cmd = 0x%02X, arg = 0x%06X\n", __func__, base, cmd, arg); target_mem_write32(t, EEFC_FCR(base), EEFC_FCR_FKEY | cmd | ((uint32_t)arg << 8)); while (!(target_mem_read32(t, EEFC_FSR(base)) & EEFC_FSR_FRDY)) if(target_check_error(t)) return -1; uint32_t sr = target_mem_read32(t, EEFC_FSR(base)); return sr & EEFC_FSR_ERROR; }
static void stm32f1_flash_unlock(target *t) { target_mem_write32(t, FLASH_KEYR, KEY1); target_mem_write32(t, FLASH_KEYR, KEY2); }