aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/lib.rs44
1 files changed, 44 insertions, 0 deletions
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index 1c83e306d..4602e66f4 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -352,6 +352,50 @@ pub fn init(config: config::Config) -> Peripherals {
352 peripherals 352 peripherals
353} 353}
354 354
355#[cfg(feature = "rt")]
356#[cortex_m_rt::pre_init]
357unsafe fn pre_init() {
358 // SIO does not get reset when core0 is reset with either `scb::sys_reset()` or with SWD.
359 // Since we're using SIO spinlock 31 for the critical-section impl, this causes random
360 // hangs if we reset in the middle of a CS, because the next boot sees the spinlock
361 // as locked and waits forever.
362 //
363 // See https://github.com/embassy-rs/embassy/issues/1736
364 // and https://github.com/rp-rs/rp-hal/issues/292
365 // and https://matrix.to/#/!vhKMWjizPZBgKeknOo:matrix.org/$VfOkQgyf1PjmaXZbtycFzrCje1RorAXd8BQFHTl4d5M
366 //
367 // According to Raspberry Pi, this is considered Working As Intended, and not an errata,
368 // even though this behavior is different from every other ARM chip (sys_reset usually resets
369 // the *system* as its name implies, not just the current core).
370 //
371 // To fix this, reset SIO on boot. We must do this in pre_init because it's unsound to do it
372 // in `embassy_rp::init`, since the user could've acquired a CS by then. pre_init is guaranteed
373 // to run before any user code.
374 //
375 // A similar thing could happen with PROC1. It is unclear whether it's possible for PROC1
376 // to stay unreset through a PROC0 reset, so we reset it anyway just in case.
377 //
378 // Important info from PSM logic (from Luke Wren in above Matrix thread)
379 //
380 // The logic is, each PSM stage is reset if either of the following is true:
381 // - The previous stage is in reset and FRCE_ON is false
382 // - FRCE_OFF is true
383 //
384 // The PSM order is SIO -> PROC0 -> PROC1.
385 // So, we have to force-on PROC0 to prevent it from getting reset when resetting SIO.
386 pac::PSM.frce_on().write(|w| {
387 w.set_proc0(true);
388 });
389 // Then reset SIO and PROC1.
390 pac::PSM.frce_off().write(|w| {
391 w.set_sio(true);
392 w.set_proc1(true);
393 });
394 // clear force_off first, force_on second. The other way around would reset PROC0.
395 pac::PSM.frce_off().write(|_| {});
396 pac::PSM.frce_on().write(|_| {});
397}
398
355/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes. 399/// Extension trait for PAC regs, adding atomic xor/bitset/bitclear writes.
356trait RegExt<T: Copy> { 400trait RegExt<T: Copy> {
357 #[allow(unused)] 401 #[allow(unused)]