Przeglądaj źródła

update xhci driver

zhugengyu 2 lat temu
rodzic
commit
ef126eafa6
6 zmienionych plików z 4469 dodań i 1575 usunięć
  1. 181 968
      port/xhci/usb_hc_xhci.c
  2. 16 161
      port/xhci/usb_hc_xhci.h
  3. 2563 0
      port/xhci/xhci.c
  4. 940 0
      port/xhci/xhci.h
  5. 353 0
      port/xhci/xhci_dbg.c
  6. 416 446
      port/xhci/xhci_reg.h

Plik diff jest za duży
+ 181 - 968
port/xhci/usb_hc_xhci.c


+ 16 - 161
port/xhci/usb_hc_xhci.h

@@ -1,183 +1,38 @@
 /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc. 
+ * Copyright : (C) 2022 Phytium Information Technology, Inc.
  * All Rights Reserved.
- *  
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it  
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,  
- * either version 1.0 of the License, or (at your option) any later version. 
- *  
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;  
+ *
+ * This program is OPEN SOURCE software: you can redistribute it and/or modify it
+ * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
+ * either version 1.0 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details. 
- *  
- * 
+ * See the Phytium Public License for more details.
+ *
+ *
  * FilePath: usb_hc_xhci.h
  * Date: 2022-07-19 09:26:25
  * LastEditTime: 2022-07-19 09:26:25
- * Description:  This files is for xhci data structure definition
- * 
- * Modify History: 
+ * Description:  This file is for xhci data structure definition.
+ *
+ * Modify History:
  *  Ver   Who        Date         Changes
  * ----- ------     --------    --------------------------------------
  * 1.0   zhugengyu  2022/9/19   init commit
+ * 2.0   zhugengyu  2023/3/29   support usb3.0 device attached at roothub
  */
+
 #ifndef  USB_HC_XHCI_H
 #define  USB_HC_XHCI_H
 
 /***************************** Include Files *********************************/
 #include "usbh_core.h"
 
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
 /************************** Constant Definitions *****************************/
 
-/************************** Type Definitions     *****************************/
-/* slot context */
-struct xhci_slotctx {
-    uint32_t ctx[4];
-#define XHCI_SLOTCTX_0_MAX_EPID_SET(maxid)  XHCI32_SET_BITS(maxid, 31, 27)
-#define XHCI_SLOTCTX_0_SPEED_SET(speed)     XHCI32_SET_BITS(speed, 23, 20)
-#define XHCI_SLOTCTX_1_ROOT_PORT_GET(val)   XHCI32_GET_BITS(val, 23, 16)
-#define XHCI_SLOTCTX_1_ROOT_PORT_SET(port)  XHCI32_SET_BITS(port, 23, 16)
-#define XHCI_SLOTCTX_0_ROUTE_SET(route)     XHCI32_SET_BITS(route, 19, 0)
-#define XHCI_SLOTCTX_0_ROUTE_GET(route)     XHCI32_GET_BITS(route, 19, 0)
-#define XHCI_SLOTCTX_2_HUB_SLOT_SET(slot)   XHCI32_SET_BITS(slot, 7, 0)
-#define XHCI_SLOTCTX_2_HUB_SLOT_GET(slot)   XHCI32_GET_BITS(slot, 7, 0)
-#define XHCI_SLOTCTX_2_HUB_PORT_SET(port)   XHCI32_SET_BITS(port, 15, 8)
-#define XHCI_SLOTCTX_2_HUB_PORT_GET(port)   XHCI32_GET_BITS(port, 15, 8)
-#define XHCI_SLOTCTX_3_SLOT_STATE_GET(ctx)  XHCI32_GET_BITS(ctx, 31, 27)
-    uint32_t reserved_01[4];
-#define XHCI_SLOTCTX_ENTRY_NUM     32U
-#define XHCI_SLOTCTX_ALIGMENT      1024U
-} __PACKED;
-
-enum xhci_slot_state {
-    XHCI_SLOT_DEFAULT  = 1,
-    XHCI_SLOT_ADDRESS  = 2,
-    XHCI_SLOT_CONFIG   = 3
-};
-
-/* endpoint context */
-struct xhci_epctx {
-    uint32_t ctx[2];
-#define XHCI_EPCTX_0_EP_STATE_GET(ctx)          XHCI32_GET_BITS(ctx, 2, 0)
-#define XHCI_EPCTX_0_INTERVAL_SET(interval)     XHCI32_SET_BITS(interval, 23, 16)
-#define XHCI_EPCTX_1_MPS_SET(mps)               XHCI32_SET_BITS(mps, 31, 16)    
-#define XHCI_EPCTX_1_MPS_GET(ctx)               XHCI32_GET_BITS(ctx, 31, 16)
-#define XHCI_EPCTX_1_EPTYPE_GET(ctx)            XHCI32_GET_BITS(ctx, 5, 3)
-#define XHCI_EPCTX_1_CERR_SET(cerr)             XHCI32_SET_BITS(cerr, 2, 1)      
-    uint32_t deq_low;
-    uint32_t deq_high;
-    uint32_t length;
-#define XHCI_EPCTX_AVE_TRB_LEN_SET(len)         XHCI32_SET_BITS(len, 15, 0)  
-#define XHCI_EPCTX_MAX_ESIT_SET(esit)           XHCI32_SET_BITS(esit, 31, 16)
-    uint32_t reserved_01[3];
-} __PACKED;
-
-/* device context array element */
-struct xhci_devlist {
-    uint32_t ptr_low;
-    uint32_t ptr_high;
-} __PACKED;
-
-/* input context */
-struct xhci_inctx {
-    uint32_t del;
-    uint32_t add;
-    uint32_t reserved_01[6];
-/* refer to spec. The Input Context is an array of up to 33 context data structure entries */
-#define XHCI_INCTX_ENTRY_NUM     33U
-#define XHCI_INCTX_ALIGMENT      2048
-} __PACKED;
-
-/* transfer block (ring element) */
-struct xhci_trb {
-    uint32_t ptr_low;
-    uint32_t ptr_high;
-    uint32_t status;
-    uint32_t control;
-} __PACKED;
-
-/* event ring segment */
-struct xhci_er_seg {
-    uint32_t ptr_low;
-    uint32_t ptr_high;
-    uint32_t size;
-    uint32_t reserved_01;
-} __PACKED;
-
-struct xhci_portmap {
-    uint8_t             start;
-    uint8_t             count;
-};
-
-struct xhci_ring {
-    struct xhci_trb      ring[XHCI_RING_ITEMS];
-    struct xhci_trb      evt;
-    uint32_t             eidx;
-    uint32_t             nidx;
-    uint32_t             cs;
-    usb_osal_mutex_t     lock;
-};
-
-struct xhci_pipe {
-    struct xhci_ring     reqs; /* DO NOT MOVE reqs from structure beg */
-    uint8_t              epaddr;
-    uint8_t              speed;
-    uint8_t              interval;
-    uint8_t              eptype;
-    uint16_t             maxpacket;
-    uint32_t             slotid;
-    uint32_t             epid;
-
-    /* command or transfer waiter */
-    int                  timeout; /* = 0 no need to wait */
-    bool                 waiter;
-    usb_osal_sem_t       waitsem;
-
-    /* handle urb */
-    struct usbh_hubport *hport;
-    struct usbh_urb     *urb; /* NULL if no active URB */
-};
-
-struct xhci_s {
-    /* devinfo */
-    uint32_t             ports;
-    uint32_t             slots;
-    bool                 context64;
-    struct xhci_portmap  usb2;
-    struct xhci_portmap  usb3;
-
-    /* xhci registers base addr */
-    unsigned long        base; /* register base */
-    unsigned long        caps; /* capability register base */
-    unsigned long        op;   /* operational register base */
-    unsigned long        pr;   /* port register base */
-    unsigned long        ir;   /* interrupt runtime register base */
-    unsigned long        db;   /* doorbell register base */
-    unsigned long        xcap; /* extended capability */
-    uint32_t             hcs[3]; /* capability cache */
-    uint32_t             hcc;
-    uint16_t             version; /* xhci version */
-
-    /* xhci data structures */
-    struct xhci_devlist  *devs;
-    struct xhci_ring     *cmds;
-    struct xhci_ring     *evts;
-    struct xhci_er_seg   *eseg;
-};
+/************************** Variable Definitions *****************************/
 
 /***************** Macros (Inline Functions) Definitions *********************/
 
 /************************** Function Prototypes ******************************/
-
-/*****************************************************************************/
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif

+ 2563 - 0
port/xhci/xhci.c

