diff options
| author | Dario Nieuwenhuis <[email protected]> | 2024-05-24 20:04:14 +0200 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2024-05-24 20:04:14 +0200 |
| commit | 33bdc9e85ff391da4ff4ff439abe86c2bae32986 (patch) | |
| tree | c177a1129fb16abfd61b46c825086e59c5485b33 /embassy-rp/src | |
| parent | 891ec5fa5da384cc7c8ffe48ef2df0bbfca769a3 (diff) | |
rp: fix spinlocks staying locked after reset.
Fixes #1736
Diffstat (limited to 'embassy-rp/src')
| -rw-r--r-- | embassy-rp/src/lib.rs | 44 |
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] | ||
| 357 | unsafe 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. |
| 356 | trait RegExt<T: Copy> { | 400 | trait RegExt<T: Copy> { |
| 357 | #[allow(unused)] | 401 | #[allow(unused)] |
