1*13194f3bSVivek Gautam /* 2*13194f3bSVivek Gautam * SAMSUNG EXYNOS5 USB HOST XHCI Controller 3*13194f3bSVivek Gautam * 4*13194f3bSVivek Gautam * Copyright (C) 2012 Samsung Electronics Co.Ltd 5*13194f3bSVivek Gautam * Vivek Gautam <gautam.vivek@samsung.com> 6*13194f3bSVivek Gautam * Vikas Sajjan <vikas.sajjan@samsung.com> 7*13194f3bSVivek Gautam * 8*13194f3bSVivek Gautam * SPDX-License-Identifier: GPL-2.0+ 9*13194f3bSVivek Gautam */ 10*13194f3bSVivek Gautam 11*13194f3bSVivek Gautam /* 12*13194f3bSVivek Gautam * This file is a conglomeration for DWC3-init sequence and further 13*13194f3bSVivek Gautam * exynos5 specific PHY-init sequence. 14*13194f3bSVivek Gautam */ 15*13194f3bSVivek Gautam 16*13194f3bSVivek Gautam #include <common.h> 17*13194f3bSVivek Gautam #include <fdtdec.h> 18*13194f3bSVivek Gautam #include <libfdt.h> 19*13194f3bSVivek Gautam #include <malloc.h> 20*13194f3bSVivek Gautam #include <usb.h> 21*13194f3bSVivek Gautam #include <watchdog.h> 22*13194f3bSVivek Gautam #include <asm/arch/cpu.h> 23*13194f3bSVivek Gautam #include <asm/arch/power.h> 24*13194f3bSVivek Gautam #include <asm/arch/xhci-exynos.h> 25*13194f3bSVivek Gautam #include <asm-generic/errno.h> 26*13194f3bSVivek Gautam #include <linux/compat.h> 27*13194f3bSVivek Gautam #include <linux/usb/dwc3.h> 28*13194f3bSVivek Gautam 29*13194f3bSVivek Gautam #include "xhci.h" 30*13194f3bSVivek Gautam 31*13194f3bSVivek Gautam /* Declare global data pointer */ 32*13194f3bSVivek Gautam DECLARE_GLOBAL_DATA_PTR; 33*13194f3bSVivek Gautam 34*13194f3bSVivek Gautam /** 35*13194f3bSVivek Gautam * Contains pointers to register base addresses 36*13194f3bSVivek Gautam * for the usb controller. 37*13194f3bSVivek Gautam */ 38*13194f3bSVivek Gautam struct exynos_xhci { 39*13194f3bSVivek Gautam struct exynos_usb3_phy *usb3_phy; 40*13194f3bSVivek Gautam struct xhci_hccr *hcd; 41*13194f3bSVivek Gautam struct dwc3 *dwc3_reg; 42*13194f3bSVivek Gautam }; 43*13194f3bSVivek Gautam 44*13194f3bSVivek Gautam static struct exynos_xhci exynos; 45*13194f3bSVivek Gautam 46*13194f3bSVivek Gautam #ifdef CONFIG_OF_CONTROL 47*13194f3bSVivek Gautam static int exynos_usb3_parse_dt(const void *blob, struct exynos_xhci *exynos) 48*13194f3bSVivek Gautam { 49*13194f3bSVivek Gautam fdt_addr_t addr; 50*13194f3bSVivek Gautam unsigned int node; 51*13194f3bSVivek Gautam int depth; 52*13194f3bSVivek Gautam 53*13194f3bSVivek Gautam node = fdtdec_next_compatible(blob, 0, COMPAT_SAMSUNG_EXYNOS5_XHCI); 54*13194f3bSVivek Gautam if (node <= 0) { 55*13194f3bSVivek Gautam debug("XHCI: Can't get device node for xhci\n"); 56*13194f3bSVivek Gautam return -ENODEV; 57*13194f3bSVivek Gautam } 58*13194f3bSVivek Gautam 59*13194f3bSVivek Gautam /* 60*13194f3bSVivek Gautam * Get the base address for XHCI controller from the device node 61*13194f3bSVivek Gautam */ 62*13194f3bSVivek Gautam addr = fdtdec_get_addr(blob, node, "reg"); 63*13194f3bSVivek Gautam if (addr == FDT_ADDR_T_NONE) { 64*13194f3bSVivek Gautam debug("Can't get the XHCI register base address\n"); 65*13194f3bSVivek Gautam return -ENXIO; 66*13194f3bSVivek Gautam } 67*13194f3bSVivek Gautam exynos->hcd = (struct xhci_hccr *)addr; 68*13194f3bSVivek Gautam 69*13194f3bSVivek Gautam depth = 0; 70*13194f3bSVivek Gautam node = fdtdec_next_compatible_subnode(blob, node, 71*13194f3bSVivek Gautam COMPAT_SAMSUNG_EXYNOS5_USB3_PHY, &depth); 72*13194f3bSVivek Gautam if (node <= 0) { 73*13194f3bSVivek Gautam debug("XHCI: Can't get device node for usb3-phy controller\n"); 74*13194f3bSVivek Gautam return -ENODEV; 75*13194f3bSVivek Gautam } 76*13194f3bSVivek Gautam 77*13194f3bSVivek Gautam /* 78*13194f3bSVivek Gautam * Get the base address for usbphy from the device node 79*13194f3bSVivek Gautam */ 80*13194f3bSVivek Gautam exynos->usb3_phy = (struct exynos_usb3_phy *)fdtdec_get_addr(blob, node, 81*13194f3bSVivek Gautam "reg"); 82*13194f3bSVivek Gautam if (exynos->usb3_phy == NULL) { 83*13194f3bSVivek Gautam debug("Can't get the usbphy register address\n"); 84*13194f3bSVivek Gautam return -ENXIO; 85*13194f3bSVivek Gautam } 86*13194f3bSVivek Gautam 87*13194f3bSVivek Gautam return 0; 88*13194f3bSVivek Gautam } 89*13194f3bSVivek Gautam #endif 90*13194f3bSVivek Gautam 91*13194f3bSVivek Gautam static void exynos5_usb3_phy_init(struct exynos_usb3_phy *phy) 92*13194f3bSVivek Gautam { 93*13194f3bSVivek Gautam u32 reg; 94*13194f3bSVivek Gautam 95*13194f3bSVivek Gautam /* enabling usb_drd phy */ 96*13194f3bSVivek Gautam set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_EN); 97*13194f3bSVivek Gautam 98*13194f3bSVivek Gautam /* Reset USB 3.0 PHY */ 99*13194f3bSVivek Gautam writel(0x0, &phy->phy_reg0); 100*13194f3bSVivek Gautam 101*13194f3bSVivek Gautam clrbits_le32(&phy->phy_param0, 102*13194f3bSVivek Gautam /* Select PHY CLK source */ 103*13194f3bSVivek Gautam PHYPARAM0_REF_USE_PAD | 104*13194f3bSVivek Gautam /* Set Loss-of-Signal Detector sensitivity */ 105*13194f3bSVivek Gautam PHYPARAM0_REF_LOSLEVEL_MASK); 106*13194f3bSVivek Gautam setbits_le32(&phy->phy_param0, PHYPARAM0_REF_LOSLEVEL); 107*13194f3bSVivek Gautam 108*13194f3bSVivek Gautam writel(0x0, &phy->phy_resume); 109*13194f3bSVivek Gautam 110*13194f3bSVivek Gautam /* 111*13194f3bSVivek Gautam * Setting the Frame length Adj value[6:1] to default 0x20 112*13194f3bSVivek Gautam * See xHCI 1.0 spec, 5.2.4 113*13194f3bSVivek Gautam */ 114*13194f3bSVivek Gautam setbits_le32(&phy->link_system, 115*13194f3bSVivek Gautam LINKSYSTEM_XHCI_VERSION_CONTROL | 116*13194f3bSVivek Gautam LINKSYSTEM_FLADJ(0x20)); 117*13194f3bSVivek Gautam 118*13194f3bSVivek Gautam /* Set Tx De-Emphasis level */ 119*13194f3bSVivek Gautam clrbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH_MASK); 120*13194f3bSVivek Gautam setbits_le32(&phy->phy_param1, PHYPARAM1_PCS_TXDEEMPH); 121*13194f3bSVivek Gautam 122*13194f3bSVivek Gautam setbits_le32(&phy->phy_batchg, PHYBATCHG_UTMI_CLKSEL); 123*13194f3bSVivek Gautam 124*13194f3bSVivek Gautam /* PHYTEST POWERDOWN Control */ 125*13194f3bSVivek Gautam clrbits_le32(&phy->phy_test, 126*13194f3bSVivek Gautam PHYTEST_POWERDOWN_SSP | 127*13194f3bSVivek Gautam PHYTEST_POWERDOWN_HSP); 128*13194f3bSVivek Gautam 129*13194f3bSVivek Gautam /* UTMI Power Control */ 130*13194f3bSVivek Gautam writel(PHYUTMI_OTGDISABLE, &phy->phy_utmi); 131*13194f3bSVivek Gautam 132*13194f3bSVivek Gautam /* Use core clock from main PLL */ 133*13194f3bSVivek Gautam reg = PHYCLKRST_REFCLKSEL_EXT_REFCLK | 134*13194f3bSVivek Gautam /* Default 24Mhz crystal clock */ 135*13194f3bSVivek Gautam PHYCLKRST_FSEL(FSEL_CLKSEL_24M) | 136*13194f3bSVivek Gautam PHYCLKRST_MPLL_MULTIPLIER_24MHZ_REF | 137*13194f3bSVivek Gautam PHYCLKRST_SSC_REFCLKSEL(0x88) | 138*13194f3bSVivek Gautam /* Force PortReset of PHY */ 139*13194f3bSVivek Gautam PHYCLKRST_PORTRESET | 140*13194f3bSVivek Gautam /* Digital power supply in normal operating mode */ 141*13194f3bSVivek Gautam PHYCLKRST_RETENABLEN | 142*13194f3bSVivek Gautam /* Enable ref clock for SS function */ 143*13194f3bSVivek Gautam PHYCLKRST_REF_SSP_EN | 144*13194f3bSVivek Gautam /* Enable spread spectrum */ 145*13194f3bSVivek Gautam PHYCLKRST_SSC_EN | 146*13194f3bSVivek Gautam /* Power down HS Bias and PLL blocks in suspend mode */ 147*13194f3bSVivek Gautam PHYCLKRST_COMMONONN; 148*13194f3bSVivek Gautam 149*13194f3bSVivek Gautam writel(reg, &phy->phy_clk_rst); 150*13194f3bSVivek Gautam 151*13194f3bSVivek Gautam /* giving time to Phy clock to settle before resetting */ 152*13194f3bSVivek Gautam udelay(10); 153*13194f3bSVivek Gautam 154*13194f3bSVivek Gautam reg &= ~PHYCLKRST_PORTRESET; 155*13194f3bSVivek Gautam writel(reg, &phy->phy_clk_rst); 156*13194f3bSVivek Gautam } 157*13194f3bSVivek Gautam 158*13194f3bSVivek Gautam static void exynos5_usb3_phy_exit(struct exynos_usb3_phy *phy) 159*13194f3bSVivek Gautam { 160*13194f3bSVivek Gautam setbits_le32(&phy->phy_utmi, 161*13194f3bSVivek Gautam PHYUTMI_OTGDISABLE | 162*13194f3bSVivek Gautam PHYUTMI_FORCESUSPEND | 163*13194f3bSVivek Gautam PHYUTMI_FORCESLEEP); 164*13194f3bSVivek Gautam 165*13194f3bSVivek Gautam clrbits_le32(&phy->phy_clk_rst, 166*13194f3bSVivek Gautam PHYCLKRST_REF_SSP_EN | 167*13194f3bSVivek Gautam PHYCLKRST_SSC_EN | 168*13194f3bSVivek Gautam PHYCLKRST_COMMONONN); 169*13194f3bSVivek Gautam 170*13194f3bSVivek Gautam /* PHYTEST POWERDOWN Control to remove leakage current */ 171*13194f3bSVivek Gautam setbits_le32(&phy->phy_test, 172*13194f3bSVivek Gautam PHYTEST_POWERDOWN_SSP | 173*13194f3bSVivek Gautam PHYTEST_POWERDOWN_HSP); 174*13194f3bSVivek Gautam 175*13194f3bSVivek Gautam /* disabling usb_drd phy */ 176*13194f3bSVivek Gautam set_usbdrd_phy_ctrl(POWER_USB_DRD_PHY_CTRL_DISABLE); 177*13194f3bSVivek Gautam } 178*13194f3bSVivek Gautam 179*13194f3bSVivek Gautam void dwc3_set_mode(struct dwc3 *dwc3_reg, u32 mode) 180*13194f3bSVivek Gautam { 181*13194f3bSVivek Gautam clrsetbits_le32(&dwc3_reg->g_ctl, 182*13194f3bSVivek Gautam DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG), 183*13194f3bSVivek Gautam DWC3_GCTL_PRTCAPDIR(mode)); 184*13194f3bSVivek Gautam } 185*13194f3bSVivek Gautam 186*13194f3bSVivek Gautam static void dwc3_core_soft_reset(struct dwc3 *dwc3_reg) 187*13194f3bSVivek Gautam { 188*13194f3bSVivek Gautam /* Before Resetting PHY, put Core in Reset */ 189*13194f3bSVivek Gautam setbits_le32(&dwc3_reg->g_ctl, 190*13194f3bSVivek Gautam DWC3_GCTL_CORESOFTRESET); 191*13194f3bSVivek Gautam 192*13194f3bSVivek Gautam /* Assert USB3 PHY reset */ 193*13194f3bSVivek Gautam setbits_le32(&dwc3_reg->g_usb3pipectl[0], 194*13194f3bSVivek Gautam DWC3_GUSB3PIPECTL_PHYSOFTRST); 195*13194f3bSVivek Gautam 196*13194f3bSVivek Gautam /* Assert USB2 PHY reset */ 197*13194f3bSVivek Gautam setbits_le32(&dwc3_reg->g_usb2phycfg, 198*13194f3bSVivek Gautam DWC3_GUSB2PHYCFG_PHYSOFTRST); 199*13194f3bSVivek Gautam 200*13194f3bSVivek Gautam mdelay(100); 201*13194f3bSVivek Gautam 202*13194f3bSVivek Gautam /* Clear USB3 PHY reset */ 203*13194f3bSVivek Gautam clrbits_le32(&dwc3_reg->g_usb3pipectl[0], 204*13194f3bSVivek Gautam DWC3_GUSB3PIPECTL_PHYSOFTRST); 205*13194f3bSVivek Gautam 206*13194f3bSVivek Gautam /* Clear USB2 PHY reset */ 207*13194f3bSVivek Gautam clrbits_le32(&dwc3_reg->g_usb2phycfg, 208*13194f3bSVivek Gautam DWC3_GUSB2PHYCFG_PHYSOFTRST); 209*13194f3bSVivek Gautam 210*13194f3bSVivek Gautam /* After PHYs are stable we can take Core out of reset state */ 211*13194f3bSVivek Gautam clrbits_le32(&dwc3_reg->g_ctl, 212*13194f3bSVivek Gautam DWC3_GCTL_CORESOFTRESET); 213*13194f3bSVivek Gautam } 214*13194f3bSVivek Gautam 215*13194f3bSVivek Gautam static int dwc3_core_init(struct dwc3 *dwc3_reg) 216*13194f3bSVivek Gautam { 217*13194f3bSVivek Gautam u32 reg; 218*13194f3bSVivek Gautam u32 revision; 219*13194f3bSVivek Gautam unsigned int dwc3_hwparams1; 220*13194f3bSVivek Gautam 221*13194f3bSVivek Gautam revision = readl(&dwc3_reg->g_snpsid); 222*13194f3bSVivek Gautam /* This should read as U3 followed by revision number */ 223*13194f3bSVivek Gautam if ((revision & DWC3_GSNPSID_MASK) != 0x55330000) { 224*13194f3bSVivek Gautam puts("this is not a DesignWare USB3 DRD Core\n"); 225*13194f3bSVivek Gautam return -EINVAL; 226*13194f3bSVivek Gautam } 227*13194f3bSVivek Gautam 228*13194f3bSVivek Gautam dwc3_core_soft_reset(dwc3_reg); 229*13194f3bSVivek Gautam 230*13194f3bSVivek Gautam dwc3_hwparams1 = readl(&dwc3_reg->g_hwparams1); 231*13194f3bSVivek Gautam 232*13194f3bSVivek Gautam reg = readl(&dwc3_reg->g_ctl); 233*13194f3bSVivek Gautam reg &= ~DWC3_GCTL_SCALEDOWN_MASK; 234*13194f3bSVivek Gautam reg &= ~DWC3_GCTL_DISSCRAMBLE; 235*13194f3bSVivek Gautam switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc3_hwparams1)) { 236*13194f3bSVivek Gautam case DWC3_GHWPARAMS1_EN_PWROPT_CLK: 237*13194f3bSVivek Gautam reg &= ~DWC3_GCTL_DSBLCLKGTNG; 238*13194f3bSVivek Gautam break; 239*13194f3bSVivek Gautam default: 240*13194f3bSVivek Gautam debug("No power optimization available\n"); 241*13194f3bSVivek Gautam } 242*13194f3bSVivek Gautam 243*13194f3bSVivek Gautam /* 244*13194f3bSVivek Gautam * WORKAROUND: DWC3 revisions <1.90a have a bug 245*13194f3bSVivek Gautam * where the device can fail to connect at SuperSpeed 246*13194f3bSVivek Gautam * and falls back to high-speed mode which causes 247*13194f3bSVivek Gautam * the device to enter a Connect/Disconnect loop 248*13194f3bSVivek Gautam */ 249*13194f3bSVivek Gautam if ((revision & DWC3_REVISION_MASK) < 0x190a) 250*13194f3bSVivek Gautam reg |= DWC3_GCTL_U2RSTECN; 251*13194f3bSVivek Gautam 252*13194f3bSVivek Gautam writel(reg, &dwc3_reg->g_ctl); 253*13194f3bSVivek Gautam 254*13194f3bSVivek Gautam return 0; 255*13194f3bSVivek Gautam } 256*13194f3bSVivek Gautam 257*13194f3bSVivek Gautam static int exynos_xhci_core_init(struct exynos_xhci *exynos) 258*13194f3bSVivek Gautam { 259*13194f3bSVivek Gautam int ret; 260*13194f3bSVivek Gautam 261*13194f3bSVivek Gautam exynos5_usb3_phy_init(exynos->usb3_phy); 262*13194f3bSVivek Gautam 263*13194f3bSVivek Gautam ret = dwc3_core_init(exynos->dwc3_reg); 264*13194f3bSVivek Gautam if (ret) { 265*13194f3bSVivek Gautam debug("failed to initialize core\n"); 266*13194f3bSVivek Gautam return -EINVAL; 267*13194f3bSVivek Gautam } 268*13194f3bSVivek Gautam 269*13194f3bSVivek Gautam /* We are hard-coding DWC3 core to Host Mode */ 270*13194f3bSVivek Gautam dwc3_set_mode(exynos->dwc3_reg, DWC3_GCTL_PRTCAP_HOST); 271*13194f3bSVivek Gautam 272*13194f3bSVivek Gautam return 0; 273*13194f3bSVivek Gautam } 274*13194f3bSVivek Gautam 275*13194f3bSVivek Gautam static void exynos_xhci_core_exit(struct exynos_xhci *exynos) 276*13194f3bSVivek Gautam { 277*13194f3bSVivek Gautam exynos5_usb3_phy_exit(exynos->usb3_phy); 278*13194f3bSVivek Gautam } 279*13194f3bSVivek Gautam 280*13194f3bSVivek Gautam int xhci_hcd_init(int index, struct xhci_hccr **hccr, struct xhci_hcor **hcor) 281*13194f3bSVivek Gautam { 282*13194f3bSVivek Gautam struct exynos_xhci *ctx = &exynos; 283*13194f3bSVivek Gautam int ret; 284*13194f3bSVivek Gautam 285*13194f3bSVivek Gautam #ifdef CONFIG_OF_CONTROL 286*13194f3bSVivek Gautam exynos_usb3_parse_dt(gd->fdt_blob, ctx); 287*13194f3bSVivek Gautam #else 288*13194f3bSVivek Gautam ctx->usb3_phy = (struct exynos_usb3_phy *)samsung_get_base_usb3_phy(); 289*13194f3bSVivek Gautam ctx->hcd = (struct xhci_hccr *)samsung_get_base_usb_xhci(); 290*13194f3bSVivek Gautam #endif 291*13194f3bSVivek Gautam 292*13194f3bSVivek Gautam ctx->dwc3_reg = (struct dwc3 *)((char *)(ctx->hcd) + DWC3_REG_OFFSET); 293*13194f3bSVivek Gautam 294*13194f3bSVivek Gautam ret = exynos_xhci_core_init(ctx); 295*13194f3bSVivek Gautam if (ret) { 296*13194f3bSVivek Gautam puts("XHCI: failed to initialize controller\n"); 297*13194f3bSVivek Gautam return -EINVAL; 298*13194f3bSVivek Gautam } 299*13194f3bSVivek Gautam 300*13194f3bSVivek Gautam *hccr = (ctx->hcd); 301*13194f3bSVivek Gautam *hcor = (struct xhci_hcor *)((uint32_t) *hccr 302*13194f3bSVivek Gautam + HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 303*13194f3bSVivek Gautam 304*13194f3bSVivek Gautam debug("Exynos5-xhci: init hccr %x and hcor %x hc_length %d\n", 305*13194f3bSVivek Gautam (uint32_t)*hccr, (uint32_t)*hcor, 306*13194f3bSVivek Gautam (uint32_t)HC_LENGTH(xhci_readl(&(*hccr)->cr_capbase))); 307*13194f3bSVivek Gautam 308*13194f3bSVivek Gautam return 0; 309*13194f3bSVivek Gautam } 310*13194f3bSVivek Gautam 311*13194f3bSVivek Gautam void xhci_hcd_stop(int index) 312*13194f3bSVivek Gautam { 313*13194f3bSVivek Gautam struct exynos_xhci *ctx = &exynos; 314*13194f3bSVivek Gautam 315*13194f3bSVivek Gautam exynos_xhci_core_exit(ctx); 316*13194f3bSVivek Gautam } 317