Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

USB IRQ integration #613

Merged
merged 19 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading