Skip to content

Commit

Permalink
Merge pull request #613 from betrusted-io/usb-irq
Browse files Browse the repository at this point in the history
USB IRQ integration
  • Loading branch information
bunnie authored Jan 2, 2025
2 parents 89ebd5d + 5f11dad commit e0d1085
Show file tree
Hide file tree
Showing 16 changed files with 408 additions and 43 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

66 changes: 66 additions & 0 deletions libs/cramium-hal/src/axp2101.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,41 @@ const REG_DLDO1_V: usize = 0x99;
#[allow(dead_code)]
const REG_DLDO2_V: usize = 0x9A;

const REG_IRQ_ENABLE0: u8 = 0x40;
#[allow(dead_code)]
const REG_IRQ_ENABLE1: u8 = 0x41;
#[allow(dead_code)]
const REG_IRQ_ENABLE2: u8 = 0x42;
const REG_IRQ_STATUS0: u8 = 0x48;
const REG_IRQ_STATUS1: u8 = 0x49;
#[allow(dead_code)]
const REG_IRQ_STATUS2: u8 = 0x4A;
const VBUS_INSERT_MASK: u8 = 0x80;
const VBUS_REMOVE_MASK: u8 = 0x40;

#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub enum VbusIrq {
None,
Insert,
Remove,
InsertAndRemove,
}

/// From the raw u8 read back from the register
impl From<u8> for VbusIrq {
fn from(value: u8) -> Self {
if (value & VBUS_INSERT_MASK) == 0 && (value & VBUS_REMOVE_MASK) == 0 {
VbusIrq::None
} else if (value & VBUS_INSERT_MASK) != 0 && (value & VBUS_REMOVE_MASK) == 0 {
VbusIrq::Insert
} else if (value & VBUS_INSERT_MASK) == 0 && (value & VBUS_REMOVE_MASK) != 0 {
VbusIrq::Remove
} else {
VbusIrq::InsertAndRemove
}
}
}

#[repr(u8)]
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum WhichLdo {
Expand Down Expand Up @@ -215,6 +250,37 @@ impl Axp2101 {
}
ctl
}

/// This will clear all other IRQ sources except VBUS IRQ
/// If we need to take more IRQ sources then this API will need to be refactored.
pub fn setup_vbus_irq(&mut self, i2c: &mut dyn i2c::I2cApi, mode: VbusIrq) -> Result<(), xous::Error> {
let data = match mode {
VbusIrq::None => 0u8,
VbusIrq::Insert => VBUS_INSERT_MASK,
VbusIrq::Remove => VBUS_REMOVE_MASK,
VbusIrq::InsertAndRemove => VBUS_INSERT_MASK | VBUS_REMOVE_MASK,
};
// ENABLE1 has the code we want to target, but the rest also needs to be cleared so
// fill the values in with 0.
i2c.i2c_write(AXP2101_DEV, REG_IRQ_ENABLE0, &[0, data, 0]).map(|_| ())?;

// clear the status bits
let mut status = [0u8; 3];
i2c.i2c_read(AXP2101_DEV, REG_IRQ_STATUS0, &mut status, false)?;
i2c.i2c_write(AXP2101_DEV, REG_IRQ_STATUS0, &status).map(|_| ())
}

pub fn get_vbus_irq_status(&self, i2c: &mut dyn i2c::I2cApi) -> Result<VbusIrq, xous::Error> {
let mut buf = [0u8];
i2c.i2c_read(AXP2101_DEV, REG_IRQ_STATUS1, &mut buf, false)?;
Ok(VbusIrq::from(buf[0]))
}

/// This will clear all pending IRQs, regardless of the setup
pub fn clear_vbus_irq_pending(&mut self, i2c: &mut dyn i2c::I2cApi) -> Result<(), xous::Error> {
let data = VBUS_INSERT_MASK | VBUS_REMOVE_MASK;
i2c.i2c_write(AXP2101_DEV, REG_IRQ_STATUS1, &[data]).map(|_| ())
}
}

