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);
}