Skip to content

Commit

Permalink
Merge pull request #595 from betrusted-io/usb-integrate
Browse files Browse the repository at this point in the history
Usb integrate
  • Loading branch information
bunnie authored Nov 21, 2024
2 parents 5279e50 + ec3d8b5 commit c1564d2
Show file tree
Hide file tree
Showing 27 changed files with 2,267 additions and 98 deletions.
136 changes: 92 additions & 44 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,8 @@ path = "services/aes"

[patch.crates-io.curve25519-dalek]
git = "https://github.com/betrusted-io/curve25519-dalek.git"
branch = "main"

branch = "main" # c25519
# path = "../curve25519-dalek/curve25519-dalek" # when doing local dev work
# feature overrides are specified at the crate level

Expand Down
45 changes: 42 additions & 3 deletions libs/cramium-hal/src/board/baosec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -207,17 +207,56 @@ pub fn setup_ov2640_pins<T: IoSetup + IoGpio>(iox: &T) -> (IoxPort, u8) {
}

/// returns the USB SE0 port and pin number
const SE0_PIN: u8 = 14;
pub fn setup_usb_pins<T: IoSetup + IoGpio>(iox: &T) -> (IoxPort, u8) {
iox.setup_pin(
IoxPort::PB,
1,
SE0_PIN,
Some(IoxDir::Output),
Some(IoxFunction::Gpio),
None,
None,
Some(IoxEnable::Enable),
Some(IoxDriveStrength::Drive2mA),
);
iox.set_gpio_pin_value(IoxPort::PB, 1, IoxValue::Low);
(IoxPort::PB, 1)
iox.set_gpio_pin_value(IoxPort::PB, SE0_PIN, IoxValue::Low);
(IoxPort::PB, SE0_PIN)
}

// These constants definitely change for NTO. These will only work on NTO.
const KB_PORT: IoxPort = IoxPort::PD;
const R_PINS: [u8; 3] = [0, 1, 4];
const C_PINS: [u8; 3] = [5, 6, 7];
pub fn setup_kb_pins<T: IoSetup + IoGpio>(iox: &T) -> ([(IoxPort, u8); 3], [(IoxPort, u8); 3]) {
for r in R_PINS {
iox.setup_pin(
KB_PORT,
r,
Some(IoxDir::Output),
Some(IoxFunction::Gpio),
None,
None,
Some(IoxEnable::Enable),
Some(IoxDriveStrength::Drive2mA),
);
iox.set_gpio_pin_value(KB_PORT, r, IoxValue::High);
}

for c in C_PINS {
iox.setup_pin(
KB_PORT,
c,
Some(IoxDir::Input),
Some(IoxFunction::Gpio),
Some(IoxEnable::Enable),
None,
Some(IoxEnable::Enable),
Some(IoxDriveStrength::Drive2mA),
);
}
([(KB_PORT, R_PINS[0]), (KB_PORT, R_PINS[1]), (KB_PORT, R_PINS[2])], [
(KB_PORT, C_PINS[0]),
(KB_PORT, C_PINS[1]),
(KB_PORT, C_PINS[2]),
])
}
1 change: 1 addition & 0 deletions libs/cramium-hal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ pub mod shared_csr;
pub mod udma;
pub mod usb;
pub use shared_csr::*;
pub mod mbox;
pub mod minigfx;
244 changes: 244 additions & 0 deletions libs/cramium-hal/src/mbox.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,244 @@
use utra::mailbox;
use utralib::generated::*;

/// This constraint is limited by the size of the memory on the CM7 side
pub const MAX_PKT_LEN: usize = 128;
pub const MBOX_PROTOCOL_REV: u32 = 0;
pub const TX_FIFO_DEPTH: u32 = 128;
pub const PAYLOAD_LEN_WORDS: usize = MAX_PKT_LEN - 2;
pub const RERAM_PAGE_SIZE_BYTES: usize = 32;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[allow(dead_code)]
pub enum MboxError {
None,
NotReady,
TxOverflow,
TxUnderflow,
RxOverflow,
RxUnderflow,
InvalidOpcode,
ProtocolErr,
}

#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum ToRvOp {
Invalid = 0,

