Skip to main content

ws63_hal/
sfc.rs

1//! SFC (SPI Flash Controller) driver for WS63.
2//!
3//! The WS63 SFC provides a high-speed interface to external SPI NOR Flash
4//! memory. It supports standard, dual, and quad SPI modes, configurable
5//! timing, command-based operations, and bus DMA for efficient data transfer.
6//!
7//! # Features
8//!
9//! - Standard/Dual/Quad SPI modes
10//! - 3-byte and 4-byte addressing
11//! - Configurable SPI mode (Mode0/Mode3)
12//! - Command-based flash operations (read, write, erase)
13//! - 16-word (64-byte) data buffer for indirect operations
14//! - Bus DMA for direct memory-mapped flash access
15//! - Hardware write protect
16//! - AES low-power mode for XIP encryption
17
18use crate::peripherals::SfcCfg;
19
20/// SPI interface type for flash operations.
21#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum SpiIfType {
23    /// Standard SPI (1 data line).
24    Standard = 0,
25    /// Dual I/O (2 data lines).
26    DualIO = 1,
27    /// Dual I/O continuous.
28    DualIOCont = 2,
29    /// Quad I/O (4 data lines).
30    QuadIO = 3,
31    /// Quad I/O continuous.
32    QuadIOCont = 4,
33}
34
35/// Flash address mode.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub enum AddressMode {
38    /// 3-byte addressing (up to 16 MB).
39    ThreeByte = 0,
40    /// 4-byte addressing (up to 4 GB).
41    FourByte = 1,
42}
43
44/// SPI mode for the flash bus.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum FlashSpiMode {
47    /// CPOL=0, CPHA=0.
48    Mode0 = 0,
49    /// CPOL=1, CPHA=1.
50    Mode3 = 1,
51}
52
53/// SFC read data delay.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum ReadDelay {
56    /// No delay.
57    Delay0,
58    /// Half cycle delay.
59    DelayHalf,
60    /// 1 cycle delay.
61    Delay1,
62    /// 1.5 cycle delay.
63    Delay1_5,
64}
65
66/// SFC bus configuration for memory-mapped reads.
67#[derive(Debug, Clone, Copy)]
68pub struct BusConfig {
69    /// SPI interface type for read operations.
70    pub read_if_type: SpiIfType,
71    /// Number of dummy bytes for read operations.
72    pub read_dummy_bytes: u8,
73    /// Read instruction code (e.g., 0x03 for standard read, 0xEB for quad read).
74    pub read_instruction: u8,
75    /// Prefetch count for read operations.
76    pub read_prefetch_cnt: u8,
77    /// SPI interface type for write operations.
78    pub write_if_type: SpiIfType,
79    /// Number of dummy bytes for write operations.
80    pub write_dummy_bytes: u8,
81    /// Write instruction code.
82    pub write_instruction: u8,
83}
84
85impl Default for BusConfig {
86    fn default() -> Self {
87        Self {
88            read_if_type: SpiIfType::Standard,
89            read_dummy_bytes: 0,
90            read_instruction: 0x03, // Standard SPI read
91            read_prefetch_cnt: 0,
92            write_if_type: SpiIfType::Standard,
93            write_dummy_bytes: 0,
94            write_instruction: 0x02, // Standard page program
95        }
96    }
97}
98
99/// SFC driver.
100pub struct SfcDriver<'d> {
101    _sfc: SfcCfg<'d>,
102}
103
104/// Minimum inter-operation delay in clock cycles.
105const MIN_TSHSL: u32 = 5;
106
107impl<'d> SfcDriver<'d> {
108    /// Create a new SFC driver.
109    pub fn new(sfc: SfcCfg<'d>) -> Self {
110        Self { _sfc: sfc }
111    }
112
113    fn regs(&self) -> &'static ws63_pac::sfc_cfg::RegisterBlock {
114        // SAFETY: PAC peripheral pointer is a static physical MMIO address, always valid
115        unsafe { &*SfcCfg::ptr() }
116    }
117
118    // ── Global configuration ───────────────────────────────────────
119
120    /// Configure the global SFC settings.
121    pub fn configure_global(
122        &mut self,
123        spi_mode: FlashSpiMode,
124        addr_mode: AddressMode,
125        read_delay: ReadDelay,
126        write_protect: bool,
127    ) {
128        let mut val: u32 = 0;
129        val |= spi_mode as u32; // mode [0]
130        if write_protect {
131            val |= 1 << 1; // wp_en [1]
132        }
133        if matches!(addr_mode, AddressMode::FourByte) {
134            val |= 1 << 2; // flash_addr_mode [2]
135        }
136        val |= (read_delay as u32) << 3; // rd_delay [3:5]
137
138        unsafe {
139            self.regs().global_config().write(|w| w.bits(val));
140        }
141    }
142
143    /// Configure the SFC timing parameters.
144    ///
145    /// * `tshsl` — Inter-operation delay: (tshsl + 2) clock cycles
146    /// * `tcss` — CS setup time: (tcss + 1) clock cycles
147    /// * `tcsh` — CS hold time: (tcsh + 1) clock cycles
148    pub fn configure_timing(&mut self, tshsl: u8, tcss: u8, tcsh: u8) {
149        // Clamp to register field widths
150        let tshsl = (tshsl.max(MIN_TSHSL as u8 - 2) as u32) & 0x0F;
151        let tcss = (tcss as u32) & 0x07;
152        let tcsh = (tcsh as u32) & 0x07;
153
154        let val = tshsl | (tcss << 8) | (tcsh << 12);
155
156        unsafe {
157            self.regs().timing().write(|w| w.bits(val));
158        }
159    }
160
161    // ── Bus configuration ──────────────────────────────────────────
162
163    /// Configure the bus read/write parameters for memory-mapped access.
164    pub fn configure_bus(&mut self, config: &BusConfig) {
165        let r = self.regs();
166
167        // BUS_CONFIG1
168        let mut cfg1: u32 = 0;
169        cfg1 |= (config.read_if_type as u32) & 0x07; // rd_mem_if_type [0:2]
170        cfg1 |= ((config.read_dummy_bytes as u32) & 0x07) << 3; // rd_dummy_bytes [3:5]
171        cfg1 |= ((config.read_prefetch_cnt as u32) & 0x03) << 6; // rd_prefetch_cnt [6:7]
172        cfg1 |= ((config.read_instruction as u32) & 0xFF) << 8; // rd_ins [8:15]
173        cfg1 |= ((config.write_if_type as u32) & 0x07) << 16; // wr_mem_if_type [16:18]
174        cfg1 |= ((config.write_dummy_bytes as u32) & 0x07) << 19; // wr_dummy_bytes [19:21]
175        cfg1 |= ((config.write_instruction as u32) & 0xFF) << 22; // wr_ins [22:29]
176
177        unsafe {
178            r.bus_config1().write(|w| w.bits(cfg1));
179        }
180    }
181
182    /// Release the SFC bus from soft reset.
183    pub fn release_bus_reset(&mut self) {
184        unsafe {
185            self.regs().soft_rst_mask().write(|w| w.bits(0x01));
186        }
187    }
188
189    /// Hold the SFC bus in soft reset.
190    pub fn hold_bus_reset(&mut self) {
191        unsafe {
192            self.regs().soft_rst_mask().write(|w| w.bits(0x00));
193        }
194    }
195
196    // ── Command operations ──────────────────────────────────────────
197
198    /// Write a 32-bit word to a specific data buffer register.
199    fn write_databuf(r: &ws63_pac::sfc_cfg::RegisterBlock, idx: usize, word: u32) {
200        unsafe {
201            match idx {
202                0 => {
203                    r.cmd_databuf_0().write(|w| w.bits(word));
204                }
205                1 => {
206                    r.cmd_databuf_1().write(|w| w.bits(word));
207                }
208                2 => {
209                    r.cmd_databuf_2().write(|w| w.bits(word));
210                }
211                3 => {
212                    r.cmd_databuf_3().write(|w| w.bits(word));
213                }
214                4 => {
215                    r.cmd_databuf_4().write(|w| w.bits(word));
216                }
217                5 => {
218                    r.cmd_databuf_5().write(|w| w.bits(word));
219                }
220                6 => {
221                    r.cmd_databuf_6().write(|w| w.bits(word));
222                }
223                7 => {
224                    r.cmd_databuf_7().write(|w| w.bits(word));
225                }
226                8 => {
227                    r.cmd_databuf_8().write(|w| w.bits(word));
228                }
229                9 => {
230                    r.cmd_databuf_9().write(|w| w.bits(word));
231                }
232                10 => {
233                    r.cmd_databuf_10().write(|w| w.bits(word));
234                }
235                11 => {
236                    r.cmd_databuf_11().write(|w| w.bits(word));
237                }
238                12 => {
239                    r.cmd_databuf_12().write(|w| w.bits(word));
240                }
241                13 => {
242                    r.cmd_databuf_13().write(|w| w.bits(word));
243                }
244                14 => {
245                    r.cmd_databuf_14().write(|w| w.bits(word));
246                }
247                15 => {
248                    r.cmd_databuf_15().write(|w| w.bits(word));
249                }
250                _ => {}
251            }
252        }
253    }
254
255    /// Read a 32-bit word from a specific data buffer register.
256    fn read_databuf(r: &ws63_pac::sfc_cfg::RegisterBlock, idx: usize) -> u32 {
257        match idx {
258            0 => r.cmd_databuf_0().read().bits(),
259            1 => r.cmd_databuf_1().read().bits(),
260            2 => r.cmd_databuf_2().read().bits(),
261            3 => r.cmd_databuf_3().read().bits(),
262            4 => r.cmd_databuf_4().read().bits(),
263            5 => r.cmd_databuf_5().read().bits(),
264            6 => r.cmd_databuf_6().read().bits(),
265            7 => r.cmd_databuf_7().read().bits(),
266            8 => r.cmd_databuf_8().read().bits(),
267            9 => r.cmd_databuf_9().read().bits(),
268            10 => r.cmd_databuf_10().read().bits(),
269            11 => r.cmd_databuf_11().read().bits(),
270            12 => r.cmd_databuf_12().read().bits(),
271            13 => r.cmd_databuf_13().read().bits(),
272            14 => r.cmd_databuf_14().read().bits(),
273            15 => r.cmd_databuf_15().read().bits(),
274            _ => 0,
275        }
276    }
277
278    /// Execute a flash command (no data phase).
279    ///
280    /// * `instruction` — Flash operation code.
281    /// * `address` — Operation address (for commands with address phase).
282    /// * `address_enable` — Whether the command includes an address phase.
283    pub fn send_command(&mut self, instruction: u8, address: u32, address_enable: bool) {
284        let r = self.regs();
285
286        // Write instruction
287        unsafe {
288            r.cmd_ins().write(|w| w.bits(instruction as u32));
289        }
290
291        // Write address
292        if address_enable {
293            unsafe {
294                r.cmd_addr().write(|w| w.bits(address));
295            }
296        }
297
298        // Build command config
299        let mut cmd_cfg: u32 = 0;
300        cmd_cfg |= 0x01; // start
301        if address_enable {
302            cmd_cfg |= 1 << 2; // addr_en
303        }
304        cmd_cfg |= 0 << 17; // mem_if_type = Standard
305
306        unsafe {
307            r.cmd_config().write(|w| w.bits(cmd_cfg));
308        }
309
310        // Wait for command completion
311        while !self.command_done() {}
312        self.clear_interrupts();
313    }
314
315    /// Execute a flash command with data phase.
316    ///
317    /// * `instruction` — Flash operation code.
318    /// * `address` — Operation address.
319    /// * `write_data` — Data to write (for write commands).
320    /// * `read` — `true` for read commands, `false` for write commands.
321    ///
322    /// Returns the read data (up to 64 bytes) for read commands.
323    pub fn command_with_data(
324        &mut self,
325        instruction: u8,
326        address: u32,
327        write_data: &[u8],
328        read: bool,
329    ) -> Result<[u8; 64], SfcError> {
330        let r = self.regs();
331        let data_len = write_data.len().min(64);
332
333        if !read && !write_data.is_empty() {
334            // Load write data into data buffer
335            for (i, chunk) in write_data[..data_len].chunks(4).enumerate() {
336                let mut word: u32 = 0;
337                for (j, &b) in chunk.iter().enumerate() {
338                    word |= (b as u32) << (j * 8);
339                }
340                Self::write_databuf(r, i, word);
341            }
342        }
343
344        // Write instruction and address
345        unsafe {
346            r.cmd_ins().write(|w| w.bits(instruction as u32));
347            r.cmd_addr().write(|w| w.bits(address));
348        }
349
350        // Build command config
351        let mut cmd_cfg: u32 = 0;
352        cmd_cfg |= 0x01; // start
353        cmd_cfg |= 1 << 2; // addr_en
354        cmd_cfg |= 1 << 7; // data_en
355        if read {
356            cmd_cfg |= 1 << 8; // rw = read
357        }
358        cmd_cfg |= (((data_len.saturating_sub(1)) as u32) & 0x3F) << 9; // data_cnt
359        cmd_cfg |= 0 << 17; // mem_if_type = Standard
360
361        unsafe {
362            r.cmd_config().write(|w| w.bits(cmd_cfg));
363        }
364
365        // Wait for command completion
366        while !self.command_done() {}
367        self.clear_interrupts();
368
369        // Read back data for read commands
370        let mut result = [0u8; 64];
371        if read {
372            let mut idx = 0;
373            for i in 0..data_len.div_ceil(4) {
374                let word = Self::read_databuf(r, i);
375                let bytes = word.to_le_bytes();
376                for &b in &bytes {
377                    if idx < data_len {
378                        result[idx] = b;
379                        idx += 1;
380                    }
381                }
382            }
383        }
384
385        Ok(result)
386    }
387
388    // ── Bus DMA ────────────────────────────────────────────────────
389
390    /// Start a bus DMA transfer between flash and memory.
391    ///
392    /// * `mem_addr` — Memory address (must be in valid range).
393    /// * `flash_addr` — Flash address.
394    /// * `length` — Number of bytes to transfer.
395    /// * `read` — `true` for flash-to-memory read, `false` for memory-to-flash write.
396    pub fn bus_dma_start(&mut self, mem_addr: u32, flash_addr: u32, length: u32, read: bool) {
397        let r = self.regs();
398
399        unsafe {
400            r.bus_dma_mem_saddr().write(|w| w.bits(mem_addr));
401            r.bus_dma_flash_saddr().write(|w| w.bits(flash_addr));
402            r.bus_dma_len().write(|w| w.bits(length & 0x3FFF_FFFF));
403        }
404
405        let mut ctrl: u32 = 0;
406        ctrl |= 0x01; // dma_start
407        if read {
408            ctrl |= 1 << 1; // dma_rw = read
409        }
410
411        unsafe {
412            r.bus_dma_ctrl().write(|w| w.bits(ctrl));
413        }
414    }
415
416    /// Wait for bus DMA to complete.
417    pub fn bus_dma_wait(&self) {
418        while !self.dma_done() {}
419        self.clear_interrupts();
420    }
421
422    /// Check if the DMA transfer is complete.
423    pub fn dma_done(&self) -> bool {
424        self.regs().int_status().read().bits() & 0x02 != 0
425    }
426
427    /// Check if a flash command is complete.
428    pub fn command_done(&self) -> bool {
429        self.regs().int_status().read().bits() & 0x01 != 0
430    }
431
432    /// Clear all SFC interrupts.
433    pub fn clear_interrupts(&self) {
434        unsafe {
435            self.regs().int_clear().write(|w| w.bits(0x03));
436        }
437    }
438
439    /// Enable specific SFC interrupts.
440    ///
441    /// * `cmd_done` — Command operation complete interrupt.
442    /// * `dma_done` — DMA transfer complete interrupt.
443    pub fn enable_interrupts(&mut self, cmd_done: bool, dma_done: bool) {
444        let mut mask: u32 = 0;
445        if cmd_done {
446            mask |= 0x01;
447        }
448        if dma_done {
449            mask |= 0x02;
450        }
451        unsafe {
452            self.regs().int_mask().write(|w| w.bits(mask));
453        }
454    }
455
456    /// Check raw interrupt status.
457    ///
458    /// Returns `(cmd_done_raw, dma_done_raw)`.
459    pub fn raw_interrupt_status(&self) -> (bool, bool) {
460        let sts = self.regs().int_raw_status().read().bits();
461        ((sts & 0x01) != 0, (sts & 0x02) != 0)
462    }
463
464    // ── AES (XIP encryption) control ───────────────────────────────
465
466    /// Enable AES low-power mode (for XIP encrypted execution).
467    pub fn enable_aes_low_power(&mut self) {
468        unsafe {
469            self.regs().lea_lp_en().write(|w| w.bits(0x01));
470        }
471    }
472
473    /// Disable AES low-power mode.
474    pub fn disable_aes_low_power(&mut self) {
475        unsafe {
476            self.regs().lea_lp_en().write(|w| w.bits(0x00));
477        }
478    }
479
480    /// Set AES IV valid flag.
481    pub fn set_iv_valid(&mut self) {
482        unsafe {
483            self.regs().lea_iv_vld().write(|w| w.bits(0x01));
484        }
485    }
486
487    /// Read AES DFX information (for debugging).
488    pub fn read_aes_dfx(&self) -> u32 {
489        self.regs().lea_dfx_info().read().bits()
490    }
491}
492
493/// SFC operation error.
494#[derive(Debug)]
495pub enum SfcError {
496    /// Command timeout.
497    Timeout,
498    /// DMA transfer error.
499    DmaError,
500}