aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2023-06-05 22:16:44 +0000
committerGitHub <[email protected]>2023-06-05 22:16:44 +0000
commit79b982c941576597bd09d585a9bdaa7fce47688a (patch)
tree10b980663e8326f4a9a15e64a0c1f6df3c3cae17
parentd690a1717fd03a1f3fdad509d6a638567f8a645a (diff)
parent593fc78dd892338386a2a81400e0621372264053 (diff)
Merge pull request #1536 from embassy-rs/rp-flash-fix
Rp flash fix
-rw-r--r--embassy-rp/Cargo.toml5
-rw-r--r--embassy-rp/src/dma.rs5
-rw-r--r--embassy-rp/src/flash.rs82
-rw-r--r--tests/rp/Cargo.toml2
4 files changed, 53 insertions, 41 deletions
diff --git a/embassy-rp/Cargo.toml b/embassy-rp/Cargo.toml
index 5f08c7f33..ddada655b 100644
--- a/embassy-rp/Cargo.toml
+++ b/embassy-rp/Cargo.toml
@@ -41,6 +41,11 @@ boot2-ram-memcpy = []
41boot2-w25q080 = [] 41boot2-w25q080 = []
42boot2-w25x10cl = [] 42boot2-w25x10cl = []
43 43
44# Indicate code is running from RAM.
45# Set this if all code is in RAM, and the cores never access memory-mapped flash memory through XIP.
46# This allows the flash driver to not force pausing execution on both cores when doing flash operations.
47run-from-ram = []
48
44# Enable nightly-only features 49# Enable nightly-only features
45nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"] 50nightly = ["embassy-executor/nightly", "embedded-hal-1", "embedded-hal-async", "embassy-embedded-hal/nightly", "dep:embassy-usb-driver", "dep:embedded-io"]
46 51
diff --git a/embassy-rp/src/dma.rs b/embassy-rp/src/dma.rs
index 74f4e6998..1cbb4651a 100644
--- a/embassy-rp/src/dma.rs
+++ b/embassy-rp/src/dma.rs
@@ -75,16 +75,17 @@ pub unsafe fn write<'a, C: Channel, W: Word>(
75 ) 75 )
76} 76}
77 77
78static DUMMY: u32 = 0;
79
78pub unsafe fn write_repeated<'a, C: Channel, W: Word>( 80pub unsafe fn write_repeated<'a, C: Channel, W: Word>(
79 ch: impl Peripheral<P = C> + 'a, 81 ch: impl Peripheral<P = C> + 'a,
80 to: *mut W, 82 to: *mut W,
81 len: usize, 83 len: usize,
82 dreq: u8, 84 dreq: u8,
83) -> Transfer<'a, C> { 85) -> Transfer<'a, C> {
84 let dummy: u32 = 0;
85 copy_inner( 86 copy_inner(
86 ch, 87 ch,
87 &dummy as *const u32, 88 &DUMMY as *const u32,
88 to as *mut u32, 89 to as *mut u32,
89 len, 90 len,
90 W::size(), 91 W::size(),
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 0410429e0..5d928abad 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -9,7 +9,11 @@ use embedded_storage::nor_flash::{
9use crate::pac; 9use crate::pac;
10use crate::peripherals::FLASH; 10use crate::peripherals::FLASH;
11 11
12pub const FLASH_BASE: usize = 0x10000000; 12pub const FLASH_BASE: *const u32 = 0x10000000 as _;
13
14// If running from RAM, we might have no boot2. Use bootrom `flash_enter_cmd_xip` instead.
15// TODO: when run-from-ram is set, completely skip the "pause cores and jumpp to RAM" dance.
16pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram");
13 17
14// **NOTE**: 18// **NOTE**:
15// 19//
@@ -63,8 +67,8 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
63 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> { 67 pub fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
64 trace!( 68 trace!(
65 "Reading from 0x{:x} to 0x{:x}", 69 "Reading from 0x{:x} to 0x{:x}",
66 FLASH_BASE + offset as usize, 70 FLASH_BASE as u32 + offset,
67 FLASH_BASE + offset as usize + bytes.len() 71 FLASH_BASE as u32 + offset + bytes.len() as u32
68 ); 72 );
69 check_read(self, offset, bytes.len())?; 73 check_read(self, offset, bytes.len())?;
70 74
@@ -89,7 +93,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
89 93
90 let len = to - from; 94 let len = to - from;
91 95
92 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len, true))? }; 96 unsafe { self.in_ram(|| ram_helpers::flash_range_erase(from, len))? };
93 97
94 Ok(()) 98 Ok(())
95 } 99 }
@@ -114,7 +118,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
114 118
115 let unaligned_offset = offset as usize - start; 119 let unaligned_offset = offset as usize - start;
116 120
117 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 121 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
118 } 122 }
119 123
120 let remaining_len = bytes.len() - start_padding; 124 let remaining_len = bytes.len() - start_padding;
@@ -132,12 +136,12 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
132 if bytes.as_ptr() as usize >= 0x2000_0000 { 136 if bytes.as_ptr() as usize >= 0x2000_0000 {
133 let aligned_data = &bytes[start_padding..end_padding]; 137 let aligned_data = &bytes[start_padding..end_padding];
134 138
135 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data, true))? } 139 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
136 } else { 140 } else {
137 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) { 141 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
138 let mut ram_buf = [0xFF_u8; PAGE_SIZE]; 142 let mut ram_buf = [0xFF_u8; PAGE_SIZE];
139 ram_buf.copy_from_slice(chunk); 143 ram_buf.copy_from_slice(chunk);
140 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf, true))? } 144 unsafe { self.in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
141 aligned_offset += PAGE_SIZE; 145 aligned_offset += PAGE_SIZE;
142 } 146 }
143 } 147 }
@@ -152,7 +156,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
152 156
153 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset); 157 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
154 158
155 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf, true))? } 159 unsafe { self.in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
156 } 160 }
157 161
158 Ok(()) 162 Ok(())
@@ -190,7 +194,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
190 194
191 /// Read SPI flash unique ID 195 /// Read SPI flash unique ID
192 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> { 196 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
193 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? }; 197 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid))? };
194 Ok(()) 198 Ok(())
195 } 199 }
196 200
@@ -199,7 +203,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
199 let mut jedec = None; 203 let mut jedec = None;
200 unsafe { 204 unsafe {
201 self.in_ram(|| { 205 self.in_ram(|| {
202 jedec.replace(ram_helpers::flash_jedec_id(true)); 206 jedec.replace(ram_helpers::flash_jedec_id());
203 })?; 207 })?;
204 }; 208 };
205 Ok(jedec.unwrap()) 209 Ok(jedec.unwrap())
@@ -242,6 +246,7 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, FLASH_S
242mod ram_helpers { 246mod ram_helpers {
243 use core::marker::PhantomData; 247 use core::marker::PhantomData;
244 248
249 use super::*;
245 use crate::rom_data; 250 use crate::rom_data;
246 251
247 #[repr(C)] 252 #[repr(C)]
@@ -306,7 +311,7 @@ mod ram_helpers {
306 /// 311 ///
307 /// `addr` and `len` must be multiples of 4096 312 /// `addr` and `len` must be multiples of 4096
308 /// 313 ///
309 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 314 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
310 /// is used to re-initialize the XIP engine after flashing. 315 /// is used to re-initialize the XIP engine after flashing.
311 /// 316 ///
312 /// # Safety 317 /// # Safety
@@ -318,10 +323,10 @@ mod ram_helpers {
318 /// - DMA must not access flash memory 323 /// - DMA must not access flash memory
319 /// 324 ///
320 /// `addr` and `len` parameters must be valid and are not checked. 325 /// `addr` and `len` parameters must be valid and are not checked.
321 pub unsafe fn flash_range_erase(addr: u32, len: u32, use_boot2: bool) { 326 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
322 let mut boot2 = [0u32; 256 / 4]; 327 let mut boot2 = [0u32; 256 / 4];
323 let ptrs = if use_boot2 { 328 let ptrs = if USE_BOOT2 {
324 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 329 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
325 flash_function_pointers_with_boot2(true, false, &boot2) 330 flash_function_pointers_with_boot2(true, false, &boot2)
326 } else { 331 } else {
327 flash_function_pointers(true, false) 332 flash_function_pointers(true, false)
@@ -336,7 +341,7 @@ mod ram_helpers {
336 /// 341 ///
337 /// `addr` and `data.len()` must be multiples of 4096 342 /// `addr` and `data.len()` must be multiples of 4096
338 /// 343 ///
339 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 344 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
340 /// is used to re-initialize the XIP engine after flashing. 345 /// is used to re-initialize the XIP engine after flashing.
341 /// 346 ///
342 /// # Safety 347 /// # Safety
@@ -348,10 +353,10 @@ mod ram_helpers {
348 /// - DMA must not access flash memory 353 /// - DMA must not access flash memory
349 /// 354 ///
350 /// `addr` and `len` parameters must be valid and are not checked. 355 /// `addr` and `len` parameters must be valid and are not checked.
351 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8], use_boot2: bool) { 356 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
352 let mut boot2 = [0u32; 256 / 4]; 357 let mut boot2 = [0u32; 256 / 4];
353 let ptrs = if use_boot2 { 358 let ptrs = if USE_BOOT2 {
354 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 359 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
355 flash_function_pointers_with_boot2(true, true, &boot2) 360 flash_function_pointers_with_boot2(true, true, &boot2)
356 } else { 361 } else {
357 flash_function_pointers(true, true) 362 flash_function_pointers(true, true)
@@ -371,7 +376,7 @@ mod ram_helpers {
371 /// 376 ///
372 /// `addr` and `data.len()` must be multiples of 256 377 /// `addr` and `data.len()` must be multiples of 256
373 /// 378 ///
374 /// If `use_boot2` is `true`, a copy of the 2nd stage boot loader 379 /// If `USE_BOOT2` is `true`, a copy of the 2nd stage boot loader
375 /// is used to re-initialize the XIP engine after flashing. 380 /// is used to re-initialize the XIP engine after flashing.
376 /// 381 ///
377 /// # Safety 382 /// # Safety
@@ -383,10 +388,10 @@ mod ram_helpers {
383 /// - DMA must not access flash memory 388 /// - DMA must not access flash memory
384 /// 389 ///
385 /// `addr` and `len` parameters must be valid and are not checked. 390 /// `addr` and `len` parameters must be valid and are not checked.
386 pub unsafe fn flash_range_program(addr: u32, data: &[u8], use_boot2: bool) { 391 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
387 let mut boot2 = [0u32; 256 / 4]; 392 let mut boot2 = [0u32; 256 / 4];
388 let ptrs = if use_boot2 { 393 let ptrs = if USE_BOOT2 {
389 rom_data::memcpy44(&mut boot2 as *mut _, super::FLASH_BASE as *const _, 256); 394 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
390 flash_function_pointers_with_boot2(false, true, &boot2) 395 flash_function_pointers_with_boot2(false, true, &boot2)
391 } else { 396 } else {
392 flash_function_pointers(false, true) 397 flash_function_pointers(false, true)
@@ -508,10 +513,10 @@ mod ram_helpers {
508 /// - DMA must not access flash memory 513 /// - DMA must not access flash memory
509 /// 514 ///
510 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 515 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
511 pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) { 516 pub unsafe fn flash_unique_id(out: &mut [u8]) {
512 let mut boot2 = [0u32; 256 / 4]; 517 let mut boot2 = [0u32; 256 / 4];
513 let ptrs = if use_boot2 { 518 let ptrs = if USE_BOOT2 {
514 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 519 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
515 flash_function_pointers_with_boot2(false, false, &boot2) 520 flash_function_pointers_with_boot2(false, false, &boot2)
516 } else { 521 } else {
517 flash_function_pointers(false, false) 522 flash_function_pointers(false, false)
@@ -536,10 +541,10 @@ mod ram_helpers {
536 /// - DMA must not access flash memory 541 /// - DMA must not access flash memory
537 /// 542 ///
538 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT) 543 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
539 pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 { 544 pub unsafe fn flash_jedec_id() -> u32 {
540 let mut boot2 = [0u32; 256 / 4]; 545 let mut boot2 = [0u32; 256 / 4];
541 let ptrs = if use_boot2 { 546 let ptrs = if USE_BOOT2 {
542 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256); 547 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
543 flash_function_pointers_with_boot2(false, false, &boot2) 548 flash_function_pointers_with_boot2(false, false, &boot2)
544 } else { 549 } else {
545 flash_function_pointers(false, false) 550 flash_function_pointers(false, false)
@@ -586,7 +591,6 @@ mod ram_helpers {
586 "ldr r4, [r5, #4]", 591 "ldr r4, [r5, #4]",
587 "blx r4", // flash_exit_xip() 592 "blx r4", // flash_exit_xip()
588 593
589 "mov r7, r10", // cmd
590 594
591 "movs r4, #0x18", 595 "movs r4, #0x18",
592 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13 596 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
@@ -603,8 +607,9 @@ mod ram_helpers {
603 "str r1, [r4, #0]", 607 "str r1, [r4, #0]",
604 608
605 // Write ctrlr1 with len-1 609 // Write ctrlr1 with len-1
606 "ldr r0, [r7, #8]", // dummy_len 610 "mov r3, r10", // cmd
607 "ldr r1, [r7, #16]", // data_len 611 "ldr r0, [r3, #8]", // dummy_len
612 "ldr r1, [r3, #16]", // data_len
608 "add r0, r1", 613 "add r0, r1",
609 "subs r0, #1", 614 "subs r0, #1",
610 "str r0, [r4, #0x04]", // CTRLR1 615 "str r0, [r4, #0x04]", // CTRLR1
@@ -616,8 +621,8 @@ mod ram_helpers {
616 // Write cmd/addr phase to DR 621 // Write cmd/addr phase to DR
617 "mov r2, r4", 622 "mov r2, r4",
618 "adds r2, 0x60", // &DR 623 "adds r2, 0x60", // &DR
619 "ldr r0, [r7, #0]", // cmd_addr 624 "ldr r0, [r3, #0]", // cmd_addr
620 "ldr r1, [r7, #4]", // cmd_addr_len 625 "ldr r1, [r3, #4]", // cmd_addr_len
621 "10:", 626 "10:",
622 "ldrb r3, [r0]", 627 "ldrb r3, [r0]",
623 "strb r3, [r2]", // DR 628 "strb r3, [r2]", // DR
@@ -626,7 +631,8 @@ mod ram_helpers {
626 "bne 10b", 631 "bne 10b",
627 632
628 // Skip any dummy cycles 633 // Skip any dummy cycles
629 "ldr r1, [r7, #8]", // dummy_len 634 "mov r3, r10", // cmd
635 "ldr r1, [r3, #8]", // dummy_len
630 "cmp r1, #0", 636 "cmp r1, #0",
631 "beq 9f", 637 "beq 9f",
632 "4:", 638 "4:",
@@ -643,8 +649,9 @@ mod ram_helpers {
643 649
644 // Read RX fifo 650 // Read RX fifo
645 "9:", 651 "9:",
646 "ldr r0, [r7, #12]", // data 652 "mov r2, r10", // cmd
647 "ldr r1, [r7, #16]", // data_len 653 "ldr r0, [r2, #12]", // data
654 "ldr r1, [r2, #16]", // data_len
648 655
649 "2:", 656 "2:",
650 "ldr r3, [r4, #0x28]", // SR 657 "ldr r3, [r4, #0x28]", // SR
@@ -678,13 +685,12 @@ mod ram_helpers {
678 out("r2") _, 685 out("r2") _,
679 out("r3") _, 686 out("r3") _,
680 out("r4") _, 687 out("r4") _,
688 out("r5") _,
681 // Registers r8-r10 are used to store values 689 // Registers r8-r10 are used to store values
682 // from r0-r2 in registers not clobbered by 690 // from r0-r2 in registers not clobbered by
683 // function calls. 691 // function calls.
684 // The values can't be passed in using r8-r10 directly 692 // The values can't be passed in using r8-r10 directly
685 // due to https://github.com/rust-lang/rust/issues/99071 693 // due to https://github.com/rust-lang/rust/issues/99071
686 out("r8") _,
687 out("r9") _,
688 out("r10") _, 694 out("r10") _,
689 clobber_abi("C"), 695 clobber_abi("C"),
690 ); 696 );
diff --git a/tests/rp/Cargo.toml b/tests/rp/Cargo.toml
index 1786baee3..6bcac373c 100644
--- a/tests/rp/Cargo.toml
+++ b/tests/rp/Cargo.toml
@@ -10,7 +10,7 @@ teleprobe-meta = "1"
10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.2.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.2.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] } 12embassy-time = { version = "0.1.0", path = "../../embassy-time", features = ["defmt"] }
13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics"] } 13embassy-rp = { version = "0.1.0", path = "../../embassy-rp", features = ["nightly", "defmt", "unstable-pac", "unstable-traits", "time-driver", "critical-section-impl", "intrinsics", "rom-v2-intrinsics", "run-from-ram"] }
14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } 14embassy-futures = { version = "0.1.0", path = "../../embassy-futures" }
15 15
16defmt = "0.3.0" 16defmt = "0.3.0"