1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0

use anyhow::Result;
use clap::Args;
use serde::{Deserialize, Serialize};
use std::rc::Rc;
use std::str::FromStr;
use thiserror::Error;

use super::{eeprom, gpio};
use crate::app::TransportWrapper;
use crate::impl_serializable_error;
use crate::transport::TransportError;
use crate::util::voltage::Voltage;

#[derive(Clone, Debug, Args, Serialize, Deserialize)]
pub struct SpiParams {
    /// SPI instance.
    #[arg(long)]
    pub bus: Option<String>,

    /// SPI bus speed.
    #[arg(long)]
    pub speed: Option<u32>,

    /// SPI chip select pin.
    #[arg(long)]
    pub chip_select: Option<String>,

    /// SPI bus voltage.
    #[arg(long)]
    pub voltage: Option<Voltage>,

    /// SPI polarity/phase mode.
    #[arg(long)]
    pub mode: Option<TransferMode>,
}

impl SpiParams {
    pub fn create(
        &self,
        transport: &TransportWrapper,
        default_instance: &str,
    ) -> Result<Rc<dyn Target>> {
        let spi = transport.spi(self.bus.as_deref().unwrap_or(default_instance))?;
        if let Some(ref cs) = self.chip_select {
            spi.set_pins(
                None,
                None,
                None,
                Some(&transport.gpio_pin(cs.as_str())?),
                None,
            )?;
        }
        if let Some(speed) = self.speed {
            spi.set_max_speed(speed)?;
        }
        if let Some(voltage) = self.voltage {
            spi.set_voltage(voltage)?;
        }
        if let Some(mode) = self.mode {
            spi.set_transfer_mode(mode)?;
        }
        Ok(spi)
    }
}

/// Errors related to the SPI interface and SPI transactions.
#[derive(Error, Debug, Serialize, Deserialize)]
pub enum SpiError {
    #[error("Invalid option: {0}")]
    InvalidOption(String),
    #[error("Invalid word size: {0}")]
    InvalidWordSize(u32),
    #[error("Invalid speed: {0}")]
    InvalidSpeed(u32),
    #[error("Invalid data length: {0}")]
    InvalidDataLength(usize),
    #[error("Invalid data width: {0:?}")]
    InvalidDataWidth(eeprom::DataWidth),
    #[error("Double transfer rate not supported")]
    InvalidDoubleTransferRate(),
    #[error("Invalid number of dummy cycles: {0}")]
    InvalidDummyCycles(u8),
    #[error("Mismatched data length: {0} != {1}")]
    MismatchedDataLength(usize, usize),
    #[error("Invalid transfer mode: {0}")]
    InvalidTransferMode(String),
    #[error("Invalid SPI voltage: {0}")]
    InvalidVoltage(Voltage),
    #[error("Given pin does not support requested SPI function")]
    InvalidPin,
}
impl_serializable_error!(SpiError);

/// Represents the SPI transfer mode.
/// See <https://en.wikipedia.org/wiki/Serial_Peripheral_Interface#Clock_polarity_and_phase>
/// for details about SPI transfer modes.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize)]
pub enum TransferMode {
    /// `Mode0` is CPOL=0, CPHA=0.
    Mode0,
    /// `Mode1` is CPOL=0, CPHA=1.
    Mode1,
    /// `Mode2` is CPOL=1, CPHA=0.
    Mode2,
    /// `Mode3` is CPOL=1, CPHA=1.
    Mode3,
}

impl FromStr for TransferMode {
    type Err = SpiError;
    fn from_str(s: &str) -> std::result::Result<TransferMode, Self::Err> {
        match s {
            "Mode0" | "mode0" | "0" => Ok(TransferMode::Mode0),
            "Mode1" | "mode1" | "1" => Ok(TransferMode::Mode1),
            "Mode2" | "mode2" | "2" => Ok(TransferMode::Mode2),
            "Mode3" | "mode3" | "3" => Ok(TransferMode::Mode3),
            _ => Err(SpiError::InvalidTransferMode(s.to_string())),
        }
    }
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ClockPhase {
    SampleLeading,
    SampleTrailing,
}

#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub enum ClockPolarity {
    IdleLow,
    IdleHigh,
}

impl TransferMode {
    pub fn phase(&self) -> ClockPhase {
        match self {
            TransferMode::Mode0 | TransferMode::Mode2 => ClockPhase::SampleLeading,
            TransferMode::Mode1 | TransferMode::Mode3 => ClockPhase::SampleTrailing,
        }
    }
    pub fn polarity(&self) -> ClockPolarity {
        match self {
            TransferMode::Mode0 | TransferMode::Mode1 => ClockPolarity::IdleLow,
            TransferMode::Mode2 | TransferMode::Mode3 => ClockPolarity::IdleHigh,
        }
    }
}

/// Represents maximum allowed read or write operation in bytes.
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
pub struct MaxSizes {
    pub read: usize,
    pub write: usize,
}

