From 50ec3651c08073367406921e2ed7fa4ff4c1a567 Mon Sep 17 00:00:00 2001 From: sakumisu <1203593632@qq.com> Date: Wed, 10 Aug 2022 23:28:00 +0800 Subject: rename ehci file and dcache name --- port/ehci/usb_ehci.c | 2844 ----------------------------------------------- port/ehci/usb_ehci.h | 1008 ----------------- port/ehci/usb_hc_ehci.h | 1008 +++++++++++++++++ 3 files changed, 1008 insertions(+), 3852 deletions(-) delete mode 100644 port/ehci/usb_ehci.c delete mode 100644 port/ehci/usb_ehci.h create mode 100644 port/ehci/usb_hc_ehci.h diff --git a/port/ehci/usb_ehci.c b/port/ehci/usb_ehci.c deleted file mode 100644 index 85c3f620..00000000 --- a/port/ehci/usb_ehci.c +++ /dev/null @@ -1,2844 +0,0 @@ -#include "usbh_core.h" -#include "usb_ehci.h" - -#ifndef USBH_IRQHandler -#define USBH_IRQHandler USBH_IRQHandler -#endif - -#define DEBUGASSERT(f) - -/* Configurable number of Queue Head (QH) structures. The default is one per - * Root hub port plus one for EP0. - */ - -#ifndef CONFIG_USB_EHCI_QH_NUM -#define CONFIG_USB_EHCI_QH_NUM (CONFIG_USBHOST_RHPORTS + 1) -#endif - -/* Configurable number of Queue Element Transfer Descriptor (qTDs). The - * default is one per root hub plus three from EP0. - */ - -#ifndef CONFIG_USB_EHCI_QTD_NUM -#define CONFIG_USB_EHCI_QTD_NUM (CONFIG_USBHOST_RHPORTS + 3) -#endif - -/* Registers ****************************************************************/ - -/* Traditionally, NuttX specifies register locations using individual - * register offsets from a base address. That tradition is broken here and, - * instead, register blocks are represented as structures. This is done here - * because, in principle, EHCI operational register address may not be known - * at compile time; the operational registers lie at an offset specified in - * the 'caplength' byte of the Host Controller Capability Registers. - * - * However, for the case of the LPC43 EHCI, we know apriori that locations - * of these register blocks. - */ - -/* Host Controller Capability Registers */ - -#define HCCR ((struct ehci_hccr_s *)CONFIG_USB_EHCI_HCCR_BASE) - -/* Host Controller Operational Registers */ - -#define HCOR ((volatile struct ehci_hcor_s *)CONFIG_USB_EHCI_HCOR_BASE) - -/* Interrupts ***************************************************************/ - -/* This is the set of interrupts handled by this driver */ - -#define EHCI_HANDLED_INTS (EHCI_INT_USBINT | EHCI_INT_USBERRINT | \ - EHCI_INT_PORTSC | EHCI_INT_SYSERROR | \ - EHCI_INT_AAINT) - -/* The periodic frame list is a 4K-page aligned array of Frame List Link - * pointers. The length of the frame list may be programmable. The - * programmability of the periodic frame list is exported to system software - * via the HCCPARAMS register. If non-programmable, the length is 1024 - * elements. If programmable, the length can be selected by system software - * as one of 256, 512, or 1024 elements. - */ - -#define FRAME_LIST_SIZE 1024 - -/* DMA **********************************************************************/ - -/* For now, we are assuming an identity mapping between physical and virtual - * address spaces. - */ - -#define usb_ehci_physramaddr(a) (a) -#define usb_ehci_virtramaddr(a) (a) - -/**************************************************************************** - * Private Types - ****************************************************************************/ - -/* Internal representation of the EHCI Queue Head (QH) */ - -struct usb_ehci_epinfo_s; -struct usb_ehci_qh_s { - /* Fields visible to hardware */ - - struct ehci_qh_s hw; /* Hardware representation of the queue head */ - - /* Internal fields used by the EHCI driver */ - - struct usb_ehci_epinfo_s *epinfo; /* Endpoint used for the transfer */ - uint32_t fqp; /* First qTD in the list (physical address) */ -#if (CONFIG_USB_ALIGN_SIZE == 64) - uint8_t pad[4]; /* Padding to assure 64-byte alignment */ -#elif (CONFIG_USB_ALIGN_SIZE == 32) - uint8_t pad[8]; /* Padding to assure 32-byte alignment */ -#else -#error "ehci align size must be 32 or 64" -#endif -}; - -/* Internal representation of the EHCI Queue Element Transfer Descriptor - * (qTD) - */ - -struct usb_ehci_qtd_s { - /* Fields visible to hardware */ - - struct ehci_qtd_s hw; /* Hardware representation of the queue head */ - - /* Internal fields used by the EHCI driver */ -}; - -/* The following is used to manage lists of free QHs and qTDs */ - -struct usb_ehci_list_s { - struct usb_ehci_list_s *flink; /* Link to next entry in the list */ - /* Variable length entry data follows */ -}; - -/* List traversal callout functions */ - -typedef int (*foreach_qh_t)(struct usb_ehci_qh_s *qh, uint32_t **bp, void *arg); -typedef int (*foreach_qtd_t)(struct usb_ehci_qtd_s *qtd, uint32_t **bp, void *arg); - -/* This structure describes one endpoint. */ - -struct usb_ehci_epinfo_s { - uint8_t epno : 7; /* Endpoint number */ - uint8_t dirin : 1; /* 1:IN endpoint 0:OUT endpoint */ - uint8_t devaddr : 7; /* Device address */ - uint8_t toggle : 1; /* Next data toggle */ -#ifndef CONFIG_USBHOST_INT_DISABLE - uint8_t interval; /* Polling interval */ -#endif - bool inuse; - uint8_t status; /* Retained token status bits (for debug purposes) */ - uint16_t maxpacket : 11; /* Maximum packet size */ - uint16_t xfrtype : 2; /* See USB_EP_ATTR_XFER_* definitions in usb.h */ - uint16_t speed : 2; /* See USB_*_SPEED definitions in ehci.h */ - int result; /* The result of the transfer */ - uint32_t xfrd; /* On completion, will hold the number of bytes transferred */ - volatile bool iocwait; /* TRUE: Thread is waiting for transfer completion */ - usb_osal_sem_t iocsem; /* Semaphore used to wait for transfer completion */ - usb_osal_mutex_t exclsem; /* Support mutually exclusive access */ -#ifdef CONFIG_USBHOST_ASYNCH - usbh_asynch_callback_t callback; /* Transfer complete callback */ - void *arg; /* Argument that accompanies the callback */ -#endif - struct usbh_hubport *hport; - struct usb_ehci_qh_s *qh; -}; - -/* This structure retains the overall state of the USB host controller */ - -struct ehci_hcd { - struct usb_ehci_list_s *qhfree; /* List of free Queue Head (QH) structures */ - struct usb_ehci_list_s *qtdfree; /* List of free Queue Element Transfer Descriptor (qTD) */ - USB_MEM_ALIGNX struct usb_ehci_qh_s qhpool[CONFIG_USB_EHCI_QH_NUM]; /* Queue Head (QH) pool */ - USB_MEM_ALIGNX struct usb_ehci_qtd_s qtdpool[CONFIG_USB_EHCI_QTD_NUM]; /* Queue Element Transfer Descriptor (qTD) pool */ - struct usb_ehci_epinfo_s chan[CONFIG_USBHOST_PIPE_NUM]; -}; - -/**************************************************************************** - * Private Function Prototypes - ****************************************************************************/ - -/* Register operations ******************************************************/ - -static uint16_t usb_ehci_read16(const uint8_t *addr); -static uint32_t usb_ehci_read32(const uint8_t *addr); -#if 0 /* Not used */ -static void usb_ehci_write16(uint16_t memval, uint8_t *addr); -static void usb_ehci_write32(uint32_t memval, uint8_t *addr); -#endif - -#ifdef CONFIG_ENDIAN_BIG -static uint16_t usb_ehci_swap16(uint16_t value); -static uint32_t usb_ehci_swap32(uint32_t value); -#else -#define usb_ehci_swap16(value) (value) -#define usb_ehci_swap32(value) (value) -#endif - -#ifdef CONFIG_USB_DCACHE_ENABLE -void usb_ehci_dcache_clean(uintptr_t addr, uint32_t len); -void usb_ehci_dcache_invalidate(uintptr_t addr, uint32_t len); -void usb_ehci_dcache_clean_invalidate(uintptr_t addr, uint32_t len); -#else -#define usb_ehci_dcache_clean(addr, len) -#define usb_ehci_dcache_invalidate(addr, len) -#define usb_ehci_dcache_clean_invalidate(addr, len) -#endif - -/**************************************************************************** - * Private Data - ****************************************************************************/ - -/* In this driver implementation, support is provided for only a single - * USB device. All status information can be simply retained in a single - * global instance. - */ - -/* Maps USB chapter 9 speed to EHCI speed */ - -static const uint8_t g_ehci_speed[4] = { - 0, EHCI_LOW_SPEED, EHCI_FULL_SPEED, EHCI_HIGH_SPEED -}; - -/* In this driver implementation, support is provided for only a single - * USB device. All status information can be simply retained in a single - * global instance. - */ - -static struct ehci_hcd g_ehci_hcd; - -/* The head of the asynchronous queue */ - -static struct usb_ehci_qh_s g_asynchead __attribute__((aligned(32))); - -/* The head of the periodic queue */ - -static struct usb_ehci_qh_s g_intrhead __attribute__((aligned(32))); - -/* The frame list */ -static uint32_t g_framelist[FRAME_LIST_SIZE] __attribute__((aligned(4096))); -/**************************************************************************** - * Private Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: usb_ehci_read16 - * - * Description: - * Read 16-bit little endian data - * - ****************************************************************************/ - -static uint16_t usb_ehci_read16(const uint8_t *addr) -{ -#ifdef CONFIG_ENDIAN_BIG - return (uint16_t)addr[0] << 8 | (uint16_t)addr[1]; -#else - return (uint16_t)addr[1] << 8 | (uint16_t)addr[0]; -#endif -} - -/**************************************************************************** - * Name: usb_ehci_read32 - * - * Description: - * Read 32-bit little endian data - * - ****************************************************************************/ - -static inline uint32_t usb_ehci_read32(const uint8_t *addr) -{ -#ifdef CONFIG_ENDIAN_BIG - return (uint32_t)usb_ehci_read16(&addr[0]) << 16 | - (uint32_t)usb_ehci_read16(&addr[2]); -#else - return (uint32_t)usb_ehci_read16(&addr[2]) << 16 | - (uint32_t)usb_ehci_read16(&addr[0]); -#endif -} - -/**************************************************************************** - * Name: usb_ehci_swap16 - * - * Description: - * Swap bytes on a 16-bit value - * - ****************************************************************************/ - -#ifdef CONFIG_ENDIAN_BIG -static uint16_t usb_ehci_swap16(uint16_t value) -{ - return ((value >> 8) & 0xff) | ((value & 0xff) << 8); -} -#endif - -/**************************************************************************** - * Name: usb_ehci_swap32 - * - * Description: - * Swap bytes on a 32-bit value - * - ****************************************************************************/ - -#ifdef CONFIG_ENDIAN_BIG -static uint32_t usb_ehci_swap32(uint32_t value) -{ - return (uint32_t)usb_ehci_swap16((uint16_t)((value >> 16) & 0xffff)) | - (uint32_t)usb_ehci_swap16((uint16_t)(value & 0xffff)) << 16; -} -#endif - -static inline void usb_ehci_putreg(uint32_t regval, volatile uint32_t *regaddr) -{ - *regaddr = regval; -} - -static inline uint32_t usb_ehci_getreg(volatile uint32_t *regaddr) -{ - return *regaddr; -} - -static int usb_ehci_chan_alloc(void) -{ - int chidx; - - /* Search the table of channels */ - - for (chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) { - /* Is this channel available? */ - if (!g_ehci_hcd.chan[chidx].inuse) { - /* Yes... make it "in use" and return the index */ - - g_ehci_hcd.chan[chidx].inuse = true; - return chidx; - } - } - - /* All of the channels are "in-use" */ - - return -EBUSY; -} - -static void usb_ehci_chan_free(struct usb_ehci_epinfo_s *chan) -{ - /* Mark the channel available */ - chan->inuse = false; -} -/**************************************************************************** - * Name: usb_ehci_qh_alloc - * - * Description: - * Allocate a Queue Head (QH) structure by removing it from the free list - * - * Assumption: Caller holds the exclsem - * - ****************************************************************************/ - -static struct usb_ehci_qh_s *usb_ehci_qh_alloc(void) -{ - struct usb_ehci_qh_s *qh; - - /* Remove the QH structure from the freelist */ - - qh = (struct usb_ehci_qh_s *)g_ehci_hcd.qhfree; - if (qh) { - g_ehci_hcd.qhfree = ((struct usb_ehci_list_s *)qh)->flink; - memset(qh, 0, sizeof(struct usb_ehci_qh_s)); - } - - return qh; -} - -/**************************************************************************** - * Name: usb_ehci_qh_free - * - * Description: - * Free a Queue Head (QH) structure by returning it to the free list - * - * Assumption: Caller holds the exclsem - * - ****************************************************************************/ - -static void usb_ehci_qh_free(struct usb_ehci_qh_s *qh) -{ - struct usb_ehci_list_s *entry = (struct usb_ehci_list_s *)qh; - - /* Put the QH structure back into the free list */ - - entry->flink = g_ehci_hcd.qhfree; - g_ehci_hcd.qhfree = entry; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_alloc - * - * Description: - * Allocate a Queue Element Transfer Descriptor (qTD) by removing it from - * the free list - * - * Assumption: Caller holds the exclsem - * - ****************************************************************************/ - -static struct usb_ehci_qtd_s *usb_ehci_qtd_alloc(void) -{ - struct usb_ehci_qtd_s *qtd; - - /* Remove the qTD from the freelist */ - - qtd = (struct usb_ehci_qtd_s *)g_ehci_hcd.qtdfree; - if (qtd) { - g_ehci_hcd.qtdfree = ((struct usb_ehci_list_s *)qtd)->flink; - memset(qtd, 0, sizeof(struct usb_ehci_qtd_s)); - } - - return qtd; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_free - * - * Description: - * Free a Queue Element Transfer Descriptor (qTD) by returning it to the - * free list - * - * Assumption: Caller holds the exclsem - * - ****************************************************************************/ - -static void usb_ehci_qtd_free(struct usb_ehci_qtd_s *qtd) -{ - struct usb_ehci_list_s *entry = (struct usb_ehci_list_s *)qtd; - - /* Put the qTD back into the free list */ - - entry->flink = g_ehci_hcd.qtdfree; - g_ehci_hcd.qtdfree = entry; -} - -/**************************************************************************** - * Name: usb_ehci_qh_foreach - * - * Description: - * Give the first entry in a list of Queue Head (QH) structures, call the - * handler for each QH structure in the list (including the one at the head - * of the list). - * - ****************************************************************************/ - -static int usb_ehci_qh_foreach(struct usb_ehci_qh_s *qh, uint32_t **bp, - foreach_qh_t handler, void *arg) -{ - struct usb_ehci_qh_s *next; - uintptr_t physaddr; - int ret; - - DEBUGASSERT(qh && handler); - while (qh) { - /* Is this the end of the list? Check the horizontal link pointer - * (HLP) terminate (T) bit. If T==1, then the HLP address is not - * valid. - */ - - physaddr = usb_ehci_swap32(qh->hw.hlp); - - if ((physaddr & QH_HLP_T) != 0) { - /* Set the next pointer to NULL. This will terminate the loop. */ - - next = NULL; - } - - /* Is the next QH the asynchronous list head which will always be at - * the end of the asynchronous queue? - */ - - else if (usb_ehci_virtramaddr(physaddr & QH_HLP_MASK) == - (uintptr_t)&g_asynchead) { - /* That will also terminate the loop */ - - next = NULL; - } - - /* Otherwise, there is a QH structure after this one that describes - * another transaction. - */ - - else { - physaddr = usb_ehci_swap32(qh->hw.hlp) & QH_HLP_MASK; - next = (struct usb_ehci_qh_s *)usb_ehci_virtramaddr(physaddr); - } - - /* Perform the user action on this entry. The action might result in - * unlinking the entry! But that is okay because we already have the - * next QH pointer. - * - * Notice that we do not manage the back pointer (bp). If the callout - * uses it, it must update it as necessary. - */ - - ret = handler(qh, bp, arg); - - /* If the handler returns any non-zero value, then terminate the - * traversal early. - */ - - if (ret != 0) { - return ret; - } - - /* Set up to visit the next entry */ - - qh = next; - } - - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_foreach - * - * Description: - * Give a Queue Head (QH) instance, call the handler for each qTD structure - * in the queue. - * - ****************************************************************************/ - -static int usb_ehci_qtd_foreach(struct usb_ehci_qh_s *qh, foreach_qtd_t handler, - void *arg) -{ - struct usb_ehci_qtd_s *qtd; - struct usb_ehci_qtd_s *next; - uintptr_t physaddr; - uint32_t *bp; - int ret; - - DEBUGASSERT(qh && handler); - - /* Handle the special case where the queue is empty */ - - bp = &qh->fqp; /* Start of qTDs in original list */ - physaddr = usb_ehci_swap32(*bp); /* Physical address of first qTD in CPU order */ - - if ((physaddr & QTD_NQP_T) != 0) { - return 0; - } - - /* Start with the first qTD in the list */ - - qtd = (struct usb_ehci_qtd_s *)usb_ehci_virtramaddr(physaddr); - next = NULL; - - /* And loop until we encounter the end of the qTD list */ - - while (qtd) { - /* Is this the end of the list? Check the next qTD pointer (NQP) - * terminate (T) bit. If T==1, then the NQP address is not valid. - */ - - if ((usb_ehci_swap32(qtd->hw.nqp) & QTD_NQP_T) != 0) { - /* Set the next pointer to NULL. This will terminate the loop. */ - - next = NULL; - } else { - physaddr = usb_ehci_swap32(qtd->hw.nqp) & QTD_NQP_NTEP_MASK; - next = (struct usb_ehci_qtd_s *)usb_ehci_virtramaddr(physaddr); - } - - /* Perform the user action on this entry. The action might result in - * unlinking the entry! But that is okay because we already have the - * next qTD pointer. - * - * Notice that we do not manage the back pointer (bp). If the call- - * out uses it, it must update it as necessary. - */ - - ret = handler(qtd, &bp, arg); - - /* If the handler returns any non-zero value, then terminate the - * traversal early. - */ - - if (ret != 0) { - return ret; - } - - /* Set up to visit the next entry */ - - qtd = next; - } - - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_discard - * - * Description: - * This is a usb_ehci_qtd_foreach callback. It simply unlinks the QTD, - * updates the back pointer, and frees the QTD structure. - * - ****************************************************************************/ - -static int usb_ehci_qtd_discard(struct usb_ehci_qtd_s *qtd, uint32_t **bp, - void *arg) -{ - DEBUGASSERT(qtd && bp && *bp); - - /* Remove the qTD from the list by updating the forward pointer to skip - * around this qTD. We do not change that pointer because are repeatedly - * removing the aTD at the head of the QH list. - */ - - **bp = qtd->hw.nqp; - - /* Then free the qTD */ - - usb_ehci_qtd_free(qtd); - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qh_discard - * - * Description: - * Free the Queue Head (QH) and all qTD's attached to the QH. - * - * Assumptions: - * The QH structure itself has already been unlinked from whatever list it - * may have been in. - * - ****************************************************************************/ - -static int usb_ehci_qh_discard(struct usb_ehci_qh_s *qh) -{ - int ret; - - DEBUGASSERT(qh); - - /* Free all of the qTD's attached to the QH */ - - ret = usb_ehci_qtd_foreach(qh, usb_ehci_qtd_discard, NULL); - if (ret < 0) { - } - - /* Then free the QH itself */ - - usb_ehci_qh_free(qh); - return ret; -} -#ifdef CONFIG_USB_DCACHE_ENABLE -/**************************************************************************** - * Name: usb_ehci_qtd_flush - * - * Description: - * This is a callback from usb_ehci_qtd_foreach. It simply flushes D-cache - * for address range of the qTD entry. - * - ****************************************************************************/ - -static int usb_ehci_qtd_flush(struct usb_ehci_qtd_s *qtd, uint32_t **bp, void *arg) -{ - /* Flush the D-Cache, i.e., make the contents of the memory match the - * contents of the D-Cache in the specified address range and invalidate - * the D-Cache to force re-loading of the data from memory when next - * accessed. - */ - - usb_ehci_dcache_clean_invalidate((uintptr_t)&qtd->hw, sizeof(struct usb_ehci_qtd_s)); - - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qh_flush - * - * Description: - * Invalidate the Queue Head and all qTD entries in the queue. - * - ****************************************************************************/ - -static int usb_ehci_qh_flush(struct usb_ehci_qh_s *qh) -{ - /* Flush the QH first. This will write the contents of the D-cache to RAM - * and invalidate the contents of the D-cache so that the next access will - * be reloaded from D-Cache. - */ - - usb_ehci_dcache_clean_invalidate((uintptr_t)&qh->hw, sizeof(struct usb_ehci_qh_s)); - - /* Then flush all of the qTD entries in the queue */ - - return usb_ehci_qtd_foreach(qh, usb_ehci_qtd_flush, NULL); -} -#else -#define usb_ehci_qtd_flush(qtd, bp, arg) -#define usb_ehci_qtd_flush(qh) -#endif -/**************************************************************************** - * Name: usb_ehci_speed - * - * Description: - * Map a speed enumeration value per Chapter 9 of the USB specification to - * the speed enumeration required in the EHCI queue head. - * - ****************************************************************************/ - -static inline uint8_t usb_ehci_speed(uint8_t usbspeed) -{ - DEBUGASSERT(usbspeed >= USB_SPEED_LOW && usbspeed <= USB_SPEED_HIGH); - return g_ehci_speed[usbspeed]; -} - -static struct usb_ehci_qh_s *usb_ehci_qh_create(struct usb_ehci_epinfo_s *epinfo) -{ - struct usb_ehci_qh_s *qh; - uint32_t regval; - uint8_t hubaddr; - uint8_t hubport; - struct usb_ehci_epinfo_s *ep0info; - struct usbh_hubport *rhport; - - rhport = epinfo->hport; - - while (rhport->parent != NULL) { - rhport = rhport->parent->parent; - } - ep0info = (struct usb_ehci_epinfo_s *)rhport->ep0; - /* Allocate a new queue head structure */ - - qh = usb_ehci_qh_alloc(); - if (qh == NULL) { - return NULL; - } - - /* Save the endpoint information with the QH itself */ - - qh->epinfo = epinfo; - - /* Write QH endpoint characteristics: - * - * FIELD DESCRIPTION VALUE/SOURCE - * -------- ------------------------------- -------------------- - * DEVADDR Device address Endpoint structure - * I Inactivate on Next Transaction 0 - * ENDPT Endpoint number Endpoint structure - * EPS Endpoint speed Endpoint structure - * DTC Data toggle control 1 - * MAXPKT Max packet size Endpoint structure - * C Control endpoint Calculated - * RL NAK count reloaded 0 - */ - - regval = ((uint32_t)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | - ((uint32_t)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | - ((uint32_t)usb_ehci_speed(epinfo->speed) << QH_EPCHAR_EPS_SHIFT) | - QH_EPCHAR_DTC | - ((uint32_t)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | - ((uint32_t)0 << QH_EPCHAR_RL_SHIFT); - - /* Paragraph 3.6.3: "Control Endpoint Flag (C). If the QH.EPS field - * indicates the endpoint is not a high-speed device, and the endpoint - * is an control endpoint, then software must set this bit to a one. - * Otherwise it should always set this bit to a zero." - */ - - if (epinfo->speed != USB_SPEED_HIGH && - epinfo->xfrtype == USB_ENDPOINT_TYPE_CONTROL) { - regval |= QH_EPCHAR_C; - } - - /* Save the endpoint characteristics word with the correct byte order */ - - qh->hw.epchar = usb_ehci_swap32(regval); - - /* Write QH endpoint capabilities - * - * FIELD DESCRIPTION VALUE/SOURCE - * -------- ------------------------------- -------------------- - * SSMASK Interrupt Schedule Mask Depends on epinfo->xfrtype - * SCMASK Split Completion Mask 0 - * HUBADDR Hub Address roothub port devaddr - * PORT Port number RH port index - * MULT High band width multiplier 1 - */ - - hubaddr = ep0info->devaddr; - hubport = rhport->port; - - regval = ((uint32_t)hubaddr << QH_EPCAPS_HUBADDR_SHIFT) | - ((uint32_t)hubport << QH_EPCAPS_PORT_SHIFT) | - ((uint32_t)1 << QH_EPCAPS_MULT_SHIFT); - -#ifndef CONFIG_USBHOST_INT_DISABLE - if (epinfo->xfrtype == USB_ENDPOINT_TYPE_INTERRUPT) { - regval |= ((uint32_t)1 << QH_EPCAPS_SSMASK_SHIFT); - } -#endif - - qh->hw.epcaps = usb_ehci_swap32(regval); - - /* Mark this as the end of this list. This will be overwritten if/when the - * next qTD is added to the queue. - */ - - qh->hw.hlp = usb_ehci_swap32(QH_HLP_T); - qh->hw.overlay.nqp = usb_ehci_swap32(QH_NQP_T); - qh->hw.overlay.alt = usb_ehci_swap32(QH_AQP_T); - return qh; -} - -static int usb_ehci_qtd_addbpl(struct usb_ehci_qtd_s *qtd, const void *buffer, size_t buflen) -{ - uint32_t physaddr; - uint32_t nbytes; - uint32_t next; - int ndx; - - usb_ehci_dcache_clean_invalidate((uintptr_t)buffer, buflen); - /* Loop, adding the aligned physical addresses of the buffer to the buffer - * page list. Only the first entry need not be aligned (because only the - * first entry has the offset field). The subsequent entries must begin on - * 4KB address boundaries. - */ - - physaddr = (uint32_t)usb_ehci_physramaddr((uintptr_t)buffer); - - for (ndx = 0; ndx < 5; ndx++) { - /* Write the physical address of the buffer into the qTD buffer - * pointer list. - */ - - qtd->hw.bpl[ndx] = usb_ehci_swap32(physaddr); - - /* Get the next buffer pointer (in the case where we will have to - * transfer more then one chunk). This buffer must be aligned to a - * 4KB address boundary. - */ - - next = (physaddr + 4096) & ~4095; - - /* How many bytes were included in the last buffer? Was it the whole - * thing? - */ - - nbytes = next - physaddr; - if (nbytes >= buflen) { - /* Yes... it was the whole thing. Break out of the loop early. */ - - break; - } - - /* Adjust the buffer length and physical address for the next time - * through the loop. - */ - - buflen -= nbytes; - physaddr = next; - } - - /* Handle the case of a huge buffer > 4*4KB = 16KB */ - - if (ndx >= 5) { - return -EFBIG; - } - - return 0; -} - -static struct usb_ehci_qtd_s *usb_ehci_qtd_setupphase(struct usb_ehci_epinfo_s *epinfo, struct usb_setup_packet *setup) -{ - struct usb_ehci_qtd_s *qtd; - uint32_t regval; - int ret; - - /* Allocate a new Queue Element Transfer Descriptor (qTD) */ - - qtd = usb_ehci_qtd_alloc(); - if (qtd == NULL) { - return NULL; - } - - /* Mark this as the end of the list (this will be overwritten if another - * qTD is added after this one). - */ - - qtd->hw.nqp = usb_ehci_swap32(QTD_NQP_T); - qtd->hw.alt = usb_ehci_swap32(QTD_AQP_T); - - /* Write qTD token: - * - * FIELD DESCRIPTION VALUE/SOURCE - * -------- ------------------------------- -------------------- - * STATUS Status QTD_TOKEN_ACTIVE - * PID PID Code QTD_TOKEN_PID_SETUP - * CERR Error Counter 3 - * CPAGE Current Page 0 - * IOC Interrupt on complete 0 - * NBYTES Total Bytes to Transfer 8 - * TOGGLE Data Toggle 0 - */ - - regval = QTD_TOKEN_ACTIVE | QTD_TOKEN_PID_SETUP | - ((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) | - ((uint32_t)8 << QTD_TOKEN_NBYTES_SHIFT); - - qtd->hw.token = usb_ehci_swap32(regval); - - /* Add the buffer data */ - ret = usb_ehci_qtd_addbpl(qtd, (uint8_t *)setup, 8); - if (ret < 0) { - usb_ehci_qtd_free(qtd); - return NULL; - } - - /* Add the data transfer size to the count in the epinfo structure */ - epinfo->xfrd += 8; - - return qtd; -} - -static struct usb_ehci_qtd_s *usb_ehci_qtd_dataphase(struct usb_ehci_epinfo_s *epinfo, void *buffer, int buflen, uint32_t tokenbits) -{ - struct usb_ehci_qtd_s *qtd; - uint32_t regval; - int ret; - - /* Allocate a new Queue Element Transfer Descriptor (qTD) */ - - qtd = usb_ehci_qtd_alloc(); - if (qtd == NULL) { - return NULL; - } - - /* Mark this as the end of the list (this will be overwritten if another - * qTD is added after this one). - */ - - qtd->hw.nqp = usb_ehci_swap32(QTD_NQP_T); - qtd->hw.alt = usb_ehci_swap32(QTD_AQP_T); - - /* Write qTD token: - * - * FIELD DESCRIPTION VALUE/SOURCE - * -------- ------------------------------- -------------------- - * STATUS Status QTD_TOKEN_ACTIVE - * PID PID Code Contained in tokenbits - * CERR Error Counter 3 - * CPAGE Current Page 0 - * IOC Interrupt on complete Contained in tokenbits - * NBYTES Total Bytes to Transfer buflen - * TOGGLE Data Toggle Contained in tokenbits - */ - - regval = tokenbits | QTD_TOKEN_ACTIVE | - ((uint32_t)3 << QTD_TOKEN_CERR_SHIFT) | - ((uint32_t)buflen << QTD_TOKEN_NBYTES_SHIFT); - - qtd->hw.token = usb_ehci_swap32(regval); - - ret = usb_ehci_qtd_addbpl(qtd, buffer, buflen); - if (ret < 0) { - usb_ehci_qtd_free(qtd); - return NULL; - } - - /* Add the data transfer size to the count in the epinfo structure */ - epinfo->xfrd += buflen; - - return qtd; -} - -static struct usb_ehci_qtd_s *usb_ehci_qtd_statusphase(uint32_t tokenbits) -{ - struct usb_ehci_qtd_s *qtd; - uint32_t regval; - - /* Allocate a new Queue Element Transfer Descriptor (qTD) */ - - qtd = usb_ehci_qtd_alloc(); - if (qtd == NULL) { - return NULL; - } - - /* Mark this as the end of the list (this will be overwritten if another - * qTD is added after this one). - */ - - qtd->hw.nqp = usb_ehci_swap32(QTD_NQP_T); - qtd->hw.alt = usb_ehci_swap32(QTD_AQP_T); - - /* Write qTD token: - * - * FIELD DESCRIPTION VALUE/SOURCE - * -------- ------------------------------- -------------------- - * STATUS Status QTD_TOKEN_ACTIVE - * PID PID Code Contained in tokenbits - * CERR Error Counter 3 - * CPAGE Current Page 0 - * IOC Interrupt on complete QTD_TOKEN_IOC - * NBYTES Total Bytes to Transfer 0 - * TOGGLE Data Toggle Contained in tokenbits - */ - - regval = tokenbits | QTD_TOKEN_ACTIVE | QTD_TOKEN_IOC | - ((uint32_t)3 << QTD_TOKEN_CERR_SHIFT); - - qtd->hw.token = usb_ehci_swap32(regval); - - return qtd; -} - -static void usb_ehci_qh_enqueue(struct usb_ehci_qh_s *qhead, struct usb_ehci_qh_s *qh) -{ - uintptr_t physaddr; - - /* Set the internal fqp field. When we transverse the QH list later, - * we need to know the correct place to start because the overlay may no - * longer point to the first qTD entry. - */ - - qh->fqp = qh->hw.overlay.nqp; - - /* Add the new QH to the head of the asynchronous queue list. - * - * First, attach the old head as the new QH HLP and flush the new QH and - * its attached qTDs to RAM. - */ - - qh->hw.hlp = qhead->hw.hlp; - usb_ehci_qh_flush(qh); - /* Then set the new QH as the first QH in the asynchronous queue */ - - physaddr = (uintptr_t)usb_ehci_physramaddr((uintptr_t)qh); - qhead->hw.hlp = usb_ehci_swap32(physaddr | QH_HLP_TYP_QH); - usb_ehci_dcache_clean((uintptr_t)&qhead->hw, sizeof(struct usb_ehci_qh_s)); -} - -static int usb_ehci_control_init(struct usb_ehci_epinfo_s *epinfo, struct usb_setup_packet *setup, uint8_t *buffer, uint32_t buflen) -{ - struct usb_ehci_qh_s *qh; - struct usb_ehci_qtd_s *qtd; - uint32_t tokenbits; - uintptr_t physaddr; - uint32_t *flink; - uint32_t *alt; - uint32_t toggle; - bool dirin = false; - - /* Create and initialize a Queue Head (QH) structure for this transfer */ - qh = usb_ehci_qh_create(epinfo); - if (qh == NULL) { - return -ENOMEM; - } - - epinfo->qh = qh; - /* Initialize the QH link and get the next data toggle (not used for SETUP - * transfers) - */ - - flink = &qh->hw.overlay.nqp; - toggle = (uint32_t)epinfo->toggle << QTD_TOKEN_TOGGLE_SHIFT; - - /* Is there an EP0 SETUP request? If so, we will queue two or three qTDs: - * - * 1) One for the SETUP phase, - * 2) One for the DATA phase (if there is data), and - * 3) One for the STATUS phase. - */ - - /* Allocate a new Queue Element Transfer Descriptor (qTD) for the SETUP - * phase of the request sequence. - */ - { - qtd = usb_ehci_qtd_setupphase(epinfo, setup); - if (qtd == NULL) { - return -ENOMEM; - } - /* Link the new qTD to the QH head. */ - - physaddr = usb_ehci_physramaddr((uintptr_t)qtd); - *flink = usb_ehci_swap32(physaddr); - - /* Get the new forward link pointer and data toggle */ - - flink = &qtd->hw.nqp; - toggle = QTD_TOKEN_TOGGLE; - } - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer - * will always be present for normal endpoint data transfers. - */ - - alt = NULL; - - if (buffer != NULL && buflen > 0) { - /* Extra TOKEN bits include the data toggle, the data PID, and if - * there is no request, an indication to interrupt at the end of this - * transfer. - */ - - tokenbits = toggle; - - /* Get the data token direction. - * - * If this is a SETUP request, use the direction contained in the - * request. The IOC bit is not set. - */ - if ((setup->bmRequestType & 0x80) == 0x80) { - tokenbits |= QTD_TOKEN_PID_IN; - dirin = true; - } else { - tokenbits |= QTD_TOKEN_PID_OUT; - dirin = false; - } - - /* Allocate a new Queue Element Transfer Descriptor (qTD) for the data - * buffer. - */ - - qtd = usb_ehci_qtd_dataphase(epinfo, buffer, buflen, tokenbits); - if (qtd == NULL) { - return -ENOMEM; - } - - /* Link the new qTD to either QH head of the SETUP qTD. */ - physaddr = usb_ehci_physramaddr((uintptr_t)qtd); - *flink = usb_ehci_swap32(physaddr); - - /* Set the forward link pointer to this new qTD */ - - flink = &qtd->hw.nqp; - - /* If this was an IN transfer, then setup a pointer alternate link. - * The EHCI hardware will use this link if a short packet is received. - */ - - if (dirin) { - alt = &qtd->hw.alt; - } - } - - { - /* Extra TOKEN bits include the data toggle and the correct data PID. */ - - tokenbits = toggle; - - /* The status phase direction is the opposite of the data phase. If - * this is an IN request, then we received the buffer and we will send - * the zero length packet handshake. - */ - if ((setup->bmRequestType & 0x80) == 0x80) { - tokenbits |= QTD_TOKEN_PID_OUT; - } else { - /* Otherwise, this in an OUT request. We send the buffer and we expect - * to receive the NULL packet handshake. - */ - tokenbits |= QTD_TOKEN_PID_IN; - } - - /* Allocate a new Queue Element Transfer Descriptor (qTD) for the - * status - */ - qtd = usb_ehci_qtd_statusphase(tokenbits); - if (qtd == NULL) { - return -ENOMEM; - } - - /* Link the new qTD to either the SETUP or data qTD. */ - physaddr = usb_ehci_physramaddr((uintptr_t)qtd); - *flink = usb_ehci_swap32(physaddr); - - /* In an IN data qTD was also enqueued, then linked the data qTD's - * alternate pointer to this STATUS phase qTD in order to handle short - * transfers. - */ - - if (alt) { - *alt = usb_ehci_swap32(physaddr); - } - } - /* Add the new QH to the head of the asynchronous queue list */ - usb_ehci_qh_enqueue(&g_asynchead, qh); - return 0; -} - -static int usb_ehci_bulk_init(struct usb_ehci_epinfo_s *epinfo, uint8_t *buffer, uint32_t buflen) -{ - struct usb_ehci_qh_s *qh; - struct usb_ehci_qtd_s *qtd; - uint32_t tokenbits; - uintptr_t physaddr; - - /* Create and initialize a Queue Head (QH) structure for this transfer */ - qh = usb_ehci_qh_create(epinfo); - if (qh == NULL) { - return -ENOMEM; - } - - epinfo->qh = qh; - - /* Initialize the QH link and get the next data toggle */ - tokenbits = (uint32_t)epinfo->toggle << QTD_TOKEN_TOGGLE_SHIFT; - - if (buffer != NULL && buflen > 0) { - /* Get the direction from the epinfo structure. Since this is not an EP0 SETUP request, - * nothing follows the data and we want the IOC interrupt when the data transfer completes. - */ - if (epinfo->dirin) { - tokenbits |= (QTD_TOKEN_PID_IN | QTD_TOKEN_IOC); - } else { - tokenbits |= (QTD_TOKEN_PID_OUT | QTD_TOKEN_IOC); - } - - /* Allocate a new Queue Element Transfer Descriptor (qTD) for the data - * buffer. - */ - - qtd = usb_ehci_qtd_dataphase(epinfo, buffer, buflen, tokenbits); - if (qtd == NULL) { - return -ENOMEM; - } - - /* Link the new qTD to the QH. */ - physaddr = usb_ehci_physramaddr((uintptr_t)qtd); - qh->hw.overlay.nqp = usb_ehci_swap32(physaddr); - } - - /* Add the new QH to the head of the asynchronous queue list */ - usb_ehci_qh_enqueue(&g_asynchead, qh); - return 0; -} - -static int usb_ehci_intr_init(struct usb_ehci_epinfo_s *epinfo, uint8_t *buffer, uint32_t buflen) -{ - struct usb_ehci_qh_s *qh; - struct usb_ehci_qtd_s *qtd; - uint32_t tokenbits; - uintptr_t physaddr; - uint32_t regval; - - /* Create and initialize a Queue Head (QH) structure for this transfer */ - qh = usb_ehci_qh_create(epinfo); - if (qh == NULL) { - return -ENOMEM; - } - - epinfo->qh = qh; - - /* Initialize the QH link and get the next data toggle */ - tokenbits = (uint32_t)epinfo->toggle << QTD_TOKEN_TOGGLE_SHIFT; - - /* Get the direction from the epinfo structure. Since this is not an EP0 SETUP request, - * nothing follows the data and we want the IOC interrupt when the data transfer completes. - */ - if (epinfo->dirin) { - tokenbits |= (QTD_TOKEN_PID_IN | QTD_TOKEN_IOC); - } else { - tokenbits |= (QTD_TOKEN_PID_OUT | QTD_TOKEN_IOC); - } - - /* Allocate a new Queue Element Transfer Descriptor (qTD) for the data - * buffer. - */ - - qtd = usb_ehci_qtd_dataphase(epinfo, buffer, buflen, tokenbits); - if (qtd == NULL) { - return -ENOMEM; - } - - /* Link the new qTD to the QH. */ - physaddr = usb_ehci_physramaddr((uintptr_t)qtd); - qh->hw.overlay.nqp = usb_ehci_swap32(physaddr); - - /* Disable the periodic schedule */ - regval = usb_ehci_getreg(&HCOR->usbcmd); - regval &= ~EHCI_USBCMD_PSEN; - usb_ehci_putreg(regval, &HCOR->usbcmd); - - /* Add the new QH to the head of the interrupt transfer list */ - usb_ehci_qh_enqueue(&g_intrhead, qh); - - /* Re-enable the periodic schedule */ - regval |= EHCI_USBCMD_PSEN; - usb_ehci_putreg(regval, &HCOR->usbcmd); - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_ioc_setup - * - * Description: - * Set the request for the IOC event well BEFORE enabling the transfer (as - * soon as we are absolutely committed to the to avoid transfer). We do - * this to minimize race conditions. This logic would have to be expanded - * if we want to have more than one packet in flight at a time! - * - * Assumption: The caller holds tex EHCI exclsem - * - ****************************************************************************/ - -static int usb_ehci_ioc_setup(struct usb_ehci_epinfo_s *epinfo) -{ - uint32_t flags; - int ret = -ENODEV; - - DEBUGASSERT(rhport && epinfo && !epinfo->iocwait); -#ifdef CONFIG_USBHOST_ASYNCH - DEBUGASSERT(epinfo->callback == NULL); -#endif - - /* Is the device still connected? */ - - flags = usb_osal_enter_critical_section(); - if (epinfo->hport->connected) { - /* Then set iocwait to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer - * completed. - */ - - epinfo->iocwait = true; /* We want to be awakened by IOC interrupt */ - epinfo->status = 0; /* No status yet */ - epinfo->xfrd = 0; /* Nothing transferred yet */ - epinfo->result = -EBUSY; /* Transfer in progress */ -#ifdef CONFIG_USBHOST_ASYNCH - epinfo->callback = NULL; /* No asynchronous callback */ - epinfo->arg = NULL; -#endif - ret = 0; /* We are good to go */ - } - usb_osal_leave_critical_section(flags); - return ret; -} - -/**************************************************************************** - * Name: usb_ehci_ioc_async_setup - * - * Description: - * Setup to receive an asynchronous notification when a transfer completes. - * - * Input Parameters: - * epinfo - The IN or OUT endpoint descriptor for the device endpoint on - * which the transfer will be performed. - * callback - The function to be called when the completes - * arg - An arbitrary argument that will be provided with the callback. - * - * Returned Value: - * None - * - * Assumptions: - * - Called from the interrupt level - * - ****************************************************************************/ - -#ifdef CONFIG_USBHOST_ASYNCH -static int usb_ehci_ioc_async_setup(struct usb_ehci_epinfo_s *epinfo, usbh_asynch_callback_t callback, void *arg) -{ - uint32_t flags; - int ret = -ENODEV; - - DEBUGASSERT(rhport && epinfo && !epinfo->iocwait); -#ifdef CONFIG_USBHOST_ASYNCH - DEBUGASSERT(epinfo->callback == NULL); -#endif - - /* Is the device still connected? */ - - flags = usb_osal_enter_critical_section(); - if (epinfo->hport->connected) { - /* Then set iocwait to indicate that we expect to be informed when - * either (1) the device is disconnected, or (2) the transfer - * completed. - */ - - epinfo->iocwait = false; /* We want to be awakened by IOC interrupt */ - epinfo->status = 0; /* No status yet */ - epinfo->xfrd = 0; /* Nothing transferred yet */ - epinfo->result = -EBUSY; /* Transfer in progress */ -#ifdef CONFIG_USBHOST_ASYNCH - epinfo->callback = callback; /* No asynchronous callback */ - epinfo->arg = arg; -#endif - ret = 0; /* We are good to go */ - } - - usb_osal_leave_critical_section(flags); - return ret; -} -#endif - -/**************************************************************************** - * Name: usb_ehci_asynch_completion - * - * Description: - * This function is called at the interrupt level when an asynchronous - * transfer completes. It performs the pending callback. - * - * Input Parameters: - * epinfo - The IN or OUT endpoint descriptor for the device endpoint on - * which the transfer was performed. - * - * Returned Value: - * None - * - * Assumptions: - * - Called from the interrupt level - * - ****************************************************************************/ - -#ifdef CONFIG_USBHOST_ASYNCH -static void usb_ehci_asynch_completion(struct usb_ehci_epinfo_s *epinfo) -{ - usbh_asynch_callback_t callback; - int nbytes; - void *arg; - int result; - - DEBUGASSERT(epinfo != NULL && epinfo->iocwait == false && - epinfo->callback != NULL); - - /* Extract and reset the callback info */ - - callback = epinfo->callback; - arg = epinfo->arg; - result = epinfo->result; - nbytes = epinfo->xfrd; - - epinfo->callback = NULL; - epinfo->arg = NULL; - epinfo->result = 0; - epinfo->iocwait = false; - - /* Then perform the callback. Provide the number of bytes successfully - * transferred or the negated errno value in the event of a failure. - */ - - if (result < 0) { - nbytes = (int)result; - } - - callback(arg, nbytes); -} -#endif - -/**************************************************************************** - * Name: usb_ehci_transfer_wait - * - * Description: - * Wait for an IN or OUT transfer to complete. - * - * Assumption: The caller holds the EHCI exclsem. The caller must be aware - * that the EHCI exclsem will released while waiting for the transfer to - * complete, but will be re-acquired when before returning. The state of - * EHCI resources could be very different upon return. - * - * Returned Value: - * On success, this function returns the number of bytes actually - * transferred. For control transfers, this size includes the size of the - * control request plus the size of the data (which could be short); for - * bulk transfers, this will be the number of data bytes transfers (which - * could be short). - * - ****************************************************************************/ - -static int usb_ehci_transfer_wait(struct usb_ehci_epinfo_s *epinfo, uint32_t timeout) -{ - int ret = 0; - - /* Wait for the IOC completion event */ - if (epinfo->iocwait) { - ret = usb_osal_sem_take(epinfo->iocsem, timeout); - if (ret < 0) { - return ret; - } - } - - ret = epinfo->result; - - if (ret < 0) { - return ret; - } - - /* Transfer completed successfully. Return the number of bytes transferred.*/ - return epinfo->xfrd; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_ioccheck - * - * Description: - * This function is a usb_ehci_qtd_foreach() callback function. It services - * one qTD in the asynchronous queue. It removes all of the qTD - * structures that are no longer active. - * - ****************************************************************************/ - -static int usb_ehci_qtd_ioccheck(struct usb_ehci_qtd_s *qtd, uint32_t **bp, - void *arg) -{ - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)arg; - DEBUGASSERT(qtd && epinfo); - - usb_ehci_dcache_invalidate((uintptr_t)&qtd->hw, sizeof(struct usb_ehci_qtd_s)); - - /* Remove the qTD from the list - * - * NOTE that we don't check if the qTD is active nor do we check if there - * are any errors reported in the qTD. If the transfer halted due to - * an error, then qTDs in the list after the error qTD will still appear - * to be active. - */ - - **bp = qtd->hw.nqp; - - /* Subtract the number of bytes left untransferred. The epinfo->xfrd - * field is initialized to the total number of bytes to be transferred - * (all qTDs in the list). We subtract out the number of untransferred - * bytes on each transfer and the final result will be the number of bytes - * actually transferred. - */ - - epinfo->xfrd -= (usb_ehci_swap32(qtd->hw.token) & QTD_TOKEN_NBYTES_MASK) >> - QTD_TOKEN_NBYTES_SHIFT; - - /* Release this QH by returning it to the free list */ - - usb_ehci_qtd_free(qtd); - - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qh_ioccheck - * - * Description: - * This function is a usb_ehci_qh_foreach() callback function. It services - * one QH in the asynchronous queue. It check all attached qTD structures - * and remove all of the structures that are no longer active. if all of - * the qTD structures are removed, then QH itself will also be removed. - * - ****************************************************************************/ - -static int usb_ehci_qh_ioccheck(struct usb_ehci_qh_s *qh, uint32_t **bp, void *arg) -{ - struct usb_ehci_epinfo_s *epinfo; - uint32_t token; - int ret; - - DEBUGASSERT(qh && bp); - - usb_ehci_dcache_invalidate((uintptr_t)&qh->hw, sizeof(struct ehci_qh_s)); - - /* Get the endpoint info pointer from the extended QH data. Only the - * g_asynchead QH can have a NULL epinfo field. - */ - - epinfo = qh->epinfo; - DEBUGASSERT(epinfo); - - /* Paragraph 3.6.3: "The nine DWords in [the Transfer Overlay] area - * represent a transaction working space for the host controller. The - * general operational model is that the host controller can detect - * whether the overlay area contains a description of an active transfer. - * If it does not contain an active transfer, then it follows the Queue - * Head Horizontal Link Pointer to the next queue head. The host - * controller will never follow the Next Transfer Queue Element or - * Alternate Queue Element pointers unless it is actively attempting to - * advance the queue ..." - */ - - /* Is the qTD still active? */ - - token = usb_ehci_swap32(qh->hw.overlay.token); - - if ((token & QH_TOKEN_ACTIVE) != 0) { - /* Yes... we cannot process the QH while it is still active. Return - * zero to visit the next QH in the list. - */ - *bp = &qh->hw.hlp; - return 0; - } - - /* Remove all active, attached qTD structures from the inactive QH */ - ret = usb_ehci_qtd_foreach(qh, usb_ehci_qtd_ioccheck, (void *)qh->epinfo); - if (ret < 0) { - } - /* If there is no longer anything attached to the QH, then remove it from - * the asynchronous queue. - */ - - if ((usb_ehci_swap32(qh->fqp) & QTD_NQP_T) != 0) { - /* Set the forward link of the previous QH to point to the next - * QH in the list. - */ - - **bp = qh->hw.hlp; - usb_ehci_dcache_clean((uintptr_t)*bp, sizeof(uint32_t)); - /* Check for errors, update the data toggle */ - - if ((token & QH_TOKEN_ERRORS) == 0) { - /* No errors.. Save the last data toggle value */ - - epinfo->toggle = (token >> QTD_TOKEN_TOGGLE_SHIFT) & 1; - - /* Report success */ - - epinfo->status = 0; - epinfo->result = 0; - - } else { - /* An error occurred */ - - epinfo->status = (token & QH_TOKEN_STATUS_MASK) >> - QH_TOKEN_STATUS_SHIFT; - - /* The HALT condition is set on a variety of conditions: babble, - * error counter countdown to zero, or a STALL. If we can rule - * out babble (babble bit not set) and if the error counter is - * non-zero, then we can assume a STALL. In this case, we return - * -PERM to inform the class driver of the stall condition. - */ - - if ((token & (QH_TOKEN_BABBLE | QH_TOKEN_HALTED)) == - QH_TOKEN_HALTED && - (token & QH_TOKEN_CERR_MASK) != 0) { - /* It is a stall, Note that the data toggle is reset - * after the stall. - */ - - epinfo->result = -EPERM; - epinfo->toggle = 0; - } else { - /* Otherwise, it is some kind of data transfer error */ - - epinfo->result = -EIO; - } - } - - /* Is there a thread waiting for this transfer to complete? */ - if (epinfo->iocwait) { - /* Yes... wake it up */ - epinfo->iocwait = false; - usb_osal_sem_give(epinfo->iocsem); - } -#ifdef CONFIG_USBHOST_ASYNCH - /* No.. Is there a pending asynchronous transfer? */ - - else if (epinfo->callback != NULL) { - /* Yes.. perform the callback */ - - usb_ehci_asynch_completion(epinfo); - } -#endif - /* Then release this QH by returning it to the free list */ - usb_ehci_qh_free(qh); - } else { - /* Otherwise, the horizontal link pointer of this QH will become the - * next back pointer. - */ - - *bp = &qh->hw.hlp; - } - - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qtd_cancel - * - * Description: - * This function is a usb_ehci_qtd_foreach() callback function. It removes - * each qTD attached to a QH. - * - ****************************************************************************/ -static int usb_ehci_qtd_cancel(struct usb_ehci_qtd_s *qtd, uint32_t **bp, - void *arg) -{ - DEBUGASSERT(qtd != NULL && bp != NULL); - - usb_ehci_dcache_invalidate((uintptr_t)&qtd->hw, sizeof(struct usb_ehci_qtd_s)); - - /* Remove the qTD from the list - * - * NOTE that we don't check if the qTD is active nor do we check if there - * are any errors reported in the qTD. If the transfer halted due to - * an error, then qTDs in the list after the error qTD will still appear - * to be active. - * - * REVISIT: There is a race condition here that needs to be resolved. - */ - - **bp = qtd->hw.nqp; - - /* Release this QH by returning it to the free list */ - - usb_ehci_qtd_free(qtd); - return 0; -} - -/**************************************************************************** - * Name: usb_ehci_qh_cancel - * - * Description: - * This function is a imxrt_qh_foreach() callback function. It cancels - * one QH in the asynchronous queue. It will remove all attached qTD - * structures and remove all of the structures that are no longer active. - * Then QH itself will also be removed. - * - ****************************************************************************/ -static int usb_ehci_qh_cancel(struct usb_ehci_qh_s *qh, uint32_t **bp, void *arg) -{ - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)arg; - uint32_t regval; - int ret; - - DEBUGASSERT(qh != NULL && bp != NULL && epinfo != NULL); - - usb_ehci_dcache_invalidate((uintptr_t)&qh->hw, sizeof(struct usb_ehci_qh_s)); - - /* Check if this is the QH that we are looking for */ - - if (qh->epinfo == epinfo) { - /* No... keep looking */ - - return 0; - } - - /* Disable both the asynchronous and period schedules */ - - regval = usb_ehci_getreg(&HCOR->usbcmd); - usb_ehci_putreg(regval & ~(EHCI_USBCMD_ASEN | EHCI_USBCMD_PSEN), - &HCOR->usbcmd); - - /* Remove the QH from the list - * - * NOTE that we don't check if the qTD is active nor do we check if there - * are any errors reported in the qTD. If the transfer halted due to - * an error, then qTDs in the list after the error qTD will still appear - * to be active. - * - * REVISIT: There is a race condition here that needs to be resolved. - */ - - **bp = qh->hw.hlp; - usb_ehci_dcache_clean((uintptr_t)*bp, sizeof(uint32_t)); - /* Re-enable the schedules (if they were enabled before. */ - - usb_ehci_putreg(regval, &HCOR->usbcmd); - - /* Remove all active, attached qTD structures from the removed QH */ - - ret = usb_ehci_qtd_foreach(qh, usb_ehci_qtd_cancel, NULL); - if (ret < 0) { - } - - /* Then release this QH by returning it to the free list. Return 1 - * to stop the traverse without an error. - */ - - usb_ehci_qh_free(qh); - return 1; -} - -static inline void usb_ehci_ioc_bottomhalf(void) -{ - struct usb_ehci_qh_s *qh; - uint32_t *bp; - int ret; - - usb_ehci_dcache_invalidate((uintptr_t)&g_asynchead.hw, sizeof(struct usb_ehci_qh_s)); - /* Set the back pointer to the forward qTD pointer of the asynchronous - * queue head. - */ - - bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct usb_ehci_qh_s *) - usb_ehci_virtramaddr(usb_ehci_swap32(*bp) & QH_HLP_MASK); - - /* If the asynchronous queue is empty, then the forward point in the - * asynchronous queue head will point back to the queue head. - */ - if (qh && qh != &g_asynchead) { - /* Then traverse and operate on every QH and qTD in the asynchronous - * queue - */ - usb_ehci_qh_foreach(qh, &bp, usb_ehci_qh_ioccheck, NULL); - } -#ifndef CONFIG_USBHOST_INT_DISABLE - /* Check the Interrupt Queue */ - - usb_ehci_dcache_invalidate((uintptr_t)&g_intrhead.hw, sizeof(struct usb_ehci_qh_s)); - /* Set the back pointer to the forward qTD pointer of the asynchronous - * queue head. - */ - - bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct usb_ehci_qh_s *) - usb_ehci_virtramaddr(usb_ehci_swap32(*bp) & QH_HLP_MASK); - if (qh) { - /* Then traverse and operate on every QH and qTD in the asynchronous - * queue. - */ - - ret = usb_ehci_qh_foreach(qh, &bp, usb_ehci_qh_ioccheck, NULL); - if (ret < 0) { - } - } -#endif -} - -/**************************************************************************** - * Name: usb_ehci_portsc_bottomhalf - * - * Description: - * EHCI Port Change Detect "Bottom Half" interrupt handler - * - * "The Host Controller sets this bit to a one when any port for which the - * Port Owner bit is set to zero ... has a change bit transition from a - * zero to a one or a Force Port Resume bit transition from a zero to a - * one as a result of a J-K transition detected on a suspended port. - * This bit will also be set as a result of the Connect Status Change - * being set to a one after system software has relinquished ownership of - * a connected port by writing a one to a port's Port Owner bit... - * - * "This bit is allowed to be maintained in the Auxiliary power well. - * Alternatively, it is also acceptable that on a D3 to D0 transition of - * the EHCI HC device, this bit is loaded with the OR of all of the PORTSC - * change bits (including: Force port resume, over-current change, - * enable/disable change and connect status change)." - * - ****************************************************************************/ -static inline void usb_ehci_portsc_bottomhalf(void) -{ - uint32_t portsc; - int rhpndx; - - /* Handle root hub status change on each root port */ - - for (rhpndx = 0; rhpndx < CONFIG_USBHOST_RHPORTS; rhpndx++) { - portsc = usb_ehci_getreg(&HCOR->portsc[rhpndx]); - - /* Handle port connection status change (CSC) events */ - if ((portsc & EHCI_PORTSC_CSC) != 0) { - if ((portsc & EHCI_PORTSC_CCS) == EHCI_PORTSC_CCS) { - /* Connected ... Did we just become connected? */ - usbh_event_notify_handler(USBH_EVENT_CONNECTED, 1); - } else { - for (uint8_t chidx = 0; chidx < CONFIG_USBHOST_PIPE_NUM; chidx++) { - struct usb_ehci_epinfo_s *epinfo = &g_ehci_hcd.chan[chidx]; - if (epinfo->iocwait) { - epinfo->iocwait = false; - usb_osal_sem_give(epinfo->iocsem); - } - } - usbh_event_notify_handler(USBH_EVENT_DISCONNECTED, 1); - } - } - - /* Clear all pending port interrupt sources by writing a '1' to the - * corresponding bit in the PORTSC register. In addition, we need - * to preserve the values of all R/W bits (RO bits don't matter) - */ - usb_ehci_putreg(portsc, &HCOR->portsc[rhpndx]); - } -} - -/**************************************************************************** - * Name: usb_ehci_reset - * - * Description: - * Set the HCRESET bit in the USBCMD register to reset the EHCI hardware. - * - * Table 2-9. USBCMD - USB Command Register Bit Definitions - * - * "Host Controller Reset (HCRESET) ... This control bit is used by - * software to reset the host controller. The effects of this on Root - * Hub registers are similar to a Chip Hardware Reset. - * - * "When software writes a one to this bit, the Host Controller resets its - * internal pipelines, timers, counters, state machines, etc. to their - * initial value. Any transaction currently in progress on USB is - * immediately terminated. A USB reset is not driven on downstream - * ports. - * - * "PCI Configuration registers are not affected by this reset. All - * operational registers, including port registers and port state - * machines are set to their initial values. Port ownership reverts - * to the companion host controller(s)... Software must reinitialize - * the host controller ... in order to return the host controller to - * an operational state. - * - * "This bit is set to zero by the Host Controller when the reset process - * is complete. Software cannot terminate the reset process early by - * writing a zero to this register. Software should not set this bit to - * a one when the HCHalted bit in the USBSTS register is a zero. - * Attempting to reset an actively running host controller will result - * in undefined behavior." - * - * Input Parameters: - * None. - * - * Returned Value: - * Zero (OK) is returned on success; A negated errno value is returned - * on failure. - * - * Assumptions: - * - Called during the initialization of the EHCI. - * - ****************************************************************************/ - -static int usb_ehci_reset(void) -{ - uint32_t regval; - unsigned int timeout; - - /* Make sure that the EHCI is halted: "When [the Run/Stop] bit is set to - * 0, the Host Controller completes the current transaction on the USB and - * then halts. The HC Halted bit in the status register indicates when the - * Host Controller has finished the transaction and has entered the - * stopped state..." - */ - - usb_ehci_putreg(0, &HCOR->usbcmd); - - /* "... Software should not set [HCRESET] to a one when the HCHalted bit in - * the USBSTS register is a zero. Attempting to reset an actively running - * host controller will result in undefined behavior." - */ - - timeout = 0; - do { - /* Wait one microsecond and update the timeout counter */ - - usb_osal_msleep(1); - timeout++; - - /* Get the current value of the USBSTS register. This loop will - * terminate when either the timeout exceeds one millisecond or when - * the HCHalted bit is no longer set in the USBSTS register. - */ - - regval = usb_ehci_getreg(&HCOR->usbsts); - } while (((regval & EHCI_USBSTS_HALTED) == 0) && (timeout < 1000)); - - /* Is the EHCI still running? Did we timeout? */ - - if ((regval & EHCI_USBSTS_HALTED) == 0) { - return -ETIMEDOUT; - } - - /* Now we can set the HCReset bit in the USBCMD register to - * initiate the reset - */ - - regval = usb_ehci_getreg(&HCOR->usbcmd); - regval |= EHCI_USBCMD_HCRESET; - usb_ehci_putreg(regval, &HCOR->usbcmd); - - /* Wait for the HCReset bit to become clear */ - - do { - /* Wait five microsecondw and update the timeout counter */ - - usb_osal_msleep(5); - timeout += 5; - - /* Get the current value of the USBCMD register. This loop will - * terminate when either the timeout exceeds one second or when the - * HCReset bit is no longer set in the USBSTS register. - */ - - regval = usb_ehci_getreg(&HCOR->usbcmd); - } while (((regval & EHCI_USBCMD_HCRESET) != 0) && (timeout < 1000000)); - - /* Return either success or a timeout */ - - return (regval & EHCI_USBCMD_HCRESET) != 0 ? -ETIMEDOUT : 0; -} - -/**************************************************************************** - * Name: usb_ehci_wait_usbsts - * - * Description: - * Wait for either (1) a field in the USBSTS register to take a specific - * value, (2) for a timeout to occur, or (3) a error to occur. Return - * a value to indicate which terminated the wait. - * - ****************************************************************************/ - -static int usb_ehci_wait_usbsts(uint32_t maskbits, uint32_t donebits, unsigned int delay) -{ - uint32_t regval; - unsigned int timeout; - - timeout = 0; - do { - /* Wait 5usec before trying again */ - - usb_osal_msleep(5); - timeout += 5; - - /* Read the USBSTS register and check for a system error */ - - regval = usb_ehci_getreg(&HCOR->usbsts); - if ((regval & EHCI_INT_SYSERROR) != 0) { - return -EIO; - } - - /* Mask out the bits of interest */ - - regval &= maskbits; - - /* Loop until the masked bits take the specified value or until a - * timeout occurs. - */ - } while (regval != donebits && timeout < delay); - - /* We got here because either the waited for condition or a timeout - * occurred. Return a value to indicate which. - */ - - return (regval == donebits) ? 0 : -ETIMEDOUT; -} - -__WEAK void usb_hc_low_level_init(void) -{ -} - -int usb_hc_sw_init(void) -{ - memset(&g_ehci_hcd, 0, sizeof(struct ehci_hcd)); - - /* Initialize the list of free Queue Head (QH) structures */ - for (uint8_t i = 0; i < CONFIG_USB_EHCI_QH_NUM; i++) { - /* Put the QH structure in a free list */ - - usb_ehci_qh_free(&g_ehci_hcd.qhpool[i]); - } - - /* Initialize the list of free Queue Head (QH) structures */ - for (uint8_t i = 0; i < CONFIG_USB_EHCI_QTD_NUM; i++) { - /* Put the QH structure in a free list */ - - usb_ehci_qtd_free(&g_ehci_hcd.qtdpool[i]); - } - - for (uint8_t chidx = 0; chidx < CONFIG_USB_EHCI_QH_NUM; chidx++) { - struct usb_ehci_epinfo_s *epinfo; - - epinfo = &g_ehci_hcd.chan[chidx]; - epinfo->iocsem = usb_osal_sem_create(0); - epinfo->exclsem = usb_osal_mutex_create(); - } - - return 0; -} - -int usb_hc_hw_init(void) -{ - int ret; - uint32_t regval; - uintptr_t physaddr1; - uintptr_t physaddr2; - - /* Initialize the head of the asynchronous queue/reclamation list. - * - * "In order to communicate with devices via the asynchronous schedule, - * system software must write the ASYNDLISTADDR register with the address - * of a control or bulk queue head. Software must then enable the - * asynchronous schedule by writing a one to the Asynchronous Schedule - * Enable bit in the USBCMD register. In order to communicate with devices - * via the periodic schedule, system software must enable the periodic - * schedule by writing a one to the Periodic Schedule Enable bit in the - * USBCMD register. Note that the schedules can be turned on before the - * first port is reset (and enabled)." - */ - - memset(&g_asynchead, 0, sizeof(struct usb_ehci_qh_s)); - physaddr1 = usb_ehci_physramaddr((uintptr_t)&g_asynchead); - g_asynchead.hw.hlp = usb_ehci_swap32(physaddr1 | QH_HLP_TYP_QH); - g_asynchead.hw.epchar = usb_ehci_swap32(QH_EPCHAR_H | - QH_EPCHAR_EPS_FULL); - g_asynchead.hw.overlay.nqp = usb_ehci_swap32(QH_NQP_T); - g_asynchead.hw.overlay.alt = usb_ehci_swap32(QH_NQP_T); - g_asynchead.hw.overlay.token = usb_ehci_swap32(QH_TOKEN_HALTED); - g_asynchead.fqp = usb_ehci_swap32(QTD_NQP_T); - - usb_ehci_dcache_clean((uintptr_t)&g_asynchead.hw, sizeof(struct usb_ehci_qh_s)); - - /* Initialize the head of the periodic list. Since Isochronous - * endpoints are not not yet supported, each element of the - * frame list is initialized to point to the Interrupt Queue - * Head (g_intrhead). - */ - - memset(&g_intrhead, 0, sizeof(struct usb_ehci_qh_s)); - g_intrhead.hw.hlp = usb_ehci_swap32(QH_HLP_T); - g_intrhead.hw.overlay.nqp = usb_ehci_swap32(QH_NQP_T); - g_intrhead.hw.overlay.alt = usb_ehci_swap32(QH_NQP_T); - g_intrhead.hw.overlay.token = usb_ehci_swap32(QH_TOKEN_HALTED); - g_intrhead.hw.epcaps = usb_ehci_swap32(QH_EPCAPS_SSMASK(1)); - - /* Attach the periodic QH to Period Frame List */ - physaddr2 = usb_ehci_physramaddr((uintptr_t)&g_intrhead); - for (uint32_t i = 0; i < FRAME_LIST_SIZE; i++) { - g_framelist[i] = usb_ehci_swap32(physaddr2) | PFL_TYP_QH; - } - - /* Set the Periodic Frame List Base Address. */ - physaddr2 = usb_ehci_physramaddr((uintptr_t)g_framelist); - - usb_ehci_dcache_clean((uintptr_t)&g_intrhead.hw, sizeof(struct usb_ehci_qh_s)); - usb_ehci_dcache_clean((uintptr_t)g_framelist, FRAME_LIST_SIZE * sizeof(uint32_t)); - - usb_hc_low_level_init(); - /* Host Controller Initialization. Paragraph 4.1 */ - - /* Reset the EHCI hardware */ - ret = usb_ehci_reset(); - if (ret < 0) { - return -1; - } - - /* Disable all interrupts */ - usb_ehci_putreg(0, &HCOR->usbintr); - - /* Clear pending interrupts. Bits in the USBSTS register are cleared by - * writing a '1' to the corresponding bit. - */ - usb_ehci_putreg(EHCI_INT_ALLINTS, &HCOR->usbsts); - -#if defined(CONFIG_USB_EHCI_INFO_ENABLE) - /* Show the EHCI version */ - uint16_t regval16 = usb_ehci_swap16(HCCR->hciversion); - USB_LOG_INFO("EHCI HCIVERSION %x.%02x\r\n", regval16 >> 8, regval16 & 0xff); - - /* Verify that the correct number of ports is reported */ - regval = usb_ehci_getreg(&HCCR->hcsparams); - uint8_t nports = (regval & EHCI_HCSPARAMS_NPORTS_MASK) >> EHCI_HCSPARAMS_NPORTS_SHIFT; - USB_LOG_INFO("EHCI nports=%d, HCSPARAMS=%04x\r\n", nports, regval); - - /* Show the HCCPARAMS register */ - regval = usb_ehci_getreg(&HCCR->hccparams); - USB_LOG_INFO("EHCI HCCPARAMS=%06x\r\n", regval); -#endif - /* Set the Current Asynchronous List Address. */ - usb_ehci_putreg(usb_ehci_swap32(physaddr1), &HCOR->asynclistaddr); - /* Set the Periodic Frame List Base Address. */ - usb_ehci_putreg(usb_ehci_swap32(physaddr2), &HCOR->periodiclistbase); - - /* Enable the asynchronous schedule and, possibly enable the periodic - * schedule and set the frame list size. - */ - regval = usb_ehci_getreg(&HCOR->usbcmd); - regval &= ~(EHCI_USBCMD_HCRESET | EHCI_USBCMD_FLSIZE_MASK | - EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN | EHCI_USBCMD_IAADB); - regval |= EHCI_USBCMD_ASEN; - -#ifndef CONFIG_USBHOST_INT_DISABLE - regval |= EHCI_USBCMD_PSEN; -#if FRAME_LIST_SIZE == 1024 - regval |= EHCI_USBCMD_FLSIZE_1024; -#elif FRAME_LIST_SIZE == 512 - regval |= EHCI_USBCMD_FLSIZE_512; -#elif FRAME_LIST_SIZE == 256 - regval |= EHCI_USBCMD_FLSIZE_256; -#else -#error Unsupported frame size list size -#endif -#endif - - usb_ehci_putreg(regval, &HCOR->usbcmd); - - /* Start the host controller by setting the RUN bit in the - * USBCMD register. - */ - regval = usb_ehci_getreg(&HCOR->usbcmd); - regval |= EHCI_USBCMD_RUN; - usb_ehci_putreg(regval, &HCOR->usbcmd); - - /* Route all ports to this host controller by setting the CONFIG flag. */ -#ifdef CONFIG_USB_EHCI_CONFIGFLAG - regval = usb_ehci_getreg(&HCOR->configflag); - regval |= EHCI_CONFIGFLAG; - usb_ehci_putreg(regval, &HCOR->configflag); -#endif - /* Wait for the EHCI to run (i.e., no longer report halted) */ - ret = usb_ehci_wait_usbsts(EHCI_USBSTS_HALTED, 0, 100 * 1000); - if (ret < 0) { - return -2; - } -#ifdef CONFIG_USB_EHCI_PORT_POWER - for (uint8_t port = 1; i <= CONFIG_USBHOST_RHPORTS; port++) { - regval = usb_ehci_getreg(&HCOR->portsc[port - 1]); - regval |= EHCI_PORTSC_PP; - usb_ehci_putreg(regval, &HCOR->portsc[port - 1]); - } -#endif - /* Enable EHCI interrupts. Interrupts are still disabled at the level of - * the interrupt controller. - */ - usb_ehci_putreg(EHCI_HANDLED_INTS, &HCOR->usbintr); - - return ret; -} - -bool usbh_get_port_connect_status(const uint8_t port) -{ - uint32_t portsc; - portsc = usb_ehci_getreg(&HCOR->portsc[port - 1]); - if ((portsc & EHCI_PORTSC_CCS) == EHCI_PORTSC_CCS) { - return true; - } else { - return false; - } -} - -int usbh_reset_port(const uint8_t port) -{ - uint32_t timeout = 0; - uint32_t regval; - regval = usb_ehci_getreg(&HCOR->portsc[port - 1]); - regval &= ~EHCI_PORTSC_PE; - regval |= EHCI_PORTSC_RESET; - usb_ehci_putreg(regval, &HCOR->portsc[port - 1]); - - usb_osal_msleep(55); - - regval = usb_ehci_getreg(&HCOR->portsc[port - 1]); - regval &= ~EHCI_PORTSC_RESET; - usb_ehci_putreg(regval, &HCOR->portsc[port - 1]); - - /* Wait for the port reset to complete - * - * Paragraph 2.3.9: - * - * "Note that when software writes a zero to this bit there may be a - * delay before the bit status changes to a zero. The bit status will - * not read as a zero until after the reset has completed. If the port - * is in high-speed mode after reset is complete, the host controller - * will automatically enable this port (e.g. set the Port Enable bit - * to a one). A host controller must terminate the reset and stabilize - * the state of the port within 2 milliseconds of software transitioning - * this bit from a one to a zero ..." - */ - - while ((usb_ehci_getreg(&HCOR->portsc[port - 1]) & EHCI_PORTSC_RESET) != 0) { - usb_osal_msleep(1); - timeout++; - if (timeout > 100) { - return -ETIMEDOUT; - } - } - - return 0; -} - -// __WEAK uint8_t usbh_get_port_speed(const uint8_t port) -// { -// /* Defined by individual manufacturers */ -// return 0; -// } - -int usbh_ep0_reconfigure(usbh_epinfo_t ep, uint8_t dev_addr, uint8_t ep_mps, uint8_t speed) -{ - struct usb_ehci_epinfo_s *epinfo; - int ret; - - epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo != NULL && ep_mps < 2048); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - epinfo->devaddr = dev_addr; - epinfo->speed = speed; - epinfo->maxpacket = ep_mps; - - usb_osal_mutex_give(epinfo->exclsem); - - return ret; -} - -int usbh_ep_alloc(usbh_epinfo_t *ep, const struct usbh_endpoint_cfg *ep_cfg) -{ - struct usb_ehci_epinfo_s *epinfo; - struct usbh_hubport *hport; - usb_osal_sem_t iocsem; - usb_osal_mutex_t exclsem; - int chidx; - - DEBUGASSERT(ep_cfg != NULL && ep_cfg->hport != NULL); - - hport = ep_cfg->hport; - - chidx = usb_ehci_chan_alloc(); - - epinfo = &g_ehci_hcd.chan[chidx]; - - iocsem = epinfo->iocsem; - exclsem = epinfo->exclsem; - - memset(epinfo, 0, sizeof(struct usb_ehci_epinfo_s)); - - epinfo->epno = ep_cfg->ep_addr & 0x7f; - epinfo->dirin = (ep_cfg->ep_addr & 0x80) ? 1 : 0; - epinfo->devaddr = hport->dev_addr; -#ifndef CONFIG_USBHOST_INT_DISABLE - epinfo->interval = ep_cfg->ep_interval; -#endif - epinfo->maxpacket = ep_cfg->ep_mps; - epinfo->xfrtype = ep_cfg->ep_type; - epinfo->speed = hport->speed; - epinfo->hport = hport; - - /* restore variable */ - epinfo->inuse = true; - epinfo->iocsem = iocsem; - epinfo->exclsem = exclsem; - - *ep = (usbh_epinfo_t)epinfo; - - return 0; -} - -int usbh_ep_free(usbh_epinfo_t ep) -{ - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - usb_ehci_chan_free(epinfo); - - return 0; -} - -int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, uint8_t *buffer) -{ - int ret; - - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo); - - /* A buffer may or may be supplied with an EP0 SETUP transfer. A buffer - * will always be present for normal endpoint data transfers. - */ - - DEBUGASSERT(setup || buffer); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - /* Set the request for the IOC event well BEFORE initiating the transfer. */ - ret = usb_ehci_ioc_setup(epinfo); - if (ret != 0) { - goto errout_with_setup; - } - - ret = usb_ehci_control_init(epinfo, setup, buffer, setup->wLength); - if (ret < 0) { - goto errout_with_iocwait; - } - - /* And wait for the transfer to complete */ - ret = usb_ehci_transfer_wait(epinfo, CONFIG_USBHOST_CONTROL_TRANSFER_TIMEOUT); - if (ret < 0) { - goto errout_with_iocwait; - } - - usb_osal_mutex_give(epinfo->exclsem); - return ret; - -errout_with_iocwait: - epinfo->iocwait = false; - /* Clean-up after an error */ - if (epinfo->qh) { - usb_ehci_qh_discard(epinfo->qh); - epinfo->qh = NULL; - } -errout_with_setup: - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} - -int usbh_ep_bulk_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout) -{ - int ret; - - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo && buffer && buflen > 0); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - ret = usb_ehci_ioc_setup(epinfo); - if (ret < 0) { - goto errout_with_setup; - } - - ret = usb_ehci_bulk_init(epinfo, buffer, buflen); - if (ret < 0) { - goto errout_with_iocwait; - } - - /* And wait for the transfer to complete */ - ret = usb_ehci_transfer_wait(epinfo, timeout); - if (ret < 0) { - goto errout_with_iocwait; - } - usb_osal_mutex_give(epinfo->exclsem); - return ret; - -errout_with_iocwait: - epinfo->iocwait = false; - /* Clean-up after an error */ - if (epinfo->qh) { - usb_ehci_qh_discard(epinfo->qh); - epinfo->qh = NULL; - } -errout_with_setup: - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} - -int usbh_ep_intr_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, uint32_t timeout) -{ - int ret; - - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo && buffer && buflen > 0); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - ret = usb_ehci_ioc_setup(epinfo); - if (ret < 0) { - goto errout_with_setup; - } - - ret = usb_ehci_intr_init(epinfo, buffer, buflen); - if (ret < 0) { - goto errout_with_iocwait; - } - - /* And wait for the transfer to complete */ - ret = usb_ehci_transfer_wait(epinfo, timeout); - if (ret < 0) { - goto errout_with_iocwait; - } - usb_osal_mutex_give(epinfo->exclsem); - return ret; - -errout_with_iocwait: - epinfo->iocwait = false; - /* Clean-up after an error */ - if (epinfo->qh) { - usb_ehci_qh_discard(epinfo->qh); - epinfo->qh = NULL; - } -errout_with_setup: - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} -#ifdef CONFIG_USBHOST_ASYNCH -int usbh_ep_bulk_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, usbh_asynch_callback_t callback, void *arg) -{ - int ret; - - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo && buffer && buflen > 0); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - /* Set the request for the callback well BEFORE initiating the transfer. */ - ret = usb_ehci_ioc_async_setup(epinfo, callback, arg); - if (ret != 0) { - goto errout_with_setup; - } - - /* Check for errors in the setup of the transfer */ - ret = usb_ehci_bulk_init(epinfo, buffer, buflen); - if (ret < 0) { - goto errout_with_qh; - } - - /* The transfer is in progress */ - usb_osal_mutex_give(epinfo->exclsem); - return 0; - -errout_with_qh: - /* Clean-up after an error */ - if (epinfo->qh) { - usb_ehci_qh_discard(epinfo->qh); - epinfo->qh = NULL; - } -errout_with_setup: - epinfo->callback = NULL; - epinfo->arg = NULL; - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} - -int usbh_ep_intr_async_transfer(usbh_epinfo_t ep, uint8_t *buffer, uint32_t buflen, usbh_asynch_callback_t callback, void *arg) -{ - int ret; - - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - - DEBUGASSERT(epinfo && buffer && buflen > 0); - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - /* Set the request for the callback well BEFORE initiating the transfer. */ - ret = usb_ehci_ioc_async_setup(epinfo, callback, arg); - if (ret != 0) { - goto errout_with_setup; - } - - /* Check for errors in the setup of the transfer */ - ret = usb_ehci_intr_init(epinfo, buffer, buflen); - if (ret < 0) { - goto errout_with_qh; - } - - /* The transfer is in progress */ - usb_osal_mutex_give(epinfo->exclsem); - return 0; - -errout_with_qh: - /* Clean-up after an error */ - if (epinfo->qh) { - usb_ehci_qh_discard(epinfo->qh); - epinfo->qh = NULL; - } -errout_with_setup: - epinfo->callback = NULL; - epinfo->arg = NULL; - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} -#endif -/**************************************************************************** - * Name: usb_ehci_cancel - * - * Description: - * Cancel a pending transfer on an endpoint. Canceled synchronous or - * asynchronous transfer will complete normally with the error -ESHUTDOWN. - * - * Input Parameters: - * drvr - The USB host driver instance obtained as a parameter from the - * call to the class create() method. - * ep - The IN or OUT endpoint descriptor for the device endpoint on - * which an asynchronous transfer should be transferred. - * - * Returned Value: - * On success, zero (OK) is returned. On a failure, a negated errno value - * is returned indicating the nature of the failure - * - ****************************************************************************/ - -int usb_ep_cancel(usbh_epinfo_t ep) -{ - struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; - struct usb_ehci_qh_s *qh; -#ifdef CONFIG_USBHOST_ASYNCH - usbh_asynch_callback_t callback; - void *arg; -#endif - uint32_t *bp; - uint32_t flags; - bool iocwait; - int ret; - - DEBUGASSERT(epinfo); - - /* We must have exclusive access to the EHCI hardware and data structures. - * This will prevent servicing any transfer completion events while we - * perform the cancellation, but will not prevent DMA-related race - * conditions. - * - * REVISIT: This won't work. This function must be callable from the - * interrupt level. - */ - - ret = usb_osal_mutex_take(epinfo->exclsem); - if (ret < 0) { - return ret; - } - - /* Sample and reset all transfer termination information. This will - * prevent any callbacks from occurring while are performing the - * cancellation. The transfer may still be in progress, however, so this - * does not eliminate other DMA-related race conditions. - */ - - flags = usb_osal_enter_critical_section(); -#ifdef CONFIG_USBHOST_ASYNCH - callback = epinfo->callback; - arg = epinfo->arg; -#endif - iocwait = epinfo->iocwait; - -#ifdef CONFIG_USBHOST_ASYNCH - epinfo->callback = NULL; - epinfo->arg = NULL; -#endif - epinfo->iocwait = false; - - /* This will prevent any callbacks from occurring while are performing - * the cancellation. The transfer may still be in progress, however, so - * this does not eliminate other DMA-related race conditions. - */ - - epinfo->callback = NULL; - epinfo->arg = NULL; - usb_osal_leave_critical_section(flags); - - /* Bail if there is no transfer in progress for this endpoint */ - -#ifdef CONFIG_USBHOST_ASYNCH - if (callback == NULL && !iocwait) -#else - if (!iocwait) -#endif - { - ret = 0; - goto errout_with_sem; - } - - /* Handle the cancellation according to the type of the transfer */ - - switch (epinfo->xfrtype) { - case USB_ENDPOINT_TYPE_CONTROL: - case USB_ENDPOINT_TYPE_BULK: { - /* Get the horizontal pointer from the head of the asynchronous - * queue. - */ - - bp = (uint32_t *)&g_asynchead.hw.hlp; - qh = (struct usb_ehci_qh_s *) - usb_ehci_virtramaddr(usb_ehci_swap32(*bp) & QH_HLP_MASK); - - /* If the asynchronous queue is empty, then the forward point in - * the asynchronous queue head will point back to the queue - * head. - */ - - if (qh && qh != &g_asynchead) { - /* Claim that we successfully cancelled the transfer */ - - ret = 0; - goto exit_terminate; - } - } break; - -#ifndef CONFIG_USBHOST_INT_DISABLE - case USB_ENDPOINT_TYPE_INTERRUPT: { - /* Get the horizontal pointer from the head of the interrupt - * queue. - */ - - bp = (uint32_t *)&g_intrhead.hw.hlp; - qh = (struct usb_ehci_qh_s *) - usb_ehci_virtramaddr(usb_ehci_swap32(*bp) & QH_HLP_MASK); - if (qh) { - /* if the queue is empty, then just claim that we successfully - * cancelled the transfer. - */ - - ret = 0; - goto exit_terminate; - } - } break; -#endif - - case USB_ENDPOINT_TYPE_ISOCHRONOUS: - default: - ret = -ENOSYS; - goto errout_with_sem; - } - - /* Find and remove the QH. There are four possibilities: - * - * 1) The transfer has already completed and the QH is no longer in the - * list. In this case, sam_hq_foreach will return zero - * 2a) The transfer is not active and still pending. It was removed from - * the list and sam_hq_foreach will return one. - * 2b) The is active but not yet complete. This is currently handled the - * same as 2a). REVISIT: This needs to be fixed. - * 3) Some bad happened and sam_hq_foreach returned an error code < 0. - */ - - ret = usb_ehci_qh_foreach(qh, &bp, usb_ehci_qh_cancel, epinfo); - if (ret < 0) { - } - - /* Was there a pending synchronous transfer? */ - -exit_terminate: - epinfo->result = -ESHUTDOWN; -#ifdef CONFIG_USBHOST_ASYNCH - if (iocwait) { - /* Yes... wake it up */ - - DEBUGASSERT(callback == NULL); - usb_osal_sem_give(epinfo->iocsem); - } - - /* No.. Is there a pending asynchronous transfer? */ - - else /* if (callback != NULL) */ - { - /* Yes.. perform the callback */ - - callback(arg, -ESHUTDOWN); - } - -#else - /* Wake up the waiting thread */ - - usb_osal_sem_give(epinfo->iocsem); -#endif - -errout_with_sem: - usb_osal_mutex_give(epinfo->exclsem); - return ret; -} - -static void usb_ehci_bottomhalf(void *arg) -{ - uint32_t pending = (uint32_t)arg; - - /* USB Interrupt (USBINT) - * - * "The Host Controller sets this bit to 1 on the completion of a USB - * transaction, which results in the retirement of a Transfer Descriptor - * that had its IOC bit set. - * - * "The Host Controller also sets this bit to 1 when a short packet is - * detected (actual number of bytes received was less than the expected - * number of bytes)." - * - * USB Error Interrupt (USBERRINT) - * - * "The Host Controller sets this bit to 1 when completion of a USB - * transaction results in an error condition (e.g., error counter - * underflow). If the TD on which the error interrupt occurred also - * had its IOC bit set, both this bit and USBINT bit are set. ..." - * - * We do the same thing in either case: Traverse the asynchronous queue - * and remove all of the transfers that are no longer active. - */ - if ((pending & (EHCI_INT_USBINT | EHCI_INT_USBERRINT)) != 0) { - usb_ehci_ioc_bottomhalf(); - } - /* Port Change Detect - * - * "The Host Controller sets this bit to a one when any port for which - * the Port Owner bit is set to zero ... has a change bit transition - * from a zero to a one or a Force Port Resume bit transition from a zero - * to a one as a result of a J-K transition detected on a suspended port. - * This bit will also be set as a result of the Connect Status Change - * being set to a one after system software has relinquished ownership - * of a connected port by writing a one to a port's Port Owner bit... - * - * "This bit is allowed to be maintained in the Auxiliary power well. - * Alternatively, it is also acceptable that on a D3 to D0 transition - * of the EHCI HC device, this bit is loaded with the OR of all of the - * PORTSC change bits (including: Force port resume, over-current change, - * enable/disable change and connect status change)." - */ - if ((pending & EHCI_INT_PORTSC) != 0) { - usb_ehci_portsc_bottomhalf(); - } - /* Frame List Rollover - * - * "The Host Controller sets this bit to a one when the Frame List Index - * ... rolls over from its maximum value to zero. The exact value at - * which the rollover occurs depends on the frame list size. For example, - * if the frame list size (as programmed in the Frame List Size field of - * the USBCMD register) is 1024, the Frame Index Register rolls over - * every time FRINDEX[13] toggles. Similarly, if the size is 512, the - * Host Controller sets this bit to a one every time FRINDEX[12] - * toggles." - */ - -#if 0 /* Not used */ - if ((pending & EHCI_INT_FLROLL) != 0) - { - - } -#endif - /* Host System Error - * - * "The Host Controller sets this bit to 1 when a serious error occurs - * during a host system access involving the Host Controller module. ... - * When this error occurs, the Host Controller clears the Run/Stop bit - * in the Command register to prevent further execution of the scheduled - * TDs." - */ - - if ((pending & EHCI_INT_SYSERROR) != 0) { - } - /* Interrupt on Async Advance - * - * "System software can force the host controller to issue an interrupt - * the next time the host controller advances the asynchronous schedule - * by writing a one to the Interrupt on Async Advance Doorbell bit in - * the USBCMD register. This status bit indicates the assertion of that - * interrupt source." - */ - - if ((pending & EHCI_INT_AAINT) != 0) { - } -} - -void USBH_IRQHandler(void) -{ - uint32_t usbsts; - uint32_t pending; - uint32_t regval; - - /* Read Interrupt Status and mask out interrupts that are not enabled. */ - - usbsts = usb_ehci_getreg(&HCOR->usbsts); - regval = usb_ehci_getreg(&HCOR->usbintr); - - /* Handle all unmasked interrupt sources */ - pending = usbsts & regval; - - if (pending != 0) { - /* Disable further EHCI interrupts so that we do not overrun the work queue.*/ - usb_ehci_putreg(0, &HCOR->usbintr); - /* Clear all pending status bits by writing the value of the pending - * interrupt bits back to the status register. - */ - usb_ehci_putreg(usbsts & EHCI_INT_ALLINTS, &HCOR->usbsts); - - usb_ehci_bottomhalf((void *)pending); - - /* Re-enable relevant EHCI interrupts. Interrupts should still be enabled - * at the level of the interrupt controller. - */ - usb_ehci_putreg(EHCI_HANDLED_INTS, &HCOR->usbintr); - } -} \ No newline at end of file diff --git a/port/ehci/usb_ehci.h b/port/ehci/usb_ehci.h deleted file mode 100644 index c2c37b93..00000000 --- a/port/ehci/usb_ehci.h +++ /dev/null @@ -1,1008 +0,0 @@ -/**************************************************************************** - * include/nuttx/usb/ehci.h - * - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. The - * ASF licenses this file to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance with the - * License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the - * License for the specific language governing permissions and limitations - * under the License. - * - ****************************************************************************/ - -#ifndef __INCLUDE_NUTTX_USB_EHCI_H -#define __INCLUDE_NUTTX_USB_EHCI_H - -/**************************************************************************** - * Included Files - ****************************************************************************/ - -#include - -/**************************************************************************** - * Pre-processor Definitions - ****************************************************************************/ - -/* General definitions ******************************************************/ - -/* Endpoint speed values as used in endpoint characteristics field. - * NOTE: These values are *NOT* the same as the SPEED definitions in usb.h. - */ - -#define EHCI_FULL_SPEED (0) /* Full-Speed (12Mbs) */ -#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */ -#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */ - -#define EHCI_DIR_IN (1) /* Direction IN: Peripheral to host */ -#define EHCI_DIR_OUT (0) /* Direction OUT: Host to peripheral */ - -/* PCI Configuration Space Register Offsets *********************************/ - -/* Paragraph 2.1 */ - -/* 0x0009-0x000b: Class Code */ - -#define EHCI_PCI_CLASSC_OFFSET 0x0009 - -/* 0x0010-0x0013: Base Address to Memory-mapped Host Controller Register - * Space - */ - -#define EHCI_PCIUSBBASE_OFFSET 0x0010 - -/* 0x0060: Serial Bus Release Number */ - -#define EHCI_PCI_SBRN_OFFSET 0x0060 - -/* 0x0061: Frame Length Adjustment Register */ - -#define EHCI_PCI_FLADJ_OFFSET 0x0061 - -/* 0x0062-0x0063: Port wake capabilities register (OPTIONAL) */ - -#define EHCI_PCI_PORTWAKECAP_OFFSET 0x0062 - -/* EECP+0x0000: USB Legacy Support EHCI Extended Capability Register */ - -#define EHCI_PCI_USBLEGSUP_OFFSET 0x0000 - -/* EECP+0x0000: USB Legacy Support Control and Status Register */ - -#define EHCI_PCI_USBLEGCTLSTS_OFFSET 0x0004 - -/* Host Controller Capability Register Offsets ******************************/ - -/* Paragraph 2.2 */ - -#define EHCI_CAPLENGTH_OFFSET 0x0000 /* Core Capability Register Length */ - /* 0x0001 Reserved */ -#define EHCI_HCIVERSION_OFFSET 0x0002 /* Core Interface Version Number */ -#define EHCI_HCSPARAMS_OFFSET 0x0004 /* Core Structural Parameters */ -#define EHCI_HCCPARAMS_OFFSET 0x0008 /* Core Capability Parameters */ -#define EHCI_HCSP_PORTROUTE_OFFSET 0x000c /* Core Companion Port Route Description */ - -/* Host Controller Operational Register Offsets *****************************/ - -/* Paragraph 2.3 */ - -#define EHCI_USBCMD_OFFSET 0x0000 /* USB Command */ -#define EHCI_USBSTS_OFFSET 0x0004 /* USB Status */ -#define EHCI_USBINTR_OFFSET 0x0008 /* USB Interrupt Enable */ -#define EHCI_FRINDEX_OFFSET 0x000c /* USB Frame Index */ -#define EHCI_CTRLDSSEGMENT_OFFSET 0x0010 /* 4G Segment Selector */ -#define EHCI_PERIODICLISTBASE_OFFSET 0x0014 /* Frame List Base Address */ -#define EHCI_ASYNCLISTADDR_OFFSET 0x0018 /* Next Asynchronous List Address */ - /* 0x001c-0x003f: Reserved */ -#define EHCI_CONFIGFLAG_OFFSET 0x0040 /* Configured Flag Register */ - -/* Port Status/Control, Port 1-n */ - -#define EHCI_PORTSC_OFFSET(n) (0x0044 + ((n-1) << 2)) -#define EHCI_PORTSC1_OFFSET 0x0044 /* Port Status/Control, Port 1 */ -#define EHCI_PORTSC2_OFFSET 0x0048 /* Port Status/Control, Port 2 */ -#define EHCI_PORTSC3_OFFSET 0x004c /* Port Status/Control, Port 3 */ -#define EHCI_PORTSC4_OFFSET 0x0050 /* Port Status/Control, Port 4 */ -#define EHCI_PORTSC5_OFFSET 0x0054 /* Port Status/Control, Port 5 */ -#define EHCI_PORTSC6_OFFSET 0x0058 /* Port Status/Control, Port 6 */ -#define EHCI_PORTSC7_OFFSET 0x005c /* Port Status/Control, Port 7 */ -#define EHCI_PORTSC8_OFFSET 0x0060 /* Port Status/Control, Port 8 */ -#define EHCI_PORTSC9_OFFSET 0x0064 /* Port Status/Control, Port 9 */ -#define EHCI_PORTSC10_OFFSET 0x0068 /* Port Status/Control, Port 10 */ -#define EHCI_PORTSC11_OFFSET 0x006c /* Port Status/Control, Port 11 */ -#define EHCI_PORTSC12_OFFSET 0x0070 /* Port Status/Control, Port 12 */ -#define EHCI_PORTSC13_OFFSET 0x0074 /* Port Status/Control, Port 13 */ -#define EHCI_PORTSC14_OFFSET 0x0078 /* Port Status/Control, Port 14 */ -#define EHCI_PORTSC15_OFFSET 0x007c /* Port Status/Control, Port 15 */ - -/* Debug Register Offsets ***************************************************/ - -/* Paragraph C.3 */ - -#define EHCI_DEBUG_PCS_OFFSET 0x0000 /* Debug Port Control/Status Register */ -#define EHCI_DEBUG_USBPIDS_OFFSET 0x0004 /* Debug USB PIDs Register */ -#define EHCI_DEBUG_DATA0_OFFSET 0x0008 /* Debug Data Buffer 0 Register [31:0] */ -#define EHCI_DEBUG_DATA1_OFFSET 0x000c /* Debug Data Buffer 1 Register [63:32] */ -#define EHCI_DEBUG_DEVADDR_OFFSET 0x0010 /* Debug Device Address Register */ - -/* PCI Configuration Space Register Bit Definitions *************************/ - -/* 0x0009-0x000b: Class Code. Paragraph 2.1.2 */ - -#define EHCI_PCI_PI_SHIFT (0) /* Bits 0-7: Programming Interface */ -#define EHCI_PCI_PI_MASK (0xff << EHCI_PCI_PI_SHIFT) -# define EHCI_PCI_PI (0x20 << EHCI_PCI_PI_SHIFT) -#define EHCI_PCI_SCC_SHIFT (8) /* Bits 8-15: Sub-Class Code */ -#define EHCI_PCI_SCC_MASK (0xff << EHCI_PCI_SCC_SHIFT) -# define EHCI_PCI_SCC (0x03 << EHCI_PCI_SCC_SHIFT) -#define EHCI_PCI_BASEC_SHIFT (16) /* Base Class Code */ -#define EHCI_PCI_BASEC_MASK (0xff << EHCI_PCI_BASEC_SHIFT) -# define EHCI_PCI_BASEC (0x0c << EHCI_PCI_BASEC_SHIFT) -#define EHCI_PCI_CLASSC 0x000c0320 /* Default value (little endian) */ - -/* 0x0010-0x0013: Base Address to Memory-mapped Host Controller Register - * Space. Paragraph 2.1.3 - */ - - /* Bit 0: Reserved */ - -#define EHCI_PCIUSBBASE_TYPE_SHIFT (0) /* Bits 1-2: Type */ -#define EHCI_PCIUSBBASE_TYPE_MASK (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) -# define EHCI_PCIUSBBASE_TYPE_32BIT (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) /* 32-bit addressing */ -# define EHCI_PCIUSBBASE_TYPE_64BIT (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) /* 64-bit addressing */ - - /* Bits 3-7: Reserved */ -#define EHCI_PCIUSBBASE_BASE_SHIFT (8) /* Bits 8-31: Base address */ -#define EHCI_PCIUSBBASE_BASE_MASK (0xffffff00) - -/* 0x0060: Serial Bus Release Number. Paragraph 2.1.4 */ - -#define EHCI_PCI_SBRN_MASK 0xff /* Bits 0-7: Serial Bus Release Number */ - -/* 0x0061: Frame Length Adjustment Register. Paragraph 2.1.5 */ - -#define EHCI_PCI_FLADJ_SHIFT (0) /* Bit 0-5: Frame Length Timing Value */ -#define EHCI_PCI_FLADJ_MASK (0x3f >> EHCI_PCI_FLADJ_SHIFT) - /* Bits 6-7: Reserved */ - -/* 0x0062-0x0063: Port wake capabilities register (OPTIONAL). - * Paragraph 2.1.6 - */ - -#define EHCI_PCI_PORTWAKECAP_MASK (0xffff) - -/* EECP+0x0000: USB Legacy Support EHCI Extended Capability Register. - * Paragraph 2.1.7 - */ - -#define EHCI_PCI_USBLEGSUP_CAPID_SHIFT (0) /* Bits 0-7 Capability ID */ -#define EHCI_PCI_USBLEGSUP_CAPID_MASK (0xff << EHCI_PCI_USBLEGSUP_CAPID_SHIFT) -#define EHCI_PCI_USBLEGSUP_NEECP_SHIFT (8) /* Bits 8-15: Next EHCI Extended Capability Pointer */ -#define EHCI_PCI_USBLEGSUP_NEECP_MASK (0xff << EHCI_PCI_USBLEGSUP_NEECP_SHIFT) -#define EHCI_PCI_USBLEGSUP_BOWN (1 << 16) /* Bit 16: HC BIOS Owned Semaphore */ - /* Bits 17-23: Reserved */ -#define EHCI_PCI_USBLEGSUP_OSOWN (1 << 24) /* Bit 24: HC OS Owned Semaphore */ - /* Bits 25-31: Reserved */ - -/* EECP+0x0000: USB Legacy Support Control and Status Register. - * Paragraph 2.1.8 - */ - -#define EHCI_PCI_USBLEGCTLSTS_USBCMPEN (1 << 0) /* Bit 0: USB SMI Enable */ -#define EHCI_PCI_USBLEGCTLSTS_USBERREN (1 << 1) /* Bit 1: SMI on USB Error Enable */ -#define EHCI_PCI_USBLEGCTLSTS_PCHEN (1 << 2) /* Bit 2: SMI on Port Change Enable */ -#define EHCI_PCI_USBLEGCTLSTS_FLREN (1 << 3) /* Bit 3: SMI on Frame List Rollover Enable */ -#define EHCI_PCI_USBLEGCTLSTS_HSEEN (1 << 4) /* Bit 4: SMI on Host System Error Enable */ -#define EHCI_PCI_USBLEGCTLSTS_AAEN (1 << 5) /* Bit 5: SMI on Async Advance Enable */ - /* Bits 6-12: Reserved */ -#define EHCI_PCI_USBLEGCTLSTS_OOEN (1 << 13) /* Bit 13: SMI on OS Ownership Enable */ -#define EHCI_PCI_USBLEGCTLSTS_PCEN (1 << 14) /* Bit 14: SMI on PCI Command Enable */ -#define EHCI_PCI_USBLEGCTLSTS_BAREN (1 << 15) /* Bit 15: SMI on BAR Enable */ -#define EHCI_PCI_USBLEGCTLSTS_USBCMP (1 << 16) /* Bit 16: SMI on USB Complete */ -#define EHCI_PCI_USBLEGCTLSTS_USBERR (1 << 17) /* Bit 17: SMI on USB Error */ -#define EHCI_PCI_USBLEGCTLSTS_PCH (1 << 18) /* Bit 18: SMI on Port Change Detect */ -#define EHCI_PCI_USBLEGCTLSTS_FLR (1 << 19) /* Bit 19: SMI on Frame List Rollover */ -#define EHCI_PCI_USBLEGCTLSTS_HSE (1 << 20) /* Bit 20: SMI on Host System Error */ -#define EHCI_PCI_USBLEGCTLSTS_AA (1 << 21) /* Bit 21: SMI on Async Advance */ - /* Bits 22-28: Reserved */ -#define EHCI_PCI_USBLEGCTLSTS_OO (1 << 29) /* Bit 29: SMI on OS Ownership Change */ -#define EHCI_PCI_USBLEGCTLSTS_PC (1 << 30) /* Bit 30: SMI on PCI Command */ -#define EHCI_PCI_USBLEGCTLSTS_BAR (1 << 31) /* Bit 31: SMI on BAR */ - -/* Host Controller Capability Register Bit Definitions **********************/ - -/* Paragraph 2.2 */ - -/* Core Capability Register Length. Paragraph 2.2.1. 8-bit length. */ - -/* Core Interface Version Number. Paragraph 2.2.2. Two byte BCD encoding */ - -/* Core Structural Parameters. Paragraph 2.2.3 */ - -#define EHCI_HCSPARAMS_NPORTS_SHIFT (0) /* Bit 0-3: Number of physical downstream ports */ -#define EHCI_HCSPARAMS_NPORTS_MASK (15 << EHCI_HCSPARAMS_NPORTS_SHIFT) -#define EHCI_HCSPARAMS_PPC (1 << 4) /* Bit 4: Port Power Control */ - /* Bits 5-6: Reserved */ -#define EHCI_HCSPARAMS_PRR (1 << 7) /* Bit 7: Port Routing Rules */ -#define EHCI_HCSPARAMS_NPCC_SHIFT (8) /* Bit 8-11: Number of Ports per Companion Controller */ -#define EHCI_HCSPARAMS_NPCC_MASK (15 << EHCI_HCSPARAMS_NPCC_SHIFT) -#define EHCI_HCSPARAMS_NCC_SHIFT (12) /* Bit 12-15: Number of Companion Controllers */ -#define EHCI_HCSPARAMS_NCC_MASK (15 << EHCI_HCSPARAMS_NCC_SHIFT) -#define EHCI_HCSPARAMS_PIND (1 << 16) /* Bit 16: Port Indicators */ - /* Bits 17-19: Reserved */ -#define EHCI_HCSPARAMS_DBGPORT_SHIFT (20) /* Bit 20-23: Debug Port Number */ -#define EHCI_HCSPARAMS_DBGPORT_MASK (15 << EHCI_HCSPARAMS_DBGPORT_SHIFT) - /* Bits 24-31: Reserved */ - -/* Core Capability Parameters. Paragraph 2.2.4 */ - -#define EHCI_HCCPARAMS_64BIT (1 << 0) /* Bit 0: 64-bit Addressing Capability */ -#define EHCI_HCCPARAMS_PFLF (1 << 1) /* Bit 1: Programmable Frame List Flag */ -#define EHCI_HCCPARAMS_ASPC (1 << 2) /* Bit 2: Asynchronous Schedule Park Capability */ - /* Bit 3: Reserved */ -#define EHCI_HCCPARAMS_IST_SHIFT (4) /* Bits 4-7: Isochronous Scheduling Threshold */ -#define EHCI_HCCPARAMS_IST_MASK (15 << EHCI_HCCPARAMS_IST_SHIFT) -#define EHCI_HCCPARAMS_EECP_SHIFT (8) /* Bits 8-15: EHCI Extended Capabilities Pointer */ -#define EHCI_HCCPARAMS_EECP_MASK (0xff << EHCI_HCCPARAMS_EECP_SHIFT) - /* Bits 16-31: Reserved */ - -/* Core Companion Port Route Description. - * Paragraph 2.2.5. 15 x 4-bit array (60 bits) - */ - -/* Host Controller Operational Register Bit Definitions *********************/ - -/* Paragraph 2.3 */ - -/* USB Command. Paragraph 2.3.1 */ - -#define EHCI_USBCMD_RUN (1 << 0) /* Bit 0: Run/Stop */ -#define EHCI_USBCMD_HCRESET (1 << 1) /* Bit 1: Host Controller Reset */ -#define EHCI_USBCMD_FLSIZE_SHIFT (2) /* Bits 2-3: Frame List Size */ -#define EHCI_USBCMD_FLSIZE_MASK (3 << EHCI_USBCMD_FLSIZE_SHIFT) -# define EHCI_USBCMD_FLSIZE_1024 (0 << EHCI_USBCMD_FLSIZE_SHIFT) /* 1024 elements (4096 bytes) */ -# define EHCI_USBCMD_FLSIZE_512 (1 << EHCI_USBCMD_FLSIZE_SHIFT) /* 512 elements (2048 bytes) */ -# define EHCI_USBCMD_FLSIZE_256 (2 << EHCI_USBCMD_FLSIZE_SHIFT) /* 256 elements (1024 bytes) */ - -#define EHCI_USBCMD_PSEN (1 << 4) /* Bit 4: Periodic Schedule Enable */ -#define EHCI_USBCMD_ASEN (1 << 5) /* Bit 5: Asynchronous Schedule Enable */ -#define EHCI_USBCMD_IAADB (1 << 6) /* Bit 6: Interrupt on Async Advance Doorbell */ -#define EHCI_USBCMD_LRESET (1 << 7) /* Bit 7: Light Host Controller Reset */ -#define EHCI_USBCMD_PARKCNT_SHIFT (8) /* Bits 8-9: Asynchronous Schedule Park Mode Count */ -#define EHCI_USBCMD_PARKCNT_MASK (3 << EHCI_USBCMD_PARKCNT_SHIFT) - /* Bit 10: Reserved */ -#define EHCI_USBCMD_PARK (1 << 11) /* Bit 11: Asynchronous Schedule Park Mode Enable */ - /* Bits 12-15: Reserved */ -#define EHCI_USBCMD_ITHRE_SHIFT (16) /* Bits 16-23: Interrupt Threshold Control */ -#define EHCI_USBCMD_ITHRE_MASK (0xff << EHCI_USBCMD_ITHRE_SHIFT) -# define EHCI_USBCMD_ITHRE_1MF (0x01 << EHCI_USBCMD_ITHRE_SHIFT) /* 1 micro-frame */ -# define EHCI_USBCMD_ITHRE_2MF (0x02 << EHCI_USBCMD_ITHRE_SHIFT) /* 2 micro-frames */ -# define EHCI_USBCMD_ITHRE_4MF (0x04 << EHCI_USBCMD_ITHRE_SHIFT) /* 4 micro-frames */ -# define EHCI_USBCMD_ITHRE_8MF (0x08 << EHCI_USBCMD_ITHRE_SHIFT) /* 8 micro-frames (default, 1 ms) */ -# define EHCI_USBCMD_ITHRE_16MF (0x10 << EHCI_USBCMD_ITHRE_SHIFT) /* 16 micro-frames (2 ms) */ -# define EHCI_USBCMD_ITHRE_32MF (0x20 << EHCI_USBCMD_ITHRE_SHIFT) /* 32 micro-frames (4 ms) */ -# define EHCI_USBCMD_ITHRE_64MF (0x40 << EHCI_USBCMD_ITHRE_SHIFT) /* 64 micro-frames (8 ms) */ - - /* Bits 24-31: Reserved */ - -/* USB Status. Paragraph 2.3.2 */ - -/* USB Interrupt Enable. Paragraph 2.3.3 */ - -#define EHCI_INT_USBINT (1 << 0) /* Bit 0: USB Interrupt */ -#define EHCI_INT_USBERRINT (1 << 1) /* Bit 1: USB Error Interrupt */ -#define EHCI_INT_PORTSC (1 << 2) /* Bit 2: Port Change Detect */ -#define EHCI_INT_FLROLL (1 << 3) /* Bit 3: Frame List Rollover */ -#define EHCI_INT_SYSERROR (1 << 4) /* Bit 4: Host System Error */ -#define EHCI_INT_AAINT (1 << 5) /* Bit 5: Interrupt on Async Advance */ -#define EHCI_INT_ALLINTS (0x3f) /* Bits 0-5: All interrupts */ - /* Bits 6-11: Reserved */ -#define EHCI_USBSTS_HALTED (1 << 12) /* Bit 12: HC Halted */ -#define EHCI_USBSTS_RECLAM (1 << 13) /* Bit 13: Reclamation */ -#define EHCI_USBSTS_PSS (1 << 14) /* Bit 14: Periodic Schedule Status */ -#define EHCI_USBSTS_ASS (1 << 15) /* Bit 15: Asynchronous Schedule Status */ - /* Bits 16-31: Reserved */ - -/* USB Frame Index. Paragraph 2.3.4 */ - -#define EHCI_FRINDEX_MASK (0x1fff) /* Bits 0-13: Frame index */ - /* Bits 14-31: Reserved */ - -/* 4G Segment Selector. - * Paragraph 2.3.5, Bits[64:32] of data structure addresses - */ - -/* Frame List Base Address. Paragraph 2.3.6 */ - - /* Bits 0-11: Reserved */ -#define EHCI_PERIODICLISTBASE_MASK (0xfffff000) /* Bits 12-31: Base Address (Low) */ - -/* Next Asynchronous List Address. Paragraph 2.3.7 */ - - /* Bits 0-4: Reserved */ -#define EHCI_ASYNCLISTADDR_MASK (0xffffffe0) /* Bits 5-31: Link Pointer Low (LPL) */ - -/* Configured Flag Register. Paragraph 2.3.8 */ - -#define EHCI_CONFIGFLAG (1 << 0) /* Bit 0: Configure Flag */ - /* Bits 1-31: Reserved */ - -/* Port Status/Control, Port 1-n. Paragraph 2.3.9 */ - -#define EHCI_PORTSC_CCS (1 << 0) /* Bit 0: Current Connect Status */ -#define EHCI_PORTSC_CSC (1 << 1) /* Bit 1: Connect Status Change */ -#define EHCI_PORTSC_PE (1 << 2) /* Bit 2: Port Enable */ -#define EHCI_PORTSC_PEC (1 << 3) /* Bit 3: Port Enable/Disable Change */ -#define EHCI_PORTSC_OCA (1 << 4) /* Bit 4: Over-current Active */ -#define EHCI_PORTSC_OCC (1 << 5) /* Bit 5: Over-current Change */ -#define EHCI_PORTSC_RESUME (1 << 6) /* Bit 6: Force Port Resume */ -#define EHCI_PORTSC_SUSPEND (1 << 7) /* Bit 7: Suspend */ -#define EHCI_PORTSC_RESET (1 << 8) /* Bit 8: Port Reset */ - /* Bit 9: Reserved */ -#define EHCI_PORTSC_LSTATUS_SHIFT (10) /* Bits 10-11: Line Status */ -#define EHCI_PORTSC_LSTATUS_MASK (3 << EHCI_PORTSC_LSTATUS_SHIFT) -# define EHCI_PORTSC_LSTATUS_SE0 (0 << EHCI_PORTSC_LSTATUS_SHIFT) /* SE0 Not Low-speed device, perform EHCI reset */ -# define EHCI_PORTSC_LSTATUS_KSTATE (1 << EHCI_PORTSC_LSTATUS_SHIFT) /* K-state Low-speed device, release ownership of port */ -# define EHCI_PORTSC_LSTATUS_JSTATE (2 << EHCI_PORTSC_LSTATUS_SHIFT) /* J-state Not Low-speed device, perform EHCI reset */ - -#define EHCI_PORTSC_PP (1 << 12) /* Bit 12: Port Power */ -#define EHCI_PORTSC_OWNER (1 << 13) /* Bit 13: Port Owner */ -#define EHCI_PORTSC_PIC_SHIFT (14) /* Bits 14-15: Port Indicator Control */ -#define EHCI_PORTSC_PIC_MASK (3 << EHCI_PORTSC_PIC_SHIFT) -# define EHCI_PORTSC_PIC_OFF (0 << EHCI_PORTSC_PIC_SHIFT) /* Port indicators are off */ -# define EHCI_PORTSC_PIC_AMBER (1 << EHCI_PORTSC_PIC_SHIFT) /* Amber */ -# define EHCI_PORTSC_PIC_GREEN (2 << EHCI_PORTSC_PIC_SHIFT) /* Green */ - -#define EHCI_PORTSC_PTC_SHIFT (16) /* Bits 16-19: Port Test Control */ -#define EHCI_PORTSC_PTC_MASK (15 << EHCI_PORTSC_PTC_SHIFT) -# define EHCI_PORTSC_PTC_DISABLED (0 << EHCI_PORTSC_PTC_SHIFT) /* Test mode not enabled */ -# define EHCI_PORTSC_PTC_JSTATE (1 << EHCI_PORTSC_PTC_SHIFT) /* Test J_STATE */ -# define EHCI_PORTSC_PTC_KSTATE (2 << EHCI_PORTSC_PTC_SHIFT) /* Test K_STATE */ -# define EHCI_PORTSC_PTC_SE0NAK (3 << EHCI_PORTSC_PTC_SHIFT) /* Test SE0_NAK */ -# define EHCI_PORTSC_PTC_PACKET (4 << EHCI_PORTSC_PTC_SHIFT) /* Test Packet */ -# define EHCI_PORTSC_PTC_ENABLE (5 << EHCI_PORTSC_PTC_SHIFT) /* Test FORCE_ENABLE */ - -#define EHCI_PORTSC_WKCCNTE (1 << 20) /* Bit 20: Wake on Connect Enable */ -#define EHCI_PORTSC_WKDSCNNTE (1 << 21) /* Bit 21: Wake on Disconnect Enable */ -#define EHCI_PORTSC_WKOCE (1 << 22) /* Bit 22: Wake on Over-current Enable */ - /* Bits 23-31: Reserved */ - -#define EHCI_PORTSC_ALLINTS (EHCI_PORTSC_CSC | EHCI_PORTSC_PEC | \ - EHCI_PORTSC_OCC | EHCI_PORTSC_RESUME) - -/* Debug Register Bit Definitions *******************************************/ - -/* Debug Port Control/Status Register. Paragraph C.3.1 */ - -#define EHCI_DEBUG_PCS_LENGTH_SHIFT (0) /* Bits 0-3: Data Length */ -#define EHCI_DEBUG_PCS_LENGTH_MASK (15 << EHCI_DEBUG_PCS_LENGTH_SHIFT) -#define EHCI_DEBUG_PCS_WRITE (1 << 4) /* Bit 6: Write/Read# */ -#define EHCI_DEBUG_PCS_GO (1 << 5) /* Bit 5: Go */ -#define EHCI_DEBUG_PCS_ERROR (1 << 6) /* Bit 6: Error/Good# */ -#define EHCI_DEBUG_PCS_EXCEPTION_SHIFT (17) /* Bits 7-9: Exception */ -#define EHCI_DEBUG_PCS_EXCEPTION_MASK (7 << EHCI_DEBUG_PCS_EXCEPTION_SHIFT) -#define EHCI_DEBUG_PCS_INUSE (1 << 10) /* Bit 10: In Use */ - /* Bits 11-15: Reserved */ -#define EHCI_DEBUG_PCS_DONE (1 << 16) /* Bit 16: Done */ - /* Bits 17-27: Reserved */ -#define EHCI_DEBUG_PCS_ENABLED (1 << 28) /* Bit 28: Enabled */ - /* Bit 29: Reserved */ -#define EHCI_DEBUG_PCS_OWNER (1 << 30) /* Bit 30: Owner */ - /* Bit 31: Reserved */ - -/* Debug USB PIDs Register. Paragraph C.3.2 */ - -#define EHCI_DEBUG_USBPIDS_TKPID_SHIFT (0) /* Bits 0-7: Token PID */ -#define EHCI_DEBUG_USBPIDS_TKPID_MASK (0xff << EHCI_DEBUG_USBPIDS_TKPID_SHIFT) -#define EHCI_DEBUG_USBPIDS_SPID_SHIFT (8) /* Bits 8-15: Sent PID */ -#define EHCI_DEBUG_USBPIDS_SPID_MASK (0xff << EHCI_DEBUG_USBPIDS_SPID_SHIFT) -#define EHCI_DEBUG_USBPIDS_RPID_SHIFT (16) /* Bits 16-23: Received PID */ -#define EHCI_DEBUG_USBPIDS_RPID_MASK (0xff << EHCI_DEBUG_USBPIDS_RPID_SHIFT) - /* Bits 24-31: Reserved */ - -/* Debug Data Buffer 0/1 Register [64:0]. - * Paragreph C.3.3. 64 bits of data. - */ - -/* Debug Device Address Register. Paragraph C.3.4 */ - -#define EHCI_DEBUG_DEVADDR_ENDPT_SHIFT (0) /* Bit 0-3: USB Endpoint */ -#define EHCI_DEBUG_DEVADDR_ENDPT_MASK (15 << EHCI_DEBUG_DEVADDR_ENDPT_SHIFT) - /* Bits 4-7: Reserved */ -#define EHCI_DEBUG_DEVADDR_ADDR_SHIFT (8) /* Bits 8-14: USB Address */ -#define EHCI_DEBUG_DEVADDR_ADDR_MASK (0x7f << EHCI_DEBUG_DEVADDR_ADDR_SHIFT) - /* Bits 15-31: Reserved */ - -/* Data Structures **********************************************************/ - -/* Paragraph 3 */ - -/* Periodic Frame List. Paragraph 3.1 */ - -#define PFL_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ -#define PFL_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define PFL_TYP_MASK (3 << PFL_TYP_SHIFT) -# define PFL_TYP_ITD (0 << PFL_TYP_SHIFT) /* Isochronous Transfer Descriptor */ -# define PFL_TYP_QH (1 << PFL_TYP_SHIFT) /* Queue Head */ -# define PFL_TYP_SITD (2 << PFL_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ -# define PFL_TYP_FSTN (3 << PFL_TYP_SHIFT) /* Frame Span Traversal Node */ - - /* Bits 3-4: zero */ -#define PFL_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ - -/* Aysnchronous List Queue Head Pointer. - * Paragraph 3.2. Circular list of queue heads - */ - -/* Isochronous (High-Speed) Transfer Descriptor (iTD). Paragraph 3.3 */ - -/* iTD Next Link Pointer. Paragraph 3.3.1 */ - -#define ITD_NLP_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ -#define ITD_NLP_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define ITD_NLP_TYP_MASK (3 << ITD_NLP_TYP_SHIFT) -# define ITD_NLP_TYP_ITD (0 << ITD_NLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ -# define ITD_NLP_TYP_QH (1 << ITD_NLP_TYP_SHIFT) /* Queue Head */ -# define ITD_NLP_TYP_SITD (2 << ITD_NLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ -# define ITD_NLP_TYP_FSTN (3 << ITD_NLP_TYP_SHIFT) /* Frame Span Traversal Node */ - - /* Bits 3-4: zero */ -#define ITD_NLP_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ - -/* iTD Transaction Status and Control List. Paragraph 3.3.2 */ - -#define ITD_TRAN_XOFFS_SHIFT (0) /* Bits 0-11: Transaction X offset */ -#define ITD_TRAN_XOFFS_MASK (0xfff << ITD_TRAN_XOFFS_SHIFT) -#define ITD_TRAN_PG_SHIFT (12) /* Bits 12-14: Page select */ -#define ITD_TRAN_PG_MASK (7 << ITD_TRAN_PG_SHIFT) -#define ITD_TRAN_IOC (1 << 15) /* Bit 15: Interrupt On Comp */ -#define ITD_TRAN_LENGTH_SHIFT (16) /* Bits 16-27: Transaction length */ -#define ITD_TRAN_LENGTH_MASK (0xfff << ITD_TRAN_LENGTH_SHIFT) -#define ITD_TRAN_STATUS_SHIFT (28) /* Bits 28-31: Transaction status */ -#define ITD_TRAN_STATUS_MASK (15 << ITD_TRAN_STATUS_SHIFT) -# define ITD_TRAN_STATUS_XACTERR (1 << 28) /* Bit 28: Transaction error */ -# define ITD_TRAN_STATUS_BABBLE (1 << 29) /* Bit 29: Babble Detected */ -# define ITD_TRAN_STATUS_DBERROR (1 << 30) /* Bit 30: Data Buffer Error */ -# define ITD_TRAN_STATUS_ACTIVE (1 << 31) /* Bit 28: Transaction error */ - -/* iTD Buffer Page Pointer List. Paragraph 3.3.4 */ - -/* iTD Buffer Pointer Page 0. Table 3-4 */ - -#define ITD_BUFPTR0_DEVADDR_SHIFT (0) /* Bits 0-6: Device Address */ -#define ITD_BUFPTR0_DEVADDR_MASK (0x7f << ITD_BUFPTR0_DEVADDR_SHIFT) - /* Bit 7: Reserved */ -#define ITD_BUFPTR0_ENDPT_SHIFT (8) /* Bits 8-11: Endpoint Number */ -#define ITD_BUFPTR0_ENDPT_MASK (15 << ITD_BUFPTR0_ENDPT_SHIFT) - -/* iTD Buffer Pointer Page 1. Table 3-5 */ - -#define ITD_BUFPTR1_MAXPKT_SHIFT (0) /* Bits 0-10: Maximum Packet Size */ -#define ITD_BUFPTR1_MAXPKT_MASK (0x7ff << ITD_BUFPTR1_MAXPKT_SHIFT) -#define ITD_BUFPTR1_DIRIN (1 << 11) /* Bit 11: Direction 1=IN */ -#define ITD_BUFPTR1_DIROUT (0) /* Bit 11: Direction 0=OUT */ - -/* iTD Buffer Pointer Page 2. Table 3-6 */ - -#define ITD_BUFPTR2_MULTI_SHIFT (0) /* Bits 0-1: Multi */ -#define ITD_BUFPTR2_MULTI_MASK (3 << ITD_BUFPTR2_MULTI_SHIFT) -# define ITD_BUFPTR2_MULTI_1 (1 << ITD_BUFPTR2_MULTI_SHIFT) /* One transaction per micro-frame */ -# define ITD_BUFPTR2_MULTI_2 (2 << ITD_BUFPTR2_MULTI_SHIFT) /* Two transactions per micro-frame */ -# define ITD_BUFPTR2_MULTI_3 (3 << ITD_BUFPTR2_MULTI_SHIFT) /* Three transactions per micro-frame */ - - /* Bits 2-11: Reserved */ - -/* iTD Buffer Pointer Page 3-6. Table 3-7 */ - - /* Bits 0-11: Reserved */ - -/* iTD Buffer Pointer All Pages */ - -#define ITD_BUFPTR_MASK (0xfffff000) /* Bits 12-31: Buffer Pointer */ - -/* Split Transaction Isochronous Transfer Descriptor (siTD). - * Paragraph 3.4 - */ - -/* siTD Next Link Pointer. Paragraph 3.4.1 */ - -#define SITD_NLP_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ -#define SITD_NLP_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define SITD_NLP_TYP_MASK (3 << SITD_NLP_TYP_SHIFT) -# define SITD_NLP_TYP_ITD (0 << SITD_NLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ -# define SITD_NLP_TYP_QH (1 << SITD_NLP_TYP_SHIFT) /* Queue Head */ -# define SITD_NLP_TYP_SITD (2 << SITD_NLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ -# define SITD_NLP_TYP_FSTN (3 << SITD_NLP_TYP_SHIFT) /* Frame Span Traversal Node */ - - /* Bits 3-4: zero */ -#define SITD_NLP_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ - -/* siTD Endpoint Capabilities/Characteristics. - * Paragraph 3.4.2 - */ - -/* Endpoint and Transaction Translator Characteristics. Table 3-9 */ - -#define SITD_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */ -#define SITD_EPCHAR_DEVADDR_MASK (0x7f << SITD_EPCHAR_DEVADDR_SHIFT) - /* Bits 7: Reserved */ -#define SITD_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */ -#define SITD_EPCHAR_ENDPT_MASK (15 << SITD_EPCHAR_ENDPT_SHIFT) - /* Bits 12-15: Reserved */ -#define SITD_EPCHAR_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */ -#define SITD_EPCHAR_HUBADDR_MASK (0x7f << SITD_EPCHAR_HUBADDR_SHIFT) - /* Bit 23: Reserved */ -#define SITD_EPCHAR_DIRIN (1 << 31) /* Bit 31: Direction 1=IN */ -#define SITD_EPCHAR_DIROUT (0) /* Bit 31: Direction 0=OUT */ - -/* Micro-frame Schedule Control. Table 3-10 */ - -#define SITD_FMSCHED_SSMASK_SHIFT (0) /* Bitx 0-7: Split Start Mask (�Frame S-mask) */ -#define SITD_FMSCHED_SSMASK_MASK (0xff << SITD_FMSCHED_SSMASK_SHIFT) -# define SITD_FMSCHED_SSMASK(n) ((n) << SITD_FMSCHED_SSMASK_SHIFT) -#define SITD_FMSCHED_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (�Frame C-Mask) */ -#define SITD_FMSCHED_SCMASK_MASK (0xff << SITD_FMSCHED_SCMASK_SHIFT) -# define SITD_FMSCHED_SCMASK(n) ((n) << SITD_FMSCHED_SCMASK_SHIFT) - /* Bits 16-31: Reserved */ - -/* siTD Transfer State. Paragraph 3.4.3 */ - -#define SITD_XFRSTATE_STATUS_SHIFT (0) /* Bits 0-7: Status */ -#define SITD_XFRSTATE_STATUS_MASK (0xff << SITD_XFRSTATE_STATUS_SHIFT) -#define SITD_XFRSTATE_CPROGMASK_SHIFT (8) /* Bits 8-15: �Frame Complete-split Progress Mask */ -#define SITD_XFRSTATE_CPROGMASK_MASK (0xff << SITD_XFRSTATE_CPROGMASK_SHIFT) -#define SITD_XFRSTATE_NBYTES_SHIFT (16) /* Bits 16-25: Total Bytes To Transfer */ -#define SITD_XFRSTATE_NBYTES_MASK (0x3ff << SITD_XFRSTATE_NBYTES_SHIFT) - /* Bits 26-29: Reserved */ -#define SITD_XFRSTATE_P (1 << 30) /* Bit 30: Page Select */ -#define SITD_XFRSTATE_IOC (1 << 31) /* Bit 31: Interrupt On Complete */ - -/* siTD Buffer Pointer List. - * Paragraph 3.4.4 - */ - -/* Page 0 */ - -#define SITD_BUFPTR0_OFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ -#define SITD_BUFPTR0_OFFSET_MASK (0xff << SITD_BUFPTR0_OFFSET_SHIFT) - -/* Page 1 */ - -#define SITD_BUFPTR1_TCOUNT_SHIFT (0) /* Bits 0-2: Transaction count */ -#define SITD_BUFPTR1_TCOUNT_MASK (7 << SITD_BUFPTR1_TCOUNT_SHIFT) -#define SITD_BUFPTR1_TP_SHIFT (33) /* Bits 3-4: Transaction position */ -#define SITD_BUFPTR1_TP_MASK (3 << SITD_BUFPTR1_TP_SHIFT) -# define SITD_BUFPTR1_TP_ENTIRE (0 << SITD_BUFPTR1_TP_SHIFT) /* Entire full-speed transaction data payload. */ -# define SITD_BUFPTR1_TP_BEGIN (1 << SITD_BUFPTR1_TP_SHIFT) /* This is the first data payload */ -# define SITD_BUFPTR1_TP_MID (2 << SITD_BUFPTR1_TP_SHIFT) /* This the middle payload */ -# define SITD_BUFPTR1_TP_END (3 << SITD_BUFPTR1_TP_SHIFT) /* This is the last payload */ - - /* Bits 5-11: Reserved */ - -/* All pages */ - -#define SITD_BUFPTR_MASK (0xfffff000) /* Bits 12-31: Buffer Pointer List */ - -/* Queue Element Transfer Descriptor (qTD). - * Paragraph 3.5 - */ - -/* Next qTD Pointer. - * Paragraph 3.5.1 - */ - -#define QTD_NQP_T (1 << 0) /* Bit 0: Terminate */ - /* Bits 1-4: Reserved */ -#define QTD_NQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ -#define QTD_NQP_NTEP_MASK (0xffffffe0) - -/* Alternate Next qTD Pointer. - * Paragraph 3.5.2 - */ - -#define QTD_AQP_T (1 << 0) /* Bit 0: Terminate */ - /* Bits 1-4: Reserved */ -#define QTD_AQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ -#define QTD_AQP_NTEP_MASK (0xffffffe0) - -/* qTD Token. - * Paragraph 3.5.3 - */ - -#define QTD_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */ -#define QTD_TOKEN_STATUS_MASK (0xff << QTD_TOKEN_STATUS_SHIFT) -# define QTD_TOKEN_P (1 << 0) /* Bit 0 Ping State */ -# define QTD_TOKEN_ERR (1 << 0) /* Bit 0 Error */ -# define QTD_TOKEN_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */ -# define QTD_TOKEN_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */ -# define QTD_TOKEN_XACTERR (1 << 3) /* Bit 3 Transaction Error */ -# define QTD_TOKEN_BABBLE (1 << 4) /* Bit 4 Babble Detected */ -# define QTD_TOKEN_DBERR (1 << 5) /* Bit 5 Data Buffer Error */ -# define QTD_TOKEN_HALTED (1 << 6) /* Bit 6 Halted */ -# define QTD_TOKEN_ACTIVE (1 << 7) /* Bit 7 Active */ -# define QTD_TOKEN_ERRORS (0x78 << QTD_TOKEN_STATUS_SHIFT) -#define QTD_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */ -#define QTD_TOKEN_PID_MASK (3 << QTD_TOKEN_PID_SHIFT) -# define QTD_TOKEN_PID_OUT (0 << QTD_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */ -# define QTD_TOKEN_PID_IN (1 << QTD_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */ -# define QTD_TOKEN_PID_SETUP (2 << QTD_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */ - -#define QTD_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */ -#define QTD_TOKEN_CERR_MASK (3 << QTD_TOKEN_CERR_SHIFT) -#define QTD_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */ -#define QTD_TOKEN_CPAGE_MASK (7 << QTD_TOKEN_CPAGE_SHIFT) -#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */ -#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */ -#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT) -#define QTD_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */ -#define QTD_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */ - -/* qTD Buffer Page Pointer List. - * Paragraph 3.5.4 - */ - -/* Page 0 */ - -#define QTD_BUFPTR0_OFFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ -#define QTD_BUFPTR0_OFFFSET_MASK (0xfff << QTD_BUFPTR0_OFFFSET_SHIFT) - -/* Other pages */ - - /* Bits 0-11: Reserved */ - -/* All pages */ - -#define QTD_BUFPTR_SHIFT (12) /* Bits 12-31: Buffer Pointer List */ -#define QTD_BUFPTR_MASK (0xfffff000) - -/* Queue Head. Paragraph 3.6 */ - -/* Queue Head Horizontal Link Pointer. - * Paragraph 3.6.1 - */ - -#define QH_HLP_T (1 << 0) /* Bit 0: Terminate, QH HL pointer invalid */ -#define QH_HLP_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define QH_HLP_TYP_MASK (3 << QH_HLP_TYP_SHIFT) -# define QH_HLP_TYP_ITD (0 << QH_HLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ -# define QH_HLP_TYP_QH (1 << QH_HLP_TYP_SHIFT) /* Queue Head */ -# define QH_HLP_TYP_SITD (2 << QH_HLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ -# define QH_HLP_TYP_FSTN (3 << QH_HLP_TYP_SHIFT) /* Frame Span Traversal Node */ - - /* Bits 3-4: Reserved */ -#define QH_HLP_MASK (0xffffffe0) /* Bits 5-31: Queue Head Horizontal Link Pointer */ - -/* Endpoint Capabilities/Characteristics. Paragraph 3.6.2 */ - -/* Endpoint Characteristics: Queue Head DWord. Table 3-19 */ - -#define QH_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */ -#define QH_EPCHAR_DEVADDR_MASK (0x7f << QH_EPCHAR_DEVADDR_SHIFT) -#define QH_EPCHAR_I (1 << 7) /* Bit 7: Inactivate on Next Transaction */ -#define QH_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */ -#define QH_EPCHAR_ENDPT_MASK (15 << QH_EPCHAR_ENDPT_SHIFT) -#define QH_EPCHAR_EPS_SHIFT (12) /* Bitx 12-13: Endpoint Speed */ -#define QH_EPCHAR_EPS_MASK (3 << QH_EPCHAR_EPS_SHIFT) -# define QH_EPCHAR_EPS_FULL (0 << QH_EPCHAR_EPS_SHIFT) /* Full-Speed (12Mbs) */ -# define QH_EPCHAR_EPS_LOW (1 << QH_EPCHAR_EPS_SHIFT) /* Low-Speed (1.5Mbs) */ -# define QH_EPCHAR_EPS_HIGH (2 << QH_EPCHAR_EPS_SHIFT) /* High-Speed (480 Mb/s) */ - -#define QH_EPCHAR_DTC (1 << 14) /* Bit 14: Data Toggle Control */ -#define QH_EPCHAR_H (1 << 15) /* Bit 15: Head of Reclamation List Flag */ -#define QH_EPCHAR_MAXPKT_SHIFT (16) /* Bitx 16-26: Maximum Packet Length */ -#define QH_EPCHAR_MAXPKT_MASK (0x7ff << QH_EPCHAR_MAXPKT_SHIFT) -#define QH_EPCHAR_C (1 << 27) /* Bit 27: Control Endpoint Flag */ -#define QH_EPCHAR_RL_SHIFT (28) /* Bitx 28-31: Nak Count Reload */ -#define QH_EPCHAR_RL_MASK (15 << QH_EPCHAR_RL_SHIFT) - -/* Endpoint Capabilities: Queue Head DWord 2. Table 3-20 */ - -#define QH_EPCAPS_SSMASK_SHIFT (0) /* Bitx 0-7: Interrupt Schedule Mask (�Frame S-mask) */ -#define QH_EPCAPS_SSMASK_MASK (0xff << QH_EPCAPS_SSMASK_SHIFT) -# define QH_EPCAPS_SSMASK(n) ((n) << QH_EPCAPS_SSMASK_SHIFT) -#define QH_EPCAPS_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (�Frame C-Mask) */ -#define QH_EPCAPS_SCMASK_MASK (0xff << QH_EPCAPS_SCMASK_SHIFT) -# define QH_EPCAPS_SCMASK(n) ((n) << QH_EPCAPS_SCMASK_SHIFT) -#define QH_EPCAPS_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */ -#define QH_EPCAPS_HUBADDR_MASK (0x7f << QH_EPCAPS_HUBADDR_SHIFT) -# define QH_EPCAPS_HUBADDR(n) ((n) << QH_EPCAPS_HUBADDR_SHIFT) -#define QH_EPCAPS_PORT_SHIFT (23) /* Bit 23-29: Port Number */ -#define QH_EPCAPS_PORT_MASK (0x7f << QH_EPCAPS_PORT_SHIFT) -# define QH_EPCAPS_PORT(n) ((n) << QH_EPCAPS_PORT_SHIFT) -#define QH_EPCAPS_MULT_SHIFT (30) /* Bit 30-31: High-Bandwidth Pipe Multiplier */ -#define QH_EPCAPS_MULT_MASK (3 << QH_EPCAPS_MULT_SHIFT) -# define QH_EPCAPS_MULT(n) ((n) << QH_EPCAPS_MULT_SHIFT) - -/* Current qTD Link Pointer. Table 3-21 */ - -#define QH_CQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ -#define QH_CQP_NTEP_MASK (0xffffffe0) - -/* Transfer Overlay. Paragraph 3.6.3 - * - * NOTES: - * 1. Same as the field of the same name in struct ehci_qtd_s - * 2. Similar to the field of the same name in struct ehci_qtd_s, but with - * some additional bitfields. - */ - -/* Next qTD Pointer (NOTE 1) */ - -#define QH_NQP_T (1 << 0) /* Bit 0: Terminate */ - /* Bits 1-4: Reserved */ -#define QH_NQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ -#define QH_NQP_NTEP_MASK (0xffffffe0) - -/* Alternate Next qTD Pointer. Table 3.7 (NOTE 2) */ - -#define QH_AQP_T (1 << 0) /* Bit 0: Terminate */ -#define QH_AQP_NAKCNT (1) /* Bits 1-4: Nak Counter */ -#define QH_AQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ -#define QH_AQP_NTEP_MASK (0xffffffe0) - -/* qTD Token (NOTE 1) */ - -#define QH_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */ -#define QH_TOKEN_STATUS_MASK (0xff << QH_TOKEN_STATUS_SHIFT) -# define QH_TOKEN_P (1 << 0) /* Bit 0 Ping State */ -# define QH_TOKEN_ERR (1 << 0) /* Bit 0 Error */ -# define QH_TOKEN_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */ -# define QH_TOKEN_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */ -# define QH_TOKEN_XACTERR (1 << 3) /* Bit 3 Transaction Error */ -# define QH_TOKEN_BABBLE (1 << 4) /* Bit 4 Babble Detected */ -# define QH_TOKEN_DBERR (1 << 5) /* Bit 5 Data Buffer Error */ -# define QH_TOKEN_HALTED (1 << 6) /* Bit 6 Halted */ -# define QH_TOKEN_ACTIVE (1 << 7) /* Bit 7 Active */ -# define QH_TOKEN_ERRORS (0x78 << QH_TOKEN_STATUS_SHIFT) -#define QH_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */ -#define QH_TOKEN_PID_MASK (3 << QH_TOKEN_PID_SHIFT) -# define QH_TOKEN_PID_OUT (0 << QH_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */ -# define QH_TOKEN_PID_IN (1 << QH_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */ -# define QH_TOKEN_PID_SETUP (2 << QH_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */ - -#define QH_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */ -#define QH_TOKEN_CERR_MASK (3 << QH_TOKEN_CERR_SHIFT) -#define QH_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */ -#define QH_TOKEN_CPAGE_MASK (7 << QH_TOKEN_CPAGE_SHIFT) -#define QH_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */ -#define QH_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */ -#define QH_TOKEN_NBYTES_MASK (0x7fff << QH_TOKEN_NBYTES_SHIFT) -#define QH_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */ -#define QH_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */ - -/* Buffer Page Pointer List (NOTE 2) */ - -/* Page 0 */ - -#define QH_BUFPTR0_OFFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ -#define QH_BUFPTR0_OFFFSET_MASK (0xfff << QH_BUFPTR0_OFFFSET_SHIFT) - -/* Page 1. Table 3.22 */ - -#define QH_BUFPTR1_CPROGMASK_SHIFT (0) /* Bits 0-7: Split-transaction Complete-split Progress */ -#define QH_BUFPTR1_CPROGMASK_MASK (0xff << QH_BUFPTR1_CPROGMASK_SHIFT) - /* Bits 8-11: Reserved */ - -/* Page 2. Table 3.22 */ - -#define QH_BUFPTR2_FRAMETAG_SHIFT (0) /* Bits 0-4: Split-transaction Frame Tag */ -#define QH_BUFPTR2_FRAMETAG_MASK (31 << QH_BUFPTR2_FRAMETAG_SHIFT) -#define QH_BUFPTR2_SBYTES_SHIFT (5) /* Bits 5-11: S-bytes */ -#define QH_BUFPTR2_SBYTES_MASK (0x7f << QH_BUFPTR2_SBYTES_SHIFT) - -/* Other pages */ - - /* Bits 0-11: Reserved */ - -/* All pages */ - -#define QH_BUFPTR_SHIFT (12) /* Bits 12-31: Buffer Pointer List */ -#define QH_BUFPTR_MASK (0xfffff000) - -/* Periodic Frame Span Traversal Node (STN). Paragrap 3.7 */ - -/* FSTN Normal Path Pointer. Paragraph 3.7.1 */ - -#define FSTN_NPP_T (1 << 0) /* Bit 0: Terminate. 1=Link Pointer not valid */ -#define FSTN_NPP_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define FSTN_NPP_TYP_MASK (3 << FSTN_NPP_TYP_SHIFT) -# define FSTN_NPP_TYP_ITD (0 << FSTN_NPP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ -# define FSTN_NPP_TYP_QH (1 << FSTN_NPP_TYP_SHIFT) /* Queue Head */ -# define FSTN_NPP_TYP_SITD (2 << FSTN_NPP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ -# define FSTN_NPP_TYP_FSTN (3 << FSTN_NPP_TYP_SHIFT) /* Frame Span Traversal Node */ - - /* Bits 3-4: Reserved */ -#define FSTN_NPP_NPLP_SHIFT (5) /* Bits 5-31: Normal Path Link Pointer */ -#define FSTN_NPP_NPLP_MASK (0xffffffe0) - -/* FSTN Back Path Link Pointer. Paragraph 3.7.2 */ - -#define FSTN_BPP_T (1 << 0) /* Bit 0: Terminate. 1=Link Pointer not valid */ -#define FSTN_BPP_TYP_SHIFT (1) /* Bits 1-2: Type */ -#define FSTN_BPP_TYP_MASK (3 << FSTN_BPP_TYP_SHIFT) -# define FSTN_BPP_TYP_QH (1 << FSTN_BPP_TYP_SHIFT) /* Queue Head */ - - /* Bits 3-4: Reserved */ -#define FSTN_BPP_BPLP_SHIFT (5) /* Bits 5-31: Back Path Link Pointer */ -#define FSTN_BPP_BPLP_MASK (0xffffffe0) - -/**************************************************************************** - * Public Types - ****************************************************************************/ - -/* Registers ****************************************************************/ - -/* Since the operational registers are not known a compile time, representing - * register blocks with structures is more convenient than using individual - * register offsets. - */ - -/* Host Controller Capability Registers. - * This register block must be positioned at a well known address. - */ - -struct ehci_hccr_s -{ - uint8_t caplength; /* 0x00: Capability Register Length */ - uint8_t reserved; - uint16_t hciversion; /* 0x02: Interface Version Number */ - uint32_t hcsparams; /* 0x04: Structural Parameters */ - uint32_t hccparams; /* 0x08: Capability Parameters */ - uint8_t hcspportrt[8]; /* 0x0c: Companion Port Route Description */ -}; - -/* Host Controller Operational Registers. - * This register block is positioned at an offset of 'caplength' from the - * beginning of the Host Controller Capability Registers. - */ - -struct ehci_hcor_s -{ - uint32_t usbcmd; /* 0x00: USB Command */ - uint32_t usbsts; /* 0x04: USB Status */ - uint32_t usbintr; /* 0x08: USB Interrupt Enable */ - uint32_t frindex; /* 0x0c: USB Frame Index */ - uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */ - uint32_t periodiclistbase; /* 0x14: Frame List Base Address */ - uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */ -#ifndef CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE - uint32_t reserved[9]; -#endif - uint32_t configflag; /* 0x40: Configured Flag Register */ - uint32_t portsc[15]; /* 0x44: Port Status/Control */ -}; - -/* USB2 Debug Port Register Interface. - * This register block is normally found via the PCI capabalities. - * In non-PCI implementions, you need apriori information about the - * location of these registers. - */ - -struct ehci_debug_s -{ - uint32_t psc; /* 0x00: Debug Port Control/Status Register */ - uint32_t pids; /* 0x04: Debug USB PIDs Register */ - uint32_t data[2]; /* 0x08: Debug Data buffer Registers */ - uint32_t addr; /* 0x10: Device Address Register */ -}; - -/* Data Structures **********************************************************/ - -/* Paragraph 3 */ - -/* Periodic Frame List. - * Paragraph 3.1. An array of pointers. - */ - -/* Aysnchronous List Queue Head Pointer. - * Paragraph 3.2. Circular list of queue heads - */ - -/* Isochronous (High-Speed) Transfer Descriptor (iTD). - * Paragraph 3.3. Must be aligned to 32-byte boundaries. - */ - -struct ehci_itd_s -{ - uint32_t nlp; /* 0x00-0x03: Next link pointer */ - uint32_t trans[8]; /* 0x04-0x23: Transaction Status and Control List */ - uint32_t bpl[7]; /* 0x24-0x3c: Buffer Page Pointer List */ -}; - -#define SIZEOF_EHCI_ITD_S (64) /* 16*sizeof(uint32_t) */ - -/* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */ - -struct ehci_sitd_s -{ - uint32_t nlp; /* 0x00-0x03: Next link pointer */ - uint32_t epchar; /* 0x04-0x07: Endpoint and Transaction Translator Characteristics */ - uint32_t fmsched; /* 0x08-0x0b: Micro-frame Schedule Control */ - uint32_t xfrstate; /* 0x0c-0x0f: Transfer Status and Control */ - uint32_t bpl[2]; /* 0x10-0x17: Buffer Pointer List */ - uint32_t blp; /* 0x18-0x1b: Back link pointer */ -}; - -#define SIZEOF_EHCI_SITD_S (28) /* 7*sizeof(uint32_t) */ - -/* Queue Element Transfer Descriptor (qTD). Paragraph 3.5 */ - -/* 32-bit version. See EHCI Appendix B for the 64-bit version. */ - -struct ehci_qtd_s -{ - uint32_t nqp; /* 0x00-0x03: Next qTD Pointer */ - uint32_t alt; /* 0x04-0x07: Alternate Next qTD Pointer */ - uint32_t token; /* 0x08-0x0b: qTD Token */ - uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List */ -}; - -#define SIZEOF_EHCI_QTD_S (32) /* 8*sizeof(uint32_t) */ - -/* Queue Head. Paragraph 3.6 - * - * NOTE: - * 1. Same as the field of the same name in struct ehci_qtd_s - * 2. Similar to the field of the same name in struct ehci_qtd_s, - * but with some additional bitfields. - */ - -struct ehci_overlay_s -{ - uint32_t nqp; /* 0x00-0x03: Next qTD Pointer (NOTE 1) */ - uint32_t alt; /* 0x04-0x07: Alternate Next qTD Pointer (NOTE 2) */ - uint32_t token; /* 0x08-0x0b: qTD Token (NOTE 1) */ - uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List (NOTE 2) */ -}; - -#define SIZEOF_EHCI_OVERLAY (32) /* 8*sizeof(uint32_t) */ - -struct ehci_qh_s -{ - uint32_t hlp; /* 0x00-0x03: Queue Head Horizontal Link Pointer */ - uint32_t epchar; /* 0x04-0x07: Endpoint Characteristics */ - uint32_t epcaps; /* 0x08-0x0b: Endpoint Capabilities */ - uint32_t cqp; /* 0x0c-0x0f: Current qTD Pointer */ - struct ehci_overlay_s overlay; /* 0x10-0x2c: Transfer overlay */ -}; - -#define SIZEOF_EHCI_QH (48) /* 4*sizeof(uint32_t) + SIZEOF_EHCI_OVERLAY */ - -/* Periodic Frame Span Traversal Node (STN). Paragrap 3.7 */ - -struct ehci_fstn_s -{ - uint32_t npp; /* 0x00-0x03: Normal Path Pointer */ - uint32_t bpp; /* 0x04-0x07: Back Path Link Pointer */ -}; - -#define SIZEOF_EHCI_FSTN_S (8) /* 2*sizeof(uint32_t) */ - -/**************************************************************************** - * Public Data - ****************************************************************************/ - -#ifdef __cplusplus -#define EXTERN extern "C" -extern "C" -{ -#else -#define EXTERN extern -#endif - -/**************************************************************************** - * Public Function Prototypes - ****************************************************************************/ - -#undef EXTERN -#ifdef __cplusplus -} -#endif -#endif /* __INCLUDE_NUTTX_USB_EHCI_H */ diff --git a/port/ehci/usb_hc_ehci.h b/port/ehci/usb_hc_ehci.h new file mode 100644 index 00000000..c2c37b93 --- /dev/null +++ b/port/ehci/usb_hc_ehci.h @@ -0,0 +1,1008 @@ +/**************************************************************************** + * include/nuttx/usb/ehci.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_USB_EHCI_H +#define __INCLUDE_NUTTX_USB_EHCI_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* General definitions ******************************************************/ + +/* Endpoint speed values as used in endpoint characteristics field. + * NOTE: These values are *NOT* the same as the SPEED definitions in usb.h. + */ + +#define EHCI_FULL_SPEED (0) /* Full-Speed (12Mbs) */ +#define EHCI_LOW_SPEED (1) /* Low-Speed (1.5Mbs) */ +#define EHCI_HIGH_SPEED (2) /* High-Speed (480 Mb/s) */ + +#define EHCI_DIR_IN (1) /* Direction IN: Peripheral to host */ +#define EHCI_DIR_OUT (0) /* Direction OUT: Host to peripheral */ + +/* PCI Configuration Space Register Offsets *********************************/ + +/* Paragraph 2.1 */ + +/* 0x0009-0x000b: Class Code */ + +#define EHCI_PCI_CLASSC_OFFSET 0x0009 + +/* 0x0010-0x0013: Base Address to Memory-mapped Host Controller Register + * Space + */ + +#define EHCI_PCIUSBBASE_OFFSET 0x0010 + +/* 0x0060: Serial Bus Release Number */ + +#define EHCI_PCI_SBRN_OFFSET 0x0060 + +/* 0x0061: Frame Length Adjustment Register */ + +#define EHCI_PCI_FLADJ_OFFSET 0x0061 + +/* 0x0062-0x0063: Port wake capabilities register (OPTIONAL) */ + +#define EHCI_PCI_PORTWAKECAP_OFFSET 0x0062 + +/* EECP+0x0000: USB Legacy Support EHCI Extended Capability Register */ + +#define EHCI_PCI_USBLEGSUP_OFFSET 0x0000 + +/* EECP+0x0000: USB Legacy Support Control and Status Register */ + +#define EHCI_PCI_USBLEGCTLSTS_OFFSET 0x0004 + +/* Host Controller Capability Register Offsets ******************************/ + +/* Paragraph 2.2 */ + +#define EHCI_CAPLENGTH_OFFSET 0x0000 /* Core Capability Register Length */ + /* 0x0001 Reserved */ +#define EHCI_HCIVERSION_OFFSET 0x0002 /* Core Interface Version Number */ +#define EHCI_HCSPARAMS_OFFSET 0x0004 /* Core Structural Parameters */ +#define EHCI_HCCPARAMS_OFFSET 0x0008 /* Core Capability Parameters */ +#define EHCI_HCSP_PORTROUTE_OFFSET 0x000c /* Core Companion Port Route Description */ + +/* Host Controller Operational Register Offsets *****************************/ + +/* Paragraph 2.3 */ + +#define EHCI_USBCMD_OFFSET 0x0000 /* USB Command */ +#define EHCI_USBSTS_OFFSET 0x0004 /* USB Status */ +#define EHCI_USBINTR_OFFSET 0x0008 /* USB Interrupt Enable */ +#define EHCI_FRINDEX_OFFSET 0x000c /* USB Frame Index */ +#define EHCI_CTRLDSSEGMENT_OFFSET 0x0010 /* 4G Segment Selector */ +#define EHCI_PERIODICLISTBASE_OFFSET 0x0014 /* Frame List Base Address */ +#define EHCI_ASYNCLISTADDR_OFFSET 0x0018 /* Next Asynchronous List Address */ + /* 0x001c-0x003f: Reserved */ +#define EHCI_CONFIGFLAG_OFFSET 0x0040 /* Configured Flag Register */ + +/* Port Status/Control, Port 1-n */ + +#define EHCI_PORTSC_OFFSET(n) (0x0044 + ((n-1) << 2)) +#define EHCI_PORTSC1_OFFSET 0x0044 /* Port Status/Control, Port 1 */ +#define EHCI_PORTSC2_OFFSET 0x0048 /* Port Status/Control, Port 2 */ +#define EHCI_PORTSC3_OFFSET 0x004c /* Port Status/Control, Port 3 */ +#define EHCI_PORTSC4_OFFSET 0x0050 /* Port Status/Control, Port 4 */ +#define EHCI_PORTSC5_OFFSET 0x0054 /* Port Status/Control, Port 5 */ +#define EHCI_PORTSC6_OFFSET 0x0058 /* Port Status/Control, Port 6 */ +#define EHCI_PORTSC7_OFFSET 0x005c /* Port Status/Control, Port 7 */ +#define EHCI_PORTSC8_OFFSET 0x0060 /* Port Status/Control, Port 8 */ +#define EHCI_PORTSC9_OFFSET 0x0064 /* Port Status/Control, Port 9 */ +#define EHCI_PORTSC10_OFFSET 0x0068 /* Port Status/Control, Port 10 */ +#define EHCI_PORTSC11_OFFSET 0x006c /* Port Status/Control, Port 11 */ +#define EHCI_PORTSC12_OFFSET 0x0070 /* Port Status/Control, Port 12 */ +#define EHCI_PORTSC13_OFFSET 0x0074 /* Port Status/Control, Port 13 */ +#define EHCI_PORTSC14_OFFSET 0x0078 /* Port Status/Control, Port 14 */ +#define EHCI_PORTSC15_OFFSET 0x007c /* Port Status/Control, Port 15 */ + +/* Debug Register Offsets ***************************************************/ + +/* Paragraph C.3 */ + +#define EHCI_DEBUG_PCS_OFFSET 0x0000 /* Debug Port Control/Status Register */ +#define EHCI_DEBUG_USBPIDS_OFFSET 0x0004 /* Debug USB PIDs Register */ +#define EHCI_DEBUG_DATA0_OFFSET 0x0008 /* Debug Data Buffer 0 Register [31:0] */ +#define EHCI_DEBUG_DATA1_OFFSET 0x000c /* Debug Data Buffer 1 Register [63:32] */ +#define EHCI_DEBUG_DEVADDR_OFFSET 0x0010 /* Debug Device Address Register */ + +/* PCI Configuration Space Register Bit Definitions *************************/ + +/* 0x0009-0x000b: Class Code. Paragraph 2.1.2 */ + +#define EHCI_PCI_PI_SHIFT (0) /* Bits 0-7: Programming Interface */ +#define EHCI_PCI_PI_MASK (0xff << EHCI_PCI_PI_SHIFT) +# define EHCI_PCI_PI (0x20 << EHCI_PCI_PI_SHIFT) +#define EHCI_PCI_SCC_SHIFT (8) /* Bits 8-15: Sub-Class Code */ +#define EHCI_PCI_SCC_MASK (0xff << EHCI_PCI_SCC_SHIFT) +# define EHCI_PCI_SCC (0x03 << EHCI_PCI_SCC_SHIFT) +#define EHCI_PCI_BASEC_SHIFT (16) /* Base Class Code */ +#define EHCI_PCI_BASEC_MASK (0xff << EHCI_PCI_BASEC_SHIFT) +# define EHCI_PCI_BASEC (0x0c << EHCI_PCI_BASEC_SHIFT) +#define EHCI_PCI_CLASSC 0x000c0320 /* Default value (little endian) */ + +/* 0x0010-0x0013: Base Address to Memory-mapped Host Controller Register + * Space. Paragraph 2.1.3 + */ + + /* Bit 0: Reserved */ + +#define EHCI_PCIUSBBASE_TYPE_SHIFT (0) /* Bits 1-2: Type */ +#define EHCI_PCIUSBBASE_TYPE_MASK (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) +# define EHCI_PCIUSBBASE_TYPE_32BIT (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) /* 32-bit addressing */ +# define EHCI_PCIUSBBASE_TYPE_64BIT (3 << EHCI_PCIUSBBASE_TYPE_SHIFT) /* 64-bit addressing */ + + /* Bits 3-7: Reserved */ +#define EHCI_PCIUSBBASE_BASE_SHIFT (8) /* Bits 8-31: Base address */ +#define EHCI_PCIUSBBASE_BASE_MASK (0xffffff00) + +/* 0x0060: Serial Bus Release Number. Paragraph 2.1.4 */ + +#define EHCI_PCI_SBRN_MASK 0xff /* Bits 0-7: Serial Bus Release Number */ + +/* 0x0061: Frame Length Adjustment Register. Paragraph 2.1.5 */ + +#define EHCI_PCI_FLADJ_SHIFT (0) /* Bit 0-5: Frame Length Timing Value */ +#define EHCI_PCI_FLADJ_MASK (0x3f >> EHCI_PCI_FLADJ_SHIFT) + /* Bits 6-7: Reserved */ + +/* 0x0062-0x0063: Port wake capabilities register (OPTIONAL). + * Paragraph 2.1.6 + */ + +#define EHCI_PCI_PORTWAKECAP_MASK (0xffff) + +/* EECP+0x0000: USB Legacy Support EHCI Extended Capability Register. + * Paragraph 2.1.7 + */ + +#define EHCI_PCI_USBLEGSUP_CAPID_SHIFT (0) /* Bits 0-7 Capability ID */ +#define EHCI_PCI_USBLEGSUP_CAPID_MASK (0xff << EHCI_PCI_USBLEGSUP_CAPID_SHIFT) +#define EHCI_PCI_USBLEGSUP_NEECP_SHIFT (8) /* Bits 8-15: Next EHCI Extended Capability Pointer */ +#define EHCI_PCI_USBLEGSUP_NEECP_MASK (0xff << EHCI_PCI_USBLEGSUP_NEECP_SHIFT) +#define EHCI_PCI_USBLEGSUP_BOWN (1 << 16) /* Bit 16: HC BIOS Owned Semaphore */ + /* Bits 17-23: Reserved */ +#define EHCI_PCI_USBLEGSUP_OSOWN (1 << 24) /* Bit 24: HC OS Owned Semaphore */ + /* Bits 25-31: Reserved */ + +/* EECP+0x0000: USB Legacy Support Control and Status Register. + * Paragraph 2.1.8 + */ + +#define EHCI_PCI_USBLEGCTLSTS_USBCMPEN (1 << 0) /* Bit 0: USB SMI Enable */ +#define EHCI_PCI_USBLEGCTLSTS_USBERREN (1 << 1) /* Bit 1: SMI on USB Error Enable */ +#define EHCI_PCI_USBLEGCTLSTS_PCHEN (1 << 2) /* Bit 2: SMI on Port Change Enable */ +#define EHCI_PCI_USBLEGCTLSTS_FLREN (1 << 3) /* Bit 3: SMI on Frame List Rollover Enable */ +#define EHCI_PCI_USBLEGCTLSTS_HSEEN (1 << 4) /* Bit 4: SMI on Host System Error Enable */ +#define EHCI_PCI_USBLEGCTLSTS_AAEN (1 << 5) /* Bit 5: SMI on Async Advance Enable */ + /* Bits 6-12: Reserved */ +#define EHCI_PCI_USBLEGCTLSTS_OOEN (1 << 13) /* Bit 13: SMI on OS Ownership Enable */ +#define EHCI_PCI_USBLEGCTLSTS_PCEN (1 << 14) /* Bit 14: SMI on PCI Command Enable */ +#define EHCI_PCI_USBLEGCTLSTS_BAREN (1 << 15) /* Bit 15: SMI on BAR Enable */ +#define EHCI_PCI_USBLEGCTLSTS_USBCMP (1 << 16) /* Bit 16: SMI on USB Complete */ +#define EHCI_PCI_USBLEGCTLSTS_USBERR (1 << 17) /* Bit 17: SMI on USB Error */ +#define EHCI_PCI_USBLEGCTLSTS_PCH (1 << 18) /* Bit 18: SMI on Port Change Detect */ +#define EHCI_PCI_USBLEGCTLSTS_FLR (1 << 19) /* Bit 19: SMI on Frame List Rollover */ +#define EHCI_PCI_USBLEGCTLSTS_HSE (1 << 20) /* Bit 20: SMI on Host System Error */ +#define EHCI_PCI_USBLEGCTLSTS_AA (1 << 21) /* Bit 21: SMI on Async Advance */ + /* Bits 22-28: Reserved */ +#define EHCI_PCI_USBLEGCTLSTS_OO (1 << 29) /* Bit 29: SMI on OS Ownership Change */ +#define EHCI_PCI_USBLEGCTLSTS_PC (1 << 30) /* Bit 30: SMI on PCI Command */ +#define EHCI_PCI_USBLEGCTLSTS_BAR (1 << 31) /* Bit 31: SMI on BAR */ + +/* Host Controller Capability Register Bit Definitions **********************/ + +/* Paragraph 2.2 */ + +/* Core Capability Register Length. Paragraph 2.2.1. 8-bit length. */ + +/* Core Interface Version Number. Paragraph 2.2.2. Two byte BCD encoding */ + +/* Core Structural Parameters. Paragraph 2.2.3 */ + +#define EHCI_HCSPARAMS_NPORTS_SHIFT (0) /* Bit 0-3: Number of physical downstream ports */ +#define EHCI_HCSPARAMS_NPORTS_MASK (15 << EHCI_HCSPARAMS_NPORTS_SHIFT) +#define EHCI_HCSPARAMS_PPC (1 << 4) /* Bit 4: Port Power Control */ + /* Bits 5-6: Reserved */ +#define EHCI_HCSPARAMS_PRR (1 << 7) /* Bit 7: Port Routing Rules */ +#define EHCI_HCSPARAMS_NPCC_SHIFT (8) /* Bit 8-11: Number of Ports per Companion Controller */ +#define EHCI_HCSPARAMS_NPCC_MASK (15 << EHCI_HCSPARAMS_NPCC_SHIFT) +#define EHCI_HCSPARAMS_NCC_SHIFT (12) /* Bit 12-15: Number of Companion Controllers */ +#define EHCI_HCSPARAMS_NCC_MASK (15 << EHCI_HCSPARAMS_NCC_SHIFT) +#define EHCI_HCSPARAMS_PIND (1 << 16) /* Bit 16: Port Indicators */ + /* Bits 17-19: Reserved */ +#define EHCI_HCSPARAMS_DBGPORT_SHIFT (20) /* Bit 20-23: Debug Port Number */ +#define EHCI_HCSPARAMS_DBGPORT_MASK (15 << EHCI_HCSPARAMS_DBGPORT_SHIFT) + /* Bits 24-31: Reserved */ + +/* Core Capability Parameters. Paragraph 2.2.4 */ + +#define EHCI_HCCPARAMS_64BIT (1 << 0) /* Bit 0: 64-bit Addressing Capability */ +#define EHCI_HCCPARAMS_PFLF (1 << 1) /* Bit 1: Programmable Frame List Flag */ +#define EHCI_HCCPARAMS_ASPC (1 << 2) /* Bit 2: Asynchronous Schedule Park Capability */ + /* Bit 3: Reserved */ +#define EHCI_HCCPARAMS_IST_SHIFT (4) /* Bits 4-7: Isochronous Scheduling Threshold */ +#define EHCI_HCCPARAMS_IST_MASK (15 << EHCI_HCCPARAMS_IST_SHIFT) +#define EHCI_HCCPARAMS_EECP_SHIFT (8) /* Bits 8-15: EHCI Extended Capabilities Pointer */ +#define EHCI_HCCPARAMS_EECP_MASK (0xff << EHCI_HCCPARAMS_EECP_SHIFT) + /* Bits 16-31: Reserved */ + +/* Core Companion Port Route Description. + * Paragraph 2.2.5. 15 x 4-bit array (60 bits) + */ + +/* Host Controller Operational Register Bit Definitions *********************/ + +/* Paragraph 2.3 */ + +/* USB Command. Paragraph 2.3.1 */ + +#define EHCI_USBCMD_RUN (1 << 0) /* Bit 0: Run/Stop */ +#define EHCI_USBCMD_HCRESET (1 << 1) /* Bit 1: Host Controller Reset */ +#define EHCI_USBCMD_FLSIZE_SHIFT (2) /* Bits 2-3: Frame List Size */ +#define EHCI_USBCMD_FLSIZE_MASK (3 << EHCI_USBCMD_FLSIZE_SHIFT) +# define EHCI_USBCMD_FLSIZE_1024 (0 << EHCI_USBCMD_FLSIZE_SHIFT) /* 1024 elements (4096 bytes) */ +# define EHCI_USBCMD_FLSIZE_512 (1 << EHCI_USBCMD_FLSIZE_SHIFT) /* 512 elements (2048 bytes) */ +# define EHCI_USBCMD_FLSIZE_256 (2 << EHCI_USBCMD_FLSIZE_SHIFT) /* 256 elements (1024 bytes) */ + +#define EHCI_USBCMD_PSEN (1 << 4) /* Bit 4: Periodic Schedule Enable */ +#define EHCI_USBCMD_ASEN (1 << 5) /* Bit 5: Asynchronous Schedule Enable */ +#define EHCI_USBCMD_IAADB (1 << 6) /* Bit 6: Interrupt on Async Advance Doorbell */ +#define EHCI_USBCMD_LRESET (1 << 7) /* Bit 7: Light Host Controller Reset */ +#define EHCI_USBCMD_PARKCNT_SHIFT (8) /* Bits 8-9: Asynchronous Schedule Park Mode Count */ +#define EHCI_USBCMD_PARKCNT_MASK (3 << EHCI_USBCMD_PARKCNT_SHIFT) + /* Bit 10: Reserved */ +#define EHCI_USBCMD_PARK (1 << 11) /* Bit 11: Asynchronous Schedule Park Mode Enable */ + /* Bits 12-15: Reserved */ +#define EHCI_USBCMD_ITHRE_SHIFT (16) /* Bits 16-23: Interrupt Threshold Control */ +#define EHCI_USBCMD_ITHRE_MASK (0xff << EHCI_USBCMD_ITHRE_SHIFT) +# define EHCI_USBCMD_ITHRE_1MF (0x01 << EHCI_USBCMD_ITHRE_SHIFT) /* 1 micro-frame */ +# define EHCI_USBCMD_ITHRE_2MF (0x02 << EHCI_USBCMD_ITHRE_SHIFT) /* 2 micro-frames */ +# define EHCI_USBCMD_ITHRE_4MF (0x04 << EHCI_USBCMD_ITHRE_SHIFT) /* 4 micro-frames */ +# define EHCI_USBCMD_ITHRE_8MF (0x08 << EHCI_USBCMD_ITHRE_SHIFT) /* 8 micro-frames (default, 1 ms) */ +# define EHCI_USBCMD_ITHRE_16MF (0x10 << EHCI_USBCMD_ITHRE_SHIFT) /* 16 micro-frames (2 ms) */ +# define EHCI_USBCMD_ITHRE_32MF (0x20 << EHCI_USBCMD_ITHRE_SHIFT) /* 32 micro-frames (4 ms) */ +# define EHCI_USBCMD_ITHRE_64MF (0x40 << EHCI_USBCMD_ITHRE_SHIFT) /* 64 micro-frames (8 ms) */ + + /* Bits 24-31: Reserved */ + +/* USB Status. Paragraph 2.3.2 */ + +/* USB Interrupt Enable. Paragraph 2.3.3 */ + +#define EHCI_INT_USBINT (1 << 0) /* Bit 0: USB Interrupt */ +#define EHCI_INT_USBERRINT (1 << 1) /* Bit 1: USB Error Interrupt */ +#define EHCI_INT_PORTSC (1 << 2) /* Bit 2: Port Change Detect */ +#define EHCI_INT_FLROLL (1 << 3) /* Bit 3: Frame List Rollover */ +#define EHCI_INT_SYSERROR (1 << 4) /* Bit 4: Host System Error */ +#define EHCI_INT_AAINT (1 << 5) /* Bit 5: Interrupt on Async Advance */ +#define EHCI_INT_ALLINTS (0x3f) /* Bits 0-5: All interrupts */ + /* Bits 6-11: Reserved */ +#define EHCI_USBSTS_HALTED (1 << 12) /* Bit 12: HC Halted */ +#define EHCI_USBSTS_RECLAM (1 << 13) /* Bit 13: Reclamation */ +#define EHCI_USBSTS_PSS (1 << 14) /* Bit 14: Periodic Schedule Status */ +#define EHCI_USBSTS_ASS (1 << 15) /* Bit 15: Asynchronous Schedule Status */ + /* Bits 16-31: Reserved */ + +/* USB Frame Index. Paragraph 2.3.4 */ + +#define EHCI_FRINDEX_MASK (0x1fff) /* Bits 0-13: Frame index */ + /* Bits 14-31: Reserved */ + +/* 4G Segment Selector. + * Paragraph 2.3.5, Bits[64:32] of data structure addresses + */ + +/* Frame List Base Address. Paragraph 2.3.6 */ + + /* Bits 0-11: Reserved */ +#define EHCI_PERIODICLISTBASE_MASK (0xfffff000) /* Bits 12-31: Base Address (Low) */ + +/* Next Asynchronous List Address. Paragraph 2.3.7 */ + + /* Bits 0-4: Reserved */ +#define EHCI_ASYNCLISTADDR_MASK (0xffffffe0) /* Bits 5-31: Link Pointer Low (LPL) */ + +/* Configured Flag Register. Paragraph 2.3.8 */ + +#define EHCI_CONFIGFLAG (1 << 0) /* Bit 0: Configure Flag */ + /* Bits 1-31: Reserved */ + +/* Port Status/Control, Port 1-n. Paragraph 2.3.9 */ + +#define EHCI_PORTSC_CCS (1 << 0) /* Bit 0: Current Connect Status */ +#define EHCI_PORTSC_CSC (1 << 1) /* Bit 1: Connect Status Change */ +#define EHCI_PORTSC_PE (1 << 2) /* Bit 2: Port Enable */ +#define EHCI_PORTSC_PEC (1 << 3) /* Bit 3: Port Enable/Disable Change */ +#define EHCI_PORTSC_OCA (1 << 4) /* Bit 4: Over-current Active */ +#define EHCI_PORTSC_OCC (1 << 5) /* Bit 5: Over-current Change */ +#define EHCI_PORTSC_RESUME (1 << 6) /* Bit 6: Force Port Resume */ +#define EHCI_PORTSC_SUSPEND (1 << 7) /* Bit 7: Suspend */ +#define EHCI_PORTSC_RESET (1 << 8) /* Bit 8: Port Reset */ + /* Bit 9: Reserved */ +#define EHCI_PORTSC_LSTATUS_SHIFT (10) /* Bits 10-11: Line Status */ +#define EHCI_PORTSC_LSTATUS_MASK (3 << EHCI_PORTSC_LSTATUS_SHIFT) +# define EHCI_PORTSC_LSTATUS_SE0 (0 << EHCI_PORTSC_LSTATUS_SHIFT) /* SE0 Not Low-speed device, perform EHCI reset */ +# define EHCI_PORTSC_LSTATUS_KSTATE (1 << EHCI_PORTSC_LSTATUS_SHIFT) /* K-state Low-speed device, release ownership of port */ +# define EHCI_PORTSC_LSTATUS_JSTATE (2 << EHCI_PORTSC_LSTATUS_SHIFT) /* J-state Not Low-speed device, perform EHCI reset */ + +#define EHCI_PORTSC_PP (1 << 12) /* Bit 12: Port Power */ +#define EHCI_PORTSC_OWNER (1 << 13) /* Bit 13: Port Owner */ +#define EHCI_PORTSC_PIC_SHIFT (14) /* Bits 14-15: Port Indicator Control */ +#define EHCI_PORTSC_PIC_MASK (3 << EHCI_PORTSC_PIC_SHIFT) +# define EHCI_PORTSC_PIC_OFF (0 << EHCI_PORTSC_PIC_SHIFT) /* Port indicators are off */ +# define EHCI_PORTSC_PIC_AMBER (1 << EHCI_PORTSC_PIC_SHIFT) /* Amber */ +# define EHCI_PORTSC_PIC_GREEN (2 << EHCI_PORTSC_PIC_SHIFT) /* Green */ + +#define EHCI_PORTSC_PTC_SHIFT (16) /* Bits 16-19: Port Test Control */ +#define EHCI_PORTSC_PTC_MASK (15 << EHCI_PORTSC_PTC_SHIFT) +# define EHCI_PORTSC_PTC_DISABLED (0 << EHCI_PORTSC_PTC_SHIFT) /* Test mode not enabled */ +# define EHCI_PORTSC_PTC_JSTATE (1 << EHCI_PORTSC_PTC_SHIFT) /* Test J_STATE */ +# define EHCI_PORTSC_PTC_KSTATE (2 << EHCI_PORTSC_PTC_SHIFT) /* Test K_STATE */ +# define EHCI_PORTSC_PTC_SE0NAK (3 << EHCI_PORTSC_PTC_SHIFT) /* Test SE0_NAK */ +# define EHCI_PORTSC_PTC_PACKET (4 << EHCI_PORTSC_PTC_SHIFT) /* Test Packet */ +# define EHCI_PORTSC_PTC_ENABLE (5 << EHCI_PORTSC_PTC_SHIFT) /* Test FORCE_ENABLE */ + +#define EHCI_PORTSC_WKCCNTE (1 << 20) /* Bit 20: Wake on Connect Enable */ +#define EHCI_PORTSC_WKDSCNNTE (1 << 21) /* Bit 21: Wake on Disconnect Enable */ +#define EHCI_PORTSC_WKOCE (1 << 22) /* Bit 22: Wake on Over-current Enable */ + /* Bits 23-31: Reserved */ + +#define EHCI_PORTSC_ALLINTS (EHCI_PORTSC_CSC | EHCI_PORTSC_PEC | \ + EHCI_PORTSC_OCC | EHCI_PORTSC_RESUME) + +/* Debug Register Bit Definitions *******************************************/ + +/* Debug Port Control/Status Register. Paragraph C.3.1 */ + +#define EHCI_DEBUG_PCS_LENGTH_SHIFT (0) /* Bits 0-3: Data Length */ +#define EHCI_DEBUG_PCS_LENGTH_MASK (15 << EHCI_DEBUG_PCS_LENGTH_SHIFT) +#define EHCI_DEBUG_PCS_WRITE (1 << 4) /* Bit 6: Write/Read# */ +#define EHCI_DEBUG_PCS_GO (1 << 5) /* Bit 5: Go */ +#define EHCI_DEBUG_PCS_ERROR (1 << 6) /* Bit 6: Error/Good# */ +#define EHCI_DEBUG_PCS_EXCEPTION_SHIFT (17) /* Bits 7-9: Exception */ +#define EHCI_DEBUG_PCS_EXCEPTION_MASK (7 << EHCI_DEBUG_PCS_EXCEPTION_SHIFT) +#define EHCI_DEBUG_PCS_INUSE (1 << 10) /* Bit 10: In Use */ + /* Bits 11-15: Reserved */ +#define EHCI_DEBUG_PCS_DONE (1 << 16) /* Bit 16: Done */ + /* Bits 17-27: Reserved */ +#define EHCI_DEBUG_PCS_ENABLED (1 << 28) /* Bit 28: Enabled */ + /* Bit 29: Reserved */ +#define EHCI_DEBUG_PCS_OWNER (1 << 30) /* Bit 30: Owner */ + /* Bit 31: Reserved */ + +/* Debug USB PIDs Register. Paragraph C.3.2 */ + +#define EHCI_DEBUG_USBPIDS_TKPID_SHIFT (0) /* Bits 0-7: Token PID */ +#define EHCI_DEBUG_USBPIDS_TKPID_MASK (0xff << EHCI_DEBUG_USBPIDS_TKPID_SHIFT) +#define EHCI_DEBUG_USBPIDS_SPID_SHIFT (8) /* Bits 8-15: Sent PID */ +#define EHCI_DEBUG_USBPIDS_SPID_MASK (0xff << EHCI_DEBUG_USBPIDS_SPID_SHIFT) +#define EHCI_DEBUG_USBPIDS_RPID_SHIFT (16) /* Bits 16-23: Received PID */ +#define EHCI_DEBUG_USBPIDS_RPID_MASK (0xff << EHCI_DEBUG_USBPIDS_RPID_SHIFT) + /* Bits 24-31: Reserved */ + +/* Debug Data Buffer 0/1 Register [64:0]. + * Paragreph C.3.3. 64 bits of data. + */ + +/* Debug Device Address Register. Paragraph C.3.4 */ + +#define EHCI_DEBUG_DEVADDR_ENDPT_SHIFT (0) /* Bit 0-3: USB Endpoint */ +#define EHCI_DEBUG_DEVADDR_ENDPT_MASK (15 << EHCI_DEBUG_DEVADDR_ENDPT_SHIFT) + /* Bits 4-7: Reserved */ +#define EHCI_DEBUG_DEVADDR_ADDR_SHIFT (8) /* Bits 8-14: USB Address */ +#define EHCI_DEBUG_DEVADDR_ADDR_MASK (0x7f << EHCI_DEBUG_DEVADDR_ADDR_SHIFT) + /* Bits 15-31: Reserved */ + +/* Data Structures **********************************************************/ + +/* Paragraph 3 */ + +/* Periodic Frame List. Paragraph 3.1 */ + +#define PFL_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ +#define PFL_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define PFL_TYP_MASK (3 << PFL_TYP_SHIFT) +# define PFL_TYP_ITD (0 << PFL_TYP_SHIFT) /* Isochronous Transfer Descriptor */ +# define PFL_TYP_QH (1 << PFL_TYP_SHIFT) /* Queue Head */ +# define PFL_TYP_SITD (2 << PFL_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ +# define PFL_TYP_FSTN (3 << PFL_TYP_SHIFT) /* Frame Span Traversal Node */ + + /* Bits 3-4: zero */ +#define PFL_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ + +/* Aysnchronous List Queue Head Pointer. + * Paragraph 3.2. Circular list of queue heads + */ + +/* Isochronous (High-Speed) Transfer Descriptor (iTD). Paragraph 3.3 */ + +/* iTD Next Link Pointer. Paragraph 3.3.1 */ + +#define ITD_NLP_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ +#define ITD_NLP_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define ITD_NLP_TYP_MASK (3 << ITD_NLP_TYP_SHIFT) +# define ITD_NLP_TYP_ITD (0 << ITD_NLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ +# define ITD_NLP_TYP_QH (1 << ITD_NLP_TYP_SHIFT) /* Queue Head */ +# define ITD_NLP_TYP_SITD (2 << ITD_NLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ +# define ITD_NLP_TYP_FSTN (3 << ITD_NLP_TYP_SHIFT) /* Frame Span Traversal Node */ + + /* Bits 3-4: zero */ +#define ITD_NLP_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ + +/* iTD Transaction Status and Control List. Paragraph 3.3.2 */ + +#define ITD_TRAN_XOFFS_SHIFT (0) /* Bits 0-11: Transaction X offset */ +#define ITD_TRAN_XOFFS_MASK (0xfff << ITD_TRAN_XOFFS_SHIFT) +#define ITD_TRAN_PG_SHIFT (12) /* Bits 12-14: Page select */ +#define ITD_TRAN_PG_MASK (7 << ITD_TRAN_PG_SHIFT) +#define ITD_TRAN_IOC (1 << 15) /* Bit 15: Interrupt On Comp */ +#define ITD_TRAN_LENGTH_SHIFT (16) /* Bits 16-27: Transaction length */ +#define ITD_TRAN_LENGTH_MASK (0xfff << ITD_TRAN_LENGTH_SHIFT) +#define ITD_TRAN_STATUS_SHIFT (28) /* Bits 28-31: Transaction status */ +#define ITD_TRAN_STATUS_MASK (15 << ITD_TRAN_STATUS_SHIFT) +# define ITD_TRAN_STATUS_XACTERR (1 << 28) /* Bit 28: Transaction error */ +# define ITD_TRAN_STATUS_BABBLE (1 << 29) /* Bit 29: Babble Detected */ +# define ITD_TRAN_STATUS_DBERROR (1 << 30) /* Bit 30: Data Buffer Error */ +# define ITD_TRAN_STATUS_ACTIVE (1 << 31) /* Bit 28: Transaction error */ + +/* iTD Buffer Page Pointer List. Paragraph 3.3.4 */ + +/* iTD Buffer Pointer Page 0. Table 3-4 */ + +#define ITD_BUFPTR0_DEVADDR_SHIFT (0) /* Bits 0-6: Device Address */ +#define ITD_BUFPTR0_DEVADDR_MASK (0x7f << ITD_BUFPTR0_DEVADDR_SHIFT) + /* Bit 7: Reserved */ +#define ITD_BUFPTR0_ENDPT_SHIFT (8) /* Bits 8-11: Endpoint Number */ +#define ITD_BUFPTR0_ENDPT_MASK (15 << ITD_BUFPTR0_ENDPT_SHIFT) + +/* iTD Buffer Pointer Page 1. Table 3-5 */ + +#define ITD_BUFPTR1_MAXPKT_SHIFT (0) /* Bits 0-10: Maximum Packet Size */ +#define ITD_BUFPTR1_MAXPKT_MASK (0x7ff << ITD_BUFPTR1_MAXPKT_SHIFT) +#define ITD_BUFPTR1_DIRIN (1 << 11) /* Bit 11: Direction 1=IN */ +#define ITD_BUFPTR1_DIROUT (0) /* Bit 11: Direction 0=OUT */ + +/* iTD Buffer Pointer Page 2. Table 3-6 */ + +#define ITD_BUFPTR2_MULTI_SHIFT (0) /* Bits 0-1: Multi */ +#define ITD_BUFPTR2_MULTI_MASK (3 << ITD_BUFPTR2_MULTI_SHIFT) +# define ITD_BUFPTR2_MULTI_1 (1 << ITD_BUFPTR2_MULTI_SHIFT) /* One transaction per micro-frame */ +# define ITD_BUFPTR2_MULTI_2 (2 << ITD_BUFPTR2_MULTI_SHIFT) /* Two transactions per micro-frame */ +# define ITD_BUFPTR2_MULTI_3 (3 << ITD_BUFPTR2_MULTI_SHIFT) /* Three transactions per micro-frame */ + + /* Bits 2-11: Reserved */ + +/* iTD Buffer Pointer Page 3-6. Table 3-7 */ + + /* Bits 0-11: Reserved */ + +/* iTD Buffer Pointer All Pages */ + +#define ITD_BUFPTR_MASK (0xfffff000) /* Bits 12-31: Buffer Pointer */ + +/* Split Transaction Isochronous Transfer Descriptor (siTD). + * Paragraph 3.4 + */ + +/* siTD Next Link Pointer. Paragraph 3.4.1 */ + +#define SITD_NLP_T (1 << 0) /* Bit 0: Terminate, Link pointer invalid */ +#define SITD_NLP_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define SITD_NLP_TYP_MASK (3 << SITD_NLP_TYP_SHIFT) +# define SITD_NLP_TYP_ITD (0 << SITD_NLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ +# define SITD_NLP_TYP_QH (1 << SITD_NLP_TYP_SHIFT) /* Queue Head */ +# define SITD_NLP_TYP_SITD (2 << SITD_NLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ +# define SITD_NLP_TYP_FSTN (3 << SITD_NLP_TYP_SHIFT) /* Frame Span Traversal Node */ + + /* Bits 3-4: zero */ +#define SITD_NLP_MASK (0xffffffe0) /* Bits 5-31: Frame List Link Pointer */ + +/* siTD Endpoint Capabilities/Characteristics. + * Paragraph 3.4.2 + */ + +/* Endpoint and Transaction Translator Characteristics. Table 3-9 */ + +#define SITD_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */ +#define SITD_EPCHAR_DEVADDR_MASK (0x7f << SITD_EPCHAR_DEVADDR_SHIFT) + /* Bits 7: Reserved */ +#define SITD_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */ +#define SITD_EPCHAR_ENDPT_MASK (15 << SITD_EPCHAR_ENDPT_SHIFT) + /* Bits 12-15: Reserved */ +#define SITD_EPCHAR_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */ +#define SITD_EPCHAR_HUBADDR_MASK (0x7f << SITD_EPCHAR_HUBADDR_SHIFT) + /* Bit 23: Reserved */ +#define SITD_EPCHAR_DIRIN (1 << 31) /* Bit 31: Direction 1=IN */ +#define SITD_EPCHAR_DIROUT (0) /* Bit 31: Direction 0=OUT */ + +/* Micro-frame Schedule Control. Table 3-10 */ + +#define SITD_FMSCHED_SSMASK_SHIFT (0) /* Bitx 0-7: Split Start Mask (�Frame S-mask) */ +#define SITD_FMSCHED_SSMASK_MASK (0xff << SITD_FMSCHED_SSMASK_SHIFT) +# define SITD_FMSCHED_SSMASK(n) ((n) << SITD_FMSCHED_SSMASK_SHIFT) +#define SITD_FMSCHED_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (�Frame C-Mask) */ +#define SITD_FMSCHED_SCMASK_MASK (0xff << SITD_FMSCHED_SCMASK_SHIFT) +# define SITD_FMSCHED_SCMASK(n) ((n) << SITD_FMSCHED_SCMASK_SHIFT) + /* Bits 16-31: Reserved */ + +/* siTD Transfer State. Paragraph 3.4.3 */ + +#define SITD_XFRSTATE_STATUS_SHIFT (0) /* Bits 0-7: Status */ +#define SITD_XFRSTATE_STATUS_MASK (0xff << SITD_XFRSTATE_STATUS_SHIFT) +#define SITD_XFRSTATE_CPROGMASK_SHIFT (8) /* Bits 8-15: �Frame Complete-split Progress Mask */ +#define SITD_XFRSTATE_CPROGMASK_MASK (0xff << SITD_XFRSTATE_CPROGMASK_SHIFT) +#define SITD_XFRSTATE_NBYTES_SHIFT (16) /* Bits 16-25: Total Bytes To Transfer */ +#define SITD_XFRSTATE_NBYTES_MASK (0x3ff << SITD_XFRSTATE_NBYTES_SHIFT) + /* Bits 26-29: Reserved */ +#define SITD_XFRSTATE_P (1 << 30) /* Bit 30: Page Select */ +#define SITD_XFRSTATE_IOC (1 << 31) /* Bit 31: Interrupt On Complete */ + +/* siTD Buffer Pointer List. + * Paragraph 3.4.4 + */ + +/* Page 0 */ + +#define SITD_BUFPTR0_OFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ +#define SITD_BUFPTR0_OFFSET_MASK (0xff << SITD_BUFPTR0_OFFSET_SHIFT) + +/* Page 1 */ + +#define SITD_BUFPTR1_TCOUNT_SHIFT (0) /* Bits 0-2: Transaction count */ +#define SITD_BUFPTR1_TCOUNT_MASK (7 << SITD_BUFPTR1_TCOUNT_SHIFT) +#define SITD_BUFPTR1_TP_SHIFT (33) /* Bits 3-4: Transaction position */ +#define SITD_BUFPTR1_TP_MASK (3 << SITD_BUFPTR1_TP_SHIFT) +# define SITD_BUFPTR1_TP_ENTIRE (0 << SITD_BUFPTR1_TP_SHIFT) /* Entire full-speed transaction data payload. */ +# define SITD_BUFPTR1_TP_BEGIN (1 << SITD_BUFPTR1_TP_SHIFT) /* This is the first data payload */ +# define SITD_BUFPTR1_TP_MID (2 << SITD_BUFPTR1_TP_SHIFT) /* This the middle payload */ +# define SITD_BUFPTR1_TP_END (3 << SITD_BUFPTR1_TP_SHIFT) /* This is the last payload */ + + /* Bits 5-11: Reserved */ + +/* All pages */ + +#define SITD_BUFPTR_MASK (0xfffff000) /* Bits 12-31: Buffer Pointer List */ + +/* Queue Element Transfer Descriptor (qTD). + * Paragraph 3.5 + */ + +/* Next qTD Pointer. + * Paragraph 3.5.1 + */ + +#define QTD_NQP_T (1 << 0) /* Bit 0: Terminate */ + /* Bits 1-4: Reserved */ +#define QTD_NQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ +#define QTD_NQP_NTEP_MASK (0xffffffe0) + +/* Alternate Next qTD Pointer. + * Paragraph 3.5.2 + */ + +#define QTD_AQP_T (1 << 0) /* Bit 0: Terminate */ + /* Bits 1-4: Reserved */ +#define QTD_AQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ +#define QTD_AQP_NTEP_MASK (0xffffffe0) + +/* qTD Token. + * Paragraph 3.5.3 + */ + +#define QTD_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */ +#define QTD_TOKEN_STATUS_MASK (0xff << QTD_TOKEN_STATUS_SHIFT) +# define QTD_TOKEN_P (1 << 0) /* Bit 0 Ping State */ +# define QTD_TOKEN_ERR (1 << 0) /* Bit 0 Error */ +# define QTD_TOKEN_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */ +# define QTD_TOKEN_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */ +# define QTD_TOKEN_XACTERR (1 << 3) /* Bit 3 Transaction Error */ +# define QTD_TOKEN_BABBLE (1 << 4) /* Bit 4 Babble Detected */ +# define QTD_TOKEN_DBERR (1 << 5) /* Bit 5 Data Buffer Error */ +# define QTD_TOKEN_HALTED (1 << 6) /* Bit 6 Halted */ +# define QTD_TOKEN_ACTIVE (1 << 7) /* Bit 7 Active */ +# define QTD_TOKEN_ERRORS (0x78 << QTD_TOKEN_STATUS_SHIFT) +#define QTD_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */ +#define QTD_TOKEN_PID_MASK (3 << QTD_TOKEN_PID_SHIFT) +# define QTD_TOKEN_PID_OUT (0 << QTD_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */ +# define QTD_TOKEN_PID_IN (1 << QTD_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */ +# define QTD_TOKEN_PID_SETUP (2 << QTD_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */ + +#define QTD_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */ +#define QTD_TOKEN_CERR_MASK (3 << QTD_TOKEN_CERR_SHIFT) +#define QTD_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */ +#define QTD_TOKEN_CPAGE_MASK (7 << QTD_TOKEN_CPAGE_SHIFT) +#define QTD_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */ +#define QTD_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */ +#define QTD_TOKEN_NBYTES_MASK (0x7fff << QTD_TOKEN_NBYTES_SHIFT) +#define QTD_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */ +#define QTD_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */ + +/* qTD Buffer Page Pointer List. + * Paragraph 3.5.4 + */ + +/* Page 0 */ + +#define QTD_BUFPTR0_OFFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ +#define QTD_BUFPTR0_OFFFSET_MASK (0xfff << QTD_BUFPTR0_OFFFSET_SHIFT) + +/* Other pages */ + + /* Bits 0-11: Reserved */ + +/* All pages */ + +#define QTD_BUFPTR_SHIFT (12) /* Bits 12-31: Buffer Pointer List */ +#define QTD_BUFPTR_MASK (0xfffff000) + +/* Queue Head. Paragraph 3.6 */ + +/* Queue Head Horizontal Link Pointer. + * Paragraph 3.6.1 + */ + +#define QH_HLP_T (1 << 0) /* Bit 0: Terminate, QH HL pointer invalid */ +#define QH_HLP_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define QH_HLP_TYP_MASK (3 << QH_HLP_TYP_SHIFT) +# define QH_HLP_TYP_ITD (0 << QH_HLP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ +# define QH_HLP_TYP_QH (1 << QH_HLP_TYP_SHIFT) /* Queue Head */ +# define QH_HLP_TYP_SITD (2 << QH_HLP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ +# define QH_HLP_TYP_FSTN (3 << QH_HLP_TYP_SHIFT) /* Frame Span Traversal Node */ + + /* Bits 3-4: Reserved */ +#define QH_HLP_MASK (0xffffffe0) /* Bits 5-31: Queue Head Horizontal Link Pointer */ + +/* Endpoint Capabilities/Characteristics. Paragraph 3.6.2 */ + +/* Endpoint Characteristics: Queue Head DWord. Table 3-19 */ + +#define QH_EPCHAR_DEVADDR_SHIFT (0) /* Bitx 0-6: Device Address */ +#define QH_EPCHAR_DEVADDR_MASK (0x7f << QH_EPCHAR_DEVADDR_SHIFT) +#define QH_EPCHAR_I (1 << 7) /* Bit 7: Inactivate on Next Transaction */ +#define QH_EPCHAR_ENDPT_SHIFT (8) /* Bitx 8-11: Endpoint Number */ +#define QH_EPCHAR_ENDPT_MASK (15 << QH_EPCHAR_ENDPT_SHIFT) +#define QH_EPCHAR_EPS_SHIFT (12) /* Bitx 12-13: Endpoint Speed */ +#define QH_EPCHAR_EPS_MASK (3 << QH_EPCHAR_EPS_SHIFT) +# define QH_EPCHAR_EPS_FULL (0 << QH_EPCHAR_EPS_SHIFT) /* Full-Speed (12Mbs) */ +# define QH_EPCHAR_EPS_LOW (1 << QH_EPCHAR_EPS_SHIFT) /* Low-Speed (1.5Mbs) */ +# define QH_EPCHAR_EPS_HIGH (2 << QH_EPCHAR_EPS_SHIFT) /* High-Speed (480 Mb/s) */ + +#define QH_EPCHAR_DTC (1 << 14) /* Bit 14: Data Toggle Control */ +#define QH_EPCHAR_H (1 << 15) /* Bit 15: Head of Reclamation List Flag */ +#define QH_EPCHAR_MAXPKT_SHIFT (16) /* Bitx 16-26: Maximum Packet Length */ +#define QH_EPCHAR_MAXPKT_MASK (0x7ff << QH_EPCHAR_MAXPKT_SHIFT) +#define QH_EPCHAR_C (1 << 27) /* Bit 27: Control Endpoint Flag */ +#define QH_EPCHAR_RL_SHIFT (28) /* Bitx 28-31: Nak Count Reload */ +#define QH_EPCHAR_RL_MASK (15 << QH_EPCHAR_RL_SHIFT) + +/* Endpoint Capabilities: Queue Head DWord 2. Table 3-20 */ + +#define QH_EPCAPS_SSMASK_SHIFT (0) /* Bitx 0-7: Interrupt Schedule Mask (�Frame S-mask) */ +#define QH_EPCAPS_SSMASK_MASK (0xff << QH_EPCAPS_SSMASK_SHIFT) +# define QH_EPCAPS_SSMASK(n) ((n) << QH_EPCAPS_SSMASK_SHIFT) +#define QH_EPCAPS_SCMASK_SHIFT (8) /* Bitx 8-15: Split Completion Mask (�Frame C-Mask) */ +#define QH_EPCAPS_SCMASK_MASK (0xff << QH_EPCAPS_SCMASK_SHIFT) +# define QH_EPCAPS_SCMASK(n) ((n) << QH_EPCAPS_SCMASK_SHIFT) +#define QH_EPCAPS_HUBADDR_SHIFT (16) /* Bitx 16-22: Hub Address */ +#define QH_EPCAPS_HUBADDR_MASK (0x7f << QH_EPCAPS_HUBADDR_SHIFT) +# define QH_EPCAPS_HUBADDR(n) ((n) << QH_EPCAPS_HUBADDR_SHIFT) +#define QH_EPCAPS_PORT_SHIFT (23) /* Bit 23-29: Port Number */ +#define QH_EPCAPS_PORT_MASK (0x7f << QH_EPCAPS_PORT_SHIFT) +# define QH_EPCAPS_PORT(n) ((n) << QH_EPCAPS_PORT_SHIFT) +#define QH_EPCAPS_MULT_SHIFT (30) /* Bit 30-31: High-Bandwidth Pipe Multiplier */ +#define QH_EPCAPS_MULT_MASK (3 << QH_EPCAPS_MULT_SHIFT) +# define QH_EPCAPS_MULT(n) ((n) << QH_EPCAPS_MULT_SHIFT) + +/* Current qTD Link Pointer. Table 3-21 */ + +#define QH_CQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ +#define QH_CQP_NTEP_MASK (0xffffffe0) + +/* Transfer Overlay. Paragraph 3.6.3 + * + * NOTES: + * 1. Same as the field of the same name in struct ehci_qtd_s + * 2. Similar to the field of the same name in struct ehci_qtd_s, but with + * some additional bitfields. + */ + +/* Next qTD Pointer (NOTE 1) */ + +#define QH_NQP_T (1 << 0) /* Bit 0: Terminate */ + /* Bits 1-4: Reserved */ +#define QH_NQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ +#define QH_NQP_NTEP_MASK (0xffffffe0) + +/* Alternate Next qTD Pointer. Table 3.7 (NOTE 2) */ + +#define QH_AQP_T (1 << 0) /* Bit 0: Terminate */ +#define QH_AQP_NAKCNT (1) /* Bits 1-4: Nak Counter */ +#define QH_AQP_NTEP_SHIFT (5) /* Bits 5-31: Next Transfer Element Pointer */ +#define QH_AQP_NTEP_MASK (0xffffffe0) + +/* qTD Token (NOTE 1) */ + +#define QH_TOKEN_STATUS_SHIFT (0) /* Bits 0-7: Status */ +#define QH_TOKEN_STATUS_MASK (0xff << QH_TOKEN_STATUS_SHIFT) +# define QH_TOKEN_P (1 << 0) /* Bit 0 Ping State */ +# define QH_TOKEN_ERR (1 << 0) /* Bit 0 Error */ +# define QH_TOKEN_SPLITXSTATE (1 << 1) /* Bit 1 Split Transaction State */ +# define QH_TOKEN_MMF (1 << 2) /* Bit 2 Missed Micro-Frame */ +# define QH_TOKEN_XACTERR (1 << 3) /* Bit 3 Transaction Error */ +# define QH_TOKEN_BABBLE (1 << 4) /* Bit 4 Babble Detected */ +# define QH_TOKEN_DBERR (1 << 5) /* Bit 5 Data Buffer Error */ +# define QH_TOKEN_HALTED (1 << 6) /* Bit 6 Halted */ +# define QH_TOKEN_ACTIVE (1 << 7) /* Bit 7 Active */ +# define QH_TOKEN_ERRORS (0x78 << QH_TOKEN_STATUS_SHIFT) +#define QH_TOKEN_PID_SHIFT (8) /* Bits 8-9: PID Code */ +#define QH_TOKEN_PID_MASK (3 << QH_TOKEN_PID_SHIFT) +# define QH_TOKEN_PID_OUT (0 << QH_TOKEN_PID_SHIFT) /* OUT Token generates token (E1H) */ +# define QH_TOKEN_PID_IN (1 << QH_TOKEN_PID_SHIFT) /* IN Token generates token (69H) */ +# define QH_TOKEN_PID_SETUP (2 << QH_TOKEN_PID_SHIFT) /* SETUP Token generates token (2DH) */ + +#define QH_TOKEN_CERR_SHIFT (10) /* Bits 10-11: Error Counter */ +#define QH_TOKEN_CERR_MASK (3 << QH_TOKEN_CERR_SHIFT) +#define QH_TOKEN_CPAGE_SHIFT (12) /* Bits 12-14: Current Page */ +#define QH_TOKEN_CPAGE_MASK (7 << QH_TOKEN_CPAGE_SHIFT) +#define QH_TOKEN_IOC (1 << 15) /* Bit 15: Interrupt On Complete */ +#define QH_TOKEN_NBYTES_SHIFT (16) /* Bits 16-30: Total Bytes to Transfer */ +#define QH_TOKEN_NBYTES_MASK (0x7fff << QH_TOKEN_NBYTES_SHIFT) +#define QH_TOKEN_TOGGLE_SHIFT (31) /* Bit 31: Data Toggle */ +#define QH_TOKEN_TOGGLE (1 << 31) /* Bit 31: Data Toggle */ + +/* Buffer Page Pointer List (NOTE 2) */ + +/* Page 0 */ + +#define QH_BUFPTR0_OFFFSET_SHIFT (0) /* Bits 0-11: Current Offset */ +#define QH_BUFPTR0_OFFFSET_MASK (0xfff << QH_BUFPTR0_OFFFSET_SHIFT) + +/* Page 1. Table 3.22 */ + +#define QH_BUFPTR1_CPROGMASK_SHIFT (0) /* Bits 0-7: Split-transaction Complete-split Progress */ +#define QH_BUFPTR1_CPROGMASK_MASK (0xff << QH_BUFPTR1_CPROGMASK_SHIFT) + /* Bits 8-11: Reserved */ + +/* Page 2. Table 3.22 */ + +#define QH_BUFPTR2_FRAMETAG_SHIFT (0) /* Bits 0-4: Split-transaction Frame Tag */ +#define QH_BUFPTR2_FRAMETAG_MASK (31 << QH_BUFPTR2_FRAMETAG_SHIFT) +#define QH_BUFPTR2_SBYTES_SHIFT (5) /* Bits 5-11: S-bytes */ +#define QH_BUFPTR2_SBYTES_MASK (0x7f << QH_BUFPTR2_SBYTES_SHIFT) + +/* Other pages */ + + /* Bits 0-11: Reserved */ + +/* All pages */ + +#define QH_BUFPTR_SHIFT (12) /* Bits 12-31: Buffer Pointer List */ +#define QH_BUFPTR_MASK (0xfffff000) + +/* Periodic Frame Span Traversal Node (STN). Paragrap 3.7 */ + +/* FSTN Normal Path Pointer. Paragraph 3.7.1 */ + +#define FSTN_NPP_T (1 << 0) /* Bit 0: Terminate. 1=Link Pointer not valid */ +#define FSTN_NPP_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define FSTN_NPP_TYP_MASK (3 << FSTN_NPP_TYP_SHIFT) +# define FSTN_NPP_TYP_ITD (0 << FSTN_NPP_TYP_SHIFT) /* Isochronous Transfer Descriptor */ +# define FSTN_NPP_TYP_QH (1 << FSTN_NPP_TYP_SHIFT) /* Queue Head */ +# define FSTN_NPP_TYP_SITD (2 << FSTN_NPP_TYP_SHIFT) /* Split Transaction Isochronous Transfer Descriptor */ +# define FSTN_NPP_TYP_FSTN (3 << FSTN_NPP_TYP_SHIFT) /* Frame Span Traversal Node */ + + /* Bits 3-4: Reserved */ +#define FSTN_NPP_NPLP_SHIFT (5) /* Bits 5-31: Normal Path Link Pointer */ +#define FSTN_NPP_NPLP_MASK (0xffffffe0) + +/* FSTN Back Path Link Pointer. Paragraph 3.7.2 */ + +#define FSTN_BPP_T (1 << 0) /* Bit 0: Terminate. 1=Link Pointer not valid */ +#define FSTN_BPP_TYP_SHIFT (1) /* Bits 1-2: Type */ +#define FSTN_BPP_TYP_MASK (3 << FSTN_BPP_TYP_SHIFT) +# define FSTN_BPP_TYP_QH (1 << FSTN_BPP_TYP_SHIFT) /* Queue Head */ + + /* Bits 3-4: Reserved */ +#define FSTN_BPP_BPLP_SHIFT (5) /* Bits 5-31: Back Path Link Pointer */ +#define FSTN_BPP_BPLP_MASK (0xffffffe0) + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* Registers ****************************************************************/ + +/* Since the operational registers are not known a compile time, representing + * register blocks with structures is more convenient than using individual + * register offsets. + */ + +/* Host Controller Capability Registers. + * This register block must be positioned at a well known address. + */ + +struct ehci_hccr_s +{ + uint8_t caplength; /* 0x00: Capability Register Length */ + uint8_t reserved; + uint16_t hciversion; /* 0x02: Interface Version Number */ + uint32_t hcsparams; /* 0x04: Structural Parameters */ + uint32_t hccparams; /* 0x08: Capability Parameters */ + uint8_t hcspportrt[8]; /* 0x0c: Companion Port Route Description */ +}; + +/* Host Controller Operational Registers. + * This register block is positioned at an offset of 'caplength' from the + * beginning of the Host Controller Capability Registers. + */ + +struct ehci_hcor_s +{ + uint32_t usbcmd; /* 0x00: USB Command */ + uint32_t usbsts; /* 0x04: USB Status */ + uint32_t usbintr; /* 0x08: USB Interrupt Enable */ + uint32_t frindex; /* 0x0c: USB Frame Index */ + uint32_t ctrldssegment; /* 0x10: 4G Segment Selector */ + uint32_t periodiclistbase; /* 0x14: Frame List Base Address */ + uint32_t asynclistaddr; /* 0x18: Next Asynchronous List Address */ +#ifndef CONFIG_USB_ECHI_HCOR_RESERVED_DISABLE + uint32_t reserved[9]; +#endif + uint32_t configflag; /* 0x40: Configured Flag Register */ + uint32_t portsc[15]; /* 0x44: Port Status/Control */ +}; + +/* USB2 Debug Port Register Interface. + * This register block is normally found via the PCI capabalities. + * In non-PCI implementions, you need apriori information about the + * location of these registers. + */ + +struct ehci_debug_s +{ + uint32_t psc; /* 0x00: Debug Port Control/Status Register */ + uint32_t pids; /* 0x04: Debug USB PIDs Register */ + uint32_t data[2]; /* 0x08: Debug Data buffer Registers */ + uint32_t addr; /* 0x10: Device Address Register */ +}; + +/* Data Structures **********************************************************/ + +/* Paragraph 3 */ + +/* Periodic Frame List. + * Paragraph 3.1. An array of pointers. + */ + +/* Aysnchronous List Queue Head Pointer. + * Paragraph 3.2. Circular list of queue heads + */ + +/* Isochronous (High-Speed) Transfer Descriptor (iTD). + * Paragraph 3.3. Must be aligned to 32-byte boundaries. + */ + +struct ehci_itd_s +{ + uint32_t nlp; /* 0x00-0x03: Next link pointer */ + uint32_t trans[8]; /* 0x04-0x23: Transaction Status and Control List */ + uint32_t bpl[7]; /* 0x24-0x3c: Buffer Page Pointer List */ +}; + +#define SIZEOF_EHCI_ITD_S (64) /* 16*sizeof(uint32_t) */ + +/* Split Transaction Isochronous Transfer Descriptor (siTD). Paragraph 3.4 */ + +struct ehci_sitd_s +{ + uint32_t nlp; /* 0x00-0x03: Next link pointer */ + uint32_t epchar; /* 0x04-0x07: Endpoint and Transaction Translator Characteristics */ + uint32_t fmsched; /* 0x08-0x0b: Micro-frame Schedule Control */ + uint32_t xfrstate; /* 0x0c-0x0f: Transfer Status and Control */ + uint32_t bpl[2]; /* 0x10-0x17: Buffer Pointer List */ + uint32_t blp; /* 0x18-0x1b: Back link pointer */ +}; + +#define SIZEOF_EHCI_SITD_S (28) /* 7*sizeof(uint32_t) */ + +/* Queue Element Transfer Descriptor (qTD). Paragraph 3.5 */ + +/* 32-bit version. See EHCI Appendix B for the 64-bit version. */ + +struct ehci_qtd_s +{ + uint32_t nqp; /* 0x00-0x03: Next qTD Pointer */ + uint32_t alt; /* 0x04-0x07: Alternate Next qTD Pointer */ + uint32_t token; /* 0x08-0x0b: qTD Token */ + uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List */ +}; + +#define SIZEOF_EHCI_QTD_S (32) /* 8*sizeof(uint32_t) */ + +/* Queue Head. Paragraph 3.6 + * + * NOTE: + * 1. Same as the field of the same name in struct ehci_qtd_s + * 2. Similar to the field of the same name in struct ehci_qtd_s, + * but with some additional bitfields. + */ + +struct ehci_overlay_s +{ + uint32_t nqp; /* 0x00-0x03: Next qTD Pointer (NOTE 1) */ + uint32_t alt; /* 0x04-0x07: Alternate Next qTD Pointer (NOTE 2) */ + uint32_t token; /* 0x08-0x0b: qTD Token (NOTE 1) */ + uint32_t bpl[5]; /* 0x0c-0x1c: Buffer Page Pointer List (NOTE 2) */ +}; + +#define SIZEOF_EHCI_OVERLAY (32) /* 8*sizeof(uint32_t) */ + +struct ehci_qh_s +{ + uint32_t hlp; /* 0x00-0x03: Queue Head Horizontal Link Pointer */ + uint32_t epchar; /* 0x04-0x07: Endpoint Characteristics */ + uint32_t epcaps; /* 0x08-0x0b: Endpoint Capabilities */ + uint32_t cqp; /* 0x0c-0x0f: Current qTD Pointer */ + struct ehci_overlay_s overlay; /* 0x10-0x2c: Transfer overlay */ +}; + +#define SIZEOF_EHCI_QH (48) /* 4*sizeof(uint32_t) + SIZEOF_EHCI_OVERLAY */ + +/* Periodic Frame Span Traversal Node (STN). Paragrap 3.7 */ + +struct ehci_fstn_s +{ + uint32_t npp; /* 0x00-0x03: Normal Path Pointer */ + uint32_t bpp; /* 0x04-0x07: Back Path Link Pointer */ +}; + +#define SIZEOF_EHCI_FSTN_S (8) /* 2*sizeof(uint32_t) */ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +#ifdef __cplusplus +#define EXTERN extern "C" +extern "C" +{ +#else +#define EXTERN extern +#endif + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +#undef EXTERN +#ifdef __cplusplus +} +#endif +#endif /* __INCLUDE_NUTTX_USB_EHCI_H */ -- cgit v1.3.1