sam4l/
flashcalw.rs

1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Tock Contributors 2022.
4
5//! Implementation of the SAM4L flash controller.
6//!
7//! This implementation of the flash controller for the SAM4L uses interrupts to
8//! handle main tasks of a flash -- write, reads, and erases. If modifying this
9//! file, you should check whether the flash commands (issued via issue_command)
10//! generates an interrupt and design a higher level function based off of that.
11//!
12//! Although the datasheet says that when the FRDY interrupt is on, an interrupt
13//! will be generated after a command is complete, it doesn't appear to occur
14//! for some commands.
15//!
16//! A clean interface for reading from flash, writing pages and erasing pages is
17//! defined below and should be used to handle the complexity of these tasks.
18//!
19//! A Client should be set to enable a callback after a command is completed.
20//!
21//! Almost all of the flash controller functionality is implemented (except for
22//! general purpose fuse bits, and more granular control of the cache).
23//!
24//! - Author:  Kevin Baichoo <kbaichoo@cs.stanford.edu>
25//! - Date: July 27, 2016
26
27use crate::pm;
28use core::cell::Cell;
29use core::ops::{Index, IndexMut};
30use kernel::deferred_call::{DeferredCall, DeferredCallClient};
31use kernel::hil;
32use kernel::utilities::cells::{OptionalCell, TakeCell};
33use kernel::utilities::registers::interfaces::{ReadWriteable, Readable, Writeable};
34use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
35use kernel::utilities::StaticRef;
36use kernel::ErrorCode;
37
38/// Struct of the FLASHCALW registers. Section 14.10 of the datasheet.
39#[repr(C)]
40struct FlashcalwRegisters {
41    fcr: ReadWrite<u32, FlashControl::Register>,
42    fcmd: ReadWrite<u32, FlashCommand::Register>,
43    fsr: ReadOnly<u32, FlashStatus::Register>,
44    fpr: ReadOnly<u32, FlashParameter::Register>,
45    fvr: ReadOnly<u32, FlashVersion::Register>,
46    fgpfrhi: ReadOnly<u32, FlashGeneralPurposeFuseHigh::Register>,
47    fgpfrlo: ReadOnly<u32, FlashGeneralPurposeFuseLow::Register>,
48    _reserved1: [u32; 251],
49    ctrl: WriteOnly<u32, PicoCacheControl::Register>,
50    sr: ReadWrite<u32, PicoCacheStatus::Register>,
51    _reserved2: [u32; 4],
52    maint0: WriteOnly<u32, PicoCacheMaintenance0::Register>,
53    maint1: WriteOnly<u32, PicoCacheMaintenance1::Register>,
54    mcfg: ReadWrite<u32, PicoCacheMonitorConfiguration::Register>,
55    men: ReadWrite<u32, PicoCacheMonitorEnable::Register>,
56    mctrl: WriteOnly<u32, PicoCacheMonitorStatus::Register>,
57    msr: ReadOnly<u32, PicoCacheMonitorStatus::Register>,
58}
59
60register_bitfields![u32,
61    FlashControl [
62        /// Wait State 1 Optimization
63        WS1OPT OFFSET(7) NUMBITS(1) [
64            NoOptimize = 0,
65            Optimize = 1
66        ],
67        /// Flash Wait State
68        FWS OFFSET(6) NUMBITS(1) [
69            ZeroWaitStates = 0,
70            OneWaitState = 1
71        ],
72        /// ECC Error Interrupt Enable
73        ECCE OFFSET(4) NUMBITS(1) [],
74        /// Programming Error Interrupt Enable
75        PROGE OFFSET(3) NUMBITS(1) [],
76        /// Lock Error Interrupt Enable
77        LOCKE OFFSET(2) NUMBITS(1) [],
78        /// Flash Ready Interrupt Enable
79        FRDY OFFSET(0) NUMBITS(1) []
80    ],
81
82    FlashCommand [
83        /// Write protection key
84        KEY OFFSET(24) NUMBITS(8) [],
85        /// Page number
86        PAGEN OFFSET(8) NUMBITS(16) [],
87        /// Command
88        CMD OFFSET(0) NUMBITS(6) [
89            NOP = 0,
90            WP = 1,
91            EP = 2,
92            CPB = 3,
93            LP = 4,
94            UP = 5,
95            EA = 6,
96            WGPB = 7,
97            EGPB = 8,
98            SSB = 9,
99            PGPFB = 10,
100            EAGPF = 11,
101            QPR = 12,
102            WUP = 13,
103            EUP = 14,
104            QPRUP = 15,
105            HSEN = 16,
106            HSDIS = 17
107        ]
108    ],
109
110    FlashStatus [
111        /// Lock region x Lock Status
112        LOCK15 31,
113        LOCK14 30,
114        LOCK13 29,
115        LOCK12 28,
116        LOCK11 27,
117        LOCK10 26,
118        LOCK9 25,
119        LOCK8 24,
120        LOCK7 23,
121        LOCK6 22,
122        LOCK5 21,
123        LOCK4 20,
124        LOCK3 19,
125        LOCK2 18,
126        LOCK1 17,
127        LOCK0 16,
128        ///ECC Error Status
129        ///
130        /// WARNING! Datasheet has this bit listed in two places...
131        ECCERR 9,
132        /// High Speed Mode
133        HSMODE 6,
134        /// Quick Page Read Result
135        QPRR 5,
136        /// Security Fuses Status
137        SECURITY 4,
138        /// Programming Error Status
139        PROGE 3,
140        /// Lock Error Status
141        LOCKE 2,
142        /// Flash Ready Status
143        FRDY 0
144    ],
145
146    FlashParameter [
147        /// Page Size
148        PSZ OFFSET(8) NUMBITS(3) [
149            Bytes32 = 0,
150            Bytes64 = 1,
151            Bytes128 = 2,
152            Bytes256 = 3,
153            Bytes512 = 4,
154            Bytes1024 = 5,
155            Bytes2048 = 6,
156            Bytes4096 = 7
157        ],
158        /// Flash Size
159        FSZ OFFSET(0) NUMBITS(4) [
160            KBytes4 = 0,
161            KBytes8 = 1,
162            KBytes16 = 2,
163            KBytes32 = 3,
164            KBytes48 = 4,
165            KBytes64 = 5,
166            KBytes96 = 6,
167            KBytes128 = 7,
168            KBytes192 = 8,
169            KBytes256 = 9,
170            KBytes384 = 10,
171            KBytes512 = 11,
172            KBytes768 = 12,
173            KBytes1024 = 13,
174            KBytes2048 = 14
175        ]
176    ],
177
178    FlashVersion [
179        /// Variant Number
180        VARIANT OFFSET(16) NUMBITS(4) [],
181        /// Version Number
182        VERSION OFFSET(0) NUMBITS(12) []
183    ],
184
185    FlashGeneralPurposeFuseHigh [
186        /// General Purpose Fuse
187        GPF63 31,
188        GPF62 30,
189        GPF61 29,
190        GPF60 28,
191        GPF59 27,
192        GPF58 26,
193        GPF57 25,
194        GPF56 24,
195        GPF55 23,
196        GPF54 22,
197        GPF53 21,
198        GPF52 20,
199        GPF51 19,
200        GPF50 18,
201        GPF49 17,
202        GPF48 16,
203        GPF47 15,
204        GPF46 14,
205        GPF45 13,
206        GPF44 12,
207        GPF43 11,
208        GPF42 10,
209        GPF41 9,
210        GPF40 8,
211        GPF39 7,
212        GPF38 6,
213        GPF37 5,
214        GPF36 4,
215        GPF35 3,
216        GPF34 2,
217        GPF33 1,
218        GPF32 0
219    ],
220
221    FlashGeneralPurposeFuseLow [
222        GPF31 31,
223        GPF30 30,
224        GPF29 29,
225        GPF28 28,
226        GPF27 27,
227        GPF26 26,
228        GPF25 25,
229        GPF24 24,
230        GPF23 23,
231        GPF22 22,
232        GPF21 21,
233        GPF20 20,
234        GPF19 19,
235        GPF18 18,
236        GPF17 17,
237        GPF16 16,
238        GPF15 15,
239        GPF14 14,
240        GPF13 13,
241        GPF12 12,
242        GPF11 11,
243        GPF10 10,
244        GPF9 9,
245        GPF8 8,
246        GPF7 7,
247        GPF6 6,
248        GPF5 5,
249        GPF4 4,
250        GPF3 3,
251        GPF2 2,
252        GPF1 1,
253        GPF0 0
254    ],
255
256    PicoCacheControl [
257        /// Cache Enable
258        CEN OFFSET(0) NUMBITS(1) [
259            Disable = 0,
260            Enable = 1
261        ]
262    ],
263
264    PicoCacheStatus [
265        /// Cache Controller Status
266        CSTS OFFSET(0) NUMBITS(1) [
267            Disabled = 0,
268            Enabled = 1
269        ]
270    ],
271
272    PicoCacheMaintenance0 [
273        /// Cache Controller Invalidate All
274        INVALL 0
275    ],
276
277    PicoCacheMaintenance1 [
278        /// Invalidate Index
279        INDEX OFFSET(4) NUMBITS(4) []
280    ],
281
282    PicoCacheMonitorConfiguration [
283        /// Cache Controller Monitor Counter Mode
284        MODE OFFSET(0) NUMBITS(1) [
285            CycleCount = 0,
286            IhitCount = 1,
287            DhitCount = 2
288        ]
289    ],
290
291    PicoCacheMonitorEnable [
292        /// Monitor Enable
293        MENABLE OFFSET(0) NUMBITS(1) [
294            Disable = 0,
295            Enable = 1
296        ]
297    ],
298
299    PicoCacheMonitorControl [
300        /// Monitor Software Reset
301        SWRST 0
302    ],
303
304    PicoCacheMonitorStatus [
305        /// Monitor Event Counter
306        EVENTCNT OFFSET(0) NUMBITS(32) []
307    ]
308];
309
310const FLASHCALW_ADDRESS: StaticRef<FlashcalwRegisters> =
311    unsafe { StaticRef::new(0x400A0000 as *const FlashcalwRegisters) };
312
313#[allow(dead_code)]
314enum RegKey {
315    CONTROL,
316    COMMAND,
317    STATUS,
318    PARAMETER,
319    VERSION,
320    GPFRHI,
321    GPFRLO,
322}
323
324/// There are 18 recognized commands for the flash. These are "bare-bones"
325/// commands and values that are written to the Flash's command register to
326/// inform the flash what to do. Table 14-5.
327#[derive(Clone, Copy, PartialEq)]
328#[allow(dead_code)]
329enum FlashCMD {
330    NOP,
331    WP,
332    EP,
333    CPB,
334    LP,
335    UP,
336    EA,
337    WGPB,
338    EGPB,
339    SSB,
340    PGPFB,
341    EAGPF,
342    QPR,
343    WUP,
344    EUP,
345    QPRUP,
346    HSEN,
347    HSDIS,
348}
349
350/// FlashState is used to track the current state and command of the flash.
351#[derive(Clone, Copy, PartialEq)]
352enum FlashState {
353    Unconfigured,                 // Flash is unconfigured, call configure().
354    Ready,                        // Flash is ready to complete a command.
355    Read,                         // Performing a read operation.
356    WriteUnlocking { page: i32 }, // Started a write operation.
357    WriteErasing { page: i32 },   // Waiting on the page to erase.
358    WriteWriting,                 // Waiting on the page to actually be written.
359    EraseUnlocking { page: i32 }, // Started an erase operation.
360    EraseErasing,                 // Waiting on the erase to finish.
361}
362
363/// This is a wrapper around a u8 array that is sized to a single page for the
364/// SAM4L. Users of this module must pass an object of this type to use the
365/// `hil::flash::Flash` interface.
366///
367/// An example looks like:
368///
369/// ```rust
370/// # extern crate sam4l;
371/// # use sam4l::flashcalw::Sam4lPage;
372/// # use kernel::static_init;
373///
374/// let pagebuffer = unsafe { static_init!(Sam4lPage, Sam4lPage::default()) };
375/// ```
376pub struct Sam4lPage(pub [u8; PAGE_SIZE as usize]);
377
378impl Default for Sam4lPage {
379    fn default() -> Self {
380        Self([0; PAGE_SIZE as usize])
381    }
382}
383
384impl Sam4lPage {
385    fn len(&self) -> usize {
386        self.0.len()
387    }
388}
389
390impl Index<usize> for Sam4lPage {
391    type Output = u8;
392
393    fn index(&self, idx: usize) -> &u8 {
394        &self.0[idx]
395    }
396}
397
398impl IndexMut<usize> for Sam4lPage {
399    fn index_mut(&mut self, idx: usize) -> &mut u8 {
400        &mut self.0[idx]
401    }
402}
403
404impl AsMut<[u8]> for Sam4lPage {
405    fn as_mut(&mut self) -> &mut [u8] {
406        &mut self.0
407    }
408}
409
410// The FLASHCALW controller
411pub struct FLASHCALW {
412    registers: StaticRef<FlashcalwRegisters>,
413    ahb_clock: pm::Clock,
414    hramc1_clock: pm::Clock,
415    pb_clock: pm::Clock,
416    client: OptionalCell<&'static dyn hil::flash::Client<FLASHCALW>>,
417    current_state: Cell<FlashState>,
418    buffer: TakeCell<'static, Sam4lPage>,
419    deferred_call: DeferredCall,
420}
421
422// Few constants relating to module configuration.
423const PAGE_SIZE: u32 = 512;
424
425const FREQ_PS2_FWS_0_MAX_FREQ: u32 = 24000000;
426
427impl FLASHCALW {
428    pub fn new(ahb_clk: pm::HSBClock, hramc1_clk: pm::HSBClock, pb_clk: pm::PBBClock) -> FLASHCALW {
429        FLASHCALW {
430            registers: FLASHCALW_ADDRESS,
431            ahb_clock: pm::Clock::HSB(ahb_clk),
432            hramc1_clock: pm::Clock::HSB(hramc1_clk),
433            pb_clock: pm::Clock::PBB(pb_clk),
434            client: OptionalCell::empty(),
435            current_state: Cell::new(FlashState::Unconfigured),
436            buffer: TakeCell::empty(),
437            deferred_call: DeferredCall::new(),
438        }
439    }
440
441    /// Cache controlling functionality.
442
443    //  Flush the cache. Should be called after every write!
444    fn invalidate_cache(&self) {
445        self.registers
446            .maint0
447            .write(PicoCacheMaintenance0::INVALL::SET);
448    }
449
450    fn enable_picocache(&self, enable: bool) {
451        if enable {
452            self.registers.ctrl.write(PicoCacheControl::CEN::Enable);
453        } else {
454            self.registers.ctrl.write(PicoCacheControl::CEN::Disable);
455        }
456    }
457
458    /// Enable HCACHE
459    pub fn enable_cache(&self) {
460        // enable appropriate clocks
461        pm::enable_clock(pm::Clock::HSB(pm::HSBClock::FLASHCALWP));
462        pm::enable_clock(pm::Clock::PBB(pm::PBBClock::HRAMC1));
463
464        // enable and wait for it to be ready
465        self.enable_picocache(true);
466        while !self.pico_enabled() {}
467    }
468
469    fn pico_enabled(&self) -> bool {
470        self.registers.sr.is_set(PicoCacheStatus::CSTS)
471    }
472
473    pub fn handle_interrupt(&self) {
474        // Disable the interrupt line for flash
475        self.registers.fcr.modify(FlashControl::FRDY::CLEAR);
476
477        // Since the only interrupt on is FRDY, a command should have
478        // either completed or failed at this point.
479
480        // Check for errors and report to Client if there are any
481        if self.is_error() {
482            let attempted_operation = self.current_state.get();
483
484            // Reset state now that we are ready to do a new operation.
485            self.current_state.set(FlashState::Ready);
486
487            self.client.map(|client| match attempted_operation {
488                FlashState::Read => {
489                    self.buffer.take().map(|buffer| {
490                        client.read_complete(buffer, Err(hil::flash::Error::FlashError));
491                    });
492                }
493                FlashState::WriteUnlocking { .. }
494                | FlashState::WriteErasing { .. }
495                | FlashState::WriteWriting => {
496                    self.buffer.take().map(|buffer| {
497                        client.write_complete(buffer, Err(hil::flash::Error::FlashError));
498                    });
499                }
500                FlashState::EraseUnlocking { .. } | FlashState::EraseErasing => {
501                    client.erase_complete(Err(hil::flash::Error::FlashError));
502                }
503                _ => {}
504            });
505        }
506
507        // Part of a command succeeded -- continue onto next steps.
508        match self.current_state.get() {
509            FlashState::Read => {
510                self.current_state.set(FlashState::Ready);
511
512                self.client.map(|client| {
513                    self.buffer.take().map(|buffer| {
514                        client.read_complete(buffer, Ok(()));
515                    });
516                });
517            }
518            FlashState::WriteUnlocking { page } => {
519                self.current_state.set(FlashState::WriteErasing { page });
520                self.flashcalw_erase_page(page);
521            }
522            FlashState::WriteErasing { page } => {
523                //  Write page buffer isn't really a command, and
524                //  clear page buffer doesn't trigger an interrupt thus
525                //  I'm combining these with an actual command, write_page,
526                //  which generates and interrupt and saves the page.
527                self.clear_page_buffer();
528                self.write_to_page_buffer(page as usize * PAGE_SIZE as usize);
529
530                self.current_state.set(FlashState::WriteWriting);
531                self.flashcalw_write_page(page);
532            }
533            FlashState::WriteWriting => {
534                // Flush the cache
535                self.invalidate_cache();
536
537                self.current_state.set(FlashState::Ready);
538
539                self.client.map(|client| {
540                    self.buffer.take().map(|buffer| {
541                        client.write_complete(buffer, Ok(()));
542                    });
543                });
544            }
545            FlashState::EraseUnlocking { page } => {
546                self.current_state.set(FlashState::EraseErasing);
547                self.flashcalw_erase_page(page);
548            }
549            FlashState::EraseErasing => {
550                // Flush the cache
551                self.invalidate_cache();
552
553                self.current_state.set(FlashState::Ready);
554
555                self.client.map(|client| {
556                    client.erase_complete(Ok(()));
557                });
558            }
559            _ => {
560                self.current_state.set(FlashState::Ready);
561            }
562        }
563    }
564
565    /// FLASH properties.
566    fn get_flash_size(&self) -> u32 {
567        let flash_sizes = [
568            4, 8, 16, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 2048,
569        ];
570        // get the FSZ number and lookup in the table for the size.
571        flash_sizes[self.registers.fpr.read(FlashParameter::FSZ) as usize] << 10
572    }
573
574    /// FLASHC Control
575    pub fn set_wait_state(&self, wait_state: u32) {
576        self.registers.fcr.modify(FlashControl::FWS.val(wait_state));
577    }
578
579    fn enable_ws1_read_opt(&self, enable: bool) {
580        if enable {
581            self.registers.fcr.modify(FlashControl::WS1OPT::Optimize);
582        } else {
583            self.registers.fcr.modify(FlashControl::WS1OPT::NoOptimize);
584        }
585    }
586
587    //  By default, we are going with High Speed Enable (based on our device running
588    //  in PS2).
589    fn set_flash_waitstate_and_readmode(&self, cpu_freq: u32, _ps_val: u32, _is_fwu_enabled: bool) {
590        // ps_val and is_fwu_enabled not used in this implementation.
591        if cpu_freq > FREQ_PS2_FWS_0_MAX_FREQ {
592            self.set_wait_state(1);
593        } else {
594            self.set_wait_state(0);
595        }
596
597        self.issue_command(FlashCMD::HSEN, -1);
598    }
599
600    /// Configure high-speed flash mode. This is taken from the ASF code
601    pub fn enable_high_speed_flash(&self) {
602        // Since we are running at a fast speed we have to set a clock delay
603        // for flash, as well as enable fast flash mode.
604        self.registers.fcr.modify(FlashControl::FWS::OneWaitState);
605
606        // Enable high speed mode for flash
607        self.registers
608            .fcmd
609            .modify(FlashCommand::KEY.val(0xA5) + FlashCommand::CMD::HSEN);
610
611        // And wait for the flash to be ready
612        while !self.registers.fsr.is_set(FlashStatus::FRDY) {}
613    }
614
615    /// Flashcalw status
616    fn is_error(&self) -> bool {
617        pm::enable_clock(self.pb_clock);
618        self.registers.fsr.is_set(FlashStatus::LOCKE)
619            | self.registers.fsr.is_set(FlashStatus::PROGE)
620    }
621
622    /// Flashcalw command control
623    fn issue_command(&self, command: FlashCMD, page_number: i32) {
624        pm::enable_clock(self.pb_clock);
625        // For most commands we wait for the interrupt, for some certain
626        // fast/rarely used commands or commands that don't generate interrupts
627        // it is better to wait (or at least that is how this driver was
628        // originally implemented).
629        if command != FlashCMD::QPRUP
630            && command != FlashCMD::QPR
631            && command != FlashCMD::CPB
632            && command != FlashCMD::HSEN
633        {
634            // Enable ready interrupt.
635            self.registers.fcr.modify(FlashControl::FRDY::SET);
636        }
637
638        // Setup the command register to run this command.
639        let mut cmd = FlashCommand::KEY.val(0xA5) + FlashCommand::CMD.val(command as u32);
640
641        // If this command relies on using a certain page, we need to add that
642        // in as well.
643        if page_number >= 0 {
644            cmd += FlashCommand::PAGEN.val(page_number as u32);
645        }
646
647        self.registers.fcmd.write(cmd);
648
649        // Since we don't enable interrupts for these commands, spin wait
650        // until they are finished. In particular, QPR and QPRUP will not issue
651        // interrupts (see datasheet 14.6 paragraph 2).
652        if command == FlashCMD::QPRUP
653            || command == FlashCMD::QPR
654            || command == FlashCMD::CPB
655            || command == FlashCMD::HSEN
656        {
657            while !self.registers.fsr.is_set(FlashStatus::FRDY) {}
658        }
659    }
660
661    /// Flashcalw global commands
662    fn lock_page_region(&self, page_number: i32, lock: bool) {
663        if lock {
664            self.issue_command(FlashCMD::LP, page_number);
665        } else {
666            self.issue_command(FlashCMD::UP, page_number);
667        }
668    }
669
670    /// Flashcalw Access to Flash Pages
671    fn clear_page_buffer(&self) {
672        self.issue_command(FlashCMD::CPB, -1);
673    }
674
675    fn is_page_erased(&self) -> bool {
676        self.registers.fsr.is_set(FlashStatus::QPRR)
677    }
678
679    fn flashcalw_erase_page(&self, page_number: i32) {
680        self.issue_command(FlashCMD::EP, page_number);
681    }
682
683    fn flashcalw_write_page(&self, page_number: i32) {
684        self.issue_command(FlashCMD::WP, page_number);
685    }
686
687    /// There's a user_page that isn't contiguous with the rest of the flash.
688    /// Currently it's not being used.
689    #[allow(dead_code)]
690    fn quick_user_page_read(&self) -> bool {
691        self.issue_command(FlashCMD::QPRUP, -1);
692        self.is_page_erased()
693    }
694
695    #[allow(dead_code)]
696    fn erase_user_page(&self, check: bool) -> bool {
697        self.issue_command(FlashCMD::EUP, -1);
698        if check {
699            self.quick_user_page_read()
700        } else {
701            true
702        }
703    }
704
705    #[allow(dead_code)]
706    fn write_user_page(&self) {
707        self.issue_command(FlashCMD::WUP, -1);
708    }
709
710    // Instead of having several memset/memcpy functions as Atmel's ASF
711    // implementation will only have one to write to the page buffer.
712    fn write_to_page_buffer(&self, pg_buff_addr: usize) {
713        let mut page_buffer: *mut u8 = pg_buff_addr as *mut u8;
714
715        // Errata 45.1.7 - Need to write a 64-bit all one word for every write
716        // to the page buffer.
717        let cleared_double_word: [u8; 8] = [255; 8];
718        let clr_ptr: *const u8 = &cleared_double_word[0] as *const u8;
719
720        self.buffer.map(|buffer| {
721            unsafe {
722                use core::ptr;
723
724                let mut start_buffer: *const u8 = &buffer[0] as *const u8;
725                let mut data_transfered: u32 = 0;
726                while data_transfered < PAGE_SIZE {
727                    // errata copy..
728                    ptr::copy(clr_ptr, page_buffer, 8);
729
730                    // real copy
731                    ptr::copy(start_buffer, page_buffer, 8);
732                    page_buffer = page_buffer.offset(8);
733                    start_buffer = start_buffer.offset(8);
734                    data_transfered += 8;
735                }
736            }
737        });
738    }
739}
740
741// Implementation of high level calls using the low-lv functions.
742impl FLASHCALW {
743    pub fn configure(&self) {
744        // Enable all clocks (if they aren't on already...).
745        pm::enable_clock(self.ahb_clock);
746        pm::enable_clock(self.hramc1_clock);
747        pm::enable_clock(self.pb_clock);
748
749        // Configure all other interrupts explicitly. Note the issue_command
750        // function turns this on when need be.
751        self.registers.fcr.modify(
752            FlashControl::FRDY::CLEAR
753                + FlashControl::LOCKE::CLEAR
754                + FlashControl::PROGE::CLEAR
755                + FlashControl::ECCE::CLEAR,
756        );
757
758        // Enable wait state 1 optimization.
759        self.enable_ws1_read_opt(true);
760        // Change speed mode.
761        self.set_flash_waitstate_and_readmode(48_000_000, 0, false);
762
763        // By default the picocache ( a cache only for the flash) is turned off.
764        // However the bootloader turns it on. I will explicitly turn it on
765        // here. So if the bootloader changes, nothing breaks.
766        self.enable_picocache(true);
767
768        self.current_state.set(FlashState::Ready);
769    }
770
771    // Address is some raw address in flash that you want to read.
772    fn read_range(
773        &self,
774        address: usize,
775        size: usize,
776        buffer: &'static mut Sam4lPage,
777    ) -> Result<(), (ErrorCode, &'static mut Sam4lPage)> {
778        if self.current_state.get() == FlashState::Unconfigured {
779            self.configure();
780        }
781
782        // Enable clock in case it's off.
783        pm::enable_clock(self.ahb_clock);
784
785        // Check that address makes sense and buffer has room.
786        let Some(end_address) = address.checked_add(size) else {
787            return Err((ErrorCode::INVAL, buffer));
788        };
789        if end_address > (self.get_flash_size() as usize) || buffer.len() < size {
790            return Err((ErrorCode::INVAL, buffer));
791        }
792
793        // Actually do a copy from flash into the buffer.
794        let mut byte: *const u8 = address as *const u8;
795        unsafe {
796            for i in 0..size {
797                buffer[i] = *byte;
798                byte = byte.offset(1);
799            }
800        }
801
802        self.current_state.set(FlashState::Read);
803        // Hold on to the buffer for the callback.
804        self.buffer.replace(buffer);
805
806        // This is kind of strange, but because read() in this case is
807        // synchronous, we still need to schedule as if we had an interrupt so
808        // we can allow this function to return and then call the callback.
809        self.deferred_call.set();
810
811        Ok(())
812    }
813
814    fn write_page(
815        &self,
816        page_num: i32,
817        data: &'static mut Sam4lPage,
818    ) -> Result<(), (ErrorCode, &'static mut Sam4lPage)> {
819        // Enable clock in case it's off.
820        pm::enable_clock(self.ahb_clock);
821
822        match self.current_state.get() {
823            FlashState::Unconfigured => self.configure(),
824            FlashState::Ready => {}
825            // If we're not ready don't take the command
826            _ => return Err((ErrorCode::BUSY, data)),
827        }
828
829        // Save the buffer for the future write.
830        self.buffer.replace(data);
831
832        self.current_state
833            .set(FlashState::WriteUnlocking { page: page_num });
834        self.lock_page_region(page_num, false);
835        Ok(())
836    }
837
838    fn erase_page(&self, page_num: i32) -> Result<(), ErrorCode> {
839        // Enable AHB clock (in case it was off).
840        pm::enable_clock(self.ahb_clock);
841
842        match self.current_state.get() {
843            FlashState::Unconfigured => self.configure(),
844            FlashState::Ready => {}
845            // If we're not ready don't take the command
846            _ => return Err(ErrorCode::BUSY),
847        }
848
849        self.current_state
850            .set(FlashState::EraseUnlocking { page: page_num });
851        self.lock_page_region(page_num, false);
852        Ok(())
853    }
854}
855
856impl DeferredCallClient for FLASHCALW {
857    fn handle_deferred_call(&self) {
858        self.handle_interrupt();
859    }
860
861    fn register(&'static self) {
862        self.deferred_call.register(self);
863    }
864}
865
866impl<C: hil::flash::Client<Self>> hil::flash::HasClient<'static, C> for FLASHCALW {
867    fn set_client(&self, client: &'static C) {
868        self.client.set(client);
869    }
870}
871
872impl hil::flash::Flash for FLASHCALW {
873    type Page = Sam4lPage;
874
875    fn read_page(
876        &self,
877        page_number: usize,
878        buf: &'static mut Self::Page,
879    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
880        self.read_range(page_number * (PAGE_SIZE as usize), buf.len(), buf)
881    }
882
883    fn write_page(
884        &self,
885        page_number: usize,
886        buf: &'static mut Self::Page,
887    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
888        self.write_page(page_number as i32, buf)
889    }
890
891    fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
892        self.erase_page(page_number as i32)
893    }
894}