@@ -0,0 +1,2563 @@
+/*
+ * Copyright : (C) 2022 Phytium Information Technology, Inc.
+ * All Rights Reserved.
+ *
+ * This program is OPEN SOURCE software: you can redistribute it and/or modify it
+ * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
+ * either version 1.0 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Phytium Public License for more details.
+ *
+ *
+ * FilePath: xhci.c
+ * Date: 2022-07-19 09:26:25
+ * LastEditTime: 2022-07-19 09:26:25
+ * Description:  This file is for xhci functions implmentation.
+ *
+ * Modify History:
+ *  Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0   zhugengyu  2022/9/19   init commit
+ * 2.0   zhugengyu  2023/3/29   support usb3.0 device attached at roothub
+ */
+
+#include "usbh_core.h"
+#include "usbh_hub.h"
+
+#include "xhci_reg.h"
+#include "xhci.h"
+
+
+/** @file
+ *
+ * USB eXtensible Host Controller Interface (xHCI) driver
+ *
+ */
+
+#define XHCI_DUMP  1
+
+/** Define a XHCI speed in PSI
+ *
+ * @v mantissa		Mantissa
+ * @v exponent		Exponent (in engineering terms: 1=k, 2=M, 3=G)
+ * @ret speed		USB speed
+ */
+#define XCHI_PSI( mantissa, exponent ) ( (exponent << 16) | (mantissa) )
+
+/** USB device speeds */
+enum {
+	/** Not connected */
+	XCHI_PSI_NONE = 0,
+	/** Low speed (1.5Mbps) */
+	XCHI_PSI_LOW = XCHI_PSI ( 1500, 1 ),
+	/** Full speed (12Mbps) */
+	XCHI_PSI_FULL = XCHI_PSI ( 12, 2 ),
+	/** High speed (480Mbps) */
+	XCHI_PSI_HIGH = XCHI_PSI ( 480, 2 ),
+	/** Super speed (5Gbps) */
+	XCHI_PSI_SUPER = XCHI_PSI ( 5, 3 ),
+};
+
+
+/**
+ * Calculate buffer alignment
+ *
+ * @v len		Length
+ * @ret align		Buffer alignment
+ *
+ * Determine alignment required for a buffer which must be aligned to
+ * at least XHCI_MIN_ALIGN and which must not cross a page boundary.
+ */
+static inline size_t xhci_align ( size_t len ) {
+	size_t align;
+
+	/* Align to own length (rounded up to a power of two) */
+	align = ( 1 << fls ( len - 1 ) );
+
+	/* Round up to XHCI_MIN_ALIGN if needed */
+	if ( align < XHCI_MIN_ALIGN )
+		align = XHCI_MIN_ALIGN;
+
+	return align;
+}
+
+/**
+ * Write potentially 64-bit register
+ *
+ * @v xhci		xHCI device
+ * @v value		Value
+ * @v reg		Register address
+ * @ret rc		Return status code
+ */
+static inline int xhci_writeq ( struct xhci_host *xhci, uintptr_t value, void *reg ) {
+
+	/* If this is a 32-bit build, then this can never fail
+	 * (allowing the compiler to optimise out the error path).
+	 */
+	if ( sizeof ( value ) <= sizeof ( uint32_t ) ) {
+		writel ( value, reg );
+		writel ( 0, ( reg + sizeof ( uint32_t ) ) );
+		return 0;
+	}
+
+	/* If the device does not support 64-bit addresses and this
+	 * address is outside the 32-bit address space, then fail.
+	 */
+	if ( ( value & ~0xffffffffULL ) && ! xhci->addr64 ) {
+		USB_LOG_DBG("XHCI %s cannot access address %lx\n",
+		       xhci->name, value );
+		return -ENOTSUP;
+	}
+
+	/* If this is a 64-bit build, then writeq() is available */
+	writeq ( value, reg );
+	return 0;
+}
+
+/**
+ * Initialise device
+ *
+ * @v xhci		xHCI device
+ * @v regs		MMIO registers
+ */
+static void xhci_init ( struct xhci_host *xhci, void *regs ) {
+	uint32_t hcsparams1;
+	uint32_t hcsparams2;
+	uint32_t hccparams1;
+	uint32_t pagesize;
+	size_t caplength;
+	size_t rtsoff;
+	size_t dboff;
+
+	/* Locate capability, operational, runtime, and doorbell registers */
+	xhci->cap = regs;
+	caplength = readb ( xhci->cap + XHCI_CAP_CAPLENGTH );
+	rtsoff = readl ( xhci->cap + XHCI_CAP_RTSOFF );
+	dboff = readl ( xhci->cap + XHCI_CAP_DBOFF );
+	xhci->op = ( xhci->cap + caplength );
+	xhci->run = ( xhci->cap + rtsoff );
+	xhci->db = ( xhci->cap + dboff );
+
+    /* avoid access XHCI_REG_CAP_HCIVERSION = 0x2, unaligned memory  */
+    xhci->version = ((readl ( xhci->cap + XHCI_CAP_CAPLENGTH ) >> 16) & 0xffff);
+
+	USB_LOG_DBG("XHCI %s version %x cap %08lx op %08lx run %08lx db %08lx\n",
+		xhci->name, xhci->version, ( xhci->cap ),
+		 ( xhci->op ),  ( xhci->run ),
+		 ( xhci->db ) );
+
+    if (xhci->version < 0x96 || xhci->version > 0x120) {
+        USB_LOG_WRN("XHCI %s not support.\n", xhci->name);
+    }
+
+	/* Read structural parameters 1 */
+	hcsparams1 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS1 );
+	xhci->slots = XHCI_HCSPARAMS1_SLOTS ( hcsparams1 );
+	xhci->intrs = XHCI_HCSPARAMS1_INTRS ( hcsparams1 );
+	xhci->ports = XHCI_HCSPARAMS1_PORTS ( hcsparams1 );
+	USB_LOG_DBG("XHCI %s has %d slots %d intrs %d ports\n",
+	       xhci->name, xhci->slots, xhci->intrs, xhci->ports );
+
+	/* Read structural parameters 2 */
+	hcsparams2 = readl ( xhci->cap + XHCI_CAP_HCSPARAMS2 );
+	xhci->scratch.count = XHCI_HCSPARAMS2_SCRATCHPADS ( hcsparams2 );
+	USB_LOG_DBG("XHCI %s needs %d scratchpads\n",
+		xhci->name, xhci->scratch.count );
+
+	/* Read capability parameters 1 */
+	hccparams1 = readl ( xhci->cap + XHCI_CAP_HCCPARAMS1 );
+	xhci->addr64 = XHCI_HCCPARAMS1_ADDR64 ( hccparams1 );
+	xhci->csz_shift = XHCI_HCCPARAMS1_CSZ_SHIFT ( hccparams1 );
+	xhci->xecp = (XHCI_HCCPARAMS1_XECP ( hccparams1 ));
+	USB_LOG_DBG("XHCI %s context %d bit\n",
+		xhci->name, (xhci->addr64 ? 64 : 32) );
+
+	/* Read page size */
+	pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
+	xhci->pagesize = XHCI_PAGESIZE ( pagesize );
+	USB_ASSERT ( xhci->pagesize != 0 );
+	USB_ASSERT ( ( ( xhci->pagesize ) & ( xhci->pagesize - 1 ) ) == 0 );
+	USB_LOG_DBG("XHCI %s page size %zd bytes\n",
+		xhci->name, xhci->pagesize );
+}
+
+/**
+ * Find extended capability
+ *
+ * @v xhci		xHCI device
+ * @v id		Capability ID
+ * @v offset	Offset to previous extended capability instance, or zero
+ * @ret offset	Offset to extended capability, or zero if not found
+ */
+static unsigned int xhci_extended_capability ( struct xhci_host *xhci,
+					       					   unsigned int id,
+					       					   unsigned int offset ) {
+	uint32_t xecp;
+	unsigned int next;
+
+	/* Locate the extended capability */
+	while ( 1 ) {
+
+		/* Locate first or next capability as applicable */
+		if ( offset ) {
+			xecp = readl ( xhci->cap + offset );
+			next = XHCI_XECP_NEXT ( xecp );
+		} else {
+			next = xhci->xecp;
+		}
+		if ( ! next )
+			return 0;
+		offset += next;
+
+		/* Check if this is the requested capability */
+		xecp = readl ( xhci->cap + offset );
+		if ( XHCI_XECP_ID ( xecp ) == id )
+			return offset;
+	}
+}
+
+/**
+ * Initialise USB legacy support
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_legacy_init ( struct xhci_host *xhci ) {
+	unsigned int legacy;
+	uint8_t bios;
+
+	/* Locate USB legacy support capability (if present) */
+	legacy = xhci_extended_capability ( xhci, XHCI_XECP_ID_LEGACY, 0 );
+	if ( ! legacy ) {
+		/* Not an error; capability may not be present */
+		USB_LOG_DBG("XHCI %s has no USB legacy support capability\n",
+		       xhci->name );
+		return;
+	}
+
+	/* Check if legacy USB support is enabled */
+	USB_LOG_DBG("XHCI %s bios offset 0x%x\n", xhci->name, (xhci->cap + legacy + XHCI_USBLEGSUP_BIOS));
+	/* bios = readb ( xhci->cap + legacy + XHCI_USBLEGSUP_BIOS ); cannot access offset 0x2, work around */
+	bios = readl ( xhci->cap + legacy );
+	bios = (bios >> 16) & 0xffff;
+	if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
+		/* Not an error; already owned by OS */
+		USB_LOG_DBG("XHCI %s USB legacy support already disabled\n",
+		       xhci->name );
+		return;
+	}
+
+	/* Record presence of USB legacy support capability */
+	xhci->legacy = legacy;
+}
+
+/**
+ * Claim ownership from BIOS
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_legacy_claim ( struct xhci_host *xhci ) {
+	uint32_t ctlsts;
+	uint8_t bios;
+	unsigned int i;
+
+	/* Do nothing unless legacy support capability is present */
+	if ( ! xhci->legacy )
+		return;
+
+	/* Claim ownership */
+	writeb ( XHCI_USBLEGSUP_OS_OWNED,
+		 xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
+
+	/* Wait for BIOS to release ownership */
+	for ( i = 0 ; i < XHCI_USBLEGSUP_MAX_WAIT_MS ; i++ ) {
+
+		/* Check if BIOS has released ownership */
+		bios = readb ( xhci->cap + xhci->legacy + XHCI_USBLEGSUP_BIOS );
+		if ( ! ( bios & XHCI_USBLEGSUP_BIOS_OWNED ) ) {
+			USB_LOG_DBG("XHCI %s claimed ownership from BIOS\n",
+			       xhci->name );
+			ctlsts = readl ( xhci->cap + xhci->legacy +
+					 XHCI_USBLEGSUP_CTLSTS );
+			if ( ctlsts ) {
+				USB_LOG_DBG("XHCI %s warning: BIOS retained "
+				       "SMIs: %08x\n", xhci->name, ctlsts );
+			}
+			return;
+		}
+
+		/* Delay */
+		usb_osal_msleep ( 1 );
+	}
+
+	/* BIOS did not release ownership.  Claim it forcibly by
+	 * disabling all SMIs.
+	 */
+	USB_LOG_DBG("XHCI %s could not claim ownership from BIOS: forcibly "
+	       "disabling SMIs\n", xhci->name );
+	writel ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_CTLSTS );
+}
+
+/** Prevent the release of ownership back to BIOS */
+static int xhci_legacy_prevent_release;
+
+/**
+ * Release ownership back to BIOS
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_legacy_release ( struct xhci_host *xhci ) {
+
+	/* Do nothing unless legacy support capability is present */
+	if ( ! xhci->legacy )
+		return;
+
+	/* Do nothing if releasing ownership is prevented */
+	if ( xhci_legacy_prevent_release ) {
+		USB_LOG_DBG("XHCI %s not releasing ownership to BIOS\n",
+		       xhci->name );
+		return;
+	}
+
+	/* Release ownership */
+	writeb ( 0, xhci->cap + xhci->legacy + XHCI_USBLEGSUP_OS );
+	USB_LOG_DBG("XHCI %s released ownership to BIOS\n", xhci->name );
+}
+
+/**
+ * Stop xHCI device
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_stop ( struct xhci_host *xhci ) {
+	uint32_t usbcmd;
+	uint32_t usbsts;
+	unsigned int i;
+
+	/* Clear run/stop bit */
+	usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+	usbcmd &= ~XHCI_USBCMD_RUN;
+	writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );
+
+	/* Wait for device to stop */
+	for ( i = 0 ; i < XHCI_STOP_MAX_WAIT_MS ; i++ ) {
+
+		/* Check if device is stopped */
+		usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
+		if ( usbsts & XHCI_USBSTS_HCH )
+			return 0;
+
+		/* Delay */
+		usb_osal_msleep ( 1 );
+	}
+
+	USB_LOG_DBG("XHCI %s timed out waiting for stop\n", xhci->name );
+	return -ETIMEDOUT;
+}
+
+/**
+ * Reset xHCI device
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_reset ( struct xhci_host *xhci ) {
+	uint32_t usbcmd;
+	unsigned int i;
+	int rc;
+
+	/* The xHCI specification states that resetting a running
+	 * device may result in undefined behaviour, so try stopping
+	 * it first.
+	 */
+	if ( ( rc = xhci_stop ( xhci ) ) != 0 ) {
+		/* Ignore errors and attempt to reset the device anyway */
+	}
+
+	/* Reset device */
+	writel ( XHCI_USBCMD_HCRST, xhci->op + XHCI_OP_USBCMD );
+
+	/* Wait for reset to complete */
+	for ( i = 0 ; i < XHCI_RESET_MAX_WAIT_MS ; i++ ) {
+
+		/* Check if reset is complete */
+		usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+		if ( ! ( usbcmd & XHCI_USBCMD_HCRST ) )
+			return 0;
+
+		/* Delay */
+		usb_osal_msleep ( 1 );
+	}
+
+	USB_LOG_DBG("XHCI %s timed out waiting for reset\n", xhci->name );
+	return -ETIMEDOUT;
+}
+
+
+/**
+ * Find supported protocol extended capability for a port
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ * @ret supported	Offset to extended capability, or zero if not found
+ */
+static unsigned int xhci_supported_protocol ( struct xhci_host *xhci,
+					      					  unsigned int port ) {
+	unsigned int supported = 0;
+	unsigned int offset;
+	unsigned int count;
+	uint32_t ports;
+
+	/* Iterate over all supported protocol structures */
+	while ( ( supported = xhci_extended_capability ( xhci,
+							 XHCI_XECP_ID_SUPPORTED,
+							 supported ) ) ) {
+
+		/* Determine port range */
+		ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+		offset = XHCI_SUPPORTED_PORTS_OFFSET ( ports );
+		count = XHCI_SUPPORTED_PORTS_COUNT ( ports );
+
+		/* Check if port lies within this range */
+		if ( ( port - offset ) < count )
+			return supported;
+	}
+
+	USB_LOG_DBG("XHCI %s Port-%d has no supported protocol\n",
+	       xhci->name, port );
+	return 0;
+}
+
+/**
+ * Transcribe port speed (for debugging)
+ *
+ * @v psi		Protocol speed ID
+ * @ret speed		Transcribed speed
+ */
+static inline const char * xhci_speed_name ( uint32_t psi ) {
+	static const char *exponents[4] = { "", "k", "M", "G" };
+	static char buf[ 10 /* "xxxxxXbps" + NUL */ ];
+	unsigned int mantissa;
+	unsigned int exponent;
+
+	/* Extract mantissa and exponent */
+	mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+	exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+
+	/* Transcribe speed */
+	snprintf ( buf, sizeof ( buf ), "%d%sbps",
+		   mantissa, exponents[exponent] );
+	return buf;
+}
+
+/**
+ * Find port protocol
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ * @ret protocol	USB protocol, or zero if not found
+ */
+static unsigned int xhci_port_protocol ( struct xhci_host *xhci,
+					 					 unsigned int port ) {
+	unsigned int supported = xhci_supported_protocol ( xhci, port );
+	union {
+		uint32_t raw;
+		char text[5];
+	} name;
+	unsigned int protocol;
+	unsigned int type;
+	unsigned int psic;
+	unsigned int psiv;
+	unsigned int i;
+	uint32_t revision;
+	uint32_t ports;
+	uint32_t slot;
+	uint32_t psi;
+
+	/* Fail if there is no supported protocol */
+	if ( ! supported )
+		return 0;
+
+	/* Determine protocol version */
+	revision = readl ( xhci->cap + supported + XHCI_SUPPORTED_REVISION );
+	protocol = XHCI_SUPPORTED_REVISION_VER ( revision );
+
+	/* Describe port protocol */
+#if XHCI_DUMP 
+    {
+		name.raw = CPU_TO_LE32 ( readl ( xhci->cap + supported +
+						 XHCI_SUPPORTED_NAME ) );
+		name.text[4] = '\0';
+		slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
+		type = XHCI_SUPPORTED_SLOT_TYPE ( slot );
+		USB_LOG_DBG("XHCI %s-%d %sv%04x type %d \r\n",
+			xhci->name, port, name.text, protocol, type );
+		ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+		psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+		if ( psic ) {
+			USB_LOG_DBG(" speeds \r\n" );
+			for ( i = 0 ; i < psic ; i++ ) {
+				psi = readl ( xhci->cap + supported +
+					      XHCI_SUPPORTED_PSI ( i ) );
+				psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
+				USB_LOG_DBG(" %d:%s \r\n", psiv, xhci_speed_name ( psi ) );
+			}
+		}
+	}
+#endif
+
+	return protocol;
+}
+
+/**
+ * Probe XCHI device
+ *
+ * @v xhci		XCHI device
+ * @v baseaddr  XHCI device register base address
+ * @ret rc		Return status code
+ */
+int xhci_probe ( struct xhci_host *xhci, unsigned long baseaddr ) {
+    USB_ASSERT(xhci);
+    int error = 0;
+	struct usbh_hubport *port;
+	unsigned int i;
+
+    xhci->base = (void *)baseaddr;
+	xhci->name[0] = '0' + xhci->id; /* Assert there are less than 10 xhci host */
+    xhci->name[1] = '\0';
+
+	/* Initialise xHCI device */
+	xhci_init ( xhci, xhci->base );
+
+	/* Initialise USB legacy support and claim ownership */
+	xhci_legacy_init ( xhci );
+	xhci_legacy_claim ( xhci );
+
+	/* Reset device */
+	if ( ( error = xhci_reset ( xhci ) ) != 0 )
+		goto err_reset;
+
+	/* Set port protocols */
+	for ( i = 1 ; i <= xhci->ports ; i++ ) {
+		port = usbh_get_roothub_port ( i );
+		port->protocol = xhci_port_protocol ( xhci, i );
+	}
+
+    return error;
+
+err_reset:
+	xhci_legacy_release ( xhci );
+	return -1;
+}
+
+/*********************************************************************/
+
+/**
+ * Allocate device context base address array
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_dcbaa_alloc ( struct xhci_host *xhci ) {
+	size_t len;
+	uintptr_t dcbaap;
+	int rc;
+
+	/* Allocate and initialise structure.  Must be at least
+	 * 64-byte aligned and must not cross a page boundary, so
+	 * align on its own size (rounded up to a power of two and
+	 * with a minimum of 64 bytes).
+	 */
+	len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) );
+	xhci->dcbaa.context = usb_align(xhci_align ( len ), len);
+	if ( ! xhci->dcbaa.context ) {
+		USB_LOG_ERR("XHCI %s could not allocate DCBAA\n", xhci->name );
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	memset ( xhci->dcbaa.context, 0, len );
+
+	/* Program DCBAA pointer */
+	dcbaap =  (uintptr_t)( xhci->dcbaa.context );
+	if ( ( rc = xhci_writeq ( xhci, dcbaap,
+				  xhci->op + XHCI_OP_DCBAAP ) ) != 0 )
+		goto err_writeq;
+
+	USB_LOG_DBG("XHCI %s DCBAA at [%08lx,%08lx)\n", xhci->name,
+		 ( xhci->dcbaa.context ),
+		(  ( xhci->dcbaa.context ) + len ) );
+	return 0;
+
+ err_writeq:
+	usb_free ( xhci->dcbaa.context );
+ err_alloc:
+	return rc;
+}
+
+
+/**
+ * Allocate scratchpad buffers
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_scratchpad_alloc ( struct xhci_host *xhci ) {
+	struct xhci_scratchpad *scratch = &xhci->scratch;
+	size_t buffer_len;
+	size_t array_len;
+	uintptr_t addr;
+	unsigned int i;
+	int rc;
+
+	/* Do nothing if no scratchpad buffers are used */
+	if ( ! scratch->count ) {
+		USB_LOG_INFO("XHCI %s no need to allocate scratchpad buffers\n",
+		       xhci->name );
+		return 0;
+    }
+
+	/* Allocate scratchpad buffers */
+	buffer_len = ( scratch->count * xhci->pagesize );
+	scratch->buffer = (uintptr_t)usb_align ( xhci->pagesize, buffer_len );
+	if ( ! scratch->buffer ) {
+		USB_LOG_ERR("XHCI %s could not allocate scratchpad buffers\n",
+		       xhci->name );
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	memset ( (void *)scratch->buffer, 0, buffer_len );
+
+	/* Allocate scratchpad array */
+	array_len = ( scratch->count * sizeof ( scratch->array[0] ) );
+	scratch->array = usb_align(xhci_align ( array_len ), array_len);
+	if ( ! scratch->array ) {
+		USB_LOG_ERR("XHCI %s could not allocate scratchpad buffer "
+		       "array\n", xhci->name );
+		rc = -ENOMEM;
+		goto err_alloc_array;
+	}
+
+	/* Populate scratchpad array */
+	addr = ( scratch->buffer + 0 );
+	for ( i = 0 ; i < scratch->count ; i++ ) {
+		scratch->array[i] = CPU_TO_LE64 ( addr );
+		addr += xhci->pagesize;
+	}
+
+	/* Set scratchpad array pointer */
+	USB_ASSERT ( xhci->dcbaa.context != NULL );
+	xhci->dcbaa.context[0] = CPU_TO_LE64 ( ( scratch->array ) );
+
+	USB_LOG_DBG("XHCI %s scratchpad [%08lx,%08lx) array [%08lx,%08lx)\n",
+		xhci->name,  ( scratch->buffer, 0 ),
+		 ( scratch->buffer, buffer_len ),
+		 ( scratch->array ),
+		(  ( scratch->array ) + array_len ) );
+	return 0;
+
+	usb_free ( scratch->array );
+ err_alloc_array:
+	usb_free ( scratch->buffer );
+ err_alloc:
+	return rc;
+}
+
+/**
+ * Allocate command ring
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_command_alloc ( struct xhci_host *xhci ) {
+	uintptr_t crp;
+	int rc;
+
+    /* Allocate TRB ring */
+    xhci->cmds = usb_align(XHCI_RING_SIZE, sizeof(*xhci->cmds)); /* command ring */
+    if (! xhci->cmds)
+        goto err_ring_alloc;
+
+    memset(xhci->cmds, 0U, sizeof(*xhci->cmds));
+
+    xhci->cmds->lock = usb_osal_mutex_create();
+    USB_ASSERT(xhci->cmds->lock);
+
+    xhci->cmds->cs = 1; /* cycle state = 1 */
+
+	/* Program command ring control register */
+	crp = (uintptr_t)( xhci->cmds );
+	if ( ( rc = xhci_writeq ( xhci, ( crp | XHCI_CRCR_RCS ),
+				  xhci->op + XHCI_OP_CRCR ) ) != 0 )
+		goto err_writeq;
+
+	USB_LOG_DBG("XHCI %s CRCR at [%08lx,%08lx)\n", xhci->name,
+		 ( xhci->cmds->ring ),
+		 ( ( xhci->cmds->ring ) + sizeof(xhci->cmds->ring) ) );
+	return 0;
+
+ err_writeq:
+	usb_free(xhci->cmds);;
+ err_ring_alloc:
+	return rc;
+}
+
+/**
+ * Allocate event ring
+ *
+ * @v xhci		xHCI device
+ * @ret rc		Return status code
+ */
+static int xhci_event_alloc ( struct xhci_host *xhci ) {
+	unsigned int count;
+	size_t len;
+	int rc;
+
+	/* Allocate event ring */
+	xhci->evts = usb_align(XHCI_RING_SIZE, sizeof(*xhci->evts)); /* event ring */
+	if ( ! xhci->evts ) {
+		rc = -ENOMEM;
+		goto err_alloc_trb;
+	}
+
+	memset(xhci->evts, 0U, sizeof(*xhci->evts));
+
+	/* Allocate event ring segment table */
+	xhci->eseg = usb_align(XHCI_ALIGMENT, sizeof(*xhci->eseg)); /* event segment */
+	if ( ! xhci->eseg ) {
+		rc = -ENOMEM;
+		goto err_alloc_segment;
+	}
+	memset(xhci->eseg, 0U, sizeof(*xhci->eseg));
+    xhci->eseg->base = CPU_TO_LE64 ( ( xhci->evts ) );
+    xhci->eseg->count = XHCI_RING_ITEMS; /* items of event ring TRB */
+
+	/* Program event ring registers */
+	writel ( 1, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) ); /* bit[15:0] event ring segment table size */
+	if ( ( rc = xhci_writeq ( xhci, (uintptr_t)( xhci->evts ),
+				  xhci->run + XHCI_RUN_ERDP ( 0 ) ) ) != 0 ) /* bit[63:4] event ring dequeue pointer */
+		goto err_writeq_erdp;
+	if ( ( rc = xhci_writeq ( xhci, (uintptr_t)( xhci->eseg ),
+				  xhci->run + XHCI_RUN_ERSTBA ( 0 ) ) ) != 0 ) /* bit[63:6] event ring segment table base addr */
+		goto err_writeq_erstba;
+
+	xhci->evts->cs = 1; /* cycle state = 1 */
+	USB_LOG_DBG("XHCI %s event ring [%08lx,%08lx) table [%08lx,%08lx)\n",
+		xhci->name,  ( xhci->evts->ring ),
+		(  ( xhci->evts->ring ) + sizeof(xhci->evts->ring) ),
+		 ( xhci->eseg ),
+		(  ( xhci->eseg ) +
+		  sizeof ( xhci->eseg[0] ) ) );
+	return 0;
+
+	xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
+ err_writeq_erstba:
+	xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );
+ err_writeq_erdp:
+	usb_free ( xhci->eseg );
+ err_alloc_segment:
+	usb_free ( xhci->evts );
+ err_alloc_trb:
+	return rc;
+}
+
+/**
+ * Start xHCI device
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_run ( struct xhci_host *xhci ) {
+	uint32_t config;
+	uint32_t usbcmd;
+	uint32_t runtime;
+
+	/* Configure number of device slots */
+	config = readl ( xhci->op + XHCI_OP_CONFIG );
+	config &= ~XHCI_CONFIG_MAX_SLOTS_EN_MASK;
+	config |= XHCI_CONFIG_MAX_SLOTS_EN ( xhci->slots );
+	writel ( config, xhci->op + XHCI_OP_CONFIG );
+
+	/* Enable port interrupt */
+	writel ( 500U, xhci->run + XHCI_RUN_IR_IMOD ( 0 ) );
+	runtime = readl(xhci->run + XHCI_RUN_IR_IMAN ( 0 ));
+	runtime |= XHCI_RUN_IR_IMAN_IE;
+	writel (runtime, xhci->run + XHCI_RUN_IR_IMAN ( 0 ));
+
+	/* Set run/stop bit and enable interrupt */
+	usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+	usbcmd |= XHCI_USBCMD_RUN | XHCI_USBCMD_INTE;
+	writel ( usbcmd, xhci->op + XHCI_OP_USBCMD );
+
+	USB_LOG_DBG("XHCI %s start running\n", xhci->name );
+}
+
+/**
+ * Free event ring
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_event_free ( struct xhci_host *xhci ) {
+	
+    /* Clear event ring registers */
+	writel ( 0, xhci->run + XHCI_RUN_ERSTSZ ( 0 ) );
+	xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERSTBA ( 0 ) );
+	xhci_writeq ( xhci, 0, xhci->run + XHCI_RUN_ERDP ( 0 ) );
+
+	/* Free event ring segment table */
+	usb_free ( xhci->eseg );
+
+	/* Free event ring */
+	usb_free ( xhci->evts );
+}
+
+/**
+ * Free command ring
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_command_free ( struct xhci_host *xhci ) {
+
+	/* Sanity check */
+	USB_ASSERT ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
+
+	/* Clear command ring control register */
+	xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_CRCR );
+
+	/* Free TRB ring */
+	usb_free ( xhci->cmds );
+}
+
+/**
+ * Free scratchpad buffers
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_scratchpad_free ( struct xhci_host *xhci ) {
+	struct xhci_scratchpad *scratch = &xhci->scratch;
+	size_t array_len;
+	size_t buffer_len;
+
+	/* Do nothing if no scratchpad buffers are used */
+	if ( ! scratch->count )
+		return;
+
+	/* Clear scratchpad array pointer */
+	USB_ASSERT ( xhci->dcbaa.context != NULL );
+	xhci->dcbaa.context[0] = 0;
+
+	/* Free scratchpad array */
+	array_len = ( scratch->count * sizeof ( scratch->array[0] ) );
+	usb_free ( scratch->array );
+
+	/* Free scratchpad buffers */
+	buffer_len = ( scratch->count * xhci->pagesize );
+	usb_free ( scratch->buffer );
+}
+
+/**
+ * Free device context base address array
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_dcbaa_free ( struct xhci_host *xhci ) {
+	size_t len;
+	unsigned int i;
+
+	/* Sanity check */
+	for ( i = 0 ; i <= xhci->slots ; i++ )
+		USB_ASSERT ( xhci->dcbaa.context[i] == 0 );
+
+	/* Clear DCBAA pointer */
+	xhci_writeq ( xhci, 0, xhci->op + XHCI_OP_DCBAAP );
+
+	/* Free DCBAA */
+	len = ( ( xhci->slots + 1 ) * sizeof ( xhci->dcbaa.context[0] ) );
+	usb_free ( xhci->dcbaa.context );
+}
+
+/**
+ * Open XHCI device
+ *
+ * @v xhci		XHCI device
+ * @ret rc		Return status code
+ */
+int xhci_open ( struct xhci_host *xhci ) {
+	int rc;
+
+	/* Allocate device slot array */
+	xhci->slot = usb_malloc ( ( xhci->slots + 1 ) * sizeof ( xhci->slot[0] ) );
+	if ( ! xhci->slot ) {
+		rc = -ENOMEM;
+		goto err_slot_alloc;
+	}
+
+	/* Allocate device context base address array */
+	if ( ( rc = xhci_dcbaa_alloc ( xhci ) ) != 0 )
+		goto err_dcbaa_alloc;
+
+	/* Allocate scratchpad buffers */
+	if ( ( rc = xhci_scratchpad_alloc ( xhci ) ) != 0 )
+		goto err_scratchpad_alloc;
+
+	/* Allocate command ring */
+	if ( ( rc = xhci_command_alloc ( xhci ) ) != 0 )
+		goto err_command_alloc;
+
+    /* Allocate event ring */
+	if ( ( rc = xhci_event_alloc ( xhci ) ) != 0 )
+		goto err_event_alloc;
+
+	/* Start controller */
+	xhci_run ( xhci );
+
+	return 0;
+
+	xhci_stop ( xhci );
+	xhci_event_free ( xhci );
+ err_event_alloc:
+	xhci_command_free ( xhci );
+ err_command_alloc:
+	xhci_scratchpad_free ( xhci );
+ err_scratchpad_alloc:
+	xhci_dcbaa_free ( xhci );
+ err_dcbaa_alloc:
+	usb_free ( xhci->slot );
+ err_slot_alloc:
+	return rc;
+
+}
+
+/**
+ * Close XHCI device
+ *
+ * @v xhci		XHCI Device
+ */
+void xhci_close ( struct xhci_host *xhci ) {
+	unsigned int i;
+
+	/* Sanity checks */
+	USB_ASSERT ( xhci->slot != NULL );
+	for ( i = 0 ; i <= xhci->slots ; i++ )
+		USB_ASSERT ( xhci->slot[i] == NULL );
+
+	xhci_stop ( xhci );
+	usb_free (xhci->evts);
+	usb_free (xhci->eseg);
+	usb_free (xhci->cmds);
+	xhci_scratchpad_free ( xhci );
+	xhci_dcbaa_free ( xhci );
+	usb_free ( xhci->slot );
+}
+
+/**
+ * Remove XHCI device
+ *
+ * @v xhci		XHCI device
+ */
+void xhci_remove ( struct xhci_host *xhci ) {
+	xhci_reset ( xhci );
+	xhci_legacy_release ( xhci );
+	usb_free ( xhci );
+
+	/* If we are shutting down to boot an OS, then prevent the
+	 * release of ownership back to BIOS.
+	 */
+	xhci_legacy_prevent_release = 0;
+}
+
+/*********************************************************************/
+
+/**
+ * Enable port
+ *
+ * @v xhci		XHCI device
+ * @v port		Port number
+ * @ret rc		Return status code
+ */
+int xhci_port_enable(struct xhci_host *xhci, uint32_t port) {
+	uint32_t portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
+
+	/* double check if connected */
+	if (!(portsc & XHCI_PORTSC_CCS)) {
+        USB_LOG_ERR("device connectiong lost !!! \r\n");
+        return -ENOENT;
+	}
+
+	switch ( portsc & XHCI_PORTSC_PLS_MASK )
+	{
+	case XHCI_PORTSC_PLS_U0:
+		/* A USB3 port - controller automatically performs reset */
+		break;
+	case XHCI_PORTSC_PLS_POLLING:
+		/* A USB2 port - perform device reset */
+		xhci_dump_port_status(port, portsc);
+		writel ((portsc | XHCI_PORTSC_PR), (xhci->op + XHCI_OP_PORTSC ( port )));  /* reset port */
+		break;
+	default:
+		USB_LOG_ERR("PLS: %d \r\n", (portsc & XHCI_PORTSC_PLS_MASK));
+		return -ENOENT;
+	}
+
+	/* Wait for device to complete reset and be enabled */
+	uint32_t end = 1000U, start = 0U;
+	for (;;) {
+		portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
+		if (!(portsc & XHCI_PORTSC_CCS)) {
+            /* USB 2.0 port would be disconnected after reset */
+            USB_LOG_INFO("USB 2.0 port disconnected during reset, need rescan \r\n");
+            return 0;
+		}
+
+        if (portsc & XHCI_PORTSC_PED) { /* check if port enabled */
+			/* Reset complete */
+            break;
+        }
+
+        if (++start > end) {
+            USB_LOG_ERR("Wait timeout, portsc=0x%x !!!\n", portsc);
+            return -ENXIO;
+        }
+
+        usb_osal_msleep(1);
+	}
+
+	xhci_dump_port_status(port, portsc);
+	return 0;
+}
+
+/**
+ * Convert USB Speed to PSI
+ *
+ * @v speed		USB speed 
+ * @ret psi		USB speed in PSI
+ */
+static unsigned int xhci_speed_to_psi(int speed) {
+	unsigned int psi = USB_SPEED_UNKNOWN;
+	
+	switch (speed) {
+		case USB_SPEED_LOW:
+			psi = XCHI_PSI_LOW;
+			break;
+		case USB_SPEED_FULL:
+			psi = XCHI_PSI_FULL;
+			break;
+		case USB_SPEED_HIGH:
+			psi = XCHI_PSI_HIGH;
+			break;
+		case USB_SPEED_SUPER:
+			psi = XCHI_PSI_SUPER;
+			break;
+	}
+
+	return psi;
+}
+
+/**
+ * Convert USB PSI to Speed
+ *
+ * @v psi		USB speed in PSI 
+ * @ret speed	USB speed	
+ */
+static int xhci_psi_to_speed(int psi) {
+	int speed = USB_SPEED_UNKNOWN;
+	
+	switch (psi) {
+		case XCHI_PSI_LOW:
+			speed = USB_SPEED_LOW;
+			break;
+		case XCHI_PSI_FULL:
+			speed = USB_SPEED_FULL;
+			break;
+		case XCHI_PSI_HIGH:
+			speed = USB_SPEED_HIGH;
+			break;
+		case XCHI_PSI_SUPER:
+			speed = USB_SPEED_SUPER;
+			break;
+	}
+
+	return speed;
+}
+
+/**
+ * Find port speed
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ * @v psiv		Protocol speed ID value
+ * @ret speed		Port speed, or negative error
+ */
+static int xhci_port_speed ( struct xhci_host *xhci, unsigned int port,
+			     			 unsigned int psiv ) {
+	unsigned int supported = xhci_supported_protocol ( xhci, port );
+	unsigned int psic;
+	unsigned int mantissa;
+	unsigned int exponent;
+	unsigned int speed;
+	unsigned int i;
+	uint32_t ports;
+	uint32_t psi;
+
+	/* Fail if there is no supported protocol */
+	if ( ! supported )
+		return -ENOTSUP;
+
+	/* Get protocol speed ID count */
+	ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+	psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+
+	/* Use protocol speed ID table unless device is known to be faulty */
+	/* Iterate over PSI dwords looking for a match */
+	for ( i = 0 ; i < psic ; i++ ) {
+		psi = readl ( xhci->cap + supported +
+					XHCI_SUPPORTED_PSI ( i ) );
+		if ( psiv == XHCI_SUPPORTED_PSI_VALUE ( psi ) ) {
+			mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+			exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+			return xhci_psi_to_speed(XCHI_PSI ( mantissa, exponent ));
+		}
+	}
+
+	/* Record device as faulty if no match is found */
+	if ( psic != 0 ) {
+		USB_LOG_ERR("XHCI %s-%d spurious PSI value %d: "
+				"assuming PSI table is invalid\n",
+				xhci->name, port, psiv );
+	}
+
+	/* Use the default mappings */
+	switch ( psiv ) {
+	case XHCI_SPEED_LOW :	return USB_SPEED_LOW;
+	case XHCI_SPEED_FULL :	return USB_SPEED_FULL;
+	case XHCI_SPEED_HIGH :	return USB_SPEED_HIGH;
+	case XHCI_SPEED_SUPER :	return USB_SPEED_SUPER;
+	default:
+		USB_LOG_ERR("XHCI %s-%d unrecognised PSI value %d\n",
+		       xhci->name, port, psiv );
+		return -ENOTSUP;
+	}
+}
+
+/**
+ * Find protocol speed ID value
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ * @v speed		USB speed
+ * @ret psiv		Protocol speed ID value, or negative error
+ */
+static int xhci_port_psiv ( struct xhci_host *xhci, unsigned int port,
+			    			unsigned int speed ) {
+	unsigned int supported = xhci_supported_protocol ( xhci, port );
+	unsigned int psic;
+	unsigned int mantissa;
+	unsigned int exponent;
+	unsigned int psiv;
+	unsigned int i;
+	uint32_t ports;
+	uint32_t psi;
+
+	/* Fail if there is no supported protocol */
+	if ( ! supported )
+		return -ENOTSUP;
+
+	/* Get protocol speed ID count */
+	ports = readl ( xhci->cap + supported + XHCI_SUPPORTED_PORTS );
+	psic = XHCI_SUPPORTED_PORTS_PSIC ( ports );
+
+	/* Use the default mappings if applicable */
+	if ( psic == 0  ) {
+		switch ( speed ) {
+		case USB_SPEED_LOW :	return XHCI_SPEED_LOW;
+		case USB_SPEED_FULL :	return XHCI_SPEED_FULL;
+		case USB_SPEED_HIGH :	return XHCI_SPEED_HIGH;
+		case USB_SPEED_SUPER :	return XHCI_SPEED_SUPER;
+		default:
+			USB_LOG_DBG("XHCI %s-%d non-standard speed %d\n",
+			       xhci->name, port, speed );
+			return -ENOTSUP;
+		}
+	}
+
+	/* Iterate over PSI dwords looking for a match */
+	for ( i = 0 ; i < psic ; i++ ) {
+		psi = readl ( xhci->cap + supported + XHCI_SUPPORTED_PSI ( i ));
+		mantissa = XHCI_SUPPORTED_PSI_MANTISSA ( psi );
+		exponent = XHCI_SUPPORTED_PSI_EXPONENT ( psi );
+		if ( xhci_speed_to_psi(speed) == XCHI_PSI ( mantissa, exponent ) ) {
+			psiv = XHCI_SUPPORTED_PSI_VALUE ( psi );
+			return psiv;
+		}
+	}
+
+	USB_LOG_DBG("XHCI %s-%d unrepresentable speed %#x\n",
+	       xhci->name, port, speed );
+	return -ENOENT;
+}
+
+/**
+ * Update root hub port speed
+ *
+ * @v xhci		XHCI device
+ * @v port		Port number
+ * @ret rc		Return status code (speed)
+ */
+uint32_t xhci_root_speed ( struct xhci_host *xhci, uint8_t port ) {
+	uint32_t portsc;
+	unsigned int psiv;
+	int ccs;
+	int ped;
+	int csc;
+	int speed;
+	unsigned int protocol = xhci_port_protocol(xhci, port);
+
+	/* Read port status */
+	portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
+	USB_LOG_DBG("XHCI %s-%d status is 0x%08x, protocol 0x%x\n",
+		xhci->name, port, portsc, protocol );
+	ccs = ( portsc & XHCI_PORTSC_CCS );
+	ped = ( portsc & XHCI_PORTSC_PED );
+	csc = ( portsc & XHCI_PORTSC_CSC );
+	psiv = XHCI_PORTSC_PSIV ( portsc );
+
+	USB_LOG_DBG("XHCI %s port-%d ccs: %d, ped: %d, csc: %d, psiv: 0x%x\n", 
+				 xhci->name, port, !!ccs, !!ped, !!csc, psiv);
+
+	/* Port speed is not valid unless port is connected */
+	if ( ! ccs ) {
+		speed = USB_SPEED_UNKNOWN;
+		USB_LOG_ERR("XHCI %s port-%d speed unkown\n", xhci->name, port);
+		return speed;
+	}
+
+	/* For USB2 ports, the PSIV field is not valid until the port
+	 * completes reset and becomes enabled.
+	 */
+	if ( ( protocol < USB_3_0 ) && ! ped ) {
+		speed = USB_SPEED_FULL;
+		return speed;
+	}
+
+	/* Get port speed and map to generic USB speed */
+	speed = xhci_port_speed ( xhci, port, psiv );
+	if ( speed < 0 ) {
+		return speed;
+	}
+
+	return speed;
+}
+
+/*********************************************************************/
+/**
+ * Add a TRB to the given ring
+ *
+ * @v ring		XHCI TRB ring
+ * @v trb		TRB content to be added
+ */
+static inline void xhci_trb_fill(struct xhci_ring *ring, union xhci_trb *trb) {
+	union xhci_trb *dst = &ring->ring[ring->nidx];
+	memcpy((void *)dst, (void *)trb, sizeof(*trb));
+	dst->template.control |= (ring->cs ? XHCI_TRB_C : 0);
+	xhci_dump_trbs(dst, 1);
+}
+
+/**
+ * Queue a TRB onto a ring, wrapping ring as needed
+ *
+ * @v ring		XHCI TRB ring
+ * @v trb		TRB content to be added
+ */
+static void xhci_trb_queue(struct xhci_ring *ring, union xhci_trb *trb) {
+
+	if (ring->nidx >= XHCI_RING_ITEMS - 1) {
+		/* if it is the last trb in the list, put a link trb in the end */
+		union xhci_trb link_trb;
+		link_trb.link.type = XHCI_TRB_LINK;
+		link_trb.link.flags = XHCI_TRB_TC;
+		link_trb.link.next = CPU_TO_LE64((ring->ring));
+
+		xhci_trb_fill(ring, &link_trb);
+
+		ring->nidx = 0; /* adjust dequeue index to 0 */
+		ring->cs ^= 1; /* toggle cycle interpretation of sw */
+	}
+
+	xhci_trb_fill(ring, trb);
+	ring->nidx++; /* ahead dequeue index */
+}
+
+/**
+ * Wait for a ring to empty (all TRBs processed by hardware)
+ *
+ * @v xhci      XHCI Device
+ * @v ep		Owner Endpoint of current TRB ring
+ * @  ring		XHCI TRB ring
+ */
+int xhci_event_wait(struct xhci_host *xhci,
+					struct xhci_endpoint *ep,
+					struct xhci_ring *ring) {
+    int cc = XHCI_CMPLT_SUCCESS;
+
+    if (ep->timeout > 0)
+    {
+        if (usb_osal_sem_take(ep->waitsem, ep->timeout) < 0)
+        {
+            cc = XHCI_CMPLT_TIMEOUT;
+        }
+        else
+        {
+            cc = ring->evt.complete.code; /* bit[31:24] completion code */
+        }
+    }
+
+    return cc;
+}
+
+/**
+ * Ring doorbell register
+ *
+ * @v xhci		XHCI device
+ * @v slotid	Slot id to ring
+ * @v value     Value send to doorbell
+ */
+static inline void xhci_doorbell ( struct xhci_host *xhci, uint32_t slotid, uint32_t value ) {
+
+	DSB();
+	writel ( value, xhci->db + slotid * XHCI_REG_DB_SIZE ); /* bit[7:0] db target, is ep_id */
+}
+
+/**
+ * Abort command
+ *
+ * @v xhci		xHCI device
+ */
+static void xhci_abort ( struct xhci_host *xhci ) {
+	uintptr_t crp;
+
+	/* Abort the command */
+	USB_LOG_WRN("XHCI %s aborting command\n", xhci->name );
+	xhci_writeq ( xhci, XHCI_CRCR_CA, xhci->op + XHCI_OP_CRCR );
+
+	/* Allow time for command to abort */
+	usb_osal_msleep ( XHCI_COMMAND_ABORT_DELAY_MS );
+
+	/* Sanity check */
+	USB_ASSERT ( ( readl ( xhci->op + XHCI_OP_CRCR ) & XHCI_CRCR_CRR ) == 0 );
+
+	/* Consume (and ignore) any final command status */
+	int cc = xhci_event_wait(xhci, xhci->cur_cmd_pipe, xhci->cmds);
+	if (XHCI_CMPLT_SUCCESS != cc) {
+		USB_LOG_ERR("XHCI %s abort command failed, cc %d\n", xhci->name, cc);	
+	}
+
+ 	/* Reset the command ring control register */
+    memset(xhci->cmds->ring, 0U, XHCI_RING_ITEMS * sizeof(union xhci_trb));
+	xhci_writeq ( xhci, ( (uint64_t)(uintptr_t)xhci->cmds | xhci->cmds->cs ), xhci->op + XHCI_OP_CRCR );
+}
+
+/**
+ * Submit a command to the xhci controller ring
+ *
+ * @v xhci      XHCI Device
+ * @v ep		Owner Endpoint of current TRB ring
+ * @  trb		Command TRB to be sent
+ */
+static int xhci_cmd_submit(struct xhci_host *xhci, struct xhci_endpoint *ep, union xhci_trb *trb) {
+    
+	int rc = 0;
+	usb_osal_mutex_take(xhci->cmds->lock); /* handle command one by one */
+
+    ep->timeout = 5000;
+    ep->waiter = true;
+	xhci->cur_cmd_pipe = ep;
+
+	xhci_trb_queue(xhci->cmds, trb);
+
+    /* pass command trb to hardware */
+    DSB();
+
+    xhci_doorbell(xhci, 0, 0); /* 0 = db host controller, 0 = db targe hc command */
+	int cc = xhci_event_wait(xhci, ep, xhci->cmds);
+	if (XHCI_CMPLT_SUCCESS != cc) {
+		USB_LOG_ERR("XHCI %s cmd failed, cc %d\n", xhci->name, cc);
+		xhci_abort(xhci); /* Abort command */
+		rc = -ENOTSUP;		
+	}
+
+    usb_osal_mutex_give(xhci->cmds->lock);
+	xhci->cur_cmd_pipe = NULL;
+    return rc;
+}
+
+/**
+ * Issue NOP and wait for completion
+ *
+ * @v xhci		xHCI device
+ * @v ep		Command Endpoint
+ * @ret rc		Return status code
+ */
+static int xhci_nop ( struct xhci_host *xhci, struct xhci_endpoint *ep ) {
+	union xhci_trb trb;
+	struct xhci_trb_common *nop = &trb.common;
+	int rc;
+
+	/* Construct command */
+	memset ( nop, 0, sizeof ( *nop ) );
+	nop->flags = XHCI_TRB_IOC;
+	nop->type = XHCI_TRB_NOP_CMD;
+
+	/* Issue command and wait for completion */
+	if ( ( rc = xhci_cmd_submit(xhci, ep, &trb ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/**
+ * Issue Enable slot and wait for completion
+ *
+ * @v xhci		xHCI device
+ * @v ep		Command Endpoint
+ * @v type      Type of Slot to be enabled
+ * @ret rc		Return status code
+ */
+static int xhci_enable_slot(struct xhci_host *xhci, struct xhci_endpoint *ep, unsigned int type) {
+	union xhci_trb trb;
+	struct xhci_trb_enable_slot *enable = &trb.enable;
+	struct xhci_trb_complete *enabled;
+	unsigned int slot;
+	int rc;
+
+	/* Construct command */
+	memset ( enable, 0, sizeof ( *enable ) );
+	enable->slot = type;
+	enable->type = XHCI_TRB_ENABLE_SLOT;
+
+	/* Issue command and Wait for completion */
+	if ( ( rc = xhci_cmd_submit(xhci, ep, &trb) ) != 0 ) {
+		USB_LOG_ERR("XHCI %s could not enable new slot, type %d\n",
+		       xhci->name, type );
+		return rc;
+	}
+
+	/* Extract slot number */
+	enabled = &(xhci->cmds->evt.complete);
+	slot = enabled->slot;
+
+	USB_LOG_DBG("XHCI %s slot %d enabled\n", xhci->name, slot );
+	return slot;
+}
+
+/**
+ * Disable slot
+ *
+ * @v xhci		xHCI device
+ * @v ep		Command Endpoint
+ * @v slot		Device slot
+ * @ret rc		Return status code
+ */
+static int xhci_disable_slot ( struct xhci_host *xhci, struct xhci_endpoint *ep,
+				      		   unsigned int slot ) {
+	union xhci_trb trb;
+	struct xhci_trb_disable_slot *disable = &trb.disable;
+	int rc;
+
+	/* Construct command */
+	memset ( disable, 0, sizeof ( *disable ) );
+	disable->type = XHCI_TRB_DISABLE_SLOT;
+	disable->slot = slot;
+
+	/* Issue command and wait for completion */
+	if ( ( rc = xhci_cmd_submit ( xhci, ep, &trb ) ) != 0 ) {
+		USB_LOG_DBG("XHCI %s could not disable slot %d: %s\n",
+		       xhci->name, slot, strerror ( rc ) );
+		return rc;
+	}
+
+	USB_LOG_DBG("XHCI %s slot %d disabled\n", xhci->name, slot );
+	return 0;
+}
+
+/**
+ * Issue context-based command and wait for completion
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint	Endpoint
+ * @v type		TRB type
+ * @v populate	Input context populater
+ * @ret rc		Return status code
+ */
+static int xhci_context ( struct xhci_host *xhci, struct xhci_slot *slot,
+						  struct xhci_endpoint *ep, unsigned int type,
+						  void ( * populate ) ( struct xhci_host *xhci,
+												struct xhci_slot *slot,
+												struct xhci_endpoint *ep,
+												void *input ) ) {
+	union xhci_trb trb;
+	struct xhci_trb_context *context = &trb.context;
+	size_t len;
+	void *input;
+	int rc;
+
+	/* Allocate an input context */
+	len = xhci_input_context_offset ( xhci, XHCI_CTX_END );
+	input = usb_align(xhci_align ( len ), len);
+	if ( ! input ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	memset ( input, 0, len );
+
+	/* Populate input context */
+	populate ( xhci, slot, ep, input );
+
+	/* Construct command */
+	memset ( context, 0, sizeof ( *context ) );
+	context->type = type;
+	context->input = CPU_TO_LE64 ( ( input ) );
+	context->slot = slot->id;
+
+	/* Issue command and wait for completion */
+	if ( ( rc = xhci_cmd_submit ( xhci, ep, &trb ) ) != 0 ) {
+		xhci_dump_input_ctx(xhci, ep, input);
+		goto err_command;
+	}
+
+ err_command:
+	usb_free ( input );
+ err_alloc:
+	return rc;		
+}
+
+/**
+ * Populate address device input context
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @v input		Input context
+ */
+static void xhci_address_device_input ( struct xhci_host *xhci,
+										struct xhci_slot *slot,
+										struct xhci_endpoint *endpoint,
+										void *input ) {
+	struct xhci_control_context *control_ctx;
+	struct xhci_slot_context *slot_ctx;
+	struct xhci_endpoint_context *ep_ctx;
+
+	/* Sanity checks */
+	USB_ASSERT ( endpoint->ctx == XHCI_CTX_EP0 );	
+
+	/* Populate control context, add slot context and ep context */
+	control_ctx = input;
+	control_ctx->add = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) |
+					 ( 1 << XHCI_CTX_EP0 ) );
+
+	/* Populate slot context */
+	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+	slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( 1, 0, slot->psiv,
+							slot->route ) );
+	slot_ctx->port = slot->port;
+	slot_ctx->tt_id = slot->tt_id;
+	slot_ctx->tt_port = slot->tt_port;
+
+	/* Populate control endpoint context */
+	ep_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_EP0 ) );
+	ep_ctx->type = XHCI_EP_TYPE_CONTROL; /* bit[5:3] endpoint type */
+	ep_ctx->burst = endpoint->burst; /* bit[16:8] max burst size */
+	ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max packet size */
+
+	/*
+		bit[63:4] tr dequeue pointer
+		bit[0] dequeue cycle state
+	*/
+	ep_ctx->dequeue = CPU_TO_LE64 ( (uint64_t)( &endpoint->reqs.ring[0] ) | XHCI_EP_DCS );
+	ep_ctx->trb_len = CPU_TO_LE16 ( XHCI_EP0_TRB_LEN );	/* bit[15:0] average trb length */
+}
+
+/**
+ * Address device
+ *
+ * @v xhci		xHCI device
+ * @v endpoint	Endpoint
+ * @v slot		Device slot
+ * @ret rc		Return status code
+ */
+static inline int xhci_address_device ( struct xhci_host *xhci, 
+										struct xhci_endpoint *ep,
+										struct xhci_slot *slot ) {
+	struct xhci_slot_context *slot_ctx;
+	int rc;
+
+	/* Assign device address */
+	if ( ( rc = xhci_context ( xhci, slot, slot->endpoint[XHCI_CTX_EP0],
+				   XHCI_TRB_ADDRESS_DEVICE,
+				   xhci_address_device_input ) ) != 0 )
+	
+	USB_LOG_DBG("XHCI %s slot ctx 0x%x\n", xhci->name, slot->context);
+
+	/* Get assigned address for check */
+	slot_ctx = ( slot->context +
+		     xhci_device_context_offset ( xhci, XHCI_CTX_SLOT ) );
+	USB_LOG_DBG("XHCI %s slot ctx 0x%x assigned address 0x%x\n",
+		xhci->name, slot_ctx, slot_ctx->address );
+
+	return rc;					
+}
+
+/**
+ * Reset endpoint
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @ret rc		Return status code
+ */
+int xhci_reset_endpoint ( struct xhci_host *xhci,
+						  struct xhci_slot *slot,
+						  struct xhci_endpoint *endpoint ) {
+	union xhci_trb trb;
+	struct xhci_trb_reset_endpoint *reset = &trb.reset;
+	int rc;
+
+	/* Construct command */
+	memset ( reset, 0, sizeof ( *reset ) );
+	reset->slot = slot->id;
+	reset->endpoint = endpoint->ctx;
+	reset->type = XHCI_TRB_RESET_ENDPOINT;
+
+	/* Issue command and wait for completion */
+	if ( ( rc = xhci_cmd_submit ( xhci, endpoint, &trb ) ) != 0 ) {
+		USB_LOG_DBG("XHCI %s slot %d ctx %d could not reset endpoint "
+		       "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
+		       endpoint->context->state, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/**
+ * Stop endpoint
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint	Endpoint
+ * @ret rc		Return status code
+ */
+static inline int xhci_stop_endpoint ( struct xhci_host *xhci,
+				       				   struct xhci_slot *slot,
+				       			       struct xhci_endpoint *endpoint ) {
+	union xhci_trb trb;
+	struct xhci_trb_stop_endpoint *stop = &trb.stop;
+	int rc;
+
+	/* Construct command */
+	memset ( stop, 0, sizeof ( *stop ) );
+	stop->slot = slot->id;
+	stop->endpoint = endpoint->ctx;
+	stop->type = XHCI_TRB_STOP_ENDPOINT;
+
+	/* Issue command and wait for completion */
+	if ( ( rc = xhci_cmd_submit ( xhci, endpoint, &trb ) ) != 0 ) {
+		USB_LOG_DBG("XHCI %s slot %d ctx %d could not stop endpoint "
+		       "in state %d: %s\n", xhci->name, slot->id, endpoint->ctx,
+		       endpoint->context->state, strerror ( rc ) );
+		return rc;
+	}
+
+	return 0;
+}
+
+/*********************************************************************/
+
+/**
+ * Find port slot type
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ * @ret type	Slot type, or negative error
+ */
+static int xhci_port_slot_type ( struct xhci_host *xhci, unsigned int port ) {
+	unsigned int supported = xhci_supported_protocol ( xhci, port );
+	unsigned int type;
+	uint32_t slot;
+
+	/* Fail if there is no supported protocol */
+	if ( ! supported )
+		return -ENOTSUP;
+
+	/* Get slot type */
+	slot = readl ( xhci->cap + supported + XHCI_SUPPORTED_SLOT );
+	type = XHCI_SUPPORTED_SLOT_TYPE ( slot );
+
+	return type;
+}
+
+/**
+ * Open device
+ *
+ * @v xhci		XHCI device
+ * @v ep		Endpoint
+ * @ret slot_id Return device slot id  
+ * @ret rc		Return status code
+ */
+int xhci_device_open ( struct xhci_host *xhci, struct xhci_endpoint *ep, int *slot_id ) {
+	struct usbh_hubport *hport = ep->hport;
+	struct usbh_hubport *tt = usbh_transaction_translator(hport);	
+	struct xhci_slot *slot;
+	struct xhci_slot *tt_slot;
+	int type;
+	int rc;
+	int id;
+	size_t len;
+
+	/* Determine applicable slot type */
+	type = xhci_port_slot_type ( xhci, hport->port );
+	if ( type < 0 ) {
+		rc = type;
+		USB_LOG_ERR("XHCI %s-%d has no slot type\n",
+		       xhci->name, hport->port );
+		goto err_type;
+	}
+
+	/* Allocate a device slot number */
+	id = xhci_enable_slot ( xhci, ep, type );
+	if ( id < 0 ) {
+		rc = id;
+		goto err_enable_slot;
+	}
+
+	USB_ASSERT ( ( id > 0 ) && ( ( unsigned int ) id <= xhci->slots ) );
+	USB_ASSERT ( xhci->slot[id] == NULL );
+
+	/* Allocate and initialise structure */
+	slot = usb_malloc ( sizeof ( *slot ) );
+	if ( ! slot ) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	slot->id = id;
+	xhci->slot[id] = slot;
+	slot->xhci = xhci;
+	if ( tt ) {
+		tt_slot = xhci->slot[tt->dev_addr];
+		slot->tt_id = tt_slot->id;
+		slot->tt_port = tt->port;
+	}
+
+	/* Allocate a device context */
+	len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
+	slot->context = usb_align(xhci_align ( len ), len);
+	if ( ! slot->context ) {
+		rc = -ENOMEM;
+		goto err_alloc_context;
+	}
+	memset ( slot->context, 0, len );
+
+	/* Set device context base address */
+	USB_ASSERT ( xhci->dcbaa.context[id] == 0 );
+	xhci->dcbaa.context[id] = CPU_TO_LE64 ( ( slot->context ) );
+
+	USB_LOG_DBG("XHCI %s slot %d device context [%08lx,%08lx)\n",
+		xhci->name, slot->id,  ( slot->context ),
+		(  ( slot->context ) + len ) );
+	*slot_id = id;
+	return 0;
+
+	xhci->dcbaa.context[id] = 0;
+	usb_free ( slot->context );
+
+err_alloc_context:
+	xhci->slot[id] = NULL;
+	usb_free ( slot );
+err_alloc:
+	xhci_disable_slot ( xhci, ep, id );	
+err_enable_slot:
+err_type:
+	return rc;
+}
+
+/*********************************************************************/
+
+/**
+ * Assign device address
+ *
+ * @v xhci		XHCI device
+ * @v slot		Slot
+ * @v ep		Endpoint
+ * @ret rc		Return status code
+ */
+int xhci_device_address ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) {
+	USB_ASSERT((slot->xhci) && (ep->hport));
+	struct usbh_hubport *hport = ep->hport;
+	int psiv;
+	int rc;
+
+	/* Calculate route string */
+	slot->route = usbh_route_string (hport);
+
+	/* Calculate root hub port number */
+	struct usbh_hubport *root_port = usbh_root_hub_port (hport);
+	slot->port = root_port->port;
+
+	/* Calculate protocol speed ID */
+	psiv = xhci_port_psiv ( xhci, slot->port, hport->speed );
+	if ( psiv < 0 ) {
+		rc = psiv;
+		return rc;
+	}
+	slot->psiv = psiv;
+
+	/* Address device */
+	if ( ( rc = xhci_address_device ( xhci, ep, slot ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+
+/**
+ * Close device
+ *
+ * @v slot		Slot
+ */
+void xhci_device_close ( struct xhci_slot *slot ) {
+	struct xhci_host *xhci = slot->xhci;
+	size_t len = xhci_device_context_offset ( xhci, XHCI_CTX_END );
+	unsigned int id = slot->id;
+	int rc;
+
+	/* Disable slot */
+	if ( ( rc = xhci_disable_slot ( xhci, slot->endpoint[0], id ) ) != 0 ) {
+		/* Slot is still enabled.  Leak the slot context,
+		 * since the controller may still write to this
+		 * memory, and leave the DCBAA entry intact.
+		 *
+		 * If the controller later reports that this same slot
+		 * has been re-enabled, then some assertions will be
+		 * triggered.
+		 */
+		USB_LOG_DBG("XHCI %s slot %d leaking context memory\n",
+		       xhci->name, slot->id );
+		slot->context = NULL;
+	}
+
+	/* Free slot */
+	if ( slot->context ) {
+		usb_free ( slot->context );
+		xhci->dcbaa.context[id] = 0;
+	}
+	xhci->slot[id] = NULL;
+	usb_free ( slot );
+}
+
+
+/**
+ * Populate configure endpoint input context
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @v input		Input context
+ */
+static void xhci_configure_endpoint_input ( struct xhci_host *xhci,
+					    struct xhci_slot *slot,
+					    struct xhci_endpoint *endpoint,
+					    void *input ) {
+	struct xhci_control_context *control_ctx;
+	struct xhci_slot_context *slot_ctx;
+	struct xhci_endpoint_context *ep_ctx;
+
+	xhci_dump_endpoint(endpoint);
+
+	/* Populate control context */
+	control_ctx = input;
+	control_ctx->add = CPU_TO_LE32 (( 1 << XHCI_CTX_SLOT ) | ( 1 << endpoint->ctx ) );
+	control_ctx->drop = CPU_TO_LE32 (( 1 << XHCI_CTX_SLOT ) | ( 1 << endpoint->ctx ) );
+
+	/* Populate slot context */
+	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+	slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+							( slot->ports ? 1 : 0 ),
+							slot->psiv, 0 ) );
+	slot_ctx->ports = slot->ports;
+
+	/* Populate endpoint context */
+	ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
+	ep_ctx->interval = endpoint->interval; /* bit[23:16] for interrupt ep, set interval to control interrupt period */
+	/*
+        Value Endpoint Type Direction
+            0 Not Valid N/A
+            1 Isoch Out
+            2 Bulk Out
+            3 Interrupt Out
+            4 Control Bidirectional
+            5 Isoch In
+            6 Bulk In
+            7 Interrupt In
+    */
+	ep_ctx->type = endpoint->ctx_type;
+	ep_ctx->burst = endpoint->burst;
+	ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max packet size */
+	ep_ctx->dequeue = CPU_TO_LE64 ( (uint64_t)( &(endpoint->reqs.ring[0]) ) | XHCI_EP_DCS );
+	
+	/* TODO: endpoint attached on hub may need different setting here */
+	if (endpoint->ep_type == USB_ENDPOINT_TYPE_BULK) {
+		ep_ctx->trb_len = CPU_TO_LE16 ( 256U ); /* bit[15:0] average trb length */
+	} else if (endpoint->ep_type == USB_ENDPOINT_TYPE_INTERRUPT) {
+		ep_ctx->trb_len = CPU_TO_LE16 (16U);
+		ep_ctx->esit_low = CPU_TO_LE16 ( endpoint->mtu ); /* bit[31:16] max ESIT payload */
+	}
+
+	xhci_dump_input_ctx(xhci, endpoint, input);
+}
+
+/**
+ * Configure endpoint
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @ret rc		Return status code
+ */
+static inline int xhci_configure_endpoint ( struct xhci_host *xhci,
+					    struct xhci_slot *slot,
+					    struct xhci_endpoint *endpoint ){
+	int rc;
+
+	/* Configure endpoint */
+	if ( ( rc = xhci_context ( xhci, slot, endpoint,
+				   XHCI_TRB_CONFIGURE_ENDPOINT,
+				   xhci_configure_endpoint_input ) ) != 0 ){
+		USB_LOG_ERR("XHCI %s slot %d ctx %d configure failed, error %d !!!\n",
+			xhci->name, slot->id, endpoint->ctx, rc );		
+		return rc;
+	}
+
+	/* Sanity check */
+	if ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK )
+		   != XHCI_ENDPOINT_RUNNING ){
+		xhci_dump_slot_ctx(endpoint->slot->context);
+		xhci_dump_ep_ctx(endpoint->context);
+		USB_LOG_ERR("XHCI %s slot %d ctx %d configure failed !!!\n",
+			xhci->name, slot->id, endpoint->ctx );	
+		return -1;
+	}
+
+	USB_LOG_DBG("XHCI %s slot %d ctx %d configured\n",
+		xhci->name, slot->id, endpoint->ctx );
+	return 0;
+}
+
+/**
+ * Populate deconfigure endpoint input context
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @v input		Input context
+ */
+static void
+xhci_deconfigure_endpoint_input ( struct xhci_host *xhci __unused,
+				  struct xhci_slot *slot __unused,
+				  struct xhci_endpoint *endpoint,
+				  void *input ) {
+	struct xhci_control_context *control_ctx;
+	struct xhci_slot_context *slot_ctx;
+
+	/* Populate control context */
+	control_ctx = input;
+	control_ctx->add = CPU_TO_LE32 ( 1 << XHCI_CTX_SLOT );
+	control_ctx->drop = CPU_TO_LE32 ( 1 << endpoint->ctx );
+
+	/* Populate slot context */
+	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+	slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+							0, 0, 0 ) );
+}
+
+/**
+ * Deconfigure endpoint
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @ret rc		Return status code
+ */
+static inline int xhci_deconfigure_endpoint ( struct xhci_host *xhci,
+					      					  struct xhci_slot *slot,
+					      					  struct xhci_endpoint *endpoint ) {
+	int rc;
+
+	/* Deconfigure endpoint */
+	if ( ( rc = xhci_context ( xhci, slot, endpoint,
+				   XHCI_TRB_CONFIGURE_ENDPOINT,
+				   xhci_deconfigure_endpoint_input ) ) != 0 )
+		return rc;
+
+	USB_LOG_DBG("XHCI %s slot %d ctx %d deconfigured\n",
+		xhci->name, slot->id, endpoint->ctx );
+	return 0;
+}
+
+/*********************************************************************/
+
+/**
+ * Open control endpoint
+ *
+ * @v xhci		XHCI device
+ * @v slot		Slot
+ * @v ep		Endpoint
+ * @ret rc		Return status code
+ */
+int xhci_ctrl_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) {
+	unsigned int ctx;
+
+	/* Calculate context index */
+	ctx = XHCI_CTX ( ep->address );
+	USB_ASSERT ( slot->endpoint[ctx] == NULL );
+
+	if (USB_ENDPOINT_TYPE_CONTROL != ep->ep_type) {
+		return -EINVAL;
+	}
+
+	/* initialise structure */
+	slot->endpoint[ctx] = ep;
+	ep->xhci = xhci;
+	ep->slot = slot;
+	ep->ctx = ctx;
+	ep->ctx_type = XHCI_EP_TYPE_CONTROL;
+	ep->context = ( ( ( void * ) slot->context ) +
+			      xhci_device_context_offset ( xhci, ctx ) );
+	ep->reqs.cs = 1; /* cycle state = 1 */
+
+	USB_LOG_DBG("XHCI %s slot %d endpoint 0x%x ep type %d xhci ep type 0x%x\n",
+		xhci->name, slot->id, ep->address, ep->ep_type, 
+		(ep->ctx_type >> 3) );
+
+	USB_LOG_DBG("XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n",
+		xhci->name, slot->id, ctx,  ( ep->reqs.ring ),
+		(  ( ep->reqs.ring ) + sizeof(ep->reqs.ring) ) );
+
+	return 0;
+}
+
+/*********************************************************************/
+
+/**
+ * Open work endpoint
+ *
+ * @v xhci		XHCI device
+ * @v slot		Slot
+ * @v ep		USB endpoint
+ * @ret rc		Return status code
+ */
+int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *ep ) {
+	unsigned int ctx;
+	unsigned int interval;
+	unsigned int ctx_type;
+	int rc;
+
+	/* Calculate context index */
+	ctx = XHCI_CTX ( ep->address );
+	USB_ASSERT ( slot->endpoint[ctx] == NULL );
+
+	if (USB_ENDPOINT_TYPE_CONTROL == ep->ep_type) {
+		return -EINVAL;
+	}
+
+	/* Calculate endpoint type */
+    /*
+        Value Endpoint Type Direction, bit[5:3]
+            0 Not Valid N/A
+            1 Isoch Out
+            2 Bulk Out
+            3 Interrupt Out
+            4 Control Bidirectional
+            5 Isoch In
+            6 Bulk In
+            7 Interrupt In
+    */
+	ctx_type = XHCI_EP_TYPE ( ep->ep_type );
+    if ( ep->address & USB_EP_DIR_IN )
+		ctx_type |= XHCI_EP_TYPE_IN;
+
+	/* initialise structure */
+	slot->endpoint[ctx] = ep;
+	ep->xhci = xhci;
+	ep->slot = slot;
+	ep->ctx = ctx;
+	
+	/* Calculate interval */
+	if ( ctx_type & XHCI_EP_TYPE_PERIODIC ) {
+		ep->interval = ( fls ( ep->interval ) - 1 );
+	}
+
+	ep->ctx_type = ctx_type;
+	ep->context = ( ( ( void * ) slot->context ) +
+			      xhci_device_context_offset ( xhci, ctx ) );
+	ep->reqs.cs = 1; /* cycle state = 1 */
+
+	USB_LOG_DBG("XHCI %s slot %d endpoint 0x%x ep type %d xhci ep type 0x%x\n",
+		xhci->name, slot->id, ep->address, ep->ep_type, 
+		(ep->ctx_type >> 3) );
+
+	/* Configure endpoint */
+	if (( rc = xhci_configure_endpoint ( xhci, slot, ep ) ) != 0) {
+		goto err_configure_endpoint;
+	}
+
+	USB_LOG_DBG("XHCI %s slot %d ctx %d ring [%08lx,%08lx)\n",
+		xhci->name, slot->id, ctx,  ( ep->reqs.ring ),
+		(  ( ep->reqs.ring ) + sizeof(ep->reqs.ring) ) );
+
+	return 0;
+ err_configure_endpoint:
+ 	(void)xhci_deconfigure_endpoint ( xhci, slot, ep );
+ 	slot->endpoint[ctx] = NULL;
+	return rc;
+}
+
+/**
+ * Close endpoint
+ *
+ * @v ep		USB endpoint
+ */
+void xhci_endpoint_close ( struct xhci_endpoint *ep ) {
+	struct xhci_slot *slot = ep->slot;
+	struct xhci_host *xhci = slot->xhci;
+	unsigned int ctx = ep->ctx;
+
+	/* Deconfigure endpoint, if applicable */
+	if ( ctx != XHCI_CTX_EP0 )
+		(void)xhci_deconfigure_endpoint ( xhci, slot, ep );
+
+	slot->endpoint[ctx] = NULL;
+	usb_free(ep);	
+}
+
+/*********************************************************************/
+
+/**
+ * Enqueue message transfer
+ *
+ * @v ep		USB endpoint
+ * @v packet	Setup packet buffer
+ * @v data_buff	Data buffer
+ * @v datalen	Data length
+ * @ret rc		Return status code
+ */
+void xhci_endpoint_message ( struct xhci_endpoint *ep, 
+							 struct usb_setup_packet *packet,
+				   			 void *data_buff, 
+							 int datalen ) {
+	struct xhci_host *xhci = ep->xhci;
+	struct xhci_slot *slot = ep->slot;
+	union xhci_trb trb;
+	struct xhci_trb_setup *setup;
+	struct xhci_trb_data *data;
+	struct xhci_trb_status *status;
+	unsigned int input;
+
+	/* Construct setup stage TRB */
+	setup = &(trb.setup);
+	memset ( setup, 0, sizeof ( *setup ) );
+
+	memcpy ( &setup->packet, packet, sizeof ( setup->packet ) );
+	setup->len = CPU_TO_LE32 ( sizeof ( *packet ) ); /* bit[16:0] trb transfer length, always 8 */
+	setup->flags = XHCI_TRB_IDT; /* bit[6] Immediate Data (IDT), parameters take effect */
+	setup->type = XHCI_TRB_SETUP; /* bit[15:10] trb type */
+	input = ( packet->bmRequestType & CPU_TO_LE16 ( USB_REQUEST_DIR_IN ) );
+	if (datalen > 0) {
+		/* bit[17:16] Transfer type, 2 = OUT Data, 3 = IN Data */
+		setup->direction = ( input ? XHCI_SETUP_IN : XHCI_SETUP_OUT );
+	}
+
+	xhci_trb_queue(&(ep->reqs), &trb);
+
+	/* Construct data stage TRB, if applicable */
+	if (datalen > 0) {
+		data = &(trb.data);
+		memset ( data, 0, sizeof ( *data ) );
+
+		data->data = CPU_TO_LE64 ( data_buff );
+		data->len = CPU_TO_LE32 ( datalen );
+		data->type = XHCI_TRB_DATA; /* bit[15:10] trb type */
+		data->direction = ( input ? XHCI_DATA_IN : XHCI_DATA_OUT ); /* bit[16] Direction, 0 = OUT, 1 = IN */
+
+		xhci_trb_queue(&(ep->reqs), &trb);
+	}
+
+	status = &(trb.status);
+	memset ( status, 0, sizeof ( *status ) );
+	status->flags = XHCI_TRB_IOC;
+	status->type = XHCI_TRB_STATUS;
+	status->direction =
+		( ( datalen && input ) ? XHCI_STATUS_OUT : XHCI_STATUS_IN );
+
+	xhci_trb_queue(&(ep->reqs), &trb);
+
+    /* pass command trb to hardware */
+    DSB();
+
+    USB_LOG_DBG("ring doorbell slot-%d ep-%d \r\n", slot->id, ep->ctx);
+    xhci_doorbell(xhci, slot->id, ep->ctx); /* 0 = db host controller, 0 = db targe hc command */
+
+	return;
+}
+
+/*********************************************************************/
+
+/**
+ * Enqueue stream transfer
+ *
+ * @v ep		USB endpoint
+ * @v data_buff	Data buffer
+ * @v datalen	Data length
+ * @ret rc		Return status code
+ */
+void xhci_endpoint_stream ( struct xhci_endpoint *ep, 
+							void *data_buff, 
+							int datalen ) {
+	struct xhci_host *xhci = ep->xhci;
+	struct xhci_slot *slot = ep->slot;
+	union xhci_trb trbs;
+	union xhci_trb *trb = &trbs;
+	struct xhci_trb_normal *normal;
+	int trb_len;
+
+	/* Calculate TRB length */
+	trb_len = XHCI_MTU;
+	if ( trb_len > datalen ) {
+		trb_len = datalen;
+	} else {
+		USB_LOG_ERR("transfer length %d exceed MTU %d \r\n", datalen, trb_len);
+		goto err_enqueue;
+	}
+
+	/* Construct normal TRBs */
+	normal = &trb->normal;
+	memset ( normal, 0, sizeof ( *normal ) );
+	normal->data = CPU_TO_LE64 ( (uintptr_t)data_buff );
+	normal->len = CPU_TO_LE32 ( trb_len );
+	normal->type = XHCI_TRB_NORMAL;
+	normal->flags = XHCI_TRB_IOC;
+
+	xhci_trb_queue(&(ep->reqs), trb);
+
+    /* pass command trb to hardware */
+    DSB();
+
+	xhci_doorbell(xhci, slot->id, ep->ctx);
+
+err_enqueue:
+	return;	
+}
+
+/*********************************************************************/
+
+/**
+ * Populate evaluate context input context
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @v input		Input context
+ */
+static void xhci_evaluate_context_input ( struct xhci_host *xhci,
+					  					  struct xhci_slot *slot __unused,
+					  					  struct xhci_endpoint *endpoint,
+					  					  void *input ) {
+	struct xhci_control_context *control_ctx;
+	struct xhci_slot_context *slot_ctx;
+	struct xhci_endpoint_context *ep_ctx;
+
+	/* Populate control context */
+	control_ctx = input;
+	control_ctx->add = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) /*|
+					 ( 1 << endpoint->ctx )*/ );
+	control_ctx->drop = CPU_TO_LE32 ( ( 1 << XHCI_CTX_SLOT ) /* |
+					 ( 1 << endpoint->ctx )*/ );
+
+	/* Populate slot context */
+	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+	slot_ctx->info = CPU_TO_LE32 ( XHCI_SLOT_INFO ( ( XHCI_CTX_END - 1 ),
+							0, 0, 0 ) );
+
+	/* Populate endpoint context */
+	ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
+	ep_ctx->mtu = CPU_TO_LE16 ( endpoint->mtu );
+}
+
+/**
+ * Evaluate context
+ *
+ * @v xhci		xHCI device
+ * @v slot		Device slot
+ * @v endpoint		Endpoint
+ * @ret rc		Return status code
+ */
+static inline int xhci_evaluate_context ( struct xhci_host *xhci,
+					  					  struct xhci_slot *slot,
+					  					  struct xhci_endpoint *endpoint ) {
+	int rc;
+
+	/* Configure endpoint */
+	if ( ( rc = xhci_context ( xhci, slot, endpoint,
+				   XHCI_TRB_EVALUATE_CONTEXT,
+				   xhci_evaluate_context_input ) ) != 0 )
+		return rc;
+
+	USB_LOG_DBG("XHCI %s slot %d ctx %d (re-)evaluated\n",
+		xhci->name, slot->id, endpoint->ctx );
+	return 0;
+}
+
+/**
+ * Update MTU
+ *
+ * @v ep		USB endpoint
+ * @ret rc		Return status code
+ */
+int xhci_endpoint_mtu ( struct xhci_endpoint *ep ) {
+	struct xhci_endpoint *endpoint = ( ep );
+	struct xhci_slot *slot = endpoint->slot;
+	struct xhci_host *xhci = slot->xhci;
+	int rc;
+
+	/* Evalulate context */
+	if ( ( rc = xhci_evaluate_context ( xhci, slot, endpoint ) ) != 0 )
+		return rc;
+
+	return 0;
+}
+
+/*********************************************************************/
+
+/**
+ * Handle port status event
+ *
+ * @v xhci		xHCI device
+ * @v trb		Port status event
+ */
+static void xhci_port_status ( struct xhci_host *xhci,
+			       			   struct xhci_trb_port_status *trb ) {
+    uint32_t portsc;
+
+	/* Sanity check */
+	USB_ASSERT ( ( trb->port > 0 ) && ( trb->port <= xhci->ports ) );
+
+	/* Record disconnections, changes flag will be cleared later */
+	portsc = readl ( xhci->op + XHCI_OP_PORTSC ( trb->port ) );
+	xhci_dump_port_status(trb->port, portsc);
+
+	if (portsc & XHCI_PORTSC_CSC) {
+		/* Report port status change */
+		usbh_roothub_thread_wakeup ( trb->port );
+	}                                
+}
+
+/**
+ * Handle transfer event
+ *
+ * @v xhci		xHCI device
+ * @v trb		Transfer event TRB
+ */
+static void xhci_transfer ( struct xhci_host *xhci,
+			    			struct xhci_trb_transfer *trb ) {
+	struct xhci_slot *slot;
+	struct xhci_endpoint *endpoint;	
+	union xhci_trb *trans_trb = (void *)(uintptr_t)(trb->transfer);
+    struct xhci_ring *trans_ring = XHCI_RING(trans_trb); /* to align addr is ring base */
+	union xhci_trb *pending = &trans_ring->evt; /* preserve event trb pending to handle */
+    uint32_t eidx = trans_trb - trans_ring->ring + 1; /* calculate current evt trb index */	
+	int rc;
+
+	/* Identify slot */
+	if ( ( trb->slot > xhci->slots ) ||
+	     ( ( slot = xhci->slot[trb->slot] ) == NULL ) ) {
+		USB_LOG_DBG("XHCI %s transfer event invalid slot %d:\n",
+		       xhci->name, trb->slot );
+		return;
+	}
+
+	/* Identify endpoint */
+	if ( ( trb->endpoint >= XHCI_CTX_END ) ||
+	     ( ( endpoint = slot->endpoint[trb->endpoint] ) == NULL ) ) {
+		USB_LOG_DBG("XHCI %s slot %d transfer event invalid epid "
+		       "%d:\n", xhci->name, slot->id, trb->endpoint );
+		return;
+	}
+
+	/* Record completion */
+	memcpy(pending, trb, sizeof(*trb)); /* copy current trb to cmd/transfer ring */
+	trans_ring->eidx = eidx;
+
+	/* Check for errors */
+	if ( ! ( ( trb->code == XHCI_CMPLT_SUCCESS ) ||
+		 ( trb->code == XHCI_CMPLT_SHORT ) ) ) {
+		USB_LOG_ERR("XHCI %s slot %d ctx %d failed (code %d)\n",
+		       xhci->name, slot->id, endpoint->ctx, trb->code);
+
+		/* Sanity check */
+		USB_ASSERT ( ( endpoint->context->state & XHCI_ENDPOINT_STATE_MASK )
+			 != XHCI_ENDPOINT_RUNNING );
+
+		xhci_dump_ep_ctx(endpoint->context);
+		return;
+	}
+
+	if (endpoint->waiter) {
+		endpoint->waiter = false;
+		usb_osal_sem_give(endpoint->waitsem);
+	}
+
+	if (endpoint->urb) {
+		struct usbh_urb *cur_urb = endpoint->urb;
+		cur_urb->errorcode = trb->code;
+		/* bit [23:0] TRB Transfer length, residual number of bytes not transferred
+				for OUT, is the value of (len of trb) - (data bytes transmitted), '0' means successful
+				for IN, is the value of (len of trb) - (data bytes received),
+					if cc is Short Packet, value is the diff between expected trans size and actual recv bytes
+					if cc is other error, value is the diff between expected trans size and actual recv bytes */
+		cur_urb->actual_length += cur_urb->transfer_buffer_length - trb->residual; /* bit [23:0] */
+
+        if (cur_urb->complete) {
+            if (cur_urb->errorcode < 0) {
+                cur_urb->complete(cur_urb->arg, cur_urb->errorcode);
+            } else {
+                cur_urb->complete(cur_urb->arg, cur_urb->actual_length);
+            }
+        }
+	}
+
+	return;    
+}
+
+/**
+ * Handle command completion event
+ *
+ * @v xhci		xHCI device
+ * @v trb		Command completion event
+ */
+static void xhci_complete ( struct xhci_host *xhci,
+			    			struct xhci_trb_complete *trb ) {
+	int rc;
+	union xhci_trb *cmd_trb = (void *)(uintptr_t)(trb->command);
+    struct xhci_ring *cmd_ring = XHCI_RING(cmd_trb); /* to align addr is ring base */
+	union xhci_trb *pending = &cmd_ring->evt; /* preserve event trb pending to handle */
+    uint32_t eidx = cmd_trb - cmd_ring->ring + 1; /* calculate current evt trb index */
+	struct xhci_endpoint *work_pipe = xhci->cur_cmd_pipe;
+
+	/* Ignore "command ring stopped" notifications */
+	if ( trb->code == XHCI_CMPLT_CMD_STOPPED ) {
+		USB_LOG_DBG("XHCI %s command ring stopped\n", xhci->name );
+		return;
+	}
+
+	/* Record completion */
+	USB_LOG_DBG("command-0x%x completed !!! \r\n", pending);
+	memcpy(pending, trb, sizeof(*trb)); /* copy current trb to cmd/transfer ring */
+	cmd_ring->eidx = eidx;
+
+	USB_ASSERT(work_pipe);
+	if (work_pipe->waiter)
+	{
+		work_pipe->waiter = false;
+		usb_osal_sem_give(work_pipe->waitsem);
+	}
+}
+
+/**
+ * Handle host controller event
+ *
+ * @v xhci		xHCI device
+ * @v trb		Host controller event
+ */
+static void xhci_host_controller ( struct xhci_host *xhci,
+				   				   struct xhci_trb_host_controller *trb ) {
+	int rc;
+
+	/* Construct error */
+	rc = -( trb->code );
+	USB_LOG_ERR("XHCI %s host controller event (code %d)\n",
+	       xhci->name, trb->code );
+}
+
+/**
+ * Process event ring in interrupt
+ *
+ * @v xhci		xHCI device
+ * @r workpip   current work endpoint
+ */
+struct xhci_endpoint *xhci_event_process(struct xhci_host *xhci) {
+    struct xhci_endpoint *work_pipe = NULL;
+    struct xhci_ring *evts = xhci->evts;
+    unsigned int evt_type;
+    unsigned int evt_cc;
+
+    /* check and ack event */
+    for (;;) {
+		/* Stop if we reach an empty TRB */
+		DSB();
+
+        uint32_t nidx = evts->nidx; /* index of dequeue trb */
+        uint32_t cs = evts->cs; /* cycle state toggle by xHc */
+        union xhci_trb *trb = evts->ring + nidx; /* current trb */
+        uint32_t control = trb->common.flags; /* trb control field */
+
+        if ((control & XHCI_TRB_C) != (cs ? 1 : 0)) { /* if cycle state not toggle, no events need to handle */
+            break;
+        }
+
+        /* Handle TRB */
+		evt_type = ( trb->common.type & XHCI_TRB_TYPE_MASK );
+		switch ( evt_type ) {
+
+		case XHCI_TRB_TRANSFER :
+			evt_cc = trb->transfer.code;
+			xhci_transfer ( xhci, &trb->transfer );
+			break;
+
+		case XHCI_TRB_COMPLETE :
+			evt_cc = trb->complete.code;
+			xhci_complete ( xhci, &trb->complete );
+			break;
+
+		case XHCI_TRB_PORT_STATUS:
+			evt_cc = trb->port.code;
+			xhci_port_status ( xhci, &trb->port );
+			break;
+
+		case XHCI_TRB_HOST_CONTROLLER:
+			evt_cc = trb->host.code;
+			xhci_host_controller ( xhci, &trb->host );
+			break;
+
+		default:
+			USB_LOG_DBG("XHCI %s unrecognised event type %d, cc %d\n:",
+			       xhci->name, ( evt_type ) );
+			break;
+        }
+
+        /* move ring index, notify xhci */
+        nidx++; /* head to next trb */
+        if (nidx == XHCI_RING_ITEMS)
+        {
+            nidx = 0; /* roll-back if reach end of list */
+            cs = cs ? 0 : 1;
+            evts->cs = cs; /* sw toggle cycle state */
+        }
+        evts->nidx = nidx;
+
+        /* Update dequeue pointer if applicable */
+        uint64_t erdp = (uint64_t)(unsigned long)(evts->ring + nidx);
+		xhci_writeq ( xhci, (uintptr_t)( erdp ) | XHCI_RUN_ERDP_EHB,
+				xhci->run + XHCI_RUN_ERDP ( 0 ) );
+   }
+
+   return work_pipe;    
+}

