1use core::marker::PhantomData;
33
34use super::Nvm;
35use crate::pac::{Nvmctrl, nvmctrl::ctrlb::Cmdselect};
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 unsafe {
173 core::slice::from_raw_parts_mut(
174 Self::SEEPROM_ADDR as _,
175 self.virtual_size / core::mem::size_of::<TP>(),
176 )
177 }
178 }
179
180 pub fn get<TP: SmartEepromPointableSize>(&self, offset: usize, buffer: &mut [TP]) {
186 let slice = unsafe { self.get_slice() };
187 buffer
188 .iter_mut()
189 .zip(slice.iter().skip(offset))
190 .for_each(|(target, source)| {
191 wait_if_busy();
192 *target = *source
193 });
194 }
195
196 pub fn iter<TP: SmartEepromPointableSize>(&'a self) -> SmartEepromIter<'a, TP> {
198 SmartEepromIter {
199 iter: unsafe { self.get_slice().iter() },
200 }
201 }
202}
203
204pub trait SmartEepromPointableSize: Sealed + Copy {}
207
208impl SmartEepromPointableSize for u8 {}
209impl SmartEepromPointableSize for u16 {}
210impl SmartEepromPointableSize for u32 {}
211
212impl<'a> SmartEeprom<'a, Unlocked> {
213 pub unsafe fn get_mut_slice<TP: SmartEepromPointableSize>(&mut self) -> &mut [TP] {
223 unsafe {
224 core::slice::from_raw_parts_mut(
225 Self::SEEPROM_ADDR as _,
226 self.virtual_size / core::mem::size_of::<TP>(),
227 )
228 }
229 }
230
231 pub fn set<TP: SmartEepromPointableSize>(&mut self, offset: usize, buffer: &[TP]) {
236 let slice = unsafe { self.get_mut_slice() };
237 buffer
238 .iter()
239 .zip(slice.iter_mut().skip(offset))
240 .for_each(|(source, target)| {
241 wait_if_busy();
242 *target = *source
243 });
244 }
245
246 pub fn iter_mut<TP: SmartEepromPointableSize>(&'a mut self) -> SmartEepromIterMut<'a, TP> {
248 SmartEepromIterMut {
249 iter: unsafe { self.get_mut_slice().iter_mut() },
250 }
251 }
252
253 pub fn lock(self) -> SmartEeprom<'a, Locked> {
255 self.nvm
257 .command_sync(Cmdselect::Lsee)
258 .expect("SmartEEPROM locking failed");
259 let Self {
260 nvm, virtual_size, ..
261 } = self;
262 SmartEeprom {
263 nvm,
264 virtual_size,
265 __: PhantomData,
266 }
267 }
268}
269
270impl<'a> SmartEeprom<'a, Locked> {
271 pub fn unlock(self) -> SmartEeprom<'a, Unlocked> {
273 self.nvm
275 .command_sync(Cmdselect::Usee)
276 .expect("SmartEEPROM unlocking failed");
277 let Self {
278 nvm, virtual_size, ..
279 } = self;
280 SmartEeprom {
281 nvm,
282 virtual_size,
283 __: PhantomData,
284 }
285 }
286}
287
288pub struct SmartEepromIter<'a, TP: SmartEepromPointableSize> {
290 iter: core::slice::Iter<'a, TP>,
291}
292
293impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIter<'a, TP> {
294 type Item = &'a TP;
295 fn next(&mut self) -> Option<Self::Item> {
296 wait_if_busy();
297 self.iter.next()
298 }
299}
300
301impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIter<'_, TP> {
302 fn next_back(&mut self) -> Option<Self::Item> {
303 wait_if_busy();
304 self.iter.next_back()
305 }
306}
307
308pub struct SmartEepromIterMut<'a, TP: SmartEepromPointableSize> {
310 iter: core::slice::IterMut<'a, TP>,
311}
312
313impl<'a, TP: SmartEepromPointableSize> Iterator for SmartEepromIterMut<'a, TP> {
314 type Item = &'a mut TP;
315 fn next(&mut self) -> Option<Self::Item> {
316 wait_if_busy();
317 self.iter.next()
318 }
319}
320
321impl<TP: SmartEepromPointableSize> DoubleEndedIterator for SmartEepromIterMut<'_, TP> {
322 fn next_back(&mut self) -> Option<Self::Item> {
323 wait_if_busy();
324 self.iter.next_back()
325 }
326}
327
328#[cfg(test)]
329mod tests {
330 use super::*;
331 #[test]
332 fn test_if_virtual_size_is_mapped_correctly() {
333 fn f(sblk: u32, psz: u32) -> usize {
337 SmartEepromMode::map_sblk_psz_to_virtual_size((sblk, psz))
338 }
339 assert_eq!(f(1, 0), 512);
340 assert_eq!(f(1, 1), 1024);
341 assert_eq!(f(1, 2), 2048);
342 assert_eq!(f(1, 3), 4096);
343 assert_eq!(f(1, 4), 4096);
344 assert_eq!(f(1, 5), 4096);
345 assert_eq!(f(1, 6), 4096);
346 assert_eq!(f(1, 7), 4096);
347 assert_eq!(f(2, 0), 512);
348 assert_eq!(f(2, 1), 1024);
349 assert_eq!(f(2, 2), 2048);
350 assert_eq!(f(2, 3), 4096);
351 assert_eq!(f(2, 4), 8192);
352 assert_eq!(f(2, 5), 8192);
353 assert_eq!(f(2, 6), 8192);
354 assert_eq!(f(2, 7), 8192);
355 assert_eq!(f(3, 0), 512);
356 for i in 3..=4 {
357 assert_eq!(f(i, 1), 1024);
358 assert_eq!(f(i, 2), 2048);
359 assert_eq!(f(i, 3), 4096);
360 assert_eq!(f(i, 4), 8192);
361 assert_eq!(f(i, 5), 16384);
362 assert_eq!(f(i, 6), 16384);
363 assert_eq!(f(i, 7), 16384);
364 }
365 for i in 5..=8 {
366 assert_eq!(f(i, 0), 512);
367 assert_eq!(f(i, 1), 1024);
368 assert_eq!(f(i, 2), 2048);
369 assert_eq!(f(i, 3), 4096);
370 assert_eq!(f(i, 4), 8192);
371 assert_eq!(f(i, 5), 16384);
372 assert_eq!(f(i, 6), 32768);
373 assert_eq!(f(i, 7), 32768);
374 }
375 for i in 9..=10 {
376 assert_eq!(f(i, 0), 512);
377 assert_eq!(f(i, 1), 1024);
378 assert_eq!(f(i, 2), 2048);
379 assert_eq!(f(i, 3), 4096);
380 assert_eq!(f(i, 4), 8192);
381 assert_eq!(f(i, 5), 16384);
382 assert_eq!(f(i, 6), 32768);
383 assert_eq!(f(i, 7), 65536);
384 }
385 }
386}