diff options
| -rw-r--r-- | embassy-nrf/src/lib.rs | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 0fa1c0f66..a9683df44 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs | |||
| @@ -235,10 +235,26 @@ mod consts { | |||
| 235 | pub const APPROTECT_DISABLED: u32 = 0x0000_005a; | 235 | pub const APPROTECT_DISABLED: u32 = 0x0000_005a; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | unsafe fn uicr_write(address: *mut u32, value: u32) -> bool { | 238 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] |
| 239 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 240 | enum WriteResult { | ||
| 241 | /// Word was written successfully, needs reset. | ||
| 242 | Written, | ||
| 243 | /// Word was already set to the value we wanted to write, nothing was done. | ||
| 244 | Noop, | ||
| 245 | /// Word is already set to something else, we couldn't write the desired value. | ||
| 246 | Failed, | ||
| 247 | } | ||
| 248 | |||
| 249 | unsafe fn uicr_write(address: *mut u32, value: u32) -> WriteResult { | ||
| 239 | let curr_val = address.read_volatile(); | 250 | let curr_val = address.read_volatile(); |
| 240 | if curr_val == value { | 251 | if curr_val == value { |
| 241 | return false; | 252 | return WriteResult::Noop; |
| 253 | } | ||
| 254 | |||
| 255 | // We can only change `1` bits to `0` bits. | ||
| 256 | if curr_val & value != value { | ||
| 257 | return WriteResult::Failed; | ||
| 242 | } | 258 | } |
| 243 | 259 | ||
| 244 | // Writing to UICR can only change `1` bits to `0` bits. | 260 | // Writing to UICR can only change `1` bits to `0` bits. |
| @@ -257,7 +273,7 @@ unsafe fn uicr_write(address: *mut u32, value: u32) -> bool { | |||
| 257 | nvmc.config.reset(); | 273 | nvmc.config.reset(); |
| 258 | while nvmc.ready.read().ready().is_busy() {} | 274 | while nvmc.ready.read().ready().is_busy() {} |
| 259 | 275 | ||
| 260 | true | 276 | WriteResult::Written |
| 261 | } | 277 | } |
| 262 | 278 | ||
| 263 | /// Initialize peripherals with the provided configuration. This should only be called once at startup. | 279 | /// Initialize peripherals with the provided configuration. This should only be called once at startup. |
| @@ -283,7 +299,8 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 283 | // which needs explicit action by the firmware to keep it unlocked | 299 | // which needs explicit action by the firmware to keep it unlocked |
| 284 | 300 | ||
| 285 | // UICR.APPROTECT = SwDisabled | 301 | // UICR.APPROTECT = SwDisabled |
| 286 | needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | 302 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); |
| 303 | needs_reset |= res == WriteResult::Written; | ||
| 287 | // APPROTECT.DISABLE = SwDisabled | 304 | // APPROTECT.DISABLE = SwDisabled |
| 288 | (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED); | 305 | (0x4000_0558 as *mut u32).write_volatile(consts::APPROTECT_DISABLED); |
| 289 | } else { | 306 | } else { |
| @@ -295,12 +312,14 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 295 | unsafe { | 312 | unsafe { |
| 296 | let p = &*pac::CTRLAP::ptr(); | 313 | let p = &*pac::CTRLAP::ptr(); |
| 297 | 314 | ||
| 298 | needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); | 315 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_DISABLED); |
| 316 | needs_reset |= res == WriteResult::Written; | ||
| 299 | p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | 317 | p.approtect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); |
| 300 | 318 | ||
| 301 | #[cfg(feature = "_nrf5340-app")] | 319 | #[cfg(feature = "_nrf5340-app")] |
| 302 | { | 320 | { |
| 303 | needs_reset |= uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); | 321 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_DISABLED); |
| 322 | needs_reset |= res == WriteResult::Written; | ||
| 304 | p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); | 323 | p.secureapprotect.disable.write(|w| w.bits(consts::APPROTECT_DISABLED)); |
| 305 | } | 324 | } |
| 306 | } | 325 | } |
| @@ -309,24 +328,57 @@ pub fn init(config: config::Config) -> Peripherals { | |||
| 309 | } | 328 | } |
| 310 | config::Debug::Disallowed => unsafe { | 329 | config::Debug::Disallowed => unsafe { |
| 311 | // UICR.APPROTECT = Enabled | 330 | // UICR.APPROTECT = Enabled |
| 312 | needs_reset |= uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); | 331 | let res = uicr_write(consts::UICR_APPROTECT, consts::APPROTECT_ENABLED); |
| 332 | needs_reset |= res == WriteResult::Written; | ||
| 313 | #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))] | 333 | #[cfg(any(feature = "_nrf5340-app", feature = "_nrf9160"))] |
| 314 | { | 334 | { |
| 315 | needs_reset |= uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); | 335 | let res = uicr_write(consts::UICR_SECUREAPPROTECT, consts::APPROTECT_ENABLED); |
| 336 | needs_reset |= res == WriteResult::Written; | ||
| 316 | } | 337 | } |
| 317 | }, | 338 | }, |
| 318 | config::Debug::NotConfigured => {} | 339 | config::Debug::NotConfigured => {} |
| 319 | } | 340 | } |
| 320 | 341 | ||
| 321 | #[cfg(all(feature = "_nrf52", not(feature = "reset-pin-as-gpio")))] | 342 | #[cfg(feature = "_nrf52")] |
| 322 | unsafe { | 343 | unsafe { |
| 323 | needs_reset |= uicr_write(consts::UICR_PSELRESET1, chip::RESET_PIN); | 344 | let value = if cfg!(feature = "reset-pin-as-gpio") { |
| 324 | needs_reset |= uicr_write(consts::UICR_PSELRESET2, chip::RESET_PIN); | 345 | !0 |
| 346 | } else { | ||
| 347 | chip::RESET_PIN | ||
| 348 | }; | ||
| 349 | let res1 = uicr_write(consts::UICR_PSELRESET1, value); | ||
| 350 | let res2 = uicr_write(consts::UICR_PSELRESET2, value); | ||
| 351 | needs_reset |= res1 == WriteResult::Written || res2 == WriteResult::Written; | ||
| 352 | if res1 == WriteResult::Failed || res2 == WriteResult::Failed { | ||
| 353 | #[cfg(not(feature = "reset-pin-as-gpio"))] | ||
| 354 | warn!( | ||
| 355 | "You have requested enabling chip reset functionality on the reset pin, by not enabling the Cargo feature `reset-pin-as-gpio`.\n\ | ||
| 356 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 357 | To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." | ||
| 358 | ); | ||
| 359 | #[cfg(feature = "reset-pin-as-gpio")] | ||
| 360 | warn!( | ||
| 361 | "You have requested using the reset pin as GPIO, by enabling the Cargo feature `reset-pin-as-gpio`.\n\ | ||
| 362 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 363 | To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." | ||
| 364 | ); | ||
| 365 | } | ||
| 325 | } | 366 | } |
| 326 | 367 | ||
| 327 | #[cfg(all(any(feature = "_nrf52", feature = "_nrf5340-app"), feature = "nfc-pins-as-gpio"))] | 368 | #[cfg(any(feature = "_nrf52", feature = "_nrf5340-app"))] |
| 328 | unsafe { | 369 | unsafe { |
| 329 | needs_reset |= uicr_write(consts::UICR_NFCPINS, 0); | 370 | let value = if cfg!(feature = "nfc-pins-as-gpio") { 0 } else { !0 }; |
| 371 | let res = uicr_write(consts::UICR_NFCPINS, value); | ||
| 372 | needs_reset |= res == WriteResult::Written; | ||
| 373 | if res == WriteResult::Failed { | ||
| 374 | // with nfc-pins-as-gpio, this can never fail because we're writing all zero bits. | ||
| 375 | #[cfg(not(feature = "nfc-pins-as-gpio"))] | ||
| 376 | warn!( | ||
| 377 | "You have requested to use P0.09 and P0.10 pins for NFC, by not enabling the Cargo feature `nfc-pins-as-gpio`.\n\ | ||
| 378 | However, UICR is already programmed to some other setting, and can't be changed without erasing it.\n\ | ||
| 379 | To fix this, erase UICR manually, for example using `probe-rs-cli erase` or `nrfjprog --eraseuicr`." | ||
| 380 | ); | ||
| 381 | } | ||
| 330 | } | 382 | } |
| 331 | 383 | ||
| 332 | if needs_reset { | 384 | if needs_reset { |
