Skip to main content

atsam4_hal/
efc.rs

1//! HAL interface to the Enhanced Embedded Flash Controller (EEFC) peripheral
2//!
3//! Loosely based off of <https://github.com/nrf-rs/nrf-hal/blob/master/nrf-hal-common/src/nvmc.rs>
4//! Many of the functions are named the same as ASF (minus flash_) and should be mostly equivalent.
5
6#[cfg(any(feature = "atsam4e", feature = "atsam4n"))]
7use crate::pac::efc;
8
9#[cfg(any(feature = "atsam4e", feature = "atsam4n"))]
10use crate::pac::EFC;
11
12#[cfg(feature = "atsam4s")]
13use crate::pac::efc0 as efc;
14
15#[cfg(feature = "atsam4s")]
16use crate::pac::EFC0 as EFC;
17
18#[cfg(feature = "atsam4sd")]
19use crate::pac::EFC1;
20
21use cortex_m::interrupt;
22use embedded_storage::nor_flash::{
23    ErrorType, NorFlash, NorFlashError, NorFlashErrorKind, ReadNorFlash,
24};
25
26// Common EEFC constants for sam4-hal
27const FLASH_PAGE_SIZE: u32 = 512;
28const USER_SIG_FLASH_SIZE: u32 = 512;
29const FLASH_LOCK_REGION_SIZE: u32 = 8192;
30const FLASH_READ_SIZE: u32 = 4;
31const FLASH_WRITE_SIZE: u32 = 4;
32
33struct FlashParameters {
34    gpnvm_num_max: u8,
35    flash0_addr: u32,
36    flash0_size: u32,
37    #[cfg(feature = "atsam4sd")]
38    flash1_addr: u32,
39    #[cfg(feature = "atsam4sd")]
40    flash1_size: u32,
41}
42
43#[cfg(any(feature = "atsam4e8c", feature = "atsam4e8e"))]
44const FLASH_PARAMS: FlashParameters = FlashParameters {
45    gpnvm_num_max: 2,
46    flash0_addr: 0x00400000,
47    flash0_size: 0x00080000,
48};
49
50#[cfg(any(feature = "atsam4e16c", feature = "atsam4e16e"))]
51const FLASH_PARAMS: FlashParameters = FlashParameters {
52    gpnvm_num_max: 2,
53    flash0_addr: 0x00400000,
54    flash0_size: 0x00100000,
55};
56
57#[cfg(any(feature = "atsam4n8a", feature = "atsam4n8b", feature = "atsam4n8c"))]
58const FLASH_PARAMS: FlashParameters = FlashParameters {
59    gpnvm_num_max: 2,
60    flash0_addr: 0x00400000,
61    flash0_size: 0x00080000,
62};
63
64#[cfg(any(feature = "atsam4n16b", feature = "atsam4n16c"))]
65const FLASH_PARAMS: FlashParameters = FlashParameters {
66    gpnvm_num_max: 2,
67    flash0_addr: 0x00400000,
68    flash0_size: 0x00100000,
69};
70
71#[cfg(any(feature = "atsam4s2a", feature = "atsam4s2b", feature = "atsam4s2c"))]
72const FLASH_PARAMS: FlashParameters = FlashParameters {
73    gpnvm_num_max: 2,
74    flash0_addr: 0x00400000,
75    flash0_size: 0x00020000,
76};
77
78#[cfg(any(feature = "atsam4s4a", feature = "atsam4s4b", feature = "atsam4s4c"))]
79const FLASH_PARAMS: FlashParameters = FlashParameters {
80    gpnvm_num_max: 2,
81    flash0_addr: 0x00400000,
82    flash0_size: 0x00040000,
83};
84
85#[cfg(any(feature = "atsam4s8b", feature = "atsam4s8c"))]
86const FLASH_PARAMS: FlashParameters = FlashParameters {
87    gpnvm_num_max: 2,
88    flash0_addr: 0x00400000,
89    flash0_size: 0x0080000,
90};
91
92#[cfg(any(feature = "atsam4sa16b", feature = "atsam4sa16c"))]
93const FLASH_PARAMS: FlashParameters = FlashParameters {
94    gpnvm_num_max: 2,
95    flash0_addr: 0x00400000,
96    flash0_size: 0x00100000,
97};
98
99#[cfg(any(feature = "atsam4sd16b", feature = "atsam4sd16c"))]
100const FLASH_PARAMS: FlashParameters = FlashParameters {
101    gpnvm_num_max: 3,
102    flash0_addr: 0x00400000,
103    flash0_size: 0x00080000,
104    flash1_addr: 0x00480000,
105    flash1_size: 0x00080000,
106};
107
108#[cfg(any(feature = "atsam4sd32b", feature = "atsam4sd32c"))]
109const FLASH_PARAMS: FlashParameters = FlashParameters {
110    gpnvm_num_max: 3,
111    flash0_addr: 0x00400000,
112    flash0_size: 0x00100000,
113    flash1_addr: 0x00500000,
114    flash1_size: 0x00100000,
115};
116
117extern "C" {
118    /// RAM Function needed for certain EFC accesses (unique id and signature section)
119    /// It's currently not possible to do this with pure rust as there can be no flash accesses
120    /// while this function is executing.
121    /// See: https://github.com/rust-embedded/cortex-m-rt/issues/42#issuecomment-559061416
122    ///
123    /// Will always return 0 unless the input buf is null
124    fn efc_perform_read_sequence(
125        efc: *const u32,
126        cmd_st: u32,
127        cmd_sp: u32,
128        buf: *mut u32,
129        size: u32,
130        flash_addr: *mut u32,
131    ) -> u32;
132
133    /// RAM Function alternative to the iap_function
134    /// See 3.2.1.3 on how to use the iap_function (haven't had much success so far on atsam4s).
135    /// <http://ww1.microchip.com/downloads/en/AppNotes/Atmel-42141-SAM-AT02333-Safe-and-Secure-Bootloader-Implementation-for-SAM3-4_Application-Note.pdf>
136    ///
137    /// Returns the status of the transfer
138    fn efc_perform_fcr(efc: *const u32, fcr: u32) -> u32;
139}
140
141/// Interface to an EFC instance
142///
143/// Partial Programming
144/// - Must be done using 32-bit (or higher) boundaries
145/// - 8 or 16-bit boundaries must be filled with 0xFF (full 32-bits must be written to the buffer)
146/// - See Section 19.4.3.2
147/// <https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-11158-32-bit%20Cortex-M4-Microcontroller-SAM4N16-SAM4N8_Datasheet.pdf>
148///
149/// Example memory.x configuration (atsam4s8b)
150/// ```
151/// MEMORY
152/// {
153///   FLASH (rx) : ORIGIN = 0x00400000, LENGTH = 512K
154///   RAM (xrw)  : ORIGIN = 0x20000000, LENGTH = 128K
155///   CS0 (xrw)  : ORIGIN = 0x60000000, LENGTH = 16M
156///   CS1 (xrw)  : ORIGIN = 0x61000000, LENGTH = 16M
157///   CS2 (xrw)  : ORIGIN = 0x62000000, LENGTH = 16M
158///   CS3 (xrw)  : ORIGIN = 0x63000000, LENGTH = 16M
159/// }
160///
161/// _flash = ORIGIN(FLASH);
162/// ```
163///
164/// ```rust
165/// // 512K flash (unfortunately we need this at compile-time, not link time)
166/// const FLASH_CONFIG_SIZE: usize = 524288 / core::mem::size_of::<u32>();
167/// extern "C" {
168///     #[link_name = "_flash"]
169///     static mut FLASH_CONFIG: [u32; FLASH_CONFIG_SIZE];
170/// }
171///
172/// use hal::efc::Efc;
173/// use atsam4_hal::pac::Peripherals;
174///
175/// let peripherals = Peripherals::take().unwrap();
176/// // Clock configuration will also do a small bit of the EFC init
177/// let _clocks = ClockController::new(
178///     peripherals.PMC,
179///     &peripherals.SUPC,
180///     &peripherals.EFC0,
181///     MainClock::Crystal12Mhz,
182///     SlowClock::RcOscillator32Khz,
183/// );
184///
185/// // Setup efc driver
186/// // FLASH_CONFIG indicates where the usable flash starts
187/// let mut efc = Efc::new(cx.device.EFC0, unsafe { &mut FLASH_CONFIG });
188///
189/// // Retrieve the uid from the efc
190/// let uid = efc.read_unique_id().unwrap();
191///
192/// // Erase user signature
193/// efc.erase_user_signature().unwrap();
194///
195/// // Write to the user signature (max 512 bytes)
196/// efc.write_user_signature(&[1,2,3]).unwrap();
197///
198/// // Read back the user signatfure
199/// let mut sig: [u32; 3];
200/// efc.read_user_signature(&mut sig, sig.len()).unwrap();
201/// ```
202pub struct Efc {
203    #[cfg(any(feature = "atsam4e", feature = "atsam4n", feature = "atsam4s"))]
204    efc: EFC,
205    #[cfg(feature = "atsam4sd")]
206    efc1: EFC1,
207    storage: &'static mut [u32],
208}
209
210impl Efc {
211    /// Takes ownership of the peripheral and storage area
212    #[cfg(any(
213        feature = "atsam4e",
214        feature = "atsam4n",
215        feature = "atsam4s_",
216        feature = "atsam4sa"
217    ))]
218    pub fn new(efc: EFC, storage: &'static mut [u32]) -> Efc {
219        Self { efc, storage }
220    }
221
222    /// Takes ownership of the peripheral and storage area
223    #[cfg(feature = "atsam4sd")]
224    pub fn new(efc0: EFC, efc1: EFC1, storage: &'static mut [u32]) -> Efc {
225        Self {
226            efc: efc0,
227            efc1,
228            storage,
229        }
230    }
231
232    /// Consumes `self` and returns back the raw peripheral and associated storage
233    #[cfg(any(feature = "atsam4e", feature = "atsam4n", feature = "atsam4s_"))]
234    pub fn free(self) -> (EFC, &'static mut [u32]) {
235        (self.efc, self.storage)
236    }
237
238    /// Consumes `self` and returns back the raw peripheral and associated storage
239    #[cfg(feature = "atsam4sd")]
240    pub fn free(self) -> (EFC, EFC1, &'static mut [u32]) {
241        (self.efc, self.efc1, self.storage)
242    }
243
244    #[inline]
245    fn wait_ready(&self) {
246        while !self.efc.fsr.read().frdy().bit() {}
247    }
248
249    /// Translate the given flash address to page and offset values
250    /// Returns: (page, offset, bank)
251    #[cfg(feature = "atsam4sd")]
252    fn translate_address(&self, address: u32) -> Result<(u16, u16, u8), EfcError> {
253        if address < FLASH_PARAMS.flash0_addr
254            || address > FLASH_PARAMS.flash1_addr + FLASH_PARAMS.flash1_size
255        {
256            return Err(EfcError::AddressBoundsError);
257        }
258
259        // Check if the bank swap gpnvm bit is set
260        let gpnvm2 = self.is_gpnvm_set(2)?;
261        if address >= FLASH_PARAMS.flash1_addr {
262            let bank = if gpnvm2 { 0 } else { 1 }; // Swap banks
263            let page = (address - FLASH_PARAMS.flash1_addr) / FLASH_PAGE_SIZE;
264            let offset = (address - FLASH_PARAMS.flash1_addr) % FLASH_PAGE_SIZE;
265            Ok((page as u16, offset as u16, bank))
266        } else {
267            let bank = u8::from(gpnvm2);
268            let page = (address - FLASH_PARAMS.flash0_addr) / FLASH_PAGE_SIZE;
269            let offset = (address - FLASH_PARAMS.flash0_addr) % FLASH_PAGE_SIZE;
270            Ok((page as u16, offset as u16, bank))
271        }
272    }
273
274    /// Translate the given flash address to page and offset values
275    /// Returns: (page, offset, bank)
276    #[cfg(not(feature = "atsam4sd"))]
277    fn translate_address(&self, address: u32) -> Result<(u16, u16, u8), EfcError> {
278        if address < FLASH_PARAMS.flash0_addr
279            || address > FLASH_PARAMS.flash0_addr + FLASH_PARAMS.flash0_size
280        {
281            return Err(EfcError::AddressBoundsError);
282        }
283
284        let page = (address - FLASH_PARAMS.flash0_addr) / FLASH_PAGE_SIZE;
285        let offset = (address - FLASH_PARAMS.flash0_addr) % FLASH_PAGE_SIZE;
286        Ok((page as u16, offset as u16, 0))
287    }
288
289    /* XXX (HaaTa): Wasn't needed? Probably can just remove this
290    /// Compute the address of a flash by the given page and offset
291    #[cfg(feature = "atsam4sd")]
292    fn compute_address(&self, bank: u8, page: u16, offset: u16) -> Result<u32, EfcError> {
293        // Check if the bank swap gpnvm bit is set
294        let gpnvm2 = self.is_gpnvm_set(2)?;
295
296        // Determine the address
297        Ok(if bank == 0 {
298            if gpnvm2 {
299                FLASH_PARAMS.flash1_addr + page * FLASH_PAGE_SIZE + offset
300            } else {
301                FLASH_PARAMS.flash0_addr + page * FLASH_PAGE_SIZE + offset
302            }
303        } else {
304            if gpnvm2 {
305                FLASH_PARAMS.flash0_addr + page * FLASH_PAGE_SIZE + offset
306            } else {
307                FLASH_PARAMS.flash1_addr + page * FLASH_PAGE_SIZE + offset
308            }
309        })
310    }
311
312    /// Compute the address of a flash by the given page and offset
313    #[cfg(not(feature = "atsam4sd"))]
314    fn compute_address(&self, _bank: u8, page: u16, offset: u16) -> Result<u32, EfcError> {
315        Ok(FLASH_PARAMS.flash0_addr + page as u32 * FLASH_PAGE_SIZE + offset as u32)
316    }
317    */
318
319    /// Compute the lock range associated with the given address range
320    /// Returns: (actual_start, actual_end)
321    fn compute_lock_range(&self, start: u32, end: u32) -> (u32, u32) {
322        let actual_start = start - (start % FLASH_LOCK_REGION_SIZE);
323        let actual_end = end - (end % FLASH_LOCK_REGION_SIZE) + FLASH_LOCK_REGION_SIZE - 1;
324        (actual_start, actual_end)
325    }
326
327    /// Lock all the regions in the given address range.
328    /// The actual lock range is reported through two output parameters.
329    /// Returns: (actual_start, actual_end)
330    pub fn lock(&self, start: u32, end: u32) -> Result<(u32, u32), EfcError> {
331        let num_pages_in_region = (FLASH_LOCK_REGION_SIZE / FLASH_PAGE_SIZE) as u16;
332
333        // Compute actual lock range
334        let (actual_start, actual_end) = self.compute_lock_range(start, end);
335
336        // Determine page numbers
337        let (mut start_page, _, bank) = self.translate_address(actual_start)?;
338        let (_, end_page, _) = self.translate_address(actual_end)?;
339
340        // Lock computed pages
341        while start_page < end_page {
342            self.efc_perform_command(bank, efc::fcr::FCMD_AW::SLB, start_page)?;
343            start_page += num_pages_in_region;
344        }
345
346        Ok((actual_start, actual_end))
347    }
348
349    /// Unlock all the regions in the given address range.
350    /// The actual unlock range is reported through two output parameters.
351    pub fn unlock(&self, start: u32, end: u32) -> Result<(u32, u32), EfcError> {
352        let num_pages_in_region = (FLASH_LOCK_REGION_SIZE / FLASH_PAGE_SIZE) as u16;
353
354        // Compute actual unlock range
355        let (actual_start, actual_end) = self.compute_lock_range(start, end);
356
357        // Determine page numbers
358        let (mut start_page, _, bank) = self.translate_address(actual_start)?;
359        let (_, end_page, _) = self.translate_address(actual_end)?;
360
361        // Unlock computed pages
362        while start_page < end_page {
363            self.efc_perform_command(bank, efc::fcr::FCMD_AW::CLB, start_page)?;
364            start_page += num_pages_in_region;
365        }
366
367        Ok((actual_start, actual_end))
368    }
369
370    /// Get the number of locked regions inside the given address range.
371    pub fn is_locked(&self, start: u32, end: u32) -> Result<u32, EfcError> {
372        if end < start
373            || start < FLASH_PARAMS.flash0_addr
374            || end > FLASH_PARAMS.flash0_addr + FLASH_PARAMS.flash0_size
375        {
376            return Err(EfcError::AddressBoundsError);
377        }
378
379        // Compute page numbers
380        let (start_page, _, bank) = self.translate_address(start)?;
381        let (_, end_page, _) = self.translate_address(end)?;
382
383        // Compute region numbers
384        let num_pages_in_region = FLASH_LOCK_REGION_SIZE / FLASH_PAGE_SIZE;
385        let start_region = start_page as u32 / num_pages_in_region;
386        let end_region = end_page as u32 / num_pages_in_region;
387
388        // Retrieve lock status
389        self.efc_perform_command(bank, efc::fcr::FCMD_AW::GLB, 0)?;
390
391        // Skip unrequested regions (if necessary)
392        let mut count = 0;
393        let mut status = self.efc_get_result(bank);
394        while count <= start_region && start_region < count + 32 {
395            status = self.efc_get_result(bank);
396            count += 32;
397        }
398
399        let mut bit = start_region - count;
400        count = end_region - start_region + 1;
401        let mut num_locked_regions = 0;
402
403        while count > 0 {
404            if status & (1 << bit) != 0 {
405                num_locked_regions += 1;
406            }
407
408            count -= 1;
409            bit += 1;
410            if bit == 32 {
411                status = self.efc_get_result(bank);
412                bit = 0;
413            }
414        }
415
416        Ok(num_locked_regions)
417    }
418
419    /// Set the given GPNVM bit
420    pub fn set_gpnvm(&self, gpnvm: u8) -> Result<(), EfcError> {
421        // Make sure this is a valid gpnvm bit
422        if gpnvm >= FLASH_PARAMS.gpnvm_num_max {
423            return Err(EfcError::InvalidGpnvmBitError);
424        }
425
426        // Check to see if the bit is already set
427        if self.is_gpnvm_set(gpnvm)? {
428            return Ok(());
429        }
430
431        // Attempt to set the bit
432        self.efc_perform_command(0, efc::fcr::FCMD_AW::SGPB, gpnvm as u16)
433    }
434
435    /// Clear the given GPNVM bit
436    pub fn clear_gpnvm(&self, gpnvm: u8) -> Result<(), EfcError> {
437        // Make sure this is a valid gpnvm bit
438        if gpnvm >= FLASH_PARAMS.gpnvm_num_max {
439            return Err(EfcError::InvalidGpnvmBitError);
440        }
441
442        // Check to see if the bit is already clear
443        if !self.is_gpnvm_set(gpnvm)? {
444            return Ok(());
445        }
446
447        // Attempt to set the bit
448        self.efc_perform_command(0, efc::fcr::FCMD_AW::CGPB, gpnvm as u16)
449    }
450
451    /// Check if the given GPNVM bit is set or not
452    pub fn is_gpnvm_set(&self, gpnvm: u8) -> Result<bool, EfcError> {
453        // Make sure this is a valid gpnvm bit
454        if gpnvm >= FLASH_PARAMS.gpnvm_num_max {
455            return Err(EfcError::InvalidGpnvmBitError);
456        }
457
458        // Retrieve bit status
459        self.efc_perform_command(0, efc::fcr::FCMD_AW::GGPB, gpnvm as u16)?;
460        let gpnvm_bits = self.efc_get_result(0);
461
462        // Check bit
463        Ok(gpnvm_bits & (1 << gpnvm) != 0)
464    }
465
466    /// Set security bit
467    pub fn enable_security_bit(&self) -> Result<(), EfcError> {
468        self.set_gpnvm(0)
469    }
470
471    /// Check if security bit is enabled
472    pub fn is_security_bit_enabled(&self) -> Result<bool, EfcError> {
473        self.is_gpnvm_set(0)
474    }
475
476    /// Read the flash unique ID
477    pub fn read_unique_id(&self) -> Result<[u32; 4], EfcError> {
478        // Read into uid
479        let mut uid: [u32; 4] = [0; 4];
480        self.efc_perform_read_sequence(
481            0,
482            efc::fcr::FCMD_AW::STUI,
483            efc::fcr::FCMD_AW::SPUI,
484            &mut uid,
485            4,
486        )?;
487
488        // Prepare id as an arry of 32-bit values
489        Ok(uid)
490    }
491
492    /// Read the flash user signature
493    pub fn read_user_signature(&self, data: &mut [u32], len: usize) -> Result<(), EfcError> {
494        // Make sure we're only reading at most 512 bytes
495        if len > USER_SIG_FLASH_SIZE as usize / core::mem::size_of::<u32>() {
496            return Err(EfcError::InvalidUserSignatureSizeError);
497        }
498
499        // Read user signature into the buffer
500        self.efc_perform_read_sequence(
501            0,
502            efc::fcr::FCMD_AW::STUS,
503            efc::fcr::FCMD_AW::SPUS,
504            data,
505            len,
506        )
507    }
508
509    /// Write the flash user signature
510    pub fn write_user_signature(&mut self, data: &[u32]) -> Result<(), EfcError> {
511        // Make sure the signature does not exceed the max size
512        if data.len() > USER_SIG_FLASH_SIZE as usize / core::mem::size_of::<u32>() {
513            return Err(EfcError::InvalidUserSignatureSizeError);
514        }
515
516        // Must write signature in chunks of 32-bits (does not support 8 or 16-bit writes)
517        self.storage[..data.len()].clone_from_slice(data);
518
519        // Send the write signature command
520        self.efc_perform_command(0, efc::fcr::FCMD_AW::WUS, 0)
521    }
522
523    /// Erase the flash user signature
524    pub fn erase_user_signature(&self) -> Result<(), EfcError> {
525        self.efc_perform_command(0, efc::fcr::FCMD_AW::EUS, 0)
526    }
527
528    /// Get result of last executed EFC command
529    #[cfg(not(feature = "atsam4sd"))]
530    fn efc_get_result(&self, _bank: u8) -> u32 {
531        self.efc.frr.read().fvalue().bits()
532    }
533
534    /// Get result of last executed EFC command
535    #[cfg(feature = "atsam4sd")]
536    fn efc_get_result(&self, bank: u8) -> u32 {
537        if bank == 0 {
538            self.efc.frr.read().fvalue().bits()
539        } else {
540            self.efc1.frr.read().fvalue().bits()
541        }
542    }
543
544    /// Perform the given command and wait until its completion (or an error).
545    ///
546    /// NOTE: Unique ID commands are not supported, use efc_perform_read_sequence.
547    /// NOTE: This function uses the IAP function (which is contained in ROM)
548    fn efc_perform_command(
549        &self,
550        bank: u8,
551        command: efc::fcr::FCMD_AW,
552        argument: u16,
553    ) -> Result<(), EfcError> {
554        // Unique ID commands are not supported
555        match command {
556            efc::fcr::FCMD_AW::STUI | efc::fcr::FCMD_AW::SPUI => {
557                return Err(EfcError::UnsupportedCommandError);
558            }
559            _ => {}
560        }
561
562        self.efc_fcr_command(bank, command, argument)
563    }
564
565    /// Convenience function to handle the IAP function
566    ///
567    /// NOTE: This function uses a RAM function written in C.
568    fn efc_fcr_command(
569        &self,
570        bank: u8,
571        command: efc::fcr::FCMD_AW,
572        argument: u16,
573    ) -> Result<(), EfcError> {
574        // Build command for efc_perform_fcr (or possibly the iap_function)
575        let fcr_cmd: u32 = ((efc::fcr::FKEY_AW::PASSWD as u32) << 24)
576            | ((argument as u32) << 8)
577            | (command as u32);
578
579        // Select the flash bank
580        #[cfg(not(feature = "atsam4sd"))]
581        let efc_ptr = {
582            let _ = bank;
583            EFC::PTR as *const _
584        };
585        #[cfg(feature = "atsam4sd")]
586        let efc_ptr = if bank == 0 {
587            EFC::PTR as *const _
588        } else if bank == 1 {
589            EFC1::PTR as *const _
590        } else {
591            return Err(EfcError::InvalidFlashBank);
592        };
593
594        // Force processor to flush any pending flash transactions
595        cortex_m::asm::dsb();
596        cortex_m::asm::isb();
597
598        // Call RAM function
599        let status = interrupt::free(|_| unsafe { efc_perform_fcr(efc_ptr, fcr_cmd) });
600
601        // Check for a command error
602        if status & (1 << 1) != 0 {
603            Err(EfcError::CommandError)
604        } else if status & (1 << 2) != 0 {
605            Err(EfcError::LockError)
606        } else if status & (1 << 3) != 0 {
607            Err(EfcError::FlashError)
608        } else {
609            // Success (though the write may not have fully finished if bit 0 is not set)
610            Ok(())
611        }
612    }
613
614    /// Perform read sequence
615    /// Supported sequences are read Unique ID and read User Signature
616    ///
617    /// NOTE: This function uses a RAM function written in C.
618    fn efc_perform_read_sequence(
619        &self,
620        bank: u8,
621        start_cmd: efc::fcr::FCMD_AW,
622        stop_cmd: efc::fcr::FCMD_AW,
623        bytes: &mut [u32],
624        len: usize,
625    ) -> Result<(), EfcError> {
626        // Check incoming buffer size
627        if bytes.len() < len {
628            return Err(EfcError::InvalidBufferSizeError);
629        }
630
631        // Run RAM function version of the command as we cannot read from flash for any reason
632        // until the EEFC mode sequence has finished.
633        #[cfg(not(feature = "atsam4sd"))]
634        let status = {
635            let _ = bank;
636            unsafe {
637                efc_perform_read_sequence(
638                    EFC::PTR as *const _,
639                    start_cmd as u32,
640                    stop_cmd as u32,
641                    bytes.as_mut_ptr(),
642                    len as u32,
643                    FLASH_PARAMS.flash0_addr as *mut _,
644                )
645            }
646        };
647        #[cfg(feature = "atsam4sd")]
648        let status = {
649            unsafe {
650                if bank == 0 {
651                    efc_perform_read_sequence(
652                        EFC::PTR as *const _,
653                        start_cmd as u32,
654                        stop_cmd as u32,
655                        bytes.as_mut_ptr(),
656                        len as u32,
657                        FLASH_PARAMS.flash0_addr as *mut _,
658                    )
659                } else if bank == 1 {
660                    efc_perform_read_sequence(
661                        EFC1::PTR as *const _,
662                        start_cmd as u32,
663                        stop_cmd as u32,
664                        bytes.as_mut_ptr(),
665                        len as u32,
666                        FLASH_PARAMS.flash1_addr as *mut _,
667                    )
668                } else {
669                    return Err(EfcError::InvalidFlashBank);
670                }
671            }
672        };
673
674        if status != 0 {
675            // The only possible error is a null pointer check for bytes buffer
676            Err(EfcError::InvalidBufferSizeError)
677        } else {
678            Ok(())
679        }
680    }
681}
682
683impl ErrorType for Efc {
684    type Error = EfcError;
685}
686
687impl ReadNorFlash for Efc {
688    const READ_SIZE: usize = FLASH_READ_SIZE as usize;
689
690    /// Reads from atsam4 internal flash
691    ///
692    /// NOTE: EEFC does not have a requirement that reads must start from an
693    ///       aligned address. However we're imposing this restriction due to:
694    ///       1. Reads are faster if they are aligned
695    ///       2. Less complicated logic
696    ///       3. You shouldn't really be using this for unaligned reads anyways
697    fn read(&mut self, offset: u32, bytes: &mut [u8]) -> Result<(), Self::Error> {
698        let offset = offset as usize;
699        let bytes_len = bytes.len();
700        let read_len = bytes_len + (Self::READ_SIZE - (bytes_len % Self::READ_SIZE));
701        let target_offset = offset + read_len;
702        if offset % Self::READ_SIZE == 0 && target_offset <= self.capacity() {
703            self.wait_ready();
704            let last_offset = target_offset - Self::READ_SIZE;
705            for offset in (offset..last_offset).step_by(Self::READ_SIZE) {
706                let word = self.storage[offset >> 2];
707                bytes[offset] = (word >> 24) as u8;
708                bytes[offset + 1] = (word >> 16) as u8;
709                bytes[offset + 2] = (word >> 8) as u8;
710                bytes[offset + 3] = (word) as u8;
711            }
712            let offset = last_offset;
713            let word = self.storage[offset >> 2];
714            let mut bytes_offset = offset;
715            if bytes_offset < bytes_len {
716                bytes[bytes_offset] = (word >> 24) as u8;
717                bytes_offset += 1;
718                if bytes_offset < bytes_len {
719                    bytes[bytes_offset] = (word >> 16) as u8;
720                    bytes_offset += 1;
721                    if bytes_offset < bytes_len {
722                        bytes[bytes_offset] = (word >> 8) as u8;
723                        bytes_offset += 1;
724                        if bytes_offset < bytes_len {
725                            bytes[bytes_offset] = (word) as u8;
726                        }
727                    }
728                }
729            }
730            Ok(())
731        } else {
732            Err(EfcError::Unaligned)
733        }
734    }
735
736    #[cfg(not(feature = "atsam4sd"))]
737    fn capacity(&self) -> usize {
738        FLASH_PARAMS.flash0_size as usize
739    }
740
741    #[cfg(feature = "atsam4sd")]
742    fn capacity(&self) -> usize {
743        (FLASH_PARAMS.flash0_size + FLASH_PARAMS.flash1_size) as usize
744    }
745}
746
747impl NorFlash for Efc {
748    /// 32-bits is the smallest write size
749    /// If you'd like to write smaller amounts, you must pad the rest of the 4 bytes
750    /// with 0xFFs
751    const WRITE_SIZE: usize = FLASH_WRITE_SIZE as usize;
752
753    /// NOTE: We can optimize erase quite a bit by trying to combine multiple erase bounds
754    ///       e.g. pages then sectors then pages
755    ///
756    /// The actual erase will vary depending on the situation
757    /// 4 pages  (* 512 ->  2048) - (EPA) Only for 8KB sectors
758    /// 8 pages  (* 512 ->  4096) - (EPA) Can be done anywhere
759    /// 16 pages (* 512 ->  8192) - (EPA) Can be done anywhere
760    /// 32 pages (* 512 -> 16384) - (EPA) Not valid for 8KB sectors
761    /// 1 sector                  - (ES) Size depends on which sector
762    ///   - Sector 0   (8192)
763    ///   - Sector 1   (8192)
764    ///   - Sector 2  (49152)
765    ///   - Sector 3+ (65536)
766    ///   See 2.3.1 for more details
767    ///   <http://ww1.microchip.com/downloads/en/Appnotes/Atmel-42218-EEPROM-Emulation-Using-Internal-Flash-SAM4_AT4066_AP-Note.pdf>
768    /// All pages                 - For a flash bank (for chips with dual bank flashes)
769    ///
770    /// If your chip has two banks, you must call erase twice to erase both banks.
771    ///
772    /// Setting the smallest safe interval as the "default"
773    const ERASE_SIZE: usize = 8 * FLASH_PAGE_SIZE as usize;
774
775    /// Erases range of addresses
776    /// Will not succeed if the erase bounds are not set to an allowed boundary.
777    /// * page
778    /// * sector
779    /// * bank
780    fn erase(&mut self, from: u32, to: u32) -> Result<(), Self::Error> {
781        // Nothing to do
782        if from == to {
783            return Ok(());
784        }
785
786        // From must be smaller than to
787        if from > to {
788            return Err(EfcError::AddressBoundsError);
789        }
790
791        // Make sure we're within the address bounds
792        if to >= FLASH_PARAMS.flash0_size {
793            return Err(EfcError::AddressBoundsError);
794        }
795
796        // Check if erasing entire flash, or entire bank
797        if from == 0 && to == FLASH_PARAMS.flash0_size {
798            return self.efc_perform_command(0, efc::fcr::FCMD_AW::EA, 0);
799        }
800        #[cfg(feature = "atsam4sd")]
801        if from == FLASH_PARAMS.flash1_addr && to == FLASH_PARAMS.flash1_size {
802            return self.efc_perform_command(1, efc::fcr::FCMD_AW::EA, 0);
803        }
804        #[cfg(feature = "atsam4sd")]
805        if from == 0 && to == FLASH_PARAMS.flash0_size + FLASH_PARAMS.flash1_size {
806            self.efc_perform_command(0, efc::fcr::FCMD_AW::EA, 0)?;
807            return self.efc_perform_command(1, efc::fcr::FCMD_AW::EA, 0);
808        }
809
810        // Flash must be a multiple of self::ERASE_SIZE
811        // TODO: Optimization: 8 kB sectors can have a smaller erase size
812        if from % Self::ERASE_SIZE as u32 != 0 || to % Self::ERASE_SIZE as u32 != 0 {
813            return Err(EfcError::NotWithinFlashPageBoundsError);
814        }
815
816        // TODO: Optimization: Check if 16 kB of pages can be erased (all sectors) or 32 pages can
817        //       erased (64 kB sectors)
818        // TODO: Optimization: Check if entire sector can be erased
819        for address in (from..to).step_by(Self::ERASE_SIZE) {
820            // Determine page FARG[15:2] and bank
821            // No shifting on page is needed as the page must be a multiple of 4, 8, 16 or 32
822            let (page, _, bank) = self.translate_address(address)?;
823
824            // Specifies number of pages to erase FARG[0:1]
825            // 0 - 4 pages (only valid on small 8 kB sectors)
826            // 1 - 8 pages
827            // 2 - 16 pages
828            // 3 - 32 pages (not valid on small 16 kB sectors)
829            let farg = 1;
830
831            self.efc_perform_command(bank, efc::fcr::FCMD_AW::EPA, farg | page)?;
832        }
833
834        Ok(())
835    }
836
837    /// Write a data buffer on flash.
838    ///
839    /// This function works in polling mode, and thus only returns when the
840    /// data has been effectively written.
841    fn write(&mut self, offset: u32, bytes: &[u8]) -> Result<(), Self::Error> {
842        // Make sure write is aligned
843        let offset = offset as usize;
844        if offset % Self::WRITE_SIZE == 0 && bytes.len() % Self::WRITE_SIZE == 0 {
845            // Check to make sure we're not trying to write over the size of one bank
846            if bytes.len() + offset > FLASH_PARAMS.flash0_size as usize {
847                return Err(EfcError::AddressBoundsError);
848            }
849
850            // Write 32-bits at a time into the latched write buffer
851            for offset in (offset..(offset + bytes.len())).step_by(Self::WRITE_SIZE) {
852                let word = ((bytes[offset] as u32) << 24)
853                    | ((bytes[offset + 1] as u32) << 16)
854                    | ((bytes[offset + 2] as u32) << 8)
855                    | (bytes[offset + 3] as u32);
856
857                // Write word to flash location
858                self.storage[offset >> 2] = word;
859
860                // Commit write to flash on page boundaries or on the last partial write
861                if (offset + Self::WRITE_SIZE) % FLASH_PAGE_SIZE as usize == 0
862                    || offset + Self::WRITE_SIZE == offset + bytes.len()
863                {
864                    // Translate address to page and offset
865                    let (page, _, bank) =
866                        self.translate_address(FLASH_PARAMS.flash0_addr + offset as u32)?;
867
868                    self.efc_perform_command(bank, efc::fcr::FCMD_AW::WP, page)?;
869                }
870            }
871
872            Ok(())
873        } else {
874            Err(EfcError::Unaligned)
875        }
876    }
877}
878
879#[derive(Debug, defmt::Format)]
880pub enum EfcError {
881    /// An operation was attempted on an unaligned boundary
882    Unaligned,
883    /// Bad keyword has been written to the EEFC_FCR register
884    CommandError,
885    /// Attempted write to a locked page, must be unlocked first to succeed
886    LockError,
887    /// WriteVerify test of flash memory has failed (possibly EraseVerify)
888    FlashError,
889    /// Address outside of flash region bounds
890    AddressBoundsError,
891    /// Unsupported command FMD key for given function
892    UnsupportedCommandError,
893    /// Invalid GPNVM bit
894    InvalidGpnvmBitError,
895    /// Invalid buffer sizef
896    InvalidBufferSizeError,
897    /// Invalid UserSignature size
898    InvalidUserSignatureSizeError,
899    /// Not within page bounds
900    NotWithinFlashPageBoundsError,
901    /// Invalid flash bank
902    InvalidFlashBank,
903}
904
905impl NorFlashError for EfcError {
906    fn kind(&self) -> NorFlashErrorKind {
907        match self {
908            EfcError::AddressBoundsError => NorFlashErrorKind::OutOfBounds,
909            EfcError::CommandError => NorFlashErrorKind::Other,
910            EfcError::FlashError => NorFlashErrorKind::Other,
911            EfcError::InvalidBufferSizeError => NorFlashErrorKind::Other,
912            EfcError::InvalidFlashBank => NorFlashErrorKind::Other,
913            EfcError::InvalidGpnvmBitError => NorFlashErrorKind::Other,
914            EfcError::InvalidUserSignatureSizeError => NorFlashErrorKind::Other,
915            EfcError::LockError => NorFlashErrorKind::Other,
916            EfcError::NotWithinFlashPageBoundsError => NorFlashErrorKind::Other,
917            EfcError::Unaligned => NorFlashErrorKind::NotAligned,
918            EfcError::UnsupportedCommandError => NorFlashErrorKind::Other,
919        }
920    }
921}