1use anyhow::{Context, Result, bail, ensure};
6use std::cell::RefCell;
7use std::rc::Rc;
8
9use crate::io::eeprom;
10use crate::io::eeprom::Transaction::{Read, WaitForBusyClear, Write};
11use crate::io::spi::{
12 AssertChipSelect, ClockPolarity, MaxSizes, SpiError, Target, TargetChipDeassert, Transfer,
13 TransferMode,
14};
15use crate::spiflash::flash::SpiFlash;
16use crate::transport::dediprog::{ClockSpeed, Command, Inner};
17use crate::util::voltage::Voltage;
18
19pub struct DediprogSpi {
20 inner: Rc<RefCell<Inner>>,
21 max_chunk_size: usize,
22}
23
24#[repr(u8)]
25enum ReadMode {
26 ReadStandard = 1,
27 ReadFast = 2,
28 ReadAtmel45 = 3,
29 Read4bAddrFast = 4,
30 Read4bAddrFast0x0c = 5,
31}
32
33#[repr(u8)]
34enum WriteMode {
35 WritePageProgram = 1,
36 WritePageWrite = 2,
37 Write1bAai = 3,
38 Write2bAai = 4,
39 Write128bPage = 5,
40 WritePageAt26df041 = 6,
41 WriteSiliconBlueFpga = 7,
42 Write64bPageNumonyx = 8,
43 Write4bAddr256bPagePgm = 9,
44 Write32bPageMxic512k = 10,
45 Write4bAdr256bPagePgm0x12 = 11,
46 Write4bAdr256bPagePgmFlags = 12,
47}
48
49impl DediprogSpi {
50 const MAX_GENERIC_DATA_LEN: usize = 16;
51
52 const READ_CHUNK_SIZE: usize = 512;
53 const WRITE_CHUNK_SIZE: usize = 256;
54
55 pub fn open(inner: Rc<RefCell<Inner>>) -> Result<Self> {
56 let this = Self {
57 inner,
58 max_chunk_size: 65535 * 256,
59 };
60 this.set_spi_clock()?;
61 Ok(this)
62 }
63
64 fn set_spi_clock(&self) -> Result<()> {
65 self.inner.borrow().device.write_control(
66 rusb::request_type(
67 rusb::Direction::Out,
68 rusb::RequestType::Vendor,
69 rusb::Recipient::Endpoint,
70 ),
71 Command::SetSpiClk as u8,
72 self.inner.borrow().spi_clock as u16,
73 0,
74 &[],
75 )?;
76 Ok(())
77 }
78
79 fn read_sfdp(&self, mut address: u32, mut rbuf: &mut [u8]) -> Result<()> {
80 while !rbuf.is_empty() {
82 let chunk_size = std::cmp::min(rbuf.len(), Self::MAX_GENERIC_DATA_LEN);
83 let addr_bytes = address.to_be_bytes();
84 let sub_cmd: [u8; 5] = [
85 SpiFlash::READ_SFDP,
86 addr_bytes[1],
87 addr_bytes[2],
88 addr_bytes[3],
89 0,
90 ];
91 self.transmit(&sub_cmd, chunk_size)?;
92 self.receive(&mut rbuf[..chunk_size])?;
93 rbuf = &mut rbuf[chunk_size..];
94 address += chunk_size as u32;
95 }
96 Ok(())
97 }
98
99 fn transmit(&self, wbuf: &[u8], rbuf_len: usize) -> Result<()> {
100 self.inner.borrow().device.write_control(
101 rusb::request_type(
102 rusb::Direction::Out,
103 rusb::RequestType::Vendor,
104 rusb::Recipient::Endpoint,
105 ),
106 Command::Transceive as u8,
107 rbuf_len as u16,
108 0,
109 wbuf,
110 )?;
111 Ok(())
112 }
113
114 fn receive(&self, rbuf: &mut [u8]) -> Result<()> {
116 self.inner.borrow().device.read_control(
117 rusb::request_type(
118 rusb::Direction::In,
119 rusb::RequestType::Vendor,
120 rusb::Recipient::Endpoint,
121 ),
122 Command::Transceive as u8,
123 0,
124 0,
125 rbuf,
126 )?;
127 Ok(())
128 }
129
130 fn eeprom_read_transaction(&self, cmd: &eeprom::Cmd, rbuf: &mut [u8]) -> Result<()> {
131 let mut usbcmd = [0u8; 10];
132 match (
133 cmd.get_opcode(),
134 cmd.get_address_len(),
135 cmd.get_dummy_cycles(),
136 ) {
137 ([SpiFlash::READ_SFDP], 3, 8) => {
138 return self.read_sfdp(cmd.get_address(), rbuf);
139 }
140 ([SpiFlash::READ], 3, 0) => {
141 usbcmd[3] = ReadMode::ReadStandard as u8;
143 usbcmd[4] = SpiFlash::READ;
144 }
145 ([SpiFlash::READ], 4, 0) => {
146 usbcmd[3] = ReadMode::Read4bAddrFast as u8;
149 usbcmd[4] = SpiFlash::FAST_READ;
150 }
151 _ => bail!(SpiError::InvalidTransferMode(
152 "Command not supported".to_string()
153 )),
154 }
155
156 ensure!(
157 rbuf.len().is_multiple_of(Self::READ_CHUNK_SIZE),
158 SpiError::InvalidTransferMode(format!(
159 "Read length {} not multiple of {}",
160 rbuf.len(),
161 Self::READ_CHUNK_SIZE
162 ))
163 );
164
165 let chunks = (rbuf.len() / Self::READ_CHUNK_SIZE) as u16;
166
167 usbcmd[0..2].clone_from_slice(&chunks.to_le_bytes());
168 usbcmd[6..10].clone_from_slice(&cmd.get_address().to_le_bytes());
169 self.inner.borrow().device.write_control(
170 rusb::request_type(
171 rusb::Direction::Out,
172 rusb::RequestType::Vendor,
173 rusb::Recipient::Endpoint,
174 ),
175 Command::Read as u8,
176 0,
177 0,
178 &usbcmd,
179 )?;
180 for chunk in rbuf.chunks_exact_mut(Self::READ_CHUNK_SIZE) {
181 self.inner
182 .borrow()
183 .device
184 .read_bulk(self.inner.borrow().in_endpoint, chunk)?;
185 }
186 Ok(())
187 }
188
189 fn eeprom_write_transaction(
190 &self,
191 cmd: &eeprom::Cmd,
192 wbuf: &[u8],
193 _wait_for_busy_clear: bool,
194 ) -> Result<()> {
195 ensure!(
196 wbuf.len().is_multiple_of(Self::WRITE_CHUNK_SIZE),
197 SpiError::InvalidTransferMode(format!(
198 "Write length {} not multiple of {}",
199 wbuf.len(),
200 Self::WRITE_CHUNK_SIZE
201 ))
202 );
203
204 let chunks = (wbuf.len() / Self::WRITE_CHUNK_SIZE) as u16;
205
206 let mut usbcmd = [0u8; 10];
207 usbcmd[0..2].clone_from_slice(&chunks.to_le_bytes());
208
209 match (
210 cmd.get_opcode(),
211 cmd.get_address_len(),
212 cmd.get_dummy_cycles(),
213 ) {
214 ([SpiFlash::PAGE_PROGRAM], 3, 0) => {
215 usbcmd[3] = WriteMode::WritePageProgram as u8;
216 usbcmd[4] = SpiFlash::PAGE_PROGRAM;
217 }
218 ([SpiFlash::PAGE_PROGRAM], 4, 0) => {
219 usbcmd[3] = WriteMode::Write4bAddr256bPagePgm as u8;
220 usbcmd[4] = SpiFlash::PAGE_PROGRAM;
221 }
222 _ => bail!(SpiError::InvalidTransferMode(
223 "Command not supported".to_string()
224 )),
225 }
226 usbcmd[6..10].clone_from_slice(&cmd.get_address().to_le_bytes());
227 self.inner.borrow().device.write_control(
228 rusb::request_type(
229 rusb::Direction::Out,
230 rusb::RequestType::Vendor,
231 rusb::Recipient::Endpoint,
232 ),
233 Command::Write as u8,
234 0,
235 0,
236 &usbcmd,
237 )?;
238 for chunk in wbuf.chunks_exact(Self::WRITE_CHUNK_SIZE) {
239 let mut buf = [0xFFu8; 512];
240 buf[0..Self::WRITE_CHUNK_SIZE].clone_from_slice(chunk);
241 self.inner
242 .borrow()
243 .device
244 .write_bulk(self.inner.borrow().out_endpoint, &buf)?;
245 }
246 Ok(())
247 }
248
249 fn do_run_eeprom_transactions(
250 &self,
251 mut transactions: &mut [eeprom::Transaction],
252 ) -> Result<()> {
253 loop {
254 match transactions {
255 [
256 eeprom::Transaction::Command(pre_cmd),
257 Write(cmd, wbuf),
258 WaitForBusyClear,
259 rest @ ..,
260 ] => {
261 transactions = rest;
262 if pre_cmd.get_opcode() == [SpiFlash::WRITE_ENABLE] {
263 } else {
265 self.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?)])?
266 }
267 self.eeprom_write_transaction(cmd, wbuf, true)?;
268 }
269 [eeprom::Transaction::Command(cmd), rest @ ..] => {
270 transactions = rest;
271 self.run_transaction(&mut [Transfer::Write(cmd.to_bytes()?)])?
272 }
273 [Read(cmd, rbuf), rest @ ..] => {
274 transactions = rest;
275 self.eeprom_read_transaction(cmd, rbuf)?;
276 }
277 [Write(cmd, wbuf), WaitForBusyClear, rest @ ..] => {
278 transactions = rest;
279 self.eeprom_write_transaction(cmd, wbuf, true)?;
280 }
281 [Write(cmd, wbuf), rest @ ..] => {
282 transactions = rest;
283 self.eeprom_write_transaction(cmd, wbuf, false)?;
284 }
285 [WaitForBusyClear, rest @ ..] => {
286 transactions = rest;
287 let mut status = eeprom::STATUS_WIP;
288 while status & eeprom::STATUS_WIP != 0 {
289 self.run_transaction(&mut [
290 Transfer::Write(&[eeprom::READ_STATUS]),
291 Transfer::Read(std::slice::from_mut(&mut status)),
292 ])?;
293 }
294 }
295 [] => return Ok(()),
296 }
297 }
298 }
299}
300
301impl Target for DediprogSpi {
302 fn get_transfer_mode(&self) -> Result<TransferMode> {
303 unimplemented!();
304 }
305 fn set_transfer_mode(&self, _mode: TransferMode) -> Result<()> {
306 unimplemented!();
307 }
308
309 fn get_bits_per_word(&self) -> Result<u32> {
310 Ok(8)
311 }
312 fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
313 match bits_per_word {
314 8 => Ok(()),
315 _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
316 }
317 }
318
319 fn get_max_speed(&self) -> Result<u32> {
320 Ok(match self.inner.borrow().spi_clock {
321 ClockSpeed::Clk24Mhz => 24_000_000,
322 ClockSpeed::Clk12Mhz => 12_000_000,
323 ClockSpeed::Clk8Mhz => 8_000_000,
324 ClockSpeed::Clk3Mhz => 3_000_000,
325 ClockSpeed::Clk2p18Mhz => 2_180_000,
326 ClockSpeed::Clk1p5Mhz => 1_500_000,
327 ClockSpeed::Clk750Khz => 750_000,
328 ClockSpeed::Clk375Khz => 375_000,
329 })
330 }
331 fn set_max_speed(&self, frequency: u32) -> Result<()> {
332 self.inner.borrow_mut().spi_clock = if frequency >= 24_000_000 {
333 ClockSpeed::Clk24Mhz
334 } else if frequency >= 12_000_000 {
335 ClockSpeed::Clk12Mhz
336 } else if frequency >= 8_000_000 {
337 ClockSpeed::Clk8Mhz
338 } else if frequency >= 3_000_000 {
339 ClockSpeed::Clk3Mhz
340 } else if frequency >= 2_180_000 {
341 ClockSpeed::Clk2p18Mhz
342 } else if frequency >= 1_500_000 {
343 ClockSpeed::Clk1p5Mhz
344 } else if frequency >= 750_000 {
345 ClockSpeed::Clk750Khz
346 } else {
347 ClockSpeed::Clk375Khz
348 };
349 self.set_spi_clock()
350 }
351
352 fn supports_bidirectional_transfer(&self) -> Result<bool> {
353 Ok(false)
354 }
355
356 fn supports_tpm_poll(&self) -> Result<bool> {
357 Ok(false)
358 }
359
360 fn get_max_transfer_count(&self) -> Result<usize> {
361 Ok(42)
363 }
364
365 fn get_max_transfer_sizes(&self) -> Result<MaxSizes> {
367 Ok(MaxSizes {
368 read: Self::MAX_GENERIC_DATA_LEN,
369 write: Self::MAX_GENERIC_DATA_LEN,
370 })
371 }
372
373 fn set_voltage(&self, voltage: Voltage) -> Result<()> {
375 let mut inner = self.inner.borrow_mut();
376 inner.voltage = if voltage.as_volts() <= 0.3 {
377 super::Voltage::V0
378 } else if voltage.as_volts() >= 1.6 && voltage.as_volts() <= 2.0 {
379 super::Voltage::V1p8
380 } else if voltage.as_volts() >= 2.3 && voltage.as_volts() <= 2.7 {
381 super::Voltage::V2p5
382 } else if voltage.as_volts() >= 3.0 && voltage.as_volts() <= 3.6 {
383 super::Voltage::V3p5
384 } else {
385 bail!(SpiError::InvalidVoltage(voltage))
386 };
387 inner.set_voltage()
388 }
389
390 fn get_flashrom_programmer(&self) -> Result<String> {
391 let inner = self.inner.borrow();
392 let voltage = match inner.voltage {
393 super::Voltage::V0 => "0V",
394 super::Voltage::V1p8 => "1.8V",
395 super::Voltage::V2p5 => "2.5V",
396 super::Voltage::V3p5 => "3.5V",
397 };
398 let spispeed = match inner.spi_clock {
399 ClockSpeed::Clk24Mhz => "24M",
400 ClockSpeed::Clk12Mhz => "12M",
401 ClockSpeed::Clk8Mhz => "8M",
402 ClockSpeed::Clk3Mhz => "3M",
403 ClockSpeed::Clk2p18Mhz => "2.18M",
404 ClockSpeed::Clk1p5Mhz => "1.5M",
405 ClockSpeed::Clk750Khz => "750k",
406 ClockSpeed::Clk375Khz => "375k",
407 };
408 Ok(format!("dediprog:voltage={voltage},spispeed={spispeed}"))
409 }
410
411 fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
414 match transaction {
415 [] => (),
416 [Transfer::Write(wbuf), Transfer::Read(rbuf)] => {
417 ensure!(
420 wbuf.len() <= Self::MAX_GENERIC_DATA_LEN,
421 SpiError::InvalidDataLength(wbuf.len())
422 );
423 ensure!(
424 rbuf.len() <= Self::MAX_GENERIC_DATA_LEN,
425 SpiError::InvalidDataLength(rbuf.len())
426 );
427 self.transmit(wbuf, rbuf.len())?;
428 self.receive(rbuf)?;
429 }
430 [Transfer::Write(wbuf)] => {
431 ensure!(
432 wbuf.len() <= Self::MAX_GENERIC_DATA_LEN,
433 SpiError::InvalidDataLength(wbuf.len())
434 );
435 self.transmit(wbuf, 0)?;
436 }
437 _ => bail!(SpiError::InvalidTransferMode(
438 "Unsupported combination".to_string()
439 )),
440 }
441 Ok(())
442 }
443
444 fn get_eeprom_max_transfer_sizes(&self) -> Result<MaxSizes> {
446 Ok(MaxSizes {
447 read: self.max_chunk_size,
448 write: self.max_chunk_size,
449 })
450 }
451
452 fn run_eeprom_transactions(&self, transactions: &mut [eeprom::Transaction]) -> Result<()> {
453 self.do_run_eeprom_transactions(transactions)
454 }
455
456 fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
457 unimplemented!();
458 }
459}