use std::{
sync::Arc,
thread,
time::{Duration, Instant},
};
use crate::{
architecture::arm::{
ap::{AccessPort, ApAccess, GenericAp, MemoryAp, DRW, IDR, TAR},
communication_interface::{FlushableArmAccess, Initialized},
core::armv7m::{Aircr, Demcr, Dhcsr},
dp::{Abort, Ctrl, DpAccess, Select, DPIDR},
memory::adi_v5_memory_interface::ArmProbe,
ApAddress, ArmCommunicationInterface, ArmError, DapAccess, DpAddress,
},
core::MemoryMappedRegister,
};
use super::ArmDebugSequence;
fn debug_port_start(
interface: &mut ArmCommunicationInterface<Initialized>,
dp: DpAddress,
select: Select,
) -> Result<bool, ArmError> {
interface.write_dp_register(dp, select)?;
let ctrl = interface.read_dp_register::<Ctrl>(dp)?;
let powered_down = !(ctrl.csyspwrupack() && ctrl.cdbgpwrupack());
if powered_down {
let mut ctrl = Ctrl(0);
ctrl.set_cdbgpwrupreq(true);
ctrl.set_csyspwrupreq(true);
interface.write_dp_register(dp, ctrl)?;
let start = Instant::now();
let mut timeout = true;
while start.elapsed() < Duration::from_micros(100_0000) {
let ctrl = interface.read_dp_register::<Ctrl>(dp)?;
if ctrl.csyspwrupack() && ctrl.cdbgpwrupack() {
timeout = false;
break;
}
}
if timeout {
return Err(ArmError::Timeout);
}
let mut ctrl = Ctrl(0);
ctrl.set_cdbgpwrupreq(true);
ctrl.set_csyspwrupreq(true);
ctrl.set_mask_lane(0b1111);
interface.write_dp_register(dp, ctrl)?;
let mut abort = Abort(0);
abort.set_orunerrclr(true);
abort.set_wderrclr(true);
abort.set_stkerrclr(true);
abort.set_stkcmpclr(true);
interface.write_dp_register(dp, abort)?;
}
Ok(powered_down)
}
pub struct LPC55S69(());
impl LPC55S69 {
pub fn create() -> Arc<dyn ArmDebugSequence> {
Arc::new(Self(()))
}
}
impl ArmDebugSequence for LPC55S69 {
fn debug_port_start(
&self,
interface: &mut ArmCommunicationInterface<Initialized>,
dp: DpAddress,
) -> Result<(), ArmError> {
tracing::info!("debug_port_start");
let powered_down = self::debug_port_start(interface, dp, Select(0))?;
if powered_down {
enable_debug_mailbox(interface, dp)?;
}
Ok(())
}
fn reset_catch_set(
&self,
interface: &mut dyn ArmProbe,
_core_type: crate::CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut reset_vector = 0xffff_ffff;
let mut demcr = Demcr(interface.read_word_32(Demcr::ADDRESS)?);
demcr.set_vc_corereset(false);
interface.write_word_32(Demcr::ADDRESS, demcr.into())?;
interface.write_word_32(0x40034010, 0x00000000)?; interface.write_word_32(0x40034014, 0x00000000)?; interface.write_word_32(0x40034080, 0x00000000)?; interface.write_word_32(0x40034084, 0x00000000)?; interface.write_word_32(0x40034088, 0x00000000)?; interface.write_word_32(0x4003408C, 0x00000000)?; interface.write_word_32(0x40034090, 0x00000000)?; interface.write_word_32(0x40034094, 0x00000000)?; interface.write_word_32(0x40034098, 0x00000000)?; interface.write_word_32(0x4003409C, 0x00000000)?;
interface.write_word_32(0x40034FE8, 0x0000000F)?; interface.write_word_32(0x40034000, 0x00000003)?; interface.flush()?;
let start = Instant::now();
let mut timeout = true;
while start.elapsed() < Duration::from_micros(10_0000) {
let value = interface.read_word_32(0x40034FE0)?;
if (value & 0x4) == 0x4 {
timeout = false;
break;
}
}
if timeout {
tracing::warn!("Failed: Wait for flash word read to finish");
return Err(ArmError::Timeout);
}
if (interface.read_word_32(0x4003_4fe0)? & 0xB) == 0 {
tracing::info!("No Error reading Flash Word with Reset Vector");
reset_vector = interface.read_word_32(0x0000_0004)?;
}
if reset_vector != 0xffff_ffff {
tracing::info!("Breakpoint on user application reset vector");
interface.write_word_32(0xE000_2008, reset_vector | 1)?;
interface.write_word_32(0xE000_2000, 3)?;
}
if reset_vector == 0xffff_ffff {
tracing::info!("Enable reset vector catch");
let mut demcr = Demcr(interface.read_word_32(Demcr::ADDRESS)?);
demcr.set_vc_corereset(true);
interface.write_word_32(Demcr::ADDRESS, demcr.into())?;
}
let _ = interface.read_word_32(Dhcsr::ADDRESS)?;
tracing::debug!("reset_catch_set -- done");
Ok(())
}
fn reset_catch_clear(
&self,
interface: &mut dyn ArmProbe,
_core_type: crate::CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
interface.write_word_32(0xE000_2008, 0x0)?;
interface.write_word_32(0xE000_2000, 0x2)?;
let mut demcr = Demcr(interface.read_word_32(Demcr::ADDRESS)?);
demcr.set_vc_corereset(false);
interface.write_word_32(Demcr::ADDRESS, demcr.into())
}
fn reset_system(
&self,
interface: &mut dyn ArmProbe,
_core_type: crate::CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_sysresetreq(true);
let mut result = interface.write_word_32(Aircr::ADDRESS, aircr.into());
if result.is_ok() {
result = interface.flush();
}
if let Err(e) = result {
tracing::debug!("Error requesting reset: {:?}", e);
}
tracing::info!("Waiting after reset");
thread::sleep(Duration::from_millis(10));
wait_for_stop_after_reset(interface)
}
}
fn wait_for_stop_after_reset(memory: &mut dyn ArmProbe) -> Result<(), ArmError> {
tracing::info!("Wait for stop after reset");
thread::sleep(Duration::from_millis(10));
let dp = memory.ap().ap_address().dp;
let interface = memory.get_arm_communication_interface()?;
enable_debug_mailbox(interface, dp)?;
let mut timeout = true;
let start = Instant::now();
tracing::info!("Polling for reset");
while start.elapsed() < Duration::from_micros(50_0000) {
let dhcsr = Dhcsr(memory.read_word_32(Dhcsr::ADDRESS)?);
if !dhcsr.s_reset_st() {
timeout = false;
break;
}
}
if timeout {
return Err(ArmError::Timeout);
}
let dhcsr = Dhcsr(memory.read_word_32(Dhcsr::ADDRESS)?);
if !dhcsr.s_halt() {
let mut dhcsr = Dhcsr(0);
dhcsr.enable_write();
dhcsr.set_c_halt(true);
dhcsr.set_c_debugen(true);
memory.write_word_32(Dhcsr::ADDRESS, dhcsr.into())?;
}
Ok(())
}
fn enable_debug_mailbox(
interface: &mut ArmCommunicationInterface<Initialized>,
dp: DpAddress,
) -> Result<(), ArmError> {
tracing::info!("LPC55xx connect srcipt start");
let ap = ApAddress { dp, ap: 2 };
let status: IDR = interface.read_ap_register(GenericAp::new(ap))?;
tracing::info!("APIDR: {:?}", status);
tracing::info!("APIDR: 0x{:08X}", u32::from(status));
let status: u32 = interface.read_dp_register::<DPIDR>(dp)?.into();
tracing::info!("DPIDR: 0x{:08X}", status);
interface.write_raw_ap_register(ap, 0x0, 0x0000_0021)?;
interface.flush()?;
thread::sleep(Duration::from_micros(30000));
let _ = interface.read_raw_ap_register(ap, 0)?;
interface.write_raw_ap_register(ap, 0x4, 0x0000_0007)?;
interface.flush()?;
thread::sleep(Duration::from_micros(30000));
let _ = interface.read_raw_ap_register(ap, 8)?;
tracing::info!("LPC55xx connect srcipt end");
Ok(())
}
pub struct MIMXRT10xx(());
impl MIMXRT10xx {
pub fn create() -> Arc<dyn ArmDebugSequence> {
Arc::new(Self(()))
}
fn check_core_type(&self, core_type: crate::CoreType) -> Result<(), ArmError> {
const EXPECTED: crate::CoreType = crate::CoreType::Armv7em;
if core_type != EXPECTED {
tracing::warn!(
"MIMXRT10xx core type supplied as {core_type:?}, but the actual core is a {EXPECTED:?}"
);
}
Ok(())
}
}
impl ArmDebugSequence for MIMXRT10xx {
fn reset_system(
&self,
interface: &mut dyn ArmProbe,
core_type: crate::CoreType,
_: Option<u64>,
) -> Result<(), ArmError> {
self.check_core_type(core_type)?;
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_sysresetreq(true);
interface.write_word_32(Aircr::ADDRESS, aircr.into()).ok();
interface.flush().ok();
std::thread::sleep(Duration::from_millis(100));
interface.read_word_32(Dhcsr::ADDRESS)?;
Ok(())
}
}
pub struct MIMXRT11xx(());
impl MIMXRT11xx {
pub fn create() -> Arc<dyn ArmDebugSequence> {
Arc::new(Self(()))
}
fn prepare_cm7_trap_code(
&self,
ap: MemoryAp,
interface: &mut ArmCommunicationInterface<Initialized>,
) -> Result<(), ArmError> {
const START: u32 = 0x2001FF00;
const IOMUX_LPSR_GPR26: u32 = 0x40C0C068;
interface.write_ap_register(ap, TAR { address: START })?;
interface.write_ap_register(ap, DRW { data: START + 0x20 })?;
interface.write_ap_register(ap, TAR { address: START + 4 })?;
interface.write_ap_register(ap, DRW { data: 0x23105 })?;
interface.write_ap_register(
ap,
TAR {
address: IOMUX_LPSR_GPR26,
},
)?;
interface.write_ap_register(ap, DRW { data: START >> 7 })?;
Ok(())
}
fn prepare_cm4_trap_code(
&self,
ap: MemoryAp,
interface: &mut ArmCommunicationInterface<Initialized>,
) -> Result<(), ArmError> {
const START: u32 = 0x20250000;
const IOMUX_LPSR_GPR0: u32 = 0x40c0c000;
const IOMUX_LPSR_GPR1: u32 = 0x40c0c004;
interface.write_ap_register(ap, TAR { address: START })?;
interface.write_ap_register(ap, DRW { data: START + 0x20 })?;
interface.write_ap_register(ap, TAR { address: START + 4 })?;
interface.write_ap_register(ap, DRW { data: 0x23F041 })?;
interface.write_ap_register(
ap,
TAR {
address: IOMUX_LPSR_GPR0,
},
)?;
interface.write_ap_register(
ap,
DRW {
data: START & 0xFFFF,
},
)?;
interface.write_ap_register(
ap,
TAR {
address: IOMUX_LPSR_GPR1,
},
)?;
interface.write_ap_register(ap, DRW { data: START >> 16 })?;
Ok(())
}
fn release_cm4(
&self,
ap: MemoryAp,
interface: &mut ArmCommunicationInterface<Initialized>,
) -> Result<(), ArmError> {
const SRC_SCR: u32 = 0x40c04000;
interface.write_ap_register(ap, TAR { address: SRC_SCR })?;
interface.write_ap_register(ap, DRW { data: 1 })?;
Ok(())
}
fn change_reset_modes(
&self,
ap: MemoryAp,
interface: &mut ArmCommunicationInterface<Initialized>,
) -> Result<(), ArmError> {
const SRC_SBMR: u32 = 0x40c04004;
interface.write_ap_register(ap, TAR { address: SRC_SBMR })?;
let DRW { data: mut src_sbmr } = interface.read_ap_register(ap)?;
src_sbmr |= 0xF << 10; interface.write_ap_register(ap, DRW { data: src_sbmr })?;
Ok(())
}
}
impl ArmDebugSequence for MIMXRT11xx {
fn debug_port_start(
&self,
interface: &mut ArmCommunicationInterface<Initialized>,
dp: DpAddress,
) -> Result<(), ArmError> {
tracing::debug!("debug_port_start");
self::debug_port_start(interface, dp, Select(0))?;
let ap = ApAddress { dp, ap: 0 };
let ap = MemoryAp::new(ap);
tracing::debug!("Prepare trap code for Cortex M7");
self.prepare_cm7_trap_code(ap, interface)?;
tracing::debug!("Prepare trap code for Cortex M4");
self.prepare_cm4_trap_code(ap, interface)?;
tracing::debug!("Release the CM4");
self.release_cm4(ap, interface)?;
tracing::debug!("Change reset mode of both cores");
self.change_reset_modes(ap, interface)?;
Ok(())
}
fn reset_system(
&self,
interface: &mut dyn ArmProbe,
_: crate::CoreType,
_: Option<u64>,
) -> Result<(), ArmError> {
tracing::debug!("Halting MIMXRT11xx core before VECTRESET");
let mut dhcsr = Dhcsr(0);
dhcsr.set_c_halt(true);
dhcsr.set_c_debugen(true);
dhcsr.enable_write();
interface.write_word_32(Dhcsr::ADDRESS, dhcsr.into())?;
std::thread::sleep(Duration::from_millis(100));
tracing::debug!("Resetting MIMXRT11xx with VECTRESET");
let mut aircr = Aircr(0);
aircr.vectkey();
aircr.set_vectreset(true);
interface.write_word_32(Aircr::ADDRESS, aircr.into()).ok();
interface.flush().ok();
std::thread::sleep(Duration::from_millis(100));
interface.read_word_32(Dhcsr::ADDRESS)?;
Ok(())
}
}