opentitanlib/transport/chip_whisperer/
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 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    // Perform a SPI transaction.
31    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        // FIXME: what is the speed of the SAM3U SPI interface on the Chip Whisperer board?
69        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                // Explicitly choosing pins for some of the SPI signals, while leaving others at
117                // their default, is not supported.
118                Err(TransportError::UnsupportedOperation.into())
119            }
120        }
121    }
122
123    fn get_max_transfer_count(&self) -> Result<usize> {
124        // Arbitrary value: number of `Transfers` that can be in a single transaction.
125        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        // Assert CS# (drive low).
137        self.device.borrow().spi1_set_cs_pin(false)?;
138        // Translate SPI Read/Write Transactions into Chip Whisperer spi operations.
139        let result = self.spi_transaction(transaction);
140        // Release CS# (allow to float high).
141        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}