summary refs log tree commit diff
diff options
context:
space:
mode:
authorJingkui Wang <jkwang@google.com>2018-07-18 11:14:00 -0700
committerchrome-bot <chrome-bot@chromium.org>2018-12-25 17:55:08 -0800
commit62affa765921321f3bba39db95b41f28b9fc4e03 (patch)
tree58941ac2cfd451b3462a35d472f4bcabbfee7aa3
parent212b45f77b069f245250030286d68f91b7ba8b16 (diff)
downloadcrosvm-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>
-rw-r--r--devices/src/usb/xhci/mod.rs3
-rw-r--r--devices/src/usb/xhci/xhci_regs.rs482
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(&register_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(&register_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(&register_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)
+}