adiv5/romtable: Prepare CortexM devices to read the ROMTABLE
It seems, writing to DHCSR fails silent when the device is sleeping. Reading DHCS during sleep may return nonsense. Repeated write may at some point catch the device running and succeed. With devices sleeping for long time and running on faster clock the chance for a successful hotplug gets smaller. - Try hard to halt a sleeping device - Prepare vector catch and enable all debug units by TRACENA - Release reset - Apply device specific fixes -- STM32F7: Store old value of DBGMCU_CR, enable debug in sleep in DBGMCU before reading PIDR and restore DBGMCU on detach. Signed-off-by: Uwe Bonnes <bon@elektron.ikp.physik.tu-darmstadt.de>
This commit is contained in:
parent
ceaee2a11e
commit
9bb2807706
|
@ -36,6 +36,13 @@
|
|||
* are consistently named and accessible when needed in the codebase.
|
||||
*/
|
||||
|
||||
/* Values from ST RM0436 (STM32MP157), 66.9 APx_IDR
|
||||
* and ST RM0438 (STM32L5) 52.3.1, AP_IDR */
|
||||
#define ARM_AP_TYPE_AHB 1
|
||||
#define ARM_AP_TYPE_APB 3
|
||||
#define ARM_AP_TYPE_AXI 4
|
||||
#define ARM_AP_TYPE_AHB5 5
|
||||
|
||||
/* ROM table CIDR values */
|
||||
#define CIDR0_OFFSET 0xFF0 /* DBGCID0 */
|
||||
#define CIDR1_OFFSET 0xFF4 /* DBGCID1 */
|
||||
|
@ -299,6 +306,99 @@ uint64_t adiv5_ap_read_pidr(ADIv5_AP_t *ap, uint32_t addr)
|
|||
return pidr;
|
||||
}
|
||||
|
||||
/* Prepare to read SYSROM and SYSROM PIDR
|
||||
*
|
||||
* Try hard to halt, if not connecting under reset
|
||||
* Request TRCENA and default vector catch
|
||||
* release from reset when connecting under reset.
|
||||
*
|
||||
* E.g. Stm32F7
|
||||
* - fails reading romtable in WFI
|
||||
* - fails with some AP accesses when romtable is read under reset.
|
||||
* - fails reading some ROMTABLE entries w/o TRCENA
|
||||
* - fails reading outside SYSROM when halted from WFI and
|
||||
* DBGMCU_CR not set.
|
||||
*
|
||||
* Keep a copy of DEMCR at startup to restore with exit, to
|
||||
* not interrupt tracing initialed by the CPU.
|
||||
*/
|
||||
static bool cortexm_prepare(ADIv5_AP_t *ap)
|
||||
{
|
||||
platform_timeout to ;
|
||||
platform_timeout_set(&to, cortexm_wait_timeout);
|
||||
uint32_t dhcsr_ctl = CORTEXM_DHCSR_DBGKEY | CORTEXM_DHCSR_C_DEBUGEN |
|
||||
CORTEXM_DHCSR_C_HALT;
|
||||
uint32_t dhcsr_valid = CORTEXM_DHCSR_S_HALT | CORTEXM_DHCSR_C_DEBUGEN;
|
||||
#ifdef PLATFORM_HAS_DEBUG
|
||||
uint32_t start_time = platform_time_ms();
|
||||
#endif
|
||||
uint32_t dhcsr;
|
||||
bool reset_seen = false;
|
||||
while (true) {
|
||||
adiv5_mem_write(ap, CORTEXM_DHCSR, &dhcsr_ctl, sizeof(dhcsr_ctl));
|
||||
dhcsr = adiv5_mem_read32(ap, CORTEXM_DHCSR);
|
||||
/* On a sleeping STM32F7, invalid DHCSR reads with e.g. 0xffffffff and
|
||||
* 0x0xA05F0000 may happen.
|
||||
* M23/33 will have S_SDE set when debug is allowed
|
||||
*/
|
||||
if ((dhcsr != 0xffffffff) && /* Invalid read */
|
||||
((dhcsr & 0xf000fff0) == 0)) {/* Check RAZ bits */
|
||||
if ((dhcsr & CORTEXM_DHCSR_S_RESET_ST) && !reset_seen) {
|
||||
if (connect_assert_srst)
|
||||
break;
|
||||
reset_seen = true;
|
||||
continue;
|
||||
}
|
||||
if ((dhcsr & dhcsr_valid) == dhcsr_valid) { /* Halted */
|
||||
DEBUG_INFO("Halt via DHCSR: success %08" PRIx32 " after %"
|
||||
PRId32 "ms\n",
|
||||
dhcsr, platform_time_ms() - start_time);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (platform_timeout_is_expired(&to)) {
|
||||
DEBUG_WARN("Halt via DHCSR: Failure DHCSR %08" PRIx32 " after % "
|
||||
PRId32 "ms\nTry again, evt. with longer timeout or "
|
||||
"connect under reset\n",
|
||||
dhcsr, platform_time_ms() - start_time);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
ap->ap_cortexm_demcr = adiv5_mem_read32(ap, CORTEXM_DEMCR);
|
||||
uint32_t demcr = CORTEXM_DEMCR_TRCENA | CORTEXM_DEMCR_VC_HARDERR |
|
||||
CORTEXM_DEMCR_VC_CORERESET;
|
||||
adiv5_mem_write(ap, CORTEXM_DEMCR, &demcr, sizeof(demcr));
|
||||
platform_timeout_set(&to, cortexm_wait_timeout);
|
||||
platform_srst_set_val(false);
|
||||
while (1) {
|
||||
dhcsr = adiv5_mem_read32(ap, CORTEXM_DHCSR);
|
||||
if (!(dhcsr & CORTEXM_DHCSR_S_RESET_ST))
|
||||
break;
|
||||
if (platform_timeout_is_expired(&to)) {
|
||||
DEBUG_WARN("Error releasing from srst\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/* Apply device specific settings for successfull Romtable scan
|
||||
*
|
||||
* STM32F7 in WFI will not read ROMTABLE when using WFI
|
||||
*/
|
||||
if ((ap->dp->targetid >> 1 & 0x7ff) == 0x20) {
|
||||
uint32_t dbgmcu_cr = 7;
|
||||
uint32_t dbgmcu_cr_addr = 0xE0042004;
|
||||
switch ((ap->dp->targetid >> 16) & 0xfff) {
|
||||
case 0x449:
|
||||
case 0x451:
|
||||
case 0x452:
|
||||
ap->ap_storage = adiv5_mem_read32(ap, dbgmcu_cr_addr);
|
||||
dbgmcu_cr = ap->ap_storage | 7;
|
||||
adiv5_mem_write(ap, dbgmcu_cr_addr, &dbgmcu_cr, sizeof(dbgmcu_cr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool adiv5_component_probe(ADIv5_AP_t *ap, uint32_t addr, int recursion, int num_entry)
|
||||
{
|
||||
(void) num_entry;
|
||||
|
@ -490,6 +590,26 @@ ADIv5_AP_t *adiv5_new_ap(ADIv5_DP_t *dp, uint8_t apsel)
|
|||
DEBUG_INFO("AP %3d: IDR=%08"PRIx32" CFG=%08"PRIx32" BASE=%08" PRIx32
|
||||
" CSW=%08"PRIx32"\n", apsel, ap->idr, cfg, ap->base, ap->csw);
|
||||
#endif
|
||||
if (!apsel && ((ap->idr & 0xf) == ARM_AP_TYPE_AHB)) {
|
||||
/* Test for protected Atmel devices. Access outside DSU fails.
|
||||
* For protected device, continue with Rom Table anyways.
|
||||
*/
|
||||
adiv5_dp_error(ap->dp);
|
||||
adiv5_mem_read32(ap, CORTEXM_DHCSR);
|
||||
if ( adiv5_dp_error(ap->dp) & ADIV5_DP_CTRLSTAT_STICKYERR) {
|
||||
uint32_t err = adiv5_dp_error(ap->dp);
|
||||
if (err & ADIV5_DP_CTRLSTAT_STICKYERR) {
|
||||
DEBUG_WARN("...\nHit error on DHCSR read. Suspect protected Atmel "
|
||||
"part, skipping to PIDR check.\n");
|
||||
}
|
||||
} else {
|
||||
if (!cortexm_prepare(ap)) {
|
||||
free(ap);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
adiv5_ap_ref(ap);
|
||||
return ap;
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,8 @@ struct ADIv5_AP_s {
|
|||
uint32_t idr;
|
||||
uint32_t base;
|
||||
uint32_t csw;
|
||||
uint32_t ap_cortexm_demcr; /* Copy of demcr when starting */
|
||||
uint32_t ap_storage; /* E.g to hold STM32F7 initial DBGMCU_CR value.*/
|
||||
};
|
||||
|
||||
#if PC_HOSTED == 0
|
||||
|
|
|
@ -265,6 +265,7 @@ static void cortexm_priv_free(void *priv)
|
|||
|
||||
static bool cortexm_forced_halt(target *t)
|
||||
{
|
||||
DEBUG_WARN("cortexm_forced_halt\n");
|
||||
target_halt_request(t);
|
||||
platform_srst_set_val(false);
|
||||
uint32_t dhcsr = 0;
|
||||
|
@ -490,6 +491,9 @@ void cortexm_detach(target *t)
|
|||
for(i = 0; i < priv->hw_watchpoint_max; i++)
|
||||
target_mem_write32(t, CORTEXM_DWT_FUNC(i), 0);
|
||||
|
||||
/* Restort DEMCR*/
|
||||
ADIv5_AP_t *ap = cortexm_ap(t);
|
||||
target_mem_write32(t, CORTEXM_DEMCR, ap->ap_cortexm_demcr);
|
||||
/* Disable debug */
|
||||
target_mem_write32(t, CORTEXM_DHCSR, CORTEXM_DHCSR_DBGKEY);
|
||||
/* Add some clock cycles to get the CPU running again.*/
|
||||
|
|
|
@ -197,7 +197,8 @@ char *stm32f4_get_chip_name(uint32_t idcode)
|
|||
|
||||
static void stm32f7_detach(target *t)
|
||||
{
|
||||
target_mem_write32(t, DBGMCU_CR, t->target_storage);
|
||||
ADIv5_AP_t *ap = cortexm_ap(t);
|
||||
target_mem_write32(t, DBGMCU_CR, ap->ap_storage);
|
||||
cortexm_detach(t);
|
||||
}
|
||||
|
||||
|
@ -306,8 +307,6 @@ static bool stm32f4_attach(target *t)
|
|||
bool use_dual_bank = false;
|
||||
target_mem_map_free(t);
|
||||
if (is_f7) {
|
||||
t->target_storage = target_mem_read32(t, DBGMCU_CR);
|
||||
target_mem_write32(t, DBGMCU_CR, DBG_SLEEP);
|
||||
target_add_ram(t, 0x00000000, 0x4000); /* 16 k ITCM Ram */
|
||||
target_add_ram(t, 0x20000000, 0x20000); /* 128 k DTCM Ram */
|
||||
target_add_ram(t, 0x20020000, 0x60000); /* 384 k Ram */
|
||||
|
|
|
@ -188,11 +188,6 @@ static bool stm32h7_attach(target *t)
|
|||
{
|
||||
if (!cortexm_attach(t))
|
||||
return false;
|
||||
/* RM0433 Rev 4 is not really clear, what bits are needed.
|
||||
* Set all possible relevant bits for now. */
|
||||
uint32_t dbgmcu_cr = target_mem_read32(t, DBGMCU_CR);
|
||||
t->target_storage = dbgmcu_cr;
|
||||
target_mem_write32(t, DBGMCU_CR, DBGSLEEP_D1 | D1DBGCKEN);
|
||||
/* If IWDG runs as HARDWARE watchdog (44.3.4) erase
|
||||
* will be aborted by the Watchdog and erase fails!
|
||||
* Setting IWDG_KR to 0xaaaa does not seem to help!*/
|
||||
|
@ -234,6 +229,12 @@ bool stm32h7_probe(target *t)
|
|||
t->attach = stm32h7_attach;
|
||||
t->detach = stm32h7_detach;
|
||||
target_add_commands(t, stm32h7_cmd_list, stm32h74_driver_str);
|
||||
t->target_storage = target_mem_read32(t, DBGMCU_CR);
|
||||
/* RM0433 Rev 4 is not really clear, what bits are needed in DBGMCU_CR.
|
||||
* Maybe more flags needed?
|
||||
*/
|
||||
uint32_t dbgmcu_cr = DBGSLEEP_D1 | D1DBGCKEN;
|
||||
target_mem_write32(t, DBGMCU_CR, dbgmcu_cr);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue