1use core::marker::PhantomData;
33
34use super::Nvm;
35use crate::pac::{nvmctrl::ctrlb::Cmdselect, Nvmctrl};
36use crate::typelevel::Sealed;
37
38pub struct SmartEeprom<'a, T: SmartEepromState> {
44 nvm: &'a mut Nvm,
45 virtual_size: usize,
46 __: PhantomData<T>,
47}
48
49pub trait SmartEepromState: Sealed {}
51
52pub enum Locked {}
55impl SmartEepromState for Locked {}
56impl Sealed for Locked {}
57pub enum Unlocked {}
60impl SmartEepromState for Unlocked {}
61impl Sealed for Unlocked {}
62
63#[derive(Debug)]
66pub enum SmartEepromRetrievalFailure {
67 Disabled,
70 DisabledAutomaticPageReallocationNotSupported,
72 BufferedWritesNotSupported,
74 InvalidBlockCount {
79 sblk: u32,
81 },
82}
83
84pub enum SmartEepromMode<'a> {
86 Locked(SmartEeprom<'a, Locked>),
88 Unlocked(SmartEeprom<'a, Unlocked>),
90}
91
92pub type Result<'a> = core::result::Result<SmartEepromMode<'a>, SmartEepromRetrievalFailure>;
94
95#[inline]
96fn wait_if_busy() {
97 let nvmctrl = unsafe { &*Nvmctrl::ptr() };
100 while nvmctrl.seestat().read().busy().bit_is_set() {}
101}
102
103impl<'a> SmartEepromMode<'a> {
104 pub(super) fn retrieve(nvm: &'a mut Nvm) -> Result<'a> {
107 use SmartEepromMode as Mode;
108 use SmartEepromRetrievalFailure::*;
109 if nvm.nvm.seecfg().read().aprdis().bit_is_set() {
110 return Err(DisabledAutomaticPageReallocationNotSupported);
111 }
112 if nvm.nvm.seecfg().read().wmode().is_buffered() {
113 return Err(BufferedWritesNotSupported);
114 }
115 let sblk = nvm.nvm.seestat().read().sblk().bits() as u32;
116 let psz = nvm.nvm.seestat().read().psz().bits() as u32;
117 let virtual_size = match (sblk, psz) {
118 (0, _) => return Err(Disabled),
119 (sblk @ 11..=u32::MAX, _) => return Err(InvalidBlockCount { sblk }),
120 (_, 8..=u32::MAX) => {
121 unreachable!("`Nvmctrl.SEESTAT.PSZ` value is represented with 3 bits in user page")
122 }
123 others => Self::map_sblk_psz_to_virtual_size(others),
124 };
125 if nvm.nvm.seestat().read().lock().bit_is_set() {
126 Ok(Mode::Locked(SmartEeprom {
127 nvm,
128 virtual_size,
129 __: PhantomData::<Locked>,
130 }))
131 } else {
132 Ok(Mode::Unlocked(SmartEeprom {
133 nvm,
134 virtual_size,
135 __: PhantomData::<Unlocked>,
136 }))
137 }
138 }
139
140 fn map_sblk_psz_to_virtual_size(sblk_psz_pair: (u32, u32)) -> usize {
141 match sblk_psz_pair {
142 (_, 0) => 512,
143 (_, 1) => 1024,
144 (_, 2) => 2048,
145 (_, 3) => 4096,
146 (1, _) => 4096,
147 (_, 4) => 8192,
148 (2, _) => 8192,
149 (_, 5) => 16384,
150 (3 | 4, _) => 16384,
151 (_, 6) => 32768,
152 (5..=8, _) => 32768,
153 (_, 7) => 65536,
154 _ => unreachable!(),
155 }
156 }
157}
158
159impl<'a, T: SmartEepromState> SmartEeprom<'a, T> {
160 const SEEPROM_ADDR: *mut usize = 0x44000000 as _;
161
162 pub unsafe fn get_slice<TP: SmartEepromPointableSize>(&self) -> &[TP] {
172 core::slice::from_raw_parts_mut(
173 Self::SEEPROM_ADDR as _,
174 self.virtual_size / core::mem::size_of::<TP>(),
175 )
176 }
177
178 pub fn get<TP: SmartEepromPointableSize>(&self, offset: usize, buffer: &mut [TP]) {
184 let slice = unsafe { self.get_slice() };
185 buffer
186 .iter_mut()
187 .zip(slice.iter().skip(offset))
188 .for_each(|(target, source)| {
189 wait_if_busy();
190 *target = *source
191 });
192 }
193
194 pub fn iter<TP: SmartEepromPointableSize>(&'a self) -> SmartEepromIter<'a, TP> {
196 SmartEepromIter {
197 iter: unsafe { self.get_slice().iter() },
198 }
199 }
200}
201
202pub trait SmartEepromPointableSize: Sealed + Copy {}
205
206impl SmartEepromPointableSize for u8 {}
207impl SmartEepromPointableSize for u16 {}
208impl SmartEepromPointableSize for u32 {}
209
210impl<'a> SmartEeprom<'a, Unlocked> {
211 pub unsafe fn get_mut_slice<TP: SmartEepromPointableSize>(&mut self) -> &mut [TP] {
221 core::slice::from_raw_parts_mut(
222 Self::SEEPROM_ADDR as _,
223 self.virtual_size / core::mem::size_of::<TP>(),
224 )
225 }
226
227 pub fn set<TP: SmartEepromPointableSize>(&mut self, offset: usize, buffer: &[TP]) {
232 let slice = unsafe { self.get_mut_slice() };
233 buffer
234 .iter()
235 .zip(slice.iter_mut().skip(offset))
236 .for_each(|(source, target)| {
237 wait_if_busy();
238 *target = *source
239 });
240 }
241
242 pub fn iter_mut<TP: SmartEepromPointableSize>(&'a mut self) -> SmartEepromIterMut<'a, TP> {
244 SmartEepromIterMut {
245 iter: unsafe { self.get_mut_slice().iter_mut() },
246 }
247 }
248
249 pub fn lock(self) -> SmartEeprom<'a, Locked> {
251 self.nvm
253 .command_sync(Cmdselect::Lsee)
254 .expect("SmartEEPROM locking failed");
255 let Self {
256 nvm, virtual_size, ..
257 } = self;
258 SmartEeprom {
259 nvm,
260 virtual_size,
261 __: PhantomData,
262 }
263 }
264}
265
266impl<'a> SmartEeprom<'a, Locked> {
267 pub fn unlock(self) -> SmartEeprom<'a, Unlocked> {
269 self.nvm
271 .command_sync(Cmdselect::Usee)
272 .expect("SmartEEPROM unlocking failed");
273 let Self {
274 nvm, virtual_size, ..
275 } = self;
276 SmartEeprom {
277 nvm,
278 virtual_size,
279 __: PhantomData,
280 }
281 }
282}
283
284pub struct SmartEepromIter<'a, TP: SmartEepromPointableSize> {
286 iter: core::slice::Iter<'a, TP>,
287}
288
289impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIter<'a, TP> {
290 type Item = &'a TP;
291 fn next(&mut self) -> Option<Self::Item> {
292 wait_if_busy();
293 self.iter.next()
294 }
295}
296
297impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIter<'_, TP> {
298 fn next_back(&mut self) -> Option<Self::Item> {
299 wait_if_busy();
300 self.iter.next_back()
301 }
302}
303
304pub struct SmartEepromIterMut<'a, TP: SmartEepromPointableSize> {
306 iter: core::slice::IterMut<'a, TP>,
307}
308
309impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIterMut<'a, TP> {
310 type Item = &'a mut TP;
311 fn next(&mut self) -> Option<Self::Item> {
312 wait_if_busy();
313 self.iter.next()
314 }
315}
316
317impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIterMut<'_, TP> {
318 fn next_back(&mut self) -> Option<Self::Item> {
319 wait_if_busy();
320 self.iter.next_back()
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327 #[test]
328 fn test_if_virtual_size_is_mapped_correctly() {
329 fn f(sblk: u32, psz: u32) -> usize {
333 SmartEepromMode::map_sblk_psz_to_virtual_size((sblk, psz))
334 }
335 assert_eq!(f(1, 0), 512);
336 assert_eq!(f(1, 1), 1024);
337 assert_eq!(f(1, 2), 2048);
338 assert_eq!(f(1, 3), 4096);
339 assert_eq!(f(1, 4), 4096);
340 assert_eq!(f(1, 5), 4096);
341 assert_eq!(f(1, 6), 4096);
342 assert_eq!(f(1, 7), 4096);
343 assert_eq!(f(2, 0), 512);
344 assert_eq!(f(2, 1), 1024);
345 assert_eq!(f(2, 2), 2048);
346 assert_eq!(f(2, 3), 4096);
347 assert_eq!(f(2, 4), 8192);
348 assert_eq!(f(2, 5), 8192);
349 assert_eq!(f(2, 6), 8192);
350 assert_eq!(f(2, 7), 8192);
351 assert_eq!(f(3, 0), 512);
352 for i in 3..=4 {
353 assert_eq!(f(i, 1), 1024);
354 assert_eq!(f(i, 2), 2048);
355 assert_eq!(f(i, 3), 4096);
356 assert_eq!(f(i, 4), 8192);
357 assert_eq!(f(i, 5), 16384);
358 assert_eq!(f(i, 6), 16384);
359 assert_eq!(f(i, 7), 16384);
360 }
361 for i in 5..=8 {
362 assert_eq!(f(i, 0), 512);
363 assert_eq!(f(i, 1), 1024);
364 assert_eq!(f(i, 2), 2048);
365 assert_eq!(f(i, 3), 4096);
366 assert_eq!(f(i, 4), 8192);
367 assert_eq!(f(i, 5), 16384);
368 assert_eq!(f(i, 6), 32768);
369 assert_eq!(f(i, 7), 32768);
370 }
371 for i in 9..=10 {
372 assert_eq!(f(i, 0), 512);
373 assert_eq!(f(i, 1), 1024);
374 assert_eq!(f(i, 2), 2048);
375 assert_eq!(f(i, 3), 4096);
376 assert_eq!(f(i, 4), 8192);
377 assert_eq!(f(i, 5), 16384);
378 assert_eq!(f(i, 6), 32768);
379 assert_eq!(f(i, 7), 65536);
380 }
381 }
382}