RetKnock = 128,
RetDct8x8 = 129,
RetClifford = 130,
RetFlashWrite = 131,
}
impl TryFrom<u16> for ToRvOp {
type Error = MboxError;

fn try_from(value: u16) -> Result<Self, Self::Error> {
match value {
0 => Ok(ToRvOp::Invalid),
128 => Ok(ToRvOp::RetKnock),
129 => Ok(ToRvOp::RetDct8x8),
130 => Ok(ToRvOp::RetClifford),
131 => Ok(ToRvOp::RetFlashWrite),
_ => Err(MboxError::InvalidOpcode),
}
}
}

#[repr(u16)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[allow(dead_code)]
pub enum ToCm7Op {
Invalid = 0,

Knock = 1,
Dct8x8 = 2,
Clifford = 3,
FlashWrite = 4,
}

pub struct MboxToCm7Pkt<'a> {
pub version: u32,
pub opcode: ToCm7Op,
pub data: &'a [u32],
}

pub struct MboxToRvPkt {
pub version: u32,
pub opcode: ToRvOp,
#[cfg(target_os = "xous")]
pub data: Vec<u32>,
#[cfg(not(target_os = "xous"))]
pub len: usize,
}

pub struct Mbox {
csr: CSR<u32>,
}
impl Mbox {
pub fn new() -> Mbox {
#[cfg(target_os = "xous")]
let csr_mem = xous::syscall::map_memory(
xous::MemoryAddress::new(mailbox::HW_MAILBOX_BASE),
None,
4096,
xous::MemoryFlags::R | xous::MemoryFlags::W,
)
.expect("couldn't map mailbox CSR range");
#[cfg(target_os = "xous")]
let mut csr = CSR::new(csr_mem.as_mut_ptr() as *mut u32);
#[cfg(not(target_os = "xous"))]
let mut csr = CSR::new(mailbox::HW_MAILBOX_BASE as *mut u32);
csr.wfo(mailbox::LOOPBACK_LOOPBACK, 0); // ensure we're not in loopback mode
// generate available events - not hooked up to IRQ, but we'll poll for now
csr.wfo(mailbox::EV_ENABLE_AVAILABLE, 1);

Self { csr }
}

fn expect_tx(&mut self, val: u32) -> Result<(), MboxError> {
if (TX_FIFO_DEPTH - self.csr.rf(mailbox::STATUS_TX_WORDS)) == 0 {
return Err(MboxError::TxOverflow);
} else {
self.csr.wo(mailbox::WDATA, val);
Ok(())
}
}

pub fn try_send(&mut self, to_cm7: MboxToCm7Pkt) -> Result<(), MboxError> {
if to_cm7.data.len() > PAYLOAD_LEN_WORDS {
Err(MboxError::TxOverflow)
} else {
self.expect_tx(to_cm7.version)?;
self.expect_tx(to_cm7.opcode as u32 | (to_cm7.data.len() as u32) << 16)?;
for &d in to_cm7.data.iter() {
self.expect_tx(d)?;
}
// trigger the send
self.csr.wfo(mailbox::DONE_DONE, 1);
Ok(())
}
}

fn expect_rx(&mut self) -> Result<u32, MboxError> {
if self.csr.rf(mailbox::STATUS_RX_WORDS) == 0 {
Err(MboxError::RxUnderflow)
} else {
Ok(self.csr.r(mailbox::RDATA))
}
}

#[cfg(target_os = "xous")]
pub fn try_rx(&mut self) -> Result<MboxToRvPkt, MboxError> {
let version = self.expect_rx()?;
let op_and_len = self.expect_rx()?;
let opcode = ToRvOp::try_from((op_and_len & 0xFFFF) as u16)?;
let len = (op_and_len >> 16) as usize;
let mut data = Vec::new();
for _ in 0..len {
data.push(self.expect_rx()?);
}
Ok(MboxToRvPkt { version, opcode, data })
}

#[cfg(not(target_os = "xous"))]
pub fn try_rx(&mut self, data: &mut [u32]) -> Result<MboxToRvPkt, MboxError> {
let version = self.expect_rx()?;
let op_and_len = self.expect_rx()?;
let opcode = ToRvOp::try_from((op_and_len & 0xFFFF) as u16)?;
let len = (op_and_len >> 16) as usize;
for i in 0..len {
if i < data.len() {
data[i] = self.expect_rx()?
}
}
Ok(MboxToRvPkt { version, opcode, len })
}

pub fn poll_not_ready(&self) -> bool { self.csr.rf(mailbox::EV_PENDING_AVAILABLE) == 0 }

pub fn poll_rx_available(&self) -> bool { self.csr.rf(mailbox::STATUS_RX_WORDS) != 0 }
}

