imxrt_boot_gen/
flexspi.rs

1//! FlexSPI configuration block definitions
2//!
3//! The FlexSPI module includes
4//!
5//! - instruction sequences
6//! - instruction lookup table (LUT)
7//! - the FlexSPI configuration block
8//!
9//! The `flexspi` types are used throughout the [`serial_flash`](crate::serial_flash) API, since the FlexSPI
10//! configuration block is at the start of every serial NOR / NAND configuration block.
11//!
12//! # Sequences and LUTs
13//!
14//! A [`Sequence`] is a collection of up to eight FlexSPI instructions ([`Instr`]).
15//! The FlexSPI controller sequentially executes instructions to perform reads, writes
16//! and I/O with a connected FLASH device. The FlexSPI controller finds each sequence
17//! in a [`LookupTable`].
18//!
19//! Use a [`SequenceBuilder`] to create `Sequence`s:
20//!
21//! ```
22//! use imxrt_boot_gen::flexspi::{Instr, Sequence, SequenceBuilder, Pads, opcodes::sdr::*};
23//!
24//! # const FAST_READ_QUAD_IO: u8 = 0;
25//! # const READ_STATUS_REGISTER_1: u8 = 0;
26//! const SEQ_READ: Sequence = SequenceBuilder::new()
27//!     .instr(Instr::new(CMD, Pads::One, FAST_READ_QUAD_IO))
28//!     .instr(Instr::new(RADDR, Pads::Four, 0x18))
29//!     .instr(Instr::new(DUMMY, Pads::Four, 0x06))
30//!     .instr(Instr::new(READ, Pads::Four, 0x04))
31//!     .build();
32//!
33//! const SEQ_READ_STATUS: Sequence = SequenceBuilder::new()
34//!     .instr(Instr::new(CMD, Pads::One, READ_STATUS_REGISTER_1))
35//!     .instr(Instr::new(READ, Pads::One, 0x04))
36//!     .build();
37//! ```
38//!
39//! Then, assign each sequence to a [`Command`] in a `LookupTable`:
40//!
41//! ```
42//! use imxrt_boot_gen::flexspi::{Command, LookupTable};
43//! # use imxrt_boot_gen::flexspi::{Sequence, SequenceBuilder};
44//!
45//! # const SEQ_READ: Sequence = SequenceBuilder::new().build();
46//! # const SEQ_READ_STATUS: Sequence = SequenceBuilder::new().build();
47//! const LUT: LookupTable = LookupTable::new()
48//!     .command(Command::Read, SEQ_READ)
49//!     .command(Command::ReadStatus, SEQ_READ_STATUS);
50//! ```
51//!
52//! # FlexSPI Configuration Block
53//!
54//! Once you've created your sequences and lookup table, use the lookup table to create
55//! a [`ConfigurationBlock`]. See the `ConfigurationBlock` documentation
56//! for more information.
57
58mod fields;
59mod lookup;
60mod sequence;
61
62use core::num::NonZeroU8;
63
64pub use fields::*;
65pub use lookup::{Command, LookupTable};
66pub use sequence::{Instr, JUMP_ON_CS, Pads, STOP, Sequence, SequenceBuilder, opcodes};
67
68/// A version identifier.
69#[derive(Debug, Clone, Copy, PartialEq, Eq)]
70#[repr(transparent)]
71pub struct Version(u32);
72
73impl Version {
74    /// Construct a version number for your FCB.
75    ///
76    /// Once constructed, pass the version to the configuration block with
77    /// [`ConfigurationBlock::version`](ConfigurationBlock::version).
78    pub const fn new(major: u8, minor: u8, bugfix: u8) -> Version {
79        Version(
80            ((b'V' as u32) << 24) | ((major as u32) << 16) | ((minor as u32) << 8) | bugfix as u32,
81        )
82    }
83}
84
85/// ASCII 'FCFB'
86const TAG: u32 = 0x4246_4346;
87/// The default FCB version used by this library.
88///
89/// Use [`Version::new`](Version::new) to compute your own version identifier.
90pub const VERSION_DEFAULT: Version = Version::new(1, 0, 0);
91#[allow(clippy::assertions_on_constants)] // Sanity check.
92const _: () = assert!(VERSION_DEFAULT.0 == 0x5601_0000);
93
94/// The recommended `csHoldTime`, `0x03`.
95///
96/// This is the default value if not set with [`ConfigurationBlock::cs_hold_time`].
97pub const RECOMMENDED_CS_HOLD_TIME: u8 = 0x03;
98/// The recommended `csSetupTime`, `0x03`.
99///
100/// This is the default value if not set with [`ConfigurationBlock::cs_setup_time`].
101pub const RECOMMENDED_CS_SETUP_TIME: u8 = 0x03;
102
103/// FlexSPI configuration block
104///
105/// The FlexSPI configuration block consists of parameters that are for specific flash
106/// devices. The configuration block includes the FlexSPI [`LookupTable`]. The configuration
107/// block is shared between serial NOR and NAND configuration blocks.
108///
109/// # Default Values
110///
111/// - `cs_hold_time` is [`RECOMMENDED_CS_HOLD_TIME`]
112/// - `cs_setup_time` is [`RECOMMENDED_CS_SETUP_TIME`]
113///
114/// All other configurable values are set to a bit pattern of 0.
115///
116/// # Examples
117///
118/// ```
119/// use imxrt_boot_gen::{Imxrt, flexspi::*};
120///
121/// const CHIP: Imxrt = // ...
122/// # Imxrt::Imxrt1010;
123///
124/// # const LUT: LookupTable = LookupTable::new();
125/// const FLEXSPI_CONFIGURATION_BLOCK: ConfigurationBlock =
126///     ConfigurationBlock::new(LUT)
127///         .read_sample_clk_src(ReadSampleClockSource::LoopbackFromDQSPad)
128///         .cs_hold_time(0x01)
129///         .cs_setup_time(0x02)
130///         .column_address_width(ColumnAddressWidth::OtherDevices)
131///         .device_mode_configuration(DeviceModeConfiguration::Disabled)
132///         .configuration_command(2, ConfigurationCommand::new(1, 12), 42)
133///         .wait_time_cfg_commands(WaitTimeConfigurationCommands::new(40_000))
134///         .flash_size(SerialFlashRegion::A1, 0x0020_0000)
135///         .serial_clk_freq(CHIP.serial_clock_frequency(SerialClockOption::MHz60))
136///         .serial_flash_pad_type(FlashPadType::Quad);
137///
138#[derive(Debug, Clone, Copy)]
139#[repr(C, packed)]
140pub struct ConfigurationBlock {
141    tag: u32,
142    version: Version,
143    _reserved0: [u8; 4], // 0x008
144    read_sample_clk_src: ReadSampleClockSource,
145    cs_hold_time: u8,
146    cs_setup_time: u8,
147    column_address_width: ColumnAddressWidth,
148    device_mode_configuration: u8,
149    /// TODO: this isn't reserved on 1170.
150    /// It's "device mode type", with a default value
151    /// of "generic."
152    _reserved1: [u8; 1], // 0x011
153    wait_time_cfg_commands: WaitTimeConfigurationCommands,
154    device_mode_sequence: DeviceModeSequence,
155    device_mode_arg: u32,
156    config_cmd_enable: u8,
157    _reserved2: [u8; 3], // 0x01D
158    config_cmd_seqs: [ConfigurationCommand; 3],
159    _reserved3: [u8; 4], // 0x02C
160    cfg_cmd_args: [u32; 3],
161    _reserved4: [u8; 4], // 0x03C
162    controller_misc_options: u32,
163    pub(crate) device_type: u8,
164    serial_flash_pad_type: FlashPadType,
165    serial_clk_freq: SerialClockFrequency,
166    lut_custom_seq_enable: u8,
167    _reserved5: [u8; 8], // 0x048
168    /// A1, A2, B1, B2
169    serial_flash_sizes: [u32; 4],
170    cs_pad_setting_override: u32,
171    sclk_pad_setting_override: u32,
172    data_pad_setting_override: u32,
173    dqs_pad_setting_override: u32,
174    timeout_ms: u32,
175    command_interval: u32,
176    data_valid_time: u32,
177    busy_offset: u16,
178    busy_bit_polarity: u16,
179    lookup_table: LookupTable,
180    lut_custom_seq: [u8; 48],
181    _reserved6: [u8; 16],
182}
183
184impl ConfigurationBlock {
185    /// Create a new configuration block that uses `lookup_table` as the
186    /// FlexSPI LUT
187    pub const fn new(lookup_table: LookupTable) -> Self {
188        ConfigurationBlock {
189            tag: TAG,
190            version: VERSION_DEFAULT,
191            read_sample_clk_src: ReadSampleClockSource::InternalLoopback,
192            cs_hold_time: RECOMMENDED_CS_HOLD_TIME,
193            cs_setup_time: RECOMMENDED_CS_SETUP_TIME,
194            column_address_width: ColumnAddressWidth::OtherDevices,
195            device_mode_configuration: 0, // Disabled
196            wait_time_cfg_commands: WaitTimeConfigurationCommands::disable(),
197            device_mode_sequence: DeviceModeSequence::zeroed(),
198            device_mode_arg: 0,
199            config_cmd_enable: 0,
200            config_cmd_seqs: [ConfigurationCommand::zeroed(); 3],
201            cfg_cmd_args: [0; 3],
202            controller_misc_options: 0,
203            device_type: 0, // Invalid value; must be updated in NOR / NAND configuration block
204            serial_flash_pad_type: FlashPadType::Single,
205            serial_clk_freq: SerialClockFrequency(NonZeroU8::new(1).unwrap()), // 30MHz on all parts
206            lut_custom_seq_enable: 0,
207            serial_flash_sizes: [0; 4],
208            cs_pad_setting_override: 0,
209            sclk_pad_setting_override: 0,
210            data_pad_setting_override: 0,
211            dqs_pad_setting_override: 0,
212            timeout_ms: 0,
213            command_interval: 0,
214            data_valid_time: 0,
215            busy_offset: 0,
216            busy_bit_polarity: 0,
217            lookup_table,
218            lut_custom_seq: [0; 48],
219
220            _reserved0: [0; 4],
221            _reserved1: [0; 1],
222            _reserved2: [0; 3],
223            _reserved3: [0; 4],
224            _reserved4: [0; 4],
225            _reserved5: [0; 8],
226            _reserved6: [0; 16],
227        }
228    }
229
230    /// Override the version.
231    ///
232    /// The default value is [`VERSION_DEFAULT`].
233    pub const fn version(mut self, version: Version) -> Self {
234        self.version = version;
235        self
236    }
237
238    /// `readSampleClkSrc`, the clock source for FlexSPI
239    ///
240    /// If not set, this defaults to `ReadSampleClockSource::InternalLoopback`.
241    pub const fn read_sample_clk_src(mut self, read_sample_clk_src: ReadSampleClockSource) -> Self {
242        self.read_sample_clk_src = read_sample_clk_src;
243        self
244    }
245
246    /// Set the chip select hold time (`csHoldTime`)
247    ///
248    /// If not set, this will be `RECOMMENDED_CS_HOLD_TIME`, which is `0x03`.
249    pub const fn cs_hold_time(mut self, cs_hold_time: u8) -> Self {
250        self.cs_hold_time = cs_hold_time;
251        self
252    }
253
254    /// Set the chip select setup time (`csSetupTime`)
255    ///
256    /// If not set, this will be `RECOMMENDED_CS_SETUP_TIME`, which is `0x03`.
257    pub const fn cs_setup_time(mut self, cs_setup_time: u8) -> Self {
258        self.cs_setup_time = cs_setup_time;
259        self
260    }
261
262    /// `columnAddressWidth`, the properties of the flash memory
263    ///
264    /// If not set, this defaults to `ColumnAddressWidth::OtherDevices`
265    pub const fn column_address_width(mut self, column_address_width: ColumnAddressWidth) -> Self {
266        self.column_address_width = column_address_width;
267        self
268    }
269
270    /// Sets device configuration mode. The `DeviceModeConfiguration::Disabled` variant
271    /// will set `deviceModeCfgEnable` to "disabled". Otherwise, we will set
272    /// `deviceModeCfgEnable` to "enabled," and we use the sequence and argument
273    /// parameters in the FCB.
274    ///
275    /// If not set, this defaults to `DeviceModeConfiguration::Disabled`.
276    pub const fn device_mode_configuration(
277        mut self,
278        device_mode_configuration: DeviceModeConfiguration,
279    ) -> Self {
280        match device_mode_configuration {
281            DeviceModeConfiguration::Disabled => {
282                self.device_mode_configuration = 0;
283            }
284            DeviceModeConfiguration::Enabled {
285                device_mode_seq,
286                device_mode_arg,
287            } => {
288                self.device_mode_configuration = 1;
289                self.device_mode_sequence = device_mode_seq;
290                self.device_mode_arg = device_mode_arg;
291            }
292        }
293        self
294    }
295
296    /// Set a configuration command.
297    ///
298    /// If this is ever called, it automatically enables configuration commands.
299    /// There is no way to clear the enable flag, even if you were to override it
300    /// with zero-initialized `config_command`s.
301    ///
302    /// If your boot ROM supports it, you can use this to augment flash part setup,
303    /// such as setting read parameters.
304    ///
305    /// # Panics
306    ///
307    /// There are only three configuration commands. Panics if `index` is anything
308    /// other than 0, 1, or 2.
309    pub const fn configuration_command(
310        mut self,
311        index: usize,
312        config_command: ConfigurationCommand,
313        config_arg: u32,
314    ) -> Self {
315        self.config_cmd_enable = 1;
316        self.config_cmd_seqs[index] = config_command;
317        self.cfg_cmd_args[index] = config_arg;
318        self
319    }
320
321    /// Sets `waitTimeCfgCommands`
322    ///
323    /// If not set, this defaults to `WaitTimeConfigurationCommands::disable()`.
324    pub const fn wait_time_cfg_commands(
325        mut self,
326        wait_time_cfg_commands: WaitTimeConfigurationCommands,
327    ) -> Self {
328        self.wait_time_cfg_commands = wait_time_cfg_commands;
329        self
330    }
331
332    /// Sets the serial flash pad type, `sFlashPad`.
333    ///
334    /// If not set, this defaults to `FlashPadType::Single`.
335    pub const fn serial_flash_pad_type(mut self, serial_flash_pad_type: FlashPadType) -> Self {
336        self.serial_flash_pad_type = serial_flash_pad_type;
337        self
338    }
339
340    /// Sets the serial clock frequencey, `serialClkFreq`
341    ///
342    /// If not set, this defaults to `SerialClockFrequency::MHz30`.
343    pub const fn serial_clk_freq(mut self, serial_clk_freq: SerialClockFrequency) -> Self {
344        self.serial_clk_freq = serial_clk_freq;
345        self
346    }
347
348    /// Set a flash size for the provided flash region
349    ///
350    /// Any region that's not set will default to `0`.
351    pub const fn flash_size(mut self, flash_region: SerialFlashRegion, flash_size: u32) -> Self {
352        self.serial_flash_sizes[flash_region as usize] = flash_size;
353        self
354    }
355
356    /// Set miscellaneous controller options.
357    ///
358    /// See your chip's reference manual for more information on valid values. This method performs
359    /// no checking on the input.
360    pub const fn controller_misc_options(mut self, options: u32) -> Self {
361        self.controller_misc_options = options;
362        self
363    }
364}
365
366const _STATIC_ASSERT_SIZE: [u32; 1] =
367    [0; (core::mem::size_of::<ConfigurationBlock>() == 448) as usize];