mirror of https://github.com/ipxe/ipxe.git
1151 lines
27 KiB
C
1151 lines
27 KiB
C
#ifndef _IPXE_XHCI_H
|
|
#define _IPXE_XHCI_H
|
|
|
|
/** @file
|
|
*
|
|
* USB eXtensible Host Controller Interface (xHCI) driver
|
|
*
|
|
*/
|
|
|
|
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|
|
|
#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
|
|
|
|
/** Maximum transfer size */
|
|
#define XHCI_MTU 65536
|
|
|
|
/** 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 abort */
|
|
#define XHCI_CRCR_CA 0x00000004UL
|
|
|
|
/** 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
|
|
|
|
/** Time to delay after writing the port link state */
|
|
#define XHCI_LINK_STATE_DELAY_MS 100
|
|
|
|
/** 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,
|
|
/** Command ring stopped */
|
|
XHCI_CMPLT_CMD_STOPPED = 24,
|
|
};
|
|
|
|
/** 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 port status change transfer request block */
|
|
struct xhci_trb_host_controller {
|
|
/** Reserved */
|
|
uint64_t reserved_a;
|
|
/** Reserved */
|
|
uint8_t reserved_b[3];
|
|
/** 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_HOST_CONTROLLER XHCI_TRB_TYPE ( 37 )
|
|
|
|
/** 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;
|
|
/** Host controller event */
|
|
struct xhci_trb_host_controller host;
|
|
} __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 )
|
|
|
|
/** Periodic endpoint type */
|
|
#define XHCI_EP_TYPE_PERIODIC XHCI_EP_TYPE ( 1 )
|
|
|
|
/** 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
|
|
*
|
|
* The "address device" command involves waiting for a response to a
|
|
* USB control transaction, and so we must wait for up to the 5000ms
|
|
* that USB allows for devices to respond to control transactions.
|
|
*/
|
|
#define XHCI_COMMAND_MAX_WAIT_MS USB_CONTROL_MAX_WAIT_MS
|
|
|
|
/** Time to delay after aborting a command
|
|
*
|
|
* This is a policy decision
|
|
*/
|
|
#define XHCI_COMMAND_ABORT_DELAY_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
|
|
|
|
/** Intel PCH quirk */
|
|
struct xhci_pch {
|
|
/** USB2 port routing register original value */
|
|
uint32_t xusb2pr;
|
|
/** USB3 port SuperSpeed enable register original value */
|
|
uint32_t usb3pssen;
|
|
};
|
|
|
|
/** Intel PCH quirk flag */
|
|
#define XHCI_PCH 0x0001
|
|
|
|
/** Intel PCH USB2 port routing register */
|
|
#define XHCI_PCH_XUSB2PR 0xd0
|
|
|
|
/** Intel PCH USB2 port routing mask register */
|
|
#define XHCI_PCH_XUSB2PRM 0xd4
|
|
|
|
/** Intel PCH SuperSpeed enable register */
|
|
#define XHCI_PCH_USB3PSSEN 0xd8
|
|
|
|
/** Intel PCH USB3 port routing mask register */
|
|
#define XHCI_PCH_USB3PRM 0xdc
|
|
|
|
/** Invalid protocol speed ID values quirk */
|
|
#define XHCI_BAD_PSIV 0x0002
|
|
|
|
/** An xHCI device */
|
|
struct xhci_device {
|
|
/** Registers */
|
|
void *regs;
|
|
/** Name */
|
|
const char *name;
|
|
/** Quirks */
|
|
unsigned int quirks;
|
|
|
|
/** 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 (if any) */
|
|
union xhci_trb *pending;
|
|
|
|
/** Device slots, indexed by slot ID */
|
|
struct xhci_slot **slot;
|
|
|
|
/** USB bus */
|
|
struct usb_bus *bus;
|
|
|
|
/** Intel PCH quirk */
|
|
struct xhci_pch pch;
|
|
};
|
|
|
|
/** 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;
|
|
/** Number of ports (if this device is a hub) */
|
|
unsigned int ports;
|
|
/** Transaction translator slot ID */
|
|
unsigned int tt_id;
|
|
/** Transaction translator port */
|
|
unsigned int tt_port;
|
|
/** 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 interval */
|
|
unsigned int interval;
|
|
/** Endpoint context */
|
|
struct xhci_endpoint_context *context;
|
|
/** Transfer ring */
|
|
struct xhci_trb_ring ring;
|
|
};
|
|
|
|
#endif /* _IPXE_XHCI_H */
|