+ 940 - 0
port/xhci/xhci.h

@@ -0,0 +1,940 @@
+/*
+ * Copyright : (C) 2022 Phytium Information Technology, Inc.
+ * All Rights Reserved.
+ *
+ * This program is OPEN SOURCE software: you can redistribute it and/or modify it
+ * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
+ * either version 1.0 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Phytium Public License for more details.
+ *
+ *
+ * FilePath: xhci.h
+ * Date: 2022-07-19 09:26:25
+ * LastEditTime: 2022-07-19 09:26:25
+ * Description:  This file is for xhci register definition.
+ *
+ * Modify History:
+ *  Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0   zhugengyu  2022/9/19   init commit
+ * 2.0   zhugengyu  2023/3/29   support usb3.0 device attached at roothub
+ */
+#ifndef XHCI_H
+#define XHCI_H
+
+#include "xhci_reg.h"
+
+#include "usbh_core.h"
+
+/** @file
+ *
+ * USB eXtensible Host Controller Interface (xHCI) driver
+ *
+ */
+
+#define XHCI_RING_ITEMS     16U
+#define XHCI_ALIGMENT       64U
+#define XHCI_RING_SIZE      (XHCI_RING_ITEMS * sizeof(union xhci_trb))
+
+/*
+ *  xhci_ring structs are allocated with XHCI_RING_SIZE alignment,
+ *  then we can get it from a trb pointer (provided by evt ring).
+ */
+#define XHCI_RING(_trb)          \
+    ((struct xhci_ring*)((unsigned long)(_trb) & ~(XHCI_RING_SIZE-1)))
+
+/** Device context base address array */
+struct xhci_dcbaa {
+	/** Context base addresses */
+	uint64_t *context;
+};
+
+/** Scratchpad buffer */
+struct xhci_scratchpad {
+	/** Number of page-sized scratchpad buffers */
+	unsigned int count;
+	/** Scratchpad buffer area */
+	uintptr_t buffer;
+	/** Scratchpad array */
+	uint64_t *array;
+};
+
+/** 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 03-00h */
+	uint32_t info;
+	/** Maximum exit latency */
+	uint16_t latency;
+	/** Root hub port number */
+	uint8_t port;
+	/** Number of downstream ports 07-04h */
+	uint8_t ports;
+	/** TT hub slot ID */
+	uint8_t tt_id;
+	/** TT port number */
+	uint8_t tt_port;
+	/** Interrupter target 0b-08h */
+	uint16_t intr;
+	/** USB address */
+	uint8_t address;
+	/** Reserved */
+	uint16_t reserved_a;
+	/** Slot state 0f-0ch */
+	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  03-00h*/
+	uint8_t state;
+	/** Stream configuration */
+	uint8_t stream;
+#define XHCI_EPCTX_MULT_GET(stream)		XHCI32_GET_BITS(stream, 1, 0)
+#define XHCI_EPCTX_STREAM_GET(stream)	XHCI32_GET_BITS(stream, 6, 2)
+#define XHCI_EPCTX_LSA					BIT(7)
+	/** Polling interval */
+	uint8_t interval;
+	/** Max ESIT payload high */
+	uint8_t esit_high;
+	/** Endpoint type 04-04h */
+	uint8_t type;
+#define XHCI_EPCTX_CERR_GET(type)		XHCI32_GET_BITS(type, 2, 1)
+#define XHCI_EPCTX_TYPE_GET(type)		XHCI32_GET_BITS(type, 5, 3)
+#define XHCI_EPCTX_HID					BIT(7)
+	/** Maximum burst size */
+	uint8_t burst;
+	/** Maximum packet size */
+	uint16_t mtu;
+	/** Transfer ring dequeue pointer 0f-08h */
+	uint64_t dequeue;
+#define XHCI_EPCTX_DCS				   BIT(0)
+	/** Average TRB length 13-10h */
+	uint16_t trb_len;
+	/** Max ESIT payload low */
+	uint16_t esit_low;
+	/** Reserved */
+	uint32_t reserved[3];
+} __attribute__ (( packed ));
+
+/** Endpoint states */
+enum {
+	/** 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
+
+/**
+ * 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 ) )
+
+
+/** Slot context index */
+#define XHCI_CTX_SLOT 0
+
+/** Calculate context index from USB endpoint address */
+/* refer to spec. Figure 4-4: Endpoint Context Addressing
+		ep0 = 1, ep1-out = 2, ep1-in = 3, ... ep15-out = 30, ep15-in = 31 */
+#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 5000
+
+/** 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
+
+/** 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, 04-00h sw will copy request content to this field */
+	struct usb_setup_packet packet;
+	/** Length 08h */
+	uint32_t len;
+	/** Flags 0ch */
+	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 {
+	/** Timeout */
+	XHCI_CMPLT_TIMEOUT = -1,
+	/** Success */
+	XHCI_CMPLT_SUCCESS = 1,
+	/** Stall Error */
+	XHCI_CMPLT_STALL = 6,
+	/** Bandwidth Error */
+	XHCI_CMPLT_BANDWIDTH = 8,
+	/** Endpoint Not Enabled Error */
+	XHCI_CMPLT_ENDPOINT_NOT_ENABLED = 12,
+	/** Short packet */
+	XHCI_CMPLT_SHORT = 13,
+	/** Parameter Error */
+	XHCI_CMPLT_PARAMETER = 17,
+	/** 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 ));
+
+struct xhci_ring {
+    union  xhci_trb      ring[XHCI_RING_ITEMS];
+    union  xhci_trb      evt;
+    uint32_t             eidx;
+    uint32_t             nidx;
+    uint32_t             cs;
+    usb_osal_mutex_t     lock;
+};
+
+/** An event ring segment */
+struct xhci_er_seg {
+	/** Base address */
+	uint64_t base;
+	/** Number of TRBs */
+	uint32_t count;
+	/** Reserved */
+	uint32_t reserved;
+} __attribute__ (( packed ));
+
+/** An xHCI endpoint */
+struct xhci_endpoint {
+    struct xhci_ring     reqs; /* DO NOT MOVE reqs from structure beg */
+	/** xHCI device */
+	struct xhci_host   *xhci;
+	/** xHCI slot */
+	struct xhci_slot     *slot;
+	/** Endpoint address */
+	unsigned int address;
+	/** Context index */
+	unsigned int ctx;
+	/** Endpoint type in USB definition */
+	unsigned int ep_type;
+	/** Endpoint type in XHCI Endpoint context definition */
+	unsigned int ctx_type;
+
+	/** Maximum transfer size (Maximum packet size) */
+	unsigned int mtu;
+	/** Maximum burst size */
+	unsigned int burst;    
+	/** Endpoint interval */
+	unsigned int interval;
+
+	/** Endpoint context */
+	struct xhci_endpoint_context *context;
+
+    /* command or transfer waiter */
+    int                  timeout; /* = 0 no need to wait */
+    bool                 waiter;
+    usb_osal_sem_t       waitsem;
+
+    /* handle urb */
+    struct usbh_hubport *hport;
+    struct usbh_urb     *urb; /* NULL if no active URB */
+};
+
+/** An xHCI device slot */
+struct xhci_slot {
+	/** xHCI device */
+	struct xhci_host *xhci;
+	/** 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 device */
+struct xhci_host {
+	/** ID */
+	uint32_t			 id;
+	/** Name */
+	char           		 name[4];
+
+    /* xhci registers base addr */
+    /** Registers base */
+    void                 *base;
+	/** Capability registers */
+	void                 *cap;
+	/** Operational registers */
+	void                 *op;
+	/** Runtime registers */
+	void                 *run;
+	/** Doorbell registers */
+	void                 *db;
+    /** extended capability */
+    unsigned int         xecp;
+    /** capability cache */
+    uint32_t             hcs[3];
+    uint32_t             hcc;
+    /** xhci version */
+    uint16_t             version;
+
+	/** Number of device slots */
+	unsigned int         slots;
+	/** Number of interrupters */
+	unsigned int         intrs;
+	/** Number of ports */
+	unsigned int         ports;
+
+	/** 64-bit addressing capability */
+	int                  addr64;
+	/** Context size shift */
+	unsigned int         csz_shift;
+	/** Page size */
+	size_t               pagesize;
+
+	/** USB legacy support capability (if present and enabled) */
+	unsigned int         legacy;
+
+	/** Device context base address array */
+	struct xhci_dcbaa    dcbaa;
+
+	/** Scratchpad buffer */
+	struct xhci_scratchpad scratch;
+
+	/** Device slots, indexed by slot ID */
+	struct xhci_slot       **slot;
+
+	/** Command ring */
+	struct xhci_ring       *cmds;
+	/** Event ring */
+	struct xhci_ring       *evts;
+    struct xhci_er_seg     *eseg;
+
+	struct xhci_endpoint   *cur_cmd_pipe;
+};
+
+/**
+ * Calculate input context offset
+ *
+ * @v xhci		xHCI device
+ * @v ctx		Context index
+ */
+static inline size_t xhci_input_context_offset ( struct xhci_host *xhci,
+						 unsigned int ctx ) {
+
+	return ( XHCI_ICI ( ctx ) << xhci->csz_shift );
+}
+
+/**
+ * Calculate device context offset
+ *
+ * @v xhci		xHCI device
+ * @v ctx		Context index
+ */
+static inline size_t xhci_device_context_offset ( struct xhci_host *xhci,
+						  unsigned int ctx ) {
+
+	return ( XHCI_DCI ( ctx ) << xhci->csz_shift );
+}
+
+/* Probe XCHI device */
+int xhci_probe ( struct xhci_host *xhci, unsigned long baseaddr );
+
+/* Open XHCI device and start running */
+int xhci_open ( struct xhci_host *xhci );
+
+/* Close XHCI device and stop running */
+void xhci_close ( struct xhci_host *xhci );
+
+/* Remove XHCI device and free allocated memory */
+void xhci_remove ( struct xhci_host *xhci );
+
+/* Enable port */
+int xhci_port_enable (struct xhci_host *xhci, uint32_t port);
+
+/* Get port speed */
+uint32_t xhci_root_speed ( struct xhci_host *xhci, uint8_t port );
+
+/* Open and enable device */
+int xhci_device_open ( struct xhci_host *xhci, struct xhci_endpoint *pipe, int *slot_id );
+
+/* Assign device address */
+int xhci_device_address ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe );
+
+/* Close device and free allocated memory */
+void xhci_device_close ( struct xhci_slot *slot );
+
+/* Open control endpoint for slot */
+int xhci_ctrl_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe );
+
+/* Open work endpoint for slot */
+int xhci_work_endpoint_open ( struct xhci_host *xhci, struct xhci_slot *slot, struct xhci_endpoint *pipe );
+
+/* Close endpoint and free allocated memory */
+void xhci_endpoint_close ( struct xhci_endpoint *ep );
+
+/* Update MTU (Max packet size) of endpoint */
+int xhci_endpoint_mtu ( struct xhci_endpoint *ep );
+
+/* Enqueue message transfer, usually for control transfer */
+void xhci_endpoint_message ( struct xhci_endpoint *ep, struct usb_setup_packet *packet,
+				   			void *data_buff, int datalen );
+
+/* Enqueue stream transfer, usually for bulk/interrupt transfer */
+void xhci_endpoint_stream ( struct xhci_endpoint *ep, void *data_buff, int datalen );
+
+/* Process event ring in interrupt */
+struct xhci_endpoint *xhci_event_process(struct xhci_host *xhci);
+
+/* Wait for a ring to empty (all TRBs processed by hardware) */
+int xhci_event_wait(struct xhci_host *xhci,
+					struct xhci_endpoint *pipe,
+					struct xhci_ring *ring);
+
+/* Dump host controller registers */
+void xhci_dump(struct xhci_host *xhci);
+
+/* Dump port registers */
+void xhci_dump_port ( struct xhci_host *xhci,
+				      unsigned int port );
+
+/* Dump Port status */
+void xhci_dump_port_status(uint32_t port, uint32_t portsc);
+
+/* Dump input context */
+void xhci_dump_input_ctx( struct xhci_host *xhci, const struct xhci_endpoint *endpoint, const void *input);
+
+/* Dump Endpoint */
+void xhci_dump_endpoint(const struct xhci_endpoint *ep);
+
+/* Dump endpoint context */
+void xhci_dump_ep_ctx(const struct xhci_endpoint_context *ep);
+
+/* Dump TRB */
+void xhci_dump_trbs(const union xhci_trb *trbs, unsigned int count);
+
+/* Dump slot context */
+void xhci_dump_slot_ctx(const struct xhci_slot_context *const sc);
+
+#endif /* XHCI_H */

+ 353 - 0
port/xhci/xhci_dbg.c

@@ -0,0 +1,353 @@
+/*
+ * Copyright : (C) 2022 Phytium Information Technology, Inc.
+ * All Rights Reserved.
+ *
+ * This program is OPEN SOURCE software: you can redistribute it and/or modify it
+ * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
+ * either version 1.0 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the Phytium Public License for more details.
+ *
+ *
+ * FilePath: xhci_dbg.c
+ * Date: 2022-07-19 09:26:25
+ * LastEditTime: 2022-07-19 09:26:25
+ * Description:  This file is for implment xhci debug functions
+ *
+ * Modify History:
+ *  Ver   Who        Date         Changes
+ * ----- ------     --------    --------------------------------------
+ * 1.0   zhugengyu  2022/9/19   init commit
+ * 2.0   zhugengyu  2023/3/29   support usb3.0 device attached at roothub
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+
+#include "usbh_core.h"
+
+#include "xhci.h"
+
+/* macro to enable dump */
+#define XHCI_DUMP	   1
+#define XHCI_DUMP_PORT 1
+#define XHCI_DUMP_TRB  0
+#define XHCI_DUMP_SLOT 0
+#define XHCI_DUMP_EP_CTX 0
+#define XHCI_DUMP_INPUT_CTX 0
+#define XHCI_DUMP_ENDPOINT 0
+#define XHCI_DUMP_PORT_STATUS 0
+
+/**
+ * Dump host controller registers
+ *
+ * @v xhci		xHCI device
+ */
+void xhci_dump(struct xhci_host *xhci) {
+#if XHCI_DUMP
+	uint32_t usbcmd;
+	uint32_t usbsts;
+	uint32_t pagesize;
+	uint32_t dnctrl;
+	uint32_t config;
+
+	/* Dump USBCMD */
+	usbcmd = readl ( xhci->op + XHCI_OP_USBCMD );
+	USB_LOG_DBG ( "XHCI %s USBCMD %08x%s%s\n", xhci->name, usbcmd,
+	       ( ( usbcmd & XHCI_USBCMD_RUN ) ? " run" : "" ),
+	       ( ( usbcmd & XHCI_USBCMD_HCRST ) ? " hcrst" : "" ) );
+
+	/* Dump USBSTS */
+	usbsts = readl ( xhci->op + XHCI_OP_USBSTS );
+	USB_LOG_DBG ( "XHCI %s USBSTS %08x%s\n", xhci->name, usbsts,
+	       ( ( usbsts & XHCI_USBSTS_HCH ) ? " hch" : "" ) );
+
+	/* Dump PAGESIZE */
+	pagesize = readl ( xhci->op + XHCI_OP_PAGESIZE );
+	USB_LOG_DBG ( "XHCI %s PAGESIZE %08x\n", xhci->name, pagesize );
+
+	/* Dump DNCTRL */
+	dnctrl = readl ( xhci->op + XHCI_OP_DNCTRL );
+	USB_LOG_DBG ( "XHCI %s DNCTRL %08x\n", xhci->name, dnctrl );
+
+	/* Dump CONFIG */
+	config = readl ( xhci->op + XHCI_OP_CONFIG );
+	USB_LOG_DBG ( "XHCI %s CONFIG %08x\n", xhci->name, config );	
+#endif
+}
+
+/**
+ * Dump port registers
+ *
+ * @v xhci		xHCI device
+ * @v port		Port number
+ */
+void xhci_dump_port ( struct xhci_host *xhci,
+				      unsigned int port ) {
+#if  XHCI_DUMP_PORT
+	uint32_t portsc;
+	uint32_t portpmsc;
+	uint32_t portli;
+	uint32_t porthlpmc;
+
+	/* Dump PORTSC */
+	portsc = readl ( xhci->op + XHCI_OP_PORTSC ( port ) );
+	USB_LOG_DBG ( "XHCI %s-%d PORTSC %08x%s%s%s%s psiv=%d\n",
+	       xhci->name, port, portsc,
+	       ( ( portsc & XHCI_PORTSC_CCS ) ? " ccs" : "" ),
+	       ( ( portsc & XHCI_PORTSC_PED ) ? " ped" : "" ),
+	       ( ( portsc & XHCI_PORTSC_PR ) ? " pr" : "" ),
+	       ( ( portsc & XHCI_PORTSC_PP ) ? " pp" : "" ),
+	       XHCI_PORTSC_PSIV ( portsc ) );
+
+	/* Dump PORTPMSC */
+	portpmsc = readl ( xhci->op + XHCI_OP_PORTPMSC ( port ) );
+	USB_LOG_DBG ( "XHCI %s-%d PORTPMSC %08x\n", xhci->name, port, portpmsc );
+
+	/* Dump PORTLI */
+	portli = readl ( xhci->op + XHCI_OP_PORTLI ( port ) );
+	USB_LOG_DBG ( "XHCI %s-%d PORTLI %08x\n", xhci->name, port, portli );
+
+	/* Dump PORTHLPMC */
+	porthlpmc = readl ( xhci->op + XHCI_OP_PORTHLPMC ( port ) );
+	USB_LOG_DBG ( "XHCI %s-%d PORTHLPMC %08x\n",
+	       xhci->name, port, porthlpmc );
+#endif    						
+}
+
+/**
+ * Dump slot context
+ *
+ * @v sc		Slot context
+ */
+void xhci_dump_slot_ctx(const struct xhci_slot_context *const sc) {
+#if XHCI_DUMP_SLOT
+	const uint8_t *ctx = (uint8_t *)sc;
+
+	USB_LOG_DBG("===== slot ctx ===== \r\n");
+	USB_LOG_DBG("ctx[0]=0x%x\n", *((uint32_t*)ctx));
+	USB_LOG_DBG("	info: 0x%x \r\n", sc->info);
+	USB_LOG_DBG("ctx[1]=0x%x\n", *((uint32_t*)ctx + 1));
+	USB_LOG_DBG("	latency: 0x%x \r\n", sc->latency);
+	USB_LOG_DBG("	port: 0x%x \r\n", sc->port);
+	USB_LOG_DBG("	ports: 0x%x \r\n", sc->ports);
+	USB_LOG_DBG("ctx[2]=0x%x\n", *((uint32_t*)ctx + 2));
+	USB_LOG_DBG("	tt_id: 0x%x \r\n", sc->tt_id);
+	USB_LOG_DBG("	tt_port: 0x%x \r\n", sc->tt_port);
+	USB_LOG_DBG("ctx[3]=0x%x\n", *((uint32_t*)ctx + 3));
+	USB_LOG_DBG("	intr: 0x%x \r\n", sc->intr);
+	USB_LOG_DBG("	address: 0x%x \r\n", sc->address);
+	USB_LOG_DBG("	state: 0x%x \r\n", sc->state);
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}
+
+/**
+ * Dump endpoint context
+ *
+ * @v ep		Endpoint context
+ */
+void xhci_dump_ep_ctx(const struct xhci_endpoint_context *ep) {
+#if XHCI_DUMP_EP_CTX
+	const uint8_t *ctx = (uint8_t *)ep;
+
+	USB_LOG_DBG("===== ep ctx ===== \r\n");
+	USB_LOG_DBG("ctx[0]=0x%x\n", *((uint32_t*)ctx));
+	USB_LOG_DBG("	ep_state: 0x%x \r\n", ep->state);
+	USB_LOG_DBG("	mult: 0x%x \r\n", XHCI_EPCTX_MULT_GET(ep->stream));
+	USB_LOG_DBG("	stream: 0x%x \r\n", XHCI_EPCTX_STREAM_GET(ep->stream));
+	USB_LOG_DBG("	lsa: 0x%x \r\n", !!(XHCI_EPCTX_LSA & (ep->stream)));
+	USB_LOG_DBG("	interval: 0x%x \r\n", ep->interval);
+	USB_LOG_DBG("	esit_high: 0x%x \r\n", ep->esit_high);
+	USB_LOG_DBG("ctx[1]=0x%x\n", *((uint32_t*)ctx + 1));
+	USB_LOG_DBG("	cerr: 0x%x \r\n", XHCI_EPCTX_CERR_GET(ep->type));
+	USB_LOG_DBG("	type: 0x%x \r\n", XHCI_EPCTX_TYPE_GET(ep->type));
+	USB_LOG_DBG("	hid: 0x%x \r\n", !!(XHCI_EPCTX_HID & (ep->type)));
+	USB_LOG_DBG("	burst: 0x%x \r\n", ep->burst);
+	USB_LOG_DBG("	mtu: 0x%x \r\n", ep->mtu);
+	USB_LOG_DBG("ctx[2]=0x%x\n", *((uint32_t*)ctx + 2));
+	USB_LOG_DBG("ctx[3]=0x%x\n", *((uint32_t*)ctx + 3));
+	USB_LOG_DBG("	dequeue: 0x%lx \r\n", ep->dequeue);
+	USB_LOG_DBG("	dcs: 0x%lx \r\n", !!(XHCI_EPCTX_DCS & ep->dequeue));
+	USB_LOG_DBG("ctx[4]=0x%x\n", *((uint32_t*)ctx + 4));
+	USB_LOG_DBG("	trb_len: 0x%x \r\n", ep->trb_len);
+	USB_LOG_DBG("	esit_low: 0x%x \r\n", ep->esit_low);		
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}
+
+/**
+ * Dump input context
+ *
+ * @v xhci		XHCI device
+ * @v endpoint  Endpoint
+ * @v input		Input context
+ */
+void xhci_dump_input_ctx( struct xhci_host *xhci, const struct xhci_endpoint *endpoint, const void *input) {
+#if XHCI_DUMP_INPUT_CTX
+	const struct xhci_control_context *control_ctx;
+	const struct xhci_slot_context *slot_ctx;
+	const struct xhci_endpoint_context *ep_ctx;
+
+	control_ctx = input;
+	slot_ctx = ( input + xhci_input_context_offset ( xhci, XHCI_CTX_SLOT ));
+	ep_ctx = ( input + xhci_input_context_offset ( xhci, endpoint->ctx ) );
+
+	USB_LOG_DBG("===input ctx====\n");
+	USB_LOG_DBG("ctrl@%p=0x%x\n", control_ctx, *control_ctx);
+    USB_LOG_DBG("add=0x%x\n", control_ctx->add);
+    USB_LOG_DBG("del=0x%x\n", control_ctx->drop);
+
+	USB_LOG_DBG("slot@%p\n", slot_ctx);	
+	xhci_dump_slot_ctx(slot_ctx);
+
+	USB_LOG_DBG("ep-%d@%p\n", endpoint->ctx, ep_ctx);
+	xhci_dump_ep_ctx(ep_ctx);
+
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}
+
+/**
+ * Get next TRB in ring
+ *
+ * @v trbs		TRB in ring
+ * @v trb  		Next TRB
+ */
+static const union xhci_trb * xhci_get_next_trb(const union xhci_trb *trbs) {
+	const struct xhci_trb_link *link = &(trbs->link);
+	if (link->type == XHCI_TRB_LINK) {
+		return (link->next) ? (const union xhci_trb *)(link->next) : NULL;
+	} else {
+		return trbs + 1;
+	}
+}
+
+/**
+ * Dump TRB
+ *
+ * @v trbs		TRB header
+ * @v count  	Number of TRB to dump
+ */
+void xhci_dump_trbs(const union xhci_trb *trbs, unsigned int count) {
+#if XHCI_DUMP_TRB
+	const union xhci_trb *cur;
+	const struct xhci_trb_common *comm;
+	const uint8_t *dword;
+
+	USB_LOG_DBG("===trbs    ====\n");
+	for (unsigned int i = 0; i < count; i++) {
+		cur = &(trbs[i]);
+		dword = (const uint8_t *)cur;
+
+		comm = &(cur->common);
+		USB_LOG_DBG("[0x%x-0x%x-0x%x-0x%x]\n", 
+					*((uint32_t *)dword), *((uint32_t *)dword + 1), 
+					*((uint32_t *)dword + 2), *((uint32_t *)dword + 3));
+		if (XHCI_TRB_SETUP == comm->type) {
+			const struct xhci_trb_setup *setup = (const struct xhci_trb_setup *)comm;
+
+			USB_LOG_DBG("setup trb\n");
+			USB_LOG_DBG("	packet=0x%x\n", setup->packet);
+			USB_LOG_DBG("		bmRequestType type=0x%x\n", setup->packet.bmRequestType);
+			USB_LOG_DBG("		bRequest=0x%x\n", setup->packet.bRequest);
+			USB_LOG_DBG("		wValue=0x%x\n", setup->packet.wValue);
+			USB_LOG_DBG("		wIndex=0x%x\n", setup->packet.wIndex);
+			USB_LOG_DBG("		wLength=0x%x\n", setup->packet.wLength);
+			USB_LOG_DBG("	trb_trans_len=%d\n", setup->len);
+			USB_LOG_DBG("	flags=0x%x\n", setup->flags);
+			USB_LOG_DBG("	direction=%d\n", setup->direction);
+		} else if (XHCI_TRB_DATA == comm->type) {
+			const struct xhci_trb_data *data = (const struct xhci_trb_data *)comm;
+
+			USB_LOG_DBG("data trb......\n");
+			USB_LOG_DBG("	data=0x%x\n", data->data);
+			USB_LOG_DBG("	len=%d\n", data->len);
+			USB_LOG_DBG("	direction=%d\n", data->direction);
+		} else if (XHCI_TRB_STATUS == comm->type) {
+			const struct xhci_trb_status *status = (const struct xhci_trb_status *)comm;
+
+			USB_LOG_DBG("status trb......\n");
+			USB_LOG_DBG("	direction=%d\n", status->direction);
+		}
+	}
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}
+
+static const char *xhci_endpoint_xhci_type (unsigned int ep_xhci_type) {
+	static const char *ep_names[] = {"not_valid", "isoc_out", "bulk_out", 
+									 "intr_out", "ctrl", "isoc_in",
+									 "bulk_in", "intr_in"};
+	unsigned int index = ep_xhci_type >> 3;
+	if (index < sizeof(ep_names)/sizeof(ep_names[0])) {
+		return ep_names[index];
+	}
+
+	return "unkown";
+}
+
+static const char *xhci_endpoint_type (unsigned int ep_type) {
+	const char *ep_name = "unkown";
+
+	switch (ep_type)
+	{
+	case USB_ENDPOINT_TYPE_CONTROL:
+		ep_name = "ctrl-ep";
+		break;
+	case USB_ENDPOINT_TYPE_ISOCHRONOUS:
+		ep_name = "isoc-ep";
+		break;
+	case USB_ENDPOINT_TYPE_BULK:
+		ep_name = "bulk-ep";
+		break;
+	case USB_ENDPOINT_TYPE_INTERRUPT:
+		ep_name = "intr-ep";
+		break;
+	default:
+		break;
+	}
+
+	return ep_name;
+}
+
+/**
+ * Dump Endpoint
+ *
+ * @v ep		Endpoint
+ */
+void xhci_dump_endpoint(const struct xhci_endpoint *ep) {
+#if XHCI_DUMP_ENDPOINT
+	USB_LOG_DBG("===endpoint====\n");
+	USB_LOG_DBG("xhci=0x%x\n", ep->xhci);
+	USB_LOG_DBG("slot=0x%x\n", ep->slot);
+	USB_LOG_DBG("address=0x%x\n", ep->address);
+	USB_LOG_DBG("mtu=0x%x\n", ep->mtu);
+	USB_LOG_DBG("burst=0x%x\n", ep->burst);
+	USB_LOG_DBG("ctx=0x%x\n", ep->ctx);
+	USB_LOG_DBG("ep_type=%s\n", xhci_endpoint_type(ep->ep_type));
+	USB_LOG_DBG("xhci_type=%s\n", xhci_endpoint_xhci_type(ep->ctx_type));
+	USB_LOG_DBG("interval=0x%x\n", ep->interval);
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}
+
+/**
+ * Dump Port status
+ *
+ * @v port		Port number
+ * @v portsc	Port status
+ */
+void xhci_dump_port_status(uint32_t port, uint32_t portsc) {
+#if XHCI_DUMP_PORT_STATUS
+	USB_LOG_DBG("====port-%d====\n");
+	USB_LOG_DBG("connect=%d \n", !!(XHCI_PORTSC_CCS & port));
+	USB_LOG_DBG("enabled=%d \n", !!(XHCI_PORTSC_PED & port));
+	USB_LOG_DBG("powered=%d \n", !!(XHCI_PORTSC_PP & port));
+	USB_LOG_DBG("=====+++++++++===== \r\n");
+#endif
+}

+ 416 - 446
port/xhci/xhci_reg.h

@@ -1,38 +1,31 @@
 /*
- * Copyright : (C) 2022 Phytium Information Technology, Inc. 
+ * Copyright : (C) 2022 Phytium Information Technology, Inc.
  * All Rights Reserved.
- *  
- * This program is OPEN SOURCE software: you can redistribute it and/or modify it  
- * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,  
- * either version 1.0 of the License, or (at your option) any later version. 
- *  
- * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;  
+ *
+ * This program is OPEN SOURCE software: you can redistribute it and/or modify it
+ * under the terms of the Phytium Public License as published by the Phytium Technology Co.,Ltd,
+ * either version 1.0 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY;
  * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the Phytium Public License for more details. 
- *  
- * 
+ * See the Phytium Public License for more details.
+ *
+ *
  * FilePath: xhci_reg.h
  * Date: 2022-07-19 09:26:25
  * LastEditTime: 2022-07-19 09:26:25
- * Description:  This files is for xhci register definition
- * 
- * Modify History: 
+ * Description:  This file is for xhci register definition.
+ *
+ * Modify History:
  *  Ver   Who        Date         Changes
  * ----- ------     --------    --------------------------------------
  * 1.0   zhugengyu  2022/9/19   init commit
+ * 2.0   zhugengyu  2023/3/29   support usb3.0 device attached at roothub
  */
-#ifndef  XHCI_REG_H
-#define  XHCI_REG_H
 
-/***************************** Include Files *********************************/
-#include "usbh_core.h"
+#ifndef XHCI_REG_H
+#define XHCI_REG_H
 
-#ifdef __cplusplus
-extern "C"
-{
-#endif
-
-/************************** Constant Definitions *****************************/
 #if defined(__aarch64__)
 #define BITS_PER_LONG 64U
 #define XHCI_AARCH64
@@ -42,431 +35,356 @@ extern "C"
 #endif
 
 #define XHCI_GENMASK(h, l) \
-	(((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
+    (((~0UL) - (1UL << (l)) + 1) & (~0UL >> (BITS_PER_LONG - 1 - (h))))
 
 #define XHCI_GENMASK_ULL(h, l)            \
-	(((~0ULL) - (1ULL << (l)) + 1) & \
-	 (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
+    (((~0ULL) - (1ULL << (l)) + 1) & \
+     (~0ULL >> (BITS_PER_LONG_LONG - 1 - (h))))
 
 #define XHCI32_GET_BITS(x, a, b)                  (uint32_t)((((uint32_t)(x)) & XHCI_GENMASK(a, b)) >> b)
 #define XHCI32_SET_BITS(x, a, b)                  (uint32_t)((((uint32_t)(x)) << b) & XHCI_GENMASK(a, b))
 #define XHCI64_GET_BITS(x, a, b)                  (uint64_t)((((uint64_t)(x)) & XHCI_GENMASK_ULL(a, b)) >> b)
 #define XHCI64_SET_BITS(x, a, b)                  (uint64_t)((((uint64_t)(x)) << b) & XHCI_GENMASK_ULL(a, b))
 
-/** @name Register Map
- *
- * Register offsets from the base address of an XHCI device.
- * @{
- */
-#define XHCI_REG_CAP_CAPLENGTH		    0x00    /* specify the limits, restrictions and capabilities */
-#define XHCI_REG_CAP_HCIVERSION		    0x02    /* Interface Version Number */
-#define XHCI_REG_CAP_HCS1		        0x04	/* Host Controller Structural Parameters 1 */
-#define XHCI_REG_CAP_HCS2		        0x08	/* Host Controller Structural Parameters 2 */
-#define XHCI_REG_CAP_HCS3		        0x0C	/* Host Controller Structural Parameters 3 */
-#define XHCI_REG_CAP_HCC		        0x10	/* Capability Parameters 1 */
-#define XHCI_REG_CAP_DBOFF		        0x14	/* Doorbell Offset Register */
-#define XHCI_REG_CAP_RTSOFF		        0x18	/* Runtime Register Space Offset Register */
-
-/***************** Host Controller Operational Registers ***********************/
-#define XHCI_REG_OP_USBCMD		        0x00	/* USB Command Register */
-#define XHCI_REG_OP_USBSTS		        0x04	/* USB Status Register */
-#define XHCI_REG_OP_PAGESIZE	        0x08	/* Page Size Register */
-#define XHCI_REG_OP_DNCTRL		        0x14	/* Device Notification Control Register */
-#define XHCI_REG_OP_CRCR		        0x18	/* Command Ring Control Register */
-#define XHCI_REG_OP_DCBAAP		        0x30	/* Device Context Base Address Array Pointer Register */
-#define XHCI_REG_OP_CONFIG		        0x38	/* Configure Register */
-
-/* Port Status and Ctrl Register : OP Base + (400h + (10h * (n–1))) 'n' is port num */
-#define XHCI_REG_OP_PORTS_BASE		    0x400	/* Port Status and Control Register Base */
-#define XHCI_REG_OP_PORTS_SIZE          0x10    /* Size of one Port SC Register */
-#define XHCI_REG_OP_PORTS_OFF(port, off)   ((port) * XHCI_REG_OP_PORTS_SIZE + offset)
-
-#define XHCI_REG_OP_PORTS_PORTSC	    0x00	/* Port Status and Control Register */
-#define XHCI_REG_OP_PORTS_PORTPMSC	    0x04	/* USB3 Port Power Management Status and Control Register */
-#define XHCI_REG_OP_PORTS_PORTLI	    0x08	/* Port Link Info Register */
-
-/***************** Host Controller Runtime Registers ***********************/
-#define XHCI_REG_RT_MFINDEX		        0x00	/* Microframe Index */
-#define XHCI_REG_RT_IR0			        0x20	/* Interrupter Register Set 0 */
-#define XHCI_REG_RT_IR1023		        0x8000	/* Interrupter Register Set 1023 */
-
-/* Interrupter Register Set : RT Base + 020h + (32 * Interrupter) */
-#define XHCI_REG_RT_IR_IMAN		        0x00	/* Interrupter Management Register */
-#define XHCI_REG_RT_IR_IMOD		        0x04	/* Interrupter Moderation Register */
-#define XHCI_REG_RT_IR_ERSTSZ		    0x08	/* Event Ring Segment Table Size Register */
-#define XHCI_REG_RT_IR_ERSTBA   	    0x10	/* Event Ring Segment Table Base Address Register */
-#define XHCI_REG_RT_IR_ERDP		        0x18	/* Event Ring Dequeue Pointer Register */
-#define XHCI_REG_RT_IR_SIZE             0x20    /* Size of one IR Register */
-
-/***************** Doorbell Register ***********************/
-#define XHCI_REG_DB_SIZE                4       /* Doorbell registers are 32 bits in length */
-
-/***************** eXtensible Host Controller Capability Registers ***********************/
-
-/** @name XHCI_REG_CAP_HCS1 Register 
- */
-#define XHCI_REG_CAP_HCS1_MAX_SLOTS_GET(x)    XHCI32_GET_BITS(x, 7, 0)  /* Number of Device Slots (MaxSlots) */
-#define XHCI_REG_CAP_HCS1_MAX_INTRS_GET(x)	  XHCI32_GET_BITS(x, 18, 8)  /* Number of Interrupters (MaxIntrs) */
-#define XHCI_REG_CAP_HCS1_MAX_PORTS_GET(x)	  XHCI32_GET_BITS(x, 31, 24) /* Number of Ports (MaxPorts) */
+/** Capability register length */
+#define XHCI_CAP_CAPLENGTH 0x00
 
-/** @name XHCI_REG_CAP_HCS2 Register 
- */
-#define XHCI_REG_CAP_HCS2_IST_GET(x)			        XHCI32_GET_BITS(x, 3, 0)	/* Isochronous Scheduling Threshold (IST) */
-#define XHCI_REG_CAP_HCS2_ERST_MAX_GET(x)		        XHCI32_GET_BITS(x, 7, 4)  /* Event Ring Segment Table Max (ERST Max) */
-#define XHCI_REG_CAP_HCS2_SPR					        (1 << 26)                   /* Scratchpad Restore (SPR) */
-#define XHCI_REG_CAP_HCS2_MAX_SCRATCHPAD_BUFS_GET(x)	XHCI32_GET_BITS(x, 25, 21) | XHCI32_GET_BITS(x, 31, 27)    /* Max Scratchpad Buffers (Max Scratchpad Bufs) */
+/** Host controller interface version number */
+#define XHCI_CAP_HCIVERSION 0x02
 
-/** @name XHCI_REG_CAP_HCS3 Register 
- */
-#define XHCI_REG_CAP_HCS3_U1_DEV_EXIT_LATENCY_GET(x)	XHCI32_GET_BITS(x, 7, 0)	/* U1 Device Exit Latency */
-#define XHCI_REG_CAP_HCS3_U2_DEV_EXIT_LATENCY_GET(x)	XHCI32_GET_BITS(x, 31, 16) /* U2 Device Exit Latency */
+/** Structural parameters 1 */
+#define XHCI_CAP_HCSPARAMS1 0x04
 
-/** @name XHCI_REG_CAP_HCC Register 
- */
-#define XHCI_REG_CAP_HCC_AC64		                (1 << 0)	/* 64-bit Addressing Capabilitya 1: 64-bit */
-#define XHCI_REG_CAP_HCC_BNC			            (1 << 1)	/* BW Negotiation Capability (BNC) 1: support */
-#define XHCI_REG_CAP_HCC_CSZ			            (1 << 2)	/* Context Size (CSZ) 1: 64 byte context data */
-#define XHCI_REG_CAP_HCC_PPC			            (1 << 3)	/* Port Power Control (PPC) 1: support */
-#define XHCI_REG_CAP_HCC_PIND		                (1 << 4)	/* Port Indicators (PIND) 1: support */
-#define XHCI_REG_CAP_HCC_LHRC		                (1 << 5)	/* Light HC Reset Capability (LHRC) 1: support */
-#define XHCI_REG_CAP_HCC_LTC			            (1 << 6)	/* Latency Tolerance Messaging Capability (LTC) */
-#define XHCI_REG_CAP_HCC_NSS			            (1 << 7)	/* No Secondary SID Support (NSS) */
-#define XHCI_REG_CAP_HCC_MAX_PSA_SIZE_GET(x)	    XHCI32_GET_BITS(x, 15, 12)    /* Maximum Primary Stream Array Size (MaxPSASize) */
-#define XHCI_REG_CAP_HCC_XECP_GET(x)			    XHCI32_GET_BITS(x, 31, 16)    /* xHCI Extended Capabilities Pointer (xECP) */
-
-/** @name XHCI_REG_CAP_DBOFF Register 
- */
-#define XHCI_REG_CAP_DBOFF_GET(x)        ((x) & XHCI_GENMASK(31, 2))  /* 32-byte offset of the Doorbell Array base address from the Base */
+/** Number of device slots */
+#define XHCI_HCSPARAMS1_SLOTS(params) ( ( (params) >> 0 ) & 0xff )
 
-/** @name XHCI_REG_CAP_RTSOFF Register 
- */
-#define XHCI_REG_CAP_RTSOFF_GET(x)       ((x) & XHCI_GENMASK(31, 5)) /* 32-byte offset of the xHCI Runtime Registers */
+/** Number of interrupters */
+#define XHCI_HCSPARAMS1_INTRS(params) ( ( (params) >> 8 ) & 0x3ff )
 
+/** Number of ports */
+#define XHCI_HCSPARAMS1_PORTS(params) ( ( (params) >> 24 ) & 0xff )
 
-/***************** Host Controller Operational Registers ***********************/
+/** Structural parameters 2 */
+#define XHCI_CAP_HCSPARAMS2 0x08
 
-/** @name XHCI_REG_OP_USBCMD Register 
- */
-#define XHCI_REG_OP_USBCMD_RUN_STOP		    (1 << 0)	/* Run/Stop (R/S) 1: RUN, 0: STOP - RW */
-#define XHCI_REG_OP_USBCMD_HCRST			(1 << 1)	/* Host Controller Reset (HCRST) 1: RESET - RW */
-#define XHCI_REG_OP_USBCMD_INTE			    (1 << 2)	/* Interrupter Enable (INTE) 1: enabled - RW */
-#define XHCI_REG_OP_USBCMD_HSEE			    (1 << 3)	/* Host System Error Enable (HSEE) - RW */
-#define XHCI_REG_OP_USBCMD_LHCRST			(1 << 7)	/* Light Host Controller Reset (LHCRST) - RW */
-#define XHCI_REG_OP_USBCMD_CSS				(1 << 8)	/* Controller Save State (CSS) - RW */
-#define XHCI_REG_OP_USBCMD_CRS				(1 << 9)	/* Controller Restore State (CRS) - RW */
-#define XHCI_REG_OP_USBCMD_EWE				(1 << 10)	/* Enable Wrap Event (EWE) - RW */
-#define XHCI_REG_OP_USBCMD_EU3S			    (1 << 11)	/* Enable U3 MFINDEX Stop (EU3S) - RW */
-
-/** @name XHCI_REG_OP_USBSTS Register 
- */
-#define XHCI_REG_OP_USBSTS_HCH				(1 << 0)	/* 1: Stopped executing */
-#define XHCI_REG_OP_USBSTS_HSE				(1 << 2)	/* 1: Serious error detected */
-#define XHCI_REG_OP_USBSTS_EINT				(1 << 3)	/* 1: Interrupt Pending (IP) */
-#define XHCI_REG_OP_USBSTS_PCD				(1 << 4)	/* 1: Port Change Detect */
-#define XHCI_REG_OP_USBSTS_SSS				(1 << 8)	/* remain 1 while the xHC saves its internal state */
-#define XHCI_REG_OP_USBSTS_RSS				(1 << 9)	/* remain 1 while the xHC restores its internal state */
-#define XHCI_REG_OP_USBSTS_SRE				(1 << 10)	/* if error occurs during a Save or Restore operation this bit shall be set to ‘1’. */
-#define XHCI_REG_OP_USBSTS_CNR				(1 << 11)	/* 1: Controller Not Ready */
-#define XHCI_REG_OP_USBSTS_HCE				(1 << 12)	/* 1: Internal xHC error condition */
-#define XHCI_REG_OP_USBSTS_PRSRV_MASK		((1 << 1) | 0xffffe000) /* Rsvd bits */
-
-
-/** @name XHCI_REG_OP_PAGESIZE Register 
- */
-/* This xHC supports a page size of 2^(n+12) if bit n is Set */
-#define XHCI_REG_OP_PAGESIZE_4K				(1 << 0)    /* if bit 0 is Set, the xHC supports 4k byte page sizes */
+/** Number of page-sized scratchpad buffers */
+#define XHCI_HCSPARAMS2_SCRATCHPADS(params) \
+	( ( ( (params) >> 16 ) & 0x3e0 ) | ( ( (params) >> 27 ) & 0x1f ) )
 
-/** @name XHCI_REG_OP_CRCR Register 
- */
-#define XHCI_REG_OP_CRCR_RCS				(1 << 0)	/* Ring Cycle State, value of the xHC Consumer Cycle State (CCS) flag */
-#define XHCI_REG_OP_CRCR_CS					(1 << 1)	/* Command Stop, 1 */
-#define XHCI_REG_OP_CRCR_CA					(1 << 2)	/* Command Abort, 1 */
-#define XHCI_REG_OP_CRCR_CRR				(1 << 3)	/* Command Ring Running */
-#define XHCI_REG_OP_CRCR_CR_PTR_MASK		XHCI_GENMASK_ULL(63, 6)	/* Command Ring Pointer, Dequeue Ptr of Command Ring */
+/** Capability parameters */
+#define XHCI_CAP_HCCPARAMS1 0x10
 
-/** @name XHCI_REG_OP_DCBAAP Register 
- */
-#define XHCI_REG_OP_DCBAAP_MASK                     XHCI_GENMASK_ULL(63, 6)	            /* bit[31:6] Ptr of DCBAA */
+/** 64-bit addressing capability */
+#define XHCI_HCCPARAMS1_ADDR64(params) ( ( (params) >> 0 ) & 0x1 )
 
-/** @name XHCI_REG_OP_CONFIG Register 
- */
-#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_MASK        XHCI_GENMASK(7, 0)               /* Max Device Slots Enabled (MaxSlotsEn) – RW */
-#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_SET(x)		XHCI32_SET_BITS(x, 7, 0)	/* bit[7:0] Max Device Slots Enabled */
-#define XHCI_REG_OP_CONFIG_MAX_SLOTS_EN_GET(x)      XHCI32_GET_BITS(x, 7, 0)
+/** Context size shift */
+#define XHCI_HCCPARAMS1_CSZ_SHIFT(params) ( 5 + ( ( (params) >> 2 ) & 0x1 ) )
 
-/** @name XHCI_REG_OP_PORTS_PORTSC Register 
- */
-#define XHCI_REG_OP_PORTS_PORTSC_CCS			(1 << 0)	/* Current Connect Status (CCS) – ROS */
-#define XHCI_REG_OP_PORTS_PORTSC_PED			(1 << 1)	/* Port Enabled/Disabled (PED) – RW1CS */
-#define XHCI_REG_OP_PORTS_PORTSC_OCA			(1 << 3)	/* Over-current Active (OCA) – RO */
-#define XHCI_REG_OP_PORTS_PORTSC_PR				(1 << 4)	/* Port Reset (PR) – RW1S */
-#define XHCI_REG_OP_PORTS_PORTSC_PLS_GET(x) 	XHCI32_GET_BITS(x, 8, 5)	/* Port Link State (PLS) – RWS */
-#define XHCI_REG_OP_PORTS_PORTSC_PLS_SET(x) 	XHCI32_SET_BITS(x, 8, 5)
-#define XHCI_REG_OP_PORTS_PORTSC_PLS_MASK		XHCI_GENMASK(8, 5)
-#define XHCI_REG_OP_PORTS_PORTSC_PLS(x)			(x << 5)
-#define XHCI_REG_OP_PORTS_PORTSC_PLS_SET(x)	  	XHCI32_SET_BITS(x, 8, 5)
-
-enum PLSStatus{
-    PLS_U0              =  0,
-    PLS_U1              =  1,
-    PLS_U2              =  2,
-    PLS_U3              =  3,
-    PLS_DISABLED        =  4,
-    PLS_RX_DETECT       =  5,
-    PLS_INACTIVE        =  6,
-    PLS_POLLING         =  7,
-    PLS_RECOVERY        =  8,
-    PLS_HOT_RESET       =  9,
-    PLS_COMPILANCE_MODE = 10,
-    PLS_TEST_MODE       = 11,
-    PLS_RESUME          = 15,
-}; /* Port status type */
-
-#define XHCI_REG_OP_PORTS_PORTSC_PP (1 << 9)			/* Port Power (PP) – RWS */
-#define XHCI_REG_OP_PORTS_PORTSC_PORT_SPEED_GET(x) XHCI32_GET_BITS(x, 13, 10)	/* Port Speed (Port Speed) – ROS */
-
-/* Protocol Speed ID (PSI) */
-#define XHCI_PORT_SPEED_UNKOWN		0U
-#define XHCI_PORT_SPEED_FULL		1U
-#define XHCI_PORT_SPEED_LOW			2U
-#define XHCI_PORT_SPEED_HIGH		3U
-#define XHCI_PORT_SPEED_SUPER		4U
-
-#define XHCI_REG_OP_PORTS_PORTSC_PIC_SET(x)   XHCI32_SET_BITS(x, 15, 14)
-#define XHCI_REG_OP_PORTS_PORTSC_PIC_MASK	  XHCI_GENMASK(15, 14)
-
-#define XHCI_REG_OP_PORTS_PORTSC_LWS (1 << 16)		 /* Port Link State Write Strobe (LWS) */
-#define XHCI_REG_OP_PORTS_PORTSC_CSC (1 << 17)		 /* Connect Status Change (CSC) */
-#define XHCI_REG_OP_PORTS_PORTSC_PEC (1 << 18)		 /* Port Enabled/Disabled Change (PEC) 1: clear PED */
-#define XHCI_REG_OP_PORTS_PORTSC_WRC (1 << 19)		 /* Warm Port Reset Change 1: Warm Reset complete */
-#define XHCI_REG_OP_PORTS_PORTSC_OCC (1 << 20)		 /* Over-current Change 1: Over-current Active */
-#define XHCI_REG_OP_PORTS_PORTSC_PRC (1 << 21)		 /* Port Reset Change 1: Transition of Port Reset */
-#define XHCI_REG_OP_PORTS_PORTSC_PLC (1 << 22)		 /* Port Link State Change 1: PLS transition */
-#define XHCI_REG_OP_PORTS_PORTSC_CEC (1 << 23)		 /* Port Config Error Change 1: Port Config Error detected */
-#define XHCI_REG_OP_PORTS_PORTSC_CAS (1 << 24)		 /* Cold Attach Status  1: Far-end Receiver Terminations were detected */
-#define XHCI_REG_OP_PORTS_PORTSC_WCE (1 << 25)		 /* Wake on Connect Enable 1: enable port to be sensitive to device connects */
-#define XHCI_REG_OP_PORTS_PORTSC_WDE (1 << 26)		 /* Wake on Disconnect Enable 1: enable port to be sensitive to device disconnects */
-#define XHCI_REG_OP_PORTS_PORTSC_WOE (1 << 27)		 /* Wake on Over-current Enable 1: enable port to be sensitive to  over-current conditions */
-#define XHCI_REG_OP_PORTS_PORTSC_DR  (1 << 30)		 /* Device Removable, 0: Device is removable. 1:  Device is non-removable */
-#define XHCI_REG_OP_PORTS_PORTSC_WPR (1 << 31)		 /* Warm Port Reset 1: follow Warm Reset sequence */
-#define XHCI_REG_OP_PORTS_PORTSC_RW_MASK (XHCI_REG_OP_PORTS_PORTSC_PR | XHCI_REG_OP_PORTS_PORTSC_PLS_MASK | XHCI_REG_OP_PORTS_PORTSC_PP \
-										| XHCI_REG_OP_PORTS_PORTSC_PIC_MASK | XHCI_REG_OP_PORTS_PORTSC_LWS | XHCI_REG_OP_PORTS_PORTSC_WCE \
-										| XHCI_REG_OP_PORTS_PORTSC_WDE | XHCI_REG_OP_PORTS_PORTSC_WOE)
-
-
-/***************** Host Controller Runtime Registers ***********************/
-
-/** @name XHCI_REG_RT_IR_IMAN Register 
- */
-#define XHCI_REG_RT_IR_IMAN_IP				(1 << 0)	/* Interrupt Pending, 1: an interrupt is pending for this Interrupter */
-#define XHCI_REG_RT_IR_IMAN_IE				(1 << 1)	/* Interrupt Enable, 1: capable of generating an interrupt. */
+/** xHCI extended capabilities pointer */
+#define XHCI_HCCPARAMS1_XECP(params) ( ( ( (params) >> 16 ) & 0xffff ) << 2 )
 
-/** @name XHCI_REG_RT_IR_IMOD Register 
- */
-#define XHCI_REG_RT_IR_IMOD_IMODI_MASK			XHCI_GENMASK(15, 0)	/* bit[15:0] Interrupt Moderation Interval default 4000 ==> 1ms  */
-#define XHCI_REG_RT_IR_IMOD_IMODC_MASK			XHCI_GENMASK(31, 16)	/* bit[31:16] Interrupt Moderation Counter(Down counter) */
+/** Doorbell offset */
+#define XHCI_CAP_DBOFF 0x14
 
-/** @name XHCI_REG_RT_IR_ERSTSZ Register 
- */
-#define XHCI_REG_RT_IR_ERSTSZ_MASK			    XHCI_GENMASK(15, 0)	/* bit[15:0] the number of valid Event Ring Segment Table entries */
+/** Runtime register space offset */
+#define XHCI_CAP_RTSOFF 0x18
 
-/** @name XHCI_REG_RT_IR_ERSTBA Register 
- */
-#define XHCI_REG_RT_IR_ERSTBA_MASK			    XHCI_GENMASK_ULL(63, 6) /* Event Ring Segment Table Base Address */
+/** xHCI extended capability ID */
+#define XHCI_XECP_ID(xecp) ( ( (xecp) >> 0 ) & 0xff )
 
-/** @name XHCI_REG_RT_IR_ERDP Register 
- */
-#define XHCI_REG_RT_IR_ERDP_DESI_MASK			XHCI_GENMASK_ULL(2, 0)	/* bit[2:0] Dequeue ERST Segment Index */
-#define XHCI_REG_RT_IR_ERDP_EHB					(1 << 3)			/* Event Handler Busy */
-#define XHCI_REG_RT_IR_ERDP_MASK				XHCI_GENMASK_ULL(63, 4)	/* Event Ring Dequeue Pointer */
-
-/***************** Doorbell Register ***********************/
-#define XHCI_REG_DB_TARGET_HC_COMMAND			0   /* Host Controller Doorbell (0) Command Doorbell */
-#define XHCI_REG_DB_TARGET_EP0					1   /* Device Context Doorbells Control EP 0 Enqueue Pointer Update */
-#define XHCI_REG_DB_TARGET_EP1_OUT				2   /* EP 1 OUT Enqueue Pointer Update */
-#define XHCI_REG_DB_TARGET_EP1_IN				3   /* EP 1 IN Enqueue Pointer Update */
-#define XHCI_REG_DB_TARGET_EP15_OUT				30	/* EP 15 OUT Enqueue Pointer Update */
-#define XHCI_REG_DB_TARGET_EP15_IN				31  /* EP 15 IN Enqueue Pointer Update */
-
-/***************** xHCI Extended Capabilities Registers ***********************/
-#define XHCI_REG_EXT_CAP_USBSPCF_OFFSET			     0x0
-#define XHCI_REG_EXT_CAP_CAP_ID_GET(x)				 XHCI32_GET_BITS(x, 7, 0)
-#define XHCI_REG_EXT_NEXT_CAP_PTR_GET(x)             XHCI32_GET_BITS(x, 15, 8)
-/* refer to 'Table 138: xHCI Extended Capability Codes' for more details */
-enum
-{
-	XHCI_EXT_CAP_ID_USB_LEGACY_SUPPORT 		= 1,
-	XHCI_EXT_CAP_ID_SUPPORT_PROTOCOL 		= 2,
-	XHCI_EXT_CAP_ID_EXTEND_POWER_MANAGEMENT = 3,
-	XHCI_EXT_CAP_ID_IO_VIRTUALIZATION 		= 4,
-	XHCI_EXT_CAP_ID_MESSAGE_INTERRUPT 		= 5,
-	XHCI_EXT_CAP_ID_LOCAL_MEMORY 			= 6,
-	XHCI_EXT_CAP_ID_USB_DEBUG_CAPABILITY 	= 10,
-	XHCI_EXT_CAP_ID_EXT_MESSAGE_INTERRUPT 	= 17,
-
-	XHCI_EXT_CAP_ID_VENDOR_DEFINED_MIN 		= 192,
-	XHCI_EXT_CAP_ID_VENDOR_DEFINED_MAX 		= 255
-};
+/** Next xHCI extended capability pointer */
+#define XHCI_XECP_NEXT(xecp) ( ( ( (xecp) >> 8 ) & 0xff ) << 2 )
 
-/* xHCI Supported Protocol Capability */
-#define XHCI_REG_EXT_CAP_USBSPCFDEF_OFFSET		    0x4
-
-#define XHCI_USBSPCF_MINOR_REVERSION_GET(x)		    XHCI32_GET_BITS(x, 23, 16)
-#define XHCI_USBSPCF_MAJOR_REVERSION_GET(x) 		XHCI32_GET_BITS(x, 31, 24)
-
-#define XHCI_USBSPCFDEF_NAME_STRING_GET(x)		    XHCI32_GET_BITS(x, 31, 0)	/* four ASCII characters may be defined */
-#define XHCI_USBSPCFDEF_NAME_STRING_USB		        0x20425355 /* ASCII = "USB" */
-
-#define XHCI_REG_EXT_CAP_USBSPCFDEF2_OFFSET		    0x8
-#define XHCI_USBSPCFDEF2_COMPATIBLE_PORT_OFF_GET(x) XHCI32_GET_BITS(x, 7, 0)
-#define XHCI_USBSPCFDEF2_COMPATIBLE_PORT_CNT_GET(x) XHCI32_GET_BITS(x, 15, 8)
-#define XHCI_USBSPCFDEF2_PROTOCOL_DEFINED_GET(x)	XHCI32_GET_BITS(x, 27, 16)
-
-/* trb bit definitions */
-
-/* configuration */
-#define XHCI_RING_ITEMS     16U
-#define XHCI_ALIGMENT       64U
-#define XHCI_RING_SIZE      (XHCI_RING_ITEMS*sizeof(struct xhci_trb))
-
-#define TRB_C               (1<<0)
-#define TRB_TYPE_SHIFT      10
-#define TRB_TYPE_MASK       0x3f
-#define TRB_TYPE_GET(val)   XHCI32_GET_BITS(val, 15, 10)
-#define TRB_TYPE_SET(t)     XHCI32_SET_BITS(t, 15, 10)
-
-#define TRB_EV_ED           (1<<2)
-
-#define TRB_TR_ENT          (1<<1)
-#define TRB_TR_ISP          (1<<2)
-#define TRB_TR_NS           (1<<3)
-#define TRB_TR_CH           (1<<4)
-#define TRB_TR_IOC          (1<<5)
-#define TRB_TR_IDT          (1<<6)
-#define TRB_TR_TBC_SHIFT    7
-#define TRB_TR_TBC_MASK     0x3
-#define TRB_TR_BEI          (1<<9)
-#define TRB_TR_TLBPC_SHIFT  16
-#define TRB_TR_TLBPC_MASK   0xf
-#define TRB_TR_FRAMEID_SHIFT 20
-#define TRB_TR_FRAMEID_MASK 0x7ff
-#define TRB_TR_SIA          (1<<31)
-#define TRB_TR_TRANS_LEN_SET(len)  XHCI32_SET_BITS(len, 23, 0)    
-#define TRB_TR_TRANS_LEN_MASK      XHCI_GENMASK(23, 0)
-
-#define TRB_TR_DIR           (1<<16)
-#define TRB_TR_TYPE_SET(t)   XHCI32_SET_BITS(t, 17, 16)
-#define TRB_TR_NO_DATA      0U
-#define TRB_TR_OUT_DATA     2U
-#define TRB_TR_IN_DATA      3U
-
-#define TRB_CC_GET(val)          XHCI32_GET_BITS(val, 31, 24)
-#define TRB_PORT_ID_GET(val)     XHCI32_GET_BITS(val, 31, 24)
-
-
-#define TRB_CR_SLOTID_SHIFT 24
-#define TRB_CR_SLOTID_MASK  0xff
-#define TRB_CR_SLOTID_SET(id)    XHCI32_SET_BITS(id, 31, 24)
-#define TRB_CR_SLOTID_GET(val)   XHCI32_GET_BITS(val, 31, 24)
-
-#define TRB_CR_EPID_SHIFT   16
-#define TRB_CR_EPID_MASK    0x1f
-#define TRB_CR_EPID_SET(id)      XHCI32_SET_BITS(id, 20, 16)
-#define TRB_CR_EPID_GET(field)   XHCI32_GET_BITS(field, 20, 16)
-
-#define TRB_CR_BSR          (1<<9)
-#define TRB_CR_DC           (1<<9)
-
-#define TRB_LK_TC           (1<<1)
-
-#define TRB_INTR_SHIFT      22
-#define TRB_INTR_MASK       0x3ff
-#define TRB_INTR(t)         (((t).status >> TRB_INTR_SHIFT) & TRB_INTR_MASK)
-
-/************************** Type Definitions *********************************/
-enum TRBType {
-    TRB_RESERVED = 0,
-    TR_NORMAL,
-    TR_SETUP,
-    TR_DATA,
-    TR_STATUS,
-    TR_ISOCH,
-    TR_LINK,
-    TR_EVDATA,
-    TR_NOOP,
-    CR_ENABLE_SLOT,
-    CR_DISABLE_SLOT,
-    CR_ADDRESS_DEVICE,
-    CR_CONFIGURE_ENDPOINT,
-    CR_EVALUATE_CONTEXT,
-    CR_RESET_ENDPOINT,
-    CR_STOP_ENDPOINT,
-    CR_SET_TR_DEQUEUE,
-    CR_RESET_DEVICE,
-    CR_FORCE_EVENT,
-    CR_NEGOTIATE_BW,
-    CR_SET_LATENCY_TOLERANCE,
-    CR_GET_PORT_BANDWIDTH,
-    CR_FORCE_HEADER,
-    CR_NOOP,
-    ER_TRANSFER_COMPLETE = 32,
-    ER_COMMAND_COMPLETE,
-    ER_PORT_STATUS_CHANGE,
-    ER_BANDWIDTH_REQUEST,
-    ER_DOORBELL,
-    ER_HOST_CONTROLLER,
-    ER_DEVICE_NOTIFICATION,
-    ER_MFINDEX_WRAP,
-};
+/** 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 )
 
-enum TRBCCode {
-    CC_DISCONNECTED = -2,
-    CC_TIMEOUT = -1,
-    CC_INVALID = 0,
-    CC_SUCCESS,
-    CC_DATA_BUFFER_ERROR,
-    CC_BABBLE_DETECTED,
-    CC_USB_TRANSACTION_ERROR,
-    CC_TRB_ERROR,
-    CC_STALL_ERROR,
-    CC_RESOURCE_ERROR,
-    CC_BANDWIDTH_ERROR,
-    CC_NO_SLOTS_ERROR,
-    CC_INVALID_STREAM_TYPE_ERROR,
-    CC_SLOT_NOT_ENABLED_ERROR,
-    CC_EP_NOT_ENABLED_ERROR,
-    CC_SHORT_PACKET,
-    CC_RING_UNDERRUN,
-    CC_RING_OVERRUN,
-    CC_VF_ER_FULL,
-    CC_PARAMETER_ERROR,
-    CC_BANDWIDTH_OVERRUN,
-    CC_CONTEXT_STATE_ERROR,
-    CC_NO_PING_RESPONSE_ERROR,
-    CC_EVENT_RING_FULL_ERROR,
-    CC_INCOMPATIBLE_DEVICE_ERROR,
-    CC_MISSED_SERVICE_ERROR,
-    CC_COMMAND_RING_STOPPED,
-    CC_COMMAND_ABORTED,
-    CC_STOPPED,
-    CC_STOPPED_LENGTH_INVALID,
-    CC_MAX_EXIT_LATENCY_TOO_LARGE_ERROR = 29,
-    CC_ISOCH_BUFFER_OVERRUN = 31,
-    CC_EVENT_LOST_ERROR,
-    CC_UNDEFINED_ERROR,
-    CC_INVALID_STREAM_ID_ERROR,
-    CC_SECONDARY_BANDWIDTH_ERROR,
-    CC_SPLIT_TRANSACTION_ERROR
+/** 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 {
+	/** 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,
 };
 
-/***************** Macros (Inline Functions) Definitions *********************/
-/*
- *  xhci_ring structs are allocated with XHCI_RING_SIZE alignment,
- *  then we can get it from a trb pointer (provided by evt ring).
+/** USB command register */
+#define XHCI_OP_USBCMD 0x00
+
+/** Run/stop */
+#define XHCI_USBCMD_RUN 0x00000001UL
+
+/* Interrupter Enable (INTE) 1: enabled - RW */
+#define XHCI_USBCMD_INTE  (1UL << 2)
+
+/** Host controller reset */
+#define XHCI_USBCMD_HCRST 0x00000002UL
+
+/** USB status register */
+#define XHCI_OP_USBSTS 0x04
+
+/** Host controller halted */
+#define XHCI_USBSTS_HCH 0x00000001UL
+
+/** Interrupt Pending (IP) */
+#define XHCI_USBSTS_EINT (1UL << 3)
+
+/** 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
+
+#define XHCI_PORTSC_OCA (1 << 3)
+
+/** Port reset */
+#define XHCI_PORTSC_PR 0x00000010UL
+
+/** Port link state */
+#define XHCI_PORTSC_PLS(pls) ( (pls) << 5 )
+
+/** U0 state */
+#define XHCI_PORTSC_PLS_U0 XHCI_PORTSC_PLS ( 0 )
+
+/** 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 )
+
+/** Polling state */
+#define XHCI_PORTSC_PLS_POLLING XHCI_PORTSC_PLS ( 7 )
+
+/** 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 (1 << 17)
+
+/** Port enabled/disabled change */
+#define XHCI_PORTSC_PEC (1 << 18)
+
+/** Warm port reset change */
+#define XHCI_PORTSC_WRC (1 << 19) 
+
+/** Over-current change */
+#define XHCI_PORTSC_OCC (1 << 20)
+
+/** Port reset change */
+#define XHCI_PORTSC_PRC (1 << 21)
+
+/** Port link state change */
+#define XHCI_PORTSC_PLC (1 << 22)
+
+/** Port config error change */
+#define XHCI_PORTSC_CEC (1 << 23)
+
+/* Cold Attach Status  1: Far-end Receiver Terminations were detected */
+#define XHCI_PORTSC_CAS (1 << 24)       
+
+/* Wake on Connect Enable 1: enable port to be sensitive to device connects */
+#define XHCI_PORTSC_WCE (1 << 25)       
+
+/* Wake on Disconnect Enable 1: enable port to be sensitive to device disconnects */
+#define XHCI_PORTSC_WDE (1 << 26)       
+
+/* Wake on Over-current Enable 1: enable port to be sensitive to  over-current conditions */
+#define XHCI_PORTSC_WOE (1 << 27)       
+
+/* Device Removable, 0: Device is removable. 1:  Device is non-removable */
+#define XHCI_PORTSC_DR  (1 << 30)       
+
+/* Warm Port Reset 1: follow Warm Reset sequence */
+#define XHCI_PORTSC_WPR (1 << 31)   
+
+/** 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 )
+
+#define XHCI_PORTSC_RW_MASK (XHCI_PORTSC_PR | XHCI_PORTSC_PLS_MASK | XHCI_PORTSC_PP \
+							| XHCI_PORTSC_PIC_MASK | XHCI_PORTSC_LWS | XHCI_PORTSC_WCE \
+							| XHCI_PORTSC_WDE | XHCI_PORTSC_WOE)
+
+/** 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_RING(_trb)          \
-    ((struct xhci_ring*)((unsigned long)(_trb) & ~(XHCI_RING_SIZE-1)))
+#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 ) )
+
+/* Doorbell registers are 32 bits in length */
+#define XHCI_REG_DB_SIZE                4       
+
+/** Interrupter Management Register */
+#define XHCI_RUN_IR_IMAN(intr) ( 0x20 + ( (intr) << 5 ) )
+
+/* Interrupt Pending, 1: an interrupt is pending for this Interrupter */
+#define XHCI_RUN_IR_IMAN_IP              (1 << 0)
+
+/* Interrupt Enable, 1: capable of generating an interrupt. */
+#define XHCI_RUN_IR_IMAN_IE              (1 << 1)
+
+/** Interrupter Moderation Register */
+#define XHCI_RUN_IR_IMOD(intr) ( 0x24 + ( (intr) << 5 ) )
+
+/** 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 ) )
+
+/** Event Handler Busy */
+#define XHCI_RUN_ERDP_EHB	(1 << 3)
+
+/** 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
+
+/** Read/Write Data Barrier for ARM */
 #define BARRIER() __asm__ __volatile__("": : :"memory")
 
 #ifdef XHCI_AARCH64
@@ -475,55 +393,107 @@ enum TRBCCode {
 #define DSB() __asm__ __volatile__("dsb": : : "memory")
 #endif
 
-/************************** Function Prototypes ******************************/
-
-/*****************************************************************************/
-static inline void writeq(unsigned long addr, uint64_t val) {
+/**
+ * Read byte from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+static inline uint8_t readb(void *io_addr ) {
+    uint8_t val = *(volatile const uint8_t *)io_addr;
     BARRIER();
-    *(volatile uint64_t *)addr = val;
+    return val;
 }
 
-static inline void writel(unsigned long addr, uint32_t val) {
+/**
+ * Read 16-bit word from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+static inline uint16_t readw(void * io_addr ) {
+    uint16_t val = *(volatile const uint16_t *)io_addr;
     BARRIER();
-    *(volatile uint32_t *)addr = val;
+    return val;
 }
 
-static inline void writew(unsigned long addr, uint16_t val) {
+/**
+ * Read 32-bit dword from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+static inline uint32_t readl(void * io_addr ) {
+    uint32_t val = *(volatile const uint32_t *)io_addr;
     BARRIER();
-    *(volatile uint16_t *)addr = val;
+    return val;
 }
 
-static inline void writeb(unsigned long addr, uint8_t val) {
+/**
+ * Read 64-bit qword from memory-mapped device
+ *
+ * @v io_addr		I/O address
+ * @ret data		Value read
+ */
+static inline uint64_t readq(void * io_addr ) {
+    uint64_t val = *(volatile const uint64_t *)io_addr;
     BARRIER();
-    *(volatile uint8_t *)addr = val;
+    return val;
 }
 
-static inline uint64_t readq(unsigned long addr) {
-    uint64_t val = *(volatile const uint64_t *)addr;
+/**
+ * Write byte to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+static inline void writeb(uint8_t data, void * io_addr ) {
     BARRIER();
-    return val;
+    *(volatile uint8_t *)io_addr = data;
 }
 
-static inline uint32_t readl(unsigned long addr) {
-    uint32_t val = *(volatile const uint32_t *)addr;
+/**
+ * Write 16-bit word to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr	I/O address
+ */
+static inline void writew(uint16_t data, void * io_addr ) {
     BARRIER();
-    return val;
+    *(volatile uint16_t *)io_addr = data;
 }
 
-static inline uint16_t readw(unsigned long addr) {
-    uint16_t val = *(volatile const uint16_t *)addr;
+/**
+ * Write 32-bit dword to memory-mapped device
+ *
+ * @v data		Value to writed
+ * @v io_addr		I/O address
+ */
+static inline void writel(uint32_t data, void * io_addr ) {
     BARRIER();
-    return val;
+    *(volatile uint32_t *)io_addr = data;
 }
 
-static inline uint8_t readb(unsigned long addr) {
-    uint8_t val = *(volatile const uint8_t *)addr;
+/**
+ * Write 64-bit qword to memory-mapped device
+ *
+ * @v data		Value to write
+ * @v io_addr		I/O address
+ */
+static inline void writeq(uint64_t data, void * io_addr ) {
     BARRIER();
-    return val;
+    *(volatile uint64_t *)io_addr = data;
 }
 
-#ifdef __cplusplus
-}
-#endif
+/**
+ *  Byte-order converter for ARM-Little-End 
+ */
+#define CPU_TO_LE64(x) ((uint64_t)(x))
+#define LE64_to_CPU(x) ((uint64_t)(x))
+#define CPU_TO_LE32(x) ((uint32_t)(x))
+#define LE32_TO_CPU(x) ((uint32_t)(x))
+#define CPU_TO_LE16(x) ((uint16_t)(x))
+#define LE16_TO_CPU(x) ((uint16_t)(x))
+
 
-#endif
+#endif /* XHCI_REG_H */

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików