aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2023-05-16 09:36:06 +0000
committerGitHub <[email protected]>2023-05-16 09:36:06 +0000
commit56f2e0c9a02f6db9fe4e3a72a9b7fdd160a90aa8 (patch)
tree08c779b0eb667841d33131a0d4f302d3a7b234a7
parentb0541c01bed231e0e6355db83c87e3ec2b196e70 (diff)
parentb950d6d72bf92f1943f885ce700685fedf4b6cd9 (diff)
Merge #1462
1462: rp: Read flash unique id and jedec id r=Dirbaio a=kalkyl Co-authored-by: kalkyl <[email protected]>
-rw-r--r--embassy-rp/src/flash.rs231
-rw-r--r--examples/rp/src/bin/flash.rs10
-rw-r--r--tests/rp/src/bin/flash.rs9
3 files changed, 250 insertions, 0 deletions
diff --git a/embassy-rp/src/flash.rs b/embassy-rp/src/flash.rs
index 51c7af913..929bd028c 100644
--- a/embassy-rp/src/flash.rs
+++ b/embassy-rp/src/flash.rs
@@ -187,6 +187,23 @@ impl<'d, T: Instance, const FLASH_SIZE: usize> Flash<'d, T, FLASH_SIZE> {
187 crate::multicore::resume_core1(); 187 crate::multicore::resume_core1();
188 Ok(()) 188 Ok(())
189 } 189 }
190
191 /// Read SPI flash unique ID
192 pub fn unique_id(&mut self, uid: &mut [u8]) -> Result<(), Error> {
193 unsafe { self.in_ram(|| ram_helpers::flash_unique_id(uid, true))? };
194 Ok(())
195 }
196
197 /// Read SPI flash JEDEC ID
198 pub fn jedec_id(&mut self) -> Result<u32, Error> {
199 let mut jedec = None;
200 unsafe {
201 self.in_ram(|| {
202 jedec.replace(ram_helpers::flash_jedec_id(true));
203 })?;
204 };
205 Ok(jedec.unwrap())
206 }
190} 207}
191 208
192impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> { 209impl<'d, T: Instance, const FLASH_SIZE: usize> ErrorType for Flash<'d, T, FLASH_SIZE> {
@@ -457,6 +474,220 @@ mod ram_helpers {
457 clobber_abi("C"), 474 clobber_abi("C"),
458 ); 475 );
459 } 476 }
477
478 #[repr(C)]
479 struct FlashCommand {
480 cmd_addr: *const u8,
481 cmd_addr_len: u32,
482 dummy_len: u32,
483 data: *mut u8,
484 data_len: u32,
485 }
486
487 /// Return SPI flash unique ID
488 ///
489 /// Not all SPI flashes implement this command, so check the JEDEC
490 /// ID before relying on it. The Winbond parts commonly seen on
491 /// RP2040 devboards (JEDEC=0xEF7015) support an 8-byte unique ID;
492 /// https://forums.raspberrypi.com/viewtopic.php?t=331949 suggests
493 /// that LCSC (Zetta) parts have a 16-byte unique ID (which is
494 /// *not* unique in just its first 8 bytes),
495 /// JEDEC=0xBA6015. Macronix and Spansion parts do not have a
496 /// unique ID.
497 ///
498 /// The returned bytes are relatively predictable and should be
499 /// salted and hashed before use if that is an issue (e.g. for MAC
500 /// addresses).
501 ///
502 /// # Safety
503 ///
504 /// Nothing must access flash while this is running.
505 /// Usually this means:
506 /// - interrupts must be disabled
507 /// - 2nd core must be running code from RAM or ROM with interrupts disabled
508 /// - DMA must not access flash memory
509 ///
510 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
511 pub unsafe fn flash_unique_id(out: &mut [u8], use_boot2: bool) {
512 let mut boot2 = [0u32; 256 / 4];
513 let ptrs = if use_boot2 {
514 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
515 flash_function_pointers_with_boot2(false, false, &boot2)
516 } else {
517 flash_function_pointers(false, false)
518 };
519 // 4B - read unique ID
520 let cmd = [0x4B];
521 read_flash(&cmd[..], 4, out, &ptrs as *const FlashFunctionPointers);
522 }
523
524 /// Return SPI flash JEDEC ID
525 ///
526 /// This is the three-byte manufacturer-and-model identifier
527 /// commonly used to check before using manufacturer-specific SPI
528 /// flash features, e.g. 0xEF7015 for Winbond W25Q16JV.
529 ///
530 /// # Safety
531 ///
532 /// Nothing must access flash while this is running.
533 /// Usually this means:
534 /// - interrupts must be disabled
535 /// - 2nd core must be running code from RAM or ROM with interrupts disabled
536 /// - DMA must not access flash memory
537 ///
538 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
539 pub unsafe fn flash_jedec_id(use_boot2: bool) -> u32 {
540 let mut boot2 = [0u32; 256 / 4];
541 let ptrs = if use_boot2 {
542 rom_data::memcpy44(&mut boot2 as *mut _, 0x10000000 as *const _, 256);
543 flash_function_pointers_with_boot2(false, false, &boot2)
544 } else {
545 flash_function_pointers(false, false)
546 };
547 let mut id = [0u8; 4];
548 // 9F - read JEDEC ID
549 let cmd = [0x9F];
550 read_flash(&cmd[..], 0, &mut id[1..4], &ptrs as *const FlashFunctionPointers);
551 u32::from_be_bytes(id)
552 }
553
554 unsafe fn read_flash(cmd_addr: &[u8], dummy_len: u32, out: &mut [u8], ptrs: *const FlashFunctionPointers) {
555 read_flash_inner(
556 FlashCommand {
557 cmd_addr: cmd_addr.as_ptr(),
558 cmd_addr_len: cmd_addr.len() as u32,
559 dummy_len,
560 data: out.as_mut_ptr(),
561 data_len: out.len() as u32,
562 },
563 ptrs,
564 );
565 }
566
567 /// Issue a generic SPI flash read command
568 ///
569 /// # Arguments
570 ///
571 /// * `cmd` - `FlashCommand` structure
572 /// * `ptrs` - Flash function pointers as per `write_flash_inner`
573 ///
574 /// Credit: taken from `rp2040-flash` (also licensed Apache+MIT)
575 #[inline(never)]
576 #[link_section = ".data.ram_func"]
577 unsafe fn read_flash_inner(cmd: FlashCommand, ptrs: *const FlashFunctionPointers) {
578 core::arch::asm!(
579 "mov r10, r0", // cmd
580 "mov r5, r1", // ptrs
581
582 "ldr r4, [r5, #0]",
583 "blx r4", // connect_internal_flash()
584
585 "ldr r4, [r5, #4]",
586 "blx r4", // flash_exit_xip()
587
588 "mov r7, r10", // cmd
589
590 "movs r4, #0x18",
591 "lsls r4, r4, #24", // 0x18000000, SSI, RP2040 datasheet 4.10.13
592
593 // Disable, write 0 to SSIENR
594 "movs r0, #0",
595 "str r0, [r4, #8]", // SSIENR
596
597 // Write ctrlr0
598 "movs r0, #0x3",
599 "lsls r0, r0, #8", // TMOD=0x300
600 "ldr r1, [r4, #0]", // CTRLR0
601 "orrs r1, r0",
602 "str r1, [r4, #0]",
603
604 // Write ctrlr1 with len-1
605 "ldr r0, [r7, #8]", // dummy_len
606 "ldr r1, [r7, #16]", // data_len
607 "add r0, r1",
608 "subs r0, #1",
609 "str r0, [r4, #0x04]", // CTRLR1
610
611 // Enable, write 1 to ssienr
612 "movs r0, #1",
613 "str r0, [r4, #8]", // SSIENR
614
615 // Write cmd/addr phase to DR
616 "mov r2, r4",
617 "adds r2, 0x60", // &DR
618 "ldr r0, [r7, #0]", // cmd_addr
619 "ldr r1, [r7, #4]", // cmd_addr_len
620 "10:",
621 "ldrb r3, [r0]",
622 "strb r3, [r2]", // DR
623 "adds r0, #1",
624 "subs r1, #1",
625 "bne 10b",
626
627 // Skip any dummy cycles
628 "ldr r1, [r7, #8]", // dummy_len
629 "cmp r1, #0",
630 "beq 9f",
631 "4:",
632 "ldr r3, [r4, #0x28]", // SR
633 "movs r2, #0x8",
634 "tst r3, r2", // SR.RFNE
635 "beq 4b",
636
637 "mov r2, r4",
638 "adds r2, 0x60", // &DR
639 "ldrb r3, [r2]", // DR
640 "subs r1, #1",
641 "bne 4b",
642
643 // Read RX fifo
644 "9:",
645 "ldr r0, [r7, #12]", // data
646 "ldr r1, [r7, #16]", // data_len
647
648 "2:",
649 "ldr r3, [r4, #0x28]", // SR
650 "movs r2, #0x8",
651 "tst r3, r2", // SR.RFNE
652 "beq 2b",
653
654 "mov r2, r4",
655 "adds r2, 0x60", // &DR
656 "ldrb r3, [r2]", // DR
657 "strb r3, [r0]",
658 "adds r0, #1",
659 "subs r1, #1",
660 "bne 2b",
661
662 // Disable, write 0 to ssienr
663 "movs r0, #0",
664 "str r0, [r4, #8]", // SSIENR
665
666 // Write 0 to CTRLR1 (returning to its default value)
667 //
668 // flash_enter_cmd_xip does NOT do this, and everything goes
669 // wrong unless we do it here
670 "str r0, [r4, #4]", // CTRLR1
671
672 "ldr r4, [r5, #20]",
673 "blx r4", // flash_enter_cmd_xip();
674
675 in("r0") &cmd as *const FlashCommand,
676 in("r1") ptrs,
677 out("r2") _,
678 out("r3") _,
679 out("r4") _,
680 // Registers r8-r10 are used to store values
681 // from r0-r2 in registers not clobbered by
682 // function calls.
683 // The values can't be passed in using r8-r10 directly
684 // due to https://github.com/rust-lang/rust/issues/99071
685 out("r8") _,
686 out("r9") _,
687 out("r10") _,
688 clobber_abi("C"),
689 );
690 }
460} 691}
461 692
462mod sealed { 693mod sealed {
diff --git a/examples/rp/src/bin/flash.rs b/examples/rp/src/bin/flash.rs
index 8d6b379f4..19076150c 100644
--- a/examples/rp/src/bin/flash.rs
+++ b/examples/rp/src/bin/flash.rs
@@ -24,6 +24,16 @@ async fn main(_spawner: Spawner) {
24 Timer::after(Duration::from_millis(10)).await; 24 Timer::after(Duration::from_millis(10)).await;
25 25
26 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH); 26 let mut flash = embassy_rp::flash::Flash::<_, FLASH_SIZE>::new(p.FLASH);
27
28 // Get JEDEC id
29 let jedec = flash.jedec_id().unwrap();
30 info!("jedec id: 0x{:x}", jedec);
31
32 // Get unique id
33 let mut uid = [0; 8];
34 flash.unique_id(&mut uid).unwrap();
35 info!("unique id: {:?}", uid);
36
27 erase_write_sector(&mut flash, 0x00); 37 erase_write_sector(&mut flash, 0x00);
28 38
29 multiwrite_bytes(&mut flash, ERASE_SIZE as u32); 39 multiwrite_bytes(&mut flash, ERASE_SIZE as u32);
diff --git a/tests/rp/src/bin/flash.rs b/tests/rp/src/bin/flash.rs
index 897e3804f..00bebe2b6 100644
--- a/tests/rp/src/bin/flash.rs
+++ b/tests/rp/src/bin/flash.rs
@@ -23,6 +23,15 @@ async fn main(_spawner: Spawner) {
23 23
24 let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH); 24 let mut flash = embassy_rp::flash::Flash::<_, { 2 * 1024 * 1024 }>::new(p.FLASH);
25 25
26 // Get JEDEC id
27 let jedec = defmt::unwrap!(flash.jedec_id());
28 info!("jedec id: 0x{:x}", jedec);
29
30 // Get unique id
31 let mut uid = [0; 8];
32 defmt::unwrap!(flash.unique_id(&mut uid));
33 info!("unique id: {:?}", uid);
34
26 let mut buf = [0u8; ERASE_SIZE]; 35 let mut buf = [0u8; ERASE_SIZE];
27 defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf)); 36 defmt::unwrap!(flash.read(ADDR_OFFSET, &mut buf));
28 37