12d2358acSDan Murphy /* 22d2358acSDan Murphy * OMAP USB HOST xHCI Controller 32d2358acSDan Murphy * 42d2358acSDan Murphy * (C) Copyright 2013 52d2358acSDan Murphy * Texas Instruments, <www.ti.com> 62d2358acSDan Murphy * 72d2358acSDan Murphy * Author: Dan Murphy <dmurphy@ti.com> 82d2358acSDan Murphy * 92d2358acSDan Murphy * SPDX-License-Identifier: GPL-2.0+ 102d2358acSDan Murphy */ 112d2358acSDan Murphy 122d2358acSDan Murphy #include <common.h> 132d2358acSDan Murphy #include <usb.h> 142d2358acSDan Murphy #include <asm-generic/errno.h> 152d2358acSDan Murphy #include <asm/omap_common.h> 162d2358acSDan Murphy #include <asm/arch/cpu.h> 172d2358acSDan Murphy #include <asm/arch/sys_proto.h> 182d2358acSDan Murphy 192d2358acSDan Murphy #include <linux/compat.h> 202d2358acSDan Murphy #include <linux/usb/dwc3.h> 2141b667b8SDan Murphy #include <linux/usb/xhci-omap.h> 222d2358acSDan Murphy 232d2358acSDan Murphy #include "xhci.h" 242d2358acSDan Murphy 252d2358acSDan Murphy /* Declare global data pointer */ 262d2358acSDan Murphy DECLARE_GLOBAL_DATA_PTR; 272d2358acSDan Murphy 282d2358acSDan Murphy static struct omap_xhci omap; 292d2358acSDan Murphy 307e575c46STroy Kisky inline int __board_usb_init(int index, enum usb_init_type init) 312d2358acSDan Murphy { 322d2358acSDan Murphy return 0; 332d2358acSDan Murphy } 347e575c46STroy Kisky int board_usb_init(int index, enum usb_init_type init) 35b2168211SDan Murphy __attribute__((weak, alias("__board_usb_init"))); 362d2358acSDan Murphy 372d2358acSDan Murphy static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) 382d2358acSDan Murphy { 392d2358acSDan Murphy clrsetbits_le32(&dwc3_reg->g_ctl, 402d2358acSDan Murphy DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG), 412d2358acSDan Murphy DWC3_GCTL_PRTCAPDIR(mode)); 422d2358acSDan Murphy } 432d2358acSDan Murphy 442d2358acSDan Murphy static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) 452d2358acSDan Murphy { 462d2358acSDan Murphy /* Before Resetting PHY, put Core in Reset */ 472d2358acSDan Murphy setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); 482d2358acSDan Murphy 49ba55453cSDan Murphy omap_reset_usb_phy(dwc3_reg); 502d2358acSDan Murphy 512d2358acSDan Murphy /* After PHYs are stable we can take Core out of reset state */ 522d2358acSDan Murphy clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); 532d2358acSDan Murphy } 542d2358acSDan Murphy 552d2358acSDan Murphy static int dwc3_core_init(struct dwc3 *dwc3_reg) 562d2358acSDan Murphy { 572d2358acSDan Murphy u32 reg; 582d2358acSDan Murphy u32 revision; 592d2358acSDan Murphy unsigned int dwc3_hwparams1; 602d2358acSDan Murphy 612d2358acSDan Murphy revision = readl(&dwc3_reg->g_snpsid); 622d2358acSDan Murphy /* This should read as U3 followed by revision number */ 632d2358acSDan Murphy if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) { 642d2358acSDan Murphy puts("this is not a DesignWare USB3 DRD Core\n"); 652d2358acSDan Murphy return -1; 662d2358acSDan Murphy } 672d2358acSDan Murphy 682d2358acSDan Murphy dwc3_core_soft_reset(dwc3_reg); 692d2358acSDan Murphy 702d2358acSDan Murphy dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1); 712d2358acSDan Murphy 722d2358acSDan Murphy reg = readl(&dwc3_reg->g_ctl); 732d2358acSDan Murphy reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 742d2358acSDan Murphy reg &= ~DWC3_GCTL_DISSCRAMBLE; 752d2358acSDan Murphy switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) { 762d2358acSDan Murphy case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 772d2358acSDan Murphy reg &= ~DWC3_GCTL_DSBLCLKGTNG; 782d2358acSDan Murphy break; 792d2358acSDan Murphy default: 802d2358acSDan Murphy debug("No power optimization available\n"); 812d2358acSDan Murphy } 822d2358acSDan Murphy 832d2358acSDan Murphy /* 842d2358acSDan Murphy * WORKAROUND: DWC3 revisions <1.90a have a bug 852d2358acSDan Murphy * where the device can fail to connect at SuperSpeed 862d2358acSDan Murphy * and falls back to high-speed mode which causes 872d2358acSDan Murphy * the device to enter a Connect/Disconnect loop 882d2358acSDan Murphy */ 892d2358acSDan Murphy if ((revision & DWC3_REVISION_MASK) < 0x190a) 902d2358acSDan Murphy reg |= DWC3_GCTL_U2RSTECN; 912d2358acSDan Murphy 922d2358acSDan Murphy writel(reg, &dwc3_reg->g_ctl); 932d2358acSDan Murphy 942d2358acSDan Murphy return 0; 952d2358acSDan Murphy } 962d2358acSDan Murphy 972d2358acSDan Murphy static int omap_xhci_core_init(struct omap_xhci *omap) 982d2358acSDan Murphy { 992d2358acSDan Murphy int ret = 0; 1002d2358acSDan Murphy 101*26707d9eSFelipe Balbi usb_phy_power(1); 102834e91afSDan Murphy omap_enable_phy(omap); 1032d2358acSDan Murphy 1042d2358acSDan Murphy ret = dwc3_core_init(omap->dwc3_reg); 1052d2358acSDan Murphy if (ret) { 1062d2358acSDan Murphy debug("%s:failed to initialize core\n", __func__); 1072d2358acSDan Murphy return ret; 1082d2358acSDan Murphy } 1092d2358acSDan Murphy 1102d2358acSDan Murphy /* We are hard-coding DWC3 core to Host Mode */ 1112d2358acSDan Murphy dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 1122d2358acSDan Murphy 1132d2358acSDan Murphy return ret; 1142d2358acSDan Murphy } 1152d2358acSDan Murphy 1162d2358acSDan Murphy static void omap_xhci_core_exit(struct omap_xhci *omap) 1172d2358acSDan Murphy { 118834e91afSDan Murphy usb_phy_power(0); 1192d2358acSDan Murphy } 1202d2358acSDan Murphy 1212d2358acSDan Murphy int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) 1222d2358acSDan Murphy { 1232d2358acSDan Murphy struct omap_xhci *ctx = &omap; 1242d2358acSDan Murphy int ret = 0; 1252d2358acSDan Murphy 1262d2358acSDan Murphy ctx->hcd = (struct xhci_hccr *)OMAP_XHCI_BASE; 1272d2358acSDan Murphy ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 1282d2358acSDan Murphy ctx->usb3_phy = (struct omap_usb3_phy *)OMAP_OCP1_SCP_BASE; 1292d2358acSDan Murphy ctx->otg_wrapper = (struct omap_dwc_wrapper *)OMAP_OTG_WRAPPER_BASE; 1302d2358acSDan Murphy 131b2168211SDan Murphy ret = board_usb_init(index, USB_INIT_HOST); 1322d2358acSDan Murphy if (ret != 0) { 1332d2358acSDan Murphy puts("Failed to initialize board for USB\n"); 1342d2358acSDan Murphy return ret; 1352d2358acSDan Murphy } 1362d2358acSDan Murphy 1372d2358acSDan Murphy ret = omap_xhci_core_init(ctx); 1382d2358acSDan Murphy if (ret < 0) { 1392d2358acSDan Murphy puts("Failed to initialize xhci\n"); 1402d2358acSDan Murphy return ret; 1412d2358acSDan Murphy } 1422d2358acSDan Murphy 1432d2358acSDan Murphy *hccr = (struct xhci_hccr *)(OMAP_XHCI_BASE); 1442d2358acSDan Murphy *hcor = (struct xhci_hcor *)((uint32_t) *hccr 1452d2358acSDan Murphy + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 1462d2358acSDan Murphy 1472d2358acSDan Murphy debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n", 1482d2358acSDan Murphy (uint32_t)*hccr, (uint32_t)*hcor, 1492d2358acSDan Murphy (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 1502d2358acSDan Murphy 1512d2358acSDan Murphy return ret; 1522d2358acSDan Murphy } 1532d2358acSDan Murphy 1542d2358acSDan Murphy void xhci_hcd_stop(int index) 1552d2358acSDan Murphy { 1562d2358acSDan Murphy struct omap_xhci *ctx = &omap; 1572d2358acSDan Murphy 1582d2358acSDan Murphy omap_xhci_core_exit(ctx); 1592d2358acSDan Murphy } 160