opentitanlib/console/
spi.rs1use anyhow::Result;
6use std::cell::{Cell, RefCell};
7use std::collections::VecDeque;
8use std::rc::Rc;
9use std::time::Duration;
10
11use crate::io::console::ConsoleDevice;
12use crate::io::gpio::GpioPin;
13use crate::io::spi::Target;
14use crate::spiflash::flash::SpiFlash;
15
16pub struct SpiConsoleDevice<'a> {
17 spi: &'a dyn Target,
18 flash: SpiFlash,
19 console_next_frame_number: Cell<u32>,
20 rx_buf: RefCell<VecDeque<u8>>,
21 next_read_address: Cell<u32>,
22 device_tx_ready_pin: Option<&'a Rc<dyn GpioPin>>,
23 ignore_frame_num: bool,
24}
25
26impl<'a> SpiConsoleDevice<'a> {
27 const SPI_FRAME_HEADER_SIZE: usize = 12;
28 const SPI_FLASH_READ_BUFFER_SIZE: u32 = 2048;
29 const SPI_MAX_DATA_LENGTH: usize = 2036;
30 const SPI_FRAME_MAGIC_NUMBER: u32 = 0xa5a5beef;
31 const SPI_FLASH_PAYLOAD_BUFFER_SIZE: usize = 256;
32 const SPI_TX_LAST_CHUNK_MAGIC_ADDRESS: u32 = 0x100;
33 const SPI_BOOT_MAGIC_PATTERN: u32 = 0xcafeb002;
34
35 pub fn new(
36 spi: &'a dyn Target,
37 device_tx_ready_pin: Option<&'a Rc<dyn GpioPin>>,
38 ignore_frame_num: bool,
39 ) -> Result<Self> {
40 let flash = SpiFlash {
41 ..Default::default()
42 };
43 Ok(Self {
44 spi,
45 flash,
46 rx_buf: RefCell::new(VecDeque::new()),
47 console_next_frame_number: Cell::new(0),
48 next_read_address: Cell::new(0),
49 device_tx_ready_pin,
50 ignore_frame_num,
51 })
52 }
53
54 pub fn reset_frame_counter(&self) {
55 self.console_next_frame_number.set(0);
56 self.next_read_address.set(0);
57 }
58
59 fn check_device_boot_up(&self, buf: &[u8]) -> Result<usize> {
60 for i in (0..buf.len()).step_by(4) {
61 let pattern: u32 = u32::from_le_bytes(buf[i..i + 4].try_into().unwrap());
62 if pattern != SpiConsoleDevice::SPI_BOOT_MAGIC_PATTERN {
63 return Ok(0);
64 }
65 }
66 self.flash.program(self.spi, 0, buf)?;
68 self.reset_frame_counter();
69 Ok(0)
70 }
71
72 fn read_from_spi(&self) -> Result<usize> {
73 let read_address = self.next_read_address.get();
75 let mut header = vec![0u8; SpiConsoleDevice::SPI_FRAME_HEADER_SIZE];
76 self.read_data(read_address, &mut header)?;
77
78 let magic_number: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
79 let frame_number: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
80 let data_len_bytes: usize = u32::from_le_bytes(header[8..12].try_into().unwrap()) as usize;
81 if magic_number != SpiConsoleDevice::SPI_FRAME_MAGIC_NUMBER
82 || (!self.ignore_frame_num && frame_number != self.console_next_frame_number.get())
83 || data_len_bytes > SpiConsoleDevice::SPI_MAX_DATA_LENGTH
84 {
85 if self.device_tx_ready_pin.is_none() {
86 self.check_device_boot_up(&header)?;
87 }
88 return Ok(0);
90 }
91 self.console_next_frame_number.set(frame_number + 1);
92
93 let data_len_bytes_w_pad = (data_len_bytes + 3) & !3;
95 let mut data = vec![0u8; data_len_bytes_w_pad];
96 let data_address: u32 = (read_address
97 + u32::try_from(SpiConsoleDevice::SPI_FRAME_HEADER_SIZE).unwrap())
98 % SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE;
99 self.read_data(data_address, &mut data)?;
100
101 if self.device_tx_ready_pin.is_some() {
102 self.next_read_address.set(0);
106 } else {
107 let next_read_address: u32 = (read_address
108 + u32::try_from(SpiConsoleDevice::SPI_FRAME_HEADER_SIZE + data_len_bytes_w_pad)
109 .unwrap())
110 % SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE;
111 self.next_read_address.set(next_read_address);
112 }
113
114 self.rx_buf.borrow_mut().extend(&data[..data_len_bytes]);
116 Ok(data_len_bytes)
117 }
118
119 fn read_data(&self, address: u32, buf: &mut [u8]) -> Result<&Self> {
120 let buf_len: usize = buf.len();
121 let space_to_end_of_buffer: usize =
122 usize::try_from(SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE - address).unwrap();
123 let first_part_size: usize = if buf_len > space_to_end_of_buffer {
124 space_to_end_of_buffer
125 } else {
126 buf_len
127 };
128 self.flash
129 .read(self.spi, address, &mut buf[0..first_part_size])?;
130 if first_part_size < buf_len {
132 self.flash
133 .read(self.spi, 0, &mut buf[first_part_size..buf_len])?;
134 }
135 Ok(self)
136 }
137}
138
139impl<'a> ConsoleDevice for SpiConsoleDevice<'a> {
140 fn poll_read(
141 &self,
142 cx: &mut std::task::Context<'_>,
143 buf: &mut [u8],
144 ) -> std::task::Poll<Result<usize>> {
145 const POLL_INTERVAL: Duration = Duration::from_millis(1);
149
150 if self.rx_buf.borrow().is_empty() {
151 if let Some(ready_pin) = self.device_tx_ready_pin {
152 if !ready_pin.read()? {
155 return crate::util::runtime::poll_later(cx, POLL_INTERVAL);
156 }
157 }
158
159 if self.read_from_spi()? == 0 {
160 return crate::util::runtime::poll_later(cx, POLL_INTERVAL);
161 }
162 }
163
164 let mut i: usize = 0;
166 while !self.rx_buf.borrow().is_empty() && i < buf.len() {
167 buf[i] = self.rx_buf.borrow_mut().pop_front().unwrap();
168 i += 1;
169 }
170
171 std::task::Poll::Ready(Ok(i))
172 }
173
174 fn write(&self, buf: &[u8]) -> Result<()> {
175 let buf_len: usize = buf.len();
176 let mut written_data_len: usize = 0;
177 while written_data_len < buf_len {
178 let mut write_address = SpiConsoleDevice::SPI_TX_LAST_CHUNK_MAGIC_ADDRESS;
179 let mut data_len: usize = buf_len - written_data_len;
180
181 if data_len > SpiConsoleDevice::SPI_FLASH_PAYLOAD_BUFFER_SIZE {
182 data_len = SpiConsoleDevice::SPI_FLASH_PAYLOAD_BUFFER_SIZE;
183 write_address = 0;
184 }
185
186 self.flash.program(
187 self.spi,
188 write_address,
189 &buf[written_data_len..written_data_len + data_len],
190 )?;
191 written_data_len += data_len;
192 }
193
194 Ok(())
195 }
196}