aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-rp/src/flash.rs135
-rw-r--r--embassy-rp/src/lib.rs4
-rw-r--r--examples/rp23/.cargo/config.toml3
-rw-r--r--examples/rp23/src/bin/flash.rs15
4 files changed, 68 insertions, 89 deletions
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 5f7922f8e..dab99b4e2 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -17,9 +17,13 @@ use crate::peripherals::FLASH;
17/// Flash base address. 17/// Flash base address.
18pub const FLASH_BASE: *const u32 = 0x10000000 as _; 18pub const FLASH_BASE: *const u32 = 0x10000000 as _;
19 19
20/// Address for xip setup function set up by the 235x bootrom.
21#[cfg(feature = "_rp235x")]
22pub const BOOTROM_BASE: *const u32 = 0x400e0000 as _;
23
20/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead. 24/// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
21// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance. 25// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
22pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram"); 26pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram") | cfg!(feature = "_rp235x");
23 27
24// **NOTE**: 28// **NOTE**:
25// 29//
@@ -97,7 +101,10 @@ impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, '
97 // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in 101 // Errata RP2040-E8: Perform an uncached read to make sure there's not a transfer in
98 // flight that might effect an address written to start a new transfer. This stalls 102 // flight that might effect an address written to start a new transfer. This stalls
99 // until after any transfer is complete, so the address will not change anymore. 103 // until after any transfer is complete, so the address will not change anymore.
104 #[cfg(feature = "rp2040")]
100 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _; 105 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x13000000 as *const _;
106 #[cfg(feature = "_rp235x")]
107 const XIP_NOCACHE_NOALLOC_BASE: *const u32 = 0x14000000 as *const _;
101 unsafe { 108 unsafe {
102 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE); 109 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE);
103 } 110 }
@@ -225,12 +232,14 @@ impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SI
225 } 232 }
226 233
227 /// Read SPI flash unique ID 234 /// Read SPI flash unique ID
235 #[cfg(feature = "rp2040")]
228 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 236 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
229 unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? }; 237 unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? };
230 Ok(()) 238 Ok(())
231 } 239 }
232 240
233 /// Read SPI flash JEDEC ID 241 /// Read SPI flash JEDEC ID
242 #[cfg(feature = "rp2040")]
234 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> { 243 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
235 let mut jedec = None; 244 let mut jedec = None;
236 unsafe { 245 unsafe {
@@ -301,7 +310,10 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
301 // Use the XIP AUX bus port, rather than the FIFO register access (e.x. 310 // Use the XIP AUX bus port, rather than the FIFO register access (e.x.
302 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on 311 // pac::XIP_CTRL.stream_fifo().as_ptr()) to avoid DMA stalling on
303 // general XIP access. 312 // general XIP access.
313 #[cfg(feature = "rp2040")]
304 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _; 314 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
315 #[cfg(feature = "_rp235x")]
316 const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _;
305 let transfer = unsafe { 317 let transfer = unsafe {
306 crate::dma::read( 318 crate::dma::read(
307 self.dma.as_mut().unwrap(), 319 self.dma.as_mut().unwrap(),
@@ -510,19 +522,14 @@ mod ram_helpers {
510 /// 522 ///
511 /// `addr` and `len` parameters must be valid and are not checked. 523 /// `addr` and `len` parameters must be valid and are not checked.
512 pub unsafe fn flash_range_erase(addr: u32, len: u32) { 524 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
513 #[cfg(feature = "rp2040")]
514 let mut boot2 = [0u32; 256 / 4]; 525 let mut boot2 = [0u32; 256 / 4];
515 let ptrs = { 526 let ptrs = if USE_BOOT2 {
516 #[cfg(feature = "rp2040")] 527 #[cfg(feature = "rp2040")]
517 { 528 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
518 if USE_BOOT2 {
519 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
520 flash_function_pointers_with_boot2(true, false, &boot2)
521 } else {
522 flash_function_pointers(true, false)
523 }
524 }
525 #[cfg(feature = "_rp235x")] 529 #[cfg(feature = "_rp235x")]
530 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
531 flash_function_pointers_with_boot2(true, false, &boot2)
532 } else {
526 flash_function_pointers(true, false) 533 flash_function_pointers(true, false)
527 }; 534 };
528 535
@@ -548,19 +555,14 @@ mod ram_helpers {
548 /// 555 ///
549 /// `addr` and `len` parameters must be valid and are not checked. 556 /// `addr` and `len` parameters must be valid and are not checked.
550 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) { 557 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
551 #[cfg(feature = "rp2040")]
552 let mut boot2 = [0u32; 256 / 4]; 558 let mut boot2 = [0u32; 256 / 4];
553 let ptrs = { 559 let ptrs = if USE_BOOT2 {
554 #[cfg(feature = "rp2040")] 560 #[cfg(feature = "rp2040")]
555 { 561 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
556 if USE_BOOT2 {
557 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
558 flash_function_pointers_with_boot2(true, true, &boot2)
559 } else {
560 flash_function_pointers(true, true)
561 }
562 }
563 #[cfg(feature = "_rp235x")] 562 #[cfg(feature = "_rp235x")]
563 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256);
564 flash_function_pointers_with_boot2(true, true, &boot2)
565 } else {
564 flash_function_pointers(true, true) 566 flash_function_pointers(true, true)
565 }; 567 };
566 568
@@ -591,19 +593,14 @@ mod ram_helpers {
591 /// 593 ///
592 /// `addr` and `len` parameters must be valid and are not checked. 594 /// `addr` and `len` parameters must be valid and are not checked.
593 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) { 595 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
594 #[cfg(feature = "rp2040")]
595 let mut boot2 = [0u32; 256 / 4]; 596 let mut boot2 = [0u32; 256 / 4];
596 let ptrs = { 597 let ptrs = if USE_BOOT2 {
597 #[cfg(feature = "rp2040")] 598 #[cfg(feature = "rp2040")]
598 { 599 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
599 if USE_BOOT2 {
600 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
601 flash_function_pointers_with_boot2(false, true, &boot2)
602 } else {
603 flash_function_pointers(false, true)
604 }
605 }
606 #[cfg(feature = "_rp235x")] 600 #[cfg(feature = "_rp235x")]
601 core::ptr::copy_nonoverlapping(BOOTROM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
602 flash_function_pointers_with_boot2(false, true, &boot2)
603 } else {
607 flash_function_pointers(false, true) 604 flash_function_pointers(false, true)
608 }; 605 };
609 606
@@ -630,16 +627,7 @@ mod ram_helpers {
630 #[link_section = ".data.ram_func"] 627 #[link_section = ".data.ram_func"]
631 #[cfg(feature = "rp2040")] 628 #[cfg(feature = "rp2040")]
632 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) { 629 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
633 /* 630 //#[cfg(target_arch = "arm")]
634 Should be equivalent to:
635 rom_data::connect_internal_flash();
636 rom_data::flash_exit_xip();
637 rom_data::flash_range_erase(addr, len, 1 << 31, 0); // if selected
638 rom_data::flash_range_program(addr, data as *const _, len); // if selected
639 rom_data::flash_flush_cache();
640 rom_data::flash_enter_cmd_xip();
641 */
642 #[cfg(target_arch = "arm")]
643 core::arch::asm!( 631 core::arch::asm!(
644 "mov r8, r0", 632 "mov r8, r0",
645 "mov r9, r2", 633 "mov r9, r2",
@@ -691,11 +679,30 @@ mod ram_helpers {
691 ); 679 );
692 } 680 }
693 681
682 /// # Safety
683 ///
684 /// Nothing must access flash while this is running.
685 /// Usually this means:
686 /// - interrupts must be disabled
687 /// - 2nd core must be running code from RAM or ROM with interrupts disabled
688 /// - DMA must not access flash memory
689 /// Length of data must be a multiple of 4096
690 /// addr must be aligned to 4096
694 #[inline(never)] 691 #[inline(never)]
695 #[link_section = ".data.ram_func"] 692 #[link_section = ".data.ram_func"]
696 #[cfg(feature = "_rp235x")] 693 #[cfg(feature = "_rp235x")]
697 unsafe fn write_flash_inner(_addr: u32, _len: u32, _data: Option<&[u8]>, _ptrs: *const FlashFunctionPointers) { 694 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
698 todo!(); 695 let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null());
696 ((*ptrs).connect_internal_flash)();
697 ((*ptrs).flash_exit_xip)();
698 if (*ptrs).flash_range_erase.is_some() {
699 ((*ptrs).flash_range_erase.unwrap())(addr, len as usize, 1 << 31, 0);
700 }
701 if (*ptrs).flash_range_program.is_some() {
702 ((*ptrs).flash_range_program.unwrap())(addr, data as *const _, len as usize);
703 }
704 ((*ptrs).flash_flush_cache)();
705 ((*ptrs).flash_enter_cmd_xip)();
699 } 706 }
700 707
701 #[repr(C)] 708 #[repr(C)]
@@ -731,20 +738,13 @@ mod ram_helpers {
731 /// - DMA must not access flash memory 738 /// - DMA must not access flash memory
732 /// 739 ///
733 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 740 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
741 #[cfg(feature = "rp2040")]
734 pub unsafe fn flash_unique_id(out: &mut [u8]) { 742 pub unsafe fn flash_unique_id(out: &mut [u8]) {
735 #[cfg(feature = "rp2040")]
736 let mut boot2 = [0u32; 256 / 4]; 743 let mut boot2 = [0u32; 256 / 4];
737 let ptrs = { 744 let ptrs = if USE_BOOT2 {
738 #[cfg(feature = "rp2040")] 745 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
739 { 746 flash_function_pointers_with_boot2(false, false, &boot2)
740 if USE_BOOT2 { 747 } else {
741 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
742 flash_function_pointers_with_boot2(false, false, &boot2)
743 } else {
744 flash_function_pointers(false, false)
745 }
746 }
747 #[cfg(feature = "_rp235x")]
748 flash_function_pointers(false, false) 748 flash_function_pointers(false, false)
749 }; 749 };
750 750
@@ -768,20 +768,13 @@ mod ram_helpers {
768 /// - DMA must not access flash memory 768 /// - DMA must not access flash memory
769 /// 769 ///
770 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 770 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
771 #[cfg(feature = "rp2040")]
771 pub unsafe fn flash_jedec_id() -> u32 { 772 pub unsafe fn flash_jedec_id() -> u32 {
772 #[cfg(feature = "rp2040")]
773 let mut boot2 = [0u32; 256 / 4]; 773 let mut boot2 = [0u32; 256 / 4];
774 let ptrs = { 774 let ptrs = if USE_BOOT2 {
775 #[cfg(feature = "rp2040")] 775 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
776 { 776 flash_function_pointers_with_boot2(false, false, &boot2)
777 if USE_BOOT2 { 777 } else {
778 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
779 flash_function_pointers_with_boot2(false, false, &boot2)
780 } else {
781 flash_function_pointers(false, false)
782 }
783 }
784 #[cfg(feature = "_rp235x")]
785 flash_function_pointers(false, false) 778 flash_function_pointers(false, false)
786 }; 779 };
787 780
@@ -792,6 +785,7 @@ mod ram_helpers {
792 u32::from_be_bytes(id) 785 u32::from_be_bytes(id)
793 } 786 }
794 787
788 #[cfg(feature = "rp2040")]
795 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) { 789 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) {
796 read_flash_inner( 790 read_flash_inner(
797 FlashCommand { 791 FlashCommand {
@@ -932,13 +926,6 @@ mod ram_helpers {
932 clobber_abi("C"), 926 clobber_abi("C"),
933 ); 927 );
934 } 928 }
935
936 #[inline(never)]
937 #[link_section = ".data.ram_func"]
938 #[cfg(feature = "_rp235x")]
939 unsafe fn read_flash_inner(_cmd: FlashCommand, _ptrs: *const FlashFunctionPointers) {
940 todo!();
941 }
942} 929}
943 930
944/// Make sure to uphold the contract points with rp2040-flash. 931/// Make sure to uphold the contract points with rp2040-flash.
diff --git a/embassy-rp/src/lib.rs b/embassy-rp/src/lib.rs
index c2c57eaa0..f8fcfe52b 100644
--- a/embassy-rp/src/lib.rs
+++ b/embassy-rp/src/lib.rs
@@ -402,7 +402,7 @@ embassy_hal_internal::peripherals! {
402 BOOTSEL, 402 BOOTSEL,
403} 403}
404 404
405#[cfg(not(feature = "boot2-none"))] 405#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
406macro_rules! select_bootloader { 406macro_rules! select_bootloader {
407 ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => { 407 ( $( $feature:literal => $loader:ident, )+ default => $default:ident ) => {
408 $( 408 $(
@@ -419,7 +419,7 @@ macro_rules! select_bootloader {
419 } 419 }
420} 420}
421 421
422#[cfg(not(feature = "boot2-none"))] 422#[cfg(all(not(feature = "boot2-none"), feature = "rp2040"))]
423select_bootloader! { 423select_bootloader! {
424 "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A, 424 "boot2-at25sf128a" => BOOT_LOADER_AT25SF128A,
425 "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS, 425 "boot2-gd25q64cs" => BOOT_LOADER_GD25Q64CS,
diff --git a/examples/rp23/.cargo/config.toml b/examples/rp23/.cargo/config.toml
index f77e004dc..9a92b1ce2 100644
--- a/examples/rp23/.cargo/config.toml
+++ b/examples/rp23/.cargo/config.toml
@@ -1,6 +1,7 @@
1[target.'cfg(all(target_arch = "arm", target_os = "none"))'] 1[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2#runner = "probe-rs run --chip RP2040" 2#runner = "probe-rs run --chip RP2040"
3runner = "elf2uf2-rs -d" 3#runner = "elf2uf2-rs -d"
4runner = "picotool load -u -v -x -t elf"
4 5
5[build] 6[build]
6target = "thumbv8m.main-none-eabihf" 7target = "thumbv8m.main-none-eabihf"
diff --git a/examples/rp23/src/bin/flash.rs b/examples/rp23/src/bin/flash.rs
index 811561f26..84011e394 100644
--- a/examples/rp23/src/bin/flash.rs
+++ b/examples/rp23/src/bin/flash.rs
@@ -21,7 +21,7 @@ pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [ 21pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
22 embassy_rp::binary_info::rp_program_name!(c"example"), 22 embassy_rp::binary_info::rp_program_name!(c"example"),
23 embassy_rp::binary_info::rp_cargo_version!(), 23 embassy_rp::binary_info::rp_cargo_version!(),
24 embassy_rp::binary_info::rp_program_description!(c"Blinky"), 24 embassy_rp::binary_info::rp_program_description!(c"Flash"),
25 embassy_rp::binary_info::rp_program_build_attribute!(), 25 embassy_rp::binary_info::rp_program_build_attribute!(),
26]; 26];
27 27
@@ -41,22 +41,13 @@ async fn main(_spawner: Spawner) {
41 41
42 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0); 42 let mut flash = embassy_rp::flash::Flash::<_, Async, FLASH_SIZE>::new(p.FLASH, p.DMA_CH0);
43 43
44 // Get JEDEC id
45 let jedec = flash.blocking_jedec_id().unwrap();
46 info!("jedec id: 0x{:x}", jedec);
47
48 // Get unique id
49 let mut uid = [0; 8];
50 flash.blocking_unique_id(&mut uid).unwrap();
51 info!("unique id: {:?}", uid);
52
53 erase_write_sector(&mut flash, 0x00); 44 erase_write_sector(&mut flash, 0x00);
54 45
55 multiwrite_bytes(&mut flash, ERASE_SIZE as u32); 46 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
56 47
57 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await; 48 background_read(&mut flash, (ERASE_SIZE * 2) as u32).await;
58 49
59 loop {} 50 info!("Flash Works!");
60} 51}
61 52
62fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) { 53fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH_SIZE>, offset: u32) {
@@ -82,7 +73,7 @@ fn multiwrite_bytes(flash: &mut embassy_rp::flash::Flash<'_, FLASH, Async, FLASH
82 73
83 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf)); 74 defmt::unwrap!(flash.blocking_read(ADDR_OFFSET + offset, &mut read_buf));
84 info!("Contents after write starts with {=[u8]}", read_buf[0..4]); 75 info!("Contents after write starts with {=[u8]}", read_buf[0..4]);
85 if &read_buf[0..4] != &[0x01, 0x02, 0x03, 0x04] { 76 if read_buf[0..4] != [0x01, 0x02, 0x03, 0x04] {
86 defmt::panic!("unexpected"); 77 defmt::panic!("unexpected");
87 } 78 }
88} 79}