aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaleb Jamison <[email protected]>2024-08-27 13:19:07 -0400
committerCaleb Jamison <[email protected]>2024-08-29 10:47:03 -0400
commit372270a9b962196ede9c60a705cc3138ba592fec (patch)
tree575ac05a27915fc3165f51adf281b177cddca541
parent0a33edc9976caddcdebe0943cce78376f9c49789 (diff)
rp235x flash support.
The 2350 doesn't have a boot2 like the 2040, but it does have the concept of a xip setup function that could be customized. By default the bootrom searches for the attached flash chip and provides an xip setup func at the base of the bootram. That bootram is not executable, so it still needs to be copied to ram like boot2 would be. Currently does not use inline assembly. Also switch to picotool, as elf2uf2 has not been patched to support the 2350.
-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}