blob: 76d29052a88f90c36e8be90592847c19ca502ae6 [file]
// Licensed under the Apache-2.0 license
//! I3C hardware constants and register definitions
//!
//! # Register Map
//! | Offset | Register | Description |
//! |--------|-----------------------|--------------------------------|
//! | 0x0C | COMMAND_QUEUE_PORT | Command queue port |
//! | 0x10 | RESPONSE_QUEUE_PORT | Response queue port |
//! | 0x18 | IBI_QUEUE_STATUS | IBI queue status |
//! | 0x3C | INTR_STATUS | Interrupt status |
//! | 0x40 | INTR_STATUS_EN | Interrupt status enable |
//! | 0x44 | INTR_SIGNAL_EN | Interrupt signal enable |
// =============================================================================
// Message Flags
// =============================================================================
/// I3C message write flag
pub const I3C_MSG_WRITE: u8 = 0x0;
/// I3C message read flag
pub const I3C_MSG_READ: u8 = 0x1;
/// I3C message stop flag
pub const I3C_MSG_STOP: u8 = 0x2;
// =============================================================================
// I2C Timing Constants (nanoseconds)
// =============================================================================
// Standard mode (100 kHz)
pub const I3C_BUS_I2C_STD_TLOW_MIN_NS: u32 = 4_700;
pub const I3C_BUS_I2C_STD_THIGH_MIN_NS: u32 = 4_000;
pub const I3C_BUS_I2C_STD_TR_MAX_NS: u32 = 1_000;
pub const I3C_BUS_I2C_STD_TF_MAX_NS: u32 = 300;
// Fast mode (400 kHz)
pub const I3C_BUS_I2C_FM_TLOW_MIN_NS: u32 = 1_300;
pub const I3C_BUS_I2C_FM_THIGH_MIN_NS: u32 = 600;
pub const I3C_BUS_I2C_FM_TR_MAX_NS: u32 = 300;
pub const I3C_BUS_I2C_FM_TF_MAX_NS: u32 = 300;
// Fast mode plus (1 MHz)
pub const I3C_BUS_I2C_FMP_TLOW_MIN_NS: u32 = 500;
pub const I3C_BUS_I2C_FMP_THIGH_MIN_NS: u32 = 260;
pub const I3C_BUS_I2C_FMP_TR_MAX_NS: u32 = 120;
pub const I3C_BUS_I2C_FMP_TF_MAX_NS: u32 = 120;
// I3C timing
pub const I3C_BUS_THIGH_MAX_NS: u32 = 41;
/// Nanoseconds per second
pub const NSEC_PER_SEC: u32 = 1_000_000_000;
// =============================================================================
// SDA TX Hold Configuration
// =============================================================================
pub const SDA_TX_HOLD_MIN: u32 = 0b001;
pub const SDA_TX_HOLD_MAX: u32 = 0b111;
pub const SDA_TX_HOLD_MASK: u32 = 0x0007_0000; // bits 18:16
// =============================================================================
// Slave Configuration
// =============================================================================
pub const SLV_DCR_MASK: u32 = 0x0000_ff00;
pub const SLV_EVENT_CTRL: u32 = 0x38;
pub const SLV_EVENT_CTRL_MWL_UPD: u32 = bit(7);
pub const SLV_EVENT_CTRL_MRL_UPD: u32 = bit(6);
pub const SLV_EVENT_CTRL_HJ_REQ: u32 = bit(3);
pub const SLV_EVENT_CTRL_SIR_EN: u32 = bit(0);
// =============================================================================
// I3C Global Register Bits
// =============================================================================
pub const I3CG_REG1_SCL_IN_SW_MODE_VAL: u32 = bit(23);
pub const I3CG_REG1_SDA_IN_SW_MODE_VAL: u32 = bit(27);
pub const I3CG_REG1_SCL_IN_SW_MODE_EN: u32 = bit(28);
pub const I3CG_REG1_SDA_IN_SW_MODE_EN: u32 = bit(29);
// =============================================================================
// Transfer Status
// =============================================================================
pub const CM_TFR_STS_MASTER_HALT: u8 = 0xf;
pub const CM_TFR_STS_TARGET_HALT: u8 = 0x6;
// =============================================================================
// Command Queue Port (0x0C)
// =============================================================================
pub const COMMAND_QUEUE_PORT: u32 = 0x0c;
// Command port bit flags
pub const COMMAND_PORT_PEC: u32 = bit(31);
pub const COMMAND_PORT_TOC: u32 = bit(30);
pub const COMMAND_PORT_READ_TRANSFER: u32 = bit(28);
pub const COMMAND_PORT_SDAP: u32 = bit(27);
pub const COMMAND_PORT_ROC: u32 = bit(26);
pub const COMMAND_PORT_DBP: u32 = bit(25);
pub const COMMAND_PORT_CP: u32 = bit(15);
// Command port field masks
pub const COMMAND_PORT_SPEED: u32 = bits(23, 21);
pub const COMMAND_PORT_DEV_INDEX: u32 = bits(20, 16);
pub const COMMAND_PORT_CMD: u32 = bits(14, 7);
pub const COMMAND_PORT_TID: u32 = bits(6, 3);
pub const COMMAND_PORT_ARG_DB: u32 = bits(15, 8);
pub const COMMAND_PORT_ARG_DATA_LEN: u32 = bits(31, 16);
pub const COMMAND_PORT_ATTR: u32 = bits(2, 0);
pub const COMMAND_PORT_DEV_COUNT: u32 = bits(25, 21);
// =============================================================================
// Transaction IDs
// =============================================================================
pub const TID_TARGET_IBI: u32 = 0x1;
pub const TID_TARGET_RD_DATA: u32 = 0x2;
pub const TID_TARGET_MASTER_WR: u32 = 0x8;
pub const TID_TARGET_MASTER_DEF: u32 = 0xf;
// =============================================================================
// Command Attributes
// =============================================================================
pub const COMMAND_ATTR_XFER_CMD: u32 = 0;
pub const COMMAND_ATTR_XFER_ARG: u32 = 1;
pub const COMMAND_ATTR_SHORT_ARG: u32 = 2;
pub const COMMAND_ATTR_ADDR_ASSGN_CMD: u32 = 3;
pub const COMMAND_ATTR_SLAVE_DATA_CMD: u32 = 0;
// =============================================================================
// Device Address Table
// =============================================================================
pub const DEV_ADDR_TABLE_LEGACY_I2C_DEV: u32 = bit(31);
pub const DEV_ADDR_TABLE_DYNAMIC_ADDR: u32 = bits(23, 16);
pub const DEV_ADDR_TABLE_MR_REJECT: u32 = bit(14);
pub const DEV_ADDR_TABLE_SIR_REJECT: u32 = bit(13);
pub const DEV_ADDR_TABLE_IBI_MDB: u32 = bit(12);
pub const DEV_ADDR_TABLE_IBI_PEC: u32 = bit(11);
pub const DEV_ADDR_TABLE_STATIC_ADDR: u32 = bits(6, 0);
// =============================================================================
// IBI Queue Status (0x18)
// =============================================================================
pub const IBI_QUEUE_STATUS: u32 = 0x18;
pub const IBIQ_STATUS_IBI_ID: u32 = bits(15, 8);
pub const IBIQ_STATUS_IBI_ID_SHIFT: u32 = 8;
pub const IBIQ_STATUS_IBI_DATA_LEN: u32 = bits(7, 0);
pub const IBIQ_STATUS_IBI_DATA_LEN_SHIFT: u32 = 0;
// =============================================================================
// Reset Control
// =============================================================================
pub const RESET_CTRL_IBI_QUEUE: u32 = bit(5);
pub const RESET_CTRL_RX_FIFO: u32 = bit(4);
pub const RESET_CTRL_TX_FIFO: u32 = bit(3);
pub const RESET_CTRL_RESP_QUEUE: u32 = bit(2);
pub const RESET_CTRL_CMD_QUEUE: u32 = bit(1);
pub const RESET_CTRL_SOFT: u32 = bit(0);
pub const RESET_CTRL_ALL: u32 = RESET_CTRL_IBI_QUEUE
| RESET_CTRL_RX_FIFO
| RESET_CTRL_TX_FIFO
| RESET_CTRL_RESP_QUEUE
| RESET_CTRL_CMD_QUEUE
| RESET_CTRL_SOFT;
pub const RESET_CTRL_QUEUES: u32 = RESET_CTRL_IBI_QUEUE
| RESET_CTRL_RX_FIFO
| RESET_CTRL_TX_FIFO
| RESET_CTRL_RESP_QUEUE
| RESET_CTRL_CMD_QUEUE;
pub const RESET_CTRL_XFER_QUEUES: u32 =
RESET_CTRL_RX_FIFO | RESET_CTRL_TX_FIFO | RESET_CTRL_RESP_QUEUE | RESET_CTRL_CMD_QUEUE;
// =============================================================================
// Response Queue Port (0x10)
// =============================================================================
pub const RESPONSE_QUEUE_PORT: u32 = 0x10;
pub const RESPONSE_PORT_ERR_STATUS_SHIFT: u32 = 28;
pub const RESPONSE_PORT_ERR_STATUS_MASK: u32 = genmask(31, 28);
pub const RESPONSE_PORT_TID_SHIFT: u32 = 24;
pub const RESPONSE_PORT_TID_MASK: u32 = genmask(27, 24);
pub const RESPONSE_PORT_DATA_LEN_SHIFT: u32 = 0;
pub const RESPONSE_PORT_DATA_LEN_MASK: u32 = genmask(15, 0);
// Response error codes
pub const RESPONSE_NO_ERROR: u32 = 0;
pub const RESPONSE_ERROR_CRC: u32 = 1;
pub const RESPONSE_ERROR_PARITY: u32 = 2;
pub const RESPONSE_ERROR_FRAME: u32 = 3;
pub const RESPONSE_ERROR_IBA_NACK: u32 = 4;
pub const RESPONSE_ERROR_ADDRESS_NACK: u32 = 5;
pub const RESPONSE_ERROR_OVER_UNDER_FLOW: u32 = 6;
pub const RESPONSE_ERROR_TRANSF_ABORT: u32 = 8;
pub const RESPONSE_ERROR_I2C_W_NACK_ERR: u32 = 9;
pub const RESPONSE_ERROR_EARLY_TERMINATE: u32 = 10;
pub const RESPONSE_ERROR_PEC_ERR: u32 = 12;
// =============================================================================
// Interrupt Registers (0x3C - 0x48)
// =============================================================================
pub const INTR_STATUS: u32 = 0x3c;
pub const INTR_STATUS_EN: u32 = 0x40;
pub const INTR_SIGNAL_EN: u32 = 0x44;
pub const INTR_FORCE: u32 = 0x48;
// Interrupt status bits
pub const INTR_BUSOWNER_UPDATE_STAT: u32 = bit(13);
pub const INTR_IBI_UPDATED_STAT: u32 = bit(12);
pub const INTR_READ_REQ_RECV_STAT: u32 = bit(11);
pub const INTR_DEFSLV_STAT: u32 = bit(10);
pub const INTR_TRANSFER_ERR_STAT: u32 = bit(9);
pub const INTR_DYN_ADDR_ASSGN_STAT: u32 = bit(8);
pub const INTR_CCC_UPDATED_STAT: u32 = bit(6);
pub const INTR_TRANSFER_ABORT_STAT: u32 = bit(5);
pub const INTR_RESP_READY_STAT: u32 = bit(4);
pub const INTR_CMD_QUEUE_READY_STAT: u32 = bit(3);
pub const INTR_IBI_THLD_STAT: u32 = bit(2);
pub const INTR_RX_THLD_STAT: u32 = bit(1);
pub const INTR_TX_THLD_STAT: u32 = bit(0);
// BCR bits
pub const I3C_BCR_IBI_PAYLOAD_HAS_DATA_BYTE: u32 = bit(2);
// =============================================================================
// Address Constants
// =============================================================================
/// I3C broadcast address
pub const I3C_BROADCAST_ADDR: u8 = 0x7E;
/// Maximum I3C address
pub const I3C_MAX_ADDR: u8 = 0x7F;
// =============================================================================
// Hardware Limits
// =============================================================================
/// Maximum number of commands in a single transfer
pub const MAX_CMDS: usize = 32;
/// Maximum number of I3C buses supported
pub const MAX_BUSES: usize = 4;
/// Maximum devices per bus
pub const MAX_DEVICES_PER_BUS: usize = 8;
// =============================================================================
// CCC (Common Command Code) Constants
// =============================================================================
pub const I3C_CCC_RSTDAA: u8 = 0x06;
pub const I3C_CCC_ENTDAA: u8 = 0x07;
pub const I3C_CCC_SETHID: u8 = 0x61;
pub const I3C_CCC_DEVCTRL: u8 = 0x62;
pub const I3C_CCC_SETDASA: u8 = 0x87;
pub const I3C_CCC_SETNEWDA: u8 = 0x88;
pub const I3C_CCC_GETPID: u8 = 0x8D;
pub const I3C_CCC_GETBCR: u8 = 0x8E;
pub const I3C_CCC_GETSTATUS: u8 = 0x90;
// CCC event bits
pub const I3C_CCC_EVT_INTR: u8 = 1 << 0;
pub const I3C_CCC_EVT_CR: u8 = 1 << 1;
pub const I3C_CCC_EVT_HJ: u8 = 1 << 3;
pub const I3C_CCC_EVT_ALL: u8 = I3C_CCC_EVT_INTR | I3C_CCC_EVT_CR | I3C_CCC_EVT_HJ;
// =============================================================================
// Helper Functions
// =============================================================================
/// Create a single bit mask at position `n`
#[inline]
#[must_use]
pub const fn bit(n: u32) -> u32 {
1 << n
}
/// Create a bit mask from bit `l` to bit `h` (inclusive)
#[inline]
#[must_use]
pub const fn bits(h: u32, l: u32) -> u32 {
((1u32 << (h - l + 1)) - 1) << l
}
/// Prepare a value for a masked field
#[inline]
#[must_use]
pub const fn field_prep(mask: u32, val: u32) -> u32 {
(val << mask.trailing_zeros()) & mask
}
/// Extract a value from a masked field
#[inline]
#[must_use]
pub const fn field_get(val: u32, mask: u32, shift: u32) -> u32 {
(val & mask) >> shift
}
/// Generate a mask from MSB to LSB
#[inline]
#[must_use]
pub const fn genmask(msb: u32, lsb: u32) -> u32 {
let width = msb - lsb + 1;
if width >= 32 {
u32::MAX
} else {
((1u32 << width) - 1) << lsb
}
}