imxrt_boot_gen/
lib.rs

1//! Generate i.MX RT boot-time data structures.
2//!
3//! # Rationale
4//!
5//! i.MX RT processors require certain data structures in order to configure
6//! FlexSPI and SEMC peripherals. The data structures must be placed
7//! in a certain region of memory with values that describe how a peripheral should
8//! interact with external storage. The data structures only support certain values,
9//! and need a particular layout in order to boot the system.
10//!
11//! The `imxrt-boot-gen` crate helps you generate data structures to boot i.MX RT processors.
12//! As of this writing, the API supports
13//!
14//! - serial NOR flash via FlexSPI
15//!
16//! Other configurations, like NAND flash and parallel SEMC, may be added in the future.
17//!
18//! `imxrt-boot-gen` does not perscribe a way to properly place these data structures in a
19//! firmware image. Consider using [`imxrt-rt`](https://docs.rs/imxrt-rt) if you need
20//! a runtime that can place these data structures in your firmware image.
21//!
22//! # Usage
23//!
24//! Add `imxrt-boot-gen` to your dependencies:
25//!
26//! ```toml
27//! [dependencies]
28//! imxrt-boot-gen = # ...
29//! ```
30//!
31//! The entire API is `const`. You may define your data structures at compile
32//! time, and assign the values to `static` memory in your embedded program.
33//!
34//! See the module-level documentation for more information about the API.
35//!
36//! ## License
37//!
38//! Licensed under either of
39//!
40//! - [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) ([LICENSE-APACHE](./LICENSE-APACHE))
41//! - [MIT License](http://opensource.org/licenses/MIT) ([LICENSE-MIT](./LICENSE-MIT))
42//!
43//! at your option.
44//!
45//! Unless you explicitly state otherwise, any contribution intentionally submitted
46//! for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
47//! dual licensed as above, without any additional terms or conditions.
48
49#![cfg_attr(not(test), no_std)]
50
51use core::num::NonZeroU8;
52
53use flexspi::{SerialClockFrequency, SerialClockOption};
54use serial_flash::nor::IpSerialClockFrequency;
55
56pub mod flexspi;
57pub mod serial_flash;
58
59/// The MCU family.
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub enum Imxrt {
62    /// A 1010 MCU.
63    Imxrt1010,
64    /// A 1020 MCU.
65    ///
66    /// This should also work for the 1024 MCUs.
67    Imxrt1020,
68    /// A 1040 MCU.
69    Imxrt1040,
70    /// A 1050 MCU.
71    Imxrt1050,
72    /// A 1060 MCU.
73    ///
74    /// This is expected to work with 1064 MCUs.
75    Imxrt1060,
76    /// A 1160 MCU, booting core.
77    Imxrt1160,
78    /// A 1170 MCU, booting core.
79    Imxrt1170,
80    /// A 1180 MCU, booting core.
81    Imxrt1180,
82}
83
84/// An error during generation.
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86#[non_exhaustive]
87pub enum Error {
88    /// This isn't supported for your selected chip.
89    NotSupportedForChip,
90}
91
92impl Imxrt {
93    /// Produce a serial clock frequency for most flash access.
94    ///
95    /// If your chip doesn't support the given option, this returns
96    /// [`Error::NotSupportedForChip`].
97    pub const fn try_serial_clock_frequency(
98        self,
99        opt: SerialClockOption,
100    ) -> Result<SerialClockFrequency, Error> {
101        let [scf, _] = match self {
102            Self::Imxrt1010 => Self::imxrt1010(opt),
103            Self::Imxrt1020 => Self::imxrt1020(opt),
104            Self::Imxrt1040 => Self::imxrt1040(opt),
105            Self::Imxrt1050 => Self::imxrt1050(opt),
106            Self::Imxrt1060 => Self::imxrt1060(opt),
107            Self::Imxrt1160 => Self::imxrt1160(opt),
108            Self::Imxrt1170 => Self::imxrt1170(opt),
109            Self::Imxrt1180 => Self::imxrt1180(opt),
110        };
111
112        let Some(scf) = NonZeroU8::new(scf) else {
113            return Err(Error::NotSupportedForChip);
114        };
115
116        Ok(SerialClockFrequency(scf))
117    }
118
119    /// Produce a serial clock frequency for most flash accesses.
120    ///
121    /// # Panics
122    ///
123    /// Panics if the chip doesn't support the serial clock option.
124    pub const fn serial_clock_frequency(self, opt: SerialClockOption) -> SerialClockFrequency {
125        match self.try_serial_clock_frequency(opt) {
126            Ok(freq) => freq,
127            // Maybe someday, we can be more specific in a const fn.
128            Err(_) => panic!("This chip doesn't support that frequency"),
129        }
130    }
131
132    /// Produce a serial clock frequency for IP access.
133    pub const fn try_ip_serial_clock_frequency(
134        self,
135        opt: SerialClockOption,
136    ) -> Result<IpSerialClockFrequency, Error> {
137        let [_, ipscf] = match self {
138            Self::Imxrt1010 => Self::imxrt1010(opt),
139            Self::Imxrt1020 => Self::imxrt1020(opt),
140            Self::Imxrt1040 => Self::imxrt1040(opt),
141            Self::Imxrt1050 => Self::imxrt1050(opt),
142            Self::Imxrt1060 => Self::imxrt1060(opt),
143            Self::Imxrt1160 => Self::imxrt1160(opt),
144            Self::Imxrt1170 => Self::imxrt1170(opt),
145            Self::Imxrt1180 => Self::imxrt1180(opt),
146        };
147
148        let Some(ipscf) = NonZeroU8::new(ipscf) else {
149            return Err(Error::NotSupportedForChip);
150        };
151
152        Ok(IpSerialClockFrequency(ipscf))
153    }
154
155    /// Produce a serial clock frequency for IP access.
156    ///
157    /// # Panics
158    ///
159    /// Panics if the chip doesn't support the serial clock option.
160    pub const fn ip_serial_clock_frequency(self, opt: SerialClockOption) -> IpSerialClockFrequency {
161        match self.try_ip_serial_clock_frequency(opt) {
162            Ok(freq) => freq,
163            Err(_) => panic!("This chip doesn't support that frequency"),
164        }
165    }
166
167    //
168    // Element 0 => serial clock enum
169    // Element 1 => IP serial clock enum
170    //
171    // If the value isn't supported, return zero.
172    //
173
174    const fn imxrt1010(opt: SerialClockOption) -> [u8; 2] {
175        match opt {
176            SerialClockOption::MHz30 => [1, 1],
177            SerialClockOption::MHz50 => [2, 2],
178            SerialClockOption::MHz60 => [3, 3],
179            SerialClockOption::MHz75 => [4, 4],
180            SerialClockOption::MHz80 => [5, 5],
181            SerialClockOption::MHz100 => [6, 6],
182            SerialClockOption::MHz120 => [7, 0],
183            SerialClockOption::MHz133 => [8, 7],
184            SerialClockOption::MHz166 => [0, 0],
185        }
186    }
187
188    const fn imxrt1020(opt: SerialClockOption) -> [u8; 2] {
189        match opt {
190            SerialClockOption::MHz30 => [1, 1],
191            SerialClockOption::MHz50 => [2, 2],
192            SerialClockOption::MHz60 => [3, 3],
193            SerialClockOption::MHz75 => [4, 4],
194            SerialClockOption::MHz80 => [5, 5],
195            SerialClockOption::MHz100 => [6, 6],
196            SerialClockOption::MHz120 => [0, 0],
197            SerialClockOption::MHz133 => [7, 7],
198            SerialClockOption::MHz166 => [8, 8],
199        }
200    }
201
202    const fn imxrt1040(opt: SerialClockOption) -> [u8; 2] {
203        match opt {
204            SerialClockOption::MHz30 => [1, 1],
205            SerialClockOption::MHz50 => [2, 2],
206            SerialClockOption::MHz60 => [3, 3],
207            SerialClockOption::MHz75 => [4, 4],
208            SerialClockOption::MHz80 => [5, 5],
209            SerialClockOption::MHz100 => [6, 6],
210            SerialClockOption::MHz120 => [7, 7],
211            SerialClockOption::MHz133 => [8, 8],
212            SerialClockOption::MHz166 => [9, 9],
213        }
214    }
215
216    const fn imxrt1050(opt: SerialClockOption) -> [u8; 2] {
217        Self::imxrt1020(opt)
218    }
219
220    const fn imxrt1060(opt: SerialClockOption) -> [u8; 2] {
221        Self::imxrt1040(opt)
222    }
223
224    const fn imxrt1160(opt: SerialClockOption) -> [u8; 2] {
225        match opt {
226            SerialClockOption::MHz30 => [1, 1],
227            SerialClockOption::MHz50 => [2, 2],
228            SerialClockOption::MHz60 => [3, 3],
229            SerialClockOption::MHz75 => [0, 0],
230            SerialClockOption::MHz80 => [4, 4],
231            SerialClockOption::MHz100 => [5, 5],
232            SerialClockOption::MHz120 => [6, 6],
233            SerialClockOption::MHz133 => [7, 7],
234            SerialClockOption::MHz166 => [8, 8],
235        }
236    }
237
238    const fn imxrt1170(opt: SerialClockOption) -> [u8; 2] {
239        Self::imxrt1160(opt)
240    }
241
242    const fn imxrt1180(opt: SerialClockOption) -> [u8; 2] {
243        Self::imxrt1160(opt)
244    }
245}