/// Represents a SPI transfer.
pub enum Transfer<'rd, 'wr> {
    Read(&'rd mut [u8]),
    Write(&'wr [u8]),
    // Check supports_bidirectional_transfer before using this.
    Both(&'wr [u8], &'rd mut [u8]),
    // Repeatedly poll until device response with 0x01
    TpmPoll,
    // Wait for pulse on non-standard Google signal
    GscReady,
}

/// A trait which represents a SPI Target.
pub trait Target {
    /// Gets the current SPI transfer mode.
    fn get_transfer_mode(&self) -> Result<TransferMode>;
    /// Sets the current SPI transfer mode.
    fn set_transfer_mode(&self, mode: TransferMode) -> Result<()>;

    /// Gets the current number of bits per word.
    fn get_bits_per_word(&self) -> Result<u32>;
    /// Sets the current number of bits per word.
    fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()>;

    /// Gets the maximum allowed speed of the SPI bus.
    fn get_max_speed(&self) -> Result<u32>;
    /// Sets the maximum allowed speed of the SPI bus.
    fn set_max_speed(&self, max_speed: u32) -> Result<()>;

    /// Indicates whether `Transfer::Both()` is supported.
    fn supports_bidirectional_transfer(&self) -> Result<bool>;

    /// Indicates whether `Transfer::TpmPoll` is supported.
    fn supports_tpm_poll(&self) -> Result<bool>;

    /// Sets which pins should be used for SPI communication.  `None` value means use the same pin
    /// as previously, or the implementation default if never before specified.  This call is not
    /// supported by most backend transports, and ones that do support it may still have
    /// restrictions on which set of pins can be used in which roles.
    fn set_pins(
        &self,
        _serial_clock: Option<&Rc<dyn gpio::GpioPin>>,
        _host_out_device_in: Option<&Rc<dyn gpio::GpioPin>>,
        _host_in_device_out: Option<&Rc<dyn gpio::GpioPin>>,
        _chip_select: Option<&Rc<dyn gpio::GpioPin>>,
        _gsc_ready: Option<&Rc<dyn gpio::GpioPin>>,
    ) -> Result<()> {
        Err(SpiError::InvalidPin.into())
    }

    /// Returns the maximum number of transfers allowed in a single transaction.
    fn get_max_transfer_count(&self) -> Result<usize>;

    /// Maximum `Read` and `Write` data size for `run_transaction()`.
    fn get_max_transfer_sizes(&self) -> Result<MaxSizes>;

    fn set_voltage(&self, _voltage: Voltage) -> Result<()> {
        Err(SpiError::InvalidOption("This target does not support set_voltage".to_string()).into())
    }

    /// Returns `"raiden_debug_spi:serial=XXX"` or similar string usable for passing via `-p`
    /// argument to `flashrom`, in order for it to connect to this SPI port instance.
    fn get_flashrom_programmer(&self) -> Result<String> {
        Err(TransportError::UnsupportedOperation.into())
    }

    /// Runs a SPI transaction composed from the slice of [`Transfer`] objects.  Will assert the
    /// CS for the duration of the entire transactions.
    fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()>;

    /// Maximum payload size of `Read` and `Write` elements for `run_eeprom_transactions()`.
    fn get_eeprom_max_transfer_sizes(&self) -> Result<MaxSizes> {
        // By default, go by the low-level SPI limits, allowing for 6 bytes of opcode+address+dummy
        let spi_max = self.get_max_transfer_sizes()?;
        Ok(MaxSizes {
            read: spi_max.read,
            write: spi_max.write - 6,
        })
    }

    /// Runs a number of EEPROM/FLASH protocol SPI transactions.  Will assert and deassert CS for
    /// each transaction.
    fn run_eeprom_transactions(&self, transactions: &mut [eeprom::Transaction]) -> Result<()> {
        eeprom::default_run_eeprom_transactions(self, transactions)
    }

    /// Assert the CS signal.  Uses reference counting, will be deasserted when each and every
    /// returned `AssertChipSelect` object have gone out of scope.
    fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect>;
}

/// Object that keeps the CS asserted, deasserting when it goes out of scope, (unless another
/// instance keeps CS asserted longer.)
pub struct AssertChipSelect {
    target: Rc<dyn TargetChipDeassert>,
}

impl AssertChipSelect {
    // Needs to be public in order for implementation of `Target` to be able to call it.  Never
    // called by users of `Target`.
    pub fn new(target: Rc<dyn TargetChipDeassert>) -> Self {
        Self { target }
    }
}

impl Drop for AssertChipSelect {
    fn drop(&mut self) {
        self.target.deassert_cs()
    }
}

// Needs to be public in order for implementation of `Target` to be able to implement it.  Never
// called by users of `Target`.
pub trait TargetChipDeassert {
    fn deassert_cs(&self);
}