use crate::register_space::Register;
use crate::register_space::RegisterSpace;
pub const MAX_INTERRUPTER: u8 = 1;
pub const MAX_SLOTS: u8 = 16;
pub const USB2_PORTS_START: u8 = 0;
pub const USB2_PORTS_END: u8 = 8;
pub const USB3_PORTS_START: u8 = 8;
pub const USB3_PORTS_END: u8 = 16;
pub const MAX_PORTS: u8 = USB3_PORTS_END;
pub const XHCI_CAPLENGTH: u8 = 0x20;
pub const XHCI_DBOFF: u32 = 0x00002000;
pub const XHCI_RTSOFF: u32 = 0x00003000;
pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
pub const USB_CMD_RESET: u32 = 1u32 << 1;
pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
pub const USB_STS_HALTED: u32 = 1u32 << 0;
pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
pub const PORTSC_PORT_SPEED_MASK: u32 = 0x00003C00;
pub const PORTSC_PORT_SPEED_SHIFT: u32 = 10;
pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
pub const DOORBELL_TARGET: u32 = 0xFF;
pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
pub const HCCPARAMS1_MAX_PSA_SIZE_OFFSET: u32 = 12;
pub const MAX_PSA_SIZE: u32 = 3;
pub fn valid_slot_id(slot_id: u8) -> bool {
slot_id > 0 && slot_id <= MAX_SLOTS
}
pub fn valid_max_pstreams(max_pstreams: u8) -> bool {
max_pstreams <= MAX_PSA_SIZE as u8
}
pub fn valid_stream_id(stream_id: u16) -> bool {
stream_id > 0 && stream_id < (1 << (MAX_PSA_SIZE + 1))
}
pub struct XhciRegs {
pub usbcmd: Register<u32>,
pub usbsts: Register<u32>,
pub dnctrl: Register<u32>,
pub crcr: Register<u64>,
pub dcbaap: Register<u64>,
pub config: Register<u64>,
pub portsc: Vec<Register<u32>>,
pub doorbells: Vec<Register<u32>>,
pub iman: Register<u32>,
pub imod: Register<u32>,
pub erstsz: Register<u32>,
pub erstba: Register<u64>,
pub erdp: Register<u64>,
}
pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
let mut mmio = RegisterSpace::new();
mmio.add_register(
static_register!(
ty: u8,
offset: 0x00,
value: XHCI_CAPLENGTH,
),
);
mmio.add_register(
static_register!(
ty: u16,
offset: 0x02,
value: 0x0110,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x04,
value: 0x10000110,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x08,
value: 0xf0,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x0c,
value: 0x07FF000A,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x10,
value: 0x30000501 | (MAX_PSA_SIZE << HCCPARAMS1_MAX_PSA_SIZE_OFFSET),
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x14,
value: XHCI_DBOFF,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x18,
value: XHCI_RTSOFF,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x1c,
value: 0,
),
);
let usbcmd = register!(
name: "usbcmd",
ty: u32,
offset: 0x20,
reset_value: 0,
guest_writeable_mask: 0x00002F0F,
guest_write_1_to_clear_mask: 0,
);
mmio.add_register(usbcmd.clone());
let usbsts = register!(
name: "usbsts",
ty: u32,
offset: 0x24,
reset_value: 0x00000001,
guest_writeable_mask: 0x0000041C,
guest_write_1_to_clear_mask: 0x0000041C,
);
mmio.add_register(usbsts.clone());
mmio.add_register(
static_register!(
ty: u32,
offset: 0x28,
value: 0x00000001,
),
);
let dnctrl = register!(
name: "dnctrl",
ty: u32,
offset: 0x34,
reset_value: 0,
guest_writeable_mask: 0x0000FFFF,
guest_write_1_to_clear_mask: 0,
);
mmio.add_register(dnctrl.clone());
let crcr = register!(
name: "crcr",
ty: u64,
offset: 0x38,
reset_value: 9,
guest_writeable_mask: 0xFFFFFFFFFFFFFFC7,
guest_write_1_to_clear_mask: 0,
);
mmio.add_register(crcr.clone());
let dcbaap = register!(
name: "dcbaap",
ty: u64,
offset: 0x50,
reset_value: 0x0,
guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
guest_write_1_to_clear_mask: 0,
);
mmio.add_register(dcbaap.clone());
let config = register!(
name: "config",
ty: u64,
offset: 0x58,
reset_value: 0,
guest_writeable_mask: 0x0000003F,
guest_write_1_to_clear_mask: 0,
);
mmio.add_register(config.clone());
let portsc = register_array!(
name: "portsc",
ty: u32,
cnt: MAX_PORTS,
base_offset: 0x420,
stride: 16,
reset_value: 0x000002A0,
guest_writeable_mask: 0x8EFFC3F2,
guest_write_1_to_clear_mask: 0x00FE0002,);
mmio.add_register_array(&portsc);
mmio.add_register_array(®ister_array!(
name: "portpmsc",
ty: u32,
cnt: MAX_PORTS,
base_offset: 0x424,
stride: 16,
reset_value: 0,
guest_writeable_mask: 0x0001FFFF,
guest_write_1_to_clear_mask: 0,));
mmio.add_register_array(®ister_array!(
name: "portli",
ty: u32,
cnt: MAX_PORTS,
base_offset: 0x428,
stride: 16,
reset_value: 0,
guest_writeable_mask: 0,
guest_write_1_to_clear_mask: 0,));
mmio.add_register_array(®ister_array!(
name: "porthlpmc",
ty: u32,
cnt: MAX_PORTS,
base_offset: 0x42c,
stride: 16,
reset_value: 0,
guest_writeable_mask: 0x00003FFF,
guest_write_1_to_clear_mask: 0,));
let doorbells = register_array!(
name: "doorbell",
ty: u32,
cnt: MAX_SLOTS + 1,
base_offset: 0x2000,
stride: 4,
reset_value: 0,
guest_writeable_mask: 0xFFFF00FF,
guest_write_1_to_clear_mask: 0,);
mmio.add_register_array(&doorbells);
mmio.add_register(
static_register!(
ty: u32,
offset: 0x3000,
value: 0,
),
);
let iman = register!(
name: "iman",
ty: u32,
offset: 0x3020,
reset_value: 0,
guest_writeable_mask: 0x00000003,
guest_write_1_to_clear_mask: 0x00000001,);
mmio.add_register(iman.clone());
let imod = register!(
name: "imod",
ty: u32,
offset: 0x3024,
reset_value: 0x00000FA0,
guest_writeable_mask: 0xFFFFFFFF,
guest_write_1_to_clear_mask: 0,);
mmio.add_register(imod.clone());
let erstsz = register!(
name: "erstsz",
ty: u32,
offset: 0x3028,
reset_value: 0,
guest_writeable_mask: 0x0000FFFF,
guest_write_1_to_clear_mask: 0,);
mmio.add_register(erstsz.clone());
let erstba = register!(
name: "erstba",
ty: u64,
offset: 0x3030,
reset_value: 0,
guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
guest_write_1_to_clear_mask: 0,);
mmio.add_register(erstba.clone());
let erdp = register!(
name: "erdp",
ty: u64,
offset: 0x3038,
reset_value: 0,
guest_writeable_mask: 0xFFFFFFFFFFFFFFFF,
guest_write_1_to_clear_mask: 0x0000000000000008,);
mmio.add_register(erdp.clone());
let xhci_regs = XhciRegs {
usbcmd,
usbsts,
dnctrl,
crcr,
dcbaap,
config,
portsc,
doorbells,
iman,
imod,
erstsz,
erstba,
erdp,
};
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc000,
value: 0x02004002,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc004,
value: 0x20425355,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc008,
value: 0x00000801,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc00c,
value: 0,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc100,
value: 0x03000002,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc104,
value: 0x20425355,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc108,
value: 0x00000809,
),
);
mmio.add_register(
static_register!(
ty: u32,
offset: 0xc10c,
value: 0,
),
);
(mmio, xhci_regs)
}