1*5a822118SMateusz Kulikowski /* 2*5a822118SMateusz Kulikowski * Qualcomm EHCI driver 3*5a822118SMateusz Kulikowski * 4*5a822118SMateusz Kulikowski * (C) Copyright 2015 Mateusz Kulikowski <mateusz.kulikowski@gmail.com> 5*5a822118SMateusz Kulikowski * 6*5a822118SMateusz Kulikowski * Based on Linux driver 7*5a822118SMateusz Kulikowski * 8*5a822118SMateusz Kulikowski * SPDX-License-Identifier: GPL-2.0+ 9*5a822118SMateusz Kulikowski */ 10*5a822118SMateusz Kulikowski 11*5a822118SMateusz Kulikowski #include <common.h> 12*5a822118SMateusz Kulikowski #include <dm.h> 13*5a822118SMateusz Kulikowski #include <errno.h> 14*5a822118SMateusz Kulikowski #include <fdtdec.h> 15*5a822118SMateusz Kulikowski #include <libfdt.h> 16*5a822118SMateusz Kulikowski #include <usb.h> 17*5a822118SMateusz Kulikowski #include <usb/ehci-ci.h> 18*5a822118SMateusz Kulikowski #include <usb/ulpi.h> 19*5a822118SMateusz Kulikowski #include <wait_bit.h> 20*5a822118SMateusz Kulikowski #include <asm/gpio.h> 21*5a822118SMateusz Kulikowski #include <asm/io.h> 22*5a822118SMateusz Kulikowski #include <linux/compat.h> 23*5a822118SMateusz Kulikowski #include "ehci.h" 24*5a822118SMateusz Kulikowski 25*5a822118SMateusz Kulikowski /* PHY viewport regs */ 26*5a822118SMateusz Kulikowski #define ULPI_MISC_A_READ 0x96 27*5a822118SMateusz Kulikowski #define ULPI_MISC_A_SET 0x97 28*5a822118SMateusz Kulikowski #define ULPI_MISC_A_CLEAR 0x98 29*5a822118SMateusz Kulikowski #define ULPI_MISC_A_VBUSVLDEXTSEL (1 << 1) 30*5a822118SMateusz Kulikowski #define ULPI_MISC_A_VBUSVLDEXT (1 << 0) 31*5a822118SMateusz Kulikowski 32*5a822118SMateusz Kulikowski #define GEN2_SESS_VLD_CTRL_EN (1 << 7) 33*5a822118SMateusz Kulikowski 34*5a822118SMateusz Kulikowski #define SESS_VLD_CTRL (1 << 25) 35*5a822118SMateusz Kulikowski 36*5a822118SMateusz Kulikowski struct msm_ehci_priv { 37*5a822118SMateusz Kulikowski struct ehci_ctrl ctrl; /* Needed by EHCI */ 38*5a822118SMateusz Kulikowski struct usb_ehci *ehci; /* Start of IP core*/ 39*5a822118SMateusz Kulikowski struct ulpi_viewport ulpi_vp; /* ULPI Viewport */ 40*5a822118SMateusz Kulikowski }; 41*5a822118SMateusz Kulikowski 42*5a822118SMateusz Kulikowski int __weak board_prepare_usb(enum usb_init_type type) 43*5a822118SMateusz Kulikowski { 44*5a822118SMateusz Kulikowski return 0; 45*5a822118SMateusz Kulikowski } 46*5a822118SMateusz Kulikowski 47*5a822118SMateusz Kulikowski static void setup_usb_phy(struct msm_ehci_priv *priv) 48*5a822118SMateusz Kulikowski { 49*5a822118SMateusz Kulikowski /* Select and enable external configuration with USB PHY */ 50*5a822118SMateusz Kulikowski ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_SET, 51*5a822118SMateusz Kulikowski ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); 52*5a822118SMateusz Kulikowski } 53*5a822118SMateusz Kulikowski 54*5a822118SMateusz Kulikowski static void reset_usb_phy(struct msm_ehci_priv *priv) 55*5a822118SMateusz Kulikowski { 56*5a822118SMateusz Kulikowski /* Disable VBUS mimicing in the controller. */ 57*5a822118SMateusz Kulikowski ulpi_write(&priv->ulpi_vp, (u8 *)ULPI_MISC_A_CLEAR, 58*5a822118SMateusz Kulikowski ULPI_MISC_A_VBUSVLDEXTSEL | ULPI_MISC_A_VBUSVLDEXT); 59*5a822118SMateusz Kulikowski } 60*5a822118SMateusz Kulikowski 61*5a822118SMateusz Kulikowski 62*5a822118SMateusz Kulikowski static int msm_init_after_reset(struct ehci_ctrl *dev) 63*5a822118SMateusz Kulikowski { 64*5a822118SMateusz Kulikowski struct msm_ehci_priv *p = container_of(dev, struct msm_ehci_priv, ctrl); 65*5a822118SMateusz Kulikowski struct usb_ehci *ehci = p->ehci; 66*5a822118SMateusz Kulikowski 67*5a822118SMateusz Kulikowski /* select ULPI phy */ 68*5a822118SMateusz Kulikowski writel(PORT_PTS_ULPI, &ehci->portsc); 69*5a822118SMateusz Kulikowski setup_usb_phy(p); 70*5a822118SMateusz Kulikowski 71*5a822118SMateusz Kulikowski /* Enable sess_vld */ 72*5a822118SMateusz Kulikowski setbits_le32(&ehci->genconfig2, GEN2_SESS_VLD_CTRL_EN); 73*5a822118SMateusz Kulikowski 74*5a822118SMateusz Kulikowski /* Enable external vbus configuration in the LINK */ 75*5a822118SMateusz Kulikowski setbits_le32(&ehci->usbcmd, SESS_VLD_CTRL); 76*5a822118SMateusz Kulikowski 77*5a822118SMateusz Kulikowski /* USB_OTG_HS_AHB_BURST */ 78*5a822118SMateusz Kulikowski writel(0x0, &ehci->sbuscfg); 79*5a822118SMateusz Kulikowski 80*5a822118SMateusz Kulikowski /* USB_OTG_HS_AHB_MODE: HPROT_MODE */ 81*5a822118SMateusz Kulikowski /* Bus access related config. */ 82*5a822118SMateusz Kulikowski writel(0x08, &ehci->sbusmode); 83*5a822118SMateusz Kulikowski 84*5a822118SMateusz Kulikowski /* set mode to host controller */ 85*5a822118SMateusz Kulikowski writel(CM_HOST, &ehci->usbmode); 86*5a822118SMateusz Kulikowski 87*5a822118SMateusz Kulikowski return 0; 88*5a822118SMateusz Kulikowski } 89*5a822118SMateusz Kulikowski 90*5a822118SMateusz Kulikowski static const struct ehci_ops msm_ehci_ops = { 91*5a822118SMateusz Kulikowski .init_after_reset = msm_init_after_reset 92*5a822118SMateusz Kulikowski }; 93*5a822118SMateusz Kulikowski 94*5a822118SMateusz Kulikowski static int ehci_usb_probe(struct udevice *dev) 95*5a822118SMateusz Kulikowski { 96*5a822118SMateusz Kulikowski struct msm_ehci_priv *p = dev_get_priv(dev); 97*5a822118SMateusz Kulikowski struct usb_ehci *ehci = p->ehci; 98*5a822118SMateusz Kulikowski struct ehci_hccr *hccr; 99*5a822118SMateusz Kulikowski struct ehci_hcor *hcor; 100*5a822118SMateusz Kulikowski int ret; 101*5a822118SMateusz Kulikowski 102*5a822118SMateusz Kulikowski hccr = (struct ehci_hccr *)((phys_addr_t)&ehci->caplength); 103*5a822118SMateusz Kulikowski hcor = (struct ehci_hcor *)((phys_addr_t)hccr + 104*5a822118SMateusz Kulikowski HC_LENGTH(ehci_readl(&(hccr)->cr_capbase))); 105*5a822118SMateusz Kulikowski 106*5a822118SMateusz Kulikowski ret = board_prepare_usb(USB_INIT_HOST); 107*5a822118SMateusz Kulikowski if (ret < 0) 108*5a822118SMateusz Kulikowski return ret; 109*5a822118SMateusz Kulikowski 110*5a822118SMateusz Kulikowski return ehci_register(dev, hccr, hcor, &msm_ehci_ops, 0, USB_INIT_HOST); 111*5a822118SMateusz Kulikowski } 112*5a822118SMateusz Kulikowski 113*5a822118SMateusz Kulikowski static int ehci_usb_remove(struct udevice *dev) 114*5a822118SMateusz Kulikowski { 115*5a822118SMateusz Kulikowski struct msm_ehci_priv *p = dev_get_priv(dev); 116*5a822118SMateusz Kulikowski struct usb_ehci *ehci = p->ehci; 117*5a822118SMateusz Kulikowski int ret; 118*5a822118SMateusz Kulikowski 119*5a822118SMateusz Kulikowski ret = ehci_deregister(dev); 120*5a822118SMateusz Kulikowski if (ret) 121*5a822118SMateusz Kulikowski return ret; 122*5a822118SMateusz Kulikowski 123*5a822118SMateusz Kulikowski /* Stop controller. */ 124*5a822118SMateusz Kulikowski clrbits_le32(&ehci->usbcmd, CMD_RUN); 125*5a822118SMateusz Kulikowski 126*5a822118SMateusz Kulikowski reset_usb_phy(p); 127*5a822118SMateusz Kulikowski 128*5a822118SMateusz Kulikowski ret = board_prepare_usb(USB_INIT_DEVICE); /* Board specific hook */ 129*5a822118SMateusz Kulikowski if (ret < 0) 130*5a822118SMateusz Kulikowski return ret; 131*5a822118SMateusz Kulikowski 132*5a822118SMateusz Kulikowski /* Reset controller */ 133*5a822118SMateusz Kulikowski setbits_le32(&ehci->usbcmd, CMD_RESET); 134*5a822118SMateusz Kulikowski 135*5a822118SMateusz Kulikowski /* Wait for reset */ 136*5a822118SMateusz Kulikowski if (wait_for_bit(__func__, &ehci->usbcmd, CMD_RESET, false, 30, 137*5a822118SMateusz Kulikowski false)) { 138*5a822118SMateusz Kulikowski printf("Stuck on USB reset.\n"); 139*5a822118SMateusz Kulikowski return -ETIMEDOUT; 140*5a822118SMateusz Kulikowski } 141*5a822118SMateusz Kulikowski 142*5a822118SMateusz Kulikowski return 0; 143*5a822118SMateusz Kulikowski } 144*5a822118SMateusz Kulikowski 145*5a822118SMateusz Kulikowski static int ehci_usb_ofdata_to_platdata(struct udevice *dev) 146*5a822118SMateusz Kulikowski { 147*5a822118SMateusz Kulikowski struct msm_ehci_priv *priv = dev_get_priv(dev); 148*5a822118SMateusz Kulikowski 149*5a822118SMateusz Kulikowski priv->ulpi_vp.port_num = 0; 150*5a822118SMateusz Kulikowski priv->ehci = (void *)dev_get_addr(dev); 151*5a822118SMateusz Kulikowski 152*5a822118SMateusz Kulikowski if (priv->ehci == (void *)FDT_ADDR_T_NONE) 153*5a822118SMateusz Kulikowski return -EINVAL; 154*5a822118SMateusz Kulikowski 155*5a822118SMateusz Kulikowski /* Warning: this will not work if viewport address is > 64 bit due to 156*5a822118SMateusz Kulikowski * ULPI design. 157*5a822118SMateusz Kulikowski */ 158*5a822118SMateusz Kulikowski priv->ulpi_vp.viewport_addr = (phys_addr_t)&priv->ehci->ulpi_viewpoint; 159*5a822118SMateusz Kulikowski 160*5a822118SMateusz Kulikowski return 0; 161*5a822118SMateusz Kulikowski } 162*5a822118SMateusz Kulikowski 163*5a822118SMateusz Kulikowski static const struct udevice_id ehci_usb_ids[] = { 164*5a822118SMateusz Kulikowski { .compatible = "qcom,ehci-host", }, 165*5a822118SMateusz Kulikowski { } 166*5a822118SMateusz Kulikowski }; 167*5a822118SMateusz Kulikowski 168*5a822118SMateusz Kulikowski U_BOOT_DRIVER(usb_ehci) = { 169*5a822118SMateusz Kulikowski .name = "ehci_msm", 170*5a822118SMateusz Kulikowski .id = UCLASS_USB, 171*5a822118SMateusz Kulikowski .of_match = ehci_usb_ids, 172*5a822118SMateusz Kulikowski .ofdata_to_platdata = ehci_usb_ofdata_to_platdata, 173*5a822118SMateusz Kulikowski .probe = ehci_usb_probe, 174*5a822118SMateusz Kulikowski .remove = ehci_usb_remove, 175*5a822118SMateusz Kulikowski .ops = &ehci_usb_ops, 176*5a822118SMateusz Kulikowski .priv_auto_alloc_size = sizeof(struct msm_ehci_priv), 177*5a822118SMateusz Kulikowski .flags = DM_FLAG_ALLOC_PRIV_DMA, 178*5a822118SMateusz Kulikowski }; 179