/* * Copyright (c) 2020-2022 Artinchip Technology Co., Ltd. All rights reserved. * * Dehuang Wu */ #include #include #include #include #include #include #include #include #include "usb_ehci.h" #include "usbh_core.h" #include #include //#define USBH_DEBUG 0 #define USB_EHCI_HCCR_BASE(id) (USB_HOST_REG_BASE(id)) /* Host Controller Capability Registers */ /* 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) #define false 0 #define true 1 struct usb_ehci_epinfo_s; struct usb_ehci_qh_s { /* Fields visible to hardware */ struct ehci_qh_s hw __attribute__((aligned(CACHE_LINE_SIZE))); /* Hardware representation of the queue head, 48 bytes */ struct usb_ehci_epinfo_s *epinfo; /* Endpoint used for the transfer */ /* Internal fields used by the EHCI driver */ u32 fqp; /* First qTD in the list (physical address) */ #if (__LONG_WIDTH__ == 32) u8 pad[8]; /* Padding to assure 32-byte alignment */ #endif }; /* This structure describes one endpoint. */ struct usb_ehci_epinfo_s { u8 epno : 7; /* Endpoint number */ u8 dirin : 1; /* 1:IN endpoint 0:OUT endpoint */ u8 devaddr : 7; /* Device address */ u8 toggle : 1; /* Next data toggle */ bool inuse; u8 status; /* Retained token status bits (for debug purposes) */ u16 maxpacket : 11; /* Maximum packet size */ u16 xfrtype : 2; /* See USB_EP_ATTR_XFER_* definitions in usb.h */ u16 speed : 2; /* See USB_*_SPEED definitions in ehci.h */ int result; /* The result of the transfer */ u32 xfrd; /* On completion, will hold the number of bytes transferred */ struct usbh_hubport *hport; struct usb_ehci_qh_s *qh; }; /* Internal representation of the EHCI Queue Element Transfer Descriptor * (qTD) */ struct usb_ehci_qtd_s { /* Fields visible to hardware */ struct ehci_qtd_s hw __attribute__((aligned(CACHE_LINE_SIZE))); /* 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, u32 **bp, void *arg); typedef int (*foreach_qtd_t)(struct usb_ehci_qtd_s *qtd, u32 **bp, void *arg); /* This structure retains the overall state of the USB host controller */ #define CONFIG_USBHOST_PIPE_NUM (3) // EP0, in, out #define CONFIG_USB_EHCI_QH_NUM (1) #define CONFIG_USB_EHCI_QTD_NUM (3) struct ehci_hcd { /* Queue Head (QH) pool */ __attribute__((aligned(CACHE_LINE_SIZE))) struct usb_ehci_qh_s qhpool[CONFIG_USB_EHCI_QH_NUM]; /* Queue Element Transfer Descriptor (qTD) pool */ __attribute__((aligned(CACHE_LINE_SIZE))) struct usb_ehci_qtd_s qtdpool[CONFIG_USB_EHCI_QTD_NUM]; /* List of free Queue Head (QH) structures */ struct usb_ehci_list_s *qhfree; /* List of free Queue Element Transfer Descriptor (qTD) */ struct usb_ehci_list_s *qtdfree; struct usb_ehci_epinfo_s chan[CONFIG_USBHOST_PIPE_NUM]; }; struct ehci_hcd g_ehci_hcd __attribute__((aligned(CACHE_LINE_SIZE))); struct usb_ehci_qh_s g_asynchead __attribute__((aligned(CACHE_LINE_SIZE))); static void usb_ehci_qh_free(struct usb_ehci_qh_s *qh); static void usb_ehci_qtd_free(struct usb_ehci_qtd_s *qtd); static int usb_ehci_reset(int id); static int usb_ehci_wait_usbsts(int id, u32 maskbits, u32 donebits, u32 delay); #ifdef USBH_DEBUG void dump_hcor(volatile struct ehci_hcor_s *hcor) { pr_err("usbcmd:0x%x\n", readl(&hcor->usbcmd)); pr_err("usbsts:0x%x\n", readl(&hcor->usbsts)); pr_err("usbintr:0x%x\n", readl(&hcor->usbintr)); pr_err("frindex:0x%x\n", readl(&hcor->frindex)); pr_err("ctrldssegment:0x%x\n", readl(&hcor->ctrldssegment)); pr_err("periodiclistbase:0x%x\n", readl(&hcor->periodiclistbase)); pr_err("asynclistaddr:0x%x\n", readl(&hcor->asynclistaddr)); pr_err("configflag:0x%x\n", readl(&hcor->configflag)); pr_err("portsc[0]:0x%x\n\n", readl(&hcor->portsc[0])); } void dump_qtd(struct usb_ehci_qtd_s *qtd) { u32 addr; pr_err("qTD 0x%x:\n", (u32)(uintptr_t)qtd); pr_err(" nqp: (0x%x)\n", qtd->hw.nqp); pr_err(" alt: (0x%x)\n", qtd->hw.alt); pr_err(" token: (0x%x)\n", qtd->hw.token); pr_err(" bpl0: (0x%x)\n", qtd->hw.bpl[0]); pr_err(" bpl1: (0x%x)\n", qtd->hw.bpl[1]); pr_err(" bpl2: (0x%x)\n", qtd->hw.bpl[2]); pr_err(" bpl3: (0x%x)\n", qtd->hw.bpl[3]); pr_err(" bpl4: (0x%x)\n", qtd->hw.bpl[4]); addr = qtd->hw.nqp & 0xFFFFFFFC; if (addr) dump_qtd((void *)(uintptr_t)addr); } void dump_qh(struct usb_ehci_qh_s *qh) { u32 qtd; pr_err("Queue Head 0x%x, sizeof qh %d %d %d:\n", (u32)(uintptr_t)qh, (int)sizeof(*qh), (int)sizeof(struct usb_ehci_qh_s), (int)sizeof(struct ehci_qh_s)); pr_err("HW part:\n"); pr_err(" qhlp: (0x%x, TYP=%x,T=%d)\n", qh->hw.hlp & 0xFFFFFFE0, (qh->hw.hlp & 0x6) >> 1, qh->hw.hlp & 1); pr_err(" epchar: (0x%x)\n", qh->hw.epchar); pr_err(" epcaps: (0x%x)\n", qh->hw.epcaps); pr_err(" cqp: (0x%x)\n", qh->hw.cqp); pr_err(" overlay: \n"); pr_err(" nqp: (0x%x)\n", qh->hw.overlay.nqp); pr_err(" alt: (0x%x)\n", qh->hw.overlay.alt); pr_err(" token: (0x%x)\n", qh->hw.overlay.token); pr_err(" bpl0: (0x%x)\n", qh->hw.overlay.bpl[0]); pr_err(" bpl1: (0x%x)\n", qh->hw.overlay.bpl[1]); pr_err(" bpl2: (0x%x)\n", qh->hw.overlay.bpl[2]); pr_err(" bpl3: (0x%x)\n", qh->hw.overlay.bpl[3]); pr_err(" bpl4: (0x%x)\n", qh->hw.overlay.bpl[4]); pr_err("fqp: (0x%x)\n", qh->fqp); pr_err("epinfo: (0x%x)\n", (u32)(uintptr_t)qh->epinfo); qtd = qh->hw.overlay.nqp & 0xFFFFFFFC; if (qtd) dump_qtd((void *)(uintptr_t)qtd); } #else void dump_hcor(volatile struct ehci_hcor_s *hcor) { } void dump_qtd(struct usb_ehci_qtd_s *qtd) { } void dump_qh(struct usb_ehci_qh_s *qh) { } #endif 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 (u8 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 (u8 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]); } return 0; } void usb_hc_low_level_init(int id) { u32 val, clk_usbh, clk_usb_phy; //, reset_usbphy, reset_usbh; if (id == 0) syscfg_usb_phy0_sw_host(1); /* Switch to HOST mode */ /* Enable clock */ clk_usbh = CLK_USBH0 + id; hal_clk_enable_deassertrst_iter(clk_usbh); clk_usb_phy = CLK_USB_PHY0 + id; hal_clk_enable_deassertrst_iter(clk_usb_phy); /* set phy type: UTMI/ULPI */ val = readl(USBH_REG_HOST_CTL(id)); writel((val | 0x1), USBH_REG_HOST_CTL(id)); } int usb_hc_hw_init(int id) { volatile struct ehci_hcor_s *hcor; int ret; u32 regval; u32 physaddr1; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); usb_hc_low_level_init(id); /* 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 = (u32)(uintptr_t)&g_asynchead; g_asynchead.hw.hlp = physaddr1 | QH_HLP_TYP_QH; g_asynchead.hw.epchar = (QH_EPCHAR_H | QH_EPCHAR_EPS_FULL); g_asynchead.hw.overlay.nqp = (QH_NQP_T); g_asynchead.hw.overlay.alt = (QH_NQP_T); g_asynchead.hw.overlay.token = (QH_TOKEN_HALTED); g_asynchead.fqp = (QTD_NQP_T); aicos_dcache_clean_range((void *)(uintptr_t)&g_asynchead.hw, sizeof(struct usb_ehci_qh_s)); /* Host Controller Initialization. Paragraph 4.1 */ /* Reset the EHCI hardware */ ret = usb_ehci_reset(id); if (ret < 0) { pr_err("ehci reset failed.\n"); return -1; } /* Disable all interrupts */ writel(0, &hcor->usbintr); /* Clear pending interrupts. Bits in the USBSTS register are cleared by * writing a '1' to the corresponding bit. */ writel(EHCI_INT_ALLINTS, &hcor->usbsts); /* Set the Current Asynchronous List Address. */ writel(physaddr1, &hcor->asynclistaddr); /* Enable the asynchronous schedule and, possibly enable the periodic * schedule and set the frame list size. */ regval = readl(&hcor->usbcmd); regval &= ~(EHCI_USBCMD_HCRESET | EHCI_USBCMD_FLSIZE_MASK | EHCI_USBCMD_PSEN | EHCI_USBCMD_ASEN | EHCI_USBCMD_IAADB); regval |= EHCI_USBCMD_ASEN; writel(regval, &hcor->usbcmd); /* Start the host controller by setting the RUN bit in the USBCMD register. */ regval = readl(&hcor->usbcmd); regval |= EHCI_USBCMD_RUN; writel(regval, &hcor->usbcmd); /* Route all ports to this host controller by setting the CONFIG flag. */ regval = readl(&hcor->configflag); regval |= EHCI_CONFIGFLAG; writel(regval, &hcor->configflag); /* Wait for the EHCI to run (i.e., no longer report halted) */ ret = usb_ehci_wait_usbsts(id, EHCI_USBSTS_HALTED, 0, 100 * 1000); if (ret < 0) { pr_err("Wait ehci run timeout.\n"); return -2; } /* Enable port power */ regval = readl(&hcor->portsc[0]); regval |= EHCI_PORTSC_PP; writel(regval, &hcor->portsc[0]); /* Enable EHCI interrupts. Interrupts are still disabled at the level of * the interrupt controller. */ writel(EHCI_HANDLED_INTS, &hcor->usbintr); return ret; } int usb_hc_hw_fast_init(int id) { volatile struct ehci_hcor_s *hcor; int ret; u32 regval; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); usb_hc_low_level_init(id); /* Reset the EHCI hardware */ ret = usb_ehci_reset(id); if (ret < 0) { pr_err("ehci reset failed.\n"); return -1; } /* Disable all interrupts */ writel(0, &hcor->usbintr); /* Clear pending interrupts. Bits in the USBSTS register are cleared by * writing a '1' to the corresponding bit. */ writel(EHCI_INT_ALLINTS, &hcor->usbsts); /* Start the host controller by setting the RUN bit in the USBCMD register. */ regval = readl(&hcor->usbcmd); regval |= EHCI_USBCMD_RUN; writel(regval, &hcor->usbcmd); /* Route all ports to this host controller by setting the CONFIG flag. */ regval = readl(&hcor->configflag); regval |= EHCI_CONFIGFLAG; writel(regval, &hcor->configflag); /* Wait for the EHCI to run (i.e., no longer report halted) */ ret = usb_ehci_wait_usbsts(id, EHCI_USBSTS_HALTED, 0, 100 * 1000); if (ret < 0) { pr_err("Wait ehci run timeout.\n"); return -2; } /* Enable port power */ regval = readl(&hcor->portsc[0]); regval |= EHCI_PORTSC_PP; writel(regval, &hcor->portsc[0]); /* Enable EHCI interrupts. Interrupts are still disabled at the level of * the interrupt controller. */ writel(EHCI_HANDLED_INTS, &hcor->usbintr); return ret; } 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; } } pr_debug("%s, line %d: EBUSY.\n", __func__, __LINE__); /* 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; } 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; } 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; } 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; } 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; } static int usb_ehci_qh_foreach(struct usb_ehci_qh_s *qh, u32 **bp, foreach_qh_t handler, void *arg) { struct usb_ehci_qh_s *next; u32 physaddr; int ret; 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 = (qh->hw.hlp); if ((physaddr & QH_HLP_T) != 0) { /* Set the next pointer to NULL. This will terminate the loop. */ next = NULL; } else if ((physaddr & QH_HLP_MASK) == (u32)(uintptr_t)&g_asynchead) { /* Is the next QH the asynchronous list head which will always be at * the end of the asynchronous queue? */ /* That will also terminate the loop */ next = NULL; } else { /* Otherwise, there is a QH structure after this one that describes * another transaction. */ physaddr = (qh->hw.hlp) & QH_HLP_MASK; next = (struct usb_ehci_qh_s *)(uintptr_t)(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; } 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; u32 physaddr; u32 *bp; int ret; /* Handle the special case where the queue is empty */ bp = &qh->fqp; /* Start of qTDs in original list */ physaddr = (*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 *)(uintptr_t)(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 (((qtd->hw.nqp) & QTD_NQP_T) != 0) { /* Set the next pointer to NULL. This will terminate the loop. */ next = NULL; } else { physaddr = (qtd->hw.nqp) & QTD_NQP_NTEP_MASK; next = (struct usb_ehci_qtd_s *)(uintptr_t)(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; } static int usb_ehci_qtd_discard(struct usb_ehci_qtd_s *qtd, u32 **bp, void *arg) { aicos_dcache_clean_invalid_range((void *)&qtd->hw, sizeof(struct usb_ehci_qtd_s)); /* 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; } static int usb_ehci_qh_discard(struct usb_ehci_qh_s *qh) { int ret; aicos_dcache_clean_invalid_range((void *)&qh->hw, sizeof(struct usb_ehci_qh_s)); /* Free all of the qTD's attached to the QH */ ret = usb_ehci_qtd_foreach(qh, usb_ehci_qtd_discard, NULL); /* Then free the QH itself */ usb_ehci_qh_free(qh); return ret; } #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) */ static inline u8 usb_ehci_speed(u8 usbspeed) { u8 g_ehci_speed[4] = { 0, EHCI_LOW_SPEED, EHCI_FULL_SPEED, EHCI_HIGH_SPEED }; 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; u32 regval; u8 hubaddr; u8 hubport; struct usb_ehci_epinfo_s *ep0info; struct usbh_hubport *rhport; rhport = epinfo->hport; 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 = ((u32)epinfo->devaddr << QH_EPCHAR_DEVADDR_SHIFT) | ((u32)epinfo->epno << QH_EPCHAR_ENDPT_SHIFT) | ((u32)usb_ehci_speed(epinfo->speed) << QH_EPCHAR_EPS_SHIFT) | QH_EPCHAR_DTC | ((u32)epinfo->maxpacket << QH_EPCHAR_MAXPKT_SHIFT) | ((u32)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 = (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 = ((u32)hubaddr << QH_EPCAPS_HUBADDR_SHIFT) | ((u32)hubport << QH_EPCAPS_PORT_SHIFT) | ((u32)1 << QH_EPCAPS_MULT_SHIFT); qh->hw.epcaps = (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 = (QH_HLP_T); qh->hw.overlay.nqp = (QH_NQP_T); qh->hw.overlay.alt = (QH_AQP_T); return qh; } 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; int chidx; hport = ep_cfg->hport; chidx = usb_ehci_chan_alloc(); if (chidx < 0) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } epinfo = &g_ehci_hcd.chan[chidx]; 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; epinfo->maxpacket = ep_cfg->ep_mps; epinfo->xfrtype = ep_cfg->ep_type; epinfo->speed = hport->speed; epinfo->hport = hport; /* restore variable */ epinfo->inuse = true; *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; } static int usb_ehci_reset(int id) { u32 regval = 0; u64 start_us; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); /* 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..." */ writel(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." */ start_us = aic_get_time_us(); do { /* Wait and update the timeout counter */ if ((aic_get_time_us() - start_us) > 1000) break; /* 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 = readl(&hcor->usbsts); } while ((regval & EHCI_USBSTS_HALTED) == 0); /* Is the EHCI still running? Did we timeout? */ if ((regval & EHCI_USBSTS_HALTED) == 0) { pr_err("Wait ehci halt timeout.\n"); return -ETIMEDOUT; } /* Now we can set the HCReset bit in the USBCMD register to * initiate the reset */ regval = readl(&hcor->usbcmd); regval |= EHCI_USBCMD_HCRESET; writel(regval, &hcor->usbcmd); /* Wait for the HCReset bit to become clear */ start_us = aic_get_time_us(); do { /* Wait and update the timeout counter */ if ((aic_get_time_us() - start_us) > 1000) break; /* 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 = readl(&hcor->usbcmd); } while ((regval & EHCI_USBCMD_HCRESET) != 0); /* Return either success or a timeout */ return (regval & EHCI_USBCMD_HCRESET) != 0 ? -ETIMEDOUT : 0; } static int usb_ehci_wait_usbsts(int id, u32 maskbits, u32 donebits, u32 timeout) { u32 regval; u32 start, cur; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); start = aic_get_time_us(); do { /* Read the USBSTS register and check for a system error */ regval = readl(&hcor->usbsts); if ((regval & EHCI_INT_SYSERROR) != 0) { return -EIO; } /* Mask out the bits of interest */ regval &= maskbits; cur = aic_get_time_us(); /* Loop until the masked bits take the specified value or until a * timeout occurs. */ if (!(regval != donebits)) break; } while ((cur - start) < timeout); /* We got here because either the waited for condition or a timeout * occurred. Return a value to indicate which. */ return (regval == donebits) ? 0 : -ETIMEDOUT; } int usbh_portchange_wait(int id) { u32 usbsts, pending, regval; u64 start_us; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); start_us = aic_get_time_us(); do { /* Read Interrupt Status and mask out interrupts that are not enabled. */ usbsts = readl(&hcor->usbsts); regval = readl(&hcor->usbintr); /* Handle all unmasked interrupt sources */ pending = usbsts & regval; /* Clear all pending interrupts */ writel(usbsts & EHCI_INT_ALLINTS, &hcor->usbsts); if ((pending & EHCI_INT_PORTSC) != 0) { pr_warn("Port status changed.\n"); return 0; } } while ((aic_get_time_us() - start_us) < 1000); return -1; } int usbh_get_port_connect_status(int id, int port) { u32 portsc; bool connected = false; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); if (port <= 0) { pr_err("port id not correct %d\n", port); return false; } /* Only one root hub port */ portsc = readl(&hcor->portsc[port - 1]); /* 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? */ pr_warn("port connected\n"); connected = true; } else { pr_warn("port disconnected\n"); connected = false; } } /* 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) */ writel(portsc, &hcor->portsc[port - 1]); return connected; } int usbh_reset_port(int port, int id) { u64 start_us; u32 regval; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); regval = readl(&hcor->portsc[port - 1]); regval &= ~EHCI_PORTSC_PE; regval |= EHCI_PORTSC_RESET; writel(regval, &hcor->portsc[port - 1]); aic_mdelay(3); regval = readl(&hcor->portsc[port - 1]); regval &= ~EHCI_PORTSC_RESET; writel(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 ..." */ start_us = aic_get_time_us(); while ((readl(&hcor->portsc[port - 1]) & EHCI_PORTSC_RESET) != 0) { if ((aic_get_time_us() - start_us) > 3000) return -ETIMEDOUT; } return 0; } u8 usbh_get_port_speed(int id) { /* Defined by individual manufacturers */ u32 regval; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); regval = readl(&hcor->portsc[0]); if ((regval & EHCI_PORTSC_LSTATUS_MASK) == EHCI_PORTSC_LSTATUS_KSTATE) { pr_err("USB_SPEED_LOW\n"); return USB_SPEED_LOW; } if (regval & EHCI_PORTSC_PE) { pr_err("USB_SPEED_HIGH\n"); return USB_SPEED_HIGH; } pr_info("USB_SPEED_FULL\n"); return USB_SPEED_FULL; } int usbh_ep0_reconfigure(usbh_epinfo_t ep, u8 dev_addr, u8 ep_mps, u8 speed) { struct usb_ehci_epinfo_s *epinfo; int ret = 0; epinfo = (struct usb_ehci_epinfo_s *)ep; epinfo->devaddr = dev_addr; epinfo->speed = speed; epinfo->maxpacket = ep_mps; return ret; } static int usb_ehci_qtd_addbpl(struct usb_ehci_qtd_s *qtd, const void *buffer, u32 buflen) { u32 physaddr, nbytes, next, ndx; aicos_dcache_clean_invalid_range((void *)buffer, buflen); physaddr = (u32)(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] = (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) { pr_err("%s, line %d\n", __func__, __LINE__); 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; u32 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 = (QTD_NQP_T); qtd->hw.alt = (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 | ((u32)3 << QTD_TOKEN_CERR_SHIFT) | ((u32)8 << QTD_TOKEN_NBYTES_SHIFT); qtd->hw.token = (regval); /* Add the buffer data */ ret = usb_ehci_qtd_addbpl(qtd, (u8 *)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, u32 tokenbits) { struct usb_ehci_qtd_s *qtd; u32 regval; int ret; /* Allocate a new Queue Element Transfer Descriptor (qTD) */ qtd = usb_ehci_qtd_alloc(); if (qtd == NULL) { pr_err("%s qtd null\n", __func__); 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 = (QTD_NQP_T); qtd->hw.alt = (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 | ((u32)3 << QTD_TOKEN_CERR_SHIFT) | ((u32)buflen << QTD_TOKEN_NBYTES_SHIFT); qtd->hw.token = (regval); ret = usb_ehci_qtd_addbpl(qtd, buffer, buflen); if (ret < 0) { pr_err("%s qtd addbpl failed\n", __func__); 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(u32 tokenbits) { struct usb_ehci_qtd_s *qtd; u32 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 = (QTD_NQP_T); qtd->hw.alt = (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 | ((u32)3 << QTD_TOKEN_CERR_SHIFT); qtd->hw.token = (regval); return qtd; } static int usb_ehci_qtd_flush(struct usb_ehci_qtd_s *qtd, u32 **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. */ aicos_dcache_clean_invalid_range((void *)(uintptr_t)&qtd->hw, sizeof(struct ehci_qtd_s)); return 0; } 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. */ aicos_dcache_clean_invalid_range((void *)(uintptr_t)&qh->hw, sizeof(struct ehci_qh_s)); /* Then flush all of the qTD entries in the queue */ return usb_ehci_qtd_foreach(qh, usb_ehci_qtd_flush, NULL); } static void usb_ehci_qh_enqueue(struct usb_ehci_qh_s *qhead, struct usb_ehci_qh_s *qh) { u32 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 = (u32)(uintptr_t)qh; qhead->hw.hlp = (physaddr | QH_HLP_TYP_QH); aicos_dcache_clean_range((void *)(uintptr_t)&qhead->hw, sizeof(struct ehci_qh_s)); } static int usb_ehci_ioc_setup(struct usb_ehci_epinfo_s *epinfo) { int ret = -ENODEV; /* Is the device still connected? */ if (epinfo->hport->connected) { /* 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 */ ret = 0; /* We are good to go */ } return ret; } static int usb_ehci_qtd_ioccheck(struct usb_ehci_qtd_s *qtd, u32 **bp, void *arg) { struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)arg; aicos_dcache_invalid_range((void *)(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 -= ((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; } static int usb_ehci_qh_ioccheck(struct usb_ehci_qh_s *qh, u32 **bp, void *arg) { struct usb_ehci_epinfo_s *epinfo; u32 token; int ret; aicos_dcache_invalid_range((void *)(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; /* 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 = (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 ((qh->fqp & QTD_NQP_T) == 0) { /* the horizontal link pointer of this QH will become the * next back pointer. */ *bp = &qh->hw.hlp; aicos_dcache_clean_range((void *)(uintptr_t)bp, sizeof(uint32_t)); return 0; } /* Not terminal case: */ /* Set the forward link of the previous QH to point to the next * QH in the list. */ **bp = qh->hw.hlp; /* 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; } } /* Then release this QH by returning it to the free list */ usb_ehci_qh_free(qh); return 0; } static int usb_ehci_transfer_wait(int id, struct usb_ehci_epinfo_s *epinfo, u32 timeout) { int ret = 0; u32 start, cur; u32 usbsts, pending, regval; struct usb_ehci_qh_s *qh = NULL; volatile struct ehci_hcor_s *hcor; u32 *bp; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); start = aic_get_time_us(); do { /* Read Interrupt Status and mask out interrupts that are not enabled. */ usbsts = readl(&hcor->usbsts); regval = readl(&hcor->usbintr); /* Handle all unmasked interrupt sources */ pending = usbsts & regval; /* Clear all pending interrupts */ writel(usbsts & EHCI_INT_ALLINTS, &hcor->usbsts); cur = aic_get_time_us(); if ((pending & (EHCI_INT_USBINT | EHCI_INT_USBERRINT)) == 0) continue; bp = (u32 *)&g_asynchead.hw.hlp; qh = (struct usb_ehci_qh_s *)(uintptr_t)((*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); } if (epinfo->result >= 0) { break; } } while (cur - start < timeout); ret = epinfo->result; if (ret < 0) { return ret; } /* Transfer completed successfully. Return the number of bytes transferred.*/ return epinfo->xfrd; } #define USBHOST_CONTROL_TRANSFER_TIMEOUT 2000000 static void ehci_disable_async(int id) { u32 regval; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); regval = readl(&hcor->usbcmd); regval &= ~(EHCI_USBCMD_ASEN); writel(regval, &hcor->usbcmd); usb_ehci_wait_usbsts(id, EHCI_USBSTS_ASS, 0, USBHOST_CONTROL_TRANSFER_TIMEOUT); } static void ehci_enable_async(int id) { u32 regval; volatile struct ehci_hcor_s *hcor; hcor = (struct ehci_hcor_s *)USB_EHCI_HCOR_BASE(id); regval = (u32)(uintptr_t)&g_asynchead; /* Set the Current Asynchronous List Address. */ writel(regval, &hcor->asynclistaddr); regval = readl(&hcor->usbcmd); regval |= (EHCI_USBCMD_ASEN); writel(regval, &hcor->usbcmd); usb_ehci_wait_usbsts(id, EHCI_USBSTS_ASS, EHCI_USBSTS_ASS, USBHOST_CONTROL_TRANSFER_TIMEOUT); } static int usb_ehci_control_init(struct usb_ehci_epinfo_s *epinfo, struct usb_setup_packet *setup, u8 *buffer, u32 buflen) { struct usb_ehci_qh_s *qh; struct usb_ehci_qtd_s *qtd; u32 tokenbits, physaddr, *flink, *alt, toggle; bool dirin = false; /* Create and initialize a Queue Head (QH) structure for this transfer */ qh = usb_ehci_qh_create(epinfo); if (qh == NULL) { pr_err("Failed to create QH.\n"); 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 = (u32)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) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } /* Link the new qTD to the QH head. */ physaddr = ((u32)(uintptr_t)qtd); *flink = (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) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } /* Link the new qTD to either QH head of the SETUP qTD. */ physaddr = ((u32)(uintptr_t)qtd); *flink = (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) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } /* Link the new qTD to either the SETUP or data qTD. */ physaddr = ((u32)(uintptr_t)qtd); *flink = (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 = (physaddr); } } /* Add the new QH to the head of the asynchronous queue list */ usb_ehci_qh_enqueue(&g_asynchead, qh); return 0; } int usbh_control_transfer(usbh_epinfo_t ep, struct usb_setup_packet *setup, u8 *buffer, int id) { struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; int ret; /* Set the request for the IOC event well BEFORE initiating the transfer. */ ret = usb_ehci_ioc_setup(epinfo); if (ret != 0) { pr_err("%s, line %d: setup failed.\n", __func__, __LINE__); goto errout_with_setup; } ehci_disable_async(id); ret = usb_ehci_control_init(epinfo, setup, buffer, setup->wLength); if (ret < 0) { pr_err("%s, line %d: init failed.\n", __func__, __LINE__); goto errout_with_iocwait; } ehci_enable_async(id); /* And wait for the transfer to complete */ ret = usb_ehci_transfer_wait(id, epinfo, USBHOST_CONTROL_TRANSFER_TIMEOUT); if (ret < 0) { pr_err("%s, line %d: wait tmo.\n", __func__, __LINE__); goto errout_with_iocwait; } return ret; errout_with_iocwait: /* Clean-up after an error */ if (epinfo->qh) { usb_ehci_qh_discard(epinfo->qh); epinfo->qh = NULL; } errout_with_setup: return ret; } int usb_ehci_bulk_init(struct usb_ehci_epinfo_s *epinfo, u8 *buffer, u32 buflen) { struct usb_ehci_qh_s *qh; struct usb_ehci_qtd_s *qtd; u32 tokenbits; u32 physaddr; /* Create and initialize a Queue Head (QH) structure for this transfer */ qh = usb_ehci_qh_create(epinfo); if (qh == NULL) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } epinfo->qh = qh; /* Initialize the QH link and get the next data toggle */ tokenbits = (u32)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) { pr_err("%s, line %d: NOMEM.\n", __func__, __LINE__); return -ENOMEM; } /* Link the new qTD to the QH. */ physaddr = (u32)(uintptr_t)qtd; qh->hw.overlay.nqp = (physaddr); } /* Add the new QH to the head of the asynchronous queue list */ usb_ehci_qh_enqueue(&g_asynchead, qh); return 0; } int usbh_ep_bulk_transfer(usbh_epinfo_t ep, u8 *buffer, u32 buflen, u32 timeout, int id) { int ret; struct usb_ehci_epinfo_s *epinfo = (struct usb_ehci_epinfo_s *)ep; ret = usb_ehci_ioc_setup(epinfo); if (ret < 0) { goto errout_with_setup; } ehci_disable_async(id); ret = usb_ehci_bulk_init(epinfo, buffer, buflen); if (ret < 0) { goto errout_with_iocwait; } ehci_enable_async(id); /* And wait for the transfer to complete */ ret = usb_ehci_transfer_wait(id, epinfo, timeout); if (ret < 0) { goto errout_with_iocwait; } return ret; errout_with_iocwait: /* Clean-up after an error */ if (epinfo->qh) { usb_ehci_qh_discard(epinfo->qh); epinfo->qh = NULL; } errout_with_setup: return ret; }