Tighten I3C constants and timeout handling
diff --git a/target/ast10x0/peripherals/i3c/constants.rs b/target/ast10x0/peripherals/i3c/constants.rs index d98e965..45aaeb0 100644 --- a/target/ast10x0/peripherals/i3c/constants.rs +++ b/target/ast10x0/peripherals/i3c/constants.rs
@@ -51,6 +51,8 @@ /// Nanoseconds per second pub const NSEC_PER_SEC: u32 = 1_000_000_000; +/// Microseconds per second +pub const USEC_PER_SEC: u32 = 1_000_000; // ============================================================================= // SDA TX Hold Configuration @@ -253,6 +255,33 @@ pub const MAX_DEVICES_PER_BUS: usize = 8; // ============================================================================= +// Driver Policy / Bring-up Defaults +// ============================================================================= + +/// Default static address programmed into the controller during init. +pub const I3C_DEFAULT_STATIC_ADDR: u8 = 0x74; +/// One-second operation timeout expressed in microseconds. +pub const I3C_OP_TIMEOUT_US: u32 = USEC_PER_SEC; +/// Generic bounded-poll iteration ceiling used by controller bring-up waits. +pub const I3C_POLL_MAX_ITERS: u32 = 1_000_000; +/// Generic bounded-poll delay between iterations in nanoseconds. +pub const I3C_POLL_DELAY_NS: u32 = 10_000; +/// IBI enable / halt / reset-control poll ceiling. +pub const I3C_CTRL_POLL_MAX_ITERS: u32 = 1_000_000; +/// Queue reset / halt / IBI enable poll delay in nanoseconds. +pub const I3C_CTRL_POLL_DELAY_NS: u32 = 10_000; +/// Program the maximum IBI data threshold supported by the controller. +pub const I3C_IBI_DATA_THRESHOLD_MAX: u8 = 31; +/// Global I3C reset deassert bit in `SCU054`. +pub const I3C_GLOBAL_RESET_DEASSERT_MASK: u32 = 0x80; +/// Write-one-to-clear mask for all interrupt-status bits. +pub const I3C_INTR_STATUS_ALL_BITS: u32 = u32::MAX; +/// Bring-up value for `BUS_FREE_TIMING` (`i3cd0d4`). +pub const I3C_BUS_FREE_TIMING_RESET: u32 = 0xffff_007c; +/// AST10x0 target MIPI manufacturer identifier. +pub const I3C_AST10X0_MIPI_MANUF_ID: u16 = 0x03f6; + +// ============================================================================= // CCC (Common Command Code) Constants // =============================================================================
diff --git a/target/ast10x0/peripherals/i3c/hardware.rs b/target/ast10x0/peripherals/i3c/hardware.rs index d2789fc..f150e44 100644 --- a/target/ast10x0/peripherals/i3c/hardware.rs +++ b/target/ast10x0/peripherals/i3c/hardware.rs
@@ -37,21 +37,24 @@ COMMAND_PORT_CP, COMMAND_PORT_DBP, COMMAND_PORT_DEV_COUNT, COMMAND_PORT_DEV_INDEX, COMMAND_PORT_READ_TRANSFER, COMMAND_PORT_ROC, COMMAND_PORT_SPEED, COMMAND_PORT_TID, COMMAND_PORT_TOC, DEV_ADDR_TABLE_IBI_MDB, DEV_ADDR_TABLE_IBI_PEC, DEV_ADDR_TABLE_SIR_REJECT, - I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE, I3C_BUS_I2C_FM_TF_MAX_NS, I3C_BUS_I2C_FM_THIGH_MIN_NS, - I3C_BUS_I2C_FM_TLOW_MIN_NS, I3C_BUS_I2C_FM_TR_MAX_NS, I3C_BUS_I2C_FMP_TF_MAX_NS, - I3C_BUS_I2C_FMP_THIGH_MIN_NS, I3C_BUS_I2C_FMP_TLOW_MIN_NS, I3C_BUS_I2C_FMP_TR_MAX_NS, - I3C_BUS_I2C_STD_TF_MAX_NS, I3C_BUS_I2C_STD_THIGH_MIN_NS, I3C_BUS_I2C_STD_TLOW_MIN_NS, - I3C_BUS_I2C_STD_TR_MAX_NS, I3C_BUS_THIGH_MAX_NS, I3C_CCC_DEVCTRL, I3C_CCC_ENTDAA, - I3C_CCC_EVT_INTR, I3C_CCC_SETHID, I3C_MSG_READ, I3CG_REG1_SCL_IN_SW_MODE_EN, - I3CG_REG1_SCL_IN_SW_MODE_VAL, I3CG_REG1_SDA_IN_SW_MODE_EN, I3CG_REG1_SDA_IN_SW_MODE_VAL, - IBIQ_STATUS_IBI_DATA_LEN, IBIQ_STATUS_IBI_DATA_LEN_SHIFT, IBIQ_STATUS_IBI_ID, - IBIQ_STATUS_IBI_ID_SHIFT, INTR_CCC_UPDATED_STAT, INTR_DYN_ADDR_ASSGN_STAT, INTR_IBI_THLD_STAT, - INTR_RESP_READY_STAT, INTR_TRANSFER_ABORT_STAT, INTR_TRANSFER_ERR_STAT, MAX_CMDS, NSEC_PER_SEC, - RESET_CTRL_ALL, RESET_CTRL_QUEUES, RESET_CTRL_XFER_QUEUES, RESPONSE_ERROR_IBA_NACK, - RESPONSE_PORT_DATA_LEN_MASK, RESPONSE_PORT_DATA_LEN_SHIFT, RESPONSE_PORT_ERR_STATUS_MASK, - RESPONSE_PORT_ERR_STATUS_SHIFT, RESPONSE_PORT_TID_MASK, RESPONSE_PORT_TID_SHIFT, - SDA_TX_HOLD_MASK, SDA_TX_HOLD_MAX, SDA_TX_HOLD_MIN, SLV_DCR_MASK, SLV_EVENT_CTRL_SIR_EN, bit, - field_get, field_prep, + I3C_AST10X0_MIPI_MANUF_ID, I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE, I3C_BUS_FREE_TIMING_RESET, + I3C_BUS_I2C_FM_TF_MAX_NS, I3C_BUS_I2C_FM_THIGH_MIN_NS, I3C_BUS_I2C_FM_TLOW_MIN_NS, + I3C_BUS_I2C_FM_TR_MAX_NS, I3C_BUS_I2C_FMP_TF_MAX_NS, I3C_BUS_I2C_FMP_THIGH_MIN_NS, + I3C_BUS_I2C_FMP_TLOW_MIN_NS, I3C_BUS_I2C_FMP_TR_MAX_NS, I3C_BUS_I2C_STD_TF_MAX_NS, + I3C_BUS_I2C_STD_THIGH_MIN_NS, I3C_BUS_I2C_STD_TLOW_MIN_NS, I3C_BUS_I2C_STD_TR_MAX_NS, + I3C_BUS_THIGH_MAX_NS, I3C_CCC_DEVCTRL, I3C_CCC_ENTDAA, I3C_CCC_EVT_INTR, I3C_CCC_SETHID, + I3C_CTRL_POLL_DELAY_NS, I3C_CTRL_POLL_MAX_ITERS, I3C_DEFAULT_STATIC_ADDR, + I3C_GLOBAL_RESET_DEASSERT_MASK, I3C_IBI_DATA_THRESHOLD_MAX, I3C_INTR_STATUS_ALL_BITS, + I3C_MSG_READ, I3C_OP_TIMEOUT_US, I3C_POLL_DELAY_NS, I3C_POLL_MAX_ITERS, + I3CG_REG1_SCL_IN_SW_MODE_EN, I3CG_REG1_SCL_IN_SW_MODE_VAL, I3CG_REG1_SDA_IN_SW_MODE_EN, + I3CG_REG1_SDA_IN_SW_MODE_VAL, IBIQ_STATUS_IBI_DATA_LEN, IBIQ_STATUS_IBI_DATA_LEN_SHIFT, + IBIQ_STATUS_IBI_ID, IBIQ_STATUS_IBI_ID_SHIFT, INTR_CCC_UPDATED_STAT, INTR_DYN_ADDR_ASSGN_STAT, + INTR_IBI_THLD_STAT, INTR_RESP_READY_STAT, INTR_TRANSFER_ABORT_STAT, INTR_TRANSFER_ERR_STAT, + MAX_CMDS, NSEC_PER_SEC, RESET_CTRL_ALL, RESET_CTRL_QUEUES, RESET_CTRL_XFER_QUEUES, + RESPONSE_ERROR_IBA_NACK, RESPONSE_PORT_DATA_LEN_MASK, RESPONSE_PORT_DATA_LEN_SHIFT, + RESPONSE_PORT_ERR_STATUS_MASK, RESPONSE_PORT_ERR_STATUS_SHIFT, RESPONSE_PORT_TID_MASK, + RESPONSE_PORT_TID_SHIFT, SDA_TX_HOLD_MASK, SDA_TX_HOLD_MAX, SDA_TX_HOLD_MIN, SLV_DCR_MASK, + SLV_EVENT_CTRL_SIR_EN, bit, field_get, field_prep, }; use super::error::I3cError as I3cDrvError; use super::error::I3cError; @@ -60,7 +63,6 @@ use core::cell::UnsafeCell; use core::marker::PhantomData; -use core::ptr::read_volatile; use core::sync::atomic::Ordering; use cortex_m::peripheral::NVIC; @@ -713,9 +715,10 @@ } fn global_reset_deassert(&mut self) { - self.scu() - .scu054() - .modify(|_, w| unsafe { w.scu050sys_rst_ctrl_clear_reg2().bits(0x80) }); + self.scu().scu054().modify(|_, w| unsafe { + w.scu050sys_rst_ctrl_clear_reg2() + .bits(I3C_GLOBAL_RESET_DEASSERT_MASK) + }); } fn clock_on(&mut self, bus: u8) { @@ -739,7 +742,7 @@ .instid() .bits(I3C::BUS_NUM) .staticaddr() - .bits(0x74) + .bits(I3C_DEFAULT_STATIC_ADDR) }); let reg = read_i3cg_reg1!(self, I3C::BUS_NUM); i3c_debug!(self.logger, "i3cg_reg1: {:#x}", reg); @@ -752,17 +755,6 @@ self.clock_on(I3C::BUS_NUM); self.core_reset_deassert(I3C::BUS_NUM); self.i3c_disable(config.is_secondary); - unsafe { - let scu090: u32 = 0x7e6e_2090; - - let reg: u32 = read_volatile(scu090 as *const u32); - i3c_debug!(self.logger, "scu090: {:#x}", reg); - - let scu050: u32 = 0x7e6e_2050; - - let reg: u32 = read_volatile(scu050 as *const u32); - i3c_debug!(self.logger, "scu050: {:#x}", reg); - } i3c_debug!( self.logger, @@ -791,8 +783,8 @@ || regs.i3cd034().read().bits(), |val| val == 0, &mut self.yield_fn, - 100_000, - 1_000_000, + I3C_POLL_DELAY_NS, + I3C_POLL_MAX_ITERS, ); self.set_role(config.is_secondary); @@ -800,7 +792,7 @@ self.i3c() .i3cd03c() - .write(|w| unsafe { w.bits(0xffff_ffff) }); + .write(|w| unsafe { w.bits(I3C_INTR_STATUS_ALL_BITS) }); if config.is_secondary { self.i3c().i3cd040().write(|w| { w.transfererrstaten() @@ -851,7 +843,7 @@ self.i3c() .i3cd01c() - .write(|w| unsafe { w.ibidata_threshold_value().bits(31) }); + .write(|w| unsafe { w.ibidata_threshold_value().bits(I3C_IBI_DATA_THRESHOLD_MAX) }); self.i3c() .i3cd020() @@ -875,10 +867,10 @@ self.i3c() .i3cd02c() - .write(|w| unsafe { w.bits(0xffff_ffff) }); + .write(|w| unsafe { w.bits(I3C_INTR_STATUS_ALL_BITS) }); self.i3c() .i3cd030() - .write(|w| unsafe { w.bits(0xffff_ffff) }); + .write(|w| unsafe { w.bits(I3C_INTR_STATUS_ALL_BITS) }); self.i3c() .i3cd000() .modify(|_, w| w.hot_join_ack_nack_ctrl().set_bit()); @@ -1124,7 +1116,7 @@ // BUS_FREE_TIMING self.i3c() .i3cd0d4() - .write(|w| unsafe { w.bits(0xffff_007c) }); + .write(|w| unsafe { w.bits(I3C_BUS_FREE_TIMING_RESET) }); } fn calc_i2c_clk(&mut self, fscl_hz: u32) -> (u32, u32) { @@ -1161,9 +1153,12 @@ fn init_pid(&mut self, config: &mut I3cConfig) { let bus = I3C::BUS_NUM; - self.i3c() - .i3cd070() - .write(|w| unsafe { w.slvmipimfgid().bits(0x3f6).slvpiddcr().clear_bit() }); + self.i3c().i3cd070().write(|w| unsafe { + w.slvmipimfgid() + .bits(I3C_AST10X0_MIPI_MANUF_ID) + .slvpiddcr() + .clear_bit() + }); let rev_id: u32 = self.scu().scu004().read().hw_rev_id().bits().into(); let mut reg: u32 = rev_id << 16 | u32::from(bus) << 12; @@ -1292,8 +1287,8 @@ || u32::from(regs.i3cd054().read().cmtfrstatus().bits()), |val| val != u32::from(expected), &mut self.yield_fn, - 10000, - 1_000_000, + I3C_CTRL_POLL_DELAY_NS, + I3C_CTRL_POLL_MAX_ITERS, ); if rc.is_err() { @@ -1317,8 +1312,8 @@ || u32::from(regs.i3cd054().read().cmtfrstatus().bits()), |val| val == u32::from(expected), &mut self.yield_fn, - 10000, - 1_000_000, + I3C_CTRL_POLL_DELAY_NS, + I3C_CTRL_POLL_MAX_ITERS, ); if rc.is_err() { @@ -1339,8 +1334,8 @@ || regs.i3cd034().read().bits(), |val| val == 0, &mut self.yield_fn, - 10_000, - 1_000_000, + I3C_CTRL_POLL_DELAY_NS, + I3C_CTRL_POLL_MAX_ITERS, ); if rc.is_err() { @@ -1478,6 +1473,11 @@ return; } + // SAFETY: `curr_xfer` is written by `start_xfer` from a unique `&mut I3cXfer` + // for the duration of the active transfer, and is reset back to null exactly + // once here with `swap(..., AcqRel)` before reconstructing the reference. + // The caller waits for transfer completion before dropping the stack-owned + // `xfer`, so the pointed-to object remains valid for this ISR handoff. let xfer: &mut I3cXfer = unsafe { &mut *(p.cast::<I3cXfer>()) }; let nresp = self.i3c().i3cd04c().read().respbufblr().bits() as usize; @@ -1724,7 +1724,7 @@ let mut xfer = I3cXfer::new(&mut cmds[..]); self.start_xfer(config, &mut xfer); - if !xfer.done.wait_for_us(1_000_000_000, &mut self.yield_fn) { + if !xfer.done.wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { self.enter_halt(true, config); self.reset_ctrl(RESET_CTRL_XFER_QUEUES); self.exit_halt(config); @@ -1780,7 +1780,7 @@ self.start_xfer(config, &mut xfer); - if !xfer.done.wait_for_us(1_000_000_000, &mut self.yield_fn) { + if !xfer.done.wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { self.enter_halt(true, config); self.reset_ctrl(RESET_CTRL_XFER_QUEUES); self.exit_halt(config); @@ -1887,7 +1887,7 @@ let mut xfer = I3cXfer::new(cmds); self.start_xfer(config, &mut xfer); - if !xfer.done.wait_for_us(1_000_000_000, &mut self.yield_fn) { + if !xfer.done.wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { self.enter_halt(true, config); self.reset_ctrl(RESET_CTRL_XFER_QUEUES); self.exit_halt(config); @@ -1934,7 +1934,7 @@ let mut xfer = I3cXfer::new(cmds.as_mut_slice()); self.start_xfer(config, &mut xfer); - if !xfer.done.wait_for_us(1_000_000_000, &mut self.yield_fn) { + if !xfer.done.wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { self.enter_halt(true, config); self.reset_ctrl(RESET_CTRL_XFER_QUEUES); self.exit_halt(config); @@ -2157,7 +2157,7 @@ if !config .target_ibi_done - .wait_for_us(1_000_000_000, &mut self.yield_fn) + .wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { i3c_debug!(self.logger, "SIR timeout! Reset I3C controller"); self.enter_halt(false, config); @@ -2168,7 +2168,7 @@ if !config .target_data_done - .wait_for_us(1_000_000_000, &mut self.yield_fn) + .wait_for_us(I3C_OP_TIMEOUT_US, &mut self.yield_fn) { i3c_debug!(self.logger, "wait master read timeout! Reset queues"); self.i3c_disable(config.is_secondary);