1use anyhow::Result;
6use clap::Args;
7use serde::{Deserialize, Serialize};
8use std::rc::Rc;
9use std::str::FromStr;
10use thiserror::Error;
11
12use super::{eeprom, gpio};
13use crate::app::TransportWrapper;
14use crate::impl_serializable_error;
15use crate::transport::TransportError;
16use crate::util::voltage::Voltage;
17
18#[derive(Clone, Debug, Args, Serialize, Deserialize)]
19pub struct SpiParams {
20 #[arg(long)]
22 pub bus: Option<String>,
23
24 #[arg(long)]
26 pub speed: Option<u32>,
27
28 #[arg(long)]
30 pub chip_select: Option<String>,
31
32 #[arg(long)]
34 pub voltage: Option<Voltage>,
35
36 #[arg(long)]
38 pub mode: Option<TransferMode>,
39}
40
41impl SpiParams {
42 pub fn create(
43 &self,
44 transport: &TransportWrapper,
45 default_instance: &str,
46 ) -> Result<Rc<dyn Target>> {
47 let spi = transport.spi(self.bus.as_deref().unwrap_or(default_instance))?;
48 if let Some(ref cs) = self.chip_select {
49 spi.set_pins(
50 None,
51 None,
52 None,
53 Some(&transport.gpio_pin(cs.as_str())?),
54 None,
55 )?;
56 }
57 if let Some(speed) = self.speed {
58 spi.set_max_speed(speed)?;
59 }
60 if let Some(voltage) = self.voltage {
61 spi.set_voltage(voltage)?;
62 }
63 if let Some(mode) = self.mode {
64 spi.set_transfer_mode(mode)?;
65 }
66 Ok(spi)
67 }
68}
69
70#[derive(Error, Debug, Serialize, Deserialize)]
72pub enum SpiError {
73 #[error("Invalid option: {0}")]
74 InvalidOption(String),
75 #[error("Invalid word size: {0}")]
76 InvalidWordSize(u32),
77 #[error("Invalid speed: {0}")]
78 InvalidSpeed(u32),
79 #[error("Invalid data length: {0}")]
80 InvalidDataLength(usize),
81 #[error("Invalid data width: {0:?}")]
82 InvalidDataWidth(eeprom::DataWidth),
83 #[error("Double transfer rate not supported")]
84 InvalidDoubleTransferRate(),
85 #[error("Invalid number of dummy cycles: {0}")]
86 InvalidDummyCycles(u8),
87 #[error("Mismatched data length: {0} != {1}")]
88 MismatchedDataLength(usize, usize),
89 #[error("Invalid transfer mode: {0}")]
90 InvalidTransferMode(String),
91 #[error("Invalid SPI voltage: {0}")]
92 InvalidVoltage(Voltage),
93 #[error("Given pin does not support requested SPI function")]
94 InvalidPin,
95}
96impl_serializable_error!(SpiError);
97
98#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
102pub enum TransferMode {
103 Mode0,
105 Mode1,
107 Mode2,
109 Mode3,
111}
112
113impl FromStr for TransferMode {
114 type Err = SpiError;
115 fn from_str(s: &str) -> std::result::Result<TransferMode, Self::Err> {
116 match s {
117 "Mode0" | "mode0" | "0" => Ok(TransferMode::Mode0),
118 "Mode1" | "mode1" | "1" => Ok(TransferMode::Mode1),
119 "Mode2" | "mode2" | "2" => Ok(TransferMode::Mode2),
120 "Mode3" | "mode3" | "3" => Ok(TransferMode::Mode3),
121 _ => Err(SpiError::InvalidTransferMode(s.to_string())),
122 }
123 }
124}
125
126#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
127pub enum ClockPhase {
128 SampleLeading,
129 SampleTrailing,
130}
131
132#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
133pub enum ClockPolarity {
134 IdleLow,
135 IdleHigh,
136}
137
138impl TransferMode {
139 pub fn phase(&self) -> ClockPhase {
140 match self {
141 TransferMode::Mode0 | TransferMode::Mode2 => ClockPhase::SampleLeading,
142 TransferMode::Mode1 | TransferMode::Mode3 => ClockPhase::SampleTrailing,
143 }
144 }
145 pub fn polarity(&self) -> ClockPolarity {
146 match self {
147 TransferMode::Mode0 | TransferMode::Mode1 => ClockPolarity::IdleLow,
148 TransferMode::Mode2 | TransferMode::Mode3 => ClockPolarity::IdleHigh,
149 }
150 }
151}
152
153#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
155pub struct MaxSizes {
156 pub read: usize,
157 pub write: usize,
158}
159
160pub enum Transfer<'rd, 'wr> {
162 Read(&'rd mut [u8]),
163 Write(&'wr [u8]),
164 Both(&'wr [u8], &'rd mut [u8]),
166 TpmPoll,
168 GscReady,
170}
171
172pub trait Target {
174 fn get_transfer_mode(&self) -> Result<TransferMode>;
176 fn set_transfer_mode(&self, mode: TransferMode) -> Result<()>;
178
179 fn get_bits_per_word(&self) -> Result<u32>;
181 fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()>;
183
184 fn get_max_speed(&self) -> Result<u32>;
186 fn set_max_speed(&self, max_speed: u32) -> Result<()>;
188
189 fn supports_bidirectional_transfer(&self) -> Result<bool>;
191
192 fn supports_tpm_poll(&self) -> Result<bool>;
194
195 fn set_pins(
200 &self,
201 _serial_clock: Option<&Rc<dyn gpio::GpioPin>>,
202 _host_out_device_in: Option<&Rc<dyn gpio::GpioPin>>,
203 _host_in_device_out: Option<&Rc<dyn gpio::GpioPin>>,
204 _chip_select: Option<&Rc<dyn gpio::GpioPin>>,
205 _gsc_ready: Option<&Rc<dyn gpio::GpioPin>>,
206 ) -> Result<()> {
207 Err(SpiError::InvalidPin.into())
208 }
209
210 fn get_max_transfer_count(&self) -> Result<usize>;
212
213 fn get_max_transfer_sizes(&self) -> Result<MaxSizes>;
215
216 fn set_voltage(&self, _voltage: Voltage) -> Result<()> {
217 Err(SpiError::InvalidOption("This target does not support set_voltage".to_string()).into())
218 }
219
220 fn get_flashrom_programmer(&self) -> Result<String> {
223 Err(TransportError::UnsupportedOperation.into())
224 }
225
226 fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()>;
229
230 fn get_eeprom_max_transfer_sizes(&self) -> Result<MaxSizes> {
232 let spi_max = self.get_max_transfer_sizes()?;
234 Ok(MaxSizes {
235 read: spi_max.read,
236 write: spi_max.write - 6,
237 })
238 }
239
240 fn run_eeprom_transactions(&self, transactions: &mut [eeprom::Transaction]) -> Result<()> {
243 eeprom::default_run_eeprom_transactions(self, transactions)
244 }
245
246 fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect>;
249}
250
251pub struct AssertChipSelect {
254 target: Rc<dyn TargetChipDeassert>,
255}
256
257impl AssertChipSelect {
258 pub fn new(target: Rc<dyn TargetChipDeassert>) -> Self {
261 Self { target }
262 }
263}
264
265impl Drop for AssertChipSelect {
266 fn drop(&mut self) {
267 self.target.deassert_cs()
268 }
269}
270
271pub trait TargetChipDeassert {
274 fn deassert_cs(&self);
275}