Skip to content

Commit

Permalink
Add cosmo hf mux control; minor cleanup (#1884)
Browse files Browse the repository at this point in the history
- Implements (virtual) mux control for `cosmo-hf`
- Adds checks on reads and writes that the flash is muxed to the SP
- Moves some magic numbers into named constants in the `regs` module
  • Loading branch information
mkeeter authored Oct 2, 2024
1 parent 2675b6d commit ab8604a
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 7 deletions.
28 changes: 24 additions & 4 deletions drv/cosmo-hf/src/hf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,20 @@ pub struct ServerImpl {
impl ServerImpl {
/// Construct a new `ServerImpl`, with side effects
///
/// The SP / host virtual mux is configured to select the SP.
///
/// Persistent data is loaded from the flash chip and used to select `dev`;
/// in addition, it is made reduntant (written to both virtual devices).
/// in addition, it is made redundant (written to both virtual devices).
pub fn new(drv: FlashDriver) -> Self {
let mut out = Self {
dev: drv_hf_api::HfDevSelect::Flash0,
drv,
};
out.drv.set_flash_mux_state(HfMuxState::SP);
out.ensure_persistent_data_is_redundant();
if let Ok(p) = out.get_persistent_data() {
out.dev = p.dev_select;
out.drv.set_espi_addr_offset(out.flash_base());
}
out
}
Expand Down Expand Up @@ -128,6 +132,8 @@ impl ServerImpl {
fn get_raw_persistent_data(
&mut self,
) -> Result<HfRawPersistentData, HfError> {
self.drv.check_flash_mux_state()?;

// Read the two slots
let (data0, _) = self.persistent_data_scan(HfDevSelect::Flash0);
let (data1, _) = self.persistent_data_scan(HfDevSelect::Flash1);
Expand Down Expand Up @@ -162,6 +168,10 @@ impl ServerImpl {

/// Ensures that the persistent data is consistent between the virtual devs
fn ensure_persistent_data_is_redundant(&mut self) {
// This should only be called on startup, at which point we're always
// muxed to the SP.
self.drv.check_flash_mux_state().unwrap_lite();

// Load the current state of persistent data from flash
let (data0, next0) = self.persistent_data_scan(HfDevSelect::Flash0);
let (data1, next1) = self.persistent_data_scan(HfDevSelect::Flash1);
Expand Down Expand Up @@ -196,6 +206,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
&mut self,
_: &RecvMessage,
) -> Result<[u8; 20], RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
Ok(self.drv.flash_read_id())
}

Expand All @@ -211,6 +222,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
&mut self,
_: &RecvMessage,
) -> Result<u8, RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
Ok(self.drv.read_flash_status())
}

Expand All @@ -223,6 +235,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
if !matches!(protect, HfProtectMode::AllowModificationsToSector0) {
return Err(HfError::Sector0IsReserved.into());
}
self.drv.check_flash_mux_state()?;
// Don't use the bulk erase command, because it will erase the entire
// chip. Instead, use the sector erase to erase the currently-active
// virtual device.
Expand All @@ -241,6 +254,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
data: LenLimit<Leased<R, [u8]>, PAGE_SIZE_BYTES>,
) -> Result<(), RequestError<HfError>> {
self.check_addr_writable(addr, protect)?;
self.drv.check_flash_mux_state()?;
self.drv
.flash_write(
self.flash_addr(addr),
Expand All @@ -256,6 +270,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
addr: u32,
dest: LenLimit<Leased<W, [u8]>, PAGE_SIZE_BYTES>,
) -> Result<(), RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
self.drv
.flash_read(
self.flash_addr(addr),
Expand All @@ -276,6 +291,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
addr: u32,
protect: HfProtectMode,
) -> Result<(), RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
self.check_addr_writable(addr, protect)?;
self.drv.flash_sector_erase(self.flash_addr(addr));
Ok(())
Expand All @@ -285,15 +301,16 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
&mut self,
_: &RecvMessage,
) -> Result<HfMuxState, RequestError<HfError>> {
todo!()
Ok(self.drv.get_flash_mux_state())
}

fn set_mux(
&mut self,
_: &RecvMessage,
_state: HfMuxState,
state: HfMuxState,
) -> Result<(), RequestError<HfError>> {
todo!()
self.drv.set_flash_mux_state(state);
Ok(())
}

fn get_dev(
Expand All @@ -308,6 +325,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
_: &RecvMessage,
dev: HfDevSelect,
) -> Result<(), RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
self.dev = dev;
self.drv.set_espi_addr_offset(self.flash_base());
Ok(())
Expand All @@ -320,6 +338,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
addr: u32,
len: u32,
) -> Result<[u8; SHA256_SZ], RequestError<HfError>> {
self.drv.check_flash_mux_state()?;
let hash_driver = drv_hash_api::Hash::from(HASH.get_task_id());
if let Err(e) = hash_driver.init_sha256() {
ringbuf_entry!(Trace::HashInitError(e));
Expand Down Expand Up @@ -368,6 +387,7 @@ impl idl::InOrderHostFlashImpl for ServerImpl {
dev_select: HfDevSelect,
) -> Result<(), RequestError<HfError>> {
let data = HfPersistentData { dev_select };
self.drv.check_flash_mux_state()?;

// Scan both slots for persistent data
let (data0, next0) = self.persistent_data_scan(HfDevSelect::Flash0);
Expand Down
46 changes: 43 additions & 3 deletions drv/cosmo-hf/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,15 @@ mod reg {

pub const NOR: *mut u32 = BASE.wrapping_add(0x40);
pub const SPICR: *mut u32 = NOR.wrapping_add(0x0);
pub mod spisr {
pub const RX_EMPTY_BIT: u32 = 1 << 6;
}
pub const SPISR: *mut u32 = NOR.wrapping_add(0x1);
pub mod spicr {
pub const SP5_OWNS_FLASH: u32 = 1 << 31;
pub const RX_FIFO_RESET: u32 = 1 << 15;
pub const TX_FIFO_RESET: u32 = 1 << 7;
}
pub const ADDR: *mut u32 = NOR.wrapping_add(0x2);
pub const DUMMY_CYCLES: *mut u32 = NOR.wrapping_add(0x3);
pub const DATA_BYTES: *mut u32 = NOR.wrapping_add(0x4);
Expand Down Expand Up @@ -149,6 +157,11 @@ impl FlashDriver {
unsafe { reg.write_volatile(v) };
}

fn modify_reg<F: Fn(u32) -> u32>(&self, reg: *mut u32, f: F) {
let prev = self.read_reg(reg);
self.write_reg(reg, f(prev));
}

/// Wait until the FPGA is idle
fn wait_fpga_busy(&self) {
loop {
Expand All @@ -165,8 +178,7 @@ impl FlashDriver {
fn wait_fpga_rx(&self) {
for i in 0.. {
let spi_sr = self.read_reg(reg::SPISR);
const RX_EMPTY_BIT: u32 = 1 << 6;
if spi_sr & RX_EMPTY_BIT == 0 {
if spi_sr & reg::spisr::RX_EMPTY_BIT == 0 {
break;
}
ringbuf_entry!(Trace::FpgaBusy { spi_sr });
Expand All @@ -179,7 +191,9 @@ impl FlashDriver {

/// Clears the FPGA's internal FIFOs
fn clear_fifos(&self) {
self.write_reg(reg::SPICR, 0x8080);
self.modify_reg(reg::SPICR, |v| {
v | reg::spicr::RX_FIFO_RESET | reg::spicr::TX_FIFO_RESET
});
}

/// Wait until the SPI flash is idle
Expand Down Expand Up @@ -327,6 +341,32 @@ impl FlashDriver {
self.wait_fpga_busy();
}

fn get_flash_mux_state(&self) -> drv_hf_api::HfMuxState {
let v = self.read_reg(reg::SPICR);
if v & reg::spicr::SP5_OWNS_FLASH != 0 {
drv_hf_api::HfMuxState::HostCPU
} else {
drv_hf_api::HfMuxState::SP
}
}

/// Returns an error if the flash mux state is not `HfMuxState::SP`
fn check_flash_mux_state(&self) -> Result<(), drv_hf_api::HfError> {
match self.get_flash_mux_state() {
drv_hf_api::HfMuxState::SP => Ok(()),
drv_hf_api::HfMuxState::HostCPU => {
Err(drv_hf_api::HfError::NotMuxedToSP)
}
}
}

fn set_flash_mux_state(&self, ms: drv_hf_api::HfMuxState) {
self.modify_reg(reg::SPICR, |v| match ms {
drv_hf_api::HfMuxState::SP => v & !reg::spicr::SP5_OWNS_FLASH,
drv_hf_api::HfMuxState::HostCPU => v | reg::spicr::SP5_OWNS_FLASH,
});
}

fn set_espi_addr_offset(&self, v: u32) {
self.write_reg(reg::SP5_FLASH_OFFSET, v);
}
Expand Down

0 comments on commit ab8604a

Please sign in to comment.