opentitanlib/transport/ftdi/
spi.rs

1// Copyright lowRISC contributors (OpenTitan project).
2// Licensed under the Apache License, Version 2.0, see LICENSE for details.
3// SPDX-License-Identifier: Apache-2.0
4
5use crate::io::spi::Transfer;
6use anyhow::Result;
7use std::cell::RefCell;
8use std::collections::HashMap;
9use std::rc::Rc;
10
11use embedded_hal::spi::SpiBus;
12
13use ftdi_embedded_hal as ftdi_hal;
14
15use crate::io::gpio;
16use crate::io::spi::AssertChipSelect;
17use crate::io::spi::MaxSizes;
18use crate::io::spi::SpiError;
19use crate::io::spi::TransferMode;
20use crate::transport::Target;
21use crate::transport::TransportError;
22
23pub struct Spi<T> {
24    spi: Rc<RefCell<ftdi_hal::Spi<ftdi::Device>>>,
25    cs: T,
26}
27
28impl<T: gpio::GpioPin> Spi<T> {
29    pub fn open(
30        ftdi_interfaces: &Rc<HashMap<ftdi::Interface, ftdi_hal::FtHal<ftdi::Device>>>,
31        cs: T,
32    ) -> Result<Self> {
33        let hal = ftdi_interfaces
34            .get(&ftdi::Interface::B)
35            .ok_or_else(|| SpiError::InvalidOption("spi interface".to_owned()))?;
36        let spi = hal.spi()?;
37        Ok(Spi {
38            spi: Rc::new(RefCell::new(spi)),
39            cs,
40        })
41    }
42
43    // Perform a SPI transaction.
44    fn spi_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
45        for transfer in transaction.iter_mut() {
46            match transfer {
47                Transfer::Read(buf) => self.spi.borrow_mut().read(buf)?,
48                Transfer::Write(buf) => self.spi.borrow_mut().write(buf)?,
49                Transfer::Both(wbuf, rbuf) => self.spi.borrow_mut().transfer(rbuf, wbuf)?,
50                Transfer::TpmPoll => (),
51                Transfer::GscReady => (),
52            }
53        }
54        Ok(())
55    }
56}
57
58impl<T: gpio::GpioPin> Target for Spi<T> {
59    fn get_transfer_mode(&self) -> Result<TransferMode> {
60        Ok(TransferMode::Mode0)
61    }
62    fn set_transfer_mode(&self, mode: TransferMode) -> Result<()> {
63        log::warn!(
64            "set_transfer_mode to {:?}, but only Mode0 is supported on this device",
65            mode
66        );
67        Ok(())
68    }
69
70    fn get_bits_per_word(&self) -> Result<u32> {
71        Ok(8)
72    }
73    fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
74        match bits_per_word {
75            8 => Ok(()),
76            _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
77        }
78    }
79
80    fn get_max_speed(&self) -> Result<u32> {
81        Ok(6_000_000)
82    }
83    fn set_max_speed(&self, frequency: u32) -> Result<()> {
84        log::warn!(
85            "set_max_speed to {:?}, but this device doesn't support changing speeds.",
86            frequency
87        );
88        Ok(())
89    }
90
91    fn supports_bidirectional_transfer(&self) -> Result<bool> {
92        Ok(true)
93    }
94
95    /// Indicates whether `Transfer::TpmPoll` is supported.
96    fn supports_tpm_poll(&self) -> Result<bool> {
97        Ok(false)
98    }
99
100    fn set_pins(
101        &self,
102        _serial_clock: Option<&Rc<dyn gpio::GpioPin>>,
103        _host_out_device_in: Option<&Rc<dyn gpio::GpioPin>>,
104        _host_in_device_out: Option<&Rc<dyn gpio::GpioPin>>,
105        _chip_select: Option<&Rc<dyn gpio::GpioPin>>,
106        _gsc_ready: Option<&Rc<dyn gpio::GpioPin>>,
107    ) -> Result<()> {
108        Err(TransportError::UnsupportedOperation.into())
109    }
110
111    fn get_max_transfer_count(&self) -> Result<usize> {
112        // Arbitrary value: number of `Transfers` that can be in a single transaction.
113        Ok(42)
114    }
115
116    fn get_max_transfer_sizes(&self) -> Result<MaxSizes> {
117        Ok(MaxSizes {
118            read: 1024,
119            write: 1024,
120        })
121    }
122
123    fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
124        // Assert CS# (drive low).
125        self.cs.write(false)?;
126        // Translate SPI Read/Write Transactions into Chip Whisperer spi operations.
127        let result = self.spi_transaction(transaction);
128        // Release CS# (allow to float high).
129        self.cs.write(true)?;
130        result
131    }
132
133    fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
134        Err(TransportError::UnsupportedOperation.into())
135    }
136}