/* Fill in the USB 2.0 roothub descriptor */ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci, struct usb_hub_descriptor *desc) { int ports; u16 temp; __u8 port_removable[(USB_MAXCHILDREN + 1 + 7) / 8]; u32 portsc; unsigned int i; ports = xhci->num_usb2_ports; xhci_common_hub_descriptor(xhci, desc, ports); desc->bDescriptorType = 0x29; temp = 1 + (ports / 8); desc->bDescLength = 7 + 2 * temp; /* The Device Removable bits are reported on a byte granularity. * If the port doesn't exist within that byte, the bit is set to 0. */ memset(port_removable, 0, sizeof(port_removable)); for (i = 0; i < ports; i++) { portsc = xhci_readl(xhci, xhci->usb2_ports[i]); /* If a device is removable, PORTSC reports a 0, same as in the * hub descriptor DeviceRemovable bits. */ if (portsc & PORT_DEV_REMOVE) /* This math is hairy because bit 0 of DeviceRemovable * is reserved, and bit 1 is for port 1, etc. */ port_removable[(i + 1) / 8] |= 1 << ((i + 1) % 8); } /* ch11.h defines a hub descriptor that has room for USB_MAXCHILDREN * ports on it. The USB 2.0 specification says that there are two * variable length fields at the end of the hub descriptor: * DeviceRemovable and PortPwrCtrlMask. But since we can have less than * USB_MAXCHILDREN ports, we may need to use the DeviceRemovable array * to set PortPwrCtrlMask bits. PortPwrCtrlMask must always be set to * 0xFF, so we initialize the both arrays (DeviceRemovable and * PortPwrCtrlMask) to 0xFF. Then we set the DeviceRemovable for each * set of ports that actually exist. */ memset(desc->u.hs.DeviceRemovable, 0xff, sizeof(desc->u.hs.DeviceRemovable)); memset(desc->u.hs.PortPwrCtrlMask, 0xff, sizeof(desc->u.hs.PortPwrCtrlMask)); for (i = 0; i < (ports + 1 + 7) / 8; i++) memset(&desc->u.hs.DeviceRemovable[i], port_removable[i], sizeof(__u8)); }
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, u16 wIndex, __le32 __iomem *addr, u32 port_status) { char *port_change_bit; u32 status; switch (wValue) { case USB_PORT_FEAT_C_RESET: status = PORT_RC; port_change_bit = "reset"; break; case USB_PORT_FEAT_C_BH_PORT_RESET: status = PORT_WRC; port_change_bit = "warm(BH) reset"; break; case USB_PORT_FEAT_C_CONNECTION: status = PORT_CSC; port_change_bit = "connect"; break; case USB_PORT_FEAT_C_OVER_CURRENT: status = PORT_OCC; port_change_bit = "over-current"; break; case USB_PORT_FEAT_C_ENABLE: status = PORT_PEC; port_change_bit = "enable/disable"; break; case USB_PORT_FEAT_C_SUSPEND: status = PORT_PLC; port_change_bit = "suspend/resume"; break; case USB_PORT_FEAT_C_PORT_LINK_STATE: status = PORT_PLC; port_change_bit = "link state"; break; case USB_PORT_FEAT_C_PORT_CONFIG_ERROR: status = PORT_CEC; port_change_bit = "config error"; break; default: /* Should never happen */ return; } /* Change bits are all write 1 to clear */ xhci_writel(xhci, port_status | status, addr); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); port_status = xhci_readl(xhci, addr); xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", port_change_bit, wIndex, port_status); }
static int xhci_fsl_probe(struct udevice *dev) { struct xhci_fsl_priv *priv = dev_get_priv(dev); struct xhci_hccr *hccr; struct xhci_hcor *hcor; int ret = 0; /* * Get the base address for XHCI controller from the device node */ priv->hcd_base = devfdt_get_addr(dev); if (priv->hcd_base == FDT_ADDR_T_NONE) { debug("Can't get the XHCI register base address\n"); return -ENXIO; } priv->ctx.hcd = (struct xhci_hccr *)priv->hcd_base; priv->ctx.dwc3_reg = (struct dwc3 *)((char *)(priv->hcd_base) + DWC3_REG_OFFSET); fsl_apply_xhci_errata(); ret = fsl_xhci_core_init(&priv->ctx); if (ret < 0) { puts("Failed to initialize xhci\n"); return ret; } hccr = (struct xhci_hccr *)(priv->ctx.hcd); hcor = (struct xhci_hcor *)((uintptr_t) hccr + HC_LENGTH(xhci_readl(&hccr->cr_capbase))); debug("xhci-fsl: init hccr %lx and hcor %lx hc_length %lx\n", (uintptr_t)hccr, (uintptr_t)hcor, (uintptr_t)HC_LENGTH(xhci_readl(&hccr->cr_capbase))); return xhci_register(dev, hccr, hcor); }
int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status) { unsigned long flags; int ret; u32 temp; struct xhci_hcd *xhci; struct xhci_td *td; unsigned int ep_index; struct xhci_ring *ep_ring; struct xhci_virt_ep *ep; xhci = hcd_to_xhci(hcd); spin_lock_irqsave(&xhci->lock, flags); ret = usb_hcd_check_unlink_urb(hcd, urb, status); if (ret || !urb->hcpriv) goto done; temp = xhci_readl(xhci, &xhci->op_regs->status); if (temp == 0xffffffff) { xhci_dbg(xhci, "HW died, freeing TD.\n"); td = (struct xhci_td *) urb->hcpriv; usb_hcd_unlink_urb_from_ep(hcd, urb); spin_unlock_irqrestore(&xhci->lock, flags); usb_hcd_giveback_urb(xhci_to_hcd(xhci), urb, -ESHUTDOWN); kfree(td); return ret; } xhci_dbg(xhci, "Cancel URB %p\n", urb); xhci_dbg(xhci, "Event ring:\n"); xhci_debug_ring(xhci, xhci->event_ring); ep_index = xhci_get_endpoint_index(&urb->ep->desc); ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index]; ep_ring = ep->ring; xhci_dbg(xhci, "Endpoint ring:\n"); xhci_debug_ring(xhci, ep_ring); td = (struct xhci_td *) urb->hcpriv; ep->cancels_pending++; list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list); if (ep->cancels_pending == 1) { xhci_queue_stop_endpoint(xhci, urb->dev->slot_id, ep_index); xhci_ring_cmd_db(xhci); } done: spin_unlock_irqrestore(&xhci->lock, flags); return ret; }
void ms_xhci_print_regs(struct xhci_hcd *pXhci) { u32 u32Val; ms_dbg("xhci capability regs at %p:\n", pXhci->cap_regs); u32Val = xhci_readl(pXhci, &pXhci->cap_regs->caplen_hciver); ms_dbg("CAPLENGTH&HCIVERSION %p = 0x%x \n", &pXhci->cap_regs->caplen_hciver, u32Val); ms_dbg("xhci operational regs at %p:\n", pXhci->op_regs); u32Val = xhci_readl(pXhci, &pXhci->cap_regs->u32RtsOff); ms_dbg("RTSOFF %p = 0x%x \n", &pXhci->cap_regs->u32RtsOff, (unsigned int) u32Val & RTSOFF_RSVD_MASK); ms_dbg("xhci runtime regss at %p:\n", pXhci->run_regs); u32Val = xhci_readl(pXhci, &pXhci->cap_regs->u32DbOff); ms_dbg("DBOFF %p = 0x%x \n", &pXhci->cap_regs->u32DbOff, u32Val); ms_dbg("doorbell array at %p:\n", pXhci->doorbells); }
/* Test and clear port RWC bit */ void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, int port_id, u32 port_bit) { u32 temp; temp = xhci_readl(xhci, port_array[port_id]); if (temp & port_bit) { temp = xhci_port_state_to_neutral(temp); temp |= port_bit; xhci_writel(xhci, temp, port_array[port_id]); if (xhci->quirks & XHCI_PORTSC_DELAY) ndelay(100); } }
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) { struct exynos_xhci *ctx = &exynos; int ret; #ifdef CONFIG_OF_CONTROL exynos_usb3_parse_dt(gd->fdt_blob, ctx); #else ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy(); ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci(); #endif ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); #ifdef CONFIG_OF_CONTROL /* setup the Vbus gpio here */ if (fdt_gpio_isvalid(&ctx->vbus_gpio) && !fdtdec_setup_gpio(&ctx->vbus_gpio)) gpio_direction_output(ctx->vbus_gpio.gpio, 1); #endif ret = exynos_xhci_core_init(ctx); if (ret) { puts("XHCI: failed to initialize controller\n"); return -EINVAL; } *hccr = (ctx->hcd); *hcor = (struct xhci_hcor *)((uint32_t) *hccr + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n", (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); return 0; }
/* set 0 to PORT_POWER of PORT_STATUS register of each port */ void mtktest_disableXhciAllPortPower(struct xhci_hcd *xhci){ int i; u32 port_id, temp; u32 __iomem *addr; #ifdef CONFIG_MTK_OTG_PMIC_BOOST_5V mtk_disable_pmic_otg_mode() ; #else #if CON_HOST_DEV g_num_u3_port = getU3PortNumber(); g_num_u2_port = getU2PortNumber(); #else g_num_u3_port = SSUSB_U3_PORT_NUM(readl(SSUSB_IP_CAP)); g_num_u2_port = SSUSB_U2_PORT_NUM(readl(SSUSB_IP_CAP)); #endif for(i=1; i<=g_num_u3_port; i++){ port_id=i; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(port_id-1 & 0xff); temp = xhci_readl(xhci, addr); temp = mtktest_xhci_port_state_to_neutral(temp); temp &= ~PORT_POWER; xhci_writel(xhci, temp, addr); while(xhci_readl(xhci, addr) & PORT_POWER); } for(i=1; i<=g_num_u2_port; i++){ port_id=i+g_num_u3_port; addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(port_id-1 & 0xff); temp = xhci_readl(xhci, addr); temp = mtktest_xhci_port_state_to_neutral(temp); temp &= ~PORT_POWER; xhci_writel(xhci, temp, addr); while(xhci_readl(xhci, addr) & PORT_POWER); } #endif }
void xhci_shutdown(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); spin_lock_irq(&xhci->lock); xhci_halt(xhci); spin_unlock_irq(&xhci->lock); #if 0 xhci_cleanup_msix(xhci); #endif xhci_dbg(xhci, "xhci_shutdown completed - status = %x\n", xhci_readl(xhci, &xhci->op_regs->status)); }
/* called during probe() after chip reset completes */ static int xhci_mtk_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci; // struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval; u32 temp; hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2; /* xHCI private pointer was set in xhci_pci_probe for the second * registered roothub. */ xhci = hcd_to_xhci(hcd); xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); xhci->run_regs = hcd->regs + (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); xhci->hci_version = HC_VERSION(xhci->hcc_params); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); mtktest_xhci_print_registers(xhci); /* Make sure the HC is halted. */ retval = mtktest_xhci_halt(xhci); if (retval) goto error; xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ retval = mtktest_xhci_reset(xhci); if (retval) goto error; xhci_dbg(xhci, "Reset complete\n"); xhci_dbg(xhci, "Calling HCD init\n"); mtktest_setInitialReg(); /* Initialize HCD and host controller data structures. */ retval = mtktest_xhci_init(hcd); if (retval) goto error; xhci_dbg(xhci, "Called HCD init\n"); return retval; error: kfree(xhci); return retval; }
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) { struct ipq_xhci *ctx = &ipq; unsigned int ipq_base; int ret = 0; if ( index == 0 ) ipq_base = IPQ_XHCI_BASE_1; else ipq_base = IPQ_XHCI_BASE_2; ctx->hcd = (struct xhci_hccr *)ipq_base; ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); ret = board_usb_init(index, USB_INIT_HOST); if (ret != 0) { puts("Failed to initialize board for USB\n"); return ret; } ret = ipq_xhci_core_init(ctx, ipq_base); if (ret < 0) { puts("Failed to initialize xhci\n"); return ret; } *hccr = (struct xhci_hccr *)(ipq_base); *hcor = (struct xhci_hcor *)((uint32_t) *hccr + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n", (uint32_t)*hccr, (uint32_t)*hcor, (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); return ret; }
static void xhci_pci_init(struct udevice *dev, struct xhci_hccr **ret_hccr, struct xhci_hcor **ret_hcor) { struct xhci_hccr *hccr; struct xhci_hcor *hcor; u32 cmd; hccr = (struct xhci_hccr *)dm_pci_map_bar(dev, PCI_BASE_ADDRESS_0, PCI_REGION_MEM); hcor = (struct xhci_hcor *)((uintptr_t) hccr + HC_LENGTH(xhci_readl(&hccr->cr_capbase))); debug("XHCI-PCI init hccr 0x%x and hcor 0x%x hc_length %d\n", (u32)hccr, (u32)hcor, (u32)HC_LENGTH(xhci_readl(&hccr->cr_capbase))); *ret_hccr = hccr; *ret_hcor = hcor; /* enable busmaster */ dm_pci_read_config32(dev, PCI_COMMAND, &cmd); cmd |= PCI_COMMAND_MASTER; dm_pci_write_config32(dev, PCI_COMMAND, cmd); }
static void xhci_disable_port(struct usb_hcd *hcd, struct xhci_hcd *xhci, u16 wIndex, __le32 __iomem *addr, u32 port_status) { /* Don't allow the USB core to disable SuperSpeed ports. */ if (hcd->speed == HCD_USB3) { xhci_dbg(xhci, "Ignoring request to disable " "SuperSpeed port.\n"); return; } /* Write 1 to disable the port */ xhci_writel(xhci, port_status | PORT_PE, addr); port_status = xhci_readl(xhci, addr); xhci_dbg(xhci, "disable port, actual port %d status = 0x%x\n", wIndex, port_status); }
/* * Returns 0 if the status hasn't changed, or the number of bytes in buf. * Ports are 0-indexed from the HCD point of view, * and 1-indexed from the USB core pointer of view. * * Note that the status change bits will be cleared as soon as a port status * change event is generated, so we use the saved status from that event. */ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) { unsigned long flags; u32 temp, status; u32 mask; int i, retval; struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; bool reset_change = false; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; /* Initial status is no changes */ retval = (max_ports + 8) / 8; memset(buf, 0, retval); status = 0; mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < max_ports; i++) { temp = xhci_readl(xhci, port_array[i]); if (temp == 0xffffffff) { retval = -ENODEV; break; } if ((temp & mask) != 0 || (bus_state->port_c_suspend & 1 << i) || (bus_state->resume_done[i] && time_after_eq( jiffies, bus_state->resume_done[i]))) { buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } if ((temp & PORT_RC)) reset_change = true; } if (!status && !reset_change) { xhci_dbg(xhci, "%s: stopping port polling.\n", __func__); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); } spin_unlock_irqrestore(&xhci->lock, flags); return status ? retval : 0; }
static void xhci_print_command_reg(struct xhci_hcd *xhci) { u32 temp; temp = xhci_readl(xhci, &xhci->op_regs->command); xhci_dbg(xhci, "USBCMD 0x%x:\n", temp); xhci_dbg(xhci, " HC is %s\n", (temp & CMD_RUN) ? "running" : "being stopped"); xhci_dbg(xhci, " HC has %sfinished hard reset\n", (temp & CMD_RESET) ? "not " : ""); xhci_dbg(xhci, " Event Interrupts %s\n", (temp & CMD_EIE) ? "enabled " : "disabled"); xhci_dbg(xhci, " Host System Error Interrupts %s\n", (temp & CMD_EIE) ? "enabled " : "disabled"); xhci_dbg(xhci, " HC has %sfinished light reset\n", (temp & CMD_LRESET) ? "not " : ""); }
/* * Returns 0 if the status hasn't changed, or the number of bytes in buf. * Ports are 0-indexed from the HCD point of view, * and 1-indexed from the USB core pointer of view. * * Note that the status change bits will be cleared as soon as a port status * change event is generated, so we use the saved status from that event. */ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) { unsigned long flags; u32 temp, status; u32 mask; int i, retval; struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ports; u32 __iomem **port_array; struct xhci_bus_state *bus_state; if (hcd->speed == HCD_USB3) { ports = xhci->num_usb3_ports; port_array = xhci->usb3_ports; } else { ports = xhci->num_usb2_ports; port_array = xhci->usb2_ports; } bus_state = &xhci->bus_state[hcd_index(hcd)]; /* Initial status is no changes */ retval = (ports + 8) / 8; memset(buf, 0, retval); status = 0; mask = PORT_CSC | PORT_PEC | PORT_OCC; spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < ports; i++) { temp = xhci_readl(xhci, port_array[i]); if (temp == 0xffffffff) { retval = -ENODEV; break; } if ((temp & mask) != 0 || (bus_state->port_c_suspend & 1 << i) || (bus_state->resume_done[i] && time_after_eq( jiffies, bus_state->resume_done[i]))) { buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } } spin_unlock_irqrestore(&xhci->lock, flags); return status ? retval : 0; }
/* * Returns 0 if the status hasn't changed, or the number of bytes in buf. * Ports are 0-indexed from the HCD point of view, * and 1-indexed from the USB core pointer of view. * * Note that the status change bits will be cleared as soon as a port status * change event is generated, so we use the saved status from that event. */ int etxhci_hub_status_data(struct usb_hcd *hcd, char *buf) { unsigned long flags; u32 temp, status; u32 mask; int i, retval; struct xhci_hcd *xhci = hcd_to_xhci(hcd); int max_ports; __le32 __iomem **port_array; struct xhci_bus_state *bus_state; max_ports = xhci_get_ports(hcd, &port_array); bus_state = &xhci->bus_state[hcd_index(hcd)]; /* Initial status is no changes */ retval = (max_ports + 8) / 8; memset(buf, 0, retval); /* * Inform the usbcore about resume-in-progress by returning * a non-zero value even if there are no status changes. */ status = bus_state->resuming_ports; mask = PORT_CSC | PORT_PEC | PORT_OCC | PORT_PLC | PORT_WRC | PORT_CEC; spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < max_ports; i++) { temp = xhci_readl(xhci, port_array[i]); if (temp == 0xffffffff) { retval = -ENODEV; break; } if ((temp & mask) != 0 || (bus_state->port_c_connection & 1 << i) || (bus_state->port_c_suspend & 1 << i) || (bus_state->resume_done[i] && time_after_eq( jiffies, bus_state->resume_done[i]))) { buf[(i + 1) / 8] |= 1 << (i + 1) % 8; status = 1; } } spin_unlock_irqrestore(&xhci->lock, flags); return status ? retval : 0; }
static int handshake(struct xhci_hcd *xhci, void __iomem *ptr, u32 mask, u32 done, int usec) { u32 result; do { result = xhci_readl(xhci, ptr); if (result == ~(u32)0) return -ENODEV; result &= mask; if (result == done) return 0; udelay(1); usec--; } while (usec > 0); return -ETIMEDOUT; }
/** * Debug a transfer request block (TRB). */ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb) { u64 address; u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK; switch (type) { case TRB_TYPE(TRB_LINK): xhci_dbg(xhci, "Link TRB:\n"); xhci_print_trb_offsets(xhci, trb); address = trb->link.segment_ptr; xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address); xhci_dbg(xhci, "Interrupter target = 0x%x\n", GET_INTR_TARGET(trb->link.intr_target)); xhci_dbg(xhci, "Cycle bit = %u\n", (unsigned int) (trb->link.control & TRB_CYCLE)); xhci_dbg(xhci, "Toggle cycle bit = %u\n", (unsigned int) (trb->link.control & LINK_TOGGLE)); xhci_dbg(xhci, "No Snoop bit = %u\n", (unsigned int) (trb->link.control & TRB_NO_SNOOP)); break; case TRB_TYPE(TRB_TRANSFER): address = trb->trans_event.buffer; /* * FIXME: look at flags to figure out if it's an address or if * the data is directly in the buffer field. */ xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address); break; case TRB_TYPE(TRB_COMPLETION): address = trb->event_cmd.cmd_trb; xhci_dbg(xhci, "Command TRB pointer = %llu\n", address); xhci_dbg(xhci, "Completion status = %u\n", (unsigned int) GET_COMP_CODE(trb->event_cmd.status)); xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags); break; default: xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n", (unsigned int) type>>10); xhci_print_trb_offsets(xhci, trb); break; } }
static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) { u32 reg; int i; /* Before Resetting PHY, put Core in Reset */ reg = xhci_readl(&dwc3_reg->g_ctl); reg |= DWC3_GCTL_CORESOFTRESET; xhci_writel(&dwc3_reg->g_ctl, reg); for (i = 0; i < amlogic.u3_port_num; i++) { /* Assert USB3 PHY reset */ reg = xhci_readl(&dwc3_reg->g_usb3pipectl[i]); reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST; xhci_writel(&dwc3_reg->g_usb3pipectl[i], reg); } for (i = 0; i < amlogic.u2_port_num; i++) { /* Assert USB2 PHY reset */ reg = xhci_readl(&dwc3_reg->g_usb2phycfg[i]); reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST; xhci_writel(&dwc3_reg->g_usb2phycfg[i], reg); } amlogic_usb2_phy_init(amlogic.usb2_phy); amlogic_usb3_phy_init(amlogic.usb3_phy); mdelay(100); for (i = 0; i < amlogic.u3_port_num; i++) { /* Clear USB3 PHY reset */ reg = xhci_readl(&dwc3_reg->g_usb3pipectl[i]); reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST; xhci_writel(&dwc3_reg->g_usb3pipectl[i], reg); } for (i = 0; i < amlogic.u2_port_num; i++) { /* Clear USB2 PHY reset */ reg = xhci_readl(&dwc3_reg->g_usb2phycfg[i]); reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST; reg &= ~DWC3_GUSB2PHYCFG_SUSPHY; xhci_writel(&dwc3_reg->g_usb2phycfg[i], reg); } mdelay(100); /* After PHYs are stable we can take Core out of reset state */ reg = xhci_readl(&dwc3_reg->g_ctl); reg &= ~DWC3_GCTL_CORESOFTRESET; xhci_writel(&dwc3_reg->g_ctl, reg); }
int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) { int ret; struct xhci_hccr *cr; struct xhci_hcor *or; ret = get_uniphier_xhci_base(index, &cr); if (ret < 0) return ret; uniphier_xhci_reset(cr, 0); or = (void *)cr + HC_LENGTH(xhci_readl(&cr->cr_capbase)); *hccr = cr; *hcor = or; return 0; }
static void xhci_print_cap_regs(struct xhci_hcd *xhci) { u32 temp; xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs); temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase); xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, "CAPLENGTH: 0x%x\n", (unsigned int) HC_LENGTH(temp)); xhci_dbg(xhci, "HCIVERSION: 0x%x\n", (unsigned int) HC_VERSION(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Max device slots: %u\n", (unsigned int) HCS_MAX_SLOTS(temp)); xhci_dbg(xhci, " Max interrupters: %u\n", (unsigned int) HCS_MAX_INTRS(temp)); xhci_dbg(xhci, " Max ports: %u\n", (unsigned int) HCS_MAX_PORTS(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n", (unsigned int) temp); xhci_dbg(xhci, " Isoc scheduling threshold: %u\n", (unsigned int) HCS_IST(temp)); xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n", (unsigned int) HCS_ERST_MAX(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n", (unsigned int) HCS_U1_LATENCY(temp)); xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n", (unsigned int) HCS_U2_LATENCY(temp)); temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp); xhci_dbg(xhci, " HC generates %s bit addresses\n", HCC_64BIT_ADDR(temp) ? "64" : "32"); /* FIXME */ xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n"); temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off); xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK); }
/** * Generic function for queueing a command TRB on the command ring. * Check to make sure there's room on the command ring for one command TRB. * * @param ctrl Host controller data structure * @param ptr Pointer address to write in the first two fields (opt.) * @param slot_id Slot ID to encode in the flags field (opt.) * @param ep_index Endpoint index to encode in the flags field (opt.) * @param cmd Command type to enqueue * @return none */ void xhci_queue_command(struct xhci_ctrl *ctrl, u8 *ptr, u32 slot_id, u32 ep_index, trb_type cmd) { u32 fields[4]; u64 val_64 = (uintptr_t)ptr; BUG_ON(prepare_ring(ctrl, ctrl->cmd_ring, EP_STATE_RUNNING)); fields[0] = lower_32_bits(val_64); fields[1] = upper_32_bits(val_64); fields[2] = 0; fields[3] = TRB_TYPE(cmd) | EP_ID_FOR_TRB(ep_index) | SLOT_ID_FOR_TRB(slot_id) | ctrl->cmd_ring->cycle_state; queue_trb(ctrl, ctrl->cmd_ring, false, fields); /* Ring the command ring doorbell */ xhci_writel(&ctrl->dba->doorbell[0], DB_VALUE_HOST); xhci_readl(&ctrl->dba->doorbell[0]); }
static int xhci_usb_probe(struct udevice *dev) { struct zynqmp_xhci_platdata *plat = dev_get_platdata(dev); struct zynqmp_xhci *ctx = dev_get_priv(dev); struct xhci_hcor *hcor; int ret; ctx->hcd = (struct xhci_hccr *)plat->hcd_base; ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); ret = zynqmp_xhci_core_init(ctx); if (ret) { puts("XHCI: failed to initialize controller\n"); return -EINVAL; } hcor = (struct xhci_hcor *)((ulong)ctx->hcd + HC_LENGTH(xhci_readl(&ctx->hcd->cr_capbase))); return xhci_register(dev, ctx->hcd, hcor); }
static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue, u16 wIndex, u32 __iomem *addr, u32 port_status) { char *port_change_bit; u32 status; switch (wValue) { case USB_PORT_FEAT_C_RESET: status = PORT_RC; port_change_bit = "reset"; break; case USB_PORT_FEAT_C_CONNECTION: status = PORT_CSC; #ifdef CONFIG_UBICOM32 status |= PORT_PLC; #endif port_change_bit = "connect"; break; case USB_PORT_FEAT_C_OVER_CURRENT: status = PORT_OCC; port_change_bit = "over-current"; break; case USB_PORT_FEAT_C_ENABLE: status = PORT_PEC; port_change_bit = "enable/disable"; break; case USB_PORT_FEAT_C_SUSPEND: status = PORT_PLC; port_change_bit = "suspend/resume"; break; default: /* Should never happen */ return; } /* Change bits are all write 1 to clear */ xhci_writel(xhci, port_status | status, addr); port_status = xhci_readl(xhci, addr); xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n", port_change_bit, wIndex, port_status); }
static ssize_t config_imod_show(struct device *pdev, struct device_attribute *attr, char *buff) { struct usb_hcd *hcd = dev_get_drvdata(pdev); struct xhci_hcd *xhci; struct mxhci_hsic_hcd *mxhci; u32 temp; unsigned long flags; mxhci = hcd_to_hsic(hcd); xhci = hcd_to_xhci(hcd); if (mxhci->in_lpm) return -EACCES; spin_lock_irqsave(&xhci->lock, flags); temp = xhci_readl(xhci, &xhci->ir_set->irq_control) & ER_IRQ_INTERVAL_MASK; spin_unlock_irqrestore(&xhci->lock, flags); return snprintf(buff, PAGE_SIZE, "%08x\n", temp); }
/* * Returns 0 if the status hasn't changed, or the number of bytes in buf. * Ports are 0-indexed from the HCD point of view, * and 1-indexed from the USB core pointer of view. * xHCI instances can have up to 127 ports, so FIXME if you see more than 15. * * Note that the status change bits will be cleared as soon as a port status * change event is generated, so we use the saved status from that event. */ int xhci_hub_status_data(struct usb_hcd *hcd, char *buf) { unsigned long flags; u32 temp, status; int i, retval; struct xhci_hcd *xhci = hcd_to_xhci(hcd); int ports; u32 __iomem *addr; ports = HCS_MAX_PORTS(xhci->hcs_params1); /* Initial status is no changes */ buf[0] = 0; status = 0; if (ports > 7) { buf[1] = 0; retval = 2; } else { retval = 1; } spin_lock_irqsave(&xhci->lock, flags); /* For each port, did anything change? If so, set that bit in buf. */ for (i = 0; i < ports; i++) { addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*i; temp = xhci_readl(xhci, addr); if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) { if (i < 7) buf[0] |= 1 << (i + 1); else buf[1] |= 1 << (i - 7); status = 1; } } spin_unlock_irqrestore(&xhci->lock, flags); return status ? retval : 0; }
static void xhci_print_ports(struct xhci_hcd *xhci) { u32 __iomem *addr; int i, j; int ports; char *names[NUM_PORT_REGS] = { "status", "power", "link", "reserved", }; ports = HCS_MAX_PORTS(xhci->hcs_params1); addr = &xhci->op_regs->port_status_base; for (i = 0; i < ports; i++) { for (j = 0; j < NUM_PORT_REGS; ++j) { xhci_dbg(xhci, "%p port %s reg = 0x%x\n", addr, names[j], (unsigned int) xhci_readl(xhci, addr)); addr++; } } }
static void amlogic_usb3_phy_init(struct usb_aml_regs *phy) { union usb_r1_t r1 = {.d32 = 0}; int i; if (amlogic.u3_port_num == 0) { for (i = 0; i < 1; i++) { usb_aml_reg = (struct usb_aml_regs *)((ulong)phy+i*PHY_REGISTER_SIZE); r1.d32 = usb_aml_reg->usb_r1; r1.b.u3h_fladj_30mhz_reg = 0x20; usb_aml_reg->usb_r1 = r1.d32; } } return; } static void amlogic_usb2_phy_exit(struct u2p_aml_regs *phy) { return; } static void amlogic_usb3_phy_exit(struct usb_aml_regs *phy) { return; } void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) { u32 reg; reg = xhci_readl(&dwc3_reg->g_ctl); reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG)); reg |= DWC3_GCTL_PRTCAPDIR(mode); xhci_writel(&dwc3_reg->g_ctl, reg); }
/* called during probe() after chip reset completes */ static int xhci_pci_setup(struct usb_hcd *hcd) { struct xhci_hcd *xhci = hcd_to_xhci(hcd); struct pci_dev *pdev = to_pci_dev(hcd->self.controller); int retval; xhci->cap_regs = hcd->regs; xhci->op_regs = hcd->regs + HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase)); xhci->run_regs = hcd->regs + (xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1); xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2); xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3); xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params); xhci_print_registers(xhci); /* Make sure the HC is halted. */ retval = xhci_halt(xhci); if (retval) return retval; xhci_dbg(xhci, "Resetting HCD\n"); /* Reset the internal HC memory state and registers. */ retval = xhci_reset(xhci); if (retval) return retval; xhci_dbg(xhci, "Reset complete\n"); xhci_dbg(xhci, "Calling HCD init\n"); /* Initialize HCD and host controller data structures. */ retval = xhci_init(hcd); if (retval) return retval; xhci_dbg(xhci, "Called HCD init\n"); pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn); xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn); /* Find any debug ports */ return xhci_pci_reinit(xhci, pdev); }