use std::{sync::Arc, thread, time::Duration};
use bitfield::bitfield;
use crate::{
MemoryMappedRegister, Permissions,
architecture::arm::{
ApV2Address, ArmDebugInterface, ArmError, FullyQualifiedApAddress,
core::armv7m::Dhcsr,
dp::DpAddress,
memory::ArmMemoryInterface,
sequences::{ArmDebugSequence, cortex_m_wait_for_reset},
},
};
const AP_CSW: u64 = 0xD00;
const AP_TAR: u64 = 0xD04;
const AP_DRW: u64 = 0xD0C;
const SYS_AP_BASE: u64 = 0xF000_0000;
const SRSS_RES_SOFT_CTL: u32 = 0x5220_0410;
const SRSS_RES_SOFT_CTL_TRIG_SOFT: u32 = 1;
const RESET_DELAY_MS: u64 = 350;
bitfield! {
#[derive(Clone, Copy)]
struct SysApCsw(u32);
impl Debug;
pub dbg_sw_enable, set_dbg_sw_enable: 31;
pub hnonsec, set_hnonsec: 30;
pub master_type, set_master_type: 29;
pub cacheable, set_cacheable: 27;
pub privileged, set_privileged: 25;
pub data, set_data: 24;
u8, size, set_size: 2, 0;
}
impl SysApCsw {
fn secure_word() -> Self {
let mut v = Self(0);
v.set_dbg_sw_enable(true);
v.set_hnonsec(false); v.set_master_type(true);
v.set_cacheable(true);
v.set_privileged(true);
v.set_data(true);
v.set_size(2); v
}
}
bitfield! {
#[derive(Clone, Copy)]
struct Cm33ApCsw(u32);
impl Debug;
u8, size, set_size: 2, 0;
u8, addr_inc, set_addr_inc: 5, 4;
pub device_en, _: 6;
pub s_device_en, _: 23;
pub data, set_data: 24;
pub privileged, set_privileged: 25;
pub cacheable, set_cacheable: 27;
pub hnonsec, set_hnonsec: 30;
}
impl Cm33ApCsw {
const PRESERVE_MASK: u32 = 0xB0FF_FFC0;
fn with_standard_access(csw: u32) -> Self {
let mut out = Self(csw & Self::PRESERVE_MASK);
out.set_size(2); out.set_addr_inc(1); out.set_data(true); out.set_privileged(true); out.set_cacheable(true); out.set_hnonsec((csw >> 23) & 1 == 0);
out
}
}
#[derive(Debug)]
pub struct PsocC3;
impl PsocC3 {
pub fn create() -> Arc<Self> {
Arc::new(PsocC3)
}
fn sys_ap(dp: DpAddress) -> FullyQualifiedApAddress {
FullyQualifiedApAddress::v2_with_dp(dp, ApV2Address(Some(SYS_AP_BASE)))
}
fn write_mem32(
iface: &mut dyn ArmDebugInterface,
ap: &FullyQualifiedApAddress,
addr: u32,
val: u32,
) -> Result<(), ArmError> {
iface.write_raw_ap_register(ap, AP_TAR, addr)?;
iface.write_raw_ap_register(ap, AP_DRW, val)?;
Ok(())
}
}
impl ArmDebugSequence for PsocC3 {
fn debug_device_unlock(
&self,
interface: &mut dyn ArmDebugInterface,
default_ap: &FullyQualifiedApAddress,
_permissions: &Permissions,
) -> Result<(), ArmError> {
let csw = interface.read_raw_ap_register(default_ap, AP_CSW)?;
let csw_bits = Cm33ApCsw(csw);
if !csw_bits.device_en() {
tracing::warn!(
"PSOC C3: CM33 AP is closed (DeviceEn=0), CSW: 0x{:08X}. \
This chip may require a debug-certificate WFA unlock, which is not \
supported yet — subsequent AP register accesses will likely fail.",
csw
);
}
let new_csw = Cm33ApCsw::with_standard_access(csw);
tracing::debug!(
"PSOC C3: AP CSW 0x{:08X} -> 0x{:08X} (SDeviceEn={}, HNONSEC={})",
csw,
new_csw.0,
csw_bits.s_device_en(),
new_csw.hnonsec(),
);
interface.write_raw_ap_register(default_ap, AP_CSW, new_csw.0)?;
Ok(())
}
fn reset_system(
&self,
interface: &mut dyn ArmMemoryInterface,
_core_type: probe_rs_target::CoreType,
_debug_base: Option<u64>,
) -> Result<(), ArmError> {
let mut dhcsr = Dhcsr(0);
dhcsr.set_c_debugen(true);
dhcsr.set_c_halt(true);
dhcsr.enable_write();
let _ = interface.write_word_32(Dhcsr::get_mmio_address(), dhcsr.into());
let dp = interface.fully_qualified_address().dp();
let sys_ap = Self::sys_ap(dp);
let cm33_ap = interface.fully_qualified_address();
{
let arm = interface.get_arm_debug_interface()?;
arm.write_raw_ap_register(&sys_ap, AP_CSW, SysApCsw::secure_word().0)?;
let _ = Self::write_mem32(arm, &sys_ap, SRSS_RES_SOFT_CTL, SRSS_RES_SOFT_CTL_TRIG_SOFT);
let _ = arm.flush();
}
tracing::debug!(
"PSOC C3: reset_system — waiting {}ms for boot ROM",
RESET_DELAY_MS
);
thread::sleep(Duration::from_millis(RESET_DELAY_MS));
cortex_m_wait_for_reset(interface)?;
let arm = interface.get_arm_debug_interface()?;
self.debug_device_unlock(arm, &cm33_ap, &Permissions::new())
}
}