pub fn parse_dcdc_ena(d: u8) -> ([bool; 4], bool, bool) {
Expand Down
18 changes: 17 additions & 1 deletion libs/cramium-hal/src/board/baosec.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Constants that define pin locations, RAM offsets, etc. for the BaoSec board
use crate::iox;
use crate::iox::IoSetup;
use crate::iox::*;
use crate::iox::{IoIrq, IoSetup};

pub const I2C_AXP2101_ADR: u8 = 0x34;
pub const I2C_TUSB320_ADR: u8 = 0x47;
Expand Down Expand Up @@ -150,6 +150,7 @@ pub fn setup_memory_pins(iox: &dyn IoSetup) -> crate::udma::SpimChannel {
crate::udma::SpimChannel::Channel1
}

/// This also sets up I2C-adjacent interrupt inputs as well
pub fn setup_i2c_pins(iox: &dyn IoSetup) -> crate::udma::I2cChannel {
// I2C_SCL_B[0]
iox.setup_pin(
Expand All @@ -173,6 +174,17 @@ pub fn setup_i2c_pins(iox: &dyn IoSetup) -> crate::udma::I2cChannel {
Some(IoxEnable::Enable),
Some(IoxDriveStrength::Drive2mA),
);
// PB13 -> PMIC IRQ
iox.setup_pin(
IoxPort::PB,
13,
Some(IoxDir::Input),
Some(IoxFunction::Gpio),
Some(IoxEnable::Enable),
Some(IoxEnable::Enable),
None,
None,
);
crate::udma::I2cChannel::Channel0
}

Expand Down Expand Up @@ -260,3 +272,7 @@ pub fn setup_kb_pins<T: IoSetup + IoGpio>(iox: &T) -> ([(IoxPort, u8); 3], [(Iox
(KB_PORT, C_PINS[2]),
])
}

pub fn setup_pmic_irq<T: IoIrq>(iox: &T, server: &str, opcode: usize) {
iox.set_irq_pin(IoxPort::PB, 13, IoxValue::Low, server, opcode);
}
8 changes: 8 additions & 0 deletions libs/cramium-hal/src/iox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,14 @@ pub trait IoGpio {
fn set_gpio_pin_dir(&self, port: IoxPort, pin: u8, dir: IoxDir);
}

pub trait IoIrq {
/// This hooks a given port/pin to generate a message to the server specified
/// with `server` and the opcode number `usize` when an IRQ is detected on the port/pin.
/// The active state of the IRQ is defined by `active`; the transition edge from inactive
/// to active is when the event is generated.
fn set_irq_pin(&self, port: IoxPort, pin: u8, active: IoxValue, server: &str, opcode: usize);
}

pub struct Iox {
pub csr: SharedCsr<u32>,
}
Expand Down
61 changes: 32 additions & 29 deletions libs/cramium-hal/src/usb/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ const CRG_EVENT_RING_NUM: usize = 1;
const CRG_ERST_SIZE: usize = 1;
const CRG_EVENT_RING_SIZE: usize = 128;
const CRG_EP0_TD_RING_SIZE: usize = 16;
const CRG_EP_NUM: usize = 4;
pub const CRG_EP_NUM: usize = 4;
const CRG_TD_RING_SIZE: usize = 512; // was 1280 in original code. not even sure we need ... 64?
const CRG_UDC_MAX_BURST: u32 = 15;
const CRG_UDC_ISO_INTERVAL: u8 = 3;
Expand Down Expand Up @@ -1243,10 +1243,6 @@ impl CorigineUsb {
compiler_fence(Ordering::SeqCst);

// Set up storage for Endpoint contexts
#[cfg(feature = "std")]
log::trace!("Begin init_device_context");
#[cfg(not(feature = "std"))]
println!("Begin init_device_context");
// init device context and ep context, refer to 7.6.2
self.p_epcx = AtomicPtr::new((self.ifram_base_ptr + CRG_UDC_EPCX_OFFSET) as *mut EpCxS);
self.p_epcx_len = CRG_EP_NUM * 2 * size_of::<EpCxS>();
Expand All @@ -1265,13 +1261,12 @@ impl CorigineUsb {
// disable 2.0 LPM
self.csr.wo(U2PORTPMSC, 0);

#[cfg(feature = "std")]
log::trace!("USB init done");
crate::println!("USB hw init done");
}

pub fn init_ep0(&mut self) {
#[cfg(feature = "std")]
log::trace!("Begin init_ep0");
#[cfg(feature = "verbose-debug")]
crate::println!("Begin init_ep0");
let udc_ep = &mut self.udc_ep[0];

udc_ep.ep_num = 0;
Expand Down Expand Up @@ -1311,15 +1306,7 @@ impl CorigineUsb {
let cmd_param0: u32 = (udc_ep.tran_ring_info.vaddr.load(Ordering::SeqCst) as u32) & 0xFFFF_FFF0
| self.csr.ms(CMDPARA0_CMD0_INIT_EP0_DCS, udc_ep.pcs as u32);
let cmd_param1: u32 = 0;
#[cfg(feature = "std")]
{
log::debug!(
"ep0 ring dma addr = {:x}",
udc_ep.tran_ring_info.vaddr.load(Ordering::SeqCst) as usize
);
log::debug!("INIT EP0 CMD par0 = {:x} par1 = {:x}", cmd_param0, cmd_param1);
}
#[cfg(not(feature = "std"))]
#[cfg(feature = "verbose-debug")]
{
println!("ep0 ring dma addr = {:x}", udc_ep.tran_ring_info.vaddr.load(Ordering::SeqCst) as usize);
println!("INIT EP0 CMD par0 = {:x} par1 = {:x}", cmd_param0, cmd_param1);
Expand All @@ -1329,8 +1316,6 @@ impl CorigineUsb {
.expect("couldn't issue ep0 init command");

self.ep0_buf = AtomicPtr::new((self.ifram_base_ptr + CRG_UDC_EP0_BUF_OFFSET) as *mut u8);
#[cfg(feature = "std")]
log::trace!("End init_ep0");
}

#[cfg(feature = "std")]
Expand Down Expand Up @@ -2168,7 +2153,7 @@ pub struct CorigineWrapper {
/// Tuple is (type of endpoint, max packet size)
pub ep_meta: [Option<(EpType, usize)>; CRG_EP_NUM],
pub ep_out_ready: Box<[AtomicBool]>,
pub address_is_set: AtomicBool,
pub address_is_set: Arc<AtomicBool>,
pub event: Option<CrgEvent>,
}
#[cfg(feature = "std")]
Expand All @@ -2183,7 +2168,7 @@ impl CorigineWrapper {
.collect::<Vec<_>>()
.into_boxed_slice(),
event: None,
address_is_set: AtomicBool::new(false),
address_is_set: Arc::new(AtomicBool::new(false)),
};
c
}
Expand All @@ -2198,7 +2183,7 @@ impl CorigineWrapper {
.collect::<Vec<_>>()
.into_boxed_slice(),
event: None,
address_is_set: AtomicBool::new(self.address_is_set.load(Ordering::SeqCst)),
address_is_set: self.address_is_set.clone(),
};
c.ep_meta.copy_from_slice(&self.ep_meta);
for (dst, src) in c.ep_out_ready.iter().zip(self.ep_out_ready.iter()) {
Expand Down Expand Up @@ -2327,7 +2312,7 @@ impl UsbBus for CorigineWrapper {
let irq_csr = {
let mut hw = self.core();
// disable IRQs
hw.irq_csr.wfo(utralib::utra::irqarray1::EV_ENABLE_USBC_DUPE, 0);
hw.irq_csr.wo(utralib::utra::irqarray1::EV_ENABLE, 0);
hw.reset();
hw.init();
hw.start();
Expand All @@ -2337,7 +2322,7 @@ impl UsbBus for CorigineWrapper {
};
// the lock is released, now we can enable irqs
irq_csr.wo(utralib::utra::irqarray1::EV_PENDING, 0xffff_ffff); // blanket clear
irq_csr.wfo(utralib::utra::irqarray1::EV_ENABLE_USBC_DUPE, 1);
irq_csr.wo(utralib::utra::irqarray1::EV_ENABLE, 3); // FIXME: hard coded value that enables CORIGINE_IRQ_MASK | SW_IRQ_MASK

// TODO -- figure out what this means
// self.force_reset().ok();
Expand Down Expand Up @@ -2530,9 +2515,11 @@ impl UsbBus for CorigineWrapper {
let ret = if let Some((ptr, len)) = self.core().app_ptr.take() {
self.ep_out_ready[ep_addr.index()].store(false, Ordering::SeqCst);
let app_buf = unsafe { core::slice::from_raw_parts(ptr as *const u8, len) };
if buf.len() > app_buf.len() {
if buf.len() < app_buf.len() {
Err(UsbError::BufferOverflow)
} else {
#[cfg(feature = "verbose-debug")]
crate::println!("copy into len {} from len {}", buf.len(), app_buf.len());
buf[..app_buf.len()].copy_from_slice(app_buf);
crate::println!(" {:x?}", &buf[..app_buf.len().min(8)]);
Ok(app_buf.len())
Expand Down Expand Up @@ -2681,9 +2668,25 @@ impl UsbBus for CorigineWrapper {
fn force_reset(&self) -> Result<()> {
crate::println!(" ******* force_reset");

// This is the minimum we need to do to restart EP0, but, I think we also need to reset
// TRB pointers etc. See page 67 of the manual.
self.core().update_current_speed();
self.address_is_set.store(false, Ordering::SeqCst);
for eor in self.ep_out_ready.iter() {
eor.store(false, Ordering::SeqCst);
}
crate::println!(" ******** reset");
let irq_csr = {
let mut hw = self.core();
// disable IRQs
hw.irq_csr.wo(utralib::utra::irqarray1::EV_ENABLE, 0);
hw.reset();
hw.init();
hw.start();
hw.update_current_speed();
// IRQ enable must happen without dependency on the hardware lock
hw.irq_csr.clone()
};
// the lock is released, now we can enable irqs
irq_csr.wo(utralib::utra::irqarray1::EV_PENDING, 0xffff_ffff); // blanket clear
irq_csr.wo(utralib::utra::irqarray1::EV_ENABLE, 3); // FIXME: hard coded value that enables CORIGINE_IRQ_MASK | SW_IRQ_MASK

Ok(())
}
Expand Down
5 changes: 5 additions & 0 deletions loader/src/platform/cramium/cramium.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1542,6 +1542,11 @@ unsafe fn init_clock_asic(freq_hz: u32) -> u32 {
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_2.offset()).write_volatile(0x1f3f); // hclk
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_3.offset()).write_volatile(0x0f1f); // iclk
daric_cgu.add(utra::sysctrl::SFR_CGUFD_CFGFDCR_0_4_4.offset()).write_volatile(0x070f); // pclk

#[cfg(not(feature = "cramium-mpw"))]
// perclk divider - set to divide by 8 off of an 800Mhz base. Only found on NTO.
daric_cgu.add(utra::sysctrl::SFR_CGUFDPER.offset()).write_volatile(0x03_ff_ff);

// commit dividers
daric_cgu.add(utra::sysctrl::SFR_CGUSET.offset()).write_volatile(0x32);
}
Expand Down
3 changes: 3 additions & 0 deletions services/cram-console/src/cmds/mbox.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,9 @@ impl Mbox {
}

pub fn try_send(&mut self, to_cm7: MboxToCm7Pkt) -> Result<(), MboxError> {
// clear any pending bits from previous transactions
self.csr.wo(mailbox::EV_PENDING, self.csr.r(mailbox::EV_PENDING));

if to_cm7.data.len() > MAX_PKT_LEN {
Err(MboxError::TxOverflow)
} else {
Expand Down
3 changes: 2 additions & 1 deletion services/cram-hal-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ pio-proc = "0.2.2"
pio = "0.2.1"
rand_core = "0.6.4"
rand_chacha = "0.3.1"
bitfield = "0.13.2"

num-derive = { version = "0.4.2", default-features = false }
num-traits = { version = "0.2.14", default-features = false }
Expand All @@ -45,4 +46,4 @@ swap = []
mpw = ["cramium-hal/mpw"]
# add this feature to enable pre-emption
quantum-timer = ["utralib", "pio"]
default = ["app-uart"]
default = ["app-uart", "utralib"]
15 changes: 14 additions & 1 deletion services/cram-hal-service/src/api.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub mod keyboard;
use cramium_hal::iox;
use cramium_hal::iox::{self, IoxPort, IoxValue};
pub use keyboard::*;

/// The Opcode numbers here should not be changed. You can add new ones,
Expand Down Expand Up @@ -47,6 +47,10 @@ pub enum Opcode {
/// Peripheral reset
PeriphReset = 10,

/// Configure Iox IRQ
ConfigureIoxIrq = 11,
IrqLocalHandler = 12,

/// Exit server
Quit = 255,

Expand Down Expand Up @@ -145,3 +149,12 @@ pub struct I2cTransactions {
impl From<Vec<I2cTransaction>> for I2cTransactions {
fn from(value: Vec<I2cTransaction>) -> Self { Self { transactions: value } }
}

#[derive(Debug, rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)]
pub struct IoxIrqRegistration {
pub server: String,
pub opcode: usize,
pub port: IoxPort,
pub pin: u8,
pub active: IoxValue,
}
15 changes: 13 additions & 2 deletions services/cram-hal-service/src/iox_lib.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
use core::sync::atomic::Ordering;

use cramium_hal::iox::{
IoGpio, IoSetup, IoxDir, IoxDriveStrength, IoxEnable, IoxFunction, IoxPort, IoxValue,
IoGpio, IoIrq, IoSetup, IoxDir, IoxDriveStrength, IoxEnable, IoxFunction, IoxPort, IoxValue,
};
use num_traits::*;

use crate::{Opcode, SERVER_NAME_CRAM_HAL, api::IoxConfigMessage};
use crate::{
Opcode, SERVER_NAME_CRAM_HAL,
api::{IoxConfigMessage, IoxIrqRegistration},
};

pub struct IoxHal {
conn: xous::CID,
Expand Down Expand Up @@ -176,3 +179,11 @@ impl Drop for IoxHal {
}
}
}

impl IoIrq for IoxHal {
fn set_irq_pin(&self, port: IoxPort, pin: u8, active: IoxValue, server: &str, opcode: usize) {
let msg = IoxIrqRegistration { server: server.to_owned(), opcode, port, pin, active };
let buf = xous_ipc::Buffer::into_buf(msg).unwrap();
buf.lend(self.conn, Opcode::ConfigureIoxIrq.to_u32().unwrap()).expect("Couldn't set up IRQ");
}
}
Loading

0 comments on commit e0d1085

Please sign in to comment.