diff options
author | Jingkui Wang <jkwang@google.com> | 2018-07-18 11:14:00 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-12-25 17:55:08 -0800 |
commit | 62affa765921321f3bba39db95b41f28b9fc4e03 (patch) | |
tree | 58941ac2cfd451b3462a35d472f4bcabbfee7aa3 /devices/src/usb | |
parent | 212b45f77b069f245250030286d68f91b7ba8b16 (diff) | |
download | crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar.gz crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar.bz2 crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar.lz crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar.xz crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.tar.zst crosvm-62affa765921321f3bba39db95b41f28b9fc4e03.zip |
usb: add xhci registers and mmio space.
Adds xhci register definitions. BUG=chromium:831850 TEST=cargo test Change-Id: I9b5d1a66031d291eb5408f22b88d6e8a1ece6865 Reviewed-on: https://chromium-review.googlesource.com/1142437 Commit-Ready: ChromeOS CL Exonerator Bot <chromiumos-cl-exonerator@appspot.gserviceaccount.com> Tested-by: Jingkui Wang <jkwang@google.com> Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Reviewed-by: Zach Reizner <zachr@chromium.org>
Diffstat (limited to 'devices/src/usb')
-rw-r--r-- | devices/src/usb/xhci/mod.rs | 3 | ||||
-rw-r--r-- | devices/src/usb/xhci/xhci_regs.rs | 482 |
2 files changed, 485 insertions, 0 deletions
diff --git a/devices/src/usb/xhci/mod.rs b/devices/src/usb/xhci/mod.rs index ca4d7fd..6802bb7 100644 --- a/devices/src/usb/xhci/mod.rs +++ b/devices/src/usb/xhci/mod.rs @@ -5,3 +5,6 @@ #[macro_use] mod mmio_register; mod mmio_space; + +#[allow(dead_code)] +mod xhci_regs; diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs new file mode 100644 index 0000000..44f9770 --- /dev/null +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -0,0 +1,482 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +use super::mmio_register::{BarOffset, Register, RegisterSpec, StaticRegister, StaticRegisterSpec}; +use super::mmio_space::MMIOSpace; + +/// Max interrupter number. +pub const MAX_INTERRUPTER: u8 = 1; +/// For port configuration, see register HCSPARAMS1, spcap1.3 and spcap2.3. +pub const MAX_SLOTS: u8 = 8; +/// Max port number. +pub const MAX_PORTS: u8 = 8; + +/// Cap register length. +pub const XHCI_CAPLENGTH: u8 = 0x20; +/// Offset for doorbell register. +pub const XHCI_DBOFF: u32 = 0x00002000; +/// Offset for RTs. +pub const XHCI_RTSOFF: u32 = 0x00003000; + +/// Bitmask for the usbcmd register, see spec 5.4.1. +pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0; +/// Bitmask for the usbcmd register, see spec 5.4.1. +pub const USB_CMD_RESET: u32 = 1u32 << 1; +/// Bitmask for the usbcmd register, see spec 5.4.1. +pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2; + +/// Bitmask for the usbsts register, see spec 5.4.2. +pub const USB_STS_HALTED: u32 = 1u32 << 0; +/// Bitmask for the usbsts register, see spec 5.4.2. +pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3; +/// Bitmask for the usbsts register, see spec 5.4.2. +pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4; +/// Bitmask for the usbsts register, see spec 5.4.2. +pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11; +/// Bitmask for the usbsts register, see spec 5.4.2. +pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C; + +/// Bitmask for the crcr register, see spec 5.4.5. +pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0; +/// Bitmask for the crcr register, see spec 5.4.5. +pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1; +/// Bitmask for the crcr register, see spec 5.4.5. +pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2; +/// Bitmask for the crcr register, see spec 5.4.5. +pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3; +/// Bitmask for the crcr register, see spec 5.4.5. +pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0; + +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_RESET: u32 = 1u32 << 4; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_POWER: u32 = 1u32 << 9; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31; +/// Bitmask for portsc register, see spec 5.4.8. +pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002; + +/// Bitmask for iman registers, see spec 5.5.2.1. +pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0; +/// Bitmask for iman registers, see spec 5.5.2.1. +pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1; +/// Bitmask for iman registers, see spec 5.5.2.1. +pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001; + +/// Bitmask for imod registers, see spec 5.5.2.2. +pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF; +/// Bitmask for imod registers, see spec 5.5.2.2. +pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16; + +/// Bitmask for erstsz registers, see 5.5.2.3. +pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF; + +/// Bitmask for erstba registers, see 5.5.2.3. +pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0; + +/// Bitmask for erdp registers, see 5.5.2.3. +pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3; +/// Bitmask for erdp registers, see 5.5.2.3. +pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0; +/// Bitmask for erdp registers, see 5.5.2.3. +pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008; + +/// Bitmask for doorbell registers. +pub const DOORBELL_TARGET: u32 = 0xFF; +/// Offset of stream id. +pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16; + +/// Bitmask for structural parameter registers. +pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00; +/// Offset of max interrupters. +pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8; +/// Mask to get max slots. +pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF; + +/// Bitmask for extended capabilities registers. +pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00; +/// Offset of port count. +pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8; + +/// Helper function for validating slot_id. +pub fn valid_slot_id(slot_id: u8) -> bool { + // slot id count from 1. + slot_id > 0 && slot_id <= MAX_SLOTS +} + +/// XhciRegs hold all xhci registers. +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>, +} + +/// This function returns mmio space definition for xhci. See Xhci spec chapter 5 +/// for details. +pub fn init_xhci_mmio_space_and_regs() -> (MMIOSpace, XhciRegs) { + let mut mmio = MMIOSpace::new(); + + /* Host Controller Capability Registers */ + mmio.add_register( + // CAPLENGTH + static_register!( + ty: u8, + offset: 0x00, + value: XHCI_CAPLENGTH, // Operation register start at offset 0x20 + ), + ); + mmio.add_register( + // HCIVERSION + static_register!( + ty: u16, + offset: 0x02, + value: 0x0110,// Revision 1.1 + ), + ); + mmio.add_register( + // HCSPARAMS1 + static_register!( + ty: u32, + offset: 0x04, + value: 0x08000108, // max_slots = 8, max_interrupters = 1, max_ports = 8 + ), + ); + + mmio.add_register( + // HCSPARAMS2 + static_register!( + ty: u32, + offset: 0x08, + // Maximum number of event ring segment table entries = 32k + // No scratchpad buffers. + value: 0xf0, + ), + ); + + mmio.add_register( + // HCSPARAM3 + static_register!( + ty: u32, + offset: 0x0c, + + // Exit latencies for U1 (standby with fast exit) and U2 (standby with + // slower exit) power states. We use the max values: + // - U1 to U0: < 10 us + // - U2 to U1: < 2047 us + value: 0x07FF000A, + ), + ); + + mmio.add_register( + // HCCPARAMS1 + static_register!( + ty: u32, + offset: 0x10, + // Supports 64 bit addressing + // Max primary stream array size = 0 (streams not supported). + // Extended capabilities pointer = 0xC000 offset from base. + value: 0x30000501, + ), + ); + mmio.add_register( + // DBOFF + static_register!( + ty: u32, + offset: 0x14, + value: XHCI_DBOFF, // Doorbell array offset 0x2000 from base. + ), + ); + + mmio.add_register( + // RTSOFF + static_register!( + ty: u32, + offset: 0x18, + value: XHCI_RTSOFF, // Runtime registers offset 0x3000 from base. + ), + ); + + mmio.add_register( + // HCCPARAMS2 + static_register!( + ty: u32, + offset: 0x1c, + value: 0, + ), + ); + /* End of Host Controller Capability Registers */ + + /* Host Controller Operational Registers */ + 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( + // Pagesize + 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: 8, // Must be equal to 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); + + // Portpmsc. + mmio.add_register_array(®ister_array!( + name: "portpmsc", + ty: u32, + cnt: 8, + base_offset: 0x424, + stride: 16, + reset_value: 0, + guest_writeable_mask: 0x0001FFFF, + guest_write_1_to_clear_mask: 0,)); + + // Portli + mmio.add_register_array(®ister_array!( + name: "portli", + ty: u32, + cnt: 8, + base_offset: 0x428, + stride: 16, + reset_value: 0, + guest_writeable_mask: 0, + guest_write_1_to_clear_mask: 0,)); + + // Porthlpmc + mmio.add_register_array(®ister_array!( + name: "porthlpmc", + ty: u32, + cnt: 8, + 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: 9, // Must be equal to max_ports + base_offset: 0x2000, + stride: 4, + reset_value: 0, + guest_writeable_mask: 0xFFFF00FF, + guest_write_1_to_clear_mask: 0,); + mmio.add_register_array(&doorbells); + + /*Runtime Registers */ + + mmio.add_register( + // mfindex + static_register!( + ty: u32, + offset: 0x3000, + value: 0, // 4 ports starting at port 5 + ), + ); + + /* Reg Array for interrupters */ + // Although the following should be register arrays, we only have one interrupter. + 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()); + + /* End of Runtime Registers */ + + let xhci_regs = XhciRegs { + usbcmd, + usbsts, + dnctrl, + crcr, + dcbaap, + config, + portsc, + doorbells, + iman, + imod, + erstsz, + erstba, + erdp, + }; + + /* End of Host Controller Operational Registers */ + + /* Extended Capability Registers */ + + // Extended capability registers. Base offset defined by hccparams1. + // Each set of 4 registers represents a "Supported Protocol" extended + // capability. The first capability indicates that ports 1-8 are USB 2.0. There is no USB 3.0 + // port for now. See xHCI spec 7.1 & 7.2 for more details. + mmio.add_register( + // spcap 1.1 + static_register!( + ty: u32, + offset: 0xc000, + // "Supported Protocol" capability. + // Not next capability. + // USB 2.0. Revision 2.0. + value: 0x02000002, + ), + ); + mmio.add_register( + // spcap 1.2 + static_register!( + ty: u32, + offset: 0xc004, + value: 0x20425355, // Name string = "USB " + ), + ); + mmio.add_register( + // spcap 1.3 + static_register!( + ty: u32, + offset: 0xc008, + value: 0x00000801, // 4 ports starting at port 1. + ), + ); + + mmio.add_register( + // spcap 1.4 + static_register!( + ty: u32, + offset: 0xc00c, + // The specification says that this shall be set to 0. + // Section 7.2.2.1.4. + value: 0, + ), + ); + /* End of Host Controller Operational Registers */ + + (mmio, xhci_regs) +} |