diff options
author | Michael Brown | 2015-02-02 15:40:06 +0100 |
---|---|---|
committer | Michael Brown | 2015-02-03 13:33:28 +0100 |
commit | fd53ada87cc3b715738e01d5470829b9948c1e09 (patch) | |
tree | 9d61593756103fff88b190647dbdae5416491f71 /src/drivers/usb/xhci.h | |
parent | [usb] Add basic support for USB hubs (diff) | |
download | ipxe-fd53ada87cc3b715738e01d5470829b9948c1e09.tar.gz ipxe-fd53ada87cc3b715738e01d5470829b9948c1e09.tar.xz ipxe-fd53ada87cc3b715738e01d5470829b9948c1e09.zip |
[usb] Add support for xHCI host controllers
Signed-off-by: Michael Brown <mcb30@ipxe.org>
Diffstat (limited to 'src/drivers/usb/xhci.h')
-rw-r--r-- | src/drivers/usb/xhci.h | 1066 |
1 files changed, 1066 insertions, 0 deletions
diff --git a/src/drivers/usb/xhci.h b/src/drivers/usb/xhci.h new file mode 100644 index 00000000..b9f6d9fe --- /dev/null +++ b/src/drivers/usb/xhci.h @@ -0,0 +1,1066 @@ +#ifndef _IPXE_XHCI_H +#define _IPXE_XHCI_H + +/** @file + * + * USB eXtensible Host Controller Interface (xHCI) driver + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +#include <assert.h> +#include <ipxe/pci.h> +#include <ipxe/uaccess.h> +#include <ipxe/usb.h> + +/** Minimum alignment required for data structures + * + * With the exception of the scratchpad buffer pages (which are + * page-aligned), data structures used by xHCI generally require from + * 16 to 64 byte alignment and must not cross an (xHCI) page boundary. + * We simplify this requirement by aligning each structure on its own + * size, with a minimum of a 64 byte alignment. + */ +#define XHCI_MIN_ALIGN 64 + +/** xHCI PCI BAR */ +#define XHCI_BAR PCI_BASE_ADDRESS_0 + +/** Capability register length */ +#define XHCI_CAP_CAPLENGTH 0x00 + +/** Host controller interface version number */ +#define XHCI_CAP_HCIVERSION 0x02 + +/** Structural parameters 1 */ +#define XHCI_CAP_HCSPARAMS1 0x04 + +/** Number of device slots */ +#define XHCI_HCSPARAMS1_SLOTS(params) ( ( (params) >> 0 ) & 0xff ) + +/** Number of interrupters */ +#define XHCI_HCSPARAMS1_INTRS(params) ( ( (params) >> 8 ) & 0x3ff ) + +/** Number of ports */ +#define XHCI_HCSPARAMS1_PORTS(params) ( ( (params) >> 24 ) & 0xff ) + +/** Structural parameters 2 */ +#define XHCI_CAP_HCSPARAMS2 0x08 + +/** Number of page-sized scratchpad buffers */ +#define XHCI_HCSPARAMS2_SCRATCHPADS(params) \ + ( ( ( (params) >> 16 ) & 0x3e0 ) | ( ( (params) >> 27 ) & 0x1f ) ) + +/** Capability parameters */ +#define XHCI_CAP_HCCPARAMS1 0x10 + +/** 64-bit addressing capability */ +#define XHCI_HCCPARAMS1_ADDR64(params) ( ( (params) >> 0 ) & 0x1 ) + +/** Context size shift */ +#define XHCI_HCCPARAMS1_CSZ_SHIFT(params) ( 5 + ( ( (params) >> 2 ) & 0x1 ) ) + +/** xHCI extended capabilities pointer */ +#define XHCI_HCCPARAMS1_XECP(params) ( ( ( (params) >> 16 ) & 0xffff ) << 2 ) + +/** Doorbell offset */ +#define XHCI_CAP_DBOFF 0x14 + +/** Runtime register space offset */ +#define XHCI_CAP_RTSOFF 0x18 + +/** xHCI extended capability ID */ +#define XHCI_XECP_ID(xecp) ( ( (xecp) >> 0 ) & 0xff ) + +/** Next xHCI extended capability pointer */ +#define XHCI_XECP_NEXT(xecp) ( ( ( (xecp) >> 8 ) & 0xff ) << 2 ) + +/** USB legacy support extended capability */ +#define XHCI_XECP_ID_LEGACY 1 + +/** USB legacy support BIOS owned semaphore */ +#define XHCI_USBLEGSUP_BIOS 0x02 + +/** USB legacy support BIOS ownership flag */ +#define XHCI_USBLEGSUP_BIOS_OWNED 0x01 + +/** USB legacy support OS owned semaphore */ +#define XHCI_USBLEGSUP_OS 0x03 + +/** USB legacy support OS ownership flag */ +#define XHCI_USBLEGSUP_OS_OWNED 0x01 + +/** USB legacy support control/status */ +#define XHCI_USBLEGSUP_CTLSTS 0x04 + +/** Supported protocol extended capability */ +#define XHCI_XECP_ID_SUPPORTED 2 + +/** Supported protocol revision */ +#define XHCI_SUPPORTED_REVISION 0x00 + +/** Supported protocol minor revision */ +#define XHCI_SUPPORTED_REVISION_VER(revision) ( ( (revision) >> 16 ) & 0xffff ) + +/** Supported protocol name */ +#define XHCI_SUPPORTED_NAME 0x04 + +/** Supported protocol ports */ +#define XHCI_SUPPORTED_PORTS 0x08 + +/** Supported protocol port offset */ +#define XHCI_SUPPORTED_PORTS_OFFSET(ports) ( ( (ports) >> 0 ) & 0xff ) + +/** Supported protocol port count */ +#define XHCI_SUPPORTED_PORTS_COUNT(ports) ( ( (ports) >> 8 ) & 0xff ) + +/** Supported protocol PSI count */ +#define XHCI_SUPPORTED_PORTS_PSIC(ports) ( ( (ports) >> 28 ) & 0x0f ) + +/** Supported protocol slot */ +#define XHCI_SUPPORTED_SLOT 0x0c + +/** Supported protocol slot type */ +#define XHCI_SUPPORTED_SLOT_TYPE(slot) ( ( (slot) >> 0 ) & 0x1f ) + +/** Supported protocol PSI */ +#define XHCI_SUPPORTED_PSI(index) ( 0x10 + ( (index) * 4 ) ) + +/** Supported protocol PSI value */ +#define XHCI_SUPPORTED_PSI_VALUE(psi) ( ( (psi) >> 0 ) & 0x0f ) + +/** Supported protocol PSI mantissa */ +#define XHCI_SUPPORTED_PSI_MANTISSA(psi) ( ( (psi) >> 16 ) & 0xffff ) + +/** Supported protocol PSI exponent */ +#define XHCI_SUPPORTED_PSI_EXPONENT(psi) ( ( (psi) >> 4 ) & 0x03 ) + +/** Default PSI values */ +enum xhci_default_psi_value { + /** Full speed (12Mbps) */ + XHCI_SPEED_FULL = 1, + /** Low speed (1.5Mbps) */ + XHCI_SPEED_LOW = 2, + /** High speed (480Mbps) */ + XHCI_SPEED_HIGH = 3, + /** Super speed */ + XHCI_SPEED_SUPER = 4, +}; + +/** USB command register */ +#define XHCI_OP_USBCMD 0x00 + +/** Run/stop */ +#define XHCI_USBCMD_RUN 0x00000001UL + +/** Host controller reset */ +#define XHCI_USBCMD_HCRST 0x00000002UL + +/** USB status register */ +#define XHCI_OP_USBSTS 0x04 + +/** Host controller halted */ +#define XHCI_USBSTS_HCH 0x00000001UL + +/** Page size register */ +#define XHCI_OP_PAGESIZE 0x08 + +/** Page size */ +#define XHCI_PAGESIZE(pagesize) ( (pagesize) << 12 ) + +/** Device notifcation control register */ +#define XHCI_OP_DNCTRL 0x14 + +/** Command ring control register */ +#define XHCI_OP_CRCR 0x18 + +/** Command ring cycle state */ +#define XHCI_CRCR_RCS 0x00000001UL + +/** Command ring running */ +#define XHCI_CRCR_CRR 0x00000008UL + +/** Device context base address array pointer */ +#define XHCI_OP_DCBAAP 0x30 + +/** Configure register */ +#define XHCI_OP_CONFIG 0x38 + +/** Maximum device slots enabled */ +#define XHCI_CONFIG_MAX_SLOTS_EN(slots) ( (slots) << 0 ) + +/** Maximum device slots enabled mask */ +#define XHCI_CONFIG_MAX_SLOTS_EN_MASK \ + XHCI_CONFIG_MAX_SLOTS_EN ( 0xff ) + +/** Port status and control register */ +#define XHCI_OP_PORTSC(port) ( 0x400 - 0x10 + ( (port) << 4 ) ) + +/** Current connect status */ +#define XHCI_PORTSC_CCS 0x00000001UL + +/** Port enabled */ +#define XHCI_PORTSC_PED 0x00000002UL + +/** Port reset */ +#define XHCI_PORTSC_PR 0x00000010UL + +/** Port link state */ +#define XHCI_PORTSC_PLS(pls) ( (pls) << 5 ) + +/** Disabled port link state */ +#define XHCI_PORTSC_PLS_DISABLED XHCI_PORTSC_PLS ( 4 ) + +/** RxDetect port link state */ +#define XHCI_PORTSC_PLS_RXDETECT XHCI_PORTSC_PLS ( 5 ) + +/** Port link state mask */ +#define XHCI_PORTSC_PLS_MASK XHCI_PORTSC_PLS ( 0xf ) + +/** Port power */ +#define XHCI_PORTSC_PP 0x00000200UL + +/** Time to delay after enabling power to a port */ +#define XHCI_PORT_POWER_DELAY_MS 20 + +/** Port speed ID value */ +#define XHCI_PORTSC_PSIV(portsc) ( ( (portsc) >> 10 ) & 0xf ) + +/** Port indicator control */ +#define XHCI_PORTSC_PIC(indicators) ( (indicators) << 14 ) + +/** Port indicator control mask */ +#define XHCI_PORTSC_PIC_MASK XHCI_PORTSC_PIC ( 3 ) + +/** Port link state write strobe */ +#define XHCI_PORTSC_LWS 0x00010000UL + +/** Connect status change */ +#define XHCI_PORTSC_CSC 0x00020000UL + +/** Port enabled/disabled change */ +#define XHCI_PORTSC_PEC 0x00040000UL + +/** Warm port reset change */ +#define XHCI_PORTSC_WRC 0x00080000UL + +/** Over-current change */ +#define XHCI_PORTSC_OCC 0x00100000UL + +/** Port reset change */ +#define XHCI_PORTSC_PRC 0x00200000UL + +/** Port link state change */ +#define XHCI_PORTSC_PLC 0x00400000UL + +/** Port config error change */ +#define XHCI_PORTSC_CEC 0x00800000UL + +/** Port status change mask */ +#define XHCI_PORTSC_CHANGE \ + ( XHCI_PORTSC_CSC | XHCI_PORTSC_PEC | XHCI_PORTSC_WRC | \ + XHCI_PORTSC_OCC | XHCI_PORTSC_PRC | XHCI_PORTSC_PLC | \ + XHCI_PORTSC_CEC ) + +/** Port status and control bits which should be preserved + * + * The port status and control register is a horrendous mix of + * differing semantics. Some bits are written to only when a separate + * write strobe bit is set. Some bits should be preserved when + * modifying other bits. Some bits will be cleared if written back as + * a one. Most excitingly, the "port enabled" bit has the semantics + * that 1=enabled, 0=disabled, yet writing a 1 will disable the port. + */ +#define XHCI_PORTSC_PRESERVE ( XHCI_PORTSC_PP | XHCI_PORTSC_PIC_MASK ) + +/** Port power management status and control register */ +#define XHCI_OP_PORTPMSC(port) ( 0x404 - 0x10 + ( (port) << 4 ) ) + +/** Port link info register */ +#define XHCI_OP_PORTLI(port) ( 0x408 - 0x10 + ( (port) << 4 ) ) + +/** Port hardware link power management control register */ +#define XHCI_OP_PORTHLPMC(port) ( 0x40c - 0x10 + ( (port) << 4 ) ) + +/** Event ring segment table size register */ +#define XHCI_RUN_ERSTSZ(intr) ( 0x28 + ( (intr) << 5 ) ) + +/** Event ring segment table base address register */ +#define XHCI_RUN_ERSTBA(intr) ( 0x30 + ( (intr) << 5 ) ) + +/** Event ring dequeue pointer register */ +#define XHCI_RUN_ERDP(intr) ( 0x38 + ( (intr) << 5 ) ) + +/** A transfer request block template */ +struct xhci_trb_template { + /** Parameter */ + uint64_t parameter; + /** Status */ + uint32_t status; + /** Control */ + uint32_t control; +}; + +/** A transfer request block */ +struct xhci_trb_common { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint16_t reserved_c; +} __attribute__ (( packed )); + +/** Transfer request block cycle bit flag */ +#define XHCI_TRB_C 0x01 + +/** Transfer request block toggle cycle bit flag */ +#define XHCI_TRB_TC 0x02 + +/** Transfer request block chain flag */ +#define XHCI_TRB_CH 0x10 + +/** Transfer request block interrupt on completion flag */ +#define XHCI_TRB_IOC 0x20 + +/** Transfer request block immediate data flag */ +#define XHCI_TRB_IDT 0x40 + +/** Transfer request block type */ +#define XHCI_TRB_TYPE(type) ( (type) << 2 ) + +/** Transfer request block type mask */ +#define XHCI_TRB_TYPE_MASK XHCI_TRB_TYPE ( 0x3f ) + +/** A normal transfer request block */ +struct xhci_trb_normal { + /** Data buffer */ + uint64_t data; + /** Length */ + uint32_t len; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint16_t reserved; +} __attribute__ (( packed )); + +/** A normal transfer request block */ +#define XHCI_TRB_NORMAL XHCI_TRB_TYPE ( 1 ) + +/** Construct TD size field */ +#define XHCI_TD_SIZE(remaining) \ + ( ( ( (remaining) <= 0xf ) ? remaining : 0xf ) << 17 ) + +/** A setup stage transfer request block */ +struct xhci_trb_setup { + /** Setup packet */ + struct usb_setup_packet packet; + /** Length */ + uint32_t len; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Transfer direction */ + uint8_t direction; + /** Reserved */ + uint8_t reserved; +} __attribute__ (( packed )); + +/** A setup stage transfer request block */ +#define XHCI_TRB_SETUP XHCI_TRB_TYPE ( 2 ) + +/** Setup stage input data direction */ +#define XHCI_SETUP_IN 3 + +/** Setup stage output data direction */ +#define XHCI_SETUP_OUT 2 + +/** A data stage transfer request block */ +struct xhci_trb_data { + /** Data buffer */ + uint64_t data; + /** Length */ + uint32_t len; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Transfer direction */ + uint8_t direction; + /** Reserved */ + uint8_t reserved; +} __attribute__ (( packed )); + +/** A data stage transfer request block */ +#define XHCI_TRB_DATA XHCI_TRB_TYPE ( 3 ) + +/** Input data direction */ +#define XHCI_DATA_IN 0x01 + +/** Output data direction */ +#define XHCI_DATA_OUT 0x00 + +/** A status stage transfer request block */ +struct xhci_trb_status { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Direction */ + uint8_t direction; + /** Reserved */ + uint8_t reserved_c; +} __attribute__ (( packed )); + +/** A status stage transfer request block */ +#define XHCI_TRB_STATUS XHCI_TRB_TYPE ( 4 ) + +/** Input status direction */ +#define XHCI_STATUS_IN 0x01 + +/** Output status direction */ +#define XHCI_STATUS_OUT 0x00 + +/** A link transfer request block */ +struct xhci_trb_link { + /** Next ring segment */ + uint64_t next; + /** Reserved */ + uint32_t reserved_a; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint16_t reserved_c; +} __attribute__ (( packed )); + +/** A link transfer request block */ +#define XHCI_TRB_LINK XHCI_TRB_TYPE ( 6 ) + +/** A no-op transfer request block */ +#define XHCI_TRB_NOP XHCI_TRB_TYPE ( 8 ) + +/** An enable slot transfer request block */ +struct xhci_trb_enable_slot { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Slot type */ + uint8_t slot; + /** Reserved */ + uint8_t reserved_c; +} __attribute__ (( packed )); + +/** An enable slot transfer request block */ +#define XHCI_TRB_ENABLE_SLOT XHCI_TRB_TYPE ( 9 ) + +/** A disable slot transfer request block */ +struct xhci_trb_disable_slot { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint8_t reserved_c; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A disable slot transfer request block */ +#define XHCI_TRB_DISABLE_SLOT XHCI_TRB_TYPE ( 10 ) + +/** A context transfer request block */ +struct xhci_trb_context { + /** Input context */ + uint64_t input; + /** Reserved */ + uint32_t reserved_a; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint8_t reserved_b; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** An address device transfer request block */ +#define XHCI_TRB_ADDRESS_DEVICE XHCI_TRB_TYPE ( 11 ) + +/** A configure endpoint transfer request block */ +#define XHCI_TRB_CONFIGURE_ENDPOINT XHCI_TRB_TYPE ( 12 ) + +/** An evaluate context transfer request block */ +#define XHCI_TRB_EVALUATE_CONTEXT XHCI_TRB_TYPE ( 13 ) + +/** A reset endpoint transfer request block */ +struct xhci_trb_reset_endpoint { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Endpoint ID */ + uint8_t endpoint; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A reset endpoint transfer request block */ +#define XHCI_TRB_RESET_ENDPOINT XHCI_TRB_TYPE ( 14 ) + +/** A stop endpoint transfer request block */ +struct xhci_trb_stop_endpoint { + /** Reserved */ + uint64_t reserved_a; + /** Reserved */ + uint32_t reserved_b; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Endpoint ID */ + uint8_t endpoint; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A stop endpoint transfer request block */ +#define XHCI_TRB_STOP_ENDPOINT XHCI_TRB_TYPE ( 15 ) + +/** A set transfer ring dequeue pointer transfer request block */ +struct xhci_trb_set_tr_dequeue_pointer { + /** Dequeue pointer */ + uint64_t dequeue; + /** Reserved */ + uint32_t reserved; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Endpoint ID */ + uint8_t endpoint; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A set transfer ring dequeue pointer transfer request block */ +#define XHCI_TRB_SET_TR_DEQUEUE_POINTER XHCI_TRB_TYPE ( 16 ) + +/** A no-op command transfer request block */ +#define XHCI_TRB_NOP_CMD XHCI_TRB_TYPE ( 23 ) + +/** A transfer event transfer request block */ +struct xhci_trb_transfer { + /** Transfer TRB pointer */ + uint64_t transfer; + /** Residual transfer length */ + uint16_t residual; + /** Reserved */ + uint8_t reserved; + /** Completion code */ + uint8_t code; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Endpoint ID */ + uint8_t endpoint; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A transfer event transfer request block */ +#define XHCI_TRB_TRANSFER XHCI_TRB_TYPE ( 32 ) + +/** A command completion event transfer request block */ +struct xhci_trb_complete { + /** Command TRB pointer */ + uint64_t command; + /** Parameter */ + uint8_t parameter[3]; + /** Completion code */ + uint8_t code; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Virtual function ID */ + uint8_t vf; + /** Slot ID */ + uint8_t slot; +} __attribute__ (( packed )); + +/** A command completion event transfer request block */ +#define XHCI_TRB_COMPLETE XHCI_TRB_TYPE ( 33 ) + +/** xHCI completion codes */ +enum xhci_completion_code { + /** Success */ + XHCI_CMPLT_SUCCESS = 1, + /** Short packet */ + XHCI_CMPLT_SHORT = 13, +}; + +/** A port status change transfer request block */ +struct xhci_trb_port_status { + /** Reserved */ + uint8_t reserved_a[3]; + /** Port ID */ + uint8_t port; + /** Reserved */ + uint8_t reserved_b[7]; + /** Completion code */ + uint8_t code; + /** Flags */ + uint8_t flags; + /** Type */ + uint8_t type; + /** Reserved */ + uint16_t reserved_c; +} __attribute__ (( packed )); + +/** A port status change transfer request block */ +#define XHCI_TRB_PORT_STATUS XHCI_TRB_TYPE ( 34 ) + +/** A transfer request block */ +union xhci_trb { + /** Template */ + struct xhci_trb_template template; + /** Common fields */ + struct xhci_trb_common common; + /** Normal TRB */ + struct xhci_trb_normal normal; + /** Setup stage TRB */ + struct xhci_trb_setup setup; + /** Data stage TRB */ + struct xhci_trb_data data; + /** Status stage TRB */ + struct xhci_trb_status status; + /** Link TRB */ + struct xhci_trb_link link; + /** Enable slot TRB */ + struct xhci_trb_enable_slot enable; + /** Disable slot TRB */ + struct xhci_trb_disable_slot disable; + /** Input context TRB */ + struct xhci_trb_context context; + /** Reset endpoint TRB */ + struct xhci_trb_reset_endpoint reset; + /** Stop endpoint TRB */ + struct xhci_trb_stop_endpoint stop; + /** Set transfer ring dequeue pointer TRB */ + struct xhci_trb_set_tr_dequeue_pointer dequeue; + /** Transfer event */ + struct xhci_trb_transfer transfer; + /** Command completion event */ + struct xhci_trb_complete complete; + /** Port status changed event */ + struct xhci_trb_port_status port; +} __attribute__ (( packed )); + +/** An input control context */ +struct xhci_control_context { + /** Drop context flags */ + uint32_t drop; + /** Add context flags */ + uint32_t add; + /** Reserved */ + uint32_t reserved_a[5]; + /** Configuration value */ + uint8_t config; + /** Interface number */ + uint8_t intf; + /** Alternate setting */ + uint8_t alt; + /** Reserved */ + uint8_t reserved_b; +} __attribute__ (( packed )); + +/** A slot context */ +struct xhci_slot_context { + /** Device info */ + uint32_t info; + /** Maximum exit latency */ + uint16_t latency; + /** Root hub port number */ + uint8_t port; + /** Number of downstream ports */ + uint8_t ports; + /** TT hub slot ID */ + uint8_t tt_id; + /** TT port number */ + uint8_t tt_port; + /** Interrupter target */ + uint16_t intr; + /** USB address */ + uint8_t address; + /** Reserved */ + uint16_t reserved_a; + /** Slot state */ + uint8_t state; + /** Reserved */ + uint32_t reserved_b[4]; +} __attribute__ (( packed )); + +/** Construct slot context device info */ +#define XHCI_SLOT_INFO( entries, hub, speed, route ) \ + ( ( (entries) << 27 ) | ( (hub) << 26 ) | ( (speed) << 20 ) | (route) ) + +/** An endpoint context */ +struct xhci_endpoint_context { + /** Endpoint state */ + uint8_t state; + /** Stream configuration */ + uint8_t stream; + /** Polling interval */ + uint8_t interval; + /** Max ESIT payload high */ + uint8_t esit_high; + /** Endpoint type */ + uint8_t type; + /** Maximum burst size */ + uint8_t burst; + /** Maximum packet size */ + uint16_t mtu; + /** Transfer ring dequeue pointer */ + uint64_t dequeue; + /** Average TRB length */ + uint16_t trb_len; + /** Max ESIT payload low */ + uint16_t esit_low; + /** Reserved */ + uint32_t reserved[3]; +} __attribute__ (( packed )); + +/** Endpoint states */ +enum xhci_endpoint_state { + /** Endpoint is disabled */ + XHCI_ENDPOINT_DISABLED = 0, + /** Endpoint is running */ + XHCI_ENDPOINT_RUNNING = 1, + /** Endpoint is halted due to a USB Halt condition */ + XHCI_ENDPOINT_HALTED = 2, + /** Endpoint is stopped */ + XHCI_ENDPOINT_STOPPED = 3, + /** Endpoint is halted due to a TRB error */ + XHCI_ENDPOINT_ERROR = 4, +}; + +/** Endpoint state mask */ +#define XHCI_ENDPOINT_STATE_MASK 0x07 + +/** Endpoint type */ +#define XHCI_EP_TYPE(type) ( (type) << 3 ) + +/** Control endpoint type */ +#define XHCI_EP_TYPE_CONTROL XHCI_EP_TYPE ( 4 ) + +/** Input endpoint type */ +#define XHCI_EP_TYPE_IN XHCI_EP_TYPE ( 4 ) + +/** Endpoint dequeue cycle state */ +#define XHCI_EP_DCS 0x00000001UL + +/** Control endpoint average TRB length */ +#define XHCI_EP0_TRB_LEN 8 + +/** An event ring segment */ +struct xhci_event_ring_segment { + /** Base address */ + uint64_t base; + /** Number of TRBs */ + uint32_t count; + /** Reserved */ + uint32_t reserved; +} __attribute__ (( packed )); + +/** A transfer request block command/transfer ring */ +struct xhci_trb_ring { + /** Producer counter */ + unsigned int prod; + /** Consumer counter */ + unsigned int cons; + /** Ring size (log2) */ + unsigned int shift; + /** Ring counter mask */ + unsigned int mask; + + /** I/O buffers */ + struct io_buffer **iobuf; + + /** Transfer request blocks */ + union xhci_trb *trb; + /** Length of transfer request blocks */ + size_t len; + /** Link TRB (if applicable) */ + struct xhci_trb_link *link; + + /** Doorbell register */ + void *db; + /** Doorbell register value */ + uint32_t dbval; +}; + +/** An event ring */ +struct xhci_event_ring { + /** Consumer counter */ + unsigned int cons; + /** Event ring segment table */ + struct xhci_event_ring_segment *segment; + /** Transfer request blocks */ + union xhci_trb *trb; +}; + +/** + * Calculate doorbell register value + * + * @v target Doorbell target + * @v stream Doorbell stream ID + * @ret dbval Doorbell register value + */ +#define XHCI_DBVAL( target, stream ) ( (target) | ( (stream) << 16 ) ) + +/** + * Calculate space used in TRB ring + * + * @v ring TRB ring + * @ret fill Number of entries used + */ +static inline __attribute__ (( always_inline )) unsigned int +xhci_ring_fill ( struct xhci_trb_ring *ring ) { + + return ( ring->prod - ring->cons ); +} + +/** + * Calculate space remaining in TRB ring + * + * @v ring TRB ring + * @ret remaining Number of entries remaining + * + * xHCI does not allow us to completely fill a ring; there must be at + * least one free entry (excluding the Link TRB). + */ +static inline __attribute__ (( always_inline )) unsigned int +xhci_ring_remaining ( struct xhci_trb_ring *ring ) { + unsigned int fill = xhci_ring_fill ( ring ); + + /* We choose to utilise rings with ( 2^n + 1 ) entries, with + * the final entry being a Link TRB. The maximum fill level + * is therefore + * + * ( ( 2^n + 1 ) - 1 (Link TRB) - 1 (one slot always empty) + * == ( 2^n - 1 ) + * + * which is therefore equal to the ring mask. + */ + assert ( fill <= ring->mask ); + return ( ring->mask - fill ); +} + +/** + * Calculate physical address of most recently consumed TRB + * + * @v ring TRB ring + * @ret trb TRB physical address + */ +static inline __attribute__ (( always_inline )) physaddr_t +xhci_ring_consumed ( struct xhci_trb_ring *ring ) { + unsigned int index = ( ( ring->cons - 1 ) & ring->mask ); + + return virt_to_phys ( &ring->trb[index] ); +} + +/** Slot context index */ +#define XHCI_CTX_SLOT 0 + +/** Calculate context index from USB endpoint address */ +#define XHCI_CTX(address) \ + ( (address) ? ( ( ( (address) & 0x0f ) << 1 ) | \ + ( ( (address) & 0x80 ) >> 7 ) ) : 1 ) + +/** Endpoint zero context index */ +#define XHCI_CTX_EP0 XHCI_CTX ( 0x00 ) + +/** End of contexts */ +#define XHCI_CTX_END 32 + +/** Device context index */ +#define XHCI_DCI(ctx) ( (ctx) + 0 ) + +/** Input context index */ +#define XHCI_ICI(ctx) ( (ctx) + 1 ) + +/** Number of TRBs (excluding Link TRB) in the command ring + * + * This is a policy decision. + */ +#define XHCI_CMD_TRBS_LOG2 2 + +/** Number of TRBs in the event ring + * + * This is a policy decision. + */ +#define XHCI_EVENT_TRBS_LOG2 6 + +/** Number of TRBs in a transfer ring + * + * This is a policy decision. + */ +#define XHCI_TRANSFER_TRBS_LOG2 6 + +/** Maximum time to wait for BIOS to release ownership + * + * This is a policy decision. + */ +#define XHCI_USBLEGSUP_MAX_WAIT_MS 100 + +/** Maximum time to wait for host controller to stop + * + * This is a policy decision. + */ +#define XHCI_STOP_MAX_WAIT_MS 100 + +/** Maximum time to wait for reset to complete + * + * This is a policy decision. + */ +#define XHCI_RESET_MAX_WAIT_MS 500 + +/** Maximum time to wait for a command to complete + * + * This is a policy decision. + */ +#define XHCI_COMMAND_MAX_WAIT_MS 500 + +/** Maximum time to wait for a port reset to complete + * + * This is a policy decision. + */ +#define XHCI_PORT_RESET_MAX_WAIT_MS 500 + +/** An xHCI device */ +struct xhci_device { + /** Registers */ + void *regs; + + /** Capability registers */ + void *cap; + /** Operational registers */ + void *op; + /** Runtime registers */ + void *run; + /** Doorbell registers */ + void *db; + + /** Number of device slots */ + unsigned int slots; + /** Number of interrupters */ + unsigned int intrs; + /** Number of ports */ + unsigned int ports; + + /** Number of page-sized scratchpad buffers */ + unsigned int scratchpads; + + /** 64-bit addressing capability */ + int addr64; + /** Context size shift */ + unsigned int csz_shift; + /** xHCI extended capabilities offset */ + unsigned int xecp; + + /** Page size */ + size_t pagesize; + + /** USB legacy support capability (if present and enabled) */ + unsigned int legacy; + + /** Device context base address array */ + uint64_t *dcbaa; + + /** Scratchpad buffer area */ + userptr_t scratchpad; + /** Scratchpad buffer array */ + uint64_t *scratchpad_array; + + /** Command ring */ + struct xhci_trb_ring command; + /** Event ring */ + struct xhci_event_ring event; + /** Current command completion buffer (if any) */ + union xhci_trb *completion; + + /** Device slots, indexed by slot ID */ + struct xhci_slot **slot; + + /** USB bus */ + struct usb_bus *bus; +}; + +/** An xHCI device slot */ +struct xhci_slot { + /** xHCI device */ + struct xhci_device *xhci; + /** USB device */ + struct usb_device *usb; + /** Slot ID */ + unsigned int id; + /** Slot context */ + struct xhci_slot_context *context; + /** Route string */ + unsigned int route; + /** Root hub port number */ + unsigned int port; + /** Protocol speed ID */ + unsigned int psiv; + /** Endpoints, indexed by context ID */ + struct xhci_endpoint *endpoint[XHCI_CTX_END]; +}; + +/** An xHCI endpoint */ +struct xhci_endpoint { + /** xHCI device */ + struct xhci_device *xhci; + /** xHCI slot */ + struct xhci_slot *slot; + /** USB endpoint */ + struct usb_endpoint *ep; + /** Context index */ + unsigned int ctx; + /** Endpoint type */ + unsigned int type; + /** Endpoint context */ + struct xhci_endpoint_context *context; + /** Transfer ring */ + struct xhci_trb_ring ring; +}; + +#endif /* _IPXE_XHCI_H */ |