capsules_extra/
mx25r6435f.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//! SyscallDriver for the MX25R6435F flash chip.
6//!
7//! <http://www.macronix.com/en-us/products/NOR-Flash/Serial-NOR-Flash/Pages/spec.aspx?p=MX25R6435F>
8//!
9//! From the datasheet:
10//!
11//! > MX25R6435F is 64Mb bits Serial NOR Flash memory, which is configured as
12//! > 8,388,608 x 8 internally. When it is in four I/O mode, the structure
13//! > becomes 16,777,216 bits x 4 or 33,554,432 bits x 2. MX25R6435F feature a
14//! > serial peripheral interface and software protocol allowing operation on a
15//! > simple 3-wire bus while it is in single I/O mode. The three bus signals
16//! > are a clock input (SCLK), a serial data input (SI), and a serial data
17//! > output (SO). Serial access to the device is enabled by CS# input.
18//!
19//! Usage
20//! -----
21//!
22//! ```rust,ignore
23//! # use kernel::static_init;
24//! # use capsules::virtual_alarm::VirtualMuxAlarm;
25//!
26//! // Create a SPI device for this chip.
27//! let mx25r6435f_spi = static_init!(
28//!     capsules::virtual_spi::VirtualSpiMasterDevice<'static, nrf52::spi::SPIM>,
29//!     capsules::virtual_spi::VirtualSpiMasterDevice::new(mux_spi, &nrf5x::gpio::PORT[17])
30//! );
31//! // Create an alarm for this chip.
32//! let mx25r6435f_virtual_alarm = static_init!(
33//!     VirtualMuxAlarm<'static, nrf5x::rtc::Rtc>,
34//!     VirtualMuxAlarm::new(mux_alarm)
35//! );
36//! mx25r6435f_virtual_alarm.setup();
37//!
38//! // Setup the actual MX25R6435F driver.
39//! let mx25r6435f = static_init!(
40//!     capsules::mx25r6435f::MX25R6435F<
41//!         'static,
42//!         capsules::virtual_spi::VirtualSpiMasterDevice<'static, nrf52::spi::SPIM>,
43//!         nrf5x::gpio::GPIOPin,
44//!     >,
45//!     capsules::mx25r6435f::MX25R6435F::new(
46//!         mx25r6435f_spi,
47//!         &mut capsules::mx25r6435f::TXBUFFER,
48//!         &mut capsules::mx25r6435f::RXBUFFER,
49//!         Some(&nrf5x::gpio::PORT[22]),
50//!         Some(&nrf5x::gpio::PORT[23])
51//!     )
52//! );
53//! mx25r6435f_spi.set_client(mx25r6435f);
54//! mx25r6435f_virtual_alarm.set_client(mx25r6435f);
55//! ```
56
57use core::cell::Cell;
58use core::ops::{Index, IndexMut};
59use kernel::debug;
60use kernel::hil;
61use kernel::hil::time::ConvertTicks;
62use kernel::utilities::cells::TakeCell;
63use kernel::utilities::cells::{MapCell, OptionalCell};
64use kernel::utilities::leasable_buffer::SubSliceMut;
65use kernel::ErrorCode;
66
67pub const TX_BUF_LEN: usize = PAGE_SIZE as usize + 4;
68pub const RX_BUF_LEN: usize = PAGE_SIZE as usize + 4;
69
70const SPI_SPEED: u32 = 8000000;
71pub const SECTOR_SIZE: u32 = 4096;
72pub const PAGE_SIZE: u32 = 256;
73
74/// This is a wrapper around a u8 array that is sized to a single page for the
75/// MX25R6435F. The page size is 4k because that is the smallest size that can
76/// be erased (even though 256 bytes can be written).
77///
78/// An example looks like:
79///
80/// ```rust,ignore
81/// # use capsules::mx25r6435f::Mx25r6435fSector;
82///
83/// static mut PAGEBUFFER: Mx25r6435fSector = Mx25r6435fSector::new();
84/// ```
85pub struct Mx25r6435fSector(pub [u8; SECTOR_SIZE as usize]);
86
87impl Mx25r6435fSector {
88    pub const fn new() -> Self {
89        Self([0; SECTOR_SIZE as usize])
90    }
91}
92
93impl Default for Mx25r6435fSector {
94    fn default() -> Self {
95        Self::new()
96    }
97}
98
99impl Index<usize> for Mx25r6435fSector {
100    type Output = u8;
101
102    fn index(&self, idx: usize) -> &u8 {
103        &self.0[idx]
104    }
105}
106
107impl IndexMut<usize> for Mx25r6435fSector {
108    fn index_mut(&mut self, idx: usize) -> &mut u8 {
109        &mut self.0[idx]
110    }
111}
112
113impl AsMut<[u8]> for Mx25r6435fSector {
114    fn as_mut(&mut self) -> &mut [u8] {
115        &mut self.0
116    }
117}
118
119#[allow(dead_code)]
120enum Opcodes {
121    WREN = 0x06, // Write Enable
122    WRDI = 0x04, // Write Disable
123    SE = 0x20,   // Sector Erase
124    READ = 0x03, // Normal Read
125    PP = 0x02,   // Page Program (write)
126    RDID = 0x9f, // Read Identification
127    RDSR = 0x05, // Read Status Register
128}
129
130#[derive(Clone, Copy, PartialEq)]
131enum Operation {
132    Erase,
133    Write { sector_index: u32 },
134}
135
136#[derive(Clone, Copy, PartialEq)]
137enum State {
138    Idle,
139
140    ReadSector {
141        sector_index: u32,
142        page_index: u32,
143    },
144
145    EraseSectorWriteEnable {
146        sector_index: u32,
147        operation: Operation,
148    },
149    EraseSectorErase {
150        operation: Operation,
151    },
152    EraseSectorCheckDone {
153        operation: Operation,
154    },
155    EraseSectorDone,
156
157    WriteSectorWriteEnable {
158        sector_index: u32,
159        page_index: u32,
160    },
161    WriteSectorWrite {
162        sector_index: u32,
163        page_index: u32,
164    },
165    WriteSectorCheckDone {
166        sector_index: u32,
167        page_index: u32,
168    },
169    WriteSectorWaitDone {
170        sector_index: u32,
171        page_index: u32,
172    },
173
174    ReadId,
175}
176
177pub struct MX25R6435F<
178    'a,
179    S: hil::spi::SpiMasterDevice<'a> + 'a,
180    P: hil::gpio::Pin + 'a,
181    A: hil::time::Alarm<'a> + 'a,
182> {
183    spi: &'a S,
184    alarm: &'a A,
185    state: Cell<State>,
186    write_protect_pin: Option<&'a P>,
187    hold_pin: Option<&'a P>,
188    txbuffer: MapCell<SubSliceMut<'static, u8>>,
189    rxbuffer: MapCell<SubSliceMut<'static, u8>>,
190    client: OptionalCell<&'a dyn hil::flash::Client<MX25R6435F<'a, S, P, A>>>,
191    client_sector: TakeCell<'static, Mx25r6435fSector>,
192}
193
194impl<
195        'a,
196        S: hil::spi::SpiMasterDevice<'a> + 'a,
197        P: hil::gpio::Pin + 'a,
198        A: hil::time::Alarm<'a> + 'a,
199    > MX25R6435F<'a, S, P, A>
200{
201    pub fn new(
202        spi: &'a S,
203        alarm: &'a A,
204        txbuffer: &'static mut [u8],
205        rxbuffer: &'static mut [u8],
206        write_protect_pin: Option<&'a P>,
207        hold_pin: Option<&'a P>,
208    ) -> MX25R6435F<'a, S, P, A> {
209        MX25R6435F {
210            spi,
211            alarm,
212            state: Cell::new(State::Idle),
213            write_protect_pin,
214            hold_pin,
215            txbuffer: MapCell::new(txbuffer.into()),
216            rxbuffer: MapCell::new(rxbuffer.into()),
217            client: OptionalCell::empty(),
218            client_sector: TakeCell::empty(),
219        }
220    }
221
222    /// Setup SPI for this chip
223    fn configure_spi(&self) -> Result<(), ErrorCode> {
224        self.hold_pin.map(|pin| {
225            pin.set();
226        });
227        self.spi.configure(
228            hil::spi::ClockPolarity::IdleLow,
229            hil::spi::ClockPhase::SampleLeading,
230            SPI_SPEED,
231        )
232    }
233
234    /// Requests the readout of a 24-bit identification number.
235    /// This command will cause a debug print when succeeded.
236    pub fn read_identification(&self) -> Result<(), ErrorCode> {
237        self.configure_spi()?;
238
239        self.txbuffer
240            .take()
241            .map_or(Err(ErrorCode::RESERVE), |mut txbuffer| {
242                self.rxbuffer
243                    .take()
244                    .map_or(Err(ErrorCode::RESERVE), move |rxbuffer| {
245                        txbuffer.reset();
246                        txbuffer[0] = Opcodes::RDID as u8;
247                        txbuffer.slice(0..4);
248
249                        self.state.set(State::ReadId);
250                        if let Err((err, txbuffer, rxbuffer)) =
251                            self.spi.read_write_bytes(txbuffer, Some(rxbuffer))
252                        {
253                            self.txbuffer.replace(txbuffer);
254                            self.rxbuffer.replace(rxbuffer.unwrap());
255                            Err(err)
256                        } else {
257                            Ok(())
258                        }
259                    })
260            })
261    }
262
263    fn enable_write(&self) -> Result<(), ErrorCode> {
264        self.write_protect_pin.map(|pin| {
265            pin.set();
266        });
267        self.txbuffer
268            .take()
269            .map_or(Err(ErrorCode::RESERVE), |mut txbuffer| {
270                txbuffer.reset();
271                txbuffer[0] = Opcodes::WREN as u8;
272                txbuffer.slice(0..1);
273                if let Err((err, txbuffer, _)) = self.spi.read_write_bytes(txbuffer, None) {
274                    self.txbuffer.replace(txbuffer);
275                    Err(err)
276                } else {
277                    Ok(())
278                }
279            })
280    }
281
282    fn erase_sector(&self, sector_index: u32) -> Result<(), ErrorCode> {
283        self.configure_spi()?;
284        self.state.set(State::EraseSectorWriteEnable {
285            sector_index,
286            operation: Operation::Erase,
287        });
288        self.enable_write()
289    }
290
291    fn read_sector(
292        &self,
293        sector_index: u32,
294        sector: &'static mut Mx25r6435fSector,
295    ) -> Result<(), (ErrorCode, &'static mut Mx25r6435fSector)> {
296        match self.configure_spi() {
297            Ok(()) => {
298                let retval =
299                    self.txbuffer
300                        .take()
301                        .map_or(Err(ErrorCode::RESERVE), |mut txbuffer| {
302                            self.rxbuffer.take().map_or(
303                                Err(ErrorCode::RESERVE),
304                                move |mut rxbuffer| {
305                                    // Setup the read instruction
306                                    txbuffer.reset();
307                                    txbuffer[0] = Opcodes::READ as u8;
308                                    txbuffer[1] = ((sector_index * SECTOR_SIZE) >> 16) as u8;
309                                    txbuffer[2] = ((sector_index * SECTOR_SIZE) >> 8) as u8;
310                                    txbuffer[3] = ((sector_index * SECTOR_SIZE) >> 0) as u8;
311                                    txbuffer.slice(0..(PAGE_SIZE as usize + 4));
312
313                                    rxbuffer.reset();
314                                    rxbuffer.slice(0..(PAGE_SIZE as usize + 4));
315
316                                    // Call the SPI driver to kick things off.
317                                    self.state.set(State::ReadSector {
318                                        sector_index,
319                                        page_index: 0,
320                                    });
321                                    if let Err((err, txbuffer, rxbuffer)) =
322                                        self.spi.read_write_bytes(txbuffer, Some(rxbuffer))
323                                    {
324                                        self.txbuffer.replace(txbuffer);
325                                        self.rxbuffer.replace(rxbuffer.unwrap());
326                                        Err(err)
327                                    } else {
328                                        Ok(())
329                                    }
330                                },
331                            )
332                        });
333
334                match retval {
335                    Ok(()) => {
336                        self.client_sector.replace(sector);
337                        Ok(())
338                    }
339                    Err(ecode) => Err((ecode, sector)),
340                }
341            }
342            Err(error) => Err((error, sector)),
343        }
344    }
345
346    fn write_sector(
347        &self,
348        sector_index: u32,
349        sector: &'static mut Mx25r6435fSector,
350    ) -> Result<(), (ErrorCode, &'static mut Mx25r6435fSector)> {
351        match self.configure_spi() {
352            Ok(()) => {
353                self.state.set(State::EraseSectorWriteEnable {
354                    sector_index,
355                    operation: Operation::Write { sector_index },
356                });
357                let retval = self.enable_write();
358
359                match retval {
360                    Ok(()) => {
361                        self.client_sector.replace(sector);
362                        Ok(())
363                    }
364                    Err(ecode) => Err((ecode, sector)),
365                }
366            }
367            Err(error) => Err((error, sector)),
368        }
369    }
370}
371
372impl<
373        'a,
374        S: hil::spi::SpiMasterDevice<'a> + 'a,
375        P: hil::gpio::Pin + 'a,
376        A: hil::time::Alarm<'a> + 'a,
377    > hil::spi::SpiMasterClient for MX25R6435F<'a, S, P, A>
378{
379    fn read_write_done(
380        &self,
381        mut write_buffer: SubSliceMut<'static, u8>,
382        read_buffer: Option<SubSliceMut<'static, u8>>,
383        read_write_status: Result<usize, ErrorCode>,
384    ) {
385        match self.state.get() {
386            State::ReadId => {
387                self.txbuffer.replace(write_buffer);
388                read_buffer.map(|read_buffer| {
389                    debug!(
390                        "id 0x{:02x}{:02x}{:02x}",
391                        read_buffer[1], read_buffer[2], read_buffer[3]
392                    );
393                    self.rxbuffer.replace(read_buffer);
394                });
395            }
396            State::ReadSector {
397                sector_index,
398                page_index,
399            } => {
400                self.client_sector.take().map(|sector| {
401                    read_buffer.map(move |read_buffer| {
402                        // Copy read in bytes to user page
403                        for i in 0..(PAGE_SIZE as usize) {
404                            // Skip the command and address bytes (hence the +4).
405                            sector[i + (page_index * PAGE_SIZE) as usize] = read_buffer[i + 4];
406                        }
407
408                        if (page_index + 1) * PAGE_SIZE == SECTOR_SIZE {
409                            // Done reading
410                            self.state.set(State::Idle);
411                            self.txbuffer.replace(write_buffer);
412                            self.rxbuffer.replace(read_buffer);
413
414                            self.client.map(move |client| {
415                                client.read_complete(
416                                    sector,
417                                    read_write_status
418                                        .and(Ok(()))
419                                        .or(Err(hil::flash::Error::FlashError)),
420                                );
421                            });
422                        } else {
423                            let address =
424                                (sector_index * SECTOR_SIZE) + ((page_index + 1) * PAGE_SIZE);
425                            write_buffer.reset();
426                            write_buffer[0] = Opcodes::READ as u8;
427                            write_buffer[1] = (address >> 16) as u8;
428                            write_buffer[2] = (address >> 8) as u8;
429                            write_buffer[3] = (address >> 0) as u8;
430                            write_buffer.slice(0..(PAGE_SIZE as usize + 4));
431
432                            self.state.set(State::ReadSector {
433                                sector_index,
434                                page_index: page_index + 1,
435                            });
436                            self.client_sector.replace(sector);
437
438                            // TODO verify SPI return value
439                            let _ = self.spi.read_write_bytes(write_buffer, Some(read_buffer));
440                        }
441                    });
442                });
443            }
444            State::EraseSectorWriteEnable {
445                sector_index,
446                operation,
447            } => {
448                self.state.set(State::EraseSectorErase { operation });
449
450                write_buffer.reset();
451                write_buffer[0] = Opcodes::SE as u8;
452                write_buffer[1] = ((sector_index * SECTOR_SIZE) >> 16) as u8;
453                write_buffer[2] = ((sector_index * SECTOR_SIZE) >> 8) as u8;
454                write_buffer[3] = ((sector_index * SECTOR_SIZE) >> 0) as u8;
455                write_buffer.slice(0..4);
456
457                // TODO verify SPI return value
458                let _ = self.spi.read_write_bytes(write_buffer, None);
459            }
460            State::EraseSectorErase { operation } => {
461                self.state.set(State::EraseSectorCheckDone { operation });
462                self.txbuffer.replace(write_buffer);
463                // Datasheet says erase takes 58 ms on average. So we wait that
464                // long.
465                let delay = self.alarm.ticks_from_ms(58);
466                self.alarm.set_alarm(self.alarm.now(), delay);
467            }
468            State::EraseSectorCheckDone { operation } => {
469                read_buffer.map(move |read_buffer| {
470                    let status = read_buffer[1];
471
472                    // Check the status byte to see if the erase is done or not.
473                    if status & 0x01 == 0x01 {
474                        // Erase is still in progress.
475                        let _ = self.spi.read_write_bytes(write_buffer, Some(read_buffer));
476                    } else {
477                        // Erase has finished, so jump to the next state.
478                        let next_state = match operation {
479                            Operation::Erase => State::EraseSectorDone,
480                            Operation::Write { sector_index } => State::WriteSectorWriteEnable {
481                                sector_index,
482                                page_index: 0,
483                            },
484                        };
485                        self.state.set(next_state);
486                        self.rxbuffer.replace(read_buffer);
487                        self.read_write_done(write_buffer, None, read_write_status);
488                    }
489                });
490            }
491            State::EraseSectorDone => {
492                // No need to disable write, chip does it automatically.
493                self.state.set(State::Idle);
494                self.txbuffer.replace(write_buffer);
495                self.client.map(|client| {
496                    client.erase_complete(
497                        read_write_status
498                            .and(Ok(()))
499                            .or(Err(hil::flash::Error::FlashError)),
500                    );
501                });
502            }
503            State::WriteSectorWriteEnable {
504                sector_index,
505                page_index,
506            } => {
507                // Check if we are done. This happens when we have written a
508                // sector's worth of data, one page at a time.
509                if page_index * PAGE_SIZE == SECTOR_SIZE {
510                    // No need to disable writes since it happens automatically.
511                    self.state.set(State::Idle);
512                    self.txbuffer.replace(write_buffer);
513                    self.client.map(|client| {
514                        self.client_sector.take().map(|sector| {
515                            client.write_complete(
516                                sector,
517                                read_write_status
518                                    .and(Ok(()))
519                                    .or(Err(hil::flash::Error::FlashError)),
520                            );
521                        });
522                    });
523                } else {
524                    self.state.set(State::WriteSectorWrite {
525                        sector_index,
526                        page_index,
527                    });
528                    // Need to write enable before each PP
529                    write_buffer[0] = Opcodes::WREN as u8;
530                    write_buffer.slice(0..1);
531                    // TODO verify SPI return value
532                    let _ = self.spi.read_write_bytes(write_buffer, None);
533                }
534            }
535            State::WriteSectorWrite {
536                sector_index,
537                page_index,
538            } => {
539                // Continue writing page by page.
540                self.state.set(State::WriteSectorCheckDone {
541                    sector_index,
542                    page_index: page_index + 1,
543                });
544                let address = (sector_index * SECTOR_SIZE) + (page_index * PAGE_SIZE);
545                write_buffer.reset();
546                write_buffer.slice(0..(PAGE_SIZE as usize + 4));
547
548                write_buffer[0] = Opcodes::PP as u8;
549                write_buffer[1] = (address >> 16) as u8;
550                write_buffer[2] = (address >> 8) as u8;
551                write_buffer[3] = (address >> 0) as u8;
552
553                self.client_sector.map(|sector| {
554                    for i in 0..(PAGE_SIZE as usize) {
555                        write_buffer[i + 4] = sector[i + (page_index * PAGE_SIZE) as usize];
556                    }
557                });
558
559                let _ = self.spi.read_write_bytes(write_buffer, None);
560            }
561            State::WriteSectorCheckDone {
562                sector_index,
563                page_index,
564            } => {
565                self.state.set(State::WriteSectorWaitDone {
566                    sector_index,
567                    page_index,
568                });
569                self.txbuffer.replace(write_buffer);
570                // Datasheet says write page takes 3.2 ms on average. So we wait
571                // that long.
572                let delay = self.alarm.ticks_from_us(3200);
573                self.alarm.set_alarm(self.alarm.now(), delay);
574            }
575            State::WriteSectorWaitDone {
576                sector_index,
577                page_index,
578            } => {
579                read_buffer.map(move |mut read_buffer| {
580                    let status = read_buffer[1];
581
582                    read_buffer.slice(0..2);
583
584                    // Check the status byte to see if the write is done or not.
585                    if status & 0x01 == 0x01 {
586                        // Write is still in progress.
587                        let _ = self.spi.read_write_bytes(write_buffer, Some(read_buffer));
588                    } else {
589                        // Write has finished, so go back to writing.
590                        self.state.set(State::WriteSectorWriteEnable {
591                            sector_index,
592                            page_index,
593                        });
594                        self.rxbuffer.replace(read_buffer);
595                        self.read_write_done(write_buffer, None, read_write_status);
596                    }
597                });
598            }
599            _ => {}
600        }
601    }
602}
603
604impl<
605        'a,
606        S: hil::spi::SpiMasterDevice<'a> + 'a,
607        P: hil::gpio::Pin + 'a,
608        A: hil::time::Alarm<'a> + 'a,
609    > hil::time::AlarmClient for MX25R6435F<'a, S, P, A>
610{
611    fn alarm(&self) {
612        // After the timer expires we still have to check that the erase/write
613        // operation has finished.
614        self.txbuffer.take().map(|mut write_buffer| {
615            self.rxbuffer.take().map(move |read_buffer| {
616                write_buffer.reset();
617                write_buffer.slice(0..2);
618                write_buffer[0] = Opcodes::RDSR as u8;
619                let _ = self.spi.read_write_bytes(write_buffer, Some(read_buffer));
620            });
621        });
622    }
623}
624
625impl<
626        'a,
627        S: hil::spi::SpiMasterDevice<'a> + 'a,
628        P: hil::gpio::Pin + 'a,
629        A: hil::time::Alarm<'a> + 'a,
630        C: hil::flash::Client<Self>,
631    > hil::flash::HasClient<'a, C> for MX25R6435F<'a, S, P, A>
632{
633    fn set_client(&self, client: &'a C) {
634        self.client.set(client);
635    }
636}
637
638impl<
639        'a,
640        S: hil::spi::SpiMasterDevice<'a> + 'a,
641        P: hil::gpio::Pin + 'a,
642        A: hil::time::Alarm<'a> + 'a,
643    > hil::flash::Flash for MX25R6435F<'a, S, P, A>
644{
645    type Page = Mx25r6435fSector;
646
647    fn read_page(
648        &self,
649        page_number: usize,
650        buf: &'static mut Self::Page,
651    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
652        self.read_sector(page_number as u32, buf)
653    }
654
655    fn write_page(
656        &self,
657        page_number: usize,
658        buf: &'static mut Self::Page,
659    ) -> Result<(), (ErrorCode, &'static mut Self::Page)> {
660        self.write_sector(page_number as u32, buf)
661    }
662
663    fn erase_page(&self, page_number: usize) -> Result<(), ErrorCode> {
664        self.erase_sector(page_number as u32)
665    }
666}