Skip to content

Commit

Permalink
[opentitanlib] support SPI console in flash mode
Browse files Browse the repository at this point in the history
This updates the console module to use SPI device flash mode feature to
support SPI device console. It's currently a one way console.

Signed-off-by: Anthony Chen <[email protected]>
  • Loading branch information
anthonychen1251 committed Aug 16, 2024
1 parent d0462e1 commit a929411
Showing 1 changed file with 70 additions and 13 deletions.
83 changes: 70 additions & 13 deletions sw/host/opentitanlib/src/console/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,34 +8,66 @@ use std::collections::VecDeque;
use std::time::Duration;

use crate::io::console::ConsoleDevice;
use crate::io::spi::{Target, Transfer};
use crate::io::eeprom::AddressMode;
use crate::io::spi::Target;
use crate::spiflash::flash::SpiFlash;

pub struct SpiConsoleDevice<'a> {
spi: &'a dyn Target,
flash: SpiFlash,
console_next_frame_number: Cell<u32>,
rx_buf: RefCell<VecDeque<u8>>,
next_read_address: Cell<u32>,
}

impl<'a> SpiConsoleDevice<'a> {
const SPI_FRAME_HEADER_SIZE: usize = 8;
const SPI_MAX_DATA_LENGTH: usize = 2032;
const SPI_FRAME_HEADER_SIZE: usize = 12;
const SPI_FLASH_READ_BUFFER_SIZE: u32 = 2048;
const SPI_MAX_DATA_LENGTH: usize = 2036;
const SPI_FRAME_MAGIC_NUMBER: u32 = 0xa5a5beef;

pub fn new(spi: &'a dyn Target) -> Self {
Self {
pub fn new(spi: &'a dyn Target) -> Result<Self> {
let mut flash = SpiFlash {
..Default::default()
};
flash.set_address_mode(&*spi, AddressMode::Mode3b)?;
Ok(Self {
spi,
flash,
rx_buf: RefCell::new(VecDeque::new()),
console_next_frame_number: Cell::new(0),
}
next_read_address: Cell::new(0),
})
}

fn read_from_spi(&self) -> Result<usize> {
// Read the SPI console frame header.
let read_address = self.next_read_address.get();
let mut header = vec![0u8; SpiConsoleDevice::SPI_FRAME_HEADER_SIZE];
self.spi
.run_transaction(&mut [Transfer::Write(&[0xff; 4]), Transfer::Read(&mut header)])?;
let frame_number: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
let data_len_bytes: usize = u32::from_le_bytes(header[4..8].try_into().unwrap()) as usize;
if frame_number != self.console_next_frame_number.get()

// Handle wrap-around
if (SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE - read_address)
< u32::try_from(SpiConsoleDevice::SPI_FRAME_HEADER_SIZE).unwrap()
{
let first_part_size: usize =
usize::try_from(SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE - read_address)
.unwrap();
self.flash
.read(&*self.spi, read_address, &mut header[0..first_part_size])?;
self.flash.read(
&*self.spi,
0,
&mut header[first_part_size..SpiConsoleDevice::SPI_FRAME_HEADER_SIZE],
)?;
} else {
self.flash.read(&*self.spi, read_address, &mut header)?;
}

let magic_number: u32 = u32::from_le_bytes(header[0..4].try_into().unwrap());
let frame_number: u32 = u32::from_le_bytes(header[4..8].try_into().unwrap());
let data_len_bytes: usize = u32::from_le_bytes(header[8..12].try_into().unwrap()) as usize;
if magic_number != SpiConsoleDevice::SPI_FRAME_MAGIC_NUMBER
|| frame_number != self.console_next_frame_number.get()
|| data_len_bytes > SpiConsoleDevice::SPI_MAX_DATA_LENGTH
{
// This frame is junk, so we do not read the data.
Expand All @@ -46,8 +78,33 @@ impl<'a> SpiConsoleDevice<'a> {
// Read the SPI console frame data.
let data_len_bytes_w_pad = (data_len_bytes + 3) & !3;
let mut data = vec![0u8; data_len_bytes_w_pad];
self.spi
.run_transaction(&mut [Transfer::Write(&[0xff; 4]), Transfer::Read(&mut data)])?;
let data_address: u32 = (read_address
+ u32::try_from(SpiConsoleDevice::SPI_FRAME_HEADER_SIZE).unwrap())
% SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE;

// Handle wrap-around
if (SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE - data_address)
< u32::try_from(data_len_bytes_w_pad).unwrap()
{
let first_part_size: usize =
usize::try_from(SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE - data_address)
.unwrap();
self.flash
.read(&*self.spi, data_address, &mut data[0..first_part_size])?;
self.flash.read(
&*self.spi,
0,
&mut data[first_part_size..data_len_bytes_w_pad],
)?;
} else {
self.flash.read(&*self.spi, data_address, &mut data)?;
}

let next_read_address: u32 = (read_address
+ u32::try_from(SpiConsoleDevice::SPI_FRAME_HEADER_SIZE + data_len_bytes_w_pad)
.unwrap())
% SpiConsoleDevice::SPI_FLASH_READ_BUFFER_SIZE;
self.next_read_address.set(next_read_address);

// Copy data to the internal data queue.
self.rx_buf.borrow_mut().extend(&data[..data_len_bytes]);
Expand Down

0 comments on commit a929411

Please sign in to comment.