| 1 | use core::ptr::write_volatile; |
| 2 | use core::sync::atomic::{fence, Ordering}; |
| 3 | |
| 4 | use super::{FlashBank, FlashRegion, FlashSector, FLASH_REGIONS, WRITE_SIZE}; |
| 5 | use crate::flash::Error; |
| 6 | use crate::pac; |
| 7 | |
| 8 | pub(crate) const fn is_default_layout() -> bool { |
| 9 | true |
| 10 | } |
| 11 | |
| 12 | pub(crate) const fn get_flash_regions() -> &'static [&'static FlashRegion] { |
| 13 | &FLASH_REGIONS |
| 14 | } |
| 15 | |
| 16 | pub(crate) unsafe fn lock() { |
| 17 | #[cfg (feature = "trustzone-secure" )] |
| 18 | pac::FLASH.seccr().modify(|w| w.set_lock(true)); |
| 19 | #[cfg (not(feature = "trustzone-secure" ))] |
| 20 | pac::FLASH.nscr().modify(|w: &mut Nscr| w.set_lock(val:true)); |
| 21 | } |
| 22 | |
| 23 | pub(crate) unsafe fn unlock() { |
| 24 | #[cfg (feature = "trustzone-secure" )] |
| 25 | if pac::FLASH.seccr().read().lock() { |
| 26 | pac::FLASH.seckeyr().write_value(0x4567_0123); |
| 27 | pac::FLASH.seckeyr().write_value(0xCDEF_89AB); |
| 28 | } |
| 29 | #[cfg (not(feature = "trustzone-secure" ))] |
| 30 | if pac::FLASH.nscr().read().lock() { |
| 31 | pac::FLASH.nskeyr().write_value(val:0x4567_0123); |
| 32 | pac::FLASH.nskeyr().write_value(val:0xCDEF_89AB); |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | pub(crate) unsafe fn enable_blocking_write() { |
| 37 | assert_eq!(0, WRITE_SIZE % 4); |
| 38 | |
| 39 | #[cfg (feature = "trustzone-secure" )] |
| 40 | pac::FLASH.seccr().write(|w| { |
| 41 | w.set_pg(pac::flash::vals::SeccrPg::B_0X1); |
| 42 | }); |
| 43 | #[cfg (not(feature = "trustzone-secure" ))] |
| 44 | pac::FLASH.nscr().write(|w: &mut Nscr| { |
| 45 | w.set_pg(val:pac::flash::vals::NscrPg::B_0X1); |
| 46 | }); |
| 47 | } |
| 48 | |
| 49 | pub(crate) unsafe fn disable_blocking_write() { |
| 50 | #[cfg (feature = "trustzone-secure" )] |
| 51 | pac::FLASH.seccr().write(|w| w.set_pg(pac::flash::vals::SeccrPg::B_0X0)); |
| 52 | #[cfg (not(feature = "trustzone-secure" ))] |
| 53 | pac::FLASH.nscr().write(|w: &mut Nscr| w.set_pg(val:pac::flash::vals::NscrPg::B_0X0)); |
| 54 | } |
| 55 | |
| 56 | pub(crate) unsafe fn blocking_write(start_address: u32, buf: &[u8; WRITE_SIZE]) -> Result<(), Error> { |
| 57 | let mut address: u32 = start_address; |
| 58 | for val: &[u8] in buf.chunks(chunk_size:4) { |
| 59 | write_volatile(dst:address as *mut u32, src:u32::from_le_bytes(unwrap!(val.try_into()))); |
| 60 | address += val.len() as u32; |
| 61 | |
| 62 | // prevents parallelism errors |
| 63 | fence(order:Ordering::SeqCst); |
| 64 | } |
| 65 | |
| 66 | blocking_wait_ready() |
| 67 | } |
| 68 | |
| 69 | pub(crate) unsafe fn blocking_erase_sector(sector: &FlashSector) -> Result<(), Error> { |
| 70 | #[cfg (feature = "trustzone-secure" )] |
| 71 | pac::FLASH.seccr().modify(|w| { |
| 72 | w.set_per(pac::flash::vals::SeccrPer::B_0X1); |
| 73 | w.set_pnb(sector.index_in_bank); |
| 74 | // TODO: add check for bank swap |
| 75 | w.set_bker(match sector.bank { |
| 76 | FlashBank::Bank1 => pac::flash::vals::SeccrBker::B_0X0, |
| 77 | FlashBank::Bank2 => pac::flash::vals::SeccrBker::B_0X1, |
| 78 | }); |
| 79 | }); |
| 80 | #[cfg (not(feature = "trustzone-secure" ))] |
| 81 | pac::FLASH.nscr().modify(|w| { |
| 82 | w.set_per(pac::flash::vals::NscrPer::B_0X1); |
| 83 | w.set_pnb(sector.index_in_bank); |
| 84 | // TODO: add check for bank swap |
| 85 | w.set_bker(match sector.bank { |
| 86 | FlashBank::Bank1 => pac::flash::vals::NscrBker::B_0X0, |
| 87 | FlashBank::Bank2 => pac::flash::vals::NscrBker::B_0X1, |
| 88 | }); |
| 89 | }); |
| 90 | |
| 91 | #[cfg (feature = "trustzone-secure" )] |
| 92 | pac::FLASH.seccr().modify(|w| { |
| 93 | w.set_strt(true); |
| 94 | }); |
| 95 | #[cfg (not(feature = "trustzone-secure" ))] |
| 96 | pac::FLASH.nscr().modify(|w| { |
| 97 | w.set_strt(true); |
| 98 | }); |
| 99 | |
| 100 | let ret: Result<(), Error> = blocking_wait_ready(); |
| 101 | #[cfg (feature = "trustzone-secure" )] |
| 102 | pac::FLASH |
| 103 | .seccr() |
| 104 | .modify(|w| w.set_per(pac::flash::vals::SeccrPer::B_0X0)); |
| 105 | #[cfg (not(feature = "trustzone-secure" ))] |
| 106 | pac::FLASH |
| 107 | .nscr() |
| 108 | .modify(|w| w.set_per(pac::flash::vals::NscrPer::B_0X0)); |
| 109 | clear_all_err(); |
| 110 | ret |
| 111 | } |
| 112 | |
| 113 | pub(crate) unsafe fn clear_all_err() { |
| 114 | // read and write back the same value. |
| 115 | // This clears all "write 1 to clear" bits. |
| 116 | #[cfg (feature = "trustzone-secure" )] |
| 117 | pac::FLASH.secsr().modify(|_| {}); |
| 118 | #[cfg (not(feature = "trustzone-secure" ))] |
| 119 | pac::FLASH.nssr().modify(|_| {}); |
| 120 | } |
| 121 | |
| 122 | unsafe fn blocking_wait_ready() -> Result<(), Error> { |
| 123 | loop { |
| 124 | #[cfg (feature = "trustzone-secure" )] |
| 125 | let sr = pac::FLASH.secsr().read(); |
| 126 | #[cfg (not(feature = "trustzone-secure" ))] |
| 127 | let sr = pac::FLASH.nssr().read(); |
| 128 | |
| 129 | if !sr.bsy() { |
| 130 | if sr.pgserr() { |
| 131 | return Err(Error::Seq); |
| 132 | } |
| 133 | |
| 134 | if sr.sizerr() { |
| 135 | return Err(Error::Size); |
| 136 | } |
| 137 | |
| 138 | if sr.pgaerr() { |
| 139 | return Err(Error::Unaligned); |
| 140 | } |
| 141 | |
| 142 | if sr.wrperr() { |
| 143 | return Err(Error::Protected); |
| 144 | } |
| 145 | |
| 146 | if sr.progerr() { |
| 147 | return Err(Error::Prog); |
| 148 | } |
| 149 | |
| 150 | return Ok(()); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | |