1 /* 2 * OMAP USB HOST xHCI Controller 3 * 4 * (C) Copyright 2013 5 * Texas Instruments, <www.ti.com> 6 * 7 * Author: Dan Murphy <dmurphy@ti.com> 8 * 9 * SPDX-License-Identifier: GPL-2.0+ 10 */ 11 12 #include <common.h> 13 #include <usb.h> 14 #include <asm-generic/errno.h> 15 #include <asm/omap_common.h> 16 #include <asm/arch/cpu.h> 17 #include <asm/arch/sys_proto.h> 18 19 #include <linux/compat.h> 20 #include <linux/usb/dwc3.h> 21 #include <linux/usb/xhci-omap.h> 22 23 #include "xhci.h" 24 25 /* Declare global data pointer */ 26 DECLARE_GLOBAL_DATA_PTR; 27 28 static struct omap_xhci omap; 29 30 inline int __board_usb_init(int index, enum usb_init_type init) 31 { 32 return 0; 33 } 34 int board_usb_init(int index, enum usb_init_type init) 35 __attribute__((weak, alias("__board_usb_init"))); 36 37 static void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) 38 { 39 clrsetbits_le32(&dwc3_reg->g_ctl, 40 DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG), 41 DWC3_GCTL_PRTCAPDIR(mode)); 42 } 43 44 static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) 45 { 46 /* Before Resetting PHY, put Core in Reset */ 47 setbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); 48 49 omap_reset_usb_phy(dwc3_reg); 50 51 /* After PHYs are stable we can take Core out of reset state */ 52 clrbits_le32(&dwc3_reg->g_ctl, DWC3_GCTL_CORESOFTRESET); 53 } 54 55 static int dwc3_core_init(struct dwc3 *dwc3_reg) 56 { 57 u32 reg; 58 u32 revision; 59 unsigned int dwc3_hwparams1; 60 61 revision = readl(&dwc3_reg->g_snpsid); 62 /* This should read as U3 followed by revision number */ 63 if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) { 64 puts("this is not a DesignWare USB3 DRD Core\n"); 65 return -1; 66 } 67 68 dwc3_core_soft_reset(dwc3_reg); 69 70 dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1); 71 72 reg = readl(&dwc3_reg->g_ctl); 73 reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 74 reg &= ~DWC3_GCTL_DISSCRAMBLE; 75 switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) { 76 case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 77 reg &= ~DWC3_GCTL_DSBLCLKGTNG; 78 break; 79 default: 80 debug("No power optimization available\n"); 81 } 82 83 /* 84 * WORKAROUND: DWC3 revisions <1.90a have a bug 85 * where the device can fail to connect at SuperSpeed 86 * and falls back to high-speed mode which causes 87 * the device to enter a Connect/Disconnect loop 88 */ 89 if ((revision & DWC3_REVISION_MASK) < 0x190a) 90 reg |= DWC3_GCTL_U2RSTECN; 91 92 writel(reg, &dwc3_reg->g_ctl); 93 94 return 0; 95 } 96 97 static int omap_xhci_core_init(struct omap_xhci *omap) 98 { 99 int ret = 0; 100 101 usb_phy_power(1); 102 omap_enable_phy(omap); 103 104 ret = dwc3_core_init(omap->dwc3_reg); 105 if (ret) { 106 debug("%s:failed to initialize core\n", __func__); 107 return ret; 108 } 109 110 /* We are hard-coding DWC3 core to Host Mode */ 111 dwc3_set_mode(omap->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 112 113 return ret; 114 } 115 116 static void omap_xhci_core_exit(struct omap_xhci *omap) 117 { 118 usb_phy_power(0); 119 } 120 121 int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) 122 { 123 struct omap_xhci *ctx = &omap; 124 int ret = 0; 125 126 ctx->hcd = (struct xhci_hccr *)OMAP_XHCI_BASE; 127 ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 128 ctx->usb3_phy = (struct omap_usb3_phy *)OMAP_OCP1_SCP_BASE; 129 ctx->otg_wrapper = (struct omap_dwc_wrapper *)OMAP_OTG_WRAPPER_BASE; 130 131 ret = board_usb_init(index, USB_INIT_HOST); 132 if (ret != 0) { 133 puts("Failed to initialize board for USB\n"); 134 return ret; 135 } 136 137 ret = omap_xhci_core_init(ctx); 138 if (ret < 0) { 139 puts("Failed to initialize xhci\n"); 140 return ret; 141 } 142 143 *hccr = (struct xhci_hccr *)(OMAP_XHCI_BASE); 144 *hcor = (struct xhci_hcor *)((uint32_t) *hccr 145 + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 146 147 debug("omap-xhci: init hccr %x and hcor %x hc_length %d\n", 148 (uint32_t)*hccr, (uint32_t)*hcor, 149 (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 150 151 return ret; 152 } 153 154 void xhci_hcd_stop(int index) 155 { 156 struct omap_xhci *ctx = &omap; 157 158 omap_xhci_core_exit(ctx); 159 } 160