1use core::future::Future;
3use core::marker::PhantomData;
4use core::pin::Pin;
5use core::task::{Context, Poll};
6
7use embassy_hal_internal::{Peri, PeripheralType};
8use embedded_storage::nor_flash::{
9 check_erase, check_read, check_write, ErrorType, MultiwriteNorFlash, NorFlash, NorFlashError, NorFlashErrorKind,
10 ReadNorFlash,
11};
12
13use crate::dma::{AnyChannel, Channel, Transfer};
14use crate::pac;
15use crate::peripherals::FLASH;
16
17pub const FLASH_BASE: *const u32 = 0x10000000 as _;
19
20#[cfg(feature = "_rp235x")]
22pub const BOOTRAM_BASE: *const u32 = 0x400e0000 as _;
23
24pub const USE_BOOT2: bool = !cfg!(feature = "run-from-ram") | cfg!(feature = "_rp235x");
27
28pub const PAGE_SIZE: usize = 256;
35pub const WRITE_SIZE: usize = 1;
37pub const READ_SIZE: usize = 1;
39pub const ERASE_SIZE: usize = 4096;
41pub const ASYNC_READ_SIZE: usize = 4;
43
44#[derive(Debug, Copy, Clone, PartialEq, Eq)]
46#[cfg_attr(feature = "defmt", derive(defmt::Format))]
47pub enum Error {
48 OutOfBounds,
50 Unaligned,
52 InvalidCore,
54 Other,
56}
57
58impl From<NorFlashErrorKind> for Error {
59 fn from(e: NorFlashErrorKind) -> Self {
60 match e {
61 NorFlashErrorKind::NotAligned => Self::Unaligned,
62 NorFlashErrorKind::OutOfBounds => Self::OutOfBounds,
63 _ => Self::Other,
64 }
65 }
66}
67
68impl NorFlashError for Error {
69 fn kind(&self) -> NorFlashErrorKind {
70 match self {
71 Self::OutOfBounds => NorFlashErrorKind::OutOfBounds,
72 Self::Unaligned => NorFlashErrorKind::NotAligned,
73 _ => NorFlashErrorKind::Other,
74 }
75 }
76}
77
78#[must_use = "futures do nothing unless you `.await` or poll them"]
80pub struct BackgroundRead<'a, 'd, T: Instance, const FLASH_SIZE: usize> {
81 flash: PhantomData<&'a mut Flash<'d, T, Async, FLASH_SIZE>>,
82 transfer: Transfer<'a, AnyChannel>,
83}
84
85impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Future for BackgroundRead<'a, 'd, T, FLASH_SIZE> {
86 type Output = ();
87 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
88 Pin::new(&mut self.transfer).poll(cx)
89 }
90}
91
92impl<'a, 'd, T: Instance, const FLASH_SIZE: usize> Drop for BackgroundRead<'a, 'd, T, FLASH_SIZE> {
93 fn drop(&mut self) {
94 if pac::XIP_CTRL.stream_ctr().read().0 == 0 {
95 return;
96 }
97 pac::XIP_CTRL
98 .stream_ctr()
99 .write_value(pac::xip_ctrl::regs::StreamCtr(0));
100 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
101 #[cfg(feature = "rp2040")]
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 _;
108 unsafe {
109 core::ptr::read_volatile(XIP_NOCACHE_NOALLOC_BASE);
110 }
111 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
112 }
113}
114
115pub struct Flash<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> {
117 dma: Option<Peri<'d, AnyChannel>>,
118 phantom: PhantomData<(&'d mut T, M)>,
119}
120
121impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> Flash<'d, T, M, FLASH_SIZE> {
122 pub fn blocking_read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
128 trace!(
129 "Reading from 0x{:x} to 0x{:x}",
130 FLASH_BASE as u32 + offset,
131 FLASH_BASE as u32 + offset + bytes.len() as u32
132 );
133 check_read(self, offset, bytes.len())?;
134
135 let flash_data = unsafe { core::slice::from_raw_parts((FLASH_BASE as u32 + offset) as *const u8, bytes.len()) };
136
137 bytes.copy_from_slice(flash_data);
138 Ok(())
139 }
140
141 pub fn capacity(&self) -> usize {
143 FLASH_SIZE
144 }
145
146 pub fn blocking_erase(&mut self, from: u32, to: u32) -> Result<(), Error> {
150 check_erase(self, from, to)?;
151
152 trace!(
153 "Erasing from 0x{:x} to 0x{:x}",
154 FLASH_BASE as u32 + from,
155 FLASH_BASE as u32 + to
156 );
157
158 let len = to - from;
159
160 unsafe { in_ram(|| ram_helpers::flash_range_erase(from, len))? };
161
162 Ok(())
163 }
164
165 pub fn blocking_write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Error> {
171 check_write(self, offset, bytes.len())?;
172
173 trace!("Writing {:?} bytes to 0x{:x}", bytes.len(), FLASH_BASE as u32 + offset);
174
175 let end_offset = offset as usize + bytes.len();
176
177 let padded_offset = (offset as *const u8).align_offset(PAGE_SIZE);
178 let start_padding = core::cmp::min(padded_offset, bytes.len());
179
180 if start_padding > 0 {
182 let start = PAGE_SIZE - padded_offset;
183 let end = start + start_padding;
184
185 let mut pad_buf = [0xFF_u8; PAGE_SIZE];
186 pad_buf[start..end].copy_from_slice(&bytes[..start_padding]);
187
188 let unaligned_offset = offset as usize - start;
189
190 unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
191 }
192
193 let remaining_len = bytes.len() - start_padding;
194 let end_padding = start_padding + PAGE_SIZE * (remaining_len / PAGE_SIZE);
195
196 if remaining_len >= PAGE_SIZE {
199 let mut aligned_offset = if start_padding > 0 {
200 offset as usize + padded_offset
201 } else {
202 offset as usize
203 };
204
205 if bytes.as_ptr() as usize >= 0x2000_0000 {
206 let aligned_data = &bytes[start_padding..end_padding];
207
208 unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, aligned_data))? }
209 } else {
210 for chunk in bytes[start_padding..end_padding].chunks_exact(PAGE_SIZE) {
211 let mut ram_buf = [0xFF_u8; PAGE_SIZE];
212 ram_buf.copy_from_slice(chunk);
213 unsafe { in_ram(|| ram_helpers::flash_range_program(aligned_offset as u32, &ram_buf))? }
214 aligned_offset += PAGE_SIZE;
215 }
216 }
217 }
218
219 let rem_offset = (end_offset as *const u8).align_offset(PAGE_SIZE);
221 let rem_padding = remaining_len % PAGE_SIZE;
222 if rem_padding > 0 {
223 let mut pad_buf = [0xFF_u8; PAGE_SIZE];
224 pad_buf[..rem_padding].copy_from_slice(&bytes[end_padding..]);
225
226 let unaligned_offset = end_offset - (PAGE_SIZE - rem_offset);
227
228 unsafe { in_ram(|| ram_helpers::flash_range_program(unaligned_offset as u32, &pad_buf))? }
229 }
230
231 Ok(())
232 }
233
234 #[cfg(feature = "rp2040")]
236 pub fn blocking_unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
237 unsafe { in_ram(|| ram_helpers::flash_unique_id(uid))? };
238 Ok(())
239 }
240
241 #[cfg(feature = "rp2040")]
243 pub fn blocking_jedec_id(&mut self) -> Result<u32, Error> {
244 let mut jedec = None;
245 unsafe {
246 in_ram(|| {
247 jedec.replace(ram_helpers::flash_jedec_id());
248 })?;
249 };
250 Ok(jedec.unwrap())
251 }
252}
253
254impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Blocking, FLASH_SIZE> {
255 pub fn new_blocking(_flash: Peri<'d, T>) -> Self {
257 Self {
258 dma: None,
259 phantom: PhantomData,
260 }
261 }
262}
263
264impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, Async, FLASH_SIZE> {
265 pub fn new(_flash: Peri<'d, T>, dma: Peri<'d, impl Channel>) -> Self {
267 Self {
268 dma: Some(dma.into()),
269 phantom: PhantomData,
270 }
271 }
272
273 pub fn background_read<'a>(
279 &'a mut self,
280 offset: u32,
281 data: &'a mut [u32],
282 ) -> Result<BackgroundRead<'a, 'd, T, FLASH_SIZE>, Error> {
283 trace!(
284 "Reading in background from 0x{:x} to 0x{:x}",
285 FLASH_BASE as u32 + offset,
286 FLASH_BASE as u32 + offset + (data.len() * 4) as u32
287 );
288 let offset = offset as usize;
290 let length = data.len() * 4;
291 if length > self.capacity() || offset > self.capacity() - length {
292 return Err(Error::OutOfBounds);
293 }
294 if offset % 4 != 0 {
295 return Err(Error::Unaligned);
296 }
297
298 while !pac::XIP_CTRL.stat().read().fifo_empty() {
299 pac::XIP_CTRL.stream_fifo().read();
300 }
301
302 pac::XIP_CTRL
303 .stream_addr()
304 .write_value(pac::xip_ctrl::regs::StreamAddr(FLASH_BASE as u32 + offset as u32));
305 pac::XIP_CTRL
306 .stream_ctr()
307 .write_value(pac::xip_ctrl::regs::StreamCtr(data.len() as u32));
308
309 #[cfg(feature = "rp2040")]
313 const XIP_AUX_BASE: *const u32 = 0x50400000 as *const _;
314 #[cfg(feature = "_rp235x")]
315 const XIP_AUX_BASE: *const u32 = 0x50500000 as *const _;
316 let transfer = unsafe {
317 crate::dma::read(
318 self.dma.as_mut().unwrap().reborrow(),
319 XIP_AUX_BASE,
320 data,
321 pac::dma::vals::TreqSel::XIP_STREAM,
322 )
323 };
324
325 Ok(BackgroundRead {
326 flash: PhantomData,
327 transfer,
328 })
329 }
330
331 pub async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Error> {
337 use core::mem::MaybeUninit;
338
339 if bytes.len() % 4 != 0 {
341 return Err(Error::Unaligned);
342 }
343
344 if (bytes.as_ptr() as u32) % 4 == 0 {
346 let buf: &mut [u32] =
348 unsafe { core::slice::from_raw_parts_mut(bytes.as_mut_ptr() as *mut u32, bytes.len() / 4) };
349 self.background_read(offset, buf)?.await;
350 return Ok(());
351 }
352
353 const REALIGN_CHUNK: usize = PAGE_SIZE;
355 let mut buf: [MaybeUninit<u32>; REALIGN_CHUNK / 4] = unsafe { MaybeUninit::uninit().assume_init() };
357 let mut chunk_offset: usize = 0;
358 while chunk_offset < bytes.len() {
359 let chunk_size = (bytes.len() - chunk_offset).min(REALIGN_CHUNK);
360 let buf = &mut buf[..(chunk_size / 4)];
361
362 let buf = unsafe { &mut *(buf as *mut [MaybeUninit<u32>] as *mut [u32]) };
364 self.background_read(offset + chunk_offset as u32, buf)?.await;
365
366 let buf = unsafe { core::slice::from_raw_parts(buf.as_ptr() as *const _, buf.len() * 4) };
368 bytes[chunk_offset..(chunk_offset + chunk_size)].copy_from_slice(&buf[..chunk_size]);
369
370 chunk_offset += chunk_size;
371 }
372
373 Ok(())
374 }
375}
376
377impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, M, FLASH_SIZE> {
378 type Error = Error;
379}
380
381impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> ReadNorFlash for Flash<'d, T, M, FLASH_SIZE> {
382 const READ_SIZE: usize = READ_SIZE;
383
384 fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
385 self.blocking_read(offset, bytes)
386 }
387
388 fn capacity(&self) -> usize {
389 self.capacity()
390 }
391}
392
393impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> MultiwriteNorFlash for Flash<'d, T, M, FLASH_SIZE> {}
394
395impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::MultiwriteNorFlash
396 for Flash<'d, T, Async, FLASH_SIZE>
397{
398}
399
400impl<'d, T: Instance, M: Mode, const FLASH_SIZE: usize> NorFlash for Flash<'d, T, M, FLASH_SIZE> {
401 const WRITE_SIZE: usize = WRITE_SIZE;
402
403 const ERASE_SIZE: usize = ERASE_SIZE;
404
405 fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
406 self.blocking_erase(from, to)
407 }
408
409 fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
410 self.blocking_write(offset, bytes)
411 }
412}
413
414impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::ReadNorFlash
415 for Flash<'d, T, Async, FLASH_SIZE>
416{
417 const READ_SIZE: usize = ASYNC_READ_SIZE;
418
419 async fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
420 self.read(offset, bytes).await
421 }
422
423 fn capacity(&self) -> usize {
424 self.capacity()
425 }
426}
427
428impl<'d, T: Instance, const FLASH_SIZE: usize> embedded_storage_async::nor_flash::NorFlash
429 for Flash<'d, T, Async, FLASH_SIZE>
430{
431 const WRITE_SIZE: usize = WRITE_SIZE;
432
433 const ERASE_SIZE: usize = ERASE_SIZE;
434
435 async fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
436 self.blocking_erase(from, to)
437 }
438
439 async fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
440 self.blocking_write(offset, bytes)
441 }
442}
443
444#[allow(dead_code)]
445mod ram_helpers {
446 use super::*;
447 use crate::rom_data;
448
449 #[repr(C)]
450 struct FlashFunctionPointers<'a> {
451 connect_internal_flash: unsafe extern "C" fn() -> (),
452 flash_exit_xip: unsafe extern "C" fn() -> (),
453 flash_range_erase: Option<unsafe extern "C" fn(addr: u32, count: usize, block_size: u32, block_cmd: u8) -> ()>,
454 flash_range_program: Option<unsafe extern "C" fn(addr: u32, data: *const u8, count: usize) -> ()>,
455 flash_flush_cache: unsafe extern "C" fn() -> (),
456 flash_enter_cmd_xip: unsafe extern "C" fn() -> (),
457 phantom: PhantomData<&'a ()>,
458 }
459
460 #[allow(unused)]
461 fn flash_function_pointers(erase: bool, write: bool) -> FlashFunctionPointers<'static> {
462 FlashFunctionPointers {
463 connect_internal_flash: rom_data::connect_internal_flash::ptr(),
464 flash_exit_xip: rom_data::flash_exit_xip::ptr(),
465 flash_range_erase: if erase {
466 Some(rom_data::flash_range_erase::ptr())
467 } else {
468 None
469 },
470 flash_range_program: if write {
471 Some(rom_data::flash_range_program::ptr())
472 } else {
473 None
474 },
475 flash_flush_cache: rom_data::flash_flush_cache::ptr(),
476 flash_enter_cmd_xip: rom_data::flash_enter_cmd_xip::ptr(),
477 phantom: PhantomData,
478 }
479 }
480
481 #[allow(unused)]
482 unsafe fn flash_function_pointers_with_boot2(
486 erase: bool,
487 write: bool,
488 boot2: &[u32; 64],
489 ) -> FlashFunctionPointers<'_> {
490 let boot2_fn_ptr = (boot2 as *const u32 as *const u8).offset(1);
491 let boot2_fn: unsafe extern "C" fn() -> () = core::mem::transmute(boot2_fn_ptr);
492 FlashFunctionPointers {
493 connect_internal_flash: rom_data::connect_internal_flash::ptr(),
494 flash_exit_xip: rom_data::flash_exit_xip::ptr(),
495 flash_range_erase: if erase {
496 Some(rom_data::flash_range_erase::ptr())
497 } else {
498 None
499 },
500 flash_range_program: if write {
501 Some(rom_data::flash_range_program::ptr())
502 } else {
503 None
504 },
505 flash_flush_cache: rom_data::flash_flush_cache::ptr(),
506 flash_enter_cmd_xip: boot2_fn,
507 phantom: PhantomData,
508 }
509 }
510
511 pub unsafe fn flash_range_erase(addr: u32, len: u32) {
528 let mut boot2 = [0u32; 256 / 4];
529 let ptrs = if USE_BOOT2 {
530 #[cfg(feature = "rp2040")]
531 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
532 #[cfg(feature = "_rp235x")]
533 core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
534 flash_function_pointers_with_boot2(true, false, &boot2)
535 } else {
536 flash_function_pointers(true, false)
537 };
538
539 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
540
541 write_flash_inner(addr, len, None, &ptrs as *const FlashFunctionPointers);
542 }
543
544 pub unsafe fn flash_range_erase_and_program(addr: u32, data: &[u8]) {
561 let mut boot2 = [0u32; 256 / 4];
562 let ptrs = if USE_BOOT2 {
563 #[cfg(feature = "rp2040")]
564 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
565 #[cfg(feature = "_rp235x")]
566 core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, (boot2).as_mut_ptr() as *mut u8, 256);
567 flash_function_pointers_with_boot2(true, true, &boot2)
568 } else {
569 flash_function_pointers(true, true)
570 };
571
572 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
573
574 write_flash_inner(
575 addr,
576 data.len() as u32,
577 Some(data),
578 &ptrs as *const FlashFunctionPointers,
579 );
580 }
581
582 pub unsafe fn flash_range_program(addr: u32, data: &[u8]) {
599 let mut boot2 = [0u32; 256 / 4];
600 let ptrs = if USE_BOOT2 {
601 #[cfg(feature = "rp2040")]
602 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
603 #[cfg(feature = "_rp235x")]
604 core::ptr::copy_nonoverlapping(BOOTRAM_BASE as *const u8, boot2.as_mut_ptr() as *mut u8, 256);
605 flash_function_pointers_with_boot2(false, true, &boot2)
606 } else {
607 flash_function_pointers(false, true)
608 };
609
610 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
611
612 write_flash_inner(
613 addr,
614 data.len() as u32,
615 Some(data),
616 &ptrs as *const FlashFunctionPointers,
617 );
618 }
619
620 #[inline(never)]
630 #[link_section = ".data.ram_func"]
631 #[cfg(feature = "rp2040")]
632 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
633 #[cfg(target_arch = "arm")]
634 core::arch::asm!(
635 "mov r8, r0",
636 "mov r9, r2",
637 "mov r10, r1",
638 "ldr r4, [{ptrs}, #0]",
639 "blx r4", "ldr r4, [{ptrs}, #4]",
642 "blx r4", "mov r0, r8", "mov r1, r10", "movs r2, #1",
647 "lsls r2, r2, #31", "movs r3, #0", "ldr r4, [{ptrs}, #8]",
650 "cmp r4, #0",
651 "beq 2f",
652 "blx r4", "2:",
654
655 "mov r0, r8", "mov r1, r9", "mov r2, r10", "ldr r4, [{ptrs}, #12]",
659 "cmp r4, #0",
660 "beq 2f",
661 "blx r4", "2:",
663
664 "ldr r4, [{ptrs}, #16]",
665 "blx r4", "ldr r4, [{ptrs}, #20]",
668 "blx r4", ptrs = in(reg) ptrs,
670 in("r0") addr,
674 in("r2") data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null()),
675 in("r1") len,
676 out("r3") _,
677 out("r4") _,
678 lateout("r8") _,
679 lateout("r9") _,
680 lateout("r10") _,
681 clobber_abi("C"),
682 );
683 }
684
685 #[inline(never)]
695 #[link_section = ".data.ram_func"]
696 #[cfg(feature = "_rp235x")]
697 unsafe fn write_flash_inner(addr: u32, len: u32, data: Option<&[u8]>, ptrs: *const FlashFunctionPointers) {
698 let data = data.map(|d| d.as_ptr()).unwrap_or(core::ptr::null());
699 ((*ptrs).connect_internal_flash)();
700 ((*ptrs).flash_exit_xip)();
701 if (*ptrs).flash_range_erase.is_some() {
702 ((*ptrs).flash_range_erase.unwrap())(addr, len as usize, 1 << 31, 0);
703 }
704 if (*ptrs).flash_range_program.is_some() {
705 ((*ptrs).flash_range_program.unwrap())(addr, data as *const _, len as usize);
706 }
707 ((*ptrs).flash_flush_cache)();
708 ((*ptrs).flash_enter_cmd_xip)();
709 }
710
711 #[repr(C)]
712 struct FlashCommand {
713 cmd_addr: *const u8,
714 cmd_addr_len: u32,
715 dummy_len: u32,
716 data: *mut u8,
717 data_len: u32,
718 }
719
720 #[cfg(feature = "rp2040")]
745 pub unsafe fn flash_unique_id(out: &mut [u8]) {
746 let mut boot2 = [0u32; 256 / 4];
747 let ptrs = if USE_BOOT2 {
748 rom_data::memcpy44(&mut boot2 as *mut _, FLASH_BASE, 256);
749 flash_function_pointers_with_boot2(false, false, &boot2)
750 } else {
751 flash_function_pointers(false, false)
752 };
753
754 let cmd = [0x4B];
756 read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers);
757 }
758
759 #[cfg(feature = "rp2040")]
775 pub unsafe fn flash_jedec_id() -> u32 {
776 let mut boot2 = [0u32; 256 / 4];
777 let ptrs = if USE_BOOT2 {
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 let mut id = [0u8; 4];
785 let cmd = [0x9F];
787 read_flash(&cmd[..], 0, &mut id[1..4], &ptrs as *const FlashFunctionPointers);
788 u32::from_be_bytes(id)
789 }
790
791 #[cfg(feature = "rp2040")]
792 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) {
793 read_flash_inner(
794 FlashCommand {
795 cmd_addr: cmd_addr.as_ptr(),
796 cmd_addr_len: cmd_addr.len() as u32,
797 dummy_len,
798 data: out.as_mut_ptr(),
799 data_len: out.len() as u32,
800 },
801 ptrs,
802 );
803 }
804
805 #[inline(never)]
814 #[link_section = ".data.ram_func"]
815 #[cfg(feature = "rp2040")]
816 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
817 #[cfg(target_arch = "arm")]
818 core::arch::asm!(
819 "mov r10, r0", "mov r5, r1", "ldr r4, [r5, #0]",
823 "blx r4", "ldr r4, [r5, #4]",
826 "blx r4", "movs r4, #0x18",
830 "lsls r4, r4, #24", "movs r0, #0",
834 "str r0, [r4, #8]", "movs r0, #0x3",
838 "lsls r0, r0, #8", "ldr r1, [r4, #0]", "orrs r1, r0",
841 "str r1, [r4, #0]",
842
843 "mov r3, r10", "ldr r0, [r3, #8]", "ldr r1, [r3, #16]", "add r0, r1",
848 "subs r0, #1",
849 "str r0, [r4, #0x04]", "movs r0, #1",
853 "str r0, [r4, #8]", "mov r2, r4",
857 "adds r2, 0x60", "ldr r0, [r3, #0]", "ldr r1, [r3, #4]", "3:",
861 "ldrb r3, [r0]",
862 "strb r3, [r2]", "adds r0, #1",
864 "subs r1, #1",
865 "bne 3b",
866
867 "mov r3, r10", "ldr r1, [r3, #8]", "cmp r1, #0",
871 "beq 9f",
872 "4:",
873 "ldr r3, [r4, #0x28]", "movs r2, #0x8",
875 "tst r3, r2", "beq 4b",
877
878 "mov r2, r4",
879 "adds r2, 0x60", "ldrb r3, [r2]", "subs r1, #1",
882 "bne 4b",
883
884 "9:",
886 "mov r2, r10", "ldr r0, [r2, #12]", "ldr r1, [r2, #16]", "2:",
891 "ldr r3, [r4, #0x28]", "movs r2, #0x8",
893 "tst r3, r2", "beq 2b",
895
896 "mov r2, r4",
897 "adds r2, 0x60", "ldrb r3, [r2]", "strb r3, [r0]",
900 "adds r0, #1",
901 "subs r1, #1",
902 "bne 2b",
903
904 "movs r0, #0",
906 "str r0, [r4, #8]", "str r0, [r4, #4]", "ldr r4, [r5, #20]",
915 "blx r4", in("r0") &cmd as *const FlashCommand,
918 in("r1") ptrs,
919 out("r2") _,
920 out("r3") _,
921 out("r4") _,
922 out("r5") _,
923 out("r10") _,
929 clobber_abi("C"),
930 );
931 }
932}
933
934pub(crate) unsafe fn in_ram(operation: impl FnOnce()) -> Result<(), Error> {
938 let core_id: u32 = pac::SIO.cpuid().read();
940 if core_id != 0 {
941 return Err(Error::InvalidCore);
942 }
943
944 crate::multicore::pause_core1();
946
947 critical_section::with(|_| {
948 const SRAM_LOWER: u32 = 0x2000_0000;
950 for n in 0..crate::dma::CHANNEL_COUNT {
951 let ch = crate::pac::DMA.ch(n);
952 while ch.read_addr().read() < SRAM_LOWER && ch.ctrl_trig().read().busy() {}
953 }
954 while pac::XIP_CTRL.stream_ctr().read().0 > 0 {}
956
957 operation();
959 });
960
961 crate::multicore::resume_core1();
963 Ok(())
964}
965
966trait SealedInstance {}
967trait SealedMode {}
968
969#[allow(private_bounds)]
971pub trait Instance: SealedInstance + PeripheralType {}
972#[allow(private_bounds)]
974pub trait Mode: SealedMode {}
975
976impl SealedInstance for FLASH {}
977impl Instance for FLASH {}
978
979macro_rules! impl_mode {
980 ($name:ident) => {
981 impl SealedMode for $name {}
982 impl Mode for $name {}
983 };
984}
985
986pub struct Blocking;
988pub struct Async;
990
991impl_mode!(Blocking);
992impl_mode!(Async);