Skip to main content

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