1use anyhow::Result;
6use serde::{Deserialize, Serialize};
7
8use super::spi::{SpiError, Target, Transfer};
9use crate::spiflash::SpiFlash;
10
11#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
12pub enum Switch {
14 Mode111,
15 Mode11N,
16 Mode1NN,
17 ModeNNN,
18}
19
20#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
21pub enum DataWidth {
22 Single, Dual, Quad,
25 Octo,
26}
27
28#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
29pub struct Cmd {
30 data: [u8; 8],
31 opcode_len: u8,
32 addr_len: u8,
33 mode: Mode,
34}
35
36#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
37pub enum AddressMode {
38 #[default]
39 Mode3b = 3,
40 Mode4b = 4,
41}
42
43#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
44pub struct Mode {
45 pub dummy_cycles: u8,
47 pub switch: Switch,
50 pub width: DataWidth,
52 pub double_transfer_rate: bool,
54}
55
56impl Mode {
57 pub fn cmd(&self, opcode: u8) -> Cmd {
59 let mut result = Cmd {
60 data: [0u8; 8],
61 opcode_len: 1,
62 addr_len: 0,
63 mode: *self,
64 };
65 result.data[0] = opcode;
66 result
67 }
68 pub fn cmd_addr(&self, opcode: u8, addr: u32, addr_mode: AddressMode) -> Cmd {
70 let mut result = Cmd {
71 data: [0u8; 8],
72 opcode_len: 1,
73 addr_len: addr_mode as u8,
74 mode: *self,
75 };
76 result.data[0] = opcode;
77 result.data[1..1 + result.addr_len as usize]
78 .clone_from_slice(&addr.to_be_bytes()[4 - result.addr_len as usize..]);
79 result
80 }
81 pub fn cmd2(&self, opcode1: u8, opcode2: u8) -> Cmd {
83 let mut result = Cmd {
84 data: [0u8; 8],
85 opcode_len: 2,
86 addr_len: 0,
87 mode: *self,
88 };
89 result.data[0] = opcode1;
90 result.data[1] = opcode2;
91 result
92 }
93 pub fn cmd2_addr(&self, opcode1: u8, opcode2: u8, addr: u32, addr_mode: AddressMode) -> Cmd {
95 let mut result = Cmd {
96 data: [0u8; 8],
97 opcode_len: 2,
98 addr_len: addr_mode as u8,
99 mode: *self,
100 };
101 result.data[0] = opcode1;
102 result.data[1] = opcode2;
103 result.data[2..2 + result.addr_len as usize]
104 .clone_from_slice(&addr.to_be_bytes()[4 - result.addr_len as usize..]);
105 result
106 }
107
108 pub fn dummy_cycles(&self, dummy_cycles: u8) -> Mode {
109 Mode {
110 dummy_cycles,
111 switch: self.switch,
112 width: self.width,
113 double_transfer_rate: self.double_transfer_rate,
114 }
115 }
116}
117
118pub const MODE_111: Mode = Mode {
120 dummy_cycles: 0,
121 switch: Switch::Mode111,
122 width: DataWidth::Single,
123 double_transfer_rate: false,
124};
125
126pub const MODE_1S1S1D: Mode = Mode {
128 dummy_cycles: 0,
129 switch: Switch::Mode11N,
130 width: DataWidth::Single,
131 double_transfer_rate: true,
132};
133
134pub const MODE_1S1D1D: Mode = Mode {
136 dummy_cycles: 0,
137 switch: Switch::Mode1NN,
138 width: DataWidth::Single,
139 double_transfer_rate: true,
140};
141
142pub const MODE_112: Mode = Mode {
144 dummy_cycles: 0,
145 switch: Switch::Mode11N,
146 width: DataWidth::Dual,
147 double_transfer_rate: false,
148};
149
150pub const MODE_122: Mode = Mode {
151 dummy_cycles: 0,
152 switch: Switch::Mode1NN,
153 width: DataWidth::Dual,
154 double_transfer_rate: false,
155};
156
157pub const MODE_222: Mode = Mode {
158 dummy_cycles: 0,
159 switch: Switch::ModeNNN,
160 width: DataWidth::Dual,
161 double_transfer_rate: false,
162};
163
164pub const MODE_114: Mode = Mode {
166 dummy_cycles: 0,
167 switch: Switch::Mode11N,
168 width: DataWidth::Quad,
169 double_transfer_rate: false,
170};
171
172pub const MODE_144: Mode = Mode {
173 dummy_cycles: 0,
174 switch: Switch::Mode1NN,
175 width: DataWidth::Quad,
176 double_transfer_rate: false,
177};
178
179pub const MODE_444: Mode = Mode {
180 dummy_cycles: 0,
181 switch: Switch::ModeNNN,
182 width: DataWidth::Quad,
183 double_transfer_rate: false,
184};
185
186impl Cmd {
187 pub fn to_bytes(&self) -> Result<&[u8]> {
191 if self.mode.switch == Switch::Mode111 && self.mode.dummy_cycles.is_multiple_of(8) {
192 Ok(&self.data
193 [0..(self.opcode_len + self.addr_len + self.mode.dummy_cycles / 8) as usize])
194 } else {
195 Err(SpiError::InvalidOption(
196 "This target does not support the requested mode".to_string(),
197 )
198 .into())
199 }
200 }
201
202 pub fn get_opcode_len(&self) -> u8 {
203 self.opcode_len
204 }
205
206 pub fn get_opcode(&self) -> &[u8] {
207 &self.data[..self.opcode_len as usize]
208 }
209
210 pub fn get_address_len(&self) -> u8 {
211 self.addr_len
212 }
213
214 pub fn get_address(&self) -> u32 {
215 let mut addr_bytes = [0u8; 4];
216 addr_bytes[4 - self.addr_len as usize..].clone_from_slice(
217 &self.data[self.opcode_len as usize..(self.opcode_len + self.addr_len) as usize],
218 );
219 u32::from_be_bytes(addr_bytes)
220 }
221
222 pub fn get_dummy_cycles(&self) -> u8 {
223 self.mode.dummy_cycles
224 }
225
226 pub fn get_switch(&self) -> Switch {
227 self.mode.switch
228 }
229
230 pub fn get_width(&self) -> DataWidth {
231 self.mode.width
232 }
233
234 pub fn get_double_transfer_rate(&self) -> bool {
235 self.mode.double_transfer_rate
236 }
237}
238
239pub enum Transaction<'rd, 'wr> {
240 Command(Cmd),
241 Read(Cmd, &'rd mut [u8]),
242 Write(Cmd, &'wr [u8]),
243 WaitForBusyClear,
244}
245
246pub fn default_run_eeprom_transactions<T: Target + ?Sized>(
247 spi: &T,
248 transactions: &mut [Transaction],
249) -> Result<()> {
250 for transfer in transactions {
254 match transfer {
255 Transaction::Command(cmd) => {
256 spi.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?)])?
257 }
258 Transaction::Read(cmd, rbuf) => {
259 spi.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?), Transfer::Read(rbuf)])?
260 }
261 Transaction::Write(cmd, wbuf) => {
262 spi.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?), Transfer::Write(wbuf)])?
263 }
264 Transaction::WaitForBusyClear => {
265 let mut status = SpiFlash::STATUS_WIP;
266 while status & SpiFlash::STATUS_WIP != 0 {
267 spi.run_transaction(&mut [
268 Transfer::Write(&[SpiFlash::READ_STATUS]),
269 Transfer::Read(std::slice::from_mut(&mut status)),
270 ])?;
271 }
272 }
273 }
274 }
275 Ok(())
276}