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 void apb_write(target *t, uint16_t reg, uint32_t val) { struct cortexa_priv *priv = t->priv; ADIv5_AP_t *ap = priv->apb; uint32_t addr = priv->base + 4*reg; adiv5_ap_write(ap, ADIV5_AP_TAR, addr); adiv5_dp_low_access(ap->dp, ADIV5_LOW_WRITE, ADIV5_AP_DRW, val); }
static uint32_t apb_read(target *t, uint16_t reg) { struct cortexa_priv *priv = t->priv; ADIv5_AP_t *ap = priv->apb; uint32_t addr = priv->base + 4*reg; adiv5_ap_write(ap, ADIV5_AP_TAR, addr); adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_AP_DRW, 0); return adiv5_dp_low_access(ap->dp, ADIV5_LOW_READ, ADIV5_DP_RDBUFF, 0); }
bool cortexa_probe(ADIv5_AP_t *apb, uint32_t debug_base) { target *t; t = target_new(); adiv5_ap_ref(apb); struct cortexa_priv *priv = calloc(1, sizeof(*priv)); t->priv = priv; t->priv_free = free; priv->apb = apb; /* FIXME Find a better way to find the AHB. This is likely to be * device specific. */ priv->ahb = adiv5_new_ap(apb->dp, 0); adiv5_ap_ref(priv->ahb); if ((priv->ahb->idr & 0xfffe00f) == 0x4770001) { /* This is an AHB */ t->mem_read = cortexa_mem_read; t->mem_write = cortexa_mem_write; } else { /* This is not an AHB, fall back to slow APB access */ adiv5_ap_unref(priv->ahb); priv->ahb = NULL; t->mem_read = cortexa_slow_mem_read; t->mem_write = cortexa_slow_mem_write; } priv->base = debug_base; /* Set up APB CSW, we won't touch this again */ uint32_t csw = apb->csw | ADIV5_AP_CSW_SIZE_WORD; adiv5_ap_write(apb, ADIV5_AP_CSW, csw); uint32_t dbgdidr = apb_read(t, DBGDIDR); priv->hw_breakpoint_max = ((dbgdidr >> 24) & 15)+1; t->check_error = cortexa_check_error; t->driver = cortexa_driver_str; t->attach = cortexa_attach; t->detach = cortexa_detach; t->tdesc = tdesc_cortex_a; t->regs_read = cortexa_regs_read; t->regs_write = cortexa_regs_write; t->reset = cortexa_reset; t->halt_request = cortexa_halt_request; t->halt_poll = cortexa_halt_poll; t->halt_resume = cortexa_halt_resume; t->regs_size = sizeof(priv->reg_cache); t->breakwatch_set = cortexa_breakwatch_set; t->breakwatch_clear = cortexa_breakwatch_clear; return true; }
static bool kinetis_mdm_cmd_erase_mass(target *t) { ADIv5_AP_t *ap = t->priv; uint32_t status, control; status = adiv5_ap_read(ap, MDM_STATUS); control = adiv5_ap_read(ap, MDM_CONTROL); tc_printf(t, "Requesting mass erase (status = 0x%"PRIx32")\n", status); if (!(status & MDM_STATUS_MASS_ERASE_ENABLED)) { tc_printf(t, "ERROR: Mass erase disabled!\n"); return false; } if (!(status & MDM_STATUS_FLASH_READY)) { tc_printf(t, "ERROR: Flash not ready!\n"); return false; } if (status & MDM_STATUS_MASS_ERASE_ACK) { tc_printf(t, "ERROR: Mass erase already in progress!\n"); return false; } adiv5_ap_write(ap, MDM_CONTROL, MDM_CONTROL_MASS_ERASE); do { status = adiv5_ap_read(ap, MDM_STATUS); } while (!(status & MDM_STATUS_MASS_ERASE_ACK)); tc_printf(t, "Mass erase acknowledged\n"); do { control = adiv5_ap_read(ap, MDM_CONTROL); } while (!(control & MDM_CONTROL_MASS_ERASE)); tc_printf(t, "Mass erase complete\n"); return true; }