opentitanlib/transport/chip_whisperer/
spi.rs1use anyhow::{Result, bail};
6use std::cell::RefCell;
7use std::rc::Rc;
8
9use crate::io::gpio;
10use crate::io::spi::{AssertChipSelect, MaxSizes, SpiError, Target, Transfer, TransferMode};
11use crate::transport::TransportError;
12use crate::transport::chip_whisperer::usb::Backend;
13
14use super::board::Board;
15
16pub struct Spi<B: Board> {
17 device: Rc<RefCell<Backend<B>>>,
18}
19
20impl<B: Board> Spi<B> {
21 pub fn open(device: Rc<RefCell<Backend<B>>>) -> Result<Self> {
22 {
23 let usb = device.borrow();
24 usb.spi1_enable(true)?;
25 }
26
27 Ok(Spi { device })
28 }
29
30 fn spi_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
32 let usb = self.device.borrow();
33 for transfer in transaction.iter_mut() {
34 match transfer {
35 Transfer::Read(buf) => usb.spi1_read(buf)?,
36 Transfer::Write(buf) => usb.spi1_write(buf)?,
37 Transfer::Both(wbuf, rbuf) => usb.spi1_both(wbuf, rbuf)?,
38 _ => bail!(TransportError::UnsupportedOperation),
39 }
40 }
41 Ok(())
42 }
43}
44
45impl<B: Board> Target for Spi<B> {
46 fn get_transfer_mode(&self) -> Result<TransferMode> {
47 Ok(TransferMode::Mode0)
48 }
49 fn set_transfer_mode(&self, mode: TransferMode) -> Result<()> {
50 log::warn!(
51 "set_transfer_mode to {:?}, but only Mode0 is supported on this device",
52 mode
53 );
54 Ok(())
55 }
56
57 fn get_bits_per_word(&self) -> Result<u32> {
58 Ok(8)
59 }
60 fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
61 match bits_per_word {
62 8 => Ok(()),
63 _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
64 }
65 }
66
67 fn get_max_speed(&self) -> Result<u32> {
68 Ok(6_000_000)
70 }
71 fn set_max_speed(&self, frequency: u32) -> Result<()> {
72 log::warn!(
73 "set_max_speed to {:?}, but this device doesn't support changing speeds.",
74 frequency
75 );
76 Ok(())
77 }
78
79 fn supports_bidirectional_transfer(&self) -> Result<bool> {
80 Ok(true)
81 }
82
83 fn supports_tpm_poll(&self) -> Result<bool> {
84 Ok(false)
85 }
86
87 fn set_pins(
88 &self,
89 serial_clock: Option<&Rc<dyn gpio::GpioPin>>,
90 host_out_device_in: Option<&Rc<dyn gpio::GpioPin>>,
91 host_in_device_out: Option<&Rc<dyn gpio::GpioPin>>,
92 chip_select: Option<&Rc<dyn gpio::GpioPin>>,
93 gsc_ready: Option<&Rc<dyn gpio::GpioPin>>,
94 ) -> Result<()> {
95 match (
96 serial_clock,
97 host_out_device_in,
98 host_in_device_out,
99 chip_select,
100 gsc_ready,
101 ) {
102 (Some(clk), Some(sdo), Some(sdi), Some(cs), None) => {
103 let usb = self.device.borrow();
104 usb.spi1_enable(false)?;
105 usb.spi1_setpins(
106 sdo.get_internal_pin_name().unwrap(),
107 sdi.get_internal_pin_name().unwrap(),
108 clk.get_internal_pin_name().unwrap(),
109 cs.get_internal_pin_name().unwrap(),
110 )?;
111 usb.spi1_enable(true)?;
112 Ok(())
113 }
114 (None, None, None, None, None) => Ok(()),
115 _ => {
116 Err(TransportError::UnsupportedOperation.into())
119 }
120 }
121 }
122
123 fn get_max_transfer_count(&self) -> Result<usize> {
124 Ok(42)
126 }
127
128 fn get_max_transfer_sizes(&self) -> Result<MaxSizes> {
129 Ok(MaxSizes {
130 read: 65536,
131 write: 65536,
132 })
133 }
134
135 fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
136 self.device.borrow().spi1_set_cs_pin(false)?;
138 let result = self.spi_transaction(transaction);
140 self.device.borrow().spi1_set_cs_pin(true)?;
142 result
143 }
144
145 fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
146 Err(TransportError::UnsupportedOperation.into())
147 }
148}