matcha/tock: add nexus spi flash support Change-Id: I1d1ba5c7f85e1357b3adaab6721d181eac3c06d7
diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index 1b59b4a..4051ccb 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs
@@ -5,3 +5,4 @@ pub mod elfloader_capsule; pub mod mailbox_capsule; pub mod storage_capsule; +pub mod nexus_spiflash;
diff --git a/capsules/src/nexus_spiflash.rs b/capsules/src/nexus_spiflash.rs new file mode 100644 index 0000000..92edacf --- /dev/null +++ b/capsules/src/nexus_spiflash.rs
@@ -0,0 +1,186 @@ +use core::cell::Cell; +use core::ops::{Index, IndexMut}; +use kernel::common::cells::{OptionalCell, TakeCell}; +use kernel::hil; + +pub static mut TXBUFFER: [u8; PAGE_SIZE + 5] = [0; PAGE_SIZE + 5]; +pub static mut RXBUFFER: [u8; PAGE_SIZE + 5] = [0; PAGE_SIZE + 5]; +const PAGE_SIZE: usize = 512; + +pub struct NexusSpiflashPage(pub [u8; PAGE_SIZE]); + +impl Default for NexusSpiflashPage { + fn default() -> Self { + Self { 0: [0; PAGE_SIZE] } + } +} + +impl Index<usize> for NexusSpiflashPage { + type Output = u8; + fn index(&self, idx: usize) -> &u8 { + &self.0[idx] + } +} + +impl IndexMut<usize> for NexusSpiflashPage { + fn index_mut(&mut self, idx: usize) -> &mut u8 { + &mut self.0[idx] + } +} + +impl AsMut<[u8]> for NexusSpiflashPage { + fn as_mut(&mut self) -> &mut [u8] { + &mut self.0 + } +} + +enum Opcodes { + Read = 0x03, +} + +#[derive(Clone, Copy, PartialEq)] +enum State { + Idle, + WriteOpcode, + ReadPage { offset: usize }, +} + +pub struct NexusSpiflash<'a, S: hil::spi::SpiMasterDevice + 'a> { + spi: &'a S, + state: Cell<State>, + txbuffer: TakeCell<'static, [u8]>, + rxbuffer: TakeCell<'static, [u8]>, + client: OptionalCell<&'a dyn hil::flash::Client<NexusSpiflash<'a, S>>>, + client_page: TakeCell<'static, NexusSpiflashPage>, +} + +impl<'a, S: hil::spi::SpiMasterDevice + 'a> NexusSpiflash<'a, S> { + pub fn new( + spi: &'a S, + txbuffer: &'static mut [u8], + rxbuffer: &'static mut [u8], + ) -> NexusSpiflash<'a, S> { + NexusSpiflash { + spi: spi, + state: Cell::new(State::Idle), + txbuffer: TakeCell::new(txbuffer), + rxbuffer: TakeCell::new(rxbuffer), + client: OptionalCell::empty(), + client_page: TakeCell::empty(), + } + } +} + +impl<'a, S: hil::spi::SpiMasterDevice + 'a, C: hil::flash::Client<Self>> + hil::flash::HasClient<'a, C> for NexusSpiflash<'a, S> +{ + fn set_client(&'a self, client: &'a C) { + self.client.set(client); + } +} + +impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::flash::Flash for NexusSpiflash<'a, S> { + type Page = NexusSpiflashPage; + fn read_page( + &self, + page: usize, + read_buffer: &'static mut <Self as kernel::hil::flash::Flash>::Page, + ) -> core::result::Result< + (), + ( + kernel::ReturnCode, + &'static mut <Self as kernel::hil::flash::Flash>::Page, + ), + > { + self.txbuffer.take().map(|txbuffer| { + self.rxbuffer.take().map(move |rxbuffer| { + txbuffer[0] = Opcodes::Read as u8; + // TODO(atv): See if we can make 4-byte addressing work. Otherwise limited to 2**24 bytes. + let byte = page * PAGE_SIZE; + txbuffer[1] = ((byte >> 16) & 0xFF) as u8; + txbuffer[2] = ((byte >> 08) & 0xFF) as u8; + txbuffer[3] = ((byte >> 00) & 0xFF) as u8; + self.state.set(State::WriteOpcode); + self.spi.hold_low(); + self.spi + .read_write_bytes(txbuffer, Some(rxbuffer), 4 as usize); + }); + }); + self.client_page.replace(read_buffer); + Ok(()) + } + fn write_page( + &self, + _: usize, + _: &'static mut <Self as kernel::hil::flash::Flash>::Page, + ) -> core::result::Result< + (), + ( + kernel::ReturnCode, + &'static mut <Self as kernel::hil::flash::Flash>::Page, + ), + > { + todo!() + } + fn erase_page(&self, _: usize) -> kernel::ReturnCode { + todo!() + } +} + +impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::time::AlarmClient for NexusSpiflash<'a, S> { + fn alarm(&self) { + todo!() + } +} + +impl<'a, S: hil::spi::SpiMasterDevice + 'a> hil::spi::SpiMasterClient for NexusSpiflash<'a, S> { + fn read_write_done( + &self, + write_buffer: &'static mut [u8], + read_buffer: core::option::Option<&'static mut [u8]>, + _len: usize, + ) { + match self.state.get() { + State::WriteOpcode => { + read_buffer.map(move |read_buffer| { + self.state.set(State::ReadPage { offset: 0 }); + self.spi + .read_write_bytes(write_buffer, Some(read_buffer), PAGE_SIZE / 2); + }); + } + State::ReadPage { offset } => { + read_buffer.map(move |read_buffer| { + self.client_page.map(|page| { + for i in 0..(PAGE_SIZE / 2) { + page[i + offset] = read_buffer[i]; + } + }); + let next_offset = offset + (PAGE_SIZE / 2); + if next_offset == PAGE_SIZE { + self.state.set(State::Idle); + self.client_page.take().map(|page| { + self.client.map(move |client| { + self.txbuffer.replace(read_buffer); + self.rxbuffer.replace(write_buffer); + client.read_complete(page, hil::flash::Error::CommandComplete); + }); + }); + } else { + self.state.set(State::ReadPage { + offset: next_offset, + }); + // release_low will cause our SPI host to release CS after the read/write. + if next_offset + (PAGE_SIZE / 2) == PAGE_SIZE { + self.spi.release_low(); + } + self.spi + .read_write_bytes(write_buffer, Some(read_buffer), PAGE_SIZE / 2); + } + }); + } + State::Idle => { + panic!(); + } + } + } +}
diff --git a/config/src/lib.rs b/config/src/lib.rs index f365b17..aa777b3 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs
@@ -18,6 +18,7 @@ pub const CAPSULE_STORAGE: usize = 0x50003; pub const CAPSULE_ELFLOADER: usize = 0x50004; pub const CAPSULE_MAILBOX: usize = 0x50005; +pub const CAPSULE_SPIFLASH: usize = 0x50006; pub const CMD_MAILBOX_INIT: usize = 1; pub const CMD_MAILBOX_SEND: usize = 2;
diff --git a/platform/src/chip.rs b/platform/src/chip.rs index 86a216d..444fd95 100644 --- a/platform/src/chip.rs +++ b/platform/src/chip.rs
@@ -3,7 +3,6 @@ use core::fmt::Write; use core::hint::unreachable_unchecked; use kernel; -use kernel::debug; use kernel::hil::time::Alarm; use rv32i::csr::{mcause, mie::mie, mip::mip, mtvec::mtvec, CSR}; use rv32i::syscall::SysCall; @@ -13,6 +12,7 @@ use matcha_hal::mailbox_hal; use matcha_hal::plic_hal; use matcha_hal::timer_hal; +use matcha_hal::spi_host_hal; use matcha_hal::uart_hal; PMPConfigMacro!(4); @@ -59,7 +59,10 @@ MAILBOX_EIRQ => { self.mailbox_isr.get().map(|mb| mb.on_eirq()); } - _ => debug!("Pidx {}", interrupt), + SPI_HOST0_SPI_EVENT_IRQ => { + spi_host_hal::SPI_HOST0.handle_interrupt() + } + _ => panic!("Pidx {}", interrupt), } plic_hal::complete(interrupt); }