1use core::marker::PhantomData;
2
3pub use crate::shared::{FifoClear, TriggerLevel};
4
5cfg_if::cfg_if! {
6 if #[cfg(feature = "vor1x")] {
7 pub const BASE_ADDR_0: usize = 0x4005_0000;
9 pub const BASE_ADDR_1: usize = 0x4005_1000;
11 pub const BASE_ADDR_2: usize = 0x4005_2000;
13 } else if #[cfg(feature = "vor4x")] {
14 pub const BASE_ADDR_0: usize = 0x4001_5000;
16 pub const BASE_ADDR_1: usize = 0x4001_5400;
18 pub const BASE_ADDR_2: usize = 0x4001_5800;
20 pub const BASE_ADDR_3: usize = 0x4001_5C00;
22 }
23}
24
25#[derive(Debug, PartialEq, Eq, Clone, Copy)]
26#[cfg_attr(feature = "defmt", derive(defmt::Format))]
27pub enum Bank {
28 Spi0,
29 Spi1,
30 Spi2,
31 #[cfg(feature = "vor4x")]
32 Spi3,
33}
34
35impl Bank {
36 pub unsafe fn steal_regs(&self) -> MmioSpi<'static> {
42 Spi::new_mmio(*self)
43 }
44}
45
46#[bitbybit::bitenum(u4)]
47#[derive(Debug, PartialEq, Eq)]
48#[cfg_attr(feature = "defmt", derive(defmt::Format))]
49pub enum WordSize {
50 OneBit = 0x00,
51 FourBits = 0x03,
52 EightBits = 0x07,
53 SixteenBits = 0x0f,
54}
55
56#[derive(Debug, PartialEq, Eq)]
57#[bitbybit::bitenum(u3, exhaustive = true)]
58#[cfg_attr(feature = "defmt", derive(defmt::Format))]
59pub enum HwChipSelectId {
60 Id0 = 0,
61 Id1 = 1,
62 Id2 = 2,
63 Id3 = 3,
64 Id4 = 4,
65 Id5 = 5,
66 Id6 = 6,
67 Id7 = 7,
68}
69
70#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_fields(feature = "defmt"))]
71pub struct Control0 {
72 #[bits(8..=15, rw)]
73 scrdv: u8,
74 #[bit(7, rw)]
75 sph: bool,
76 #[bit(6, rw)]
77 spo: bool,
78 #[bits(0..=3, rw)]
79 word_size: Option<WordSize>,
80}
81
82#[bitbybit::bitfield(u32, default = 0x0, debug, defmt_bitfields(feature = "defmt"))]
83pub struct Control1 {
84 #[bit(11, rw)]
85 mtxpause: bool,
86 #[bit(10, rw)]
87 mdlycap: bool,
88 #[bit(9, rw)]
89 bm_stall: bool,
90 #[bit(8, rw)]
91 bm_start: bool,
92 #[bit(7, rw)]
93 blockmode: bool,
94 #[bits(4..=6, rw)]
95 ss: HwChipSelectId,
96 #[bit(3, rw)]
97 sod: bool,
98 #[bit(2, rw)]
99 slave_mode: bool,
100 #[bit(1, rw)]
101 enable: bool,
102 #[bit(0, rw)]
103 lbm: bool,
104}
105
106#[bitbybit::bitfield(u32)]
107#[derive(Debug)]
108pub struct Data {
109 #[bit(31, rw)]
113 bm_start_stop: bool,
114 #[bit(30, rw)]
118 bm_skipdata: bool,
119 #[bits(0..=15, rw)]
120 data: u16,
121}
122
123#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
124pub struct Status {
125 #[bit(7, r)]
127 tx_trigger: bool,
128 #[bit(6, r)]
130 rx_trigger: bool,
131 #[bit(5, r)]
132 rx_data_first: bool,
133 #[bit(4, r)]
134 busy: bool,
135 #[bit(3, r)]
136 rx_full: bool,
137 #[bit(2, r)]
138 rx_not_empty: bool,
139 #[bit(1, r)]
140 tx_not_full: bool,
141 #[bit(0, r)]
142 tx_empty: bool,
143}
144
145#[derive(Debug, Copy, Clone, PartialEq, Eq)]
149pub struct ClockPrescaler(arbitrary_int::UInt<u32, 8>);
150
151impl ClockPrescaler {
152 pub const fn new(value: u8) -> Self {
153 ClockPrescaler(arbitrary_int::UInt::<u32, 8>::new(value as u32))
154 }
155 pub const fn value(&self) -> u8 {
156 self.0.value() as u8
157 }
158}
159
160#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
161pub struct InterruptControl {
162 #[bit(3, rw)]
164 tx: bool,
165 #[bit(2, rw)]
167 rx: bool,
168 #[bit(1, rw)]
172 rx_timeout: bool,
173 #[bit(0, rw)]
174 rx_overrun: bool,
175}
176
177#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
178pub struct InterruptStatus {
179 #[bit(3, r)]
181 tx: bool,
182 #[bit(2, r)]
184 rx: bool,
185 #[bit(1, r)]
189 rx_timeout: bool,
190 #[bit(0, r)]
191 rx_overrun: bool,
192}
193
194#[bitbybit::bitfield(u32)]
195#[derive(Debug)]
196pub struct InterruptClear {
197 #[bit(1, w)]
199 rx_timeout: bool,
200 #[bit(0, w)]
201 rx_overrun: bool,
202}
203
204#[bitbybit::bitfield(u32, debug, defmt_bitfields(feature = "defmt"))]
205pub struct State {
206 #[bits(0..=7, r)]
207 rx_state: u8,
208 #[bits(8..=15, r)]
209 rx_fifo: u8,
210 #[bits(24..=31, r)]
211 tx_fifo: u8,
212}
213
214#[derive(derive_mmio::Mmio)]
215#[mmio(no_ctors)]
216#[repr(C)]
217pub struct Spi {
218 ctrl0: Control0,
219 ctrl1: Control1,
220 data: Data,
221 #[mmio(PureRead)]
222 status: Status,
223 clkprescale: ClockPrescaler,
224 irq_enb: InterruptControl,
225 #[mmio(PureRead)]
227 irq_raw: InterruptStatus,
228 #[mmio(PureRead)]
230 irq_status: InterruptStatus,
231 #[mmio(Write)]
232 irq_clear: InterruptClear,
233 rx_fifo_trigger: TriggerLevel,
234 tx_fifo_trigger: TriggerLevel,
235 #[mmio(Write)]
236 fifo_clear: FifoClear,
237 #[mmio(PureRead)]
238 state: u32,
239 #[cfg(feature = "vor1x")]
240 _reserved: [u32; 0x3F2],
241 #[cfg(feature = "vor4x")]
242 _reserved: [u32; 0xF2],
243 #[mmio(PureRead)]
245 perid: u32,
246}
247
248cfg_if::cfg_if! {
249 if #[cfg(feature = "vor1x")] {
250 static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x1000);
251 } else if #[cfg(feature = "vor4x")] {
252 static_assertions::const_assert_eq!(core::mem::size_of::<Spi>(), 0x400);
253 }
254}
255
256impl Spi {
257 fn new_mmio_at(base: usize) -> MmioSpi<'static> {
258 MmioSpi {
259 ptr: base as *mut _,
260 phantom: PhantomData,
261 }
262 }
263
264 pub fn new_mmio(bank: Bank) -> MmioSpi<'static> {
265 match bank {
266 Bank::Spi0 => Self::new_mmio_at(BASE_ADDR_0),
267 Bank::Spi1 => Self::new_mmio_at(BASE_ADDR_1),
268 Bank::Spi2 => Self::new_mmio_at(BASE_ADDR_2),
269 #[cfg(feature = "vor4x")]
270 Bank::Spi3 => Self::new_mmio_at(BASE_ADDR_2),
271 }
272 }
273}