// TODO: make these protocol-level interactions more modular. Right now this is just a stand-alone
// test routine suitable for use in a no_std bootloader environment.
//
// TODO: resolve the timeout timer requirement in this code - there isn't a standard timer in
// the bootloader.
/*
#[cfg(not(target_os = "xous"))]
#[allow(dead_code)]
pub fn knock(mbox: &mut Mbox) -> Result<(), MboxError> {
let test_data = [0xC0DE_0000u32, 0x0000_600Du32];
let mut expected_result = 0;
for &d in test_data.iter() {
expected_result ^= d;
}
let test_pkt = MboxToCm7Pkt { version: MBOX_PROTOCOL_REV, opcode: ToCm7Op::Knock, data: &test_data };
crate::println!("sending knock...");
match mbox.try_send(test_pkt) {
Ok(_) => {
crate::println!("Packet send Ok\n");
let mut timeout = 0;
while mbox.poll_not_ready() {
timeout += 1;
if timeout > 1000 {
crate::println!("flash write timeout");
return Err(MboxError::NotReady);
}
crate::platform::delay(2);
} // now receive the packet
let mut rx_data = [0u32; 16];
timeout = 0;
while !mbox.poll_rx_available() {
timeout += 1;
if timeout > 1000 {
crate::println!("flash handshake timeout");
return Err(MboxError::NotReady);
}
crate::platform::delay(2);
}
match mbox.try_rx(&mut rx_data) {
Ok(rx_pkt) => {
crate::println!("Knock result: {:x}", rx_data[0]);
if rx_pkt.version != MBOX_PROTOCOL_REV {
crate::println!("Version mismatch {} != {}", rx_pkt.version, MBOX_PROTOCOL_REV);
}
if rx_pkt.opcode != ToRvOp::RetKnock {
crate::println!(
"Opcode mismatch {} != {}",
rx_pkt.opcode as u16,
ToRvOp::RetKnock as u16
);
}
if rx_pkt.len != 1 {
crate::println!("Expected length mismatch {} != {}", rx_pkt.len, 1);
Err(MboxError::ProtocolErr)
} else {
if rx_data[0] != expected_result {
crate::println!(
"Expected data mismatch {:x} != {:x}",
rx_data[0],
expected_result
);
Err(MboxError::ProtocolErr)
} else {
crate::println!("Knock test PASS: {:x}", rx_data[0]);
Ok(())
}
}
}
Err(e) => {
crate::println!("Error while deserializing: {:?}\n", e);
Err(e)
}
}
}
Err(e) => {
crate::println!("Packet send error: {:?}\n", e);
Err(e)
}
}
}
*/
6 changes: 6 additions & 0 deletions libs/cramium-hal/src/udma/i2c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,14 @@ impl I2c {
timeout += 1;
if timeout > TIMEOUT_ITERS {
// reset the block
self.udma_reset(Bank::Custom);
self.udma_reset(Bank::Tx);
self.udma_reset(Bank::Rx);
self.csr.wfo(utra::udma_i2c_0::REG_SETUP_R_DO_RST, 1);
self.csr.wo(utra::udma_i2c_0::REG_SETUP, 0);

self.send_cmd_list(&[I2cCmd::Config(self.divider)]);
self.pending.take();
return Err(xous::Error::Timeout);
}
#[cfg(feature = "std")]
Expand Down
6 changes: 6 additions & 0 deletions libs/cramium-hal/src/udma/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,12 @@ pub trait Udma {
bank_addr.add(DmaReg::Size.into()).write_volatile((buf.len() * size_of::<T>()) as u32);
bank_addr.add(DmaReg::Cfg.into()).write_volatile(config | CFG_EN)
}
fn udma_reset(&self, bank: Bank) {
unsafe {
let bank_addr = self.csr().base().add(bank as usize);
bank_addr.add(DmaReg::Cfg.into()).write_volatile(CFG_CLEAR);
}
}
fn udma_can_enqueue(&self, bank: Bank) -> bool {
// Safety: only safe when used in the context of UDMA registers.
unsafe {
Expand Down
Loading

0 comments on commit c1564d2

Please sign in to comment.