1*a94bb7a4SSanchayan Maity /* 2*a94bb7a4SSanchayan Maity * Copyright (c) 2015 Sanchayan Maity <sanchayan.maity@toradex.com> 3*a94bb7a4SSanchayan Maity * Copyright (C) 2015 Toradex AG 4*a94bb7a4SSanchayan Maity * 5*a94bb7a4SSanchayan Maity * Based on ehci-mx6 driver 6*a94bb7a4SSanchayan Maity * 7*a94bb7a4SSanchayan Maity * SPDX-License-Identifier: GPL-2.0+ 8*a94bb7a4SSanchayan Maity */ 9*a94bb7a4SSanchayan Maity 10*a94bb7a4SSanchayan Maity #include <common.h> 11*a94bb7a4SSanchayan Maity #include <usb.h> 12*a94bb7a4SSanchayan Maity #include <errno.h> 13*a94bb7a4SSanchayan Maity #include <linux/compiler.h> 14*a94bb7a4SSanchayan Maity #include <asm/io.h> 15*a94bb7a4SSanchayan Maity #include <asm/arch/clock.h> 16*a94bb7a4SSanchayan Maity #include <asm/arch/imx-regs.h> 17*a94bb7a4SSanchayan Maity #include <asm/arch/crm_regs.h> 18*a94bb7a4SSanchayan Maity #include <asm/imx-common/iomux-v3.h> 19*a94bb7a4SSanchayan Maity #include <asm/imx-common/regs-usbphy.h> 20*a94bb7a4SSanchayan Maity #include <usb/ehci-fsl.h> 21*a94bb7a4SSanchayan Maity 22*a94bb7a4SSanchayan Maity #include "ehci.h" 23*a94bb7a4SSanchayan Maity 24*a94bb7a4SSanchayan Maity #define USB_NC_REG_OFFSET 0x00000800 25*a94bb7a4SSanchayan Maity 26*a94bb7a4SSanchayan Maity #define ANADIG_PLL_CTRL_EN_USB_CLKS (1 << 6) 27*a94bb7a4SSanchayan Maity 28*a94bb7a4SSanchayan Maity #define UCTRL_OVER_CUR_POL (1 << 8) /* OTG Polarity of Overcurrent */ 29*a94bb7a4SSanchayan Maity #define UCTRL_OVER_CUR_DIS (1 << 7) /* Disable OTG Overcurrent Detection */ 30*a94bb7a4SSanchayan Maity 31*a94bb7a4SSanchayan Maity /* USBCMD */ 32*a94bb7a4SSanchayan Maity #define UCMD_RUN_STOP (1 << 0) /* controller run/stop */ 33*a94bb7a4SSanchayan Maity #define UCMD_RESET (1 << 1) /* controller reset */ 34*a94bb7a4SSanchayan Maity 35*a94bb7a4SSanchayan Maity static const unsigned phy_bases[] = { 36*a94bb7a4SSanchayan Maity USB_PHY0_BASE_ADDR, 37*a94bb7a4SSanchayan Maity USB_PHY1_BASE_ADDR, 38*a94bb7a4SSanchayan Maity }; 39*a94bb7a4SSanchayan Maity 40*a94bb7a4SSanchayan Maity static const unsigned nc_reg_bases[] = { 41*a94bb7a4SSanchayan Maity USBC0_BASE_ADDR, 42*a94bb7a4SSanchayan Maity USBC1_BASE_ADDR, 43*a94bb7a4SSanchayan Maity }; 44*a94bb7a4SSanchayan Maity 45*a94bb7a4SSanchayan Maity static void usb_internal_phy_clock_gate(int index) 46*a94bb7a4SSanchayan Maity { 47*a94bb7a4SSanchayan Maity void __iomem *phy_reg; 48*a94bb7a4SSanchayan Maity 49*a94bb7a4SSanchayan Maity phy_reg = (void __iomem *)phy_bases[index]; 50*a94bb7a4SSanchayan Maity clrbits_le32(phy_reg + USBPHY_CTRL, USBPHY_CTRL_CLKGATE); 51*a94bb7a4SSanchayan Maity } 52*a94bb7a4SSanchayan Maity 53*a94bb7a4SSanchayan Maity static void usb_power_config(int index) 54*a94bb7a4SSanchayan Maity { 55*a94bb7a4SSanchayan Maity struct anadig_reg __iomem *anadig = 56*a94bb7a4SSanchayan Maity (struct anadig_reg __iomem *)ANADIG_BASE_ADDR; 57*a94bb7a4SSanchayan Maity void __iomem *pll_ctrl; 58*a94bb7a4SSanchayan Maity 59*a94bb7a4SSanchayan Maity switch (index) { 60*a94bb7a4SSanchayan Maity case 0: 61*a94bb7a4SSanchayan Maity pll_ctrl = &anadig->pll3_ctrl; 62*a94bb7a4SSanchayan Maity clrbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_BYPASS); 63*a94bb7a4SSanchayan Maity setbits_le32(pll_ctrl, ANADIG_PLL3_CTRL_ENABLE 64*a94bb7a4SSanchayan Maity | ANADIG_PLL3_CTRL_POWERDOWN 65*a94bb7a4SSanchayan Maity | ANADIG_PLL_CTRL_EN_USB_CLKS); 66*a94bb7a4SSanchayan Maity break; 67*a94bb7a4SSanchayan Maity case 1: 68*a94bb7a4SSanchayan Maity pll_ctrl = &anadig->pll7_ctrl; 69*a94bb7a4SSanchayan Maity clrbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_BYPASS); 70*a94bb7a4SSanchayan Maity setbits_le32(pll_ctrl, ANADIG_PLL7_CTRL_ENABLE 71*a94bb7a4SSanchayan Maity | ANADIG_PLL7_CTRL_POWERDOWN 72*a94bb7a4SSanchayan Maity | ANADIG_PLL_CTRL_EN_USB_CLKS); 73*a94bb7a4SSanchayan Maity break; 74*a94bb7a4SSanchayan Maity default: 75*a94bb7a4SSanchayan Maity return; 76*a94bb7a4SSanchayan Maity } 77*a94bb7a4SSanchayan Maity } 78*a94bb7a4SSanchayan Maity 79*a94bb7a4SSanchayan Maity static void usb_phy_enable(int index, struct usb_ehci *ehci) 80*a94bb7a4SSanchayan Maity { 81*a94bb7a4SSanchayan Maity void __iomem *phy_reg; 82*a94bb7a4SSanchayan Maity void __iomem *phy_ctrl; 83*a94bb7a4SSanchayan Maity void __iomem *usb_cmd; 84*a94bb7a4SSanchayan Maity 85*a94bb7a4SSanchayan Maity phy_reg = (void __iomem *)phy_bases[index]; 86*a94bb7a4SSanchayan Maity phy_ctrl = (void __iomem *)(phy_reg + USBPHY_CTRL); 87*a94bb7a4SSanchayan Maity usb_cmd = (void __iomem *)&ehci->usbcmd; 88*a94bb7a4SSanchayan Maity 89*a94bb7a4SSanchayan Maity /* Stop then Reset */ 90*a94bb7a4SSanchayan Maity clrbits_le32(usb_cmd, UCMD_RUN_STOP); 91*a94bb7a4SSanchayan Maity while (readl(usb_cmd) & UCMD_RUN_STOP) 92*a94bb7a4SSanchayan Maity ; 93*a94bb7a4SSanchayan Maity 94*a94bb7a4SSanchayan Maity setbits_le32(usb_cmd, UCMD_RESET); 95*a94bb7a4SSanchayan Maity while (readl(usb_cmd) & UCMD_RESET) 96*a94bb7a4SSanchayan Maity ; 97*a94bb7a4SSanchayan Maity 98*a94bb7a4SSanchayan Maity /* Reset USBPHY module */ 99*a94bb7a4SSanchayan Maity setbits_le32(phy_ctrl, USBPHY_CTRL_SFTRST); 100*a94bb7a4SSanchayan Maity udelay(10); 101*a94bb7a4SSanchayan Maity 102*a94bb7a4SSanchayan Maity /* Remove CLKGATE and SFTRST */ 103*a94bb7a4SSanchayan Maity clrbits_le32(phy_ctrl, USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST); 104*a94bb7a4SSanchayan Maity udelay(10); 105*a94bb7a4SSanchayan Maity 106*a94bb7a4SSanchayan Maity /* Power up the PHY */ 107*a94bb7a4SSanchayan Maity writel(0, phy_reg + USBPHY_PWD); 108*a94bb7a4SSanchayan Maity 109*a94bb7a4SSanchayan Maity /* Enable FS/LS device */ 110*a94bb7a4SSanchayan Maity setbits_le32(phy_ctrl, USBPHY_CTRL_ENUTMILEVEL2 | 111*a94bb7a4SSanchayan Maity USBPHY_CTRL_ENUTMILEVEL3); 112*a94bb7a4SSanchayan Maity } 113*a94bb7a4SSanchayan Maity 114*a94bb7a4SSanchayan Maity static void usb_oc_config(int index) 115*a94bb7a4SSanchayan Maity { 116*a94bb7a4SSanchayan Maity void __iomem *ctrl; 117*a94bb7a4SSanchayan Maity 118*a94bb7a4SSanchayan Maity ctrl = (void __iomem *)(nc_reg_bases[index] + USB_NC_REG_OFFSET); 119*a94bb7a4SSanchayan Maity 120*a94bb7a4SSanchayan Maity setbits_le32(ctrl, UCTRL_OVER_CUR_POL); 121*a94bb7a4SSanchayan Maity setbits_le32(ctrl, UCTRL_OVER_CUR_DIS); 122*a94bb7a4SSanchayan Maity } 123*a94bb7a4SSanchayan Maity 124*a94bb7a4SSanchayan Maity int ehci_hcd_init(int index, enum usb_init_type init, 125*a94bb7a4SSanchayan Maity struct ehci_hccr **hccr, struct ehci_hcor **hcor) 126*a94bb7a4SSanchayan Maity { 127*a94bb7a4SSanchayan Maity struct usb_ehci *ehci; 128*a94bb7a4SSanchayan Maity 129*a94bb7a4SSanchayan Maity if (index >= ARRAY_SIZE(nc_reg_bases)) 130*a94bb7a4SSanchayan Maity return -EINVAL; 131*a94bb7a4SSanchayan Maity 132*a94bb7a4SSanchayan Maity if (init == USB_INIT_DEVICE && index == 1) 133*a94bb7a4SSanchayan Maity return -ENODEV; 134*a94bb7a4SSanchayan Maity if (init == USB_INIT_HOST && index == 0) 135*a94bb7a4SSanchayan Maity return -ENODEV; 136*a94bb7a4SSanchayan Maity 137*a94bb7a4SSanchayan Maity ehci = (struct usb_ehci *)nc_reg_bases[index]; 138*a94bb7a4SSanchayan Maity 139*a94bb7a4SSanchayan Maity usb_power_config(index); 140*a94bb7a4SSanchayan Maity usb_oc_config(index); 141*a94bb7a4SSanchayan Maity usb_internal_phy_clock_gate(index); 142*a94bb7a4SSanchayan Maity usb_phy_enable(index, ehci); 143*a94bb7a4SSanchayan Maity 144*a94bb7a4SSanchayan Maity *hccr = (struct ehci_hccr *)((uint32_t)&ehci->caplength); 145*a94bb7a4SSanchayan Maity *hcor = (struct ehci_hcor *)((uint32_t)*hccr + 146*a94bb7a4SSanchayan Maity HC_LENGTH(ehci_readl(&(*hccr)->cr_capbase))); 147*a94bb7a4SSanchayan Maity 148*a94bb7a4SSanchayan Maity if (init == USB_INIT_DEVICE) { 149*a94bb7a4SSanchayan Maity setbits_le32(&ehci->usbmode, CM_DEVICE); 150*a94bb7a4SSanchayan Maity writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); 151*a94bb7a4SSanchayan Maity setbits_le32(&ehci->portsc, USB_EN); 152*a94bb7a4SSanchayan Maity } else if (init == USB_INIT_HOST) { 153*a94bb7a4SSanchayan Maity setbits_le32(&ehci->usbmode, CM_HOST); 154*a94bb7a4SSanchayan Maity writel((PORT_PTS_UTMI | PORT_PTS_PTW), &ehci->portsc); 155*a94bb7a4SSanchayan Maity setbits_le32(&ehci->portsc, USB_EN); 156*a94bb7a4SSanchayan Maity } 157*a94bb7a4SSanchayan Maity 158*a94bb7a4SSanchayan Maity return 0; 159*a94bb7a4SSanchayan Maity } 160*a94bb7a4SSanchayan Maity 161*a94bb7a4SSanchayan Maity int ehci_hcd_stop(int index) 162*a94bb7a4SSanchayan Maity { 163*a94bb7a4SSanchayan Maity return 0; 164*a94bb7a4SSanchayan Maity } 165